intl/locale/src/nsLocaleService.cpp

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

michael@0 1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #ifdef MOZ_WIDGET_QT
michael@0 7 #include <QString>
michael@0 8 #include <QtCore/QLocale>
michael@0 9 #endif
michael@0 10
michael@0 11 #include "nsCOMPtr.h"
michael@0 12 #include "nsAutoPtr.h"
michael@0 13 #include "nsILocale.h"
michael@0 14 #include "nsILocaleService.h"
michael@0 15 #include "nsLocale.h"
michael@0 16 #include "nsCRT.h"
michael@0 17 #include "prprf.h"
michael@0 18 #include "nsTArray.h"
michael@0 19 #include "nsString.h"
michael@0 20
michael@0 21 #include <ctype.h>
michael@0 22
michael@0 23 #if defined(XP_WIN)
michael@0 24 # include "nsWin32Locale.h"
michael@0 25 #elif defined(XP_MACOSX)
michael@0 26 # include <Carbon/Carbon.h>
michael@0 27 #elif defined(XP_UNIX)
michael@0 28 # include <locale.h>
michael@0 29 # include <stdlib.h>
michael@0 30 # include "nsPosixLocale.h"
michael@0 31 #endif
michael@0 32
michael@0 33 //
michael@0 34 // implementation constants
michael@0 35 const int LocaleListLength = 6;
michael@0 36 const char* LocaleList[LocaleListLength] =
michael@0 37 {
michael@0 38 NSILOCALE_COLLATE,
michael@0 39 NSILOCALE_CTYPE,
michael@0 40 NSILOCALE_MONETARY,
michael@0 41 NSILOCALE_NUMERIC,
michael@0 42 NSILOCALE_TIME,
michael@0 43 NSILOCALE_MESSAGE
michael@0 44 };
michael@0 45
michael@0 46 #define NSILOCALE_MAX_ACCEPT_LANGUAGE 16
michael@0 47 #define NSILOCALE_MAX_ACCEPT_LENGTH 18
michael@0 48
michael@0 49 #if (defined(XP_UNIX) && !defined(XP_MACOSX))
michael@0 50 static int posix_locale_category[LocaleListLength] =
michael@0 51 {
michael@0 52 LC_COLLATE,
michael@0 53 LC_CTYPE,
michael@0 54 LC_MONETARY,
michael@0 55 LC_NUMERIC,
michael@0 56 LC_TIME,
michael@0 57 #ifdef HAVE_I18N_LC_MESSAGES
michael@0 58 LC_MESSAGES
michael@0 59 #else
michael@0 60 LC_CTYPE
michael@0 61 #endif
michael@0 62 };
michael@0 63 #endif
michael@0 64
michael@0 65 //
michael@0 66 // nsILocaleService implementation
michael@0 67 //
michael@0 68 class nsLocaleService: public nsILocaleService {
michael@0 69
michael@0 70 public:
michael@0 71
michael@0 72 //
michael@0 73 // nsISupports
michael@0 74 //
michael@0 75 NS_DECL_THREADSAFE_ISUPPORTS
michael@0 76
michael@0 77 //
michael@0 78 // nsILocaleService
michael@0 79 //
michael@0 80 NS_DECL_NSILOCALESERVICE
michael@0 81
michael@0 82
michael@0 83 nsLocaleService(void);
michael@0 84 virtual ~nsLocaleService(void);
michael@0 85
michael@0 86 protected:
michael@0 87
michael@0 88 nsresult SetSystemLocale(void);
michael@0 89 nsresult SetApplicationLocale(void);
michael@0 90
michael@0 91 nsCOMPtr<nsILocale> mSystemLocale;
michael@0 92 nsCOMPtr<nsILocale> mApplicationLocale;
michael@0 93
michael@0 94 };
michael@0 95
michael@0 96 //
michael@0 97 // nsLocaleService methods
michael@0 98 //
michael@0 99 nsLocaleService::nsLocaleService(void)
michael@0 100 {
michael@0 101 #ifdef XP_WIN
michael@0 102 nsAutoString xpLocale;
michael@0 103 //
michael@0 104 // get the system LCID
michael@0 105 //
michael@0 106 LCID win_lcid = GetSystemDefaultLCID();
michael@0 107 NS_ENSURE_TRUE_VOID(win_lcid);
michael@0 108 nsWin32Locale::GetXPLocale(win_lcid, xpLocale);
michael@0 109 nsresult rv = NewLocale(xpLocale, getter_AddRefs(mSystemLocale));
michael@0 110 NS_ENSURE_SUCCESS_VOID(rv);
michael@0 111
michael@0 112 //
michael@0 113 // get the application LCID
michael@0 114 //
michael@0 115 win_lcid = GetUserDefaultLCID();
michael@0 116 NS_ENSURE_TRUE_VOID(win_lcid);
michael@0 117 nsWin32Locale::GetXPLocale(win_lcid, xpLocale);
michael@0 118 rv = NewLocale(xpLocale, getter_AddRefs(mApplicationLocale));
michael@0 119 NS_ENSURE_SUCCESS_VOID(rv);
michael@0 120 #endif
michael@0 121 #if defined(XP_UNIX) && !defined(XP_MACOSX)
michael@0 122 nsRefPtr<nsLocale> resultLocale(new nsLocale());
michael@0 123 NS_ENSURE_TRUE_VOID(resultLocale);
michael@0 124
michael@0 125 #ifdef MOZ_WIDGET_QT
michael@0 126 const char* lang = QLocale::system().name().toUtf8();
michael@0 127 #else
michael@0 128 // Get system configuration
michael@0 129 const char* lang = getenv("LANG");
michael@0 130 #endif
michael@0 131
michael@0 132 nsAutoString xpLocale, platformLocale;
michael@0 133 nsAutoString category, category_platform;
michael@0 134 int i;
michael@0 135
michael@0 136 for( i = 0; i < LocaleListLength; i++ ) {
michael@0 137 nsresult result;
michael@0 138 // setlocale( , "") evaluates LC_* and LANG
michael@0 139 char* lc_temp = setlocale(posix_locale_category[i], "");
michael@0 140 CopyASCIItoUTF16(LocaleList[i], category);
michael@0 141 category_platform = category;
michael@0 142 category_platform.AppendLiteral("##PLATFORM");
michael@0 143 if (lc_temp != nullptr) {
michael@0 144 result = nsPosixLocale::GetXPLocale(lc_temp, xpLocale);
michael@0 145 CopyASCIItoUTF16(lc_temp, platformLocale);
michael@0 146 } else {
michael@0 147 if ( lang == nullptr ) {
michael@0 148 platformLocale.AssignLiteral("en_US");
michael@0 149 result = nsPosixLocale::GetXPLocale("en-US", xpLocale);
michael@0 150 } else {
michael@0 151 CopyASCIItoUTF16(lang, platformLocale);
michael@0 152 result = nsPosixLocale::GetXPLocale(lang, xpLocale);
michael@0 153 }
michael@0 154 }
michael@0 155 if (NS_FAILED(result)) {
michael@0 156 return;
michael@0 157 }
michael@0 158 resultLocale->AddCategory(category, xpLocale);
michael@0 159 resultLocale->AddCategory(category_platform, platformLocale);
michael@0 160 }
michael@0 161 mSystemLocale = do_QueryInterface(resultLocale);
michael@0 162 mApplicationLocale = do_QueryInterface(resultLocale);
michael@0 163
michael@0 164 #endif // XP_UNIX
michael@0 165
michael@0 166 #ifdef XP_MACOSX
michael@0 167 // Get string representation of user's current locale
michael@0 168 CFLocaleRef userLocaleRef = ::CFLocaleCopyCurrent();
michael@0 169 CFStringRef userLocaleStr = ::CFLocaleGetIdentifier(userLocaleRef);
michael@0 170 ::CFRetain(userLocaleStr);
michael@0 171
michael@0 172 nsAutoTArray<UniChar, 32> buffer;
michael@0 173 int size = ::CFStringGetLength(userLocaleStr);
michael@0 174 buffer.SetLength(size + 1);
michael@0 175 CFRange range = ::CFRangeMake(0, size);
michael@0 176 ::CFStringGetCharacters(userLocaleStr, range, buffer.Elements());
michael@0 177 buffer[size] = 0;
michael@0 178
michael@0 179 // Convert the locale string to the format that Mozilla expects
michael@0 180 nsAutoString xpLocale(reinterpret_cast<char16_t*>(buffer.Elements()));
michael@0 181 xpLocale.ReplaceChar('_', '-');
michael@0 182
michael@0 183 nsresult rv = NewLocale(xpLocale, getter_AddRefs(mSystemLocale));
michael@0 184 if (NS_SUCCEEDED(rv)) {
michael@0 185 mApplicationLocale = mSystemLocale;
michael@0 186 }
michael@0 187
michael@0 188 ::CFRelease(userLocaleStr);
michael@0 189 ::CFRelease(userLocaleRef);
michael@0 190
michael@0 191 NS_ASSERTION(mApplicationLocale, "Failed to create locale objects");
michael@0 192 #endif // XP_MACOSX
michael@0 193 }
michael@0 194
michael@0 195 nsLocaleService::~nsLocaleService(void)
michael@0 196 {
michael@0 197 }
michael@0 198
michael@0 199 NS_IMPL_ISUPPORTS(nsLocaleService, nsILocaleService)
michael@0 200
michael@0 201 NS_IMETHODIMP
michael@0 202 nsLocaleService::NewLocale(const nsAString &aLocale, nsILocale **_retval)
michael@0 203 {
michael@0 204 nsresult result;
michael@0 205
michael@0 206 *_retval = nullptr;
michael@0 207
michael@0 208 nsRefPtr<nsLocale> resultLocale(new nsLocale());
michael@0 209 if (!resultLocale) return NS_ERROR_OUT_OF_MEMORY;
michael@0 210
michael@0 211 for (int32_t i = 0; i < LocaleListLength; i++) {
michael@0 212 NS_ConvertASCIItoUTF16 category(LocaleList[i]);
michael@0 213 result = resultLocale->AddCategory(category, aLocale);
michael@0 214 if (NS_FAILED(result)) return result;
michael@0 215 #if defined(XP_UNIX) && !defined(XP_MACOSX)
michael@0 216 category.AppendLiteral("##PLATFORM");
michael@0 217 result = resultLocale->AddCategory(category, aLocale);
michael@0 218 if (NS_FAILED(result)) return result;
michael@0 219 #endif
michael@0 220 }
michael@0 221
michael@0 222 NS_ADDREF(*_retval = resultLocale);
michael@0 223 return NS_OK;
michael@0 224 }
michael@0 225
michael@0 226
michael@0 227 NS_IMETHODIMP
michael@0 228 nsLocaleService::GetSystemLocale(nsILocale **_retval)
michael@0 229 {
michael@0 230 if (mSystemLocale) {
michael@0 231 NS_ADDREF(*_retval = mSystemLocale);
michael@0 232 return NS_OK;
michael@0 233 }
michael@0 234
michael@0 235 *_retval = (nsILocale*)nullptr;
michael@0 236 return NS_ERROR_FAILURE;
michael@0 237 }
michael@0 238
michael@0 239 NS_IMETHODIMP
michael@0 240 nsLocaleService::GetApplicationLocale(nsILocale **_retval)
michael@0 241 {
michael@0 242 if (mApplicationLocale) {
michael@0 243 NS_ADDREF(*_retval = mApplicationLocale);
michael@0 244 return NS_OK;
michael@0 245 }
michael@0 246
michael@0 247 *_retval=(nsILocale*)nullptr;
michael@0 248 return NS_ERROR_FAILURE;
michael@0 249 }
michael@0 250
michael@0 251 NS_IMETHODIMP
michael@0 252 nsLocaleService::GetLocaleFromAcceptLanguage(const char *acceptLanguage, nsILocale **_retval)
michael@0 253 {
michael@0 254 char* cPtr;
michael@0 255 char* cPtr1;
michael@0 256 char* cPtr2;
michael@0 257 int i;
michael@0 258 int j;
michael@0 259 int countLang = 0;
michael@0 260 char acceptLanguageList[NSILOCALE_MAX_ACCEPT_LANGUAGE][NSILOCALE_MAX_ACCEPT_LENGTH];
michael@0 261 nsresult result;
michael@0 262
michael@0 263 nsAutoArrayPtr<char> input(new char[strlen(acceptLanguage)+1]);
michael@0 264
michael@0 265 strcpy(input, acceptLanguage);
michael@0 266 cPtr1 = input-1;
michael@0 267 cPtr2 = input;
michael@0 268
michael@0 269 /* put in standard form */
michael@0 270 while (*(++cPtr1)) {
michael@0 271 if (isalpha(*cPtr1)) *cPtr2++ = tolower(*cPtr1); /* force lower case */
michael@0 272 else if (isspace(*cPtr1)) ; /* ignore any space */
michael@0 273 else if (*cPtr1=='-') *cPtr2++ = '_'; /* "-" -> "_" */
michael@0 274 else if (*cPtr1=='*') ; /* ignore "*" */
michael@0 275 else *cPtr2++ = *cPtr1; /* else unchanged */
michael@0 276 }
michael@0 277 *cPtr2 = '\0';
michael@0 278
michael@0 279 countLang = 0;
michael@0 280
michael@0 281 if (strchr(input,';')) {
michael@0 282 /* deal with the quality values */
michael@0 283
michael@0 284 float qvalue[NSILOCALE_MAX_ACCEPT_LANGUAGE];
michael@0 285 float qSwap;
michael@0 286 float bias = 0.0f;
michael@0 287 char* ptrLanguage[NSILOCALE_MAX_ACCEPT_LANGUAGE];
michael@0 288 char* ptrSwap;
michael@0 289
michael@0 290 cPtr = nsCRT::strtok(input,",",&cPtr2);
michael@0 291 while (cPtr) {
michael@0 292 qvalue[countLang] = 1.0f;
michael@0 293 /* add extra parens to get rid of warning */
michael@0 294 if ((cPtr1 = strchr(cPtr,';')) != nullptr) {
michael@0 295 PR_sscanf(cPtr1,";q=%f",&qvalue[countLang]);
michael@0 296 *cPtr1 = '\0';
michael@0 297 }
michael@0 298 if (strlen(cPtr)<NSILOCALE_MAX_ACCEPT_LANGUAGE) { /* ignore if too long */
michael@0 299 qvalue[countLang] -= (bias += 0.0001f); /* to insure original order */
michael@0 300 ptrLanguage[countLang++] = cPtr;
michael@0 301 if (countLang>=NSILOCALE_MAX_ACCEPT_LANGUAGE) break; /* quit if too many */
michael@0 302 }
michael@0 303 cPtr = nsCRT::strtok(cPtr2,",",&cPtr2);
michael@0 304 }
michael@0 305
michael@0 306 /* sort according to decending qvalue */
michael@0 307 /* not a very good algorithm, but count is not likely large */
michael@0 308 for ( i=0 ; i<countLang-1 ; i++ ) {
michael@0 309 for ( j=i+1 ; j<countLang ; j++ ) {
michael@0 310 if (qvalue[i]<qvalue[j]) {
michael@0 311 qSwap = qvalue[i];
michael@0 312 qvalue[i] = qvalue[j];
michael@0 313 qvalue[j] = qSwap;
michael@0 314 ptrSwap = ptrLanguage[i];
michael@0 315 ptrLanguage[i] = ptrLanguage[j];
michael@0 316 ptrLanguage[j] = ptrSwap;
michael@0 317 }
michael@0 318 }
michael@0 319 }
michael@0 320 for ( i=0 ; i<countLang ; i++ ) {
michael@0 321 PL_strncpyz(acceptLanguageList[i],ptrLanguage[i],NSILOCALE_MAX_ACCEPT_LENGTH);
michael@0 322 }
michael@0 323
michael@0 324 } else {
michael@0 325 /* simple case: no quality values */
michael@0 326
michael@0 327 cPtr = nsCRT::strtok(input,",",&cPtr2);
michael@0 328 while (cPtr) {
michael@0 329 if (strlen(cPtr)<NSILOCALE_MAX_ACCEPT_LENGTH) { /* ignore if too long */
michael@0 330 PL_strncpyz(acceptLanguageList[countLang++],cPtr,NSILOCALE_MAX_ACCEPT_LENGTH);
michael@0 331 if (countLang>=NSILOCALE_MAX_ACCEPT_LENGTH) break; /* quit if too many */
michael@0 332 }
michael@0 333 cPtr = nsCRT::strtok(cPtr2,",",&cPtr2);
michael@0 334 }
michael@0 335 }
michael@0 336
michael@0 337 //
michael@0 338 // now create the locale
michael@0 339 //
michael@0 340 result = NS_ERROR_FAILURE;
michael@0 341 if (countLang>0) {
michael@0 342 result = NewLocale(NS_ConvertASCIItoUTF16(acceptLanguageList[0]), _retval);
michael@0 343 }
michael@0 344
michael@0 345 //
michael@0 346 // clean up
michael@0 347 //
michael@0 348 return result;
michael@0 349 }
michael@0 350
michael@0 351
michael@0 352 nsresult
michael@0 353 nsLocaleService::GetLocaleComponentForUserAgent(nsAString& retval)
michael@0 354 {
michael@0 355 nsCOMPtr<nsILocale> system_locale;
michael@0 356 nsresult result;
michael@0 357
michael@0 358 result = GetSystemLocale(getter_AddRefs(system_locale));
michael@0 359 if (NS_SUCCEEDED(result))
michael@0 360 {
michael@0 361 result = system_locale->
michael@0 362 GetCategory(NS_LITERAL_STRING(NSILOCALE_MESSAGE), retval);
michael@0 363 return result;
michael@0 364 }
michael@0 365
michael@0 366 return result;
michael@0 367 }
michael@0 368
michael@0 369
michael@0 370
michael@0 371 nsresult
michael@0 372 NS_NewLocaleService(nsILocaleService** result)
michael@0 373 {
michael@0 374 if(!result)
michael@0 375 return NS_ERROR_NULL_POINTER;
michael@0 376 *result = new nsLocaleService();
michael@0 377 if (! *result)
michael@0 378 return NS_ERROR_OUT_OF_MEMORY;
michael@0 379 NS_ADDREF(*result);
michael@0 380 return NS_OK;
michael@0 381 }

mercurial