Wed, 31 Dec 2014 07:22:50 +0100
Correct previous dual key logic pending first delivery installment.
michael@0 | 1 | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
michael@0 | 2 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 5 | |
michael@0 | 6 | #include "nsCollationMacUC.h" |
michael@0 | 7 | #include "nsILocaleService.h" |
michael@0 | 8 | #include "nsIServiceManager.h" |
michael@0 | 9 | #include "prmem.h" |
michael@0 | 10 | #include "nsString.h" |
michael@0 | 11 | |
michael@0 | 12 | NS_IMPL_ISUPPORTS(nsCollationMacUC, nsICollation) |
michael@0 | 13 | |
michael@0 | 14 | nsCollationMacUC::nsCollationMacUC() |
michael@0 | 15 | : mInit(false) |
michael@0 | 16 | , mHasCollator(false) |
michael@0 | 17 | , mLocale(nullptr) |
michael@0 | 18 | , mLastStrength(-1) |
michael@0 | 19 | , mCollator(nullptr) |
michael@0 | 20 | , mBuffer(nullptr) |
michael@0 | 21 | , mBufferLen(1) |
michael@0 | 22 | { |
michael@0 | 23 | } |
michael@0 | 24 | |
michael@0 | 25 | nsCollationMacUC::~nsCollationMacUC() |
michael@0 | 26 | { |
michael@0 | 27 | if (mHasCollator) { |
michael@0 | 28 | #ifdef DEBUG |
michael@0 | 29 | OSStatus err = |
michael@0 | 30 | #endif |
michael@0 | 31 | ::UCDisposeCollator(&mCollator); |
michael@0 | 32 | mHasCollator = false; |
michael@0 | 33 | NS_ASSERTION((err == noErr), "UCDisposeCollator failed"); |
michael@0 | 34 | } |
michael@0 | 35 | PR_FREEIF(mBuffer); |
michael@0 | 36 | } |
michael@0 | 37 | |
michael@0 | 38 | nsresult nsCollationMacUC::StrengthToOptions(const int32_t aStrength, |
michael@0 | 39 | UCCollateOptions* aOptions) |
michael@0 | 40 | { |
michael@0 | 41 | NS_ENSURE_ARG_POINTER(aOptions); |
michael@0 | 42 | NS_ENSURE_TRUE((aStrength < 4), NS_ERROR_FAILURE); |
michael@0 | 43 | // set our default collation options |
michael@0 | 44 | UCCollateOptions options = kUCCollateStandardOptions | kUCCollatePunctuationSignificantMask; |
michael@0 | 45 | if (aStrength & kCollationCaseInsensitiveAscii) |
michael@0 | 46 | options |= kUCCollateCaseInsensitiveMask; |
michael@0 | 47 | if (aStrength & kCollationAccentInsenstive) |
michael@0 | 48 | options |= kUCCollateDiacritInsensitiveMask; |
michael@0 | 49 | *aOptions = options; |
michael@0 | 50 | return NS_OK; |
michael@0 | 51 | } |
michael@0 | 52 | |
michael@0 | 53 | nsresult nsCollationMacUC::ConvertLocale(nsILocale* aNSLocale, LocaleRef* aMacLocale) |
michael@0 | 54 | { |
michael@0 | 55 | NS_ENSURE_ARG_POINTER(aNSLocale); |
michael@0 | 56 | NS_ENSURE_ARG_POINTER(aMacLocale); |
michael@0 | 57 | |
michael@0 | 58 | nsAutoString localeString; |
michael@0 | 59 | nsresult res = aNSLocale->GetCategory(NS_LITERAL_STRING("NSILOCALE_COLLATE"), localeString); |
michael@0 | 60 | NS_ENSURE_TRUE(NS_SUCCEEDED(res) && !localeString.IsEmpty(), |
michael@0 | 61 | NS_ERROR_FAILURE); |
michael@0 | 62 | NS_LossyConvertUTF16toASCII tmp(localeString); |
michael@0 | 63 | tmp.ReplaceChar('-', '_'); |
michael@0 | 64 | OSStatus err; |
michael@0 | 65 | err = ::LocaleRefFromLocaleString(tmp.get(), aMacLocale); |
michael@0 | 66 | NS_ENSURE_TRUE((err == noErr), NS_ERROR_FAILURE); |
michael@0 | 67 | |
michael@0 | 68 | return NS_OK; |
michael@0 | 69 | } |
michael@0 | 70 | |
michael@0 | 71 | nsresult nsCollationMacUC::EnsureCollator(const int32_t newStrength) |
michael@0 | 72 | { |
michael@0 | 73 | NS_ENSURE_TRUE(mInit, NS_ERROR_NOT_INITIALIZED); |
michael@0 | 74 | if (mHasCollator && (mLastStrength == newStrength)) |
michael@0 | 75 | return NS_OK; |
michael@0 | 76 | |
michael@0 | 77 | OSStatus err; |
michael@0 | 78 | if (mHasCollator) { |
michael@0 | 79 | err = ::UCDisposeCollator(&mCollator); |
michael@0 | 80 | mHasCollator = false; |
michael@0 | 81 | NS_ENSURE_TRUE((err == noErr), NS_ERROR_FAILURE); |
michael@0 | 82 | } |
michael@0 | 83 | |
michael@0 | 84 | UCCollateOptions newOptions; |
michael@0 | 85 | nsresult res = StrengthToOptions(newStrength, &newOptions); |
michael@0 | 86 | NS_ENSURE_SUCCESS(res, res); |
michael@0 | 87 | |
michael@0 | 88 | LocaleOperationVariant opVariant = 0; // default variant for now |
michael@0 | 89 | err = ::UCCreateCollator(mLocale, opVariant, newOptions, &mCollator); |
michael@0 | 90 | NS_ENSURE_TRUE((err == noErr), NS_ERROR_FAILURE); |
michael@0 | 91 | mHasCollator = true; |
michael@0 | 92 | |
michael@0 | 93 | mLastStrength = newStrength; |
michael@0 | 94 | return NS_OK; |
michael@0 | 95 | } |
michael@0 | 96 | |
michael@0 | 97 | NS_IMETHODIMP nsCollationMacUC::Initialize(nsILocale* locale) |
michael@0 | 98 | { |
michael@0 | 99 | NS_ENSURE_TRUE((!mInit), NS_ERROR_ALREADY_INITIALIZED); |
michael@0 | 100 | nsCOMPtr<nsILocale> appLocale; |
michael@0 | 101 | |
michael@0 | 102 | nsresult rv; |
michael@0 | 103 | if (!locale) { |
michael@0 | 104 | nsCOMPtr<nsILocaleService> localeService = do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv); |
michael@0 | 105 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 106 | rv = localeService->GetApplicationLocale(getter_AddRefs(appLocale)); |
michael@0 | 107 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 108 | locale = appLocale; |
michael@0 | 109 | } |
michael@0 | 110 | |
michael@0 | 111 | rv = ConvertLocale(locale, &mLocale); |
michael@0 | 112 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 113 | |
michael@0 | 114 | mInit = true; |
michael@0 | 115 | return NS_OK; |
michael@0 | 116 | } |
michael@0 | 117 | |
michael@0 | 118 | NS_IMETHODIMP nsCollationMacUC::AllocateRawSortKey(int32_t strength, const nsAString& stringIn, |
michael@0 | 119 | uint8_t** key, uint32_t* outLen) |
michael@0 | 120 | { |
michael@0 | 121 | NS_ENSURE_TRUE(mInit, NS_ERROR_NOT_INITIALIZED); |
michael@0 | 122 | NS_ENSURE_ARG_POINTER(key); |
michael@0 | 123 | NS_ENSURE_ARG_POINTER(outLen); |
michael@0 | 124 | |
michael@0 | 125 | nsresult res = EnsureCollator(strength); |
michael@0 | 126 | NS_ENSURE_SUCCESS(res, res); |
michael@0 | 127 | |
michael@0 | 128 | uint32_t stringInLen = stringIn.Length(); |
michael@0 | 129 | uint32_t maxKeyLen = (1 + stringInLen) * kCollationValueSizeFactor * sizeof(UCCollationValue); |
michael@0 | 130 | if (maxKeyLen > mBufferLen) { |
michael@0 | 131 | uint32_t newBufferLen = mBufferLen; |
michael@0 | 132 | do { |
michael@0 | 133 | newBufferLen *= 2; |
michael@0 | 134 | } while (newBufferLen < maxKeyLen); |
michael@0 | 135 | void *newBuffer = PR_Malloc(newBufferLen); |
michael@0 | 136 | if (!newBuffer) |
michael@0 | 137 | return NS_ERROR_OUT_OF_MEMORY; |
michael@0 | 138 | |
michael@0 | 139 | PR_FREEIF(mBuffer); |
michael@0 | 140 | mBuffer = newBuffer; |
michael@0 | 141 | mBufferLen = newBufferLen; |
michael@0 | 142 | } |
michael@0 | 143 | |
michael@0 | 144 | ItemCount actual; |
michael@0 | 145 | OSStatus err = ::UCGetCollationKey(mCollator, (const UniChar*) PromiseFlatString(stringIn).get(), |
michael@0 | 146 | (UniCharCount) stringInLen, |
michael@0 | 147 | (ItemCount) (mBufferLen / sizeof(UCCollationValue)), |
michael@0 | 148 | &actual, (UCCollationValue *)mBuffer); |
michael@0 | 149 | NS_ENSURE_TRUE((err == noErr), NS_ERROR_FAILURE); |
michael@0 | 150 | |
michael@0 | 151 | uint32_t keyLength = actual * sizeof(UCCollationValue); |
michael@0 | 152 | void *newKey = PR_Malloc(keyLength); |
michael@0 | 153 | if (!newKey) |
michael@0 | 154 | return NS_ERROR_OUT_OF_MEMORY; |
michael@0 | 155 | |
michael@0 | 156 | memcpy(newKey, mBuffer, keyLength); |
michael@0 | 157 | *key = (uint8_t *)newKey; |
michael@0 | 158 | *outLen = keyLength; |
michael@0 | 159 | |
michael@0 | 160 | return NS_OK; |
michael@0 | 161 | } |
michael@0 | 162 | |
michael@0 | 163 | NS_IMETHODIMP nsCollationMacUC::CompareString(int32_t strength, const nsAString& string1, |
michael@0 | 164 | const nsAString& string2, int32_t* result) |
michael@0 | 165 | { |
michael@0 | 166 | NS_ENSURE_TRUE(mInit, NS_ERROR_NOT_INITIALIZED); |
michael@0 | 167 | NS_ENSURE_ARG_POINTER(result); |
michael@0 | 168 | *result = 0; |
michael@0 | 169 | |
michael@0 | 170 | nsresult res = EnsureCollator(strength); |
michael@0 | 171 | NS_ENSURE_SUCCESS(res, res); |
michael@0 | 172 | *result = 0; |
michael@0 | 173 | |
michael@0 | 174 | OSStatus err; |
michael@0 | 175 | err = ::UCCompareText(mCollator, |
michael@0 | 176 | (const UniChar *) PromiseFlatString(string1).get(), (UniCharCount) string1.Length(), |
michael@0 | 177 | (const UniChar *) PromiseFlatString(string2).get(), (UniCharCount) string2.Length(), |
michael@0 | 178 | nullptr, (SInt32*) result); |
michael@0 | 179 | |
michael@0 | 180 | NS_ENSURE_TRUE((err == noErr), NS_ERROR_FAILURE); |
michael@0 | 181 | return NS_OK; |
michael@0 | 182 | } |
michael@0 | 183 | |
michael@0 | 184 | NS_IMETHODIMP nsCollationMacUC::CompareRawSortKey(const uint8_t* key1, uint32_t len1, |
michael@0 | 185 | const uint8_t* key2, uint32_t len2, |
michael@0 | 186 | int32_t* result) |
michael@0 | 187 | { |
michael@0 | 188 | NS_ENSURE_TRUE(mInit, NS_ERROR_NOT_INITIALIZED); |
michael@0 | 189 | NS_ENSURE_ARG_POINTER(key1); |
michael@0 | 190 | NS_ENSURE_ARG_POINTER(key2); |
michael@0 | 191 | NS_ENSURE_ARG_POINTER(result); |
michael@0 | 192 | *result = 0; |
michael@0 | 193 | |
michael@0 | 194 | OSStatus err; |
michael@0 | 195 | err = ::UCCompareCollationKeys((const UCCollationValue*) key1, (ItemCount) len1, |
michael@0 | 196 | (const UCCollationValue*) key2, (ItemCount) len2, |
michael@0 | 197 | nullptr, (SInt32*) result); |
michael@0 | 198 | |
michael@0 | 199 | NS_ENSURE_TRUE((err == noErr), NS_ERROR_FAILURE); |
michael@0 | 200 | |
michael@0 | 201 | return NS_OK; |
michael@0 | 202 | } |