RetroArch/emscripten/browserfs.js

11847 lines
440 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

(function() {
/**
* This file installs all of the polyfills that BrowserFS requires.
*/
// IE < 9 does not define this function.
if (!Date.now) {
Date.now = function now() {
return new Date().getTime();
};
}
// IE < 9 does not define this function.
if (!Array.isArray) {
Array.isArray = function (vArg) {
return Object.prototype.toString.call(vArg) === "[object Array]";
};
}
// IE < 9 does not define this function.
// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
if (!Object.keys) {
Object.keys = (function () {
var hasOwnProperty = Object.prototype.hasOwnProperty, hasDontEnumBug = !({ toString: null }).propertyIsEnumerable('toString'), dontEnums = [
'toString',
'toLocaleString',
'valueOf',
'hasOwnProperty',
'isPrototypeOf',
'propertyIsEnumerable',
'constructor'
], dontEnumsLength = dontEnums.length;
return function (obj) {
if (typeof obj !== 'object' && (typeof obj !== 'function' || obj === null)) {
throw new TypeError('Object.keys called on non-object');
}
var result = [], prop, i;
for (prop in obj) {
if (hasOwnProperty.call(obj, prop)) {
result.push(prop);
}
}
if (hasDontEnumBug) {
for (i = 0; i < dontEnumsLength; i++) {
if (hasOwnProperty.call(obj, dontEnums[i])) {
result.push(dontEnums[i]);
}
}
}
return result;
};
}());
}
// IE substr does not support negative indices
if ('ab'.substr(-1) !== 'b') {
String.prototype.substr = function (substr) {
return function (start, length) {
// did we get a negative start, calculate how much it is from the
// beginning of the string
if (start < 0)
start = this.length + start;
// call the original function
return substr.call(this, start, length);
};
}(String.prototype.substr);
}
// IE < 9 does not support forEach
if (!Array.prototype.forEach) {
Array.prototype.forEach = function (fn, scope) {
for (var i = 0; i < this.length; ++i) {
if (i in this) {
fn.call(scope, this[i], i, this);
}
}
};
}
// Only IE10 has setImmediate.
// @todo: Determine viability of switching to the 'proper' polyfill for this.
if (typeof setImmediate === 'undefined') {
// XXX avoid importing the global module.
var gScope = typeof window !== 'undefined' ? window : typeof self !== 'undefined' ? self : global;
var timeouts = [];
var messageName = "zero-timeout-message";
var canUsePostMessage = function () {
if (typeof gScope.importScripts !== 'undefined' || !gScope.postMessage) {
return false;
}
var postMessageIsAsync = true;
var oldOnMessage = gScope.onmessage;
gScope.onmessage = function () {
postMessageIsAsync = false;
};
gScope.postMessage('', '*');
gScope.onmessage = oldOnMessage;
return postMessageIsAsync;
};
if (canUsePostMessage()) {
gScope.setImmediate = function (fn) {
timeouts.push(fn);
gScope.postMessage(messageName, "*");
};
var handleMessage = function (event) {
if (event.source === self && event.data === messageName) {
if (event.stopPropagation) {
event.stopPropagation();
} else {
event.cancelBubble = true;
}
if (timeouts.length > 0) {
var fn = timeouts.shift();
return fn();
}
}
};
if (gScope.addEventListener) {
gScope.addEventListener('message', handleMessage, true);
} else {
gScope.attachEvent('onmessage', handleMessage);
}
} else if (gScope.MessageChannel) {
// WebWorker MessageChannel
var channel = new gScope.MessageChannel();
channel.port1.onmessage = function (event) {
if (timeouts.length > 0) {
return timeouts.shift()();
}
};
gScope.setImmediate = function (fn) {
timeouts.push(fn);
channel.port2.postMessage('');
};
} else {
gScope.setImmediate = function (fn) {
return setTimeout(fn, 0);
var scriptEl = window.document.createElement("script");
scriptEl.onreadystatechange = function () {
fn();
scriptEl.onreadystatechange = null;
scriptEl.parentNode.removeChild(scriptEl);
return scriptEl = null;
};
gScope.document.documentElement.appendChild(scriptEl);
};
}
}
// IE<9 does not define indexOf.
// From: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf
if (!Array.prototype.indexOf) {
Array.prototype.indexOf = function (searchElement, fromIndex) {
if (typeof fromIndex === "undefined") { fromIndex = 0; }
if (!this) {
throw new TypeError();
}
var length = this.length;
if (length === 0 || pivot >= length) {
return -1;
}
var pivot = fromIndex;
if (pivot < 0) {
pivot = length + pivot;
}
for (var i = pivot; i < length; i++) {
if (this[i] === searchElement) {
return i;
}
}
return -1;
};
}
// IE<9 does not support forEach
// From: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
if (!Array.prototype.forEach) {
Array.prototype.forEach = function (fn, scope) {
var i, len;
for (i = 0, len = this.length; i < len; ++i) {
if (i in this) {
fn.call(scope, this[i], i, this);
}
}
};
}
// IE<9 does not support map
// From: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
if (!Array.prototype.map) {
Array.prototype.map = function (callback, thisArg) {
var T, A, k;
if (this == null) {
throw new TypeError(" this is null or not defined");
}
// 1. Let O be the result of calling ToObject passing the |this| value as the argument.
var O = Object(this);
// 2. Let lenValue be the result of calling the Get internal method of O with the argument "length".
// 3. Let len be ToUint32(lenValue).
var len = O.length >>> 0;
// 4. If IsCallable(callback) is false, throw a TypeError exception.
// See: http://es5.github.com/#x9.11
if (typeof callback !== "function") {
throw new TypeError(callback + " is not a function");
}
// 5. If thisArg was supplied, let T be thisArg; else let T be undefined.
if (thisArg) {
T = thisArg;
}
// 6. Let A be a new array created as if by the expression new Array(len) where Array is
// the standard built-in constructor with that name and len is the value of len.
A = new Array(len);
// 7. Let k be 0
k = 0;
while (k < len) {
var kValue, mappedValue;
// a. Let Pk be ToString(k).
// This is implicit for LHS operands of the in operator
// b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk.
// This step can be combined with c
// c. If kPresent is true, then
if (k in O) {
// i. Let kValue be the result of calling the Get internal method of O with argument Pk.
kValue = O[k];
// ii. Let mappedValue be the result of calling the Call internal method of callback
// with T as the this value and argument list containing kValue, k, and O.
mappedValue = callback.call(T, kValue, k, O);
// iii. Call the DefineOwnProperty internal method of A with arguments
// Pk, Property Descriptor {Value: mappedValue, : true, Enumerable: true, Configurable: true},
// and false.
// In browsers that support Object.defineProperty, use the following:
// Object.defineProperty(A, Pk, { value: mappedValue, writable: true, enumerable: true, configurable: true });
// For best browser support, use the following:
A[k] = mappedValue;
}
// d. Increase k by 1.
k++;
}
// 9. return A
return A;
};
}
/**
* IE9 and below only: Injects a VBScript function that converts the
* 'responseBody' attribute of an XMLHttpRequest into a bytestring.
* From: http://miskun.com/javascript/internet-explorer-and-binary-files-data-access/#comment-17
*
* This must be performed *before* the page finishes loading, otherwise
* document.write will refresh the page. :(
*
* This is harmless to inject into non-IE browsers.
*/
if (typeof document !== 'undefined' && window['chrome'] === undefined) {
document.write("<!-- IEBinaryToArray_ByteStr -->\r\n" + "<script type='text/vbscript'>\r\n" + "Function IEBinaryToArray_ByteStr(Binary)\r\n" + " IEBinaryToArray_ByteStr = CStr(Binary)\r\n" + "End Function\r\n" + "Function IEBinaryToArray_ByteStr_Last(Binary)\r\n" + " Dim lastIndex\r\n" + " lastIndex = LenB(Binary)\r\n" + " if lastIndex mod 2 Then\r\n" + " IEBinaryToArray_ByteStr_Last = Chr( AscB( MidB( Binary, lastIndex, 1 ) ) )\r\n" + " Else\r\n" + " IEBinaryToArray_ByteStr_Last = " + '""' + "\r\n" + " End If\r\n" + "End Function\r\n" + "</script>\r\n");
}
//# sourceMappingURL=polyfills.js.map
/**
* @license almond 0.3.0 Copyright (c) 2011-2014, The Dojo Foundation All Rights Reserved.
* Available via the MIT or new BSD license.
* see: http://github.com/jrburke/almond for details
*/
//Going sloppy to avoid 'use strict' string cost, but strict practices should
//be followed.
/*jslint sloppy: true */
/*global setTimeout: false */
var requirejs, require, define;
(function (undef) {
var main, req, makeMap, handlers,
defined = {},
waiting = {},
config = {},
defining = {},
hasOwn = Object.prototype.hasOwnProperty,
aps = [].slice,
jsSuffixRegExp = /\.js$/;
function hasProp(obj, prop) {
return hasOwn.call(obj, prop);
}
/**
* Given a relative module name, like ./something, normalize it to
* a real name that can be mapped to a path.
* @param {String} name the relative name
* @param {String} baseName a real name that the name arg is relative
* to.
* @returns {String} normalized name
*/
function normalize(name, baseName) {
var nameParts, nameSegment, mapValue, foundMap, lastIndex,
foundI, foundStarMap, starI, i, j, part,
baseParts = baseName && baseName.split("/"),
map = config.map,
starMap = (map && map['*']) || {};
//Adjust any relative paths.
if (name && name.charAt(0) === ".") {
//If have a base name, try to normalize against it,
//otherwise, assume it is a top-level require that will
//be relative to baseUrl in the end.
if (baseName) {
//Convert baseName to array, and lop off the last part,
//so that . matches that "directory" and not name of the baseName's
//module. For instance, baseName of "one/two/three", maps to
//"one/two/three.js", but we want the directory, "one/two" for
//this normalization.
baseParts = baseParts.slice(0, baseParts.length - 1);
name = name.split('/');
lastIndex = name.length - 1;
// Node .js allowance:
if (config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex])) {
name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, '');
}
name = baseParts.concat(name);
//start trimDots
for (i = 0; i < name.length; i += 1) {
part = name[i];
if (part === ".") {
name.splice(i, 1);
i -= 1;
} else if (part === "..") {
if (i === 1 && (name[2] === '..' || name[0] === '..')) {
//End of the line. Keep at least one non-dot
//path segment at the front so it can be mapped
//correctly to disk. Otherwise, there is likely
//no path mapping for a path starting with '..'.
//This can still fail, but catches the most reasonable
//uses of ..
break;
} else if (i > 0) {
name.splice(i - 1, 2);
i -= 2;
}
}
}
//end trimDots
name = name.join("/");
} else if (name.indexOf('./') === 0) {
// No baseName, so this is ID is resolved relative
// to baseUrl, pull off the leading dot.
name = name.substring(2);
}
}
//Apply map config if available.
if ((baseParts || starMap) && map) {
nameParts = name.split('/');
for (i = nameParts.length; i > 0; i -= 1) {
nameSegment = nameParts.slice(0, i).join("/");
if (baseParts) {
//Find the longest baseName segment match in the config.
//So, do joins on the biggest to smallest lengths of baseParts.
for (j = baseParts.length; j > 0; j -= 1) {
mapValue = map[baseParts.slice(0, j).join('/')];
//baseName segment has config, find if it has one for
//this name.
if (mapValue) {
mapValue = mapValue[nameSegment];
if (mapValue) {
//Match, update name to the new value.
foundMap = mapValue;
foundI = i;
break;
}
}
}
}
if (foundMap) {
break;
}
//Check for a star map match, but just hold on to it,
//if there is a shorter segment match later in a matching
//config, then favor over this star map.
if (!foundStarMap && starMap && starMap[nameSegment]) {
foundStarMap = starMap[nameSegment];
starI = i;
}
}
if (!foundMap && foundStarMap) {
foundMap = foundStarMap;
foundI = starI;
}
if (foundMap) {
nameParts.splice(0, foundI, foundMap);
name = nameParts.join('/');
}
}
return name;
}
function makeRequire(relName, forceSync) {
return function () {
//A version of a require function that passes a moduleName
//value for items that may need to
//look up paths relative to the moduleName
var args = aps.call(arguments, 0);
//If first arg is not require('string'), and there is only
//one arg, it is the array form without a callback. Insert
//a null so that the following concat is correct.
if (typeof args[0] !== 'string' && args.length === 1) {
args.push(null);
}
return req.apply(undef, args.concat([relName, forceSync]));
};
}
function makeNormalize(relName) {
return function (name) {
return normalize(name, relName);
};
}
function makeLoad(depName) {
return function (value) {
defined[depName] = value;
};
}
function callDep(name) {
if (hasProp(waiting, name)) {
var args = waiting[name];
delete waiting[name];
defining[name] = true;
main.apply(undef, args);
}
if (!hasProp(defined, name) && !hasProp(defining, name)) {
throw new Error('No ' + name);
}
return defined[name];
}
//Turns a plugin!resource to [plugin, resource]
//with the plugin being undefined if the name
//did not have a plugin prefix.
function splitPrefix(name) {
var prefix,
index = name ? name.indexOf('!') : -1;
if (index > -1) {
prefix = name.substring(0, index);
name = name.substring(index + 1, name.length);
}
return [prefix, name];
}
/**
* Makes a name map, normalizing the name, and using a plugin
* for normalization if necessary. Grabs a ref to plugin
* too, as an optimization.
*/
makeMap = function (name, relName) {
var plugin,
parts = splitPrefix(name),
prefix = parts[0];
name = parts[1];
if (prefix) {
prefix = normalize(prefix, relName);
plugin = callDep(prefix);
}
//Normalize according
if (prefix) {
if (plugin && plugin.normalize) {
name = plugin.normalize(name, makeNormalize(relName));
} else {
name = normalize(name, relName);
}
} else {
name = normalize(name, relName);
parts = splitPrefix(name);
prefix = parts[0];
name = parts[1];
if (prefix) {
plugin = callDep(prefix);
}
}
//Using ridiculous property names for space reasons
return {
f: prefix ? prefix + '!' + name : name, //fullName
n: name,
pr: prefix,
p: plugin
};
};
function makeConfig(name) {
return function () {
return (config && config.config && config.config[name]) || {};
};
}
handlers = {
require: function (name) {
return makeRequire(name);
},
exports: function (name) {
var e = defined[name];
if (typeof e !== 'undefined') {
return e;
} else {
return (defined[name] = {});
}
},
module: function (name) {
return {
id: name,
uri: '',
exports: defined[name],
config: makeConfig(name)
};
}
};
main = function (name, deps, callback, relName) {
var cjsModule, depName, ret, map, i,
args = [],
callbackType = typeof callback,
usingExports;
//Use name if no relName
relName = relName || name;
//Call the callback to define the module, if necessary.
if (callbackType === 'undefined' || callbackType === 'function') {
//Pull out the defined dependencies and pass the ordered
//values to the callback.
//Default to [require, exports, module] if no deps
deps = !deps.length && callback.length ? ['require', 'exports', 'module'] : deps;
for (i = 0; i < deps.length; i += 1) {
map = makeMap(deps[i], relName);
depName = map.f;
//Fast path CommonJS standard dependencies.
if (depName === "require") {
args[i] = handlers.require(name);
} else if (depName === "exports") {
//CommonJS module spec 1.1
args[i] = handlers.exports(name);
usingExports = true;
} else if (depName === "module") {
//CommonJS module spec 1.1
cjsModule = args[i] = handlers.module(name);
} else if (hasProp(defined, depName) ||
hasProp(waiting, depName) ||
hasProp(defining, depName)) {
args[i] = callDep(depName);
} else if (map.p) {
map.p.load(map.n, makeRequire(relName, true), makeLoad(depName), {});
args[i] = defined[depName];
} else {
throw new Error(name + ' missing ' + depName);
}
}
ret = callback ? callback.apply(defined[name], args) : undefined;
if (name) {
//If setting exports via "module" is in play,
//favor that over return value and exports. After that,
//favor a non-undefined return value over exports use.
if (cjsModule && cjsModule.exports !== undef &&
cjsModule.exports !== defined[name]) {
defined[name] = cjsModule.exports;
} else if (ret !== undef || !usingExports) {
//Use the return value from the function.
defined[name] = ret;
}
}
} else if (name) {
//May just be an object definition for the module. Only
//worry about defining if have a module name.
defined[name] = callback;
}
};
requirejs = require = req = function (deps, callback, relName, forceSync, alt) {
if (typeof deps === "string") {
if (handlers[deps]) {
//callback in this case is really relName
return handlers[deps](callback);
}
//Just return the module wanted. In this scenario, the
//deps arg is the module name, and second arg (if passed)
//is just the relName.
//Normalize module name, if it contains . or ..
return callDep(makeMap(deps, callback).f);
} else if (!deps.splice) {
//deps is a config object, not an array.
config = deps;
if (config.deps) {
req(config.deps, config.callback);
}
if (!callback) {
return;
}
if (callback.splice) {
//callback is an array, which means it is a dependency list.
//Adjust args if there are dependencies
deps = callback;
callback = relName;
relName = null;
} else {
deps = undef;
}
}
//Support require(['a'])
callback = callback || function () {};
//If relName is a function, it is an errback handler,
//so remove it.
if (typeof relName === 'function') {
relName = forceSync;
forceSync = alt;
}
//Simulate async callback;
if (forceSync) {
main(undef, deps, callback, relName);
} else {
//Using a non-zero value because of concern for what old browsers
//do, and latest browsers "upgrade" to 4 if lower value is used:
//http://www.whatwg.org/specs/web-apps/current-work/multipage/timers.html#dom-windowtimers-settimeout:
//If want a value immediately, use require('id') instead -- something
//that works in almond on the global level, but not guaranteed and
//unlikely to work in other AMD implementations.
setTimeout(function () {
main(undef, deps, callback, relName);
}, 4);
}
return req;
};
/**
* Just drops the config on the floor, but returns req in case
* the config return value is used.
*/
req.config = function (cfg) {
return req(cfg);
};
/**
* Expose module registry for debugging and tooling
*/
requirejs._defined = defined;
define = function (name, deps, callback) {
//This module may not have dependencies
if (!deps.splice) {
//deps is not an array, so probably means
//an object literal or factory function for
//the value. Adjust args.
callback = deps;
deps = [];
}
if (!hasProp(defined, name) && !hasProp(waiting, name)) {
waiting[name] = [name, deps, callback];
}
};
define.amd = {
jQuery: true
};
}());
define("../../vendor/almond/almond", function(){});
/**
* @module core/api_error
*/
define('core/api_error',["require", "exports"], function(require, exports) {
/**
* Standard libc error codes. Add more to this enum and ErrorStrings as they are
* needed.
* @url http://www.gnu.org/software/libc/manual/html_node/Error-Codes.html
*/
(function (ErrorCode) {
ErrorCode[ErrorCode["EPERM"] = 0] = "EPERM";
ErrorCode[ErrorCode["ENOENT"] = 1] = "ENOENT";
ErrorCode[ErrorCode["EIO"] = 2] = "EIO";
ErrorCode[ErrorCode["EBADF"] = 3] = "EBADF";
ErrorCode[ErrorCode["EACCES"] = 4] = "EACCES";
ErrorCode[ErrorCode["EBUSY"] = 5] = "EBUSY";
ErrorCode[ErrorCode["EEXIST"] = 6] = "EEXIST";
ErrorCode[ErrorCode["ENOTDIR"] = 7] = "ENOTDIR";
ErrorCode[ErrorCode["EISDIR"] = 8] = "EISDIR";
ErrorCode[ErrorCode["EINVAL"] = 9] = "EINVAL";
ErrorCode[ErrorCode["EFBIG"] = 10] = "EFBIG";
ErrorCode[ErrorCode["ENOSPC"] = 11] = "ENOSPC";
ErrorCode[ErrorCode["EROFS"] = 12] = "EROFS";
ErrorCode[ErrorCode["ENOTEMPTY"] = 13] = "ENOTEMPTY";
ErrorCode[ErrorCode["ENOTSUP"] = 14] = "ENOTSUP";
})(exports.ErrorCode || (exports.ErrorCode = {}));
var ErrorCode = exports.ErrorCode;
/**
* Strings associated with each error code.
*/
var ErrorStrings = {};
ErrorStrings[0 /* EPERM */] = 'Operation not permitted.';
ErrorStrings[1 /* ENOENT */] = 'No such file or directory.';
ErrorStrings[2 /* EIO */] = 'Input/output error.';
ErrorStrings[3 /* EBADF */] = 'Bad file descriptor.';
ErrorStrings[4 /* EACCES */] = 'Permission denied.';
ErrorStrings[5 /* EBUSY */] = 'Resource busy or locked.';
ErrorStrings[6 /* EEXIST */] = 'File exists.';
ErrorStrings[7 /* ENOTDIR */] = 'File is not a directory.';
ErrorStrings[8 /* EISDIR */] = 'File is a directory.';
ErrorStrings[9 /* EINVAL */] = 'Invalid argument.';
ErrorStrings[10 /* EFBIG */] = 'File is too big.';
ErrorStrings[11 /* ENOSPC */] = 'No space left on disk.';
ErrorStrings[12 /* EROFS */] = 'Cannot modify a read-only file system.';
ErrorStrings[13 /* ENOTEMPTY */] = 'Directory is not empty.';
ErrorStrings[14 /* ENOTSUP */] = 'Operation is not supported.';
/**
* Represents a BrowserFS error. Passed back to applications after a failed
* call to the BrowserFS API.
*/
var ApiError = (function () {
/**
* Represents a BrowserFS error. Passed back to applications after a failed
* call to the BrowserFS API.
*
* Error codes mirror those returned by regular Unix file operations, which is
* what Node returns.
* @constructor ApiError
* @param type The type of the error.
* @param [message] A descriptive error message.
*/
function ApiError(type, message) {
this.type = type;
this.code = ErrorCode[type];
if (message != null) {
this.message = message;
} else {
this.message = ErrorStrings[type];
}
}
/**
* @return A friendly error message.
*/
ApiError.prototype.toString = function () {
return this.code + ": " + ErrorStrings[this.type] + " " + this.message;
};
ApiError.FileError = function (code, p) {
return new ApiError(code, p + ": " + ErrorStrings[code]);
};
ApiError.ENOENT = function (path) {
return this.FileError(1 /* ENOENT */, path);
};
ApiError.EEXIST = function (path) {
return this.FileError(6 /* EEXIST */, path);
};
ApiError.EISDIR = function (path) {
return this.FileError(8 /* EISDIR */, path);
};
ApiError.ENOTDIR = function (path) {
return this.FileError(7 /* ENOTDIR */, path);
};
ApiError.EPERM = function (path) {
return this.FileError(0 /* EPERM */, path);
};
return ApiError;
})();
exports.ApiError = ApiError;
});
//# sourceMappingURL=api_error.js.map
;
define('core/buffer_core',["require", "exports", './api_error'], function(require, exports, api_error) {
var FLOAT_POS_INFINITY = Math.pow(2, 128);
var FLOAT_NEG_INFINITY = -1 * FLOAT_POS_INFINITY;
var FLOAT_POS_INFINITY_AS_INT = 0x7F800000;
var FLOAT_NEG_INFINITY_AS_INT = -8388608;
var FLOAT_NaN_AS_INT = 0x7fc00000;
/**
* Contains common definitions for most of the BufferCore classes.
* Subclasses only need to implement write/readUInt8 for full functionality.
*/
var BufferCoreCommon = (function () {
function BufferCoreCommon() {
}
BufferCoreCommon.prototype.getLength = function () {
throw new api_error.ApiError(14 /* ENOTSUP */, 'BufferCore implementations should implement getLength.');
};
BufferCoreCommon.prototype.writeInt8 = function (i, data) {
// Pack the sign bit as the highest bit.
// Note that we keep the highest bit in the value byte as the sign bit if it
// exists.
this.writeUInt8(i, (data & 0xFF) | ((data & 0x80000000) >>> 24));
};
BufferCoreCommon.prototype.writeInt16LE = function (i, data) {
this.writeUInt8(i, data & 0xFF);
// Pack the sign bit as the highest bit.
// Note that we keep the highest bit in the value byte as the sign bit if it
// exists.
this.writeUInt8(i + 1, ((data >>> 8) & 0xFF) | ((data & 0x80000000) >>> 24));
};
BufferCoreCommon.prototype.writeInt16BE = function (i, data) {
this.writeUInt8(i + 1, data & 0xFF);
// Pack the sign bit as the highest bit.
// Note that we keep the highest bit in the value byte as the sign bit if it
// exists.
this.writeUInt8(i, ((data >>> 8) & 0xFF) | ((data & 0x80000000) >>> 24));
};
BufferCoreCommon.prototype.writeInt32LE = function (i, data) {
this.writeUInt8(i, data & 0xFF);
this.writeUInt8(i + 1, (data >>> 8) & 0xFF);
this.writeUInt8(i + 2, (data >>> 16) & 0xFF);
this.writeUInt8(i + 3, (data >>> 24) & 0xFF);
};
BufferCoreCommon.prototype.writeInt32BE = function (i, data) {
this.writeUInt8(i + 3, data & 0xFF);
this.writeUInt8(i + 2, (data >>> 8) & 0xFF);
this.writeUInt8(i + 1, (data >>> 16) & 0xFF);
this.writeUInt8(i, (data >>> 24) & 0xFF);
};
BufferCoreCommon.prototype.writeUInt8 = function (i, data) {
throw new api_error.ApiError(14 /* ENOTSUP */, 'BufferCore implementations should implement writeUInt8.');
};
BufferCoreCommon.prototype.writeUInt16LE = function (i, data) {
this.writeUInt8(i, data & 0xFF);
this.writeUInt8(i + 1, (data >> 8) & 0xFF);
};
BufferCoreCommon.prototype.writeUInt16BE = function (i, data) {
this.writeUInt8(i + 1, data & 0xFF);
this.writeUInt8(i, (data >> 8) & 0xFF);
};
BufferCoreCommon.prototype.writeUInt32LE = function (i, data) {
this.writeInt32LE(i, data | 0);
};
BufferCoreCommon.prototype.writeUInt32BE = function (i, data) {
this.writeInt32BE(i, data | 0);
};
BufferCoreCommon.prototype.writeFloatLE = function (i, data) {
this.writeInt32LE(i, this.float2intbits(data));
};
BufferCoreCommon.prototype.writeFloatBE = function (i, data) {
this.writeInt32BE(i, this.float2intbits(data));
};
BufferCoreCommon.prototype.writeDoubleLE = function (i, data) {
var doubleBits = this.double2longbits(data);
this.writeInt32LE(i, doubleBits[0]);
this.writeInt32LE(i + 4, doubleBits[1]);
};
BufferCoreCommon.prototype.writeDoubleBE = function (i, data) {
var doubleBits = this.double2longbits(data);
this.writeInt32BE(i + 4, doubleBits[0]);
this.writeInt32BE(i, doubleBits[1]);
};
BufferCoreCommon.prototype.readInt8 = function (i) {
var val = this.readUInt8(i);
if (val & 0x80) {
// Sign bit is set, so perform sign extension.
return val | 0xFFFFFF80;
} else {
return val;
}
};
BufferCoreCommon.prototype.readInt16LE = function (i) {
var val = this.readUInt16LE(i);
if (val & 0x8000) {
// Sign bit is set, so perform sign extension.
return val | 0xFFFF8000;
} else {
return val;
}
};
BufferCoreCommon.prototype.readInt16BE = function (i) {
var val = this.readUInt16BE(i);
if (val & 0x8000) {
// Sign bit is set, so perform sign extension.
return val | 0xFFFF8000;
} else {
return val;
}
};
BufferCoreCommon.prototype.readInt32LE = function (i) {
return this.readUInt32LE(i) | 0;
};
BufferCoreCommon.prototype.readInt32BE = function (i) {
return this.readUInt32BE(i) | 0;
};
BufferCoreCommon.prototype.readUInt8 = function (i) {
throw new api_error.ApiError(14 /* ENOTSUP */, 'BufferCore implementations should implement readUInt8.');
};
BufferCoreCommon.prototype.readUInt16LE = function (i) {
return (this.readUInt8(i + 1) << 8) | this.readUInt8(i);
};
BufferCoreCommon.prototype.readUInt16BE = function (i) {
return (this.readUInt8(i) << 8) | this.readUInt8(i + 1);
};
BufferCoreCommon.prototype.readUInt32LE = function (i) {
return ((this.readUInt8(i + 3) << 24) | (this.readUInt8(i + 2) << 16) | (this.readUInt8(i + 1) << 8) | this.readUInt8(i)) >>> 0;
};
BufferCoreCommon.prototype.readUInt32BE = function (i) {
return ((this.readUInt8(i) << 24) | (this.readUInt8(i + 1) << 16) | (this.readUInt8(i + 2) << 8) | this.readUInt8(i + 3)) >>> 0;
};
BufferCoreCommon.prototype.readFloatLE = function (i) {
return this.intbits2float(this.readInt32LE(i));
};
BufferCoreCommon.prototype.readFloatBE = function (i) {
return this.intbits2float(this.readInt32BE(i));
};
BufferCoreCommon.prototype.readDoubleLE = function (i) {
return this.longbits2double(this.readInt32LE(i + 4), this.readInt32LE(i));
};
BufferCoreCommon.prototype.readDoubleBE = function (i) {
return this.longbits2double(this.readInt32BE(i), this.readInt32BE(i + 4));
};
BufferCoreCommon.prototype.copy = function (start, end) {
throw new api_error.ApiError(14 /* ENOTSUP */, 'BufferCore implementations should implement copy.');
};
BufferCoreCommon.prototype.fill = function (value, start, end) {
for (var i = start; i < end; i++) {
this.writeUInt8(i, value);
}
};
BufferCoreCommon.prototype.float2intbits = function (f_val) {
var exp, f_view, i_view, sig, sign;
// Special cases!
if (f_val === 0) {
return 0;
}
// We map the infinities to JavaScript infinities. Map them back.
if (f_val === Number.POSITIVE_INFINITY) {
return FLOAT_POS_INFINITY_AS_INT;
}
if (f_val === Number.NEGATIVE_INFINITY) {
return FLOAT_NEG_INFINITY_AS_INT;
}
// Convert JavaScript NaN to Float NaN value.
if (isNaN(f_val)) {
return FLOAT_NaN_AS_INT;
}
// We have more bits of precision than a float, so below we round to
// the nearest significand. This appears to be what the x86
// Java does for normal floating point operations.
sign = f_val < 0 ? 1 : 0;
f_val = Math.abs(f_val);
// Subnormal zone!
// (1)^signbits×2^126×0.significandbits
// Largest subnormal magnitude:
// 0000 0000 0111 1111 1111 1111 1111 1111
// Smallest subnormal magnitude:
// 0000 0000 0000 0000 0000 0000 0000 0001
if (f_val <= 1.1754942106924411e-38 && f_val >= 1.4012984643248170e-45) {
exp = 0;
sig = Math.round((f_val / Math.pow(2, -126)) * Math.pow(2, 23));
return (sign << 31) | (exp << 23) | sig;
} else {
// Regular FP numbers
exp = Math.floor(Math.log(f_val) / Math.LN2);
sig = Math.round((f_val / Math.pow(2, exp) - 1) * Math.pow(2, 23));
return (sign << 31) | ((exp + 127) << 23) | sig;
}
};
BufferCoreCommon.prototype.double2longbits = function (d_val) {
var d_view, exp, high_bits, i_view, sig, sign;
// Special cases
if (d_val === 0) {
return [0, 0];
}
if (d_val === Number.POSITIVE_INFINITY) {
// High bits: 0111 1111 1111 0000 0000 0000 0000 0000
// Low bits: 0000 0000 0000 0000 0000 0000 0000 0000
return [0, 2146435072];
} else if (d_val === Number.NEGATIVE_INFINITY) {
// High bits: 1111 1111 1111 0000 0000 0000 0000 0000
// Low bits: 0000 0000 0000 0000 0000 0000 0000 0000
return [0, -1048576];
} else if (isNaN(d_val)) {
// High bits: 0111 1111 1111 1000 0000 0000 0000 0000
// Low bits: 0000 0000 0000 0000 0000 0000 0000 0000
return [0, 2146959360];
}
sign = d_val < 0 ? 1 << 31 : 0;
d_val = Math.abs(d_val);
// Check if it is a subnormal number.
// (-1)s × 0.f × 2-1022
// Largest subnormal magnitude:
// 0000 0000 0000 1111 1111 1111 1111 1111
// 1111 1111 1111 1111 1111 1111 1111 1111
// Smallest subnormal magnitude:
// 0000 0000 0000 0000 0000 0000 0000 0000
// 0000 0000 0000 0000 0000 0000 0000 0001
if (d_val <= 2.2250738585072010e-308 && d_val >= 5.0000000000000000e-324) {
exp = 0;
sig = (d_val / Math.pow(2, -1022)) * Math.pow(2, 52);
} else {
exp = Math.floor(Math.log(d_val) / Math.LN2);
// If d_val is close to a power of two, there's a chance that exp
// will be 1 greater than it should due to loss of accuracy in the
// log result.
if (d_val < Math.pow(2, exp)) {
exp = exp - 1;
}
sig = (d_val / Math.pow(2, exp) - 1) * Math.pow(2, 52);
exp = (exp + 1023) << 20;
}
// Simulate >> 32
high_bits = ((sig * Math.pow(2, -32)) | 0) | sign | exp;
return [sig & 0xFFFF, high_bits];
};
BufferCoreCommon.prototype.intbits2float = function (int32) {
// Map +/- infinity to JavaScript equivalents
if (int32 === FLOAT_POS_INFINITY_AS_INT) {
return Number.POSITIVE_INFINITY;
} else if (int32 === FLOAT_NEG_INFINITY_AS_INT) {
return Number.NEGATIVE_INFINITY;
}
var sign = (int32 & 0x80000000) >>> 31;
var exponent = (int32 & 0x7F800000) >>> 23;
var significand = int32 & 0x007FFFFF;
var value;
if (exponent === 0) {
value = Math.pow(-1, sign) * significand * Math.pow(2, -149);
} else {
value = Math.pow(-1, sign) * (1 + significand * Math.pow(2, -23)) * Math.pow(2, exponent - 127);
}
// NaN check
if (value < FLOAT_NEG_INFINITY || value > FLOAT_POS_INFINITY) {
value = NaN;
}
return value;
};
BufferCoreCommon.prototype.longbits2double = function (uint32_a, uint32_b) {
var sign = (uint32_a & 0x80000000) >>> 31;
var exponent = (uint32_a & 0x7FF00000) >>> 20;
var significand = ((uint32_a & 0x000FFFFF) * Math.pow(2, 32)) + uint32_b;
// Special values!
if (exponent === 0 && significand === 0) {
return 0;
}
if (exponent === 2047) {
if (significand === 0) {
if (sign === 1) {
return Number.NEGATIVE_INFINITY;
}
return Number.POSITIVE_INFINITY;
} else {
return NaN;
}
}
if (exponent === 0)
return Math.pow(-1, sign) * significand * Math.pow(2, -1074);
return Math.pow(-1, sign) * (1 + significand * Math.pow(2, -52)) * Math.pow(2, exponent - 1023);
};
return BufferCoreCommon;
})();
exports.BufferCoreCommon = BufferCoreCommon;
});
//# sourceMappingURL=buffer_core.js.map
;
var __extends = this.__extends || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
define('core/buffer_core_array',["require", "exports", './buffer_core'], function(require, exports, buffer_core) {
// Used to clear segments of an array index.
var clearMasks = [0xFFFFFF00, 0xFFFF00FF, 0xFF00FFFF, 0x00FFFFFF];
/**
* Implementation of BufferCore that is backed by an array of 32-bit ints.
* Data is stored little endian.
* Example: Bytes 0 through 3 are present in the first int:
* BYTE 3 BYTE 2 BYTE 1 BYTE 0
* 0000 0000 | 0000 0000 | 0000 0000 | 0000 0000
*/
var BufferCoreArray = (function (_super) {
__extends(BufferCoreArray, _super);
function BufferCoreArray(length) {
_super.call(this);
this.length = length;
this.buff = new Array(Math.ceil(length / 4));
// Zero-fill the array.
var bufflen = this.buff.length;
for (var i = 0; i < bufflen; i++) {
this.buff[i] = 0;
}
}
BufferCoreArray.isAvailable = function () {
return true;
};
BufferCoreArray.prototype.getLength = function () {
return this.length;
};
BufferCoreArray.prototype.writeUInt8 = function (i, data) {
data &= 0xFF;
// Which int? (Equivalent to (i/4)|0)
var arrIdx = i >> 2;
// Which offset? (Equivalent to i - arrIdx*4)
var intIdx = i & 3;
this.buff[arrIdx] = this.buff[arrIdx] & clearMasks[intIdx];
this.buff[arrIdx] = this.buff[arrIdx] | (data << (intIdx << 3));
};
BufferCoreArray.prototype.readUInt8 = function (i) {
// Which int?
var arrIdx = i >> 2;
// Which offset?
var intIdx = i & 3;
// Bring the data we want into the lowest 8 bits, and truncate.
return (this.buff[arrIdx] >> (intIdx << 3)) & 0xFF;
};
BufferCoreArray.prototype.copy = function (start, end) {
// Stupid unoptimized copy. Later, we could do optimizations when aligned.
var newBC = new BufferCoreArray(end - start);
for (var i = start; i < end; i++) {
newBC.writeUInt8(i - start, this.readUInt8(i));
}
return newBC;
};
return BufferCoreArray;
})(buffer_core.BufferCoreCommon);
exports.BufferCoreArray = BufferCoreArray;
// Type-check the class.
var _ = BufferCoreArray;
});
//# sourceMappingURL=buffer_core_array.js.map
;
var __extends = this.__extends || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
define('core/buffer_core_arraybuffer',["require", "exports", './buffer_core'], function(require, exports, buffer_core) {
/**
* Represents data using an ArrayBuffer.
*/
var BufferCoreArrayBuffer = (function (_super) {
__extends(BufferCoreArrayBuffer, _super);
function BufferCoreArrayBuffer(arg1) {
_super.call(this);
if (typeof arg1 === 'number') {
this.buff = new DataView(new ArrayBuffer(arg1));
} else if (arg1 instanceof DataView) {
this.buff = arg1;
} else {
this.buff = new DataView(arg1);
}
this.length = this.buff.byteLength;
}
BufferCoreArrayBuffer.isAvailable = function () {
return typeof DataView !== 'undefined';
};
BufferCoreArrayBuffer.prototype.getLength = function () {
return this.length;
};
BufferCoreArrayBuffer.prototype.writeInt8 = function (i, data) {
this.buff.setInt8(i, data);
};
BufferCoreArrayBuffer.prototype.writeInt16LE = function (i, data) {
this.buff.setInt16(i, data, true);
};
BufferCoreArrayBuffer.prototype.writeInt16BE = function (i, data) {
this.buff.setInt16(i, data, false);
};
BufferCoreArrayBuffer.prototype.writeInt32LE = function (i, data) {
this.buff.setInt32(i, data, true);
};
BufferCoreArrayBuffer.prototype.writeInt32BE = function (i, data) {
this.buff.setInt32(i, data, false);
};
BufferCoreArrayBuffer.prototype.writeUInt8 = function (i, data) {
this.buff.setUint8(i, data);
};
BufferCoreArrayBuffer.prototype.writeUInt16LE = function (i, data) {
this.buff.setUint16(i, data, true);
};
BufferCoreArrayBuffer.prototype.writeUInt16BE = function (i, data) {
this.buff.setUint16(i, data, false);
};
BufferCoreArrayBuffer.prototype.writeUInt32LE = function (i, data) {
this.buff.setUint32(i, data, true);
};
BufferCoreArrayBuffer.prototype.writeUInt32BE = function (i, data) {
this.buff.setUint32(i, data, false);
};
BufferCoreArrayBuffer.prototype.writeFloatLE = function (i, data) {
this.buff.setFloat32(i, data, true);
};
BufferCoreArrayBuffer.prototype.writeFloatBE = function (i, data) {
this.buff.setFloat32(i, data, false);
};
BufferCoreArrayBuffer.prototype.writeDoubleLE = function (i, data) {
this.buff.setFloat64(i, data, true);
};
BufferCoreArrayBuffer.prototype.writeDoubleBE = function (i, data) {
this.buff.setFloat64(i, data, false);
};
BufferCoreArrayBuffer.prototype.readInt8 = function (i) {
return this.buff.getInt8(i);
};
BufferCoreArrayBuffer.prototype.readInt16LE = function (i) {
return this.buff.getInt16(i, true);
};
BufferCoreArrayBuffer.prototype.readInt16BE = function (i) {
return this.buff.getInt16(i, false);
};
BufferCoreArrayBuffer.prototype.readInt32LE = function (i) {
return this.buff.getInt32(i, true);
};
BufferCoreArrayBuffer.prototype.readInt32BE = function (i) {
return this.buff.getInt32(i, false);
};
BufferCoreArrayBuffer.prototype.readUInt8 = function (i) {
return this.buff.getUint8(i);
};
BufferCoreArrayBuffer.prototype.readUInt16LE = function (i) {
return this.buff.getUint16(i, true);
};
BufferCoreArrayBuffer.prototype.readUInt16BE = function (i) {
return this.buff.getUint16(i, false);
};
BufferCoreArrayBuffer.prototype.readUInt32LE = function (i) {
return this.buff.getUint32(i, true);
};
BufferCoreArrayBuffer.prototype.readUInt32BE = function (i) {
return this.buff.getUint32(i, false);
};
BufferCoreArrayBuffer.prototype.readFloatLE = function (i) {
return this.buff.getFloat32(i, true);
};
BufferCoreArrayBuffer.prototype.readFloatBE = function (i) {
return this.buff.getFloat32(i, false);
};
BufferCoreArrayBuffer.prototype.readDoubleLE = function (i) {
return this.buff.getFloat64(i, true);
};
BufferCoreArrayBuffer.prototype.readDoubleBE = function (i) {
return this.buff.getFloat64(i, false);
};
BufferCoreArrayBuffer.prototype.copy = function (start, end) {
var aBuff = this.buff.buffer;
var newBuff;
// Some ArrayBuffer implementations (IE10) do not have 'slice'.
// XXX: Type hacks - the typings don't have slice either.
if (ArrayBuffer.prototype.slice) {
// ArrayBuffer.slice is copying; exactly what we want.
newBuff = aBuff.slice(start, end);
} else {
var len = end - start;
newBuff = new ArrayBuffer(len);
// Copy the old contents in.
var newUintArray = new Uint8Array(newBuff);
var oldUintArray = new Uint8Array(aBuff);
newUintArray.set(oldUintArray.subarray(start, end));
}
return new BufferCoreArrayBuffer(newBuff);
};
BufferCoreArrayBuffer.prototype.fill = function (value, start, end) {
// Value must be a byte wide.
value = value & 0xFF;
var i;
var len = end - start;
var intBytes = (((len) / 4) | 0) * 4;
// Optimization: Write 4 bytes at a time.
// TODO: Could we copy 8 bytes at a time using Float64, or could we
// lose precision?
var intVal = (value << 24) | (value << 16) | (value << 8) | value;
for (i = 0; i < intBytes; i += 4) {
this.writeInt32LE(i + start, intVal);
}
for (i = intBytes; i < len; i++) {
this.writeUInt8(i + start, value);
}
};
/**
* Custom method for this buffer core. Get the backing object.
*/
BufferCoreArrayBuffer.prototype.getDataView = function () {
return this.buff;
};
return BufferCoreArrayBuffer;
})(buffer_core.BufferCoreCommon);
exports.BufferCoreArrayBuffer = BufferCoreArrayBuffer;
// Type-check the class.
var _ = BufferCoreArrayBuffer;
});
//# sourceMappingURL=buffer_core_arraybuffer.js.map
;
var __extends = this.__extends || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
define('core/buffer_core_imagedata',["require", "exports", './buffer_core'], function(require, exports, buffer_core) {
/**
* Implementation of BufferCore that is backed by an ImageData object.
* Useful in browsers with HTML5 canvas support, but no TypedArray support
* (IE9).
*/
var BufferCoreImageData = (function (_super) {
__extends(BufferCoreImageData, _super);
function BufferCoreImageData(length) {
_super.call(this);
this.length = length;
this.buff = BufferCoreImageData.getCanvasPixelArray(length);
}
/**
* Constructs a CanvasPixelArray that represents the given amount of bytes.
*/
BufferCoreImageData.getCanvasPixelArray = function (bytes) {
var ctx = BufferCoreImageData.imageDataFactory;
// Lazily initialize, otherwise every browser (even those that will never
// use this code) will create a canvas on script load.
if (ctx === undefined) {
BufferCoreImageData.imageDataFactory = ctx = document.createElement('canvas').getContext('2d');
}
// You cannot create image data with size 0, so up it to size 1.
if (bytes === 0)
bytes = 1;
return ctx.createImageData(Math.ceil(bytes / 4), 1).data;
};
BufferCoreImageData.isAvailable = function () {
// Modern browsers have removed this deprecated API, so it is not always around.
return typeof CanvasPixelArray !== 'undefined';
};
BufferCoreImageData.prototype.getLength = function () {
return this.length;
};
BufferCoreImageData.prototype.writeUInt8 = function (i, data) {
this.buff[i] = data;
};
BufferCoreImageData.prototype.readUInt8 = function (i) {
return this.buff[i];
};
BufferCoreImageData.prototype.copy = function (start, end) {
// AFAIK, there's no efficient way to clone ImageData.
var newBC = new BufferCoreImageData(end - start);
for (var i = start; i < end; i++) {
newBC.writeUInt8(i - start, this.buff[i]);
}
return newBC;
};
return BufferCoreImageData;
})(buffer_core.BufferCoreCommon);
exports.BufferCoreImageData = BufferCoreImageData;
// Type-check the class.
var _ = BufferCoreImageData;
});
//# sourceMappingURL=buffer_core_imagedata.js.map
;
define('core/string_util',["require", "exports"], function(require, exports) {
/**
* Find the 'utility' object for the given string encoding. Throws an exception
* if the encoding is invalid.
* @param [String] encoding a string encoding
* @return [BrowserFS.StringUtil.*] The StringUtil object for the given encoding
*/
function FindUtil(encoding) {
encoding = (function () {
switch (typeof encoding) {
case 'object':
return "" + encoding;
case 'string':
return encoding;
default:
throw new Error('Invalid encoding argument specified');
}
})();
encoding = encoding.toLowerCase();
switch (encoding) {
case 'utf8':
case 'utf-8':
return UTF8;
case 'ascii':
return ASCII;
case 'binary':
return BINARY;
case 'ucs2':
case 'ucs-2':
case 'utf16le':
case 'utf-16le':
return UCS2;
case 'hex':
return HEX;
case 'base64':
return BASE64;
case 'binary_string':
return BINSTR;
case 'binary_string_ie':
return BINSTRIE;
case 'extended_ascii':
return ExtendedASCII;
default:
throw new Error("Unknown encoding: " + encoding);
}
}
exports.FindUtil = FindUtil;
/**
* String utility functions for UTF-8. Note that some UTF-8 strings *cannot* be
* expressed in terms of JavaScript UTF-16 strings.
* @see http://en.wikipedia.org/wiki/UTF-8
*/
var UTF8 = (function () {
function UTF8() {
}
UTF8.str2byte = function (str, buf) {
var length = buf.length;
var i = 0;
var j = 0;
var maxJ = length;
var rv = [];
var numChars = 0;
while (i < str.length && j < maxJ) {
var code = str.charCodeAt(i++);
var next = str.charCodeAt(i);
if (0xD800 <= code && code <= 0xDBFF && 0xDC00 <= next && next <= 0xDFFF) {
// 4 bytes: Surrogate pairs! UTF-16 fun time.
if (j + 3 >= maxJ) {
break;
} else {
numChars++;
}
// First pair: 10 bits of data, with an implicitly set 11th bit
// Second pair: 10 bits of data
var codePoint = (((code & 0x3FF) | 0x400) << 10) | (next & 0x3FF);
// Highest 3 bits in first byte
buf.writeUInt8((codePoint >> 18) | 0xF0, j++);
// Rest are all 6 bits
buf.writeUInt8(((codePoint >> 12) & 0x3F) | 0x80, j++);
buf.writeUInt8(((codePoint >> 6) & 0x3F) | 0x80, j++);
buf.writeUInt8((codePoint & 0x3F) | 0x80, j++);
i++;
} else if (code < 0x80) {
// One byte
buf.writeUInt8(code, j++);
numChars++;
} else if (code < 0x800) {
// Two bytes
if (j + 1 >= maxJ) {
break;
} else {
numChars++;
}
// Highest 5 bits in first byte
buf.writeUInt8((code >> 6) | 0xC0, j++);
// Lower 6 bits in second byte
buf.writeUInt8((code & 0x3F) | 0x80, j++);
} else if (code < 0x10000) {
// Three bytes
if (j + 2 >= maxJ) {
break;
} else {
numChars++;
}
// Highest 4 bits in first byte
buf.writeUInt8((code >> 12) | 0xE0, j++);
// Middle 6 bits in second byte
buf.writeUInt8(((code >> 6) & 0x3F) | 0x80, j++);
// Lowest 6 bits in third byte
buf.writeUInt8((code & 0x3F) | 0x80, j++);
}
}
return j;
};
UTF8.byte2str = function (buff) {
var chars = [];
var i = 0;
while (i < buff.length) {
var code = buff.readUInt8(i++);
if (code < 0x80) {
chars.push(String.fromCharCode(code));
} else if (code < 0xC0) {
throw new Error('Found incomplete part of character in string.');
} else if (code < 0xE0) {
// 2 bytes: 5 and 6 bits
chars.push(String.fromCharCode(((code & 0x1F) << 6) | (buff.readUInt8(i++) & 0x3F)));
} else if (code < 0xF0) {
// 3 bytes: 4, 6, and 6 bits
chars.push(String.fromCharCode(((code & 0xF) << 12) | ((buff.readUInt8(i++) & 0x3F) << 6) | (buff.readUInt8(i++) & 0x3F)));
} else if (code < 0xF8) {
// 4 bytes: 3, 6, 6, 6 bits; surrogate pairs time!
// First 11 bits; remove 11th bit as per UTF-16 standard
var byte3 = buff.readUInt8(i + 2);
chars.push(String.fromCharCode(((((code & 0x7) << 8) | ((buff.readUInt8(i++) & 0x3F) << 2) | ((buff.readUInt8(i++) & 0x3F) >> 4)) & 0x3FF) | 0xD800));
// Final 10 bits
chars.push(String.fromCharCode((((byte3 & 0xF) << 6) | (buff.readUInt8(i++) & 0x3F)) | 0xDC00));
} else {
throw new Error('Unable to represent UTF-8 string as UTF-16 JavaScript string.');
}
}
return chars.join('');
};
UTF8.byteLength = function (str) {
// Matches only the 10.. bytes that are non-initial characters in a
// multi-byte sequence.
// @todo This may be slower than iterating through the string in some cases.
var m = encodeURIComponent(str).match(/%[89ABab]/g);
return str.length + (m ? m.length : 0);
};
return UTF8;
})();
exports.UTF8 = UTF8;
/**
* String utility functions for 8-bit ASCII. Like Node, we mask the high bits of
* characters in JavaScript UTF-16 strings.
* @see http://en.wikipedia.org/wiki/ASCII
*/
var ASCII = (function () {
function ASCII() {
}
ASCII.str2byte = function (str, buf) {
var length = str.length > buf.length ? buf.length : str.length;
for (var i = 0; i < length; i++) {
buf.writeUInt8(str.charCodeAt(i) % 256, i);
}
return length;
};
ASCII.byte2str = function (buff) {
var chars = new Array(buff.length);
for (var i = 0; i < buff.length; i++) {
chars[i] = String.fromCharCode(buff.readUInt8(i) & 0x7F);
}
return chars.join('');
};
ASCII.byteLength = function (str) {
return str.length;
};
return ASCII;
})();
exports.ASCII = ASCII;
/**
* (Nonstandard) String utility function for 8-bit ASCII with the extended
* character set. Unlike the ASCII above, we do not mask the high bits.
* @see http://en.wikipedia.org/wiki/Extended_ASCII
*/
var ExtendedASCII = (function () {
function ExtendedASCII() {
}
ExtendedASCII.str2byte = function (str, buf) {
var length = str.length > buf.length ? buf.length : str.length;
for (var i = 0; i < length; i++) {
var charCode = str.charCodeAt(i);
if (charCode > 0x7F) {
// Check if extended ASCII.
var charIdx = ExtendedASCII.extendedChars.indexOf(str.charAt(i));
if (charIdx > -1) {
charCode = charIdx + 0x80;
}
// Otherwise, keep it as-is.
}
buf.writeUInt8(charCode, i);
}
return length;
};
ExtendedASCII.byte2str = function (buff) {
var chars = new Array(buff.length);
for (var i = 0; i < buff.length; i++) {
var charCode = buff.readUInt8(i);
if (charCode > 0x7F) {
chars[i] = ExtendedASCII.extendedChars[charCode - 128];
} else {
chars[i] = String.fromCharCode(charCode);
}
}
return chars.join('');
};
ExtendedASCII.byteLength = function (str) {
return str.length;
};
ExtendedASCII.extendedChars = [
'\u00C7', '\u00FC', '\u00E9', '\u00E2', '\u00E4',
'\u00E0', '\u00E5', '\u00E7', '\u00EA', '\u00EB', '\u00E8', '\u00EF',
'\u00EE', '\u00EC', '\u00C4', '\u00C5', '\u00C9', '\u00E6', '\u00C6',
'\u00F4', '\u00F6', '\u00F2', '\u00FB', '\u00F9', '\u00FF', '\u00D6',
'\u00DC', '\u00F8', '\u00A3', '\u00D8', '\u00D7', '\u0192', '\u00E1',
'\u00ED', '\u00F3', '\u00FA', '\u00F1', '\u00D1', '\u00AA', '\u00BA',
'\u00BF', '\u00AE', '\u00AC', '\u00BD', '\u00BC', '\u00A1', '\u00AB',
'\u00BB', '_', '_', '_', '\u00A6', '\u00A6', '\u00C1', '\u00C2', '\u00C0',
'\u00A9', '\u00A6', '\u00A6', '+', '+', '\u00A2', '\u00A5', '+', '+', '-',
'-', '+', '-', '+', '\u00E3', '\u00C3', '+', '+', '-', '-', '\u00A6', '-',
'+', '\u00A4', '\u00F0', '\u00D0', '\u00CA', '\u00CB', '\u00C8', 'i',
'\u00CD', '\u00CE', '\u00CF', '+', '+', '_', '_', '\u00A6', '\u00CC', '_',
'\u00D3', '\u00DF', '\u00D4', '\u00D2', '\u00F5', '\u00D5', '\u00B5',
'\u00FE', '\u00DE', '\u00DA', '\u00DB', '\u00D9', '\u00FD', '\u00DD',
'\u00AF', '\u00B4', '\u00AD', '\u00B1', '_', '\u00BE', '\u00B6', '\u00A7',
'\u00F7', '\u00B8', '\u00B0', '\u00A8', '\u00B7', '\u00B9', '\u00B3',
'\u00B2', '_', ' '];
return ExtendedASCII;
})();
exports.ExtendedASCII = ExtendedASCII;
/**
* String utility functions for Node's BINARY strings, which represent a single
* byte per character.
*/
var BINARY = (function () {
function BINARY() {
}
BINARY.str2byte = function (str, buf) {
var length = str.length > buf.length ? buf.length : str.length;
for (var i = 0; i < length; i++) {
buf.writeUInt8(str.charCodeAt(i) & 0xFF, i);
}
return length;
};
BINARY.byte2str = function (buff) {
var chars = new Array(buff.length);
for (var i = 0; i < buff.length; i++) {
chars[i] = String.fromCharCode(buff.readUInt8(i) & 0xFF);
}
return chars.join('');
};
BINARY.byteLength = function (str) {
return str.length;
};
return BINARY;
})();
exports.BINARY = BINARY;
/**
* Contains string utility functions for base-64 encoding.
*
* Adapted from the StackOverflow comment linked below.
* @see http://stackoverflow.com/questions/246801/how-can-you-encode-to-base64-using-javascript#246813
* @see http://en.wikipedia.org/wiki/Base64
* @todo Bake in support for btoa() and atob() if available.
*/
var BASE64 = (function () {
function BASE64() {
}
BASE64.byte2str = function (buff) {
var output = '';
var i = 0;
while (i < buff.length) {
var chr1 = buff.readUInt8(i++);
var chr2 = i < buff.length ? buff.readUInt8(i++) : NaN;
var chr3 = i < buff.length ? buff.readUInt8(i++) : NaN;
var enc1 = chr1 >> 2;
var enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
var enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
var enc4 = chr3 & 63;
if (isNaN(chr2)) {
enc3 = enc4 = 64;
} else if (isNaN(chr3)) {
enc4 = 64;
}
output = output + BASE64.num2b64[enc1] + BASE64.num2b64[enc2] + BASE64.num2b64[enc3] + BASE64.num2b64[enc4];
}
return output;
};
BASE64.str2byte = function (str, buf) {
var length = buf.length;
var output = '';
var i = 0;
str = str.replace(/[^A-Za-z0-9\+\/\=\-\_]/g, '');
var j = 0;
while (i < str.length) {
var enc1 = BASE64.b642num[str.charAt(i++)];
var enc2 = BASE64.b642num[str.charAt(i++)];
var enc3 = BASE64.b642num[str.charAt(i++)];
var enc4 = BASE64.b642num[str.charAt(i++)];
var chr1 = (enc1 << 2) | (enc2 >> 4);
var chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
var chr3 = ((enc3 & 3) << 6) | enc4;
buf.writeUInt8(chr1, j++);
if (j === length) {
break;
}
if (enc3 !== 64) {
output += buf.writeUInt8(chr2, j++);
}
if (j === length) {
break;
}
if (enc4 !== 64) {
output += buf.writeUInt8(chr3, j++);
}
if (j === length) {
break;
}
}
return j;
};
BASE64.byteLength = function (str) {
return Math.floor(((str.replace(/[^A-Za-z0-9\+\/\-\_]/g, '')).length * 6) / 8);
};
BASE64.b64chars = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', '='];
BASE64.num2b64 = (function () {
var obj = new Array(BASE64.b64chars.length);
for (var idx = 0; idx < BASE64.b64chars.length; idx++) {
var i = BASE64.b64chars[idx];
obj[idx] = i;
}
return obj;
})();
BASE64.b642num = (function () {
var obj = {};
for (var idx = 0; idx < BASE64.b64chars.length; idx++) {
var i = BASE64.b64chars[idx];
obj[i] = idx;
}
obj['-'] = 62;
obj['_'] = 63;
return obj;
})();
return BASE64;
})();
exports.BASE64 = BASE64;
/**
* String utility functions for the UCS-2 encoding. Note that our UCS-2 handling
* is identical to our UTF-16 handling.
*
* Note: UCS-2 handling is identical to UTF-16.
* @see http://en.wikipedia.org/wiki/UCS2
*/
var UCS2 = (function () {
function UCS2() {
}
UCS2.str2byte = function (str, buf) {
var len = str.length;
// Clip length to longest string of valid characters that can fit in the
// byte range.
if (len * 2 > buf.length) {
len = buf.length % 2 === 1 ? (buf.length - 1) / 2 : buf.length / 2;
}
for (var i = 0; i < len; i++) {
buf.writeUInt16LE(str.charCodeAt(i), i * 2);
}
return len * 2;
};
UCS2.byte2str = function (buff) {
if (buff.length % 2 !== 0) {
throw new Error('Invalid UCS2 byte array.');
}
var chars = new Array(buff.length / 2);
for (var i = 0; i < buff.length; i += 2) {
chars[i / 2] = String.fromCharCode(buff.readUInt8(i) | (buff.readUInt8(i + 1) << 8));
}
return chars.join('');
};
UCS2.byteLength = function (str) {
return str.length * 2;
};
return UCS2;
})();
exports.UCS2 = UCS2;
/**
* Contains string utility functions for hex encoding.
* @see http://en.wikipedia.org/wiki/Hexadecimal
*/
var HEX = (function () {
function HEX() {
}
HEX.str2byte = function (str, buf) {
if (str.length % 2 === 1) {
throw new Error('Invalid hex string');
}
// Each character is 1 byte encoded as two hex characters; so 1 byte becomes
// 2 bytes.
var numBytes = str.length >> 1;
if (numBytes > buf.length) {
numBytes = buf.length;
}
for (var i = 0; i < numBytes; i++) {
var char1 = this.hex2num[str.charAt(i << 1)];
var char2 = this.hex2num[str.charAt((i << 1) + 1)];
buf.writeUInt8((char1 << 4) | char2, i);
}
return numBytes;
};
HEX.byte2str = function (buff) {
var len = buff.length;
var chars = new Array(len << 1);
var j = 0;
for (var i = 0; i < len; i++) {
var hex2 = buff.readUInt8(i) & 0xF;
var hex1 = buff.readUInt8(i) >> 4;
chars[j++] = this.num2hex[hex1];
chars[j++] = this.num2hex[hex2];
}
return chars.join('');
};
HEX.byteLength = function (str) {
// Assuming a valid string.
return str.length >> 1;
};
HEX.HEXCHARS = '0123456789abcdef';
HEX.num2hex = (function () {
var obj = new Array(HEX.HEXCHARS.length);
for (var idx = 0; idx < HEX.HEXCHARS.length; idx++) {
var i = HEX.HEXCHARS[idx];
obj[idx] = i;
}
return obj;
})();
HEX.hex2num = (function () {
var idx, i;
var obj = {};
for (idx = 0; idx < HEX.HEXCHARS.length; idx++) {
i = HEX.HEXCHARS[idx];
obj[i] = idx;
}
var capitals = 'ABCDEF';
for (idx = 0; idx < capitals.length; idx++) {
i = capitals[idx];
obj[i] = idx + 10;
}
return obj;
})();
return HEX;
})();
exports.HEX = HEX;
/**
* Contains string utility functions for binary string encoding. This is where we
* pack arbitrary binary data as a UTF-16 string.
*
* Each character in the string is two bytes. The first character in the string
* is special: The first byte specifies if the binary data is of odd byte length.
* If it is, then it is a 1 and the second byte is the first byte of data; if
* not, it is a 0 and the second byte is 0.
*
* Everything is little endian.
*/
var BINSTR = (function () {
function BINSTR() {
}
BINSTR.str2byte = function (str, buf) {
// Special case: Empty string
if (str.length === 0) {
return 0;
}
var numBytes = BINSTR.byteLength(str);
if (numBytes > buf.length) {
numBytes = buf.length;
}
var j = 0;
var startByte = 0;
var endByte = startByte + numBytes;
// Handle first character separately
var firstChar = str.charCodeAt(j++);
if (firstChar !== 0) {
buf.writeUInt8(firstChar & 0xFF, 0);
startByte = 1;
}
for (var i = startByte; i < endByte; i += 2) {
var chr = str.charCodeAt(j++);
if (endByte - i === 1) {
// Write first byte of character
buf.writeUInt8(chr >> 8, i);
}
if (endByte - i >= 2) {
// Write both bytes in character
buf.writeUInt16BE(chr, i);
}
}
return numBytes;
};
BINSTR.byte2str = function (buff) {
var len = buff.length;
// Special case: Empty string
if (len === 0) {
return '';
}
var chars = new Array((len >> 1) + 1);
var j = 0;
for (var i = 0; i < chars.length; i++) {
if (i === 0) {
if (len % 2 === 1) {
chars[i] = String.fromCharCode((1 << 8) | buff.readUInt8(j++));
} else {
chars[i] = String.fromCharCode(0);
}
} else {
chars[i] = String.fromCharCode((buff.readUInt8(j++) << 8) | buff.readUInt8(j++));
}
}
return chars.join('');
};
BINSTR.byteLength = function (str) {
if (str.length === 0) {
// Special case: Empty string.
return 0;
}
var firstChar = str.charCodeAt(0);
var bytelen = (str.length - 1) << 1;
if (firstChar !== 0) {
bytelen++;
}
return bytelen;
};
return BINSTR;
})();
exports.BINSTR = BINSTR;
/**
* IE/older FF version of binary string. One byte per character, offset by 0x20.
*/
var BINSTRIE = (function () {
function BINSTRIE() {
}
BINSTRIE.str2byte = function (str, buf) {
var length = str.length > buf.length ? buf.length : str.length;
for (var i = 0; i < length; i++) {
buf.writeUInt8(str.charCodeAt(i) - 0x20, i);
}
return length;
};
BINSTRIE.byte2str = function (buff) {
var chars = new Array(buff.length);
for (var i = 0; i < buff.length; i++) {
chars[i] = String.fromCharCode(buff.readUInt8(i) + 0x20);
}
return chars.join('');
};
BINSTRIE.byteLength = function (str) {
return str.length;
};
return BINSTRIE;
})();
exports.BINSTRIE = BINSTRIE;
});
//# sourceMappingURL=string_util.js.map
;
define('core/buffer',["require", "exports", './buffer_core', './buffer_core_array', './buffer_core_arraybuffer', './buffer_core_imagedata', './string_util'], function(require, exports, buffer_core, buffer_core_array, buffer_core_arraybuffer, buffer_core_imagedata, string_util) {
// BC implementations earlier in the array are preferred.
var BufferCorePreferences = [
buffer_core_arraybuffer.BufferCoreArrayBuffer,
buffer_core_imagedata.BufferCoreImageData,
buffer_core_array.BufferCoreArray
];
var PreferredBufferCore = (function () {
var i, bci;
for (i = 0; i < BufferCorePreferences.length; i++) {
bci = BufferCorePreferences[i];
if (bci.isAvailable())
return bci;
}
throw new Error("This browser does not support any available BufferCore implementations.");
})();
/**
* Emulates Node's Buffer API. Wraps a BufferCore object that is responsible
* for actually writing/reading data from some data representation in memory.
*/
var Buffer = (function () {
function Buffer(arg1, arg2, arg3) {
if (typeof arg2 === "undefined") { arg2 = 'utf8'; }
this.offset = 0;
var i;
// Node apparently allows you to construct buffers w/o 'new'.
if (!(this instanceof Buffer)) {
return new Buffer(arg1, arg2);
}
if (arg1 instanceof buffer_core.BufferCoreCommon) {
// constructor (data: buffer_core.BufferCore, start?: number, end?: number)
this.data = arg1;
var start = typeof arg2 === 'number' ? arg2 : 0;
var end = typeof arg3 === 'number' ? arg3 : this.data.getLength();
this.offset = start;
this.length = end - start;
} else if (typeof arg1 === 'number') {
// constructor (size: number);
if (arg1 !== (arg1 >>> 0)) {
throw new TypeError('Buffer size must be a uint32.');
}
this.length = arg1;
this.data = new PreferredBufferCore(arg1);
} else if (typeof DataView !== 'undefined' && arg1 instanceof DataView) {
// constructor (data: DataView);
this.data = new buffer_core_arraybuffer.BufferCoreArrayBuffer(arg1);
this.length = arg1.byteLength;
} else if (typeof ArrayBuffer !== 'undefined' && arg1 instanceof ArrayBuffer) {
// constructor (data: ArrayBuffer);
this.data = new buffer_core_arraybuffer.BufferCoreArrayBuffer(arg1);
this.length = arg1.byteLength;
} else if (arg1 instanceof Buffer) {
// constructor (data: Buffer);
var argBuff = arg1;
this.data = new PreferredBufferCore(arg1.length);
this.length = arg1.length;
argBuff.copy(this);
} else if (Array.isArray(arg1) || (arg1 != null && typeof arg1 === 'object' && typeof arg1[0] === 'number')) {
// constructor (data: number[]);
this.data = new PreferredBufferCore(arg1.length);
for (i = 0; i < arg1.length; i++) {
this.data.writeUInt8(i, arg1[i]);
}
this.length = arg1.length;
} else if (typeof arg1 === 'string') {
// constructor (data: string, encoding?: string);
this.length = Buffer.byteLength(arg1, arg2);
this.data = new PreferredBufferCore(this.length);
this.write(arg1, 0, this.length, arg2);
} else {
throw new Error("Invalid argument to Buffer constructor: " + arg1);
}
}
Buffer.prototype.getBufferCore = function () {
return this.data;
};
Buffer.prototype.getOffset = function () {
return this.offset;
};
/**
* **NONSTANDARD**: Set the octet at index. Emulates NodeJS buffer's index
* operation. Octet can be signed or unsigned.
* @param {number} index - the index to set the value at
* @param {number} value - the value to set at the given index
*/
Buffer.prototype.set = function (index, value) {
// In Node, the following happens:
// buffer[0] = -1;
// buffer[0]; // 255
if (value < 0) {
return this.writeInt8(value, index);
} else {
return this.writeUInt8(value, index);
}
};
/**
* **NONSTANDARD**: Get the octet at index.
* @param {number} index - index to fetch the value at
* @return {number} the value at the given index
*/
Buffer.prototype.get = function (index) {
return this.readUInt8(index);
};
/**
* Writes string to the buffer at offset using the given encoding.
* If buffer did not contain enough space to fit the entire string, it will
* write a partial amount of the string.
* @param {string} str - Data to be written to buffer
* @param {number} [offset=0] - Offset in the buffer to write to
* @param {number} [length=this.length] - Number of bytes to write
* @param {string} [encoding=utf8] - Character encoding
* @return {number} Number of octets written.
*/
Buffer.prototype.write = function (str, offset, length, encoding) {
if (typeof offset === "undefined") { offset = 0; }
if (typeof length === "undefined") { length = this.length; }
if (typeof encoding === "undefined") { encoding = 'utf8'; }
// I hate Node's optional arguments.
if (typeof offset === 'string') {
// 'str' and 'encoding' specified
encoding = "" + offset;
offset = 0;
length = this.length;
} else if (typeof length === 'string') {
// 'str', 'offset', and 'encoding' specified
encoding = "" + length;
length = this.length;
}
// Don't waste our time if the offset is beyond the buffer length
if (offset >= this.length) {
return 0;
}
var strUtil = string_util.FindUtil(encoding);
// Are we trying to write past the buffer?
length = length + offset > this.length ? this.length - offset : length;
offset += this.offset;
return strUtil.str2byte(str, offset === 0 && length === this.length ? this : new Buffer(this.data, offset, length + offset));
};
/**
* Decodes a portion of the Buffer into a String.
* @param {string} encoding - Character encoding to decode to
* @param {number} [start=0] - Start position in the buffer
* @param {number} [end=this.length] - Ending position in the buffer
* @return {string} A string from buffer data encoded with encoding, beginning
* at start, and ending at end.
*/
Buffer.prototype.toString = function (encoding, start, end) {
if (typeof encoding === "undefined") { encoding = 'utf8'; }
if (typeof start === "undefined") { start = 0; }
if (typeof end === "undefined") { end = this.length; }
if (!(start <= end)) {
throw new Error("Invalid start/end positions: " + start + " - " + end);
}
if (start === end) {
return '';
}
if (end > this.length) {
end = this.length;
}
var strUtil = string_util.FindUtil(encoding);
// Get the string representation of the given slice. Create a new buffer
// if need be.
return strUtil.byte2str(start === 0 && end === this.length ? this : new Buffer(this.data, start + this.offset, end + this.offset));
};
/**
* Returns a JSON-representation of the Buffer instance, which is identical to
* the output for JSON Arrays. JSON.stringify implicitly calls this function
* when stringifying a Buffer instance.
* @return {object} An object that can be used for JSON stringification.
*/
Buffer.prototype.toJSON = function () {
// Construct a byte array for the JSON 'data'.
var len = this.length;
var byteArr = new Array(len);
for (var i = 0; i < len; i++) {
byteArr[i] = this.readUInt8(i);
}
return {
type: 'Buffer',
data: byteArr
};
};
/**
* Does copy between buffers. The source and target regions can be overlapped.
* All values passed that are undefined/NaN or are out of bounds are set equal
* to their respective defaults.
* @param {Buffer} target - Buffer to copy into
* @param {number} [targetStart=0] - Index to start copying to in the targetBuffer
* @param {number} [sourceStart=0] - Index in this buffer to start copying from
* @param {number} [sourceEnd=this.length] - Index in this buffer stop copying at
* @return {number} The number of bytes copied into the target buffer.
*/
Buffer.prototype.copy = function (target, targetStart, sourceStart, sourceEnd) {
if (typeof targetStart === "undefined") { targetStart = 0; }
if (typeof sourceStart === "undefined") { sourceStart = 0; }
if (typeof sourceEnd === "undefined") { sourceEnd = this.length; }
// The Node code is weird. It sets some out-of-bounds args to their defaults
// and throws exceptions for others (sourceEnd).
targetStart = targetStart < 0 ? 0 : targetStart;
sourceStart = sourceStart < 0 ? 0 : sourceStart;
// Need to sanity check all of the input. Node has really odd rules regarding
// when to apply default arguments. I decided to copy Node's logic.
if (sourceEnd < sourceStart) {
throw new RangeError('sourceEnd < sourceStart');
}
if (sourceEnd === sourceStart) {
return 0;
}
if (targetStart >= target.length) {
throw new RangeError('targetStart out of bounds');
}
if (sourceStart >= this.length) {
throw new RangeError('sourceStart out of bounds');
}
if (sourceEnd > this.length) {
throw new RangeError('sourceEnd out of bounds');
}
var bytesCopied = Math.min(sourceEnd - sourceStart, target.length - targetStart, this.length - sourceStart);
for (var i = 0; i < bytesCopied; i++) {
target.writeUInt8(this.readUInt8(sourceStart + i), targetStart + i);
}
return bytesCopied;
};
/**
* Returns a slice of this buffer.
* @param {number} [start=0] - Index to start slicing from
* @param {number} [end=this.length] - Index to stop slicing at
* @return {Buffer} A new buffer which references the same
* memory as the old, but offset and cropped by the start (defaults to 0) and
* end (defaults to buffer.length) indexes. Negative indexes start from the end
* of the buffer.
*/
Buffer.prototype.slice = function (start, end) {
if (typeof start === "undefined") { start = 0; }
if (typeof end === "undefined") { end = this.length; }
// Translate negative indices to positive ones.
if (start < 0) {
start += this.length;
if (start < 0) {
start = 0;
}
}
if (end < 0) {
end += this.length;
if (end < 0) {
end = 0;
}
}
if (end > this.length) {
end = this.length;
}
if (start > end) {
start = end;
}
// Sanity check.
if (start < 0 || end < 0 || start >= this.length || end > this.length) {
throw new Error("Invalid slice indices.");
}
// Create a new buffer backed by the same BufferCore.
return new Buffer(this.data, start + this.offset, end + this.offset);
};
/**
* [NONSTANDARD] A copy-based version of Buffer.slice.
*/
Buffer.prototype.sliceCopy = function (start, end) {
if (typeof start === "undefined") { start = 0; }
if (typeof end === "undefined") { end = this.length; }
// Translate negative indices to positive ones.
if (start < 0) {
start += this.length;
if (start < 0) {
start = 0;
}
}
if (end < 0) {
end += this.length;
if (end < 0) {
end = 0;
}
}
if (end > this.length) {
end = this.length;
}
if (start > end) {
start = end;
}
// Sanity check.
if (start < 0 || end < 0 || start >= this.length || end > this.length) {
throw new Error("Invalid slice indices.");
}
// Copy the BufferCore.
return new Buffer(this.data.copy(start + this.offset, end + this.offset));
};
/**
* Fills the buffer with the specified value. If the offset and end are not
* given it will fill the entire buffer.
* @param {(string|number)} value - The value to fill the buffer with
* @param {number} [offset=0]
* @param {number} [end=this.length]
*/
Buffer.prototype.fill = function (value, offset, end) {
if (typeof offset === "undefined") { offset = 0; }
if (typeof end === "undefined") { end = this.length; }
var i;
var valType = typeof value;
switch (valType) {
case "string":
// Trim to a byte.
value = value.charCodeAt(0) & 0xFF;
break;
case "number":
break;
default:
throw new Error('Invalid argument to fill.');
}
offset += this.offset;
end += this.offset;
this.data.fill(value, offset, end);
};
Buffer.prototype.readUInt8 = function (offset, noAssert) {
if (typeof noAssert === "undefined") { noAssert = false; }
offset += this.offset;
return this.data.readUInt8(offset);
};
Buffer.prototype.readUInt16LE = function (offset, noAssert) {
if (typeof noAssert === "undefined") { noAssert = false; }
offset += this.offset;
return this.data.readUInt16LE(offset);
};
Buffer.prototype.readUInt16BE = function (offset, noAssert) {
if (typeof noAssert === "undefined") { noAssert = false; }
offset += this.offset;
return this.data.readUInt16BE(offset);
};
Buffer.prototype.readUInt32LE = function (offset, noAssert) {
if (typeof noAssert === "undefined") { noAssert = false; }
offset += this.offset;
return this.data.readUInt32LE(offset);
};
Buffer.prototype.readUInt32BE = function (offset, noAssert) {
if (typeof noAssert === "undefined") { noAssert = false; }
offset += this.offset;
return this.data.readUInt32BE(offset);
};
Buffer.prototype.readInt8 = function (offset, noAssert) {
if (typeof noAssert === "undefined") { noAssert = false; }
offset += this.offset;
return this.data.readInt8(offset);
};
Buffer.prototype.readInt16LE = function (offset, noAssert) {
if (typeof noAssert === "undefined") { noAssert = false; }
offset += this.offset;
return this.data.readInt16LE(offset);
};
Buffer.prototype.readInt16BE = function (offset, noAssert) {
if (typeof noAssert === "undefined") { noAssert = false; }
offset += this.offset;
return this.data.readInt16BE(offset);
};
Buffer.prototype.readInt32LE = function (offset, noAssert) {
if (typeof noAssert === "undefined") { noAssert = false; }
offset += this.offset;
return this.data.readInt32LE(offset);
};
Buffer.prototype.readInt32BE = function (offset, noAssert) {
if (typeof noAssert === "undefined") { noAssert = false; }
offset += this.offset;
return this.data.readInt32BE(offset);
};
Buffer.prototype.readFloatLE = function (offset, noAssert) {
if (typeof noAssert === "undefined") { noAssert = false; }
offset += this.offset;
return this.data.readFloatLE(offset);
};
Buffer.prototype.readFloatBE = function (offset, noAssert) {
if (typeof noAssert === "undefined") { noAssert = false; }
offset += this.offset;
return this.data.readFloatBE(offset);
};
Buffer.prototype.readDoubleLE = function (offset, noAssert) {
if (typeof noAssert === "undefined") { noAssert = false; }
offset += this.offset;
return this.data.readDoubleLE(offset);
};
Buffer.prototype.readDoubleBE = function (offset, noAssert) {
if (typeof noAssert === "undefined") { noAssert = false; }
offset += this.offset;
return this.data.readDoubleBE(offset);
};
Buffer.prototype.writeUInt8 = function (value, offset, noAssert) {
if (typeof noAssert === "undefined") { noAssert = false; }
offset += this.offset;
this.data.writeUInt8(offset, value);
};
Buffer.prototype.writeUInt16LE = function (value, offset, noAssert) {
if (typeof noAssert === "undefined") { noAssert = false; }
offset += this.offset;
this.data.writeUInt16LE(offset, value);
};
Buffer.prototype.writeUInt16BE = function (value, offset, noAssert) {
if (typeof noAssert === "undefined") { noAssert = false; }
offset += this.offset;
this.data.writeUInt16BE(offset, value);
};
Buffer.prototype.writeUInt32LE = function (value, offset, noAssert) {
if (typeof noAssert === "undefined") { noAssert = false; }
offset += this.offset;
this.data.writeUInt32LE(offset, value);
};
Buffer.prototype.writeUInt32BE = function (value, offset, noAssert) {
if (typeof noAssert === "undefined") { noAssert = false; }
offset += this.offset;
this.data.writeUInt32BE(offset, value);
};
Buffer.prototype.writeInt8 = function (value, offset, noAssert) {
if (typeof noAssert === "undefined") { noAssert = false; }
offset += this.offset;
this.data.writeInt8(offset, value);
};
Buffer.prototype.writeInt16LE = function (value, offset, noAssert) {
if (typeof noAssert === "undefined") { noAssert = false; }
offset += this.offset;
this.data.writeInt16LE(offset, value);
};
Buffer.prototype.writeInt16BE = function (value, offset, noAssert) {
if (typeof noAssert === "undefined") { noAssert = false; }
offset += this.offset;
this.data.writeInt16BE(offset, value);
};
Buffer.prototype.writeInt32LE = function (value, offset, noAssert) {
if (typeof noAssert === "undefined") { noAssert = false; }
offset += this.offset;
this.data.writeInt32LE(offset, value);
};
Buffer.prototype.writeInt32BE = function (value, offset, noAssert) {
if (typeof noAssert === "undefined") { noAssert = false; }
offset += this.offset;
this.data.writeInt32BE(offset, value);
};
Buffer.prototype.writeFloatLE = function (value, offset, noAssert) {
if (typeof noAssert === "undefined") { noAssert = false; }
offset += this.offset;
this.data.writeFloatLE(offset, value);
};
Buffer.prototype.writeFloatBE = function (value, offset, noAssert) {
if (typeof noAssert === "undefined") { noAssert = false; }
offset += this.offset;
this.data.writeFloatBE(offset, value);
};
Buffer.prototype.writeDoubleLE = function (value, offset, noAssert) {
if (typeof noAssert === "undefined") { noAssert = false; }
offset += this.offset;
this.data.writeDoubleLE(offset, value);
};
Buffer.prototype.writeDoubleBE = function (value, offset, noAssert) {
if (typeof noAssert === "undefined") { noAssert = false; }
offset += this.offset;
this.data.writeDoubleBE(offset, value);
};
///**************************STATIC METHODS********************************///
/**
* Checks if enc is a valid string encoding type.
* @param {string} enc - Name of a string encoding type.
* @return {boolean} Whether or not enc is a valid encoding type.
*/
Buffer.isEncoding = function (enc) {
try {
string_util.FindUtil(enc);
} catch (e) {
return false;
}
return true;
};
/**
* Tests if obj is a Buffer.
* @param {object} obj - An arbitrary object
* @return {boolean} True if this object is a Buffer.
*/
Buffer.isBuffer = function (obj) {
return obj instanceof Buffer;
};
/**
* Gives the actual byte length of a string. This is not the same as
* String.prototype.length since that returns the number of characters in a
* string.
* @param {string} str - The string to get the byte length of
* @param {string} [encoding=utf8] - Character encoding of the string
* @return {number} The number of bytes in the string
*/
Buffer.byteLength = function (str, encoding) {
if (typeof encoding === "undefined") { encoding = 'utf8'; }
var strUtil = string_util.FindUtil(encoding);
return strUtil.byteLength(str);
};
/**
* Returns a buffer which is the result of concatenating all the buffers in the
* list together.
* If the list has no items, or if the totalLength is 0, then it returns a
* zero-length buffer.
* If the list has exactly one item, then the first item of the list is
* returned.
* If the list has more than one item, then a new Buffer is created.
* If totalLength is not provided, it is read from the buffers in the list.
* However, this adds an additional loop to the function, so it is faster to
* provide the length explicitly.
* @param {Buffer[]} list - List of Buffer objects to concat
* @param {number} [totalLength] - Total length of the buffers when concatenated
* @return {Buffer}
*/
Buffer.concat = function (list, totalLength) {
var item;
if (list.length === 0 || totalLength === 0) {
return new Buffer(0);
} else if (list.length === 1) {
return list[0];
} else {
if (totalLength == null) {
// Calculate totalLength
totalLength = 0;
for (var i = 0; i < list.length; i++) {
item = list[i];
totalLength += item.length;
}
}
var buf = new Buffer(totalLength);
var curPos = 0;
for (var j = 0; j < list.length; j++) {
item = list[j];
curPos += item.copy(buf, curPos);
}
return buf;
}
};
return Buffer;
})();
exports.Buffer = Buffer;
// Type-check the class.
var _ = Buffer;
});
//# sourceMappingURL=buffer.js.map
;
define('core/file_flag',["require", "exports", './api_error'], function(require, exports, api_error) {
/**
* @class
*/
(function (ActionType) {
// Indicates that the code should not do anything.
ActionType[ActionType["NOP"] = 0] = "NOP";
// Indicates that the code should throw an exception.
ActionType[ActionType["THROW_EXCEPTION"] = 1] = "THROW_EXCEPTION";
// Indicates that the code should truncate the file, but only if it is a file.
ActionType[ActionType["TRUNCATE_FILE"] = 2] = "TRUNCATE_FILE";
// Indicates that the code should create the file.
ActionType[ActionType["CREATE_FILE"] = 3] = "CREATE_FILE";
})(exports.ActionType || (exports.ActionType = {}));
var ActionType = exports.ActionType;
/**
* Represents one of the following file flags. A convenience object.
*
* * `'r'` - Open file for reading. An exception occurs if the file does not exist.
* * `'r+'` - Open file for reading and writing. An exception occurs if the file does not exist.
* * `'rs'` - Open file for reading in synchronous mode. Instructs the filesystem to not cache writes.
* * `'rs+'` - Open file for reading and writing, and opens the file in synchronous mode.
* * `'w'` - Open file for writing. The file is created (if it does not exist) or truncated (if it exists).
* * `'wx'` - Like 'w' but opens the file in exclusive mode.
* * `'w+'` - Open file for reading and writing. The file is created (if it does not exist) or truncated (if it exists).
* * `'wx+'` - Like 'w+' but opens the file in exclusive mode.
* * `'a'` - Open file for appending. The file is created if it does not exist.
* * `'ax'` - Like 'a' but opens the file in exclusive mode.
* * `'a+'` - Open file for reading and appending. The file is created if it does not exist.
* * `'ax+'` - Like 'a+' but opens the file in exclusive mode.
*
* Exclusive mode ensures that the file path is newly created.
* @class
*/
var FileFlag = (function () {
/**
* This should never be called directly.
* @param [String] modeStr The string representing the mode
* @throw [BrowserFS.ApiError] when the mode string is invalid
*/
function FileFlag(flagStr) {
this.flagStr = flagStr;
if (FileFlag.validFlagStrs.indexOf(flagStr) < 0) {
throw new api_error.ApiError(9 /* EINVAL */, "Invalid flag: " + flagStr);
}
}
/**
* Get an object representing the given file mode.
* @param [String] modeStr The string representing the mode
* @return [BrowserFS.FileMode] The FileMode object representing the mode
* @throw [BrowserFS.ApiError] when the mode string is invalid
*/
FileFlag.getFileFlag = function (flagStr) {
// Check cache first.
if (FileFlag.flagCache.hasOwnProperty(flagStr)) {
return FileFlag.flagCache[flagStr];
}
return FileFlag.flagCache[flagStr] = new FileFlag(flagStr);
};
/**
* Returns true if the file is readable.
* @return [Boolean]
*/
FileFlag.prototype.isReadable = function () {
return this.flagStr.indexOf('r') !== -1 || this.flagStr.indexOf('+') !== -1;
};
/**
* Returns true if the file is writeable.
* @return [Boolean]
*/
FileFlag.prototype.isWriteable = function () {
return this.flagStr.indexOf('w') !== -1 || this.flagStr.indexOf('a') !== -1 || this.flagStr.indexOf('+') !== -1;
};
/**
* Returns true if the file mode should truncate.
* @return [Boolean]
*/
FileFlag.prototype.isTruncating = function () {
return this.flagStr.indexOf('w') !== -1;
};
/**
* Returns true if the file is appendable.
* @return [Boolean]
*/
FileFlag.prototype.isAppendable = function () {
return this.flagStr.indexOf('a') !== -1;
};
/**
* Returns true if the file is open in synchronous mode.
* @return [Boolean]
*/
FileFlag.prototype.isSynchronous = function () {
return this.flagStr.indexOf('s') !== -1;
};
/**
* Returns true if the file is open in exclusive mode.
* @return [Boolean]
*/
FileFlag.prototype.isExclusive = function () {
return this.flagStr.indexOf('x') !== -1;
};
/**
* Returns one of the static fields on this object that indicates the
* appropriate response to the path existing.
* @return [Number]
*/
FileFlag.prototype.pathExistsAction = function () {
if (this.isExclusive()) {
return 1 /* THROW_EXCEPTION */;
} else if (this.isTruncating()) {
return 2 /* TRUNCATE_FILE */;
} else {
return 0 /* NOP */;
}
};
/**
* Returns one of the static fields on this object that indicates the
* appropriate response to the path not existing.
* @return [Number]
*/
FileFlag.prototype.pathNotExistsAction = function () {
if ((this.isWriteable() || this.isAppendable()) && this.flagStr !== 'r+') {
return 3 /* CREATE_FILE */;
} else {
return 1 /* THROW_EXCEPTION */;
}
};
FileFlag.flagCache = {};
FileFlag.validFlagStrs = ['r', 'r+', 'rs', 'rs+', 'w', 'wx', 'w+', 'wx+', 'a', 'ax', 'a+', 'ax+'];
return FileFlag;
})();
exports.FileFlag = FileFlag;
});
//# sourceMappingURL=file_flag.js.map
;
var __extends = this.__extends || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
define('core/node_eventemitter',["require", "exports", './buffer', './api_error'], function(require, exports, buffer, api_error) {
var Buffer = buffer.Buffer;
var ApiError = api_error.ApiError;
var ErrorCode = api_error.ErrorCode;
/**
* Internal class. Represents a buffered event.
*/
var BufferedEvent = (function () {
function BufferedEvent(data, encoding, cb) {
this.data = data;
this.encoding = encoding;
this.cb = cb;
this.size = typeof (data) !== 'string' ? data.length : Buffer.byteLength(data, encoding != null ? encoding : undefined);
// If data is a buffer, we need to copy it.
if (typeof (this.data) !== 'string') {
this.data = this.data.sliceCopy();
}
}
BufferedEvent.prototype.getData = function (encoding) {
if (encoding == null) {
if (typeof (this.data) === 'string') {
return new Buffer(this.data, this.encoding != null ? this.encoding : undefined);
} else {
return this.data;
}
} else {
if (typeof (this.data) === 'string') {
if (encoding === this.encoding) {
return this.data;
} else {
return (new Buffer(this.data, this.encoding != null ? this.encoding : undefined)).toString(encoding);
}
} else {
return this.data.toString(encoding);
}
}
};
return BufferedEvent;
})();
/**
* Provides an abstract implementation of the EventEmitter interface.
*/
var AbstractEventEmitter = (function () {
function AbstractEventEmitter() {
this._listeners = {};
this.maxListeners = 10;
}
/**
* Adds a listener for the particular event.
*/
AbstractEventEmitter.prototype.addListener = function (event, listener) {
if (typeof (this._listeners[event]) === 'undefined') {
this._listeners[event] = [];
}
if (this._listeners[event].push(listener) > this.maxListeners) {
process.stdout.write("Warning: Event " + event + " has more than " + this.maxListeners + " listeners.\n");
}
this.emit('newListener', event, listener);
return this;
};
/**
* Adds a listener for the particular event.
*/
AbstractEventEmitter.prototype.on = function (event, listener) {
return this.addListener(event, listener);
};
/**
* Adds a listener for the particular event that fires only once.
*/
AbstractEventEmitter.prototype.once = function (event, listener) {
// Create a new callback that will only fire once.
var fired = false, newListener = function () {
this.removeListener(event, newListener);
if (!fired) {
fired = true;
listener.apply(this, arguments);
}
};
return this.addListener(event, newListener);
};
/**
* Emits the 'removeListener' event for the specified listeners.
*/
AbstractEventEmitter.prototype._emitRemoveListener = function (event, listeners) {
var i;
// Only emit the event if someone is listening.
if (this._listeners['removeListener'] && this._listeners['removeListener'].length > 0) {
for (i = 0; i < listeners.length; i++) {
this.emit('removeListener', event, listeners[i]);
}
}
};
/**
* Removes the particular listener for the given event.
*/
AbstractEventEmitter.prototype.removeListener = function (event, listener) {
var listeners = this._listeners[event];
if (typeof (listeners) !== 'undefined') {
// Remove listener, if present.
var idx = listeners.indexOf(listener);
if (idx > -1) {
listeners.splice(idx, 1);
}
}
this.emit('removeListener', event, listener);
return this;
};
/**
* Removes all listeners, or those of the specified event.
*/
AbstractEventEmitter.prototype.removeAllListeners = function (event) {
var removed, keys, i;
if (typeof (event) !== 'undefined') {
removed = this._listeners[event];
// Clear one event.
this._listeners[event] = [];
this._emitRemoveListener(event, removed);
} else {
// Clear all events.
keys = Object.keys(this._listeners);
for (i = 0; i < keys.length; i++) {
this.removeAllListeners(keys[i]);
}
}
return this;
};
/**
* EventEmitters print a warning when an event has greater than this specified
* number of listeners.
*/
AbstractEventEmitter.prototype.setMaxListeners = function (n) {
this.maxListeners = n;
};
/**
* Returns the listeners for the given event.
*/
AbstractEventEmitter.prototype.listeners = function (event) {
if (typeof (this._listeners[event]) === 'undefined') {
this._listeners[event] = [];
}
// Return a *copy* of our internal structure.
return this._listeners[event].slice(0);
};
/**
* Emits the specified event to all listeners of the particular event.
*/
AbstractEventEmitter.prototype.emit = function (event) {
var args = [];
for (var _i = 0; _i < (arguments.length - 1); _i++) {
args[_i] = arguments[_i + 1];
}
var listeners = this._listeners[event], rv = false;
if (typeof (listeners) !== 'undefined') {
var i;
for (i = 0; i < listeners.length; i++) {
rv = true;
listeners[i].apply(this, args);
}
}
return rv;
};
return AbstractEventEmitter;
})();
exports.AbstractEventEmitter = AbstractEventEmitter;
/**
* Provides an abstract implementation of the WritableStream and ReadableStream
* interfaces.
* @todo: Check readable/writable status.
*/
var AbstractDuplexStream = (function (_super) {
__extends(AbstractDuplexStream, _super);
/**
* Abstract stream implementation that can be configured to be readable and/or
* writable.
*/
function AbstractDuplexStream(writable, readable) {
_super.call(this);
this.writable = writable;
this.readable = readable;
/**
* How should the data output be encoded? 'null' means 'Buffer'.
*/
this.encoding = null;
/**
* Is this stream currently flowing (resumed) or non-flowing (paused)?
*/
this.flowing = false;
/**
* Event buffer. Simply queues up all write requests.
*/
this.buffer = [];
/**
* Once set, the stream is closed. Emitted once 'buffer' is empty.
*/
this.endEvent = null;
/**
* Has the stream ended?
*/
this.ended = false;
/**
* The last time we checked, was the buffer empty?
* We emit 'readable' events when this transitions from 'true' -> 'false'.
*/
this.drained = true;
}
/**
* Adds a listener for the particular event.
* Implemented here so that we can capture data EventListeners, which trigger
* us to 'resume'.
*/
AbstractDuplexStream.prototype.addListener = function (event, listener) {
var rv = _super.prototype.addListener.call(this, event, listener), _this = this;
if (event === 'data' && !this.flowing) {
this.resume();
} else if (event === 'readable' && this.buffer.length > 0) {
setTimeout(function () {
_this.emit('readable');
}, 0);
}
return rv;
};
/**
* Helper function for 'write' and 'end' functions.
*/
AbstractDuplexStream.prototype._processArgs = function (data, arg2, arg3) {
if (typeof (arg2) === 'string') {
// data, encoding, cb?
return new BufferedEvent(data, arg2, arg3);
} else {
// data, cb?
return new BufferedEvent(data, null, arg2);
}
};
/**
* If flowing, this will process pending events.
*/
AbstractDuplexStream.prototype._processEvents = function () {
var drained = this.buffer.length === 0;
if (this.drained !== drained) {
if (this.drained) {
// Went from drained to not drained. New stuff is available.
// @todo: Is this event relevant in flowing mode?
this.emit('readable');
}
}
if (this.flowing && this.buffer.length !== 0) {
this.emit('data', this.read());
}
// Are we drained? Check.
this.drained = this.buffer.length === 0;
};
/**
* Emits the given buffered event.
*/
AbstractDuplexStream.prototype.emitEvent = function (type, event) {
this.emit(type, event.getData(this.encoding));
if (event.cb) {
event.cb();
}
};
AbstractDuplexStream.prototype.write = function (data, arg2, arg3) {
if (this.ended) {
throw new ApiError(0 /* EPERM */, 'Cannot write to an ended stream.');
}
var event = this._processArgs(data, arg2, arg3);
this._push(event);
return this.flowing;
};
AbstractDuplexStream.prototype.end = function (data, arg2, arg3) {
if (this.ended) {
throw new ApiError(0 /* EPERM */, 'Stream is already closed.');
}
var event = this._processArgs(data, arg2, arg3);
this.ended = true;
this.endEvent = event;
this._processEvents();
};
/**** Readable Interface ****/
/**
* Read a given number of bytes from the buffer. Should only be called in
* non-flowing mode.
* If we do not have `size` bytes available, return null.
*/
AbstractDuplexStream.prototype.read = function (size) {
var events = [], eventsCbs = [], lastCb, eventsSize = 0, event, buff, trueSize, i = 0, sizeUnspecified = typeof (size) !== 'number';
// I do this so I do not need to specialize the loop below.
if (sizeUnspecified)
size = 4294967295;
for (i = 0; i < this.buffer.length && eventsSize < size; i++) {
event = this.buffer[i];
events.push(event.getData());
if (event.cb) {
eventsCbs.push(event.cb);
}
eventsSize += event.size;
lastCb = event.cb;
}
if (!sizeUnspecified && eventsSize < size) {
// For some reason, the Node stream API specifies that we either return
// 'size' bytes of data, or nothing at all.
return null;
}
// Remove all of the events we are processing from the buffer.
this.buffer = this.buffer.slice(events.length);
// The 'true size' of the final event we're going to send out.
trueSize = eventsSize > size ? size : eventsSize;
// Concat at all of the events into one buffer.
buff = Buffer.concat(events);
if (eventsSize > size) {
// If last event had a cb, ignore it -- we trigger it when that *entire*
// write finishes.
if (lastCb)
eventsCbs.pop();
// Make a new event for the remaining data.
this._push(new BufferedEvent(buff.slice(size), null, lastCb));
}
// Schedule the relevant cbs to fire *after* we've returned these values.
if (eventsCbs.length > 0) {
setTimeout(function () {
var i;
for (i = 0; i < eventsCbs.length; i++) {
eventsCbs[i]();
}
}, 0);
}
// If we're at the end of the buffer and an endEvent is specified, schedule
// the event to fire.
if (this.ended && this.buffer.length === 0 && this.endEvent !== null) {
var endEvent = this.endEvent, _this = this;
// Erase it so we don't accidentally trigger it again.
this.endEvent = null;
setTimeout(function () {
_this.emitEvent('end', endEvent);
}, 0);
}
// Return in correct encoding.
if (events.length === 0) {
// Buffer was empty. We're supposed to return 'null', as opposed to an
// empty buffer or string.
// [BFS] Emit a '_read' event to signal that maybe the write-end of this
// should push some data into the pipe.
this.emit('_read');
return null;
} else if (this.encoding === null) {
return buff.slice(0, trueSize);
} else {
return buff.toString(this.encoding, 0, trueSize);
}
};
/**
* Set the encoding for the 'data' event.
*/
AbstractDuplexStream.prototype.setEncoding = function (encoding) {
this.encoding = encoding;
};
/**
* Pause the stream.
*/
AbstractDuplexStream.prototype.pause = function () {
this.flowing = false;
};
/**
* Resume the stream.
*/
AbstractDuplexStream.prototype.resume = function () {
this.flowing = true;
// Process any buffered writes.
this._processEvents();
};
/**
* Pipe a readable stream into a writable stream. Currently unimplemented.
*/
AbstractDuplexStream.prototype.pipe = function (destination, options) {
throw new ApiError(0 /* EPERM */, "Unimplemented.");
};
AbstractDuplexStream.prototype.unpipe = function (destination) {
};
AbstractDuplexStream.prototype.unshift = function (chunk) {
if (this.ended) {
throw new ApiError(0 /* EPERM */, "Stream has ended.");
}
this.buffer.unshift(new BufferedEvent(chunk, this.encoding));
this._processEvents();
};
/**
* 'Push' the given piece of data to the back of the buffer.
* Returns true if the event was sent out, false if buffered.
*/
AbstractDuplexStream.prototype._push = function (event) {
this.buffer.push(event);
this._processEvents();
};
/**
* Enables backwards-compatibility with older versions of Node and their
* stream interface. Unimplemented.
*/
AbstractDuplexStream.prototype.wrap = function (stream) {
throw new ApiError(0 /* EPERM */, "Unimplemented.");
};
return AbstractDuplexStream;
})(AbstractEventEmitter);
exports.AbstractDuplexStream = AbstractDuplexStream;
});
//# sourceMappingURL=node_eventemitter.js.map
;
var __extends = this.__extends || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
define('core/node_process',["require", "exports", './node_eventemitter'], function(require, exports, eventemitter) {
var path = null;
var TTY = (function (_super) {
__extends(TTY, _super);
function TTY() {
_super.call(this, true, true);
this.isRaw = false;
this.columns = 80;
this.rows = 120;
this.isTTY = true;
}
/**
* Set read mode to 'true' to enable raw mode.
*/
TTY.prototype.setReadMode = function (mode) {
if (this.isRaw !== mode) {
this.isRaw = mode;
// [BFS] TTY implementations can use this to change their event emitting
// patterns.
this.emit('modeChange');
}
};
/**
* [BFS] Update the number of columns available on the terminal.
*/
TTY.prototype.changeColumns = function (columns) {
if (columns !== this.columns) {
this.columns = columns;
// Resize event.
this.emit('resize');
}
};
/**
* [BFS] Update the number of rows available on the terminal.
*/
TTY.prototype.changeRows = function (rows) {
if (rows !== this.rows) {
this.rows = rows;
// Resize event.
this.emit('resize');
}
};
/**
* Returns 'true' if the given object is a TTY.
*/
TTY.isatty = function (fd) {
return fd instanceof TTY;
};
return TTY;
})(eventemitter.AbstractDuplexStream);
exports.TTY = TTY;
/**
* Partial implementation of Node's `process` module.
* We implement the portions that are relevant for the filesystem.
* @see http://nodejs.org/api/process.html
* @class
*/
var Process = (function () {
function Process() {
this.startTime = Date.now();
this._cwd = '/';
/**
* Returns what platform you are running on.
* @return [String]
*/
this.platform = 'browser';
this.argv = [];
this.stdout = new TTY();
this.stderr = new TTY();
this.stdin = new TTY();
}
/**
* Changes the current working directory.
*
* **Note**: BrowserFS does not validate that the directory actually exists.
*
* @example Usage example
* console.log('Starting directory: ' + process.cwd());
* process.chdir('/tmp');
* console.log('New directory: ' + process.cwd());
* @param [String] dir The directory to change to.
*/
Process.prototype.chdir = function (dir) {
// XXX: Circular dependency hack.
if (path === null) {
path = require('./node_path').path;
}
this._cwd = path.resolve(dir);
};
/**
* Returns the current working directory.
* @example Usage example
* console.log('Current directory: ' + process.cwd());
* @return [String] The current working directory.
*/
Process.prototype.cwd = function () {
return this._cwd;
};
/**
* Number of seconds BrowserFS has been running.
* @return [Number]
*/
Process.prototype.uptime = function () {
return ((Date.now() - this.startTime) / 1000) | 0;
};
return Process;
})();
exports.Process = Process;
// process is a singleton.
exports.process = new Process();
});
//# sourceMappingURL=node_process.js.map
;
define('core/node_path',["require", "exports", './node_process'], function(require, exports, node_process) {
var process = node_process.process;
/**
* Emulates Node's `path` module. This module contains utilities for handling and
* transforming file paths. **All** of these methods perform only string
* transformations. The file system is not consulted to check whether paths are
* valid.
* @see http://nodejs.org/api/path.html
* @class
*/
var path = (function () {
function path() {
}
/**
* Normalize a string path, taking care of '..' and '.' parts.
*
* When multiple slashes are found, they're replaced by a single one; when the path contains a trailing slash, it is preserved. On Windows backslashes are used.
* @example Usage example
* path.normalize('/foo/bar//baz/asdf/quux/..')
* // returns
* '/foo/bar/baz/asdf'
* @param [String] p The path to normalize.
* @return [String]
*/
path.normalize = function (p) {
// Special case: '' -> '.'
if (p === '') {
p = '.';
}
// It's very important to know if the path is relative or not, since it
// changes how we process .. and reconstruct the split string.
var absolute = p.charAt(0) === path.sep;
// Remove repeated //s
p = path._removeDuplicateSeps(p);
// Try to remove as many '../' as possible, and remove '.' completely.
var components = p.split(path.sep);
var goodComponents = [];
for (var idx = 0; idx < components.length; idx++) {
var c = components[idx];
if (c === '.') {
continue;
} else if (c === '..' && (absolute || (!absolute && goodComponents.length > 0 && goodComponents[0] !== '..'))) {
// In the absolute case: Path is relative to root, so we may pop even if
// goodComponents is empty (e.g. /../ => /)
// In the relative case: We're getting rid of a directory that preceded
// it (e.g. /foo/../bar -> /bar)
goodComponents.pop();
} else {
goodComponents.push(c);
}
}
// Add in '.' when it's a relative path with no other nonempty components.
// Possible results: '.' and './' (input: [''] or [])
// @todo Can probably simplify this logic.
if (!absolute && goodComponents.length < 2) {
switch (goodComponents.length) {
case 1:
if (goodComponents[0] === '') {
goodComponents.unshift('.');
}
break;
default:
goodComponents.push('.');
}
}
p = goodComponents.join(path.sep);
if (absolute && p.charAt(0) !== path.sep) {
p = path.sep + p;
}
return p;
};
/**
* Join all arguments together and normalize the resulting path.
*
* Arguments must be strings.
* @example Usage
* path.join('/foo', 'bar', 'baz/asdf', 'quux', '..')
* // returns
* '/foo/bar/baz/asdf'
*
* path.join('foo', {}, 'bar')
* // throws exception
* TypeError: Arguments to path.join must be strings
* @param [String,...] paths Each component of the path
* @return [String]
*/
path.join = function () {
var paths = [];
for (var _i = 0; _i < (arguments.length - 0); _i++) {
paths[_i] = arguments[_i + 0];
}
// Required: Prune any non-strings from the path. I also prune empty segments
// so we can do a simple join of the array.
var processed = [];
for (var i = 0; i < paths.length; i++) {
var segment = paths[i];
if (typeof segment !== 'string') {
throw new TypeError("Invalid argument type to path.join: " + (typeof segment));
} else if (segment !== '') {
processed.push(segment);
}
}
return path.normalize(processed.join(path.sep));
};
/**
* Resolves to to an absolute path.
*
* If to isn't already absolute from arguments are prepended in right to left
* order, until an absolute path is found. If after using all from paths still
* no absolute path is found, the current working directory is used as well.
* The resulting path is normalized, and trailing slashes are removed unless
* the path gets resolved to the root directory. Non-string arguments are
* ignored.
*
* Another way to think of it is as a sequence of cd commands in a shell.
*
* path.resolve('foo/bar', '/tmp/file/', '..', 'a/../subfile')
*
* Is similar to:
*
* cd foo/bar
* cd /tmp/file/
* cd ..
* cd a/../subfile
* pwd
*
* The difference is that the different paths don't need to exist and may also
* be files.
* @example Usage example
* path.resolve('/foo/bar', './baz')
* // returns
* '/foo/bar/baz'
*
* path.resolve('/foo/bar', '/tmp/file/')
* // returns
* '/tmp/file'
*
* path.resolve('wwwroot', 'static_files/png/', '../gif/image.gif')
* // if currently in /home/myself/node, it returns
* '/home/myself/node/wwwroot/static_files/gif/image.gif'
* @param [String,...] paths
* @return [String]
*/
path.resolve = function () {
var paths = [];
for (var _i = 0; _i < (arguments.length - 0); _i++) {
paths[_i] = arguments[_i + 0];
}
// Monitor for invalid paths, throw out empty paths, and look for the *last*
// absolute path that we see.
var processed = [];
for (var i = 0; i < paths.length; i++) {
var p = paths[i];
if (typeof p !== 'string') {
throw new TypeError("Invalid argument type to path.join: " + (typeof p));
} else if (p !== '') {
// Remove anything that has occurred before this absolute path, as it
// doesn't matter.
if (p.charAt(0) === path.sep) {
processed = [];
}
processed.push(p);
}
}
// Special: Remove trailing slash unless it's the root
var resolved = path.normalize(processed.join(path.sep));
if (resolved.length > 1 && resolved.charAt(resolved.length - 1) === path.sep) {
return resolved.substr(0, resolved.length - 1);
}
// Special: If it doesn't start with '/', it's relative and we need to append
// the current directory.
if (resolved.charAt(0) !== path.sep) {
// Remove ./, since we're going to append the current directory.
if (resolved.charAt(0) === '.' && (resolved.length === 1 || resolved.charAt(1) === path.sep)) {
resolved = resolved.length === 1 ? '' : resolved.substr(2);
}
// Append the current directory, which *must* be an absolute path.
var cwd = process.cwd();
if (resolved !== '') {
// cwd will never end in a /... unless it's the root.
resolved = this.normalize(cwd + (cwd !== '/' ? path.sep : '') + resolved);
} else {
resolved = cwd;
}
}
return resolved;
};
/**
* Solve the relative path from from to to.
*
* At times we have two absolute paths, and we need to derive the relative path
* from one to the other. This is actually the reverse transform of
* path.resolve, which means we see that:
*
* path.resolve(from, path.relative(from, to)) == path.resolve(to)
*
* @example Usage example
* path.relative('C:\\orandea\\test\\aaa', 'C:\\orandea\\impl\\bbb')
* // returns
* '..\\..\\impl\\bbb'
*
* path.relative('/data/orandea/test/aaa', '/data/orandea/impl/bbb')
* // returns
* '../../impl/bbb'
* @param [String] from
* @param [String] to
* @return [String]
*/
path.relative = function (from, to) {
var i;
// Alright. Let's resolve these two to absolute paths and remove any
// weirdness.
from = path.resolve(from);
to = path.resolve(to);
var fromSegs = from.split(path.sep);
var toSegs = to.split(path.sep);
// Remove the first segment on both, as it's '' (both are absolute paths)
toSegs.shift();
fromSegs.shift();
// There are two segments to this path:
// * Going *up* the directory hierarchy with '..'
// * Going *down* the directory hierarchy with foo/baz/bat.
var upCount = 0;
var downSegs = [];
for (i = 0; i < fromSegs.length; i++) {
var seg = fromSegs[i];
if (seg === toSegs[i]) {
continue;
}
// The rest of 'from', including the current element, indicates how many
// directories we need to go up.
upCount = fromSegs.length - i;
break;
}
// The rest of 'to' indicates where we need to change to. We place this
// outside of the loop, as toSegs.length may be greater than fromSegs.length.
downSegs = toSegs.slice(i);
// Special case: If 'from' is '/'
if (fromSegs.length === 1 && fromSegs[0] === '') {
upCount = 0;
}
// upCount can't be greater than the number of fromSegs
// (cd .. from / is still /)
if (upCount > fromSegs.length) {
upCount = fromSegs.length;
}
// Create the final string!
var rv = '';
for (i = 0; i < upCount; i++) {
rv += '../';
}
rv += downSegs.join(path.sep);
// Special case: Remove trailing '/'. Happens if it's all up and no down.
if (rv.length > 1 && rv.charAt(rv.length - 1) === path.sep) {
rv = rv.substr(0, rv.length - 1);
}
return rv;
};
/**
* Return the directory name of a path. Similar to the Unix `dirname` command.
*
* Note that BrowserFS does not validate if the path is actually a valid
* directory.
* @example Usage example
* path.dirname('/foo/bar/baz/asdf/quux')
* // returns
* '/foo/bar/baz/asdf'
* @param [String] p The path to get the directory name of.
* @return [String]
*/
path.dirname = function (p) {
// We get rid of //, but we don't modify anything else (e.g. any extraneous .
// and ../ are kept intact)
p = path._removeDuplicateSeps(p);
var absolute = p.charAt(0) === path.sep;
var sections = p.split(path.sep);
// Do 1 if it's /foo/bar, 2 if it's /foo/bar/
if (sections.pop() === '' && sections.length > 0) {
sections.pop();
}
if (sections.length > 1) {
return sections.join(path.sep);
} else if (absolute) {
return path.sep;
} else {
return '.';
}
};
/**
* Return the last portion of a path. Similar to the Unix basename command.
* @example Usage example
* path.basename('/foo/bar/baz/asdf/quux.html')
* // returns
* 'quux.html'
*
* path.basename('/foo/bar/baz/asdf/quux.html', '.html')
* // returns
* 'quux'
* @param [String] p
* @param [String?] ext
* @return [String]
*/
path.basename = function (p, ext) {
if (typeof ext === "undefined") { ext = ""; }
// Special case: Normalize will modify this to '.'
if (p === '') {
return p;
}
// Normalize the string first to remove any weirdness.
p = path.normalize(p);
// Get the last part of the string.
var sections = p.split(path.sep);
var lastPart = sections[sections.length - 1];
// Special case: If it's empty, then we have a string like so: foo/
// Meaning, 'foo' is guaranteed to be a directory.
if (lastPart === '' && sections.length > 1) {
return sections[sections.length - 2];
}
// Remove the extension, if need be.
if (ext.length > 0) {
var lastPartExt = lastPart.substr(lastPart.length - ext.length);
if (lastPartExt === ext) {
return lastPart.substr(0, lastPart.length - ext.length);
}
}
return lastPart;
};
/**
* Return the extension of the path, from the last '.' to end of string in the
* last portion of the path. If there is no '.' in the last portion of the path
* or the first character of it is '.', then it returns an empty string.
* @example Usage example
* path.extname('index.html')
* // returns
* '.html'
*
* path.extname('index.')
* // returns
* '.'
*
* path.extname('index')
* // returns
* ''
* @param [String] p
* @return [String]
*/
path.extname = function (p) {
p = path.normalize(p);
var sections = p.split(path.sep);
p = sections.pop();
// Special case: foo/file.ext/ should return '.ext'
if (p === '' && sections.length > 0) {
p = sections.pop();
}
if (p === '..') {
return '';
}
var i = p.lastIndexOf('.');
if (i === -1 || i === 0) {
return '';
}
return p.substr(i);
};
/**
* Checks if the given path is an absolute path.
*
* Despite not being documented, this is a tested part of Node's path API.
* @param [String] p
* @return [Boolean] True if the path appears to be an absolute path.
*/
path.isAbsolute = function (p) {
return p.length > 0 && p.charAt(0) === path.sep;
};
/**
* Unknown. Undocumented.
*/
path._makeLong = function (p) {
return p;
};
path._removeDuplicateSeps = function (p) {
p = p.replace(this._replaceRegex, this.sep);
return p;
};
path.sep = '/';
path._replaceRegex = new RegExp("//+", 'g');
path.delimiter = ':';
return path;
})();
exports.path = path;
});
//# sourceMappingURL=node_path.js.map
;
define('core/node_fs',["require", "exports", './api_error', './file_flag', './buffer', './node_path'], function(require, exports, api_error, file_flag, buffer, node_path) {
var ApiError = api_error.ApiError;
var ErrorCode = api_error.ErrorCode;
var FileFlag = file_flag.FileFlag;
var Buffer = buffer.Buffer;
var path = node_path.path;
/**
* Wraps a callback with a setImmediate call.
* @param [Function] cb The callback to wrap.
* @param [Number] numArgs The number of arguments that the callback takes.
* @return [Function] The wrapped callback.
*/
function wrapCb(cb, numArgs) {
if (typeof cb !== 'function') {
throw new ApiError(9 /* EINVAL */, 'Callback must be a function.');
}
// @todo This is used for unit testing. Maybe we should inject this logic
// dynamically rather than bundle it in 'production' code.
if (typeof __numWaiting === 'undefined') {
__numWaiting = 0;
}
__numWaiting++;
switch (numArgs) {
case 1:
return function (arg1) {
setImmediate(function () {
__numWaiting--;
return cb(arg1);
});
};
case 2:
return function (arg1, arg2) {
setImmediate(function () {
__numWaiting--;
return cb(arg1, arg2);
});
};
case 3:
return function (arg1, arg2, arg3) {
setImmediate(function () {
__numWaiting--;
return cb(arg1, arg2, arg3);
});
};
default:
throw new Error('Invalid invocation of wrapCb.');
}
}
/**
* Checks if the fd is valid.
* @param [BrowserFS.File] fd A file descriptor (in BrowserFS, it's a File object)
* @return [Boolean, BrowserFS.ApiError] Returns `true` if the FD is OK,
* otherwise returns an ApiError.
*/
function checkFd(fd) {
if (typeof fd['write'] !== 'function') {
throw new ApiError(3 /* EBADF */, 'Invalid file descriptor.');
}
}
function normalizeMode(mode, def) {
switch (typeof mode) {
case 'number':
// (path, flag, mode, cb?)
return mode;
case 'string':
// (path, flag, modeString, cb?)
var trueMode = parseInt(mode, 8);
if (trueMode !== NaN) {
return trueMode;
}
default:
return def;
}
}
function normalizePath(p) {
// Node doesn't allow null characters in paths.
if (p.indexOf('\u0000') >= 0) {
throw new ApiError(9 /* EINVAL */, 'Path must be a string without null bytes.');
} else if (p === '') {
throw new ApiError(9 /* EINVAL */, 'Path must not be empty.');
}
return path.resolve(p);
}
function normalizeOptions(options, defEnc, defFlag, defMode) {
switch (typeof options) {
case 'object':
return {
encoding: typeof options['encoding'] !== 'undefined' ? options['encoding'] : defEnc,
flag: typeof options['flag'] !== 'undefined' ? options['flag'] : defFlag,
mode: normalizeMode(options['mode'], defMode)
};
case 'string':
return {
encoding: options,
flag: defFlag,
mode: defMode
};
default:
return {
encoding: defEnc,
flag: defFlag,
mode: defMode
};
}
}
// The default callback is a NOP.
function nopCb() {
}
;
/**
* The node frontend to all filesystems.
* This layer handles:
*
* * Sanity checking inputs.
* * Normalizing paths.
* * Resetting stack depth for asynchronous operations which may not go through
* the browser by wrapping all input callbacks using `setImmediate`.
* * Performing the requested operation through the filesystem or the file
* descriptor, as appropriate.
* * Handling optional arguments and setting default arguments.
* @see http://nodejs.org/api/fs.html
* @class
*/
var fs = (function () {
function fs() {
}
fs._initialize = function (rootFS) {
if (!rootFS.constructor.isAvailable()) {
throw new ApiError(9 /* EINVAL */, 'Tried to instantiate BrowserFS with an unavailable file system.');
}
return fs.root = rootFS;
};
fs._toUnixTimestamp = function (time) {
if (typeof time === 'number') {
return time;
} else if (time instanceof Date) {
return time.getTime() / 1000;
}
throw new Error("Cannot parse time: " + time);
};
/**
* **NONSTANDARD**: Grab the FileSystem instance that backs this API.
* @return [BrowserFS.FileSystem | null] Returns null if the file system has
* not been initialized.
*/
fs.getRootFS = function () {
if (fs.root) {
return fs.root;
} else {
return null;
}
};
// FILE OR DIRECTORY METHODS
/**
* Asynchronous rename. No arguments other than a possible exception are given
* to the completion callback.
* @param [String] oldPath
* @param [String] newPath
* @param [Function(BrowserFS.ApiError)] callback
*/
fs.rename = function (oldPath, newPath, cb) {
if (typeof cb === "undefined") { cb = nopCb; }
var newCb = wrapCb(cb, 1);
try {
fs.root.rename(normalizePath(oldPath), normalizePath(newPath), newCb);
} catch (e) {
newCb(e);
}
};
/**
* Synchronous rename.
* @param [String] oldPath
* @param [String] newPath
*/
fs.renameSync = function (oldPath, newPath) {
fs.root.renameSync(normalizePath(oldPath), normalizePath(newPath));
};
/**
* Test whether or not the given path exists by checking with the file system.
* Then call the callback argument with either true or false.
* @example Sample invocation
* fs.exists('/etc/passwd', function (exists) {
* util.debug(exists ? "it's there" : "no passwd!");
* });
* @param [String] path
* @param [Function(Boolean)] callback
*/
fs.exists = function (path, cb) {
if (typeof cb === "undefined") { cb = nopCb; }
var newCb = wrapCb(cb, 1);
try {
return fs.root.exists(normalizePath(path), newCb);
} catch (e) {
// Doesn't return an error. If something bad happens, we assume it just
// doesn't exist.
return newCb(false);
}
};
/**
* Test whether or not the given path exists by checking with the file system.
* @param [String] path
* @return [boolean]
*/
fs.existsSync = function (path) {
try {
return fs.root.existsSync(normalizePath(path));
} catch (e) {
// Doesn't return an error. If something bad happens, we assume it just
// doesn't exist.
return false;
}
};
/**
* Asynchronous `stat`.
* @param [String] path
* @param [Function(BrowserFS.ApiError, BrowserFS.node.fs.Stats)] callback
*/
fs.stat = function (path, cb) {
if (typeof cb === "undefined") { cb = nopCb; }
var newCb = wrapCb(cb, 2);
try {
return fs.root.stat(normalizePath(path), false, newCb);
} catch (e) {
return newCb(e, null);
}
};
/**
* Synchronous `stat`.
* @param [String] path
* @return [BrowserFS.node.fs.Stats]
*/
fs.statSync = function (path) {
return fs.root.statSync(normalizePath(path), false);
};
/**
* Asynchronous `lstat`.
* `lstat()` is identical to `stat()`, except that if path is a symbolic link,
* then the link itself is stat-ed, not the file that it refers to.
* @param [String] path
* @param [Function(BrowserFS.ApiError, BrowserFS.node.fs.Stats)] callback
*/
fs.lstat = function (path, cb) {
if (typeof cb === "undefined") { cb = nopCb; }
var newCb = wrapCb(cb, 2);
try {
return fs.root.stat(normalizePath(path), true, newCb);
} catch (e) {
return newCb(e, null);
}
};
/**
* Synchronous `lstat`.
* `lstat()` is identical to `stat()`, except that if path is a symbolic link,
* then the link itself is stat-ed, not the file that it refers to.
* @param [String] path
* @return [BrowserFS.node.fs.Stats]
*/
fs.lstatSync = function (path) {
return fs.root.statSync(normalizePath(path), true);
};
fs.truncate = function (path, arg2, cb) {
if (typeof arg2 === "undefined") { arg2 = 0; }
if (typeof cb === "undefined") { cb = nopCb; }
var len = 0;
if (typeof arg2 === 'function') {
cb = arg2;
} else if (typeof arg2 === 'number') {
len = arg2;
}
var newCb = wrapCb(cb, 1);
try {
if (len < 0) {
throw new ApiError(9 /* EINVAL */);
}
return fs.root.truncate(normalizePath(path), len, newCb);
} catch (e) {
return newCb(e);
}
};
/**
* Synchronous `truncate`.
* @param [String] path
* @param [Number] len
*/
fs.truncateSync = function (path, len) {
if (typeof len === "undefined") { len = 0; }
if (len < 0) {
throw new ApiError(9 /* EINVAL */);
}
return fs.root.truncateSync(normalizePath(path), len);
};
/**
* Asynchronous `unlink`.
* @param [String] path
* @param [Function(BrowserFS.ApiError)] callback
*/
fs.unlink = function (path, cb) {
if (typeof cb === "undefined") { cb = nopCb; }
var newCb = wrapCb(cb, 1);
try {
return fs.root.unlink(normalizePath(path), newCb);
} catch (e) {
return newCb(e);
}
};
/**
* Synchronous `unlink`.
* @param [String] path
*/
fs.unlinkSync = function (path) {
return fs.root.unlinkSync(normalizePath(path));
};
fs.open = function (path, flag, arg2, cb) {
if (typeof cb === "undefined") { cb = nopCb; }
var mode = normalizeMode(arg2, 0x1a4);
cb = typeof arg2 === 'function' ? arg2 : cb;
var newCb = wrapCb(cb, 2);
try {
return fs.root.open(normalizePath(path), FileFlag.getFileFlag(flag), mode, newCb);
} catch (e) {
return newCb(e, null);
}
};
fs.openSync = function (path, flag, mode) {
if (typeof mode === "undefined") { mode = 0x1a4; }
return fs.root.openSync(normalizePath(path), FileFlag.getFileFlag(flag), mode);
};
fs.readFile = function (filename, arg2, cb) {
if (typeof arg2 === "undefined") { arg2 = {}; }
if (typeof cb === "undefined") { cb = nopCb; }
var options = normalizeOptions(arg2, null, 'r', null);
cb = typeof arg2 === 'function' ? arg2 : cb;
var newCb = wrapCb(cb, 2);
try {
var flag = FileFlag.getFileFlag(options['flag']);
if (!flag.isReadable()) {
return newCb(new ApiError(9 /* EINVAL */, 'Flag passed to readFile must allow for reading.'));
}
return fs.root.readFile(normalizePath(filename), options.encoding, flag, newCb);
} catch (e) {
return newCb(e, null);
}
};
fs.readFileSync = function (filename, arg2) {
if (typeof arg2 === "undefined") { arg2 = {}; }
var options = normalizeOptions(arg2, null, 'r', null);
var flag = FileFlag.getFileFlag(options.flag);
if (!flag.isReadable()) {
throw new ApiError(9 /* EINVAL */, 'Flag passed to readFile must allow for reading.');
}
return fs.root.readFileSync(normalizePath(filename), options.encoding, flag);
};
fs.writeFile = function (filename, data, arg3, cb) {
if (typeof arg3 === "undefined") { arg3 = {}; }
if (typeof cb === "undefined") { cb = nopCb; }
var options = normalizeOptions(arg3, 'utf8', 'w', 0x1a4);
cb = typeof arg3 === 'function' ? arg3 : cb;
var newCb = wrapCb(cb, 1);
try {
var flag = FileFlag.getFileFlag(options.flag);
if (!flag.isWriteable()) {
return newCb(new ApiError(9 /* EINVAL */, 'Flag passed to writeFile must allow for writing.'));
}
return fs.root.writeFile(normalizePath(filename), data, options.encoding, flag, options.mode, newCb);
} catch (e) {
return newCb(e);
}
};
fs.writeFileSync = function (filename, data, arg3) {
var options = normalizeOptions(arg3, 'utf8', 'w', 0x1a4);
var flag = FileFlag.getFileFlag(options.flag);
if (!flag.isWriteable()) {
throw new ApiError(9 /* EINVAL */, 'Flag passed to writeFile must allow for writing.');
}
return fs.root.writeFileSync(normalizePath(filename), data, options.encoding, flag, options.mode);
};
fs.appendFile = function (filename, data, arg3, cb) {
if (typeof cb === "undefined") { cb = nopCb; }
var options = normalizeOptions(arg3, 'utf8', 'a', 0x1a4);
cb = typeof arg3 === 'function' ? arg3 : cb;
var newCb = wrapCb(cb, 1);
try {
var flag = FileFlag.getFileFlag(options.flag);
if (!flag.isAppendable()) {
return newCb(new ApiError(9 /* EINVAL */, 'Flag passed to appendFile must allow for appending.'));
}
fs.root.appendFile(normalizePath(filename), data, options.encoding, flag, options.mode, newCb);
} catch (e) {
newCb(e);
}
};
fs.appendFileSync = function (filename, data, arg3) {
var options = normalizeOptions(arg3, 'utf8', 'a', 0x1a4);
var flag = FileFlag.getFileFlag(options.flag);
if (!flag.isAppendable()) {
throw new ApiError(9 /* EINVAL */, 'Flag passed to appendFile must allow for appending.');
}
return fs.root.appendFileSync(normalizePath(filename), data, options.encoding, flag, options.mode);
};
// FILE DESCRIPTOR METHODS
/**
* Asynchronous `fstat`.
* `fstat()` is identical to `stat()`, except that the file to be stat-ed is
* specified by the file descriptor `fd`.
* @param [BrowserFS.File] fd
* @param [Function(BrowserFS.ApiError, BrowserFS.node.fs.Stats)] callback
*/
fs.fstat = function (fd, cb) {
if (typeof cb === "undefined") { cb = nopCb; }
var newCb = wrapCb(cb, 2);
try {
checkFd(fd);
fd.stat(newCb);
} catch (e) {
newCb(e);
}
};
/**
* Synchronous `fstat`.
* `fstat()` is identical to `stat()`, except that the file to be stat-ed is
* specified by the file descriptor `fd`.
* @param [BrowserFS.File] fd
* @return [BrowserFS.node.fs.Stats]
*/
fs.fstatSync = function (fd) {
checkFd(fd);
return fd.statSync();
};
/**
* Asynchronous close.
* @param [BrowserFS.File] fd
* @param [Function(BrowserFS.ApiError)] callback
*/
fs.close = function (fd, cb) {
if (typeof cb === "undefined") { cb = nopCb; }
var newCb = wrapCb(cb, 1);
try {
checkFd(fd);
fd.close(newCb);
} catch (e) {
newCb(e);
}
};
/**
* Synchronous close.
* @param [BrowserFS.File] fd
*/
fs.closeSync = function (fd) {
checkFd(fd);
return fd.closeSync();
};
fs.ftruncate = function (fd, arg2, cb) {
if (typeof cb === "undefined") { cb = nopCb; }
var length = typeof arg2 === 'number' ? arg2 : 0;
cb = typeof arg2 === 'function' ? arg2 : cb;
var newCb = wrapCb(cb, 1);
try {
checkFd(fd);
if (length < 0) {
throw new ApiError(9 /* EINVAL */);
}
fd.truncate(length, newCb);
} catch (e) {
newCb(e);
}
};
/**
* Synchronous ftruncate.
* @param [BrowserFS.File] fd
* @param [Number] len
*/
fs.ftruncateSync = function (fd, len) {
if (typeof len === "undefined") { len = 0; }
checkFd(fd);
return fd.truncateSync(len);
};
/**
* Asynchronous fsync.
* @param [BrowserFS.File] fd
* @param [Function(BrowserFS.ApiError)] callback
*/
fs.fsync = function (fd, cb) {
if (typeof cb === "undefined") { cb = nopCb; }
var newCb = wrapCb(cb, 1);
try {
checkFd(fd);
fd.sync(newCb);
} catch (e) {
newCb(e);
}
};
/**
* Synchronous fsync.
* @param [BrowserFS.File] fd
*/
fs.fsyncSync = function (fd) {
checkFd(fd);
return fd.syncSync();
};
/**
* Asynchronous fdatasync.
* @param [BrowserFS.File] fd
* @param [Function(BrowserFS.ApiError)] callback
*/
fs.fdatasync = function (fd, cb) {
if (typeof cb === "undefined") { cb = nopCb; }
var newCb = wrapCb(cb, 1);
try {
checkFd(fd);
fd.datasync(newCb);
} catch (e) {
newCb(e);
}
};
/**
* Synchronous fdatasync.
* @param [BrowserFS.File] fd
*/
fs.fdatasyncSync = function (fd) {
checkFd(fd);
fd.datasyncSync();
};
fs.write = function (fd, arg2, arg3, arg4, arg5, cb) {
if (typeof cb === "undefined") { cb = nopCb; }
var buffer, offset, length, position = null;
if (typeof arg2 === 'string') {
// Signature 1: (fd, string, [position?, [encoding?]], cb?)
var encoding = 'utf8';
switch (typeof arg3) {
case 'function':
// (fd, string, cb)
cb = arg3;
break;
case 'number':
// (fd, string, position, encoding?, cb?)
position = arg3;
encoding = typeof arg4 === 'string' ? arg4 : 'utf8';
cb = typeof arg5 === 'function' ? arg5 : cb;
break;
default:
// ...try to find the callback and get out of here!
cb = typeof arg4 === 'function' ? arg4 : typeof arg5 === 'function' ? arg5 : cb;
return cb(new ApiError(9 /* EINVAL */, 'Invalid arguments.'));
}
buffer = new Buffer(arg2, encoding);
offset = 0;
length = buffer.length;
} else {
// Signature 2: (fd, buffer, offset, length, position?, cb?)
buffer = arg2;
offset = arg3;
length = arg4;
position = typeof arg5 === 'number' ? arg5 : null;
cb = typeof arg5 === 'function' ? arg5 : cb;
}
var newCb = wrapCb(cb, 3);
try {
checkFd(fd);
if (position == null) {
position = fd.getPos();
}
fd.write(buffer, offset, length, position, newCb);
} catch (e) {
newCb(e);
}
};
fs.writeSync = function (fd, arg2, arg3, arg4, arg5) {
var buffer, offset = 0, length, position;
if (typeof arg2 === 'string') {
// Signature 1: (fd, string, [position?, [encoding?]])
position = typeof arg3 === 'number' ? arg3 : null;
var encoding = typeof arg4 === 'string' ? arg4 : 'utf8';
offset = 0;
buffer = new Buffer(arg2, encoding);
length = buffer.length;
} else {
// Signature 2: (fd, buffer, offset, length, position?)
buffer = arg2;
offset = arg3;
length = arg4;
position = typeof arg5 === 'number' ? arg5 : null;
}
checkFd(fd);
if (position == null) {
position = fd.getPos();
}
return fd.writeSync(buffer, offset, length, position);
};
fs.read = function (fd, arg2, arg3, arg4, arg5, cb) {
if (typeof cb === "undefined") { cb = nopCb; }
var position, offset, length, buffer, newCb;
if (typeof arg2 === 'number') {
// legacy interface
// (fd, length, position, encoding, callback)
length = arg2;
position = arg3;
var encoding = arg4;
cb = typeof arg5 === 'function' ? arg5 : cb;
offset = 0;
buffer = new Buffer(length);
// XXX: Inefficient.
// Wrap the cb so we shelter upper layers of the API from these
// shenanigans.
newCb = wrapCb((function (err, bytesRead, buf) {
if (err) {
return cb(err);
}
cb(err, buf.toString(encoding), bytesRead);
}), 3);
} else {
buffer = arg2;
offset = arg3;
length = arg4;
position = arg5;
newCb = wrapCb(cb, 3);
}
try {
checkFd(fd);
if (position == null) {
position = fd.getPos();
}
fd.read(buffer, offset, length, position, newCb);
} catch (e) {
newCb(e);
}
};
fs.readSync = function (fd, arg2, arg3, arg4, arg5) {
var shenanigans = false;
var buffer, offset, length, position;
if (typeof arg2 === 'number') {
length = arg2;
position = arg3;
var encoding = arg4;
offset = 0;
buffer = new Buffer(length);
shenanigans = true;
} else {
buffer = arg2;
offset = arg3;
length = arg4;
position = arg5;
}
checkFd(fd);
if (position == null) {
position = fd.getPos();
}
var rv = fd.readSync(buffer, offset, length, position);
if (!shenanigans) {
return rv;
} else {
return [buffer.toString(encoding), rv];
}
};
/**
* Asynchronous `fchown`.
* @param [BrowserFS.File] fd
* @param [Number] uid
* @param [Number] gid
* @param [Function(BrowserFS.ApiError)] callback
*/
fs.fchown = function (fd, uid, gid, callback) {
if (typeof callback === "undefined") { callback = nopCb; }
var newCb = wrapCb(callback, 1);
try {
checkFd(fd);
fd.chown(uid, gid, newCb);
} catch (e) {
newCb(e);
}
};
/**
* Synchronous `fchown`.
* @param [BrowserFS.File] fd
* @param [Number] uid
* @param [Number] gid
*/
fs.fchownSync = function (fd, uid, gid) {
checkFd(fd);
return fd.chownSync(uid, gid);
};
fs.fchmod = function (fd, mode, cb) {
if (typeof cb === "undefined") { cb = nopCb; }
var newCb = wrapCb(cb, 1);
try {
mode = typeof mode === 'string' ? parseInt(mode, 8) : mode;
checkFd(fd);
fd.chmod(mode, newCb);
} catch (e) {
newCb(e);
}
};
fs.fchmodSync = function (fd, mode) {
mode = typeof mode === 'string' ? parseInt(mode, 8) : mode;
checkFd(fd);
return fd.chmodSync(mode);
};
fs.futimes = function (fd, atime, mtime, cb) {
if (typeof cb === "undefined") { cb = nopCb; }
var newCb = wrapCb(cb, 1);
try {
checkFd(fd);
if (typeof atime === 'number') {
atime = new Date(atime * 1000);
}
if (typeof mtime === 'number') {
mtime = new Date(mtime * 1000);
}
fd.utimes(atime, mtime, newCb);
} catch (e) {
newCb(e);
}
};
fs.futimesSync = function (fd, atime, mtime) {
checkFd(fd);
if (typeof atime === 'number') {
atime = new Date(atime * 1000);
}
if (typeof mtime === 'number') {
mtime = new Date(mtime * 1000);
}
return fd.utimesSync(atime, mtime);
};
// DIRECTORY-ONLY METHODS
/**
* Asynchronous `rmdir`.
* @param [String] path
* @param [Function(BrowserFS.ApiError)] callback
*/
fs.rmdir = function (path, cb) {
if (typeof cb === "undefined") { cb = nopCb; }
var newCb = wrapCb(cb, 1);
try {
path = normalizePath(path);
fs.root.rmdir(path, newCb);
} catch (e) {
newCb(e);
}
};
/**
* Synchronous `rmdir`.
* @param [String] path
*/
fs.rmdirSync = function (path) {
path = normalizePath(path);
return fs.root.rmdirSync(path);
};
/**
* Asynchronous `mkdir`.
* @param [String] path
* @param [Number?] mode defaults to `0777`
* @param [Function(BrowserFS.ApiError)] callback
*/
fs.mkdir = function (path, mode, cb) {
if (typeof cb === "undefined") { cb = nopCb; }
if (typeof mode === 'function') {
cb = mode;
mode = 0x1ff;
}
var newCb = wrapCb(cb, 1);
try {
path = normalizePath(path);
fs.root.mkdir(path, mode, newCb);
} catch (e) {
newCb(e);
}
};
fs.mkdirSync = function (path, mode) {
if (typeof mode === "undefined") { mode = 0x1ff; }
mode = typeof mode === 'string' ? parseInt(mode, 8) : mode;
path = normalizePath(path);
return fs.root.mkdirSync(path, mode);
};
/**
* Asynchronous `readdir`. Reads the contents of a directory.
* The callback gets two arguments `(err, files)` where `files` is an array of
* the names of the files in the directory excluding `'.'` and `'..'`.
* @param [String] path
* @param [Function(BrowserFS.ApiError, String[])] callback
*/
fs.readdir = function (path, cb) {
if (typeof cb === "undefined") { cb = nopCb; }
var newCb = wrapCb(cb, 2);
try {
path = normalizePath(path);
fs.root.readdir(path, newCb);
} catch (e) {
newCb(e);
}
};
/**
* Synchronous `readdir`. Reads the contents of a directory.
* @param [String] path
* @return [String[]]
*/
fs.readdirSync = function (path) {
path = normalizePath(path);
return fs.root.readdirSync(path);
};
// SYMLINK METHODS
/**
* Asynchronous `link`.
* @param [String] srcpath
* @param [String] dstpath
* @param [Function(BrowserFS.ApiError)] callback
*/
fs.link = function (srcpath, dstpath, cb) {
if (typeof cb === "undefined") { cb = nopCb; }
var newCb = wrapCb(cb, 1);
try {
srcpath = normalizePath(srcpath);
dstpath = normalizePath(dstpath);
fs.root.link(srcpath, dstpath, newCb);
} catch (e) {
newCb(e);
}
};
/**
* Synchronous `link`.
* @param [String] srcpath
* @param [String] dstpath
*/
fs.linkSync = function (srcpath, dstpath) {
srcpath = normalizePath(srcpath);
dstpath = normalizePath(dstpath);
return fs.root.linkSync(srcpath, dstpath);
};
fs.symlink = function (srcpath, dstpath, arg3, cb) {
if (typeof cb === "undefined") { cb = nopCb; }
var type = typeof arg3 === 'string' ? arg3 : 'file';
cb = typeof arg3 === 'function' ? arg3 : cb;
var newCb = wrapCb(cb, 1);
try {
if (type !== 'file' && type !== 'dir') {
return newCb(new ApiError(9 /* EINVAL */, "Invalid type: " + type));
}
srcpath = normalizePath(srcpath);
dstpath = normalizePath(dstpath);
fs.root.symlink(srcpath, dstpath, type, newCb);
} catch (e) {
newCb(e);
}
};
/**
* Synchronous `symlink`.
* @param [String] srcpath
* @param [String] dstpath
* @param [String?] type can be either `'dir'` or `'file'` (default is `'file'`)
*/
fs.symlinkSync = function (srcpath, dstpath, type) {
if (type == null) {
type = 'file';
} else if (type !== 'file' && type !== 'dir') {
throw new ApiError(9 /* EINVAL */, "Invalid type: " + type);
}
srcpath = normalizePath(srcpath);
dstpath = normalizePath(dstpath);
return fs.root.symlinkSync(srcpath, dstpath, type);
};
/**
* Asynchronous readlink.
* @param [String] path
* @param [Function(BrowserFS.ApiError, String)] callback
*/
fs.readlink = function (path, cb) {
if (typeof cb === "undefined") { cb = nopCb; }
var newCb = wrapCb(cb, 2);
try {
path = normalizePath(path);
fs.root.readlink(path, newCb);
} catch (e) {
newCb(e);
}
};
/**
* Synchronous readlink.
* @param [String] path
* @return [String]
*/
fs.readlinkSync = function (path) {
path = normalizePath(path);
return fs.root.readlinkSync(path);
};
// PROPERTY OPERATIONS
/**
* Asynchronous `chown`.
* @param [String] path
* @param [Number] uid
* @param [Number] gid
* @param [Function(BrowserFS.ApiError)] callback
*/
fs.chown = function (path, uid, gid, cb) {
if (typeof cb === "undefined") { cb = nopCb; }
var newCb = wrapCb(cb, 1);
try {
path = normalizePath(path);
fs.root.chown(path, false, uid, gid, newCb);
} catch (e) {
newCb(e);
}
};
/**
* Synchronous `chown`.
* @param [String] path
* @param [Number] uid
* @param [Number] gid
*/
fs.chownSync = function (path, uid, gid) {
path = normalizePath(path);
fs.root.chownSync(path, false, uid, gid);
};
/**
* Asynchronous `lchown`.
* @param [String] path
* @param [Number] uid
* @param [Number] gid
* @param [Function(BrowserFS.ApiError)] callback
*/
fs.lchown = function (path, uid, gid, cb) {
if (typeof cb === "undefined") { cb = nopCb; }
var newCb = wrapCb(cb, 1);
try {
path = normalizePath(path);
fs.root.chown(path, true, uid, gid, newCb);
} catch (e) {
newCb(e);
}
};
/**
* Synchronous `lchown`.
* @param [String] path
* @param [Number] uid
* @param [Number] gid
*/
fs.lchownSync = function (path, uid, gid) {
path = normalizePath(path);
return fs.root.chownSync(path, true, uid, gid);
};
fs.chmod = function (path, mode, cb) {
if (typeof cb === "undefined") { cb = nopCb; }
var newCb = wrapCb(cb, 1);
try {
mode = typeof mode === 'string' ? parseInt(mode, 8) : mode;
path = normalizePath(path);
fs.root.chmod(path, false, mode, newCb);
} catch (e) {
newCb(e);
}
};
fs.chmodSync = function (path, mode) {
mode = typeof mode === 'string' ? parseInt(mode, 8) : mode;
path = normalizePath(path);
return fs.root.chmodSync(path, false, mode);
};
fs.lchmod = function (path, mode, cb) {
if (typeof cb === "undefined") { cb = nopCb; }
var newCb = wrapCb(cb, 1);
try {
mode = typeof mode === 'string' ? parseInt(mode, 8) : mode;
path = normalizePath(path);
fs.root.chmod(path, true, mode, newCb);
} catch (e) {
newCb(e);
}
};
fs.lchmodSync = function (path, mode) {
path = normalizePath(path);
mode = typeof mode === 'string' ? parseInt(mode, 8) : mode;
return fs.root.chmodSync(path, true, mode);
};
fs.utimes = function (path, atime, mtime, cb) {
if (typeof cb === "undefined") { cb = nopCb; }
var newCb = wrapCb(cb, 1);
try {
path = normalizePath(path);
if (typeof atime === 'number') {
atime = new Date(atime * 1000);
}
if (typeof mtime === 'number') {
mtime = new Date(mtime * 1000);
}
fs.root.utimes(path, atime, mtime, newCb);
} catch (e) {
newCb(e);
}
};
fs.utimesSync = function (path, atime, mtime) {
path = normalizePath(path);
if (typeof atime === 'number') {
atime = new Date(atime * 1000);
}
if (typeof mtime === 'number') {
mtime = new Date(mtime * 1000);
}
return fs.root.utimesSync(path, atime, mtime);
};
fs.realpath = function (path, arg2, cb) {
if (typeof cb === "undefined") { cb = nopCb; }
var cache = typeof arg2 === 'object' ? arg2 : {};
cb = typeof arg2 === 'function' ? arg2 : nopCb;
var newCb = wrapCb(cb, 2);
try {
path = normalizePath(path);
fs.root.realpath(path, cache, newCb);
} catch (e) {
newCb(e);
}
};
/**
* Synchronous `realpath`.
* @param [String] path
* @param [Object?] cache An object literal of mapped paths that can be used to
* force a specific path resolution or avoid additional `fs.stat` calls for
* known real paths.
* @return [String]
*/
fs.realpathSync = function (path, cache) {
if (typeof cache === "undefined") { cache = {}; }
path = normalizePath(path);
return fs.root.realpathSync(path, cache);
};
fs.root = null;
return fs;
})();
exports.fs = fs;
});
//# sourceMappingURL=node_fs.js.map
;
define('core/browserfs',["require", "exports", './buffer', './node_fs', './node_path', './node_process'], function(require, exports, buffer, node_fs, node_path, node_process) {
/**
* Installs BrowserFS onto the given object.
* We recommend that you run install with the 'window' object to make things
* global, as in Node.
*
* Properties installed:
*
* * Buffer
* * process
* * require (we monkey-patch it)
*
* This allows you to write code as if you were running inside Node.
* @param {object} obj - The object to install things onto (e.g. window)
*/
function install(obj) {
obj.Buffer = buffer.Buffer;
obj.process = node_process.process;
var oldRequire = obj.require != null ? obj.require : null;
// Monkey-patch require for Node-style code.
obj.require = function (arg) {
var rv = exports.BFSRequire(arg);
if (rv == null) {
return oldRequire.apply(null, Array.prototype.slice.call(arguments, 0));
} else {
return rv;
}
};
}
exports.install = install;
exports.FileSystem = {};
function registerFileSystem(name, fs) {
exports.FileSystem[name] = fs;
}
exports.registerFileSystem = registerFileSystem;
function BFSRequire(module) {
switch (module) {
case 'fs':
return node_fs.fs;
case 'path':
return node_path.path;
case 'buffer':
// The 'buffer' module has 'Buffer' as a property.
return buffer;
case 'process':
return node_process.process;
default:
return exports.FileSystem[module];
}
}
exports.BFSRequire = BFSRequire;
/**
* You must call this function with a properly-instantiated root file system
* before using any file system API method.
* @param {BrowserFS.FileSystem} rootFS - The root filesystem to use for the
* entire BrowserFS file system.
*/
function initialize(rootfs) {
return node_fs.fs._initialize(rootfs);
}
exports.initialize = initialize;
});
//# sourceMappingURL=browserfs.js.map
;
define('generic/emscripten_fs',["require", "exports", '../core/browserfs', '../core/node_fs', '../core/buffer', '../core/buffer_core_arraybuffer'], function(require, exports, BrowserFS, node_fs, buffer, buffer_core_arraybuffer) {
var Buffer = buffer.Buffer;
var BufferCoreArrayBuffer = buffer_core_arraybuffer.BufferCoreArrayBuffer;
var fs = node_fs.fs;
var BFSEmscriptenStreamOps = (function () {
function BFSEmscriptenStreamOps(fs) {
this.fs = fs;
}
BFSEmscriptenStreamOps.prototype.open = function (stream) {
var path = this.fs.realPath(stream.node);
try {
if (FS.isFile(stream.node.mode)) {
stream.nfd = fs.openSync(path, this.fs.flagsToPermissionString(stream.flags));
}
} catch (e) {
if (!e.code)
throw e;
throw new FS.ErrnoError(ERRNO_CODES[e.code]);
}
};
BFSEmscriptenStreamOps.prototype.close = function (stream) {
try {
if (FS.isFile(stream.node.mode) && stream.nfd) {
fs.closeSync(stream.nfd);
}
} catch (e) {
if (!e.code)
throw e;
throw new FS.ErrnoError(ERRNO_CODES[e.code]);
}
};
BFSEmscriptenStreamOps.prototype.read = function (stream, buffer, offset, length, position) {
// Avoid copying overhead by reading directly into buffer.
var bcore = new BufferCoreArrayBuffer(buffer.buffer);
var nbuffer = new Buffer(bcore, buffer.byteOffset + offset, buffer.byteOffset + offset + length);
var res;
try {
res = fs.readSync(stream.nfd, nbuffer, 0, length, position);
} catch (e) {
throw new FS.ErrnoError(ERRNO_CODES[e.code]);
}
// No copying needed, since we wrote directly into UintArray.
return res;
};
BFSEmscriptenStreamOps.prototype.write = function (stream, buffer, offset, length, position) {
// Avoid copying overhead; plug the buffer directly into a BufferCore.
var bcore = new BufferCoreArrayBuffer(buffer.buffer);
var nbuffer = new Buffer(bcore, buffer.byteOffset + offset, buffer.byteOffset + offset + length);
var res;
try {
res = fs.writeSync(stream.nfd, nbuffer, 0, length, position);
} catch (e) {
throw new FS.ErrnoError(ERRNO_CODES[e.code]);
}
return res;
};
BFSEmscriptenStreamOps.prototype.llseek = function (stream, offset, whence) {
var position = offset;
if (whence === 1) {
position += stream.position;
} else if (whence === 2) {
if (FS.isFile(stream.node.mode)) {
try {
var stat = fs.fstatSync(stream.nfd);
position += stat.size;
} catch (e) {
throw new FS.ErrnoError(ERRNO_CODES[e.code]);
}
}
}
if (position < 0) {
throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
}
stream.position = position;
return position;
};
return BFSEmscriptenStreamOps;
})();
var BFSEmscriptenNodeOps = (function () {
function BFSEmscriptenNodeOps(fs) {
this.fs = fs;
}
BFSEmscriptenNodeOps.prototype.getattr = function (node) {
var path = this.fs.realPath(node);
var stat;
try {
stat = fs.lstatSync(path);
} catch (e) {
if (!e.code)
throw e;
throw new FS.ErrnoError(ERRNO_CODES[e.code]);
}
return {
dev: stat.dev,
ino: stat.ino,
mode: stat.mode,
nlink: stat.nlink,
uid: stat.uid,
gid: stat.gid,
rdev: stat.rdev,
size: stat.size,
atime: stat.atime,
mtime: stat.mtime,
ctime: stat.ctime,
blksize: stat.blksize,
blocks: stat.blocks
};
};
BFSEmscriptenNodeOps.prototype.setattr = function (node, attr) {
var path = this.fs.realPath(node);
try {
if (attr.mode !== undefined) {
fs.chmodSync(path, attr.mode);
// update the common node structure mode as well
node.mode = attr.mode;
}
if (attr.timestamp !== undefined) {
var date = new Date(attr.timestamp);
fs.utimesSync(path, date, date);
}
if (attr.size !== undefined) {
fs.truncateSync(path, attr.size);
}
} catch (e) {
if (!e.code)
throw e;
if (e.code === "ENOTSUP") {
// Ignore not supported errors. Emscripten does utimesSync when it
// writes files, but never really requires the value to be set.
return;
}
throw new FS.ErrnoError(ERRNO_CODES[e.code]);
}
};
BFSEmscriptenNodeOps.prototype.lookup = function (parent, name) {
var path = PATH.join2(this.fs.realPath(parent), name);
var mode = this.fs.getMode(path);
return this.fs.createNode(parent, name, mode);
};
BFSEmscriptenNodeOps.prototype.mknod = function (parent, name, mode, dev) {
var node = this.fs.createNode(parent, name, mode, dev);
// create the backing node for this in the fs root as well
var path = this.fs.realPath(node);
try {
if (FS.isDir(node.mode)) {
fs.mkdirSync(path, node.mode);
} else {
fs.writeFileSync(path, '', { mode: node.mode });
}
} catch (e) {
if (!e.code)
throw e;
throw new FS.ErrnoError(ERRNO_CODES[e.code]);
}
return node;
};
BFSEmscriptenNodeOps.prototype.rename = function (oldNode, newDir, newName) {
var oldPath = this.fs.realPath(oldNode);
var newPath = PATH.join2(this.fs.realPath(newDir), newName);
try {
fs.renameSync(oldPath, newPath);
} catch (e) {
if (!e.code)
throw e;
throw new FS.ErrnoError(ERRNO_CODES[e.code]);
}
};
BFSEmscriptenNodeOps.prototype.unlink = function (parent, name) {
var path = PATH.join2(this.fs.realPath(parent), name);
try {
fs.unlinkSync(path);
} catch (e) {
if (!e.code)
throw e;
throw new FS.ErrnoError(ERRNO_CODES[e.code]);
}
};
BFSEmscriptenNodeOps.prototype.rmdir = function (parent, name) {
var path = PATH.join2(this.fs.realPath(parent), name);
try {
fs.rmdirSync(path);
} catch (e) {
if (!e.code)
throw e;
throw new FS.ErrnoError(ERRNO_CODES[e.code]);
}
};
BFSEmscriptenNodeOps.prototype.readdir = function (node) {
var path = this.fs.realPath(node);
try {
return fs.readdirSync(path);
} catch (e) {
if (!e.code)
throw e;
throw new FS.ErrnoError(ERRNO_CODES[e.code]);
}
};
BFSEmscriptenNodeOps.prototype.symlink = function (parent, newName, oldPath) {
var newPath = PATH.join2(this.fs.realPath(parent), newName);
try {
fs.symlinkSync(oldPath, newPath);
} catch (e) {
if (!e.code)
throw e;
throw new FS.ErrnoError(ERRNO_CODES[e.code]);
}
};
BFSEmscriptenNodeOps.prototype.readlink = function (node) {
var path = this.fs.realPath(node);
try {
return fs.readlinkSync(path);
} catch (e) {
if (!e.code)
throw e;
throw new FS.ErrnoError(ERRNO_CODES[e.code]);
}
};
return BFSEmscriptenNodeOps;
})();
var BFSEmscriptenFS = (function () {
function BFSEmscriptenFS() {
// This maps the integer permission modes from http://linux.die.net/man/3/open
// to node.js-specific file open permission strings at http://nodejs.org/api/fs.html#fs_fs_open_path_flags_mode_callback
this.flagsToPermissionStringMap = {
0: 'r',
1: 'r+',
2: 'r+',
64: 'r',
65: 'r+',
66: 'r+',
129: 'rx+',
193: 'rx+',
514: 'w+',
577: 'w',
578: 'w+',
705: 'wx',
706: 'wx+',
1024: 'a',
1025: 'a',
1026: 'a+',
1089: 'a',
1090: 'a+',
1153: 'ax',
1154: 'ax+',
1217: 'ax',
1218: 'ax+',
4096: 'rs',
4098: 'rs+'
};
this.node_ops = new BFSEmscriptenNodeOps(this);
this.stream_ops = new BFSEmscriptenStreamOps(this);
if (typeof BrowserFS === 'undefined') {
throw new Error("BrowserFS is not loaded. Please load it before this library.");
}
}
BFSEmscriptenFS.prototype.mount = function (mount) {
return this.createNode(null, '/', this.getMode(mount.opts.root), 0);
};
BFSEmscriptenFS.prototype.createNode = function (parent, name, mode, dev) {
if (!FS.isDir(mode) && !FS.isFile(mode) && !FS.isLink(mode)) {
throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
}
var node = FS.createNode(parent, name, mode);
node.node_ops = this.node_ops;
node.stream_ops = this.stream_ops;
return node;
};
BFSEmscriptenFS.prototype.getMode = function (path) {
var stat;
try {
stat = fs.lstatSync(path);
} catch (e) {
if (!e.code)
throw e;
throw new FS.ErrnoError(ERRNO_CODES[e.code]);
}
return stat.mode;
};
BFSEmscriptenFS.prototype.realPath = function (node) {
var parts = [];
while (node.parent !== node) {
parts.push(node.name);
node = node.parent;
}
parts.push(node.mount.opts.root);
parts.reverse();
return PATH.join.apply(null, parts);
};
BFSEmscriptenFS.prototype.flagsToPermissionString = function (flags) {
if (flags in this.flagsToPermissionStringMap) {
return this.flagsToPermissionStringMap[flags];
} else {
return flags;
}
};
return BFSEmscriptenFS;
})();
exports.BFSEmscriptenFS = BFSEmscriptenFS;
// Make it available on the global BrowserFS object.
BrowserFS['EmscriptenFS'] = BFSEmscriptenFS;
});
//# sourceMappingURL=emscripten_fs.js.map
;
var __extends = this.__extends || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
define('core/file_system',["require", "exports", './api_error', './file_flag', './node_path', './buffer'], function(require, exports, api_error, file_flag, node_path, buffer) {
var ApiError = api_error.ApiError;
var ErrorCode = api_error.ErrorCode;
var path = node_path.path;
var Buffer = buffer.Buffer;
var ActionType = file_flag.ActionType;
/**
* Basic filesystem class. Most filesystems should extend this class, as it
* provides default implementations for a handful of methods.
*/
var BaseFileSystem = (function () {
function BaseFileSystem() {
}
BaseFileSystem.prototype.supportsLinks = function () {
return false;
};
BaseFileSystem.prototype.diskSpace = function (p, cb) {
cb(0, 0);
};
/**
* Opens the file at path p with the given flag. The file must exist.
* @param p The path to open.
* @param flag The flag to use when opening the file.
*/
BaseFileSystem.prototype.openFile = function (p, flag, cb) {
throw new ApiError(14 /* ENOTSUP */);
};
/**
* Create the file at path p with the given mode. Then, open it with the given
* flag.
*/
BaseFileSystem.prototype.createFile = function (p, flag, mode, cb) {
throw new ApiError(14 /* ENOTSUP */);
};
BaseFileSystem.prototype.open = function (p, flag, mode, cb) {
var _this = this;
var must_be_file = function (e, stats) {
if (e) {
switch (flag.pathNotExistsAction()) {
case 3 /* CREATE_FILE */:
// Ensure parent exists.
return _this.stat(path.dirname(p), false, function (e, parentStats) {
if (e) {
cb(e);
} else if (!parentStats.isDirectory()) {
cb(new ApiError(7 /* ENOTDIR */, path.dirname(p) + " is not a directory."));
} else {
_this.createFile(p, flag, mode, cb);
}
});
case 1 /* THROW_EXCEPTION */:
return cb(new ApiError(1 /* ENOENT */, "" + p + " doesn't exist."));
default:
return cb(new ApiError(9 /* EINVAL */, 'Invalid FileFlag object.'));
}
} else {
// File exists.
if (stats.isDirectory()) {
return cb(new ApiError(8 /* EISDIR */, p + " is a directory."));
}
switch (flag.pathExistsAction()) {
case 1 /* THROW_EXCEPTION */:
return cb(new ApiError(6 /* EEXIST */, p + " already exists."));
case 2 /* TRUNCATE_FILE */:
// NOTE: In a previous implementation, we deleted the file and
// re-created it. However, this created a race condition if another
// asynchronous request was trying to read the file, as the file
// would not exist for a small period of time.
return _this.openFile(p, flag, function (e, fd) {
if (e) {
cb(e);
} else {
fd.truncate(0, function () {
fd.sync(function () {
cb(null, fd);
});
});
}
});
case 0 /* NOP */:
return _this.openFile(p, flag, cb);
default:
return cb(new ApiError(9 /* EINVAL */, 'Invalid FileFlag object.'));
}
}
};
this.stat(p, false, must_be_file);
};
BaseFileSystem.prototype.rename = function (oldPath, newPath, cb) {
cb(new ApiError(14 /* ENOTSUP */));
};
BaseFileSystem.prototype.renameSync = function (oldPath, newPath) {
throw new ApiError(14 /* ENOTSUP */);
};
BaseFileSystem.prototype.stat = function (p, isLstat, cb) {
cb(new ApiError(14 /* ENOTSUP */));
};
BaseFileSystem.prototype.statSync = function (p, isLstat) {
throw new ApiError(14 /* ENOTSUP */);
};
/**
* Opens the file at path p with the given flag. The file must exist.
* @param p The path to open.
* @param flag The flag to use when opening the file.
* @return A File object corresponding to the opened file.
*/
BaseFileSystem.prototype.openFileSync = function (p, flag) {
throw new ApiError(14 /* ENOTSUP */);
};
/**
* Create the file at path p with the given mode. Then, open it with the given
* flag.
*/
BaseFileSystem.prototype.createFileSync = function (p, flag, mode) {
throw new ApiError(14 /* ENOTSUP */);
};
BaseFileSystem.prototype.openSync = function (p, flag, mode) {
// Check if the path exists, and is a file.
var stats;
try {
stats = this.statSync(p, false);
} catch (e) {
switch (flag.pathNotExistsAction()) {
case 3 /* CREATE_FILE */:
// Ensure parent exists.
var parentStats = this.statSync(path.dirname(p), false);
if (!parentStats.isDirectory()) {
throw new ApiError(7 /* ENOTDIR */, path.dirname(p) + " is not a directory.");
}
return this.createFileSync(p, flag, mode);
case 1 /* THROW_EXCEPTION */:
throw new ApiError(1 /* ENOENT */, "" + p + " doesn't exist.");
default:
throw new ApiError(9 /* EINVAL */, 'Invalid FileFlag object.');
}
}
// File exists.
if (stats.isDirectory()) {
throw new ApiError(8 /* EISDIR */, p + " is a directory.");
}
switch (flag.pathExistsAction()) {
case 1 /* THROW_EXCEPTION */:
throw new ApiError(6 /* EEXIST */, p + " already exists.");
case 2 /* TRUNCATE_FILE */:
// Delete file.
this.unlinkSync(p);
// Create file. Use the same mode as the old file.
// Node itself modifies the ctime when this occurs, so this action
// will preserve that behavior if the underlying file system
// supports those properties.
return this.createFileSync(p, flag, stats.mode);
case 0 /* NOP */:
return this.openFileSync(p, flag);
default:
throw new ApiError(9 /* EINVAL */, 'Invalid FileFlag object.');
}
};
BaseFileSystem.prototype.unlink = function (p, cb) {
cb(new ApiError(14 /* ENOTSUP */));
};
BaseFileSystem.prototype.unlinkSync = function (p) {
throw new ApiError(14 /* ENOTSUP */);
};
BaseFileSystem.prototype.rmdir = function (p, cb) {
cb(new ApiError(14 /* ENOTSUP */));
};
BaseFileSystem.prototype.rmdirSync = function (p) {
throw new ApiError(14 /* ENOTSUP */);
};
BaseFileSystem.prototype.mkdir = function (p, mode, cb) {
cb(new ApiError(14 /* ENOTSUP */));
};
BaseFileSystem.prototype.mkdirSync = function (p, mode) {
throw new ApiError(14 /* ENOTSUP */);
};
BaseFileSystem.prototype.readdir = function (p, cb) {
cb(new ApiError(14 /* ENOTSUP */));
};
BaseFileSystem.prototype.readdirSync = function (p) {
throw new ApiError(14 /* ENOTSUP */);
};
BaseFileSystem.prototype.exists = function (p, cb) {
this.stat(p, null, function (err) {
cb(err == null);
});
};
BaseFileSystem.prototype.existsSync = function (p) {
try {
this.statSync(p, true);
return true;
} catch (e) {
return false;
}
};
BaseFileSystem.prototype.realpath = function (p, cache, cb) {
if (this.supportsLinks()) {
// The path could contain symlinks. Split up the path,
// resolve any symlinks, return the resolved string.
var splitPath = p.split(path.sep);
for (var i = 0; i < splitPath.length; i++) {
var addPaths = splitPath.slice(0, i + 1);
splitPath[i] = path.join.apply(null, addPaths);
}
} else {
// No symlinks. We just need to verify that it exists.
this.exists(p, function (doesExist) {
if (doesExist) {
cb(null, p);
} else {
cb(new ApiError(1 /* ENOENT */, "File " + p + " not found."));
}
});
}
};
BaseFileSystem.prototype.realpathSync = function (p, cache) {
if (this.supportsLinks()) {
// The path could contain symlinks. Split up the path,
// resolve any symlinks, return the resolved string.
var splitPath = p.split(path.sep);
for (var i = 0; i < splitPath.length; i++) {
var addPaths = splitPath.slice(0, i + 1);
splitPath[i] = path.join.apply(null, addPaths);
}
} else {
// No symlinks. We just need to verify that it exists.
if (this.existsSync(p)) {
return p;
} else {
throw new ApiError(1 /* ENOENT */, "File " + p + " not found.");
}
}
};
BaseFileSystem.prototype.truncate = function (p, len, cb) {
this.open(p, file_flag.FileFlag.getFileFlag('r+'), 0x1a4, (function (er, fd) {
if (er) {
return cb(er);
}
fd.truncate(len, (function (er) {
fd.close((function (er2) {
cb(er || er2);
}));
}));
}));
};
BaseFileSystem.prototype.truncateSync = function (p, len) {
var fd = this.openSync(p, file_flag.FileFlag.getFileFlag('r+'), 0x1a4);
try {
fd.truncateSync(len);
} catch (e) {
throw e;
} finally {
fd.closeSync();
}
};
BaseFileSystem.prototype.readFile = function (fname, encoding, flag, cb) {
// Wrap cb in file closing code.
var oldCb = cb;
// Get file.
this.open(fname, flag, 0x1a4, function (err, fd) {
if (err) {
return cb(err);
}
cb = function (err, arg) {
fd.close(function (err2) {
if (err == null) {
err = err2;
}
return oldCb(err, arg);
});
};
fd.stat(function (err, stat) {
if (err != null) {
return cb(err);
}
// Allocate buffer.
var buf = new Buffer(stat.size);
fd.read(buf, 0, stat.size, 0, function (err) {
if (err != null) {
return cb(err);
} else if (encoding === null) {
return cb(err, buf);
}
try {
cb(null, buf.toString(encoding));
} catch (e) {
cb(e);
}
});
});
});
};
BaseFileSystem.prototype.readFileSync = function (fname, encoding, flag) {
// Get file.
var fd = this.openSync(fname, flag, 0x1a4);
try {
var stat = fd.statSync();
// Allocate buffer.
var buf = new Buffer(stat.size);
fd.readSync(buf, 0, stat.size, 0);
fd.closeSync();
if (encoding === null) {
return buf;
}
return buf.toString(encoding);
} finally {
fd.closeSync();
}
};
BaseFileSystem.prototype.writeFile = function (fname, data, encoding, flag, mode, cb) {
// Wrap cb in file closing code.
var oldCb = cb;
// Get file.
this.open(fname, flag, 0x1a4, function (err, fd) {
if (err != null) {
return cb(err);
}
cb = function (err) {
fd.close(function (err2) {
oldCb(err != null ? err : err2);
});
};
try {
if (typeof data === 'string') {
data = new Buffer(data, encoding);
}
} catch (e) {
return cb(e);
}
// Write into file.
fd.write(data, 0, data.length, 0, cb);
});
};
BaseFileSystem.prototype.writeFileSync = function (fname, data, encoding, flag, mode) {
// Get file.
var fd = this.openSync(fname, flag, mode);
try {
if (typeof data === 'string') {
data = new Buffer(data, encoding);
}
// Write into file.
fd.writeSync(data, 0, data.length, 0);
} finally {
fd.closeSync();
}
};
BaseFileSystem.prototype.appendFile = function (fname, data, encoding, flag, mode, cb) {
// Wrap cb in file closing code.
var oldCb = cb;
this.open(fname, flag, mode, function (err, fd) {
if (err != null) {
return cb(err);
}
cb = function (err) {
fd.close(function (err2) {
oldCb(err != null ? err : err2);
});
};
if (typeof data === 'string') {
data = new Buffer(data, encoding);
}
fd.write(data, 0, data.length, null, cb);
});
};
BaseFileSystem.prototype.appendFileSync = function (fname, data, encoding, flag, mode) {
var fd = this.openSync(fname, flag, mode);
try {
if (typeof data === 'string') {
data = new Buffer(data, encoding);
}
fd.writeSync(data, 0, data.length, null);
} finally {
fd.closeSync();
}
};
BaseFileSystem.prototype.chmod = function (p, isLchmod, mode, cb) {
cb(new ApiError(14 /* ENOTSUP */));
};
BaseFileSystem.prototype.chmodSync = function (p, isLchmod, mode) {
throw new ApiError(14 /* ENOTSUP */);
};
BaseFileSystem.prototype.chown = function (p, isLchown, uid, gid, cb) {
cb(new ApiError(14 /* ENOTSUP */));
};
BaseFileSystem.prototype.chownSync = function (p, isLchown, uid, gid) {
throw new ApiError(14 /* ENOTSUP */);
};
BaseFileSystem.prototype.utimes = function (p, atime, mtime, cb) {
cb(new ApiError(14 /* ENOTSUP */));
};
BaseFileSystem.prototype.utimesSync = function (p, atime, mtime) {
throw new ApiError(14 /* ENOTSUP */);
};
BaseFileSystem.prototype.link = function (srcpath, dstpath, cb) {
cb(new ApiError(14 /* ENOTSUP */));
};
BaseFileSystem.prototype.linkSync = function (srcpath, dstpath) {
throw new ApiError(14 /* ENOTSUP */);
};
BaseFileSystem.prototype.symlink = function (srcpath, dstpath, type, cb) {
cb(new ApiError(14 /* ENOTSUP */));
};
BaseFileSystem.prototype.symlinkSync = function (srcpath, dstpath, type) {
throw new ApiError(14 /* ENOTSUP */);
};
BaseFileSystem.prototype.readlink = function (p, cb) {
cb(new ApiError(14 /* ENOTSUP */));
};
BaseFileSystem.prototype.readlinkSync = function (p) {
throw new ApiError(14 /* ENOTSUP */);
};
return BaseFileSystem;
})();
exports.BaseFileSystem = BaseFileSystem;
/**
* Implements the asynchronous API in terms of the synchronous API.
* @class SynchronousFileSystem
*/
var SynchronousFileSystem = (function (_super) {
__extends(SynchronousFileSystem, _super);
function SynchronousFileSystem() {
_super.apply(this, arguments);
}
SynchronousFileSystem.prototype.supportsSynch = function () {
return true;
};
SynchronousFileSystem.prototype.rename = function (oldPath, newPath, cb) {
try {
this.renameSync(oldPath, newPath);
cb();
} catch (e) {
cb(e);
}
};
SynchronousFileSystem.prototype.stat = function (p, isLstat, cb) {
try {
cb(null, this.statSync(p, isLstat));
} catch (e) {
cb(e);
}
};
SynchronousFileSystem.prototype.open = function (p, flags, mode, cb) {
try {
cb(null, this.openSync(p, flags, mode));
} catch (e) {
cb(e);
}
};
SynchronousFileSystem.prototype.unlink = function (p, cb) {
try {
this.unlinkSync(p);
cb();
} catch (e) {
cb(e);
}
};
SynchronousFileSystem.prototype.rmdir = function (p, cb) {
try {
this.rmdirSync(p);
cb();
} catch (e) {
cb(e);
}
};
SynchronousFileSystem.prototype.mkdir = function (p, mode, cb) {
try {
this.mkdirSync(p, mode);
cb();
} catch (e) {
cb(e);
}
};
SynchronousFileSystem.prototype.readdir = function (p, cb) {
try {
cb(null, this.readdirSync(p));
} catch (e) {
cb(e);
}
};
SynchronousFileSystem.prototype.chmod = function (p, isLchmod, mode, cb) {
try {
this.chmodSync(p, isLchmod, mode);
cb();
} catch (e) {
cb(e);
}
};
SynchronousFileSystem.prototype.chown = function (p, isLchown, uid, gid, cb) {
try {
this.chownSync(p, isLchown, uid, gid);
cb();
} catch (e) {
cb(e);
}
};
SynchronousFileSystem.prototype.utimes = function (p, atime, mtime, cb) {
try {
this.utimesSync(p, atime, mtime);
cb();
} catch (e) {
cb(e);
}
};
SynchronousFileSystem.prototype.link = function (srcpath, dstpath, cb) {
try {
this.linkSync(srcpath, dstpath);
cb();
} catch (e) {
cb(e);
}
};
SynchronousFileSystem.prototype.symlink = function (srcpath, dstpath, type, cb) {
try {
this.symlinkSync(srcpath, dstpath, type);
cb();
} catch (e) {
cb(e);
}
};
SynchronousFileSystem.prototype.readlink = function (p, cb) {
try {
cb(null, this.readlinkSync(p));
} catch (e) {
cb(e);
}
};
return SynchronousFileSystem;
})(BaseFileSystem);
exports.SynchronousFileSystem = SynchronousFileSystem;
});
//# sourceMappingURL=file_system.js.map
;
define('core/node_fs_stats',["require", "exports"], function(require, exports) {
/**
* Indicates the type of the given file. Applied to 'mode'.
*/
(function (FileType) {
FileType[FileType["FILE"] = 0x8000] = "FILE";
FileType[FileType["DIRECTORY"] = 0x4000] = "DIRECTORY";
FileType[FileType["SYMLINK"] = 0xA000] = "SYMLINK";
})(exports.FileType || (exports.FileType = {}));
var FileType = exports.FileType;
/**
* Emulation of Node's `fs.Stats` object.
*
* Attribute descriptions are from `man 2 stat'
* @see http://nodejs.org/api/fs.html#fs_class_fs_stats
* @see http://man7.org/linux/man-pages/man2/stat.2.html
* @class
*/
var Stats = (function () {
/**
* Provides information about a particular entry in the file system.
* @param [Number] item_type type of the item (FILE, DIRECTORY, SYMLINK, or SOCKET)
* @param [Number] size Size of the item in bytes. For directories/symlinks,
* this is normally the size of the struct that represents the item.
* @param [Number] mode Unix-style file mode (e.g. 0o644)
* @param [Date?] atime time of last access
* @param [Date?] mtime time of last modification
* @param [Date?] ctime time of creation
*/
function Stats(item_type, size, mode, atime, mtime, ctime) {
if (typeof atime === "undefined") { atime = new Date(); }
if (typeof mtime === "undefined") { mtime = new Date(); }
if (typeof ctime === "undefined") { ctime = new Date(); }
this.size = size;
this.mode = mode;
this.atime = atime;
this.mtime = mtime;
this.ctime = ctime;
/**
* UNSUPPORTED ATTRIBUTES
* I assume no one is going to need these details, although we could fake
* appropriate values if need be.
*/
// ID of device containing file
this.dev = 0;
// inode number
this.ino = 0;
// device ID (if special file)
this.rdev = 0;
// number of hard links
this.nlink = 1;
// blocksize for file system I/O
this.blksize = 4096;
// @todo Maybe support these? atm, it's a one-user filesystem.
// user ID of owner
this.uid = 0;
// group ID of owner
this.gid = 0;
if (this.mode == null) {
switch (item_type) {
case 32768 /* FILE */:
this.mode = 0x1a4;
break;
case 16384 /* DIRECTORY */:
default:
this.mode = 0x1ff;
}
}
// number of 512B blocks allocated
this.blocks = Math.ceil(size / 512);
// Check if mode also includes top-most bits, which indicate the file's
// type.
if (this.mode < 0x1000) {
this.mode |= item_type;
}
}
/**
* **Nonstandard**: Clone the stats object.
* @return [BrowserFS.node.fs.Stats]
*/
Stats.prototype.clone = function () {
return new Stats(this.mode & 0xF000, this.size, this.mode & 0xFFF, this.atime, this.mtime, this.ctime);
};
/**
* @return [Boolean] True if this item is a file.
*/
Stats.prototype.isFile = function () {
return (this.mode & 0xF000) === 32768 /* FILE */;
};
/**
* @return [Boolean] True if this item is a directory.
*/
Stats.prototype.isDirectory = function () {
return (this.mode & 0xF000) === 16384 /* DIRECTORY */;
};
/**
* @return [Boolean] True if this item is a symbolic link (only valid through lstat)
*/
Stats.prototype.isSymbolicLink = function () {
return (this.mode & 0xF000) === 40960 /* SYMLINK */;
};
/**
* Change the mode of the file. We use this helper function to prevent messing
* up the type of the file, which is encoded in mode.
*/
Stats.prototype.chmod = function (mode) {
this.mode = (this.mode & 0xF000) | mode;
};
// We don't support the following types of files.
Stats.prototype.isSocket = function () {
return false;
};
Stats.prototype.isBlockDevice = function () {
return false;
};
Stats.prototype.isCharacterDevice = function () {
return false;
};
Stats.prototype.isFIFO = function () {
return false;
};
return Stats;
})();
exports.Stats = Stats;
});
//# sourceMappingURL=node_fs_stats.js.map
;
define('generic/inode',["require", "exports", '../core/node_fs_stats', '../core/buffer'], function(require, exports, node_fs_stats, buffer) {
/**
* Generic inode definition that can easily be serialized.
*/
var Inode = (function () {
function Inode(id, size, mode, atime, mtime, ctime) {
this.id = id;
this.size = size;
this.mode = mode;
this.atime = atime;
this.mtime = mtime;
this.ctime = ctime;
}
/**
* Handy function that converts the Inode to a Node Stats object.
*/
Inode.prototype.toStats = function () {
return new node_fs_stats.Stats((this.mode & 0xF000) === 16384 /* DIRECTORY */ ? 16384 /* DIRECTORY */ : 32768 /* FILE */, this.size, this.mode, new Date(this.atime), new Date(this.mtime), new Date(this.ctime));
};
/**
* Get the size of this Inode, in bytes.
*/
Inode.prototype.getSize = function () {
// ASSUMPTION: ID is ASCII (1 byte per char).
return 30 + this.id.length;
};
/**
* Writes the inode into the start of the buffer.
*/
Inode.prototype.toBuffer = function (buff) {
if (typeof buff === "undefined") { buff = new buffer.Buffer(this.getSize()); }
buff.writeUInt32LE(this.size, 0);
buff.writeUInt16LE(this.mode, 4);
buff.writeDoubleLE(this.atime, 6);
buff.writeDoubleLE(this.mtime, 14);
buff.writeDoubleLE(this.ctime, 22);
buff.write(this.id, 30, this.id.length, 'ascii');
return buff;
};
/**
* Updates the Inode using information from the stats object. Used by file
* systems at sync time, e.g.:
* - Program opens file and gets a File object.
* - Program mutates file. File object is responsible for maintaining
* metadata changes locally -- typically in a Stats object.
* - Program closes file. File object's metadata changes are synced with the
* file system.
* @return True if any changes have occurred.
*/
Inode.prototype.update = function (stats) {
var hasChanged = false;
if (this.size !== stats.size) {
this.size = stats.size;
hasChanged = true;
}
if (this.mode !== stats.mode) {
this.mode = stats.mode;
hasChanged = true;
}
var atimeMs = stats.atime.getTime();
if (this.atime !== atimeMs) {
this.atime = atimeMs;
hasChanged = true;
}
var mtimeMs = stats.mtime.getTime();
if (this.mtime !== mtimeMs) {
this.mtime = mtimeMs;
hasChanged = true;
}
var ctimeMs = stats.ctime.getTime();
if (this.ctime !== ctimeMs) {
this.ctime = ctimeMs;
hasChanged = true;
}
return hasChanged;
};
/**
* Converts the buffer into an Inode.
*/
Inode.fromBuffer = function (buffer) {
if (buffer === undefined) {
throw new Error("NO");
}
return new Inode(buffer.toString('ascii', 30), buffer.readUInt32LE(0), buffer.readUInt16LE(4), buffer.readDoubleLE(6), buffer.readDoubleLE(14), buffer.readDoubleLE(22));
};
// XXX: Copied from Stats. Should reconcile these two into something more
// compact.
/**
* @return [Boolean] True if this item is a file.
*/
Inode.prototype.isFile = function () {
return (this.mode & 0xF000) === 32768 /* FILE */;
};
/**
* @return [Boolean] True if this item is a directory.
*/
Inode.prototype.isDirectory = function () {
return (this.mode & 0xF000) === 16384 /* DIRECTORY */;
};
return Inode;
})();
return Inode;
});
//# sourceMappingURL=inode.js.map
;
define('core/file',["require", "exports", './api_error'], function(require, exports, api_error) {
var ApiError = api_error.ApiError;
var ErrorCode = api_error.ErrorCode;
/**
* Base class that contains shared implementations of functions for the file
* object.
* @class
*/
var BaseFile = (function () {
function BaseFile() {
}
BaseFile.prototype.sync = function (cb) {
cb(new ApiError(14 /* ENOTSUP */));
};
BaseFile.prototype.syncSync = function () {
throw new ApiError(14 /* ENOTSUP */);
};
BaseFile.prototype.datasync = function (cb) {
this.sync(cb);
};
BaseFile.prototype.datasyncSync = function () {
return this.syncSync();
};
BaseFile.prototype.chown = function (uid, gid, cb) {
cb(new ApiError(14 /* ENOTSUP */));
};
BaseFile.prototype.chownSync = function (uid, gid) {
throw new ApiError(14 /* ENOTSUP */);
};
BaseFile.prototype.chmod = function (mode, cb) {
cb(new ApiError(14 /* ENOTSUP */));
};
BaseFile.prototype.chmodSync = function (mode) {
throw new ApiError(14 /* ENOTSUP */);
};
BaseFile.prototype.utimes = function (atime, mtime, cb) {
cb(new ApiError(14 /* ENOTSUP */));
};
BaseFile.prototype.utimesSync = function (atime, mtime) {
throw new ApiError(14 /* ENOTSUP */);
};
return BaseFile;
})();
exports.BaseFile = BaseFile;
});
//# sourceMappingURL=file.js.map
;
var __extends = this.__extends || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
define('generic/preload_file',["require", "exports", '../core/file', '../core/buffer', '../core/api_error', '../core/node_fs'], function(require, exports, file, buffer, api_error, node_fs) {
var ApiError = api_error.ApiError;
var ErrorCode = api_error.ErrorCode;
var fs = node_fs.fs;
var Buffer = buffer.Buffer;
/**
* An implementation of the File interface that operates on a file that is
* completely in-memory. PreloadFiles are backed by a Buffer.
*
* This is also an abstract class, as it lacks an implementation of 'sync' and
* 'close'. Each filesystem that wishes to use this file representation must
* extend this class and implement those two methods.
* @todo 'close' lever that disables functionality once closed.
*/
var PreloadFile = (function (_super) {
__extends(PreloadFile, _super);
/**
* Creates a file with the given path and, optionally, the given contents. Note
* that, if contents is specified, it will be mutated by the file!
* @param [BrowserFS.FileSystem] _fs The file system that created the file.
* @param [String] _path
* @param [BrowserFS.FileMode] _mode The mode that the file was opened using.
* Dictates permissions and where the file pointer starts.
* @param [BrowserFS.node.fs.Stats] _stat The stats object for the given file.
* PreloadFile will mutate this object. Note that this object must contain
* the appropriate mode that the file was opened as.
* @param [BrowserFS.node.Buffer?] contents A buffer containing the entire
* contents of the file. PreloadFile will mutate this buffer. If not
* specified, we assume it is a new file.
*/
function PreloadFile(_fs, _path, _flag, _stat, contents) {
_super.call(this);
this._pos = 0;
this._fs = _fs;
this._path = _path;
this._flag = _flag;
this._stat = _stat;
if (contents != null) {
this._buffer = contents;
} else {
// Empty buffer. It'll expand once we write stuff to it.
this._buffer = new Buffer(0);
}
// Note: This invariant is *not* maintained once the file starts getting
// modified.
if (this._stat.size !== this._buffer.length) {
throw new Error("Invalid buffer: Buffer is " + this._buffer.length + " long, yet Stats object specifies that file is " + this._stat.size + " long.");
}
}
/**
* Get the path to this file.
* @return [String] The path to the file.
*/
PreloadFile.prototype.getPath = function () {
return this._path;
};
/**
* Get the current file position.
*
* We emulate the following bug mentioned in the Node documentation:
* > On Linux, positional writes don't work when the file is opened in append
* mode. The kernel ignores the position argument and always appends the data
* to the end of the file.
* @return [Number] The current file position.
*/
PreloadFile.prototype.getPos = function () {
if (this._flag.isAppendable()) {
return this._stat.size;
}
return this._pos;
};
/**
* Advance the current file position by the indicated number of positions.
* @param [Number] delta
*/
PreloadFile.prototype.advancePos = function (delta) {
return this._pos += delta;
};
/**
* Set the file position.
* @param [Number] newPos
*/
PreloadFile.prototype.setPos = function (newPos) {
return this._pos = newPos;
};
/**
* **Core**: Asynchronous sync. Must be implemented by subclasses of this
* class.
* @param [Function(BrowserFS.ApiError)] cb
*/
PreloadFile.prototype.sync = function (cb) {
try {
this.syncSync();
cb();
} catch (e) {
cb(e);
}
};
/**
* **Core**: Synchronous sync.
*/
PreloadFile.prototype.syncSync = function () {
throw new ApiError(14 /* ENOTSUP */);
};
/**
* **Core**: Asynchronous close. Must be implemented by subclasses of this
* class.
* @param [Function(BrowserFS.ApiError)] cb
*/
PreloadFile.prototype.close = function (cb) {
try {
this.closeSync();
cb();
} catch (e) {
cb(e);
}
};
/**
* **Core**: Synchronous close.
*/
PreloadFile.prototype.closeSync = function () {
throw new ApiError(14 /* ENOTSUP */);
};
/**
* Asynchronous `stat`.
* @param [Function(BrowserFS.ApiError, BrowserFS.node.fs.Stats)] cb
*/
PreloadFile.prototype.stat = function (cb) {
try {
cb(null, this._stat.clone());
} catch (e) {
cb(e);
}
};
/**
* Synchronous `stat`.
*/
PreloadFile.prototype.statSync = function () {
return this._stat.clone();
};
/**
* Asynchronous truncate.
* @param [Number] len
* @param [Function(BrowserFS.ApiError)] cb
*/
PreloadFile.prototype.truncate = function (len, cb) {
try {
this.truncateSync(len);
if (this._flag.isSynchronous() && !fs.getRootFS().supportsSynch()) {
this.sync(cb);
}
cb();
} catch (e) {
return cb(e);
}
};
/**
* Synchronous truncate.
* @param [Number] len
*/
PreloadFile.prototype.truncateSync = function (len) {
if (!this._flag.isWriteable()) {
throw new ApiError(0 /* EPERM */, 'File not opened with a writeable mode.');
}
this._stat.mtime = new Date();
if (len > this._buffer.length) {
var buf = new Buffer(len - this._buffer.length);
buf.fill(0);
// Write will set @_stat.size for us.
this.writeSync(buf, 0, buf.length, this._buffer.length);
if (this._flag.isSynchronous() && fs.getRootFS().supportsSynch()) {
this.syncSync();
}
return;
}
this._stat.size = len;
// Truncate buffer to 'len'.
var newBuff = new Buffer(len);
this._buffer.copy(newBuff, 0, 0, len);
this._buffer = newBuff;
if (this._flag.isSynchronous() && fs.getRootFS().supportsSynch()) {
this.syncSync();
}
};
/**
* Write buffer to the file.
* Note that it is unsafe to use fs.write multiple times on the same file
* without waiting for the callback.
* @param [BrowserFS.node.Buffer] buffer Buffer containing the data to write to
* the file.
* @param [Number] offset Offset in the buffer to start reading data from.
* @param [Number] length The amount of bytes to write to the file.
* @param [Number] position Offset from the beginning of the file where this
* data should be written. If position is null, the data will be written at
* the current position.
* @param [Function(BrowserFS.ApiError, Number, BrowserFS.node.Buffer)]
* cb The number specifies the number of bytes written into the file.
*/
PreloadFile.prototype.write = function (buffer, offset, length, position, cb) {
try {
cb(null, this.writeSync(buffer, offset, length, position), buffer);
} catch (e) {
cb(e);
}
};
/**
* Write buffer to the file.
* Note that it is unsafe to use fs.writeSync multiple times on the same file
* without waiting for the callback.
* @param [BrowserFS.node.Buffer] buffer Buffer containing the data to write to
* the file.
* @param [Number] offset Offset in the buffer to start reading data from.
* @param [Number] length The amount of bytes to write to the file.
* @param [Number] position Offset from the beginning of the file where this
* data should be written. If position is null, the data will be written at
* the current position.
* @return [Number]
*/
PreloadFile.prototype.writeSync = function (buffer, offset, length, position) {
if (position == null) {
position = this.getPos();
}
if (!this._flag.isWriteable()) {
throw new ApiError(0 /* EPERM */, 'File not opened with a writeable mode.');
}
var endFp = position + length;
if (endFp > this._stat.size) {
this._stat.size = endFp;
if (endFp > this._buffer.length) {
// Extend the buffer!
var newBuff = new Buffer(endFp);
this._buffer.copy(newBuff);
this._buffer = newBuff;
}
}
var len = buffer.copy(this._buffer, position, offset, offset + length);
this._stat.mtime = new Date();
if (this._flag.isSynchronous()) {
this.syncSync();
return len;
}
this.setPos(position + len);
return len;
};
/**
* Read data from the file.
* @param [BrowserFS.node.Buffer] buffer The buffer that the data will be
* written to.
* @param [Number] offset The offset within the buffer where writing will
* start.
* @param [Number] length An integer specifying the number of bytes to read.
* @param [Number] position An integer specifying where to begin reading from
* in the file. If position is null, data will be read from the current file
* position.
* @param [Function(BrowserFS.ApiError, Number, BrowserFS.node.Buffer)] cb The
* number is the number of bytes read
*/
PreloadFile.prototype.read = function (buffer, offset, length, position, cb) {
try {
cb(null, this.readSync(buffer, offset, length, position), buffer);
} catch (e) {
cb(e);
}
};
/**
* Read data from the file.
* @param [BrowserFS.node.Buffer] buffer The buffer that the data will be
* written to.
* @param [Number] offset The offset within the buffer where writing will
* start.
* @param [Number] length An integer specifying the number of bytes to read.
* @param [Number] position An integer specifying where to begin reading from
* in the file. If position is null, data will be read from the current file
* position.
* @return [Number]
*/
PreloadFile.prototype.readSync = function (buffer, offset, length, position) {
if (!this._flag.isReadable()) {
throw new ApiError(0 /* EPERM */, 'File not opened with a readable mode.');
}
if (position == null) {
position = this.getPos();
}
var endRead = position + length;
if (endRead > this._stat.size) {
length = this._stat.size - position;
}
var rv = this._buffer.copy(buffer, offset, position, position + length);
this._stat.atime = new Date();
this._pos = position + length;
return rv;
};
/**
* Asynchronous `fchmod`.
* @param [Number|String] mode
* @param [Function(BrowserFS.ApiError)] cb
*/
PreloadFile.prototype.chmod = function (mode, cb) {
try {
this.chmodSync(mode);
cb();
} catch (e) {
cb(e);
}
};
/**
* Asynchronous `fchmod`.
* @param [Number] mode
*/
PreloadFile.prototype.chmodSync = function (mode) {
if (!this._fs.supportsProps()) {
throw new ApiError(14 /* ENOTSUP */);
}
this._stat.chmod(mode);
this.syncSync();
};
return PreloadFile;
})(file.BaseFile);
exports.PreloadFile = PreloadFile;
/**
* File class for the InMemory and XHR file systems.
* Doesn't sync to anything, so it works nicely for memory-only files.
*/
var NoSyncFile = (function (_super) {
__extends(NoSyncFile, _super);
function NoSyncFile(_fs, _path, _flag, _stat, contents) {
_super.call(this, _fs, _path, _flag, _stat, contents);
}
/**
* Asynchronous sync. Doesn't do anything, simply calls the cb.
* @param [Function(BrowserFS.ApiError)] cb
*/
NoSyncFile.prototype.sync = function (cb) {
cb();
};
/**
* Synchronous sync. Doesn't do anything.
*/
NoSyncFile.prototype.syncSync = function () {
};
/**
* Asynchronous close. Doesn't do anything, simply calls the cb.
* @param [Function(BrowserFS.ApiError)] cb
*/
NoSyncFile.prototype.close = function (cb) {
cb();
};
/**
* Synchronous close. Doesn't do anything.
*/
NoSyncFile.prototype.closeSync = function () {
};
return NoSyncFile;
})(PreloadFile);
exports.NoSyncFile = NoSyncFile;
});
//# sourceMappingURL=preload_file.js.map
;
var __extends = this.__extends || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
define('generic/key_value_filesystem',["require", "exports", '../core/file_system', '../core/api_error', '../core/node_fs_stats', '../core/node_path', '../generic/inode', '../core/buffer', '../generic/preload_file'], function(require, exports, file_system, api_error, node_fs_stats, node_path, Inode, buffer, preload_file) {
var ROOT_NODE_ID = "/", path = node_path.path, ApiError = api_error.ApiError, Buffer = buffer.Buffer;
/**
* Generates a random ID.
*/
function GenerateRandomID() {
// From http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
/**
* Helper function. Checks if 'e' is defined. If so, it triggers the callback
* with 'e' and returns false. Otherwise, returns true.
*/
function noError(e, cb) {
if (e) {
cb(e);
return false;
}
return true;
}
/**
* Helper function. Checks if 'e' is defined. If so, it aborts the transaction,
* triggers the callback with 'e', and returns false. Otherwise, returns true.
*/
function noErrorTx(e, tx, cb) {
if (e) {
tx.abort(function () {
cb(e);
});
return false;
}
return true;
}
/**
* A simple RW transaction for simple synchronous key-value stores.
*/
var SimpleSyncRWTransaction = (function () {
function SimpleSyncRWTransaction(store) {
this.store = store;
/**
* Stores data in the keys we modify prior to modifying them.
* Allows us to roll back commits.
*/
this.originalData = {};
/**
* List of keys modified in this transaction, if any.
*/
this.modifiedKeys = [];
}
/**
* Stashes given key value pair into `originalData` if it doesn't already
* exist. Allows us to stash values the program is requesting anyway to
* prevent needless `get` requests if the program modifies the data later
* on during the transaction.
*/
SimpleSyncRWTransaction.prototype.stashOldValue = function (key, value) {
// Keep only the earliest value in the transaction.
if (!this.originalData.hasOwnProperty(key)) {
this.originalData[key] = value;
}
};
/**
* Marks the given key as modified, and stashes its value if it has not been
* stashed already.
*/
SimpleSyncRWTransaction.prototype.markModified = function (key) {
if (this.modifiedKeys.indexOf(key) === -1) {
this.modifiedKeys.push(key);
if (!this.originalData.hasOwnProperty(key)) {
this.originalData[key] = this.store.get(key);
}
}
};
SimpleSyncRWTransaction.prototype.get = function (key) {
var val = this.store.get(key);
this.stashOldValue(key, val);
return val;
};
SimpleSyncRWTransaction.prototype.put = function (key, data, overwrite) {
this.markModified(key);
return this.store.put(key, data, overwrite);
};
SimpleSyncRWTransaction.prototype.delete = function (key) {
this.markModified(key);
this.store.delete(key);
};
SimpleSyncRWTransaction.prototype.commit = function () {
};
SimpleSyncRWTransaction.prototype.abort = function () {
// Rollback old values.
var i, key, value;
for (i = 0; i < this.modifiedKeys.length; i++) {
key = this.modifiedKeys[i];
value = this.originalData[key];
if (value === null) {
// Key didn't exist.
this.store.delete(key);
} else {
// Key existed. Store old value.
this.store.put(key, value, true);
}
}
};
return SimpleSyncRWTransaction;
})();
exports.SimpleSyncRWTransaction = SimpleSyncRWTransaction;
var SyncKeyValueFile = (function (_super) {
__extends(SyncKeyValueFile, _super);
function SyncKeyValueFile(_fs, _path, _flag, _stat, contents) {
_super.call(this, _fs, _path, _flag, _stat, contents);
}
SyncKeyValueFile.prototype.syncSync = function () {
this._fs._syncSync(this._path, this._buffer, this._stat);
};
SyncKeyValueFile.prototype.closeSync = function () {
this.syncSync();
};
return SyncKeyValueFile;
})(preload_file.PreloadFile);
exports.SyncKeyValueFile = SyncKeyValueFile;
/**
* A "Synchronous key-value file system". Stores data to/retrieves data from an
* underlying key-value store.
*
* We use a unique ID for each node in the file system. The root node has a
* fixed ID.
* @todo Introduce Node ID caching.
* @todo Check modes.
*/
var SyncKeyValueFileSystem = (function (_super) {
__extends(SyncKeyValueFileSystem, _super);
function SyncKeyValueFileSystem(options) {
_super.call(this);
this.store = options.store;
// INVARIANT: Ensure that the root exists.
this.makeRootDirectory();
}
SyncKeyValueFileSystem.isAvailable = function () {
return true;
};
SyncKeyValueFileSystem.prototype.getName = function () {
return this.store.name();
};
SyncKeyValueFileSystem.prototype.isReadOnly = function () {
return false;
};
SyncKeyValueFileSystem.prototype.supportsSymlinks = function () {
return false;
};
SyncKeyValueFileSystem.prototype.supportsProps = function () {
return false;
};
SyncKeyValueFileSystem.prototype.supportsSynch = function () {
return true;
};
/**
* Checks if the root directory exists. Creates it if it doesn't.
*/
SyncKeyValueFileSystem.prototype.makeRootDirectory = function () {
var tx = this.store.beginTransaction('readwrite');
if (tx.get(ROOT_NODE_ID) === undefined) {
// Create new inode.
var currTime = (new Date()).getTime(), dirInode = new Inode(GenerateRandomID(), 4096, 511 | 16384 /* DIRECTORY */, currTime, currTime, currTime);
// If the root doesn't exist, the first random ID shouldn't exist,
// either.
tx.put(dirInode.id, new Buffer("{}"), false);
tx.put(ROOT_NODE_ID, dirInode.toBuffer(), false);
tx.commit();
}
};
/**
* Helper function for findINode.
* @param parent The parent directory of the file we are attempting to find.
* @param filename The filename of the inode we are attempting to find, minus
* the parent.
* @return string The ID of the file's inode in the file system.
*/
SyncKeyValueFileSystem.prototype._findINode = function (tx, parent, filename) {
var _this = this;
var read_directory = function (inode) {
// Get the root's directory listing.
var dirList = _this.getDirListing(tx, parent, inode);
// Get the file's ID.
if (dirList[filename]) {
return dirList[filename];
} else {
throw ApiError.ENOENT(path.resolve(parent, filename));
}
};
if (parent === '/') {
if (filename === '') {
// BASE CASE #1: Return the root's ID.
return ROOT_NODE_ID;
} else {
// BASE CASE #2: Find the item in the root ndoe.
return read_directory(this.getINode(tx, parent, ROOT_NODE_ID));
}
} else {
return read_directory(this.getINode(tx, parent + path.sep + filename, this._findINode(tx, path.dirname(parent), path.basename(parent))));
}
};
/**
* Finds the Inode of the given path.
* @param p The path to look up.
* @return The Inode of the path p.
* @todo memoize/cache
*/
SyncKeyValueFileSystem.prototype.findINode = function (tx, p) {
return this.getINode(tx, p, this._findINode(tx, path.dirname(p), path.basename(p)));
};
/**
* Given the ID of a node, retrieves the corresponding Inode.
* @param tx The transaction to use.
* @param p The corresponding path to the file (used for error messages).
* @param id The ID to look up.
*/
SyncKeyValueFileSystem.prototype.getINode = function (tx, p, id) {
var inode = tx.get(id);
if (inode === undefined) {
throw ApiError.ENOENT(p);
}
return Inode.fromBuffer(inode);
};
/**
* Given the Inode of a directory, retrieves the corresponding directory
* listing.
*/
SyncKeyValueFileSystem.prototype.getDirListing = function (tx, p, inode) {
if (!inode.isDirectory()) {
throw ApiError.ENOTDIR(p);
}
var data = tx.get(inode.id);
if (data === undefined) {
throw ApiError.ENOENT(p);
}
return JSON.parse(data.toString());
};
/**
* Creates a new node under a random ID. Retries 5 times before giving up in
* the exceedingly unlikely chance that we try to reuse a random GUID.
* @return The GUID that the data was stored under.
*/
SyncKeyValueFileSystem.prototype.addNewNode = function (tx, data) {
var retries = 0, currId;
while (retries < 5) {
try {
currId = GenerateRandomID();
tx.put(currId, data, false);
return currId;
} catch (e) {
// Ignore and reroll.
}
}
throw new ApiError(2 /* EIO */, 'Unable to commit data to key-value store.');
};
/**
* Commits a new file (well, a FILE or a DIRECTORY) to the file system with
* the given mode.
* Note: This will commit the transaction.
* @param p The path to the new file.
* @param type The type of the new file.
* @param mode The mode to create the new file with.
* @param data The data to store at the file's data node.
* @return The Inode for the new file.
*/
SyncKeyValueFileSystem.prototype.commitNewFile = function (tx, p, type, mode, data) {
var parentDir = path.dirname(p), fname = path.basename(p), parentNode = this.findINode(tx, parentDir), dirListing = this.getDirListing(tx, parentDir, parentNode), currTime = (new Date()).getTime();
// Invariant: The root always exists.
// If we don't check this prior to taking steps below, we will create a
// file with name '' in root should p == '/'.
if (p === '/') {
throw ApiError.EEXIST(p);
}
// Check if file already exists.
if (dirListing[fname]) {
throw ApiError.EEXIST(p);
}
try {
// Commit data.
var dataId = this.addNewNode(tx, data), fileNode = new Inode(dataId, data.length, mode | type, currTime, currTime, currTime), fileNodeId = this.addNewNode(tx, fileNode.toBuffer());
// Update and commit parent directory listing.
dirListing[fname] = fileNodeId;
tx.put(parentNode.id, new Buffer(JSON.stringify(dirListing)), true);
} catch (e) {
tx.abort();
throw e;
}
tx.commit();
return fileNode;
};
/**
* Delete all contents stored in the file system.
*/
SyncKeyValueFileSystem.prototype.empty = function () {
this.store.clear();
// INVARIANT: Root always exists.
this.makeRootDirectory();
};
SyncKeyValueFileSystem.prototype.renameSync = function (oldPath, newPath) {
var tx = this.store.beginTransaction('readwrite'), oldParent = path.dirname(oldPath), oldName = path.basename(oldPath), newParent = path.dirname(newPath), newName = path.basename(newPath), oldDirNode = this.findINode(tx, oldParent), oldDirList = this.getDirListing(tx, oldParent, oldDirNode);
if (!oldDirList[oldName]) {
throw ApiError.ENOENT(oldPath);
}
var nodeId = oldDirList[oldName];
delete oldDirList[oldName];
// Invariant: Can't move a folder inside itself.
// This funny little hack ensures that the check passes only if oldPath
// is a subpath of newParent. We append '/' to avoid matching folders that
// are a substring of the bottom-most folder in the path.
if ((newParent + '/').indexOf(oldPath + '/') === 0) {
throw new ApiError(5 /* EBUSY */, oldParent);
}
// Add newPath to parent's directory listing.
var newDirNode, newDirList;
if (newParent === oldParent) {
// Prevent us from re-grabbing the same directory listing, which still
// contains oldName.
newDirNode = oldDirNode;
newDirList = oldDirList;
} else {
newDirNode = this.findINode(tx, newParent);
newDirList = this.getDirListing(tx, newParent, newDirNode);
}
if (newDirList[newName]) {
// If it's a file, delete it.
var newNameNode = this.getINode(tx, newPath, newDirList[newName]);
if (newNameNode.isFile()) {
try {
tx.delete(newNameNode.id);
tx.delete(newDirList[newName]);
} catch (e) {
tx.abort();
throw e;
}
} else {
throw ApiError.EPERM(newPath);
}
}
newDirList[newName] = nodeId;
try {
tx.put(oldDirNode.id, new Buffer(JSON.stringify(oldDirList)), true);
tx.put(newDirNode.id, new Buffer(JSON.stringify(newDirList)), true);
} catch (e) {
tx.abort();
throw e;
}
tx.commit();
};
SyncKeyValueFileSystem.prototype.statSync = function (p, isLstat) {
// Get the inode to the item, convert it into a Stats object.
return this.findINode(this.store.beginTransaction('readonly'), p).toStats();
};
SyncKeyValueFileSystem.prototype.createFileSync = function (p, flag, mode) {
var tx = this.store.beginTransaction('readwrite'), data = new Buffer(0), newFile = this.commitNewFile(tx, p, 32768 /* FILE */, mode, data);
// Open the file.
return new SyncKeyValueFile(this, p, flag, newFile.toStats(), data);
};
SyncKeyValueFileSystem.prototype.openFileSync = function (p, flag) {
var tx = this.store.beginTransaction('readonly'), node = this.findINode(tx, p), data = tx.get(node.id);
if (data === undefined) {
throw ApiError.ENOENT(p);
}
return new SyncKeyValueFile(this, p, flag, node.toStats(), data);
};
/**
* Remove all traces of the given path from the file system.
* @param p The path to remove from the file system.
* @param isDir Does the path belong to a directory, or a file?
* @todo Update mtime.
*/
SyncKeyValueFileSystem.prototype.removeEntry = function (p, isDir) {
var tx = this.store.beginTransaction('readwrite'), parent = path.dirname(p), parentNode = this.findINode(tx, parent), parentListing = this.getDirListing(tx, parent, parentNode), fileName = path.basename(p);
if (!parentListing[fileName]) {
throw ApiError.ENOENT(p);
}
// Remove from directory listing of parent.
var fileNodeId = parentListing[fileName];
delete parentListing[fileName];
// Get file inode.
var fileNode = this.getINode(tx, p, fileNodeId);
if (!isDir && fileNode.isDirectory()) {
throw ApiError.EISDIR(p);
} else if (isDir && !fileNode.isDirectory()) {
throw ApiError.ENOTDIR(p);
}
try {
// Delete data.
tx.delete(fileNode.id);
// Delete node.
tx.delete(fileNodeId);
// Update directory listing.
tx.put(parentNode.id, new Buffer(JSON.stringify(parentListing)), true);
} catch (e) {
tx.abort();
throw e;
}
// Success.
tx.commit();
};
SyncKeyValueFileSystem.prototype.unlinkSync = function (p) {
this.removeEntry(p, false);
};
SyncKeyValueFileSystem.prototype.rmdirSync = function (p) {
this.removeEntry(p, true);
};
SyncKeyValueFileSystem.prototype.mkdirSync = function (p, mode) {
var tx = this.store.beginTransaction('readwrite'), data = new Buffer('{}');
this.commitNewFile(tx, p, 16384 /* DIRECTORY */, mode, data);
};
SyncKeyValueFileSystem.prototype.readdirSync = function (p) {
var tx = this.store.beginTransaction('readonly');
return Object.keys(this.getDirListing(tx, p, this.findINode(tx, p)));
};
SyncKeyValueFileSystem.prototype._syncSync = function (p, data, stats) {
// @todo Ensure mtime updates properly, and use that to determine if a data
// update is required.
var tx = this.store.beginTransaction('readwrite'), fileInodeId = this._findINode(tx, path.dirname(p), path.basename(p)), fileInode = this.getINode(tx, p, fileInodeId), inodeChanged = fileInode.update(stats);
try {
// Sync data.
tx.put(fileInode.id, data, true);
// Sync metadata.
if (inodeChanged) {
tx.put(fileInodeId, fileInode.toBuffer(), true);
}
} catch (e) {
tx.abort();
throw e;
}
tx.commit();
};
return SyncKeyValueFileSystem;
})(file_system.SynchronousFileSystem);
exports.SyncKeyValueFileSystem = SyncKeyValueFileSystem;
var AsyncKeyValueFile = (function (_super) {
__extends(AsyncKeyValueFile, _super);
function AsyncKeyValueFile(_fs, _path, _flag, _stat, contents) {
_super.call(this, _fs, _path, _flag, _stat, contents);
}
AsyncKeyValueFile.prototype.sync = function (cb) {
this._fs._sync(this._path, this._buffer, this._stat, cb);
};
AsyncKeyValueFile.prototype.close = function (cb) {
this.sync(cb);
};
return AsyncKeyValueFile;
})(preload_file.PreloadFile);
exports.AsyncKeyValueFile = AsyncKeyValueFile;
/**
* An "Asynchronous key-value file system". Stores data to/retrieves data from
* an underlying asynchronous key-value store.
*/
var AsyncKeyValueFileSystem = (function (_super) {
__extends(AsyncKeyValueFileSystem, _super);
function AsyncKeyValueFileSystem() {
_super.apply(this, arguments);
}
/**
* Initializes the file system. Typically called by subclasses' async
* constructors.
*/
AsyncKeyValueFileSystem.prototype.init = function (store, cb) {
this.store = store;
// INVARIANT: Ensure that the root exists.
this.makeRootDirectory(cb);
};
AsyncKeyValueFileSystem.isAvailable = function () {
return true;
};
AsyncKeyValueFileSystem.prototype.getName = function () {
return this.store.name();
};
AsyncKeyValueFileSystem.prototype.isReadOnly = function () {
return false;
};
AsyncKeyValueFileSystem.prototype.supportsSymlinks = function () {
return false;
};
AsyncKeyValueFileSystem.prototype.supportsProps = function () {
return false;
};
AsyncKeyValueFileSystem.prototype.supportsSynch = function () {
return false;
};
/**
* Checks if the root directory exists. Creates it if it doesn't.
*/
AsyncKeyValueFileSystem.prototype.makeRootDirectory = function (cb) {
var tx = this.store.beginTransaction('readwrite');
tx.get(ROOT_NODE_ID, function (e, data) {
if (e || data === undefined) {
// Create new inode.
var currTime = (new Date()).getTime(), dirInode = new Inode(GenerateRandomID(), 4096, 511 | 16384 /* DIRECTORY */, currTime, currTime, currTime);
// If the root doesn't exist, the first random ID shouldn't exist,
// either.
tx.put(dirInode.id, new Buffer("{}"), false, function (e) {
if (noErrorTx(e, tx, cb)) {
tx.put(ROOT_NODE_ID, dirInode.toBuffer(), false, function (e) {
if (e) {
tx.abort(function () {
cb(e);
});
} else {
tx.commit(cb);
}
});
}
});
} else {
// We're good.
tx.commit(cb);
}
});
};
/**
* Helper function for findINode.
* @param parent The parent directory of the file we are attempting to find.
* @param filename The filename of the inode we are attempting to find, minus
* the parent.
* @param cb Passed an error or the ID of the file's inode in the file system.
*/
AsyncKeyValueFileSystem.prototype._findINode = function (tx, parent, filename, cb) {
var _this = this;
var handle_directory_listings = function (e, inode, dirList) {
if (e) {
cb(e);
} else if (dirList[filename]) {
cb(null, dirList[filename]);
} else {
cb(ApiError.ENOENT(path.resolve(parent, filename)));
}
};
if (parent === '/') {
if (filename === '') {
// BASE CASE #1: Return the root's ID.
cb(null, ROOT_NODE_ID);
} else {
// BASE CASE #2: Find the item in the root node.
this.getINode(tx, parent, ROOT_NODE_ID, function (e, inode) {
if (noError(e, cb)) {
_this.getDirListing(tx, parent, inode, function (e, dirList) {
// handle_directory_listings will handle e for us.
handle_directory_listings(e, inode, dirList);
});
}
});
}
} else {
// Get the parent directory's INode, and find the file in its directory
// listing.
this.findINodeAndDirListing(tx, parent, handle_directory_listings);
}
};
/**
* Finds the Inode of the given path.
* @param p The path to look up.
* @param cb Passed an error or the Inode of the path p.
* @todo memoize/cache
*/
AsyncKeyValueFileSystem.prototype.findINode = function (tx, p, cb) {
var _this = this;
this._findINode(tx, path.dirname(p), path.basename(p), function (e, id) {
if (noError(e, cb)) {
_this.getINode(tx, p, id, cb);
}
});
};
/**
* Given the ID of a node, retrieves the corresponding Inode.
* @param tx The transaction to use.
* @param p The corresponding path to the file (used for error messages).
* @param id The ID to look up.
* @param cb Passed an error or the inode under the given id.
*/
AsyncKeyValueFileSystem.prototype.getINode = function (tx, p, id, cb) {
tx.get(id, function (e, data) {
if (noError(e, cb)) {
if (data === undefined) {
cb(ApiError.ENOENT(p));
} else {
cb(null, Inode.fromBuffer(data));
}
}
});
};
/**
* Given the Inode of a directory, retrieves the corresponding directory
* listing.
*/
AsyncKeyValueFileSystem.prototype.getDirListing = function (tx, p, inode, cb) {
if (!inode.isDirectory()) {
cb(ApiError.ENOTDIR(p));
} else {
tx.get(inode.id, function (e, data) {
if (noError(e, cb)) {
try {
cb(null, JSON.parse(data.toString()));
} catch (e) {
// Occurs when data is undefined, or corresponds to something other
// than a directory listing. The latter should never occur unless
// the file system is corrupted.
cb(ApiError.ENOENT(p));
}
}
});
}
};
/**
* Given a path to a directory, retrieves the corresponding INode and
* directory listing.
*/
AsyncKeyValueFileSystem.prototype.findINodeAndDirListing = function (tx, p, cb) {
var _this = this;
this.findINode(tx, p, function (e, inode) {
if (noError(e, cb)) {
_this.getDirListing(tx, p, inode, function (e, listing) {
if (noError(e, cb)) {
cb(null, inode, listing);
}
});
}
});
};
/**
* Adds a new node under a random ID. Retries 5 times before giving up in
* the exceedingly unlikely chance that we try to reuse a random GUID.
* @param cb Passed an error or the GUID that the data was stored under.
*/
AsyncKeyValueFileSystem.prototype.addNewNode = function (tx, data, cb) {
var retries = 0, currId, reroll = function () {
if (++retries === 5) {
// Max retries hit. Return with an error.
cb(new ApiError(2 /* EIO */, 'Unable to commit data to key-value store.'));
} else {
// Try again.
currId = GenerateRandomID();
tx.put(currId, data, false, function (e, committed) {
if (e || !committed) {
reroll();
} else {
// Successfully stored under 'currId'.
cb(null, currId);
}
});
}
};
reroll();
};
/**
* Commits a new file (well, a FILE or a DIRECTORY) to the file system with
* the given mode.
* Note: This will commit the transaction.
* @param p The path to the new file.
* @param type The type of the new file.
* @param mode The mode to create the new file with.
* @param data The data to store at the file's data node.
* @param cb Passed an error or the Inode for the new file.
*/
AsyncKeyValueFileSystem.prototype.commitNewFile = function (tx, p, type, mode, data, cb) {
var _this = this;
var parentDir = path.dirname(p), fname = path.basename(p), currTime = (new Date()).getTime();
// Invariant: The root always exists.
// If we don't check this prior to taking steps below, we will create a
// file with name '' in root should p == '/'.
if (p === '/') {
return cb(ApiError.EEXIST(p));
}
// Let's build a pyramid of code!
// Step 1: Get the parent directory's inode and directory listing
this.findINodeAndDirListing(tx, parentDir, function (e, parentNode, dirListing) {
if (noErrorTx(e, tx, cb)) {
if (dirListing[fname]) {
// File already exists.
tx.abort(function () {
cb(ApiError.EEXIST(p));
});
} else {
// Step 2: Commit data to store.
_this.addNewNode(tx, data, function (e, dataId) {
if (noErrorTx(e, tx, cb)) {
// Step 3: Commit the file's inode to the store.
var fileInode = new Inode(dataId, data.length, mode | type, currTime, currTime, currTime);
_this.addNewNode(tx, fileInode.toBuffer(), function (e, fileInodeId) {
if (noErrorTx(e, tx, cb)) {
// Step 4: Update parent directory's listing.
dirListing[fname] = fileInodeId;
tx.put(parentNode.id, new Buffer(JSON.stringify(dirListing)), true, function (e) {
if (noErrorTx(e, tx, cb)) {
// Step 5: Commit and return the new inode.
tx.commit(function (e) {
if (noErrorTx(e, tx, cb)) {
cb(null, fileInode);
}
});
}
});
}
});
}
});
}
}
});
};
/**
* Delete all contents stored in the file system.
*/
AsyncKeyValueFileSystem.prototype.empty = function (cb) {
var _this = this;
this.store.clear(function (e) {
if (noError(e, cb)) {
// INVARIANT: Root always exists.
_this.makeRootDirectory(cb);
}
});
};
AsyncKeyValueFileSystem.prototype.rename = function (oldPath, newPath, cb) {
var _this = this;
var tx = this.store.beginTransaction('readwrite'), oldParent = path.dirname(oldPath), oldName = path.basename(oldPath), newParent = path.dirname(newPath), newName = path.basename(newPath), inodes = {}, lists = {}, errorOccurred = false;
// Invariant: Can't move a folder inside itself.
// This funny little hack ensures that the check passes only if oldPath
// is a subpath of newParent. We append '/' to avoid matching folders that
// are a substring of the bottom-most folder in the path.
if ((newParent + '/').indexOf(oldPath + '/') === 0) {
return cb(new ApiError(5 /* EBUSY */, oldParent));
}
/**
* Responsible for Phase 2 of the rename operation: Modifying and
* committing the directory listings. Called once we have successfully
* retrieved both the old and new parent's inodes and listings.
*/
var theOleSwitcharoo = function () {
// Sanity check: Ensure both paths are present, and no error has occurred.
if (errorOccurred || !lists.hasOwnProperty(oldParent) || !lists.hasOwnProperty(newParent)) {
return;
}
var oldParentList = lists[oldParent], oldParentINode = inodes[oldParent], newParentList = lists[newParent], newParentINode = inodes[newParent];
// Delete file from old parent.
if (!oldParentList[oldName]) {
cb(ApiError.ENOENT(oldPath));
} else {
var fileId = oldParentList[oldName];
delete oldParentList[oldName];
// Finishes off the renaming process by adding the file to the new
// parent.
var completeRename = function () {
newParentList[newName] = fileId;
// Commit old parent's list.
tx.put(oldParentINode.id, new Buffer(JSON.stringify(oldParentList)), true, function (e) {
if (noErrorTx(e, tx, cb)) {
if (oldParent === newParent) {
// DONE!
tx.commit(cb);
} else {
// Commit new parent's list.
tx.put(newParentINode.id, new Buffer(JSON.stringify(newParentList)), true, function (e) {
if (noErrorTx(e, tx, cb)) {
tx.commit(cb);
}
});
}
}
});
};
if (newParentList[newName]) {
// 'newPath' already exists. Check if it's a file or a directory, and
// act accordingly.
_this.getINode(tx, newPath, newParentList[newName], function (e, inode) {
if (noErrorTx(e, tx, cb)) {
if (inode.isFile()) {
// Delete the file and continue.
tx.delete(inode.id, function (e) {
if (noErrorTx(e, tx, cb)) {
tx.delete(newParentList[newName], function (e) {
if (noErrorTx(e, tx, cb)) {
completeRename();
}
});
}
});
} else {
// Can't overwrite a directory using rename.
tx.abort(function (e) {
cb(ApiError.EPERM(newPath));
});
}
}
});
} else {
completeRename();
}
}
};
/**
* Grabs a path's inode and directory listing, and shoves it into the
* inodes and lists hashes.
*/
var processInodeAndListings = function (p) {
_this.findINodeAndDirListing(tx, p, function (e, node, dirList) {
if (e) {
if (!errorOccurred) {
errorOccurred = true;
tx.abort(function () {
cb(e);
});
}
// If error has occurred already, just stop here.
} else {
inodes[p] = node;
lists[p] = dirList;
theOleSwitcharoo();
}
});
};
processInodeAndListings(oldParent);
if (oldParent !== newParent) {
processInodeAndListings(newParent);
}
};
AsyncKeyValueFileSystem.prototype.stat = function (p, isLstat, cb) {
var tx = this.store.beginTransaction('readonly');
this.findINode(tx, p, function (e, inode) {
if (noError(e, cb)) {
cb(null, inode.toStats());
}
});
};
AsyncKeyValueFileSystem.prototype.createFile = function (p, flag, mode, cb) {
var _this = this;
var tx = this.store.beginTransaction('readwrite'), data = new Buffer(0);
this.commitNewFile(tx, p, 32768 /* FILE */, mode, data, function (e, newFile) {
if (noError(e, cb)) {
cb(null, new AsyncKeyValueFile(_this, p, flag, newFile.toStats(), data));
}
});
};
AsyncKeyValueFileSystem.prototype.openFile = function (p, flag, cb) {
var _this = this;
var tx = this.store.beginTransaction('readonly');
// Step 1: Grab the file's inode.
this.findINode(tx, p, function (e, inode) {
if (noError(e, cb)) {
// Step 2: Grab the file's data.
tx.get(inode.id, function (e, data) {
if (noError(e, cb)) {
if (data === undefined) {
cb(ApiError.ENOENT(p));
} else {
cb(null, new AsyncKeyValueFile(_this, p, flag, inode.toStats(), data));
}
}
});
}
});
};
/**
* Remove all traces of the given path from the file system.
* @param p The path to remove from the file system.
* @param isDir Does the path belong to a directory, or a file?
* @todo Update mtime.
*/
AsyncKeyValueFileSystem.prototype.removeEntry = function (p, isDir, cb) {
var _this = this;
var tx = this.store.beginTransaction('readwrite'), parent = path.dirname(p), fileName = path.basename(p);
// Step 1: Get parent directory's node and directory listing.
this.findINodeAndDirListing(tx, parent, function (e, parentNode, parentListing) {
if (noErrorTx(e, tx, cb)) {
if (!parentListing[fileName]) {
tx.abort(function () {
cb(ApiError.ENOENT(p));
});
} else {
// Remove from directory listing of parent.
var fileNodeId = parentListing[fileName];
delete parentListing[fileName];
// Step 2: Get file inode.
_this.getINode(tx, p, fileNodeId, function (e, fileNode) {
if (noErrorTx(e, tx, cb)) {
if (!isDir && fileNode.isDirectory()) {
tx.abort(function () {
cb(ApiError.EISDIR(p));
});
} else if (isDir && !fileNode.isDirectory()) {
tx.abort(function () {
cb(ApiError.ENOTDIR(p));
});
} else {
// Step 3: Delete data.
tx.delete(fileNode.id, function (e) {
if (noErrorTx(e, tx, cb)) {
// Step 4: Delete node.
tx.delete(fileNodeId, function (e) {
if (noErrorTx(e, tx, cb)) {
// Step 5: Update directory listing.
tx.put(parentNode.id, new Buffer(JSON.stringify(parentListing)), true, function (e) {
if (noErrorTx(e, tx, cb)) {
tx.commit(cb);
}
});
}
});
}
});
}
}
});
}
}
});
};
AsyncKeyValueFileSystem.prototype.unlink = function (p, cb) {
this.removeEntry(p, false, cb);
};
AsyncKeyValueFileSystem.prototype.rmdir = function (p, cb) {
this.removeEntry(p, true, cb);
};
AsyncKeyValueFileSystem.prototype.mkdir = function (p, mode, cb) {
var tx = this.store.beginTransaction('readwrite'), data = new Buffer('{}');
this.commitNewFile(tx, p, 16384 /* DIRECTORY */, mode, data, cb);
};
AsyncKeyValueFileSystem.prototype.readdir = function (p, cb) {
var _this = this;
var tx = this.store.beginTransaction('readonly');
this.findINode(tx, p, function (e, inode) {
if (noError(e, cb)) {
_this.getDirListing(tx, p, inode, function (e, dirListing) {
if (noError(e, cb)) {
cb(null, Object.keys(dirListing));
}
});
}
});
};
AsyncKeyValueFileSystem.prototype._sync = function (p, data, stats, cb) {
var _this = this;
// @todo Ensure mtime updates properly, and use that to determine if a data
// update is required.
var tx = this.store.beginTransaction('readwrite');
// Step 1: Get the file node's ID.
this._findINode(tx, path.dirname(p), path.basename(p), function (e, fileInodeId) {
if (noErrorTx(e, tx, cb)) {
// Step 2: Get the file inode.
_this.getINode(tx, p, fileInodeId, function (e, fileInode) {
if (noErrorTx(e, tx, cb)) {
var inodeChanged = fileInode.update(stats);
// Step 3: Sync the data.
tx.put(fileInode.id, data, true, function (e) {
if (noErrorTx(e, tx, cb)) {
// Step 4: Sync the metadata (if it changed)!
if (inodeChanged) {
tx.put(fileInodeId, fileInode.toBuffer(), true, function (e) {
if (noErrorTx(e, tx, cb)) {
tx.commit(cb);
}
});
} else {
// No need to sync metadata; return.
tx.commit(cb);
}
}
});
}
});
}
});
};
return AsyncKeyValueFileSystem;
})(file_system.BaseFileSystem);
exports.AsyncKeyValueFileSystem = AsyncKeyValueFileSystem;
});
//# sourceMappingURL=key_value_filesystem.js.map
;
define('core/global',["require", "exports"], function(require, exports) {
/**
* Exports the global scope variable.
* In the main browser thread, this is "window".
* In a WebWorker, this is "self".
* In Node, this is "global".
*/
var toExport;
if (typeof (window) !== 'undefined') {
toExport = window;
} else if (typeof (self) !== 'undefined') {
toExport = self;
} else {
toExport = global;
}
return toExport;
});
//# sourceMappingURL=global.js.map
;
var __extends = this.__extends || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
define('backend/IndexedDB',["require", "exports", '../core/buffer', '../core/browserfs', '../generic/key_value_filesystem', '../core/api_error', '../core/buffer_core_arraybuffer', '../core/global'], function(require, exports, buffer, browserfs, kvfs, api_error, buffer_core_arraybuffer, global) {
var Buffer = buffer.Buffer, ApiError = api_error.ApiError, ErrorCode = api_error.ErrorCode, indexedDB = global.indexedDB || global.mozIndexedDB || global.webkitIndexedDB || global.msIndexedDB;
/**
* Converts a DOMException or a DOMError from an IndexedDB event into a
* standardized BrowserFS API error.
*/
function convertError(e, message) {
if (typeof message === "undefined") { message = e.toString(); }
switch (e.name) {
case "NotFoundError":
return new ApiError(1 /* ENOENT */, message);
case "QuotaExceededError":
return new ApiError(11 /* ENOSPC */, message);
default:
// The rest do not seem to map cleanly to standard error codes.
return new ApiError(2 /* EIO */, message);
}
}
/**
* Produces a new onerror handler for IDB. Our errors are always fatal, so we
* handle them generically: Call the user-supplied callback with a translated
* version of the error, and let the error bubble up.
*/
function onErrorHandler(cb, code, message) {
if (typeof code === "undefined") { code = 2 /* EIO */; }
if (typeof message === "undefined") { message = null; }
return function (e) {
// Prevent the error from canceling the transaction.
e.preventDefault();
cb(new ApiError(code, message));
};
}
/**
* Converts a NodeBuffer into an ArrayBuffer.
*/
function buffer2arraybuffer(buffer) {
// XXX: Typing hack.
var backing_mem = buffer.getBufferCore();
if (!(backing_mem instanceof buffer_core_arraybuffer.BufferCoreArrayBuffer)) {
// Copy into an ArrayBuffer-backed Buffer.
buffer = new Buffer(this._buffer.length);
this._buffer.copy(buffer);
backing_mem = buffer.getBufferCore();
}
// Reach into the BC, grab the DV.
var dv = backing_mem.getDataView();
return dv.buffer;
}
var IndexedDBROTransaction = (function () {
function IndexedDBROTransaction(tx, store) {
this.tx = tx;
this.store = store;
}
IndexedDBROTransaction.prototype.get = function (key, cb) {
try {
var r = this.store.get(key);
r.onerror = onErrorHandler(cb);
r.onsuccess = function (event) {
// IDB returns the value 'undefined' when you try to get keys that
// don't exist. The caller expects this behavior.
var result = event.target.result;
if (result === undefined) {
cb(null, result);
} else {
// IDB data is stored as an ArrayBuffer
cb(null, new Buffer(result));
}
};
} catch (e) {
cb(convertError(e));
}
};
return IndexedDBROTransaction;
})();
exports.IndexedDBROTransaction = IndexedDBROTransaction;
var IndexedDBRWTransaction = (function (_super) {
__extends(IndexedDBRWTransaction, _super);
function IndexedDBRWTransaction(tx, store) {
_super.call(this, tx, store);
}
IndexedDBRWTransaction.prototype.put = function (key, data, overwrite, cb) {
try {
var arraybuffer = buffer2arraybuffer(data), r;
if (overwrite) {
r = this.store.put(arraybuffer, key);
} else {
// 'add' will never overwrite an existing key.
r = this.store.add(arraybuffer, key);
}
// XXX: NEED TO RETURN FALSE WHEN ADD HAS A KEY CONFLICT. NO ERROR.
r.onerror = onErrorHandler(cb);
r.onsuccess = function (event) {
cb(null, true);
};
} catch (e) {
cb(convertError(e));
}
};
IndexedDBRWTransaction.prototype.delete = function (key, cb) {
try {
var r = this.store.delete(key);
r.onerror = onErrorHandler(cb);
r.onsuccess = function (event) {
cb();
};
} catch (e) {
cb(convertError(e));
}
};
IndexedDBRWTransaction.prototype.commit = function (cb) {
// Return to the event loop to commit the transaction.
setTimeout(cb, 0);
};
IndexedDBRWTransaction.prototype.abort = function (cb) {
var _e;
try {
this.tx.abort();
} catch (e) {
_e = convertError(e);
} finally {
cb(_e);
}
};
return IndexedDBRWTransaction;
})(IndexedDBROTransaction);
exports.IndexedDBRWTransaction = IndexedDBRWTransaction;
var IndexedDBStore = (function () {
/**
* Constructs an IndexedDB file system.
* @param cb Called once the database is instantiated and ready for use.
* Passes an error if there was an issue instantiating the database.
* @param objectStoreName The name of this file system. You can have
* multiple IndexedDB file systems operating at once, but each must have
* a different name.
*/
function IndexedDBStore(cb, storeName) {
if (typeof storeName === "undefined") { storeName = 'browserfs'; }
var _this = this;
this.storeName = storeName;
var openReq = indexedDB.open(this.storeName, 1);
openReq.onupgradeneeded = function (event) {
var db = event.target.result;
// Huh. This should never happen; we're at version 1. Why does another
// database exist?
if (db.objectStoreNames.contains(_this.storeName)) {
db.deleteObjectStore(_this.storeName);
}
db.createObjectStore(_this.storeName);
};
openReq.onsuccess = function (event) {
_this.db = event.target.result;
cb(null, _this);
};
openReq.onerror = onErrorHandler(cb, 4 /* EACCES */);
}
IndexedDBStore.prototype.name = function () {
return "IndexedDB - " + this.storeName;
};
IndexedDBStore.prototype.clear = function (cb) {
try {
var tx = this.db.transaction(this.storeName, 'readwrite'), objectStore = tx.objectStore(this.storeName), r = objectStore.clear();
r.onsuccess = function (event) {
// Use setTimeout to commit transaction.
setTimeout(cb, 0);
};
r.onerror = onErrorHandler(cb);
} catch (e) {
cb(convertError(e));
}
};
IndexedDBStore.prototype.beginTransaction = function (type) {
if (typeof type === "undefined") { type = 'readonly'; }
var tx = this.db.transaction(this.storeName, type), objectStore = tx.objectStore(this.storeName);
if (type === 'readwrite') {
return new IndexedDBRWTransaction(tx, objectStore);
} else if (type === 'readonly') {
return new IndexedDBROTransaction(tx, objectStore);
} else {
throw new ApiError(9 /* EINVAL */, 'Invalid transaction type.');
}
};
return IndexedDBStore;
})();
exports.IndexedDBStore = IndexedDBStore;
/**
* A file system that uses the IndexedDB key value file system.
*/
var IndexedDBFileSystem = (function (_super) {
__extends(IndexedDBFileSystem, _super);
function IndexedDBFileSystem(cb, storeName) {
var _this = this;
_super.call(this);
new IndexedDBStore(function (e, store) {
if (e) {
cb(e);
} else {
_this.init(store, function (e) {
cb(e, _this);
});
}
}, storeName);
}
IndexedDBFileSystem.isAvailable = function () {
return typeof indexedDB !== 'undefined';
};
return IndexedDBFileSystem;
})(kvfs.AsyncKeyValueFileSystem);
exports.IndexedDBFileSystem = IndexedDBFileSystem;
browserfs.registerFileSystem('IndexedDB', IndexedDBFileSystem);
});
//# sourceMappingURL=IndexedDB.js.map
;
define('generic/file_index',["require", "exports", '../core/node_fs_stats', '../core/node_path'], function(require, exports, node_fs_stats, node_path) {
var Stats = node_fs_stats.Stats;
var path = node_path.path;
/**
* A simple class for storing a filesystem index. Assumes that all paths passed
* to it are *absolute* paths.
*
* Can be used as a partial or a full index, although care must be taken if used
* for the former purpose, especially when directories are concerned.
*/
var FileIndex = (function () {
/**
* Constructs a new FileIndex.
*/
function FileIndex() {
// _index is a single-level key,value store that maps *directory* paths to
// DirInodes. File information is only contained in DirInodes themselves.
this._index = {};
// Create the root directory.
this.addPath('/', new DirInode());
}
/**
* Split into a (directory path, item name) pair
*/
FileIndex.prototype._split_path = function (p) {
var dirpath = path.dirname(p);
var itemname = p.substr(dirpath.length + (dirpath === "/" ? 0 : 1));
return [dirpath, itemname];
};
/**
* Runs the given function over all files in the index.
*/
FileIndex.prototype.fileIterator = function (cb) {
for (var path in this._index) {
var dir = this._index[path];
var files = dir.getListing();
for (var i = 0; i < files.length; i++) {
var item = dir.getItem(files[i]);
if (item.isFile()) {
cb(item.getData());
}
}
}
};
/**
* Adds the given absolute path to the index if it is not already in the index.
* Creates any needed parent directories.
* @param [String] path The path to add to the index.
* @param [BrowserFS.FileInode | BrowserFS.DirInode] inode The inode for the
* path to add.
* @return [Boolean] 'True' if it was added or already exists, 'false' if there
* was an issue adding it (e.g. item in path is a file, item exists but is
* different).
* @todo If adding fails and implicitly creates directories, we do not clean up
* the new empty directories.
*/
FileIndex.prototype.addPath = function (path, inode) {
if (inode == null) {
throw new Error('Inode must be specified');
}
if (path[0] !== '/') {
throw new Error('Path must be absolute, got: ' + path);
}
// Check if it already exists.
if (this._index.hasOwnProperty(path)) {
return this._index[path] === inode;
}
var splitPath = this._split_path(path);
var dirpath = splitPath[0];
var itemname = splitPath[1];
// Try to add to its parent directory first.
var parent = this._index[dirpath];
if (parent === undefined && path !== '/') {
// Create parent.
parent = new DirInode();
if (!this.addPath(dirpath, parent)) {
return false;
}
}
// Add myself to my parent.
if (path !== '/') {
if (!parent.addItem(itemname, inode)) {
return false;
}
}
// If I'm a directory, add myself to the index.
if (!inode.isFile()) {
this._index[path] = inode;
}
return true;
};
/**
* Removes the given path. Can be a file or a directory.
* @return [BrowserFS.FileInode | BrowserFS.DirInode | null] The removed item,
* or null if it did not exist.
*/
FileIndex.prototype.removePath = function (path) {
var splitPath = this._split_path(path);
var dirpath = splitPath[0];
var itemname = splitPath[1];
// Try to remove it from its parent directory first.
var parent = this._index[dirpath];
if (parent === undefined) {
return null;
}
// Remove myself from my parent.
var inode = parent.remItem(itemname);
if (inode === null) {
return null;
}
// If I'm a directory, remove myself from the index, and remove my children.
if (!inode.isFile()) {
var dirInode = inode;
var children = dirInode.getListing();
for (var i = 0; i < children.length; i++) {
this.removePath(path + '/' + children[i]);
}
// Remove the directory from the index, unless it's the root.
if (path !== '/') {
delete this._index[path];
}
}
return inode;
};
/**
* Retrieves the directory listing of the given path.
* @return [String[]] An array of files in the given path, or 'null' if it does
* not exist.
*/
FileIndex.prototype.ls = function (path) {
var item = this._index[path];
if (item === undefined) {
return null;
}
return item.getListing();
};
/**
* Returns the inode of the given item.
* @param [String] path
* @return [BrowserFS.FileInode | BrowserFS.DirInode | null] Returns null if
* the item does not exist.
*/
FileIndex.prototype.getInode = function (path) {
var splitPath = this._split_path(path);
var dirpath = splitPath[0];
var itemname = splitPath[1];
// Retrieve from its parent directory.
var parent = this._index[dirpath];
if (parent === undefined) {
return null;
}
// Root case
if (dirpath === path) {
return parent;
}
return parent.getItem(itemname);
};
/**
* Static method for constructing indices from a JSON listing.
* @param [Object] listing Directory listing generated by tools/XHRIndexer.coffee
* @return [BrowserFS.FileIndex] A new FileIndex object.
*/
FileIndex.from_listing = function (listing) {
var idx = new FileIndex();
// Add a root DirNode.
var rootInode = new DirInode();
idx._index['/'] = rootInode;
var queue = [['', listing, rootInode]];
while (queue.length > 0) {
var inode;
var next = queue.pop();
var pwd = next[0];
var tree = next[1];
var parent = next[2];
for (var node in tree) {
var children = tree[node];
var name = "" + pwd + "/" + node;
if (children != null) {
idx._index[name] = inode = new DirInode();
queue.push([name, children, inode]);
} else {
// This inode doesn't have correct size information, noted with -1.
inode = new FileInode(new Stats(32768 /* FILE */, -1, 0x16D));
}
if (parent != null) {
parent._ls[node] = inode;
}
}
}
return idx;
};
return FileIndex;
})();
exports.FileIndex = FileIndex;
/**
* Inode for a file. Stores an arbitrary (filesystem-specific) data payload.
*/
var FileInode = (function () {
function FileInode(data) {
this.data = data;
}
FileInode.prototype.isFile = function () {
return true;
};
FileInode.prototype.isDir = function () {
return false;
};
FileInode.prototype.getData = function () {
return this.data;
};
FileInode.prototype.setData = function (data) {
this.data = data;
};
return FileInode;
})();
exports.FileInode = FileInode;
/**
* Inode for a directory. Currently only contains the directory listing.
*/
var DirInode = (function () {
/**
* Constructs an inode for a directory.
*/
function DirInode() {
this._ls = {};
}
DirInode.prototype.isFile = function () {
return false;
};
DirInode.prototype.isDir = function () {
return true;
};
/**
* Return a Stats object for this inode.
* @todo Should probably remove this at some point. This isn't the
* responsibility of the FileIndex.
* @return [BrowserFS.node.fs.Stats]
*/
DirInode.prototype.getStats = function () {
return new Stats(16384 /* DIRECTORY */, 4096, 0x16D);
};
/**
* Returns the directory listing for this directory. Paths in the directory are
* relative to the directory's path.
* @return [String[]] The directory listing for this directory.
*/
DirInode.prototype.getListing = function () {
return Object.keys(this._ls);
};
/**
* Returns the inode for the indicated item, or null if it does not exist.
* @param [String] p Name of item in this directory.
* @return [BrowserFS.FileInode | BrowserFS.DirInode | null]
*/
DirInode.prototype.getItem = function (p) {
var _ref;
return (_ref = this._ls[p]) != null ? _ref : null;
};
/**
* Add the given item to the directory listing. Note that the given inode is
* not copied, and will be mutated by the DirInode if it is a DirInode.
* @param [String] p Item name to add to the directory listing.
* @param [BrowserFS.FileInode | BrowserFS.DirInode] inode The inode for the
* item to add to the directory inode.
* @return [Boolean] True if it was added, false if it already existed.
*/
DirInode.prototype.addItem = function (p, inode) {
if (p in this._ls) {
return false;
}
this._ls[p] = inode;
return true;
};
/**
* Removes the given item from the directory listing.
* @param [String] p Name of item to remove from the directory listing.
* @return [BrowserFS.FileInode | BrowserFS.DirInode | null] Returns the item
* removed, or null if the item did not exist.
*/
DirInode.prototype.remItem = function (p) {
var item = this._ls[p];
if (item === undefined) {
return null;
}
delete this._ls[p];
return item;
};
return DirInode;
})();
exports.DirInode = DirInode;
});
//# sourceMappingURL=file_index.js.map
;
/**
* Grab bag of utility functions used across the code.
*/
define('core/util',["require", "exports"], function(require, exports) {
/**
* Estimates the size of a JS object.
* @param {Object} object - the object to measure.
* @return {Number} estimated object size.
* @see http://stackoverflow.com/a/11900218/10601
*/
function roughSizeOfObject(object) {
var bytes, key, objectList, prop, stack, value;
objectList = [];
stack = [object];
bytes = 0;
while (stack.length !== 0) {
value = stack.pop();
if (typeof value === 'boolean') {
bytes += 4;
} else if (typeof value === 'string') {
bytes += value.length * 2;
} else if (typeof value === 'number') {
bytes += 8;
} else if (typeof value === 'object' && objectList.indexOf(value) < 0) {
objectList.push(value);
bytes += 4;
for (key in value) {
prop = value[key];
bytes += key.length * 2;
stack.push(prop);
}
}
}
return bytes;
}
exports.roughSizeOfObject = roughSizeOfObject;
/**
* Checks for any IE version, including IE11 which removed MSIE from the
* userAgent string.
*/
exports.isIE = (/(msie) ([\w.]+)/.exec(navigator.userAgent.toLowerCase()) != null || navigator.userAgent.indexOf('Trident') !== -1);
});
//# sourceMappingURL=util.js.map
;
/**
* Contains utility methods for performing a variety of tasks with
* XmlHttpRequest across browsers.
*/
define('generic/xhr',["require", "exports", '../core/util', '../core/buffer', '../core/api_error'], function(require, exports, util, buffer, api_error) {
var ApiError = api_error.ApiError;
var ErrorCode = api_error.ErrorCode;
var Buffer = buffer.Buffer;
// Converts 'responseBody' in IE into the equivalent 'responseText' that other
// browsers would generate.
function getIEByteArray(IEByteArray) {
var rawBytes = IEBinaryToArray_ByteStr(IEByteArray);
var lastChr = IEBinaryToArray_ByteStr_Last(IEByteArray);
var data_str = rawBytes.replace(/[\s\S]/g, function (match) {
var v = match.charCodeAt(0);
return String.fromCharCode(v & 0xff, v >> 8);
}) + lastChr;
var data_array = new Array(data_str.length);
for (var i = 0; i < data_str.length; i++) {
data_array[i] = data_str.charCodeAt(i);
}
return data_array;
}
function downloadFileIE(async, p, type, cb) {
switch (type) {
case 'buffer':
case 'json':
break;
default:
return cb(new ApiError(9 /* EINVAL */, "Invalid download type: " + type));
}
var req = new XMLHttpRequest();
req.open('GET', p, async);
req.setRequestHeader("Accept-Charset", "x-user-defined");
req.onreadystatechange = function (e) {
var data_array;
if (req.readyState === 4) {
if (req.status === 200) {
switch (type) {
case 'buffer':
data_array = getIEByteArray(req.responseBody);
return cb(null, new Buffer(data_array));
case 'json':
return cb(null, JSON.parse(req.responseText));
}
} else {
return cb(new ApiError(req.status, "XHR error."));
}
}
};
req.send();
}
function asyncDownloadFileIE(p, type, cb) {
downloadFileIE(true, p, type, cb);
}
function syncDownloadFileIE(p, type) {
var rv;
downloadFileIE(false, p, type, function (err, data) {
if (err)
throw err;
rv = data;
});
return rv;
}
function asyncDownloadFileModern(p, type, cb) {
var req = new XMLHttpRequest();
req.open('GET', p, true);
var jsonSupported = true;
switch (type) {
case 'buffer':
req.responseType = 'arraybuffer';
break;
case 'json':
try {
req.responseType = 'json';
jsonSupported = req.responseType === 'json';
} catch (e) {
jsonSupported = false;
}
break;
default:
return cb(new ApiError(9 /* EINVAL */, "Invalid download type: " + type));
}
req.onreadystatechange = function (e) {
if (req.readyState === 4) {
if (req.status === 200) {
switch (type) {
case 'buffer':
// XXX: WebKit-based browsers return *null* when XHRing an empty file.
return cb(null, new Buffer(req.response ? req.response : 0));
case 'json':
if (jsonSupported) {
return cb(null, req.response);
} else {
return cb(null, JSON.parse(req.responseText));
}
}
} else {
return cb(new ApiError(req.status, "XHR error."));
}
}
};
req.send();
}
function syncDownloadFileModern(p, type) {
var req = new XMLHttpRequest();
req.open('GET', p, false);
// On most platforms, we cannot set the responseType of synchronous downloads.
// @todo Test for this; IE10 allows this, as do older versions of Chrome/FF.
var data = null;
var err = null;
// Classic hack to download binary data as a string.
req.overrideMimeType('text/plain; charset=x-user-defined');
req.onreadystatechange = function (e) {
if (req.readyState === 4) {
if (req.status === 200) {
switch (type) {
case 'buffer':
// Convert the text into a buffer.
var text = req.responseText;
data = new Buffer(text.length);
for (var i = 0; i < text.length; i++) {
// This will automatically throw away the upper bit of each
// character for us.
data.writeUInt8(text.charCodeAt(i), i);
}
return;
case 'json':
data = JSON.parse(req.responseText);
return;
}
} else {
err = new ApiError(req.status, "XHR error.");
return;
}
}
};
req.send();
if (err) {
throw err;
}
return data;
}
function syncDownloadFileIE10(p, type) {
var req = new XMLHttpRequest();
req.open('GET', p, false);
switch (type) {
case 'buffer':
req.responseType = 'arraybuffer';
break;
case 'json':
break;
default:
throw new ApiError(9 /* EINVAL */, "Invalid download type: " + type);
}
var data;
var err;
req.onreadystatechange = function (e) {
if (req.readyState === 4) {
if (req.status === 200) {
switch (type) {
case 'buffer':
data = new Buffer(req.response);
break;
case 'json':
data = JSON.parse(req.response);
break;
}
} else {
err = new ApiError(req.status, "XHR error.");
}
}
};
req.send();
if (err) {
throw err;
}
return data;
}
function getFileSize(async, p, cb) {
var req = new XMLHttpRequest();
req.open('HEAD', p, async);
req.onreadystatechange = function (e) {
if (req.readyState === 4) {
if (req.status == 200) {
try {
return cb(null, parseInt(req.getResponseHeader('Content-Length'), 10));
} catch (e) {
// In the event that the header isn't present or there is an error...
return cb(new ApiError(2 /* EIO */, "XHR HEAD error: Could not read content-length."));
}
} else {
return cb(new ApiError(req.status, "XHR HEAD error."));
}
}
};
req.send();
}
/**
* Asynchronously download a file as a buffer or a JSON object.
* Note that the third function signature with a non-specialized type is
* invalid, but TypeScript requires it when you specialize string arguments to
* constants.
*/
exports.asyncDownloadFile = (util.isIE && typeof Blob === 'undefined') ? asyncDownloadFileIE : asyncDownloadFileModern;
/**
* Synchronously download a file as a buffer or a JSON object.
* Note that the third function signature with a non-specialized type is
* invalid, but TypeScript requires it when you specialize string arguments to
* constants.
*/
exports.syncDownloadFile = (util.isIE && typeof Blob === 'undefined') ? syncDownloadFileIE : (util.isIE && typeof Blob !== 'undefined') ? syncDownloadFileIE10 : syncDownloadFileModern;
/**
* Synchronously retrieves the size of the given file in bytes.
*/
function getFileSizeSync(p) {
var rv;
getFileSize(false, p, function (err, size) {
if (err) {
throw err;
}
rv = size;
});
return rv;
}
exports.getFileSizeSync = getFileSizeSync;
/**
* Asynchronously retrieves the size of the given file in bytes.
*/
function getFileSizeAsync(p, cb) {
getFileSize(true, p, cb);
}
exports.getFileSizeAsync = getFileSizeAsync;
});
//# sourceMappingURL=xhr.js.map
;
var __extends = this.__extends || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
define('backend/XmlHttpRequest',["require", "exports", '../core/file_system', '../generic/file_index', '../core/buffer', '../core/api_error', '../core/file_flag', '../generic/preload_file', '../core/browserfs', '../generic/xhr'], function(require, exports, file_system, file_index, buffer, api_error, file_flag, preload_file, browserfs, xhr) {
var Buffer = buffer.Buffer;
var ApiError = api_error.ApiError;
var ErrorCode = api_error.ErrorCode;
var FileFlag = file_flag.FileFlag;
var ActionType = file_flag.ActionType;
/**
* A simple filesystem backed by XmlHttpRequests.
*/
var XmlHttpRequest = (function (_super) {
__extends(XmlHttpRequest, _super);
/**
* Constructs the file system.
* @param [String] listing_url The path to the JSON file index generated by
* tools/XHRIndexer.coffee. This can be relative to the current webpage URL
* or absolutely specified.
* @param [String] prefix_url The url prefix to use for all web-server requests.
*/
function XmlHttpRequest(listing_url, prefix_url) {
if (typeof prefix_url === "undefined") { prefix_url = ''; }
_super.call(this);
this.prefix_url = prefix_url;
if (listing_url == null) {
listing_url = 'index.json';
}
// prefix_url must end in a directory separator.
if (prefix_url.length > 0 && prefix_url.charAt(prefix_url.length - 1) !== '/') {
prefix_url = prefix_url + '/';
}
var listing = this._requestFileSync(listing_url, 'json');
if (listing == null) {
throw new Error("Unable to find listing at URL: " + listing_url);
}
this._index = file_index.FileIndex.from_listing(listing);
}
XmlHttpRequest.prototype.empty = function () {
this._index.fileIterator(function (file) {
file.file_data = null;
});
};
XmlHttpRequest.prototype.getXhrPath = function (filePath) {
if (filePath.charAt(0) === '/') {
filePath = filePath.slice(1);
}
return this.prefix_url + filePath;
};
/**
* Only requests the HEAD content, for the file size.
*/
XmlHttpRequest.prototype._requestFileSizeAsync = function (path, cb) {
xhr.getFileSizeAsync(this.getXhrPath(path), cb);
};
XmlHttpRequest.prototype._requestFileSizeSync = function (path) {
return xhr.getFileSizeSync(this.getXhrPath(path));
};
XmlHttpRequest.prototype._requestFileAsync = function (p, type, cb) {
xhr.asyncDownloadFile(this.getXhrPath(p), type, cb);
};
XmlHttpRequest.prototype._requestFileSync = function (p, type) {
return xhr.syncDownloadFile(this.getXhrPath(p), type);
};
XmlHttpRequest.prototype.getName = function () {
return 'XmlHttpRequest';
};
XmlHttpRequest.isAvailable = function () {
// @todo Older browsers use a different name for XHR, iirc.
return typeof XMLHttpRequest !== "undefined" && XMLHttpRequest !== null;
};
XmlHttpRequest.prototype.diskSpace = function (path, cb) {
// Read-only file system. We could calculate the total space, but that's not
// important right now.
cb(0, 0);
};
XmlHttpRequest.prototype.isReadOnly = function () {
return true;
};
XmlHttpRequest.prototype.supportsLinks = function () {
return false;
};
XmlHttpRequest.prototype.supportsProps = function () {
return false;
};
XmlHttpRequest.prototype.supportsSynch = function () {
return true;
};
/**
* Special XHR function: Preload the given file into the index.
* @param [String] path
* @param [BrowserFS.Buffer] buffer
*/
XmlHttpRequest.prototype.preloadFile = function (path, buffer) {
var inode = this._index.getInode(path);
if (inode === null) {
throw ApiError.ENOENT(path);
}
var stats = inode.getData();
stats.size = buffer.length;
stats.file_data = buffer;
};
XmlHttpRequest.prototype.stat = function (path, isLstat, cb) {
var inode = this._index.getInode(path);
if (inode === null) {
return cb(ApiError.ENOENT(path));
}
var stats;
if (inode.isFile()) {
stats = inode.getData();
// At this point, a non-opened file will still have default stats from the listing.
if (stats.size < 0) {
this._requestFileSizeAsync(path, function (e, size) {
if (e) {
return cb(e);
}
stats.size = size;
cb(null, stats.clone());
});
} else {
cb(null, stats.clone());
}
} else {
stats = inode.getStats();
cb(null, stats);
}
};
XmlHttpRequest.prototype.statSync = function (path, isLstat) {
var inode = this._index.getInode(path);
if (inode === null) {
throw ApiError.ENOENT(path);
}
var stats;
if (inode.isFile()) {
stats = inode.getData();
// At this point, a non-opened file will still have default stats from the listing.
if (stats.size < 0) {
stats.size = this._requestFileSizeSync(path);
}
} else {
stats = inode.getStats();
}
return stats;
};
XmlHttpRequest.prototype.open = function (path, flags, mode, cb) {
// INVARIANT: You can't write to files on this file system.
if (flags.isWriteable()) {
return cb(new ApiError(0 /* EPERM */, path));
}
var _this = this;
// Check if the path exists, and is a file.
var inode = this._index.getInode(path);
if (inode === null) {
return cb(ApiError.ENOENT(path));
}
if (inode.isDir()) {
return cb(ApiError.EISDIR(path));
}
var stats = inode.getData();
switch (flags.pathExistsAction()) {
case 1 /* THROW_EXCEPTION */:
case 2 /* TRUNCATE_FILE */:
return cb(ApiError.EEXIST(path));
case 0 /* NOP */:
// Use existing file contents.
// XXX: Uh, this maintains the previously-used flag.
if (stats.file_data != null) {
return cb(null, new preload_file.NoSyncFile(_this, path, flags, stats.clone(), stats.file_data));
}
// @todo be lazier about actually requesting the file
this._requestFileAsync(path, 'buffer', function (err, buffer) {
if (err) {
return cb(err);
}
// we don't initially have file sizes
stats.size = buffer.length;
stats.file_data = buffer;
return cb(null, new preload_file.NoSyncFile(_this, path, flags, stats.clone(), buffer));
});
break;
default:
return cb(new ApiError(9 /* EINVAL */, 'Invalid FileMode object.'));
}
};
XmlHttpRequest.prototype.openSync = function (path, flags, mode) {
// INVARIANT: You can't write to files on this file system.
if (flags.isWriteable()) {
throw new ApiError(0 /* EPERM */, path);
}
// Check if the path exists, and is a file.
var inode = this._index.getInode(path);
if (inode === null) {
throw ApiError.ENOENT(path);
}
if (inode.isDir()) {
throw ApiError.EISDIR(path);
}
var stats = inode.getData();
switch (flags.pathExistsAction()) {
case 1 /* THROW_EXCEPTION */:
case 2 /* TRUNCATE_FILE */:
throw ApiError.EEXIST(path);
case 0 /* NOP */:
// Use existing file contents.
// XXX: Uh, this maintains the previously-used flag.
if (stats.file_data != null) {
return new preload_file.NoSyncFile(this, path, flags, stats.clone(), stats.file_data);
}
// @todo be lazier about actually requesting the file
var buffer = this._requestFileSync(path, 'buffer');
// we don't initially have file sizes
stats.size = buffer.length;
stats.file_data = buffer;
return new preload_file.NoSyncFile(this, path, flags, stats.clone(), buffer);
default:
throw new ApiError(9 /* EINVAL */, 'Invalid FileMode object.');
}
};
XmlHttpRequest.prototype.readdir = function (path, cb) {
try {
cb(null, this.readdirSync(path));
} catch (e) {
cb(e);
}
};
XmlHttpRequest.prototype.readdirSync = function (path) {
// Check if it exists.
var inode = this._index.getInode(path);
if (inode === null) {
throw ApiError.ENOENT(path);
} else if (inode.isFile()) {
throw ApiError.ENOTDIR(path);
}
return inode.getListing();
};
/**
* We have the entire file as a buffer; optimize readFile.
*/
XmlHttpRequest.prototype.readFile = function (fname, encoding, flag, cb) {
// Wrap cb in file closing code.
var oldCb = cb;
// Get file.
this.open(fname, flag, 0x1a4, function (err, fd) {
if (err) {
return cb(err);
}
cb = function (err, arg) {
fd.close(function (err2) {
if (err == null) {
err = err2;
}
return oldCb(err, arg);
});
};
var fdCast = fd;
var fdBuff = fdCast._buffer;
if (encoding === null) {
if (fdBuff.length > 0) {
return cb(err, fdBuff.sliceCopy());
} else {
return cb(err, new buffer.Buffer(0));
}
}
try {
cb(null, fdBuff.toString(encoding));
} catch (e) {
cb(e);
}
});
};
/**
* Specially-optimized readfile.
*/
XmlHttpRequest.prototype.readFileSync = function (fname, encoding, flag) {
// Get file.
var fd = this.openSync(fname, flag, 0x1a4);
try {
var fdCast = fd;
var fdBuff = fdCast._buffer;
if (encoding === null) {
if (fdBuff.length > 0) {
return fdBuff.sliceCopy();
} else {
return new buffer.Buffer(0);
}
}
return fdBuff.toString(encoding);
} finally {
fd.closeSync();
}
};
return XmlHttpRequest;
})(file_system.BaseFileSystem);
exports.XmlHttpRequest = XmlHttpRequest;
browserfs.registerFileSystem('XmlHttpRequest', XmlHttpRequest);
});
//# sourceMappingURL=XmlHttpRequest.js.map
;
/*global setImmediate: false, setTimeout: false, console: false */
(function () {
var async = {};
// global on the server, window in the browser
var root, previous_async;
root = this;
if (root != null) {
previous_async = root.async;
}
async.noConflict = function () {
root.async = previous_async;
return async;
};
function only_once(fn) {
var called = false;
return function() {
if (called) throw new Error("Callback was already called.");
called = true;
fn.apply(root, arguments);
}
}
//// cross-browser compatiblity functions ////
var _each = function (arr, iterator) {
if (arr.forEach) {
return arr.forEach(iterator);
}
for (var i = 0; i < arr.length; i += 1) {
iterator(arr[i], i, arr);
}
};
var _map = function (arr, iterator) {
if (arr.map) {
return arr.map(iterator);
}
var results = [];
_each(arr, function (x, i, a) {
results.push(iterator(x, i, a));
});
return results;
};
var _reduce = function (arr, iterator, memo) {
if (arr.reduce) {
return arr.reduce(iterator, memo);
}
_each(arr, function (x, i, a) {
memo = iterator(memo, x, i, a);
});
return memo;
};
var _keys = function (obj) {
if (Object.keys) {
return Object.keys(obj);
}
var keys = [];
for (var k in obj) {
if (obj.hasOwnProperty(k)) {
keys.push(k);
}
}
return keys;
};
//// exported async module functions ////
//// nextTick implementation with browser-compatible fallback ////
if (typeof process === 'undefined' || !(process.nextTick)) {
if (typeof setImmediate === 'function') {
async.nextTick = function (fn) {
// not a direct alias for IE10 compatibility
setImmediate(fn);
};
async.setImmediate = async.nextTick;
}
else {
async.nextTick = function (fn) {
setTimeout(fn, 0);
};
async.setImmediate = async.nextTick;
}
}
else {
async.nextTick = process.nextTick;
if (typeof setImmediate !== 'undefined') {
async.setImmediate = function (fn) {
// not a direct alias for IE10 compatibility
setImmediate(fn);
};
}
else {
async.setImmediate = async.nextTick;
}
}
async.each = function (arr, iterator, callback) {
callback = callback || function () {};
if (!arr.length) {
return callback();
}
var completed = 0;
_each(arr, function (x) {
iterator(x, only_once(function (err) {
if (err) {
callback(err);
callback = function () {};
}
else {
completed += 1;
if (completed >= arr.length) {
callback(null);
}
}
}));
});
};
async.forEach = async.each;
async.eachSeries = function (arr, iterator, callback) {
callback = callback || function () {};
if (!arr.length) {
return callback();
}
var completed = 0;
var iterate = function () {
iterator(arr[completed], function (err) {
if (err) {
callback(err);
callback = function () {};
}
else {
completed += 1;
if (completed >= arr.length) {
callback(null);
}
else {
iterate();
}
}
});
};
iterate();
};
async.forEachSeries = async.eachSeries;
async.eachLimit = function (arr, limit, iterator, callback) {
var fn = _eachLimit(limit);
fn.apply(null, [arr, iterator, callback]);
};
async.forEachLimit = async.eachLimit;
var _eachLimit = function (limit) {
return function (arr, iterator, callback) {
callback = callback || function () {};
if (!arr.length || limit <= 0) {
return callback();
}
var completed = 0;
var started = 0;
var running = 0;
(function replenish () {
if (completed >= arr.length) {
return callback();
}
while (running < limit && started < arr.length) {
started += 1;
running += 1;
iterator(arr[started - 1], function (err) {
if (err) {
callback(err);
callback = function () {};
}
else {
completed += 1;
running -= 1;
if (completed >= arr.length) {
callback();
}
else {
replenish();
}
}
});
}
})();
};
};
var doParallel = function (fn) {
return function () {
var args = Array.prototype.slice.call(arguments);
return fn.apply(null, [async.each].concat(args));
};
};
var doParallelLimit = function(limit, fn) {
return function () {
var args = Array.prototype.slice.call(arguments);
return fn.apply(null, [_eachLimit(limit)].concat(args));
};
};
var doSeries = function (fn) {
return function () {
var args = Array.prototype.slice.call(arguments);
return fn.apply(null, [async.eachSeries].concat(args));
};
};
var _asyncMap = function (eachfn, arr, iterator, callback) {
var results = [];
arr = _map(arr, function (x, i) {
return {index: i, value: x};
});
eachfn(arr, function (x, callback) {
iterator(x.value, function (err, v) {
results[x.index] = v;
callback(err);
});
}, function (err) {
callback(err, results);
});
};
async.map = doParallel(_asyncMap);
async.mapSeries = doSeries(_asyncMap);
async.mapLimit = function (arr, limit, iterator, callback) {
return _mapLimit(limit)(arr, iterator, callback);
};
var _mapLimit = function(limit) {
return doParallelLimit(limit, _asyncMap);
};
// reduce only has a series version, as doing reduce in parallel won't
// work in many situations.
async.reduce = function (arr, memo, iterator, callback) {
async.eachSeries(arr, function (x, callback) {
iterator(memo, x, function (err, v) {
memo = v;
callback(err);
});
}, function (err) {
callback(err, memo);
});
};
// inject alias
async.inject = async.reduce;
// foldl alias
async.foldl = async.reduce;
async.reduceRight = function (arr, memo, iterator, callback) {
var reversed = _map(arr, function (x) {
return x;
}).reverse();
async.reduce(reversed, memo, iterator, callback);
};
// foldr alias
async.foldr = async.reduceRight;
var _filter = function (eachfn, arr, iterator, callback) {
var results = [];
arr = _map(arr, function (x, i) {
return {index: i, value: x};
});
eachfn(arr, function (x, callback) {
iterator(x.value, function (v) {
if (v) {
results.push(x);
}
callback();
});
}, function (err) {
callback(_map(results.sort(function (a, b) {
return a.index - b.index;
}), function (x) {
return x.value;
}));
});
};
async.filter = doParallel(_filter);
async.filterSeries = doSeries(_filter);
// select alias
async.select = async.filter;
async.selectSeries = async.filterSeries;
var _reject = function (eachfn, arr, iterator, callback) {
var results = [];
arr = _map(arr, function (x, i) {
return {index: i, value: x};
});
eachfn(arr, function (x, callback) {
iterator(x.value, function (v) {
if (!v) {
results.push(x);
}
callback();
});
}, function (err) {
callback(_map(results.sort(function (a, b) {
return a.index - b.index;
}), function (x) {
return x.value;
}));
});
};
async.reject = doParallel(_reject);
async.rejectSeries = doSeries(_reject);
var _detect = function (eachfn, arr, iterator, main_callback) {
eachfn(arr, function (x, callback) {
iterator(x, function (result) {
if (result) {
main_callback(x);
main_callback = function () {};
}
else {
callback();
}
});
}, function (err) {
main_callback();
});
};
async.detect = doParallel(_detect);
async.detectSeries = doSeries(_detect);
async.some = function (arr, iterator, main_callback) {
async.each(arr, function (x, callback) {
iterator(x, function (v) {
if (v) {
main_callback(true);
main_callback = function () {};
}
callback();
});
}, function (err) {
main_callback(false);
});
};
// any alias
async.any = async.some;
async.every = function (arr, iterator, main_callback) {
async.each(arr, function (x, callback) {
iterator(x, function (v) {
if (!v) {
main_callback(false);
main_callback = function () {};
}
callback();
});
}, function (err) {
main_callback(true);
});
};
// all alias
async.all = async.every;
async.sortBy = function (arr, iterator, callback) {
async.map(arr, function (x, callback) {
iterator(x, function (err, criteria) {
if (err) {
callback(err);
}
else {
callback(null, {value: x, criteria: criteria});
}
});
}, function (err, results) {
if (err) {
return callback(err);
}
else {
var fn = function (left, right) {
var a = left.criteria, b = right.criteria;
return a < b ? -1 : a > b ? 1 : 0;
};
callback(null, _map(results.sort(fn), function (x) {
return x.value;
}));
}
});
};
async.auto = function (tasks, callback) {
callback = callback || function () {};
var keys = _keys(tasks);
if (!keys.length) {
return callback(null);
}
var results = {};
var listeners = [];
var addListener = function (fn) {
listeners.unshift(fn);
};
var removeListener = function (fn) {
for (var i = 0; i < listeners.length; i += 1) {
if (listeners[i] === fn) {
listeners.splice(i, 1);
return;
}
}
};
var taskComplete = function () {
_each(listeners.slice(0), function (fn) {
fn();
});
};
addListener(function () {
if (_keys(results).length === keys.length) {
callback(null, results);
callback = function () {};
}
});
_each(keys, function (k) {
var task = (tasks[k] instanceof Function) ? [tasks[k]]: tasks[k];
var taskCallback = function (err) {
var args = Array.prototype.slice.call(arguments, 1);
if (args.length <= 1) {
args = args[0];
}
if (err) {
var safeResults = {};
_each(_keys(results), function(rkey) {
safeResults[rkey] = results[rkey];
});
safeResults[k] = args;
callback(err, safeResults);
// stop subsequent errors hitting callback multiple times
callback = function () {};
}
else {
results[k] = args;
async.setImmediate(taskComplete);
}
};
var requires = task.slice(0, Math.abs(task.length - 1)) || [];
var ready = function () {
return _reduce(requires, function (a, x) {
return (a && results.hasOwnProperty(x));
}, true) && !results.hasOwnProperty(k);
};
if (ready()) {
task[task.length - 1](taskCallback, results);
}
else {
var listener = function () {
if (ready()) {
removeListener(listener);
task[task.length - 1](taskCallback, results);
}
};
addListener(listener);
}
});
};
async.waterfall = function (tasks, callback) {
callback = callback || function () {};
if (tasks.constructor !== Array) {
var err = new Error('First argument to waterfall must be an array of functions');
return callback(err);
}
if (!tasks.length) {
return callback();
}
var wrapIterator = function (iterator) {
return function (err) {
if (err) {
callback.apply(null, arguments);
callback = function () {};
}
else {
var args = Array.prototype.slice.call(arguments, 1);
var next = iterator.next();
if (next) {
args.push(wrapIterator(next));
}
else {
args.push(callback);
}
async.setImmediate(function () {
iterator.apply(null, args);
});
}
};
};
wrapIterator(async.iterator(tasks))();
};
var _parallel = function(eachfn, tasks, callback) {
callback = callback || function () {};
if (tasks.constructor === Array) {
eachfn.map(tasks, function (fn, callback) {
if (fn) {
fn(function (err) {
var args = Array.prototype.slice.call(arguments, 1);
if (args.length <= 1) {
args = args[0];
}
callback.call(null, err, args);
});
}
}, callback);
}
else {
var results = {};
eachfn.each(_keys(tasks), function (k, callback) {
tasks[k](function (err) {
var args = Array.prototype.slice.call(arguments, 1);
if (args.length <= 1) {
args = args[0];
}
results[k] = args;
callback(err);
});
}, function (err) {
callback(err, results);
});
}
};
async.parallel = function (tasks, callback) {
_parallel({ map: async.map, each: async.each }, tasks, callback);
};
async.parallelLimit = function(tasks, limit, callback) {
_parallel({ map: _mapLimit(limit), each: _eachLimit(limit) }, tasks, callback);
};
async.series = function (tasks, callback) {
callback = callback || function () {};
if (tasks.constructor === Array) {
async.mapSeries(tasks, function (fn, callback) {
if (fn) {
fn(function (err) {
var args = Array.prototype.slice.call(arguments, 1);
if (args.length <= 1) {
args = args[0];
}
callback.call(null, err, args);
});
}
}, callback);
}
else {
var results = {};
async.eachSeries(_keys(tasks), function (k, callback) {
tasks[k](function (err) {
var args = Array.prototype.slice.call(arguments, 1);
if (args.length <= 1) {
args = args[0];
}
results[k] = args;
callback(err);
});
}, function (err) {
callback(err, results);
});
}
};
async.iterator = function (tasks) {
var makeCallback = function (index) {
var fn = function () {
if (tasks.length) {
tasks[index].apply(null, arguments);
}
return fn.next();
};
fn.next = function () {
return (index < tasks.length - 1) ? makeCallback(index + 1): null;
};
return fn;
};
return makeCallback(0);
};
async.apply = function (fn) {
var args = Array.prototype.slice.call(arguments, 1);
return function () {
return fn.apply(
null, args.concat(Array.prototype.slice.call(arguments))
);
};
};
var _concat = function (eachfn, arr, fn, callback) {
var r = [];
eachfn(arr, function (x, cb) {
fn(x, function (err, y) {
r = r.concat(y || []);
cb(err);
});
}, function (err) {
callback(err, r);
});
};
async.concat = doParallel(_concat);
async.concatSeries = doSeries(_concat);
async.whilst = function (test, iterator, callback) {
if (test()) {
iterator(function (err) {
if (err) {
return callback(err);
}
async.whilst(test, iterator, callback);
});
}
else {
callback();
}
};
async.doWhilst = function (iterator, test, callback) {
iterator(function (err) {
if (err) {
return callback(err);
}
if (test()) {
async.doWhilst(iterator, test, callback);
}
else {
callback();
}
});
};
async.until = function (test, iterator, callback) {
if (!test()) {
iterator(function (err) {
if (err) {
return callback(err);
}
async.until(test, iterator, callback);
});
}
else {
callback();
}
};
async.doUntil = function (iterator, test, callback) {
iterator(function (err) {
if (err) {
return callback(err);
}
if (!test()) {
async.doUntil(iterator, test, callback);
}
else {
callback();
}
});
};
async.queue = function (worker, concurrency) {
if (concurrency === undefined) {
concurrency = 1;
}
function _insert(q, data, pos, callback) {
if(data.constructor !== Array) {
data = [data];
}
_each(data, function(task) {
var item = {
data: task,
callback: typeof callback === 'function' ? callback : null
};
if (pos) {
q.tasks.unshift(item);
} else {
q.tasks.push(item);
}
if (q.saturated && q.tasks.length === concurrency) {
q.saturated();
}
async.setImmediate(q.process);
});
}
var workers = 0;
var q = {
tasks: [],
concurrency: concurrency,
saturated: null,
empty: null,
drain: null,
push: function (data, callback) {
_insert(q, data, false, callback);
},
unshift: function (data, callback) {
_insert(q, data, true, callback);
},
process: function () {
if (workers < q.concurrency && q.tasks.length) {
var task = q.tasks.shift();
if (q.empty && q.tasks.length === 0) {
q.empty();
}
workers += 1;
var next = function () {
workers -= 1;
if (task.callback) {
task.callback.apply(task, arguments);
}
if (q.drain && q.tasks.length + workers === 0) {
q.drain();
}
q.process();
};
var cb = only_once(next);
worker(task.data, cb);
}
},
length: function () {
return q.tasks.length;
},
running: function () {
return workers;
}
};
return q;
};
async.cargo = function (worker, payload) {
var working = false,
tasks = [];
var cargo = {
tasks: tasks,
payload: payload,
saturated: null,
empty: null,
drain: null,
push: function (data, callback) {
if(data.constructor !== Array) {
data = [data];
}
_each(data, function(task) {
tasks.push({
data: task,
callback: typeof callback === 'function' ? callback : null
});
if (cargo.saturated && tasks.length === payload) {
cargo.saturated();
}
});
async.setImmediate(cargo.process);
},
process: function process() {
if (working) return;
if (tasks.length === 0) {
if(cargo.drain) cargo.drain();
return;
}
var ts = typeof payload === 'number'
? tasks.splice(0, payload)
: tasks.splice(0);
var ds = _map(ts, function (task) {
return task.data;
});
if(cargo.empty) cargo.empty();
working = true;
worker(ds, function () {
working = false;
var args = arguments;
_each(ts, function (data) {
if (data.callback) {
data.callback.apply(null, args);
}
});
process();
});
},
length: function () {
return tasks.length;
},
running: function () {
return working;
}
};
return cargo;
};
var _console_fn = function (name) {
return function (fn) {
var args = Array.prototype.slice.call(arguments, 1);
fn.apply(null, args.concat([function (err) {
var args = Array.prototype.slice.call(arguments, 1);
if (typeof console !== 'undefined') {
if (err) {
if (console.error) {
console.error(err);
}
}
else if (console[name]) {
_each(args, function (x) {
console[name](x);
});
}
}
}]));
};
};
async.log = _console_fn('log');
async.dir = _console_fn('dir');
/*async.info = _console_fn('info');
async.warn = _console_fn('warn');
async.error = _console_fn('error');*/
async.memoize = function (fn, hasher) {
var memo = {};
var queues = {};
hasher = hasher || function (x) {
return x;
};
var memoized = function () {
var args = Array.prototype.slice.call(arguments);
var callback = args.pop();
var key = hasher.apply(null, args);
if (key in memo) {
callback.apply(null, memo[key]);
}
else if (key in queues) {
queues[key].push(callback);
}
else {
queues[key] = [callback];
fn.apply(null, args.concat([function () {
memo[key] = arguments;
var q = queues[key];
delete queues[key];
for (var i = 0, l = q.length; i < l; i++) {
q[i].apply(null, arguments);
}
}]));
}
};
memoized.memo = memo;
memoized.unmemoized = fn;
return memoized;
};
async.unmemoize = function (fn) {
return function () {
return (fn.unmemoized || fn).apply(null, arguments);
};
};
async.times = function (count, iterator, callback) {
var counter = [];
for (var i = 0; i < count; i++) {
counter.push(i);
}
return async.map(counter, iterator, callback);
};
async.timesSeries = function (count, iterator, callback) {
var counter = [];
for (var i = 0; i < count; i++) {
counter.push(i);
}
return async.mapSeries(counter, iterator, callback);
};
async.compose = function (/* functions... */) {
var fns = Array.prototype.reverse.call(arguments);
return function () {
var that = this;
var args = Array.prototype.slice.call(arguments);
var callback = args.pop();
async.reduce(fns, args, function (newargs, fn, cb) {
fn.apply(that, newargs.concat([function () {
var err = arguments[0];
var nextargs = Array.prototype.slice.call(arguments, 1);
cb(err, nextargs);
}]))
},
function (err, results) {
callback.apply(that, [err].concat(results));
});
};
};
var _applyEach = function (eachfn, fns /*args...*/) {
var go = function () {
var that = this;
var args = Array.prototype.slice.call(arguments);
var callback = args.pop();
return eachfn(fns, function (fn, cb) {
fn.apply(that, args.concat([cb]));
},
callback);
};
if (arguments.length > 2) {
var args = Array.prototype.slice.call(arguments, 2);
return go.apply(this, args);
}
else {
return go;
}
};
async.applyEach = doParallel(_applyEach);
async.applyEachSeries = doSeries(_applyEach);
async.forever = function (fn, callback) {
function next(err) {
if (err) {
if (callback) {
return callback(err);
}
throw err;
}
fn(next);
}
next();
};
// AMD / RequireJS
if (typeof define !== 'undefined' && define.amd) {
define('async',[], function () {
return async;
});
}
// Node.js
else if (typeof module !== 'undefined' && module.exports) {
module.exports = async;
}
// included directly via <script> tag
else {
root.async = async;
}
}());
var __extends = this.__extends || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
define('backend/dropbox',["require", "exports", '../generic/preload_file', '../core/file_system', '../core/node_fs_stats', '../core/buffer', '../core/api_error', '../core/node_path', '../core/browserfs', '../core/buffer_core_arraybuffer', "async"], function(require, exports, preload_file, file_system, node_fs_stats, buffer, api_error, node_path, browserfs, buffer_core_arraybuffer) {
var Buffer = buffer.Buffer;
var Stats = node_fs_stats.Stats;
var ApiError = api_error.ApiError;
var ErrorCode = api_error.ErrorCode;
var path = node_path.path;
var FileType = node_fs_stats.FileType;
// XXX: No typings available for the Dropbox client. :(
// XXX: The typings for async on DefinitelyTyped are out of date.
var async = require('async');
var Buffer = buffer.Buffer;
var DropboxFile = (function (_super) {
__extends(DropboxFile, _super);
function DropboxFile(_fs, _path, _flag, _stat, contents) {
_super.call(this, _fs, _path, _flag, _stat, contents);
}
DropboxFile.prototype.sync = function (cb) {
var buffer = this._buffer;
// XXX: Typing hack.
var backing_mem = this._buffer.getBufferCore();
if (!(backing_mem instanceof buffer_core_arraybuffer.BufferCoreArrayBuffer)) {
// Copy into an ArrayBuffer-backed Buffer.
buffer = new Buffer(this._buffer.length);
this._buffer.copy(buffer);
backing_mem = buffer.getBufferCore();
}
// Reach into the BC, grab the DV.
var dv = backing_mem.getDataView();
// Create an appropriate view on the array buffer.
var abv = new DataView(dv.buffer, dv.byteOffset + buffer.getOffset(), buffer.length);
this._fs._writeFileStrict(this._path, abv, cb);
};
DropboxFile.prototype.close = function (cb) {
this.sync(cb);
};
return DropboxFile;
})(preload_file.PreloadFile);
exports.DropboxFile = DropboxFile;
var DropboxFileSystem = (function (_super) {
__extends(DropboxFileSystem, _super);
/**
* Arguments: an authenticated Dropbox.js client
*/
function DropboxFileSystem(client) {
_super.call(this);
this.client = client;
}
DropboxFileSystem.prototype.getName = function () {
return 'Dropbox';
};
DropboxFileSystem.isAvailable = function () {
// Checks if the Dropbox library is loaded.
// @todo Check if the Dropbox library *can be used* in the current browser.
return typeof Dropbox !== 'undefined';
};
DropboxFileSystem.prototype.isReadOnly = function () {
return false;
};
// Dropbox doesn't support symlinks, properties, or synchronous calls
DropboxFileSystem.prototype.supportsSymlinks = function () {
return false;
};
DropboxFileSystem.prototype.supportsProps = function () {
return false;
};
DropboxFileSystem.prototype.supportsSynch = function () {
return false;
};
DropboxFileSystem.prototype.empty = function (main_cb) {
var _this = this;
this.client.readdir('/', function (error, paths, dir, files) {
if (error) {
main_cb(_this.convert(error));
} else {
var deleteFile = function (file, cb) {
_this.client.remove(file.path, function (err, stat) {
cb(err ? _this.convert(err) : err);
});
};
var finished = function (err) {
if (err) {
main_cb(_this.convert(err));
} else {
main_cb();
}
};
async.each(files, deleteFile, finished);
}
});
};
DropboxFileSystem.prototype.rename = function (oldPath, newPath, cb) {
this.client.move(oldPath, newPath, function (error, stat) {
if (error) {
// XXX: Assume 404 for now.
var missingPath = error.response.error.indexOf(oldPath) > -1 ? oldPath : newPath;
cb(new ApiError(1 /* ENOENT */, missingPath + " doesn't exist"));
} else {
cb();
}
});
};
DropboxFileSystem.prototype.stat = function (path, isLstat, cb) {
var _this = this;
// Ignore lstat case -- Dropbox doesn't support symlinks
// Stat the file
this.client.stat(path, function (error, stat) {
// Dropbox keeps track of deleted files, so if a file has existed in the
// past but doesn't any longer, you wont get an error
if (error || ((stat != null) && stat.isRemoved)) {
cb(new ApiError(1 /* ENOENT */, path + " doesn't exist"));
} else {
var stats = new Stats(_this._statType(stat), stat.size);
return cb(null, stats);
}
});
};
DropboxFileSystem.prototype.open = function (path, flags, mode, cb) {
var _this = this;
// Try and get the file's contents
this.client.readFile(path, {
arrayBuffer: true
}, function (error, content, db_stat, range) {
if (error) {
// If the file's being opened for reading and doesn't exist, return an
// error
if (flags.isReadable()) {
cb(new ApiError(1 /* ENOENT */, path + " doesn't exist"));
} else {
switch (error.status) {
case 0:
return console.error('No connection');
case 404:
var ab = new ArrayBuffer(0);
return _this._writeFileStrict(path, ab, function (error2, stat) {
if (error2) {
cb(error2);
} else {
var file = _this._makeFile(path, flags, stat, new Buffer(ab));
cb(null, file);
}
});
default:
return console.log("Unhandled error: " + error);
}
}
} else {
// No error
var buffer;
// Dropbox.js seems to set `content` to `null` rather than to an empty
// buffer when reading an empty file. Not sure why this is.
if (content === null) {
buffer = new Buffer(0);
} else {
buffer = new Buffer(content);
}
var file = _this._makeFile(path, flags, db_stat, buffer);
return cb(null, file);
}
});
};
DropboxFileSystem.prototype._writeFileStrict = function (p, data, cb) {
var _this = this;
var parent = path.dirname(p);
this.stat(parent, false, function (error, stat) {
if (error) {
cb(new ApiError(1 /* ENOENT */, "Can't create " + p + " because " + parent + " doesn't exist"));
} else {
_this.client.writeFile(p, data, function (error2, stat) {
if (error2) {
cb(_this.convert(error2));
} else {
cb(null, stat);
}
});
}
});
};
/**
* Private
* Returns a BrowserFS object representing the type of a Dropbox.js stat object
*/
DropboxFileSystem.prototype._statType = function (stat) {
return stat.isFile ? 32768 /* FILE */ : 16384 /* DIRECTORY */;
};
/**
* Private
* Returns a BrowserFS object representing a File, created from the data
* returned by calls to the Dropbox API.
*/
DropboxFileSystem.prototype._makeFile = function (path, flag, stat, buffer) {
var type = this._statType(stat);
var stats = new Stats(type, stat.size);
return new DropboxFile(this, path, flag, stats, buffer);
};
/**
* Private
* Delete a file or directory from Dropbox
* isFile should reflect which call was made to remove the it (`unlink` or
* `rmdir`). If this doesn't match what's actually at `path`, an error will be
* returned
*/
DropboxFileSystem.prototype._remove = function (path, cb, isFile) {
var _this = this;
this.client.stat(path, function (error, stat) {
var message = null;
if (error) {
cb(new ApiError(1 /* ENOENT */, path + " doesn't exist"));
} else {
if (stat.isFile && !isFile) {
cb(new ApiError(7 /* ENOTDIR */, path + " is a file."));
} else if (!stat.isFile && isFile) {
cb(new ApiError(8 /* EISDIR */, path + " is a directory."));
} else {
_this.client.remove(path, function (error, stat) {
if (error) {
// @todo Make this more specific.
cb(new ApiError(2 /* EIO */, "Failed to remove " + path));
} else {
cb(null);
}
});
}
}
});
};
/**
* Delete a file
*/
DropboxFileSystem.prototype.unlink = function (path, cb) {
this._remove(path, cb, true);
};
/**
* Delete a directory
*/
DropboxFileSystem.prototype.rmdir = function (path, cb) {
this._remove(path, cb, false);
};
/**
* Create a directory
*/
DropboxFileSystem.prototype.mkdir = function (p, mode, cb) {
var _this = this;
// Dropbox.js' client.mkdir() behaves like `mkdir -p`, i.e. it creates a
// directory and all its ancestors if they don't exist.
// Node's fs.mkdir() behaves like `mkdir`, i.e. it throws an error if an attempt
// is made to create a directory without a parent.
// To handle this inconsistency, a check for the existence of `path`'s parent
// must be performed before it is created, and an error thrown if it does
// not exist
var parent = path.dirname(p);
this.client.stat(parent, function (error, stat) {
if (error) {
cb(new ApiError(1 /* ENOENT */, "Can't create " + p + " because " + parent + " doesn't exist"));
} else {
_this.client.mkdir(p, function (error, stat) {
if (error) {
cb(new ApiError(6 /* EEXIST */, p + " already exists"));
} else {
cb(null);
}
});
}
});
};
/**
* Get the names of the files in a directory
*/
DropboxFileSystem.prototype.readdir = function (path, cb) {
var _this = this;
this.client.readdir(path, function (error, files, dir_stat, content_stats) {
if (error) {
return cb(_this.convert(error));
} else {
return cb(null, files);
}
});
};
/**
* Converts a Dropbox-JS error into a BFS error.
*/
DropboxFileSystem.prototype.convert = function (err, message) {
if (typeof message === "undefined") { message = ""; }
switch (err.status) {
case 400:
// INVALID_PARAM
return new ApiError(9 /* EINVAL */, message);
case 401:
case 403:
// OAUTH_ERROR
return new ApiError(2 /* EIO */, message);
case 404:
// NOT_FOUND
return new ApiError(1 /* ENOENT */, message);
case 405:
// INVALID_METHOD
return new ApiError(14 /* ENOTSUP */, message);
case 0:
case 304:
case 406:
case 409:
default:
return new ApiError(2 /* EIO */, message);
}
};
return DropboxFileSystem;
})(file_system.BaseFileSystem);
exports.DropboxFileSystem = DropboxFileSystem;
browserfs.registerFileSystem('Dropbox', DropboxFileSystem);
});
//# sourceMappingURL=dropbox.js.map
;
var __extends = this.__extends || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
define('backend/html5fs',["require", "exports", '../generic/preload_file', '../core/file_system', '../core/api_error', '../core/file_flag', '../core/node_fs_stats', '../core/buffer', '../core/browserfs', '../core/buffer_core_arraybuffer', '../core/node_path', '../core/global', "async"], function(require, exports, preload_file, file_system, api_error, file_flag, node_fs_stats, buffer, browserfs, buffer_core_arraybuffer, node_path, global) {
var Buffer = buffer.Buffer;
var Stats = node_fs_stats.Stats;
var FileType = node_fs_stats.FileType;
var ApiError = api_error.ApiError;
var ErrorCode = api_error.ErrorCode;
var ActionType = file_flag.ActionType;
// XXX: The typings for async on DefinitelyTyped are out of date.
var async = require('async');
var _getFS = global.webkitRequestFileSystem || global.requestFileSystem || null;
function _requestQuota(type, size, success, errorCallback) {
// We cast navigator and window to '<any>' because everything here is
// nonstandard functionality, despite the fact that Chrome has the only
// implementation of the HTML5FS and is likely driving the standardization
// process. Thus, these objects defined off of navigator and window are not
// present in the DefinitelyTyped TypeScript typings for FileSystem.
if (typeof navigator['webkitPersistentStorage'] !== 'undefined') {
switch (type) {
case global.PERSISTENT:
navigator.webkitPersistentStorage.requestQuota(size, success, errorCallback);
break;
case global.TEMPORARY:
navigator.webkitTemporaryStorage.requestQuota(size, success, errorCallback);
break;
default:
// TODO: Figure out how to construct a DOMException/DOMError.
errorCallback(null);
break;
}
} else {
global.webkitStorageInfo.requestQuota(type, size, success, errorCallback);
}
}
function _toArray(list) {
return Array.prototype.slice.call(list || [], 0);
}
// A note about getFile and getDirectory options:
// These methods are called at numerous places in this file, and are passed
// some combination of these two options:
// - create: If true, the entry will be created if it doesn't exist.
// If false, an error will be thrown if it doesn't exist.
// - exclusive: If true, only create the entry if it doesn't already exist,
// and throw an error if it does.
var HTML5FSFile = (function (_super) {
__extends(HTML5FSFile, _super);
function HTML5FSFile(_fs, _path, _flag, _stat, contents) {
_super.call(this, _fs, _path, _flag, _stat, contents);
}
HTML5FSFile.prototype.sync = function (cb) {
var _this = this;
// Don't create the file (it should already have been created by `open`)
var opts = {
create: false
};
var _fs = this._fs;
var success = function (entry) {
entry.createWriter(function (writer) {
// XXX: Typing hack.
var buffer = _this._buffer;
var backing_mem = _this._buffer.getBufferCore();
if (!(backing_mem instanceof buffer_core_arraybuffer.BufferCoreArrayBuffer)) {
// Copy into an ArrayBuffer-backed Buffer.
buffer = new Buffer(_this._buffer.length);
_this._buffer.copy(buffer);
backing_mem = buffer.getBufferCore();
}
// Reach into the BC, grab the DV.
var dv = backing_mem.getDataView();
// Create an appropriate view on the array buffer.
var abv = new DataView(dv.buffer, dv.byteOffset + buffer.getOffset(), buffer.length);
var blob = new Blob([abv]);
var length = blob.size;
writer.onwriteend = function (event) {
writer.onwriteend = null;
writer.truncate(length);
cb();
};
writer.onerror = function (err) {
cb(_fs.convert(err));
};
writer.write(blob);
});
};
var error = function (err) {
cb(_fs.convert(err));
};
_fs.fs.root.getFile(this._path, opts, success, error);
};
HTML5FSFile.prototype.close = function (cb) {
this.sync(cb);
};
return HTML5FSFile;
})(preload_file.PreloadFile);
exports.HTML5FSFile = HTML5FSFile;
var HTML5FS = (function (_super) {
__extends(HTML5FS, _super);
/**
* Arguments:
* - type: PERSISTENT or TEMPORARY
* - size: storage quota to request, in megabytes. Allocated value may be less.
*/
function HTML5FS(size, type) {
_super.call(this);
this.size = size != null ? size : 5;
this.type = type != null ? type : global.PERSISTENT;
var kb = 1024;
var mb = kb * kb;
this.size *= mb;
}
HTML5FS.prototype.getName = function () {
return 'HTML5 FileSystem';
};
HTML5FS.isAvailable = function () {
return _getFS != null;
};
HTML5FS.prototype.isReadOnly = function () {
return false;
};
HTML5FS.prototype.supportsSymlinks = function () {
return false;
};
HTML5FS.prototype.supportsProps = function () {
return false;
};
HTML5FS.prototype.supportsSynch = function () {
return false;
};
/**
* Converts the given DOMError into an appropriate ApiError.
* Full list of values here:
* https://developer.mozilla.org/en-US/docs/Web/API/DOMError
* I've only implemented the most obvious ones, but more can be added to
* make errors more descriptive in the future.
*/
HTML5FS.prototype.convert = function (err, message) {
if (typeof message === "undefined") { message = ""; }
switch (err.name) {
case 'QuotaExceededError':
return new ApiError(11 /* ENOSPC */, message);
case 'NotFoundError':
return new ApiError(1 /* ENOENT */, message);
case 'SecurityError':
return new ApiError(4 /* EACCES */, message);
case 'InvalidModificationError':
return new ApiError(0 /* EPERM */, message);
case 'SyntaxError':
case 'TypeMismatchError':
return new ApiError(9 /* EINVAL */, message);
default:
return new ApiError(9 /* EINVAL */, message);
}
};
/**
* Converts the given ErrorEvent (from a FileReader) into an appropriate
* APIError.
*/
HTML5FS.prototype.convertErrorEvent = function (err, message) {
if (typeof message === "undefined") { message = ""; }
return new ApiError(1 /* ENOENT */, err.message + "; " + message);
};
/**
* Nonstandard
* Requests a storage quota from the browser to back this FS.
*/
HTML5FS.prototype.allocate = function (cb) {
var _this = this;
if (typeof cb === "undefined") { cb = function () {
}; }
var success = function (fs) {
_this.fs = fs;
cb();
};
var error = function (err) {
cb(_this.convert(err));
};
if (this.type === global.PERSISTENT) {
_requestQuota(this.type, this.size, function (granted) {
_getFS(_this.type, granted, success, error);
}, error);
} else {
_getFS(this.type, this.size, success, error);
}
};
/**
* Nonstandard
* Deletes everything in the FS. Used for testing.
* Karma clears the storage after you quit it but not between runs of the test
* suite, and the tests expect an empty FS every time.
*/
HTML5FS.prototype.empty = function (main_cb) {
var _this = this;
// Get a list of all entries in the root directory to delete them
this._readdir('/', function (err, entries) {
if (err) {
console.error('Failed to empty FS');
main_cb(err);
} else {
// Called when every entry has been operated on
var finished = function (er) {
if (err) {
console.error("Failed to empty FS");
main_cb(err);
} else {
main_cb();
}
};
// Removes files and recursively removes directories
var deleteEntry = function (entry, cb) {
var succ = function () {
cb();
};
var error = function (err) {
cb(_this.convert(err, entry.fullPath));
};
if (entry.isFile) {
entry.remove(succ, error);
} else {
entry.removeRecursively(succ, error);
}
};
// Loop through the entries and remove them, then call the callback
// when they're all finished.
async.each(entries, deleteEntry, finished);
}
});
};
HTML5FS.prototype.rename = function (oldPath, newPath, cb) {
var _this = this;
var semaphore = 2, successCount = 0, root = this.fs.root, error = function (err) {
if (--semaphore === 0) {
cb(_this.convert(err, "Failed to rename " + oldPath + " to " + newPath + "."));
}
}, success = function (file) {
if (++successCount === 2) {
console.error("Something was identified as both a file and a directory. This should never happen.");
return;
}
// SPECIAL CASE: If newPath === oldPath, and the path exists, then
// this operation trivially succeeds.
if (oldPath === newPath) {
return cb();
}
// Get the new parent directory.
root.getDirectory(node_path.path.dirname(newPath), {}, function (parentDir) {
file.moveTo(parentDir, node_path.path.basename(newPath), function (entry) {
cb();
}, function (err) {
// SPECIAL CASE: If oldPath is a directory, and newPath is a
// file, rename should delete the file and perform the move.
if (file.isDirectory) {
// Unlink only works on files. Try to delete newPath.
_this.unlink(newPath, function (e) {
if (e) {
// newPath is probably a directory.
error(err);
} else {
// Recurse, now that newPath doesn't exist.
_this.rename(oldPath, newPath, cb);
}
});
} else {
error(err);
}
});
}, error);
};
// We don't know if oldPath is a *file* or a *directory*, and there's no
// way to stat items. So launch both requests, see which one succeeds.
root.getFile(oldPath, {}, success, error);
root.getDirectory(oldPath, {}, success, error);
};
HTML5FS.prototype.stat = function (path, isLstat, cb) {
var _this = this;
// Throw an error if the entry doesn't exist, because then there's nothing
// to stat.
var opts = {
create: false
};
// Called when the path has been successfully loaded as a file.
var loadAsFile = function (entry) {
var fileFromEntry = function (file) {
var stat = new Stats(32768 /* FILE */, file.size);
cb(null, stat);
};
entry.file(fileFromEntry, failedToLoad);
};
// Called when the path has been successfully loaded as a directory.
var loadAsDir = function (dir) {
// Directory entry size can't be determined from the HTML5 FS API, and is
// implementation-dependant anyway, so a dummy value is used.
var size = 4096;
var stat = new Stats(16384 /* DIRECTORY */, size);
cb(null, stat);
};
// Called when the path couldn't be opened as a directory or a file.
var failedToLoad = function (err) {
cb(_this.convert(err, path));
};
// Called when the path couldn't be opened as a file, but might still be a
// directory.
var failedToLoadAsFile = function () {
_this.fs.root.getDirectory(path, opts, loadAsDir, failedToLoad);
};
// No method currently exists to determine whether a path refers to a
// directory or a file, so this implementation tries both and uses the first
// one that succeeds.
this.fs.root.getFile(path, opts, loadAsFile, failedToLoadAsFile);
};
HTML5FS.prototype.open = function (path, flags, mode, cb) {
var _this = this;
var opts = {
create: flags.pathNotExistsAction() === 3 /* CREATE_FILE */,
exclusive: flags.isExclusive()
};
var error = function (err) {
cb(_this.convertErrorEvent(err, path));
};
var error2 = function (err) {
cb(_this.convert(err, path));
};
var success = function (entry) {
var success2 = function (file) {
var reader = new FileReader();
reader.onloadend = function (event) {
var bfs_file = _this._makeFile(path, flags, file, reader.result);
cb(null, bfs_file);
};
reader.onerror = error;
reader.readAsArrayBuffer(file);
};
entry.file(success2, error2);
};
this.fs.root.getFile(path, opts, success, error);
};
/**
* Returns a BrowserFS object representing the type of a Dropbox.js stat object
*/
HTML5FS.prototype._statType = function (stat) {
return stat.isFile ? 32768 /* FILE */ : 16384 /* DIRECTORY */;
};
/**
* Returns a BrowserFS object representing a File, created from the data
* returned by calls to the Dropbox API.
*/
HTML5FS.prototype._makeFile = function (path, flag, stat, data) {
if (typeof data === "undefined") { data = new ArrayBuffer(0); }
var stats = new Stats(32768 /* FILE */, stat.size);
var buffer = new Buffer(data);
return new HTML5FSFile(this, path, flag, stats, buffer);
};
/**
* Delete a file or directory from the file system
* isFile should reflect which call was made to remove the it (`unlink` or
* `rmdir`). If this doesn't match what's actually at `path`, an error will be
* returned
*/
HTML5FS.prototype._remove = function (path, cb, isFile) {
var _this = this;
var success = function (entry) {
var succ = function () {
cb();
};
var err = function (err) {
cb(_this.convert(err, path));
};
entry.remove(succ, err);
};
var error = function (err) {
cb(_this.convert(err, path));
};
// Deleting the entry, so don't create it
var opts = {
create: false
};
if (isFile) {
this.fs.root.getFile(path, opts, success, error);
} else {
this.fs.root.getDirectory(path, opts, success, error);
}
};
HTML5FS.prototype.unlink = function (path, cb) {
this._remove(path, cb, true);
};
HTML5FS.prototype.rmdir = function (path, cb) {
this._remove(path, cb, false);
};
HTML5FS.prototype.mkdir = function (path, mode, cb) {
var _this = this;
// Create the directory, but throw an error if it already exists, as per
// mkdir(1)
var opts = {
create: true,
exclusive: true
};
var success = function (dir) {
cb();
};
var error = function (err) {
cb(_this.convert(err, path));
};
this.fs.root.getDirectory(path, opts, success, error);
};
/**
* Returns an array of `FileEntry`s. Used internally by empty and readdir.
*/
HTML5FS.prototype._readdir = function (path, cb) {
var _this = this;
// Grab the requested directory.
this.fs.root.getDirectory(path, { create: false }, function (dirEntry) {
var reader = dirEntry.createReader();
var entries = [];
var error = function (err) {
cb(_this.convert(err, path));
};
// Call the reader.readEntries() until no more results are returned.
var readEntries = function () {
reader.readEntries((function (results) {
if (results.length) {
entries = entries.concat(_toArray(results));
readEntries();
} else {
cb(null, entries);
}
}), error);
};
readEntries();
});
};
/**
* Map _readdir's list of `FileEntry`s to their names and return that.
*/
HTML5FS.prototype.readdir = function (path, cb) {
this._readdir(path, function (e, entries) {
if (e != null) {
return cb(e);
}
var rv = [];
for (var i = 0; i < entries.length; i++) {
rv.push(entries[i].name);
}
cb(null, rv);
});
};
return HTML5FS;
})(file_system.BaseFileSystem);
exports.HTML5FS = HTML5FS;
browserfs.registerFileSystem('HTML5FS', HTML5FS);
});
//# sourceMappingURL=html5fs.js.map
;
var __extends = this.__extends || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
define('backend/in_memory',["require", "exports", '../generic/key_value_filesystem', '../core/browserfs'], function(require, exports, kvfs, browserfs) {
/**
* A simple in-memory key-value store backed by a JavaScript object.
*/
var InMemoryStore = (function () {
function InMemoryStore() {
this.store = {};
}
InMemoryStore.prototype.name = function () {
return 'In-memory';
};
InMemoryStore.prototype.clear = function () {
this.store = {};
};
InMemoryStore.prototype.beginTransaction = function (type) {
return new kvfs.SimpleSyncRWTransaction(this);
};
InMemoryStore.prototype.get = function (key) {
return this.store[key];
};
InMemoryStore.prototype.put = function (key, data, overwrite) {
if (!overwrite && this.store.hasOwnProperty(key)) {
return false;
}
this.store[key] = data;
return true;
};
InMemoryStore.prototype.delete = function (key) {
delete this.store[key];
};
return InMemoryStore;
})();
exports.InMemoryStore = InMemoryStore;
/**
* A simple in-memory file system backed by an InMemoryStore.
*/
var InMemoryFileSystem = (function (_super) {
__extends(InMemoryFileSystem, _super);
function InMemoryFileSystem() {
_super.call(this, { store: new InMemoryStore() });
}
return InMemoryFileSystem;
})(kvfs.SyncKeyValueFileSystem);
exports.InMemoryFileSystem = InMemoryFileSystem;
browserfs.registerFileSystem('InMemory', InMemoryFileSystem);
});
//# sourceMappingURL=in_memory.js.map
;
var __extends = this.__extends || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
define('backend/localStorage',["require", "exports", '../core/buffer', '../core/browserfs', '../generic/key_value_filesystem', '../core/api_error', '../core/global'], function(require, exports, buffer, browserfs, kvfs, api_error, global) {
var Buffer = buffer.Buffer, ApiError = api_error.ApiError, ErrorCode = api_error.ErrorCode;
// Some versions of FF and all versions of IE do not support the full range of
// 16-bit numbers encoded as characters, as they enforce UTF-16 restrictions.
// http://stackoverflow.com/questions/11170716/are-there-any-characters-that-are-not-allowed-in-localstorage/11173673#11173673
var supportsBinaryString = false, binaryEncoding;
try {
global.localStorage.setItem("__test__", String.fromCharCode(0xD800));
supportsBinaryString = global.localStorage.getItem("__test__") === String.fromCharCode(0xD800);
} catch (e) {
// IE throws an exception.
supportsBinaryString = false;
}
binaryEncoding = supportsBinaryString ? 'binary_string' : 'binary_string_ie';
/**
* A synchronous key-value store backed by localStorage.
*/
var LocalStorageStore = (function () {
function LocalStorageStore() {
}
LocalStorageStore.prototype.name = function () {
return 'LocalStorage';
};
LocalStorageStore.prototype.clear = function () {
global.localStorage.clear();
};
LocalStorageStore.prototype.beginTransaction = function (type) {
// No need to differentiate.
return new kvfs.SimpleSyncRWTransaction(this);
};
LocalStorageStore.prototype.get = function (key) {
try {
var data = global.localStorage.getItem(key);
if (data !== null) {
return new Buffer(data, binaryEncoding);
}
} catch (e) {
}
// Key doesn't exist, or a failure occurred.
return undefined;
};
LocalStorageStore.prototype.put = function (key, data, overwrite) {
try {
if (!overwrite && global.localStorage.getItem(key) !== null) {
// Don't want to overwrite the key!
return false;
}
global.localStorage.setItem(key, data.toString(binaryEncoding));
return true;
} catch (e) {
throw new ApiError(11 /* ENOSPC */, "LocalStorage is full.");
}
};
LocalStorageStore.prototype.delete = function (key) {
try {
global.localStorage.removeItem(key);
} catch (e) {
throw new ApiError(2 /* EIO */, "Unable to delete key " + key + ": " + e);
}
};
return LocalStorageStore;
})();
exports.LocalStorageStore = LocalStorageStore;
/**
* A synchronous file system backed by localStorage. Connects our
* LocalStorageStore to our SyncKeyValueFileSystem.
*/
var LocalStorageFileSystem = (function (_super) {
__extends(LocalStorageFileSystem, _super);
function LocalStorageFileSystem() {
_super.call(this, { store: new LocalStorageStore() });
}
LocalStorageFileSystem.isAvailable = function () {
return typeof global.localStorage !== 'undefined';
};
return LocalStorageFileSystem;
})(kvfs.SyncKeyValueFileSystem);
exports.LocalStorageFileSystem = LocalStorageFileSystem;
browserfs.registerFileSystem('LocalStorage', LocalStorageFileSystem);
});
//# sourceMappingURL=localStorage.js.map
;
var __extends = this.__extends || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
define('backend/mountable_file_system',["require", "exports", '../core/file_system', './in_memory', '../core/api_error', '../core/node_fs', '../core/browserfs'], function(require, exports, file_system, in_memory, api_error, node_fs, browserfs) {
var ApiError = api_error.ApiError;
var ErrorCode = api_error.ErrorCode;
var fs = node_fs.fs;
/**
* The MountableFileSystem allows you to mount multiple backend types or
* multiple instantiations of the same backend into a single file system tree.
* The file systems do not need to know about each other; all interactions are
* automatically facilitated through this interface.
*
* For example, if a file system is mounted at /mnt/blah, and a request came in
* for /mnt/blah/foo.txt, the file system would see a request for /foo.txt.
*/
var MountableFileSystem = (function (_super) {
__extends(MountableFileSystem, _super);
function MountableFileSystem() {
_super.call(this);
this.mntMap = {};
// The InMemory file system serves purely to provide directory listings for
// mounted file systems.
this.rootFs = new in_memory.InMemoryFileSystem();
}
/**
* Mounts the file system at the given mount point.
*/
MountableFileSystem.prototype.mount = function (mnt_pt, fs) {
if (this.mntMap[mnt_pt]) {
throw new ApiError(9 /* EINVAL */, "Mount point " + mnt_pt + " is already taken.");
}
// @todo Ensure new mount path is not subsumed by active mount paths.
this.rootFs.mkdirSync(mnt_pt, 0x1ff);
this.mntMap[mnt_pt] = fs;
};
MountableFileSystem.prototype.umount = function (mnt_pt) {
if (!this.mntMap[mnt_pt]) {
throw new ApiError(9 /* EINVAL */, "Mount point " + mnt_pt + " is already unmounted.");
}
delete this.mntMap[mnt_pt];
this.rootFs.rmdirSync(mnt_pt);
};
/**
* Returns the file system that the path points to.
*/
MountableFileSystem.prototype._get_fs = function (path) {
for (var mnt_pt in this.mntMap) {
var fs = this.mntMap[mnt_pt];
if (path.indexOf(mnt_pt) === 0) {
path = path.substr(mnt_pt.length > 1 ? mnt_pt.length : 0);
if (path === '') {
path = '/';
}
return { fs: fs, path: path };
}
}
// Query our root file system.
return { fs: this.rootFs, path: path };
};
// Global information methods
MountableFileSystem.prototype.getName = function () {
return 'MountableFileSystem';
};
MountableFileSystem.isAvailable = function () {
return true;
};
MountableFileSystem.prototype.diskSpace = function (path, cb) {
cb(0, 0);
};
MountableFileSystem.prototype.isReadOnly = function () {
return false;
};
MountableFileSystem.prototype.supportsLinks = function () {
// I'm not ready for cross-FS links yet.
return false;
};
MountableFileSystem.prototype.supportsProps = function () {
return false;
};
MountableFileSystem.prototype.supportsSynch = function () {
return true;
};
/**
* Fixes up error messages so they mention the mounted file location relative
* to the MFS root, not to the particular FS's root.
* Mutates the input error, and returns it.
*/
MountableFileSystem.prototype.standardizeError = function (err, path, realPath) {
var index;
if (-1 !== (index = err.message.indexOf(path))) {
err.message = err.message.substr(0, index) + realPath + err.message.substr(index + path.length);
}
return err;
};
// The following methods involve multiple file systems, and thus have custom
// logic.
// Note that we go through the Node API to use its robust default argument
// processing.
MountableFileSystem.prototype.rename = function (oldPath, newPath, cb) {
// Scenario 1: old and new are on same FS.
var fs1_rv = this._get_fs(oldPath);
var fs2_rv = this._get_fs(newPath);
if (fs1_rv.fs === fs2_rv.fs) {
var _this = this;
return fs1_rv.fs.rename(fs1_rv.path, fs2_rv.path, function (e) {
if (e)
_this.standardizeError(_this.standardizeError(e, fs1_rv.path, oldPath), fs2_rv.path, newPath);
cb(e);
});
}
// Scenario 2: Different file systems.
// Read old file, write new file, delete old file.
return fs.readFile(oldPath, function (err, data) {
if (err) {
return cb(err);
}
fs.writeFile(newPath, data, function (err) {
if (err) {
return cb(err);
}
fs.unlink(oldPath, cb);
});
});
};
MountableFileSystem.prototype.renameSync = function (oldPath, newPath) {
// Scenario 1: old and new are on same FS.
var fs1_rv = this._get_fs(oldPath);
var fs2_rv = this._get_fs(newPath);
if (fs1_rv.fs === fs2_rv.fs) {
try {
return fs1_rv.fs.renameSync(fs1_rv.path, fs2_rv.path);
} catch (e) {
this.standardizeError(this.standardizeError(e, fs1_rv.path, oldPath), fs2_rv.path, newPath);
throw e;
}
}
// Scenario 2: Different file systems.
var data = fs.readFileSync(oldPath);
fs.writeFileSync(newPath, data);
return fs.unlinkSync(oldPath);
};
return MountableFileSystem;
})(file_system.BaseFileSystem);
exports.MountableFileSystem = MountableFileSystem;
/**
* Tricky: Define all of the functions that merely forward arguments to the
* relevant file system, or return/throw an error.
* Take advantage of the fact that the *first* argument is always the path, and
* the *last* is the callback function (if async).
*/
function defineFcn(name, isSync, numArgs) {
if (isSync) {
return function () {
var args = [];
for (var _i = 0; _i < (arguments.length - 0); _i++) {
args[_i] = arguments[_i + 0];
}
var path = args[0];
var rv = this._get_fs(path);
args[0] = rv.path;
try {
return rv.fs[name].apply(rv.fs, args);
} catch (e) {
this.standardizeError(e, rv.path, path);
throw e;
}
};
} else {
return function () {
var args = [];
for (var _i = 0; _i < (arguments.length - 0); _i++) {
args[_i] = arguments[_i + 0];
}
var path = args[0];
var rv = this._get_fs(path);
args[0] = rv.path;
if (typeof args[args.length - 1] === 'function') {
var cb = args[args.length - 1];
var _this = this;
args[args.length - 1] = function () {
var args = [];
for (var _i = 0; _i < (arguments.length - 0); _i++) {
args[_i] = arguments[_i + 0];
}
if (args.length > 0 && args[0] instanceof api_error.ApiError) {
_this.standardizeError(args[0], rv.path, path);
}
cb.apply(null, args);
};
}
return rv.fs[name].apply(rv.fs, args);
};
}
}
var fsCmdMap = [
['readdir', 'exists', 'unlink', 'rmdir', 'readlink'],
['stat', 'mkdir', 'realpath', 'truncate'],
['open', 'readFile', 'chmod', 'utimes'],
['chown'],
['writeFile', 'appendFile']];
for (var i = 0; i < fsCmdMap.length; i++) {
var cmds = fsCmdMap[i];
for (var j = 0; j < cmds.length; j++) {
var fnName = cmds[j];
MountableFileSystem.prototype[fnName] = defineFcn(fnName, false, i + 1);
MountableFileSystem.prototype[fnName + 'Sync'] = defineFcn(fnName + 'Sync', true, i + 1);
}
}
browserfs.registerFileSystem('MountableFileSystem', MountableFileSystem);
});
//# sourceMappingURL=mountable_file_system.js.map
;
/** @license zlib.js 2012 - imaya [ https://github.com/imaya/zlib.js ] The MIT License */(function() {var l=void 0,p=this;function q(c,d){var a=c.split("."),b=p;!(a[0]in b)&&b.execScript&&b.execScript("var "+a[0]);for(var e;a.length&&(e=a.shift());)!a.length&&d!==l?b[e]=d:b=b[e]?b[e]:b[e]={}};var r="undefined"!==typeof Uint8Array&&"undefined"!==typeof Uint16Array&&"undefined"!==typeof Uint32Array;function u(c){var d=c.length,a=0,b=Number.POSITIVE_INFINITY,e,f,g,h,k,m,s,n,t;for(n=0;n<d;++n)c[n]>a&&(a=c[n]),c[n]<b&&(b=c[n]);e=1<<a;f=new (r?Uint32Array:Array)(e);g=1;h=0;for(k=2;g<=a;){for(n=0;n<d;++n)if(c[n]===g){m=0;s=h;for(t=0;t<g;++t)m=m<<1|s&1,s>>=1;for(t=m;t<e;t+=k)f[t]=g<<16|n;++h}++g;h<<=1;k<<=1}return[f,a,b]};function v(c,d){this.g=[];this.h=32768;this.c=this.f=this.d=this.k=0;this.input=r?new Uint8Array(c):c;this.l=!1;this.i=w;this.p=!1;if(d||!(d={}))d.index&&(this.d=d.index),d.bufferSize&&(this.h=d.bufferSize),d.bufferType&&(this.i=d.bufferType),d.resize&&(this.p=d.resize);switch(this.i){case x:this.a=32768;this.b=new (r?Uint8Array:Array)(32768+this.h+258);break;case w:this.a=0;this.b=new (r?Uint8Array:Array)(this.h);this.e=this.u;this.m=this.r;this.j=this.s;break;default:throw Error("invalid inflate mode");
}}var x=0,w=1;
v.prototype.t=function(){for(;!this.l;){var c=y(this,3);c&1&&(this.l=!0);c>>>=1;switch(c){case 0:var d=this.input,a=this.d,b=this.b,e=this.a,f=l,g=l,h=l,k=b.length,m=l;this.c=this.f=0;f=d[a++];if(f===l)throw Error("invalid uncompressed block header: LEN (first byte)");g=f;f=d[a++];if(f===l)throw Error("invalid uncompressed block header: LEN (second byte)");g|=f<<8;f=d[a++];if(f===l)throw Error("invalid uncompressed block header: NLEN (first byte)");h=f;f=d[a++];if(f===l)throw Error("invalid uncompressed block header: NLEN (second byte)");h|=
f<<8;if(g===~h)throw Error("invalid uncompressed block header: length verify");if(a+g>d.length)throw Error("input buffer is broken");switch(this.i){case x:for(;e+g>b.length;){m=k-e;g-=m;if(r)b.set(d.subarray(a,a+m),e),e+=m,a+=m;else for(;m--;)b[e++]=d[a++];this.a=e;b=this.e();e=this.a}break;case w:for(;e+g>b.length;)b=this.e({o:2});break;default:throw Error("invalid inflate mode");}if(r)b.set(d.subarray(a,a+g),e),e+=g,a+=g;else for(;g--;)b[e++]=d[a++];this.d=a;this.a=e;this.b=b;break;case 1:this.j(z,
A);break;case 2:B(this);break;default:throw Error("unknown BTYPE: "+c);}}return this.m()};
var C=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],D=r?new Uint16Array(C):C,E=[3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258,258,258],F=r?new Uint16Array(E):E,G=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0],H=r?new Uint8Array(G):G,I=[1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577],J=r?new Uint16Array(I):I,K=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,
13],L=r?new Uint8Array(K):K,M=new (r?Uint8Array:Array)(288),N,O;N=0;for(O=M.length;N<O;++N)M[N]=143>=N?8:255>=N?9:279>=N?7:8;var z=u(M),P=new (r?Uint8Array:Array)(30),Q,R;Q=0;for(R=P.length;Q<R;++Q)P[Q]=5;var A=u(P);function y(c,d){for(var a=c.f,b=c.c,e=c.input,f=c.d,g;b<d;){g=e[f++];if(g===l)throw Error("input buffer is broken");a|=g<<b;b+=8}g=a&(1<<d)-1;c.f=a>>>d;c.c=b-d;c.d=f;return g}
function S(c,d){for(var a=c.f,b=c.c,e=c.input,f=c.d,g=d[0],h=d[1],k,m,s;b<h;){k=e[f++];if(k===l)break;a|=k<<b;b+=8}m=g[a&(1<<h)-1];s=m>>>16;c.f=a>>s;c.c=b-s;c.d=f;return m&65535}
function B(c){function d(a,c,b){var d,f,e,g;for(g=0;g<a;)switch(d=S(this,c),d){case 16:for(e=3+y(this,2);e--;)b[g++]=f;break;case 17:for(e=3+y(this,3);e--;)b[g++]=0;f=0;break;case 18:for(e=11+y(this,7);e--;)b[g++]=0;f=0;break;default:f=b[g++]=d}return b}var a=y(c,5)+257,b=y(c,5)+1,e=y(c,4)+4,f=new (r?Uint8Array:Array)(D.length),g,h,k,m;for(m=0;m<e;++m)f[D[m]]=y(c,3);g=u(f);h=new (r?Uint8Array:Array)(a);k=new (r?Uint8Array:Array)(b);c.j(u(d.call(c,a,g,h)),u(d.call(c,b,g,k)))}
v.prototype.j=function(c,d){var a=this.b,b=this.a;this.n=c;for(var e=a.length-258,f,g,h,k;256!==(f=S(this,c));)if(256>f)b>=e&&(this.a=b,a=this.e(),b=this.a),a[b++]=f;else{g=f-257;k=F[g];0<H[g]&&(k+=y(this,H[g]));f=S(this,d);h=J[f];0<L[f]&&(h+=y(this,L[f]));b>=e&&(this.a=b,a=this.e(),b=this.a);for(;k--;)a[b]=a[b++-h]}for(;8<=this.c;)this.c-=8,this.d--;this.a=b};
v.prototype.s=function(c,d){var a=this.b,b=this.a;this.n=c;for(var e=a.length,f,g,h,k;256!==(f=S(this,c));)if(256>f)b>=e&&(a=this.e(),e=a.length),a[b++]=f;else{g=f-257;k=F[g];0<H[g]&&(k+=y(this,H[g]));f=S(this,d);h=J[f];0<L[f]&&(h+=y(this,L[f]));b+k>e&&(a=this.e(),e=a.length);for(;k--;)a[b]=a[b++-h]}for(;8<=this.c;)this.c-=8,this.d--;this.a=b};
v.prototype.e=function(){var c=new (r?Uint8Array:Array)(this.a-32768),d=this.a-32768,a,b,e=this.b;if(r)c.set(e.subarray(32768,c.length));else{a=0;for(b=c.length;a<b;++a)c[a]=e[a+32768]}this.g.push(c);this.k+=c.length;if(r)e.set(e.subarray(d,d+32768));else for(a=0;32768>a;++a)e[a]=e[d+a];this.a=32768;return e};
v.prototype.u=function(c){var d,a=this.input.length/this.d+1|0,b,e,f,g=this.input,h=this.b;c&&("number"===typeof c.o&&(a=c.o),"number"===typeof c.q&&(a+=c.q));2>a?(b=(g.length-this.d)/this.n[2],f=258*(b/2)|0,e=f<h.length?h.length+f:h.length<<1):e=h.length*a;r?(d=new Uint8Array(e),d.set(h)):d=h;return this.b=d};
v.prototype.m=function(){var c=0,d=this.b,a=this.g,b,e=new (r?Uint8Array:Array)(this.k+(this.a-32768)),f,g,h,k;if(0===a.length)return r?this.b.subarray(32768,this.a):this.b.slice(32768,this.a);f=0;for(g=a.length;f<g;++f){b=a[f];h=0;for(k=b.length;h<k;++h)e[c++]=b[h]}f=32768;for(g=this.a;f<g;++f)e[c++]=d[f];this.g=[];return this.buffer=e};
v.prototype.r=function(){var c,d=this.a;r?this.p?(c=new Uint8Array(d),c.set(this.b.subarray(0,d))):c=this.b.subarray(0,d):(this.b.length>d&&(this.b.length=d),c=this.b);return this.buffer=c};q("Zlib.RawInflate",v);q("Zlib.RawInflate.prototype.decompress",v.prototype.t);var T={ADAPTIVE:w,BLOCK:x},U,V,W,X;if(Object.keys)U=Object.keys(T);else for(V in U=[],W=0,T)U[W++]=V;W=0;for(X=U.length;W<X;++W)V=U[W],q("Zlib.RawInflate.BufferType."+V,T[V]);}).call(this); //@ sourceMappingURL=rawinflate.min.js.map
;
define("zlib", (function (global) {
return function () {
var ret, fn;
return ret || global.Zlib.RawInflate;
};
}(this)));
/// <amd-dependency path="zlib" />
var __extends = this.__extends || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
define('backend/zipfs',["require", "exports", '../core/buffer', '../core/api_error', '../generic/file_index', '../core/browserfs', '../core/node_fs_stats', '../core/file_system', '../core/file_flag', '../core/buffer_core_arraybuffer', '../generic/preload_file', "zlib"], function(require, exports, buffer, api_error, file_index, browserfs, node_fs_stats, file_system, file_flag, buffer_core_arraybuffer, preload_file) {
var ApiError = api_error.ApiError;
var ErrorCode = api_error.ErrorCode;
var ActionType = file_flag.ActionType;
var RawInflate = Zlib.RawInflate;
/**
* 4.4.2.2: Indicates the compatibiltiy of a file's external attributes.
*/
(function (ExternalFileAttributeType) {
ExternalFileAttributeType[ExternalFileAttributeType["MSDOS"] = 0] = "MSDOS";
ExternalFileAttributeType[ExternalFileAttributeType["AMIGA"] = 1] = "AMIGA";
ExternalFileAttributeType[ExternalFileAttributeType["OPENVMS"] = 2] = "OPENVMS";
ExternalFileAttributeType[ExternalFileAttributeType["UNIX"] = 3] = "UNIX";
ExternalFileAttributeType[ExternalFileAttributeType["VM_CMS"] = 4] = "VM_CMS";
ExternalFileAttributeType[ExternalFileAttributeType["ATARI_ST"] = 5] = "ATARI_ST";
ExternalFileAttributeType[ExternalFileAttributeType["OS2_HPFS"] = 6] = "OS2_HPFS";
ExternalFileAttributeType[ExternalFileAttributeType["MAC"] = 7] = "MAC";
ExternalFileAttributeType[ExternalFileAttributeType["Z_SYSTEM"] = 8] = "Z_SYSTEM";
ExternalFileAttributeType[ExternalFileAttributeType["CP_M"] = 9] = "CP_M";
ExternalFileAttributeType[ExternalFileAttributeType["NTFS"] = 10] = "NTFS";
ExternalFileAttributeType[ExternalFileAttributeType["MVS"] = 11] = "MVS";
ExternalFileAttributeType[ExternalFileAttributeType["VSE"] = 12] = "VSE";
ExternalFileAttributeType[ExternalFileAttributeType["ACORN_RISC"] = 13] = "ACORN_RISC";
ExternalFileAttributeType[ExternalFileAttributeType["VFAT"] = 14] = "VFAT";
ExternalFileAttributeType[ExternalFileAttributeType["ALT_MVS"] = 15] = "ALT_MVS";
ExternalFileAttributeType[ExternalFileAttributeType["BEOS"] = 16] = "BEOS";
ExternalFileAttributeType[ExternalFileAttributeType["TANDEM"] = 17] = "TANDEM";
ExternalFileAttributeType[ExternalFileAttributeType["OS_400"] = 18] = "OS_400";
ExternalFileAttributeType[ExternalFileAttributeType["OSX"] = 19] = "OSX";
})(exports.ExternalFileAttributeType || (exports.ExternalFileAttributeType = {}));
var ExternalFileAttributeType = exports.ExternalFileAttributeType;
/**
* 4.4.5
*/
(function (CompressionMethod) {
CompressionMethod[CompressionMethod["STORED"] = 0] = "STORED";
CompressionMethod[CompressionMethod["SHRUNK"] = 1] = "SHRUNK";
CompressionMethod[CompressionMethod["REDUCED_1"] = 2] = "REDUCED_1";
CompressionMethod[CompressionMethod["REDUCED_2"] = 3] = "REDUCED_2";
CompressionMethod[CompressionMethod["REDUCED_3"] = 4] = "REDUCED_3";
CompressionMethod[CompressionMethod["REDUCED_4"] = 5] = "REDUCED_4";
CompressionMethod[CompressionMethod["IMPLODE"] = 6] = "IMPLODE";
CompressionMethod[CompressionMethod["DEFLATE"] = 8] = "DEFLATE";
CompressionMethod[CompressionMethod["DEFLATE64"] = 9] = "DEFLATE64";
CompressionMethod[CompressionMethod["TERSE_OLD"] = 10] = "TERSE_OLD";
CompressionMethod[CompressionMethod["BZIP2"] = 12] = "BZIP2";
CompressionMethod[CompressionMethod["LZMA"] = 14] = "LZMA";
CompressionMethod[CompressionMethod["TERSE_NEW"] = 18] = "TERSE_NEW";
CompressionMethod[CompressionMethod["LZ77"] = 19] = "LZ77";
CompressionMethod[CompressionMethod["WAVPACK"] = 97] = "WAVPACK";
CompressionMethod[CompressionMethod["PPMD"] = 98] = "PPMD";
})(exports.CompressionMethod || (exports.CompressionMethod = {}));
var CompressionMethod = exports.CompressionMethod;
/**
* Converts the input time and date in MS-DOS format into a JavaScript Date
* object.
*/
function msdos2date(time, date) {
// MS-DOS Date
//|0 0 0 0 0|0 0 0 0|0 0 0 0 0 0 0
// D (1-31) M (1-23) Y (from 1980)
var day = date & 0x1F;
// JS date is 0-indexed, DOS is 1-indexed.
var month = ((date >> 5) & 0xF) - 1;
var year = (date >> 9) + 1980;
// MS DOS Time
//|0 0 0 0 0|0 0 0 0 0 0|0 0 0 0 0
// Second Minute Hour
var second = time & 0x1F;
var minute = (time >> 5) & 0x3F;
var hour = time >> 11;
return new Date(year, month, day, hour, minute, second);
}
/**
* Safely returns the string from the buffer, even if it is 0 bytes long.
* (Normally, calling toString() on a buffer with start === end causes an
* exception).
*/
function safeToString(buff, useUTF8, start, length) {
return length === 0 ? "" : buff.toString(useUTF8 ? 'utf8' : 'extended_ascii', start, start + length);
}
/*
4.3.6 Overall .ZIP file format:
[local file header 1]
[encryption header 1]
[file data 1]
[data descriptor 1]
.
.
.
[local file header n]
[encryption header n]
[file data n]
[data descriptor n]
[archive decryption header]
[archive extra data record]
[central directory header 1]
.
.
.
[central directory header n]
[zip64 end of central directory record]
[zip64 end of central directory locator]
[end of central directory record]
*/
/*
4.3.7 Local file header:
local file header signature 4 bytes (0x04034b50)
version needed to extract 2 bytes
general purpose bit flag 2 bytes
compression method 2 bytes
last mod file time 2 bytes
last mod file date 2 bytes
crc-32 4 bytes
compressed size 4 bytes
uncompressed size 4 bytes
file name length 2 bytes
extra field length 2 bytes
file name (variable size)
extra field (variable size)
*/
var FileHeader = (function () {
function FileHeader(data) {
this.data = data;
if (data.readUInt32LE(0) !== 0x04034b50) {
throw new ApiError(9 /* EINVAL */, "Invalid Zip file: Local file header has invalid signature: " + this.data.readUInt32LE(0));
}
}
FileHeader.prototype.versionNeeded = function () {
return this.data.readUInt16LE(4);
};
FileHeader.prototype.flags = function () {
return this.data.readUInt16LE(6);
};
FileHeader.prototype.compressionMethod = function () {
return this.data.readUInt16LE(8);
};
FileHeader.prototype.lastModFileTime = function () {
// Time and date is in MS-DOS format.
return msdos2date(this.data.readUInt16LE(10), this.data.readUInt16LE(12));
};
FileHeader.prototype.crc32 = function () {
return this.data.readUInt32LE(14);
};
/**
* These two values are COMPLETELY USELESS.
*
* Section 4.4.9:
* If bit 3 of the general purpose bit flag is set,
* these fields are set to zero in the local header and the
* correct values are put in the data descriptor and
* in the central directory.
*
* So we'll just use the central directory's values.
*/
// public compressedSize(): number { return this.data.readUInt32LE(18); }
// public uncompressedSize(): number { return this.data.readUInt32LE(22); }
FileHeader.prototype.fileNameLength = function () {
return this.data.readUInt16LE(26);
};
FileHeader.prototype.extraFieldLength = function () {
return this.data.readUInt16LE(28);
};
FileHeader.prototype.fileName = function () {
return safeToString(this.data, this.useUTF8(), 30, this.fileNameLength());
};
FileHeader.prototype.extraField = function () {
var start = 30 + this.fileNameLength();
return this.data.slice(start, start + this.extraFieldLength());
};
FileHeader.prototype.totalSize = function () {
return 30 + this.fileNameLength() + this.extraFieldLength();
};
FileHeader.prototype.useUTF8 = function () {
return (this.flags() & 0x800) === 0x800;
};
return FileHeader;
})();
exports.FileHeader = FileHeader;
/**
4.3.8 File data
Immediately following the local header for a file
SHOULD be placed the compressed or stored data for the file.
If the file is encrypted, the encryption header for the file
SHOULD be placed after the local header and before the file
data. The series of [local file header][encryption header]
[file data][data descriptor] repeats for each file in the
.ZIP archive.
Zero-byte files, directories, and other file types that
contain no content MUST not include file data.
*/
var FileData = (function () {
function FileData(header, record, data) {
this.header = header;
this.record = record;
this.data = data;
}
FileData.prototype.decompress = function () {
var buff = this.data;
// Check the compression
var compressionMethod = this.header.compressionMethod();
switch (compressionMethod) {
case 8 /* DEFLATE */:
// Convert to Uint8Array or an array of bytes for the library.
if (buff.getBufferCore() instanceof buffer_core_arraybuffer.BufferCoreArrayBuffer) {
// Grab a slice of the zip file that contains the compressed data
// (avoids copying).
// XXX: Does RawInflate mutate the buffer? I hope not.
var bcore = buff.getBufferCore();
var dview = bcore.getDataView();
var start = dview.byteOffset + buff.getOffset();
var uarray = (new Uint8Array(dview.buffer)).subarray(start, start + this.record.compressedSize());
var data = (new RawInflate(uarray)).decompress();
return new buffer.Buffer(new buffer_core_arraybuffer.BufferCoreArrayBuffer(data.buffer), data.byteOffset, data.byteOffset + data.length);
} else {
// Convert to an array of bytes and decompress, then write into a new
// buffer :(
var newBuff = buff.slice(0, this.record.compressedSize());
return new buffer.Buffer((new RawInflate(newBuff.toJSON().data)).decompress());
}
case 0 /* STORED */:
// Grab and copy.
return buff.sliceCopy(0, this.record.uncompressedSize());
default:
var name = CompressionMethod[compressionMethod];
name = name ? name : "Unknown: " + compressionMethod;
throw new ApiError(9 /* EINVAL */, "Invalid compression method on file '" + this.header.fileName() + "': " + name);
}
};
return FileData;
})();
exports.FileData = FileData;
/*
4.3.9 Data descriptor:
crc-32 4 bytes
compressed size 4 bytes
uncompressed size 4 bytes
*/
var DataDescriptor = (function () {
function DataDescriptor(data) {
this.data = data;
}
DataDescriptor.prototype.crc32 = function () {
return this.data.readUInt32LE(0);
};
DataDescriptor.prototype.compressedSize = function () {
return this.data.readUInt32LE(4);
};
DataDescriptor.prototype.uncompressedSize = function () {
return this.data.readUInt32LE(8);
};
return DataDescriptor;
})();
exports.DataDescriptor = DataDescriptor;
/*
` 4.3.10 Archive decryption header:
4.3.10.1 The Archive Decryption Header is introduced in version 6.2
of the ZIP format specification. This record exists in support
of the Central Directory Encryption Feature implemented as part of
the Strong Encryption Specification as described in this document.
When the Central Directory Structure is encrypted, this decryption
header MUST precede the encrypted data segment.
*/
/*
4.3.11 Archive extra data record:
archive extra data signature 4 bytes (0x08064b50)
extra field length 4 bytes
extra field data (variable size)
4.3.11.1 The Archive Extra Data Record is introduced in version 6.2
of the ZIP format specification. This record MAY be used in support
of the Central Directory Encryption Feature implemented as part of
the Strong Encryption Specification as described in this document.
When present, this record MUST immediately precede the central
directory data structure.
*/
var ArchiveExtraDataRecord = (function () {
function ArchiveExtraDataRecord(data) {
this.data = data;
if (this.data.readUInt32LE(0) !== 0x08064b50) {
throw new ApiError(9 /* EINVAL */, "Invalid archive extra data record signature: " + this.data.readUInt32LE(0));
}
}
ArchiveExtraDataRecord.prototype.length = function () {
return this.data.readUInt32LE(4);
};
ArchiveExtraDataRecord.prototype.extraFieldData = function () {
return this.data.slice(8, 8 + this.length());
};
return ArchiveExtraDataRecord;
})();
exports.ArchiveExtraDataRecord = ArchiveExtraDataRecord;
/*
4.3.13 Digital signature:
header signature 4 bytes (0x05054b50)
size of data 2 bytes
signature data (variable size)
With the introduction of the Central Directory Encryption
feature in version 6.2 of this specification, the Central
Directory Structure MAY be stored both compressed and encrypted.
Although not required, it is assumed when encrypting the
Central Directory Structure, that it will be compressed
for greater storage efficiency. Information on the
Central Directory Encryption feature can be found in the section
describing the Strong Encryption Specification. The Digital
Signature record will be neither compressed nor encrypted.
*/
var DigitalSignature = (function () {
function DigitalSignature(data) {
this.data = data;
if (this.data.readUInt32LE(0) !== 0x05054b50) {
throw new ApiError(9 /* EINVAL */, "Invalid digital signature signature: " + this.data.readUInt32LE(0));
}
}
DigitalSignature.prototype.size = function () {
return this.data.readUInt16LE(4);
};
DigitalSignature.prototype.signatureData = function () {
return this.data.slice(6, 6 + this.size());
};
return DigitalSignature;
})();
exports.DigitalSignature = DigitalSignature;
/*
4.3.12 Central directory structure:
central file header signature 4 bytes (0x02014b50)
version made by 2 bytes
version needed to extract 2 bytes
general purpose bit flag 2 bytes
compression method 2 bytes
last mod file time 2 bytes
last mod file date 2 bytes
crc-32 4 bytes
compressed size 4 bytes
uncompressed size 4 bytes
file name length 2 bytes
extra field length 2 bytes
file comment length 2 bytes
disk number start 2 bytes
internal file attributes 2 bytes
external file attributes 4 bytes
relative offset of local header 4 bytes
file name (variable size)
extra field (variable size)
file comment (variable size)
*/
var CentralDirectory = (function () {
function CentralDirectory(zipData, data) {
this.zipData = zipData;
this.data = data;
// Sanity check.
if (this.data.readUInt32LE(0) !== 0x02014b50)
throw new ApiError(9 /* EINVAL */, "Invalid Zip file: Central directory record has invalid signature: " + this.data.readUInt32LE(0));
}
CentralDirectory.prototype.versionMadeBy = function () {
return this.data.readUInt16LE(4);
};
CentralDirectory.prototype.versionNeeded = function () {
return this.data.readUInt16LE(6);
};
CentralDirectory.prototype.flag = function () {
return this.data.readUInt16LE(8);
};
CentralDirectory.prototype.compressionMethod = function () {
return this.data.readUInt16LE(10);
};
CentralDirectory.prototype.lastModFileTime = function () {
// Time and date is in MS-DOS format.
return msdos2date(this.data.readUInt16LE(12), this.data.readUInt16LE(14));
};
CentralDirectory.prototype.crc32 = function () {
return this.data.readUInt32LE(16);
};
CentralDirectory.prototype.compressedSize = function () {
return this.data.readUInt32LE(20);
};
CentralDirectory.prototype.uncompressedSize = function () {
return this.data.readUInt32LE(24);
};
CentralDirectory.prototype.fileNameLength = function () {
return this.data.readUInt16LE(28);
};
CentralDirectory.prototype.extraFieldLength = function () {
return this.data.readUInt16LE(30);
};
CentralDirectory.prototype.fileCommentLength = function () {
return this.data.readUInt16LE(32);
};
CentralDirectory.prototype.diskNumberStart = function () {
return this.data.readUInt16LE(34);
};
CentralDirectory.prototype.internalAttributes = function () {
return this.data.readUInt16LE(36);
};
CentralDirectory.prototype.externalAttributes = function () {
return this.data.readUInt32LE(38);
};
CentralDirectory.prototype.headerRelativeOffset = function () {
return this.data.readUInt32LE(42);
};
CentralDirectory.prototype.fileName = function () {
/*
4.4.17.1 claims:
* All slashes are forward ('/') slashes.
* Filename doesn't begin with a slash.
* No drive letters or any nonsense like that.
* If filename is missing, the input came from standard input.
Unfortunately, this isn't true in practice. Some Windows zip utilities use
a backslash here, but the correct Unix-style path in file headers.
To avoid seeking all over the file to recover the known-good filenames
from file headers, we simply convert '/' to '\' here.
*/
var fileName = safeToString(this.data, this.useUTF8(), 46, this.fileNameLength());
return fileName.replace(/\\/g, "/");
};
CentralDirectory.prototype.extraField = function () {
var start = 44 + this.fileNameLength();
return this.data.slice(start, start + this.extraFieldLength());
};
CentralDirectory.prototype.fileComment = function () {
var start = 46 + this.fileNameLength() + this.extraFieldLength();
return safeToString(this.data, this.useUTF8(), start, this.fileCommentLength());
};
CentralDirectory.prototype.totalSize = function () {
return 46 + this.fileNameLength() + this.extraFieldLength() + this.fileCommentLength();
};
CentralDirectory.prototype.isDirectory = function () {
// NOTE: This assumes that the zip file implementation uses the lower byte
// of external attributes for DOS attributes for
// backwards-compatibility. This is not mandated, but appears to be
// commonplace.
// According to the spec, the layout of external attributes is
// platform-dependent.
// If that fails, we also check if the name of the file ends in '/',
// which is what Java's ZipFile implementation does.
var fileName = this.fileName();
return (this.externalAttributes() & 0x10 ? true : false) || (fileName.charAt(fileName.length - 1) === '/');
};
CentralDirectory.prototype.isFile = function () {
return !this.isDirectory();
};
CentralDirectory.prototype.useUTF8 = function () {
return (this.flag() & 0x800) === 0x800;
};
CentralDirectory.prototype.isEncrypted = function () {
return (this.flag() & 0x1) === 0x1;
};
CentralDirectory.prototype.getData = function () {
// Need to grab the header before we can figure out where the actual
// compressed data starts.
var start = this.headerRelativeOffset();
var header = new FileHeader(this.zipData.slice(start));
var filedata = new FileData(header, this, this.zipData.slice(start + header.totalSize()));
return filedata.decompress();
};
CentralDirectory.prototype.getStats = function () {
return new node_fs_stats.Stats(32768 /* FILE */, this.uncompressedSize(), 0x16D, new Date(), this.lastModFileTime());
};
return CentralDirectory;
})();
exports.CentralDirectory = CentralDirectory;
/*
4.3.16: end of central directory record
end of central dir signature 4 bytes (0x06054b50)
number of this disk 2 bytes
number of the disk with the
start of the central directory 2 bytes
total number of entries in the
central directory on this disk 2 bytes
total number of entries in
the central directory 2 bytes
size of the central directory 4 bytes
offset of start of central
directory with respect to
the starting disk number 4 bytes
.ZIP file comment length 2 bytes
.ZIP file comment (variable size)
*/
var EndOfCentralDirectory = (function () {
function EndOfCentralDirectory(data) {
this.data = data;
if (this.data.readUInt32LE(0) !== 0x06054b50)
throw new ApiError(9 /* EINVAL */, "Invalid Zip file: End of central directory record has invalid signature: " + this.data.readUInt32LE(0));
}
EndOfCentralDirectory.prototype.diskNumber = function () {
return this.data.readUInt16LE(4);
};
EndOfCentralDirectory.prototype.cdDiskNumber = function () {
return this.data.readUInt16LE(6);
};
EndOfCentralDirectory.prototype.cdDiskEntryCount = function () {
return this.data.readUInt16LE(8);
};
EndOfCentralDirectory.prototype.cdTotalEntryCount = function () {
return this.data.readUInt16LE(10);
};
EndOfCentralDirectory.prototype.cdSize = function () {
return this.data.readUInt32LE(12);
};
EndOfCentralDirectory.prototype.cdOffset = function () {
return this.data.readUInt32LE(16);
};
EndOfCentralDirectory.prototype.cdZipComment = function () {
// Assuming UTF-8. The specification doesn't specify.
return safeToString(this.data, true, 22, this.data.readUInt16LE(20));
};
return EndOfCentralDirectory;
})();
exports.EndOfCentralDirectory = EndOfCentralDirectory;
var ZipFS = (function (_super) {
__extends(ZipFS, _super);
/**
* Constructs a ZipFS from the given zip file data. Name is optional, and is
* used primarily for our unit tests' purposes to differentiate different
* test zip files in test output.
*/
function ZipFS(data, name) {
if (typeof name === "undefined") { name = ''; }
_super.call(this);
this.data = data;
this.name = name;
this._index = new file_index.FileIndex();
this.populateIndex();
}
ZipFS.prototype.getName = function () {
return 'ZipFS' + (this.name !== '' ? ' ' + this.name : '');
};
ZipFS.isAvailable = function () {
return true;
};
ZipFS.prototype.diskSpace = function (path, cb) {
// Read-only file system.
cb(this.data.length, 0);
};
ZipFS.prototype.isReadOnly = function () {
return true;
};
ZipFS.prototype.supportsLinks = function () {
return false;
};
ZipFS.prototype.supportsProps = function () {
return false;
};
ZipFS.prototype.supportsSynch = function () {
return true;
};
ZipFS.prototype.statSync = function (path, isLstat) {
var inode = this._index.getInode(path);
if (inode === null) {
throw new ApiError(1 /* ENOENT */, "" + path + " not found.");
}
var stats;
if (inode.isFile()) {
stats = inode.getData().getStats();
} else {
stats = inode.getStats();
}
return stats;
};
ZipFS.prototype.openSync = function (path, flags, mode) {
// INVARIANT: Cannot write to RO file systems.
if (flags.isWriteable()) {
throw new ApiError(0 /* EPERM */, path);
}
// Check if the path exists, and is a file.
var inode = this._index.getInode(path);
if (inode === null) {
throw new ApiError(1 /* ENOENT */, "" + path + " is not in the FileIndex.");
}
if (inode.isDir()) {
throw new ApiError(8 /* EISDIR */, "" + path + " is a directory.");
}
var cdRecord = inode.getData();
var stats = cdRecord.getStats();
switch (flags.pathExistsAction()) {
case 1 /* THROW_EXCEPTION */:
case 2 /* TRUNCATE_FILE */:
throw new ApiError(6 /* EEXIST */, "" + path + " already exists.");
case 0 /* NOP */:
return new preload_file.NoSyncFile(this, path, flags, stats, cdRecord.getData());
default:
throw new ApiError(9 /* EINVAL */, 'Invalid FileMode object.');
}
return null;
};
ZipFS.prototype.readdirSync = function (path) {
// Check if it exists.
var inode = this._index.getInode(path);
if (inode === null) {
throw new ApiError(1 /* ENOENT */, "" + path + " not found.");
} else if (inode.isFile()) {
throw new ApiError(7 /* ENOTDIR */, "" + path + " is a file, not a directory.");
}
return inode.getListing();
};
/**
* Specially-optimized readfile.
*/
ZipFS.prototype.readFileSync = function (fname, encoding, flag) {
// Get file.
var fd = this.openSync(fname, flag, 0x1a4);
try {
var fdCast = fd;
var fdBuff = fdCast._buffer;
if (encoding === null) {
if (fdBuff.length > 0) {
return fdBuff.sliceCopy();
} else {
return new buffer.Buffer(0);
}
}
return fdBuff.toString(encoding);
} finally {
fd.closeSync();
}
};
/**
* Locates the end of central directory record at the end of the file.
* Throws an exception if it cannot be found.
*/
ZipFS.prototype.getEOCD = function () {
// Unfortunately, the comment is variable size and up to 64K in size.
// We assume that the magic signature does not appear in the comment, and
// in the bytes between the comment and the signature. Other ZIP
// implementations make this same assumption, since the alternative is to
// read thread every entry in the file to get to it. :(
// These are *negative* offsets from the end of the file.
var startOffset = 22;
var endOffset = Math.min(startOffset + 0xFFFF, this.data.length - 1);
for (var i = startOffset; i < endOffset; i++) {
// Magic number: EOCD Signature
if (this.data.readUInt32LE(this.data.length - i) === 0x06054b50) {
return new EndOfCentralDirectory(this.data.slice(this.data.length - i));
}
}
throw new ApiError(9 /* EINVAL */, "Invalid ZIP file: Could not locate End of Central Directory signature.");
};
ZipFS.prototype.populateIndex = function () {
var eocd = this.getEOCD();
if (eocd.diskNumber() !== eocd.cdDiskNumber())
throw new ApiError(9 /* EINVAL */, "ZipFS does not support spanned zip files.");
var cdPtr = eocd.cdOffset();
if (cdPtr === 0xFFFFFFFF)
throw new ApiError(9 /* EINVAL */, "ZipFS does not support Zip64.");
var cdEnd = cdPtr + eocd.cdSize();
while (cdPtr < cdEnd) {
var cd = new CentralDirectory(this.data, this.data.slice(cdPtr));
cdPtr += cd.totalSize();
// Paths must be absolute, yet zip file paths are always relative to the
// zip root. So we append '/' and call it a day.
var filename = cd.fileName();
if (filename.charAt(0) === '/')
throw new Error("WHY IS THIS ABSOLUTE");
// XXX: For the file index, strip the trailing '/'.
if (filename.charAt(filename.length - 1) === '/') {
filename = filename.substr(0, filename.length - 1);
}
if (cd.isDirectory()) {
this._index.addPath('/' + filename, new file_index.DirInode());
} else {
this._index.addPath('/' + filename, new file_index.FileInode(cd));
}
}
};
return ZipFS;
})(file_system.SynchronousFileSystem);
exports.ZipFS = ZipFS;
browserfs.registerFileSystem('ZipFS', ZipFS);
});
//# sourceMappingURL=zipfs.js.map
;require('core/global').BrowserFS=require('core/browserfs');require('generic/emscripten_fs');require('backend/IndexedDB');require('backend/XmlHttpRequest');require('backend/dropbox');require('backend/html5fs');require('backend/in_memory');require('backend/localStorage');require('backend/mountable_file_system');require('backend/zipfs');})();
//# sourceMappingURL=browserfs.js.map