|
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/. */ |
|
5 |
|
6 #include "nsCollationMacUC.h" |
|
7 #include "nsILocaleService.h" |
|
8 #include "nsIServiceManager.h" |
|
9 #include "prmem.h" |
|
10 #include "nsString.h" |
|
11 |
|
12 NS_IMPL_ISUPPORTS(nsCollationMacUC, nsICollation) |
|
13 |
|
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 } |
|
24 |
|
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 } |
|
37 |
|
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 } |
|
52 |
|
53 nsresult nsCollationMacUC::ConvertLocale(nsILocale* aNSLocale, LocaleRef* aMacLocale) |
|
54 { |
|
55 NS_ENSURE_ARG_POINTER(aNSLocale); |
|
56 NS_ENSURE_ARG_POINTER(aMacLocale); |
|
57 |
|
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); |
|
67 |
|
68 return NS_OK; |
|
69 } |
|
70 |
|
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; |
|
76 |
|
77 OSStatus err; |
|
78 if (mHasCollator) { |
|
79 err = ::UCDisposeCollator(&mCollator); |
|
80 mHasCollator = false; |
|
81 NS_ENSURE_TRUE((err == noErr), NS_ERROR_FAILURE); |
|
82 } |
|
83 |
|
84 UCCollateOptions newOptions; |
|
85 nsresult res = StrengthToOptions(newStrength, &newOptions); |
|
86 NS_ENSURE_SUCCESS(res, res); |
|
87 |
|
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; |
|
92 |
|
93 mLastStrength = newStrength; |
|
94 return NS_OK; |
|
95 } |
|
96 |
|
97 NS_IMETHODIMP nsCollationMacUC::Initialize(nsILocale* locale) |
|
98 { |
|
99 NS_ENSURE_TRUE((!mInit), NS_ERROR_ALREADY_INITIALIZED); |
|
100 nsCOMPtr<nsILocale> appLocale; |
|
101 |
|
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 } |
|
110 |
|
111 rv = ConvertLocale(locale, &mLocale); |
|
112 NS_ENSURE_SUCCESS(rv, rv); |
|
113 |
|
114 mInit = true; |
|
115 return NS_OK; |
|
116 } |
|
117 |
|
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); |
|
124 |
|
125 nsresult res = EnsureCollator(strength); |
|
126 NS_ENSURE_SUCCESS(res, res); |
|
127 |
|
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; |
|
138 |
|
139 PR_FREEIF(mBuffer); |
|
140 mBuffer = newBuffer; |
|
141 mBufferLen = newBufferLen; |
|
142 } |
|
143 |
|
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); |
|
150 |
|
151 uint32_t keyLength = actual * sizeof(UCCollationValue); |
|
152 void *newKey = PR_Malloc(keyLength); |
|
153 if (!newKey) |
|
154 return NS_ERROR_OUT_OF_MEMORY; |
|
155 |
|
156 memcpy(newKey, mBuffer, keyLength); |
|
157 *key = (uint8_t *)newKey; |
|
158 *outLen = keyLength; |
|
159 |
|
160 return NS_OK; |
|
161 } |
|
162 |
|
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; |
|
169 |
|
170 nsresult res = EnsureCollator(strength); |
|
171 NS_ENSURE_SUCCESS(res, res); |
|
172 *result = 0; |
|
173 |
|
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); |
|
179 |
|
180 NS_ENSURE_TRUE((err == noErr), NS_ERROR_FAILURE); |
|
181 return NS_OK; |
|
182 } |
|
183 |
|
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; |
|
193 |
|
194 OSStatus err; |
|
195 err = ::UCCompareCollationKeys((const UCCollationValue*) key1, (ItemCount) len1, |
|
196 (const UCCollationValue*) key2, (ItemCount) len2, |
|
197 nullptr, (SInt32*) result); |
|
198 |
|
199 NS_ENSURE_TRUE((err == noErr), NS_ERROR_FAILURE); |
|
200 |
|
201 return NS_OK; |
|
202 } |