2001-10-16 16:30:44 +04:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
2012-05-21 15:12:37 +04:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
2001-10-16 16:30:44 +04:00
|
|
|
|
2017-03-23 07:42:49 +03:00
|
|
|
#include "nsCollation.h"
|
2017-08-24 17:13:42 +03:00
|
|
|
#include "mozilla/intl/LocaleService.h"
|
2013-09-27 20:45:04 +04:00
|
|
|
#include "nsString.h"
|
2001-10-16 16:30:44 +04:00
|
|
|
|
2017-03-23 07:42:49 +03:00
|
|
|
NS_IMPL_ISUPPORTS(nsCollation, nsICollation)
|
2001-10-16 16:30:44 +04:00
|
|
|
|
2017-03-23 07:42:49 +03:00
|
|
|
nsCollation::nsCollation()
|
2011-10-17 18:59:28 +04:00
|
|
|
: mInit(false),
|
|
|
|
mHasCollator(false),
|
2009-05-02 02:57:08 +04:00
|
|
|
mLastStrength(-1),
|
2014-10-08 18:43:47 +04:00
|
|
|
mCollatorICU(nullptr) {}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2017-03-23 07:42:49 +03:00
|
|
|
nsCollation::~nsCollation() {
|
2010-07-11 16:41:54 +04:00
|
|
|
#ifdef DEBUG
|
2014-10-08 18:43:47 +04:00
|
|
|
nsresult res =
|
2010-07-11 16:41:54 +04:00
|
|
|
#endif
|
2014-10-08 18:43:47 +04:00
|
|
|
CleanUpCollator();
|
|
|
|
NS_ASSERTION(NS_SUCCEEDED(res), "CleanUpCollator failed");
|
|
|
|
}
|
|
|
|
|
2017-03-23 07:42:49 +03:00
|
|
|
nsresult nsCollation::ConvertStrength(const int32_t aNSStrength,
|
|
|
|
UCollationStrength* aICUStrength,
|
|
|
|
UColAttributeValue* aCaseLevelOut) {
|
2014-10-08 18:43:47 +04:00
|
|
|
NS_ENSURE_ARG_POINTER(aICUStrength);
|
|
|
|
NS_ENSURE_TRUE((aNSStrength < 4), NS_ERROR_FAILURE);
|
|
|
|
|
|
|
|
UCollationStrength strength = UCOL_DEFAULT;
|
|
|
|
UColAttributeValue caseLevel = UCOL_OFF;
|
|
|
|
switch (aNSStrength) {
|
|
|
|
case kCollationCaseInSensitive:
|
|
|
|
strength = UCOL_PRIMARY;
|
|
|
|
break;
|
|
|
|
case kCollationCaseInsensitiveAscii:
|
|
|
|
strength = UCOL_SECONDARY;
|
|
|
|
break;
|
|
|
|
case kCollationAccentInsenstive:
|
|
|
|
caseLevel = UCOL_ON;
|
|
|
|
strength = UCOL_PRIMARY;
|
|
|
|
break;
|
|
|
|
case kCollationCaseSensitive:
|
|
|
|
strength = UCOL_TERTIARY;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
NS_WARNING("Bad aNSStrength passed to ConvertStrength.");
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
*aICUStrength = strength;
|
|
|
|
*aCaseLevelOut = caseLevel;
|
|
|
|
|
|
|
|
return NS_OK;
|
2001-10-16 16:30:44 +04:00
|
|
|
}
|
|
|
|
|
2017-03-23 07:42:49 +03:00
|
|
|
nsresult nsCollation::EnsureCollator(const int32_t newStrength) {
|
2001-10-16 16:30:44 +04:00
|
|
|
NS_ENSURE_TRUE(mInit, NS_ERROR_NOT_INITIALIZED);
|
|
|
|
if (mHasCollator && (mLastStrength == newStrength)) return NS_OK;
|
|
|
|
|
2014-10-08 18:43:47 +04:00
|
|
|
nsresult res;
|
|
|
|
res = CleanUpCollator();
|
|
|
|
NS_ENSURE_SUCCESS(res, res);
|
|
|
|
|
2015-12-16 11:27:44 +03:00
|
|
|
UErrorCode status;
|
|
|
|
status = U_ZERO_ERROR;
|
2017-02-07 23:52:03 +03:00
|
|
|
mCollatorICU = ucol_open(mLocale.get(), &status);
|
2015-12-16 11:27:44 +03:00
|
|
|
NS_ENSURE_TRUE(U_SUCCESS(status), NS_ERROR_FAILURE);
|
|
|
|
|
|
|
|
UCollationStrength strength;
|
|
|
|
UColAttributeValue caseLevel;
|
|
|
|
res = ConvertStrength(newStrength, &strength, &caseLevel);
|
|
|
|
NS_ENSURE_SUCCESS(res, res);
|
|
|
|
|
|
|
|
status = U_ZERO_ERROR;
|
|
|
|
ucol_setAttribute(mCollatorICU, UCOL_STRENGTH, strength, &status);
|
|
|
|
NS_ENSURE_TRUE(U_SUCCESS(status), NS_ERROR_FAILURE);
|
|
|
|
ucol_setAttribute(mCollatorICU, UCOL_CASE_LEVEL, caseLevel, &status);
|
|
|
|
NS_ENSURE_TRUE(U_SUCCESS(status), NS_ERROR_FAILURE);
|
|
|
|
ucol_setAttribute(mCollatorICU, UCOL_ALTERNATE_HANDLING, UCOL_DEFAULT,
|
|
|
|
&status);
|
|
|
|
NS_ENSURE_TRUE(U_SUCCESS(status), NS_ERROR_FAILURE);
|
|
|
|
ucol_setAttribute(mCollatorICU, UCOL_NUMERIC_COLLATION, UCOL_OFF, &status);
|
|
|
|
NS_ENSURE_TRUE(U_SUCCESS(status), NS_ERROR_FAILURE);
|
|
|
|
ucol_setAttribute(mCollatorICU, UCOL_NORMALIZATION_MODE, UCOL_ON, &status);
|
|
|
|
NS_ENSURE_TRUE(U_SUCCESS(status), NS_ERROR_FAILURE);
|
|
|
|
ucol_setAttribute(mCollatorICU, UCOL_CASE_FIRST, UCOL_DEFAULT, &status);
|
|
|
|
NS_ENSURE_TRUE(U_SUCCESS(status), NS_ERROR_FAILURE);
|
2001-10-16 16:30:44 +04:00
|
|
|
|
2011-10-17 18:59:28 +04:00
|
|
|
mHasCollator = true;
|
2001-10-16 16:30:44 +04:00
|
|
|
|
|
|
|
mLastStrength = newStrength;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2017-03-23 07:42:49 +03:00
|
|
|
nsresult nsCollation::CleanUpCollator(void) {
|
2014-10-08 18:43:47 +04:00
|
|
|
if (mHasCollator) {
|
2015-12-16 11:27:44 +03:00
|
|
|
ucol_close(mCollatorICU);
|
|
|
|
mHasCollator = false;
|
2014-10-08 18:43:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2017-03-23 07:42:49 +03:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsCollation::Initialize(const nsACString& locale) {
|
2001-10-16 16:30:44 +04:00
|
|
|
NS_ENSURE_TRUE((!mInit), NS_ERROR_ALREADY_INITIALIZED);
|
|
|
|
|
2017-08-24 17:13:42 +03:00
|
|
|
// Check whether locale parameter is valid. If no, use application locale
|
|
|
|
UErrorCode status = U_ZERO_ERROR;
|
|
|
|
UCollator* collator = ucol_open(PromiseFlatCString(locale).get(), &status);
|
|
|
|
if (U_SUCCESS(status)) {
|
|
|
|
mLocale = locale;
|
|
|
|
} else {
|
|
|
|
status = U_ZERO_ERROR;
|
2020-01-17 22:29:09 +03:00
|
|
|
mozilla::LocaleService::GetInstance()->GetAppLocaleAsBCP47(mLocale);
|
2017-08-24 17:13:42 +03:00
|
|
|
collator = ucol_open(mLocale.get(), &status);
|
|
|
|
if (NS_WARN_IF(U_FAILURE(status))) {
|
|
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ucol_close(collator);
|
2001-10-16 16:30:44 +04:00
|
|
|
|
2011-10-17 18:59:28 +04:00
|
|
|
mInit = true;
|
2001-10-16 16:30:44 +04:00
|
|
|
return NS_OK;
|
2009-05-02 02:57:08 +04:00
|
|
|
}
|
|
|
|
|
2017-03-23 07:42:49 +03:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsCollation::AllocateRawSortKey(int32_t strength, const nsAString& stringIn,
|
2019-11-11 21:03:42 +03:00
|
|
|
nsTArray<uint8_t>& key) {
|
2001-10-16 16:30:44 +04:00
|
|
|
NS_ENSURE_TRUE(mInit, NS_ERROR_NOT_INITIALIZED);
|
|
|
|
|
|
|
|
nsresult res = EnsureCollator(strength);
|
|
|
|
NS_ENSURE_SUCCESS(res, res);
|
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t stringInLen = stringIn.Length();
|
2014-10-08 18:43:47 +04:00
|
|
|
|
2016-05-02 08:30:40 +03:00
|
|
|
const UChar* str = (const UChar*)stringIn.BeginReading();
|
2014-10-08 18:43:47 +04:00
|
|
|
|
2015-12-16 11:27:44 +03:00
|
|
|
int32_t keyLength =
|
|
|
|
ucol_getSortKey(mCollatorICU, str, stringInLen, nullptr, 0);
|
|
|
|
NS_ENSURE_TRUE((stringInLen == 0 || keyLength > 0), NS_ERROR_FAILURE);
|
2014-10-08 18:43:47 +04:00
|
|
|
|
2019-11-11 21:03:42 +03:00
|
|
|
key.SetLength(keyLength + 1);
|
2003-07-25 00:31:35 +04:00
|
|
|
|
2019-11-11 21:03:42 +03:00
|
|
|
keyLength = ucol_getSortKey(mCollatorICU, str, stringInLen, key.Elements(),
|
|
|
|
keyLength + 1);
|
2015-12-16 11:27:44 +03:00
|
|
|
NS_ENSURE_TRUE((stringInLen == 0 || keyLength > 0), NS_ERROR_FAILURE);
|
|
|
|
|
2019-11-11 21:03:42 +03:00
|
|
|
key.SetLength(keyLength);
|
2001-10-16 16:30:44 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2017-03-23 07:42:49 +03:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsCollation::CompareString(int32_t strength, const nsAString& string1,
|
|
|
|
const nsAString& string2, int32_t* result) {
|
2001-10-16 16:30:44 +04:00
|
|
|
NS_ENSURE_TRUE(mInit, NS_ERROR_NOT_INITIALIZED);
|
|
|
|
NS_ENSURE_ARG_POINTER(result);
|
|
|
|
*result = 0;
|
|
|
|
|
2015-12-16 11:27:44 +03:00
|
|
|
nsresult rv = EnsureCollator(strength);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2014-10-08 18:43:47 +04:00
|
|
|
|
2015-12-16 11:27:44 +03:00
|
|
|
UCollationResult uresult;
|
2016-05-02 08:30:40 +03:00
|
|
|
uresult = ucol_strcoll(mCollatorICU, (const UChar*)string1.BeginReading(),
|
|
|
|
string1.Length(), (const UChar*)string2.BeginReading(),
|
|
|
|
string2.Length());
|
2015-12-16 11:27:44 +03:00
|
|
|
int32_t res;
|
|
|
|
switch (uresult) {
|
|
|
|
case UCOL_LESS:
|
|
|
|
res = -1;
|
|
|
|
break;
|
|
|
|
case UCOL_EQUAL:
|
|
|
|
res = 0;
|
|
|
|
break;
|
|
|
|
case UCOL_GREATER:
|
|
|
|
res = 1;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
MOZ_CRASH("ucol_strcoll returned bad UCollationResult");
|
2014-10-08 18:43:47 +04:00
|
|
|
}
|
2015-12-16 11:27:44 +03:00
|
|
|
*result = res;
|
2001-10-16 16:30:44 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2017-03-23 07:42:49 +03:00
|
|
|
NS_IMETHODIMP
|
2019-11-11 21:03:42 +03:00
|
|
|
nsCollation::CompareRawSortKey(const nsTArray<uint8_t>& key1,
|
|
|
|
const nsTArray<uint8_t>& key2, int32_t* result) {
|
2001-10-16 16:30:44 +04:00
|
|
|
NS_ENSURE_TRUE(mInit, NS_ERROR_NOT_INITIALIZED);
|
|
|
|
NS_ENSURE_ARG_POINTER(result);
|
|
|
|
*result = 0;
|
2009-05-02 02:57:08 +04:00
|
|
|
|
2019-11-11 21:03:42 +03:00
|
|
|
size_t minLength = std::min(key1.Length(), key2.Length());
|
|
|
|
int32_t tmpResult = strncmp((const char*)key1.Elements(),
|
|
|
|
(const char*)key2.Elements(), minLength);
|
2015-12-16 11:27:44 +03:00
|
|
|
int32_t res;
|
|
|
|
if (tmpResult < 0) {
|
2014-10-08 18:43:47 +04:00
|
|
|
res = -1;
|
2015-12-16 11:27:44 +03:00
|
|
|
} else if (tmpResult > 0) {
|
2014-10-08 18:43:47 +04:00
|
|
|
res = 1;
|
2019-11-11 21:03:42 +03:00
|
|
|
} else if (key1.Length() > minLength) {
|
|
|
|
// First string contains second one, so comes later, hence return > 0.
|
|
|
|
res = 1;
|
|
|
|
} else if (key2.Length() > minLength) {
|
|
|
|
// First string is a substring of second one, so comes earlier,
|
|
|
|
// hence return < 0.
|
|
|
|
res = -1;
|
2015-12-16 11:27:44 +03:00
|
|
|
} else {
|
2014-10-08 18:43:47 +04:00
|
|
|
res = 0;
|
|
|
|
}
|
2015-12-16 11:27:44 +03:00
|
|
|
*result = res;
|
2001-10-16 16:30:44 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|