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
4 : *
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/
9 : *
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.
14 : *
15 : * The Original Code is Mozilla Communicator client code.
16 : *
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.
21 : *
22 : * Contributor(s):
23 : *
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.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
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"
58 : #include "mozilla/Services.h"
59 :
60 : #define NS_INTERFACE_PREFIX "nsI"
61 : #define NS_DOM_INTERFACE_PREFIX "nsIDOM"
62 :
63 : using namespace mozilla;
64 :
65 : // Our extended PLDHashEntryHdr
66 : class GlobalNameMapEntry : public PLDHashEntryHdr
67 : {
68 : public:
69 : // Our hash table ops don't care about the order of these members
70 : nsString mKey;
71 : nsGlobalNameStruct mGlobalName;
72 : };
73 :
74 :
75 : static PLDHashNumber
76 429318 : GlobalNameHashHashKey(PLDHashTable *table, const void *key)
77 : {
78 429318 : const nsAString *str = static_cast<const nsAString *>(key);
79 429318 : return HashString(*str);
80 : }
81 :
82 : static bool
83 277542 : GlobalNameHashMatchEntry(PLDHashTable *table, const PLDHashEntryHdr *entry,
84 : const void *key)
85 : {
86 : const GlobalNameMapEntry *e =
87 277542 : static_cast<const GlobalNameMapEntry *>(entry);
88 277542 : const nsAString *str = static_cast<const nsAString *>(key);
89 :
90 277542 : return str->Equals(e->mKey);
91 : }
92 :
93 : static void
94 151280 : GlobalNameHashClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
95 : {
96 151280 : GlobalNameMapEntry *e = static_cast<GlobalNameMapEntry *>(entry);
97 :
98 : // An entry is being cleared, let the key (nsString) do its own
99 : // cleanup.
100 151280 : e->mKey.~nsString();
101 151280 : if (e->mGlobalName.mType == nsGlobalNameStruct::eTypeExternalClassInfo) {
102 0 : nsIClassInfo* ci = GET_CLEAN_CI_PTR(e->mGlobalName.mData->mCachedClassInfo);
103 :
104 : // If we constructed an internal helper, we'll let the helper delete
105 : // the nsDOMClassInfoData structure, if not we do it here.
106 0 : if (!ci || e->mGlobalName.mData->u.mExternalConstructorFptr) {
107 0 : delete e->mGlobalName.mData;
108 : }
109 :
110 : // Release our pointer to the helper.
111 0 : NS_IF_RELEASE(ci);
112 : }
113 151280 : else if (e->mGlobalName.mType == nsGlobalNameStruct::eTypeExternalConstructorAlias) {
114 915 : delete e->mGlobalName.mAlias;
115 : }
116 :
117 : // This will set e->mGlobalName.mType to
118 : // nsGlobalNameStruct::eTypeNotInitialized
119 151280 : memset(&e->mGlobalName, 0, sizeof(nsGlobalNameStruct));
120 151280 : }
121 :
122 : static bool
123 151776 : GlobalNameHashInitEntry(PLDHashTable *table, PLDHashEntryHdr *entry,
124 : const void *key)
125 : {
126 151776 : GlobalNameMapEntry *e = static_cast<GlobalNameMapEntry *>(entry);
127 151776 : const nsAString *keyStr = static_cast<const nsAString *>(key);
128 :
129 : // Initialize the key in the entry with placement new
130 151776 : new (&e->mKey) nsString(*keyStr);
131 :
132 : // This will set e->mGlobalName.mType to
133 : // nsGlobalNameStruct::eTypeNotInitialized
134 151776 : memset(&e->mGlobalName, 0, sizeof(nsGlobalNameStruct));
135 151776 : return true;
136 : }
137 :
138 2833 : NS_IMPL_ISUPPORTS2(nsScriptNameSpaceManager,
139 : nsIObserver,
140 : nsISupportsWeakReference)
141 :
142 306 : nsScriptNameSpaceManager::nsScriptNameSpaceManager()
143 306 : : mIsInitialized(false)
144 : {
145 306 : MOZ_COUNT_CTOR(nsScriptNameSpaceManager);
146 306 : }
147 :
148 915 : nsScriptNameSpaceManager::~nsScriptNameSpaceManager()
149 : {
150 305 : if (mIsInitialized) {
151 : // Destroy the hash
152 305 : PL_DHashTableFinish(&mGlobalNames);
153 305 : PL_DHashTableFinish(&mNavigatorNames);
154 : }
155 305 : MOZ_COUNT_DTOR(nsScriptNameSpaceManager);
156 1220 : }
157 :
158 : nsGlobalNameStruct *
159 429318 : nsScriptNameSpaceManager::AddToHash(PLDHashTable *aTable, const char *aKey,
160 : const PRUnichar **aClassName)
161 : {
162 858636 : NS_ConvertASCIItoUTF16 key(aKey);
163 : GlobalNameMapEntry *entry =
164 : static_cast<GlobalNameMapEntry *>
165 429318 : (PL_DHashTableOperate(aTable, &key, PL_DHASH_ADD));
166 :
167 429318 : if (!entry) {
168 0 : return nsnull;
169 : }
170 :
171 429318 : if (aClassName) {
172 115362 : *aClassName = entry->mKey.get();
173 : }
174 :
175 429318 : return &entry->mGlobalName;
176 : }
177 :
178 : nsGlobalNameStruct*
179 0 : nsScriptNameSpaceManager::GetConstructorProto(const nsGlobalNameStruct* aStruct)
180 : {
181 0 : NS_ASSERTION(aStruct->mType == nsGlobalNameStruct::eTypeExternalConstructorAlias,
182 : "This function only works on constructor aliases!");
183 0 : if (!aStruct->mAlias->mProto) {
184 : GlobalNameMapEntry *proto =
185 : static_cast<GlobalNameMapEntry *>
186 : (PL_DHashTableOperate(&mGlobalNames,
187 : &aStruct->mAlias->mProtoName,
188 0 : PL_DHASH_LOOKUP));
189 :
190 0 : if (PL_DHASH_ENTRY_IS_BUSY(proto)) {
191 0 : aStruct->mAlias->mProto = &proto->mGlobalName;
192 : }
193 : }
194 0 : return aStruct->mAlias->mProto;
195 : }
196 :
197 : nsresult
198 1836 : nsScriptNameSpaceManager::FillHash(nsICategoryManager *aCategoryManager,
199 : const char *aCategory)
200 : {
201 3672 : nsCOMPtr<nsISimpleEnumerator> e;
202 : nsresult rv = aCategoryManager->EnumerateCategory(aCategory,
203 1836 : getter_AddRefs(e));
204 1836 : NS_ENSURE_SUCCESS(rv, rv);
205 :
206 3672 : nsCOMPtr<nsISupports> entry;
207 1836 : while (NS_SUCCEEDED(e->GetNext(getter_AddRefs(entry)))) {
208 3672 : rv = AddCategoryEntryToHash(aCategoryManager, aCategory, entry);
209 3672 : if (NS_FAILED(rv)) {
210 0 : return rv;
211 : }
212 : }
213 :
214 1836 : return NS_OK;
215 : }
216 :
217 :
218 : // This method enumerates over all installed interfaces (in .xpt
219 : // files) and finds ones that start with "nsIDOM" and has constants
220 : // defined in the interface itself (inherited constants doesn't
221 : // count), once such an interface is found the "nsIDOM" prefix is cut
222 : // off the name and the rest of the name is added into the hash for
223 : // global names. This makes things like 'Node.ELEMENT_NODE' work in
224 : // JS. See nsCommonWindowSH::GlobalResolve() for detais on how this is used.
225 :
226 : nsresult
227 306 : nsScriptNameSpaceManager::FillHashWithDOMInterfaces()
228 : {
229 : nsCOMPtr<nsIInterfaceInfoManager>
230 612 : iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID));
231 306 : NS_ENSURE_TRUE(iim, NS_ERROR_UNEXPECTED);
232 :
233 : // First look for all interfaces whose name starts with nsIDOM
234 612 : nsCOMPtr<nsIEnumerator> domInterfaces;
235 : nsresult rv =
236 306 : iim->EnumerateInterfacesWhoseNamesStartWith(NS_DOM_INTERFACE_PREFIX,
237 306 : getter_AddRefs(domInterfaces));
238 306 : NS_ENSURE_SUCCESS(rv, rv);
239 :
240 612 : nsCOMPtr<nsISupports> entry;
241 :
242 306 : rv = domInterfaces->First();
243 :
244 306 : if (NS_FAILED(rv)) {
245 : // Empty interface list?
246 :
247 0 : NS_WARNING("What, no nsIDOM interfaces installed?");
248 :
249 0 : return NS_OK;
250 : }
251 :
252 : bool found_old;
253 612 : nsCOMPtr<nsIInterfaceInfo> if_info;
254 306 : const char *if_name = nsnull;
255 : const nsIID *iid;
256 :
257 130356 : for ( ; domInterfaces->IsDone() == NS_ENUMERATOR_FALSE; domInterfaces->Next()) {
258 130050 : rv = domInterfaces->CurrentItem(getter_AddRefs(entry));
259 130050 : NS_ENSURE_SUCCESS(rv, rv);
260 :
261 260100 : nsCOMPtr<nsIInterfaceInfo> if_info(do_QueryInterface(entry));
262 130050 : if_info->GetNameShared(&if_name);
263 130050 : if_info->GetIIDShared(&iid);
264 : rv = RegisterInterface(if_name + sizeof(NS_DOM_INTERFACE_PREFIX) - 1,
265 130050 : iid, &found_old);
266 :
267 : #ifdef DEBUG
268 130050 : NS_ASSERTION(!found_old,
269 : "Whaaa, interface name already in hash!");
270 : #endif
271 : }
272 :
273 : // Next, look for externally registered DOM interfaces
274 306 : rv = RegisterExternalInterfaces(false);
275 :
276 306 : return rv;
277 : }
278 :
279 : nsresult
280 612 : nsScriptNameSpaceManager::RegisterExternalInterfaces(bool aAsProto)
281 : {
282 : nsresult rv;
283 : nsCOMPtr<nsICategoryManager> cm =
284 1224 : do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv);
285 612 : NS_ENSURE_SUCCESS(rv, rv);
286 :
287 : nsCOMPtr<nsIInterfaceInfoManager>
288 1224 : iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID));
289 612 : NS_ENSURE_TRUE(iim, NS_ERROR_NOT_AVAILABLE);
290 :
291 1224 : nsCOMPtr<nsISimpleEnumerator> enumerator;
292 612 : rv = cm->EnumerateCategory(JAVASCRIPT_DOM_INTERFACE,
293 612 : getter_AddRefs(enumerator));
294 612 : NS_ENSURE_SUCCESS(rv, rv);
295 :
296 1224 : nsXPIDLCString IID_string;
297 1224 : nsCAutoString category_entry;
298 : const char* if_name;
299 1224 : nsCOMPtr<nsISupports> entry;
300 1224 : nsCOMPtr<nsIInterfaceInfo> if_info;
301 : bool found_old, dom_prefix;
302 :
303 1224 : while (NS_SUCCEEDED(enumerator->GetNext(getter_AddRefs(entry)))) {
304 0 : nsCOMPtr<nsISupportsCString> category(do_QueryInterface(entry));
305 :
306 0 : if (!category) {
307 0 : NS_WARNING("Category entry not an nsISupportsCString!");
308 :
309 0 : continue;
310 : }
311 :
312 0 : rv = category->GetData(category_entry);
313 0 : NS_ENSURE_SUCCESS(rv, rv);
314 :
315 0 : rv = cm->GetCategoryEntry(JAVASCRIPT_DOM_INTERFACE, category_entry.get(),
316 0 : getter_Copies(IID_string));
317 0 : NS_ENSURE_SUCCESS(rv, rv);
318 :
319 : nsIID primary_IID;
320 0 : if (!primary_IID.Parse(IID_string) ||
321 0 : primary_IID.Equals(NS_GET_IID(nsISupports))) {
322 0 : NS_ERROR("Invalid IID registered with the script namespace manager!");
323 0 : continue;
324 : }
325 :
326 0 : iim->GetInfoForIID(&primary_IID, getter_AddRefs(if_info));
327 :
328 0 : while (if_info) {
329 : const nsIID *iid;
330 0 : if_info->GetIIDShared(&iid);
331 0 : NS_ENSURE_TRUE(iid, NS_ERROR_UNEXPECTED);
332 :
333 0 : if (iid->Equals(NS_GET_IID(nsISupports))) {
334 0 : break;
335 : }
336 :
337 0 : if_info->GetNameShared(&if_name);
338 : dom_prefix = (strncmp(if_name, NS_DOM_INTERFACE_PREFIX,
339 0 : sizeof(NS_DOM_INTERFACE_PREFIX) - 1) == 0);
340 :
341 : const char* name;
342 0 : if (dom_prefix) {
343 0 : if (!aAsProto) {
344 : // nsIDOM* interfaces have already been registered.
345 0 : break;
346 : }
347 0 : name = if_name + sizeof(NS_DOM_INTERFACE_PREFIX) - 1;
348 : } else {
349 0 : name = if_name + sizeof(NS_INTERFACE_PREFIX) - 1;
350 : }
351 :
352 0 : if (aAsProto) {
353 0 : RegisterClassProto(name, iid, &found_old);
354 : } else {
355 0 : RegisterInterface(name, iid, &found_old);
356 : }
357 :
358 0 : if (found_old) {
359 0 : break;
360 : }
361 :
362 0 : nsCOMPtr<nsIInterfaceInfo> tmp(if_info);
363 0 : tmp->GetParent(getter_AddRefs(if_info));
364 : }
365 : }
366 :
367 612 : return NS_OK;
368 : }
369 :
370 : nsresult
371 130050 : nsScriptNameSpaceManager::RegisterInterface(const char* aIfName,
372 : const nsIID *aIfIID,
373 : bool* aFoundOld)
374 : {
375 130050 : *aFoundOld = false;
376 :
377 130050 : nsGlobalNameStruct *s = AddToHash(&mGlobalNames, aIfName);
378 130050 : NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
379 :
380 130050 : if (s->mType != nsGlobalNameStruct::eTypeNotInitialized) {
381 0 : *aFoundOld = true;
382 :
383 0 : return NS_OK;
384 : }
385 :
386 130050 : s->mType = nsGlobalNameStruct::eTypeInterface;
387 130050 : s->mIID = *aIfIID;
388 :
389 130050 : return NS_OK;
390 : }
391 :
392 : #define GLOBALNAME_HASHTABLE_INITIAL_SIZE 1024
393 :
394 : nsresult
395 306 : nsScriptNameSpaceManager::Init()
396 : {
397 : static PLDHashTableOps hash_table_ops =
398 : {
399 : PL_DHashAllocTable,
400 : PL_DHashFreeTable,
401 : GlobalNameHashHashKey,
402 : GlobalNameHashMatchEntry,
403 : PL_DHashMoveEntryStub,
404 : GlobalNameHashClearEntry,
405 : PL_DHashFinalizeStub,
406 : GlobalNameHashInitEntry
407 : };
408 :
409 : mIsInitialized = PL_DHashTableInit(&mGlobalNames, &hash_table_ops, nsnull,
410 : sizeof(GlobalNameMapEntry),
411 306 : GLOBALNAME_HASHTABLE_INITIAL_SIZE);
412 306 : NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_OUT_OF_MEMORY);
413 :
414 : mIsInitialized = PL_DHashTableInit(&mNavigatorNames, &hash_table_ops, nsnull,
415 : sizeof(GlobalNameMapEntry),
416 306 : GLOBALNAME_HASHTABLE_INITIAL_SIZE);
417 306 : if (!mIsInitialized) {
418 0 : PL_DHashTableFinish(&mGlobalNames);
419 :
420 0 : return NS_ERROR_OUT_OF_MEMORY;
421 : }
422 :
423 306 : nsresult rv = NS_OK;
424 :
425 306 : rv = FillHashWithDOMInterfaces();
426 306 : NS_ENSURE_SUCCESS(rv, rv);
427 :
428 : nsCOMPtr<nsICategoryManager> cm =
429 612 : do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv);
430 306 : NS_ENSURE_SUCCESS(rv, rv);
431 :
432 306 : rv = FillHash(cm, JAVASCRIPT_GLOBAL_CONSTRUCTOR_CATEGORY);
433 306 : NS_ENSURE_SUCCESS(rv, rv);
434 :
435 306 : rv = FillHash(cm, JAVASCRIPT_GLOBAL_PROPERTY_CATEGORY);
436 306 : NS_ENSURE_SUCCESS(rv, rv);
437 :
438 306 : rv = FillHash(cm, JAVASCRIPT_GLOBAL_PRIVILEGED_PROPERTY_CATEGORY);
439 306 : NS_ENSURE_SUCCESS(rv, rv);
440 :
441 306 : rv = FillHash(cm, JAVASCRIPT_GLOBAL_STATIC_NAMESET_CATEGORY);
442 306 : NS_ENSURE_SUCCESS(rv, rv);
443 :
444 306 : rv = FillHash(cm, JAVASCRIPT_GLOBAL_DYNAMIC_NAMESET_CATEGORY);
445 306 : NS_ENSURE_SUCCESS(rv, rv);
446 :
447 306 : rv = FillHash(cm, JAVASCRIPT_NAVIGATOR_PROPERTY_CATEGORY);
448 306 : NS_ENSURE_SUCCESS(rv, rv);
449 :
450 : // Initial filling of the has table has been done.
451 : // Now, listen for changes.
452 : nsCOMPtr<nsIObserverService> serv =
453 612 : mozilla::services::GetObserverService();
454 :
455 306 : if (serv) {
456 306 : serv->AddObserver(this, NS_XPCOM_CATEGORY_ENTRY_ADDED_OBSERVER_ID, true);
457 : }
458 :
459 306 : return NS_OK;
460 : }
461 :
462 : struct NameSetClosure {
463 : nsIScriptContext* ctx;
464 : nsresult rv;
465 : };
466 :
467 : static PLDHashOperator
468 0 : NameSetInitCallback(PLDHashTable *table, PLDHashEntryHdr *hdr,
469 : PRUint32 number, void *arg)
470 : {
471 0 : GlobalNameMapEntry *entry = static_cast<GlobalNameMapEntry *>(hdr);
472 :
473 0 : if (entry->mGlobalName.mType == nsGlobalNameStruct::eTypeStaticNameSet) {
474 0 : nsresult rv = NS_OK;
475 : nsCOMPtr<nsIScriptExternalNameSet> ns =
476 0 : do_CreateInstance(entry->mGlobalName.mCID, &rv);
477 0 : NS_ENSURE_SUCCESS(rv, PL_DHASH_NEXT);
478 :
479 0 : NameSetClosure *closure = static_cast<NameSetClosure *>(arg);
480 0 : closure->rv = ns->InitializeNameSet(closure->ctx);
481 0 : if (NS_FAILED(closure->rv)) {
482 0 : NS_ERROR("Initing external script classes failed!");
483 0 : return PL_DHASH_STOP;
484 : }
485 : }
486 :
487 0 : return PL_DHASH_NEXT;
488 : }
489 :
490 : nsresult
491 0 : nsScriptNameSpaceManager::InitForContext(nsIScriptContext *aContext)
492 : {
493 : NameSetClosure closure;
494 0 : closure.ctx = aContext;
495 0 : closure.rv = NS_OK;
496 0 : PL_DHashTableEnumerate(&mGlobalNames, NameSetInitCallback, &closure);
497 :
498 0 : return closure.rv;
499 : }
500 :
501 : nsresult
502 0 : nsScriptNameSpaceManager::LookupName(const nsAString& aName,
503 : const nsGlobalNameStruct **aNameStruct,
504 : const PRUnichar **aClassName)
505 : {
506 : GlobalNameMapEntry *entry =
507 : static_cast<GlobalNameMapEntry *>
508 : (PL_DHashTableOperate(&mGlobalNames, &aName,
509 0 : PL_DHASH_LOOKUP));
510 :
511 0 : if (PL_DHASH_ENTRY_IS_BUSY(entry) &&
512 0 : !((&entry->mGlobalName)->mDisabled)) {
513 0 : *aNameStruct = &entry->mGlobalName;
514 0 : if (aClassName) {
515 0 : *aClassName = entry->mKey.get();
516 : }
517 : } else {
518 0 : *aNameStruct = nsnull;
519 0 : if (aClassName) {
520 0 : *aClassName = nsnull;
521 : }
522 : }
523 :
524 0 : return NS_OK;
525 : }
526 :
527 : nsresult
528 0 : nsScriptNameSpaceManager::LookupNavigatorName(const nsAString& aName,
529 : const nsGlobalNameStruct **aNameStruct)
530 : {
531 : GlobalNameMapEntry *entry =
532 : static_cast<GlobalNameMapEntry *>
533 : (PL_DHashTableOperate(&mNavigatorNames, &aName,
534 0 : PL_DHASH_LOOKUP));
535 :
536 0 : if (PL_DHASH_ENTRY_IS_BUSY(entry) &&
537 0 : !((&entry->mGlobalName)->mDisabled)) {
538 0 : *aNameStruct = &entry->mGlobalName;
539 : } else {
540 0 : *aNameStruct = nsnull;
541 : }
542 :
543 0 : return NS_OK;
544 : }
545 :
546 : nsresult
547 115362 : nsScriptNameSpaceManager::RegisterClassName(const char *aClassName,
548 : PRInt32 aDOMClassInfoID,
549 : bool aPrivileged,
550 : bool aDisabled,
551 : const PRUnichar **aResult)
552 : {
553 115362 : if (!nsCRT::IsAscii(aClassName)) {
554 0 : NS_ERROR("Trying to register a non-ASCII class name");
555 0 : return NS_OK;
556 : }
557 115362 : nsGlobalNameStruct *s = AddToHash(&mGlobalNames, aClassName, aResult);
558 115362 : NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
559 :
560 115362 : if (s->mType == nsGlobalNameStruct::eTypeClassConstructor) {
561 612 : return NS_OK;
562 : }
563 :
564 : // If a external constructor is already defined with aClassName we
565 : // won't overwrite it.
566 :
567 114750 : if (s->mType == nsGlobalNameStruct::eTypeExternalConstructor) {
568 0 : return NS_OK;
569 : }
570 :
571 114750 : NS_ASSERTION(s->mType == nsGlobalNameStruct::eTypeNotInitialized ||
572 : s->mType == nsGlobalNameStruct::eTypeInterface,
573 : "Whaaa, JS environment name clash!");
574 :
575 114750 : s->mType = nsGlobalNameStruct::eTypeClassConstructor;
576 114750 : s->mDOMClassInfoID = aDOMClassInfoID;
577 114750 : s->mChromeOnly = aPrivileged;
578 114750 : s->mDisabled = aDisabled;
579 :
580 114750 : return NS_OK;
581 : }
582 :
583 : nsresult
584 180234 : nsScriptNameSpaceManager::RegisterClassProto(const char *aClassName,
585 : const nsIID *aConstructorProtoIID,
586 : bool *aFoundOld)
587 : {
588 180234 : NS_ENSURE_ARG_POINTER(aConstructorProtoIID);
589 :
590 180234 : *aFoundOld = false;
591 :
592 180234 : nsGlobalNameStruct *s = AddToHash(&mGlobalNames, aClassName);
593 180234 : NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
594 :
595 180234 : if (s->mType != nsGlobalNameStruct::eTypeNotInitialized &&
596 : s->mType != nsGlobalNameStruct::eTypeInterface) {
597 172584 : *aFoundOld = true;
598 :
599 172584 : return NS_OK;
600 : }
601 :
602 7650 : s->mType = nsGlobalNameStruct::eTypeClassProto;
603 7650 : s->mIID = *aConstructorProtoIID;
604 :
605 7650 : return NS_OK;
606 : }
607 :
608 : nsresult
609 0 : nsScriptNameSpaceManager::RegisterExternalClassName(const char *aClassName,
610 : nsCID& aCID)
611 : {
612 0 : nsGlobalNameStruct *s = AddToHash(&mGlobalNames, aClassName);
613 0 : NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
614 :
615 : // If an external constructor is already defined with aClassName we
616 : // won't overwrite it.
617 :
618 0 : if (s->mType == nsGlobalNameStruct::eTypeExternalConstructor) {
619 0 : return NS_OK;
620 : }
621 :
622 0 : NS_ASSERTION(s->mType == nsGlobalNameStruct::eTypeNotInitialized ||
623 : s->mType == nsGlobalNameStruct::eTypeInterface,
624 : "Whaaa, JS environment name clash!");
625 :
626 0 : s->mType = nsGlobalNameStruct::eTypeExternalClassInfoCreator;
627 0 : s->mCID = aCID;
628 :
629 0 : return NS_OK;
630 : }
631 :
632 : nsresult
633 0 : nsScriptNameSpaceManager::RegisterDOMCIData(const char *aName,
634 : nsDOMClassInfoExternalConstructorFnc aConstructorFptr,
635 : const nsIID *aProtoChainInterface,
636 : const nsIID **aInterfaces,
637 : PRUint32 aScriptableFlags,
638 : bool aHasClassInterface,
639 : const nsCID *aConstructorCID)
640 : {
641 : const PRUnichar* className;
642 0 : nsGlobalNameStruct *s = AddToHash(&mGlobalNames, aName, &className);
643 0 : NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
644 :
645 : // If an external constructor is already defined with aClassName we
646 : // won't overwrite it.
647 :
648 0 : if (s->mType == nsGlobalNameStruct::eTypeClassConstructor ||
649 : s->mType == nsGlobalNameStruct::eTypeExternalClassInfo) {
650 0 : return NS_OK;
651 : }
652 :
653 : // XXX Should we bail out here?
654 0 : NS_ASSERTION(s->mType == nsGlobalNameStruct::eTypeNotInitialized ||
655 : s->mType == nsGlobalNameStruct::eTypeExternalClassInfoCreator,
656 : "Someone tries to register classinfo data for a class that isn't new or external!");
657 :
658 0 : s->mData = new nsExternalDOMClassInfoData;
659 0 : NS_ENSURE_TRUE(s->mData, NS_ERROR_OUT_OF_MEMORY);
660 :
661 0 : s->mType = nsGlobalNameStruct::eTypeExternalClassInfo;
662 0 : s->mData->mName = aName;
663 0 : s->mData->mNameUTF16 = className;
664 0 : if (aConstructorFptr)
665 0 : s->mData->u.mExternalConstructorFptr = aConstructorFptr;
666 : else
667 : // null constructor will cause us to use nsDOMGenericSH::doCreate
668 0 : s->mData->u.mExternalConstructorFptr = nsnull;
669 0 : s->mData->mCachedClassInfo = nsnull;
670 0 : s->mData->mProtoChainInterface = aProtoChainInterface;
671 0 : s->mData->mInterfaces = aInterfaces;
672 0 : s->mData->mScriptableFlags = aScriptableFlags;
673 0 : s->mData->mHasClassInterface = aHasClassInterface;
674 0 : s->mData->mConstructorCID = aConstructorCID;
675 :
676 0 : return NS_OK;
677 : }
678 :
679 : nsresult
680 3835 : nsScriptNameSpaceManager::AddCategoryEntryToHash(nsICategoryManager* aCategoryManager,
681 : const char* aCategory,
682 : nsISupports* aEntry)
683 : {
684 : // Get the type from the category name.
685 : // NOTE: we could have passed the type in FillHash() and guessed it in
686 : // Observe() but this way, we have only one place to update and this is
687 : // not performance sensitive.
688 : nsGlobalNameStruct::nametype type;
689 3835 : if (strcmp(aCategory, JAVASCRIPT_GLOBAL_CONSTRUCTOR_CATEGORY) == 0) {
690 1530 : type = nsGlobalNameStruct::eTypeExternalConstructor;
691 3692 : } else if (strcmp(aCategory, JAVASCRIPT_GLOBAL_PROPERTY_CATEGORY) == 0 ||
692 1387 : strcmp(aCategory, JAVASCRIPT_GLOBAL_PRIVILEGED_PROPERTY_CATEGORY) == 0) {
693 1224 : type = nsGlobalNameStruct::eTypeProperty;
694 1081 : } else if (strcmp(aCategory, JAVASCRIPT_NAVIGATOR_PROPERTY_CATEGORY) == 0) {
695 612 : type = nsGlobalNameStruct::eTypeNavigatorProperty;
696 469 : } else if (strcmp(aCategory, JAVASCRIPT_GLOBAL_STATIC_NAMESET_CATEGORY) == 0) {
697 306 : type = nsGlobalNameStruct::eTypeStaticNameSet;
698 163 : } else if (strcmp(aCategory, JAVASCRIPT_GLOBAL_DYNAMIC_NAMESET_CATEGORY) == 0) {
699 0 : type = nsGlobalNameStruct::eTypeDynamicNameSet;
700 : } else {
701 163 : return NS_OK;
702 : }
703 :
704 7344 : nsCOMPtr<nsISupportsCString> strWrapper = do_QueryInterface(aEntry);
705 :
706 3672 : if (!strWrapper) {
707 0 : NS_WARNING("Category entry not an nsISupportsCString!");
708 0 : return NS_OK;
709 : }
710 :
711 7344 : nsCAutoString categoryEntry;
712 3672 : nsresult rv = strWrapper->GetData(categoryEntry);
713 3672 : NS_ENSURE_SUCCESS(rv, rv);
714 :
715 7344 : nsXPIDLCString contractId;
716 : rv = aCategoryManager->GetCategoryEntry(aCategory, categoryEntry.get(),
717 3672 : getter_Copies(contractId));
718 3672 : NS_ENSURE_SUCCESS(rv, rv);
719 :
720 7344 : nsCOMPtr<nsIComponentRegistrar> registrar;
721 3672 : rv = NS_GetComponentRegistrar(getter_AddRefs(registrar));
722 3672 : NS_ENSURE_SUCCESS(rv, rv);
723 :
724 : nsCID *cidPtr;
725 3672 : rv = registrar->ContractIDToCID(contractId, &cidPtr);
726 :
727 3672 : if (NS_FAILED(rv)) {
728 0 : NS_WARNING("Bad contract id registed with the script namespace manager");
729 0 : return NS_OK;
730 : }
731 :
732 : // Copy CID onto the stack, so we can free it right away and avoid having
733 : // to add cleanup code at every exit point from this function.
734 3672 : nsCID cid = *cidPtr;
735 3672 : nsMemory::Free(cidPtr);
736 :
737 3672 : if (type == nsGlobalNameStruct::eTypeExternalConstructor) {
738 3060 : nsXPIDLCString constructorProto;
739 : rv = aCategoryManager->GetCategoryEntry(JAVASCRIPT_GLOBAL_CONSTRUCTOR_PROTO_ALIAS_CATEGORY,
740 : categoryEntry.get(),
741 1530 : getter_Copies(constructorProto));
742 1530 : if (NS_SUCCEEDED(rv)) {
743 918 : nsGlobalNameStruct *s = AddToHash(&mGlobalNames, categoryEntry.get());
744 918 : NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
745 :
746 918 : if (s->mType == nsGlobalNameStruct::eTypeNotInitialized) {
747 918 : s->mAlias = new nsGlobalNameStruct::ConstructorAlias;
748 918 : s->mType = nsGlobalNameStruct::eTypeExternalConstructorAlias;
749 918 : s->mChromeOnly = false;
750 918 : s->mAlias->mCID = cid;
751 918 : AppendASCIItoUTF16(constructorProto, s->mAlias->mProtoName);
752 918 : s->mAlias->mProto = nsnull;
753 : } else {
754 0 : NS_WARNING("Global script name not overwritten!");
755 : }
756 :
757 918 : return NS_OK;
758 : }
759 : }
760 :
761 : PLDHashTable *table;
762 2754 : if (type == nsGlobalNameStruct::eTypeNavigatorProperty) {
763 612 : table = &mNavigatorNames;
764 : } else {
765 2142 : table = &mGlobalNames;
766 : }
767 :
768 2754 : nsGlobalNameStruct *s = AddToHash(table, categoryEntry.get());
769 2754 : NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
770 :
771 2754 : if (s->mType == nsGlobalNameStruct::eTypeNotInitialized) {
772 2754 : s->mType = type;
773 2754 : s->mCID = cid;
774 : s->mChromeOnly =
775 2754 : strcmp(aCategory, JAVASCRIPT_GLOBAL_PRIVILEGED_PROPERTY_CATEGORY) == 0;
776 : } else {
777 0 : NS_WARNING("Global script name not overwritten!");
778 : }
779 :
780 2754 : return NS_OK;
781 : }
782 :
783 : NS_IMETHODIMP
784 163 : nsScriptNameSpaceManager::Observe(nsISupports* aSubject, const char* aTopic,
785 : const PRUnichar* aData)
786 : {
787 163 : if (!aData) {
788 0 : return NS_OK;
789 : }
790 :
791 163 : if (strcmp(aTopic, NS_XPCOM_CATEGORY_ENTRY_ADDED_OBSERVER_ID) == 0) {
792 : nsCOMPtr<nsICategoryManager> cm =
793 326 : do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
794 163 : if (!cm) {
795 0 : return NS_OK;
796 : }
797 :
798 163 : return AddCategoryEntryToHash(cm, NS_ConvertUTF16toUTF8(aData).get(),
799 163 : aSubject);
800 : }
801 :
802 : // TODO: we could observe NS_XPCOM_CATEGORY_ENTRY_REMOVED_OBSERVER_ID
803 : // and NS_XPCOM_CATEGORY_CLEARED_OBSERVER_ID but we are safe without it.
804 : // See bug 600460.
805 :
806 0 : return NS_OK;
807 : }
808 :
|