diff --git a/Objective-J/Bootstrap.js b/Objective-J/Bootstrap.js index 9467f0c93..a31dfda6b 100644 --- a/Objective-J/Bootstrap.js +++ b/Objective-J/Bootstrap.js @@ -1,29 +1,41 @@ -var rootNode = new StaticResourceNode("", NULL, StaticResourceNode.DirectoryType, YES), - cwd = FILE.cwd(); -#ifndef COMMONJS -rootNode.nodeAtSubPath(FILE.dirname(cwd), YES); -rootNode.resolveSubPath(cwd, StaticResourceNode.DirectoryType, function(cwdNode) + +var cwd = FILE.cwd(), + root = new StaticResourceNode("", NULL, StaticResourceNode.DirectoryType, cwd !== "/"), + rootNode = root; + +#ifdef BROWSER +if (root.isResolved()) { + root.nodeAtSubPath(FILE.dirname(cwd), YES); + resolveCWD(); +} +else +{ + root.resolve(); + root.addEventListener("resolve", resolveCWD); +} - var includePaths = exports.includePaths(), - index = 0, - count = includePaths.length; - - for (; index < count; ++index) - cwdNode.nodeAtSubPath(FILE.normal(includePaths[index]), YES); -#ifdef BROWSER - if (typeof OBJJ_MAIN_FILE === "undefined") - OBJJ_MAIN_FILE = "main.j"; - - fileImporterForPath(cwd)(OBJJ_MAIN_FILE, YES, function() +function resolveCWD() +{ + root.resolveSubPath(cwd, StaticResourceNode.DirectoryType, function(/*StaticResource*/ aResource) { - afterDocumentLoad(main); - }); -#endif -}); -#endif + var includePaths = exports.includePaths(), + index = 0, + count = includePaths.length; + + for (; index < count; ++index) + aResource.nodeAtSubPath(FILE.normal(includePaths[index]), YES); + + if (typeof OBJJ_MAIN_FILE === "undefined") + OBJJ_MAIN_FILE = "main.j"; + + fileImporterForPath(cwd)(OBJJ_MAIN_FILE || "main.j", YES, function() + { + afterDocumentLoad(main); + }); + }); +} -#ifdef BROWSER function afterDocumentLoad(/*Function*/ aFunction) { if (documentLoaded) diff --git a/Objective-J/CFBundle.js b/Objective-J/CFBundle.js index 12a0a1471..f3a3cd4da 100644 --- a/Objective-J/CFBundle.js +++ b/Objective-J/CFBundle.js @@ -159,13 +159,27 @@ CFBundle.prototype.load = function(/*BOOL*/ shouldExecute) if (this._loadStatus !== CFBundleUnloaded) return; - var self = this; + this._loadStatus = CFBundleLoading | CFBundleLoadingInfoPlist; - self._loadStatus = CFBundleLoading | CFBundleLoadingInfoPlist; + var self = this; rootNode.resolveSubPath(FILE.dirname(self.path()), StaticResourceNode.DirectoryType, function(aStaticResourceNode) { - self._staticResourceNode = new StaticResourceNode(FILE.basename(self.path()), aStaticResourceNode, StaticResourceNode.DirectoryType, NO); + var path = self.path(); + + // If this bundle exists at the root path, no need to create a node. + if (path === "/") + self._staticResourceNode = rootNode; + + else + { + var name = FILE.basename(path); + + self._staticResourceNode = aStaticResourceNode._childNodes[name]; + + if (!self._staticResourceNode) + self._staticResourceNode = new StaticResourceNode(name, aStaticResourceNode, StaticResourceNode.DirectoryType, NO); + } function onsuccess(/*Event*/ anEvent) { @@ -174,11 +188,7 @@ CFBundle.prototype.load = function(/*BOOL*/ shouldExecute) if (!self._infoDictionary) { - self._eventDispatcher.dispatchEvent( - { - type:"error", - error: new Error("Could not load bundle at \"" + self.path() + "\"") - }); + finishBundleLoadingWithError(self, new Error("Could not load bundle at \"" + path + "\"")); return; } @@ -188,16 +198,24 @@ CFBundle.prototype.load = function(/*BOOL*/ shouldExecute) function onfailure() { - self._staticResourceNode._isResolved = YES; self._loadStatus = CFBundleUnloaded; - self._eventDispatcher.dispatchEvent( - { - type:"error", - error: new Error("Could not load bundle at \"" + self.path() + "\"") - }); + + finishBundleLoadingWithError(self, new Error("Could not load bundle at \"" + path + "\"")); } - new FileRequest(FILE.join(self.path(), "Info.plist"), onsuccess, onfailure); + new FileRequest(FILE.join(path, "Info.plist"), onsuccess, onfailure); + }); +} + +function finishBundleLoadingWithError(/*CFBundle*/ aBundle, /*Event*/ anError) +{ + resolveStaticResource(aBundle._staticResourceNode); + + aBundle._eventDispatcher.dispatchEvent( + { + type:"error", + error:anError, + bundle:aBundle }); } @@ -224,16 +242,7 @@ function loadExecutableAndResources(/*Bundle*/ aBundle, /*BOOL*/ shouldExecute) aBundle._loadStatus = CFBundleUnloaded; - resolveStaticResourceNode(aBundle._staticResourceNode, NO); - - aBundle._eventDispatcher.dispatchEvent( - { - type:"error", - error:anError || new Error("Could not recognize executable code format in Bundle " + aBundle), - bundle:aBundle - }); - - resolveStaticResourceNode(aBundle._staticResourceNode, YES); + finishBundleLoadingWithError(aBundle, anError || new Error("Could not recognize executable code format in Bundle " + aBundle)); } function success() @@ -245,17 +254,15 @@ function loadExecutableAndResources(/*Bundle*/ aBundle, /*BOOL*/ shouldExecute) // Set resolved to true here in case during evaluation this bundle // needs to resolve another bundle which in turn needs it to be resolved (cycle). - resolveStaticResourceNode(aBundle._staticResourceNode, NO); + resolveStaticResource(aBundle._staticResourceNode); function complete() { aBundle._eventDispatcher.dispatchEvent( { - type:"load", + type:"load", bundle:aBundle }); - - resolveStaticResourceNode(aBundle._staticResourceNode, YES); } if (shouldExecute) @@ -276,7 +283,7 @@ function loadExecutableForBundle(/*Bundle*/ aBundle, success, failure) { try { - decompileStaticFile(aBundle, anEvent.request.responseText()) + decompileStaticFile(aBundle, anEvent.request.responseText()); aBundle._loadStatus &= ~CFBundleLoadingExecutable; success(); } @@ -346,7 +353,7 @@ function CFBundleTestSpriteSupport(/*String*/ MHTMLPath, /*Function*/ aCallback) return; CFBundleTestSpriteTypes([ - CFBundleDataURLSpriteType, + CFBundleDataURLSpriteType, "data:image/gif;base64,R0lGODlhAQABAIAAAMc9BQAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==", CFBundleMHTMLSpriteType, MHTMLPath, @@ -385,7 +392,7 @@ function CFBundleTestSpriteTypes(/*Array*/ spriteTypes) CFBundleNotifySpriteSupportListeners(); } else - CFBundleTestSpriteType(spriteTypes.slice(2)); + CFBundleTestSpriteTypes(spriteTypes.slice(2)); } image.src = spriteTypes[1]; @@ -496,7 +503,9 @@ function decompileStaticFile(/*Bundle*/ aBundle, /*String*/ aString) aBundle._URIMap[text] = URI; // The unresolved directories must not be bundles. - rootNode.nodeAtSubPath(FILE.join(bundlePath, FILE.dirname(text)), YES); + var parentNode = rootNode.nodeAtSubPath(FILE.join(bundlePath, FILE.dirname(text)), YES); + + new StaticResourceNode(FILE.basename(text), parentNode, StaticResourceNode.FileType, YES); } else if (marker === MARKER_TEXT) diff --git a/Objective-J/StaticResourceNode.js b/Objective-J/StaticResourceNode.js index 124750bf7..7eea0224f 100644 --- a/Objective-J/StaticResourceNode.js +++ b/Objective-J/StaticResourceNode.js @@ -92,7 +92,10 @@ require("file"); join: function() { - return Array.prototype.join.apply(arguments, ["/"]); + if (arguments.length === 1 && arguments[0] === "") + return "/"; + + return FILE.normal(Array.prototype.join.call(arguments, "/")); }, split: function(/*String*/ aPath) @@ -121,7 +124,7 @@ function StaticResourceNode(/*String*/ aName, /*StaticResourceNode*/ aParentNode this._eventDispatcher = new EventDispatcher(this); this._name = aName; - this._isResolved = isResolved; + this._isResolved = !!isResolved; if (!aParentNode) this._path = "/"; @@ -141,11 +144,48 @@ function StaticResourceNode(/*String*/ aName, /*StaticResourceNode*/ aParentNode this._childNodes = { }; else if (aType === StaticResourceNode.FileType) - { this._contents = ""; +} - if (!isResolved) - this.resolveAsFile(); +function resolveStaticResource(/*StaticResource*/ aResource) +{ + aResource._isResolved = YES; + aResource._eventDispatcher.dispatchEvent( + { + type:"resolve", + staticResourceNode:aResource + }); +} + +StaticResourceNode.prototype.resolve = function() +{ + if (this.type() === StaticResourceNode.DirectoryType) + { + var bundle = new CFBundle(this.path()); + + // Eat any errors. + bundle.onerror = function() { }; + + // The bundle will actually resolve this node. + bundle.load(NO); + } + else + { + var self = this; + + function onsuccess(/*anEvent*/ anEvent) + { + self._contents = anEvent.request.responseText(); + resolveStaticResource(self); + } + + function onfailure() + { + self._type = StaticResourceNode.NotFoundType; + resolveStaticResource(self); + } + + new FileRequest(this.path(), onsuccess, onfailure); } } @@ -184,45 +224,11 @@ StaticResourceNode.prototype.isResolved = function() return this._isResolved; } -function resolveStaticResourceNode(/*StaticResourceNode*/ aStaticResourceNode, /*BOOL*/ shouldDispatchEvent) -{ - aStaticResourceNode._isResolved = YES; - - if (shouldDispatchEvent) - aStaticResourceNode._eventDispatcher.dispatchEvent( - { - type:"resolve", - staticResourceNode:aStaticResourceNode - }); -} - StaticResourceNode.prototype.write = function(/*String*/ aString) { this._contents += aString; } -StaticResourceNode.prototype.resolveAsFile = function() -{ - var self = this; - - function onsuccess(/*anEvent*/ anEvent) - { - self._type = StaticResourceNode.FileType; - self._contents = anEvent.request.responseText(); - - resolveStaticResourceNode(self, YES); - } - - function onfailure() - { - self._type = StaticResourceNode.NotFoundType; - - resolveStaticResourceNode(self, YES); - } - - new FileRequest(this.path(), onsuccess, onfailure); -} - StaticResourceNode.prototype.resolveSubPath = function(/*String*/ aPath, /*Type*/ aType, /*Function*/ aCallback) { aPath = FILE.normal(aPath); @@ -260,56 +266,28 @@ function resolvePathComponents(/*StaticResourceNode*/ startNode, /*Type*/aType, if (!childNode) { + var type = index + 1 < count || aType === StaticResourceNode.DirectoryType ? StaticResourceNode.DirectoryType : StaticResourceNode.FileType; - if (index + 1 < count || aType === StaticResourceNode.DirectoryType) - { - var bundle = new CFBundle(components.slice(0, index + 1).join("/")); - - // Eat any errors. - bundle.onerror = function() { }; - - bundle.addEventListener("load", continueResolution); - bundle.addEventListener("error", continueResolution); - - bundle.load(NO); - } - else - { - childNode = new StaticResourceNode(name, parentNode, StaticResourceNode.FileType, NO); - - if (childNode.isResolved()) - continueResolution(); - else - childNode.addEventListener("resolve", continueResolution); - } - - return; + childNode = new StaticResourceNode(name, parentNode, type, NO); + childNode.resolve(); } - else if (childNode.isResolved()) - { - // If we've already determined that this file doesn't exist... - if (childNode.isNotFound()) - return aCallback(null, new Error("File not found: " + components.join("/"))); - // If we have no more path components... - if (index + 1 >= count) - return aCallback(childNode); - - // Make sure this is a directory - if (childNode.type() !== StaticResourceNode.DirectoryType) - return aCallback(null, new Error("File is not a directory: " + components.join("/"))); - - // Do nothing: simply allow the loop to progress to the next child. - } // If this node is still being resolved, just wait and rerun this same method when it's ready. - else - { - childNode.addEventListener("resolve", continueResolution); - return; - } + if (!childNode.isResolved()) + return childNode.addEventListener("resolve", continueResolution); + + // If we've already determined that this file doesn't exist... + if (childNode.isNotFound()) + return aCallback(null, new Error("File not found: " + components.join("/"))); + + // If we have more path components and this is not a directory... + if ((index + 1 < count) && childNode.type() !== StaticResourceNode.DirectoryType) + return aCallback(null, new Error("File is not a directory: " + components.join("/"))); parentNode = childNode; } + + return aCallback(parentNode); } StaticResourceNode.prototype.addEventListener = function(/*String*/ anEventName, /*Function*/ anEventListener) @@ -365,7 +343,7 @@ StaticResourceNode.prototype.nodeAtSubPath = function(/*String*/ aPath, /*BOOL*/ { var name = components[index]; - if (hasOwnProperty.apply(parentNode._childNodes, [name])) + if (hasOwnProperty.call(parentNode._childNodes, name)) parentNode = parentNode._childNodes[name]; else if (shouldResolveAsDirectories) @@ -409,4 +387,4 @@ exports.includePaths = function() return global.OBJJ_INCLUDE_PATHS || ["Frameworks", "Frameworks/Debug"]; } -exports.StaticResourceNode = StaticResourceNode; \ No newline at end of file +exports.StaticResourceNode = StaticResourceNode;