You've already forked linux-packaging-mono
							
							
		
			
				
	
	
		
			2008 lines
		
	
	
		
			80 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			2008 lines
		
	
	
		
			80 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| //------------------------------------------------------------------------------
 | |
| // <copyright file="ContentValidator.cs" company="Microsoft">
 | |
| //     Copyright (c) Microsoft Corporation.  All rights reserved.
 | |
| // </copyright>
 | |
| // <owner current="true" primary="true">Microsoft</owner>
 | |
| //------------------------------------------------------------------------------
 | |
| using System;
 | |
| using System.Collections;
 | |
| using System.Collections.Generic;
 | |
| using System.Globalization;
 | |
| using System.Text;
 | |
| using System.Diagnostics;
 | |
| 
 | |
| namespace System.Xml.Schema {
 | |
| 
 | |
|     #region ExceptionSymbolsPositions
 | |
|     
 | |
|     /// <summary>
 | |
|     /// UPA violations will throw this exception
 | |
|     /// </summary>
 | |
|     class UpaException : Exception {
 | |
|         object particle1;
 | |
|         object particle2;
 | |
|         public UpaException(object particle1, object particle2) {
 | |
|             this.particle1 = particle1;
 | |
|             this.particle2 = particle2;
 | |
|         }
 | |
|         public object Particle1 { get { return particle1; } }
 | |
|         public object Particle2 { get { return particle2; } }
 | |
|     }
 | |
| 
 | |
|     /// <summary>
 | |
|     /// SymbolsDictionary is a map between names that ContextValidator recognizes and symbols - int symbol[XmlQualifiedName name].
 | |
|     /// There are two types of name - full names and wildcards (namespace is specified, local name is anythig).
 | |
|     /// Wildcard excludes all full names that would match by the namespace part.
 | |
|     /// SymbolsDictionry alwas recognizes all the symbols - the last one is a true wildcard - 
 | |
|     ///      both name and namespace can be anything that none of the other symbols matched.
 | |
|     /// </summary>
 | |
|     class SymbolsDictionary {
 | |
|         int last = 0;
 | |
|         Hashtable names;
 | |
|         Hashtable wildcards = null;
 | |
|         ArrayList particles;
 | |
|         object particleLast = null; 
 | |
|         bool isUpaEnforced = true;
 | |
| 
 | |
|         public SymbolsDictionary() {
 | |
|             names = new Hashtable();
 | |
|             particles = new ArrayList();
 | |
|         }
 | |
| 
 | |
|         public int Count {
 | |
|             // last one is a "*:*" any wildcard
 | |
|             get { return last + 1; }
 | |
|         }
 | |
|         
 | |
|         public int CountOfNames {
 | |
|             get { return names.Count; }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// True is particle can be deterministically attributed from the symbol and conversion to DFA is possible.
 | |
|         /// </summary>
 | |
|         public bool IsUpaEnforced {
 | |
|             get { return isUpaEnforced; }
 | |
|             set { isUpaEnforced = value; }
 | |
|         }
 | |
|         
 | |
|         /// <summary>
 | |
|         /// Add name  and return it's number
 | |
|         /// </summary>
 | |
|         public int AddName(XmlQualifiedName name, object particle) {
 | |
|             object lookup = names[name];
 | |
|             if (lookup != null) {
 | |
|                 int symbol = (int)lookup;
 | |
|                 if (particles[symbol] != particle) {
 | |
|                     isUpaEnforced = false;
 | |
|                 }
 | |
|                 return symbol;
 | |
|             }
 | |
|             else {
 | |
|                 names.Add(name, last);
 | |
|                 particles.Add(particle);
 | |
|                 Debug.Assert(particles.Count == last + 1);
 | |
|                 return last ++;
 | |
|             }
 | |
|         }
 | |
|         
 | |
|         public void AddNamespaceList(NamespaceList list, object particle, bool allowLocal) {
 | |
|             switch (list.Type) {
 | |
|             case NamespaceList.ListType.Any:
 | |
|                 particleLast = particle;   
 | |
|                 break;
 | |
|             case NamespaceList.ListType.Other:
 | |
|                 // Create a symbol for the excluded namespace, but don't set a particle for it.
 | |
|                 AddWildcard(list.Excluded, null);
 | |
|                 if (!allowLocal) {
 | |
|                     AddWildcard(string.Empty, null); //##local is not allowed
 | |
|                 }
 | |
|                 break; 
 | |
|             case NamespaceList.ListType.Set:
 | |
|                 foreach(string wildcard in list.Enumerate) {
 | |
|                     AddWildcard(wildcard, particle);
 | |
|                 }
 | |
|                 break;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private void AddWildcard(string wildcard, object particle) {
 | |
|             if (wildcards == null) {
 | |
|                 wildcards = new Hashtable();
 | |
|             }
 | |
|             object lookup = wildcards[wildcard];
 | |
|             if (lookup == null) {
 | |
|                 wildcards.Add(wildcard, last);
 | |
|                 particles.Add(particle);
 | |
|                 Debug.Assert(particles.Count == last + 1);
 | |
|                 last ++;
 | |
|             }
 | |
|             else if (particle != null) {
 | |
|                 particles[(int)lookup] = particle;    
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public ICollection GetNamespaceListSymbols(NamespaceList list) {
 | |
|             ArrayList match = new ArrayList();
 | |
|             foreach(XmlQualifiedName name in names.Keys) {
 | |
|                 if (name != XmlQualifiedName.Empty && list.Allows(name)) {
 | |
|                     match.Add(names[name]);
 | |
|                 }
 | |
|             }
 | |
|             if (wildcards != null) {
 | |
|                 foreach(string wildcard in wildcards.Keys) {
 | |
|                     if (list.Allows(wildcard)) {
 | |
|                         match.Add(wildcards[wildcard]);
 | |
|                     }
 | |
|                 }              
 | |
|             }
 | |
|             if (list.Type == NamespaceList.ListType.Any || list.Type == NamespaceList.ListType.Other) {
 | |
|                 match.Add(last); // add wildcard
 | |
|             }
 | |
|             return match;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Find the symbol for the given name. If neither names nor wilcards match it last (*.*) symbol will be returned
 | |
|         /// </summary>
 | |
|         public int this[XmlQualifiedName name] {
 | |
|             get {
 | |
|                 object lookup = names[name];
 | |
|                 if (lookup != null) {
 | |
|                     return (int)lookup;
 | |
|                 }
 | |
|                 if (wildcards != null) {
 | |
|                     lookup = wildcards[name.Namespace];
 | |
|                     if (lookup != null) {
 | |
|                         return (int)lookup;
 | |
|                     }   
 | |
|                 }
 | |
|                 return last; // true wildcard
 | |
|             }
 | |
|         }
 | |
|         
 | |
|         /// <summary>
 | |
|         /// Check if a name exists in the symbol dictionary
 | |
|         /// </summary>
 | |
|         public bool Exists(XmlQualifiedName name) {
 | |
| 
 | |
|             object lookup = names[name];
 | |
|             if (lookup != null) {
 | |
|                 return true;
 | |
|             }
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Return content processing mode for the symbol
 | |
|         /// </summary>
 | |
|         public object GetParticle(int symbol) {
 | |
|             return symbol == last ? particleLast : particles[symbol];
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Output symbol's name
 | |
|         /// </summary>
 | |
|         public string NameOf(int symbol) {
 | |
|             foreach (DictionaryEntry de in names) {
 | |
|                 if ((int)de.Value == symbol) {
 | |
|                     return ((XmlQualifiedName)de.Key).ToString();
 | |
|                 }
 | |
|             }
 | |
|             if (wildcards != null) {
 | |
|                 foreach (DictionaryEntry de in wildcards) {
 | |
|                     if ((int)de.Value == symbol) {
 | |
|                         return (string)de.Key + ":*";
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             return "##other:*";
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     struct Position {
 | |
|         public int symbol;
 | |
|         public object particle;
 | |
|         public Position(int symbol, object particle) {
 | |
|             this.symbol = symbol;
 | |
|             this.particle = particle;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     class Positions {
 | |
|         ArrayList positions = new ArrayList();
 | |
| 
 | |
|         public int Add(int symbol, object particle) {
 | |
|             return positions.Add(new Position(symbol, particle));
 | |
|         }
 | |
| 
 | |
|         public Position this[int pos] {
 | |
|             get { return (Position)positions[pos]; }
 | |
|         }
 | |
| 
 | |
|         public int Count {
 | |
|             get { return positions.Count; }
 | |
|         }
 | |
|     }
 | |
|     #endregion
 | |
| 
 | |
|     #region SystaxTree
 | |
|     /// <summary>
 | |
|     /// Base class for the systax tree nodes
 | |
|     /// </summary>
 | |
|     abstract class SyntaxTreeNode {
 | |
|         /// <summary>
 | |
|         /// Expand NamesapceListNode and RangeNode nodes. All other nodes
 | |
|         /// </summary>
 | |
|         public abstract void ExpandTree(InteriorNode parent, SymbolsDictionary symbols, Positions positions);
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Clone the syntaxTree. We need to pass symbolsByPosition because leaf nodes have to add themselves to it.
 | |
|         /// </summary>
 | |
|         public abstract SyntaxTreeNode Clone(Positions positions);
 | |
| 
 | |
|         /// <summary>
 | |
|         /// From a regular expression to a DFA
 | |
|         /// Compilers by Aho, Sethi, Ullman.
 | |
|         /// ISBN 0-201-10088-6, p135 
 | |
|         /// Construct firstpos, lastpos and calculate followpos 
 | |
|         /// </summary>
 | |
|         public abstract void ConstructPos(BitSet firstpos, BitSet lastpos, BitSet[] followpos);
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Returns nullable property that is being used by ConstructPos
 | |
|         /// </summary>
 | |
|         public abstract bool IsNullable { get; }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Returns true if node is a range node
 | |
|         /// </summary>
 | |
|         public virtual bool IsRangeNode { 
 | |
|             get {
 | |
|                 return false;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Print syntax tree
 | |
|         /// </summary>
 | |
| #if DEBUG        
 | |
|         public abstract void Dump(StringBuilder bb, SymbolsDictionary symbols, Positions positions);
 | |
| #endif
 | |
|     }
 | |
| 
 | |
|     /// <summary>
 | |
|     /// Terminal of the syntax tree
 | |
|     /// </summary>
 | |
|     class LeafNode : SyntaxTreeNode {
 | |
|         int pos;
 | |
| 
 | |
|         public LeafNode(int pos) {
 | |
|             this.pos = pos;
 | |
|         }
 | |
| 
 | |
|         public int Pos {
 | |
|             get { return pos;}
 | |
|             set { pos = value; }
 | |
|         }
 | |
| 
 | |
|         public override void ExpandTree(InteriorNode parent, SymbolsDictionary symbols, Positions positions) {
 | |
|             // do nothing
 | |
|         }
 | |
| 
 | |
|         public override SyntaxTreeNode Clone(Positions positions) {
 | |
|             return new LeafNode(positions.Add(positions[pos].symbol, positions[pos].particle));
 | |
|         }
 | |
| 
 | |
|         public override void ConstructPos(BitSet firstpos, BitSet lastpos, BitSet[] followpos) {
 | |
|             firstpos.Set(pos);
 | |
|             lastpos.Set(pos);
 | |
|         }
 | |
| 
 | |
|         public override bool IsNullable {
 | |
|             get { return false; }
 | |
|         }
 | |
| 
 | |
| #if DEBUG
 | |
|         public override void Dump(StringBuilder bb, SymbolsDictionary symbols, Positions positions) {
 | |
|             bb.Append("\"" + symbols.NameOf(positions[pos].symbol) + "\"");
 | |
|         }
 | |
| #endif
 | |
|     }
 | |
| 
 | |
|     /// <summary>
 | |
|     /// Temporary node to represent NamespaceList. Will be expended as a choice of symbols
 | |
|     /// </summary>
 | |
|     class NamespaceListNode : SyntaxTreeNode {
 | |
|         protected NamespaceList namespaceList;
 | |
|         protected object particle;
 | |
| 
 | |
|         public NamespaceListNode(NamespaceList namespaceList, object particle) {
 | |
|             this.namespaceList = namespaceList;
 | |
|             this.particle = particle;
 | |
|         }
 | |
| 
 | |
|         public override SyntaxTreeNode Clone(Positions positions) {
 | |
|             // NamespaceListNode nodes have to be removed prior to that
 | |
|             throw new InvalidOperationException();
 | |
|         }
 | |
| 
 | |
|         public virtual ICollection GetResolvedSymbols(SymbolsDictionary symbols)  {
 | |
|             return symbols.GetNamespaceListSymbols(namespaceList);
 | |
|         }
 | |
| 
 | |
|         public override void ExpandTree(InteriorNode parent, SymbolsDictionary symbols, Positions positions) {
 | |
|             SyntaxTreeNode replacementNode = null;
 | |
|             foreach(int symbol in GetResolvedSymbols(symbols)) {
 | |
|                 if (symbols.GetParticle(symbol) != particle) {
 | |
|                     symbols.IsUpaEnforced = false;
 | |
|                 }
 | |
|                 LeafNode node = new LeafNode(positions.Add(symbol, particle));
 | |
|                 if (replacementNode == null) {
 | |
|                     replacementNode = node;
 | |
|                 }
 | |
|                 else {
 | |
|                     InteriorNode choice = new ChoiceNode();
 | |
|                     choice.LeftChild = replacementNode;
 | |
|                     choice.RightChild = node;
 | |
|                     replacementNode = choice;
 | |
|                 }
 | |
|             }
 | |
|             if (parent.LeftChild == this) {
 | |
|                 parent.LeftChild = replacementNode;
 | |
|             }
 | |
|             else {
 | |
|                 parent.RightChild = replacementNode;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public override void ConstructPos(BitSet firstpos, BitSet lastpos, BitSet[] followpos) {
 | |
|             // NamespaceListNode nodes have to be removed prior to that
 | |
|             throw new InvalidOperationException();
 | |
|         }
 | |
| 
 | |
|         public override bool IsNullable {
 | |
|             // NamespaceListNode nodes have to be removed prior to that
 | |
|             get { throw new InvalidOperationException(); }
 | |
|         }
 | |
| 
 | |
| #if DEBUG
 | |
|         public override void Dump(StringBuilder bb, SymbolsDictionary symbols, Positions positions) {
 | |
|             bb.Append("[" + namespaceList.ToString() + "]");
 | |
|         }
 | |
| #endif
 | |
|     }
 | |
| 
 | |
|     /// <summary>
 | |
|     /// Base class for all internal node. Note that only sequence and choice have right child
 | |
|     /// </summary>
 | |
|     abstract class InteriorNode : SyntaxTreeNode {
 | |
|         SyntaxTreeNode leftChild;
 | |
|         SyntaxTreeNode rightChild;
 | |
| 
 | |
|         public SyntaxTreeNode LeftChild {
 | |
|             get { return leftChild;}
 | |
|             set { leftChild = value;}
 | |
|         }
 | |
| 
 | |
|         public SyntaxTreeNode RightChild {
 | |
|             get { return rightChild;}
 | |
|             set { rightChild = value;}
 | |
|         }
 | |
| 
 | |
|         public override SyntaxTreeNode Clone(Positions positions) {
 | |
|             InteriorNode other = (InteriorNode)this.MemberwiseClone();
 | |
|             other.LeftChild = leftChild.Clone(positions);
 | |
|             if (rightChild != null) {
 | |
|                 other.RightChild = rightChild.Clone(positions);
 | |
|             }
 | |
|             return other;
 | |
|         }
 | |
| 
 | |
|         //no recursive version of expand tree for Sequence and Choice node
 | |
|         protected void ExpandTreeNoRecursive(InteriorNode parent, SymbolsDictionary symbols, Positions positions) {
 | |
|             Stack<InteriorNode> nodeStack = new Stack<InteriorNode>();
 | |
|             InteriorNode this_ = this;
 | |
|             while (true) {
 | |
|                 if (this_.leftChild is ChoiceNode || this_.leftChild is SequenceNode) {
 | |
|                     nodeStack.Push(this_);
 | |
|                     this_ = (InteriorNode)this_.leftChild;
 | |
|                     continue;
 | |
|                 }
 | |
|                 this_.leftChild.ExpandTree(this_, symbols, positions);
 | |
| 
 | |
|             ProcessRight:
 | |
|                 if (this_.rightChild != null) {
 | |
|                     this_.rightChild.ExpandTree(this_, symbols, positions);
 | |
|                 }
 | |
| 
 | |
|                 if (nodeStack.Count == 0)
 | |
|                     break;
 | |
| 
 | |
|                 this_ = nodeStack.Pop();
 | |
|                 goto ProcessRight;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public override void ExpandTree(InteriorNode parent, SymbolsDictionary symbols, Positions positions) {
 | |
|             leftChild.ExpandTree(this, symbols, positions);
 | |
|             if (rightChild != null) {
 | |
|                 rightChild.ExpandTree(this, symbols, positions);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     
 | |
|     sealed class SequenceNode : InteriorNode {
 | |
| 
 | |
|         struct SequenceConstructPosContext {
 | |
|             public SequenceNode this_;
 | |
|             public BitSet firstpos;
 | |
|             public BitSet lastpos;
 | |
|             public BitSet lastposLeft;
 | |
|             public BitSet firstposRight;
 | |
| 
 | |
|             public SequenceConstructPosContext(SequenceNode node, BitSet firstpos, BitSet lastpos) {
 | |
|                 this_ = node;
 | |
|                 this.firstpos = firstpos;
 | |
|                 this.lastpos = lastpos;
 | |
| 
 | |
|                 lastposLeft = null;
 | |
|                 firstposRight = null;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public override void ConstructPos(BitSet firstpos, BitSet lastpos, BitSet[] followpos) {
 | |
| 
 | |
|             Stack<SequenceConstructPosContext> contextStack = new Stack<SequenceConstructPosContext>();
 | |
|             SequenceConstructPosContext context = new SequenceConstructPosContext(this, firstpos, lastpos);
 | |
| 
 | |
|             while (true) {
 | |
|                 SequenceNode this_ = context.this_;
 | |
|                 context.lastposLeft = new BitSet(lastpos.Count);
 | |
|                 if (this_.LeftChild is SequenceNode) {
 | |
|                     contextStack.Push(context);
 | |
|                     context = new SequenceConstructPosContext((SequenceNode)this_.LeftChild, context.firstpos, context.lastposLeft);
 | |
|                     continue;
 | |
|                 }
 | |
|                 this_.LeftChild.ConstructPos(context.firstpos, context.lastposLeft, followpos);
 | |
| 
 | |
|             ProcessRight:
 | |
|                 context.firstposRight = new BitSet(firstpos.Count);
 | |
|                 this_.RightChild.ConstructPos(context.firstposRight, context.lastpos, followpos);
 | |
| 
 | |
|                 if (this_.LeftChild.IsNullable && !this_.RightChild.IsRangeNode) {
 | |
|                     context.firstpos.Or(context.firstposRight);
 | |
|                 }
 | |
|                 if (this_.RightChild.IsNullable) {
 | |
|                     context.lastpos.Or(context.lastposLeft);
 | |
|                 }
 | |
|                 for (int pos = context.lastposLeft.NextSet(-1); pos != -1; pos = context.lastposLeft.NextSet(pos)) {
 | |
|                     followpos[pos].Or(context.firstposRight);
 | |
|                 }
 | |
|                 if (this_.RightChild.IsRangeNode) { //firstpos is leftchild.firstpos as the or with firstposRight has not been done as it is a rangenode
 | |
|                     ((LeafRangeNode)this_.RightChild).NextIteration = context.firstpos.Clone();
 | |
|                 }
 | |
| 
 | |
|                 if (contextStack.Count == 0)
 | |
|                     break;
 | |
| 
 | |
|                 context = contextStack.Pop();
 | |
|                 this_ = context.this_;
 | |
|                 goto ProcessRight;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public override bool IsNullable {
 | |
|             get {
 | |
|                 SyntaxTreeNode n;
 | |
|                 SequenceNode this_ = this;
 | |
|                 do {
 | |
|                     if (this_.RightChild.IsRangeNode && ((LeafRangeNode)this_.RightChild).Min == 0)
 | |
|                         return true;
 | |
|                     if (!this_.RightChild.IsNullable && !this_.RightChild.IsRangeNode)
 | |
|                         return false;
 | |
|                     n = this_.LeftChild;
 | |
|                     this_ = n as SequenceNode;
 | |
|                 }
 | |
|                 while (this_ != null);
 | |
|                 return n.IsNullable;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public override void ExpandTree(InteriorNode parent, SymbolsDictionary symbols, Positions positions) {
 | |
|  	        ExpandTreeNoRecursive(parent, symbols, positions);
 | |
|         }
 | |
| 
 | |
| #if DEBUG
 | |
|         internal static void WritePos(BitSet firstpos, BitSet lastpos, BitSet[] followpos) {
 | |
|             Debug.WriteLineIf(DiagnosticsSwitches.XmlSchemaContentModel.Enabled, "FirstPos:  ");
 | |
|             WriteBitSet(firstpos);
 | |
| 
 | |
|             Debug.WriteLineIf(DiagnosticsSwitches.XmlSchemaContentModel.Enabled, "LastPos:  ");
 | |
|             WriteBitSet(lastpos);
 | |
| 
 | |
|             Debug.WriteLineIf(DiagnosticsSwitches.XmlSchemaContentModel.Enabled, "Followpos:  ");
 | |
|             for(int i =0; i < followpos.Length; i++) {
 | |
|                 WriteBitSet(followpos[i]);
 | |
|             }
 | |
|         }
 | |
|         internal static void WriteBitSet(BitSet curpos) {
 | |
|             int[] list = new int[curpos.Count];
 | |
|             for (int pos = curpos.NextSet(-1); pos != -1; pos = curpos.NextSet(pos)) {
 | |
|                 list[pos] = 1;
 | |
|             }
 | |
|             for(int i = 0; i < list.Length; i++) {
 | |
|                 Debug.WriteIf(DiagnosticsSwitches.XmlSchemaContentModel.Enabled, list[i] + " ");
 | |
|             }
 | |
|             Debug.WriteLineIf(DiagnosticsSwitches.XmlSchemaContentModel.Enabled, "");
 | |
|         }
 | |
|        
 | |
| 
 | |
|         public override void Dump(StringBuilder bb, SymbolsDictionary symbols, Positions positions) {
 | |
|             Stack<SequenceNode> nodeStack = new Stack<SequenceNode>();
 | |
|             SequenceNode this_ = this;
 | |
| 
 | |
|             while (true) {
 | |
|                 bb.Append("(");
 | |
|                 if (this_.LeftChild is SequenceNode) {
 | |
|                     nodeStack.Push(this_);
 | |
|                     this_ = (SequenceNode)this_.LeftChild;
 | |
|                     continue;
 | |
|                 }
 | |
|                 this_.LeftChild.Dump(bb, symbols, positions);
 | |
| 
 | |
|             ProcessRight:
 | |
|                 bb.Append(", ");
 | |
|                 this_.RightChild.Dump(bb, symbols, positions);
 | |
|                 bb.Append(")");
 | |
|                 if (nodeStack.Count == 0)
 | |
|                     break;
 | |
| 
 | |
|                 this_ = nodeStack.Pop();
 | |
|                 goto ProcessRight;
 | |
|             }
 | |
|         }
 | |
| #endif
 | |
| 
 | |
|     }
 | |
| 
 | |
|     sealed class ChoiceNode : InteriorNode {
 | |
| 
 | |
|         private static void ConstructChildPos(SyntaxTreeNode child, BitSet firstpos, BitSet lastpos, BitSet[] followpos) {
 | |
|             BitSet firstPosTemp = new BitSet(firstpos.Count);
 | |
|             BitSet lastPosTemp = new BitSet(lastpos.Count);
 | |
|             child.ConstructPos(firstPosTemp, lastPosTemp, followpos);
 | |
|             firstpos.Or(firstPosTemp);
 | |
|             lastpos.Or(lastPosTemp);
 | |
|         }
 | |
| 
 | |
|         public override void ConstructPos(BitSet firstpos, BitSet lastpos, BitSet[] followpos) {
 | |
| 
 | |
|             BitSet firstPosTemp = new BitSet(firstpos.Count);
 | |
|             BitSet lastPosTemp = new BitSet(lastpos.Count);
 | |
|             SyntaxTreeNode n;
 | |
|             ChoiceNode this_ = this;
 | |
|             do {
 | |
|                 ConstructChildPos(this_.RightChild, firstPosTemp, lastPosTemp, followpos);
 | |
|                 n = this_.LeftChild;
 | |
|                 this_ = n as ChoiceNode;
 | |
|             } while (this_ != null);
 | |
| 
 | |
|             n.ConstructPos(firstpos, lastpos, followpos);
 | |
|             firstpos.Or(firstPosTemp);
 | |
|             lastpos.Or(lastPosTemp);
 | |
|         }
 | |
| 
 | |
|         public override bool IsNullable {
 | |
|             get {
 | |
|                 SyntaxTreeNode n;
 | |
|                 ChoiceNode this_ = this;
 | |
|                 do {
 | |
|                     if (this_.RightChild.IsNullable)
 | |
|                         return true;
 | |
|                     n = this_.LeftChild;
 | |
|                     this_ = n as ChoiceNode;
 | |
|                 }
 | |
|                 while (this_ != null);
 | |
|                 return n.IsNullable;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public override void ExpandTree(InteriorNode parent, SymbolsDictionary symbols, Positions positions) {
 | |
|  	        ExpandTreeNoRecursive(parent, symbols, positions);
 | |
|         }
 | |
| 
 | |
| #if DEBUG
 | |
|         public override void Dump(StringBuilder bb, SymbolsDictionary symbols, Positions positions) {
 | |
|             Stack<ChoiceNode> nodeStack = new Stack<ChoiceNode>();
 | |
|             ChoiceNode this_ = this;
 | |
| 
 | |
|             while (true) {
 | |
|                 bb.Append("(");
 | |
|                 if (this_.LeftChild is ChoiceNode) {
 | |
|                     nodeStack.Push(this_);
 | |
|                     this_ = (ChoiceNode)this_.LeftChild;
 | |
|                     continue;
 | |
|                 }
 | |
|                 this_.LeftChild.Dump(bb, symbols, positions);
 | |
| 
 | |
|             ProcessRight:
 | |
|                 bb.Append(" | ");
 | |
|                 this_.RightChild.Dump(bb, symbols, positions);
 | |
|                 bb.Append(")");
 | |
|                 if (nodeStack.Count == 0)
 | |
|                     break;
 | |
| 
 | |
|                 this_ = nodeStack.Pop();
 | |
|                 goto ProcessRight;
 | |
|             }
 | |
|         }
 | |
| #endif
 | |
|     }
 | |
|     
 | |
|     sealed class PlusNode : InteriorNode {
 | |
|         public override void ConstructPos(BitSet firstpos, BitSet lastpos, BitSet[] followpos) {
 | |
|             LeftChild.ConstructPos(firstpos, lastpos, followpos);
 | |
|             for (int pos = lastpos.NextSet(-1); pos != -1; pos = lastpos.NextSet(pos)) {
 | |
|                 followpos[pos].Or(firstpos);
 | |
|             }
 | |
|         }
 | |
|         
 | |
|         public override bool IsNullable {
 | |
|             get { return LeftChild.IsNullable; }
 | |
|         }
 | |
| 
 | |
| #if DEBUG
 | |
|         public override void Dump(StringBuilder bb, SymbolsDictionary symbols, Positions positions) {
 | |
|             LeftChild.Dump(bb, symbols, positions);
 | |
|             bb.Append("+");
 | |
|         }
 | |
| #endif
 | |
|     }
 | |
|     
 | |
|     sealed class QmarkNode : InteriorNode {
 | |
|         public override void ConstructPos(BitSet firstpos, BitSet lastpos, BitSet[] followpos) {
 | |
|             LeftChild.ConstructPos(firstpos, lastpos, followpos);
 | |
|         }
 | |
| 
 | |
|         public override bool IsNullable {
 | |
|             get { return true; }
 | |
|         }
 | |
| 
 | |
| #if DEBUG
 | |
|         public override void Dump(StringBuilder bb, SymbolsDictionary symbols, Positions positions) {
 | |
|             LeftChild.Dump(bb, symbols, positions);
 | |
|             bb.Append("?");
 | |
|         }
 | |
| #endif
 | |
|     }
 | |
| 
 | |
|     sealed class StarNode : InteriorNode {
 | |
|         public override void ConstructPos(BitSet firstpos, BitSet lastpos, BitSet[] followpos) {
 | |
|             LeftChild.ConstructPos(firstpos, lastpos, followpos);
 | |
|             for (int pos = lastpos.NextSet(-1); pos != -1; pos = lastpos.NextSet(pos)) {
 | |
|                 followpos[pos].Or(firstpos);
 | |
|             }
 | |
|         }
 | |
|         
 | |
|         public override bool IsNullable {
 | |
|             get { return true; }
 | |
|         }
 | |
| 
 | |
| #if DEBUG
 | |
|         public override void Dump(StringBuilder bb, SymbolsDictionary symbols, Positions positions) {
 | |
|             LeftChild.Dump(bb, symbols, positions);
 | |
|             bb.Append("*");
 | |
|         }
 | |
| #endif
 | |
|     }
 | |
| 
 | |
| #if EXPANDRANGE
 | |
|     /// <summary>
 | |
|     /// Temporary node to occurance range. Will be expended to a sequence of terminals
 | |
|     /// </summary>
 | |
|     sealed class RangeNode : InteriorNode {
 | |
|         int min;
 | |
|         int max;
 | |
|         
 | |
|         public RangeNode(int min, int max) {
 | |
|             this.min = min;
 | |
|             this.max = max;
 | |
|         }
 | |
| 
 | |
|         public int Max {
 | |
|             get { return max;}
 | |
|         }
 | |
| 
 | |
|         public int Min {
 | |
|             get { return min;}
 | |
|         }
 | |
| 
 | |
|         public override SyntaxTreeNode Clone(Positions positions) {
 | |
|             // range nodes have to be removed prior to that
 | |
|             throw new InvalidOperationException();
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Expand tree will replace a{min, max} using following algorithm. Bare in mind that this sequence will have at least two leaves
 | |
|         /// if min == 0 (max cannot be unbounded)
 | |
|         ///         a?, ...  a?
 | |
|         ///         \__     __/
 | |
|         ///             max
 | |
|         /// else
 | |
|         ///     if max == unbounded
 | |
|         ///         a,  ...   a, a*
 | |
|         ///         \__     __/
 | |
|         ///             min
 | |
|         ///     else
 | |
|         ///         a,  ...   a, a?,   ...     a?
 | |
|         ///         \__     __/  \__          __/
 | |
|         ///             min          max - min
 | |
|         /// </summary>
 | |
|         public override void ExpandTree(InteriorNode parent, SymbolsDictionary symbols, Positions positions) {
 | |
|             LeftChild.ExpandTree(this, symbols, positions);
 | |
|             SyntaxTreeNode replacementNode = null;
 | |
|             if (min == 0) {
 | |
|                 Debug.Assert(max != int.MaxValue);
 | |
|                 replacementNode = NewQmark(LeftChild);
 | |
|                 for (int i = 0; i < max - 1; i ++) {
 | |
|                     replacementNode = NewSequence(replacementNode, NewQmark(LeftChild.Clone(positions)));
 | |
|                 }
 | |
|             }
 | |
|             else {
 | |
|                 replacementNode = LeftChild;
 | |
|                 for (int i = 0; i < min - 1; i ++) {
 | |
|                     replacementNode = NewSequence(replacementNode, LeftChild.Clone(positions));
 | |
|                 }
 | |
|                 if (max == int.MaxValue) {
 | |
|                     replacementNode = NewSequence(replacementNode, NewStar(LeftChild.Clone(positions)));
 | |
|                 }
 | |
|                 else {
 | |
|                     for (int i = 0; i < max - min; i ++) {
 | |
|                         replacementNode = NewSequence(replacementNode, NewQmark(LeftChild.Clone(positions)));
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             if (parent.LeftChild == this) {
 | |
|                 parent.LeftChild = replacementNode;
 | |
|             }
 | |
|             else {
 | |
|                 parent.RightChild = replacementNode;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private SyntaxTreeNode NewSequence(SyntaxTreeNode leftChild, SyntaxTreeNode rightChild) {
 | |
|             InteriorNode sequence = new SequenceNode();
 | |
|             sequence.LeftChild = leftChild;
 | |
|             sequence.RightChild = rightChild;
 | |
|             return sequence;
 | |
|         }
 | |
| 
 | |
|         private SyntaxTreeNode NewStar(SyntaxTreeNode leftChild) {
 | |
|             InteriorNode star = new StarNode();
 | |
|             star.LeftChild = leftChild;
 | |
|             return star;
 | |
|         }
 | |
| 
 | |
|         private SyntaxTreeNode NewQmark(SyntaxTreeNode leftChild) {
 | |
|             InteriorNode qmark = new QmarkNode();
 | |
|             qmark.LeftChild = leftChild;
 | |
|             return qmark;
 | |
|         }
 | |
|         
 | |
|         public override void ConstructPos(BitSet firstpos, BitSet lastpos, BitSet[] followpos) {
 | |
|             throw new InvalidOperationException();
 | |
|         }
 | |
| 
 | |
|         public override bool IsNullable {
 | |
|             get { throw new InvalidOperationException(); }
 | |
|         }
 | |
| 
 | |
|         public override void Dump(StringBuilder bb, SymbolsDictionary symbols, Positions positions) {
 | |
|             LeftChild.Dump(bb, symbols, positions);
 | |
|             bb.Append("{" + Convert.ToString(min, NumberFormatInfo.InvariantInfo) + ", " + Convert.ToString(max, NumberFormatInfo.InvariantInfo) + "}");
 | |
|         }
 | |
| 
 | |
|     }
 | |
| #endif
 | |
| 
 | |
| 
 | |
|     /// <summary>
 | |
|     /// Using range node as one of the terminals
 | |
|     /// </summary>
 | |
|     sealed class LeafRangeNode : LeafNode {
 | |
|         decimal min;
 | |
|         decimal max;
 | |
|         BitSet nextIteration;
 | |
| 
 | |
|         public LeafRangeNode(decimal min, decimal max) : this(-1, min, max) {}
 | |
| 
 | |
|         public LeafRangeNode(int pos, decimal min, decimal max) : base(pos) {
 | |
|             this.min = min;
 | |
|             this.max = max;
 | |
|         }
 | |
| 
 | |
|         public decimal Max {
 | |
|             get { return max;}
 | |
|         }
 | |
| 
 | |
|         public decimal Min {
 | |
|             get { return min;}
 | |
|         }
 | |
| 
 | |
|         public BitSet NextIteration {
 | |
|             get {
 | |
|                 return nextIteration;
 | |
|             }
 | |
|             set {
 | |
|                 nextIteration = value;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public override SyntaxTreeNode Clone(Positions positions) {
 | |
|             return new LeafRangeNode(this.Pos, this.min, this.max);
 | |
|         }
 | |
|         
 | |
|         public override bool IsRangeNode { 
 | |
|             get {
 | |
|                 return true;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public override void ExpandTree(InteriorNode parent, SymbolsDictionary symbols, Positions positions) {
 | |
|             Debug.Assert(parent is SequenceNode);
 | |
|             Debug.Assert(this == parent.RightChild);
 | |
|             //change the range node min to zero if left is nullable
 | |
|             if (parent.LeftChild.IsNullable) {
 | |
|                 min = 0;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     #endregion
 | |
| 
 | |
|     #region ContentValidator
 | |
|     /// <summary>
 | |
|     /// Basic ContentValidator
 | |
|     /// </summary>
 | |
|     class ContentValidator {
 | |
|         XmlSchemaContentType contentType;
 | |
|         bool isOpen;  //For XDR Content Models or ANY
 | |
|         bool isEmptiable;
 | |
| 
 | |
|         public static readonly ContentValidator Empty = new ContentValidator(XmlSchemaContentType.Empty);
 | |
|         public static readonly ContentValidator TextOnly = new ContentValidator(XmlSchemaContentType.TextOnly, false, false);
 | |
|         public static readonly ContentValidator Mixed = new ContentValidator(XmlSchemaContentType.Mixed);
 | |
|         public static readonly ContentValidator Any = new ContentValidator(XmlSchemaContentType.Mixed, true, true);
 | |
| 
 | |
|         public ContentValidator(XmlSchemaContentType contentType) {
 | |
|             this.contentType = contentType;
 | |
|             this.isEmptiable = true;
 | |
|         }
 | |
|         
 | |
|         protected ContentValidator(XmlSchemaContentType contentType, bool isOpen, bool isEmptiable) {
 | |
|             this.contentType = contentType;
 | |
|             this.isOpen = isOpen;
 | |
|             this.isEmptiable = isEmptiable;
 | |
|         }
 | |
|         
 | |
|         public XmlSchemaContentType ContentType { 
 | |
|             get { return contentType; }
 | |
|         }
 | |
| 
 | |
|         public bool PreserveWhitespace {
 | |
|             get { return contentType == XmlSchemaContentType.TextOnly || contentType == XmlSchemaContentType.Mixed; }
 | |
|         }
 | |
| 
 | |
|         public virtual bool IsEmptiable { 
 | |
|             get { return isEmptiable; }
 | |
|         }
 | |
|         
 | |
|         public bool IsOpen {
 | |
|             get { 
 | |
|                 if (contentType == XmlSchemaContentType.TextOnly || contentType == XmlSchemaContentType.Empty)
 | |
|                     return false;
 | |
|                 else
 | |
|                     return isOpen; 
 | |
|             }
 | |
|             set { isOpen = value; }
 | |
|         }
 | |
| 
 | |
|         public virtual void InitValidation(ValidationState context) {
 | |
|             // do nothin'
 | |
|         }
 | |
| 
 | |
|         public virtual object ValidateElement(XmlQualifiedName name, ValidationState context, out int errorCode) {
 | |
|             if (contentType == XmlSchemaContentType.TextOnly || contentType == XmlSchemaContentType.Empty) { //Cannot have elements in TextOnly or Empty content
 | |
|                 context.NeedValidateChildren = false;
 | |
|             }
 | |
|             errorCode = -1;
 | |
|             return null;
 | |
|         }
 | |
| 
 | |
|         public virtual bool CompleteValidation(ValidationState context) {
 | |
|             return true;
 | |
|         }
 | |
| 
 | |
|         public virtual ArrayList ExpectedElements(ValidationState context, bool isRequiredOnly) {
 | |
|             return null;
 | |
|         }
 | |
| 
 | |
|         public virtual ArrayList ExpectedParticles(ValidationState context, bool isRequiredOnly, XmlSchemaSet schemaSet) {
 | |
|             return null;
 | |
|         }
 | |
| 
 | |
|         public static void AddParticleToExpected(XmlSchemaParticle p, XmlSchemaSet schemaSet, ArrayList particles) {
 | |
|             AddParticleToExpected(p, schemaSet, particles, false);
 | |
|         }
 | |
| 
 | |
|         public static void AddParticleToExpected(XmlSchemaParticle p, XmlSchemaSet schemaSet, ArrayList particles, bool global) {
 | |
|             if (!particles.Contains(p)) {
 | |
|                 particles.Add(p);
 | |
|             }
 | |
|             //Only then it can be head of substitutionGrp, if it is, add its members 
 | |
|             XmlSchemaElement elem = p as XmlSchemaElement;
 | |
|             if (elem != null && (global ||!elem.RefName.IsEmpty)) { 
 | |
| 				XmlSchemaObjectTable substitutionGroups = schemaSet.SubstitutionGroups;
 | |
|                 XmlSchemaSubstitutionGroup grp = (XmlSchemaSubstitutionGroup)substitutionGroups[elem.QualifiedName];
 | |
|                 if (grp != null) {
 | |
|                     //Grp members wil contain the head as well, so filter head as we added it already
 | |
|                     for (int i = 0; i < grp.Members.Count; ++i) {
 | |
|                         XmlSchemaElement member = (XmlSchemaElement)grp.Members[i];
 | |
|                         if (!elem.QualifiedName.Equals(member.QualifiedName) && !particles.Contains(member)) { //A member might have been directly present as an element in the content model
 | |
|                             particles.Add(member);
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     sealed class ParticleContentValidator : ContentValidator {
 | |
|         SymbolsDictionary symbols;          
 | |
|         Positions positions;                
 | |
|         Stack stack;                        // parsing context
 | |
|         SyntaxTreeNode contentNode;         // content model points to syntax tree
 | |
|         bool isPartial;                     // whether the closure applies to partial or the whole node that is on top of the stack
 | |
|         int minMaxNodesCount;
 | |
|         bool enableUpaCheck;
 | |
| 
 | |
|         public ParticleContentValidator(XmlSchemaContentType contentType) : this(contentType, true) {
 | |
|         }
 | |
| 
 | |
|         public ParticleContentValidator(XmlSchemaContentType contentType, bool enableUpaCheck) : base(contentType) {
 | |
|             this.enableUpaCheck = enableUpaCheck;
 | |
|         }
 | |
| 
 | |
|         public override void InitValidation(ValidationState context) {
 | |
|             // ParticleContentValidator cannot be used during validation
 | |
|             throw new InvalidOperationException();
 | |
|         }
 | |
| 
 | |
|         public override object ValidateElement(XmlQualifiedName name, ValidationState context, out int errorCode) {
 | |
|             // ParticleContentValidator cannot be used during validation
 | |
|             throw new InvalidOperationException();
 | |
|         }
 | |
| 
 | |
|         public override bool CompleteValidation(ValidationState context) {
 | |
|             // ParticleContentValidator cannot be used during validation
 | |
|             throw new InvalidOperationException();
 | |
|         }
 | |
| 
 | |
|         public void Start() {
 | |
|             symbols = new SymbolsDictionary();
 | |
|             positions = new Positions();
 | |
|             stack = new Stack();
 | |
|         }
 | |
| 
 | |
|         public void OpenGroup() {
 | |
|             stack.Push(null);
 | |
|         }
 | |
| 
 | |
|         public void CloseGroup() {
 | |
|             SyntaxTreeNode node = (SyntaxTreeNode)stack.Pop();
 | |
|             if (node == null) {
 | |
|                 return;
 | |
|             }
 | |
|             if (stack.Count == 0) {
 | |
|                 contentNode = node;
 | |
|                 isPartial = false;
 | |
|             }
 | |
|             else {
 | |
|                 // some collapsing to do...
 | |
|                 InteriorNode inNode = (InteriorNode)stack.Pop();
 | |
|                 if (inNode != null) {
 | |
|                     inNode.RightChild = node;
 | |
|                     node = inNode;
 | |
|                     isPartial = true;
 | |
|                 }
 | |
|                 else {
 | |
|                     isPartial = false;
 | |
|                 }
 | |
|                 stack.Push(node);
 | |
|             }
 | |
|         }
 | |
|         
 | |
|         public bool Exists(XmlQualifiedName name) {
 | |
|             if (symbols.Exists(name)) {
 | |
|                 return true;
 | |
|             }
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         public void AddName(XmlQualifiedName name, object particle) {
 | |
|             AddLeafNode(new LeafNode(positions.Add(symbols.AddName(name, particle), particle)));
 | |
|         }
 | |
|         
 | |
|         public void AddNamespaceList(NamespaceList namespaceList, object particle) {
 | |
|             symbols.AddNamespaceList(namespaceList, particle, false);
 | |
|             AddLeafNode(new NamespaceListNode(namespaceList, particle));
 | |
|         }
 | |
| 
 | |
|         private void AddLeafNode(SyntaxTreeNode node) {
 | |
|             if (stack.Count > 0) {
 | |
|                 InteriorNode inNode = (InteriorNode)stack.Pop();
 | |
|                 if (inNode != null) {
 | |
|                     inNode.RightChild = node;
 | |
|                     node = inNode;
 | |
|                 }
 | |
|             }
 | |
|             stack.Push( node );
 | |
|             isPartial = true;
 | |
|         }
 | |
| 
 | |
|         public void AddChoice() {
 | |
|             SyntaxTreeNode node = (SyntaxTreeNode)stack.Pop();
 | |
|             InteriorNode choice = new ChoiceNode();
 | |
|             choice.LeftChild = node;
 | |
|             stack.Push(choice);
 | |
|         }
 | |
| 
 | |
|         public void AddSequence() {
 | |
|             SyntaxTreeNode node = (SyntaxTreeNode)stack.Pop();
 | |
|             InteriorNode sequence = new SequenceNode();
 | |
|             sequence.LeftChild = node;
 | |
|             stack.Push(sequence);
 | |
|         }
 | |
| 
 | |
|         public void AddStar() {
 | |
|             Closure(new StarNode());
 | |
|         }
 | |
| 
 | |
|         public void AddPlus() {
 | |
|             Closure(new PlusNode());
 | |
|         }
 | |
| 
 | |
|         public void AddQMark() {
 | |
|             Closure(new QmarkNode());
 | |
|         }
 | |
| 
 | |
|         public void AddLeafRange(decimal min, decimal max) {
 | |
|             LeafRangeNode rNode = new LeafRangeNode(min, max);
 | |
|             int pos = positions.Add(-2, rNode);
 | |
|             rNode.Pos = pos;
 | |
| 
 | |
|             InteriorNode sequence = new SequenceNode();
 | |
|             sequence.RightChild = rNode;
 | |
|             Closure(sequence);
 | |
|             minMaxNodesCount++;
 | |
|         }
 | |
| 
 | |
| #if EXPANDRANGE
 | |
|         public void AddRange(int min, int max) {
 | |
|             Closure(new RangeNode(min, max));
 | |
|         }
 | |
| #endif
 | |
|         private void Closure(InteriorNode node) {
 | |
|             if (stack.Count > 0) {
 | |
|                 SyntaxTreeNode topNode = (SyntaxTreeNode)stack.Pop();
 | |
|                 InteriorNode inNode = topNode as InteriorNode;
 | |
|                 if (isPartial && inNode != null) {
 | |
|                     // need to reach in and wrap right hand side of element.
 | |
|                     // and n remains the same.
 | |
|                     node.LeftChild = inNode.RightChild;
 | |
|                     inNode.RightChild = node;
 | |
|                 }
 | |
|                 else {
 | |
|                     // wrap terminal or any node
 | |
|                     node.LeftChild = topNode;
 | |
|                     topNode = node;
 | |
|                 }
 | |
|                 stack.Push(topNode);
 | |
|             }
 | |
|             else if (contentNode != null) { //If there is content to wrap
 | |
|                 // wrap whole content
 | |
|                 node.LeftChild = contentNode;
 | |
|                 contentNode = node;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public ContentValidator Finish() {
 | |
|             return Finish(true);
 | |
|         }
 | |
| 
 | |
|         public ContentValidator Finish(bool useDFA) {
 | |
|             Debug.Assert(ContentType == XmlSchemaContentType.ElementOnly || ContentType == XmlSchemaContentType.Mixed);
 | |
|             if (contentNode == null) {
 | |
|                 if (ContentType == XmlSchemaContentType.Mixed) {
 | |
|                     string ctype = IsOpen ? "Any" : "TextOnly";
 | |
|                     Debug.WriteLineIf(DiagnosticsSwitches.XmlSchemaContentModel.Enabled,  "\t\t\tContentType:  " + ctype);
 | |
|                     return IsOpen ? ContentValidator.Any : ContentValidator.TextOnly;
 | |
|                 }
 | |
|                 else {
 | |
|                     Debug.WriteLineIf(DiagnosticsSwitches.XmlSchemaContentModel.Enabled,  "\t\t\tContent:   EMPTY");
 | |
|                     Debug.Assert(!IsOpen);
 | |
|                     return ContentValidator.Empty;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             #if DEBUG
 | |
|             StringBuilder bb = new StringBuilder();
 | |
|             contentNode.Dump(bb, symbols, positions);
 | |
|             Debug.WriteLineIf(DiagnosticsSwitches.XmlSchemaContentModel.Enabled,  "\t\t\tContent :   " + bb.ToString());
 | |
|             #endif
 | |
| 
 | |
|             // Add end marker
 | |
|             InteriorNode contentRoot = new SequenceNode();
 | |
|             contentRoot.LeftChild = contentNode;
 | |
|             LeafNode endMarker = new LeafNode(positions.Add(symbols.AddName(XmlQualifiedName.Empty, null), null));
 | |
|             contentRoot.RightChild = endMarker;
 | |
| 
 | |
|             // Eliminate NamespaceListNode(s) and RangeNode(s)
 | |
|             contentNode.ExpandTree(contentRoot, symbols, positions);
 | |
| 
 | |
|             #if DEBUG
 | |
|             bb = new StringBuilder();
 | |
|             contentRoot.LeftChild.Dump(bb, symbols, positions);
 | |
|             Debug.WriteLineIf(DiagnosticsSwitches.XmlSchemaContentModel.Enabled,  "\t\t\tExpended:   " + bb.ToString());
 | |
|             #endif
 | |
| 
 | |
|             // calculate followpos
 | |
|             int symbolsCount = symbols.Count;
 | |
|             int positionsCount = positions.Count;
 | |
|             BitSet firstpos = new BitSet(positionsCount);
 | |
|             BitSet lastpos = new BitSet(positionsCount);
 | |
|             BitSet[] followpos = new BitSet[positionsCount];
 | |
|             for (int i = 0; i < positionsCount; i++) {
 | |
|                 followpos[i] = new BitSet(positionsCount);
 | |
|             }
 | |
|             contentRoot.ConstructPos(firstpos, lastpos, followpos);
 | |
| #if DEBUG
 | |
|             Debug.WriteLineIf(DiagnosticsSwitches.XmlSchemaContentModel.Enabled, "firstpos, lastpos, followpos");
 | |
|             SequenceNode.WritePos(firstpos, lastpos, followpos);
 | |
| #endif
 | |
|             if (minMaxNodesCount > 0) { //If the tree has any terminal range nodes
 | |
|                 BitSet positionsWithRangeTerminals;
 | |
|                 BitSet[] minMaxFollowPos = CalculateTotalFollowposForRangeNodes(firstpos, followpos, out positionsWithRangeTerminals);
 | |
|                 
 | |
|                 if (enableUpaCheck) {
 | |
|                     CheckCMUPAWithLeafRangeNodes(GetApplicableMinMaxFollowPos(firstpos, positionsWithRangeTerminals, minMaxFollowPos));
 | |
|                     for (int i = 0; i < positionsCount; i++) {
 | |
|                         CheckCMUPAWithLeafRangeNodes(GetApplicableMinMaxFollowPos(followpos[i], positionsWithRangeTerminals, minMaxFollowPos));
 | |
|                     }
 | |
|                 }
 | |
|                 return new RangeContentValidator(firstpos, followpos, symbols, positions, endMarker.Pos, this.ContentType, contentRoot.LeftChild.IsNullable, positionsWithRangeTerminals, minMaxNodesCount); 
 | |
|             }
 | |
|             else {
 | |
|                 int[][] transitionTable = null;
 | |
|                 // if each symbol has unique particle we are golden
 | |
|                 if (!symbols.IsUpaEnforced) {
 | |
|                     if (enableUpaCheck) {
 | |
|                         // multiple positions that match the same symbol have different particles, but they never follow the same position
 | |
|                         CheckUniqueParticleAttribution(firstpos, followpos);
 | |
|                     }
 | |
|                 }
 | |
|                 else if (useDFA) {
 | |
|                     // Can return null if the number of states reaches higher than 8192 / positionsCount
 | |
|                     transitionTable = BuildTransitionTable(firstpos, followpos, endMarker.Pos); 
 | |
|                 }
 | |
|                 #if DEBUG
 | |
|                 bb = new StringBuilder();
 | |
|                 Dump(bb, followpos, transitionTable);    
 | |
|                 Debug.WriteLineIf(DiagnosticsSwitches.XmlSchemaContentModel.Enabled, bb.ToString());
 | |
|                 #endif
 | |
|                 if (transitionTable != null) {
 | |
|                     return new DfaContentValidator(transitionTable, symbols,this.ContentType, this.IsOpen, contentRoot.LeftChild.IsNullable);
 | |
|                 } else {
 | |
|                     return new NfaContentValidator(firstpos, followpos, symbols, positions, endMarker.Pos, this.ContentType, this.IsOpen, contentRoot.LeftChild.IsNullable);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private BitSet[] CalculateTotalFollowposForRangeNodes(BitSet firstpos, BitSet[] followpos, out BitSet posWithRangeTerminals) {
 | |
|             int positionsCount = positions.Count; //terminals
 | |
|             posWithRangeTerminals = new BitSet(positionsCount);
 | |
|             
 | |
|             //Compute followpos for each range node
 | |
|             //For any range node that is surrounded by an outer range node, its follow positions will include those of the outer range node
 | |
|             BitSet[] minmaxFollowPos = new BitSet[minMaxNodesCount];
 | |
|             int localMinMaxNodesCount = 0;
 | |
|             
 | |
|             for (int i = positionsCount - 1;  i >= 0; i--) { 
 | |
|                 Position p = positions[i];
 | |
|                 if (p.symbol == -2) { //P is a LeafRangeNode
 | |
|                     LeafRangeNode lrNode = p.particle as LeafRangeNode;
 | |
|                     Debug.Assert(lrNode != null);
 | |
|                     BitSet tempFollowPos = new BitSet(positionsCount);
 | |
|                     tempFollowPos.Clear();
 | |
|                     tempFollowPos.Or(followpos[i]); //Add the followpos of the range node
 | |
|                     if (lrNode.Min != lrNode.Max) { //If they are the same, then followpos cannot include the firstpos
 | |
|                         tempFollowPos.Or(lrNode.NextIteration); //Add the nextIteration of the range node (this is the firstpos of its parent's leftChild)
 | |
|                     }
 | |
| 
 | |
|                     //For each position in the bitset, if it is a outer range node (pos > i), then add its followpos as well to the current node's followpos
 | |
|                     for (int pos = tempFollowPos.NextSet(-1); pos != -1; pos = tempFollowPos.NextSet(pos)) {
 | |
|                         if (pos > i) {
 | |
|                             Position p1 = positions[pos];
 | |
|                             if (p1.symbol == -2) {
 | |
|                                 LeafRangeNode lrNode1 = p1.particle as LeafRangeNode;
 | |
|                                 Debug.Assert(lrNode1 != null);
 | |
|                                 tempFollowPos.Or(minmaxFollowPos[lrNode1.Pos]);
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
|                     //set the followpos built to the index in the BitSet[]
 | |
|                     minmaxFollowPos[localMinMaxNodesCount] = tempFollowPos; 
 | |
|                     lrNode.Pos = localMinMaxNodesCount++; 
 | |
|                     posWithRangeTerminals.Set(i);
 | |
|                 }
 | |
|             }
 | |
|             return minmaxFollowPos;
 | |
|         }
 | |
| 
 | |
|         private void CheckCMUPAWithLeafRangeNodes(BitSet curpos) {
 | |
|             object[] symbolMatches = new object[symbols.Count];
 | |
|             for (int pos = curpos.NextSet(-1); pos != -1; pos = curpos.NextSet(pos)) {
 | |
|                 Position currentPosition = positions[pos];
 | |
|                 int symbol = currentPosition.symbol;
 | |
|                 if (symbol >= 0) { //its not a range position
 | |
|                     if (symbolMatches[symbol] != null) {
 | |
|                         throw new UpaException(symbolMatches[symbol], currentPosition.particle);
 | |
|                     }
 | |
|                     else {
 | |
|                         symbolMatches[symbol] = currentPosition.particle;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         //For each position, this method calculates the additional follows of any range nodes that need to be added to its followpos
 | |
|         //((ab?)2-4)c, Followpos of a is b as well as that of node R(2-4) = c
 | |
|         private BitSet GetApplicableMinMaxFollowPos(BitSet curpos, BitSet posWithRangeTerminals, BitSet[] minmaxFollowPos) {
 | |
|             if (curpos.Intersects(posWithRangeTerminals)) {
 | |
|                 BitSet newSet = new BitSet(positions.Count); //Doing work again 
 | |
|                 newSet.Or(curpos);
 | |
|                 newSet.And(posWithRangeTerminals);
 | |
|                 curpos = curpos.Clone();
 | |
|                 for (int pos = newSet.NextSet(-1); pos != -1; pos = newSet.NextSet(pos)) {
 | |
|                     LeafRangeNode lrNode = positions[pos].particle as LeafRangeNode;
 | |
|                     curpos.Or(minmaxFollowPos[lrNode.Pos]);
 | |
|                 }
 | |
|             }
 | |
|             return curpos;
 | |
|         }
 | |
| 
 | |
|         private void CheckUniqueParticleAttribution(BitSet firstpos, BitSet[] followpos) {
 | |
|             CheckUniqueParticleAttribution(firstpos);
 | |
|             for (int i = 0; i < positions.Count; i++) {
 | |
|                 CheckUniqueParticleAttribution(followpos[i]);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private void CheckUniqueParticleAttribution(BitSet curpos) {
 | |
|             // particles will be attributed uniquely if the same symbol never poins to two different ones
 | |
|             object[] particles = new object[symbols.Count]; 
 | |
|             for (int pos = curpos.NextSet(-1); pos != -1; pos = curpos.NextSet(pos)) {
 | |
|                 // if position can follow
 | |
|                 int symbol = positions[pos].symbol;
 | |
|                 if (particles[symbol] == null) {
 | |
|                     // set particle for the symbol
 | |
|                     particles[symbol] = positions[pos].particle;
 | |
|                 }
 | |
|                 else if (particles[symbol] != positions[pos].particle) {
 | |
|                     throw new UpaException(particles[symbol], positions[pos].particle);
 | |
|                 }
 | |
|                 // two different position point to the same symbol and particle - that's OK
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Algorithm 3.5 Construction of a DFA from a regular expression
 | |
|         /// </summary>
 | |
|         private int[][] BuildTransitionTable(BitSet firstpos, BitSet[] followpos, int endMarkerPos) {
 | |
|             const int TimeConstant = 8192; //(MaxStates * MaxPositions should be a constant) 
 | |
|             int positionsCount = positions.Count;
 | |
|             int MaxStatesCount = TimeConstant / positionsCount;
 | |
|             int symbolsCount = symbols.Count;
 | |
|             
 | |
|             // transition table (Dtran in the book)
 | |
|             ArrayList transitionTable = new ArrayList();
 | |
|             
 | |
|             // state lookup table (Dstate in the book)
 | |
|             Hashtable stateTable = new Hashtable();
 | |
|             
 | |
|             // Add empty set that would signal an error
 | |
|             stateTable.Add(new BitSet(positionsCount), -1);
 | |
| 
 | |
|             // lists unmarked states
 | |
|             Queue unmarked = new Queue();
 | |
| 
 | |
|             // initially, the only unmarked state in Dstates is firstpo(root) 
 | |
|             int state = 0;
 | |
|             unmarked.Enqueue(firstpos);
 | |
|             stateTable.Add(firstpos, 0);
 | |
|             transitionTable.Add(new int[symbolsCount + 1]);
 | |
| 
 | |
|             // while there is an umnarked state T in Dstates do begin
 | |
|             while (unmarked.Count > 0) {
 | |
|                 BitSet statePosSet = (BitSet)unmarked.Dequeue(); // all positions that constitute DFA state 
 | |
|                 Debug.Assert(state == (int)stateTable[statePosSet]); // just make sure that statePosSet is for correct state
 | |
|                 int[] transition = (int[])transitionTable[state];
 | |
|                 if (statePosSet[endMarkerPos]) {
 | |
|                     transition[symbolsCount] = 1;   // accepting
 | |
|                 }
 | |
| 
 | |
|                 // for each input symbol a do begin
 | |
|                 for (int symbol = 0; symbol < symbolsCount; symbol ++) {
 | |
|                     // let U be the set of positions that are in followpos(p)
 | |
|                     //       for some position p in T
 | |
|                     //       such that the symbol at position p is a
 | |
|                     BitSet newset = new BitSet(positionsCount);
 | |
|                     for (int pos = statePosSet.NextSet(-1); pos != -1; pos = statePosSet.NextSet(pos)) {
 | |
|                         if (symbol == positions[pos].symbol) {
 | |
|                             newset.Or(followpos[pos]);
 | |
|                         }
 | |
|                     }
 | |
| 
 | |
|                     // if U is not empty and is not in Dstates then
 | |
|                     //      add U as an unmarked state to Dstates
 | |
|                     object lookup = stateTable[newset];
 | |
|                     if (lookup != null) {
 | |
|                         transition[symbol] = (int)lookup;
 | |
|                     }
 | |
|                     else {
 | |
|                         // construct new state
 | |
|                         int newState = stateTable.Count - 1;
 | |
|                         if (newState >= MaxStatesCount) {
 | |
|                             return null;
 | |
|                         }
 | |
|                         unmarked.Enqueue(newset);
 | |
|                         stateTable.Add(newset, newState);
 | |
|                         transitionTable.Add(new int[symbolsCount + 1]);
 | |
|                         transition[symbol] = newState;
 | |
|                     }
 | |
|                 }
 | |
|                 state++;
 | |
|             }
 | |
|             // now convert transition table to array
 | |
|             return (int[][])transitionTable.ToArray(typeof(int[]));
 | |
|         }
 | |
| 
 | |
| #if DEBUG
 | |
|         private void Dump(StringBuilder bb, BitSet[] followpos, int[][] transitionTable) {
 | |
|             // Temporary printout
 | |
|             bb.AppendLine("Positions");
 | |
|             for (int i = 0; i < positions.Count; i ++) {
 | |
|                 bb.AppendLine(i + " " + positions[i].symbol.ToString(NumberFormatInfo.InvariantInfo) + " " + symbols.NameOf(positions[i].symbol));
 | |
|             }
 | |
|             bb.AppendLine("Followpos");
 | |
|             for (int i = 0; i < positions.Count; i++) {
 | |
|                 for (int j = 0; j < positions.Count; j++) {
 | |
|                     bb.Append(followpos[i][j] ? "X" : "O");
 | |
|                 }
 | |
|                bb.AppendLine();
 | |
|             }
 | |
|             if (transitionTable != null) {
 | |
|                 // Temporary printout
 | |
|                 bb.AppendLine("Transitions");
 | |
|                 for (int i = 0; i < transitionTable.Length; i++) {
 | |
|                     for (int j = 0; j < symbols.Count; j++) {
 | |
|                         if (transitionTable[i][j] == -1) {
 | |
|                             bb.Append("  x  ");
 | |
|                         }
 | |
|                         else {
 | |
|                             bb.AppendFormat(" {0:000} ", transitionTable[i][j]);
 | |
|                         }
 | |
|                     }
 | |
|                     bb.AppendLine(transitionTable[i][symbols.Count] == 1 ? "+" : "");
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| #endif
 | |
|     }
 | |
| 
 | |
|     /// <summary>
 | |
|     /// Deterministic Finite Automata
 | |
|     /// Compilers by Aho, Sethi, Ullman.
 | |
|     /// ISBN 0-201-10088-6, pp. 115, 116, 140 
 | |
|     /// </summary>
 | |
|     sealed class DfaContentValidator : ContentValidator {
 | |
|         int[][] transitionTable;
 | |
|         SymbolsDictionary symbols;
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Algorithm 3.5 Construction of a DFA from a regular expression
 | |
|         /// </summary>
 | |
|         internal DfaContentValidator(
 | |
|             int[][] transitionTable, SymbolsDictionary symbols,
 | |
|             XmlSchemaContentType contentType, bool isOpen, bool isEmptiable)  : base(contentType, isOpen, isEmptiable) {
 | |
|             this.transitionTable = transitionTable;
 | |
|             this.symbols = symbols;
 | |
|         }
 | |
| 
 | |
|         public override void InitValidation(ValidationState context) {
 | |
|             context.CurrentState.State = 0;
 | |
|             context.HasMatched = transitionTable[0][symbols.Count] > 0;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Algorithm 3.1 Simulating a DFA
 | |
|         /// </summary>
 | |
|         public override object ValidateElement(XmlQualifiedName name, ValidationState context, out int errorCode) {
 | |
|             int symbol = symbols[name];
 | |
|             int state = transitionTable[context.CurrentState.State][symbol];
 | |
|             errorCode = 0;
 | |
|             if (state != -1) {
 | |
|                 context.CurrentState.State = state;
 | |
|                 context.HasMatched = transitionTable[context.CurrentState.State][symbols.Count] > 0;
 | |
|                 return symbols.GetParticle(symbol); // OK
 | |
|             }
 | |
|             if (IsOpen && context.HasMatched) {
 | |
|                 // XDR allows any well-formed contents after matched.
 | |
|                 return null;
 | |
|             }
 | |
|             context.NeedValidateChildren = false;
 | |
|             errorCode = -1;
 | |
|             return null; // will never be here
 | |
|         }
 | |
| 
 | |
|         public override bool CompleteValidation(ValidationState context) {
 | |
|             if (!context.HasMatched) {
 | |
|                 return false;
 | |
|             }
 | |
|             return true;
 | |
|         }
 | |
| 
 | |
|         public override ArrayList ExpectedElements(ValidationState context, bool isRequiredOnly) {
 | |
|             ArrayList names = null;
 | |
|             int[] transition = transitionTable[context.CurrentState.State];
 | |
|             if (transition != null) {
 | |
|                 for (int i = 0; i < transition.Length - 1; i ++) {
 | |
|                     if (transition[i] != -1) {
 | |
|                         if (names == null) {
 | |
|                             names = new ArrayList();
 | |
|                         }
 | |
|                         XmlSchemaParticle p = (XmlSchemaParticle)symbols.GetParticle(i);
 | |
|                         if (p == null) {
 | |
|                             string s = symbols.NameOf(i);
 | |
|                             if (s.Length != 0) {
 | |
|                                 names.Add(s);
 | |
|                             }
 | |
|                         }
 | |
|                         else {
 | |
|                             string s = p.NameString;
 | |
|                             if (!names.Contains(s)) {
 | |
|                                 names.Add(s);
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             return names;
 | |
|         }
 | |
| 
 | |
|         public override ArrayList ExpectedParticles(ValidationState context, bool isRequiredOnly, XmlSchemaSet schemaSet) {
 | |
|             ArrayList particles = new ArrayList();
 | |
|             int[] transition = transitionTable[context.CurrentState.State];
 | |
|             if (transition != null) {
 | |
|                 for (int i = 0; i < transition.Length - 1; i ++) {
 | |
|                     if (transition[i] != -1) {
 | |
|                         XmlSchemaParticle p = (XmlSchemaParticle)symbols.GetParticle(i);
 | |
|                         if (p == null) {
 | |
|                             continue;
 | |
|                         }
 | |
|                         AddParticleToExpected(p, schemaSet, particles);
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             return particles;
 | |
|         }        
 | |
|     }
 | |
| 
 | |
|     /// <summary>
 | |
|     /// Nondeterministic Finite Automata
 | |
|     /// Compilers by Aho, Sethi, Ullman.
 | |
|     /// ISBN 0-201-10088-6, pp. 126,140 
 | |
|     /// </summary>
 | |
|     sealed class NfaContentValidator : ContentValidator {
 | |
|         BitSet firstpos;
 | |
|         BitSet[] followpos;
 | |
|         SymbolsDictionary symbols;
 | |
|         Positions positions;
 | |
|         int endMarkerPos;
 | |
| 
 | |
|         internal NfaContentValidator(
 | |
|             BitSet firstpos, BitSet[] followpos, SymbolsDictionary symbols, Positions positions, int endMarkerPos,
 | |
|             XmlSchemaContentType contentType, bool isOpen, bool isEmptiable)  : base(contentType, isOpen, isEmptiable) {
 | |
|             this.firstpos = firstpos;
 | |
|             this.followpos = followpos;
 | |
|             this.symbols = symbols;
 | |
|             this.positions = positions;
 | |
|             this.endMarkerPos = endMarkerPos;
 | |
|         }
 | |
| 
 | |
|         public override void InitValidation(ValidationState context) {
 | |
|             context.CurPos[0] = firstpos.Clone();
 | |
|             context.CurPos[1] = new BitSet(firstpos.Count);
 | |
|             context.CurrentState.CurPosIndex = 0;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Algorithm 3.4 Simulation of an NFA
 | |
|         /// </summary>
 | |
|         public override object ValidateElement(XmlQualifiedName name, ValidationState context, out int errorCode) {
 | |
|             BitSet curpos = context.CurPos[context.CurrentState.CurPosIndex];
 | |
|             int next = (context.CurrentState.CurPosIndex + 1) % 2;
 | |
|             BitSet nextpos = context.CurPos[next];
 | |
|             nextpos.Clear();
 | |
|             int symbol = symbols[name];
 | |
|             object particle = null;
 | |
|             errorCode = 0;
 | |
|             for (int pos = curpos.NextSet(-1); pos != -1; pos = curpos.NextSet(pos)) {
 | |
|                 // if position can follow
 | |
|                 if (symbol == positions[pos].symbol) {
 | |
|                     nextpos.Or(followpos[pos]);
 | |
|                     particle = positions[pos].particle; //Between element and wildcard, element will be in earlier pos than wildcard since we add the element nodes to the list of positions first
 | |
|                     break;                              // and then ExpandTree for the namespace nodes which adds the wildcards to the positions list
 | |
|                 }
 | |
|             }
 | |
|             if (!nextpos.IsEmpty) {
 | |
|                 context.CurrentState.CurPosIndex = next;
 | |
|                 return particle;
 | |
|             }
 | |
|             if (IsOpen && curpos[endMarkerPos]) {
 | |
|                 // XDR allows any well-formed contents after matched.
 | |
|                 return null;
 | |
|             }
 | |
|             context.NeedValidateChildren = false;
 | |
|             errorCode = -1;
 | |
|             return null; // will never be here
 | |
| 
 | |
|         }
 | |
| 
 | |
| #if FINDUPA_PARTICLE
 | |
|         private bool FindUPAParticle(ref object originalParticle, object newParticle) {
 | |
|             if (originalParticle == null) { 
 | |
|                 originalParticle = newParticle;
 | |
|                 if (originalParticle is XmlSchemaElement) { //if the first particle is element, then break, otherwise try to find an element
 | |
|                     return true;
 | |
|                 }
 | |
|             }
 | |
|             else if (newParticle is XmlSchemaElement) {
 | |
|                 if (originalParticle is XmlSchemaAny) { //Weak wildcards, element takes precendence over any
 | |
|                     originalParticle = newParticle;
 | |
|                     return true;
 | |
|                 }
 | |
|             }
 | |
|             return false;
 | |
|         }
 | |
| #endif
 | |
| 
 | |
|         public override bool CompleteValidation(ValidationState context) {
 | |
|             if (!context.CurPos[context.CurrentState.CurPosIndex][endMarkerPos]) {
 | |
|                 return false;
 | |
|             }
 | |
|             return true;
 | |
|         }
 | |
| 
 | |
|         public override ArrayList ExpectedElements(ValidationState context, bool isRequiredOnly) {
 | |
|             ArrayList names = null;
 | |
|             BitSet curpos = context.CurPos[context.CurrentState.CurPosIndex];
 | |
|             for (int pos = curpos.NextSet(-1); pos != -1; pos = curpos.NextSet(pos)) {
 | |
|                 if (names == null) {
 | |
|                     names = new ArrayList();
 | |
|                 }
 | |
|                 XmlSchemaParticle p = (XmlSchemaParticle)positions[pos].particle;
 | |
|                 if (p == null) {
 | |
|                     string s = symbols.NameOf(positions[pos].symbol);
 | |
|                     if (s.Length != 0) {
 | |
|                         names.Add(s);
 | |
|                     }
 | |
|                 }
 | |
|                 else {
 | |
|                     string s = p.NameString;
 | |
|                     if (!names.Contains(s)) {
 | |
|                         names.Add(s);
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             return names;
 | |
|         }
 | |
| 
 | |
|         public override ArrayList ExpectedParticles(ValidationState context, bool isRequiredOnly, XmlSchemaSet schemaSet) {
 | |
|             ArrayList particles = new ArrayList();
 | |
|             BitSet curpos = context.CurPos[context.CurrentState.CurPosIndex];
 | |
|             for (int pos = curpos.NextSet(-1); pos != -1; pos = curpos.NextSet(pos)) {
 | |
|                 XmlSchemaParticle p = (XmlSchemaParticle)positions[pos].particle;
 | |
|                 if (p == null) {
 | |
|                     continue;
 | |
|                 }
 | |
|                 else {
 | |
|                     AddParticleToExpected(p, schemaSet, particles);
 | |
|                 }
 | |
|             }
 | |
|             return particles;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     internal struct RangePositionInfo {
 | |
|         public BitSet curpos;            
 | |
|         public decimal[] rangeCounters;
 | |
|     }
 | |
|     
 | |
|     sealed class RangeContentValidator : ContentValidator {
 | |
|         BitSet firstpos;
 | |
|         BitSet[] followpos;
 | |
|         BitSet positionsWithRangeTerminals;
 | |
|         SymbolsDictionary symbols;
 | |
|         Positions positions;
 | |
|         int minMaxNodesCount;    
 | |
|         int endMarkerPos;
 | |
| 
 | |
|         internal RangeContentValidator(
 | |
|             BitSet firstpos, BitSet[] followpos, SymbolsDictionary symbols, Positions positions, int endMarkerPos, XmlSchemaContentType contentType, bool isEmptiable, BitSet positionsWithRangeTerminals, int minmaxNodesCount)  : base(contentType, false, isEmptiable) {
 | |
|             this.firstpos = firstpos;
 | |
|             this.followpos = followpos;
 | |
|             this.symbols = symbols;
 | |
|             this.positions = positions;
 | |
|             this.positionsWithRangeTerminals = positionsWithRangeTerminals;
 | |
|             this.minMaxNodesCount = minmaxNodesCount;
 | |
|             this.endMarkerPos = endMarkerPos;
 | |
|         }
 | |
| 
 | |
|         public override void InitValidation(ValidationState context) {
 | |
|             int positionsCount = positions.Count;
 | |
|             List<RangePositionInfo> runningPositions = context.RunningPositions;
 | |
|             if (runningPositions != null) {
 | |
|                 Debug.Assert(minMaxNodesCount != 0);
 | |
|                 runningPositions.Clear();
 | |
|             }
 | |
|             else {
 | |
|                 runningPositions = new List<RangePositionInfo>();
 | |
|                 context.RunningPositions = runningPositions;
 | |
|             }
 | |
|             RangePositionInfo rposInfo = new RangePositionInfo();
 | |
|             rposInfo.curpos = firstpos.Clone();
 | |
| 
 | |
|             rposInfo.rangeCounters = new decimal[minMaxNodesCount];
 | |
|             runningPositions.Add(rposInfo);
 | |
|             context.CurrentState.NumberOfRunningPos = 1;
 | |
|             context.HasMatched = rposInfo.curpos.Get(endMarkerPos);
 | |
|         }
 | |
| 
 | |
|         public override object ValidateElement(XmlQualifiedName name, ValidationState context, out int errorCode) {
 | |
|             errorCode = 0;
 | |
|             int symbol = symbols[name];
 | |
|             bool hasSeenFinalPosition = false;
 | |
|             List<RangePositionInfo> runningPositions = context.RunningPositions;
 | |
|             int matchCount = context.CurrentState.NumberOfRunningPos;
 | |
|             int k = 0; 
 | |
|             RangePositionInfo rposInfo;
 | |
|             
 | |
|             int pos = -1;
 | |
|             int firstMatchedIndex = -1;
 | |
|             bool matched = false;
 | |
| 
 | |
| #if RANGE_DEBUG
 | |
|             WriteRunningPositions("Current running positions to match", runningPositions, name, matchCount);
 | |
| #endif
 | |
| 
 | |
|             while (k < matchCount) { //we are looking for the first match in the list of bitsets
 | |
|                 rposInfo = runningPositions[k];
 | |
|                 BitSet curpos = rposInfo.curpos;
 | |
|                 for (int matchpos = curpos.NextSet(-1); matchpos != -1; matchpos = curpos.NextSet(matchpos)) { //In all sets, have to scan all positions because of Disabled UPA possibility
 | |
|                     if (symbol == positions[matchpos].symbol) {
 | |
|                         pos = matchpos; 
 | |
|                         if (firstMatchedIndex == -1) { // get the first match for this symbol
 | |
|                             firstMatchedIndex = k;
 | |
|                         }
 | |
|                         matched = true;
 | |
|                         break;
 | |
|                     }
 | |
|                 }
 | |
|                 if (matched && positions[pos].particle is XmlSchemaElement) { //We found a match in the list, break at that bitset
 | |
|                     break;
 | |
|                 }
 | |
|                 else {
 | |
|                     k++;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             if (k == matchCount && pos != -1) { // we did find a match but that was any and hence continued ahead for element
 | |
|                 k = firstMatchedIndex;
 | |
|             }
 | |
|             if (k < matchCount) { //There is a match
 | |
|                 if (k != 0) { //If the first bitset itself matched, then no need to remove anything
 | |
| #if RANGE_DEBUG
 | |
|                     WriteRunningPositions("Removing unmatched entries till the first match", runningPositions, XmlQualifiedName.Empty, k);
 | |
| #endif
 | |
|                     runningPositions.RemoveRange(0, k); //Delete entries from 0 to k-1
 | |
|                 }
 | |
|                 matchCount = matchCount - k;
 | |
|                 k = 0; // Since we re-sized the array
 | |
|                 while (k < matchCount) {
 | |
|                     rposInfo = runningPositions[k];
 | |
|                     matched = rposInfo.curpos.Get(pos); //Look for the bitset that matches the same position as pos
 | |
|                     if (matched) { //If match found, get the follow positions of the current matched position
 | |
| #if RANGE_DEBUG
 | |
|                         Debug.WriteIf(DiagnosticsSwitches.XmlSchemaContentModel.Enabled, "Matched position: " + pos + " "); SequenceNode.WriteBitSet(rposInfo.curpos);
 | |
|                         Debug.WriteIf(DiagnosticsSwitches.XmlSchemaContentModel.Enabled, "Follow pos of Matched position: "); SequenceNode.WriteBitSet(followpos[pos]);
 | |
| #endif
 | |
|                         rposInfo.curpos = followpos[pos]; //Note that we are copying the same counters of the current position to that of the follow position
 | |
|                         runningPositions[k] = rposInfo; 
 | |
|                         k++;
 | |
|                     }
 | |
|                     else { //Clear the current pos and get another position from the list to start matching
 | |
|                         matchCount--;
 | |
|                         if (matchCount > 0) {
 | |
|                             RangePositionInfo lastrpos = runningPositions[matchCount];
 | |
|                             runningPositions[matchCount] = runningPositions[k];
 | |
|                             runningPositions[k] = lastrpos;
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             else { //There is no match
 | |
|                 matchCount = 0;
 | |
|             }
 | |
| 
 | |
|             if (matchCount > 0) {
 | |
|                 Debug.Assert(minMaxNodesCount > 0);
 | |
|                 if (matchCount >= 10000) {
 | |
|                     context.TooComplex = true;
 | |
|                     matchCount /= 2;
 | |
|                 }
 | |
| #if RANGE_DEBUG
 | |
|                 WriteRunningPositions("Matched positions to expand ", runningPositions, name, matchCount);
 | |
| #endif
 | |
| 
 | |
|                 for (k = matchCount - 1; k >= 0; k--) { 
 | |
|                     int j = k;
 | |
|                     BitSet currentRunningPosition = runningPositions[k].curpos;
 | |
|                     hasSeenFinalPosition = hasSeenFinalPosition || currentRunningPosition.Get(endMarkerPos); //Accepting position reached if the current position BitSet contains the endPosition
 | |
|                     while (matchCount < 10000 && currentRunningPosition.Intersects(positionsWithRangeTerminals)) {
 | |
|                         //Now might add 2 more positions to followpos 
 | |
|                         //1. nextIteration of the rangeNode, which is firstpos of its parent's leftChild
 | |
|                         //2. Followpos of the range node
 | |
| 
 | |
|                         BitSet countingPosition = currentRunningPosition.Clone();
 | |
|                         countingPosition.And(positionsWithRangeTerminals);
 | |
|                         int cPos = countingPosition.NextSet(-1); //Get the first position where leaf range node appears
 | |
|                         LeafRangeNode lrNode = positions[cPos].particle as LeafRangeNode; //For a position with leaf range node, the particle is the node itself
 | |
|                         Debug.Assert(lrNode != null);
 | |
| 
 | |
|                         rposInfo = runningPositions[j];
 | |
|                         if (matchCount + 2 >= runningPositions.Count) {
 | |
|                             runningPositions.Add(new RangePositionInfo());
 | |
|                             runningPositions.Add(new RangePositionInfo());
 | |
|                         }
 | |
|                         RangePositionInfo newRPosInfo = runningPositions[matchCount];
 | |
|                         if (newRPosInfo.rangeCounters == null) {
 | |
|                             newRPosInfo.rangeCounters = new decimal[minMaxNodesCount];
 | |
|                         }
 | |
|                         Array.Copy(rposInfo.rangeCounters, 0, newRPosInfo.rangeCounters, 0, rposInfo.rangeCounters.Length);
 | |
|                         decimal count = ++newRPosInfo.rangeCounters[lrNode.Pos];
 | |
| 
 | |
|                         if (count == lrNode.Max) {
 | |
|                             newRPosInfo.curpos = followpos[cPos]; //since max has been reached, Get followposition of range node
 | |
|                             newRPosInfo.rangeCounters[lrNode.Pos] = 0; //reset counter
 | |
|                             runningPositions[matchCount] = newRPosInfo;
 | |
|                             j = matchCount++;
 | |
|                         }
 | |
|                         else if (count < lrNode.Min) {
 | |
|                             newRPosInfo.curpos = lrNode.NextIteration;
 | |
|                             runningPositions[matchCount] = newRPosInfo;
 | |
|                             matchCount++;
 | |
|                             break;
 | |
|                         }
 | |
|                         else { // min <= count < max
 | |
|                             newRPosInfo.curpos = lrNode.NextIteration; //set currentpos to firstpos of node which has the range
 | |
|                             runningPositions[matchCount] = newRPosInfo;
 | |
|                             j = matchCount + 1;
 | |
|                             newRPosInfo = runningPositions[j];
 | |
|                             if (newRPosInfo.rangeCounters == null) {
 | |
|                                 newRPosInfo.rangeCounters = new decimal[minMaxNodesCount];
 | |
|                             }
 | |
|                             Array.Copy(rposInfo.rangeCounters, 0, newRPosInfo.rangeCounters, 0, rposInfo.rangeCounters.Length);
 | |
|                             newRPosInfo.curpos = followpos[cPos];
 | |
|                             newRPosInfo.rangeCounters[lrNode.Pos] = 0;
 | |
|                             runningPositions[j] = newRPosInfo;
 | |
|                             matchCount += 2;
 | |
|                         }
 | |
|                         currentRunningPosition = runningPositions[j].curpos;
 | |
|                         hasSeenFinalPosition = hasSeenFinalPosition || currentRunningPosition.Get(endMarkerPos);
 | |
|                     }
 | |
|                 }
 | |
|                 context.HasMatched = hasSeenFinalPosition;
 | |
|                 context.CurrentState.NumberOfRunningPos = matchCount;
 | |
|                 return positions[pos].particle;
 | |
|             } //matchcount > 0
 | |
|             errorCode = -1;
 | |
|             context.NeedValidateChildren = false;
 | |
|             return null;
 | |
|         }
 | |
| 
 | |
| #if RANGE_DEBUG
 | |
|         private void WriteRunningPositions(string text, List<RangePositionInfo> runningPositions, XmlQualifiedName name, int length) {
 | |
|             int counter = 0;
 | |
|             Debug.WriteLineIf(DiagnosticsSwitches.XmlSchemaContentModel.Enabled, "");
 | |
|             Debug.WriteLineIf(DiagnosticsSwitches.XmlSchemaContentModel.Enabled, "");
 | |
|             Debug.WriteLineIf(DiagnosticsSwitches.XmlSchemaContentModel.Enabled, text + name.Name);
 | |
|             while (counter < length) {
 | |
|                 BitSet curpos = runningPositions[counter].curpos;
 | |
|                 SequenceNode.WriteBitSet(curpos);
 | |
|                 for(int rcnt = 0; rcnt < runningPositions[counter].rangeCounters.Length; rcnt++) {
 | |
|                     Debug.WriteIf(DiagnosticsSwitches.XmlSchemaContentModel.Enabled, "RangeCounter[" + rcnt + "]" + runningPositions[counter].rangeCounters[rcnt] + " ");                    
 | |
|                 }
 | |
|                 Debug.WriteLineIf(DiagnosticsSwitches.XmlSchemaContentModel.Enabled, "");
 | |
|                 Debug.WriteLineIf(DiagnosticsSwitches.XmlSchemaContentModel.Enabled, "");
 | |
|                 counter++;
 | |
|             }
 | |
|         }
 | |
| #endif
 | |
|         public override bool CompleteValidation(ValidationState context) {
 | |
|             return context.HasMatched;
 | |
|         }
 | |
| 
 | |
|         public override ArrayList ExpectedElements(ValidationState context, bool isRequiredOnly) {
 | |
|             ArrayList names = null;
 | |
|             BitSet expectedPos;
 | |
|             if (context.RunningPositions != null) {
 | |
|                 List<RangePositionInfo> runningPositions = context.RunningPositions;
 | |
|                 expectedPos = new BitSet(positions.Count);
 | |
|                 for (int i = context.CurrentState.NumberOfRunningPos - 1; i >=0; i--) {
 | |
|                     Debug.Assert(runningPositions[i].curpos != null);
 | |
|                     expectedPos.Or(runningPositions[i].curpos);
 | |
|                 }
 | |
|                 for (int pos = expectedPos.NextSet(-1); pos != -1; pos = expectedPos.NextSet(pos)) {
 | |
|                     if (names == null) {
 | |
|                         names = new ArrayList();
 | |
|                     }
 | |
|                     int symbol = positions[pos].symbol;
 | |
|                     if (symbol >= 0) { //non range nodes
 | |
|                         XmlSchemaParticle p = positions[pos].particle as XmlSchemaParticle;
 | |
|                         if (p == null) {
 | |
|                             string s = symbols.NameOf(positions[pos].symbol);
 | |
|                             if (s.Length != 0) {
 | |
|                                 names.Add(s);
 | |
|                             }
 | |
|                         }
 | |
|                         else {
 | |
|                             string s = p.NameString;
 | |
|                             if (!names.Contains(s)) {
 | |
|                                 names.Add(s);
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             return names;
 | |
|         }
 | |
| 
 | |
|         public override ArrayList ExpectedParticles(ValidationState context, bool isRequiredOnly, XmlSchemaSet schemaSet) {
 | |
|             ArrayList particles = new ArrayList();
 | |
|             BitSet expectedPos;
 | |
|             if (context.RunningPositions != null) {
 | |
|                 List<RangePositionInfo> runningPositions = context.RunningPositions;
 | |
|                 expectedPos = new BitSet(positions.Count);
 | |
|                 for (int i = context.CurrentState.NumberOfRunningPos - 1; i >=0; i--) { 
 | |
|                     Debug.Assert(runningPositions[i].curpos != null);
 | |
|                     expectedPos.Or(runningPositions[i].curpos);
 | |
|                 }
 | |
|                 for (int pos = expectedPos.NextSet(-1); pos != -1; pos = expectedPos.NextSet(pos)) {
 | |
|                     int symbol = positions[pos].symbol;
 | |
|                     if (symbol >= 0) { //non range nodes
 | |
|                         XmlSchemaParticle p = positions[pos].particle as XmlSchemaParticle;
 | |
|                         if (p == null) {
 | |
|                            continue;
 | |
|                         }
 | |
|                         AddParticleToExpected(p, schemaSet, particles);
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             return particles;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     sealed class AllElementsContentValidator : ContentValidator {
 | |
|         Hashtable elements;     // unique terminal names to positions in Bitset mapping
 | |
|         object[] particles;
 | |
|         BitSet isRequired;      // required flags
 | |
|         int countRequired = 0;
 | |
| 
 | |
|         public AllElementsContentValidator(XmlSchemaContentType contentType, int size, bool isEmptiable) : base(contentType, false, isEmptiable) {
 | |
|             elements = new Hashtable(size);
 | |
|             particles = new object[size];
 | |
|             isRequired = new BitSet(size);
 | |
|         }
 | |
| 
 | |
|         public bool AddElement(XmlQualifiedName name, object particle, bool isEmptiable) {
 | |
|             if (elements[name] != null) {
 | |
|                 return false;
 | |
|             }
 | |
|             int i = elements.Count;
 | |
|             elements.Add(name, i);
 | |
|             particles[i] = particle;
 | |
|             if (!isEmptiable) {
 | |
|                 isRequired.Set(i);
 | |
|                 countRequired ++;
 | |
|             }
 | |
|             return true;
 | |
|         }
 | |
| 
 | |
|         public override bool IsEmptiable { 
 | |
|             get { return base.IsEmptiable || countRequired == 0; }
 | |
|         }
 | |
| 
 | |
|         public override void InitValidation(ValidationState context) {
 | |
|             Debug.Assert(elements.Count > 0);
 | |
|             context.AllElementsSet = new BitSet(elements.Count); //
 | |
|             context.CurrentState.AllElementsRequired = -1; // no elements at all
 | |
|         }
 | |
| 
 | |
|         public override object ValidateElement(XmlQualifiedName name, ValidationState context, out int errorCode) {
 | |
|             object lookup = elements[name];
 | |
|             errorCode = 0;
 | |
|             if (lookup == null) {
 | |
|                 context.NeedValidateChildren = false;
 | |
|                 return null;
 | |
|             }
 | |
|             int index = (int)lookup;
 | |
|             if (context.AllElementsSet[index]) {
 | |
|                 errorCode = -2;
 | |
|                 return null;
 | |
|             }
 | |
|             if (context.CurrentState.AllElementsRequired == -1) {
 | |
|                 context.CurrentState.AllElementsRequired = 0;
 | |
|             }
 | |
|             context.AllElementsSet.Set(index);
 | |
|             if (isRequired[index]) {
 | |
|                 context.CurrentState.AllElementsRequired++;
 | |
|             }
 | |
|             return particles[index];
 | |
|         }
 | |
|  
 | |
|         public override bool CompleteValidation(ValidationState context) {
 | |
|             if (context.CurrentState.AllElementsRequired == countRequired || IsEmptiable && context.CurrentState.AllElementsRequired == -1) {
 | |
|                 return true;
 | |
|             }
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         public override ArrayList ExpectedElements(ValidationState context, bool isRequiredOnly) {
 | |
|             ArrayList names = null;
 | |
|             foreach (DictionaryEntry entry in elements) {
 | |
|                 if (!context.AllElementsSet[(int)entry.Value] && (!isRequiredOnly || isRequired[(int)entry.Value])) {
 | |
|                     if (names == null) {
 | |
|                         names = new ArrayList();
 | |
|                     }
 | |
|                     names.Add(entry.Key);
 | |
|                 }
 | |
|             }
 | |
|             return names;
 | |
|         }
 | |
| 
 | |
|         public override ArrayList ExpectedParticles(ValidationState context, bool isRequiredOnly, XmlSchemaSet schemaSet) {
 | |
|             ArrayList expectedParticles = new ArrayList();
 | |
|             foreach (DictionaryEntry entry in elements) {
 | |
|                 if (!context.AllElementsSet[(int)entry.Value] && (!isRequiredOnly || isRequired[(int)entry.Value])) {
 | |
|                     AddParticleToExpected(this.particles[(int)entry.Value] as XmlSchemaParticle, schemaSet, expectedParticles);
 | |
|                 }
 | |
|             }
 | |
|             return expectedParticles;
 | |
|         }
 | |
|     }
 | |
|     #endregion
 | |
| }
 |