summaryrefslogtreecommitdiff
path: root/intl/locale/mac/nsCollationMacUC.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'intl/locale/mac/nsCollationMacUC.cpp')
-rw-r--r--intl/locale/mac/nsCollationMacUC.cpp253
1 files changed, 253 insertions, 0 deletions
diff --git a/intl/locale/mac/nsCollationMacUC.cpp b/intl/locale/mac/nsCollationMacUC.cpp
new file mode 100644
index 0000000000..d230f4d771
--- /dev/null
+++ b/intl/locale/mac/nsCollationMacUC.cpp
@@ -0,0 +1,253 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+#include "nsCollationMacUC.h"
+#include "nsILocaleService.h"
+#include "nsIPrefBranch.h"
+#include "nsIPrefService.h"
+#include "nsIServiceManager.h"
+#include "prmem.h"
+#include "nsString.h"
+
+NS_IMPL_ISUPPORTS(nsCollationMacUC, nsICollation)
+
+nsCollationMacUC::nsCollationMacUC()
+ : mInit(false)
+ , mHasCollator(false)
+ , mLocaleICU(nullptr)
+ , mLastStrength(-1)
+ , mCollatorICU(nullptr)
+{ }
+
+nsCollationMacUC::~nsCollationMacUC()
+{
+#ifdef DEBUG
+ nsresult res =
+#endif
+ CleanUpCollator();
+ NS_ASSERTION(NS_SUCCEEDED(res), "CleanUpCollator failed");
+ if (mLocaleICU) {
+ free(mLocaleICU);
+ mLocaleICU = nullptr;
+ }
+}
+
+nsresult nsCollationMacUC::ConvertStrength(const int32_t aNSStrength,
+ UCollationStrength* aICUStrength,
+ UColAttributeValue* aCaseLevelOut)
+{
+ 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;
+}
+
+nsresult nsCollationMacUC::ConvertLocaleICU(nsILocale* aNSLocale, char** aICULocale)
+{
+ NS_ENSURE_ARG_POINTER(aNSLocale);
+ NS_ENSURE_ARG_POINTER(aICULocale);
+
+ nsAutoString localeString;
+ nsresult res = aNSLocale->GetCategory(NS_LITERAL_STRING("NSILOCALE_COLLATE"), localeString);
+ NS_ENSURE_TRUE(NS_SUCCEEDED(res) && !localeString.IsEmpty(),
+ NS_ERROR_FAILURE);
+ NS_LossyConvertUTF16toASCII tmp(localeString);
+ tmp.ReplaceChar('-', '_');
+ char* locale = (char*)malloc(tmp.Length() + 1);
+ if (!locale) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+ strcpy(locale, tmp.get());
+
+ *aICULocale = locale;
+
+ return NS_OK;
+}
+
+nsresult nsCollationMacUC::EnsureCollator(const int32_t newStrength)
+{
+ NS_ENSURE_TRUE(mInit, NS_ERROR_NOT_INITIALIZED);
+ if (mHasCollator && (mLastStrength == newStrength))
+ return NS_OK;
+
+ nsresult res;
+ res = CleanUpCollator();
+ NS_ENSURE_SUCCESS(res, res);
+
+ NS_ENSURE_TRUE(mLocaleICU, NS_ERROR_NOT_INITIALIZED);
+
+ UErrorCode status;
+ status = U_ZERO_ERROR;
+ mCollatorICU = ucol_open(mLocaleICU, &status);
+ 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);
+
+ mHasCollator = true;
+
+ mLastStrength = newStrength;
+ return NS_OK;
+}
+
+nsresult nsCollationMacUC::CleanUpCollator(void)
+{
+ if (mHasCollator) {
+ ucol_close(mCollatorICU);
+ mHasCollator = false;
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsCollationMacUC::Initialize(nsILocale* locale)
+{
+ NS_ENSURE_TRUE((!mInit), NS_ERROR_ALREADY_INITIALIZED);
+ nsCOMPtr<nsILocale> appLocale;
+
+ nsresult rv;
+ if (!locale) {
+ nsCOMPtr<nsILocaleService> localeService = do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+ rv = localeService->GetApplicationLocale(getter_AddRefs(appLocale));
+ NS_ENSURE_SUCCESS(rv, rv);
+ locale = appLocale;
+ }
+
+ rv = ConvertLocaleICU(locale, &mLocaleICU);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ mInit = true;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsCollationMacUC::AllocateRawSortKey(int32_t strength, const nsAString& stringIn,
+ uint8_t** key, uint32_t* outLen)
+{
+ NS_ENSURE_TRUE(mInit, NS_ERROR_NOT_INITIALIZED);
+ NS_ENSURE_ARG_POINTER(key);
+ NS_ENSURE_ARG_POINTER(outLen);
+
+ nsresult res = EnsureCollator(strength);
+ NS_ENSURE_SUCCESS(res, res);
+
+ uint32_t stringInLen = stringIn.Length();
+
+ const UChar* str = (const UChar*)stringIn.BeginReading();
+
+ int32_t keyLength = ucol_getSortKey(mCollatorICU, str, stringInLen, nullptr, 0);
+ NS_ENSURE_TRUE((stringInLen == 0 || keyLength > 0), NS_ERROR_FAILURE);
+
+ // Since key is freed elsewhere with PR_Free, allocate with PR_Malloc.
+ uint8_t* newKey = (uint8_t*)PR_Malloc(keyLength + 1);
+ if (!newKey) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ keyLength = ucol_getSortKey(mCollatorICU, str, stringInLen, newKey, keyLength + 1);
+ NS_ENSURE_TRUE((stringInLen == 0 || keyLength > 0), NS_ERROR_FAILURE);
+
+ *key = newKey;
+ *outLen = keyLength;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsCollationMacUC::CompareString(int32_t strength, const nsAString& string1,
+ const nsAString& string2, int32_t* result)
+{
+ NS_ENSURE_TRUE(mInit, NS_ERROR_NOT_INITIALIZED);
+ NS_ENSURE_ARG_POINTER(result);
+ *result = 0;
+
+ nsresult rv = EnsureCollator(strength);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ UCollationResult uresult;
+ uresult = ucol_strcoll(mCollatorICU,
+ (const UChar*)string1.BeginReading(),
+ string1.Length(),
+ (const UChar*)string2.BeginReading(),
+ string2.Length());
+ 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");
+ }
+ *result = res;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsCollationMacUC::CompareRawSortKey(const uint8_t* key1, uint32_t len1,
+ const uint8_t* key2, uint32_t len2,
+ int32_t* result)
+{
+ NS_ENSURE_TRUE(mInit, NS_ERROR_NOT_INITIALIZED);
+ NS_ENSURE_ARG_POINTER(key1);
+ NS_ENSURE_ARG_POINTER(key2);
+ NS_ENSURE_ARG_POINTER(result);
+ *result = 0;
+
+ int32_t tmpResult = strcmp((const char*)key1, (const char*)key2);
+ int32_t res;
+ if (tmpResult < 0) {
+ res = -1;
+ } else if (tmpResult > 0) {
+ res = 1;
+ } else {
+ res = 0;
+ }
+ *result = res;
+ return NS_OK;
+}