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