1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is TransforMiiX XSLT processor code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Jonas Sicking.
19 : * Portions created by the Initial Developer are Copyright (C) 2001
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Jonas Sicking <sicking@bigfoot.com>
24 : * Peter Van der Beken <peterv@propagandism.org>
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either the GNU General Public License Version 2 or later (the "GPL"), or
28 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 :
40 : #include "txXPathResultComparator.h"
41 : #include "txExpr.h"
42 : #include "txCore.h"
43 : #include "nsCollationCID.h"
44 : #include "nsILocale.h"
45 : #include "nsILocaleService.h"
46 : #include "nsIServiceManager.h"
47 : #include "nsLocaleCID.h"
48 : #include "prmem.h"
49 :
50 : #define kAscending (1<<0)
51 : #define kUpperFirst (1<<1)
52 :
53 0 : txResultStringComparator::txResultStringComparator(bool aAscending,
54 : bool aUpperFirst,
55 0 : const nsAFlatString& aLanguage)
56 : {
57 0 : mSorting = 0;
58 0 : if (aAscending)
59 0 : mSorting |= kAscending;
60 0 : if (aUpperFirst)
61 0 : mSorting |= kUpperFirst;
62 0 : nsresult rv = init(aLanguage);
63 0 : if (NS_FAILED(rv))
64 0 : NS_ERROR("Failed to initialize txResultStringComparator");
65 0 : }
66 :
67 0 : nsresult txResultStringComparator::init(const nsAFlatString& aLanguage)
68 : {
69 : nsresult rv;
70 :
71 : nsCOMPtr<nsILocaleService> localeService =
72 0 : do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv);
73 0 : NS_ENSURE_SUCCESS(rv, rv);
74 :
75 0 : nsCOMPtr<nsILocale> locale;
76 0 : if (!aLanguage.IsEmpty()) {
77 0 : rv = localeService->NewLocale(aLanguage,
78 0 : getter_AddRefs(locale));
79 : }
80 : else {
81 0 : rv = localeService->GetApplicationLocale(getter_AddRefs(locale));
82 : }
83 0 : NS_ENSURE_SUCCESS(rv, rv);
84 :
85 : nsCOMPtr<nsICollationFactory> colFactory =
86 0 : do_CreateInstance(NS_COLLATIONFACTORY_CONTRACTID, &rv);
87 0 : NS_ENSURE_SUCCESS(rv, rv);
88 :
89 0 : rv = colFactory->CreateCollation(locale, getter_AddRefs(mCollation));
90 0 : NS_ENSURE_SUCCESS(rv, rv);
91 :
92 0 : return NS_OK;
93 : }
94 :
95 : nsresult
96 0 : txResultStringComparator::createSortableValue(Expr *aExpr,
97 : txIEvalContext *aContext,
98 : txObject *&aResult)
99 : {
100 0 : nsAutoPtr<StringValue> val(new StringValue);
101 0 : if (!val) {
102 0 : return NS_ERROR_OUT_OF_MEMORY;
103 : }
104 :
105 0 : if (!mCollation)
106 0 : return NS_ERROR_FAILURE;
107 :
108 0 : val->mCaseKey = new nsString;
109 0 : if (!val->mCaseKey) {
110 0 : return NS_ERROR_OUT_OF_MEMORY;
111 : }
112 :
113 0 : nsString& nsCaseKey = *(nsString *)val->mCaseKey;
114 0 : nsresult rv = aExpr->evaluateToString(aContext, nsCaseKey);
115 0 : NS_ENSURE_SUCCESS(rv, rv);
116 :
117 0 : if (nsCaseKey.IsEmpty()) {
118 0 : aResult = val.forget();
119 :
120 0 : return NS_OK;
121 : }
122 :
123 0 : rv = mCollation->AllocateRawSortKey(nsICollation::kCollationCaseInSensitive,
124 0 : nsCaseKey, &val->mKey, &val->mLength);
125 0 : NS_ENSURE_SUCCESS(rv, rv);
126 :
127 0 : aResult = val.forget();
128 :
129 0 : return NS_OK;
130 : }
131 :
132 0 : int txResultStringComparator::compareValues(txObject* aVal1, txObject* aVal2)
133 : {
134 0 : StringValue* strval1 = (StringValue*)aVal1;
135 0 : StringValue* strval2 = (StringValue*)aVal2;
136 :
137 0 : if (!mCollation)
138 0 : return -1;
139 :
140 0 : if (strval1->mLength == 0) {
141 0 : if (strval2->mLength == 0)
142 0 : return 0;
143 0 : return ((mSorting & kAscending) ? -1 : 1);
144 : }
145 :
146 0 : if (strval2->mLength == 0)
147 0 : return ((mSorting & kAscending) ? 1 : -1);
148 :
149 : nsresult rv;
150 0 : PRInt32 result = -1;
151 0 : rv = mCollation->CompareRawSortKey(strval1->mKey, strval1->mLength,
152 : strval2->mKey, strval2->mLength,
153 0 : &result);
154 0 : if (NS_FAILED(rv)) {
155 : // XXX ErrorReport
156 0 : return -1;
157 : }
158 :
159 0 : if (result != 0)
160 0 : return ((mSorting & kAscending) ? 1 : -1) * result;
161 :
162 0 : if ((strval1->mCaseLength == 0) && (strval1->mLength != 0)) {
163 0 : nsString* caseString = (nsString *)strval1->mCaseKey;
164 0 : rv = mCollation->AllocateRawSortKey(nsICollation::kCollationCaseSensitive,
165 : *caseString,
166 : (PRUint8**)&strval1->mCaseKey,
167 0 : &strval1->mCaseLength);
168 0 : if (NS_FAILED(rv)) {
169 : // XXX ErrorReport
170 0 : strval1->mCaseKey = caseString;
171 0 : strval1->mCaseLength = 0;
172 0 : return -1;
173 : }
174 0 : delete caseString;
175 : }
176 0 : if ((strval2->mCaseLength == 0) && (strval2->mLength != 0)) {
177 0 : nsString* caseString = (nsString *)strval2->mCaseKey;
178 0 : rv = mCollation->AllocateRawSortKey(nsICollation::kCollationCaseSensitive,
179 : *caseString,
180 : (PRUint8**)&strval2->mCaseKey,
181 0 : &strval2->mCaseLength);
182 0 : if (NS_FAILED(rv)) {
183 : // XXX ErrorReport
184 0 : strval2->mCaseKey = caseString;
185 0 : strval2->mCaseLength = 0;
186 0 : return -1;
187 : }
188 0 : delete caseString;
189 : }
190 0 : rv = mCollation->CompareRawSortKey((PRUint8*)strval1->mCaseKey, strval1->mCaseLength,
191 : (PRUint8*)strval2->mCaseKey, strval2->mCaseLength,
192 0 : &result);
193 0 : if (NS_FAILED(rv)) {
194 : // XXX ErrorReport
195 0 : return -1;
196 : }
197 :
198 : return ((mSorting & kAscending) ? 1 : -1) *
199 0 : ((mSorting & kUpperFirst) ? -1 : 1) * result;
200 : }
201 :
202 0 : txResultStringComparator::StringValue::StringValue() : mKey(0),
203 : mCaseKey(0),
204 : mLength(0),
205 0 : mCaseLength(0)
206 : {
207 0 : }
208 :
209 0 : txResultStringComparator::StringValue::~StringValue()
210 : {
211 0 : PR_Free(mKey);
212 0 : if (mCaseLength > 0)
213 0 : PR_Free((PRUint8*)mCaseKey);
214 : else
215 0 : delete (nsString*)mCaseKey;
216 0 : }
217 :
218 0 : txResultNumberComparator::txResultNumberComparator(bool aAscending)
219 : {
220 0 : mAscending = aAscending ? 1 : -1;
221 0 : }
222 :
223 : nsresult
224 0 : txResultNumberComparator::createSortableValue(Expr *aExpr,
225 : txIEvalContext *aContext,
226 : txObject *&aResult)
227 : {
228 0 : nsAutoPtr<NumberValue> numval(new NumberValue);
229 0 : if (!numval) {
230 0 : return NS_ERROR_OUT_OF_MEMORY;
231 : }
232 :
233 0 : nsRefPtr<txAExprResult> exprRes;
234 0 : nsresult rv = aExpr->evaluate(aContext, getter_AddRefs(exprRes));
235 0 : NS_ENSURE_SUCCESS(rv, rv);
236 :
237 0 : numval->mVal = exprRes->numberValue();
238 :
239 0 : aResult = numval.forget();
240 :
241 0 : return NS_OK;
242 : }
243 :
244 0 : int txResultNumberComparator::compareValues(txObject* aVal1, txObject* aVal2)
245 : {
246 0 : double dval1 = ((NumberValue*)aVal1)->mVal;
247 0 : double dval2 = ((NumberValue*)aVal2)->mVal;
248 :
249 0 : if (txDouble::isNaN(dval1))
250 0 : return txDouble::isNaN(dval2) ? 0 : -mAscending;
251 :
252 0 : if (txDouble::isNaN(dval2))
253 0 : return mAscending;
254 :
255 0 : if (dval1 == dval2)
256 0 : return 0;
257 :
258 0 : return (dval1 < dval2) ? -mAscending : mAscending;
259 : }
|