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