The Labs \ Source Viewer \ SSCLI \ System.Xml.Schema \ RangeContentValidator

  1. //------------------------------------------------------------------------------
  2. // <copyright file="ContentValidator.cs" company="Microsoft">
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. // </copyright>
  14. //------------------------------------------------------------------------------
  15. using System;
  16. using System.Collections;
  17. using System.Collections.Generic;
  18. using System.Globalization;
  19. using System.Text;
  20. using System.Diagnostics;
  21. namespace System.Xml.Schema
  22. {
  23.    
  24.     #region ExceptionSymbolsPositions
  25.    
  26.     /// <summary>
  27.     /// UPA violations will throw this exception
  28.     /// </summary>
  29.     class UpaException : Exception
  30.     {
  31.         object particle1;
  32.         object particle2;
  33.         public UpaException(object particle1, object particle2)
  34.         {
  35.             this.particle1 = particle1;
  36.             this.particle2 = particle2;
  37.         }
  38.         public object Particle1 {
  39.             get { return particle1; }
  40.         }
  41.         public object Particle2 {
  42.             get { return particle2; }
  43.         }
  44.     }
  45.    
  46.     /// <summary>
  47.     /// SymbolsDictionary is a map between names that ContextValidator recognizes and symbols - int symbol[XmlQualifiedName name].
  48.     /// There are two types of name - full names and wildcards (namespace is specified, local name is anythig).
  49.     /// Wildcard excludes all full names that would match by the namespace part.
  50.     /// SymbolsDictionry alwas recognizes all the symbols - the last one is a true wildcard -
  51.     /// both name and namespace can be anything that none of the other symbols matched.
  52.     /// </summary>
  53.     class SymbolsDictionary
  54.     {
  55.         int last = 0;
  56.         Hashtable names;
  57.         Hashtable wildcards = null;
  58.         ArrayList particles;
  59.         object particleLast = null;
  60.         bool isUpaEnforced = true;
  61.        
  62.         public SymbolsDictionary()
  63.         {
  64.             names = new Hashtable();
  65.             particles = new ArrayList();
  66.         }
  67.        
  68.         public int Count {
  69.             // last one is a "*:*" any wildcard
  70.             get { return last + 1; }
  71.         }
  72.        
  73.         public int CountOfNames {
  74.             get { return names.Count; }
  75.         }
  76.        
  77.         /// <summary>
  78.         /// True is particle can be deterministically attributed from the symbol and conversion to DFA is possible.
  79.         /// </summary>
  80.         public bool IsUpaEnforced {
  81.             get { return isUpaEnforced; }
  82.             set { isUpaEnforced = value; }
  83.         }
  84.        
  85.         /// <summary>
  86.         /// Add name and return it's number
  87.         /// </summary>
  88.         public int AddName(XmlQualifiedName name, object particle)
  89.         {
  90.             object lookup = names[name];
  91.             if (lookup != null) {
  92.                 int symbol = (int)lookup;
  93.                 if (particles[symbol] != particle) {
  94.                     isUpaEnforced = false;
  95.                 }
  96.                 return symbol;
  97.             }
  98.             else {
  99.                 names.Add(name, last);
  100.                 particles.Add(particle);
  101.                 Debug.Assert(particles.Count == last + 1);
  102.                 return last++;
  103.             }
  104.         }
  105.        
  106.         public void AddNamespaceList(NamespaceList list, object particle, bool allowLocal)
  107.         {
  108.             switch (list.Type) {
  109.                 case NamespaceList.ListType.Any:
  110.                     particleLast = particle;
  111.                     break;
  112.                 case NamespaceList.ListType.Other:
  113.                     // Create a symbol for the excluded namespace, but don't set a particle for it.
  114.                     AddWildcard(list.Excluded, null);
  115.                     if (!allowLocal) {
  116.                         AddWildcard(string.Empty, null);
  117.                         //##local is not allowed
  118.                     }
  119.                     break;
  120.                 case NamespaceList.ListType.Set:
  121.                     foreach (string wildcard in list.Enumerate) {
  122.                         AddWildcard(wildcard, particle);
  123.                     }
  124.                     break;
  125.             }
  126.         }
  127.        
  128.         private void AddWildcard(string wildcard, object particle)
  129.         {
  130.             if (wildcards == null) {
  131.                 wildcards = new Hashtable();
  132.             }
  133.             object lookup = wildcards[wildcard];
  134.             if (lookup == null) {
  135.                 wildcards.Add(wildcard, last);
  136.                 particles.Add(particle);
  137.                 Debug.Assert(particles.Count == last + 1);
  138.                 last++;
  139.             }
  140.             else if (particle != null) {
  141.                 particles[(int)lookup] = particle;
  142.             }
  143.         }
  144.        
  145.         public ICollection GetNamespaceListSymbols(NamespaceList list)
  146.         {
  147.             ArrayList match = new ArrayList();
  148.             foreach (XmlQualifiedName name in names.Keys) {
  149.                 if (name != XmlQualifiedName.Empty && list.Allows(name)) {
  150.                     match.Add(names[name]);
  151.                 }
  152.             }
  153.             if (wildcards != null) {
  154.                 foreach (string wildcard in wildcards.Keys) {
  155.                     if (list.Allows(wildcard)) {
  156.                         match.Add(wildcards[wildcard]);
  157.                     }
  158.                 }
  159.             }
  160.             if (list.Type == NamespaceList.ListType.Any || list.Type == NamespaceList.ListType.Other) {
  161.                 match.Add(last);
  162.                 // add wildcard
  163.             }
  164.             return match;
  165.         }
  166.        
  167.         /// <summary>
  168.         /// Find the symbol for the given name. If neither names nor wilcards match it last (*.*) symbol will be returned
  169.         /// </summary>
  170.         public int this[XmlQualifiedName name]
  171.         {
  172.             get {
  173.                 object lookup = names[name];
  174.                 if (lookup != null) {
  175.                     return (int)lookup;
  176.                 }
  177.                 if (wildcards != null) {
  178.                     lookup = wildcards[name.Namespace];
  179.                     if (lookup != null) {
  180.                         return (int)lookup;
  181.                     }
  182.                 }
  183.                 return last;
  184.                 // true wildcard
  185.             }
  186.         }
  187.        
  188.         /// <summary>
  189.         /// Check if a name exists in the symbol dictionary
  190.         /// </summary>
  191.         public bool Exists(XmlQualifiedName name)
  192.         {
  193.            
  194.             object lookup = names[name];
  195.             if (lookup != null) {
  196.                 return true;
  197.             }
  198.             return false;
  199.         }
  200.        
  201.         /// <summary>
  202.         /// Return content processing mode for the symbol
  203.         /// </summary>
  204.         public object GetParticle(int symbol)
  205.         {
  206.             return symbol == last ? particleLast : particles[symbol];
  207.         }
  208.        
  209.         /// <summary>
  210.         /// Output symbol's name
  211.         /// </summary>
  212.         public string NameOf(int symbol)
  213.         {
  214.             foreach (DictionaryEntry de in names) {
  215.                 if ((int)de.Value == symbol) {
  216.                     return ((XmlQualifiedName)de.Key).ToString();
  217.                 }
  218.             }
  219.             if (wildcards != null) {
  220.                 foreach (DictionaryEntry de in wildcards) {
  221.                     if ((int)de.Value == symbol) {
  222.                         return (string)de.Key + ":*";
  223.                     }
  224.                 }
  225.             }
  226.             return "##other:*";
  227.         }
  228.     }
  229.    
  230.     struct Position
  231.     {
  232.         public int symbol;
  233.         public object particle;
  234.         public Position(int symbol, object particle)
  235.         {
  236.             this.symbol = symbol;
  237.             this.particle = particle;
  238.         }
  239.     }
  240.    
  241.     class Positions
  242.     {
  243.         ArrayList positions = new ArrayList();
  244.        
  245.         public int Add(int symbol, object particle)
  246.         {
  247.             return positions.Add(new Position(symbol, particle));
  248.         }
  249.        
  250.         public Position this[int pos]
  251.         {
  252.             get { return (Position)positions[pos]; }
  253.         }
  254.        
  255.         public int Count {
  256.             get { return positions.Count; }
  257.         }
  258.     }
  259.     #endregion
  260.    
  261.     #region SystaxTree
  262.     /// <summary>
  263.     /// Base class for the systax tree nodes
  264.     /// </summary>
  265.     abstract class SyntaxTreeNode
  266.     {
  267.         /// <summary>
  268.         /// Expand NamesapceListNode and RangeNode nodes. All other nodes
  269.         /// </summary>
  270.         public abstract void ExpandTree(InteriorNode parent, SymbolsDictionary symbols, Positions positions);
  271.        
  272.         /// <summary>
  273.         /// Clone the syntaxTree. We need to pass symbolsByPosition because leaf nodes have to add themselves to it.
  274.         /// </summary>
  275.         public abstract SyntaxTreeNode Clone(Positions positions);
  276.        
  277.         /// <summary>
  278.         /// From a regular expression to a DFA
  279.         /// Compilers by Aho, Sethi, Ullman.
  280.         /// ISBN 0-201-10088-6, p135
  281.         /// Construct firstpos, lastpos and calculate followpos
  282.         /// </summary>
  283.         public abstract void ConstructPos(BitSet firstpos, BitSet lastpos, BitSet[] followpos);
  284.        
  285.         /// <summary>
  286.         /// Returns nullable property that is being used by ConstructPos
  287.         /// </summary>
  288.         public abstract bool IsNullable {
  289.             get;
  290.         }
  291.        
  292.         /// <summary>
  293.         /// Returns true if node is a range node
  294.         /// </summary>
  295.         public virtual bool IsRangeNode {
  296.             get { return false; }
  297.         }
  298.        
  299.         /// <summary>
  300.         /// Print syntax tree
  301.         /// </summary>
  302.         #if DEBUG
  303.         public abstract void Dump(StringBuilder bb, SymbolsDictionary symbols, Positions positions);
  304.         #endif
  305.     }
  306.    
  307.     /// <summary>
  308.     /// Terminal of the syntax tree
  309.     /// </summary>
  310.     class LeafNode : SyntaxTreeNode
  311.     {
  312.         int pos;
  313.        
  314.         public LeafNode(int pos)
  315.         {
  316.             this.pos = pos;
  317.         }
  318.        
  319.         public int Pos {
  320.             get { return pos; }
  321.             set { pos = value; }
  322.         }
  323.        
  324.         public override void ExpandTree(InteriorNode parent, SymbolsDictionary symbols, Positions positions)
  325.         {
  326.             // do nothing
  327.         }
  328.        
  329.         public override SyntaxTreeNode Clone(Positions positions)
  330.         {
  331.             return new LeafNode(positions.Add(positions[pos].symbol, positions[pos].particle));
  332.         }
  333.        
  334.         public override void ConstructPos(BitSet firstpos, BitSet lastpos, BitSet[] followpos)
  335.         {
  336.             firstpos.Set(pos);
  337.             lastpos.Set(pos);
  338.         }
  339.        
  340.         public override bool IsNullable {
  341.             get { return false; }
  342.         }
  343.        
  344.         #if DEBUG
  345.         public override void Dump(StringBuilder bb, SymbolsDictionary symbols, Positions positions)
  346.         {
  347.             bb.Append("\"" + symbols.NameOf(positions[pos].symbol) + "\"");
  348.         }
  349.         #endif
  350.     }
  351.    
  352.     /// <summary>
  353.     /// Temporary node to represent NamespaceList. Will be expended as a choice of symbols
  354.     /// </summary>
  355.     class NamespaceListNode : SyntaxTreeNode
  356.     {
  357.         protected NamespaceList namespaceList;
  358.         protected object particle;
  359.        
  360.         public NamespaceListNode(NamespaceList namespaceList, object particle)
  361.         {
  362.             this.namespaceList = namespaceList;
  363.             this.particle = particle;
  364.         }
  365.        
  366.         public override SyntaxTreeNode Clone(Positions positions)
  367.         {
  368.             // NamespaceListNode nodes have to be removed prior to that
  369.             throw new InvalidOperationException();
  370.         }
  371.        
  372.         public virtual ICollection GetResolvedSymbols(SymbolsDictionary symbols)
  373.         {
  374.             return symbols.GetNamespaceListSymbols(namespaceList);
  375.         }
  376.        
  377.         public override void ExpandTree(InteriorNode parent, SymbolsDictionary symbols, Positions positions)
  378.         {
  379.             SyntaxTreeNode replacementNode = null;
  380.             foreach (int symbol in GetResolvedSymbols(symbols)) {
  381.                 if (symbols.GetParticle(symbol) != particle) {
  382.                     symbols.IsUpaEnforced = false;
  383.                 }
  384.                 LeafNode node = new LeafNode(positions.Add(symbol, particle));
  385.                 if (replacementNode == null) {
  386.                     replacementNode = node;
  387.                 }
  388.                 else {
  389.                     InteriorNode choice = new ChoiceNode();
  390.                     choice.LeftChild = replacementNode;
  391.                     choice.RightChild = node;
  392.                     replacementNode = choice;
  393.                 }
  394.             }
  395.             if (parent.LeftChild == this) {
  396.                 parent.LeftChild = replacementNode;
  397.             }
  398.             else {
  399.                 parent.RightChild = replacementNode;
  400.             }
  401.         }
  402.        
  403.         public override void ConstructPos(BitSet firstpos, BitSet lastpos, BitSet[] followpos)
  404.         {
  405.             // NamespaceListNode nodes have to be removed prior to that
  406.             throw new InvalidOperationException();
  407.         }
  408.        
  409.         public override bool IsNullable {
  410.             // NamespaceListNode nodes have to be removed prior to that
  411.             get {
  412.                 throw new InvalidOperationException();
  413.             }
  414.         }
  415.        
  416.         #if DEBUG
  417.         public override void Dump(StringBuilder bb, SymbolsDictionary symbols, Positions positions)
  418.         {
  419.             bb.Append("[" + namespaceList.ToString() + "]");
  420.         }
  421.         #endif
  422.     }
  423.    
  424.     /// <summary>
  425.     /// Base class for all internal node. Note that only sequence and choice have right child
  426.     /// </summary>
  427.     abstract class InteriorNode : SyntaxTreeNode
  428.     {
  429.         SyntaxTreeNode leftChild;
  430.         SyntaxTreeNode rightChild;
  431.        
  432.         public SyntaxTreeNode LeftChild {
  433.             get { return leftChild; }
  434.             set { leftChild = value; }
  435.         }
  436.        
  437.         public SyntaxTreeNode RightChild {
  438.             get { return rightChild; }
  439.             set { rightChild = value; }
  440.         }
  441.        
  442.         public override SyntaxTreeNode Clone(Positions positions)
  443.         {
  444.             InteriorNode other = (InteriorNode)this.MemberwiseClone();
  445.             other.LeftChild = leftChild.Clone(positions);
  446.             if (rightChild != null) {
  447.                 other.RightChild = rightChild.Clone(positions);
  448.             }
  449.             return other;
  450.         }
  451.        
  452.         public override void ExpandTree(InteriorNode parent, SymbolsDictionary symbols, Positions positions)
  453.         {
  454.             leftChild.ExpandTree(this, symbols, positions);
  455.             if (rightChild != null) {
  456.                 rightChild.ExpandTree(this, symbols, positions);
  457.             }
  458.         }
  459.     }
  460.    
  461.     sealed class SequenceNode : InteriorNode
  462.     {
  463.         public override void ConstructPos(BitSet firstpos, BitSet lastpos, BitSet[] followpos)
  464.         {
  465.             BitSet lastposLeft = new BitSet(lastpos.Count);
  466.             LeftChild.ConstructPos(firstpos, lastposLeft, followpos);
  467.            
  468.             BitSet firstposRight = new BitSet(firstpos.Count);
  469.             RightChild.ConstructPos(firstposRight, lastpos, followpos);
  470.            
  471.             if (LeftChild.IsNullable && !RightChild.IsRangeNode) {
  472.                 firstpos.Or(firstposRight);
  473.             }
  474.             if (RightChild.IsNullable) {
  475.                 lastpos.Or(lastposLeft);
  476.             }
  477.             for (int pos = lastposLeft.NextSet(-1); pos != -1; pos = lastposLeft.NextSet(pos)) {
  478.                 followpos[pos].Or(firstposRight);
  479.             }
  480.             if (RightChild.IsRangeNode) {
  481.                 //firstpos is leftchild.firstpos as the or with firstposRight has not been done as it is a rangenode
  482.                 ((LeafRangeNode)RightChild).NextIteration = firstpos.Clone();
  483.             }
  484.         }
  485.        
  486.         public override bool IsNullable {
  487.             get { return (LeftChild.IsNullable && (RightChild.IsNullable || RightChild.IsRangeNode)) || (RightChild.IsRangeNode && ((LeafRangeNode)RightChild).Min == 0); }
  488.         }
  489.        
  490.         #if DEBUG
  491.         static internal void WritePos(BitSet firstpos, BitSet lastpos, BitSet[] followpos)
  492.         {
  493.             Debug.WriteLineIf(DiagnosticsSwitches.XmlSchemaContentModel.Enabled, "FirstPos: ");
  494.             WriteBitSet(firstpos);
  495.            
  496.             Debug.WriteLineIf(DiagnosticsSwitches.XmlSchemaContentModel.Enabled, "LastPos: ");
  497.             WriteBitSet(lastpos);
  498.            
  499.             Debug.WriteLineIf(DiagnosticsSwitches.XmlSchemaContentModel.Enabled, "Followpos: ");
  500.             for (int i = 0; i < followpos.Length; i++) {
  501.                 WriteBitSet(followpos[i]);
  502.             }
  503.         }
  504.         static internal void WriteBitSet(BitSet curpos)
  505.         {
  506.             int[] list = new int[curpos.Count];
  507.             for (int pos = curpos.NextSet(-1); pos != -1; pos = curpos.NextSet(pos)) {
  508.                 list[pos] = 1;
  509.             }
  510.             for (int i = 0; i < list.Length; i++) {
  511.                 Debug.WriteIf(DiagnosticsSwitches.XmlSchemaContentModel.Enabled, list[i] + " ");
  512.             }
  513.             Debug.WriteLineIf(DiagnosticsSwitches.XmlSchemaContentModel.Enabled, "");
  514.         }
  515.        
  516.        
  517.         public override void Dump(StringBuilder bb, SymbolsDictionary symbols, Positions positions)
  518.         {
  519.             bb.Append("(");
  520.             LeftChild.Dump(bb, symbols, positions);
  521.             bb.Append(", ");
  522.             RightChild.Dump(bb, symbols, positions);
  523.             bb.Append(")");
  524.         }
  525.         #endif
  526.     }
  527.    
  528.     sealed class ChoiceNode : InteriorNode
  529.     {
  530.         public override void ConstructPos(BitSet firstpos, BitSet lastpos, BitSet[] followpos)
  531.         {
  532.             LeftChild.ConstructPos(firstpos, lastpos, followpos);
  533.            
  534.             BitSet firstposRight = new BitSet(firstpos.Count);
  535.             BitSet lastposRight = new BitSet(lastpos.Count);
  536.             RightChild.ConstructPos(firstposRight, lastposRight, followpos);
  537.            
  538.             firstpos.Or(firstposRight);
  539.             lastpos.Or(lastposRight);
  540.         }
  541.        
  542.         public override bool IsNullable {
  543.             get { return LeftChild.IsNullable || RightChild.IsNullable; }
  544.         }
  545.        
  546.         #if DEBUG
  547.         public override void Dump(StringBuilder bb, SymbolsDictionary symbols, Positions positions)
  548.         {
  549.             bb.Append("(");
  550.             LeftChild.Dump(bb, symbols, positions);
  551.             bb.Append(" | ");
  552.             RightChild.Dump(bb, symbols, positions);
  553.             bb.Append(")");
  554.         }
  555.         #endif
  556.     }
  557.    
  558.     sealed class PlusNode : InteriorNode
  559.     {
  560.         public override void ConstructPos(BitSet firstpos, BitSet lastpos, BitSet[] followpos)
  561.         {
  562.             LeftChild.ConstructPos(firstpos, lastpos, followpos);
  563.             for (int pos = lastpos.NextSet(-1); pos != -1; pos = lastpos.NextSet(pos)) {
  564.                 followpos[pos].Or(firstpos);
  565.             }
  566.         }
  567.        
  568.         public override bool IsNullable {
  569.             get { return LeftChild.IsNullable; }
  570.         }
  571.        
  572.         #if DEBUG
  573.         public override void Dump(StringBuilder bb, SymbolsDictionary symbols, Positions positions)
  574.         {
  575.             LeftChild.Dump(bb, symbols, positions);
  576.             bb.Append("+");
  577.         }
  578.         #endif
  579.     }
  580.    
  581.     sealed class QmarkNode : InteriorNode
  582.     {
  583.         public override void ConstructPos(BitSet firstpos, BitSet lastpos, BitSet[] followpos)
  584.         {
  585.             LeftChild.ConstructPos(firstpos, lastpos, followpos);
  586.         }
  587.        
  588.         public override bool IsNullable {
  589.             get { return true; }
  590.         }
  591.        
  592.         #if DEBUG
  593.         public override void Dump(StringBuilder bb, SymbolsDictionary symbols, Positions positions)
  594.         {
  595.             LeftChild.Dump(bb, symbols, positions);
  596.             bb.Append("?");
  597.         }
  598.         #endif
  599.     }
  600.    
  601.     sealed class StarNode : InteriorNode
  602.     {
  603.         public override void ConstructPos(BitSet firstpos, BitSet lastpos, BitSet[] followpos)
  604.         {
  605.             LeftChild.ConstructPos(firstpos, lastpos, followpos);
  606.             for (int pos = lastpos.NextSet(-1); pos != -1; pos = lastpos.NextSet(pos)) {
  607.                 followpos[pos].Or(firstpos);
  608.             }
  609.         }
  610.        
  611.         public override bool IsNullable {
  612.             get { return true; }
  613.         }
  614.        
  615.         #if DEBUG
  616.         public override void Dump(StringBuilder bb, SymbolsDictionary symbols, Positions positions)
  617.         {
  618.             LeftChild.Dump(bb, symbols, positions);
  619.             bb.Append("*");
  620.         }
  621.         #endif
  622.     }
  623.    
  624.    
  625.    
  626.     /// <summary>
  627.     /// Using range node as one of the terminals
  628.     /// </summary>
  629.     sealed class LeafRangeNode : LeafNode
  630.     {
  631.         decimal min;
  632.         decimal max;
  633.         BitSet nextIteration;
  634.        
  635.         public LeafRangeNode(decimal min, decimal max) : this(-1, min, max)
  636.         {
  637.         }
  638.        
  639.         public LeafRangeNode(int pos, decimal min, decimal max) : base(pos)
  640.         {
  641.             this.min = min;
  642.             this.max = max;
  643.         }
  644.        
  645.         public decimal Max {
  646.             get { return max; }
  647.         }
  648.        
  649.         public decimal Min {
  650.             get { return min; }
  651.         }
  652.        
  653.         public BitSet NextIteration {
  654.             get { return nextIteration; }
  655.             set { nextIteration = value; }
  656.         }
  657.        
  658.         public override SyntaxTreeNode Clone(Positions positions)
  659.         {
  660.             return new LeafRangeNode(this.Pos, this.min, this.max);
  661.         }
  662.        
  663.         public override bool IsRangeNode {
  664.             get { return true; }
  665.         }
  666.     }
  667.    
  668.     #endregion
  669.    
  670.     #region ContentValidator
  671.     /// <summary>
  672.     /// Basic ContentValidator
  673.     /// </summary>
  674.     class ContentValidator
  675.     {
  676.         XmlSchemaContentType contentType;
  677.         bool isOpen;
  678.         //For XDR Content Models or ANY
  679.         bool isEmptiable;
  680.        
  681.         public static readonly ContentValidator Empty = new ContentValidator(XmlSchemaContentType.Empty);
  682.         public static readonly ContentValidator TextOnly = new ContentValidator(XmlSchemaContentType.TextOnly, false, false);
  683.         public static readonly ContentValidator Mixed = new ContentValidator(XmlSchemaContentType.Mixed);
  684.         public static readonly ContentValidator Any = new ContentValidator(XmlSchemaContentType.Mixed, true, true);
  685.        
  686.         public ContentValidator(XmlSchemaContentType contentType)
  687.         {
  688.             this.contentType = contentType;
  689.             this.isEmptiable = true;
  690.         }
  691.        
  692.         protected ContentValidator(XmlSchemaContentType contentType, bool isOpen, bool isEmptiable)
  693.         {
  694.             this.contentType = contentType;
  695.             this.isOpen = isOpen;
  696.             this.isEmptiable = isEmptiable;
  697.         }
  698.        
  699.         public XmlSchemaContentType ContentType {
  700.             get { return contentType; }
  701.         }
  702.        
  703.         public bool PreserveWhitespace {
  704.             get { return contentType == XmlSchemaContentType.TextOnly || contentType == XmlSchemaContentType.Mixed; }
  705.         }
  706.        
  707.         public virtual bool IsEmptiable {
  708.             get { return isEmptiable; }
  709.         }
  710.        
  711.         public bool IsOpen {
  712.             get {
  713.                 if (contentType == XmlSchemaContentType.TextOnly || contentType == XmlSchemaContentType.Empty)
  714.                     return false;
  715.                 else
  716.                     return isOpen;
  717.             }
  718.             set { isOpen = value; }
  719.         }
  720.        
  721.         public virtual void InitValidation(ValidationState context)
  722.         {
  723.             // do nothin'
  724.         }
  725.        
  726.         public virtual object ValidateElement(XmlQualifiedName name, ValidationState context, out int errorCode)
  727.         {
  728.             if (contentType == XmlSchemaContentType.TextOnly || contentType == XmlSchemaContentType.Empty) {
  729.                 //Cannot have elements in TextOnly or Empty content
  730.                 context.NeedValidateChildren = false;
  731.             }
  732.             errorCode = -1;
  733.             return null;
  734.         }
  735.        
  736.         public virtual bool CompleteValidation(ValidationState context)
  737.         {
  738.             return true;
  739.         }
  740.        
  741.         public virtual ArrayList ExpectedElements(ValidationState context, bool isRequiredOnly)
  742.         {
  743.             return null;
  744.         }
  745.        
  746.         public virtual ArrayList ExpectedParticles(ValidationState context, bool isRequiredOnly)
  747.         {
  748.             return null;
  749.         }
  750.     }
  751.    
  752.     sealed class ParticleContentValidator : ContentValidator
  753.     {
  754.         SymbolsDictionary symbols;
  755.         Positions positions;
  756.         Stack stack;
  757.         // parsing context
  758.         SyntaxTreeNode contentNode;
  759.         // content model points to syntax tree
  760.         bool isPartial;
  761.         // whether the closure applies to partial or the whole node that is on top of the stack
  762.         int minMaxNodesCount;
  763.         bool enableUpaCheck;
  764.        
  765.         public ParticleContentValidator(XmlSchemaContentType contentType) : this(contentType, true)
  766.         {
  767.         }
  768.        
  769.         public ParticleContentValidator(XmlSchemaContentType contentType, bool enableUpaCheck) : base(contentType)
  770.         {
  771.             this.enableUpaCheck = enableUpaCheck;
  772.         }
  773.        
  774.         public override void InitValidation(ValidationState context)
  775.         {
  776.             // ParticleContentValidator cannot be used during validation
  777.             throw new InvalidOperationException();
  778.         }
  779.        
  780.         public override object ValidateElement(XmlQualifiedName name, ValidationState context, out int errorCode)
  781.         {
  782.             // ParticleContentValidator cannot be used during validation
  783.             throw new InvalidOperationException();
  784.         }
  785.        
  786.         public override bool CompleteValidation(ValidationState context)
  787.         {
  788.             // ParticleContentValidator cannot be used during validation
  789.             throw new InvalidOperationException();
  790.         }
  791.        
  792.         public void Start()
  793.         {
  794.             symbols = new SymbolsDictionary();
  795.             positions = new Positions();
  796.             stack = new Stack();
  797.         }
  798.        
  799.         public void OpenGroup()
  800.         {
  801.             stack.Push(null);
  802.         }
  803.        
  804.         public void CloseGroup()
  805.         {
  806.             SyntaxTreeNode node = (SyntaxTreeNode)stack.Pop();
  807.             if (node == null) {
  808.                 return;
  809.             }
  810.             if (stack.Count == 0) {
  811.                 contentNode = node;
  812.                 isPartial = false;
  813.             }
  814.             else {
  815.                 // some collapsing to do...
  816.                 InteriorNode inNode = (InteriorNode)stack.Pop();
  817.                 if (inNode != null) {
  818.                     inNode.RightChild = node;
  819.                     node = inNode;
  820.                     isPartial = true;
  821.                 }
  822.                 else {
  823.                     isPartial = false;
  824.                 }
  825.                 stack.Push(node);
  826.             }
  827.         }
  828.        
  829.         public bool Exists(XmlQualifiedName name)
  830.         {
  831.             if (symbols.Exists(name)) {
  832.                 return true;
  833.             }
  834.             return false;
  835.         }
  836.        
  837.         public void AddName(XmlQualifiedName name, object particle)
  838.         {
  839.             AddLeafNode(new LeafNode(positions.Add(symbols.AddName(name, particle), particle)));
  840.         }
  841.        
  842.         public void AddNamespaceList(NamespaceList namespaceList, object particle)
  843.         {
  844.             symbols.AddNamespaceList(namespaceList, particle, false);
  845.             AddLeafNode(new NamespaceListNode(namespaceList, particle));
  846.         }
  847.        
  848.         private void AddLeafNode(SyntaxTreeNode node)
  849.         {
  850.             if (stack.Count > 0) {
  851.                 InteriorNode inNode = (InteriorNode)stack.Pop();
  852.                 if (inNode != null) {
  853.                     inNode.RightChild = node;
  854.                     node = inNode;
  855.                 }
  856.             }
  857.             stack.Push(node);
  858.             isPartial = true;
  859.         }
  860.        
  861.         public void AddChoice()
  862.         {
  863.             SyntaxTreeNode node = (SyntaxTreeNode)stack.Pop();
  864.             InteriorNode choice = new ChoiceNode();
  865.             choice.LeftChild = node;
  866.             stack.Push(choice);
  867.         }
  868.        
  869.         public void AddSequence()
  870.         {
  871.             SyntaxTreeNode node = (SyntaxTreeNode)stack.Pop();
  872.             InteriorNode sequence = new SequenceNode();
  873.             sequence.LeftChild = node;
  874.             stack.Push(sequence);
  875.         }
  876.        
  877.         public void AddStar()
  878.         {
  879.             Closure(new StarNode());
  880.         }
  881.        
  882.         public void AddPlus()
  883.         {
  884.             Closure(new PlusNode());
  885.         }
  886.        
  887.         public void AddQMark()
  888.         {
  889.             Closure(new QmarkNode());
  890.         }
  891.        
  892.         public void AddLeafRange(decimal min, decimal max)
  893.         {
  894.             LeafRangeNode rNode = new LeafRangeNode(min, max);
  895.             int pos = positions.Add(-2, rNode);
  896.             rNode.Pos = pos;
  897.            
  898.             InteriorNode sequence = new SequenceNode();
  899.             sequence.RightChild = rNode;
  900.             Closure(sequence);
  901.             minMaxNodesCount++;
  902.         }
  903.        
  904.         private void Closure(InteriorNode node)
  905.         {
  906.             if (stack.Count > 0) {
  907.                 SyntaxTreeNode topNode = (SyntaxTreeNode)stack.Pop();
  908.                 InteriorNode inNode = topNode as InteriorNode;
  909.                 if (isPartial && inNode != null) {
  910.                     // need to reach in and wrap right hand side of element.
  911.                     // and n remains the same.
  912.                     node.LeftChild = inNode.RightChild;
  913.                     inNode.RightChild = node;
  914.                 }
  915.                 else {
  916.                     // wrap terminal or any node
  917.                     node.LeftChild = topNode;
  918.                     topNode = node;
  919.                 }
  920.                 stack.Push(topNode);
  921.             }
  922.             else if (contentNode != null) {
  923.                 //If there is content to wrap
  924.                 // wrap whole content
  925.                 node.LeftChild = contentNode;
  926.                 contentNode = node;
  927.             }
  928.         }
  929.        
  930.         public ContentValidator Finish()
  931.         {
  932.             return Finish(true);
  933.         }
  934.        
  935.         public ContentValidator Finish(bool useDFA)
  936.         {
  937.             Debug.Assert(ContentType == XmlSchemaContentType.ElementOnly || ContentType == XmlSchemaContentType.Mixed);
  938.             if (contentNode == null) {
  939.                 if (ContentType == XmlSchemaContentType.Mixed) {
  940.                     string ctype = IsOpen ? "Any" : "TextOnly";
  941.                     Debug.WriteLineIf(DiagnosticsSwitches.XmlSchemaContentModel.Enabled, "\t\t\tContentType: " + ctype);
  942.                     return IsOpen ? ContentValidator.Any : ContentValidator.TextOnly;
  943.                 }
  944.                 else {
  945.                     Debug.WriteLineIf(DiagnosticsSwitches.XmlSchemaContentModel.Enabled, "\t\t\tContent: EMPTY");
  946.                     Debug.Assert(!IsOpen);
  947.                     return ContentValidator.Empty;
  948.                 }
  949.             }
  950.            
  951.             #if DEBUG
  952.             StringBuilder bb = new StringBuilder();
  953.             contentNode.Dump(bb, symbols, positions);
  954.             Debug.WriteLineIf(DiagnosticsSwitches.XmlSchemaContentModel.Enabled, "\t\t\tContent : " + bb.ToString());
  955.             #endif
  956.            
  957.             // Add end marker
  958.             InteriorNode contentRoot = new SequenceNode();
  959.             contentRoot.LeftChild = contentNode;
  960.             LeafNode endMarker = new LeafNode(positions.Add(symbols.AddName(XmlQualifiedName.Empty, null), null));
  961.             contentRoot.RightChild = endMarker;
  962.            
  963.             // Eliminate NamespaceListNode(s) and RangeNode(s)
  964.             contentNode.ExpandTree(contentRoot, symbols, positions);
  965.            
  966.             #if DEBUG
  967.             bb = new StringBuilder();
  968.             contentRoot.LeftChild.Dump(bb, symbols, positions);
  969.             Debug.WriteLineIf(DiagnosticsSwitches.XmlSchemaContentModel.Enabled, "\t\t\tExpended: " + bb.ToString());
  970.             #endif
  971.            
  972.             // calculate followpos
  973.             int symbolsCount = symbols.Count;
  974.             int positionsCount = positions.Count;
  975.             BitSet firstpos = new BitSet(positionsCount);
  976.             BitSet lastpos = new BitSet(positionsCount);
  977.             BitSet[] followpos = new BitSet[positionsCount];
  978.             for (int i = 0; i < positionsCount; i++) {
  979.                 followpos[i] = new BitSet(positionsCount);
  980.             }
  981.             contentRoot.ConstructPos(firstpos, lastpos, followpos);
  982.             #if DEBUG
  983.             Debug.WriteLineIf(DiagnosticsSwitches.XmlSchemaContentModel.Enabled, "firstpos, lastpos, followpos");
  984.             SequenceNode.WritePos(firstpos, lastpos, followpos);
  985.             #endif
  986.             if (minMaxNodesCount > 0) {
  987.                 //If the tree has any terminal range nodes
  988.                 BitSet positionsWithRangeTerminals;
  989.                 BitSet[] minMaxFollowPos = CalculateTotalFollowposForRangeNodes(firstpos, followpos, out positionsWithRangeTerminals);
  990.                
  991.                 if (enableUpaCheck) {
  992.                     CheckCMUPAWithLeafRangeNodes(GetApplicableMinMaxFollowPos(firstpos, positionsWithRangeTerminals, minMaxFollowPos));
  993.                     for (int i = 0; i < positionsCount; i++) {
  994.                         CheckCMUPAWithLeafRangeNodes(GetApplicableMinMaxFollowPos(followpos[i], positionsWithRangeTerminals, minMaxFollowPos));
  995.                     }
  996.                 }
  997.                 return new RangeContentValidator(firstpos, followpos, symbols, positions, endMarker.Pos, this.ContentType, contentRoot.LeftChild.IsNullable, positionsWithRangeTerminals, minMaxNodesCount);
  998.             }
  999.             else {
  1000.                 int[][] transitionTable = null;
  1001.                 // if each symbol has unique particle we are golden
  1002.                 if (!symbols.IsUpaEnforced) {
  1003.                     if (enableUpaCheck) {
  1004.                         // multiple positions that match the same symbol have different particles, but they never follow the same position
  1005.                         CheckUniqueParticleAttribution(firstpos, followpos);
  1006.                     }
  1007.                 }
  1008.                 else if (useDFA) {
  1009.                     // Can return null if the number of states reaches higher than 8192 / positionsCount
  1010.                     transitionTable = BuildTransitionTable(firstpos, followpos, endMarker.Pos);
  1011.                 }
  1012.                 #if DEBUG
  1013.                 bb = new StringBuilder();
  1014.                 Dump(bb, followpos, transitionTable);
  1015.                 Debug.WriteLineIf(DiagnosticsSwitches.XmlSchemaContentModel.Enabled, bb.ToString());
  1016.                 #endif
  1017.                 if (transitionTable != null) {
  1018.                     return new DfaContentValidator(transitionTable, symbols, this.ContentType, this.IsOpen, contentRoot.LeftChild.IsNullable);
  1019.                 }
  1020.                 else {
  1021.                     return new NfaContentValidator(firstpos, followpos, symbols, positions, endMarker.Pos, this.ContentType, this.IsOpen, contentRoot.LeftChild.IsNullable);
  1022.                 }
  1023.             }
  1024.         }
  1025.        
  1026.         private BitSet[] CalculateTotalFollowposForRangeNodes(BitSet firstpos, BitSet[] followpos, out BitSet posWithRangeTerminals)
  1027.         {
  1028.             int positionsCount = positions.Count;
  1029.             //terminals
  1030.             posWithRangeTerminals = new BitSet(positionsCount);
  1031.            
  1032.             //Compute followpos for each range node
  1033.             //For any range node that is surrounded by an outer range node, its follow positions will include those of the outer range node
  1034.             BitSet[] minmaxFollowPos = new BitSet[minMaxNodesCount];
  1035.             int localMinMaxNodesCount = 0;
  1036.            
  1037.             for (int i = positionsCount - 1; i >= 0; i--) {
  1038.                 Position p = positions[i];
  1039.                 if (p.symbol == -2) {
  1040.                     //P is a LeafRangeNode
  1041.                     LeafRangeNode lrNode = p.particle as LeafRangeNode;
  1042.                     Debug.Assert(lrNode != null);
  1043.                     BitSet tempFollowPos = new BitSet(positionsCount);
  1044.                     tempFollowPos.Clear();
  1045.                     tempFollowPos.Or(followpos[i]);
  1046.                     //Add the followpos of the range node
  1047.                     if (lrNode.Min != lrNode.Max) {
  1048.                         //If they are the same, then followpos cannot include the firstpos
  1049.                         tempFollowPos.Or(lrNode.NextIteration);
  1050.                         //Add the nextIteration of the range node (this is the firstpos of its parent's leftChild)
  1051.                     }
  1052.                    
  1053.                     //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
  1054.                     for (int pos = tempFollowPos.NextSet(-1); pos != -1; pos = tempFollowPos.NextSet(pos)) {
  1055.                         if (pos > i) {
  1056.                             Position p1 = positions[pos];
  1057.                             if (p1.symbol == -2) {
  1058.                                 LeafRangeNode lrNode1 = p1.particle as LeafRangeNode;
  1059.                                 Debug.Assert(lrNode1 != null);
  1060.                                 tempFollowPos.Or(minmaxFollowPos[lrNode1.Pos]);
  1061.                             }
  1062.                         }
  1063.                     }
  1064.                     //set the followpos built to the index in the BitSet[]
  1065.                     minmaxFollowPos[localMinMaxNodesCount] = tempFollowPos;
  1066.                     lrNode.Pos = localMinMaxNodesCount++;
  1067.                     posWithRangeTerminals.Set(i);
  1068.                 }
  1069.             }
  1070.             return minmaxFollowPos;
  1071.         }
  1072.        
  1073.         private void CheckCMUPAWithLeafRangeNodes(BitSet curpos)
  1074.         {
  1075.             object[] symbolMatches = new object[symbols.Count];
  1076.             for (int pos = curpos.NextSet(-1); pos != -1; pos = curpos.NextSet(pos)) {
  1077.                 Position currentPosition = positions[pos];
  1078.                 int symbol = currentPosition.symbol;
  1079.                 if (symbol >= 0) {
  1080.                     //its not a range position
  1081.                     if (symbolMatches[symbol] != null) {
  1082.                         throw new UpaException(symbolMatches[symbol], currentPosition.particle);
  1083.                     }
  1084.                     else {
  1085.                         symbolMatches[symbol] = currentPosition.particle;
  1086.                     }
  1087.                 }
  1088.             }
  1089.         }
  1090.        
  1091.         //For each position, this method calculates the additional follows of any range nodes that need to be added to its followpos
  1092.         //((ab?)2-4)c, Followpos of a is b as well as that of node R(2-4) = c
  1093.         private BitSet GetApplicableMinMaxFollowPos(BitSet curpos, BitSet posWithRangeTerminals, BitSet[] minmaxFollowPos)
  1094.         {
  1095.             if (curpos.Intersects(posWithRangeTerminals)) {
  1096.                 BitSet newSet = new BitSet(positions.Count);
  1097.                 //Doing work again
  1098.                 newSet.Or(curpos);
  1099.                 newSet.And(posWithRangeTerminals);
  1100.                 curpos = curpos.Clone();
  1101.                 for (int pos = newSet.NextSet(-1); pos != -1; pos = newSet.NextSet(pos)) {
  1102.                     LeafRangeNode lrNode = positions[pos].particle as LeafRangeNode;
  1103.                     curpos.Or(minmaxFollowPos[lrNode.Pos]);
  1104.                 }
  1105.             }
  1106.             return curpos;
  1107.         }
  1108.        
  1109.         private void CheckUniqueParticleAttribution(BitSet firstpos, BitSet[] followpos)
  1110.         {
  1111.             CheckUniqueParticleAttribution(firstpos);
  1112.             for (int i = 0; i < positions.Count; i++) {
  1113.                 CheckUniqueParticleAttribution(followpos[i]);
  1114.             }
  1115.         }
  1116.        
  1117.         private void CheckUniqueParticleAttribution(BitSet curpos)
  1118.         {
  1119.             // particles will be attributed uniquely if the same symbol never poins to two different ones
  1120.             object[] particles = new object[symbols.Count];
  1121.             for (int pos = curpos.NextSet(-1); pos != -1; pos = curpos.NextSet(pos)) {
  1122.                 // if position can follow
  1123.                 int symbol = positions[pos].symbol;
  1124.                 if (particles[symbol] == null) {
  1125.                     // set particle for the symbol
  1126.                     particles[symbol] = positions[pos].particle;
  1127.                 }
  1128.                 else if (particles[symbol] != positions[pos].particle) {
  1129.                     throw new UpaException(particles[symbol], positions[pos].particle);
  1130.                 }
  1131.                 // two different position point to the same symbol and particle - that's OK
  1132.             }
  1133.         }
  1134.        
  1135.         /// <summary>
  1136.         /// Algorithm 3.5 Construction of a DFA from a regular expression
  1137.         /// </summary>
  1138.         private int[][] BuildTransitionTable(BitSet firstpos, BitSet[] followpos, int endMarkerPos)
  1139.         {
  1140.             const int TimeConstant = 8192;
  1141.             //(MaxStates * MaxPositions should be a constant)
  1142.             int positionsCount = positions.Count;
  1143.             int MaxStatesCount = TimeConstant / positionsCount;
  1144.             int symbolsCount = symbols.Count;
  1145.            
  1146.             // transition table (Dtran in the book)
  1147.             ArrayList transitionTable = new ArrayList();
  1148.            
  1149.             // state lookup table (Dstate in the book)
  1150.             Hashtable stateTable = new Hashtable();
  1151.            
  1152.             // Add empty set that would signal an error
  1153.             stateTable.Add(new BitSet(positionsCount), -1);
  1154.            
  1155.             // lists unmarked states
  1156.             Queue unmarked = new Queue();
  1157.            
  1158.             // initially, the only unmarked state in Dstates is firstpo(root)
  1159.             int state = 0;
  1160.             unmarked.Enqueue(firstpos);
  1161.             stateTable.Add(firstpos, 0);
  1162.             transitionTable.Add(new int[symbolsCount + 1]);
  1163.            
  1164.             // while there is an umnarked state T in Dstates do begin
  1165.             while (unmarked.Count > 0) {
  1166.                 BitSet statePosSet = (BitSet)unmarked.Dequeue();
  1167.                 // all positions that constitute DFA state
  1168.                 Debug.Assert(state == (int)stateTable[statePosSet]);
  1169.                 // just make sure that statePosSet is for correct state
  1170.                 int[] transition = (int[])transitionTable[state];
  1171.                 if (statePosSet[endMarkerPos]) {
  1172.                     transition[symbolsCount] = 1;
  1173.                     // accepting
  1174.                 }
  1175.                
  1176.                 // for each input symbol a do begin
  1177.                 for (int symbol = 0; symbol < symbolsCount; symbol++) {
  1178.                     // let U be the set of positions that are in followpos(p)
  1179.                     // for some position p in T
  1180.                     // such that the symbol at position p is a
  1181.                     BitSet newset = new BitSet(positionsCount);
  1182.                     for (int pos = statePosSet.NextSet(-1); pos != -1; pos = statePosSet.NextSet(pos)) {
  1183.                         if (symbol == positions[pos].symbol) {
  1184.                             newset.Or(followpos[pos]);
  1185.                         }
  1186.                     }
  1187.                    
  1188.                     // if U is not empty and is not in Dstates then
  1189.                     // add U as an unmarked state to Dstates
  1190.                     object lookup = stateTable[newset];
  1191.                     if (lookup != null) {
  1192.                         transition[symbol] = (int)lookup;
  1193.                     }
  1194.                     else {
  1195.                         // construct new state
  1196.                         int newState = stateTable.Count - 1;
  1197.                         if (newState >= MaxStatesCount) {
  1198.                             return null;
  1199.                         }
  1200.                         unmarked.Enqueue(newset);
  1201.                         stateTable.Add(newset, newState);
  1202.                         transitionTable.Add(new int[symbolsCount + 1]);
  1203.                         transition[symbol] = newState;
  1204.                     }
  1205.                 }
  1206.                 state++;
  1207.             }
  1208.             // now convert transition table to array
  1209.             return (int[][])transitionTable.ToArray(typeof(int[]));
  1210.         }
  1211.        
  1212.         #if DEBUG
  1213.         private void Dump(StringBuilder bb, BitSet[] followpos, int[][] transitionTable)
  1214.         {
  1215.             // Temporary printout
  1216.             bb.AppendLine("Positions");
  1217.             for (int i = 0; i < positions.Count; i++) {
  1218.                 bb.AppendLine(i + " " + positions[i].symbol.ToString(NumberFormatInfo.InvariantInfo) + " " + symbols.NameOf(positions[i].symbol));
  1219.             }
  1220.             bb.AppendLine("Followpos");
  1221.             for (int i = 0; i < positions.Count; i++) {
  1222.                 for (int j = 0; j < positions.Count; j++) {
  1223.                     bb.Append(followpos[i][j] ? "X" : "O");
  1224.                 }
  1225.                 bb.AppendLine();
  1226.             }
  1227.             if (transitionTable != null) {
  1228.                 // Temporary printout
  1229.                 bb.AppendLine("Transitions");
  1230.                 for (int i = 0; i < transitionTable.Length; i++) {
  1231.                     for (int j = 0; j < symbols.Count; j++) {
  1232.                         if (transitionTable[i][j] == -1) {
  1233.                             bb.Append(" x ");
  1234.                         }
  1235.                         else {
  1236.                             bb.AppendFormat(" {0:000} ", transitionTable[i][j]);
  1237.                         }
  1238.                     }
  1239.                     bb.AppendLine(transitionTable[i][symbols.Count] == 1 ? "+" : "");
  1240.                 }
  1241.             }
  1242.         }
  1243.         #endif
  1244.     }
  1245.    
  1246.     /// <summary>
  1247.     /// Deterministic Finite Automata
  1248.     /// Compilers by Aho, Sethi, Ullman.
  1249.     /// ISBN 0-201-10088-6, pp. 115, 116, 140
  1250.     /// </summary>
  1251.     sealed class DfaContentValidator : ContentValidator
  1252.     {
  1253.         int[][] transitionTable;
  1254.         SymbolsDictionary symbols;
  1255.        
  1256.         /// <summary>
  1257.         /// Algorithm 3.5 Construction of a DFA from a regular expression
  1258.         /// </summary>
  1259.         internal DfaContentValidator(int[][] transitionTable, SymbolsDictionary symbols, XmlSchemaContentType contentType, bool isOpen, bool isEmptiable) : base(contentType, isOpen, isEmptiable)
  1260.         {
  1261.             this.transitionTable = transitionTable;
  1262.             this.symbols = symbols;
  1263.         }
  1264.        
  1265.         public override void InitValidation(ValidationState context)
  1266.         {
  1267.             context.CurrentState.State = 0;
  1268.             context.HasMatched = transitionTable[0][symbols.Count] > 0;
  1269.         }
  1270.        
  1271.         /// <summary>
  1272.         /// Algorithm 3.1 Simulating a DFA
  1273.         /// </summary>
  1274.         public override object ValidateElement(XmlQualifiedName name, ValidationState context, out int errorCode)
  1275.         {
  1276.             int symbol = symbols[name];
  1277.             int state = transitionTable[context.CurrentState.State][symbol];
  1278.             errorCode = 0;
  1279.             if (state != -1) {
  1280.                 context.CurrentState.State = state;
  1281.                 context.HasMatched = transitionTable[context.CurrentState.State][symbols.Count] > 0;
  1282.                 return symbols.GetParticle(symbol);
  1283.                 // OK
  1284.             }
  1285.             if (IsOpen && context.HasMatched) {
  1286.                 // XDR allows any well-formed contents after matched.
  1287.                 return null;
  1288.             }
  1289.             context.NeedValidateChildren = false;
  1290.             errorCode = -1;
  1291.             return null;
  1292.             // will never be here
  1293.         }
  1294.        
  1295.         public override bool CompleteValidation(ValidationState context)
  1296.         {
  1297.             if (!context.HasMatched) {
  1298.                 return false;
  1299.             }
  1300.             return true;
  1301.         }
  1302.        
  1303.         public override ArrayList ExpectedElements(ValidationState context, bool isRequiredOnly)
  1304.         {
  1305.             ArrayList names = null;
  1306.             int[] transition = transitionTable[context.CurrentState.State];
  1307.             if (transition != null) {
  1308.                 for (int i = 0; i < transition.Length - 1; i++) {
  1309.                     if (transition[i] != -1) {
  1310.                         if (names == null) {
  1311.                             names = new ArrayList();
  1312.                         }
  1313.                         XmlSchemaParticle p = (XmlSchemaParticle)symbols.GetParticle(i);
  1314.                         if (p == null) {
  1315.                             string s = symbols.NameOf(i);
  1316.                             if (s.Length != 0) {
  1317.                                 names.Add(s);
  1318.                             }
  1319.                         }
  1320.                         else {
  1321.                             string s = p.NameString;
  1322.                             if (!names.Contains(s)) {
  1323.                                 names.Add(s);
  1324.                             }
  1325.                         }
  1326.                     }
  1327.                 }
  1328.             }
  1329.             return names;
  1330.         }
  1331.        
  1332.         public override ArrayList ExpectedParticles(ValidationState context, bool isRequiredOnly)
  1333.         {
  1334.             ArrayList particles = new ArrayList();
  1335.             int[] transition = transitionTable[context.CurrentState.State];
  1336.             if (transition != null) {
  1337.                 for (int i = 0; i < transition.Length - 1; i++) {
  1338.                     if (transition[i] != -1) {
  1339.                         XmlSchemaParticle p = (XmlSchemaParticle)symbols.GetParticle(i);
  1340.                         if (p == null) {
  1341.                             continue;
  1342.                         }
  1343.                         if (!particles.Contains(p)) {
  1344.                             particles.Add(p);
  1345.                         }
  1346.                     }
  1347.                 }
  1348.             }
  1349.             return particles;
  1350.         }
  1351.     }
  1352.    
  1353.     /// <summary>
  1354.     /// Nondeterministic Finite Automata
  1355.     /// Compilers by Aho, Sethi, Ullman.
  1356.     /// ISBN 0-201-10088-6, pp. 126,140
  1357.     /// </summary>
  1358.     sealed class NfaContentValidator : ContentValidator
  1359.     {
  1360.         BitSet firstpos;
  1361.         BitSet[] followpos;
  1362.         SymbolsDictionary symbols;
  1363.         Positions positions;
  1364.         int endMarkerPos;
  1365.        
  1366.         internal NfaContentValidator(BitSet firstpos, BitSet[] followpos, SymbolsDictionary symbols, Positions positions, int endMarkerPos, XmlSchemaContentType contentType, bool isOpen, bool isEmptiable) : base(contentType, isOpen, isEmptiable)
  1367.         {
  1368.             this.firstpos = firstpos;
  1369.             this.followpos = followpos;
  1370.             this.symbols = symbols;
  1371.             this.positions = positions;
  1372.             this.endMarkerPos = endMarkerPos;
  1373.         }
  1374.        
  1375.         public override void InitValidation(ValidationState context)
  1376.         {
  1377.             context.CurPos[0] = firstpos.Clone();
  1378.             context.CurPos[1] = new BitSet(firstpos.Count);
  1379.             context.CurrentState.CurPosIndex = 0;
  1380.         }
  1381.        
  1382.         /// <summary>
  1383.         /// Algorithm 3.4 Simulation of an NFA
  1384.         /// </summary>
  1385.         public override object ValidateElement(XmlQualifiedName name, ValidationState context, out int errorCode)
  1386.         {
  1387.             BitSet curpos = context.CurPos[context.CurrentState.CurPosIndex];
  1388.             int next = (context.CurrentState.CurPosIndex + 1) % 2;
  1389.             BitSet nextpos = context.CurPos[next];
  1390.             nextpos.Clear();
  1391.             int symbol = symbols[name];
  1392.             object particle = null;
  1393.             errorCode = 0;
  1394.             for (int pos = curpos.NextSet(-1); pos != -1; pos = curpos.NextSet(pos)) {
  1395.                 // if position can follow
  1396.                 if (symbol == positions[pos].symbol) {
  1397.                     nextpos.Or(followpos[pos]);
  1398.                     particle = positions[pos].particle;
  1399.                     //Between element and wildcard, element will be in earlier pos than wildcard since we add the element nodes to the list of positions first
  1400.                     break;
  1401.                     // and then ExpandTree for the namespace nodes which adds the wildcards to the positions list
  1402.                 }
  1403.             }
  1404.             if (!nextpos.IsEmpty) {
  1405.                 context.CurrentState.CurPosIndex = next;
  1406.                 return particle;
  1407.             }
  1408.             if (IsOpen && curpos[endMarkerPos]) {
  1409.                 // XDR allows any well-formed contents after matched.
  1410.                 return null;
  1411.             }
  1412.             context.NeedValidateChildren = false;
  1413.             errorCode = -1;
  1414.             return null;
  1415.             // will never be here
  1416.         }
  1417.        
  1418.        
  1419.         public override bool CompleteValidation(ValidationState context)
  1420.         {
  1421.             if (!context.CurPos[context.CurrentState.CurPosIndex][endMarkerPos]) {
  1422.                 return false;
  1423.             }
  1424.             return true;
  1425.         }
  1426.        
  1427.         public override ArrayList ExpectedElements(ValidationState context, bool isRequiredOnly)
  1428.         {
  1429.             ArrayList names = null;
  1430.             BitSet curpos = context.CurPos[context.CurrentState.CurPosIndex];
  1431.             for (int pos = curpos.NextSet(-1); pos != -1; pos = curpos.NextSet(pos)) {
  1432.                 if (names == null) {
  1433.                     names = new ArrayList();
  1434.                 }
  1435.                 XmlSchemaParticle p = (XmlSchemaParticle)positions[pos].particle;
  1436.                 if (p == null) {
  1437.                     string s = symbols.NameOf(positions[pos].symbol);
  1438.                     if (s.Length != 0) {
  1439.                         names.Add(s);
  1440.                     }
  1441.                 }
  1442.                 else {
  1443.                     string s = p.NameString;
  1444.                     if (!names.Contains(s)) {
  1445.                         names.Add(s);
  1446.                     }
  1447.                 }
  1448.             }
  1449.             return names;
  1450.         }
  1451.        
  1452.         public override ArrayList ExpectedParticles(ValidationState context, bool isRequiredOnly)
  1453.         {
  1454.             ArrayList particles = new ArrayList();
  1455.             BitSet curpos = context.CurPos[context.CurrentState.CurPosIndex];
  1456.             for (int pos = curpos.NextSet(-1); pos != -1; pos = curpos.NextSet(pos)) {
  1457.                 XmlSchemaParticle p = (XmlSchemaParticle)positions[pos].particle;
  1458.                 if (p == null) {
  1459.                     continue;
  1460.                 }
  1461.                 else {
  1462.                     if (!particles.Contains(p)) {
  1463.                         particles.Add(p);
  1464.                     }
  1465.                 }
  1466.             }
  1467.             return particles;
  1468.         }
  1469.     }
  1470.    
  1471.     internal struct RangePositionInfo
  1472.     {
  1473.         public BitSet curpos;
  1474.         public decimal[] rangeCounters;
  1475.     }
  1476.    
  1477.     sealed class RangeContentValidator : ContentValidator
  1478.     {
  1479.         BitSet firstpos;
  1480.         BitSet[] followpos;
  1481.         BitSet positionsWithRangeTerminals;
  1482.         SymbolsDictionary symbols;
  1483.         Positions positions;
  1484.         int minMaxNodesCount;
  1485.         int endMarkerPos;
  1486.        
  1487.         internal RangeContentValidator(BitSet firstpos, BitSet[] followpos, SymbolsDictionary symbols, Positions positions, int endMarkerPos, XmlSchemaContentType contentType, bool isEmptiable, BitSet positionsWithRangeTerminals, int minmaxNodesCount) : base(contentType, false, isEmptiable)
  1488.         {
  1489.             this.firstpos = firstpos;
  1490.             this.followpos = followpos;
  1491.             this.symbols = symbols;
  1492.             this.positions = positions;
  1493.             this.positionsWithRangeTerminals = positionsWithRangeTerminals;
  1494.             this.minMaxNodesCount = minmaxNodesCount;
  1495.             this.endMarkerPos = endMarkerPos;
  1496.         }
  1497.        
  1498.         public override void InitValidation(ValidationState context)
  1499.         {
  1500.             int positionsCount = positions.Count;
  1501.             List<RangePositionInfo> runningPositions = context.RunningPositions;
  1502.             if (runningPositions != null) {
  1503.                 Debug.Assert(minMaxNodesCount != 0);
  1504.                 runningPositions.Clear();
  1505.             }
  1506.             else {
  1507.                 runningPositions = new List<RangePositionInfo>();
  1508.                 context.RunningPositions = runningPositions;
  1509.             }
  1510.             RangePositionInfo rposInfo = new RangePositionInfo();
  1511.             rposInfo.curpos = firstpos.Clone();
  1512.            
  1513.             rposInfo.rangeCounters = new decimal[minMaxNodesCount];
  1514.             runningPositions.Add(rposInfo);
  1515.             context.CurrentState.NumberOfRunningPos = 1;
  1516.             context.HasMatched = rposInfo.curpos.Get(endMarkerPos);
  1517.         }
  1518.        
  1519.         public override object ValidateElement(XmlQualifiedName name, ValidationState context, out int errorCode)
  1520.         {
  1521.             errorCode = 0;
  1522.             int symbol = symbols[name];
  1523.             bool hasSeenFinalPosition = false;
  1524.             List<RangePositionInfo> runningPositions = context.RunningPositions;
  1525.             int matchCount = context.CurrentState.NumberOfRunningPos;
  1526.             int k = 0;
  1527.             RangePositionInfo rposInfo;
  1528.            
  1529.             int pos = -1;
  1530.             int firstMatchedIndex = -1;
  1531.             bool matched = false;
  1532.            
  1533.            
  1534.             while (k < matchCount) {
  1535.                 //we are looking for the first match in the list of bitsets
  1536.                 rposInfo = runningPositions[k];
  1537.                 BitSet curpos = rposInfo.curpos;
  1538.                 for (int matchpos = curpos.NextSet(-1); matchpos != -1; matchpos = curpos.NextSet(matchpos)) {
  1539.                     //In all sets, have to scan all positions because of Disabled UPA possibility
  1540.                     if (symbol == positions[matchpos].symbol) {
  1541.                         pos = matchpos;
  1542.                         if (firstMatchedIndex == -1) {
  1543.                             // get the first match for this symbol
  1544.                             firstMatchedIndex = k;
  1545.                         }
  1546.                         matched = true;
  1547.                         break;
  1548.                     }
  1549.                 }
  1550.                 if (matched && positions[pos].particle is XmlSchemaElement) {
  1551.                     //We found a match in the list, break at that bitset
  1552.                     break;
  1553.                 }
  1554.                 else {
  1555.                     k++;
  1556.                 }
  1557.             }
  1558.            
  1559.             if (k == matchCount && pos != -1) {
  1560.                 // we did find a match but that was any and hence continued ahead for element
  1561.                 k = firstMatchedIndex;
  1562.             }
  1563.             if (k < matchCount) {
  1564.                 //There is a match
  1565.                 if (k != 0) {
  1566.                     //If the first bitset itself matched, then no need to remove anything
  1567.                     runningPositions.RemoveRange(0, k);
  1568.                     //Delete entries from 0 to k-1
  1569.                 }
  1570.                 matchCount = matchCount - k;
  1571.                 k = 0;
  1572.                 // Since we re-sized the array
  1573.                 while (k < matchCount) {
  1574.                     rposInfo = runningPositions[k];
  1575.                     matched = rposInfo.curpos.Get(pos);
  1576.                     //Look for the bitset that matches the same position as pos
  1577.                     if (matched) {
  1578.                         //If match found, get the follow positions of the current matched position
  1579.                         rposInfo.curpos = followpos[pos];
  1580.                         //Note that we are copying the same counters of the current position to that of the follow position
  1581.                         runningPositions[k] = rposInfo;
  1582.                         k++;
  1583.                     }
  1584.                     else {
  1585.                         //Clear the current pos and get another position from the list to start matching
  1586.                         matchCount--;
  1587.                         if (matchCount > 0) {
  1588.                             RangePositionInfo lastrpos = runningPositions[matchCount];
  1589.                             runningPositions[matchCount] = runningPositions[k];
  1590.                             runningPositions[k] = lastrpos;
  1591.                         }
  1592.                     }
  1593.                 }
  1594.             }
  1595.             else {
  1596.                 //There is no match
  1597.                 matchCount = 0;
  1598.             }
  1599.            
  1600.             if (matchCount > 0) {
  1601.                 Debug.Assert(minMaxNodesCount > 0);
  1602.                 if (matchCount >= 10000) {
  1603.                     context.TooComplex = true;
  1604.                     matchCount /= 2;
  1605.                 }
  1606.                
  1607.                 for (k = matchCount - 1; k >= 0; k--) {
  1608.                     int j = k;
  1609.                     BitSet currentRunningPosition = runningPositions[k].curpos;
  1610.                     hasSeenFinalPosition = hasSeenFinalPosition || currentRunningPosition.Get(endMarkerPos);
  1611.                     //Accepting position reached if the current position BitSet contains the endPosition
  1612.                     while (matchCount < 10000 && currentRunningPosition.Intersects(positionsWithRangeTerminals)) {
  1613.                         //Now might add 2 more positions to followpos
  1614.                         //1. nextIteration of the rangeNode, which is firstpos of its parent's leftChild
  1615.                         //2. Followpos of the range node
  1616.                        
  1617.                         BitSet countingPosition = currentRunningPosition.Clone();
  1618.                         countingPosition.And(positionsWithRangeTerminals);
  1619.                         int cPos = countingPosition.NextSet(-1);
  1620.                         //Get the first position where leaf range node appears
  1621.                         LeafRangeNode lrNode = positions[cPos].particle as LeafRangeNode;
  1622.                         //For a position with leaf range node, the particle is the node itself
  1623.                         Debug.Assert(lrNode != null);
  1624.                        
  1625.                         rposInfo = runningPositions[j];
  1626.                         if (matchCount + 2 >= runningPositions.Count) {
  1627.                             runningPositions.Add(new RangePositionInfo());
  1628.                             runningPositions.Add(new RangePositionInfo());
  1629.                         }
  1630.                         RangePositionInfo newRPosInfo = runningPositions[matchCount];
  1631.                         if (newRPosInfo.rangeCounters == null) {
  1632.                             newRPosInfo.rangeCounters = new decimal[minMaxNodesCount];
  1633.                         }
  1634.                         Array.Copy(rposInfo.rangeCounters, 0, newRPosInfo.rangeCounters, 0, rposInfo.rangeCounters.Length);
  1635.                         decimal count = ++newRPosInfo.rangeCounters[lrNode.Pos];
  1636.                        
  1637.                         if (count == lrNode.Max) {
  1638.                             newRPosInfo.curpos = followpos[cPos];
  1639.                             //since max has been reached, Get followposition of range node
  1640.                             newRPosInfo.rangeCounters[lrNode.Pos] = 0;
  1641.                             //reset counter
  1642.                             runningPositions[matchCount] = newRPosInfo;
  1643.                             j = matchCount++;
  1644.                         }
  1645.                         else if (count < lrNode.Min) {
  1646.                             newRPosInfo.curpos = lrNode.NextIteration;
  1647.                             runningPositions[matchCount] = newRPosInfo;
  1648.                             matchCount++;
  1649.                             break;
  1650.                         }
  1651.                         else {
  1652.                             // min <= count < max
  1653.                             newRPosInfo.curpos = lrNode.NextIteration;
  1654.                             //set currentpos to firstpos of node which has the range
  1655.                             runningPositions[matchCount] = newRPosInfo;
  1656.                             j = matchCount + 1;
  1657.                             newRPosInfo = runningPositions[j];
  1658.                             if (newRPosInfo.rangeCounters == null) {
  1659.                                 newRPosInfo.rangeCounters = new decimal[minMaxNodesCount];
  1660.                             }
  1661.                             Array.Copy(rposInfo.rangeCounters, 0, newRPosInfo.rangeCounters, 0, rposInfo.rangeCounters.Length);
  1662.                             newRPosInfo.curpos = followpos[cPos];
  1663.                             newRPosInfo.rangeCounters[lrNode.Pos] = 0;
  1664.                             runningPositions[j] = newRPosInfo;
  1665.                             matchCount += 2;
  1666.                         }
  1667.                         currentRunningPosition = runningPositions[j].curpos;
  1668.                         hasSeenFinalPosition = hasSeenFinalPosition || currentRunningPosition.Get(endMarkerPos);
  1669.                     }
  1670.                 }
  1671.                 context.HasMatched = hasSeenFinalPosition;
  1672.                 context.CurrentState.NumberOfRunningPos = matchCount;
  1673.                 return positions[pos].particle;
  1674.             }
  1675.             //matchcount > 0
  1676.             errorCode = -1;
  1677.             context.NeedValidateChildren = false;
  1678.             return null;
  1679.         }
  1680.        
  1681.         public override bool CompleteValidation(ValidationState context)
  1682.         {
  1683.             return context.HasMatched;
  1684.         }
  1685.        
  1686.         public override ArrayList ExpectedElements(ValidationState context, bool isRequiredOnly)
  1687.         {
  1688.             ArrayList names = null;
  1689.             BitSet expectedPos;
  1690.             if (context.RunningPositions != null) {
  1691.                 List<RangePositionInfo> runningPositions = context.RunningPositions;
  1692.                 expectedPos = new BitSet(positions.Count);
  1693.                 for (int i = context.CurrentState.NumberOfRunningPos - 1; i >= 0; i--) {
  1694.                     Debug.Assert(runningPositions[i].curpos != null);
  1695.                     expectedPos.Or(runningPositions[i].curpos);
  1696.                 }
  1697.                 for (int pos = expectedPos.NextSet(-1); pos != -1; pos = expectedPos.NextSet(pos)) {
  1698.                     if (names == null) {
  1699.                         names = new ArrayList();
  1700.                     }
  1701.                     int symbol = positions[pos].symbol;
  1702.                     if (symbol >= 0) {
  1703.                         //non range nodes
  1704.                         XmlSchemaParticle p = positions[pos].particle as XmlSchemaParticle;
  1705.                         if (p == null) {
  1706.                             string s = symbols.NameOf(positions[pos].symbol);
  1707.                             if (s.Length != 0) {
  1708.                                 names.Add(s);
  1709.                             }
  1710.                         }
  1711.                         else {
  1712.                             string s = p.NameString;
  1713.                             if (!names.Contains(s)) {
  1714.                                 names.Add(s);
  1715.                             }
  1716.                         }
  1717.                     }
  1718.                 }
  1719.             }
  1720.             return names;
  1721.         }
  1722.        
  1723.         public override ArrayList ExpectedParticles(ValidationState context, bool isRequiredOnly)
  1724.         {
  1725.             ArrayList particles = new ArrayList();
  1726.             BitSet expectedPos;
  1727.             if (context.RunningPositions != null) {
  1728.                 List<RangePositionInfo> runningPositions = context.RunningPositions;
  1729.                 expectedPos = new BitSet(positions.Count);
  1730.                 for (int i = context.CurrentState.NumberOfRunningPos - 1; i >= 0; i--) {
  1731.                     Debug.Assert(runningPositions[i].curpos != null);
  1732.                     expectedPos.Or(runningPositions[i].curpos);
  1733.                 }
  1734.                 for (int pos = expectedPos.NextSet(-1); pos != -1; pos = expectedPos.NextSet(pos)) {
  1735.                     int symbol = positions[pos].symbol;
  1736.                     if (symbol >= 0) {
  1737.                         //non range nodes
  1738.                         XmlSchemaParticle p = positions[pos].particle as XmlSchemaParticle;
  1739.                         if (p == null) {
  1740.                             continue;
  1741.                         }
  1742.                         else if (!particles.Contains(p)) {
  1743.                             particles.Add(p);
  1744.                         }
  1745.                     }
  1746.                 }
  1747.             }
  1748.             return particles;
  1749.         }
  1750.     }
  1751.    
  1752.     sealed class AllElementsContentValidator : ContentValidator
  1753.     {
  1754.         Hashtable elements;
  1755.         // unique terminal names to positions in Bitset mapping
  1756.         object[] particles;
  1757.         BitSet isRequired;
  1758.         // required flags
  1759.         int countRequired = 0;
  1760.        
  1761.         public AllElementsContentValidator(XmlSchemaContentType contentType, int size, bool isEmptiable) : base(contentType, false, isEmptiable)
  1762.         {
  1763.             elements = new Hashtable(size);
  1764.             particles = new object[size];
  1765.             isRequired = new BitSet(size);
  1766.         }
  1767.        
  1768.         public bool AddElement(XmlQualifiedName name, object particle, bool isEmptiable)
  1769.         {
  1770.             if (elements[name] != null) {
  1771.                 return false;
  1772.             }
  1773.             int i = elements.Count;
  1774.             elements.Add(name, i);
  1775.             particles[i] = particle;
  1776.             if (!isEmptiable) {
  1777.                 isRequired.Set(i);
  1778.                 countRequired++;
  1779.             }
  1780.             return true;
  1781.         }
  1782.        
  1783.         public override bool IsEmptiable {
  1784.             get { return base.IsEmptiable || countRequired == 0; }
  1785.         }
  1786.        
  1787.         public override void InitValidation(ValidationState context)
  1788.         {
  1789.             Debug.Assert(elements.Count > 0);
  1790.             context.AllElementsSet = new BitSet(elements.Count);
  1791.             //TODO if already non-null can clear
  1792.             context.CurrentState.AllElementsRequired = -1;
  1793.             // no elements at all
  1794.         }
  1795.        
  1796.         public override object ValidateElement(XmlQualifiedName name, ValidationState context, out int errorCode)
  1797.         {
  1798.             object lookup = elements[name];
  1799.             errorCode = 0;
  1800.             if (lookup == null) {
  1801.                 context.NeedValidateChildren = false;
  1802.                 return null;
  1803.             }
  1804.             int index = (int)lookup;
  1805.             if (context.AllElementsSet[index]) {
  1806.                 errorCode = -2;
  1807.                 return null;
  1808.             }
  1809.             if (context.CurrentState.AllElementsRequired == -1) {
  1810.                 context.CurrentState.AllElementsRequired = 0;
  1811.             }
  1812.             context.AllElementsSet.Set(index);
  1813.             if (isRequired[index]) {
  1814.                 context.CurrentState.AllElementsRequired++;
  1815.             }
  1816.             return particles[index];
  1817.         }
  1818.        
  1819.         public override bool CompleteValidation(ValidationState context)
  1820.         {
  1821.             if (context.CurrentState.AllElementsRequired == countRequired || IsEmptiable && context.CurrentState.AllElementsRequired == -1) {
  1822.                 return true;
  1823.             }
  1824.             return false;
  1825.         }
  1826.        
  1827.         public override ArrayList ExpectedElements(ValidationState context, bool isRequiredOnly)
  1828.         {
  1829.             ArrayList names = null;
  1830.             foreach (DictionaryEntry entry in elements) {
  1831.                 if (!context.AllElementsSet[(int)entry.Value] && (!isRequiredOnly || isRequired[(int)entry.Value])) {
  1832.                     if (names == null) {
  1833.                         names = new ArrayList();
  1834.                     }
  1835.                     names.Add(entry.Key);
  1836.                 }
  1837.             }
  1838.             return names;
  1839.         }
  1840.        
  1841.         public override ArrayList ExpectedParticles(ValidationState context, bool isRequiredOnly)
  1842.         {
  1843.             ArrayList expectedParticles = new ArrayList();
  1844.             foreach (DictionaryEntry entry in elements) {
  1845.                 if (!context.AllElementsSet[(int)entry.Value] && (!isRequiredOnly || isRequired[(int)entry.Value])) {
  1846.                     expectedParticles.Add(this.particles[(int)entry.Value]);
  1847.                 }
  1848.             }
  1849.             return expectedParticles;
  1850.         }
  1851.     }
  1852.     #endregion
  1853. }

Developer Fusion