michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include michael@0: michael@0: #include "mozilla/ArrayUtils.h" michael@0: michael@0: #include "nsIPlatformCharset.h" michael@0: #include "nsUConvPropertySearch.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsReadableUtils.h" michael@0: #include "nsIComponentManager.h" michael@0: #include "nsIServiceManager.h" michael@0: #include "nsIUnicodeDecoder.h" michael@0: #include "nsIUnicodeEncoder.h" michael@0: #include "nsICharsetConverterManager.h" michael@0: #include "nsEncoderDecoderUtils.h" michael@0: #if HAVE_GNU_LIBC_VERSION_H michael@0: #include michael@0: #endif michael@0: #ifdef HAVE_NL_TYPES_H michael@0: #include michael@0: #endif michael@0: #if HAVE_LANGINFO_CODESET michael@0: #include michael@0: #endif michael@0: #include "nsPlatformCharset.h" michael@0: #include "prinit.h" michael@0: #include "nsUnicharUtils.h" michael@0: michael@0: using namespace mozilla; michael@0: michael@0: static const char* kUnixCharsets[][3] = { michael@0: #include "unixcharset.properties.h" michael@0: }; michael@0: michael@0: NS_IMPL_ISUPPORTS(nsPlatformCharset, nsIPlatformCharset) michael@0: michael@0: nsPlatformCharset::nsPlatformCharset() michael@0: { michael@0: } michael@0: michael@0: static nsresult michael@0: ConvertLocaleToCharsetUsingDeprecatedConfig(const nsACString& locale, michael@0: nsACString& oResult) michael@0: { michael@0: if (!(locale.IsEmpty())) { michael@0: nsAutoCString localeKey; michael@0: localeKey.AssignLiteral("locale.all."); michael@0: localeKey.Append(locale); michael@0: if (NS_SUCCEEDED(nsUConvPropertySearch::SearchPropertyValue(kUnixCharsets, michael@0: ArrayLength(kUnixCharsets), localeKey, oResult))) { michael@0: return NS_OK; michael@0: } michael@0: } michael@0: NS_ERROR("unable to convert locale to charset using deprecated config"); michael@0: oResult.AssignLiteral("ISO-8859-1"); michael@0: return NS_SUCCESS_USING_FALLBACK_LOCALE; michael@0: } michael@0: michael@0: nsPlatformCharset::~nsPlatformCharset() michael@0: { michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsPlatformCharset::GetCharset(nsPlatformCharsetSel selector, nsACString& oResult) michael@0: { michael@0: oResult = mCharset; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsPlatformCharset::GetDefaultCharsetForLocale(const nsAString& localeName, nsACString &oResult) michael@0: { michael@0: // michael@0: // if this locale is the user's locale then use the charset michael@0: // we already determined at initialization michael@0: // michael@0: if (mLocale.Equals(localeName) || michael@0: // support the 4.x behavior michael@0: (mLocale.LowerCaseEqualsLiteral("en_us") && michael@0: localeName.LowerCaseEqualsLiteral("c"))) { michael@0: oResult = mCharset; michael@0: return NS_OK; michael@0: } michael@0: michael@0: #if HAVE_LANGINFO_CODESET michael@0: // michael@0: // This locale appears to be a different locale from the user's locale. michael@0: // To do this we would need to lock the global resource we are currently michael@0: // using or use a library that provides multi locale support. michael@0: // ICU is a possible example of a multi locale library. michael@0: // http://oss.software.ibm.com/icu/ michael@0: // michael@0: // A more common cause of hitting this warning than the above is that michael@0: // Mozilla is launched under an ll_CC.UTF-8 locale. In xpLocale, michael@0: // we only store the language and the region (ll-CC) losing 'UTF-8', which michael@0: // leads |mLocale| to be different from |localeName|. Although we lose michael@0: // 'UTF-8', we init'd |mCharset| with the value obtained via michael@0: // |nl_langinfo(CODESET)| so that we're all right here. michael@0: // michael@0: NS_WARNING("GetDefaultCharsetForLocale: need to add multi locale support"); michael@0: #ifdef DEBUG_jungshik michael@0: printf("localeName=%s mCharset=%s\n", NS_ConvertUTF16toUTF8(localeName).get(), michael@0: mCharset.get()); michael@0: #endif michael@0: // until we add multi locale support: use the the charset of the user's locale michael@0: oResult = mCharset; michael@0: return NS_SUCCESS_USING_FALLBACK_LOCALE; michael@0: #else michael@0: // michael@0: // convert from locale to charset michael@0: // using the deprecated locale to charset mapping michael@0: // michael@0: NS_LossyConvertUTF16toASCII localeStr(localeName); michael@0: return ConvertLocaleToCharsetUsingDeprecatedConfig(localeStr, oResult); michael@0: #endif michael@0: } michael@0: michael@0: nsresult michael@0: nsPlatformCharset::InitGetCharset(nsACString &oString) michael@0: { michael@0: char* nl_langinfo_codeset = nullptr; michael@0: nsCString aCharset; michael@0: nsresult res; michael@0: michael@0: #if HAVE_LANGINFO_CODESET michael@0: nl_langinfo_codeset = nl_langinfo(CODESET); michael@0: NS_ASSERTION(nl_langinfo_codeset, "cannot get nl_langinfo(CODESET)"); michael@0: michael@0: // michael@0: // see if we can use nl_langinfo(CODESET) directly michael@0: // michael@0: if (nl_langinfo_codeset) { michael@0: aCharset.Assign(nl_langinfo_codeset); michael@0: res = VerifyCharset(aCharset); michael@0: if (NS_SUCCEEDED(res)) { michael@0: oString = aCharset; michael@0: return res; michael@0: } michael@0: } michael@0: michael@0: NS_ERROR("unable to use nl_langinfo(CODESET)"); michael@0: #endif michael@0: michael@0: // michael@0: // try falling back on a deprecated (locale based) name michael@0: // michael@0: char* locale = setlocale(LC_CTYPE, nullptr); michael@0: nsAutoCString localeStr; michael@0: localeStr.Assign(locale); michael@0: return ConvertLocaleToCharsetUsingDeprecatedConfig(localeStr, oString); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsPlatformCharset::Init() michael@0: { michael@0: // michael@0: // remember default locale so we can use the michael@0: // same charset when asked for the same locale michael@0: // michael@0: char* locale = setlocale(LC_CTYPE, nullptr); michael@0: NS_ASSERTION(locale, "cannot setlocale"); michael@0: if (locale) { michael@0: CopyASCIItoUTF16(locale, mLocale); michael@0: } else { michael@0: mLocale.AssignLiteral("en_US"); michael@0: } michael@0: michael@0: // InitGetCharset only returns NS_OK or NS_SUCESS_USING_FALLBACK_LOCALE michael@0: return InitGetCharset(mCharset); michael@0: } michael@0: michael@0: nsresult michael@0: nsPlatformCharset::VerifyCharset(nsCString &aCharset) michael@0: { michael@0: // fast path for UTF-8. Most platform uses UTF-8 as charset now. michael@0: if (aCharset.EqualsLiteral("UTF-8")) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult res; michael@0: // michael@0: // get the convert manager michael@0: // michael@0: nsCOMPtr charsetConverterManager; michael@0: charsetConverterManager = do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &res); michael@0: if (NS_FAILED(res)) michael@0: return res; michael@0: michael@0: // michael@0: // check if we can get an input converter michael@0: // michael@0: nsCOMPtr enc; michael@0: res = charsetConverterManager->GetUnicodeEncoder(aCharset.get(), getter_AddRefs(enc)); michael@0: if (NS_FAILED(res)) { michael@0: NS_ERROR("failed to create encoder"); michael@0: return res; michael@0: } michael@0: michael@0: // michael@0: // check if we can get an output converter michael@0: // michael@0: nsCOMPtr dec; michael@0: res = charsetConverterManager->GetUnicodeDecoder(aCharset.get(), getter_AddRefs(dec)); michael@0: if (NS_FAILED(res)) { michael@0: NS_ERROR("failed to create decoder"); michael@0: return res; michael@0: } michael@0: michael@0: // michael@0: // check if we recognize the charset string michael@0: // michael@0: michael@0: nsAutoCString result; michael@0: res = charsetConverterManager->GetCharsetAlias(aCharset.get(), result); michael@0: if (NS_FAILED(res)) { michael@0: return res; michael@0: } michael@0: michael@0: // michael@0: // return the preferred string michael@0: // michael@0: michael@0: aCharset.Assign(result); michael@0: return NS_OK; michael@0: }