Back to index

lightning-sunbird  0.9+nobinonly
nsCollationMac.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 #include "nsCollationMac.h"
00039 #include <Resources.h>
00040 #include <TextUtils.h>
00041 #include <Script.h>
00042 #include "prmem.h"
00043 #include "prmon.h"
00044 #include "nsIServiceManager.h"
00045 #include "nsIComponentManager.h"
00046 #include "nsILocaleService.h"
00047 #include "nsLocaleCID.h"
00048 #include "nsIPlatformCharset.h"
00049 #include "nsIMacLocale.h"
00050 #include "nsCOMPtr.h"
00051 
00053 
00054 /* Copy from FE_StrColl(), macfe/utility/locale.cp. */
00055 static short mac_get_script_sort_id(const short scriptcode)
00056 {
00057        short itl2num;
00058        ItlbRecord **ItlbRecordHandle;
00059 
00060        /* get itlb of the system script */
00061        ItlbRecordHandle = (ItlbRecord **) GetResource('itlb', scriptcode);
00062        
00063        /* get itl2 number of current system script from itlb if possible
00064         * otherwise, try script manager (Script manager won't update 
00065         * itl2 number when the change on the fly )
00066         */
00067        if(ItlbRecordHandle != NULL)
00068        {
00069               if(*ItlbRecordHandle == NULL)
00070                      LoadResource((Handle)ItlbRecordHandle);
00071                      
00072               if(*ItlbRecordHandle != NULL)
00073                      itl2num = (*ItlbRecordHandle)->itlbSort;
00074               else
00075                      itl2num = GetScriptVariable(scriptcode, smScriptSort);
00076        } else {      /* Use this as fallback */
00077               itl2num = GetScriptVariable(scriptcode, smScriptSort);
00078        }
00079        
00080        return itl2num;
00081 }
00082 
00083 static Handle itl2Handle;
00084 
00085 static int mac_sort_tbl_compare(const void* s1, const void* s2)
00086 {
00087        return CompareText((Ptr) s1, (Ptr) s2, 1, 1, itl2Handle);
00088 }
00089 
00090 static int mac_sort_tbl_init(const short scriptcode, unsigned char *mac_sort_tbl)
00091 {
00092        int i;
00093        unsigned char sort_tbl[256];
00094        
00095        for (i = 0; i < 256; i++)
00096               sort_tbl[i] = (unsigned char) i;
00097 
00098        /* Get itl2. */
00099        itl2Handle = GetResource('itl2', mac_get_script_sort_id(scriptcode));
00100        if (itl2Handle == NULL)
00101               return -1;
00102        
00103        /* qsort */
00104        PRMonitor* mon = PR_NewMonitor();
00105        PR_EnterMonitor(mon);
00106        qsort((void *) sort_tbl, 256, 1, mac_sort_tbl_compare);
00107        (void) PR_ExitMonitor(mon);
00108        PR_DestroyMonitor(mon);
00109        
00110        /* Put index to the table so we can map character code to sort oder. */
00111        for (i = 0; i < 256; i++)
00112               mac_sort_tbl[sort_tbl[i]] = (unsigned char) i;
00113               
00114        return 0;
00115 }
00116 
00117 inline unsigned char mac_sort_tbl_search(const unsigned char ch, const unsigned char* mac_sort_tbl)
00118 {
00119        /* Map character code to sort order. */
00120        return mac_sort_tbl[ch];
00121 }
00122 
00124 
00125 NS_IMPL_ISUPPORTS1(nsCollationMac, nsICollation)
00126 
00127 
00128 nsCollationMac::nsCollationMac() 
00129 {
00130   mCollation = NULL;
00131 }
00132 
00133 nsCollationMac::~nsCollationMac() 
00134 {
00135   if (mCollation != NULL)
00136     delete mCollation;
00137 }
00138 
00139 nsresult nsCollationMac::Initialize(nsILocale* locale) 
00140 {
00141   NS_ASSERTION(mCollation == NULL, "Should only be initialized once.");
00142   nsresult res;
00143   mCollation = new nsCollation;
00144   if (mCollation == NULL) {
00145     NS_ASSERTION(0, "mCollation creation failed");
00146     return NS_ERROR_OUT_OF_MEMORY;
00147   }
00148 
00149   // locale -> script code + charset name
00150   m_scriptcode = smRoman;
00151 
00152   nsAutoString localeStr;
00153 
00154   // get locale string, use app default if no locale specified
00155   if (locale == nsnull) {
00156     nsCOMPtr<nsILocaleService> localeService = 
00157              do_GetService(NS_LOCALESERVICE_CONTRACTID, &res);
00158     if (NS_SUCCEEDED(res)) {
00159       nsCOMPtr<nsILocale> appLocale;
00160       res = localeService->GetApplicationLocale(getter_AddRefs(appLocale));
00161       if (NS_SUCCEEDED(res)) {
00162         res = appLocale->GetCategory(NS_LITERAL_STRING("NSILOCALE_COLLATE"), 
00163                                      localeStr);
00164       }
00165     }
00166   }
00167   else {
00168     res = locale->GetCategory(NS_LITERAL_STRING("NSILOCALE_COLLATE"), 
00169                               localeStr);
00170   }
00171 
00172   if (NS_SUCCEEDED(res)) {
00173     short scriptcode, langcode, regioncode;
00174     nsCOMPtr <nsIMacLocale> macLocale = do_GetService(NS_MACLOCALE_CONTRACTID, &res);
00175     if (NS_SUCCEEDED(res)) {
00176       if (NS_SUCCEEDED(res = macLocale->GetPlatformLocale(localeStr, &scriptcode, &langcode, &regioncode))) {
00177         m_scriptcode = scriptcode;
00178       }
00179     }
00180 
00181     nsCOMPtr <nsIPlatformCharset> platformCharset = do_GetService(NS_PLATFORMCHARSET_CONTRACTID, &res);
00182     if (NS_SUCCEEDED(res)) {
00183       nsCAutoString mappedCharset;
00184       res = platformCharset->GetDefaultCharsetForLocale(localeStr, mappedCharset);
00185       if (NS_SUCCEEDED(res)) {
00186         res = mCollation->SetCharset(mappedCharset.get());
00187       }
00188     }
00189   }
00190   NS_ASSERTION(NS_SUCCEEDED(res), "initialization failed, use default values");
00191 
00192   // Initialize a mapping table for the script code.
00193   if (mac_sort_tbl_init(m_scriptcode, m_mac_sort_tbl) == -1) {
00194     return NS_ERROR_FAILURE;
00195   }
00196 
00197   return NS_OK;
00198 };
00199 
00200 
00201 nsresult nsCollationMac::CompareString(PRInt32 strength, 
00202                                        const nsAString& string1, const nsAString& string2, PRInt32* result)
00203 {
00204   PRUint32 aLength1, aLength2;
00205   PRUint8 *aKey1 = nsnull, *aKey2 = nsnull;
00206   nsresult res;
00207 
00208   res = AllocateRawSortKey(strength, string1, &aKey1, &aLength1);
00209   if (NS_SUCCEEDED(res)) {
00210     res = AllocateRawSortKey(strength, string2, &aKey2, &aLength2);
00211     if (NS_SUCCEEDED(res))
00212       *result = strcmp((const char *)aKey1, (const char *)aKey2); // compare keys
00213   }
00214 
00215   // delete keys
00216   PR_FREEIF(aKey1);
00217   PR_FREEIF(aKey2);
00218 
00219   return res;
00220 }
00221  
00222 
00223 nsresult nsCollationMac::AllocateRawSortKey(PRInt32 strength, 
00224                                             const nsAString& stringIn, PRUint8** key, PRUint32* outLen)
00225 {
00226   nsresult res = NS_OK;
00227 
00228   nsAutoString stringNormalized;
00229   if (strength != kCollationCaseSensitive) {
00230     res = mCollation->NormalizeString(stringIn, stringNormalized);
00231   } else {
00232     stringNormalized = stringIn;
00233   }
00234 
00235   // convert unicode to charset
00236   char *str;
00237   int str_len;
00238 
00239   res = mCollation->UnicodeToChar(stringNormalized, &str);
00240   if (NS_SUCCEEDED(res) && str != NULL) {
00241     str_len = strlen(str);
00242     *key = (PRUint8 *)str;
00243     *outLen = str_len + 1;
00244     
00245     // If no CJK then generate a collation key
00246     if (smJapanese != m_scriptcode && smKorean != m_scriptcode && 
00247         smTradChinese != m_scriptcode && smSimpChinese != m_scriptcode) {
00248       while (*str) {
00249         *str = (PRUint8) mac_sort_tbl_search((const unsigned char) *str, m_mac_sort_tbl);
00250         ++str;
00251       }
00252     }
00253     // No CJK support, just copy the row string.
00254     // ShiftJIS specific, shift hankaku kana in front of zenkaku.
00255     else if (smJapanese == m_scriptcode) {
00256       while (*str) {
00257         if ((unsigned char) *str >= 0xA0 && (unsigned char) *str < 0xE0) {
00258           *str -= (0xA0 - 0x81);
00259         }
00260         else if ((unsigned char) *str >= 0x81 && (unsigned char) *str < 0xA0) {
00261           *str += (0xE0 - 0xA0);
00262         } 
00263         // advance 2 bytes if the API says so and not passing the end of the string
00264         if (CharacterByteType((Ptr) str, 0, m_scriptcode) == smFirstByte) {
00265           ++str;
00266           if (!*str)
00267             break;
00268         }
00269       ++str;
00270       }
00271     }
00272   }
00273 
00274   return NS_OK;
00275 }
00276 
00277 nsresult nsCollationMac::CompareRawSortKey(const PRUint8* key1, PRUint32 len1, 
00278                                            const PRUint8* key2, PRUint32 len2, 
00279                                            PRInt32* result)
00280 {
00281   *result = PL_strcmp((const char *)key1, (const char *)key2);
00282   return NS_OK;
00283 }