2004-08-10 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / class / System.XML / Mono.Xml.Schema / XsdValidatingReader.cs
1 //
2 // Mono.Xml.Schema.XsdValidatingReader.cs
3 //
4 // Author:
5 //      Atsushi Enomoto (ginga@kit.hi-ho.ne.jp)
6 //
7 //      (C)2003 Atsushi Enomoto
8 //
9 // Note:
10 //
11 // This class doesn't support set_XmlResolver, since it isn't common to XmlReader interface. 
12 // Try to set that of xml reader which is used to construct this object.
13 //
14
15 //
16 // Permission is hereby granted, free of charge, to any person obtaining
17 // a copy of this software and associated documentation files (the
18 // "Software"), to deal in the Software without restriction, including
19 // without limitation the rights to use, copy, modify, merge, publish,
20 // distribute, sublicense, and/or sell copies of the Software, and to
21 // permit persons to whom the Software is furnished to do so, subject to
22 // the following conditions:
23 // 
24 // The above copyright notice and this permission notice shall be
25 // included in all copies or substantial portions of the Software.
26 // 
27 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
31 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
32 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 //
35 using System;
36 using System.Collections;
37 using System.Collections.Specialized;
38 using System.Text;
39 using System.Xml;
40 using System.Xml.Schema;
41 using Mono.Xml;
42
43 namespace Mono.Xml.Schema
44 {
45         internal class XsdValidatingReader : XmlReader, IXmlLineInfo, IHasXmlSchemaInfo, IHasXmlParserContext, IXmlNamespaceResolver
46         {
47                 static char [] wsChars = new char [] {' ', '\t', '\n', '\r'};
48
49                 XmlReader reader;
50                 XmlValidatingReader xvReader;
51                 XmlResolver resolver;
52                 IHasXmlSchemaInfo sourceReaderSchemaInfo;
53                 IXmlLineInfo readerLineInfo;
54                 bool laxElementValidation = true;
55                 bool reportNoValidationError;
56                 XmlSchemaSet schemas = new XmlSchemaSet ();
57                 bool namespaces = true;
58
59                 Hashtable idList = new Hashtable ();
60                 ArrayList missingIDReferences = new ArrayList ();
61                 string thisElementId;
62
63                 ArrayList keyTables = new ArrayList ();
64                 ArrayList currentKeyFieldConsumers = new ArrayList ();
65
66                 XsdValidationStateManager stateManager = new XsdValidationStateManager ();
67                 XsdValidationContext context = new XsdValidationContext ();
68                 XsdValidationState childParticleState;
69
70                 int xsiNilDepth = -1;
71                 StringBuilder storedCharacters = new StringBuilder ();
72                 bool shouldValidateCharacters;
73                 int skipValidationDepth = -1;
74
75                 XmlSchemaAttribute [] defaultAttributes = new XmlSchemaAttribute [0];
76                 int currentDefaultAttribute = -1;
77                 XmlQualifiedName currentQName;
78
79                 ArrayList elementQNameStack = new ArrayList ();
80                 bool popContext;
81
82                 // Property Cache.
83                 int nonDefaultAttributeCount;
84                 bool defaultAttributeConsumed;
85
86                 // Validation engine cached object
87                 ArrayList defaultAttributesCache = new ArrayList ();
88                 ArrayList tmpKeyrefPool = new ArrayList ();
89
90 #region .ctor
91                 public XsdValidatingReader (XmlReader reader)
92                         : this (reader, null)
93                 {
94                 }
95                 
96                 public XsdValidatingReader (XmlReader reader, XmlReader validatingReader)
97                 {
98                         this.reader = reader;
99                         xvReader = validatingReader as XmlValidatingReader;
100                         if (xvReader != null) {
101                                 if (xvReader.ValidationType == ValidationType.None)
102                                         reportNoValidationError = true;
103                         }
104                         readerLineInfo = reader as IXmlLineInfo;
105                         sourceReaderSchemaInfo = reader as IHasXmlSchemaInfo;
106                 }
107 #endregion
108                 // Provate Properties
109                 private XmlQualifiedName CurrentQName {
110                         get {
111                                 if (currentQName == null)
112                                         currentQName = new XmlQualifiedName (LocalName, NamespaceURI);
113                                 return currentQName;
114                         }
115                 }
116
117                 internal ArrayList CurrentKeyFieldConsumers {
118                         get { return currentKeyFieldConsumers; }
119                 }
120
121                 // Public Non-overrides
122
123                 public int XsiNilDepth {
124                         get { return xsiNilDepth; }
125                 }
126
127                 public bool Namespaces {
128                         get { return namespaces; }
129                         set { namespaces = value; }
130                 }
131
132                 public XmlReader Reader {
133                         get { return reader; }
134                 }
135
136                 // This is required to resolve xsi:schemaLocation
137                 public XmlResolver XmlResolver {
138                         set {
139                                 resolver = value;
140                         }
141                 }
142
143                 // This should be changed before the first Read() call.
144                 public XmlSchemaSet Schemas {
145                         get { return schemas; }
146                         set {
147                                 if (ReadState != ReadState.Initial)
148                                         throw new InvalidOperationException ("Schemas must be set before the first call to Read().");
149                                 schemas = value;
150                         }
151                 }
152
153                 public object SchemaType {
154                         get {
155                                 if (ReadState != ReadState.Interactive)
156                                         return null;
157
158                                 switch (NodeType) {
159                                 case XmlNodeType.Element:
160                                         if (context.ActualType != null)
161                                                 return context.ActualType;
162                                         else if (context.Element != null)
163                                                 return context.Element.ElementType;
164                                         else
165                                                 return SourceReaderSchemaType;
166                                 case XmlNodeType.Attribute:
167                                         XmlSchemaComplexType ct = context.ActualType as XmlSchemaComplexType;
168                                         if (ct != null) {
169                                                 XmlSchemaAttribute attdef = ct.AttributeUses [CurrentQName] as XmlSchemaAttribute;
170                                                 if (attdef != null)
171                                                         return attdef.AttributeType;
172                                         }
173                                         return SourceReaderSchemaType;
174                                 default:
175                                         return SourceReaderSchemaType;
176                                 }
177                         }
178                 }
179
180                 private object SourceReaderSchemaType {
181                         get { return this.sourceReaderSchemaInfo != null ? sourceReaderSchemaInfo.SchemaType : null; }
182                 }
183
184                 // This property is never used in Mono.
185                 public ValidationType ValidationType {
186                         get {
187                                 if (reportNoValidationError)
188                                         return ValidationType.None;
189                                 else
190                                         return ValidationType.Schema;
191                         }
192                 }
193
194                 IDictionary IXmlNamespaceResolver.GetNamespacesInScope (XmlNamespaceScope scope)
195                 {
196                         IXmlNamespaceResolver resolver = reader as IXmlNamespaceResolver;
197                         if (resolver == null)
198                                 throw new NotSupportedException ("The input XmlReader does not implement IXmlNamespaceResolver and thus this validating reader cannot collect in-scope namespaces.");
199                         return resolver.GetNamespacesInScope (scope);
200                 }
201
202                 string IXmlNamespaceResolver.LookupPrefix (string ns)
203                 {
204                         return ((IXmlNamespaceResolver) this).LookupPrefix (ns, false);
205                 }
206
207                 string IXmlNamespaceResolver.LookupPrefix (string ns, bool atomizedNames)
208                 {
209                         IXmlNamespaceResolver resolver = reader as IXmlNamespaceResolver;
210                         if (resolver == null)
211                                 throw new NotSupportedException ("The input XmlReader does not implement IXmlNamespaceResolver and thus this validating reader cannot execute namespace prefix lookup.");
212                         return resolver.LookupPrefix (ns, atomizedNames);
213                 }
214
215                 // It is used only for independent XmlReader use, not for XmlValidatingReader.
216                 public object ReadTypedValue ()
217                 {
218                         XmlSchemaDatatype dt = SchemaType as XmlSchemaDatatype;
219                         XmlSchemaSimpleType st = SchemaType as XmlSchemaSimpleType;
220                         if (st != null)
221                                 dt = st.Datatype;
222                         if (dt == null)
223                                 return null;
224
225                         switch (NodeType) {
226                         case XmlNodeType.Element:
227                                 if (IsEmptyElement)
228                                         return null;
229
230                                 storedCharacters.Length = 0;
231                                 bool loop = true;
232                                 do {
233                                         Read ();
234                                         switch (NodeType) {
235                                         case XmlNodeType.SignificantWhitespace:
236                                         case XmlNodeType.Text:
237                                         case XmlNodeType.CDATA:
238                                                 storedCharacters.Append (Value);
239                                                 break;
240                                         case XmlNodeType.Comment:
241                                                 break;
242                                         default:
243                                                 loop = false;
244                                                 break;
245                                         }
246                                 } while (loop && !EOF);
247                                 return dt.ParseValue (storedCharacters.ToString (), NameTable, ParserContext.NamespaceManager);
248                         case XmlNodeType.Attribute:
249                                 return dt.ParseValue (Value, NameTable, ParserContext.NamespaceManager);
250                         }
251                         return null;
252                 }
253
254                 public ValidationEventHandler ValidationEventHandler;
255
256                 // Public Overrided Properties
257
258                 public override int AttributeCount {
259                         get {
260                                 return nonDefaultAttributeCount + defaultAttributes.Length;
261                         }
262                 }
263
264                 public override string BaseURI {
265                         get { return reader.BaseURI; }
266                 }
267
268                 // If this class is used to implement XmlValidatingReader,
269                 // it should be left to DTDValidatingReader. In other cases,
270                 // it depends on the reader's ability.
271                 public override bool CanResolveEntity {
272                         get { return reader.CanResolveEntity; }
273                 }
274
275                 public override int Depth {
276                         get {
277                                 if (currentDefaultAttribute < 0)
278                                         return reader.Depth;
279                                 if (this.defaultAttributeConsumed)
280                                         return reader.Depth + 2;
281                                 return reader.Depth + 1;
282                         }
283                 }
284
285                 public override bool EOF {
286                         get { return reader.EOF; }
287                 }
288
289                 public override bool HasValue {
290                         get {
291                                 if (currentDefaultAttribute < 0)
292                                         return reader.HasValue;
293                                 return true;
294                         }
295                 }
296
297                 public override bool IsDefault {
298                         get {
299                                 if (currentDefaultAttribute < 0)
300                                         return reader.IsDefault;
301                                 return true;
302                         }
303                 }
304
305                 public override bool IsEmptyElement {
306                         get {
307                                 if (currentDefaultAttribute < 0)
308                                         return reader.IsEmptyElement;
309                                 return false;
310                         }
311                 }
312
313                 public override string this [int i] {
314                         get { return GetAttribute (i); }
315                 }
316
317                 public override string this [string name] {
318                         get { return GetAttribute (name); }
319                 }
320
321                 public override string this [string localName, string ns] {
322                         get { return GetAttribute (localName, ns); }
323                 }
324
325                 int IXmlLineInfo.LineNumber {
326                         get { return readerLineInfo != null ? readerLineInfo.LineNumber : 0; }
327                 }
328
329                 int IXmlLineInfo.LinePosition {
330                         get { return readerLineInfo != null ? readerLineInfo.LinePosition : 0; }
331                 }
332
333                 public override string LocalName {
334                         get {
335                                 if (currentDefaultAttribute < 0)
336                                         return reader.LocalName;
337                                 if (defaultAttributeConsumed)
338                                         return String.Empty;
339                                 return defaultAttributes [currentDefaultAttribute].QualifiedName.Name;
340                         }
341                 }
342
343                 public override string Name {
344                         get {
345                                 if (currentDefaultAttribute < 0)
346                                         return reader.Name;
347                                 if (defaultAttributeConsumed)
348                                         return String.Empty;
349
350                                 XmlQualifiedName qname = defaultAttributes [currentDefaultAttribute].QualifiedName;
351                                 string prefix = Prefix;
352                                 if (prefix == String.Empty)
353                                         return qname.Name;
354                                 else
355                                         return String.Concat (prefix, ":", qname.Name);
356                         }
357                 }
358
359                 public override string NamespaceURI {
360                         get {
361                                 if (currentDefaultAttribute < 0)
362                                         return reader.NamespaceURI;
363                                 if (defaultAttributeConsumed)
364                                         return String.Empty;
365                                 return defaultAttributes [currentDefaultAttribute].QualifiedName.Namespace;
366                         }
367                 }
368
369                 public override XmlNameTable NameTable {
370                         get { return reader.NameTable; }
371                 }
372
373                 public override XmlNodeType NodeType {
374                         get {
375                                 if (currentDefaultAttribute < 0)
376                                         return reader.NodeType;
377                                 if (defaultAttributeConsumed)
378                                         return XmlNodeType.Text;
379                                 return XmlNodeType.Attribute;
380                         }
381                 }
382
383                 public XmlParserContext ParserContext {
384                         get { return XmlSchemaUtil.GetParserContext (reader); }
385                 }
386
387                 public override string Prefix {
388                         get {
389                                 if (currentDefaultAttribute < 0)
390                                         return reader.Prefix;
391                                 if (defaultAttributeConsumed)
392                                         return String.Empty;
393                                 XmlQualifiedName qname = defaultAttributes [currentDefaultAttribute].QualifiedName;
394                                 string prefix = this.ParserContext.NamespaceManager.LookupPrefix (qname.Namespace, false);
395                                 if (prefix == null)
396                                         return String.Empty;
397                                 else
398                                         return prefix;
399                         }
400                 }
401
402                 public override char QuoteChar {
403                         get { return reader.QuoteChar; }
404                 }
405
406                 public override ReadState ReadState {
407                         get { return reader.ReadState; }
408                 }
409
410                 public override string Value {
411                         get {
412                                 if (currentDefaultAttribute < 0)
413                                         return reader.Value;
414                                 string value = defaultAttributes [currentDefaultAttribute].ValidatedDefaultValue;
415                                 if (value == null)
416                                         value = defaultAttributes [currentDefaultAttribute].ValidatedFixedValue;
417                                 return value;
418                         }
419                 }
420
421                 XmlQualifiedName qnameXmlLang = new XmlQualifiedName ("lang", XmlNamespaceManager.XmlnsXml);
422
423                 public override string XmlLang {
424                         get {
425                                 string xmlLang = reader.XmlLang;
426                                 if (xmlLang != null)
427                                         return xmlLang;
428                                 int idx = this.FindDefaultAttribute ("lang", XmlNamespaceManager.XmlnsXml);
429                                 if (idx < 0)
430                                         return null;
431                                 xmlLang = defaultAttributes [idx].ValidatedDefaultValue;
432                                 if (xmlLang == null)
433                                         xmlLang = defaultAttributes [idx].ValidatedFixedValue;
434                                 return xmlLang;
435                         }
436                 }
437
438                 public override XmlSpace XmlSpace {
439                         get {
440                                 XmlSpace space = reader.XmlSpace;
441                                 if (space != XmlSpace.None)
442                                         return space;
443                                 int idx = this.FindDefaultAttribute ("space", XmlNamespaceManager.XmlnsXml);
444                                 if (idx < 0)
445                                         return XmlSpace.None;
446                                 string spaceSpec = defaultAttributes [idx].ValidatedDefaultValue;
447                                 if (spaceSpec == null)
448                                         spaceSpec = defaultAttributes [idx].ValidatedFixedValue;
449                                 return (XmlSpace) Enum.Parse (typeof (XmlSpace), spaceSpec, false);
450                         }
451                 }
452
453                 // Private Methods
454
455                 private XmlQualifiedName QualifyName (string name)
456                 {
457                         return XmlQualifiedName.Parse (name, this);
458                 }
459
460                 private void HandleError (string error)
461                 {
462                         HandleError (error, null);
463                 }
464
465                 private void HandleError (string error, Exception innerException)
466                 {
467                         HandleError (error, innerException, false);
468                 }
469
470                 private void HandleError (string error, Exception innerException, bool isWarning)
471                 {
472                         if (reportNoValidationError)    // extra quick check
473                                 return;
474
475                         XmlSchemaException schemaException = new XmlSchemaException (error, 
476                                         this, this.BaseURI, null, innerException);
477                         HandleError (schemaException, isWarning);
478                 }
479
480                 private void HandleError (XmlSchemaException schemaException)
481                 {
482                         HandleError (schemaException, false);
483                 }
484
485                 private void HandleError (XmlSchemaException schemaException, bool isWarning)
486                 {
487                         if (reportNoValidationError)
488                                 return;
489
490                         ValidationEventArgs e = new ValidationEventArgs (schemaException,
491                                 schemaException.Message, isWarning ? XmlSeverityType.Warning : XmlSeverityType.Error);
492
493                         if (this.ValidationEventHandler != null)
494                                 this.ValidationEventHandler (this, e);
495                         else if (xvReader != null)
496                                 xvReader.OnValidationEvent (this, e);
497                         else if (e.Severity == XmlSeverityType.Error)
498 #if NON_MONO_ENV
499                                 this.xvReader.OnValidationEvent (this, e);
500 #else
501                                 throw e.Exception;
502 #endif
503                 }
504
505                 private XmlSchemaElement FindElement (string name, string ns)
506                 {
507                         return (XmlSchemaElement) schemas.GlobalElements [new XmlQualifiedName (name, ns)];
508                 }
509
510                 private XmlSchemaType FindType (XmlQualifiedName qname)
511                 {
512                         return (XmlSchemaType) schemas.GlobalTypes [qname];
513                 }
514
515                 private void ValidateStartElementParticle ()
516                 {
517                         stateManager.CurrentElement = null;
518                         context.ParticleState = context.ParticleState.EvaluateStartElement (reader.LocalName, reader.NamespaceURI);
519                         if (context.ParticleState == XsdValidationState.Invalid)
520                                 HandleError ("Invalid start element: " + reader.NamespaceURI + ":" + reader.LocalName);
521
522                         context.Element = stateManager.CurrentElement;
523                         if (context.Element != null)
524                                 context.SchemaType = context.Element.ElementType;
525                 }
526
527                 private void ValidateEndElementParticle ()
528                 {
529                         if (childParticleState != null) {
530                                 if (!childParticleState.EvaluateEndElement ()) {
531                                         HandleError ("Invalid end element: " + reader.Name);
532                                 }
533                         }
534                         context.PopScope (reader.Depth);
535                 }
536
537                 // Utility for missing validation completion related to child items.
538                 private void ValidateCharacters ()
539                 {
540                         if (xsiNilDepth >= 0 && xsiNilDepth < reader.Depth)
541                                 HandleError ("Element item appeared, while current element context is nil.");
542
543                         storedCharacters.Append (reader.Value);
544                 }
545
546                 // Utility for missing validation completion related to child items.
547                 private void ValidateEndCharacters ()
548                 {
549                         if (context.ActualType == null)
550                                 return;
551
552                         string value = storedCharacters.ToString ();
553
554                         if (storedCharacters.Length == 0) {
555                                 // 3.3.4 Element Locally Valid (Element) 5.1.2
556                                 if (context.Element != null) {
557                                         if (context.Element.ValidatedDefaultValue != null)
558                                                 value = context.Element.ValidatedDefaultValue;
559                                 }                                       
560                         }
561
562                         XmlSchemaDatatype dt = context.ActualType as XmlSchemaDatatype;
563                         XmlSchemaSimpleType st = context.ActualType as XmlSchemaSimpleType;
564                         if (dt == null) {
565                                 if (st != null) {
566                                         dt = st.Datatype;
567                                 } else {
568                                         XmlSchemaComplexType ct = context.ActualType as XmlSchemaComplexType;
569                                         dt = ct.Datatype;
570                                         switch (ct.ContentType) {
571                                         case XmlSchemaContentType.ElementOnly:
572                                         case XmlSchemaContentType.Empty:
573                                                 if (storedCharacters.Length > 0)
574                                                         HandleError ("Character content not allowed.");
575                                                 break;
576                                         }
577                                 }
578                         }
579                         if (dt != null) {
580                                 // 3.3.4 Element Locally Valid (Element) :: 5.2.2.2. Fixed value constraints
581                                 if (context.Element != null && context.Element.ValidatedFixedValue != null)
582                                         if (value != context.Element.ValidatedFixedValue)
583                                                 HandleError ("Fixed value constraint was not satisfied.");
584                                 AssessStringValid (st, dt, value);
585                         }
586
587                         // Identity field value
588                         while (this.currentKeyFieldConsumers.Count > 0) {
589                                 XsdKeyEntryField field = this.currentKeyFieldConsumers [0] as XsdKeyEntryField;
590                                 if (field.Identity != null)
591                                         HandleError ("Two or more identical field was found. Former value is '" + field.Identity + "' .");
592                                 object identity = null; // This means empty value
593                                 if (dt != null) {
594                                         try {
595                                                 identity = dt.ParseValue (value, NameTable, ParserContext.NamespaceManager);
596                                         } catch (Exception ex) { // FIXME: (wishlist) This is bad manner ;-(
597                                                 HandleError ("Identity value is invalid against its data type " + dt.TokenizedType, ex);
598                                         }
599                                 }
600                                 if (identity == null)
601                                         identity = value;
602
603                                 if (!field.SetIdentityField (identity, reader.Depth == xsiNilDepth, dt as XsdAnySimpleType, this))
604                                         HandleError ("Two or more identical key value was found: '" + value + "' .");
605                                 this.currentKeyFieldConsumers.RemoveAt (0);
606                         }
607
608                         shouldValidateCharacters = false;
609                 }
610
611                 // 3.14.4 String Valid 
612                 private void AssessStringValid (XmlSchemaSimpleType st,
613                         XmlSchemaDatatype dt, string value)
614                 {
615                         XmlSchemaDatatype validatedDatatype = dt;
616                         if (st != null) {
617                                 string normalized = validatedDatatype.Normalize (value);
618                                 string [] values;
619                                 XmlSchemaDatatype itemDatatype;
620                                 XmlSchemaSimpleType itemSimpleType;
621                                 switch (st.DerivedBy) {
622                                 case XmlSchemaDerivationMethod.List:
623                                         XmlSchemaSimpleTypeList listContent = st.Content as XmlSchemaSimpleTypeList;
624                                         values = normalized.Split (wsChars);
625                                         itemDatatype = listContent.ValidatedListItemType as XmlSchemaDatatype;
626                                         itemSimpleType = listContent.ValidatedListItemType as XmlSchemaSimpleType;
627                                         for (int vi = 0; vi < values.Length; vi++) {
628                                                 string each = values [vi];
629                                                 if (each == String.Empty)
630                                                         continue;
631                                                 // validate against ValidatedItemType
632                                                 if (itemDatatype != null) {
633                                                         try {
634                                                                 itemDatatype.ParseValue (each, NameTable, ParserContext.NamespaceManager);
635                                                         } catch (Exception ex) { // FIXME: (wishlist) better exception handling ;-(
636                                                                 HandleError ("List type value contains one or more invalid values.", ex);
637                                                                 break;
638                                                         }
639                                                 }
640                                                 else
641                                                         AssessStringValid (itemSimpleType, itemSimpleType.Datatype, each);
642                                         }
643                                         break;
644                                 case XmlSchemaDerivationMethod.Union:
645                                         XmlSchemaSimpleTypeUnion union = st.Content as XmlSchemaSimpleTypeUnion;
646                                         {
647                                                 string each = normalized;
648                                                 // validate against ValidatedItemType
649                                                 bool passed = false;
650                                                 foreach (object eachType in union.ValidatedTypes) {
651                                                         itemDatatype = eachType as XmlSchemaDatatype;
652                                                         itemSimpleType = eachType as XmlSchemaSimpleType;
653                                                         if (itemDatatype != null) {
654                                                                 try {
655                                                                         itemDatatype.ParseValue (each, NameTable, ParserContext.NamespaceManager);
656                                                                 } catch (Exception) { // FIXME: (wishlist) better exception handling ;-(
657                                                                         continue;
658                                                                 }
659                                                         }
660                                                         else {
661                                                                 try {
662                                                                         AssessStringValid (itemSimpleType, itemSimpleType.Datatype, each);
663                                                                 } catch (XmlSchemaException) {
664                                                                         continue;
665                                                                 }
666                                                         }
667                                                         passed = true;
668                                                         break;
669                                                 }
670                                                 if (!passed) {
671                                                         HandleError ("Union type value contains one or more invalid values.");
672                                                         break;
673                                                 }
674                                         }
675                                         break;
676                                 case XmlSchemaDerivationMethod.Restriction:
677                                         XmlSchemaSimpleTypeRestriction str = st.Content as XmlSchemaSimpleTypeRestriction;
678                                         // facet validation
679                                         if (str != null) {
680                                                 /* Don't forget to validate against inherited type's facets 
681                                                  * Could we simplify this by assuming that the basetype will also
682                                                  * be restriction?
683                                                  * */
684                                                  // mmm, will check later.
685                                                 XmlSchemaSimpleType baseType = st.BaseXmlSchemaType as XmlSchemaSimpleType;
686                                                 if (baseType != null) {
687                                                          AssessStringValid(baseType, dt, normalized);
688                                                 }
689                                                 if (!str.ValidateValueWithFacets (normalized, NameTable)) {
690                                                         HandleError ("Specified value was invalid against the facets.");
691                                                         break;
692                                                 }
693                                         }
694                                         validatedDatatype = st.Datatype;
695                                         break;
696                                 }
697                         }
698                         if (validatedDatatype != null) {
699                                 try {
700                                         validatedDatatype.ParseValue (value, NameTable, ParserContext.NamespaceManager);
701                                 } catch (Exception ex) {        // FIXME: (wishlist) It is bad manner ;-(
702                                         HandleError ("Invalidly typed data was specified.", ex);
703                                 }
704                         }
705                 }
706
707                 private object GetLocalTypeDefinition (string name)
708                 {
709                         object xsiType = null;
710                         XmlQualifiedName typeQName = QualifyName (name);
711                         if (typeQName == XmlSchemaComplexType.AnyTypeName)
712                                 xsiType = XmlSchemaComplexType.AnyType;
713                         else if (XmlSchemaUtil.IsBuiltInDatatypeName (typeQName))
714                                 xsiType = XmlSchemaDatatype.FromName (typeQName);
715                         else
716                                 xsiType = FindType (typeQName);
717                         return xsiType;
718                 }
719
720                 // It is common to ElementLocallyValid::4 and SchemaValidityAssessment::1.2.1.2.4
721                 private void AssessLocalTypeDerivationOK (object xsiType, object baseType, XmlSchemaDerivationMethod flag)
722                 {
723                         XmlSchemaType xsiSchemaType = xsiType as XmlSchemaType;
724                         XmlSchemaComplexType baseComplexType = baseType as XmlSchemaComplexType;
725                         XmlSchemaComplexType xsiComplexType = xsiSchemaType as XmlSchemaComplexType;
726                         if (xsiType != baseType) {
727                                 // Extracted (not extraneous) check for 3.4.6 TypeDerivationOK.
728                                 if (baseComplexType != null)
729                                         flag |= baseComplexType.BlockResolved;
730                                 if (flag == XmlSchemaDerivationMethod.All) {
731                                         HandleError ("Prohibited element type substitution.");
732                                         return;
733                                 } else if (xsiSchemaType != null && (flag & xsiSchemaType.DerivedBy) != 0) {
734                                         HandleError ("Prohibited element type substitution.");
735                                         return;
736                                 }
737                         }
738
739                         if (xsiComplexType != null)
740                                 try {
741                                         xsiComplexType.ValidateTypeDerivationOK (baseType, null, null);
742                                 } catch (XmlSchemaException ex) {
743 //                                      HandleError ("Locally specified schema complex type derivation failed. " + ex.Message, ex);
744                                         HandleError (ex);
745                                 }
746                         else {
747                                 XmlSchemaSimpleType xsiSimpleType = xsiType as XmlSchemaSimpleType;
748                                 if (xsiSimpleType != null) {
749                                         try {
750                                                 xsiSimpleType.ValidateTypeDerivationOK (baseType, null, null, true);
751                                         } catch (XmlSchemaException ex) {
752 //                                              HandleError ("Locally specified schema simple type derivation failed. " + ex.Message, ex);
753                                                 HandleError (ex);
754                                         }
755                                 }
756                                 else if (xsiType is XmlSchemaDatatype) {
757                                         // do nothing
758                                 }
759                                 else
760                                         HandleError ("Primitive data type cannot be derived type using xsi:type specification.");
761                         }
762                 }
763
764                 // Section 3.3.4 of the spec.
765                 private void AssessStartElementSchemaValidity ()
766                 {
767                         // If the reader is inside xsi:nil (and failed on validation),
768                         // then simply skip its content.
769                         if (xsiNilDepth >= 0 && xsiNilDepth < reader.Depth)
770                                 HandleError ("Element item appeared, while current element context is nil.");
771
772                         context.Load (reader.Depth);
773                         if (childParticleState != null) {
774                                 context.ParticleState = childParticleState;
775                                 childParticleState = null;
776                         }
777
778                         // If validation state exists, then first assess particle validity.
779                         context.SchemaType = null;
780                         if (context.ParticleState != null) {
781                                 ValidateStartElementParticle ();
782                         }
783
784                         string xsiNilValue = reader.GetAttribute ("nil", XmlSchema.InstanceNamespace);
785                         if (xsiNilValue != null)
786                                 xsiNilValue = xsiNilValue.Trim (XmlChar.WhitespaceChars);
787                         bool isXsiNil = xsiNilValue == "true";
788                         if (isXsiNil && this.xsiNilDepth < 0)
789                                 xsiNilDepth = reader.Depth;
790
791                         // [Schema Validity Assessment (Element) 1.2]
792                         // Evaluate "local type definition" from xsi:type.
793                         // (See spec 3.3.4 Schema Validity Assessment (Element) 1.2.1.2.3.
794                         // Note that Schema Validity Assessment(Element) 1.2 takes
795                         // precedence than 1.1 of that.
796
797                         string xsiTypeName = reader.GetAttribute ("type", XmlSchema.InstanceNamespace);
798                         if (xsiTypeName != null) {
799                                 xsiTypeName = xsiTypeName.Trim (XmlChar.WhitespaceChars);
800                                 object xsiType = GetLocalTypeDefinition (xsiTypeName);
801                                 if (xsiType == null)
802                                         HandleError ("The instance type was not found: " + xsiTypeName + " .");
803                                 else {
804                                         XmlSchemaType xsiSchemaType = xsiType as XmlSchemaType;
805                                         if (xsiSchemaType != null && this.context.Element != null) {
806                                                 XmlSchemaType elemBaseType = context.Element.ElementType as XmlSchemaType;
807                                                 if (elemBaseType != null && (xsiSchemaType.DerivedBy & elemBaseType.FinalResolved) != 0)
808                                                         HandleError ("The instance type is prohibited by the type of the context element.");
809                                                 if (elemBaseType != xsiType && (xsiSchemaType.DerivedBy & this.context.Element.BlockResolved) != 0)
810                                                         HandleError ("The instance type is prohibited by the context element.");
811                                         }
812                                         XmlSchemaComplexType xsiComplexType = xsiType as XmlSchemaComplexType;
813                                         if (xsiComplexType != null && xsiComplexType.IsAbstract)
814                                                 HandleError ("The instance type is abstract: " + xsiTypeName + " .");
815                                         else {
816                                                 // If current schema type exists, then this xsi:type must be
817                                                 // valid extension of that type. See 1.2.1.2.4.
818                                                 if (context.Element != null) {
819                                                         AssessLocalTypeDerivationOK (xsiType, context.Element.ElementType, context.Element.BlockResolved);
820                                                 }
821                                                 AssessStartElementLocallyValidType (xsiType);   // 1.2.2:
822                                                 context.LocalTypeDefinition = xsiType;
823                                         }
824                                 }
825                         }
826                         else
827                                 context.LocalTypeDefinition = null;
828
829                         // Create Validation Root, if not exist.
830                         // [Schema Validity Assessment (Element) 1.1]
831                         if (context.Element == null)
832                                 context.Element = FindElement (reader.LocalName, reader.NamespaceURI);
833                         if (context.Element != null) {
834                                 if (xsiTypeName == null) {
835                                         context.SchemaType = context.Element.ElementType;
836                                         AssessElementLocallyValidElement (context.Element, xsiNilValue);        // 1.1.2
837                                 }
838                         } else {
839                                 XmlSchema schema;
840                                 switch (stateManager.ProcessContents) {
841                                 case XmlSchemaContentProcessing.Skip:
842                                         break;
843                                 case XmlSchemaContentProcessing.Lax:
844                                         /*
845                                         schema = schemas [reader.NamespaceURI];
846                                         if (schema != null && !schema.missedSubComponents)
847                                                 HandleError ("Element declaration for " + reader.LocalName + " is missing.");
848                                         */
849                                         break;
850                                 default:
851                                         if (xsiTypeName == null &&
852                                                 (schemas.Contains (reader.NamespaceURI) ||
853                                                 !schemas.MissedSubComponents (reader.NamespaceURI)))
854                                                 HandleError ("Element declaration for " + reader.LocalName + " is missing.");
855                                         break;
856                                 }
857                         }
858
859                         if (stateManager.ProcessContents == XmlSchemaContentProcessing.Skip)
860                                 skipValidationDepth = reader.Depth;
861
862                         // Finally, create child particle state.
863                         XmlSchemaComplexType xsComplexType = SchemaType as XmlSchemaComplexType;
864                         if (xsComplexType != null)
865                                 childParticleState = stateManager.Create (xsComplexType.ValidatableParticle);
866                         else if (stateManager.ProcessContents == XmlSchemaContentProcessing.Lax)
867                                 childParticleState = stateManager.Create (XmlSchemaAny.AnyTypeContent);
868                         else
869                                 childParticleState = stateManager.Create (XmlSchemaParticle.Empty);
870
871                         AssessStartIdentityConstraints ();
872
873                         context.PushScope (reader.Depth);
874                 }
875
876                 // 3.3.4 Element Locally Valid (Element)
877                 private void AssessElementLocallyValidElement (XmlSchemaElement element, string xsiNilValue)
878                 {
879                         XmlQualifiedName qname = new XmlQualifiedName (reader.LocalName, reader.NamespaceURI);
880                         // 1.
881                         if (element == null)
882                                 HandleError ("Element declaration is required for " + qname);
883                         // 2.
884                         if (element.ActualIsAbstract)
885                                 HandleError ("Abstract element declaration was specified for " + qname);
886                         // 3.1.
887                         if (!element.ActualIsNillable && xsiNilValue != null)
888                                 HandleError ("This element declaration is not nillable: " + qname);
889                         // 3.2.
890                         // Note that 3.2.1 xsi:nil constraints are to be validated in
891                         else if (xsiNilValue == "true") {
892                                 // AssessElementSchemaValidity() and ValidateCharacters()
893
894                                 if (element.ValidatedFixedValue != null)
895                                         HandleError ("Schema instance nil was specified, where the element declaration for " + qname + "has fixed value constraints.");
896                         }
897                         // 4.
898                         string xsiType = reader.GetAttribute ("type", XmlSchema.InstanceNamespace);
899                         if (xsiType != null) {
900                                 context.LocalTypeDefinition = GetLocalTypeDefinition (xsiType);
901                                 AssessLocalTypeDerivationOK (context.LocalTypeDefinition, element.ElementType, element.BlockResolved);
902                         }
903                         else
904                                 context.LocalTypeDefinition = null;
905
906                         // 5 Not all things cannot be assessed here.
907                         // It is common to 5.1 and 5.2
908                         if (element.ElementType != null)
909                                 AssessStartElementLocallyValidType (SchemaType);
910
911                         // 6. should be out from here.
912                         // See invokation of AssessStartIdentityConstraints().
913
914                         // 7 is going to be validated in Read() (in case of xmlreader's EOF).
915                 }
916
917                 // 3.3.4 Element Locally Valid (Type)
918                 private void AssessStartElementLocallyValidType (object schemaType)
919                 {
920                         if (schemaType == null) {       // 1.
921                                 HandleError ("Schema type does not exist.");
922                                 return;
923                         }
924                         XmlSchemaComplexType cType = schemaType as XmlSchemaComplexType;
925                         XmlSchemaSimpleType sType = schemaType as XmlSchemaSimpleType;
926                         if (sType != null) {
927                                 // 3.1.1.
928                                 while (reader.MoveToNextAttribute ()) {
929                                         if (reader.NamespaceURI == XmlNamespaceManager.XmlnsXmlns)
930                                                 continue;
931                                         if (reader.NamespaceURI != XmlSchema.InstanceNamespace)
932                                                 HandleError ("Current simple type cannot accept attributes other than schema instance namespace.");
933                                         switch (reader.LocalName) {
934                                         case "type":
935                                         case "nil":
936                                         case "schemaLocation":
937                                         case "noNamespaceSchemaLocation":
938                                                 break;
939                                         default:
940                                                 HandleError ("Unknown schema instance namespace attribute: " + reader.LocalName);
941                                                 break;
942                                         }
943                                 }
944                                 reader.MoveToElement ();
945                                 // 3.1.2 and 3.1.3 cannot be assessed here.
946                         } else if (cType != null) {
947                                 if (cType.IsAbstract) { // 2.
948                                         HandleError ("Target complex type is abstract.");
949                                         return;
950                                 }
951                                 // 3.2
952                                 AssessElementLocallyValidComplexType (cType);
953                         }
954                 }
955
956                 // 3.4.4 Element Locally Valid (Complex Type)
957                 private void AssessElementLocallyValidComplexType (XmlSchemaComplexType cType)
958                 {
959                         // 1.
960                         if (cType.IsAbstract)
961                                 HandleError ("Target complex type is abstract.");
962
963                         // 2 (xsi:nil and content prohibition)
964                         // See AssessStartElementSchemaValidity() and ValidateCharacters()
965
966                         string elementNs = reader.NamespaceURI;
967                         // 3. attribute uses and 
968                         // 5. wild IDs
969                         while (reader.MoveToNextAttribute ()) {
970                                 if (reader.NamespaceURI == "http://www.w3.org/2000/xmlns/")
971                                         continue;
972                                 else if (reader.NamespaceURI == XmlSchema.InstanceNamespace)
973                                         continue;
974                                 XmlQualifiedName qname = new XmlQualifiedName (reader.LocalName, reader.NamespaceURI);
975                                 XmlSchemaObject attMatch = FindAttributeDeclaration (cType, qname, elementNs);
976                                 if (attMatch == null)
977                                         HandleError ("Attribute declaration was not found for " + qname);
978                                 else {
979                                         XmlSchemaAttribute attdecl = attMatch as XmlSchemaAttribute;
980                                         if (attdecl == null) { // i.e. anyAttribute
981                                                 XmlSchemaAnyAttribute anyAttrMatch = attMatch as XmlSchemaAnyAttribute;
982                                         } else {
983                                                 AssessAttributeLocallyValidUse (attdecl);
984                                                 AssessAttributeLocallyValid (attdecl, true);
985                                         }
986                                 }
987                         }
988                         reader.MoveToElement ();
989
990                         // Collect default attributes.
991                         // 4.
992                         foreach (DictionaryEntry entry in cType.AttributeUses) {
993                                 XmlSchemaAttribute attr = (XmlSchemaAttribute) entry.Value;
994                                 if (reader [attr.QualifiedName.Name, attr.QualifiedName.Namespace] == null) {
995                                         if (attr.ValidatedUse == XmlSchemaUse.Required && 
996                                                 attr.ValidatedFixedValue == null)
997                                                 HandleError ("Required attribute " + attr.QualifiedName + " was not found.");
998                                         else if (attr.ValidatedDefaultValue != null)
999                                                 defaultAttributesCache.Add (attr);
1000                                         else if (attr.ValidatedFixedValue != null)
1001                                                 defaultAttributesCache.Add (attr);
1002                                 }
1003                         }
1004                         defaultAttributes = (XmlSchemaAttribute []) 
1005                                 defaultAttributesCache.ToArray (typeof (XmlSchemaAttribute));
1006                         context.DefaultAttributes = defaultAttributes;
1007                         defaultAttributesCache.Clear ();
1008                         // 5. wild IDs was already checked above.
1009                 }
1010
1011                 // Spec 3.10.4 Item Valid (Wildcard)
1012                 private bool AttributeWildcardItemValid (XmlSchemaAnyAttribute anyAttr, XmlQualifiedName qname)
1013                 {
1014                         if (anyAttr.HasValueAny)
1015                                 return true;
1016                         if (anyAttr.HasValueOther && (anyAttr.TargetNamespace == "" || reader.NamespaceURI != anyAttr.TargetNamespace))
1017                                 return true;
1018                         if (anyAttr.HasValueTargetNamespace && reader.NamespaceURI == anyAttr.TargetNamespace)
1019                                 return true;
1020                         if (anyAttr.HasValueLocal && reader.NamespaceURI == "")
1021                                 return true;
1022                         for (int i = 0; i < anyAttr.ResolvedNamespaces.Count; i++)
1023                                 if (anyAttr.ResolvedNamespaces [i] == reader.NamespaceURI)
1024                                         return true;
1025                         return false;
1026                 }
1027
1028                 private XmlSchemaObject FindAttributeDeclaration (
1029                         XmlSchemaComplexType cType,
1030                         XmlQualifiedName qname,
1031                         string elementNs)
1032                 {
1033                         XmlSchemaObject result = cType.AttributeUses [qname];
1034                         if (result != null)
1035                                 return result;
1036                         if (cType.AttributeWildcard == null)
1037                                 return null;
1038
1039                         if (!AttributeWildcardItemValid (cType.AttributeWildcard, qname))
1040                                 return null;
1041
1042                         if (cType.AttributeWildcard.ResolvedProcessContents == XmlSchemaContentProcessing.Skip)
1043                                 return cType.AttributeWildcard;
1044                         XmlSchemaAttribute attr = schemas.GlobalAttributes [qname] as XmlSchemaAttribute;
1045                         if (attr != null)
1046                                 return attr;
1047                         if (cType.AttributeWildcard.ResolvedProcessContents == XmlSchemaContentProcessing.Lax)
1048                                 return cType.AttributeWildcard;
1049                         else
1050                                 return null;
1051                 }
1052
1053                 // 3.2.4 Attribute Locally Valid and 3.4.4 - 5.wildIDs
1054                 private void AssessAttributeLocallyValid (XmlSchemaAttribute attr, bool checkWildIDs)
1055                 {
1056                         // 1.
1057                         switch (reader.NamespaceURI) {
1058                         case XmlNamespaceManager.XmlnsXml:
1059                         case XmlNamespaceManager.XmlnsXmlns:
1060                         case XmlSchema.InstanceNamespace:
1061                                 break;
1062                         }
1063                         // 2. - 4.
1064                         if (attr.AttributeType == null)
1065                                 HandleError ("Attribute type is missing for " + attr.QualifiedName);
1066                         XmlSchemaDatatype dt = attr.AttributeType as XmlSchemaDatatype;
1067                         if (dt == null)
1068                                 dt = ((XmlSchemaSimpleType) attr.AttributeType).Datatype;
1069                         // It is a bit heavy process, so let's omit as long as possible ;-)
1070                         if (dt != XmlSchemaSimpleType.AnySimpleType || attr.ValidatedFixedValue != null) {
1071                                 string normalized = dt.Normalize (reader.Value);
1072                                 object parsedValue = null;
1073                                 try {
1074                                         parsedValue = dt.ParseValue (normalized, reader.NameTable, this.ParserContext.NamespaceManager);
1075                                 } catch (Exception ex) { // FIXME: (wishlist) It is bad manner ;-(
1076                                         HandleError ("Attribute value is invalid against its data type " + dt.TokenizedType, ex);
1077                                 }
1078                                 if (attr.ValidatedFixedValue != null && attr.ValidatedFixedValue != normalized)
1079                                         HandleError ("The value of the attribute " + attr.QualifiedName + " does not match with its fixed value.");
1080                                 if (checkWildIDs)
1081                                         AssessEachAttributeIdentityConstraint (dt, normalized, parsedValue);
1082                         }
1083                 }
1084
1085                 private void AssessEachAttributeIdentityConstraint (XmlSchemaDatatype dt,
1086                         string normalized, object parsedValue)
1087                 {
1088                         // Get normalized value and (if required) parsedValue if missing.
1089                         switch (dt.TokenizedType) {
1090                         case XmlTokenizedType.IDREFS:
1091                                 if (normalized == null)
1092                                         normalized = dt.Normalize (reader.Value);
1093                                 if (parsedValue == null)
1094                                         parsedValue = dt.ParseValue (normalized, reader.NameTable, ParserContext.NamespaceManager);
1095                                 break;
1096                         case XmlTokenizedType.ID:
1097                         case XmlTokenizedType.IDREF:
1098                                 if (normalized == null)
1099                                         normalized = dt.Normalize (reader.Value);
1100                                 break;
1101                         }
1102
1103                         // Validate identity constraints.
1104                         switch (dt.TokenizedType) {
1105                         case XmlTokenizedType.ID:
1106                                 if (thisElementId != null)
1107                                         HandleError ("ID type attribute was already assigned in the containing element.");
1108                                 thisElementId = normalized;
1109                                 if (idList.Contains (normalized))
1110                                         HandleError ("Duplicate ID value was found.");
1111                                 else
1112                                         idList.Add (normalized, normalized);
1113                                 if (missingIDReferences.Contains (normalized))
1114                                         missingIDReferences.Remove (normalized);
1115                                 break;
1116                         case XmlTokenizedType.IDREF:
1117                                 if (!idList.Contains (normalized))
1118                                         missingIDReferences.Add (normalized);
1119                                 break;
1120                         case XmlTokenizedType.IDREFS:
1121                                 string [] idrefs = (string []) parsedValue;
1122                                 for (int i = 0; i < idrefs.Length; i++) {
1123                                         string id = idrefs [i];
1124                                         if (!idList.Contains (id))
1125                                                 missingIDReferences.Add (id);
1126                                 }
1127                                 break;
1128                         }
1129                 }
1130
1131                 private void AssessAttributeLocallyValidUse (XmlSchemaAttribute attr)
1132                 {
1133                         // This is extra check than spec 3.5.4
1134                         if (attr.ValidatedUse == XmlSchemaUse.Prohibited)
1135                                 HandleError ("Attribute " + attr.QualifiedName + " is prohibited in this context.");
1136                 }
1137
1138                 private void AssessEndElementSchemaValidity ()
1139                 {
1140                         if (childParticleState == null)
1141                                 childParticleState = context.ParticleState;
1142                         ValidateEndElementParticle ();  // validate against childrens' state.
1143
1144                         if (shouldValidateCharacters) {
1145                                 ValidateEndCharacters ();
1146                                 shouldValidateCharacters = false;
1147                         }
1148
1149                         // 3.3.4 Assess ElementLocallyValidElement 5: value constraints.
1150                         // 3.3.4 Assess ElementLocallyValidType 3.1.3. = StringValid(3.14.4)
1151                         // => ValidateEndCharacters().
1152
1153                         // Reset Identity constraints.
1154                         for (int i = 0; i < keyTables.Count; i++) {
1155                                 XsdKeyTable keyTable = this.keyTables [i] as XsdKeyTable;
1156                                 if (keyTable.StartDepth == reader.Depth) {
1157                                         EndIdentityValidation (keyTable);
1158                                 } else {
1159                                         for (int k = 0; k < keyTable.Entries.Count; k++) {
1160                                                 XsdKeyEntry entry = keyTable.Entries [k] as XsdKeyEntry;
1161                                                 // Remove finished (maybe key not found) entries.
1162                                                 if (entry.StartDepth == reader.Depth) {
1163                                                         if (entry.KeyFound)
1164                                                                 keyTable.FinishedEntries.Add (entry);
1165                                                         else if (entry.KeySequence.SourceSchemaIdentity is XmlSchemaKey)
1166                                                                 HandleError ("Key sequence is missing.");
1167                                                         keyTable.Entries.RemoveAt (k);
1168                                                         k--;
1169                                                 }
1170                                                 // Pop validated key depth to find two or more fields.
1171                                                 else {
1172                                                         for (int j = 0; j < entry.KeyFields.Count; j++) {
1173                                                                 XsdKeyEntryField kf = entry.KeyFields [j];
1174                                                                 if (!kf.FieldFound && kf.FieldFoundDepth == reader.Depth) {
1175                                                                         kf.FieldFoundDepth = 0;
1176                                                                         kf.FieldFoundPath = null;
1177                                                                 }
1178                                                         }
1179                                                 }
1180                                         }
1181                                 }
1182                         }
1183                         for (int i = 0; i < keyTables.Count; i++) {
1184                                 XsdKeyTable keyseq = this.keyTables [i] as XsdKeyTable;
1185                                 if (keyseq.StartDepth == reader.Depth) {
1186                                         keyTables.RemoveAt (i);
1187                                         i--;
1188                                 }
1189                         }
1190
1191                         // Reset xsi:nil, if required.
1192                         if (xsiNilDepth == reader.Depth)
1193                                 xsiNilDepth = -1;
1194                 }
1195
1196                 // 3.11.4 Identity Constraint Satisfied
1197                 private void AssessStartIdentityConstraints ()
1198                 {
1199                         tmpKeyrefPool.Clear ();
1200                         if (context.Element != null && context.Element.Constraints.Count > 0) {
1201                                 // (a) Create new key sequences, if required.
1202                                 for (int i = 0; i < context.Element.Constraints.Count; i++) {
1203                                         XmlSchemaIdentityConstraint ident = (XmlSchemaIdentityConstraint) context.Element.Constraints [i];
1204                                         XsdKeyTable seq = CreateNewKeyTable (ident);
1205                                         if (ident is XmlSchemaKeyref)
1206                                                 tmpKeyrefPool.Add (seq);
1207                                 }
1208                         }
1209
1210                         // (b) Evaluate current key sequences.
1211                         for (int i = 0; i < keyTables.Count; i++) {
1212                                 XsdKeyTable seq  = (XsdKeyTable) keyTables [i];
1213                                 if (seq.SelectorMatches (this.elementQNameStack, reader) != null) {
1214                                         // creates and registers new entry.
1215                                         XsdKeyEntry entry = new XsdKeyEntry (seq, reader);
1216                                         seq.Entries.Add (entry);
1217                                 }
1218                         }
1219
1220                         // (c) Evaluate field paths.
1221                         for (int i = 0; i < keyTables.Count; i++) {
1222                                 XsdKeyTable seq  = (XsdKeyTable) keyTables [i];
1223                                 // If possible, create new field entry candidates.
1224                                 for (int j = 0; j < seq.Entries.Count; j++) {
1225                                         XsdKeyEntry entry = seq.Entries [j] as XsdKeyEntry;
1226                                         try {
1227                                                 entry.FieldMatches (this.elementQNameStack, this);
1228                                         } catch (Exception ex) { // FIXME: (wishlist) It is bad manner ;-(
1229                                                 HandleError ("Identity field value is invalid against its data type.", ex);
1230                                         }
1231                                 }
1232                         }
1233                 }
1234
1235                 private XsdKeyTable CreateNewKeyTable (XmlSchemaIdentityConstraint ident)
1236                 {
1237                         XsdKeyTable seq = new XsdKeyTable (ident, this);
1238                         seq.StartDepth = reader.Depth;
1239                         XmlSchemaKeyref keyref = ident as XmlSchemaKeyref;
1240                         this.keyTables.Add (seq);
1241                         return seq;
1242                 }
1243
1244                 private void EndIdentityValidation (XsdKeyTable seq)
1245                 {
1246                         ArrayList errors = new ArrayList ();
1247                         for (int i = 0; i < seq.Entries.Count; i++) {
1248                                 XsdKeyEntry entry = (XsdKeyEntry) seq.Entries [i];
1249                                 if (entry.KeyFound)
1250                                         continue;
1251                                 if (seq.SourceSchemaIdentity is XmlSchemaKey)
1252                                         errors.Add ("line " + entry.SelectorLineNumber + "position " + entry.SelectorLinePosition);
1253                         }
1254                         if (errors.Count > 0)
1255                                 HandleError ("Invalid identity constraints were found. Key was not found. "
1256                                         + String.Join (", ", errors.ToArray (typeof (string)) as string []));
1257
1258                         errors.Clear ();
1259                         // Find reference target
1260                         XmlSchemaKeyref xsdKeyref = seq.SourceSchemaIdentity as XmlSchemaKeyref;
1261                         if (xsdKeyref != null) {
1262                                 for (int i = this.keyTables.Count - 1; i >= 0; i--) {
1263                                         XsdKeyTable target = this.keyTables [i] as XsdKeyTable;
1264                                         if (target.SourceSchemaIdentity == xsdKeyref.Target) {
1265                                                 seq.ReferencedKey = target;
1266                                                 for (int j = 0; j < seq.FinishedEntries.Count; j++) {
1267                                                         XsdKeyEntry entry = (XsdKeyEntry) seq.FinishedEntries [j];
1268                                                         for (int k = 0; k < target.FinishedEntries.Count; k++) {
1269                                                                 XsdKeyEntry targetEntry = (XsdKeyEntry) target.FinishedEntries [k];
1270                                                                 if (entry.CompareIdentity (targetEntry)) {
1271                                                                         entry.KeyRefFound = true;
1272                                                                         break;
1273                                                                 }
1274                                                         }
1275                                                 }
1276                                         }
1277                                 }
1278                                 if (seq.ReferencedKey == null)
1279                                         HandleError ("Target key was not found.");
1280                                 for (int i = 0; i < seq.FinishedEntries.Count; i++) {
1281                                         XsdKeyEntry entry = (XsdKeyEntry) seq.FinishedEntries [i];
1282                                         if (!entry.KeyRefFound)
1283                                                 errors.Add (" line " + entry.SelectorLineNumber + ", position " + entry.SelectorLinePosition);
1284                                 }
1285                                 if (errors.Count > 0)
1286                                         HandleError ("Invalid identity constraints were found. Referenced key was not found: "
1287                                                 + String.Join (" / ", errors.ToArray (typeof (string)) as string []));
1288                         }
1289                 }
1290
1291                 // Overrided Methods
1292
1293                 public override void Close ()
1294                 {
1295                         reader.Close ();
1296                 }
1297
1298                 public override string GetAttribute (int i)
1299                 {
1300                         switch (reader.NodeType) {
1301                         case XmlNodeType.XmlDeclaration:
1302                         case XmlNodeType.DocumentType:
1303                                 return reader.GetAttribute (i);
1304                         }
1305
1306                         if (reader.AttributeCount > i)
1307                                 reader.GetAttribute (i);
1308                         int defIdx = i - nonDefaultAttributeCount;
1309                         if (i < AttributeCount)
1310                                 return defaultAttributes [defIdx].DefaultValue;
1311
1312                         throw new ArgumentOutOfRangeException ("i", i, "Specified attribute index is out of range.");
1313                 }
1314
1315                 public override string GetAttribute (string name)
1316                 {
1317                         switch (reader.NodeType) {
1318                         case XmlNodeType.XmlDeclaration:
1319                         case XmlNodeType.DocumentType:
1320                                 return reader.GetAttribute (name);
1321                         }
1322
1323                         string value = reader.GetAttribute (name);
1324                         if (value != null)
1325                                 return value;
1326
1327                         XmlQualifiedName qname = SplitQName (name);
1328                         return GetDefaultAttribute (qname.Name, qname.Namespace);
1329                 }
1330
1331                 private XmlQualifiedName SplitQName (string name)
1332                 {
1333                         if (!XmlChar.IsName (name))
1334                                 throw new ArgumentException ("Invalid name was specified.", "name");
1335
1336                         Exception ex = null;
1337                         XmlQualifiedName qname = XmlSchemaUtil.ToQName (reader, name, out ex);
1338                         if (ex != null)
1339                                 return XmlQualifiedName.Empty;
1340                         else
1341                                 return qname;
1342                 }
1343
1344                 public override string GetAttribute (string localName, string ns)
1345                 {
1346                         switch (reader.NodeType) {
1347                         case XmlNodeType.XmlDeclaration:
1348                         case XmlNodeType.DocumentType:
1349                                 return reader.GetAttribute (localName, ns);
1350                         }
1351
1352                         string value = reader.GetAttribute (localName, ns);
1353                         if (value != null)
1354                                 return value;
1355
1356                         return GetDefaultAttribute (localName, ns);
1357                 }
1358
1359                 private string GetDefaultAttribute (string localName, string ns)
1360                 {
1361                         int idx = this.FindDefaultAttribute (localName, ns);
1362                         if (idx < 0)
1363                                 return null;
1364                         string value = defaultAttributes [idx].ValidatedDefaultValue;
1365                         if (value == null)
1366                                 value = defaultAttributes [idx].ValidatedFixedValue;
1367                         return value;
1368                 }
1369
1370                 private int FindDefaultAttribute (string localName, string ns)
1371                 {
1372                         for (int i = 0; i < this.defaultAttributes.Length; i++) {
1373                                 XmlSchemaAttribute attr = defaultAttributes [i];
1374                                 if (attr.QualifiedName.Name == localName &&
1375                                         (ns == null || attr.QualifiedName.Namespace == ns))
1376                                         return i;
1377                         }
1378                         return -1;
1379                 }
1380
1381                 bool IXmlLineInfo.HasLineInfo ()
1382                 {
1383                         return readerLineInfo != null && readerLineInfo.HasLineInfo ();
1384                 }
1385
1386                 public override string LookupNamespace (string prefix)
1387                 {
1388                         return reader.LookupNamespace (prefix);
1389                 }
1390
1391                 string IXmlNamespaceResolver.LookupNamespace (string prefix, bool atomizedNames)
1392                 {
1393                         IXmlNamespaceResolver res = reader as IXmlNamespaceResolver;
1394                         if (res != null)
1395                                 return res.LookupNamespace (prefix, atomizedNames);
1396                         else
1397                                 return reader.LookupNamespace (prefix);
1398                 }
1399
1400                 public override void MoveToAttribute (int i)
1401                 {
1402                         switch (reader.NodeType) {
1403                         case XmlNodeType.XmlDeclaration:
1404                         case XmlNodeType.DocumentType:
1405                                 reader.MoveToAttribute (i);
1406                                 return;
1407                         }
1408
1409                         currentQName = null;
1410                         if (i < this.nonDefaultAttributeCount) {
1411                                 reader.MoveToAttribute (i);
1412                                 this.currentDefaultAttribute = -1;
1413                                 this.defaultAttributeConsumed = false;
1414                         }
1415
1416                         if (i < AttributeCount) {
1417                                 this.currentDefaultAttribute = i - nonDefaultAttributeCount;
1418                                 this.defaultAttributeConsumed = false;
1419                         }
1420                         else
1421                                 throw new ArgumentOutOfRangeException ("i", i, "Attribute index is out of range.");
1422                 }
1423
1424                 public override bool MoveToAttribute (string name)
1425                 {
1426                         switch (reader.NodeType) {
1427                         case XmlNodeType.XmlDeclaration:
1428                         case XmlNodeType.DocumentType:
1429                                 return reader.MoveToAttribute (name);
1430                         }
1431
1432                         currentQName = null;
1433                         bool b = reader.MoveToAttribute (name);
1434                         if (b) {
1435                                 this.currentDefaultAttribute = -1;
1436                                 this.defaultAttributeConsumed = false;
1437                                 return true;
1438                         }
1439
1440                         return MoveToDefaultAttribute (name, null);
1441                 }
1442
1443                 public override bool MoveToAttribute (string localName, string ns)
1444                 {
1445                         switch (reader.NodeType) {
1446                         case XmlNodeType.XmlDeclaration:
1447                         case XmlNodeType.DocumentType:
1448                                 return reader.MoveToAttribute (localName, ns);
1449                         }
1450
1451                         currentQName = null;
1452                         bool b = reader.MoveToAttribute (localName, ns);
1453                         if (b) {
1454                                 this.currentDefaultAttribute = -1;
1455                                 this.defaultAttributeConsumed = false;
1456                                 return true;
1457                         }
1458
1459                         return MoveToDefaultAttribute (localName, ns);
1460                 }
1461
1462                 private bool MoveToDefaultAttribute (string localName, string ns)
1463                 {
1464                         int idx = this.FindDefaultAttribute (localName, ns);
1465                         if (idx < 0)
1466                                 return false;
1467                         currentDefaultAttribute = idx;
1468                         defaultAttributeConsumed = false;
1469                         return true;
1470                 }
1471
1472                 public override bool MoveToElement ()
1473                 {
1474                         currentDefaultAttribute = -1;
1475                         defaultAttributeConsumed = false;
1476                         currentQName = null;
1477                         return reader.MoveToElement ();
1478                 }
1479
1480                 public override bool MoveToFirstAttribute ()
1481                 {
1482                         switch (reader.NodeType) {
1483                         case XmlNodeType.XmlDeclaration:
1484                         case XmlNodeType.DocumentType:
1485                                 return reader.MoveToFirstAttribute ();
1486                         }
1487
1488                         currentQName = null;
1489                         if (this.nonDefaultAttributeCount > 0) {
1490                                 bool b = reader.MoveToFirstAttribute ();
1491                                 if (b) {
1492                                         currentDefaultAttribute = -1;
1493                                         defaultAttributeConsumed = false;
1494                                 }
1495                                 return b;
1496                         }
1497
1498                         if (this.defaultAttributes.Length > 0) {
1499                                 currentDefaultAttribute = 0;
1500                                 defaultAttributeConsumed = false;
1501                                 return true;
1502                         }
1503                         else
1504                                 return false;
1505                 }
1506
1507                 public override bool MoveToNextAttribute ()
1508                 {
1509                         switch (reader.NodeType) {
1510                         case XmlNodeType.XmlDeclaration:
1511                         case XmlNodeType.DocumentType:
1512                                 return reader.MoveToNextAttribute ();
1513                         }
1514
1515                         currentQName = null;
1516                         if (currentDefaultAttribute >= 0) {
1517                                 if (defaultAttributes.Length == currentDefaultAttribute + 1)
1518                                         return false;
1519                                 currentDefaultAttribute++;
1520                                 defaultAttributeConsumed = false;
1521                                 return true;
1522                         }
1523
1524                         bool b = reader.MoveToNextAttribute ();
1525                         if (b) {
1526                                 currentDefaultAttribute = -1;
1527                                 defaultAttributeConsumed = false;
1528                                 return true;
1529                         }
1530
1531                         if (defaultAttributes.Length > 0) {
1532                                 currentDefaultAttribute = 0;
1533                                 defaultAttributeConsumed = false;
1534                                 return true;
1535                         }
1536                         else
1537                                 return false;
1538                 }
1539
1540                 private void ExamineAdditionalSchema ()
1541                 {
1542                         XmlSchema schema = null;
1543                         string schemaLocation = reader.GetAttribute ("schemaLocation", XmlSchema.InstanceNamespace);
1544                         bool schemaAdded = false;
1545                         if (schemaLocation != null) {
1546                                 string [] tmp = null;
1547                                 try {
1548                                         schemaLocation = XmlSchemaDatatype.FromName ("token", XmlSchema.Namespace).Normalize (schemaLocation);
1549                                         tmp = schemaLocation.Split (XmlChar.WhitespaceChars);
1550                                 } catch (Exception ex) {
1551                                         HandleError ("Invalid schemaLocation attribute format.", ex, true);
1552                                         tmp = new string [0];
1553                                 }
1554                                 if (tmp.Length % 2 != 0)
1555                                         HandleError ("Invalid schemaLocation attribute format.");
1556                                 for (int i = 0; i < tmp.Length; i += 2) {
1557                                         Uri absUri = null;
1558                                         XmlTextReader xtr = null;
1559                                         try {
1560                                                 absUri = new Uri ((this.BaseURI != "" ? new Uri (BaseURI) : null), tmp [i + 1]);
1561                                                 xtr = new XmlTextReader (absUri.ToString ());
1562                                                 schema = XmlSchema.Read (xtr, null);
1563                                         } catch (Exception) { // FIXME: (wishlist) It is bad manner ;-(
1564                                                 HandleError ("Could not resolve schema location URI: " + absUri, null, true);
1565                                                 continue;
1566                                         } finally {
1567                                                 if (xtr != null)
1568                                                         xtr.Close ();
1569                                         }
1570                                         if (schema.TargetNamespace == null)
1571                                                 schema.TargetNamespace = tmp [i];
1572                                         else if (schema.TargetNamespace != tmp [i])
1573                                                 HandleError ("Specified schema has different target namespace.");
1574                                 }
1575                         }
1576                         if (schema != null) {
1577                                 if (!schemas.Contains (schema.TargetNamespace)) {
1578                                         schemaAdded = true;
1579                                         schemas.Add (schema);
1580                                 }
1581                         }
1582                         schema = null;
1583                         string noNsSchemaLocation = reader.GetAttribute ("noNamespaceSchemaLocation", XmlSchema.InstanceNamespace);
1584                         if (noNsSchemaLocation != null) {
1585                                 Uri absUri = null;
1586                                 XmlTextReader xtr = null;
1587                                 try {
1588                                         absUri = new Uri ((this.BaseURI != "" ? new Uri (BaseURI) : null), noNsSchemaLocation);
1589                                         xtr = new XmlTextReader (absUri.ToString ());
1590                                         schema = XmlSchema.Read (xtr, null);
1591                                 } catch (Exception) { // FIXME: (wishlist) It is bad manner ;-(
1592                                         HandleError ("Could not resolve schema location URI: " + absUri, null, true);
1593                                 } finally {
1594                                         if (xtr != null)
1595                                                 xtr.Close ();
1596                                 }
1597                                 if (schema != null && schema.TargetNamespace != null)
1598                                         HandleError ("Specified schema has different target namespace.");
1599                         }
1600                         if (schema != null) {
1601                                 if (!schemas.Contains (schema.TargetNamespace)) {
1602                                         schemaAdded = true;
1603                                         schemas.Add (schema);
1604                                 }
1605                         }
1606                         // FIXME: should call Reprocess()?
1607                         if (schemaAdded)
1608                                 schemas.Compile ();
1609                 }
1610
1611                 public override bool Read ()
1612                 {
1613                         nonDefaultAttributeCount = 0;
1614                         currentDefaultAttribute = -1;
1615                         defaultAttributeConsumed = false;
1616                         currentQName = null;
1617                         thisElementId = null;
1618                         defaultAttributes = new XmlSchemaAttribute [0];
1619                         if (popContext) {
1620                                 elementQNameStack.RemoveAt (elementQNameStack.Count - 1);
1621                                 popContext = false;
1622                         }
1623
1624                         bool result = reader.Read ();
1625                         // 3.3.4 ElementLocallyValidElement 7 = Root Valid.
1626                         if (!result && missingIDReferences.Count > 0)
1627                                 HandleError ("There are missing ID references: " +
1628                                         String.Join (" ",
1629                                         this.missingIDReferences.ToArray (typeof (string)) as string []));
1630
1631                         switch (reader.NodeType) {
1632                         case XmlNodeType.XmlDeclaration:
1633                                 this.nonDefaultAttributeCount = reader.AttributeCount;
1634                                 break;
1635                         case XmlNodeType.Element:
1636                                 nonDefaultAttributeCount = reader.AttributeCount;
1637
1638                                 // FIXME: schemaLocation could be specified 
1639                                 // at any Depth.
1640                                 if (reader.Depth == 0)
1641                                         ExamineAdditionalSchema ();
1642
1643                                 this.elementQNameStack.Add (new XmlQualifiedName (reader.LocalName, reader.NamespaceURI));
1644
1645                                 // If there is no schema information, then no validation is performed.
1646                                 if (schemas.Count == 0)
1647                                         break;
1648
1649                                 if (skipValidationDepth < 0 || reader.Depth <= skipValidationDepth) {
1650                                         if (shouldValidateCharacters) {
1651                                                 ValidateEndCharacters ();
1652                                                 shouldValidateCharacters = false;
1653                                         }
1654                                         AssessStartElementSchemaValidity ();
1655                                         storedCharacters.Length = 0;
1656                                 } else {
1657                                         context.Clear ();
1658                                 }
1659
1660                                 if (reader.IsEmptyElement)
1661                                         goto case XmlNodeType.EndElement;
1662                                 else
1663                                         shouldValidateCharacters = true;
1664                                 break;
1665                         case XmlNodeType.EndElement:
1666                                 if (reader.Depth == skipValidationDepth) {
1667                                         skipValidationDepth = -1;
1668                                         context.Clear ();
1669                                 }
1670                                 else
1671                                         AssessEndElementSchemaValidity ();
1672
1673                                 storedCharacters.Length = 0;
1674                                 childParticleState = null;
1675                                 popContext = true;
1676                                 break;
1677
1678                         case XmlNodeType.CDATA:
1679                         case XmlNodeType.SignificantWhitespace:
1680                         case XmlNodeType.Text:
1681                                 XmlSchemaComplexType ct = context.ActualType as XmlSchemaComplexType;
1682                                 if (ct != null && storedCharacters.Length > 0) {
1683                                         switch (ct.ContentType) {
1684                                         case XmlSchemaContentType.ElementOnly:
1685                                         case XmlSchemaContentType.Empty:
1686                                                 HandleError ("Not allowed character content was found.");
1687                                                 break;
1688                                         }
1689                                 }
1690
1691                                 ValidateCharacters ();
1692                                 break;
1693                         }
1694
1695                         return result;
1696                 }
1697
1698                 public override bool ReadAttributeValue ()
1699                 {
1700                         if (currentDefaultAttribute < 0)
1701                                 return reader.ReadAttributeValue ();
1702
1703                         if (this.defaultAttributeConsumed)
1704                                 return false;
1705
1706                         defaultAttributeConsumed = true;
1707                         return true;
1708                 }
1709
1710 #if NET_1_0
1711                 public override string ReadInnerXml ()
1712                 {
1713                         // MS.NET 1.0 has a serious bug here. It skips validation.
1714                         return reader.ReadInnerXml ();
1715                 }
1716
1717                 public override string ReadOuterXml ()
1718                 {
1719                         // MS.NET 1.0 has a serious bug here. It skips validation.
1720                         return reader.ReadOuterXml ();
1721                 }
1722 #endif
1723
1724                 // XmlReader.ReadString() should call derived this.Read().
1725                 public override string ReadString ()
1726                 {
1727 #if NET_1_0
1728                         return reader.ReadString ();
1729 #else
1730                         return base.ReadString ();
1731 #endif
1732                 }
1733
1734                 // This class itself does not have this feature.
1735                 public override void ResolveEntity ()
1736                 {
1737                         reader.ResolveEntity ();
1738                 }
1739
1740                 internal class XsdValidationContext
1741                 {
1742                         Hashtable contextStack;
1743
1744                         public XsdValidationContext ()
1745                         {
1746                                 contextStack = new Hashtable ();
1747                         }
1748
1749                         // Some of them might be missing (See the spec section 5.3, and also 3.3.4).
1750                         public XmlSchemaElement Element;
1751                         public XsdValidationState ParticleState;
1752                         public XmlSchemaAttribute [] DefaultAttributes;
1753
1754                         // Some of them might be missing (See the spec section 5.3).
1755                         public object SchemaType;
1756
1757                         public object LocalTypeDefinition;
1758
1759                         public object ActualType {
1760                                 get {
1761                                         if (LocalTypeDefinition != null)
1762                                                 return LocalTypeDefinition;
1763                                         else
1764                                                 return SchemaType;
1765                                 }
1766                         }
1767
1768                         public void Clear ()
1769                         {
1770                                 Element = null;
1771                                 SchemaType = null;
1772                                 ParticleState = null;
1773                                 LocalTypeDefinition = null;
1774                         }
1775
1776                         public void PushScope (int depth)
1777                         {
1778                                 contextStack [depth] = this.MemberwiseClone ();
1779                         }
1780
1781                         public void PopScope (int depth)
1782                         {
1783                                 Load (depth);
1784                                 contextStack.Remove (depth + 1);
1785                         }
1786
1787                         public void Load (int depth)
1788                         {
1789                                 Clear ();
1790                                 XsdValidationContext restored = (XsdValidationContext) contextStack [depth];
1791                                 if (restored != null) {
1792                                         this.Element = restored.Element;
1793                                         this.ParticleState = restored.ParticleState;
1794                                         this.SchemaType = restored.SchemaType;
1795                                         this.LocalTypeDefinition = restored.LocalTypeDefinition;
1796                                 }
1797                         }
1798                 }
1799         }
1800
1801 }