checkin for bstell@netscape.com:

bug 54000; r=ftang@netscape.com, sr=erik@netscape.com
get charset using ns_langinfo(CODESET)
(instead of mapping setlocale(LC_LCTYPE, nsnull);)
This commit is contained in:
erik%netscape.com 2001-04-03 06:05:05 +00:00
parent dd072af443
commit 9a12a8c928

View File

@ -29,6 +29,17 @@
#include "nsLocaleCID.h"
#include "nsUConvDll.h"
#include "nsIComponentManager.h"
#include "nsIServiceManager.h"
#include "nsIUnicodeDecoder.h"
#include "nsIUnicodeEncoder.h"
#include "nsICharsetConverterManager.h"
#include "nsICharsetConverterManager2.h"
#if HAVE_GNU_LIBC_VERSION_H
#include <gnu/libc-version.h>
#endif
#if HAVE_NL_LANGINFO
#include <langinfo.h>
#endif
NS_DEFINE_IID(kIPosixLocaleIID,NS_IPOSIXLOCALE_IID);
NS_DEFINE_CID(kPosixLocaleFactoryCID,NS_POSIXLOCALEFACTORY_CID);
@ -42,16 +53,23 @@ public:
nsUNIXCharset();
virtual ~nsUNIXCharset();
NS_IMETHOD Init();
NS_IMETHOD GetCharset(nsPlatformCharsetSel selector, nsString& oResult);
NS_IMETHOD GetDefaultCharsetForLocale(const PRUnichar* localeName, PRUnichar** _retValue);
private:
nsString mCharset;
nsString mLocale; // remember the locale & charset
NS_IMETHOD InitGetCharset(nsString&);
NS_IMETHOD ConvertLocaleToCharsetUsingDeprecatedConfig(nsAutoString&, nsString&);
NS_IMETHOD VerifyCharset(nsString &aCharset);
};
NS_IMPL_ISUPPORTS(nsUNIXCharset, kIPlatformCharsetIID);
static nsURLProperties *gInfo = nsnull;
static nsURLProperties *gNLInfo = nsnull;
static nsURLProperties *gInfo_deprecated = nsnull;
static PRInt32 gCnt=0;
nsUNIXCharset::nsUNIXCharset()
@ -59,48 +77,61 @@ nsUNIXCharset::nsUNIXCharset()
NS_INIT_REFCNT();
PR_AtomicIncrement(&g_InstanceCount);
PR_AtomicIncrement(&gCnt);
}
char* locale = setlocale(LC_CTYPE, "");
NS_ASSERTION(locale, "cannot setlocale");
NS_IMETHODIMP
nsUNIXCharset::ConvertLocaleToCharsetUsingDeprecatedConfig(nsAutoString& locale, nsString& oResult)
{
// XXX we should make the following block critical section
if(nsnull == gInfo)
// XXX for thread safety the following block should be locked
if(nsnull == gInfo_deprecated)
{
nsAutoString propertyURL;
propertyURL.AssignWithConversion("resource:/res/unixcharset.properties");
nsURLProperties *info = new nsURLProperties( propertyURL );
NS_ASSERTION( info, "cannot create nsURLProperties");
gInfo = info;
gInfo_deprecated = info;
}
if(gInfo && locale)
if(gInfo_deprecated && locale.Length())
{
nsAutoString platformLocaleKey;
platformLocaleKey.AssignWithConversion("locale." OSTYPE ".");
platformLocaleKey.AppendWithConversion(locale);
// note: NS_LITERAL_STRING("locale." OSTYPE ".") does not compile on AIX
platformLocaleKey.Assign(NS_LITERAL_STRING("locale."));
platformLocaleKey.AppendWithConversion(OSTYPE);
platformLocaleKey.Append(NS_LITERAL_STRING("."));
platformLocaleKey.Append(locale.get());
nsresult res = gInfo->Get(platformLocaleKey, mCharset);
if(NS_FAILED(res))
{
nsAutoString localeKey;
localeKey.AssignWithConversion("locale.all.");
localeKey.AppendWithConversion(locale);
res = gInfo->Get(localeKey, mCharset);
if(NS_SUCCEEDED(res)) {
return; // succeeded
}
nsresult res = gInfo_deprecated->Get(platformLocaleKey, oResult);
if(NS_SUCCEEDED(res)) {
return NS_OK;
}
nsAutoString localeKey;
localeKey.Assign(NS_LITERAL_STRING("locale.all."));
localeKey.Append(locale.get());
res = gInfo_deprecated->Get(localeKey, oResult);
if(NS_SUCCEEDED(res)) {
return NS_OK;
}
}
NS_ASSERTION(0, "unable to convert locale to charset using deprecated config");
mCharset.AssignWithConversion("ISO-8859-1");
return; // failed
return NS_ERROR_USING_FALLBACK_LOCALE;
}
nsUNIXCharset::~nsUNIXCharset()
{
PR_AtomicDecrement(&g_InstanceCount);
PR_AtomicDecrement(&gCnt);
if(0 == gCnt) {
delete gInfo;
gInfo = nsnull;
if (gNLInfo) {
delete gNLInfo;
gNLInfo = nsnull;
}
if (gInfo_deprecated) {
delete gInfo_deprecated;
gInfo_deprecated = nsnull;
}
}
}
@ -114,44 +145,49 @@ nsUNIXCharset::GetCharset(nsPlatformCharsetSel selector, nsString& oResult)
NS_IMETHODIMP
nsUNIXCharset::GetDefaultCharsetForLocale(const PRUnichar* localeName, PRUnichar** _retValue)
{
nsCOMPtr<nsIPosixLocale> pPosixLocale;
nsString charset, localeNameAsString(localeName);
charset.AssignWithConversion("ISO-8859-1");
char posix_locale[128];
nsAutoString localeNameAsString(localeName);
//
// convert the locale name
//
nsresult rv = nsComponentManager::CreateInstance(kPosixLocaleFactoryCID,nsnull,
kIPosixLocaleIID,
getter_AddRefs(pPosixLocale));
if (NS_FAILED(rv)) { *_retValue = charset.ToNewUnicode(); return rv; }
//
// if this locale is the user's locale then use the charset
// we already determined at initialization
//
if (mLocale.Equals(localeNameAsString) ||
// support the 4.x behavior
(mLocale.EqualsIgnoreCase("en_US") && localeNameAsString.EqualsIgnoreCase("C"))) {
*_retValue = mCharset.ToNewUnicode();
return NS_OK;
}
rv = pPosixLocale->GetPlatformLocale(&localeNameAsString,posix_locale,sizeof(posix_locale));
if (NS_FAILED(rv)) { *_retValue = charset.ToNewUnicode(); return rv; }
#if HAVE_NL_LANGINFO
//
// This locale appears to be a different locale from the user's locale.
// To do this we would need to lock the global resource we are currently
// using or use a library that provides multi locale support.
// ICU is a possible example of a multi locale library.
// http://oss.software.ibm.com/icu/
//
NS_ASSERTION(0, "GetDefaultCharsetForLocale: need to add multi locale support");
// until we add multi locale support: use the the charset of the user's locale
*_retValue = mCharset.ToNewUnicode();
return NS_ERROR_USING_FALLBACK_LOCALE;
#endif
//
// convert from locale to charset
// using the deprecated locale to charset mapping
//
if (!gInfo) { *_retValue=charset.ToNewUnicode(); return NS_ERROR_OUT_OF_MEMORY; }
nsAutoString locale_key;
locale_key.AssignWithConversion("locale." OSTYPE ".");
locale_key.AppendWithConversion(posix_locale);
rv = gInfo->Get(locale_key,charset);
if(NS_FAILED(rv)) {
locale_key.AssignWithConversion("locale.all.");
locale_key.AppendWithConversion(posix_locale);
rv = gInfo->Get(locale_key,charset);
if(NS_FAILED(rv)) { charset.AssignWithConversion("ISO-8859-1"); }
nsAutoString localeStr(localeName);
nsString charset;
nsresult res = ConvertLocaleToCharsetUsingDeprecatedConfig(localeStr, charset);
if (NS_SUCCEEDED(res)) {
*_retValue = charset.ToNewUnicode();
return res; // succeeded
}
*_retValue = charset.ToNewUnicode();
return rv;
NS_ASSERTION(0, "unable to convert locale to charset using deprecated config");
charset.Assign(NS_LITERAL_STRING("ISO-8859-1"));
*_retValue=charset.ToNewUnicode();
return NS_ERROR_USING_FALLBACK_LOCALE;
}
//----------------------------------------------------------------------
@ -173,10 +209,209 @@ NS_NewPlatformCharset(nsISupports* aOuter,
*aResult = nsnull;
return NS_ERROR_OUT_OF_MEMORY;
}
nsresult res = inst->QueryInterface(aIID, aResult);
nsresult res = inst->Init();
if (NS_FAILED(res)) {
if (res != NS_ERROR_USING_FALLBACK_LOCALE) {
delete inst;
return res;
}
}
res = inst->QueryInterface(aIID, aResult);
if (NS_FAILED(res)) {
*aResult = nsnull;
delete inst;
}
return res;
}
NS_IMETHODIMP
nsUNIXCharset::InitGetCharset(nsString &oString)
{
char* nl_langinfo_codeset = nsnull;
nsString aCharset;
nsresult res;
#if HAVE_NL_LANGINFO
nl_langinfo_codeset = nl_langinfo(CODESET);
NS_ASSERTION(nl_langinfo_codeset, "cannot get nl_langinfo(CODESET)");
// XXX for thread safety the following block should be locked
if(nsnull == gNLInfo) {
nsAutoString propertyURL;
// note: NS_LITERAL_STRING("resource:/res/unixcharset." OSARCH ".properties") does not compile on AIX
propertyURL.Assign(NS_LITERAL_STRING("resource:/res/unixcharset."));
propertyURL.AppendWithConversion(OSARCH);
propertyURL.Append(NS_LITERAL_STRING(".properties"));
nsURLProperties *info;
info = new nsURLProperties( propertyURL );
NS_ASSERTION( info, "cannot create nsURLProperties");
if (info) {
PRBool didLoad;
info->DidLoad(didLoad);
if (!didLoad) {
delete info;
info = nsnull;
}
}
gNLInfo = info;
}
#endif
//
// See if we are remapping nl_langinfo(CODESET)
//
if (gNLInfo && nl_langinfo_codeset) {
nsAutoString localeKey;
#if HAVE_GNU_GET_LIBC_VERSION
//
// look for an glibc version specific charset remap
//
const char *glibc_version = gnu_get_libc_version();
if ((glibc_version != nsnull) && (strlen(glibc_version))) {
localeKey.Assign(NS_LITERAL_STRING("nllic."));
localeKey.AppendWithConversion(glibc_version);
localeKey.Append(NS_LITERAL_STRING("."));
localeKey.AppendWithConversion(nl_langinfo_codeset);
res = gNLInfo->Get(localeKey, aCharset);
if (NS_SUCCEEDED(res)) {
res = VerifyCharset(aCharset);
if (NS_SUCCEEDED(res)) {
oString = aCharset;
return res;
}
}
}
#endif
//
// look for a charset specific charset remap
//
localeKey.Assign(NS_LITERAL_STRING("nllic."));
localeKey.AppendWithConversion(nl_langinfo_codeset);
res = gNLInfo->Get(localeKey, aCharset);
if (NS_SUCCEEDED(res)) {
res = VerifyCharset(aCharset);
if (NS_SUCCEEDED(res)) {
oString = aCharset;
return res;
}
}
}
//
// Did not find a charset override so
// see if we can use nl_langinfo(CODESET) directly
//
if (nl_langinfo_codeset) {
aCharset.AssignWithConversion(nl_langinfo_codeset);
res = VerifyCharset(aCharset);
if (NS_SUCCEEDED(res)) {
oString = aCharset;
return res;
}
}
#if HAVE_NL_LANGINFO
NS_ASSERTION(0, "unable to use nl_langinfo(CODESET)");
#endif
//
// try falling back on a deprecated (locale based) name
//
char* locale = setlocale(LC_CTYPE, nsnull);
nsAutoString localeStr;
localeStr.AssignWithConversion(locale);
res = ConvertLocaleToCharsetUsingDeprecatedConfig(localeStr, aCharset);
if (NS_SUCCEEDED(res)) {
oString = aCharset;
return res; // succeeded
}
return res;
}
NS_IMETHODIMP
nsUNIXCharset::Init()
{
nsString charset;
nsresult res;
//
// remember default locale so we can use the
// same charset when asked for the same locale
//
char* locale = setlocale(LC_CTYPE, nsnull);
NS_ASSERTION(locale, "cannot setlocale");
if (locale) {
mLocale.AssignWithConversion(locale);
} else {
mLocale.Assign(NS_LITERAL_STRING("en_US"));
}
res = InitGetCharset(charset);
if (NS_SUCCEEDED(res)) {
mCharset = charset;
return res; // succeeded
}
// last resort fallback
NS_ASSERTION(0, "unable to convert locale to charset using deprecated config");
mCharset.Assign(NS_LITERAL_STRING("ISO-8859-1"));
return NS_ERROR_USING_FALLBACK_LOCALE;
}
NS_IMETHODIMP
nsUNIXCharset::VerifyCharset(nsString &aCharset)
{
nsresult res;
//
// get the convert manager
//
nsCOMPtr <nsICharsetConverterManager2> charsetConverterManager;
charsetConverterManager = do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &res);
if (NS_FAILED(res))
return res;
//
// check if we recognize the charset string
//
nsCOMPtr <nsIAtom> charsetAtom;
res = charsetConverterManager->GetCharsetAtom(aCharset.GetUnicode(),
getter_AddRefs(charsetAtom));
if (NS_FAILED(res)) {
return res;
}
//
// check if we can get an input converter
//
nsCOMPtr <nsIUnicodeEncoder> enc;
res = charsetConverterManager->GetUnicodeEncoder(charsetAtom, getter_AddRefs(enc));
if (NS_FAILED(res)) {
NS_ASSERTION(0, "failed to create encoder");
return res;
}
//
// check if we can get an output converter
//
nsCOMPtr <nsIUnicodeDecoder> dec;
res = charsetConverterManager->GetUnicodeDecoder(charsetAtom, getter_AddRefs(dec));
if (NS_FAILED(res)) {
NS_ASSERTION(0, "failed to create decoder");
return res;
}
//
// return the preferred string
//
const PRUnichar *prefName;
res = charsetAtom->GetUnicode(&prefName);
if (NS_SUCCEEDED(res))
aCharset.Assign(prefName);
NS_ASSERTION(NS_SUCCEEDED(res), "failed to get preferred charset name, using non-preferred");
return NS_OK;
}