Bug 454376 add -lCrun -lCstd for Solaris OS_LIBS, r=bsmedberg
[wine-gecko.git] / intl / uconv / src / nsUNIXCharset.cpp
blob39157e9fdc383dc226530f135fa07f484b486bde
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
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/
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.
15 * The Original Code is Mozilla Communicator client code.
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.
22 * Contributor(s):
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.
36 * ***** END LICENSE BLOCK ***** */
38 #include <locale.h>
39 #include "nsIPlatformCharset.h"
40 #include "pratom.h"
41 #include "nsGREResProperties.h"
42 #include "nsCOMPtr.h"
43 #include "nsReadableUtils.h"
44 #include "nsLocaleCID.h"
45 #include "nsUConvDll.h"
46 #include "nsIComponentManager.h"
47 #include "nsIServiceManager.h"
48 #include "nsIUnicodeDecoder.h"
49 #include "nsIUnicodeEncoder.h"
50 #include "nsICharsetConverterManager.h"
51 #include "nsEncoderDecoderUtils.h"
52 #if HAVE_GNU_LIBC_VERSION_H
53 #include <gnu/libc-version.h>
54 #endif
55 #ifdef HAVE_NL_TYPES_H
56 #include <nl_types.h>
57 #endif
58 #if HAVE_LANGINFO_CODESET
59 #include <langinfo.h>
60 #endif
61 #include "nsPlatformCharset.h"
62 #include "nsAutoLock.h"
63 #include "prinit.h"
64 #include "nsUnicharUtils.h"
66 NS_IMPL_THREADSAFE_ISUPPORTS1(nsPlatformCharset, nsIPlatformCharset)
68 static nsGREResProperties *gNLInfo = nsnull;
69 static nsGREResProperties *gInfo_deprecated = nsnull;
70 static PRInt32 gCnt=0;
72 //this lock is for protecting above static variable operation
73 static PRLock *gLock = nsnull;
75 static PRStatus InitLock(void)
77 gLock = PR_NewLock();
78 if (gLock)
79 return PR_SUCCESS;
80 return PR_FAILURE;
83 nsPlatformCharset::nsPlatformCharset()
85 PR_AtomicIncrement(&gCnt);
86 static PRCallOnceType once;
87 PR_CallOnce(&once, InitLock);
88 NS_ASSERTION(gLock, "Can't allocate a lock?!");
91 nsresult
92 nsPlatformCharset::ConvertLocaleToCharsetUsingDeprecatedConfig(nsAString& locale, nsACString& oResult)
95 // locked for thread safety
97 nsAutoLock guard(gLock);
98 if (!gInfo_deprecated) {
99 nsGREResProperties *info =
100 new nsGREResProperties(NS_LITERAL_CSTRING("unixcharset.properties"));
101 NS_ASSERTION(info, "cannot create nsGREResProperties");
102 gInfo_deprecated = info;
106 if (gInfo_deprecated && !(locale.IsEmpty())) {
107 nsAutoString platformLocaleKey;
108 // note: NS_LITERAL_STRING("locale." OSTYPE ".") does not compile on AIX
109 platformLocaleKey.AssignLiteral("locale.");
110 platformLocaleKey.AppendWithConversion(OSTYPE);
111 platformLocaleKey.AppendLiteral(".");
112 platformLocaleKey.Append(locale);
114 nsAutoString charset;
115 nsresult res = gInfo_deprecated->Get(platformLocaleKey, charset);
116 if (NS_SUCCEEDED(res)) {
117 LossyCopyUTF16toASCII(charset, oResult);
118 return NS_OK;
120 nsAutoString localeKey;
121 localeKey.AssignLiteral("locale.all.");
122 localeKey.Append(locale);
123 res = gInfo_deprecated->Get(localeKey, charset);
124 if (NS_SUCCEEDED(res)) {
125 LossyCopyUTF16toASCII(charset, oResult);
126 return NS_OK;
129 NS_ASSERTION(0, "unable to convert locale to charset using deprecated config");
130 mCharset.AssignLiteral("ISO-8859-1");
131 oResult.AssignLiteral("ISO-8859-1");
132 return NS_SUCCESS_USING_FALLBACK_LOCALE;
135 nsPlatformCharset::~nsPlatformCharset()
137 PR_AtomicDecrement(&gCnt);
138 if (!gCnt) {
139 if (gNLInfo) {
140 delete gNLInfo;
141 gNLInfo = nsnull;
142 PR_DestroyLock(gLock);
143 gLock = nsnull;
145 if (gInfo_deprecated) {
146 delete gInfo_deprecated;
147 gInfo_deprecated = nsnull;
152 NS_IMETHODIMP
153 nsPlatformCharset::GetCharset(nsPlatformCharsetSel selector, nsACString& oResult)
155 oResult = mCharset;
156 return NS_OK;
159 NS_IMETHODIMP
160 nsPlatformCharset::GetDefaultCharsetForLocale(const nsAString& localeName, nsACString &oResult)
163 // if this locale is the user's locale then use the charset
164 // we already determined at initialization
166 if (mLocale.Equals(localeName) ||
167 // support the 4.x behavior
168 (mLocale.LowerCaseEqualsLiteral("en_us") &&
169 localeName.LowerCaseEqualsLiteral("c"))) {
170 oResult = mCharset;
171 return NS_OK;
174 #if HAVE_LANGINFO_CODESET
176 // This locale appears to be a different locale from the user's locale.
177 // To do this we would need to lock the global resource we are currently
178 // using or use a library that provides multi locale support.
179 // ICU is a possible example of a multi locale library.
180 // http://oss.software.ibm.com/icu/
182 // A more common cause of hitting this warning than the above is that
183 // Mozilla is launched under an ll_CC.UTF-8 locale. In xpLocale,
184 // we only store the language and the region (ll-CC) losing 'UTF-8', which
185 // leads |mLocale| to be different from |localeName|. Although we lose
186 // 'UTF-8', we init'd |mCharset| with the value obtained via
187 // |nl_langinfo(CODESET)| so that we're all right here.
189 NS_WARNING("GetDefaultCharsetForLocale: need to add multi locale support");
190 #ifdef DEBUG_jungshik
191 printf("localeName=%s mCharset=%s\n", NS_ConvertUTF16toUTF8(localeName).get(),
192 mCharset.get());
193 #endif
194 // until we add multi locale support: use the the charset of the user's locale
195 oResult = mCharset;
196 return NS_SUCCESS_USING_FALLBACK_LOCALE;
197 #endif
200 // convert from locale to charset
201 // using the deprecated locale to charset mapping
203 nsAutoString localeStr(localeName);
204 nsresult res = ConvertLocaleToCharsetUsingDeprecatedConfig(localeStr, oResult);
205 if (NS_SUCCEEDED(res))
206 return res;
208 NS_ASSERTION(0, "unable to convert locale to charset using deprecated config");
209 oResult.AssignLiteral("ISO-8859-1");
210 return NS_SUCCESS_USING_FALLBACK_LOCALE;
213 nsresult
214 nsPlatformCharset::InitGetCharset(nsACString &oString)
216 char* nl_langinfo_codeset = nsnull;
217 nsCString aCharset;
218 nsresult res;
220 #if HAVE_LANGINFO_CODESET
221 nl_langinfo_codeset = nl_langinfo(CODESET);
222 NS_ASSERTION(nl_langinfo_codeset, "cannot get nl_langinfo(CODESET)");
225 // see if we can use nl_langinfo(CODESET) directly
227 if (nl_langinfo_codeset) {
228 aCharset.Assign(nl_langinfo_codeset);
229 res = VerifyCharset(aCharset);
230 if (NS_SUCCEEDED(res)) {
231 oString = aCharset;
232 return res;
236 // locked for thread safety
238 nsAutoLock guard(gLock);
240 if (!gNLInfo) {
241 nsCAutoString propertyFile;
242 // note: NS_LITERAL_CSTRING("unixcharset." OSARCH ".properties") does not compile on AIX
243 propertyFile.AssignLiteral("unixcharset.");
244 propertyFile.AppendLiteral(NS_STRINGIFY(OSARCH));
245 propertyFile.AppendLiteral(".properties");
246 nsGREResProperties *info = new nsGREResProperties(propertyFile);
247 NS_ASSERTION(info, "cannot create nsGREResProperties");
248 if (info) {
249 PRBool didLoad = info->DidLoad();
250 if (!didLoad) {
251 delete info;
252 info = nsnull;
255 gNLInfo = info;
260 // See if we are remapping nl_langinfo(CODESET)
262 if (gNLInfo && nl_langinfo_codeset) {
263 nsAutoString localeKey;
265 #if HAVE_GNU_GET_LIBC_VERSION
267 // look for an glibc version specific charset remap
269 const char *glibc_version = gnu_get_libc_version();
270 if ((glibc_version != nsnull) && (strlen(glibc_version))) {
271 localeKey.AssignLiteral("nllic.");
272 localeKey.AppendWithConversion(glibc_version);
273 localeKey.AppendLiteral(".");
274 localeKey.AppendWithConversion(nl_langinfo_codeset);
275 nsAutoString uCharset;
276 res = gNLInfo->Get(localeKey, uCharset);
277 if (NS_SUCCEEDED(res)) {
278 aCharset.AssignWithConversion(uCharset);
279 res = VerifyCharset(aCharset);
280 if (NS_SUCCEEDED(res)) {
281 oString = aCharset;
282 return res;
286 #endif
289 // look for a charset specific charset remap
291 localeKey.AssignLiteral("nllic.");
292 localeKey.AppendWithConversion(nl_langinfo_codeset);
293 nsAutoString uCharset;
294 res = gNLInfo->Get(localeKey, uCharset);
295 if (NS_SUCCEEDED(res)) {
296 aCharset.AssignWithConversion(uCharset);
297 res = VerifyCharset(aCharset);
298 if (NS_SUCCEEDED(res)) {
299 oString = aCharset;
300 return res;
305 NS_ASSERTION(0, "unable to use nl_langinfo(CODESET)");
306 #endif
309 // try falling back on a deprecated (locale based) name
311 char* locale = setlocale(LC_CTYPE, nsnull);
312 nsAutoString localeStr;
313 localeStr.AssignWithConversion(locale);
314 res = ConvertLocaleToCharsetUsingDeprecatedConfig(localeStr, oString);
315 if (NS_SUCCEEDED(res)) {
316 return res; // succeeded
319 oString.Truncate();
320 return res;
323 NS_IMETHODIMP
324 nsPlatformCharset::Init()
326 nsCAutoString charset;
327 nsresult res = NS_OK;
330 // remember default locale so we can use the
331 // same charset when asked for the same locale
333 char* locale = setlocale(LC_CTYPE, nsnull);
334 NS_ASSERTION(locale, "cannot setlocale");
335 if (locale) {
336 CopyASCIItoUTF16(locale, mLocale);
337 } else {
338 mLocale.AssignLiteral("en_US");
341 res = InitGetCharset(charset);
342 if (NS_SUCCEEDED(res)) {
343 mCharset = charset;
344 return res; // succeeded
347 // last resort fallback
348 NS_ASSERTION(0, "unable to convert locale to charset using deprecated config");
349 mCharset.AssignLiteral("ISO-8859-1");
350 return NS_SUCCESS_USING_FALLBACK_LOCALE;
353 nsresult
354 nsPlatformCharset::VerifyCharset(nsCString &aCharset)
356 nsresult res;
358 // get the convert manager
360 nsCOMPtr <nsICharsetConverterManager> charsetConverterManager;
361 charsetConverterManager = do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &res);
362 if (NS_FAILED(res))
363 return res;
366 // check if we can get an input converter
368 nsCOMPtr <nsIUnicodeEncoder> enc;
369 res = charsetConverterManager->GetUnicodeEncoder(aCharset.get(), getter_AddRefs(enc));
370 if (NS_FAILED(res)) {
371 NS_ASSERTION(0, "failed to create encoder");
372 return res;
376 // check if we can get an output converter
378 nsCOMPtr <nsIUnicodeDecoder> dec;
379 res = charsetConverterManager->GetUnicodeDecoder(aCharset.get(), getter_AddRefs(dec));
380 if (NS_FAILED(res)) {
381 NS_ASSERTION(0, "failed to create decoder");
382 return res;
386 // check if we recognize the charset string
389 nsCAutoString result;
390 res = charsetConverterManager->GetCharsetAlias(aCharset.get(), result);
391 if (NS_FAILED(res)) {
392 return res;
396 // return the preferred string
399 aCharset.Assign(result);
400 NS_ASSERTION(NS_SUCCEEDED(res), "failed to get preferred charset name, using non-preferred");
401 return NS_OK;
404 nsresult
405 nsPlatformCharset::InitInfo()
407 return NS_OK;