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 +}