michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "nsCollation.h" michael@0: #include "nsCollationCID.h" michael@0: #include "nsUnicharUtils.h" michael@0: #include "prmem.h" michael@0: #include "nsIUnicodeEncoder.h" michael@0: #include "nsICharsetConverterManager.h" michael@0: #include "nsServiceManagerUtils.h" michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: NS_DEFINE_CID(kCollationCID, NS_COLLATION_CID); michael@0: michael@0: NS_IMPL_ISUPPORTS(nsCollationFactory, nsICollationFactory) michael@0: michael@0: nsresult nsCollationFactory::CreateCollation(nsILocale* locale, nsICollation** instancePtr) michael@0: { michael@0: // Create a collation interface instance. michael@0: // michael@0: nsICollation *inst; michael@0: nsresult res; michael@0: michael@0: res = CallCreateInstance(kCollationCID, &inst); michael@0: if (NS_FAILED(res)) { michael@0: return res; michael@0: } michael@0: michael@0: inst->Initialize(locale); michael@0: *instancePtr = inst; michael@0: michael@0: return res; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: nsCollation::nsCollation() michael@0: { michael@0: MOZ_COUNT_CTOR(nsCollation); michael@0: } michael@0: michael@0: nsCollation::~nsCollation() michael@0: { michael@0: MOZ_COUNT_DTOR(nsCollation); michael@0: } michael@0: michael@0: nsresult nsCollation::NormalizeString(const nsAString& stringIn, nsAString& stringOut) michael@0: { michael@0: int32_t aLength = stringIn.Length(); michael@0: michael@0: if (aLength <= 64) { michael@0: char16_t conversionBuffer[64]; michael@0: ToLowerCase(PromiseFlatString(stringIn).get(), conversionBuffer, aLength); michael@0: stringOut.Assign(conversionBuffer, aLength); michael@0: } michael@0: else { michael@0: char16_t* conversionBuffer; michael@0: conversionBuffer = new char16_t[aLength]; michael@0: if (!conversionBuffer) { michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: ToLowerCase(PromiseFlatString(stringIn).get(), conversionBuffer, aLength); michael@0: stringOut.Assign(conversionBuffer, aLength); michael@0: delete [] conversionBuffer; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult nsCollation::SetCharset(const char* aCharset) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aCharset); michael@0: michael@0: nsresult rv; michael@0: nsCOMPtr charsetConverterManager = do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: rv = charsetConverterManager->GetUnicodeEncoder(aCharset, michael@0: getter_AddRefs(mEncoder)); michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: nsresult nsCollation::UnicodeToChar(const nsAString& aSrc, char** dst) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(dst); michael@0: michael@0: nsresult res = NS_OK; michael@0: if (!mEncoder) michael@0: res = SetCharset("ISO-8859-1"); michael@0: michael@0: if (NS_SUCCEEDED(res)) { michael@0: const nsPromiseFlatString& src = PromiseFlatString(aSrc); michael@0: const char16_t *unichars = src.get(); michael@0: int32_t unicharLength = src.Length(); michael@0: int32_t dstLength; michael@0: res = mEncoder->GetMaxLength(unichars, unicharLength, &dstLength); michael@0: if (NS_SUCCEEDED(res)) { michael@0: int32_t bufLength = dstLength + 1 + 32; // extra 32 bytes for Finish() call michael@0: *dst = (char *) PR_Malloc(bufLength); michael@0: if (*dst) { michael@0: **dst = '\0'; michael@0: res = mEncoder->Convert(unichars, &unicharLength, *dst, &dstLength); michael@0: michael@0: if (NS_SUCCEEDED(res) || (NS_ERROR_UENC_NOMAPPING == res)) { michael@0: // Finishes the conversion. The converter has the possibility to write some michael@0: // extra data and flush its final state. michael@0: int32_t finishLength = bufLength - dstLength; // remaining unused buffer length michael@0: if (finishLength > 0) { michael@0: res = mEncoder->Finish((*dst + dstLength), &finishLength); michael@0: if (NS_SUCCEEDED(res)) { michael@0: (*dst)[dstLength + finishLength] = '\0'; michael@0: } michael@0: } michael@0: } michael@0: if (NS_FAILED(res)) { michael@0: PR_Free(*dst); michael@0: *dst = nullptr; michael@0: } michael@0: } michael@0: else { michael@0: res = NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: } michael@0: } michael@0: michael@0: return res; michael@0: } michael@0: michael@0: michael@0: