a | b/c2iec.js | ||
---|---|---|---|
1 | |||
2 | |||
3 | // The Module object: Our interface to the outside world. We import |
||
4 | // and export values on it. There are various ways Module can be used: |
||
5 | // 1. Not defined. We create it here |
||
6 | // 2. A function parameter, function(Module) { ..generated code.. } |
||
7 | // 3. pre-run appended it, var Module = {}; ..generated code.. |
||
8 | // 4. External script tag defines var Module. |
||
9 | // We need to check if Module already exists (e.g. case 3 above). |
||
10 | // Substitution will be replaced with actual code on later stage of the build, |
||
11 | // this way Closure Compiler will not mangle it (e.g. case 4. above). |
||
12 | // Note that if you want to run closure, and also to use Module |
||
13 | // after the generated code, you will need to define var Module = {}; |
||
14 | // before the code. Then that object will be used in the code, and you |
||
15 | // can continue to use Module afterwards as well. |
||
16 | var Module = typeof Module !== 'undefined' ? Module : {}; |
||
17 | |||
18 | |||
19 | |||
20 | // --pre-jses are emitted after the Module integration code, so that they can |
||
21 | // refer to Module (if they choose; they can also define Module) |
||
22 | // {{PRE_JSES}} |
||
23 | |||
24 | // Sometimes an existing Module object exists with properties |
||
25 | // meant to overwrite the default module functionality. Here |
||
26 | // we collect those properties and reapply _after_ we configure |
||
27 | // the current environment's defaults to avoid having to be so |
||
28 | // defensive during initialization. |
||
29 | var moduleOverrides = {}; |
||
30 | var key; |
||
31 | for (key in Module) { |
||
32 | if (Module.hasOwnProperty(key)) { |
||
33 | moduleOverrides[key] = Module[key]; |
||
34 | } |
||
35 | } |
||
36 | |||
37 | var arguments_ = []; |
||
38 | var thisProgram = './this.program'; |
||
39 | var quit_ = function(status, toThrow) { |
||
40 | throw toThrow; |
||
41 | }; |
||
42 | |||
43 | // Determine the runtime environment we are in. You can customize this by |
||
44 | // setting the ENVIRONMENT setting at compile time (see settings.js). |
||
45 | |||
46 | var ENVIRONMENT_IS_WEB = false; |
||
47 | var ENVIRONMENT_IS_WORKER = false; |
||
48 | var ENVIRONMENT_IS_NODE = false; |
||
49 | var ENVIRONMENT_IS_SHELL = false; |
||
50 | ENVIRONMENT_IS_WEB = typeof window === 'object'; |
||
51 | ENVIRONMENT_IS_WORKER = typeof importScripts === 'function'; |
||
52 | // N.b. Electron.js environment is simultaneously a NODE-environment, but |
||
53 | // also a web environment. |
||
54 | ENVIRONMENT_IS_NODE = typeof process === 'object' && typeof process.versions === 'object' && typeof process.versions.node === 'string'; |
||
55 | ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER; |
||
56 | |||
57 | if (Module['ENVIRONMENT']) { |
||
58 | throw new Error('Module.ENVIRONMENT has been deprecated. To force the environment, use the ENVIRONMENT compile-time option (for example, -s ENVIRONMENT=web or -s ENVIRONMENT=node)'); |
||
59 | } |
||
60 | |||
61 | |||
62 | |||
63 | // `/` should be present at the end if `scriptDirectory` is not empty |
||
64 | var scriptDirectory = ''; |
||
65 | function locateFile(path) { |
||
66 | if (Module['locateFile']) { |
||
67 | return Module['locateFile'](path, scriptDirectory); |
||
68 | } |
||
69 | return scriptDirectory + path; |
||
70 | } |
||
71 | |||
72 | // Hooks that are implemented differently in different runtime environments. |
||
73 | var read_, |
||
74 | readAsync, |
||
75 | readBinary, |
||
76 | setWindowTitle; |
||
77 | |||
78 | var nodeFS; |
||
79 | var nodePath; |
||
80 | |||
81 | if (ENVIRONMENT_IS_NODE) { |
||
82 | if (ENVIRONMENT_IS_WORKER) { |
||
83 | scriptDirectory = require('path').dirname(scriptDirectory) + '/'; |
||
84 | } else { |
||
85 | scriptDirectory = __dirname + '/'; |
||
86 | } |
||
87 | |||
88 | |||
89 | |||
90 | |||
91 | read_ = function shell_read(filename, binary) { |
||
92 | if (!nodeFS) nodeFS = require('fs'); |
||
93 | if (!nodePath) nodePath = require('path'); |
||
94 | filename = nodePath['normalize'](filename); |
||
95 | return nodeFS['readFileSync'](filename, binary ? null : 'utf8'); |
||
96 | }; |
||
97 | |||
98 | readBinary = function readBinary(filename) { |
||
99 | var ret = read_(filename, true); |
||
100 | if (!ret.buffer) { |
||
101 | ret = new Uint8Array(ret); |
||
102 | } |
||
103 | assert(ret.buffer); |
||
104 | return ret; |
||
105 | }; |
||
106 | |||
107 | |||
108 | |||
109 | |||
110 | if (process['argv'].length > 1) { |
||
111 | thisProgram = process['argv'][1].replace(/\\/g, '/'); |
||
112 | } |
||
113 | |||
114 | arguments_ = process['argv'].slice(2); |
||
115 | |||
116 | if (typeof module !== 'undefined') { |
||
117 | module['exports'] = Module; |
||
118 | } |
||
119 | |||
120 | process['on']('uncaughtException', function(ex) { |
||
121 | // suppress ExitStatus exceptions from showing an error |
||
122 | if (!(ex instanceof ExitStatus)) { |
||
123 | throw ex; |
||
124 | } |
||
125 | }); |
||
126 | |||
127 | process['on']('unhandledRejection', abort); |
||
128 | |||
129 | quit_ = function(status) { |
||
130 | process['exit'](status); |
||
131 | }; |
||
132 | |||
133 | Module['inspect'] = function () { return '[Emscripten Module object]'; }; |
||
134 | |||
135 | |||
136 | |||
137 | } else |
||
138 | if (ENVIRONMENT_IS_SHELL) { |
||
139 | |||
140 | |||
141 | if (typeof read != 'undefined') { |
||
142 | read_ = function shell_read(f) { |
||
143 | return read(f); |
||
144 | }; |
||
145 | } |
||
146 | |||
147 | readBinary = function readBinary(f) { |
||
148 | var data; |
||
149 | if (typeof readbuffer === 'function') { |
||
150 | return new Uint8Array(readbuffer(f)); |
||
151 | } |
||
152 | data = read(f, 'binary'); |
||
153 | assert(typeof data === 'object'); |
||
154 | return data; |
||
155 | }; |
||
156 | |||
157 | if (typeof scriptArgs != 'undefined') { |
||
158 | arguments_ = scriptArgs; |
||
159 | } else if (typeof arguments != 'undefined') { |
||
160 | arguments_ = arguments; |
||
161 | } |
||
162 | |||
163 | if (typeof quit === 'function') { |
||
164 | quit_ = function(status) { |
||
165 | quit(status); |
||
166 | }; |
||
167 | } |
||
168 | |||
169 | if (typeof print !== 'undefined') { |
||
170 | // Prefer to use print/printErr where they exist, as they usually work better. |
||
171 | if (typeof console === 'undefined') console = /** @type{!Console} */({}); |
||
172 | console.log = /** @type{!function(this:Console, ...*): undefined} */ (print); |
||
173 | console.warn = console.error = /** @type{!function(this:Console, ...*): undefined} */ (typeof printErr !== 'undefined' ? printErr : print); |
||
174 | } |
||
175 | |||
176 | |||
177 | } else |
||
178 | |||
179 | // Note that this includes Node.js workers when relevant (pthreads is enabled). |
||
180 | // Node.js workers are detected as a combination of ENVIRONMENT_IS_WORKER and |
||
181 | // ENVIRONMENT_IS_NODE. |
||
182 | if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) { |
||
183 | if (ENVIRONMENT_IS_WORKER) { // Check worker, not web, since window could be polyfilled |
||
184 | scriptDirectory = self.location.href; |
||
185 | } else if (document.currentScript) { // web |
||
186 | scriptDirectory = document.currentScript.src; |
||
187 | } |
||
188 | // blob urls look like blob:http://site.com/etc/etc and we cannot infer anything from them. |
||
189 | // otherwise, slice off the final part of the url to find the script directory. |
||
190 | // if scriptDirectory does not contain a slash, lastIndexOf will return -1, |
||
191 | // and scriptDirectory will correctly be replaced with an empty string. |
||
192 | if (scriptDirectory.indexOf('blob:') !== 0) { |
||
193 | scriptDirectory = scriptDirectory.substr(0, scriptDirectory.lastIndexOf('/')+1); |
||
194 | } else { |
||
195 | scriptDirectory = ''; |
||
196 | } |
||
197 | |||
198 | |||
199 | // Differentiate the Web Worker from the Node Worker case, as reading must |
||
200 | // be done differently. |
||
201 | { |
||
202 | |||
203 | |||
204 | |||
205 | |||
206 | read_ = function shell_read(url) { |
||
207 | var xhr = new XMLHttpRequest(); |
||
208 | xhr.open('GET', url, false); |
||
209 | xhr.send(null); |
||
210 | return xhr.responseText; |
||
211 | }; |
||
212 | |||
213 | if (ENVIRONMENT_IS_WORKER) { |
||
214 | readBinary = function readBinary(url) { |
||
215 | var xhr = new XMLHttpRequest(); |
||
216 | xhr.open('GET', url, false); |
||
217 | xhr.responseType = 'arraybuffer'; |
||
218 | xhr.send(null); |
||
219 | return new Uint8Array(/** @type{!ArrayBuffer} */(xhr.response)); |
||
220 | }; |
||
221 | } |
||
222 | |||
223 | readAsync = function readAsync(url, onload, onerror) { |
||
224 | var xhr = new XMLHttpRequest(); |
||
225 | xhr.open('GET', url, true); |
||
226 | xhr.responseType = 'arraybuffer'; |
||
227 | xhr.onload = function xhr_onload() { |
||
228 | if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) { // file URLs can return 0 |
||
229 | onload(xhr.response); |
||
230 | return; |
||
231 | } |
||
232 | onerror(); |
||
233 | }; |
||
234 | xhr.onerror = onerror; |
||
235 | xhr.send(null); |
||
236 | }; |
||
237 | |||
238 | |||
239 | |||
240 | |||
241 | } |
||
242 | |||
243 | setWindowTitle = function(title) { document.title = title }; |
||
244 | } else |
||
245 | { |
||
246 | throw new Error('environment detection error'); |
||
247 | } |
||
248 | |||
249 | |||
250 | // Set up the out() and err() hooks, which are how we can print to stdout or |
||
251 | // stderr, respectively. |
||
252 | var out = Module['print'] || console.log.bind(console); |
||
253 | var err = Module['printErr'] || console.warn.bind(console); |
||
254 | |||
255 | // Merge back in the overrides |
||
256 | for (key in moduleOverrides) { |
||
257 | if (moduleOverrides.hasOwnProperty(key)) { |
||
258 | Module[key] = moduleOverrides[key]; |
||
259 | } |
||
260 | } |
||
261 | // Free the object hierarchy contained in the overrides, this lets the GC |
||
262 | // reclaim data used e.g. in memoryInitializerRequest, which is a large typed array. |
||
263 | moduleOverrides = null; |
||
264 | |||
265 | // Emit code to handle expected values on the Module object. This applies Module.x |
||
266 | // to the proper local x. This has two benefits: first, we only emit it if it is |
||
267 | // expected to arrive, and second, by using a local everywhere else that can be |
||
268 | // minified. |
||
269 | if (Module['arguments']) arguments_ = Module['arguments'];if (!Object.getOwnPropertyDescriptor(Module, 'arguments')) Object.defineProperty(Module, 'arguments', { configurable: true, get: function() { abort('Module.arguments has been replaced with plain arguments_ (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)') } }); |
||
270 | if (Module['thisProgram']) thisProgram = Module['thisProgram'];if (!Object.getOwnPropertyDescriptor(Module, 'thisProgram')) Object.defineProperty(Module, 'thisProgram', { configurable: true, get: function() { abort('Module.thisProgram has been replaced with plain thisProgram (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)') } }); |
||
271 | if (Module['quit']) quit_ = Module['quit'];if (!Object.getOwnPropertyDescriptor(Module, 'quit')) Object.defineProperty(Module, 'quit', { configurable: true, get: function() { abort('Module.quit has been replaced with plain quit_ (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)') } }); |
||
272 | |||
273 | // perform assertions in shell.js after we set up out() and err(), as otherwise if an assertion fails it cannot print the message |
||
274 | // Assertions on removed incoming Module JS APIs. |
||
275 | assert(typeof Module['memoryInitializerPrefixURL'] === 'undefined', 'Module.memoryInitializerPrefixURL option was removed, use Module.locateFile instead'); |
||
276 | assert(typeof Module['pthreadMainPrefixURL'] === 'undefined', 'Module.pthreadMainPrefixURL option was removed, use Module.locateFile instead'); |
||
277 | assert(typeof Module['cdInitializerPrefixURL'] === 'undefined', 'Module.cdInitializerPrefixURL option was removed, use Module.locateFile instead'); |
||
278 | assert(typeof Module['filePackagePrefixURL'] === 'undefined', 'Module.filePackagePrefixURL option was removed, use Module.locateFile instead'); |
||
279 | assert(typeof Module['read'] === 'undefined', 'Module.read option was removed (modify read_ in JS)'); |
||
280 | assert(typeof Module['readAsync'] === 'undefined', 'Module.readAsync option was removed (modify readAsync in JS)'); |
||
281 | assert(typeof Module['readBinary'] === 'undefined', 'Module.readBinary option was removed (modify readBinary in JS)'); |
||
282 | assert(typeof Module['setWindowTitle'] === 'undefined', 'Module.setWindowTitle option was removed (modify setWindowTitle in JS)'); |
||
283 | assert(typeof Module['TOTAL_MEMORY'] === 'undefined', 'Module.TOTAL_MEMORY has been renamed Module.INITIAL_MEMORY'); |
||
284 | if (!Object.getOwnPropertyDescriptor(Module, 'read')) Object.defineProperty(Module, 'read', { configurable: true, get: function() { abort('Module.read has been replaced with plain read_ (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)') } }); |
||
285 | if (!Object.getOwnPropertyDescriptor(Module, 'readAsync')) Object.defineProperty(Module, 'readAsync', { configurable: true, get: function() { abort('Module.readAsync has been replaced with plain readAsync (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)') } }); |
||
286 | if (!Object.getOwnPropertyDescriptor(Module, 'readBinary')) Object.defineProperty(Module, 'readBinary', { configurable: true, get: function() { abort('Module.readBinary has been replaced with plain readBinary (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)') } }); |
||
287 | if (!Object.getOwnPropertyDescriptor(Module, 'setWindowTitle')) Object.defineProperty(Module, 'setWindowTitle', { configurable: true, get: function() { abort('Module.setWindowTitle has been replaced with plain setWindowTitle (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)') } }); |
||
288 | var IDBFS = 'IDBFS is no longer included by default; build with -lidbfs.js'; |
||
289 | var PROXYFS = 'PROXYFS is no longer included by default; build with -lproxyfs.js'; |
||
290 | var WORKERFS = 'WORKERFS is no longer included by default; build with -lworkerfs.js'; |
||
291 | var NODEFS = 'NODEFS is no longer included by default; build with -lnodefs.js'; |
||
292 | |||
293 | |||
294 | |||
295 | |||
296 | |||
297 | |||
298 | // {{PREAMBLE_ADDITIONS}} |
||
299 | |||
300 | var STACK_ALIGN = 16; |
||
301 | |||
302 | function dynamicAlloc(size) { |
||
303 | assert(DYNAMICTOP_PTR); |
||
304 | var ret = HEAP32[DYNAMICTOP_PTR>>2]; |
||
305 | var end = (ret + size + 15) & -16; |
||
306 | assert(end <= HEAP8.length, 'failure to dynamicAlloc - memory growth etc. is not supported there, call malloc/sbrk directly'); |
||
307 | HEAP32[DYNAMICTOP_PTR>>2] = end; |
||
308 | return ret; |
||
309 | } |
||
310 | |||
311 | function alignMemory(size, factor) { |
||
312 | if (!factor) factor = STACK_ALIGN; // stack alignment (16-byte) by default |
||
313 | return Math.ceil(size / factor) * factor; |
||
314 | } |
||
315 | |||
316 | function getNativeTypeSize(type) { |
||
317 | switch (type) { |
||
318 | case 'i1': case 'i8': return 1; |
||
319 | case 'i16': return 2; |
||
320 | case 'i32': return 4; |
||
321 | case 'i64': return 8; |
||
322 | case 'float': return 4; |
||
323 | case 'double': return 8; |
||
324 | default: { |
||
325 | if (type[type.length-1] === '*') { |
||
326 | return 4; // A pointer |
||
327 | } else if (type[0] === 'i') { |
||
328 | var bits = Number(type.substr(1)); |
||
329 | assert(bits % 8 === 0, 'getNativeTypeSize invalid bits ' + bits + ', type ' + type); |
||
330 | return bits / 8; |
||
331 | } else { |
||
332 | return 0; |
||
333 | } |
||
334 | } |
||
335 | } |
||
336 | } |
||
337 | |||
338 | function warnOnce(text) { |
||
339 | if (!warnOnce.shown) warnOnce.shown = {}; |
||
340 | if (!warnOnce.shown[text]) { |
||
341 | warnOnce.shown[text] = 1; |
||
342 | err(text); |
||
343 | } |
||
344 | } |
||
345 | |||
346 | |||
347 | |||
348 | |||
349 | |||
350 | |||
351 | |||
352 | |||
353 | // Wraps a JS function as a wasm function with a given signature. |
||
354 | function convertJsFunctionToWasm(func, sig) { |
||
355 | |||
356 | // If the type reflection proposal is available, use the new |
||
357 | // "WebAssembly.Function" constructor. |
||
358 | // Otherwise, construct a minimal wasm module importing the JS function and |
||
359 | // re-exporting it. |
||
360 | if (typeof WebAssembly.Function === "function") { |
||
361 | var typeNames = { |
||
362 | 'i': 'i32', |
||
363 | 'j': 'i64', |
||
364 | 'f': 'f32', |
||
365 | 'd': 'f64' |
||
366 | }; |
||
367 | var type = { |
||
368 | parameters: [], |
||
369 | results: sig[0] == 'v' ? [] : [typeNames[sig[0]]] |
||
370 | }; |
||
371 | for (var i = 1; i < sig.length; ++i) { |
||
372 | type.parameters.push(typeNames[sig[i]]); |
||
373 | } |
||
374 | return new WebAssembly.Function(type, func); |
||
375 | } |
||
376 | |||
377 | // The module is static, with the exception of the type section, which is |
||
378 | // generated based on the signature passed in. |
||
379 | var typeSection = [ |
||
380 | 0x01, // id: section, |
||
381 | 0x00, // length: 0 (placeholder) |
||
382 | 0x01, // count: 1 |
||
383 | 0x60, // form: func |
||
384 | ]; |
||
385 | var sigRet = sig.slice(0, 1); |
||
386 | var sigParam = sig.slice(1); |
||
387 | var typeCodes = { |
||
388 | 'i': 0x7f, // i32 |
||
389 | 'j': 0x7e, // i64 |
||
390 | 'f': 0x7d, // f32 |
||
391 | 'd': 0x7c, // f64 |
||
392 | }; |
||
393 | |||
394 | // Parameters, length + signatures |
||
395 | typeSection.push(sigParam.length); |
||
396 | for (var i = 0; i < sigParam.length; ++i) { |
||
397 | typeSection.push(typeCodes[sigParam[i]]); |
||
398 | } |
||
399 | |||
400 | // Return values, length + signatures |
||
401 | // With no multi-return in MVP, either 0 (void) or 1 (anything else) |
||
402 | if (sigRet == 'v') { |
||
403 | typeSection.push(0x00); |
||
404 | } else { |
||
405 | typeSection = typeSection.concat([0x01, typeCodes[sigRet]]); |
||
406 | } |
||
407 | |||
408 | // Write the overall length of the type section back into the section header |
||
409 | // (excepting the 2 bytes for the section id and length) |
||
410 | typeSection[1] = typeSection.length - 2; |
||
411 | |||
412 | // Rest of the module is static |
||
413 | var bytes = new Uint8Array([ |
||
414 | 0x00, 0x61, 0x73, 0x6d, // magic ("\0asm") |
||
415 | 0x01, 0x00, 0x00, 0x00, // version: 1 |
||
416 | ].concat(typeSection, [ |
||
417 | 0x02, 0x07, // import section |
||
418 | // (import "e" "f" (func 0 (type 0))) |
||
419 | 0x01, 0x01, 0x65, 0x01, 0x66, 0x00, 0x00, |
||
420 | 0x07, 0x05, // export section |
||
421 | // (export "f" (func 0 (type 0))) |
||
422 | 0x01, 0x01, 0x66, 0x00, 0x00, |
||
423 | ])); |
||
424 | |||
425 | // We can compile this wasm module synchronously because it is very small. |
||
426 | // This accepts an import (at "e.f"), that it reroutes to an export (at "f") |
||
427 | var module = new WebAssembly.Module(bytes); |
||
428 | var instance = new WebAssembly.Instance(module, { |
||
429 | 'e': { |
||
430 | 'f': func |
||
431 | } |
||
432 | }); |
||
433 | var wrappedFunc = instance.exports['f']; |
||
434 | return wrappedFunc; |
||
435 | } |
||
436 | |||
437 | var freeTableIndexes = []; |
||
438 | |||
439 | // Weak map of functions in the table to their indexes, created on first use. |
||
440 | var functionsInTableMap; |
||
441 | |||
442 | // Add a wasm function to the table. |
||
443 | function addFunctionWasm(func, sig) { |
||
444 | var table = wasmTable; |
||
445 | |||
446 | // Check if the function is already in the table, to ensure each function |
||
447 | // gets a unique index. First, create the map if this is the first use. |
||
448 | if (!functionsInTableMap) { |
||
449 | functionsInTableMap = new WeakMap(); |
||
450 | for (var i = 0; i < table.length; i++) { |
||
451 | var item = table.get(i); |
||
452 | // Ignore null values. |
||
453 | if (item) { |
||
454 | functionsInTableMap.set(item, i); |
||
455 | } |
||
456 | } |
||
457 | } |
||
458 | if (functionsInTableMap.has(func)) { |
||
459 | return functionsInTableMap.get(func); |
||
460 | } |
||
461 | |||
462 | // It's not in the table, add it now. |
||
463 | |||
464 | |||
465 | var ret; |
||
466 | // Reuse a free index if there is one, otherwise grow. |
||
467 | if (freeTableIndexes.length) { |
||
468 | ret = freeTableIndexes.pop(); |
||
469 | } else { |
||
470 | ret = table.length; |
||
471 | // Grow the table |
||
472 | try { |
||
473 | table.grow(1); |
||
474 | } catch (err) { |
||
475 | if (!(err instanceof RangeError)) { |
||
476 | throw err; |
||
477 | } |
||
478 | throw 'Unable to grow wasm table. Set ALLOW_TABLE_GROWTH.'; |
||
479 | } |
||
480 | } |
||
481 | |||
482 | // Set the new value. |
||
483 | try { |
||
484 | // Attempting to call this with JS function will cause of table.set() to fail |
||
485 | table.set(ret, func); |
||
486 | } catch (err) { |
||
487 | if (!(err instanceof TypeError)) { |
||
488 | throw err; |
||
489 | } |
||
490 | assert(typeof sig !== 'undefined', 'Missing signature argument to addFunction'); |
||
491 | var wrapped = convertJsFunctionToWasm(func, sig); |
||
492 | table.set(ret, wrapped); |
||
493 | } |
||
494 | |||
495 | functionsInTableMap.set(func, ret); |
||
496 | |||
497 | return ret; |
||
498 | } |
||
499 | |||
500 | function removeFunctionWasm(index) { |
||
501 | functionsInTableMap.delete(wasmTable.get(index)); |
||
502 | freeTableIndexes.push(index); |
||
503 | } |
||
504 | |||
505 | // 'sig' parameter is required for the llvm backend but only when func is not |
||
506 | // already a WebAssembly function. |
||
507 | function addFunction(func, sig) { |
||
508 | assert(typeof func !== 'undefined'); |
||
509 | |||
510 | return addFunctionWasm(func, sig); |
||
511 | } |
||
512 | |||
513 | function removeFunction(index) { |
||
514 | removeFunctionWasm(index); |
||
515 | } |
||
516 | |||
517 | |||
518 | |||
519 | var funcWrappers = {}; |
||
520 | |||
521 | function getFuncWrapper(func, sig) { |
||
522 | if (!func) return; // on null pointer, return undefined |
||
523 | assert(sig); |
||
524 | if (!funcWrappers[sig]) { |
||
525 | funcWrappers[sig] = {}; |
||
526 | } |
||
527 | var sigCache = funcWrappers[sig]; |
||
528 | if (!sigCache[func]) { |
||
529 | // optimize away arguments usage in common cases |
||
530 | if (sig.length === 1) { |
||
531 | sigCache[func] = function dynCall_wrapper() { |
||
532 | return dynCall(sig, func); |
||
533 | }; |
||
534 | } else if (sig.length === 2) { |
||
535 | sigCache[func] = function dynCall_wrapper(arg) { |
||
536 | return dynCall(sig, func, [arg]); |
||
537 | }; |
||
538 | } else { |
||
539 | // general case |
||
540 | sigCache[func] = function dynCall_wrapper() { |
||
541 | return dynCall(sig, func, Array.prototype.slice.call(arguments)); |
||
542 | }; |
||
543 | } |
||
544 | } |
||
545 | return sigCache[func]; |
||
546 | } |
||
547 | |||
548 | |||
549 | |||
550 | |||
551 | |||
552 | |||
553 | |||
554 | function makeBigInt(low, high, unsigned) { |
||
555 | return unsigned ? ((+((low>>>0)))+((+((high>>>0)))*4294967296.0)) : ((+((low>>>0)))+((+((high|0)))*4294967296.0)); |
||
556 | } |
||
557 | |||
558 | /** @param {Array=} args */ |
||
559 | function dynCall(sig, ptr, args) { |
||
560 | if (args && args.length) { |
||
561 | // j (64-bit integer) must be passed in as two numbers [low 32, high 32]. |
||
562 | assert(args.length === sig.substring(1).replace(/j/g, '--').length); |
||
563 | assert(('dynCall_' + sig) in Module, 'bad function pointer type - no table for sig \'' + sig + '\''); |
||
564 | return Module['dynCall_' + sig].apply(null, [ptr].concat(args)); |
||
565 | } else { |
||
566 | assert(sig.length == 1); |
||
567 | assert(('dynCall_' + sig) in Module, 'bad function pointer type - no table for sig \'' + sig + '\''); |
||
568 | return Module['dynCall_' + sig].call(null, ptr); |
||
569 | } |
||
570 | } |
||
571 | |||
572 | var tempRet0 = 0; |
||
573 | |||
574 | var setTempRet0 = function(value) { |
||
575 | tempRet0 = value; |
||
576 | }; |
||
577 | |||
578 | var getTempRet0 = function() { |
||
579 | return tempRet0; |
||
580 | }; |
||
581 | |||
582 | function getCompilerSetting(name) { |
||
583 | throw 'You must build with -s RETAIN_COMPILER_SETTINGS=1 for getCompilerSetting or emscripten_get_compiler_setting to work'; |
||
584 | } |
||
585 | |||
586 | // The address globals begin at. Very low in memory, for code size and optimization opportunities. |
||
587 | // Above 0 is static memory, starting with globals. |
||
588 | // Then the stack. |
||
589 | // Then 'dynamic' memory for sbrk. |
||
590 | var GLOBAL_BASE = 1024; |
||
591 | |||
592 | |||
593 | |||
594 | |||
595 | |||
596 | // === Preamble library stuff === |
||
597 | |||
598 | // Documentation for the public APIs defined in this file must be updated in: |
||
599 | // site/source/docs/api_reference/preamble.js.rst |
||
600 | // A prebuilt local version of the documentation is available at: |
||
601 | // site/build/text/docs/api_reference/preamble.js.txt |
||
602 | // You can also build docs locally as HTML or other formats in site/ |
||
603 | // An online HTML version (which may be of a different version of Emscripten) |
||
604 | // is up at http://kripken.github.io/emscripten-site/docs/api_reference/preamble.js.html |
||
605 | |||
606 | |||
607 | var wasmBinary;if (Module['wasmBinary']) wasmBinary = Module['wasmBinary'];if (!Object.getOwnPropertyDescriptor(Module, 'wasmBinary')) Object.defineProperty(Module, 'wasmBinary', { configurable: true, get: function() { abort('Module.wasmBinary has been replaced with plain wasmBinary (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)') } }); |
||
608 | var noExitRuntime;if (Module['noExitRuntime']) noExitRuntime = Module['noExitRuntime'];if (!Object.getOwnPropertyDescriptor(Module, 'noExitRuntime')) Object.defineProperty(Module, 'noExitRuntime', { configurable: true, get: function() { abort('Module.noExitRuntime has been replaced with plain noExitRuntime (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)') } }); |
||
609 | |||
610 | |||
611 | if (typeof WebAssembly !== 'object') { |
||
612 | abort('No WebAssembly support found. Build with -s WASM=0 to target JavaScript instead.'); |
||
613 | } |
||
614 | |||
615 | |||
616 | |||
617 | |||
618 | // In MINIMAL_RUNTIME, setValue() and getValue() are only available when building with safe heap enabled, for heap safety checking. |
||
619 | // In traditional runtime, setValue() and getValue() are always available (although their use is highly discouraged due to perf penalties) |
||
620 | |||
621 | /** @param {number} ptr |
||
622 | @param {number} value |
||
623 | @param {string} type |
||
624 | @param {number|boolean=} noSafe */ |
||
625 | function setValue(ptr, value, type, noSafe) { |
||
626 | type = type || 'i8'; |
||
627 | if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit |
||
628 | switch(type) { |
||
629 | case 'i1': HEAP8[((ptr)>>0)]=value; break; |
||
630 | case 'i8': HEAP8[((ptr)>>0)]=value; break; |
||
631 | case 'i16': HEAP16[((ptr)>>1)]=value; break; |
||
632 | case 'i32': HEAP32[((ptr)>>2)]=value; break; |
||
633 | 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; |
||
634 | case 'float': HEAPF32[((ptr)>>2)]=value; break; |
||
635 | case 'double': HEAPF64[((ptr)>>3)]=value; break; |
||
636 | default: abort('invalid type for setValue: ' + type); |
||
637 | } |
||
638 | } |
||
639 | |||
640 | /** @param {number} ptr |
||
641 | @param {string} type |
||
642 | @param {number|boolean=} noSafe */ |
||
643 | function getValue(ptr, type, noSafe) { |
||
644 | type = type || 'i8'; |
||
645 | if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit |
||
646 | switch(type) { |
||
647 | case 'i1': return HEAP8[((ptr)>>0)]; |
||
648 | case 'i8': return HEAP8[((ptr)>>0)]; |
||
649 | case 'i16': return HEAP16[((ptr)>>1)]; |
||
650 | case 'i32': return HEAP32[((ptr)>>2)]; |
||
651 | case 'i64': return HEAP32[((ptr)>>2)]; |
||
652 | case 'float': return HEAPF32[((ptr)>>2)]; |
||
653 | case 'double': return HEAPF64[((ptr)>>3)]; |
||
654 | default: abort('invalid type for getValue: ' + type); |
||
655 | } |
||
656 | return null; |
||
657 | } |
||
658 | |||
659 | |||
660 | |||
661 | |||
662 | |||
663 | |||
664 | // Wasm globals |
||
665 | |||
666 | var wasmMemory; |
||
667 | |||
668 | // In fastcomp asm.js, we don't need a wasm Table at all. |
||
669 | // In the wasm backend, we polyfill the WebAssembly object, |
||
670 | // so this creates a (non-native-wasm) table for us. |
||
671 | var wasmTable = new WebAssembly.Table({ |
||
672 | 'initial': 10, |
||
673 | 'maximum': 10 + 0, |
||
674 | 'element': 'anyfunc' |
||
675 | }); |
||
676 | |||
677 | |||
678 | //======================================== |
||
679 | // Runtime essentials |
||
680 | //======================================== |
||
681 | |||
682 | // whether we are quitting the application. no code should run after this. |
||
683 | // set in exit() and abort() |
||
684 | var ABORT = false; |
||
685 | |||
686 | // set by exit() and abort(). Passed to 'onExit' handler. |
||
687 | // NOTE: This is also used as the process return code code in shell environments |
||
688 | // but only when noExitRuntime is false. |
||
689 | var EXITSTATUS = 0; |
||
690 | |||
691 | /** @type {function(*, string=)} */ |
||
692 | function assert(condition, text) { |
||
693 | if (!condition) { |
||
694 | abort('Assertion failed: ' + text); |
||
695 | } |
||
696 | } |
||
697 | |||
698 | // Returns the C function with a specified identifier (for C++, you need to do manual name mangling) |
||
699 | function getCFunc(ident) { |
||
700 | var func = Module['_' + ident]; // closure exported function |
||
701 | assert(func, 'Cannot call unknown function ' + ident + ', make sure it is exported'); |
||
702 | return func; |
||
703 | } |
||
704 | |||
705 | // C calling interface. |
||
706 | /** @param {string|null=} returnType |
||
707 | @param {Array=} argTypes |
||
708 | @param {Arguments|Array=} args |
||
709 | @param {Object=} opts */ |
||
710 | function ccall(ident, returnType, argTypes, args, opts) { |
||
711 | // For fast lookup of conversion functions |
||
712 | var toC = { |
||
713 | 'string': function(str) { |
||
714 | var ret = 0; |
||
715 | if (str !== null && str !== undefined && str !== 0) { // null string |
||
716 | // at most 4 bytes per UTF-8 code point, +1 for the trailing '\0' |
||
717 | var len = (str.length << 2) + 1; |
||
718 | ret = stackAlloc(len); |
||
719 | stringToUTF8(str, ret, len); |
||
720 | } |
||
721 | return ret; |
||
722 | }, |
||
723 | 'array': function(arr) { |
||
724 | var ret = stackAlloc(arr.length); |
||
725 | writeArrayToMemory(arr, ret); |
||
726 | return ret; |
||
727 | } |
||
728 | }; |
||
729 | |||
730 | function convertReturnValue(ret) { |
||
731 | if (returnType === 'string') return UTF8ToString(ret); |
||
732 | if (returnType === 'boolean') return Boolean(ret); |
||
733 | return ret; |
||
734 | } |
||
735 | |||
736 | var func = getCFunc(ident); |
||
737 | var cArgs = []; |
||
738 | var stack = 0; |
||
739 | assert(returnType !== 'array', 'Return type should not be "array".'); |
||
740 | if (args) { |
||
741 | for (var i = 0; i < args.length; i++) { |
||
742 | var converter = toC[argTypes[i]]; |
||
743 | if (converter) { |
||
744 | if (stack === 0) stack = stackSave(); |
||
745 | cArgs[i] = converter(args[i]); |
||
746 | } else { |
||
747 | cArgs[i] = args[i]; |
||
748 | } |
||
749 | } |
||
750 | } |
||
751 | var ret = func.apply(null, cArgs); |
||
752 | |||
753 | ret = convertReturnValue(ret); |
||
754 | if (stack !== 0) stackRestore(stack); |
||
755 | return ret; |
||
756 | } |
||
757 | |||
758 | /** @param {string=} returnType |
||
759 | @param {Array=} argTypes |
||
760 | @param {Object=} opts */ |
||
761 | function cwrap(ident, returnType, argTypes, opts) { |
||
762 | return function() { |
||
763 | return ccall(ident, returnType, argTypes, arguments, opts); |
||
764 | } |
||
765 | } |
||
766 | |||
767 | var ALLOC_NORMAL = 0; // Tries to use _malloc() |
||
768 | var ALLOC_STACK = 1; // Lives for the duration of the current function call |
||
769 | var ALLOC_DYNAMIC = 2; // Cannot be freed except through sbrk |
||
770 | var ALLOC_NONE = 3; // Do not allocate |
||
771 | |||
772 | // allocate(): This is for internal use. You can use it yourself as well, but the interface |
||
773 | // is a little tricky (see docs right below). The reason is that it is optimized |
||
774 | // for multiple syntaxes to save space in generated code. So you should |
||
775 | // normally not use allocate(), and instead allocate memory using _malloc(), |
||
776 | // initialize it with setValue(), and so forth. |
||
777 | // @slab: An array of data, or a number. If a number, then the size of the block to allocate, |
||
778 | // in *bytes* (note that this is sometimes confusing: the next parameter does not |
||
779 | // affect this!) |
||
780 | // @types: Either an array of types, one for each byte (or 0 if no type at that position), |
||
781 | // or a single type which is used for the entire block. This only matters if there |
||
782 | // is initial data - if @slab is a number, then this does not matter at all and is |
||
783 | // ignored. |
||
784 | // @allocator: How to allocate memory, see ALLOC_* |
||
785 | /** @type {function((TypedArray|Array<number>|number), string, number, number=)} */ |
||
786 | function allocate(slab, types, allocator, ptr) { |
||
787 | var zeroinit, size; |
||
788 | if (typeof slab === 'number') { |
||
789 | zeroinit = true; |
||
790 | size = slab; |
||
791 | } else { |
||
792 | zeroinit = false; |
||
793 | size = slab.length; |
||
794 | } |
||
795 | |||
796 | var singleType = typeof types === 'string' ? types : null; |
||
797 | |||
798 | var ret; |
||
799 | if (allocator == ALLOC_NONE) { |
||
800 | ret = ptr; |
||
801 | } else { |
||
802 | ret = [_malloc, |
||
803 | stackAlloc, |
||
804 | dynamicAlloc][allocator](Math.max(size, singleType ? 1 : types.length)); |
||
805 | } |
||
806 | |||
807 | if (zeroinit) { |
||
808 | var stop; |
||
809 | ptr = ret; |
||
810 | assert((ret & 3) == 0); |
||
811 | stop = ret + (size & ~3); |
||
812 | for (; ptr < stop; ptr += 4) { |
||
813 | HEAP32[((ptr)>>2)]=0; |
||
814 | } |
||
815 | stop = ret + size; |
||
816 | while (ptr < stop) { |
||
817 | HEAP8[((ptr++)>>0)]=0; |
||
818 | } |
||
819 | return ret; |
||
820 | } |
||
821 | |||
822 | if (singleType === 'i8') { |
||
823 | if (slab.subarray || slab.slice) { |
||
824 | HEAPU8.set(/** @type {!Uint8Array} */ (slab), ret); |
||
825 | } else { |
||
826 | HEAPU8.set(new Uint8Array(slab), ret); |
||
827 | } |
||
828 | return ret; |
||
829 | } |
||
830 | |||
831 | var i = 0, type, typeSize, previousType; |
||
832 | while (i < size) { |
||
833 | var curr = slab[i]; |
||
834 | |||
835 | type = singleType || types[i]; |
||
836 | if (type === 0) { |
||
837 | i++; |
||
838 | continue; |
||
839 | } |
||
840 | assert(type, 'Must know what type to store in allocate!'); |
||
841 | |||
842 | if (type == 'i64') type = 'i32'; // special case: we have one i32 here, and one i32 later |
||
843 | |||
844 | setValue(ret+i, curr, type); |
||
845 | |||
846 | // no need to look up size unless type changes, so cache it |
||
847 | if (previousType !== type) { |
||
848 | typeSize = getNativeTypeSize(type); |
||
849 | previousType = type; |
||
850 | } |
||
851 | i += typeSize; |
||
852 | } |
||
853 | |||
854 | return ret; |
||
855 | } |
||
856 | |||
857 | // Allocate memory during any stage of startup - static memory early on, dynamic memory later, malloc when ready |
||
858 | function getMemory(size) { |
||
859 | if (!runtimeInitialized) return dynamicAlloc(size); |
||
860 | return _malloc(size); |
||
861 | } |
||
862 | |||
863 | |||
864 | |||
865 | |||
866 | // runtime_strings.js: Strings related runtime functions that are part of both MINIMAL_RUNTIME and regular runtime. |
||
867 | |||
868 | // Given a pointer 'ptr' to a null-terminated UTF8-encoded string in the given array that contains uint8 values, returns |
||
869 | // a copy of that string as a Javascript String object. |
||
870 | |||
871 | var UTF8Decoder = typeof TextDecoder !== 'undefined' ? new TextDecoder('utf8') : undefined; |
||
872 | |||
873 | /** |
||
874 | * @param {number} idx |
||
875 | * @param {number=} maxBytesToRead |
||
876 | * @return {string} |
||
877 | */ |
||
878 | function UTF8ArrayToString(heap, idx, maxBytesToRead) { |
||
879 | var endIdx = idx + maxBytesToRead; |
||
880 | var endPtr = idx; |
||
881 | // TextDecoder needs to know the byte length in advance, it doesn't stop on null terminator by itself. |
||
882 | // Also, use the length info to avoid running tiny strings through TextDecoder, since .subarray() allocates garbage. |
||
883 | // (As a tiny code save trick, compare endPtr against endIdx using a negation, so that undefined means Infinity) |
||
884 | while (heap[endPtr] && !(endPtr >= endIdx)) ++endPtr; |
||
885 | |||
886 | if (endPtr - idx > 16 && heap.subarray && UTF8Decoder) { |
||
887 | return UTF8Decoder.decode(heap.subarray(idx, endPtr)); |
||
888 | } else { |
||
889 | var str = ''; |
||
890 | // If building with TextDecoder, we have already computed the string length above, so test loop end condition against that |
||
891 | while (idx < endPtr) { |
||
892 | // For UTF8 byte structure, see: |
||
893 | // http://en.wikipedia.org/wiki/UTF-8#Description |
||
894 | // https://www.ietf.org/rfc/rfc2279.txt |
||
895 | // https://tools.ietf.org/html/rfc3629 |
||
896 | var u0 = heap[idx++]; |
||
897 | if (!(u0 & 0x80)) { str += String.fromCharCode(u0); continue; } |
||
898 | var u1 = heap[idx++] & 63; |
||
899 | if ((u0 & 0xE0) == 0xC0) { str += String.fromCharCode(((u0 & 31) << 6) | u1); continue; } |
||
900 | var u2 = heap[idx++] & 63; |
||
901 | if ((u0 & 0xF0) == 0xE0) { |
||
902 | u0 = ((u0 & 15) << 12) | (u1 << 6) | u2; |
||
903 | } else { |
||
904 | if ((u0 & 0xF8) != 0xF0) warnOnce('Invalid UTF-8 leading byte 0x' + u0.toString(16) + ' encountered when deserializing a UTF-8 string on the asm.js/wasm heap to a JS string!'); |
||
905 | u0 = ((u0 & 7) << 18) | (u1 << 12) | (u2 << 6) | (heap[idx++] & 63); |
||
906 | } |
||
907 | |||
908 | if (u0 < 0x10000) { |
||
909 | str += String.fromCharCode(u0); |
||
910 | } else { |
||
911 | var ch = u0 - 0x10000; |
||
912 | str += String.fromCharCode(0xD800 | (ch >> 10), 0xDC00 | (ch & 0x3FF)); |
||
913 | } |
||
914 | } |
||
915 | } |
||
916 | return str; |
||
917 | } |
||
918 | |||
919 | // Given a pointer 'ptr' to a null-terminated UTF8-encoded string in the emscripten HEAP, returns a |
||
920 | // copy of that string as a Javascript String object. |
||
921 | // maxBytesToRead: an optional length that specifies the maximum number of bytes to read. You can omit |
||
922 | // this parameter to scan the string until the first \0 byte. If maxBytesToRead is |
||
923 | // passed, and the string at [ptr, ptr+maxBytesToReadr[ contains a null byte in the |
||
924 | // middle, then the string will cut short at that byte index (i.e. maxBytesToRead will |
||
925 | // not produce a string of exact length [ptr, ptr+maxBytesToRead[) |
||
926 | // N.B. mixing frequent uses of UTF8ToString() with and without maxBytesToRead may |
||
927 | // throw JS JIT optimizations off, so it is worth to consider consistently using one |
||
928 | // style or the other. |
||
929 | /** |
||
930 | * @param {number} ptr |
||
931 | * @param {number=} maxBytesToRead |
||
932 | * @return {string} |
||
933 | */ |
||
934 | function UTF8ToString(ptr, maxBytesToRead) { |
||
935 | return ptr ? UTF8ArrayToString(HEAPU8, ptr, maxBytesToRead) : ''; |
||
936 | } |
||
937 | |||
938 | // Copies the given Javascript String object 'str' to the given byte array at address 'outIdx', |
||
939 | // encoded in UTF8 form and null-terminated. The copy will require at most str.length*4+1 bytes of space in the HEAP. |
||
940 | // Use the function lengthBytesUTF8 to compute the exact number of bytes (excluding null terminator) that this function will write. |
||
941 | // Parameters: |
||
942 | // str: the Javascript string to copy. |
||
943 | // heap: the array to copy to. Each index in this array is assumed to be one 8-byte element. |
||
944 | // outIdx: The starting offset in the array to begin the copying. |
||
945 | // maxBytesToWrite: The maximum number of bytes this function can write to the array. |
||
946 | // This count should include the null terminator, |
||
947 | // i.e. if maxBytesToWrite=1, only the null terminator will be written and nothing else. |
||
948 | // maxBytesToWrite=0 does not write any bytes to the output, not even the null terminator. |
||
949 | // Returns the number of bytes written, EXCLUDING the null terminator. |
||
950 | |||
951 | function stringToUTF8Array(str, heap, outIdx, maxBytesToWrite) { |
||
952 | if (!(maxBytesToWrite > 0)) // Parameter maxBytesToWrite is not optional. Negative values, 0, null, undefined and false each don't write out any bytes. |
||
953 | return 0; |
||
954 | |||
955 | var startIdx = outIdx; |
||
956 | var endIdx = outIdx + maxBytesToWrite - 1; // -1 for string null terminator. |
||
957 | for (var i = 0; i < str.length; ++i) { |
||
958 | // 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. |
||
959 | // See http://unicode.org/faq/utf_bom.html#utf16-3 |
||
960 | // 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 |
||
961 | var u = str.charCodeAt(i); // possibly a lead surrogate |
||
962 | if (u >= 0xD800 && u <= 0xDFFF) { |
||
963 | var u1 = str.charCodeAt(++i); |
||
964 | u = 0x10000 + ((u & 0x3FF) << 10) | (u1 & 0x3FF); |
||
965 | } |
||
966 | if (u <= 0x7F) { |
||
967 | if (outIdx >= endIdx) break; |
||
968 | heap[outIdx++] = u; |
||
969 | } else if (u <= 0x7FF) { |
||
970 | if (outIdx + 1 >= endIdx) break; |
||
971 | heap[outIdx++] = 0xC0 | (u >> 6); |
||
972 | heap[outIdx++] = 0x80 | (u & 63); |
||
973 | } else if (u <= 0xFFFF) { |
||
974 | if (outIdx + 2 >= endIdx) break; |
||
975 | heap[outIdx++] = 0xE0 | (u >> 12); |
||
976 | heap[outIdx++] = 0x80 | ((u >> 6) & 63); |
||
977 | heap[outIdx++] = 0x80 | (u & 63); |
||
978 | } else { |
||
979 | if (outIdx + 3 >= endIdx) break; |
||
980 | if (u >= 0x200000) warnOnce('Invalid Unicode code point 0x' + u.toString(16) + ' encountered when serializing a JS string to an UTF-8 string on the asm.js/wasm heap! (Valid unicode code points should be in range 0-0x1FFFFF).'); |
||
981 | heap[outIdx++] = 0xF0 | (u >> 18); |
||
982 | heap[outIdx++] = 0x80 | ((u >> 12) & 63); |
||
983 | heap[outIdx++] = 0x80 | ((u >> 6) & 63); |
||
984 | heap[outIdx++] = 0x80 | (u & 63); |
||
985 | } |
||
986 | } |
||
987 | // Null-terminate the pointer to the buffer. |
||
988 | heap[outIdx] = 0; |
||
989 | return outIdx - startIdx; |
||
990 | } |
||
991 | |||
992 | // Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr', |
||
993 | // null-terminated and encoded in UTF8 form. The copy will require at most str.length*4+1 bytes of space in the HEAP. |
||
994 | // Use the function lengthBytesUTF8 to compute the exact number of bytes (excluding null terminator) that this function will write. |
||
995 | // Returns the number of bytes written, EXCLUDING the null terminator. |
||
996 | |||
997 | function stringToUTF8(str, outPtr, maxBytesToWrite) { |
||
998 | assert(typeof maxBytesToWrite == 'number', 'stringToUTF8(str, outPtr, maxBytesToWrite) is missing the third parameter that specifies the length of the output buffer!'); |
||
999 | return stringToUTF8Array(str, HEAPU8,outPtr, maxBytesToWrite); |
||
1000 | } |
||
1001 | |||
1002 | // Returns the number of bytes the given Javascript string takes if encoded as a UTF8 byte array, EXCLUDING the null terminator byte. |
||
1003 | function lengthBytesUTF8(str) { |
||
1004 | var len = 0; |
||
1005 | for (var i = 0; i < str.length; ++i) { |
||
1006 | // 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. |
||
1007 | // See http://unicode.org/faq/utf_bom.html#utf16-3 |
||
1008 | var u = str.charCodeAt(i); // possibly a lead surrogate |
||
1009 | if (u >= 0xD800 && u <= 0xDFFF) u = 0x10000 + ((u & 0x3FF) << 10) | (str.charCodeAt(++i) & 0x3FF); |
||
1010 | if (u <= 0x7F) ++len; |
||
1011 | else if (u <= 0x7FF) len += 2; |
||
1012 | else if (u <= 0xFFFF) len += 3; |
||
1013 | else len += 4; |
||
1014 | } |
||
1015 | return len; |
||
1016 | } |
||
1017 | |||
1018 | |||
1019 | |||
1020 | |||
1021 | |||
1022 | // runtime_strings_extra.js: Strings related runtime functions that are available only in regular runtime. |
||
1023 | |||
1024 | // Given a pointer 'ptr' to a null-terminated ASCII-encoded string in the emscripten HEAP, returns |
||
1025 | // a copy of that string as a Javascript String object. |
||
1026 | |||
1027 | function AsciiToString(ptr) { |
||
1028 | var str = ''; |
||
1029 | while (1) { |
||
1030 | var ch = HEAPU8[((ptr++)>>0)]; |
||
1031 | if (!ch) return str; |
||
1032 | str += String.fromCharCode(ch); |
||
1033 | } |
||
1034 | } |
||
1035 | |||
1036 | // Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr', |
||
1037 | // null-terminated and encoded in ASCII form. The copy will require at most str.length+1 bytes of space in the HEAP. |
||
1038 | |||
1039 | function stringToAscii(str, outPtr) { |
||
1040 | return writeAsciiToMemory(str, outPtr, false); |
||
1041 | } |
||
1042 | |||
1043 | // Given a pointer 'ptr' to a null-terminated UTF16LE-encoded string in the emscripten HEAP, returns |
||
1044 | // a copy of that string as a Javascript String object. |
||
1045 | |||
1046 | var UTF16Decoder = typeof TextDecoder !== 'undefined' ? new TextDecoder('utf-16le') : undefined; |
||
1047 | |||
1048 | function UTF16ToString(ptr, maxBytesToRead) { |
||
1049 | assert(ptr % 2 == 0, 'Pointer passed to UTF16ToString must be aligned to two bytes!'); |
||
1050 | var endPtr = ptr; |
||
1051 | // TextDecoder needs to know the byte length in advance, it doesn't stop on null terminator by itself. |
||
1052 | // Also, use the length info to avoid running tiny strings through TextDecoder, since .subarray() allocates garbage. |
||
1053 | var idx = endPtr >> 1; |
||
1054 | var maxIdx = idx + maxBytesToRead / 2; |
||
1055 | // If maxBytesToRead is not passed explicitly, it will be undefined, and this |
||
1056 | // will always evaluate to true. This saves on code size. |
||
1057 | while (!(idx >= maxIdx) && HEAPU16[idx]) ++idx; |
||
1058 | endPtr = idx << 1; |
||
1059 | |||
1060 | if (endPtr - ptr > 32 && UTF16Decoder) { |
||
1061 | return UTF16Decoder.decode(HEAPU8.subarray(ptr, endPtr)); |
||
1062 | } else { |
||
1063 | var i = 0; |
||
1064 | |||
1065 | var str = ''; |
||
1066 | while (1) { |
||
1067 | var codeUnit = HEAP16[(((ptr)+(i*2))>>1)]; |
||
1068 | if (codeUnit == 0 || i == maxBytesToRead / 2) return str; |
||
1069 | ++i; |
||
1070 | // fromCharCode constructs a character from a UTF-16 code unit, so we can pass the UTF16 string right through. |
||
1071 | str += String.fromCharCode(codeUnit); |
||
1072 | } |
||
1073 | } |
||
1074 | } |
||
1075 | |||
1076 | // Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr', |
||
1077 | // null-terminated and encoded in UTF16 form. The copy will require at most str.length*4+2 bytes of space in the HEAP. |
||
1078 | // Use the function lengthBytesUTF16() to compute the exact number of bytes (excluding null terminator) that this function will write. |
||
1079 | // Parameters: |
||
1080 | // str: the Javascript string to copy. |
||
1081 | // outPtr: Byte address in Emscripten HEAP where to write the string to. |
||
1082 | // maxBytesToWrite: The maximum number of bytes this function can write to the array. This count should include the null |
||
1083 | // terminator, i.e. if maxBytesToWrite=2, only the null terminator will be written and nothing else. |
||
1084 | // maxBytesToWrite<2 does not write any bytes to the output, not even the null terminator. |
||
1085 | // Returns the number of bytes written, EXCLUDING the null terminator. |
||
1086 | |||
1087 | function stringToUTF16(str, outPtr, maxBytesToWrite) { |
||
1088 | assert(outPtr % 2 == 0, 'Pointer passed to stringToUTF16 must be aligned to two bytes!'); |
||
1089 | assert(typeof maxBytesToWrite == 'number', 'stringToUTF16(str, outPtr, maxBytesToWrite) is missing the third parameter that specifies the length of the output buffer!'); |
||
1090 | // Backwards compatibility: if max bytes is not specified, assume unsafe unbounded write is allowed. |
||
1091 | if (maxBytesToWrite === undefined) { |
||
1092 | maxBytesToWrite = 0x7FFFFFFF; |
||
1093 | } |
||
1094 | if (maxBytesToWrite < 2) return 0; |
||
1095 | maxBytesToWrite -= 2; // Null terminator. |
||
1096 | var startPtr = outPtr; |
||
1097 | var numCharsToWrite = (maxBytesToWrite < str.length*2) ? (maxBytesToWrite / 2) : str.length; |
||
1098 | for (var i = 0; i < numCharsToWrite; ++i) { |
||
1099 | // charCodeAt returns a UTF-16 encoded code unit, so it can be directly written to the HEAP. |
||
1100 | var codeUnit = str.charCodeAt(i); // possibly a lead surrogate |
||
1101 | HEAP16[((outPtr)>>1)]=codeUnit; |
||
1102 | outPtr += 2; |
||
1103 | } |
||
1104 | // Null-terminate the pointer to the HEAP. |
||
1105 | HEAP16[((outPtr)>>1)]=0; |
||
1106 | return outPtr - startPtr; |
||
1107 | } |
||
1108 | |||
1109 | // Returns the number of bytes the given Javascript string takes if encoded as a UTF16 byte array, EXCLUDING the null terminator byte. |
||
1110 | |||
1111 | function lengthBytesUTF16(str) { |
||
1112 | return str.length*2; |
||
1113 | } |
||
1114 | |||
1115 | function UTF32ToString(ptr, maxBytesToRead) { |
||
1116 | assert(ptr % 4 == 0, 'Pointer passed to UTF32ToString must be aligned to four bytes!'); |
||
1117 | var i = 0; |
||
1118 | |||
1119 | var str = ''; |
||
1120 | // If maxBytesToRead is not passed explicitly, it will be undefined, and this |
||
1121 | // will always evaluate to true. This saves on code size. |
||
1122 | while (!(i >= maxBytesToRead / 4)) { |
||
1123 | var utf32 = HEAP32[(((ptr)+(i*4))>>2)]; |
||
1124 | if (utf32 == 0) break; |
||
1125 | ++i; |
||
1126 | // 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. |
||
1127 | // See http://unicode.org/faq/utf_bom.html#utf16-3 |
||
1128 | if (utf32 >= 0x10000) { |
||
1129 | var ch = utf32 - 0x10000; |
||
1130 | str += String.fromCharCode(0xD800 | (ch >> 10), 0xDC00 | (ch & 0x3FF)); |
||
1131 | } else { |
||
1132 | str += String.fromCharCode(utf32); |
||
1133 | } |
||
1134 | } |
||
1135 | return str; |
||
1136 | } |
||
1137 | |||
1138 | // Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr', |
||
1139 | // null-terminated and encoded in UTF32 form. The copy will require at most str.length*4+4 bytes of space in the HEAP. |
||
1140 | // Use the function lengthBytesUTF32() to compute the exact number of bytes (excluding null terminator) that this function will write. |
||
1141 | // Parameters: |
||
1142 | // str: the Javascript string to copy. |
||
1143 | // outPtr: Byte address in Emscripten HEAP where to write the string to. |
||
1144 | // maxBytesToWrite: The maximum number of bytes this function can write to the array. This count should include the null |
||
1145 | // terminator, i.e. if maxBytesToWrite=4, only the null terminator will be written and nothing else. |
||
1146 | // maxBytesToWrite<4 does not write any bytes to the output, not even the null terminator. |
||
1147 | // Returns the number of bytes written, EXCLUDING the null terminator. |
||
1148 | |||
1149 | function stringToUTF32(str, outPtr, maxBytesToWrite) { |
||
1150 | assert(outPtr % 4 == 0, 'Pointer passed to stringToUTF32 must be aligned to four bytes!'); |
||
1151 | assert(typeof maxBytesToWrite == 'number', 'stringToUTF32(str, outPtr, maxBytesToWrite) is missing the third parameter that specifies the length of the output buffer!'); |
||
1152 | // Backwards compatibility: if max bytes is not specified, assume unsafe unbounded write is allowed. |
||
1153 | if (maxBytesToWrite === undefined) { |
||
1154 | maxBytesToWrite = 0x7FFFFFFF; |
||
1155 | } |
||
1156 | if (maxBytesToWrite < 4) return 0; |
||
1157 | var startPtr = outPtr; |
||
1158 | var endPtr = startPtr + maxBytesToWrite - 4; |
||
1159 | for (var i = 0; i < str.length; ++i) { |
||
1160 | // 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. |
||
1161 | // See http://unicode.org/faq/utf_bom.html#utf16-3 |
||
1162 | var codeUnit = str.charCodeAt(i); // possibly a lead surrogate |
||
1163 | if (codeUnit >= 0xD800 && codeUnit <= 0xDFFF) { |
||
1164 | var trailSurrogate = str.charCodeAt(++i); |
||
1165 | codeUnit = 0x10000 + ((codeUnit & 0x3FF) << 10) | (trailSurrogate & 0x3FF); |
||
1166 | } |
||
1167 | HEAP32[((outPtr)>>2)]=codeUnit; |
||
1168 | outPtr += 4; |
||
1169 | if (outPtr + 4 > endPtr) break; |
||
1170 | } |
||
1171 | // Null-terminate the pointer to the HEAP. |
||
1172 | HEAP32[((outPtr)>>2)]=0; |
||
1173 | return outPtr - startPtr; |
||
1174 | } |
||
1175 | |||
1176 | // Returns the number of bytes the given Javascript string takes if encoded as a UTF16 byte array, EXCLUDING the null terminator byte. |
||
1177 | |||
1178 | function lengthBytesUTF32(str) { |
||
1179 | var len = 0; |
||
1180 | for (var i = 0; i < str.length; ++i) { |
||
1181 | // 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. |
||
1182 | // See http://unicode.org/faq/utf_bom.html#utf16-3 |
||
1183 | var codeUnit = str.charCodeAt(i); |
||
1184 | if (codeUnit >= 0xD800 && codeUnit <= 0xDFFF) ++i; // possibly a lead surrogate, so skip over the tail surrogate. |
||
1185 | len += 4; |
||
1186 | } |
||
1187 | |||
1188 | return len; |
||
1189 | } |
||
1190 | |||
1191 | // Allocate heap space for a JS string, and write it there. |
||
1192 | // It is the responsibility of the caller to free() that memory. |
||
1193 | function allocateUTF8(str) { |
||
1194 | var size = lengthBytesUTF8(str) + 1; |
||
1195 | var ret = _malloc(size); |
||
1196 | if (ret) stringToUTF8Array(str, HEAP8, ret, size); |
||
1197 | return ret; |
||
1198 | } |
||
1199 | |||
1200 | // Allocate stack space for a JS string, and write it there. |
||
1201 | function allocateUTF8OnStack(str) { |
||
1202 | var size = lengthBytesUTF8(str) + 1; |
||
1203 | var ret = stackAlloc(size); |
||
1204 | stringToUTF8Array(str, HEAP8, ret, size); |
||
1205 | return ret; |
||
1206 | } |
||
1207 | |||
1208 | // Deprecated: This function should not be called because it is unsafe and does not provide |
||
1209 | // a maximum length limit of how many bytes it is allowed to write. Prefer calling the |
||
1210 | // function stringToUTF8Array() instead, which takes in a maximum length that can be used |
||
1211 | // to be secure from out of bounds writes. |
||
1212 | /** @deprecated |
||
1213 | @param {boolean=} dontAddNull */ |
||
1214 | function writeStringToMemory(string, buffer, dontAddNull) { |
||
1215 | warnOnce('writeStringToMemory is deprecated and should not be called! Use stringToUTF8() instead!'); |
||
1216 | |||
1217 | var /** @type {number} */ lastChar, /** @type {number} */ end; |
||
1218 | if (dontAddNull) { |
||
1219 | // stringToUTF8Array always appends null. If we don't want to do that, remember the |
||
1220 | // character that existed at the location where the null will be placed, and restore |
||
1221 | // that after the write (below). |
||
1222 | end = buffer + lengthBytesUTF8(string); |
||
1223 | lastChar = HEAP8[end]; |
||
1224 | } |
||
1225 | stringToUTF8(string, buffer, Infinity); |
||
1226 | if (dontAddNull) HEAP8[end] = lastChar; // Restore the value under the null character. |
||
1227 | } |
||
1228 | |||
1229 | function writeArrayToMemory(array, buffer) { |
||
1230 | assert(array.length >= 0, 'writeArrayToMemory array must have a length (should be an array or typed array)') |
||
1231 | HEAP8.set(array, buffer); |
||
1232 | } |
||
1233 | |||
1234 | /** @param {boolean=} dontAddNull */ |
||
1235 | function writeAsciiToMemory(str, buffer, dontAddNull) { |
||
1236 | for (var i = 0; i < str.length; ++i) { |
||
1237 | assert(str.charCodeAt(i) === str.charCodeAt(i)&0xff); |
||
1238 | HEAP8[((buffer++)>>0)]=str.charCodeAt(i); |
||
1239 | } |
||
1240 | // Null-terminate the pointer to the HEAP. |
||
1241 | if (!dontAddNull) HEAP8[((buffer)>>0)]=0; |
||
1242 | } |
||
1243 | |||
1244 | |||
1245 | |||
1246 | // Memory management |
||
1247 | |||
1248 | var PAGE_SIZE = 16384; |
||
1249 | var WASM_PAGE_SIZE = 65536; |
||
1250 | var ASMJS_PAGE_SIZE = 16777216; |
||
1251 | |||
1252 | function alignUp(x, multiple) { |
||
1253 | if (x % multiple > 0) { |
||
1254 | x += multiple - (x % multiple); |
||
1255 | } |
||
1256 | return x; |
||
1257 | } |
||
1258 | |||
1259 | var HEAP, |
||
1260 | /** @type {ArrayBuffer} */ |
||
1261 | buffer, |
||
1262 | /** @type {Int8Array} */ |
||
1263 | HEAP8, |
||
1264 | /** @type {Uint8Array} */ |
||
1265 | HEAPU8, |
||
1266 | /** @type {Int16Array} */ |
||
1267 | HEAP16, |
||
1268 | /** @type {Uint16Array} */ |
||
1269 | HEAPU16, |
||
1270 | /** @type {Int32Array} */ |
||
1271 | HEAP32, |
||
1272 | /** @type {Uint32Array} */ |
||
1273 | HEAPU32, |
||
1274 | /** @type {Float32Array} */ |
||
1275 | HEAPF32, |
||
1276 | /** @type {Float64Array} */ |
||
1277 | HEAPF64; |
||
1278 | |||
1279 | function updateGlobalBufferAndViews(buf) { |
||
1280 | buffer = buf; |
||
1281 | Module['HEAP8'] = HEAP8 = new Int8Array(buf); |
||
1282 | Module['HEAP16'] = HEAP16 = new Int16Array(buf); |
||
1283 | Module['HEAP32'] = HEAP32 = new Int32Array(buf); |
||
1284 | Module['HEAPU8'] = HEAPU8 = new Uint8Array(buf); |
||
1285 | Module['HEAPU16'] = HEAPU16 = new Uint16Array(buf); |
||
1286 | Module['HEAPU32'] = HEAPU32 = new Uint32Array(buf); |
||
1287 | Module['HEAPF32'] = HEAPF32 = new Float32Array(buf); |
||
1288 | Module['HEAPF64'] = HEAPF64 = new Float64Array(buf); |
||
1289 | } |
||
1290 | |||
1291 | var STATIC_BASE = 1024, |
||
1292 | STACK_BASE = 6013600, |
||
1293 | STACKTOP = STACK_BASE, |
||
1294 | STACK_MAX = 770720, |
||
1295 | DYNAMIC_BASE = 6013600, |
||
1296 | DYNAMICTOP_PTR = 770560; |
||
1297 | |||
1298 | assert(STACK_BASE % 16 === 0, 'stack must start aligned'); |
||
1299 | assert(DYNAMIC_BASE % 16 === 0, 'heap must start aligned'); |
||
1300 | |||
1301 | |||
1302 | var TOTAL_STACK = 5242880; |
||
1303 | if (Module['TOTAL_STACK']) assert(TOTAL_STACK === Module['TOTAL_STACK'], 'the stack size can no longer be determined at runtime') |
||
1304 | |||
1305 | var INITIAL_INITIAL_MEMORY = Module['INITIAL_MEMORY'] || 16777216;if (!Object.getOwnPropertyDescriptor(Module, 'INITIAL_MEMORY')) Object.defineProperty(Module, 'INITIAL_MEMORY', { configurable: true, get: function() { abort('Module.INITIAL_MEMORY has been replaced with plain INITIAL_INITIAL_MEMORY (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)') } }); |
||
1306 | |||
1307 | assert(INITIAL_INITIAL_MEMORY >= TOTAL_STACK, 'INITIAL_MEMORY should be larger than TOTAL_STACK, was ' + INITIAL_INITIAL_MEMORY + '! (TOTAL_STACK=' + TOTAL_STACK + ')'); |
||
1308 | |||
1309 | // check for full engine support (use string 'subarray' to avoid closure compiler confusion) |
||
1310 | assert(typeof Int32Array !== 'undefined' && typeof Float64Array !== 'undefined' && Int32Array.prototype.subarray !== undefined && Int32Array.prototype.set !== undefined, |
||
1311 | 'JS engine does not provide full typed array support'); |
||
1312 | |||
1313 | |||
1314 | |||
1315 | |||
1316 | |||
1317 | |||
1318 | |||
1319 | |||
1320 | // In non-standalone/normal mode, we create the memory here. |
||
1321 | |||
1322 | |||
1323 | |||
1324 | // Create the main memory. (Note: this isn't used in STANDALONE_WASM mode since the wasm |
||
1325 | // memory is created in the wasm, not in JS.) |
||
1326 | |||
1327 | if (Module['wasmMemory']) { |
||
1328 | wasmMemory = Module['wasmMemory']; |
||
1329 | } else |
||
1330 | { |
||
1331 | wasmMemory = new WebAssembly.Memory({ |
||
1332 | 'initial': INITIAL_INITIAL_MEMORY / WASM_PAGE_SIZE |
||
1333 | , |
||
1334 | 'maximum': INITIAL_INITIAL_MEMORY / WASM_PAGE_SIZE |
||
1335 | }); |
||
1336 | } |
||
1337 | |||
1338 | |||
1339 | if (wasmMemory) { |
||
1340 | buffer = wasmMemory.buffer; |
||
1341 | } |
||
1342 | |||
1343 | // If the user provides an incorrect length, just use that length instead rather than providing the user to |
||
1344 | // specifically provide the memory length with Module['INITIAL_MEMORY']. |
||
1345 | INITIAL_INITIAL_MEMORY = buffer.byteLength; |
||
1346 | assert(INITIAL_INITIAL_MEMORY % WASM_PAGE_SIZE === 0); |
||
1347 | updateGlobalBufferAndViews(buffer); |
||
1348 | |||
1349 | HEAP32[DYNAMICTOP_PTR>>2] = DYNAMIC_BASE; |
||
1350 | |||
1351 | |||
1352 | |||
1353 | |||
1354 | |||
1355 | |||
1356 | // Initializes the stack cookie. Called at the startup of main and at the startup of each thread in pthreads mode. |
||
1357 | function writeStackCookie() { |
||
1358 | assert((STACK_MAX & 3) == 0); |
||
1359 | // The stack grows downwards |
||
1360 | HEAPU32[(STACK_MAX >> 2)+1] = 0x2135467; |
||
1361 | HEAPU32[(STACK_MAX >> 2)+2] = 0x89BACDFE; |
||
1362 | // Also test the global address 0 for integrity. |
||
1363 | // We don't do this with ASan because ASan does its own checks for this. |
||
1364 | HEAP32[0] = 0x63736d65; /* 'emsc' */ |
||
1365 | } |
||
1366 | |||
1367 | function checkStackCookie() { |
||
1368 | var cookie1 = HEAPU32[(STACK_MAX >> 2)+1]; |
||
1369 | var cookie2 = HEAPU32[(STACK_MAX >> 2)+2]; |
||
1370 | if (cookie1 != 0x2135467 || cookie2 != 0x89BACDFE) { |
||
1371 | abort('Stack overflow! Stack cookie has been overwritten, expected hex dwords 0x89BACDFE and 0x2135467, but received 0x' + cookie2.toString(16) + ' ' + cookie1.toString(16)); |
||
1372 | } |
||
1373 | // Also test the global address 0 for integrity. |
||
1374 | // We don't do this with ASan because ASan does its own checks for this. |
||
1375 | if (HEAP32[0] !== 0x63736d65 /* 'emsc' */) abort('Runtime error: The application has corrupted its heap memory area (address zero)!'); |
||
1376 | } |
||
1377 | |||
1378 | |||
1379 | |||
1380 | |||
1381 | |||
1382 | // Endianness check (note: assumes compiler arch was little-endian) |
||
1383 | (function() { |
||
1384 | var h16 = new Int16Array(1); |
||
1385 | var h8 = new Int8Array(h16.buffer); |
||
1386 | h16[0] = 0x6373; |
||
1387 | if (h8[0] !== 0x73 || h8[1] !== 0x63) throw 'Runtime error: expected the system to be little-endian!'; |
||
1388 | })(); |
||
1389 | |||
1390 | function abortFnPtrError(ptr, sig) { |
||
1391 | abort("Invalid function pointer " + ptr + " called with signature '" + sig + "'. Perhaps this is an invalid value (e.g. caused by calling a virtual method on a NULL pointer)? Or calling a function with an incorrect type, which will fail? (it is worth building your source files with -Werror (warnings are errors), as warnings can indicate undefined behavior which can cause this). Build with ASSERTIONS=2 for more info."); |
||
1392 | } |
||
1393 | |||
1394 | |||
1395 | |||
1396 | function callRuntimeCallbacks(callbacks) { |
||
1397 | while(callbacks.length > 0) { |
||
1398 | var callback = callbacks.shift(); |
||
1399 | if (typeof callback == 'function') { |
||
1400 | callback(Module); // Pass the module as the first argument. |
||
1401 | continue; |
||
1402 | } |
||
1403 | var func = callback.func; |
||
1404 | if (typeof func === 'number') { |
||
1405 | if (callback.arg === undefined) { |
||
1406 | Module['dynCall_v'](func); |
||
1407 | } else { |
||
1408 | Module['dynCall_vi'](func, callback.arg); |
||
1409 | } |
||
1410 | } else { |
||
1411 | func(callback.arg === undefined ? null : callback.arg); |
||
1412 | } |
||
1413 | } |
||
1414 | } |
||
1415 | |||
1416 | var __ATPRERUN__ = []; // functions called before the runtime is initialized |
||
1417 | var __ATINIT__ = []; // functions called during startup |
||
1418 | var __ATMAIN__ = []; // functions called when main() is to be run |
||
1419 | var __ATEXIT__ = []; // functions called during shutdown |
||
1420 | var __ATPOSTRUN__ = []; // functions called after the main() is called |
||
1421 | |||
1422 | var runtimeInitialized = false; |
||
1423 | var runtimeExited = false; |
||
1424 | |||
1425 | |||
1426 | function preRun() { |
||
1427 | |||
1428 | if (Module['preRun']) { |
||
1429 | if (typeof Module['preRun'] == 'function') Module['preRun'] = [Module['preRun']]; |
||
1430 | while (Module['preRun'].length) { |
||
1431 | addOnPreRun(Module['preRun'].shift()); |
||
1432 | } |
||
1433 | } |
||
1434 | |||
1435 | callRuntimeCallbacks(__ATPRERUN__); |
||
1436 | } |
||
1437 | |||
1438 | function initRuntime() { |
||
1439 | checkStackCookie(); |
||
1440 | assert(!runtimeInitialized); |
||
1441 | runtimeInitialized = true; |
||
1442 | if (!Module["noFSInit"] && !FS.init.initialized) FS.init(); |
||
1443 | TTY.init(); |
||
1444 | callRuntimeCallbacks(__ATINIT__); |
||
1445 | } |
||
1446 | |||
1447 | function preMain() { |
||
1448 | checkStackCookie(); |
||
1449 | FS.ignorePermissions = false; |
||
1450 | callRuntimeCallbacks(__ATMAIN__); |
||
1451 | } |
||
1452 | |||
1453 | function exitRuntime() { |
||
1454 | checkStackCookie(); |
||
1455 | runtimeExited = true; |
||
1456 | } |
||
1457 | |||
1458 | function postRun() { |
||
1459 | checkStackCookie(); |
||
1460 | |||
1461 | if (Module['postRun']) { |
||
1462 | if (typeof Module['postRun'] == 'function') Module['postRun'] = [Module['postRun']]; |
||
1463 | while (Module['postRun'].length) { |
||
1464 | addOnPostRun(Module['postRun'].shift()); |
||
1465 | } |
||
1466 | } |
||
1467 | |||
1468 | callRuntimeCallbacks(__ATPOSTRUN__); |
||
1469 | } |
||
1470 | |||
1471 | function addOnPreRun(cb) { |
||
1472 | __ATPRERUN__.unshift(cb); |
||
1473 | } |
||
1474 | |||
1475 | function addOnInit(cb) { |
||
1476 | __ATINIT__.unshift(cb); |
||
1477 | } |
||
1478 | |||
1479 | function addOnPreMain(cb) { |
||
1480 | __ATMAIN__.unshift(cb); |
||
1481 | } |
||
1482 | |||
1483 | function addOnExit(cb) { |
||
1484 | } |
||
1485 | |||
1486 | function addOnPostRun(cb) { |
||
1487 | __ATPOSTRUN__.unshift(cb); |
||
1488 | } |
||
1489 | |||
1490 | /** @param {number|boolean=} ignore */ |
||
1491 | function unSign(value, bits, ignore) { |
||
1492 | if (value >= 0) { |
||
1493 | return value; |
||
1494 | } |
||
1495 | return bits <= 32 ? 2*Math.abs(1 << (bits-1)) + value // Need some trickery, since if bits == 32, we are right at the limit of the bits JS uses in bitshifts |
||
1496 | : Math.pow(2, bits) + value; |
||
1497 | } |
||
1498 | /** @param {number|boolean=} ignore */ |
||
1499 | function reSign(value, bits, ignore) { |
||
1500 | if (value <= 0) { |
||
1501 | return value; |
||
1502 | } |
||
1503 | var half = bits <= 32 ? Math.abs(1 << (bits-1)) // abs is needed if bits == 32 |
||
1504 | : Math.pow(2, bits-1); |
||
1505 | if (value >= half && (bits <= 32 || value > half)) { // for huge values, we can hit the precision limit and always get true here. so don't do that |
||
1506 | // but, in general there is no perfect solution here. With 64-bit ints, we get rounding and errors |
||
1507 | // TODO: In i64 mode 1, resign the two parts separately and safely |
||
1508 | value = -2*half + value; // Cannot bitshift half, as it may be at the limit of the bits JS uses in bitshifts |
||
1509 | } |
||
1510 | return value; |
||
1511 | } |
||
1512 | |||
1513 | |||
1514 | |||
1515 | |||
1516 | // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/imul |
||
1517 | |||
1518 | // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/fround |
||
1519 | |||
1520 | // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/clz32 |
||
1521 | |||
1522 | // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/trunc |
||
1523 | |||
1524 | assert(Math.imul, 'This browser does not support Math.imul(), build with LEGACY_VM_SUPPORT or POLYFILL_OLD_MATH_FUNCTIONS to add in a polyfill'); |
||
1525 | assert(Math.fround, 'This browser does not support Math.fround(), build with LEGACY_VM_SUPPORT or POLYFILL_OLD_MATH_FUNCTIONS to add in a polyfill'); |
||
1526 | assert(Math.clz32, 'This browser does not support Math.clz32(), build with LEGACY_VM_SUPPORT or POLYFILL_OLD_MATH_FUNCTIONS to add in a polyfill'); |
||
1527 | assert(Math.trunc, 'This browser does not support Math.trunc(), build with LEGACY_VM_SUPPORT or POLYFILL_OLD_MATH_FUNCTIONS to add in a polyfill'); |
||
1528 | |||
1529 | var Math_abs = Math.abs; |
||
1530 | var Math_cos = Math.cos; |
||
1531 | var Math_sin = Math.sin; |
||
1532 | var Math_tan = Math.tan; |
||
1533 | var Math_acos = Math.acos; |
||
1534 | var Math_asin = Math.asin; |
||
1535 | var Math_atan = Math.atan; |
||
1536 | var Math_atan2 = Math.atan2; |
||
1537 | var Math_exp = Math.exp; |
||
1538 | var Math_log = Math.log; |
||
1539 | var Math_sqrt = Math.sqrt; |
||
1540 | var Math_ceil = Math.ceil; |
||
1541 | var Math_floor = Math.floor; |
||
1542 | var Math_pow = Math.pow; |
||
1543 | var Math_imul = Math.imul; |
||
1544 | var Math_fround = Math.fround; |
||
1545 | var Math_round = Math.round; |
||
1546 | var Math_min = Math.min; |
||
1547 | var Math_max = Math.max; |
||
1548 | var Math_clz32 = Math.clz32; |
||
1549 | var Math_trunc = Math.trunc; |
||
1550 | |||
1551 | |||
1552 | |||
1553 | // A counter of dependencies for calling run(). If we need to |
||
1554 | // do asynchronous work before running, increment this and |
||
1555 | // decrement it. Incrementing must happen in a place like |
||
1556 | // Module.preRun (used by emcc to add file preloading). |
||
1557 | // Note that you can add dependencies in preRun, even though |
||
1558 | // it happens right before run - run will be postponed until |
||
1559 | // the dependencies are met. |
||
1560 | var runDependencies = 0; |
||
1561 | var runDependencyWatcher = null; |
||
1562 | var dependenciesFulfilled = null; // overridden to take different actions when all run dependencies are fulfilled |
||
1563 | var runDependencyTracking = {}; |
||
1564 | |||
1565 | function getUniqueRunDependency(id) { |
||
1566 | var orig = id; |
||
1567 | while (1) { |
||
1568 | if (!runDependencyTracking[id]) return id; |
||
1569 | id = orig + Math.random(); |
||
1570 | } |
||
1571 | } |
||
1572 | |||
1573 | function addRunDependency(id) { |
||
1574 | runDependencies++; |
||
1575 | |||
1576 | if (Module['monitorRunDependencies']) { |
||
1577 | Module['monitorRunDependencies'](runDependencies); |
||
1578 | } |
||
1579 | |||
1580 | if (id) { |
||
1581 | assert(!runDependencyTracking[id]); |
||
1582 | runDependencyTracking[id] = 1; |
||
1583 | if (runDependencyWatcher === null && typeof setInterval !== 'undefined') { |
||
1584 | // Check for missing dependencies every few seconds |
||
1585 | runDependencyWatcher = setInterval(function() { |
||
1586 | if (ABORT) { |
||
1587 | clearInterval(runDependencyWatcher); |
||
1588 | runDependencyWatcher = null; |
||
1589 | return; |
||
1590 | } |
||
1591 | var shown = false; |
||
1592 | for (var dep in runDependencyTracking) { |
||
1593 | if (!shown) { |
||
1594 | shown = true; |
||
1595 | err('still waiting on run dependencies:'); |
||
1596 | } |
||
1597 | err('dependency: ' + dep); |
||
1598 | } |
||
1599 | if (shown) { |
||
1600 | err('(end of list)'); |
||
1601 | } |
||
1602 | }, 10000); |
||
1603 | } |
||
1604 | } else { |
||
1605 | err('warning: run dependency added without ID'); |
||
1606 | } |
||
1607 | } |
||
1608 | |||
1609 | function removeRunDependency(id) { |
||
1610 | runDependencies--; |
||
1611 | |||
1612 | if (Module['monitorRunDependencies']) { |
||
1613 | Module['monitorRunDependencies'](runDependencies); |
||
1614 | } |
||
1615 | |||
1616 | if (id) { |
||
1617 | assert(runDependencyTracking[id]); |
||
1618 | delete runDependencyTracking[id]; |
||
1619 | } else { |
||
1620 | err('warning: run dependency removed without ID'); |
||
1621 | } |
||
1622 | if (runDependencies == 0) { |
||
1623 | if (runDependencyWatcher !== null) { |
||
1624 | clearInterval(runDependencyWatcher); |
||
1625 | runDependencyWatcher = null; |
||
1626 | } |
||
1627 | if (dependenciesFulfilled) { |
||
1628 | var callback = dependenciesFulfilled; |
||
1629 | dependenciesFulfilled = null; |
||
1630 | callback(); // can add another dependenciesFulfilled |
||
1631 | } |
||
1632 | } |
||
1633 | } |
||
1634 | |||
1635 | Module["preloadedImages"] = {}; // maps url to image data |
||
1636 | Module["preloadedAudios"] = {}; // maps url to audio data |
||
1637 | |||
1638 | /** @param {string|number=} what */ |
||
1639 | function abort(what) { |
||
1640 | if (Module['onAbort']) { |
||
1641 | Module['onAbort'](what); |
||
1642 | } |
||
1643 | |||
1644 | what += ''; |
||
1645 | out(what); |
||
1646 | err(what); |
||
1647 | |||
1648 | ABORT = true; |
||
1649 | EXITSTATUS = 1; |
||
1650 | |||
1651 | var output = 'abort(' + what + ') at ' + stackTrace(); |
||
1652 | what = output; |
||
1653 | |||
1654 | // Throw a wasm runtime error, because a JS error might be seen as a foreign |
||
1655 | // exception, which means we'd run destructors on it. We need the error to |
||
1656 | // simply make the program stop. |
||
1657 | throw new WebAssembly.RuntimeError(what); |
||
1658 | } |
||
1659 | |||
1660 | |||
1661 | var memoryInitializer = null; |
||
1662 | |||
1663 | |||
1664 | |||
1665 | |||
1666 | |||
1667 | |||
1668 | |||
1669 | |||
1670 | |||
1671 | |||
1672 | |||
1673 | |||
1674 | function hasPrefix(str, prefix) { |
||
1675 | return String.prototype.startsWith ? |
||
1676 | str.startsWith(prefix) : |
||
1677 | str.indexOf(prefix) === 0; |
||
1678 | } |
||
1679 | |||
1680 | // Prefix of data URIs emitted by SINGLE_FILE and related options. |
||
1681 | var dataURIPrefix = 'data:application/octet-stream;base64,'; |
||
1682 | |||
1683 | // Indicates whether filename is a base64 data URI. |
||
1684 | function isDataURI(filename) { |
||
1685 | return hasPrefix(filename, dataURIPrefix); |
||
1686 | } |
||
1687 | |||
1688 | var fileURIPrefix = "file://"; |
||
1689 | |||
1690 | // Indicates whether filename is delivered via file protocol (as opposed to http/https) |
||
1691 | function isFileURI(filename) { |
||
1692 | return hasPrefix(filename, fileURIPrefix); |
||
1693 | } |
||
1694 | |||
1695 | |||
1696 | |||
1697 | function createExportWrapper(name, fixedasm) { |
||
1698 | return function() { |
||
1699 | var displayName = name; |
||
1700 | var asm = fixedasm; |
||
1701 | if (!fixedasm) { |
||
1702 | asm = Module['asm']; |
||
1703 | } |
||
1704 | assert(runtimeInitialized, 'native function `' + displayName + '` called before runtime initialization'); |
||
1705 | assert(!runtimeExited, 'native function `' + displayName + '` called after runtime exit (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); |
||
1706 | if (!asm[name]) { |
||
1707 | assert(asm[name], 'exported native function `' + displayName + '` not found'); |
||
1708 | } |
||
1709 | return asm[name].apply(null, arguments); |
||
1710 | }; |
||
1711 | } |
||
1712 | |||
1713 | var wasmBinaryFile = 'c2iec.wasm'; |
||
1714 | if (!isDataURI(wasmBinaryFile)) { |
||
1715 | wasmBinaryFile = locateFile(wasmBinaryFile); |
||
1716 | } |
||
1717 | |||
1718 | function getBinary() { |
||
1719 | try { |
||
1720 | if (wasmBinary) { |
||
1721 | return new Uint8Array(wasmBinary); |
||
1722 | } |
||
1723 | |||
1724 | if (readBinary) { |
||
1725 | return readBinary(wasmBinaryFile); |
||
1726 | } else { |
||
1727 | throw "both async and sync fetching of the wasm failed"; |
||
1728 | } |
||
1729 | } |
||
1730 | catch (err) { |
||
1731 | abort(err); |
||
1732 | } |
||
1733 | } |
||
1734 | |||
1735 | function getBinaryPromise() { |
||
1736 | // If we don't have the binary yet, and have the Fetch api, use that; |
||
1737 | // in some environments, like Electron's render process, Fetch api may be present, but have a different context than expected, let's only use it on the Web |
||
1738 | if (!wasmBinary && (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) && typeof fetch === 'function' |
||
1739 | // Let's not use fetch to get objects over file:// as it's most likely Cordova which doesn't support fetch for file:// |
||
1740 | && !isFileURI(wasmBinaryFile) |
||
1741 | ) { |
||
1742 | return fetch(wasmBinaryFile, { credentials: 'same-origin' }).then(function(response) { |
||
1743 | if (!response['ok']) { |
||
1744 | throw "failed to load wasm binary file at '" + wasmBinaryFile + "'"; |
||
1745 | } |
||
1746 | return response['arrayBuffer'](); |
||
1747 | }).catch(function () { |
||
1748 | return getBinary(); |
||
1749 | }); |
||
1750 | } |
||
1751 | // Otherwise, getBinary should be able to get it synchronously |
||
1752 | return new Promise(function(resolve, reject) { |
||
1753 | resolve(getBinary()); |
||
1754 | }); |
||
1755 | } |
||
1756 | |||
1757 | |||
1758 | |||
1759 | // Create the wasm instance. |
||
1760 | // Receives the wasm imports, returns the exports. |
||
1761 | function createWasm() { |
||
1762 | // prepare imports |
||
1763 | var info = { |
||
1764 | 'env': asmLibraryArg, |
||
1765 | 'wasi_snapshot_preview1': asmLibraryArg |
||
1766 | }; |
||
1767 | // Load the wasm module and create an instance of using native support in the JS engine. |
||
1768 | // handle a generated wasm instance, receiving its exports and |
||
1769 | // performing other necessary setup |
||
1770 | /** @param {WebAssembly.Module=} module*/ |
||
1771 | function receiveInstance(instance, module) { |
||
1772 | var exports = instance.exports; |
||
1773 | Module['asm'] = exports; |
||
1774 | removeRunDependency('wasm-instantiate'); |
||
1775 | } |
||
1776 | // we can't run yet (except in a pthread, where we have a custom sync instantiator) |
||
1777 | addRunDependency('wasm-instantiate'); |
||
1778 | |||
1779 | |||
1780 | // Async compilation can be confusing when an error on the page overwrites Module |
||
1781 | // (for example, if the order of elements is wrong, and the one defining Module is |
||
1782 | // later), so we save Module and check it later. |
||
1783 | var trueModule = Module; |
||
1784 | function receiveInstantiatedSource(output) { |
||
1785 | // 'output' is a WebAssemblyInstantiatedSource object which has both the module and instance. |
||
1786 | // receiveInstance() will swap in the exports (to Module.asm) so they can be called |
||
1787 | assert(Module === trueModule, 'the Module object should not be replaced during async compilation - perhaps the order of HTML elements is wrong?'); |
||
1788 | trueModule = null; |
||
1789 | // 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. |
||
1790 | // When the regression is fixed, can restore the above USE_PTHREADS-enabled path. |
||
1791 | receiveInstance(output['instance']); |
||
1792 | } |
||
1793 | |||
1794 | |||
1795 | function instantiateArrayBuffer(receiver) { |
||
1796 | return getBinaryPromise().then(function(binary) { |
||
1797 | return WebAssembly.instantiate(binary, info); |
||
1798 | }).then(receiver, function(reason) { |
||
1799 | err('failed to asynchronously prepare wasm: ' + reason); |
||
1800 | abort(reason); |
||
1801 | }); |
||
1802 | } |
||
1803 | |||
1804 | // Prefer streaming instantiation if available. |
||
1805 | function instantiateAsync() { |
||
1806 | if (!wasmBinary && |
||
1807 | typeof WebAssembly.instantiateStreaming === 'function' && |
||
1808 | !isDataURI(wasmBinaryFile) && |
||
1809 | // Don't use streaming for file:// delivered objects in a webview, fetch them synchronously. |
||
1810 | !isFileURI(wasmBinaryFile) && |
||
1811 | typeof fetch === 'function') { |
||
1812 | fetch(wasmBinaryFile, { credentials: 'same-origin' }).then(function (response) { |
||
1813 | var result = WebAssembly.instantiateStreaming(response, info); |
||
1814 | return result.then(receiveInstantiatedSource, function(reason) { |
||
1815 | // We expect the most common failure cause to be a bad MIME type for the binary, |
||
1816 | // in which case falling back to ArrayBuffer instantiation should work. |
||
1817 | err('wasm streaming compile failed: ' + reason); |
||
1818 | err('falling back to ArrayBuffer instantiation'); |
||
1819 | return instantiateArrayBuffer(receiveInstantiatedSource); |
||
1820 | }); |
||
1821 | }); |
||
1822 | } else { |
||
1823 | return instantiateArrayBuffer(receiveInstantiatedSource); |
||
1824 | } |
||
1825 | } |
||
1826 | // User shell pages can write their own Module.instantiateWasm = function(imports, successCallback) callback |
||
1827 | // to manually instantiate the Wasm module themselves. This allows pages to run the instantiation parallel |
||
1828 | // to any other async startup actions they are performing. |
||
1829 | if (Module['instantiateWasm']) { |
||
1830 | try { |
||
1831 | var exports = Module['instantiateWasm'](info, receiveInstance); |
||
1832 | return exports; |
||
1833 | } catch(e) { |
||
1834 | err('Module.instantiateWasm callback failed with error: ' + e); |
||
1835 | return false; |
||
1836 | } |
||
1837 | } |
||
1838 | |||
1839 | instantiateAsync(); |
||
1840 | return {}; // no exports yet; we'll fill them in later |
||
1841 | } |
||
1842 | |||
1843 | |||
1844 | // Globals used by JS i64 conversions |
||
1845 | var tempDouble; |
||
1846 | var tempI64; |
||
1847 | |||
1848 | // === Body === |
||
1849 | |||
1850 | var ASM_CONSTS = { |
||
1851 | |||
1852 | }; |
||
1853 | |||
1854 | |||
1855 | |||
1856 | |||
1857 | // STATICTOP = STATIC_BASE + 769696; |
||
1858 | /* global initializers */ __ATINIT__.push({ func: function() { ___wasm_call_ctors() } }); |
||
1859 | |||
1860 | |||
1861 | |||
1862 | |||
1863 | /* no memory initializer */ |
||
1864 | // {{PRE_LIBRARY}} |
||
1865 | |||
1866 | |||
1867 | function abortStackOverflow(allocSize) { |
||
1868 | abort('Stack overflow! Attempted to allocate ' + allocSize + ' bytes on the stack, but stack has only ' + (STACK_MAX - stackSave() + allocSize) + ' bytes available!'); |
||
1869 | } |
||
1870 | |||
1871 | function demangle(func) { |
||
1872 | warnOnce('warning: build with -s DEMANGLE_SUPPORT=1 to link in libcxxabi demangling'); |
||
1873 | return func; |
||
1874 | } |
||
1875 | |||
1876 | function demangleAll(text) { |
||
1877 | var regex = |
||
1878 | /\b_Z[\w\d_]+/g; |
||
1879 | return text.replace(regex, |
||
1880 | function(x) { |
||
1881 | var y = demangle(x); |
||
1882 | return x === y ? x : (y + ' [' + x + ']'); |
||
1883 | }); |
||
1884 | } |
||
1885 | |||
1886 | function jsStackTrace() { |
||
1887 | var err = new Error(); |
||
1888 | if (!err.stack) { |
||
1889 | // IE10+ special cases: It does have callstack info, but it is only populated if an Error object is thrown, |
||
1890 | // so try that as a special-case. |
||
1891 | try { |
||
1892 | throw new Error(); |
||
1893 | } catch(e) { |
||
1894 | err = e; |
||
1895 | } |
||
1896 | if (!err.stack) { |
||
1897 | return '(no stack trace available)'; |
||
1898 | } |
||
1899 | } |
||
1900 | return err.stack.toString(); |
||
1901 | } |
||
1902 | |||
1903 | function stackTrace() { |
||
1904 | var js = jsStackTrace(); |
||
1905 | if (Module['extraStackTrace']) js += '\n' + Module['extraStackTrace'](); |
||
1906 | return demangleAll(js); |
||
1907 | } |
||
1908 | |||
1909 | function ___handle_stack_overflow() { |
||
1910 | abort('stack overflow') |
||
1911 | } |
||
1912 | |||
1913 | function _emscripten_get_sbrk_ptr() { |
||
1914 | return 770560; |
||
1915 | } |
||
1916 | |||
1917 | function _emscripten_memcpy_big(dest, src, num) { |
||
1918 | HEAPU8.copyWithin(dest, src, src + num); |
||
1919 | } |
||
1920 | |||
1921 | |||
1922 | function _emscripten_get_heap_size() { |
||
1923 | return HEAPU8.length; |
||
1924 | } |
||
1925 | |||
1926 | function abortOnCannotGrowMemory(requestedSize) { |
||
1927 | abort('Cannot enlarge memory arrays to size ' + requestedSize + ' bytes (OOM). Either (1) compile with -s INITIAL_MEMORY=X with X higher than the current value ' + HEAP8.length + ', (2) compile with -s ALLOW_MEMORY_GROWTH=1 which allows increasing the size at runtime, or (3) if you want malloc to return NULL (0) instead of this abort, compile with -s ABORTING_MALLOC=0 '); |
||
1928 | }function _emscripten_resize_heap(requestedSize) { |
||
1929 | requestedSize = requestedSize >>> 0; |
||
1930 | abortOnCannotGrowMemory(requestedSize); |
||
1931 | } |
||
1932 | |||
1933 | function _exit(status) { |
||
1934 | // void _exit(int status); |
||
1935 | // http://pubs.opengroup.org/onlinepubs/000095399/functions/exit.html |
||
1936 | exit(status); |
||
1937 | } |
||
1938 | |||
1939 | |||
1940 | |||
1941 | var PATH={splitPath:function(filename) { |
||
1942 | var splitPathRe = /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/; |
||
1943 | return splitPathRe.exec(filename).slice(1); |
||
1944 | },normalizeArray:function(parts, allowAboveRoot) { |
||
1945 | // if the path tries to go above the root, `up` ends up > 0 |
||
1946 | var up = 0; |
||
1947 | for (var i = parts.length - 1; i >= 0; i--) { |
||
1948 | var last = parts[i]; |
||
1949 | if (last === '.') { |
||
1950 | parts.splice(i, 1); |
||
1951 | } else if (last === '..') { |
||
1952 | parts.splice(i, 1); |
||
1953 | up++; |
||
1954 | } else if (up) { |
||
1955 | parts.splice(i, 1); |
||
1956 | up--; |
||
1957 | } |
||
1958 | } |
||
1959 | // if the path is allowed to go above the root, restore leading ..s |
||
1960 | if (allowAboveRoot) { |
||
1961 | for (; up; up--) { |
||
1962 | parts.unshift('..'); |
||
1963 | } |
||
1964 | } |
||
1965 | return parts; |
||
1966 | },normalize:function(path) { |
||
1967 | var isAbsolute = path.charAt(0) === '/', |
||
1968 | trailingSlash = path.substr(-1) === '/'; |
||
1969 | // Normalize the path |
||
1970 | path = PATH.normalizeArray(path.split('/').filter(function(p) { |
||
1971 | return !!p; |
||
1972 | }), !isAbsolute).join('/'); |
||
1973 | if (!path && !isAbsolute) { |
||
1974 | path = '.'; |
||
1975 | } |
||
1976 | if (path && trailingSlash) { |
||
1977 | path += '/'; |
||
1978 | } |
||
1979 | return (isAbsolute ? '/' : '') + path; |
||
1980 | },dirname:function(path) { |
||
1981 | var result = PATH.splitPath(path), |
||
1982 | root = result[0], |
||
1983 | dir = result[1]; |
||
1984 | if (!root && !dir) { |
||
1985 | // No dirname whatsoever |
||
1986 | return '.'; |
||
1987 | } |
||
1988 | if (dir) { |
||
1989 | // It has a dirname, strip trailing slash |
||
1990 | dir = dir.substr(0, dir.length - 1); |
||
1991 | } |
||
1992 | return root + dir; |
||
1993 | },basename:function(path) { |
||
1994 | // EMSCRIPTEN return '/'' for '/', not an empty string |
||
1995 | if (path === '/') return '/'; |
||
1996 | var lastSlash = path.lastIndexOf('/'); |
||
1997 | if (lastSlash === -1) return path; |
||
1998 | return path.substr(lastSlash+1); |
||
1999 | },extname:function(path) { |
||
2000 | return PATH.splitPath(path)[3]; |
||
2001 | },join:function() { |
||
2002 | var paths = Array.prototype.slice.call(arguments, 0); |
||
2003 | return PATH.normalize(paths.join('/')); |
||
2004 | },join2:function(l, r) { |
||
2005 | return PATH.normalize(l + '/' + r); |
||
2006 | }}; |
||
2007 | |||
2008 | |||
2009 | function setErrNo(value) { |
||
2010 | HEAP32[((___errno_location())>>2)]=value; |
||
2011 | return value; |
||
2012 | } |
||
2013 | |||
2014 | var PATH_FS={resolve:function() { |
||
2015 | var resolvedPath = '', |
||
2016 | resolvedAbsolute = false; |
||
2017 | for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) { |
||
2018 | var path = (i >= 0) ? arguments[i] : FS.cwd(); |
||
2019 | // Skip empty and invalid entries |
||
2020 | if (typeof path !== 'string') { |
||
2021 | throw new TypeError('Arguments to path.resolve must be strings'); |
||
2022 | } else if (!path) { |
||
2023 | return ''; // an invalid portion invalidates the whole thing |
||
2024 | } |
||
2025 | resolvedPath = path + '/' + resolvedPath; |
||
2026 | resolvedAbsolute = path.charAt(0) === '/'; |
||
2027 | } |
||
2028 | // At this point the path should be resolved to a full absolute path, but |
||
2029 | // handle relative paths to be safe (might happen when process.cwd() fails) |
||
2030 | resolvedPath = PATH.normalizeArray(resolvedPath.split('/').filter(function(p) { |
||
2031 | return !!p; |
||
2032 | }), !resolvedAbsolute).join('/'); |
||
2033 | return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.'; |
||
2034 | },relative:function(from, to) { |
||
2035 | from = PATH_FS.resolve(from).substr(1); |
||
2036 | to = PATH_FS.resolve(to).substr(1); |
||
2037 | function trim(arr) { |
||
2038 | var start = 0; |
||
2039 | for (; start < arr.length; start++) { |
||
2040 | if (arr[start] !== '') break; |
||
2041 | } |
||
2042 | var end = arr.length - 1; |
||
2043 | for (; end >= 0; end--) { |
||
2044 | if (arr[end] !== '') break; |
||
2045 | } |
||
2046 | if (start > end) return []; |
||
2047 | return arr.slice(start, end - start + 1); |
||
2048 | } |
||
2049 | var fromParts = trim(from.split('/')); |
||
2050 | var toParts = trim(to.split('/')); |
||
2051 | var length = Math.min(fromParts.length, toParts.length); |
||
2052 | var samePartsLength = length; |
||
2053 | for (var i = 0; i < length; i++) { |
||
2054 | if (fromParts[i] !== toParts[i]) { |
||
2055 | samePartsLength = i; |
||
2056 | break; |
||
2057 | } |
||
2058 | } |
||
2059 | var outputParts = []; |
||
2060 | for (var i = samePartsLength; i < fromParts.length; i++) { |
||
2061 | outputParts.push('..'); |
||
2062 | } |
||
2063 | outputParts = outputParts.concat(toParts.slice(samePartsLength)); |
||
2064 | return outputParts.join('/'); |
||
2065 | }}; |
||
2066 | |||
2067 | var TTY={ttys:[],init:function () { |
||
2068 | // https://github.com/emscripten-core/emscripten/pull/1555 |
||
2069 | // if (ENVIRONMENT_IS_NODE) { |
||
2070 | // // currently, FS.init does not distinguish if process.stdin is a file or TTY |
||
2071 | // // device, it always assumes it's a TTY device. because of this, we're forcing |
||
2072 | // // process.stdin to UTF8 encoding to at least make stdin reading compatible |
||
2073 | // // with text files until FS.init can be refactored. |
||
2074 | // process['stdin']['setEncoding']('utf8'); |
||
2075 | // } |
||
2076 | },shutdown:function() { |
||
2077 | // https://github.com/emscripten-core/emscripten/pull/1555 |
||
2078 | // if (ENVIRONMENT_IS_NODE) { |
||
2079 | // // inolen: any idea as to why node -e 'process.stdin.read()' wouldn't exit immediately (with process.stdin being a tty)? |
||
2080 | // // isaacs: because now it's reading from the stream, you've expressed interest in it, so that read() kicks off a _read() which creates a ReadReq operation |
||
2081 | // // inolen: I thought read() in that case was a synchronous operation that just grabbed some amount of buffered data if it exists? |
||
2082 | // // isaacs: it is. but it also triggers a _read() call, which calls readStart() on the handle |
||
2083 | // // isaacs: do process.stdin.pause() and i'd think it'd probably close the pending call |
||
2084 | // process['stdin']['pause'](); |
||
2085 | // } |
||
2086 | },register:function(dev, ops) { |
||
2087 | TTY.ttys[dev] = { input: [], output: [], ops: ops }; |
||
2088 | FS.registerDevice(dev, TTY.stream_ops); |
||
2089 | },stream_ops:{open:function(stream) { |
||
2090 | var tty = TTY.ttys[stream.node.rdev]; |
||
2091 | if (!tty) { |
||
2092 | throw new FS.ErrnoError(43); |
||
2093 | } |
||
2094 | stream.tty = tty; |
||
2095 | stream.seekable = false; |
||
2096 | },close:function(stream) { |
||
2097 | // flush any pending line data |
||
2098 | stream.tty.ops.flush(stream.tty); |
||
2099 | },flush:function(stream) { |
||
2100 | stream.tty.ops.flush(stream.tty); |
||
2101 | },read:function(stream, buffer, offset, length, pos /* ignored */) { |
||
2102 | if (!stream.tty || !stream.tty.ops.get_char) { |
||
2103 | throw new FS.ErrnoError(60); |
||
2104 | } |
||
2105 | var bytesRead = 0; |
||
2106 | for (var i = 0; i < length; i++) { |
||
2107 | var result; |
||
2108 | try { |
||
2109 | result = stream.tty.ops.get_char(stream.tty); |
||
2110 | } catch (e) { |
||
2111 | throw new FS.ErrnoError(29); |
||
2112 | } |
||
2113 | if (result === undefined && bytesRead === 0) { |
||
2114 | throw new FS.ErrnoError(6); |
||
2115 | } |
||
2116 | if (result === null || result === undefined) break; |
||
2117 | bytesRead++; |
||
2118 | buffer[offset+i] = result; |
||
2119 | } |
||
2120 | if (bytesRead) { |
||
2121 | stream.node.timestamp = Date.now(); |
||
2122 | } |
||
2123 | return bytesRead; |
||
2124 | },write:function(stream, buffer, offset, length, pos) { |
||
2125 | if (!stream.tty || !stream.tty.ops.put_char) { |
||
2126 | throw new FS.ErrnoError(60); |
||
2127 | } |
||
2128 | try { |
||
2129 | for (var i = 0; i < length; i++) { |
||
2130 | stream.tty.ops.put_char(stream.tty, buffer[offset+i]); |
||
2131 | } |
||
2132 | } catch (e) { |
||
2133 | throw new FS.ErrnoError(29); |
||
2134 | } |
||
2135 | if (length) { |
||
2136 | stream.node.timestamp = Date.now(); |
||
2137 | } |
||
2138 | return i; |
||
2139 | }},default_tty_ops:{get_char:function(tty) { |
||
2140 | if (!tty.input.length) { |
||
2141 | var result = null; |
||
2142 | if (ENVIRONMENT_IS_NODE) { |
||
2143 | // we will read data by chunks of BUFSIZE |
||
2144 | var BUFSIZE = 256; |
||
2145 | var buf = Buffer.alloc ? Buffer.alloc(BUFSIZE) : new Buffer(BUFSIZE); |
||
2146 | var bytesRead = 0; |
||
2147 | |||
2148 | try { |
||
2149 | bytesRead = nodeFS.readSync(process.stdin.fd, buf, 0, BUFSIZE, null); |
||
2150 | } catch(e) { |
||
2151 | // Cross-platform differences: on Windows, reading EOF throws an exception, but on other OSes, |
||
2152 | // reading EOF returns 0. Uniformize behavior by treating the EOF exception to return 0. |
||
2153 | if (e.toString().indexOf('EOF') != -1) bytesRead = 0; |
||
2154 | else throw e; |
||
2155 | } |
||
2156 | |||
2157 | if (bytesRead > 0) { |
||
2158 | result = buf.slice(0, bytesRead).toString('utf-8'); |
||
2159 | } else { |
||
2160 | result = null; |
||
2161 | } |
||
2162 | } else |
||
2163 | if (typeof window != 'undefined' && |
||
2164 | typeof window.prompt == 'function') { |
||
2165 | // Browser. |
||
2166 | result = window.prompt('Input: '); // returns null on cancel |
||
2167 | if (result !== null) { |
||
2168 | result += '\n'; |
||
2169 | } |
||
2170 | } else if (typeof readline == 'function') { |
||
2171 | // Command line. |
||
2172 | result = readline(); |
||
2173 | if (result !== null) { |
||
2174 | result += '\n'; |
||
2175 | } |
||
2176 | } |
||
2177 | if (!result) { |
||
2178 | return null; |
||
2179 | } |
||
2180 | tty.input = intArrayFromString(result, true); |
||
2181 | } |
||
2182 | return tty.input.shift(); |
||
2183 | },put_char:function(tty, val) { |
||
2184 | if (val === null || val === 10) { |
||
2185 | out(UTF8ArrayToString(tty.output, 0)); |
||
2186 | tty.output = []; |
||
2187 | } else { |
||
2188 | if (val != 0) tty.output.push(val); // val == 0 would cut text output off in the middle. |
||
2189 | } |
||
2190 | },flush:function(tty) { |
||
2191 | if (tty.output && tty.output.length > 0) { |
||
2192 | out(UTF8ArrayToString(tty.output, 0)); |
||
2193 | tty.output = []; |
||
2194 | } |
||
2195 | }},default_tty1_ops:{put_char:function(tty, val) { |
||
2196 | if (val === null || val === 10) { |
||
2197 | err(UTF8ArrayToString(tty.output, 0)); |
||
2198 | tty.output = []; |
||
2199 | } else { |
||
2200 | if (val != 0) tty.output.push(val); |
||
2201 | } |
||
2202 | },flush:function(tty) { |
||
2203 | if (tty.output && tty.output.length > 0) { |
||
2204 | err(UTF8ArrayToString(tty.output, 0)); |
||
2205 | tty.output = []; |
||
2206 | } |
||
2207 | }}}; |
||
2208 | |||
2209 | var MEMFS={ops_table:null,mount:function(mount) { |
||
2210 | return MEMFS.createNode(null, '/', 16384 | 511 /* 0777 */, 0); |
||
2211 | },createNode:function(parent, name, mode, dev) { |
||
2212 | if (FS.isBlkdev(mode) || FS.isFIFO(mode)) { |
||
2213 | // no supported |
||
2214 | throw new FS.ErrnoError(63); |
||
2215 | } |
||
2216 | if (!MEMFS.ops_table) { |
||
2217 | MEMFS.ops_table = { |
||
2218 | dir: { |
||
2219 | node: { |
||
2220 | getattr: MEMFS.node_ops.getattr, |
||
2221 | setattr: MEMFS.node_ops.setattr, |
||
2222 | lookup: MEMFS.node_ops.lookup, |
||
2223 | mknod: MEMFS.node_ops.mknod, |
||
2224 | rename: MEMFS.node_ops.rename, |
||
2225 | unlink: MEMFS.node_ops.unlink, |
||
2226 | rmdir: MEMFS.node_ops.rmdir, |
||
2227 | readdir: MEMFS.node_ops.readdir, |
||
2228 | symlink: MEMFS.node_ops.symlink |
||
2229 | }, |
||
2230 | stream: { |
||
2231 | llseek: MEMFS.stream_ops.llseek |
||
2232 | } |
||
2233 | }, |
||
2234 | file: { |
||
2235 | node: { |
||
2236 | getattr: MEMFS.node_ops.getattr, |
||
2237 | setattr: MEMFS.node_ops.setattr |
||
2238 | }, |
||
2239 | stream: { |
||
2240 | llseek: MEMFS.stream_ops.llseek, |
||
2241 | read: MEMFS.stream_ops.read, |
||
2242 | write: MEMFS.stream_ops.write, |
||
2243 | allocate: MEMFS.stream_ops.allocate, |
||
2244 | mmap: MEMFS.stream_ops.mmap, |
||
2245 | msync: MEMFS.stream_ops.msync |
||
2246 | } |
||
2247 | }, |
||
2248 | link: { |
||
2249 | node: { |
||
2250 | getattr: MEMFS.node_ops.getattr, |
||
2251 | setattr: MEMFS.node_ops.setattr, |
||
2252 | readlink: MEMFS.node_ops.readlink |
||
2253 | }, |
||
2254 | stream: {} |
||
2255 | }, |
||
2256 | chrdev: { |
||
2257 | node: { |
||
2258 | getattr: MEMFS.node_ops.getattr, |
||
2259 | setattr: MEMFS.node_ops.setattr |
||
2260 | }, |
||
2261 | stream: FS.chrdev_stream_ops |
||
2262 | } |
||
2263 | }; |
||
2264 | } |
||
2265 | var node = FS.createNode(parent, name, mode, dev); |
||
2266 | if (FS.isDir(node.mode)) { |
||
2267 | node.node_ops = MEMFS.ops_table.dir.node; |
||
2268 | node.stream_ops = MEMFS.ops_table.dir.stream; |
||
2269 | node.contents = {}; |
||
2270 | } else if (FS.isFile(node.mode)) { |
||
2271 | node.node_ops = MEMFS.ops_table.file.node; |
||
2272 | node.stream_ops = MEMFS.ops_table.file.stream; |
||
2273 | node.usedBytes = 0; // The actual number of bytes used in the typed array, as opposed to contents.length which gives the whole capacity. |
||
2274 | // When the byte data of the file is populated, this will point to either a typed array, or a normal JS array. Typed arrays are preferred |
||
2275 | // for performance, and used by default. However, typed arrays are not resizable like normal JS arrays are, so there is a small disk size |
||
2276 | // penalty involved for appending file writes that continuously grow a file similar to std::vector capacity vs used -scheme. |
||
2277 | node.contents = null; |
||
2278 | } else if (FS.isLink(node.mode)) { |
||
2279 | node.node_ops = MEMFS.ops_table.link.node; |
||
2280 | node.stream_ops = MEMFS.ops_table.link.stream; |
||
2281 | } else if (FS.isChrdev(node.mode)) { |
||
2282 | node.node_ops = MEMFS.ops_table.chrdev.node; |
||
2283 | node.stream_ops = MEMFS.ops_table.chrdev.stream; |
||
2284 | } |
||
2285 | node.timestamp = Date.now(); |
||
2286 | // add the new node to the parent |
||
2287 | if (parent) { |
||
2288 | parent.contents[name] = node; |
||
2289 | } |
||
2290 | return node; |
||
2291 | },getFileDataAsRegularArray:function(node) { |
||
2292 | if (node.contents && node.contents.subarray) { |
||
2293 | var arr = []; |
||
2294 | for (var i = 0; i < node.usedBytes; ++i) arr.push(node.contents[i]); |
||
2295 | return arr; // Returns a copy of the original data. |
||
2296 | } |
||
2297 | return node.contents; // No-op, the file contents are already in a JS array. Return as-is. |
||
2298 | },getFileDataAsTypedArray:function(node) { |
||
2299 | if (!node.contents) return new Uint8Array(0); |
||
2300 | if (node.contents.subarray) return node.contents.subarray(0, node.usedBytes); // Make sure to not return excess unused bytes. |
||
2301 | return new Uint8Array(node.contents); |
||
2302 | },expandFileStorage:function(node, newCapacity) { |
||
2303 | var prevCapacity = node.contents ? node.contents.length : 0; |
||
2304 | if (prevCapacity >= newCapacity) return; // No need to expand, the storage was already large enough. |
||
2305 | // Don't expand strictly to the given requested limit if it's only a very small increase, but instead geometrically grow capacity. |
||
2306 | // For small filesizes (<1MB), perform size*2 geometric increase, but for large sizes, do a much more conservative size*1.125 increase to |
||
2307 | // avoid overshooting the allocation cap by a very large margin. |
||
2308 | var CAPACITY_DOUBLING_MAX = 1024 * 1024; |
||
2309 | newCapacity = Math.max(newCapacity, (prevCapacity * (prevCapacity < CAPACITY_DOUBLING_MAX ? 2.0 : 1.125)) >>> 0); |
||
2310 | if (prevCapacity != 0) newCapacity = Math.max(newCapacity, 256); // At minimum allocate 256b for each file when expanding. |
||
2311 | var oldContents = node.contents; |
||
2312 | node.contents = new Uint8Array(newCapacity); // Allocate new storage. |
||
2313 | if (node.usedBytes > 0) node.contents.set(oldContents.subarray(0, node.usedBytes), 0); // Copy old data over to the new storage. |
||
2314 | return; |
||
2315 | },resizeFileStorage:function(node, newSize) { |
||
2316 | if (node.usedBytes == newSize) return; |
||
2317 | if (newSize == 0) { |
||
2318 | node.contents = null; // Fully decommit when requesting a resize to zero. |
||
2319 | node.usedBytes = 0; |
||
2320 | return; |
||
2321 | } |
||
2322 | if (!node.contents || node.contents.subarray) { // Resize a typed array if that is being used as the backing store. |
||
2323 | var oldContents = node.contents; |
||
2324 | node.contents = new Uint8Array(newSize); // Allocate new storage. |
||
2325 | if (oldContents) { |
||
2326 | node.contents.set(oldContents.subarray(0, Math.min(newSize, node.usedBytes))); // Copy old data over to the new storage. |
||
2327 | } |
||
2328 | node.usedBytes = newSize; |
||
2329 | return; |
||
2330 | } |
||
2331 | // Backing with a JS array. |
||
2332 | if (!node.contents) node.contents = []; |
||
2333 | if (node.contents.length > newSize) node.contents.length = newSize; |
||
2334 | else while (node.contents.length < newSize) node.contents.push(0); |
||
2335 | node.usedBytes = newSize; |
||
2336 | },node_ops:{getattr:function(node) { |
||
2337 | var attr = {}; |
||
2338 | // device numbers reuse inode numbers. |
||
2339 | attr.dev = FS.isChrdev(node.mode) ? node.id : 1; |
||
2340 | attr.ino = node.id; |
||
2341 | attr.mode = node.mode; |
||
2342 | attr.nlink = 1; |
||
2343 | attr.uid = 0; |
||
2344 | attr.gid = 0; |
||
2345 | attr.rdev = node.rdev; |
||
2346 | if (FS.isDir(node.mode)) { |
||
2347 | attr.size = 4096; |
||
2348 | } else if (FS.isFile(node.mode)) { |
||
2349 | attr.size = node.usedBytes; |
||
2350 | } else if (FS.isLink(node.mode)) { |
||
2351 | attr.size = node.link.length; |
||
2352 | } else { |
||
2353 | attr.size = 0; |
||
2354 | } |
||
2355 | attr.atime = new Date(node.timestamp); |
||
2356 | attr.mtime = new Date(node.timestamp); |
||
2357 | attr.ctime = new Date(node.timestamp); |
||
2358 | // NOTE: In our implementation, st_blocks = Math.ceil(st_size/st_blksize), |
||
2359 | // but this is not required by the standard. |
||
2360 | attr.blksize = 4096; |
||
2361 | attr.blocks = Math.ceil(attr.size / attr.blksize); |
||
2362 | return attr; |
||
2363 | },setattr:function(node, attr) { |
||
2364 | if (attr.mode !== undefined) { |
||
2365 | node.mode = attr.mode; |
||
2366 | } |
||
2367 | if (attr.timestamp !== undefined) { |
||
2368 | node.timestamp = attr.timestamp; |
||
2369 | } |
||
2370 | if (attr.size !== undefined) { |
||
2371 | MEMFS.resizeFileStorage(node, attr.size); |
||
2372 | } |
||
2373 | },lookup:function(parent, name) { |
||
2374 | throw FS.genericErrors[44]; |
||
2375 | },mknod:function(parent, name, mode, dev) { |
||
2376 | return MEMFS.createNode(parent, name, mode, dev); |
||
2377 | },rename:function(old_node, new_dir, new_name) { |
||
2378 | // if we're overwriting a directory at new_name, make sure it's empty. |
||
2379 | if (FS.isDir(old_node.mode)) { |
||
2380 | var new_node; |
||
2381 | try { |
||
2382 | new_node = FS.lookupNode(new_dir, new_name); |
||
2383 | } catch (e) { |
||
2384 | } |
||
2385 | if (new_node) { |
||
2386 | for (var i in new_node.contents) { |
||
2387 | throw new FS.ErrnoError(55); |
||
2388 | } |
||
2389 | } |
||
2390 | } |
||
2391 | // do the internal rewiring |
||
2392 | delete old_node.parent.contents[old_node.name]; |
||
2393 | old_node.name = new_name; |
||
2394 | new_dir.contents[new_name] = old_node; |
||
2395 | old_node.parent = new_dir; |
||
2396 | },unlink:function(parent, name) { |
||
2397 | delete parent.contents[name]; |
||
2398 | },rmdir:function(parent, name) { |
||
2399 | var node = FS.lookupNode(parent, name); |
||
2400 | for (var i in node.contents) { |
||
2401 | throw new FS.ErrnoError(55); |
||
2402 | } |
||
2403 | delete parent.contents[name]; |
||
2404 | },readdir:function(node) { |
||
2405 | var entries = ['.', '..']; |
||
2406 | for (var key in node.contents) { |
||
2407 | if (!node.contents.hasOwnProperty(key)) { |
||
2408 | continue; |
||
2409 | } |
||
2410 | entries.push(key); |
||
2411 | } |
||
2412 | return entries; |
||
2413 | },symlink:function(parent, newname, oldpath) { |
||
2414 | var node = MEMFS.createNode(parent, newname, 511 /* 0777 */ | 40960, 0); |
||
2415 | node.link = oldpath; |
||
2416 | return node; |
||
2417 | },readlink:function(node) { |
||
2418 | if (!FS.isLink(node.mode)) { |
||
2419 | throw new FS.ErrnoError(28); |
||
2420 | } |
||
2421 | return node.link; |
||
2422 | }},stream_ops:{read:function(stream, buffer, offset, length, position) { |
||
2423 | var contents = stream.node.contents; |
||
2424 | if (position >= stream.node.usedBytes) return 0; |
||
2425 | var size = Math.min(stream.node.usedBytes - position, length); |
||
2426 | assert(size >= 0); |
||
2427 | if (size > 8 && contents.subarray) { // non-trivial, and typed array |
||
2428 | buffer.set(contents.subarray(position, position + size), offset); |
||
2429 | } else { |
||
2430 | for (var i = 0; i < size; i++) buffer[offset + i] = contents[position + i]; |
||
2431 | } |
||
2432 | return size; |
||
2433 | },write:function(stream, buffer, offset, length, position, canOwn) { |
||
2434 | // The data buffer should be a typed array view |
||
2435 | assert(!(buffer instanceof ArrayBuffer)); |
||
2436 | |||
2437 | if (!length) return 0; |
||
2438 | var node = stream.node; |
||
2439 | node.timestamp = Date.now(); |
||
2440 | |||
2441 | if (buffer.subarray && (!node.contents || node.contents.subarray)) { // This write is from a typed array to a typed array? |
||
2442 | if (canOwn) { |
||
2443 | assert(position === 0, 'canOwn must imply no weird position inside the file'); |
||
2444 | node.contents = buffer.subarray(offset, offset + length); |
||
2445 | node.usedBytes = length; |
||
2446 | return length; |
||
2447 | } else if (node.usedBytes === 0 && position === 0) { // If this is a simple first write to an empty file, do a fast set since we don't need to care about old data. |
||
2448 | node.contents = buffer.slice(offset, offset + length); |
||
2449 | node.usedBytes = length; |
||
2450 | return length; |
||
2451 | } else if (position + length <= node.usedBytes) { // Writing to an already allocated and used subrange of the file? |
||
2452 | node.contents.set(buffer.subarray(offset, offset + length), position); |
||
2453 | return length; |
||
2454 | } |
||
2455 | } |
||
2456 | |||
2457 | // Appending to an existing file and we need to reallocate, or source data did not come as a typed array. |
||
2458 | MEMFS.expandFileStorage(node, position+length); |
||
2459 | if (node.contents.subarray && buffer.subarray) node.contents.set(buffer.subarray(offset, offset + length), position); // Use typed array write if available. |
||
2460 | else { |
||
2461 | for (var i = 0; i < length; i++) { |
||
2462 | node.contents[position + i] = buffer[offset + i]; // Or fall back to manual write if not. |
||
2463 | } |
||
2464 | } |
||
2465 | node.usedBytes = Math.max(node.usedBytes, position + length); |
||
2466 | return length; |
||
2467 | },llseek:function(stream, offset, whence) { |
||
2468 | var position = offset; |
||
2469 | if (whence === 1) { |
||
2470 | position += stream.position; |
||
2471 | } else if (whence === 2) { |
||
2472 | if (FS.isFile(stream.node.mode)) { |
||
2473 | position += stream.node.usedBytes; |
||
2474 | } |
||
2475 | } |
||
2476 | if (position < 0) { |
||
2477 | throw new FS.ErrnoError(28); |
||
2478 | } |
||
2479 | return position; |
||
2480 | },allocate:function(stream, offset, length) { |
||
2481 | MEMFS.expandFileStorage(stream.node, offset + length); |
||
2482 | stream.node.usedBytes = Math.max(stream.node.usedBytes, offset + length); |
||
2483 | },mmap:function(stream, address, length, position, prot, flags) { |
||
2484 | // We don't currently support location hints for the address of the mapping |
||
2485 | assert(address === 0); |
||
2486 | |||
2487 | if (!FS.isFile(stream.node.mode)) { |
||
2488 | throw new FS.ErrnoError(43); |
||
2489 | } |
||
2490 | var ptr; |
||
2491 | var allocated; |
||
2492 | var contents = stream.node.contents; |
||
2493 | // Only make a new copy when MAP_PRIVATE is specified. |
||
2494 | if (!(flags & 2) && contents.buffer === buffer) { |
||
2495 | // We can't emulate MAP_SHARED when the file is not backed by the buffer |
||
2496 | // we're mapping to (e.g. the HEAP buffer). |
||
2497 | allocated = false; |
||
2498 | ptr = contents.byteOffset; |
||
2499 | } else { |
||
2500 | // Try to avoid unnecessary slices. |
||
2501 | if (position > 0 || position + length < contents.length) { |
||
2502 | if (contents.subarray) { |
||
2503 | contents = contents.subarray(position, position + length); |
||
2504 | } else { |
||
2505 | contents = Array.prototype.slice.call(contents, position, position + length); |
||
2506 | } |
||
2507 | } |
||
2508 | allocated = true; |
||
2509 | ptr = _malloc(length); |
||
2510 | if (!ptr) { |
||
2511 | throw new FS.ErrnoError(48); |
||
2512 | } |
||
2513 | HEAP8.set(contents, ptr); |
||
2514 | } |
||
2515 | return { ptr: ptr, allocated: allocated }; |
||
2516 | },msync:function(stream, buffer, offset, length, mmapFlags) { |
||
2517 | if (!FS.isFile(stream.node.mode)) { |
||
2518 | throw new FS.ErrnoError(43); |
||
2519 | } |
||
2520 | if (mmapFlags & 2) { |
||
2521 | // MAP_PRIVATE calls need not to be synced back to underlying fs |
||
2522 | return 0; |
||
2523 | } |
||
2524 | |||
2525 | var bytesWritten = MEMFS.stream_ops.write(stream, buffer, 0, length, offset, false); |
||
2526 | // should we check if bytesWritten and length are the same? |
||
2527 | return 0; |
||
2528 | }}}; |
||
2529 | |||
2530 | var ERRNO_MESSAGES={0:"Success",1:"Arg list too long",2:"Permission denied",3:"Address already in use",4:"Address not available",5:"Address family not supported by protocol family",6:"No more processes",7:"Socket already connected",8:"Bad file number",9:"Trying to read unreadable message",10:"Mount device busy",11:"Operation canceled",12:"No children",13:"Connection aborted",14:"Connection refused",15:"Connection reset by peer",16:"File locking deadlock error",17:"Destination address required",18:"Math arg out of domain of func",19:"Quota exceeded",20:"File exists",21:"Bad address",22:"File too large",23:"Host is unreachable",24:"Identifier removed",25:"Illegal byte sequence",26:"Connection already in progress",27:"Interrupted system call",28:"Invalid argument",29:"I/O error",30:"Socket is already connected",31:"Is a directory",32:"Too many symbolic links",33:"Too many open files",34:"Too many links",35:"Message too long",36:"Multihop attempted",37:"File or path name too long",38:"Network interface is not configured",39:"Connection reset by network",40:"Network is unreachable",41:"Too many open files in system",42:"No buffer space available",43:"No such device",44:"No such file or directory",45:"Exec format error",46:"No record locks available",47:"The link has been severed",48:"Not enough core",49:"No message of desired type",50:"Protocol not available",51:"No space left on device",52:"Function not implemented",53:"Socket is not connected",54:"Not a directory",55:"Directory not empty",56:"State not recoverable",57:"Socket operation on non-socket",59:"Not a typewriter",60:"No such device or address",61:"Value too large for defined data type",62:"Previous owner died",63:"Not super-user",64:"Broken pipe",65:"Protocol error",66:"Unknown protocol",67:"Protocol wrong type for socket",68:"Math result not representable",69:"Read only file system",70:"Illegal seek",71:"No such process",72:"Stale file handle",73:"Connection timed out",74:"Text file busy",75:"Cross-device link",100:"Device not a stream",101:"Bad font file fmt",102:"Invalid slot",103:"Invalid request code",104:"No anode",105:"Block device required",106:"Channel number out of range",107:"Level 3 halted",108:"Level 3 reset",109:"Link number out of range",110:"Protocol driver not attached",111:"No CSI structure available",112:"Level 2 halted",113:"Invalid exchange",114:"Invalid request descriptor",115:"Exchange full",116:"No data (for no delay io)",117:"Timer expired",118:"Out of streams resources",119:"Machine is not on the network",120:"Package not installed",121:"The object is remote",122:"Advertise error",123:"Srmount error",124:"Communication error on send",125:"Cross mount point (not really error)",126:"Given log. name not unique",127:"f.d. invalid for this operation",128:"Remote address changed",129:"Can access a needed shared lib",130:"Accessing a corrupted shared lib",131:".lib section in a.out corrupted",132:"Attempting to link in too many libs",133:"Attempting to exec a shared library",135:"Streams pipe error",136:"Too many users",137:"Socket type not supported",138:"Not supported",139:"Protocol family not supported",140:"Can't send after socket shutdown",141:"Too many references",142:"Host is down",148:"No medium (in tape drive)",156:"Level 2 not synchronized"}; |
||
2531 | |||
2532 | var ERRNO_CODES={EPERM:63,ENOENT:44,ESRCH:71,EINTR:27,EIO:29,ENXIO:60,E2BIG:1,ENOEXEC:45,EBADF:8,ECHILD:12,EAGAIN:6,EWOULDBLOCK:6,ENOMEM:48,EACCES:2,EFAULT:21,ENOTBLK:105,EBUSY:10,EEXIST:20,EXDEV:75,ENODEV:43,ENOTDIR:54,EISDIR:31,EINVAL:28,ENFILE:41,EMFILE:33,ENOTTY:59,ETXTBSY:74,EFBIG:22,ENOSPC:51,ESPIPE:70,EROFS:69,EMLINK:34,EPIPE:64,EDOM:18,ERANGE:68,ENOMSG:49,EIDRM:24,ECHRNG:106,EL2NSYNC:156,EL3HLT:107,EL3RST:108,ELNRNG:109,EUNATCH:110,ENOCSI:111,EL2HLT:112,EDEADLK:16,ENOLCK:46,EBADE:113,EBADR:114,EXFULL:115,ENOANO:104,EBADRQC:103,EBADSLT:102,EDEADLOCK:16,EBFONT:101,ENOSTR:100,ENODATA:116,ETIME:117,ENOSR:118,ENONET:119,ENOPKG:120,EREMOTE:121,ENOLINK:47,EADV:122,ESRMNT:123,ECOMM:124,EPROTO:65,EMULTIHOP:36,EDOTDOT:125,EBADMSG:9,ENOTUNIQ:126,EBADFD:127,EREMCHG:128,ELIBACC:129,ELIBBAD:130,ELIBSCN:131,ELIBMAX:132,ELIBEXEC:133,ENOSYS:52,ENOTEMPTY:55,ENAMETOOLONG:37,ELOOP:32,EOPNOTSUPP:138,EPFNOSUPPORT:139,ECONNRESET:15,ENOBUFS:42,EAFNOSUPPORT:5,EPROTOTYPE:67,ENOTSOCK:57,ENOPROTOOPT:50,ESHUTDOWN:140,ECONNREFUSED:14,EADDRINUSE:3,ECONNABORTED:13,ENETUNREACH:40,ENETDOWN:38,ETIMEDOUT:73,EHOSTDOWN:142,EHOSTUNREACH:23,EINPROGRESS:26,EALREADY:7,EDESTADDRREQ:17,EMSGSIZE:35,EPROTONOSUPPORT:66,ESOCKTNOSUPPORT:137,EADDRNOTAVAIL:4,ENETRESET:39,EISCONN:30,ENOTCONN:53,ETOOMANYREFS:141,EUSERS:136,EDQUOT:19,ESTALE:72,ENOTSUP:138,ENOMEDIUM:148,EILSEQ:25,EOVERFLOW:61,ECANCELED:11,ENOTRECOVERABLE:56,EOWNERDEAD:62,ESTRPIPE:135};var FS={root:null,mounts:[],devices:{},streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:false,ignorePermissions:true,trackingDelegate:{},tracking:{openFlags:{READ:1,WRITE:2}},ErrnoError:null,genericErrors:{},filesystems:null,syncFSRequests:0,handleFSError:function(e) { |
||
2533 | if (!(e instanceof FS.ErrnoError)) throw e + ' : ' + stackTrace(); |
||
2534 | return setErrNo(e.errno); |
||
2535 | },lookupPath:function(path, opts) { |
||
2536 | path = PATH_FS.resolve(FS.cwd(), path); |
||
2537 | opts = opts || {}; |
||
2538 | |||
2539 | if (!path) return { path: '', node: null }; |
||
2540 | |||
2541 | var defaults = { |
||
2542 | follow_mount: true, |
||
2543 | recurse_count: 0 |
||
2544 | }; |
||
2545 | for (var key in defaults) { |
||
2546 | if (opts[key] === undefined) { |
||
2547 | opts[key] = defaults[key]; |
||
2548 | } |
||
2549 | } |
||
2550 | |||
2551 | if (opts.recurse_count > 8) { // max recursive lookup of 8 |
||
2552 | throw new FS.ErrnoError(32); |
||
2553 | } |
||
2554 | |||
2555 | // split the path |
||
2556 | var parts = PATH.normalizeArray(path.split('/').filter(function(p) { |
||
2557 | return !!p; |
||
2558 | }), false); |
||
2559 | |||
2560 | // start at the root |
||
2561 | var current = FS.root; |
||
2562 | var current_path = '/'; |
||
2563 | |||
2564 | for (var i = 0; i < parts.length; i++) { |
||
2565 | var islast = (i === parts.length-1); |
||
2566 | if (islast && opts.parent) { |
||
2567 | // stop resolving |
||
2568 | break; |
||
2569 | } |
||
2570 | |||
2571 | current = FS.lookupNode(current, parts[i]); |
||
2572 | current_path = PATH.join2(current_path, parts[i]); |
||
2573 | |||
2574 | // jump to the mount's root node if this is a mountpoint |
||
2575 | if (FS.isMountpoint(current)) { |
||
2576 | if (!islast || (islast && opts.follow_mount)) { |
||
2577 | current = current.mounted.root; |
||
2578 | } |
||
2579 | } |
||
2580 | |||
2581 | // by default, lookupPath will not follow a symlink if it is the final path component. |
||
2582 | // setting opts.follow = true will override this behavior. |
||
2583 | if (!islast || opts.follow) { |
||
2584 | var count = 0; |
||
2585 | while (FS.isLink(current.mode)) { |
||
2586 | var link = FS.readlink(current_path); |
||
2587 | current_path = PATH_FS.resolve(PATH.dirname(current_path), link); |
||
2588 | |||
2589 | var lookup = FS.lookupPath(current_path, { recurse_count: opts.recurse_count }); |
||
2590 | current = lookup.node; |
||
2591 | |||
2592 | if (count++ > 40) { // limit max consecutive symlinks to 40 (SYMLOOP_MAX). |
||
2593 | throw new FS.ErrnoError(32); |
||
2594 | } |
||
2595 | } |
||
2596 | } |
||
2597 | } |
||
2598 | |||
2599 | return { path: current_path, node: current }; |
||
2600 | },getPath:function(node) { |
||
2601 | var path; |
||
2602 | while (true) { |
||
2603 | if (FS.isRoot(node)) { |
||
2604 | var mount = node.mount.mountpoint; |
||
2605 | if (!path) return mount; |
||
2606 | return mount[mount.length-1] !== '/' ? mount + '/' + path : mount + path; |
||
2607 | } |
||
2608 | path = path ? node.name + '/' + path : node.name; |
||
2609 | node = node.parent; |
||
2610 | } |
||
2611 | },hashName:function(parentid, name) { |
||
2612 | var hash = 0; |
||
2613 | |||
2614 | |||
2615 | for (var i = 0; i < name.length; i++) { |
||
2616 | hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0; |
||
2617 | } |
||
2618 | return ((parentid + hash) >>> 0) % FS.nameTable.length; |
||
2619 | },hashAddNode:function(node) { |
||
2620 | var hash = FS.hashName(node.parent.id, node.name); |
||
2621 | node.name_next = FS.nameTable[hash]; |
||
2622 | FS.nameTable[hash] = node; |
||
2623 | },hashRemoveNode:function(node) { |
||
2624 | var hash = FS.hashName(node.parent.id, node.name); |
||
2625 | if (FS.nameTable[hash] === node) { |
||
2626 | FS.nameTable[hash] = node.name_next; |
||
2627 | } else { |
||
2628 | var current = FS.nameTable[hash]; |
||
2629 | while (current) { |
||
2630 | if (current.name_next === node) { |
||
2631 | current.name_next = node.name_next; |
||
2632 | break; |
||
2633 | } |
||
2634 | current = current.name_next; |
||
2635 | } |
||
2636 | } |
||
2637 | },lookupNode:function(parent, name) { |
||
2638 | var errCode = FS.mayLookup(parent); |
||
2639 | if (errCode) { |
||
2640 | throw new FS.ErrnoError(errCode, parent); |
||
2641 | } |
||
2642 | var hash = FS.hashName(parent.id, name); |
||
2643 | for (var node = FS.nameTable[hash]; node; node = node.name_next) { |
||
2644 | var nodeName = node.name; |
||
2645 | if (node.parent.id === parent.id && nodeName === name) { |
||
2646 | return node; |
||
2647 | } |
||
2648 | } |
||
2649 | // if we failed to find it in the cache, call into the VFS |
||
2650 | return FS.lookup(parent, name); |
||
2651 | },createNode:function(parent, name, mode, rdev) { |
||
2652 | var node = new FS.FSNode(parent, name, mode, rdev); |
||
2653 | |||
2654 | FS.hashAddNode(node); |
||
2655 | |||
2656 | return node; |
||
2657 | },destroyNode:function(node) { |
||
2658 | FS.hashRemoveNode(node); |
||
2659 | },isRoot:function(node) { |
||
2660 | return node === node.parent; |
||
2661 | },isMountpoint:function(node) { |
||
2662 | return !!node.mounted; |
||
2663 | },isFile:function(mode) { |
||
2664 | return (mode & 61440) === 32768; |
||
2665 | },isDir:function(mode) { |
||
2666 | return (mode & 61440) === 16384; |
||
2667 | },isLink:function(mode) { |
||
2668 | return (mode & 61440) === 40960; |
||
2669 | },isChrdev:function(mode) { |
||
2670 | return (mode & 61440) === 8192; |
||
2671 | },isBlkdev:function(mode) { |
||
2672 | return (mode & 61440) === 24576; |
||
2673 | },isFIFO:function(mode) { |
||
2674 | return (mode & 61440) === 4096; |
||
2675 | },isSocket:function(mode) { |
||
2676 | return (mode & 49152) === 49152; |
||
2677 | },flagModes:{"r":0,"rs":1052672,"r+":2,"w":577,"wx":705,"xw":705,"w+":578,"wx+":706,"xw+":706,"a":1089,"ax":1217,"xa":1217,"a+":1090,"ax+":1218,"xa+":1218},modeStringToFlags:function(str) { |
||
2678 | var flags = FS.flagModes[str]; |
||
2679 | if (typeof flags === 'undefined') { |
||
2680 | throw new Error('Unknown file open mode: ' + str); |
||
2681 | } |
||
2682 | return flags; |
||
2683 | },flagsToPermissionString:function(flag) { |
||
2684 | var perms = ['r', 'w', 'rw'][flag & 3]; |
||
2685 | if ((flag & 512)) { |
||
2686 | perms += 'w'; |
||
2687 | } |
||
2688 | return perms; |
||
2689 | },nodePermissions:function(node, perms) { |
||
2690 | if (FS.ignorePermissions) { |
||
2691 | return 0; |
||
2692 | } |
||
2693 | // return 0 if any user, group or owner bits are set. |
||
2694 | if (perms.indexOf('r') !== -1 && !(node.mode & 292)) { |
||
2695 | return 2; |
||
2696 | } else if (perms.indexOf('w') !== -1 && !(node.mode & 146)) { |
||
2697 | return 2; |
||
2698 | } else if (perms.indexOf('x') !== -1 && !(node.mode & 73)) { |
||
2699 | return 2; |
||
2700 | } |
||
2701 | return 0; |
||
2702 | },mayLookup:function(dir) { |
||
2703 | var errCode = FS.nodePermissions(dir, 'x'); |
||
2704 | if (errCode) return errCode; |
||
2705 | if (!dir.node_ops.lookup) return 2; |
||
2706 | return 0; |
||
2707 | },mayCreate:function(dir, name) { |
||
2708 | try { |
||
2709 | var node = FS.lookupNode(dir, name); |
||
2710 | return 20; |
||
2711 | } catch (e) { |
||
2712 | } |
||
2713 | return FS.nodePermissions(dir, 'wx'); |
||
2714 | },mayDelete:function(dir, name, isdir) { |
||
2715 | var node; |
||
2716 | try { |
||
2717 | node = FS.lookupNode(dir, name); |
||
2718 | } catch (e) { |
||
2719 | return e.errno; |
||
2720 | } |
||
2721 | var errCode = FS.nodePermissions(dir, 'wx'); |
||
2722 | if (errCode) { |
||
2723 | return errCode; |
||
2724 | } |
||
2725 | if (isdir) { |
||
2726 | if (!FS.isDir(node.mode)) { |
||
2727 | return 54; |
||
2728 | } |
||
2729 | if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) { |
||
2730 | return 10; |
||
2731 | } |
||
2732 | } else { |
||
2733 | if (FS.isDir(node.mode)) { |
||
2734 | return 31; |
||
2735 | } |
||
2736 | } |
||
2737 | return 0; |
||
2738 | },mayOpen:function(node, flags) { |
||
2739 | if (!node) { |
||
2740 | return 44; |
||
2741 | } |
||
2742 | if (FS.isLink(node.mode)) { |
||
2743 | return 32; |
||
2744 | } else if (FS.isDir(node.mode)) { |
||
2745 | if (FS.flagsToPermissionString(flags) !== 'r' || // opening for write |
||
2746 | (flags & 512)) { // TODO: check for O_SEARCH? (== search for dir only) |
||
2747 | return 31; |
||
2748 | } |
||
2749 | } |
||
2750 | return FS.nodePermissions(node, FS.flagsToPermissionString(flags)); |
||
2751 | },MAX_OPEN_FDS:4096,nextfd:function(fd_start, fd_end) { |
||
2752 | fd_start = fd_start || 0; |
||
2753 | fd_end = fd_end || FS.MAX_OPEN_FDS; |
||
2754 | for (var fd = fd_start; fd <= fd_end; fd++) { |
||
2755 | if (!FS.streams[fd]) { |
||
2756 | return fd; |
||
2757 | } |
||
2758 | } |
||
2759 | throw new FS.ErrnoError(33); |
||
2760 | },getStream:function(fd) { |
||
2761 | return FS.streams[fd]; |
||
2762 | },createStream:function(stream, fd_start, fd_end) { |
||
2763 | if (!FS.FSStream) { |
||
2764 | FS.FSStream = /** @constructor */ function(){}; |
||
2765 | FS.FSStream.prototype = { |
||
2766 | object: { |
||
2767 | get: function() { return this.node; }, |
||
2768 | set: function(val) { this.node = val; } |
||
2769 | }, |
||
2770 | isRead: { |
||
2771 | get: function() { return (this.flags & 2097155) !== 1; } |
||
2772 | }, |
||
2773 | isWrite: { |
||
2774 | get: function() { return (this.flags & 2097155) !== 0; } |
||
2775 | }, |
||
2776 | isAppend: { |
||
2777 | get: function() { return (this.flags & 1024); } |
||
2778 | } |
||
2779 | }; |
||
2780 | } |
||
2781 | // clone it, so we can return an instance of FSStream |
||
2782 | var newStream = new FS.FSStream(); |
||
2783 | for (var p in stream) { |
||
2784 | newStream[p] = stream[p]; |
||
2785 | } |
||
2786 | stream = newStream; |
||
2787 | var fd = FS.nextfd(fd_start, fd_end); |
||
2788 | stream.fd = fd; |
||
2789 | FS.streams[fd] = stream; |
||
2790 | return stream; |
||
2791 | },closeStream:function(fd) { |
||
2792 | FS.streams[fd] = null; |
||
2793 | },chrdev_stream_ops:{open:function(stream) { |
||
2794 | var device = FS.getDevice(stream.node.rdev); |
||
2795 | // override node's stream ops with the device's |
||
2796 | stream.stream_ops = device.stream_ops; |
||
2797 | // forward the open call |
||
2798 | if (stream.stream_ops.open) { |
||
2799 | stream.stream_ops.open(stream); |
||
2800 | } |
||
2801 | },llseek:function() { |
||
2802 | throw new FS.ErrnoError(70); |
||
2803 | }},major:function(dev) { |
||
2804 | return ((dev) >> 8); |
||
2805 | },minor:function(dev) { |
||
2806 | return ((dev) & 0xff); |
||
2807 | },makedev:function(ma, mi) { |
||
2808 | return ((ma) << 8 | (mi)); |
||
2809 | },registerDevice:function(dev, ops) { |
||
2810 | FS.devices[dev] = { stream_ops: ops }; |
||
2811 | },getDevice:function(dev) { |
||
2812 | return FS.devices[dev]; |
||
2813 | },getMounts:function(mount) { |
||
2814 | var mounts = []; |
||
2815 | var check = [mount]; |
||
2816 | |||
2817 | while (check.length) { |
||
2818 | var m = check.pop(); |
||
2819 | |||
2820 | mounts.push(m); |
||
2821 | |||
2822 | check.push.apply(check, m.mounts); |
||
2823 | } |
||
2824 | |||
2825 | return mounts; |
||
2826 | },syncfs:function(populate, callback) { |
||
2827 | if (typeof(populate) === 'function') { |
||
2828 | callback = populate; |
||
2829 | populate = false; |
||
2830 | } |
||
2831 | |||
2832 | FS.syncFSRequests++; |
||
2833 | |||
2834 | if (FS.syncFSRequests > 1) { |
||
2835 | err('warning: ' + FS.syncFSRequests + ' FS.syncfs operations in flight at once, probably just doing extra work'); |
||
2836 | } |
||
2837 | |||
2838 | var mounts = FS.getMounts(FS.root.mount); |
||
2839 | var completed = 0; |
||
2840 | |||
2841 | function doCallback(errCode) { |
||
2842 | assert(FS.syncFSRequests > 0); |
||
2843 | FS.syncFSRequests--; |
||
2844 | return callback(errCode); |
||
2845 | } |
||
2846 | |||
2847 | function done(errCode) { |
||
2848 | if (errCode) { |
||
2849 | if (!done.errored) { |
||
2850 | done.errored = true; |
||
2851 | return doCallback(errCode); |
||
2852 | } |
||
2853 | return; |
||
2854 | } |
||
2855 | if (++completed >= mounts.length) { |
||
2856 | doCallback(null); |
||
2857 | } |
||
2858 | }; |
||
2859 | |||
2860 | // sync all mounts |
||
2861 | mounts.forEach(function (mount) { |
||
2862 | if (!mount.type.syncfs) { |
||
2863 | return done(null); |
||
2864 | } |
||
2865 | mount.type.syncfs(mount, populate, done); |
||
2866 | }); |
||
2867 | },mount:function(type, opts, mountpoint) { |
||
2868 | if (typeof type === 'string') { |
||
2869 | // The filesystem was not included, and instead we have an error |
||
2870 | // message stored in the variable. |
||
2871 | throw type; |
||
2872 | } |
||
2873 | var root = mountpoint === '/'; |
||
2874 | var pseudo = !mountpoint; |
||
2875 | var node; |
||
2876 | |||
2877 | if (root && FS.root) { |
||
2878 | throw new FS.ErrnoError(10); |
||
2879 | } else if (!root && !pseudo) { |
||
2880 | var lookup = FS.lookupPath(mountpoint, { follow_mount: false }); |
||
2881 | |||
2882 | mountpoint = lookup.path; // use the absolute path |
||
2883 | node = lookup.node; |
||
2884 | |||
2885 | if (FS.isMountpoint(node)) { |
||
2886 | throw new FS.ErrnoError(10); |
||
2887 | } |
||
2888 | |||
2889 | if (!FS.isDir(node.mode)) { |
||
2890 | throw new FS.ErrnoError(54); |
||
2891 | } |
||
2892 | } |
||
2893 | |||
2894 | var mount = { |
||
2895 | type: type, |
||
2896 | opts: opts, |
||
2897 | mountpoint: mountpoint, |
||
2898 | mounts: [] |
||
2899 | }; |
||
2900 | |||
2901 | // create a root node for the fs |
||
2902 | var mountRoot = type.mount(mount); |
||
2903 | mountRoot.mount = mount; |
||
2904 | mount.root = mountRoot; |
||
2905 | |||
2906 | if (root) { |
||
2907 | FS.root = mountRoot; |
||
2908 | } else if (node) { |
||
2909 | // set as a mountpoint |
||
2910 | node.mounted = mount; |
||
2911 | |||
2912 | // add the new mount to the current mount's children |
||
2913 | if (node.mount) { |
||
2914 | node.mount.mounts.push(mount); |
||
2915 | } |
||
2916 | } |
||
2917 | |||
2918 | return mountRoot; |
||
2919 | },unmount:function (mountpoint) { |
||
2920 | var lookup = FS.lookupPath(mountpoint, { follow_mount: false }); |
||
2921 | |||
2922 | if (!FS.isMountpoint(lookup.node)) { |
||
2923 | throw new FS.ErrnoError(28); |
||
2924 | } |
||
2925 | |||
2926 | // destroy the nodes for this mount, and all its child mounts |
||
2927 | var node = lookup.node; |
||
2928 | var mount = node.mounted; |
||
2929 | var mounts = FS.getMounts(mount); |
||
2930 | |||
2931 | Object.keys(FS.nameTable).forEach(function (hash) { |
||
2932 | var current = FS.nameTable[hash]; |
||
2933 | |||
2934 | while (current) { |
||
2935 | var next = current.name_next; |
||
2936 | |||
2937 | if (mounts.indexOf(current.mount) !== -1) { |
||
2938 | FS.destroyNode(current); |
||
2939 | } |
||
2940 | |||
2941 | current = next; |
||
2942 | } |
||
2943 | }); |
||
2944 | |||
2945 | // no longer a mountpoint |
||
2946 | node.mounted = null; |
||
2947 | |||
2948 | // remove this mount from the child mounts |
||
2949 | var idx = node.mount.mounts.indexOf(mount); |
||
2950 | assert(idx !== -1); |
||
2951 | node.mount.mounts.splice(idx, 1); |
||
2952 | },lookup:function(parent, name) { |
||
2953 | return parent.node_ops.lookup(parent, name); |
||
2954 | },mknod:function(path, mode, dev) { |
||
2955 | var lookup = FS.lookupPath(path, { parent: true }); |
||
2956 | var parent = lookup.node; |
||
2957 | var name = PATH.basename(path); |
||
2958 | if (!name || name === '.' || name === '..') { |
||
2959 | throw new FS.ErrnoError(28); |
||
2960 | } |
||
2961 | var errCode = FS.mayCreate(parent, name); |
||
2962 | if (errCode) { |
||
2963 | throw new FS.ErrnoError(errCode); |
||
2964 | } |
||
2965 | if (!parent.node_ops.mknod) { |
||
2966 | throw new FS.ErrnoError(63); |
||
2967 | } |
||
2968 | return parent.node_ops.mknod(parent, name, mode, dev); |
||
2969 | },create:function(path, mode) { |
||
2970 | mode = mode !== undefined ? mode : 438 /* 0666 */; |
||
2971 | mode &= 4095; |
||
2972 | mode |= 32768; |
||
2973 | return FS.mknod(path, mode, 0); |
||
2974 | },mkdir:function(path, mode) { |
||
2975 | mode = mode !== undefined ? mode : 511 /* 0777 */; |
||
2976 | mode &= 511 | 512; |
||
2977 | mode |= 16384; |
||
2978 | return FS.mknod(path, mode, 0); |
||
2979 | },mkdirTree:function(path, mode) { |
||
2980 | var dirs = path.split('/'); |
||
2981 | var d = ''; |
||
2982 | for (var i = 0; i < dirs.length; ++i) { |
||
2983 | if (!dirs[i]) continue; |
||
2984 | d += '/' + dirs[i]; |
||
2985 | try { |
||
2986 | FS.mkdir(d, mode); |
||
2987 | } catch(e) { |
||
2988 | if (e.errno != 20) throw e; |
||
2989 | } |
||
2990 | } |
||
2991 | },mkdev:function(path, mode, dev) { |
||
2992 | if (typeof(dev) === 'undefined') { |
||
2993 | dev = mode; |
||
2994 | mode = 438 /* 0666 */; |
||
2995 | } |
||
2996 | mode |= 8192; |
||
2997 | return FS.mknod(path, mode, dev); |
||
2998 | },symlink:function(oldpath, newpath) { |
||
2999 | if (!PATH_FS.resolve(oldpath)) { |
||
3000 | throw new FS.ErrnoError(44); |
||
3001 | } |
||
3002 | var lookup = FS.lookupPath(newpath, { parent: true }); |
||
3003 | var parent = lookup.node; |
||
3004 | if (!parent) { |
||
3005 | throw new FS.ErrnoError(44); |
||
3006 | } |
||
3007 | var newname = PATH.basename(newpath); |
||
3008 | var errCode = FS.mayCreate(parent, newname); |
||
3009 | if (errCode) { |
||
3010 | throw new FS.ErrnoError(errCode); |
||
3011 | } |
||
3012 | if (!parent.node_ops.symlink) { |
||
3013 | throw new FS.ErrnoError(63); |
||
3014 | } |
||
3015 | return parent.node_ops.symlink(parent, newname, oldpath); |
||
3016 | },rename:function(old_path, new_path) { |
||
3017 | var old_dirname = PATH.dirname(old_path); |
||
3018 | var new_dirname = PATH.dirname(new_path); |
||
3019 | var old_name = PATH.basename(old_path); |
||
3020 | var new_name = PATH.basename(new_path); |
||
3021 | // parents must exist |
||
3022 | var lookup, old_dir, new_dir; |
||
3023 | try { |
||
3024 | lookup = FS.lookupPath(old_path, { parent: true }); |
||
3025 | old_dir = lookup.node; |
||
3026 | lookup = FS.lookupPath(new_path, { parent: true }); |
||
3027 | new_dir = lookup.node; |
||
3028 | } catch (e) { |
||
3029 | throw new FS.ErrnoError(10); |
||
3030 | } |
||
3031 | if (!old_dir || !new_dir) throw new FS.ErrnoError(44); |
||
3032 | // need to be part of the same mount |
||
3033 | if (old_dir.mount !== new_dir.mount) { |
||
3034 | throw new FS.ErrnoError(75); |
||
3035 | } |
||
3036 | // source must exist |
||
3037 | var old_node = FS.lookupNode(old_dir, old_name); |
||
3038 | // old path should not be an ancestor of the new path |
||
3039 | var relative = PATH_FS.relative(old_path, new_dirname); |
||
3040 | if (relative.charAt(0) !== '.') { |
||
3041 | throw new FS.ErrnoError(28); |
||
3042 | } |
||
3043 | // new path should not be an ancestor of the old path |
||
3044 | relative = PATH_FS.relative(new_path, old_dirname); |
||
3045 | if (relative.charAt(0) !== '.') { |
||
3046 | throw new FS.ErrnoError(55); |
||
3047 | } |
||
3048 | // see if the new path already exists |
||
3049 | var new_node; |
||
3050 | try { |
||
3051 | new_node = FS.lookupNode(new_dir, new_name); |
||
3052 | } catch (e) { |
||
3053 | // not fatal |
||
3054 | } |
||
3055 | // early out if nothing needs to change |
||
3056 | if (old_node === new_node) { |
||
3057 | return; |
||
3058 | } |
||
3059 | // we'll need to delete the old entry |
||
3060 | var isdir = FS.isDir(old_node.mode); |
||
3061 | var errCode = FS.mayDelete(old_dir, old_name, isdir); |
||
3062 | if (errCode) { |
||
3063 | throw new FS.ErrnoError(errCode); |
||
3064 | } |
||
3065 | // need delete permissions if we'll be overwriting. |
||
3066 | // need create permissions if new doesn't already exist. |
||
3067 | errCode = new_node ? |
||
3068 | FS.mayDelete(new_dir, new_name, isdir) : |
||
3069 | FS.mayCreate(new_dir, new_name); |
||
3070 | if (errCode) { |
||
3071 | throw new FS.ErrnoError(errCode); |
||
3072 | } |
||
3073 | if (!old_dir.node_ops.rename) { |
||
3074 | throw new FS.ErrnoError(63); |
||
3075 | } |
||
3076 | if (FS.isMountpoint(old_node) || (new_node && FS.isMountpoint(new_node))) { |
||
3077 | throw new FS.ErrnoError(10); |
||
3078 | } |
||
3079 | // if we are going to change the parent, check write permissions |
||
3080 | if (new_dir !== old_dir) { |
||
3081 | errCode = FS.nodePermissions(old_dir, 'w'); |
||
3082 | if (errCode) { |
||
3083 | throw new FS.ErrnoError(errCode); |
||
3084 | } |
||
3085 | } |
||
3086 | try { |
||
3087 | if (FS.trackingDelegate['willMovePath']) { |
||
3088 | FS.trackingDelegate['willMovePath'](old_path, new_path); |
||
3089 | } |
||
3090 | } catch(e) { |
||
3091 | err("FS.trackingDelegate['willMovePath']('"+old_path+"', '"+new_path+"') threw an exception: " + e.message); |
||
3092 | } |
||
3093 | // remove the node from the lookup hash |
||
3094 | FS.hashRemoveNode(old_node); |
||
3095 | // do the underlying fs rename |
||
3096 | try { |
||
3097 | old_dir.node_ops.rename(old_node, new_dir, new_name); |
||
3098 | } catch (e) { |
||
3099 | throw e; |
||
3100 | } finally { |
||
3101 | // add the node back to the hash (in case node_ops.rename |
||
3102 | // changed its name) |
||
3103 | FS.hashAddNode(old_node); |
||
3104 | } |
||
3105 | try { |
||
3106 | if (FS.trackingDelegate['onMovePath']) FS.trackingDelegate['onMovePath'](old_path, new_path); |
||
3107 | } catch(e) { |
||
3108 | err("FS.trackingDelegate['onMovePath']('"+old_path+"', '"+new_path+"') threw an exception: " + e.message); |
||
3109 | } |
||
3110 | },rmdir:function(path) { |
||
3111 | var lookup = FS.lookupPath(path, { parent: true }); |
||
3112 | var parent = lookup.node; |
||
3113 | var name = PATH.basename(path); |
||
3114 | var node = FS.lookupNode(parent, name); |
||
3115 | var errCode = FS.mayDelete(parent, name, true); |
||
3116 | if (errCode) { |
||
3117 | throw new FS.ErrnoError(errCode); |
||
3118 | } |
||
3119 | if (!parent.node_ops.rmdir) { |
||
3120 | throw new FS.ErrnoError(63); |
||
3121 | } |
||
3122 | if (FS.isMountpoint(node)) { |
||
3123 | throw new FS.ErrnoError(10); |
||
3124 | } |
||
3125 | try { |
||
3126 | if (FS.trackingDelegate['willDeletePath']) { |
||
3127 | FS.trackingDelegate['willDeletePath'](path); |
||
3128 | } |
||
3129 | } catch(e) { |
||
3130 | err("FS.trackingDelegate['willDeletePath']('"+path+"') threw an exception: " + e.message); |
||
3131 | } |
||
3132 | parent.node_ops.rmdir(parent, name); |
||
3133 | FS.destroyNode(node); |
||
3134 | try { |
||
3135 | if (FS.trackingDelegate['onDeletePath']) FS.trackingDelegate['onDeletePath'](path); |
||
3136 | } catch(e) { |
||
3137 | err("FS.trackingDelegate['onDeletePath']('"+path+"') threw an exception: " + e.message); |
||
3138 | } |
||
3139 | },readdir:function(path) { |
||
3140 | var lookup = FS.lookupPath(path, { follow: true }); |
||
3141 | var node = lookup.node; |
||
3142 | if (!node.node_ops.readdir) { |
||
3143 | throw new FS.ErrnoError(54); |
||
3144 | } |
||
3145 | return node.node_ops.readdir(node); |
||
3146 | },unlink:function(path) { |
||
3147 | var lookup = FS.lookupPath(path, { parent: true }); |
||
3148 | var parent = lookup.node; |
||
3149 | var name = PATH.basename(path); |
||
3150 | var node = FS.lookupNode(parent, name); |
||
3151 | var errCode = FS.mayDelete(parent, name, false); |
||
3152 | if (errCode) { |
||
3153 | // According to POSIX, we should map EISDIR to EPERM, but |
||
3154 | // we instead do what Linux does (and we must, as we use |
||
3155 | // the musl linux libc). |
||
3156 | throw new FS.ErrnoError(errCode); |
||
3157 | } |
||
3158 | if (!parent.node_ops.unlink) { |
||
3159 | throw new FS.ErrnoError(63); |
||
3160 | } |
||
3161 | if (FS.isMountpoint(node)) { |
||
3162 | throw new FS.ErrnoError(10); |
||
3163 | } |
||
3164 | try { |
||
3165 | if (FS.trackingDelegate['willDeletePath']) { |
||
3166 | FS.trackingDelegate['willDeletePath'](path); |
||
3167 | } |
||
3168 | } catch(e) { |
||
3169 | err("FS.trackingDelegate['willDeletePath']('"+path+"') threw an exception: " + e.message); |
||
3170 | } |
||
3171 | parent.node_ops.unlink(parent, name); |
||
3172 | FS.destroyNode(node); |
||
3173 | try { |
||
3174 | if (FS.trackingDelegate['onDeletePath']) FS.trackingDelegate['onDeletePath'](path); |
||
3175 | } catch(e) { |
||
3176 | err("FS.trackingDelegate['onDeletePath']('"+path+"') threw an exception: " + e.message); |
||
3177 | } |
||
3178 | },readlink:function(path) { |
||
3179 | var lookup = FS.lookupPath(path); |
||
3180 | var link = lookup.node; |
||
3181 | if (!link) { |
||
3182 | throw new FS.ErrnoError(44); |
||
3183 | } |
||
3184 | if (!link.node_ops.readlink) { |
||
3185 | throw new FS.ErrnoError(28); |
||
3186 | } |
||
3187 | return PATH_FS.resolve(FS.getPath(link.parent), link.node_ops.readlink(link)); |
||
3188 | },stat:function(path, dontFollow) { |
||
3189 | var lookup = FS.lookupPath(path, { follow: !dontFollow }); |
||
3190 | var node = lookup.node; |
||
3191 | if (!node) { |
||
3192 | throw new FS.ErrnoError(44); |
||
3193 | } |
||
3194 | if (!node.node_ops.getattr) { |
||
3195 | throw new FS.ErrnoError(63); |
||
3196 | } |
||
3197 | return node.node_ops.getattr(node); |
||
3198 | },lstat:function(path) { |
||
3199 | return FS.stat(path, true); |
||
3200 | },chmod:function(path, mode, dontFollow) { |
||
3201 | var node; |
||
3202 | if (typeof path === 'string') { |
||
3203 | var lookup = FS.lookupPath(path, { follow: !dontFollow }); |
||
3204 | node = lookup.node; |
||
3205 | } else { |
||
3206 | node = path; |
||
3207 | } |
||
3208 | if (!node.node_ops.setattr) { |
||
3209 | throw new FS.ErrnoError(63); |
||
3210 | } |
||
3211 | node.node_ops.setattr(node, { |
||
3212 | mode: (mode & 4095) | (node.mode & ~4095), |
||
3213 | timestamp: Date.now() |
||
3214 | }); |
||
3215 | },lchmod:function(path, mode) { |
||
3216 | FS.chmod(path, mode, true); |
||
3217 | },fchmod:function(fd, mode) { |
||
3218 | var stream = FS.getStream(fd); |
||
3219 | if (!stream) { |
||
3220 | throw new FS.ErrnoError(8); |
||
3221 | } |
||
3222 | FS.chmod(stream.node, mode); |
||
3223 | },chown:function(path, uid, gid, dontFollow) { |
||
3224 | var node; |
||
3225 | if (typeof path === 'string') { |
||
3226 | var lookup = FS.lookupPath(path, { follow: !dontFollow }); |
||
3227 | node = lookup.node; |
||
3228 | } else { |
||
3229 | node = path; |
||
3230 | } |
||
3231 | if (!node.node_ops.setattr) { |
||
3232 | throw new FS.ErrnoError(63); |
||
3233 | } |
||
3234 | node.node_ops.setattr(node, { |
||
3235 | timestamp: Date.now() |
||
3236 | // we ignore the uid / gid for now |
||
3237 | }); |
||
3238 | },lchown:function(path, uid, gid) { |
||
3239 | FS.chown(path, uid, gid, true); |
||
3240 | },fchown:function(fd, uid, gid) { |
||
3241 | var stream = FS.getStream(fd); |
||
3242 | if (!stream) { |
||
3243 | throw new FS.ErrnoError(8); |
||
3244 | } |
||
3245 | FS.chown(stream.node, uid, gid); |
||
3246 | },truncate:function(path, len) { |
||
3247 | if (len < 0) { |
||
3248 | throw new FS.ErrnoError(28); |
||
3249 | } |
||
3250 | var node; |
||
3251 | if (typeof path === 'string') { |
||
3252 | var lookup = FS.lookupPath(path, { follow: true }); |
||
3253 | node = lookup.node; |
||
3254 | } else { |
||
3255 | node = path; |
||
3256 | } |
||
3257 | if (!node.node_ops.setattr) { |
||
3258 | throw new FS.ErrnoError(63); |
||
3259 | } |
||
3260 | if (FS.isDir(node.mode)) { |
||
3261 | throw new FS.ErrnoError(31); |
||
3262 | } |
||
3263 | if (!FS.isFile(node.mode)) { |
||
3264 | throw new FS.ErrnoError(28); |
||
3265 | } |
||
3266 | var errCode = FS.nodePermissions(node, 'w'); |
||
3267 | if (errCode) { |
||
3268 | throw new FS.ErrnoError(errCode); |
||
3269 | } |
||
3270 | node.node_ops.setattr(node, { |
||
3271 | size: len, |
||
3272 | timestamp: Date.now() |
||
3273 | }); |
||
3274 | },ftruncate:function(fd, len) { |
||
3275 | var stream = FS.getStream(fd); |
||
3276 | if (!stream) { |
||
3277 | throw new FS.ErrnoError(8); |
||
3278 | } |
||
3279 | if ((stream.flags & 2097155) === 0) { |
||
3280 | throw new FS.ErrnoError(28); |
||
3281 | } |
||
3282 | FS.truncate(stream.node, len); |
||
3283 | },utime:function(path, atime, mtime) { |
||
3284 | var lookup = FS.lookupPath(path, { follow: true }); |
||
3285 | var node = lookup.node; |
||
3286 | node.node_ops.setattr(node, { |
||
3287 | timestamp: Math.max(atime, mtime) |
||
3288 | }); |
||
3289 | },open:function(path, flags, mode, fd_start, fd_end) { |
||
3290 | if (path === "") { |
||
3291 | throw new FS.ErrnoError(44); |
||
3292 | } |
||
3293 | flags = typeof flags === 'string' ? FS.modeStringToFlags(flags) : flags; |
||
3294 | mode = typeof mode === 'undefined' ? 438 /* 0666 */ : mode; |
||
3295 | if ((flags & 64)) { |
||
3296 | mode = (mode & 4095) | 32768; |
||
3297 | } else { |
||
3298 | mode = 0; |
||
3299 | } |
||
3300 | var node; |
||
3301 | if (typeof path === 'object') { |
||
3302 | node = path; |
||
3303 | } else { |
||
3304 | path = PATH.normalize(path); |
||
3305 | try { |
||
3306 | var lookup = FS.lookupPath(path, { |
||
3307 | follow: !(flags & 131072) |
||
3308 | }); |
||
3309 | node = lookup.node; |
||
3310 | } catch (e) { |
||
3311 | // ignore |
||
3312 | } |
||
3313 | } |
||
3314 | // perhaps we need to create the node |
||
3315 | var created = false; |
||
3316 | if ((flags & 64)) { |
||
3317 | if (node) { |
||
3318 | // if O_CREAT and O_EXCL are set, error out if the node already exists |
||
3319 | if ((flags & 128)) { |
||
3320 | throw new FS.ErrnoError(20); |
||
3321 | } |
||
3322 | } else { |
||
3323 | // node doesn't exist, try to create it |
||
3324 | node = FS.mknod(path, mode, 0); |
||
3325 | created = true; |
||
3326 | } |
||
3327 | } |
||
3328 | if (!node) { |
||
3329 | throw new FS.ErrnoError(44); |
||
3330 | } |
||
3331 | // can't truncate a device |
||
3332 | if (FS.isChrdev(node.mode)) { |
||
3333 | flags &= ~512; |
||
3334 | } |
||
3335 | // if asked only for a directory, then this must be one |
||
3336 | if ((flags & 65536) && !FS.isDir(node.mode)) { |
||
3337 | throw new FS.ErrnoError(54); |
||
3338 | } |
||
3339 | // check permissions, if this is not a file we just created now (it is ok to |
||
3340 | // create and write to a file with read-only permissions; it is read-only |
||
3341 | // for later use) |
||
3342 | if (!created) { |
||
3343 | var errCode = FS.mayOpen(node, flags); |
||
3344 | if (errCode) { |
||
3345 | throw new FS.ErrnoError(errCode); |
||
3346 | } |
||
3347 | } |
||
3348 | // do truncation if necessary |
||
3349 | if ((flags & 512)) { |
||
3350 | FS.truncate(node, 0); |
||
3351 | } |
||
3352 | // we've already handled these, don't pass down to the underlying vfs |
||
3353 | flags &= ~(128 | 512 | 131072); |
||
3354 | |||
3355 | // register the stream with the filesystem |
||
3356 | var stream = FS.createStream({ |
||
3357 | node: node, |
||
3358 | path: FS.getPath(node), // we want the absolute path to the node |
||
3359 | flags: flags, |
||
3360 | seekable: true, |
||
3361 | position: 0, |
||
3362 | stream_ops: node.stream_ops, |
||
3363 | // used by the file family libc calls (fopen, fwrite, ferror, etc.) |
||
3364 | ungotten: [], |
||
3365 | error: false |
||
3366 | }, fd_start, fd_end); |
||
3367 | // call the new stream's open function |
||
3368 | if (stream.stream_ops.open) { |
||
3369 | stream.stream_ops.open(stream); |
||
3370 | } |
||
3371 | if (Module['logReadFiles'] && !(flags & 1)) { |
||
3372 | if (!FS.readFiles) FS.readFiles = {}; |
||
3373 | if (!(path in FS.readFiles)) { |
||
3374 | FS.readFiles[path] = 1; |
||
3375 | err("FS.trackingDelegate error on read file: " + path); |
||
3376 | } |
||
3377 | } |
||
3378 | try { |
||
3379 | if (FS.trackingDelegate['onOpenFile']) { |
||
3380 | var trackingFlags = 0; |
||
3381 | if ((flags & 2097155) !== 1) { |
||
3382 | trackingFlags |= FS.tracking.openFlags.READ; |
||
3383 | } |
||
3384 | if ((flags & 2097155) !== 0) { |
||
3385 | trackingFlags |= FS.tracking.openFlags.WRITE; |
||
3386 | } |
||
3387 | FS.trackingDelegate['onOpenFile'](path, trackingFlags); |
||
3388 | } |
||
3389 | } catch(e) { |
||
3390 | err("FS.trackingDelegate['onOpenFile']('"+path+"', flags) threw an exception: " + e.message); |
||
3391 | } |
||
3392 | return stream; |
||
3393 | },close:function(stream) { |
||
3394 | if (FS.isClosed(stream)) { |
||
3395 | throw new FS.ErrnoError(8); |
||
3396 | } |
||
3397 | if (stream.getdents) stream.getdents = null; // free readdir state |
||
3398 | try { |
||
3399 | if (stream.stream_ops.close) { |
||
3400 | stream.stream_ops.close(stream); |
||
3401 | } |
||
3402 | } catch (e) { |
||
3403 | throw e; |
||
3404 | } finally { |
||
3405 | FS.closeStream(stream.fd); |
||
3406 | } |
||
3407 | stream.fd = null; |
||
3408 | },isClosed:function(stream) { |
||
3409 | return stream.fd === null; |
||
3410 | },llseek:function(stream, offset, whence) { |
||
3411 | if (FS.isClosed(stream)) { |
||
3412 | throw new FS.ErrnoError(8); |
||
3413 | } |
||
3414 | if (!stream.seekable || !stream.stream_ops.llseek) { |
||
3415 | throw new FS.ErrnoError(70); |
||
3416 | } |
||
3417 | if (whence != 0 && whence != 1 && whence != 2) { |
||
3418 | throw new FS.ErrnoError(28); |
||
3419 | } |
||
3420 | stream.position = stream.stream_ops.llseek(stream, offset, whence); |
||
3421 | stream.ungotten = []; |
||
3422 | return stream.position; |
||
3423 | },read:function(stream, buffer, offset, length, position) { |
||
3424 | if (length < 0 || position < 0) { |
||
3425 | throw new FS.ErrnoError(28); |
||
3426 | } |
||
3427 | if (FS.isClosed(stream)) { |
||
3428 | throw new FS.ErrnoError(8); |
||
3429 | } |
||
3430 | if ((stream.flags & 2097155) === 1) { |
||
3431 | throw new FS.ErrnoError(8); |
||
3432 | } |
||
3433 | if (FS.isDir(stream.node.mode)) { |
||
3434 | throw new FS.ErrnoError(31); |
||
3435 | } |
||
3436 | if (!stream.stream_ops.read) { |
||
3437 | throw new FS.ErrnoError(28); |
||
3438 | } |
||
3439 | var seeking = typeof position !== 'undefined'; |
||
3440 | if (!seeking) { |
||
3441 | position = stream.position; |
||
3442 | } else if (!stream.seekable) { |
||
3443 | throw new FS.ErrnoError(70); |
||
3444 | } |
||
3445 | var bytesRead = stream.stream_ops.read(stream, buffer, offset, length, position); |
||
3446 | if (!seeking) stream.position += bytesRead; |
||
3447 | return bytesRead; |
||
3448 | },write:function(stream, buffer, offset, length, position, canOwn) { |
||
3449 | if (length < 0 || position < 0) { |
||
3450 | throw new FS.ErrnoError(28); |
||
3451 | } |
||
3452 | if (FS.isClosed(stream)) { |
||
3453 | throw new FS.ErrnoError(8); |
||
3454 | } |
||
3455 | if ((stream.flags & 2097155) === 0) { |
||
3456 | throw new FS.ErrnoError(8); |
||
3457 | } |
||
3458 | if (FS.isDir(stream.node.mode)) { |
||
3459 | throw new FS.ErrnoError(31); |
||
3460 | } |
||
3461 | if (!stream.stream_ops.write) { |
||
3462 | throw new FS.ErrnoError(28); |
||
3463 | } |
||
3464 | if (stream.seekable && stream.flags & 1024) { |
||
3465 | // seek to the end before writing in append mode |
||
3466 | FS.llseek(stream, 0, 2); |
||
3467 | } |
||
3468 | var seeking = typeof position !== 'undefined'; |
||
3469 | if (!seeking) { |
||
3470 | position = stream.position; |
||
3471 | } else if (!stream.seekable) { |
||
3472 | throw new FS.ErrnoError(70); |
||
3473 | } |
||
3474 | var bytesWritten = stream.stream_ops.write(stream, buffer, offset, length, position, canOwn); |
||
3475 | if (!seeking) stream.position += bytesWritten; |
||
3476 | try { |
||
3477 | if (stream.path && FS.trackingDelegate['onWriteToFile']) FS.trackingDelegate['onWriteToFile'](stream.path); |
||
3478 | } catch(e) { |
||
3479 | err("FS.trackingDelegate['onWriteToFile']('"+stream.path+"') threw an exception: " + e.message); |
||
3480 | } |
||
3481 | return bytesWritten; |
||
3482 | },allocate:function(stream, offset, length) { |
||
3483 | if (FS.isClosed(stream)) { |
||
3484 | throw new FS.ErrnoError(8); |
||
3485 | } |
||
3486 | if (offset < 0 || length <= 0) { |
||
3487 | throw new FS.ErrnoError(28); |
||
3488 | } |
||
3489 | if ((stream.flags & 2097155) === 0) { |
||
3490 | throw new FS.ErrnoError(8); |
||
3491 | } |
||
3492 | if (!FS.isFile(stream.node.mode) && !FS.isDir(stream.node.mode)) { |
||
3493 | throw new FS.ErrnoError(43); |
||
3494 | } |
||
3495 | if (!stream.stream_ops.allocate) { |
||
3496 | throw new FS.ErrnoError(138); |
||
3497 | } |
||
3498 | stream.stream_ops.allocate(stream, offset, length); |
||
3499 | },mmap:function(stream, address, length, position, prot, flags) { |
||
3500 | // User requests writing to file (prot & PROT_WRITE != 0). |
||
3501 | // Checking if we have permissions to write to the file unless |
||
3502 | // MAP_PRIVATE flag is set. According to POSIX spec it is possible |
||
3503 | // to write to file opened in read-only mode with MAP_PRIVATE flag, |
||
3504 | // as all modifications will be visible only in the memory of |
||
3505 | // the current process. |
||
3506 | if ((prot & 2) !== 0 |
||
3507 | && (flags & 2) === 0 |
||
3508 | && (stream.flags & 2097155) !== 2) { |
||
3509 | throw new FS.ErrnoError(2); |
||
3510 | } |
||
3511 | if ((stream.flags & 2097155) === 1) { |
||
3512 | throw new FS.ErrnoError(2); |
||
3513 | } |
||
3514 | if (!stream.stream_ops.mmap) { |
||
3515 | throw new FS.ErrnoError(43); |
||
3516 | } |
||
3517 | return stream.stream_ops.mmap(stream, address, length, position, prot, flags); |
||
3518 | },msync:function(stream, buffer, offset, length, mmapFlags) { |
||
3519 | if (!stream || !stream.stream_ops.msync) { |
||
3520 | return 0; |
||
3521 | } |
||
3522 | return stream.stream_ops.msync(stream, buffer, offset, length, mmapFlags); |
||
3523 | },munmap:function(stream) { |
||
3524 | return 0; |
||
3525 | },ioctl:function(stream, cmd, arg) { |
||
3526 | if (!stream.stream_ops.ioctl) { |
||
3527 | throw new FS.ErrnoError(59); |
||
3528 | } |
||
3529 | return stream.stream_ops.ioctl(stream, cmd, arg); |
||
3530 | },readFile:function(path, opts) { |
||
3531 | opts = opts || {}; |
||
3532 | opts.flags = opts.flags || 'r'; |
||
3533 | opts.encoding = opts.encoding || 'binary'; |
||
3534 | if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') { |
||
3535 | throw new Error('Invalid encoding type "' + opts.encoding + '"'); |
||
3536 | } |
||
3537 | var ret; |
||
3538 | var stream = FS.open(path, opts.flags); |
||
3539 | var stat = FS.stat(path); |
||
3540 | var length = stat.size; |
||
3541 | var buf = new Uint8Array(length); |
||
3542 | FS.read(stream, buf, 0, length, 0); |
||
3543 | if (opts.encoding === 'utf8') { |
||
3544 | ret = UTF8ArrayToString(buf, 0); |
||
3545 | } else if (opts.encoding === 'binary') { |
||
3546 | ret = buf; |
||
3547 | } |
||
3548 | FS.close(stream); |
||
3549 | return ret; |
||
3550 | },writeFile:function(path, data, opts) { |
||
3551 | opts = opts || {}; |
||
3552 | opts.flags = opts.flags || 'w'; |
||
3553 | var stream = FS.open(path, opts.flags, opts.mode); |
||
3554 | if (typeof data === 'string') { |
||
3555 | var buf = new Uint8Array(lengthBytesUTF8(data)+1); |
||
3556 | var actualNumBytes = stringToUTF8Array(data, buf, 0, buf.length); |
||
3557 | FS.write(stream, buf, 0, actualNumBytes, undefined, opts.canOwn); |
||
3558 | } else if (ArrayBuffer.isView(data)) { |
||
3559 | FS.write(stream, data, 0, data.byteLength, undefined, opts.canOwn); |
||
3560 | } else { |
||
3561 | throw new Error('Unsupported data type'); |
||
3562 | } |
||
3563 | FS.close(stream); |
||
3564 | },cwd:function() { |
||
3565 | return FS.currentPath; |
||
3566 | },chdir:function(path) { |
||
3567 | var lookup = FS.lookupPath(path, { follow: true }); |
||
3568 | if (lookup.node === null) { |
||
3569 | throw new FS.ErrnoError(44); |
||
3570 | } |
||
3571 | if (!FS.isDir(lookup.node.mode)) { |
||
3572 | throw new FS.ErrnoError(54); |
||
3573 | } |
||
3574 | var errCode = FS.nodePermissions(lookup.node, 'x'); |
||
3575 | if (errCode) { |
||
3576 | throw new FS.ErrnoError(errCode); |
||
3577 | } |
||
3578 | FS.currentPath = lookup.path; |
||
3579 | },createDefaultDirectories:function() { |
||
3580 | FS.mkdir('/tmp'); |
||
3581 | FS.mkdir('/home'); |
||
3582 | FS.mkdir('/home/web_user'); |
||
3583 | },createDefaultDevices:function() { |
||
3584 | // create /dev |
||
3585 | FS.mkdir('/dev'); |
||
3586 | // setup /dev/null |
||
3587 | FS.registerDevice(FS.makedev(1, 3), { |
||
3588 | read: function() { return 0; }, |
||
3589 | write: function(stream, buffer, offset, length, pos) { return length; } |
||
3590 | }); |
||
3591 | FS.mkdev('/dev/null', FS.makedev(1, 3)); |
||
3592 | // setup /dev/tty and /dev/tty1 |
||
3593 | // stderr needs to print output using Module['printErr'] |
||
3594 | // so we register a second tty just for it. |
||
3595 | TTY.register(FS.makedev(5, 0), TTY.default_tty_ops); |
||
3596 | TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops); |
||
3597 | FS.mkdev('/dev/tty', FS.makedev(5, 0)); |
||
3598 | FS.mkdev('/dev/tty1', FS.makedev(6, 0)); |
||
3599 | // setup /dev/[u]random |
||
3600 | var random_device; |
||
3601 | if (typeof crypto === 'object' && typeof crypto['getRandomValues'] === 'function') { |
||
3602 | // for modern web browsers |
||
3603 | var randomBuffer = new Uint8Array(1); |
||
3604 | random_device = function() { crypto.getRandomValues(randomBuffer); return randomBuffer[0]; }; |
||
3605 | } else |
||
3606 | if (ENVIRONMENT_IS_NODE) { |
||
3607 | // for nodejs with or without crypto support included |
||
3608 | try { |
||
3609 | var crypto_module = require('crypto'); |
||
3610 | // nodejs has crypto support |
||
3611 | random_device = function() { return crypto_module['randomBytes'](1)[0]; }; |
||
3612 | } catch (e) { |
||
3613 | // nodejs doesn't have crypto support |
||
3614 | } |
||
3615 | } else |
||
3616 | {} |
||
3617 | if (!random_device) { |
||
3618 | // we couldn't find a proper implementation, as Math.random() is not suitable for /dev/random, see emscripten-core/emscripten/pull/7096 |
||
3619 | random_device = function() { abort("no cryptographic support found for random_device. consider polyfilling it if you want to use something insecure like Math.random(), e.g. put this in a --pre-js: var crypto = { getRandomValues: function(array) { for (var i = 0; i < array.length; i++) array[i] = (Math.random()*256)|0 } };"); }; |
||
3620 | } |
||
3621 | FS.createDevice('/dev', 'random', random_device); |
||
3622 | FS.createDevice('/dev', 'urandom', random_device); |
||
3623 | // we're not going to emulate the actual shm device, |
||
3624 | // just create the tmp dirs that reside in it commonly |
||
3625 | FS.mkdir('/dev/shm'); |
||
3626 | FS.mkdir('/dev/shm/tmp'); |
||
3627 | },createSpecialDirectories:function() { |
||
3628 | // create /proc/self/fd which allows /proc/self/fd/6 => readlink gives the name of the stream for fd 6 (see test_unistd_ttyname) |
||
3629 | FS.mkdir('/proc'); |
||
3630 | FS.mkdir('/proc/self'); |
||
3631 | FS.mkdir('/proc/self/fd'); |
||
3632 | FS.mount({ |
||
3633 | mount: function() { |
||
3634 | var node = FS.createNode('/proc/self', 'fd', 16384 | 511 /* 0777 */, 73); |
||
3635 | node.node_ops = { |
||
3636 | lookup: function(parent, name) { |
||
3637 | var fd = +name; |
||
3638 | var stream = FS.getStream(fd); |
||
3639 | if (!stream) throw new FS.ErrnoError(8); |
||
3640 | var ret = { |
||
3641 | parent: null, |
||
3642 | mount: { mountpoint: 'fake' }, |
||
3643 | node_ops: { readlink: function() { return stream.path } } |
||
3644 | }; |
||
3645 | ret.parent = ret; // make it look like a simple root node |
||
3646 | return ret; |
||
3647 | } |
||
3648 | }; |
||
3649 | return node; |
||
3650 | } |
||
3651 | }, {}, '/proc/self/fd'); |
||
3652 | },createStandardStreams:function() { |
||
3653 | // TODO deprecate the old functionality of a single |
||
3654 | // input / output callback and that utilizes FS.createDevice |
||
3655 | // and instead require a unique set of stream ops |
||
3656 | |||
3657 | // by default, we symlink the standard streams to the |
||
3658 | // default tty devices. however, if the standard streams |
||
3659 | // have been overwritten we create a unique device for |
||
3660 | // them instead. |
||
3661 | if (Module['stdin']) { |
||
3662 | FS.createDevice('/dev', 'stdin', Module['stdin']); |
||
3663 | } else { |
||
3664 | FS.symlink('/dev/tty', '/dev/stdin'); |
||
3665 | } |
||
3666 | if (Module['stdout']) { |
||
3667 | FS.createDevice('/dev', 'stdout', null, Module['stdout']); |
||
3668 | } else { |
||
3669 | FS.symlink('/dev/tty', '/dev/stdout'); |
||
3670 | } |
||
3671 | if (Module['stderr']) { |
||
3672 | FS.createDevice('/dev', 'stderr', null, Module['stderr']); |
||
3673 | } else { |
||
3674 | FS.symlink('/dev/tty1', '/dev/stderr'); |
||
3675 | } |
||
3676 | |||
3677 | // open default streams for the stdin, stdout and stderr devices |
||
3678 | var stdin = FS.open('/dev/stdin', 'r'); |
||
3679 | var stdout = FS.open('/dev/stdout', 'w'); |
||
3680 | var stderr = FS.open('/dev/stderr', 'w'); |
||
3681 | assert(stdin.fd === 0, 'invalid handle for stdin (' + stdin.fd + ')'); |
||
3682 | assert(stdout.fd === 1, 'invalid handle for stdout (' + stdout.fd + ')'); |
||
3683 | assert(stderr.fd === 2, 'invalid handle for stderr (' + stderr.fd + ')'); |
||
3684 | },ensureErrnoError:function() { |
||
3685 | if (FS.ErrnoError) return; |
||
3686 | FS.ErrnoError = /** @this{Object} */ function ErrnoError(errno, node) { |
||
3687 | this.node = node; |
||
3688 | this.setErrno = /** @this{Object} */ function(errno) { |
||
3689 | this.errno = errno; |
||
3690 | for (var key in ERRNO_CODES) { |
||
3691 | if (ERRNO_CODES[key] === errno) { |
||
3692 | this.code = key; |
||
3693 | break; |
||
3694 | } |
||
3695 | } |
||
3696 | }; |
||
3697 | this.setErrno(errno); |
||
3698 | this.message = ERRNO_MESSAGES[errno]; |
||
3699 | |||
3700 | // Try to get a maximally helpful stack trace. On Node.js, getting Error.stack |
||
3701 | // now ensures it shows what we want. |
||
3702 | if (this.stack) { |
||
3703 | // Define the stack property for Node.js 4, which otherwise errors on the next line. |
||
3704 | Object.defineProperty(this, "stack", { value: (new Error).stack, writable: true }); |
||
3705 | this.stack = demangleAll(this.stack); |
||
3706 | } |
||
3707 | }; |
||
3708 | FS.ErrnoError.prototype = new Error(); |
||
3709 | FS.ErrnoError.prototype.constructor = FS.ErrnoError; |
||
3710 | // Some errors may happen quite a bit, to avoid overhead we reuse them (and suffer a lack of stack info) |
||
3711 | [44].forEach(function(code) { |
||
3712 | FS.genericErrors[code] = new FS.ErrnoError(code); |
||
3713 | FS.genericErrors[code].stack = '<generic error, no stack>'; |
||
3714 | }); |
||
3715 | },staticInit:function() { |
||
3716 | FS.ensureErrnoError(); |
||
3717 | |||
3718 | FS.nameTable = new Array(4096); |
||
3719 | |||
3720 | FS.mount(MEMFS, {}, '/'); |
||
3721 | |||
3722 | FS.createDefaultDirectories(); |
||
3723 | FS.createDefaultDevices(); |
||
3724 | FS.createSpecialDirectories(); |
||
3725 | |||
3726 | FS.filesystems = { |
||
3727 | 'MEMFS': MEMFS, |
||
3728 | }; |
||
3729 | },init:function(input, output, error) { |
||
3730 | assert(!FS.init.initialized, 'FS.init was previously called. If you want to initialize later with custom parameters, remove any earlier calls (note that one is automatically added to the generated code)'); |
||
3731 | FS.init.initialized = true; |
||
3732 | |||
3733 | FS.ensureErrnoError(); |
||
3734 | |||
3735 | // Allow Module.stdin etc. to provide defaults, if none explicitly passed to us here |
||
3736 | Module['stdin'] = input || Module['stdin']; |
||
3737 | Module['stdout'] = output || Module['stdout']; |
||
3738 | Module['stderr'] = error || Module['stderr']; |
||
3739 | |||
3740 | FS.createStandardStreams(); |
||
3741 | },quit:function() { |
||
3742 | FS.init.initialized = false; |
||
3743 | // force-flush all streams, so we get musl std streams printed out |
||
3744 | var fflush = Module['_fflush']; |
||
3745 | if (fflush) fflush(0); |
||
3746 | // close all of our streams |
||
3747 | for (var i = 0; i < FS.streams.length; i++) { |
||
3748 | var stream = FS.streams[i]; |
||
3749 | if (!stream) { |
||
3750 | continue; |
||
3751 | } |
||
3752 | FS.close(stream); |
||
3753 | } |
||
3754 | },getMode:function(canRead, canWrite) { |
||
3755 | var mode = 0; |
||
3756 | if (canRead) mode |= 292 | 73; |
||
3757 | if (canWrite) mode |= 146; |
||
3758 | return mode; |
||
3759 | },joinPath:function(parts, forceRelative) { |
||
3760 | var path = PATH.join.apply(null, parts); |
||
3761 | if (forceRelative && path[0] == '/') path = path.substr(1); |
||
3762 | return path; |
||
3763 | },absolutePath:function(relative, base) { |
||
3764 | return PATH_FS.resolve(base, relative); |
||
3765 | },standardizePath:function(path) { |
||
3766 | return PATH.normalize(path); |
||
3767 | },findObject:function(path, dontResolveLastLink) { |
||
3768 | var ret = FS.analyzePath(path, dontResolveLastLink); |
||
3769 | if (ret.exists) { |
||
3770 | return ret.object; |
||
3771 | } else { |
||
3772 | setErrNo(ret.error); |
||
3773 | return null; |
||
3774 | } |
||
3775 | },analyzePath:function(path, dontResolveLastLink) { |
||
3776 | // operate from within the context of the symlink's target |
||
3777 | try { |
||
3778 | var lookup = FS.lookupPath(path, { follow: !dontResolveLastLink }); |
||
3779 | path = lookup.path; |
||
3780 | } catch (e) { |
||
3781 | } |
||
3782 | var ret = { |
||
3783 | isRoot: false, exists: false, error: 0, name: null, path: null, object: null, |
||
3784 | parentExists: false, parentPath: null, parentObject: null |
||
3785 | }; |
||
3786 | try { |
||
3787 | var lookup = FS.lookupPath(path, { parent: true }); |
||
3788 | ret.parentExists = true; |
||
3789 | ret.parentPath = lookup.path; |
||
3790 | ret.parentObject = lookup.node; |
||
3791 | ret.name = PATH.basename(path); |
||
3792 | lookup = FS.lookupPath(path, { follow: !dontResolveLastLink }); |
||
3793 | ret.exists = true; |
||
3794 | ret.path = lookup.path; |
||
3795 | ret.object = lookup.node; |
||
3796 | ret.name = lookup.node.name; |
||
3797 | ret.isRoot = lookup.path === '/'; |
||
3798 | } catch (e) { |
||
3799 | ret.error = e.errno; |
||
3800 | }; |
||
3801 | return ret; |
||
3802 | },createFolder:function(parent, name, canRead, canWrite) { |
||
3803 | var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name); |
||
3804 | var mode = FS.getMode(canRead, canWrite); |
||
3805 | return FS.mkdir(path, mode); |
||
3806 | },createPath:function(parent, path, canRead, canWrite) { |
||
3807 | parent = typeof parent === 'string' ? parent : FS.getPath(parent); |
||
3808 | var parts = path.split('/').reverse(); |
||
3809 | while (parts.length) { |
||
3810 | var part = parts.pop(); |
||
3811 | if (!part) continue; |
||
3812 | var current = PATH.join2(parent, part); |
||
3813 | try { |
||
3814 | FS.mkdir(current); |
||
3815 | } catch (e) { |
||
3816 | // ignore EEXIST |
||
3817 | } |
||
3818 | parent = current; |
||
3819 | } |
||
3820 | return current; |
||
3821 | },createFile:function(parent, name, properties, canRead, canWrite) { |
||
3822 | var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name); |
||
3823 | var mode = FS.getMode(canRead, canWrite); |
||
3824 | return FS.create(path, mode); |
||
3825 | },createDataFile:function(parent, name, data, canRead, canWrite, canOwn) { |
||
3826 | var path = name ? PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name) : parent; |
||
3827 | var mode = FS.getMode(canRead, canWrite); |
||
3828 | var node = FS.create(path, mode); |
||
3829 | if (data) { |
||
3830 | if (typeof data === 'string') { |
||
3831 | var arr = new Array(data.length); |
||
3832 | for (var i = 0, len = data.length; i < len; ++i) arr[i] = data.charCodeAt(i); |
||
3833 | data = arr; |
||
3834 | } |
||
3835 | // make sure we can write to the file |
||
3836 | FS.chmod(node, mode | 146); |
||
3837 | var stream = FS.open(node, 'w'); |
||
3838 | FS.write(stream, data, 0, data.length, 0, canOwn); |
||
3839 | FS.close(stream); |
||
3840 | FS.chmod(node, mode); |
||
3841 | } |
||
3842 | return node; |
||
3843 | },createDevice:function(parent, name, input, output) { |
||
3844 | var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name); |
||
3845 | var mode = FS.getMode(!!input, !!output); |
||
3846 | if (!FS.createDevice.major) FS.createDevice.major = 64; |
||
3847 | var dev = FS.makedev(FS.createDevice.major++, 0); |
||
3848 | // Create a fake device that a set of stream ops to emulate |
||
3849 | // the old behavior. |
||
3850 | FS.registerDevice(dev, { |
||
3851 | open: function(stream) { |
||
3852 | stream.seekable = false; |
||
3853 | }, |
||
3854 | close: function(stream) { |
||
3855 | // flush any pending line data |
||
3856 | if (output && output.buffer && output.buffer.length) { |
||
3857 | output(10); |
||
3858 | } |
||
3859 | }, |
||
3860 | read: function(stream, buffer, offset, length, pos /* ignored */) { |
||
3861 | var bytesRead = 0; |
||
3862 | for (var i = 0; i < length; i++) { |
||
3863 | var result; |
||
3864 | try { |
||
3865 | result = input(); |
||
3866 | } catch (e) { |
||
3867 | throw new FS.ErrnoError(29); |
||
3868 | } |
||
3869 | if (result === undefined && bytesRead === 0) { |
||
3870 | throw new FS.ErrnoError(6); |
||
3871 | } |
||
3872 | if (result === null || result === undefined) break; |
||
3873 | bytesRead++; |
||
3874 | buffer[offset+i] = result; |
||
3875 | } |
||
3876 | if (bytesRead) { |
||
3877 | stream.node.timestamp = Date.now(); |
||
3878 | } |
||
3879 | return bytesRead; |
||
3880 | }, |
||
3881 | write: function(stream, buffer, offset, length, pos) { |
||
3882 | for (var i = 0; i < length; i++) { |
||
3883 | try { |
||
3884 | output(buffer[offset+i]); |
||
3885 | } catch (e) { |
||
3886 | throw new FS.ErrnoError(29); |
||
3887 | } |
||
3888 | } |
||
3889 | if (length) { |
||
3890 | stream.node.timestamp = Date.now(); |
||
3891 | } |
||
3892 | return i; |
||
3893 | } |
||
3894 | }); |
||
3895 | return FS.mkdev(path, mode, dev); |
||
3896 | },createLink:function(parent, name, target, canRead, canWrite) { |
||
3897 | var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name); |
||
3898 | return FS.symlink(target, path); |
||
3899 | },forceLoadFile:function(obj) { |
||
3900 | if (obj.isDevice || obj.isFolder || obj.link || obj.contents) return true; |
||
3901 | var success = true; |
||
3902 | if (typeof XMLHttpRequest !== 'undefined') { |
||
3903 | 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."); |
||
3904 | } else if (read_) { |
||
3905 | // Command-line. |
||
3906 | try { |
||
3907 | // WARNING: Can't read binary files in V8's d8 or tracemonkey's js, as |
||
3908 | // read() will try to parse UTF8. |
||
3909 | obj.contents = intArrayFromString(read_(obj.url), true); |
||
3910 | obj.usedBytes = obj.contents.length; |
||
3911 | } catch (e) { |
||
3912 | success = false; |
||
3913 | } |
||
3914 | } else { |
||
3915 | throw new Error('Cannot load without read() or XMLHttpRequest.'); |
||
3916 | } |
||
3917 | if (!success) setErrNo(29); |
||
3918 | return success; |
||
3919 | },createLazyFile:function(parent, name, url, canRead, canWrite) { |
||
3920 | // Lazy chunked Uint8Array (implements get and length from Uint8Array). Actual getting is abstracted away for eventual reuse. |
||
3921 | /** @constructor */ |
||
3922 | function LazyUint8Array() { |
||
3923 | this.lengthKnown = false; |
||
3924 | this.chunks = []; // Loaded chunks. Index is the chunk number |
||
3925 | } |
||
3926 | LazyUint8Array.prototype.get = /** @this{Object} */ function LazyUint8Array_get(idx) { |
||
3927 | if (idx > this.length-1 || idx < 0) { |
||
3928 | return undefined; |
||
3929 | } |
||
3930 | var chunkOffset = idx % this.chunkSize; |
||
3931 | var chunkNum = (idx / this.chunkSize)|0; |
||
3932 | return this.getter(chunkNum)[chunkOffset]; |
||
3933 | }; |
||
3934 | LazyUint8Array.prototype.setDataGetter = function LazyUint8Array_setDataGetter(getter) { |
||
3935 | this.getter = getter; |
||
3936 | }; |
||
3937 | LazyUint8Array.prototype.cacheLength = function LazyUint8Array_cacheLength() { |
||
3938 | // Find length |
||
3939 | var xhr = new XMLHttpRequest(); |
||
3940 | xhr.open('HEAD', url, false); |
||
3941 | xhr.send(null); |
||
3942 | if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status); |
||
3943 | var datalength = Number(xhr.getResponseHeader("Content-length")); |
||
3944 | var header; |
||
3945 | var hasByteServing = (header = xhr.getResponseHeader("Accept-Ranges")) && header === "bytes"; |
||
3946 | var usesGzip = (header = xhr.getResponseHeader("Content-Encoding")) && header === "gzip"; |
||
3947 | |||
3948 | var chunkSize = 1024*1024; // Chunk size in bytes |
||
3949 | |||
3950 | if (!hasByteServing) chunkSize = datalength; |
||
3951 | |||
3952 | // Function to get a range from the remote URL. |
||
3953 | var doXHR = (function(from, to) { |
||
3954 | if (from > to) throw new Error("invalid range (" + from + ", " + to + ") or no bytes requested!"); |
||
3955 | if (to > datalength-1) throw new Error("only " + datalength + " bytes available! programmer error!"); |
||
3956 | |||
3957 | // TODO: Use mozResponseArrayBuffer, responseStream, etc. if available. |
||
3958 | var xhr = new XMLHttpRequest(); |
||
3959 | xhr.open('GET', url, false); |
||
3960 | if (datalength !== chunkSize) xhr.setRequestHeader("Range", "bytes=" + from + "-" + to); |
||
3961 | |||
3962 | // Some hints to the browser that we want binary data. |
||
3963 | if (typeof Uint8Array != 'undefined') xhr.responseType = 'arraybuffer'; |
||
3964 | if (xhr.overrideMimeType) { |
||
3965 | xhr.overrideMimeType('text/plain; charset=x-user-defined'); |
||
3966 | } |
||
3967 | |||
3968 | xhr.send(null); |
||
3969 | if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status); |
||
3970 | if (xhr.response !== undefined) { |
||
3971 | return new Uint8Array(/** @type{Array<number>} */(xhr.response || [])); |
||
3972 | } else { |
||
3973 | return intArrayFromString(xhr.responseText || '', true); |
||
3974 | } |
||
3975 | }); |
||
3976 | var lazyArray = this; |
||
3977 | lazyArray.setDataGetter(function(chunkNum) { |
||
3978 | var start = chunkNum * chunkSize; |
||
3979 | var end = (chunkNum+1) * chunkSize - 1; // including this byte |
||
3980 | end = Math.min(end, datalength-1); // if datalength-1 is selected, this is the last block |
||
3981 | if (typeof(lazyArray.chunks[chunkNum]) === "undefined") { |
||
3982 | lazyArray.chunks[chunkNum] = doXHR(start, end); |
||
3983 | } |
||
3984 | if (typeof(lazyArray.chunks[chunkNum]) === "undefined") throw new Error("doXHR failed!"); |
||
3985 | return lazyArray.chunks[chunkNum]; |
||
3986 | }); |
||
3987 | |||
3988 | if (usesGzip || !datalength) { |
||
3989 | // if the server uses gzip or doesn't supply the length, we have to download the whole file to get the (uncompressed) length |
||
3990 | chunkSize = datalength = 1; // this will force getter(0)/doXHR do download the whole file |
||
3991 | datalength = this.getter(0).length; |
||
3992 | chunkSize = datalength; |
||
3993 | out("LazyFiles on gzip forces download of the whole file when length is accessed"); |
||
3994 | } |
||
3995 | |||
3996 | this._length = datalength; |
||
3997 | this._chunkSize = chunkSize; |
||
3998 | this.lengthKnown = true; |
||
3999 | }; |
||
4000 | if (typeof XMLHttpRequest !== 'undefined') { |
||
4001 | if (!ENVIRONMENT_IS_WORKER) throw 'Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc'; |
||
4002 | var lazyArray = new LazyUint8Array(); |
||
4003 | Object.defineProperties(lazyArray, { |
||
4004 | length: { |
||
4005 | get: /** @this{Object} */ function() { |
||
4006 | if(!this.lengthKnown) { |
||
4007 | this.cacheLength(); |
||
4008 | } |
||
4009 | return this._length; |
||
4010 | } |
||
4011 | }, |
||
4012 | chunkSize: { |
||
4013 | get: /** @this{Object} */ function() { |
||
4014 | if(!this.lengthKnown) { |
||
4015 | this.cacheLength(); |
||
4016 | } |
||
4017 | return this._chunkSize; |
||
4018 | } |
||
4019 | } |
||
4020 | }); |
||
4021 | |||
4022 | var properties = { isDevice: false, contents: lazyArray }; |
||
4023 | } else { |
||
4024 | var properties = { isDevice: false, url: url }; |
||
4025 | } |
||
4026 | |||
4027 | var node = FS.createFile(parent, name, properties, canRead, canWrite); |
||
4028 | // This is a total hack, but I want to get this lazy file code out of the |
||
4029 | // core of MEMFS. If we want to keep this lazy file concept I feel it should |
||
4030 | // be its own thin LAZYFS proxying calls to MEMFS. |
||
4031 | if (properties.contents) { |
||
4032 | node.contents = properties.contents; |
||
4033 | } else if (properties.url) { |
||
4034 | node.contents = null; |
||
4035 | node.url = properties.url; |
||
4036 | } |
||
4037 | // Add a function that defers querying the file size until it is asked the first time. |
||
4038 | Object.defineProperties(node, { |
||
4039 | usedBytes: { |
||
4040 | get: /** @this {FSNode} */ function() { return this.contents.length; } |
||
4041 | } |
||
4042 | }); |
||
4043 | // override each stream op with one that tries to force load the lazy file first |
||
4044 | var stream_ops = {}; |
||
4045 | var keys = Object.keys(node.stream_ops); |
||
4046 | keys.forEach(function(key) { |
||
4047 | var fn = node.stream_ops[key]; |
||
4048 | stream_ops[key] = function forceLoadLazyFile() { |
||
4049 | if (!FS.forceLoadFile(node)) { |
||
4050 | throw new FS.ErrnoError(29); |
||
4051 | } |
||
4052 | return fn.apply(null, arguments); |
||
4053 | }; |
||
4054 | }); |
||
4055 | // use a custom read function |
||
4056 | stream_ops.read = function stream_ops_read(stream, buffer, offset, length, position) { |
||
4057 | if (!FS.forceLoadFile(node)) { |
||
4058 | throw new FS.ErrnoError(29); |
||
4059 | } |
||
4060 | var contents = stream.node.contents; |
||
4061 | if (position >= contents.length) |
||
4062 | return 0; |
||
4063 | var size = Math.min(contents.length - position, length); |
||
4064 | assert(size >= 0); |
||
4065 | if (contents.slice) { // normal array |
||
4066 | for (var i = 0; i < size; i++) { |
||
4067 | buffer[offset + i] = contents[position + i]; |
||
4068 | } |
||
4069 | } else { |
||
4070 | for (var i = 0; i < size; i++) { // LazyUint8Array from sync binary XHR |
||
4071 | buffer[offset + i] = contents.get(position + i); |
||
4072 | } |
||
4073 | } |
||
4074 | return size; |
||
4075 | }; |
||
4076 | node.stream_ops = stream_ops; |
||
4077 | return node; |
||
4078 | },createPreloadedFile:function(parent, name, url, canRead, canWrite, onload, onerror, dontCreateFile, canOwn, preFinish) { |
||
4079 | Browser.init(); // XXX perhaps this method should move onto Browser? |
||
4080 | // TODO we should allow people to just pass in a complete filename instead |
||
4081 | // of parent and name being that we just join them anyways |
||
4082 | var fullname = name ? PATH_FS.resolve(PATH.join2(parent, name)) : parent; |
||
4083 | var dep = getUniqueRunDependency('cp ' + fullname); // might have several active requests for the same fullname |
||
4084 | function processData(byteArray) { |
||
4085 | function finish(byteArray) { |
||
4086 | if (preFinish) preFinish(); |
||
4087 | if (!dontCreateFile) { |
||
4088 | FS.createDataFile(parent, name, byteArray, canRead, canWrite, canOwn); |
||
4089 | } |
||
4090 | if (onload) onload(); |
||
4091 | removeRunDependency(dep); |
||
4092 | } |
||
4093 | var handled = false; |
||
4094 | Module['preloadPlugins'].forEach(function(plugin) { |
||
4095 | if (handled) return; |
||
4096 | if (plugin['canHandle'](fullname)) { |
||
4097 | plugin['handle'](byteArray, fullname, finish, function() { |
||
4098 | if (onerror) onerror(); |
||
4099 | removeRunDependency(dep); |
||
4100 | }); |
||
4101 | handled = true; |
||
4102 | } |
||
4103 | }); |
||
4104 | if (!handled) finish(byteArray); |
||
4105 | } |
||
4106 | addRunDependency(dep); |
||
4107 | if (typeof url == 'string') { |
||
4108 | Browser.asyncLoad(url, function(byteArray) { |
||
4109 | processData(byteArray); |
||
4110 | }, onerror); |
||
4111 | } else { |
||
4112 | processData(url); |
||
4113 | } |
||
4114 | },indexedDB:function() { |
||
4115 | return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB; |
||
4116 | },DB_NAME:function() { |
||
4117 | return 'EM_FS_' + window.location.pathname; |
||
4118 | },DB_VERSION:20,DB_STORE_NAME:"FILE_DATA",saveFilesToDB:function(paths, onload, onerror) { |
||
4119 | onload = onload || function(){}; |
||
4120 | onerror = onerror || function(){}; |
||
4121 | var indexedDB = FS.indexedDB(); |
||
4122 | try { |
||
4123 | var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION); |
||
4124 | } catch (e) { |
||
4125 | return onerror(e); |
||
4126 | } |
||
4127 | openRequest.onupgradeneeded = function openRequest_onupgradeneeded() { |
||
4128 | out('creating db'); |
||
4129 | var db = openRequest.result; |
||
4130 | db.createObjectStore(FS.DB_STORE_NAME); |
||
4131 | }; |
||
4132 | openRequest.onsuccess = function openRequest_onsuccess() { |
||
4133 | var db = openRequest.result; |
||
4134 | var transaction = db.transaction([FS.DB_STORE_NAME], 'readwrite'); |
||
4135 | var files = transaction.objectStore(FS.DB_STORE_NAME); |
||
4136 | var ok = 0, fail = 0, total = paths.length; |
||
4137 | function finish() { |
||
4138 | if (fail == 0) onload(); else onerror(); |
||
4139 | } |
||
4140 | paths.forEach(function(path) { |
||
4141 | var putRequest = files.put(FS.analyzePath(path).object.contents, path); |
||
4142 | putRequest.onsuccess = function putRequest_onsuccess() { ok++; if (ok + fail == total) finish() }; |
||
4143 | putRequest.onerror = function putRequest_onerror() { fail++; if (ok + fail == total) finish() }; |
||
4144 | }); |
||
4145 | transaction.onerror = onerror; |
||
4146 | }; |
||
4147 | openRequest.onerror = onerror; |
||
4148 | },loadFilesFromDB:function(paths, onload, onerror) { |
||
4149 | onload = onload || function(){}; |
||
4150 | onerror = onerror || function(){}; |
||
4151 | var indexedDB = FS.indexedDB(); |
||
4152 | try { |
||
4153 | var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION); |
||
4154 | } catch (e) { |
||
4155 | return onerror(e); |
||
4156 | } |
||
4157 | openRequest.onupgradeneeded = onerror; // no database to load from |
||
4158 | openRequest.onsuccess = function openRequest_onsuccess() { |
||
4159 | var db = openRequest.result; |
||
4160 | try { |
||
4161 | var transaction = db.transaction([FS.DB_STORE_NAME], 'readonly'); |
||
4162 | } catch(e) { |
||
4163 | onerror(e); |
||
4164 | return; |
||
4165 | } |
||
4166 | var files = transaction.objectStore(FS.DB_STORE_NAME); |
||
4167 | var ok = 0, fail = 0, total = paths.length; |
||
4168 | function finish() { |
||
4169 | if (fail == 0) onload(); else onerror(); |
||
4170 | } |
||
4171 | paths.forEach(function(path) { |
||
4172 | var getRequest = files.get(path); |
||
4173 | getRequest.onsuccess = function getRequest_onsuccess() { |
||
4174 | if (FS.analyzePath(path).exists) { |
||
4175 | FS.unlink(path); |
||
4176 | } |
||
4177 | FS.createDataFile(PATH.dirname(path), PATH.basename(path), getRequest.result, true, true, true); |
||
4178 | ok++; |
||
4179 | if (ok + fail == total) finish(); |
||
4180 | }; |
||
4181 | getRequest.onerror = function getRequest_onerror() { fail++; if (ok + fail == total) finish() }; |
||
4182 | }); |
||
4183 | transaction.onerror = onerror; |
||
4184 | }; |
||
4185 | openRequest.onerror = onerror; |
||
4186 | }};var SYSCALLS={mappings:{},DEFAULT_POLLMASK:5,umask:511,calculateAt:function(dirfd, path) { |
||
4187 | if (path[0] !== '/') { |
||
4188 | // relative path |
||
4189 | var dir; |
||
4190 | if (dirfd === -100) { |
||
4191 | dir = FS.cwd(); |
||
4192 | } else { |
||
4193 | var dirstream = FS.getStream(dirfd); |
||
4194 | if (!dirstream) throw new FS.ErrnoError(8); |
||
4195 | dir = dirstream.path; |
||
4196 | } |
||
4197 | path = PATH.join2(dir, path); |
||
4198 | } |
||
4199 | return path; |
||
4200 | },doStat:function(func, path, buf) { |
||
4201 | try { |
||
4202 | var stat = func(path); |
||
4203 | } catch (e) { |
||
4204 | if (e && e.node && PATH.normalize(path) !== PATH.normalize(FS.getPath(e.node))) { |
||
4205 | // an error occurred while trying to look up the path; we should just report ENOTDIR |
||
4206 | return -54; |
||
4207 | } |
||
4208 | throw e; |
||
4209 | } |
||
4210 | HEAP32[((buf)>>2)]=stat.dev; |
||
4211 | HEAP32[(((buf)+(4))>>2)]=0; |
||
4212 | HEAP32[(((buf)+(8))>>2)]=stat.ino; |
||
4213 | HEAP32[(((buf)+(12))>>2)]=stat.mode; |
||
4214 | HEAP32[(((buf)+(16))>>2)]=stat.nlink; |
||
4215 | HEAP32[(((buf)+(20))>>2)]=stat.uid; |
||
4216 | HEAP32[(((buf)+(24))>>2)]=stat.gid; |
||
4217 | HEAP32[(((buf)+(28))>>2)]=stat.rdev; |
||
4218 | HEAP32[(((buf)+(32))>>2)]=0; |
||
4219 | (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]); |
||
4220 | HEAP32[(((buf)+(48))>>2)]=4096; |
||
4221 | HEAP32[(((buf)+(52))>>2)]=stat.blocks; |
||
4222 | HEAP32[(((buf)+(56))>>2)]=(stat.atime.getTime() / 1000)|0; |
||
4223 | HEAP32[(((buf)+(60))>>2)]=0; |
||
4224 | HEAP32[(((buf)+(64))>>2)]=(stat.mtime.getTime() / 1000)|0; |
||
4225 | HEAP32[(((buf)+(68))>>2)]=0; |
||
4226 | HEAP32[(((buf)+(72))>>2)]=(stat.ctime.getTime() / 1000)|0; |
||
4227 | HEAP32[(((buf)+(76))>>2)]=0; |
||
4228 | (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]); |
||
4229 | return 0; |
||
4230 | },doMsync:function(addr, stream, len, flags, offset) { |
||
4231 | var buffer = HEAPU8.slice(addr, addr + len); |
||
4232 | FS.msync(stream, buffer, offset, len, flags); |
||
4233 | },doMkdir:function(path, mode) { |
||
4234 | // remove a trailing slash, if one - /a/b/ has basename of '', but |
||
4235 | // we want to create b in the context of this function |
||
4236 | path = PATH.normalize(path); |
||
4237 | if (path[path.length-1] === '/') path = path.substr(0, path.length-1); |
||
4238 | FS.mkdir(path, mode, 0); |
||
4239 | return 0; |
||
4240 | },doMknod:function(path, mode, dev) { |
||
4241 | // we don't want this in the JS API as it uses mknod to create all nodes. |
||
4242 | switch (mode & 61440) { |
||
4243 | case 32768: |
||
4244 | case 8192: |
||
4245 | case 24576: |
||
4246 | case 4096: |
||
4247 | case 49152: |
||
4248 | break; |
||
4249 | default: return -28; |
||
4250 | } |
||
4251 | FS.mknod(path, mode, dev); |
||
4252 | return 0; |
||
4253 | },doReadlink:function(path, buf, bufsize) { |
||
4254 | if (bufsize <= 0) return -28; |
||
4255 | var ret = FS.readlink(path); |
||
4256 | |||
4257 | var len = Math.min(bufsize, lengthBytesUTF8(ret)); |
||
4258 | var endChar = HEAP8[buf+len]; |
||
4259 | stringToUTF8(ret, buf, bufsize+1); |
||
4260 | // readlink is one of the rare functions that write out a C string, but does never append a null to the output buffer(!) |
||
4261 | // stringToUTF8() always appends a null byte, so restore the character under the null byte after the write. |
||
4262 | HEAP8[buf+len] = endChar; |
||
4263 | |||
4264 | return len; |
||
4265 | },doAccess:function(path, amode) { |
||
4266 | if (amode & ~7) { |
||
4267 | // need a valid mode |
||
4268 | return -28; |
||
4269 | } |
||
4270 | var node; |
||
4271 | var lookup = FS.lookupPath(path, { follow: true }); |
||
4272 | node = lookup.node; |
||
4273 | if (!node) { |
||
4274 | return -44; |
||
4275 | } |
||
4276 | var perms = ''; |
||
4277 | if (amode & 4) perms += 'r'; |
||
4278 | if (amode & 2) perms += 'w'; |
||
4279 | if (amode & 1) perms += 'x'; |
||
4280 | if (perms /* otherwise, they've just passed F_OK */ && FS.nodePermissions(node, perms)) { |
||
4281 | return -2; |
||
4282 | } |
||
4283 | return 0; |
||
4284 | },doDup:function(path, flags, suggestFD) { |
||
4285 | var suggest = FS.getStream(suggestFD); |
||
4286 | if (suggest) FS.close(suggest); |
||
4287 | return FS.open(path, flags, 0, suggestFD, suggestFD).fd; |
||
4288 | },doReadv:function(stream, iov, iovcnt, offset) { |
||
4289 | var ret = 0; |
||
4290 | for (var i = 0; i < iovcnt; i++) { |
||
4291 | var ptr = HEAP32[(((iov)+(i*8))>>2)]; |
||
4292 | var len = HEAP32[(((iov)+(i*8 + 4))>>2)]; |
||
4293 | var curr = FS.read(stream, HEAP8,ptr, len, offset); |
||
4294 | if (curr < 0) return -1; |
||
4295 | ret += curr; |
||
4296 | if (curr < len) break; // nothing more to read |
||
4297 | } |
||
4298 | return ret; |
||
4299 | },doWritev:function(stream, iov, iovcnt, offset) { |
||
4300 | var ret = 0; |
||
4301 | for (var i = 0; i < iovcnt; i++) { |
||
4302 | var ptr = HEAP32[(((iov)+(i*8))>>2)]; |
||
4303 | var len = HEAP32[(((iov)+(i*8 + 4))>>2)]; |
||
4304 | var curr = FS.write(stream, HEAP8,ptr, len, offset); |
||
4305 | if (curr < 0) return -1; |
||
4306 | ret += curr; |
||
4307 | } |
||
4308 | return ret; |
||
4309 | },varargs:undefined,get:function() { |
||
4310 | assert(SYSCALLS.varargs != undefined); |
||
4311 | SYSCALLS.varargs += 4; |
||
4312 | var ret = HEAP32[(((SYSCALLS.varargs)-(4))>>2)]; |
||
4313 | return ret; |
||
4314 | },getStr:function(ptr) { |
||
4315 | var ret = UTF8ToString(ptr); |
||
4316 | return ret; |
||
4317 | },getStreamFromFD:function(fd) { |
||
4318 | var stream = FS.getStream(fd); |
||
4319 | if (!stream) throw new FS.ErrnoError(8); |
||
4320 | return stream; |
||
4321 | },get64:function(low, high) { |
||
4322 | if (low >= 0) assert(high === 0); |
||
4323 | else assert(high === -1); |
||
4324 | return low; |
||
4325 | }};function _fd_close(fd) {try { |
||
4326 | |||
4327 | var stream = SYSCALLS.getStreamFromFD(fd); |
||
4328 | FS.close(stream); |
||
4329 | return 0; |
||
4330 | } catch (e) { |
||
4331 | if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e); |
||
4332 | return e.errno; |
||
4333 | } |
||
4334 | } |
||
4335 | |||
4336 | function _fd_fdstat_get(fd, pbuf) {try { |
||
4337 | |||
4338 | var stream = SYSCALLS.getStreamFromFD(fd); |
||
4339 | // All character devices are terminals (other things a Linux system would |
||
4340 | // assume is a character device, like the mouse, we have special APIs for). |
||
4341 | var type = stream.tty ? 2 : |
||
4342 | FS.isDir(stream.mode) ? 3 : |
||
4343 | FS.isLink(stream.mode) ? 7 : |
||
4344 | 4; |
||
4345 | HEAP8[((pbuf)>>0)]=type; |
||
4346 | // TODO HEAP16[(((pbuf)+(2))>>1)]=?; |
||
4347 | // TODO (tempI64 = [?>>>0,(tempDouble=?,(+(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[(((pbuf)+(8))>>2)]=tempI64[0],HEAP32[(((pbuf)+(12))>>2)]=tempI64[1]); |
||
4348 | // TODO (tempI64 = [?>>>0,(tempDouble=?,(+(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[(((pbuf)+(16))>>2)]=tempI64[0],HEAP32[(((pbuf)+(20))>>2)]=tempI64[1]); |
||
4349 | return 0; |
||
4350 | } catch (e) { |
||
4351 | if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e); |
||
4352 | return e.errno; |
||
4353 | } |
||
4354 | } |
||
4355 | |||
4356 | function _fd_read(fd, iov, iovcnt, pnum) {try { |
||
4357 | |||
4358 | var stream = SYSCALLS.getStreamFromFD(fd); |
||
4359 | var num = SYSCALLS.doReadv(stream, iov, iovcnt); |
||
4360 | HEAP32[((pnum)>>2)]=num |
||
4361 | return 0; |
||
4362 | } catch (e) { |
||
4363 | if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e); |
||
4364 | return e.errno; |
||
4365 | } |
||
4366 | } |
||
4367 | |||
4368 | function _fd_seek(fd, offset_low, offset_high, whence, newOffset) {try { |
||
4369 | |||
4370 | |||
4371 | var stream = SYSCALLS.getStreamFromFD(fd); |
||
4372 | var HIGH_OFFSET = 0x100000000; // 2^32 |
||
4373 | // use an unsigned operator on low and shift high by 32-bits |
||
4374 | var offset = offset_high * HIGH_OFFSET + (offset_low >>> 0); |
||
4375 | |||
4376 | var DOUBLE_LIMIT = 0x20000000000000; // 2^53 |
||
4377 | // we also check for equality since DOUBLE_LIMIT + 1 == DOUBLE_LIMIT |
||
4378 | if (offset <= -DOUBLE_LIMIT || offset >= DOUBLE_LIMIT) { |
||
4379 | return -61; |
||
4380 | } |
||
4381 | |||
4382 | FS.llseek(stream, offset, whence); |
||
4383 | (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]); |
||
4384 | if (stream.getdents && offset === 0 && whence === 0) stream.getdents = null; // reset readdir state |
||
4385 | return 0; |
||
4386 | } catch (e) { |
||
4387 | if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e); |
||
4388 | return e.errno; |
||
4389 | } |
||
4390 | } |
||
4391 | |||
4392 | function _fd_write(fd, iov, iovcnt, pnum) {try { |
||
4393 | |||
4394 | var stream = SYSCALLS.getStreamFromFD(fd); |
||
4395 | var num = SYSCALLS.doWritev(stream, iov, iovcnt); |
||
4396 | HEAP32[((pnum)>>2)]=num |
||
4397 | return 0; |
||
4398 | } catch (e) { |
||
4399 | if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e); |
||
4400 | return e.errno; |
||
4401 | } |
||
4402 | } |
||
4403 | |||
4404 | function _setTempRet0($i) { |
||
4405 | setTempRet0(($i) | 0); |
||
4406 | } |
||
4407 | var FSNode = /** @constructor */ function(parent, name, mode, rdev) { |
||
4408 | if (!parent) { |
||
4409 | parent = this; // root node sets parent to itself |
||
4410 | } |
||
4411 | this.parent = parent; |
||
4412 | this.mount = parent.mount; |
||
4413 | this.mounted = null; |
||
4414 | this.id = FS.nextInode++; |
||
4415 | this.name = name; |
||
4416 | this.mode = mode; |
||
4417 | this.node_ops = {}; |
||
4418 | this.stream_ops = {}; |
||
4419 | this.rdev = rdev; |
||
4420 | }; |
||
4421 | var readMode = 292/*292*/ | 73/*73*/; |
||
4422 | var writeMode = 146/*146*/; |
||
4423 | Object.defineProperties(FSNode.prototype, { |
||
4424 | read: { |
||
4425 | get: /** @this{FSNode} */function() { |
||
4426 | return (this.mode & readMode) === readMode; |
||
4427 | }, |
||
4428 | set: /** @this{FSNode} */function(val) { |
||
4429 | val ? this.mode |= readMode : this.mode &= ~readMode; |
||
4430 | } |
||
4431 | }, |
||
4432 | write: { |
||
4433 | get: /** @this{FSNode} */function() { |
||
4434 | return (this.mode & writeMode) === writeMode; |
||
4435 | }, |
||
4436 | set: /** @this{FSNode} */function(val) { |
||
4437 | val ? this.mode |= writeMode : this.mode &= ~writeMode; |
||
4438 | } |
||
4439 | }, |
||
4440 | isFolder: { |
||
4441 | get: /** @this{FSNode} */function() { |
||
4442 | return FS.isDir(this.mode); |
||
4443 | } |
||
4444 | }, |
||
4445 | isDevice: { |
||
4446 | get: /** @this{FSNode} */function() { |
||
4447 | return FS.isChrdev(this.mode); |
||
4448 | } |
||
4449 | } |
||
4450 | }); |
||
4451 | FS.FSNode = FSNode; |
||
4452 | FS.staticInit();; |
||
4453 | var ASSERTIONS = true; |
||
4454 | |||
4455 | |||
4456 | |||
4457 | /** @type {function(string, boolean=, number=)} */ |
||
4458 | function intArrayFromString(stringy, dontAddNull, length) { |
||
4459 | var len = length > 0 ? length : lengthBytesUTF8(stringy)+1; |
||
4460 | var u8array = new Array(len); |
||
4461 | var numBytesWritten = stringToUTF8Array(stringy, u8array, 0, u8array.length); |
||
4462 | if (dontAddNull) u8array.length = numBytesWritten; |
||
4463 | return u8array; |
||
4464 | } |
||
4465 | |||
4466 | function intArrayToString(array) { |
||
4467 | var ret = []; |
||
4468 | for (var i = 0; i < array.length; i++) { |
||
4469 | var chr = array[i]; |
||
4470 | if (chr > 0xFF) { |
||
4471 | if (ASSERTIONS) { |
||
4472 | assert(false, 'Character code ' + chr + ' (' + String.fromCharCode(chr) + ') at offset ' + i + ' not in 0x00-0xFF.'); |
||
4473 | } |
||
4474 | chr &= 0xFF; |
||
4475 | } |
||
4476 | ret.push(String.fromCharCode(chr)); |
||
4477 | } |
||
4478 | return ret.join(''); |
||
4479 | } |
||
4480 | |||
4481 | |||
4482 | var asmGlobalArg = {}; |
||
4483 | var asmLibraryArg = { "__handle_stack_overflow": ___handle_stack_overflow, "emscripten_get_sbrk_ptr": _emscripten_get_sbrk_ptr, "emscripten_memcpy_big": _emscripten_memcpy_big, "emscripten_resize_heap": _emscripten_resize_heap, "exit": _exit, "fd_close": _fd_close, "fd_fdstat_get": _fd_fdstat_get, "fd_read": _fd_read, "fd_seek": _fd_seek, "fd_write": _fd_write, "memory": wasmMemory, "setTempRet0": _setTempRet0, "table": wasmTable }; |
||
4484 | var asm = createWasm(); |
||
4485 | /** @type {function(...*):?} */ |
||
4486 | var ___wasm_call_ctors = Module["___wasm_call_ctors"] = createExportWrapper("__wasm_call_ctors"); |
||
4487 | |||
4488 | /** @type {function(...*):?} */ |
||
4489 | var ___errno_location = Module["___errno_location"] = createExportWrapper("__errno_location"); |
||
4490 | |||
4491 | /** @type {function(...*):?} */ |
||
4492 | var _malloc = Module["_malloc"] = createExportWrapper("malloc"); |
||
4493 | |||
4494 | /** @type {function(...*):?} */ |
||
4495 | var _free = Module["_free"] = createExportWrapper("free"); |
||
4496 | |||
4497 | /** @type {function(...*):?} */ |
||
4498 | var _fflush = Module["_fflush"] = createExportWrapper("fflush"); |
||
4499 | |||
4500 | /** @type {function(...*):?} */ |
||
4501 | var _main = Module["_main"] = createExportWrapper("main"); |
||
4502 | |||
4503 | /** @type {function(...*):?} */ |
||
4504 | var stackSave = Module["stackSave"] = createExportWrapper("stackSave"); |
||
4505 | |||
4506 | /** @type {function(...*):?} */ |
||
4507 | var stackRestore = Module["stackRestore"] = createExportWrapper("stackRestore"); |
||
4508 | |||
4509 | /** @type {function(...*):?} */ |
||
4510 | var stackAlloc = Module["stackAlloc"] = createExportWrapper("stackAlloc"); |
||
4511 | |||
4512 | /** @type {function(...*):?} */ |
||
4513 | var ___set_stack_limit = Module["___set_stack_limit"] = createExportWrapper("__set_stack_limit"); |
||
4514 | |||
4515 | /** @type {function(...*):?} */ |
||
4516 | var __growWasmMemory = Module["__growWasmMemory"] = createExportWrapper("__growWasmMemory"); |
||
4517 | |||
4518 | /** @type {function(...*):?} */ |
||
4519 | var dynCall_iiii = Module["dynCall_iiii"] = createExportWrapper("dynCall_iiii"); |
||
4520 | |||
4521 | /** @type {function(...*):?} */ |
||
4522 | var dynCall_iidiiii = Module["dynCall_iidiiii"] = createExportWrapper("dynCall_iidiiii"); |
||
4523 | |||
4524 | /** @type {function(...*):?} */ |
||
4525 | var dynCall_vii = Module["dynCall_vii"] = createExportWrapper("dynCall_vii"); |
||
4526 | |||
4527 | /** @type {function(...*):?} */ |
||
4528 | var dynCall_ii = Module["dynCall_ii"] = createExportWrapper("dynCall_ii"); |
||
4529 | |||
4530 | /** @type {function(...*):?} */ |
||
4531 | var dynCall_jiji = Module["dynCall_jiji"] = createExportWrapper("dynCall_jiji"); |
||
4532 | |||
4533 | |||
4534 | |||
4535 | |||
4536 | |||
4537 | // === Auto-generated postamble setup entry stuff === |
||
4538 | |||
4539 | |||
4540 | if (!Object.getOwnPropertyDescriptor(Module, "intArrayFromString")) Module["intArrayFromString"] = function() { abort("'intArrayFromString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4541 | if (!Object.getOwnPropertyDescriptor(Module, "intArrayToString")) Module["intArrayToString"] = function() { abort("'intArrayToString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4542 | if (!Object.getOwnPropertyDescriptor(Module, "ccall")) Module["ccall"] = function() { abort("'ccall' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4543 | if (!Object.getOwnPropertyDescriptor(Module, "cwrap")) Module["cwrap"] = function() { abort("'cwrap' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4544 | if (!Object.getOwnPropertyDescriptor(Module, "setValue")) Module["setValue"] = function() { abort("'setValue' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4545 | if (!Object.getOwnPropertyDescriptor(Module, "getValue")) Module["getValue"] = function() { abort("'getValue' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4546 | if (!Object.getOwnPropertyDescriptor(Module, "allocate")) Module["allocate"] = function() { abort("'allocate' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4547 | if (!Object.getOwnPropertyDescriptor(Module, "getMemory")) Module["getMemory"] = function() { abort("'getMemory' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you") }; |
||
4548 | if (!Object.getOwnPropertyDescriptor(Module, "UTF8ArrayToString")) Module["UTF8ArrayToString"] = function() { abort("'UTF8ArrayToString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4549 | if (!Object.getOwnPropertyDescriptor(Module, "UTF8ToString")) Module["UTF8ToString"] = function() { abort("'UTF8ToString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4550 | if (!Object.getOwnPropertyDescriptor(Module, "stringToUTF8Array")) Module["stringToUTF8Array"] = function() { abort("'stringToUTF8Array' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4551 | if (!Object.getOwnPropertyDescriptor(Module, "stringToUTF8")) Module["stringToUTF8"] = function() { abort("'stringToUTF8' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4552 | if (!Object.getOwnPropertyDescriptor(Module, "lengthBytesUTF8")) Module["lengthBytesUTF8"] = function() { abort("'lengthBytesUTF8' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4553 | if (!Object.getOwnPropertyDescriptor(Module, "stackTrace")) Module["stackTrace"] = function() { abort("'stackTrace' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4554 | if (!Object.getOwnPropertyDescriptor(Module, "addOnPreRun")) Module["addOnPreRun"] = function() { abort("'addOnPreRun' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4555 | if (!Object.getOwnPropertyDescriptor(Module, "addOnInit")) Module["addOnInit"] = function() { abort("'addOnInit' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4556 | if (!Object.getOwnPropertyDescriptor(Module, "addOnPreMain")) Module["addOnPreMain"] = function() { abort("'addOnPreMain' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4557 | if (!Object.getOwnPropertyDescriptor(Module, "addOnExit")) Module["addOnExit"] = function() { abort("'addOnExit' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4558 | if (!Object.getOwnPropertyDescriptor(Module, "addOnPostRun")) Module["addOnPostRun"] = function() { abort("'addOnPostRun' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4559 | if (!Object.getOwnPropertyDescriptor(Module, "writeStringToMemory")) Module["writeStringToMemory"] = function() { abort("'writeStringToMemory' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4560 | if (!Object.getOwnPropertyDescriptor(Module, "writeArrayToMemory")) Module["writeArrayToMemory"] = function() { abort("'writeArrayToMemory' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4561 | if (!Object.getOwnPropertyDescriptor(Module, "writeAsciiToMemory")) Module["writeAsciiToMemory"] = function() { abort("'writeAsciiToMemory' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4562 | if (!Object.getOwnPropertyDescriptor(Module, "addRunDependency")) Module["addRunDependency"] = function() { abort("'addRunDependency' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you") }; |
||
4563 | if (!Object.getOwnPropertyDescriptor(Module, "removeRunDependency")) Module["removeRunDependency"] = function() { abort("'removeRunDependency' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you") }; |
||
4564 | if (!Object.getOwnPropertyDescriptor(Module, "FS_createFolder")) Module["FS_createFolder"] = function() { abort("'FS_createFolder' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you") }; |
||
4565 | if (!Object.getOwnPropertyDescriptor(Module, "FS_createPath")) Module["FS_createPath"] = function() { abort("'FS_createPath' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you") }; |
||
4566 | if (!Object.getOwnPropertyDescriptor(Module, "FS_createDataFile")) Module["FS_createDataFile"] = function() { abort("'FS_createDataFile' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you") }; |
||
4567 | if (!Object.getOwnPropertyDescriptor(Module, "FS_createPreloadedFile")) Module["FS_createPreloadedFile"] = function() { abort("'FS_createPreloadedFile' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you") }; |
||
4568 | if (!Object.getOwnPropertyDescriptor(Module, "FS_createLazyFile")) Module["FS_createLazyFile"] = function() { abort("'FS_createLazyFile' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you") }; |
||
4569 | if (!Object.getOwnPropertyDescriptor(Module, "FS_createLink")) Module["FS_createLink"] = function() { abort("'FS_createLink' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you") }; |
||
4570 | if (!Object.getOwnPropertyDescriptor(Module, "FS_createDevice")) Module["FS_createDevice"] = function() { abort("'FS_createDevice' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you") }; |
||
4571 | if (!Object.getOwnPropertyDescriptor(Module, "FS_unlink")) Module["FS_unlink"] = function() { abort("'FS_unlink' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you") }; |
||
4572 | if (!Object.getOwnPropertyDescriptor(Module, "dynamicAlloc")) Module["dynamicAlloc"] = function() { abort("'dynamicAlloc' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4573 | if (!Object.getOwnPropertyDescriptor(Module, "loadDynamicLibrary")) Module["loadDynamicLibrary"] = function() { abort("'loadDynamicLibrary' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4574 | if (!Object.getOwnPropertyDescriptor(Module, "loadWebAssemblyModule")) Module["loadWebAssemblyModule"] = function() { abort("'loadWebAssemblyModule' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4575 | if (!Object.getOwnPropertyDescriptor(Module, "getLEB")) Module["getLEB"] = function() { abort("'getLEB' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4576 | if (!Object.getOwnPropertyDescriptor(Module, "getFunctionTables")) Module["getFunctionTables"] = function() { abort("'getFunctionTables' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4577 | if (!Object.getOwnPropertyDescriptor(Module, "alignFunctionTables")) Module["alignFunctionTables"] = function() { abort("'alignFunctionTables' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4578 | if (!Object.getOwnPropertyDescriptor(Module, "registerFunctions")) Module["registerFunctions"] = function() { abort("'registerFunctions' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4579 | if (!Object.getOwnPropertyDescriptor(Module, "addFunction")) Module["addFunction"] = function() { abort("'addFunction' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4580 | if (!Object.getOwnPropertyDescriptor(Module, "removeFunction")) Module["removeFunction"] = function() { abort("'removeFunction' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4581 | if (!Object.getOwnPropertyDescriptor(Module, "getFuncWrapper")) Module["getFuncWrapper"] = function() { abort("'getFuncWrapper' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4582 | if (!Object.getOwnPropertyDescriptor(Module, "prettyPrint")) Module["prettyPrint"] = function() { abort("'prettyPrint' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4583 | if (!Object.getOwnPropertyDescriptor(Module, "makeBigInt")) Module["makeBigInt"] = function() { abort("'makeBigInt' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4584 | if (!Object.getOwnPropertyDescriptor(Module, "dynCall")) Module["dynCall"] = function() { abort("'dynCall' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4585 | if (!Object.getOwnPropertyDescriptor(Module, "getCompilerSetting")) Module["getCompilerSetting"] = function() { abort("'getCompilerSetting' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4586 | if (!Object.getOwnPropertyDescriptor(Module, "print")) Module["print"] = function() { abort("'print' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4587 | if (!Object.getOwnPropertyDescriptor(Module, "printErr")) Module["printErr"] = function() { abort("'printErr' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4588 | if (!Object.getOwnPropertyDescriptor(Module, "getTempRet0")) Module["getTempRet0"] = function() { abort("'getTempRet0' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4589 | if (!Object.getOwnPropertyDescriptor(Module, "setTempRet0")) Module["setTempRet0"] = function() { abort("'setTempRet0' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4590 | if (!Object.getOwnPropertyDescriptor(Module, "callMain")) Module["callMain"] = function() { abort("'callMain' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4591 | if (!Object.getOwnPropertyDescriptor(Module, "abort")) Module["abort"] = function() { abort("'abort' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4592 | if (!Object.getOwnPropertyDescriptor(Module, "stringToNewUTF8")) Module["stringToNewUTF8"] = function() { abort("'stringToNewUTF8' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4593 | if (!Object.getOwnPropertyDescriptor(Module, "abortOnCannotGrowMemory")) Module["abortOnCannotGrowMemory"] = function() { abort("'abortOnCannotGrowMemory' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4594 | if (!Object.getOwnPropertyDescriptor(Module, "emscripten_realloc_buffer")) Module["emscripten_realloc_buffer"] = function() { abort("'emscripten_realloc_buffer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4595 | if (!Object.getOwnPropertyDescriptor(Module, "ENV")) Module["ENV"] = function() { abort("'ENV' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4596 | if (!Object.getOwnPropertyDescriptor(Module, "ERRNO_CODES")) Module["ERRNO_CODES"] = function() { abort("'ERRNO_CODES' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4597 | if (!Object.getOwnPropertyDescriptor(Module, "ERRNO_MESSAGES")) Module["ERRNO_MESSAGES"] = function() { abort("'ERRNO_MESSAGES' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4598 | if (!Object.getOwnPropertyDescriptor(Module, "setErrNo")) Module["setErrNo"] = function() { abort("'setErrNo' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4599 | if (!Object.getOwnPropertyDescriptor(Module, "DNS")) Module["DNS"] = function() { abort("'DNS' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4600 | if (!Object.getOwnPropertyDescriptor(Module, "GAI_ERRNO_MESSAGES")) Module["GAI_ERRNO_MESSAGES"] = function() { abort("'GAI_ERRNO_MESSAGES' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4601 | if (!Object.getOwnPropertyDescriptor(Module, "Protocols")) Module["Protocols"] = function() { abort("'Protocols' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4602 | if (!Object.getOwnPropertyDescriptor(Module, "Sockets")) Module["Sockets"] = function() { abort("'Sockets' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4603 | if (!Object.getOwnPropertyDescriptor(Module, "UNWIND_CACHE")) Module["UNWIND_CACHE"] = function() { abort("'UNWIND_CACHE' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4604 | if (!Object.getOwnPropertyDescriptor(Module, "readAsmConstArgs")) Module["readAsmConstArgs"] = function() { abort("'readAsmConstArgs' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4605 | if (!Object.getOwnPropertyDescriptor(Module, "jstoi_q")) Module["jstoi_q"] = function() { abort("'jstoi_q' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4606 | if (!Object.getOwnPropertyDescriptor(Module, "jstoi_s")) Module["jstoi_s"] = function() { abort("'jstoi_s' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4607 | if (!Object.getOwnPropertyDescriptor(Module, "abortStackOverflow")) Module["abortStackOverflow"] = function() { abort("'abortStackOverflow' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4608 | if (!Object.getOwnPropertyDescriptor(Module, "reallyNegative")) Module["reallyNegative"] = function() { abort("'reallyNegative' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4609 | if (!Object.getOwnPropertyDescriptor(Module, "formatString")) Module["formatString"] = function() { abort("'formatString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4610 | if (!Object.getOwnPropertyDescriptor(Module, "PATH")) Module["PATH"] = function() { abort("'PATH' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4611 | if (!Object.getOwnPropertyDescriptor(Module, "PATH_FS")) Module["PATH_FS"] = function() { abort("'PATH_FS' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4612 | if (!Object.getOwnPropertyDescriptor(Module, "SYSCALLS")) Module["SYSCALLS"] = function() { abort("'SYSCALLS' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4613 | if (!Object.getOwnPropertyDescriptor(Module, "syscallMmap2")) Module["syscallMmap2"] = function() { abort("'syscallMmap2' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4614 | if (!Object.getOwnPropertyDescriptor(Module, "syscallMunmap")) Module["syscallMunmap"] = function() { abort("'syscallMunmap' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4615 | if (!Object.getOwnPropertyDescriptor(Module, "JSEvents")) Module["JSEvents"] = function() { abort("'JSEvents' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4616 | if (!Object.getOwnPropertyDescriptor(Module, "specialHTMLTargets")) Module["specialHTMLTargets"] = function() { abort("'specialHTMLTargets' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4617 | if (!Object.getOwnPropertyDescriptor(Module, "demangle")) Module["demangle"] = function() { abort("'demangle' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4618 | if (!Object.getOwnPropertyDescriptor(Module, "demangleAll")) Module["demangleAll"] = function() { abort("'demangleAll' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4619 | if (!Object.getOwnPropertyDescriptor(Module, "jsStackTrace")) Module["jsStackTrace"] = function() { abort("'jsStackTrace' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4620 | if (!Object.getOwnPropertyDescriptor(Module, "stackTrace")) Module["stackTrace"] = function() { abort("'stackTrace' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4621 | if (!Object.getOwnPropertyDescriptor(Module, "getEnvStrings")) Module["getEnvStrings"] = function() { abort("'getEnvStrings' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4622 | if (!Object.getOwnPropertyDescriptor(Module, "checkWasiClock")) Module["checkWasiClock"] = function() { abort("'checkWasiClock' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4623 | if (!Object.getOwnPropertyDescriptor(Module, "writeI53ToI64")) Module["writeI53ToI64"] = function() { abort("'writeI53ToI64' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4624 | if (!Object.getOwnPropertyDescriptor(Module, "writeI53ToI64Clamped")) Module["writeI53ToI64Clamped"] = function() { abort("'writeI53ToI64Clamped' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4625 | if (!Object.getOwnPropertyDescriptor(Module, "writeI53ToI64Signaling")) Module["writeI53ToI64Signaling"] = function() { abort("'writeI53ToI64Signaling' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4626 | if (!Object.getOwnPropertyDescriptor(Module, "writeI53ToU64Clamped")) Module["writeI53ToU64Clamped"] = function() { abort("'writeI53ToU64Clamped' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4627 | if (!Object.getOwnPropertyDescriptor(Module, "writeI53ToU64Signaling")) Module["writeI53ToU64Signaling"] = function() { abort("'writeI53ToU64Signaling' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4628 | if (!Object.getOwnPropertyDescriptor(Module, "readI53FromI64")) Module["readI53FromI64"] = function() { abort("'readI53FromI64' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4629 | if (!Object.getOwnPropertyDescriptor(Module, "readI53FromU64")) Module["readI53FromU64"] = function() { abort("'readI53FromU64' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4630 | if (!Object.getOwnPropertyDescriptor(Module, "convertI32PairToI53")) Module["convertI32PairToI53"] = function() { abort("'convertI32PairToI53' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4631 | if (!Object.getOwnPropertyDescriptor(Module, "convertU32PairToI53")) Module["convertU32PairToI53"] = function() { abort("'convertU32PairToI53' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4632 | if (!Object.getOwnPropertyDescriptor(Module, "Browser")) Module["Browser"] = function() { abort("'Browser' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4633 | if (!Object.getOwnPropertyDescriptor(Module, "FS")) Module["FS"] = function() { abort("'FS' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4634 | if (!Object.getOwnPropertyDescriptor(Module, "MEMFS")) Module["MEMFS"] = function() { abort("'MEMFS' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4635 | if (!Object.getOwnPropertyDescriptor(Module, "TTY")) Module["TTY"] = function() { abort("'TTY' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4636 | if (!Object.getOwnPropertyDescriptor(Module, "PIPEFS")) Module["PIPEFS"] = function() { abort("'PIPEFS' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4637 | if (!Object.getOwnPropertyDescriptor(Module, "SOCKFS")) Module["SOCKFS"] = function() { abort("'SOCKFS' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4638 | if (!Object.getOwnPropertyDescriptor(Module, "GL")) Module["GL"] = function() { abort("'GL' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4639 | if (!Object.getOwnPropertyDescriptor(Module, "emscriptenWebGLGet")) Module["emscriptenWebGLGet"] = function() { abort("'emscriptenWebGLGet' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4640 | if (!Object.getOwnPropertyDescriptor(Module, "emscriptenWebGLGetTexPixelData")) Module["emscriptenWebGLGetTexPixelData"] = function() { abort("'emscriptenWebGLGetTexPixelData' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4641 | if (!Object.getOwnPropertyDescriptor(Module, "emscriptenWebGLGetUniform")) Module["emscriptenWebGLGetUniform"] = function() { abort("'emscriptenWebGLGetUniform' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4642 | if (!Object.getOwnPropertyDescriptor(Module, "emscriptenWebGLGetVertexAttrib")) Module["emscriptenWebGLGetVertexAttrib"] = function() { abort("'emscriptenWebGLGetVertexAttrib' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4643 | if (!Object.getOwnPropertyDescriptor(Module, "AL")) Module["AL"] = function() { abort("'AL' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4644 | if (!Object.getOwnPropertyDescriptor(Module, "SDL_unicode")) Module["SDL_unicode"] = function() { abort("'SDL_unicode' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4645 | if (!Object.getOwnPropertyDescriptor(Module, "SDL_ttfContext")) Module["SDL_ttfContext"] = function() { abort("'SDL_ttfContext' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4646 | if (!Object.getOwnPropertyDescriptor(Module, "SDL_audio")) Module["SDL_audio"] = function() { abort("'SDL_audio' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4647 | if (!Object.getOwnPropertyDescriptor(Module, "SDL")) Module["SDL"] = function() { abort("'SDL' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4648 | if (!Object.getOwnPropertyDescriptor(Module, "SDL_gfx")) Module["SDL_gfx"] = function() { abort("'SDL_gfx' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4649 | if (!Object.getOwnPropertyDescriptor(Module, "GLUT")) Module["GLUT"] = function() { abort("'GLUT' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4650 | if (!Object.getOwnPropertyDescriptor(Module, "EGL")) Module["EGL"] = function() { abort("'EGL' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4651 | if (!Object.getOwnPropertyDescriptor(Module, "GLFW_Window")) Module["GLFW_Window"] = function() { abort("'GLFW_Window' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4652 | if (!Object.getOwnPropertyDescriptor(Module, "GLFW")) Module["GLFW"] = function() { abort("'GLFW' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4653 | if (!Object.getOwnPropertyDescriptor(Module, "GLEW")) Module["GLEW"] = function() { abort("'GLEW' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4654 | if (!Object.getOwnPropertyDescriptor(Module, "IDBStore")) Module["IDBStore"] = function() { abort("'IDBStore' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4655 | if (!Object.getOwnPropertyDescriptor(Module, "runAndAbortIfError")) Module["runAndAbortIfError"] = function() { abort("'runAndAbortIfError' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4656 | if (!Object.getOwnPropertyDescriptor(Module, "warnOnce")) Module["warnOnce"] = function() { abort("'warnOnce' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4657 | if (!Object.getOwnPropertyDescriptor(Module, "stackSave")) Module["stackSave"] = function() { abort("'stackSave' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4658 | if (!Object.getOwnPropertyDescriptor(Module, "stackRestore")) Module["stackRestore"] = function() { abort("'stackRestore' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4659 | if (!Object.getOwnPropertyDescriptor(Module, "stackAlloc")) Module["stackAlloc"] = function() { abort("'stackAlloc' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4660 | if (!Object.getOwnPropertyDescriptor(Module, "AsciiToString")) Module["AsciiToString"] = function() { abort("'AsciiToString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4661 | if (!Object.getOwnPropertyDescriptor(Module, "stringToAscii")) Module["stringToAscii"] = function() { abort("'stringToAscii' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4662 | if (!Object.getOwnPropertyDescriptor(Module, "UTF16ToString")) Module["UTF16ToString"] = function() { abort("'UTF16ToString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4663 | if (!Object.getOwnPropertyDescriptor(Module, "stringToUTF16")) Module["stringToUTF16"] = function() { abort("'stringToUTF16' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4664 | if (!Object.getOwnPropertyDescriptor(Module, "lengthBytesUTF16")) Module["lengthBytesUTF16"] = function() { abort("'lengthBytesUTF16' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4665 | if (!Object.getOwnPropertyDescriptor(Module, "UTF32ToString")) Module["UTF32ToString"] = function() { abort("'UTF32ToString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4666 | if (!Object.getOwnPropertyDescriptor(Module, "stringToUTF32")) Module["stringToUTF32"] = function() { abort("'stringToUTF32' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4667 | if (!Object.getOwnPropertyDescriptor(Module, "lengthBytesUTF32")) Module["lengthBytesUTF32"] = function() { abort("'lengthBytesUTF32' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4668 | if (!Object.getOwnPropertyDescriptor(Module, "allocateUTF8")) Module["allocateUTF8"] = function() { abort("'allocateUTF8' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4669 | if (!Object.getOwnPropertyDescriptor(Module, "allocateUTF8OnStack")) Module["allocateUTF8OnStack"] = function() { abort("'allocateUTF8OnStack' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") }; |
||
4670 | Module["writeStackCookie"] = writeStackCookie; |
||
4671 | Module["checkStackCookie"] = checkStackCookie;if (!Object.getOwnPropertyDescriptor(Module, "ALLOC_NORMAL")) Object.defineProperty(Module, "ALLOC_NORMAL", { configurable: true, get: function() { abort("'ALLOC_NORMAL' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") } }); |
||
4672 | if (!Object.getOwnPropertyDescriptor(Module, "ALLOC_STACK")) Object.defineProperty(Module, "ALLOC_STACK", { configurable: true, get: function() { abort("'ALLOC_STACK' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") } }); |
||
4673 | if (!Object.getOwnPropertyDescriptor(Module, "ALLOC_DYNAMIC")) Object.defineProperty(Module, "ALLOC_DYNAMIC", { configurable: true, get: function() { abort("'ALLOC_DYNAMIC' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") } }); |
||
4674 | if (!Object.getOwnPropertyDescriptor(Module, "ALLOC_NONE")) Object.defineProperty(Module, "ALLOC_NONE", { configurable: true, get: function() { abort("'ALLOC_NONE' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") } }); |
||
4675 | |||
4676 | |||
4677 | |||
4678 | var calledRun; |
||
4679 | |||
4680 | /** |
||
4681 | * @constructor |
||
4682 | * @this {ExitStatus} |
||
4683 | */ |
||
4684 | function ExitStatus(status) { |
||
4685 | this.name = "ExitStatus"; |
||
4686 | this.message = "Program terminated with exit(" + status + ")"; |
||
4687 | this.status = status; |
||
4688 | } |
||
4689 | |||
4690 | var calledMain = false; |
||
4691 | |||
4692 | |||
4693 | dependenciesFulfilled = function runCaller() { |
||
4694 | // If run has never been called, and we should call run (INVOKE_RUN is true, and Module.noInitialRun is not false) |
||
4695 | if (!calledRun) run(); |
||
4696 | if (!calledRun) dependenciesFulfilled = runCaller; // try this again later, after new deps are fulfilled |
||
4697 | }; |
||
4698 | |||
4699 | function callMain(args) { |
||
4700 | assert(runDependencies == 0, 'cannot call main when async dependencies remain! (listen on Module["onRuntimeInitialized"])'); |
||
4701 | assert(__ATPRERUN__.length == 0, 'cannot call main when preRun functions remain to be called'); |
||
4702 | |||
4703 | var entryFunction = Module['_main']; |
||
4704 | |||
4705 | |||
4706 | args = args || []; |
||
4707 | |||
4708 | var argc = args.length+1; |
||
4709 | var argv = stackAlloc((argc + 1) * 4); |
||
4710 | HEAP32[argv >> 2] = allocateUTF8OnStack(thisProgram); |
||
4711 | for (var i = 1; i < argc; i++) { |
||
4712 | HEAP32[(argv >> 2) + i] = allocateUTF8OnStack(args[i - 1]); |
||
4713 | } |
||
4714 | HEAP32[(argv >> 2) + argc] = 0; |
||
4715 | |||
4716 | try { |
||
4717 | |||
4718 | Module['___set_stack_limit'](STACK_MAX); |
||
4719 | |||
4720 | var ret = entryFunction(argc, argv); |
||
4721 | |||
4722 | |||
4723 | // In PROXY_TO_PTHREAD builds, we should never exit the runtime below, as execution is asynchronously handed |
||
4724 | // off to a pthread. |
||
4725 | // if we're not running an evented main loop, it's time to exit |
||
4726 | exit(ret, /* implicit = */ true); |
||
4727 | } |
||
4728 | catch(e) { |
||
4729 | if (e instanceof ExitStatus) { |
||
4730 | // exit() throws this once it's done to make sure execution |
||
4731 | // has been stopped completely |
||
4732 | return; |
||
4733 | } else if (e == 'unwind') { |
||
4734 | // running an evented main loop, don't immediately exit |
||
4735 | noExitRuntime = true; |
||
4736 | return; |
||
4737 | } else { |
||
4738 | var toLog = e; |
||
4739 | if (e && typeof e === 'object' && e.stack) { |
||
4740 | toLog = [e, e.stack]; |
||
4741 | } |
||
4742 | err('exception thrown: ' + toLog); |
||
4743 | quit_(1, e); |
||
4744 | } |
||
4745 | } finally { |
||
4746 | calledMain = true; |
||
4747 | } |
||
4748 | } |
||
4749 | |||
4750 | |||
4751 | |||
4752 | |||
4753 | /** @type {function(Array=)} */ |
||
4754 | function run(args) { |
||
4755 | args = args || arguments_; |
||
4756 | |||
4757 | if (runDependencies > 0) { |
||
4758 | return; |
||
4759 | } |
||
4760 | |||
4761 | writeStackCookie(); |
||
4762 | |||
4763 | preRun(); |
||
4764 | |||
4765 | if (runDependencies > 0) return; // a preRun added a dependency, run will be called later |
||
4766 | |||
4767 | function doRun() { |
||
4768 | // run may have just been called through dependencies being fulfilled just in this very frame, |
||
4769 | // or while the async setStatus time below was happening |
||
4770 | if (calledRun) return; |
||
4771 | calledRun = true; |
||
4772 | Module['calledRun'] = true; |
||
4773 | |||
4774 | if (ABORT) return; |
||
4775 | |||
4776 | initRuntime(); |
||
4777 | |||
4778 | preMain(); |
||
4779 | |||
4780 | if (Module['onRuntimeInitialized']) Module['onRuntimeInitialized'](); |
||
4781 | |||
4782 | if (shouldRunNow) callMain(args); |
||
4783 | |||
4784 | postRun(); |
||
4785 | } |
||
4786 | |||
4787 | if (Module['setStatus']) { |
||
4788 | Module['setStatus']('Running...'); |
||
4789 | setTimeout(function() { |
||
4790 | setTimeout(function() { |
||
4791 | Module['setStatus'](''); |
||
4792 | }, 1); |
||
4793 | doRun(); |
||
4794 | }, 1); |
||
4795 | } else |
||
4796 | { |
||
4797 | doRun(); |
||
4798 | } |
||
4799 | checkStackCookie(); |
||
4800 | } |
||
4801 | Module['run'] = run; |
||
4802 | |||
4803 | function checkUnflushedContent() { |
||
4804 | // Compiler settings do not allow exiting the runtime, so flushing |
||
4805 | // the streams is not possible. but in ASSERTIONS mode we check |
||
4806 | // if there was something to flush, and if so tell the user they |
||
4807 | // should request that the runtime be exitable. |
||
4808 | // Normally we would not even include flush() at all, but in ASSERTIONS |
||
4809 | // builds we do so just for this check, and here we see if there is any |
||
4810 | // content to flush, that is, we check if there would have been |
||
4811 | // something a non-ASSERTIONS build would have not seen. |
||
4812 | // How we flush the streams depends on whether we are in SYSCALLS_REQUIRE_FILESYSTEM=0 |
||
4813 | // mode (which has its own special function for this; otherwise, all |
||
4814 | // the code is inside libc) |
||
4815 | var print = out; |
||
4816 | var printErr = err; |
||
4817 | var has = false; |
||
4818 | out = err = function(x) { |
||
4819 | has = true; |
||
4820 | } |
||
4821 | try { // it doesn't matter if it fails |
||
4822 | var flush = Module['_fflush']; |
||
4823 | if (flush) flush(0); |
||
4824 | // also flush in the JS FS layer |
||
4825 | ['stdout', 'stderr'].forEach(function(name) { |
||
4826 | var info = FS.analyzePath('/dev/' + name); |
||
4827 | if (!info) return; |
||
4828 | var stream = info.object; |
||
4829 | var rdev = stream.rdev; |
||
4830 | var tty = TTY.ttys[rdev]; |
||
4831 | if (tty && tty.output && tty.output.length) { |
||
4832 | has = true; |
||
4833 | } |
||
4834 | }); |
||
4835 | } catch(e) {} |
||
4836 | out = print; |
||
4837 | err = printErr; |
||
4838 | if (has) { |
||
4839 | warnOnce('stdio streams had content in them that was not flushed. you should set EXIT_RUNTIME to 1 (see the FAQ), or make sure to emit a newline when you printf etc.'); |
||
4840 | } |
||
4841 | } |
||
4842 | |||
4843 | /** @param {boolean|number=} implicit */ |
||
4844 | function exit(status, implicit) { |
||
4845 | checkUnflushedContent(); |
||
4846 | |||
4847 | // if this is just main exit-ing implicitly, and the status is 0, then we |
||
4848 | // don't need to do anything here and can just leave. if the status is |
||
4849 | // non-zero, though, then we need to report it. |
||
4850 | // (we may have warned about this earlier, if a situation justifies doing so) |
||
4851 | if (implicit && noExitRuntime && status === 0) { |
||
4852 | return; |
||
4853 | } |
||
4854 | |||
4855 | if (noExitRuntime) { |
||
4856 | // if exit() was called, we may warn the user if the runtime isn't actually being shut down |
||
4857 | if (!implicit) { |
||
4858 | var msg = 'program exited (with status: ' + status + '), but EXIT_RUNTIME is not set, so halting execution but not exiting the runtime or preventing further async execution (build with EXIT_RUNTIME=1, if you want a true shutdown)'; |
||
4859 | err(msg); |
||
4860 | } |
||
4861 | } else { |
||
4862 | |||
4863 | ABORT = true; |
||
4864 | EXITSTATUS = status; |
||
4865 | |||
4866 | exitRuntime(); |
||
4867 | |||
4868 | if (Module['onExit']) Module['onExit'](status); |
||
4869 | } |
||
4870 | |||
4871 | quit_(status, new ExitStatus(status)); |
||
4872 | } |
||
4873 | |||
4874 | if (Module['preInit']) { |
||
4875 | if (typeof Module['preInit'] == 'function') Module['preInit'] = [Module['preInit']]; |
||
4876 | while (Module['preInit'].length > 0) { |
||
4877 | Module['preInit'].pop()(); |
||
4878 | } |
||
4879 | } |
||
4880 | |||
4881 | // shouldRunNow refers to calling main(), not run(). |
||
4882 | var shouldRunNow = true; |
||
4883 | |||
4884 | if (Module['noInitialRun']) shouldRunNow = false; |
||
4885 | |||
4886 | |||
4887 | noExitRuntime = true; |
||
4888 | |||
4889 | run(); |
||
4890 | |||
4891 | |||
4892 | |||
4893 | |||
4894 | |||
4895 | |||
4896 | // {{MODULE_ADDITIONS}} |
||
4897 | |||
4898 | |||
4899 |