diff options
-rwxr-xr-x | emlibtool | 11 | ||||
-rw-r--r-- | emlibtool.bat | 2 | ||||
-rw-r--r-- | src/intertyper.js | 12 | ||||
-rw-r--r-- | src/jsifier.js | 4 | ||||
-rw-r--r-- | src/library.js | 61 | ||||
-rw-r--r-- | src/library_fs.js | 1389 | ||||
-rw-r--r-- | system/include/libcxx/__locale | 12 | ||||
-rw-r--r-- | system/include/libcxx/locale | 2 | ||||
-rw-r--r-- | system/lib/libcxx/exception.cpp | 6 | ||||
-rw-r--r-- | system/lib/libcxx/locale.cpp | 24 | ||||
-rw-r--r-- | system/lib/libcxxabi/src/cxa_new_delete.cpp | 2 | ||||
-rw-r--r-- | tests/filesystem/src.js | 22 | ||||
-rwxr-xr-x | tests/runner.py | 2 | ||||
-rw-r--r-- | tests/test_core.py | 66 | ||||
-rw-r--r-- | tests/unistd/access.c | 8 | ||||
-rw-r--r-- | tests/unistd/access.js | 4 | ||||
-rw-r--r-- | tests/unistd/access.out | 4 | ||||
-rw-r--r-- | tests/unistd/curdir.c | 11 | ||||
-rw-r--r-- | tests/unistd/curdir.js | 7 | ||||
-rw-r--r-- | tests/unistd/io.c | 50 | ||||
-rw-r--r-- | tests/unistd/io.js | 52 | ||||
-rw-r--r-- | tests/unistd/links.c | 7 | ||||
-rw-r--r-- | tests/unistd/links.js | 3 | ||||
-rw-r--r-- | tests/unistd/truncate.c | 7 | ||||
-rw-r--r-- | tests/unistd/truncate.js | 2 | ||||
-rw-r--r-- | tools/js-optimizer.js | 2 | ||||
-rw-r--r-- | tools/shared.py | 28 |
27 files changed, 933 insertions, 867 deletions
diff --git a/emlibtool b/emlibtool deleted file mode 100755 index 1eb18edc..00000000 --- a/emlibtool +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env python2 - -''' -This is a helper script. See emcc. -''' - -import os, sys -from tools import shared - -raise Exception('TODO: emlibtool') - diff --git a/emlibtool.bat b/emlibtool.bat deleted file mode 100644 index 4ea705be..00000000 --- a/emlibtool.bat +++ /dev/null @@ -1,2 +0,0 @@ -@echo off -python "%~dp0\emlibtool" %*
\ No newline at end of file diff --git a/src/intertyper.js b/src/intertyper.js index 31e97bd0..5432b1ca 100644 --- a/src/intertyper.js +++ b/src/intertyper.js @@ -712,11 +712,13 @@ function intertyper(data, sidePass, baseLineNums) { if (tokensLeft[0].text == 'sideeffect') tokensLeft.splice(0, 1); item.ident = tokensLeft[0].text.substr(1, tokensLeft[0].text.length-2) || ';'; // use ; for empty inline assembly var i = 0; - splitTokenList(tokensLeft[3].item.tokens).map(function(element) { - var ident = toNiceIdent(element[1].text); - var type = element[0].text; - item.ident = item.ident.replace(new RegExp('\\$' + i++, 'g'), ident); - }); + if (tokensLeft[3].item) { // not present in x86 inline asm + splitTokenList(tokensLeft[3].item.tokens).map(function(element) { + var ident = toNiceIdent(element[1].text); + var type = element[0].text; + item.ident = item.ident.replace(new RegExp('\\$' + i++, 'g'), ident); + }); + } return { forward: null, ret: [item], item: item }; } if (item.ident.substr(-2) == '()') { diff --git a/src/jsifier.js b/src/jsifier.js index f5682a1b..38f3bd5e 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -1143,8 +1143,8 @@ function JSify(data, functionsOnly, givenFunctions) { }); var range = maxx - minn; var useIfs = (item.switchLabels.length+1) < 6 || range > 10*1024 || (range/item.switchLabels.length) > 1024; // heuristics - if (VERBOSE && useIfs && item.switchLabels.length > 2) { - warn('not optimizing llvm switch into js switch because ' + [range, range/item.switchLabels.length]); + if (VERBOSE && useIfs && item.switchLabels.length >= 6) { + warn('not optimizing llvm switch into js switch because range of values is ' + range + ', density is ' + range/item.switchLabels.length); } var phiSets = calcPhiSets(item); diff --git a/src/library.js b/src/library.js index 3008a055..f3c3c1ec 100644 --- a/src/library.js +++ b/src/library.js @@ -323,10 +323,16 @@ LibraryManager.library = { path = Pointer_stringify(path); // we don't want this in the JS API as the JS API // uses mknod to create all nodes. - var err = FS.mayMknod(mode); - if (err) { - ___setErrNo(err); - return -1; + switch (mode & {{{ cDefine('S_IFMT') }}}) { + case {{{ cDefine('S_IFREG') }}}: + case {{{ cDefine('S_IFCHR') }}}: + case {{{ cDefine('S_IFBLK') }}}: + case {{{ cDefine('S_IFIFO') }}}: + case {{{ cDefine('S_IFSOCK') }}}: + break; + default: + ___setErrNo(ERRNO_CODES.EINVAL); + return -1; } try { FS.mknod(path, mode, dev); @@ -4659,20 +4665,28 @@ LibraryManager.library = { cos: 'Math.cos', cosf: 'Math.cos', + cosl: 'Math.cos', sin: 'Math.sin', sinf: 'Math.sin', + sinl: 'Math.sin', tan: 'Math.tan', tanf: 'Math.tan', + tanl: 'Math.tan', acos: 'Math.acos', acosf: 'Math.acos', + acosl: 'Math.acos', asin: 'Math.asin', asinf: 'Math.asin', + asinl: 'Math.asin', atan: 'Math.atan', atanf: 'Math.atan', + atanl: 'Math.atan', atan2: 'Math.atan2', atan2f: 'Math.atan2', + atan2l: 'Math.atan2', exp: 'Math.exp', expf: 'Math.exp', + expl: 'Math.exp', // The erf and erfc functions are inspired from // http://www.digitalmars.com/archives/cplusplus/3634.html @@ -4708,7 +4722,8 @@ LibraryManager.library = { } while (Math.abs(q1 - q2) / q2 > MATH_TOLERANCE); return (ONE_SQRTPI * Math.exp(- x * x) * q2); }, - erfcf: 'erfcf', + erfcf: 'erfc', + erfcl: 'erfc', erf__deps: ['erfc'], erf: function(x) { var MATH_TOLERANCE = 1E-12; @@ -4732,6 +4747,7 @@ LibraryManager.library = { return (TWO_SQRTPI * sum); }, erff: 'erf', + erfl: 'erf', log: 'Math.log', logf: 'Math.log', logl: 'Math.log', @@ -4820,6 +4836,7 @@ LibraryManager.library = { return __reallyNegative(a) === __reallyNegative(b) ? a : -a; }, copysignf: 'copysign', + copysignl: 'copysign', __signbit__deps: ['copysign'], __signbit: function(x) { // We implement using copysign so that we get support @@ -4832,56 +4849,70 @@ LibraryManager.library = { return Math.sqrt(a*a + b*b); }, hypotf: 'hypot', + hypotl: 'hypot', sinh: function(x) { var p = Math.pow(Math.E, x); return (p - (1 / p)) / 2; }, sinhf: 'sinh', + sinhl: 'sinh', cosh: function(x) { var p = Math.pow(Math.E, x); return (p + (1 / p)) / 2; }, coshf: 'cosh', + coshl: 'cosh', tanh__deps: ['sinh', 'cosh'], tanh: function(x) { return _sinh(x) / _cosh(x); }, tanhf: 'tanh', + tanhl: 'tanh', asinh: function(x) { return Math.log(x + Math.sqrt(x * x + 1)); }, asinhf: 'asinh', + asinhl: 'asinh', acosh: function(x) { return Math.log(x * 1 + Math.sqrt(x * x - 1)); }, acoshf: 'acosh', + acoshl: 'acosh', atanh: function(x) { return Math.log((1 + x) / (1 - x)) / 2; }, atanhf: 'atanh', + atanhl: 'atanh', exp2: function(x) { return Math.pow(2, x); }, exp2f: 'exp2', + exp2l: 'exp2', expm1: function(x) { return Math.exp(x) - 1; }, expm1f: 'expm1', + expm1l: 'expm1', round: function(x) { return (x < 0) ? -Math.round(-x) : Math.round(x); }, roundf: 'round', + roundl: 'round', lround: 'round', lroundf: 'round', + lroundl: 'round', llround: 'round', llroundf: 'round', + llroundl: 'round', rint: function(x) { if (Math.abs(x % 1) !== 0.5) return Math.round(x); return x + x % 2 + ((x < 0) ? 1 : -1); }, rintf: 'rint', + rintl: 'rint', lrint: 'rint', lrintf: 'rint', + lrintl: 'rint', #if USE_TYPED_ARRAYS == 2 llrint: function(x) { x = (x < 0) ? -Math.round(-x) : Math.round(x); @@ -4891,50 +4922,63 @@ LibraryManager.library = { llrint: 'rint', #endif llrintf: 'llrint', + llrintl: 'llrint', nearbyint: 'rint', nearbyintf: 'rint', + nearbyintl: 'rint', trunc: function(x) { return (x < 0) ? Math.ceil(x) : Math.floor(x); }, truncf: 'trunc', + truncl: 'trunc', fdim: function(x, y) { return (x > y) ? x - y : 0; }, fdimf: 'fdim', + fdiml: 'fdim', fmax: function(x, y) { return isNaN(x) ? y : isNaN(y) ? x : Math.max(x, y); }, fmaxf: 'fmax', + fmaxl: 'fmax', fmin: function(x, y) { return isNaN(x) ? y : isNaN(y) ? x : Math.min(x, y); }, fminf: 'fmin', + fminl: 'fmin', fma: function(x, y, z) { return x * y + z; }, fmaf: 'fma', + fmal: 'fma', fmod: function(x, y) { return x % y; }, fmodf: 'fmod', + fmodl: 'fmod', remainder: 'fmod', remainderf: 'fmod', + remainderl: 'fmod', log10: function(x) { return Math.log(x) / Math.LN10; }, log10f: 'log10', + log10l: 'log10', log1p: function(x) { return Math.log(1 + x); }, log1pf: 'log1p', + log1pl: 'log1p', log2: function(x) { return Math.log(x) / Math.LN2; }, log2f: 'log2', + log2l: 'log2', nan: function(x) { return NaN; }, nanf: 'nan', + nanl: 'nan', sincos: function(x, sine, cosine) { var sineVal = Math.sin(x), @@ -4942,6 +4986,7 @@ LibraryManager.library = { {{{ makeSetValue('sine', '0', 'sineVal', 'double') }}}; {{{ makeSetValue('cosine', '0', 'cosineVal', 'double') }}}; }, + sincosl: 'sincos', sincosf: function(x, sine, cosine) { var sineVal = Math.sin(x), @@ -6071,7 +6116,7 @@ LibraryManager.library = { // int clock_gettime(clockid_t clk_id, struct timespec *tp); var now = Date.now(); {{{ makeSetValue('tp', '___timespec_struct_layout.tv_sec', 'Math.floor(now/1000)', 'i32') }}}; // seconds - {{{ makeSetValue('tp', '___timespec_struct_layout.tv_nsec', '0', 'i32') }}}; // nanoseconds - not supported + {{{ makeSetValue('tp', '___timespec_struct_layout.tv_nsec', '(now % 1000) * 1000 * 1000', 'i32') }}}; // nanoseconds (really milliseconds) return 0; }, clock_settime: function(clk_id, tp) { @@ -6083,7 +6128,7 @@ LibraryManager.library = { clock_getres: function(clk_id, res) { // int clock_getres(clockid_t clk_id, struct timespec *res); {{{ makeSetValue('res', '___timespec_struct_layout.tv_sec', '1', 'i32') }}} - {{{ makeSetValue('res', '___timespec_struct_layout.tv_nsec', '0', 'i32') }}} + {{{ makeSetValue('res', '___timespec_struct_layout.tv_nsec', '1000 * 1000', 'i32') }}} // resolution is milliseconds return 0; }, @@ -7392,7 +7437,7 @@ LibraryManager.library = { var aliasesBuf = _malloc(4); {{{ makeSetValue('aliasesBuf', '0', '0', 'i8*') }}} {{{ makeSetValue('ret', '___hostent_struct_layout.h_aliases', 'aliasesBuf', 'i8**') }}} - var afinet = {{{ cDefine("AF_INET") }}}; + var afinet = {{{ cDefine('AF_INET') }}}; {{{ makeSetValue('ret', '___hostent_struct_layout.h_addrtype', 'afinet', 'i32') }}} {{{ makeSetValue('ret', '___hostent_struct_layout.h_length', '4', 'i32') }}} var addrListBuf = _malloc(12); diff --git a/src/library_fs.js b/src/library_fs.js index 5573dc27..4a150d80 100644 --- a/src/library_fs.js +++ b/src/library_fs.js @@ -14,11 +14,10 @@ mergeInto(LibraryManager.library, { 'Module["FS_createDevice"] = FS.createDevice;', $FS: { root: null, - nodes: [null], devices: [null], streams: [null], nextInode: 1, - name_table: null, + nameTable: null, currentPath: '/', initialized: false, // Whether we are currently ignoring permissions. Useful when preparing the @@ -49,6 +48,76 @@ mergeInto(LibraryManager.library, { }, // + // paths + // + cwd: function() { + return FS.currentPath; + }, + lookupPath: function(path, opts) { + path = PATH.resolve(FS.currentPath, path); + opts = opts || { recurse_count: 0 }; + + if (opts.recurse_count > 8) { // max recursive lookup of 8 + throw new FS.ErrnoError(ERRNO_CODES.ELOOP); + } + + // split the path + var parts = PATH.normalizeArray(path.split('/').filter(function(p) { + return !!p; + }), false); + + // start at the root + var current = FS.root; + var current_path = '/'; + + for (var i = 0; i < parts.length; i++) { + var islast = (i === parts.length-1); + if (islast && opts.parent) { + // stop resolving + break; + } + + current = FS.lookupNode(current, parts[i]); + current_path = PATH.join(current_path, parts[i]); + + // jump to the mount's root node if this is a mountpoint + if (FS.isMountpoint(current)) { + current = current.mount.root; + } + + // follow symlinks + // by default, lookupPath will not follow a symlink if it is the final path component. + // setting opts.follow = true will override this behavior. + if (!islast || opts.follow) { + var count = 0; + while (FS.isLink(current.mode)) { + var link = FS.readlink(current_path); + current_path = PATH.resolve(PATH.dirname(current_path), link); + + var lookup = FS.lookupPath(current_path, { recurse_count: opts.recurse_count }); + current = lookup.node; + + if (count++ > 40) { // limit max consecutive symlinks to 40 (SYMLOOP_MAX). + throw new FS.ErrnoError(ERRNO_CODES.ELOOP); + } + } + } + } + + return { path: current_path, node: current }; + }, + getPath: function(node) { + var path; + while (true) { + if (FS.isRoot(node)) { + return path ? PATH.join(node.mount.mountpoint, path) : node.mount.mountpoint; + } + path = path ? PATH.join(node.name, path) : node.name; + node = node.parent; + } + }, + + // // nodes // hashName: function(parentid, name) { @@ -56,19 +125,19 @@ mergeInto(LibraryManager.library, { for (var i = 0; i < name.length; i++) { hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0; } - return ((parentid + hash) >>> 0) % FS.name_table.length; + return ((parentid + hash) >>> 0) % FS.nameTable.length; }, hashAddNode: function(node) { var hash = FS.hashName(node.parent.id, node.name); - node.name_next = FS.name_table[hash]; - FS.name_table[hash] = node; + node.name_next = FS.nameTable[hash]; + FS.nameTable[hash] = node; }, hashRemoveNode: function(node) { var hash = FS.hashName(node.parent.id, node.name); - if (FS.name_table[hash] === node) { - FS.name_table[hash] = node.name_next; + if (FS.nameTable[hash] === node) { + FS.nameTable[hash] = node.name_next; } else { - var current = FS.name_table[hash]; + var current = FS.nameTable[hash]; while (current) { if (current.name_next === node) { current.name_next = node.name_next; @@ -84,7 +153,7 @@ mergeInto(LibraryManager.library, { throw new FS.ErrnoError(err); } var hash = FS.hashName(parent.id, name); - for (var node = FS.name_table[hash]; node; node = node.name_next) { + for (var node = FS.nameTable[hash]; node; node = node.name_next) { if (node.parent.id === parent.id && node.name === name) { return node; } @@ -164,76 +233,6 @@ mergeInto(LibraryManager.library, { }, // - // paths - // - cwd: function() { - return FS.currentPath; - }, - lookupPath: function(path, opts) { - path = PATH.resolve(FS.currentPath, path); - opts = opts || { recurse_count: 0 }; - - if (opts.recurse_count > 8) { // max recursive lookup of 8 - throw new FS.ErrnoError(ERRNO_CODES.ELOOP); - } - - // split the path - var parts = PATH.normalizeArray(path.split('/').filter(function(p) { - return !!p; - }), false); - - // start at the root - var current = FS.root; - var current_path = '/'; - - for (var i = 0; i < parts.length; i++) { - var islast = (i === parts.length-1); - if (islast && opts.parent) { - // stop resolving - break; - } - - current = FS.lookupNode(current, parts[i]); - current_path = PATH.join(current_path, parts[i]); - - // jump to the mount's root node if this is a mountpoint - if (FS.isMountpoint(current)) { - current = current.mount.root; - } - - // follow symlinks - // by default, lookupPath will not follow a symlink if it is the final path component. - // setting opts.follow = true will override this behavior. - if (!islast || opts.follow) { - var count = 0; - while (FS.isLink(current.mode)) { - var link = FS.readlink(current_path); - current_path = PATH.resolve(PATH.dirname(current_path), link); - - var lookup = FS.lookupPath(current_path, { recurse_count: opts.recurse_count }); - current = lookup.node; - - if (count++ > 40) { // limit max consecutive symlinks to 40 (SYMLOOP_MAX). - throw new FS.ErrnoError(ERRNO_CODES.ELOOP); - } - } - } - } - - return { path: current_path, node: current }; - }, - getPath: function(node) { - var path; - while (true) { - if (FS.isRoot(node)) { - return path ? PATH.join(node.mount.mountpoint, path) : node.mount.mountpoint; - } - path = path ? PATH.join(node.name, path) : node.name; - node = node.parent; - } - }, - - // // permissions // flagModes: { @@ -287,18 +286,6 @@ mergeInto(LibraryManager.library, { mayLookup: function(dir) { return FS.nodePermissions(dir, 'x'); }, - mayMknod: function(mode) { - switch (mode & {{{ cDefine('S_IFMT') }}}) { - case {{{ cDefine('S_IFREG') }}}: - case {{{ cDefine('S_IFCHR') }}}: - case {{{ cDefine('S_IFBLK') }}}: - case {{{ cDefine('S_IFIFO') }}}: - case {{{ cDefine('S_IFSOCK') }}}: - return 0; - default: - return ERRNO_CODES.EINVAL; - } - }, mayCreate: function(dir, name) { try { var node = FS.lookupNode(dir, name); @@ -348,45 +335,6 @@ mergeInto(LibraryManager.library, { }, // - // devices - // - // each character device consists of a device id + stream operations. - // when a character device node is created (e.g. /dev/stdin) it is - // assigned a device id that lets us map back to the actual device. - // by default, each character device stream (e.g. _stdin) uses chrdev_stream_ops. - // however, once opened, the stream's operations are overridden with - // the operations of the device its underlying node maps back to. - chrdev_stream_ops: { - open: function(stream) { - var device = FS.getDevice(stream.node.rdev); - // override node's stream ops with the device's - stream.stream_ops = device.stream_ops; - // forward the open call - if (stream.stream_ops.open) { - stream.stream_ops.open(stream); - } - }, - llseek: function() { - throw new FS.ErrnoError(ERRNO_CODES.ESPIPE); - } - }, - major: function(dev) { - return ((dev) >> 8); - }, - minor: function(dev) { - return ((dev) & 0xff); - }, - makedev: function(ma, mi) { - return ((ma) << 8 | (mi)); - }, - registerDevice: function(dev, ops) { - FS.devices[dev] = { stream_ops: ops }; - }, - getDevice: function(dev) { - return FS.devices[dev]; - }, - - // // streams // MAX_OPEN_FDS: 4096, @@ -433,563 +381,46 @@ mergeInto(LibraryManager.library, { }, // - // compatibility + // devices // - getMode: function(canRead, canWrite) { - var mode = 0; - if (canRead) mode |= {{{ cDefine('S_IRUGO') }}} | {{{ cDefine('S_IXUGO') }}}; - if (canWrite) mode |= {{{ cDefine('S_IWUGO') }}}; - return mode; - }, - joinPath: function(parts, forceRelative) { - var path = PATH.join.apply(null, parts); - if (forceRelative && path[0] == '/') path = path.substr(1); - return path; - }, - absolutePath: function(relative, base) { - return PATH.resolve(base, relative); - }, - standardizePath: function(path) { - return PATH.normalize(path); - }, - findObject: function(path, dontResolveLastLink) { - var ret = FS.analyzePath(path, dontResolveLastLink); - if (ret.exists) { - return ret.object; - } else { - ___setErrNo(ret.error); - return null; - } - }, - analyzePath: function(path, dontResolveLastLink) { - // operate from within the context of the symlink's target - try { - var lookup = FS.lookupPath(path, { follow: !dontResolveLastLink }); - path = lookup.path; - } catch (e) { - } - var ret = { - isRoot: false, exists: false, error: 0, name: null, path: null, object: null, - parentExists: false, parentPath: null, parentObject: null - }; - try { - var lookup = FS.lookupPath(path, { parent: true }); - ret.parentExists = true; - ret.parentPath = lookup.path; - ret.parentObject = lookup.node; - ret.name = PATH.basename(path); - lookup = FS.lookupPath(path, { follow: !dontResolveLastLink }); - ret.exists = true; - ret.path = lookup.path; - ret.object = lookup.node; - ret.name = lookup.node.name; - ret.isRoot = lookup.path === '/'; - } catch (e) { - ret.error = e.errno; - }; - return ret; - }, - createFolder: function(parent, name, canRead, canWrite) { - var path = PATH.join(typeof parent === 'string' ? parent : FS.getPath(parent), name); - var mode = FS.getMode(canRead, canWrite); - return FS.mkdir(path, mode); - }, - createPath: function(parent, path, canRead, canWrite) { - parent = typeof parent === 'string' ? parent : FS.getPath(parent); - var parts = path.split('/').reverse(); - while (parts.length) { - var part = parts.pop(); - if (!part) continue; - var current = PATH.join(parent, part); - try { - FS.mkdir(current, 0777); - } catch (e) { - // ignore EEXIST - } - parent = current; - } - return current; - }, - createFile: function(parent, name, properties, canRead, canWrite) { - var path = PATH.join(typeof parent === 'string' ? parent : FS.getPath(parent), name); - var mode = FS.getMode(canRead, canWrite); - return FS.create(path, mode); - }, - createDataFile: function(parent, name, data, canRead, canWrite, canOwn) { - var path = name ? PATH.join(typeof parent === 'string' ? parent : FS.getPath(parent), name) : parent; - var mode = FS.getMode(canRead, canWrite); - var node = FS.create(path, mode); - if (data) { - if (typeof data === 'string') { - var arr = new Array(data.length); - for (var i = 0, len = data.length; i < len; ++i) arr[i] = data.charCodeAt(i); - data = arr; - } - // make sure we can write to the file - FS.chmod(path, mode | {{{ cDefine('S_IWUGO') }}}); - var stream = FS.open(path, 'w'); - FS.write(stream, data, 0, data.length, 0, canOwn); - FS.close(stream); - FS.chmod(path, mode); - } - return node; - }, - createDevice: function(parent, name, input, output) { - var path = PATH.join(typeof parent === 'string' ? parent : FS.getPath(parent), name); - var mode = FS.getMode(!!input, !!output); - if (!FS.createDevice.major) FS.createDevice.major = 64; - var dev = FS.makedev(FS.createDevice.major++, 0); - // Create a fake device that a set of stream ops to emulate - // the old behavior. - FS.registerDevice(dev, { - open: function(stream) { - stream.seekable = false; - }, - close: function(stream) { - // flush any pending line data - if (output && output.buffer && output.buffer.length) { - output({{{ charCode('\n') }}}); - } - }, - read: function(stream, buffer, offset, length, pos /* ignored */) { - var bytesRead = 0; - for (var i = 0; i < length; i++) { - var result; - try { - result = input(); - } catch (e) { - throw new FS.ErrnoError(ERRNO_CODES.EIO); - } - if (result === undefined && bytesRead === 0) { - throw new FS.ErrnoError(ERRNO_CODES.EAGAIN); - } - if (result === null || result === undefined) break; - bytesRead++; - buffer[offset+i] = result; - } - if (bytesRead) { - stream.node.timestamp = Date.now(); - } - return bytesRead; - }, - write: function(stream, buffer, offset, length, pos) { - for (var i = 0; i < length; i++) { - try { - output(buffer[offset+i]); - } catch (e) { - throw new FS.ErrnoError(ERRNO_CODES.EIO); - } - } - if (length) { - stream.node.timestamp = Date.now(); - } - return i; - } - }); - return FS.mkdev(path, mode, dev); - }, - createLink: function(parent, name, target, canRead, canWrite) { - var path = PATH.join(typeof parent === 'string' ? parent : FS.getPath(parent), name); - return FS.symlink(target, path); - }, - // Makes sure a file's contents are loaded. Returns whether the file has - // been loaded successfully. No-op for files that have been loaded already. - forceLoadFile: function(obj) { - if (obj.isDevice || obj.isFolder || obj.link || obj.contents) return true; - var success = true; - if (typeof XMLHttpRequest !== 'undefined') { - throw new Error("Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread."); - } else if (Module['read']) { - // Command-line. - try { - // WARNING: Can't read binary files in V8's d8 or tracemonkey's js, as - // read() will try to parse UTF8. - obj.contents = intArrayFromString(Module['read'](obj.url), true); - } catch (e) { - success = false; - } - } else { - throw new Error('Cannot load without read() or XMLHttpRequest.'); - } - if (!success) ___setErrNo(ERRNO_CODES.EIO); - return success; - }, - // Creates a file record for lazy-loading from a URL. XXX This requires a synchronous - // XHR, which is not possible in browsers except in a web worker! Use preloading, - // either --preload-file in emcc or FS.createPreloadedFile - createLazyFile: function(parent, name, url, canRead, canWrite) { - if (typeof XMLHttpRequest !== 'undefined') { - if (!ENVIRONMENT_IS_WORKER) throw 'Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc'; - // Lazy chunked Uint8Array (implements get and length from Uint8Array). Actual getting is abstracted away for eventual reuse. - var LazyUint8Array = function() { - this.lengthKnown = false; - this.chunks = []; // Loaded chunks. Index is the chunk number - } - LazyUint8Array.prototype.get = function(idx) { - if (idx > this.length-1 || idx < 0) { - return undefined; - } - var chunkOffset = idx % this.chunkSize; - var chunkNum = Math.floor(idx / this.chunkSize); - return this.getter(chunkNum)[chunkOffset]; - } - LazyUint8Array.prototype.setDataGetter = function(getter) { - this.getter = getter; - } - LazyUint8Array.prototype.cacheLength = function() { - // Find length - var xhr = new XMLHttpRequest(); - xhr.open('HEAD', url, false); - xhr.send(null); - if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status); - var datalength = Number(xhr.getResponseHeader("Content-length")); - var header; - var hasByteServing = (header = xhr.getResponseHeader("Accept-Ranges")) && header === "bytes"; -#if SMALL_XHR_CHUNKS - var chunkSize = 1024; // Chunk size in bytes -#else - var chunkSize = 1024*1024; // Chunk size in bytes -#endif - - if (!hasByteServing) chunkSize = datalength; - - // Function to get a range from the remote URL. - var doXHR = (function(from, to) { - if (from > to) throw new Error("invalid range (" + from + ", " + to + ") or no bytes requested!"); - if (to > datalength-1) throw new Error("only " + datalength + " bytes available! programmer error!"); - - // TODO: Use mozResponseArrayBuffer, responseStream, etc. if available. - var xhr = new XMLHttpRequest(); - xhr.open('GET', url, false); - if (datalength !== chunkSize) xhr.setRequestHeader("Range", "bytes=" + from + "-" + to); - - // Some hints to the browser that we want binary data. - if (typeof Uint8Array != 'undefined') xhr.responseType = 'arraybuffer'; - if (xhr.overrideMimeType) { - xhr.overrideMimeType('text/plain; charset=x-user-defined'); - } - - xhr.send(null); - if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status); - if (xhr.response !== undefined) { - return new Uint8Array(xhr.response || []); - } else { - return intArrayFromString(xhr.responseText || '', true); |