Bug 568691 part C - Register all components based on reading .manifest files from the components directories. Binary components auto-register using "binary-component name.dll". JS components register using "component CID file.js" "contract @mozilla.org/contract;1 CID" and "category categoryname keyname value".
authorBenjamin Smedberg <benjamin@smedbergs.us>
Fri, 11 Jun 2010 16:13:26 -0400
changeset 47005 c5827927d1403dfd94ab40c9235c1e0202684aa0
parent 47004 1b5cdc6d408502cc4721847482b4809f8a3dc427
child 47007 6f1e1300abcd96e3b5f7fd5bbab69fd836c1c2bf
push id14223
push userbsmedberg@mozilla.com
push dateThu, 01 Jul 2010 18:30:48 +0000
treeherdermozilla-central@836fd3f8feba [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs568691
milestone1.9.3a6pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 568691 part C - Register all components based on reading .manifest files from the components directories. Binary components auto-register using "binary-component name.dll". JS components register using "component CID file.js" "contract @mozilla.org/contract;1 CID" and "category categoryname keyname value". This patch has some bugs, specifically we stop looking for .manifest files in chrome/. I will fix that in a followup. It also probably breaks non-libxul builds because of ordering issues. Another followup will actually fix our in-tree JS components and add build machinery for creating a proper components.manifest file.
chrome/src/Makefile.in
chrome/src/nsChromeFactory.cpp
chrome/src/nsChromeRegistry.cpp
chrome/src/nsChromeRegistry.h
js/src/xpconnect/loader/mozJSComponentLoader.cpp
js/src/xpconnect/loader/mozJSComponentLoader.h
toolkit/library/libxul-config.mk
toolkit/library/nsStaticXULComponents.cpp
toolkit/toolkit-tiers.mk
xpcom/Makefile.in
xpcom/build/Makefile.in
xpcom/build/dlldeps.cpp
xpcom/build/nsXPComInit.cpp
xpcom/build/nsXULAppAPI.h
xpcom/components/Makefile.in
xpcom/components/ManifestParser.cpp
xpcom/components/ManifestParser.h
xpcom/components/nsComponentManager.cpp
xpcom/components/nsComponentManager.h
xpcom/glue/nsClassHashtable.h
xpcom/sample/Makefile.in
xpcom/sample/nsSample.js
xpcom/sample/nsSample.manifest
xpcom/tests/TestRegistrationOrder.cpp
--- a/chrome/src/Makefile.in
+++ b/chrome/src/Makefile.in
@@ -38,26 +38,22 @@
 DEPTH		= ../..
 topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE          = chrome
-LIBRARY_NAME    = chrome
-EXPORT_LIBRARY = 1
-IS_COMPONENT    = 1
-MODULE_NAME     = nsChromeModule
-GRE_MODULE      = 1
+LIBRARY_NAME    = chrome_s
 LIBXUL_LIBRARY  = 1
+FORCE_STATIC_LIB = 1
 
 
 CPPSRCS		= \
-		nsChromeFactory.cpp \
 		nsChromeRegistry.cpp \
 		nsChromeProtocolHandler.cpp \
 		$(NULL)
 
 EXTRA_DSO_LDOPTS = \
                 $(MOZ_UNICHARUTIL_LIBS) \
                 $(MOZ_COMPONENT_LIBS) \
                 $(NULL)
@@ -71,8 +67,12 @@ EXTRA_DSO_LDOPTS += $(TK_LIBS)
 endif
 
 include $(topsrcdir)/config/rules.mk
 
 ifneq (,$(filter gtk2,$(MOZ_WIDGET_TOOLKIT)))
 CXXFLAGS          += $(MOZ_GTK2_CFLAGS)
 endif
 
+LOCAL_INCLUDES += \
+  -I$(topsrcdir)/xpcom/components \
+  -I$(DEPTH)/xpcom \
+  $(NULL)
deleted file mode 100644
--- a/chrome/src/nsChromeFactory.cpp
+++ /dev/null
@@ -1,73 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is mozilla.org code.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 1998
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#include "nsCOMPtr.h"
-#include "mozilla/ModuleUtils.h"
-
-#include "nsIServiceManager.h"
-#include "nsIComponentManager.h"
-#include "nsIChromeRegistry.h"
-#include "nscore.h"
-#include "nsChromeProtocolHandler.h"
-#include "nsChromeRegistry.h"
-
-NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsChromeRegistry, Init)
-NS_GENERIC_FACTORY_CONSTRUCTOR(nsChromeProtocolHandler)
-
-NS_DEFINE_NAMED_CID(NS_CHROMEREGISTRY_CID);
-NS_DEFINE_NAMED_CID(NS_CHROMEPROTOCOLHANDLER_CID);
-
-static const mozilla::Module::CIDEntry kChromeCIDs[] = {
-    { &kNS_CHROMEREGISTRY_CID, false, NULL, nsChromeRegistryConstructor },
-    { &kNS_CHROMEPROTOCOLHANDLER_CID, false, NULL, nsChromeProtocolHandlerConstructor },
-    { NULL }
-};
-
-static const mozilla::Module::ContractIDEntry kChromeContracts[] = {
-    { NS_CHROMEREGISTRY_CONTRACTID, &kNS_CHROMEREGISTRY_CID },
-    { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "chrome", &kNS_CHROMEPROTOCOLHANDLER_CID },
-    { NULL }
-};
-
-static const mozilla::Module kChromeModule = {
-    mozilla::Module::kVersion,
-    kChromeCIDs,
-    kChromeContracts
-};
-
-NSMODULE_DEFN(nsChromeModule) = &kChromeModule;
-
--- a/chrome/src/nsChromeRegistry.cpp
+++ b/chrome/src/nsChromeRegistry.cpp
@@ -50,16 +50,17 @@
 #elif defined(XP_MACOSX)
 #include <CoreServices/CoreServices.h>
 #elif defined(MOZ_WIDGET_GTK2)
 #include <gtk/gtk.h>
 #endif
 
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsArrayEnumerator.h"
+#include "nsComponentManager.h"
 #include "nsStringEnumerator.h"
 #include "nsEnumeratorUtils.h"
 #include "nsCOMPtr.h"
 #include "nsDOMError.h"
 #include "nsEscape.h"
 #include "nsInt64.h"
 #include "nsLayoutCID.h"
 #include "nsNetCID.h"
@@ -457,27 +458,18 @@ nsresult
 nsChromeRegistry::Init()
 {
   nsresult rv;
 
   // 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
   // to call Components.utils.import("chrome:///") early in registration
-
-  nsCOMPtr<nsIIOService> io (do_GetIOService());
-  if (!io) return NS_ERROR_FAILURE;
-
-  nsCOMPtr<nsIProtocolHandler> ph;
-  rv = io->GetProtocolHandler("jar", getter_AddRefs(ph));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsCOMPtr<nsIJARProtocolHandler> jph = do_QueryInterface(ph);
-  if (!jph)
-    return NS_ERROR_NOT_INITIALIZED;
+  NS_ASSERTION(nsCOMPtr<nsIIOService>(mozilla::services::GetIOService()),
+               "I/O service not registered or available early enough?");
 
   if (!PL_DHashTableInit(&mPackagesHash, &kTableOps,
                          nsnull, sizeof(PackageEntry), 16))
     return NS_ERROR_FAILURE;
 
   if (!mOverlayHash.Init() ||
       !mStyleHash.Init() ||
       !mOverrideTable.Init())
@@ -526,18 +518,16 @@ nsChromeRegistry::Init()
 
   nsCOMPtr<nsIObserverService> obsService =
     mozilla::services::GetObserverService();
   if (obsService) {
     obsService->AddObserver(this, "command-line-startup", PR_TRUE);
     obsService->AddObserver(this, "profile-initial-state", PR_TRUE);
   }
 
-  CheckForNewChrome();
-
   mInitialized = PR_TRUE;
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsChromeRegistry::CheckForOSAccessibility()
 {
@@ -1142,111 +1132,22 @@ static PLDHashOperator
 RemoveAll(PLDHashTable *table, PLDHashEntryHdr *entry, PRUint32 number, void *arg)
 {
   return (PLDHashOperator) (PL_DHASH_NEXT | PL_DHASH_REMOVE);
 }
 
 NS_IMETHODIMP
 nsChromeRegistry::CheckForNewChrome()
 {
-  nsresult rv;
-
   PL_DHashTableEnumerate(&mPackagesHash, RemoveAll, nsnull);
   mOverlayHash.Clear();
   mStyleHash.Clear();
   mOverrideTable.Clear();
 
-  nsCOMPtr<nsIProperties> dirSvc (do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID));
-  NS_ENSURE_TRUE(dirSvc, NS_ERROR_FAILURE);
-
-  // check the extra chrome directories
-  nsCOMPtr<nsISimpleEnumerator> chromeML;
-  rv = dirSvc->Get(NS_CHROME_MANIFESTS_FILE_LIST, NS_GET_IID(nsISimpleEnumerator),
-                   getter_AddRefs(chromeML));
-  if (NS_FAILED(rv)) {
-    // ok, then simply load all .manifest files in the app chrome dir.
-    nsCOMPtr<nsIFile> chromeDir;
-    rv = dirSvc->Get(NS_APP_CHROME_DIR, NS_GET_IID(nsIFile),
-                     getter_AddRefs(chromeDir));
-    if (NS_FAILED(rv))
-      return rv;
-    rv = NS_NewSingletonEnumerator(getter_AddRefs(chromeML), chromeDir);
-    if (NS_FAILED(rv))
-      return rv;
-  }
-
-  PRBool exists;
-  nsCOMPtr<nsISupports> next;
-  while (NS_SUCCEEDED(chromeML->HasMoreElements(&exists)) && exists) {
-    chromeML->GetNext(getter_AddRefs(next));
-    nsCOMPtr<nsILocalFile> lmanifest = do_QueryInterface(next);
-    if (!lmanifest) {
-      NS_ERROR("Directory enumerator returned a non-nsILocalFile");
-      continue;
-    }
-
-    PRBool isDir;
-    if (NS_SUCCEEDED(lmanifest->IsDirectory(&isDir)) && isDir) {
-      nsCOMPtr<nsISimpleEnumerator> entries;
-      rv = lmanifest->GetDirectoryEntries(getter_AddRefs(entries));
-      if (NS_FAILED(rv))
-        continue;
-
-      while (NS_SUCCEEDED(entries->HasMoreElements(&exists)) && exists) {
-        entries->GetNext(getter_AddRefs(next));
-        lmanifest = do_QueryInterface(next);
-        if (lmanifest) {
-          nsCAutoString leafName;
-          lmanifest->GetNativeLeafName(leafName);
-          if (StringEndsWith(leafName, NS_LITERAL_CSTRING(".manifest"))) {
-            rv = ProcessManifest(lmanifest, PR_FALSE);
-            if (NS_FAILED(rv)) {
-              nsCAutoString path;
-              lmanifest->GetNativePath(path);
-              LogMessage("Failed to process chrome manifest '%s'.",
-                         path.get());
-
-            }
-          }
-        }
-      }
-    }
-    else {
-      rv = ProcessManifest(lmanifest, PR_FALSE);
-      if (NS_FAILED(rv)) {
-        nsCAutoString path;
-        lmanifest->GetNativePath(path);
-        LogMessage("Failed to process chrome manifest: '%s'.",
-                   path.get());
-      }
-    }
-  }
-
-  rv = dirSvc->Get(NS_SKIN_MANIFESTS_FILE_LIST, NS_GET_IID(nsISimpleEnumerator),
-                   getter_AddRefs(chromeML));
-  if (NS_FAILED(rv))
-    return NS_OK;
-
-  while (NS_SUCCEEDED(chromeML->HasMoreElements(&exists)) && exists) {
-    chromeML->GetNext(getter_AddRefs(next));
-    nsCOMPtr<nsILocalFile> lmanifest = do_QueryInterface(next);
-    if (!lmanifest) {
-      NS_ERROR("Directory enumerator returned a non-nsILocalFile");
-      continue;
-    }
-
-    rv = ProcessManifest(lmanifest, PR_TRUE);
-    if (NS_FAILED(rv)) {
-      nsCAutoString path;
-      lmanifest->GetNativePath(path);
-      LogMessage("Failed to process chrome manifest: '%s'.",
-                 path.get());
-    }
-  }
-
+  nsComponentManagerImpl::gComponentManager->RereadChromeManifests();
   return NS_OK;
 }
 
 NS_IMETHODIMP_(PRBool)
 nsChromeRegistry::WrappersEnabled(nsIURI *aURI)
 {
   nsCOMPtr<nsIURL> chromeURL (do_QueryInterface(aURI));
   if (!chromeURL)
@@ -1346,822 +1247,288 @@ NS_IMETHODIMP nsChromeRegistry::Observe(
   }
   else {
     NS_ERROR("Unexpected observer topic!");
   }
 
   return rv;
 }
 
-nsresult
-nsChromeRegistry::ProcessManifest(nsILocalFile* aManifest, PRBool aSkinOnly)
+nsIURI*
+nsChromeRegistry::ManifestProcessingContext::GetManifestURI()
 {
-  nsresult rv;
-
-  PRFileDesc* fd;
-  rv = aManifest->OpenNSPRFileDesc(PR_RDONLY, 0, &fd);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  PRInt32 n, size;
-  char *buf;
-
-  size = PR_Available(fd);
-  if (size == -1) {
-    rv = NS_ERROR_UNEXPECTED;
-    goto mend;
-  }
-
-  buf = (char *) malloc(size + 1);
-  if (!buf) {
-    rv = NS_ERROR_OUT_OF_MEMORY;
-    goto mend;
-  }
-
-  n = PR_Read(fd, buf, size);
-  if (n > 0) {
-    buf[size] = '\0';
-    rv = ProcessManifestBuffer(buf, size, aManifest, aSkinOnly);
-  }
-  free(buf);
-
-mend:
-  PR_Close(fd);
-  return rv;
-}
-
-static const char kWhitespace[] = "\t ";
-static const char kNewlines[]   = "\r\n";
+  if (!mManifestURI) {
+    nsCOMPtr<nsIIOService> io = mozilla::services::GetIOService();
+    if (!io) {
+      NS_WARNING("No IO service trying to process chrome manifests");
+      return NULL;
+    }
 
-/**
- * Check for a modifier flag of the following forms:
- *   "flag"   (same as "true")
- *   "flag=yes|true|1"
- *   "flag="no|false|0"
- * @param aFlag The flag to compare.
- * @param aData The tokenized data to check; this is lowercased
- *              before being passed in.
- * @param aResult If the flag is found, the value is assigned here.
- * @return Whether the flag was handled.
- */
-static PRBool
-CheckFlag(const nsSubstring& aFlag, const nsSubstring& aData, PRBool& aResult)
-{
-  if (!StringBeginsWith(aData, aFlag))
-    return PR_FALSE;
-
-  if (aFlag.Length() == aData.Length()) {
-    // the data is simply "flag", which is the same as "flag=yes"
-    aResult = PR_TRUE;
-    return PR_TRUE;
+    io->NewFileURI(mFile, getter_AddRefs(mManifestURI));
   }
-
-  if (aData.CharAt(aFlag.Length()) != '=') {
-    // the data is "flag2=", which is not anything we care about
-    return PR_FALSE;
-  }
-
-  if (aData.Length() == aFlag.Length() + 1) {
-    aResult = PR_FALSE;
-    return PR_TRUE;
-  }
-
-  switch (aData.CharAt(aFlag.Length() + 1)) {
-  case '1':
-  case 't': //true
-  case 'y': //yes
-    aResult = PR_TRUE;
-    return PR_TRUE;
-
-  case '0':
-  case 'f': //false
-  case 'n': //no
-    aResult = PR_FALSE;
-    return PR_TRUE;
-  }
-
-  return PR_FALSE;
+  return mManifestURI;
 }
 
-enum TriState {
-  eUnspecified,
-  eBad,
-  eOK
-};
-
-/**
- * Check for a modifier flag of the following form:
- *   "flag=string"
- *   "flag!=string"
- * @param aFlag The flag to compare.
- * @param aData The tokenized data to check; this is lowercased
- *              before being passed in.
- * @param aValue The value that is expected.
- * @param aResult If this is "ok" when passed in, this is left alone.
- *                Otherwise if the flag is found it is set to eBad or eOK.
- * @return Whether the flag was handled.
- */
-static PRBool
-CheckStringFlag(const nsSubstring& aFlag, const nsSubstring& aData,
-                const nsSubstring& aValue, TriState& aResult)
+nsIXPConnect*
+nsChromeRegistry::ManifestProcessingContext::GetXPConnect()
 {
-  if (aData.Length() < aFlag.Length() + 1)
-    return PR_FALSE;
-
-  if (!StringBeginsWith(aData, aFlag))
-    return PR_FALSE;
+  if (!mXPConnect)
+    mXPConnect = do_GetService("@mozilla.org/js/xpc/XPConnect;1");
 
-  PRBool comparison = PR_TRUE;
-  if (aData[aFlag.Length()] != '=') {
-    if (aData[aFlag.Length()] == '!' &&
-        aData.Length() >= aFlag.Length() + 2 &&
-        aData[aFlag.Length() + 1] == '=')
-      comparison = PR_FALSE;
-    else
-      return PR_FALSE;
-  }
-
-  if (aResult != eOK) {
-    nsDependentSubstring testdata = Substring(aData, aFlag.Length() + (comparison ? 1 : 2));
-    if (testdata.Equals(aValue))
-      aResult = comparison ? eOK : eBad;
-    else
-      aResult = comparison ? eBad : eOK;
-  }
-
-  return PR_TRUE;
+  return mXPConnect;
 }
 
-/**
- * Check for a modifier flag of the following form:
- *   "flag=version"
- *   "flag<=version"
- *   "flag<version"
- *   "flag>=version"
- *   "flag>version"
- * @param aFlag The flag to compare.
- * @param aData The tokenized data to check; this is lowercased
- *              before being passed in.
- * @param aValue The value that is expected. If this is empty then no
- *               comparison will match.
- * @param aChecker the version checker to use. If null, aResult will always
- *                 be eBad.
- * @param aResult If this is eOK when passed in, this is left alone.
- *                Otherwise if the flag is found it is set to eBad or eOK.
- * @return Whether the flag was handled.
- */
-
-#define COMPARE_EQ    1 << 0
-#define COMPARE_LT    1 << 1
-#define COMPARE_GT    1 << 2
-
-static PRBool
-CheckVersionFlag(const nsSubstring& aFlag, const nsSubstring& aData,
-                 const nsSubstring& aValue, nsIVersionComparator* aChecker,
-                 TriState& aResult)
+already_AddRefed<nsIURI>
+nsChromeRegistry::ManifestProcessingContext::ResolveURI(const char* uri)
 {
-  if (aData.Length() < aFlag.Length() + 2)
-    return PR_FALSE;
-
-  if (!StringBeginsWith(aData, aFlag))
-    return PR_FALSE;
-
-  if (aValue.Length() == 0) {
-    if (aResult != eOK)
-      aResult = eBad;
-    return PR_TRUE;
-  }
-
-  PRUint32 comparison;
-  nsAutoString testdata;
-
-  switch (aData[aFlag.Length()]) {
-  case '=':
-    comparison = COMPARE_EQ;
-    testdata = Substring(aData, aFlag.Length() + 1);
-    break;
+  nsIURI* baseuri = GetManifestURI();
+  if (!baseuri)
+    return NULL;
 
-  case '<':
-    if (aData[aFlag.Length() + 1] == '=') {
-      comparison = COMPARE_EQ | COMPARE_LT;
-      testdata = Substring(aData, aFlag.Length() + 2);
-    }
-    else {
-      comparison = COMPARE_LT;
-      testdata = Substring(aData, aFlag.Length() + 1);
-    }
-    break;
-
-  case '>':
-    if (aData[aFlag.Length() + 1] == '=') {
-      comparison = COMPARE_EQ | COMPARE_GT;
-      testdata = Substring(aData, aFlag.Length() + 2);
-    }
-    else {
-      comparison = COMPARE_GT;
-      testdata = Substring(aData, aFlag.Length() + 1);
-    }
-    break;
-
-  default:
-    return PR_FALSE;
-  }
+  nsCOMPtr<nsIURI> resolved;
+  nsresult rv = NS_NewURI(getter_AddRefs(resolved), uri, baseuri);
+  if (NS_FAILED(rv))
+    return NULL;
 
-  if (testdata.Length() == 0)
-    return PR_FALSE;
-
-  if (aResult != eOK) {
-    if (!aChecker) {
-      aResult = eBad;
-    }
-    else {
-      PRInt32 c;
-      nsresult rv = aChecker->Compare(NS_ConvertUTF16toUTF8(aValue),
-                                      NS_ConvertUTF16toUTF8(testdata), &c);
-      if (NS_FAILED(rv)) {
-        aResult = eBad;
-      }
-      else {
-        if ((c == 0 && comparison & COMPARE_EQ) ||
-            (c < 0 && comparison & COMPARE_LT) ||
-            (c > 0 && comparison & COMPARE_GT))
-          aResult = eOK;
-        else
-          aResult = eBad;
-      }
-    }
-  }
-
-  return PR_TRUE;
+  return resolved.forget();
 }
 
 static void
 EnsureLowerCase(char *aBuf)
 {
   for (; *aBuf; ++aBuf) {
     char ch = *aBuf;
     if (ch >= 'A' && ch <= 'Z')
       *aBuf = ch + 'a' - 'A';
   }
 }
 
-nsresult
-nsChromeRegistry::ProcessManifestBuffer(char *buf, PRInt32 length,
-                                        nsILocalFile* aManifest,
-                                        PRBool aSkinOnly)
+void
+nsChromeRegistry::ManifestContent(ManifestProcessingContext& cx, int lineno,
+                                  char *const * argv, bool platform, bool contentaccessible)
 {
-  nsresult rv;
+  char* package = argv[0];
+  char* uri = argv[1];
+
+  EnsureLowerCase(package);
+
+  nsCOMPtr<nsIURI> resolved = cx.ResolveURI(uri);
+  if (!resolved) {
+    LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
+                          "During chrome registration, unable to create URI '%s'.", uri);
+    return;
+  }
+
+  if (!CanLoadResource(resolved)) {
+    LogMessageWithContext(resolved, lineno, nsIScriptError::warningFlag,
+                          "During chrome registration, cannot register non-local URI '%s' as content.",
+                          uri);
+    return;
+  }
+
+  PackageEntry* entry =
+    static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
+                                                    & (const nsACString&) nsDependentCString(package),
+                                                    PL_DHASH_ADD));
+  if (!entry)
+    return;
+
+  entry->baseURI = resolved;
+
+  if (platform)
+    entry->flags |= PackageEntry::PLATFORM_PACKAGE;
+  if (contentaccessible)
+    entry->flags |= PackageEntry::CONTENT_ACCESSIBLE;
+  if (cx.GetXPConnect()) {
+    nsCAutoString urlp("chrome://");
+    urlp.Append(package);
+    urlp.Append('/');
+
+    cx.GetXPConnect()->FlagSystemFilenamePrefix(urlp.get(), true);
+  }
+}
+
+void
+nsChromeRegistry::ManifestLocale(ManifestProcessingContext& cx, int lineno,
+                                 char *const * argv, bool platform, bool contentaccessible)
+{
+  char* package = argv[0];
+  char* provider = argv[1];
+  char* uri = argv[2];
+
+  EnsureLowerCase(package);
+
+  nsCOMPtr<nsIURI> resolved = cx.ResolveURI(uri);
+  if (!resolved) {
+    LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
+                          "During chrome registration, unable to create URI '%s'.", uri);
+    return;
+  }
+
+  if (!CanLoadResource(resolved)) {
+    LogMessageWithContext(resolved, lineno, nsIScriptError::warningFlag,
+                          "During chrome registration, cannot register non-local URI '%s' as content.",
+                          uri);
+    return;
+  }
+
+  PackageEntry* entry =
+    static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
+                                                    & (const nsACString&) nsDependentCString(package),
+                                                    PL_DHASH_ADD));
+  if (!entry)
+    return;
+
+  entry->locales.SetBase(nsDependentCString(provider), resolved);
+}
+
+void
+nsChromeRegistry::ManifestSkin(ManifestProcessingContext& cx, int lineno,
+                               char *const * argv, bool platform, bool contentaccessible)
+{
+  char* package = argv[0];
+  char* provider = argv[1];
+  char* uri = argv[2];
+
+  EnsureLowerCase(package);
+
+  nsCOMPtr<nsIURI> resolved = cx.ResolveURI(uri);
+  if (!resolved) {
+    LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
+                          "During chrome registration, unable to create URI '%s'.", uri);
+    return;
+  }
 
-  NS_NAMED_LITERAL_STRING(kPlatform, "platform");
-  NS_NAMED_LITERAL_STRING(kContentAccessible, "contentaccessible");
-  NS_NAMED_LITERAL_STRING(kApplication, "application");
-  NS_NAMED_LITERAL_STRING(kAppVersion, "appversion");
-  NS_NAMED_LITERAL_STRING(kOs, "os");
-  NS_NAMED_LITERAL_STRING(kOsVersion, "osversion");
+  if (!CanLoadResource(resolved)) {
+    LogMessageWithContext(resolved, lineno, nsIScriptError::warningFlag,
+                          "During chrome registration, cannot register non-local URI '%s' as content.",
+                          uri);
+    return;
+  }
+
+  PackageEntry* entry =
+    static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
+                                                    & (const nsACString&) nsDependentCString(package),
+                                                    PL_DHASH_ADD));
+  if (!entry)
+    return;
+
+  entry->skins.SetBase(nsDependentCString(provider), resolved);
+}
+
+void
+nsChromeRegistry::ManifestOverlay(ManifestProcessingContext& cx, int lineno,
+                                  char *const * argv, bool platform, bool contentaccessible)
+{
+  char* base = argv[0];
+  char* overlay = argv[1];
+
+  nsCOMPtr<nsIURI> baseuri = cx.ResolveURI(base);
+  nsCOMPtr<nsIURI> overlayuri = cx.ResolveURI(overlay);
+  if (!baseuri || !overlayuri) {
+    LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
+                          "During chrome registration, unable to create URI.");
+    return;
+  }
+
+  if (!CanLoadResource(overlayuri)) {
+    LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
+                          "Cannot register non-local URI '%s' as an overlay.", overlay);
+    return;
+  }
+
+  mOverlayHash.Add(baseuri, overlayuri);
+}
+
+void
+nsChromeRegistry::ManifestStyle(ManifestProcessingContext& cx, int lineno,
+                                char *const * argv, bool platform, bool contentaccessible)
+{
+  char* base = argv[0];
+  char* overlay = argv[1];
 
-  nsCOMPtr<nsIIOService> io (do_GetIOService());
-  if (!io) return NS_ERROR_FAILURE;
+  nsCOMPtr<nsIURI> baseuri = cx.ResolveURI(base);
+  nsCOMPtr<nsIURI> overlayuri = cx.ResolveURI(overlay);
+  if (!baseuri || !overlayuri) {
+    LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
+                          "During chrome registration, unable to create URI.");
+    return;
+  }
+
+  if (!CanLoadResource(overlayuri)) {
+    LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
+                          "Cannot register non-local URI '%s' as a style overlay.", overlay);
+    return;
+  }
+
+  mStyleHash.Add(baseuri, overlayuri);
+}
+
+void
+nsChromeRegistry::ManifestOverride(ManifestProcessingContext& cx, int lineno,
+                                   char *const * argv, bool platform, bool contentaccessible)
+{
+  char* chrome = argv[0];
+  char* resolved = argv[1];
+
+  nsCOMPtr<nsIURI> chromeuri = cx.ResolveURI(chrome);
+  nsCOMPtr<nsIURI> resolveduri = cx.ResolveURI(resolved);
+  if (!chromeuri || !resolveduri) {
+    LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
+                          "During chrome registration, unable to create URI.");
+    return;
+  }
+
+  if (!CanLoadResource(resolveduri)) {
+    LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
+                          "Cannot register non-local URI '%s' for an override.", resolved);
+    return;
+  }
+  mOverrideTable.Put(chromeuri, resolveduri);
+}
+
+void
+nsChromeRegistry::ManifestResource(ManifestProcessingContext& cx, int lineno,
+                                   char *const * argv, bool platform, bool contentaccessible)
+{
+  char* package = argv[0];
+  char* uri = argv[1];
+
+  EnsureLowerCase(package);
+  nsDependentCString host(package);
+
+  nsCOMPtr<nsIIOService> io = mozilla::services::GetIOService();
+  if (!io) {
+    NS_WARNING("No IO service trying to process chrome manifests");
+    return;
+  }
 
   nsCOMPtr<nsIProtocolHandler> ph;
-  rv = io->GetProtocolHandler("resource", getter_AddRefs(ph));
-  NS_ENSURE_SUCCESS(rv, rv);
-  
-  nsCOMPtr<nsIResProtocolHandler> rph (do_QueryInterface(ph));
-  if (!rph) return NS_ERROR_FAILURE;
-
-  nsCOMPtr<nsIURI> manifestURI;
-  rv = io->NewFileURI(aManifest, getter_AddRefs(manifestURI));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsCOMPtr<nsIXPConnect> xpc (do_GetService("@mozilla.org/js/xpc/XPConnect;1"));
-  nsCOMPtr<nsIVersionComparator> vc (do_GetService("@mozilla.org/xpcom/version-comparator;1"));
-
-  nsAutoString appID;
-  nsAutoString appVersion;
-  nsAutoString osTarget;
-  nsCOMPtr<nsIXULAppInfo> xapp (do_GetService(XULAPPINFO_SERVICE_CONTRACTID));
-  if (xapp) {
-    nsCAutoString s;
-    rv = xapp->GetID(s);
-    if (NS_SUCCEEDED(rv))
-      CopyUTF8toUTF16(s, appID);
-
-    rv = xapp->GetVersion(s);
-    if (NS_SUCCEEDED(rv))
-      CopyUTF8toUTF16(s, appVersion);
-    
-    nsCOMPtr<nsIXULRuntime> xruntime (do_QueryInterface(xapp));
-    if (xruntime) {
-      rv = xruntime->GetOS(s);
-      if (NS_SUCCEEDED(rv)) {
-        CopyUTF8toUTF16(s, osTarget);
-        ToLowerCase(osTarget);
-      }
-    }
-  }
+  nsresult rv = io->GetProtocolHandler("resource", getter_AddRefs(ph));
+  if (NS_FAILED(rv))
+    return;
   
-  nsAutoString osVersion;
-#if defined(XP_WIN)
-  OSVERSIONINFO info = { sizeof(OSVERSIONINFO) };
-  if (GetVersionEx(&info)) {
-    nsTextFormatter::ssprintf(osVersion, NS_LITERAL_STRING("%ld.%ld").get(),
-                                         info.dwMajorVersion,
-                                         info.dwMinorVersion);
-  }
-#elif defined(XP_MACOSX)
-  SInt32 majorVersion, minorVersion;
-  if ((Gestalt(gestaltSystemVersionMajor, &majorVersion) == noErr) &&
-      (Gestalt(gestaltSystemVersionMinor, &minorVersion) == noErr)) {
-    nsTextFormatter::ssprintf(osVersion, NS_LITERAL_STRING("%ld.%ld").get(),
-                                         majorVersion,
-                                         minorVersion);
-  }
-#elif defined(MOZ_WIDGET_GTK2)
-  nsTextFormatter::ssprintf(osVersion, NS_LITERAL_STRING("%ld.%ld").get(),
-                                       gtk_major_version,
-                                       gtk_minor_version);
-#endif
-
-  char *token;
-  char *newline = buf;
-  PRUint32 line = 0;
-
-  // outer loop tokenizes by newline
-  while (nsnull != (token = nsCRT::strtok(newline, kNewlines, &newline))) {
-    ++line;
-
-    if (*token == '#') // ignore lines that begin with # as comments
-      continue;
-
-    char *whitespace = token;
-    token = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
-    if (!token) continue;
-
-    if (!strcmp(token, "content")) {
-      if (aSkinOnly) {
-        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
-                              "Warning: Ignoring content registration in skin-only manifest.");
-        continue;
-      }
-      char *package = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
-      char *uri     = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
-      if (!package || !uri) {
-        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
-                              "Warning: Malformed content registration.");
-        continue;
-      }
-
-      EnsureLowerCase(package);
-
-      // NOTE: We check for platform modifiers on content packages, but they
-      // are *applied* to content|skin|locale.
-
-      PRBool platform = PR_FALSE;
-      PRBool contentAccessible = PR_FALSE;
-      TriState stAppVersion = eUnspecified;
-      TriState stApp = eUnspecified;
-      TriState stOsVersion = eUnspecified;
-      TriState stOs = eUnspecified;
-
-      PRBool badFlag = PR_FALSE;
-
-      while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
-             !badFlag) {
-        NS_ConvertASCIItoUTF16 wtoken(token);
-        ToLowerCase(wtoken);
-
-        if (CheckFlag(kPlatform, wtoken, platform) ||
-            CheckFlag(kContentAccessible, wtoken, contentAccessible) ||
-            CheckStringFlag(kApplication, wtoken, appID, stApp) ||
-            CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
-            CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
-            CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
-          continue;
-
-        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
-                              "Warning: Unrecognized chrome registration modifier '%s'.",
-                              token);
-        badFlag = PR_TRUE;
-      }
-
-      if (badFlag || stApp == eBad || stAppVersion == eBad || 
-          stOs == eBad || stOsVersion == eBad)
-        continue;
-
-      nsCOMPtr<nsIURI> resolved;
-      rv = io->NewURI(nsDependentCString(uri), nsnull, manifestURI,
-                      getter_AddRefs(resolved));
-      if (NS_FAILED(rv))
-        continue;
-
-      if (!CanLoadResource(resolved)) {
-        LogMessageWithContext(resolved, line, nsIScriptError::warningFlag,
-                              "Warning: cannot register non-local URI '%s' as content.",
-                              uri);
-        continue;
-      }
-
-      PackageEntry* entry =
-        static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
-                                                            & (const nsACString&) nsDependentCString(package),
-                                                            PL_DHASH_ADD));
-      if (!entry)
-        return NS_ERROR_OUT_OF_MEMORY;
-
-      entry->baseURI = resolved;
-
-      if (platform)
-        entry->flags |= PackageEntry::PLATFORM_PACKAGE;
-      if (contentAccessible)
-        entry->flags |= PackageEntry::CONTENT_ACCESSIBLE;
-      if (xpc) {
-        nsCAutoString urlp("chrome://");
-        urlp.Append(package);
-        urlp.Append('/');
-
-        rv = xpc->FlagSystemFilenamePrefix(urlp.get(), true);
-        NS_ENSURE_SUCCESS(rv, rv);
-      }
-    }
-    else if (!strcmp(token, "locale")) {
-      if (aSkinOnly) {
-        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
-                              "Warning: Ignoring locale registration in skin-only manifest.");
-        continue;
-      }
-      char *package  = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
-      char *provider = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
-      char *uri      = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
-      if (!package || !provider || !uri) {
-        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
-                              "Warning: Malformed locale registration.");
-        continue;
-      }
-
-      EnsureLowerCase(package);
-
-      TriState stAppVersion = eUnspecified;
-      TriState stApp = eUnspecified;
-      TriState stOs = eUnspecified;
-      TriState stOsVersion = eUnspecified;
-
-      PRBool badFlag = PR_FALSE;
-
-      while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
-             !badFlag) {
-        NS_ConvertASCIItoUTF16 wtoken(token);
-        ToLowerCase(wtoken);
-
-        if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
-            CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
-            CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
-            CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
-          continue;
-
-        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
-                              "Warning: Unrecognized chrome registration modifier '%s'.",
-                              token);
-        badFlag = PR_TRUE;
-      }
-
-      if (badFlag || stApp == eBad || stAppVersion == eBad ||
-          stOs == eBad || stOsVersion == eBad)
-        continue;
-
-      nsCOMPtr<nsIURI> resolved;
-      rv = io->NewURI(nsDependentCString(uri), nsnull, manifestURI,
-                      getter_AddRefs(resolved));
-      if (NS_FAILED(rv))
-        continue;
-
-      if (!CanLoadResource(resolved)) {
-        LogMessageWithContext(resolved, line, nsIScriptError::warningFlag,
-                              "Warning: cannot register non-local URI '%s' as a locale.",
-                              uri);
-        continue;
-      }
-
-      PackageEntry* entry =
-        static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
-                                                            & (const nsACString&) nsDependentCString(package),
-                                                            PL_DHASH_ADD));
-      if (!entry)
-        return NS_ERROR_OUT_OF_MEMORY;
-
-      entry->locales.SetBase(nsDependentCString(provider), resolved);
-    }
-    else if (!strcmp(token, "skin")) {
-      char *package  = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
-      char *provider = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
-      char *uri      = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
-      if (!package || !provider || !uri) {
-        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
-                              "Warning: Malformed skin registration.");
-        continue;
-      }
-
-      EnsureLowerCase(package);
-
-      TriState stAppVersion = eUnspecified;
-      TriState stApp = eUnspecified;
-      TriState stOs = eUnspecified;
-      TriState stOsVersion = eUnspecified;
-
-      PRBool badFlag = PR_FALSE;
-
-      while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
-             !badFlag) {
-        NS_ConvertASCIItoUTF16 wtoken(token);
-        ToLowerCase(wtoken);
-
-        if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
-            CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
-            CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
-            CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
-          continue;
-
-        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
-                              "Warning: Unrecognized chrome registration modifier '%s'.",
-                              token);
-        badFlag = PR_TRUE;
-      }
-
-      if (badFlag || stApp == eBad || stAppVersion == eBad ||
-          stOs == eBad || stOsVersion == eBad)
-        continue;
+  nsCOMPtr<nsIResProtocolHandler> rph = do_QueryInterface(ph);
 
-      nsCOMPtr<nsIURI> resolved;
-      rv = io->NewURI(nsDependentCString(uri), nsnull, manifestURI,
-                      getter_AddRefs(resolved));
-      if (NS_FAILED(rv))
-        continue;
-
-      if (!CanLoadResource(resolved)) {
-        LogMessageWithContext(resolved, line, nsIScriptError::warningFlag,
-                              "Warning: cannot register non-local URI '%s' as a skin.",
-                              uri);
-        continue;
-      }
-
-      PackageEntry* entry =
-        static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
-                                                            & (const nsACString&) nsDependentCString(package),
-                                                            PL_DHASH_ADD));
-      if (!entry)
-        return NS_ERROR_OUT_OF_MEMORY;
-
-      entry->skins.SetBase(nsDependentCString(provider), resolved);
-    }
-    else if (!strcmp(token, "overlay")) {
-      if (aSkinOnly) {
-        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
-                              "Warning: Ignoring overlay registration in skin-only manifest.");
-        continue;
-      }
-      char *base    = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
-      char *overlay = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
-      if (!base || !overlay) {
-        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
-                              "Warning: malformed chrome overlay instruction.");
-        continue;
-      }
-
-      TriState stAppVersion = eUnspecified;
-      TriState stApp = eUnspecified;
-      TriState stOs = eUnspecified;
-      TriState stOsVersion = eUnspecified;
-
-      PRBool badFlag = PR_FALSE;
-
-      while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
-             !badFlag) {
-        NS_ConvertASCIItoUTF16 wtoken(token);
-        ToLowerCase(wtoken);
-
-        if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
-            CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
-            CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
-            CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
-          continue;
-
-        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
-                              "Warning: Unrecognized chrome registration modifier '%s'.",
-                              token);
-        badFlag = PR_TRUE;
-      }
-
-      if (badFlag || stApp == eBad || stAppVersion == eBad ||
-          stOs == eBad || stOsVersion == eBad)
-        continue;
-
-      nsCOMPtr<nsIURI> baseuri, overlayuri;
-      rv  = io->NewURI(nsDependentCString(base), nsnull, nsnull,
-                       getter_AddRefs(baseuri));
-      rv |= io->NewURI(nsDependentCString(overlay), nsnull, nsnull,
-                       getter_AddRefs(overlayuri));
-      if (NS_FAILED(rv)) {
-        NS_WARNING("Could not make URIs for overlay directive. Ignoring.");
-        continue;
-      }
-
-      if (!CanLoadResource(overlayuri)) {
-        LogMessageWithContext(overlayuri, line, nsIScriptError::warningFlag,
-                              "Warning: cannot register non-local URI '%s' as an overlay.",
-                              overlay);
-        continue;
-      }
-
-      mOverlayHash.Add(baseuri, overlayuri);
-    }
-    else if (!strcmp(token, "style")) {
-      char *base    = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
-      char *overlay = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
-      if (!base || !overlay) {
-        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
-                              "Warning: malformed chrome style instruction.");
-        continue;
-      }
-
-      TriState stAppVersion = eUnspecified;
-      TriState stApp = eUnspecified;
-      TriState stOs = eUnspecified;
-      TriState stOsVersion = eUnspecified;
-
-      PRBool badFlag = PR_FALSE;
-
-      while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
-             !badFlag) {
-        NS_ConvertASCIItoUTF16 wtoken(token);
-        ToLowerCase(wtoken);
-
-        if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
-            CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
-            CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
-            CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
-          continue;
-
-        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
-                              "Warning: Unrecognized chrome registration modifier '%s'.",
-                              token);
-        badFlag = PR_TRUE;
-      }
-
-      if (badFlag || stApp == eBad || stAppVersion == eBad ||
-          stOs == eBad || stOsVersion == eBad)
-        continue;
-
-      nsCOMPtr<nsIURI> baseuri, overlayuri;
-      rv  = io->NewURI(nsDependentCString(base), nsnull, nsnull,
-                      getter_AddRefs(baseuri));
-      rv |= io->NewURI(nsDependentCString(overlay), nsnull, nsnull,
-                       getter_AddRefs(overlayuri));
-      if (NS_FAILED(rv))
-        continue;
-
-      if (!CanLoadResource(overlayuri)) {
-        LogMessageWithContext(overlayuri, line, nsIScriptError::warningFlag,
-                              "Warning: cannot register non-local URI '%s' as a style overlay.",
-                              overlay);
-        continue;
-      }
-
-      mStyleHash.Add(baseuri, overlayuri);
-    }
-    else if (!strcmp(token, "override")) {
-      if (aSkinOnly) {
-        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
-                              "Warning: Ignoring override registration in skin-only manifest.");
-        continue;
-      }
-
-      char *chrome    = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
-      char *resolved  = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
-      if (!chrome || !resolved) {
-        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
-                              "Warning: malformed chrome override instruction.");
-        continue;
-      }
-
-      TriState stAppVersion = eUnspecified;
-      TriState stApp = eUnspecified;
-      TriState stOs = eUnspecified;
-      TriState stOsVersion = eUnspecified;
-
-      PRBool badFlag = PR_FALSE;
-
-      while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
-             !badFlag) {
-        NS_ConvertASCIItoUTF16 wtoken(token);
-        ToLowerCase(wtoken);
-
-        if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
-            CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
-            CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
-            CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
-          continue;
-
-        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
-                              "Warning: Unrecognized chrome registration modifier '%s'.",
-                              token);
-        badFlag = PR_TRUE;
-      }
-
-      if (badFlag || stApp == eBad || stAppVersion == eBad ||
-          stOs == eBad || stOsVersion == eBad)
-        continue;
-
-      nsCOMPtr<nsIURI> chromeuri, resolveduri;
-      rv  = io->NewURI(nsDependentCString(chrome), nsnull, nsnull,
-                      getter_AddRefs(chromeuri));
-      rv |= io->NewURI(nsDependentCString(resolved), nsnull, manifestURI,
-                       getter_AddRefs(resolveduri));
-      if (NS_FAILED(rv))
-        continue;
-
-      if (!CanLoadResource(resolveduri)) {
-        LogMessageWithContext(resolveduri, line, nsIScriptError::warningFlag,
-                              "Warning: cannot register non-local URI '%s' as an override.",
-                              resolved);
-        continue;
-      }
-
-      mOverrideTable.Put(chromeuri, resolveduri);
-    }
-    else if (!strcmp(token, "resource")) {
-      if (aSkinOnly) {
-        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
-                              "Warning: Ignoring resource registration in skin-only manifest.");
-        continue;
-      }
-
-      char *package = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
-      char *uri     = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
-      if (!package || !uri) {
-        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
-                              "Warning: Malformed resource registration.");
-        continue;
-      }
-
-      EnsureLowerCase(package);
-
-      TriState stAppVersion = eUnspecified;
-      TriState stApp = eUnspecified;
-      TriState stOsVersion = eUnspecified;
-      TriState stOs = eUnspecified;
-
-      PRBool badFlag = PR_FALSE;
-
-      while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
-             !badFlag) {
-        NS_ConvertASCIItoUTF16 wtoken(token);
-        ToLowerCase(wtoken);
-
-        if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
-            CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
-            CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
-            CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
-          continue;
-
-        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
-                              "Warning: Unrecognized chrome registration modifier '%s'.",
-                              token);
-        badFlag = PR_TRUE;
-      }
-
-      if (badFlag || stApp == eBad || stAppVersion == eBad || 
-          stOs == eBad || stOsVersion == eBad)
-        continue;
-      
-      nsDependentCString host(package);
-
-      PRBool exists;
-      rv = rph->HasSubstitution(host, &exists);
-      NS_ENSURE_SUCCESS(rv, rv);
-      if (exists) {
-        LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
-                              "Warning: Duplicate resource declaration for '%s' ignored.",
-                              package);
-        continue;
-      }
-
-      nsCOMPtr<nsIURI> resolved;
-      rv = io->NewURI(nsDependentCString(uri), nsnull, manifestURI,
-                      getter_AddRefs(resolved));
-      if (NS_FAILED(rv))
-        continue;
-
-      if (!CanLoadResource(resolved)) {
-        LogMessageWithContext(resolved, line, nsIScriptError::warningFlag,
-                              "Warning: cannot register non-local URI '%s' as a resource.",
-                              uri);
-        continue;
-      }
-
-      rv = rph->SetSubstitution(host, resolved);
-      NS_ENSURE_SUCCESS(rv, rv);
-    }
-    else {
-      LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
-                            "Warning: Ignoring unrecognized chrome manifest instruction.");
-    }
+  PRBool exists = PR_FALSE;
+  rv = rph->HasSubstitution(host, &exists);
+  if (exists) {
+    LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
+                          "Duplicate resource declaration for '%s' ignored.", package);
+    return;
   }
 
-  return NS_OK;
+  nsCOMPtr<nsIURI> resolved = cx.ResolveURI(uri);
+  if (!resolved) {
+    LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
+                          "During chrome registration, unable to create URI '%s'.", uri);
+    return;
+  }
+
+  if (!CanLoadResource(resolved)) {
+    LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
+                          "Warning: cannot register non-local URI '%s' as a resource.",
+                          uri);
+    return;
+  }
+
+  rph->SetSubstitution(host, resolved);
 }
--- a/chrome/src/nsChromeRegistry.h
+++ b/chrome/src/nsChromeRegistry.h
@@ -50,16 +50,19 @@
 
 #include "nsCOMArray.h"
 #include "nsString.h"
 #include "nsTHashtable.h"
 #include "nsURIHashKey.h"
 #include "nsVoidArray.h"
 #include "nsTArray.h"
 #include "nsInterfaceHashtable.h"
+#include "nsXULAppAPI.h"
+#include "nsIResProtocolHandler.h"
+#include "nsIXPConnect.h"
 
 struct PRFileDesc;
 class nsIAtom;
 class nsIDOMWindowInternal;
 class nsILocalFile;
 class nsIPrefBranch;
 class nsIRDFDataSource;
 class nsIRDFResource;
@@ -116,29 +119,51 @@ protected:
 
 private:
   nsresult SelectLocaleFromPref(nsIPrefBranch* prefs);
 
   static nsresult RefreshWindow(nsIDOMWindowInternal* aWindow);
   static nsresult GetProviderAndPath(nsIURL* aChromeURL,
                                      nsACString& aProvider, nsACString& aPath);
 
-#ifdef MOZ_XUL
-  NS_HIDDEN_(void) ProcessProvider(PRFileDesc *fd, nsIRDFService* aRDFs,
-                                   nsIRDFDataSource* ds, nsIRDFResource* aRoot,
-                                   PRBool aIsLocale, const nsACString& aBaseURL);
-  NS_HIDDEN_(void) ProcessOverlays(PRFileDesc *fd, nsIRDFDataSource* ds,
-                                   nsIRDFResource* aRoot,
-                                   const nsCSubstring& aType);
-#endif
+public:
+  struct ManifestProcessingContext
+  {
+    ManifestProcessingContext(NSLocationType aType, nsILocalFile* aFile)
+      : mType(aType)
+      , mFile(aFile)
+    { }
+    ~ManifestProcessingContext()
+    { }
+
+    nsIURI* GetManifestURI();
+    nsIXPConnect* GetXPConnect();
+
+    already_AddRefed<nsIURI> ResolveURI(const char* uri);
 
-  NS_HIDDEN_(nsresult) ProcessManifest(nsILocalFile* aManifest, PRBool aSkinOnly);
-  NS_HIDDEN_(nsresult) ProcessManifestBuffer(char *aBuffer, PRInt32 aLength, nsILocalFile* aManifest, PRBool aSkinOnly);
-  NS_HIDDEN_(nsresult) ProcessNewChromeFile(nsILocalFile *aListFile, nsIURI* aManifest);
-  NS_HIDDEN_(nsresult) ProcessNewChromeBuffer(char *aBuffer, PRInt32 aLength, nsIURI* aManifest);
+    NSLocationType mType;
+    nsCOMPtr<nsILocalFile> mFile;
+    nsCOMPtr<nsIURI> mManifestURI;
+    nsCOMPtr<nsIXPConnect> mXPConnect;
+  };
+
+  void ManifestContent(ManifestProcessingContext& cx, int lineno,
+                       char *const * argv, bool platform, bool contentaccessible);
+  void ManifestLocale(ManifestProcessingContext& cx, int lineno,
+                      char *const * argv, bool platform, bool contentaccessible);
+  void ManifestSkin(ManifestProcessingContext& cx, int lineno,
+                    char *const * argv, bool platform, bool contentaccessible);
+  void ManifestOverlay(ManifestProcessingContext& cx, int lineno,
+                       char *const * argv, bool platform, bool contentaccessible);
+  void ManifestStyle(ManifestProcessingContext& cx, int lineno,
+                     char *const * argv, bool platform, bool contentaccessible);
+  void ManifestOverride(ManifestProcessingContext& cx, int lineno,
+                        char *const * argv, bool platform, bool contentaccessible);
+  void ManifestResource(ManifestProcessingContext& cx, int lineno,
+                        char *const * argv, bool platform, bool contentaccessible);
 
 public:
   struct ProviderEntry
   {
     ProviderEntry(const nsACString& aProvider, nsIURI* aBase) :
       provider(aProvider),
       baseURI(aBase) { }
 
--- a/js/src/xpconnect/loader/mozJSComponentLoader.cpp
+++ b/js/src/xpconnect/loader/mozJSComponentLoader.cpp
@@ -750,57 +750,55 @@ mozJSComponentLoader::LoadModule(nsILoca
 
     rv = file_holder->GetJSObject(&file_jsobj);
     if (NS_FAILED(rv)) {
         return NULL;
     }
 
     JSCLAutoErrorReporterSetter aers(cx, mozJSLoaderErrorReporter);
 
-    jsval argv[2], retval, NSGetFactory_val;
+    jsval NSGetFactory_val;
 
     if (!JS_GetProperty(cx, entry->global, "NSGetFactory", &NSGetFactory_val) ||
         JSVAL_IS_VOID(NSGetFactory_val)) {
         return NULL;
     }
 
     if (JS_TypeOfValue(cx, NSGetFactory_val) != JSTYPE_FUNCTION) {
         nsCAutoString path;
         aComponentFile->GetNativePath(path);
 
         JS_ReportError(cx, "%s has NSGetFactory property that is not a function",
                        path.get());
         return NULL;
     }
     
     JSObject *jsGetFactoryObj;
-    if (!JS_ValueToObject(cx, retval, &jsGetFactoryObj) ||
+    if (!JS_ValueToObject(cx, NSGetFactory_val, &jsGetFactoryObj) ||
         !jsGetFactoryObj) {
         /* XXX report error properly */
         return NULL;
     }
 
     rv = xpc->WrapJS(cx, jsGetFactoryObj,
-                     NS_GET_IID(xpcIJSGetFactory), getter_AddRefs(entry->getfactory));
+                     NS_GET_IID(xpcIJSGetFactory), getter_AddRefs(entry->getfactoryobj));
     if (NS_FAILED(rv)) {
         /* XXX report error properly */
 #ifdef DEBUG
         fprintf(stderr, "mJCL: couldn't get nsIModule from jsval\n");
 #endif
         return NULL;
     }
 
     // Cache this module for later
     if (!mModules.Put(lfhash, entry))
         return NULL;
 
     // The hash owns the ModuleEntry now, forget about it
-    entry.forget();
-
-    return entry;
+    return entry.forget();
 }
 
 // Some stack based classes for cleaning up on early return
 #ifdef HAVE_PR_MEMMAP
 class FileAutoCloser
 {
  public:
     explicit FileAutoCloser(PRFileDesc *file) : mFile(file) {}
@@ -1372,24 +1370,32 @@ mozJSComponentLoader::GlobalForLocation(
         *aGlobal = nsnull;
         return NS_ERROR_OUT_OF_MEMORY;
     }
 
     JS_AddNamedRoot(cx, aGlobal, *aLocation);
     return NS_OK;
 }
 
+/* static */ PLDHashOperator
+mozJSComponentLoader::ClearModules(nsIHashable* key, ModuleEntry*& entry, void* cx)
+{
+    entry->Clear();
+    return PL_DHASH_REMOVE;
+}
+    
 void
 mozJSComponentLoader::UnloadModules()
 {
     mInitialized = PR_FALSE;
 
     mInProgressImports.Clear();
     mImports.Clear();
-    mModules.Clear();
+
+    mModules.Enumerate(ClearModules, NULL);
 
     // Destroying our context will force a GC.
     JS_DestroyContext(mContext);
     mContext = nsnull;
 
     mRuntimeService = nsnull;
     mContextStack = nsnull;
 #ifdef DEBUG_shaver_off
@@ -1655,16 +1661,31 @@ mozJSComponentLoader::Observe(nsISupport
     }
     else {
         NS_ERROR("Unexpected observer topic.");
     }
 
     return NS_OK;
 }
 
+/* static */ already_AddRefed<nsIFactory>
+mozJSComponentLoader::ModuleEntry::GetFactory(const mozilla::Module& module,
+                                              const mozilla::Module::CIDEntry& entry)
+{
+    const ModuleEntry& self = static_cast<const ModuleEntry&>(module);
+    NS_ASSERTION(self.getfactoryobj, "Handing out an uninitialized module?");
+
+    nsCOMPtr<nsIFactory> f;
+    nsresult rv = self.getfactoryobj->Get(*entry.cid, getter_AddRefs(f));
+    if (NS_FAILED(rv))
+        return NULL;
+
+    return f.forget();
+}
+
 //----------------------------------------------------------------------
 
 JSCLContextHelper::JSCLContextHelper(mozJSComponentLoader *loader)
     : mContext(loader->mContext), mContextThread(0),
       mContextStack(loader->mContextStack)
 {
     mContextStack->Push(mContext);
     mContextThread = JS_GetContextThread(mContext);
--- a/js/src/xpconnect/loader/mozJSComponentLoader.h
+++ b/js/src/xpconnect/loader/mozJSComponentLoader.h
@@ -137,42 +137,59 @@ class mozJSComponentLoader : public mozi
 #endif
     JSRuntime *mRuntime;
     JSContext *mContext;
 
     class ModuleEntry : public mozilla::Module
     {
     public:
         ModuleEntry() : mozilla::Module() {
-            
+            mVersion = mozilla::Module::kVersion;
+            mCIDs = NULL;
+            mContractIDs = NULL;
+            mCategoryEntries = NULL;
+            getfactory = GetFactory;
+            loaded = NULL;
+            unloaded = NULL;
+
             global = nsnull;
             location = nsnull;
         }
 
         ~ModuleEntry() {
-            getfactory = NULL;
+            Clear();
+        }
+
+        void Clear() {
+            getfactoryobj = NULL;
 
             if (global) {
                 JSAutoRequest ar(sSelf->mContext);
                 JS_ClearScope(sSelf->mContext, global);
                 JS_RemoveRoot(sSelf->mContext, &global);
             }
 
             if (location)
                 NS_Free(location);
+
+            global = NULL;
+            location = NULL;
         }
 
         static already_AddRefed<nsIFactory> GetFactory(const mozilla::Module& module,
                                                        const mozilla::Module::CIDEntry& entry);
 
-        nsCOMPtr<xpcIJSGetFactory> getfactory;
+        nsCOMPtr<xpcIJSGetFactory> getfactoryobj;
         JSObject            *global;
         char                *location;
     };
 
     friend class ModuleEntry;
 
-    nsClassHashtable<nsHashableHashKey, ModuleEntry> mModules;
+    // Modules are intentionally leaked, but still cleared.
+    static PLDHashOperator ClearModules(nsIHashable* key, ModuleEntry*& entry, void* cx);
+    nsDataHashtable<nsHashableHashKey, ModuleEntry*> mModules;
+
     nsClassHashtable<nsHashableHashKey, ModuleEntry> mImports;
     nsDataHashtable<nsHashableHashKey, ModuleEntry*> mInProgressImports;
 
     PRBool mInitialized;
 };
--- a/toolkit/library/libxul-config.mk
+++ b/toolkit/library/libxul-config.mk
@@ -139,17 +139,16 @@ COMPONENT_LIBS += \
 	htmlpars \
 	imglib2 \
 	gklayout \
 	docshell \
 	embedcomponents \
 	webbrwsr \
 	nsappshell \
 	txmgr \
-	chrome \
 	commandlines \
 	extensions \
 	toolkitcomps \
 	pipboot \
 	pipnss \
 	appcomps \
 	$(NULL)
 
--- a/toolkit/library/nsStaticXULComponents.cpp
+++ b/toolkit/library/nsStaticXULComponents.cpp
@@ -247,17 +247,16 @@
     MODULE(nsLayoutModule)                   \
     MODULE(docshell_provider)                \
     MODULE(embedcomponents)                  \
     MODULE(Browser_Embedding_Module)         \
     ACCESS_MODULES                           \
     MODULE(appshell)                         \
     MODULE(nsTransactionManagerModule)       \
     COMPOSER_MODULE                          \
-    MODULE(nsChromeModule)                   \
     MODULE(application)                      \
     MODULE(Apprunner)                        \
     MODULE(CommandLineModule)                \
     FILEVIEW_MODULE                          \
     STORAGE_MODULE                           \
     PLACES_MODULES                           \
     XULENABLED_MODULES                       \
     MODULE(AddonsModule)                     \
--- a/toolkit/toolkit-tiers.mk
+++ b/toolkit/toolkit-tiers.mk
@@ -195,17 +195,17 @@ endif
 ifdef ACCESSIBILITY
 tier_platform_dirs    += accessible
 endif
 
 #
 # "toolkit" - xpfe & toolkit
 #
 
-tier_platform_dirs += chrome profile
+tier_platform_dirs += profile
 
 # This must preceed xpfe
 ifdef MOZ_JPROF
 tier_platform_dirs        += tools/jprof
 endif
 
 tier_platform_dirs	+= xpfe/components
 
--- a/xpcom/Makefile.in
+++ b/xpcom/Makefile.in
@@ -52,16 +52,17 @@ DIRS		= \
 		base \
 		ds \
 		io \
 		components \
 		threads \
 		reflect \
 		proxy \
                 system \
+		../chrome \
 		build \
 		$(NULL)
 
 ifndef MOZ_ENABLE_LIBXUL
 DIRS += stub
 endif
 
 ifeq ($(OS_ARCH),WINNT)
--- a/xpcom/build/Makefile.in
+++ b/xpcom/build/Makefile.in
@@ -77,16 +77,17 @@ CPPSRCS += dlldeps.cpp
 endif
 endif
 
 ifdef MOZ_OMNIJAR
 CPPSRCS += Omnijar.cpp
 endif
 
 SHARED_LIBRARY_LIBS = \
+		$(DEPTH)/chrome/src/chrome_s.$(LIB_SUFFIX) \
 		../ds/$(LIB_PREFIX)xpcomds_s.$(LIB_SUFFIX) \
 		../io/$(LIB_PREFIX)xpcomio_s.$(LIB_SUFFIX) \
 		../components/$(LIB_PREFIX)xpcomcomponents_s.$(LIB_SUFFIX) \
 		../threads/$(LIB_PREFIX)xpcomthreads_s.$(LIB_SUFFIX) \
 		../proxy/src/$(LIB_PREFIX)xpcomproxy_s.$(LIB_SUFFIX) \
 		../base/$(LIB_PREFIX)xpcombase_s.$(LIB_SUFFIX) \
 		../reflect/xptcall/src/$(LIB_PREFIX)xptcall.$(LIB_SUFFIX) \
 		../reflect/xptcall/src/$(LIB_PREFIX)xptcmd.$(LIB_SUFFIX) \
@@ -108,16 +109,17 @@ LOCAL_INCLUDES	= \
 		-I$(srcdir)/../base \
 		-I$(srcdir)/../ds \
 		-I$(srcdir)/../io \
 		-I$(srcdir)/../components \
 		-I$(srcdir)/../threads \
 		-I$(srcdir)/../threads/_xpidlgen \
 		-I$(srcdir)/../proxy/src \
 		-I$(srcdir)/../reflect/xptinfo/src \
+		-I$(topsrcdir)/chrome/src \
 		$(NULL)
 
 EXPORTS_NAMESPACES = mozilla
 
 SDK_HEADERS =  \
   nsXPCOM.h       \
   nsXPCOMCID.h    \
   $(NULL)
--- a/xpcom/build/dlldeps.cpp
+++ b/xpcom/build/dlldeps.cpp
@@ -301,10 +301,10 @@ void XXXNeverCalled()
     TimeStamp theTimeStamp = TimeStamp::Now();
     TimeDuration theTimeDuration = TimeDuration::FromMilliseconds(0);
 
     NS_WildCardValid((const char *)nsnull);
     NS_WildCardValid((const PRUnichar *)nsnull);
     NS_WildCardMatch((const char *)nsnull, (const char *)nsnull, PR_FALSE);
     NS_WildCardMatch((const PRUnichar *)nsnull, (const PRUnichar *)nsnull, PR_FALSE);
     XRE_AddStaticComponent(NULL);
-    XRE_AddComponentLocation(NULL);
+    XRE_AddComponentLocation(NS_COMPONENT_LOCATION, NULL);
 }
--- a/xpcom/build/nsXPComInit.cpp
+++ b/xpcom/build/nsXPComInit.cpp
@@ -138,16 +138,19 @@ extern nsresult nsStringInputStreamConst
 
 #include "nsSystemInfo.h"
 #include "nsMemoryReporterManager.h"
 
 #include <locale.h>
 #include "mozilla/Services.h"
 #include "mozilla/FunctionTimer.h"
 
+#include "nsChromeRegistry.h"
+#include "nsChromeProtocolHandler.h"
+
 #ifdef MOZ_IPC
 #include "base/at_exit.h"
 #include "base/command_line.h"
 #include "base/message_loop.h"
 
 #include "mozilla/ipc/BrowserProcessSubThread.h"
 
 using base::AtExitManager;
@@ -259,16 +262,22 @@ nsXPTIInterfaceInfoManagerGetSingleton(n
 
 nsComponentManagerImpl* nsComponentManagerImpl::gComponentManager = NULL;
 PRBool gXPCOMShuttingDown = PR_FALSE;
 
 static NS_DEFINE_CID(kComponentManagerCID, NS_COMPONENTMANAGER_CID);
 static NS_DEFINE_CID(kINIParserFactoryCID, NS_INIPARSERFACTORY_CID);
 static NS_DEFINE_CID(kSimpleUnicharStreamFactoryCID, NS_SIMPLE_UNICHAR_STREAM_FACTORY_CID);
 
+NS_DEFINE_NAMED_CID(NS_CHROMEREGISTRY_CID);
+NS_DEFINE_NAMED_CID(NS_CHROMEPROTOCOLHANDLER_CID);
+
+NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsChromeRegistry, Init)
+NS_GENERIC_FACTORY_CONSTRUCTOR(nsChromeProtocolHandler)
+
 #define NS_PERSISTENTPROPERTIES_CID NS_IPERSISTENTPROPERTIES_CID /* sigh */
 #define NS_XPCOMPROXY_CID NS_PROXYEVENT_MANAGER_CID
 
 static already_AddRefed<nsIFactory>
 CreateINIParserFactory(const mozilla::Module& module,
                        const mozilla::Module::CIDEntry& entry)
 {
     nsIFactory* f = new nsINIParserFactory();
@@ -288,23 +297,27 @@ CreateUnicharStreamFactory(const mozilla
 #undef COMPONENT
 
 #define COMPONENT(NAME, Ctor) { &kNS_##NAME##_CID, false, NULL, Ctor },
 const mozilla::Module::CIDEntry kXPCOMCIDEntries[] = {
     { &kComponentManagerCID, true, NULL, nsComponentManagerImpl::Create },
     { &kINIParserFactoryCID, false, CreateINIParserFactory },
     { &kSimpleUnicharStreamFactoryCID, false, CreateUnicharStreamFactory },
 #include "XPCOMModule.inc"
+    { &kNS_CHROMEREGISTRY_CID, false, NULL, nsChromeRegistryConstructor },
+    { &kNS_CHROMEPROTOCOLHANDLER_CID, false, NULL, nsChromeProtocolHandlerConstructor },
     { NULL }
 };
 #undef COMPONENT
 
 #define COMPONENT(NAME, Ctor) { NS_##NAME##_CONTRACTID, &kNS_##NAME##_CID },
 const mozilla::Module::ContractIDEntry kXPCOMContracts[] = {
 #include "XPCOMModule.inc"
+    { NS_CHROMEREGISTRY_CONTRACTID, &kNS_CHROMEREGISTRY_CID },
+    { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "chrome", &kNS_CHROMEPROTOCOLHANDLER_CID },
     { NULL }
 };
 #undef COMPONENT
 
 const mozilla::Module kXPCOMModule = { mozilla::Module::kVersion, kXPCOMCIDEntries, kXPCOMContracts };
 
 // gDebug will be freed during shutdown.
 static nsIDebug* gDebug = nsnull;
@@ -468,35 +481,28 @@ NS_InitXPCOM2(nsIServiceManager* *result
     }
 #endif
 
     NS_ASSERTION(nsComponentManagerImpl::gComponentManager == NULL, "CompMgr not null at init");
 
     NS_TIME_FUNCTION_MARK("Next: component manager init");
 
     // Create the Component/Service Manager
-    nsComponentManagerImpl *compMgr = new nsComponentManagerImpl();
-    if (compMgr == NULL)
-        return NS_ERROR_OUT_OF_MEMORY;
-    NS_ADDREF(compMgr);
+    nsComponentManagerImpl::gComponentManager = new nsComponentManagerImpl();
+    NS_ADDREF(nsComponentManagerImpl::gComponentManager);
     
-    rv = compMgr->Init();
+    rv = nsComponentManagerImpl::gComponentManager->Init();
     if (NS_FAILED(rv))
     {
-        NS_RELEASE(compMgr);
+        NS_RELEASE(nsComponentManagerImpl::gComponentManager);
         return rv;
     }
 
-    nsComponentManagerImpl::gComponentManager = compMgr;
-
     if (result) {
-        nsIServiceManager *serviceManager =
-            static_cast<nsIServiceManager*>(compMgr);
-
-        NS_ADDREF(*result = serviceManager);
+        NS_ADDREF(*result = nsComponentManagerImpl::gComponentManager);
     }
 
     NS_TIME_FUNCTION_MARK("Next: cycle collector startup");
 
     rv = nsCycleCollector_startup();
     if (NS_FAILED(rv)) return rv;
 
     NS_TIME_FUNCTION_MARK("Next: interface info manager init");
--- a/xpcom/build/nsXULAppAPI.h
+++ b/xpcom/build/nsXULAppAPI.h
@@ -348,27 +348,41 @@ XRE_API(nsresult,
 
 /**
  * Register static XPCOM component information.
  * This method may be called at any time before or after XRE_main or
  * XRE_InitEmbedding.
  */
 XRE_API(nsresult,
         XRE_AddStaticComponent, (const mozilla::Module* aComponent))
+
 /**
  * Register XPCOM components found in an array of files/directories.
  * This method may be called at any time before or after XRE_main or
  * XRE_InitEmbedding.
  *
  * @param aFiles An array of files or directories.
  * @param aFileCount the number of items in the aFiles array.
  * @note appdir/components is registered automatically.
+ *
+ * NS_COMPONENT_LOCATION specifies a location to search for binary XPCOM
+ * components as well as component/chrome manifest files.
+ *
+ * NS_SKIN_LOCATION specifies a location to search for chrome manifest files
+ * which are only allowed to register only skin packages and style overlays.
  */
+enum NSLocationType
+{
+  NS_COMPONENT_LOCATION,
+  NS_SKIN_LOCATION
+};
+
 XRE_API(nsresult,
-        XRE_AddComponentLocation, (nsILocalFile* aLocation))
+        XRE_AddComponentLocation, (NSLocationType aType,
+                                   nsILocalFile* aLocation))
 
 /**
  * Fire notifications to inform the toolkit about a new profile. This
  * method should be called after XRE_InitEmbedding if the embedder
  * wishes to run with a profile. Normally the embedder should call
  * XRE_LockProfileDirectory to lock the directory before calling this
  * method.
  *
--- a/xpcom/components/Makefile.in
+++ b/xpcom/components/Makefile.in
@@ -41,16 +41,17 @@ srcdir		= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE		= xpcom
 XPIDL_MODULE	= xpcom_components
 LIBRARY_NAME	= xpcomcomponents_s
 GRE_MODULE	= 1
+LIBXUL_LIBRARY = 1
 MOZILLA_INTERNAL_API = 1
 
 EXPORTS_NAMESPACES = mozilla
 
 EXPORTS	= \
   nsCategoryManagerUtils.h \
   $(NULL)
 
@@ -59,16 +60,17 @@ EXPORTS_mozilla = \
   Module.h \
   ModuleLoader.h \
   ModuleUtils.h \
   $(NULL)
 
 CPPSRCS		= \
 		nsCategoryManager.cpp \
 		nsComponentManager.cpp \
+		ManifestParser.cpp \
 		nsNativeComponentLoader.cpp \
 		GenericFactory.cpp \
 		$(NULL)
 
 SDK_XPIDLSRCS	= \
 		nsIClassInfo.idl	      \
 		nsIComponentRegistrar.idl     \
 		nsIFactory.idl                \
@@ -79,16 +81,17 @@ SDK_XPIDLSRCS	= \
 
 LOCAL_INCLUDES	= \
 	-I$(srcdir)/../reflect/xptinfo/src \
 	-I$(srcdir)/../base \
 	-I$(srcdir)/../thread \
 	-I$(srcdir)/../ds \
 	-I$(srcdir)/../build \
 	-I.. \
+	-I$(topsrcdir)/chrome/src \
 	$(NULL)
 
 # we don't want the shared lib, but we want to force the creation of a static lib.
 FORCE_STATIC_LIB = 1
 
 # Force use of PIC
 FORCE_USE_PIC	= 1
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/xpcom/components/ManifestParser.cpp
@@ -0,0 +1,472 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Firefox
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation <http://www.mozilla.org/>.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "ManifestParser.h"
+
+#include <string.h>
+
+#include "prio.h"
+#include "prprf.h"
+#if defined(XP_WIN)
+#include <windows.h>
+#elif defined(XP_MACOSX)
+#include <CoreServices/CoreServices.h>
+#elif defined(MOZ_WIDGET_GTK2)
+#include <gtk/gtk.h>
+#endif
+
+#include "nsTextFormatter.h"
+#include "nsUnicharUtils.h"
+#include "nsVersionComparator.h"
+#include "nsXPCOMCIDInternal.h"
+
+#include "nsIConsoleService.h"
+#include "nsIScriptError.h"
+#include "nsIXULAppInfo.h"
+#include "nsIXULRuntime.h"
+
+struct ManifestDirective
+{
+  const char* directive;
+  int argc;
+
+  // Some directives should only be delivered for NS_COMPONENT_LOCATION
+  // manifests.
+  bool componentonly;
+
+  bool ischrome;
+
+  // The platform/contentaccessible flags only apply to content directives.
+  bool contentflags;
+
+  // Function to handle this directive. This isn't a union because C++ still
+  // hasn't learned how to initialize unions in a sane way.
+  void (nsComponentManagerImpl::*mgrfunc)
+    (nsComponentManagerImpl::ManifestProcessingContext& cx,
+     int lineno, char *const * argv);
+  void (nsChromeRegistry::*regfunc)
+    (nsChromeRegistry::ManifestProcessingContext& cx,
+     int lineno, char *const *argv,
+     bool platform, bool contentaccessible);
+};
+static const ManifestDirective kParsingTable[] = {
+  { "binary-component", 1, true, false, false,
+    &nsComponentManagerImpl::ManifestBinaryComponent, NULL },
+  { "component",        2, true, false, false,
+    &nsComponentManagerImpl::ManifestComponent, NULL },
+  { "contract",         2, true, false, false,
+    &nsComponentManagerImpl::ManifestContract, NULL },
+  { "category",         3, true, false, false,
+    &nsComponentManagerImpl::ManifestCategory, NULL },
+  { "content",          2, true, true,  true,
+    NULL, &nsChromeRegistry::ManifestContent },
+  { "locale",           3, true, true,  false,
+    NULL, &nsChromeRegistry::ManifestLocale },
+  { "skin",             3, false, true,  false,
+    NULL, &nsChromeRegistry::ManifestSkin },
+  { "overlay",          2, true, true,  false,
+    NULL, &nsChromeRegistry::ManifestOverlay },
+  { "style",            2, false, true,  false,
+    NULL, &nsChromeRegistry::ManifestStyle },
+  { "override",         2, true, true,  false,
+    NULL, &nsChromeRegistry::ManifestOverride },
+  { "resource",         2, true, true,  false,
+    NULL, &nsChromeRegistry::ManifestResource }
+};
+
+static const char kWhitespace[] = "\t ";
+static const char kNewlines[]   = "\r\n";
+
+static void LogMessageWithContext(nsILocalFile* aFile, PRUint32 aLineNumber, const char* aMsg, ...)
+{
+  nsCOMPtr<nsIConsoleService> console =
+    do_GetService(NS_CONSOLESERVICE_CONTRACTID);
+  nsCOMPtr<nsIScriptError> error =
+    do_CreateInstance(NS_SCRIPTERROR_CONTRACTID);
+  if (!console || !error)
+    return;
+
+  va_list args;
+  va_start(args, aMsg);
+  char* formatted = PR_vsmprintf(aMsg, args);
+  va_end(args);
+  if (!formatted)
+    return;
+
+  nsString file;
+  aFile->GetPath(file);
+
+  nsresult rv = error->Init(NS_ConvertUTF8toUTF16(formatted).get(),
+			    file.get(), NULL,
+			    aLineNumber, 0, nsIScriptError::warningFlag,
+			    "chrome registration");
+  PR_smprintf_free(formatted);
+  if (NS_FAILED(rv))
+    return;
+
+  console->LogMessage(error);
+}
+
+/**
+ * Check for a modifier flag of the following forms:
+ *   "flag"   (same as "true")
+ *   "flag=yes|true|1"
+ *   "flag="no|false|0"
+ * @param aFlag The flag to compare.
+ * @param aData The tokenized data to check; this is lowercased
+ *              before being passed in.
+ * @param aResult If the flag is found, the value is assigned here.
+ * @return Whether the flag was handled.
+ */
+static bool
+CheckFlag(const nsSubstring& aFlag, const nsSubstring& aData, bool& aResult)
+{
+  if (!StringBeginsWith(aData, aFlag))
+    return false;
+
+  if (aFlag.Length() == aData.Length()) {
+    // the data is simply "flag", which is the same as "flag=yes"
+    aResult = true;
+    return true;
+  }
+
+  if (aData.CharAt(aFlag.Length()) != '=') {
+    // the data is "flag2=", which is not anything we care about
+    return false;
+  }
+
+  if (aData.Length() == aFlag.Length() + 1) {
+    aResult = false;
+    return true;
+  }
+
+  switch (aData.CharAt(aFlag.Length() + 1)) {
+  case '1':
+  case 't': //true
+  case 'y': //yes
+    aResult = true;
+    return true;
+
+  case '0':
+  case 'f': //false
+  case 'n': //no
+    aResult = false;
+    return true;
+  }
+
+  return false;
+}
+
+enum TriState {
+  eUnspecified,
+  eBad,
+  eOK
+};
+
+/**
+ * Check for a modifier flag of the following form:
+ *   "flag=string"
+ *   "flag!=string"
+ * @param aFlag The flag to compare.
+ * @param aData The tokenized data to check; this is lowercased
+ *              before being passed in.
+ * @param aValue The value that is expected.
+ * @param aResult If this is "ok" when passed in, this is left alone.
+ *                Otherwise if the flag is found it is set to eBad or eOK.
+ * @return Whether the flag was handled.
+ */
+static bool
+CheckStringFlag(const nsSubstring& aFlag, const nsSubstring& aData,
+                const nsSubstring& aValue, TriState& aResult)
+{
+  if (aData.Length() < aFlag.Length() + 1)
+    return false;
+
+  if (!StringBeginsWith(aData, aFlag))
+    return false;
+
+  bool comparison = true;
+  if (aData[aFlag.Length()] != '=') {
+    if (aData[aFlag.Length()] == '!' &&
+        aData.Length() >= aFlag.Length() + 2 &&
+        aData[aFlag.Length() + 1] == '=')
+      comparison = false;
+    else
+      return false;
+  }
+
+  if (aResult != eOK) {
+    nsDependentSubstring testdata = Substring(aData, aFlag.Length() + (comparison ? 1 : 2));
+    if (testdata.Equals(aValue))
+      aResult = comparison ? eOK : eBad;
+    else
+      aResult = comparison ? eBad : eOK;
+  }
+
+  return true;
+}
+
+/**
+ * Check for a modifier flag of the following form:
+ *   "flag=version"
+ *   "flag<=version"
+ *   "flag<version"
+ *   "flag>=version"
+ *   "flag>version"
+ * @param aFlag The flag to compare.
+ * @param aData The tokenized data to check; this is lowercased
+ *              before being passed in.
+ * @param aValue The value that is expected. If this is empty then no
+ *               comparison will match.
+ * @param aResult If this is eOK when passed in, this is left alone.
+ *                Otherwise if the flag is found it is set to eBad or eOK.
+ * @return Whether the flag was handled.
+ */
+
+#define COMPARE_EQ    1 << 0
+#define COMPARE_LT    1 << 1
+#define COMPARE_GT    1 << 2
+
+static bool
+CheckVersionFlag(const nsString& aFlag, const nsString& aData,
+                 const nsString& aValue, TriState& aResult)
+{
+  if (aData.Length() < aFlag.Length() + 2)
+    return false;
+
+  if (!StringBeginsWith(aData, aFlag))
+    return false;
+
+  if (aValue.Length() == 0) {
+    if (aResult != eOK)
+      aResult = eBad;
+    return true;
+  }
+
+  PRUint32 comparison;
+  nsAutoString testdata;
+
+  switch (aData[aFlag.Length()]) {
+  case '=':
+    comparison = COMPARE_EQ;
+    testdata = Substring(aData, aFlag.Length() + 1);
+    break;
+
+  case '<':
+    if (aData[aFlag.Length() + 1] == '=') {
+      comparison = COMPARE_EQ | COMPARE_LT;
+      testdata = Substring(aData, aFlag.Length() + 2);
+    }
+    else {
+      comparison = COMPARE_LT;
+      testdata = Substring(aData, aFlag.Length() + 1);
+    }
+    break;
+
+  case '>':
+    if (aData[aFlag.Length() + 1] == '=') {
+      comparison = COMPARE_EQ | COMPARE_GT;
+      testdata = Substring(aData, aFlag.Length() + 2);
+    }
+    else {
+      comparison = COMPARE_GT;
+      testdata = Substring(aData, aFlag.Length() + 1);
+    }
+    break;
+
+  default:
+    return false;
+  }
+
+  if (testdata.Length() == 0)
+    return false;
+
+  if (aResult != eOK) {
+    PRInt32 c = NS_CompareVersions(aValue.get(), testdata.get());
+    if ((c == 0 && comparison & COMPARE_EQ) ||
+	(c < 0 && comparison & COMPARE_LT) ||
+	(c > 0 && comparison & COMPARE_GT))
+      aResult = eOK;
+    else
+      aResult = eBad;
+  }
+
+  return true;
+}
+
+void
+ParseManifest(NSLocationType aType, nsILocalFile* aFile, char* buf)
+{
+  nsresult rv;
+
+  nsComponentManagerImpl::ManifestProcessingContext mgrcx(aType, aFile);
+  nsChromeRegistry::ManifestProcessingContext chromecx(aType, aFile);
+
+  NS_NAMED_LITERAL_STRING(kPlatform, "platform");
+  NS_NAMED_LITERAL_STRING(kContentAccessible, "contentaccessible");
+  NS_NAMED_LITERAL_STRING(kApplication, "application");
+  NS_NAMED_LITERAL_STRING(kAppVersion, "appversion");
+  NS_NAMED_LITERAL_STRING(kOs, "os");
+  NS_NAMED_LITERAL_STRING(kOsVersion, "osversion");
+
+  nsAutoString appID;
+  nsAutoString appVersion;
+  nsAutoString osTarget;
+  nsCOMPtr<nsIXULAppInfo> xapp (do_GetService(XULAPPINFO_SERVICE_CONTRACTID));
+  if (xapp) {
+    nsCAutoString s;
+    rv = xapp->GetID(s);
+    if (NS_SUCCEEDED(rv))
+      CopyUTF8toUTF16(s, appID);
+
+    rv = xapp->GetVersion(s);
+    if (NS_SUCCEEDED(rv))
+      CopyUTF8toUTF16(s, appVersion);
+    
+    nsCOMPtr<nsIXULRuntime> xruntime (do_QueryInterface(xapp));
+    if (xruntime) {
+      rv = xruntime->GetOS(s);
+      if (NS_SUCCEEDED(rv)) {
+        CopyUTF8toUTF16(s, osTarget);
+        ToLowerCase(osTarget);
+      }
+    }
+  }
+
+  nsAutoString osVersion;
+#if defined(XP_WIN)
+  OSVERSIONINFO info = { sizeof(OSVERSIONINFO) };
+  if (GetVersionEx(&info)) {
+    nsTextFormatter::ssprintf(osVersion, NS_LITERAL_STRING("%ld.%ld").get(),
+                                         info.dwMajorVersion,
+                                         info.dwMinorVersion);
+  }
+#elif defined(XP_MACOSX)
+  SInt32 majorVersion, minorVersion;
+  if ((Gestalt(gestaltSystemVersionMajor, &majorVersion) == noErr) &&
+      (Gestalt(gestaltSystemVersionMinor, &minorVersion) == noErr)) {
+    nsTextFormatter::ssprintf(osVersion, NS_LITERAL_STRING("%ld.%ld").get(),
+                                         majorVersion,
+                                         minorVersion);
+  }
+#elif defined(MOZ_WIDGET_GTK2)
+  nsTextFormatter::ssprintf(osVersion, NS_LITERAL_STRING("%ld.%ld").get(),
+                                       gtk_major_version,
+                                       gtk_minor_version);
+#endif
+
+  char *token;
+  char *newline = buf;
+  PRUint32 line = 0;
+
+  // outer loop tokenizes by newline
+  while (nsnull != (token = nsCRT::strtok(newline, kNewlines, &newline))) {
+    ++line;
+
+    if (*token == '#') // ignore lines that begin with # as comments
+      continue;
+
+    char *whitespace = token;
+    token = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
+    if (!token) continue;
+
+    const ManifestDirective* directive = NULL;
+    for (const ManifestDirective* d = kParsingTable;
+	 d < kParsingTable + NS_ARRAY_LENGTH(kParsingTable);
+	 ++d) {
+      if (!strcmp(d->directive, token)) {
+	directive = d;
+	break;
+      }
+    }
+    if (!directive) {
+      LogMessageWithContext(aFile, line, "Ignoring unrecognized chrome manifest directive '%s'.", token);
+      continue;
+    }
+    if (directive->componentonly && NS_COMPONENT_LOCATION != aType) {
+      LogMessageWithContext(aFile, line, "Skin manifest not allowed to use '%s' directive.", token);
+      continue;
+    }
+
+    NS_ASSERTION(directive->argc < 4, "Need to reset argv array length");
+    char* argv[4];
+    for (int i = 0; i < directive->argc; ++i)
+      argv[i] = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
+
+    if (!argv[directive->argc - 1]) {
+      LogMessageWithContext(aFile, line, "Not enough arguments for chrome manifest directive '%s', expected %i.", token, directive->argc);
+      continue;
+    }
+
+    bool ok = true;
+    TriState stAppVersion = eUnspecified;
+    TriState stApp = eUnspecified;
+    TriState stOsVersion = eUnspecified;
+    TriState stOs = eUnspecified;
+    bool platform = false;
+    bool contentAccessible = false;
+
+    while (NULL != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) && ok) {
+      NS_ConvertASCIItoUTF16 wtoken(token);
+      ToLowerCase(wtoken);
+
+      if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
+	  CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
+	  CheckVersionFlag(kOsVersion, wtoken, osVersion, stOsVersion) ||
+	  CheckVersionFlag(kAppVersion, wtoken, appVersion, stAppVersion))
+	continue;
+
+      if (directive->contentflags &&
+	  (CheckFlag(kPlatform, wtoken, platform) ||
+	   CheckFlag(kContentAccessible, wtoken, contentAccessible)))
+	  continue;
+
+      LogMessageWithContext(aFile, line, "Unrecognized chrome manifest modifier '%s'.", token);
+      ok = false;
+    }
+
+    if (!ok || stApp == eBad || stAppVersion == eBad || stOs == eBad || stOsVersion == eBad)
+      continue;
+
+    if (directive->ischrome)
+      (nsChromeRegistry::gChromeRegistry->*(directive->regfunc))
+	(chromecx, line, argv, platform, contentAccessible);
+    else
+      (nsComponentManagerImpl::gComponentManager->*(directive->mgrfunc))
+	(mgrcx, line, argv);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/xpcom/components/ManifestParser.h
@@ -0,0 +1,48 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Firefox
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation <http://www.mozilla.org/>.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef ManifestParser_h
+#define ManifestParser_h
+
+#include "nsComponentManager.h"
+#include "nsChromeRegistry.h"
+
+class nsILocalFile;
+
+void ParseManifest(NSLocationType type, nsILocalFile* file, char* buf);
+
+#endif // ManifestParser_h
--- a/xpcom/components/nsComponentManager.cpp
+++ b/xpcom/components/nsComponentManager.cpp
@@ -84,16 +84,17 @@
 #include "prcmon.h"
 #include "xptinfo.h" // this after nsISupports, to pick up IID so that xpt stuff doesn't try to define it itself...
 #include "nsThreadUtils.h"
 #include "prthread.h"
 #include "private/pprthred.h"
 #include "nsTArray.h"
 #include "prio.h"
 #include "mozilla/FunctionTimer.h"
+#include "ManifestParser.h"
 
 #include "nsInt64.h"
 #include "nsManifestLineReader.h"
 #include "mozilla/GenericFactory.h"
 #include "nsSupportsPrimitives.h"
 #include "nsArrayEnumerator.h"
 #include "nsStringEnumerator.h"
 
@@ -308,25 +309,26 @@ nsComponentManagerImpl::InitializeStatic
         return;
 
     sStaticModules = new nsTArray<const mozilla::Module*>;
     for (const mozilla::Module *const *staticModules = kPStaticModules;
          *staticModules; ++staticModules)
         sStaticModules->AppendElement(*staticModules);
 }
 
-nsCOMArray<nsILocalFile>* nsComponentManagerImpl::sModuleLocations;
+nsTArray<nsComponentManagerImpl::ComponentLocation>*
+nsComponentManagerImpl::sModuleLocations;
 
 /* static */ void
 nsComponentManagerImpl::InitializeModuleLocations()
 {
     if (sModuleLocations)
         return;
 
-    sModuleLocations = new nsCOMArray<nsILocalFile>;
+    sModuleLocations = new nsTArray<ComponentLocation>;
 }
 
 nsresult nsComponentManagerImpl::Init()
 {
     NS_TIME_FUNCTION;
 
     PR_ASSERT(NOT_INITIALIZED == mStatus);
 
@@ -336,70 +338,85 @@ nsresult nsComponentManagerImpl::Init()
     }
 
     // Initialize our arena
     NS_TIME_FUNCTION_MARK("Next: init component manager arena");
     PL_INIT_ARENA_POOL(&mArena, "ComponentManagerArena", NS_CM_BLOCK_SIZE);
 
     mFactories.Init(CONTRACTID_HASHTABLE_INITIAL_SIZE);
     mContractIDs.Init(CONTRACTID_HASHTABLE_INITIAL_SIZE);
+    mLoaderMap.Init();
+    mKnownFileModules.Init();
 
     mMon = nsAutoMonitor::NewMonitor("nsComponentManagerImpl");
     if (mMon == nsnull)
         return NS_ERROR_OUT_OF_MEMORY;
 
     static const char *const kComponents[] = { "components", NULL };
 
     nsCOMPtr<nsILocalFile> greComponents =
         GetLocationFromDirectoryService(NS_GRE_DIR, kComponents);
 
     nsCOMPtr<nsILocalFile> appComponents =
         GetLocationFromDirectoryService(NS_XPCOM_CURRENT_PROCESS_DIR, kComponents);
     InitializeStaticModules();
     InitializeModuleLocations();
 
+    ComponentLocation* l = sModuleLocations->InsertElementAt(0);
+    l->type = NS_COMPONENT_LOCATION;
+    l->location = appComponents;
+
     PRBool equals = PR_FALSE;
     appComponents->Equals(greComponents, &equals);
-    if (!equals)
-        sModuleLocations->InsertObjectAt(greComponents, 0);
-    sModuleLocations->InsertObjectAt(appComponents, 0);
+    if (!equals) {
+        l = sModuleLocations->InsertElementAt(0);
+        l->type = NS_COMPONENT_LOCATION;
+        l->location = greComponents;
+    }
 
     PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG,
            ("nsComponentManager: Initialized."));
 
     NS_TIME_FUNCTION_MARK("Next: init native module loader");
     nsresult rv = mNativeModuleLoader.Init();
     if (NS_FAILED(rv))
         return rv;
 
     nsCategoryManager::GetSingleton()->SuppressNotifications(true);
 
     RegisterModule(&kXPCOMModule, NULL);
 
     for (PRUint32 i = 0; i < sStaticModules->Length(); ++i)
         RegisterModule((*sStaticModules)[i], NULL);
 
-    for (PRInt32 i = 0; i < sModuleLocations->Count(); ++i)
-        RegisterLocation((*sModuleLocations)[i]);
+    for (PRUint32 i = 0; i < sModuleLocations->Length(); ++i) {
+        ComponentLocation& l = sModuleLocations->ElementAt(i);
+        RegisterLocation(l.type, l.location);
+    }
 
     nsCategoryManager::GetSingleton()->SuppressNotifications(false);
 
     mStatus = NORMAL;
 
     return NS_OK;
 }
 
 void
 nsComponentManagerImpl::RegisterModule(const mozilla::Module* aModule,
                                        nsILocalFile* aFile)
 {
     nsAutoMonitor mon(mMon);
 
     KnownModule* m = new KnownModule(aModule, aFile);
-    mKnownModules.AppendElement(m);
+    if (aFile) {
+        nsCOMPtr<nsIHashable> h = do_QueryInterface(aFile);
+        mKnownFileModules.Put(h, m);
+    }
+    else
+        mKnownStaticModules.AppendElement(m);
 
     if (aModule->mCIDs) {
         const mozilla::Module::CIDEntry* entry;
         for (entry = aModule->mCIDs; entry->cid; ++entry)
             RegisterCIDEntry(entry, m);
     }
 
     if (aModule->mContractIDs) {
@@ -447,81 +464,278 @@ nsComponentManagerImpl::RegisterContract
         // XXX REPORT ERROR, CID isn't registered
         return;
     }
 
     mContractIDs.Put(nsDependentCString(aEntry->contractid), f);
 }
 
 void
-nsComponentManagerImpl::RegisterLocation(nsILocalFile* aLocation)
+nsComponentManagerImpl::RegisterLocation(NSLocationType aType,
+                                         nsILocalFile* aLocation)
 {
+    nsCOMArray<nsILocalFile> manifests;
+
     PRBool directory = PR_FALSE;
     aLocation->IsDirectory(&directory);
     if (directory)
-        RegisterDirectory(aLocation);
+        RegisterDirectory(aType, aLocation, manifests);
     else
-        RegisterFile(aLocation);
+        RegisterFile(aType, aLocation, manifests);
+
+    for (PRInt32 i = 0; i < manifests.Count(); ++i)
+        RegisterManifestFile(aType, manifests[i]);
 }
 
 void
-nsComponentManagerImpl::RegisterDirectory(nsILocalFile* aDirectory)
+nsComponentManagerImpl::RegisterDirectory(NSLocationType aType,
+                                          nsILocalFile* aDirectory,
+                                          nsCOMArray<nsILocalFile>& aManifests)
 {
     nsCOMPtr<nsISimpleEnumerator> entries;
     aDirectory->GetDirectoryEntries(getter_AddRefs(entries));
     if (!entries)
         return;
 
     PRBool more;
     while (NS_SUCCEEDED(entries->HasMoreElements(&more)) && more) {
         nsCOMPtr<nsISupports> supp;
         entries->GetNext(getter_AddRefs(supp));
         nsCOMPtr<nsILocalFile> f = do_QueryInterface(supp);
         if (!f)
             continue;
 
-        RegisterFile(f);
+        RegisterFile(aType, f, aManifests);
     }
 }
 
-void
-nsComponentManagerImpl::RegisterFile(nsILocalFile* aFile)
+static void
+GetExtension(nsILocalFile* file, nsCString& extension)
 {
-    nsCString extension;
-    aFile->GetNativePath(extension);
+    file->GetNativePath(extension);
 
     PRInt32 dotPos = extension.RFindChar('.');
     if (kNotFound == dotPos)
+        extension.Truncate();
+    else
+        extension.Cut(0, dotPos + 1);
+}
+
+void
+nsComponentManagerImpl::RegisterFile(NSLocationType aType,
+                                     nsILocalFile* aFile,
+                                     nsCOMArray<nsILocalFile>& aManifests)
+{
+    nsCString extension;
+    GetExtension(aFile, extension);
+
+    if (NS_COMPONENT_LOCATION == aType) {
+        if (extension.EqualsLiteral("xpt")) {
+            xptiInterfaceInfoManager::GetSingleton()
+                ->RegisterFile(aFile,
+                               xptiInterfaceInfoManager::XPT);
+        }
+        else if (extension.EqualsLiteral("jar")) {
+            xptiInterfaceInfoManager::GetSingleton()
+                ->RegisterFile(aFile,
+                               xptiInterfaceInfoManager::ZIP);
+        }
+    }
+
+    if (extension.LowerCaseEqualsLiteral("manifest"))
+        aManifests.AppendObject(aFile);
+}
+
+namespace {
+struct AutoCloseFD
+{
+    AutoCloseFD()
+        : mFD(NULL)
+    { }
+    ~AutoCloseFD() {
+        if (mFD)
+            PR_Close(mFD);
+    }
+    operator PRFileDesc*() {
+        return mFD;
+    }
+
+    PRFileDesc** operator&() {
+        NS_ASSERTION(!mFD, "Re-opening a file");
+        return &mFD;
+    }
+
+    PRFileDesc* mFD;
+};
+
+} // anonymous namespace
+
+void
+nsComponentManagerImpl::RegisterManifestFile(NSLocationType aType,
+                                             nsILocalFile* aFile)
+{
+    nsresult rv;
+
+    AutoCloseFD fd;
+    rv = aFile->OpenNSPRFileDesc(PR_RDONLY, 0444, &fd);
+    if (NS_FAILED(rv))
+        return;
+
+    PRFileInfo64 fileInfo;
+    if (PR_SUCCESS != PR_GetOpenFileInfo64(fd, &fileInfo))
+        return;
+
+    if (fileInfo.size > PRInt64(PR_INT32_MAX))
         return;
 
-    extension.Cut(0, dotPos + 1);
-    if (extension.LowerCaseEqualsLiteral(NAKED_DLL_SUFFIX)) {
-        const mozilla::Module* m = mNativeModuleLoader.LoadModule(aFile);
-        if (!m)
+    nsAutoArrayPtr<char> data(new char[PRInt32(fileInfo.size + 1)]);
+
+    for (PRInt32 totalRead = 0; totalRead < fileInfo.size; ) {
+        PRInt32 read = PR_Read(fd, data + totalRead, PRInt32(fileInfo.size));
+        if (read < 0)
             return;
-        RegisterModule(m, aFile);
+        totalRead += read;
+    }
+
+    data[fileInfo.size] = '\0';
+    ParseManifest(aType, aFile, data);
+}
+
+void
+nsComponentManagerImpl::ManifestBinaryComponent(ManifestProcessingContext& cx, int lineno, char *const * argv)
+{
+    char* file = argv[0];
+
+    nsCOMPtr<nsIFile> cfile;
+    cx.mFile->GetParent(getter_AddRefs(cfile));
+    nsCOMPtr<nsILocalFile> clfile = do_QueryInterface(cfile);
+
+    nsresult rv = clfile->AppendRelativeNativePath(nsDependentCString(file));
+    if (NS_FAILED(rv)) {
+        NS_WARNING("Couldn't append relative path?");
+        return;
+    }
+
+    const mozilla::Module* m = mNativeModuleLoader.LoadModule(clfile);
+    if (!m) {
+        // XXX report load error
+        return;
+    }
+    RegisterModule(m, clfile);
+}
+
+void
+nsComponentManagerImpl::ManifestComponent(ManifestProcessingContext& cx, int lineno, char *const * argv)
+{
+    char* id = argv[0];
+    char* file = argv[1];
+
+    nsID cid;
+    if (!cid.Parse(id)) {
+        // XXX report parse error
+        return;
+    }
+
+    nsAutoMonitor mon(mMon);
+    nsFactoryEntry* f = mFactories.Get(cid);
+    if (f) {
+        // XXX report double-register error
+        return;
+    }
+
+    nsCOMPtr<nsIFile> cfile;
+    cx.mFile->GetParent(getter_AddRefs(cfile));
+    nsCOMPtr<nsILocalFile> clfile = do_QueryInterface(cfile);
+
+    nsresult rv = clfile->AppendRelativeNativePath(nsDependentCString(file));
+    if (NS_FAILED(rv)) {
+        NS_WARNING("Couldn't append relative path?");
+        return;
     }
-    else if (extension.EqualsLiteral("xpt")) {
-        xptiInterfaceInfoManager::GetSingleton()
-            ->RegisterFile(aFile,
-                           xptiInterfaceInfoManager::XPT);
+
+    nsCOMPtr<nsIHashable> h = do_QueryInterface(clfile);
+    KnownModule* km = mKnownFileModules.Get(h);
+    if (!km) {
+        km = new KnownModule(clfile);
+        mKnownFileModules.Put(h, km);
+    }
+
+    void* place;
+
+    PL_ARENA_ALLOCATE(place, &mArena, sizeof(nsCID));
+    nsID* permanentCID = static_cast<nsID*>(place);
+    *permanentCID = cid;
+
+    PL_ARENA_ALLOCATE(place, &mArena, sizeof(mozilla::Module::CIDEntry));
+    mozilla::Module::CIDEntry* e = new (place) mozilla::Module::CIDEntry();
+    e->cid = permanentCID;
+
+    f = new nsFactoryEntry(e, km);
+    mFactories.Put(cid, f);
+}
+
+void
+nsComponentManagerImpl::ManifestContract(ManifestProcessingContext& cx, int lineno, char *const * argv)
+{
+    char* contract = argv[0];
+    char* id = argv[1];
+
+    nsID cid;
+    if (!cid.Parse(id)) {
+        // XXX report parse error
+        return;
     }
-    else if (extension.EqualsLiteral("jar")) {
-        xptiInterfaceInfoManager::GetSingleton()
-            ->RegisterFile(aFile,
-                           xptiInterfaceInfoManager::ZIP);
+
+    nsAutoMonitor mon(mMon);
+    nsFactoryEntry* f = mFactories.Get(cid);
+    if (!f) {
+        // XXX report unregistered CID
+        return;
     }
+
+    mContractIDs.Put(nsDependentCString(contract), f);
+}
+
+void
+nsComponentManagerImpl::ManifestCategory(ManifestProcessingContext& cx, int lineno, char *const * argv)
+{
+    char* category = argv[0];
+    char* key = argv[1];
+    char* value = argv[2];
+
+    nsCategoryManager::GetSingleton()->
+        AddCategoryEntry(category, key, value);
+}
+
+void
+nsComponentManagerImpl::RereadChromeManifests()
+{
+    NS_ERROR("XXX Not done!");
+}
+
+bool
+nsComponentManagerImpl::KnownModule::EnsureLoader()
+{
+    if (!mLoader) {
+        nsCString extension;
+        GetExtension(mFile, extension);
+
+        mLoader = nsComponentManagerImpl::gComponentManager->LoaderForExtension(extension);
+    }
+    return !!mLoader;
 }
 
 bool
 nsComponentManagerImpl::KnownModule::Load()
 {
     if (mFailed)
         return false;
     if (!mModule) {
+        if (!EnsureLoader())
+            return false;
         mModule = mLoader->LoadModule(mFile);
         if (!mModule) {
             mFailed = true;
             return false;
         }
     }
     if (!mLoaded) {
         if (mModule->loaded) {
@@ -545,16 +759,18 @@ nsresult nsComponentManagerImpl::Shutdow
     mStatus = SHUTDOWN_IN_PROGRESS;
 
     // Shutdown the component manager
     PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsComponentManager: Beginning Shutdown."));
 
     // Release all cached factories
     mContractIDs.Clear();
     mFactories.Clear(); // XXX release the objects, don't just clear
+    mLoaderMap.Clear();
+    mKnownFileModules.Clear();
 
     mLoaderData.Clear();
 
     // Unload libraries
     mNativeModuleLoader.UnloadLibraries();
 
     // delete arena for strings and small objects
     PL_FinishArenaPool(&mArena);
@@ -1239,26 +1455,16 @@ nsComponentManagerImpl::LoaderForExtensi
             return NULL;
 
         mLoaderMap.Put(aExt, loader);
     }
 
     return loader.forget();
 }
 
-static void
-ReportLoadFailure(nsIFile* aFile, nsIConsoleService* aCS)
-{
-    nsAutoString message;
-    aFile->GetPath(message);
-    message.Insert(NS_LITERAL_STRING("Failed to load XPCOM component: "), 0);
-
-    aCS->LogStringMessage(message.get());
-}
-
 NS_IMETHODIMP
 nsComponentManagerImpl::RegisterFactory(const nsCID& aClass,
                                         const char* aName,
                                         const char* aContractID,
                                         nsIFactory* aFactory)
 {
     nsAutoPtr<nsFactoryEntry> f = new nsFactoryEntry(aFactory);
 
@@ -1413,17 +1619,17 @@ nsFactoryEntry::GetFactory()
 
         if (!mModule->Load())
             return NULL;
 
         if (mModule->Module()->getfactory) {
             mFactory = mModule->Module()->getfactory(*mModule->Module(),
                                                     *mCIDEntry);
         }
-        if (mCIDEntry->getfactory) {
+        else if (mCIDEntry->getfactory) {
             mFactory = mCIDEntry->getfactory(*mModule->Module(), *mCIDEntry);
         }
         else {
             NS_ASSERTION(mCIDEntry->constructor, "no getfactory or constructor");
             mFactory = new mozilla::GenericFactory(mCIDEntry->constructor);
         }
         if (!mFactory)
             return NULL;
@@ -1476,19 +1682,22 @@ XRE_AddStaticComponent(const mozilla::Mo
     if (nsComponentManagerImpl::gComponentManager &&
         nsComponentManagerImpl::NORMAL == nsComponentManagerImpl::gComponentManager->mStatus)
         nsComponentManagerImpl::gComponentManager->RegisterModule(aComponent, NULL);
 
     return NS_OK;
 }
 
 EXPORT_XPCOM_API(nsresult)
-XRE_AddComponentLocation(nsILocalFile* aLocation)
+XRE_AddComponentLocation(NSLocationType aType, nsILocalFile* aLocation)
 {
     nsComponentManagerImpl::InitializeModuleLocations();
-    nsComponentManagerImpl::sModuleLocations->AppendObject(aLocation);
+    nsComponentManagerImpl::ComponentLocation* c = 
+        nsComponentManagerImpl::sModuleLocations->AppendElement();
+    c->type = aType;
+    c->location = aLocation;
 
     if (nsComponentManagerImpl::gComponentManager &&
         nsComponentManagerImpl::NORMAL == nsComponentManagerImpl::gComponentManager->mStatus)
-        nsComponentManagerImpl::gComponentManager->RegisterLocation(aLocation);
+        nsComponentManagerImpl::gComponentManager->RegisterLocation(aType, aLocation);
 
     return NS_OK;
 }
--- a/xpcom/components/nsComponentManager.h
+++ b/xpcom/components/nsComponentManager.h
@@ -42,31 +42,33 @@
 
 #include "xpcom-private.h"
 #include "nsIComponentManager.h"
 #include "nsIComponentRegistrar.h"
 #include "nsIServiceManager.h"
 #include "nsILocalFile.h"
 #include "mozilla/Module.h"
 #include "mozilla/ModuleLoader.h"
+#include "nsXULAppAPI.h"
 #include "nsNativeComponentLoader.h"
 #include "nsIFactory.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "pldhash.h"
 #include "prtime.h"
 #include "prmon.h"
 #include "nsCOMPtr.h"
 #include "nsAutoPtr.h"
 #include "nsWeakReference.h"
 #include "nsIFile.h"
 #include "plarena.h"
 #include "nsCOMArray.h"
 #include "nsDataHashtable.h"
 #include "nsInterfaceHashtable.h"
+#include "nsClassHashtable.h"
 #include "nsTArray.h"
 
 struct nsFactoryEntry;
 class nsIServiceManager;
 struct PRThread;
 
 #define NS_COMPONENTMANAGER_CID                      \
 { /* 91775d60-d5dc-11d2-92fb-00e09805570f */         \
@@ -152,74 +154,111 @@ public:
     nsDataHashtable<nsIDHashKey, nsFactoryEntry*> mFactories;
     nsDataHashtable<nsCStringHashKey, nsFactoryEntry*> mContractIDs;
 
     PRMonitor*          mMon;
 
     static void InitializeStaticModules();
     static void InitializeModuleLocations();
 
+    struct ComponentLocation
+    {
+        NSLocationType type;
+        nsCOMPtr<nsILocalFile> location;
+    };
+
     static nsTArray<const mozilla::Module*>* sStaticModules;
-    static nsCOMArray<nsILocalFile>* sModuleLocations;
+    static nsTArray<ComponentLocation>* sModuleLocations;
 
     nsNativeModuleLoader mNativeModuleLoader;
 
     class KnownModule
     {
     public:
         /**
          * Static or binary module.
          */
         KnownModule(const mozilla::Module* aModule, nsILocalFile* aFile)
             : mModule(aModule)
             , mFile(aFile)
             , mLoaded(false)
             , mFailed(false)
         { }
 
-        KnownModule(nsILocalFile* aFile, mozilla::ModuleLoader* aLoader)
+        KnownModule(nsILocalFile* aFile)
             : mModule(NULL)
             , mFile(aFile)
-            , mLoader(aLoader)
+            , mLoader(NULL)
             , mLoaded(false)
             , mFailed(false)
         { }
 
         ~KnownModule()
         {
             if (mLoaded && mModule->unloaded)
                 mModule->unloaded();
         }
 
+        bool EnsureLoader();
         bool Load();
 
         const mozilla::Module* Module() const
         {
             return mModule;
         }
 
     private:
         const mozilla::Module* mModule;
         nsCOMPtr<nsILocalFile> mFile;
         nsCOMPtr<mozilla::ModuleLoader> mLoader;
         bool mLoaded;
         bool mFailed;
     };
 
-    nsTArray< nsAutoPtr<KnownModule> > mKnownModules;
+    // The KnownModule is kept alive by these members, it is referenced by pointer
+    // from the factory entries.
+    nsTArray< nsAutoPtr<KnownModule> > mKnownStaticModules;
+    nsClassHashtable<nsHashableHashKey, KnownModule> mKnownFileModules;
 
     void RegisterModule(const mozilla::Module* aModule,
                         nsILocalFile* aFile);
     void RegisterCIDEntry(const mozilla::Module::CIDEntry* aEntry,
                           KnownModule* aModule);
     void RegisterContractID(const mozilla::Module::ContractIDEntry* aEntry);
 
-    void RegisterLocation(nsILocalFile* aLocation);
-    void RegisterDirectory(nsILocalFile* aDirectory);
-    void RegisterFile(nsILocalFile* aFile);
+    void RegisterLocation(NSLocationType aType, nsILocalFile* aLocation);
+
+    // Register XPT/XPTJAR files, and fills aManifests with .manifest
+    // files, which must be registered after all DLLs so that networking is
+    // registered.
+    void RegisterDirectory(NSLocationType aType, nsILocalFile* aDirectory,
+                           nsCOMArray<nsILocalFile>& aManifests);
+    void RegisterFile(NSLocationType aType, nsILocalFile* aFile,
+                      nsCOMArray<nsILocalFile>& aManifests);
+
+    void RegisterManifestFile(NSLocationType aType, nsILocalFile* aFile);
+
+    struct ManifestProcessingContext
+    {
+        ManifestProcessingContext(NSLocationType aType, nsILocalFile* aFile)
+            : mType(aType)
+            , mFile(aFile)
+        { }
+        ~ManifestProcessingContext() { }
+
+        NSLocationType mType;
+        nsCOMPtr<nsILocalFile> mFile;
+    };
+
+    void ManifestBinaryComponent(ManifestProcessingContext& cx, int lineno, char *const * argv);
+    void ManifestComponent(ManifestProcessingContext& cx, int lineno, char *const * argv);
+    void ManifestContract(ManifestProcessingContext& cx, int lineno, char* const * argv);
+    void ManifestCategory(ManifestProcessingContext& cx, int lineno, char* const * argv);
+
+    void RereadChromeManifests();
 
     // Shutdown
     enum {
         NOT_INITIALIZED,
         NORMAL,
         SHUTDOWN_IN_PROGRESS,
         SHUTDOWN_COMPLETE
     } mStatus;
--- a/xpcom/glue/nsClassHashtable.h
+++ b/xpcom/glue/nsClassHashtable.h
@@ -58,16 +58,22 @@ public:
   typedef typename KeyClass::KeyType KeyType;
   typedef T* UserDataType;
 
   /**
    * @copydoc nsBaseHashtable::Get
    * @param pData if the key doesn't exist, pData will be set to nsnull.
    */
   PRBool Get(KeyType aKey, UserDataType* pData) const;
+
+  /**
+   * @copydoc nsBaseHashtable::Get
+   * @returns NULL if the key is not present.
+   */
+  UserDataType Get(KeyType aKey) const;
 };
 
 
 /**
  * Thread-safe version of nsClassHashtable
  * @param KeyClass a wrapper-class for the hashtable key, see nsHashKeys.h
  *   for a complete specification.
  * @param Class the class-type being wrapped
@@ -109,16 +115,29 @@ nsClassHashtable<KeyClass,T>::Get(KeyTyp
   }
 
   if (retVal)
     *retVal = nsnull;
 
   return PR_FALSE;
 }
 
+template<class KeyClass,class T>
+T*
+nsClassHashtable<KeyClass,T>::Get(KeyType aKey) const
+{
+  typename nsBaseHashtable<KeyClass,nsAutoPtr<T>,T*>::EntryType* ent =
+    GetEntry(aKey);
+
+  if (!ent)
+    return NULL;
+
+  return ent->mData;
+}
+
 
 //
 // nsClassHashtableMT definitions
 //
 
 template<class KeyClass,class T>
 PRBool
 nsClassHashtableMT<KeyClass,T>::Get(KeyType aKey, T** retVal) const
--- a/xpcom/sample/Makefile.in
+++ b/xpcom/sample/Makefile.in
@@ -104,8 +104,13 @@ endif
 include $(topsrcdir)/config/rules.mk
 
 libs:: $(TARGETS)
 	$(INSTALL) $(srcdir)/xpconnect-sample.html $(DIST)/bin/res/samples
 
 install:: $(TARGETS)
 	$(SYSINSTALL) $(IFLAGS1) $(srcdir)/xpconnect-sample.html $(DESTDIR)$(mozappdir)/res/samples
 
+# XXX TEMPORARY DEMONSTRATION HACK
+libs::
+	$(PYTHON) $(topsrcdir)/config/Preprocessor.py -Fsubstitution $(DEFINES) $(srcdir)/nsSample.manifest > $(DIST)/bin/components/nsSample.manifest
+
+DEFINES += -DSHARED_LIBRARY=$(SHARED_LIBRARY)
--- a/xpcom/sample/nsSample.js
+++ b/xpcom/sample/nsSample.js
@@ -35,95 +35,35 @@ mySample.prototype = {
         if (iid.equals(Components.interfaces.nsISample) ||
             iid.equals(Components.interfaces.nsISupports))
             return this;
 
         throw Components.results.NS_ERROR_NO_INTERFACE;
     },
 
     val: "<default value>"
-}
-
-var myModule = {
-    firstTime: true,
-
-    /*
-     * RegisterSelf is called at registration time (component installation
-     * or the only-until-release startup autoregistration) and is responsible
-     * for notifying the component manager of all components implemented in
-     * this module.  The fileSpec, location and type parameters are mostly
-     * opaque, and should be passed on to the registerComponent call
-     * unmolested.
-     */
-    registerSelf: function (compMgr, fileSpec, location, type) {
-        if (this.firstTime) {
-            debug("*** Deferring registration of sample JS components\n");
-            this.firstTime = false;
-            throw Components.results.NS_ERROR_FACTORY_REGISTER_AGAIN;
-        }
-        debug("*** Registering sample JS components\n");
-        compMgr = compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
-        compMgr.registerFactoryLocation(this.myCID,
-                                        "Sample JS Component",
-                                        this.myProgID,
-                                        fileSpec,
-                                        location,
-                                        type);
-    },
-
-    /*
-     * The GetClassObject method is responsible for producing Factory objects
-     */
-    getClassObject: function (compMgr, cid, iid) {
-        if (!cid.equals(this.myCID))
-            throw Components.results.NS_ERROR_NO_INTERFACE;
-
-        if (!iid.equals(Components.interfaces.nsIFactory))
-            throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
-
-        return this.myFactory;
-    },
-
-    /* CID for this class */
-    myCID: Components.ID("{dea98e50-1dd1-11b2-9344-8902b4805a2e}"),
-
-    /* ProgID for this class */
-    myProgID: "@mozilla.org/jssample;1",
-
-    /* factory object */
-    myFactory: {
-        /*
-         * Construct an instance of the interface specified by iid, possibly
-         * aggregating it with the provided outer.  (If you don't know what
-         * aggregation is all about, you don't need to.  It reduces even the
-         * mightiest of XPCOM warriors to snivelling cowards.)
-         */
-        createInstance: function (outer, iid) {
-            debug("CI: " + iid + "\n");
-            if (outer != null)
-                throw Components.results.NS_ERROR_NO_AGGREGATION;
-
-            return (new mySample()).QueryInterface(iid);
-        }
-    },
-
-    /*
-     * The canUnload method signals that the component is about to be unloaded.
-     * C++ components can return false to indicate that they don't wish to be
-     * unloaded, but the return value from JS components' canUnload is ignored:
-     * mark-and-sweep will keep everything around until it's no longer in use,
-     * making unconditional ``unload'' safe.
-     *
-     * You still need to provide a (likely useless) canUnload method, though:
-     * it's part of the nsIModule interface contract, and the JS loader _will_
-     * call it.
-     */
-    canUnload: function(compMgr) {
-        debug("*** Unloading sample JS components\n");
-        return true;
-    }
 };
 
-function NSGetModule(compMgr, fileSpec) {
-    return myModule;
+const kMyCID = Components.ID("{dea98e50-1dd1-11b2-9344-8902b4805a2e}");
+
+const kMyFactory = {
+    /*
+     * Construct an instance of the interface specified by iid, possibly
+     * aggregating it with the provided outer.  (If you don't know what
+     * aggregation is all about, you don't need to.  It reduces even the
+     * mightiest of XPCOM warriors to snivelling cowards.)
+     */
+ createInstance: function (outer, iid) {
+   debug("CI: " + iid + "\n");
+   if (outer != null)
+     throw Components.results.NS_ERROR_NO_AGGREGATION;
+
+   return (new mySample()).QueryInterface(iid);
+  }
+};
+
+function NSGetFactory(cid)
+{
+    if (cid.equals(kMyCID))
+        return kMyFactory;
+        
+    throw Components.results.NS_ERROR_FACTORY_NOT_REGISTERED;
 }
-
-
new file mode 100644
--- /dev/null
+++ b/xpcom/sample/nsSample.manifest
@@ -0,0 +1,3 @@
+component dea98e50-1dd1-11b2-9344-8902b4805a2e nsSample.js
+contract @mozilla.org/jssample;1 dea98e50-1dd1-11b2-9344-8902b4805a2e
+binary-component @SHARED_LIBRARY@
--- a/xpcom/tests/TestRegistrationOrder.cpp
+++ b/xpcom/tests/TestRegistrationOrder.cpp
@@ -156,18 +156,20 @@ int main(int argc, char** argv)
   if (argc < 2)
   {
     fprintf(stderr, "not enough arguments -- need registration dir path\n");
     return 1;
   }
 
   
   const char *regPath = argv[1];
-  XRE_AddComponentLocation(nsCOMPtr<nsILocalFile>(GetRegDirectory(regPath, "core")));
-  XRE_AddComponentLocation(nsCOMPtr<nsILocalFile>(GetRegDirectory(regPath, "extension")));
+  XRE_AddComponentLocation(NS_COMPONENT_LOCATION,
+                           nsCOMPtr<nsILocalFile>(GetRegDirectory(regPath, "core")));
+  XRE_AddComponentLocation(NS_COMPONENT_LOCATION,
+                           nsCOMPtr<nsILocalFile>(GetRegDirectory(regPath, "extension")));
   ScopedXPCOM xpcom("RegistrationOrder");
   if (xpcom.failed())
     return 1;
 
   int rv = 0;
   if (NS_FAILED(TestRegular()))
     rv = 1;
   if (NS_FAILED(TestDeferred()))