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 
63 QT_BEGIN_NAMESPACE
64 
65 using namespace QPatternist;
66 
XsdSchemaSourceLocationReflection(const QSourceLocation & location)67 XsdSchemaSourceLocationReflection::XsdSchemaSourceLocationReflection(const QSourceLocation &location)
68     : m_sourceLocation(location)
69 {
70 }
71 
actualReflection() const72 const SourceLocationReflection* XsdSchemaSourceLocationReflection::actualReflection() const
73 {
74     return this;
75 }
76 
sourceLocation() const77 QSourceLocation XsdSchemaSourceLocationReflection::sourceLocation() const
78 {
79     return m_sourceLocation;
80 }
81 
82 
comparableType(const AnySimpleType::Ptr & type)83 static 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 
totalDigitsForSignedLongLong(long long value)102 static int totalDigitsForSignedLongLong(long long value)
103 {
104     QString number = QString::number(value);
105     if (number.startsWith(QLatin1Char('-')))
106         number = number.mid(1);
107 
108     return number.length();
109 }
110 
totalDigitsForUnsignedLongLong(unsigned long long value)111 static int totalDigitsForUnsignedLongLong(unsigned long long value)
112 {
113     const QString number = QString::number(value);
114     return number.length();
115 }
116 
totalDigitsForDecimal(const QString & lexicalValue)117 static 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(pos) == zeroChar && (pos != length))
125         pos++;
126 
127     QString value = lexicalValue.mid(pos);
128 
129     // if contains '.' strip trailing zeros
130     if (value.contains(QLatin1Char('.'))) {
131         pos = value.length() - 1;
132         while (value.at(pos) == zeroChar) {
133             pos--;
134         }
135 
136         value = value.left(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 
fractionDigitsForDecimal(const QString & lexicalValue)151 static int fractionDigitsForDecimal(const QString &lexicalValue)
152 {
153     const int pos = lexicalValue.indexOf(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 
XsdTypeChecker(const XsdSchemaContext::Ptr & context,const QVector<QXmlName> & namespaceBindings,const QSourceLocation & location)163 XsdTypeChecker::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 
~XsdTypeChecker()171 XsdTypeChecker::~XsdTypeChecker()
172 {
173     delete m_reflection;
174 }
175 
normalizedValue(const QString & value,const XsdFacet::Hash & facets)176 QString XsdTypeChecker::normalizedValue(const QString &value, const XsdFacet::Hash &facets)
177 {
178     if (!facets.contains(XsdFacet::WhiteSpace))
179         return value;
180 
181     const XsdFacet::Ptr whiteSpaceFacet = facets.value(XsdFacet::WhiteSpace);
182 
183     const DerivedString<TypeString>::Ptr facetValue = whiteSpaceFacet->value();
184     const QString stringValue = facetValue->stringValue();
185     if (stringValue == XsdSchemaToken::toString(XsdSchemaToken::Preserve))
186         return value;
187     else if (stringValue == XsdSchemaToken::toString(XsdSchemaToken::Replace)) {
188         QString newValue(value);
189         newValue.replace(QLatin1Char('\t'), QLatin1Char(' '));
190         newValue.replace(QLatin1Char('\n'), QLatin1Char(' '));
191         newValue.replace(QLatin1Char('\r'), QLatin1Char(' '));
192 
193         return newValue;
194     } else if (stringValue == XsdSchemaToken::toString(XsdSchemaToken::Collapse)) {
195         return value.simplified();
196     }
197 
198     return value;
199 }
200 
mergedFacetsForType(const SchemaType::Ptr & type,const XsdSchemaContext::Ptr & context)201 XsdFacet::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->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(it.key(), it.value());
212 
213     return result;
214 }
215 
isValidString(const QString & normalizedString,const AnySimpleType::Ptr & type,QString & errorMsg,AnySimpleType::Ptr * boundType) const216 bool XsdTypeChecker::isValidString(const QString &normalizedString, const AnySimpleType::Ptr &type, QString &errorMsg, AnySimpleType::Ptr *boundType) const
217 {
218     if (type->name(m_namePool) == BuiltinTypes::xsAnySimpleType->name(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(type)) {
228             if (!XPathHelper::isQName(normalizedString)) {
229                 errorMsg = QtXmlPatterns::tr("%1 is not valid according to %2.").arg(formatData(normalizedString)).arg(formatType(m_namePool, type));
230                 return false;
231             }
232         }
233 
234         const AtomicValue::Ptr value = fromLexical(normalizedString, type, m_context, m_reflection);
235         if (value->hasError()) {
236             errorMsg = QtXmlPatterns::tr("%1 is not valid according to %2.").arg(formatData(normalizedString)).arg(formatType(m_namePool, type));
237             return false;
238         }
239 
240         if (!checkConstrainingFacets(value, 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(normalizedString, targetType, m_context, m_reflection);
256             if (value->hasError()) {
257                 errorMsg = QtXmlPatterns::tr("%1 is not valid according to %2.").arg(formatData(normalizedString)).arg(formatType(m_namePool, targetType));
258                 return false;
259             }
260 
261             if (!checkConstrainingFacets(value, 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(QLatin1Char(' '), Qt::SkipEmptyParts);
270             for (int i = 0; i < entries.count(); ++i) {
271                 entries[i] = normalizedValue(entries.at(i), mergedFacetsForType(simpleType->itemType(), m_context));
272             }
273 
274             if (!checkConstrainingFacetsList(entries, normalizedString, simpleType->itemType(), mergedFacetsForType(simpleType, m_context), errorMsg)) {
275                 return false;
276             }
277 
278             for (int i = 0; i < entries.count(); ++i) {
279                 if (!isValidString(entries.at(i), 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(normalizedString, normalizedString, simpleType, mergedFacetsForType(simpleType, 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(memberTypes.at(i), m_context);
297                 if (isValidString(normalizedValue(normalizedString, mergedFacets), 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 
valuesAreEqual(const QString & value,const QString & otherValue,const AnySimpleType::Ptr & type) const316 bool 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(m_namePool) == BuiltinTypes::xsAnySimpleType->name(m_namePool))
322         return (value == otherValue);
323 
324     if (BuiltinTypes::xsQName->wxsTypeMatches(type)) {
325         const QXmlName valueName = convertToQName(value);
326         const QXmlName otherValueName = convertToQName(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(m_namePool, value);
335         const DerivedString<TypeString>::Ptr otherValueStr = DerivedString<TypeString>::fromLexical(m_namePool, otherValue);
336 
337         return XsdSchemaHelper::constructAndCompare(valueStr, AtomicComparator::OperatorEqual, otherValueStr, targetType, m_context, m_reflection);
338     } else if (type->category() == SchemaType::SimpleTypeList) {
339         const QStringList values = value.split(QLatin1Char(' '), Qt::SkipEmptyParts);
340         const QStringList otherValues = otherValue.split(QLatin1Char(' '), Qt::SkipEmptyParts);
341         if (values.count() != otherValues.count())
342             return false;
343 
344         for (int i = 0; i < values.count(); ++i) {
345             if (!valuesAreEqual(values.at(i), otherValues.at(i), 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, memberTypes.at(i))) {
354                 return true;
355             }
356         }
357 
358         return false;
359     }
360 
361     return false;
362 }
363 
checkConstrainingFacets(const AtomicValue::Ptr & value,const QString & lexicalValue,const AnySimpleType::Ptr & type,QString & errorMsg) const364 bool XsdTypeChecker::checkConstrainingFacets(const AtomicValue::Ptr &value, const QString &lexicalValue, const AnySimpleType::Ptr &type, QString &errorMsg) const
365 {
366     const XsdFacet::Hash facets = mergedFacetsForType(type, m_context);
367 
368     if (BuiltinTypes::xsString->wxsTypeMatches(type) ||
369         BuiltinTypes::xsUntypedAtomic->wxsTypeMatches(type)) {
370         return checkConstrainingFacetsString(value->stringValue(), facets, BuiltinTypes::xsString, errorMsg);
371     } else if (BuiltinTypes::xsAnyURI->wxsTypeMatches(type)) {
372         return checkConstrainingFacetsString(value->stringValue(), facets, BuiltinTypes::xsAnyURI, errorMsg);
373     } else if (BuiltinTypes::xsNOTATION->wxsTypeMatches(type)) {
374         return checkConstrainingFacetsNotation(value->as<QNameValue>()->qName(), facets, errorMsg);
375     } else if (BuiltinTypes::xsUnsignedByte->wxsTypeMatches(type) ||
376                BuiltinTypes::xsUnsignedInt->wxsTypeMatches(type) ||
377                BuiltinTypes::xsUnsignedLong->wxsTypeMatches(type) ||
378                BuiltinTypes::xsUnsignedShort->wxsTypeMatches(type)) {
379         return checkConstrainingFacetsUnsignedInteger(value->as<Numeric>()->toUnsignedInteger(), lexicalValue, facets, errorMsg);
380     } else if (BuiltinTypes::xsInteger->wxsTypeMatches(type)) {
381         return checkConstrainingFacetsSignedInteger(value->as<Numeric>()->toInteger(), lexicalValue, facets, errorMsg);
382     } else if (BuiltinTypes::xsFloat->wxsTypeMatches(type) ||
383                BuiltinTypes::xsDouble->wxsTypeMatches(type)) {
384         return checkConstrainingFacetsDouble(value->as<Numeric>()->toDouble(), lexicalValue, facets, errorMsg);
385     } else if (BuiltinTypes::xsDecimal->wxsTypeMatches(type)) {
386         return checkConstrainingFacetsDecimal(value, lexicalValue, facets, errorMsg);
387     } else if (BuiltinTypes::xsDateTime->wxsTypeMatches(type)) {
388         return checkConstrainingFacetsDateTime(value->as<AbstractDateTime>()->toDateTime(), lexicalValue, facets, BuiltinTypes::xsDateTime, errorMsg);
389     } else if (BuiltinTypes::xsDate->wxsTypeMatches(type)) {
390         return checkConstrainingFacetsDateTime(value->as<AbstractDateTime>()->toDateTime(), lexicalValue, facets, BuiltinTypes::xsDate, errorMsg);
391     } else if (BuiltinTypes::xsGYear->wxsTypeMatches(type)) {
392         return checkConstrainingFacetsDateTime(value->as<AbstractDateTime>()->toDateTime(), lexicalValue, facets, BuiltinTypes::xsGYear, errorMsg);
393     } else if (BuiltinTypes::xsGYearMonth->wxsTypeMatches(type)) {
394         return checkConstrainingFacetsDateTime(value->as<AbstractDateTime>()->toDateTime(), lexicalValue, facets, BuiltinTypes::xsGYearMonth, errorMsg);
395     } else if (BuiltinTypes::xsGMonth->wxsTypeMatches(type)) {
396         return checkConstrainingFacetsDateTime(value->as<AbstractDateTime>()->toDateTime(), lexicalValue, facets, BuiltinTypes::xsGMonth, errorMsg);
397     } else if (BuiltinTypes::xsGMonthDay->wxsTypeMatches(type)) {
398         return checkConstrainingFacetsDateTime(value->as<AbstractDateTime>()->toDateTime(), lexicalValue, facets, BuiltinTypes::xsGMonthDay, errorMsg);
399     } else if (BuiltinTypes::xsGDay->wxsTypeMatches(type)) {
400         return checkConstrainingFacetsDateTime(value->as<AbstractDateTime>()->toDateTime(), lexicalValue, facets, BuiltinTypes::xsGDay, errorMsg);
401     } else if (BuiltinTypes::xsTime->wxsTypeMatches(type)) {
402         return checkConstrainingFacetsDateTime(value->as<AbstractDateTime>()->toDateTime(), lexicalValue, facets, BuiltinTypes::xsTime, errorMsg);
403     } else if (BuiltinTypes::xsDuration->wxsTypeMatches(type)) {
404         return checkConstrainingFacetsDuration(value, lexicalValue, facets, errorMsg);
405     } else if (BuiltinTypes::xsBoolean->wxsTypeMatches(type)) {
406         return checkConstrainingFacetsBoolean(value->as<Boolean>()->value(), lexicalValue, facets, errorMsg);
407     } else if (BuiltinTypes::xsHexBinary->wxsTypeMatches(type)) {
408         return checkConstrainingFacetsBinary(value->as<Base64Binary>()->asByteArray(), facets, BuiltinTypes::xsHexBinary, errorMsg);
409     } else if (BuiltinTypes::xsBase64Binary->wxsTypeMatches(type)) {
410         return checkConstrainingFacetsBinary(value->as<Base64Binary>()->asByteArray(), facets, BuiltinTypes::xsBase64Binary, errorMsg);
411     } else if (BuiltinTypes::xsQName->wxsTypeMatches(type)) {
412         return checkConstrainingFacetsQName(value->as<QNameValue>()->qName(), lexicalValue, facets, errorMsg);
413     }
414 
415     return true;
416 }
417 
checkConstrainingFacetsString(const QString & value,const XsdFacet::Hash & facets,const AnySimpleType::Ptr & type,QString & errorMsg) const418 bool XsdTypeChecker::checkConstrainingFacetsString(const QString &value, const XsdFacet::Hash &facets, const AnySimpleType::Ptr &type, QString &errorMsg) const
419 {
420     if (facets.contains(XsdFacet::Length)) {
421         const XsdFacet::Ptr facet = facets.value(XsdFacet::Length);
422         const DerivedInteger<TypeNonNegativeInteger>::Ptr length = facet->value();
423         if (length->toInteger() != value.length()) {
424             errorMsg = QtXmlPatterns::tr("String content does not match the length facet.");
425             return false;
426         }
427     }
428     if (facets.contains(XsdFacet::MinimumLength)) {
429         const XsdFacet::Ptr facet = facets.value(XsdFacet::MinimumLength);
430         const DerivedInteger<TypeNonNegativeInteger>::Ptr length = facet->value();
431         if (length->toInteger() > value.length()) {
432             errorMsg = QtXmlPatterns::tr("String content does not match the minLength facet.");
433             return false;
434         }
435     }
436     if (facets.contains(XsdFacet::MaximumLength)) {
437         const XsdFacet::Ptr facet = facets.value(XsdFacet::MaximumLength);
438         const DerivedInteger<TypeNonNegativeInteger>::Ptr length = facet->value();
439         if (length->toInteger() < value.length()) {
440             errorMsg = QtXmlPatterns::tr("String content does not match the maxLength facet.");
441             return false;
442         }
443     }
444     if (facets.contains(XsdFacet::Pattern)) {
445         const XsdFacet::Ptr facet = facets.value(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(j)->as<DerivedString<TypeString> >()->stringValue();
450             QRegExp exp = PatternPlatform::parsePattern(pattern, m_context, m_reflection);
451             if (exp.exactMatch(value)) {
452                 found = true;
453                 break;
454             }
455         }
456 
457         if (!found) {
458             errorMsg = QtXmlPatterns::tr("String content does not match pattern facet.");
459             return false;
460         }
461     }
462     if (facets.contains(XsdFacet::Enumeration)) {
463         const XsdFacet::Ptr facet = facets.value(XsdFacet::Enumeration);
464         const DerivedString<TypeString>::Ptr valueStr = DerivedString<TypeString>::fromLexical(m_namePool, 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(valueStr, AtomicComparator::OperatorEqual, multiValue.at(j), type, m_context, m_reflection)) {
470                 found = true;
471                 break;
472             }
473         }
474 
475         if (!found) {
476             errorMsg = QtXmlPatterns::tr("String content is not listed in the enumeration facet.");
477             return false;
478         }
479     }
480     if (facets.contains(XsdFacet::Assertion)) {
481         //TODO: implement
482     }
483 
484     return true;
485 }
486 
checkConstrainingFacetsSignedInteger(long long value,const QString & lexicalValue,const XsdFacet::Hash & facets,QString & errorMsg) const487 bool XsdTypeChecker::checkConstrainingFacetsSignedInteger(long long value, const QString &lexicalValue, const XsdFacet::Hash &facets, QString &errorMsg) const
488 {
489     if (facets.contains(XsdFacet::MaximumInclusive)) {
490         const XsdFacet::Ptr facet = facets.value(XsdFacet::MaximumInclusive);
491         const Numeric::Ptr facetValue = ValueFactory::fromLexical(facet->value()->as<DerivedString<TypeString> >()->stringValue(), BuiltinTypes::xsLong, m_context, m_reflection);
492         if (facetValue->toInteger() < value) {
493             errorMsg = QtXmlPatterns::tr("Signed integer content does not match the maxInclusive facet.");
494             return false;
495         }
496     }
497     if (facets.contains(XsdFacet::MaximumExclusive)) {
498         const XsdFacet::Ptr facet = facets.value(XsdFacet::MaximumExclusive);
499         const Numeric::Ptr facetValue = ValueFactory::fromLexical(facet->value()->as<DerivedString<TypeString> >()->stringValue(), BuiltinTypes::xsLong, m_context, m_reflection);
500         if (facetValue->toInteger() <= value) {
501             errorMsg = QtXmlPatterns::tr("Signed integer content does not match the maxExclusive facet.");
502             return false;
503         }
504     }
505     if (facets.contains(XsdFacet::MinimumInclusive)) {
506         const XsdFacet::Ptr facet = facets.value(XsdFacet::MinimumInclusive);
507         const Numeric::Ptr facetValue = ValueFactory::fromLexical(facet->value()->as<DerivedString<TypeString> >()->stringValue(), BuiltinTypes::xsLong, m_context, m_reflection);
508         if (facetValue->toInteger() > value) {
509             errorMsg = QtXmlPatterns::tr("Signed integer content does not match the minInclusive facet.");
510             return false;
511         }
512     }
513     if (facets.contains(XsdFacet::MinimumExclusive)) {
514         const XsdFacet::Ptr facet = facets.value(XsdFacet::MinimumExclusive);
515         const Numeric::Ptr facetValue = ValueFactory::fromLexical(facet->value()->as<DerivedString<TypeString> >()->stringValue(), BuiltinTypes::xsLong, m_context, m_reflection);
516         if (facetValue->toInteger() >= value) {
517             errorMsg = QtXmlPatterns::tr("Signed integer content does not match the minExclusive facet.");
518             return false;
519         }
520     }
521     if (facets.contains(XsdFacet::Enumeration)) {
522         const XsdFacet::Ptr facet = facets.value(XsdFacet::Enumeration);
523         const DerivedString<TypeString>::Ptr valueStr = DerivedString<TypeString>::fromLexical(m_namePool, 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(valueStr, AtomicComparator::OperatorEqual, multiValue.at(j), BuiltinTypes::xsLong, m_context, m_reflection)) {
529                 found = true;
530                 break;
531             }
532         }
533 
534         if (!found) {
535             errorMsg = QtXmlPatterns::tr("Signed integer content is not listed in the enumeration facet.");
536             return false;
537         }
538     }
539     if (facets.contains(XsdFacet::Pattern)) {
540         const XsdFacet::Ptr facet = facets.value(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(j)->as<DerivedString<TypeString> >()->stringValue();
545             QRegExp exp = PatternPlatform::parsePattern(pattern, m_context, m_reflection);
546             if (exp.exactMatch(lexicalValue)) {
547                 found = true;
548                 break;
549             }
550         }
551 
552         if (!found) {
553             errorMsg = QtXmlPatterns::tr("Signed integer content does not match pattern facet.");
554             return false;
555         }
556     }
557     if (facets.contains(XsdFacet::TotalDigits)) {
558         const XsdFacet::Ptr facet = facets.value(XsdFacet::TotalDigits);
559         const DerivedInteger<TypePositiveInteger>::Ptr facetValue = facet->value();
560 
561         if (totalDigitsForSignedLongLong(value) > facetValue->toInteger()) {
562             errorMsg = QtXmlPatterns::tr("Signed integer content does not match in the totalDigits facet.");
563             return false;
564         }
565     }
566     if (facets.contains(XsdFacet::Assertion)) {
567         //TODO: implement
568     }
569 
570     return true;
571 }
572 
checkConstrainingFacetsUnsignedInteger(unsigned long long value,const QString & lexicalValue,const XsdFacet::Hash & facets,QString & errorMsg) const573 bool XsdTypeChecker::checkConstrainingFacetsUnsignedInteger(unsigned long long value, const QString &lexicalValue, const XsdFacet::Hash &facets, QString &errorMsg) const
574 {
575     if (facets.contains(XsdFacet::MaximumInclusive)) {
576         const XsdFacet::Ptr facet = facets.value(XsdFacet::MaximumInclusive);
577         const Numeric::Ptr facetValue = ValueFactory::fromLexical(facet->value()->as<DerivedString<TypeString> >()->stringValue(), BuiltinTypes::xsUnsignedLong, m_context, m_reflection);
578         if (facetValue->toUnsignedInteger() < value) {
579             errorMsg = QtXmlPatterns::tr("Unsigned integer content does not match the maxInclusive facet.");
580             return false;
581         }
582     }
583     if (facets.contains(XsdFacet::MaximumExclusive)) {
584         const XsdFacet::Ptr facet = facets.value(XsdFacet::MaximumExclusive);
585         const Numeric::Ptr facetValue = ValueFactory::fromLexical(facet->value()->as<DerivedString<TypeString> >()->stringValue(), BuiltinTypes::xsUnsignedLong, m_context, m_reflection);
586         if (facetValue->toUnsignedInteger() <= value) {
587             errorMsg = QtXmlPatterns::tr("Unsigned integer content does not match the maxExclusive facet.");
588             return false;
589         }
590     }
591     if (facets.contains(XsdFacet::MinimumInclusive)) {
592         const XsdFacet::Ptr facet = facets.value(XsdFacet::MinimumInclusive);
593         const Numeric::Ptr facetValue = ValueFactory::fromLexical(facet->value()->as<DerivedString<TypeString> >()->stringValue(), BuiltinTypes::xsUnsignedLong, m_context, m_reflection);
594         if (facetValue->toUnsignedInteger() > value) {
595             errorMsg = QtXmlPatterns::tr("Unsigned integer content does not match the minInclusive facet.");
596             return false;
597         }
598     }
599     if (facets.contains(XsdFacet::MinimumExclusive)) {
600         const XsdFacet::Ptr facet = facets.value(XsdFacet::MinimumExclusive);
601         const Numeric::Ptr facetValue = ValueFactory::fromLexical(facet->value()->as<DerivedString<TypeString> >()->stringValue(), BuiltinTypes::xsUnsignedLong, m_context, m_reflection);
602         if (facetValue->toUnsignedInteger() >= value) {
603             errorMsg = QtXmlPatterns::tr("Unsigned integer content does not match the minExclusive facet.");
604             return false;
605         }
606     }
607     if (facets.contains(XsdFacet::Enumeration)) {
608         const XsdFacet::Ptr facet = facets.value(XsdFacet::Enumeration);
609         const DerivedString<TypeString>::Ptr valueStr = DerivedString<TypeString>::fromLexical(m_namePool, 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(valueStr, AtomicComparator::OperatorEqual, multiValue.at(j), BuiltinTypes::xsUnsignedLong, m_context, m_reflection)) {
615                 found = true;
616                 break;
617             }
618         }
619 
620         if (!found) {
621             errorMsg = QtXmlPatterns::tr("Unsigned integer content is not listed in the enumeration facet.");
622             return false;
623         }
624     }
625     if (facets.contains(XsdFacet::Pattern)) {
626         const XsdFacet::Ptr facet = facets.value(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(j)->as<DerivedString<TypeString> >()->stringValue();
631             QRegExp exp = PatternPlatform::parsePattern(pattern, m_context, m_reflection);
632             if (exp.exactMatch(lexicalValue)) {
633                 found = true;
634                 break;
635             }
636         }
637 
638         if (!found) {
639             errorMsg = QtXmlPatterns::tr("Unsigned integer content does not match pattern facet.");
640             return false;
641         }
642     }
643     if (facets.contains(XsdFacet::TotalDigits)) {
644         const XsdFacet::Ptr facet = facets.value(XsdFacet::TotalDigits);
645         const DerivedInteger<TypePositiveInteger>::Ptr facetValue = facet->value();
646 
647         if (totalDigitsForUnsignedLongLong(value) > facetValue->toInteger()) {
648             errorMsg = QtXmlPatterns::tr("Unsigned integer content does not match in the totalDigits facet.");
649             return false;
650         }
651     }
652     if (facets.contains(XsdFacet::Assertion)) {
653         //TODO: implement
654     }
655 
656     return true;
657 }
658 
checkConstrainingFacetsDouble(double value,const QString & lexicalValue,const XsdFacet::Hash & facets,QString & errorMsg) const659 bool XsdTypeChecker::checkConstrainingFacetsDouble(double value, const QString &lexicalValue, const XsdFacet::Hash &facets, QString &errorMsg) const
660 {
661     if (facets.contains(XsdFacet::MaximumInclusive)) {
662         const XsdFacet::Ptr facet = facets.value(XsdFacet::MaximumInclusive);
663         const Numeric::Ptr facetValue = ValueFactory::fromLexical(facet->value()->as<DerivedString<TypeString> >()->stringValue(), BuiltinTypes::xsDouble, m_context, m_reflection);
664         if (facetValue->toDouble() < value) {
665             errorMsg = QtXmlPatterns::tr("Double content does not match the maxInclusive facet.");
666             return false;
667         }
668     }
669     if (facets.contains(XsdFacet::MaximumExclusive)) {
670         const XsdFacet::Ptr facet = facets.value(XsdFacet::MaximumExclusive);
671         const Numeric::Ptr facetValue = ValueFactory::fromLexical(facet->value()->as<DerivedString<TypeString> >()->stringValue(), BuiltinTypes::xsDouble, m_context, m_reflection);
672         if (facetValue->toDouble() <= value) {
673             errorMsg = QtXmlPatterns::tr("Double content does not match the maxExclusive facet.");
674             return false;
675         }
676     }
677     if (facets.contains(XsdFacet::MinimumInclusive)) {
678         const XsdFacet::Ptr facet = facets.value(XsdFacet::MinimumInclusive);
679         const Numeric::Ptr facetValue = ValueFactory::fromLexical(facet->value()->as<DerivedString<TypeString> >()->stringValue(), BuiltinTypes::xsDouble, m_context, m_reflection);
680         if (facetValue->toDouble() > value) {
681             errorMsg = QtXmlPatterns::tr("Double content does not match the minInclusive facet.");
682             return false;
683         }
684     }
685     if (facets.contains(XsdFacet::MinimumExclusive)) {
686         const XsdFacet::Ptr facet = facets.value(XsdFacet::MinimumExclusive);
687         const Numeric::Ptr facetValue = ValueFactory::fromLexical(facet->value()->as<DerivedString<TypeString> >()->stringValue(), BuiltinTypes::xsDouble, m_context, m_reflection);
688         if (facetValue->toDouble() >= value) {
689             errorMsg = QtXmlPatterns::tr("Double content does not match the minExclusive facet.");
690             return false;
691         }
692     }
693     if (facets.contains(XsdFacet::Enumeration)) {
694         const XsdFacet::Ptr facet = facets.value(XsdFacet::Enumeration);
695         const DerivedString<TypeString>::Ptr valueStr = DerivedString<TypeString>::fromLexical(m_namePool, 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(valueStr, AtomicComparator::OperatorEqual, multiValue.at(j), BuiltinTypes::xsDouble, m_context, m_reflection)) {
701                 found = true;
702                 break;
703             }
704         }
705 
706         if (!found) {
707             errorMsg = QtXmlPatterns::tr("Double content is not listed in the enumeration facet.");
708             return false;
709         }
710     }
711     if (facets.contains(XsdFacet::Pattern)) {
712         const XsdFacet::Ptr facet = facets.value(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(j)->as<DerivedString<TypeString> >()->stringValue();
717             QRegExp exp = PatternPlatform::parsePattern(pattern, m_context, m_reflection);
718             if (exp.exactMatch(lexicalValue)) {
719                 found = true;
720                 break;
721             }
722         }
723 
724         if (!found) {
725             errorMsg = QtXmlPatterns::tr("Double content does not match pattern facet.");
726             return false;
727         }
728     }
729     if (facets.contains(XsdFacet::Assertion)) {
730         //TODO: implement
731     }
732 
733     return true;
734 }
735 
checkConstrainingFacetsDecimal(const AtomicValue::Ptr & value,const QString & lexicalValue,const XsdFacet::Hash & facets,QString & errorMsg) const736 bool XsdTypeChecker::checkConstrainingFacetsDecimal(const AtomicValue::Ptr &value, const QString &lexicalValue, const XsdFacet::Hash &facets, QString &errorMsg) const
737 {
738     if (facets.contains(XsdFacet::FractionDigits)) {
739         const XsdFacet::Ptr facet = facets.value(XsdFacet::FractionDigits);
740         const DerivedInteger<TypePositiveInteger>::Ptr facetValue = facet->value();
741 
742         if (fractionDigitsForDecimal(lexicalValue) > facetValue->toInteger()) {
743             errorMsg = QtXmlPatterns::tr("Decimal content does not match in the fractionDigits facet.");
744             return false;
745         }
746     }
747     if (facets.contains(XsdFacet::TotalDigits)) {
748         const XsdFacet::Ptr facet = facets.value(XsdFacet::TotalDigits);
749         const DerivedInteger<TypePositiveInteger>::Ptr facetValue = facet->value();
750 
751         if (totalDigitsForDecimal(lexicalValue) > facetValue->toInteger()) {
752             errorMsg = QtXmlPatterns::tr("Decimal content does not match in the totalDigits facet.");
753             return false;
754         }
755     }
756 
757     return checkConstrainingFacetsDouble(value->as<Decimal>()->toDouble(), lexicalValue, facets, errorMsg);
758 }
759 
checkConstrainingFacetsDateTime(const QDateTime & value,const QString & lexicalValue,const XsdFacet::Hash & facets,const AnySimpleType::Ptr & type,QString & errorMsg) const760 bool XsdTypeChecker::checkConstrainingFacetsDateTime(const QDateTime &value, const QString &lexicalValue, const XsdFacet::Hash &facets, const AnySimpleType::Ptr &type, QString &errorMsg) const
761 {
762     if (facets.contains(XsdFacet::MaximumInclusive)) {
763         const XsdFacet::Ptr facet = facets.value(XsdFacet::MaximumInclusive);
764         const AbstractDateTime::Ptr facetValue = ValueFactory::fromLexical(facet->value()->as<DerivedString<TypeString> >()->stringValue(), type, m_context, m_reflection);
765         if (facetValue->toDateTime() < value) {
766             errorMsg = QtXmlPatterns::tr("Date time content does not match the maxInclusive facet.");
767             return false;
768         }
769     }
770     if (facets.contains(XsdFacet::MaximumExclusive)) {
771         const XsdFacet::Ptr facet = facets.value(XsdFacet::MaximumExclusive);
772         const AbstractDateTime::Ptr facetValue = ValueFactory::fromLexical(facet->value()->as<DerivedString<TypeString> >()->stringValue(), type, m_context, m_reflection);
773         if (facetValue->toDateTime() <= value) {
774             errorMsg = QtXmlPatterns::tr("Date time content does not match the maxExclusive facet.");
775             return false;
776         }
777     }
778     if (facets.contains(XsdFacet::MinimumInclusive)) {
779         const XsdFacet::Ptr facet = facets.value(XsdFacet::MinimumInclusive);
780         const AbstractDateTime::Ptr facetValue = ValueFactory::fromLexical(facet->value()->as<DerivedString<TypeString> >()->stringValue(), type, m_context, m_reflection);
781         if (facetValue->toDateTime() > value) {
782             errorMsg = QtXmlPatterns::tr("Date time content does not match the minInclusive facet.");
783             return false;
784         }
785     }
786     if (facets.contains(XsdFacet::MinimumExclusive)) {
787         const XsdFacet::Ptr facet = facets.value(XsdFacet::MinimumExclusive);
788         const AbstractDateTime::Ptr facetValue = ValueFactory::fromLexical(facet->value()->as<DerivedString<TypeString> >()->stringValue(), type, m_context, m_reflection);
789         if (facetValue->toDateTime() >= value) {
790             errorMsg = QtXmlPatterns::tr("Date time content does not match the minExclusive facet.");
791             return false;
792         }
793     }
794     if (facets.contains(XsdFacet::Enumeration)) {
795         const XsdFacet::Ptr facet = facets.value(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(multiValue.at(j)->as<DerivedString<TypeString> >()->stringValue(), type, m_context, m_reflection);
801             if (facetValue->toDateTime() == value) {
802                 found = true;
803                 break;
804             }
805         }
806 
807         if (!found) {
808             errorMsg = QtXmlPatterns::tr("Date time content is not listed in the enumeration facet.");
809             return false;
810         }
811     }
812     if (facets.contains(XsdFacet::Pattern)) {
813         const XsdFacet::Ptr facet = facets.value(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(j)->as<DerivedString<TypeString> >()->stringValue();
818             QRegExp exp = PatternPlatform::parsePattern(pattern, m_context, m_reflection);
819             if (exp.exactMatch(lexicalValue)) {
820                 found = true;
821                 break;
822             }
823         }
824 
825         if (!found) {
826             errorMsg = QtXmlPatterns::tr("Date time content does not match pattern facet.");
827             return false;
828         }
829     }
830 
831     return true;
832 }
833 
checkConstrainingFacetsDuration(const AtomicValue::Ptr &,const QString & lexicalValue,const XsdFacet::Hash & facets,QString & errorMsg) const834 bool XsdTypeChecker::checkConstrainingFacetsDuration(const AtomicValue::Ptr&, const QString &lexicalValue, const XsdFacet::Hash &facets, QString &errorMsg) const
835 {
836     if (facets.contains(XsdFacet::MaximumInclusive)) {
837         const XsdFacet::Ptr facet = facets.value(XsdFacet::MaximumInclusive);
838         const DerivedString<TypeString>::Ptr value = DerivedString<TypeString>::fromLexical(m_namePool, lexicalValue);
839 
840         if (XsdSchemaHelper::constructAndCompare(facets.value(XsdFacet::MaximumInclusive)->value(), AtomicComparator::OperatorLessThan, value, BuiltinTypes::xsDuration, m_context, m_reflection)) {
841             errorMsg = QtXmlPatterns::tr("Duration content does not match the maxInclusive facet.");
842             return false;
843         }
844     }
845     if (facets.contains(XsdFacet::MaximumExclusive)) {
846         const XsdFacet::Ptr facet = facets.value(XsdFacet::MaximumExclusive);
847         const DerivedString<TypeString>::Ptr value = DerivedString<TypeString>::fromLexical(m_namePool, lexicalValue);
848 
849         if (XsdSchemaHelper::constructAndCompare(facets.value(XsdFacet::MaximumExclusive)->value(), AtomicComparator::OperatorLessOrEqual, value, BuiltinTypes::xsDuration, m_context, m_reflection)) {
850             errorMsg = QtXmlPatterns::tr("Duration content does not match the maxExclusive facet.");
851             return false;
852         }
853     }
854     if (facets.contains(XsdFacet::MinimumInclusive)) {
855         const XsdFacet::Ptr facet = facets.value(XsdFacet::MinimumInclusive);
856         const DerivedString<TypeString>::Ptr value = DerivedString<TypeString>::fromLexical(m_namePool, lexicalValue);
857 
858         if (XsdSchemaHelper::constructAndCompare(facets.value(XsdFacet::MinimumInclusive)->value(), AtomicComparator::OperatorGreaterThan, value, BuiltinTypes::xsDuration, m_context, m_reflection)) {
859             errorMsg = QtXmlPatterns::tr("Duration content does not match the minInclusive facet.");
860             return false;
861         }
862     }
863     if (facets.contains(XsdFacet::MinimumExclusive)) {
864         const XsdFacet::Ptr facet = facets.value(XsdFacet::MinimumExclusive);
865         const DerivedString<TypeString>::Ptr value = DerivedString<TypeString>::fromLexical(m_namePool, lexicalValue);
866 
867         if (XsdSchemaHelper::constructAndCompare(facets.value(XsdFacet::MinimumExclusive)->value(), AtomicComparator::OperatorGreaterOrEqual, value, BuiltinTypes::xsDuration, m_context, m_reflection)) {
868             errorMsg = QtXmlPatterns::tr("Duration content does not match the minExclusive facet.");
869             return false;
870         }
871     }
872     if (facets.contains(XsdFacet::Enumeration)) {
873         const XsdFacet::Ptr facet = facets.value(XsdFacet::Enumeration);
874         const DerivedString<TypeString>::Ptr value = DerivedString<TypeString>::fromLexical(m_namePool, 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(multiValue.at(j), AtomicComparator::OperatorEqual, value, BuiltinTypes::xsDuration, m_context, m_reflection)) {
880                 found = true;
881                 break;
882             }
883         }
884 
885         if (!found) {
886             errorMsg = QtXmlPatterns::tr("Duration content is not listed in the enumeration facet.");
887             return false;
888         }
889     }
890     if (facets.contains(XsdFacet::Pattern)) {
891         const XsdFacet::Ptr facet = facets.value(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(j)->as<DerivedString<TypeString> >()->stringValue();
896             QRegExp exp = PatternPlatform::parsePattern(pattern, m_context, m_reflection);
897             if (exp.exactMatch(lexicalValue)) {
898                 found = true;
899                 break;
900             }
901         }
902 
903         if (!found) {
904             errorMsg = QtXmlPatterns::tr("Duration content does not match pattern facet.");
905             return false;
906         }
907     }
908     if (facets.contains(XsdFacet::Assertion)) {
909         //TODO: implement
910     }
911 
912     return true;
913 }
914 
checkConstrainingFacetsBoolean(bool,const QString & lexicalValue,const XsdFacet::Hash & facets,QString & errorMsg) const915 bool XsdTypeChecker::checkConstrainingFacetsBoolean(bool, const QString &lexicalValue, const XsdFacet::Hash &facets, QString &errorMsg) const
916 {
917     if (facets.contains(XsdFacet::Pattern)) {
918         const XsdFacet::Ptr facet = facets.value(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(j)->as<DerivedString<TypeString> >()->stringValue();
923             QRegExp exp = PatternPlatform::parsePattern(pattern, m_context, m_reflection);
924             if (exp.exactMatch(lexicalValue)) {
925                 found = true;
926                 break;
927             }
928         }
929 
930         if (!found) {
931             errorMsg = QtXmlPatterns::tr("Boolean content does not match pattern facet.");
932             return false;
933         }
934     }
935     if (facets.contains(XsdFacet::Assertion)) {
936         //TODO: implement
937     }
938 
939     return true;
940 }
941 
checkConstrainingFacetsBinary(const QByteArray & value,const XsdFacet::Hash & facets,const AnySimpleType::Ptr & type,QString & errorMsg) const942 bool XsdTypeChecker::checkConstrainingFacetsBinary(const QByteArray &value, const XsdFacet::Hash &facets, const AnySimpleType::Ptr &type, QString &errorMsg) const
943 {
944     if (facets.contains(XsdFacet::Length)) {
945         const XsdFacet::Ptr facet = facets.value(XsdFacet::Length);
946         const DerivedInteger<TypeNonNegativeInteger>::Ptr length = facet->value();
947         if (length->toInteger() != value.length()) {
948             errorMsg = QtXmlPatterns::tr("Binary content does not match the length facet.");
949             return false;
950         }
951     }
952     if (facets.contains(XsdFacet::MinimumLength)) {
953         const XsdFacet::Ptr facet = facets.value(XsdFacet::MinimumLength);
954         const DerivedInteger<TypeNonNegativeInteger>::Ptr length = facet->value();
955         if (length->toInteger() > value.length()) {
956             errorMsg = QtXmlPatterns::tr("Binary content does not match the minLength facet.");
957             return false;
958         }
959     }
960     if (facets.contains(XsdFacet::MaximumLength)) {
961         const XsdFacet::Ptr facet = facets.value(XsdFacet::MaximumLength);
962         const DerivedInteger<TypeNonNegativeInteger>::Ptr length = facet->value();
963         if (length->toInteger() < value.length()) {
964             errorMsg = QtXmlPatterns::tr("Binary content does not match the maxLength facet.");
965             return false;
966         }
967     }
968     if (facets.contains(XsdFacet::Enumeration)) {
969         const XsdFacet::Ptr facet = facets.value(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(multiValue.at(j)->as<DerivedString<TypeString> >()->stringValue(), type, m_context, 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("Binary content is not listed in the enumeration facet.");
983             return false;
984         }
985     }
986     if (facets.contains(XsdFacet::Pattern)) {
987         //TODO: implement
988     }
989     if (facets.contains(XsdFacet::Assertion)) {
990         //TODO: implement
991     }
992 
993     return true;
994 }
995 
checkConstrainingFacetsQName(const QXmlName & value,const QString & lexicalValue,const XsdFacet::Hash & facets,QString & errorMsg) const996 bool XsdTypeChecker::checkConstrainingFacetsQName(const QXmlName &value, const QString &lexicalValue, const XsdFacet::Hash &facets, QString &errorMsg) const
997 {
998     if (facets.contains(XsdFacet::Length)) {
999         // always true
1000     }
1001     if (facets.contains(XsdFacet::MinimumLength)) {
1002         // always true
1003     }
1004     if (facets.contains(XsdFacet::MaximumLength)) {
1005         // always true
1006     }
1007     if (facets.contains(XsdFacet::Enumeration)) {
1008         if (!XPathHelper::isQName(lexicalValue)) {
1009             errorMsg = QtXmlPatterns::tr("Invalid QName content: %1.").arg(formatData(lexicalValue));
1010             return false;
1011         }
1012 
1013         const XsdFacet::Ptr facet = facets.value(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(j)->as<QNameValue>()->qName();
1018 
1019             if (value == facetValue) {
1020                 found = true;
1021                 break;
1022             }
1023         }
1024 
1025         if (!found) {
1026             errorMsg = QtXmlPatterns::tr("QName content is not listed in the enumeration facet.");
1027             return false;
1028         }
1029     }
1030     if (facets.contains(XsdFacet::Pattern)) {
1031         const XsdFacet::Ptr facet = facets.value(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(j)->as<DerivedString<TypeString> >()->stringValue();
1036             QRegExp exp = PatternPlatform::parsePattern(pattern, m_context, m_reflection);
1037             if (exp.exactMatch(lexicalValue)) {
1038                 found = true;
1039                 break;
1040             }
1041         }
1042 
1043         if (!found) {
1044             errorMsg = QtXmlPatterns::tr("QName content does not match pattern facet.");
1045             return false;
1046         }
1047     }
1048     if (facets.contains(XsdFacet::Assertion)) {
1049         //TODO: implement
1050     }
1051 
1052     return true;
1053 }
1054 
checkConstrainingFacetsNotation(const QXmlName & value,const XsdFacet::Hash & facets,QString & errorMsg) const1055 bool XsdTypeChecker::checkConstrainingFacetsNotation(const QXmlName &value, const XsdFacet::Hash &facets, QString &errorMsg) const
1056 {
1057     if (facets.contains(XsdFacet::Length)) {
1058         // deprecated by spec
1059     }
1060     if (facets.contains(XsdFacet::MinimumLength)) {
1061         // deprecated by spec
1062     }
1063     if (facets.contains(XsdFacet::MaximumLength)) {
1064         // deprecated by spec
1065     }
1066     if (facets.contains(XsdFacet::Enumeration)) {
1067         const XsdFacet::Ptr facet = facets.value(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(j)->as<QNameValue>()->qName();
1072 
1073             if (value == facetValue) {
1074                 found = true;
1075                 break;
1076             }
1077         }
1078 
1079         if (!found) {
1080             errorMsg = QtXmlPatterns::tr("Notation content is not listed in the enumeration facet.");
1081             return false;
1082         }
1083     }
1084     if (facets.contains(XsdFacet::Pattern)) {
1085         //TODO: implement
1086     }
1087     if (facets.contains(XsdFacet::Assertion)) {
1088         //TODO: implement
1089     }
1090 
1091     return true;
1092 }
1093 
checkConstrainingFacetsList(const QStringList & values,const QString & lexicalValue,const AnySimpleType::Ptr & itemType,const XsdFacet::Hash & facets,QString & errorMsg) const1094 bool XsdTypeChecker::checkConstrainingFacetsList(const QStringList &values, const QString &lexicalValue, const AnySimpleType::Ptr &itemType, const XsdFacet::Hash &facets, QString &errorMsg) const
1095 {
1096     if (facets.contains(XsdFacet::Length)) {
1097         const DerivedInteger<TypeNonNegativeInteger>::Ptr value = facets.value(XsdFacet::Length)->value();
1098         if (value->toInteger() != values.count()) {
1099             errorMsg = QtXmlPatterns::tr("List content does not match length facet.");
1100             return false;
1101         }
1102     }
1103     if (facets.contains(XsdFacet::MinimumLength)) {
1104         const DerivedInteger<TypeNonNegativeInteger>::Ptr value = facets.value(XsdFacet::MinimumLength)->value();
1105         if (value->toInteger() > values.count()) {
1106             errorMsg = QtXmlPatterns::tr("List content does not match minLength facet.");
1107             return false;
1108         }
1109     }
1110     if (facets.contains(XsdFacet::MaximumLength)) {
1111         const DerivedInteger<TypeNonNegativeInteger>::Ptr value = facets.value(XsdFacet::MaximumLength)->value();
1112         if (value->toInteger() < values.count()) {
1113             errorMsg = QtXmlPatterns::tr("List content does not match maxLength facet.");
1114             return false;
1115         }
1116     }
1117     if (facets.contains(XsdFacet::Enumeration)) {
1118 
1119         bool found = false;
1120 
1121         // we have to handle lists with QName derived items differently
1122         if (BuiltinTypes::xsQName->wxsTypeMatches(itemType) || BuiltinTypes::xsNOTATION->wxsTypeMatches(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(convertToQName(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(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(QLatin1Char(' '), 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(convertToQName(facetValueList.at(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(j) != facetValues.at(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(DerivedString<TypeString>::fromLexical(m_namePool, 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(XsdFacet::Enumeration);
1169 
1170             const AnySimpleType::Ptr targetType = comparableType(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(QLatin1Char(' '), 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(DerivedString<TypeString>::fromLexical(m_namePool, facetValueList.at(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(instanceValues.at(j), AtomicComparator::OperatorEqual, facetValues.at(j), targetType, m_context, 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("List content is not listed in the enumeration facet.");
1204             return false;
1205         }
1206     }
1207     if (facets.contains(XsdFacet::Pattern)) {
1208         const XsdFacet::Ptr facet = facets.value(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(j)->as<DerivedString<TypeString> >()->stringValue();
1213             QRegExp exp = PatternPlatform::parsePattern(pattern, m_context, m_reflection);
1214             if (exp.exactMatch(lexicalValue)) {
1215                 found = true;
1216                 break;
1217             }
1218         }
1219 
1220         if (!found) {
1221             errorMsg = QtXmlPatterns::tr("List content does not match pattern facet.");
1222             return false;
1223         }
1224     }
1225     if (facets.contains(XsdFacet::Assertion)) {
1226         //TODO: implement
1227     }
1228 
1229     return true;
1230 }
1231 
checkConstrainingFacetsUnion(const QString & value,const QString & lexicalValue,const XsdSimpleType::Ptr & simpleType,const XsdFacet::Hash & facets,QString & errorMsg) const1232 bool XsdTypeChecker::checkConstrainingFacetsUnion(const QString &value, const QString &lexicalValue, const XsdSimpleType::Ptr &simpleType, const XsdFacet::Hash &facets, QString &errorMsg) const
1233 {
1234     if (facets.contains(XsdFacet::Enumeration)) {
1235         const AnySimpleType::List memberTypes = simpleType->memberTypes();
1236 
1237         const XsdFacet::Ptr facet = facets.value(XsdFacet::Enumeration);
1238 
1239         // convert the instance value into an atomic string value
1240         const DerivedString<TypeString>::Ptr valueString = DerivedString<TypeString>::fromLexical(m_namePool, 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(memberTypes.at(i));
1251             for (int j = 0; j < facetValues.count(); ++j) {
1252                 if (XsdSchemaHelper::constructAndCompare(valueString, AtomicComparator::OperatorEqual, facetValues.at(j), targetType, m_context, m_reflection)) {
1253                     found = true;
1254                     break;
1255                 }
1256             }
1257         }
1258 
1259         if (!found) {
1260             errorMsg = QtXmlPatterns::tr("Union content is not listed in the enumeration facet.");
1261             return false;
1262         }
1263     }
1264     if (facets.contains(XsdFacet::Pattern)) {
1265         const XsdFacet::Ptr facet = facets.value(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(j)->as<DerivedString<TypeString> >()->stringValue();
1270             QRegExp exp = PatternPlatform::parsePattern(pattern, m_context, m_reflection);
1271             if (exp.exactMatch(lexicalValue)) {
1272                 found = true;
1273                 break;
1274             }
1275         }
1276 
1277         if (!found) {
1278             errorMsg = QtXmlPatterns::tr("Union content does not match pattern facet.");
1279             return false;
1280         }
1281     }
1282     if (facets.contains(XsdFacet::Assertion)) {
1283         //TODO: implement
1284     }
1285 
1286     return true;
1287 }
1288 
fromLexical(const QString & value,const SchemaType::Ptr & type,const ReportContext::Ptr & context,const SourceLocationReflection * const reflection) const1289 AtomicValue::Ptr XsdTypeChecker::fromLexical(const QString &value, const SchemaType::Ptr &type, const ReportContext::Ptr &context, const SourceLocationReflection *const reflection) const
1290 {
1291     if (type->name(m_namePool) == BuiltinTypes::xsNOTATION->name(m_namePool) || type->name(m_namePool) == BuiltinTypes::xsQName->name(m_namePool)) {
1292         if (value.simplified().isEmpty())
1293             return ValidationError::createError(QtXmlPatterns::tr("Data of type %1 are not allowed to be empty.").arg(formatType(m_namePool, BuiltinTypes::xsNOTATION)));
1294 
1295         const QXmlName valueName = convertToQName(value);
1296         return QNameValue::fromValue(m_namePool, valueName);
1297     } else {
1298         return ValueFactory::fromLexical(value, type, context, reflection);
1299     }
1300 }
1301 
convertToQName(const QString & name) const1302 QXmlName XsdTypeChecker::convertToQName(const QString &name) const
1303 {
1304     const int pos = name.indexOf(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(name.left(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(name.mid(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(name);
1329     }
1330 
1331     return QXmlName(namespaceCode, localNameCode, prefixCode);
1332 }
1333 
1334 QT_END_NAMESPACE
1335