intl/locale/src/nsCollation.cpp
author Ms2ger <ms2ger@gmail.com>
Thu, 09 Aug 2012 09:09:40 +0200
changeset 101928 4587cc2d01545d18cea6d650e725af5751f549ee
parent 100870 b5c4b792f3f2a047e3517472d72842a76afb77cd
child 103019 a16372ce30b5f6b747246b01fcd215a4bf3b6342
permissions -rw-r--r--
Bug 780387 - Part b: Stop using PRIntn; r=bsmedberg

/* -*- 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 "nsIPlatformCharset.h"
#include "nsIServiceManager.h"
#include "nsIComponentManager.h"
#include "nsCollation.h"
#include "nsCollationCID.h"
#include "nsUnicharUtils.h"
#include "prmem.h"
#include "nsReadableUtils.h"

////////////////////////////////////////////////////////////////////////////////

NS_DEFINE_CID(kCollationCID, NS_COLLATION_CID);

NS_IMPL_ISUPPORTS1(nsCollationFactory, nsICollationFactory)

nsresult nsCollationFactory::CreateCollation(nsILocale* locale, nsICollation** instancePtr)
{
  // Create a collation interface instance.
  //
  nsICollation *inst;
  nsresult res;
  
  res = CallCreateInstance(kCollationCID, &inst);
  if (NS_FAILED(res)) {
    return res;
  }

  inst->Initialize(locale);
  *instancePtr = inst;

  return res;
}

////////////////////////////////////////////////////////////////////////////////

nsCollation::nsCollation()
{
  MOZ_COUNT_CTOR(nsCollation);
}

nsCollation::~nsCollation()
{
  MOZ_COUNT_DTOR(nsCollation);
}

nsresult nsCollation::NormalizeString(const nsAString& stringIn, nsAString& stringOut)
{
  PRInt32 aLength = stringIn.Length();

  if (aLength <= 64) {
    PRUnichar conversionBuffer[64];
    ToLowerCase(PromiseFlatString(stringIn).get(), conversionBuffer, aLength);
    stringOut.Assign(conversionBuffer, aLength);
  }
  else {
    PRUnichar* conversionBuffer;
    conversionBuffer = new PRUnichar[aLength];
    if (!conversionBuffer) {
      return NS_ERROR_OUT_OF_MEMORY;
    }
    ToLowerCase(PromiseFlatString(stringIn).get(), conversionBuffer, aLength);
    stringOut.Assign(conversionBuffer, aLength);
    delete [] conversionBuffer;
  }
  return NS_OK;
}

nsresult nsCollation::SetCharset(const char* aCharset)
{
  NS_ENSURE_ARG_POINTER(aCharset);

  nsresult rv;
  nsCOMPtr <nsICharsetConverterManager> charsetConverterManager = do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
  if (NS_SUCCEEDED(rv)) {
    rv = charsetConverterManager->GetUnicodeEncoder(aCharset,
                                                    getter_AddRefs(mEncoder));
  }
  return rv;
}

nsresult nsCollation::UnicodeToChar(const nsAString& aSrc, char** dst)
{
  NS_ENSURE_ARG_POINTER(dst);

  nsresult res = NS_OK;
  if (!mEncoder)
    res = SetCharset("ISO-8859-1");

  if (NS_SUCCEEDED(res)) {
    const nsPromiseFlatString& src = PromiseFlatString(aSrc);
    const PRUnichar *unichars = src.get();
    PRInt32 unicharLength = src.Length();
    PRInt32 dstLength;
    res = mEncoder->GetMaxLength(unichars, unicharLength, &dstLength);
    if (NS_SUCCEEDED(res)) {
      PRInt32 bufLength = dstLength + 1 + 32; // extra 32 bytes for Finish() call
      *dst = (char *) PR_Malloc(bufLength);
      if (*dst) {
        **dst = '\0';
        res = mEncoder->Convert(unichars, &unicharLength, *dst, &dstLength);

        if (NS_SUCCEEDED(res) || (NS_ERROR_UENC_NOMAPPING == res)) {
          // Finishes the conversion. The converter has the possibility to write some 
          // extra data and flush its final state.
          PRInt32 finishLength = bufLength - dstLength; // remaining unused buffer length
          if (finishLength > 0) {
            res = mEncoder->Finish((*dst + dstLength), &finishLength);
            if (NS_SUCCEEDED(res)) {
              (*dst)[dstLength + finishLength] = '\0';
            }
          }
        }
        if (NS_FAILED(res)) {
          PR_Free(*dst);
          *dst = nullptr;
        }
      }
      else {
        res = NS_ERROR_OUT_OF_MEMORY;
      }
    }
  }

  return res;
}