--- a/js/src/xpconnect/loader/mozJSComponentLoader.cpp
+++ b/js/src/xpconnect/loader/mozJSComponentLoader.cpp
@@ -67,26 +67,30 @@
#include "nsMemory.h"
#include "nsIObserverService.h"
#include "nsIXPCScriptable.h"
#include "nsString.h"
#ifndef XPCONNECT_STANDALONE
#include "nsIScriptSecurityManager.h"
#include "nsIURI.h"
#include "nsIFileURL.h"
+#include "nsIJARURI.h"
#include "nsNetUtil.h"
#endif
#include "jsxdrapi.h"
#include "jsprf.h"
#include "nsIFastLoadFileControl.h"
// For reporting errors with the console service
#include "nsIScriptError.h"
#include "nsIConsoleService.h"
#include "prmem.h"
#include "plbase64.h"
+#if defined(XP_WIN)
+#include "nsILocalFileWin.h"
+#endif
#if defined(MOZ_SHARK) || defined(MOZ_CALLGRIND) || defined(MOZ_VTUNE) || defined(MOZ_TRACEVIS)
#include "jsdbgapi.h"
#endif
#include "mozilla/FunctionTimer.h"
static const char kJSRuntimeServiceContractID[] = "@mozilla.org/js/xpc/RuntimeService;1";
@@ -655,59 +659,154 @@ mozJSComponentLoader::ReallyInit()
#ifdef DEBUG_shaver_off
fprintf(stderr, "mJCL: ReallyInit success!\n");
#endif
mInitialized = PR_TRUE;
return NS_OK;
}
+nsresult
+mozJSComponentLoader::FileKey(nsILocalFile* aFile, nsAString &aResult)
+{
+ nsresult rv = NS_OK;
+ nsAutoString canonicalPath;
+
+#if defined(XP_WIN)
+ nsCOMPtr<nsILocalFileWin> winFile = do_QueryInterface(aFile, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ winFile->GetCanonicalPath(canonicalPath);
+#else
+ aFile->GetPath(canonicalPath);
+#endif
+
+ aResult = NS_LITERAL_STRING("f");
+ aResult += canonicalPath;
+
+ return rv;
+}
+
+nsresult
+mozJSComponentLoader::JarKey(nsILocalFile* aFile,
+ const nsACString &aComponentPath,
+ nsAString &aResult)
+{
+ nsresult rv = NS_OK;
+ nsAutoString canonicalPath;
+
+#if defined(XP_WIN)
+ nsCOMPtr<nsILocalFileWin> winFile = do_QueryInterface(aFile, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ winFile->GetCanonicalPath(canonicalPath);
+#else
+ aFile->GetPath(canonicalPath);
+#endif
+
+ aResult = NS_LITERAL_STRING("j");
+ aResult += canonicalPath;
+ AppendUTF8toUTF16(aComponentPath, aResult);
+
+ return rv;
+}
+
NS_IMETHODIMP
mozJSComponentLoader::LoadModule(nsILocalFile* aComponentFile,
nsIModule* *aResult)
{
+ nsCOMPtr<nsIURI> uri;
+ nsCAutoString spec;
+ NS_GetURLSpecFromActualFile(aComponentFile, spec);
+
+ nsresult rv = NS_NewURI(getter_AddRefs(uri), spec);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsAutoString hashstring;
+ rv = FileKey(aComponentFile, hashstring);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ return LoadModuleImpl(aComponentFile,
+ hashstring,
+ uri, aResult);
+}
+
+NS_IMETHODIMP
+mozJSComponentLoader::LoadModuleFromJAR(nsILocalFile *aJarFile,
+ const nsACString &aComponentPath,
+ nsIModule* *aResult)
+{
+#if !defined(XPCONNECT_STANDALONE)
+ nsresult rv;
+
+ nsCAutoString fileSpec;
+ NS_GetURLSpecFromActualFile(aJarFile, fileSpec);
+
+ nsCAutoString jarSpec("jar:");
+ jarSpec += fileSpec;
+ jarSpec += "!/";
+ jarSpec += aComponentPath;
+
+ nsCOMPtr<nsIURI> uri;
+ rv = NS_NewURI(getter_AddRefs(uri), jarSpec);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsAutoString hashstring;
+ rv = JarKey(aJarFile, aComponentPath, hashstring);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ return LoadModuleImpl(aJarFile,
+ hashstring,
+ uri, aResult);
+#else
+ return NS_ERROR_NOT_IMPLEMENTED;
+#endif
+}
+
+nsresult
+mozJSComponentLoader::LoadModuleImpl(nsILocalFile* aSourceFile,
+ nsAString &aKey,
+ nsIURI* aComponentURI,
+ nsIModule* *aResult)
+{
nsresult rv;
#ifdef NS_FUNCTION_TIMER
nsAutoString path__(NS_LITERAL_STRING("N/A"));
aComponentFile->GetPath(path__);
NS_TIME_FUNCTION_FMT("%s (line %d) (file: %s)", MOZ_FUNCTION_NAME,
__LINE__, nsPromiseFlatCString(NS_LossyConvertUTF16toASCII(path__)).BeginReading());
#endif
- nsCAutoString leafName;
- aComponentFile->GetNativeLeafName(leafName);
- if (!StringTail(leafName, 3).LowerCaseEqualsLiteral(".js"))
- return NS_ERROR_INVALID_ARG;
-
if (!mInitialized) {
rv = ReallyInit();
if (NS_FAILED(rv))
return rv;
}
- nsCOMPtr<nsIHashable> lfhash(do_QueryInterface(aComponentFile));
- if (!lfhash) {
- NS_ERROR("nsLocalFile not implementing nsIHashable");
- return NS_NOINTERFACE;
- }
+ nsCAutoString uriStr;
+ rv = aComponentURI->GetSpec(uriStr);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (!StringTail(uriStr, 3).LowerCaseEqualsLiteral(".js"))
+ return NS_ERROR_INVALID_ARG;
ModuleEntry* mod;
- if (mModules.Get(lfhash, &mod)) {
+ if (mModules.Get(aKey, &mod)) {
NS_ASSERTION(mod->module, "Bad hashtable data!");
NS_ADDREF(*aResult = mod->module);
return NS_OK;
}
nsAutoPtr<ModuleEntry> entry(new ModuleEntry);
if (!entry)
return NS_ERROR_OUT_OF_MEMORY;
- rv = GlobalForLocation(aComponentFile, &entry->global, &entry->location,
- nsnull);
+ rv = GlobalForLocation(aSourceFile, aComponentURI, &entry->global,
+ &entry->location, nsnull);
if (NS_FAILED(rv)) {
#ifdef DEBUG_shaver
fprintf(stderr, "GlobalForLocation failed!\n");
#endif
return rv;
}
nsCOMPtr<nsIXPConnect> xpc = do_GetService(kXPConnectServiceContractID,
@@ -741,17 +840,17 @@ mozJSComponentLoader::LoadModule(nsILoca
#ifdef DEBUG_shaver
fprintf(stderr, "GetJSObject of ComponentManager failed\n");
#endif
return rv;
}
JSObject* file_jsobj;
nsCOMPtr<nsIXPConnectJSObjectHolder> file_holder;
- rv = xpc->WrapNative(cx, entry->global, aComponentFile,
+ rv = xpc->WrapNative(cx, entry->global, aSourceFile,
NS_GET_IID(nsIFile),
getter_AddRefs(file_holder));
if (NS_FAILED(rv)) {
return rv;
}
rv = file_holder->GetJSObject(&file_jsobj);
@@ -764,21 +863,18 @@ mozJSComponentLoader::LoadModule(nsILoca
jsval argv[2], retval, NSGetModule_val;
if (!JS_GetProperty(cx, entry->global, "NSGetModule", &NSGetModule_val) ||
JSVAL_IS_VOID(NSGetModule_val)) {
return NS_ERROR_FAILURE;
}
if (JS_TypeOfValue(cx, NSGetModule_val) != JSTYPE_FUNCTION) {
- nsCAutoString path;
- aComponentFile->GetNativePath(path);
-
JS_ReportError(cx, "%s has NSGetModule property that is not a function",
- path.get());
+ uriStr.get());
return NS_ERROR_FAILURE;
}
argv[0] = OBJECT_TO_JSVAL(cm_jsobj);
argv[1] = OBJECT_TO_JSVAL(file_jsobj);
if (!JS_CallFunctionValue(cx, entry->global, NSGetModule_val,
2, argv, &retval)) {
return NS_ERROR_FAILURE;
@@ -803,17 +899,17 @@ mozJSComponentLoader::LoadModule(nsILoca
/* XXX report error properly */
#ifdef DEBUG
fprintf(stderr, "mJCL: couldn't get nsIModule from jsval\n");
#endif
return rv;
}
// Cache this module for later
- if (!mModules.Put(lfhash, entry))
+ if (!mModules.Put(aKey, entry))
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(*aResult = entry->module);
// The hash owns the ModuleEntry now, forget about it
entry.forget();
return NS_OK;
@@ -1098,17 +1194,18 @@ mozJSComponentLoader::WriteScript(nsIFas
rv = WriteScriptToStream(cx, script, mFastLoadOutput);
NS_ENSURE_SUCCESS(rv, rv);
return flSvc->EndMuxedDocument(uri);
}
nsresult
-mozJSComponentLoader::GlobalForLocation(nsILocalFile *aComponent,
+mozJSComponentLoader::GlobalForLocation(nsILocalFile *aComponentFile,
+ nsIURI *aURI,
JSObject **aGlobal,
char **aLocation,
jsval *exception)
{
nsresult rv;
JSPrincipals* jsPrincipals = nsnull;
JSCLContextHelper cx(this);
@@ -1145,40 +1242,54 @@ mozJSComponentLoader::GlobalForLocation(
JSObject *global;
rv = holder->GetJSObject(&global);
NS_ENSURE_SUCCESS(rv, rv);
if (!JS_DefineFunctions(cx, global, gGlobalFun)) {
return NS_ERROR_FAILURE;
}
- nsCOMPtr<nsIXPConnectJSObjectHolder> locationHolder;
- rv = xpc->WrapNative(cx, global, aComponent,
- NS_GET_IID(nsILocalFile),
- getter_AddRefs(locationHolder));
- NS_ENSURE_SUCCESS(rv, rv);
+ bool realFile = false;
+ // need to be extra careful checking for URIs pointing to files
+ // EnsureFile may not always get called, especially on resource URIs
+ // so we need to call GetFile to make sure this is a valid file
+ nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(aURI, &rv);
+ nsCOMPtr<nsIFile> testFile;
+ if (NS_SUCCEEDED(rv)) {
+ fileURL->GetFile(getter_AddRefs(testFile));
+ }
+
+ if (testFile) {
+ realFile = true;
- JSObject *locationObj;
- rv = locationHolder->GetJSObject(&locationObj);
- NS_ENSURE_SUCCESS(rv, rv);
+ nsCOMPtr<nsIXPConnectJSObjectHolder> locationHolder;
+ rv = xpc->WrapNative(cx, global, aComponentFile,
+ NS_GET_IID(nsILocalFile),
+ getter_AddRefs(locationHolder));
+ NS_ENSURE_SUCCESS(rv, rv);
- if (!JS_DefineProperty(cx, global, "__LOCATION__",
- OBJECT_TO_JSVAL(locationObj), nsnull, nsnull, 0)) {
- return NS_ERROR_FAILURE;
+ JSObject *locationObj;
+ rv = locationHolder->GetJSObject(&locationObj);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (!JS_DefineProperty(cx, global, "__LOCATION__",
+ OBJECT_TO_JSVAL(locationObj), nsnull, nsnull, 0))
+ return NS_ERROR_FAILURE;
}
nsCAutoString nativePath;
// Quick hack to unbust XPCONNECT_STANDALONE.
// This leaves the jsdebugger with a non-URL pathname in the
// XPCONNECT_STANDALONE case - but at least it builds and runs otherwise.
// See: http://bugzilla.mozilla.org/show_bug.cgi?id=121438
#ifdef XPCONNECT_STANDALONE
localFile->GetNativePath(nativePath);
#else
- NS_GetURLSpecFromActualFile(aComponent, nativePath);
+ rv = aURI->GetSpec(nativePath);
+ NS_ENSURE_SUCCESS(rv, rv);
#endif
// Before compiling the script, first check to see if we have it in
// the fastload file. Note: as a rule, fastload errors are not fatal
// to loading the script, since we can always slow-load.
nsCOMPtr<nsIFastLoadService> flSvc = do_GetFastLoadService(&rv);
// Save the old state and restore it upon return
@@ -1187,24 +1298,20 @@ mozJSComponentLoader::GlobalForLocation(
if (NS_SUCCEEDED(rv)) {
rv = StartFastLoad(flSvc);
if (NS_SUCCEEDED(rv)) {
fastLoading = PR_TRUE;
}
}
- nsCOMPtr<nsIURI> uri;
- rv = NS_NewURI(getter_AddRefs(uri), nativePath);
- NS_ENSURE_SUCCESS(rv, rv);
-
JSScript *script = nsnull;
if (fastLoading) {
- rv = ReadScript(flSvc, nativePath.get(), uri, cx, &script);
+ rv = ReadScript(flSvc, nativePath.get(), aURI, cx, &script);
if (NS_SUCCEEDED(rv)) {
LOG(("Successfully loaded %s from fastload\n", nativePath.get()));
fastLoading = PR_FALSE; // no need to write out the script
} else if (rv == NS_ERROR_NOT_AVAILABLE) {
// This is ok, it just means the script is not yet in the
// fastload file.
rv = NS_OK;
} else {
@@ -1240,90 +1347,126 @@ mozJSComponentLoader::GlobalForLocation(
// any exceptions out to our caller. Ensure that the engine doesn't
// eagerly report the exception.
uint32 oldopts = 0;
if (exception) {
oldopts = JS_GetOptions(cx);
JS_SetOptions(cx, oldopts | JSOPTION_DONT_REPORT_UNCAUGHT);
}
+ if (realFile) {
#ifdef HAVE_PR_MEMMAP
- PRInt64 fileSize;
- rv = aComponent->GetFileSize(&fileSize);
- if (NS_FAILED(rv)) {
- JS_SetOptions(cx, oldopts);
- return rv;
- }
+ PRInt64 fileSize;
+ rv = aComponentFile->GetFileSize(&fileSize);
+ if (NS_FAILED(rv)) {
+ JS_SetOptions(cx, oldopts);
+ return rv;
+ }
- PRInt64 maxSize;
- LL_UI2L(maxSize, PR_UINT32_MAX);
- if (LL_CMP(fileSize, >, maxSize)) {
- NS_ERROR("file too large");
- JS_SetOptions(cx, oldopts);
- return NS_ERROR_FAILURE;
- }
+ PRInt64 maxSize;
+ LL_UI2L(maxSize, PR_UINT32_MAX);
+ if (LL_CMP(fileSize, >, maxSize)) {
+ NS_ERROR("file too large");
+ JS_SetOptions(cx, oldopts);
+ return NS_ERROR_FAILURE;
+ }
- PRFileDesc *fileHandle;
- rv = aComponent->OpenNSPRFileDesc(PR_RDONLY, 0, &fileHandle);
- if (NS_FAILED(rv)) {
- JS_SetOptions(cx, oldopts);
- return NS_ERROR_FILE_NOT_FOUND;
- }
+ PRFileDesc *fileHandle;
+ rv = aComponentFile->OpenNSPRFileDesc(PR_RDONLY, 0, &fileHandle);
+ if (NS_FAILED(rv)) {
+ JS_SetOptions(cx, oldopts);
+ return NS_ERROR_FILE_NOT_FOUND;
+ }
- // Make sure the file is closed, no matter how we return.
- FileAutoCloser fileCloser(fileHandle);
+ // Make sure the file is closed, no matter how we return.
+ FileAutoCloser fileCloser(fileHandle);
- PRFileMap *map = PR_CreateFileMap(fileHandle, fileSize,
- PR_PROT_READONLY);
- if (!map) {
- NS_ERROR("Failed to create file map");
- JS_SetOptions(cx, oldopts);
- return NS_ERROR_FAILURE;
- }
+ PRFileMap *map = PR_CreateFileMap(fileHandle, fileSize,
+ PR_PROT_READONLY);
+ if (!map) {
+ NS_ERROR("Failed to create file map");
+ JS_SetOptions(cx, oldopts);
+ return NS_ERROR_FAILURE;
+ }
- // Make sure the file map is closed, no matter how we return.
- FileMapAutoCloser mapCloser(map);
+ // Make sure the file map is closed, no matter how we return.
+ FileMapAutoCloser mapCloser(map);
- PRUint32 fileSize32;
- LL_L2UI(fileSize32, fileSize);
+ PRUint32 fileSize32;
+ LL_L2UI(fileSize32, fileSize);
- char *buf = static_cast<char*>(PR_MemMap(map, 0, fileSize32));
- if (!buf) {
- NS_WARNING("Failed to map file");
- JS_SetOptions(cx, oldopts);
- return NS_ERROR_FAILURE;
- }
+ char *buf = static_cast<char*>(PR_MemMap(map, 0, fileSize32));
+ if (!buf) {
+ NS_WARNING("Failed to map file");
+ JS_SetOptions(cx, oldopts);
+ return NS_ERROR_FAILURE;
+ }
- script = JS_CompileScriptForPrincipals(cx, global,
- jsPrincipals,
- buf, fileSize32,
- nativePath.get(), 1);
- PR_MemUnmap(buf, fileSize32);
+ script = JS_CompileScriptForPrincipals(cx, global,
+ jsPrincipals,
+ buf, fileSize32,
+ nativePath.get(), 1);
+ PR_MemUnmap(buf, fileSize32);
#else /* HAVE_PR_MEMMAP */
- /**
- * No memmap implementation, so fall back to using
- * JS_CompileFileHandleForPrincipals().
- */
+ /**
+ * No memmap implementation, so fall back to using
+ * JS_CompileFileHandleForPrincipals().
+ */
+
+ FILE *fileHandle;
+ rv = aComponentFile->OpenANSIFileDesc("r", &fileHandle);
+ if (NS_FAILED(rv)) {
+ JS_SetOptions(cx, oldopts);
+ return NS_ERROR_FILE_NOT_FOUND;
+ }
+
+ script = JS_CompileFileHandleForPrincipals(cx, global,
+ nativePath.get(),
+ fileHandle, jsPrincipals);
+
+ /* JS will close the filehandle after compilation is complete. */
+#endif /* HAVE_PR_MEMMAP */
+ } else {
+ nsCOMPtr<nsIIOService> ioService = do_GetIOService(&rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsIChannel> scriptChannel;
+ rv = ioService->NewChannelFromURI(aURI, getter_AddRefs(scriptChannel));
+ NS_ENSURE_SUCCESS(rv, rv);
- FILE *fileHandle;
- rv = aComponent->OpenANSIFileDesc("r", &fileHandle);
- if (NS_FAILED(rv)) {
- JS_SetOptions(cx, oldopts);
- return NS_ERROR_FILE_NOT_FOUND;
- }
+ nsCOMPtr<nsIInputStream> scriptStream;
+ rv = scriptChannel->Open(getter_AddRefs(scriptStream));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ PRUint32 len, bytesRead;
+
+ rv = scriptStream->Available(&len);
+ NS_ENSURE_SUCCESS(rv, rv);
+ if (!len)
+ return NS_ERROR_FAILURE;
- script = JS_CompileFileHandleForPrincipals(cx, global,
- nativePath.get(),
- fileHandle, jsPrincipals);
+ /* malloc an internal buf the size of the file */
+ nsAutoArrayPtr<char> buf(new char[len + 1]);
+ if (!buf)
+ return NS_ERROR_OUT_OF_MEMORY;
- /* JS will close the filehandle after compilation is complete. */
-#endif /* HAVE_PR_MEMMAP */
+ /* read the file in one swoop */
+ rv = scriptStream->Read(buf, len, &bytesRead);
+ if (bytesRead != len)
+ return NS_BASE_STREAM_OSERROR;
+ buf[len] = '\0';
+
+ script = JS_CompileScriptForPrincipals(cx, global,
+ jsPrincipals,
+ buf, bytesRead,
+ nativePath.get(), 1);
+ }
// Propagate the exception, if one exists. Also, don't leave the stale
// exception on this context.
// NB: The caller must stick exception into a rooted slot (probably on
// its context) as soon as possible to avoid GC hazards.
if (exception) {
JS_SetOptions(cx, oldopts);
if (!script) {
JS_GetPendingException(cx, exception);
@@ -1353,17 +1496,17 @@ mozJSComponentLoader::GlobalForLocation(
#ifdef DEBUG_shaver_off
fprintf(stderr, "mJCL: compiled JS component %s\n",
nativePath.get());
#endif
if (fastLoading) {
// We successfully compiled the script, so cache it in fastload.
- rv = WriteScript(flSvc, script, aComponent, nativePath.get(), uri, cx);
+ rv = WriteScript(flSvc, script, aComponentFile, nativePath.get(), aURI, cx);
// Don't treat failure to write as fatal, since we might be working
// with a read-only fastload file.
if (NS_SUCCEEDED(rv)) {
LOG(("Successfully wrote to fastload\n"));
} else {
LOG(("Failed to write to fastload\n"));
}
@@ -1381,19 +1524,17 @@ mozJSComponentLoader::GlobalForLocation(
#ifdef DEBUG_shaver_off
fprintf(stderr, "mJCL: failed to execute %s\n", nativePath.get());
#endif
*aGlobal = nsnull;
return NS_ERROR_FAILURE;
}
/* Freed when we remove from the table. */
- nsCAutoString path;
- aComponent->GetNativePath(path);
- *aLocation = ToNewCString(path);
+ *aLocation = ToNewCString(nativePath);
if (!*aLocation) {
*aGlobal = nsnull;
return NS_ERROR_OUT_OF_MEMORY;
}
JS_AddNamedRoot(cx, aGlobal, *aLocation);
return NS_OK;
}
@@ -1525,45 +1666,75 @@ mozJSComponentLoader::ImportInto(const n
}
nsCOMPtr<nsIIOService> ioService = do_GetIOService(&rv);
NS_ENSURE_SUCCESS(rv, rv);
// Get the URI.
nsCOMPtr<nsIURI> resURI;
rv = ioService->NewURI(aLocation, nsnull, nsnull, getter_AddRefs(resURI));
- nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(resURI, &rv);
- // If we don't have a file URL, then the location passed in is invalid.
- NS_ENSURE_SUCCESS(rv, NS_ERROR_INVALID_ARG);
+ NS_ENSURE_SUCCESS(rv, rv);
- // Get the file belonging to it.
- nsCOMPtr<nsIFile> file;
- rv = fileURL->GetFile(getter_AddRefs(file));
+ // figure out the resolved URI
+ nsCOMPtr<nsIChannel> scriptChannel;
+ rv = ioService->NewChannelFromURI(resURI, getter_AddRefs(scriptChannel));
NS_ENSURE_SUCCESS(rv, rv);
- nsCOMPtr<nsILocalFile> componentFile = do_QueryInterface(file, &rv);
+
+ nsCOMPtr<nsIURI> resolvedURI;
+ rv = scriptChannel->GetURI(getter_AddRefs(resolvedURI));
NS_ENSURE_SUCCESS(rv, rv);
- nsCOMPtr<nsIHashable> lfhash(do_QueryInterface(componentFile));
- if (!lfhash) {
- NS_ERROR("nsLocalFile not implementing nsIHashable");
- return NS_NOINTERFACE;
+ // get the JAR if there is one
+ nsCOMPtr<nsIJARURI> jarURI;
+ jarURI = do_QueryInterface(resolvedURI, &rv);
+ nsCOMPtr<nsIFileURL> baseFileURL;
+ nsCAutoString jarEntry;
+ if (NS_SUCCEEDED(rv)) {
+ nsCOMPtr<nsIURI> baseURI;
+ rv = jarURI->GetJARFile(getter_AddRefs(baseURI));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ baseFileURL = do_QueryInterface(baseURI, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ jarURI->GetJAREntry(jarEntry);
+ NS_ENSURE_SUCCESS(rv, rv);
+ } else {
+ baseFileURL = do_QueryInterface(resolvedURI, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
}
+ nsCOMPtr<nsIFile> sourceFile;
+ rv = baseFileURL->GetFile(getter_AddRefs(sourceFile));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsILocalFile> sourceLocalFile;
+ sourceLocalFile = do_QueryInterface(sourceFile, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsAutoString key;
+ if (jarEntry.IsEmpty()) {
+ rv = FileKey(sourceLocalFile, key);
+ } else {
+ rv = JarKey(sourceLocalFile, jarEntry, key);
+ }
+ NS_ENSURE_SUCCESS(rv, rv);
+
ModuleEntry* mod;
nsAutoPtr<ModuleEntry> newEntry;
- if (!mImports.Get(lfhash, &mod) && !mInProgressImports.Get(lfhash, &mod)) {
+ if (!mImports.Get(key, &mod) && !mInProgressImports.Get(key, &mod)) {
newEntry = new ModuleEntry;
- if (!newEntry || !mInProgressImports.Put(lfhash, newEntry))
+ if (!newEntry || !mInProgressImports.Put(key, newEntry))
return NS_ERROR_OUT_OF_MEMORY;
jsval exception = JSVAL_VOID;
- rv = GlobalForLocation(componentFile, &newEntry->global,
+ rv = GlobalForLocation(sourceLocalFile, resURI, &newEntry->global,
&newEntry->location, &exception);
- mInProgressImports.Remove(lfhash);
+ mInProgressImports.Remove(key);
if (NS_FAILED(rv)) {
*_retval = nsnull;
if (!JSVAL_IS_VOID(exception)) {
// An exception was thrown during compilation. Propagate it
// out to our caller so they can report it.
JSContext *callercx;
@@ -1647,17 +1818,17 @@ mozJSComponentLoader::ImportInto(const n
PromiseFlatCString(aLocation).get()));
}
#endif
}
}
// Cache this module for later
if (newEntry) {
- if (!mImports.Put(lfhash, newEntry))
+ if (!mImports.Put(key, newEntry))
return NS_ERROR_OUT_OF_MEMORY;
newEntry.forget();
}
return NS_OK;
}
NS_IMETHODIMP
--- a/xpcom/components/nsComponentManager.cpp
+++ b/xpcom/components/nsComponentManager.cpp
@@ -95,16 +95,22 @@
#include NEW_H // for placement new
#ifdef XP_BEOS
#include <FindDirectory.h>
#include <Path.h>
#endif
+#ifdef MOZ_OMNIJAR
+#include "nsIZipReader.h"
+#include "mozilla/Omnijar.h"
+static NS_DEFINE_CID(kZipReaderCID, NS_ZIPREADER_CID);
+#endif
+
#include "prlog.h"
NS_COM PRLogModuleInfo* nsComponentManagerLog = nsnull;
#if 0 || defined (DEBUG_timeless)
#define SHOW_DENIED_ON_SHUTDOWN
#define SHOW_CI_ON_EXISTING_SERVICE
#endif
@@ -127,16 +133,17 @@ const char classNameValueName[]="ClassNa
const char componentCountValueName[]="ComponentsCount";
const char componentTypeValueName[]="ComponentType";
const char contractIDValueName[]="ContractID";
const char fileSizeValueName[]="FileSize";
const char inprocServerValueName[]="InprocServer";
const char lastModValueName[]="LastModTimeStamp";
const char nativeComponentType[]="application/x-mozilla-native";
const char staticComponentType[]="application/x-mozilla-static";
+const char jarComponentType[]="application/x-mozilla-jarjs";
const char versionValueName[]="VersionString";
const static char XPCOM_ABSCOMPONENT_PREFIX[] = "abs:";
const static char XPCOM_RELCOMPONENT_PREFIX[] = "rel:";
const static char XPCOM_GRECOMPONENT_PREFIX[] = "gre:";
static const char gIDFormat[] =
"{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}";
@@ -174,16 +181,18 @@ static void GetIDString(const nsID& aCID
#define COMPMGR_TIME_FUNCTION_CONTRACTID(cid) \
NS_TIME_FUNCTION_MIN_FMT(5, "%s (line %d) (contractid: %s)", MOZ_FUNCTION_NAME, \
__LINE__, (cid))
#else
#define COMPMGR_TIME_FUNCTION_CID(cid) do {} while (0)
#define COMPMGR_TIME_FUNCTION_CONTRACTID(cid) do {} while (0)
#endif
+#define kOMNIJAR_PREFIX NS_LITERAL_CSTRING("resource:///")
+
nsresult
nsGetServiceFromCategory::operator()(const nsIID& aIID, void** aInstancePtr) const
{
nsresult rv;
nsXPIDLCString value;
nsCOMPtr<nsICategoryManager> catman;
nsComponentManagerImpl *compMgr = nsComponentManagerImpl::gComponentManager;
if (!compMgr) {
@@ -1164,16 +1173,20 @@ ClassIDWriter(PLDHashTable *table,
case NS_LOADER_TYPE_STATIC:
loaderName = staticComponentType;
break;
case NS_LOADER_TYPE_NATIVE:
loaderName = nativeComponentType;
break;
+ case NS_LOADER_TYPE_JAR:
+ loaderName = jarComponentType;
+ break;
+
default:
loaderName = loaderData->ElementAt(factoryEntry->mLoaderType).type.get();
}
const char* location = factoryEntry->mLocationKey;
// cid,contract_id,type,class_name,inproc_server
PR_fprintf(fd,
@@ -2747,16 +2760,19 @@ nsComponentManagerImpl::LoaderForType(Lo
"Static component loader is special");
if (aType == NS_LOADER_TYPE_INVALID)
return nsnull;
if (aType == NS_LOADER_TYPE_NATIVE)
return &mNativeModuleLoader;
+ if (aType == NS_LOADER_TYPE_JAR)
+ return nsnull;
+
NS_ASSERTION(aType >= 0 && PRUint32(aType) < mLoaderData.Length(),
"LoaderType out of range");
if (!mLoaderData[aType].loader) {
nsCOMPtr<nsIModuleLoader> loader;
loader = do_GetServiceFromCategory("module-loader",
mLoaderData[aType].type.get());
if (!loader)
@@ -2805,16 +2821,19 @@ nsComponentManagerImpl::GetLoaderType(co
}
if (!strcmp(typeStr, staticComponentType))
return NS_LOADER_TYPE_STATIC;
if (!strcmp(typeStr, nativeComponentType))
return NS_LOADER_TYPE_NATIVE;
+ if (!strcmp(typeStr, jarComponentType))
+ return NS_LOADER_TYPE_JAR;
+
const nsDependentCString type(typeStr);
for (unsigned int i = 0; i < mLoaderData.Length(); ++i) {
if (mLoaderData[i].type == type)
return i;
}
return NS_LOADER_TYPE_INVALID;
@@ -3388,16 +3407,116 @@ nsComponentManagerImpl::EnumerateContrac
return rv;
*aEnumerator = static_cast<nsIEnumerator*>(aEnum);
return NS_OK;
}
// nsIComponentRegistrar
+#ifdef MOZ_OMNIJAR
+void
+nsComponentManagerImpl::AutoRegisterJar()
+{
+ nsresult rv;
+ nsCOMPtr<nsIZipReader> jarReader = do_CreateInstance(kZipReaderCID, &rv);
+ if (NS_FAILED(rv)) {
+ NS_ERROR("could not get jar reader");
+ return;
+ }
+
+ nsIModuleLoader *jsLoader = LoaderForType(GetLoaderType("text/javascript"));
+ if (!jsLoader) {
+ NS_ERROR("could not get JS loader");
+ return;
+ }
+
+ nsCOMPtr<nsILocalFile> omniJar(mozilla::OmnijarPath());
+ if (!omniJar) {
+ return;
+ }
+
+ rv = jarReader->Open(omniJar);
+ if (NS_FAILED(rv)) {
+ NS_ERROR("Failed to open omniJar");
+ return;
+ }
+
+ nsCOMPtr<nsIUTF8StringEnumerator> compEnum;
+ rv = jarReader->FindEntries("components/*.js$",
+ getter_AddRefs(compEnum));
+ if (NS_FAILED(rv)) {
+ NS_ERROR("Failed to get js enumerator for omniJar");
+ return;
+ }
+
+ nsTArray<DeferredModule> deferred;
+
+ nsCAutoString compName;
+ PRBool more;
+ while (NS_SUCCEEDED((rv = compEnum->HasMore(&more))) && more) {
+ rv = compEnum->GetNext(compName);
+ if (NS_FAILED(rv)) {
+ NS_ERROR("Failed to get name from js enumerator");
+ continue;
+ }
+
+ nsCAutoString entryspec(kOMNIJAR_PREFIX);
+ entryspec += compName;
+
+ nsCOMPtr<nsIModule> module;
+ rv = jsLoader->LoadModuleFromJAR(omniJar, compName, getter_AddRefs(module));
+ if (NS_FAILED(rv)) {
+ NS_ERROR("Failed to load JS component from JAR");
+ continue;
+ }
+
+ nsCOMPtr<nsIFile> fakeFile;
+ rv = omniJar->Clone(getter_AddRefs(fakeFile));
+ if (NS_FAILED(rv)) {
+ NS_ERROR("Failed to clone fake local file for JS component");
+ continue;
+ }
+
+ nsCOMPtr<nsILocalFile> fakeNativeFile = do_QueryInterface(fakeFile);
+
+ PRInt32 startIdx = compName.RFindChar('/') + 1;
+ rv = fakeNativeFile->AppendNative(Substring(compName, startIdx));
+ if (NS_FAILED(rv)) {
+ NS_ERROR("Failed to create fake local file for JS component");
+ continue;
+ }
+
+ rv = module->RegisterSelf(this, fakeNativeFile,
+ entryspec.get(),
+ jarComponentType);
+ if (NS_ERROR_FACTORY_REGISTER_AGAIN == rv) {
+ DeferredModule *d = deferred.AppendElement();
+ if (!d) {
+ NS_ERROR("Failed to allocate DeferredModule");
+ continue;
+ }
+
+ d->file = fakeNativeFile;
+ d->location = entryspec;
+ d->module = module;
+ }
+ }
+
+ for (PRInt32 i = 0; i < deferred.Length(); i++) {
+ DeferredModule &d = deferred[i];
+ rv = d.module->RegisterSelf(this, d.file,
+ d.location.get(),
+ jarComponentType);
+ if (NS_FAILED(rv))
+ NS_ERROR("js component failed to load on reregistration");
+ }
+}
+#endif /* MOZ_OMNIJAR */
+
static void
RegisterStaticModule(const char *key, nsIModule* module,
nsTArray<DeferredModule> &deferred)
{
nsresult rv = module->
RegisterSelf(nsComponentManagerImpl::gComponentManager,
nsnull, key, staticComponentType);
@@ -3445,16 +3564,20 @@ nsComponentManagerImpl::AutoRegister(nsI
if (!aSpec) {
mStaticModuleLoader.EnumerateModules(RegisterStaticModule,
deferred);
// Builtin component loaders (xpconnect!) can be static modules.
// Set them up now, so that JS components don't go into
// the leftovers list.
GetAllLoaders();
+
+#ifdef MOZ_OMNIJAR
+ AutoRegisterJar();
+#endif
}
LoaderType curLoader = GetLoaderCount();
if (aSpec) {
rv = AutoRegisterImpl(aSpec, leftovers, deferred);
}
else {
@@ -3731,16 +3854,53 @@ nsFactoryEntry::GetFactory(nsIFactory **
nsCOMPtr<nsIModule> module;
if (mLoaderType == NS_LOADER_TYPE_STATIC) {
rv = nsComponentManagerImpl::gComponentManager->
mStaticModuleLoader.
GetModuleFor(mLocationKey,
getter_AddRefs(module));
}
+ else if (mLoaderType == NS_LOADER_TYPE_JAR) {
+ nsComponentManagerImpl::gComponentManager->GetAllLoaders();
+
+ nsIModuleLoader *jsLoader =
+ nsComponentManagerImpl::gComponentManager->
+ LoaderForType(nsComponentManagerImpl::gComponentManager->
+ GetLoaderType("text/javascript"));
+ if (!jsLoader) {
+ NS_ERROR("could not get JS loader");
+ NS_ERROR(mLocationKey);
+ return NS_ERROR_FAILURE;
+ }
+
+ // currently we assume all NS_LOADER_TYPE_JAR cases point to
+ // entries in the omnijar.
+#ifdef MOZ_OMNIJAR
+ nsCOMPtr<nsILocalFile> omniJar(mozilla::OmnijarPath());
+ if (!omniJar) {
+ NS_ERROR("could not get omnijar");
+ return NS_ERROR_FAILURE;
+ }
+
+ if (strlen(mLocationKey) < kOMNIJAR_PREFIX.Length()) {
+ NS_ERROR("invalid mLocationKey");
+ return NS_ERROR_FAILURE;
+ }
+
+ rv = jsLoader->LoadModuleFromJAR(omniJar,
+ nsDependentCSubstring(nsDependentCString(mLocationKey), kOMNIJAR_PREFIX.Length()),
+ getter_AddRefs(module));
+ if (NS_FAILED(rv))
+ NS_ERROR("Failed to load JS component from JAR");
+#else
+ NS_ERROR("Omnijar not enabled");
+ return NS_ERROR_FAILURE;
+#endif
+ }
else {
nsCOMPtr<nsILocalFile> moduleFile;
rv = nsComponentManagerImpl::gComponentManager->
FileForRegistryLocation(nsDependentCString(mLocationKey),
getter_AddRefs(moduleFile));
NS_ENSURE_SUCCESS(rv, rv);
nsIModuleLoader* loader =