Back to index

lightning-sunbird  0.9+nobinonly
txXPathResultComparator.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 TransforMiiX XSLT processor code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Jonas Sicking.
00019  * Portions created by the Initial Developer are Copyright (C) 2001
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Jonas Sicking <sicking@bigfoot.com>
00024  *   Peter Van der Beken <peterv@propagandism.org>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include "txXPathResultComparator.h"
00041 #include "Expr.h"
00042 #include "ExprResult.h"
00043 #include "txCore.h"
00044 #ifndef TX_EXE
00045 #include "nsCollationCID.h"
00046 #include "nsILocale.h"
00047 #include "nsILocaleService.h"
00048 #include "nsIServiceManager.h"
00049 #include "nsLocaleCID.h"
00050 #include "prmem.h"
00051 
00052 static NS_DEFINE_CID(kCollationFactoryCID, NS_COLLATIONFACTORY_CID);
00053 #else
00054 #include "txStringUtils.h"
00055 #endif
00056 
00057 #define kAscending (1<<0)
00058 #define kUpperFirst (1<<1)
00059 
00060 txResultStringComparator::txResultStringComparator(MBool aAscending,
00061                                                    MBool aUpperFirst,
00062                                                    const nsAFlatString& aLanguage)
00063 {
00064     mSorting = 0;
00065     if (aAscending)
00066         mSorting |= kAscending;
00067     if (aUpperFirst)
00068         mSorting |= kUpperFirst;
00069 #ifndef TX_EXE
00070     nsresult rv = init(aLanguage);
00071     if (NS_FAILED(rv))
00072         NS_ERROR("Failed to initialize txResultStringComparator");
00073 #endif
00074 }
00075 
00076 txResultStringComparator::~txResultStringComparator()
00077 {
00078 }
00079 
00080 #ifndef TX_EXE
00081 nsresult txResultStringComparator::init(const nsAFlatString& aLanguage)
00082 {
00083     nsresult rv;
00084 
00085     nsCOMPtr<nsILocaleService> localeService =
00086                     do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv);
00087     NS_ENSURE_SUCCESS(rv, rv);
00088 
00089     nsCOMPtr<nsILocale> locale;
00090     if (!aLanguage.IsEmpty()) {
00091         rv = localeService->NewLocale(aLanguage,
00092                                       getter_AddRefs(locale));
00093     }
00094     else {
00095         rv = localeService->GetApplicationLocale(getter_AddRefs(locale));
00096     }
00097     NS_ENSURE_SUCCESS(rv, rv);
00098 
00099     nsCOMPtr<nsICollationFactory> colFactory =
00100                     do_CreateInstance(kCollationFactoryCID, &rv);
00101     NS_ENSURE_SUCCESS(rv, rv);
00102 
00103     rv = colFactory->CreateCollation(locale, getter_AddRefs(mCollation));
00104     NS_ENSURE_SUCCESS(rv, rv);
00105 
00106     return NS_OK;
00107 }
00108 #endif
00109 
00110 TxObject* txResultStringComparator::createSortableValue(txAExprResult* aExprRes)
00111 {
00112     StringValue* val = new StringValue;
00113 
00114     if (!val)
00115         return 0;
00116 
00117 #ifdef TX_EXE
00118     aExprRes->stringValue(val->mStr);
00119     // We don't support case-order on standalone
00120     TX_ToLowerCase(val->mStr);
00121 #else
00122     if (!mCollation)
00123         return 0;
00124 
00125     val->mCaseKey = new nsString;
00126     if (!val->mCaseKey) {
00127         delete val;
00128         return 0;
00129     }
00130 
00131     nsString& nsCaseKey = *(nsString *)val->mCaseKey;
00132     aExprRes->stringValue(nsCaseKey);
00133     if (nsCaseKey.IsEmpty()) {
00134         return val;        
00135     }
00136     nsresult rv = mCollation->AllocateRawSortKey(nsICollation::kCollationCaseInSensitive,
00137                                                  nsCaseKey,
00138                                                  &val->mKey, 
00139                                                  &val->mLength);
00140     if (NS_FAILED(rv)) {
00141         NS_ERROR("Failed to create raw sort key");
00142         delete val;
00143         return 0;
00144     }
00145 #endif
00146     return val;
00147 }
00148 
00149 int txResultStringComparator::compareValues(TxObject* aVal1, TxObject* aVal2)
00150 {
00151     StringValue* strval1 = (StringValue*)aVal1;
00152     StringValue* strval2 = (StringValue*)aVal2;
00153 #ifdef TX_EXE
00154     PRUint32 len1 = strval1->mStr.Length();
00155     PRUint32 len2 = strval2->mStr.Length();
00156     PRUint32 minLength = (len1 < len2) ? len1 : len2;
00157 
00158     PRUint32 c = 0;
00159     while (c < minLength) {
00160         PRUnichar ch1 = strval1->mStr.CharAt(c);
00161         PRUnichar ch2 = strval2->mStr.CharAt(c);
00162         if (ch1 < ch2)
00163             return ((mSorting & kAscending) ? 1 : -1) * -1;
00164         if (ch2 < ch1)
00165             return ((mSorting & kAscending) ? 1 : -1) * 1;
00166         c++;
00167     }
00168 
00169     if (len1 == len2)
00170         return 0;
00171 
00172     return ((mSorting & kAscending) ? 1 : -1) * ((len1 < len2) ? -1 : 1);
00173 #else
00174     if (!mCollation)
00175         return -1;
00176 
00177     if (strval1->mLength == 0) {
00178         if (strval2->mLength == 0)
00179             return 0;
00180         return ((mSorting & kAscending) ? -1 : 1);
00181     }
00182 
00183     if (strval2->mLength == 0)
00184         return ((mSorting & kAscending) ? 1 : -1);
00185 
00186     nsresult rv;
00187     PRInt32 result = -1;
00188     rv = mCollation->CompareRawSortKey(strval1->mKey, strval1->mLength,
00189                                        strval2->mKey, strval2->mLength,
00190                                        &result);
00191     if (NS_FAILED(rv)) {
00192         // XXX ErrorReport
00193         return -1;
00194     }
00195 
00196     if (result != 0)
00197         return ((mSorting & kAscending) ? 1 : -1) * result;
00198 
00199     if ((strval1->mCaseLength == 0) && (strval1->mLength != 0)) {
00200         nsString* caseString = (nsString *)strval1->mCaseKey;
00201         rv = mCollation->AllocateRawSortKey(nsICollation::kCollationCaseSensitive,
00202                                             *caseString,
00203                                             (PRUint8**)&strval1->mCaseKey, 
00204                                             &strval1->mCaseLength);
00205         if (NS_FAILED(rv)) {
00206             // XXX ErrorReport
00207             strval1->mCaseKey = caseString;
00208             strval1->mCaseLength = 0;
00209             return -1;
00210         }
00211         delete caseString;
00212     }
00213     if ((strval2->mCaseLength == 0) && (strval2->mLength != 0)) {
00214         nsString* caseString = (nsString *)strval2->mCaseKey;
00215         rv = mCollation->AllocateRawSortKey(nsICollation::kCollationCaseSensitive,
00216                                             *caseString,
00217                                             (PRUint8**)&strval2->mCaseKey, 
00218                                             &strval2->mCaseLength);
00219         if (NS_FAILED(rv)) {
00220             // XXX ErrorReport
00221             strval2->mCaseKey = caseString;
00222             strval2->mCaseLength = 0;
00223             return -1;
00224         }
00225         delete caseString;
00226     }
00227     rv = mCollation->CompareRawSortKey((PRUint8*)strval1->mCaseKey, strval1->mCaseLength,
00228                                        (PRUint8*)strval2->mCaseKey, strval2->mCaseLength,
00229                                        &result);
00230     if (NS_FAILED(rv)) {
00231         // XXX ErrorReport
00232         return -1;
00233     }
00234 
00235     return ((mSorting & kAscending) ? 1 : -1) *
00236            ((mSorting & kUpperFirst) ? -1 : 1) * result;
00237 #endif
00238 }
00239 
00240 #ifndef TX_EXE
00241 txResultStringComparator::StringValue::StringValue() : mKey(0),
00242                                                        mCaseKey(0),
00243                                                        mLength(0),
00244                                                        mCaseLength(0)
00245 {
00246 }
00247 
00248 txResultStringComparator::StringValue::~StringValue()
00249 {
00250     PR_Free(mKey);
00251     if (mCaseLength > 0)
00252         PR_Free((PRUint8*)mCaseKey);
00253     else
00254         delete (nsString*)mCaseKey;
00255 }
00256 #endif
00257 
00258 txResultNumberComparator::txResultNumberComparator(MBool aAscending)
00259 {
00260     mAscending = aAscending ? 1 : -1;
00261 }
00262 
00263 txResultNumberComparator::~txResultNumberComparator()
00264 {
00265 }
00266 
00267 TxObject* txResultNumberComparator::createSortableValue(txAExprResult* aExprRes)
00268 {
00269     NumberValue* numval = new NumberValue;
00270     if (numval)
00271         numval->mVal = aExprRes->numberValue();
00272     return numval;
00273 }
00274 
00275 int txResultNumberComparator::compareValues(TxObject* aVal1, TxObject* aVal2)
00276 {
00277     double dval1 = ((NumberValue*)aVal1)->mVal;
00278     double dval2 = ((NumberValue*)aVal2)->mVal;
00279 
00280     if (Double::isNaN(dval1))
00281         return Double::isNaN(dval2) ? 0 : -mAscending;
00282 
00283     if (Double::isNaN(dval2))
00284         return mAscending;
00285 
00286     if (dval1 == dval2)
00287         return 0;
00288     
00289     return (dval1 < dval2) ? -mAscending : mAscending;
00290 }