intl/locale/src/nsLocaleService.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/intl/locale/src/nsLocaleService.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,381 @@
     1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#ifdef MOZ_WIDGET_QT
    1.10 +#include <QString>
    1.11 +#include <QtCore/QLocale>
    1.12 +#endif
    1.13 +
    1.14 +#include "nsCOMPtr.h"
    1.15 +#include "nsAutoPtr.h"
    1.16 +#include "nsILocale.h"
    1.17 +#include "nsILocaleService.h"
    1.18 +#include "nsLocale.h"
    1.19 +#include "nsCRT.h"
    1.20 +#include "prprf.h"
    1.21 +#include "nsTArray.h"
    1.22 +#include "nsString.h"
    1.23 +
    1.24 +#include <ctype.h>
    1.25 +
    1.26 +#if defined(XP_WIN)
    1.27 +#  include "nsWin32Locale.h"
    1.28 +#elif defined(XP_MACOSX)
    1.29 +#  include <Carbon/Carbon.h>
    1.30 +#elif defined(XP_UNIX)
    1.31 +#  include <locale.h>
    1.32 +#  include <stdlib.h>
    1.33 +#  include "nsPosixLocale.h"
    1.34 +#endif
    1.35 +
    1.36 +//
    1.37 +// implementation constants
    1.38 +const int LocaleListLength = 6;
    1.39 +const char* LocaleList[LocaleListLength] = 
    1.40 +{
    1.41 +	NSILOCALE_COLLATE,
    1.42 +	NSILOCALE_CTYPE,
    1.43 +	NSILOCALE_MONETARY,
    1.44 +	NSILOCALE_NUMERIC,
    1.45 +	NSILOCALE_TIME,
    1.46 +	NSILOCALE_MESSAGE
    1.47 +};
    1.48 +
    1.49 +#define NSILOCALE_MAX_ACCEPT_LANGUAGE	16
    1.50 +#define NSILOCALE_MAX_ACCEPT_LENGTH		18
    1.51 +
    1.52 +#if (defined(XP_UNIX) && !defined(XP_MACOSX))
    1.53 +static int posix_locale_category[LocaleListLength] =
    1.54 +{
    1.55 +  LC_COLLATE,
    1.56 +  LC_CTYPE,
    1.57 +  LC_MONETARY,
    1.58 +  LC_NUMERIC,
    1.59 +  LC_TIME,
    1.60 +#ifdef HAVE_I18N_LC_MESSAGES
    1.61 +  LC_MESSAGES
    1.62 +#else
    1.63 +  LC_CTYPE
    1.64 +#endif
    1.65 +};
    1.66 +#endif
    1.67 +
    1.68 +//
    1.69 +// nsILocaleService implementation
    1.70 +//
    1.71 +class nsLocaleService: public nsILocaleService {
    1.72 +
    1.73 +public:
    1.74 +	
    1.75 +	//
    1.76 +	// nsISupports
    1.77 +	//
    1.78 +	NS_DECL_THREADSAFE_ISUPPORTS
    1.79 +
    1.80 +	//
    1.81 +	// nsILocaleService
    1.82 +	//
    1.83 +    NS_DECL_NSILOCALESERVICE
    1.84 +
    1.85 +
    1.86 +	nsLocaleService(void);
    1.87 +	virtual ~nsLocaleService(void);
    1.88 +
    1.89 +protected:
    1.90 +
    1.91 +	nsresult SetSystemLocale(void);
    1.92 +	nsresult SetApplicationLocale(void);
    1.93 +
    1.94 +	nsCOMPtr<nsILocale>				mSystemLocale;
    1.95 +	nsCOMPtr<nsILocale>				mApplicationLocale;
    1.96 +
    1.97 +};
    1.98 +
    1.99 +//
   1.100 +// nsLocaleService methods
   1.101 +//
   1.102 +nsLocaleService::nsLocaleService(void) 
   1.103 +{
   1.104 +#ifdef XP_WIN
   1.105 +    nsAutoString        xpLocale;
   1.106 +    //
   1.107 +    // get the system LCID
   1.108 +    //
   1.109 +    LCID win_lcid = GetSystemDefaultLCID();
   1.110 +    NS_ENSURE_TRUE_VOID(win_lcid);
   1.111 +    nsWin32Locale::GetXPLocale(win_lcid, xpLocale);
   1.112 +    nsresult rv = NewLocale(xpLocale, getter_AddRefs(mSystemLocale));
   1.113 +    NS_ENSURE_SUCCESS_VOID(rv);
   1.114 +
   1.115 +    //
   1.116 +    // get the application LCID
   1.117 +    //
   1.118 +    win_lcid = GetUserDefaultLCID();
   1.119 +    NS_ENSURE_TRUE_VOID(win_lcid);
   1.120 +    nsWin32Locale::GetXPLocale(win_lcid, xpLocale);
   1.121 +    rv = NewLocale(xpLocale, getter_AddRefs(mApplicationLocale));
   1.122 +    NS_ENSURE_SUCCESS_VOID(rv);
   1.123 +#endif
   1.124 +#if defined(XP_UNIX) && !defined(XP_MACOSX)
   1.125 +    nsRefPtr<nsLocale> resultLocale(new nsLocale());
   1.126 +    NS_ENSURE_TRUE_VOID(resultLocale);
   1.127 +
   1.128 +#ifdef MOZ_WIDGET_QT
   1.129 +    const char* lang = QLocale::system().name().toUtf8();
   1.130 +#else
   1.131 +    // Get system configuration
   1.132 +    const char* lang = getenv("LANG");
   1.133 +#endif
   1.134 +
   1.135 +    nsAutoString xpLocale, platformLocale;
   1.136 +    nsAutoString category, category_platform;
   1.137 +    int i;
   1.138 +
   1.139 +    for( i = 0; i < LocaleListLength; i++ ) {
   1.140 +        nsresult result;
   1.141 +        // setlocale( , "") evaluates LC_* and LANG
   1.142 +        char* lc_temp = setlocale(posix_locale_category[i], "");
   1.143 +        CopyASCIItoUTF16(LocaleList[i], category);
   1.144 +        category_platform = category;
   1.145 +        category_platform.AppendLiteral("##PLATFORM");
   1.146 +        if (lc_temp != nullptr) {
   1.147 +            result = nsPosixLocale::GetXPLocale(lc_temp, xpLocale);
   1.148 +            CopyASCIItoUTF16(lc_temp, platformLocale);
   1.149 +        } else {
   1.150 +            if ( lang == nullptr ) {
   1.151 +                platformLocale.AssignLiteral("en_US");
   1.152 +                result = nsPosixLocale::GetXPLocale("en-US", xpLocale);
   1.153 +            } else {
   1.154 +                CopyASCIItoUTF16(lang, platformLocale);
   1.155 +                result = nsPosixLocale::GetXPLocale(lang, xpLocale);
   1.156 +            }
   1.157 +        }
   1.158 +        if (NS_FAILED(result)) {
   1.159 +            return;
   1.160 +        }
   1.161 +        resultLocale->AddCategory(category, xpLocale);
   1.162 +        resultLocale->AddCategory(category_platform, platformLocale);
   1.163 +    }
   1.164 +    mSystemLocale = do_QueryInterface(resultLocale);
   1.165 +    mApplicationLocale = do_QueryInterface(resultLocale);
   1.166 +       
   1.167 +#endif // XP_UNIX
   1.168 +
   1.169 +#ifdef XP_MACOSX
   1.170 +    // Get string representation of user's current locale
   1.171 +    CFLocaleRef userLocaleRef = ::CFLocaleCopyCurrent();
   1.172 +    CFStringRef userLocaleStr = ::CFLocaleGetIdentifier(userLocaleRef);
   1.173 +    ::CFRetain(userLocaleStr);
   1.174 +
   1.175 +    nsAutoTArray<UniChar, 32> buffer;
   1.176 +    int size = ::CFStringGetLength(userLocaleStr);
   1.177 +    buffer.SetLength(size + 1);
   1.178 +    CFRange range = ::CFRangeMake(0, size);
   1.179 +    ::CFStringGetCharacters(userLocaleStr, range, buffer.Elements());
   1.180 +    buffer[size] = 0;
   1.181 +
   1.182 +    // Convert the locale string to the format that Mozilla expects
   1.183 +    nsAutoString xpLocale(reinterpret_cast<char16_t*>(buffer.Elements()));
   1.184 +    xpLocale.ReplaceChar('_', '-');
   1.185 +
   1.186 +    nsresult rv = NewLocale(xpLocale, getter_AddRefs(mSystemLocale));
   1.187 +    if (NS_SUCCEEDED(rv)) {
   1.188 +        mApplicationLocale = mSystemLocale;
   1.189 +    }
   1.190 +
   1.191 +    ::CFRelease(userLocaleStr);
   1.192 +    ::CFRelease(userLocaleRef);
   1.193 +
   1.194 +    NS_ASSERTION(mApplicationLocale, "Failed to create locale objects");
   1.195 +#endif // XP_MACOSX
   1.196 +}
   1.197 +
   1.198 +nsLocaleService::~nsLocaleService(void)
   1.199 +{
   1.200 +}
   1.201 +
   1.202 +NS_IMPL_ISUPPORTS(nsLocaleService, nsILocaleService)
   1.203 +
   1.204 +NS_IMETHODIMP
   1.205 +nsLocaleService::NewLocale(const nsAString &aLocale, nsILocale **_retval)
   1.206 +{
   1.207 +    nsresult result;
   1.208 +
   1.209 +    *_retval = nullptr;
   1.210 +
   1.211 +    nsRefPtr<nsLocale> resultLocale(new nsLocale());
   1.212 +    if (!resultLocale) return NS_ERROR_OUT_OF_MEMORY;
   1.213 +
   1.214 +    for (int32_t i = 0; i < LocaleListLength; i++) {
   1.215 +      NS_ConvertASCIItoUTF16 category(LocaleList[i]);
   1.216 +      result = resultLocale->AddCategory(category, aLocale);
   1.217 +      if (NS_FAILED(result)) return result;
   1.218 +#if defined(XP_UNIX) && !defined(XP_MACOSX)
   1.219 +      category.AppendLiteral("##PLATFORM");
   1.220 +      result = resultLocale->AddCategory(category, aLocale);
   1.221 +      if (NS_FAILED(result)) return result;
   1.222 +#endif
   1.223 +    }
   1.224 +
   1.225 +    NS_ADDREF(*_retval = resultLocale);
   1.226 +    return NS_OK;
   1.227 +}
   1.228 +
   1.229 +
   1.230 +NS_IMETHODIMP
   1.231 +nsLocaleService::GetSystemLocale(nsILocale **_retval)
   1.232 +{
   1.233 +	if (mSystemLocale) {
   1.234 +		NS_ADDREF(*_retval = mSystemLocale);
   1.235 +		return NS_OK;
   1.236 +	}
   1.237 +
   1.238 +	*_retval = (nsILocale*)nullptr;
   1.239 +	return NS_ERROR_FAILURE;
   1.240 +}
   1.241 +
   1.242 +NS_IMETHODIMP
   1.243 +nsLocaleService::GetApplicationLocale(nsILocale **_retval)
   1.244 +{
   1.245 +	if (mApplicationLocale) {
   1.246 +		NS_ADDREF(*_retval = mApplicationLocale);
   1.247 +		return NS_OK;
   1.248 +	}
   1.249 +
   1.250 +	*_retval=(nsILocale*)nullptr;
   1.251 +	return NS_ERROR_FAILURE;
   1.252 +}
   1.253 +
   1.254 +NS_IMETHODIMP
   1.255 +nsLocaleService::GetLocaleFromAcceptLanguage(const char *acceptLanguage, nsILocale **_retval)
   1.256 +{
   1.257 +  char* cPtr;
   1.258 +  char* cPtr1;
   1.259 +  char* cPtr2;
   1.260 +  int i;
   1.261 +  int j;
   1.262 +  int countLang = 0;
   1.263 +  char	acceptLanguageList[NSILOCALE_MAX_ACCEPT_LANGUAGE][NSILOCALE_MAX_ACCEPT_LENGTH];
   1.264 +  nsresult	result;
   1.265 +
   1.266 +  nsAutoArrayPtr<char> input(new char[strlen(acceptLanguage)+1]);
   1.267 +
   1.268 +  strcpy(input, acceptLanguage);
   1.269 +  cPtr1 = input-1;
   1.270 +  cPtr2 = input;
   1.271 +
   1.272 +  /* put in standard form */
   1.273 +  while (*(++cPtr1)) {
   1.274 +    if      (isalpha(*cPtr1))  *cPtr2++ = tolower(*cPtr1); /* force lower case */
   1.275 +    else if (isspace(*cPtr1))  ;                           /* ignore any space */
   1.276 +    else if (*cPtr1=='-')      *cPtr2++ = '_';             /* "-" -> "_"       */
   1.277 +    else if (*cPtr1=='*')      ;                           /* ignore "*"       */
   1.278 +    else                       *cPtr2++ = *cPtr1;          /* else unchanged   */
   1.279 +  }
   1.280 +  *cPtr2 = '\0';
   1.281 +
   1.282 +  countLang = 0;
   1.283 +
   1.284 +  if (strchr(input,';')) {
   1.285 +    /* deal with the quality values */
   1.286 +
   1.287 +    float qvalue[NSILOCALE_MAX_ACCEPT_LANGUAGE];
   1.288 +    float qSwap;
   1.289 +    float bias = 0.0f;
   1.290 +    char* ptrLanguage[NSILOCALE_MAX_ACCEPT_LANGUAGE];
   1.291 +    char* ptrSwap;
   1.292 +
   1.293 +    cPtr = nsCRT::strtok(input,",",&cPtr2);
   1.294 +    while (cPtr) {
   1.295 +      qvalue[countLang] = 1.0f;
   1.296 +      /* add extra parens to get rid of warning */
   1.297 +      if ((cPtr1 = strchr(cPtr,';')) != nullptr) {
   1.298 +        PR_sscanf(cPtr1,";q=%f",&qvalue[countLang]);
   1.299 +        *cPtr1 = '\0';
   1.300 +      }
   1.301 +      if (strlen(cPtr)<NSILOCALE_MAX_ACCEPT_LANGUAGE) {     /* ignore if too long */
   1.302 +        qvalue[countLang] -= (bias += 0.0001f); /* to insure original order */
   1.303 +        ptrLanguage[countLang++] = cPtr;
   1.304 +        if (countLang>=NSILOCALE_MAX_ACCEPT_LANGUAGE) break; /* quit if too many */
   1.305 +      }
   1.306 +      cPtr = nsCRT::strtok(cPtr2,",",&cPtr2);
   1.307 +    }
   1.308 +
   1.309 +    /* sort according to decending qvalue */
   1.310 +    /* not a very good algorithm, but count is not likely large */
   1.311 +    for ( i=0 ; i<countLang-1 ; i++ ) {
   1.312 +      for ( j=i+1 ; j<countLang ; j++ ) {
   1.313 +        if (qvalue[i]<qvalue[j]) {
   1.314 +          qSwap     = qvalue[i];
   1.315 +          qvalue[i] = qvalue[j];
   1.316 +          qvalue[j] = qSwap;
   1.317 +          ptrSwap        = ptrLanguage[i];
   1.318 +          ptrLanguage[i] = ptrLanguage[j];
   1.319 +          ptrLanguage[j] = ptrSwap;
   1.320 +        }
   1.321 +      }
   1.322 +    }
   1.323 +    for ( i=0 ; i<countLang ; i++ ) {
   1.324 +      PL_strncpyz(acceptLanguageList[i],ptrLanguage[i],NSILOCALE_MAX_ACCEPT_LENGTH);
   1.325 +    }
   1.326 +
   1.327 +  } else {
   1.328 +    /* simple case: no quality values */
   1.329 +
   1.330 +    cPtr = nsCRT::strtok(input,",",&cPtr2);
   1.331 +    while (cPtr) {
   1.332 +      if (strlen(cPtr)<NSILOCALE_MAX_ACCEPT_LENGTH) {        /* ignore if too long */
   1.333 +        PL_strncpyz(acceptLanguageList[countLang++],cPtr,NSILOCALE_MAX_ACCEPT_LENGTH);
   1.334 +        if (countLang>=NSILOCALE_MAX_ACCEPT_LENGTH) break; /* quit if too many */
   1.335 +      }
   1.336 +      cPtr = nsCRT::strtok(cPtr2,",",&cPtr2);
   1.337 +    }
   1.338 +  }
   1.339 +
   1.340 +  //
   1.341 +  // now create the locale 
   1.342 +  //
   1.343 +  result = NS_ERROR_FAILURE;
   1.344 +  if (countLang>0) {
   1.345 +	  result = NewLocale(NS_ConvertASCIItoUTF16(acceptLanguageList[0]), _retval);
   1.346 +  }
   1.347 +
   1.348 +  //
   1.349 +  // clean up
   1.350 +  //
   1.351 +  return result;
   1.352 +}
   1.353 +
   1.354 +
   1.355 +nsresult
   1.356 +nsLocaleService::GetLocaleComponentForUserAgent(nsAString& retval)
   1.357 +{
   1.358 +    nsCOMPtr<nsILocale>     system_locale;
   1.359 +    nsresult                result;
   1.360 +
   1.361 +    result = GetSystemLocale(getter_AddRefs(system_locale));
   1.362 +    if (NS_SUCCEEDED(result))
   1.363 +    {
   1.364 +        result = system_locale->
   1.365 +                 GetCategory(NS_LITERAL_STRING(NSILOCALE_MESSAGE), retval);
   1.366 +        return result;
   1.367 +    }
   1.368 +
   1.369 +    return result;
   1.370 +}
   1.371 +
   1.372 +
   1.373 +
   1.374 +nsresult
   1.375 +NS_NewLocaleService(nsILocaleService** result)
   1.376 +{
   1.377 +  if(!result)
   1.378 +    return NS_ERROR_NULL_POINTER;
   1.379 +  *result = new nsLocaleService();
   1.380 +  if (! *result)
   1.381 +    return NS_ERROR_OUT_OF_MEMORY;
   1.382 +  NS_ADDREF(*result);
   1.383 +  return NS_OK;
   1.384 +}

mercurial