1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * the Mozilla Foundation.
19 : * Portions created by the Initial Developer are Copyright (C) 2010
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Josh Matthews <josh@joshmatthews.net> (Initial Developer)
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either the GNU General Public License Version 2 or later (the "GPL"), or
27 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : #include "mozilla/dom/PContentParent.h"
40 : #include "RegistryMessageUtils.h"
41 : #include "nsResProtocolHandler.h"
42 :
43 : #include "nsChromeRegistryChrome.h"
44 :
45 : #if defined(XP_WIN)
46 : #include <windows.h>
47 : #elif defined(XP_MACOSX)
48 : #include <CoreServices/CoreServices.h>
49 : #elif defined(MOZ_WIDGET_GTK2)
50 : #include <gtk/gtk.h>
51 : #endif
52 :
53 : #include "nsArrayEnumerator.h"
54 : #include "nsAppDirectoryServiceDefs.h"
55 : #include "nsComponentManager.h"
56 : #include "nsEnumeratorUtils.h"
57 : #include "nsNetUtil.h"
58 : #include "nsStringEnumerator.h"
59 : #include "nsTextFormatter.h"
60 : #include "nsUnicharUtils.h"
61 : #include "nsXPCOMCIDInternal.h"
62 : #include "nsZipArchive.h"
63 :
64 : #include "mozilla/LookAndFeel.h"
65 :
66 : #include "nsICommandLine.h"
67 : #include "nsILocaleService.h"
68 : #include "nsILocalFile.h"
69 : #include "nsIObserverService.h"
70 : #include "nsIPrefBranch.h"
71 : #include "nsIPrefService.h"
72 : #include "nsIResProtocolHandler.h"
73 : #include "nsIScriptError.h"
74 : #include "nsIVersionComparator.h"
75 : #include "nsIXPConnect.h"
76 : #include "nsIXULAppInfo.h"
77 : #include "nsIXULRuntime.h"
78 :
79 : #define UILOCALE_CMD_LINE_ARG "UILocale"
80 :
81 : #define MATCH_OS_LOCALE_PREF "intl.locale.matchOS"
82 : #define SELECTED_LOCALE_PREF "general.useragent.locale"
83 : #define SELECTED_SKIN_PREF "general.skins.selectedSkin"
84 :
85 : using namespace mozilla;
86 :
87 : static PLDHashOperator
88 4736 : RemoveAll(PLDHashTable *table, PLDHashEntryHdr *entry, PRUint32 number, void *arg)
89 : {
90 4736 : return (PLDHashOperator) (PL_DHASH_NEXT | PL_DHASH_REMOVE);
91 : }
92 :
93 : // We use a "best-fit" algorithm for matching locales and themes.
94 : // 1) the exact selected locale/theme
95 : // 2) (locales only) same language, different country
96 : // e.g. en-GB is the selected locale, only en-US is available
97 : // 3) any available locale/theme
98 :
99 : /**
100 : * Match the language-part of two lang-COUNTRY codes, hopefully but
101 : * not guaranteed to be in the form ab-CD or abz-CD. "ab" should also
102 : * work, any other garbage-in will produce undefined results as long
103 : * as it does not crash.
104 : */
105 : static bool
106 45 : LanguagesMatch(const nsACString& a, const nsACString& b)
107 : {
108 45 : if (a.Length() < 2 || b.Length() < 2)
109 0 : return false;
110 :
111 45 : nsACString::const_iterator as, ae, bs, be;
112 45 : a.BeginReading(as);
113 45 : a.EndReading(ae);
114 45 : b.BeginReading(bs);
115 45 : b.EndReading(be);
116 :
117 45 : while (*as == *bs) {
118 3 : if (*as == '-')
119 1 : return true;
120 :
121 2 : ++as; ++bs;
122 :
123 : // reached the end
124 2 : if (as == ae && bs == be)
125 0 : return true;
126 :
127 : // "a" is short
128 2 : if (as == ae)
129 0 : return (*bs == '-');
130 :
131 : // "b" is short
132 2 : if (bs == be)
133 0 : return (*as == '-');
134 : }
135 :
136 44 : return false;
137 : }
138 :
139 1419 : nsChromeRegistryChrome::nsChromeRegistryChrome()
140 1419 : : mProfileLoaded(false)
141 : {
142 1419 : mPackagesHash.ops = nsnull;
143 1419 : }
144 :
145 4257 : nsChromeRegistryChrome::~nsChromeRegistryChrome()
146 : {
147 1419 : if (mPackagesHash.ops)
148 1419 : PL_DHashTableFinish(&mPackagesHash);
149 5676 : }
150 :
151 : nsresult
152 1419 : nsChromeRegistryChrome::Init()
153 : {
154 1419 : nsresult rv = nsChromeRegistry::Init();
155 1419 : if (NS_FAILED(rv))
156 0 : return rv;
157 :
158 2838 : if (!mOverlayHash.Init() ||
159 1419 : !mStyleHash.Init())
160 0 : return NS_ERROR_FAILURE;
161 :
162 1419 : mSelectedLocale = NS_LITERAL_CSTRING("en-US");
163 1419 : mSelectedSkin = NS_LITERAL_CSTRING("classic/1.0");
164 :
165 1419 : if (!PL_DHashTableInit(&mPackagesHash, &kTableOps,
166 1419 : nsnull, sizeof(PackageEntry), 16))
167 0 : return NS_ERROR_FAILURE;
168 :
169 1419 : bool safeMode = false;
170 2838 : nsCOMPtr<nsIXULRuntime> xulrun (do_GetService(XULAPPINFO_SERVICE_CONTRACTID));
171 1419 : if (xulrun)
172 1419 : xulrun->GetInSafeMode(&safeMode);
173 :
174 2838 : nsCOMPtr<nsIPrefService> prefserv (do_GetService(NS_PREFSERVICE_CONTRACTID));
175 2838 : nsCOMPtr<nsIPrefBranch> prefs;
176 :
177 1419 : if (safeMode)
178 0 : prefserv->GetDefaultBranch(nsnull, getter_AddRefs(prefs));
179 : else
180 1419 : prefs = do_QueryInterface(prefserv);
181 :
182 1419 : if (!prefs) {
183 0 : NS_WARNING("Could not get pref service!");
184 : }
185 : else {
186 2838 : nsXPIDLCString provider;
187 1419 : rv = prefs->GetCharPref(SELECTED_SKIN_PREF, getter_Copies(provider));
188 1419 : if (NS_SUCCEEDED(rv))
189 1419 : mSelectedSkin = provider;
190 :
191 1419 : SelectLocaleFromPref(prefs);
192 :
193 1419 : rv = prefs->AddObserver(MATCH_OS_LOCALE_PREF, this, true);
194 1419 : rv = prefs->AddObserver(SELECTED_LOCALE_PREF, this, true);
195 1419 : rv = prefs->AddObserver(SELECTED_SKIN_PREF, this, true);
196 : }
197 :
198 2838 : nsCOMPtr<nsIObserverService> obsService = mozilla::services::GetObserverService();
199 1419 : if (obsService) {
200 1419 : obsService->AddObserver(this, "command-line-startup", true);
201 1419 : obsService->AddObserver(this, "profile-initial-state", true);
202 : }
203 :
204 1419 : return NS_OK;
205 : }
206 :
207 : NS_IMETHODIMP
208 0 : nsChromeRegistryChrome::CheckForOSAccessibility()
209 : {
210 : PRInt32 useAccessibilityTheme =
211 0 : LookAndFeel::GetInt(LookAndFeel::eIntID_UseAccessibilityTheme, 0);
212 :
213 0 : if (useAccessibilityTheme) {
214 : /* Set the skin to classic and remove pref observers */
215 0 : if (!mSelectedSkin.EqualsLiteral("classic/1.0")) {
216 0 : mSelectedSkin.AssignLiteral("classic/1.0");
217 0 : RefreshSkins();
218 : }
219 :
220 0 : nsCOMPtr<nsIPrefBranch> prefs (do_GetService(NS_PREFSERVICE_CONTRACTID));
221 0 : if (prefs) {
222 0 : prefs->RemoveObserver(SELECTED_SKIN_PREF, this);
223 : }
224 : }
225 :
226 0 : return NS_OK;
227 : }
228 :
229 : NS_IMETHODIMP
230 0 : nsChromeRegistryChrome::GetLocalesForPackage(const nsACString& aPackage,
231 : nsIUTF8StringEnumerator* *aResult)
232 : {
233 0 : nsTArray<nsCString> *a = new nsTArray<nsCString>;
234 0 : if (!a)
235 0 : return NS_ERROR_OUT_OF_MEMORY;
236 :
237 : PackageEntry* entry =
238 : static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
239 : & aPackage,
240 0 : PL_DHASH_LOOKUP));
241 :
242 0 : if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
243 0 : entry->locales.EnumerateToArray(a);
244 : }
245 :
246 0 : nsresult rv = NS_NewAdoptingUTF8StringEnumerator(aResult, a);
247 0 : if (NS_FAILED(rv))
248 0 : delete a;
249 :
250 0 : return rv;
251 : }
252 :
253 : static nsresult
254 11 : getUILangCountry(nsACString& aUILang)
255 : {
256 : nsresult rv;
257 :
258 22 : nsCOMPtr<nsILocaleService> localeService = do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv);
259 11 : NS_ENSURE_SUCCESS(rv, rv);
260 :
261 22 : nsAutoString uiLang;
262 11 : rv = localeService->GetLocaleComponentForUserAgent(uiLang);
263 11 : NS_ENSURE_SUCCESS(rv, rv);
264 :
265 11 : CopyUTF16toUTF8(uiLang, aUILang);
266 11 : return NS_OK;
267 : }
268 :
269 : NS_IMETHODIMP
270 0 : nsChromeRegistryChrome::IsLocaleRTL(const nsACString& package, bool *aResult)
271 : {
272 0 : *aResult = false;
273 :
274 0 : nsCAutoString locale;
275 0 : GetSelectedLocale(package, locale);
276 0 : if (locale.Length() < 2)
277 0 : return NS_OK;
278 :
279 : // first check the intl.uidirection.<locale> preference, and if that is not
280 : // set, check the same preference but with just the first two characters of
281 : // the locale. If that isn't set, default to left-to-right.
282 0 : nsCAutoString prefString = NS_LITERAL_CSTRING("intl.uidirection.") + locale;
283 0 : nsCOMPtr<nsIPrefBranch> prefBranch (do_GetService(NS_PREFSERVICE_CONTRACTID));
284 0 : if (!prefBranch)
285 0 : return NS_OK;
286 :
287 0 : nsXPIDLCString dir;
288 0 : prefBranch->GetCharPref(prefString.get(), getter_Copies(dir));
289 0 : if (dir.IsEmpty()) {
290 0 : PRInt32 hyphen = prefString.FindChar('-');
291 0 : if (hyphen >= 1) {
292 0 : nsCAutoString shortPref(Substring(prefString, 0, hyphen));
293 0 : prefBranch->GetCharPref(shortPref.get(), getter_Copies(dir));
294 : }
295 : }
296 0 : *aResult = dir.EqualsLiteral("rtl");
297 0 : return NS_OK;
298 : }
299 :
300 : nsresult
301 50 : nsChromeRegistryChrome::GetSelectedLocale(const nsACString& aPackage,
302 : nsACString& aLocale)
303 : {
304 : PackageEntry* entry =
305 : static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
306 : & aPackage,
307 50 : PL_DHASH_LOOKUP));
308 :
309 50 : if (PL_DHASH_ENTRY_IS_FREE(entry))
310 0 : return NS_ERROR_FAILURE;
311 :
312 50 : aLocale = entry->locales.GetSelected(mSelectedLocale, nsProviderArray::LOCALE);
313 50 : if (aLocale.IsEmpty())
314 0 : return NS_ERROR_FAILURE;
315 :
316 50 : return NS_OK;
317 : }
318 :
319 : nsresult
320 1464 : nsChromeRegistryChrome::SelectLocaleFromPref(nsIPrefBranch* prefs)
321 : {
322 : nsresult rv;
323 1464 : bool matchOSLocale = false;
324 1464 : rv = prefs->GetBoolPref(MATCH_OS_LOCALE_PREF, &matchOSLocale);
325 :
326 1464 : if (NS_SUCCEEDED(rv) && matchOSLocale) {
327 : // compute lang and region code only when needed!
328 22 : nsCAutoString uiLocale;
329 11 : rv = getUILangCountry(uiLocale);
330 11 : if (NS_SUCCEEDED(rv))
331 22 : mSelectedLocale = uiLocale;
332 : }
333 : else {
334 2906 : nsXPIDLCString provider;
335 1453 : rv = prefs->GetCharPref(SELECTED_LOCALE_PREF, getter_Copies(provider));
336 1453 : if (NS_SUCCEEDED(rv)) {
337 1453 : mSelectedLocale = provider;
338 : }
339 : }
340 :
341 1464 : if (NS_FAILED(rv))
342 0 : NS_ERROR("Couldn't select locale from pref!");
343 :
344 1464 : return rv;
345 : }
346 :
347 : NS_IMETHODIMP
348 144 : nsChromeRegistryChrome::Observe(nsISupports *aSubject, const char *aTopic,
349 : const PRUnichar *someData)
350 : {
351 144 : nsresult rv = NS_OK;
352 :
353 144 : if (!strcmp(NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, aTopic)) {
354 288 : nsCOMPtr<nsIPrefBranch> prefs (do_QueryInterface(aSubject));
355 144 : NS_ASSERTION(prefs, "Bad observer call!");
356 :
357 288 : NS_ConvertUTF16toUTF8 pref(someData);
358 :
359 284 : if (pref.EqualsLiteral(MATCH_OS_LOCALE_PREF) ||
360 140 : pref.EqualsLiteral(SELECTED_LOCALE_PREF)) {
361 39 : rv = UpdateSelectedLocale();
362 39 : if (NS_SUCCEEDED(rv) && mProfileLoaded)
363 0 : FlushAllCaches();
364 : }
365 105 : else if (pref.EqualsLiteral(SELECTED_SKIN_PREF)) {
366 210 : nsXPIDLCString provider;
367 105 : rv = prefs->GetCharPref(pref.get(), getter_Copies(provider));
368 105 : if (NS_FAILED(rv)) {
369 0 : NS_ERROR("Couldn't get new skin pref!");
370 0 : return rv;
371 : }
372 :
373 105 : mSelectedSkin = provider;
374 210 : RefreshSkins();
375 : } else {
376 0 : NS_ERROR("Unexpected pref!");
377 : }
378 : }
379 0 : else if (!strcmp("command-line-startup", aTopic)) {
380 0 : nsCOMPtr<nsICommandLine> cmdLine (do_QueryInterface(aSubject));
381 0 : if (cmdLine) {
382 0 : nsAutoString uiLocale;
383 0 : rv = cmdLine->HandleFlagWithParam(NS_LITERAL_STRING(UILOCALE_CMD_LINE_ARG),
384 0 : false, uiLocale);
385 0 : if (NS_SUCCEEDED(rv) && !uiLocale.IsEmpty()) {
386 0 : CopyUTF16toUTF8(uiLocale, mSelectedLocale);
387 0 : nsCOMPtr<nsIPrefBranch> prefs (do_GetService(NS_PREFSERVICE_CONTRACTID));
388 0 : if (prefs) {
389 0 : prefs->RemoveObserver(SELECTED_LOCALE_PREF, this);
390 : }
391 : }
392 : }
393 : }
394 0 : else if (!strcmp("profile-initial-state", aTopic)) {
395 0 : mProfileLoaded = true;
396 : }
397 : else {
398 0 : NS_ERROR("Unexpected observer topic!");
399 : }
400 :
401 144 : return rv;
402 : }
403 :
404 : NS_IMETHODIMP
405 205 : nsChromeRegistryChrome::CheckForNewChrome()
406 : {
407 205 : PL_DHashTableEnumerate(&mPackagesHash, RemoveAll, nsnull);
408 205 : mOverlayHash.Clear();
409 205 : mStyleHash.Clear();
410 205 : mOverrideTable.Clear();
411 :
412 205 : nsComponentManagerImpl::gComponentManager->RereadChromeManifests();
413 205 : return NS_OK;
414 : }
415 :
416 45 : nsresult nsChromeRegistryChrome::UpdateSelectedLocale()
417 : {
418 45 : nsresult rv = NS_OK;
419 90 : nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
420 45 : if (prefs) {
421 45 : rv = SelectLocaleFromPref(prefs);
422 45 : if (NS_SUCCEEDED(rv)) {
423 : nsCOMPtr<nsIObserverService> obsSvc =
424 90 : mozilla::services::GetObserverService();
425 45 : NS_ASSERTION(obsSvc, "Couldn't get observer service.");
426 45 : obsSvc->NotifyObservers((nsIChromeRegistry*) this,
427 45 : "selected-locale-has-changed", nsnull);
428 : }
429 : }
430 :
431 45 : return rv;
432 : }
433 :
434 : static void
435 0 : SerializeURI(nsIURI* aURI,
436 : SerializedURI& aSerializedURI)
437 : {
438 0 : if (!aURI)
439 0 : return;
440 :
441 0 : aURI->GetSpec(aSerializedURI.spec);
442 0 : aURI->GetOriginCharset(aSerializedURI.charset);
443 : }
444 :
445 : static PLDHashOperator
446 0 : EnumerateOverride(nsIURI* aURIKey,
447 : nsIURI* aURI,
448 : void* aArg)
449 : {
450 : nsTArray<OverrideMapping>* overrides =
451 0 : static_cast<nsTArray<OverrideMapping>*>(aArg);
452 :
453 0 : SerializedURI chromeURI, overrideURI;
454 :
455 0 : SerializeURI(aURIKey, chromeURI);
456 0 : SerializeURI(aURI, overrideURI);
457 :
458 : OverrideMapping override = {
459 : chromeURI, overrideURI
460 0 : };
461 0 : overrides->AppendElement(override);
462 0 : return (PLDHashOperator)PL_DHASH_NEXT;
463 : }
464 :
465 : struct EnumerationArgs
466 : {
467 : InfallibleTArray<ChromePackage>& packages;
468 : const nsCString& selectedLocale;
469 : const nsCString& selectedSkin;
470 : };
471 :
472 : void
473 0 : nsChromeRegistryChrome::SendRegisteredChrome(
474 : mozilla::dom::PContentParent* aParent)
475 : {
476 0 : InfallibleTArray<ChromePackage> packages;
477 0 : InfallibleTArray<ResourceMapping> resources;
478 0 : InfallibleTArray<OverrideMapping> overrides;
479 :
480 : EnumerationArgs args = {
481 : packages, mSelectedLocale, mSelectedSkin
482 0 : };
483 0 : PL_DHashTableEnumerate(&mPackagesHash, CollectPackages, &args);
484 :
485 0 : nsCOMPtr<nsIIOService> io (do_GetIOService());
486 0 : NS_ENSURE_TRUE(io, );
487 :
488 0 : nsCOMPtr<nsIProtocolHandler> ph;
489 0 : nsresult rv = io->GetProtocolHandler("resource", getter_AddRefs(ph));
490 0 : NS_ENSURE_SUCCESS(rv, );
491 :
492 : //FIXME: Some substitutions are set up lazily and might not exist yet
493 0 : nsCOMPtr<nsIResProtocolHandler> irph (do_QueryInterface(ph));
494 0 : nsResProtocolHandler* rph = static_cast<nsResProtocolHandler*>(irph.get());
495 0 : rph->CollectSubstitutions(resources);
496 :
497 0 : mOverrideTable.EnumerateRead(&EnumerateOverride, &overrides);
498 :
499 : bool success = aParent->SendRegisterChrome(packages, resources, overrides,
500 0 : mSelectedLocale);
501 0 : NS_ENSURE_TRUE(success, );
502 : }
503 :
504 : PLDHashOperator
505 0 : nsChromeRegistryChrome::CollectPackages(PLDHashTable *table,
506 : PLDHashEntryHdr *entry,
507 : PRUint32 number,
508 : void *arg)
509 : {
510 0 : EnumerationArgs* args = static_cast<EnumerationArgs*>(arg);
511 0 : PackageEntry* package = static_cast<PackageEntry*>(entry);
512 :
513 0 : SerializedURI contentURI, localeURI, skinURI;
514 :
515 0 : SerializeURI(package->baseURI, contentURI);
516 : SerializeURI(package->locales.GetBase(args->selectedLocale,
517 0 : nsProviderArray::LOCALE), localeURI);
518 : SerializeURI(package->skins.GetBase(args->selectedSkin, nsProviderArray::ANY),
519 0 : skinURI);
520 :
521 : ChromePackage chromePackage = {
522 : package->package,
523 : contentURI,
524 : localeURI,
525 : skinURI,
526 : package->flags
527 0 : };
528 0 : args->packages.AppendElement(chromePackage);
529 0 : return (PLDHashOperator)PL_DHASH_NEXT;
530 : }
531 :
532 : static bool
533 85562 : CanLoadResource(nsIURI* aResourceURI)
534 : {
535 85562 : bool isLocalResource = false;
536 : (void)NS_URIChainHasFlags(aResourceURI,
537 : nsIProtocolHandler::URI_IS_LOCAL_RESOURCE,
538 85562 : &isLocalResource);
539 85562 : return isLocalResource;
540 : }
541 :
542 : nsIURI*
543 3039 : nsChromeRegistryChrome::GetBaseURIFromPackage(const nsCString& aPackage,
544 : const nsCString& aProvider,
545 : const nsCString& aPath)
546 : {
547 : PackageEntry* entry =
548 : static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
549 : &aPackage,
550 3039 : PL_DHASH_LOOKUP));
551 :
552 3039 : if (PL_DHASH_ENTRY_IS_FREE(entry)) {
553 917 : if (!mInitialized)
554 0 : return nsnull;
555 :
556 : LogMessage("No chrome package registered for chrome://%s/%s/%s",
557 917 : aPackage.get(), aProvider.get(), aPath.get());
558 :
559 917 : return nsnull;
560 : }
561 :
562 2122 : if (aProvider.EqualsLiteral("locale")) {
563 1728 : return entry->locales.GetBase(mSelectedLocale, nsProviderArray::LOCALE);
564 : }
565 394 : else if (aProvider.EqualsLiteral("skin")) {
566 8 : return entry->skins.GetBase(mSelectedSkin, nsProviderArray::ANY);
567 : }
568 386 : else if (aProvider.EqualsLiteral("content")) {
569 386 : return entry->baseURI;
570 : }
571 0 : return nsnull;
572 : }
573 :
574 : nsresult
575 3046 : nsChromeRegistryChrome::GetFlagsFromPackage(const nsCString& aPackage,
576 : PRUint32* aFlags)
577 : {
578 : PackageEntry* entry =
579 : static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
580 : & (nsACString&) aPackage,
581 3046 : PL_DHASH_LOOKUP));
582 3046 : if (PL_DHASH_ENTRY_IS_FREE(entry))
583 917 : return NS_ERROR_NOT_AVAILABLE;
584 :
585 2129 : *aFlags = entry->flags;
586 2129 : return NS_OK;
587 : }
588 :
589 : PLHashNumber
590 64657 : nsChromeRegistryChrome::HashKey(PLDHashTable *table, const void *key)
591 : {
592 64657 : const nsACString& str = *reinterpret_cast<const nsACString*>(key);
593 64657 : return HashString(str);
594 : }
595 :
596 : bool
597 25429 : nsChromeRegistryChrome::MatchKey(PLDHashTable *table, const PLDHashEntryHdr *entry,
598 : const void *key)
599 : {
600 25429 : const nsACString& str = *reinterpret_cast<const nsACString*>(key);
601 25429 : const PackageEntry* pentry = static_cast<const PackageEntry*>(entry);
602 25429 : return str.Equals(pentry->package);
603 : }
604 :
605 : void
606 37394 : nsChromeRegistryChrome::ClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
607 : {
608 37394 : PackageEntry* pentry = static_cast<PackageEntry*>(entry);
609 37394 : pentry->~PackageEntry();
610 37394 : }
611 :
612 : bool
613 37394 : nsChromeRegistryChrome::InitEntry(PLDHashTable *table, PLDHashEntryHdr *entry,
614 : const void *key)
615 : {
616 37394 : const nsACString& str = *reinterpret_cast<const nsACString*>(key);
617 :
618 37394 : new (entry) PackageEntry(str);
619 37394 : return true;
620 : }
621 :
622 : const PLDHashTableOps
623 : nsChromeRegistryChrome::kTableOps = {
624 : PL_DHashAllocTable,
625 : PL_DHashFreeTable,
626 : HashKey,
627 : MatchKey,
628 : PL_DHashMoveEntryStub,
629 : ClearEntry,
630 : PL_DHashFinalizeStub,
631 : InitEntry
632 : };
633 :
634 : nsChromeRegistryChrome::ProviderEntry*
635 37533 : nsChromeRegistryChrome::nsProviderArray::GetProvider(const nsACString& aPreferred, MatchType aType)
636 : {
637 37533 : PRInt32 i = mArray.Count();
638 37533 : if (!i)
639 35743 : return nsnull;
640 :
641 1790 : ProviderEntry* found = nsnull; // Only set if we find a partial-match locale
642 : ProviderEntry* entry;
643 :
644 3635 : while (i--) {
645 1801 : entry = reinterpret_cast<ProviderEntry*>(mArray[i]);
646 1801 : if (aPreferred.Equals(entry->provider))
647 1746 : return entry;
648 :
649 55 : if (aType != LOCALE)
650 10 : continue;
651 :
652 45 : if (LanguagesMatch(aPreferred, entry->provider)) {
653 1 : found = entry;
654 1 : continue;
655 : }
656 :
657 44 : if (!found && entry->provider.EqualsLiteral("en-US"))
658 30 : found = entry;
659 : }
660 :
661 44 : if (!found && aType != EXACT)
662 9 : return entry;
663 :
664 35 : return found;
665 : }
666 :
667 : nsIURI*
668 1736 : nsChromeRegistryChrome::nsProviderArray::GetBase(const nsACString& aPreferred, MatchType aType)
669 : {
670 1736 : ProviderEntry* provider = GetProvider(aPreferred, aType);
671 :
672 1736 : if (!provider)
673 0 : return nsnull;
674 :
675 1736 : return provider->baseURI;
676 : }
677 :
678 : const nsACString&
679 50 : nsChromeRegistryChrome::nsProviderArray::GetSelected(const nsACString& aPreferred, MatchType aType)
680 : {
681 50 : ProviderEntry* entry = GetProvider(aPreferred, aType);
682 :
683 50 : if (entry)
684 50 : return entry->provider;
685 :
686 0 : return EmptyCString();
687 : }
688 :
689 : void
690 35747 : nsChromeRegistryChrome::nsProviderArray::SetBase(const nsACString& aProvider, nsIURI* aBaseURL)
691 : {
692 35747 : ProviderEntry* provider = GetProvider(aProvider, EXACT);
693 :
694 35747 : if (provider) {
695 0 : provider->baseURI = aBaseURL;
696 0 : return;
697 : }
698 :
699 : // no existing entries, add a new one
700 35747 : provider = new ProviderEntry(aProvider, aBaseURL);
701 35747 : if (!provider)
702 0 : return; // It's safe to silently fail on OOM
703 :
704 35747 : mArray.AppendElement(provider);
705 : }
706 :
707 : void
708 0 : nsChromeRegistryChrome::nsProviderArray::EnumerateToArray(nsTArray<nsCString> *a)
709 : {
710 0 : PRInt32 i = mArray.Count();
711 0 : while (i--) {
712 0 : ProviderEntry *entry = reinterpret_cast<ProviderEntry*>(mArray[i]);
713 0 : a->AppendElement(entry->provider);
714 : }
715 0 : }
716 :
717 : void
718 74788 : nsChromeRegistryChrome::nsProviderArray::Clear()
719 : {
720 74788 : PRInt32 i = mArray.Count();
721 185323 : while (i--) {
722 35747 : ProviderEntry* entry = reinterpret_cast<ProviderEntry*>(mArray[i]);
723 35747 : delete entry;
724 : }
725 :
726 74788 : mArray.Clear();
727 74788 : }
728 :
729 : void
730 12992 : nsChromeRegistryChrome::OverlayListEntry::AddURI(nsIURI* aURI)
731 : {
732 12992 : PRInt32 i = mArray.Count();
733 12992 : while (i--) {
734 : bool equals;
735 4872 : if (NS_SUCCEEDED(aURI->Equals(mArray[i], &equals)) && equals)
736 0 : return;
737 : }
738 :
739 12992 : mArray.AppendObject(aURI);
740 : }
741 :
742 : void
743 12992 : nsChromeRegistryChrome::OverlayListHash::Add(nsIURI* aBase, nsIURI* aOverlay)
744 : {
745 12992 : OverlayListEntry* entry = mTable.PutEntry(aBase);
746 12992 : if (entry)
747 12992 : entry->AddURI(aOverlay);
748 12992 : }
749 :
750 : const nsCOMArray<nsIURI>*
751 4 : nsChromeRegistryChrome::OverlayListHash::GetArray(nsIURI* aBase)
752 : {
753 4 : OverlayListEntry* entry = mTable.GetEntry(aBase);
754 4 : if (!entry)
755 4 : return nsnull;
756 :
757 0 : return &entry->mArray;
758 : }
759 :
760 : #ifdef MOZ_XUL
761 : NS_IMETHODIMP
762 2 : nsChromeRegistryChrome::GetStyleOverlays(nsIURI *aChromeURL,
763 : nsISimpleEnumerator **aResult)
764 : {
765 2 : const nsCOMArray<nsIURI>* parray = mStyleHash.GetArray(aChromeURL);
766 2 : if (!parray)
767 2 : return NS_NewEmptyEnumerator(aResult);
768 :
769 0 : return NS_NewArrayEnumerator(aResult, *parray);
770 : }
771 :
772 : NS_IMETHODIMP
773 2 : nsChromeRegistryChrome::GetXULOverlays(nsIURI *aChromeURL,
774 : nsISimpleEnumerator **aResult)
775 : {
776 2 : const nsCOMArray<nsIURI>* parray = mOverlayHash.GetArray(aChromeURL);
777 2 : if (!parray)
778 2 : return NS_NewEmptyEnumerator(aResult);
779 :
780 0 : return NS_NewArrayEnumerator(aResult, *parray);
781 : }
782 : #endif // MOZ_XUL
783 :
784 : nsIURI*
785 108947 : nsChromeRegistry::ManifestProcessingContext::GetManifestURI()
786 : {
787 108947 : if (!mManifestURI) {
788 26036 : nsCString uri;
789 13018 : mFile.GetURIString(uri);
790 13018 : NS_NewURI(getter_AddRefs(mManifestURI), uri);
791 : }
792 108947 : return mManifestURI;
793 : }
794 :
795 : nsIXPConnect*
796 0 : nsChromeRegistry::ManifestProcessingContext::GetXPConnect()
797 : {
798 0 : if (!mXPConnect)
799 0 : mXPConnect = do_GetService("@mozilla.org/js/xpc/XPConnect;1");
800 :
801 0 : return mXPConnect;
802 : }
803 :
804 : already_AddRefed<nsIURI>
805 108312 : nsChromeRegistry::ManifestProcessingContext::ResolveURI(const char* uri)
806 : {
807 108312 : nsIURI* baseuri = GetManifestURI();
808 108312 : if (!baseuri)
809 0 : return NULL;
810 :
811 216624 : nsCOMPtr<nsIURI> resolved;
812 108312 : nsresult rv = NS_NewURI(getter_AddRefs(resolved), uri, baseuri);
813 108312 : if (NS_FAILED(rv))
814 0 : return NULL;
815 :
816 108312 : return resolved.forget();
817 : }
818 :
819 : static void
820 63433 : EnsureLowerCase(char *aBuf)
821 : {
822 626595 : for (; *aBuf; ++aBuf) {
823 563162 : char ch = *aBuf;
824 563162 : if (ch >= 'A' && ch <= 'Z')
825 2 : *aBuf = ch + 'a' - 'A';
826 : }
827 63433 : }
828 :
829 : void
830 22782 : nsChromeRegistryChrome::ManifestContent(ManifestProcessingContext& cx, int lineno,
831 : char *const * argv, bool platform,
832 : bool contentaccessible)
833 : {
834 22782 : char* package = argv[0];
835 22782 : char* uri = argv[1];
836 :
837 22782 : EnsureLowerCase(package);
838 :
839 45564 : nsCOMPtr<nsIURI> resolved = cx.ResolveURI(uri);
840 22782 : if (!resolved) {
841 : LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
842 0 : "During chrome registration, unable to create URI '%s'.", uri);
843 : return;
844 : }
845 :
846 22782 : if (!CanLoadResource(resolved)) {
847 : LogMessageWithContext(resolved, lineno, nsIScriptError::warningFlag,
848 : "During chrome registration, cannot register non-local URI '%s' as content.",
849 7 : uri);
850 : return;
851 : }
852 :
853 : PackageEntry* entry =
854 : static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
855 22775 : & (const nsACString&) nsDependentCString(package),
856 22775 : PL_DHASH_ADD));
857 22775 : if (!entry)
858 : return;
859 :
860 22775 : entry->baseURI = resolved;
861 :
862 22775 : if (platform)
863 1624 : entry->flags |= PLATFORM_PACKAGE;
864 22775 : if (contentaccessible)
865 4876 : entry->flags |= CONTENT_ACCESSIBLE;
866 : }
867 :
868 : void
869 29253 : nsChromeRegistryChrome::ManifestLocale(ManifestProcessingContext& cx, int lineno,
870 : char *const * argv, bool platform,
871 : bool contentaccessible)
872 : {
873 29253 : char* package = argv[0];
874 29253 : char* provider = argv[1];
875 29253 : char* uri = argv[2];
876 :
877 29253 : EnsureLowerCase(package);
878 :
879 58506 : nsCOMPtr<nsIURI> resolved = cx.ResolveURI(uri);
880 29253 : if (!resolved) {
881 : LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
882 0 : "During chrome registration, unable to create URI '%s'.", uri);
883 : return;
884 : }
885 :
886 29253 : if (!CanLoadResource(resolved)) {
887 : LogMessageWithContext(resolved, lineno, nsIScriptError::warningFlag,
888 : "During chrome registration, cannot register non-local URI '%s' as content.",
889 7 : uri);
890 : return;
891 : }
892 :
893 : PackageEntry* entry =
894 : static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
895 29246 : & (const nsACString&) nsDependentCString(package),
896 29246 : PL_DHASH_ADD));
897 29246 : if (!entry)
898 : return;
899 :
900 29246 : entry->locales.SetBase(nsDependentCString(provider), resolved);
901 : }
902 :
903 : void
904 6508 : nsChromeRegistryChrome::ManifestSkin(ManifestProcessingContext& cx, int lineno,
905 : char *const * argv, bool platform,
906 : bool contentaccessible)
907 : {
908 6508 : char* package = argv[0];
909 6508 : char* provider = argv[1];
910 6508 : char* uri = argv[2];
911 :
912 6508 : EnsureLowerCase(package);
913 :
914 13016 : nsCOMPtr<nsIURI> resolved = cx.ResolveURI(uri);
915 6508 : if (!resolved) {
916 : LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
917 0 : "During chrome registration, unable to create URI '%s'.", uri);
918 : return;
919 : }
920 :
921 6508 : if (!CanLoadResource(resolved)) {
922 : LogMessageWithContext(resolved, lineno, nsIScriptError::warningFlag,
923 : "During chrome registration, cannot register non-local URI '%s' as content.",
924 7 : uri);
925 : return;
926 : }
927 :
928 : PackageEntry* entry =
929 : static_cast<PackageEntry*>(PL_DHashTableOperate(&mPackagesHash,
930 6501 : & (const nsACString&) nsDependentCString(package),
931 6501 : PL_DHASH_ADD));
932 6501 : if (!entry)
933 : return;
934 :
935 6501 : entry->skins.SetBase(nsDependentCString(provider), resolved);
936 : }
937 :
938 : void
939 9744 : nsChromeRegistryChrome::ManifestOverlay(ManifestProcessingContext& cx, int lineno,
940 : char *const * argv, bool platform,
941 : bool contentaccessible)
942 : {
943 9744 : char* base = argv[0];
944 9744 : char* overlay = argv[1];
945 :
946 19488 : nsCOMPtr<nsIURI> baseuri = cx.ResolveURI(base);
947 19488 : nsCOMPtr<nsIURI> overlayuri = cx.ResolveURI(overlay);
948 9744 : if (!baseuri || !overlayuri) {
949 : LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
950 0 : "During chrome registration, unable to create URI.");
951 : return;
952 : }
953 :
954 9744 : if (!CanLoadResource(overlayuri)) {
955 : LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
956 0 : "Cannot register non-local URI '%s' as an overlay.", overlay);
957 : return;
958 : }
959 :
960 19488 : mOverlayHash.Add(baseuri, overlayuri);
961 : }
962 :
963 : void
964 3248 : nsChromeRegistryChrome::ManifestStyle(ManifestProcessingContext& cx, int lineno,
965 : char *const * argv, bool platform,
966 : bool contentaccessible)
967 : {
968 3248 : char* base = argv[0];
969 3248 : char* overlay = argv[1];
970 :
971 6496 : nsCOMPtr<nsIURI> baseuri = cx.ResolveURI(base);
972 6496 : nsCOMPtr<nsIURI> overlayuri = cx.ResolveURI(overlay);
973 3248 : if (!baseuri || !overlayuri) {
974 : LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
975 0 : "During chrome registration, unable to create URI.");
976 : return;
977 : }
978 :
979 3248 : if (!CanLoadResource(overlayuri)) {
980 : LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
981 0 : "Cannot register non-local URI '%s' as a style overlay.", overlay);
982 : return;
983 : }
984 :
985 6496 : mStyleHash.Add(baseuri, overlayuri);
986 : }
987 :
988 : void
989 9758 : nsChromeRegistryChrome::ManifestOverride(ManifestProcessingContext& cx, int lineno,
990 : char *const * argv, bool platform,
991 : bool contentaccessible)
992 : {
993 9758 : char* chrome = argv[0];
994 9758 : char* resolved = argv[1];
995 :
996 19516 : nsCOMPtr<nsIURI> chromeuri = cx.ResolveURI(chrome);
997 19516 : nsCOMPtr<nsIURI> resolveduri = cx.ResolveURI(resolved);
998 9758 : if (!chromeuri || !resolveduri) {
999 : LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
1000 0 : "During chrome registration, unable to create URI.");
1001 : return;
1002 : }
1003 :
1004 9758 : if (!CanLoadResource(resolveduri)) {
1005 : LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
1006 7 : "Cannot register non-local URI '%s' for an override.", resolved);
1007 : return;
1008 : }
1009 19509 : mOverrideTable.Put(chromeuri, resolveduri);
1010 : }
1011 :
1012 : void
1013 4890 : nsChromeRegistryChrome::ManifestResource(ManifestProcessingContext& cx, int lineno,
1014 : char *const * argv, bool platform,
1015 : bool contentaccessible)
1016 : {
1017 4890 : char* package = argv[0];
1018 4890 : char* uri = argv[1];
1019 :
1020 4890 : EnsureLowerCase(package);
1021 9780 : nsDependentCString host(package);
1022 :
1023 9780 : nsCOMPtr<nsIIOService> io = mozilla::services::GetIOService();
1024 4890 : if (!io) {
1025 0 : NS_WARNING("No IO service trying to process chrome manifests");
1026 : return;
1027 : }
1028 :
1029 9780 : nsCOMPtr<nsIProtocolHandler> ph;
1030 4890 : nsresult rv = io->GetProtocolHandler("resource", getter_AddRefs(ph));
1031 4890 : if (NS_FAILED(rv))
1032 : return;
1033 :
1034 9780 : nsCOMPtr<nsIResProtocolHandler> rph = do_QueryInterface(ph);
1035 :
1036 4890 : bool exists = false;
1037 4890 : rv = rph->HasSubstitution(host, &exists);
1038 4890 : if (exists) {
1039 : LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
1040 621 : "Duplicate resource declaration for '%s' ignored.", package);
1041 : return;
1042 : }
1043 :
1044 8538 : nsCOMPtr<nsIURI> resolved = cx.ResolveURI(uri);
1045 4269 : if (!resolved) {
1046 : LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
1047 0 : "During chrome registration, unable to create URI '%s'.", uri);
1048 : return;
1049 : }
1050 :
1051 4269 : if (!CanLoadResource(resolved)) {
1052 : LogMessageWithContext(cx.GetManifestURI(), lineno, nsIScriptError::warningFlag,
1053 : "Warning: cannot register non-local URI '%s' as a resource.",
1054 7 : uri);
1055 : return;
1056 : }
1057 :
1058 8531 : rph->SetSubstitution(host, resolved);
1059 : }
|