123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345 |
- /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
- /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
- #include "nsCOMPtr.h"
- #include "nsILocale.h"
- #include "nsILocaleService.h"
- #include "nsLocale.h"
- #include "nsCRT.h"
- #include "prprf.h"
- #include "nsTArray.h"
- #include "nsString.h"
- #include "mozilla/UniquePtr.h"
- #include <ctype.h>
- #if defined(XP_WIN)
- # include "nsWin32Locale.h"
- #elif defined(XP_UNIX)
- # include <locale.h>
- # include <stdlib.h>
- # include "nsPosixLocale.h"
- #endif
- //
- // implementation constants
- const int LocaleListLength = 6;
- const char* LocaleList[LocaleListLength] =
- {
- NSILOCALE_COLLATE,
- NSILOCALE_CTYPE,
- NSILOCALE_MONETARY,
- NSILOCALE_NUMERIC,
- NSILOCALE_TIME,
- NSILOCALE_MESSAGE
- };
- #define NSILOCALE_MAX_ACCEPT_LANGUAGE 16
- #define NSILOCALE_MAX_ACCEPT_LENGTH 18
- #if defined(XP_UNIX)
- static int posix_locale_category[LocaleListLength] =
- {
- LC_COLLATE,
- LC_CTYPE,
- LC_MONETARY,
- LC_NUMERIC,
- LC_TIME,
- #ifdef HAVE_I18N_LC_MESSAGES
- LC_MESSAGES
- #else
- LC_CTYPE
- #endif
- };
- #endif
- //
- // nsILocaleService implementation
- //
- class nsLocaleService: public nsILocaleService {
- public:
-
- //
- // nsISupports
- //
- NS_DECL_THREADSAFE_ISUPPORTS
- //
- // nsILocaleService
- //
- NS_DECL_NSILOCALESERVICE
- nsLocaleService(void);
- protected:
- nsresult SetSystemLocale(void);
- nsresult SetApplicationLocale(void);
- nsCOMPtr<nsILocale> mSystemLocale;
- nsCOMPtr<nsILocale> mApplicationLocale;
- virtual ~nsLocaleService(void);
- };
- //
- // nsLocaleService methods
- //
- nsLocaleService::nsLocaleService(void)
- {
- #ifdef XP_WIN
- nsAutoString xpLocale;
- //
- // get the system LCID
- //
- LCID win_lcid = GetSystemDefaultLCID();
- NS_ENSURE_TRUE_VOID(win_lcid);
- nsWin32Locale::GetXPLocale(win_lcid, xpLocale);
- nsresult rv = NewLocale(xpLocale, getter_AddRefs(mSystemLocale));
- NS_ENSURE_SUCCESS_VOID(rv);
- //
- // get the application LCID
- //
- win_lcid = GetUserDefaultLCID();
- NS_ENSURE_TRUE_VOID(win_lcid);
- nsWin32Locale::GetXPLocale(win_lcid, xpLocale);
- rv = NewLocale(xpLocale, getter_AddRefs(mApplicationLocale));
- NS_ENSURE_SUCCESS_VOID(rv);
- #endif
- #if defined(XP_UNIX)
- RefPtr<nsLocale> resultLocale(new nsLocale());
- NS_ENSURE_TRUE_VOID(resultLocale);
- // Get system configuration
- const char* lang = getenv("LANG");
- nsAutoString xpLocale, platformLocale;
- nsAutoString category, category_platform;
- int i;
- for( i = 0; i < LocaleListLength; i++ ) {
- nsresult result;
- // setlocale( , "") evaluates LC_* and LANG
- char* lc_temp = setlocale(posix_locale_category[i], "");
- CopyASCIItoUTF16(LocaleList[i], category);
- category_platform = category;
- category_platform.AppendLiteral("##PLATFORM");
- bool lc_temp_valid = lc_temp != nullptr;
- if (lc_temp_valid) {
- result = nsPosixLocale::GetXPLocale(lc_temp, xpLocale);
- CopyASCIItoUTF16(lc_temp, platformLocale);
- } else {
- if ( lang == nullptr ) {
- platformLocale.AssignLiteral("en_US");
- result = nsPosixLocale::GetXPLocale("en-US", xpLocale);
- } else {
- CopyASCIItoUTF16(lang, platformLocale);
- result = nsPosixLocale::GetXPLocale(lang, xpLocale);
- }
- }
- if (NS_FAILED(result)) {
- return;
- }
- resultLocale->AddCategory(category, xpLocale);
- resultLocale->AddCategory(category_platform, platformLocale);
- }
- mSystemLocale = do_QueryInterface(resultLocale);
- mApplicationLocale = do_QueryInterface(resultLocale);
- #endif // XP_UNIX
- }
- nsLocaleService::~nsLocaleService(void)
- {
- }
- NS_IMPL_ISUPPORTS(nsLocaleService, nsILocaleService)
- NS_IMETHODIMP
- nsLocaleService::NewLocale(const nsAString &aLocale, nsILocale **_retval)
- {
- nsresult result;
- *_retval = nullptr;
- RefPtr<nsLocale> resultLocale(new nsLocale());
- if (!resultLocale) return NS_ERROR_OUT_OF_MEMORY;
- for (int32_t i = 0; i < LocaleListLength; i++) {
- NS_ConvertASCIItoUTF16 category(LocaleList[i]);
- result = resultLocale->AddCategory(category, aLocale);
- if (NS_FAILED(result)) return result;
- #if defined(XP_UNIX)
- category.AppendLiteral("##PLATFORM");
- result = resultLocale->AddCategory(category, aLocale);
- if (NS_FAILED(result)) return result;
- #endif
- }
- NS_ADDREF(*_retval = resultLocale);
- return NS_OK;
- }
- NS_IMETHODIMP
- nsLocaleService::GetSystemLocale(nsILocale **_retval)
- {
- if (mSystemLocale) {
- NS_ADDREF(*_retval = mSystemLocale);
- return NS_OK;
- }
- *_retval = (nsILocale*)nullptr;
- return NS_ERROR_FAILURE;
- }
- NS_IMETHODIMP
- nsLocaleService::GetApplicationLocale(nsILocale **_retval)
- {
- if (mApplicationLocale) {
- NS_ADDREF(*_retval = mApplicationLocale);
- return NS_OK;
- }
- *_retval=(nsILocale*)nullptr;
- return NS_ERROR_FAILURE;
- }
- NS_IMETHODIMP
- nsLocaleService::GetLocaleFromAcceptLanguage(const char *acceptLanguage, nsILocale **_retval)
- {
- char* cPtr;
- char* cPtr1;
- char* cPtr2;
- int i;
- int j;
- int countLang = 0;
- char acceptLanguageList[NSILOCALE_MAX_ACCEPT_LANGUAGE][NSILOCALE_MAX_ACCEPT_LENGTH];
- nsresult result;
- auto input = MakeUnique<char[]>(strlen(acceptLanguage)+1);
- strcpy(input.get(), acceptLanguage);
- cPtr1 = input.get()-1;
- cPtr2 = input.get();
- /* put in standard form */
- while (*(++cPtr1)) {
- if (isalpha(*cPtr1)) *cPtr2++ = tolower(*cPtr1); /* force lower case */
- else if (isspace(*cPtr1)) ; /* ignore any space */
- else if (*cPtr1=='-') *cPtr2++ = '_'; /* "-" -> "_" */
- else if (*cPtr1=='*') ; /* ignore "*" */
- else *cPtr2++ = *cPtr1; /* else unchanged */
- }
- *cPtr2 = '\0';
- countLang = 0;
- if (strchr(input.get(), ';')) {
- /* deal with the quality values */
- float qvalue[NSILOCALE_MAX_ACCEPT_LANGUAGE];
- float qSwap;
- float bias = 0.0f;
- char* ptrLanguage[NSILOCALE_MAX_ACCEPT_LANGUAGE];
- char* ptrSwap;
- cPtr = nsCRT::strtok(input.get(),",",&cPtr2);
- while (cPtr) {
- qvalue[countLang] = 1.0f;
- /* add extra parens to get rid of warning */
- if ((cPtr1 = strchr(cPtr,';')) != nullptr) {
- PR_sscanf(cPtr1,";q=%f",&qvalue[countLang]);
- *cPtr1 = '\0';
- }
- if (strlen(cPtr)<NSILOCALE_MAX_ACCEPT_LANGUAGE) { /* ignore if too long */
- qvalue[countLang] -= (bias += 0.0001f); /* to insure original order */
- ptrLanguage[countLang++] = cPtr;
- if (countLang>=NSILOCALE_MAX_ACCEPT_LANGUAGE) break; /* quit if too many */
- }
- cPtr = nsCRT::strtok(cPtr2,",",&cPtr2);
- }
- /* sort according to decending qvalue */
- /* not a very good algorithm, but count is not likely large */
- for ( i=0 ; i<countLang-1 ; i++ ) {
- for ( j=i+1 ; j<countLang ; j++ ) {
- if (qvalue[i]<qvalue[j]) {
- qSwap = qvalue[i];
- qvalue[i] = qvalue[j];
- qvalue[j] = qSwap;
- ptrSwap = ptrLanguage[i];
- ptrLanguage[i] = ptrLanguage[j];
- ptrLanguage[j] = ptrSwap;
- }
- }
- }
- for ( i=0 ; i<countLang ; i++ ) {
- PL_strncpyz(acceptLanguageList[i],ptrLanguage[i],NSILOCALE_MAX_ACCEPT_LENGTH);
- }
- } else {
- /* simple case: no quality values */
- cPtr = nsCRT::strtok(input.get(),",",&cPtr2);
- while (cPtr) {
- if (strlen(cPtr)<NSILOCALE_MAX_ACCEPT_LENGTH) { /* ignore if too long */
- PL_strncpyz(acceptLanguageList[countLang++],cPtr,NSILOCALE_MAX_ACCEPT_LENGTH);
- if (countLang>=NSILOCALE_MAX_ACCEPT_LENGTH) break; /* quit if too many */
- }
- cPtr = nsCRT::strtok(cPtr2,",",&cPtr2);
- }
- }
- //
- // now create the locale
- //
- result = NS_ERROR_FAILURE;
- if (countLang>0) {
- result = NewLocale(NS_ConvertASCIItoUTF16(acceptLanguageList[0]), _retval);
- }
- //
- // clean up
- //
- return result;
- }
- nsresult
- nsLocaleService::GetLocaleComponentForUserAgent(nsAString& retval)
- {
- nsCOMPtr<nsILocale> system_locale;
- nsresult result;
- result = GetSystemLocale(getter_AddRefs(system_locale));
- if (NS_SUCCEEDED(result))
- {
- result = system_locale->
- GetCategory(NS_LITERAL_STRING(NSILOCALE_MESSAGE), retval);
- return result;
- }
- return result;
- }
- nsresult
- NS_NewLocaleService(nsILocaleService** result)
- {
- if(!result)
- return NS_ERROR_NULL_POINTER;
- *result = new nsLocaleService();
- if (! *result)
- return NS_ERROR_OUT_OF_MEMORY;
- NS_ADDREF(*result);
- return NS_OK;
- }
|