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