/src/mozilla-central/intl/locale/nsCollation.cpp
Line | Count | Source (jump to first uncovered line) |
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 "nsCollation.h" |
7 | | #include "mozilla/intl/LocaleService.h" |
8 | | #include "nsIServiceManager.h" |
9 | | #include "nsString.h" |
10 | | |
11 | | NS_IMPL_ISUPPORTS(nsCollation, nsICollation) |
12 | | |
13 | | nsCollation::nsCollation() |
14 | | : mInit(false) |
15 | | , mHasCollator(false) |
16 | | , mLastStrength(-1) |
17 | | , mCollatorICU(nullptr) |
18 | 0 | { } |
19 | | |
20 | | nsCollation::~nsCollation() |
21 | 0 | { |
22 | | #ifdef DEBUG |
23 | | nsresult res = |
24 | | #endif |
25 | | CleanUpCollator(); |
26 | 0 | NS_ASSERTION(NS_SUCCEEDED(res), "CleanUpCollator failed"); |
27 | 0 | } |
28 | | |
29 | | nsresult |
30 | | nsCollation::ConvertStrength(const int32_t aNSStrength, |
31 | | UCollationStrength* aICUStrength, |
32 | | UColAttributeValue* aCaseLevelOut) |
33 | 0 | { |
34 | 0 | NS_ENSURE_ARG_POINTER(aICUStrength); |
35 | 0 | NS_ENSURE_TRUE((aNSStrength < 4), NS_ERROR_FAILURE); |
36 | 0 |
|
37 | 0 | UCollationStrength strength = UCOL_DEFAULT; |
38 | 0 | UColAttributeValue caseLevel = UCOL_OFF; |
39 | 0 | switch (aNSStrength) { |
40 | 0 | case kCollationCaseInSensitive: |
41 | 0 | strength = UCOL_PRIMARY; |
42 | 0 | break; |
43 | 0 | case kCollationCaseInsensitiveAscii: |
44 | 0 | strength = UCOL_SECONDARY; |
45 | 0 | break; |
46 | 0 | case kCollationAccentInsenstive: |
47 | 0 | caseLevel = UCOL_ON; |
48 | 0 | strength = UCOL_PRIMARY; |
49 | 0 | break; |
50 | 0 | case kCollationCaseSensitive: |
51 | 0 | strength = UCOL_TERTIARY; |
52 | 0 | break; |
53 | 0 | default: |
54 | 0 | NS_WARNING("Bad aNSStrength passed to ConvertStrength."); |
55 | 0 | return NS_ERROR_FAILURE; |
56 | 0 | } |
57 | 0 |
|
58 | 0 | *aICUStrength = strength; |
59 | 0 | *aCaseLevelOut = caseLevel; |
60 | 0 |
|
61 | 0 | return NS_OK; |
62 | 0 | } |
63 | | |
64 | | nsresult |
65 | | nsCollation::EnsureCollator(const int32_t newStrength) |
66 | 0 | { |
67 | 0 | NS_ENSURE_TRUE(mInit, NS_ERROR_NOT_INITIALIZED); |
68 | 0 | if (mHasCollator && (mLastStrength == newStrength)) |
69 | 0 | return NS_OK; |
70 | 0 | |
71 | 0 | nsresult res; |
72 | 0 | res = CleanUpCollator(); |
73 | 0 | NS_ENSURE_SUCCESS(res, res); |
74 | 0 |
|
75 | 0 | UErrorCode status; |
76 | 0 | status = U_ZERO_ERROR; |
77 | 0 | mCollatorICU = ucol_open(mLocale.get(), &status); |
78 | 0 | NS_ENSURE_TRUE(U_SUCCESS(status), NS_ERROR_FAILURE); |
79 | 0 |
|
80 | 0 | UCollationStrength strength; |
81 | 0 | UColAttributeValue caseLevel; |
82 | 0 | res = ConvertStrength(newStrength, &strength, &caseLevel); |
83 | 0 | NS_ENSURE_SUCCESS(res, res); |
84 | 0 |
|
85 | 0 | status = U_ZERO_ERROR; |
86 | 0 | ucol_setAttribute(mCollatorICU, UCOL_STRENGTH, strength, &status); |
87 | 0 | NS_ENSURE_TRUE(U_SUCCESS(status), NS_ERROR_FAILURE); |
88 | 0 | ucol_setAttribute(mCollatorICU, UCOL_CASE_LEVEL, caseLevel, &status); |
89 | 0 | NS_ENSURE_TRUE(U_SUCCESS(status), NS_ERROR_FAILURE); |
90 | 0 | ucol_setAttribute(mCollatorICU, UCOL_ALTERNATE_HANDLING, UCOL_DEFAULT, &status); |
91 | 0 | NS_ENSURE_TRUE(U_SUCCESS(status), NS_ERROR_FAILURE); |
92 | 0 | ucol_setAttribute(mCollatorICU, UCOL_NUMERIC_COLLATION, UCOL_OFF, &status); |
93 | 0 | NS_ENSURE_TRUE(U_SUCCESS(status), NS_ERROR_FAILURE); |
94 | 0 | ucol_setAttribute(mCollatorICU, UCOL_NORMALIZATION_MODE, UCOL_ON, &status); |
95 | 0 | NS_ENSURE_TRUE(U_SUCCESS(status), NS_ERROR_FAILURE); |
96 | 0 | ucol_setAttribute(mCollatorICU, UCOL_CASE_FIRST, UCOL_DEFAULT, &status); |
97 | 0 | NS_ENSURE_TRUE(U_SUCCESS(status), NS_ERROR_FAILURE); |
98 | 0 |
|
99 | 0 | mHasCollator = true; |
100 | 0 |
|
101 | 0 | mLastStrength = newStrength; |
102 | 0 | return NS_OK; |
103 | 0 | } |
104 | | |
105 | | nsresult |
106 | | nsCollation::CleanUpCollator(void) |
107 | 0 | { |
108 | 0 | if (mHasCollator) { |
109 | 0 | ucol_close(mCollatorICU); |
110 | 0 | mHasCollator = false; |
111 | 0 | } |
112 | 0 |
|
113 | 0 | return NS_OK; |
114 | 0 | } |
115 | | |
116 | | NS_IMETHODIMP |
117 | | nsCollation::Initialize(const nsACString& locale) |
118 | 0 | { |
119 | 0 | NS_ENSURE_TRUE((!mInit), NS_ERROR_ALREADY_INITIALIZED); |
120 | 0 |
|
121 | 0 | // Check whether locale parameter is valid. If no, use application locale |
122 | 0 | UErrorCode status = U_ZERO_ERROR; |
123 | 0 | UCollator* collator = ucol_open(PromiseFlatCString(locale).get(), &status); |
124 | 0 | if (U_SUCCESS(status)) { |
125 | 0 | mLocale = locale; |
126 | 0 | } else { |
127 | 0 | status = U_ZERO_ERROR; |
128 | 0 | mozilla::LocaleService::GetInstance()->GetAppLocaleAsLangTag(mLocale); |
129 | 0 | collator = ucol_open(mLocale.get(), &status); |
130 | 0 | if (NS_WARN_IF(U_FAILURE(status))) { |
131 | 0 | return NS_ERROR_UNEXPECTED; |
132 | 0 | } |
133 | 0 | } |
134 | 0 | ucol_close(collator); |
135 | 0 |
|
136 | 0 | mInit = true; |
137 | 0 | return NS_OK; |
138 | 0 | } |
139 | | |
140 | | NS_IMETHODIMP |
141 | | nsCollation::AllocateRawSortKey(int32_t strength, const nsAString& stringIn, |
142 | | uint8_t** key, uint32_t* outLen) |
143 | 0 | { |
144 | 0 | NS_ENSURE_TRUE(mInit, NS_ERROR_NOT_INITIALIZED); |
145 | 0 | NS_ENSURE_ARG_POINTER(key); |
146 | 0 | NS_ENSURE_ARG_POINTER(outLen); |
147 | 0 |
|
148 | 0 | nsresult res = EnsureCollator(strength); |
149 | 0 | NS_ENSURE_SUCCESS(res, res); |
150 | 0 |
|
151 | 0 | uint32_t stringInLen = stringIn.Length(); |
152 | 0 |
|
153 | 0 | const UChar* str = (const UChar*)stringIn.BeginReading(); |
154 | 0 |
|
155 | 0 | int32_t keyLength = ucol_getSortKey(mCollatorICU, str, stringInLen, nullptr, 0); |
156 | 0 | NS_ENSURE_TRUE((stringInLen == 0 || keyLength > 0), NS_ERROR_FAILURE); |
157 | 0 |
|
158 | 0 | // Since key is freed elsewhere with free, allocate with malloc. |
159 | 0 | uint8_t* newKey = (uint8_t*)malloc(keyLength + 1); |
160 | 0 | if (!newKey) { |
161 | 0 | return NS_ERROR_OUT_OF_MEMORY; |
162 | 0 | } |
163 | 0 | |
164 | 0 | keyLength = ucol_getSortKey(mCollatorICU, str, stringInLen, newKey, keyLength + 1); |
165 | 0 | NS_ENSURE_TRUE((stringInLen == 0 || keyLength > 0), NS_ERROR_FAILURE); |
166 | 0 |
|
167 | 0 | *key = newKey; |
168 | 0 | *outLen = keyLength; |
169 | 0 |
|
170 | 0 | return NS_OK; |
171 | 0 | } |
172 | | |
173 | | NS_IMETHODIMP |
174 | | nsCollation::CompareString(int32_t strength, const nsAString& string1, |
175 | | const nsAString& string2, int32_t* result) |
176 | 0 | { |
177 | 0 | NS_ENSURE_TRUE(mInit, NS_ERROR_NOT_INITIALIZED); |
178 | 0 | NS_ENSURE_ARG_POINTER(result); |
179 | 0 | *result = 0; |
180 | 0 |
|
181 | 0 | nsresult rv = EnsureCollator(strength); |
182 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
183 | 0 |
|
184 | 0 | UCollationResult uresult; |
185 | 0 | uresult = ucol_strcoll(mCollatorICU, |
186 | 0 | (const UChar*)string1.BeginReading(), |
187 | 0 | string1.Length(), |
188 | 0 | (const UChar*)string2.BeginReading(), |
189 | 0 | string2.Length()); |
190 | 0 | int32_t res; |
191 | 0 | switch (uresult) { |
192 | 0 | case UCOL_LESS: |
193 | 0 | res = -1; |
194 | 0 | break; |
195 | 0 | case UCOL_EQUAL: |
196 | 0 | res = 0; |
197 | 0 | break; |
198 | 0 | case UCOL_GREATER: |
199 | 0 | res = 1; |
200 | 0 | break; |
201 | 0 | default: |
202 | 0 | MOZ_CRASH("ucol_strcoll returned bad UCollationResult"); |
203 | 0 | } |
204 | 0 | *result = res; |
205 | 0 | return NS_OK; |
206 | 0 | } |
207 | | |
208 | | NS_IMETHODIMP |
209 | | nsCollation::CompareRawSortKey(const uint8_t* key1, uint32_t len1, |
210 | | const uint8_t* key2, uint32_t len2, |
211 | | int32_t* result) |
212 | 0 | { |
213 | 0 | NS_ENSURE_TRUE(mInit, NS_ERROR_NOT_INITIALIZED); |
214 | 0 | NS_ENSURE_ARG_POINTER(key1); |
215 | 0 | NS_ENSURE_ARG_POINTER(key2); |
216 | 0 | NS_ENSURE_ARG_POINTER(result); |
217 | 0 | *result = 0; |
218 | 0 |
|
219 | 0 | int32_t tmpResult = strcmp((const char*)key1, (const char*)key2); |
220 | 0 | int32_t res; |
221 | 0 | if (tmpResult < 0) { |
222 | 0 | res = -1; |
223 | 0 | } else if (tmpResult > 0) { |
224 | 0 | res = 1; |
225 | 0 | } else { |
226 | 0 | res = 0; |
227 | 0 | } |
228 | 0 | *result = res; |
229 | 0 | return NS_OK; |
230 | 0 | } |