1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/intl/locale/src/mac/nsCollationMacUC.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,202 @@ 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 "nsCollationMacUC.h" 1.10 +#include "nsILocaleService.h" 1.11 +#include "nsIServiceManager.h" 1.12 +#include "prmem.h" 1.13 +#include "nsString.h" 1.14 + 1.15 +NS_IMPL_ISUPPORTS(nsCollationMacUC, nsICollation) 1.16 + 1.17 +nsCollationMacUC::nsCollationMacUC() 1.18 + : mInit(false) 1.19 + , mHasCollator(false) 1.20 + , mLocale(nullptr) 1.21 + , mLastStrength(-1) 1.22 + , mCollator(nullptr) 1.23 + , mBuffer(nullptr) 1.24 + , mBufferLen(1) 1.25 +{ 1.26 +} 1.27 + 1.28 +nsCollationMacUC::~nsCollationMacUC() 1.29 +{ 1.30 + if (mHasCollator) { 1.31 +#ifdef DEBUG 1.32 + OSStatus err = 1.33 +#endif 1.34 + ::UCDisposeCollator(&mCollator); 1.35 + mHasCollator = false; 1.36 + NS_ASSERTION((err == noErr), "UCDisposeCollator failed"); 1.37 + } 1.38 + PR_FREEIF(mBuffer); 1.39 +} 1.40 + 1.41 +nsresult nsCollationMacUC::StrengthToOptions(const int32_t aStrength, 1.42 + UCCollateOptions* aOptions) 1.43 +{ 1.44 + NS_ENSURE_ARG_POINTER(aOptions); 1.45 + NS_ENSURE_TRUE((aStrength < 4), NS_ERROR_FAILURE); 1.46 + // set our default collation options 1.47 + UCCollateOptions options = kUCCollateStandardOptions | kUCCollatePunctuationSignificantMask; 1.48 + if (aStrength & kCollationCaseInsensitiveAscii) 1.49 + options |= kUCCollateCaseInsensitiveMask; 1.50 + if (aStrength & kCollationAccentInsenstive) 1.51 + options |= kUCCollateDiacritInsensitiveMask; 1.52 + *aOptions = options; 1.53 + return NS_OK; 1.54 +} 1.55 + 1.56 +nsresult nsCollationMacUC::ConvertLocale(nsILocale* aNSLocale, LocaleRef* aMacLocale) 1.57 +{ 1.58 + NS_ENSURE_ARG_POINTER(aNSLocale); 1.59 + NS_ENSURE_ARG_POINTER(aMacLocale); 1.60 + 1.61 + nsAutoString localeString; 1.62 + nsresult res = aNSLocale->GetCategory(NS_LITERAL_STRING("NSILOCALE_COLLATE"), localeString); 1.63 + NS_ENSURE_TRUE(NS_SUCCEEDED(res) && !localeString.IsEmpty(), 1.64 + NS_ERROR_FAILURE); 1.65 + NS_LossyConvertUTF16toASCII tmp(localeString); 1.66 + tmp.ReplaceChar('-', '_'); 1.67 + OSStatus err; 1.68 + err = ::LocaleRefFromLocaleString(tmp.get(), aMacLocale); 1.69 + NS_ENSURE_TRUE((err == noErr), NS_ERROR_FAILURE); 1.70 + 1.71 + return NS_OK; 1.72 +} 1.73 + 1.74 +nsresult nsCollationMacUC::EnsureCollator(const int32_t newStrength) 1.75 +{ 1.76 + NS_ENSURE_TRUE(mInit, NS_ERROR_NOT_INITIALIZED); 1.77 + if (mHasCollator && (mLastStrength == newStrength)) 1.78 + return NS_OK; 1.79 + 1.80 + OSStatus err; 1.81 + if (mHasCollator) { 1.82 + err = ::UCDisposeCollator(&mCollator); 1.83 + mHasCollator = false; 1.84 + NS_ENSURE_TRUE((err == noErr), NS_ERROR_FAILURE); 1.85 + } 1.86 + 1.87 + UCCollateOptions newOptions; 1.88 + nsresult res = StrengthToOptions(newStrength, &newOptions); 1.89 + NS_ENSURE_SUCCESS(res, res); 1.90 + 1.91 + LocaleOperationVariant opVariant = 0; // default variant for now 1.92 + err = ::UCCreateCollator(mLocale, opVariant, newOptions, &mCollator); 1.93 + NS_ENSURE_TRUE((err == noErr), NS_ERROR_FAILURE); 1.94 + mHasCollator = true; 1.95 + 1.96 + mLastStrength = newStrength; 1.97 + return NS_OK; 1.98 +} 1.99 + 1.100 +NS_IMETHODIMP nsCollationMacUC::Initialize(nsILocale* locale) 1.101 +{ 1.102 + NS_ENSURE_TRUE((!mInit), NS_ERROR_ALREADY_INITIALIZED); 1.103 + nsCOMPtr<nsILocale> appLocale; 1.104 + 1.105 + nsresult rv; 1.106 + if (!locale) { 1.107 + nsCOMPtr<nsILocaleService> localeService = do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv); 1.108 + NS_ENSURE_SUCCESS(rv, rv); 1.109 + rv = localeService->GetApplicationLocale(getter_AddRefs(appLocale)); 1.110 + NS_ENSURE_SUCCESS(rv, rv); 1.111 + locale = appLocale; 1.112 + } 1.113 + 1.114 + rv = ConvertLocale(locale, &mLocale); 1.115 + NS_ENSURE_SUCCESS(rv, rv); 1.116 + 1.117 + mInit = true; 1.118 + return NS_OK; 1.119 +} 1.120 + 1.121 +NS_IMETHODIMP nsCollationMacUC::AllocateRawSortKey(int32_t strength, const nsAString& stringIn, 1.122 + uint8_t** key, uint32_t* outLen) 1.123 +{ 1.124 + NS_ENSURE_TRUE(mInit, NS_ERROR_NOT_INITIALIZED); 1.125 + NS_ENSURE_ARG_POINTER(key); 1.126 + NS_ENSURE_ARG_POINTER(outLen); 1.127 + 1.128 + nsresult res = EnsureCollator(strength); 1.129 + NS_ENSURE_SUCCESS(res, res); 1.130 + 1.131 + uint32_t stringInLen = stringIn.Length(); 1.132 + uint32_t maxKeyLen = (1 + stringInLen) * kCollationValueSizeFactor * sizeof(UCCollationValue); 1.133 + if (maxKeyLen > mBufferLen) { 1.134 + uint32_t newBufferLen = mBufferLen; 1.135 + do { 1.136 + newBufferLen *= 2; 1.137 + } while (newBufferLen < maxKeyLen); 1.138 + void *newBuffer = PR_Malloc(newBufferLen); 1.139 + if (!newBuffer) 1.140 + return NS_ERROR_OUT_OF_MEMORY; 1.141 + 1.142 + PR_FREEIF(mBuffer); 1.143 + mBuffer = newBuffer; 1.144 + mBufferLen = newBufferLen; 1.145 + } 1.146 + 1.147 + ItemCount actual; 1.148 + OSStatus err = ::UCGetCollationKey(mCollator, (const UniChar*) PromiseFlatString(stringIn).get(), 1.149 + (UniCharCount) stringInLen, 1.150 + (ItemCount) (mBufferLen / sizeof(UCCollationValue)), 1.151 + &actual, (UCCollationValue *)mBuffer); 1.152 + NS_ENSURE_TRUE((err == noErr), NS_ERROR_FAILURE); 1.153 + 1.154 + uint32_t keyLength = actual * sizeof(UCCollationValue); 1.155 + void *newKey = PR_Malloc(keyLength); 1.156 + if (!newKey) 1.157 + return NS_ERROR_OUT_OF_MEMORY; 1.158 + 1.159 + memcpy(newKey, mBuffer, keyLength); 1.160 + *key = (uint8_t *)newKey; 1.161 + *outLen = keyLength; 1.162 + 1.163 + return NS_OK; 1.164 +} 1.165 + 1.166 +NS_IMETHODIMP nsCollationMacUC::CompareString(int32_t strength, const nsAString& string1, 1.167 + const nsAString& string2, int32_t* result) 1.168 +{ 1.169 + NS_ENSURE_TRUE(mInit, NS_ERROR_NOT_INITIALIZED); 1.170 + NS_ENSURE_ARG_POINTER(result); 1.171 + *result = 0; 1.172 + 1.173 + nsresult res = EnsureCollator(strength); 1.174 + NS_ENSURE_SUCCESS(res, res); 1.175 + *result = 0; 1.176 + 1.177 + OSStatus err; 1.178 + err = ::UCCompareText(mCollator, 1.179 + (const UniChar *) PromiseFlatString(string1).get(), (UniCharCount) string1.Length(), 1.180 + (const UniChar *) PromiseFlatString(string2).get(), (UniCharCount) string2.Length(), 1.181 + nullptr, (SInt32*) result); 1.182 + 1.183 + NS_ENSURE_TRUE((err == noErr), NS_ERROR_FAILURE); 1.184 + return NS_OK; 1.185 +} 1.186 + 1.187 +NS_IMETHODIMP nsCollationMacUC::CompareRawSortKey(const uint8_t* key1, uint32_t len1, 1.188 + const uint8_t* key2, uint32_t len2, 1.189 + int32_t* result) 1.190 +{ 1.191 + NS_ENSURE_TRUE(mInit, NS_ERROR_NOT_INITIALIZED); 1.192 + NS_ENSURE_ARG_POINTER(key1); 1.193 + NS_ENSURE_ARG_POINTER(key2); 1.194 + NS_ENSURE_ARG_POINTER(result); 1.195 + *result = 0; 1.196 + 1.197 + OSStatus err; 1.198 + err = ::UCCompareCollationKeys((const UCCollationValue*) key1, (ItemCount) len1, 1.199 + (const UCCollationValue*) key2, (ItemCount) len2, 1.200 + nullptr, (SInt32*) result); 1.201 + 1.202 + NS_ENSURE_TRUE((err == noErr), NS_ERROR_FAILURE); 1.203 + 1.204 + return NS_OK; 1.205 +}