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