aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xemlibtool11
-rw-r--r--emlibtool.bat2
-rw-r--r--src/intertyper.js12
-rw-r--r--src/jsifier.js4
-rw-r--r--src/library.js61
-rw-r--r--src/library_fs.js1389
-rw-r--r--system/include/libcxx/__locale12
-rw-r--r--system/include/libcxx/locale2
-rw-r--r--system/lib/libcxx/exception.cpp6
-rw-r--r--system/lib/libcxx/locale.cpp24
-rw-r--r--system/lib/libcxxabi/src/cxa_new_delete.cpp2
-rw-r--r--tests/filesystem/src.js22
-rwxr-xr-xtests/runner.py2
-rw-r--r--tests/test_core.py66
-rw-r--r--tests/unistd/access.c8
-rw-r--r--tests/unistd/access.js4
-rw-r--r--tests/unistd/access.out4
-rw-r--r--tests/unistd/curdir.c11
-rw-r--r--tests/unistd/curdir.js7
-rw-r--r--tests/unistd/io.c50
-rw-r--r--tests/unistd/io.js52
-rw-r--r--tests/unistd/links.c7
-rw-r--r--tests/unistd/links.js3
-rw-r--r--tests/unistd/truncate.c7
-rw-r--r--tests/unistd/truncate.js2
-rw-r--r--tools/js-optimizer.js2
-rw-r--r--tools/shared.py28
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);