diff options
Diffstat (limited to 'utils/platforms')
-rwxr-xr-x | utils/platforms/browser/inline.js | 56 | ||||
-rwxr-xr-x | utils/platforms/browser/lib/modules.js | 1449 | ||||
-rwxr-xr-x | utils/platforms/browser/lib/system.js | 3 | ||||
-rwxr-xr-x | utils/platforms/default/lib/binary-platform.js | 53 | ||||
-rwxr-xr-x | utils/platforms/default/lib/binary.js | 719 | ||||
-rwxr-xr-x | utils/platforms/default/lib/os-platform.js | 3 | ||||
-rwxr-xr-x | utils/platforms/k7/bin/narwhal-k7 | 32 | ||||
-rwxr-xr-x | utils/platforms/k7/bootstrap.js | 78 | ||||
-rwxr-xr-x | utils/platforms/k7/lib/binary.js | 2 | ||||
-rwxr-xr-x | utils/platforms/k7/lib/file-platform.js | 116 | ||||
-rwxr-xr-x | utils/platforms/k7/lib/io-platform.js | 8 | ||||
-rwxr-xr-x | utils/platforms/k7/lib/system.js | 25 | ||||
-rwxr-xr-x | utils/platforms/rhino/bin/narwhal-rhino.cmd | 25 | ||||
-rwxr-xr-x | utils/platforms/rhino/lib/binary-platform.js | 44 |
14 files changed, 2613 insertions, 0 deletions
diff --git a/utils/platforms/browser/inline.js b/utils/platforms/browser/inline.js new file mode 100755 index 0000000..16d8b11 --- /dev/null +++ b/utils/platforms/browser/inline.js @@ -0,0 +1,56 @@ +(function (ids, id, path) { + + var factories = {}; + var pending; + + var require = this.require = function (id, baseId) { + // defer to require set later from the sandbox module + require(id, baseId); + }; + + require.register = function (id, factory) { + factories[id] = factory; + if (!--pending) + main(); + }; + + var pending = ids.length; + var head = document.getElementsByTagName('head')[0]; + for (var i = 0; i < pending; i++) { + var script = document.createElement('script'); + script.src = path + ids[i] + '.js'; + head.appendChild(script); + }; + + function main() { + + var system = {}; + system.print = function () { + if (typeof console != "undefined") { + console.log(Array.prototype.join.call(arguments, ' ')); + } + }; + + var loader = {}; + loader.reload = function (topId) { + return factories[topId]; + }; + loader.load = function (topId) { + return loader.reload(topId); + }; + + var sandbox = {}; + loader.load('sandbox')( + null, + sandbox, + {}, + system, + system.print + ); + require = sandbox.Sandbox({loader: loader}); + loader.resolve = sandbox.resolve; + require(id); + + } + +}) diff --git a/utils/platforms/browser/lib/modules.js b/utils/platforms/browser/lib/modules.js new file mode 100755 index 0000000..db89b93 --- /dev/null +++ b/utils/platforms/browser/lib/modules.js @@ -0,0 +1,1449 @@ +/*preamble-kriskowal + Copyright (c) 2002-2009 Kris Kowal <http://cixar.com/~kris.kowal> + MIT License +*/ + +/* + isolate the module loader in an enclosure by creating an + annonymous function and then--at the end of this file-- + calling it. + + also, take the evalGlobal function as an argument so that it can be + declared in global scope. this prevents the eval function + from inheriting variables from the modulesjs enclosure scope. +*/ +(function (evalGlobal) { + + /* + kernel module factory functions. this module bootstrapper script + can also be used as a module, since it contains module + factory functions that can be used to bootstrap platform-specific + modules. to that end, we export the module factory functions if + there is an ambient "exports" object + */ + var factories = typeof exports == "undefined" ? {} : exports; + /* kernel module instances */ + var modules = {}; + + /* + a rudimentary require function to jumpstart + the module system + */ + var require = function (id) { + if (!Object.prototype.hasOwnProperty.call(modules, id)) { + var exports = {}; + modules[id] = exports; + factories[id](require, exports, system); + } + return modules[id]; + }; + + /* a permissive system for kernel modules */ + var system = { + window: window, + evalGlobal: evalGlobal + }; + + factories.main = function (require, exports, system) { + + var FILE = 'modules'; /* used to find the corresponding <script> */ + + var urls = require('urls'); + var browser = require('browser'); + var console = require('console'); + + var window = system.window; + var document = window.document; + system.print = console.print; + system.messages = console.messages; + + /* grab the URL of modules.js relative to the containing page, + and remove the <script> tag that invoked this module loader + from the DOM for maximum stealth. + */ + var PATH = urls.resolve(function () { /* enclosure */ + var scripts = document.getElementsByTagName("script"); + for (var i = 0; i < scripts.length; i++) { + var script = scripts[i]; + if (browser.hasAttr(script, "src")) { + var src = script.getAttribute("src"); + src = urls.parse(src); + if (src.file == FILE) { + script.parentNode.removeChild(script); + return urls.resolve(src, window.location.href); + } + } + } + throw new Error("could not find '" + FILE + "' <script>"); + }()); + + /* wait for the DOM to be fully loaded */ + browser.observeDomReady(function () { + + var sandbox = require('sandbox'); + sandbox.execUrl(PATH, PATH, system); + + /* note for CSS that JavaScript is enabled, and ready */ + document.body.className = document.body.className + ' javascript'; + + }); + + }; + + factories.sandbox = function (require, exports, system) { + + var http = require('http'); + var urls = require('urls'); + var evalGlobal = system.evalGlobal; + + exports.Loader = function (options) { + options = options || {}; + var factories = options.factories || {}; + var path = options.path; + var exportsLocal = options.exportsLocal; + var importsLocal = options.importsLocal; + + var loader = {}; + + loader.fetch = function (id) { + var url = urls.resolve(id, path) + '.js'; + return http.requestContent(url); + }; + + loader.evaluate = function (text, id) { + var iojs = /"use iojs";/.test(text); + /* optionally bring imports into scope with include */ + if (importsLocal && !iojs) + text = "with (imports||{}) {" + text + "}"; + /* optional bring exports into scope when assigned to exports */ + if (exportsLocal && !iojs) + text = "with (exports) {" + text + "}"; + /* safeguard "var" declarations from being + * applied to the "with" object in ES3-non-conformant browsers + * (really only Safari < 3) */ + if ((importsLocal || exportsLocal) && !iojs) + text = "(function () {" + text + "}).apply(this, arguments)"; + if (iojs) + text = "include = undefined; " + text; + text = ( + "(function (require, exports, module, system, print, include, imports) {" + + text + + "})" + ); + /* annotate with the module id */ + if (id) + text = '/* ' + id + ' */ ' + text; + return evalGlobal(text); + }; + + loader.resolve = function (id, baseId) { + if (typeof id != "string") + throw new Error("module id '" + id + "' is not a String"); + if (!baseId) { + baseId = path; + } + if (id.charAt(0) != ".") { + baseId = path; + } + return urls.resolve(id, baseId); + }; + + loader.load = function (id) { + if (!Object.prototype.hasOwnProperty.call(factories, id)) { + factories[id] = loader.evaluate(loader.fetch(id), id); + } + return factories[id]; + }; + + loader.getPath = function () { + return path; + }; + + return loader; + }; + + exports.Sandbox = function (options) { + options = options || {}; + var loader = options.loader || exports.Loader(options); + var sandboxSystem = options.system || system; + var modules = options.modules || {}; + var debug = options.debug === true; + var main; + + var debugDepth = 0; + + var sandbox = function (id, baseId) { + + id = loader.resolve(id, baseId); + + /* populate memo with module instance */ + if (!Object.prototype.hasOwnProperty.call(modules, id)) { + + + if (debug) { + debugDepth++; + var debugAcc = ""; + for (var i = 0; i < debugDepth; i++) debugAcc += "+"; + system.print(debugAcc + " " + id, 'module'); + } + + var exports = modules[id] = new Module(); + var factory = loader.load(id); + var require = Require(id); + var module = {id: id}; + var imports = {}; + var include = Include(require, imports); + try { + factory.call( + exports, + require, + exports, + module, + sandboxSystem, + sandboxSystem.print, + include, + imports + ); + } catch (exception) { + delete modules[id]; + throw exception; + } + + if (debug) { + var debugAcc = ""; + for (var i = 0; i < debugDepth; i++) debugAcc += "-"; + system.print(debugAcc + " " + id, 'module'); + debugDepth--; + } + + + } + + /* snapshot exports with requested bound methods */ + var exports = modules[id]; + var imports = new Module(); + var importsUsed = false; + for (var name in exports) { + if ( + exports[name] !== undefined && + exports[name] !== null && + exports[name].xChironCurryId + ) { + importsUsed = true; + imports[name] = (function (callback) { + var curried = function () { + return callback.apply( + this, + [baseId].concat(Array.prototype.slice.call(arguments, 0)) + ); + }; + curried.xChironCurryId = callback; + return curried; + })(exports[name].xChironCurryId); + } else { + imports[name] = exports[name]; + } + } + + if (!importsUsed) + imports = exports; + + return imports; + }; + + var Require = function (baseId) { + var require = function (id) { + try { + return sandbox(id, baseId); + } catch (exception) { + if (exception && !exception.message) + exception.message = 'Error'; + try { + try { + eval("throw new Error()"); + } catch (deliberate) { + if (deliberate.lineNumber !== undefined) + exception.message += ' at ' + (exception.lineNumber - deliberate.lineNumber + 1); + } + exception.message += ' in ' + baseId; + } catch (ignore) { + } + throw exception; + } + }; + + require.loader = loader; + + /* extensions */ + require.xChironModule = Module; + require.xChironId = baseId; + require.main = main; + require.xChironCurryId = function (callback) { + var curried = function () { + return callback.apply( + this, + [baseId].concat(Array.prototype.slice.call(arguments)) + ); + }; + curried.curryId = callback; + return curried; + }; + require.xChironIsLoaded = function (id) { + return Object.prototype.hasOwnProperty.call(modules, urls.resolve(id, baseId)); + }; + return require; + }; + + var Include = function (require, imports) { + return function (id) { + var exports = require(id); + for (var name in exports) { + imports[name] = exports[name]; + }; + return exports; + }; + }; + + sandbox.main = function (id, baseId) { + main = loader.resolve(id, baseId); + return sandbox(main); + }; + + /* just for use as a base prototype */ + var Module = function () {}; + + return sandbox; + }; + + /* execUrl is a utility method of this ipmlementation, not necessary + * for the interoperable modules specification. */ + exports.execUrl = function (url, PATH, sandboxSystem) { + + /* populate a list of initial ids from the query string of the PATH */ + var mainIds = []; + var url = urls.parse(url); + if (url.query != "") { + mainIds = url.query.split("&"); + if (/^path=(.*)/.test(mainIds[0])) { + PATH = urls.resolve(/^path=(.*)/.exec(mainIds[0])[1], system.window.location.href); + mainIds.shift(); + } + } + + /* load main modules */ + sandboxSystem.moduleFactories = system.moduleFactories || {}; + var sandbox = exports.Sandbox({ + path: PATH, + importsLocal: true, + exportsLocal: true, + system: sandboxSystem//, + //factories: sandboxSystem.moduleFactories + }); + for (var i = 0; i < mainIds.length; i++) { + try { + sandbox.main(mainIds[i], system.window.location.href); + } catch (exception) { + sandboxSystem.print('' + exception, 'error'); + throw exception; + } + } + + /* notify the user that all main modules have finished loading */ + sandboxSystem.print('ready', 'info'); + + }; + + }; + + factories.environment = function (require, exports, system) { + + if (system.window) { + var window = system.window; + var navigator = window.navigator; + + exports.isIE = navigator.appVersion.indexOf("MSIE") >= 0; + exports.isSafari = navigator.appVersion.indexOf("Safari") >= 0; + exports.isOpera = !!window.opera; + } + + }; + + factories.console = function (require, exports, system) { + + var window = system.window; + var console = system.console || window.console; + + /*** exports + */ + exports.messages = []; + + /*** print + + accepts: + - a ``message`` and + - an optional ``label``. + + The label, by convention, is one of `"log"``, ``"info"``, + ``"warn"``, or ``"error"``. Custom loggers treat labels like + ``"module"``, ``"pass"``, or ``"fail"``. Attempts to write + the message to `window.console`, progressively handling + `console` implementations that provide a function for the + given ``label``, or defaulting to `log` depending on + availability. + + Also adds a ``[message, label]`` array to the end + of `messages`. ``label`` is one of ``"log"``, + ``"warn"``, ``"info"``, or ``"error"`` by convention. + In Safari, `log` writes to the Javascript debug console, which + is only available if you set the preference:: + + defaults write com.apple.Safari IncludeDebugMenu 1 + + Or in Safari 3:: + + defaults write com.apple.Safari IncludeDevelopMenu 1 + + And in Safari 4, the preference has been exposed + in the Advanced tab; check "Show Develop Menu". + + In Firefox, you can get a debug console with Firebug, + http://getfirebug.com. + + You can override the behavior of `log` by assigning + a different function to ``require('environment').log`` + in any module. + + Chiron can create a debug console for the purpose of + unit testing or page debugging. To debug a web page, + use `modules.js` to include `debug.js` on a page. + To run a unit test, view `run.html`, `lite.html`, + or `edit.html` with the `moduleId` of the unit test + as a query string. + + */ + exports.print = function (message, label) { + + label = label || 'log'; + + /* + buffer messages so that console overrides + can retrieve and display them later. + */ + exports.messages.push([message, label]); + + /* + attempt to send the message to window.console if it + exists, progressively handling the availability + of a logging function crafted especially for the + requested label, or defaulting to 'log'. + */ + + if (console) { + if (console.print) { + console.print(message, label); + } else if (console[label]) { + console[label](message); + } else if (console.log) { + console.log(message); + } + } + + }; + + }; + + factories.browser = function (require, exports, system) { + + var environment = require('environment'); + var window = system.window; + var document = window.document; + var top = window.top; + + exports.hasAttr = function (element, key) { + if (element.hasAttribute) { + exports.hasAttr = function (element, key) { + return element.hasAttribute(key); + }; + return exports.hasAttr(element, key); + } else { + exports.hasAttr = function (element, key) { + var node = element.getAttributeNode(key); + return node && node.specified; + }; + return exports.hasAttr(element, key); + } + }; + + var isDomReady = false; + exports.observeDomReady = function (callback) { + + /* call immediately if we've already noted a DOM + * ready event */ + if (isDomReady) + return callback(); + + /* arrange to call back exactly once, even if multiple + * methods of detecting dom completion call "ready" */ + var hasCalledBack = false; + var ready = function () { + if (hasCalledBack) + return; + hasCalledBack = true; + isDomReady = true; + callback(); + }; + + /* + wait for the DOM and CSS to be ready, but don't wait + for images unless they're absolutely necessary. + + ported from jQuery's event.js, with previous implementations + taking from similar sources, including Dean Edwards + and PPK. + */ + + /* + Opera uses DOMContentLoaded but has special code for + pending style sheets. + */ + if (environment.isOpera) + document.addEventListener("DOMContentLoaded", function () { + if (isDomReady) return; + for (var i = 0; i < document.styleSheets.length; i++) + if (document.styleSheets[i].disabled) { + window.setTimeout(arguments.callee, 0); + return; + } + // and execute any waiting functions + ready(); + }, false); + + /* Mozilla and WebKit nightlies currently support this event */ + if (document.addEventListener) + /* Use the handy event callback */ + document.addEventListener("DOMContentLoaded", ready, false); + + /* + If IE is used and is not in a frame, + continually check to see whether the document is ready. + */ + if (environment.isIE && window == top) (function () { + if (isDomReady) return; + try { + /* + If IE is used, use the trick by Diego Perini + http://javascript.nwbox.com/IEContentLoaded/ + */ + document.documentElement.doScroll("left"); + } catch (error) { + /* + using setTimeout with a 0 milisecond dellay + is effectively the equivalent of a "yield" + in a cooperative multi-task language. + This permits the browser to breathe before + we check whether we're ready again. + */ + window.setTimeout(arguments.callee, 0); + return; + } + ready(); + })(); + + if (environment.isSafari) { + (function () { + if (isDomReady) return; + if ( + document.readyState != "loaded" && + document.readyState != "complete" + ) { + window.setTimeout(arguments.callee, 0); + return; + } + var numStyles = document.getElementsByTagName('style').length; + var links = document.getElementsByTagName('link'); + for (var i = 0; i < links.length; i++) { + var link = links[i]; + numStyles += ( + link.hasAttribute('rel') && + link.getAttribute('rel').toLowerCase() == + 'stylesheet' + ); + } + if (document.styleSheets.length != numStyles) { + window.setTimeout(arguments.callee, 0); + return; + } + ready(); + })(); + } + + /* + for other browsers, give up on the time saving + techniques and wait for all the images to load. + also, do this in other browsers just in case they missed + the boat. + */ + if (window.onload) { + /* if there's already an onload listener, call ready after it, + preserving first-come-first-serve event observation */ + window.onload = (function (onload) { + return function () { + onload.call(this); + ready(); + }; + })(window.onload); + } else { + window.onload = ready; + } + + }; + + }; + + factories.urls = function (require, exports, system) { + + /**** keys + members of a parsed URI object. + */ + exports.keys = [ + "url", + "protocol", + "authorityRoot", + "authority", + "userInfo", + "user", + "password", + "domain", + "domains", + "port", + "path", + "root", + "directory", + "directories", + "file", + "query", + "anchor" + ]; + + /**** expressionKeys + members of a parsed URI object that you get + from evaluting the strict regular expression. + */ + exports.expressionKeys = [ + "url", + "protocol", + "authorityRoot", + "authority", + "userInfo", + "user", + "password", + "domain", + "port", + "path", + "root", + "directory", + "file", + "query", + "anchor" + ]; + + /**** strictExpression + */ + exports.strictExpression = new RegExp( /* url */ + "^" + + "(?:" + + "([^:/?#]+):" + /* protocol */ + ")?" + + "(?:" + + "(//)" + /* authorityRoot */ + "(" + /* authority */ + "(?:" + + "(" + /* userInfo */ + "([^:@]*)" + /* user */ + ":?" + + "([^:@]*)" + /* password */ + ")?" + + "@" + + ")?" + + "([^:/?#]*)" + /* domain */ + "(?::(\\d*))?" + /* port */ + ")" + + ")?" + + "(" + /* path */ + "(/?)" + /* root */ + "((?:[^?#/]*/)*)" + + "([^?#]*)" + /* file */ + ")" + + "(?:\\?([^#]*))?" + /* query */ + "(?:#(.*))?" /*anchor */ + ); + + /**** Parser + returns a URI parser function given + a regular expression that renders + `expressionKeys` and returns an `Object` + mapping all `keys` to values. + */ + exports.Parser = function (expression) { + return function (url) { + if (typeof url == "undefined") + throw new Error("HttpError: URL is undefined"); + if (typeof url != "string") return new Object(url); + + var items = {}; + var parts = expression.exec(url); + + for (var i = 0; i < parts.length; i++) { + items[exports.expressionKeys[i]] = parts[i] ? parts[i] : ""; + } + + items.root = (items.root || items.authorityRoot) ? '/' : ''; + + items.directories = items.directory.split("/"); + if (items.directories[items.directories.length - 1] == "") { + items.directories.pop(); + } + + /* normalize */ + var directories = []; + for (var i = 0; i < items.directories.length; i++) { + var directory = items.directories[i]; + if (directory == '.') { + } else if (directory == '..') { + if (directories.length && directories[directories.length - 1] != '..') + directories.pop(); + else + directories.push('..'); + } else { + directories.push(directory); + } + } + items.directories = directories; + + items.domains = items.domain.split("."); + + return items; + }; + }; + + /**** parse + a strict URI parser. + */ + exports.parse = exports.Parser(exports.strictExpression); + + /**** format + accepts a parsed URI object and returns + the corresponding string. + */ + exports.format = function (object) { + if (typeof(object) == 'undefined') + throw new Error("UrlError: URL undefined for urls#format"); + if (object instanceof String || typeof(object) == 'string') + return object; + var domain = + object.domains ? + object.domains.join(".") : + object.domain; + var userInfo = ( + object.user || + object.password + ) ? + ( + (object.user || "") + + (object.password ? ":" + object.password : "") + ) : + object.userInfo; + var authority = ( + userInfo || + domain || + object.port + ) ? ( + (userInfo ? userInfo + "@" : "") + + (domain || "") + + (object.port ? ":" + object.port : "") + ) : + object.authority; + var directory = + object.directories ? + object.directories.join("/") : + object.directory; + var path = + directory || object.file ? + ( + (directory ? directory + "/" : "") + + (object.file || "") + ) : + object.path; + return ( + (object.protocol ? object.protocol + ":" : "") + + (authority ? "//" + authority : "") + + (object.root || (authority && path) ? "/" : "") + + (path ? path : "") + + (object.query ? "?" + object.query : "") + + (object.anchor ? "#" + object.anchor : "") + ) || object.url || ""; + }; + + /**** resolveObject + returns an object representing a URL resolved from + a relative location and a base location. + */ + exports.resolveObject = function (relative, base) { + if (!base) + return relative; + + base = exports.parse(base); + relative = exports.parse(relative); + + if (relative.url == "") + return base; + + delete base.url; + delete base.authority; + delete base.domain; + delete base.userInfo; + delete base.path; + delete base.directory; + + if ( + relative.protocol && relative.protocol != base.protocol || + relative.authority && relative.authority != base.authority + ) { + base = relative; + } else { + if (relative.root) { + base.directories = relative.directories; + } else { + + var directories = relative.directories; + for (var i = 0; i < directories.length; i++) { + var directory = directories[i]; + if (directory == ".") { + } else if (directory == "..") { + if (base.directories.length) { + base.directories.pop(); + } else { + base.directories.push('..'); + } + } else { + base.directories.push(directory); + } + } + + if (relative.file == ".") { + relative.file = ""; + } else if (relative.file == "..") { + base.directories.pop(); + relative.file = ""; + } + } + } + + if (relative.root) + base.root = relative.root; + if (relative.protcol) + base.protocol = relative.protocol; + if (!(!relative.path && relative.anchor)) + base.file = relative.file; + base.query = relative.query; + base.anchor = relative.anchor; + + return base; + }; + + /**** relativeObject + returns an object representing a relative URL to + a given target URL from a source URL. + */ + exports.relativeObject = function (target, base) { + target = exports.parse(target); + base = exports.parse(base); + + delete target.url; + + if ( + target.protocol == base.protocol && + target.authority == base.authority + ) { + delete target.protocol; + delete target.authority; + delete target.userInfo; + delete target.user; + delete target.password; + delete target.domain; + delete target.domains; + delete target.port; + if ( + !!target.root == !!base.root && !( + target.root && + target.directories[0] != base.directories[0] + ) + ) { + delete target.path; + delete target.root; + delete target.directory; + while ( + base.directories.length && + target.directories.length && + target.directories[0] == base.directories[0] + ) { + target.directories.shift(); + base.directories.shift(); + } + while (base.directories.length) { + base.directories.shift(); + target.directories.unshift('..'); + } + + if (!target.root && !target.directories.length && !target.file && base.file) + target.directories.push('.'); + + if (base.file == target.file) + delete target.file; + if (base.query == target.query) + delete target.query; + if (base.anchor == target.anchor) + delete target.anchor; + } + } + + return target; + }; + + /**** resolve + returns a URL resovled to a relative URL from a base URL. + */ + exports.resolve = function (relative, base) { + return exports.format(exports.resolveObject(relative, base)); + }; + + /**** relative + returns a relative URL to a target from a source. + */ + exports.relative = function (target, base) { + return exports.format(exports.relativeObject(target, base)); + }; + + }; + + factories.http = function (require, exports, system) { + + var urls = require('urls'); + var environment = require('environment'); + var window = system.window; + + /**** requestContent + returns the text at a given URL using an HTTP + request. + supports continuation passing form for asynchronous + requests. + */ + exports.requestContent = function (url, observer) { + if (observer !== undefined) { + return exports.request(url, function (response) { + if (response.isOk()) + observer(response.getContent()); + }); + } else { + var response = exports.request(url); + if (response.isError()) + throw new Error("HttpError: " + url + " status " + response.getStatus()); + return response.getContent(); + } + }; + + /**** request + sends an HTTP request to a given URL and returns + the response. + supports continuation passing form for asynchronous + requests. + */ + exports.request = function (url, observer) { + var request = exports.Request(); + var response = request.getResponse(); + + url = urls.resolve(url, system.window.location.href); + + if (observer) + request.observe("ok", observer); + + request.open("GET", url, !!observer); + + try { + request.send(); + } catch (exception) { + request.abort(); + throw new Error('HttpError: "' + url + '": ' + exception); + } + + if (observer !== undefined) { + return request; + } else { + return response; + } + + }; + + /*todo + Look deeper into dojo/src/hostenv_browser.js for + _blockAsync lock to prevent eternal hanging in KHTML + */ + + /**** Request + returns a wrapped HTTP Request object. + */ + exports.Request = function () { + /* this line permits the user to create a request with + * either new Request() or Request(). internally, + * we just use the Request() so that Request can be + * overloaded later in HTTP to be a type constructor + * function instead of a prototype constructor */ + if (this == exports) return new exports.Request(); + + var self = this; + var method, url, asynchronous, user, password; + var realRequest = exports.NativeRequest(); + var response = exports.Response(realRequest); + var isOpen; + var readyStateChanged; + var timeout; + var timeoutHandle; + var aborted; + + var readyObservers = []; + var okObservers = []; + var errorObservers = []; + var warnObservers = []; + var timeoutObservers = []; + + /***** toString + */ + self.toString = function () {return "[object HttpRequest]"}; + + /***** getResponse + */ + self.getResponse = function () { + return response; + }; + + var signal = function (response, observers) { + while (observers.length) { + var observer = observers.shift(); + observer(response); + } + }; + + /***** pogress + an event function that the Request calls when it + receives a chunk of content. + */ + self.progress = function () { + /* necessary: this function becomes an observable signal */ + }; + + /***** ready + an event function that the Request calls when + the Reponse is ready. + */ + self.ready = function () { + signal(response, readyObservers); + }; + + /***** ok + an event function that the Request calls when a Response + is ready and all went well. Note that Safari and FireFox, at least, + will fire this event even when the connection is abruptly + terminated by the server, reporting a 200 status and + an empty response content. + */ + self.ok = function () { + signal(response, okObservers); + }; + + /***** error + an event function that the Request calls when a Reponse + is completed but failed to retrieve the requested content. + */ + self.error = function () { + signal(response, errorObservers); + }; + + /***** warn + an event function that the Request calls when + something is amiss with message. + */ + self.warn = function (message) { + warn(message); + signal(response, warnObservers); + }; + + /***** timeout + an event function that Request calls when a request + times out. The default behavior is to invoke an error. + */ + self.timeout = function () { + signal(response, timeoutObservers); + }; + + /***** observe + permits a user to observe `ready`, `ok`, + `error`, and `warn` events with a handler + function. Observing any event on a `Request` + causes the `open` and `send` to implicitly become + asynchronous. + */ + self.observe = function (eventName, observer) { + asynchronous = true; + if (eventName == "ready") readyObservers.push(observer); + else if (eventName == "ok") okObservers.push(observer); + else if (eventName == "error") errorObservers.push(observer); + else if (eventName == "warn") warnObservers.push(observer); + else if (eventName == "timeout") timeoutObservers.push(observer); + else throw new Error( + "HttpError: event name '" + eventName + "' " + + "is not recognized" + ); + }; + + /***** setHeader + */ + self.setHeader = function (key, value) { + realRequest.setRequestHeader(key, value); + }; + + /***** isOpen + */ + self.isOpen = function () { + return isOpen; + }; + + /***** isSent + */ + self.isSent = function () { + return realRequest.readyState > 0; + }; + + /***** getTimeout + */ + self.getTimeout = function () { + return timeout; + }; + + /***** setTimeout + */ + self.setTimeout = function (value) { + timeout = value; + }; + + /***** open + + Accepts + + - ``method``, an HTTP request method, for example, + ``GET``, ``POST``, ``PROPFIND`` and others. + - ``url``, a web location string + - ``synchronous``, whether ``send`` will block until completed, + for example, ``synchronous``, ``asynchronous``. + - ``user``, an optional HTTP user name. + - ``password``, an optional HTTP password. + + */ + self.open = function (_method, _url, _asynchronous, _user, _password) { + try { + return realRequest.open( + method = _method, + url = _url, + asynchronous = _asynchronous, + user = _user, + password = _password + ); + } finally { + isOpen = true; + } + }; + + /***** send + Accepts an optional ``content`` argument for requests like ``POST`` method. + */ + self.send = function (content) { + + realRequest.setRequestHeader("X-Requested-With", "XMLHttpRequest"); + + if (!content) { + content = ""; + } + + if (timeout !== undefined) { + timeoutHandle = window.setTimeout(function () { + timeoutHandle = undefined; + var status = response.getStatus(); + if (status != 200 || status === undefined) { + self.timeout(); + self.abort(); + } + }, timeout); + } + + return realRequest.send(content); + }; + + /***** abort + */ + self.abort = function () { + if (timeoutHandle !== undefined) + window.clearTimeout(timeoutHandle); + aborted = true; + return realRequest.abort(); + }; + + realRequest.onreadystatechange = function () { + readyStateChanged = true; + + self.progress(); + + if (aborted) { + free(); + } else if (realRequest.readyState == 4) { + try { + + self.ready(response); + + if (response.isOk()) { + self.ok(response); + } else { + self.error(response); + } + + } catch (exception) { + system.print(exception.message || exception, 'error'); + } + free(); + } + }; + + var free = function () { + delete realRequest['onreadystatechange']; + realRequest.onreadystatechange = undefined; + }; + + return self; + }; + + /**** Response + returns a wrapped HTTP Response object. + */ + exports.Response = function (realRequest) { + /* this line permits the user to create a request with + * either new Respones() or Response(). internally, + * we just use the Response() so that Response can be + * overloaded later in HTTP to be a type constructor + * function instead of a prototype constructor */ + if (this == exports) return new exports.Response(realRequest); + + var self = this; + + /* this init function doesn't get invoked until Response becomes + * a type in HTTP. so, this method is merely for the future. */ + self.init = function (realRequestValue) { + realRequest = realRequestValue; + }; + + /***** isReady + whether the request is finished. This indicates + whether you can call `getStatus` + */ + self.isReady = function () { + return realRequest.readyState == 4; + }; + + /***** getStatus + returns the HTTP response code. Local files + return 0. Returns ``undefined`` if the + underlying XML HTTP request throws an exception, + `getStatus` returns ``undefined``. + */ + self.getStatus = function () { + /* one wouldn't think this were necessary. + * one would be wrong. */ + try { + return realRequest.status; + } catch (exception) { + return undefined; + } + }; + + /***** isOk + returns whether a request had a valid response. + This usually is indicative of a 200 HTTP response + code, but there are variations among browsers. + + HTTP Status codes in the interval [200, 300] are all legal + HTTP Ok responses. + + In Firefox and Safari 3, local files acquired with an HTTP request + have a status code of 0. + + In Safari 2, local files acquired with an asynchronous HTTP + request have a status of undefined. + + In Safari, a response with no content causes a status + of `undefined`. + + Konqueror requires acceptance of 304, "using cache", + according to dojo/src/hostenv_browser.js + + According to jQuery issue #1450, IE sometimes 1223 + instead of 204. + */ + self.isOk = function () { + var status = self.getStatus(); + return ( + /* usually */ + status >= 200 && status < 300 || + /* Firefox and Safari 3 file:// */ + status == 0 || + /* Konqueror using cache */ + status == 304 || + /* IE bug 1223 */ + status == 1223 || + /* Safari 2 asynchronous file:// and + all Safari for no file content */ + (environment.isSafari && status == undefined && ( + /^file:\/\//.test(url) || + realRequest.responseText == "" + )) + ); + }; + + /***** isError + */ + self.isError = function () { + return !self.isOk(); + }; + + /***** getContent + */ + self.getContent = function () { + return realRequest.responseText; + }; + + /***** getDocument + */ + self.getDocument = function () { + return self.getXml().documentElement; + }; + + /***** getHeader + */ + self.getHeader = function (key) { + return realRequest.getResponseHeader(key); + }; + + /***** hasHeader + */ + self.hasHeader = function (key) { + return realRequest.getResponseHeader(key) != undefined; + }; + + /***** getHeaders + */ + self.getHeaders = function () { + var headers = realRequest.getAllResponseHeaders(); + if (!headers) return {}; + return headers; + }; + + /***** len + */ + self.len = function () { + return realRequest.responseText.length; + }; + + }; + + /*** NativeRequest + returns an XMLHttpRequest in most browsers. + */ + /* Based on dojo/src/hostenv_browser.js */ + + exports.NativeRequest = function () { + /* + + subscribes to the lazy function definition pattern, since it + redefines itself as the first method that works on the first + call. + + Some other AJAX implementations check + - Msxml2.XMLHTTP.6.0 + - Msxml2.XMLHTTP.5.0 + - Msxml2.XMLHTTP.4.0 + - Msxml2.XMLHTTP.3.0 + - Microsoft.XMLHTTP + + Microsoft.XMLHTTP is an older name-space, but is equivalent to + the more lucid Msxml2.XMLHTTP.3.0 and only available when the + latter is available too. + + Msxml2.XMLHTTP.4.0 has been superseded and is currently only + intended to support legacy applications. + + Msxml2.XMLHTTP.5.0 was shipped with MS Office 2003 and was + intended for Office applications. IE7 has this component off + by default in the Internet zone, leading to canary-yellow + verification dialogs. + + Msxml2.XMLHTTP.6.0 is currently the standard MS is pushing. + I originally left out 6.0 since it would increase the burden + of testing for functionality that cannot be trusted to work + in all browsers. + However, I've taken Jonathan Snook's advice to check for + Microsoft's latest and greatest. + + see: http://snook.ca/archives/javascript/xmlhttprequest_activex_ie/ + + Msxml2.XMLHTTP.3.0 is the most widely deployed version and is + serviced regularly with the OS for security and other reasons. + It is MS's preferred alternative to MSXML6. + + see: http://blogs.msdn.com/xmlteam/archive/2006/10/23/using-the-right-version-of-msxml-in-internet-explorer.aspx + + see: http://www.telerik.com/documents/AJAX%20Page/Ajax-Part1.pdf page 3 + + */ + + var trials = [ + function () {return new window.XMLHttpRequest()}, + function () {return new window.ActiveXObject("Msxml2.XMLHTTP.6.0")}, + function () {return new window.ActiveXObject("Msxml2.XMLHTTP.3.0")}, + function () {throw new Error("No HTTP Request object available for your system.")} + ]; + + var trial, result, exception; + for (var i = 0; i < trials.length; i++) { + exception = undefined; + /* redeclare for posterity */ + exports.NativeRequest = trial = trials[i]; + try { + result = trial(); + } catch (trialException) { + exception = trialException; + continue; + } + break; + } + + if (exception) throw exception; + else return result; + }; + + }; + + if (typeof exports == "undefined") { + require('main'); + } + +/* end of module enclosure */ +})(function () { + return eval(arguments[0]); +}); + diff --git a/utils/platforms/browser/lib/system.js b/utils/platforms/browser/lib/system.js new file mode 100755 index 0000000..d50a5cf --- /dev/null +++ b/utils/platforms/browser/lib/system.js @@ -0,0 +1,3 @@ +exports.print = function () { + system.print.apply(system, arguments); +}; diff --git a/utils/platforms/default/lib/binary-platform.js b/utils/platforms/default/lib/binary-platform.js new file mode 100755 index 0000000..3bc2425 --- /dev/null +++ b/utils/platforms/default/lib/binary-platform.js @@ -0,0 +1,53 @@ +exports.B_LENGTH = function(bytes) { + return bytes.length; +} + +exports.B_ALLOC = function(length) { + var bytes = new Array(length); + for (var i = 0; i < length; i++) + bytes[i] = 0; + return bytes; +} + +exports.B_FILL = function(bytes, from, to, value) { + for (var i = from; i < to; i++) + bytes[i] = value; +} + +exports.B_COPY = function(src, srcOffset, dst, dstOffset, length) { + for (var i = 0; i < length; i++) + dst[dstOffset+i] = src[srcOffset+i]; +} + +exports.B_GET = function(bytes, index) { + return bytes[index]; +} + +exports.B_SET = function(bytes, index, value) { + return bytes[index] = value; +} + +var DEFAULT_ENCODING = "UTF-8"; + +exports.B_DECODE = function(bytes, offset, length, codec) { + var newBytes = exports.B_TRANSCODE(bytes, offset, length, codec, DEFAULT_ENCODING); + return exports.B_DECODE_DEFAULT(newBytes, 0, exports.B_LENGTH(newBytes)); +} + +exports.B_DECODE_DEFAULT = function(bytes, offset, length) { + throw "NYI"; +} + +exports.B_ENCODE = function(string, codec) { + var bytes = exports.B_ENCODE_DEFAULT(string); + return exports.B_TRANSCODE(bytes, 0, exports.B_LENGTH(bytes), DEFAULT_ENCODING, codec); +} + +exports.B_ENCODE_DEFAULT = function(string) { + throw "NYI"; +} + +exports.B_TRANSCODE = function(bytes, offset, length, sourceCodec, targetCodec) { + throw "NYI"; +} + diff --git a/utils/platforms/default/lib/binary.js b/utils/platforms/default/lib/binary.js new file mode 100755 index 0000000..7c19b80 --- /dev/null +++ b/utils/platforms/default/lib/binary.js @@ -0,0 +1,719 @@ +/* Binary */ + +var B_ALLOC = require("binary-platform").B_ALLOC, + B_LENGTH = require("binary-platform").B_LENGTH, + B_GET = require("binary-platform").B_GET, + B_SET = require("binary-platform").B_SET, + B_FILL = require("binary-platform").B_FILL, + B_COPY = require("binary-platform").B_COPY, + B_DECODE = require("binary-platform").B_DECODE, + B_ENCODE = require("binary-platform").B_ENCODE, + B_DECODE_DEFAULT = require("binary-platform").B_DECODE_DEFAULT, + B_ENCODE_DEFAULT = require("binary-platform").B_ENCODE_DEFAULT, + B_TRANSCODE = require("binary-platform").B_TRANSCODE; + +var Binary = exports.Binary = function() { + // this._bytes + // this._offset + // this._length +}; + +Binary.prototype.__defineGetter__("length", function() { return this._length; }); +Binary.prototype.__defineSetter__("length", function(length) { print("x trying to set length: " + length); }); + +// toArray() - n array of the byte values +// toArray(charset) - an array of the code points, decoded +Binary.prototype.toArray = function(codec) { + if (arguments.length === 0) { + var array = new Array(this._length); + + for (var i = 0; i < this.length; i++) + array[i] = this.get(i); + + return array; + } + else if (arguments.length === 1) { + var string = new java.lang.String(this._bytes, this._offset, this._length, codec), + length = string.length(), + array = new Array(length); + + for (var i = 0; i < length; i++) + array[i] = string.codePointAt(i); + + return array; + } + else + throw new Error("Illegal arguments to toArray()"); +}; + +// toByteArray() - just a copy +// toByteArray(sourceCharset, targetCharset) - transcoded +Binary.prototype.toByteArray = function(sourceCodec, targetCodec) { + if (arguments.length < 2) + return new ByteArray(this); + else if (arguments.length === 2 && typeof sourceCodec === "string" && typeof targetCodec === "string") { + var bytes = B_TRANSCODE(this._bytes, this._offset, this._length, sourceCodec, targetCodec); + return new ByteArray(bytes, 0, B_LENGTH(bytes)); + } + + throw new Error("Illegal arguments to ByteArray toByteArray"); +}; + +// toByteString() - byte for byte copy +// toByteString(sourceCharset, targetCharset) - transcoded +Binary.prototype.toByteString = function(sourceCodec, targetCodec) { + if (arguments.length < 2) + return new ByteString(this); + else if (arguments.length === 2 && typeof sourceCodec === "string" && typeof targetCodec === "string") { + var bytes = B_TRANSCODE(this._bytes, this._offset, this._length, sourceCodec, targetCodec); + return new ByteString(bytes, 0, B_LENGTH(bytes)); + } + + throw new Error("Illegal arguments to ByteArray toByteString"); +}; + +// decodeToString() +// decodeToString(charset) - returns a String from its decoded bytes in a given charset. If no charset is provided, or if the charset is "undefined", assumes the default system encoding. +// decodeToString(number) - returns a String from its decoded bytes in a given base, like 64, 32, 16, 8, 2 +Binary.prototype.decodeToString = function(charset) { + if (charset) { + if (typeof charset == "number") + return require("base" + charset).encode(this); + else if (charset.begins("base")) + return require(charset).encode(this); + else + return B_DECODE(this._bytes, this._offset, this._length, charset); + } + return B_DECODE_DEFAULT(this._bytes, this._offset, this._length); +}; + +// get(offset) - Return the byte at offset as a Number. +Binary.prototype.get = function(offset) { + if (offset < 0 || offset >= this._length) + return NaN; + + //var b = this._bytes[this._offset + offset]; + //return (b >= 0) ? b : -1 * ((b ^ 0xFF) + 1); + return B_GET(this._bytes, this._offset + offset) +}; + +Binary.prototype.indexOf = function(byteValue, start, stop) { + // HACK: use ByteString's slice since we know we won't be modifying result + var array = ByteString.prototype.slice.apply(this, [start, stop]).toArray(), + result = array.indexOf(byteValue); + return (result < 0) ? -1 : result + (start || 0); +}; + +Binary.prototype.lastIndexOf = function(byteValue, start, stop) { + // HACK: use ByteString's slice since we know we won't be modifying result + var array = ByteString.prototype.slice.apply(this, [start, stop]).toArray(), + result = array.lastIndexOf(byteValue); + return (result < 0) ? -1 : result + (start || 0); +}; + +// valueOf() +Binary.prototype.valueOf = function() { + return this; +}; + +/* ByteString */ + +var ByteString = exports.ByteString = function() { + if (!(this instanceof ByteString)) { + if (arguments.length == 0) + return new ByteString(); + if (arguments.length == 1) + return new ByteString(arguments[0]); + if (arguments.length == 2) + return new ByteString(arguments[0], arguments[1]); + if (arguments.length == 3) + return new ByteString(arguments[0], arguments[1], arguments[2]); + } + + // ByteString() - Construct an empty byte string. + if (arguments.length === 0) { + this._bytes = B_ALLOC(0); // null; + this._offset = 0; + this._length = 0; + } + // ByteString(byteString) - Copies byteString. + else if (arguments.length === 1 && arguments[0] instanceof ByteString) { + return arguments[0]; + } + // ByteString(byteArray) - Use the contents of byteArray. + else if (arguments.length === 1 && arguments[0] instanceof ByteArray) { + var copy = arguments[0].toByteArray(); + this._bytes = copy._bytes; + this._offset = copy._offset; + this._length = copy._length; + } + // ByteString(arrayOfNumbers) - Use the numbers in arrayOfNumbers as the bytes. + else if (arguments.length === 1 && Array.isArray(arguments[0])) { + var array = arguments[0]; + this._bytes = B_ALLOC(array.length); + for (var i = 0; i < array.length; i++) { + var b = array[i]; + // If any element is outside the range 0...255, an exception (TODO) is thrown. + if (b < -0x80 || b > 0xFF) + throw new Error("ByteString constructor argument Array of integers must be -128 - 255 ("+b+")"); + // Java "bytes" are interpreted as 2's complement + //this._bytes[i] = (b < 128) ? b : -1 * ((b ^ 0xFF) + 1); + B_SET(this._bytes, i, b); + } + this._offset = 0; + this._length = B_LENGTH(this._bytes); + } + // ByteString(string, charset) - Convert a string. The ByteString will contain string encoded with charset. + else if ((arguments.length === 1 || (arguments.length === 2 && arguments[1] === undefined)) && typeof arguments[0] === "string") { + this._bytes = B_ENCODE_DEFAULT(arguments[0]); + this._offset = 0; + this._length = B_LENGTH(this._bytes); + } + else if (arguments.length === 2 && typeof arguments[0] === "string" && typeof arguments[1] === "string") { + this._bytes = B_ENCODE(arguments[0], arguments[1]); + this._offset = 0; + this._length = B_LENGTH(this._bytes); + } + // private: ByteString(bytes, offset, length) + else if (arguments.length === 3 && typeof arguments[1] === "number" && typeof arguments[2] === "number") { + this._bytes = arguments[0]; + this._offset = arguments[1]; + this._length = arguments[2]; + } + else + throw new Error("Illegal arguments to ByteString constructor: [" + + Array.prototype.join.apply(arguments, [","]) + "] ("+arguments.length+")"); + + //seal(this); +}; + +ByteString.prototype = new Binary(); + +ByteString.prototype.__defineGetter__("length", function() { return this._length; }); +ByteString.prototype.__defineSetter__("length", function(length) {}); + +// toByteArray() - Returns a byte for byte copy in a ByteArray. +// toByteArray(sourceCharset, targetCharset) - Returns a transcoded copy in a ByteArray. +// - implemented on Binary + +// toByteString() - Returns itself, since there's no need to copy an immutable ByteString. +// toByteString(sourceCharset, targetCharset) - Returns a transcoded copy. +// - implemented on Binary + +// toArray() - Returns an array containing the bytes as numbers. +// toArray(charset) - Returns an array containing the decoded Unicode code points. +// - implemented on Binary + +// toString() +ByteString.prototype.toString = function(charset) { + if (charset) + return this.decodeToString(charset); + + return "[ByteString "+this.length+"]"; +}; + +// decodeToString(charset) - Returns the decoded ByteArray as a string. +// - implemented on Binary + +ByteString.prototype.byteAt = +ByteString.prototype.charAt = function(offset) { + var byteValue = this.get(offset); + + if (isNaN(byteValue)) + return new ByteString(); + + return new ByteString([byteValue]); +}; + +// indexOf() - implemented on Binary +// lastIndexOf() - implemented on Binary + +// charCodeAt(offset) +ByteString.prototype.charCodeAt = Binary.prototype.get; + +// get(offset) - implemented on Binary + +// byteAt(offset) ByteString - implemented on Binary +// charAt(offset) ByteString - implemented on Binary + +// split(delimiter, [options]) +ByteString.prototype.split = function(delimiters, options) { + var options = options || {}, + count = options.count === undefined ? -1 : options.count, + includeDelimiter = options.includeDelimiter || false; + + // standardize delimiters into an array of ByteStrings: + if (!Array.isArray(delimiters)) + delimiters = [delimiters]; + + delimiters = delimiters.map(function(delimiter) { + if (typeof delimiter === "number") + delimiter = [delimiter]; + return new ByteString(delimiter); + }); + + var components = [], + startOffset = this._offset, + currentOffset = this._offset; + + // loop until there's no more bytes to consume + bytes_loop : + while (currentOffset < this._offset + this._length) { + + // try each delimiter until we find a match + delimiters_loop : + for (var i = 0; i < delimiters.length; i++) { + var d = delimiters[i]; + + for (var j = 0; j < d._length; j++) { + // reached the end of the bytes, OR bytes not equal + if (currentOffset + j > this._offset + this._length || + B_GET(this._bytes, currentOffset + j) !== B_GET(d._bytes, d._offset + j)) { + continue delimiters_loop; + } + } + + // push the part before the delimiter + components.push(new ByteString(this._bytes, startOffset, currentOffset - startOffset)); + + // optionally push the delimiter + if (includeDelimiter) + components.push(new ByteString(this._bytes, currentOffset, d._length)) + + // reset the offsets + startOffset = currentOffset = currentOffset + d._length; + + continue bytes_loop; + } + + // if there was no match, increment currentOffset to try the next one + currentOffset++; + } + + // push the remaining part, if any + if (currentOffset > startOffset) + components.push(new ByteString(this._bytes, startOffset, currentOffset - startOffset)); + + return components; +}; + +// slice() +// slice(begin) +// slice(begin, end) +ByteString.prototype.slice = function(begin, end) { + if (begin === undefined) + begin = 0; + else if (begin < 0) + begin = this._length + begin; + + if (end === undefined) + end = this._length; + else if (end < 0) + end = this._length + end; + + begin = Math.min(this._length, Math.max(0, begin)); + end = Math.min(this._length, Math.max(0, end)); + + return new ByteString(this._bytes, this._offset + begin, end - begin); +}; + +// substr(start) +// substr(start, length) +ByteString.prototype.substr = function(start, length) { + if (start !== undefined) { + if (length !== undefined) + return this.slice(start); + else + return this.slice(start, start + length); + } + return this.slice(); +}; + +// substring(first) +// substring(first, last) +ByteString.prototype.substring = function(from, to) { + if (from !== undefined) { + if (to !== undefined) + return this.slice(Math.max(Math.min(begin, this._length), 0)); + else + return this.slice(Math.max(Math.min(begin, this._length), 0), + Math.max(Math.min(end, this._length), 0)); + } + return this.slice(); +}; + +// [] ByteString - TODO + +// toSource() +ByteString.prototype.toSource = function() { + return "ByteString(["+this.toArray().join(",")+"])"; +}; + +/* ByteArray */ + +// ByteArray() - New, empty ByteArray. +// ByteArray(length) - New ByteArray filled with length zero bytes. +// ByteArray(byteArray) - Copy byteArray. +// ByteArray(byteString) - Copy contents of byteString. +// ByteArray(arrayOfBytes) - Use numbers in arrayOfBytes as contents. +// Throws an exception if any element is outside the range 0...255 (TODO). +// ByteArray(string, charset) - Create a ByteArray from a Javascript string, the result being encoded with charset. +var ByteArray = exports.ByteArray = function() { + if (!this instanceof ByteArray) { + if (arguments.length == 0) + return new ByteArray(); + if (arguments.length == 1) + return new ByteArray(arguments[0]); + if (arguments.length == 2) + return new ByteArray(arguments[0], arguments[1]); + if (arguments.length == 3) + return new ByteArray(arguments[0], arguments[1], arguments[2]); + } + + // ByteArray() - New, empty ByteArray. + if (arguments.length === 0) { + this._bytes = B_ALLOC(0); // null; + this._offset = 0; + this._length = 0; + } + // ByteArray(length) - New ByteArray filled with length zero bytes. + else if (arguments.length === 1 && typeof arguments[0] === "number") { + this._bytes = B_ALLOC(arguments[0]); // null; + this._offset = 0; + this._length = B_LENGTH(this._bytes); + } + // ByteArray(byteArray) - Copy byteArray. + // ByteArray(byteString) - Copy contents of byteString. + else if (arguments.length === 1 && (arguments[0] instanceof ByteArray || arguments[0] instanceof ByteString)) { + var byteArray = new ByteArray(arguments[0]._length); + B_COPY(arguments[0]._bytes, arguments[0]._offset, byteArray._bytes, byteArray._offset, byteArray._length); + return byteArray; + } + // ByteArray(arrayOfBytes) - Use numbers in arrayOfBytes as contents. + // Throws an exception if any element is outside the range 0...255 (TODO). + else if (arguments.length === 1 && Array.isArray(arguments[0])) { + var array = arguments[0]; + this._bytes = B_ALLOC(array.length); + for (var i = 0; i < array.length; i++) { + var b = array[i]; + // If any element is outside the range 0...255, an exception (TODO) is thrown. + if (b < 0 || b > 0xFF) + throw new Error("ByteString constructor argument Array of integers must be 0 - 255 ("+b+")"); + // Java "bytes" are interpreted as 2's complement + //this._bytes[i] = (b < 128) ? b : -1 * ((b ^ 0xFF) + 1); + B_SET(this._bytes, i, b); + } + this._offset = 0; + this._length = B_LENGTH(this._bytes); + } + // ByteArray(string, charset) - Create a ByteArray from a Javascript string, the result being encoded with charset. + else if ((arguments.length === 1 || (arguments.length === 2 && arguments[1] === undefined)) && typeof arguments[0] === "string") { + this._bytes = B_ENCODE_DEFAULT(arguments[0]); + this._offset = 0; + this._length = B_LENGTH(this._bytes); + } + else if (arguments.length === 2 && typeof arguments[0] === "string" && typeof arguments[1] === "string") { + this._bytes = B_ENCODE(arguments[0], arguments[1]); + this._offset = 0; + this._length = B_LENGTH(this._bytes); + } + // private: ByteArray(bytes, offset, length) + else if (arguments.length === 3 && typeof arguments[1] === "number" && typeof arguments[2] === "number") { + this._bytes = arguments[0]; + this._offset = arguments[1]; + this._length = arguments[2]; + } + else + throw new Error("Illegal arguments to ByteString constructor: [" + + Array.prototype.join.apply(arguments, [","]) + "] ("+arguments.length+")"); +}; + +ByteArray.prototype = new Binary(); + +ByteArray.prototype.__defineGetter__("length", function() { return this._length; }); +ByteArray.prototype.__defineSetter__("length", function(length) { + if (typeof length !== "number") + return; + + // same length + if (length === this.length) { + return; + } + // new length is less, truncate + else if (length < this._length) { + this._length = length; + } + // new length is more, but fits without moving, just clear new bytes + else if (this._offset + length <= B_LENGTH(this._bytes)) { + B_FILL(this._bytes, this._length, this._offset + length - 1, 0); + this._length = length; + } + // new length is more, but fits if we shift to bottom, so do that. + else if (length <= B_LENGTH(this._bytes)) { + B_COPY(this._bytes, this._offset, this._bytes, 0, this._length); + this._offset = 0; + B_FILL(this._bytes, this._length, this._offset + length - 1, 0); + this._length = length; + } + // new length is more than the allocated bytes array, allocate a new one and copy the data + else { + var newBytes = B_ALLOC(length); + B_COPY(this._bytes, this._offset, newBytes, 0, this._length); + this._bytes = newBytes; + this._offset = 0; + this._length = length; + } +}); + +// FIXME: array notation for set and get +ByteArray.prototype.set = function(index, b) { + // If any element is outside the range 0...255, an exception (TODO) is thrown. + if (b < 0 || b > 0xFF) + throw new Error("ByteString constructor argument Array of integers must be 0 - 255 ("+b+")"); + + if (index < 0 || index >= this._length) + throw new Error("Out of range"); + + // Java "bytes" are interpreted as 2's complement + //this._bytes[this._offset + index] = (b < 128) ? b : -1 * ((b ^ 0xFF) + 1); + B_SET(this._bytes, this._offset + index, b); +}; + +// toArray() +// toArray(charset) +// - implemented on Binary + +// toByteArray() - just a copy +// toByteArray(sourceCharset, targetCharset) - transcoded +// - implemented on Binary + +// toByteString() - byte for byte copy +// toByteString(sourceCharset, targetCharset) - transcoded +// - implemented on Binary + +// toString() - a string representation like "[ByteArray 10]" +// toString(charset) - an alias for decodeToString(charset) +ByteArray.prototype.toString = function(charset) { + if (charset) + return this.decodeToString(charset); + + return "[ByteArray "+this.length+"]"; +}; + +// decodeToString(charset) - implemented on Binary + +// byteAt(offset) ByteString - Return the byte at offset as a ByteString. +// - implemented on Binary + +// get(offset) Number - Return the byte at offset as a Number. +// - implemented on Binary + +// concat(other ByteArray|ByteString|Array) +// TODO: I'm assuming Array means an array of ByteStrings/ByteArrays, not an array of integers. +ByteArray.prototype.concat = function() { + var components = [this], + totalLength = this.length; + + for (var i = 0; i < arguments.length; i++) { + var component = Array.isArray(component) ? arguments[i] : [component]; + + for (var j = 0; j < component.length; j++) { + var subcomponent = component[j]; + if (!(subcomponent instanceof ByteString) && !(subcomponent instanceof ByteArray)) + throw "Arguments to ByteArray.concat() must be ByteStrings, ByteArrays, or Arrays of those."; + + components.push(subcomponent); + totalLength += subcomponent.length; + } + } + + var result = new ByteArray(totalLength), + offset = 0; + + components.forEach(function(component) { + B_COPY(component._bytes, component._offset, result._byte, offset, component._length); + offset += component._length; + }); + + return result; +}; + +// pop() -> byte Number +ByteArray.prototype.pop = function() { + if (this._length === 0) + return undefined; + + this._length--; + + return B_GET(this._bytes, this._offset + this._length); +}; + +// push(...variadic Numbers...)-> count Number +ByteArray.prototype.push = function() { + throw "NYI"; +}; + +// extendRight(...variadic Numbers / Arrays / ByteArrays / ByteStrings ...) +ByteArray.prototype.extendRight = function() { + throw "NYI"; +}; + +// shift() -> byte Number +ByteArray.prototype.shift = function() { + if (this._length === 0) + return undefined; + + this._length--; + this._offset++; + + return B_GET(this._bytes, this._offset - 1); +}; + +// unshift(...variadic Numbers...) -> count Number +ByteArray.prototype.unshift = function() { + throw "NYI"; +}; + +// extendLeft(...variadic Numbers / Arrays / ByteArrays / ByteStrings ...) +ByteArray.prototype.extendLeft = function() { + throw "NYI"; +}; + +// reverse() in place reversal +ByteArray.prototype.reverse = function() { + // "limit" is halfway, rounded down. "top" is the last index. + var limit = Math.floor(this._length/2) + this._offset, + top = this._length - 1; + + // swap each pair of bytes, up to the halfway point + for (var i = this._offset; i < limit; i++) { + var tmp = B_GET(this._bytes, i); + B_SET(this._bytes, i, B_GET(this._bytes, top - i)); + B_SET(this._bytes, top - i, tmp); + } + + return this; +}; + +// slice() +ByteArray.prototype.slice = function() { + return new ByteArray(ByteString.prototype.apply.slice(this, arguments)); +}; + +var numericCompareFunction = function(o1, o2) { return o1 - o2; }; + +// sort([compareFunction]) +ByteArray.prototype.sort = function(compareFunction) { + // FIXME: inefficient? + + var array = this.toArray(); + + if (arguments.length) + array.sort(compareFunction); + else + array.sort(numericCompareFunction); + + for (var i = 0; i < array.length; i++) + this.set(i, array[i]); +}; + +// splice() +ByteArray.prototype.splice = function() { + throw "NYI"; +}; + +// indexOf() - implemented on Binary +// lastIndexOf() - implemented on Binary + +// split() Returns an array of ByteArrays instead of ByteStrings. +ByteArray.prototype.split = function() { + var components = ByteString.prototype.split.apply(this.toByteString(), arguments); + + // convert ByteStrings to ByteArrays + for (var i = 0; i < components.length; i++) { + // we know we can use these byte buffers directly since we copied them above + components[i] = new ByteArray(components[i]._bytes, components[i]._offset, components[i]._length); + } + + return components; +}; + +// filter(callback[, thisObject]) +ByteArray.prototype.filter = function(callback, thisObject) { + var result = new ByteArray(this.length); + for (var i = 0, length = this.length; i < length; i++) { + var value = this.get(i); + if (callback.apply(thisObject, [value, i, this])) + result.push(value); + } + return result; +}; + +// forEach(callback[, thisObject]); +ByteArray.prototype.forEach = function(callback) { + for (var i = 0, length = this.length; i < length; i++) + callback.apply(thisObject, [this.get(i), i, this]); +}; + +// every(callback[, thisObject]) +ByteArray.prototype.every = function(callback, thisObject) { + for (var i = 0, length = this.length; i < length; i++) + if (!callback.apply(thisObject, [this.get(i), i, this])) + return false; + return true; +}; + +// some(callback[, thisObject]) +ByteArray.prototype.some = function(callback, thisObject) { + for (var i = 0, length = this.length; i < length; i++) + if (callback.apply(thisObject, [this.get(i), i, this])) + return true; + return false; +}; + +// map(callback[, thisObject]); +ByteArray.prototype.map = function(callback, thisObject) { + var result = new ByteArray(this.length); + for (var i = 0, length = this.length; i < length; i++) + result.set(i, callback.apply(thisObject, [this.get(i), i, this])); + return result; +}; + +// reduce(callback[, initialValue]) +ByteArray.prototype.reduce = function(callback, initialValue) { + var value = initialValue; + for (var i = 0, length = this.length; i < length; i++) + value = callback(value, this.get(i), i, this); + return value; +}; + +// reduceRight(callback[, initialValue]) +ByteArray.prototype.reduceRight = function(callback, initialValue) { + var value = initialValue; + for (var i = this.length-1; i > 0; i--) + value = callback(value, this.get(i), i, this); + return value; +}; + +// displace(begin, end, values/ByteStrings/ByteArrays/Arrays...) -> length +// begin/end are specified like for slice. Can be used like splice but does not return the removed elements. +ByteArray.prototype.displace = function(begin, end) { + throw "NYI"; +}; + +// toSource() returns a string like "ByteArray([])" for a null byte-array. +ByteArray.prototype.toSource = function() { + return "ByteArray(["+this.toArray().join(",")+"])"; +}; + +/* BinaryIO */ + +exports.BinaryIO = function(binary) { + if (!binary) + throw "NYI"; + + var stream = new (require("io").IO)(new java.io.ByteArrayInputStream(binary._bytes, binary._offset, binary._length), null); + stream.length = binary.length; + return stream; +}; + diff --git a/utils/platforms/default/lib/os-platform.js b/utils/platforms/default/lib/os-platform.js new file mode 100755 index 0000000..9d3a6f8 --- /dev/null +++ b/utils/platforms/default/lib/os-platform.js @@ -0,0 +1,3 @@ +exports.exit = function(status) { + throw new Error("Exiting with status="+status); +} diff --git a/utils/platforms/k7/bin/narwhal-k7 b/utils/platforms/k7/bin/narwhal-k7 new file mode 100755 index 0000000..495c9d8 --- /dev/null +++ b/utils/platforms/k7/bin/narwhal-k7 @@ -0,0 +1,32 @@ +#!/bin/bash + +# get the absolute path of the executable +SELF_PATH=$(cd -P -- "$(dirname -- "$0")" && pwd -P) && SELF_PATH=$SELF_PATH/$(basename -- "$0") + +# resolve symlinks +while [ -h $SELF_PATH ]; do + DIR=$(dirname -- "$SELF_PATH") + SYM=$(readlink $SELF_PATH) + SELF_PATH=$(cd $DIR && cd $(dirname -- "$SYM") && pwd)/$(basename -- "$SYM") +done + +NARWHAL_PLATFORM_HOME=$(dirname $(dirname $SELF_PATH)) +BOOTSTRAP="$NARWHAL_PLATFORM_HOME/bootstrap.js" + +if [ ! "$NARWHAL_HOME" ]; then + NARWHAL_HOME=$(dirname $(dirname $NARWHAL_PLATFORM_HOME)) +fi + +export NARWHAL_HOME + +# uses rlwrap (readline wrapper) if present +K7="$(which rlwrap) k7" + +# drop into shell if there are no additional arguments +if [ $# -lt 1 ]; then + # FIXME: no way to explicitly drop into shell + $K7 $BOOTSTRAP "$@" +else + MAIN=$(cd -P -- "$(dirname -- "$1")" && pwd -P) && MAIN=$MAIN/$(basename -- "$1" .js) + $K7 $BOOTSTRAP $MAIN "$0" "$@" +fi diff --git a/utils/platforms/k7/bootstrap.js b/utils/platforms/k7/bootstrap.js new file mode 100755 index 0000000..4fc18f5 --- /dev/null +++ b/utils/platforms/k7/bootstrap.js @@ -0,0 +1,78 @@ +(function (evalGlobal) { + + // NOTE: Newer version of K7 (>May 2009) does not but anything + // else than modules in the global namespace + if (typeof(ENV) == "undefined") { + GLOBAL = system.GLOBAL + ENV = system.ENV; + print = system.shell.print; + } + + var prefix = ENV["NARWHAL_HOME"]; + var debug = false; + + _system = system; + + var fopen = _system.posix.fopen, + fread = _system.posix.fread, + fclose = _system.posix.fclose; + + var isFile = function (path) { + try { read(path); } catch(e) { return false; } + return true; + }; + + var read = function(path) { + var result = "", + fd = fopen(path, "r"); + if (!fd) + throw new Error("File not found: " + path); + try { + var length = 1024, + data; + do { + length *= 2; + data = fread(1, length, fd); + result += data; + } while (data.length === length); + } finally { + fclose(fd); + } + if (result.length === 0) + throw new Error("File not found (length=0): " + path); + return result; + }; + + var isFile = function(path) { + return _system.posix.isFile(path); + } + + var _print = print; + delete print; + + eval(read(prefix + "/narwhal.js"))({ + global: GLOBAL, + evalGlobal: evalGlobal, + platform: 'k7', + platforms: ['k7', 'v8', 'c', 'default'], + debug: debug, + print: function (string) { + _print("" + string); + }, + evaluate: function (text) { + return eval("(function(require,exports,module,system,print){" + text + "/**/\n})"); + }, + fs: { + read: read, + isFile: isFile + }, + prefix: prefix, + complianceStage: "system" + }); + +})(function () { + return eval(arguments[0]); +}); + +//throw "Exiting. (FIXME: this exception does not mean an actual error occurred, we just need a better way to exit)"; +// EOF - vim: ts=4 sw=4 et diff --git a/utils/platforms/k7/lib/binary.js b/utils/platforms/k7/lib/binary.js new file mode 100755 index 0000000..139597f --- /dev/null +++ b/utils/platforms/k7/lib/binary.js @@ -0,0 +1,2 @@ + + diff --git a/utils/platforms/k7/lib/file-platform.js b/utils/platforms/k7/lib/file-platform.js new file mode 100755 index 0000000..89680cc --- /dev/null +++ b/utils/platforms/k7/lib/file-platform.js @@ -0,0 +1,116 @@ + +var exports = require('./file'); + +exports.SEPARATOR = '/'; + +exports.cwd = function () { + throw Error("cwd not yet implemented."); +}; + +// TODO necessary for package loading +exports.list = function (path) { + throw Error("list not yet implemented."); +}; + +// TODO necessary for package loading +exports.canonical = function (path) { + throw Error("canonical not yet implemented."); +}; + +exports.exists = function (path) { + throw Error("exists not yet implemented."); +}; + +// TODO necessary for lazy module reloading in sandboxes +exports.mtime = function (path) { + return exports.stat(path).mtime; +}; + +exports.size = function (path) { + throw Error("size not yet implemented."); +}; + +exports.stat = function (path) { + return _system.posix.stat(path); +}; + +// TODO necessary for package loading +exports.isDirectory = function (path) { + throw Error("isDirectory not yet implemented."); +}; + +// TODO necessary for module loading +exports.isFile = function (path) { + throw Error("isFile not yet implemented."); +}; + +exports.isFile = system.fs.isFile; // TEMPORARY HACK + +exports.isLink = function (path) { + throw Error("isLink not yet implemented."); +}; + +exports.isReadable = function (path) { + throw Error("isReadable not yet implemented."); +}; + +exports.isWritable = function (path) { + throw Error("isWritable not yet implemented."); +}; + +exports.rename = function (source, target) { + throw Error("rename not yet implemented."); +}; + +exports.move = function (source, target) { + throw Error("move not yet implemented."); +}; + +exports.remove = function (path) { + throw Error("remove not yet implemented."); +}; + +exports.mkdir = function (path) { + throw Error("mkdir not yet implemented."); +}; + +exports.rmdir = function(path) { + throw Error("rmdir not yet implemented."); +}; + +exports.touch = function (path, mtime) { + throw Error("touch not yet implemented."); +}; + +// FIXME temporary hack +var read = system.fs.read; // from k7 bootstrap fixtures + +exports.FileIO = function (path, mode, permissions) { + mode = exports.mode(mode); + var read = mode.read, + write = mode.write, + append = mode.append, + update = mode.update; + + if (update) { + throw new Error("Updating IO not yet implemented."); + } else if (write || append) { + throw new Error("Writing IO not yet implemented."); + } else if (read) { + // FIXME temporary hack + return { + 'read': function () { + return read(path); + }, + 'close': function () { + }, + 'isatty': function () { + return false; + } + }; + } else { + throw new Error("Files must be opened either for read, write, or update mode."); + } +}; + +// vim: ts=4 sw=4 et diff --git a/utils/platforms/k7/lib/io-platform.js b/utils/platforms/k7/lib/io-platform.js new file mode 100755 index 0000000..363544f --- /dev/null +++ b/utils/platforms/k7/lib/io-platform.js @@ -0,0 +1,8 @@ + +exports.IO = function () { +}; + +exports.TextIOWrapper = function (raw, mode, lineBuffering, buffering, charset, options) { + return raw; +}; + diff --git a/utils/platforms/k7/lib/system.js b/utils/platforms/k7/lib/system.js new file mode 100755 index 0000000..a92b8dd --- /dev/null +++ b/utils/platforms/k7/lib/system.js @@ -0,0 +1,25 @@ +/* +var IO = require("./io").IO; + +exports.stdin = new IO(function(){}, null); +exports.stdout = new IO(null, function(string) { print(String(string).replace(/\n$/,"")); }); +exports.stderr = new IO(null, function(string) { print(String(string).replace(/\n$/,"")); }); +*/ + +exports.args = ENV["argv"].slice(2); + +exports.env = {}; + +for (var key in ENV) + if (key !== "argc" && key !== "argv") + exports.env[key] = ENV[key]; + +delete ENV; + +exports.fs = require('./file'); + +/* +// default logger +var Logger = require("logger").Logger; +exports.log = new Logger(exports.stdout); +*/ diff --git a/utils/platforms/rhino/bin/narwhal-rhino.cmd b/utils/platforms/rhino/bin/narwhal-rhino.cmd new file mode 100755 index 0000000..646675a --- /dev/null +++ b/utils/platforms/rhino/bin/narwhal-rhino.cmd @@ -0,0 +1,25 @@ +@echo off +setlocal + +:: NARWHAL_PLATFORM_HOME is the parent the bin directory +set NARWHAL_PLATFORM_HOME=%~dp0.. + +set BOOTSTRAP=%NARWHAL_PLATFORM_HOME%\bootstrap.js + +if "%NARWHAL_HOME%" == "" ( + set NARWHAL_HOME=%NARWHAL_PLATFORM_HOME%\..\.. +) + +set CLASSPATH=%NARWHAL_PLATFORM_HOME%\jars\js.jar;%NARWHAL_PLATFORM_HOME%\jars\jline.jar +if not "%NARWHAL_CLASSPATH%" == "" ( + set CLASSPATH=%NARWHAL_CLASSPATH%;%CLASSPATH% +) + +set JAVA_MAIN=org.mozilla.javascript.tools.shell.Main + +:: drop into shell if there are no additional arguments +if "%1" == "" ( + java -cp "%CLASSPATH%" "%JAVA_MAIN%" -f "%BOOTSTRAP%" -f - +) else ( + java -cp "%CLASSPATH%" "%JAVA_MAIN%" "%BOOTSTRAP%" "%0" %* +) diff --git a/utils/platforms/rhino/lib/binary-platform.js b/utils/platforms/rhino/lib/binary-platform.js new file mode 100755 index 0000000..fda53fa --- /dev/null +++ b/utils/platforms/rhino/lib/binary-platform.js @@ -0,0 +1,44 @@ +exports.B_LENGTH = function(bytes) { + return bytes.length; +} + +exports.B_ALLOC = function(length) { + return java.lang.reflect.Array.newInstance(java.lang.Byte.TYPE, length); +} + +exports.B_FILL = function(bytes, length, offset, value) { + java.util.Arrays.fill(bytes, length, offset, value); +} + +exports.B_COPY = function(src, srcOffset, dst, dstOffset, length) { + java.lang.System.arraycopy(src, srcOffset, dst, dstOffset, length); +} + +exports.B_GET = function(bytes, index) { + var b = bytes[index]; + return (b >= 0) ? b : -1 * ((b ^ 0xFF) + 1); +} + +exports.B_SET = function(bytes, index, value) { + return bytes[index] = (value < 128) ? value : -1 * ((value ^ 0xFF) + 1); +} + +exports.B_DECODE = function(bytes, offset, length, codec) { + return String(new java.lang.String(bytes, offset, length, codec)); +} + +exports.B_DECODE_DEFAULT = function(bytes, offset, length) { + return String(new java.lang.String(bytes, offset, length)); +} + +exports.B_ENCODE = function(string, codec) { + return new java.lang.String(string).getBytes(codec); +} + +exports.B_ENCODE_DEFAULT = function(string) { + return new java.lang.String(string).getBytes(); +} + +exports.B_TRANSCODE = function(bytes, offset, length, sourceCodec, targetCodec) { + return new java.lang.String(bytes, offset, length, sourceCodec).getBytes(targetCodec); +} |