Coverage Report

Created: 2018-09-25 14:53

/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
}