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 : * The MITRE Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1999
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Keith Visco <kvisco@ziplink.net> (Original Author)
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either the GNU General Public License Version 2 or later (the "GPL"), or
27 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : #include "nsContentUtils.h"
40 : #include "txExpr.h"
41 : #include "txNodeSet.h"
42 : #include "txIXPathContext.h"
43 : #include "txXPathTreeWalker.h"
44 :
45 : /**
46 : * Compares the two ExprResults based on XPath 1.0 Recommendation (section 3.4)
47 : */
48 : bool
49 0 : RelationalExpr::compareResults(txIEvalContext* aContext, txAExprResult* aLeft,
50 : txAExprResult* aRight)
51 : {
52 0 : short ltype = aLeft->getResultType();
53 0 : short rtype = aRight->getResultType();
54 0 : nsresult rv = NS_OK;
55 :
56 : // Handle case for just Left NodeSet or Both NodeSets
57 0 : if (ltype == txAExprResult::NODESET) {
58 0 : if (rtype == txAExprResult::BOOLEAN) {
59 0 : BooleanResult leftBool(aLeft->booleanValue());
60 0 : return compareResults(aContext, &leftBool, aRight);
61 : }
62 :
63 0 : txNodeSet* nodeSet = static_cast<txNodeSet*>(aLeft);
64 0 : nsRefPtr<StringResult> strResult;
65 0 : rv = aContext->recycler()->getStringResult(getter_AddRefs(strResult));
66 0 : NS_ENSURE_SUCCESS(rv, false);
67 :
68 : PRInt32 i;
69 0 : for (i = 0; i < nodeSet->size(); ++i) {
70 0 : strResult->mValue.Truncate();
71 0 : txXPathNodeUtils::appendNodeValue(nodeSet->get(i),
72 0 : strResult->mValue);
73 0 : if (compareResults(aContext, strResult, aRight)) {
74 0 : return true;
75 : }
76 : }
77 :
78 0 : return false;
79 : }
80 :
81 : // Handle case for Just Right NodeSet
82 0 : if (rtype == txAExprResult::NODESET) {
83 0 : if (ltype == txAExprResult::BOOLEAN) {
84 0 : BooleanResult rightBool(aRight->booleanValue());
85 0 : return compareResults(aContext, aLeft, &rightBool);
86 : }
87 :
88 0 : txNodeSet* nodeSet = static_cast<txNodeSet*>(aRight);
89 0 : nsRefPtr<StringResult> strResult;
90 0 : rv = aContext->recycler()->getStringResult(getter_AddRefs(strResult));
91 0 : NS_ENSURE_SUCCESS(rv, false);
92 :
93 : PRInt32 i;
94 0 : for (i = 0; i < nodeSet->size(); ++i) {
95 0 : strResult->mValue.Truncate();
96 0 : txXPathNodeUtils::appendNodeValue(nodeSet->get(i),
97 0 : strResult->mValue);
98 0 : if (compareResults(aContext, aLeft, strResult)) {
99 0 : return true;
100 : }
101 : }
102 :
103 0 : return false;
104 : }
105 :
106 : // Neither is a NodeSet
107 0 : if (mOp == EQUAL || mOp == NOT_EQUAL) {
108 : bool result;
109 : const nsString *lString, *rString;
110 :
111 : // If either is a bool, compare as bools.
112 0 : if (ltype == txAExprResult::BOOLEAN ||
113 : rtype == txAExprResult::BOOLEAN) {
114 0 : result = aLeft->booleanValue() == aRight->booleanValue();
115 : }
116 :
117 : // If either is a number, compare as numbers.
118 0 : else if (ltype == txAExprResult::NUMBER ||
119 : rtype == txAExprResult::NUMBER) {
120 0 : double lval = aLeft->numberValue();
121 0 : double rval = aRight->numberValue();
122 0 : result = (lval == rval);
123 : }
124 :
125 : // Otherwise compare as strings. Try to use the stringobject in
126 : // StringResult if possible since that is a common case.
127 0 : else if ((lString = aLeft->stringValuePointer())) {
128 0 : if ((rString = aRight->stringValuePointer())) {
129 0 : result = lString->Equals(*rString);
130 : }
131 : else {
132 0 : nsAutoString rStr;
133 0 : aRight->stringValue(rStr);
134 0 : result = lString->Equals(rStr);
135 : }
136 : }
137 0 : else if ((rString = aRight->stringValuePointer())) {
138 0 : nsAutoString lStr;
139 0 : aLeft->stringValue(lStr);
140 0 : result = rString->Equals(lStr);
141 : }
142 : else {
143 0 : nsAutoString lStr, rStr;
144 0 : aLeft->stringValue(lStr);
145 0 : aRight->stringValue(rStr);
146 0 : result = lStr.Equals(rStr);
147 : }
148 :
149 0 : return mOp == EQUAL ? result : !result;
150 : }
151 :
152 0 : double leftDbl = aLeft->numberValue();
153 0 : double rightDbl = aRight->numberValue();
154 0 : switch (mOp) {
155 : case LESS_THAN:
156 : {
157 0 : return (leftDbl < rightDbl);
158 : }
159 : case LESS_OR_EQUAL:
160 : {
161 0 : return (leftDbl <= rightDbl);
162 : }
163 : case GREATER_THAN:
164 : {
165 0 : return (leftDbl > rightDbl);
166 : }
167 : case GREATER_OR_EQUAL:
168 : {
169 0 : return (leftDbl >= rightDbl);
170 : }
171 : default:
172 : {
173 0 : NS_NOTREACHED("We should have caught all cases");
174 : }
175 : }
176 :
177 0 : return false;
178 : }
179 :
180 : nsresult
181 0 : RelationalExpr::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
182 : {
183 0 : *aResult = nsnull;
184 0 : nsRefPtr<txAExprResult> lResult;
185 0 : nsresult rv = mLeftExpr->evaluate(aContext, getter_AddRefs(lResult));
186 0 : NS_ENSURE_SUCCESS(rv, rv);
187 :
188 0 : nsRefPtr<txAExprResult> rResult;
189 0 : rv = mRightExpr->evaluate(aContext, getter_AddRefs(rResult));
190 0 : NS_ENSURE_SUCCESS(rv, rv);
191 :
192 0 : aContext->recycler()->
193 0 : getBoolResult(compareResults(aContext, lResult, rResult), aResult);
194 :
195 0 : return NS_OK;
196 : }
197 :
198 0 : TX_IMPL_EXPR_STUBS_2(RelationalExpr, BOOLEAN_RESULT, mLeftExpr, mRightExpr)
199 :
200 : bool
201 0 : RelationalExpr::isSensitiveTo(ContextSensitivity aContext)
202 : {
203 0 : return mLeftExpr->isSensitiveTo(aContext) ||
204 0 : mRightExpr->isSensitiveTo(aContext);
205 : }
206 :
207 : #ifdef TX_TO_STRING
208 : void
209 0 : RelationalExpr::toString(nsAString& str)
210 : {
211 0 : mLeftExpr->toString(str);
212 :
213 0 : switch (mOp) {
214 : case NOT_EQUAL:
215 0 : str.AppendLiteral("!=");
216 0 : break;
217 : case LESS_THAN:
218 0 : str.Append(PRUnichar('<'));
219 0 : break;
220 : case LESS_OR_EQUAL:
221 0 : str.AppendLiteral("<=");
222 0 : break;
223 : case GREATER_THAN :
224 0 : str.Append(PRUnichar('>'));
225 0 : break;
226 : case GREATER_OR_EQUAL:
227 0 : str.AppendLiteral(">=");
228 0 : break;
229 : default:
230 0 : str.Append(PRUnichar('='));
231 0 : break;
232 : }
233 :
234 0 : mRightExpr->toString(str);
235 0 : }
236 : #endif
|