Reland bug 121341.
[wine-gecko.git] / chrome / src / nsChromeRegistry.cpp
blob0a85098c2e7c1f9811015a73b9b704d2cde2eb68
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 sw=2 et tw=78: */
3 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
16 * The Original Code is mozilla.org code.
18 * The Initial Developer of the Original Code is
19 * Netscape Communications Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 1998
21 * the Initial Developer. All Rights Reserved.
23 * Contributor(s):
24 * Original Author: David W. Hyatt (hyatt@netscape.com)
25 * Gagan Saksena <gagan@netscape.com>
26 * Benjamin Smedberg <benjamin@smedbergs.us>
28 * Alternatively, the contents of this file may be used under the terms of
29 * either the GNU General Public License Version 2 or later (the "GPL"), or
30 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
31 * in which case the provisions of the GPL or the LGPL are applicable instead
32 * of those above. If you wish to allow use of your version of this file only
33 * under the terms of either the GPL or the LGPL, and not to allow others to
34 * use your version of this file under the terms of the MPL, indicate your
35 * decision by deleting the provisions above and replace them with the notice
36 * and other provisions required by the GPL or the LGPL. If you do not delete
37 * the provisions above, a recipient may use your version of this file under
38 * the terms of any one of the MPL, the GPL or the LGPL.
40 * ***** END LICENSE BLOCK ***** */
42 #include "nsChromeRegistry.h"
44 #include <string.h>
46 #include "prio.h"
47 #include "prprf.h"
48 #if defined(XP_WIN)
49 #include <windows.h>
50 #elif defined(XP_MACOSX)
51 #include <Carbon/Carbon.h>
52 #elif defined(MOZ_WIDGET_GTK2)
53 #include <gtk/gtk.h>
54 #endif
56 #include "nsAppDirectoryServiceDefs.h"
57 #include "nsArrayEnumerator.h"
58 #include "nsStringEnumerator.h"
59 #include "nsEnumeratorUtils.h"
60 #include "nsCOMPtr.h"
61 #include "nsDOMError.h"
62 #include "nsEscape.h"
63 #include "nsInt64.h"
64 #include "nsLayoutCID.h"
65 #include "nsNetCID.h"
66 #include "nsNetUtil.h"
67 #include "nsReadableUtils.h"
68 #include "nsStaticAtom.h"
69 #include "nsString.h"
70 #include "nsUnicharUtils.h"
71 #include "nsWidgetsCID.h"
72 #include "nsXPIDLString.h"
73 #include "nsXULAppAPI.h"
74 #include "nsTextFormatter.h"
76 #include "nsIAtom.h"
77 #include "nsICommandLine.h"
78 #include "nsICSSLoader.h"
79 #include "nsICSSStyleSheet.h"
80 #include "nsIConsoleService.h"
81 #include "nsIDirectoryService.h"
82 #include "nsIDocument.h"
83 #include "nsIDOMDocument.h"
84 #include "nsIDocShell.h"
85 #include "nsIDocumentObserver.h"
86 #include "nsIDOMElement.h"
87 #include "nsIDOMLocation.h"
88 #include "nsIDOMWindowCollection.h"
89 #include "nsIDOMWindowInternal.h"
90 #include "nsIFileChannel.h"
91 #include "nsIFileURL.h"
92 #include "nsIIOService.h"
93 #include "nsIJARProtocolHandler.h"
94 #include "nsIJARURI.h"
95 #include "nsILocalFile.h"
96 #include "nsILocaleService.h"
97 #include "nsILookAndFeel.h"
98 #include "nsIObserverService.h"
99 #include "nsIPrefService.h"
100 #include "nsIPrefBranch.h"
101 #include "nsIPrefBranch2.h"
102 #include "nsIPresShell.h"
103 #include "nsIProtocolHandler.h"
104 #include "nsIResProtocolHandler.h"
105 #include "nsIScriptError.h"
106 #include "nsIServiceManager.h"
107 #include "nsISimpleEnumerator.h"
108 #include "nsIStyleSheet.h"
109 #include "nsISupportsArray.h"
110 #include "nsIVersionComparator.h"
111 #include "nsIWindowMediator.h"
112 #include "nsIXPConnect.h"
113 #include "nsIXULAppInfo.h"
114 #include "nsIXULRuntime.h"
115 #include "nsPresShellIterator.h"
117 #ifdef MOZ_XUL
118 // keep all the RDF stuff together, in case we can remove it in the far future
119 #include "rdf.h"
120 #include "nsRDFCID.h"
121 #include "nsIRDFService.h"
122 #include "nsIRDFDataSource.h"
123 #include "nsIRDFObserver.h"
124 #include "nsIRDFRemoteDataSource.h"
125 #include "nsIRDFXMLSink.h"
126 #include "nsIRDFResource.h"
127 #include "nsIRDFDataSource.h"
128 #include "nsIRDFContainer.h"
129 #include "nsIRDFContainerUtils.h"
131 #define CHROME_URI "http://www.mozilla.org/rdf/chrome#"
133 DEFINE_RDF_VOCAB(CHROME_URI, CHROME, packages);
134 DEFINE_RDF_VOCAB(CHROME_URI, CHROME, package);
135 DEFINE_RDF_VOCAB(CHROME_URI, CHROME, name);
136 DEFINE_RDF_VOCAB(CHROME_URI, CHROME, platformPackage);
138 #endif
140 #define UILOCALE_CMD_LINE_ARG "UILocale"
142 #define MATCH_OS_LOCALE_PREF "intl.locale.matchOS"
143 #define SELECTED_LOCALE_PREF "general.useragent.locale"
144 #define SELECTED_SKIN_PREF "general.skins.selectedSkin"
146 static NS_DEFINE_CID(kCSSLoaderCID, NS_CSS_LOADER_CID);
147 static NS_DEFINE_CID(kLookAndFeelCID, NS_LOOKANDFEEL_CID);
149 nsChromeRegistry* nsChromeRegistry::gChromeRegistry;
151 ////////////////////////////////////////////////////////////////////////////////
153 static void
154 LogMessage(const char* aMsg, ...)
156 nsCOMPtr<nsIConsoleService> console
157 (do_GetService(NS_CONSOLESERVICE_CONTRACTID));
158 if (!console)
159 return;
161 va_list args;
162 va_start(args, aMsg);
163 char* formatted = PR_vsmprintf(aMsg, args);
164 va_end(args);
165 if (!formatted)
166 return;
168 console->LogStringMessage(NS_ConvertUTF8toUTF16(formatted).get());
169 PR_smprintf_free(formatted);
172 static void
173 LogMessageWithContext(nsIURI* aURL, PRUint32 aLineNumber, PRUint32 flags,
174 const char* aMsg, ...)
176 nsresult rv;
178 nsCOMPtr<nsIConsoleService> console
179 (do_GetService(NS_CONSOLESERVICE_CONTRACTID));
181 nsCOMPtr<nsIScriptError> error
182 (do_CreateInstance(NS_SCRIPTERROR_CONTRACTID));
183 if (!console || !error)
184 return;
186 va_list args;
187 va_start(args, aMsg);
188 char* formatted = PR_vsmprintf(aMsg, args);
189 va_end(args);
190 if (!formatted)
191 return;
193 nsCString spec;
194 if (aURL)
195 aURL->GetSpec(spec);
197 rv = error->Init(NS_ConvertUTF8toUTF16(formatted).get(),
198 NS_ConvertUTF8toUTF16(spec).get(),
199 nsnull,
200 aLineNumber, 0, flags, "chrome registration");
201 PR_smprintf_free(formatted);
203 if (NS_FAILED(rv))
204 return;
206 console->LogMessage(error);
209 // We use a "best-fit" algorithm for matching locales and themes.
210 // 1) the exact selected locale/theme
211 // 2) (locales only) same language, different country
212 // e.g. en-GB is the selected locale, only en-US is available
213 // 3) any available locale/theme
216 * Match the language-part of two lang-COUNTRY codes, hopefully but
217 * not guaranteed to be in the form ab-CD or abz-CD. "ab" should also
218 * work, any other garbage-in will produce undefined results as long
219 * as it does not crash.
221 static PRBool
222 LanguagesMatch(const nsACString& a, const nsACString& b)
224 if (a.Length() < 2 || b.Length() < 2)
225 return PR_FALSE;
227 nsACString::const_iterator as, ae, bs, be;
228 a.BeginReading(as);
229 a.EndReading(ae);
230 b.BeginReading(bs);
231 b.EndReading(be);
233 while (*as == *bs) {
234 if (*as == '-')
235 return PR_TRUE;
237 ++as; ++bs;
239 // reached the end
240 if (as == ae && bs == be)
241 return PR_TRUE;
243 // "a" is short
244 if (as == ae)
245 return (*bs == '-');
247 // "b" is short
248 if (bs == be)
249 return (*as == '-');
252 return PR_FALSE;
255 nsChromeRegistry::ProviderEntry*
256 nsChromeRegistry::nsProviderArray::GetProvider(const nsACString& aPreferred, MatchType aType)
258 PRInt32 i = mArray.Count();
259 if (!i)
260 return nsnull;
262 ProviderEntry* found = nsnull; // Only set if we find a partial-match locale
263 ProviderEntry* entry;
265 while (i--) {
266 entry = reinterpret_cast<ProviderEntry*>(mArray[i]);
267 if (aPreferred.Equals(entry->provider))
268 return entry;
270 if (aType != LOCALE)
271 continue;
273 if (LanguagesMatch(aPreferred, entry->provider)) {
274 found = entry;
275 continue;
278 if (!found && entry->provider.EqualsLiteral("en-US"))
279 found = entry;
282 if (!found && aType != EXACT)
283 return entry;
285 return found;
288 nsIURI*
289 nsChromeRegistry::nsProviderArray::GetBase(const nsACString& aPreferred, MatchType aType)
291 ProviderEntry* provider = GetProvider(aPreferred, aType);
293 if (!provider)
294 return nsnull;
296 return provider->baseURI;
299 const nsACString&
300 nsChromeRegistry::nsProviderArray::GetSelected(const nsACString& aPreferred, MatchType aType)
302 ProviderEntry* entry = GetProvider(aPreferred, aType);
304 if (entry)
305 return entry->provider;
307 return EmptyCString();
310 void
311 nsChromeRegistry::nsProviderArray::SetBase(const nsACString& aProvider, nsIURI* aBaseURL)
313 ProviderEntry* provider = GetProvider(aProvider, EXACT);
315 if (provider) {
316 provider->baseURI = aBaseURL;
317 return;
320 // no existing entries, add a new one
321 provider = new ProviderEntry(aProvider, aBaseURL);
322 if (!provider)
323 return; // It's safe to silently fail on OOM
325 mArray.AppendElement(provider);
328 void
329 nsChromeRegistry::nsProviderArray::EnumerateToArray(nsCStringArray *a)
331 PRInt32 i = mArray.Count();
332 while (i--) {
333 ProviderEntry *entry = reinterpret_cast<ProviderEntry*>(mArray[i]);
334 a->AppendCString(entry->provider);
338 void
339 nsChromeRegistry::nsProviderArray::Clear()
341 PRInt32 i = mArray.Count();
342 while (i--) {
343 ProviderEntry* entry = reinterpret_cast<ProviderEntry*>(mArray[i]);
344 delete entry;
347 mArray.Clear();
350 nsChromeRegistry::PackageEntry::PackageEntry(const nsACString& aPackage) :
351 package(aPackage), flags(0)
355 PLHashNumber
356 nsChromeRegistry::HashKey(PLDHashTable *table, const void *key)
358 const nsACString& str = *reinterpret_cast<const nsACString*>(key);
359 return HashString(str);
362 PRBool
363 nsChromeRegistry::MatchKey(PLDHashTable *table, const PLDHashEntryHdr *entry,
364 const void *key)
366 const nsACString& str = *reinterpret_cast<const nsACString*>(key);
367 const PackageEntry* pentry = static_cast<const PackageEntry*>(entry);
368 return str.Equals(pentry->package);
371 void
372 nsChromeRegistry::ClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
374 PackageEntry* pentry = static_cast<PackageEntry*>(entry);
375 pentry->~PackageEntry();
378 PRBool
379 nsChromeRegistry::InitEntry(PLDHashTable *table, PLDHashEntryHdr *entry,
380 const void *key)
382 const nsACString& str = *reinterpret_cast<const nsACString*>(key);
384 new (entry) PackageEntry(str);
385 return PR_TRUE;
388 const PLDHashTableOps
389 nsChromeRegistry::kTableOps = {
390 PL_DHashAllocTable,
391 PL_DHashFreeTable,
392 HashKey,
393 MatchKey,
394 PL_DHashMoveEntryStub,
395 ClearEntry,
396 PL_DHashFinalizeStub,
397 InitEntry
400 void
401 nsChromeRegistry::OverlayListEntry::AddURI(nsIURI* aURI)
403 PRInt32 i = mArray.Count();
404 while (i--) {
405 PRBool equals;
406 if (NS_SUCCEEDED(aURI->Equals(mArray[i], &equals)) && equals)
407 return;
410 mArray.AppendObject(aURI);
413 void
414 nsChromeRegistry::OverlayListHash::Add(nsIURI* aBase, nsIURI* aOverlay)
416 OverlayListEntry* entry = mTable.PutEntry(aBase);
417 if (entry)
418 entry->AddURI(aOverlay);
421 const nsCOMArray<nsIURI>*
422 nsChromeRegistry::OverlayListHash::GetArray(nsIURI* aBase)
424 OverlayListEntry* entry = mTable.GetEntry(aBase);
425 if (!entry)
426 return nsnull;
428 return &entry->mArray;
431 nsChromeRegistry::~nsChromeRegistry()
433 if (mPackagesHash.ops)
434 PL_DHashTableFinish(&mPackagesHash);
435 gChromeRegistry = nsnull;
438 NS_INTERFACE_MAP_BEGIN(nsChromeRegistry)
439 NS_INTERFACE_MAP_ENTRY(nsIChromeRegistry)
440 NS_INTERFACE_MAP_ENTRY(nsIXULChromeRegistry)
441 NS_INTERFACE_MAP_ENTRY(nsIToolkitChromeRegistry)
442 #ifdef MOZ_XUL
443 NS_INTERFACE_MAP_ENTRY(nsIXULOverlayProvider)
444 #endif
445 NS_INTERFACE_MAP_ENTRY(nsIObserver)
446 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
447 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIChromeRegistry)
448 NS_INTERFACE_MAP_END
450 NS_IMPL_ADDREF(nsChromeRegistry)
451 NS_IMPL_RELEASE(nsChromeRegistry)
453 ////////////////////////////////////////////////////////////////////////////////
454 // nsIChromeRegistry methods:
456 static nsresult
457 getUILangCountry(nsACString& aUILang)
459 nsresult rv;
461 nsCOMPtr<nsILocaleService> localeService = do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv);
462 NS_ENSURE_SUCCESS(rv, rv);
464 nsAutoString uiLang;
465 rv = localeService->GetLocaleComponentForUserAgent(uiLang);
466 NS_ENSURE_SUCCESS(rv, rv);
468 CopyUTF16toUTF8(uiLang, aUILang);
469 return NS_OK;
472 nsresult
473 nsChromeRegistry::Init()
475 nsresult rv;
477 // these atoms appear in almost every chrome registry contents.rdf
478 // in some form or another. making static atoms prevents the atoms
479 // from constantly being created/destroyed during parsing
481 static const nsStaticAtom atoms[] = {
482 { "chrome", nsnull },
483 { "NC", nsnull },
484 { "allowScripts", nsnull },
485 { "package", nsnull },
486 { "packages", nsnull },
487 { "hasOverlays", nsnull },
490 NS_RegisterStaticAtoms(atoms, NS_ARRAY_LENGTH(atoms));
492 // Check to see if necko and the JAR protocol handler are registered yet
493 // if not, somebody is doing work during XPCOM registration that they
494 // shouldn't be doing. See bug 292549, where JS components are trying
495 // to call Components.utils.import("chrome:///") early in registration
497 nsCOMPtr<nsIIOService> io (do_GetIOService());
498 if (!io) return NS_ERROR_FAILURE;
500 nsCOMPtr<nsIProtocolHandler> ph;
501 rv = io->GetProtocolHandler("jar", getter_AddRefs(ph));
502 NS_ENSURE_SUCCESS(rv, rv);
504 nsCOMPtr<nsIJARProtocolHandler> jph = do_QueryInterface(ph);
505 if (!jph)
506 return NS_ERROR_NOT_INITIALIZED;
508 if (!PL_DHashTableInit(&mPackagesHash, &kTableOps,
509 nsnull, sizeof(PackageEntry), 16))
510 return NS_ERROR_FAILURE;
512 if (!mOverlayHash.Init() ||
513 !mStyleHash.Init() ||
514 !mOverrideTable.Init())
515 return NS_ERROR_FAILURE;
517 mSelectedLocale = NS_LITERAL_CSTRING("en-US");
518 mSelectedSkin = NS_LITERAL_CSTRING("classic/1.0");
520 // This initialization process is fairly complicated and may cause reentrant
521 // getservice calls to resolve chrome URIs (especially locale files). We
522 // don't want that, so we inform the protocol handler about our existence
523 // before we are actually fully initialized.
524 gChromeRegistry = this;
526 PRBool safeMode = PR_FALSE;
527 nsCOMPtr<nsIXULRuntime> xulrun (do_GetService(XULAPPINFO_SERVICE_CONTRACTID));
528 if (xulrun)
529 xulrun->GetInSafeMode(&safeMode);
531 nsCOMPtr<nsIPrefService> prefserv (do_GetService(NS_PREFSERVICE_CONTRACTID));
532 nsCOMPtr<nsIPrefBranch> prefs;
534 if (safeMode)
535 prefserv->GetDefaultBranch(nsnull, getter_AddRefs(prefs));
536 else
537 prefs = do_QueryInterface(prefserv);
539 if (!prefs) {
540 NS_WARNING("Could not get pref service!");
543 PRBool useLocalePref = PR_TRUE;
545 if (prefs) {
546 // check the pref first
547 PRBool matchOS = PR_FALSE;
548 rv = prefs->GetBoolPref(MATCH_OS_LOCALE_PREF, &matchOS);
550 // match os locale
551 if (NS_SUCCEEDED(rv) && matchOS) {
552 // compute lang and region code only when needed!
553 nsCAutoString uiLocale;
554 rv = getUILangCountry(uiLocale);
555 if (NS_SUCCEEDED(rv)) {
556 useLocalePref = PR_FALSE;
557 mSelectedLocale = uiLocale;
562 if (prefs) {
563 nsXPIDLCString provider;
565 rv = prefs->GetCharPref(SELECTED_SKIN_PREF, getter_Copies(provider));
566 if (NS_SUCCEEDED(rv))
567 mSelectedSkin = provider;
569 nsCOMPtr<nsIPrefBranch2> prefs2 (do_QueryInterface(prefs));
571 if (prefs2)
572 rv = prefs2->AddObserver(SELECTED_SKIN_PREF, this, PR_TRUE);
574 if (useLocalePref) {
575 rv = prefs->GetCharPref(SELECTED_LOCALE_PREF, getter_Copies(provider));
576 if (NS_SUCCEEDED(rv))
577 mSelectedLocale = provider;
579 if (prefs2)
580 prefs2->AddObserver(SELECTED_LOCALE_PREF, this, PR_TRUE);
584 CheckForNewChrome();
586 mInitialized = PR_TRUE;
588 return NS_OK;
591 NS_IMETHODIMP
592 nsChromeRegistry::CheckForOSAccessibility()
594 nsresult rv;
596 nsCOMPtr<nsILookAndFeel> lookAndFeel (do_GetService(kLookAndFeelCID));
597 if (lookAndFeel) {
598 PRInt32 useAccessibilityTheme = 0;
600 rv = lookAndFeel->GetMetric(nsILookAndFeel::eMetric_UseAccessibilityTheme,
601 useAccessibilityTheme);
603 if (NS_SUCCEEDED(rv) && useAccessibilityTheme) {
604 /* Set the skin to classic and remove pref observers */
605 if (!mSelectedSkin.EqualsLiteral("classic/1.0")) {
606 mSelectedSkin.AssignLiteral("classic/1.0");
607 RefreshSkins();
610 nsCOMPtr<nsIPrefBranch2> prefs (do_GetService(NS_PREFSERVICE_CONTRACTID));
611 if (prefs) {
612 prefs->RemoveObserver(SELECTED_SKIN_PREF, this);
617 return NS_OK;
620 nsresult
621 nsChromeRegistry::GetProviderAndPath(nsIURL* aChromeURL,
622 nsACString& aProvider, nsACString& aPath)
624 nsresult rv;
626 #ifdef DEBUG
627 PRBool isChrome;
628 aChromeURL->SchemeIs("chrome", &isChrome);
629 NS_ASSERTION(isChrome, "Non-chrome URI?");
630 #endif
632 nsCAutoString path;
633 rv = aChromeURL->GetPath(path);
634 NS_ENSURE_SUCCESS(rv, rv);
636 if (path.Length() < 3) {
637 LogMessage("Invalid chrome URI: %s", path.get());
638 return NS_ERROR_FAILURE;
641 path.SetLength(nsUnescapeCount(path.BeginWriting()));
642 NS_ASSERTION(path.First() == '/', "Path should always begin with a slash!");
644 PRInt32 slash = path.FindChar('/', 1);
645 if (slash == 1) {
646 LogMessage("Invalid chrome URI: %s", path.get());
647 return NS_ERROR_FAILURE;
650 if (slash == -1) {
651 aPath.Truncate();
653 else {
654 if (slash == (PRInt32) path.Length() - 1)
655 aPath.Truncate();
656 else
657 aPath.Assign(path.get() + slash + 1, path.Length() - slash - 1);
659 --slash;
662 aProvider.Assign(path.get() + 1, slash);
663 return NS_OK;
667 nsresult
668 nsChromeRegistry::Canonify(nsIURL* aChromeURL)
670 NS_NAMED_LITERAL_CSTRING(kSlash, "/");
672 nsresult rv;
674 nsCAutoString provider, path;
675 rv = GetProviderAndPath(aChromeURL, provider, path);
676 NS_ENSURE_SUCCESS(rv, rv);
678 if (path.IsEmpty()) {
679 nsCAutoString package;
680 rv = aChromeURL->GetHost(package);
681 NS_ENSURE_SUCCESS(rv, rv);
683 // we re-use the "path" local string to build a new URL path
684 path.Assign(kSlash + provider + kSlash + package);
685 if (provider.EqualsLiteral("content")) {
686 path.AppendLiteral(".xul");
688 else if (provider.EqualsLiteral("locale")) {
689 path.AppendLiteral(".dtd");
691 else if (provider.EqualsLiteral("skin")) {
692 path.AppendLiteral(".css");
694 else {
695 return NS_ERROR_INVALID_ARG;
697 aChromeURL->SetPath(path);
699 else {
700 // prevent directory traversals ("..")
701 // path is already unescaped once, but uris can get unescaped twice
702 const char* pos = path.BeginReading();
703 const char* end = path.EndReading();
704 while (pos < end) {
705 switch (*pos) {
706 case ':':
707 return NS_ERROR_DOM_BAD_URI;
708 case '.':
709 if (pos[1] == '.')
710 return NS_ERROR_DOM_BAD_URI;
711 break;
712 case '%':
713 // chrome: URIs with double-escapes are trying to trick us.
714 // watch for %2e, and %25 in case someone triple unescapes
715 if (pos[1] == '2' &&
716 ( pos[2] == 'e' || pos[2] == 'E' ||
717 pos[2] == '5' ))
718 return NS_ERROR_DOM_BAD_URI;
719 break;
720 case '?':
721 case '#':
722 pos = end;
723 continue;
725 ++pos;
729 return NS_OK;
732 NS_IMETHODIMP
733 nsChromeRegistry::ConvertChromeURL(nsIURI* aChromeURI, nsIURI* *aResult)
735 nsresult rv;
736 NS_ASSERTION(aChromeURI, "null url!");
738 if (mOverrideTable.Get(aChromeURI, aResult))
739 return NS_OK;
741 nsCOMPtr<nsIURL> chromeURL (do_QueryInterface(aChromeURI));
742 NS_ENSURE_TRUE(chromeURL, NS_NOINTERFACE);
744 nsCAutoString package, provider, path;
745 rv = chromeURL->GetHostPort(package);
746 NS_ENSURE_SUCCESS(rv, rv);
748 rv = GetProviderAndPath(chromeURL, provider, path);
749 NS_ENSURE_SUCCESS(rv, rv);
751 PackageEntry* entry =
752 static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
753 & (nsACString&) package,
754 PL_DHASH_LOOKUP));
756 if (PL_DHASH_ENTRY_IS_FREE(entry)) {
757 if (!mInitialized)
758 return NS_ERROR_NOT_INITIALIZED;
760 LogMessage("No chrome package registered for chrome://%s/%s/%s",
761 package.get(), provider.get(), path.get());
763 return NS_ERROR_FAILURE;
766 if (entry->flags & PackageEntry::PLATFORM_PACKAGE) {
767 #if defined(XP_WIN) || defined(XP_OS2)
768 path.Insert("win/", 0);
769 #elif defined(XP_MACOSX)
770 path.Insert("mac/", 0);
771 #else
772 path.Insert("unix/", 0);
773 #endif
776 nsIURI* baseURI = nsnull;
777 if (provider.EqualsLiteral("locale")) {
778 baseURI = entry->locales.GetBase(mSelectedLocale, nsProviderArray::LOCALE);
780 else if (provider.EqualsLiteral("skin")) {
781 baseURI = entry->skins.GetBase(mSelectedSkin, nsProviderArray::ANY);
783 else if (provider.EqualsLiteral("content")) {
784 baseURI = entry->baseURI;
787 if (!baseURI) {
788 LogMessage("No chrome package registered for chrome://%s/%s/%s",
789 package.get(), provider.get(), path.get());
790 return NS_ERROR_FAILURE;
793 return NS_NewURI(aResult, path, nsnull, baseURI);
796 nsresult
797 nsChromeRegistry::GetSelectedLocale(const nsACString& aPackage, nsACString& aLocale)
799 PackageEntry* entry =
800 static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
801 & aPackage,
802 PL_DHASH_LOOKUP));
804 if (PL_DHASH_ENTRY_IS_FREE(entry))
805 return NS_ERROR_FAILURE;
807 aLocale = entry->locales.GetSelected(mSelectedLocale, nsProviderArray::LOCALE);
808 if (aLocale.IsEmpty())
809 return NS_ERROR_FAILURE;
811 return NS_OK;
814 NS_IMETHODIMP
815 nsChromeRegistry::GetLocalesForPackage(const nsACString& aPackage,
816 nsIUTF8StringEnumerator* *aResult)
818 nsCStringArray *a = new nsCStringArray;
819 if (!a)
820 return NS_ERROR_OUT_OF_MEMORY;
822 PackageEntry* entry =
823 static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
824 & aPackage,
825 PL_DHASH_LOOKUP));
827 if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
828 entry->locales.EnumerateToArray(a);
831 nsresult rv = NS_NewAdoptingUTF8StringEnumerator(aResult, a);
832 if (NS_FAILED(rv))
833 delete a;
835 return rv;
838 #ifdef MOZ_XUL
839 NS_IMETHODIMP
840 nsChromeRegistry::GetStyleOverlays(nsIURI *aChromeURL,
841 nsISimpleEnumerator **aResult)
843 const nsCOMArray<nsIURI>* parray = mStyleHash.GetArray(aChromeURL);
844 if (!parray)
845 return NS_NewEmptyEnumerator(aResult);
847 return NS_NewArrayEnumerator(aResult, *parray);
850 NS_IMETHODIMP
851 nsChromeRegistry::GetXULOverlays(nsIURI *aChromeURL, nsISimpleEnumerator **aResult)
853 const nsCOMArray<nsIURI>* parray = mOverlayHash.GetArray(aChromeURL);
854 if (!parray)
855 return NS_NewEmptyEnumerator(aResult);
857 return NS_NewArrayEnumerator(aResult, *parray);
859 #endif // MOZ_XUL
861 ////////////////////////////////////////////////////////////////////////
863 // theme stuff
866 static void FlushSkinBindingsForWindow(nsIDOMWindowInternal* aWindow)
868 // Get the DOM document.
869 nsCOMPtr<nsIDOMDocument> domDocument;
870 aWindow->GetDocument(getter_AddRefs(domDocument));
871 if (!domDocument)
872 return;
874 nsCOMPtr<nsIDocument> document = do_QueryInterface(domDocument);
875 if (!document)
876 return;
878 // Annihilate all XBL bindings.
879 document->FlushSkinBindings();
882 // XXXbsmedberg: move this to nsIWindowMediator
883 NS_IMETHODIMP nsChromeRegistry::RefreshSkins()
885 nsCOMPtr<nsICSSLoader> cssLoader(do_CreateInstance(kCSSLoaderCID));
886 if (!cssLoader)
887 return NS_OK;
889 nsCOMPtr<nsIWindowMediator> windowMediator
890 (do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
891 if (!windowMediator)
892 return NS_OK;
894 nsCOMPtr<nsISimpleEnumerator> windowEnumerator;
895 windowMediator->GetEnumerator(nsnull, getter_AddRefs(windowEnumerator));
896 PRBool more;
897 windowEnumerator->HasMoreElements(&more);
898 while (more) {
899 nsCOMPtr<nsISupports> protoWindow;
900 windowEnumerator->GetNext(getter_AddRefs(protoWindow));
901 if (protoWindow) {
902 nsCOMPtr<nsIDOMWindowInternal> domWindow = do_QueryInterface(protoWindow);
903 if (domWindow)
904 FlushSkinBindingsForWindow(domWindow);
906 windowEnumerator->HasMoreElements(&more);
909 FlushSkinCaches();
911 windowMediator->GetEnumerator(nsnull, getter_AddRefs(windowEnumerator));
912 windowEnumerator->HasMoreElements(&more);
913 while (more) {
914 nsCOMPtr<nsISupports> protoWindow;
915 windowEnumerator->GetNext(getter_AddRefs(protoWindow));
916 if (protoWindow) {
917 nsCOMPtr<nsIDOMWindowInternal> domWindow = do_QueryInterface(protoWindow);
918 if (domWindow)
919 RefreshWindow(domWindow, cssLoader);
921 windowEnumerator->HasMoreElements(&more);
924 return NS_OK;
927 void
928 nsChromeRegistry::FlushSkinCaches()
930 nsCOMPtr<nsIObserverService> obsSvc =
931 do_GetService("@mozilla.org/observer-service;1");
932 NS_ASSERTION(obsSvc, "Couldn't get observer service.");
934 obsSvc->NotifyObservers(static_cast<nsIChromeRegistry*>(this),
935 NS_CHROME_FLUSH_SKINS_TOPIC, nsnull);
938 static PRBool IsChromeURI(nsIURI* aURI)
940 PRBool isChrome=PR_FALSE;
941 if (NS_SUCCEEDED(aURI->SchemeIs("chrome", &isChrome)) && isChrome)
942 return PR_TRUE;
943 return PR_FALSE;
946 // XXXbsmedberg: move this to windowmediator
947 nsresult nsChromeRegistry::RefreshWindow(nsIDOMWindowInternal* aWindow,
948 nsICSSLoader* aCSSLoader)
950 // Deal with our subframes first.
951 nsCOMPtr<nsIDOMWindowCollection> frames;
952 aWindow->GetFrames(getter_AddRefs(frames));
953 PRUint32 length;
954 frames->GetLength(&length);
955 PRUint32 j;
956 for (j = 0; j < length; j++) {
957 nsCOMPtr<nsIDOMWindow> childWin;
958 frames->Item(j, getter_AddRefs(childWin));
959 nsCOMPtr<nsIDOMWindowInternal> childInt(do_QueryInterface(childWin));
960 RefreshWindow(childInt, aCSSLoader);
963 nsresult rv;
964 // Get the DOM document.
965 nsCOMPtr<nsIDOMDocument> domDocument;
966 aWindow->GetDocument(getter_AddRefs(domDocument));
967 if (!domDocument)
968 return NS_OK;
970 nsCOMPtr<nsIDocument> document = do_QueryInterface(domDocument);
971 if (!document)
972 return NS_OK;
974 // Deal with the agent sheets first. Have to do all the style sets by hand.
975 nsPresShellIterator iter(document);
976 nsCOMPtr<nsIPresShell> shell;
977 while ((shell = iter.GetNextShell())) {
978 // Reload only the chrome URL agent style sheets.
979 nsCOMArray<nsIStyleSheet> agentSheets;
980 rv = shell->GetAgentStyleSheets(agentSheets);
981 NS_ENSURE_SUCCESS(rv, rv);
983 nsCOMArray<nsIStyleSheet> newAgentSheets;
984 for (PRInt32 l = 0; l < agentSheets.Count(); ++l) {
985 nsIStyleSheet *sheet = agentSheets[l];
987 nsCOMPtr<nsIURI> uri;
988 rv = sheet->GetSheetURI(getter_AddRefs(uri));
989 if (NS_FAILED(rv)) return rv;
991 if (IsChromeURI(uri)) {
992 // Reload the sheet.
993 nsCOMPtr<nsICSSStyleSheet> newSheet;
994 rv = aCSSLoader->LoadSheetSync(uri, PR_TRUE, getter_AddRefs(newSheet));
995 if (NS_FAILED(rv)) return rv;
996 if (newSheet) {
997 rv = newAgentSheets.AppendObject(newSheet) ? NS_OK : NS_ERROR_FAILURE;
998 if (NS_FAILED(rv)) return rv;
1001 else { // Just use the same sheet.
1002 rv = newAgentSheets.AppendObject(sheet) ? NS_OK : NS_ERROR_FAILURE;
1003 if (NS_FAILED(rv)) return rv;
1007 rv = shell->SetAgentStyleSheets(newAgentSheets);
1008 NS_ENSURE_SUCCESS(rv, rv);
1011 // Build an array of nsIURIs of style sheets we need to load.
1012 nsCOMArray<nsIStyleSheet> oldSheets;
1013 nsCOMArray<nsIStyleSheet> newSheets;
1015 PRInt32 count = document->GetNumberOfStyleSheets();
1017 // Iterate over the style sheets.
1018 PRInt32 i;
1019 for (i = 0; i < count; i++) {
1020 // Get the style sheet
1021 nsIStyleSheet *styleSheet = document->GetStyleSheetAt(i);
1023 if (!oldSheets.AppendObject(styleSheet)) {
1024 return NS_ERROR_OUT_OF_MEMORY;
1028 // Iterate over our old sheets and kick off a sync load of the new
1029 // sheet if and only if it's a chrome URL.
1030 for (i = 0; i < count; i++) {
1031 nsCOMPtr<nsIStyleSheet> sheet = oldSheets[i];
1032 nsCOMPtr<nsIURI> uri;
1033 rv = sheet->GetSheetURI(getter_AddRefs(uri));
1034 if (NS_FAILED(rv)) return rv;
1036 if (IsChromeURI(uri)) {
1037 // Reload the sheet.
1038 #ifdef DEBUG
1039 nsCOMPtr<nsICSSStyleSheet> oldCSSSheet = do_QueryInterface(sheet);
1040 NS_ASSERTION(oldCSSSheet, "Don't know how to reload a non-CSS sheet");
1041 #endif
1042 nsCOMPtr<nsICSSStyleSheet> newSheet;
1043 // XXX what about chrome sheets that have a title or are disabled? This
1044 // only works by sheer dumb luck.
1045 // XXXbz this should really use the document's CSSLoader!
1046 aCSSLoader->LoadSheetSync(uri, getter_AddRefs(newSheet));
1047 // Even if it's null, we put in in there.
1048 newSheets.AppendObject(newSheet);
1050 else {
1051 // Just use the same sheet.
1052 newSheets.AppendObject(sheet);
1056 // Now notify the document that multiple sheets have been added and removed.
1057 document->UpdateStyleSheets(oldSheets, newSheets);
1058 return NS_OK;
1061 void
1062 nsChromeRegistry::FlushAllCaches()
1064 nsCOMPtr<nsIObserverService> obsSvc =
1065 do_GetService("@mozilla.org/observer-service;1");
1066 NS_ASSERTION(obsSvc, "Couldn't get observer service.");
1068 obsSvc->NotifyObservers((nsIChromeRegistry*) this,
1069 NS_CHROME_FLUSH_TOPIC, nsnull);
1072 // xxxbsmedberg Move me to nsIWindowMediator
1073 NS_IMETHODIMP
1074 nsChromeRegistry::ReloadChrome()
1076 FlushAllCaches();
1077 // Do a reload of all top level windows.
1078 nsresult rv = NS_OK;
1080 // Get the window mediator
1081 nsCOMPtr<nsIWindowMediator> windowMediator
1082 (do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
1083 if (windowMediator) {
1084 nsCOMPtr<nsISimpleEnumerator> windowEnumerator;
1086 rv = windowMediator->GetEnumerator(nsnull, getter_AddRefs(windowEnumerator));
1087 if (NS_SUCCEEDED(rv)) {
1088 // Get each dom window
1089 PRBool more;
1090 rv = windowEnumerator->HasMoreElements(&more);
1091 if (NS_FAILED(rv)) return rv;
1092 while (more) {
1093 nsCOMPtr<nsISupports> protoWindow;
1094 rv = windowEnumerator->GetNext(getter_AddRefs(protoWindow));
1095 if (NS_SUCCEEDED(rv)) {
1096 nsCOMPtr<nsIDOMWindowInternal> domWindow =
1097 do_QueryInterface(protoWindow);
1098 if (domWindow) {
1099 nsCOMPtr<nsIDOMLocation> location;
1100 domWindow->GetLocation(getter_AddRefs(location));
1101 if (location) {
1102 rv = location->Reload(PR_FALSE);
1103 if (NS_FAILED(rv)) return rv;
1107 rv = windowEnumerator->HasMoreElements(&more);
1108 if (NS_FAILED(rv)) return rv;
1112 return rv;
1115 NS_IMETHODIMP
1116 nsChromeRegistry::AllowScriptsForPackage(nsIURI* aChromeURI, PRBool *aResult)
1118 nsresult rv;
1119 *aResult = PR_FALSE;
1121 #ifdef DEBUG
1122 PRBool isChrome;
1123 aChromeURI->SchemeIs("chrome", &isChrome);
1124 NS_ASSERTION(isChrome, "Non-chrome URI passed to AllowScriptsForPackage!");
1125 #endif
1127 nsCOMPtr<nsIURL> url (do_QueryInterface(aChromeURI));
1128 NS_ENSURE_TRUE(url, NS_NOINTERFACE);
1130 nsCAutoString provider, file;
1131 rv = GetProviderAndPath(url, provider, file);
1132 NS_ENSURE_SUCCESS(rv, rv);
1134 if (!provider.EqualsLiteral("skin"))
1135 *aResult = PR_TRUE;
1137 return NS_OK;
1140 NS_IMETHODIMP
1141 nsChromeRegistry::AllowContentToAccess(nsIURI *aURI, PRBool *aResult)
1143 nsresult rv;
1145 *aResult = PR_FALSE;
1147 #ifdef DEBUG
1148 PRBool isChrome;
1149 aURI->SchemeIs("chrome", &isChrome);
1150 NS_ASSERTION(isChrome, "Non-chrome URI passed to AllowContentToAccess!");
1151 #endif
1153 nsCOMPtr<nsIURL> url = do_QueryInterface(aURI);
1154 if (!url) {
1155 NS_ERROR("Chrome URL doesn't implement nsIURL.");
1156 return NS_ERROR_UNEXPECTED;
1159 nsCAutoString package;
1160 rv = url->GetHostPort(package);
1161 NS_ENSURE_SUCCESS(rv, rv);
1163 PackageEntry *entry =
1164 static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
1165 & (nsACString&) package,
1166 PL_DHASH_LOOKUP));
1168 if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
1169 *aResult = !!(entry->flags & PackageEntry::CONTENT_ACCESSIBLE);
1171 return NS_OK;
1174 static PLDHashOperator
1175 RemoveAll(PLDHashTable *table, PLDHashEntryHdr *entry, PRUint32 number, void *arg)
1177 return (PLDHashOperator) (PL_DHASH_NEXT | PL_DHASH_REMOVE);
1180 NS_IMETHODIMP
1181 nsChromeRegistry::CheckForNewChrome()
1183 nsresult rv;
1185 PL_DHashTableEnumerate(&mPackagesHash, RemoveAll, nsnull);
1186 mOverlayHash.Clear();
1187 mStyleHash.Clear();
1188 mOverrideTable.Clear();
1190 nsCOMPtr<nsIURI> manifestURI;
1191 rv = NS_NewURI(getter_AddRefs(manifestURI),
1192 NS_LITERAL_CSTRING("resource:///chrome/app-chrome.manifest"));
1194 // this is the main manifest; if it doesn't exist we generate it from
1195 // installed-chrome.txt. When the build system learns about the new system,
1196 // this code can go away.
1198 nsCOMPtr<nsIFileURL> manifestFileURL (do_QueryInterface(manifestURI));
1199 NS_ASSERTION(manifestFileURL, "Not a nsIFileURL!");
1200 NS_ENSURE_TRUE(manifestFileURL, NS_ERROR_UNEXPECTED);
1202 nsCOMPtr<nsIFile> manifest;
1203 manifestFileURL->GetFile(getter_AddRefs(manifest));
1204 NS_ENSURE_TRUE(manifest, NS_ERROR_FAILURE);
1206 PRBool exists;
1207 rv = manifest->Exists(&exists);
1208 NS_ENSURE_SUCCESS(rv, rv);
1210 #ifdef DEBUG
1211 // In debug builds, installed-chrome.txt may change during development;
1212 // we just rebuild it every time because we're not worried about startup
1213 // time or other bad/goodness.
1214 if (exists) {
1215 manifest->Remove(PR_FALSE);
1216 exists = PR_FALSE;
1218 #endif
1220 if (!exists) {
1221 nsCOMPtr<nsIFile> installed;
1222 manifest->Clone(getter_AddRefs(installed));
1223 if (!installed)
1224 return NS_ERROR_OUT_OF_MEMORY;
1226 nsCOMPtr<nsILocalFile> linstalled (do_QueryInterface(installed));
1227 NS_ENSURE_TRUE(linstalled, NS_NOINTERFACE);
1229 linstalled->SetNativeLeafName(NS_LITERAL_CSTRING("installed-chrome.txt"));
1231 rv = linstalled->Exists(&exists);
1232 NS_ENSURE_SUCCESS(rv, rv);
1234 // process installed-chrome.txt into app-chrome.manifest
1235 if (exists)
1236 ProcessNewChromeFile(linstalled, manifestURI);
1239 nsCOMPtr<nsIProperties> dirSvc (do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID));
1240 NS_ENSURE_TRUE(dirSvc, NS_ERROR_FAILURE);
1242 // check the extra chrome directories
1243 nsCOMPtr<nsISimpleEnumerator> chromeML;
1244 rv = dirSvc->Get(NS_CHROME_MANIFESTS_FILE_LIST, NS_GET_IID(nsISimpleEnumerator),
1245 getter_AddRefs(chromeML));
1246 if (NS_FAILED(rv)) {
1247 // ok, then simply load all .manifest files in the app chrome dir.
1248 nsCOMPtr<nsIFile> chromeDir;
1249 rv = dirSvc->Get(NS_APP_CHROME_DIR, NS_GET_IID(nsIFile),
1250 getter_AddRefs(chromeDir));
1251 if (NS_FAILED(rv))
1252 return rv;
1253 rv = NS_NewSingletonEnumerator(getter_AddRefs(chromeML), chromeDir);
1254 if (NS_FAILED(rv))
1255 return rv;
1258 nsCOMPtr<nsISupports> next;
1259 while (NS_SUCCEEDED(chromeML->HasMoreElements(&exists)) && exists) {
1260 chromeML->GetNext(getter_AddRefs(next));
1261 nsCOMPtr<nsILocalFile> lmanifest = do_QueryInterface(next);
1262 if (!lmanifest) {
1263 NS_ERROR("Directory enumerator returned a non-nsILocalFile");
1264 continue;
1267 PRBool isDir;
1268 if (NS_SUCCEEDED(lmanifest->IsDirectory(&isDir)) && isDir) {
1269 nsCOMPtr<nsISimpleEnumerator> entries;
1270 rv = lmanifest->GetDirectoryEntries(getter_AddRefs(entries));
1271 if (NS_FAILED(rv))
1272 continue;
1274 while (NS_SUCCEEDED(entries->HasMoreElements(&exists)) && exists) {
1275 entries->GetNext(getter_AddRefs(next));
1276 lmanifest = do_QueryInterface(next);
1277 if (lmanifest) {
1278 nsCAutoString leafName;
1279 lmanifest->GetNativeLeafName(leafName);
1280 if (StringEndsWith(leafName, NS_LITERAL_CSTRING(".manifest"))) {
1281 rv = ProcessManifest(lmanifest, PR_FALSE);
1282 if (NS_FAILED(rv)) {
1283 nsCAutoString path;
1284 lmanifest->GetNativePath(path);
1285 LogMessage("Failed to process chrome manifest '%s'.",
1286 path.get());
1293 else {
1294 rv = ProcessManifest(lmanifest, PR_FALSE);
1295 if (NS_FAILED(rv)) {
1296 nsCAutoString path;
1297 lmanifest->GetNativePath(path);
1298 LogMessage("Failed to process chrome manifest: '%s'.",
1299 path.get());
1304 rv = dirSvc->Get(NS_SKIN_MANIFESTS_FILE_LIST, NS_GET_IID(nsISimpleEnumerator),
1305 getter_AddRefs(chromeML));
1306 if (NS_FAILED(rv))
1307 return NS_OK;
1309 while (NS_SUCCEEDED(chromeML->HasMoreElements(&exists)) && exists) {
1310 chromeML->GetNext(getter_AddRefs(next));
1311 nsCOMPtr<nsILocalFile> lmanifest = do_QueryInterface(next);
1312 if (!lmanifest) {
1313 NS_ERROR("Directory enumerator returned a non-nsILocalFile");
1314 continue;
1317 rv = ProcessManifest(lmanifest, PR_TRUE);
1318 if (NS_FAILED(rv)) {
1319 nsCAutoString path;
1320 lmanifest->GetNativePath(path);
1321 LogMessage("Failed to process chrome manifest: '%s'.",
1322 path.get());
1326 return NS_OK;
1329 nsresult
1330 nsChromeRegistry::ProcessNewChromeFile(nsILocalFile *aListFile, nsIURI* aManifest)
1332 nsresult rv;
1334 PRFileDesc *file;
1335 rv = aListFile->OpenNSPRFileDesc(PR_RDONLY, 0, &file);
1336 NS_ENSURE_SUCCESS(rv, rv);
1338 PRInt32 n, size;
1339 char *buf;
1341 size = PR_Available(file);
1342 if (size == -1) {
1343 rv = NS_ERROR_UNEXPECTED;
1344 goto end;
1347 buf = (char *) malloc(size + 1);
1348 if (!buf) {
1349 rv = NS_ERROR_OUT_OF_MEMORY;
1350 goto end;
1353 n = PR_Read(file, buf, size);
1354 if (n > 0)
1355 rv = ProcessNewChromeBuffer(buf, size, aManifest);
1356 free(buf);
1358 end:
1359 PR_Close(file);
1360 return rv;
1363 nsresult
1364 nsChromeRegistry::ProcessNewChromeBuffer(char *aBuffer, PRInt32 aLength,
1365 nsIURI* aManifest)
1367 nsresult rv = NS_OK;
1368 char *bufferEnd = aBuffer + aLength;
1369 char *chromeType, // "content", "locale" or "skin"
1370 *chromeProfile, // "install" or "profile"
1371 *chromeLocType, // type of location (local path or URL)
1372 *chromeLocation; // base location of chrome (jar file)
1374 nsCOMPtr<nsIURI> baseURI;
1376 // process chromeType, chromeProfile, chromeLocType, chromeLocation
1377 while (aBuffer < bufferEnd) {
1378 // parse one line of installed-chrome.txt
1379 chromeType = aBuffer;
1380 while (aBuffer < bufferEnd && *aBuffer != ',')
1381 ++aBuffer;
1382 *aBuffer = '\0';
1384 chromeProfile = ++aBuffer;
1385 if (aBuffer >= bufferEnd)
1386 break;
1388 while (aBuffer < bufferEnd && *aBuffer != ',')
1389 ++aBuffer;
1390 *aBuffer = '\0';
1392 chromeLocType = ++aBuffer;
1393 if (aBuffer >= bufferEnd)
1394 break;
1396 while (aBuffer < bufferEnd && *aBuffer != ',')
1397 ++aBuffer;
1398 *aBuffer = '\0';
1400 chromeLocation = ++aBuffer;
1401 if (aBuffer >= bufferEnd)
1402 break;
1404 while (aBuffer < bufferEnd &&
1405 (*aBuffer != '\r' && *aBuffer != '\n' && *aBuffer != ' '))
1406 ++aBuffer;
1407 *aBuffer = '\0';
1409 // process the line
1410 // We don't do skin or locale selection from installed-chrome.txt since
1411 // ffox 0.9. Just ignore the "select" lines.
1412 if (strcmp(chromeLocType,"select")) {
1413 if (!strcmp(chromeLocType, "path")) {
1414 // location is a (full) path. convert it to an URL.
1416 /* this is some convoluted shit... this creates a file, inits it with
1417 * the path parsed above (chromeLocation), makes a url, and inits it
1418 * with the file created. the purpose of this is just to have the
1419 * canonical url of the stupid thing.
1421 nsCOMPtr<nsILocalFile> chromeFile;
1422 rv = NS_NewNativeLocalFile(nsDependentCString(chromeLocation),
1423 PR_TRUE, getter_AddRefs(chromeFile));
1424 NS_ENSURE_SUCCESS(rv, rv);
1427 * all we want here is the canonical url
1429 rv = NS_NewFileURI(getter_AddRefs(baseURI), chromeFile);
1430 if (NS_FAILED(rv)) return rv;
1432 else {
1433 rv = NS_NewURI(getter_AddRefs(baseURI), chromeLocation);
1434 if (NS_FAILED(rv)) return rv;
1437 ProcessContentsManifest(baseURI, aManifest, baseURI, PR_TRUE,
1438 strcmp(chromeType, "skin") == 0);
1441 while (aBuffer < bufferEnd && (*aBuffer == '\0' || *aBuffer == ' ' || *aBuffer == '\r' || *aBuffer == '\n'))
1442 ++aBuffer;
1445 return NS_OK;
1448 NS_IMETHODIMP nsChromeRegistry::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *someData)
1450 nsresult rv = NS_OK;
1452 if (!strcmp(NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, aTopic)) {
1453 nsCOMPtr<nsIPrefBranch> prefs (do_QueryInterface(aSubject));
1454 NS_ASSERTION(prefs, "Bad observer call!");
1456 NS_ConvertUTF16toUTF8 pref(someData);
1458 nsXPIDLCString provider;
1459 rv = prefs->GetCharPref(pref.get(), getter_Copies(provider));
1460 if (NS_FAILED(rv)) {
1461 NS_ERROR("Couldn't get new locale or skin pref!");
1462 return rv;
1465 if (pref.EqualsLiteral(SELECTED_SKIN_PREF)) {
1466 mSelectedSkin = provider;
1467 RefreshSkins();
1469 else if (pref.EqualsLiteral(SELECTED_LOCALE_PREF)) {
1470 mSelectedLocale = provider;
1471 FlushAllCaches();
1472 } else {
1473 NS_ERROR("Unexpected pref!");
1476 else if (!strcmp("command-line-startup", aTopic)) {
1477 nsCOMPtr<nsICommandLine> cmdLine (do_QueryInterface(aSubject));
1478 if (cmdLine) {
1479 nsAutoString uiLocale;
1480 rv = cmdLine->HandleFlagWithParam(NS_LITERAL_STRING(UILOCALE_CMD_LINE_ARG),
1481 PR_FALSE, uiLocale);
1482 if (NS_SUCCEEDED(rv) && !uiLocale.IsEmpty()) {
1483 CopyUTF16toUTF8(uiLocale, mSelectedLocale);
1484 nsCOMPtr<nsIPrefBranch2> prefs (do_GetService(NS_PREFSERVICE_CONTRACTID));
1485 if (prefs) {
1486 prefs->RemoveObserver(SELECTED_LOCALE_PREF, this);
1491 else {
1492 NS_ERROR("Unexpected observer topic!");
1495 return rv;
1498 #ifdef MOZ_XUL
1499 static nsresult
1500 GetContainerEnumerator(nsIRDFDataSource* ds, nsIRDFResource* res,
1501 nsISimpleEnumerator* *aResult, PRInt32 *aCountResult = nsnull)
1503 nsresult rv;
1505 nsCOMPtr<nsIRDFContainer> container
1506 (do_CreateInstance("@mozilla.org/rdf/container;1"));
1507 NS_ENSURE_TRUE(container, NS_ERROR_FAILURE);
1509 rv = container->Init(ds, res);
1510 if (NS_FAILED(rv)) return rv;
1512 if (aCountResult)
1513 container->GetCount(aCountResult);
1515 return container->GetElements(aResult);
1518 static void
1519 FollowLiteral(nsIRDFDataSource* ds, nsIRDFResource* res,
1520 nsIRDFResource* arc, nsACString& result)
1522 nsresult rv;
1524 nsCOMPtr<nsIRDFNode> node;
1525 rv = ds->GetTarget(res, arc, PR_TRUE, getter_AddRefs(node));
1526 if (NS_FAILED(rv) || !node) {
1527 result.Truncate();
1528 return;
1531 nsCOMPtr<nsIRDFLiteral> literal (do_QueryInterface(node));
1532 if (!literal) {
1533 NS_ERROR("Arc found, but doesn't point to expected literal!");
1534 result.Truncate();
1535 return;
1538 const PRUnichar* value;
1539 literal->GetValueConst(&value);
1540 CopyUTF16toUTF8(value, result);
1543 static void
1544 FollowResource(nsIRDFDataSource* ds, nsIRDFResource* res, nsIRDFResource* arc,
1545 nsIRDFResource* *result)
1547 nsresult rv;
1549 nsCOMPtr<nsIRDFNode> node;
1550 rv = ds->GetTarget(res, arc, PR_TRUE, getter_AddRefs(node));
1551 if (NS_FAILED(rv) || !node) {
1552 *result = nsnull;
1553 return;
1556 CallQueryInterface(node, result);
1559 static void
1560 GetRelativePath(nsIURI* base, nsIURI* relative, nsACString& result)
1562 nsresult rv;
1564 nsCOMPtr<nsIJARURI> jarrelative (do_QueryInterface(relative));
1565 if (jarrelative) {
1566 nsCOMPtr<nsIURI> jarbase;
1567 jarrelative->GetJARFile(getter_AddRefs(jarbase));
1569 nsCAutoString relativeBase;
1570 GetRelativePath(base, jarbase, relativeBase);
1572 nsCAutoString jarEntry;
1573 jarrelative->GetJAREntry(jarEntry);
1575 result.Assign(NS_LITERAL_CSTRING("jar:"));
1576 result.Append(relativeBase);
1577 result.Append(NS_LITERAL_CSTRING("!/"));
1578 result.Append(jarEntry);
1579 return;
1582 nsCOMPtr<nsIURL> baseURL (do_QueryInterface(base));
1583 if (!baseURL) {
1584 relative->GetSpec(result);
1585 return;
1588 rv = baseURL->GetRelativeSpec(relative, result);
1589 if (NS_FAILED(rv)) {
1590 relative->GetSpec(result);
1594 static const PRInt32 kNSPR_APPEND_FLAGS = PR_WRONLY | PR_CREATE_FILE | PR_APPEND;
1595 static const PRInt32 kNSPR_TRUNCATE_FLAGS = PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE;
1597 NS_IMETHODIMP
1598 nsChromeRegistry::ProcessContentsManifest(nsIURI* aOldManifest, nsIURI* aFile,
1599 nsIURI* aBaseURI, PRBool aAppend,
1600 PRBool aSkinOnly)
1602 nsresult rv;
1604 nsCAutoString relativePath;
1605 GetRelativePath(aFile, aBaseURI, relativePath);
1607 nsCAutoString spec;
1608 aOldManifest->GetSpec(spec);
1610 NS_ASSERTION(spec.Last() == '/', "installed-chrome manifest URI doesn't end in a slash! It probably won't work.");
1612 spec.AppendLiteral("contents.rdf");
1614 nsCOMPtr<nsIRDFService> rdfs (do_GetService("@mozilla.org/rdf/rdf-service;1"));
1615 NS_ENSURE_TRUE(rdfs, NS_ERROR_FAILURE);
1617 nsCOMPtr<nsIRDFResource> namearc, platformarc;
1618 rdfs->GetResource(NS_LITERAL_CSTRING(kURICHROME_name),
1619 getter_AddRefs(namearc));
1620 rdfs->GetResource(NS_LITERAL_CSTRING(kURICHROME_platformPackage),
1621 getter_AddRefs(platformarc));
1622 if (!(namearc && platformarc))
1623 return NS_ERROR_FAILURE;
1625 nsCOMPtr<nsIRDFDataSource> ds;
1626 rv = rdfs->GetDataSourceBlocking(spec.get(), getter_AddRefs(ds));
1627 if (NS_FAILED(rv)) {
1628 LogMessage("Failed to load old-style contents.rdf at '%s'.",
1629 spec.get());
1630 return rv;
1633 nsCOMPtr<nsIFileURL> fileURL (do_QueryInterface(aFile));
1634 NS_ENSURE_TRUE(fileURL, NS_ERROR_INVALID_ARG);
1636 nsCOMPtr<nsIFile> file;
1637 rv = fileURL->GetFile(getter_AddRefs(file));
1638 NS_ENSURE_SUCCESS(rv, rv);
1640 nsCOMPtr<nsILocalFile> lfile (do_QueryInterface(file));
1641 NS_ENSURE_TRUE(lfile, NS_ERROR_NO_INTERFACE);
1643 PRFileDesc* fd;
1644 rv = lfile->OpenNSPRFileDesc(aAppend ? kNSPR_APPEND_FLAGS : kNSPR_TRUNCATE_FLAGS,
1645 0664, &fd);
1646 NS_ENSURE_SUCCESS(rv, rv);
1648 if (aAppend)
1649 PR_Write(fd, "\n", 1);
1651 nsCOMPtr<nsIRDFResource> root;
1652 rv = rdfs->GetResource(NS_LITERAL_CSTRING("urn:mozilla:skin:root"),
1653 getter_AddRefs(root));
1654 if (NS_SUCCEEDED(rv))
1655 ProcessProvider(fd, rdfs, ds, root, PR_FALSE, relativePath);
1657 rv = rdfs->GetResource(NS_LITERAL_CSTRING("urn:mozilla:stylesheets"),
1658 getter_AddRefs(root));
1659 if (NS_SUCCEEDED(rv))
1660 ProcessOverlays(fd, ds, root, NS_LITERAL_CSTRING("style"));
1662 if (!aSkinOnly) {
1663 rv = rdfs->GetResource(NS_LITERAL_CSTRING("urn:mozilla:locale:root"),
1664 getter_AddRefs(root));
1665 if (NS_SUCCEEDED(rv))
1666 ProcessProvider(fd, rdfs, ds, root, PR_TRUE, relativePath);
1668 rv = rdfs->GetResource(NS_LITERAL_CSTRING("urn:mozilla:overlays"),
1669 getter_AddRefs(root));
1670 if (NS_SUCCEEDED(rv))
1671 ProcessOverlays(fd, ds, root, NS_LITERAL_CSTRING("overlay"));
1673 /* content packages are easier, but different */
1675 rv = rdfs->GetResource(NS_LITERAL_CSTRING("urn:mozilla:package:root"),
1676 getter_AddRefs(root));
1678 nsCOMPtr<nsISimpleEnumerator> packages;
1679 if (NS_SUCCEEDED(rv))
1680 rv = GetContainerEnumerator(ds, root, getter_AddRefs(packages));
1682 if (NS_SUCCEEDED(rv)) {
1683 PRBool more;
1684 nsCOMPtr<nsISupports> next;
1685 nsCOMPtr<nsIRDFResource> package;
1687 while (NS_SUCCEEDED(packages->HasMoreElements(&more)) && more) {
1688 packages->GetNext(getter_AddRefs(next));
1690 package = do_QueryInterface(next);
1691 if (!package) {
1692 NS_WARNING("Arc from urn:mozilla:package:root points to non-resource node.");
1693 continue;
1696 nsCAutoString name;
1697 FollowLiteral(ds, package, namearc, name);
1698 if (name.IsEmpty())
1699 continue;
1701 nsCAutoString isPlatform;
1702 FollowLiteral(ds, package, platformarc, isPlatform);
1703 name.Insert(NS_LITERAL_CSTRING("content\t"), 0);
1704 name.Append('\t');
1705 name.Append(relativePath);
1706 if (!isPlatform.IsEmpty())
1707 name.AppendLiteral("\tplatform");
1709 name.AppendLiteral(NS_LINEBREAK);
1710 PR_Write(fd, name.get(), name.Length());
1715 PR_Close(fd);
1717 return NS_OK;
1720 static void
1721 GetResourceName(nsIRDFResource* res, nsACString& result)
1723 // we need to get the provider name. Instead of doing something sane,
1724 // we munge the resource URI, looking from the right for colons.
1726 nsCAutoString providerURI;
1727 res->GetValueUTF8(providerURI);
1729 PRInt32 found = providerURI.RFindChar(':');
1730 if (found == kNotFound) {
1731 result.Truncate();
1732 return;
1735 result.Assign(Substring(providerURI, found + 1));
1739 void
1740 nsChromeRegistry::ProcessProvider(PRFileDesc *fd, nsIRDFService* aRDFs,
1741 nsIRDFDataSource* aDS, nsIRDFResource* aRoot,
1742 PRBool aIsLocale, const nsACString& aBaseURL)
1744 NS_NAMED_LITERAL_CSTRING(kSlash, "/");
1745 NS_NAMED_LITERAL_CSTRING(kTab, "\t");
1747 nsresult rv;
1749 nsCOMPtr<nsIRDFResource> packagesarc;
1750 aRDFs->GetResource(NS_LITERAL_CSTRING(kURICHROME_packages),
1751 getter_AddRefs(packagesarc));
1752 if (!packagesarc) return;
1754 nsCOMPtr<nsISimpleEnumerator> providers;
1755 rv = GetContainerEnumerator(aDS, aRoot, getter_AddRefs(providers));
1756 if (NS_FAILED(rv)) {
1757 return;
1760 nsCOMPtr<nsISupports> next;
1762 PRBool more;
1763 while (NS_SUCCEEDED(providers->HasMoreElements(&more)) && more) {
1764 providers->GetNext(getter_AddRefs(next));
1765 NS_ASSERTION(next, "GetNext failed after HasMoreElements succeeded.");
1767 nsCOMPtr<nsIRDFResource> provider (do_QueryInterface(next));
1768 if (!provider) {
1769 NS_WARNING("Provider isn't a nsIRDFResource.");
1770 continue;
1773 nsCAutoString providerName;
1774 GetResourceName(provider, providerName);
1775 if (providerName.IsEmpty()) {
1776 NS_WARNING("Couldn't calculate resource name.");
1777 continue;
1780 nsCOMPtr<nsIRDFResource> packages;
1781 FollowResource(aDS, provider, packagesarc, getter_AddRefs(packages));
1782 if (!packages) {
1783 NS_WARNING("No chrome:packages arc found!");
1784 continue;
1787 PRInt32 count;
1788 nsCOMPtr<nsISimpleEnumerator> packageList;
1789 rv = GetContainerEnumerator(aDS, packages, getter_AddRefs(packageList), &count);
1790 if (NS_FAILED(rv)) {
1791 NS_WARNING("chrome:packages was not a sequence.");
1792 continue;
1795 nsCOMPtr<nsISupports> nextPackage;
1797 PRBool morePackages;
1798 while (NS_SUCCEEDED(packageList->HasMoreElements(&morePackages)) &&
1799 morePackages) {
1800 packageList->GetNext(getter_AddRefs(nextPackage));
1802 nsCOMPtr<nsIRDFResource> packageRes (do_QueryInterface(nextPackage));
1803 if (!packageRes) {
1804 NS_WARNING("chrome:packages Seq points to a non-resource!");
1805 continue;
1808 nsCAutoString packageName;
1809 GetResourceName(packageRes, packageName);
1810 if (packageName.IsEmpty()) {
1811 NS_WARNING("couldn't extract a package name.");
1812 continue;
1815 nsCAutoString line;
1817 if (aIsLocale)
1818 line.AppendLiteral("locale\t");
1819 else
1820 line.AppendLiteral("skin\t");
1822 line += packageName + kTab + providerName + kTab + aBaseURL;
1823 if (count > 1) {
1824 line += packageName + kSlash;
1826 line.AppendLiteral(NS_LINEBREAK);
1827 PR_Write(fd, line.get(), line.Length());
1832 static void
1833 GetLiteralText(nsIRDFLiteral* lit, nsACString& result)
1835 const PRUnichar* value;
1836 lit->GetValueConst(&value);
1837 CopyUTF16toUTF8(value, result);
1840 void
1841 nsChromeRegistry::ProcessOverlays(PRFileDesc *fd, nsIRDFDataSource* aDS,
1842 nsIRDFResource* aRoot,
1843 const nsCSubstring& aType)
1845 NS_NAMED_LITERAL_CSTRING(kTab, "\t");
1846 NS_NAMED_LITERAL_CSTRING(kLinebreak, NS_LINEBREAK);
1848 nsresult rv;
1850 nsCOMPtr<nsISimpleEnumerator> overlaids;
1851 rv = GetContainerEnumerator(aDS, aRoot, getter_AddRefs(overlaids));
1852 if (NS_FAILED(rv)) {
1853 return;
1856 nsCOMPtr<nsISupports> next;
1857 PRBool more;
1858 while (NS_SUCCEEDED(overlaids->HasMoreElements(&more)) && more) {
1859 overlaids->GetNext(getter_AddRefs(next));
1860 NS_ASSERTION(next, "GetNext failed after HasMoreElements succeeded.");
1862 nsCOMPtr<nsIRDFResource> overlaid (do_QueryInterface(next));
1863 if (!overlaid) {
1864 NS_WARNING("Overlay arc is not a nsIRDFResource.");
1865 continue;
1868 nsCAutoString overlaidName;
1869 overlaid->GetValueUTF8(overlaidName);
1871 nsCOMPtr<nsISimpleEnumerator> overlays;
1872 rv = GetContainerEnumerator(aDS, overlaid, getter_AddRefs(overlays));
1873 if (NS_FAILED(rv))
1874 continue;
1876 while (NS_SUCCEEDED(overlays->HasMoreElements(&more)) && more) {
1877 overlays->GetNext(getter_AddRefs(next));
1878 NS_ASSERTION(next, "GetNext failed after HasMoreElements succeeded.");
1880 nsCOMPtr<nsIRDFLiteral> overlay (do_QueryInterface(next));
1881 if (!overlay) {
1882 NS_WARNING("Overlay was not an RDF literal.");
1883 continue;
1886 nsCAutoString overlayName;
1887 GetLiteralText(overlay, overlayName);
1889 overlayName.Insert(aType + kTab + overlaidName + kTab, 0);
1890 overlayName.Append(kLinebreak);
1891 PR_Write(fd, overlayName.get(), overlayName.Length());
1896 #else // MOZ_XUL
1898 NS_IMETHODIMP
1899 nsChromeRegistry::ProcessContentsManifest(nsIURI* aOldManifest, nsIURI* aFile,
1900 nsIURI* aBaseURI, PRBool aAppend,
1901 PRBool aSkinOnly)
1903 return NS_ERROR_NOT_IMPLEMENTED;
1906 #endif // MOZ_XUL
1908 nsresult
1909 nsChromeRegistry::ProcessManifest(nsILocalFile* aManifest, PRBool aSkinOnly)
1911 nsresult rv;
1913 PRFileDesc* fd;
1914 rv = aManifest->OpenNSPRFileDesc(PR_RDONLY, 0, &fd);
1915 NS_ENSURE_SUCCESS(rv, rv);
1917 PRInt32 n, size;
1918 char *buf;
1920 size = PR_Available(fd);
1921 if (size == -1) {
1922 rv = NS_ERROR_UNEXPECTED;
1923 goto mend;
1926 buf = (char *) malloc(size + 1);
1927 if (!buf) {
1928 rv = NS_ERROR_OUT_OF_MEMORY;
1929 goto mend;
1932 n = PR_Read(fd, buf, size);
1933 if (n > 0) {
1934 buf[size] = '\0';
1935 rv = ProcessManifestBuffer(buf, size, aManifest, aSkinOnly);
1937 free(buf);
1939 mend:
1940 PR_Close(fd);
1941 return rv;
1944 static const char kWhitespace[] = "\t ";
1945 static const char kNewlines[] = "\r\n";
1948 * Check for a modifier flag of the following forms:
1949 * "flag" (same as "true")
1950 * "flag=yes|true|1"
1951 * "flag="no|false|0"
1952 * @param aFlag The flag to compare.
1953 * @param aData The tokenized data to check; this is lowercased
1954 * before being passed in.
1955 * @param aResult If the flag is found, the value is assigned here.
1956 * @return Whether the flag was handled.
1958 static PRBool
1959 CheckFlag(const nsSubstring& aFlag, const nsSubstring& aData, PRBool& aResult)
1961 if (!StringBeginsWith(aData, aFlag))
1962 return PR_FALSE;
1964 if (aFlag.Length() == aData.Length()) {
1965 // the data is simply "flag", which is the same as "flag=yes"
1966 aResult = PR_TRUE;
1967 return PR_TRUE;
1970 if (aData.CharAt(aFlag.Length()) != '=') {
1971 // the data is "flag2=", which is not anything we care about
1972 return PR_FALSE;
1975 if (aData.Length() == aFlag.Length() + 1) {
1976 aResult = PR_FALSE;
1977 return PR_TRUE;
1980 switch (aData.CharAt(aFlag.Length() + 1)) {
1981 case '1':
1982 case 't': //true
1983 case 'y': //yes
1984 aResult = PR_TRUE;
1985 return PR_TRUE;
1987 case '0':
1988 case 'f': //false
1989 case 'n': //no
1990 aResult = PR_FALSE;
1991 return PR_TRUE;
1994 return PR_FALSE;
1997 enum TriState {
1998 eUnspecified,
1999 eBad,
2004 * Check for a modifier flag of the following form:
2005 * "flag=string"
2006 * "flag!=string"
2007 * @param aFlag The flag to compare.
2008 * @param aData The tokenized data to check; this is lowercased
2009 * before being passed in.
2010 * @param aValue The value that is expected.
2011 * @param aResult If this is "ok" when passed in, this is left alone.
2012 * Otherwise if the flag is found it is set to eBad or eOK.
2013 * @return Whether the flag was handled.
2015 static PRBool
2016 CheckStringFlag(const nsSubstring& aFlag, const nsSubstring& aData,
2017 const nsSubstring& aValue, TriState& aResult)
2019 if (aData.Length() < aFlag.Length() + 1)
2020 return PR_FALSE;
2022 if (!StringBeginsWith(aData, aFlag))
2023 return PR_FALSE;
2025 PRBool comparison = PR_TRUE;
2026 if (aData[aFlag.Length()] != '=') {
2027 if (aData[aFlag.Length()] == '!' &&
2028 aData.Length() >= aFlag.Length() + 2 &&
2029 aData[aFlag.Length() + 1] == '=')
2030 comparison = PR_FALSE;
2031 else
2032 return PR_FALSE;
2035 if (aResult != eOK) {
2036 nsDependentSubstring testdata = Substring(aData, aFlag.Length() + (comparison ? 1 : 2));
2037 if (testdata.Equals(aValue))
2038 aResult = comparison ? eOK : eBad;
2039 else
2040 aResult = comparison ? eBad : eOK;
2043 return PR_TRUE;
2047 * Check for a modifier flag of the following form:
2048 * "flag=version"
2049 * "flag<=version"
2050 * "flag<version"
2051 * "flag>=version"
2052 * "flag>version"
2053 * @param aFlag The flag to compare.
2054 * @param aData The tokenized data to check; this is lowercased
2055 * before being passed in.
2056 * @param aValue The value that is expected. If this is empty then no
2057 * comparison will match.
2058 * @param aChecker the version checker to use. If null, aResult will always
2059 * be eBad.
2060 * @param aResult If this is eOK when passed in, this is left alone.
2061 * Otherwise if the flag is found it is set to eBad or eOK.
2062 * @return Whether the flag was handled.
2065 #define COMPARE_EQ 1 << 0
2066 #define COMPARE_LT 1 << 1
2067 #define COMPARE_GT 1 << 2
2069 static PRBool
2070 CheckVersionFlag(const nsSubstring& aFlag, const nsSubstring& aData,
2071 const nsSubstring& aValue, nsIVersionComparator* aChecker,
2072 TriState& aResult)
2074 if (aData.Length() < aFlag.Length() + 2)
2075 return PR_FALSE;
2077 if (!StringBeginsWith(aData, aFlag))
2078 return PR_FALSE;
2080 if (aValue.Length() == 0) {
2081 if (aResult != eOK)
2082 aResult = eBad;
2083 return PR_TRUE;
2086 PRUint32 comparison;
2087 nsAutoString testdata;
2089 switch (aData[aFlag.Length()]) {
2090 case '=':
2091 comparison = COMPARE_EQ;
2092 testdata = Substring(aData, aFlag.Length() + 1);
2093 break;
2095 case '<':
2096 if (aData[aFlag.Length() + 1] == '=') {
2097 comparison = COMPARE_EQ | COMPARE_LT;
2098 testdata = Substring(aData, aFlag.Length() + 2);
2100 else {
2101 comparison = COMPARE_LT;
2102 testdata = Substring(aData, aFlag.Length() + 1);
2104 break;
2106 case '>':
2107 if (aData[aFlag.Length() + 1] == '=') {
2108 comparison = COMPARE_EQ | COMPARE_GT;
2109 testdata = Substring(aData, aFlag.Length() + 2);
2111 else {
2112 comparison = COMPARE_GT;
2113 testdata = Substring(aData, aFlag.Length() + 1);
2115 break;
2117 default:
2118 return PR_FALSE;
2121 if (testdata.Length() == 0)
2122 return PR_FALSE;
2124 if (aResult != eOK) {
2125 if (!aChecker) {
2126 aResult = eBad;
2128 else {
2129 PRInt32 c;
2130 nsresult rv = aChecker->Compare(NS_ConvertUTF16toUTF8(aValue),
2131 NS_ConvertUTF16toUTF8(testdata), &c);
2132 if (NS_FAILED(rv)) {
2133 aResult = eBad;
2135 else {
2136 if ((c == 0 && comparison & COMPARE_EQ) ||
2137 (c < 0 && comparison & COMPARE_LT) ||
2138 (c > 0 && comparison & COMPARE_GT))
2139 aResult = eOK;
2140 else
2141 aResult = eBad;
2146 return PR_TRUE;
2149 static void
2150 EnsureLowerCase(char *aBuf)
2152 for (; *aBuf; ++aBuf) {
2153 char ch = *aBuf;
2154 if (ch >= 'A' && ch <= 'Z')
2155 *aBuf = ch + 'a' - 'A';
2159 nsresult
2160 nsChromeRegistry::ProcessManifestBuffer(char *buf, PRInt32 length,
2161 nsILocalFile* aManifest,
2162 PRBool aSkinOnly)
2164 nsresult rv;
2166 NS_NAMED_LITERAL_STRING(kPlatform, "platform");
2167 NS_NAMED_LITERAL_STRING(kXPCNativeWrappers, "xpcnativewrappers");
2168 NS_NAMED_LITERAL_STRING(kContentAccessible, "contentaccessible");
2169 NS_NAMED_LITERAL_STRING(kApplication, "application");
2170 NS_NAMED_LITERAL_STRING(kAppVersion, "appversion");
2171 NS_NAMED_LITERAL_STRING(kOs, "os");
2172 NS_NAMED_LITERAL_STRING(kOsVersion, "osversion");
2174 nsCOMPtr<nsIIOService> io (do_GetIOService());
2175 if (!io) return NS_ERROR_FAILURE;
2177 nsCOMPtr<nsIProtocolHandler> ph;
2178 rv = io->GetProtocolHandler("resource", getter_AddRefs(ph));
2179 NS_ENSURE_SUCCESS(rv, rv);
2181 nsCOMPtr<nsIResProtocolHandler> rph (do_QueryInterface(ph));
2182 if (!rph) return NS_ERROR_FAILURE;
2184 nsCOMPtr<nsIURI> manifestURI;
2185 rv = io->NewFileURI(aManifest, getter_AddRefs(manifestURI));
2186 NS_ENSURE_SUCCESS(rv, rv);
2188 nsCOMPtr<nsIXPConnect> xpc (do_GetService("@mozilla.org/js/xpc/XPConnect;1"));
2189 nsCOMPtr<nsIVersionComparator> vc (do_GetService("@mozilla.org/xpcom/version-comparator;1"));
2191 nsAutoString appID;
2192 nsAutoString appVersion;
2193 nsAutoString osTarget;
2194 nsCOMPtr<nsIXULAppInfo> xapp (do_GetService(XULAPPINFO_SERVICE_CONTRACTID));
2195 if (xapp) {
2196 nsCAutoString s;
2197 rv = xapp->GetID(s);
2198 if (NS_SUCCEEDED(rv))
2199 CopyUTF8toUTF16(s, appID);
2201 rv = xapp->GetVersion(s);
2202 if (NS_SUCCEEDED(rv))
2203 CopyUTF8toUTF16(s, appVersion);
2205 nsCOMPtr<nsIXULRuntime> xruntime (do_QueryInterface(xapp));
2206 if (xruntime) {
2207 rv = xruntime->GetOS(s);
2208 if (NS_SUCCEEDED(rv)) {
2209 CopyUTF8toUTF16(s, osTarget);
2210 ToLowerCase(osTarget);
2215 nsAutoString osVersion;
2216 #if defined(XP_WIN)
2217 OSVERSIONINFO info = { sizeof(OSVERSIONINFO) };
2218 if (GetVersionEx(&info)) {
2219 nsTextFormatter::ssprintf(osVersion, NS_LITERAL_STRING("%ld.%ld").get(),
2220 info.dwMajorVersion,
2221 info.dwMinorVersion);
2223 #elif defined(XP_MACOSX)
2224 long majorVersion, minorVersion;
2225 if ((Gestalt(gestaltSystemVersionMajor, &majorVersion) == noErr) &&
2226 (Gestalt(gestaltSystemVersionMinor, &minorVersion) == noErr)) {
2227 nsTextFormatter::ssprintf(osVersion, NS_LITERAL_STRING("%ld.%ld").get(),
2228 majorVersion,
2229 minorVersion);
2231 #elif defined(MOZ_WIDGET_GTK2)
2232 nsTextFormatter::ssprintf(osVersion, NS_LITERAL_STRING("%ld.%ld").get(),
2233 gtk_major_version,
2234 gtk_minor_version);
2235 #endif
2237 char *token;
2238 char *newline = buf;
2239 PRUint32 line = 0;
2241 // outer loop tokenizes by newline
2242 while (nsnull != (token = nsCRT::strtok(newline, kNewlines, &newline))) {
2243 ++line;
2245 if (*token == '#') // ignore lines that begin with # as comments
2246 continue;
2248 char *whitespace = token;
2249 token = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2250 if (!token) continue;
2252 if (!strcmp(token, "content")) {
2253 if (aSkinOnly) {
2254 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2255 "Warning: Ignoring content registration in skin-only manifest.");
2256 continue;
2258 char *package = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2259 char *uri = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2260 if (!package || !uri) {
2261 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2262 "Warning: Malformed content registration.");
2263 continue;
2266 EnsureLowerCase(package);
2268 // NOTE: We check for platform and xpcnativewrappers modifiers on
2269 // content packages, but they are *applied* to content|skin|locale.
2271 PRBool platform = PR_FALSE;
2272 PRBool xpcNativeWrappers = PR_TRUE;
2273 PRBool contentAccessible = PR_FALSE;
2274 TriState stAppVersion = eUnspecified;
2275 TriState stApp = eUnspecified;
2276 TriState stOsVersion = eUnspecified;
2277 TriState stOs = eUnspecified;
2279 PRBool badFlag = PR_FALSE;
2281 while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
2282 !badFlag) {
2283 NS_ConvertASCIItoUTF16 wtoken(token);
2284 ToLowerCase(wtoken);
2286 if (CheckFlag(kPlatform, wtoken, platform) ||
2287 CheckFlag(kXPCNativeWrappers, wtoken, xpcNativeWrappers) ||
2288 CheckFlag(kContentAccessible, wtoken, contentAccessible) ||
2289 CheckStringFlag(kApplication, wtoken, appID, stApp) ||
2290 CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
2291 CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
2292 CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
2293 continue;
2295 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2296 "Warning: Unrecognized chrome registration modifier '%s'.",
2297 token);
2298 badFlag = PR_TRUE;
2301 if (badFlag || stApp == eBad || stAppVersion == eBad ||
2302 stOs == eBad || stOsVersion == eBad)
2303 continue;
2305 nsCOMPtr<nsIURI> resolved;
2306 rv = io->NewURI(nsDependentCString(uri), nsnull, manifestURI,
2307 getter_AddRefs(resolved));
2308 if (NS_FAILED(rv))
2309 continue;
2311 PackageEntry* entry =
2312 static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
2313 & (const nsACString&) nsDependentCString(package),
2314 PL_DHASH_ADD));
2315 if (!entry)
2316 return NS_ERROR_OUT_OF_MEMORY;
2318 entry->baseURI = resolved;
2320 if (platform)
2321 entry->flags |= PackageEntry::PLATFORM_PACKAGE;
2322 if (xpcNativeWrappers)
2323 entry->flags |= PackageEntry::XPCNATIVEWRAPPERS;
2324 if (contentAccessible)
2325 entry->flags |= PackageEntry::CONTENT_ACCESSIBLE;
2326 if (xpc) {
2327 nsCAutoString urlp("chrome://");
2328 urlp.Append(package);
2329 urlp.Append('/');
2331 rv = xpc->FlagSystemFilenamePrefix(urlp.get(), xpcNativeWrappers);
2332 NS_ENSURE_SUCCESS(rv, rv);
2335 else if (!strcmp(token, "locale")) {
2336 if (aSkinOnly) {
2337 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2338 "Warning: Ignoring locale registration in skin-only manifest.");
2339 continue;
2341 char *package = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2342 char *provider = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2343 char *uri = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2344 if (!package || !provider || !uri) {
2345 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2346 "Warning: Malformed locale registration.");
2347 continue;
2350 EnsureLowerCase(package);
2352 TriState stAppVersion = eUnspecified;
2353 TriState stApp = eUnspecified;
2354 TriState stOs = eUnspecified;
2355 TriState stOsVersion = eUnspecified;
2357 PRBool badFlag = PR_FALSE;
2359 while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
2360 !badFlag) {
2361 NS_ConvertASCIItoUTF16 wtoken(token);
2362 ToLowerCase(wtoken);
2364 if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
2365 CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
2366 CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
2367 CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
2368 continue;
2370 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2371 "Warning: Unrecognized chrome registration modifier '%s'.",
2372 token);
2373 badFlag = PR_TRUE;
2376 if (badFlag || stApp == eBad || stAppVersion == eBad ||
2377 stOs == eBad || stOsVersion == eBad)
2378 continue;
2380 nsCOMPtr<nsIURI> resolved;
2381 rv = io->NewURI(nsDependentCString(uri), nsnull, manifestURI,
2382 getter_AddRefs(resolved));
2383 if (NS_FAILED(rv))
2384 continue;
2386 PackageEntry* entry =
2387 static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
2388 & (const nsACString&) nsDependentCString(package),
2389 PL_DHASH_ADD));
2390 if (!entry)
2391 return NS_ERROR_OUT_OF_MEMORY;
2393 entry->locales.SetBase(nsDependentCString(provider), resolved);
2395 else if (!strcmp(token, "skin")) {
2396 char *package = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2397 char *provider = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2398 char *uri = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2399 if (!package || !provider || !uri) {
2400 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2401 "Warning: Malformed skin registration.");
2402 continue;
2405 EnsureLowerCase(package);
2407 TriState stAppVersion = eUnspecified;
2408 TriState stApp = eUnspecified;
2409 TriState stOs = eUnspecified;
2410 TriState stOsVersion = eUnspecified;
2412 PRBool badFlag = PR_FALSE;
2414 while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
2415 !badFlag) {
2416 NS_ConvertASCIItoUTF16 wtoken(token);
2417 ToLowerCase(wtoken);
2419 if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
2420 CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
2421 CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
2422 CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
2423 continue;
2425 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2426 "Warning: Unrecognized chrome registration modifier '%s'.",
2427 token);
2428 badFlag = PR_TRUE;
2431 if (badFlag || stApp == eBad || stAppVersion == eBad ||
2432 stOs == eBad || stOsVersion == eBad)
2433 continue;
2435 nsCOMPtr<nsIURI> resolved;
2436 rv = io->NewURI(nsDependentCString(uri), nsnull, manifestURI,
2437 getter_AddRefs(resolved));
2438 if (NS_FAILED(rv))
2439 continue;
2441 PackageEntry* entry =
2442 static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
2443 & (const nsACString&) nsDependentCString(package),
2444 PL_DHASH_ADD));
2445 if (!entry)
2446 return NS_ERROR_OUT_OF_MEMORY;
2448 entry->skins.SetBase(nsDependentCString(provider), resolved);
2450 else if (!strcmp(token, "overlay")) {
2451 if (aSkinOnly) {
2452 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2453 "Warning: Ignoring overlay registration in skin-only manifest.");
2454 continue;
2456 char *base = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2457 char *overlay = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2458 if (!base || !overlay) {
2459 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2460 "Warning: malformed chrome overlay instruction.");
2461 continue;
2464 TriState stAppVersion = eUnspecified;
2465 TriState stApp = eUnspecified;
2466 TriState stOs = eUnspecified;
2467 TriState stOsVersion = eUnspecified;
2469 PRBool badFlag = PR_FALSE;
2471 while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
2472 !badFlag) {
2473 NS_ConvertASCIItoUTF16 wtoken(token);
2474 ToLowerCase(wtoken);
2476 if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
2477 CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
2478 CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
2479 CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
2480 continue;
2482 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2483 "Warning: Unrecognized chrome registration modifier '%s'.",
2484 token);
2485 badFlag = PR_TRUE;
2488 if (badFlag || stApp == eBad || stAppVersion == eBad ||
2489 stOs == eBad || stOsVersion == eBad)
2490 continue;
2492 nsCOMPtr<nsIURI> baseuri, overlayuri;
2493 rv = io->NewURI(nsDependentCString(base), nsnull, nsnull,
2494 getter_AddRefs(baseuri));
2495 rv |= io->NewURI(nsDependentCString(overlay), nsnull, nsnull,
2496 getter_AddRefs(overlayuri));
2497 if (NS_FAILED(rv)) {
2498 NS_WARNING("Could not make URIs for overlay directive. Ignoring.");
2499 continue;
2502 mOverlayHash.Add(baseuri, overlayuri);
2504 else if (!strcmp(token, "style")) {
2505 char *base = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2506 char *overlay = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2507 if (!base || !overlay) {
2508 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2509 "Warning: malformed chrome style instruction.");
2510 continue;
2513 TriState stAppVersion = eUnspecified;
2514 TriState stApp = eUnspecified;
2515 TriState stOs = eUnspecified;
2516 TriState stOsVersion = eUnspecified;
2518 PRBool badFlag = PR_FALSE;
2520 while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
2521 !badFlag) {
2522 NS_ConvertASCIItoUTF16 wtoken(token);
2523 ToLowerCase(wtoken);
2525 if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
2526 CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
2527 CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
2528 CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
2529 continue;
2531 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2532 "Warning: Unrecognized chrome registration modifier '%s'.",
2533 token);
2534 badFlag = PR_TRUE;
2537 if (badFlag || stApp == eBad || stAppVersion == eBad ||
2538 stOs == eBad || stOsVersion == eBad)
2539 continue;
2541 nsCOMPtr<nsIURI> baseuri, overlayuri;
2542 rv = io->NewURI(nsDependentCString(base), nsnull, nsnull,
2543 getter_AddRefs(baseuri));
2544 rv |= io->NewURI(nsDependentCString(overlay), nsnull, nsnull,
2545 getter_AddRefs(overlayuri));
2546 if (NS_FAILED(rv))
2547 continue;
2549 mStyleHash.Add(baseuri, overlayuri);
2551 else if (!strcmp(token, "override")) {
2552 if (aSkinOnly) {
2553 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2554 "Warning: Ignoring override registration in skin-only manifest.");
2555 continue;
2558 char *chrome = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2559 char *resolved = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2560 if (!chrome || !resolved) {
2561 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2562 "Warning: malformed chrome override instruction.");
2563 continue;
2566 TriState stAppVersion = eUnspecified;
2567 TriState stApp = eUnspecified;
2568 TriState stOs = eUnspecified;
2569 TriState stOsVersion = eUnspecified;
2571 PRBool badFlag = PR_FALSE;
2573 while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
2574 !badFlag) {
2575 NS_ConvertASCIItoUTF16 wtoken(token);
2576 ToLowerCase(wtoken);
2578 if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
2579 CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
2580 CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
2581 CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
2582 continue;
2584 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2585 "Warning: Unrecognized chrome registration modifier '%s'.",
2586 token);
2587 badFlag = PR_TRUE;
2590 if (badFlag || stApp == eBad || stAppVersion == eBad ||
2591 stOs == eBad || stOsVersion == eBad)
2592 continue;
2594 nsCOMPtr<nsIURI> chromeuri, resolveduri;
2595 rv = io->NewURI(nsDependentCString(chrome), nsnull, nsnull,
2596 getter_AddRefs(chromeuri));
2597 rv |= io->NewURI(nsDependentCString(resolved), nsnull, manifestURI,
2598 getter_AddRefs(resolveduri));
2599 if (NS_FAILED(rv))
2600 continue;
2602 mOverrideTable.Put(chromeuri, resolveduri);
2604 else if (!strcmp(token, "resource")) {
2605 if (aSkinOnly) {
2606 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2607 "Warning: Ignoring resource registration in skin-only manifest.");
2608 continue;
2611 char *package = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2612 char *uri = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2613 if (!package || !uri) {
2614 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2615 "Warning: Malformed resource registration.");
2616 continue;
2619 EnsureLowerCase(package);
2621 TriState stAppVersion = eUnspecified;
2622 TriState stApp = eUnspecified;
2623 TriState stOsVersion = eUnspecified;
2624 TriState stOs = eUnspecified;
2626 PRBool badFlag = PR_FALSE;
2628 while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
2629 !badFlag) {
2630 NS_ConvertASCIItoUTF16 wtoken(token);
2631 ToLowerCase(wtoken);
2633 if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
2634 CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
2635 CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
2636 CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
2637 continue;
2639 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2640 "Warning: Unrecognized chrome registration modifier '%s'.",
2641 token);
2642 badFlag = PR_TRUE;
2645 if (badFlag || stApp == eBad || stAppVersion == eBad ||
2646 stOs == eBad || stOsVersion == eBad)
2647 continue;
2649 nsDependentCString host(package);
2651 PRBool exists;
2652 rv = rph->HasSubstitution(host, &exists);
2653 NS_ENSURE_SUCCESS(rv, rv);
2654 if (exists) {
2655 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2656 "Warning: Duplicate resource declaration for '%s' ignored.",
2657 package);
2658 continue;
2661 nsCOMPtr<nsIURI> resolved;
2662 rv = io->NewURI(nsDependentCString(uri), nsnull, manifestURI,
2663 getter_AddRefs(resolved));
2664 if (NS_FAILED(rv))
2665 continue;
2667 rv = rph->SetSubstitution(host, resolved);
2668 NS_ENSURE_SUCCESS(rv, rv);
2670 else {
2671 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2672 "Warning: Ignoring unrecognized chrome manifest instruction.");
2676 return NS_OK;