Back to index

lightning-sunbird  0.9+nobinonly
nsCollationMacUC.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Pierre Phaneuf <pp@ludusdesign.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #if TARGET_CARBON
00040 #include "nsCollationMacUC.h"
00041 #include "nsILocaleService.h"
00042 #include "nsIServiceManager.h"
00043 #include "prmem.h"
00044 
00045 
00047 
00048 NS_IMPL_ISUPPORTS1(nsCollationMacUC, nsICollation)
00049 
00050 
00051 nsCollationMacUC::nsCollationMacUC() 
00052   : mInit(PR_FALSE)
00053   , mHasCollator(PR_FALSE)
00054   , mBuffer(nsnull)
00055   , mBufferLen(1)
00056 {
00057 }
00058 
00059 nsCollationMacUC::~nsCollationMacUC() 
00060 {
00061   if (mHasCollator) 
00062   {
00063     OSStatus err = ::UCDisposeCollator(&mCollator);
00064     mHasCollator = PR_FALSE;
00065     NS_ASSERTION((err == noErr), "UCDisposeCollator failed");
00066   }
00067   PR_FREEIF(mBuffer);
00068 }
00069 
00070 nsresult nsCollationMacUC::StrengthToOptions(
00071   const PRInt32 aStrength,
00072   UCCollateOptions* aOptions)
00073 {
00074   NS_ENSURE_ARG_POINTER(aOptions);
00075   NS_ENSURE_TRUE((aStrength < 4), NS_ERROR_FAILURE);
00076   // set our default collation options
00077   UCCollateOptions options = kUCCollateStandardOptions | kUCCollatePunctuationSignificantMask;
00078   if (aStrength & kCollationCaseInsensitiveAscii)
00079     options |= kUCCollateCaseInsensitiveMask;
00080   if (aStrength & kCollationAccentInsenstive)
00081     options |= kUCCollateDiacritInsensitiveMask;
00082   *aOptions = options;
00083   return NS_OK;
00084 }
00085 
00086 nsresult nsCollationMacUC::ConvertLocale(
00087   nsILocale* aNSLocale, LocaleRef* aMacLocale) 
00088 {
00089   NS_ENSURE_ARG_POINTER(aNSLocale);
00090   NS_ENSURE_ARG_POINTER(aMacLocale);
00091 
00092   nsAutoString localeString;
00093   nsresult res = aNSLocale->GetCategory(NS_LITERAL_STRING("NSILOCALE_COLLATE"), localeString);
00094   NS_ENSURE_TRUE(res == noErr && !localeString.IsEmpty(), NS_ERROR_FAILURE);
00095   NS_LossyConvertUTF16toASCII tmp(localeString);
00096   tmp.ReplaceChar('-', '_');
00097   OSStatus err;
00098   err = ::LocaleRefFromLocaleString( tmp.get(), aMacLocale);
00099   NS_ENSURE_TRUE((err == noErr), NS_ERROR_FAILURE);
00100 
00101   return NS_OK;
00102 }
00103 
00104 nsresult nsCollationMacUC::EnsureCollator(
00105   const PRInt32 newStrength) 
00106 {
00107   NS_ENSURE_TRUE(mInit, NS_ERROR_NOT_INITIALIZED);
00108   if (mHasCollator && (mLastStrength == newStrength))
00109     return NS_OK;
00110 
00111   OSStatus err;
00112   if (mHasCollator) 
00113   {
00114     err = ::UCDisposeCollator( &mCollator );
00115     mHasCollator = PR_FALSE;
00116     NS_ENSURE_TRUE((err == noErr), NS_ERROR_FAILURE);
00117   }
00118 
00119   UCCollateOptions newOptions;
00120   nsresult res = StrengthToOptions(newStrength, &newOptions);
00121   NS_ENSURE_SUCCESS(res, res);
00122   
00123   LocaleOperationVariant opVariant = 0; // default variant for now
00124   err = ::UCCreateCollator(mLocale, opVariant, newOptions, &mCollator);
00125   NS_ENSURE_TRUE((err == noErr), NS_ERROR_FAILURE);
00126   mHasCollator = PR_TRUE;
00127 
00128   mLastStrength = newStrength;
00129   return NS_OK;
00130 }
00131 
00132 NS_IMETHODIMP nsCollationMacUC::Initialize(
00133   nsILocale* locale) 
00134 {
00135   NS_ENSURE_TRUE((!mInit), NS_ERROR_ALREADY_INITIALIZED);
00136   nsCOMPtr<nsILocale> appLocale;
00137 
00138   nsresult res;
00139   if (locale == nsnull) 
00140   {
00141     nsCOMPtr<nsILocaleService> localeService = do_GetService(NS_LOCALESERVICE_CONTRACTID, &res);
00142     NS_ENSURE_SUCCESS(res, res);
00143     res = localeService->GetApplicationLocale(getter_AddRefs(appLocale));
00144     NS_ENSURE_SUCCESS(res, res);
00145     locale = appLocale;
00146   }
00147 
00148   res = ConvertLocale(locale, &mLocale);
00149   NS_ENSURE_SUCCESS(res, res);
00150 
00151   mInit = PR_TRUE;
00152   return NS_OK;
00153 };
00154  
00155 
00156 NS_IMETHODIMP nsCollationMacUC::AllocateRawSortKey(
00157   PRInt32 strength,
00158   const nsAString& stringIn,
00159   PRUint8** key,
00160   PRUint32* outLen)
00161 {
00162   NS_ENSURE_TRUE(mInit, NS_ERROR_NOT_INITIALIZED);
00163   NS_ENSURE_ARG_POINTER(key);
00164   NS_ENSURE_ARG_POINTER(outLen);
00165 
00166   nsresult res = EnsureCollator(strength);
00167   NS_ENSURE_SUCCESS(res, res);
00168 
00169   PRUint32 stringInLen = stringIn.Length();
00170   PRUint32 maxKeyLen = (1 + stringInLen) * kCollationValueSizeFactor * sizeof(UCCollationValue);
00171   if (maxKeyLen > mBufferLen) {
00172     PRUint32 newBufferLen = mBufferLen;
00173     do newBufferLen *= 2;
00174     while (maxKeyLen > newBufferLen);
00175     void *newBuffer = PR_Malloc(newBufferLen);
00176     if (!newBuffer)
00177       return NS_ERROR_OUT_OF_MEMORY;
00178 
00179     PR_FREEIF(mBuffer);
00180     mBuffer = newBuffer;
00181     mBufferLen = newBufferLen;
00182   }
00183 
00184   ItemCount actual;
00185   OSStatus err = ::UCGetCollationKey(mCollator, (const UniChar*) PromiseFlatString(stringIn).get(),
00186                                      (UniCharCount) stringInLen,
00187                                      (ItemCount) (mBufferLen / sizeof(UCCollationValue)),
00188                                      &actual, (UCCollationValue *)key);
00189   NS_ENSURE_TRUE((err == noErr), NS_ERROR_FAILURE);
00190 
00191   PRUint32 keyLength = actual * sizeof(UCCollationValue);
00192   void *newKey = PR_Malloc(keyLength);
00193   if (!newKey)
00194     return NS_ERROR_OUT_OF_MEMORY;
00195 
00196   memcpy(newKey, mBuffer, keyLength);
00197   *key = (PRUint8 *)newKey;
00198   *outLen = keyLength;
00199 
00200   return NS_OK;
00201 }
00202 
00203     
00204 NS_IMETHODIMP nsCollationMacUC::CompareString(
00205   PRInt32 strength, 
00206   const nsAString& string1, 
00207   const nsAString& string2, 
00208   PRInt32* result) 
00209 {
00210   NS_ENSURE_TRUE(mInit, NS_ERROR_NOT_INITIALIZED);
00211   NS_ENSURE_ARG_POINTER(result);
00212   *result = 0;
00213 
00214   nsresult res = EnsureCollator(strength);
00215   NS_ENSURE_SUCCESS(res, res);
00216   *result = 0;
00217 
00218   OSStatus err;
00219   err = ::UCCompareText(mCollator, 
00220                         (const UniChar *) PromiseFlatString(string1).get(), (UniCharCount) string1.Length(),
00221                         (const UniChar *) PromiseFlatString(string2).get(), (UniCharCount) string2.Length(),
00222                         NULL, (SInt32*) result);
00223 
00224   NS_ENSURE_TRUE((err == noErr), NS_ERROR_FAILURE);
00225   return NS_OK;
00226 }
00227 
00228 
00229 NS_IMETHODIMP nsCollationMacUC::CompareRawSortKey(
00230   const PRUint8* key1, PRUint32 len1, 
00231   const PRUint8* key2, PRUint32 len2, 
00232   PRInt32* result)
00233 {
00234   NS_ENSURE_TRUE(mInit, NS_ERROR_NOT_INITIALIZED);
00235   NS_ENSURE_ARG_POINTER(key1);
00236   NS_ENSURE_ARG_POINTER(key2);
00237   NS_ENSURE_ARG_POINTER(result);
00238   *result = 0;
00239   
00240   OSStatus err;
00241   err = ::UCCompareCollationKeys((const UCCollationValue*) key1, (ItemCount) len1,
00242                                  (const UCCollationValue*) key2, (ItemCount) len2,
00243                                  NULL, (SInt32*) result);
00244 
00245   NS_ENSURE_TRUE((err == noErr), NS_ERROR_FAILURE);
00246   return NS_OK;
00247 }
00248 
00249 
00250 #endif