Follow-on fix for bug 457825. Use sheet principal for agent and user sheets. r=dbaron...
[wine-gecko.git] / chrome / src / nsChromeRegistry.cpp
blob64eb6e5e3806122984078c0c404aa92edab31fe6
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 NS_IMETHODIMP_(PRBool)
1330 nsChromeRegistry::WrappersEnabled(nsIURI *aURI)
1332 nsCOMPtr<nsIURL> chromeURL (do_QueryInterface(aURI));
1333 if (!chromeURL)
1334 return PR_FALSE;
1336 PRBool isChrome = PR_FALSE;
1337 nsresult rv = chromeURL->SchemeIs("chrome", &isChrome);
1338 if (NS_FAILED(rv) || !isChrome)
1339 return PR_FALSE;
1341 nsCAutoString package;
1342 rv = chromeURL->GetHostPort(package);
1343 if (NS_FAILED(rv))
1344 return PR_FALSE;
1346 PackageEntry* entry =
1347 static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
1348 & (nsACString&) package,
1349 PL_DHASH_LOOKUP));
1351 return PL_DHASH_ENTRY_IS_LIVE(entry) &&
1352 entry->flags & PackageEntry::XPCNATIVEWRAPPERS;
1355 nsresult
1356 nsChromeRegistry::ProcessNewChromeFile(nsILocalFile *aListFile, nsIURI* aManifest)
1358 nsresult rv;
1360 PRFileDesc *file;
1361 rv = aListFile->OpenNSPRFileDesc(PR_RDONLY, 0, &file);
1362 NS_ENSURE_SUCCESS(rv, rv);
1364 PRInt32 n, size;
1365 char *buf;
1367 size = PR_Available(file);
1368 if (size == -1) {
1369 rv = NS_ERROR_UNEXPECTED;
1370 goto end;
1373 buf = (char *) malloc(size + 1);
1374 if (!buf) {
1375 rv = NS_ERROR_OUT_OF_MEMORY;
1376 goto end;
1379 n = PR_Read(file, buf, size);
1380 if (n > 0)
1381 rv = ProcessNewChromeBuffer(buf, size, aManifest);
1382 free(buf);
1384 end:
1385 PR_Close(file);
1386 return rv;
1389 nsresult
1390 nsChromeRegistry::ProcessNewChromeBuffer(char *aBuffer, PRInt32 aLength,
1391 nsIURI* aManifest)
1393 nsresult rv = NS_OK;
1394 char *bufferEnd = aBuffer + aLength;
1395 char *chromeType, // "content", "locale" or "skin"
1396 *chromeProfile, // "install" or "profile"
1397 *chromeLocType, // type of location (local path or URL)
1398 *chromeLocation; // base location of chrome (jar file)
1400 nsCOMPtr<nsIURI> baseURI;
1402 // process chromeType, chromeProfile, chromeLocType, chromeLocation
1403 while (aBuffer < bufferEnd) {
1404 // parse one line of installed-chrome.txt
1405 chromeType = aBuffer;
1406 while (aBuffer < bufferEnd && *aBuffer != ',')
1407 ++aBuffer;
1408 *aBuffer = '\0';
1410 chromeProfile = ++aBuffer;
1411 if (aBuffer >= bufferEnd)
1412 break;
1414 while (aBuffer < bufferEnd && *aBuffer != ',')
1415 ++aBuffer;
1416 *aBuffer = '\0';
1418 chromeLocType = ++aBuffer;
1419 if (aBuffer >= bufferEnd)
1420 break;
1422 while (aBuffer < bufferEnd && *aBuffer != ',')
1423 ++aBuffer;
1424 *aBuffer = '\0';
1426 chromeLocation = ++aBuffer;
1427 if (aBuffer >= bufferEnd)
1428 break;
1430 while (aBuffer < bufferEnd &&
1431 (*aBuffer != '\r' && *aBuffer != '\n' && *aBuffer != ' '))
1432 ++aBuffer;
1433 *aBuffer = '\0';
1435 // process the line
1436 // We don't do skin or locale selection from installed-chrome.txt since
1437 // ffox 0.9. Just ignore the "select" lines.
1438 if (strcmp(chromeLocType,"select")) {
1439 if (!strcmp(chromeLocType, "path")) {
1440 // location is a (full) path. convert it to an URL.
1442 /* this is some convoluted shit... this creates a file, inits it with
1443 * the path parsed above (chromeLocation), makes a url, and inits it
1444 * with the file created. the purpose of this is just to have the
1445 * canonical url of the stupid thing.
1447 nsCOMPtr<nsILocalFile> chromeFile;
1448 rv = NS_NewNativeLocalFile(nsDependentCString(chromeLocation),
1449 PR_TRUE, getter_AddRefs(chromeFile));
1450 NS_ENSURE_SUCCESS(rv, rv);
1453 * all we want here is the canonical url
1455 rv = NS_NewFileURI(getter_AddRefs(baseURI), chromeFile);
1456 if (NS_FAILED(rv)) return rv;
1458 else {
1459 rv = NS_NewURI(getter_AddRefs(baseURI), chromeLocation);
1460 if (NS_FAILED(rv)) return rv;
1463 ProcessContentsManifest(baseURI, aManifest, baseURI, PR_TRUE,
1464 strcmp(chromeType, "skin") == 0);
1467 while (aBuffer < bufferEnd && (*aBuffer == '\0' || *aBuffer == ' ' || *aBuffer == '\r' || *aBuffer == '\n'))
1468 ++aBuffer;
1471 return NS_OK;
1474 NS_IMETHODIMP nsChromeRegistry::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *someData)
1476 nsresult rv = NS_OK;
1478 if (!strcmp(NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, aTopic)) {
1479 nsCOMPtr<nsIPrefBranch> prefs (do_QueryInterface(aSubject));
1480 NS_ASSERTION(prefs, "Bad observer call!");
1482 NS_ConvertUTF16toUTF8 pref(someData);
1484 nsXPIDLCString provider;
1485 rv = prefs->GetCharPref(pref.get(), getter_Copies(provider));
1486 if (NS_FAILED(rv)) {
1487 NS_ERROR("Couldn't get new locale or skin pref!");
1488 return rv;
1491 if (pref.EqualsLiteral(SELECTED_SKIN_PREF)) {
1492 mSelectedSkin = provider;
1493 RefreshSkins();
1495 else if (pref.EqualsLiteral(SELECTED_LOCALE_PREF)) {
1496 mSelectedLocale = provider;
1497 FlushAllCaches();
1498 } else {
1499 NS_ERROR("Unexpected pref!");
1502 else if (!strcmp("command-line-startup", aTopic)) {
1503 nsCOMPtr<nsICommandLine> cmdLine (do_QueryInterface(aSubject));
1504 if (cmdLine) {
1505 nsAutoString uiLocale;
1506 rv = cmdLine->HandleFlagWithParam(NS_LITERAL_STRING(UILOCALE_CMD_LINE_ARG),
1507 PR_FALSE, uiLocale);
1508 if (NS_SUCCEEDED(rv) && !uiLocale.IsEmpty()) {
1509 CopyUTF16toUTF8(uiLocale, mSelectedLocale);
1510 nsCOMPtr<nsIPrefBranch2> prefs (do_GetService(NS_PREFSERVICE_CONTRACTID));
1511 if (prefs) {
1512 prefs->RemoveObserver(SELECTED_LOCALE_PREF, this);
1517 else {
1518 NS_ERROR("Unexpected observer topic!");
1521 return rv;
1524 #ifdef MOZ_XUL
1525 static nsresult
1526 GetContainerEnumerator(nsIRDFDataSource* ds, nsIRDFResource* res,
1527 nsISimpleEnumerator* *aResult, PRInt32 *aCountResult = nsnull)
1529 nsresult rv;
1531 nsCOMPtr<nsIRDFContainer> container
1532 (do_CreateInstance("@mozilla.org/rdf/container;1"));
1533 NS_ENSURE_TRUE(container, NS_ERROR_FAILURE);
1535 rv = container->Init(ds, res);
1536 if (NS_FAILED(rv)) return rv;
1538 if (aCountResult)
1539 container->GetCount(aCountResult);
1541 return container->GetElements(aResult);
1544 static void
1545 FollowLiteral(nsIRDFDataSource* ds, nsIRDFResource* res,
1546 nsIRDFResource* arc, nsACString& result)
1548 nsresult rv;
1550 nsCOMPtr<nsIRDFNode> node;
1551 rv = ds->GetTarget(res, arc, PR_TRUE, getter_AddRefs(node));
1552 if (NS_FAILED(rv) || !node) {
1553 result.Truncate();
1554 return;
1557 nsCOMPtr<nsIRDFLiteral> literal (do_QueryInterface(node));
1558 if (!literal) {
1559 NS_ERROR("Arc found, but doesn't point to expected literal!");
1560 result.Truncate();
1561 return;
1564 const PRUnichar* value;
1565 literal->GetValueConst(&value);
1566 CopyUTF16toUTF8(value, result);
1569 static void
1570 FollowResource(nsIRDFDataSource* ds, nsIRDFResource* res, nsIRDFResource* arc,
1571 nsIRDFResource* *result)
1573 nsresult rv;
1575 nsCOMPtr<nsIRDFNode> node;
1576 rv = ds->GetTarget(res, arc, PR_TRUE, getter_AddRefs(node));
1577 if (NS_FAILED(rv) || !node) {
1578 *result = nsnull;
1579 return;
1582 CallQueryInterface(node, result);
1585 static void
1586 GetRelativePath(nsIURI* base, nsIURI* relative, nsACString& result)
1588 nsresult rv;
1590 nsCOMPtr<nsIJARURI> jarrelative (do_QueryInterface(relative));
1591 if (jarrelative) {
1592 nsCOMPtr<nsIURI> jarbase;
1593 jarrelative->GetJARFile(getter_AddRefs(jarbase));
1595 nsCAutoString relativeBase;
1596 GetRelativePath(base, jarbase, relativeBase);
1598 nsCAutoString jarEntry;
1599 jarrelative->GetJAREntry(jarEntry);
1601 result.Assign(NS_LITERAL_CSTRING("jar:"));
1602 result.Append(relativeBase);
1603 result.Append(NS_LITERAL_CSTRING("!/"));
1604 result.Append(jarEntry);
1605 return;
1608 nsCOMPtr<nsIURL> baseURL (do_QueryInterface(base));
1609 if (!baseURL) {
1610 relative->GetSpec(result);
1611 return;
1614 rv = baseURL->GetRelativeSpec(relative, result);
1615 if (NS_FAILED(rv)) {
1616 relative->GetSpec(result);
1620 static const PRInt32 kNSPR_APPEND_FLAGS = PR_WRONLY | PR_CREATE_FILE | PR_APPEND;
1621 static const PRInt32 kNSPR_TRUNCATE_FLAGS = PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE;
1623 NS_IMETHODIMP
1624 nsChromeRegistry::ProcessContentsManifest(nsIURI* aOldManifest, nsIURI* aFile,
1625 nsIURI* aBaseURI, PRBool aAppend,
1626 PRBool aSkinOnly)
1628 nsresult rv;
1630 nsCAutoString relativePath;
1631 GetRelativePath(aFile, aBaseURI, relativePath);
1633 nsCAutoString spec;
1634 aOldManifest->GetSpec(spec);
1636 NS_ASSERTION(spec.Last() == '/', "installed-chrome manifest URI doesn't end in a slash! It probably won't work.");
1638 spec.AppendLiteral("contents.rdf");
1640 nsCOMPtr<nsIRDFService> rdfs (do_GetService("@mozilla.org/rdf/rdf-service;1"));
1641 NS_ENSURE_TRUE(rdfs, NS_ERROR_FAILURE);
1643 nsCOMPtr<nsIRDFResource> namearc, platformarc;
1644 rdfs->GetResource(NS_LITERAL_CSTRING(kURICHROME_name),
1645 getter_AddRefs(namearc));
1646 rdfs->GetResource(NS_LITERAL_CSTRING(kURICHROME_platformPackage),
1647 getter_AddRefs(platformarc));
1648 if (!(namearc && platformarc))
1649 return NS_ERROR_FAILURE;
1651 nsCOMPtr<nsIRDFDataSource> ds;
1652 rv = rdfs->GetDataSourceBlocking(spec.get(), getter_AddRefs(ds));
1653 if (NS_FAILED(rv)) {
1654 LogMessage("Failed to load old-style contents.rdf at '%s'.",
1655 spec.get());
1656 return rv;
1659 nsCOMPtr<nsIFileURL> fileURL (do_QueryInterface(aFile));
1660 NS_ENSURE_TRUE(fileURL, NS_ERROR_INVALID_ARG);
1662 nsCOMPtr<nsIFile> file;
1663 rv = fileURL->GetFile(getter_AddRefs(file));
1664 NS_ENSURE_SUCCESS(rv, rv);
1666 nsCOMPtr<nsILocalFile> lfile (do_QueryInterface(file));
1667 NS_ENSURE_TRUE(lfile, NS_ERROR_NO_INTERFACE);
1669 PRFileDesc* fd;
1670 rv = lfile->OpenNSPRFileDesc(aAppend ? kNSPR_APPEND_FLAGS : kNSPR_TRUNCATE_FLAGS,
1671 0664, &fd);
1672 NS_ENSURE_SUCCESS(rv, rv);
1674 if (aAppend)
1675 PR_Write(fd, "\n", 1);
1677 nsCOMPtr<nsIRDFResource> root;
1678 rv = rdfs->GetResource(NS_LITERAL_CSTRING("urn:mozilla:skin:root"),
1679 getter_AddRefs(root));
1680 if (NS_SUCCEEDED(rv))
1681 ProcessProvider(fd, rdfs, ds, root, PR_FALSE, relativePath);
1683 rv = rdfs->GetResource(NS_LITERAL_CSTRING("urn:mozilla:stylesheets"),
1684 getter_AddRefs(root));
1685 if (NS_SUCCEEDED(rv))
1686 ProcessOverlays(fd, ds, root, NS_LITERAL_CSTRING("style"));
1688 if (!aSkinOnly) {
1689 rv = rdfs->GetResource(NS_LITERAL_CSTRING("urn:mozilla:locale:root"),
1690 getter_AddRefs(root));
1691 if (NS_SUCCEEDED(rv))
1692 ProcessProvider(fd, rdfs, ds, root, PR_TRUE, relativePath);
1694 rv = rdfs->GetResource(NS_LITERAL_CSTRING("urn:mozilla:overlays"),
1695 getter_AddRefs(root));
1696 if (NS_SUCCEEDED(rv))
1697 ProcessOverlays(fd, ds, root, NS_LITERAL_CSTRING("overlay"));
1699 /* content packages are easier, but different */
1701 rv = rdfs->GetResource(NS_LITERAL_CSTRING("urn:mozilla:package:root"),
1702 getter_AddRefs(root));
1704 nsCOMPtr<nsISimpleEnumerator> packages;
1705 if (NS_SUCCEEDED(rv))
1706 rv = GetContainerEnumerator(ds, root, getter_AddRefs(packages));
1708 if (NS_SUCCEEDED(rv)) {
1709 PRBool more;
1710 nsCOMPtr<nsISupports> next;
1711 nsCOMPtr<nsIRDFResource> package;
1713 while (NS_SUCCEEDED(packages->HasMoreElements(&more)) && more) {
1714 packages->GetNext(getter_AddRefs(next));
1716 package = do_QueryInterface(next);
1717 if (!package) {
1718 NS_WARNING("Arc from urn:mozilla:package:root points to non-resource node.");
1719 continue;
1722 nsCAutoString name;
1723 FollowLiteral(ds, package, namearc, name);
1724 if (name.IsEmpty())
1725 continue;
1727 nsCAutoString isPlatform;
1728 FollowLiteral(ds, package, platformarc, isPlatform);
1729 name.Insert(NS_LITERAL_CSTRING("content\t"), 0);
1730 name.Append('\t');
1731 name.Append(relativePath);
1732 if (!isPlatform.IsEmpty())
1733 name.AppendLiteral("\tplatform");
1735 name.AppendLiteral(NS_LINEBREAK);
1736 PR_Write(fd, name.get(), name.Length());
1741 PR_Close(fd);
1743 return NS_OK;
1746 static void
1747 GetResourceName(nsIRDFResource* res, nsACString& result)
1749 // we need to get the provider name. Instead of doing something sane,
1750 // we munge the resource URI, looking from the right for colons.
1752 nsCAutoString providerURI;
1753 res->GetValueUTF8(providerURI);
1755 PRInt32 found = providerURI.RFindChar(':');
1756 if (found == kNotFound) {
1757 result.Truncate();
1758 return;
1761 result.Assign(Substring(providerURI, found + 1));
1765 void
1766 nsChromeRegistry::ProcessProvider(PRFileDesc *fd, nsIRDFService* aRDFs,
1767 nsIRDFDataSource* aDS, nsIRDFResource* aRoot,
1768 PRBool aIsLocale, const nsACString& aBaseURL)
1770 NS_NAMED_LITERAL_CSTRING(kSlash, "/");
1771 NS_NAMED_LITERAL_CSTRING(kTab, "\t");
1773 nsresult rv;
1775 nsCOMPtr<nsIRDFResource> packagesarc;
1776 aRDFs->GetResource(NS_LITERAL_CSTRING(kURICHROME_packages),
1777 getter_AddRefs(packagesarc));
1778 if (!packagesarc) return;
1780 nsCOMPtr<nsISimpleEnumerator> providers;
1781 rv = GetContainerEnumerator(aDS, aRoot, getter_AddRefs(providers));
1782 if (NS_FAILED(rv)) {
1783 return;
1786 nsCOMPtr<nsISupports> next;
1788 PRBool more;
1789 while (NS_SUCCEEDED(providers->HasMoreElements(&more)) && more) {
1790 providers->GetNext(getter_AddRefs(next));
1791 NS_ASSERTION(next, "GetNext failed after HasMoreElements succeeded.");
1793 nsCOMPtr<nsIRDFResource> provider (do_QueryInterface(next));
1794 if (!provider) {
1795 NS_WARNING("Provider isn't a nsIRDFResource.");
1796 continue;
1799 nsCAutoString providerName;
1800 GetResourceName(provider, providerName);
1801 if (providerName.IsEmpty()) {
1802 NS_WARNING("Couldn't calculate resource name.");
1803 continue;
1806 nsCOMPtr<nsIRDFResource> packages;
1807 FollowResource(aDS, provider, packagesarc, getter_AddRefs(packages));
1808 if (!packages) {
1809 NS_WARNING("No chrome:packages arc found!");
1810 continue;
1813 PRInt32 count;
1814 nsCOMPtr<nsISimpleEnumerator> packageList;
1815 rv = GetContainerEnumerator(aDS, packages, getter_AddRefs(packageList), &count);
1816 if (NS_FAILED(rv)) {
1817 NS_WARNING("chrome:packages was not a sequence.");
1818 continue;
1821 nsCOMPtr<nsISupports> nextPackage;
1823 PRBool morePackages;
1824 while (NS_SUCCEEDED(packageList->HasMoreElements(&morePackages)) &&
1825 morePackages) {
1826 packageList->GetNext(getter_AddRefs(nextPackage));
1828 nsCOMPtr<nsIRDFResource> packageRes (do_QueryInterface(nextPackage));
1829 if (!packageRes) {
1830 NS_WARNING("chrome:packages Seq points to a non-resource!");
1831 continue;
1834 nsCAutoString packageName;
1835 GetResourceName(packageRes, packageName);
1836 if (packageName.IsEmpty()) {
1837 NS_WARNING("couldn't extract a package name.");
1838 continue;
1841 nsCAutoString line;
1843 if (aIsLocale)
1844 line.AppendLiteral("locale\t");
1845 else
1846 line.AppendLiteral("skin\t");
1848 line += packageName + kTab + providerName + kTab + aBaseURL;
1849 if (count > 1) {
1850 line += packageName + kSlash;
1852 line.AppendLiteral(NS_LINEBREAK);
1853 PR_Write(fd, line.get(), line.Length());
1858 static void
1859 GetLiteralText(nsIRDFLiteral* lit, nsACString& result)
1861 const PRUnichar* value;
1862 lit->GetValueConst(&value);
1863 CopyUTF16toUTF8(value, result);
1866 void
1867 nsChromeRegistry::ProcessOverlays(PRFileDesc *fd, nsIRDFDataSource* aDS,
1868 nsIRDFResource* aRoot,
1869 const nsCSubstring& aType)
1871 NS_NAMED_LITERAL_CSTRING(kTab, "\t");
1872 NS_NAMED_LITERAL_CSTRING(kLinebreak, NS_LINEBREAK);
1874 nsresult rv;
1876 nsCOMPtr<nsISimpleEnumerator> overlaids;
1877 rv = GetContainerEnumerator(aDS, aRoot, getter_AddRefs(overlaids));
1878 if (NS_FAILED(rv)) {
1879 return;
1882 nsCOMPtr<nsISupports> next;
1883 PRBool more;
1884 while (NS_SUCCEEDED(overlaids->HasMoreElements(&more)) && more) {
1885 overlaids->GetNext(getter_AddRefs(next));
1886 NS_ASSERTION(next, "GetNext failed after HasMoreElements succeeded.");
1888 nsCOMPtr<nsIRDFResource> overlaid (do_QueryInterface(next));
1889 if (!overlaid) {
1890 NS_WARNING("Overlay arc is not a nsIRDFResource.");
1891 continue;
1894 nsCAutoString overlaidName;
1895 overlaid->GetValueUTF8(overlaidName);
1897 nsCOMPtr<nsISimpleEnumerator> overlays;
1898 rv = GetContainerEnumerator(aDS, overlaid, getter_AddRefs(overlays));
1899 if (NS_FAILED(rv))
1900 continue;
1902 while (NS_SUCCEEDED(overlays->HasMoreElements(&more)) && more) {
1903 overlays->GetNext(getter_AddRefs(next));
1904 NS_ASSERTION(next, "GetNext failed after HasMoreElements succeeded.");
1906 nsCOMPtr<nsIRDFLiteral> overlay (do_QueryInterface(next));
1907 if (!overlay) {
1908 NS_WARNING("Overlay was not an RDF literal.");
1909 continue;
1912 nsCAutoString overlayName;
1913 GetLiteralText(overlay, overlayName);
1915 overlayName.Insert(aType + kTab + overlaidName + kTab, 0);
1916 overlayName.Append(kLinebreak);
1917 PR_Write(fd, overlayName.get(), overlayName.Length());
1922 #else // MOZ_XUL
1924 NS_IMETHODIMP
1925 nsChromeRegistry::ProcessContentsManifest(nsIURI* aOldManifest, nsIURI* aFile,
1926 nsIURI* aBaseURI, PRBool aAppend,
1927 PRBool aSkinOnly)
1929 return NS_ERROR_NOT_IMPLEMENTED;
1932 #endif // MOZ_XUL
1934 nsresult
1935 nsChromeRegistry::ProcessManifest(nsILocalFile* aManifest, PRBool aSkinOnly)
1937 nsresult rv;
1939 PRFileDesc* fd;
1940 rv = aManifest->OpenNSPRFileDesc(PR_RDONLY, 0, &fd);
1941 NS_ENSURE_SUCCESS(rv, rv);
1943 PRInt32 n, size;
1944 char *buf;
1946 size = PR_Available(fd);
1947 if (size == -1) {
1948 rv = NS_ERROR_UNEXPECTED;
1949 goto mend;
1952 buf = (char *) malloc(size + 1);
1953 if (!buf) {
1954 rv = NS_ERROR_OUT_OF_MEMORY;
1955 goto mend;
1958 n = PR_Read(fd, buf, size);
1959 if (n > 0) {
1960 buf[size] = '\0';
1961 rv = ProcessManifestBuffer(buf, size, aManifest, aSkinOnly);
1963 free(buf);
1965 mend:
1966 PR_Close(fd);
1967 return rv;
1970 static const char kWhitespace[] = "\t ";
1971 static const char kNewlines[] = "\r\n";
1974 * Check for a modifier flag of the following forms:
1975 * "flag" (same as "true")
1976 * "flag=yes|true|1"
1977 * "flag="no|false|0"
1978 * @param aFlag The flag to compare.
1979 * @param aData The tokenized data to check; this is lowercased
1980 * before being passed in.
1981 * @param aResult If the flag is found, the value is assigned here.
1982 * @return Whether the flag was handled.
1984 static PRBool
1985 CheckFlag(const nsSubstring& aFlag, const nsSubstring& aData, PRBool& aResult)
1987 if (!StringBeginsWith(aData, aFlag))
1988 return PR_FALSE;
1990 if (aFlag.Length() == aData.Length()) {
1991 // the data is simply "flag", which is the same as "flag=yes"
1992 aResult = PR_TRUE;
1993 return PR_TRUE;
1996 if (aData.CharAt(aFlag.Length()) != '=') {
1997 // the data is "flag2=", which is not anything we care about
1998 return PR_FALSE;
2001 if (aData.Length() == aFlag.Length() + 1) {
2002 aResult = PR_FALSE;
2003 return PR_TRUE;
2006 switch (aData.CharAt(aFlag.Length() + 1)) {
2007 case '1':
2008 case 't': //true
2009 case 'y': //yes
2010 aResult = PR_TRUE;
2011 return PR_TRUE;
2013 case '0':
2014 case 'f': //false
2015 case 'n': //no
2016 aResult = PR_FALSE;
2017 return PR_TRUE;
2020 return PR_FALSE;
2023 enum TriState {
2024 eUnspecified,
2025 eBad,
2030 * Check for a modifier flag of the following form:
2031 * "flag=string"
2032 * "flag!=string"
2033 * @param aFlag The flag to compare.
2034 * @param aData The tokenized data to check; this is lowercased
2035 * before being passed in.
2036 * @param aValue The value that is expected.
2037 * @param aResult If this is "ok" when passed in, this is left alone.
2038 * Otherwise if the flag is found it is set to eBad or eOK.
2039 * @return Whether the flag was handled.
2041 static PRBool
2042 CheckStringFlag(const nsSubstring& aFlag, const nsSubstring& aData,
2043 const nsSubstring& aValue, TriState& aResult)
2045 if (aData.Length() < aFlag.Length() + 1)
2046 return PR_FALSE;
2048 if (!StringBeginsWith(aData, aFlag))
2049 return PR_FALSE;
2051 PRBool comparison = PR_TRUE;
2052 if (aData[aFlag.Length()] != '=') {
2053 if (aData[aFlag.Length()] == '!' &&
2054 aData.Length() >= aFlag.Length() + 2 &&
2055 aData[aFlag.Length() + 1] == '=')
2056 comparison = PR_FALSE;
2057 else
2058 return PR_FALSE;
2061 if (aResult != eOK) {
2062 nsDependentSubstring testdata = Substring(aData, aFlag.Length() + (comparison ? 1 : 2));
2063 if (testdata.Equals(aValue))
2064 aResult = comparison ? eOK : eBad;
2065 else
2066 aResult = comparison ? eBad : eOK;
2069 return PR_TRUE;
2073 * Check for a modifier flag of the following form:
2074 * "flag=version"
2075 * "flag<=version"
2076 * "flag<version"
2077 * "flag>=version"
2078 * "flag>version"
2079 * @param aFlag The flag to compare.
2080 * @param aData The tokenized data to check; this is lowercased
2081 * before being passed in.
2082 * @param aValue The value that is expected. If this is empty then no
2083 * comparison will match.
2084 * @param aChecker the version checker to use. If null, aResult will always
2085 * be eBad.
2086 * @param aResult If this is eOK when passed in, this is left alone.
2087 * Otherwise if the flag is found it is set to eBad or eOK.
2088 * @return Whether the flag was handled.
2091 #define COMPARE_EQ 1 << 0
2092 #define COMPARE_LT 1 << 1
2093 #define COMPARE_GT 1 << 2
2095 static PRBool
2096 CheckVersionFlag(const nsSubstring& aFlag, const nsSubstring& aData,
2097 const nsSubstring& aValue, nsIVersionComparator* aChecker,
2098 TriState& aResult)
2100 if (aData.Length() < aFlag.Length() + 2)
2101 return PR_FALSE;
2103 if (!StringBeginsWith(aData, aFlag))
2104 return PR_FALSE;
2106 if (aValue.Length() == 0) {
2107 if (aResult != eOK)
2108 aResult = eBad;
2109 return PR_TRUE;
2112 PRUint32 comparison;
2113 nsAutoString testdata;
2115 switch (aData[aFlag.Length()]) {
2116 case '=':
2117 comparison = COMPARE_EQ;
2118 testdata = Substring(aData, aFlag.Length() + 1);
2119 break;
2121 case '<':
2122 if (aData[aFlag.Length() + 1] == '=') {
2123 comparison = COMPARE_EQ | COMPARE_LT;
2124 testdata = Substring(aData, aFlag.Length() + 2);
2126 else {
2127 comparison = COMPARE_LT;
2128 testdata = Substring(aData, aFlag.Length() + 1);
2130 break;
2132 case '>':
2133 if (aData[aFlag.Length() + 1] == '=') {
2134 comparison = COMPARE_EQ | COMPARE_GT;
2135 testdata = Substring(aData, aFlag.Length() + 2);
2137 else {
2138 comparison = COMPARE_GT;
2139 testdata = Substring(aData, aFlag.Length() + 1);
2141 break;
2143 default:
2144 return PR_FALSE;
2147 if (testdata.Length() == 0)
2148 return PR_FALSE;
2150 if (aResult != eOK) {
2151 if (!aChecker) {
2152 aResult = eBad;
2154 else {
2155 PRInt32 c;
2156 nsresult rv = aChecker->Compare(NS_ConvertUTF16toUTF8(aValue),
2157 NS_ConvertUTF16toUTF8(testdata), &c);
2158 if (NS_FAILED(rv)) {
2159 aResult = eBad;
2161 else {
2162 if ((c == 0 && comparison & COMPARE_EQ) ||
2163 (c < 0 && comparison & COMPARE_LT) ||
2164 (c > 0 && comparison & COMPARE_GT))
2165 aResult = eOK;
2166 else
2167 aResult = eBad;
2172 return PR_TRUE;
2175 static void
2176 EnsureLowerCase(char *aBuf)
2178 for (; *aBuf; ++aBuf) {
2179 char ch = *aBuf;
2180 if (ch >= 'A' && ch <= 'Z')
2181 *aBuf = ch + 'a' - 'A';
2185 nsresult
2186 nsChromeRegistry::ProcessManifestBuffer(char *buf, PRInt32 length,
2187 nsILocalFile* aManifest,
2188 PRBool aSkinOnly)
2190 nsresult rv;
2192 NS_NAMED_LITERAL_STRING(kPlatform, "platform");
2193 NS_NAMED_LITERAL_STRING(kXPCNativeWrappers, "xpcnativewrappers");
2194 NS_NAMED_LITERAL_STRING(kContentAccessible, "contentaccessible");
2195 NS_NAMED_LITERAL_STRING(kApplication, "application");
2196 NS_NAMED_LITERAL_STRING(kAppVersion, "appversion");
2197 NS_NAMED_LITERAL_STRING(kOs, "os");
2198 NS_NAMED_LITERAL_STRING(kOsVersion, "osversion");
2200 nsCOMPtr<nsIIOService> io (do_GetIOService());
2201 if (!io) return NS_ERROR_FAILURE;
2203 nsCOMPtr<nsIProtocolHandler> ph;
2204 rv = io->GetProtocolHandler("resource", getter_AddRefs(ph));
2205 NS_ENSURE_SUCCESS(rv, rv);
2207 nsCOMPtr<nsIResProtocolHandler> rph (do_QueryInterface(ph));
2208 if (!rph) return NS_ERROR_FAILURE;
2210 nsCOMPtr<nsIURI> manifestURI;
2211 rv = io->NewFileURI(aManifest, getter_AddRefs(manifestURI));
2212 NS_ENSURE_SUCCESS(rv, rv);
2214 nsCOMPtr<nsIXPConnect> xpc (do_GetService("@mozilla.org/js/xpc/XPConnect;1"));
2215 nsCOMPtr<nsIVersionComparator> vc (do_GetService("@mozilla.org/xpcom/version-comparator;1"));
2217 nsAutoString appID;
2218 nsAutoString appVersion;
2219 nsAutoString osTarget;
2220 nsCOMPtr<nsIXULAppInfo> xapp (do_GetService(XULAPPINFO_SERVICE_CONTRACTID));
2221 if (xapp) {
2222 nsCAutoString s;
2223 rv = xapp->GetID(s);
2224 if (NS_SUCCEEDED(rv))
2225 CopyUTF8toUTF16(s, appID);
2227 rv = xapp->GetVersion(s);
2228 if (NS_SUCCEEDED(rv))
2229 CopyUTF8toUTF16(s, appVersion);
2231 nsCOMPtr<nsIXULRuntime> xruntime (do_QueryInterface(xapp));
2232 if (xruntime) {
2233 rv = xruntime->GetOS(s);
2234 if (NS_SUCCEEDED(rv)) {
2235 CopyUTF8toUTF16(s, osTarget);
2236 ToLowerCase(osTarget);
2241 nsAutoString osVersion;
2242 #if defined(XP_WIN)
2243 OSVERSIONINFO info = { sizeof(OSVERSIONINFO) };
2244 if (GetVersionEx(&info)) {
2245 nsTextFormatter::ssprintf(osVersion, NS_LITERAL_STRING("%ld.%ld").get(),
2246 info.dwMajorVersion,
2247 info.dwMinorVersion);
2249 #elif defined(XP_MACOSX)
2250 long majorVersion, minorVersion;
2251 if ((Gestalt(gestaltSystemVersionMajor, &majorVersion) == noErr) &&
2252 (Gestalt(gestaltSystemVersionMinor, &minorVersion) == noErr)) {
2253 nsTextFormatter::ssprintf(osVersion, NS_LITERAL_STRING("%ld.%ld").get(),
2254 majorVersion,
2255 minorVersion);
2257 #elif defined(MOZ_WIDGET_GTK2)
2258 nsTextFormatter::ssprintf(osVersion, NS_LITERAL_STRING("%ld.%ld").get(),
2259 gtk_major_version,
2260 gtk_minor_version);
2261 #endif
2263 char *token;
2264 char *newline = buf;
2265 PRUint32 line = 0;
2267 // outer loop tokenizes by newline
2268 while (nsnull != (token = nsCRT::strtok(newline, kNewlines, &newline))) {
2269 ++line;
2271 if (*token == '#') // ignore lines that begin with # as comments
2272 continue;
2274 char *whitespace = token;
2275 token = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2276 if (!token) continue;
2278 if (!strcmp(token, "content")) {
2279 if (aSkinOnly) {
2280 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2281 "Warning: Ignoring content registration in skin-only manifest.");
2282 continue;
2284 char *package = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2285 char *uri = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2286 if (!package || !uri) {
2287 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2288 "Warning: Malformed content registration.");
2289 continue;
2292 EnsureLowerCase(package);
2294 // NOTE: We check for platform and xpcnativewrappers modifiers on
2295 // content packages, but they are *applied* to content|skin|locale.
2297 PRBool platform = PR_FALSE;
2298 PRBool xpcNativeWrappers = PR_TRUE;
2299 PRBool contentAccessible = PR_FALSE;
2300 TriState stAppVersion = eUnspecified;
2301 TriState stApp = eUnspecified;
2302 TriState stOsVersion = eUnspecified;
2303 TriState stOs = eUnspecified;
2305 PRBool badFlag = PR_FALSE;
2307 while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
2308 !badFlag) {
2309 NS_ConvertASCIItoUTF16 wtoken(token);
2310 ToLowerCase(wtoken);
2312 if (CheckFlag(kPlatform, wtoken, platform) ||
2313 CheckFlag(kXPCNativeWrappers, wtoken, xpcNativeWrappers) ||
2314 CheckFlag(kContentAccessible, wtoken, contentAccessible) ||
2315 CheckStringFlag(kApplication, wtoken, appID, stApp) ||
2316 CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
2317 CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
2318 CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
2319 continue;
2321 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2322 "Warning: Unrecognized chrome registration modifier '%s'.",
2323 token);
2324 badFlag = PR_TRUE;
2327 if (badFlag || stApp == eBad || stAppVersion == eBad ||
2328 stOs == eBad || stOsVersion == eBad)
2329 continue;
2331 nsCOMPtr<nsIURI> resolved;
2332 rv = io->NewURI(nsDependentCString(uri), nsnull, manifestURI,
2333 getter_AddRefs(resolved));
2334 if (NS_FAILED(rv))
2335 continue;
2337 PackageEntry* entry =
2338 static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
2339 & (const nsACString&) nsDependentCString(package),
2340 PL_DHASH_ADD));
2341 if (!entry)
2342 return NS_ERROR_OUT_OF_MEMORY;
2344 entry->baseURI = resolved;
2346 if (platform)
2347 entry->flags |= PackageEntry::PLATFORM_PACKAGE;
2348 if (xpcNativeWrappers)
2349 entry->flags |= PackageEntry::XPCNATIVEWRAPPERS;
2350 if (contentAccessible)
2351 entry->flags |= PackageEntry::CONTENT_ACCESSIBLE;
2352 if (xpc) {
2353 nsCAutoString urlp("chrome://");
2354 urlp.Append(package);
2355 urlp.Append('/');
2357 rv = xpc->FlagSystemFilenamePrefix(urlp.get(), xpcNativeWrappers);
2358 NS_ENSURE_SUCCESS(rv, rv);
2361 else if (!strcmp(token, "locale")) {
2362 if (aSkinOnly) {
2363 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2364 "Warning: Ignoring locale registration in skin-only manifest.");
2365 continue;
2367 char *package = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2368 char *provider = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2369 char *uri = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2370 if (!package || !provider || !uri) {
2371 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2372 "Warning: Malformed locale registration.");
2373 continue;
2376 EnsureLowerCase(package);
2378 TriState stAppVersion = eUnspecified;
2379 TriState stApp = eUnspecified;
2380 TriState stOs = eUnspecified;
2381 TriState stOsVersion = eUnspecified;
2383 PRBool badFlag = PR_FALSE;
2385 while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
2386 !badFlag) {
2387 NS_ConvertASCIItoUTF16 wtoken(token);
2388 ToLowerCase(wtoken);
2390 if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
2391 CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
2392 CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
2393 CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
2394 continue;
2396 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2397 "Warning: Unrecognized chrome registration modifier '%s'.",
2398 token);
2399 badFlag = PR_TRUE;
2402 if (badFlag || stApp == eBad || stAppVersion == eBad ||
2403 stOs == eBad || stOsVersion == eBad)
2404 continue;
2406 nsCOMPtr<nsIURI> resolved;
2407 rv = io->NewURI(nsDependentCString(uri), nsnull, manifestURI,
2408 getter_AddRefs(resolved));
2409 if (NS_FAILED(rv))
2410 continue;
2412 PackageEntry* entry =
2413 static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
2414 & (const nsACString&) nsDependentCString(package),
2415 PL_DHASH_ADD));
2416 if (!entry)
2417 return NS_ERROR_OUT_OF_MEMORY;
2419 entry->locales.SetBase(nsDependentCString(provider), resolved);
2421 else if (!strcmp(token, "skin")) {
2422 char *package = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2423 char *provider = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2424 char *uri = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2425 if (!package || !provider || !uri) {
2426 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2427 "Warning: Malformed skin registration.");
2428 continue;
2431 EnsureLowerCase(package);
2433 TriState stAppVersion = eUnspecified;
2434 TriState stApp = eUnspecified;
2435 TriState stOs = eUnspecified;
2436 TriState stOsVersion = eUnspecified;
2438 PRBool badFlag = PR_FALSE;
2440 while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
2441 !badFlag) {
2442 NS_ConvertASCIItoUTF16 wtoken(token);
2443 ToLowerCase(wtoken);
2445 if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
2446 CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
2447 CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
2448 CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
2449 continue;
2451 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2452 "Warning: Unrecognized chrome registration modifier '%s'.",
2453 token);
2454 badFlag = PR_TRUE;
2457 if (badFlag || stApp == eBad || stAppVersion == eBad ||
2458 stOs == eBad || stOsVersion == eBad)
2459 continue;
2461 nsCOMPtr<nsIURI> resolved;
2462 rv = io->NewURI(nsDependentCString(uri), nsnull, manifestURI,
2463 getter_AddRefs(resolved));
2464 if (NS_FAILED(rv))
2465 continue;
2467 PackageEntry* entry =
2468 static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
2469 & (const nsACString&) nsDependentCString(package),
2470 PL_DHASH_ADD));
2471 if (!entry)
2472 return NS_ERROR_OUT_OF_MEMORY;
2474 entry->skins.SetBase(nsDependentCString(provider), resolved);
2476 else if (!strcmp(token, "overlay")) {
2477 if (aSkinOnly) {
2478 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2479 "Warning: Ignoring overlay registration in skin-only manifest.");
2480 continue;
2482 char *base = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2483 char *overlay = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2484 if (!base || !overlay) {
2485 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2486 "Warning: malformed chrome overlay instruction.");
2487 continue;
2490 TriState stAppVersion = eUnspecified;
2491 TriState stApp = eUnspecified;
2492 TriState stOs = eUnspecified;
2493 TriState stOsVersion = eUnspecified;
2495 PRBool badFlag = PR_FALSE;
2497 while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
2498 !badFlag) {
2499 NS_ConvertASCIItoUTF16 wtoken(token);
2500 ToLowerCase(wtoken);
2502 if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
2503 CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
2504 CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
2505 CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
2506 continue;
2508 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2509 "Warning: Unrecognized chrome registration modifier '%s'.",
2510 token);
2511 badFlag = PR_TRUE;
2514 if (badFlag || stApp == eBad || stAppVersion == eBad ||
2515 stOs == eBad || stOsVersion == eBad)
2516 continue;
2518 nsCOMPtr<nsIURI> baseuri, overlayuri;
2519 rv = io->NewURI(nsDependentCString(base), nsnull, nsnull,
2520 getter_AddRefs(baseuri));
2521 rv |= io->NewURI(nsDependentCString(overlay), nsnull, nsnull,
2522 getter_AddRefs(overlayuri));
2523 if (NS_FAILED(rv)) {
2524 NS_WARNING("Could not make URIs for overlay directive. Ignoring.");
2525 continue;
2528 mOverlayHash.Add(baseuri, overlayuri);
2530 else if (!strcmp(token, "style")) {
2531 char *base = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2532 char *overlay = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2533 if (!base || !overlay) {
2534 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2535 "Warning: malformed chrome style instruction.");
2536 continue;
2539 TriState stAppVersion = eUnspecified;
2540 TriState stApp = eUnspecified;
2541 TriState stOs = eUnspecified;
2542 TriState stOsVersion = eUnspecified;
2544 PRBool badFlag = PR_FALSE;
2546 while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
2547 !badFlag) {
2548 NS_ConvertASCIItoUTF16 wtoken(token);
2549 ToLowerCase(wtoken);
2551 if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
2552 CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
2553 CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
2554 CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
2555 continue;
2557 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2558 "Warning: Unrecognized chrome registration modifier '%s'.",
2559 token);
2560 badFlag = PR_TRUE;
2563 if (badFlag || stApp == eBad || stAppVersion == eBad ||
2564 stOs == eBad || stOsVersion == eBad)
2565 continue;
2567 nsCOMPtr<nsIURI> baseuri, overlayuri;
2568 rv = io->NewURI(nsDependentCString(base), nsnull, nsnull,
2569 getter_AddRefs(baseuri));
2570 rv |= io->NewURI(nsDependentCString(overlay), nsnull, nsnull,
2571 getter_AddRefs(overlayuri));
2572 if (NS_FAILED(rv))
2573 continue;
2575 mStyleHash.Add(baseuri, overlayuri);
2577 else if (!strcmp(token, "override")) {
2578 if (aSkinOnly) {
2579 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2580 "Warning: Ignoring override registration in skin-only manifest.");
2581 continue;
2584 char *chrome = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2585 char *resolved = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2586 if (!chrome || !resolved) {
2587 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2588 "Warning: malformed chrome override instruction.");
2589 continue;
2592 TriState stAppVersion = eUnspecified;
2593 TriState stApp = eUnspecified;
2594 TriState stOs = eUnspecified;
2595 TriState stOsVersion = eUnspecified;
2597 PRBool badFlag = PR_FALSE;
2599 while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
2600 !badFlag) {
2601 NS_ConvertASCIItoUTF16 wtoken(token);
2602 ToLowerCase(wtoken);
2604 if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
2605 CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
2606 CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
2607 CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
2608 continue;
2610 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2611 "Warning: Unrecognized chrome registration modifier '%s'.",
2612 token);
2613 badFlag = PR_TRUE;
2616 if (badFlag || stApp == eBad || stAppVersion == eBad ||
2617 stOs == eBad || stOsVersion == eBad)
2618 continue;
2620 nsCOMPtr<nsIURI> chromeuri, resolveduri;
2621 rv = io->NewURI(nsDependentCString(chrome), nsnull, nsnull,
2622 getter_AddRefs(chromeuri));
2623 rv |= io->NewURI(nsDependentCString(resolved), nsnull, manifestURI,
2624 getter_AddRefs(resolveduri));
2625 if (NS_FAILED(rv))
2626 continue;
2628 mOverrideTable.Put(chromeuri, resolveduri);
2630 else if (!strcmp(token, "resource")) {
2631 if (aSkinOnly) {
2632 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2633 "Warning: Ignoring resource registration in skin-only manifest.");
2634 continue;
2637 char *package = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2638 char *uri = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2639 if (!package || !uri) {
2640 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2641 "Warning: Malformed resource registration.");
2642 continue;
2645 EnsureLowerCase(package);
2647 TriState stAppVersion = eUnspecified;
2648 TriState stApp = eUnspecified;
2649 TriState stOsVersion = eUnspecified;
2650 TriState stOs = eUnspecified;
2652 PRBool badFlag = PR_FALSE;
2654 while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
2655 !badFlag) {
2656 NS_ConvertASCIItoUTF16 wtoken(token);
2657 ToLowerCase(wtoken);
2659 if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
2660 CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
2661 CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
2662 CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
2663 continue;
2665 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2666 "Warning: Unrecognized chrome registration modifier '%s'.",
2667 token);
2668 badFlag = PR_TRUE;
2671 if (badFlag || stApp == eBad || stAppVersion == eBad ||
2672 stOs == eBad || stOsVersion == eBad)
2673 continue;
2675 nsDependentCString host(package);
2677 PRBool exists;
2678 rv = rph->HasSubstitution(host, &exists);
2679 NS_ENSURE_SUCCESS(rv, rv);
2680 if (exists) {
2681 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2682 "Warning: Duplicate resource declaration for '%s' ignored.",
2683 package);
2684 continue;
2687 nsCOMPtr<nsIURI> resolved;
2688 rv = io->NewURI(nsDependentCString(uri), nsnull, manifestURI,
2689 getter_AddRefs(resolved));
2690 if (NS_FAILED(rv))
2691 continue;
2693 rv = rph->SetSubstitution(host, resolved);
2694 NS_ENSURE_SUCCESS(rv, rv);
2696 else {
2697 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2698 "Warning: Ignoring unrecognized chrome manifest instruction.");
2702 return NS_OK;