05b3b5784a18a5d629debaf1a8cdc2c0764f7577
[mono.git] / mcs / class / referencesource / System.Xml / System / Xml / Schema / XmlSchemaValidator.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="XmlSchemaValidator.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 // <owner current="true" primary="true">Microsoft</owner>
6 //------------------------------------------------------------------------------
7
8 using System;
9 using System.Collections;
10 using System.Collections.Generic;
11 using System.Text;
12 using System.IO;
13 using System.Diagnostics;
14 using System.Xml;
15 using System.Xml.Schema;
16 using System.Xml.XPath;
17 using System.Threading;
18 using System.Runtime.Versioning;
19
20 namespace System.Xml.Schema {
21
22     public delegate object XmlValueGetter();
23
24     [Flags]
25     public enum XmlSchemaValidationFlags {
26         None                         = 0x0000,
27         ProcessInlineSchema          = 0x0001,
28         ProcessSchemaLocation        = 0x0002,
29         ReportValidationWarnings     = 0x0004,
30         ProcessIdentityConstraints   = 0x0008,
31         AllowXmlAttributes           = 0x0010,
32     }
33
34     internal enum ValidatorState {
35         None,
36         Start,
37         TopLevelAttribute,
38         TopLevelTextOrWS,
39         Element,
40         Attribute,
41         EndOfAttributes,
42         Text,
43         Whitespace,
44         EndElement,
45         SkipToEndElement,
46         Finish,
47     }
48     internal class IdRefNode {
49         internal string Id;
50         internal int LineNo;
51         internal int LinePos;
52         internal IdRefNode Next;
53
54         internal IdRefNode(IdRefNode next, string id, int lineNo, int linePos) {
55             this.Id = id;
56             this.LineNo = lineNo;
57             this.LinePos = linePos;
58             this.Next = next;
59         }
60     }
61
62     public sealed class XmlSchemaValidator {
63
64         //Schema Set
65         private XmlSchemaSet        schemaSet;
66
67         //Validation Settings
68         private XmlSchemaValidationFlags validationFlags;
69
70         //Validation
71         private int                 startIDConstraint = -1;
72         private const int           STACK_INCREMENT = 10;
73         private bool                isRoot;
74         private bool                rootHasSchema;
75
76         //PSVI
77         private bool attrValid;
78         private bool checkEntity;
79
80         private SchemaInfo          compiledSchemaInfo;
81         private IDtdInfo            dtdSchemaInfo;
82         private Hashtable           validatedNamespaces;
83
84         private HWStack             validationStack;  // validaton contexts
85         private ValidationState     context;          // current context
86         private ValidatorState      currentState;
87
88         //Attributes & IDS
89         private Hashtable           attPresence;         //(AttName Vs AttIndex)
90         private SchemaAttDef        wildID;
91
92         private Hashtable           IDs;
93         private IdRefNode           idRefListHead;
94
95         //Parsing
96         XmlQualifiedName            contextQName;
97
98         //Avoid SchemaNames creation
99         private string              NsXs;
100         private string              NsXsi;
101         private string              NsXmlNs;
102         private string              NsXml;
103
104         //PartialValidation
105         private XmlSchemaObject     partialValidationType;
106
107         //text to typedValue
108         private StringBuilder       textValue;
109
110         //Other state
111         private ValidationEventHandler eventHandler;
112         private object validationEventSender;
113         private XmlNameTable nameTable;
114         private IXmlLineInfo positionInfo;
115         private IXmlLineInfo dummyPositionInfo;
116
117         private XmlResolver xmlResolver;
118         private Uri sourceUri;
119         private string sourceUriString;
120         private IXmlNamespaceResolver nsResolver;
121
122         private XmlSchemaContentProcessing processContents = XmlSchemaContentProcessing.Strict;
123
124         private static XmlSchemaAttribute xsiTypeSO;
125         private static XmlSchemaAttribute xsiNilSO;
126         private static XmlSchemaAttribute xsiSLSO;
127         private static XmlSchemaAttribute xsiNoNsSLSO;
128
129         //Xsi Attributes that are atomized
130         private string xsiTypeString;
131         private string xsiNilString;
132         private string xsiSchemaLocationString;
133         private string xsiNoNamespaceSchemaLocationString;
134
135         //Xsi Attributes parsing
136         private static readonly XmlSchemaDatatype dtQName = XmlSchemaDatatype.FromXmlTokenizedTypeXsd(XmlTokenizedType.QName);
137         private static readonly XmlSchemaDatatype dtCDATA = XmlSchemaDatatype.FromXmlTokenizedType(XmlTokenizedType.CDATA);
138         private static readonly XmlSchemaDatatype dtStringArray = dtCDATA.DeriveByList(null);
139
140         //Error message constants
141         private const string Quote = "'";
142
143         //Empty arrays
144         private static XmlSchemaParticle[] EmptyParticleArray = new XmlSchemaParticle[0];
145         private static XmlSchemaAttribute[] EmptyAttributeArray = new XmlSchemaAttribute[0];
146
147         //Whitespace check for text nodes
148         XmlCharType xmlCharType = XmlCharType.Instance;
149
150         internal static bool[,] ValidStates = new bool[12,12] {
151                                                /*ValidatorState.None*/      /*ValidatorState.Start  /*ValidatorState.TopLevelAttribute*/     /*ValidatorState.TopLevelTOrWS*/ /*ValidatorState.Element*/      /*ValidatorState.Attribute*/    /*ValidatorState.EndAttributes*/    /*ValidatorState.Text/      /*ValidatorState.WS/*       /*ValidatorState.EndElement*/   /*ValidatorState.SkipToEndElement*/         /*ValidatorState.Finish*/
152         /*ValidatorState.None*/             {  true,                        true,                     false,                                 false,                           false,                          false,                          false,                              false,                      false,                      false,                          false,                                      false},
153         /*ValidatorState.Start*/            {  false,                       true,                     true,                                  true,                            true,                           false,                          false,                              false,                      false,                      false,                          false,                                      true },
154         /*ValidatorState.TopLevelAttribute*/{  false,                       false,                    false,                                 false,                           false,                          false,                          false,                              false,                      false,                      false,                          false,                                      true },
155         /*ValidatorState.TopLevelTextOrWS*/ {  false,                       false,                    false,                                 true,                            true,                           false,                          false,                              false,                      false,                      false,                          false,                                      true },
156         /*ValidatorState.Element*/          {  false,                       false,                    false,                                 true,                            false,                          true,                           true,                               false,                      false,                      true,                           true,                                       false},
157         /*ValidatorState.Attribute*/        {  false,                       false,                    false,                                 false,                           false,                          true,                           true,                               false,                      false,                      true,                           true,                                       false},
158         /*ValidatorState.EndAttributes*/    {  false,                       false,                    false,                                 false,                           true,                           false,                          false,                              true,                       true,                       true,                           true,                                       false},
159         /*ValidatorState.Text*/             {  false,                       false,                    false,                                 false,                           true,                           false,                          false,                              true,                       true,                       true,                           true,                                       false},
160         /*ValidatorState.Whitespace*/       {  false,                       false,                    false,                                 false,                           true,                           false,                          false,                              true,                       true,                       true,                           true,                                       false},
161         /*ValidatorState.EndElement*/       {  false,                       false,                    false,                                 true,                            true,                           false,                          false,                              true,                       true,                       true,                           true /*?*/,                                 true },
162         /*ValidatorState.SkipToEndElement*/ {  false,                       false,                    false,                                 true,                            true,                           false,                          false,                              true,                       true,                       true,                           true,                                       true },
163         /*ValidatorState.Finish*/           {  false,                       true,                     false,                                 false,                           false,                          false,                          false,                              false,                      false,                      false,                          false,                                      false},
164         };
165
166         private static string[] MethodNames = new string[12] {"None", "Initialize", "top-level ValidateAttribute", "top-level ValidateText or ValidateWhitespace", "ValidateElement", "ValidateAttribute", "ValidateEndOfAttributes", "ValidateText", "ValidateWhitespace", "ValidateEndElement", "SkipToEndElement", "EndValidation" };
167
168         public XmlSchemaValidator(XmlNameTable nameTable, XmlSchemaSet schemas, IXmlNamespaceResolver namespaceResolver, XmlSchemaValidationFlags validationFlags) {
169             if (nameTable == null) {
170                 throw new ArgumentNullException("nameTable");
171             }
172             if (schemas == null) {
173                 throw new ArgumentNullException("schemas");
174             }
175             if (namespaceResolver == null) {
176                 throw new ArgumentNullException("namespaceResolver");
177             }
178             this.nameTable = nameTable;
179             this.nsResolver = namespaceResolver;
180             this.validationFlags = validationFlags;
181
182
183             if ( ((validationFlags & XmlSchemaValidationFlags.ProcessInlineSchema) != 0) || ((validationFlags & XmlSchemaValidationFlags.ProcessSchemaLocation) != 0) ) { //Process schema hints in xml document, hence user's set might change
184                 this.schemaSet = new XmlSchemaSet(nameTable);
185                 this.schemaSet.ValidationEventHandler += schemas.GetEventHandler();
186                 this.schemaSet.CompilationSettings = schemas.CompilationSettings;
187                 this.schemaSet.XmlResolver = schemas.GetResolver();
188                 this.schemaSet.Add(schemas);
189                 validatedNamespaces = new Hashtable();
190             }
191             else { //Use the same set from the user
192                 this.schemaSet = schemas;
193             }
194             Init();
195         }
196
197         private void Init() {
198             validationStack = new HWStack(STACK_INCREMENT);
199             attPresence = new Hashtable();
200             Push(XmlQualifiedName.Empty);
201
202             dummyPositionInfo = new PositionInfo(); //Dummy position info, will return (0,0) if user does not set the LineInfoProvider property
203             positionInfo = dummyPositionInfo;
204             validationEventSender = this;
205             currentState = ValidatorState.None;
206             textValue = new StringBuilder(100);
207             xmlResolver = System.Xml.XmlConfiguration.XmlReaderSection.CreateDefaultResolver();
208             contextQName = new XmlQualifiedName(); //Re-use qname
209             Reset();
210
211             RecompileSchemaSet(); //Gets compiled info from set as well
212             //Get already Atomized strings
213             NsXs = nameTable.Add(XmlReservedNs.NsXs);
214             NsXsi = nameTable.Add(XmlReservedNs.NsXsi);
215             NsXmlNs = nameTable.Add(XmlReservedNs.NsXmlNs);
216             NsXml = nameTable.Add(XmlReservedNs.NsXml);
217             xsiTypeString = nameTable.Add("type");
218             xsiNilString = nameTable.Add("nil");
219             xsiSchemaLocationString = nameTable.Add("schemaLocation");
220             xsiNoNamespaceSchemaLocationString = nameTable.Add("noNamespaceSchemaLocation");
221         }
222
223         private void Reset() {
224             isRoot = true;
225             rootHasSchema = true;
226             while(validationStack.Length > 1) { //Clear all other context from stack
227                 validationStack.Pop();
228             }
229             startIDConstraint = -1;
230             partialValidationType = null;
231
232             //Clear previous tables
233             if (IDs != null) {
234                 IDs.Clear();
235             }
236             if (ProcessSchemaHints) {
237                 validatedNamespaces.Clear();
238             }
239         }
240
241 //Properties
242         public XmlResolver XmlResolver {
243             set {
244                 xmlResolver = value;
245             }
246         }
247
248         public IXmlLineInfo LineInfoProvider {
249             get {
250                 return positionInfo;
251             }
252             set {
253                 if (value == null) { //If value is null, retain the default dummy line info
254                     this.positionInfo = dummyPositionInfo;
255                 }
256                 else {
257                     this.positionInfo = value;
258                 }
259             }
260         }
261
262         public Uri SourceUri {
263             get {
264                 return sourceUri;
265             }
266             set {
267                 sourceUri = value;
268                 sourceUriString = sourceUri.ToString();
269             }
270         }
271
272         public object ValidationEventSender {
273             get {
274                 return validationEventSender;
275             }
276             set {
277                 validationEventSender = value;
278             }
279         }
280
281         public event ValidationEventHandler ValidationEventHandler {
282             add {
283                 eventHandler += value;
284             }
285             remove {
286                 eventHandler -= value;
287             }
288         }
289
290 //Methods
291
292         public void AddSchema(XmlSchema schema) {
293             if (schema == null) {
294                 throw new ArgumentNullException("schema");
295             }
296             if ((validationFlags & XmlSchemaValidationFlags.ProcessInlineSchema) == 0) { //Do not process schema if processInlineSchema is not set
297                 return;
298             }
299             string tns = schema.TargetNamespace;
300             if (tns == null) {
301                 tns = string.Empty;
302             }
303             //Store the previous locations
304             Hashtable schemaLocations = schemaSet.SchemaLocations;
305             DictionaryEntry[] oldLocations = new DictionaryEntry[schemaLocations.Count];
306             schemaLocations.CopyTo(oldLocations, 0);
307
308             //
309             Debug.Assert(validatedNamespaces != null);
310             if (validatedNamespaces[tns] != null && schemaSet.FindSchemaByNSAndUrl(schema.BaseUri, tns, oldLocations) == null) {
311                 SendValidationEvent(Res.Sch_ComponentAlreadySeenForNS, tns, XmlSeverityType.Error);
312             }
313             if (schema.ErrorCount == 0) {
314                 try {
315                     schemaSet.Add(schema);
316                     RecompileSchemaSet();
317                 }
318                 catch(XmlSchemaException e) {
319                     SendValidationEvent(Res.Sch_CannotLoadSchema, new string[] {schema.BaseUri.ToString(), e.Message},e);
320                 }
321                 for (int i = 0; i < schema.ImportedSchemas.Count; ++i) {     //Check for its imports
322                     XmlSchema impSchema = (XmlSchema)schema.ImportedSchemas[i];
323                     tns = impSchema.TargetNamespace;
324                     if (tns == null) {
325                         tns = string.Empty;
326                     }
327                     if (validatedNamespaces[tns] != null && schemaSet.FindSchemaByNSAndUrl(impSchema.BaseUri, tns, oldLocations) == null) {
328                         SendValidationEvent(Res.Sch_ComponentAlreadySeenForNS, tns, XmlSeverityType.Error);
329                         schemaSet.RemoveRecursive(schema);
330                         break;
331                     }
332                 }
333             }
334         }
335
336         public void Initialize() {
337             if (currentState != ValidatorState.None && currentState != ValidatorState.Finish) {
338                 throw new InvalidOperationException(Res.GetString(Res.Sch_InvalidStateTransition, new string[] { MethodNames[(int)currentState], MethodNames[(int)ValidatorState.Start] }));
339             }
340             currentState = ValidatorState.Start;
341             Reset();
342         }
343
344         public void Initialize(XmlSchemaObject partialValidationType) {
345             if (currentState != ValidatorState.None && currentState != ValidatorState.Finish) {
346                 throw new InvalidOperationException(Res.GetString(Res.Sch_InvalidStateTransition, new string[] { MethodNames[(int)currentState], MethodNames[(int)ValidatorState.Start] }));
347             }
348             if (partialValidationType == null) {
349                 throw new ArgumentNullException("partialValidationType");
350             }
351             if (!(partialValidationType is XmlSchemaElement || partialValidationType is XmlSchemaAttribute || partialValidationType is XmlSchemaType)) {
352                 throw new ArgumentException(Res.GetString(Res.Sch_InvalidPartialValidationType));
353             }
354             currentState = ValidatorState.Start;
355             Reset();
356             this.partialValidationType = partialValidationType;
357         }
358
359         // SxS: This method passes null as resource names and does not expose any resources to the caller.
360         // It's OK to suppress the SxS warning.
361         [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
362         [ResourceExposure(ResourceScope.None)]
363         public void ValidateElement(string localName, string namespaceUri, XmlSchemaInfo schemaInfo)  {
364             ValidateElement(localName, namespaceUri, schemaInfo, null, null, null, null);
365         }
366
367         [ResourceConsumption(ResourceScope.Machine)]
368         [ResourceExposure(ResourceScope.Machine)]
369         public void ValidateElement(string localName, string namespaceUri, XmlSchemaInfo schemaInfo, string xsiType, string xsiNil, string xsiSchemaLocation, string xsiNoNamespaceSchemaLocation)  {
370             if (localName == null) {
371                 throw new ArgumentNullException("localName");
372             }
373             if (namespaceUri == null) {
374                 throw new ArgumentNullException("namespaceUri");
375             }
376
377             CheckStateTransition(ValidatorState.Element, MethodNames[(int)ValidatorState.Element]);
378
379             ClearPSVI();
380             contextQName.Init(localName, namespaceUri);
381             XmlQualifiedName elementName = contextQName;
382
383             bool invalidElementInContext;
384             object particle = ValidateElementContext(elementName, out invalidElementInContext); //Check element name is allowed in current position
385             SchemaElementDecl elementDecl = FastGetElementDecl(elementName, particle);
386
387             //Change context to current element and update element decl
388             Push(elementName);
389
390             //Change current context's error state depending on whether this element was validated in its context correctly
391             if (invalidElementInContext) {
392                 context.Validity = XmlSchemaValidity.Invalid;
393             }
394
395             //Check if there are Xsi attributes
396             if ((validationFlags & XmlSchemaValidationFlags.ProcessSchemaLocation) != 0 && xmlResolver != null) { //we should process schema location
397                 ProcessSchemaLocations(xsiSchemaLocation, xsiNoNamespaceSchemaLocation);
398             }
399
400             if (processContents != XmlSchemaContentProcessing.Skip) {
401                 if (elementDecl == null && partialValidationType == null) { //Since new schemaLocations might have been added, try for decl from the set again only if no PVType is set
402                     elementDecl = compiledSchemaInfo.GetElementDecl(elementName);
403                 }
404                 bool declFound = elementDecl != null;
405                 if (xsiType != null || xsiNil != null) {
406                     elementDecl = CheckXsiTypeAndNil(elementDecl, xsiType, xsiNil, ref declFound);
407                 }
408                 if (elementDecl == null) {
409                     ThrowDeclNotFoundWarningOrError(declFound); //This updates processContents
410                 }
411             }
412
413             context.ElementDecl = elementDecl;
414             XmlSchemaElement localSchemaElement = null;
415             XmlSchemaType localSchemaType = null;
416             if (elementDecl != null) {
417                 CheckElementProperties();
418                 attPresence.Clear(); //Clear attributes hashtable for every element
419                 context.NeedValidateChildren = processContents != XmlSchemaContentProcessing.Skip;
420                 ValidateStartElementIdentityConstraints();  //Need attr collection validated here
421                 elementDecl.ContentValidator.InitValidation(context);
422
423                 localSchemaType = elementDecl.SchemaType;
424                 localSchemaElement = GetSchemaElement();
425             }
426
427             if (schemaInfo != null) {
428                 schemaInfo.SchemaType = localSchemaType;
429                 schemaInfo.SchemaElement = localSchemaElement;
430                 schemaInfo.IsNil = context.IsNill;
431                 schemaInfo.Validity = context.Validity;
432             }
433             if (ProcessSchemaHints) {
434                 if (validatedNamespaces[namespaceUri] == null) {
435                     validatedNamespaces.Add(namespaceUri, namespaceUri);
436                 }
437             }
438
439             if (isRoot) {
440                 isRoot = false;
441             }
442         }
443
444         public object ValidateAttribute(string localName, string namespaceUri, string attributeValue, XmlSchemaInfo schemaInfo) {
445             if (attributeValue == null) {
446                 throw new ArgumentNullException("attributeValue");
447             }
448             return ValidateAttribute(localName, namespaceUri, null, attributeValue, schemaInfo);
449         }
450
451         public object ValidateAttribute(string localName, string namespaceUri, XmlValueGetter attributeValue, XmlSchemaInfo schemaInfo) {
452             if (attributeValue == null) {
453                 throw new ArgumentNullException("attributeValue");
454             }
455             return ValidateAttribute(localName, namespaceUri, attributeValue, null, schemaInfo);
456         }
457
458         private object ValidateAttribute(string lName, string ns, XmlValueGetter attributeValueGetter, string attributeStringValue, XmlSchemaInfo schemaInfo) {
459             if (lName == null) {
460                 throw new ArgumentNullException("localName");
461             }
462             if (ns == null) {
463                 throw new ArgumentNullException("namespaceUri");
464             }
465
466             ValidatorState toState = validationStack.Length > 1 ? ValidatorState.Attribute : ValidatorState.TopLevelAttribute;
467             CheckStateTransition(toState, MethodNames[(int)toState]);
468
469             object typedVal = null;
470             attrValid = true;
471             XmlSchemaValidity localValidity = XmlSchemaValidity.NotKnown;
472             XmlSchemaAttribute localAttribute = null;
473             XmlSchemaSimpleType localMemberType = null;
474
475             ns = nameTable.Add(ns);
476             if(Ref.Equal(ns,NsXmlNs)) {
477                 return null;
478             }
479
480             SchemaAttDef attributeDef = null;
481             SchemaElementDecl currentElementDecl = context.ElementDecl;
482             XmlQualifiedName attQName = new XmlQualifiedName(lName, ns);
483             if (attPresence[attQName] != null) { //this attribute already checked as it is duplicate;
484                 SendValidationEvent(Res.Sch_DuplicateAttribute, attQName.ToString());
485                 if (schemaInfo != null) {
486                     schemaInfo.Clear();
487                 }
488                 return null;
489             }
490
491             if (!Ref.Equal(ns,NsXsi)) { //
492                 XmlSchemaObject pvtAttribute = currentState == ValidatorState.TopLevelAttribute ? partialValidationType : null;
493                 AttributeMatchState attributeMatchState;
494                 attributeDef = compiledSchemaInfo.GetAttributeXsd(currentElementDecl, attQName, pvtAttribute, out attributeMatchState);
495
496                 switch (attributeMatchState) {
497                     case AttributeMatchState.UndeclaredElementAndAttribute:
498                         if((attributeDef = CheckIsXmlAttribute(attQName)) != null) { //Try for xml attribute
499                             goto case AttributeMatchState.AttributeFound;
500                         }
501                         if (currentElementDecl == null
502                             && processContents == XmlSchemaContentProcessing.Strict
503                             && attQName.Namespace.Length != 0
504                             && compiledSchemaInfo.Contains(attQName.Namespace)
505                         ) {
506                             attrValid = false;
507                             SendValidationEvent(Res.Sch_UndeclaredAttribute, attQName.ToString());
508                         }
509                         else if (processContents != XmlSchemaContentProcessing.Skip) {
510                             SendValidationEvent(Res.Sch_NoAttributeSchemaFound, attQName.ToString(), XmlSeverityType.Warning);
511                         }
512                         break;
513
514                     case AttributeMatchState.UndeclaredAttribute:
515                         if((attributeDef = CheckIsXmlAttribute(attQName)) != null) {
516                             goto case AttributeMatchState.AttributeFound;
517                         }
518                         else {
519                             attrValid = false;
520                             SendValidationEvent(Res.Sch_UndeclaredAttribute, attQName.ToString());
521                         }
522                         break;
523
524                     case AttributeMatchState.ProhibitedAnyAttribute:
525                         if((attributeDef = CheckIsXmlAttribute(attQName)) != null) {
526                             goto case AttributeMatchState.AttributeFound;
527                         }
528                         else {
529                             attrValid = false;
530                             SendValidationEvent(Res.Sch_ProhibitedAttribute, attQName.ToString());
531                         }
532                         break;
533
534                     case AttributeMatchState.ProhibitedAttribute:
535                         attrValid = false;
536                         SendValidationEvent(Res.Sch_ProhibitedAttribute, attQName.ToString());
537                         break;
538
539                     case AttributeMatchState.AttributeNameMismatch:
540                         attrValid = false;
541                         SendValidationEvent(Res.Sch_SchemaAttributeNameMismatch, new string[] { attQName.ToString(), ((XmlSchemaAttribute)pvtAttribute).QualifiedName.ToString()});
542                         break;
543
544                     case AttributeMatchState.ValidateAttributeInvalidCall:
545                         Debug.Assert(currentState == ValidatorState.TopLevelAttribute); //Re-set state back to start on error with partial validation type
546                         currentState = ValidatorState.Start;
547                         attrValid = false;
548                         SendValidationEvent(Res.Sch_ValidateAttributeInvalidCall, string.Empty);
549                         break;
550
551                     case AttributeMatchState.AnyIdAttributeFound:
552                         if (wildID == null) {
553                             wildID = attributeDef;
554                             Debug.Assert(currentElementDecl != null);
555                             XmlSchemaComplexType ct = currentElementDecl.SchemaType as XmlSchemaComplexType;
556                             Debug.Assert(ct != null);
557                             if (ct.ContainsIdAttribute(false)) {
558                                 SendValidationEvent(Res.Sch_AttrUseAndWildId, string.Empty);
559                             }
560                             else {
561                                 goto case AttributeMatchState.AttributeFound;
562                             }
563                         }
564                         else { //More than one attribute per element cannot match wildcard if both their types are derived from ID
565                             SendValidationEvent(Res.Sch_MoreThanOneWildId, string.Empty);
566                         }
567                         break;
568
569                     case AttributeMatchState.AttributeFound:
570                         Debug.Assert(attributeDef != null);
571                         localAttribute = attributeDef.SchemaAttribute;
572                         if (currentElementDecl != null) { //Have to add to hashtable to check whether to add default attributes
573                             attPresence.Add(attQName, attributeDef);
574                         }
575                         object attValue;
576                         if (attributeValueGetter != null) {
577                             attValue = attributeValueGetter();
578                         }
579                         else {
580                             attValue = attributeStringValue;
581                         }
582                         typedVal = CheckAttributeValue(attValue, attributeDef);
583                         XmlSchemaDatatype datatype = attributeDef.Datatype;
584                         if (datatype.Variety == XmlSchemaDatatypeVariety.Union && typedVal != null) { //Unpack the union
585                             XsdSimpleValue simpleValue = typedVal as XsdSimpleValue;
586                             Debug.Assert(simpleValue != null);
587
588                             localMemberType = simpleValue.XmlType;
589                             datatype = simpleValue.XmlType.Datatype;
590                             typedVal = simpleValue.TypedValue;
591                         }
592                         CheckTokenizedTypes(datatype, typedVal, true);
593                         if (HasIdentityConstraints) {
594                             AttributeIdentityConstraints(attQName.Name, attQName.Namespace, typedVal, attValue.ToString(), datatype);
595                         }
596                         break;
597
598                     case AttributeMatchState.AnyAttributeLax:
599                         SendValidationEvent(Res.Sch_NoAttributeSchemaFound, attQName.ToString(), XmlSeverityType.Warning);
600                         break;
601
602                     case AttributeMatchState.AnyAttributeSkip:
603                         break;
604
605                     default:
606                         break;
607                 }
608             }
609             else { //Attribute from xsi namespace
610                 lName = nameTable.Add(lName);
611                 if (Ref.Equal(lName, xsiTypeString) || Ref.Equal(lName, xsiNilString) || Ref.Equal(lName, xsiSchemaLocationString) || Ref.Equal(lName, xsiNoNamespaceSchemaLocationString)) {
612                     attPresence.Add(attQName, SchemaAttDef.Empty);
613                 }
614                 else {
615                     attrValid = false;
616                     SendValidationEvent(Res.Sch_NotXsiAttribute, attQName.ToString());
617                 }
618             }
619
620             if (!attrValid) {
621                 localValidity = XmlSchemaValidity.Invalid;
622             }
623             else if (attributeDef != null) {
624                 localValidity = XmlSchemaValidity.Valid;
625             }
626             if (schemaInfo != null) {
627                 schemaInfo.SchemaAttribute = localAttribute;
628                 schemaInfo.SchemaType = localAttribute == null ? null : localAttribute.AttributeSchemaType;
629                 schemaInfo.MemberType = localMemberType;
630                 schemaInfo.IsDefault = false;
631                 schemaInfo.Validity = localValidity;
632             }
633             if (ProcessSchemaHints) {
634                 if (validatedNamespaces[ns] == null) {
635                     validatedNamespaces.Add(ns, ns);
636                 }
637             }
638             return typedVal;
639         }
640
641         public void GetUnspecifiedDefaultAttributes(ArrayList defaultAttributes) {
642             if (defaultAttributes == null)  {
643                 throw new ArgumentNullException("defaultAttributes");
644             }
645             CheckStateTransition(ValidatorState.Attribute, "GetUnspecifiedDefaultAttributes");
646             GetUnspecifiedDefaultAttributes(defaultAttributes, false);
647         }
648
649         public void ValidateEndOfAttributes(XmlSchemaInfo schemaInfo) {
650             CheckStateTransition(ValidatorState.EndOfAttributes, MethodNames[(int)ValidatorState.EndOfAttributes]);
651             //Check required attributes
652             SchemaElementDecl currentElementDecl = context.ElementDecl;
653             if (currentElementDecl != null && currentElementDecl.HasRequiredAttribute) {
654                 context.CheckRequiredAttribute = false;
655                 CheckRequiredAttributes(currentElementDecl);
656             }
657             if (schemaInfo != null) { //set validity depending on whether all required attributes were validated successfully
658                 schemaInfo.Validity = context.Validity;
659             }
660         }
661
662         public void ValidateText(string elementValue) {
663             if (elementValue == null) {
664                 throw new ArgumentNullException("elementValue");
665             }
666             ValidateText(elementValue, null);
667         }
668
669         public void ValidateText(XmlValueGetter elementValue) {
670             if (elementValue == null) {
671                 throw new ArgumentNullException("elementValue");
672             }
673             ValidateText(null, elementValue);
674         }
675
676         private void ValidateText(string elementStringValue, XmlValueGetter elementValueGetter) {
677             ValidatorState toState = validationStack.Length > 1 ? ValidatorState.Text : ValidatorState.TopLevelTextOrWS;
678             CheckStateTransition(toState, MethodNames[(int)toState]);
679
680             if (context.NeedValidateChildren) {
681                 if (context.IsNill) {
682                     SendValidationEvent(Res.Sch_ContentInNill, QNameString(context.LocalName, context.Namespace));
683                     return;
684                 }
685                 XmlSchemaContentType contentType = context.ElementDecl.ContentValidator.ContentType;
686                 switch(contentType) {
687                     case XmlSchemaContentType.Empty:
688                         SendValidationEvent(Res.Sch_InvalidTextInEmpty, string.Empty);
689                         break;
690
691                     case XmlSchemaContentType.TextOnly:
692                         if (elementValueGetter != null) {
693                             SaveTextValue(elementValueGetter());
694                         }
695                         else {
696                             SaveTextValue(elementStringValue);
697                         }
698                         break;
699
700                     case XmlSchemaContentType.ElementOnly:
701                         string textValue = elementValueGetter != null ? elementValueGetter().ToString() : elementStringValue;
702                         if(xmlCharType.IsOnlyWhitespace(textValue)) {
703                             break;
704                         }
705                         ArrayList names = context.ElementDecl.ContentValidator.ExpectedParticles(context, false, schemaSet);
706                         if (names == null ||  names.Count == 0) {
707                             SendValidationEvent(Res.Sch_InvalidTextInElement, BuildElementName(context.LocalName, context.Namespace));
708                         }
709                         else {
710                             Debug.Assert(names.Count > 0);
711                             SendValidationEvent(Res.Sch_InvalidTextInElementExpecting, new string[] { BuildElementName(context.LocalName, context.Namespace), PrintExpectedElements(names, true) });
712                         }
713                         break;
714
715                     case XmlSchemaContentType.Mixed:
716                         if (context.ElementDecl.DefaultValueTyped != null) {
717                             if (elementValueGetter != null) {
718                                 SaveTextValue(elementValueGetter());
719                             }
720                             else {
721                                 SaveTextValue(elementStringValue);
722                             }
723                         }
724                         break;
725                 }
726             }
727         }
728
729         public void ValidateWhitespace(string elementValue) {
730             if (elementValue == null) {
731                 throw new ArgumentNullException("elementValue");
732             }
733             ValidateWhitespace(elementValue, null);
734         }
735
736         public void ValidateWhitespace(XmlValueGetter elementValue) {
737             if (elementValue == null) {
738                 throw new ArgumentNullException("elementValue");
739             }
740             ValidateWhitespace(null, elementValue);
741         }
742
743         private void ValidateWhitespace(string elementStringValue, XmlValueGetter elementValueGetter) {
744             ValidatorState toState = validationStack.Length > 1 ? ValidatorState.Whitespace : ValidatorState.TopLevelTextOrWS;
745             CheckStateTransition(toState, MethodNames[(int)toState]);
746
747             if (context.NeedValidateChildren) {
748                 if (context.IsNill) {
749                     SendValidationEvent(Res.Sch_ContentInNill, QNameString(context.LocalName, context.Namespace));
750                 }
751                 XmlSchemaContentType contentType = context.ElementDecl.ContentValidator.ContentType;
752                 switch (contentType) {
753                     case XmlSchemaContentType.Empty:
754                         SendValidationEvent(Res.Sch_InvalidWhitespaceInEmpty, string.Empty);
755                         break;
756
757                     case XmlSchemaContentType.TextOnly:
758                         if (elementValueGetter != null) {
759                             SaveTextValue(elementValueGetter());
760                         }
761                         else {
762                             SaveTextValue(elementStringValue);
763                         }
764                         break;
765
766                     case XmlSchemaContentType.Mixed:
767                         if (context.ElementDecl.DefaultValueTyped != null) {
768                             if (elementValueGetter != null) {
769                                 SaveTextValue(elementValueGetter());
770                             }
771                             else {
772                                 SaveTextValue(elementStringValue);
773                             }
774                         }
775                         break;
776
777                     default:
778                         break;
779                 }
780             }
781         }
782
783
784         public object ValidateEndElement(XmlSchemaInfo schemaInfo) {
785             return InternalValidateEndElement(schemaInfo, null);
786         }
787
788         public object ValidateEndElement(XmlSchemaInfo schemaInfo, object typedValue) {
789             if (typedValue == null) {
790                 throw new ArgumentNullException("typedValue");
791             }
792             if (textValue.Length > 0) {
793                 throw new InvalidOperationException(Res.GetString(Res.Sch_InvalidEndElementCall));
794             }
795             return InternalValidateEndElement(schemaInfo, typedValue);
796         }
797
798         public void SkipToEndElement(XmlSchemaInfo schemaInfo) {
799             if (validationStack.Length <= 1) {
800                 throw new InvalidOperationException(Res.GetString(Res.Sch_InvalidEndElementMultiple, MethodNames[(int)ValidatorState.SkipToEndElement]));
801             }
802             CheckStateTransition(ValidatorState.SkipToEndElement, MethodNames[(int)ValidatorState.SkipToEndElement]);
803
804             if (schemaInfo != null) {
805                 SchemaElementDecl currentElementDecl = context.ElementDecl;
806                 if (currentElementDecl != null) {
807                     schemaInfo.SchemaType = currentElementDecl.SchemaType;
808                     schemaInfo.SchemaElement = GetSchemaElement();
809                 }
810                 else {
811                     schemaInfo.SchemaType = null;
812                     schemaInfo.SchemaElement = null;
813                 }
814                 schemaInfo.MemberType = null;
815                 schemaInfo.IsNil = context.IsNill;
816                 schemaInfo.IsDefault = context.IsDefault;
817                 Debug.Assert(context.Validity != XmlSchemaValidity.Valid);
818                 schemaInfo.Validity = context.Validity;
819             }
820             context.ValidationSkipped = true;
821             currentState = ValidatorState.SkipToEndElement;
822             Pop();
823         }
824
825         public void EndValidation() {
826             if (validationStack.Length > 1) { //We have pending elements in the stack to call ValidateEndElement
827                 throw new InvalidOperationException(Res.GetString(Res.Sch_InvalidEndValidation));
828             }
829             CheckStateTransition(ValidatorState.Finish, MethodNames[(int)ValidatorState.Finish]);
830             CheckForwardRefs();
831         }
832
833         public XmlSchemaParticle[] GetExpectedParticles() {
834             if (currentState == ValidatorState.Start || currentState == ValidatorState.TopLevelTextOrWS) { //Right after initialize
835                 if (partialValidationType != null) {
836                     XmlSchemaElement element = partialValidationType as XmlSchemaElement;
837                     if (element != null) {
838                         return new XmlSchemaParticle[1] {element};
839                     }
840                     return EmptyParticleArray;
841                 }
842                 else { //Should return all global elements
843                     ICollection elements = schemaSet.GlobalElements.Values;
844                     ArrayList expected = new ArrayList(elements.Count);
845                     foreach(XmlSchemaElement element in elements) { //Check for substitutions
846                         ContentValidator.AddParticleToExpected(element, schemaSet, expected, true);
847                     }
848                     return expected.ToArray(typeof(XmlSchemaParticle)) as XmlSchemaParticle[];
849                 }
850             }
851             if (context.ElementDecl != null) {
852                 ArrayList expected = context.ElementDecl.ContentValidator.ExpectedParticles(context, false, schemaSet);
853                 if (expected != null) {
854                     return expected.ToArray(typeof(XmlSchemaParticle)) as XmlSchemaParticle[];
855                 }
856             }
857             return EmptyParticleArray;
858         }
859
860         public XmlSchemaAttribute[] GetExpectedAttributes() {
861             if (currentState == ValidatorState.Element || currentState == ValidatorState.Attribute) {
862                 SchemaElementDecl elementDecl = context.ElementDecl;
863                 ArrayList attList = new ArrayList();
864                 if (elementDecl != null) {
865                     foreach(SchemaAttDef attDef in elementDecl.AttDefs.Values) {
866                         if (attPresence[attDef.Name] == null) {
867                             attList.Add(attDef.SchemaAttribute);
868                         }
869                     }
870                 }
871                 if (nsResolver.LookupPrefix(NsXsi) != null) { //Xsi namespace defined
872                     AddXsiAttributes(attList);
873                 }
874                 return attList.ToArray(typeof(XmlSchemaAttribute)) as XmlSchemaAttribute[];
875             }
876             else if (currentState == ValidatorState.Start) {
877                 if (partialValidationType != null) {
878                     XmlSchemaAttribute attribute = partialValidationType as XmlSchemaAttribute;
879                     if (attribute != null) {
880                         return new XmlSchemaAttribute[1] {attribute};
881                     }
882                 }
883             }
884             return EmptyAttributeArray;
885         }
886
887         internal void GetUnspecifiedDefaultAttributes(ArrayList defaultAttributes, bool createNodeData) {
888             currentState = ValidatorState.Attribute;
889             SchemaElementDecl currentElementDecl = context.ElementDecl;
890
891             if (currentElementDecl != null && currentElementDecl.HasDefaultAttribute) {
892                 for (int i = 0; i < currentElementDecl.DefaultAttDefs.Count; ++i) {
893                     SchemaAttDef attdef = (SchemaAttDef)currentElementDecl.DefaultAttDefs[i];
894                     if (!attPresence.Contains(attdef.Name)) {
895                         if (attdef.DefaultValueTyped == null) { //Invalid attribute default in the schema
896                             continue;
897                         }
898
899                         //Check to see default attributes WILL be qualified if attributeFormDefault = qualified in schema
900                         string attributeNS = nameTable.Add(attdef.Name.Namespace);
901                         string defaultPrefix = string.Empty;
902                         if (attributeNS.Length > 0) {
903                             defaultPrefix = GetDefaultAttributePrefix(attributeNS);
904                             if (defaultPrefix == null || defaultPrefix.Length == 0) {
905                                 SendValidationEvent(Res.Sch_DefaultAttributeNotApplied, new string[2] { attdef.Name.ToString(), QNameString(context.LocalName, context.Namespace)});
906                                 continue;
907                             }
908                         }
909                         XmlSchemaDatatype datatype = attdef.Datatype;
910                         if (createNodeData) {
911                             ValidatingReaderNodeData attrData = new ValidatingReaderNodeData();
912                             attrData.LocalName = nameTable.Add(attdef.Name.Name);
913                             attrData.Namespace = attributeNS;
914                             attrData.Prefix = nameTable.Add(defaultPrefix);
915                             attrData.NodeType = XmlNodeType.Attribute;
916
917                             //set PSVI properties
918                             AttributePSVIInfo attrValidInfo = new AttributePSVIInfo();
919                             XmlSchemaInfo attSchemaInfo = attrValidInfo.attributeSchemaInfo;
920                             Debug.Assert(attSchemaInfo != null);
921                             if (attdef.Datatype.Variety == XmlSchemaDatatypeVariety.Union) {
922                                 XsdSimpleValue simpleValue = attdef.DefaultValueTyped as XsdSimpleValue;
923                                 attSchemaInfo.MemberType = simpleValue.XmlType;
924                                 datatype = simpleValue.XmlType.Datatype;
925                                 attrValidInfo.typedAttributeValue = simpleValue.TypedValue;
926                             }
927                             else {
928                                 attrValidInfo.typedAttributeValue = attdef.DefaultValueTyped;
929                             }
930                             attSchemaInfo.IsDefault = true;
931                             attSchemaInfo.Validity = XmlSchemaValidity.Valid;
932                             attSchemaInfo.SchemaType = attdef.SchemaType;
933                             attSchemaInfo.SchemaAttribute = attdef.SchemaAttribute;
934                             attrData.RawValue = attSchemaInfo.XmlType.ValueConverter.ToString(attrValidInfo.typedAttributeValue);
935
936                             attrData.AttInfo = attrValidInfo;
937                             defaultAttributes.Add(attrData);
938                         }
939                         else {
940                             defaultAttributes.Add(attdef.SchemaAttribute);
941                         }
942                         CheckTokenizedTypes(datatype, attdef.DefaultValueTyped, true);
943                         if (HasIdentityConstraints) {
944                             AttributeIdentityConstraints(attdef.Name.Name, attdef.Name.Namespace, attdef.DefaultValueTyped, attdef.DefaultValueRaw, datatype);
945                         }
946                     }
947                 }
948             }
949             return;
950         }
951
952         internal XmlSchemaSet SchemaSet {
953             get {
954                 return schemaSet;
955             }
956         }
957
958         internal XmlSchemaValidationFlags ValidationFlags {
959             get {
960                 return validationFlags;
961             }
962         }
963
964         internal XmlSchemaContentType CurrentContentType {
965             get {
966                 if (context.ElementDecl == null) {
967                     return XmlSchemaContentType.Empty;
968                 }
969                 return context.ElementDecl.ContentValidator.ContentType;
970             }
971         }
972
973         internal XmlSchemaContentProcessing CurrentProcessContents {
974             get {
975                 return processContents;
976             }
977         }
978
979         internal void SetDtdSchemaInfo(IDtdInfo dtdSchemaInfo) {
980             this.dtdSchemaInfo = dtdSchemaInfo;
981             this.checkEntity = true;
982         }
983
984         private bool StrictlyAssessed {
985             get {
986                 return (processContents == XmlSchemaContentProcessing.Strict || processContents == XmlSchemaContentProcessing.Lax) && context.ElementDecl != null && !context.ValidationSkipped;
987             }
988         }
989
990         private bool HasSchema {
991             get {
992                 if (isRoot) {
993                     isRoot = false;
994                     if (!compiledSchemaInfo.Contains(context.Namespace)) {
995                         rootHasSchema = false;
996                     }
997                 }
998                 return rootHasSchema;
999             }
1000         }
1001
1002         internal string GetConcatenatedValue() {
1003             return textValue.ToString();
1004         }
1005
1006         private object InternalValidateEndElement(XmlSchemaInfo schemaInfo, object typedValue) {
1007             if (validationStack.Length <= 1) {
1008                 throw new InvalidOperationException(Res.GetString(Res.Sch_InvalidEndElementMultiple, MethodNames[(int)ValidatorState.EndElement]));
1009             }
1010             CheckStateTransition(ValidatorState.EndElement, MethodNames[(int)ValidatorState.EndElement]);
1011
1012             SchemaElementDecl contextElementDecl = context.ElementDecl;
1013             XmlSchemaSimpleType memberType = null;
1014             XmlSchemaType localSchemaType = null;
1015             XmlSchemaElement localSchemaElement = null;
1016
1017             string stringValue = string.Empty;
1018
1019             if (contextElementDecl != null) {
1020                 if (context.CheckRequiredAttribute && contextElementDecl.HasRequiredAttribute) {
1021                     CheckRequiredAttributes(contextElementDecl);
1022                 }
1023                 if (!context.IsNill) {
1024                     if (context.NeedValidateChildren) {
1025                         XmlSchemaContentType contentType = contextElementDecl.ContentValidator.ContentType;
1026                         switch (contentType) {
1027                             case XmlSchemaContentType.TextOnly:
1028                                 if (typedValue == null) {
1029                                     stringValue = textValue.ToString();
1030                                     typedValue = ValidateAtomicValue(stringValue, out memberType);
1031                                 }
1032                                 else { //Parsed object passed in, need to verify only facets
1033                                     typedValue = ValidateAtomicValue(typedValue, out memberType);
1034                                 }
1035                                 break;
1036
1037                             case XmlSchemaContentType.Mixed:
1038                                 if (contextElementDecl.DefaultValueTyped != null) {
1039                                     if (typedValue == null) {
1040                                         stringValue = textValue.ToString();
1041                                         typedValue = CheckMixedValueConstraint(stringValue);
1042                                     }
1043                                 }
1044                                 break;
1045
1046                             case XmlSchemaContentType.ElementOnly:
1047                                 if (typedValue != null) { //Cannot pass in typedValue for complex content
1048                                     throw new InvalidOperationException(Res.GetString(Res.Sch_InvalidEndElementCallTyped));
1049                                 }
1050                                 break;
1051
1052                             default:
1053                                 break;
1054                         }
1055                         if(!contextElementDecl.ContentValidator.CompleteValidation(context)) {
1056                             CompleteValidationError(context, eventHandler, nsResolver, sourceUriString, positionInfo.LineNumber, positionInfo.LinePosition, schemaSet);
1057                             context.Validity = XmlSchemaValidity.Invalid;
1058                         }
1059                     }
1060                 }
1061                 // for each level in the stack, endchildren and fill value from element
1062                 if (HasIdentityConstraints) {
1063                     XmlSchemaType xmlType = memberType == null ? contextElementDecl.SchemaType : memberType;
1064                     EndElementIdentityConstraints(typedValue, stringValue, xmlType.Datatype);
1065                 }
1066                 localSchemaType = contextElementDecl.SchemaType;
1067                 localSchemaElement = GetSchemaElement();
1068             }
1069             if (schemaInfo != null) { //SET SchemaInfo
1070                 schemaInfo.SchemaType = localSchemaType;
1071                 schemaInfo.SchemaElement = localSchemaElement;
1072                 schemaInfo.MemberType = memberType;
1073                 schemaInfo.IsNil = context.IsNill;
1074                 schemaInfo.IsDefault = context.IsDefault;
1075                 if (context.Validity == XmlSchemaValidity.NotKnown && StrictlyAssessed) {
1076                     context.Validity = XmlSchemaValidity.Valid;
1077                 }
1078                 schemaInfo.Validity = context.Validity;
1079             }
1080             Pop();
1081             return typedValue;
1082         }
1083
1084         [ResourceConsumption(ResourceScope.Machine)]
1085         [ResourceExposure(ResourceScope.Machine)]
1086         private void ProcessSchemaLocations(string xsiSchemaLocation, string xsiNoNamespaceSchemaLocation) {
1087             bool compile = false;
1088             if (xsiNoNamespaceSchemaLocation != null) {
1089                 compile = true;
1090                 LoadSchema(string.Empty, xsiNoNamespaceSchemaLocation);
1091             }
1092             if (xsiSchemaLocation != null) {
1093
1094                 object typedValue;
1095                 Exception exception = dtStringArray.TryParseValue(xsiSchemaLocation, nameTable, nsResolver, out typedValue);
1096                 if (exception != null) {
1097                     SendValidationEvent(Res.Sch_InvalidValueDetailedAttribute, new string[] { "schemaLocation", xsiSchemaLocation, dtStringArray.TypeCodeString, exception.Message }, exception);
1098                     return;
1099                 }
1100                 string[] locations = (string[])typedValue;
1101                 compile = true;
1102                 try {
1103                     for (int j = 0; j < locations.Length - 1; j += 2) {
1104                         LoadSchema((string)locations[j], (string)locations[j + 1]);
1105                     }
1106                 }
1107                 catch (XmlSchemaException schemaException) {
1108                     SendValidationEvent(schemaException);
1109                 }
1110             }
1111             if (compile) {
1112                 RecompileSchemaSet();
1113             }
1114         }
1115
1116
1117         private object ValidateElementContext(XmlQualifiedName elementName, out bool invalidElementInContext) {
1118             object particle = null;
1119             int errorCode = 0;
1120             XmlQualifiedName head;
1121             XmlSchemaElement headElement = null;
1122             invalidElementInContext = false;
1123
1124             if (context.NeedValidateChildren) {
1125                 if (context.IsNill) {
1126                     SendValidationEvent(Res.Sch_ContentInNill, QNameString(context.LocalName, context.Namespace));
1127                     return null;
1128                 }
1129                 ContentValidator contentValidator = context.ElementDecl.ContentValidator;
1130                 if (contentValidator.ContentType == XmlSchemaContentType.Mixed && context.ElementDecl.Presence == SchemaDeclBase.Use.Fixed) { //Mixed with default or fixed
1131                     SendValidationEvent(Res.Sch_ElementInMixedWithFixed, QNameString(context.LocalName, context.Namespace));
1132                     return null;
1133                 }
1134
1135                 head = elementName;
1136                 bool substitution = false;
1137
1138                 while (true) {
1139                     particle = context.ElementDecl.ContentValidator.ValidateElement(head, context, out errorCode);
1140                     if (particle != null) { //Match found
1141                         break;
1142                     }
1143                     if (errorCode == -2) { //ContentModel all group error
1144                         SendValidationEvent(Res.Sch_AllElement, elementName.ToString());
1145                         invalidElementInContext = true;
1146                         processContents = context.ProcessContents = XmlSchemaContentProcessing.Skip;
1147                         return null;
1148                     }
1149                     //Match not found; check for substitutionGroup
1150                     substitution = true;
1151                     headElement = GetSubstitutionGroupHead(head);
1152                     if (headElement == null) {
1153                         break;
1154                     }
1155                     else {
1156                         head = headElement.QualifiedName;
1157                     }
1158                 }
1159
1160                 if (substitution) {
1161                     XmlSchemaElement matchedElem = particle as XmlSchemaElement;
1162                     if (matchedElem == null) { //It matched an xs:any in that position
1163                         particle = null;
1164                     }
1165                     else if (matchedElem.RefName.IsEmpty) { //It is not element ref but a local element
1166                         //If the head and matched particle are not hte same, then this is not substitutable, duped by a localElement with same QName
1167                         SendValidationEvent(Res.Sch_InvalidElementSubstitution, BuildElementName(elementName), BuildElementName(matchedElem.QualifiedName));
1168                         invalidElementInContext = true;
1169                         processContents = context.ProcessContents = XmlSchemaContentProcessing.Skip;
1170                     }
1171                     else { //Correct substitution head found
1172                         particle = compiledSchemaInfo.GetElement(elementName); //Re-assign correct particle
1173                         context.NeedValidateChildren = true; //This will be reset to false once member match is not found
1174                     }
1175                 }
1176                 if (particle == null) {
1177                     ElementValidationError(elementName, context, eventHandler, nsResolver, sourceUriString, positionInfo.LineNumber, positionInfo.LinePosition, schemaSet);
1178                     invalidElementInContext = true;
1179                     processContents = context.ProcessContents = XmlSchemaContentProcessing.Skip;
1180                 }
1181             }
1182             return particle;
1183         }
1184
1185
1186         private XmlSchemaElement GetSubstitutionGroupHead(XmlQualifiedName member) {
1187             XmlSchemaElement memberElem = compiledSchemaInfo.GetElement(member);
1188             if (memberElem != null) {
1189                 XmlQualifiedName head = memberElem.SubstitutionGroup;
1190                 if(!head.IsEmpty) {
1191                     XmlSchemaElement headElem = compiledSchemaInfo.GetElement(head);
1192                     if (headElem != null) {
1193                         if ((headElem.BlockResolved & XmlSchemaDerivationMethod.Substitution) != 0) {
1194                             SendValidationEvent(Res.Sch_SubstitutionNotAllowed, new string[] {member.ToString(), head.ToString()});
1195                             return null;
1196                         }
1197                         if (!XmlSchemaType.IsDerivedFrom(memberElem.ElementSchemaType, headElem.ElementSchemaType, headElem.BlockResolved)) {
1198                             SendValidationEvent(Res.Sch_SubstitutionBlocked, new string[] {member.ToString(), head.ToString()});
1199                             return null;
1200                         }
1201                         return headElem;
1202                     }
1203                 }
1204             }
1205             return null;
1206         }
1207
1208         private object ValidateAtomicValue(string stringValue, out XmlSchemaSimpleType memberType) {
1209             object typedVal = null;
1210             memberType = null;
1211             SchemaElementDecl currentElementDecl = context.ElementDecl;
1212             if (!context.IsNill) {
1213                 if (stringValue.Length == 0 && currentElementDecl.DefaultValueTyped != null) { //default value maybe present
1214                     SchemaElementDecl declBeforeXsi = context.ElementDeclBeforeXsi;
1215                     if (declBeforeXsi != null && declBeforeXsi != currentElementDecl) { //There was xsi:type
1216                         Debug.Assert(currentElementDecl.Datatype != null);
1217                         Exception exception = currentElementDecl.Datatype.TryParseValue(currentElementDecl.DefaultValueRaw, nameTable, nsResolver, out typedVal);
1218                         if (exception != null) {
1219                             SendValidationEvent(Res.Sch_InvalidElementDefaultValue, new string[] { currentElementDecl.DefaultValueRaw, QNameString(context.LocalName, context.Namespace) });
1220                         }
1221                         else {
1222                             context.IsDefault = true;
1223                         }
1224                     }
1225                     else {
1226                         context.IsDefault = true;
1227                         typedVal = currentElementDecl.DefaultValueTyped;
1228                     }
1229                 }
1230                 else {
1231                     typedVal = CheckElementValue(stringValue);
1232                 }
1233                 XsdSimpleValue simpleValue = typedVal as XsdSimpleValue;
1234                 XmlSchemaDatatype dtype = currentElementDecl.Datatype;
1235                 if (simpleValue != null) {
1236                     memberType = simpleValue.XmlType;
1237                     typedVal = simpleValue.TypedValue;
1238                     dtype = memberType.Datatype;
1239                 }
1240                 CheckTokenizedTypes(dtype, typedVal, false);
1241             }
1242             return typedVal;
1243         }
1244
1245         private object ValidateAtomicValue(object parsedValue, out XmlSchemaSimpleType memberType) {
1246             memberType = null;
1247             SchemaElementDecl currentElementDecl = context.ElementDecl;
1248             object typedValue = null;
1249             if (!context.IsNill) {
1250                 SchemaDeclBase decl = currentElementDecl as SchemaDeclBase;
1251                 XmlSchemaDatatype dtype = currentElementDecl.Datatype;
1252                 Exception exception = dtype.TryParseValue(parsedValue, nameTable, nsResolver, out typedValue);
1253                 if (exception != null) {
1254                     string stringValue = parsedValue as string;
1255                     if (stringValue == null) {
1256                         stringValue = XmlSchemaDatatype.ConcatenatedToString(parsedValue);
1257                     }
1258                     SendValidationEvent(Res.Sch_ElementValueDataTypeDetailed, new string[] { QNameString(context.LocalName, context.Namespace), stringValue, GetTypeName(decl), exception.Message }, exception);
1259                     return null;
1260                 }
1261                 if (!decl.CheckValue(typedValue)) {
1262                     SendValidationEvent(Res.Sch_FixedElementValue, QNameString(context.LocalName, context.Namespace));
1263                 }
1264                 if (dtype.Variety == XmlSchemaDatatypeVariety.Union) {
1265                     XsdSimpleValue simpleValue = typedValue as XsdSimpleValue;
1266                     Debug.Assert(simpleValue != null);
1267                     memberType = simpleValue.XmlType;
1268                     typedValue = simpleValue.TypedValue;
1269                     dtype = memberType.Datatype;
1270                 }
1271                 CheckTokenizedTypes(dtype, typedValue, false);
1272             }
1273             return typedValue;
1274         }
1275
1276         private string GetTypeName(SchemaDeclBase decl) {
1277             Debug.Assert(decl != null && decl.SchemaType != null);
1278             string typeName = decl.SchemaType.QualifiedName.ToString();
1279             if (typeName.Length == 0) {
1280                 typeName = decl.Datatype.TypeCodeString;
1281             }
1282             return typeName;
1283         }
1284
1285         private void SaveTextValue(object value) {
1286             string s = value.ToString(); //For strings, which will mostly be the case, ToString() will return this. For other typedValues, need to go through value converter (eg: TimeSpan, DateTime etc)
1287             textValue.Append(s);
1288         }
1289
1290         private void Push(XmlQualifiedName elementName) {
1291             context = (ValidationState)validationStack.Push();
1292             if (context == null) {
1293                 context = new ValidationState();
1294                 validationStack.AddToTop(context);
1295             }
1296             context.LocalName = elementName.Name;
1297             context.Namespace = elementName.Namespace;
1298             context.HasMatched = false;
1299             context.IsNill = false;
1300             context.IsDefault = false;
1301             context.CheckRequiredAttribute = true;
1302             context.ValidationSkipped = false;
1303             context.Validity = XmlSchemaValidity.NotKnown;
1304             context.NeedValidateChildren = false;
1305             context.ProcessContents = processContents;
1306             context.ElementDeclBeforeXsi = null;
1307             context.Constr = null; //resetting the constraints to be null incase context != null
1308                                    // when pushing onto stack;
1309         }
1310
1311         private    void Pop() {
1312             Debug.Assert(validationStack.Length > 1);
1313             ValidationState previousContext = (ValidationState)validationStack.Pop();
1314
1315             if (startIDConstraint == validationStack.Length) {
1316                 startIDConstraint = -1;
1317             }
1318             context = (ValidationState)validationStack.Peek();
1319             if (previousContext.Validity == XmlSchemaValidity.Invalid) { //Should set current context's validity to that of what was popped now in case of Invalid
1320                 context.Validity = XmlSchemaValidity.Invalid;
1321             }
1322             if (previousContext.ValidationSkipped) {
1323                 context.ValidationSkipped = true;
1324             }
1325             processContents = context.ProcessContents;
1326         }
1327
1328         private void AddXsiAttributes(ArrayList attList) {
1329             BuildXsiAttributes();
1330             if (attPresence[xsiTypeSO.QualifiedName] == null) {
1331                 attList.Add(xsiTypeSO);
1332             }
1333             if (attPresence[xsiNilSO.QualifiedName] == null) {
1334                 attList.Add(xsiNilSO);
1335             }
1336             if (attPresence[xsiSLSO.QualifiedName] == null) {
1337                 attList.Add(xsiSLSO);
1338             }
1339             if (attPresence[xsiNoNsSLSO.QualifiedName] == null) {
1340                 attList.Add(xsiNoNsSLSO);
1341             }
1342         }
1343
1344         private SchemaElementDecl FastGetElementDecl(XmlQualifiedName elementName, object particle) {
1345             SchemaElementDecl elementDecl = null;
1346             if (particle != null) {
1347                 XmlSchemaElement element = particle as XmlSchemaElement;
1348                 if (element != null) {
1349                     elementDecl = element.ElementDecl;
1350                 }
1351                 else {
1352                     XmlSchemaAny any = (XmlSchemaAny)particle;
1353                     processContents = any.ProcessContentsCorrect;
1354                 }
1355             }
1356             if (elementDecl == null && processContents != XmlSchemaContentProcessing.Skip) {
1357                 if (isRoot && partialValidationType != null) {
1358                     if (partialValidationType is XmlSchemaElement) {
1359                         XmlSchemaElement element = (XmlSchemaElement)partialValidationType;
1360                         if (elementName.Equals(element.QualifiedName)) {
1361                             elementDecl = element.ElementDecl;
1362                         }
1363                         else {
1364                             SendValidationEvent(Res.Sch_SchemaElementNameMismatch, elementName.ToString(), element.QualifiedName.ToString());
1365                         }
1366                     }
1367                     else if (partialValidationType is XmlSchemaType) { //Element name is wildcard
1368                         XmlSchemaType type = (XmlSchemaType)partialValidationType;
1369                         elementDecl = type.ElementDecl;
1370                     }
1371                     else { //its XmlSchemaAttribute
1372                         Debug.Assert(partialValidationType is XmlSchemaAttribute);
1373                         SendValidationEvent(Res.Sch_ValidateElementInvalidCall, string.Empty);
1374                     }
1375                 }
1376                 else {
1377                     elementDecl = compiledSchemaInfo.GetElementDecl(elementName);
1378                 }
1379             }
1380             return elementDecl;
1381         }
1382
1383         private SchemaElementDecl CheckXsiTypeAndNil(SchemaElementDecl elementDecl, string xsiType, string xsiNil, ref bool declFound) {
1384             XmlQualifiedName xsiTypeName = XmlQualifiedName.Empty;
1385             if (xsiType != null) {
1386                 object typedVal = null;
1387                 Exception exception = dtQName.TryParseValue(xsiType, nameTable, nsResolver, out typedVal);
1388                 if (exception != null) {
1389                     SendValidationEvent(Res.Sch_InvalidValueDetailedAttribute, new string[] { "type", xsiType, dtQName.TypeCodeString, exception.Message }, exception);
1390                 }
1391                 else {
1392                     xsiTypeName = typedVal as XmlQualifiedName;
1393                 }
1394             }
1395             if (elementDecl != null) { //nillable is not dependent on xsi:type.
1396                 if (elementDecl.IsNillable) {
1397                     if (xsiNil != null) {
1398                         context.IsNill = XmlConvert.ToBoolean(xsiNil);
1399                         if (context.IsNill && elementDecl.Presence == SchemaDeclBase.Use.Fixed) {
1400                             Debug.Assert(elementDecl.DefaultValueTyped != null);                                
1401                             SendValidationEvent(Res.Sch_XsiNilAndFixed);
1402                         }
1403                     }
1404                 }
1405                 else if (xsiNil != null) {
1406                     SendValidationEvent(Res.Sch_InvalidXsiNill);
1407                 }
1408             }
1409             if (xsiTypeName.IsEmpty) {
1410                 if (elementDecl != null && elementDecl.IsAbstract) {
1411                     SendValidationEvent(Res.Sch_AbstractElement, QNameString(context.LocalName, context.Namespace));
1412                     elementDecl = null;
1413                 }
1414             }
1415             else {
1416                 SchemaElementDecl elementDeclXsi = compiledSchemaInfo.GetTypeDecl(xsiTypeName);
1417                 XmlSeverityType severity = XmlSeverityType.Warning;
1418                 if (HasSchema && processContents == XmlSchemaContentProcessing.Strict) {
1419                     severity = XmlSeverityType.Error;
1420                 }
1421                 if (elementDeclXsi == null && xsiTypeName.Namespace == NsXs) {
1422                     XmlSchemaType schemaType = DatatypeImplementation.GetSimpleTypeFromXsdType(xsiTypeName);
1423                     if (schemaType == null) { //try getting complexType - xs:anyType
1424                         schemaType = XmlSchemaType.GetBuiltInComplexType(xsiTypeName);
1425                     }
1426                     if (schemaType != null) {
1427                         elementDeclXsi = schemaType.ElementDecl;
1428                     }
1429
1430                 }
1431                 if (elementDeclXsi == null) {
1432                     SendValidationEvent(Res.Sch_XsiTypeNotFound, xsiTypeName.ToString(), severity);
1433                     elementDecl = null;
1434                 }
1435                 else {
1436                     declFound = true;
1437                     if (elementDeclXsi.IsAbstract) {
1438                         SendValidationEvent(Res.Sch_XsiTypeAbstract, xsiTypeName.ToString(), severity);
1439                         elementDecl = null;
1440                     }
1441                     else if (elementDecl != null && !XmlSchemaType.IsDerivedFrom(elementDeclXsi.SchemaType,elementDecl.SchemaType,elementDecl.Block)) {
1442                         SendValidationEvent(Res.Sch_XsiTypeBlockedEx, new string[] { xsiTypeName.ToString(), QNameString(context.LocalName, context.Namespace) });
1443                         elementDecl = null;
1444                     }
1445                     else {
1446                         if (elementDecl != null) { //Get all element decl properties before assigning xsi:type decl; nillable already checked
1447                             elementDeclXsi = elementDeclXsi.Clone(); //Before updating properties onto xsi:type decl, clone it
1448                             elementDeclXsi.Constraints = elementDecl.Constraints;
1449                             elementDeclXsi.DefaultValueRaw = elementDecl.DefaultValueRaw;
1450                             elementDeclXsi.DefaultValueTyped = elementDecl.DefaultValueTyped;
1451                             elementDeclXsi.Block = elementDecl.Block;
1452                         }
1453                         context.ElementDeclBeforeXsi = elementDecl;
1454                         elementDecl = elementDeclXsi;
1455                     }
1456                 }
1457             }
1458             return elementDecl;
1459         }
1460
1461         private void ThrowDeclNotFoundWarningOrError(bool declFound) {
1462             if (declFound) { //But invalid, so discontinue processing of children
1463                 processContents = context.ProcessContents = XmlSchemaContentProcessing.Skip;
1464                 context.NeedValidateChildren = false;
1465             }
1466             else if (HasSchema && processContents == XmlSchemaContentProcessing.Strict) { //Error and skip validation for children
1467                 processContents = context.ProcessContents = XmlSchemaContentProcessing.Skip;
1468                 context.NeedValidateChildren = false;
1469                 SendValidationEvent(Res.Sch_UndeclaredElement, QNameString(context.LocalName, context.Namespace));
1470             }
1471             else {
1472                 SendValidationEvent(Res.Sch_NoElementSchemaFound, QNameString(context.LocalName, context.Namespace), XmlSeverityType.Warning);
1473             }
1474         }
1475
1476         private void CheckElementProperties () {
1477           if (context.ElementDecl.IsAbstract) {
1478               SendValidationEvent(Res.Sch_AbstractElement, QNameString(context.LocalName, context.Namespace));
1479           }
1480         }
1481
1482         private void ValidateStartElementIdentityConstraints() {
1483             // added on June 15, set the context here, so the stack can have them
1484             if (ProcessIdentityConstraints && context.ElementDecl.Constraints != null) {
1485                 AddIdentityConstraints();
1486             }
1487             //foreach constraint in stack (including the current one)
1488             if (HasIdentityConstraints) {
1489                 ElementIdentityConstraints();
1490             }
1491         }
1492
1493         private SchemaAttDef CheckIsXmlAttribute(XmlQualifiedName attQName) {
1494             SchemaAttDef attdef = null;
1495             if (Ref.Equal(attQName.Namespace, NsXml) && (validationFlags & XmlSchemaValidationFlags.AllowXmlAttributes) != 0) {  //Need to check if this attribute is an xml attribute
1496                 if (!compiledSchemaInfo.Contains(NsXml)) { //We dont have a schema for xml namespace
1497                     // It can happen that the schemaSet already contains the schema for xml namespace
1498                     //   and we just have a stale compiled schema info (for example if the same schema set is used
1499                     //   by two validators at the same time and the one before us added the xml namespace schema
1500                     //   via this code here)
1501                     // In that case it is actually OK to try to add the schema for xml namespace again
1502                     //   since we're adding the exact same instance (the built in xml namespace schema is a singleton)
1503                     //   The addition on the schemaset is an effective no-op plus it's thread safe, so it's better to leave
1504                     //   that up to the schema set. The result of the below call will be simply that we update the
1505                     //   reference to the comipledSchemaInfo - which is exactly what we want in that case.
1506                     // In theory it can actually happen that there is some other schema registered for the xml namespace
1507                     //   (other than our built in one), and we don't know about it. In that case we don't support such scenario
1508                     //   as the user is modifying the schemaset as we're using it, which we don't support
1509                     //   for bunch of other reasons, so trying to add our built-in schema won't make it worse.
1510                     AddXmlNamespaceSchema();
1511                 }
1512                 compiledSchemaInfo.AttributeDecls.TryGetValue(attQName, out attdef); //the xml attributes are all global attributes
1513             }
1514             return attdef;
1515         }
1516
1517         private void AddXmlNamespaceSchema() {
1518             XmlSchemaSet localSet = new XmlSchemaSet(); //Avoiding cost of incremental compilation checks by compiling schema in a seperate set and adding compiled set
1519             localSet.Add(Preprocessor.GetBuildInSchema());
1520             localSet.Compile();
1521             schemaSet.Add(localSet);
1522             RecompileSchemaSet();
1523         }
1524
1525         internal object CheckMixedValueConstraint(string elementValue) {
1526             SchemaElementDecl elementDecl = context.ElementDecl;
1527             Debug.Assert(elementDecl.ContentValidator.ContentType == XmlSchemaContentType.Mixed && elementDecl.DefaultValueTyped != null);
1528             if (context.IsNill) { //Nil and fixed is error; Nil and default is compile time error
1529                 return null;
1530             }
1531             if (elementValue.Length == 0) {
1532                 context.IsDefault = true;
1533                 return elementDecl.DefaultValueTyped;
1534             }
1535             else {
1536                 SchemaDeclBase decl = elementDecl as SchemaDeclBase;
1537                 Debug.Assert(decl != null);
1538                 if (decl.Presence == SchemaDeclBase.Use.Fixed && !elementValue.Equals(elementDecl.DefaultValueRaw)) { //check string equality for mixed as it is untyped.
1539                     SendValidationEvent(Res.Sch_FixedElementValue, elementDecl.Name.ToString());
1540                 }
1541                 return elementValue;
1542             }
1543         }
1544
1545         [ResourceConsumption(ResourceScope.Machine)]
1546         [ResourceExposure(ResourceScope.Machine)]
1547         private void LoadSchema(string uri, string url) {
1548             Debug.Assert(xmlResolver != null);
1549             XmlReader Reader = null;
1550             try {
1551                 Uri ruri = xmlResolver.ResolveUri(sourceUri, url);
1552                 Stream stm = (Stream)xmlResolver.GetEntity(ruri,null,null);
1553                 XmlReaderSettings readerSettings = schemaSet.ReaderSettings;
1554                 readerSettings.CloseInput = true;
1555                 readerSettings.XmlResolver = xmlResolver;
1556                 Reader = XmlReader.Create(stm, readerSettings, ruri.ToString());
1557                 schemaSet.Add(uri, Reader, validatedNamespaces);
1558                 while(Reader.Read());// wellformness check
1559             }
1560             catch(XmlSchemaException e) {
1561                 SendValidationEvent(Res.Sch_CannotLoadSchema, new string[] {uri, e.Message}, e);
1562             }
1563             catch(Exception e) {
1564                 SendValidationEvent(Res.Sch_CannotLoadSchema, new string[] {uri, e.Message}, e, XmlSeverityType.Warning);
1565             }
1566             finally {
1567                 if (Reader != null) {
1568                     Reader.Close();
1569                 }
1570             }
1571         }
1572
1573
1574         internal void RecompileSchemaSet() {
1575             if (!schemaSet.IsCompiled) {
1576                 try {
1577                     schemaSet.Compile();
1578                 }
1579                 catch(XmlSchemaException e) {
1580                     SendValidationEvent(e);
1581                 }
1582             }
1583             compiledSchemaInfo = schemaSet.CompiledInfo; //Fetch compiled info from set
1584         }
1585
1586         private void ProcessTokenizedType(XmlTokenizedType ttype, string name, bool attrValue) {
1587             switch(ttype) {
1588                 case XmlTokenizedType.ID:
1589                     if (ProcessIdentityConstraints) {
1590                         if (FindId(name) != null) {
1591                             if (attrValue) {
1592                                 attrValid = false;
1593                             }
1594                             SendValidationEvent(Res.Sch_DupId, name);
1595                         }
1596                         else {
1597                             if (IDs == null) { //ADD ID
1598                                 IDs = new Hashtable();
1599                             }
1600                             IDs.Add(name, context.LocalName);
1601                         }
1602                     }
1603                     break;
1604                 case XmlTokenizedType.IDREF:
1605                     if (ProcessIdentityConstraints) {
1606                         object p = FindId(name);
1607                         if (p == null) { // add it to linked list to check it later
1608                             idRefListHead = new IdRefNode(idRefListHead, name, positionInfo.LineNumber, positionInfo.LinePosition);
1609                         }
1610                     }
1611                     break;
1612                 case XmlTokenizedType.ENTITY:
1613                     ProcessEntity(name);
1614                     break;
1615                 default:
1616                     break;
1617             }
1618         }
1619
1620         private object CheckAttributeValue(object value, SchemaAttDef attdef) {
1621             object typedValue = null;
1622             SchemaDeclBase decl = attdef as SchemaDeclBase;
1623
1624             XmlSchemaDatatype dtype = attdef.Datatype;
1625             Debug.Assert(dtype != null);
1626             string stringValue = value as string;
1627             Exception exception = null;
1628
1629             if (stringValue != null) { //
1630                 exception = dtype.TryParseValue(stringValue, nameTable, nsResolver, out typedValue);
1631                 if (exception != null) goto Error;
1632             }
1633             else { //Calling object ParseValue for checking facets
1634                 exception = dtype.TryParseValue(value, nameTable, nsResolver, out typedValue);
1635                 if (exception != null) goto Error;
1636             }
1637             if (!decl.CheckValue(typedValue)) {
1638                 attrValid = false;
1639                 SendValidationEvent(Res.Sch_FixedAttributeValue, attdef.Name.ToString());
1640             }
1641             return typedValue;
1642
1643         Error:
1644             attrValid = false;
1645             if (stringValue == null) {
1646                 stringValue = XmlSchemaDatatype.ConcatenatedToString(value);
1647             }
1648             SendValidationEvent(Res.Sch_AttributeValueDataTypeDetailed, new string[] { attdef.Name.ToString(), stringValue, GetTypeName(decl), exception.Message }, exception);
1649             return null;
1650         }
1651
1652         private object CheckElementValue(string stringValue) {
1653             object typedValue = null;
1654             SchemaDeclBase decl = context.ElementDecl as SchemaDeclBase;
1655
1656             XmlSchemaDatatype dtype = decl.Datatype;
1657             Debug.Assert(dtype != null);
1658
1659             Exception exception = dtype.TryParseValue(stringValue, nameTable, nsResolver, out typedValue);
1660             if (exception != null) {
1661                 SendValidationEvent(Res.Sch_ElementValueDataTypeDetailed, new string[] { QNameString(context.LocalName, context.Namespace), stringValue, GetTypeName(decl), exception.Message }, exception);
1662                 return null;
1663             }
1664             if (!decl.CheckValue(typedValue)) {
1665                 SendValidationEvent(Res.Sch_FixedElementValue, QNameString(context.LocalName, context.Namespace));
1666             }
1667             return typedValue;
1668         }
1669
1670         private void CheckTokenizedTypes(XmlSchemaDatatype dtype, object typedValue, bool attrValue) {
1671             // Check special types
1672             if (typedValue == null) {
1673                 return;
1674             }
1675             XmlTokenizedType ttype = dtype.TokenizedType;
1676             if (ttype == XmlTokenizedType.ENTITY || ttype == XmlTokenizedType.ID || ttype == XmlTokenizedType.IDREF) {
1677                 if (dtype.Variety == XmlSchemaDatatypeVariety.List) {
1678                     string[] ss = (string[])typedValue;
1679                     for (int i = 0; i < ss.Length; ++i) {
1680                         ProcessTokenizedType(dtype.TokenizedType, ss[i], attrValue);
1681                     }
1682                 }
1683                 else {
1684                     ProcessTokenizedType(dtype.TokenizedType, (string)typedValue, attrValue);
1685                 }
1686             }
1687         }
1688
1689         private object  FindId(string name) {
1690             return IDs == null ? null : IDs[name];
1691         }
1692
1693         private void CheckForwardRefs() {
1694             IdRefNode next = idRefListHead;
1695             while (next != null) {
1696                 if(FindId(next.Id) == null) {
1697                     SendValidationEvent(new XmlSchemaValidationException(Res.Sch_UndeclaredId, next.Id, this.sourceUriString, next.LineNo, next.LinePos), XmlSeverityType.Error);
1698                 }
1699                 IdRefNode ptr = next.Next;
1700                 next.Next = null; // unhook each object so it is cleaned up by Garbage Collector
1701                 next = ptr;
1702             }
1703             // not needed any more.
1704             idRefListHead = null;
1705         }
1706
1707
1708         private bool HasIdentityConstraints {
1709             get { return ProcessIdentityConstraints && startIDConstraint != -1; }
1710         }
1711
1712         internal bool ProcessIdentityConstraints {
1713             get {
1714                 return (validationFlags & XmlSchemaValidationFlags.ProcessIdentityConstraints) != 0;
1715             }
1716         }
1717
1718         internal bool ReportValidationWarnings {
1719             get {
1720                 return (validationFlags & XmlSchemaValidationFlags.ReportValidationWarnings) != 0;
1721             }
1722         }
1723
1724         internal bool ProcessInlineSchema {
1725             get {
1726                 return (validationFlags & XmlSchemaValidationFlags.ProcessInlineSchema) != 0;
1727             }
1728         }
1729
1730         internal bool ProcessSchemaLocation {
1731             get {
1732                 return (validationFlags & XmlSchemaValidationFlags.ProcessSchemaLocation) != 0;
1733             }
1734         }
1735
1736         internal bool ProcessSchemaHints {
1737             get {
1738                 return (validationFlags & XmlSchemaValidationFlags.ProcessInlineSchema) != 0 ||
1739                        (validationFlags & XmlSchemaValidationFlags.ProcessSchemaLocation) != 0;
1740             }
1741         }
1742
1743         private void CheckStateTransition(ValidatorState toState, string methodName) {
1744             if (!ValidStates[(int)currentState,(int)toState]) {
1745                 if (currentState == ValidatorState.None) {
1746                     throw new InvalidOperationException(Res.GetString(Res.Sch_InvalidStartTransition, new string[] { methodName, MethodNames[(int)ValidatorState.Start] }));
1747                 }
1748                 throw new InvalidOperationException(Res.GetString(Res.Sch_InvalidStateTransition, new string[] { MethodNames[(int)currentState], methodName }));
1749             }
1750             currentState = toState;
1751         }
1752
1753         private void ClearPSVI() {
1754             if (textValue != null) {
1755                 textValue.Length = 0;
1756             }
1757             attPresence.Clear(); //Clear attributes hashtable for every element
1758             wildID = null; //clear it for every element
1759         }
1760
1761         private void CheckRequiredAttributes(SchemaElementDecl currentElementDecl) {
1762             Debug.Assert(currentElementDecl != null);
1763             Dictionary<XmlQualifiedName, SchemaAttDef> attributeDefs = currentElementDecl.AttDefs;
1764             foreach(SchemaAttDef attdef in attributeDefs.Values) {
1765                 if (attPresence[attdef.Name] == null) {
1766                     if (attdef.Presence == SchemaDeclBase.Use.Required || attdef.Presence == SchemaDeclBase.Use.RequiredFixed) {
1767                         SendValidationEvent(Res.Sch_MissRequiredAttribute, attdef.Name.ToString());
1768                     }
1769                 }
1770             }
1771         }
1772
1773         private XmlSchemaElement GetSchemaElement() {
1774             SchemaElementDecl beforeXsiDecl = context.ElementDeclBeforeXsi;
1775             SchemaElementDecl currentDecl = context.ElementDecl;
1776
1777             if (beforeXsiDecl != null) { //Have a xsi:type
1778                 if (beforeXsiDecl.SchemaElement != null) {
1779                     XmlSchemaElement xsiElement = (XmlSchemaElement)beforeXsiDecl.SchemaElement.Clone(null);
1780                     xsiElement.SchemaTypeName = XmlQualifiedName.Empty; //Reset typeName on element as this might be different
1781                     xsiElement.SchemaType = currentDecl.SchemaType;
1782                     xsiElement.SetElementType(currentDecl.SchemaType);
1783                     xsiElement.ElementDecl = currentDecl;
1784                     return xsiElement;
1785                 }
1786             }
1787             return currentDecl.SchemaElement;
1788         }
1789
1790         internal string GetDefaultAttributePrefix(string attributeNS) {
1791             IDictionary<string,string> namespaceDecls = nsResolver.GetNamespacesInScope(XmlNamespaceScope.All);
1792             string defaultPrefix = null;
1793             string defaultNS;
1794
1795             foreach (KeyValuePair<string,string> pair in namespaceDecls) {
1796                 defaultNS = nameTable.Add(pair.Value);
1797                 if (Ref.Equal(defaultNS, attributeNS)) {
1798                     defaultPrefix = pair.Key;
1799                     if (defaultPrefix.Length != 0) { //Locate first non-empty prefix
1800                         return defaultPrefix;
1801                     }
1802                 }
1803             }
1804             return defaultPrefix;
1805         }
1806
1807         private void AddIdentityConstraints() {
1808             SchemaElementDecl currentElementDecl = context.ElementDecl;
1809             context.Constr = new ConstraintStruct[currentElementDecl.Constraints.Length];
1810             int id = 0;
1811             for (int i = 0; i < currentElementDecl.Constraints.Length; ++i)
1812             {
1813                 context.Constr[id++] = new ConstraintStruct(currentElementDecl.Constraints[i]);
1814             } // foreach constraint /constraintstruct
1815
1816             // added on June 19, make connections between new keyref tables with key/unique tables in stack
1817             // i can't put it in the above loop, coz there will be key on the same level
1818             for (int i = 0; i < context.Constr.Length; ++i) {
1819                 if ( context.Constr[i].constraint.Role == CompiledIdentityConstraint.ConstraintRole.Keyref ) {
1820                     bool find = false;
1821                     // go upwards checking or only in this level
1822                     for (int level = this.validationStack.Length - 1; level >= ((this.startIDConstraint >= 0) ? this.startIDConstraint : this.validationStack.Length - 1); level --) {
1823                         // no constraint for this level
1824                         if (((ValidationState)(this.validationStack[level])).Constr == null) {
1825                             continue;
1826                         }
1827                         // else
1828                         ConstraintStruct[] constraintStructures = ((ValidationState)this.validationStack[level]).Constr;
1829                         for (int j = 0; j < constraintStructures.Length; ++j) {
1830                             if (constraintStructures[j].constraint.name == context.Constr[i].constraint.refer) {
1831                                 find = true;
1832                                 if (constraintStructures[j].keyrefTable == null) {
1833                                     constraintStructures[j].keyrefTable = new Hashtable();
1834                                 }
1835                                 context.Constr[i].qualifiedTable = constraintStructures[j].keyrefTable;
1836                                 break;
1837                             }
1838                         }
1839
1840                         if (find) {
1841                             break;
1842                         }
1843                     }
1844                     if (!find) {
1845                         // didn't find connections, throw exceptions
1846                         SendValidationEvent(Res.Sch_RefNotInScope, QNameString(context.LocalName, context.Namespace));
1847                     }
1848                 } // finished dealing with keyref
1849
1850             }  // end foreach
1851
1852             // initial set
1853             if (this.startIDConstraint == -1) {
1854                 this.startIDConstraint = this.validationStack.Length - 1;
1855             }
1856         }
1857
1858         private void ElementIdentityConstraints () {
1859             SchemaElementDecl currentElementDecl = context.ElementDecl;
1860             string localName = context.LocalName;
1861             string namespaceUri = context.Namespace;
1862
1863             for (int i = this.startIDConstraint; i < this.validationStack.Length; i ++) {
1864                 // no constraint for this level
1865                 if (((ValidationState)(this.validationStack[i])).Constr == null) {
1866                     continue;
1867                 }
1868
1869                 // else
1870                 ConstraintStruct[] constraintStructures = ((ValidationState)this.validationStack[i]).Constr;
1871                 for (int j = 0; j < constraintStructures.Length; ++j) {
1872                     // check selector from here
1873                     if (constraintStructures[j].axisSelector.MoveToStartElement(localName, namespaceUri)) {
1874                         // selector selects new node, activate a new set of fields
1875                         Debug.WriteLine("Selector Match!");
1876                         Debug.WriteLine("Name: " + localName + "\t|\tURI: " + namespaceUri + "\n");
1877
1878                         // in which axisFields got updated
1879                         constraintStructures[j].axisSelector.PushKS(positionInfo.LineNumber, positionInfo.LinePosition);
1880                     }
1881
1882                     // axisFields is not null, but may be empty
1883                     for (int k = 0; k < constraintStructures[j].axisFields.Count; ++k) {
1884                         LocatedActiveAxis laxis = (LocatedActiveAxis)constraintStructures[j].axisFields[k];
1885
1886                         // check field from here
1887                         if (laxis.MoveToStartElement(localName, namespaceUri)) {
1888                             Debug.WriteLine("Element Field Match!");
1889                             // checking simpleType / simpleContent
1890                             if (currentElementDecl != null) {      // nextElement can be null when xml/xsd are not valid
1891                                 if (currentElementDecl.Datatype == null || currentElementDecl.ContentValidator.ContentType == XmlSchemaContentType.Mixed) {
1892                                     SendValidationEvent(Res.Sch_FieldSimpleTypeExpected, localName);
1893                                 }
1894                                 else {
1895                                     // can't fill value here, wait till later....
1896                                     // fill type : xsdType
1897                                     laxis.isMatched = true;
1898                                     // since it's simpletyped element, the endchildren will come consequently... don't worry
1899                                 }
1900                             }
1901                         }
1902                     }
1903                 }
1904             }
1905         }
1906
1907         private void AttributeIdentityConstraints(string name, string ns, object obj, string sobj, XmlSchemaDatatype datatype) {
1908             for (int ci = this.startIDConstraint; ci < this.validationStack.Length; ci ++) {
1909                 // no constraint for this level
1910                 if (((ValidationState)(this.validationStack[ci])).Constr == null) {
1911                     continue;
1912                 }
1913
1914                 // else
1915                 ConstraintStruct[] constraintStructures = ((ValidationState)this.validationStack[ci]).Constr;
1916                 for (int i = 0; i < constraintStructures.Length; ++i) {
1917                     // axisFields is not null, but may be empty
1918                     for (int j = 0; j < constraintStructures[i].axisFields.Count; ++j) {
1919                         LocatedActiveAxis laxis = (LocatedActiveAxis)constraintStructures[i].axisFields[j];
1920
1921                         // check field from here
1922                         if (laxis.MoveToAttribute(name, ns)) {
1923                             Debug.WriteLine("Attribute Field Match!");
1924                             //attribute is only simpletype, so needn't checking...
1925                             // can fill value here, yeah!!
1926                             Debug.WriteLine("Attribute Field Filling Value!");
1927                             Debug.WriteLine("Name: " + name + "\t|\tURI: " + ns + "\t|\tValue: " + obj + "\n");
1928                             if (laxis.Ks[laxis.Column] != null) {
1929                                 // should be evaluated to either an empty node-set or a node-set with exactly one member
1930                                 // two matches...
1931                                 SendValidationEvent (Res.Sch_FieldSingleValueExpected, name);
1932                             }
1933                             else {
1934                                 Debug.Assert(datatype != null);
1935                                 laxis.Ks[laxis.Column] = new TypedObject (obj, sobj, datatype);
1936                             }
1937                         }
1938                     }
1939                 }
1940             }
1941         }
1942
1943         private void EndElementIdentityConstraints(object typedValue, string stringValue, XmlSchemaDatatype datatype) {
1944             string localName = context.LocalName;
1945             string namespaceUri = context.Namespace;
1946             for (int ci = this.validationStack.Length - 1; ci >= this.startIDConstraint; ci --) {
1947                 // no constraint for this level
1948                 if (((ValidationState)(this.validationStack[ci])).Constr == null) {
1949                     continue;
1950                 }
1951
1952                 // else
1953                 ConstraintStruct[] constraints = ((ValidationState)this.validationStack[ci]).Constr;
1954                 for (int i = 0; i < constraints.Length; ++i) {
1955                     // EndChildren
1956                     // axisFields is not null, but may be empty
1957                     for (int j = 0; j < constraints[i].axisFields.Count; ++j) {
1958                         LocatedActiveAxis laxis = (LocatedActiveAxis)constraints[i].axisFields[j];
1959
1960                         // check field from here
1961                         // isMatched is false when nextElement is null. so needn't change this part.
1962                         if (laxis.isMatched) {
1963                             Debug.WriteLine("Element Field Filling Value!");
1964                             Debug.WriteLine("Name: " + localName + "\t|\tURI: " + namespaceUri + "\t|\tValue: " + typedValue + "\n");
1965                             // fill value
1966                             laxis.isMatched = false;
1967                             if (laxis.Ks[laxis.Column] != null) {
1968                                 // [field...] should be evaluated to either an empty node-set or a node-set with exactly one member
1969                                 // two matches... already existing field value in the table.
1970                                 SendValidationEvent (Res.Sch_FieldSingleValueExpected, localName);
1971                             }
1972                             else {
1973                                 // for element, Reader.Value = "";
1974                                 if(typedValue != null && stringValue.Length != 0) {
1975                                     laxis.Ks[laxis.Column] = new TypedObject(typedValue, stringValue, datatype);
1976                                 }
1977                             }
1978                         }
1979                         // EndChildren
1980                         laxis.EndElement(localName, namespaceUri);
1981                     }
1982
1983                     if (constraints[i].axisSelector.EndElement(localName, namespaceUri)) {
1984                         // insert key sequence into hash (+ located active axis tuple leave for later)
1985                         KeySequence ks = constraints[i].axisSelector.PopKS();
1986                         // unqualified keysequence are not allowed
1987                         switch (constraints[i].constraint.Role) {
1988                         case CompiledIdentityConstraint.ConstraintRole.Key:
1989                             if (! ks.IsQualified()) {
1990                                 //Key's fields can't be null...  if we can return context node's line info maybe it will be better
1991                                 //only keymissing & keyduplicate reporting cases are necessary to be dealt with... 3 places...
1992                                 SendValidationEvent(new XmlSchemaValidationException(Res.Sch_MissingKey, constraints[i].constraint.name.ToString(), sourceUriString, ks.PosLine, ks.PosCol));
1993                             }
1994                             else if (constraints[i].qualifiedTable.Contains (ks)) {
1995                                 // unique or key checking value confliction
1996                                 // for redundant key, reporting both occurings
1997                                 // doesn't work... how can i retrieve value out??
1998 //                                        KeySequence ks2 = (KeySequence) conuct.qualifiedTable[ks];
1999                                 SendValidationEvent(new XmlSchemaValidationException(Res.Sch_DuplicateKey,
2000                                     new string[2] {ks.ToString(), constraints[i].constraint.name.ToString()},
2001                                     sourceUriString, ks.PosLine, ks.PosCol));
2002                             }
2003                             else {
2004                                 constraints[i].qualifiedTable.Add (ks, ks);
2005                             }
2006                             break;
2007
2008                         case CompiledIdentityConstraint.ConstraintRole.Unique:
2009                             if (LocalAppContextSwitches.IgnoreEmptyKeySequences) {
2010                                 if (!ks.IsQualified()) {
2011                                     continue;
2012                                 }
2013                             }
2014                             if (constraints[i].qualifiedTable.Contains (ks)) {
2015                                 // unique or key checking confliction
2016 //                                        KeySequence ks2 = (KeySequence) conuct.qualifiedTable[ks];
2017                                 SendValidationEvent(new XmlSchemaValidationException(Res.Sch_DuplicateKey,
2018                                     new string[2] {ks.ToString(), constraints[i].constraint.name.ToString()},
2019                                     sourceUriString, ks.PosLine, ks.PosCol));
2020                             }
2021                             else {
2022                                 constraints[i].qualifiedTable.Add (ks, ks);
2023                             }
2024                             break;
2025                         case CompiledIdentityConstraint.ConstraintRole.Keyref:
2026                             // is there any possibility:
2027                             // 2 keyrefs: value is equal, type is not
2028                             // both put in the hashtable, 1 reference, 1 not
2029                             if (constraints[i].qualifiedTable != null) { //Will be null in cases when the keyref is outside the scope of the key, that is not allowed by our impl
2030                                 if (! ks.IsQualified() || constraints[i].qualifiedTable.Contains (ks)) {
2031                                     continue;
2032                                 }
2033                                 constraints[i].qualifiedTable.Add (ks, ks);
2034                             }
2035                         break;
2036                         }
2037                     }
2038                 }
2039             }
2040
2041
2042             // current level's constraint struct
2043             ConstraintStruct[] vcs = ((ValidationState)(this.validationStack[this.validationStack.Length - 1])).Constr;
2044             if ( vcs != null) {
2045                 // validating all referencing tables...
2046
2047                 for (int i = 0; i < vcs.Length; ++i) {
2048                     if (( vcs[i].constraint.Role == CompiledIdentityConstraint.ConstraintRole.Keyref)
2049                         || (vcs[i].keyrefTable == null)) {
2050                         continue;
2051                     }
2052                     foreach (KeySequence ks in vcs[i].keyrefTable.Keys) {
2053                         if (!vcs[i].qualifiedTable.Contains(ks)) {
2054                             SendValidationEvent(new XmlSchemaValidationException(Res.Sch_UnresolvedKeyref, new string[2] { ks.ToString(), vcs[i].constraint.name.ToString() },
2055                                 sourceUriString, ks.PosLine, ks.PosCol));
2056                         }
2057                     }
2058                 }
2059             }
2060
2061           } //End of method
2062
2063         private static void BuildXsiAttributes() {
2064             if (xsiTypeSO == null) { //xsi:type attribute
2065                 XmlSchemaAttribute tempXsiTypeSO = new XmlSchemaAttribute();
2066                 tempXsiTypeSO.Name = "type";
2067                 tempXsiTypeSO.SetQualifiedName(new XmlQualifiedName("type", XmlReservedNs.NsXsi));
2068                 tempXsiTypeSO.SetAttributeType(XmlSchemaType.GetBuiltInSimpleType(XmlTypeCode.QName));
2069                 Interlocked.CompareExchange<XmlSchemaAttribute>(ref xsiTypeSO, tempXsiTypeSO, null);
2070             }
2071             if (xsiNilSO == null) { //xsi:nil
2072                 XmlSchemaAttribute tempxsiNilSO = new XmlSchemaAttribute();
2073                 tempxsiNilSO.Name = "nil";
2074                 tempxsiNilSO.SetQualifiedName(new XmlQualifiedName("nil", XmlReservedNs.NsXsi));
2075                 tempxsiNilSO.SetAttributeType(XmlSchemaType.GetBuiltInSimpleType(XmlTypeCode.Boolean));
2076                 Interlocked.CompareExchange<XmlSchemaAttribute>(ref xsiNilSO, tempxsiNilSO, null);
2077             }
2078             if (xsiSLSO == null) { //xsi:schemaLocation
2079                 XmlSchemaSimpleType stringType = XmlSchemaType.GetBuiltInSimpleType(XmlTypeCode.String);
2080                 XmlSchemaAttribute tempxsiSLSO = new XmlSchemaAttribute();
2081                 tempxsiSLSO.Name = "schemaLocation";
2082                 tempxsiSLSO.SetQualifiedName(new XmlQualifiedName("schemaLocation", XmlReservedNs.NsXsi));
2083                 tempxsiSLSO.SetAttributeType(stringType);
2084                 Interlocked.CompareExchange<XmlSchemaAttribute>(ref xsiSLSO, tempxsiSLSO, null);
2085             }
2086             if (xsiNoNsSLSO == null) {
2087                 XmlSchemaSimpleType stringType = XmlSchemaType.GetBuiltInSimpleType(XmlTypeCode.String);
2088                 XmlSchemaAttribute tempxsiNoNsSLSO = new XmlSchemaAttribute();
2089                 tempxsiNoNsSLSO.Name = "noNamespaceSchemaLocation";
2090                 tempxsiNoNsSLSO.SetQualifiedName(new XmlQualifiedName("noNamespaceSchemaLocation", XmlReservedNs.NsXsi));
2091                 tempxsiNoNsSLSO.SetAttributeType(stringType);
2092                 Interlocked.CompareExchange<XmlSchemaAttribute>(ref xsiNoNsSLSO, tempxsiNoNsSLSO, null);
2093             }
2094         }
2095
2096         internal static void ElementValidationError(XmlQualifiedName name, ValidationState context, ValidationEventHandler eventHandler, object sender, string sourceUri, int lineNo, int linePos, XmlSchemaSet schemaSet) {
2097             ArrayList names = null;
2098             if (context.ElementDecl != null) {
2099                 ContentValidator contentValidator = context.ElementDecl.ContentValidator;
2100                 XmlSchemaContentType contentType = contentValidator.ContentType;
2101                 if (contentType == XmlSchemaContentType.ElementOnly || (contentType == XmlSchemaContentType.Mixed && contentValidator != ContentValidator.Mixed && contentValidator != ContentValidator.Any)) {
2102                     Debug.Assert(contentValidator is DfaContentValidator || contentValidator is NfaContentValidator || contentValidator is RangeContentValidator || contentValidator is AllElementsContentValidator);
2103                     bool getParticles = schemaSet != null;
2104                     if (getParticles) {
2105                         names = contentValidator.ExpectedParticles(context, false, schemaSet);
2106                     }
2107                     else {
2108                         names = contentValidator.ExpectedElements(context, false);
2109                     }
2110
2111                     if (names == null || names.Count == 0) {
2112                         if (context.TooComplex) {
2113                             SendValidationEvent(eventHandler, sender, new XmlSchemaValidationException(Res.Sch_InvalidElementContentComplex, new string[] { BuildElementName(context.LocalName, context.Namespace), BuildElementName(name), Res.GetString(Res.Sch_ComplexContentModel) }, sourceUri, lineNo, linePos), XmlSeverityType.Error);
2114                         }
2115                         else {
2116                             SendValidationEvent(eventHandler, sender, new XmlSchemaValidationException(Res.Sch_InvalidElementContent, new string[] { BuildElementName(context.LocalName, context.Namespace), BuildElementName(name) }, sourceUri, lineNo, linePos), XmlSeverityType.Error);
2117                         }
2118                     }
2119                     else {
2120                         Debug.Assert(names.Count > 0);
2121                         if (context.TooComplex) {
2122                             SendValidationEvent(eventHandler, sender, new XmlSchemaValidationException(Res.Sch_InvalidElementContentExpectingComplex, new string[] { BuildElementName(context.LocalName, context.Namespace), BuildElementName(name), PrintExpectedElements(names, getParticles), Res.GetString(Res.Sch_ComplexContentModel) }, sourceUri, lineNo, linePos), XmlSeverityType.Error);
2123                         }
2124                         else {
2125                             SendValidationEvent(eventHandler, sender, new XmlSchemaValidationException(Res.Sch_InvalidElementContentExpecting, new string[] { BuildElementName(context.LocalName, context.Namespace), BuildElementName(name), PrintExpectedElements(names, getParticles) }, sourceUri, lineNo, linePos), XmlSeverityType.Error);
2126                         }
2127                     }
2128                 }
2129                 else { //Base ContentValidator: Empty || TextOnly || Mixed || Any
2130                     if (contentType == XmlSchemaContentType.Empty) {
2131                         SendValidationEvent(eventHandler, sender, new XmlSchemaValidationException(Res.Sch_InvalidElementInEmptyEx, new string[] { QNameString(context.LocalName, context.Namespace), name.ToString() }, sourceUri, lineNo, linePos), XmlSeverityType.Error);
2132                     }
2133                     else if (!contentValidator.IsOpen) {
2134                         SendValidationEvent(eventHandler, sender, new XmlSchemaValidationException(Res.Sch_InvalidElementInTextOnlyEx, new string[] { QNameString(context.LocalName, context.Namespace), name.ToString() }, sourceUri, lineNo, linePos), XmlSeverityType.Error);
2135                     }
2136                 }
2137             }
2138         }
2139
2140         internal static void CompleteValidationError(ValidationState context, ValidationEventHandler eventHandler, object sender, string sourceUri, int lineNo, int linePos, XmlSchemaSet schemaSet)
2141         {
2142             ArrayList names = null;
2143             bool getParticles = schemaSet != null;
2144             if (context.ElementDecl != null) {
2145                 if (getParticles) {
2146                     names = context.ElementDecl.ContentValidator.ExpectedParticles(context, true, schemaSet);
2147                 }
2148                 else {
2149                     names = context.ElementDecl.ContentValidator.ExpectedElements(context, true);
2150                 }
2151             }
2152             if (names == null || names.Count == 0) {
2153                 if (context.TooComplex) {
2154                     SendValidationEvent(eventHandler, sender, new XmlSchemaValidationException(Res.Sch_IncompleteContentComplex, new string[] { BuildElementName(context.LocalName, context.Namespace), Res.GetString(Res.Sch_ComplexContentModel) }, sourceUri, lineNo, linePos), XmlSeverityType.Error);
2155                 }
2156                 SendValidationEvent(eventHandler, sender, new XmlSchemaValidationException(Res.Sch_IncompleteContent, BuildElementName(context.LocalName, context.Namespace), sourceUri, lineNo, linePos), XmlSeverityType.Error);
2157             }
2158             else {
2159                 Debug.Assert(names.Count > 0);
2160                 if (context.TooComplex) {
2161                     SendValidationEvent(eventHandler, sender, new XmlSchemaValidationException(Res.Sch_IncompleteContentExpectingComplex, new string[] { BuildElementName(context.LocalName, context.Namespace), PrintExpectedElements(names, getParticles), Res.GetString(Res.Sch_ComplexContentModel) }, sourceUri, lineNo, linePos), XmlSeverityType.Error);
2162                 }
2163                 else {
2164                     SendValidationEvent(eventHandler, sender, new XmlSchemaValidationException(Res.Sch_IncompleteContentExpecting, new string[] { BuildElementName(context.LocalName, context.Namespace), PrintExpectedElements(names, getParticles) }, sourceUri, lineNo, linePos), XmlSeverityType.Error);
2165                 }
2166             }
2167         }
2168
2169         internal static string PrintExpectedElements(ArrayList expected, bool getParticles) {
2170             if (getParticles) {
2171                 string ContinuationString = Res.GetString(Res.Sch_ContinuationString, new string[] {" "});
2172                 XmlSchemaParticle currentParticle = null;
2173                 XmlSchemaParticle nextParticle = null;
2174                 XmlQualifiedName currentQName;
2175                 ArrayList expectedNames = new ArrayList();
2176                 StringBuilder builder = new StringBuilder();
2177
2178                 if (expected.Count == 1) {
2179                     nextParticle = expected[0] as XmlSchemaParticle;
2180                 }
2181                 else {
2182                     for (int i=1; i < expected.Count; i++) {
2183                         currentParticle = expected[i-1] as XmlSchemaParticle;
2184                         nextParticle = expected[i] as XmlSchemaParticle;
2185                         currentQName = currentParticle.GetQualifiedName();
2186                         if (currentQName.Namespace != nextParticle.GetQualifiedName().Namespace) {
2187                             expectedNames.Add(currentQName);
2188                             PrintNamesWithNS(expectedNames, builder);
2189                             expectedNames.Clear();
2190                             Debug.Assert(builder.Length != 0);
2191                             builder.Append(ContinuationString);
2192                         }
2193                         else {
2194                             expectedNames.Add(currentQName);
2195                         }
2196                     }
2197                 }
2198                 //Add last one.
2199                 expectedNames.Add(nextParticle.GetQualifiedName());
2200                 PrintNamesWithNS(expectedNames, builder);
2201
2202                 return builder.ToString();
2203             }
2204             else {
2205                 return PrintNames(expected);
2206             }
2207         }
2208
2209         private static string PrintNames(ArrayList expected) {
2210             StringBuilder builder = new StringBuilder();
2211             builder.Append(Quote);
2212             builder.Append(expected[0].ToString());
2213             for (int i = 1; i < expected.Count; ++i) {
2214                 builder.Append(" ");
2215                 builder.Append(expected[i].ToString());
2216             }
2217             builder.Append(Quote);
2218             return builder.ToString();
2219         }
2220
2221         private static void PrintNamesWithNS(ArrayList expected, StringBuilder builder) {
2222             XmlQualifiedName name = null;
2223             name = expected[0] as XmlQualifiedName;
2224             if (expected.Count == 1) { //In case of one element in a namespace or any
2225                 if (name.Name == "*") { //Any
2226                     EnumerateAny(builder, name.Namespace);
2227                 }
2228                 else {
2229                     if (name.Namespace.Length != 0) {
2230                         builder.Append(Res.GetString(Res.Sch_ElementNameAndNamespace, name.Name, name.Namespace));
2231                     }
2232                     else {
2233                         builder.Append(Res.GetString(Res.Sch_ElementName, name.Name));
2234                     }
2235                 }
2236             }
2237             else {
2238                 bool foundAny = false;
2239                 bool first = true;
2240                 StringBuilder subBuilder = new StringBuilder();
2241                 for (int i = 0; i < expected.Count; i++) {
2242                     name = expected[i] as XmlQualifiedName;
2243                     if (name.Name == "*") { //rare case where ns of element and that of Any match
2244                         foundAny = true;
2245                         continue;
2246                     }
2247                     if (first) {
2248                         first = false;
2249                     }
2250                     else {
2251                         subBuilder.Append(", ");
2252                     }
2253                     subBuilder.Append(name.Name);
2254                 }
2255                 if (foundAny) {
2256                     subBuilder.Append(", ");
2257                     subBuilder.Append(Res.GetString(Res.Sch_AnyElement));
2258                 }
2259                 else {
2260                     if (name.Namespace.Length != 0) {
2261                         builder.Append(Res.GetString(Res.Sch_ElementNameAndNamespace, subBuilder.ToString(), name.Namespace));
2262                     }
2263                     else {
2264                         builder.Append(Res.GetString(Res.Sch_ElementName, subBuilder.ToString()));
2265                     }
2266                 }
2267             }
2268         }
2269
2270         private static void EnumerateAny(StringBuilder builder, string namespaces) {
2271             StringBuilder subBuilder = new StringBuilder();
2272             if (namespaces == "##any" || namespaces == "##other") {
2273                 subBuilder.Append(namespaces);
2274             }
2275             else {
2276                 string[] nsList = XmlConvert.SplitString(namespaces);
2277                 Debug.Assert(nsList.Length > 0);
2278                 subBuilder.Append(nsList[0]);
2279                 for (int i = 1; i < nsList.Length; i++) {
2280                     subBuilder.Append(", ");
2281                     subBuilder.Append(nsList[i]);
2282                 }
2283             }
2284             builder.Append(Res.GetString(Res.Sch_AnyElementNS, subBuilder.ToString()));
2285         }
2286
2287         internal static string QNameString(string localName, string ns) {
2288             return (ns.Length != 0) ? string.Concat(ns, ":", localName) : localName;
2289         }
2290
2291         internal static string BuildElementName(XmlQualifiedName qname) {
2292             return BuildElementName(qname.Name, qname.Namespace);
2293         }
2294
2295         internal static string BuildElementName(string localName, string ns) {
2296             if (ns.Length != 0) {
2297                 return Res.GetString(Res.Sch_ElementNameAndNamespace, localName, ns);
2298             }
2299             else {
2300                 return Res.GetString(Res.Sch_ElementName, localName);
2301             }
2302         }
2303
2304         private void ProcessEntity(string name) {
2305             if (!this.checkEntity) {
2306                 return;
2307             }
2308             IDtdEntityInfo entityInfo = null;
2309             if (dtdSchemaInfo != null) {
2310                 entityInfo = dtdSchemaInfo.LookupEntity(name);
2311             }
2312             if (entityInfo == null) {
2313                 // validation error, see xml spec [68]
2314                 SendValidationEvent(Res.Sch_UndeclaredEntity, name);
2315             }
2316             else if (entityInfo.IsUnparsedEntity) {
2317                 // validation error, see xml spec [68]
2318                 SendValidationEvent(Res.Sch_UnparsedEntityRef, name);
2319             }
2320         }
2321
2322         private void SendValidationEvent(string code) {
2323             SendValidationEvent(code, string.Empty);
2324         }
2325
2326         private void SendValidationEvent(string code, string[] args) {
2327             SendValidationEvent(new XmlSchemaValidationException(code, args, sourceUriString, positionInfo.LineNumber, positionInfo.LinePosition));
2328         }
2329
2330         private void SendValidationEvent(string code, string arg) {
2331             SendValidationEvent(new XmlSchemaValidationException(code, arg, sourceUriString, positionInfo.LineNumber, positionInfo.LinePosition));
2332         }
2333
2334         private void SendValidationEvent(string code, string arg1, string arg2) {
2335             SendValidationEvent(new XmlSchemaValidationException(code, new string[] { arg1, arg2 }, sourceUriString, positionInfo.LineNumber, positionInfo.LinePosition));
2336         }
2337
2338         private void SendValidationEvent(string code, string[] args, Exception innerException, XmlSeverityType severity) {
2339             if (severity != XmlSeverityType.Warning || ReportValidationWarnings) {
2340                 SendValidationEvent(new XmlSchemaValidationException(code, args, innerException, sourceUriString, positionInfo.LineNumber, positionInfo.LinePosition), severity);
2341             }
2342         }
2343
2344         private void SendValidationEvent(string code, string[] args, Exception innerException) {
2345             SendValidationEvent(new XmlSchemaValidationException(code, args, innerException, sourceUriString, positionInfo.LineNumber, positionInfo.LinePosition), XmlSeverityType.Error);
2346         }
2347
2348         private void SendValidationEvent(XmlSchemaValidationException e) {
2349             SendValidationEvent(e, XmlSeverityType.Error);
2350         }
2351
2352         private void SendValidationEvent(XmlSchemaException e) {
2353             SendValidationEvent(new XmlSchemaValidationException(e.GetRes,e.Args,e.SourceUri,e.LineNumber,e.LinePosition), XmlSeverityType.Error);
2354         }
2355
2356         private void SendValidationEvent(string code, string msg, XmlSeverityType severity) {
2357             if (severity != XmlSeverityType.Warning || ReportValidationWarnings) {
2358                 SendValidationEvent(new XmlSchemaValidationException(code, msg, sourceUriString, positionInfo.LineNumber, positionInfo.LinePosition), severity);
2359             }
2360         }
2361
2362         private void SendValidationEvent(XmlSchemaValidationException e, XmlSeverityType severity) {
2363             bool errorSeverity = false;
2364             if (severity == XmlSeverityType.Error) {
2365                 errorSeverity = true;
2366                 context.Validity = XmlSchemaValidity.Invalid;
2367             }
2368             if (errorSeverity) {
2369                 if (eventHandler != null) {
2370                     eventHandler(validationEventSender, new ValidationEventArgs(e, severity));
2371                 }
2372                 else {
2373                     throw e;
2374                 }
2375             }
2376             else if (ReportValidationWarnings && eventHandler != null) {
2377                 eventHandler(validationEventSender, new ValidationEventArgs(e, severity));
2378             }
2379         }
2380
2381         internal static void SendValidationEvent(ValidationEventHandler eventHandler, object sender, XmlSchemaValidationException e, XmlSeverityType severity) {
2382             if (eventHandler != null) {
2383                 eventHandler(sender, new ValidationEventArgs(e, severity));
2384             }
2385             else if (severity == XmlSeverityType.Error) {
2386                 throw e;
2387             }
2388         }
2389      } //End of class
2390
2391 } //End of namespace