1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #include "mozilla/FloatingPoint.h"
7
8 #include "txXPathResultComparator.h"
9 #include "txExpr.h"
10 #include "nsComponentManagerUtils.h"
11 #include "txCore.h"
12 #include "nsCollationCID.h"
13
14 using namespace mozilla;
15
16 #define kAscending (1 << 0)
17 #define kUpperFirst (1 << 1)
18
txResultStringComparator(bool aAscending,bool aUpperFirst,const nsString & aLanguage)19 txResultStringComparator::txResultStringComparator(bool aAscending,
20 bool aUpperFirst,
21 const nsString& aLanguage) {
22 mSorting = 0;
23 if (aAscending) mSorting |= kAscending;
24 if (aUpperFirst) mSorting |= kUpperFirst;
25 nsresult rv = init(aLanguage);
26 if (NS_FAILED(rv)) NS_ERROR("Failed to initialize txResultStringComparator");
27 }
28
init(const nsString & aLanguage)29 nsresult txResultStringComparator::init(const nsString& aLanguage) {
30 nsresult rv;
31
32 nsCOMPtr<nsICollationFactory> colFactory =
33 do_CreateInstance(NS_COLLATIONFACTORY_CONTRACTID, &rv);
34 NS_ENSURE_SUCCESS(rv, rv);
35
36 if (aLanguage.IsEmpty()) {
37 rv = colFactory->CreateCollation(getter_AddRefs(mCollation));
38 } else {
39 rv = colFactory->CreateCollationForLocale(NS_ConvertUTF16toUTF8(aLanguage),
40 getter_AddRefs(mCollation));
41 }
42
43 NS_ENSURE_SUCCESS(rv, rv);
44
45 return NS_OK;
46 }
47
createSortableValue(Expr * aExpr,txIEvalContext * aContext,txObject * & aResult)48 nsresult txResultStringComparator::createSortableValue(Expr* aExpr,
49 txIEvalContext* aContext,
50 txObject*& aResult) {
51 UniquePtr<StringValue> val(new StringValue);
52
53 if (!mCollation) return NS_ERROR_FAILURE;
54
55 val->mCaseKeyString = MakeUnique<nsString>();
56 nsString& nsCaseKey = *val->mCaseKeyString;
57 nsresult rv = aExpr->evaluateToString(aContext, nsCaseKey);
58 NS_ENSURE_SUCCESS(rv, rv);
59
60 if (nsCaseKey.IsEmpty()) {
61 aResult = val.release();
62
63 return NS_OK;
64 }
65
66 rv = mCollation->AllocateRawSortKey(nsICollation::kCollationCaseInSensitive,
67 nsCaseKey, val->mKey);
68 NS_ENSURE_SUCCESS(rv, rv);
69
70 aResult = val.release();
71
72 return NS_OK;
73 }
74
compareValues(txObject * aVal1,txObject * aVal2)75 int txResultStringComparator::compareValues(txObject* aVal1, txObject* aVal2) {
76 StringValue* strval1 = (StringValue*)aVal1;
77 StringValue* strval2 = (StringValue*)aVal2;
78
79 if (!mCollation) return -1;
80
81 if (strval1->mKey.Length() == 0) {
82 if (strval2->mKey.Length() == 0) return 0;
83 return ((mSorting & kAscending) ? -1 : 1);
84 }
85
86 if (strval2->mKey.Length() == 0) return ((mSorting & kAscending) ? 1 : -1);
87
88 nsresult rv;
89 int32_t result = -1;
90 rv = mCollation->CompareRawSortKey(strval1->mKey, strval2->mKey, &result);
91 if (NS_FAILED(rv)) {
92 // XXX ErrorReport
93 return -1;
94 }
95
96 if (result != 0) return ((mSorting & kAscending) ? 1 : -1) * result;
97
98 if (strval1->mCaseKeyString && strval1->mKey.Length() != 0) {
99 rv = strval1->initCaseKey(mCollation);
100 if (NS_FAILED(rv)) {
101 // XXX ErrorReport
102 return -1;
103 }
104 }
105 if (strval2->mCaseKeyString && strval2->mKey.Length() != 0) {
106 rv = strval2->initCaseKey(mCollation);
107 if (NS_FAILED(rv)) {
108 // XXX ErrorReport
109 return -1;
110 }
111 }
112 rv = mCollation->CompareRawSortKey(strval1->mCaseKey, strval2->mCaseKey,
113 &result);
114 if (NS_FAILED(rv)) {
115 // XXX ErrorReport
116 return -1;
117 }
118
119 return ((mSorting & kAscending) ? 1 : -1) *
120 ((mSorting & kUpperFirst) ? -1 : 1) * result;
121 }
122
123 txResultStringComparator::StringValue::StringValue() = default;
124
125 txResultStringComparator::StringValue::~StringValue() = default;
126
initCaseKey(nsICollation * aCollation)127 nsresult txResultStringComparator::StringValue::initCaseKey(
128 nsICollation* aCollation) {
129 nsresult rv = aCollation->AllocateRawSortKey(
130 nsICollation::kCollationCaseSensitive, *mCaseKeyString, mCaseKey);
131 if (NS_FAILED(rv)) {
132 mCaseKey.SetLength(0);
133 return rv;
134 }
135
136 mCaseKeyString = nullptr;
137 return NS_OK;
138 }
139
txResultNumberComparator(bool aAscending)140 txResultNumberComparator::txResultNumberComparator(bool aAscending) {
141 mAscending = aAscending ? 1 : -1;
142 }
143
createSortableValue(Expr * aExpr,txIEvalContext * aContext,txObject * & aResult)144 nsresult txResultNumberComparator::createSortableValue(Expr* aExpr,
145 txIEvalContext* aContext,
146 txObject*& aResult) {
147 UniquePtr<NumberValue> numval(new NumberValue);
148
149 RefPtr<txAExprResult> exprRes;
150 nsresult rv = aExpr->evaluate(aContext, getter_AddRefs(exprRes));
151 NS_ENSURE_SUCCESS(rv, rv);
152
153 numval->mVal = exprRes->numberValue();
154
155 aResult = numval.release();
156
157 return NS_OK;
158 }
159
compareValues(txObject * aVal1,txObject * aVal2)160 int txResultNumberComparator::compareValues(txObject* aVal1, txObject* aVal2) {
161 double dval1 = ((NumberValue*)aVal1)->mVal;
162 double dval2 = ((NumberValue*)aVal2)->mVal;
163
164 if (mozilla::IsNaN(dval1)) return mozilla::IsNaN(dval2) ? 0 : -mAscending;
165
166 if (mozilla::IsNaN(dval2)) return mAscending;
167
168 if (dval1 == dval2) return 0;
169
170 return (dval1 < dval2) ? -mAscending : mAscending;
171 }
172