File: System\Xml\Schema\XdrBuilder.cs
Project: ndp\fx\src\Xml\System.Xml.csproj (System.Xml)
//------------------------------------------------------------------------------
// <copyright file="XdrBuilder.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright> 
// <owner current="true" primary="true">Microsoft</owner>                                                               
//------------------------------------------------------------------------------
 
namespace System.Xml.Schema {
 
    using System.IO;
    using System.Collections;
    using System.Collections.Generic;
    using System.Diagnostics; 
    using System.ComponentModel;
    using System.Globalization;
    using System.Runtime.Versioning;
    
    /*
     * The XdrBuilder class parses the XDR Schema and 
     * builds internal validation information 
     */
    internal sealed class XdrBuilder : SchemaBuilder {
        private const int XdrSchema               = 1;
        private const int XdrElementType          = 2; 
        private const int XdrAttributeType        = 3;
        private const int XdrElement              = 4;
        private const int XdrAttribute            = 5;
        private const int XdrGroup                = 6;
        private const int XdrElementDatatype      = 7;
        private const int XdrAttributeDatatype    = 8;
 
        private const int SchemaFlagsNs           = 0x0100;
 
        private const int StackIncrement         = 10;
 
 
        private const int SchemaOrderNone       = 0;
        private const int SchemaOrderMany       = 1;
        private const int SchemaOrderSequence   = 2;
        private const int SchemaOrderChoice     = 3;
        private const int SchemaOrderAll        = 4;
 
        private const int SchemaContentNone     = 0;
        private const int SchemaContentEmpty    = 1;
        private const int SchemaContentText     = 2;
        private const int SchemaContentMixed    = 3;
        private const int SchemaContentElement  = 4;
 
 
        private sealed class DeclBaseInfo {
            // used for <element... or <attribute...
            internal XmlQualifiedName        _Name;
            internal string       _Prefix;
            internal XmlQualifiedName        _TypeName;
            internal string       _TypePrefix;
            internal object       _Default;
            internal object       _Revises;
            internal uint         _MaxOccurs;
            internal uint         _MinOccurs;
 
            // used for checking undeclared attribute type
            internal bool              _Checking;
            internal SchemaElementDecl _ElementDecl;
            internal SchemaAttDef      _Attdef;
            internal DeclBaseInfo      _Next;
            
            internal DeclBaseInfo() {
                Reset();
            }
 
            internal void Reset() {
                _Name = XmlQualifiedName.Empty;
                _Prefix = null;
		        _TypeName = XmlQualifiedName.Empty;
                _TypePrefix = null;
                _Default = null;
                _Revises = null;
                _MaxOccurs = 1;
                _MinOccurs = 1;
                _Checking = false;
                _ElementDecl = null;
                _Next = null;
                _Attdef = null;
            }
        };
 
        private sealed class GroupContent {
            internal uint             _MinVal;
            internal uint             _MaxVal;
            internal bool            _HasMaxAttr;
            internal bool            _HasMinAttr;
            internal int             _Order;              
 
            internal static void Copy(GroupContent from, GroupContent to) {
                to._MinVal = from._MinVal;
                to._MaxVal = from._MaxVal;
                to._Order = from._Order;
            }
 
            internal static GroupContent Copy(GroupContent other) {
                GroupContent g = new GroupContent();
                Copy(other, g);
                return g;
            }
        };
 
        private sealed class ElementContent {
            // for <ElementType ...
            internal SchemaElementDecl   _ElementDecl;          // Element Information
 
            internal int             _ContentAttr;              // content attribute
            internal int             _OrderAttr;                // order attribute
 
            internal bool            _MasterGroupRequired;      // In a situation like <!ELEMENT root (e1)> e1 has to have a ()
            internal bool            _ExistTerminal;            // when there exist a terminal, we need to addOrder before
            
            // we can add another terminal
            internal bool            _AllowDataType;            // must have textOnly if we have datatype
            internal bool            _HasDataType;              // got data type
 
            // for <element ...
            internal bool            _HasType;                  // user must have a type attribute in <element ...
            internal bool            _EnumerationRequired;
            internal uint             _MinVal;
            internal uint             _MaxVal;                   // -1 means infinity
 
            internal uint             _MaxLength;                // dt:maxLength
            internal uint             _MinLength;                // dt:minLength
 
            internal Hashtable       _AttDefList;               // a list of current AttDefs for the <ElementType ...
            // only the used one will be added
        };
 
        private sealed class AttributeContent {
            // used for <AttributeType ...
            internal SchemaAttDef    _AttDef;
 
            // used to store name & prefix for the AttributeType
            internal XmlQualifiedName           _Name;
            internal string          _Prefix;  
            internal bool            _Required;                  // true:  when the attribute required="yes"
 
            // used for both AttributeType and attribute
            internal uint             _MinVal;
            internal uint             _MaxVal;                   // -1 means infinity
 
            internal uint             _MaxLength;                 // dt:maxLength
            internal uint             _MinLength;                 // dt:minLength
 
            // used for datatype 
            internal bool            _EnumerationRequired;       // when we have dt:value then we must have dt:type="enumeration"
            internal bool            _HasDataType;
 
            // used for <attribute ...
            internal bool            _Global;
 
            internal object          _Default;
        };
 
        private delegate void XdrBuildFunction(XdrBuilder builder, object obj, string prefix);
        private delegate void XdrInitFunction(XdrBuilder builder, object obj);
        private delegate void XdrBeginChildFunction(XdrBuilder builder);
        private delegate void XdrEndChildFunction(XdrBuilder builder);
 
        private sealed class XdrAttributeEntry {
            internal SchemaNames.Token        _Attribute;     // possible attribute names
            internal int                   _SchemaFlags;
            internal XmlSchemaDatatype     _Datatype;     
            internal XdrBuildFunction      _BuildFunc;     // Corresponding build functions for attribute value
 
            internal XdrAttributeEntry(SchemaNames.Token a, XmlTokenizedType ttype, XdrBuildFunction build) {
                _Attribute = a;
                _Datatype = XmlSchemaDatatype.FromXmlTokenizedType(ttype);
                _SchemaFlags = 0;
                _BuildFunc = build;
            }
            internal XdrAttributeEntry(SchemaNames.Token a, XmlTokenizedType ttype, int schemaFlags, XdrBuildFunction build) {
                _Attribute = a;
                _Datatype = XmlSchemaDatatype.FromXmlTokenizedType(ttype);
                _SchemaFlags = schemaFlags;
                _BuildFunc = build;
            }
        };
 
        //
        // XdrEntry controls the states of parsing a schema document
        // and calls the corresponding "init", "end" and "build" functions when necessary
        //
        private sealed class XdrEntry {
            internal SchemaNames.Token         _Name;               // the name of the object it is comparing to
            internal int[]                  _NextStates;         // possible next states
            internal XdrAttributeEntry[]    _Attributes;         // allowed attributes
            internal XdrInitFunction        _InitFunc;           // "init" functions in XdrBuilder
            internal XdrBeginChildFunction  _BeginChildFunc;     // "begin" functions in XdrBuilder for BeginChildren
            internal XdrEndChildFunction    _EndChildFunc;       // "end" functions in XdrBuilder for EndChildren
            internal bool                   _AllowText;          // whether text content is allowed  
 
            internal XdrEntry(SchemaNames.Token n, 
                              int[] states, 
                              XdrAttributeEntry[] attributes, 
                              XdrInitFunction init, 
                              XdrBeginChildFunction begin, 
                              XdrEndChildFunction end, 
                              bool fText) {
                _Name = n;
                _NextStates = states;
                _Attributes = attributes;
                _InitFunc = init;
                _BeginChildFunc = begin;
                _EndChildFunc = end;
                _AllowText = fText; 
            }
        };
 
 
        /////////////////////////////////////////////////////////////////////////////
        // Data structures for XML-Data Reduced (XDR Schema)
        //
 
        //
        // Elements
        //
        private static readonly int[] S_XDR_Root_Element = {XdrSchema};
        private static readonly int[] S_XDR_Root_SubElements = {XdrElementType, XdrAttributeType};
        private static readonly int[] S_XDR_ElementType_SubElements = {XdrElement, XdrGroup, XdrAttributeType, XdrAttribute, XdrElementDatatype};
        private static readonly int[] S_XDR_AttributeType_SubElements = {XdrAttributeDatatype};
        private static readonly int[] S_XDR_Group_SubElements = {XdrElement, XdrGroup};
 
        //
        // Attributes
        //
        private static readonly XdrAttributeEntry[] S_XDR_Root_Attributes = 
        {
            new XdrAttributeEntry(SchemaNames.Token.SchemaName, XmlTokenizedType.CDATA, new XdrBuildFunction(XDR_BuildRoot_Name) ),
            new XdrAttributeEntry(SchemaNames.Token.SchemaId,   XmlTokenizedType.QName, new XdrBuildFunction(XDR_BuildRoot_ID) )
        };
 
        private static readonly XdrAttributeEntry[] S_XDR_ElementType_Attributes =
        {
            new XdrAttributeEntry(SchemaNames.Token.SchemaName,         XmlTokenizedType.QName, SchemaFlagsNs,  new XdrBuildFunction(XDR_BuildElementType_Name) ),
            new XdrAttributeEntry(SchemaNames.Token.SchemaContent,      XmlTokenizedType.QName,    new XdrBuildFunction(XDR_BuildElementType_Content) ),
            new XdrAttributeEntry(SchemaNames.Token.SchemaModel,        XmlTokenizedType.QName,    new XdrBuildFunction(XDR_BuildElementType_Model) ),
            new XdrAttributeEntry(SchemaNames.Token.SchemaOrder,        XmlTokenizedType.QName,    new XdrBuildFunction(XDR_BuildElementType_Order) ),
            new XdrAttributeEntry(SchemaNames.Token.SchemaDtType,       XmlTokenizedType.CDATA,    new XdrBuildFunction(XDR_BuildElementType_DtType) ),
            new XdrAttributeEntry(SchemaNames.Token.SchemaDtValues,     XmlTokenizedType.NMTOKENS, new XdrBuildFunction(XDR_BuildElementType_DtValues) ),
            new XdrAttributeEntry(SchemaNames.Token.SchemaDtMaxLength,  XmlTokenizedType.CDATA,    new XdrBuildFunction(XDR_BuildElementType_DtMaxLength) ),
            new XdrAttributeEntry(SchemaNames.Token.SchemaDtMinLength,  XmlTokenizedType.CDATA,    new XdrBuildFunction(XDR_BuildElementType_DtMinLength) )
        };
 
        private static readonly XdrAttributeEntry[] S_XDR_AttributeType_Attributes =
        {
            new XdrAttributeEntry(SchemaNames.Token.SchemaName,         XmlTokenizedType.QName,     new XdrBuildFunction(XDR_BuildAttributeType_Name) ),
            new XdrAttributeEntry(SchemaNames.Token.SchemaRequired,     XmlTokenizedType.QName,     new XdrBuildFunction(XDR_BuildAttributeType_Required) ),
            new XdrAttributeEntry(SchemaNames.Token.SchemaDefault,      XmlTokenizedType.CDATA,     new XdrBuildFunction(XDR_BuildAttributeType_Default) ),
            new XdrAttributeEntry(SchemaNames.Token.SchemaDtType,       XmlTokenizedType.QName,     new XdrBuildFunction(XDR_BuildAttributeType_DtType) ),
            new XdrAttributeEntry(SchemaNames.Token.SchemaDtValues,     XmlTokenizedType.NMTOKENS,  new XdrBuildFunction(XDR_BuildAttributeType_DtValues) ),
            new XdrAttributeEntry(SchemaNames.Token.SchemaDtMaxLength,  XmlTokenizedType.CDATA,     new XdrBuildFunction(XDR_BuildAttributeType_DtMaxLength) ),
            new XdrAttributeEntry(SchemaNames.Token.SchemaDtMinLength,  XmlTokenizedType.CDATA,     new XdrBuildFunction(XDR_BuildAttributeType_DtMinLength) )
        };
 
        private static readonly XdrAttributeEntry[] S_XDR_Element_Attributes = 
        {
            new XdrAttributeEntry(SchemaNames.Token.SchemaType,      XmlTokenizedType.QName, SchemaFlagsNs,  new XdrBuildFunction(XDR_BuildElement_Type) ),
            new XdrAttributeEntry(SchemaNames.Token.SchemaMinOccurs, XmlTokenizedType.CDATA,     new XdrBuildFunction(XDR_BuildElement_MinOccurs) ),
            new XdrAttributeEntry(SchemaNames.Token.SchemaMaxOccurs, XmlTokenizedType.CDATA,     new XdrBuildFunction(XDR_BuildElement_MaxOccurs) )
        };
 
        private static readonly XdrAttributeEntry[] S_XDR_Attribute_Attributes =
        {
            new XdrAttributeEntry(SchemaNames.Token.SchemaType,       XmlTokenizedType.QName,   new XdrBuildFunction(XDR_BuildAttribute_Type) ),
            new XdrAttributeEntry(SchemaNames.Token.SchemaRequired,   XmlTokenizedType.QName,   new XdrBuildFunction(XDR_BuildAttribute_Required) ),
            new XdrAttributeEntry(SchemaNames.Token.SchemaDefault,    XmlTokenizedType.CDATA,   new XdrBuildFunction(XDR_BuildAttribute_Default) )
        };
 
        private static readonly XdrAttributeEntry[] S_XDR_Group_Attributes =
        {
            new XdrAttributeEntry(SchemaNames.Token.SchemaOrder,     XmlTokenizedType.QName,   new XdrBuildFunction(XDR_BuildGroup_Order) ),
            new XdrAttributeEntry(SchemaNames.Token.SchemaMinOccurs, XmlTokenizedType.CDATA,   new XdrBuildFunction(XDR_BuildGroup_MinOccurs) ),
            new XdrAttributeEntry(SchemaNames.Token.SchemaMaxOccurs, XmlTokenizedType.CDATA,   new XdrBuildFunction(XDR_BuildGroup_MaxOccurs) )
        };
 
        private static readonly XdrAttributeEntry[] S_XDR_ElementDataType_Attributes = 
        {
            new XdrAttributeEntry(SchemaNames.Token.SchemaDtType,        XmlTokenizedType.CDATA,    new XdrBuildFunction(XDR_BuildElementType_DtType) ),
            new XdrAttributeEntry(SchemaNames.Token.SchemaDtValues,      XmlTokenizedType.NMTOKENS, new XdrBuildFunction(XDR_BuildElementType_DtValues) ),
            new XdrAttributeEntry(SchemaNames.Token.SchemaDtMaxLength,   XmlTokenizedType.CDATA,    new XdrBuildFunction(XDR_BuildElementType_DtMaxLength) ),
            new XdrAttributeEntry(SchemaNames.Token.SchemaDtMinLength,   XmlTokenizedType.CDATA,    new XdrBuildFunction(XDR_BuildElementType_DtMinLength) ) 
        };
 
        private static readonly XdrAttributeEntry[] S_XDR_AttributeDataType_Attributes =
        {
            new XdrAttributeEntry(SchemaNames.Token.SchemaDtType,        XmlTokenizedType.QName,    new XdrBuildFunction(XDR_BuildAttributeType_DtType) ),
            new XdrAttributeEntry(SchemaNames.Token.SchemaDtValues,      XmlTokenizedType.NMTOKENS, new XdrBuildFunction(XDR_BuildAttributeType_DtValues) ),
            new XdrAttributeEntry(SchemaNames.Token.SchemaDtMaxLength,   XmlTokenizedType.CDATA,    new XdrBuildFunction(XDR_BuildAttributeType_DtMaxLength) ),
            new XdrAttributeEntry(SchemaNames.Token.SchemaDtMinLength,   XmlTokenizedType.CDATA,    new XdrBuildFunction(XDR_BuildAttributeType_DtMinLength) )
            
        };
        //
        // Schema entries
        //
        private static readonly XdrEntry[] S_SchemaEntries =
        {
            new XdrEntry( SchemaNames.Token.Empty,     S_XDR_Root_Element, null, 
                          null, 
                          null, 
                          null,
                          false),
            new XdrEntry( SchemaNames.Token.XdrRoot,     S_XDR_Root_SubElements, S_XDR_Root_Attributes, 
                          new XdrInitFunction(XDR_InitRoot), 
                          new XdrBeginChildFunction(XDR_BeginRoot),
                          new XdrEndChildFunction(XDR_EndRoot),
                          false),
            new XdrEntry( SchemaNames.Token.XdrElementType,    S_XDR_ElementType_SubElements, S_XDR_ElementType_Attributes, 
                          new XdrInitFunction(XDR_InitElementType),    
                          new XdrBeginChildFunction(XDR_BeginElementType),   
                          new XdrEndChildFunction(XDR_EndElementType),
                          false),
            new XdrEntry( SchemaNames.Token.XdrAttributeType,  S_XDR_AttributeType_SubElements, S_XDR_AttributeType_Attributes, 
                          new XdrInitFunction(XDR_InitAttributeType),  
                          new XdrBeginChildFunction(XDR_BeginAttributeType), 
                          new XdrEndChildFunction(XDR_EndAttributeType),
                          false),
            new XdrEntry( SchemaNames.Token.XdrElement,        null, S_XDR_Element_Attributes, 
                          new XdrInitFunction(XDR_InitElement),        
                          null,                               
                          new XdrEndChildFunction(XDR_EndElement),
                          false),
            new XdrEntry( SchemaNames.Token.XdrAttribute,      null, S_XDR_Attribute_Attributes, 
                          new XdrInitFunction(XDR_InitAttribute),      
                          new XdrBeginChildFunction(XDR_BeginAttribute),                               
                          new XdrEndChildFunction(XDR_EndAttribute),
                          false),
            new XdrEntry( SchemaNames.Token.XdrGroup,          S_XDR_Group_SubElements, S_XDR_Group_Attributes, 
                          new XdrInitFunction(XDR_InitGroup),
                          null,     
                          new XdrEndChildFunction(XDR_EndGroup),
                          false), 
            new XdrEntry( SchemaNames.Token.XdrDatatype,       null, S_XDR_ElementDataType_Attributes, 
                          new XdrInitFunction(XDR_InitElementDtType),       
                          null,                               
                          new XdrEndChildFunction(XDR_EndElementDtType),
                          true),
            new XdrEntry( SchemaNames.Token.XdrDatatype,       null, S_XDR_AttributeDataType_Attributes, 
                          new XdrInitFunction(XDR_InitAttributeDtType),       
                          null,                               
                          new XdrEndChildFunction(XDR_EndAttributeDtType),
                          true)
        };
 
        private SchemaInfo        _SchemaInfo;
        private string            _TargetNamespace;
        private XmlReader         _reader;
        private PositionInfo       positionInfo;
        private ParticleContentValidator _contentValidator;
       
        private XdrEntry          _CurState;
        private XdrEntry          _NextState;
 
        private HWStack           _StateHistory;
        private HWStack           _GroupStack;
        private string            _XdrName;
        private string            _XdrPrefix;
 
        private ElementContent    _ElementDef;
        private GroupContent      _GroupDef;
        private AttributeContent  _AttributeDef;
 
        private DeclBaseInfo      _UndefinedAttributeTypes;
        private DeclBaseInfo      _BaseDecl;
 
        private XmlNameTable      _NameTable;
        private SchemaNames       _SchemaNames;
 
        private XmlNamespaceManager   _CurNsMgr;
        private string            _Text;
 
        private ValidationEventHandler validationEventHandler;
        Hashtable _UndeclaredElements = new Hashtable();
 
        private const string     x_schema = "x-schema:";
 
        private XmlResolver xmlResolver = null;
 
        internal XdrBuilder(
                           XmlReader reader,
                           XmlNamespaceManager curmgr, 
                           SchemaInfo sinfo, 
                           string targetNamspace,
                           XmlNameTable nameTable,
                           SchemaNames schemaNames,
                           ValidationEventHandler eventhandler
                           ) {
            _SchemaInfo = sinfo;
            _TargetNamespace = targetNamspace;
            _reader = reader;
            _CurNsMgr = curmgr;
            validationEventHandler = eventhandler;
            _StateHistory = new HWStack(StackIncrement);
            _ElementDef = new ElementContent();
            _AttributeDef = new AttributeContent();
            _GroupStack = new HWStack(StackIncrement);
            _GroupDef = new GroupContent();
            _NameTable = nameTable;
            _SchemaNames = schemaNames;
            _CurState = S_SchemaEntries[0];
            positionInfo = PositionInfo.GetPositionInfo(_reader);
            xmlResolver = System.Xml.XmlConfiguration.XmlReaderSection.CreateDefaultResolver();
        }
 
        internal override bool ProcessElement(string prefix, string name, string ns) {
            XmlQualifiedName qname = new XmlQualifiedName(name, XmlSchemaDatatype.XdrCanonizeUri(ns, _NameTable, _SchemaNames));
            if (GetNextState(qname)) {
                Push();
                if (_CurState._InitFunc != null) {
                    (this._CurState._InitFunc)(this, qname);
                }
                return true;
            }
            else {
                if (!IsSkipableElement(qname)) {
                    SendValidationEvent(Res.Sch_UnsupportedElement, XmlQualifiedName.ToString(name, prefix));
                }
                return false;
            }
        }
 
        // SxS: This method processes attribute from the source document and does not expose any resources to the caller
        // It is fine to suppress the SxS warning. 
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
        [ResourceExposure(ResourceScope.None)]
        internal override void ProcessAttribute(string prefix, string name, string ns, string value) {
            XmlQualifiedName qname = new XmlQualifiedName(name, XmlSchemaDatatype.XdrCanonizeUri(ns, _NameTable, _SchemaNames));
            for (int i = 0; i < _CurState._Attributes.Length; i++) {
                XdrAttributeEntry a = _CurState._Attributes[i];
                if (_SchemaNames.TokenToQName[(int)a._Attribute].Equals(qname)) {
                    XdrBuildFunction buildFunc = a._BuildFunc;
                    if (a._Datatype.TokenizedType == XmlTokenizedType.QName) {
                        string prefixValue;
                        XmlQualifiedName qnameValue = XmlQualifiedName.Parse(value, _CurNsMgr, out prefixValue);
                        qnameValue.Atomize(_NameTable);
                        if (prefixValue.Length != 0) {
                            if (a._Attribute != SchemaNames.Token.SchemaType) {    // <attribute type= || <element type= 
                                throw new XmlException(Res.Xml_UnexpectedToken, "NAME");
                            }
                        }
                        else if (IsGlobal(a._SchemaFlags)) {
                            qnameValue = new XmlQualifiedName(qnameValue.Name, _TargetNamespace);
                        }
                        else {
                            qnameValue = new XmlQualifiedName(qnameValue.Name);
                        }
                        buildFunc(this, qnameValue, prefixValue);
                    } else {
                        buildFunc(this, a._Datatype.ParseValue(value, _NameTable, _CurNsMgr), string.Empty);
                    }
                    return;
                }
            }
 
            if ((object)ns == (object)_SchemaNames.NsXmlNs && IsXdrSchema(value)) {
                LoadSchema(value);
                return;
            }
 
            // Check non-supported attribute
            if (!IsSkipableAttribute(qname) ) {
                SendValidationEvent(Res.Sch_UnsupportedAttribute, 
                                    XmlQualifiedName.ToString(qname.Name, prefix));
            }
        }
 
        internal XmlResolver XmlResolver {
            set {
                xmlResolver = value;
            }
        }
 
        [ResourceConsumption(ResourceScope.Machine)]
        [ResourceExposure(ResourceScope.Machine)]
        private bool LoadSchema(string uri) {
            if (xmlResolver == null) {
                return false;
            }
            uri = _NameTable.Add(uri);
            if (_SchemaInfo.TargetNamespaces.ContainsKey(uri)) {
                return false;
            }
            SchemaInfo schemaInfo = null;
            Uri _baseUri = xmlResolver.ResolveUri(null,_reader.BaseURI);
            XmlReader reader = null;
            try {
                Uri ruri = xmlResolver.ResolveUri(_baseUri, uri.Substring(x_schema.Length));
                Stream stm = (Stream)xmlResolver.GetEntity(ruri,null,null);
                reader = new XmlTextReader(ruri.ToString(), stm, _NameTable);
                schemaInfo = new SchemaInfo();
                Parser parser = new Parser(SchemaType.XDR, _NameTable, _SchemaNames, validationEventHandler);
                parser.XmlResolver = xmlResolver;
                parser.Parse(reader, uri);
                schemaInfo = parser.XdrSchema;
            }
            catch(XmlException e) {
                SendValidationEvent(Res.Sch_CannotLoadSchema, new string[] {uri, e.Message}, XmlSeverityType.Warning);
                schemaInfo = null;
            }
            finally {
                if (reader != null) {
                    reader.Close();
                }
            }
            if (schemaInfo != null && schemaInfo.ErrorCount == 0) {
                _SchemaInfo.Add(schemaInfo, validationEventHandler);
                return true;
            }
            return false;
        }
 
        internal static bool IsXdrSchema(string uri) {
            return uri.Length >= x_schema.Length &&
                   0 == string.Compare(uri, 0, x_schema, 0, x_schema.Length, StringComparison.Ordinal) &&
                   !uri.StartsWith("x-schema:#", StringComparison.Ordinal);
        }
 
        internal override bool IsContentParsed() {
            return true;
        }
 
        internal override void ProcessMarkup(XmlNode[] markup) {
            throw new InvalidOperationException(Res.GetString(Res.Xml_InvalidOperation)); // should never be called
        }
 
        internal override void ProcessCData(string value) {
            if (_CurState._AllowText) {
                _Text = value;
            }
            else {
                SendValidationEvent(Res.Sch_TextNotAllowed, value);
            }
        }
 
        internal override void StartChildren() {
            if (_CurState._BeginChildFunc != null) {
                (this._CurState._BeginChildFunc)(this);
            }
        }
 
        internal override void EndChildren() {
            if (_CurState._EndChildFunc != null) {
                (this._CurState._EndChildFunc)(this);
            }
 
            Pop();
        }
 
        //
        // State stack push & pop
        //
        private void Push() {
            _StateHistory.Push();
            _StateHistory[_StateHistory.Length - 1] = _CurState;
            _CurState = _NextState;
        }
 
        private void Pop() {
            _CurState = (XdrEntry)_StateHistory.Pop();
        }
 
 
        //
        // Group stack push & pop
        //
        private void PushGroupInfo() {
            _GroupStack.Push();
            _GroupStack[_GroupStack.Length - 1] = GroupContent.Copy(_GroupDef);
        }
 
        private void PopGroupInfo() {
            _GroupDef = (GroupContent)_GroupStack.Pop();
            Debug.Assert(_GroupDef != null);
        }
 
        //
        // XDR Schema
        //
        private static void XDR_InitRoot(XdrBuilder builder, object obj) {
            builder._SchemaInfo.SchemaType = SchemaType.XDR;
            builder._ElementDef._ElementDecl = null;
            builder._ElementDef._AttDefList = null;
            builder._AttributeDef._AttDef = null;
        }
 
        private static void XDR_BuildRoot_Name(XdrBuilder builder, object obj, string prefix) {
            builder._XdrName = (string) obj;
            builder._XdrPrefix = prefix;
        }
 
        private static void XDR_BuildRoot_ID(XdrBuilder builder, object obj, string prefix) {
 
        }
 
        private static void XDR_BeginRoot(XdrBuilder builder) {
            if (builder._TargetNamespace == null) { // inline xdr schema
                if (builder._XdrName != null) {
                    builder._TargetNamespace = builder._NameTable.Add("x-schema:#" + builder._XdrName);
                }
                else {
                    builder._TargetNamespace = String.Empty;
                }
            }
            builder._SchemaInfo.TargetNamespaces.Add(builder._TargetNamespace, true);
        }
 
        private static void XDR_EndRoot(XdrBuilder builder) {
            //
            // check undefined attribute types
            // We already checked local attribute types, so only need to check global attribute types here 
            //
            while (builder._UndefinedAttributeTypes != null) {
                XmlQualifiedName gname = builder._UndefinedAttributeTypes._TypeName;
 
                // if there is no URN in this name then the name is local to the
                // schema, but the global attribute was still URN qualified, so
                // we need to qualify this name now.
                if (gname.Namespace.Length == 0) {
                    gname = new XmlQualifiedName(gname.Name, builder._TargetNamespace);
                }
                SchemaAttDef ad;
                if (builder._SchemaInfo.AttributeDecls.TryGetValue(gname, out ad)) {
                    builder._UndefinedAttributeTypes._Attdef = (SchemaAttDef)ad.Clone();
                    builder._UndefinedAttributeTypes._Attdef.Name = gname;
                    builder.XDR_CheckAttributeDefault(builder._UndefinedAttributeTypes, builder._UndefinedAttributeTypes._Attdef);
                }
                else {
                    builder.SendValidationEvent(Res.Sch_UndeclaredAttribute, gname.Name);
                }
                builder._UndefinedAttributeTypes = builder._UndefinedAttributeTypes._Next;
            }
 
            foreach (SchemaElementDecl ed in builder._UndeclaredElements.Values) {
                builder.SendValidationEvent(Res.Sch_UndeclaredElement, XmlQualifiedName.ToString(ed.Name.Name, ed.Prefix));
            }
 
 
 
        }
 
 
        //
        // XDR ElementType
        //
 
        private static void XDR_InitElementType(XdrBuilder builder, object obj) {
            builder._ElementDef._ElementDecl = new SchemaElementDecl(); 
            builder._contentValidator = new ParticleContentValidator(XmlSchemaContentType.Mixed);
            builder._contentValidator.IsOpen = true;
 
            builder._ElementDef._ContentAttr = SchemaContentNone;
            builder._ElementDef._OrderAttr = SchemaOrderNone;
            builder._ElementDef._MasterGroupRequired = false; 
            builder._ElementDef._ExistTerminal = false;
            builder._ElementDef._AllowDataType = true;
            builder._ElementDef._HasDataType = false;
            builder._ElementDef._EnumerationRequired= false;
            builder._ElementDef._AttDefList = new Hashtable();
            builder._ElementDef._MaxLength = uint.MaxValue;
            builder._ElementDef._MinLength = uint.MaxValue;
 
            //        builder._AttributeDef._HasDataType = false;
            //        builder._AttributeDef._Default = null;
        }
 
        private static void XDR_BuildElementType_Name(XdrBuilder builder, object obj, string prefix) {
            XmlQualifiedName qname = (XmlQualifiedName) obj;
 
            if (builder._SchemaInfo.ElementDecls.ContainsKey(qname)) {
                builder.SendValidationEvent(Res.Sch_DupElementDecl, XmlQualifiedName.ToString(qname.Name, prefix));
            }
            builder._ElementDef._ElementDecl.Name = qname;
            builder._ElementDef._ElementDecl.Prefix = prefix;
            builder._SchemaInfo.ElementDecls.Add(qname, builder._ElementDef._ElementDecl);
            if (builder._UndeclaredElements[qname] != null) {
                builder._UndeclaredElements.Remove(qname);
            }
        }
 
        private static void XDR_BuildElementType_Content(XdrBuilder builder, object obj, string prefix) {
            builder._ElementDef._ContentAttr = builder.GetContent((XmlQualifiedName)obj);
        }
 
        private static void XDR_BuildElementType_Model(XdrBuilder builder, object obj, string prefix) {
            builder._contentValidator.IsOpen = builder.GetModel((XmlQualifiedName)obj);
        }
 
        private static void XDR_BuildElementType_Order(XdrBuilder builder, object obj, string prefix) {
            builder._ElementDef._OrderAttr = builder._GroupDef._Order = builder.GetOrder((XmlQualifiedName)obj);
        }
 
        private static void XDR_BuildElementType_DtType(XdrBuilder builder, object obj, string prefix) {
            builder._ElementDef._HasDataType = true;
            string s = ((string)obj).Trim();
            if (s.Length == 0) {
                builder.SendValidationEvent(Res.Sch_MissDtvalue);
            }
            else {
                XmlSchemaDatatype dtype = XmlSchemaDatatype.FromXdrName(s);
                if (dtype == null) {
                    builder.SendValidationEvent(Res.Sch_UnknownDtType, s);
                }
                builder._ElementDef._ElementDecl.Datatype = dtype;
            }
        }
 
        private static void XDR_BuildElementType_DtValues(XdrBuilder builder, object obj, string prefix) {
            builder._ElementDef._EnumerationRequired = true;
            builder._ElementDef._ElementDecl.Values = new List<string>((string[]) obj); 
        }
 
        private static void XDR_BuildElementType_DtMaxLength(XdrBuilder builder, object obj, string prefix) {
            ParseDtMaxLength(ref builder._ElementDef._MaxLength, obj, builder);
        }
 
        private static void XDR_BuildElementType_DtMinLength(XdrBuilder builder, object obj, string prefix) {
            ParseDtMinLength(ref builder._ElementDef._MinLength, obj, builder);
        }
 
        private static void XDR_BeginElementType(XdrBuilder builder) {
            string code = null;
            string msg = null;
 
            //
            // check name attribute
            //
            if (builder._ElementDef._ElementDecl.Name.IsEmpty) {
                code = Res.Sch_MissAttribute;
                msg = "name";
                goto cleanup;
            }
 
            //
            // check dt:type attribute
            //
            if (builder._ElementDef._HasDataType) {
                if (!builder._ElementDef._AllowDataType) {
                    code = Res.Sch_DataTypeTextOnly;
                    goto cleanup;
                }
                else {
                    builder._ElementDef._ContentAttr = SchemaContentText;
                }
            }
            else if (builder._ElementDef._ContentAttr == SchemaContentNone) {
                switch (builder._ElementDef._OrderAttr) {
                    case SchemaOrderNone:
                        builder._ElementDef._ContentAttr = SchemaContentMixed;
                        builder._ElementDef._OrderAttr = SchemaOrderMany;
                        break;
                    case SchemaOrderSequence:
                        builder._ElementDef._ContentAttr = SchemaContentElement;
                        break;
                    case SchemaOrderChoice:
                        builder._ElementDef._ContentAttr = SchemaContentElement;
                        break;
                    case SchemaOrderMany:
                        builder._ElementDef._ContentAttr = SchemaContentMixed;
                        break;
                }
            }
            
 
            //save the model value from the base
            bool tempOpen = builder._contentValidator.IsOpen;
            ElementContent def = builder._ElementDef;
            switch (builder._ElementDef._ContentAttr) {
                case SchemaContentText:
                    builder._ElementDef._ElementDecl.ContentValidator = ContentValidator.TextOnly;
                    builder._GroupDef._Order = SchemaOrderMany;
                    builder._contentValidator = null;
                    break;
                case SchemaContentElement:
                    builder._contentValidator = new ParticleContentValidator(XmlSchemaContentType.ElementOnly);
                    if (def._OrderAttr == SchemaOrderNone) {
                            builder._GroupDef._Order = SchemaOrderSequence;
                    }
                    def._MasterGroupRequired = true;
                    builder._contentValidator.IsOpen = tempOpen;
                    break;
 
                case SchemaContentEmpty:
                    builder._ElementDef._ElementDecl.ContentValidator = ContentValidator.Empty;
                    builder._contentValidator = null;
                    break;
 
                case SchemaContentMixed:
                    if (def._OrderAttr == SchemaOrderNone || def._OrderAttr == SchemaOrderMany) {
                            builder._GroupDef._Order = SchemaOrderMany;
                        }
                    else {
                            code = Res.Sch_MixedMany;
                            goto cleanup;
                    }
                    def._MasterGroupRequired = true;
                    builder._contentValidator.IsOpen = tempOpen;
                    break;
            }       
 
 
            if (def._ContentAttr == SchemaContentMixed || def._ContentAttr == SchemaContentElement) {
                builder._contentValidator.Start();
                builder._contentValidator.OpenGroup();
            }
            cleanup:
            if (code != null) {
                builder.SendValidationEvent(code, msg);
            }
        }
 
        private static void XDR_EndElementType(XdrBuilder builder) {
            SchemaElementDecl ed = builder._ElementDef._ElementDecl;
			
            // check undefined attribute types first
            if (builder._UndefinedAttributeTypes != null && builder._ElementDef._AttDefList != null) {
                DeclBaseInfo patt = builder._UndefinedAttributeTypes;
                DeclBaseInfo p1 = patt;
 
                while (patt != null) {
                    SchemaAttDef pAttdef = null;
 
                    if (patt._ElementDecl == ed) {
                        XmlQualifiedName pName = patt._TypeName;
                        pAttdef = (SchemaAttDef)builder._ElementDef._AttDefList[pName];
                        if (pAttdef != null) {
                            patt._Attdef = (SchemaAttDef)pAttdef.Clone();
                            patt._Attdef.Name = pName;
                            builder.XDR_CheckAttributeDefault(patt, pAttdef);
 
                            // remove it from _pUndefinedAttributeTypes
                            if (patt == builder._UndefinedAttributeTypes) {
                                patt = builder._UndefinedAttributeTypes = patt._Next;
                                p1 = patt;
                            }
                            else {
                                p1._Next = patt._Next;
                                patt = p1._Next;
                            }
                        }
                    }
 
                    if (pAttdef == null) {
                        if (patt != builder._UndefinedAttributeTypes)
                            p1 = p1._Next;
                        patt = patt._Next;
                    }
                }
            }
 
            if (builder._ElementDef._MasterGroupRequired) {
                // if the content is mixed, there is a group that need to be closed
                builder._contentValidator.CloseGroup();
 
                if (!builder._ElementDef._ExistTerminal) {
                    if (builder._contentValidator.IsOpen) {
                        builder._ElementDef._ElementDecl.ContentValidator = ContentValidator.Any;
                        builder._contentValidator = null;
                    }
                    else {
                        if(builder._ElementDef._ContentAttr != SchemaContentMixed)
                            builder.SendValidationEvent(Res.Sch_ElementMissing);
                    }
                }
                else {
                    if (builder._GroupDef._Order == SchemaOrderMany) {
                        builder._contentValidator.AddStar();
                    }
                }
            }
            if (ed.Datatype != null) {
                XmlTokenizedType ttype = ed.Datatype.TokenizedType;
                if (ttype == XmlTokenizedType.ENUMERATION && 
                    !builder._ElementDef._EnumerationRequired) {
                    builder.SendValidationEvent(Res.Sch_MissDtvaluesAttribute);
                }
 
                if (ttype != XmlTokenizedType.ENUMERATION && 
                    builder._ElementDef._EnumerationRequired) {
                    builder.SendValidationEvent(Res.Sch_RequireEnumeration);
                }
            }
            CompareMinMaxLength(builder._ElementDef._MinLength, builder._ElementDef._MaxLength, builder);
            ed.MaxLength = (long)builder._ElementDef._MaxLength;
            ed.MinLength = (long)builder._ElementDef._MinLength;
            
            if (builder._contentValidator != null) {
                builder._ElementDef._ElementDecl.ContentValidator = builder._contentValidator.Finish(true);
                builder._contentValidator = null;
            }
 
            builder._ElementDef._ElementDecl = null;
            builder._ElementDef._AttDefList = null;
        }
 
 
        //
        // XDR AttributeType
        // 
 
        private static void XDR_InitAttributeType(XdrBuilder builder, object obj) {
            AttributeContent ad = builder._AttributeDef;
            ad._AttDef = new SchemaAttDef(XmlQualifiedName.Empty, null);
 
            ad._Required = false;
            ad._Prefix = null;
 
            ad._Default = null;
            ad._MinVal = 0; // optional by default.
            ad._MaxVal = 1;
 
            // used for datatype
            ad._EnumerationRequired = false;
            ad._HasDataType = false;
            ad._Global = (builder._StateHistory.Length == 2);
 
            ad._MaxLength = uint.MaxValue;
            ad._MinLength = uint.MaxValue;
        }
 
        private static void XDR_BuildAttributeType_Name(XdrBuilder builder, object obj, string prefix) {
            XmlQualifiedName qname = (XmlQualifiedName) obj;
 
            builder._AttributeDef._Name = qname;
            builder._AttributeDef._Prefix = prefix;
            builder._AttributeDef._AttDef.Name = qname;
 
            if (builder._ElementDef._ElementDecl != null) {  // Local AttributeType
                if (builder._ElementDef._AttDefList[qname] == null) {
                    builder._ElementDef._AttDefList.Add(qname, builder._AttributeDef._AttDef);
                }
                else {
                    builder.SendValidationEvent(Res.Sch_DupAttribute, XmlQualifiedName.ToString(qname.Name, prefix));
                }
            }
            else {  // Global AttributeType
                // Global AttributeTypes are URN qualified so that we can look them up across schemas.
                qname = new XmlQualifiedName(qname.Name, builder._TargetNamespace);
                builder._AttributeDef._AttDef.Name = qname;
                if (!builder._SchemaInfo.AttributeDecls.ContainsKey(qname)) {
                    builder._SchemaInfo.AttributeDecls.Add(qname, builder._AttributeDef._AttDef);
                }
                else {
                    builder.SendValidationEvent(Res.Sch_DupAttribute, XmlQualifiedName.ToString(qname.Name, prefix));
                }
            }
        }
 
        private static void XDR_BuildAttributeType_Required(XdrBuilder builder, object obj, string prefix) {
            builder._AttributeDef._Required = IsYes(obj, builder);
        }
 
        private static void XDR_BuildAttributeType_Default(XdrBuilder builder, object obj, string prefix) {
            builder._AttributeDef._Default = obj;
        }
 
        private static void XDR_BuildAttributeType_DtType(XdrBuilder builder, object obj, string prefix) {
            XmlQualifiedName qname = (XmlQualifiedName)obj;
            builder._AttributeDef._HasDataType = true;
            builder._AttributeDef._AttDef.Datatype = builder.CheckDatatype(qname.Name);
        }
 
        private static void XDR_BuildAttributeType_DtValues(XdrBuilder builder, object obj, string prefix) {
            builder._AttributeDef._EnumerationRequired = true;
            builder._AttributeDef._AttDef.Values = new List<string>((string[]) obj);
        }
 
        private static void XDR_BuildAttributeType_DtMaxLength(XdrBuilder builder, object obj, string prefix) {
            ParseDtMaxLength(ref builder._AttributeDef._MaxLength, obj, builder);
        }
 
        private static void XDR_BuildAttributeType_DtMinLength(XdrBuilder builder, object obj, string prefix) {
            ParseDtMinLength(ref builder._AttributeDef._MinLength, obj, builder);
        }
 
        private static void XDR_BeginAttributeType(XdrBuilder builder) {
            if (builder._AttributeDef._Name.IsEmpty) {
                builder.SendValidationEvent(Res.Sch_MissAttribute);
            }
        }
 
        private static void XDR_EndAttributeType(XdrBuilder builder) {
            string code = null;
            if (builder._AttributeDef._HasDataType && builder._AttributeDef._AttDef.Datatype != null) {
                XmlTokenizedType ttype = builder._AttributeDef._AttDef.Datatype.TokenizedType;
 
                if (ttype == XmlTokenizedType.ENUMERATION && !builder._AttributeDef._EnumerationRequired) {
                    code = Res.Sch_MissDtvaluesAttribute;
                    goto cleanup;
                }
 
                if (ttype != XmlTokenizedType.ENUMERATION && builder._AttributeDef._EnumerationRequired) {
                    code = Res.Sch_RequireEnumeration;
                    goto cleanup;
                }
 
                // a attributes of type id is not supposed to have a default value
                if (builder._AttributeDef._Default != null && ttype ==  XmlTokenizedType.ID) {
                    code = Res.Sch_DefaultIdValue;
                    goto cleanup;
                }
            } 
            else {
                builder._AttributeDef._AttDef.Datatype = XmlSchemaDatatype.FromXmlTokenizedType(XmlTokenizedType.CDATA);
            }
 
            //
            // constraints
            //
            CompareMinMaxLength(builder._AttributeDef._MinLength, builder._AttributeDef._MaxLength, builder);
            builder._AttributeDef._AttDef.MaxLength = builder._AttributeDef._MaxLength;
            builder._AttributeDef._AttDef.MinLength = builder._AttributeDef._MinLength;
 
            //
            // checkAttributeType 
            //
            if (builder._AttributeDef._Default != null) {
                builder._AttributeDef._AttDef.DefaultValueRaw = builder._AttributeDef._AttDef.DefaultValueExpanded =  (string)builder._AttributeDef._Default;
                builder.CheckDefaultAttValue(builder._AttributeDef._AttDef);
            }
 
            builder.SetAttributePresence(builder._AttributeDef._AttDef, builder._AttributeDef._Required);
 
            cleanup:
            if (code != null) {
                builder.SendValidationEvent(code);
            }
        }
 
 
        //
        // XDR Element
        //
 
        private static void XDR_InitElement(XdrBuilder builder, object obj) {
            if (builder._ElementDef._HasDataType ||
                (builder._ElementDef._ContentAttr == SchemaContentEmpty) ||
                (builder._ElementDef._ContentAttr == SchemaContentText)) {
                builder.SendValidationEvent(Res.Sch_ElementNotAllowed);
            }
 
            builder._ElementDef._AllowDataType = false;
 
            builder._ElementDef._HasType = false;
            builder._ElementDef._MinVal = 1;
            builder._ElementDef._MaxVal = 1;
        }
 
        private static void XDR_BuildElement_Type(XdrBuilder builder, object obj, string prefix) {
            XmlQualifiedName qname = (XmlQualifiedName) obj;
 
            if (!builder._SchemaInfo.ElementDecls.ContainsKey(qname)) {
                SchemaElementDecl ed = (SchemaElementDecl)builder._UndeclaredElements[qname];
                if (ed == null) {
                    ed = new SchemaElementDecl(qname, prefix);
                    builder._UndeclaredElements.Add(qname, ed);
                }
            }
 
            builder._ElementDef._HasType = true;  
            if (builder._ElementDef._ExistTerminal)
                builder.AddOrder();
            else
                builder._ElementDef._ExistTerminal = true;
 
            builder._contentValidator.AddName(qname, null);
        }
 
        private static void XDR_BuildElement_MinOccurs(XdrBuilder builder, object obj, string prefix) {
            builder._ElementDef._MinVal = ParseMinOccurs(obj, builder);
        }
 
        private static void XDR_BuildElement_MaxOccurs(XdrBuilder builder, object obj, string prefix) {
            builder._ElementDef._MaxVal = ParseMaxOccurs(obj, builder);
        }
 
 
        //    private static void XDR_BeginElement(XdrBuilder builder)
        //  {
        //
        //  }
 
 
        private static void XDR_EndElement(XdrBuilder builder) {
            if (builder._ElementDef._HasType) {
                HandleMinMax(builder._contentValidator,
                             builder._ElementDef._MinVal, 
                             builder._ElementDef._MaxVal);
            }
            else {
                builder.SendValidationEvent(Res.Sch_MissAttribute);
            }
        }
 
 
        //
        // XDR Attribute
        //
 
        private static void XDR_InitAttribute(XdrBuilder builder, object obj) {
            if (builder._BaseDecl == null)
                builder._BaseDecl = new DeclBaseInfo();
            builder._BaseDecl._MinOccurs = 0;
        }
 
        private static void XDR_BuildAttribute_Type(XdrBuilder builder, object obj, string prefix) {
            builder._BaseDecl._TypeName = (XmlQualifiedName)obj;
            builder._BaseDecl._Prefix = prefix;
        }
 
        private static void XDR_BuildAttribute_Required(XdrBuilder builder, object obj, string prefix) {
            if (IsYes(obj, builder)) {
                builder._BaseDecl._MinOccurs = 1;
            }
        }
 
        private static void XDR_BuildAttribute_Default(XdrBuilder builder, object obj, string prefix) {
            builder._BaseDecl._Default = obj;
        }
 
        private static void XDR_BeginAttribute(XdrBuilder builder) {
            if (builder._BaseDecl._TypeName.IsEmpty) {
                builder.SendValidationEvent(Res.Sch_MissAttribute);
            }
 
            SchemaAttDef attdef = null;
            XmlQualifiedName qname = builder._BaseDecl._TypeName;
            string prefix = builder._BaseDecl._Prefix;
 
            // local?
            if (builder._ElementDef._AttDefList != null) {
                attdef = (SchemaAttDef)builder._ElementDef._AttDefList[qname];
            }
 
            // global?
            if (attdef == null) {
                // if there is no URN in this name then the name is local to the
                // schema, but the global attribute was still URN qualified, so
                // we need to qualify this name now.
                XmlQualifiedName gname = qname;
                if (prefix.Length == 0)
                    gname = new XmlQualifiedName(qname.Name, builder._TargetNamespace);
                SchemaAttDef ad;
                if (builder._SchemaInfo.AttributeDecls.TryGetValue(gname, out ad)) {
                    attdef = (SchemaAttDef)ad.Clone();
                    attdef.Name = qname;
                }
                else if (prefix.Length != 0) {
                    builder.SendValidationEvent(Res.Sch_UndeclaredAttribute, XmlQualifiedName.ToString(qname.Name, prefix));
                }
            }
 
            if (attdef != null) {
                builder.XDR_CheckAttributeDefault(builder._BaseDecl, attdef);
            }
            else {
                // will process undeclared types later
                attdef = new SchemaAttDef(qname, prefix);
                DeclBaseInfo decl = new DeclBaseInfo();
                decl._Checking = true;
                decl._Attdef = attdef;
                decl._TypeName = builder._BaseDecl._TypeName;
                decl._ElementDecl = builder._ElementDef._ElementDecl;
                decl._MinOccurs = builder._BaseDecl._MinOccurs;
                decl._Default = builder._BaseDecl._Default;
 
                // add undefined attribute types
                decl._Next = builder._UndefinedAttributeTypes;
                builder._UndefinedAttributeTypes = decl;
            }
 
            builder._ElementDef._ElementDecl.AddAttDef(attdef);
        }
 
        private static void XDR_EndAttribute(XdrBuilder builder) {
            builder._BaseDecl.Reset();
        }
 
 
        //
        // XDR Group
        //
 
        private static void XDR_InitGroup(XdrBuilder builder, object obj) {
            if (builder._ElementDef._ContentAttr == SchemaContentEmpty ||
                builder._ElementDef._ContentAttr == SchemaContentText ) {
                builder.SendValidationEvent(Res.Sch_GroupDisabled);
            }
 
            builder.PushGroupInfo();
 
            builder._GroupDef._MinVal = 1;
            builder._GroupDef._MaxVal = 1;
            builder._GroupDef._HasMaxAttr = false;
            builder._GroupDef._HasMinAttr = false;
 
            if (builder._ElementDef._ExistTerminal)
                builder.AddOrder();
 
            // now we are in a group so we reset fExistTerminal
            builder._ElementDef._ExistTerminal = false;
 
            builder._contentValidator.OpenGroup();
        }
 
        private static void XDR_BuildGroup_Order(XdrBuilder builder, object obj, string prefix) {
            builder._GroupDef._Order = builder.GetOrder((XmlQualifiedName)obj);
            if (builder._ElementDef._ContentAttr == SchemaContentMixed && builder._GroupDef._Order != SchemaOrderMany) {
                builder.SendValidationEvent(Res.Sch_MixedMany);
            }
        }
 
        private static void XDR_BuildGroup_MinOccurs(XdrBuilder builder, object obj, string prefix) {
            builder._GroupDef._MinVal = ParseMinOccurs(obj, builder);
            builder._GroupDef._HasMinAttr = true;
        }
 
        private static void XDR_BuildGroup_MaxOccurs(XdrBuilder builder, object obj, string prefix) {
            builder._GroupDef._MaxVal = ParseMaxOccurs(obj, builder);
            builder._GroupDef._HasMaxAttr = true;
        }
 
 
        //    private static void XDR_BeginGroup(XdrBuilder builder)
        //    {
        //
        //    }
 
 
        private static void XDR_EndGroup(XdrBuilder builder) {
            if (!builder._ElementDef._ExistTerminal) {
                builder.SendValidationEvent(Res.Sch_ElementMissing);
            }
 
            builder._contentValidator.CloseGroup();
 
            if (builder._GroupDef._Order == SchemaOrderMany) {
                builder._contentValidator.AddStar();
            }
            
            if (SchemaOrderMany == builder._GroupDef._Order &&
                builder._GroupDef._HasMaxAttr &&
                builder._GroupDef._MaxVal != uint.MaxValue) {
                builder.SendValidationEvent(Res.Sch_ManyMaxOccurs);
            }
 
            HandleMinMax(builder._contentValidator,
                         builder._GroupDef._MinVal, 
                         builder._GroupDef._MaxVal);
 
            builder.PopGroupInfo();
        }
 
 
        //
        // DataType
        //
 
        private static void XDR_InitElementDtType(XdrBuilder builder, object obj) {
            if (builder._ElementDef._HasDataType) {
                builder.SendValidationEvent(Res.Sch_DupDtType);
            }
 
            if (!builder._ElementDef._AllowDataType) {
                builder.SendValidationEvent(Res.Sch_DataTypeTextOnly);
            }
        }
 
        private static void XDR_EndElementDtType(XdrBuilder builder) {
            if (!builder._ElementDef._HasDataType) {
                builder.SendValidationEvent(Res.Sch_MissAttribute);
            }
            builder._ElementDef._ElementDecl.ContentValidator = ContentValidator.TextOnly;
            builder._ElementDef._ContentAttr = SchemaContentText;
            builder._ElementDef._MasterGroupRequired = false;
            builder._contentValidator = null;
        }
 
        private static void XDR_InitAttributeDtType(XdrBuilder builder, object obj) {
            if (builder._AttributeDef._HasDataType) {
                builder.SendValidationEvent(Res.Sch_DupDtType);
            }
        }
 
        private static void XDR_EndAttributeDtType(XdrBuilder builder) {
            string code = null;
 
            if (!builder._AttributeDef._HasDataType) {
                code = Res.Sch_MissAttribute;
            } 
            else {
                if(builder._AttributeDef._AttDef.Datatype != null) {
                    XmlTokenizedType ttype = builder._AttributeDef._AttDef.Datatype.TokenizedType;
 
                    if (ttype == XmlTokenizedType.ENUMERATION && !builder._AttributeDef._EnumerationRequired) {
                        code = Res.Sch_MissDtvaluesAttribute;
                    }
                    else if (ttype != XmlTokenizedType.ENUMERATION && builder._AttributeDef._EnumerationRequired) {
                        code = Res.Sch_RequireEnumeration;
                    }
                }
            }
            if (code != null) {
                builder.SendValidationEvent(code);
            }
        }
 
        //
        // private utility methods
        //
 
        private bool GetNextState(XmlQualifiedName qname) {
            if (_CurState._NextStates != null) {
                for (int i = 0; i < _CurState._NextStates.Length; i ++) {
                    if (_SchemaNames.TokenToQName[(int)S_SchemaEntries[_CurState._NextStates[i]]._Name].Equals(qname)) {
                        _NextState = S_SchemaEntries[_CurState._NextStates[i]];
                        return true;
                    }
                }
            }
 
            return false;
        }
 
        private bool IsSkipableElement(XmlQualifiedName qname) {
            string ns = qname.Namespace;
            if (ns != null && ! Ref.Equal(ns, _SchemaNames.NsXdr))
                return true;
 
            // skip description && extends
            if (_SchemaNames.TokenToQName[(int)SchemaNames.Token.XdrDescription].Equals(qname) ||
                _SchemaNames.TokenToQName[(int)SchemaNames.Token.XdrExtends].Equals(qname))
                return true;
 
            return false;
        }
 
        private bool IsSkipableAttribute(XmlQualifiedName qname) {
            string ns = qname.Namespace;
            if (
                ns.Length != 0 &&
                ! Ref.Equal(ns, _SchemaNames.NsXdr) && 
                ! Ref.Equal(ns, _SchemaNames.NsDataType)
             ) {
                return true;
            }
 
            if (Ref.Equal(ns, _SchemaNames.NsDataType) && 
                _CurState._Name == SchemaNames.Token.XdrDatatype &&
                (_SchemaNames.QnDtMax.Equals(qname) ||
                 _SchemaNames.QnDtMin.Equals(qname) ||
                 _SchemaNames.QnDtMaxExclusive.Equals(qname) ||
                 _SchemaNames.QnDtMinExclusive.Equals(qname) )) {
                return true;
            }
 
            return false;
        }
 
        private int GetOrder(XmlQualifiedName qname) {
            int order = 0;
            if (_SchemaNames.TokenToQName[(int)SchemaNames.Token.SchemaSeq].Equals(qname)) {
                order = SchemaOrderSequence;
            }
            else if (_SchemaNames.TokenToQName[(int)SchemaNames.Token.SchemaOne].Equals(qname)) {
                order = SchemaOrderChoice;
            }
            else if (_SchemaNames.TokenToQName[(int)SchemaNames.Token.SchemaMany].Equals(qname)) {
                order = SchemaOrderMany;
            }
            else {
                SendValidationEvent(Res.Sch_UnknownOrder, qname.Name);
            }
 
            return order;
        }
 
        private void AddOrder() {
            // additional order can be add on by changing the setOrder and addOrder
            switch (_GroupDef._Order) {
                case SchemaOrderSequence:
                    _contentValidator.AddSequence();
                    break;
                case SchemaOrderChoice:
                case SchemaOrderMany:
                    _contentValidator.AddChoice();
                    break;
                default: 
                case SchemaOrderAll:             
                    throw new XmlException(Res.Xml_UnexpectedToken, "NAME");
            }
        }
 
        private static bool IsYes(object obj, XdrBuilder builder) {
            XmlQualifiedName qname = (XmlQualifiedName)obj;
            bool fYes = false;
 
            if (qname.Name == "yes") {
                fYes = true;
            }
            else if (qname.Name != "no") {
                builder.SendValidationEvent(Res.Sch_UnknownRequired);
            }
 
            return fYes;
        }
 
        private static uint ParseMinOccurs(object obj, XdrBuilder builder) {
            uint cVal = 1;
 
            if (!ParseInteger((string) obj, ref cVal) || (cVal != 0 && cVal != 1)) {
                builder.SendValidationEvent(Res.Sch_MinOccursInvalid);
            }
            return cVal;
        }
 
        private static uint ParseMaxOccurs(object obj, XdrBuilder builder) {
            uint cVal = uint.MaxValue;
            string s = (string)obj;
 
            if (!s.Equals("*") &&
                (!ParseInteger(s, ref cVal) || (cVal != uint.MaxValue && cVal != 1))) {
                builder.SendValidationEvent(Res.Sch_MaxOccursInvalid);
            }
            return cVal;
        }
 
        private static void HandleMinMax(ParticleContentValidator pContent, uint cMin, uint cMax) {
            if (pContent != null) {
                if (cMax == uint.MaxValue) {
                    if (cMin == 0)
                        pContent.AddStar();           // minOccurs="0" and maxOccurs="infinite"
                    else
                        pContent.AddPlus();           // minOccurs="1" and maxOccurs="infinite"
                }
                else if (cMin == 0) {                 // minOccurs="0" and maxOccurs="1")
                    pContent.AddQMark();
                }
            }
        }
 
        private static void ParseDtMaxLength(ref uint cVal, object obj, XdrBuilder builder) {
            if (uint.MaxValue != cVal) {
                builder.SendValidationEvent(Res.Sch_DupDtMaxLength);
            }
 
            if (!ParseInteger((string) obj, ref cVal) || cVal < 0) {
                builder.SendValidationEvent(Res.Sch_DtMaxLengthInvalid, obj.ToString());
            }
        }
 
        private static void ParseDtMinLength(ref uint cVal, object obj, XdrBuilder builder) {
            if (uint.MaxValue != cVal) {
                builder.SendValidationEvent(Res.Sch_DupDtMinLength);
            }
 
            if (!ParseInteger((string)obj, ref cVal) || cVal < 0) {
                builder.SendValidationEvent(Res.Sch_DtMinLengthInvalid, obj.ToString());
            }
        }
 
        private static void CompareMinMaxLength(uint cMin, uint cMax, XdrBuilder builder) {
            if (cMin != uint.MaxValue && cMax != uint.MaxValue && cMin > cMax) {
                builder.SendValidationEvent(Res.Sch_DtMinMaxLength);
            }
        }
 
        private static bool ParseInteger(string str, ref uint n) {
            return UInt32.TryParse(str,NumberStyles.AllowLeadingWhite|NumberStyles.AllowTrailingWhite, NumberFormatInfo.InvariantInfo, out n); 
        }
 
        private void XDR_CheckAttributeDefault(DeclBaseInfo decl, SchemaAttDef pAttdef) {
            if (decl._Default != null || pAttdef.DefaultValueTyped != null) {
                if (decl._Default != null) {
                    pAttdef.DefaultValueRaw = pAttdef.DefaultValueExpanded = (string)decl._Default;                    
                    CheckDefaultAttValue(pAttdef);
                }
            }
 
            SetAttributePresence(pAttdef, 1 == decl._MinOccurs);
        }
 
        private void SetAttributePresence(SchemaAttDef pAttdef, bool fRequired) {
            if (SchemaDeclBase.Use.Fixed != pAttdef.Presence) {
                if (fRequired || SchemaDeclBase.Use.Required == pAttdef.Presence) {
                    // If it is required and it has a default value then it is a FIXED attribute.
                    if (pAttdef.DefaultValueTyped != null)
                        pAttdef.Presence = SchemaDeclBase.Use.Fixed;
                    else
                        pAttdef.Presence = SchemaDeclBase.Use.Required;
                }
                else if (pAttdef.DefaultValueTyped != null) {
                    pAttdef.Presence = SchemaDeclBase.Use.Default;
                }
                else {
                    pAttdef.Presence = SchemaDeclBase.Use.Implied;
                }
            }
        }
 
        private int GetContent(XmlQualifiedName qname) {
            int content = 0;
            if (_SchemaNames.TokenToQName[(int)SchemaNames.Token.SchemaEmpty].Equals(qname)) {
                content = SchemaContentEmpty;
                _ElementDef._AllowDataType = false;
            }
            else if (_SchemaNames.TokenToQName[(int)SchemaNames.Token.SchemaElementOnly].Equals(qname)) {
                content = SchemaContentElement;
                _ElementDef._AllowDataType = false;
            }
            else if (_SchemaNames.TokenToQName[(int)SchemaNames.Token.SchemaMixed].Equals(qname)) {
                content = SchemaContentMixed;
                _ElementDef._AllowDataType = false;
            }
            else if (_SchemaNames.TokenToQName[(int)SchemaNames.Token.SchemaTextOnly].Equals(qname)) {
                content = SchemaContentText;
            }
            else {
                SendValidationEvent(Res.Sch_UnknownContent, qname.Name);
            }
            return content;
        }
 
        private bool GetModel(XmlQualifiedName qname) {
            bool fOpen = false;
            if (_SchemaNames.TokenToQName[(int)SchemaNames.Token.SchemaOpen].Equals(qname))
                fOpen = true;
            else if (_SchemaNames.TokenToQName[(int)SchemaNames.Token.SchemaClosed].Equals(qname))
                fOpen = false;
            else
                SendValidationEvent(Res.Sch_UnknownModel, qname.Name);
            return fOpen;
        }
 
        private XmlSchemaDatatype CheckDatatype(string str) {
            XmlSchemaDatatype dtype = XmlSchemaDatatype.FromXdrName(str);
            if (dtype == null) {
                SendValidationEvent(Res.Sch_UnknownDtType, str);
            } 
            else if (dtype.TokenizedType == XmlTokenizedType.ID) {
                if (! _AttributeDef._Global) {
                    if (_ElementDef._ElementDecl.IsIdDeclared) {
                        SendValidationEvent(Res.Sch_IdAttrDeclared, 
                                            XmlQualifiedName.ToString(_ElementDef._ElementDecl.Name.Name, _ElementDef._ElementDecl.Prefix));
                    }
                    _ElementDef._ElementDecl.IsIdDeclared = true;
                }
            }
 
            return dtype;
        }
 
        private void CheckDefaultAttValue(SchemaAttDef attDef) {
            string str = (attDef.DefaultValueRaw).Trim();
            XdrValidator.CheckDefaultValue(str, attDef, _SchemaInfo, _CurNsMgr, _NameTable, null, validationEventHandler, _reader.BaseURI, positionInfo.LineNumber, positionInfo.LinePosition);
        }
 
        private bool IsGlobal(int flags) {
            return flags == SchemaFlagsNs;
        }
 
        private void SendValidationEvent(string code, string[] args, XmlSeverityType severity) {
            SendValidationEvent(new XmlSchemaException(code, args, this._reader.BaseURI, this.positionInfo.LineNumber, this.positionInfo.LinePosition), severity);
        }
 
        private void SendValidationEvent(string code) {
            SendValidationEvent(code, string.Empty);
        }
 
        private void SendValidationEvent(string code, string msg) {
            SendValidationEvent(new XmlSchemaException(code, msg, this._reader.BaseURI, this.positionInfo.LineNumber, this.positionInfo.LinePosition), XmlSeverityType.Error);
        }
 
        private void SendValidationEvent(XmlSchemaException e, XmlSeverityType severity) {
            _SchemaInfo.ErrorCount ++;
            if (validationEventHandler != null) {
                validationEventHandler(this, new ValidationEventArgs(e, severity));
            }
            else if (severity == XmlSeverityType.Error) {
                throw e;
            }
        }
 
 
    }; // class XdrBuilder
 
} // namespace System.Xml