1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtXmlPatterns module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qabstractduration_p.h"
41#include "qabstractdatetime_p.h"
42#include "qbase64binary_p.h"
43#include "qboolean_p.h"
44#include "qdynamiccontext_p.h"
45#include "qqnamevalue_p.h"
46
47#include "qatomiccomparators_p.h"
48
49QT_BEGIN_NAMESPACE
50
51using namespace QPatternist;
52
53/* -------------------------------------------------- */
54AtomicComparator::ComparisonResult
55StringComparator::compare(const Item &o1,
56 const AtomicComparator::Operator,
57 const Item &o2) const
58{
59 const int result = QString::compare(s1: o1.stringValue(), s2: o2.stringValue());
60
61 if(result > 0)
62 return GreaterThan;
63 else if(result < 0)
64 return LessThan;
65 else
66 {
67 Q_ASSERT(result == 0);
68 return Equal;
69 }
70}
71
72bool StringComparator::equals(const Item &o1,
73 const Item &o2) const
74{
75 return o1.stringValue() == o2.stringValue();
76}
77/* -------------------------------------------------- */
78
79/* -------------------------------------------------- */
80AtomicComparator::ComparisonResult
81CaseInsensitiveStringComparator::compare(const Item &o1,
82 const AtomicComparator::Operator,
83 const Item &o2) const
84{
85 const QString i1(o1.stringValue().toLower());
86 const QString i2(o2.stringValue().toLower());
87 const int result = QString::compare(s1: i1, s2: i2);
88
89 if(result > 0)
90 return GreaterThan;
91 else if(result < 0)
92 return LessThan;
93 else
94 {
95 Q_ASSERT(result == 0);
96 return Equal;
97 }
98}
99
100bool CaseInsensitiveStringComparator::equals(const Item &o1,
101 const Item &o2) const
102{
103 const QString s1(o1.stringValue());
104 const QString s2(o2.stringValue());
105
106 return s1.length() == s2.length() &&
107 s1.startsWith(s: s2, cs: Qt::CaseInsensitive);
108}
109/* -------------------------------------------------- */
110
111/* -------------------------------------------------- */
112bool BinaryDataComparator::equals(const Item &o1,
113 const Item &o2) const
114{
115 return o1.as<Base64Binary>()->asByteArray() ==
116 o2.as<Base64Binary>()->asByteArray();
117}
118/* -------------------------------------------------- */
119
120/* -------------------------------------------------- */
121AtomicComparator::ComparisonResult
122BooleanComparator::compare(const Item &o1,
123 const AtomicComparator::Operator,
124 const Item &o2) const
125{
126 /* We know Boolean::evaluateEBV doesn't use the DynamicContext. */
127 const bool v1 = o1.as<AtomicValue>()->evaluateEBV(context: QExplicitlySharedDataPointer<DynamicContext>());
128 const bool v2 = o2.as<AtomicValue>()->evaluateEBV(context: QExplicitlySharedDataPointer<DynamicContext>());
129
130 if(v1 == v2)
131 return Equal;
132 else if(v1 == false)
133 {
134 Q_ASSERT(v2 == true);
135 return LessThan;
136 }
137 else
138 {
139 Q_ASSERT(v1 == true && v2 == false);
140 return GreaterThan;
141 }
142}
143
144bool BooleanComparator::equals(const Item &o1,
145 const Item &o2) const
146{
147 /* Boolean is an atomic class. */
148 return o1.as<AtomicValue>() == o2.as<AtomicValue>();
149}
150/* -------------------------------------------------- */
151
152/* -------------------------------------------------- */
153AtomicComparator::ComparisonResult
154AbstractFloatComparator::compare(const Item &o1,
155 const AtomicComparator::Operator op,
156 const Item &o2) const
157{
158 const xsDouble v1 = o1.as<Numeric>()->toDouble();
159 const xsDouble v2 = o2.as<Numeric>()->toDouble();
160
161 if(Double::isEqual(a: v1, b: v2))
162 return Equal;
163 else if(v1 < v2)
164 return LessThan;
165 else if(v1 > v2)
166 return GreaterThan;
167 else
168 {
169 /* We have NaN values. Make sure we don't return a result which would
170 * signify success for the operator in question. */
171 if((op & OperatorGreaterThan) == OperatorGreaterThan)
172 return LessThan;
173 else
174 {
175 Q_ASSERT((op & OperatorLessThan) == OperatorLessThan);
176 return GreaterThan;
177 }
178 }
179}
180
181bool AbstractFloatComparator::equals(const Item &o1,
182 const Item &o2) const
183{
184 return Double::isEqual(a: o1.as<Numeric>()->toDouble(), b: o2.as<Numeric>()->toDouble());
185}
186/* -------------------------------------------------- */
187
188/* -------------------------------------------------- */
189AtomicComparator::ComparisonResult
190DecimalComparator::compare(const Item &o1,
191 const AtomicComparator::Operator,
192 const Item &o2) const
193{
194 const xsDecimal v1 = o1.as<Numeric>()->toDecimal();
195 const xsDecimal v2 = o2.as<Numeric>()->toDecimal();
196
197 if(Double::isEqual(a: v1, b: v2))
198 return Equal;
199 else if(v1 < v2)
200 return LessThan;
201 else
202 return GreaterThan;
203}
204
205bool DecimalComparator::equals(const Item &o1,
206 const Item &o2) const
207{
208 return Double::isEqual(a: o1.as<Numeric>()->toDecimal(), b: o2.as<Numeric>()->toDecimal());
209}
210/* -------------------------------------------------- */
211
212/* -------------------------------------------------- */
213AtomicComparator::ComparisonResult
214IntegerComparator::compare(const Item &o1,
215 const AtomicComparator::Operator,
216 const Item &o2) const
217{
218 const Numeric *const num1 = o1.as<Numeric>();
219 const Numeric *const num2 = o2.as<Numeric>();
220
221 /**
222 * Consider:
223 * xs:unsignedLong("100") > xs:unsignedLong("18446744073709551615")
224 *
225 * If we perform math on the values as if they were xsInteger, the right
226 * operand overflows, wraps around, and the expression evaluates to false.
227 * Hence we have this code to deal with it.
228 *
229 * This is runtime code, it would have been better if we had separate
230 * AtomicComparator classes for signed and unsigned values, but the changes
231 * required to the lookup code are extensive.
232 */
233 if(num1->isSigned() || num2->isSigned())
234 {
235 const xsInteger v1 = o1.as<Numeric>()->toInteger();
236 const xsInteger v2 = o2.as<Numeric>()->toInteger();
237
238 if(v1 == v2)
239 return Equal;
240 else if(v1 < v2)
241 return LessThan;
242 else
243 return GreaterThan;
244 }
245 else
246 {
247 const qulonglong v1 = o1.as<Numeric>()->toUnsignedInteger();
248 const qulonglong v2 = o2.as<Numeric>()->toUnsignedInteger();
249
250 if(v1 == v2)
251 return Equal;
252 else if(v1 < v2)
253 return LessThan;
254 else
255 return GreaterThan;
256 }
257}
258
259bool IntegerComparator::equals(const Item &o1,
260 const Item &o2) const
261{
262 return o1.as<Numeric>()->toInteger() == o2.as<Numeric>()->toInteger();
263}
264
265/* -------------------------------------------------- */
266
267/* -------------------------------------------------- */
268bool QNameComparator::equals(const Item &o1,
269 const Item &o2) const
270{
271 return o1.as<QNameValue>()->m_qName ==
272 o2.as<QNameValue>()->m_qName;
273}
274/* -------------------------------------------------- */
275
276/* -------------------------------------------------- */
277bool AbstractDateTimeComparator::equals(const Item &o1,
278 const Item &o2) const
279{
280 const QDateTime dt1(o1.as<AbstractDateTime>()->toDateTime());
281 const QDateTime dt2(o2.as<AbstractDateTime>()->toDateTime());
282
283 /*
284 pDebug() << "COMPARING:"
285 << o1->as<AbstractDateTime>()->toDateTime().toString()
286 << o2->as<AbstractDateTime>()->toDateTime().toString();
287 pDebug() << "DATE ONLY:"
288 << o1->as<AbstractDateTime>()->toDateTime().isDateOnly()
289 << o2->as<AbstractDateTime>()->toDateTime().isDateOnly();
290 */
291 return dt1 == dt2 &&
292 dt1.timeSpec() == dt2.timeSpec();
293}
294
295AtomicComparator::ComparisonResult
296AbstractDateTimeComparator::compare(const Item &operand1,
297 const AtomicComparator::Operator,
298 const Item &operand2) const
299{
300 const QDateTime &dt1 = operand1.as<AbstractDateTime>()->toDateTime();
301 const QDateTime &dt2 = operand2.as<AbstractDateTime>()->toDateTime();
302
303 if(dt1 == dt2)
304 return Equal;
305 else if(dt1 < dt2)
306 return LessThan;
307 else
308 return GreaterThan;
309}
310/* -------------------------------------------------- */
311
312/* -------------------------------------------------- */
313bool AbstractDurationComparator::equals(const Item &o1,
314 const Item &o2) const
315{
316 /* We use AbstractDuration::operator==() */
317 return *o1.as<AbstractDuration>() ==
318 *o2.as<AbstractDuration>();
319}
320
321QDateTime AbstractDurationComparator::addDurationToDateTime(const QDateTime &dateTime,
322 const AbstractDuration *const duration)
323{
324 QDateTime result(dateTime);
325 qint64 seconds = 0;
326
327 const qint8 signMultiplier = (duration->isPositive() ? 1 : -1);
328
329 result = result.addYears(years: signMultiplier * duration->years());
330 result = result.addMonths(months: signMultiplier * duration->months());
331 result = result.addDays(days: signMultiplier * duration->days());
332
333 seconds = 60 * 60 * duration->hours();
334 seconds += 60 * duration->minutes();
335 seconds += duration->seconds();
336
337 result = result.addSecs(secs: signMultiplier * seconds);
338 result = result.addMSecs(msecs: signMultiplier * duration->mseconds());
339
340 return result;
341}
342
343AtomicComparator::ComparisonResult
344AbstractDurationComparator::compare(const Item &o1,
345 const AtomicComparator::Operator,
346 const Item &o2) const
347{
348 const AbstractDuration *const duration = o1.as<AbstractDuration>();
349 const AbstractDuration *const otherDuration = o2.as<AbstractDuration>();
350
351 const QDateTime dateTime1(QDate(1696, 9, 1), QTime(0, 0, 0), Qt::UTC);
352 const QDateTime dateTime2(QDate(1697, 2, 1), QTime(0, 0, 0), Qt::UTC);
353 const QDateTime dateTime3(QDate(1903, 3, 1), QTime(0, 0, 0), Qt::UTC);
354 const QDateTime dateTime4(QDate(1903, 7, 1), QTime(0, 0, 0), Qt::UTC);
355
356 const QDateTime durationDateTime1 = addDurationToDateTime(dateTime: dateTime1, duration);
357 const QDateTime durationDateTime2 = addDurationToDateTime(dateTime: dateTime2, duration);
358 const QDateTime durationDateTime3 = addDurationToDateTime(dateTime: dateTime3, duration);
359 const QDateTime durationDateTime4 = addDurationToDateTime(dateTime: dateTime4, duration);
360
361 const QDateTime otherDurationDateTime1 = addDurationToDateTime(dateTime: dateTime1, duration: otherDuration);
362 const QDateTime otherDurationDateTime2 = addDurationToDateTime(dateTime: dateTime2, duration: otherDuration);
363 const QDateTime otherDurationDateTime3 = addDurationToDateTime(dateTime: dateTime3, duration: otherDuration);
364 const QDateTime otherDurationDateTime4 = addDurationToDateTime(dateTime: dateTime4, duration: otherDuration);
365
366 if (durationDateTime1 > otherDurationDateTime1 &&
367 durationDateTime2 > otherDurationDateTime2 &&
368 durationDateTime3 > otherDurationDateTime3 &&
369 durationDateTime4 > otherDurationDateTime4) {
370 return GreaterThan;
371 } else if (durationDateTime1 < otherDurationDateTime1 &&
372 durationDateTime2 < otherDurationDateTime2 &&
373 durationDateTime3 < otherDurationDateTime3 &&
374 durationDateTime4 < otherDurationDateTime4) {
375 return LessThan;
376 } else if (*duration == *otherDuration) {
377 return Equal;
378 } else {
379 return Incomparable;
380 }
381}
382
383/* -------------------------------------------------- */
384QT_END_NAMESPACE
385

source code of qtxmlpatterns/src/xmlpatterns/data/qatomiccomparators.cpp