Bug 469739 - Add support for displaying Vista UAC shield icon; r=joe sr=vladimir
[wine-gecko.git] / chrome / src / nsChromeRegistry.cpp
blobc5950a0265fc99f9cb682bbfad989114c93afc46
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 static PRBool
256 CanLoadResource(nsIURI* aResourceURI)
258 PRBool isLocalResource = PR_FALSE;
259 (void)NS_URIChainHasFlags(aResourceURI,
260 nsIProtocolHandler::URI_IS_LOCAL_RESOURCE,
261 &isLocalResource);
262 return isLocalResource;
265 nsChromeRegistry::ProviderEntry*
266 nsChromeRegistry::nsProviderArray::GetProvider(const nsACString& aPreferred, MatchType aType)
268 PRInt32 i = mArray.Count();
269 if (!i)
270 return nsnull;
272 ProviderEntry* found = nsnull; // Only set if we find a partial-match locale
273 ProviderEntry* entry;
275 while (i--) {
276 entry = reinterpret_cast<ProviderEntry*>(mArray[i]);
277 if (aPreferred.Equals(entry->provider))
278 return entry;
280 if (aType != LOCALE)
281 continue;
283 if (LanguagesMatch(aPreferred, entry->provider)) {
284 found = entry;
285 continue;
288 if (!found && entry->provider.EqualsLiteral("en-US"))
289 found = entry;
292 if (!found && aType != EXACT)
293 return entry;
295 return found;
298 nsIURI*
299 nsChromeRegistry::nsProviderArray::GetBase(const nsACString& aPreferred, MatchType aType)
301 ProviderEntry* provider = GetProvider(aPreferred, aType);
303 if (!provider)
304 return nsnull;
306 return provider->baseURI;
309 const nsACString&
310 nsChromeRegistry::nsProviderArray::GetSelected(const nsACString& aPreferred, MatchType aType)
312 ProviderEntry* entry = GetProvider(aPreferred, aType);
314 if (entry)
315 return entry->provider;
317 return EmptyCString();
320 void
321 nsChromeRegistry::nsProviderArray::SetBase(const nsACString& aProvider, nsIURI* aBaseURL)
323 ProviderEntry* provider = GetProvider(aProvider, EXACT);
325 if (provider) {
326 provider->baseURI = aBaseURL;
327 return;
330 // no existing entries, add a new one
331 provider = new ProviderEntry(aProvider, aBaseURL);
332 if (!provider)
333 return; // It's safe to silently fail on OOM
335 mArray.AppendElement(provider);
338 void
339 nsChromeRegistry::nsProviderArray::EnumerateToArray(nsCStringArray *a)
341 PRInt32 i = mArray.Count();
342 while (i--) {
343 ProviderEntry *entry = reinterpret_cast<ProviderEntry*>(mArray[i]);
344 a->AppendCString(entry->provider);
348 void
349 nsChromeRegistry::nsProviderArray::Clear()
351 PRInt32 i = mArray.Count();
352 while (i--) {
353 ProviderEntry* entry = reinterpret_cast<ProviderEntry*>(mArray[i]);
354 delete entry;
357 mArray.Clear();
360 nsChromeRegistry::PackageEntry::PackageEntry(const nsACString& aPackage) :
361 package(aPackage), flags(0)
365 PLHashNumber
366 nsChromeRegistry::HashKey(PLDHashTable *table, const void *key)
368 const nsACString& str = *reinterpret_cast<const nsACString*>(key);
369 return HashString(str);
372 PRBool
373 nsChromeRegistry::MatchKey(PLDHashTable *table, const PLDHashEntryHdr *entry,
374 const void *key)
376 const nsACString& str = *reinterpret_cast<const nsACString*>(key);
377 const PackageEntry* pentry = static_cast<const PackageEntry*>(entry);
378 return str.Equals(pentry->package);
381 void
382 nsChromeRegistry::ClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
384 PackageEntry* pentry = static_cast<PackageEntry*>(entry);
385 pentry->~PackageEntry();
388 PRBool
389 nsChromeRegistry::InitEntry(PLDHashTable *table, PLDHashEntryHdr *entry,
390 const void *key)
392 const nsACString& str = *reinterpret_cast<const nsACString*>(key);
394 new (entry) PackageEntry(str);
395 return PR_TRUE;
398 const PLDHashTableOps
399 nsChromeRegistry::kTableOps = {
400 PL_DHashAllocTable,
401 PL_DHashFreeTable,
402 HashKey,
403 MatchKey,
404 PL_DHashMoveEntryStub,
405 ClearEntry,
406 PL_DHashFinalizeStub,
407 InitEntry
410 void
411 nsChromeRegistry::OverlayListEntry::AddURI(nsIURI* aURI)
413 PRInt32 i = mArray.Count();
414 while (i--) {
415 PRBool equals;
416 if (NS_SUCCEEDED(aURI->Equals(mArray[i], &equals)) && equals)
417 return;
420 mArray.AppendObject(aURI);
423 void
424 nsChromeRegistry::OverlayListHash::Add(nsIURI* aBase, nsIURI* aOverlay)
426 OverlayListEntry* entry = mTable.PutEntry(aBase);
427 if (entry)
428 entry->AddURI(aOverlay);
431 const nsCOMArray<nsIURI>*
432 nsChromeRegistry::OverlayListHash::GetArray(nsIURI* aBase)
434 OverlayListEntry* entry = mTable.GetEntry(aBase);
435 if (!entry)
436 return nsnull;
438 return &entry->mArray;
441 nsChromeRegistry::~nsChromeRegistry()
443 if (mPackagesHash.ops)
444 PL_DHashTableFinish(&mPackagesHash);
445 gChromeRegistry = nsnull;
448 NS_INTERFACE_MAP_BEGIN(nsChromeRegistry)
449 NS_INTERFACE_MAP_ENTRY(nsIChromeRegistry)
450 NS_INTERFACE_MAP_ENTRY(nsIXULChromeRegistry)
451 NS_INTERFACE_MAP_ENTRY(nsIToolkitChromeRegistry)
452 #ifdef MOZ_XUL
453 NS_INTERFACE_MAP_ENTRY(nsIXULOverlayProvider)
454 #endif
455 NS_INTERFACE_MAP_ENTRY(nsIObserver)
456 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
457 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIChromeRegistry)
458 NS_INTERFACE_MAP_END
460 NS_IMPL_ADDREF(nsChromeRegistry)
461 NS_IMPL_RELEASE(nsChromeRegistry)
463 ////////////////////////////////////////////////////////////////////////////////
464 // nsIChromeRegistry methods:
466 static nsresult
467 getUILangCountry(nsACString& aUILang)
469 nsresult rv;
471 nsCOMPtr<nsILocaleService> localeService = do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv);
472 NS_ENSURE_SUCCESS(rv, rv);
474 nsAutoString uiLang;
475 rv = localeService->GetLocaleComponentForUserAgent(uiLang);
476 NS_ENSURE_SUCCESS(rv, rv);
478 CopyUTF16toUTF8(uiLang, aUILang);
479 return NS_OK;
482 nsresult
483 nsChromeRegistry::Init()
485 nsresult rv;
487 // these atoms appear in almost every chrome registry contents.rdf
488 // in some form or another. making static atoms prevents the atoms
489 // from constantly being created/destroyed during parsing
491 static const nsStaticAtom atoms[] = {
492 { "chrome", nsnull },
493 { "NC", nsnull },
494 { "allowScripts", nsnull },
495 { "package", nsnull },
496 { "packages", nsnull },
497 { "hasOverlays", nsnull },
500 NS_RegisterStaticAtoms(atoms, NS_ARRAY_LENGTH(atoms));
502 // Check to see if necko and the JAR protocol handler are registered yet
503 // if not, somebody is doing work during XPCOM registration that they
504 // shouldn't be doing. See bug 292549, where JS components are trying
505 // to call Components.utils.import("chrome:///") early in registration
507 nsCOMPtr<nsIIOService> io (do_GetIOService());
508 if (!io) return NS_ERROR_FAILURE;
510 nsCOMPtr<nsIProtocolHandler> ph;
511 rv = io->GetProtocolHandler("jar", getter_AddRefs(ph));
512 NS_ENSURE_SUCCESS(rv, rv);
514 nsCOMPtr<nsIJARProtocolHandler> jph = do_QueryInterface(ph);
515 if (!jph)
516 return NS_ERROR_NOT_INITIALIZED;
518 if (!PL_DHashTableInit(&mPackagesHash, &kTableOps,
519 nsnull, sizeof(PackageEntry), 16))
520 return NS_ERROR_FAILURE;
522 if (!mOverlayHash.Init() ||
523 !mStyleHash.Init() ||
524 !mOverrideTable.Init())
525 return NS_ERROR_FAILURE;
527 mSelectedLocale = NS_LITERAL_CSTRING("en-US");
528 mSelectedSkin = NS_LITERAL_CSTRING("classic/1.0");
530 // This initialization process is fairly complicated and may cause reentrant
531 // getservice calls to resolve chrome URIs (especially locale files). We
532 // don't want that, so we inform the protocol handler about our existence
533 // before we are actually fully initialized.
534 gChromeRegistry = this;
536 PRBool safeMode = PR_FALSE;
537 nsCOMPtr<nsIXULRuntime> xulrun (do_GetService(XULAPPINFO_SERVICE_CONTRACTID));
538 if (xulrun)
539 xulrun->GetInSafeMode(&safeMode);
541 nsCOMPtr<nsIPrefService> prefserv (do_GetService(NS_PREFSERVICE_CONTRACTID));
542 nsCOMPtr<nsIPrefBranch> prefs;
544 if (safeMode)
545 prefserv->GetDefaultBranch(nsnull, getter_AddRefs(prefs));
546 else
547 prefs = do_QueryInterface(prefserv);
549 if (!prefs) {
550 NS_WARNING("Could not get pref service!");
553 PRBool useLocalePref = PR_TRUE;
555 if (prefs) {
556 // check the pref first
557 PRBool matchOS = PR_FALSE;
558 rv = prefs->GetBoolPref(MATCH_OS_LOCALE_PREF, &matchOS);
560 // match os locale
561 if (NS_SUCCEEDED(rv) && matchOS) {
562 // compute lang and region code only when needed!
563 nsCAutoString uiLocale;
564 rv = getUILangCountry(uiLocale);
565 if (NS_SUCCEEDED(rv)) {
566 useLocalePref = PR_FALSE;
567 mSelectedLocale = uiLocale;
572 if (prefs) {
573 nsXPIDLCString provider;
575 rv = prefs->GetCharPref(SELECTED_SKIN_PREF, getter_Copies(provider));
576 if (NS_SUCCEEDED(rv))
577 mSelectedSkin = provider;
579 nsCOMPtr<nsIPrefBranch2> prefs2 (do_QueryInterface(prefs));
581 if (prefs2)
582 rv = prefs2->AddObserver(SELECTED_SKIN_PREF, this, PR_TRUE);
584 if (useLocalePref) {
585 rv = prefs->GetCharPref(SELECTED_LOCALE_PREF, getter_Copies(provider));
586 if (NS_SUCCEEDED(rv))
587 mSelectedLocale = provider;
589 if (prefs2)
590 prefs2->AddObserver(SELECTED_LOCALE_PREF, this, PR_TRUE);
594 CheckForNewChrome();
596 mInitialized = PR_TRUE;
598 return NS_OK;
601 NS_IMETHODIMP
602 nsChromeRegistry::CheckForOSAccessibility()
604 nsresult rv;
606 nsCOMPtr<nsILookAndFeel> lookAndFeel (do_GetService(kLookAndFeelCID));
607 if (lookAndFeel) {
608 PRInt32 useAccessibilityTheme = 0;
610 rv = lookAndFeel->GetMetric(nsILookAndFeel::eMetric_UseAccessibilityTheme,
611 useAccessibilityTheme);
613 if (NS_SUCCEEDED(rv) && useAccessibilityTheme) {
614 /* Set the skin to classic and remove pref observers */
615 if (!mSelectedSkin.EqualsLiteral("classic/1.0")) {
616 mSelectedSkin.AssignLiteral("classic/1.0");
617 RefreshSkins();
620 nsCOMPtr<nsIPrefBranch2> prefs (do_GetService(NS_PREFSERVICE_CONTRACTID));
621 if (prefs) {
622 prefs->RemoveObserver(SELECTED_SKIN_PREF, this);
627 return NS_OK;
630 nsresult
631 nsChromeRegistry::GetProviderAndPath(nsIURL* aChromeURL,
632 nsACString& aProvider, nsACString& aPath)
634 nsresult rv;
636 #ifdef DEBUG
637 PRBool isChrome;
638 aChromeURL->SchemeIs("chrome", &isChrome);
639 NS_ASSERTION(isChrome, "Non-chrome URI?");
640 #endif
642 nsCAutoString path;
643 rv = aChromeURL->GetPath(path);
644 NS_ENSURE_SUCCESS(rv, rv);
646 if (path.Length() < 3) {
647 LogMessage("Invalid chrome URI: %s", path.get());
648 return NS_ERROR_FAILURE;
651 path.SetLength(nsUnescapeCount(path.BeginWriting()));
652 NS_ASSERTION(path.First() == '/', "Path should always begin with a slash!");
654 PRInt32 slash = path.FindChar('/', 1);
655 if (slash == 1) {
656 LogMessage("Invalid chrome URI: %s", path.get());
657 return NS_ERROR_FAILURE;
660 if (slash == -1) {
661 aPath.Truncate();
663 else {
664 if (slash == (PRInt32) path.Length() - 1)
665 aPath.Truncate();
666 else
667 aPath.Assign(path.get() + slash + 1, path.Length() - slash - 1);
669 --slash;
672 aProvider.Assign(path.get() + 1, slash);
673 return NS_OK;
677 nsresult
678 nsChromeRegistry::Canonify(nsIURL* aChromeURL)
680 NS_NAMED_LITERAL_CSTRING(kSlash, "/");
682 nsresult rv;
684 nsCAutoString provider, path;
685 rv = GetProviderAndPath(aChromeURL, provider, path);
686 NS_ENSURE_SUCCESS(rv, rv);
688 if (path.IsEmpty()) {
689 nsCAutoString package;
690 rv = aChromeURL->GetHost(package);
691 NS_ENSURE_SUCCESS(rv, rv);
693 // we re-use the "path" local string to build a new URL path
694 path.Assign(kSlash + provider + kSlash + package);
695 if (provider.EqualsLiteral("content")) {
696 path.AppendLiteral(".xul");
698 else if (provider.EqualsLiteral("locale")) {
699 path.AppendLiteral(".dtd");
701 else if (provider.EqualsLiteral("skin")) {
702 path.AppendLiteral(".css");
704 else {
705 return NS_ERROR_INVALID_ARG;
707 aChromeURL->SetPath(path);
709 else {
710 // prevent directory traversals ("..")
711 // path is already unescaped once, but uris can get unescaped twice
712 const char* pos = path.BeginReading();
713 const char* end = path.EndReading();
714 while (pos < end) {
715 switch (*pos) {
716 case ':':
717 return NS_ERROR_DOM_BAD_URI;
718 case '.':
719 if (pos[1] == '.')
720 return NS_ERROR_DOM_BAD_URI;
721 break;
722 case '%':
723 // chrome: URIs with double-escapes are trying to trick us.
724 // watch for %2e, and %25 in case someone triple unescapes
725 if (pos[1] == '2' &&
726 ( pos[2] == 'e' || pos[2] == 'E' ||
727 pos[2] == '5' ))
728 return NS_ERROR_DOM_BAD_URI;
729 break;
730 case '?':
731 case '#':
732 pos = end;
733 continue;
735 ++pos;
739 return NS_OK;
742 NS_IMETHODIMP
743 nsChromeRegistry::ConvertChromeURL(nsIURI* aChromeURI, nsIURI* *aResult)
745 nsresult rv;
746 NS_ASSERTION(aChromeURI, "null url!");
748 if (mOverrideTable.Get(aChromeURI, aResult))
749 return NS_OK;
751 nsCOMPtr<nsIURL> chromeURL (do_QueryInterface(aChromeURI));
752 NS_ENSURE_TRUE(chromeURL, NS_NOINTERFACE);
754 nsCAutoString package, provider, path;
755 rv = chromeURL->GetHostPort(package);
756 NS_ENSURE_SUCCESS(rv, rv);
758 rv = GetProviderAndPath(chromeURL, provider, path);
759 NS_ENSURE_SUCCESS(rv, rv);
761 PackageEntry* entry =
762 static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
763 & (nsACString&) package,
764 PL_DHASH_LOOKUP));
766 if (PL_DHASH_ENTRY_IS_FREE(entry)) {
767 if (!mInitialized)
768 return NS_ERROR_NOT_INITIALIZED;
770 LogMessage("No chrome package registered for chrome://%s/%s/%s",
771 package.get(), provider.get(), path.get());
773 return NS_ERROR_FAILURE;
776 if (entry->flags & PackageEntry::PLATFORM_PACKAGE) {
777 #if defined(XP_WIN) || defined(XP_OS2)
778 path.Insert("win/", 0);
779 #elif defined(XP_MACOSX)
780 path.Insert("mac/", 0);
781 #else
782 path.Insert("unix/", 0);
783 #endif
786 nsIURI* baseURI = nsnull;
787 if (provider.EqualsLiteral("locale")) {
788 baseURI = entry->locales.GetBase(mSelectedLocale, nsProviderArray::LOCALE);
790 else if (provider.EqualsLiteral("skin")) {
791 baseURI = entry->skins.GetBase(mSelectedSkin, nsProviderArray::ANY);
793 else if (provider.EqualsLiteral("content")) {
794 baseURI = entry->baseURI;
797 if (!baseURI) {
798 LogMessage("No chrome package registered for chrome://%s/%s/%s",
799 package.get(), provider.get(), path.get());
800 return NS_ERROR_FAILURE;
803 return NS_NewURI(aResult, path, nsnull, baseURI);
806 nsresult
807 nsChromeRegistry::GetSelectedLocale(const nsACString& aPackage, nsACString& aLocale)
809 PackageEntry* entry =
810 static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
811 & aPackage,
812 PL_DHASH_LOOKUP));
814 if (PL_DHASH_ENTRY_IS_FREE(entry))
815 return NS_ERROR_FAILURE;
817 aLocale = entry->locales.GetSelected(mSelectedLocale, nsProviderArray::LOCALE);
818 if (aLocale.IsEmpty())
819 return NS_ERROR_FAILURE;
821 return NS_OK;
824 NS_IMETHODIMP
825 nsChromeRegistry::GetLocalesForPackage(const nsACString& aPackage,
826 nsIUTF8StringEnumerator* *aResult)
828 nsCStringArray *a = new nsCStringArray;
829 if (!a)
830 return NS_ERROR_OUT_OF_MEMORY;
832 PackageEntry* entry =
833 static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
834 & aPackage,
835 PL_DHASH_LOOKUP));
837 if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
838 entry->locales.EnumerateToArray(a);
841 nsresult rv = NS_NewAdoptingUTF8StringEnumerator(aResult, a);
842 if (NS_FAILED(rv))
843 delete a;
845 return rv;
848 #ifdef MOZ_XUL
849 NS_IMETHODIMP
850 nsChromeRegistry::GetStyleOverlays(nsIURI *aChromeURL,
851 nsISimpleEnumerator **aResult)
853 const nsCOMArray<nsIURI>* parray = mStyleHash.GetArray(aChromeURL);
854 if (!parray)
855 return NS_NewEmptyEnumerator(aResult);
857 return NS_NewArrayEnumerator(aResult, *parray);
860 NS_IMETHODIMP
861 nsChromeRegistry::GetXULOverlays(nsIURI *aChromeURL, nsISimpleEnumerator **aResult)
863 const nsCOMArray<nsIURI>* parray = mOverlayHash.GetArray(aChromeURL);
864 if (!parray)
865 return NS_NewEmptyEnumerator(aResult);
867 return NS_NewArrayEnumerator(aResult, *parray);
869 #endif // MOZ_XUL
871 ////////////////////////////////////////////////////////////////////////
873 // theme stuff
876 static void FlushSkinBindingsForWindow(nsIDOMWindowInternal* aWindow)
878 // Get the DOM document.
879 nsCOMPtr<nsIDOMDocument> domDocument;
880 aWindow->GetDocument(getter_AddRefs(domDocument));
881 if (!domDocument)
882 return;
884 nsCOMPtr<nsIDocument> document = do_QueryInterface(domDocument);
885 if (!document)
886 return;
888 // Annihilate all XBL bindings.
889 document->FlushSkinBindings();
892 // XXXbsmedberg: move this to nsIWindowMediator
893 NS_IMETHODIMP nsChromeRegistry::RefreshSkins()
895 nsCOMPtr<nsICSSLoader> cssLoader(do_CreateInstance(kCSSLoaderCID));
896 if (!cssLoader)
897 return NS_OK;
899 nsCOMPtr<nsIWindowMediator> windowMediator
900 (do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
901 if (!windowMediator)
902 return NS_OK;
904 nsCOMPtr<nsISimpleEnumerator> windowEnumerator;
905 windowMediator->GetEnumerator(nsnull, getter_AddRefs(windowEnumerator));
906 PRBool more;
907 windowEnumerator->HasMoreElements(&more);
908 while (more) {
909 nsCOMPtr<nsISupports> protoWindow;
910 windowEnumerator->GetNext(getter_AddRefs(protoWindow));
911 if (protoWindow) {
912 nsCOMPtr<nsIDOMWindowInternal> domWindow = do_QueryInterface(protoWindow);
913 if (domWindow)
914 FlushSkinBindingsForWindow(domWindow);
916 windowEnumerator->HasMoreElements(&more);
919 FlushSkinCaches();
921 windowMediator->GetEnumerator(nsnull, getter_AddRefs(windowEnumerator));
922 windowEnumerator->HasMoreElements(&more);
923 while (more) {
924 nsCOMPtr<nsISupports> protoWindow;
925 windowEnumerator->GetNext(getter_AddRefs(protoWindow));
926 if (protoWindow) {
927 nsCOMPtr<nsIDOMWindowInternal> domWindow = do_QueryInterface(protoWindow);
928 if (domWindow)
929 RefreshWindow(domWindow, cssLoader);
931 windowEnumerator->HasMoreElements(&more);
934 return NS_OK;
937 void
938 nsChromeRegistry::FlushSkinCaches()
940 nsCOMPtr<nsIObserverService> obsSvc =
941 do_GetService("@mozilla.org/observer-service;1");
942 NS_ASSERTION(obsSvc, "Couldn't get observer service.");
944 obsSvc->NotifyObservers(static_cast<nsIChromeRegistry*>(this),
945 NS_CHROME_FLUSH_SKINS_TOPIC, nsnull);
948 static PRBool IsChromeURI(nsIURI* aURI)
950 PRBool isChrome=PR_FALSE;
951 if (NS_SUCCEEDED(aURI->SchemeIs("chrome", &isChrome)) && isChrome)
952 return PR_TRUE;
953 return PR_FALSE;
956 // XXXbsmedberg: move this to windowmediator
957 nsresult nsChromeRegistry::RefreshWindow(nsIDOMWindowInternal* aWindow,
958 nsICSSLoader* aCSSLoader)
960 // Deal with our subframes first.
961 nsCOMPtr<nsIDOMWindowCollection> frames;
962 aWindow->GetFrames(getter_AddRefs(frames));
963 PRUint32 length;
964 frames->GetLength(&length);
965 PRUint32 j;
966 for (j = 0; j < length; j++) {
967 nsCOMPtr<nsIDOMWindow> childWin;
968 frames->Item(j, getter_AddRefs(childWin));
969 nsCOMPtr<nsIDOMWindowInternal> childInt(do_QueryInterface(childWin));
970 RefreshWindow(childInt, aCSSLoader);
973 nsresult rv;
974 // Get the DOM document.
975 nsCOMPtr<nsIDOMDocument> domDocument;
976 aWindow->GetDocument(getter_AddRefs(domDocument));
977 if (!domDocument)
978 return NS_OK;
980 nsCOMPtr<nsIDocument> document = do_QueryInterface(domDocument);
981 if (!document)
982 return NS_OK;
984 // Deal with the agent sheets first. Have to do all the style sets by hand.
985 nsPresShellIterator iter(document);
986 nsCOMPtr<nsIPresShell> shell;
987 while ((shell = iter.GetNextShell())) {
988 // Reload only the chrome URL agent style sheets.
989 nsCOMArray<nsIStyleSheet> agentSheets;
990 rv = shell->GetAgentStyleSheets(agentSheets);
991 NS_ENSURE_SUCCESS(rv, rv);
993 nsCOMArray<nsIStyleSheet> newAgentSheets;
994 for (PRInt32 l = 0; l < agentSheets.Count(); ++l) {
995 nsIStyleSheet *sheet = agentSheets[l];
997 nsCOMPtr<nsIURI> uri;
998 rv = sheet->GetSheetURI(getter_AddRefs(uri));
999 if (NS_FAILED(rv)) return rv;
1001 if (IsChromeURI(uri)) {
1002 // Reload the sheet.
1003 nsCOMPtr<nsICSSStyleSheet> newSheet;
1004 rv = aCSSLoader->LoadSheetSync(uri, PR_TRUE, getter_AddRefs(newSheet));
1005 if (NS_FAILED(rv)) return rv;
1006 if (newSheet) {
1007 rv = newAgentSheets.AppendObject(newSheet) ? NS_OK : NS_ERROR_FAILURE;
1008 if (NS_FAILED(rv)) return rv;
1011 else { // Just use the same sheet.
1012 rv = newAgentSheets.AppendObject(sheet) ? NS_OK : NS_ERROR_FAILURE;
1013 if (NS_FAILED(rv)) return rv;
1017 rv = shell->SetAgentStyleSheets(newAgentSheets);
1018 NS_ENSURE_SUCCESS(rv, rv);
1021 // Build an array of nsIURIs of style sheets we need to load.
1022 nsCOMArray<nsIStyleSheet> oldSheets;
1023 nsCOMArray<nsIStyleSheet> newSheets;
1025 PRInt32 count = document->GetNumberOfStyleSheets();
1027 // Iterate over the style sheets.
1028 PRInt32 i;
1029 for (i = 0; i < count; i++) {
1030 // Get the style sheet
1031 nsIStyleSheet *styleSheet = document->GetStyleSheetAt(i);
1033 if (!oldSheets.AppendObject(styleSheet)) {
1034 return NS_ERROR_OUT_OF_MEMORY;
1038 // Iterate over our old sheets and kick off a sync load of the new
1039 // sheet if and only if it's a chrome URL.
1040 for (i = 0; i < count; i++) {
1041 nsCOMPtr<nsIStyleSheet> sheet = oldSheets[i];
1042 nsCOMPtr<nsIURI> uri;
1043 rv = sheet->GetSheetURI(getter_AddRefs(uri));
1044 if (NS_FAILED(rv)) return rv;
1046 if (IsChromeURI(uri)) {
1047 // Reload the sheet.
1048 #ifdef DEBUG
1049 nsCOMPtr<nsICSSStyleSheet> oldCSSSheet = do_QueryInterface(sheet);
1050 NS_ASSERTION(oldCSSSheet, "Don't know how to reload a non-CSS sheet");
1051 #endif
1052 nsCOMPtr<nsICSSStyleSheet> newSheet;
1053 // XXX what about chrome sheets that have a title or are disabled? This
1054 // only works by sheer dumb luck.
1055 // XXXbz this should really use the document's CSSLoader!
1056 aCSSLoader->LoadSheetSync(uri, getter_AddRefs(newSheet));
1057 // Even if it's null, we put in in there.
1058 newSheets.AppendObject(newSheet);
1060 else {
1061 // Just use the same sheet.
1062 newSheets.AppendObject(sheet);
1066 // Now notify the document that multiple sheets have been added and removed.
1067 document->UpdateStyleSheets(oldSheets, newSheets);
1068 return NS_OK;
1071 void
1072 nsChromeRegistry::FlushAllCaches()
1074 nsCOMPtr<nsIObserverService> obsSvc =
1075 do_GetService("@mozilla.org/observer-service;1");
1076 NS_ASSERTION(obsSvc, "Couldn't get observer service.");
1078 obsSvc->NotifyObservers((nsIChromeRegistry*) this,
1079 NS_CHROME_FLUSH_TOPIC, nsnull);
1082 // xxxbsmedberg Move me to nsIWindowMediator
1083 NS_IMETHODIMP
1084 nsChromeRegistry::ReloadChrome()
1086 FlushAllCaches();
1087 // Do a reload of all top level windows.
1088 nsresult rv = NS_OK;
1090 // Get the window mediator
1091 nsCOMPtr<nsIWindowMediator> windowMediator
1092 (do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
1093 if (windowMediator) {
1094 nsCOMPtr<nsISimpleEnumerator> windowEnumerator;
1096 rv = windowMediator->GetEnumerator(nsnull, getter_AddRefs(windowEnumerator));
1097 if (NS_SUCCEEDED(rv)) {
1098 // Get each dom window
1099 PRBool more;
1100 rv = windowEnumerator->HasMoreElements(&more);
1101 if (NS_FAILED(rv)) return rv;
1102 while (more) {
1103 nsCOMPtr<nsISupports> protoWindow;
1104 rv = windowEnumerator->GetNext(getter_AddRefs(protoWindow));
1105 if (NS_SUCCEEDED(rv)) {
1106 nsCOMPtr<nsIDOMWindowInternal> domWindow =
1107 do_QueryInterface(protoWindow);
1108 if (domWindow) {
1109 nsCOMPtr<nsIDOMLocation> location;
1110 domWindow->GetLocation(getter_AddRefs(location));
1111 if (location) {
1112 rv = location->Reload(PR_FALSE);
1113 if (NS_FAILED(rv)) return rv;
1117 rv = windowEnumerator->HasMoreElements(&more);
1118 if (NS_FAILED(rv)) return rv;
1122 return rv;
1125 NS_IMETHODIMP
1126 nsChromeRegistry::AllowScriptsForPackage(nsIURI* aChromeURI, PRBool *aResult)
1128 nsresult rv;
1129 *aResult = PR_FALSE;
1131 #ifdef DEBUG
1132 PRBool isChrome;
1133 aChromeURI->SchemeIs("chrome", &isChrome);
1134 NS_ASSERTION(isChrome, "Non-chrome URI passed to AllowScriptsForPackage!");
1135 #endif
1137 nsCOMPtr<nsIURL> url (do_QueryInterface(aChromeURI));
1138 NS_ENSURE_TRUE(url, NS_NOINTERFACE);
1140 nsCAutoString provider, file;
1141 rv = GetProviderAndPath(url, provider, file);
1142 NS_ENSURE_SUCCESS(rv, rv);
1144 if (!provider.EqualsLiteral("skin"))
1145 *aResult = PR_TRUE;
1147 return NS_OK;
1150 NS_IMETHODIMP
1151 nsChromeRegistry::AllowContentToAccess(nsIURI *aURI, PRBool *aResult)
1153 nsresult rv;
1155 *aResult = PR_FALSE;
1157 #ifdef DEBUG
1158 PRBool isChrome;
1159 aURI->SchemeIs("chrome", &isChrome);
1160 NS_ASSERTION(isChrome, "Non-chrome URI passed to AllowContentToAccess!");
1161 #endif
1163 nsCOMPtr<nsIURL> url = do_QueryInterface(aURI);
1164 if (!url) {
1165 NS_ERROR("Chrome URL doesn't implement nsIURL.");
1166 return NS_ERROR_UNEXPECTED;
1169 nsCAutoString package;
1170 rv = url->GetHostPort(package);
1171 NS_ENSURE_SUCCESS(rv, rv);
1173 PackageEntry *entry =
1174 static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
1175 & (nsACString&) package,
1176 PL_DHASH_LOOKUP));
1178 if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
1179 *aResult = !!(entry->flags & PackageEntry::CONTENT_ACCESSIBLE);
1181 return NS_OK;
1184 static PLDHashOperator
1185 RemoveAll(PLDHashTable *table, PLDHashEntryHdr *entry, PRUint32 number, void *arg)
1187 return (PLDHashOperator) (PL_DHASH_NEXT | PL_DHASH_REMOVE);
1190 NS_IMETHODIMP
1191 nsChromeRegistry::CheckForNewChrome()
1193 nsresult rv;
1195 PL_DHashTableEnumerate(&mPackagesHash, RemoveAll, nsnull);
1196 mOverlayHash.Clear();
1197 mStyleHash.Clear();
1198 mOverrideTable.Clear();
1200 nsCOMPtr<nsIURI> manifestURI;
1201 rv = NS_NewURI(getter_AddRefs(manifestURI),
1202 NS_LITERAL_CSTRING("resource:///chrome/app-chrome.manifest"));
1204 // this is the main manifest; if it doesn't exist we generate it from
1205 // installed-chrome.txt. When the build system learns about the new system,
1206 // this code can go away.
1208 nsCOMPtr<nsIFileURL> manifestFileURL (do_QueryInterface(manifestURI));
1209 NS_ASSERTION(manifestFileURL, "Not a nsIFileURL!");
1210 NS_ENSURE_TRUE(manifestFileURL, NS_ERROR_UNEXPECTED);
1212 nsCOMPtr<nsIFile> manifest;
1213 manifestFileURL->GetFile(getter_AddRefs(manifest));
1214 NS_ENSURE_TRUE(manifest, NS_ERROR_FAILURE);
1216 PRBool exists;
1217 rv = manifest->Exists(&exists);
1218 NS_ENSURE_SUCCESS(rv, rv);
1220 #ifdef DEBUG
1221 // In debug builds, installed-chrome.txt may change during development;
1222 // we just rebuild it every time because we're not worried about startup
1223 // time or other bad/goodness.
1224 if (exists) {
1225 manifest->Remove(PR_FALSE);
1226 exists = PR_FALSE;
1228 #endif
1230 if (!exists) {
1231 nsCOMPtr<nsIFile> installed;
1232 manifest->Clone(getter_AddRefs(installed));
1233 if (!installed)
1234 return NS_ERROR_OUT_OF_MEMORY;
1236 nsCOMPtr<nsILocalFile> linstalled (do_QueryInterface(installed));
1237 NS_ENSURE_TRUE(linstalled, NS_NOINTERFACE);
1239 linstalled->SetNativeLeafName(NS_LITERAL_CSTRING("installed-chrome.txt"));
1241 rv = linstalled->Exists(&exists);
1242 NS_ENSURE_SUCCESS(rv, rv);
1244 // process installed-chrome.txt into app-chrome.manifest
1245 if (exists)
1246 ProcessNewChromeFile(linstalled, manifestURI);
1249 nsCOMPtr<nsIProperties> dirSvc (do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID));
1250 NS_ENSURE_TRUE(dirSvc, NS_ERROR_FAILURE);
1252 // check the extra chrome directories
1253 nsCOMPtr<nsISimpleEnumerator> chromeML;
1254 rv = dirSvc->Get(NS_CHROME_MANIFESTS_FILE_LIST, NS_GET_IID(nsISimpleEnumerator),
1255 getter_AddRefs(chromeML));
1256 if (NS_FAILED(rv)) {
1257 // ok, then simply load all .manifest files in the app chrome dir.
1258 nsCOMPtr<nsIFile> chromeDir;
1259 rv = dirSvc->Get(NS_APP_CHROME_DIR, NS_GET_IID(nsIFile),
1260 getter_AddRefs(chromeDir));
1261 if (NS_FAILED(rv))
1262 return rv;
1263 rv = NS_NewSingletonEnumerator(getter_AddRefs(chromeML), chromeDir);
1264 if (NS_FAILED(rv))
1265 return rv;
1268 nsCOMPtr<nsISupports> next;
1269 while (NS_SUCCEEDED(chromeML->HasMoreElements(&exists)) && exists) {
1270 chromeML->GetNext(getter_AddRefs(next));
1271 nsCOMPtr<nsILocalFile> lmanifest = do_QueryInterface(next);
1272 if (!lmanifest) {
1273 NS_ERROR("Directory enumerator returned a non-nsILocalFile");
1274 continue;
1277 PRBool isDir;
1278 if (NS_SUCCEEDED(lmanifest->IsDirectory(&isDir)) && isDir) {
1279 nsCOMPtr<nsISimpleEnumerator> entries;
1280 rv = lmanifest->GetDirectoryEntries(getter_AddRefs(entries));
1281 if (NS_FAILED(rv))
1282 continue;
1284 while (NS_SUCCEEDED(entries->HasMoreElements(&exists)) && exists) {
1285 entries->GetNext(getter_AddRefs(next));
1286 lmanifest = do_QueryInterface(next);
1287 if (lmanifest) {
1288 nsCAutoString leafName;
1289 lmanifest->GetNativeLeafName(leafName);
1290 if (StringEndsWith(leafName, NS_LITERAL_CSTRING(".manifest"))) {
1291 rv = ProcessManifest(lmanifest, PR_FALSE);
1292 if (NS_FAILED(rv)) {
1293 nsCAutoString path;
1294 lmanifest->GetNativePath(path);
1295 LogMessage("Failed to process chrome manifest '%s'.",
1296 path.get());
1303 else {
1304 rv = ProcessManifest(lmanifest, PR_FALSE);
1305 if (NS_FAILED(rv)) {
1306 nsCAutoString path;
1307 lmanifest->GetNativePath(path);
1308 LogMessage("Failed to process chrome manifest: '%s'.",
1309 path.get());
1314 rv = dirSvc->Get(NS_SKIN_MANIFESTS_FILE_LIST, NS_GET_IID(nsISimpleEnumerator),
1315 getter_AddRefs(chromeML));
1316 if (NS_FAILED(rv))
1317 return NS_OK;
1319 while (NS_SUCCEEDED(chromeML->HasMoreElements(&exists)) && exists) {
1320 chromeML->GetNext(getter_AddRefs(next));
1321 nsCOMPtr<nsILocalFile> lmanifest = do_QueryInterface(next);
1322 if (!lmanifest) {
1323 NS_ERROR("Directory enumerator returned a non-nsILocalFile");
1324 continue;
1327 rv = ProcessManifest(lmanifest, PR_TRUE);
1328 if (NS_FAILED(rv)) {
1329 nsCAutoString path;
1330 lmanifest->GetNativePath(path);
1331 LogMessage("Failed to process chrome manifest: '%s'.",
1332 path.get());
1336 return NS_OK;
1339 NS_IMETHODIMP_(PRBool)
1340 nsChromeRegistry::WrappersEnabled(nsIURI *aURI)
1342 nsCOMPtr<nsIURL> chromeURL (do_QueryInterface(aURI));
1343 if (!chromeURL)
1344 return PR_FALSE;
1346 PRBool isChrome = PR_FALSE;
1347 nsresult rv = chromeURL->SchemeIs("chrome", &isChrome);
1348 if (NS_FAILED(rv) || !isChrome)
1349 return PR_FALSE;
1351 nsCAutoString package;
1352 rv = chromeURL->GetHostPort(package);
1353 if (NS_FAILED(rv))
1354 return PR_FALSE;
1356 PackageEntry* entry =
1357 static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
1358 & (nsACString&) package,
1359 PL_DHASH_LOOKUP));
1361 return PL_DHASH_ENTRY_IS_LIVE(entry) &&
1362 entry->flags & PackageEntry::XPCNATIVEWRAPPERS;
1365 nsresult
1366 nsChromeRegistry::ProcessNewChromeFile(nsILocalFile *aListFile, nsIURI* aManifest)
1368 nsresult rv;
1370 PRFileDesc *file;
1371 rv = aListFile->OpenNSPRFileDesc(PR_RDONLY, 0, &file);
1372 NS_ENSURE_SUCCESS(rv, rv);
1374 PRInt32 n, size;
1375 char *buf;
1377 size = PR_Available(file);
1378 if (size == -1) {
1379 rv = NS_ERROR_UNEXPECTED;
1380 goto end;
1383 buf = (char *) malloc(size + 1);
1384 if (!buf) {
1385 rv = NS_ERROR_OUT_OF_MEMORY;
1386 goto end;
1389 n = PR_Read(file, buf, size);
1390 if (n > 0)
1391 rv = ProcessNewChromeBuffer(buf, size, aManifest);
1392 free(buf);
1394 end:
1395 PR_Close(file);
1396 return rv;
1399 nsresult
1400 nsChromeRegistry::ProcessNewChromeBuffer(char *aBuffer, PRInt32 aLength,
1401 nsIURI* aManifest)
1403 nsresult rv = NS_OK;
1404 char *bufferEnd = aBuffer + aLength;
1405 char *chromeType, // "content", "locale" or "skin"
1406 *chromeProfile, // "install" or "profile"
1407 *chromeLocType, // type of location (local path or URL)
1408 *chromeLocation; // base location of chrome (jar file)
1410 nsCOMPtr<nsIURI> baseURI;
1412 // process chromeType, chromeProfile, chromeLocType, chromeLocation
1413 while (aBuffer < bufferEnd) {
1414 // parse one line of installed-chrome.txt
1415 chromeType = aBuffer;
1416 while (aBuffer < bufferEnd && *aBuffer != ',')
1417 ++aBuffer;
1418 *aBuffer = '\0';
1420 chromeProfile = ++aBuffer;
1421 if (aBuffer >= bufferEnd)
1422 break;
1424 while (aBuffer < bufferEnd && *aBuffer != ',')
1425 ++aBuffer;
1426 *aBuffer = '\0';
1428 chromeLocType = ++aBuffer;
1429 if (aBuffer >= bufferEnd)
1430 break;
1432 while (aBuffer < bufferEnd && *aBuffer != ',')
1433 ++aBuffer;
1434 *aBuffer = '\0';
1436 chromeLocation = ++aBuffer;
1437 if (aBuffer >= bufferEnd)
1438 break;
1440 while (aBuffer < bufferEnd &&
1441 (*aBuffer != '\r' && *aBuffer != '\n' && *aBuffer != ' '))
1442 ++aBuffer;
1443 *aBuffer = '\0';
1445 // process the line
1446 // We don't do skin or locale selection from installed-chrome.txt since
1447 // ffox 0.9. Just ignore the "select" lines.
1448 if (strcmp(chromeLocType,"select")) {
1449 if (!strcmp(chromeLocType, "path")) {
1450 // location is a (full) path. convert it to an URL.
1452 /* this is some convoluted shit... this creates a file, inits it with
1453 * the path parsed above (chromeLocation), makes a url, and inits it
1454 * with the file created. the purpose of this is just to have the
1455 * canonical url of the stupid thing.
1457 nsCOMPtr<nsILocalFile> chromeFile;
1458 rv = NS_NewNativeLocalFile(nsDependentCString(chromeLocation),
1459 PR_TRUE, getter_AddRefs(chromeFile));
1460 NS_ENSURE_SUCCESS(rv, rv);
1463 * all we want here is the canonical url
1465 rv = NS_NewFileURI(getter_AddRefs(baseURI), chromeFile);
1466 if (NS_FAILED(rv)) return rv;
1468 else {
1469 rv = NS_NewURI(getter_AddRefs(baseURI), chromeLocation);
1470 if (NS_FAILED(rv)) return rv;
1473 ProcessContentsManifest(baseURI, aManifest, baseURI, PR_TRUE,
1474 strcmp(chromeType, "skin") == 0);
1477 while (aBuffer < bufferEnd && (*aBuffer == '\0' || *aBuffer == ' ' || *aBuffer == '\r' || *aBuffer == '\n'))
1478 ++aBuffer;
1481 return NS_OK;
1484 NS_IMETHODIMP nsChromeRegistry::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *someData)
1486 nsresult rv = NS_OK;
1488 if (!strcmp(NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, aTopic)) {
1489 nsCOMPtr<nsIPrefBranch> prefs (do_QueryInterface(aSubject));
1490 NS_ASSERTION(prefs, "Bad observer call!");
1492 NS_ConvertUTF16toUTF8 pref(someData);
1494 nsXPIDLCString provider;
1495 rv = prefs->GetCharPref(pref.get(), getter_Copies(provider));
1496 if (NS_FAILED(rv)) {
1497 NS_ERROR("Couldn't get new locale or skin pref!");
1498 return rv;
1501 if (pref.EqualsLiteral(SELECTED_SKIN_PREF)) {
1502 mSelectedSkin = provider;
1503 RefreshSkins();
1505 else if (pref.EqualsLiteral(SELECTED_LOCALE_PREF)) {
1506 mSelectedLocale = provider;
1507 FlushAllCaches();
1508 } else {
1509 NS_ERROR("Unexpected pref!");
1512 else if (!strcmp("command-line-startup", aTopic)) {
1513 nsCOMPtr<nsICommandLine> cmdLine (do_QueryInterface(aSubject));
1514 if (cmdLine) {
1515 nsAutoString uiLocale;
1516 rv = cmdLine->HandleFlagWithParam(NS_LITERAL_STRING(UILOCALE_CMD_LINE_ARG),
1517 PR_FALSE, uiLocale);
1518 if (NS_SUCCEEDED(rv) && !uiLocale.IsEmpty()) {
1519 CopyUTF16toUTF8(uiLocale, mSelectedLocale);
1520 nsCOMPtr<nsIPrefBranch2> prefs (do_GetService(NS_PREFSERVICE_CONTRACTID));
1521 if (prefs) {
1522 prefs->RemoveObserver(SELECTED_LOCALE_PREF, this);
1527 else {
1528 NS_ERROR("Unexpected observer topic!");
1531 return rv;
1534 #ifdef MOZ_XUL
1535 static nsresult
1536 GetContainerEnumerator(nsIRDFDataSource* ds, nsIRDFResource* res,
1537 nsISimpleEnumerator* *aResult, PRInt32 *aCountResult = nsnull)
1539 nsresult rv;
1541 nsCOMPtr<nsIRDFContainer> container
1542 (do_CreateInstance("@mozilla.org/rdf/container;1"));
1543 NS_ENSURE_TRUE(container, NS_ERROR_FAILURE);
1545 rv = container->Init(ds, res);
1546 if (NS_FAILED(rv)) return rv;
1548 if (aCountResult)
1549 container->GetCount(aCountResult);
1551 return container->GetElements(aResult);
1554 static void
1555 FollowLiteral(nsIRDFDataSource* ds, nsIRDFResource* res,
1556 nsIRDFResource* arc, nsACString& result)
1558 nsresult rv;
1560 nsCOMPtr<nsIRDFNode> node;
1561 rv = ds->GetTarget(res, arc, PR_TRUE, getter_AddRefs(node));
1562 if (NS_FAILED(rv) || !node) {
1563 result.Truncate();
1564 return;
1567 nsCOMPtr<nsIRDFLiteral> literal (do_QueryInterface(node));
1568 if (!literal) {
1569 NS_ERROR("Arc found, but doesn't point to expected literal!");
1570 result.Truncate();
1571 return;
1574 const PRUnichar* value;
1575 literal->GetValueConst(&value);
1576 CopyUTF16toUTF8(value, result);
1579 static void
1580 FollowResource(nsIRDFDataSource* ds, nsIRDFResource* res, nsIRDFResource* arc,
1581 nsIRDFResource* *result)
1583 nsresult rv;
1585 nsCOMPtr<nsIRDFNode> node;
1586 rv = ds->GetTarget(res, arc, PR_TRUE, getter_AddRefs(node));
1587 if (NS_FAILED(rv) || !node) {
1588 *result = nsnull;
1589 return;
1592 CallQueryInterface(node, result);
1595 static void
1596 GetRelativePath(nsIURI* base, nsIURI* relative, nsACString& result)
1598 nsresult rv;
1600 nsCOMPtr<nsIJARURI> jarrelative (do_QueryInterface(relative));
1601 if (jarrelative) {
1602 nsCOMPtr<nsIURI> jarbase;
1603 jarrelative->GetJARFile(getter_AddRefs(jarbase));
1605 nsCAutoString relativeBase;
1606 GetRelativePath(base, jarbase, relativeBase);
1608 nsCAutoString jarEntry;
1609 jarrelative->GetJAREntry(jarEntry);
1611 result.Assign(NS_LITERAL_CSTRING("jar:"));
1612 result.Append(relativeBase);
1613 result.Append(NS_LITERAL_CSTRING("!/"));
1614 result.Append(jarEntry);
1615 return;
1618 nsCOMPtr<nsIURL> baseURL (do_QueryInterface(base));
1619 if (!baseURL) {
1620 relative->GetSpec(result);
1621 return;
1624 rv = baseURL->GetRelativeSpec(relative, result);
1625 if (NS_FAILED(rv)) {
1626 relative->GetSpec(result);
1630 static const PRInt32 kNSPR_APPEND_FLAGS = PR_WRONLY | PR_CREATE_FILE | PR_APPEND;
1631 static const PRInt32 kNSPR_TRUNCATE_FLAGS = PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE;
1633 NS_IMETHODIMP
1634 nsChromeRegistry::ProcessContentsManifest(nsIURI* aOldManifest, nsIURI* aFile,
1635 nsIURI* aBaseURI, PRBool aAppend,
1636 PRBool aSkinOnly)
1638 nsresult rv;
1640 nsCAutoString relativePath;
1641 GetRelativePath(aFile, aBaseURI, relativePath);
1643 nsCAutoString spec;
1644 aOldManifest->GetSpec(spec);
1646 NS_ASSERTION(spec.Last() == '/', "installed-chrome manifest URI doesn't end in a slash! It probably won't work.");
1648 spec.AppendLiteral("contents.rdf");
1650 nsCOMPtr<nsIRDFService> rdfs (do_GetService("@mozilla.org/rdf/rdf-service;1"));
1651 NS_ENSURE_TRUE(rdfs, NS_ERROR_FAILURE);
1653 nsCOMPtr<nsIRDFResource> namearc, platformarc;
1654 rdfs->GetResource(NS_LITERAL_CSTRING(kURICHROME_name),
1655 getter_AddRefs(namearc));
1656 rdfs->GetResource(NS_LITERAL_CSTRING(kURICHROME_platformPackage),
1657 getter_AddRefs(platformarc));
1658 if (!(namearc && platformarc))
1659 return NS_ERROR_FAILURE;
1661 nsCOMPtr<nsIRDFDataSource> ds;
1662 rv = rdfs->GetDataSourceBlocking(spec.get(), getter_AddRefs(ds));
1663 if (NS_FAILED(rv)) {
1664 LogMessage("Failed to load old-style contents.rdf at '%s'.",
1665 spec.get());
1666 return rv;
1669 nsCOMPtr<nsIFileURL> fileURL (do_QueryInterface(aFile));
1670 NS_ENSURE_TRUE(fileURL, NS_ERROR_INVALID_ARG);
1672 nsCOMPtr<nsIFile> file;
1673 rv = fileURL->GetFile(getter_AddRefs(file));
1674 NS_ENSURE_SUCCESS(rv, rv);
1676 nsCOMPtr<nsILocalFile> lfile (do_QueryInterface(file));
1677 NS_ENSURE_TRUE(lfile, NS_ERROR_NO_INTERFACE);
1679 PRFileDesc* fd;
1680 rv = lfile->OpenNSPRFileDesc(aAppend ? kNSPR_APPEND_FLAGS : kNSPR_TRUNCATE_FLAGS,
1681 0664, &fd);
1682 NS_ENSURE_SUCCESS(rv, rv);
1684 if (aAppend)
1685 PR_Write(fd, "\n", 1);
1687 nsCOMPtr<nsIRDFResource> root;
1688 rv = rdfs->GetResource(NS_LITERAL_CSTRING("urn:mozilla:skin:root"),
1689 getter_AddRefs(root));
1690 if (NS_SUCCEEDED(rv))
1691 ProcessProvider(fd, rdfs, ds, root, PR_FALSE, relativePath);
1693 rv = rdfs->GetResource(NS_LITERAL_CSTRING("urn:mozilla:stylesheets"),
1694 getter_AddRefs(root));
1695 if (NS_SUCCEEDED(rv))
1696 ProcessOverlays(fd, ds, root, NS_LITERAL_CSTRING("style"));
1698 if (!aSkinOnly) {
1699 rv = rdfs->GetResource(NS_LITERAL_CSTRING("urn:mozilla:locale:root"),
1700 getter_AddRefs(root));
1701 if (NS_SUCCEEDED(rv))
1702 ProcessProvider(fd, rdfs, ds, root, PR_TRUE, relativePath);
1704 rv = rdfs->GetResource(NS_LITERAL_CSTRING("urn:mozilla:overlays"),
1705 getter_AddRefs(root));
1706 if (NS_SUCCEEDED(rv))
1707 ProcessOverlays(fd, ds, root, NS_LITERAL_CSTRING("overlay"));
1709 /* content packages are easier, but different */
1711 rv = rdfs->GetResource(NS_LITERAL_CSTRING("urn:mozilla:package:root"),
1712 getter_AddRefs(root));
1714 nsCOMPtr<nsISimpleEnumerator> packages;
1715 if (NS_SUCCEEDED(rv))
1716 rv = GetContainerEnumerator(ds, root, getter_AddRefs(packages));
1718 if (NS_SUCCEEDED(rv)) {
1719 PRBool more;
1720 nsCOMPtr<nsISupports> next;
1721 nsCOMPtr<nsIRDFResource> package;
1723 while (NS_SUCCEEDED(packages->HasMoreElements(&more)) && more) {
1724 packages->GetNext(getter_AddRefs(next));
1726 package = do_QueryInterface(next);
1727 if (!package) {
1728 NS_WARNING("Arc from urn:mozilla:package:root points to non-resource node.");
1729 continue;
1732 nsCAutoString name;
1733 FollowLiteral(ds, package, namearc, name);
1734 if (name.IsEmpty())
1735 continue;
1737 nsCAutoString isPlatform;
1738 FollowLiteral(ds, package, platformarc, isPlatform);
1739 name.Insert(NS_LITERAL_CSTRING("content\t"), 0);
1740 name.Append('\t');
1741 name.Append(relativePath);
1742 if (!isPlatform.IsEmpty())
1743 name.AppendLiteral("\tplatform");
1745 name.AppendLiteral(NS_LINEBREAK);
1746 PR_Write(fd, name.get(), name.Length());
1751 PR_Close(fd);
1753 return NS_OK;
1756 static void
1757 GetResourceName(nsIRDFResource* res, nsACString& result)
1759 // we need to get the provider name. Instead of doing something sane,
1760 // we munge the resource URI, looking from the right for colons.
1762 nsCAutoString providerURI;
1763 res->GetValueUTF8(providerURI);
1765 PRInt32 found = providerURI.RFindChar(':');
1766 if (found == kNotFound) {
1767 result.Truncate();
1768 return;
1771 result.Assign(Substring(providerURI, found + 1));
1775 void
1776 nsChromeRegistry::ProcessProvider(PRFileDesc *fd, nsIRDFService* aRDFs,
1777 nsIRDFDataSource* aDS, nsIRDFResource* aRoot,
1778 PRBool aIsLocale, const nsACString& aBaseURL)
1780 NS_NAMED_LITERAL_CSTRING(kSlash, "/");
1781 NS_NAMED_LITERAL_CSTRING(kTab, "\t");
1783 nsresult rv;
1785 nsCOMPtr<nsIRDFResource> packagesarc;
1786 aRDFs->GetResource(NS_LITERAL_CSTRING(kURICHROME_packages),
1787 getter_AddRefs(packagesarc));
1788 if (!packagesarc) return;
1790 nsCOMPtr<nsISimpleEnumerator> providers;
1791 rv = GetContainerEnumerator(aDS, aRoot, getter_AddRefs(providers));
1792 if (NS_FAILED(rv)) {
1793 return;
1796 nsCOMPtr<nsISupports> next;
1798 PRBool more;
1799 while (NS_SUCCEEDED(providers->HasMoreElements(&more)) && more) {
1800 providers->GetNext(getter_AddRefs(next));
1801 NS_ASSERTION(next, "GetNext failed after HasMoreElements succeeded.");
1803 nsCOMPtr<nsIRDFResource> provider (do_QueryInterface(next));
1804 if (!provider) {
1805 NS_WARNING("Provider isn't a nsIRDFResource.");
1806 continue;
1809 nsCAutoString providerName;
1810 GetResourceName(provider, providerName);
1811 if (providerName.IsEmpty()) {
1812 NS_WARNING("Couldn't calculate resource name.");
1813 continue;
1816 nsCOMPtr<nsIRDFResource> packages;
1817 FollowResource(aDS, provider, packagesarc, getter_AddRefs(packages));
1818 if (!packages) {
1819 NS_WARNING("No chrome:packages arc found!");
1820 continue;
1823 PRInt32 count;
1824 nsCOMPtr<nsISimpleEnumerator> packageList;
1825 rv = GetContainerEnumerator(aDS, packages, getter_AddRefs(packageList), &count);
1826 if (NS_FAILED(rv)) {
1827 NS_WARNING("chrome:packages was not a sequence.");
1828 continue;
1831 nsCOMPtr<nsISupports> nextPackage;
1833 PRBool morePackages;
1834 while (NS_SUCCEEDED(packageList->HasMoreElements(&morePackages)) &&
1835 morePackages) {
1836 packageList->GetNext(getter_AddRefs(nextPackage));
1838 nsCOMPtr<nsIRDFResource> packageRes (do_QueryInterface(nextPackage));
1839 if (!packageRes) {
1840 NS_WARNING("chrome:packages Seq points to a non-resource!");
1841 continue;
1844 nsCAutoString packageName;
1845 GetResourceName(packageRes, packageName);
1846 if (packageName.IsEmpty()) {
1847 NS_WARNING("couldn't extract a package name.");
1848 continue;
1851 nsCAutoString line;
1853 if (aIsLocale)
1854 line.AppendLiteral("locale\t");
1855 else
1856 line.AppendLiteral("skin\t");
1858 line += packageName + kTab + providerName + kTab + aBaseURL;
1859 if (count > 1) {
1860 line += packageName + kSlash;
1862 line.AppendLiteral(NS_LINEBREAK);
1863 PR_Write(fd, line.get(), line.Length());
1868 static void
1869 GetLiteralText(nsIRDFLiteral* lit, nsACString& result)
1871 const PRUnichar* value;
1872 lit->GetValueConst(&value);
1873 CopyUTF16toUTF8(value, result);
1876 void
1877 nsChromeRegistry::ProcessOverlays(PRFileDesc *fd, nsIRDFDataSource* aDS,
1878 nsIRDFResource* aRoot,
1879 const nsCSubstring& aType)
1881 NS_NAMED_LITERAL_CSTRING(kTab, "\t");
1882 NS_NAMED_LITERAL_CSTRING(kLinebreak, NS_LINEBREAK);
1884 nsresult rv;
1886 nsCOMPtr<nsISimpleEnumerator> overlaids;
1887 rv = GetContainerEnumerator(aDS, aRoot, getter_AddRefs(overlaids));
1888 if (NS_FAILED(rv)) {
1889 return;
1892 nsCOMPtr<nsISupports> next;
1893 PRBool more;
1894 while (NS_SUCCEEDED(overlaids->HasMoreElements(&more)) && more) {
1895 overlaids->GetNext(getter_AddRefs(next));
1896 NS_ASSERTION(next, "GetNext failed after HasMoreElements succeeded.");
1898 nsCOMPtr<nsIRDFResource> overlaid (do_QueryInterface(next));
1899 if (!overlaid) {
1900 NS_WARNING("Overlay arc is not a nsIRDFResource.");
1901 continue;
1904 nsCAutoString overlaidName;
1905 overlaid->GetValueUTF8(overlaidName);
1907 nsCOMPtr<nsISimpleEnumerator> overlays;
1908 rv = GetContainerEnumerator(aDS, overlaid, getter_AddRefs(overlays));
1909 if (NS_FAILED(rv))
1910 continue;
1912 while (NS_SUCCEEDED(overlays->HasMoreElements(&more)) && more) {
1913 overlays->GetNext(getter_AddRefs(next));
1914 NS_ASSERTION(next, "GetNext failed after HasMoreElements succeeded.");
1916 nsCOMPtr<nsIRDFLiteral> overlay (do_QueryInterface(next));
1917 if (!overlay) {
1918 NS_WARNING("Overlay was not an RDF literal.");
1919 continue;
1922 nsCAutoString overlayName;
1923 GetLiteralText(overlay, overlayName);
1925 overlayName.Insert(aType + kTab + overlaidName + kTab, 0);
1926 overlayName.Append(kLinebreak);
1927 PR_Write(fd, overlayName.get(), overlayName.Length());
1932 #else // MOZ_XUL
1934 NS_IMETHODIMP
1935 nsChromeRegistry::ProcessContentsManifest(nsIURI* aOldManifest, nsIURI* aFile,
1936 nsIURI* aBaseURI, PRBool aAppend,
1937 PRBool aSkinOnly)
1939 return NS_ERROR_NOT_IMPLEMENTED;
1942 #endif // MOZ_XUL
1944 nsresult
1945 nsChromeRegistry::ProcessManifest(nsILocalFile* aManifest, PRBool aSkinOnly)
1947 nsresult rv;
1949 PRFileDesc* fd;
1950 rv = aManifest->OpenNSPRFileDesc(PR_RDONLY, 0, &fd);
1951 NS_ENSURE_SUCCESS(rv, rv);
1953 PRInt32 n, size;
1954 char *buf;
1956 size = PR_Available(fd);
1957 if (size == -1) {
1958 rv = NS_ERROR_UNEXPECTED;
1959 goto mend;
1962 buf = (char *) malloc(size + 1);
1963 if (!buf) {
1964 rv = NS_ERROR_OUT_OF_MEMORY;
1965 goto mend;
1968 n = PR_Read(fd, buf, size);
1969 if (n > 0) {
1970 buf[size] = '\0';
1971 rv = ProcessManifestBuffer(buf, size, aManifest, aSkinOnly);
1973 free(buf);
1975 mend:
1976 PR_Close(fd);
1977 return rv;
1980 static const char kWhitespace[] = "\t ";
1981 static const char kNewlines[] = "\r\n";
1984 * Check for a modifier flag of the following forms:
1985 * "flag" (same as "true")
1986 * "flag=yes|true|1"
1987 * "flag="no|false|0"
1988 * @param aFlag The flag to compare.
1989 * @param aData The tokenized data to check; this is lowercased
1990 * before being passed in.
1991 * @param aResult If the flag is found, the value is assigned here.
1992 * @return Whether the flag was handled.
1994 static PRBool
1995 CheckFlag(const nsSubstring& aFlag, const nsSubstring& aData, PRBool& aResult)
1997 if (!StringBeginsWith(aData, aFlag))
1998 return PR_FALSE;
2000 if (aFlag.Length() == aData.Length()) {
2001 // the data is simply "flag", which is the same as "flag=yes"
2002 aResult = PR_TRUE;
2003 return PR_TRUE;
2006 if (aData.CharAt(aFlag.Length()) != '=') {
2007 // the data is "flag2=", which is not anything we care about
2008 return PR_FALSE;
2011 if (aData.Length() == aFlag.Length() + 1) {
2012 aResult = PR_FALSE;
2013 return PR_TRUE;
2016 switch (aData.CharAt(aFlag.Length() + 1)) {
2017 case '1':
2018 case 't': //true
2019 case 'y': //yes
2020 aResult = PR_TRUE;
2021 return PR_TRUE;
2023 case '0':
2024 case 'f': //false
2025 case 'n': //no
2026 aResult = PR_FALSE;
2027 return PR_TRUE;
2030 return PR_FALSE;
2033 enum TriState {
2034 eUnspecified,
2035 eBad,
2040 * Check for a modifier flag of the following form:
2041 * "flag=string"
2042 * "flag!=string"
2043 * @param aFlag The flag to compare.
2044 * @param aData The tokenized data to check; this is lowercased
2045 * before being passed in.
2046 * @param aValue The value that is expected.
2047 * @param aResult If this is "ok" when passed in, this is left alone.
2048 * Otherwise if the flag is found it is set to eBad or eOK.
2049 * @return Whether the flag was handled.
2051 static PRBool
2052 CheckStringFlag(const nsSubstring& aFlag, const nsSubstring& aData,
2053 const nsSubstring& aValue, TriState& aResult)
2055 if (aData.Length() < aFlag.Length() + 1)
2056 return PR_FALSE;
2058 if (!StringBeginsWith(aData, aFlag))
2059 return PR_FALSE;
2061 PRBool comparison = PR_TRUE;
2062 if (aData[aFlag.Length()] != '=') {
2063 if (aData[aFlag.Length()] == '!' &&
2064 aData.Length() >= aFlag.Length() + 2 &&
2065 aData[aFlag.Length() + 1] == '=')
2066 comparison = PR_FALSE;
2067 else
2068 return PR_FALSE;
2071 if (aResult != eOK) {
2072 nsDependentSubstring testdata = Substring(aData, aFlag.Length() + (comparison ? 1 : 2));
2073 if (testdata.Equals(aValue))
2074 aResult = comparison ? eOK : eBad;
2075 else
2076 aResult = comparison ? eBad : eOK;
2079 return PR_TRUE;
2083 * Check for a modifier flag of the following form:
2084 * "flag=version"
2085 * "flag<=version"
2086 * "flag<version"
2087 * "flag>=version"
2088 * "flag>version"
2089 * @param aFlag The flag to compare.
2090 * @param aData The tokenized data to check; this is lowercased
2091 * before being passed in.
2092 * @param aValue The value that is expected. If this is empty then no
2093 * comparison will match.
2094 * @param aChecker the version checker to use. If null, aResult will always
2095 * be eBad.
2096 * @param aResult If this is eOK when passed in, this is left alone.
2097 * Otherwise if the flag is found it is set to eBad or eOK.
2098 * @return Whether the flag was handled.
2101 #define COMPARE_EQ 1 << 0
2102 #define COMPARE_LT 1 << 1
2103 #define COMPARE_GT 1 << 2
2105 static PRBool
2106 CheckVersionFlag(const nsSubstring& aFlag, const nsSubstring& aData,
2107 const nsSubstring& aValue, nsIVersionComparator* aChecker,
2108 TriState& aResult)
2110 if (aData.Length() < aFlag.Length() + 2)
2111 return PR_FALSE;
2113 if (!StringBeginsWith(aData, aFlag))
2114 return PR_FALSE;
2116 if (aValue.Length() == 0) {
2117 if (aResult != eOK)
2118 aResult = eBad;
2119 return PR_TRUE;
2122 PRUint32 comparison;
2123 nsAutoString testdata;
2125 switch (aData[aFlag.Length()]) {
2126 case '=':
2127 comparison = COMPARE_EQ;
2128 testdata = Substring(aData, aFlag.Length() + 1);
2129 break;
2131 case '<':
2132 if (aData[aFlag.Length() + 1] == '=') {
2133 comparison = COMPARE_EQ | COMPARE_LT;
2134 testdata = Substring(aData, aFlag.Length() + 2);
2136 else {
2137 comparison = COMPARE_LT;
2138 testdata = Substring(aData, aFlag.Length() + 1);
2140 break;
2142 case '>':
2143 if (aData[aFlag.Length() + 1] == '=') {
2144 comparison = COMPARE_EQ | COMPARE_GT;
2145 testdata = Substring(aData, aFlag.Length() + 2);
2147 else {
2148 comparison = COMPARE_GT;
2149 testdata = Substring(aData, aFlag.Length() + 1);
2151 break;
2153 default:
2154 return PR_FALSE;
2157 if (testdata.Length() == 0)
2158 return PR_FALSE;
2160 if (aResult != eOK) {
2161 if (!aChecker) {
2162 aResult = eBad;
2164 else {
2165 PRInt32 c;
2166 nsresult rv = aChecker->Compare(NS_ConvertUTF16toUTF8(aValue),
2167 NS_ConvertUTF16toUTF8(testdata), &c);
2168 if (NS_FAILED(rv)) {
2169 aResult = eBad;
2171 else {
2172 if ((c == 0 && comparison & COMPARE_EQ) ||
2173 (c < 0 && comparison & COMPARE_LT) ||
2174 (c > 0 && comparison & COMPARE_GT))
2175 aResult = eOK;
2176 else
2177 aResult = eBad;
2182 return PR_TRUE;
2185 static void
2186 EnsureLowerCase(char *aBuf)
2188 for (; *aBuf; ++aBuf) {
2189 char ch = *aBuf;
2190 if (ch >= 'A' && ch <= 'Z')
2191 *aBuf = ch + 'a' - 'A';
2195 nsresult
2196 nsChromeRegistry::ProcessManifestBuffer(char *buf, PRInt32 length,
2197 nsILocalFile* aManifest,
2198 PRBool aSkinOnly)
2200 nsresult rv;
2202 NS_NAMED_LITERAL_STRING(kPlatform, "platform");
2203 NS_NAMED_LITERAL_STRING(kXPCNativeWrappers, "xpcnativewrappers");
2204 NS_NAMED_LITERAL_STRING(kContentAccessible, "contentaccessible");
2205 NS_NAMED_LITERAL_STRING(kApplication, "application");
2206 NS_NAMED_LITERAL_STRING(kAppVersion, "appversion");
2207 NS_NAMED_LITERAL_STRING(kOs, "os");
2208 NS_NAMED_LITERAL_STRING(kOsVersion, "osversion");
2210 nsCOMPtr<nsIIOService> io (do_GetIOService());
2211 if (!io) return NS_ERROR_FAILURE;
2213 nsCOMPtr<nsIProtocolHandler> ph;
2214 rv = io->GetProtocolHandler("resource", getter_AddRefs(ph));
2215 NS_ENSURE_SUCCESS(rv, rv);
2217 nsCOMPtr<nsIResProtocolHandler> rph (do_QueryInterface(ph));
2218 if (!rph) return NS_ERROR_FAILURE;
2220 nsCOMPtr<nsIURI> manifestURI;
2221 rv = io->NewFileURI(aManifest, getter_AddRefs(manifestURI));
2222 NS_ENSURE_SUCCESS(rv, rv);
2224 nsCOMPtr<nsIXPConnect> xpc (do_GetService("@mozilla.org/js/xpc/XPConnect;1"));
2225 nsCOMPtr<nsIVersionComparator> vc (do_GetService("@mozilla.org/xpcom/version-comparator;1"));
2227 nsAutoString appID;
2228 nsAutoString appVersion;
2229 nsAutoString osTarget;
2230 nsCOMPtr<nsIXULAppInfo> xapp (do_GetService(XULAPPINFO_SERVICE_CONTRACTID));
2231 if (xapp) {
2232 nsCAutoString s;
2233 rv = xapp->GetID(s);
2234 if (NS_SUCCEEDED(rv))
2235 CopyUTF8toUTF16(s, appID);
2237 rv = xapp->GetVersion(s);
2238 if (NS_SUCCEEDED(rv))
2239 CopyUTF8toUTF16(s, appVersion);
2241 nsCOMPtr<nsIXULRuntime> xruntime (do_QueryInterface(xapp));
2242 if (xruntime) {
2243 rv = xruntime->GetOS(s);
2244 if (NS_SUCCEEDED(rv)) {
2245 CopyUTF8toUTF16(s, osTarget);
2246 ToLowerCase(osTarget);
2251 nsAutoString osVersion;
2252 #if defined(XP_WIN)
2253 OSVERSIONINFO info = { sizeof(OSVERSIONINFO) };
2254 if (GetVersionEx(&info)) {
2255 nsTextFormatter::ssprintf(osVersion, NS_LITERAL_STRING("%ld.%ld").get(),
2256 info.dwMajorVersion,
2257 info.dwMinorVersion);
2259 #elif defined(XP_MACOSX)
2260 long majorVersion, minorVersion;
2261 if ((Gestalt(gestaltSystemVersionMajor, &majorVersion) == noErr) &&
2262 (Gestalt(gestaltSystemVersionMinor, &minorVersion) == noErr)) {
2263 nsTextFormatter::ssprintf(osVersion, NS_LITERAL_STRING("%ld.%ld").get(),
2264 majorVersion,
2265 minorVersion);
2267 #elif defined(MOZ_WIDGET_GTK2)
2268 nsTextFormatter::ssprintf(osVersion, NS_LITERAL_STRING("%ld.%ld").get(),
2269 gtk_major_version,
2270 gtk_minor_version);
2271 #endif
2273 char *token;
2274 char *newline = buf;
2275 PRUint32 line = 0;
2277 // outer loop tokenizes by newline
2278 while (nsnull != (token = nsCRT::strtok(newline, kNewlines, &newline))) {
2279 ++line;
2281 if (*token == '#') // ignore lines that begin with # as comments
2282 continue;
2284 char *whitespace = token;
2285 token = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2286 if (!token) continue;
2288 if (!strcmp(token, "content")) {
2289 if (aSkinOnly) {
2290 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2291 "Warning: Ignoring content registration in skin-only manifest.");
2292 continue;
2294 char *package = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2295 char *uri = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2296 if (!package || !uri) {
2297 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2298 "Warning: Malformed content registration.");
2299 continue;
2302 EnsureLowerCase(package);
2304 // NOTE: We check for platform and xpcnativewrappers modifiers on
2305 // content packages, but they are *applied* to content|skin|locale.
2307 PRBool platform = PR_FALSE;
2308 PRBool xpcNativeWrappers = PR_TRUE;
2309 PRBool contentAccessible = PR_FALSE;
2310 TriState stAppVersion = eUnspecified;
2311 TriState stApp = eUnspecified;
2312 TriState stOsVersion = eUnspecified;
2313 TriState stOs = eUnspecified;
2315 PRBool badFlag = PR_FALSE;
2317 while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
2318 !badFlag) {
2319 NS_ConvertASCIItoUTF16 wtoken(token);
2320 ToLowerCase(wtoken);
2322 if (CheckFlag(kPlatform, wtoken, platform) ||
2323 CheckFlag(kXPCNativeWrappers, wtoken, xpcNativeWrappers) ||
2324 CheckFlag(kContentAccessible, wtoken, contentAccessible) ||
2325 CheckStringFlag(kApplication, wtoken, appID, stApp) ||
2326 CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
2327 CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
2328 CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
2329 continue;
2331 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2332 "Warning: Unrecognized chrome registration modifier '%s'.",
2333 token);
2334 badFlag = PR_TRUE;
2337 if (badFlag || stApp == eBad || stAppVersion == eBad ||
2338 stOs == eBad || stOsVersion == eBad)
2339 continue;
2341 nsCOMPtr<nsIURI> resolved;
2342 rv = io->NewURI(nsDependentCString(uri), nsnull, manifestURI,
2343 getter_AddRefs(resolved));
2344 if (NS_FAILED(rv))
2345 continue;
2347 if (!CanLoadResource(resolved)) {
2348 LogMessageWithContext(resolved, line, nsIScriptError::warningFlag,
2349 "Warning: cannot register non-local URI '%s' as content.",
2350 uri);
2351 continue;
2354 PackageEntry* entry =
2355 static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
2356 & (const nsACString&) nsDependentCString(package),
2357 PL_DHASH_ADD));
2358 if (!entry)
2359 return NS_ERROR_OUT_OF_MEMORY;
2361 entry->baseURI = resolved;
2363 if (platform)
2364 entry->flags |= PackageEntry::PLATFORM_PACKAGE;
2365 if (xpcNativeWrappers)
2366 entry->flags |= PackageEntry::XPCNATIVEWRAPPERS;
2367 if (contentAccessible)
2368 entry->flags |= PackageEntry::CONTENT_ACCESSIBLE;
2369 if (xpc) {
2370 nsCAutoString urlp("chrome://");
2371 urlp.Append(package);
2372 urlp.Append('/');
2374 rv = xpc->FlagSystemFilenamePrefix(urlp.get(), xpcNativeWrappers);
2375 NS_ENSURE_SUCCESS(rv, rv);
2378 else if (!strcmp(token, "locale")) {
2379 if (aSkinOnly) {
2380 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2381 "Warning: Ignoring locale registration in skin-only manifest.");
2382 continue;
2384 char *package = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2385 char *provider = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2386 char *uri = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2387 if (!package || !provider || !uri) {
2388 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2389 "Warning: Malformed locale registration.");
2390 continue;
2393 EnsureLowerCase(package);
2395 TriState stAppVersion = eUnspecified;
2396 TriState stApp = eUnspecified;
2397 TriState stOs = eUnspecified;
2398 TriState stOsVersion = eUnspecified;
2400 PRBool badFlag = PR_FALSE;
2402 while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
2403 !badFlag) {
2404 NS_ConvertASCIItoUTF16 wtoken(token);
2405 ToLowerCase(wtoken);
2407 if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
2408 CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
2409 CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
2410 CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
2411 continue;
2413 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2414 "Warning: Unrecognized chrome registration modifier '%s'.",
2415 token);
2416 badFlag = PR_TRUE;
2419 if (badFlag || stApp == eBad || stAppVersion == eBad ||
2420 stOs == eBad || stOsVersion == eBad)
2421 continue;
2423 nsCOMPtr<nsIURI> resolved;
2424 rv = io->NewURI(nsDependentCString(uri), nsnull, manifestURI,
2425 getter_AddRefs(resolved));
2426 if (NS_FAILED(rv))
2427 continue;
2429 if (!CanLoadResource(resolved)) {
2430 LogMessageWithContext(resolved, line, nsIScriptError::warningFlag,
2431 "Warning: cannot register non-local URI '%s' as a locale.",
2432 uri);
2433 continue;
2436 PackageEntry* entry =
2437 static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
2438 & (const nsACString&) nsDependentCString(package),
2439 PL_DHASH_ADD));
2440 if (!entry)
2441 return NS_ERROR_OUT_OF_MEMORY;
2443 entry->locales.SetBase(nsDependentCString(provider), resolved);
2445 else if (!strcmp(token, "skin")) {
2446 char *package = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2447 char *provider = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2448 char *uri = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2449 if (!package || !provider || !uri) {
2450 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2451 "Warning: Malformed skin registration.");
2452 continue;
2455 EnsureLowerCase(package);
2457 TriState stAppVersion = eUnspecified;
2458 TriState stApp = eUnspecified;
2459 TriState stOs = eUnspecified;
2460 TriState stOsVersion = eUnspecified;
2462 PRBool badFlag = PR_FALSE;
2464 while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
2465 !badFlag) {
2466 NS_ConvertASCIItoUTF16 wtoken(token);
2467 ToLowerCase(wtoken);
2469 if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
2470 CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
2471 CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
2472 CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
2473 continue;
2475 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2476 "Warning: Unrecognized chrome registration modifier '%s'.",
2477 token);
2478 badFlag = PR_TRUE;
2481 if (badFlag || stApp == eBad || stAppVersion == eBad ||
2482 stOs == eBad || stOsVersion == eBad)
2483 continue;
2485 nsCOMPtr<nsIURI> resolved;
2486 rv = io->NewURI(nsDependentCString(uri), nsnull, manifestURI,
2487 getter_AddRefs(resolved));
2488 if (NS_FAILED(rv))
2489 continue;
2491 if (!CanLoadResource(resolved)) {
2492 LogMessageWithContext(resolved, line, nsIScriptError::warningFlag,
2493 "Warning: cannot register non-local URI '%s' as a skin.",
2494 uri);
2495 continue;
2498 PackageEntry* entry =
2499 static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
2500 & (const nsACString&) nsDependentCString(package),
2501 PL_DHASH_ADD));
2502 if (!entry)
2503 return NS_ERROR_OUT_OF_MEMORY;
2505 entry->skins.SetBase(nsDependentCString(provider), resolved);
2507 else if (!strcmp(token, "overlay")) {
2508 if (aSkinOnly) {
2509 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2510 "Warning: Ignoring overlay registration in skin-only manifest.");
2511 continue;
2513 char *base = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2514 char *overlay = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2515 if (!base || !overlay) {
2516 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2517 "Warning: malformed chrome overlay instruction.");
2518 continue;
2521 TriState stAppVersion = eUnspecified;
2522 TriState stApp = eUnspecified;
2523 TriState stOs = eUnspecified;
2524 TriState stOsVersion = eUnspecified;
2526 PRBool badFlag = PR_FALSE;
2528 while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
2529 !badFlag) {
2530 NS_ConvertASCIItoUTF16 wtoken(token);
2531 ToLowerCase(wtoken);
2533 if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
2534 CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
2535 CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
2536 CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
2537 continue;
2539 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2540 "Warning: Unrecognized chrome registration modifier '%s'.",
2541 token);
2542 badFlag = PR_TRUE;
2545 if (badFlag || stApp == eBad || stAppVersion == eBad ||
2546 stOs == eBad || stOsVersion == eBad)
2547 continue;
2549 nsCOMPtr<nsIURI> baseuri, overlayuri;
2550 rv = io->NewURI(nsDependentCString(base), nsnull, nsnull,
2551 getter_AddRefs(baseuri));
2552 rv |= io->NewURI(nsDependentCString(overlay), nsnull, nsnull,
2553 getter_AddRefs(overlayuri));
2554 if (NS_FAILED(rv)) {
2555 NS_WARNING("Could not make URIs for overlay directive. Ignoring.");
2556 continue;
2559 if (!CanLoadResource(overlayuri)) {
2560 LogMessageWithContext(overlayuri, line, nsIScriptError::warningFlag,
2561 "Warning: cannot register non-local URI '%s' as an overlay.",
2562 overlay);
2563 continue;
2566 mOverlayHash.Add(baseuri, overlayuri);
2568 else if (!strcmp(token, "style")) {
2569 char *base = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2570 char *overlay = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2571 if (!base || !overlay) {
2572 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2573 "Warning: malformed chrome style instruction.");
2574 continue;
2577 TriState stAppVersion = eUnspecified;
2578 TriState stApp = eUnspecified;
2579 TriState stOs = eUnspecified;
2580 TriState stOsVersion = eUnspecified;
2582 PRBool badFlag = PR_FALSE;
2584 while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
2585 !badFlag) {
2586 NS_ConvertASCIItoUTF16 wtoken(token);
2587 ToLowerCase(wtoken);
2589 if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
2590 CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
2591 CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
2592 CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
2593 continue;
2595 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2596 "Warning: Unrecognized chrome registration modifier '%s'.",
2597 token);
2598 badFlag = PR_TRUE;
2601 if (badFlag || stApp == eBad || stAppVersion == eBad ||
2602 stOs == eBad || stOsVersion == eBad)
2603 continue;
2605 nsCOMPtr<nsIURI> baseuri, overlayuri;
2606 rv = io->NewURI(nsDependentCString(base), nsnull, nsnull,
2607 getter_AddRefs(baseuri));
2608 rv |= io->NewURI(nsDependentCString(overlay), nsnull, nsnull,
2609 getter_AddRefs(overlayuri));
2610 if (NS_FAILED(rv))
2611 continue;
2613 if (!CanLoadResource(overlayuri)) {
2614 LogMessageWithContext(overlayuri, line, nsIScriptError::warningFlag,
2615 "Warning: cannot register non-local URI '%s' as a style overlay.",
2616 overlay);
2617 continue;
2620 mStyleHash.Add(baseuri, overlayuri);
2622 else if (!strcmp(token, "override")) {
2623 if (aSkinOnly) {
2624 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2625 "Warning: Ignoring override registration in skin-only manifest.");
2626 continue;
2629 char *chrome = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2630 char *resolved = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2631 if (!chrome || !resolved) {
2632 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2633 "Warning: malformed chrome override instruction.");
2634 continue;
2637 TriState stAppVersion = eUnspecified;
2638 TriState stApp = eUnspecified;
2639 TriState stOs = eUnspecified;
2640 TriState stOsVersion = eUnspecified;
2642 PRBool badFlag = PR_FALSE;
2644 while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
2645 !badFlag) {
2646 NS_ConvertASCIItoUTF16 wtoken(token);
2647 ToLowerCase(wtoken);
2649 if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
2650 CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
2651 CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
2652 CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
2653 continue;
2655 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2656 "Warning: Unrecognized chrome registration modifier '%s'.",
2657 token);
2658 badFlag = PR_TRUE;
2661 if (badFlag || stApp == eBad || stAppVersion == eBad ||
2662 stOs == eBad || stOsVersion == eBad)
2663 continue;
2665 nsCOMPtr<nsIURI> chromeuri, resolveduri;
2666 rv = io->NewURI(nsDependentCString(chrome), nsnull, nsnull,
2667 getter_AddRefs(chromeuri));
2668 rv |= io->NewURI(nsDependentCString(resolved), nsnull, manifestURI,
2669 getter_AddRefs(resolveduri));
2670 if (NS_FAILED(rv))
2671 continue;
2673 if (!CanLoadResource(resolveduri)) {
2674 LogMessageWithContext(resolveduri, line, nsIScriptError::warningFlag,
2675 "Warning: cannot register non-local URI '%s' as an override.",
2676 resolved);
2677 continue;
2680 mOverrideTable.Put(chromeuri, resolveduri);
2682 else if (!strcmp(token, "resource")) {
2683 if (aSkinOnly) {
2684 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2685 "Warning: Ignoring resource registration in skin-only manifest.");
2686 continue;
2689 char *package = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2690 char *uri = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
2691 if (!package || !uri) {
2692 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2693 "Warning: Malformed resource registration.");
2694 continue;
2697 EnsureLowerCase(package);
2699 TriState stAppVersion = eUnspecified;
2700 TriState stApp = eUnspecified;
2701 TriState stOsVersion = eUnspecified;
2702 TriState stOs = eUnspecified;
2704 PRBool badFlag = PR_FALSE;
2706 while (nsnull != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
2707 !badFlag) {
2708 NS_ConvertASCIItoUTF16 wtoken(token);
2709 ToLowerCase(wtoken);
2711 if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
2712 CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
2713 CheckVersionFlag(kOsVersion, wtoken, osVersion, vc, stOsVersion) ||
2714 CheckVersionFlag(kAppVersion, wtoken, appVersion, vc, stAppVersion))
2715 continue;
2717 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2718 "Warning: Unrecognized chrome registration modifier '%s'.",
2719 token);
2720 badFlag = PR_TRUE;
2723 if (badFlag || stApp == eBad || stAppVersion == eBad ||
2724 stOs == eBad || stOsVersion == eBad)
2725 continue;
2727 nsDependentCString host(package);
2729 PRBool exists;
2730 rv = rph->HasSubstitution(host, &exists);
2731 NS_ENSURE_SUCCESS(rv, rv);
2732 if (exists) {
2733 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2734 "Warning: Duplicate resource declaration for '%s' ignored.",
2735 package);
2736 continue;
2739 nsCOMPtr<nsIURI> resolved;
2740 rv = io->NewURI(nsDependentCString(uri), nsnull, manifestURI,
2741 getter_AddRefs(resolved));
2742 if (NS_FAILED(rv))
2743 continue;
2745 if (!CanLoadResource(resolved)) {
2746 LogMessageWithContext(resolved, line, nsIScriptError::warningFlag,
2747 "Warning: cannot register non-local URI '%s' as a resource.",
2748 uri);
2749 continue;
2752 rv = rph->SetSubstitution(host, resolved);
2753 NS_ENSURE_SUCCESS(rv, rv);
2755 else {
2756 LogMessageWithContext(manifestURI, line, nsIScriptError::warningFlag,
2757 "Warning: Ignoring unrecognized chrome manifest instruction.");
2761 return NS_OK;