1 : /* -*- Mode: C++; tab-width: 2; 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 Communicator client code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either of the GNU General Public License Version 2 or later (the "GPL"),
26 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : #include <locale.h>
39 :
40 : #include "mozilla/Util.h"
41 :
42 : #include "nsIPlatformCharset.h"
43 : #include "pratom.h"
44 : #include "nsUConvPropertySearch.h"
45 : #include "nsCOMPtr.h"
46 : #include "nsReadableUtils.h"
47 : #include "nsIComponentManager.h"
48 : #include "nsIServiceManager.h"
49 : #include "nsIUnicodeDecoder.h"
50 : #include "nsIUnicodeEncoder.h"
51 : #include "nsICharsetConverterManager.h"
52 : #include "nsEncoderDecoderUtils.h"
53 : #if HAVE_GNU_LIBC_VERSION_H
54 : #include <gnu/libc-version.h>
55 : #endif
56 : #ifdef HAVE_NL_TYPES_H
57 : #include <nl_types.h>
58 : #endif
59 : #if HAVE_LANGINFO_CODESET
60 : #include <langinfo.h>
61 : #endif
62 : #include "nsPlatformCharset.h"
63 : #include "prinit.h"
64 : #include "nsUnicharUtils.h"
65 :
66 : using namespace mozilla;
67 :
68 : static const char* kUnixCharsets[][3] = {
69 : #include "unixcharset.properties.h"
70 : };
71 :
72 2334 : NS_IMPL_THREADSAFE_ISUPPORTS1(nsPlatformCharset, nsIPlatformCharset)
73 :
74 241 : nsPlatformCharset::nsPlatformCharset()
75 : {
76 241 : }
77 :
78 : nsresult
79 0 : nsPlatformCharset::ConvertLocaleToCharsetUsingDeprecatedConfig(nsACString& locale, nsACString& oResult)
80 : {
81 0 : if (!(locale.IsEmpty())) {
82 0 : nsCAutoString platformLocaleKey;
83 : // note: NS_LITERAL_STRING("locale." OSTYPE ".") does not compile on AIX
84 0 : platformLocaleKey.AssignLiteral("locale.");
85 0 : platformLocaleKey.Append(OSTYPE);
86 0 : platformLocaleKey.AppendLiteral(".");
87 0 : platformLocaleKey.Append(locale);
88 :
89 : nsresult res = nsUConvPropertySearch::SearchPropertyValue(kUnixCharsets,
90 0 : ArrayLength(kUnixCharsets), platformLocaleKey, oResult);
91 0 : if (NS_SUCCEEDED(res)) {
92 0 : return NS_OK;
93 : }
94 0 : nsCAutoString localeKey;
95 0 : localeKey.AssignLiteral("locale.all.");
96 0 : localeKey.Append(locale);
97 : res = nsUConvPropertySearch::SearchPropertyValue(kUnixCharsets,
98 0 : ArrayLength(kUnixCharsets), localeKey, oResult);
99 0 : if (NS_SUCCEEDED(res)) {
100 0 : return NS_OK;
101 : }
102 : }
103 0 : NS_ERROR("unable to convert locale to charset using deprecated config");
104 0 : mCharset.AssignLiteral("ISO-8859-1");
105 0 : oResult.AssignLiteral("ISO-8859-1");
106 0 : return NS_SUCCESS_USING_FALLBACK_LOCALE;
107 : }
108 :
109 482 : nsPlatformCharset::~nsPlatformCharset()
110 : {
111 964 : }
112 :
113 : NS_IMETHODIMP
114 346 : nsPlatformCharset::GetCharset(nsPlatformCharsetSel selector, nsACString& oResult)
115 : {
116 346 : oResult = mCharset;
117 346 : return NS_OK;
118 : }
119 :
120 : NS_IMETHODIMP
121 101 : nsPlatformCharset::GetDefaultCharsetForLocale(const nsAString& localeName, nsACString &oResult)
122 : {
123 : //
124 : // if this locale is the user's locale then use the charset
125 : // we already determined at initialization
126 : //
127 170 : if (mLocale.Equals(localeName) ||
128 : // support the 4.x behavior
129 69 : (mLocale.LowerCaseEqualsLiteral("en_us") &&
130 0 : localeName.LowerCaseEqualsLiteral("c"))) {
131 32 : oResult = mCharset;
132 32 : return NS_OK;
133 : }
134 :
135 : #if HAVE_LANGINFO_CODESET
136 : //
137 : // This locale appears to be a different locale from the user's locale.
138 : // To do this we would need to lock the global resource we are currently
139 : // using or use a library that provides multi locale support.
140 : // ICU is a possible example of a multi locale library.
141 : // http://oss.software.ibm.com/icu/
142 : //
143 : // A more common cause of hitting this warning than the above is that
144 : // Mozilla is launched under an ll_CC.UTF-8 locale. In xpLocale,
145 : // we only store the language and the region (ll-CC) losing 'UTF-8', which
146 : // leads |mLocale| to be different from |localeName|. Although we lose
147 : // 'UTF-8', we init'd |mCharset| with the value obtained via
148 : // |nl_langinfo(CODESET)| so that we're all right here.
149 : //
150 69 : NS_WARNING("GetDefaultCharsetForLocale: need to add multi locale support");
151 : #ifdef DEBUG_jungshik
152 : printf("localeName=%s mCharset=%s\n", NS_ConvertUTF16toUTF8(localeName).get(),
153 : mCharset.get());
154 : #endif
155 : // until we add multi locale support: use the the charset of the user's locale
156 69 : oResult = mCharset;
157 69 : return NS_SUCCESS_USING_FALLBACK_LOCALE;
158 : #else
159 : //
160 : // convert from locale to charset
161 : // using the deprecated locale to charset mapping
162 : //
163 : NS_LossyConvertUTF16toASCII localeStr(localeName);
164 : nsresult res = ConvertLocaleToCharsetUsingDeprecatedConfig(localeStr, oResult);
165 : if (NS_SUCCEEDED(res))
166 : return res;
167 :
168 : NS_ERROR("unable to convert locale to charset using deprecated config");
169 : oResult.AssignLiteral("ISO-8859-1");
170 : return NS_SUCCESS_USING_FALLBACK_LOCALE;
171 : #endif
172 : }
173 :
174 : nsresult
175 241 : nsPlatformCharset::InitGetCharset(nsACString &oString)
176 : {
177 241 : char* nl_langinfo_codeset = nsnull;
178 482 : nsCString aCharset;
179 : nsresult res;
180 :
181 : #if HAVE_LANGINFO_CODESET
182 241 : nl_langinfo_codeset = nl_langinfo(CODESET);
183 241 : NS_ASSERTION(nl_langinfo_codeset, "cannot get nl_langinfo(CODESET)");
184 :
185 : //
186 : // see if we can use nl_langinfo(CODESET) directly
187 : //
188 241 : if (nl_langinfo_codeset) {
189 241 : aCharset.Assign(nl_langinfo_codeset);
190 241 : res = VerifyCharset(aCharset);
191 241 : if (NS_SUCCEEDED(res)) {
192 241 : oString = aCharset;
193 241 : return res;
194 : }
195 : }
196 :
197 0 : NS_ERROR("unable to use nl_langinfo(CODESET)");
198 : #endif
199 :
200 : //
201 : // try falling back on a deprecated (locale based) name
202 : //
203 0 : char* locale = setlocale(LC_CTYPE, nsnull);
204 0 : nsCAutoString localeStr;
205 0 : localeStr.Assign(locale);
206 0 : res = ConvertLocaleToCharsetUsingDeprecatedConfig(localeStr, oString);
207 0 : if (NS_SUCCEEDED(res)) {
208 0 : return res; // succeeded
209 : }
210 :
211 0 : oString.Truncate();
212 0 : return res;
213 : }
214 :
215 : NS_IMETHODIMP
216 241 : nsPlatformCharset::Init()
217 : {
218 482 : nsCAutoString charset;
219 241 : nsresult res = NS_OK;
220 :
221 : //
222 : // remember default locale so we can use the
223 : // same charset when asked for the same locale
224 : //
225 241 : char* locale = setlocale(LC_CTYPE, nsnull);
226 241 : NS_ASSERTION(locale, "cannot setlocale");
227 241 : if (locale) {
228 241 : CopyASCIItoUTF16(locale, mLocale);
229 : } else {
230 0 : mLocale.AssignLiteral("en_US");
231 : }
232 :
233 241 : res = InitGetCharset(charset);
234 241 : if (NS_SUCCEEDED(res)) {
235 241 : mCharset = charset;
236 241 : return res; // succeeded
237 : }
238 :
239 : // last resort fallback
240 0 : NS_ERROR("unable to convert locale to charset using deprecated config");
241 0 : mCharset.AssignLiteral("ISO-8859-1");
242 0 : return NS_SUCCESS_USING_FALLBACK_LOCALE;
243 : }
244 :
245 : nsresult
246 241 : nsPlatformCharset::VerifyCharset(nsCString &aCharset)
247 : {
248 : nsresult res;
249 : //
250 : // get the convert manager
251 : //
252 482 : nsCOMPtr <nsICharsetConverterManager> charsetConverterManager;
253 241 : charsetConverterManager = do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &res);
254 241 : if (NS_FAILED(res))
255 0 : return res;
256 :
257 : //
258 : // check if we can get an input converter
259 : //
260 482 : nsCOMPtr <nsIUnicodeEncoder> enc;
261 241 : res = charsetConverterManager->GetUnicodeEncoder(aCharset.get(), getter_AddRefs(enc));
262 241 : if (NS_FAILED(res)) {
263 0 : NS_ERROR("failed to create encoder");
264 0 : return res;
265 : }
266 :
267 : //
268 : // check if we can get an output converter
269 : //
270 482 : nsCOMPtr <nsIUnicodeDecoder> dec;
271 241 : res = charsetConverterManager->GetUnicodeDecoder(aCharset.get(), getter_AddRefs(dec));
272 241 : if (NS_FAILED(res)) {
273 0 : NS_ERROR("failed to create decoder");
274 0 : return res;
275 : }
276 :
277 : //
278 : // check if we recognize the charset string
279 : //
280 :
281 482 : nsCAutoString result;
282 241 : res = charsetConverterManager->GetCharsetAlias(aCharset.get(), result);
283 241 : if (NS_FAILED(res)) {
284 0 : return res;
285 : }
286 :
287 : //
288 : // return the preferred string
289 : //
290 :
291 241 : aCharset.Assign(result);
292 241 : NS_ASSERTION(NS_SUCCEEDED(res), "failed to get preferred charset name, using non-preferred");
293 241 : return NS_OK;
294 : }
|