mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 492008: Drop support for contents.rdf chrome registrations. r=bsmedberg, r=robstrong
This commit is contained in:
parent
9d02a47048
commit
bc0b863ee6
@ -41,33 +41,9 @@
|
||||
interface nsIURI;
|
||||
interface nsIUTF8StringEnumerator;
|
||||
|
||||
[scriptable, uuid(94490b3f-f094-418e-b1b9-73878d29bff3)]
|
||||
[scriptable, uuid(8727651c-9530-45a0-b81e-0e0690c30c50)]
|
||||
interface nsIToolkitChromeRegistry : nsIXULChromeRegistry
|
||||
{
|
||||
/**
|
||||
* The "canonical" manifest is a plaintext file which sits outside of a
|
||||
* JAR file. To provide backwards-compatibility with contents.rdf, we provide
|
||||
* this function which reads a contents.rdf manifest and writes it to a file.
|
||||
*
|
||||
* @param aOldManifestURI The URI of an old manifest to read, without
|
||||
* the trailing "contents.rdf", e.g.
|
||||
* "jar:resource:///chrome/foo.jar!/content/foo/" or
|
||||
* "file://path/to/contents/rdf/"
|
||||
* @param aFile The URI of a manifest file to write. It's a good
|
||||
* idea to use a resource: URI if possible.
|
||||
* @param aBaseURI The base URI for relative path creation
|
||||
* "jar:resource:///chrome/foo.jar!/content/foo/"
|
||||
* this is a separate param from aOldManifestURI so
|
||||
* the "contents.rdf" can be read outside of the jar
|
||||
* to keep the zipreader cache from holding it open.
|
||||
* @param aAppend Whether we should append to an existing manifest
|
||||
* or truncate and start empty.
|
||||
* @param aSkinOnly Only allow skin packages.
|
||||
*/
|
||||
void processContentsManifest(in nsIURI aOldManifestURI, in nsIURI aFile,
|
||||
in nsIURI aBaseURI, in boolean aAppend,
|
||||
in boolean aSkinOnly);
|
||||
|
||||
/**
|
||||
* If the OS has a "high-visibility" or "disabled-friendly" theme set,
|
||||
* we want to force mozilla into the classic theme, which (for the most part
|
||||
|
@ -115,29 +115,6 @@
|
||||
#include "nsIXULRuntime.h"
|
||||
#include "nsPresShellIterator.h"
|
||||
|
||||
#ifdef MOZ_XUL
|
||||
// keep all the RDF stuff together, in case we can remove it in the far future
|
||||
#include "rdf.h"
|
||||
#include "nsRDFCID.h"
|
||||
#include "nsIRDFService.h"
|
||||
#include "nsIRDFDataSource.h"
|
||||
#include "nsIRDFObserver.h"
|
||||
#include "nsIRDFRemoteDataSource.h"
|
||||
#include "nsIRDFXMLSink.h"
|
||||
#include "nsIRDFResource.h"
|
||||
#include "nsIRDFDataSource.h"
|
||||
#include "nsIRDFContainer.h"
|
||||
#include "nsIRDFContainerUtils.h"
|
||||
|
||||
#define CHROME_URI "http://www.mozilla.org/rdf/chrome#"
|
||||
|
||||
DEFINE_RDF_VOCAB(CHROME_URI, CHROME, packages);
|
||||
DEFINE_RDF_VOCAB(CHROME_URI, CHROME, package);
|
||||
DEFINE_RDF_VOCAB(CHROME_URI, CHROME, name);
|
||||
DEFINE_RDF_VOCAB(CHROME_URI, CHROME, platformPackage);
|
||||
|
||||
#endif
|
||||
|
||||
#define UILOCALE_CMD_LINE_ARG "UILocale"
|
||||
|
||||
#define MATCH_OS_LOCALE_PREF "intl.locale.matchOS"
|
||||
@ -485,21 +462,6 @@ nsChromeRegistry::Init()
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
// these atoms appear in almost every chrome registry contents.rdf
|
||||
// in some form or another. making static atoms prevents the atoms
|
||||
// from constantly being created/destroyed during parsing
|
||||
|
||||
static const nsStaticAtom atoms[] = {
|
||||
{ "chrome", nsnull },
|
||||
{ "NC", nsnull },
|
||||
{ "allowScripts", nsnull },
|
||||
{ "package", nsnull },
|
||||
{ "packages", nsnull },
|
||||
{ "hasOverlays", nsnull },
|
||||
};
|
||||
|
||||
NS_RegisterStaticAtoms(atoms, NS_ARRAY_LENGTH(atoms));
|
||||
|
||||
// Check to see if necko and the JAR protocol handler are registered yet
|
||||
// if not, somebody is doing work during XPCOM registration that they
|
||||
// shouldn't be doing. See bug 292549, where JS components are trying
|
||||
@ -1197,10 +1159,6 @@ nsChromeRegistry::CheckForNewChrome()
|
||||
rv = NS_NewURI(getter_AddRefs(manifestURI),
|
||||
NS_LITERAL_CSTRING("resource:///chrome/app-chrome.manifest"));
|
||||
|
||||
// this is the main manifest; if it doesn't exist we generate it from
|
||||
// installed-chrome.txt. When the build system learns about the new system,
|
||||
// this code can go away.
|
||||
|
||||
nsCOMPtr<nsIFileURL> manifestFileURL (do_QueryInterface(manifestURI));
|
||||
NS_ASSERTION(manifestFileURL, "Not a nsIFileURL!");
|
||||
NS_ENSURE_TRUE(manifestFileURL, NS_ERROR_UNEXPECTED);
|
||||
@ -1213,35 +1171,6 @@ nsChromeRegistry::CheckForNewChrome()
|
||||
rv = manifest->Exists(&exists);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
#ifdef DEBUG
|
||||
// In debug builds, installed-chrome.txt may change during development;
|
||||
// we just rebuild it every time because we're not worried about startup
|
||||
// time or other bad/goodness.
|
||||
if (exists) {
|
||||
manifest->Remove(PR_FALSE);
|
||||
exists = PR_FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!exists) {
|
||||
nsCOMPtr<nsIFile> installed;
|
||||
manifest->Clone(getter_AddRefs(installed));
|
||||
if (!installed)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
nsCOMPtr<nsILocalFile> linstalled (do_QueryInterface(installed));
|
||||
NS_ENSURE_TRUE(linstalled, NS_NOINTERFACE);
|
||||
|
||||
linstalled->SetNativeLeafName(NS_LITERAL_CSTRING("installed-chrome.txt"));
|
||||
|
||||
rv = linstalled->Exists(&exists);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// process installed-chrome.txt into app-chrome.manifest
|
||||
if (exists)
|
||||
ProcessNewChromeFile(linstalled, manifestURI);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIProperties> dirSvc (do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID));
|
||||
NS_ENSURE_TRUE(dirSvc, NS_ERROR_FAILURE);
|
||||
|
||||
@ -1358,125 +1287,6 @@ nsChromeRegistry::WrappersEnabled(nsIURI *aURI)
|
||||
entry->flags & PackageEntry::XPCNATIVEWRAPPERS;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsChromeRegistry::ProcessNewChromeFile(nsILocalFile *aListFile, nsIURI* aManifest)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
PRFileDesc *file;
|
||||
rv = aListFile->OpenNSPRFileDesc(PR_RDONLY, 0, &file);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PRInt32 n, size;
|
||||
char *buf;
|
||||
|
||||
size = PR_Available(file);
|
||||
if (size == -1) {
|
||||
rv = NS_ERROR_UNEXPECTED;
|
||||
goto end;
|
||||
}
|
||||
|
||||
buf = (char *) malloc(size + 1);
|
||||
if (!buf) {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
goto end;
|
||||
}
|
||||
|
||||
n = PR_Read(file, buf, size);
|
||||
if (n > 0)
|
||||
rv = ProcessNewChromeBuffer(buf, size, aManifest);
|
||||
free(buf);
|
||||
|
||||
end:
|
||||
PR_Close(file);
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsChromeRegistry::ProcessNewChromeBuffer(char *aBuffer, PRInt32 aLength,
|
||||
nsIURI* aManifest)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
char *bufferEnd = aBuffer + aLength;
|
||||
char *chromeType, // "content", "locale" or "skin"
|
||||
*chromeProfile, // "install" or "profile"
|
||||
*chromeLocType, // type of location (local path or URL)
|
||||
*chromeLocation; // base location of chrome (jar file)
|
||||
|
||||
nsCOMPtr<nsIURI> baseURI;
|
||||
|
||||
// process chromeType, chromeProfile, chromeLocType, chromeLocation
|
||||
while (aBuffer < bufferEnd) {
|
||||
// parse one line of installed-chrome.txt
|
||||
chromeType = aBuffer;
|
||||
while (aBuffer < bufferEnd && *aBuffer != ',')
|
||||
++aBuffer;
|
||||
*aBuffer = '\0';
|
||||
|
||||
chromeProfile = ++aBuffer;
|
||||
if (aBuffer >= bufferEnd)
|
||||
break;
|
||||
|
||||
while (aBuffer < bufferEnd && *aBuffer != ',')
|
||||
++aBuffer;
|
||||
*aBuffer = '\0';
|
||||
|
||||
chromeLocType = ++aBuffer;
|
||||
if (aBuffer >= bufferEnd)
|
||||
break;
|
||||
|
||||
while (aBuffer < bufferEnd && *aBuffer != ',')
|
||||
++aBuffer;
|
||||
*aBuffer = '\0';
|
||||
|
||||
chromeLocation = ++aBuffer;
|
||||
if (aBuffer >= bufferEnd)
|
||||
break;
|
||||
|
||||
while (aBuffer < bufferEnd &&
|
||||
(*aBuffer != '\r' && *aBuffer != '\n' && *aBuffer != ' '))
|
||||
++aBuffer;
|
||||
*aBuffer = '\0';
|
||||
|
||||
// process the line
|
||||
// We don't do skin or locale selection from installed-chrome.txt since
|
||||
// ffox 0.9. Just ignore the "select" lines.
|
||||
if (strcmp(chromeLocType,"select")) {
|
||||
if (!strcmp(chromeLocType, "path")) {
|
||||
// location is a (full) path. convert it to an URL.
|
||||
|
||||
/* this is some convoluted shit... this creates a file, inits it with
|
||||
* the path parsed above (chromeLocation), makes a url, and inits it
|
||||
* with the file created. the purpose of this is just to have the
|
||||
* canonical url of the stupid thing.
|
||||
*/
|
||||
nsCOMPtr<nsILocalFile> chromeFile;
|
||||
rv = NS_NewNativeLocalFile(nsDependentCString(chromeLocation),
|
||||
PR_TRUE, getter_AddRefs(chromeFile));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
/*
|
||||
* all we want here is the canonical url
|
||||
*/
|
||||
rv = NS_NewFileURI(getter_AddRefs(baseURI), chromeFile);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
else {
|
||||
rv = NS_NewURI(getter_AddRefs(baseURI), chromeLocation);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
ProcessContentsManifest(baseURI, aManifest, baseURI, PR_TRUE,
|
||||
strcmp(chromeType, "skin") == 0);
|
||||
}
|
||||
|
||||
while (aBuffer < bufferEnd && (*aBuffer == '\0' || *aBuffer == ' ' || *aBuffer == '\r' || *aBuffer == '\n'))
|
||||
++aBuffer;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsChromeRegistry::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *someData)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
@ -1527,416 +1337,6 @@ NS_IMETHODIMP nsChromeRegistry::Observe(nsISupports *aSubject, const char *aTopi
|
||||
return rv;
|
||||
}
|
||||
|
||||
#ifdef MOZ_XUL
|
||||
static nsresult
|
||||
GetContainerEnumerator(nsIRDFDataSource* ds, nsIRDFResource* res,
|
||||
nsISimpleEnumerator* *aResult, PRInt32 *aCountResult = nsnull)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIRDFContainer> container
|
||||
(do_CreateInstance("@mozilla.org/rdf/container;1"));
|
||||
NS_ENSURE_TRUE(container, NS_ERROR_FAILURE);
|
||||
|
||||
rv = container->Init(ds, res);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (aCountResult)
|
||||
container->GetCount(aCountResult);
|
||||
|
||||
return container->GetElements(aResult);
|
||||
}
|
||||
|
||||
static void
|
||||
FollowLiteral(nsIRDFDataSource* ds, nsIRDFResource* res,
|
||||
nsIRDFResource* arc, nsACString& result)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIRDFNode> node;
|
||||
rv = ds->GetTarget(res, arc, PR_TRUE, getter_AddRefs(node));
|
||||
if (NS_FAILED(rv) || !node) {
|
||||
result.Truncate();
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIRDFLiteral> literal (do_QueryInterface(node));
|
||||
if (!literal) {
|
||||
NS_ERROR("Arc found, but doesn't point to expected literal!");
|
||||
result.Truncate();
|
||||
return;
|
||||
}
|
||||
|
||||
const PRUnichar* value;
|
||||
literal->GetValueConst(&value);
|
||||
CopyUTF16toUTF8(value, result);
|
||||
}
|
||||
|
||||
static void
|
||||
FollowResource(nsIRDFDataSource* ds, nsIRDFResource* res, nsIRDFResource* arc,
|
||||
nsIRDFResource* *result)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIRDFNode> node;
|
||||
rv = ds->GetTarget(res, arc, PR_TRUE, getter_AddRefs(node));
|
||||
if (NS_FAILED(rv) || !node) {
|
||||
*result = nsnull;
|
||||
return;
|
||||
}
|
||||
|
||||
CallQueryInterface(node, result);
|
||||
}
|
||||
|
||||
static void
|
||||
GetRelativePath(nsIURI* base, nsIURI* relative, nsACString& result)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIJARURI> jarrelative (do_QueryInterface(relative));
|
||||
if (jarrelative) {
|
||||
nsCOMPtr<nsIURI> jarbase;
|
||||
jarrelative->GetJARFile(getter_AddRefs(jarbase));
|
||||
|
||||
nsCAutoString relativeBase;
|
||||
GetRelativePath(base, jarbase, relativeBase);
|
||||
|
||||
nsCAutoString jarEntry;
|
||||
jarrelative->GetJAREntry(jarEntry);
|
||||
|
||||
result.Assign(NS_LITERAL_CSTRING("jar:"));
|
||||
result.Append(relativeBase);
|
||||
result.Append(NS_LITERAL_CSTRING("!/"));
|
||||
result.Append(jarEntry);
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURL> baseURL (do_QueryInterface(base));
|
||||
if (!baseURL) {
|
||||
relative->GetSpec(result);
|
||||
return;
|
||||
}
|
||||
|
||||
rv = baseURL->GetRelativeSpec(relative, result);
|
||||
if (NS_FAILED(rv)) {
|
||||
relative->GetSpec(result);
|
||||
}
|
||||
}
|
||||
|
||||
static const PRInt32 kNSPR_APPEND_FLAGS = PR_WRONLY | PR_CREATE_FILE | PR_APPEND;
|
||||
static const PRInt32 kNSPR_TRUNCATE_FLAGS = PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE;
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsChromeRegistry::ProcessContentsManifest(nsIURI* aOldManifest, nsIURI* aFile,
|
||||
nsIURI* aBaseURI, PRBool aAppend,
|
||||
PRBool aSkinOnly)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsCAutoString relativePath;
|
||||
GetRelativePath(aFile, aBaseURI, relativePath);
|
||||
|
||||
nsCAutoString spec;
|
||||
aOldManifest->GetSpec(spec);
|
||||
|
||||
NS_ASSERTION(spec.Last() == '/', "installed-chrome manifest URI doesn't end in a slash! It probably won't work.");
|
||||
|
||||
spec.AppendLiteral("contents.rdf");
|
||||
|
||||
nsCOMPtr<nsIRDFService> rdfs (do_GetService("@mozilla.org/rdf/rdf-service;1"));
|
||||
NS_ENSURE_TRUE(rdfs, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<nsIRDFResource> namearc, platformarc;
|
||||
rdfs->GetResource(NS_LITERAL_CSTRING(kURICHROME_name),
|
||||
getter_AddRefs(namearc));
|
||||
rdfs->GetResource(NS_LITERAL_CSTRING(kURICHROME_platformPackage),
|
||||
getter_AddRefs(platformarc));
|
||||
if (!(namearc && platformarc))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsCOMPtr<nsIRDFDataSource> ds;
|
||||
rv = rdfs->GetDataSourceBlocking(spec.get(), getter_AddRefs(ds));
|
||||
if (NS_FAILED(rv)) {
|
||||
LogMessage("Failed to load old-style contents.rdf at '%s'.",
|
||||
spec.get());
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFileURL> fileURL (do_QueryInterface(aFile));
|
||||
NS_ENSURE_TRUE(fileURL, NS_ERROR_INVALID_ARG);
|
||||
|
||||
nsCOMPtr<nsIFile> file;
|
||||
rv = fileURL->GetFile(getter_AddRefs(file));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsILocalFile> lfile (do_QueryInterface(file));
|
||||
NS_ENSURE_TRUE(lfile, NS_ERROR_NO_INTERFACE);
|
||||
|
||||
PRFileDesc* fd;
|
||||
rv = lfile->OpenNSPRFileDesc(aAppend ? kNSPR_APPEND_FLAGS : kNSPR_TRUNCATE_FLAGS,
|
||||
0664, &fd);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (aAppend)
|
||||
PR_Write(fd, "\n", 1);
|
||||
|
||||
nsCOMPtr<nsIRDFResource> root;
|
||||
rv = rdfs->GetResource(NS_LITERAL_CSTRING("urn:mozilla:skin:root"),
|
||||
getter_AddRefs(root));
|
||||
if (NS_SUCCEEDED(rv))
|
||||
ProcessProvider(fd, rdfs, ds, root, PR_FALSE, relativePath);
|
||||
|
||||
rv = rdfs->GetResource(NS_LITERAL_CSTRING("urn:mozilla:stylesheets"),
|
||||
getter_AddRefs(root));
|
||||
if (NS_SUCCEEDED(rv))
|
||||
ProcessOverlays(fd, ds, root, NS_LITERAL_CSTRING("style"));
|
||||
|
||||
if (!aSkinOnly) {
|
||||
rv = rdfs->GetResource(NS_LITERAL_CSTRING("urn:mozilla:locale:root"),
|
||||
getter_AddRefs(root));
|
||||
if (NS_SUCCEEDED(rv))
|
||||
ProcessProvider(fd, rdfs, ds, root, PR_TRUE, relativePath);
|
||||
|
||||
rv = rdfs->GetResource(NS_LITERAL_CSTRING("urn:mozilla:overlays"),
|
||||
getter_AddRefs(root));
|
||||
if (NS_SUCCEEDED(rv))
|
||||
ProcessOverlays(fd, ds, root, NS_LITERAL_CSTRING("overlay"));
|
||||
|
||||
/* content packages are easier, but different */
|
||||
|
||||
rv = rdfs->GetResource(NS_LITERAL_CSTRING("urn:mozilla:package:root"),
|
||||
getter_AddRefs(root));
|
||||
|
||||
nsCOMPtr<nsISimpleEnumerator> packages;
|
||||
if (NS_SUCCEEDED(rv))
|
||||
rv = GetContainerEnumerator(ds, root, getter_AddRefs(packages));
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
PRBool more;
|
||||
nsCOMPtr<nsISupports> next;
|
||||
nsCOMPtr<nsIRDFResource> package;
|
||||
|
||||
while (NS_SUCCEEDED(packages->HasMoreElements(&more)) && more) {
|
||||
packages->GetNext(getter_AddRefs(next));
|
||||
|
||||
package = do_QueryInterface(next);
|
||||
if (!package) {
|
||||
NS_WARNING("Arc from urn:mozilla:package:root points to non-resource node.");
|
||||
continue;
|
||||
}
|
||||
|
||||
nsCAutoString name;
|
||||
FollowLiteral(ds, package, namearc, name);
|
||||
if (name.IsEmpty())
|
||||
continue;
|
||||
|
||||
nsCAutoString isPlatform;
|
||||
FollowLiteral(ds, package, platformarc, isPlatform);
|
||||
name.Insert(NS_LITERAL_CSTRING("content\t"), 0);
|
||||
name.Append('\t');
|
||||
name.Append(relativePath);
|
||||
if (!isPlatform.IsEmpty())
|
||||
name.AppendLiteral("\tplatform");
|
||||
|
||||
name.AppendLiteral(NS_LINEBREAK);
|
||||
PR_Write(fd, name.get(), name.Length());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PR_Close(fd);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
GetResourceName(nsIRDFResource* res, nsACString& result)
|
||||
{
|
||||
// we need to get the provider name. Instead of doing something sane,
|
||||
// we munge the resource URI, looking from the right for colons.
|
||||
|
||||
nsCAutoString providerURI;
|
||||
res->GetValueUTF8(providerURI);
|
||||
|
||||
PRInt32 found = providerURI.RFindChar(':');
|
||||
if (found == kNotFound) {
|
||||
result.Truncate();
|
||||
return;
|
||||
}
|
||||
|
||||
result.Assign(Substring(providerURI, found + 1));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nsChromeRegistry::ProcessProvider(PRFileDesc *fd, nsIRDFService* aRDFs,
|
||||
nsIRDFDataSource* aDS, nsIRDFResource* aRoot,
|
||||
PRBool aIsLocale, const nsACString& aBaseURL)
|
||||
{
|
||||
NS_NAMED_LITERAL_CSTRING(kSlash, "/");
|
||||
NS_NAMED_LITERAL_CSTRING(kTab, "\t");
|
||||
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIRDFResource> packagesarc;
|
||||
aRDFs->GetResource(NS_LITERAL_CSTRING(kURICHROME_packages),
|
||||
getter_AddRefs(packagesarc));
|
||||
if (!packagesarc) return;
|
||||
|
||||
nsCOMPtr<nsISimpleEnumerator> providers;
|
||||
rv = GetContainerEnumerator(aDS, aRoot, getter_AddRefs(providers));
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupports> next;
|
||||
|
||||
PRBool more;
|
||||
while (NS_SUCCEEDED(providers->HasMoreElements(&more)) && more) {
|
||||
providers->GetNext(getter_AddRefs(next));
|
||||
NS_ASSERTION(next, "GetNext failed after HasMoreElements succeeded.");
|
||||
|
||||
nsCOMPtr<nsIRDFResource> provider (do_QueryInterface(next));
|
||||
if (!provider) {
|
||||
NS_WARNING("Provider isn't a nsIRDFResource.");
|
||||
continue;
|
||||
}
|
||||
|
||||
nsCAutoString providerName;
|
||||
GetResourceName(provider, providerName);
|
||||
if (providerName.IsEmpty()) {
|
||||
NS_WARNING("Couldn't calculate resource name.");
|
||||
continue;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIRDFResource> packages;
|
||||
FollowResource(aDS, provider, packagesarc, getter_AddRefs(packages));
|
||||
if (!packages) {
|
||||
NS_WARNING("No chrome:packages arc found!");
|
||||
continue;
|
||||
}
|
||||
|
||||
PRInt32 count;
|
||||
nsCOMPtr<nsISimpleEnumerator> packageList;
|
||||
rv = GetContainerEnumerator(aDS, packages, getter_AddRefs(packageList), &count);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("chrome:packages was not a sequence.");
|
||||
continue;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupports> nextPackage;
|
||||
|
||||
PRBool morePackages;
|
||||
while (NS_SUCCEEDED(packageList->HasMoreElements(&morePackages)) &&
|
||||
morePackages) {
|
||||
packageList->GetNext(getter_AddRefs(nextPackage));
|
||||
|
||||
nsCOMPtr<nsIRDFResource> packageRes (do_QueryInterface(nextPackage));
|
||||
if (!packageRes) {
|
||||
NS_WARNING("chrome:packages Seq points to a non-resource!");
|
||||
continue;
|
||||
}
|
||||
|
||||
nsCAutoString packageName;
|
||||
GetResourceName(packageRes, packageName);
|
||||
if (packageName.IsEmpty()) {
|
||||
NS_WARNING("couldn't extract a package name.");
|
||||
continue;
|
||||
}
|
||||
|
||||
nsCAutoString line;
|
||||
|
||||
if (aIsLocale)
|
||||
line.AppendLiteral("locale\t");
|
||||
else
|
||||
line.AppendLiteral("skin\t");
|
||||
|
||||
line += packageName + kTab + providerName + kTab + aBaseURL;
|
||||
if (count > 1) {
|
||||
line += packageName + kSlash;
|
||||
}
|
||||
line.AppendLiteral(NS_LINEBREAK);
|
||||
PR_Write(fd, line.get(), line.Length());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
GetLiteralText(nsIRDFLiteral* lit, nsACString& result)
|
||||
{
|
||||
const PRUnichar* value;
|
||||
lit->GetValueConst(&value);
|
||||
CopyUTF16toUTF8(value, result);
|
||||
}
|
||||
|
||||
void
|
||||
nsChromeRegistry::ProcessOverlays(PRFileDesc *fd, nsIRDFDataSource* aDS,
|
||||
nsIRDFResource* aRoot,
|
||||
const nsCSubstring& aType)
|
||||
{
|
||||
NS_NAMED_LITERAL_CSTRING(kTab, "\t");
|
||||
NS_NAMED_LITERAL_CSTRING(kLinebreak, NS_LINEBREAK);
|
||||
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsISimpleEnumerator> overlaids;
|
||||
rv = GetContainerEnumerator(aDS, aRoot, getter_AddRefs(overlaids));
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupports> next;
|
||||
PRBool more;
|
||||
while (NS_SUCCEEDED(overlaids->HasMoreElements(&more)) && more) {
|
||||
overlaids->GetNext(getter_AddRefs(next));
|
||||
NS_ASSERTION(next, "GetNext failed after HasMoreElements succeeded.");
|
||||
|
||||
nsCOMPtr<nsIRDFResource> overlaid (do_QueryInterface(next));
|
||||
if (!overlaid) {
|
||||
NS_WARNING("Overlay arc is not a nsIRDFResource.");
|
||||
continue;
|
||||
}
|
||||
|
||||
nsCAutoString overlaidName;
|
||||
overlaid->GetValueUTF8(overlaidName);
|
||||
|
||||
nsCOMPtr<nsISimpleEnumerator> overlays;
|
||||
rv = GetContainerEnumerator(aDS, overlaid, getter_AddRefs(overlays));
|
||||
if (NS_FAILED(rv))
|
||||
continue;
|
||||
|
||||
while (NS_SUCCEEDED(overlays->HasMoreElements(&more)) && more) {
|
||||
overlays->GetNext(getter_AddRefs(next));
|
||||
NS_ASSERTION(next, "GetNext failed after HasMoreElements succeeded.");
|
||||
|
||||
nsCOMPtr<nsIRDFLiteral> overlay (do_QueryInterface(next));
|
||||
if (!overlay) {
|
||||
NS_WARNING("Overlay was not an RDF literal.");
|
||||
continue;
|
||||
}
|
||||
|
||||
nsCAutoString overlayName;
|
||||
GetLiteralText(overlay, overlayName);
|
||||
|
||||
overlayName.Insert(aType + kTab + overlaidName + kTab, 0);
|
||||
overlayName.Append(kLinebreak);
|
||||
PR_Write(fd, overlayName.get(), overlayName.Length());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else // MOZ_XUL
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsChromeRegistry::ProcessContentsManifest(nsIURI* aOldManifest, nsIURI* aFile,
|
||||
nsIURI* aBaseURI, PRBool aAppend,
|
||||
PRBool aSkinOnly)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
#endif // MOZ_XUL
|
||||
|
||||
nsresult
|
||||
nsChromeRegistry::ProcessManifest(nsILocalFile* aManifest, PRBool aSkinOnly)
|
||||
{
|
||||
|
@ -72,9 +72,6 @@ missingFileMessage=%S could not load this item because the file %S was missing.
|
||||
malformedMessage=%S could not install this item because "%S" (provided by the item) is not well-formed or does not exist. Please contact the author about this problem.
|
||||
malformedTitle=Malformed File
|
||||
|
||||
malformedRegistrationTitle=Chrome Registration Failed
|
||||
malformedRegistrationMessage=%S could not install this item because of a failure in Chrome Registration. Please contact the author about this problem.
|
||||
|
||||
invalidFileExtTitle=Invalid File Extension
|
||||
invalidFileExtMessage="%S" could not be installed because this item has an invalid file extension (%S is not a valid file extension for a %S). Please contact the author about this problem.
|
||||
missingPackageFilesTitle=Missing Installation Files
|
||||
|
@ -86,7 +86,6 @@ const FILE_EXTENSIONS_STARTUP_CACHE = "extensions.cache";
|
||||
const FILE_EXTENSIONS_LOG = "extensions.log";
|
||||
const FILE_AUTOREG = ".autoreg";
|
||||
const FILE_INSTALL_MANIFEST = "install.rdf";
|
||||
const FILE_CONTENTS_MANIFEST = "contents.rdf";
|
||||
const FILE_CHROME_MANIFEST = "chrome.manifest";
|
||||
|
||||
const UNKNOWN_XPCOM_ABI = "unknownABI";
|
||||
@ -124,7 +123,6 @@ const CATEGORY_INSTALL_LOCATIONS = "extension-install-locations";
|
||||
const CATEGORY_UPDATE_PARAMS = "extension-update-params";
|
||||
|
||||
const PREFIX_NS_EM = "http://www.mozilla.org/2004/em-rdf#";
|
||||
const PREFIX_NS_CHROME = "http://www.mozilla.org/rdf/chrome#";
|
||||
const PREFIX_ITEM_URI = "urn:mozilla:item:";
|
||||
const PREFIX_EXTENSION = "urn:mozilla:extension:";
|
||||
const PREFIX_THEME = "urn:mozilla:theme:";
|
||||
@ -241,10 +239,6 @@ function EM_NS(property) {
|
||||
return PREFIX_NS_EM + property;
|
||||
}
|
||||
|
||||
function CHROME_NS(property) {
|
||||
return PREFIX_NS_CHROME + property;
|
||||
}
|
||||
|
||||
function EM_R(property) {
|
||||
return gRDF.GetResource(EM_NS(property));
|
||||
}
|
||||
@ -1539,377 +1533,8 @@ WinRegInstallLocation.prototype = {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* An object which handles the installation of an Extension.
|
||||
* @constructor
|
||||
*/
|
||||
function Installer(ds, id, installLocation, type) {
|
||||
this._ds = ds;
|
||||
this._id = id;
|
||||
this._type = type;
|
||||
this._installLocation = installLocation;
|
||||
}
|
||||
Installer.prototype = {
|
||||
// Item metadata
|
||||
_id: null,
|
||||
_ds: null,
|
||||
_installLocation: null,
|
||||
_metadataDS: null,
|
||||
|
||||
/**
|
||||
* Gets the Install Manifest datasource we are installing from.
|
||||
*/
|
||||
get metadataDS() {
|
||||
if (!this._metadataDS) {
|
||||
var metadataFile = this._installLocation
|
||||
.getItemFile(this._id, FILE_INSTALL_MANIFEST);
|
||||
if (!metadataFile.exists())
|
||||
return null;
|
||||
this._metadataDS = getInstallManifest(metadataFile);
|
||||
if (!this._metadataDS) {
|
||||
LOG("Installer::install: metadata datasource for extension " +
|
||||
this._id + " at " + metadataFile.path + " could not be loaded. " +
|
||||
" Installation will not proceed.");
|
||||
}
|
||||
}
|
||||
return this._metadataDS;
|
||||
},
|
||||
|
||||
/**
|
||||
* Installs the Extension
|
||||
* @param file
|
||||
* A XPI/JAR file to install from. If this is null or does not exist,
|
||||
* the item is assumed to be an expanded directory, located at the GUID
|
||||
* key in the supplied Install Location.
|
||||
*/
|
||||
installFromFile: function Installer_installFromFile(file) {
|
||||
// Move files from the staging dir into the extension's final home.
|
||||
if (file && file.exists()) {
|
||||
this._installExtensionFiles(file);
|
||||
}
|
||||
|
||||
if (!this.metadataDS)
|
||||
return;
|
||||
|
||||
// Upgrade old-style contents.rdf Chrome Manifests if necessary.
|
||||
if (this._type == Ci.nsIUpdateItem.TYPE_THEME)
|
||||
this.upgradeThemeChrome();
|
||||
else
|
||||
this.upgradeExtensionChrome();
|
||||
|
||||
// Add metadata for the extension to the global extension metadata set
|
||||
this._ds.addItemMetadata(this._id, this.metadataDS, this._installLocation);
|
||||
},
|
||||
|
||||
/**
|
||||
* Safely extract the Extension's files into the target folder.
|
||||
* @param file
|
||||
* The XPI/JAR file to install from.
|
||||
*/
|
||||
_installExtensionFiles: function Installer__installExtensionFiles(file) {
|
||||
/**
|
||||
* Callback for |safeInstallOperation| that performs file level installation
|
||||
* steps for an Extension.
|
||||
* @param extensionID
|
||||
* The GUID of the Extension being installed.
|
||||
* @param installLocation
|
||||
* The Install Location where the Extension is being installed.
|
||||
* @param xpiFile
|
||||
* The source XPI file that contains the Extension.
|
||||
*/
|
||||
function extractExtensionFiles(extensionID, installLocation, xpiFile) {
|
||||
// Create a logger to log install operations for uninstall. This must be
|
||||
// created in the |safeInstallOperation| callback, since it creates a file
|
||||
// in the target directory. If we do this outside of the callback, we may
|
||||
// be clobbering a file we should not be.
|
||||
var zipReader = getZipReaderForFile(xpiFile);
|
||||
|
||||
// create directories first
|
||||
var entries = zipReader.findEntries("*/");
|
||||
while (entries.hasMore()) {
|
||||
var entryName = entries.getNext();
|
||||
var target = installLocation.getItemFile(extensionID, entryName);
|
||||
if (!target.exists()) {
|
||||
try {
|
||||
target.create(Ci.nsILocalFile.DIRECTORY_TYPE, PERMS_DIRECTORY);
|
||||
}
|
||||
catch (e) {
|
||||
ERROR("extractExtensionsFiles: failed to create target directory for extraction " +
|
||||
" file = " + target.path + ", exception = " + e + "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
entries = zipReader.findEntries(null);
|
||||
while (entries.hasMore()) {
|
||||
var entryName = entries.getNext();
|
||||
target = installLocation.getItemFile(extensionID, entryName);
|
||||
if (target.exists())
|
||||
continue;
|
||||
|
||||
try {
|
||||
target.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE);
|
||||
}
|
||||
catch (e) {
|
||||
ERROR("extractExtensionsFiles: failed to create target file for extraction " +
|
||||
" file = " + target.path + ", exception = " + e + "\n");
|
||||
}
|
||||
zipReader.extract(entryName, target);
|
||||
}
|
||||
zipReader.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for |safeInstallOperation| that performs file level installation
|
||||
* steps for a Theme.
|
||||
* @param id
|
||||
* The GUID of the Theme being installed.
|
||||
* @param installLocation
|
||||
* The Install Location where the Theme is being installed.
|
||||
* @param jarFile
|
||||
* The source JAR file that contains the Theme.
|
||||
*/
|
||||
function extractThemeFiles(id, installLocation, jarFile) {
|
||||
var themeDirectory = installLocation.getItemLocation(id);
|
||||
var zipReader = getZipReaderForFile(jarFile);
|
||||
|
||||
// The only critical file is the install.rdf and we would not have
|
||||
// gotten this far without one.
|
||||
var rootFiles = [FILE_INSTALL_MANIFEST, FILE_CHROME_MANIFEST,
|
||||
"preview.png", "icon.png"];
|
||||
for (var i = 0; i < rootFiles.length; ++i) {
|
||||
try {
|
||||
var target = installLocation.getItemFile(id, rootFiles[i]);
|
||||
zipReader.extract(rootFiles[i], target);
|
||||
}
|
||||
catch (e) {
|
||||
}
|
||||
}
|
||||
|
||||
var manifestFile = installLocation.getItemFile(id, FILE_CHROME_MANIFEST);
|
||||
// new theme structure requires a chrome.manifest file
|
||||
if (manifestFile.exists()) {
|
||||
var entries = zipReader.findEntries(DIR_CHROME + "/*");
|
||||
while (entries.hasMore()) {
|
||||
var entryName = entries.getNext();
|
||||
if (entryName.charAt(entryName.length - 1) == "/")
|
||||
continue;
|
||||
target = installLocation.getItemFile(id, entryName);
|
||||
try {
|
||||
target.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE);
|
||||
}
|
||||
catch (e) {
|
||||
ERROR("extractThemeFiles: failed to create target file for extraction " +
|
||||
" file = " + target.path + ", exception = " + e + "\n");
|
||||
}
|
||||
zipReader.extract(entryName, target);
|
||||
}
|
||||
zipReader.close();
|
||||
}
|
||||
else { // old theme structure requires only an install.rdf
|
||||
try {
|
||||
var contentsManifestFile = installLocation.getItemFile(id, FILE_CONTENTS_MANIFEST);
|
||||
contentsManifestFile.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE);
|
||||
zipReader.extract(FILE_CONTENTS_MANIFEST, contentsManifestFile);
|
||||
}
|
||||
catch (e) {
|
||||
zipReader.close();
|
||||
ERROR("extractThemeFiles: failed to extract contents.rdf: " + target.path);
|
||||
throw e; // let the safe-op clean up
|
||||
}
|
||||
zipReader.close();
|
||||
var chromeDir = installLocation.getItemFile(id, DIR_CHROME);
|
||||
try {
|
||||
jarFile.copyTo(chromeDir, jarFile.leafName);
|
||||
}
|
||||
catch (e) {
|
||||
ERROR("extractThemeFiles: failed to copy theme JAR file to: " + chromeDir.path);
|
||||
throw e; // let the safe-op clean up
|
||||
}
|
||||
|
||||
if (!installer.metadataDS && installer._type == Ci.nsIUpdateItem.TYPE_THEME) {
|
||||
var themeName = extensionStrings.GetStringFromName("incompatibleThemeName");
|
||||
if (contentsManifestFile && contentsManifestFile.exists()) {
|
||||
var contentsManifest = gRDF.GetDataSourceBlocking(getURLSpecFromFile(contentsManifestFile));
|
||||
try {
|
||||
var ctr = getContainer(contentsManifest,
|
||||
gRDF.GetResource("urn:mozilla:skin:root"));
|
||||
var elts = ctr.GetElements();
|
||||
var nameArc = gRDF.GetResource(CHROME_NS("displayName"));
|
||||
while (elts.hasMoreElements()) {
|
||||
var elt = elts.getNext().QueryInterface(Ci.nsIRDFResource);
|
||||
themeName = stringData(contentsManifest.GetTarget(elt, nameArc, true));
|
||||
if (themeName)
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
themeName = extensionStrings.GetStringFromName("incompatibleThemeName");
|
||||
}
|
||||
}
|
||||
showIncompatibleError({ name: themeName, version: "",
|
||||
type: Ci.nsIUpdateItem.TYPE_THEME });
|
||||
LOG("Theme JAR file: " + jarFile.leafName + " contains an Old-Style " +
|
||||
"Theme that is not compatible with this version of the software.");
|
||||
throw new Error("Old Theme"); // let the safe-op clean up
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var installer = this;
|
||||
var callback = extractExtensionFiles;
|
||||
if (this._type == Ci.nsIUpdateItem.TYPE_THEME)
|
||||
callback = extractThemeFiles;
|
||||
safeInstallOperation(this._id, this._installLocation,
|
||||
{ callback: callback, data: file });
|
||||
},
|
||||
|
||||
/**
|
||||
* Upgrade contents.rdf Chrome Manifests used by this Theme to the new
|
||||
* chrome.manifest format if necessary.
|
||||
*/
|
||||
upgradeThemeChrome: function Installer_upgradeThemeChrome() {
|
||||
// Use the Chrome Registry API to install the theme there
|
||||
var cr = Cc["@mozilla.org/chrome/chrome-registry;1"].
|
||||
getService(Ci.nsIToolkitChromeRegistry);
|
||||
var manifestFile = this._installLocation.getItemFile(this._id, FILE_CHROME_MANIFEST);
|
||||
if (manifestFile.exists() ||
|
||||
this._id == stripPrefix(RDFURI_DEFAULT_THEME, PREFIX_ITEM_URI))
|
||||
return;
|
||||
|
||||
try {
|
||||
// creates a chrome manifest for themes
|
||||
var manifestURI = getURIFromFile(manifestFile);
|
||||
var chromeDir = this._installLocation.getItemFile(this._id, DIR_CHROME);
|
||||
// We're relying on the fact that there is only one JAR file
|
||||
// in the "chrome" directory. This is a hack, but it works.
|
||||
var entries = chromeDir.directoryEntries.QueryInterface(Ci.nsIDirectoryEnumerator);
|
||||
var jarFile = entries.nextFile;
|
||||
if (jarFile) {
|
||||
var jarFileURI = getURIFromFile(jarFile);
|
||||
var contentsURI = newURI("jar:" + jarFileURI.spec + "!/");
|
||||
var contentsFile = this._installLocation.getItemFile(this._id, FILE_CONTENTS_MANIFEST);
|
||||
var contentsFileURI = getURIFromFile(contentsFile.parent);
|
||||
|
||||
cr.processContentsManifest(contentsFileURI, manifestURI, contentsURI, false, true);
|
||||
}
|
||||
entries.close();
|
||||
contentsFile.remove(false);
|
||||
}
|
||||
catch (e) {
|
||||
// Failed to register chrome, for any number of reasons - non-existent
|
||||
// contents.rdf file at the location specified, malformed contents.rdf,
|
||||
// etc. Set the pending op to be OP_NEEDS_UNINSTALL so that the
|
||||
// extension is uninstalled properly during the subsequent uninstall
|
||||
// pass in |ExtensionManager::_finishOperations|
|
||||
ERROR("upgradeThemeChrome: failed for theme " + this._id + " - why " +
|
||||
"not convert to the new chrome.manifest format while you're at it? " +
|
||||
"Failure exception: " + e);
|
||||
showMessage("malformedRegistrationTitle", [], "malformedRegistrationMessage",
|
||||
[BundleManager.appName]);
|
||||
|
||||
var stageFile = this._installLocation.getStageFile(this._id);
|
||||
if (stageFile)
|
||||
this._installLocation.removeFile(stageFile);
|
||||
|
||||
StartupCache.put(this._installLocation, this._id, OP_NEEDS_UNINSTALL, true);
|
||||
StartupCache.write();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Upgrade contents.rdf Chrome Manifests used by this Extension to the new
|
||||
* chrome.manifest format if necessary.
|
||||
*/
|
||||
upgradeExtensionChrome: function Installer_upgradeExtensionChrome() {
|
||||
// If the extension is aware of the new flat chrome manifests and has
|
||||
// included one, just use it instead of generating one from the
|
||||
// install.rdf/contents.rdf data.
|
||||
var manifestFile = this._installLocation.getItemFile(this._id, FILE_CHROME_MANIFEST);
|
||||
if (manifestFile.exists())
|
||||
return;
|
||||
|
||||
try {
|
||||
// Enumerate the metadata datasource files collection and register chrome
|
||||
// for each file, calling _registerChrome for each.
|
||||
var chromeDir = this._installLocation.getItemFile(this._id, DIR_CHROME);
|
||||
|
||||
if (!manifestFile.parent.exists())
|
||||
return;
|
||||
|
||||
// Even if an extension doesn't have any chrome, we generate an empty
|
||||
// manifest file so that we don't try to upgrade from the "old-style"
|
||||
// chrome manifests at every startup.
|
||||
manifestFile.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE);
|
||||
|
||||
var manifestURI = getURIFromFile(manifestFile);
|
||||
var files = this.metadataDS.GetTargets(gInstallManifestRoot, EM_R("file"), true);
|
||||
while (files.hasMoreElements()) {
|
||||
var file = files.getNext().QueryInterface(Ci.nsIRDFResource);
|
||||
var chromeFile = chromeDir.clone();
|
||||
var fileName = file.Value.substr("urn:mozilla:extension:file:".length, file.Value.length);
|
||||
chromeFile.append(fileName);
|
||||
|
||||
var fileURLSpec = getURLSpecFromFile(chromeFile);
|
||||
if (!chromeFile.isDirectory()) {
|
||||
var zipReader = getZipReaderForFile(chromeFile);
|
||||
fileURLSpec = "jar:" + fileURLSpec + "!/";
|
||||
var contentsFile = this._installLocation.getItemFile(this._id, FILE_CONTENTS_MANIFEST);
|
||||
contentsFile.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE);
|
||||
}
|
||||
|
||||
var providers = [EM_R("package"), EM_R("skin"), EM_R("locale")];
|
||||
for (var i = 0; i < providers.length; ++i) {
|
||||
var items = this.metadataDS.GetTargets(file, providers[i], true);
|
||||
while (items.hasMoreElements()) {
|
||||
var item = items.getNext().QueryInterface(Ci.nsIRDFLiteral);
|
||||
var fileURI = newURI(fileURLSpec + item.Value);
|
||||
// Extract the contents.rdf files instead of opening them inside of
|
||||
// the jar. This prevents the jar from being cached by the zip
|
||||
// reader which will keep the jar in use and prevent deletion.
|
||||
if (zipReader) {
|
||||
zipReader.extract(item.Value + FILE_CONTENTS_MANIFEST, contentsFile);
|
||||
var contentsFileURI = getURIFromFile(contentsFile.parent);
|
||||
}
|
||||
else
|
||||
contentsFileURI = fileURI;
|
||||
|
||||
var cr = Cc["@mozilla.org/chrome/chrome-registry;1"].
|
||||
getService(Ci.nsIToolkitChromeRegistry);
|
||||
cr.processContentsManifest(contentsFileURI, manifestURI, fileURI, true, false);
|
||||
}
|
||||
}
|
||||
if (zipReader) {
|
||||
zipReader.close();
|
||||
zipReader = null;
|
||||
contentsFile.remove(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
// Failed to register chrome, for any number of reasons - non-existent
|
||||
// contents.rdf file at the location specified, malformed contents.rdf,
|
||||
// etc. Set the pending op to be OP_NEEDS_UNINSTALL so that the
|
||||
// extension is uninstalled properly during the subsequent uninstall
|
||||
// pass in |ExtensionManager::_finishOperations|
|
||||
ERROR("upgradeExtensionChrome: failed for extension " + this._id + " - why " +
|
||||
"not convert to the new chrome.manifest format while you're at it? " +
|
||||
"Failure exception: " + e);
|
||||
showMessage("malformedRegistrationTitle", [], "malformedRegistrationMessage",
|
||||
[BundleManager.appName]);
|
||||
|
||||
var stageFile = this._installLocation.getStageFile(this._id);
|
||||
if (stageFile)
|
||||
this._installLocation.removeFile(stageFile);
|
||||
|
||||
StartupCache.put(this._installLocation, this._id, OP_NEEDS_UNINSTALL, true);
|
||||
StartupCache.write();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Safely attempt to perform a caller-defined install operation for a given
|
||||
* item ID. Using aggressive success-safety checks, this function will attempt
|
||||
* Safely attempt to install or uninstall a given item ID in an install
|
||||
* location. Using aggressive success-safety checks, this function will attempt
|
||||
* to move an existing location for an item aside and then allow installation
|
||||
* into the appropriate folder. If any operation fails the installation will
|
||||
* abort and roll back from the moved-aside old version.
|
||||
@ -1917,16 +1542,10 @@ Installer.prototype = {
|
||||
* The GUID of the item to perform the operation on.
|
||||
* @param installLocation
|
||||
* The Install Location where the item is installed.
|
||||
* @param installCallback
|
||||
* A caller supplied JS object with the following properties:
|
||||
* "data" A data parameter to be passed to the callback.
|
||||
* "callback" A function to perform the install operation. This
|
||||
* function is passed three parameters:
|
||||
* 1. The GUID of the item being operated on.
|
||||
* 2. The Install Location where the item is installed.
|
||||
* 3. The "data" parameter on the installCallback object.
|
||||
* @param file
|
||||
* An xpi file to install to the location or null to just uninstall
|
||||
*/
|
||||
function safeInstallOperation(itemID, installLocation, installCallback) {
|
||||
function safeInstallOperation(itemID, installLocation, file) {
|
||||
var movedFiles = [];
|
||||
|
||||
/**
|
||||
@ -2019,6 +1638,53 @@ function safeInstallOperation(itemID, installLocation, installCallback) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts an XPI's files into the item's directory.
|
||||
* @param itemID
|
||||
* The ID of the item being installed.
|
||||
* @param installLocation
|
||||
* The install location where the item is being installed.
|
||||
* @param xpiFile
|
||||
* The source XPI file that contains the item.
|
||||
*/
|
||||
function extractFiles(itemID, installLocation, xpiFile) {
|
||||
var zipReader = getZipReaderForFile(xpiFile);
|
||||
|
||||
// create directories first
|
||||
var entries = zipReader.findEntries("*/");
|
||||
while (entries.hasMore()) {
|
||||
var entryName = entries.getNext();
|
||||
var target = installLocation.getItemFile(itemID, entryName);
|
||||
if (!target.exists()) {
|
||||
try {
|
||||
target.create(Ci.nsILocalFile.DIRECTORY_TYPE, PERMS_DIRECTORY);
|
||||
}
|
||||
catch (e) {
|
||||
ERROR("extractFiles: failed to create target directory for extraction " +
|
||||
"file = " + target.path + ", exception = " + e + "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
entries = zipReader.findEntries(null);
|
||||
while (entries.hasMore()) {
|
||||
var entryName = entries.getNext();
|
||||
target = installLocation.getItemFile(itemID, entryName);
|
||||
if (target.exists())
|
||||
continue;
|
||||
|
||||
try {
|
||||
target.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE);
|
||||
}
|
||||
catch (e) {
|
||||
ERROR("extractFiles: failed to create target file for extraction " +
|
||||
"file = " + target.path + ", exception = " + e + "\n");
|
||||
}
|
||||
zipReader.extract(entryName, target);
|
||||
}
|
||||
zipReader.close();
|
||||
}
|
||||
|
||||
if (!installLocation.itemIsManagedIndependently(itemID)) {
|
||||
var itemLocation = installLocation.getItemLocation(itemID);
|
||||
if (itemLocation.exists()) {
|
||||
@ -2088,28 +1754,30 @@ function safeInstallOperation(itemID, installLocation, installCallback) {
|
||||
}
|
||||
}
|
||||
|
||||
// Now tell the client to do their stuff.
|
||||
try {
|
||||
installCallback.callback(itemID, installLocation, installCallback.data);
|
||||
}
|
||||
catch (e) {
|
||||
// This means the install operation failed. Remove everything and roll back.
|
||||
ERROR("safeInstallOperation: install operation (caller-supplied callback) failed, " +
|
||||
"rolling back file moves and aborting installation.");
|
||||
if (file) {
|
||||
// Extract the xpi's files into the new directory
|
||||
try {
|
||||
// Us-generated. Safe.
|
||||
removeDirRecursive(itemLocation);
|
||||
extractFiles(itemID, installLocation, file);
|
||||
}
|
||||
catch (e) {
|
||||
ERROR("safeInstallOperation: failed to remove the folder we failed to install " +
|
||||
"an item into: " + itemLocation.path + " -- There is not much to suggest " +
|
||||
"here... maybe restart and try again?");
|
||||
// This means the install operation failed. Remove everything and roll back.
|
||||
ERROR("safeInstallOperation: file extraction failed, " +
|
||||
"rolling back file moves and aborting installation.");
|
||||
try {
|
||||
// Us-generated. Safe.
|
||||
removeDirRecursive(itemLocation);
|
||||
}
|
||||
catch (e) {
|
||||
ERROR("safeInstallOperation: failed to remove the folder we failed to install " +
|
||||
"an item into: " + itemLocation.path + " -- There is not much to suggest " +
|
||||
"here... maybe restart and try again?");
|
||||
cleanUpTrash(itemLocationTrash);
|
||||
throw e;
|
||||
}
|
||||
rollbackMove();
|
||||
cleanUpTrash(itemLocationTrash);
|
||||
throw e;
|
||||
}
|
||||
rollbackMove();
|
||||
cleanUpTrash(itemLocationTrash);
|
||||
throw e;
|
||||
}
|
||||
|
||||
// Now, and only now - after everything else has succeeded (against all odds!)
|
||||
@ -3294,107 +2962,6 @@ ExtensionManager.prototype = {
|
||||
return isDirty;
|
||||
},
|
||||
|
||||
/**
|
||||
* Upgrades contents.rdf files to chrome.manifest files for any existing
|
||||
* Extensions and Themes.
|
||||
* @returns true if actions were performed that require a restart, false
|
||||
* otherwise.
|
||||
*/
|
||||
_upgradeChrome: function EM__upgradeChrome() {
|
||||
if (inSafeMode())
|
||||
return false;
|
||||
|
||||
var checkForNewChrome = false;
|
||||
var ds = this.datasource;
|
||||
// If we have extensions that were installed before the new flat chrome
|
||||
// manifests, and are still valid, we need to manually create the flat
|
||||
// manifest files.
|
||||
var extensions = this._getActiveItems(Ci.nsIUpdateItem.TYPE_EXTENSION +
|
||||
Ci.nsIUpdateItem.TYPE_LOCALE);
|
||||
for (var i = 0; i < extensions.length; ++i) {
|
||||
var e = extensions[i];
|
||||
var itemLocation = e.location.getItemLocation(e.id);
|
||||
var manifest = itemLocation.clone();
|
||||
manifest.append(FILE_CHROME_MANIFEST);
|
||||
if (!manifest.exists()) {
|
||||
var installRDF = itemLocation.clone();
|
||||
installRDF.append(FILE_INSTALL_MANIFEST);
|
||||
var installLocation = this.getInstallLocation(e.id);
|
||||
if (installLocation && installRDF.exists()) {
|
||||
var itemLocation = installLocation.getItemLocation(e.id);
|
||||
if (itemLocation.exists() && itemLocation.isDirectory()) {
|
||||
var installer = new Installer(ds, e.id, installLocation,
|
||||
Ci.nsIUpdateItem.TYPE_EXTENSION);
|
||||
installer.upgradeExtensionChrome();
|
||||
}
|
||||
}
|
||||
else {
|
||||
ds.removeItemMetadata(e.id);
|
||||
ds.removeItemFromContainer(e.id);
|
||||
}
|
||||
|
||||
checkForNewChrome = true;
|
||||
}
|
||||
}
|
||||
|
||||
var themes = this._getActiveItems(Ci.nsIUpdateItem.TYPE_THEME);
|
||||
// If we have themes that were installed before the new flat chrome
|
||||
// manifests, and are still valid, we need to manually create the flat
|
||||
// manifest files.
|
||||
for (i = 0; i < themes.length; ++i) {
|
||||
var item = themes[i];
|
||||
var itemLocation = item.location.getItemLocation(item.id);
|
||||
var manifest = itemLocation.clone();
|
||||
manifest.append(FILE_CHROME_MANIFEST);
|
||||
if (manifest.exists() ||
|
||||
item.id == stripPrefix(RDFURI_DEFAULT_THEME, PREFIX_ITEM_URI))
|
||||
continue;
|
||||
|
||||
var entries;
|
||||
try {
|
||||
var manifestURI = getURIFromFile(manifest);
|
||||
var chromeDir = itemLocation.clone();
|
||||
chromeDir.append(DIR_CHROME);
|
||||
|
||||
if (!chromeDir.exists() || !chromeDir.isDirectory()) {
|
||||
ds.removeItemMetadata(item.id);
|
||||
ds.removeItemFromContainer(item.id);
|
||||
continue;
|
||||
}
|
||||
|
||||
// We're relying on the fact that there is only one JAR file
|
||||
// in the "chrome" directory. This is a hack, but it works.
|
||||
entries = chromeDir.directoryEntries.QueryInterface(Ci.nsIDirectoryEnumerator);
|
||||
var jarFile = entries.nextFile;
|
||||
if (jarFile) {
|
||||
var jarFileURI = getURIFromFile(jarFile);
|
||||
var contentsURI = newURI("jar:" + jarFileURI.spec + "!/");
|
||||
|
||||
// Use the Chrome Registry API to install the theme there
|
||||
var cr = Cc["@mozilla.org/chrome/chrome-registry;1"].
|
||||
getService(Ci.nsIToolkitChromeRegistry);
|
||||
cr.processContentsManifest(contentsURI, manifestURI, contentsURI, false, true);
|
||||
}
|
||||
entries.close();
|
||||
}
|
||||
catch (e) {
|
||||
ERROR("_upgradeChrome: failed to upgrade contents manifest for " +
|
||||
"theme: " + item.id + ", exception: " + e + "... The theme will be " +
|
||||
"disabled.");
|
||||
this._appDisableItem(item.id);
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
entries.close();
|
||||
}
|
||||
catch (e) {
|
||||
}
|
||||
}
|
||||
checkForNewChrome = true;
|
||||
}
|
||||
return checkForNewChrome;
|
||||
},
|
||||
|
||||
_checkForUncoveredItem: function EM__checkForUncoveredItem(id) {
|
||||
var ds = this.datasource;
|
||||
var oldLocation = this.getInstallLocation(id);
|
||||
@ -3559,14 +3126,6 @@ ExtensionManager.prototype = {
|
||||
}
|
||||
while (PendingOperations.size > 0);
|
||||
|
||||
// Upgrade contents.rdf files to the new chrome.manifest format for
|
||||
// existing Extensions and Themes
|
||||
if (this._upgradeChrome()) {
|
||||
var cr = Cc["@mozilla.org/chrome/chrome-registry;1"].
|
||||
getService(Ci.nsIChromeRegistry);
|
||||
cr.checkForNewChrome();
|
||||
}
|
||||
|
||||
// If no additional restart is required, it implies that there are
|
||||
// no new components that need registering so we can inform the app
|
||||
// not to do any extra startup checking next time round.
|
||||
@ -4750,10 +4309,23 @@ ExtensionManager.prototype = {
|
||||
if (!file && "stageFile" in installLocation)
|
||||
file = installLocation.getStageFile(id);
|
||||
|
||||
// If |file| is null or does not exist, the installer assumes the item is
|
||||
// a dropped-in directory.
|
||||
var installer = new Installer(this.datasource, id, installLocation, type);
|
||||
installer.installFromFile(file);
|
||||
// If there is a staged file then we must extract it to the correct place,
|
||||
// otherwise we are dealing with a dropped-in directory.
|
||||
if (file && file.exists())
|
||||
safeInstallOperation(id, installLocation, file);
|
||||
|
||||
var metadataFile = installLocation.getItemFile(id, FILE_INSTALL_MANIFEST);
|
||||
if (metadataFile.exists()) {
|
||||
var metadataDS = getInstallManifest(metadataFile);
|
||||
if (metadataDS) {
|
||||
// Add metadata for the item to the extensions datasource
|
||||
this.datasource.addItemMetadata(id, metadataDS, installLocation);
|
||||
}
|
||||
}
|
||||
else {
|
||||
LOG("_finalizeInstall: install manifest for extension " + id + " at " +
|
||||
metadataFile.path + " could not be loaded. Add-on is not usable.");
|
||||
}
|
||||
|
||||
// If the file was staged, we must clean it up ourselves, otherwise the
|
||||
// EM caller is responsible for doing so (e.g. XPInstall)
|
||||
@ -4819,10 +4391,9 @@ ExtensionManager.prototype = {
|
||||
var installLocation = this.getInstallLocation(id);
|
||||
if (!installLocation.itemIsManagedIndependently(id)) {
|
||||
try {
|
||||
// Having a callback that does nothing just causes the directory to be
|
||||
// Passing null for the file to install will just cause the directory
|
||||
// removed.
|
||||
safeInstallOperation(id, installLocation,
|
||||
{ data: null, callback: function() { } });
|
||||
safeInstallOperation(id, installLocation, null);
|
||||
}
|
||||
catch (e) {
|
||||
ERROR("_finalizeUninstall: failed to remove directory for item: " + id +
|
||||
|
Loading…
Reference in New Issue
Block a user