/* -*- 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 constantsconstintLocaleListLength=6;constchar*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))staticintposix_locale_category[LocaleListLength]={LC_COLLATE,LC_CTYPE,LC_MONETARY,LC_NUMERIC,LC_TIME,#ifdef HAVE_I18N_LC_MESSAGESLC_MESSAGES#elseLC_CTYPE#endif};#endif//// nsILocaleService implementation//classnsLocaleService:publicnsILocaleService{public://// nsISupports//NS_DECL_THREADSAFE_ISUPPORTS//// nsILocaleService//NS_DECL_NSILOCALESERVICEnsLocaleService(void);protected:nsresultSetSystemLocale(void);nsresultSetApplicationLocale(void);nsCOMPtr<nsILocale>mSystemLocale;nsCOMPtr<nsILocale>mApplicationLocale;virtual~nsLocaleService(void);};//// nsLocaleService methods//nsLocaleService::nsLocaleService(void){#ifdef XP_WINnsAutoStringxpLocale;//// get the system LCID//LCIDwin_lcid=GetSystemDefaultLCID();NS_ENSURE_TRUE_VOID(win_lcid);nsWin32Locale::GetXPLocale(win_lcid,xpLocale);nsresultrv=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(newnsLocale());NS_ENSURE_TRUE_VOID(resultLocale);// Get system configurationconstchar*lang=getenv("LANG");nsAutoStringxpLocale,platformLocale;nsAutoStringcategory,category_platform;inti;for(i=0;i<LocaleListLength;i++){nsresultresult;// setlocale( , "") evaluates LC_* and LANGchar*lc_temp=setlocale(posix_locale_category[i],"");CopyASCIItoUTF16(LocaleList[i],category);category_platform=category;category_platform.AppendLiteral("##PLATFORM");boollc_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;#endifif(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 localeCFLocaleRefuserLocaleRef=::CFLocaleCopyCurrent();CFStringRefuserLocaleStr=::CFLocaleGetIdentifier(userLocaleRef);::CFRetain(userLocaleStr);AutoTArray<UniChar,32>buffer;intsize=::CFStringGetLength(userLocaleStr);buffer.SetLength(size+1);CFRangerange=::CFRangeMake(0,size);::CFStringGetCharacters(userLocaleStr,range,buffer.Elements());buffer[size]=0;// Convert the locale string to the format that Mozilla expectsnsAutoStringxpLocale(reinterpret_cast<char16_t*>(buffer.Elements()));xpLocale.ReplaceChar('_','-');nsresultrv=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_IMETHODIMPnsLocaleService::NewLocale(constnsAString&aLocale,nsILocale**_retval){nsresultresult;*_retval=nullptr;RefPtr<nsLocale>resultLocale(newnsLocale());if(!resultLocale)returnNS_ERROR_OUT_OF_MEMORY;for(int32_ti=0;i<LocaleListLength;i++){NS_ConvertASCIItoUTF16category(LocaleList[i]);result=resultLocale->AddCategory(category,aLocale);if(NS_FAILED(result))returnresult;#if defined(XP_UNIX) && !defined(XP_MACOSX)category.AppendLiteral("##PLATFORM");result=resultLocale->AddCategory(category,aLocale);if(NS_FAILED(result))returnresult;#endif}NS_ADDREF(*_retval=resultLocale);returnNS_OK;}NS_IMETHODIMPnsLocaleService::GetSystemLocale(nsILocale**_retval){if(mSystemLocale){NS_ADDREF(*_retval=mSystemLocale);returnNS_OK;}*_retval=(nsILocale*)nullptr;returnNS_ERROR_FAILURE;}NS_IMETHODIMPnsLocaleService::GetApplicationLocale(nsILocale**_retval){if(mApplicationLocale){NS_ADDREF(*_retval=mApplicationLocale);returnNS_OK;}*_retval=(nsILocale*)nullptr;returnNS_ERROR_FAILURE;}NS_IMETHODIMPnsLocaleService::GetLocaleFromAcceptLanguage(constchar*acceptLanguage,nsILocale**_retval){char*cPtr;char*cPtr1;char*cPtr2;inti;intj;intcountLang=0;characceptLanguageList[NSILOCALE_MAX_ACCEPT_LANGUAGE][NSILOCALE_MAX_ACCEPT_LENGTH];nsresultresult;autoinput=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 */elseif(isspace(*cPtr1));/* ignore any space */elseif(*cPtr1=='-')*cPtr2++='_';/* "-" -> "_" */elseif(*cPtr1=='*');/* ignore "*" */else*cPtr2++=*cPtr1;/* else unchanged */}*cPtr2='\0';countLang=0;if(strchr(input.get(),';')){/* deal with the quality values */floatqvalue[NSILOCALE_MAX_ACCEPT_LANGUAGE];floatqSwap;floatbias=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//returnresult;}nsresultnsLocaleService::GetLocaleComponentForUserAgent(nsAString&retval){nsCOMPtr<nsILocale>system_locale;nsresultresult;result=GetSystemLocale(getter_AddRefs(system_locale));if(NS_SUCCEEDED(result)){result=system_locale->GetCategory(NS_LITERAL_STRING(NSILOCALE_MESSAGE),retval);returnresult;}returnresult;}nsresultNS_NewLocaleService(nsILocaleService**result){if(!result)returnNS_ERROR_NULL_POINTER;*result=newnsLocaleService();if(!*result)returnNS_ERROR_OUT_OF_MEMORY;NS_ADDREF(*result);returnNS_OK;}