Bug 618017: Encountering XML should not override the version. (r=lw)
[mozilla-central.git] / dom / base / nsScriptNameSpaceManager.cpp
blobd1a75ff0267610a972b8ec010505734b7b53c574
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is Mozilla Communicator client code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
24 * Alternatively, the contents of this file may be used under the terms of
25 * either of the GNU General Public License Version 2 or later (the "GPL"),
26 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
38 #include "nsScriptNameSpaceManager.h"
39 #include "nsCOMPtr.h"
40 #include "nsIComponentManager.h"
41 #include "nsIComponentRegistrar.h"
42 #include "nsICategoryManager.h"
43 #include "nsIServiceManager.h"
44 #include "nsXPCOM.h"
45 #include "nsISupportsPrimitives.h"
46 #include "nsIScriptExternalNameSet.h"
47 #include "nsIScriptNameSpaceManager.h"
48 #include "nsIScriptContext.h"
49 #include "nsIInterfaceInfoManager.h"
50 #include "nsIInterfaceInfo.h"
51 #include "xptinfo.h"
52 #include "nsXPIDLString.h"
53 #include "nsReadableUtils.h"
54 #include "nsHashKeys.h"
55 #include "nsDOMClassInfo.h"
56 #include "nsCRT.h"
57 #include "nsIObserverService.h"
59 #define NS_INTERFACE_PREFIX "nsI"
60 #define NS_DOM_INTERFACE_PREFIX "nsIDOM"
62 // Our extended PLDHashEntryHdr
63 class GlobalNameMapEntry : public PLDHashEntryHdr
65 public:
66 // Our hash table ops don't care about the order of these members
67 nsString mKey;
68 nsGlobalNameStruct mGlobalName;
72 static PLDHashNumber
73 GlobalNameHashHashKey(PLDHashTable *table, const void *key)
75 const nsAString *str = static_cast<const nsAString *>(key);
77 return HashString(*str);
80 static PRBool
81 GlobalNameHashMatchEntry(PLDHashTable *table, const PLDHashEntryHdr *entry,
82 const void *key)
84 const GlobalNameMapEntry *e =
85 static_cast<const GlobalNameMapEntry *>(entry);
86 const nsAString *str = static_cast<const nsAString *>(key);
88 return str->Equals(e->mKey);
91 static void
92 GlobalNameHashClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
94 GlobalNameMapEntry *e = static_cast<GlobalNameMapEntry *>(entry);
96 // An entry is being cleared, let the key (nsString) do its own
97 // cleanup.
98 e->mKey.~nsString();
99 if (e->mGlobalName.mType == nsGlobalNameStruct::eTypeExternalClassInfo) {
100 nsIClassInfo* ci = GET_CLEAN_CI_PTR(e->mGlobalName.mData->mCachedClassInfo);
102 // If we constructed an internal helper, we'll let the helper delete
103 // the nsDOMClassInfoData structure, if not we do it here.
104 if (!ci || e->mGlobalName.mData->u.mExternalConstructorFptr) {
105 delete e->mGlobalName.mData;
108 // Release our pointer to the helper.
109 NS_IF_RELEASE(ci);
111 else if (e->mGlobalName.mType == nsGlobalNameStruct::eTypeExternalConstructorAlias) {
112 delete e->mGlobalName.mAlias;
115 // This will set e->mGlobalName.mType to
116 // nsGlobalNameStruct::eTypeNotInitialized
117 memset(&e->mGlobalName, 0, sizeof(nsGlobalNameStruct));
120 static PRBool
121 GlobalNameHashInitEntry(PLDHashTable *table, PLDHashEntryHdr *entry,
122 const void *key)
124 GlobalNameMapEntry *e = static_cast<GlobalNameMapEntry *>(entry);
125 const nsAString *keyStr = static_cast<const nsAString *>(key);
127 // Initialize the key in the entry with placement new
128 new (&e->mKey) nsString(*keyStr);
130 // This will set e->mGlobalName.mType to
131 // nsGlobalNameStruct::eTypeNotInitialized
132 memset(&e->mGlobalName, 0, sizeof(nsGlobalNameStruct));
133 return PR_TRUE;
136 NS_IMPL_ISUPPORTS2(nsScriptNameSpaceManager,
137 nsIObserver,
138 nsISupportsWeakReference)
140 nsScriptNameSpaceManager::nsScriptNameSpaceManager()
141 : mIsInitialized(PR_FALSE)
143 MOZ_COUNT_CTOR(nsScriptNameSpaceManager);
146 nsScriptNameSpaceManager::~nsScriptNameSpaceManager()
148 if (mIsInitialized) {
149 // Destroy the hash
150 PL_DHashTableFinish(&mGlobalNames);
152 MOZ_COUNT_DTOR(nsScriptNameSpaceManager);
155 nsGlobalNameStruct *
156 nsScriptNameSpaceManager::AddToHash(const char *aKey,
157 const PRUnichar **aClassName)
159 NS_ConvertASCIItoUTF16 key(aKey);
160 GlobalNameMapEntry *entry =
161 static_cast<GlobalNameMapEntry *>
162 (PL_DHashTableOperate(&mGlobalNames, &key, PL_DHASH_ADD));
164 if (!entry) {
165 return nsnull;
168 if (aClassName) {
169 *aClassName = entry->mKey.get();
172 return &entry->mGlobalName;
175 nsGlobalNameStruct*
176 nsScriptNameSpaceManager::GetConstructorProto(const nsGlobalNameStruct* aStruct)
178 NS_ASSERTION(aStruct->mType == nsGlobalNameStruct::eTypeExternalConstructorAlias,
179 "This function only works on constructor aliases!");
180 if (!aStruct->mAlias->mProto) {
181 GlobalNameMapEntry *proto =
182 static_cast<GlobalNameMapEntry *>
183 (PL_DHashTableOperate(&mGlobalNames,
184 &aStruct->mAlias->mProtoName,
185 PL_DHASH_LOOKUP));
187 if (PL_DHASH_ENTRY_IS_BUSY(proto)) {
188 aStruct->mAlias->mProto = &proto->mGlobalName;
191 return aStruct->mAlias->mProto;
194 nsresult
195 nsScriptNameSpaceManager::FillHash(nsICategoryManager *aCategoryManager,
196 const char *aCategory)
198 nsCOMPtr<nsISimpleEnumerator> e;
199 nsresult rv = aCategoryManager->EnumerateCategory(aCategory,
200 getter_AddRefs(e));
201 NS_ENSURE_SUCCESS(rv, rv);
203 nsCOMPtr<nsISupports> entry;
204 while (NS_SUCCEEDED(e->GetNext(getter_AddRefs(entry)))) {
205 rv = AddCategoryEntryToHash(aCategoryManager, aCategory, entry);
206 if (NS_FAILED(rv)) {
207 return rv;
211 return NS_OK;
215 // This method enumerates over all installed interfaces (in .xpt
216 // files) and finds ones that start with "nsIDOM" and has constants
217 // defined in the interface itself (inherited constants doesn't
218 // count), once such an interface is found the "nsIDOM" prefix is cut
219 // off the name and the rest of the name is added into the hash for
220 // global names. This makes things like 'Node.ELEMENT_NODE' work in
221 // JS. See nsCommonWindowSH::GlobalResolve() for detais on how this is used.
223 nsresult
224 nsScriptNameSpaceManager::FillHashWithDOMInterfaces()
226 nsCOMPtr<nsIInterfaceInfoManager>
227 iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID));
228 NS_ENSURE_TRUE(iim, NS_ERROR_UNEXPECTED);
230 // First look for all interfaces whose name starts with nsIDOM
231 nsCOMPtr<nsIEnumerator> domInterfaces;
232 nsresult rv =
233 iim->EnumerateInterfacesWhoseNamesStartWith(NS_DOM_INTERFACE_PREFIX,
234 getter_AddRefs(domInterfaces));
235 NS_ENSURE_SUCCESS(rv, rv);
237 nsCOMPtr<nsISupports> entry;
239 rv = domInterfaces->First();
241 if (NS_FAILED(rv)) {
242 // Empty interface list?
244 NS_WARNING("What, no nsIDOM interfaces installed?");
246 return NS_OK;
249 PRBool found_old;
250 nsCOMPtr<nsIInterfaceInfo> if_info;
251 const char *if_name = nsnull;
252 const nsIID *iid;
254 for ( ; domInterfaces->IsDone() == NS_ENUMERATOR_FALSE; domInterfaces->Next()) {
255 rv = domInterfaces->CurrentItem(getter_AddRefs(entry));
256 NS_ENSURE_SUCCESS(rv, rv);
258 nsCOMPtr<nsIInterfaceInfo> if_info(do_QueryInterface(entry));
259 if_info->GetNameShared(&if_name);
260 if_info->GetIIDShared(&iid);
261 rv = RegisterInterface(if_name + sizeof(NS_DOM_INTERFACE_PREFIX) - 1,
262 iid, &found_old);
264 #ifdef DEBUG
265 NS_ASSERTION(!found_old,
266 "Whaaa, interface name already in hash!");
267 #endif
270 // Next, look for externally registered DOM interfaces
271 rv = RegisterExternalInterfaces(PR_FALSE);
273 return rv;
276 nsresult
277 nsScriptNameSpaceManager::RegisterExternalInterfaces(PRBool aAsProto)
279 nsresult rv;
280 nsCOMPtr<nsICategoryManager> cm =
281 do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv);
282 NS_ENSURE_SUCCESS(rv, rv);
284 nsCOMPtr<nsIInterfaceInfoManager>
285 iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID));
286 NS_ENSURE_TRUE(iim, NS_ERROR_NOT_AVAILABLE);
288 nsCOMPtr<nsISimpleEnumerator> enumerator;
289 rv = cm->EnumerateCategory(JAVASCRIPT_DOM_INTERFACE,
290 getter_AddRefs(enumerator));
291 NS_ENSURE_SUCCESS(rv, rv);
293 nsXPIDLCString IID_string;
294 nsCAutoString category_entry;
295 const char* if_name;
296 nsCOMPtr<nsISupports> entry;
297 nsCOMPtr<nsIInterfaceInfo> if_info;
298 PRBool found_old, dom_prefix;
300 while (NS_SUCCEEDED(enumerator->GetNext(getter_AddRefs(entry)))) {
301 nsCOMPtr<nsISupportsCString> category(do_QueryInterface(entry));
303 if (!category) {
304 NS_WARNING("Category entry not an nsISupportsCString!");
306 continue;
309 rv = category->GetData(category_entry);
310 NS_ENSURE_SUCCESS(rv, rv);
312 rv = cm->GetCategoryEntry(JAVASCRIPT_DOM_INTERFACE, category_entry.get(),
313 getter_Copies(IID_string));
314 NS_ENSURE_SUCCESS(rv, rv);
316 nsIID primary_IID;
317 if (!primary_IID.Parse(IID_string) ||
318 primary_IID.Equals(NS_GET_IID(nsISupports))) {
319 NS_ERROR("Invalid IID registered with the script namespace manager!");
320 continue;
323 iim->GetInfoForIID(&primary_IID, getter_AddRefs(if_info));
325 while (if_info) {
326 const nsIID *iid;
327 if_info->GetIIDShared(&iid);
328 NS_ENSURE_TRUE(iid, NS_ERROR_UNEXPECTED);
330 if (iid->Equals(NS_GET_IID(nsISupports))) {
331 break;
334 if_info->GetNameShared(&if_name);
335 dom_prefix = (strncmp(if_name, NS_DOM_INTERFACE_PREFIX,
336 sizeof(NS_DOM_INTERFACE_PREFIX) - 1) == 0);
338 const char* name;
339 if (dom_prefix) {
340 if (!aAsProto) {
341 // nsIDOM* interfaces have already been registered.
342 break;
344 name = if_name + sizeof(NS_DOM_INTERFACE_PREFIX) - 1;
345 } else {
346 name = if_name + sizeof(NS_INTERFACE_PREFIX) - 1;
349 if (aAsProto) {
350 RegisterClassProto(name, iid, &found_old);
351 } else {
352 RegisterInterface(name, iid, &found_old);
355 if (found_old) {
356 break;
359 nsCOMPtr<nsIInterfaceInfo> tmp(if_info);
360 tmp->GetParent(getter_AddRefs(if_info));
364 return NS_OK;
367 nsresult
368 nsScriptNameSpaceManager::RegisterInterface(const char* aIfName,
369 const nsIID *aIfIID,
370 PRBool* aFoundOld)
372 *aFoundOld = PR_FALSE;
374 nsGlobalNameStruct *s = AddToHash(aIfName);
375 NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
377 if (s->mType != nsGlobalNameStruct::eTypeNotInitialized) {
378 *aFoundOld = PR_TRUE;
380 return NS_OK;
383 s->mType = nsGlobalNameStruct::eTypeInterface;
384 s->mIID = *aIfIID;
386 return NS_OK;
389 #define GLOBALNAME_HASHTABLE_INITIAL_SIZE 1024
391 nsresult
392 nsScriptNameSpaceManager::Init()
394 static PLDHashTableOps hash_table_ops =
396 PL_DHashAllocTable,
397 PL_DHashFreeTable,
398 GlobalNameHashHashKey,
399 GlobalNameHashMatchEntry,
400 PL_DHashMoveEntryStub,
401 GlobalNameHashClearEntry,
402 PL_DHashFinalizeStub,
403 GlobalNameHashInitEntry
406 mIsInitialized = PL_DHashTableInit(&mGlobalNames, &hash_table_ops, nsnull,
407 sizeof(GlobalNameMapEntry),
408 GLOBALNAME_HASHTABLE_INITIAL_SIZE);
409 NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_OUT_OF_MEMORY);
411 nsresult rv = NS_OK;
413 rv = FillHashWithDOMInterfaces();
414 NS_ENSURE_SUCCESS(rv, rv);
416 nsCOMPtr<nsICategoryManager> cm =
417 do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv);
418 NS_ENSURE_SUCCESS(rv, rv);
420 rv = FillHash(cm, JAVASCRIPT_GLOBAL_CONSTRUCTOR_CATEGORY);
421 NS_ENSURE_SUCCESS(rv, rv);
423 rv = FillHash(cm, JAVASCRIPT_GLOBAL_PROPERTY_CATEGORY);
424 NS_ENSURE_SUCCESS(rv, rv);
426 rv = FillHash(cm, JAVASCRIPT_GLOBAL_PRIVILEGED_PROPERTY_CATEGORY);
427 NS_ENSURE_SUCCESS(rv, rv);
429 rv = FillHash(cm, JAVASCRIPT_GLOBAL_STATIC_NAMESET_CATEGORY);
430 NS_ENSURE_SUCCESS(rv, rv);
432 rv = FillHash(cm, JAVASCRIPT_GLOBAL_DYNAMIC_NAMESET_CATEGORY);
433 NS_ENSURE_SUCCESS(rv, rv);
435 // Initial filling of the has table has been done.
436 // Now, listen for changes.
437 nsCOMPtr<nsIObserverService> serv =
438 do_GetService(NS_OBSERVERSERVICE_CONTRACTID);
440 if (serv) {
441 serv->AddObserver(this, NS_XPCOM_CATEGORY_ENTRY_ADDED_OBSERVER_ID, PR_TRUE);
444 return NS_OK;
447 struct NameSetClosure {
448 nsIScriptContext* ctx;
449 nsresult rv;
452 static PLDHashOperator
453 NameSetInitCallback(PLDHashTable *table, PLDHashEntryHdr *hdr,
454 PRUint32 number, void *arg)
456 GlobalNameMapEntry *entry = static_cast<GlobalNameMapEntry *>(hdr);
458 if (entry->mGlobalName.mType == nsGlobalNameStruct::eTypeStaticNameSet) {
459 nsresult rv = NS_OK;
460 nsCOMPtr<nsIScriptExternalNameSet> ns =
461 do_CreateInstance(entry->mGlobalName.mCID, &rv);
462 NS_ENSURE_SUCCESS(rv, PL_DHASH_NEXT);
464 NameSetClosure *closure = static_cast<NameSetClosure *>(arg);
465 closure->rv = ns->InitializeNameSet(closure->ctx);
466 if (NS_FAILED(closure->rv)) {
467 NS_ERROR("Initing external script classes failed!");
468 return PL_DHASH_STOP;
472 return PL_DHASH_NEXT;
475 nsresult
476 nsScriptNameSpaceManager::InitForContext(nsIScriptContext *aContext)
478 NameSetClosure closure;
479 closure.ctx = aContext;
480 closure.rv = NS_OK;
481 PL_DHashTableEnumerate(&mGlobalNames, NameSetInitCallback, &closure);
483 return closure.rv;
486 nsresult
487 nsScriptNameSpaceManager::LookupName(const nsAString& aName,
488 const nsGlobalNameStruct **aNameStruct,
489 const PRUnichar **aClassName)
491 GlobalNameMapEntry *entry =
492 static_cast<GlobalNameMapEntry *>
493 (PL_DHashTableOperate(&mGlobalNames, &aName,
494 PL_DHASH_LOOKUP));
496 if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
497 *aNameStruct = &entry->mGlobalName;
498 if (aClassName) {
499 *aClassName = entry->mKey.get();
501 } else {
502 *aNameStruct = nsnull;
503 if (aClassName) {
504 *aClassName = nsnull;
508 return NS_OK;
511 nsresult
512 nsScriptNameSpaceManager::RegisterClassName(const char *aClassName,
513 PRInt32 aDOMClassInfoID,
514 PRBool aPrivileged,
515 const PRUnichar **aResult)
517 if (!nsCRT::IsAscii(aClassName)) {
518 NS_ERROR("Trying to register a non-ASCII class name");
519 return NS_OK;
521 nsGlobalNameStruct *s = AddToHash(aClassName, aResult);
522 NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
524 if (s->mType == nsGlobalNameStruct::eTypeClassConstructor) {
525 return NS_OK;
528 // If a external constructor is already defined with aClassName we
529 // won't overwrite it.
531 if (s->mType == nsGlobalNameStruct::eTypeExternalConstructor) {
532 return NS_OK;
535 NS_ASSERTION(s->mType == nsGlobalNameStruct::eTypeNotInitialized ||
536 s->mType == nsGlobalNameStruct::eTypeInterface,
537 "Whaaa, JS environment name clash!");
539 s->mType = nsGlobalNameStruct::eTypeClassConstructor;
540 s->mDOMClassInfoID = aDOMClassInfoID;
541 s->mChromeOnly = aPrivileged;
543 return NS_OK;
546 nsresult
547 nsScriptNameSpaceManager::RegisterClassProto(const char *aClassName,
548 const nsIID *aConstructorProtoIID,
549 PRBool *aFoundOld)
551 NS_ENSURE_ARG_POINTER(aConstructorProtoIID);
553 *aFoundOld = PR_FALSE;
555 nsGlobalNameStruct *s = AddToHash(aClassName);
556 NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
558 if (s->mType != nsGlobalNameStruct::eTypeNotInitialized &&
559 s->mType != nsGlobalNameStruct::eTypeInterface) {
560 *aFoundOld = PR_TRUE;
562 return NS_OK;
565 s->mType = nsGlobalNameStruct::eTypeClassProto;
566 s->mIID = *aConstructorProtoIID;
568 return NS_OK;
571 nsresult
572 nsScriptNameSpaceManager::RegisterExternalClassName(const char *aClassName,
573 nsCID& aCID)
575 nsGlobalNameStruct *s = AddToHash(aClassName);
576 NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
578 // If an external constructor is already defined with aClassName we
579 // won't overwrite it.
581 if (s->mType == nsGlobalNameStruct::eTypeExternalConstructor) {
582 return NS_OK;
585 NS_ASSERTION(s->mType == nsGlobalNameStruct::eTypeNotInitialized ||
586 s->mType == nsGlobalNameStruct::eTypeInterface,
587 "Whaaa, JS environment name clash!");
589 s->mType = nsGlobalNameStruct::eTypeExternalClassInfoCreator;
590 s->mCID = aCID;
592 return NS_OK;
595 nsresult
596 nsScriptNameSpaceManager::RegisterDOMCIData(const char *aName,
597 nsDOMClassInfoExternalConstructorFnc aConstructorFptr,
598 const nsIID *aProtoChainInterface,
599 const nsIID **aInterfaces,
600 PRUint32 aScriptableFlags,
601 PRBool aHasClassInterface,
602 const nsCID *aConstructorCID)
604 const PRUnichar* className;
605 nsGlobalNameStruct *s = AddToHash(aName, &className);
606 NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
608 // If an external constructor is already defined with aClassName we
609 // won't overwrite it.
611 if (s->mType == nsGlobalNameStruct::eTypeClassConstructor ||
612 s->mType == nsGlobalNameStruct::eTypeExternalClassInfo) {
613 return NS_OK;
616 // XXX Should we bail out here?
617 NS_ASSERTION(s->mType == nsGlobalNameStruct::eTypeNotInitialized ||
618 s->mType == nsGlobalNameStruct::eTypeExternalClassInfoCreator,
619 "Someone tries to register classinfo data for a class that isn't new or external!");
621 s->mData = new nsExternalDOMClassInfoData;
622 NS_ENSURE_TRUE(s->mData, NS_ERROR_OUT_OF_MEMORY);
624 s->mType = nsGlobalNameStruct::eTypeExternalClassInfo;
625 s->mData->mName = aName;
626 s->mData->mNameUTF16 = className;
627 if (aConstructorFptr)
628 s->mData->u.mExternalConstructorFptr = aConstructorFptr;
629 else
630 // null constructor will cause us to use nsDOMGenericSH::doCreate
631 s->mData->u.mExternalConstructorFptr = nsnull;
632 s->mData->mCachedClassInfo = nsnull;
633 s->mData->mProtoChainInterface = aProtoChainInterface;
634 s->mData->mInterfaces = aInterfaces;
635 s->mData->mScriptableFlags = aScriptableFlags;
636 s->mData->mHasClassInterface = aHasClassInterface;
637 s->mData->mConstructorCID = aConstructorCID;
639 return NS_OK;
642 nsresult
643 nsScriptNameSpaceManager::AddCategoryEntryToHash(nsICategoryManager* aCategoryManager,
644 const char* aCategory,
645 nsISupports* aEntry)
647 // Get the type from the category name.
648 // NOTE: we could have passed the type in FillHash() and guessed it in
649 // Observe() but this way, we have only one place to update and this is
650 // not performance sensitive.
651 nsGlobalNameStruct::nametype type;
652 if (strcmp(aCategory, JAVASCRIPT_GLOBAL_CONSTRUCTOR_CATEGORY) == 0) {
653 type = nsGlobalNameStruct::eTypeExternalConstructor;
654 } else if (strcmp(aCategory, JAVASCRIPT_GLOBAL_PROPERTY_CATEGORY) == 0 ||
655 strcmp(aCategory, JAVASCRIPT_GLOBAL_PRIVILEGED_PROPERTY_CATEGORY) == 0) {
656 type = nsGlobalNameStruct::eTypeProperty;
657 } else if (strcmp(aCategory, JAVASCRIPT_GLOBAL_STATIC_NAMESET_CATEGORY) == 0) {
658 type = nsGlobalNameStruct::eTypeStaticNameSet;
659 } else if (strcmp(aCategory, JAVASCRIPT_GLOBAL_DYNAMIC_NAMESET_CATEGORY) == 0) {
660 type = nsGlobalNameStruct::eTypeDynamicNameSet;
661 } else {
662 return NS_OK;
665 nsCOMPtr<nsISupportsCString> strWrapper = do_QueryInterface(aEntry);
667 if (!strWrapper) {
668 NS_WARNING("Category entry not an nsISupportsCString!");
669 return NS_OK;
672 nsCAutoString categoryEntry;
673 nsresult rv = strWrapper->GetData(categoryEntry);
674 NS_ENSURE_SUCCESS(rv, rv);
676 nsXPIDLCString contractId;
677 rv = aCategoryManager->GetCategoryEntry(aCategory, categoryEntry.get(),
678 getter_Copies(contractId));
679 NS_ENSURE_SUCCESS(rv, rv);
681 nsCOMPtr<nsIComponentRegistrar> registrar;
682 rv = NS_GetComponentRegistrar(getter_AddRefs(registrar));
683 NS_ENSURE_SUCCESS(rv, rv);
685 nsCID *cidPtr;
686 rv = registrar->ContractIDToCID(contractId, &cidPtr);
688 if (NS_FAILED(rv)) {
689 NS_WARNING("Bad contract id registed with the script namespace manager");
690 return NS_OK;
693 // Copy CID onto the stack, so we can free it right away and avoid having
694 // to add cleanup code at every exit point from this function.
695 nsCID cid = *cidPtr;
696 nsMemory::Free(cidPtr);
698 if (type == nsGlobalNameStruct::eTypeExternalConstructor) {
699 nsXPIDLCString constructorProto;
700 rv = aCategoryManager->GetCategoryEntry(JAVASCRIPT_GLOBAL_CONSTRUCTOR_PROTO_ALIAS_CATEGORY,
701 categoryEntry.get(),
702 getter_Copies(constructorProto));
703 if (NS_SUCCEEDED(rv)) {
704 nsGlobalNameStruct *s = AddToHash(categoryEntry.get());
705 NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
707 if (s->mType == nsGlobalNameStruct::eTypeNotInitialized) {
708 s->mAlias = new nsGlobalNameStruct::ConstructorAlias;
709 s->mType = nsGlobalNameStruct::eTypeExternalConstructorAlias;
710 s->mChromeOnly = PR_FALSE;
711 s->mAlias->mCID = cid;
712 AppendASCIItoUTF16(constructorProto, s->mAlias->mProtoName);
713 s->mAlias->mProto = nsnull;
714 } else {
715 NS_WARNING("Global script name not overwritten!");
718 return NS_OK;
722 nsGlobalNameStruct *s = AddToHash(categoryEntry.get());
723 NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
725 if (s->mType == nsGlobalNameStruct::eTypeNotInitialized) {
726 s->mType = type;
727 s->mCID = cid;
728 s->mChromeOnly =
729 strcmp(aCategory, JAVASCRIPT_GLOBAL_PRIVILEGED_PROPERTY_CATEGORY) == 0;
730 } else {
731 NS_WARNING("Global script name not overwritten!");
734 return NS_OK;
737 NS_IMETHODIMP
738 nsScriptNameSpaceManager::Observe(nsISupports* aSubject, const char* aTopic,
739 const PRUnichar* aData)
741 if (!aData) {
742 return NS_OK;
745 if (strcmp(aTopic, NS_XPCOM_CATEGORY_ENTRY_ADDED_OBSERVER_ID) == 0) {
746 nsCOMPtr<nsICategoryManager> cm =
747 do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
748 if (!cm) {
749 return NS_OK;
752 return AddCategoryEntryToHash(cm, NS_ConvertUTF16toUTF8(aData).get(),
753 aSubject);
756 // TODO: we could observe NS_XPCOM_CATEGORY_ENTRY_REMOVED_OBSERVER_ID
757 // and NS_XPCOM_CATEGORY_CLEARED_OBSERVER_ID but we are safe without it.
758 // See bug 600460.
760 return NS_OK;