Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.Xml / System / Xml / Schema / FacetChecker.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="XmlSchemaFacet.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 // <owner current="true" primary="true">Microsoft</owner>
6 //------------------------------------------------------------------------------
7
8 namespace System.Xml.Schema {
9
10     using System;
11     using System.ComponentModel;
12     using System.Xml.Serialization;
13     using System.Xml.Schema;
14     using System.Xml.XPath;
15     using System.Diagnostics;
16     using System.Collections;
17     using System.Text;
18     using System.Text.RegularExpressions;
19     using System.Threading;
20     using System.Globalization;
21
22     /// <include file='doc\XmlSchemaFacet.uex' path='docs/doc[@for="XmlSchemaFacet"]/*' />
23     internal abstract class FacetsChecker {
24
25     private struct FacetsCompiler {
26         DatatypeImplementation datatype;
27         RestrictionFacets derivedRestriction;
28         
29         RestrictionFlags baseFlags; 
30         RestrictionFlags baseFixedFlags; 
31         RestrictionFlags validRestrictionFlags; 
32         
33         //Helpers
34         XmlSchemaDatatype nonNegativeInt; 
35         XmlSchemaDatatype builtInType;
36         XmlTypeCode builtInEnum;
37
38         bool firstPattern;
39         StringBuilder regStr;
40         XmlSchemaPatternFacet pattern_facet;
41
42         public FacetsCompiler(DatatypeImplementation baseDatatype, RestrictionFacets restriction) {
43             firstPattern = true;
44             regStr = null;
45             pattern_facet = null;
46             datatype = baseDatatype;
47             derivedRestriction = restriction;
48             baseFlags = datatype.Restriction != null ? datatype.Restriction.Flags : 0;
49             baseFixedFlags = datatype.Restriction != null ? datatype.Restriction.FixedFlags : 0;
50             validRestrictionFlags = datatype.ValidRestrictionFlags;
51             nonNegativeInt = DatatypeImplementation.GetSimpleTypeFromTypeCode(XmlTypeCode.NonNegativeInteger).Datatype;
52             builtInEnum = !(datatype is Datatype_union || datatype is Datatype_List) ? datatype.TypeCode : 0;
53             builtInType = (int)builtInEnum > 0 ? DatatypeImplementation.GetSimpleTypeFromTypeCode(builtInEnum).Datatype : datatype;
54         }
55
56         internal void CompileLengthFacet(XmlSchemaFacet facet) {
57             CheckProhibitedFlag(facet, RestrictionFlags.Length, Res.Sch_LengthFacetProhibited);
58             CheckDupFlag(facet, RestrictionFlags.Length, Res.Sch_DupLengthFacet);
59             derivedRestriction.Length = XmlBaseConverter.DecimalToInt32((decimal)ParseFacetValue(nonNegativeInt, facet, Res.Sch_LengthFacetInvalid, null, null));
60             
61             if ((baseFixedFlags & RestrictionFlags.Length) != 0) {
62                 if (!datatype.IsEqual(datatype.Restriction.Length, derivedRestriction.Length)) {
63                     throw new XmlSchemaException(Res.Sch_FacetBaseFixed, facet);
64                 }
65             }
66             if ((baseFlags & RestrictionFlags.Length) != 0) {
67                 if (datatype.Restriction.Length < derivedRestriction.Length) {
68                     throw new XmlSchemaException(Res.Sch_LengthGtBaseLength, facet);
69                 }
70             }
71             // If the base has the MinLength facet, check that our derived length is not violating it
72             if ((baseFlags & RestrictionFlags.MinLength) != 0) {
73                 if (datatype.Restriction.MinLength > derivedRestriction.Length) {
74                     throw new XmlSchemaException(Res.Sch_MaxMinLengthBaseLength, facet);
75                 }
76             }
77             // If the base has the MaxLength facet, check that our derived length is not violating it
78             if ((baseFlags & RestrictionFlags.MaxLength) != 0) {
79                 if (datatype.Restriction.MaxLength < derivedRestriction.Length) {
80                     throw new XmlSchemaException(Res.Sch_MaxMinLengthBaseLength, facet);
81                 }
82             }
83             SetFlag(facet, RestrictionFlags.Length);
84         }
85
86         internal void CompileMinLengthFacet(XmlSchemaFacet facet) {
87             CheckProhibitedFlag(facet, RestrictionFlags.MinLength, Res.Sch_MinLengthFacetProhibited);
88             CheckDupFlag(facet, RestrictionFlags.MinLength, Res.Sch_DupMinLengthFacet);
89             derivedRestriction.MinLength = XmlBaseConverter.DecimalToInt32((decimal)ParseFacetValue(nonNegativeInt, facet, Res.Sch_MinLengthFacetInvalid, null, null));
90             
91             if ((baseFixedFlags & RestrictionFlags.MinLength) != 0) {
92                 if (!datatype.IsEqual(datatype.Restriction.MinLength, derivedRestriction.MinLength)) {
93                     throw new XmlSchemaException(Res.Sch_FacetBaseFixed, facet);
94                 }
95             }
96             if ((baseFlags & RestrictionFlags.MinLength) != 0) {
97                 if (datatype.Restriction.MinLength > derivedRestriction.MinLength) {
98                     throw new XmlSchemaException(Res.Sch_MinLengthGtBaseMinLength, facet);
99                 }
100             }
101             if ((baseFlags & RestrictionFlags.Length) != 0) {
102                 if (datatype.Restriction.Length < derivedRestriction.MinLength) {
103                     throw new XmlSchemaException(Res.Sch_MaxMinLengthBaseLength, facet);
104                 }
105             }
106             SetFlag(facet, RestrictionFlags.MinLength);
107         }
108
109         internal void CompileMaxLengthFacet(XmlSchemaFacet facet) {
110             CheckProhibitedFlag(facet, RestrictionFlags.MaxLength, Res.Sch_MaxLengthFacetProhibited);
111             CheckDupFlag(facet, RestrictionFlags.MaxLength, Res.Sch_DupMaxLengthFacet);
112             derivedRestriction.MaxLength = XmlBaseConverter.DecimalToInt32((decimal)ParseFacetValue(nonNegativeInt, facet, Res.Sch_MaxLengthFacetInvalid, null, null));
113
114             if ((baseFixedFlags & RestrictionFlags.MaxLength) != 0) {
115                 if (!datatype.IsEqual(datatype.Restriction.MaxLength, derivedRestriction.MaxLength)) {
116                     throw new XmlSchemaException(Res.Sch_FacetBaseFixed, facet);
117                 }
118             }
119             if ((baseFlags & RestrictionFlags.MaxLength) != 0) {
120                 if (datatype.Restriction.MaxLength < derivedRestriction.MaxLength) {
121                     throw new XmlSchemaException(Res.Sch_MaxLengthGtBaseMaxLength, facet);
122                 }
123             }
124             if ((baseFlags & RestrictionFlags.Length) != 0) {
125                 if (datatype.Restriction.Length > derivedRestriction.MaxLength) {
126                     throw new XmlSchemaException(Res.Sch_MaxMinLengthBaseLength, facet);
127                 }
128             }
129             SetFlag(facet, RestrictionFlags.MaxLength);
130         }
131
132         internal void CompilePatternFacet(XmlSchemaPatternFacet facet) {
133             CheckProhibitedFlag(facet, RestrictionFlags.Pattern, Res.Sch_PatternFacetProhibited);
134             if(firstPattern == true) {
135                 regStr = new StringBuilder();
136                 regStr.Append("(");
137                 regStr.Append(facet.Value);
138                 pattern_facet = facet;
139                 firstPattern = false;
140             }
141             else {
142                 regStr.Append(")|(");
143                 regStr.Append(facet.Value);
144             }
145             SetFlag(facet, RestrictionFlags.Pattern);
146         }
147
148         internal void CompileEnumerationFacet(XmlSchemaFacet facet, IXmlNamespaceResolver nsmgr, XmlNameTable nameTable) {
149             CheckProhibitedFlag(facet, RestrictionFlags.Enumeration, Res.Sch_EnumerationFacetProhibited);
150             if (derivedRestriction.Enumeration == null) {
151                 derivedRestriction.Enumeration = new ArrayList();
152             }
153             derivedRestriction.Enumeration.Add(ParseFacetValue(datatype, facet, Res.Sch_EnumerationFacetInvalid, nsmgr, nameTable));
154             SetFlag(facet, RestrictionFlags.Enumeration);
155         }
156
157         internal void CompileWhitespaceFacet(XmlSchemaFacet facet) {
158             CheckProhibitedFlag(facet, RestrictionFlags.WhiteSpace, Res.Sch_WhiteSpaceFacetProhibited);
159             CheckDupFlag(facet, RestrictionFlags.WhiteSpace, Res.Sch_DupWhiteSpaceFacet);
160             if (facet.Value == "preserve") {
161                 derivedRestriction.WhiteSpace = XmlSchemaWhiteSpace.Preserve;
162             }
163             else if (facet.Value == "replace") {
164                 derivedRestriction.WhiteSpace = XmlSchemaWhiteSpace.Replace;
165             }
166             else if (facet.Value == "collapse") {
167                 derivedRestriction.WhiteSpace = XmlSchemaWhiteSpace.Collapse;
168             }
169             else {
170                 throw new XmlSchemaException(Res.Sch_InvalidWhiteSpace, facet.Value, facet);
171             }
172             if ((baseFixedFlags & RestrictionFlags.WhiteSpace) != 0) {
173                 if (!datatype.IsEqual(datatype.Restriction.WhiteSpace, derivedRestriction.WhiteSpace)) {
174                     throw new XmlSchemaException(Res.Sch_FacetBaseFixed, facet);
175                 }
176             }
177             //Check base and derived whitespace facets
178             XmlSchemaWhiteSpace baseWhitespace;
179             if ((baseFlags & RestrictionFlags.WhiteSpace) != 0) {
180                 baseWhitespace = datatype.Restriction.WhiteSpace;
181             }
182             else {
183                 baseWhitespace = datatype.BuiltInWhitespaceFacet;
184             }
185             if ( baseWhitespace == XmlSchemaWhiteSpace.Collapse &&
186                 (derivedRestriction.WhiteSpace == XmlSchemaWhiteSpace.Replace || derivedRestriction.WhiteSpace == XmlSchemaWhiteSpace.Preserve)
187             ) {
188                 throw new XmlSchemaException(Res.Sch_WhiteSpaceRestriction1, facet);
189             }
190             if (baseWhitespace == XmlSchemaWhiteSpace.Replace &&
191                 derivedRestriction.WhiteSpace == XmlSchemaWhiteSpace.Preserve
192             ) {
193                 throw new XmlSchemaException(Res.Sch_WhiteSpaceRestriction2, facet);
194             }
195             SetFlag(facet, RestrictionFlags.WhiteSpace);
196         }
197
198         internal void CompileMaxInclusiveFacet(XmlSchemaFacet facet) {
199             CheckProhibitedFlag(facet, RestrictionFlags.MaxInclusive, Res.Sch_MaxInclusiveFacetProhibited);
200             CheckDupFlag(facet, RestrictionFlags.MaxInclusive, Res.Sch_DupMaxInclusiveFacet);
201             derivedRestriction.MaxInclusive = ParseFacetValue(builtInType, facet, Res.Sch_MaxInclusiveFacetInvalid, null, null);
202             
203             if ((baseFixedFlags & RestrictionFlags.MaxInclusive) != 0) {
204                 if (!datatype.IsEqual(datatype.Restriction.MaxInclusive, derivedRestriction.MaxInclusive)) {
205                     throw new XmlSchemaException(Res.Sch_FacetBaseFixed, facet);
206                 }
207             }
208             CheckValue(derivedRestriction.MaxInclusive, facet);
209             SetFlag(facet, RestrictionFlags.MaxInclusive);
210         }
211
212         internal void CompileMaxExclusiveFacet(XmlSchemaFacet facet) {
213             CheckProhibitedFlag(facet, RestrictionFlags.MaxExclusive, Res.Sch_MaxExclusiveFacetProhibited);
214             CheckDupFlag(facet, RestrictionFlags.MaxExclusive, Res.Sch_DupMaxExclusiveFacet);
215             derivedRestriction.MaxExclusive = ParseFacetValue(builtInType, facet, Res.Sch_MaxExclusiveFacetInvalid, null, null);
216             
217             if ((baseFixedFlags & RestrictionFlags.MaxExclusive) != 0) {
218                 if (!datatype.IsEqual(datatype.Restriction.MaxExclusive, derivedRestriction.MaxExclusive)) {
219                     throw new XmlSchemaException(Res.Sch_FacetBaseFixed, facet);
220                 }
221             }
222             CheckValue(derivedRestriction.MaxExclusive, facet);
223             SetFlag(facet, RestrictionFlags.MaxExclusive);
224         }
225
226         internal void CompileMinInclusiveFacet(XmlSchemaFacet facet) {
227             CheckProhibitedFlag(facet, RestrictionFlags.MinInclusive, Res.Sch_MinInclusiveFacetProhibited);
228             CheckDupFlag(facet, RestrictionFlags.MinInclusive, Res.Sch_DupMinInclusiveFacet);
229             derivedRestriction.MinInclusive = ParseFacetValue(builtInType, facet, Res.Sch_MinInclusiveFacetInvalid, null, null);
230
231             if ((baseFixedFlags & RestrictionFlags.MinInclusive) != 0) {
232                 if (!datatype.IsEqual(datatype.Restriction.MinInclusive, derivedRestriction.MinInclusive)) {
233                     throw new XmlSchemaException(Res.Sch_FacetBaseFixed, facet);
234                 }
235             }
236             CheckValue(derivedRestriction.MinInclusive, facet);
237             SetFlag(facet, RestrictionFlags.MinInclusive);
238         }
239
240         internal void CompileMinExclusiveFacet(XmlSchemaFacet facet) {
241             CheckProhibitedFlag(facet, RestrictionFlags.MinExclusive, Res.Sch_MinExclusiveFacetProhibited);
242             CheckDupFlag(facet, RestrictionFlags.MinExclusive, Res.Sch_DupMinExclusiveFacet);
243             derivedRestriction.MinExclusive = ParseFacetValue(builtInType, facet, Res.Sch_MinExclusiveFacetInvalid, null, null);
244
245             if ((baseFixedFlags & RestrictionFlags.MinExclusive) != 0) {
246                 if (!datatype.IsEqual(datatype.Restriction.MinExclusive, derivedRestriction.MinExclusive)) {
247                     throw new XmlSchemaException(Res.Sch_FacetBaseFixed, facet);
248                 }
249             }
250             CheckValue(derivedRestriction.MinExclusive, facet);
251             SetFlag(facet, RestrictionFlags.MinExclusive);
252         }
253
254         internal void CompileTotalDigitsFacet(XmlSchemaFacet facet) {
255             CheckProhibitedFlag(facet, RestrictionFlags.TotalDigits, Res.Sch_TotalDigitsFacetProhibited);
256             CheckDupFlag(facet, RestrictionFlags.TotalDigits, Res.Sch_DupTotalDigitsFacet);
257             XmlSchemaDatatype positiveInt = DatatypeImplementation.GetSimpleTypeFromTypeCode(XmlTypeCode.PositiveInteger).Datatype;                        
258             derivedRestriction.TotalDigits = XmlBaseConverter.DecimalToInt32((decimal)ParseFacetValue(positiveInt, facet, Res.Sch_TotalDigitsFacetInvalid, null, null));
259             
260             if ((baseFixedFlags & RestrictionFlags.TotalDigits) != 0) {
261                 if (!datatype.IsEqual(datatype.Restriction.TotalDigits, derivedRestriction.TotalDigits)) {
262                     throw new XmlSchemaException(Res.Sch_FacetBaseFixed, facet);
263                 }
264             }
265             if ((baseFlags & RestrictionFlags.TotalDigits) != 0) {
266                 if(derivedRestriction.TotalDigits > datatype.Restriction.TotalDigits) {
267                     throw new XmlSchemaException(Res.Sch_TotalDigitsMismatch, string.Empty);
268                 }
269             }
270             SetFlag(facet, RestrictionFlags.TotalDigits);
271         }
272
273         internal void CompileFractionDigitsFacet(XmlSchemaFacet facet) {
274             CheckProhibitedFlag(facet, RestrictionFlags.FractionDigits, Res.Sch_FractionDigitsFacetProhibited);
275             CheckDupFlag(facet, RestrictionFlags.FractionDigits, Res.Sch_DupFractionDigitsFacet);
276             derivedRestriction.FractionDigits = XmlBaseConverter.DecimalToInt32((decimal)ParseFacetValue(nonNegativeInt, facet, Res.Sch_FractionDigitsFacetInvalid, null, null));
277
278             if ((derivedRestriction.FractionDigits != 0) && (datatype.TypeCode != XmlTypeCode.Decimal)) {
279                 throw new XmlSchemaException(Res.Sch_FractionDigitsFacetInvalid, Res.GetString(Res.Sch_FractionDigitsNotOnDecimal), facet);
280             }
281             if ((baseFlags & RestrictionFlags.FractionDigits) != 0) {
282                 if (derivedRestriction.FractionDigits > datatype.Restriction.FractionDigits) {
283                     throw new XmlSchemaException(Res.Sch_TotalDigitsMismatch, string.Empty);
284                 }
285             }
286             SetFlag(facet, RestrictionFlags.FractionDigits);
287         }
288
289         internal void FinishFacetCompile() {
290             //Additional check for pattern facet
291             //If facet is XMLSchemaPattern, then the String built inside the loop
292             //needs to be converted to a RegEx
293             if(firstPattern == false) {
294                 if (derivedRestriction.Patterns == null) {
295                     derivedRestriction.Patterns = new ArrayList();
296                 }
297                 try {
298                     regStr.Append(")");
299                     string tempStr = regStr.ToString();
300                     if(tempStr.IndexOf('|') != -1) { // ordinal compare
301                         regStr.Insert(0,"(");
302                         regStr.Append(")");
303                     }
304                    derivedRestriction.Patterns.Add(new Regex(Preprocess(regStr.ToString()), RegexOptions.None));
305
306                 } catch (Exception e) {
307                     throw new XmlSchemaException(Res.Sch_PatternFacetInvalid, new string[] {e.Message}, e, pattern_facet.SourceUri, pattern_facet.LineNumber, pattern_facet.LinePosition, pattern_facet);
308                 }
309             }
310         }
311
312         private void CheckValue(object value, XmlSchemaFacet facet) {
313             RestrictionFacets restriction = datatype.Restriction;
314             switch (facet.FacetType) {
315                 case FacetType.MaxInclusive:
316                     if ((baseFlags & RestrictionFlags.MaxInclusive) != 0) { //Base facet has maxInclusive
317                         if (datatype.Compare(value, restriction.MaxInclusive) > 0) {
318                             throw new XmlSchemaException(Res.Sch_MaxInclusiveMismatch, string.Empty);
319                         }
320                     }
321                     if ((baseFlags & RestrictionFlags.MaxExclusive) != 0) { //Base facet has maxExclusive
322                         if (datatype.Compare(value, restriction.MaxExclusive) >= 0) {
323                             throw new XmlSchemaException(Res.Sch_MaxIncExlMismatch, string.Empty);
324                         }
325                     }
326                 break;
327
328                 case FacetType.MaxExclusive:
329                     if ((baseFlags & RestrictionFlags.MaxExclusive) != 0) { //Base facet has maxExclusive
330                         if (datatype.Compare(value, restriction.MaxExclusive) > 0) {
331                             throw new XmlSchemaException(Res.Sch_MaxExclusiveMismatch, string.Empty);
332                         }
333                     }
334                     if ((baseFlags & RestrictionFlags.MaxInclusive) != 0) { //Base facet has maxInclusive
335                         if (datatype.Compare(value, restriction.MaxInclusive) > 0) {
336                             throw new XmlSchemaException(Res.Sch_MaxExlIncMismatch, string.Empty);
337                         }
338                     }
339                 break;
340
341                 case FacetType.MinInclusive:
342                     if ((baseFlags & RestrictionFlags.MinInclusive) != 0) { //Base facet has minInclusive
343                         if (datatype.Compare(value, restriction.MinInclusive) < 0) {
344                             throw new XmlSchemaException(Res.Sch_MinInclusiveMismatch, string.Empty);
345                         }
346                     }
347                     if ((baseFlags & RestrictionFlags.MinExclusive) != 0) { //Base facet has minExclusive
348                         if (datatype.Compare(value, restriction.MinExclusive) < 0) {
349                             throw new XmlSchemaException(Res.Sch_MinIncExlMismatch, string.Empty);
350                         }
351                     }
352                     if ((baseFlags & RestrictionFlags.MaxExclusive) != 0) { //Base facet has maxExclusive
353                         if (datatype.Compare(value, restriction.MaxExclusive) >= 0) {
354                             throw new XmlSchemaException(Res.Sch_MinIncMaxExlMismatch, string.Empty);
355                         }
356                     }
357                 break;
358
359                 case FacetType.MinExclusive:
360                     if ((baseFlags & RestrictionFlags.MinExclusive) != 0) { //Base facet has minExclusive
361                         if (datatype.Compare(value, restriction.MinExclusive) < 0) {
362                             throw new XmlSchemaException(Res.Sch_MinExclusiveMismatch, string.Empty);
363                         }
364                     }
365                     if ((baseFlags & RestrictionFlags.MinInclusive) != 0) { //Base facet has minInclusive
366                         if (datatype.Compare(value, restriction.MinInclusive) < 0) {
367                             throw new XmlSchemaException(Res.Sch_MinExlIncMismatch, string.Empty);
368                         }
369                     }
370                     if ((baseFlags & RestrictionFlags.MaxExclusive) != 0) { //Base facet has maxExclusive
371                         if (datatype.Compare(value, restriction.MaxExclusive) >= 0) {
372                             throw new XmlSchemaException(Res.Sch_MinExlMaxExlMismatch, string.Empty);
373                         }
374                     }
375                 break;
376
377                 default:
378                     Debug.Assert(false);
379                 break;
380             }
381         }
382
383         internal void CompileFacetCombinations() {
384             RestrictionFacets baseRestriction = datatype.Restriction;
385             //They are not allowed on the same type but allowed on derived types.
386             if (
387                 (derivedRestriction.Flags & RestrictionFlags.MaxInclusive) != 0 &&
388                 (derivedRestriction.Flags & RestrictionFlags.MaxExclusive) != 0
389             ) {
390                 throw new XmlSchemaException(Res.Sch_MaxInclusiveExclusive, string.Empty);
391             }
392             if (
393                 (derivedRestriction.Flags & RestrictionFlags.MinInclusive) != 0 &&
394                 (derivedRestriction.Flags & RestrictionFlags.MinExclusive) != 0
395             ) {
396                 throw new XmlSchemaException(Res.Sch_MinInclusiveExclusive, string.Empty);
397             }
398             if (
399                 (derivedRestriction.Flags & RestrictionFlags.Length) != 0 &&
400                 (derivedRestriction.Flags & (RestrictionFlags.MinLength|RestrictionFlags.MaxLength)) != 0
401             ) {
402                 throw new XmlSchemaException(Res.Sch_LengthAndMinMax, string.Empty);
403             }
404             
405             CopyFacetsFromBaseType();
406
407             // Check combinations
408             if (
409                 (derivedRestriction.Flags & RestrictionFlags.MinLength) != 0 &&
410                 (derivedRestriction.Flags & RestrictionFlags.MaxLength) != 0
411             ) {
412                 if (derivedRestriction.MinLength > derivedRestriction.MaxLength) {
413                     throw new XmlSchemaException(Res.Sch_MinLengthGtMaxLength, string.Empty);
414                 }
415             }
416
417             //
418             if (
419                 (derivedRestriction.Flags & RestrictionFlags.MinInclusive) != 0 &&
420                 (derivedRestriction.Flags & RestrictionFlags.MaxInclusive) != 0
421             ) {
422                 if (datatype.Compare(derivedRestriction.MinInclusive, derivedRestriction.MaxInclusive) > 0) {
423                     throw new XmlSchemaException(Res.Sch_MinInclusiveGtMaxInclusive, string.Empty);
424                 }
425             }
426             if (
427                 (derivedRestriction.Flags & RestrictionFlags.MinInclusive) != 0 &&
428                 (derivedRestriction.Flags & RestrictionFlags.MaxExclusive) != 0
429             ) {
430                 if (datatype.Compare(derivedRestriction.MinInclusive, derivedRestriction.MaxExclusive) > 0) {
431                     throw new XmlSchemaException(Res.Sch_MinInclusiveGtMaxExclusive, string.Empty);
432                 }
433             }
434             if (
435                 (derivedRestriction.Flags & RestrictionFlags.MinExclusive) != 0 &&
436                 (derivedRestriction.Flags & RestrictionFlags.MaxExclusive) != 0
437             ) {
438                 if (datatype.Compare(derivedRestriction.MinExclusive, derivedRestriction.MaxExclusive) > 0) {
439                     throw new XmlSchemaException(Res.Sch_MinExclusiveGtMaxExclusive, string.Empty);
440                 }
441             }
442             if (
443                 (derivedRestriction.Flags & RestrictionFlags.MinExclusive) != 0 &&
444                 (derivedRestriction.Flags & RestrictionFlags.MaxInclusive) != 0
445             ) {
446                 if (datatype.Compare(derivedRestriction.MinExclusive, derivedRestriction.MaxInclusive) > 0) {
447                     throw new XmlSchemaException(Res.Sch_MinExclusiveGtMaxInclusive, string.Empty);
448                 }
449             }
450             if ((derivedRestriction.Flags & (RestrictionFlags.TotalDigits|RestrictionFlags.FractionDigits)) == (RestrictionFlags.TotalDigits|RestrictionFlags.FractionDigits)) {
451                 if (derivedRestriction.FractionDigits > derivedRestriction.TotalDigits) {
452                     throw new XmlSchemaException(Res.Sch_FractionDigitsGtTotalDigits, string.Empty);
453                 }
454             }
455         }
456
457         private void CopyFacetsFromBaseType() {
458             RestrictionFacets baseRestriction = datatype.Restriction;
459             // Copy additional facets from the base type
460             if (
461                 (derivedRestriction.Flags & RestrictionFlags.Length) == 0 &&
462                 (baseFlags & RestrictionFlags.Length) != 0
463             ) {
464                 derivedRestriction.Length = baseRestriction.Length;
465                 SetFlag(RestrictionFlags.Length);
466             }
467             if (
468                 (derivedRestriction.Flags & RestrictionFlags.MinLength) == 0 &&
469                 (baseFlags & RestrictionFlags.MinLength) != 0
470             ) {
471                 derivedRestriction.MinLength = baseRestriction.MinLength;
472                 SetFlag(RestrictionFlags.MinLength);
473             }
474             if (
475                 (derivedRestriction.Flags & RestrictionFlags.MaxLength) == 0 &&
476                 (baseFlags & RestrictionFlags.MaxLength) != 0
477             ) {
478                 derivedRestriction.MaxLength = baseRestriction.MaxLength;
479                 SetFlag(RestrictionFlags.MaxLength);
480             }
481             if ((baseFlags & RestrictionFlags.Pattern) != 0) {
482                 if (derivedRestriction.Patterns == null) {
483                     derivedRestriction.Patterns = baseRestriction.Patterns;
484                 }
485                 else {
486                     derivedRestriction.Patterns.AddRange(baseRestriction.Patterns);
487                 }
488                 SetFlag(RestrictionFlags.Pattern);
489             }
490
491             if ((baseFlags & RestrictionFlags.Enumeration) != 0) {
492                 if (derivedRestriction.Enumeration == null) {
493                     derivedRestriction.Enumeration = baseRestriction.Enumeration;
494                 }
495                 SetFlag(RestrictionFlags.Enumeration);
496             }
497
498             if (
499                 (derivedRestriction.Flags & RestrictionFlags.WhiteSpace) == 0 &&
500                 (baseFlags & RestrictionFlags.WhiteSpace) != 0
501             ) {
502                 derivedRestriction.WhiteSpace = baseRestriction.WhiteSpace;
503                 SetFlag(RestrictionFlags.WhiteSpace);
504             }
505             if (
506                 (derivedRestriction.Flags & RestrictionFlags.MaxInclusive) == 0 &&
507                 (baseFlags & RestrictionFlags.MaxInclusive) != 0
508             ) {
509                 derivedRestriction.MaxInclusive = baseRestriction.MaxInclusive;
510                 SetFlag(RestrictionFlags.MaxInclusive);
511             }
512             if (
513                 (derivedRestriction.Flags & RestrictionFlags.MaxExclusive) == 0 &&
514                 (baseFlags & RestrictionFlags.MaxExclusive) != 0
515             ) {
516                 derivedRestriction.MaxExclusive = baseRestriction.MaxExclusive;
517                 SetFlag(RestrictionFlags.MaxExclusive);
518             }
519             if (
520                 (derivedRestriction.Flags & RestrictionFlags.MinInclusive) == 0 &&
521                 (baseFlags & RestrictionFlags.MinInclusive) != 0
522             ) {
523                 derivedRestriction.MinInclusive = baseRestriction.MinInclusive;
524                 SetFlag(RestrictionFlags.MinInclusive);
525             }
526             if (
527                 (derivedRestriction.Flags & RestrictionFlags.MinExclusive) == 0 &&
528                 (baseFlags & RestrictionFlags.MinExclusive) != 0
529             ) {
530                 derivedRestriction.MinExclusive = baseRestriction.MinExclusive;
531                 SetFlag(RestrictionFlags.MinExclusive);
532             }
533             if (
534                 (derivedRestriction.Flags & RestrictionFlags.TotalDigits) == 0 &&
535                 (baseFlags & RestrictionFlags.TotalDigits) != 0
536             ) {
537                 derivedRestriction.TotalDigits = baseRestriction.TotalDigits;
538                 SetFlag(RestrictionFlags.TotalDigits);
539             }
540             if (
541                 (derivedRestriction.Flags & RestrictionFlags.FractionDigits) == 0 &&
542                 (baseFlags & RestrictionFlags.FractionDigits) != 0
543             ) {
544                 derivedRestriction.FractionDigits = baseRestriction.FractionDigits;
545                 SetFlag(RestrictionFlags.FractionDigits);
546             }
547         }
548
549         private object ParseFacetValue(XmlSchemaDatatype datatype, XmlSchemaFacet facet, string code, IXmlNamespaceResolver nsmgr, XmlNameTable nameTable) {
550             object typedValue;
551             Exception ex = datatype.TryParseValue(facet.Value, nameTable, nsmgr, out typedValue);
552             if (ex == null) {
553                 return typedValue;
554             }
555             else {
556                 throw new XmlSchemaException(code, new string[] {ex.Message} , ex, facet.SourceUri, facet.LineNumber, facet.LinePosition, facet);
557             }
558         }
559
560         private struct Map {
561             internal Map(char m, string r) {
562                 match = m;
563                 replacement = r;
564             }
565             internal char match;
566             internal string replacement;
567         };
568
569         private static readonly Map[] c_map = {
570             new Map('c', "\\p{_xmlC}"),
571             new Map('C', "\\P{_xmlC}"),
572             new Map('d', "\\p{_xmlD}"),
573             new Map('D', "\\P{_xmlD}"),
574             new Map('i', "\\p{_xmlI}"),
575             new Map('I', "\\P{_xmlI}"),
576             new Map('w', "\\p{_xmlW}"),
577             new Map('W', "\\P{_xmlW}"),
578         };
579         private static string Preprocess(string pattern) {
580             StringBuilder bufBld = new StringBuilder();
581             bufBld.Append("^");
582
583             char[] source = pattern.ToCharArray();
584             int length = pattern.Length;
585             int copyPosition = 0;
586             for (int position = 0; position < length - 2; position ++) {
587                 if (source[position] == '\\') {
588                     if (source[position + 1] == '\\') {
589                         position ++; // skip it
590                     }
591                     else {
592                         char ch = source[position + 1];
593                         for (int i = 0; i < c_map.Length; i++) {
594                             if (c_map[i].match == ch) {
595                                 if (copyPosition < position) {
596                                     bufBld.Append(source, copyPosition, position - copyPosition);
597                                 }
598                                 bufBld.Append(c_map[i].replacement);
599                                 position ++;
600                                 copyPosition = position + 1;
601                                 break;
602                             }
603                         }
604                     }
605                 }
606             }
607             if (copyPosition < length) {
608                 bufBld.Append(source, copyPosition, length - copyPosition);
609             }
610
611             bufBld.Append("$");
612             return bufBld.ToString();
613         }
614
615         private void CheckProhibitedFlag(XmlSchemaFacet facet, RestrictionFlags flag, string errorCode) {
616             if ((validRestrictionFlags & flag) == 0) {
617                 throw new XmlSchemaException(errorCode, datatype.TypeCodeString, facet);
618             }
619         }
620
621         private void CheckDupFlag(XmlSchemaFacet facet, RestrictionFlags flag, string errorCode) {
622             if ((derivedRestriction.Flags & flag) != 0) {
623                 throw new XmlSchemaException(errorCode, facet);
624             }
625         }
626
627         private void SetFlag(XmlSchemaFacet facet, RestrictionFlags flag) {
628             derivedRestriction.Flags |= flag;
629             if (facet.IsFixed) {
630                 derivedRestriction.FixedFlags |= flag;
631             }
632         }
633
634         private void SetFlag(RestrictionFlags flag) {
635             derivedRestriction.Flags |= flag;
636             if ((baseFixedFlags & flag) != 0) {
637                 derivedRestriction.FixedFlags |= flag;
638             }
639         }
640
641     }
642         
643         internal virtual Exception CheckLexicalFacets(ref string parseString, XmlSchemaDatatype datatype) {
644             CheckWhitespaceFacets(ref parseString, datatype);
645             return CheckPatternFacets(datatype.Restriction, parseString);
646         }
647         internal virtual Exception CheckValueFacets(object value, XmlSchemaDatatype datatype) {
648             return null;
649         }
650         internal virtual Exception CheckValueFacets(decimal value, XmlSchemaDatatype datatype) {
651             return null;
652         }
653         internal virtual Exception CheckValueFacets(Int64 value, XmlSchemaDatatype datatype) {
654             return null;
655         }
656         internal virtual Exception CheckValueFacets(Int32 value, XmlSchemaDatatype datatype) {
657             return null;
658         }
659         internal virtual Exception CheckValueFacets(Int16 value, XmlSchemaDatatype datatype) {
660             return null;
661         }
662         internal virtual Exception CheckValueFacets(byte value, XmlSchemaDatatype datatype) {
663             return null;
664         }
665         internal virtual Exception CheckValueFacets(DateTime value, XmlSchemaDatatype datatype) {
666             return null;
667         }
668         internal virtual Exception CheckValueFacets(double value, XmlSchemaDatatype datatype) {
669             return null;
670         }
671         internal virtual Exception CheckValueFacets(float value, XmlSchemaDatatype datatype) {
672             return null;
673         }
674         internal virtual Exception CheckValueFacets(string value, XmlSchemaDatatype datatype) {
675             return null;
676         }
677         internal virtual Exception CheckValueFacets(byte[] value, XmlSchemaDatatype datatype) {
678             return null;
679         }
680         internal virtual Exception CheckValueFacets(TimeSpan value, XmlSchemaDatatype datatype) {
681             return null;
682         }
683         internal virtual Exception CheckValueFacets(XmlQualifiedName value, XmlSchemaDatatype datatype) {
684             return null;
685         }
686         
687         internal void CheckWhitespaceFacets(ref string s, XmlSchemaDatatype datatype) {
688             // before parsing, check whitespace facet
689             RestrictionFacets restriction = datatype.Restriction;
690
691             switch (datatype.Variety) {
692                 case XmlSchemaDatatypeVariety.List:
693                     s = s.Trim();
694                 break;
695
696                 case XmlSchemaDatatypeVariety.Atomic:
697                     if (datatype.BuiltInWhitespaceFacet == XmlSchemaWhiteSpace.Collapse) {
698                         s = XmlComplianceUtil.NonCDataNormalize(s);
699                     }
700                     else if (datatype.BuiltInWhitespaceFacet == XmlSchemaWhiteSpace.Replace) {
701                         s = XmlComplianceUtil.CDataNormalize(s);
702                     }
703                     else if (restriction != null && (restriction.Flags & RestrictionFlags.WhiteSpace) != 0) { //Restriction has whitespace facet specified
704                         if (restriction.WhiteSpace == XmlSchemaWhiteSpace.Replace) {
705                             s = XmlComplianceUtil.CDataNormalize(s);
706                         }
707                         else if (restriction.WhiteSpace == XmlSchemaWhiteSpace.Collapse) {
708                             s = XmlComplianceUtil.NonCDataNormalize(s);
709                         }
710                     }
711                 break;
712
713                 default:
714                 break;
715
716             }
717         }
718         internal Exception CheckPatternFacets(RestrictionFacets restriction, string value) {
719             if (restriction != null && (restriction.Flags & RestrictionFlags.Pattern) != 0) {
720                 for (int i = 0; i < restriction.Patterns.Count; ++i) {
721                     Regex regex = (Regex)restriction.Patterns[i];
722                     if (!regex.IsMatch(value)) {
723                         return new XmlSchemaException(Res.Sch_PatternConstraintFailed, string.Empty);
724                     }
725                 }
726             }
727             return null;
728         }
729         
730         internal virtual bool MatchEnumeration(object value, ArrayList enumeration, XmlSchemaDatatype datatype) {
731             return false;
732         }
733
734         //Compile-time Facet Checking
735         internal virtual RestrictionFacets ConstructRestriction(DatatypeImplementation datatype, XmlSchemaObjectCollection facets, XmlNameTable nameTable) {
736             //Datatype is the type on which this method is called
737             RestrictionFacets derivedRestriction = new RestrictionFacets();
738             FacetsCompiler facetCompiler = new FacetsCompiler(datatype, derivedRestriction);
739
740             for (int i = 0; i < facets.Count; ++i) {
741                 XmlSchemaFacet facet = (XmlSchemaFacet)facets[i];
742                 if (facet.Value == null) {
743                     throw new XmlSchemaException(Res.Sch_InvalidFacet, facet);
744                 }
745                 IXmlNamespaceResolver nsmgr = new SchemaNamespaceManager(facet);
746                 switch(facet.FacetType) {
747                     case FacetType.Length:
748                         facetCompiler.CompileLengthFacet(facet);
749                     break;
750
751                     case FacetType.MinLength:
752                         facetCompiler.CompileMinLengthFacet(facet);
753                     break;
754
755                     case FacetType.MaxLength:
756                         facetCompiler.CompileMaxLengthFacet(facet);
757                     break;
758     
759                     case FacetType.Pattern:
760                         facetCompiler.CompilePatternFacet(facet as XmlSchemaPatternFacet);
761                     break;
762
763                     case FacetType.Enumeration:
764                         facetCompiler.CompileEnumerationFacet(facet, nsmgr, nameTable);                        
765                     break;
766
767                     case FacetType.Whitespace:
768                         facetCompiler.CompileWhitespaceFacet(facet);
769                     break;
770
771                     case FacetType.MinInclusive:
772                         facetCompiler.CompileMinInclusiveFacet(facet);
773                     break;
774
775                     case FacetType.MinExclusive:
776                         facetCompiler.CompileMinExclusiveFacet(facet);
777                     break;
778
779                     case FacetType.MaxInclusive:
780                         facetCompiler.CompileMaxInclusiveFacet(facet);
781                     break;
782
783                     case FacetType.MaxExclusive:
784                         facetCompiler.CompileMaxExclusiveFacet(facet);
785                     break;
786
787                     case FacetType.TotalDigits:
788                         facetCompiler.CompileTotalDigitsFacet(facet);
789                     break;
790
791                     case FacetType.FractionDigits:
792                         facetCompiler.CompileFractionDigitsFacet(facet);
793                     break;
794
795                     default:
796                         throw new XmlSchemaException(Res.Sch_UnknownFacet, facet);
797                 }
798             }
799             facetCompiler.FinishFacetCompile();
800             facetCompiler.CompileFacetCombinations();
801             return derivedRestriction;
802         }
803
804         
805
806         
807
808         internal static decimal Power(int x, int y) {
809             //Returns X raised to the power Y
810             decimal returnValue = 1m;
811             decimal decimalValue = (decimal)x;
812             if ( y > 28 ) { //CLR decimal cannot handle more than 29 digits (10 power 28.)
813                 return decimal.MaxValue;
814             }
815             for (int i = 0; i < y; i++) {
816                 returnValue = returnValue * decimalValue;
817             }
818             return returnValue;
819         }
820     }
821     
822
823     internal class Numeric10FacetsChecker : FacetsChecker {
824         static readonly char[] signs = new char[] {'+', '-'};
825         decimal maxValue;
826         decimal minValue;
827
828         internal Numeric10FacetsChecker(decimal minVal, decimal maxVal) {
829             minValue = minVal;
830             maxValue = maxVal;
831         }
832         
833         internal override Exception CheckValueFacets(object value, XmlSchemaDatatype datatype) {
834
835             decimal decimalValue = datatype.ValueConverter.ToDecimal(value);
836             return CheckValueFacets(decimalValue, datatype);
837         }
838
839         internal override Exception CheckValueFacets(decimal value, XmlSchemaDatatype datatype) {
840             RestrictionFacets restriction = datatype.Restriction;
841             RestrictionFlags flags = restriction != null ? restriction.Flags : 0;
842             XmlValueConverter valueConverter = datatype.ValueConverter;
843             
844             //Check built-in facets
845             if (value > maxValue || value < minValue) {
846                 return new OverflowException(Res.GetString(Res.XmlConvert_Overflow, value.ToString(CultureInfo.InvariantCulture), datatype.TypeCodeString));
847             }
848             //Check user-defined facets
849             if (flags != 0) {
850                 if ((flags & RestrictionFlags.MaxInclusive) != 0) {
851                     if (value > valueConverter.ToDecimal(restriction.MaxInclusive)) {
852                         return new XmlSchemaException(Res.Sch_MaxInclusiveConstraintFailed, string.Empty);
853                     }
854                 }
855
856                 if ((flags & RestrictionFlags.MaxExclusive) != 0) {
857                     if (value >= valueConverter.ToDecimal(restriction.MaxExclusive)) {
858                         return new XmlSchemaException(Res.Sch_MaxExclusiveConstraintFailed, string.Empty);
859                     }
860                 }
861
862                 if ((flags & RestrictionFlags.MinInclusive) != 0) {
863                     if (value < valueConverter.ToDecimal(restriction.MinInclusive)) {
864                         return new XmlSchemaException(Res.Sch_MinInclusiveConstraintFailed, string.Empty);
865                     }
866                 }
867                 
868                 if ((flags & RestrictionFlags.MinExclusive) != 0) {
869                     if (value <= valueConverter.ToDecimal(restriction.MinExclusive)) {
870                         return new XmlSchemaException(Res.Sch_MinExclusiveConstraintFailed, string.Empty);
871                     }
872                 }
873                 if ((flags & RestrictionFlags.Enumeration) != 0) {
874                     if (!MatchEnumeration(value, restriction.Enumeration, valueConverter)) {
875                         return new XmlSchemaException(Res.Sch_EnumerationConstraintFailed, string.Empty);
876                     }
877                 }
878                 return CheckTotalAndFractionDigits(value, restriction.TotalDigits, restriction.FractionDigits, ((flags & RestrictionFlags.TotalDigits) != 0), ((flags & RestrictionFlags.FractionDigits) != 0));
879             }
880             return null;
881         }
882         
883         internal override Exception CheckValueFacets(Int64 value, XmlSchemaDatatype datatype) {
884             decimal decimalValue = (decimal)value;
885             return CheckValueFacets(decimalValue, datatype);
886         }
887
888         internal override Exception CheckValueFacets(Int32 value, XmlSchemaDatatype datatype) {
889             decimal decimalValue = (decimal)value;
890             return CheckValueFacets(decimalValue, datatype);
891         }
892         internal override Exception CheckValueFacets(Int16 value, XmlSchemaDatatype datatype) {
893             decimal decimalValue = (decimal)value;
894             return CheckValueFacets(decimalValue, datatype);
895         }
896         internal override Exception CheckValueFacets(byte value, XmlSchemaDatatype datatype) {
897             decimal decimalValue = (decimal)value;
898             return CheckValueFacets(decimalValue, datatype);
899         }
900         internal override bool MatchEnumeration(object value, ArrayList enumeration, XmlSchemaDatatype datatype) {
901             return MatchEnumeration(datatype.ValueConverter.ToDecimal(value), enumeration, datatype.ValueConverter);
902         }
903
904         internal bool MatchEnumeration(decimal value, ArrayList enumeration, XmlValueConverter valueConverter) {
905             for (int i = 0; i < enumeration.Count; ++i) {
906                 if (value == valueConverter.ToDecimal(enumeration[i])) {
907                     return true;
908                 }
909             }
910             return false;
911         }
912         internal Exception CheckTotalAndFractionDigits(decimal value, int totalDigits, int fractionDigits, bool checkTotal, bool checkFraction) {
913             decimal maxValue = FacetsChecker.Power(10, totalDigits) - 1; //(decimal)Math.Pow(10, totalDigits) - 1 ;
914             int powerCnt = 0;
915             if (value < 0) {
916                 value = Decimal.Negate(value); //Need to compare maxValue allowed against the absolute value
917             }
918             while (Decimal.Truncate(value) != value) { //Till it has a fraction
919                 value = value * 10;
920                 powerCnt++;
921             }
922         
923             if (checkTotal && (value > maxValue || powerCnt > totalDigits)) {
924                 return new XmlSchemaException(Res.Sch_TotalDigitsConstraintFailed, string.Empty);
925             }
926             if (checkFraction && powerCnt > fractionDigits) {
927                 return new XmlSchemaException(Res.Sch_FractionDigitsConstraintFailed, string.Empty);
928             }
929             return null;
930         }
931     }
932
933     
934     internal class Numeric2FacetsChecker : FacetsChecker {
935         
936         internal override Exception CheckValueFacets(object value, XmlSchemaDatatype datatype) {
937             double doubleValue = datatype.ValueConverter.ToDouble(value);
938             return CheckValueFacets(doubleValue, datatype);
939         }
940
941         internal override Exception CheckValueFacets(double value, XmlSchemaDatatype datatype) {
942             RestrictionFacets restriction = datatype.Restriction;
943             RestrictionFlags flags = restriction != null ? restriction.Flags : 0;
944             XmlValueConverter valueConverter = datatype.ValueConverter;
945
946             if ((flags & RestrictionFlags.MaxInclusive) != 0) {
947                 if (value > valueConverter.ToDouble(restriction.MaxInclusive)) {
948                     return new XmlSchemaException(Res.Sch_MaxInclusiveConstraintFailed, string.Empty);
949                 }
950             }
951             if ((flags & RestrictionFlags.MaxExclusive) != 0) {
952                 if (value >= valueConverter.ToDouble(restriction.MaxExclusive)) {
953                     return new XmlSchemaException(Res.Sch_MaxExclusiveConstraintFailed, string.Empty);
954                 }
955             }
956
957             if ((flags & RestrictionFlags.MinInclusive) != 0) {
958                 if (value < (valueConverter.ToDouble(restriction.MinInclusive))) {
959                     return new XmlSchemaException(Res.Sch_MinInclusiveConstraintFailed, string.Empty);
960                 }
961             }
962             
963             if ((flags & RestrictionFlags.MinExclusive) != 0) {
964                 if (value <= valueConverter.ToDouble(restriction.MinExclusive)) {
965                     return new XmlSchemaException(Res.Sch_MinExclusiveConstraintFailed, string.Empty);
966                 }
967             }
968             if ((flags & RestrictionFlags.Enumeration) != 0) {
969                 if (!MatchEnumeration(value, restriction.Enumeration, valueConverter)) {
970                     return new XmlSchemaException(Res.Sch_EnumerationConstraintFailed, string.Empty);
971                 }
972             }
973             return null;
974         }
975         
976         internal override Exception CheckValueFacets(float value, XmlSchemaDatatype datatype) {
977             double doubleValue = (double)value;
978             return CheckValueFacets(doubleValue, datatype);
979         }
980         internal override bool MatchEnumeration(object value, ArrayList enumeration, XmlSchemaDatatype datatype) {
981             return MatchEnumeration(datatype.ValueConverter.ToDouble(value), enumeration, datatype.ValueConverter);
982         }
983         private bool MatchEnumeration(double value, ArrayList enumeration, XmlValueConverter valueConverter) {
984             for (int i = 0; i < enumeration.Count; ++i) {
985                 if (value == valueConverter.ToDouble(enumeration[i])) {
986                     return true;
987                 }
988             }
989             return false;
990         }
991     }
992     
993     internal class DurationFacetsChecker: FacetsChecker {
994
995         internal override Exception CheckValueFacets(object value, XmlSchemaDatatype datatype) {
996             TimeSpan timeSpanValue = (TimeSpan)datatype.ValueConverter.ChangeType(value, typeof(TimeSpan));
997             return CheckValueFacets(timeSpanValue, datatype);
998         }
999
1000         internal override Exception CheckValueFacets(TimeSpan value, XmlSchemaDatatype datatype) {
1001             RestrictionFacets restriction = datatype.Restriction;
1002             RestrictionFlags flags = restriction != null ? restriction.Flags : 0;
1003
1004             if ((flags & RestrictionFlags.MaxInclusive) != 0) {
1005                 if (TimeSpan.Compare(value, (TimeSpan)restriction.MaxInclusive) > 0) {
1006                     return new XmlSchemaException(Res.Sch_MaxInclusiveConstraintFailed, string.Empty);
1007                 }
1008             }
1009             
1010             if ((flags & RestrictionFlags.MaxExclusive) != 0) {
1011                 if (TimeSpan.Compare(value, (TimeSpan)restriction.MaxExclusive) >= 0) {
1012                     return new XmlSchemaException(Res.Sch_MaxExclusiveConstraintFailed, string.Empty);
1013                 }
1014             }
1015             
1016             if ((flags & RestrictionFlags.MinInclusive) != 0) {
1017                 if (TimeSpan.Compare(value, (TimeSpan)restriction.MinInclusive) < 0) {
1018                     return new XmlSchemaException(Res.Sch_MinInclusiveConstraintFailed, string.Empty);
1019                 }
1020             }
1021             
1022             if ((flags & RestrictionFlags.MinExclusive) != 0) {
1023                 if (TimeSpan.Compare(value, (TimeSpan)restriction.MinExclusive) <= 0) {
1024                     return new XmlSchemaException(Res.Sch_MinExclusiveConstraintFailed, string.Empty);
1025                 }
1026             }
1027             if ((flags & RestrictionFlags.Enumeration) != 0) {
1028                 if (!MatchEnumeration(value, restriction.Enumeration)) {
1029                     return new XmlSchemaException(Res.Sch_EnumerationConstraintFailed, string.Empty);
1030                 }
1031             }
1032             return null;
1033         }
1034         internal override bool MatchEnumeration(object value, ArrayList enumeration, XmlSchemaDatatype datatype) {
1035             return MatchEnumeration((TimeSpan)value, enumeration);
1036         }
1037
1038         private bool MatchEnumeration(TimeSpan value, ArrayList enumeration) {
1039             for (int i = 0; i < enumeration.Count; ++i) {
1040                 if (TimeSpan.Compare(value, (TimeSpan)enumeration[i]) == 0) {
1041                     return true;
1042                 }
1043             }
1044             return false;
1045         }
1046     }
1047
1048     internal class DateTimeFacetsChecker: FacetsChecker {
1049         
1050         internal override Exception CheckValueFacets(object value, XmlSchemaDatatype datatype) {
1051             DateTime dateTimeValue = datatype.ValueConverter.ToDateTime(value);
1052             return CheckValueFacets(dateTimeValue, datatype);
1053         }
1054
1055         internal override Exception CheckValueFacets(DateTime value, XmlSchemaDatatype datatype) {
1056             RestrictionFacets restriction = datatype.Restriction;
1057             RestrictionFlags flags = restriction != null ? restriction.Flags : 0;
1058             
1059             if ((flags & RestrictionFlags.MaxInclusive) != 0) {
1060                 if (datatype.Compare(value, (DateTime)restriction.MaxInclusive) > 0) {
1061                     return new XmlSchemaException(Res.Sch_MaxInclusiveConstraintFailed, string.Empty);
1062                 }
1063             }
1064             
1065             if ((flags & RestrictionFlags.MaxExclusive) != 0) {
1066                 if (datatype.Compare(value, (DateTime)restriction.MaxExclusive) >= 0) {
1067                     return new XmlSchemaException(Res.Sch_MaxExclusiveConstraintFailed, string.Empty);
1068                 }
1069             }
1070             
1071             if ((flags & RestrictionFlags.MinInclusive) != 0) {
1072                 if (datatype.Compare(value, (DateTime)restriction.MinInclusive) < 0) {
1073                     return new XmlSchemaException(Res.Sch_MinInclusiveConstraintFailed, string.Empty);
1074                 } 
1075             }
1076             
1077             if ((flags & RestrictionFlags.MinExclusive) != 0) {
1078                 if (datatype.Compare(value, (DateTime)restriction.MinExclusive) <= 0) {
1079                     return new XmlSchemaException(Res.Sch_MinExclusiveConstraintFailed, string.Empty);
1080                 }
1081             }
1082             if ((flags & RestrictionFlags.Enumeration) != 0) {
1083                 if (!MatchEnumeration(value, restriction.Enumeration, datatype)) {
1084                     return new XmlSchemaException(Res.Sch_EnumerationConstraintFailed, string.Empty);
1085                 }
1086             }
1087             return null;
1088         }
1089
1090         internal override bool MatchEnumeration(object value, ArrayList enumeration, XmlSchemaDatatype datatype) {
1091             return MatchEnumeration(datatype.ValueConverter.ToDateTime(value), enumeration, datatype);
1092         }
1093
1094         private bool MatchEnumeration(DateTime value, ArrayList enumeration, XmlSchemaDatatype datatype) {
1095             for (int i = 0; i < enumeration.Count; ++i) {
1096                 if (datatype.Compare(value, (DateTime)enumeration[i]) == 0) {
1097                     return true;
1098                 }
1099             }
1100             return false;
1101         }
1102     }        
1103
1104     internal class StringFacetsChecker : FacetsChecker { //All types derived from string & anyURI
1105         static Regex languagePattern;
1106
1107         static Regex LanguagePattern {
1108             get {
1109                 if (languagePattern == null) {
1110                     Regex langRegex = new Regex("^([a-zA-Z]{1,8})(-[a-zA-Z0-9]{1,8})*$", RegexOptions.None);
1111                     Interlocked.CompareExchange(ref languagePattern, langRegex, null);
1112                 }
1113                 return languagePattern;
1114             }
1115         }
1116         
1117         internal override Exception CheckValueFacets(object value, XmlSchemaDatatype datatype) {
1118             string stringValue = datatype.ValueConverter.ToString(value);
1119             return CheckValueFacets(stringValue, datatype, true);
1120         }
1121
1122         internal override Exception CheckValueFacets(string value, XmlSchemaDatatype datatype) {
1123             return CheckValueFacets(value, datatype, true);
1124         }
1125
1126         internal Exception CheckValueFacets(string value, XmlSchemaDatatype datatype, bool verifyUri) {
1127             //Length, MinLength, MaxLength
1128             int length = value.Length;
1129             RestrictionFacets restriction = datatype.Restriction;
1130             RestrictionFlags flags = restriction != null ? restriction.Flags : 0;
1131             Exception exception;
1132             
1133             exception = CheckBuiltInFacets(value, datatype.TypeCode, verifyUri);
1134             if (exception != null) return exception;
1135
1136             if (flags != 0) {
1137                 if ((flags & RestrictionFlags.Length) != 0) {
1138                     if (restriction.Length != length) {
1139                         return new XmlSchemaException(Res.Sch_LengthConstraintFailed, string.Empty);
1140                     }
1141                 }
1142                 if ((flags & RestrictionFlags.MinLength) != 0) {
1143                     if (length < restriction.MinLength) {
1144                         return new XmlSchemaException(Res.Sch_MinLengthConstraintFailed, string.Empty);
1145                     }
1146                 }
1147                 if ((flags & RestrictionFlags.MaxLength) != 0) {
1148                     if (restriction.MaxLength < length) {
1149                         return new XmlSchemaException(Res.Sch_MaxLengthConstraintFailed, string.Empty);
1150                     }
1151                 }
1152                 if ((flags & RestrictionFlags.Enumeration) != 0) {
1153                     if (!MatchEnumeration(value, restriction.Enumeration, datatype)) {
1154                         return new XmlSchemaException(Res.Sch_EnumerationConstraintFailed, string.Empty);
1155                     }
1156                 }
1157             }
1158             return null;
1159         }
1160
1161         internal override bool MatchEnumeration(object value, ArrayList enumeration, XmlSchemaDatatype datatype) {
1162             return MatchEnumeration(datatype.ValueConverter.ToString(value), enumeration, datatype);
1163         }
1164
1165         private bool MatchEnumeration(string value, ArrayList enumeration, XmlSchemaDatatype datatype) {
1166             if (datatype.TypeCode == XmlTypeCode.AnyUri) {
1167                 for (int i = 0; i < enumeration.Count; ++i) {
1168                     if (value.Equals(((Uri)enumeration[i]).OriginalString)) {
1169                         return true;
1170                     }
1171                 }
1172             }
1173             else {
1174                 for (int i = 0; i < enumeration.Count; ++i) {
1175                     if (value.Equals((string)enumeration[i])) {
1176                         return true;
1177                     }
1178                 }
1179             }
1180             return false;
1181         }
1182
1183         private Exception CheckBuiltInFacets(string s, XmlTypeCode typeCode, bool verifyUri) {
1184             Exception exception = null;
1185
1186             switch (typeCode) {
1187
1188                 case XmlTypeCode.AnyUri:
1189                     if (verifyUri) {
1190                         Uri uri;
1191                         exception = XmlConvert.TryToUri(s, out uri);
1192                     }
1193                     break;
1194
1195                 case XmlTypeCode.NormalizedString:
1196                     exception = XmlConvert.TryVerifyNormalizedString(s);
1197                     break;
1198
1199                 case XmlTypeCode.Token:
1200                     exception = XmlConvert.TryVerifyTOKEN(s);
1201                     break;
1202
1203                 case XmlTypeCode.Language:
1204                     if (s == null || s.Length == 0) {
1205                         return new XmlSchemaException(Res.Sch_EmptyAttributeValue, string.Empty);
1206                     }
1207                     if (!LanguagePattern.IsMatch(s)) {
1208                         return new XmlSchemaException(Res.Sch_InvalidLanguageId, string.Empty);
1209                     }
1210                     break;
1211
1212                 case XmlTypeCode.NmToken:
1213                     exception = XmlConvert.TryVerifyNMTOKEN(s);
1214                     break;
1215
1216                 case XmlTypeCode.Name:
1217                     exception = XmlConvert.TryVerifyName(s);
1218                     break;
1219
1220                 case XmlTypeCode.NCName:
1221                 case XmlTypeCode.Id:
1222                 case XmlTypeCode.Idref:
1223                 case XmlTypeCode.Entity:
1224                     exception = XmlConvert.TryVerifyNCName(s);
1225                     break;
1226                 default:
1227                     break;
1228             }
1229             return exception;
1230         }
1231     }
1232     
1233     internal class QNameFacetsChecker : FacetsChecker {
1234
1235         internal override Exception CheckValueFacets(object value, XmlSchemaDatatype datatype) {
1236             XmlQualifiedName qualifiedNameValue = (XmlQualifiedName)datatype.ValueConverter.ChangeType(value, typeof(XmlQualifiedName));
1237             return CheckValueFacets(qualifiedNameValue, datatype);
1238         }
1239
1240         internal override Exception CheckValueFacets(XmlQualifiedName value, XmlSchemaDatatype datatype) {
1241             RestrictionFacets restriction = datatype.Restriction;
1242             RestrictionFlags flags = restriction != null ? restriction.Flags : 0;
1243             if (flags != 0) { //If there are facets defined
1244                 string strValue = value.ToString();
1245                 int length = strValue.Length;
1246                 if ((flags & RestrictionFlags.Length) != 0) {
1247                     if (restriction.Length != length) {
1248                         return new XmlSchemaException(Res.Sch_LengthConstraintFailed, string.Empty);
1249                     }
1250                 }
1251                 if ((flags & RestrictionFlags.MinLength) != 0) {
1252                     if (length < restriction.MinLength) {
1253                         return new XmlSchemaException(Res.Sch_MinLengthConstraintFailed, string.Empty);
1254                     }
1255                 }
1256                 if ((flags & RestrictionFlags.MaxLength) != 0) {
1257                     if (restriction.MaxLength < length) {
1258                         return new XmlSchemaException(Res.Sch_MaxLengthConstraintFailed, string.Empty);
1259                     }
1260                 }
1261                 if ((flags & RestrictionFlags.Enumeration) != 0) {
1262                     if (!MatchEnumeration(value, restriction.Enumeration)) {
1263                         return new XmlSchemaException(Res.Sch_EnumerationConstraintFailed, string.Empty);
1264                     }
1265                 }
1266             }
1267             return null;
1268         }
1269         internal override bool MatchEnumeration(object value, ArrayList enumeration, XmlSchemaDatatype datatype) {
1270             return MatchEnumeration((XmlQualifiedName)datatype.ValueConverter.ChangeType(value, typeof(XmlQualifiedName)), enumeration);
1271         }
1272
1273         private bool MatchEnumeration(XmlQualifiedName value, ArrayList enumeration) {
1274             for (int i = 0; i < enumeration.Count; ++i) {
1275                 if (value.Equals((XmlQualifiedName)enumeration[i])) {
1276                     return true;
1277                 }
1278             }
1279             return false;
1280         }
1281     }
1282
1283     internal class MiscFacetsChecker : FacetsChecker { //For bool, anySimpleType
1284     }
1285
1286     internal class BinaryFacetsChecker : FacetsChecker { //hexBinary & Base64Binary
1287         
1288         internal override Exception CheckValueFacets(object value, XmlSchemaDatatype datatype) {
1289             byte[] byteArrayValue = (byte[])value;
1290             return CheckValueFacets(byteArrayValue, datatype);
1291         }
1292
1293         internal override Exception CheckValueFacets(byte[] value, XmlSchemaDatatype datatype) {
1294             //Length, MinLength, MaxLength
1295             RestrictionFacets restriction = datatype.Restriction;
1296             int length = value.Length;
1297             RestrictionFlags flags = restriction != null ? restriction.Flags : 0;
1298             if (flags != 0) { //if it has facets defined
1299                 if ((flags & RestrictionFlags.Length) != 0) {
1300                     if (restriction.Length != length) {
1301                         return new XmlSchemaException(Res.Sch_LengthConstraintFailed, string.Empty);
1302                     }
1303                 }
1304                 if ((flags & RestrictionFlags.MinLength) != 0) {
1305                     if (length < restriction.MinLength) {
1306                         return new XmlSchemaException(Res.Sch_MinLengthConstraintFailed, string.Empty);
1307                     }
1308                 }
1309                 if ((flags & RestrictionFlags.MaxLength) != 0) {
1310                     if (restriction.MaxLength < length) {
1311                         return new XmlSchemaException(Res.Sch_MaxLengthConstraintFailed, string.Empty);
1312                     }
1313                 }
1314                 if ((flags & RestrictionFlags.Enumeration) != 0) {
1315                     if (!MatchEnumeration(value, restriction.Enumeration, datatype)) {
1316                         return new XmlSchemaException(Res.Sch_EnumerationConstraintFailed, string.Empty);
1317                     }
1318                 }
1319             }
1320             return null;
1321         }
1322         internal override bool MatchEnumeration(object value, ArrayList enumeration, XmlSchemaDatatype datatype) {
1323             return MatchEnumeration((byte[])value, enumeration, datatype);
1324         }
1325
1326         private bool MatchEnumeration(byte[] value, ArrayList enumeration, XmlSchemaDatatype datatype) {
1327             for (int i = 0; i < enumeration.Count; ++i) {
1328                 if (datatype.Compare(value, (byte[])enumeration[i]) == 0) {
1329                     return true;
1330                 }
1331             }
1332             return false;
1333         }
1334     }
1335     
1336     internal class ListFacetsChecker : FacetsChecker {
1337         
1338         internal override Exception CheckValueFacets(object value, XmlSchemaDatatype datatype) {
1339             //Check for facets allowed on lists - Length, MinLength, MaxLength
1340             Array values = value as Array;
1341             Debug.Assert(values != null);
1342
1343             RestrictionFacets restriction = datatype.Restriction;
1344             RestrictionFlags flags = restriction != null ? restriction.Flags : 0;
1345             
1346             if ((flags & (RestrictionFlags.Length|RestrictionFlags.MinLength|RestrictionFlags.MaxLength)) != 0) {
1347                 int length = values.Length;
1348                 if ((flags & RestrictionFlags.Length) != 0) {
1349                     if (restriction.Length != length) {
1350                         return new XmlSchemaException(Res.Sch_LengthConstraintFailed, string.Empty);
1351                     }
1352                 }
1353
1354                 if ((flags & RestrictionFlags.MinLength) != 0) {
1355                     if (length < restriction.MinLength) {
1356                         return new XmlSchemaException(Res.Sch_MinLengthConstraintFailed, string.Empty);
1357                     }
1358                 }
1359
1360                 if ((flags & RestrictionFlags.MaxLength) != 0) {
1361                     if (restriction.MaxLength < length) {
1362                         return new XmlSchemaException(Res.Sch_MaxLengthConstraintFailed, string.Empty);
1363                     }
1364                 }
1365             }
1366             if ((flags & RestrictionFlags.Enumeration) != 0) {
1367                 if (!MatchEnumeration(value, restriction.Enumeration, datatype)) {
1368                     return new XmlSchemaException(Res.Sch_EnumerationConstraintFailed, string.Empty);
1369                 }
1370             }
1371             return null;
1372         }
1373
1374         internal override bool MatchEnumeration(object value, ArrayList enumeration, XmlSchemaDatatype datatype) {
1375             for (int i = 0; i < enumeration.Count; ++i) {
1376                 if (datatype.Compare(value, enumeration[i]) == 0) {
1377                     return true;
1378                 }
1379             }
1380             return false;
1381         }
1382     }
1383
1384     internal class UnionFacetsChecker : FacetsChecker {
1385         
1386         internal override Exception CheckValueFacets(object value, XmlSchemaDatatype datatype) {
1387             RestrictionFacets restriction = datatype.Restriction;
1388             RestrictionFlags flags = restriction != null ? restriction.Flags : 0;
1389             
1390             if ((flags & RestrictionFlags.Enumeration) != 0) {
1391                 if (!MatchEnumeration(value, restriction.Enumeration, datatype)) {
1392                     return new XmlSchemaException(Res.Sch_EnumerationConstraintFailed, string.Empty);
1393                 }
1394             }
1395             return null;
1396         }
1397
1398         internal override bool MatchEnumeration(object value, ArrayList enumeration, XmlSchemaDatatype datatype) {
1399             for (int i = 0; i < enumeration.Count; ++i) {
1400                 if (datatype.Compare(value, enumeration[i]) == 0) { //Compare on Datatype_union will compare two XsdSimpleValue
1401                     return true;
1402                 }
1403             }
1404             return false;
1405         }
1406     }
1407 }