1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/intl/locale/src/unix/nsCollationUnix.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,189 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 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 +#include <locale.h> 1.10 +#include "prmem.h" 1.11 +#include "nsCollationUnix.h" 1.12 +#include "nsIServiceManager.h" 1.13 +#include "nsIComponentManager.h" 1.14 +#include "nsILocaleService.h" 1.15 +#include "nsIPlatformCharset.h" 1.16 +#include "nsPosixLocale.h" 1.17 +#include "nsCOMPtr.h" 1.18 +#include "nsUnicharUtils.h" 1.19 +#include "nsCRT.h" 1.20 +//#define DEBUG_UNIX_COLLATION 1.21 + 1.22 +inline void nsCollationUnix::DoSetLocale() 1.23 +{ 1.24 + char *locale = setlocale(LC_COLLATE, nullptr); 1.25 + mSavedLocale.Assign(locale ? locale : ""); 1.26 + if (!mSavedLocale.EqualsIgnoreCase(mLocale.get())) { 1.27 + (void) setlocale(LC_COLLATE, PromiseFlatCString(Substring(mLocale,0,MAX_LOCALE_LEN)).get()); 1.28 + } 1.29 +} 1.30 + 1.31 +inline void nsCollationUnix::DoRestoreLocale() 1.32 +{ 1.33 + if (!mSavedLocale.EqualsIgnoreCase(mLocale.get())) { 1.34 + (void) setlocale(LC_COLLATE, PromiseFlatCString(Substring(mSavedLocale,0,MAX_LOCALE_LEN)).get()); 1.35 + } 1.36 +} 1.37 + 1.38 +nsCollationUnix::nsCollationUnix() : mCollation(nullptr) 1.39 +{ 1.40 +} 1.41 + 1.42 +nsCollationUnix::~nsCollationUnix() 1.43 +{ 1.44 + if (mCollation) 1.45 + delete mCollation; 1.46 +} 1.47 + 1.48 +NS_IMPL_ISUPPORTS(nsCollationUnix, nsICollation) 1.49 + 1.50 +nsresult nsCollationUnix::Initialize(nsILocale* locale) 1.51 +{ 1.52 +#define kPlatformLocaleLength 64 1.53 + NS_ASSERTION(!mCollation, "Should only be initialized once"); 1.54 + 1.55 + nsresult res; 1.56 + 1.57 + mCollation = new nsCollation; 1.58 + 1.59 + // default platform locale 1.60 + mLocale.Assign('C'); 1.61 + 1.62 + nsAutoString localeStr; 1.63 + NS_NAMED_LITERAL_STRING(aCategory, "NSILOCALE_COLLATE##PLATFORM"); 1.64 + 1.65 + // get locale string, use app default if no locale specified 1.66 + if (locale == nullptr) { 1.67 + nsCOMPtr<nsILocaleService> localeService = 1.68 + do_GetService(NS_LOCALESERVICE_CONTRACTID, &res); 1.69 + if (NS_SUCCEEDED(res)) { 1.70 + nsCOMPtr<nsILocale> appLocale; 1.71 + res = localeService->GetApplicationLocale(getter_AddRefs(appLocale)); 1.72 + if (NS_SUCCEEDED(res)) { 1.73 + res = appLocale->GetCategory(aCategory, localeStr); 1.74 + NS_ASSERTION(NS_SUCCEEDED(res), "failed to get app locale info"); 1.75 + } 1.76 + } 1.77 + } 1.78 + else { 1.79 + res = locale->GetCategory(aCategory, localeStr); 1.80 + NS_ASSERTION(NS_SUCCEEDED(res), "failed to get locale info"); 1.81 + } 1.82 + 1.83 + // Get platform locale and charset name from locale, if available 1.84 + if (NS_SUCCEEDED(res)) { 1.85 + // keep the same behavior as 4.x as well as avoiding Linux collation key problem 1.86 + if (localeStr.LowerCaseEqualsLiteral("en_us")) { // note: locale is in platform format 1.87 + localeStr.AssignLiteral("C"); 1.88 + } 1.89 + 1.90 + nsPosixLocale::GetPlatformLocale(localeStr, mLocale); 1.91 + 1.92 + nsCOMPtr <nsIPlatformCharset> platformCharset = do_GetService(NS_PLATFORMCHARSET_CONTRACTID, &res); 1.93 + if (NS_SUCCEEDED(res)) { 1.94 + nsAutoCString mappedCharset; 1.95 + res = platformCharset->GetDefaultCharsetForLocale(localeStr, mappedCharset); 1.96 + if (NS_SUCCEEDED(res)) { 1.97 + mCollation->SetCharset(mappedCharset.get()); 1.98 + } 1.99 + } 1.100 + } 1.101 + 1.102 + return NS_OK; 1.103 +} 1.104 + 1.105 + 1.106 +nsresult nsCollationUnix::CompareString(int32_t strength, 1.107 + const nsAString& string1, 1.108 + const nsAString& string2, 1.109 + int32_t* result) 1.110 +{ 1.111 + nsresult res = NS_OK; 1.112 + 1.113 + nsAutoString stringNormalized1, stringNormalized2; 1.114 + if (strength != kCollationCaseSensitive) { 1.115 + res = mCollation->NormalizeString(string1, stringNormalized1); 1.116 + if (NS_FAILED(res)) { 1.117 + return res; 1.118 + } 1.119 + res = mCollation->NormalizeString(string2, stringNormalized2); 1.120 + if (NS_FAILED(res)) { 1.121 + return res; 1.122 + } 1.123 + } else { 1.124 + stringNormalized1 = string1; 1.125 + stringNormalized2 = string2; 1.126 + } 1.127 + 1.128 + // convert unicode to charset 1.129 + char *str1, *str2; 1.130 + 1.131 + res = mCollation->UnicodeToChar(stringNormalized1, &str1); 1.132 + if (NS_SUCCEEDED(res) && str1) { 1.133 + res = mCollation->UnicodeToChar(stringNormalized2, &str2); 1.134 + if (NS_SUCCEEDED(res) && str2) { 1.135 + DoSetLocale(); 1.136 + *result = strcoll(str1, str2); 1.137 + DoRestoreLocale(); 1.138 + PR_Free(str2); 1.139 + } 1.140 + PR_Free(str1); 1.141 + } 1.142 + 1.143 + return res; 1.144 +} 1.145 + 1.146 + 1.147 +nsresult nsCollationUnix::AllocateRawSortKey(int32_t strength, 1.148 + const nsAString& stringIn, 1.149 + uint8_t** key, uint32_t* outLen) 1.150 +{ 1.151 + nsresult res = NS_OK; 1.152 + 1.153 + nsAutoString stringNormalized; 1.154 + if (strength != kCollationCaseSensitive) { 1.155 + res = mCollation->NormalizeString(stringIn, stringNormalized); 1.156 + if (NS_FAILED(res)) 1.157 + return res; 1.158 + } else { 1.159 + stringNormalized = stringIn; 1.160 + } 1.161 + // convert unicode to charset 1.162 + char *str; 1.163 + 1.164 + res = mCollation->UnicodeToChar(stringNormalized, &str); 1.165 + if (NS_SUCCEEDED(res) && str) { 1.166 + DoSetLocale(); 1.167 + // call strxfrm to generate a key 1.168 + size_t len = strxfrm(nullptr, str, 0) + 1; 1.169 + void *buffer = PR_Malloc(len); 1.170 + if (!buffer) { 1.171 + res = NS_ERROR_OUT_OF_MEMORY; 1.172 + } else if (strxfrm((char *)buffer, str, len) >= len) { 1.173 + PR_Free(buffer); 1.174 + res = NS_ERROR_FAILURE; 1.175 + } else { 1.176 + *key = (uint8_t *)buffer; 1.177 + *outLen = len; 1.178 + } 1.179 + DoRestoreLocale(); 1.180 + PR_Free(str); 1.181 + } 1.182 + 1.183 + return res; 1.184 +} 1.185 + 1.186 +nsresult nsCollationUnix::CompareRawSortKey(const uint8_t* key1, uint32_t len1, 1.187 + const uint8_t* key2, uint32_t len2, 1.188 + int32_t* result) 1.189 +{ 1.190 + *result = PL_strcmp((const char *)key1, (const char *)key2); 1.191 + return NS_OK; 1.192 +}