Fix crash in unicode collation on Mac OS X, enable it, remove old collation impl. b=488320 r=smontagu sr=roc

This commit is contained in:
Josh Aas 2009-05-01 15:57:08 -07:00
parent 17062b2e6d
commit fb5d48f058
7 changed files with 42 additions and 434 deletions

View File

@ -146,11 +146,7 @@ static nsModuleComponentInfo components[] =
{ "Collation",
NS_COLLATION_CID,
NS_COLLATION_CONTRACTID,
#ifdef USE_UCCOLLATIONKEY
nsCollationMacUCConstructor },
#else
nsCollationMacConstructor },
#endif
{ "Date/Time formatter",
NS_DATETIMEFORMAT_CID,
NS_DATETIMEFORMAT_CONTRACTID,

View File

@ -54,16 +54,11 @@ REQUIRES = xpcom \
$(NULL)
CPPSRCS = \
nsCollationMac.cpp \
nsCollationMacUC.cpp \
nsDateTimeFormatMac.cpp \
nsMacLocale.cpp \
$(NULL)
ifdef USE_UCCOLLATIONKEY
CPPSRCS += nsCollationMacUC.cpp
endif
include $(topsrcdir)/config/rules.mk
INCLUDES += -I$(srcdir)/..

View File

@ -1,283 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Pierre Phaneuf <pp@ludusdesign.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include <Carbon/Carbon.h>
#include "nsCollationMac.h"
#include "prmem.h"
#include "prmon.h"
#include "nsIServiceManager.h"
#include "nsIComponentManager.h"
#include "nsILocaleService.h"
#include "nsLocaleCID.h"
#include "nsIPlatformCharset.h"
#include "nsIMacLocale.h"
#include "nsCOMPtr.h"
////////////////////////////////////////////////////////////////////////////////
/* Copy from FE_StrColl(), macfe/utility/locale.cp. */
static short mac_get_script_sort_id(const short scriptcode)
{
short itl2num;
ItlbRecord **ItlbRecordHandle;
/* get itlb of the system script */
ItlbRecordHandle = (ItlbRecord **) GetResource('itlb', scriptcode);
/* get itl2 number of current system script from itlb if possible
* otherwise, try script manager (Script manager won't update
* itl2 number when the change on the fly )
*/
if(ItlbRecordHandle != NULL)
{
if(*ItlbRecordHandle == NULL)
LoadResource((Handle)ItlbRecordHandle);
if(*ItlbRecordHandle != NULL)
itl2num = (*ItlbRecordHandle)->itlbSort;
else
itl2num = GetScriptVariable(scriptcode, smScriptSort);
} else { /* Use this as fallback */
itl2num = GetScriptVariable(scriptcode, smScriptSort);
}
return itl2num;
}
static Handle itl2Handle;
static int mac_sort_tbl_compare(const void* s1, const void* s2)
{
return CompareText((Ptr) s1, (Ptr) s2, 1, 1, itl2Handle);
}
static int mac_sort_tbl_init(const short scriptcode, unsigned char *mac_sort_tbl)
{
int i;
unsigned char sort_tbl[256];
for (i = 0; i < 256; i++)
sort_tbl[i] = (unsigned char) i;
/* Get itl2. */
itl2Handle = GetResource('itl2', mac_get_script_sort_id(scriptcode));
if (itl2Handle == NULL)
return -1;
/* qsort */
PRMonitor* mon = PR_NewMonitor();
PR_EnterMonitor(mon);
qsort((void *) sort_tbl, 256, 1, mac_sort_tbl_compare);
(void) PR_ExitMonitor(mon);
PR_DestroyMonitor(mon);
/* Put index to the table so we can map character code to sort oder. */
for (i = 0; i < 256; i++)
mac_sort_tbl[sort_tbl[i]] = (unsigned char) i;
return 0;
}
inline unsigned char mac_sort_tbl_search(const unsigned char ch, const unsigned char* mac_sort_tbl)
{
/* Map character code to sort order. */
return mac_sort_tbl[ch];
}
////////////////////////////////////////////////////////////////////////////////
NS_IMPL_ISUPPORTS1(nsCollationMac, nsICollation)
nsCollationMac::nsCollationMac()
{
mCollation = NULL;
}
nsCollationMac::~nsCollationMac()
{
if (mCollation != NULL)
delete mCollation;
}
nsresult nsCollationMac::Initialize(nsILocale* locale)
{
NS_ASSERTION(mCollation == NULL, "Should only be initialized once.");
nsresult res;
mCollation = new nsCollation;
if (mCollation == NULL) {
NS_ASSERTION(0, "mCollation creation failed");
return NS_ERROR_OUT_OF_MEMORY;
}
// locale -> script code + charset name
m_scriptcode = smRoman;
nsAutoString localeStr;
// get locale string, use app default if no locale specified
if (locale == nsnull) {
nsCOMPtr<nsILocaleService> localeService =
do_GetService(NS_LOCALESERVICE_CONTRACTID, &res);
if (NS_SUCCEEDED(res)) {
nsCOMPtr<nsILocale> appLocale;
res = localeService->GetApplicationLocale(getter_AddRefs(appLocale));
if (NS_SUCCEEDED(res)) {
res = appLocale->GetCategory(NS_LITERAL_STRING("NSILOCALE_COLLATE"),
localeStr);
}
}
}
else {
res = locale->GetCategory(NS_LITERAL_STRING("NSILOCALE_COLLATE"),
localeStr);
}
if (NS_SUCCEEDED(res)) {
short scriptcode, langcode, regioncode;
nsCOMPtr <nsIMacLocale> macLocale = do_GetService(NS_MACLOCALE_CONTRACTID, &res);
if (NS_SUCCEEDED(res)) {
if (NS_SUCCEEDED(res = macLocale->GetPlatformLocale(localeStr, &scriptcode, &langcode, &regioncode))) {
m_scriptcode = scriptcode;
}
}
nsCOMPtr <nsIPlatformCharset> platformCharset = do_GetService(NS_PLATFORMCHARSET_CONTRACTID, &res);
if (NS_SUCCEEDED(res)) {
nsCAutoString mappedCharset;
res = platformCharset->GetDefaultCharsetForLocale(localeStr, mappedCharset);
if (NS_SUCCEEDED(res)) {
res = mCollation->SetCharset(mappedCharset.get());
}
}
}
NS_ASSERTION(NS_SUCCEEDED(res), "initialization failed, use default values");
// Initialize a mapping table for the script code.
if (mac_sort_tbl_init(m_scriptcode, m_mac_sort_tbl) == -1) {
return NS_ERROR_FAILURE;
}
return NS_OK;
};
nsresult nsCollationMac::CompareString(PRInt32 strength,
const nsAString& string1, const nsAString& string2, PRInt32* result)
{
PRUint32 aLength1, aLength2;
PRUint8 *aKey1 = nsnull, *aKey2 = nsnull;
nsresult res;
res = AllocateRawSortKey(strength, string1, &aKey1, &aLength1);
if (NS_SUCCEEDED(res)) {
res = AllocateRawSortKey(strength, string2, &aKey2, &aLength2);
if (NS_SUCCEEDED(res))
*result = strcmp((const char *)aKey1, (const char *)aKey2); // compare keys
}
// delete keys
PR_FREEIF(aKey1);
PR_FREEIF(aKey2);
return res;
}
nsresult nsCollationMac::AllocateRawSortKey(PRInt32 strength,
const nsAString& stringIn, PRUint8** key, PRUint32* outLen)
{
nsresult res = NS_OK;
nsAutoString stringNormalized;
if (strength != kCollationCaseSensitive) {
res = mCollation->NormalizeString(stringIn, stringNormalized);
} else {
stringNormalized = stringIn;
}
// convert unicode to charset
char *str;
int str_len;
res = mCollation->UnicodeToChar(stringNormalized, &str);
if (NS_SUCCEEDED(res) && str != NULL) {
str_len = strlen(str);
*key = (PRUint8 *)str;
*outLen = str_len + 1;
// If no CJK then generate a collation key
if (smJapanese != m_scriptcode && smKorean != m_scriptcode &&
smTradChinese != m_scriptcode && smSimpChinese != m_scriptcode) {
while (*str) {
*str = (PRUint8) mac_sort_tbl_search((const unsigned char) *str, m_mac_sort_tbl);
++str;
}
}
// No CJK support, just copy the row string.
// ShiftJIS specific, shift hankaku kana in front of zenkaku.
else if (smJapanese == m_scriptcode) {
while (*str) {
if ((unsigned char) *str >= 0xA0 && (unsigned char) *str < 0xE0) {
*str -= (0xA0 - 0x81);
}
else if ((unsigned char) *str >= 0x81 && (unsigned char) *str < 0xA0) {
*str += (0xE0 - 0xA0);
}
// advance 2 bytes if the API says so and not passing the end of the string
if (CharacterByteType((Ptr) str, 0, m_scriptcode) == smFirstByte) {
++str;
if (!*str)
break;
}
++str;
}
}
}
return NS_OK;
}
nsresult nsCollationMac::CompareRawSortKey(const PRUint8* key1, PRUint32 len1,
const PRUint8* key2, PRUint32 len2,
PRInt32* result)
{
*result = PL_strcmp((const char *)key1, (const char *)key2);
return NS_OK;
}

View File

@ -1,69 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef nsCollationMac_h__
#define nsCollationMac_h__
#include "nsICollation.h"
#include "nsCollation.h" // static library
#include "plstr.h"
class nsCollationMac : public nsICollation {
protected:
nsCollation *mCollation; // XP collation class
short m_scriptcode; // Macintosh platform script code
unsigned char m_mac_sort_tbl[256]; // Mapping table from a character code to a collation key value.
public:
nsCollationMac();
~nsCollationMac();
// nsISupports interface
NS_DECL_ISUPPORTS
// nsICollation interface
NS_DECL_NSICOLLATION
};
#endif /* nsCollationMac_h__ */

View File

@ -36,30 +36,27 @@
*
* ***** END LICENSE BLOCK ***** */
#if TARGET_CARBON
#include "nsCollationMacUC.h"
#include "nsILocaleService.h"
#include "nsIServiceManager.h"
#include "prmem.h"
////////////////////////////////////////////////////////////////////////////////
NS_IMPL_ISUPPORTS1(nsCollationMacUC, nsICollation)
nsCollationMacUC::nsCollationMacUC()
: mInit(PR_FALSE)
, mHasCollator(PR_FALSE)
, mBuffer(nsnull)
, mLocale(NULL)
, mLastStrength(-1)
, mCollator(NULL)
, mBuffer(NULL)
, mBufferLen(1)
{
}
nsCollationMacUC::~nsCollationMacUC()
{
if (mHasCollator)
{
if (mHasCollator) {
OSStatus err = ::UCDisposeCollator(&mCollator);
mHasCollator = PR_FALSE;
NS_ASSERTION((err == noErr), "UCDisposeCollator failed");
@ -67,9 +64,8 @@ nsCollationMacUC::~nsCollationMacUC()
PR_FREEIF(mBuffer);
}
nsresult nsCollationMacUC::StrengthToOptions(
const PRInt32 aStrength,
UCCollateOptions* aOptions)
nsresult nsCollationMacUC::StrengthToOptions(const PRInt32 aStrength,
UCCollateOptions* aOptions)
{
NS_ENSURE_ARG_POINTER(aOptions);
NS_ENSURE_TRUE((aStrength < 4), NS_ERROR_FAILURE);
@ -83,8 +79,7 @@ nsresult nsCollationMacUC::StrengthToOptions(
return NS_OK;
}
nsresult nsCollationMacUC::ConvertLocale(
nsILocale* aNSLocale, LocaleRef* aMacLocale)
nsresult nsCollationMacUC::ConvertLocale(nsILocale* aNSLocale, LocaleRef* aMacLocale)
{
NS_ENSURE_ARG_POINTER(aNSLocale);
NS_ENSURE_ARG_POINTER(aMacLocale);
@ -95,23 +90,21 @@ nsresult nsCollationMacUC::ConvertLocale(
NS_LossyConvertUTF16toASCII tmp(localeString);
tmp.ReplaceChar('-', '_');
OSStatus err;
err = ::LocaleRefFromLocaleString( tmp.get(), aMacLocale);
err = ::LocaleRefFromLocaleString(tmp.get(), aMacLocale);
NS_ENSURE_TRUE((err == noErr), NS_ERROR_FAILURE);
return NS_OK;
}
nsresult nsCollationMacUC::EnsureCollator(
const PRInt32 newStrength)
nsresult nsCollationMacUC::EnsureCollator(const PRInt32 newStrength)
{
NS_ENSURE_TRUE(mInit, NS_ERROR_NOT_INITIALIZED);
if (mHasCollator && (mLastStrength == newStrength))
return NS_OK;
OSStatus err;
if (mHasCollator)
{
err = ::UCDisposeCollator( &mCollator );
if (mHasCollator) {
err = ::UCDisposeCollator(&mCollator);
mHasCollator = PR_FALSE;
NS_ENSURE_TRUE((err == noErr), NS_ERROR_FAILURE);
}
@ -129,35 +122,29 @@ nsresult nsCollationMacUC::EnsureCollator(
return NS_OK;
}
NS_IMETHODIMP nsCollationMacUC::Initialize(
nsILocale* locale)
NS_IMETHODIMP nsCollationMacUC::Initialize(nsILocale* locale)
{
NS_ENSURE_TRUE((!mInit), NS_ERROR_ALREADY_INITIALIZED);
nsCOMPtr<nsILocale> appLocale;
nsresult res;
if (locale == nsnull)
{
nsCOMPtr<nsILocaleService> localeService = do_GetService(NS_LOCALESERVICE_CONTRACTID, &res);
NS_ENSURE_SUCCESS(res, res);
res = localeService->GetApplicationLocale(getter_AddRefs(appLocale));
NS_ENSURE_SUCCESS(res, res);
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;
}
res = ConvertLocale(locale, &mLocale);
NS_ENSURE_SUCCESS(res, res);
rv = ConvertLocale(locale, &mLocale);
NS_ENSURE_SUCCESS(rv, rv);
mInit = PR_TRUE;
return NS_OK;
};
}
NS_IMETHODIMP nsCollationMacUC::AllocateRawSortKey(
PRInt32 strength,
const nsAString& stringIn,
PRUint8** key,
PRUint32* outLen)
NS_IMETHODIMP nsCollationMacUC::AllocateRawSortKey(PRInt32 strength, const nsAString& stringIn,
PRUint8** key, PRUint32* outLen)
{
NS_ENSURE_TRUE(mInit, NS_ERROR_NOT_INITIALIZED);
NS_ENSURE_ARG_POINTER(key);
@ -170,8 +157,9 @@ NS_IMETHODIMP nsCollationMacUC::AllocateRawSortKey(
PRUint32 maxKeyLen = (1 + stringInLen) * kCollationValueSizeFactor * sizeof(UCCollationValue);
if (maxKeyLen > mBufferLen) {
PRUint32 newBufferLen = mBufferLen;
do newBufferLen *= 2;
while (maxKeyLen > newBufferLen);
do {
newBufferLen *= 2;
} while (newBufferLen < maxKeyLen);
void *newBuffer = PR_Malloc(newBufferLen);
if (!newBuffer)
return NS_ERROR_OUT_OF_MEMORY;
@ -185,7 +173,7 @@ NS_IMETHODIMP nsCollationMacUC::AllocateRawSortKey(
OSStatus err = ::UCGetCollationKey(mCollator, (const UniChar*) PromiseFlatString(stringIn).get(),
(UniCharCount) stringInLen,
(ItemCount) (mBufferLen / sizeof(UCCollationValue)),
&actual, (UCCollationValue *)key);
&actual, (UCCollationValue *)mBuffer);
NS_ENSURE_TRUE((err == noErr), NS_ERROR_FAILURE);
PRUint32 keyLength = actual * sizeof(UCCollationValue);
@ -200,12 +188,8 @@ NS_IMETHODIMP nsCollationMacUC::AllocateRawSortKey(
return NS_OK;
}
NS_IMETHODIMP nsCollationMacUC::CompareString(
PRInt32 strength,
const nsAString& string1,
const nsAString& string2,
PRInt32* result)
NS_IMETHODIMP nsCollationMacUC::CompareString(PRInt32 strength, const nsAString& string1,
const nsAString& string2, PRInt32* result)
{
NS_ENSURE_TRUE(mInit, NS_ERROR_NOT_INITIALIZED);
NS_ENSURE_ARG_POINTER(result);
@ -225,26 +209,22 @@ NS_IMETHODIMP nsCollationMacUC::CompareString(
return NS_OK;
}
NS_IMETHODIMP nsCollationMacUC::CompareRawSortKey(
const PRUint8* key1, PRUint32 len1,
const PRUint8* key2, PRUint32 len2,
PRInt32* result)
NS_IMETHODIMP nsCollationMacUC::CompareRawSortKey(const PRUint8* key1, PRUint32 len1,
const PRUint8* key2, PRUint32 len2,
PRInt32* 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;
OSStatus err;
err = ::UCCompareCollationKeys((const UCCollationValue*) key1, (ItemCount) len1,
(const UCCollationValue*) key2, (ItemCount) len2,
NULL, (SInt32*) result);
NS_ENSURE_TRUE((err == noErr), NS_ERROR_FAILURE);
return NS_OK;
}
#endif

View File

@ -36,13 +36,12 @@
*
* ***** END LICENSE BLOCK ***** */
#ifndef nsCollationMacUC_h__
#define nsCollationMacUC_h__
#ifndef nsCollationMacUC_h_
#define nsCollationMacUC_h_
#include "nsICollation.h"
#include "nsCollation.h" // static library
#include <MacLocales.h>
#include <UnicodeUtilities.h>
#include "nsCollation.h"
#include <Carbon/Carbon.h>
// Maximum number of characters for a buffer to remember
// the generated collation key.
@ -79,4 +78,4 @@ private:
PRUint32 mBufferLen; // byte length of buffer
};
#endif /* nsCollationMacUC_h__ */
#endif /* nsCollationMacUC_h_ */

View File

@ -48,7 +48,7 @@
#include "nsLanguageAtomService.h"
#include "nsLocaleCID.h"
#if defined(XP_MAC) || defined(XP_MACOSX)
#if defined(XP_MACOSX)
#define USE_MAC_LOCALE
#endif
@ -69,13 +69,7 @@
#endif
#ifdef USE_MAC_LOCALE
// We currently do not define USE_UCCOLLATIONKEY because it causes crashes.
// See bug 128323 and bug 255192
#ifdef USE_UCCOLLATIONKEY
#include "nsCollationMacUC.h"
#else
#include "nsCollationMac.h"
#endif
#include "nsDateTimeFormatMac.h"
#include "nsMacLocale.h"
#endif
@ -123,11 +117,7 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsDateTimeFormatUnix)
#ifdef USE_MAC_LOCALE
NS_GENERIC_FACTORY_CONSTRUCTOR(nsMacLocale)
#ifdef USE_UCCOLLATIONKEY
NS_GENERIC_FACTORY_CONSTRUCTOR(nsCollationMacUC)
#else
NS_GENERIC_FACTORY_CONSTRUCTOR(nsCollationMac)
#endif
NS_GENERIC_FACTORY_CONSTRUCTOR(nsDateTimeFormatMac)
#endif