diff --git a/xpcom/components/nsCategoryManager.js b/xpcom/components/nsCategoryManager.js index f20492a331c..ed8ebd40850 100644 --- a/xpcom/components/nsCategoryManager.js +++ b/xpcom/components/nsCategoryManager.js @@ -18,123 +18,263 @@ function CategoryManager() { this.categories = { }; + this.loadRegistryData(this); } -function NYI () { throw Components.results.NS_ERROR_NOT_IMPLEMENTED; } + +function NYI() { throw Components.results.NS_ERROR_NOT_IMPLEMENTED; } var proto = CategoryManager.prototype; var nsICategoryManager = Components.interfaces.nsICategoryManager; +var categoriesKey; // registry key for category data +var registry; // registry handle proto.getCategoryEntry = function (category, entry) { var cat = this.categories[category]; if (!cat) - return null; + return null; if ("override" in cat) - return cat.override.getCategoryEntry(category, entry); + return cat.override.getCategoryEntry(category, entry); var table = cat.table; if (entry in table) - return table[entry]; - if ("fallback" in cat) { - dump("\n--fallback: " + cat.fallback + "\n"); - return cat.fallback.getCategoryEntry(category, entry); - } + return table[entry]; + if ("fallback" in cat) + return cat.fallback.getCategoryEntry(category, entry); return null; }; proto.getCategoryEntryRaw = function (category, entry) { var table; var cat = this.categories[category]; - if (!cat || - (!entry in (table = cat.table))) - return null; + if (!(cat && entry in (table = cat.table))) + return null; if (entry in table) - return table[entry]; + return table[entry]; if ("fallback" in cat) - return cat.fallback.getCategoryEntry(category, entry); + return cat.fallback.getCategoryEntry(category, entry); return null; } -proto.addCategoryEntry = function (category, entry, value, persist, replace) { - if (!(category in this.categories)) { - dump("aCE: creating category \"" + category + "\"\n"); - this.categories[category] = { name:category, table:{ } }; +function addEntryToRegistry(category, entry, value) +{ + var categorySubtree; + try { + categorySubtree = registry.getSubtreeRaw(categoriesKey, category); + } catch (e : + e instanceof Components.interfaces.nsIXPCException && + e.result === 0x80510003 /* XXX NS_ERROR_REG_NOT_FOUND */) { + categorySubtree = registry.addSubtreeRaw(categoriesKey, category); } + registry.setString(categorySubtree, entry, value); +} + +proto.addCategoryEntry = function (category, entry, value, persist, replace) { + if (!(category in this.categories)) + this.categories[category] = { name:category, table:{ } }; var table = this.categories[category].table; var oldValue; if (entry in table) { - if (!replace) - throw Components.results.NS_ERROR_INVALID_ARG; - oldValue = table[entry]; + if (!replace) + throw Components.results.NS_ERROR_INVALID_ARG; + oldValue = table[entry]; } else { - oldValue = null; + oldValue = null; } table[entry] = value; if (persist) - // need registry - throw Components.results.NS_ERROR_NOT_IMPLEMENTED; + addEntryToRegistry(category, entry, value); return oldValue; } -proto.enumerateCategory = NYI; +function deleteEntryFromRegistry(category, entry) +{ + dump("(not) deleting " + category + "[" + entry + "] from reg\n"); + try { + var categorySubtree = registry.getSubtreeRaw(categoriesKey, category); + /* registry.deleteValue(categorySubtree, entry); */ + } catch (e : + e instanceof Components.interfaces.nsIXPCException && + e.result === 0x80510003 /* XXX NS_ERROR_REG_NOT_FOUND */) { + return false; + } + return true; +} + +proto.deleteCategoryEntry = function (category, entry, persist) { + if (!(category in this.categories)) + return null; + var table = this.categories[category].table; + var old = table[entry]; + delete table[entry]; + if (persist) + deleteEntryFromRegistry(category, entry); + return old; +}; + +function deleteCategoryFromRegistry(category) { + try { + registry.removeSubtreeRaw(categoriesKey, category); + } catch (e : + e instanceof Components.interfaces.nsIXPCException && + e.result === 0x80510003 /* XXX NS_ERROR_REG_NOT_FOUND */) { + return false; + } + return true; +} + +proto.deleteCategory = function (category, persist) { + delete this.categories[category]; + /* + * Don't check for delete success, because persist means to remove from + * registry, even if someone has already done a non-persistent removal + * before. + */ + if (persist) + deleteCategoryFromRegistry(category); +}; + +function CategoryEnumerator(category) { + this.category = category; +}; + +proto.enumerateCategory = function (category) { + return new CategoryEnumerator(this.categories[category] || { }); +} + proto.getCategoryContents = NYI; proto.registerCategoryHandler = function(category, handler, mode) { - dump("nCM: handler.getCategoryEntry: " + handler.getCategoryEntry + "\n"); - dump("typeof handler: " + typeof handler + "\n"); - /* - dump('rCH: "' + category + '".' + - (mode == nsICategoryManager.fallback ? "fallback" : - (mode == nsICategoryManager.override ? "override" : - mode)) + " = " + handler + "\n"); - */ - if (!(category in this.categories)) { - dump("rCH: creating category \"" + category + "\"\n"); - this.categories[category] = { table:{ } }; - } + if (!(category in this.categories)) + this.categories[category] = { table:{ } }; + var old; var category = this.categories[category]; - if (mode == nsICategoryManager.override) { - old = category.override || null; - category.override = handler; - } else if (mode == nsICategoryManager.fallback) { - old = category.fallback || null; - category.fallback = handler; + if (mode == nsICategoryManager.OVERRIDE) { + old = category.override || null; + category.override = handler; + } else if (mode == nsICategoryManager.FALLBACK) { + old = category.fallback || null; + category.fallback = handler; } else { - dump("\nregisterCategoryHandler: illegal mode " + mode + "\n\n"); throw Components.results.NS_ERROR_INVALID_ARG; } + /* XXX shaver: store CID in the registry, repopulate at startup? */ return old; }; + proto.unregisterCategoryHandler = NYI; -var module = { - RegisterSelf:function (compMgr, fileSpec, location, type) { - compMgr.registerComponentWithType(this.myCID, - "Category Manager", - "mozilla.categorymanager.1", - fileSpec, location, true, true, - type); - }, - 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; +proto.loadRegistryData = function() { + var nsIRegistry = Components.interfaces.nsIRegistry; + registry = Components.classes["component://netscape/registry"]. + createInstance(nsIRegistry); + registry.openWellKnownRegistry(nsIRegistry.ApplicationComponentRegistry); + try { + categoriesKey = + registry.getSubtree(nsIRegistry.Common, + "Software/Mozilla/XPCOM/Categories"); + } catch (e : + e instanceof Components.interfaces.nsIXPCException && + e.result === 0x80510003 /* XXX NS_ERROR_REG_NOT_FOUND */) { + dump("creating Categories registry point\n"); + categoriesKey = + registry.addSubtree(nsIRegistry.Common, + "Software/Mozilla/XPCOM/Categories"); + return; + } - return this.myFactory; + var en = registry.enumerateSubtrees(categoriesKey); + + /* + * Waterson's right: the nsIEnumerator interface is basically + * complete crap. There is no way to do anything, really, without + * gobs of exceptions and other nonsense, because apparently boolean + * out parameters are rocket science. + * + * And don't get me started about COMFALSE. (I'm sure this seemed like + * a good idea at the time, but it really sucks right now.) + * + * Do not look directly at the following code. + */ + try { en.first(); } catch (e) { return; } + + while (en.isDone(), Components.lastResult != Components.results.NS_OK) { + try { + node = en.currentItem(); + node = node.QueryInterface(Components.interfaces.nsIRegistryNode); + } catch (e : e instanceof Components.interfaces.nsIXPCException) { + try { en.next(); } catch (e) { } + continue; + } + var category = node.name; + var catenum = registry.enumerateValues(node.key); + try { + catenum.first(); + } catch (e) { + continue; + } + while(catenum.isDone(), + Components.lastResult != Components.results.NS_OK) { + var entry; + try { + entry = catenum.currentItem(); + entry = entry.QueryInterface(Components.interfaces.nsIRegistryValue); + } catch (e : e instanceof Components.interfaces.nsIXPCException) { + dump("not a value?\n"); + try { catenum.next(); } catch (e) { } + continue; + } + try { + var value = registry.getString(node.key, entry.name); + this.addCategoryEntry(category, entry.name, value); + } catch (e) { + dump ("no " + entry.name + " in " + category + "?\n"); + } + try { catenum.next(); } catch (e) { } + } + try { en.next(); } catch (e) { } + } +} + +var module = { + registerSelf: function (compMgr, fileSpec, location, type) { + compMgr.registerComponentWithType(this.myCID, + "Category Manager", + "mozilla.categorymanager.1", + fileSpec, location, true, true, + type); }, - myCID:Components.ID("{16d222a6-1dd2-11b2-b693-f38b02c021b2}"), - myFactory:{ - CreateInstance:function (outer, iid) { - if (outer != null) - throw Components.results.NS_ERROR_NO_AGGREGATION; - - if (!(iid.equals(nsICategoryManager) || - iid.equals(Components.interfaces.nsISupports))) - throw Components.results.NS_ERROR_INVALID_ARG; - return new CategoryManager(); - } + + 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; + }, + + canUnload: function () { + dump("unloading category manager\n"); + try { registry.close(); } catch (e) { } + }, + + myCID: Components.ID("{16d222a6-1dd2-11b2-b693-f38b02c021b2}"), + + myFactory: { + CreateInstance: function (outer, iid) { + if (outer != null) + throw Components.results.NS_ERROR_NO_AGGREGATION; + + if (!(iid.equals(nsICategoryManager) || + iid.equals(Components.interfaces.nsISupports))) { + throw Components.results.NS_ERROR_INVALID_ARG; + } + + return new CategoryManager(); + } } }; function NSGetModule(compMgr, fileSpec) { return module; } + diff --git a/xpcom/components/nsICategoryManager.idl b/xpcom/components/nsICategoryManager.idl index 454bc37a407..1adc8b407e0 100644 --- a/xpcom/components/nsICategoryManager.idl +++ b/xpcom/components/nsICategoryManager.idl @@ -44,17 +44,34 @@ interface nsICategoryManager : nsISupports * @param aValue The value for the entry ("moz.httprulez.1") * @param aPersist Should we persist between invocations? * @param aReplace Should we replace an existing entry? - * @return previous entry, if any + * @return Previous entry, if any */ string addCategoryEntry(in string aCategory, in string aEntry, in string aValue, in boolean aPersist, in boolean aReplace); + /** + * Delete an entry from the category. + * @param aCategory The name of the category ("protocol") + * @param aEntry The entry to be added ("http") + * @param aPersist Delete entry from registry, if present? + * @return Previous entry, null if none. + */ + string deleteCategoryEntry(in string aCategory, in string aEntry, + in boolean aPersist); + + /** + * Delete a category and all entries. + * @param aCategory The category to be deleted. + * @param aPersist Delete the category from the registry? + */ + void deleteCategory(in string aCategory); + /** * Enumerate the entries in a category. * @param aCategory The category to be enumerated. */ - nsIEnumerator enumerateCategory(in string aCategory); + nsISimpleEnumerator enumerateCategory(in string aCategory); /** * Get all the category contents. @@ -64,10 +81,8 @@ interface nsICategoryManager : nsISupports [array, size_is(count)] out string values, [retval] out long count); - const long override = 0; - const long fallback = 1; - const long checkFirst = 0; - const long checkLast = 1; + const long OVERRIDE = 0; + const long FALLBACK = 1; /* * Register a category handler for override or fallback when diff --git a/xpcom/components/nsIModule.idl b/xpcom/components/nsIModule.idl index 4cbbf2fd958..fc47ea32c85 100644 --- a/xpcom/components/nsIModule.idl +++ b/xpcom/components/nsIModule.idl @@ -29,25 +29,25 @@ interface nsIModule : nsISupports // create new objects. // SingletonFactory can be queried off the Class Object. Services can be created // using the singletonfactory. - void GetClassObject(in nsIComponentManager aCompMgr, in nsCIDRef aClass, + void getClassObject(in nsIComponentManager aCompMgr, in nsCIDRef aClass, in nsIIDRef aIID, [retval, iid_is(aIID)] out nsQIResult result); // Component registration - void RegisterSelf(in nsIComponentManager aCompMgr, in nsIFileSpec location, + void registerSelf(in nsIComponentManager aCompMgr, in nsIFileSpec location, in string registryLocation, in string componentType); - void UnregisterSelf(in nsIComponentManager aCompMgr, in nsIFileSpec location, + void unregisterSelf(in nsIComponentManager aCompMgr, in nsIFileSpec location, in string registryLocation); // Module load management - // okToUnload: indicates to the caller if the module can be unloaded. + // @return indicates to the caller if the module can be unloaded. // Returning PR_TRUE isn't a guarantee that the module will be // unloaded. It constitues only willingness of the module to be // unloaded. // Returning PR_FALSE guaratees that the module wont be unloaded. // - void CanUnload(in nsIComponentManager aCompMgr, out boolean okToUnload); + boolean canUnload(in nsIComponentManager aCompMgr); }; %{C++