Back to index

lightning-sunbird  0.9+nobinonly
nsScriptNameSpaceManager.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Mozilla Communicator client code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "nsScriptNameSpaceManager.h"
00039 #include "nsCOMPtr.h"
00040 #include "nsIComponentManager.h"
00041 #include "nsIComponentRegistrar.h"
00042 #include "nsICategoryManager.h"
00043 #include "nsIServiceManager.h"
00044 #include "nsXPCOM.h"
00045 #include "nsISupportsPrimitives.h"
00046 #include "nsIScriptExternalNameSet.h"
00047 #include "nsIScriptNameSpaceManager.h"
00048 #include "nsIScriptContext.h"
00049 #include "nsIInterfaceInfoManager.h"
00050 #include "nsIInterfaceInfo.h"
00051 #include "xptinfo.h"
00052 #include "nsXPIDLString.h"
00053 #include "nsReadableUtils.h"
00054 #include "nsHashKeys.h"
00055 #include "nsDOMClassInfo.h"
00056 #include "nsCRT.h"
00057 
00058 #define NS_INTERFACE_PREFIX "nsI"
00059 #define NS_DOM_INTERFACE_PREFIX "nsIDOM"
00060 
00061 // Our extended PLDHashEntryHdr
00062 class GlobalNameMapEntry : public PLDHashEntryHdr
00063 {
00064 public:
00065   // Our hash table ops don't care about the order of these members
00066   nsString mKey;
00067   nsGlobalNameStruct mGlobalName;
00068 };
00069 
00070 
00071 PR_STATIC_CALLBACK(const void *)
00072 GlobalNameHashGetKey(PLDHashTable *table, PLDHashEntryHdr *entry)
00073 {
00074   GlobalNameMapEntry *e = NS_STATIC_CAST(GlobalNameMapEntry *, entry);
00075 
00076   return NS_STATIC_CAST(const nsAString *, &e->mKey);
00077 }
00078 
00079 PR_STATIC_CALLBACK(PLDHashNumber)
00080 GlobalNameHashHashKey(PLDHashTable *table, const void *key)
00081 {
00082   const nsAString *str = NS_STATIC_CAST(const nsAString *, key);
00083 
00084   return HashString(*str);
00085 }
00086 
00087 PR_STATIC_CALLBACK(PRBool)
00088 GlobalNameHashMatchEntry(PLDHashTable *table, const PLDHashEntryHdr *entry,
00089                          const void *key)
00090 {
00091   const GlobalNameMapEntry *e =
00092     NS_STATIC_CAST(const GlobalNameMapEntry *, entry);
00093   const nsAString *str = NS_STATIC_CAST(const nsAString *, key);
00094 
00095   return str->Equals(e->mKey);
00096 }
00097 
00098 PR_STATIC_CALLBACK(void)
00099 GlobalNameHashClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
00100 {
00101   GlobalNameMapEntry *e = NS_STATIC_CAST(GlobalNameMapEntry *, entry);
00102 
00103   // An entry is being cleared, let the key (nsString) do its own
00104   // cleanup.
00105   e->mKey.~nsString();
00106   if (e->mGlobalName.mType == nsGlobalNameStruct::eTypeExternalClassInfo) {
00107     nsIClassInfo* ci = GET_CLEAN_CI_PTR(e->mGlobalName.mData->mCachedClassInfo);
00108 
00109     // If we constructed an internal helper, we'll let the helper delete 
00110     // the nsDOMClassInfoData structure, if not we do it here.
00111     if (!ci || e->mGlobalName.mData->u.mExternalConstructorFptr) {
00112       delete e->mGlobalName.mData;
00113     }
00114 
00115     // Release our pointer to the helper.
00116     NS_IF_RELEASE(ci);
00117   }
00118   else if (e->mGlobalName.mType == nsGlobalNameStruct::eTypeExternalConstructorAlias) {
00119     delete e->mGlobalName.mAlias;
00120   }
00121 
00122   // This will set e->mGlobalName.mType to
00123   // nsGlobalNameStruct::eTypeNotInitialized
00124   memset(&e->mGlobalName, 0, sizeof(nsGlobalNameStruct));
00125 }
00126 
00127 PR_STATIC_CALLBACK(PRBool)
00128 GlobalNameHashInitEntry(PLDHashTable *table, PLDHashEntryHdr *entry,
00129                         const void *key)
00130 {
00131   GlobalNameMapEntry *e = NS_STATIC_CAST(GlobalNameMapEntry *, entry);
00132   const nsAString *keyStr = NS_STATIC_CAST(const nsAString *, key);
00133 
00134   // Initialize the key in the entry with placement new
00135   new (&e->mKey) nsString(*keyStr);
00136 
00137   // This will set e->mGlobalName.mType to
00138   // nsGlobalNameStruct::eTypeNotInitialized
00139   memset(&e->mGlobalName, 0, sizeof(nsGlobalNameStruct));
00140   return PR_TRUE;
00141 }
00142 
00143 nsScriptNameSpaceManager::nsScriptNameSpaceManager()
00144   : mIsInitialized(PR_FALSE)
00145 {
00146 }
00147 
00148 nsScriptNameSpaceManager::~nsScriptNameSpaceManager()
00149 {
00150   if (mIsInitialized) {
00151     // Destroy the hash
00152     PL_DHashTableFinish(&mGlobalNames);
00153   }
00154 }
00155 
00156 nsGlobalNameStruct *
00157 nsScriptNameSpaceManager::AddToHash(const char *aKey)
00158 {
00159   NS_ConvertASCIItoUTF16 key(aKey);
00160   GlobalNameMapEntry *entry =
00161     NS_STATIC_CAST(GlobalNameMapEntry *,
00162                    PL_DHashTableOperate(&mGlobalNames, &key, PL_DHASH_ADD));
00163 
00164   if (!entry) {
00165     return nsnull;
00166   }
00167 
00168   return &entry->mGlobalName;
00169 }
00170 
00171 nsGlobalNameStruct*
00172 nsScriptNameSpaceManager::GetConstructorProto(const nsGlobalNameStruct* aStruct)
00173 {
00174   NS_ASSERTION(aStruct->mType == nsGlobalNameStruct::eTypeExternalConstructorAlias,
00175                "This function only works on constructor aliases!");
00176   if (!aStruct->mAlias->mProto) {
00177     GlobalNameMapEntry *proto =
00178       NS_STATIC_CAST(GlobalNameMapEntry *,
00179                      PL_DHashTableOperate(&mGlobalNames,
00180                                           &aStruct->mAlias->mProtoName,
00181                                           PL_DHASH_LOOKUP));
00182 
00183     if (PL_DHASH_ENTRY_IS_BUSY(proto)) {
00184       aStruct->mAlias->mProto = &proto->mGlobalName;
00185     }
00186   }
00187   return aStruct->mAlias->mProto;
00188 }
00189 
00190 nsresult
00191 nsScriptNameSpaceManager::FillHash(nsICategoryManager *aCategoryManager,
00192                                    const char *aCategory,
00193                                    nsGlobalNameStruct::nametype aType)
00194 {
00195   nsCOMPtr<nsIComponentRegistrar> registrar;
00196   nsresult rv = NS_GetComponentRegistrar(getter_AddRefs(registrar));
00197   NS_ENSURE_SUCCESS(rv, rv);
00198 
00199   nsCOMPtr<nsISimpleEnumerator> e;
00200   rv = aCategoryManager->EnumerateCategory(aCategory, getter_AddRefs(e));
00201   NS_ENSURE_SUCCESS(rv, rv);
00202 
00203   nsCAutoString categoryEntry;
00204   nsXPIDLCString contractId;
00205   nsCOMPtr<nsISupports> entry;
00206 
00207   while (NS_SUCCEEDED(e->GetNext(getter_AddRefs(entry)))) {
00208     nsCOMPtr<nsISupportsCString> category(do_QueryInterface(entry));
00209 
00210     if (!category) {
00211       NS_WARNING("Category entry not an nsISupportsCString!");
00212 
00213       continue;
00214     }
00215 
00216     rv = category->GetData(categoryEntry);
00217     NS_ENSURE_SUCCESS(rv, rv);
00218 
00219     rv = aCategoryManager->GetCategoryEntry(aCategory, categoryEntry.get(),
00220                                             getter_Copies(contractId));
00221     NS_ENSURE_SUCCESS(rv, rv);
00222 
00223     nsCID *cidPtr;
00224     rv = registrar->ContractIDToCID(contractId, &cidPtr);
00225 
00226     if (NS_FAILED(rv)) {
00227       NS_WARNING("Bad contract id registed with the script namespace manager");
00228 
00229       continue;
00230     }
00231 
00232     // Copy CID onto the stack, so we can free it right away and avoid having
00233     // to add cleanup code at every exit point from this loop/function.
00234     nsCID cid = *cidPtr;
00235     nsMemory::Free(cidPtr);
00236 
00237     if (aType == nsGlobalNameStruct::eTypeExternalConstructor) {
00238       nsXPIDLCString constructorProto;
00239       rv = aCategoryManager->GetCategoryEntry(JAVASCRIPT_GLOBAL_CONSTRUCTOR_PROTO_ALIAS_CATEGORY,
00240                                               categoryEntry.get(),
00241                                               getter_Copies(constructorProto));
00242       if (NS_SUCCEEDED(rv)) {
00243         nsGlobalNameStruct *s = AddToHash(categoryEntry.get());
00244         NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
00245 
00246         if (s->mType == nsGlobalNameStruct::eTypeNotInitialized) {
00247           s->mAlias = new nsGlobalNameStruct::ConstructorAlias;
00248           if (!s->mAlias) {
00249             // Free entry
00250             NS_ConvertASCIItoUCS2 key(categoryEntry);
00251             PL_DHashTableOperate(&mGlobalNames,
00252                                  &key,
00253                                  PL_DHASH_REMOVE);
00254             return NS_ERROR_OUT_OF_MEMORY;
00255           }
00256           s->mType = nsGlobalNameStruct::eTypeExternalConstructorAlias;
00257           s->mAlias->mCID = cid;
00258           AppendASCIItoUTF16(constructorProto, s->mAlias->mProtoName);
00259           s->mAlias->mProto = nsnull;
00260         } else {
00261           NS_WARNING("Global script name not overwritten!");
00262         }
00263 
00264         continue;
00265       }
00266     }
00267 
00268     nsGlobalNameStruct *s = AddToHash(categoryEntry.get());
00269     NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
00270 
00271     if (s->mType == nsGlobalNameStruct::eTypeNotInitialized) {
00272       s->mType = aType;
00273       s->mCID = cid;
00274     } else {
00275       NS_WARNING("Global script name not overwritten!");
00276     }
00277   }
00278 
00279   return NS_OK;
00280 }
00281 
00282 
00283 // This method enumerates over all installed interfaces (in .xpt
00284 // files) and finds ones that start with "nsIDOM" and has constants
00285 // defined in the interface itself (inherited constants doesn't
00286 // count), once such an interface is found the "nsIDOM" prefix is cut
00287 // off the name and the rest of the name is added into the hash for
00288 // global names. This makes things like 'Node.ELEMENT_NODE' work in
00289 // JS. See nsWindowSH::GlobalResolve() for detais on how this is used.
00290 
00291 nsresult
00292 nsScriptNameSpaceManager::FillHashWithDOMInterfaces()
00293 {
00294   nsCOMPtr<nsIInterfaceInfoManager> iim =
00295     dont_AddRef(XPTI_GetInterfaceInfoManager());
00296   NS_ENSURE_TRUE(iim, NS_ERROR_UNEXPECTED);
00297 
00298   // First look for all interfaces whose name starts with nsIDOM
00299   nsCOMPtr<nsIEnumerator> domInterfaces;
00300   nsresult rv =
00301     iim->EnumerateInterfacesWhoseNamesStartWith(NS_DOM_INTERFACE_PREFIX,
00302                                                 getter_AddRefs(domInterfaces));
00303   NS_ENSURE_SUCCESS(rv, rv);
00304 
00305   nsCOMPtr<nsISupports> entry;
00306 
00307   rv = domInterfaces->First();
00308 
00309   if (NS_FAILED(rv)) {
00310     // Empty interface list?
00311 
00312     NS_WARNING("What, no nsIDOM interfaces installed?");
00313 
00314     return NS_OK;
00315   }
00316 
00317   PRBool found_old;
00318   nsCOMPtr<nsIInterfaceInfo> if_info;
00319   nsXPIDLCString if_name;
00320   const nsIID *iid;
00321 
00322   for ( ; domInterfaces->IsDone() == NS_ENUMERATOR_FALSE; domInterfaces->Next()) {
00323     rv = domInterfaces->CurrentItem(getter_AddRefs(entry));
00324     NS_ENSURE_SUCCESS(rv, rv);
00325 
00326     nsCOMPtr<nsIInterfaceInfo> if_info(do_QueryInterface(entry));
00327     if_info->GetName(getter_Copies(if_name));
00328     if_info->GetIIDShared(&iid);
00329     rv = RegisterInterface(if_name.get() + sizeof(NS_DOM_INTERFACE_PREFIX) - 1,
00330                            iid, &found_old);
00331 
00332 #ifdef DEBUG
00333     NS_ASSERTION(!found_old,
00334                  "Whaaa, interface name already in hash!");
00335 #endif
00336   }
00337 
00338   // Next, look for externally registered DOM interfaces
00339   rv = RegisterExternalInterfaces(PR_FALSE);
00340 
00341   return rv;
00342 }
00343 
00344 nsresult
00345 nsScriptNameSpaceManager::RegisterExternalInterfaces(PRBool aAsProto)
00346 {
00347   nsresult rv;
00348   nsCOMPtr<nsICategoryManager> cm =
00349     do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv);
00350   NS_ENSURE_SUCCESS(rv, rv);
00351 
00352   nsCOMPtr<nsIInterfaceInfoManager> iim =
00353     dont_AddRef(XPTI_GetInterfaceInfoManager());
00354   NS_ENSURE_TRUE(iim, NS_ERROR_NOT_AVAILABLE);
00355 
00356   nsCOMPtr<nsISimpleEnumerator> enumerator;
00357   rv = cm->EnumerateCategory(JAVASCRIPT_DOM_INTERFACE,
00358                              getter_AddRefs(enumerator));
00359   NS_ENSURE_SUCCESS(rv, rv);
00360 
00361   nsXPIDLCString IID_string;
00362   nsCAutoString category_entry;
00363   const char* if_name;
00364   nsCOMPtr<nsISupports> entry;
00365   nsCOMPtr<nsIInterfaceInfo> if_info;
00366   PRBool found_old, dom_prefix;
00367 
00368   while (NS_SUCCEEDED(enumerator->GetNext(getter_AddRefs(entry)))) {
00369     nsCOMPtr<nsISupportsCString> category(do_QueryInterface(entry));
00370 
00371     if (!category) {
00372       NS_WARNING("Category entry not an nsISupportsCString!");
00373 
00374       continue;
00375     }
00376 
00377     rv = category->GetData(category_entry);
00378     NS_ENSURE_SUCCESS(rv, rv);
00379 
00380     rv = cm->GetCategoryEntry(JAVASCRIPT_DOM_INTERFACE, category_entry.get(),
00381                               getter_Copies(IID_string));
00382     NS_ENSURE_SUCCESS(rv, rv);
00383 
00384     nsIID primary_IID;
00385     if (!primary_IID.Parse(IID_string) ||
00386         primary_IID.Equals(NS_GET_IID(nsISupports))) {
00387       NS_ERROR("Invalid IID registered with the script namespace manager!");
00388       continue;
00389     }
00390 
00391     iim->GetInfoForIID(&primary_IID, getter_AddRefs(if_info));
00392 
00393     while (if_info) {
00394       const nsIID *iid;
00395       if_info->GetIIDShared(&iid);
00396       NS_ENSURE_TRUE(iid, NS_ERROR_UNEXPECTED);
00397 
00398       if (iid->Equals(NS_GET_IID(nsISupports))) {
00399         break;
00400       }
00401 
00402       if_info->GetNameShared(&if_name);
00403       dom_prefix = (strncmp(if_name, NS_DOM_INTERFACE_PREFIX,
00404                             sizeof(NS_DOM_INTERFACE_PREFIX) - 1) == 0);
00405 
00406       const char* name;
00407       if (dom_prefix) {
00408         if (!aAsProto) {
00409           // nsIDOM* interfaces have already been registered.
00410           break;
00411         }
00412         name = if_name + sizeof(NS_DOM_INTERFACE_PREFIX) - 1;
00413       } else {
00414         name = if_name + sizeof(NS_INTERFACE_PREFIX) - 1;
00415       }
00416 
00417       if (aAsProto) {
00418         RegisterClassProto(name, iid, &found_old);
00419       } else {
00420         RegisterInterface(name, iid, &found_old);
00421       }
00422 
00423       if (found_old) {
00424         break;
00425       }
00426 
00427       nsCOMPtr<nsIInterfaceInfo> tmp(if_info);
00428       tmp->GetParent(getter_AddRefs(if_info));
00429     }
00430   }
00431 
00432   return NS_OK;
00433 }
00434 
00435 nsresult
00436 nsScriptNameSpaceManager::RegisterInterface(const char* aIfName,
00437                                             const nsIID *aIfIID,
00438                                             PRBool* aFoundOld)
00439 {
00440   *aFoundOld = PR_FALSE;
00441 
00442   nsGlobalNameStruct *s = AddToHash(aIfName);
00443   NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
00444 
00445   if (s->mType != nsGlobalNameStruct::eTypeNotInitialized) {
00446     *aFoundOld = PR_TRUE;
00447 
00448     return NS_OK;
00449   }
00450 
00451   s->mType = nsGlobalNameStruct::eTypeInterface;
00452   s->mIID = *aIfIID;
00453 
00454   return NS_OK;
00455 }
00456 
00457 nsresult
00458 nsScriptNameSpaceManager::Init()
00459 {
00460   static PLDHashTableOps hash_table_ops =
00461   {
00462     PL_DHashAllocTable,
00463     PL_DHashFreeTable,
00464     GlobalNameHashGetKey,
00465     GlobalNameHashHashKey,
00466     GlobalNameHashMatchEntry,
00467     PL_DHashMoveEntryStub,
00468     GlobalNameHashClearEntry,
00469     PL_DHashFinalizeStub,
00470     GlobalNameHashInitEntry
00471   };
00472 
00473   mIsInitialized = PL_DHashTableInit(&mGlobalNames, &hash_table_ops, nsnull,
00474                                      sizeof(GlobalNameMapEntry), 128);
00475   NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_OUT_OF_MEMORY);
00476 
00477   nsresult rv = NS_OK;
00478 
00479   rv = FillHashWithDOMInterfaces();
00480   NS_ENSURE_SUCCESS(rv, rv);
00481 
00482   nsCOMPtr<nsICategoryManager> cm =
00483     do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv);
00484   NS_ENSURE_SUCCESS(rv, rv);
00485 
00486   rv = FillHash(cm, JAVASCRIPT_GLOBAL_CONSTRUCTOR_CATEGORY,
00487                 nsGlobalNameStruct::eTypeExternalConstructor);
00488   NS_ENSURE_SUCCESS(rv, rv);
00489 
00490   rv = FillHash(cm, JAVASCRIPT_GLOBAL_PROPERTY_CATEGORY,
00491                 nsGlobalNameStruct::eTypeProperty);
00492   NS_ENSURE_SUCCESS(rv, rv);
00493 
00494   rv = FillHash(cm, JAVASCRIPT_GLOBAL_STATIC_NAMESET_CATEGORY,
00495                 nsGlobalNameStruct::eTypeStaticNameSet);
00496   NS_ENSURE_SUCCESS(rv, rv);
00497 
00498   rv = FillHash(cm, JAVASCRIPT_GLOBAL_DYNAMIC_NAMESET_CATEGORY,
00499                 nsGlobalNameStruct::eTypeDynamicNameSet);
00500   NS_ENSURE_SUCCESS(rv, rv);
00501 
00502   return NS_OK;
00503 }
00504 
00505 PR_STATIC_CALLBACK(PLDHashOperator)
00506 NameSetInitCallback(PLDHashTable *table, PLDHashEntryHdr *hdr,
00507                     PRUint32 number, void *arg)
00508 {
00509   GlobalNameMapEntry *entry = NS_STATIC_CAST(GlobalNameMapEntry *, hdr);
00510 
00511   if (entry->mGlobalName.mType == nsGlobalNameStruct::eTypeStaticNameSet) {
00512     nsresult rv = NS_OK;
00513     nsCOMPtr<nsIScriptExternalNameSet> ns =
00514       do_CreateInstance(entry->mGlobalName.mCID, &rv);
00515     NS_ENSURE_SUCCESS(rv, PL_DHASH_NEXT);
00516 
00517     rv = ns->InitializeNameSet(NS_STATIC_CAST(nsIScriptContext *, arg));
00518     NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
00519                      "Initing external script classes failed!");
00520   }
00521 
00522   return PL_DHASH_NEXT;
00523 }
00524 
00525 nsresult
00526 nsScriptNameSpaceManager::InitForContext(nsIScriptContext *aContext)
00527 {
00528   PL_DHashTableEnumerate(&mGlobalNames, NameSetInitCallback, aContext);
00529 
00530   return NS_OK;
00531 }
00532 
00533 nsresult
00534 nsScriptNameSpaceManager::LookupName(const nsAString& aName,
00535                                      const nsGlobalNameStruct **aNameStruct,
00536                                      const PRUnichar **aClassName)
00537 {
00538   GlobalNameMapEntry *entry =
00539     NS_STATIC_CAST(GlobalNameMapEntry *,
00540                    PL_DHashTableOperate(&mGlobalNames, &aName,
00541                                         PL_DHASH_LOOKUP));
00542 
00543   if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
00544     *aNameStruct = &entry->mGlobalName;
00545     if (aClassName) {
00546       *aClassName = entry->mKey.get();
00547     }
00548   } else {
00549     *aNameStruct = nsnull;
00550     if (aClassName) {
00551       *aClassName = nsnull;
00552     }
00553   }
00554 
00555   return NS_OK;
00556 }
00557 
00558 nsresult
00559 nsScriptNameSpaceManager::RegisterClassName(const char *aClassName,
00560                                             PRInt32 aDOMClassInfoID)
00561 {
00562   if (!nsCRT::IsAscii(aClassName)) {
00563     NS_ERROR("Trying to register a non-ASCII class name");
00564     return NS_OK;
00565   }
00566   nsGlobalNameStruct *s = AddToHash(aClassName);
00567   NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
00568 
00569   if (s->mType == nsGlobalNameStruct::eTypeClassConstructor) {
00570     return NS_OK;
00571   }
00572 
00573   // If a external constructor is already defined with aClassName we
00574   // won't overwrite it.
00575 
00576   if (s->mType == nsGlobalNameStruct::eTypeExternalConstructor) {
00577     return NS_OK;
00578   }
00579 
00580   NS_ASSERTION(s->mType == nsGlobalNameStruct::eTypeNotInitialized ||
00581                s->mType == nsGlobalNameStruct::eTypeInterface,
00582                "Whaaa, JS environment name clash!");
00583 
00584   s->mType = nsGlobalNameStruct::eTypeClassConstructor;
00585   s->mDOMClassInfoID = aDOMClassInfoID;
00586 
00587   return NS_OK;
00588 }
00589 
00590 nsresult
00591 nsScriptNameSpaceManager::RegisterClassProto(const char *aClassName,
00592                                              const nsIID *aConstructorProtoIID,
00593                                              PRBool *aFoundOld)
00594 {
00595   NS_ENSURE_ARG_POINTER(aConstructorProtoIID);
00596 
00597   *aFoundOld = PR_FALSE;
00598 
00599   nsGlobalNameStruct *s = AddToHash(aClassName);
00600   NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
00601 
00602   if (s->mType != nsGlobalNameStruct::eTypeNotInitialized &&
00603       s->mType != nsGlobalNameStruct::eTypeInterface) {
00604     *aFoundOld = PR_TRUE;
00605 
00606     return NS_OK;
00607   }
00608 
00609   s->mType = nsGlobalNameStruct::eTypeClassProto;
00610   s->mIID = *aConstructorProtoIID;
00611 
00612   return NS_OK;
00613 }
00614 
00615 nsresult
00616 nsScriptNameSpaceManager::RegisterExternalClassName(const char *aClassName,
00617                                                     nsCID& aCID)
00618 {
00619   nsGlobalNameStruct *s = AddToHash(aClassName);
00620   NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
00621 
00622   // If an external constructor is already defined with aClassName we
00623   // won't overwrite it.
00624 
00625   if (s->mType == nsGlobalNameStruct::eTypeExternalConstructor) {
00626     return NS_OK;
00627   }
00628 
00629   NS_ASSERTION(s->mType == nsGlobalNameStruct::eTypeNotInitialized ||
00630                s->mType == nsGlobalNameStruct::eTypeInterface,
00631                "Whaaa, JS environment name clash!");
00632 
00633   s->mType = nsGlobalNameStruct::eTypeExternalClassInfoCreator;
00634   s->mCID = aCID;
00635 
00636   return NS_OK;
00637 }
00638 
00639 nsresult
00640 nsScriptNameSpaceManager::RegisterDOMCIData(const char *aName,
00641                                             nsDOMClassInfoExternalConstructorFnc aConstructorFptr,
00642                                             const nsIID *aProtoChainInterface,
00643                                             const nsIID **aInterfaces,
00644                                             PRUint32 aScriptableFlags,
00645                                             PRBool aHasClassInterface,
00646                                             const nsCID *aConstructorCID)
00647 {
00648   nsGlobalNameStruct *s = AddToHash(aName);
00649   NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
00650 
00651   // If an external constructor is already defined with aClassName we
00652   // won't overwrite it.
00653 
00654   if (s->mType == nsGlobalNameStruct::eTypeClassConstructor ||
00655       s->mType == nsGlobalNameStruct::eTypeExternalClassInfo) {
00656     return NS_OK;
00657   }
00658 
00659   // XXX Should we bail out here?
00660   NS_ASSERTION(s->mType == nsGlobalNameStruct::eTypeNotInitialized ||
00661                s->mType == nsGlobalNameStruct::eTypeExternalClassInfoCreator,
00662                "Someone tries to register classinfo data for a class that isn't new or external!");
00663 
00664   s->mData = new nsExternalDOMClassInfoData;
00665   NS_ENSURE_TRUE(s->mData, NS_ERROR_OUT_OF_MEMORY);
00666 
00667   s->mType = nsGlobalNameStruct::eTypeExternalClassInfo;
00668   s->mData->mName = aName;
00669   if (aConstructorFptr)
00670     s->mData->u.mExternalConstructorFptr = aConstructorFptr;
00671   else
00672     // null constructor will cause us to use nsDOMGenericSH::doCreate
00673     s->mData->u.mExternalConstructorFptr = nsnull;
00674   s->mData->mCachedClassInfo = nsnull;
00675   s->mData->mProtoChainInterface = aProtoChainInterface;
00676   s->mData->mInterfaces = aInterfaces;
00677   s->mData->mScriptableFlags = aScriptableFlags;
00678   s->mData->mHasClassInterface = aHasClassInterface;
00679   s->mData->mConstructorCID = aConstructorCID;
00680 
00681   return NS_OK;
00682 }