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 <QtMath>
41
42#include "qxsdtypechecker_p.h"
43
44#include "qabstractdatetime_p.h"
45#include "qbase64binary_p.h"
46#include "qboolean_p.h"
47#include "qdecimal_p.h"
48#include "qderivedinteger_p.h"
49#include "qduration_p.h"
50#include "qgenericstaticcontext_p.h"
51#include "qhexbinary_p.h"
52#include "qnamespaceresolver_p.h"
53#include "qpatternplatform_p.h"
54#include "qqnamevalue_p.h"
55#include "qvaluefactory_p.h"
56#include "qxmlnamepool.h"
57#include "qxsdschemahelper_p.h"
58#include "qxsdschemamerger_p.h"
59#include "qxsdstatemachine_p.h"
60
61#include "qxsdschemadebugger_p.h"
62
63QT_BEGIN_NAMESPACE
64
65using namespace QPatternist;
66
67XsdSchemaSourceLocationReflection::XsdSchemaSourceLocationReflection(const QSourceLocation &location)
68 : m_sourceLocation(location)
69{
70}
71
72const SourceLocationReflection* XsdSchemaSourceLocationReflection::actualReflection() const
73{
74 return this;
75}
76
77QSourceLocation XsdSchemaSourceLocationReflection::sourceLocation() const
78{
79 return m_sourceLocation;
80}
81
82
83static AnySimpleType::Ptr comparableType(const AnySimpleType::Ptr &type)
84{
85 if (!type->isDefinedBySchema()) {
86 return type;
87 } else {
88 const XsdSimpleType::Ptr simpleType(type);
89 if (type->category() == SchemaType::SimpleTypeAtomic) {
90 return simpleType->primitiveType();
91 } else if (type->category() == SchemaType::SimpleTypeList) {
92 return simpleType->itemType();
93 } else if (type->category() == SchemaType::SimpleTypeUnion) {
94 return simpleType->memberTypes().first();
95 }
96 }
97
98 Q_ASSERT(false);
99 return AnySimpleType::Ptr();
100}
101
102static int totalDigitsForSignedLongLong(long long value)
103{
104 QString number = QString::number(value);
105 if (number.startsWith(c: QLatin1Char('-')))
106 number = number.mid(position: 1);
107
108 return number.length();
109}
110
111static int totalDigitsForUnsignedLongLong(unsigned long long value)
112{
113 const QString number = QString::number(value);
114 return number.length();
115}
116
117static int totalDigitsForDecimal(const QString &lexicalValue)
118{
119 const QLatin1Char zeroChar('0');
120 const int length = lexicalValue.length() - 1;
121
122 // strip leading zeros
123 int pos = 0;
124 while (lexicalValue.at(i: pos) == zeroChar && (pos != length))
125 pos++;
126
127 QString value = lexicalValue.mid(position: pos);
128
129 // if contains '.' strip trailing zeros
130 if (value.contains(c: QLatin1Char('.'))) {
131 pos = value.length() - 1;
132 while (value.at(i: pos) == zeroChar) {
133 pos--;
134 }
135
136 value = value.left(n: pos + 1);
137 }
138
139 // check number of digits of remaining string
140 int totalDigits = 0;
141 for (int i = 0; i < value.count(); ++i)
142 if (value.at(i).isDigit())
143 ++totalDigits;
144
145 if (totalDigits == 0)
146 totalDigits = 1;
147
148 return totalDigits;
149}
150
151static int fractionDigitsForDecimal(const QString &lexicalValue)
152{
153 const int pos = lexicalValue.indexOf(c: QLatin1Char('.'));
154 if (pos == -1)
155 return 0;
156 const QStringRef fraction = QStringRef(&lexicalValue).mid(pos).trimmed();
157 int i = fraction.length() - 1; // fraction[0] is '.' so fraction is not empty
158 while (fraction.at(i) == QLatin1Char('0'))
159 --i;
160 return i; // The significant fraction-digits are fraction[1 through i].
161}
162
163XsdTypeChecker::XsdTypeChecker(const XsdSchemaContext::Ptr &context, const QVector<QXmlName> &namespaceBindings, const QSourceLocation &location)
164 : m_context(context)
165 , m_namePool(m_context->namePool())
166 , m_namespaceBindings(namespaceBindings)
167 , m_reflection(new XsdSchemaSourceLocationReflection(location))
168{
169}
170
171XsdTypeChecker::~XsdTypeChecker()
172{
173 delete m_reflection;
174}
175
176QString XsdTypeChecker::normalizedValue(const QString &value, const XsdFacet::Hash &facets)
177{
178 if (!facets.contains(akey: XsdFacet::WhiteSpace))
179 return value;
180
181 const XsdFacet::Ptr whiteSpaceFacet = facets.value(akey: XsdFacet::WhiteSpace);
182
183 const DerivedString<TypeString>::Ptr facetValue = whiteSpaceFacet->value();
184 const QString stringValue = facetValue->stringValue();
185 if (stringValue == XsdSchemaToken::toString(token: XsdSchemaToken::Preserve))
186 return value;
187 else if (stringValue == XsdSchemaToken::toString(token: XsdSchemaToken::Replace)) {
188 QString newValue(value);
189 newValue.replace(before: QLatin1Char('\t'), after: QLatin1Char(' '));
190 newValue.replace(before: QLatin1Char('\n'), after: QLatin1Char(' '));
191 newValue.replace(before: QLatin1Char('\r'), after: QLatin1Char(' '));
192
193 return newValue;
194 } else if (stringValue == XsdSchemaToken::toString(token: XsdSchemaToken::Collapse)) {
195 return value.simplified();
196 }
197
198 return value;
199}
200
201XsdFacet::Hash XsdTypeChecker::mergedFacetsForType(const SchemaType::Ptr &type, const XsdSchemaContext::Ptr &context)
202{
203 if (!type)
204 return XsdFacet::Hash();
205
206 const XsdFacet::Hash baseFacets = mergedFacetsForType(type: type->wxsSuperType(), context);
207 const XsdFacet::Hash facets = context->facetsForType(type);
208
209 XsdFacet::Hash result = baseFacets;
210 for (auto it = facets.cbegin(), end = facets.cend(); it != end; ++it)
211 result.insert(akey: it.key(), avalue: it.value());
212
213 return result;
214}
215
216bool XsdTypeChecker::isValidString(const QString &normalizedString, const AnySimpleType::Ptr &type, QString &errorMsg, AnySimpleType::Ptr *boundType) const
217{
218 if (type->name(np: m_namePool) == BuiltinTypes::xsAnySimpleType->name(np: m_namePool)) {
219 if (boundType)
220 *boundType = type;
221
222 return true;
223 }
224
225 if (!type->isDefinedBySchema()) {
226 // special QName check
227 if (BuiltinTypes::xsQName->wxsTypeMatches(other: type)) {
228 if (!XPathHelper::isQName(qName: normalizedString)) {
229 errorMsg = QtXmlPatterns::tr(sourceText: "%1 is not valid according to %2.").arg(a: formatData(data: normalizedString)).arg(a: formatType(np: m_namePool, type));
230 return false;
231 }
232 }
233
234 const AtomicValue::Ptr value = fromLexical(value: normalizedString, type, context: m_context, reflection: m_reflection);
235 if (value->hasError()) {
236 errorMsg = QtXmlPatterns::tr(sourceText: "%1 is not valid according to %2.").arg(a: formatData(data: normalizedString)).arg(a: formatType(np: m_namePool, type));
237 return false;
238 }
239
240 if (!checkConstrainingFacets(value, lexicalValue: normalizedString, type, errorMsg)) {
241 return false;
242 }
243
244 if (boundType)
245 *boundType = type;
246
247 } else {
248 const XsdSimpleType::Ptr simpleType(type);
249
250 if (simpleType->category() == XsdSimpleType::SimpleTypeAtomic) {
251 AnySimpleType::Ptr targetType = simpleType->primitiveType();
252 if (!simpleType->wxsSuperType()->isDefinedBySchema())
253 targetType = simpleType->wxsSuperType();
254
255 const AtomicValue::Ptr value = fromLexical(value: normalizedString, type: targetType, context: m_context, reflection: m_reflection);
256 if (value->hasError()) {
257 errorMsg = QtXmlPatterns::tr(sourceText: "%1 is not valid according to %2.").arg(a: formatData(data: normalizedString)).arg(a: formatType(np: m_namePool, type: targetType));
258 return false;
259 }
260
261 if (!checkConstrainingFacets(value, lexicalValue: normalizedString, type, errorMsg)) {
262 return false;
263 }
264
265 if (boundType)
266 *boundType = type;
267
268 } else if (simpleType->category() == XsdSimpleType::SimpleTypeList) {
269 QStringList entries = normalizedString.split(sep: QLatin1Char(' '), behavior: Qt::SkipEmptyParts);
270 for (int i = 0; i < entries.count(); ++i) {
271 entries[i] = normalizedValue(value: entries.at(i), facets: mergedFacetsForType(type: simpleType->itemType(), context: m_context));
272 }
273
274 if (!checkConstrainingFacetsList(values: entries, lexicalValue: normalizedString, itemType: simpleType->itemType(), facets: mergedFacetsForType(type: simpleType, context: m_context), errorMsg)) {
275 return false;
276 }
277
278 for (int i = 0; i < entries.count(); ++i) {
279 if (!isValidString(normalizedString: entries.at(i), type: simpleType->itemType(), errorMsg)) {
280 return false;
281 }
282 }
283
284 if (boundType)
285 *boundType = simpleType->itemType();
286
287 } else if (simpleType->category() == XsdSimpleType::SimpleTypeUnion) {
288 if (!checkConstrainingFacetsUnion(value: normalizedString, lexicalValue: normalizedString, simpleType, facets: mergedFacetsForType(type: simpleType, context: m_context), errorMsg)) {
289 return false;
290 }
291
292 const AnySimpleType::List memberTypes = simpleType->memberTypes();
293
294 bool foundValidType = false;
295 for (int i = 0; i < memberTypes.count(); ++i) {
296 const XsdFacet::Hash mergedFacets = mergedFacetsForType(type: memberTypes.at(i), context: m_context);
297 if (isValidString(normalizedString: normalizedValue(value: normalizedString, facets: mergedFacets), type: memberTypes.at(i), errorMsg)) {
298 foundValidType = true;
299
300 if (boundType)
301 *boundType = memberTypes.at(i);
302
303 break;
304 }
305 }
306
307 if (!foundValidType) {
308 return false;
309 }
310 }
311 }
312
313 return true;
314}
315
316bool XsdTypeChecker::valuesAreEqual(const QString &value, const QString &otherValue, const AnySimpleType::Ptr &type) const
317{
318 const AnySimpleType::Ptr targetType = comparableType(type);
319
320 // if the type is xs:anySimpleType we just do string comparison...
321 if (targetType->name(np: m_namePool) == BuiltinTypes::xsAnySimpleType->name(np: m_namePool))
322 return (value == otherValue);
323
324 if (BuiltinTypes::xsQName->wxsTypeMatches(other: type)) {
325 const QXmlName valueName = convertToQName(name: value);
326 const QXmlName otherValueName = convertToQName(name: otherValue);
327
328 if (valueName == otherValueName)
329 return true;
330 }
331
332 if (type->category() == SchemaType::SimpleTypeAtomic) {
333 // ... otherwise we use the casting platform for value comparison
334 const DerivedString<TypeString>::Ptr valueStr = DerivedString<TypeString>::fromLexical(np: m_namePool, lexical: value);
335 const DerivedString<TypeString>::Ptr otherValueStr = DerivedString<TypeString>::fromLexical(np: m_namePool, lexical: otherValue);
336
337 return XsdSchemaHelper::constructAndCompare(operand1: valueStr, op: AtomicComparator::OperatorEqual, operand2: otherValueStr, type: targetType, context: m_context, sourceLocationReflection: m_reflection);
338 } else if (type->category() == SchemaType::SimpleTypeList) {
339 const QStringList values = value.split(sep: QLatin1Char(' '), behavior: Qt::SkipEmptyParts);
340 const QStringList otherValues = otherValue.split(sep: QLatin1Char(' '), behavior: Qt::SkipEmptyParts);
341 if (values.count() != otherValues.count())
342 return false;
343
344 for (int i = 0; i < values.count(); ++i) {
345 if (!valuesAreEqual(value: values.at(i), otherValue: otherValues.at(i), type: XsdSimpleType::Ptr(type)->itemType()))
346 return false;
347 }
348
349 return true;
350 } else if (type->category() == SchemaType::SimpleTypeUnion) {
351 const AnySimpleType::List memberTypes = XsdSimpleType::Ptr(type)->memberTypes();
352 for (int i = 0; i < memberTypes.count(); ++i) {
353 if (valuesAreEqual(value, otherValue, type: memberTypes.at(i))) {
354 return true;
355 }
356 }
357
358 return false;
359 }
360
361 return false;
362}
363
364bool XsdTypeChecker::checkConstrainingFacets(const AtomicValue::Ptr &value, const QString &lexicalValue, const AnySimpleType::Ptr &type, QString &errorMsg) const
365{
366 const XsdFacet::Hash facets = mergedFacetsForType(type, context: m_context);
367
368 if (BuiltinTypes::xsString->wxsTypeMatches(other: type) ||
369 BuiltinTypes::xsUntypedAtomic->wxsTypeMatches(other: type)) {
370 return checkConstrainingFacetsString(value: value->stringValue(), facets, type: BuiltinTypes::xsString, errorMsg);
371 } else if (BuiltinTypes::xsAnyURI->wxsTypeMatches(other: type)) {
372 return checkConstrainingFacetsString(value: value->stringValue(), facets, type: BuiltinTypes::xsAnyURI, errorMsg);
373 } else if (BuiltinTypes::xsNOTATION->wxsTypeMatches(other: type)) {
374 return checkConstrainingFacetsNotation(value: value->as<QNameValue>()->qName(), facets, errorMsg);
375 } else if (BuiltinTypes::xsUnsignedByte->wxsTypeMatches(other: type) ||
376 BuiltinTypes::xsUnsignedInt->wxsTypeMatches(other: type) ||
377 BuiltinTypes::xsUnsignedLong->wxsTypeMatches(other: type) ||
378 BuiltinTypes::xsUnsignedShort->wxsTypeMatches(other: type)) {
379 return checkConstrainingFacetsUnsignedInteger(value: value->as<Numeric>()->toUnsignedInteger(), lexicalValue, facets, errorMsg);
380 } else if (BuiltinTypes::xsInteger->wxsTypeMatches(other: type)) {
381 return checkConstrainingFacetsSignedInteger(value: value->as<Numeric>()->toInteger(), lexicalValue, facets, errorMsg);
382 } else if (BuiltinTypes::xsFloat->wxsTypeMatches(other: type) ||
383 BuiltinTypes::xsDouble->wxsTypeMatches(other: type)) {
384 return checkConstrainingFacetsDouble(value: value->as<Numeric>()->toDouble(), lexicalValue, facets, errorMsg);
385 } else if (BuiltinTypes::xsDecimal->wxsTypeMatches(other: type)) {
386 return checkConstrainingFacetsDecimal(value, lexicalValue, facets, errorMsg);
387 } else if (BuiltinTypes::xsDateTime->wxsTypeMatches(other: type)) {
388 return checkConstrainingFacetsDateTime(value: value->as<AbstractDateTime>()->toDateTime(), lexicalValue, facets, type: BuiltinTypes::xsDateTime, errorMsg);
389 } else if (BuiltinTypes::xsDate->wxsTypeMatches(other: type)) {
390 return checkConstrainingFacetsDateTime(value: value->as<AbstractDateTime>()->toDateTime(), lexicalValue, facets, type: BuiltinTypes::xsDate, errorMsg);
391 } else if (BuiltinTypes::xsGYear->wxsTypeMatches(other: type)) {
392 return checkConstrainingFacetsDateTime(value: value->as<AbstractDateTime>()->toDateTime(), lexicalValue, facets, type: BuiltinTypes::xsGYear, errorMsg);
393 } else if (BuiltinTypes::xsGYearMonth->wxsTypeMatches(other: type)) {
394 return checkConstrainingFacetsDateTime(value: value->as<AbstractDateTime>()->toDateTime(), lexicalValue, facets, type: BuiltinTypes::xsGYearMonth, errorMsg);
395 } else if (BuiltinTypes::xsGMonth->wxsTypeMatches(other: type)) {
396 return checkConstrainingFacetsDateTime(value: value->as<AbstractDateTime>()->toDateTime(), lexicalValue, facets, type: BuiltinTypes::xsGMonth, errorMsg);
397 } else if (BuiltinTypes::xsGMonthDay->wxsTypeMatches(other: type)) {
398 return checkConstrainingFacetsDateTime(value: value->as<AbstractDateTime>()->toDateTime(), lexicalValue, facets, type: BuiltinTypes::xsGMonthDay, errorMsg);
399 } else if (BuiltinTypes::xsGDay->wxsTypeMatches(other: type)) {
400 return checkConstrainingFacetsDateTime(value: value->as<AbstractDateTime>()->toDateTime(), lexicalValue, facets, type: BuiltinTypes::xsGDay, errorMsg);
401 } else if (BuiltinTypes::xsTime->wxsTypeMatches(other: type)) {
402 return checkConstrainingFacetsDateTime(value: value->as<AbstractDateTime>()->toDateTime(), lexicalValue, facets, type: BuiltinTypes::xsTime, errorMsg);
403 } else if (BuiltinTypes::xsDuration->wxsTypeMatches(other: type)) {
404 return checkConstrainingFacetsDuration(value, lexicalValue, facets, errorMsg);
405 } else if (BuiltinTypes::xsBoolean->wxsTypeMatches(other: type)) {
406 return checkConstrainingFacetsBoolean(value: value->as<Boolean>()->value(), lexicalValue, facets, errorMsg);
407 } else if (BuiltinTypes::xsHexBinary->wxsTypeMatches(other: type)) {
408 return checkConstrainingFacetsBinary(value: value->as<Base64Binary>()->asByteArray(), facets, type: BuiltinTypes::xsHexBinary, errorMsg);
409 } else if (BuiltinTypes::xsBase64Binary->wxsTypeMatches(other: type)) {
410 return checkConstrainingFacetsBinary(value: value->as<Base64Binary>()->asByteArray(), facets, type: BuiltinTypes::xsBase64Binary, errorMsg);
411 } else if (BuiltinTypes::xsQName->wxsTypeMatches(other: type)) {
412 return checkConstrainingFacetsQName(value->as<QNameValue>()->qName(), lexicalValue, facets, errorMsg);
413 }
414
415 return true;
416}
417
418bool XsdTypeChecker::checkConstrainingFacetsString(const QString &value, const XsdFacet::Hash &facets, const AnySimpleType::Ptr &type, QString &errorMsg) const
419{
420 if (facets.contains(akey: XsdFacet::Length)) {
421 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::Length);
422 const DerivedInteger<TypeNonNegativeInteger>::Ptr length = facet->value();
423 if (length->toInteger() != value.length()) {
424 errorMsg = QtXmlPatterns::tr(sourceText: "String content does not match the length facet.");
425 return false;
426 }
427 }
428 if (facets.contains(akey: XsdFacet::MinimumLength)) {
429 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::MinimumLength);
430 const DerivedInteger<TypeNonNegativeInteger>::Ptr length = facet->value();
431 if (length->toInteger() > value.length()) {
432 errorMsg = QtXmlPatterns::tr(sourceText: "String content does not match the minLength facet.");
433 return false;
434 }
435 }
436 if (facets.contains(akey: XsdFacet::MaximumLength)) {
437 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::MaximumLength);
438 const DerivedInteger<TypeNonNegativeInteger>::Ptr length = facet->value();
439 if (length->toInteger() < value.length()) {
440 errorMsg = QtXmlPatterns::tr(sourceText: "String content does not match the maxLength facet.");
441 return false;
442 }
443 }
444 if (facets.contains(akey: XsdFacet::Pattern)) {
445 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::Pattern);
446 const AtomicValue::List multiValue = facet->multiValue();
447 bool found = false;
448 for (int j = 0; j < multiValue.count(); ++j) {
449 const QString pattern = multiValue.at(i: j)->as<DerivedString<TypeString> >()->stringValue();
450 QRegExp exp = PatternPlatform::parsePattern(pattern, context: m_context, location: m_reflection);
451 if (exp.exactMatch(str: value)) {
452 found = true;
453 break;
454 }
455 }
456
457 if (!found) {
458 errorMsg = QtXmlPatterns::tr(sourceText: "String content does not match pattern facet.");
459 return false;
460 }
461 }
462 if (facets.contains(akey: XsdFacet::Enumeration)) {
463 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::Enumeration);
464 const DerivedString<TypeString>::Ptr valueStr = DerivedString<TypeString>::fromLexical(np: m_namePool, lexical: value);
465
466 const AtomicValue::List multiValue = facet->multiValue();
467 bool found = false;
468 for (int j = 0; j < multiValue.count(); ++j) {
469 if (XsdSchemaHelper::constructAndCompare(operand1: valueStr, op: AtomicComparator::OperatorEqual, operand2: multiValue.at(i: j), type, context: m_context, sourceLocationReflection: m_reflection)) {
470 found = true;
471 break;
472 }
473 }
474
475 if (!found) {
476 errorMsg = QtXmlPatterns::tr(sourceText: "String content is not listed in the enumeration facet.");
477 return false;
478 }
479 }
480 if (facets.contains(akey: XsdFacet::Assertion)) {
481 //TODO: implement
482 }
483
484 return true;
485}
486
487bool XsdTypeChecker::checkConstrainingFacetsSignedInteger(long long value, const QString &lexicalValue, const XsdFacet::Hash &facets, QString &errorMsg) const
488{
489 if (facets.contains(akey: XsdFacet::MaximumInclusive)) {
490 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::MaximumInclusive);
491 const Numeric::Ptr facetValue = ValueFactory::fromLexical(lexicalValue: facet->value()->as<DerivedString<TypeString> >()->stringValue(), type: BuiltinTypes::xsLong, context: m_context, sourceLocationReflection: m_reflection);
492 if (facetValue->toInteger() < value) {
493 errorMsg = QtXmlPatterns::tr(sourceText: "Signed integer content does not match the maxInclusive facet.");
494 return false;
495 }
496 }
497 if (facets.contains(akey: XsdFacet::MaximumExclusive)) {
498 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::MaximumExclusive);
499 const Numeric::Ptr facetValue = ValueFactory::fromLexical(lexicalValue: facet->value()->as<DerivedString<TypeString> >()->stringValue(), type: BuiltinTypes::xsLong, context: m_context, sourceLocationReflection: m_reflection);
500 if (facetValue->toInteger() <= value) {
501 errorMsg = QtXmlPatterns::tr(sourceText: "Signed integer content does not match the maxExclusive facet.");
502 return false;
503 }
504 }
505 if (facets.contains(akey: XsdFacet::MinimumInclusive)) {
506 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::MinimumInclusive);
507 const Numeric::Ptr facetValue = ValueFactory::fromLexical(lexicalValue: facet->value()->as<DerivedString<TypeString> >()->stringValue(), type: BuiltinTypes::xsLong, context: m_context, sourceLocationReflection: m_reflection);
508 if (facetValue->toInteger() > value) {
509 errorMsg = QtXmlPatterns::tr(sourceText: "Signed integer content does not match the minInclusive facet.");
510 return false;
511 }
512 }
513 if (facets.contains(akey: XsdFacet::MinimumExclusive)) {
514 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::MinimumExclusive);
515 const Numeric::Ptr facetValue = ValueFactory::fromLexical(lexicalValue: facet->value()->as<DerivedString<TypeString> >()->stringValue(), type: BuiltinTypes::xsLong, context: m_context, sourceLocationReflection: m_reflection);
516 if (facetValue->toInteger() >= value) {
517 errorMsg = QtXmlPatterns::tr(sourceText: "Signed integer content does not match the minExclusive facet.");
518 return false;
519 }
520 }
521 if (facets.contains(akey: XsdFacet::Enumeration)) {
522 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::Enumeration);
523 const DerivedString<TypeString>::Ptr valueStr = DerivedString<TypeString>::fromLexical(np: m_namePool, lexical: QString::number(value));
524
525 const AtomicValue::List multiValue = facet->multiValue();
526 bool found = false;
527 for (int j = 0; j < multiValue.count(); ++j) {
528 if (XsdSchemaHelper::constructAndCompare(operand1: valueStr, op: AtomicComparator::OperatorEqual, operand2: multiValue.at(i: j), type: BuiltinTypes::xsLong, context: m_context, sourceLocationReflection: m_reflection)) {
529 found = true;
530 break;
531 }
532 }
533
534 if (!found) {
535 errorMsg = QtXmlPatterns::tr(sourceText: "Signed integer content is not listed in the enumeration facet.");
536 return false;
537 }
538 }
539 if (facets.contains(akey: XsdFacet::Pattern)) {
540 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::Pattern);
541 const AtomicValue::List multiValue = facet->multiValue();
542 bool found = false;
543 for (int j = 0; j < multiValue.count(); ++j) {
544 const QString pattern = multiValue.at(i: j)->as<DerivedString<TypeString> >()->stringValue();
545 QRegExp exp = PatternPlatform::parsePattern(pattern, context: m_context, location: m_reflection);
546 if (exp.exactMatch(str: lexicalValue)) {
547 found = true;
548 break;
549 }
550 }
551
552 if (!found) {
553 errorMsg = QtXmlPatterns::tr(sourceText: "Signed integer content does not match pattern facet.");
554 return false;
555 }
556 }
557 if (facets.contains(akey: XsdFacet::TotalDigits)) {
558 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::TotalDigits);
559 const DerivedInteger<TypePositiveInteger>::Ptr facetValue = facet->value();
560
561 if (totalDigitsForSignedLongLong(value) > facetValue->toInteger()) {
562 errorMsg = QtXmlPatterns::tr(sourceText: "Signed integer content does not match in the totalDigits facet.");
563 return false;
564 }
565 }
566 if (facets.contains(akey: XsdFacet::Assertion)) {
567 //TODO: implement
568 }
569
570 return true;
571}
572
573bool XsdTypeChecker::checkConstrainingFacetsUnsignedInteger(unsigned long long value, const QString &lexicalValue, const XsdFacet::Hash &facets, QString &errorMsg) const
574{
575 if (facets.contains(akey: XsdFacet::MaximumInclusive)) {
576 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::MaximumInclusive);
577 const Numeric::Ptr facetValue = ValueFactory::fromLexical(lexicalValue: facet->value()->as<DerivedString<TypeString> >()->stringValue(), type: BuiltinTypes::xsUnsignedLong, context: m_context, sourceLocationReflection: m_reflection);
578 if (facetValue->toUnsignedInteger() < value) {
579 errorMsg = QtXmlPatterns::tr(sourceText: "Unsigned integer content does not match the maxInclusive facet.");
580 return false;
581 }
582 }
583 if (facets.contains(akey: XsdFacet::MaximumExclusive)) {
584 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::MaximumExclusive);
585 const Numeric::Ptr facetValue = ValueFactory::fromLexical(lexicalValue: facet->value()->as<DerivedString<TypeString> >()->stringValue(), type: BuiltinTypes::xsUnsignedLong, context: m_context, sourceLocationReflection: m_reflection);
586 if (facetValue->toUnsignedInteger() <= value) {
587 errorMsg = QtXmlPatterns::tr(sourceText: "Unsigned integer content does not match the maxExclusive facet.");
588 return false;
589 }
590 }
591 if (facets.contains(akey: XsdFacet::MinimumInclusive)) {
592 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::MinimumInclusive);
593 const Numeric::Ptr facetValue = ValueFactory::fromLexical(lexicalValue: facet->value()->as<DerivedString<TypeString> >()->stringValue(), type: BuiltinTypes::xsUnsignedLong, context: m_context, sourceLocationReflection: m_reflection);
594 if (facetValue->toUnsignedInteger() > value) {
595 errorMsg = QtXmlPatterns::tr(sourceText: "Unsigned integer content does not match the minInclusive facet.");
596 return false;
597 }
598 }
599 if (facets.contains(akey: XsdFacet::MinimumExclusive)) {
600 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::MinimumExclusive);
601 const Numeric::Ptr facetValue = ValueFactory::fromLexical(lexicalValue: facet->value()->as<DerivedString<TypeString> >()->stringValue(), type: BuiltinTypes::xsUnsignedLong, context: m_context, sourceLocationReflection: m_reflection);
602 if (facetValue->toUnsignedInteger() >= value) {
603 errorMsg = QtXmlPatterns::tr(sourceText: "Unsigned integer content does not match the minExclusive facet.");
604 return false;
605 }
606 }
607 if (facets.contains(akey: XsdFacet::Enumeration)) {
608 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::Enumeration);
609 const DerivedString<TypeString>::Ptr valueStr = DerivedString<TypeString>::fromLexical(np: m_namePool, lexical: QString::number(value));
610
611 const AtomicValue::List multiValue = facet->multiValue();
612 bool found = false;
613 for (int j = 0; j < multiValue.count(); ++j) {
614 if (XsdSchemaHelper::constructAndCompare(operand1: valueStr, op: AtomicComparator::OperatorEqual, operand2: multiValue.at(i: j), type: BuiltinTypes::xsUnsignedLong, context: m_context, sourceLocationReflection: m_reflection)) {
615 found = true;
616 break;
617 }
618 }
619
620 if (!found) {
621 errorMsg = QtXmlPatterns::tr(sourceText: "Unsigned integer content is not listed in the enumeration facet.");
622 return false;
623 }
624 }
625 if (facets.contains(akey: XsdFacet::Pattern)) {
626 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::Pattern);
627 const AtomicValue::List multiValue = facet->multiValue();
628 bool found = false;
629 for (int j = 0; j < multiValue.count(); ++j) {
630 const QString pattern = multiValue.at(i: j)->as<DerivedString<TypeString> >()->stringValue();
631 QRegExp exp = PatternPlatform::parsePattern(pattern, context: m_context, location: m_reflection);
632 if (exp.exactMatch(str: lexicalValue)) {
633 found = true;
634 break;
635 }
636 }
637
638 if (!found) {
639 errorMsg = QtXmlPatterns::tr(sourceText: "Unsigned integer content does not match pattern facet.");
640 return false;
641 }
642 }
643 if (facets.contains(akey: XsdFacet::TotalDigits)) {
644 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::TotalDigits);
645 const DerivedInteger<TypePositiveInteger>::Ptr facetValue = facet->value();
646
647 if (totalDigitsForUnsignedLongLong(value) > facetValue->toInteger()) {
648 errorMsg = QtXmlPatterns::tr(sourceText: "Unsigned integer content does not match in the totalDigits facet.");
649 return false;
650 }
651 }
652 if (facets.contains(akey: XsdFacet::Assertion)) {
653 //TODO: implement
654 }
655
656 return true;
657}
658
659bool XsdTypeChecker::checkConstrainingFacetsDouble(double value, const QString &lexicalValue, const XsdFacet::Hash &facets, QString &errorMsg) const
660{
661 if (facets.contains(akey: XsdFacet::MaximumInclusive)) {
662 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::MaximumInclusive);
663 const Numeric::Ptr facetValue = ValueFactory::fromLexical(lexicalValue: facet->value()->as<DerivedString<TypeString> >()->stringValue(), type: BuiltinTypes::xsDouble, context: m_context, sourceLocationReflection: m_reflection);
664 if (facetValue->toDouble() < value) {
665 errorMsg = QtXmlPatterns::tr(sourceText: "Double content does not match the maxInclusive facet.");
666 return false;
667 }
668 }
669 if (facets.contains(akey: XsdFacet::MaximumExclusive)) {
670 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::MaximumExclusive);
671 const Numeric::Ptr facetValue = ValueFactory::fromLexical(lexicalValue: facet->value()->as<DerivedString<TypeString> >()->stringValue(), type: BuiltinTypes::xsDouble, context: m_context, sourceLocationReflection: m_reflection);
672 if (facetValue->toDouble() <= value) {
673 errorMsg = QtXmlPatterns::tr(sourceText: "Double content does not match the maxExclusive facet.");
674 return false;
675 }
676 }
677 if (facets.contains(akey: XsdFacet::MinimumInclusive)) {
678 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::MinimumInclusive);
679 const Numeric::Ptr facetValue = ValueFactory::fromLexical(lexicalValue: facet->value()->as<DerivedString<TypeString> >()->stringValue(), type: BuiltinTypes::xsDouble, context: m_context, sourceLocationReflection: m_reflection);
680 if (facetValue->toDouble() > value) {
681 errorMsg = QtXmlPatterns::tr(sourceText: "Double content does not match the minInclusive facet.");
682 return false;
683 }
684 }
685 if (facets.contains(akey: XsdFacet::MinimumExclusive)) {
686 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::MinimumExclusive);
687 const Numeric::Ptr facetValue = ValueFactory::fromLexical(lexicalValue: facet->value()->as<DerivedString<TypeString> >()->stringValue(), type: BuiltinTypes::xsDouble, context: m_context, sourceLocationReflection: m_reflection);
688 if (facetValue->toDouble() >= value) {
689 errorMsg = QtXmlPatterns::tr(sourceText: "Double content does not match the minExclusive facet.");
690 return false;
691 }
692 }
693 if (facets.contains(akey: XsdFacet::Enumeration)) {
694 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::Enumeration);
695 const DerivedString<TypeString>::Ptr valueStr = DerivedString<TypeString>::fromLexical(np: m_namePool, lexical: QString::number(value));
696
697 const AtomicValue::List multiValue = facet->multiValue();
698 bool found = false;
699 for (int j = 0; j < multiValue.count(); ++j) {
700 if (XsdSchemaHelper::constructAndCompare(operand1: valueStr, op: AtomicComparator::OperatorEqual, operand2: multiValue.at(i: j), type: BuiltinTypes::xsDouble, context: m_context, sourceLocationReflection: m_reflection)) {
701 found = true;
702 break;
703 }
704 }
705
706 if (!found) {
707 errorMsg = QtXmlPatterns::tr(sourceText: "Double content is not listed in the enumeration facet.");
708 return false;
709 }
710 }
711 if (facets.contains(akey: XsdFacet::Pattern)) {
712 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::Pattern);
713 const AtomicValue::List multiValue = facet->multiValue();
714 bool found = false;
715 for (int j = 0; j < multiValue.count(); ++j) {
716 const QString pattern = multiValue.at(i: j)->as<DerivedString<TypeString> >()->stringValue();
717 QRegExp exp = PatternPlatform::parsePattern(pattern, context: m_context, location: m_reflection);
718 if (exp.exactMatch(str: lexicalValue)) {
719 found = true;
720 break;
721 }
722 }
723
724 if (!found) {
725 errorMsg = QtXmlPatterns::tr(sourceText: "Double content does not match pattern facet.");
726 return false;
727 }
728 }
729 if (facets.contains(akey: XsdFacet::Assertion)) {
730 //TODO: implement
731 }
732
733 return true;
734}
735
736bool XsdTypeChecker::checkConstrainingFacetsDecimal(const AtomicValue::Ptr &value, const QString &lexicalValue, const XsdFacet::Hash &facets, QString &errorMsg) const
737{
738 if (facets.contains(akey: XsdFacet::FractionDigits)) {
739 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::FractionDigits);
740 const DerivedInteger<TypePositiveInteger>::Ptr facetValue = facet->value();
741
742 if (fractionDigitsForDecimal(lexicalValue) > facetValue->toInteger()) {
743 errorMsg = QtXmlPatterns::tr(sourceText: "Decimal content does not match in the fractionDigits facet.");
744 return false;
745 }
746 }
747 if (facets.contains(akey: XsdFacet::TotalDigits)) {
748 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::TotalDigits);
749 const DerivedInteger<TypePositiveInteger>::Ptr facetValue = facet->value();
750
751 if (totalDigitsForDecimal(lexicalValue) > facetValue->toInteger()) {
752 errorMsg = QtXmlPatterns::tr(sourceText: "Decimal content does not match in the totalDigits facet.");
753 return false;
754 }
755 }
756
757 return checkConstrainingFacetsDouble(value: value->as<Decimal>()->toDouble(), lexicalValue, facets, errorMsg);
758}
759
760bool XsdTypeChecker::checkConstrainingFacetsDateTime(const QDateTime &value, const QString &lexicalValue, const XsdFacet::Hash &facets, const AnySimpleType::Ptr &type, QString &errorMsg) const
761{
762 if (facets.contains(akey: XsdFacet::MaximumInclusive)) {
763 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::MaximumInclusive);
764 const AbstractDateTime::Ptr facetValue = ValueFactory::fromLexical(lexicalValue: facet->value()->as<DerivedString<TypeString> >()->stringValue(), type, context: m_context, sourceLocationReflection: m_reflection);
765 if (facetValue->toDateTime() < value) {
766 errorMsg = QtXmlPatterns::tr(sourceText: "Date time content does not match the maxInclusive facet.");
767 return false;
768 }
769 }
770 if (facets.contains(akey: XsdFacet::MaximumExclusive)) {
771 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::MaximumExclusive);
772 const AbstractDateTime::Ptr facetValue = ValueFactory::fromLexical(lexicalValue: facet->value()->as<DerivedString<TypeString> >()->stringValue(), type, context: m_context, sourceLocationReflection: m_reflection);
773 if (facetValue->toDateTime() <= value) {
774 errorMsg = QtXmlPatterns::tr(sourceText: "Date time content does not match the maxExclusive facet.");
775 return false;
776 }
777 }
778 if (facets.contains(akey: XsdFacet::MinimumInclusive)) {
779 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::MinimumInclusive);
780 const AbstractDateTime::Ptr facetValue = ValueFactory::fromLexical(lexicalValue: facet->value()->as<DerivedString<TypeString> >()->stringValue(), type, context: m_context, sourceLocationReflection: m_reflection);
781 if (facetValue->toDateTime() > value) {
782 errorMsg = QtXmlPatterns::tr(sourceText: "Date time content does not match the minInclusive facet.");
783 return false;
784 }
785 }
786 if (facets.contains(akey: XsdFacet::MinimumExclusive)) {
787 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::MinimumExclusive);
788 const AbstractDateTime::Ptr facetValue = ValueFactory::fromLexical(lexicalValue: facet->value()->as<DerivedString<TypeString> >()->stringValue(), type, context: m_context, sourceLocationReflection: m_reflection);
789 if (facetValue->toDateTime() >= value) {
790 errorMsg = QtXmlPatterns::tr(sourceText: "Date time content does not match the minExclusive facet.");
791 return false;
792 }
793 }
794 if (facets.contains(akey: XsdFacet::Enumeration)) {
795 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::Enumeration);
796
797 const AtomicValue::List multiValue = facet->multiValue();
798 bool found = false;
799 for (int j = 0; j < multiValue.count(); ++j) {
800 const AbstractDateTime::Ptr facetValue = ValueFactory::fromLexical(lexicalValue: multiValue.at(i: j)->as<DerivedString<TypeString> >()->stringValue(), type, context: m_context, sourceLocationReflection: m_reflection);
801 if (facetValue->toDateTime() == value) {
802 found = true;
803 break;
804 }
805 }
806
807 if (!found) {
808 errorMsg = QtXmlPatterns::tr(sourceText: "Date time content is not listed in the enumeration facet.");
809 return false;
810 }
811 }
812 if (facets.contains(akey: XsdFacet::Pattern)) {
813 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::Pattern);
814 const AtomicValue::List multiValue = facet->multiValue();
815 bool found = false;
816 for (int j = 0; j < multiValue.count(); ++j) {
817 const QString pattern = multiValue.at(i: j)->as<DerivedString<TypeString> >()->stringValue();
818 QRegExp exp = PatternPlatform::parsePattern(pattern, context: m_context, location: m_reflection);
819 if (exp.exactMatch(str: lexicalValue)) {
820 found = true;
821 break;
822 }
823 }
824
825 if (!found) {
826 errorMsg = QtXmlPatterns::tr(sourceText: "Date time content does not match pattern facet.");
827 return false;
828 }
829 }
830
831 return true;
832}
833
834bool XsdTypeChecker::checkConstrainingFacetsDuration(const AtomicValue::Ptr&, const QString &lexicalValue, const XsdFacet::Hash &facets, QString &errorMsg) const
835{
836 if (facets.contains(akey: XsdFacet::MaximumInclusive)) {
837 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::MaximumInclusive);
838 const DerivedString<TypeString>::Ptr value = DerivedString<TypeString>::fromLexical(np: m_namePool, lexical: lexicalValue);
839
840 if (XsdSchemaHelper::constructAndCompare(operand1: facets.value(akey: XsdFacet::MaximumInclusive)->value(), op: AtomicComparator::OperatorLessThan, operand2: value, type: BuiltinTypes::xsDuration, context: m_context, sourceLocationReflection: m_reflection)) {
841 errorMsg = QtXmlPatterns::tr(sourceText: "Duration content does not match the maxInclusive facet.");
842 return false;
843 }
844 }
845 if (facets.contains(akey: XsdFacet::MaximumExclusive)) {
846 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::MaximumExclusive);
847 const DerivedString<TypeString>::Ptr value = DerivedString<TypeString>::fromLexical(np: m_namePool, lexical: lexicalValue);
848
849 if (XsdSchemaHelper::constructAndCompare(operand1: facets.value(akey: XsdFacet::MaximumExclusive)->value(), op: AtomicComparator::OperatorLessOrEqual, operand2: value, type: BuiltinTypes::xsDuration, context: m_context, sourceLocationReflection: m_reflection)) {
850 errorMsg = QtXmlPatterns::tr(sourceText: "Duration content does not match the maxExclusive facet.");
851 return false;
852 }
853 }
854 if (facets.contains(akey: XsdFacet::MinimumInclusive)) {
855 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::MinimumInclusive);
856 const DerivedString<TypeString>::Ptr value = DerivedString<TypeString>::fromLexical(np: m_namePool, lexical: lexicalValue);
857
858 if (XsdSchemaHelper::constructAndCompare(operand1: facets.value(akey: XsdFacet::MinimumInclusive)->value(), op: AtomicComparator::OperatorGreaterThan, operand2: value, type: BuiltinTypes::xsDuration, context: m_context, sourceLocationReflection: m_reflection)) {
859 errorMsg = QtXmlPatterns::tr(sourceText: "Duration content does not match the minInclusive facet.");
860 return false;
861 }
862 }
863 if (facets.contains(akey: XsdFacet::MinimumExclusive)) {
864 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::MinimumExclusive);
865 const DerivedString<TypeString>::Ptr value = DerivedString<TypeString>::fromLexical(np: m_namePool, lexical: lexicalValue);
866
867 if (XsdSchemaHelper::constructAndCompare(operand1: facets.value(akey: XsdFacet::MinimumExclusive)->value(), op: AtomicComparator::OperatorGreaterOrEqual, operand2: value, type: BuiltinTypes::xsDuration, context: m_context, sourceLocationReflection: m_reflection)) {
868 errorMsg = QtXmlPatterns::tr(sourceText: "Duration content does not match the minExclusive facet.");
869 return false;
870 }
871 }
872 if (facets.contains(akey: XsdFacet::Enumeration)) {
873 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::Enumeration);
874 const DerivedString<TypeString>::Ptr value = DerivedString<TypeString>::fromLexical(np: m_namePool, lexical: lexicalValue);
875
876 const AtomicValue::List multiValue = facet->multiValue();
877 bool found = false;
878 for (int j = 0; j < multiValue.count(); ++j) {
879 if (XsdSchemaHelper::constructAndCompare(operand1: multiValue.at(i: j), op: AtomicComparator::OperatorEqual, operand2: value, type: BuiltinTypes::xsDuration, context: m_context, sourceLocationReflection: m_reflection)) {
880 found = true;
881 break;
882 }
883 }
884
885 if (!found) {
886 errorMsg = QtXmlPatterns::tr(sourceText: "Duration content is not listed in the enumeration facet.");
887 return false;
888 }
889 }
890 if (facets.contains(akey: XsdFacet::Pattern)) {
891 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::Pattern);
892 const AtomicValue::List multiValue = facet->multiValue();
893 bool found = false;
894 for (int j = 0; j < multiValue.count(); ++j) {
895 const QString pattern = multiValue.at(i: j)->as<DerivedString<TypeString> >()->stringValue();
896 QRegExp exp = PatternPlatform::parsePattern(pattern, context: m_context, location: m_reflection);
897 if (exp.exactMatch(str: lexicalValue)) {
898 found = true;
899 break;
900 }
901 }
902
903 if (!found) {
904 errorMsg = QtXmlPatterns::tr(sourceText: "Duration content does not match pattern facet.");
905 return false;
906 }
907 }
908 if (facets.contains(akey: XsdFacet::Assertion)) {
909 //TODO: implement
910 }
911
912 return true;
913}
914
915bool XsdTypeChecker::checkConstrainingFacetsBoolean(bool, const QString &lexicalValue, const XsdFacet::Hash &facets, QString &errorMsg) const
916{
917 if (facets.contains(akey: XsdFacet::Pattern)) {
918 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::Pattern);
919 const AtomicValue::List multiValue = facet->multiValue();
920 bool found = false;
921 for (int j = 0; j < multiValue.count(); ++j) {
922 const QString pattern = multiValue.at(i: j)->as<DerivedString<TypeString> >()->stringValue();
923 QRegExp exp = PatternPlatform::parsePattern(pattern, context: m_context, location: m_reflection);
924 if (exp.exactMatch(str: lexicalValue)) {
925 found = true;
926 break;
927 }
928 }
929
930 if (!found) {
931 errorMsg = QtXmlPatterns::tr(sourceText: "Boolean content does not match pattern facet.");
932 return false;
933 }
934 }
935 if (facets.contains(akey: XsdFacet::Assertion)) {
936 //TODO: implement
937 }
938
939 return true;
940}
941
942bool XsdTypeChecker::checkConstrainingFacetsBinary(const QByteArray &value, const XsdFacet::Hash &facets, const AnySimpleType::Ptr &type, QString &errorMsg) const
943{
944 if (facets.contains(akey: XsdFacet::Length)) {
945 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::Length);
946 const DerivedInteger<TypeNonNegativeInteger>::Ptr length = facet->value();
947 if (length->toInteger() != value.length()) {
948 errorMsg = QtXmlPatterns::tr(sourceText: "Binary content does not match the length facet.");
949 return false;
950 }
951 }
952 if (facets.contains(akey: XsdFacet::MinimumLength)) {
953 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::MinimumLength);
954 const DerivedInteger<TypeNonNegativeInteger>::Ptr length = facet->value();
955 if (length->toInteger() > value.length()) {
956 errorMsg = QtXmlPatterns::tr(sourceText: "Binary content does not match the minLength facet.");
957 return false;
958 }
959 }
960 if (facets.contains(akey: XsdFacet::MaximumLength)) {
961 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::MaximumLength);
962 const DerivedInteger<TypeNonNegativeInteger>::Ptr length = facet->value();
963 if (length->toInteger() < value.length()) {
964 errorMsg = QtXmlPatterns::tr(sourceText: "Binary content does not match the maxLength facet.");
965 return false;
966 }
967 }
968 if (facets.contains(akey: XsdFacet::Enumeration)) {
969 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::Enumeration);
970 const AtomicValue::List multiValue = facet->multiValue();
971 bool found = false;
972 for (int j = 0; j < multiValue.count(); ++j) {
973 const Base64Binary::Ptr binary = ValueFactory::fromLexical(lexicalValue: multiValue.at(i: j)->as<DerivedString<TypeString> >()->stringValue(), type, context: m_context, sourceLocationReflection: m_reflection);
974 const QByteArray facetValue = binary->as<Base64Binary>()->asByteArray();
975 if (value == facetValue) {
976 found = true;
977 break;
978 }
979 }
980
981 if (!found) {
982 errorMsg = QtXmlPatterns::tr(sourceText: "Binary content is not listed in the enumeration facet.");
983 return false;
984 }
985 }
986 if (facets.contains(akey: XsdFacet::Pattern)) {
987 //TODO: implement
988 }
989 if (facets.contains(akey: XsdFacet::Assertion)) {
990 //TODO: implement
991 }
992
993 return true;
994}
995
996bool XsdTypeChecker::checkConstrainingFacetsQName(const QXmlName &value, const QString &lexicalValue, const XsdFacet::Hash &facets, QString &errorMsg) const
997{
998 if (facets.contains(akey: XsdFacet::Length)) {
999 // always true
1000 }
1001 if (facets.contains(akey: XsdFacet::MinimumLength)) {
1002 // always true
1003 }
1004 if (facets.contains(akey: XsdFacet::MaximumLength)) {
1005 // always true
1006 }
1007 if (facets.contains(akey: XsdFacet::Enumeration)) {
1008 if (!XPathHelper::isQName(qName: lexicalValue)) {
1009 errorMsg = QtXmlPatterns::tr(sourceText: "Invalid QName content: %1.").arg(a: formatData(data: lexicalValue));
1010 return false;
1011 }
1012
1013 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::Enumeration);
1014 const AtomicValue::List multiValue = facet->multiValue();
1015 bool found = false;
1016 for (int j = 0; j < multiValue.count(); ++j) {
1017 const QXmlName facetValue = multiValue.at(i: j)->as<QNameValue>()->qName();
1018
1019 if (value == facetValue) {
1020 found = true;
1021 break;
1022 }
1023 }
1024
1025 if (!found) {
1026 errorMsg = QtXmlPatterns::tr(sourceText: "QName content is not listed in the enumeration facet.");
1027 return false;
1028 }
1029 }
1030 if (facets.contains(akey: XsdFacet::Pattern)) {
1031 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::Pattern);
1032 const AtomicValue::List multiValue = facet->multiValue();
1033 bool found = false;
1034 for (int j = 0; j < multiValue.count(); ++j) {
1035 const QString pattern = multiValue.at(i: j)->as<DerivedString<TypeString> >()->stringValue();
1036 QRegExp exp = PatternPlatform::parsePattern(pattern, context: m_context, location: m_reflection);
1037 if (exp.exactMatch(str: lexicalValue)) {
1038 found = true;
1039 break;
1040 }
1041 }
1042
1043 if (!found) {
1044 errorMsg = QtXmlPatterns::tr(sourceText: "QName content does not match pattern facet.");
1045 return false;
1046 }
1047 }
1048 if (facets.contains(akey: XsdFacet::Assertion)) {
1049 //TODO: implement
1050 }
1051
1052 return true;
1053}
1054
1055bool XsdTypeChecker::checkConstrainingFacetsNotation(const QXmlName &value, const XsdFacet::Hash &facets, QString &errorMsg) const
1056{
1057 if (facets.contains(akey: XsdFacet::Length)) {
1058 // deprecated by spec
1059 }
1060 if (facets.contains(akey: XsdFacet::MinimumLength)) {
1061 // deprecated by spec
1062 }
1063 if (facets.contains(akey: XsdFacet::MaximumLength)) {
1064 // deprecated by spec
1065 }
1066 if (facets.contains(akey: XsdFacet::Enumeration)) {
1067 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::Enumeration);
1068 const AtomicValue::List multiValue = facet->multiValue();
1069 bool found = false;
1070 for (int j = 0; j < multiValue.count(); ++j) {
1071 const QXmlName facetValue = multiValue.at(i: j)->as<QNameValue>()->qName();
1072
1073 if (value == facetValue) {
1074 found = true;
1075 break;
1076 }
1077 }
1078
1079 if (!found) {
1080 errorMsg = QtXmlPatterns::tr(sourceText: "Notation content is not listed in the enumeration facet.");
1081 return false;
1082 }
1083 }
1084 if (facets.contains(akey: XsdFacet::Pattern)) {
1085 //TODO: implement
1086 }
1087 if (facets.contains(akey: XsdFacet::Assertion)) {
1088 //TODO: implement
1089 }
1090
1091 return true;
1092}
1093
1094bool XsdTypeChecker::checkConstrainingFacetsList(const QStringList &values, const QString &lexicalValue, const AnySimpleType::Ptr &itemType, const XsdFacet::Hash &facets, QString &errorMsg) const
1095{
1096 if (facets.contains(akey: XsdFacet::Length)) {
1097 const DerivedInteger<TypeNonNegativeInteger>::Ptr value = facets.value(akey: XsdFacet::Length)->value();
1098 if (value->toInteger() != values.count()) {
1099 errorMsg = QtXmlPatterns::tr(sourceText: "List content does not match length facet.");
1100 return false;
1101 }
1102 }
1103 if (facets.contains(akey: XsdFacet::MinimumLength)) {
1104 const DerivedInteger<TypeNonNegativeInteger>::Ptr value = facets.value(akey: XsdFacet::MinimumLength)->value();
1105 if (value->toInteger() > values.count()) {
1106 errorMsg = QtXmlPatterns::tr(sourceText: "List content does not match minLength facet.");
1107 return false;
1108 }
1109 }
1110 if (facets.contains(akey: XsdFacet::MaximumLength)) {
1111 const DerivedInteger<TypeNonNegativeInteger>::Ptr value = facets.value(akey: XsdFacet::MaximumLength)->value();
1112 if (value->toInteger() < values.count()) {
1113 errorMsg = QtXmlPatterns::tr(sourceText: "List content does not match maxLength facet.");
1114 return false;
1115 }
1116 }
1117 if (facets.contains(akey: XsdFacet::Enumeration)) {
1118
1119 bool found = false;
1120
1121 // we have to handle lists with QName derived items differently
1122 if (BuiltinTypes::xsQName->wxsTypeMatches(other: itemType) || BuiltinTypes::xsNOTATION->wxsTypeMatches(other: itemType)) {
1123 // first convert the string values from the instance document to a list of QXmlName
1124 QList<QXmlName> instanceValues;
1125 for (int i = 0; i < values.count(); ++i) {
1126 instanceValues.append(t: convertToQName(name: values.at(i)));
1127 }
1128
1129 // fetch the values from the facet and create a list of QXmlNames for each of them
1130 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::Enumeration);
1131
1132 const AtomicValue::List multiValue = facet->multiValue();
1133 for (int i = 0; i < multiValue.count(); ++i) {
1134 const QStringList facetValueList = multiValue.at(i)->as<DerivedString<TypeString> >()->stringValue().split(sep: QLatin1Char(' '), behavior: Qt::SkipEmptyParts);
1135
1136 // create the list of atomic string values
1137 QList<QXmlName> facetValues;
1138 for (int j = 0; j < facetValueList.count(); ++j) {
1139 facetValues.append(t: convertToQName(name: facetValueList.at(i: j)));
1140 }
1141
1142 // check if both lists have the same length
1143 if (instanceValues.count() != facetValues.count())
1144 continue;
1145
1146 // check if both lists are equal, that means the contain equal items in the same order
1147 bool matchesAll = true;
1148 for (int j = 0; j < instanceValues.count(); ++j) {
1149 if (instanceValues.at(i: j) != facetValues.at(i: j)) {
1150 matchesAll = false;
1151 break;
1152 }
1153 }
1154
1155 if (matchesAll) {
1156 found = true;
1157 break;
1158 }
1159 }
1160 } else {
1161 // first convert the string values from the instance document to atomic values of type string
1162 AtomicValue::List instanceValues;
1163 for (int i = 0; i < values.count(); ++i) {
1164 instanceValues.append(t: DerivedString<TypeString>::fromLexical(np: m_namePool, lexical: values.at(i)));
1165 }
1166
1167 // fetch the values from the facet and create a list of atomic string values for each of them
1168 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::Enumeration);
1169
1170 const AnySimpleType::Ptr targetType = comparableType(type: itemType);
1171
1172 const AtomicValue::List multiValue = facet->multiValue();
1173 for (int i = 0; i < multiValue.count(); ++i) {
1174 const QStringList facetValueList = multiValue.at(i)->as<DerivedString<TypeString> >()->stringValue().split(sep: QLatin1Char(' '), behavior: Qt::SkipEmptyParts);
1175
1176 // create the list of atomic string values
1177 AtomicValue::List facetValues;
1178 for (int j = 0; j < facetValueList.count(); ++j) {
1179 facetValues.append(t: DerivedString<TypeString>::fromLexical(np: m_namePool, lexical: facetValueList.at(i: j)));
1180 }
1181
1182 // check if both lists have the same length
1183 if (instanceValues.count() != facetValues.count())
1184 continue;
1185
1186 // check if both lists are equal, that means the contain equal items in the same order
1187 bool matchesAll = true;
1188 for (int j = 0; j < instanceValues.count(); ++j) {
1189 if (!XsdSchemaHelper::constructAndCompare(operand1: instanceValues.at(i: j), op: AtomicComparator::OperatorEqual, operand2: facetValues.at(i: j), type: targetType, context: m_context, sourceLocationReflection: m_reflection)) {
1190 matchesAll = false;
1191 break;
1192 }
1193 }
1194
1195 if (matchesAll) {
1196 found = true;
1197 break;
1198 }
1199 }
1200 }
1201
1202 if (!found) {
1203 errorMsg = QtXmlPatterns::tr(sourceText: "List content is not listed in the enumeration facet.");
1204 return false;
1205 }
1206 }
1207 if (facets.contains(akey: XsdFacet::Pattern)) {
1208 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::Pattern);
1209 const AtomicValue::List multiValue = facet->multiValue();
1210 bool found = false;
1211 for (int j = 0; j < multiValue.count(); ++j) {
1212 const QString pattern = multiValue.at(i: j)->as<DerivedString<TypeString> >()->stringValue();
1213 QRegExp exp = PatternPlatform::parsePattern(pattern, context: m_context, location: m_reflection);
1214 if (exp.exactMatch(str: lexicalValue)) {
1215 found = true;
1216 break;
1217 }
1218 }
1219
1220 if (!found) {
1221 errorMsg = QtXmlPatterns::tr(sourceText: "List content does not match pattern facet.");
1222 return false;
1223 }
1224 }
1225 if (facets.contains(akey: XsdFacet::Assertion)) {
1226 //TODO: implement
1227 }
1228
1229 return true;
1230}
1231
1232bool XsdTypeChecker::checkConstrainingFacetsUnion(const QString &value, const QString &lexicalValue, const XsdSimpleType::Ptr &simpleType, const XsdFacet::Hash &facets, QString &errorMsg) const
1233{
1234 if (facets.contains(akey: XsdFacet::Enumeration)) {
1235 const AnySimpleType::List memberTypes = simpleType->memberTypes();
1236
1237 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::Enumeration);
1238
1239 // convert the instance value into an atomic string value
1240 const DerivedString<TypeString>::Ptr valueString = DerivedString<TypeString>::fromLexical(np: m_namePool, lexical: value);
1241
1242 // collect the facet values into a list of atomic string values
1243 const AtomicValue::List facetValues = facet->multiValue();
1244
1245 // compare the instance value against the facetValues for each member type and
1246 // search for a match
1247
1248 bool found = false;
1249 for (int i = 0; i < memberTypes.count(); ++i) {
1250 const AnySimpleType::Ptr targetType = comparableType(type: memberTypes.at(i));
1251 for (int j = 0; j < facetValues.count(); ++j) {
1252 if (XsdSchemaHelper::constructAndCompare(operand1: valueString, op: AtomicComparator::OperatorEqual, operand2: facetValues.at(i: j), type: targetType, context: m_context, sourceLocationReflection: m_reflection)) {
1253 found = true;
1254 break;
1255 }
1256 }
1257 }
1258
1259 if (!found) {
1260 errorMsg = QtXmlPatterns::tr(sourceText: "Union content is not listed in the enumeration facet.");
1261 return false;
1262 }
1263 }
1264 if (facets.contains(akey: XsdFacet::Pattern)) {
1265 const XsdFacet::Ptr facet = facets.value(akey: XsdFacet::Pattern);
1266 const AtomicValue::List multiValue = facet->multiValue();
1267 bool found = false;
1268 for (int j = 0; j < multiValue.count(); ++j) {
1269 const QString pattern = multiValue.at(i: j)->as<DerivedString<TypeString> >()->stringValue();
1270 QRegExp exp = PatternPlatform::parsePattern(pattern, context: m_context, location: m_reflection);
1271 if (exp.exactMatch(str: lexicalValue)) {
1272 found = true;
1273 break;
1274 }
1275 }
1276
1277 if (!found) {
1278 errorMsg = QtXmlPatterns::tr(sourceText: "Union content does not match pattern facet.");
1279 return false;
1280 }
1281 }
1282 if (facets.contains(akey: XsdFacet::Assertion)) {
1283 //TODO: implement
1284 }
1285
1286 return true;
1287}
1288
1289AtomicValue::Ptr XsdTypeChecker::fromLexical(const QString &value, const SchemaType::Ptr &type, const ReportContext::Ptr &context, const SourceLocationReflection *const reflection) const
1290{
1291 if (type->name(np: m_namePool) == BuiltinTypes::xsNOTATION->name(np: m_namePool) || type->name(np: m_namePool) == BuiltinTypes::xsQName->name(np: m_namePool)) {
1292 if (value.simplified().isEmpty())
1293 return ValidationError::createError(description: QtXmlPatterns::tr(sourceText: "Data of type %1 are not allowed to be empty.").arg(a: formatType(np: m_namePool, type: BuiltinTypes::xsNOTATION)));
1294
1295 const QXmlName valueName = convertToQName(name: value);
1296 return QNameValue::fromValue(np: m_namePool, name: valueName);
1297 } else {
1298 return ValueFactory::fromLexical(lexicalValue: value, type, context, sourceLocationReflection: reflection);
1299 }
1300}
1301
1302QXmlName XsdTypeChecker::convertToQName(const QString &name) const
1303{
1304 const int pos = name.indexOf(c: QLatin1Char(':'));
1305
1306 QXmlName::PrefixCode prefixCode = 0;
1307 QXmlName::NamespaceCode namespaceCode;
1308 QXmlName::LocalNameCode localNameCode;
1309 if (pos != -1) {
1310 prefixCode = m_context->namePool()->allocatePrefix(prefix: name.left(n: pos));
1311 namespaceCode = StandardNamespaces::empty;
1312 for (int i = 0; i < m_namespaceBindings.count(); ++i) {
1313 if (m_namespaceBindings.at(i).prefix() == prefixCode) {
1314 namespaceCode = m_namespaceBindings.at(i).namespaceURI();
1315 break;
1316 }
1317 }
1318 localNameCode = m_context->namePool()->allocateLocalName(ln: name.mid(position: pos + 1));
1319 } else {
1320 prefixCode = StandardPrefixes::empty;
1321 namespaceCode = StandardNamespaces::empty;
1322 for (int i = 0; i < m_namespaceBindings.count(); ++i) {
1323 if (m_namespaceBindings.at(i).prefix() == prefixCode) {
1324 namespaceCode = m_namespaceBindings.at(i).namespaceURI();
1325 break;
1326 }
1327 }
1328 localNameCode = m_context->namePool()->allocateLocalName(ln: name);
1329 }
1330
1331 return QXmlName(namespaceCode, localNameCode, prefixCode);
1332}
1333
1334QT_END_NAMESPACE
1335

source code of qtxmlpatterns/src/xmlpatterns/schema/qxsdtypechecker.cpp