summaryrefslogtreecommitdiffstats
path: root/intl/locale/nsLocaleService.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'intl/locale/nsLocaleService.cpp')
-rw-r--r--intl/locale/nsLocaleService.cpp380
1 files changed, 380 insertions, 0 deletions
diff --git a/intl/locale/nsLocaleService.cpp b/intl/locale/nsLocaleService.cpp
new file mode 100644
index 000000000..6d45ec9af
--- /dev/null
+++ b/intl/locale/nsLocaleService.cpp
@@ -0,0 +1,380 @@
+/* -*- 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_MACOSX)
+# include <Carbon/Carbon.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) && !defined(XP_MACOSX))
+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) && !defined(XP_MACOSX)
+ 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 defined(MOZ_WIDGET_ANDROID)
+ // Treat the "C" env as nothing useful. See Bug 1095298.
+ lc_temp_valid = lc_temp_valid && strcmp(lc_temp, "C") != 0;
+#endif
+
+ 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
+
+#ifdef XP_MACOSX
+ // Get string representation of user's current locale
+ CFLocaleRef userLocaleRef = ::CFLocaleCopyCurrent();
+ CFStringRef userLocaleStr = ::CFLocaleGetIdentifier(userLocaleRef);
+ ::CFRetain(userLocaleStr);
+
+ AutoTArray<UniChar, 32> buffer;
+ int size = ::CFStringGetLength(userLocaleStr);
+ buffer.SetLength(size + 1);
+ CFRange range = ::CFRangeMake(0, size);
+ ::CFStringGetCharacters(userLocaleStr, range, buffer.Elements());
+ buffer[size] = 0;
+
+ // Convert the locale string to the format that Mozilla expects
+ nsAutoString xpLocale(reinterpret_cast<char16_t*>(buffer.Elements()));
+ xpLocale.ReplaceChar('_', '-');
+
+ nsresult rv = NewLocale(xpLocale, getter_AddRefs(mSystemLocale));
+ if (NS_SUCCEEDED(rv)) {
+ mApplicationLocale = mSystemLocale;
+ }
+
+ ::CFRelease(userLocaleStr);
+ ::CFRelease(userLocaleRef);
+
+ NS_ASSERTION(mApplicationLocale, "Failed to create locale objects");
+#endif // XP_MACOSX
+}
+
+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) && !defined(XP_MACOSX)
+ 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;
+}