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