Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "mozilla/dom/FallbackEncoding.h"
8 :
9 : #include "mozilla/Encoding.h"
10 : #include "mozilla/intl/LocaleService.h"
11 : #include "mozilla/Preferences.h"
12 : #include "mozilla/Services.h"
13 : #include "nsIObserverService.h"
14 : #include "nsUConvPropertySearch.h"
15 :
16 : using mozilla::intl::LocaleService;
17 :
18 : namespace mozilla {
19 : namespace dom {
20 :
21 : static constexpr nsUConvProp localesFallbacks[] = {
22 : #include "localesfallbacks.properties.h"
23 : };
24 :
25 : static constexpr nsUConvProp domainsFallbacks[] = {
26 : #include "domainsfallbacks.properties.h"
27 : };
28 :
29 : static constexpr nsUConvProp nonParticipatingDomains[] = {
30 : #include "nonparticipatingdomains.properties.h"
31 : };
32 :
33 3 : NS_IMPL_ISUPPORTS(FallbackEncoding, nsIObserver)
34 :
35 : FallbackEncoding* FallbackEncoding::sInstance = nullptr;
36 : bool FallbackEncoding::sGuessFallbackFromTopLevelDomain = true;
37 :
38 3 : FallbackEncoding::FallbackEncoding()
39 3 : : mFallback(nullptr)
40 : {
41 3 : MOZ_ASSERT(!FallbackEncoding::sInstance,
42 : "Singleton already exists.");
43 3 : }
44 :
45 : NotNull<const Encoding*>
46 2 : FallbackEncoding::Get()
47 : {
48 2 : if (mFallback) {
49 0 : return WrapNotNull(mFallback);
50 : }
51 :
52 : const nsAdoptingCString& override =
53 4 : Preferences::GetCString("intl.charset.fallback.override");
54 : // Don't let the user break things by setting the override to unreasonable
55 : // values via about:config
56 2 : auto encoding = Encoding::ForLabel(override);
57 2 : if (!encoding || !encoding->IsAsciiCompatible() ||
58 0 : encoding == UTF_8_ENCODING) {
59 2 : mFallback = nullptr;
60 : } else {
61 0 : mFallback = encoding;
62 : }
63 :
64 2 : if (mFallback) {
65 0 : return WrapNotNull(mFallback);
66 : }
67 :
68 4 : nsAutoCString locale;
69 2 : LocaleService::GetInstance()->GetAppLocaleAsLangTag(locale);
70 :
71 : // Let's lower case the string just in case unofficial language packs
72 : // don't stick to conventions.
73 2 : ToLowerCase(locale); // ASCII lowercasing with CString input!
74 :
75 : // Special case Traditional Chinese before throwing away stuff after the
76 : // language itself. Today we only ship zh-TW, but be defensive about
77 : // possible future values.
78 6 : if (locale.EqualsLiteral("zh-tw") ||
79 4 : locale.EqualsLiteral("zh-hk") ||
80 6 : locale.EqualsLiteral("zh-mo") ||
81 2 : locale.EqualsLiteral("zh-hant")) {
82 0 : mFallback = BIG5_ENCODING;
83 0 : return WrapNotNull(mFallback);
84 : }
85 :
86 : // Throw away regions and other variants to accommodate weird stuff seen
87 : // in telemetry--apparently unofficial language packs.
88 2 : int32_t index = locale.FindChar('-');
89 2 : if (index >= 0) {
90 2 : locale.Truncate(index);
91 : }
92 :
93 4 : nsAutoCString fallback;
94 2 : if (NS_FAILED(nsUConvPropertySearch::SearchPropertyValue(
95 : localesFallbacks, ArrayLength(localesFallbacks), locale, fallback))) {
96 2 : mFallback = WINDOWS_1252_ENCODING;
97 : } else {
98 0 : mFallback = Encoding::ForName(fallback);
99 : }
100 :
101 2 : return WrapNotNull(mFallback);
102 : }
103 :
104 : NotNull<const Encoding*>
105 2 : FallbackEncoding::FromLocale()
106 : {
107 2 : MOZ_ASSERT(FallbackEncoding::sInstance,
108 : "Using uninitialized fallback cache.");
109 2 : return FallbackEncoding::sInstance->Get();
110 : }
111 :
112 : // PrefChangedFunc
113 : void
114 0 : FallbackEncoding::PrefChanged(const char*, void*)
115 : {
116 0 : MOZ_ASSERT(FallbackEncoding::sInstance,
117 : "Pref callback called with null fallback cache.");
118 0 : FallbackEncoding::sInstance->Invalidate();
119 0 : }
120 :
121 : NS_IMETHODIMP
122 0 : FallbackEncoding::Observe(nsISupports *aSubject, const char *aTopic,
123 : const char16_t *aData)
124 : {
125 0 : MOZ_ASSERT(FallbackEncoding::sInstance,
126 : "Observe callback called with null fallback cache.");
127 0 : FallbackEncoding::sInstance->Invalidate();
128 0 : return NS_OK;
129 : }
130 :
131 : void
132 3 : FallbackEncoding::Initialize()
133 : {
134 3 : MOZ_ASSERT(!FallbackEncoding::sInstance,
135 : "Initializing pre-existing fallback cache.");
136 3 : FallbackEncoding::sInstance = new FallbackEncoding;
137 : Preferences::RegisterCallback(FallbackEncoding::PrefChanged,
138 : "intl.charset.fallback.override",
139 3 : nullptr);
140 : Preferences::AddBoolVarCache(&sGuessFallbackFromTopLevelDomain,
141 3 : "intl.charset.fallback.tld");
142 :
143 6 : nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
144 3 : if (obs) {
145 3 : obs->AddObserver(sInstance, "intl:requested-locales-changed", true);
146 : }
147 3 : }
148 :
149 : void
150 0 : FallbackEncoding::Shutdown()
151 : {
152 0 : MOZ_ASSERT(FallbackEncoding::sInstance,
153 : "Releasing non-existent fallback cache.");
154 0 : nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
155 0 : if (obs) {
156 0 : obs->RemoveObserver(sInstance, "intl:requested-locales-changed");
157 : }
158 0 : delete FallbackEncoding::sInstance;
159 0 : FallbackEncoding::sInstance = nullptr;
160 0 : }
161 :
162 : bool
163 0 : FallbackEncoding::IsParticipatingTopLevelDomain(const nsACString& aTLD)
164 : {
165 0 : nsAutoCString dummy;
166 0 : return NS_FAILED(nsUConvPropertySearch::SearchPropertyValue(
167 : nonParticipatingDomains,
168 : ArrayLength(nonParticipatingDomains),
169 : aTLD,
170 : dummy));
171 : }
172 :
173 : NotNull<const Encoding*>
174 0 : FallbackEncoding::FromTopLevelDomain(const nsACString& aTLD)
175 : {
176 0 : nsAutoCString fallback;
177 0 : if (NS_FAILED(nsUConvPropertySearch::SearchPropertyValue(
178 : domainsFallbacks, ArrayLength(domainsFallbacks), aTLD, fallback))) {
179 0 : return WINDOWS_1252_ENCODING;
180 : }
181 0 : return Encoding::ForName(fallback);
182 : }
183 :
184 : } // namespace dom
185 : } // namespace mozilla
|