Further migration from file paths to CFURLs.

Reviewed by me.
This commit is contained in:
Francisco Ryan Tolmasky I
2010-03-03 01:04:25 -08:00
parent f3a0710059
commit eb57d14673
15 changed files with 631 additions and 897 deletions
+1 -1
View File
@@ -113,7 +113,7 @@ var CPBundlesForPaths = { };
- (id)objectForInfoDictionaryKey:(CPString)aKey
{
return _bundle.valueForInfoDictionary(aKey);
return _bundle.valueForInfoDictionaryKey(aKey);
}
//
+36 -428
View File
@@ -29,19 +29,23 @@ CPURLCustomIconKey = @"CPURLCustomIconKey";
@implementation CPURL : CPObject
{
CPURL _base @accessors(readonly, property=baseURL);
CPString _relative @accessors(readonly, property=relativeString);
CPDictionary _resourceValues;
}
- (id)initWithScheme:(CPString)scheme host:(CPString)host path:(CPString)path
+ (id)alloc
{
var uri = new URI();
uri.scheme = scheme;
uri.authority = host;
uri.path = path;
[self initWithString:uri.toString()];
return new CFURL();
}
- (id)init
{
return nil;
}
- (id)initWithScheme:(CPString)aScheme host:(CPString)aHost path:(CPString)aPath
{
var URLString = (aScheme ? aScheme + ":" : "") + (aHost ? aHost + "//" : "") + (aPath || "");
return [self initWithString:URLString];
}
- (id)initWithString:(CPString)URLString
@@ -54,51 +58,35 @@ CPURLCustomIconKey = @"CPURLCustomIconKey";
return [[self alloc] initWithString:URLString];
}
- (id)initWithString:(CPString)URLString relativeToURL:(CPURL)baseURL
- (id)initWithString:(CPString)URLString relativeToURL:(CPURL)aBaseURL
{
if (!URI_RE.test(URLString))
return nil;
if (self)
{
_base = baseURL;
_relative = URLString;
_resourceValues = [CPDictionary dictionary];
}
return self;
return new CFURL(URLString, aBaseURL);
}
+ (id)URLWithString:(CPString)URLString relativeToURL:(CPURL)baseURL
+ (id)URLWithString:(CPString)URLString relativeToURL:(CPURL)aBaseURL
{
return [[self alloc] initWithString:URLString relativeToURL:baseURL];
return [[self alloc] initWithString:URLString relativeToURL:aBaseURL];
}
- (CPURL)absoluteURL
{
var absStr = [self absoluteString];
if (absStr !== _relative)
return [[CPURL alloc] initWithString:absStr];
return self;
return self.absoluteURL();
}
- (CPString)absoluteString
{
return resolve([_base absoluteString] || "", _relative);
return self.absoluteString();
}
// if absolute, returns same as absoluteString
- (CPString)relativeString
{
return _relative;
return self.string();
}
- (CPString)path
{
var str = [self absoluteString];
return URI_RE.test(str) ? (parse(str).path || nil) : nil;
return [self absoluteString].path();
}
// if absolute, returns the same as path
@@ -107,11 +95,9 @@ CPURLCustomIconKey = @"CPURLCustomIconKey";
return URI_RE.test(_relative) ? (parse(_relative).path || nil) : nil;
}
- (CPString)scheme
{
var str = [self absoluteString];
return URI_RE.test(str) ? (parse(str).protocol || nil) : nil;
return self.scheme();
}
- (CPString)user
@@ -164,15 +150,12 @@ CPURLCustomIconKey = @"CPURLCustomIconKey";
- (CPString)lastPathComponent
{
var path = [self path];
return path ? path.split("/").pop() : nil;
return [self absoluteURL].lastPathComponent();
}
- (CPString)pathExtension
{
var path = [self path],
ext = path.match(/\.(\w+)$/);
return ext ? ext[1] : "";
return self.pathExtension();
}
- (CPURL)standardizedURL
@@ -192,413 +175,38 @@ CPURLCustomIconKey = @"CPURLCustomIconKey";
- (id)resourceValueForKey:(CPString)aKey
{
return [_resourceValues objectForKey:aKey];
return self.resourcePropertyForKey(aKey);
}
- (id)setResourceValue:(id)anObject forKey:(CPString)aKey
{
[_resourceValues setObject:anObject forKey:aKey];
return self.setResourcePropertyForKey(aKey, anObject);
}
- (CPString)staticResourceData
{
// FIXME: This probably shouldn't go through CFBundle for no reason.
return CFBundle.dataContentsAtPath([self path]);
return self.staticResourceData();
}
@end
var CPURLURLStringKey = @"CPURLURLStringKey",
CPURLBaseURLKey = @"CPURLBaseURLKey";
@implementation CPURL (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
_base = [aCoder decodeObjectForKey:"CPURLBaseKey"];
_relative = [aCoder decodeObjectForKey:"CPURLRelativeKey"];
return self;
return [self initWithURLString:[aCoder decodeObjectForKey:CPURLURLStringKey]
baseURL:[aCoder decodeObjectForKey:CPURLBaseURLKey]];
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[aCoder encodeObject:_base forKey:"CPURLBaseKey"];
[aCoder encodeObject:_relative forKey:"CPURLRelativeKey"];
[aCoder encodeObject:_baseURL forKey:CPURLBaseURLKey];
[aCoder encodeObject:_string forKey:CPURLURLStringKey];
}
@end
// original code: http://code.google.com/p/js-uri/
// Based on the regex in RFC2396 Appendix B.
var URI_RE = /^(?:([^:\/?\#]+):)?(?:\/\/([^\/?\#]*))?([^?\#]*)(?:\?([^\#]*))?(?:\#(.*))?/;
/**
* Uniform Resource Identifier (URI) - RFC3986
*/
var URI = function(str) {
if (!str) str = "";
var result = str.match(URI_RE);
this.scheme = result[1] || null;
this.authority = result[2] || null;
this.path = result[3] || null;
this.query = result[4] || null;
this.fragment = result[5] || null;
}
/**
* Convert the URI to a String.
*/
URI.prototype.toString = function () {
var str = "";
if (this.scheme)
str += this.scheme + ":";
if (this.authority)
str += "//" + this.authority;
if (this.path)
str += this.path;
if (this.query)
str += "?" + this.query;
if (this.fragment)
str += "#" + this.fragment;
return str;
}
var parse = function(uri) {
return new URI(uri);
}
var unescape = function(str, plus) {
return decodeURI(str).replace(/\+/g, " ");
}
var unescapeComponent = function(str, plus) {
return decodeURIComponent(str).replace(/\+/g, " ");
}
// from Chiron's HTTP module:
/**** keys
members of a parsed URI object.
*/
var 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.
*/
var expressionKeys = [
"url",
"protocol",
"authorityRoot",
"authority",
"userInfo",
"user",
"password",
"domain",
"port",
"path",
"root",
"directory",
"file",
"query",
"anchor"
];
/**** strictExpression
*/
var 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.
*/
var 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[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.
*/
var parse = Parser(strictExpression);
/**** format
accepts a parsed URI object and returns
the corresponding string.
*/
var 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 source location.
*/
var resolveObject = function (source, relative) {
if (!source)
return relative;
source = parse(source);
relative = parse(relative);
if (relative.url == "")
return source;
delete source.url;
delete source.authority;
delete source.domain;
delete source.userInfo;
delete source.path;
delete source.directory;
if (
relative.protocol && relative.protocol != source.protocol ||
relative.authority && relative.authority != source.authority
) {
source = relative;
} else {
if (relative.root) {
source.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 (source.directories.length) {
source.directories.pop();
} else {
source.directories.push('..');
}
} else {
source.directories.push(directory);
}
}
if (relative.file == ".") {
relative.file = "";
} else if (relative.file == "..") {
source.directories.pop();
relative.file = "";
}
}
}
if (relative.root)
source.root = relative.root;
if (relative.protcol)
source.protocol = relative.protocol;
if (!(!relative.path && relative.anchor))
source.file = relative.file;
source.query = relative.query;
source.anchor = relative.anchor;
return source;
};
/**** relativeObject
returns an object representing a relative URL to
a given target URL from a source URL.
*/
var relativeObject = function (source, target) {
target = parse(target);
source = parse(source);
delete target.url;
if (
target.protocol == source.protocol &&
target.authority == source.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 == !!source.root && !(
target.root &&
target.directories[0] != source.directories[0]
)
) {
delete target.path;
delete target.root;
delete target.directory;
while (
source.directories.length &&
target.directories.length &&
target.directories[0] == source.directories[0]
) {
target.directories.shift();
source.directories.shift();
}
while (source.directories.length) {
source.directories.shift();
target.directories.unshift('..');
}
if (!target.root && !target.directories.length && !target.file && source.file)
target.directories.push('.');
if (source.file == target.file)
delete target.file;
if (source.query == target.query)
delete target.query;
if (source.anchor == target.anchor)
delete target.anchor;
}
}
return target;
};
/**** resolve
returns a URL resovled to a relative URL from a source URL.
*/
var resolve = function (source, relative) {
return format(resolveObject(source, relative));
};
/**** relative
returns a relative URL to a target from a source.
*/
var relative = function (source, target) {
return format(relativeObject(source, target));
};
CFURL.prototype.isa = [CPURL class];
+33 -24
View File
@@ -20,42 +20,52 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
var cwd = FILE.cwd(),
rootResource = new StaticResource("", NULL, YES, cwd !== "/");
StaticResource.root = rootResource;
#ifdef COMMONJS
var mainBundleURL = new CFURL("file:" + require("file").cwd());
#elif defined(BROWSER)
// To determine where our application lives, start with the current URL of the page.
var pageURL = new CFURL(window.location.href),
#ifdef BROWSER
// Look for any <base> tags and choose the last one (which is the one that will take effect).
DOMBaseElements = document.getElementsByTagName("base"),
DOMBaseElementsCount = DOMBaseElements.length;
if (DOMBaseElementsCount > 0)
{
var DOMBaseElement = DOMBaseElements[DOMBaseElementsCount - 1],
DOMBaseElementHref = DOMBaseElement && DOMBaseElement.getAttribute("href");
// If we have one, use it instead.
if (DOMBaseElementHref)
pageURL = new CFURL(DOMBaseElementHref, pageURL);
}
// Turn the main file into a URL.
var mainFileURL = new CFURL(window.OBJJ_MAIN_FILE || "main.j"),
// The main bundle is the containing folder of the main file.
mainBundleURL = new CFURL(".", new CFURL(mainFileURL, pageURL)).absoluteURL();
StaticResource.resourceAtURL(new CFURL("..", mainBundleURL).absoluteURL(), YES);
exports.bootstrap = function()
{
if (rootResource.isResolved())
{
rootResource.nodeAtSubPath(FILE.dirname(cwd), YES);
resolveCWD();
}
else
{
rootResource.resolve();
rootResource.addEventListener("resolve", resolveCWD);
}
resolveMainBundleURL();
}
function resolveCWD()
function resolveMainBundleURL()
{
rootResource.resolveSubPath(cwd, YES, function(/*StaticResource*/ aResource)
StaticResource.resolveResourceAtURL(mainBundleURL, YES, function(/*StaticResource*/ aResource)
{
var includePaths = StaticResource.includePaths(),
var includeURLs = StaticResource.includeURLs(),
index = 0,
count = includePaths.length;
count = includeURLs.length;
for (; index < count; ++index)
aResource.nodeAtSubPath(FILE.normal(includePaths[index]), YES);
aResource.resourceAtURL(includeURLs[index], YES);
if (typeof OBJJ_MAIN_FILE === "undefined")
OBJJ_MAIN_FILE = "main.j";
Executable.fileImporterForPath(cwd)(OBJJ_MAIN_FILE || "main.j", YES, function()
Executable.fileImporterForURL(mainBundleURL)(mainFileURL, YES, function()
{
afterDocumentLoad(main);
});
@@ -81,7 +91,6 @@ afterDocumentLoad(function()
documentLoaded = YES;
});
if (typeof OBJJ_AUTO_BOOTSTRAP === "undefined" || OBJJ_AUTO_BOOTSTRAP)
exports.bootstrap();
+144 -127
View File
@@ -27,25 +27,27 @@ var CFBundleUnloaded = 0,
CFBundleLoadingSpritedImages = 1 << 3,
CFBundleLoaded = 1 << 4;
var CFBundlesForPaths = { },
CFBundlesForClasses = { },
var CFBundlesForURLStrings = { },
CFBundlesForClasses = { },
CFCacheBuster = new Date().getTime(),
CFTotalBytesLoaded = 0,
CPApplicationSizeInBytes = 0;
GLOBAL(CFBundle) = function(/*String*/ aPath)
GLOBAL(CFBundle) = function(/*CFURL|String*/ aURL)
{
aPath = FILE.absolute(aPath);
aURL = resolveURL(aURL).asDirectoryPathURL();
var existingBundle = CFBundlesForPaths[aPath];
var URLString = aURL.absoluteString(),
existingBundle = CFBundlesForURLStrings[URLString];
if (existingBundle)
return existingBundle;
CFBundlesForPaths[aPath] = this;
CFBundlesForURLStrings[URLString] = this;
this._bundleURL = aURL;
this._resourcesDirectoryURL = new CFURL("Resources/", aURL);
this._path = aPath;
this._name = FILE.basename(aPath);
this._staticResource = NULL;
this._loadStatus = CFBundleUnloaded;
@@ -63,18 +65,18 @@ CFBundle.environments = function()
return ENVIRONMENTS;
}
CFBundle.bundleContainingPath = function(/*String*/ aPath)
CFBundle.bundleContainingURL = function(/*CFURL*/ aURL)
{
aPath = FILE.absolute(aPath);
aURL = new CFURL(".", resolveURL(aURL));
while (aPath !== "/")
while (aURL.path() !== "/")
{
var bundle = CFBundlesForPaths[aPath];
var bundle = CFBundlesForURLStrings[aURL.absoluteString()];
if (bundle)
return bundle;
aPath = FILE.dirname(aPath);
aURL = new CFURL("..", aURL);
}
return NULL;
@@ -82,7 +84,7 @@ CFBundle.bundleContainingPath = function(/*String*/ aPath)
CFBundle.mainBundle = function()
{
return new CFBundle(FILE.cwd());
return new CFBundle(mainBundleURL);
}
function addClassToBundle(aClass, aBundle)
@@ -96,9 +98,50 @@ CFBundle.bundleForClass = function(/*Class*/ aClass)
return CFBundlesForClasses[aClass.name] || CFBundle.mainBundle();
}
CFBundle.prototype.path = function()
CFBundle.prototype.bundleURL = function()
{
return this._path;
return this._bundleURL;
}
CFBundle.prototype.resourcesDirectoryURL = function()
{
return this._resourcesDirectoryURL;
}
CFBundle.prototype.resourceURL = function(/*String*/ aResourceName, /*String*/ aType, /*String*/ aSubDirectory)
{
if (aType)
aResourceName = aResourceName + "." + aType;
if (aSubDirectory)
aResourceName = aSubDirectory + "/" + aResourceName;
var resourceURL = (new CFURL(aResourceName, this.resourcesDirectoryURL())).mappedURL();
return resourceURL.absoluteURL();
}
CFBundle.prototype.mostEligibleEnvironmentURL = function()
{
if (this._mostEligibleEnvironmentURL === undefined)
this._mostEligibleEnvironmentURL = new CFURL(this.mostEligibleEnvironment() + ".environment/", this.bundleURL());
return this._mostEligibleEnvironmentURL;
}
CFBundle.prototype.executableURL = function()
{
if (this._executableURL === undefined)
{
var executableSubPath = this.valueForInfoDictionaryKey("CPBundleExecutable");
if (!executableSubPath)
this._executableURL = NULL;
else
this._executableURL = new CFURL(executableSubPath, this.mostEligibleEnvironmentURL());
}
return this._executableURL;
}
CFBundle.prototype.infoDictionary = function()
@@ -106,37 +149,11 @@ CFBundle.prototype.infoDictionary = function()
return this._infoDictionary;
}
CFBundle.prototype.valueForInfoDictionary = function(/*String*/ aKey)
CFBundle.prototype.valueForInfoDictionaryKey = function(/*String*/ aKey)
{
return this._infoDictionary.valueForKey(aKey);
}
CFBundle.prototype.resourcesPath = function()
{
return FILE.join(this.path(), "Resources");
}
CFBundle.prototype.pathForResource = function(/*String*/ aPath)
{
var mappedPath = this._URIMap[FILE.join("Resources", aPath)];
if (mappedPath)
return mappedPath;
// If not, return the trivial path.
return FILE.join(this.resourcesPath(), aPath);
}
CFBundle.prototype.executablePath = function()
{
var executableSubPath = this._infoDictionary.valueForKey("CPBundleExecutable");
if (executableSubPath)
return FILE.join(this.path(), this.mostEligibleEnvironment() + ".environment", executableSubPath);
return NULL;
}
CFBundle.prototype.hasSpritedImages = function()
{
var environments = this._infoDictionary.valueForKey("CPBundleEnvironmentsWithImageSprites") || [],
@@ -192,23 +209,19 @@ CFBundle.prototype.load = function(/*BOOL*/ shouldExecute)
var self = this;
rootResource.resolveSubPath(FILE.dirname(self.path()), YES, function(aStaticResource)
var parentURL = new CFURL("..", this.bundleURL());
//???
if (parentURL.absoluteString() === this.bundleURL().absoluteString())
parentURL = parentURL.schemeAndAuthority();
StaticResource.resolveResourceAtURL(parentURL, YES, function(aStaticResource)
{
var path = self.path();
var resourceName = self.bundleURL().absoluteURL().lastPathComponent();
// If this bundle exists at the root path, no need to create a node.
if (path === "/")
self._staticResource = rootResource;
else
{
var name = FILE.basename(path);
self._staticResource = aStaticResource._children[name];
if (!self._staticResource)
self._staticResource = new StaticResource(name, aStaticResource, YES, NO);
}
self._staticResource = aStaticResource._children[resourceName] ||
new StaticResource(resourceName, aStaticResource, YES, NO);
function onsuccess(/*Event*/ anEvent)
{
@@ -222,8 +235,8 @@ CFBundle.prototype.load = function(/*BOOL*/ shouldExecute)
return;
}
if (self === CFBundle.mainBundle() && self.valueForInfoDictionary("CPApplicationSize"))
CPApplicationSizeInBytes = self.valueForInfoDictionary("CPApplicationSize").valueForKey("executable") || 0;
if (self === CFBundle.mainBundle() && self.valueForInfoDictionaryKey("CPApplicationSize"))
CPApplicationSizeInBytes = self.valueForInfoDictionaryKey("CPApplicationSize").valueForKey("executable") || 0;
loadExecutableAndResources(self, shouldExecute);
}
@@ -232,10 +245,10 @@ CFBundle.prototype.load = function(/*BOOL*/ shouldExecute)
{
self._loadStatus = CFBundleUnloaded;
finishBundleLoadingWithError(self, new Error("Could not load bundle at \"" + path + "\""));
finishBundleLoadingWithError(self, new Error("Could not load bundle at \"" + self.bundleURL() + "\""));
}
new FileRequest(FILE.join(path, "Info.plist"), onsuccess, onfailure);
new FileRequest(new CFURL("Info.plist", self.bundleURL()), onsuccess, onfailure);
});
}
@@ -279,7 +292,7 @@ function loadExecutableAndResources(/*Bundle*/ aBundle, /*BOOL*/ shouldExecute)
function success()
{
if ((typeof CPApp === "undefined" || !CPApp || !CPApp._finishedLaunching) &&
if ((typeof CPApp === "undefined" || !CPApp || !CPApp._finishedLaunching) &&
typeof OBJJ_PROGRESS_CALLBACK === "function" && CPApplicationSizeInBytes)
{
OBJJ_PROGRESS_CALLBACK(MAX(MIN(1.0, CFTotalBytesLoaded / CPApplicationSizeInBytes), 0.0), CPApplicationSizeInBytes, aBundle.path())
@@ -312,17 +325,19 @@ function loadExecutableAndResources(/*Bundle*/ aBundle, /*BOOL*/ shouldExecute)
function loadExecutableForBundle(/*Bundle*/ aBundle, success, failure)
{
if (!aBundle.executablePath())
var executableURL = aBundle.executableURL();
if (!executableURL)
return;
aBundle._loadStatus |= CFBundleLoadingExecutable;
new FileRequest(aBundle.executablePath(), function(/*Event*/ anEvent)
new FileRequest(executableURL, function(/*Event*/ anEvent)
{
try
{
CFTotalBytesLoaded += anEvent.request.responseText().length;
decompileStaticFile(aBundle, anEvent.request.responseText(), aBundle.executablePath());
decompileStaticFile(aBundle, anEvent.request.responseText(), executableURL);
aBundle._loadStatus &= ~CFBundleLoadingExecutable;
success();
}
@@ -333,6 +348,23 @@ function loadExecutableForBundle(/*Bundle*/ aBundle, success, failure)
}, failure);
}
function spritedImagesTestURLStringForBundle(/*Bundle*/ aBundle)
{
return "mhtml:" + new CFURL("MHTMLTest.txt", aBundle.mostEligibleEnvironmentURL());
}
function spritedImagesURLForBundle(/*Bundle*/ aBundle)
{
if (CFBundleSupportedSpriteType === CFBundleDataURLSpriteType)
return new CFURL("dataURLs.txt", aBundle.mostEligibleEnvironmentURL());
if (CFBundleSupportedSpriteType === CFBundleMHTMLSpriteType ||
CFBundleSupportedSpriteType === CFBundleMHTMLUncachedSpriteType)
return new CFURL("MHTMLPaths.txt", aBundle.mostEligibleEnvironmentURL());
return NULL;
}
function loadSpritedImagesForBundle(/*Bundle*/ aBundle, success, failure)
{
if (!aBundle.hasSpritedImages())
@@ -341,25 +373,25 @@ function loadSpritedImagesForBundle(/*Bundle*/ aBundle, success, failure)
aBundle._loadStatus |= CFBundleLoadingSpritedImages;
if (!CFBundleHasTestedSpriteSupport())
return CFBundleTestSpriteSupport(spritedImagesTestPathForBundle(aBundle), function()
return CFBundleTestSpriteSupport(spritedImagesTestURLStringForBundle(aBundle), function()
{
loadSpritedImagesForBundle(aBundle, success, failure);
});
var spritedImagesPath = spritedImagesPathForBundle(aBundle);
var spritedImagesURL = spritedImagesURLForBundle(aBundle);
if (!spritedImagesPath)
if (!spritedImagesURL)
{
aBundle._loadStatus &= ~CFBundleLoadingSpritedImages;
return success();
}
new FileRequest(spritedImagesPath, function(/*Event*/ anEvent)
new FileRequest(spritedImagesURL, function(/*Event*/ anEvent)
{
try
{
CFTotalBytesLoaded += anEvent.request.responseText().length;
decompileStaticFile(aBundle, anEvent.request.responseText(), spritedImagesPath);
decompileStaticFile(aBundle, anEvent.request.responseText(), spritedImagesURL);
aBundle._loadStatus &= ~CFBundleLoadingSpritedImages;
success();
}
@@ -395,7 +427,7 @@ function CFBundleTestSpriteSupport(/*String*/ MHTMLPath, /*Function*/ aCallback)
CFBundleSpriteSupportListeners.push(function()
{
var size = 0,
sizeDictionary = CFBundle.mainBundle().valueForInfoDictionary("CPApplicationSize");
sizeDictionary = CFBundle.mainBundle().valueForInfoDictionaryKey("CPApplicationSize");
if (!sizeDictionary)
return;
@@ -463,45 +495,9 @@ function CFBundleTestSpriteTypes(/*Array*/ spriteTypes)
image.src = spriteTypes[1];
}
function mhtmlBasePath()
{
#ifdef BROWSER
//FIXME: URL stuff is kind of broken
return window.location.protocol + "//" + window.location.hostname + (window.location.port ? (":" + window.location.port) : "");
#else
return "";
#endif
}
function spritedImagesTestPathForBundle(/*Bundle*/ aBundle)
{
return "mhtml:" + mhtmlBasePath() + FILE.join(aBundle.path(), aBundle.mostEligibleEnvironment() + ".environment", "MHTMLTest.txt");
}
function spritedImagesPathForBundle(/*Bundle*/ aBundle)
{
if (CFBundleSupportedSpriteType === CFBundleDataURLSpriteType)
return FILE.join(aBundle.path(), aBundle.mostEligibleEnvironment() + ".environment", "dataURLs.txt");
if (CFBundleSupportedSpriteType === CFBundleMHTMLSpriteType || CFBundleSupportedSpriteType === CFBundleMHTMLUncachedSpriteType)
return mhtmlBasePath() + FILE.join(aBundle.path(), aBundle.mostEligibleEnvironment() + ".environment", "MHTMLPaths.txt");
return NULL;
}
CFBundle.dataContentsAtPath = function(/*String*/ aPath)
{
var data = new CFMutableData();
data.setRawString(rootResource.nodeAtSubPath(aPath).contents());
return data;
}
function executeBundle(/*Bundle*/ aBundle, /*Function*/ aCallback)
{
var staticResources = [aBundle._staticResource],
resourcesPath = aBundle.resourcesPath();
var staticResources = [aBundle._staticResource];
function executeStaticResources(index)
{
@@ -514,7 +510,7 @@ function executeBundle(/*Bundle*/ aBundle, /*Function*/ aCallback)
if (staticResource.isFile())
{
var executable = new FileExecutable(staticResource.path());
var executable = new FileExecutable(staticResource.URL());
if (executable.hasLoadedFileDependencies())
executable.execute();
@@ -532,7 +528,7 @@ function executeBundle(/*Bundle*/ aBundle, /*Function*/ aCallback)
else //if (staticResource.isDirectory())
{
// We don't want to execute resources.
if (staticResource.path() === aBundle.resourcesPath())
if (staticResource.URL().absoluteString() === aBundle.resourcesDirectoryURL().absoluteString())
continue;
var children = staticResource.children();
@@ -562,13 +558,13 @@ function decompileStaticFile(/*Bundle*/ aBundle, /*String*/ aString, /*String*/
var stream = new MarkedStream(aString);
if (stream.magicNumber() !== STATIC_MAGIC_NUMBER)
throw new Error("Could not read static file: "+aPath);
throw new Error("Could not read static file: " + aPath);
if (stream.version() !== "1.0")
throw new Error("Could not read static file: "+aPath);
throw new Error("Could not read static file: " + aPath);
var marker,
bundlePath = aBundle.path(),
bundleURL = aBundle.bundleURL(),
file = NULL;
while (marker = stream.getMarker())
@@ -577,35 +573,44 @@ function decompileStaticFile(/*Bundle*/ aBundle, /*String*/ aString, /*String*/
if (marker === MARKER_PATH)
{
var absolutePath = FILE.join(bundlePath, text),
parent = rootResource.nodeAtSubPath(FILE.dirname(absolutePath), YES);
var fileURL = new CFURL(text, bundleURL),
parent = StaticResource.resourceAtURL(new CFURL(".", fileURL), YES);
file = new StaticResource(FILE.basename(absolutePath), parent, NO, YES);
file = new StaticResource(fileURL.lastPathComponent(), parent, NO, YES);
}
else if (marker === MARKER_URI)
{
var URI = stream.getString();
var URL = new CFURL(text, bundleURL),
mappedURL,
mappedURLString = stream.getString();
if (URI.toLowerCase().indexOf("mhtml:") === 0)
if (mappedURLString.toLowerCase().indexOf("mhtml:") === 0)
{
URI = "mhtml:" + mhtmlBasePath() + FILE.join(bundlePath, URI.substr("mhtml:".length));
mappedURLString = "mhtml:" + new CFURL(URLString.substr("mhtml:".length), bundleURL);
/*
URLString = "mhtml:" + URL;
if (CFBundleSupportedSpriteType === CFBundleMHTMLUncachedSpriteType)
{
var exclamationIndex = URI.indexOf("!"),
firstPart = URI.substring(0, exclamationIndex),
lastPart = URI.substring(exclamationIndex);
var exclamationIndex = URLString.indexOf("!"),
firstPart = URLString.substring(0, exclamationIndex),
lastPart = URLString.substring(exclamationIndex);
URI = firstPart + "?" + CFCacheBuster + lastPart;
URLString = firstPart + "?" + CFCacheBuster + lastPart;
}
mappedURL = new CFURL(URLString);*/
}
aBundle._URIMap[text] = URI;
else
mappedURL = new CFURL(mappedURLString);
CFURL.setMappedURLForURL(URL, mappedURL);
// The unresolved directories must not be bundles.
var parent = rootResource.nodeAtSubPath(FILE.join(bundlePath, FILE.dirname(text)), YES);
var parent = StaticResource.resourceAtURL(new CFURL(".", URL), YES);
new StaticResource(FILE.basename(text), parent, NO, YES);
new StaticResource(URL.lastPathComponent(), parent, NO, YES);
}
else if (marker === MARKER_TEXT)
@@ -629,3 +634,15 @@ CFBundle.prototype.onerror = function(/*Event*/ anEvent)
{
throw anEvent.error;
}
//
CFBundle.prototype.path = function()
{
return this._bundleURL.absoluteString();
}
CFBundle.prototype.pathForResource = function(aResource)
{
return this.resourceURL(aResource).absoluteString();
}
+8 -5
View File
@@ -252,7 +252,7 @@ function determineAndDispatchHTTPRequestEvents(/*CFHTTPRequest*/ aRequest)
}
}
function FileRequest(/*String*/ aFilePath, onsuccess, onfailure)
function FileRequest(/*CFURL*/ aURL, onsuccess, onfailure)
{
#ifdef BROWSER
var request = new CFHTTPRequest();
@@ -260,16 +260,19 @@ function FileRequest(/*String*/ aFilePath, onsuccess, onfailure)
request.onsuccess = Asynchronous(onsuccess);
request.onfailure = Asynchronous(onfailure);
if (FILE.extension(aFilePath) === ".plist")
if (aURL.pathExtension() === "plist")
request.overrideMimeType("text/xml");
request.open("GET", aFilePath, YES);
request.open("GET", aURL.absoluteString(), YES);
request.send("");
#else
if (!FILE.exists(aFilePath))
var FILE = require("file"),
filePath = aURL.absoluteURL().path();
if (!FILE.exists(filePath))
return onfailure();
this._responseText = FILE.read(aFilePath, { charset:"UTF-8" });
this._responseText = FILE.read(filePath, { charset:"UTF-8" });
onsuccess({ type:"success", request:this });
#endif
+133 -15
View File
@@ -1,24 +1,64 @@
// Based on the regex in RFC2396 Appendix B.
var URI_RE = /^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/;
GLOBAL(CFURL) = function(/*CFURL|String*/ aURLOrString, /*CFURL*/ aBaseURL)
GLOBAL(CFURL) = function(/*CFURL|String*/ aURL, /*CFURL*/ aBaseURL)
{
if (aURLOrString instanceof CFURL)
return new CFURL(aURLOrString.string(), aBaseURL);
if (aURL instanceof CFURL)
if (!aBaseURL)
return aURL
else
{
var existingBaseURL = aURL.baseURL();
this._string = aURLOrString;
if (existingBaseURL)
aBaseURL = new CFURL(existingBaseURL, aBaseURL);
var result = (aURLOrString || "").match(URI_RE);
return new CFURL(aURL.string(), aBaseURL);
}
this._UID = objj_generateObjectUID();
this._string = aURL;
var result = (aURL || "").match(URI_RE);
this._baseURL = aBaseURL;
this._resourcePropertiesForKeys = new CFMutableDictionary();
this._scheme = result[2] || NULL;
this._authority = result[4] || NULL;
this._path = result[5] || NULL;
this._scheme = result[2];
this._authority = result[4];
this._path = result[5] || "";
this._queryString = result[7] || NULL;
this._fragment = result[9] || NULL;
}
var URLMap = { };
CFURL.prototype.mappedURL = function()
{
return URLMap[this.absoluteString()] || this;
}
CFURL.setMappedURLForURL = function(/*CFURL*/ fromURL, /*CFURL*/ toURL)
{
URLMap[fromURL.absoluteString()] = toURL;
}
CFURL.prototype.schemeAndAuthority = function()
{
var string = "",
scheme = this.scheme();
if (scheme)
string += scheme + ":";
var authority = this.authority();
if (authority)
string += "//" + authority;
return string;
}
CFURL.prototype.absoluteString = function()
{
return this.absoluteURL().string();
@@ -35,7 +75,7 @@ CFURL.prototype.absoluteURL = function()
{
var baseURL = this._baseURL;
this._absoluteURL = baseURL ? resolve(baseURL.string(), this.string()) : this;
this._absoluteURL = baseURL ? new CFURL(resolve(baseURL.absoluteString(), this.string())) : this;
}
return this._absoluteURL;
@@ -48,12 +88,22 @@ CFURL.prototype.string = function()
CFURL.prototype.authority = function()
{
return this._authority;
var authority = this._authority;
if (authority === undefined)
{
var baseURL = this.baseURL();
authority = baseURL && baseURL.authority() || NULL;
this._authority = authority;
}
return authority;
}
CFURL.prototype.hasDirectoryPath = function()
{
var path = this._path;
var path = this.path();
if (!path)
return NO;
@@ -93,6 +143,39 @@ CFURL.prototype.path = function()
return this._path;
}
CFURL.prototype.pathComponents = function()
{
if (!this._pathComponents)
{
var path = this.path();
if (!path)
this._pathComponents = [];
else
{
var components = path.split("/"),
result = [],
index = 0,
count = components.length;
for (; index < count; ++index)
{
var component = components[index];
if (component)
result.push(component);
else if (index === 0)
result.push("/");
}
this._pathComponents = result;
}
}
return this._pathComponents;
}
CFURL.prototype.pathExtension = function()
{
var lastPathComponent = this.lastPathComponent();
@@ -114,7 +197,17 @@ CFURL.prototype.queryString = function()
CFURL.prototype.scheme = function()
{
return this._scheme;
var scheme = this._scheme;
if (scheme === undefined)
{
var baseURL = this.baseURL();
scheme = baseURL && baseURL.scheme() || NULL;
this._scheme = scheme;
}
return scheme;
}
CFURL.prototype.baseURL = function()
@@ -122,7 +215,32 @@ CFURL.prototype.baseURL = function()
return this._baseURL;
}
CFURL.prototype.asDirectoryPathURL = function()
{
if (this.hasDirectoryPath())
return this;
return new CFURL(this.lastPathComponent() + "/", this);
}
CFURL.prototype.resourcePropertyForKey = function(/*String*/ aKey)
{
return this._resourcePropertiesForKeys.objectForKey(aKey);
}
CFURL.prototype.setResourcePropertyForKey = function(/*String*/ aKey, /*id*/ aValue)
{
this._resourcePropertiesForKeys.setObjectForKey(aKey, aValue);
}
CFURL.prototype.staticResourceData = function()
{
var data = new CFMutableData();
data.setRawString(StaticResource.resourceAtURL(this).contents());
return data;
}
// from Chiron's HTTP module:
@@ -335,7 +453,7 @@ var resolveObject = function (source, relative) {
) {
source = relative;
} else {
if (relative.root) {
if (relative.root || relative.protocol) {
source.directories = relative.directories;
} else {
@@ -363,9 +481,9 @@ var resolveObject = function (source, relative) {
}
}
if (relative.root)
if (relative.root || relative.protocol)
source.root = relative.root;
if (relative.protcol)
if (relative.protocol)
source.protocol = relative.protocol;
if (!(!relative.path && relative.anchor))
source.file = relative.file;
+3 -3
View File
@@ -155,8 +155,8 @@ exports.objj_eval = function(/*String*/ aString)
var code = executable._code;
// Not clear why these should be global, varing them doesn't seem to take effect with evaluateString.
global.objj_executeFile = Executable.fileExecuterForPath(FILE.cwd());
global.objj_importFile = Executable.fileImporterForPath(FILE.cwd());
global.objj_executeFile = Executable.fileExecuterForURL(FILE.cwd());
global.objj_importFile = Executable.fileImporterForURL(FILE.cwd());
if (typeof system !== "undefined" && system.engine === "rhino")
return Packages.org.mozilla.javascript.Context.getCurrentContext().evaluateString(global, code, "objj_eval", 0, NULL);
@@ -173,7 +173,7 @@ exports.make_narwhal_factory = function(path)
{
Executable.setCommonJSArguments(require, exports, module, system, print, window);
Executable.fileImporterForPath(FILE.dirname(path))(path, function()
Executable.fileImporterForURL(FILE.dirname(path))(path, YES, function()
{
print("all done");
});
+2 -2
View File
@@ -30,7 +30,7 @@ EventDispatcher.prototype.addEventListener = function(/*String*/ anEventName, /*
{
var eventListenersForEventNames = this._eventListenersForEventNames;
if (!hasOwnProperty.call(this._eventListenersForEventNames, anEventName))
if (!hasOwnProperty.call(eventListenersForEventNames, anEventName))
{
var eventListenersForEventName = [];
eventListenersForEventNames[anEventName] = eventListenersForEventName;
@@ -54,7 +54,7 @@ EventDispatcher.prototype.removeEventListener = function(/*String*/ anEventName,
if (!hasOwnProperty.call(eventListenersForEventNames, anEventName))
return;
var eventListenersForEventName = eventListenersForEventNames[anEventName].
var eventListenersForEventName = eventListenersForEventNames[anEventName],
index = eventListenersForEventName.length;
while (index--)
+49 -57
View File
@@ -22,7 +22,9 @@
var ExecutableUnloadedFileDependencies = 0,
ExecutableLoadingFileDependencies = 1,
ExecutableLoadedFileDependencies = 2;
ExecutableLoadedFileDependencies = 2,
AnonymousExecutableCount = 0;
function Executable(/*String*/ aCode, /*Array*/ fileDependencies, /*CFURL*/ aURL, /*Function*/ aFunction)
{
@@ -31,7 +33,7 @@ function Executable(/*String*/ aCode, /*Array*/ fileDependencies, /*CFURL*/ aURL
this._code = aCode;
this._function = aFunction || NULL;
this._URL = aURL || new CFURL("(Anonymous)", mainBundleURL);
this._URL = resolveURL(aURL || new CFURL("(Anonymous" + (AnonymousExecutableCount++) + ")", mainBundleURL));
this._fileDependencies = fileDependencies;
this._fileDependencyLoadStatus = ExecutableUnloadedFileDependencies;
@@ -124,7 +126,7 @@ Executable.prototype.execute = function()
#endif
var oldContextBundle = CONTEXT_BUNDLE;
CONTEXT_BUNDLE = CFBundle.bundleContainingPath(this.path());
CONTEXT_BUNDLE = CFBundle.bundleContainingURL(this.URL());
var result = this._function.apply(global, this.functionArguments());
@@ -197,7 +199,7 @@ Executable.prototype.loadFileDependencies = function()
this._fileDependencyLoadStatus = ExecutableLoadingFileDependencies;
var searchedPaths = [{ }, { }],
var searchedURLStrings = [{ }, { }],
fileExecutableSearches = new CFMutableDictionary(),
incompleteFileExecutableSearches = new CFMutableDictionary(),
loadingExecutables = { };
@@ -215,11 +217,11 @@ Executable.prototype.loadFileDependencies = function()
if (executable.hasLoadedFileDependencies())
continue;
var executablePath = executable.path();
var executableURLString = executable.URL().absoluteString();
loadingExecutables[executablePath] = executable;
loadingExecutables[executableURLString] = executable;
var cwd = FILE.dirname(executablePath),
var referenceURL = new CFURL(".", executable.URL()),
fileDependencies = executable.fileDependencies(),
fileDependencyIndex = 0,
fileDependencyCount = fileDependencies.length;
@@ -228,14 +230,19 @@ Executable.prototype.loadFileDependencies = function()
{
var fileDependency = fileDependencies[fileDependencyIndex],
isLocal = fileDependency.isLocal(),
path = importablePath(fileDependency.path(), isLocal, cwd);
URL = fileDependency.URL();
if (searchedPaths[isLocal ? 1 : 0][path])
if (isLocal)
URL = new CFURL(URL, referenceURL);
var URLString = URL.absoluteString();
if (searchedURLStrings[isLocal ? 1 : 0][URLString])
continue;
searchedPaths[isLocal ? 1 : 0][path] = YES;
searchedURLStrings[isLocal ? 1 : 0][URLString] = YES;
var fileExecutableSearch = new FileExecutableSearch(path, isLocal),
var fileExecutableSearch = new FileExecutableSearch(URL, isLocal),
fileExecutableSearchUID = fileExecutableSearch.UID();
if (fileExecutableSearches.containsKey(fileExecutableSearchUID))
@@ -278,14 +285,14 @@ Executable.prototype.loadFileDependencies = function()
CPLog("DEPENDENCY: Ended");
#endif
for (var path in loadingExecutables)
if (hasOwnProperty.call(loadingExecutables, path))
loadingExecutables[path]._fileDependencyLoadStatus = ExecutableLoadedFileDependencies;
for (var URLString in loadingExecutables)
if (hasOwnProperty.call(loadingExecutables, URLString))
loadingExecutables[URLString]._fileDependencyLoadStatus = ExecutableLoadedFileDependencies;
for (var path in loadingExecutables)
if (hasOwnProperty.call(loadingExecutables, path))
for (var URLString in loadingExecutables)
if (hasOwnProperty.call(loadingExecutables, URLString))
{
var executable = loadingExecutables[path];
var executable = loadingExecutables[URLString];
executable._eventDispatcher.dispatchEvent(
{
@@ -308,81 +315,67 @@ Executable.prototype.removeEventListener = function(/*String*/ anEventName, /*Fu
this._eventDispatcher.removeEventListener(anEventName, aListener);
}
function importablePath(/*String*/ aPath, /*BOOL*/ isLocal, /*String*/ aCWD)
{
aPath = FILE.normal(aPath);
if (FILE.isAbsolute(aPath))
return aPath;
if (isLocal)
aPath = FILE.normal(FILE.join(aCWD, aPath));
return aPath;
}
Executable.prototype.fileImporter = function()
{
return Executable.fileImporterForPath(FILE.dirname(this.path()));
return Executable.fileImporterForURL(new CFURL(".", this.URL()));
}
Executable.prototype.fileExecuter = function()
{
return Executable.fileExecuterForPath(FILE.dirname(this.path()));
return Executable.fileExecuterForURL(new CFURL(".", this.URL()));
}
var cachedFileExecutersForPaths = { };
var cachedFileExecutersForURLStrings = { };
Executable.fileExecuterForPath = function(/*String*/ referencePath)
Executable.fileExecuterForURL = function(/*CFURL|String*/ aURL)
{
referencePath = FILE.normal(referencePath);
var referenceURL = resolveURL(aURL),
referenceURLString = referenceURL.absoluteString(),
cachedFileExecuter = cachedFileExecutersForURLStrings[referenceURLString];
var fileExecuter = cachedFileExecutersForPaths[referencePath];
if (!fileExecuter)
if (!cachedFileExecuter)
{
fileExecuter = function(/*String*/ aPath, /*BOOL*/ isLocal, /*BOOL*/ shouldForce)
cachedFileExecuter = function(/*CFURL*/ aURL, /*BOOL*/ isQuoted, /*BOOL*/ shouldForce)
{
aPath = importablePath(aPath, isLocal, referencePath);
aURL = new CFURL(aURL, isQuoted ? referenceURL : NULL);
var fileExecutableSearch = new FileExecutableSearch(aPath, isLocal),
var fileExecutableSearch = new FileExecutableSearch(aURL, isQuoted),
fileExecutable = fileExecutableSearch.result();
if (0 && !fileExecutable.hasLoadedFileDependencies())
throw "No executable loaded for file at path " + aPath;
if (!fileExecutable.hasLoadedFileDependencies())
throw "No executable loaded for file at URL " + aURL;
fileExecutable.execute(shouldForce);
}
cachedFileExecutersForPaths[referencePath] = fileExecuter;
cachedFileExecutersForURLStrings[referenceURLString] = cachedFileExecuter;
}
return fileExecuter;
return cachedFileExecuter;
}
var cachedImportersForPaths = { };
var cachedImportersForURLStrings = { };
Executable.fileImporterForPath = function(/*String*/ referencePath)
Executable.fileImporterForURL = function(/*CFURL*/ aURL)
{
referencePath = FILE.normal(referencePath);
var cachedImporter = cachedImportersForPaths[referencePath];
var referenceURL = resolveURL(aURL),
referenceURLString = referenceURL.absoluteString(),
cachedImporter = cachedImportersForURLStrings[referenceURLString];
if (!cachedImporter)
{
cachedImporter = function(/*String*/ aPath, /*BOOL*/ isLocal, /*Function*/ aCallback)
cachedImporter = function(/*CFURL*/ aURL, /*BOOL*/ isQuoted, /*Function*/ aCallback)
{
aPath = importablePath(aPath, isLocal, referencePath);
aURL = new CFURL(aURL, isQuoted ? referenceURL : NULL);
var fileExecutableSearch = new FileExecutableSearch(aPath, isLocal);
var fileExecutableSearch = new FileExecutableSearch(aURL, isQuoted);
function searchComplete(/*FileExecutableSearch*/ aFileExecutableSearch)
{
var fileExecutable = aFileExecutableSearch.result(),
fileExecuter = Executable.fileExecuterForPath(referencePath),
executeAndCallback = function ()
{
fileExecuter(aPath, isLocal);
fileExecutable.execute();
if (aCallback)
aCallback();
@@ -406,9 +399,8 @@ Executable.fileImporterForPath = function(/*String*/ referencePath)
});
}
cachedImportersForPaths[referencePath] = cachedImporter;
cachedImportersForURLStrings[referenceURLString] = cachedImporter;
}
return cachedImporter;
}
+8 -6
View File
@@ -20,17 +20,17 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
function FileDependency(/*String*/ aPath, /*BOOL*/ isLocal)
function FileDependency(/*CFURL*/ aURL, /*BOOL*/ isLocal)
{
this._path = FILE.normal(aPath);
this._URL = aURL;
this._isLocal = isLocal;
}
exports.FileDependency = FileDependency;
FileDependency.prototype.path = function()
FileDependency.prototype.URL = function()
{
return this._path;
return this._URL;
}
FileDependency.prototype.isLocal = function()
@@ -40,11 +40,13 @@ FileDependency.prototype.isLocal = function()
FileDependency.prototype.toMarkedString = function()
{
var URLString = this.URL().absoluteString();
return (this.isLocal() ? MARKER_IMPORT_LOCAL : MARKER_IMPORT_STD) + ";" +
this.path().length + ";" + this.path();
URLString.length + ";" + URLString;
}
FileDependency.prototype.toString = function()
{
return (this.isLocal() ? "LOCAL: " : "STD: ") + this.path();
return (this.isLocal() ? "LOCAL: " : "STD: ") + this.URL();
}
+5 -4
View File
@@ -24,7 +24,8 @@ var FileExecutablesForURLStrings = { };
function FileExecutable(/*CFURL*/ aURL, /*Executable*/ anExecutable)
{
if (!aURL._path) aURL = new CFURL(aURL);
aURL = resolveURL(aURL);
var URLString = aURL.absoluteString(),
existingFileExecutable = FileExecutablesForURLStrings[URLString];
@@ -33,7 +34,7 @@ if (!aURL._path) aURL = new CFURL(aURL);
FileExecutablesForURLStrings[URLString] = this;
var fileContents = rootResource.nodeAtSubPath(aURL.path()).contents(),
var fileContents = StaticResource.resourceAtURL(aURL).contents(),
executable = NULL,
extension = aURL.pathExtension();
@@ -111,10 +112,10 @@ function decompile(/*String*/ aString, /*CFURL*/ aURL)
code += text;
else if (marker === MARKER_IMPORT_STD)
dependencies.push(new FileDependency(text, NO));
dependencies.push(new FileDependency(new CFURL(text), NO));
else if (marker === MARKER_IMPORT_LOCAL)
dependencies.push(new FileDependency(text, YES));
dependencies.push(new FileDependency(new CFURL(text), YES));
}
return new Executable(code, dependencies, aURL);
+16 -15
View File
@@ -22,22 +22,23 @@
var FileExecutableSearchesForPaths = [{ }, { }];
function FileExecutableSearch(/*String*/ aPath, /*BOOL*/ isLocal)
function FileExecutableSearch(/*CFURL*/ aURL, /*BOOL*/ isQuoted)
{
if (!FILE.isAbsolute(aPath) && isLocal)
throw "Local searches cannot be relative: " + aPath;
var existingSearch = FileExecutableSearchesForPaths[isLocal ? 1 : 0][aPath];
// if (isQuoted && !aURL.protocol())
// throw "Local searches cannot be relative: " + aPath;
var URLString = aURL.absoluteString(),
existingSearch = FileExecutableSearchesForPaths[isQuoted ? 1 : 0][URLString];
if (existingSearch)
return existingSearch;
FileExecutableSearchesForPaths[isLocal ? 1 : 0][aPath] = this;
FileExecutableSearchesForPaths[isQuoted ? 1 : 0][URLString] = this;
this._UID = objj_generateObjectUID();
this._URL = aURL;
this._isComplete = NO;
this._eventDispatcher = new EventDispatcher(this);
this._path = aPath;
this._result = NULL;
@@ -46,9 +47,9 @@ function FileExecutableSearch(/*String*/ aPath, /*BOOL*/ isLocal)
function completed(/*String*/ aStaticResource)
{
if (!aStaticResource)
throw new Error("Could not load file at " + aPath);
throw new Error("Could not load file at " + aURL);
self._result = new FileExecutable(aStaticResource.path());
self._result = new FileExecutable(aStaticResource.URL());
self._isComplete = YES;
self._eventDispatcher.dispatchEvent(
@@ -58,17 +59,17 @@ function FileExecutableSearch(/*String*/ aPath, /*BOOL*/ isLocal)
});
}
if (isLocal || FILE.isAbsolute(aPath))
rootResource.resolveSubPath(aPath, NO, completed);
if (isQuoted)
StaticResource.resolveResourceAtURL(aURL, NO, completed);
else
StaticResource.resolveStandardNodeAtPath(aPath, completed);
StaticResource.resolveResourceAtURLSearchingIncludeURLs(aURL, completed);
}
exports.FileExecutableSearch = FileExecutableSearch;
FileExecutableSearch.prototype.path = function()
FileExecutableSearch.prototype.URL = function()
{
return this._path;
return this._URL;
}
FileExecutableSearch.prototype.result = function()
+9 -9
View File
@@ -534,30 +534,30 @@ Preprocessor.prototype.implementation = function(tokens, /*StringBuffer*/ aStrin
Preprocessor.prototype._import = function(tokens)
{
var path = "",
var URLString = "",
token = tokens.skip_whitespace(),
isLocal = (token != TOKEN_LESS_THAN);
isQuoted = (token !== TOKEN_LESS_THAN);
if (token === TOKEN_LESS_THAN)
{
while((token = tokens.next()) && token != TOKEN_GREATER_THAN)
path += token;
while((token = tokens.next()) && token !== TOKEN_GREATER_THAN)
URLString += token;
if(!token)
throw new SyntaxError(this.error_message("*** Unterminated import statement."));
}
else if (token.charAt(0) == TOKEN_DOUBLE_QUOTE)
path = token.substr(1, token.length - 2);
else if (token.charAt(0) === TOKEN_DOUBLE_QUOTE)
URLString = token.substr(1, token.length - 2);
else
throw new SyntaxError(this.error_message("*** Expecting '<' or '\"', found \"" + token + "\"."));
CONCAT(this._buffer, "objj_executeFile(\"");
CONCAT(this._buffer, path);
CONCAT(this._buffer, isLocal ? "\", true);" : "\", false);");
CONCAT(this._buffer, URLString);
CONCAT(this._buffer, isQuoted ? "\", YES);" : "\", NO);");
this._dependencies.push(new FileDependency(path, isLocal));
this._dependencies.push(new FileDependency(new CFURL(URLString), isQuoted));
}
Preprocessor.prototype.method = function(/*Lexer*/ tokens)
+121 -201
View File
@@ -1,124 +1,5 @@
var FILE =
#ifdef COMMONJS
require("file");
#else
{
absolute: function(/*String*/ aPath)
{
aPath = FILE.normal(aPath);
if (FILE.isAbsolute(aPath))
return aPath;
return FILE.join(FILE.cwd(), aPath);
},
basename: function(/*String*/ aPath)
{
var components = FILE.split(FILE.normal(aPath));
return components[components.length - 1];
},
extension: function(/*String*/ aPath)
{
aPath = FILE.basename(aPath);
aPath = aPath.replace(/^\.*/, '');
var index = aPath.lastIndexOf(".");
return index <= 0 ? "" : aPath.substring(index);
},
cwd: function()
{
return FILE._cwd;
},
normal: function(/*String*/ aPath)
{
if (!aPath)
return "";
var components = aPath.split("/"),
results = [],
index = 0,
count = components.length,
isRoot = aPath.charAt(0) === "/";
for (; index < count; ++index)
{
var component = components[index];
// These simply remain in the current directory.
if (component === "" || component === ".")
continue;
if (component !== "..")
{
results.push(component);
continue;
}
var resultsCount = results.length;
// If we have a valid previous component, "climb" it.
if (resultsCount > 0 && results[resultsCount - 1] !== "..")
results.pop();
// If this isn't a root listing, and we are preceded by only ..'s, or
// nothing at all, then add it since it makes sense for relative paths.
else if (!isRoot && resultsCount === 0 || results[resultsCount - 1] === "..")
results.push(component);
}
return (isRoot ? "/" : "") + results.join("/");
},
dirname: function(/*String*/ aPath)
{
var aPath = FILE.normal(aPath),
components = FILE.split(aPath);
if (components.length === 2)
components.unshift("");
return FILE.join.apply(FILE, components.slice(0, components.length - 1));
},
isAbsolute: function(/*String*/ aPath)
{
return aPath.charAt(0) === "/";
},
join: function()
{
if (arguments.length === 1 && arguments[0] === "")
return "/";
return FILE.normal(Array.prototype.join.call(arguments, "/"));
},
split: function(/*String*/ aPath)
{
return FILE.normal(aPath).split("/");
}
}
var path = window.location.pathname,
DOMBaseElement = document.getElementsByTagName("base")[0];
if (DOMBaseElement)
path = DOMBaseElement.getAttribute("href");
// If this is a directory, then use it as our relative path.
if (path.charAt(path.length - 1) === "/")
FILE._cwd = path;
// If not, use it's parent.
else
FILE._cwd = FILE.dirname(path);
#endif
var rootResources = { };
function StaticResource(/*String*/ aName, /*StaticResource*/ aParent, /*BOOL*/ isDirectory, /*BOOL*/ isResolved)
{
@@ -127,7 +8,13 @@ function StaticResource(/*String*/ aName, /*StaticResource*/ aParent, /*BOOL*/ i
this._name = aName;
this._isResolved = !!isResolved;
this._path = FILE.join(aParent ? aParent.path() : "", aName);
this._URL = new CFURL(aName, aParent && aParent.URL().asDirectoryPathURL());
if (isDirectory)
this._URL = this._URL.asDirectoryPathURL();
if (!aParent)
rootResources[aName] = this;
this._isDirectory = !!isDirectory;
this._isNotFound = NO;
@@ -142,6 +29,11 @@ function StaticResource(/*String*/ aName, /*StaticResource*/ aParent, /*BOOL*/ i
this._contents = "";
}
StaticResource.rootResources = function()
{
return rootResources;
}
exports.StaticResource = StaticResource;
function resolveStaticResource(/*StaticResource*/ aResource)
@@ -158,7 +50,7 @@ StaticResource.prototype.resolve = function()
{
if (this.isDirectory())
{
var bundle = new CFBundle(this.path());
var bundle = new CFBundle(this.URL());
// Eat any errors.
bundle.onerror = function() { };
@@ -182,7 +74,7 @@ StaticResource.prototype.resolve = function()
resolveStaticResource(self);
}
new FileRequest(this.path(), onsuccess, onfailure);
new FileRequest(this.URL(), onsuccess, onfailure);
}
}
@@ -191,9 +83,9 @@ StaticResource.prototype.name = function()
return this._name;
}
StaticResource.prototype.path = function()
StaticResource.prototype.URL = function()
{
return this._path;
return this._URL;
}
StaticResource.prototype.contents = function()
@@ -221,50 +113,88 @@ StaticResource.prototype.write = function(/*String*/ aString)
this._contents += aString;
}
StaticResource.prototype.resolveSubPath = function(/*String*/ aPath, /*BOOL*/ isDirectory, /*Function*/ aCallback)
function rootResourceForAbsoluteURL(/*CFURL*/ anAbsoluteURL)
{
aPath = FILE.normal(aPath);
var schemeAndAuthority = anAbsoluteURL.schemeAndAuthority(),
resource = rootResources[schemeAndAuthority];
if (aPath === "/")
return aCallback(rootResource);
if (!resource)
resource = new StaticResource(schemeAndAuthority, NULL, YES, YES);
if (!FILE.isAbsolute(aPath))
aPath = FILE.join(this.path(), aPath);
var components = FILE.split(aPath),
index = this === rootResource ? 1 : FILE.split(this.path()).length;
resolvePathComponents(this, isDirectory, components, index, aCallback);
return resource;
}
function resolvePathComponents(/*StaticResource*/ startResource, /*BOOL*/ isDirectory, /*Array*/ components, /*Integer*/ index, /*Function*/ aCallback)
function resolveURL(/*CFURL|String*/ aURL)
{
var count = components.length,
parent = startResource;
return new CFURL(aURL, mainBundleURL);
}
function continueResolution()
StaticResource.resourceAtURL = function(/*CFURL*/ aURL, /*BOOL*/ resolveAsDirectoriesIfNecessary)
{
aURL = resolveURL(aURL).absoluteURL();
var resource = rootResourceForAbsoluteURL(aURL),
components = aURL.pathComponents(),
index = 0,
count = components.length;
for (; index < count; ++index)
{
resolvePathComponents(parent, isDirectory, components, index, aCallback);
var name = components[index];
if (hasOwnProperty.call(resource._children, name))
resource = resource._children[name];
else if (resolveAsDirectoriesIfNecessary)
resource = new StaticResource(name, resource, YES, YES);
else
throw new Error("Static Resource at " + aURL + " is not resolved (\"" + name + "\")");
}
return resource;
}
StaticResource.prototype.resourceAtURL = function(/*CFURL|String*/ aURL, /*BOOL*/ resolveAsDirectoriesIfNecessary)
{
return StaticResource.resourceAtURL(new CFURL(aURL, this.URL()), resolveAsDirectoriesIfNecessary);
}
StaticResource.resolveResourceAtURL = function(/*CFURL*/ aURL, /*BOOL*/ isDirectory, /*Function*/ aCallback)
{
aURL = resolveURL(aURL).absoluteURL();
resolveResourceComponents(rootResourceForAbsoluteURL(aURL), isDirectory, aURL.pathComponents(), 0, aCallback);
}
StaticResource.prototype.resolveResourceAtURL = function(/*CFURL|String*/ aURL, /*BOOL*/ isDirectory, /*Function*/ aCallback)
{
StaticResource.resolveResourceAtURL(new CFURL(aURL, this.URL()).absoluteURL(), isDirectory, aCallback);
}
function resolveResourceComponents(/*StaticResource*/ aResource, /*BOOL*/ isDirectory, /*Array*/ components, /*Integer*/ index, /*Function*/ aCallback)
{
var count = components.length;
for (; index < count; ++index)
{
var name = components[index],
child = parent._children[name];
//CPLog(index + " " + components + ":" + (childNode && childNode.isResolved()) + ":");
//CPLog(name + " of " + parentNode.name() + " " + (childNode && childNode.name()));
//CPLog(parentNode._childNodes);
// + "(" + components + ")" + " " + index + "/" + count + ":" + (childNode && childNode.name()) +">" + (childNode ? 1:0) + " " + (childNode && childNode.isResolved()));
child = hasOwnProperty.call(aResource._children, name) && aResource._children[name];
// If the child doesn't exist, create and resolve it.
if (!child)
{
child = new StaticResource(name, parent, index + 1 < count || isDirectory , NO);
child = new StaticResource(name, aResource, index + 1 < count || isDirectory , NO);
child.resolve();
}
// If this resource is still being resolved, just wait and rerun this same method when it's ready.
if (!child.isResolved())
return child.addEventListener("resolve", continueResolution);
return child.addEventListener("resolve", function()
{
// Continue resolving once this is done.
resolveResourceComponents(aResource, isDirectory, components, index, aCallback);
});
// If we've already determined that this file doesn't exist...
if (child.isNotFound())
@@ -274,10 +204,36 @@ function resolvePathComponents(/*StaticResource*/ startResource, /*BOOL*/ isDire
if ((index + 1 < count) && child.isFile())
return aCallback(null, new Error("File is not a directory: " + components.join("/")));
parent = child;
aResource = child;
}
return aCallback(parent);
aCallback(aResource);
}
function resolveResourceAtURLSearchingIncludeURLs(/*CFURL*/ aURL, /*Number*/ anIndex, /*Function*/ aCallback)
{
var includeURLs = StaticResource.includeURLs(),
searchURL = new CFURL(aURL, includeURLs[anIndex]).absoluteURL();
StaticResource.resolveResourceAtURL(searchURL, NO, function(/*StaticResource*/ aStaticResource)
{
if (!aStaticResource)
{
if (anIndex + 1 < includeURLs.length)
resolveResourceAtURLSearchingIncludeURLs(aURL, anIndex + 1, aCallback);
else
aCallback(NULL);
return;
}
aCallback(aStaticResource);
});
}
StaticResource.resolveResourceAtURLSearchingIncludeURLs = function(/*CFURL*/ aURL, /*Function*/ aCallback)
{
resolveResourceAtURLSearchingIncludeURLs(aURL, 0, aCallback);
}
StaticResource.prototype.addEventListener = function(/*String*/ anEventName, /*Function*/ anEventListener)
@@ -310,7 +266,7 @@ StaticResource.prototype.toString = function(/*BOOL*/ includeNotFounds)
if (this.isNotFound())
return "<file not found: " + this.name() + ">";
var string = this.parent() ? this.name() : "/";
var string = this.name();
if (this.isDirectory())
{
@@ -329,61 +285,25 @@ StaticResource.prototype.toString = function(/*BOOL*/ includeNotFounds)
return string;
}
StaticResource.prototype.nodeAtSubPath = function(/*String*/ aPath, /*BOOL*/ shouldResolveAsDirectories)
var includeURLs = NULL;
StaticResource.includeURLs = function()
{
aPath = FILE.normal(aPath);
if (includeURLs)
return includeURLs;
var components = FILE.split(FILE.isAbsolute(aPath) ? aPath : FILE.join(this.path(), aPath)),
index = 1,
count = components.length,
parent = rootResource;
var includeURLs = [];
for (; index < count; ++index)
{
var name = components[index];
if (!global.OBJJ_INCLUDE_PATHS && !global.OBJJ_INCLUDE_URLS)
includeURLs = ["Frameworks", "Frameworks/Debug"];
if (hasOwnProperty.call(parent._children, name))
parent = parent._children[name];
else
includeURLs = (global.OBJJ_INCLUDE_PATHS || []).concat(global.OBJJ_INCLUDE_URLS || []);
else if (shouldResolveAsDirectories)
parent = new StaticResource(name, parent, YES, YES);
var count = includeURLs.length;
else
throw NULL;
}
while (count--)
includeURLs[count] = new CFURL(includeURLs[count]).asDirectoryPathURL();
return parent;
return includeURLs;
}
StaticResource.resolveStandardNodeAtPath = function(/*String*/ aPath, /*Function*/ aCallback)
{
var includePaths = StaticResource.includePaths(),
resolveStandardNodeAtPath = function(/*String*/ aPath, /*int*/ anIndex)
{
var searchPath = FILE.absolute(FILE.join(includePaths[anIndex], FILE.normal(aPath)));
rootResource.resolveSubPath(searchPath, NO, function(/*StaticResource*/ aStaticResource)
{
if (!aStaticResource)
{
if (anIndex + 1< includePaths.length)
resolveStandardNodeAtPath(aPath, anIndex + 1);
else
aCallback(NULL);
return;
}
aCallback(aStaticResource);
});
};
resolveStandardNodeAtPath(aPath, 0);
}
StaticResource.includePaths = function()
{
return global.OBJJ_INCLUDE_PATHS || ["Frameworks", "Frameworks/Debug"];
}
StaticResource.cwd = FILE.cwd();
+63
View File
@@ -0,0 +1,63 @@
@implementation CFURLTest : OJTestCase
{
}
- (void)testRelativeURLs
{
var URLStrings =
{
"g:h" : "g:h",
"g" : "http://a/b/c/g",
"./g" : "http://a/b/c/g",
"g/" : "http://a/b/c/g/",
"/g" : "http://a/g",
//"//g" : "http://g",
"?y" : "http://a/b/c/?y",
"g?y" : "http://a/b/c/g?y",
//"#s" : "(current document)#s",
"g#s" : "http://a/b/c/g#s",
"g?y#s" : "http://a/b/c/g?y#s",
";x" : "http://a/b/c/;x",
"g;x" : "http://a/b/c/g;x",
"g;x?y#s" : "http://a/b/c/g;x?y#s",
"." : "http://a/b/c/",
"./" : "http://a/b/c/",
".." : "http://a/b/",
"../" : "http://a/b/",
"../g" : "http://a/b/g",
"../.." : "http://a/",
"../../" : "http://a/",
"../../g" : "http://a/g",
"../../../g" : "http://a/../g",
"../../../../g" : "http://a/g",//"http://a/../../g",
"/./g" : "http://a/g",//"http://a/./g",
// "/../g" : "http://a/g",//"http://a/../g",
"g." : "http://a/b/c/g.",
".g" : "http://a/b/c/.g",
"g.." : "http://a/b/c/g..",
"..g" : "http://a/b/c/..g",
"./../g" : "http://a/b/g",
"./g/." : "http://a/b/c/g/",
"g/./h" : "http://a/b/c/g/h",
"g/../h" : "http://a/b/c/h",
"g;x=1/./y" : "http://a/b/c/g;x=1/y",
"g;x=1/../y" : "http://a/b/c/y",
"g?y/./x" : "http://a/b/c/g?y/./x",
"g?y/../x" : "http://a/b/c/g?y/../x",
"g#s/./x" : "http://a/b/c/g#s/./x",
"g#s/../x" : "http://a/b/c/g#s/../x"
};
var URLString,
baseURL = new CFURL("http://a/b/c/d;p?q");
for (URLString in URLStrings)
if (URLStrings.hasOwnProperty(URLString))
{
print(URLStrings[URLString] + " " + new CFURL(URLString, baseURL).absoluteString());
[self assert:URLStrings[URLString] equals:new CFURL(URLString, baseURL).absoluteString()];
}
}
@end