The Labs \ Source Viewer \ SSCLI \ System.Xml \ DtdParser

  1. //------------------------------------------------------------------------------
  2. // <copyright file="DtdParser.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.IO;
  17. using System.Text;
  18. using System.Xml.Schema;
  19. using System.Diagnostics;
  20. using System.Collections;
  21. using System.Globalization;
  22. namespace System.Xml
  23. {
  24.    
  25.     internal class DtdParser
  26.     {
  27.         //
  28.         // Private types
  29.         //
  30.         enum Token
  31.         {
  32.             CDATA = XmlTokenizedType.CDATA,
  33.             // == 0
  34.             ID = XmlTokenizedType.ID,
  35.             // == 1
  36.             IDREF = XmlTokenizedType.IDREF,
  37.             // == 2
  38.             IDREFS = XmlTokenizedType.IDREFS,
  39.             // == 3
  40.             ENTITY = XmlTokenizedType.ENTITY,
  41.             // == 4
  42.             ENTITIES = XmlTokenizedType.ENTITIES,
  43.             // == 5
  44.             NMTOKEN = XmlTokenizedType.NMTOKEN,
  45.             // == 6
  46.             NMTOKENS = XmlTokenizedType.NMTOKENS,
  47.             // == 7
  48.             NOTATION = XmlTokenizedType.NOTATION,
  49.             // == 8
  50.             None,
  51.             PERef,
  52.             AttlistDecl,
  53.             ElementDecl,
  54.             EntityDecl,
  55.             NotationDecl,
  56.             Comment,
  57.             PI,
  58.             CondSectionStart,
  59.             CondSectionEnd,
  60.             Eof,
  61.             REQUIRED,
  62.             IMPLIED,
  63.             FIXED,
  64.             QName,
  65.             Name,
  66.             Nmtoken,
  67.             Quote,
  68.             LeftParen,
  69.             RightParen,
  70.             GreaterThan,
  71.             Or,
  72.             LeftBracket,
  73.             RightBracket,
  74.             PUBLIC,
  75.             SYSTEM,
  76.             Literal,
  77.             DOCTYPE,
  78.             NData,
  79.             Percent,
  80.             Star,
  81.             QMark,
  82.             Plus,
  83.             PCDATA,
  84.             Comma,
  85.             ANY,
  86.             EMPTY,
  87.             IGNORE,
  88.             INCLUDE
  89.         }
  90.        
  91.         enum ScanningFunction
  92.         {
  93.             SubsetContent,
  94.             Name,
  95.             QName,
  96.             Nmtoken,
  97.             Doctype1,
  98.             Doctype2,
  99.             Element1,
  100.             Element2,
  101.             Element3,
  102.             Element4,
  103.             Element5,
  104.             Element6,
  105.             Element7,
  106.             Attlist1,
  107.             Attlist2,
  108.             Attlist3,
  109.             Attlist4,
  110.             Attlist5,
  111.             Attlist6,
  112.             Attlist7,
  113.             Entity1,
  114.             Entity2,
  115.             Entity3,
  116.             Notation1,
  117.             CondSection1,
  118.             CondSection2,
  119.             CondSection3,
  120.             Literal,
  121.             SystemId,
  122.             PublicId1,
  123.             PublicId2,
  124.             ClosingTag,
  125.             ParamEntitySpace,
  126.             None
  127.         }
  128.        
  129.         enum LiteralType
  130.         {
  131.             AttributeValue,
  132.             EntityReplText,
  133.             SystemOrPublicID
  134.         }
  135.        
  136.         class UndeclaredNotation
  137.         {
  138.             internal string name;
  139.             internal int lineNo;
  140.             internal int linePos;
  141.             internal UndeclaredNotation next;
  142.            
  143.             internal UndeclaredNotation(string name, int lineNo, int linePos)
  144.             {
  145.                 this.name = name;
  146.                 this.lineNo = lineNo;
  147.                 this.linePos = linePos;
  148.                 this.next = null;
  149.             }
  150.         }
  151.        
  152.         //
  153.         // Fields
  154.         //
  155.         // connector to reader
  156.         IDtdParserAdapter readerAdapter;
  157.        
  158.         // name table
  159.         XmlNameTable nameTable;
  160.        
  161.         // final schema info
  162.         SchemaInfo schemaInfo;
  163.        
  164.         // XmlCharType instance
  165.         XmlCharType xmlCharType = XmlCharType.Instance;
  166.        
  167.         // system & public id
  168.         string systemId = string.Empty;
  169.         string publicId = string.Empty;
  170.        
  171.         // flags
  172.         bool validate;
  173.         bool normalize;
  174.         bool supportNamespaces;
  175.         bool v1Compat;
  176.        
  177.         // cached character buffer
  178.         char[] chars;
  179.         int charsUsed;
  180.         int curPos;
  181.        
  182.         // scanning function for the next token
  183.         ScanningFunction scanningFunction;
  184.         ScanningFunction nextScaningFunction;
  185.         ScanningFunction savedScanningFunction;
  186.         // this one is used only for adding spaces around parameter entities
  187.         // flag if whitespace seen before token
  188.         bool whitespaceSeen;
  189.        
  190.         // start position of the last token (for name and value)
  191.         int tokenStartPos;
  192.        
  193.         // colon position (for name)
  194.         int colonPos;
  195.        
  196.         // value of the internal subset
  197.         BufferBuilder internalSubsetValueSb = null;
  198.         string internalSubsetValue = string.Empty;
  199.        
  200.         // entities
  201.         int externalEntitiesDepth = 0;
  202.         int currentEntityId = 0;
  203.         int nextEntityId = 1;
  204.         int[] condSectionEntityIds = null;
  205.        
  206.         // free-floating DTD support
  207.         bool freeFloatingDtd = false;
  208.         bool hasFreeFloatingInternalSubset = false;
  209.        
  210.         // misc
  211.         BufferBuilder stringBuilder;
  212.         Hashtable undeclaredNotations = null;
  213.         int condSectionDepth = 0;
  214.         LineInfo literalLineInfo = new LineInfo(0, 0);
  215.         char literalQuoteChar = '"';
  216.         string documentBaseUri = string.Empty;
  217.         string externalDtdBaseUri = string.Empty;
  218.        
  219.         const int CondSectionEntityIdsInitialSize = 2;
  220.        
  221.         //
  222.         // Constructor
  223.         //
  224.        
  225.         #if DEBUG
  226.         static DtdParser()
  227.         {
  228.             // The absolute numbering is utilized in attribute type parsing
  229.             Debug.Assert((int)Token.CDATA == (int)XmlTokenizedType.CDATA && (int)XmlTokenizedType.CDATA == 0);
  230.             Debug.Assert((int)Token.ID == (int)XmlTokenizedType.ID && (int)XmlTokenizedType.ID == 1);
  231.             Debug.Assert((int)Token.IDREF == (int)XmlTokenizedType.IDREF && (int)XmlTokenizedType.IDREF == 2);
  232.             Debug.Assert((int)Token.IDREFS == (int)XmlTokenizedType.IDREFS && (int)XmlTokenizedType.IDREFS == 3);
  233.             Debug.Assert((int)Token.ENTITY == (int)XmlTokenizedType.ENTITY && (int)XmlTokenizedType.ENTITY == 4);
  234.             Debug.Assert((int)Token.ENTITIES == (int)XmlTokenizedType.ENTITIES && (int)XmlTokenizedType.ENTITIES == 5);
  235.             Debug.Assert((int)Token.NMTOKEN == (int)XmlTokenizedType.NMTOKEN && (int)XmlTokenizedType.NMTOKEN == 6);
  236.             Debug.Assert((int)Token.NMTOKENS == (int)XmlTokenizedType.NMTOKENS && (int)XmlTokenizedType.NMTOKENS == 7);
  237.             Debug.Assert((int)Token.NOTATION == (int)XmlTokenizedType.NOTATION && (int)XmlTokenizedType.NOTATION == 8);
  238.         }
  239.         #endif
  240.        
  241.         internal DtdParser(IDtdParserAdapter readerAdapter)
  242.         {
  243.             Debug.Assert(readerAdapter != null);
  244.             this.readerAdapter = readerAdapter;
  245.            
  246.             nameTable = readerAdapter.NameTable;
  247.            
  248.             validate = readerAdapter.DtdValidation;
  249.             normalize = readerAdapter.Normalization;
  250.             supportNamespaces = readerAdapter.Namespaces;
  251.             v1Compat = readerAdapter.V1CompatibilityMode;
  252.            
  253.             schemaInfo = new SchemaInfo();
  254.             schemaInfo.SchemaType = SchemaType.DTD;
  255.            
  256.             stringBuilder = new BufferBuilder();
  257.            
  258.             Uri baseUri = readerAdapter.BaseUri;
  259.             if (baseUri != null) {
  260.                 documentBaseUri = baseUri.ToString();
  261.             }
  262.         }
  263.        
  264.         internal DtdParser(string baseUri, string docTypeName, string publicId, string systemId, string internalSubset, IDtdParserAdapter underlyingReader) : this(underlyingReader)
  265.         {
  266.            
  267.             if (docTypeName == null || docTypeName.Length == 0) {
  268.                 throw XmlConvert.CreateInvalidNameArgumentException(docTypeName, "docTypeName");
  269.             }
  270.            
  271.             // check doctype name
  272.             XmlConvert.VerifyName(docTypeName);
  273.             int colonPos = docTypeName.IndexOf(':');
  274.             if (colonPos == -1) {
  275.                 schemaInfo.DocTypeName = new XmlQualifiedName(nameTable.Add(docTypeName));
  276.             }
  277.             else {
  278.                 schemaInfo.DocTypeName = new XmlQualifiedName(nameTable.Add(docTypeName.Substring(0, colonPos)), nameTable.Add(docTypeName.Substring(colonPos + 1)));
  279.             }
  280.            
  281.             int i;
  282.             // check system id
  283.             if (systemId != null && systemId.Length > 0) {
  284.                 if ((i = xmlCharType.IsOnlyCharData(systemId)) >= 0) {
  285.                     ThrowInvalidChar(curPos, systemId[i]);
  286.                 }
  287.                 this.systemId = systemId;
  288.             }
  289.            
  290.             // check public id
  291.             if (publicId != null && publicId.Length > 0) {
  292.                 if ((i = xmlCharType.IsPublicId(publicId)) >= 0) {
  293.                     ThrowInvalidChar(curPos, publicId[i]);
  294.                 }
  295.                 this.publicId = publicId;
  296.             }
  297.            
  298.             // init free-floating internal subset
  299.             if (internalSubset != null && internalSubset.Length > 0) {
  300.                 readerAdapter.PushInternalDtd(baseUri, internalSubset);
  301.                 hasFreeFloatingInternalSubset = true;
  302.             }
  303.            
  304.             Uri baseUriOb = readerAdapter.BaseUri;
  305.             if (baseUriOb != null) {
  306.                 documentBaseUri = baseUriOb.ToString();
  307.             }
  308.            
  309.             freeFloatingDtd = true;
  310.         }
  311.        
  312.         //
  313.         // Internal static Parse method
  314.         //
  315.         static internal SchemaInfo Parse(XmlNameTable nt, XmlNamespaceManager nsManager, bool namespaces, string baseUri, string docTypeName, string publicId, string systemId, string internalSubset, bool useResolver, XmlResolver resolver
  316.         )
  317.         {
  318.            
  319.             XmlParserContext pc = new XmlParserContext(nt, nsManager, null, null, null, null, baseUri, string.Empty, XmlSpace.None);
  320.             XmlTextReaderImpl tr = new XmlTextReaderImpl("", XmlNodeType.Element, pc);
  321.             tr.Namespaces = namespaces;
  322.             if (useResolver) {
  323.                 tr.XmlResolver = resolver;
  324.             }
  325.            
  326.             return DtdParser.Parse(tr, baseUri, docTypeName, publicId, systemId, internalSubset);
  327.         }
  328.        
  329.         static internal SchemaInfo Parse(XmlTextReaderImpl tr, string baseUri, string docTypeName, string publicId, string systemId, string internalSubset)
  330.         {
  331.             XmlTextReaderImpl.DtdParserProxy dtdParserProxy = new XmlTextReaderImpl.DtdParserProxy(baseUri, docTypeName, publicId, systemId, internalSubset, tr);
  332.             dtdParserProxy.Parse(false);
  333.             return dtdParserProxy.DtdSchemaInfo;
  334.         }
  335.         //
  336.         // Internal properties for readers
  337.         //
  338.         internal string SystemID {
  339.             get { return systemId; }
  340.         }
  341.        
  342.         internal string PublicID {
  343.             get { return publicId; }
  344.         }
  345.        
  346.         internal string InternalSubset {
  347.             get { return internalSubsetValue; }
  348.         }
  349.        
  350.         internal SchemaInfo SchemaInfo {
  351.             get { return schemaInfo; }
  352.         }
  353.        
  354.         //
  355.         // Private properties
  356.         //
  357.         private bool ParsingInternalSubset {
  358.             get { return externalEntitiesDepth == 0; }
  359.         }
  360.        
  361.         private bool IgnoreEntityReferences {
  362.             get { return scanningFunction == ScanningFunction.CondSection3; }
  363.         }
  364.        
  365.         private bool SaveInternalSubsetValue {
  366.             get { return readerAdapter.EntityStackLength == 0 && internalSubsetValueSb != null; }
  367.         }
  368.        
  369.         private bool ParsingTopLevelMarkup {
  370.             get { return scanningFunction == ScanningFunction.SubsetContent || (scanningFunction == ScanningFunction.ParamEntitySpace && savedScanningFunction == ScanningFunction.SubsetContent); }
  371.         }
  372.        
  373.         //
  374.         // Parsing methods
  375.         //
  376.         internal void Parse(bool saveInternalSubset)
  377.         {
  378.             if (freeFloatingDtd) {
  379.                 ParseFreeFloatingDtd();
  380.             }
  381.             else {
  382.                 ParseInDocumentDtd(saveInternalSubset);
  383.             }
  384.            
  385.             schemaInfo.Finish();
  386.            
  387.             // check undeclared forward references
  388.             if (validate && undeclaredNotations != null) {
  389.                 foreach (UndeclaredNotation un in undeclaredNotations.Values) {
  390.                     UndeclaredNotation tmpUn = un;
  391.                     while (tmpUn != null) {
  392.                         SendValidationEvent(XmlSeverityType.Error, new XmlSchemaException(Res.Sch_UndeclaredNotation, un.name, BaseUriStr, (int)un.lineNo, (int)un.linePos));
  393.                         tmpUn = tmpUn.next;
  394.                     }
  395.                 }
  396.             }
  397.         }
  398.        
  399.         private void ParseInDocumentDtd(bool saveInternalSubset)
  400.         {
  401.             LoadParsingBuffer();
  402.            
  403.             scanningFunction = ScanningFunction.QName;
  404.             nextScaningFunction = ScanningFunction.Doctype1;
  405.            
  406.             // doctype name
  407.             if (GetToken(false) != Token.QName) {
  408.                 OnUnexpectedError();
  409.             }
  410.             schemaInfo.DocTypeName = GetNameQualified(true);
  411.            
  412.             // SYSTEM or PUBLIC id
  413.             Token token = GetToken(false);
  414.             if (token == Token.SYSTEM || token == Token.PUBLIC) {
  415.                 ParseExternalId(token, Token.DOCTYPE, out publicId, out systemId);
  416.                 token = GetToken(false);
  417.             }
  418.            
  419.             switch (token) {
  420.                 case Token.LeftBracket:
  421.                     if (saveInternalSubset) {
  422.                         SaveParsingBuffer();
  423.                         // this will cause saving the internal subset right from the point after '['
  424.                         internalSubsetValueSb = new BufferBuilder();
  425.                     }
  426.                     ParseInternalSubset();
  427.                     break;
  428.                 case Token.GreaterThan:
  429.                     break;
  430.                 default:
  431.                     OnUnexpectedError();
  432.                     break;
  433.             }
  434.             SaveParsingBuffer();
  435.            
  436.             if (systemId != null && systemId.Length > 0) {
  437.                 ParseExternalSubset();
  438.             }
  439.         }
  440.        
  441.         private void ParseFreeFloatingDtd()
  442.         {
  443.            
  444.             if (hasFreeFloatingInternalSubset) {
  445.                 LoadParsingBuffer();
  446.                 ParseInternalSubset();
  447.                 SaveParsingBuffer();
  448.             }
  449.            
  450.             if (systemId != null && systemId.Length > 0) {
  451.                 ParseExternalSubset();
  452.             }
  453.         }
  454.        
  455.         private void ParseInternalSubset()
  456.         {
  457.             Debug.Assert(ParsingInternalSubset);
  458.             ParseSubset();
  459.         }
  460.        
  461.         private void ParseExternalSubset()
  462.         {
  463.             Debug.Assert(externalEntitiesDepth == 0);
  464.            
  465.             // push external subset
  466.             if (!readerAdapter.PushExternalSubset(systemId, publicId)) {
  467.                 return;
  468.             }
  469.            
  470.             Uri baseUri = readerAdapter.BaseUri;
  471.             if (baseUri != null) {
  472.                 externalDtdBaseUri = baseUri.ToString();
  473.             }
  474.            
  475.             externalEntitiesDepth++;
  476.             LoadParsingBuffer();
  477.            
  478.             // parse
  479.             ParseSubset();
  480.            
  481.             #if DEBUG
  482.             Debug.Assert(readerAdapter.EntityStackLength == 0 || (freeFloatingDtd && readerAdapter.EntityStackLength == 1));
  483.             #endif
  484.         }
  485.        
  486.         private void ParseSubset()
  487.         {
  488.             int startTagEntityId;
  489.             for (;;) {
  490.                 Token token = GetToken(false);
  491.                 startTagEntityId = currentEntityId;
  492.                 switch (token) {
  493.                     case Token.AttlistDecl:
  494.                         ParseAttlistDecl();
  495.                         break;
  496.                     case Token.ElementDecl:
  497.                        
  498.                         ParseElementDecl();
  499.                         break;
  500.                     case Token.EntityDecl:
  501.                        
  502.                         ParseEntityDecl();
  503.                         break;
  504.                     case Token.NotationDecl:
  505.                        
  506.                         ParseNotationDecl();
  507.                         break;
  508.                     case Token.Comment:
  509.                        
  510.                         ParseComment();
  511.                         break;
  512.                     case Token.PI:
  513.                        
  514.                         ParsePI();
  515.                         break;
  516.                     case Token.CondSectionStart:
  517.                        
  518.                         if (ParsingInternalSubset) {
  519.                             Throw(curPos - 3, Res.Xml_InvalidConditionalSection);
  520.                             // 3==strlen("<![")
  521.                         }
  522.                         ParseCondSection();
  523.                         startTagEntityId = currentEntityId;
  524.                         break;
  525.                     case Token.CondSectionEnd:
  526.                         if (condSectionDepth > 0) {
  527.                             condSectionDepth--;
  528.                             if (validate && currentEntityId != condSectionEntityIds[condSectionDepth]) {
  529.                                 SendValidationEvent(curPos, XmlSeverityType.Error, Res.Sch_ParEntityRefNesting, string.Empty);
  530.                             }
  531.                         }
  532.                         else {
  533.                             Throw(curPos - 3, Res.Xml_UnexpectedCDataEnd);
  534.                         }
  535.                         break;
  536.                     case Token.RightBracket:
  537.                         if (ParsingInternalSubset) {
  538.                             if (condSectionDepth != 0) {
  539.                                 Throw(curPos, Res.Xml_UnclosedConditionalSection);
  540.                             }
  541.                             // append the rest to internal subset value but not the closing ']'
  542.                             if (internalSubsetValueSb != null) {
  543.                                 Debug.Assert(curPos > 0 && chars[curPos - 1] == ']');
  544.                                 SaveParsingBuffer(curPos - 1);
  545.                                 internalSubsetValue = internalSubsetValueSb.ToString();
  546.                                 internalSubsetValueSb = null;
  547.                             }
  548.                             // check '>'
  549.                             if (GetToken(false) != Token.GreaterThan) {
  550.                                 ThrowUnexpectedToken(curPos, ">");
  551.                             }
  552.                             #if DEBUG
  553.                             // check entity nesting
  554.                             Debug.Assert(readerAdapter.EntityStackLength == 0 || (freeFloatingDtd && readerAdapter.EntityStackLength == 1));
  555.                             #endif
  556.                         }
  557.                         else {
  558.                             Throw(curPos, Res.Xml_ExpectDtdMarkup);
  559.                         }
  560.                         return;
  561.                     case Token.Eof:
  562.                         if (ParsingInternalSubset && !freeFloatingDtd) {
  563.                             Throw(curPos, Res.Xml_IncompleteDtdContent);
  564.                         }
  565.                         if (condSectionDepth != 0) {
  566.                             Throw(curPos, Res.Xml_UnclosedConditionalSection);
  567.                         }
  568.                         return;
  569.                     default:
  570.                         Debug.Assert(false);
  571.                         break;
  572.                 }
  573.                
  574.                 Debug.Assert(scanningFunction == ScanningFunction.SubsetContent);
  575.                
  576.                 if (currentEntityId != startTagEntityId) {
  577.                     if (validate) {
  578.                         SendValidationEvent(curPos, XmlSeverityType.Error, Res.Sch_ParEntityRefNesting, string.Empty);
  579.                     }
  580.                     else {
  581.                         if (!v1Compat) {
  582.                             Throw(curPos, Res.Sch_ParEntityRefNesting);
  583.                         }
  584.                     }
  585.                 }
  586.             }
  587.         }
  588.        
  589.         private void ParseAttlistDecl()
  590.         {
  591.            
  592.             if (GetToken(true) != Token.QName) {
  593.                 goto UnexpectedError;
  594.             }
  595.            
  596.             // element name
  597.             XmlQualifiedName elementName = GetNameQualified(true);
  598.             SchemaElementDecl elementDecl = (SchemaElementDecl)schemaInfo.ElementDecls[elementName];
  599.             if (elementDecl == null) {
  600.                 elementDecl = (SchemaElementDecl)schemaInfo.UndeclaredElementDecls[elementName];
  601.                 if (elementDecl == null) {
  602.                     elementDecl = new SchemaElementDecl(elementName, elementName.Namespace, SchemaType.DTD);
  603.                     schemaInfo.UndeclaredElementDecls.Add(elementName, elementDecl);
  604.                 }
  605.             }
  606.            
  607.             SchemaAttDef attrDef = null;
  608.             for (;;) {
  609.                 switch (GetToken(false)) {
  610.                     case Token.QName:
  611.                         XmlQualifiedName attrName = GetNameQualified(true);
  612.                         attrDef = new SchemaAttDef(attrName, attrName.Namespace);
  613.                         attrDef.IsDeclaredInExternal = !ParsingInternalSubset;
  614.                         attrDef.LineNum = (int)LineNo;
  615.                         attrDef.LinePos = (int)LinePos - (curPos - tokenStartPos);
  616.                         break;
  617.                     case Token.GreaterThan:
  618.                         if (v1Compat) {
  619.                             // check xml:space and xml:lang
  620.                             // BUG BUG: For backward compatibility, we check the correct type and values of the
  621.                             // xml:space attribute only on the last attribute in the list.
  622.                             // See Webdata bugs #97457 and #93935.
  623.                             if (attrDef != null && attrDef.Prefix.Length > 0 && attrDef.Prefix.Equals("xml") && attrDef.Name.Name == "space") {
  624.                                 attrDef.Reserved = SchemaAttDef.Reserve.XmlSpace;
  625.                                 if (attrDef.Datatype.TokenizedType != XmlTokenizedType.ENUMERATION) {
  626.                                     Throw(Res.Xml_EnumerationRequired, string.Empty, attrDef.LineNum, attrDef.LinePos);
  627.                                 }
  628.                                 if (readerAdapter.EventHandler != null) {
  629.                                     attrDef.CheckXmlSpace(readerAdapter.EventHandler);
  630.                                 }
  631.                             }
  632.                         }
  633.                         return;
  634.                     default:
  635.                         goto UnexpectedError;
  636.                         break;
  637.                 }
  638.                
  639.                 ParseAttlistType(attrDef, elementDecl);
  640.                 ParseAttlistDefault(attrDef);
  641.                
  642.                 // check xml:space and xml:lang
  643.                 if (attrDef.Prefix.Length > 0 && attrDef.Prefix.Equals("xml")) {
  644.                     if (attrDef.Name.Name == "space") {
  645.                         if (v1Compat) {
  646.                             // BUG BUG: For backward compatibility, we check the correct type and values of the
  647.                             // xml:space attribute only on the last attribute in the list, and mark it as reserved
  648.                             // only its value is correct (=prevent XmlTextReader from fhrowing on invalid value).
  649.                             // See Webdata bugs #98168, #97457 and #93935.
  650.                             string val = attrDef.DefaultValueExpanded.Trim();
  651.                             if (val.Equals("preserve") || val.Equals("default")) {
  652.                                 attrDef.Reserved = SchemaAttDef.Reserve.XmlSpace;
  653.                             }
  654.                         }
  655.                         else {
  656.                             attrDef.Reserved = SchemaAttDef.Reserve.XmlSpace;
  657.                             if (attrDef.Datatype.TokenizedType != XmlTokenizedType.ENUMERATION) {
  658.                                 Throw(Res.Xml_EnumerationRequired, string.Empty, attrDef.LineNum, attrDef.LinePos);
  659.                             }
  660.                             if (readerAdapter.EventHandler != null) {
  661.                                 attrDef.CheckXmlSpace(readerAdapter.EventHandler);
  662.                             }
  663.                         }
  664.                     }
  665.                     else if (attrDef.Name.Name == "lang") {
  666.                         attrDef.Reserved = SchemaAttDef.Reserve.XmlLang;
  667.                     }
  668.                 }
  669.                
  670.                 // add attribute to element decl
  671.                 if (elementDecl.GetAttDef(attrDef.Name) == null) {
  672.                     elementDecl.AddAttDef(attrDef);
  673.                 }
  674.             }
  675.             UnexpectedError:
  676.            
  677.             OnUnexpectedError();
  678.         }
  679.        
  680.         private void ParseAttlistType(SchemaAttDef attrDef, SchemaElementDecl elementDecl)
  681.         {
  682.             Token token = GetToken(true);
  683.            
  684.             if (token != Token.CDATA) {
  685.                 elementDecl.HasNonCDataAttribute = true;
  686.             }
  687.            
  688.             if (IsAttributeValueType(token)) {
  689.                 attrDef.Datatype = XmlSchemaDatatype.FromXmlTokenizedType((XmlTokenizedType)(int)token);
  690.                 attrDef.SchemaType = XmlSchemaType.GetBuiltInSimpleType(attrDef.Datatype.TypeCode);
  691.                
  692.                 switch (token) {
  693.                     case Token.NOTATION:
  694.                         break;
  695.                     case Token.ID:
  696.                         if (validate && elementDecl.IsIdDeclared) {
  697.                             SchemaAttDef idAttrDef = elementDecl.GetAttDef(attrDef.Name);
  698.                             if (idAttrDef == null || idAttrDef.Datatype.TokenizedType != XmlTokenizedType.ID) {
  699.                                 SendValidationEvent(XmlSeverityType.Error, Res.Sch_IdAttrDeclared, elementDecl.Name.ToString());
  700.                             }
  701.                         }
  702.                         elementDecl.IsIdDeclared = true;
  703.                         return;
  704.                     default:
  705.                         return;
  706.                 }
  707.                 // check notation constrains
  708.                 if (validate) {
  709.                     if (elementDecl.IsNotationDeclared) {
  710.                         SendValidationEvent(curPos - 8, XmlSeverityType.Error, Res.Sch_DupNotationAttribute, elementDecl.Name.ToString());
  711.                         // 8 == strlen("NOTATION")
  712.                     }
  713.                     else {
  714.                         if (elementDecl.ContentValidator != null && elementDecl.ContentValidator.ContentType == XmlSchemaContentType.Empty) {
  715.                             SendValidationEvent(curPos - 8, XmlSeverityType.Error, Res.Sch_NotationAttributeOnEmptyElement, elementDecl.Name.ToString());
  716.                             // 8 == strlen("NOTATION")
  717.                         }
  718.                         elementDecl.IsNotationDeclared = true;
  719.                     }
  720.                 }
  721.                
  722.                 if (GetToken(true) != Token.LeftParen) {
  723.                     goto UnexpectedError;
  724.                 }
  725.                
  726.                 // parse notation list
  727.                 if (GetToken(false) != Token.Name) {
  728.                     goto UnexpectedError;
  729.                 }
  730.                 for (;;) {
  731.                     string notationName = GetNameString();
  732.                     if (schemaInfo.Notations[notationName] == null) {
  733.                         if (undeclaredNotations == null) {
  734.                             undeclaredNotations = new Hashtable();
  735.                         }
  736.                         UndeclaredNotation un = new UndeclaredNotation(notationName, LineNo, LinePos - notationName.Length);
  737.                         UndeclaredNotation loggedUn = (UndeclaredNotation)undeclaredNotations[notationName];
  738.                         if (loggedUn != null) {
  739.                             un.next = loggedUn.next;
  740.                             loggedUn.next = un;
  741.                         }
  742.                         else {
  743.                             undeclaredNotations.Add(notationName, un);
  744.                         }
  745.                     }
  746.                     if (validate && !v1Compat && attrDef.Values != null && attrDef.Values.Contains(notationName)) {
  747.                         SendValidationEvent(XmlSeverityType.Error, new XmlSchemaException(Res.Xml_AttlistDuplNotationValue, notationName, BaseUriStr, (int)LineNo, (int)LinePos));
  748.                     }
  749.                     attrDef.AddValue(notationName);
  750.                    
  751.                     switch (GetToken(false)) {
  752.                         case Token.Or:
  753.                             if (GetToken(false) != Token.Name) {
  754.                                 goto UnexpectedError;
  755.                             }
  756.                             continue;
  757.                         case Token.RightParen:
  758.                             return;
  759.                         default:
  760.                             goto UnexpectedError;
  761.                             break;
  762.                     }
  763.                 }
  764.             }
  765.             else if (token == Token.LeftParen) {
  766.                 attrDef.Datatype = XmlSchemaDatatype.FromXmlTokenizedType(XmlTokenizedType.ENUMERATION);
  767.                 attrDef.SchemaType = XmlSchemaType.GetBuiltInSimpleType(attrDef.Datatype.TypeCode);
  768.                
  769.                 // parse nmtoken list
  770.                 if (GetToken(false) != Token.Nmtoken)
  771.                     goto UnexpectedError;
  772.                 attrDef.AddValue(GetNameString());
  773.                
  774.                 for (;;) {
  775.                     switch (GetToken(false)) {
  776.                         case Token.Or:
  777.                             if (GetToken(false) != Token.Nmtoken)
  778.                                 goto UnexpectedError;
  779.                             string nmtoken = GetNmtokenString();
  780.                             if (validate && !v1Compat && attrDef.Values != null && attrDef.Values.Contains(nmtoken)) {
  781.                                 SendValidationEvent(XmlSeverityType.Error, new XmlSchemaException(Res.Xml_AttlistDuplEnumValue, nmtoken, BaseUriStr, (int)LineNo, (int)LinePos));
  782.                             }
  783.                             attrDef.AddValue(nmtoken);
  784.                             break;
  785.                         case Token.RightParen:
  786.                             return;
  787.                         default:
  788.                             goto UnexpectedError;
  789.                             break;
  790.                     }
  791.                 }
  792.             }
  793.             else {
  794.                 goto UnexpectedError;
  795.             }
  796.             UnexpectedError:
  797.            
  798.             OnUnexpectedError();
  799.         }
  800.        
  801.         private void ParseAttlistDefault(SchemaAttDef attrDef)
  802.         {
  803.             switch (GetToken(true)) {
  804.                 case Token.REQUIRED:
  805.                     attrDef.Presence = SchemaDeclBase.Use.Required;
  806.                     return;
  807.                 case Token.IMPLIED:
  808.                     attrDef.Presence = SchemaDeclBase.Use.Implied;
  809.                     return;
  810.                 case Token.FIXED:
  811.                     attrDef.Presence = SchemaDeclBase.Use.Fixed;
  812.                     if (GetToken(true) != Token.Literal) {
  813.                         goto UnexpectedError;
  814.                     }
  815.                     break;
  816.                 case Token.Literal:
  817.                     break;
  818.                 default:
  819.                     goto UnexpectedError;
  820.                     break;
  821.             }
  822.            
  823.             if (validate && attrDef.Datatype.TokenizedType == XmlTokenizedType.ID) {
  824.                 SendValidationEvent(curPos, XmlSeverityType.Error, Res.Sch_AttListPresence, string.Empty);
  825.             }
  826.            
  827.             if (attrDef.Datatype.TokenizedType != XmlTokenizedType.CDATA) {
  828.                 // non-CDATA attribute type normalization - strip spaces
  829.                 attrDef.DefaultValueExpanded = GetValueWithStrippedSpaces();
  830.             }
  831.             else {
  832.                 attrDef.DefaultValueExpanded = GetValue();
  833.             }
  834.             attrDef.ValueLineNum = (int)literalLineInfo.lineNo;
  835.             attrDef.ValueLinePos = (int)literalLineInfo.linePos + 1;
  836.            
  837.             DtdValidator.SetDefaultTypedValue(attrDef, readerAdapter);
  838.            
  839.             return;
  840.             UnexpectedError:
  841.            
  842.             OnUnexpectedError();
  843.         }
  844.        
  845.         private void ParseElementDecl()
  846.         {
  847.            
  848.             // element name
  849.             if (GetToken(true) != Token.QName) {
  850.                 goto UnexpectedError;
  851.             }
  852.            
  853.             // get schema decl for element
  854.             SchemaElementDecl elementDecl = null;
  855.             XmlQualifiedName name = GetNameQualified(true);
  856.             elementDecl = (SchemaElementDecl)schemaInfo.ElementDecls[name];
  857.            
  858.             if (elementDecl != null) {
  859.                 if (validate) {
  860.                     SendValidationEvent(curPos - name.Name.Length, XmlSeverityType.Error, Res.Sch_DupElementDecl, GetNameString());
  861.                 }
  862.             }
  863.             else {
  864.                 if ((elementDecl = (SchemaElementDecl)schemaInfo.UndeclaredElementDecls[name]) != null) {
  865.                     schemaInfo.UndeclaredElementDecls.Remove(name);
  866.                 }
  867.                 else {
  868.                     elementDecl = new SchemaElementDecl(name, name.Namespace, SchemaType.DTD);
  869.                 }
  870.                 schemaInfo.ElementDecls.Add(name, elementDecl);
  871.             }
  872.             elementDecl.IsDeclaredInExternal = !ParsingInternalSubset;
  873.            
  874.             // content spec
  875.             switch (GetToken(true)) {
  876.                 case Token.EMPTY:
  877.                     elementDecl.ContentValidator = ContentValidator.Empty;
  878.                     goto End;
  879.                     break;
  880.                 case Token.ANY:
  881.                     elementDecl.ContentValidator = ContentValidator.Any;
  882.                     goto End;
  883.                     break;
  884.                 case Token.LeftParen:
  885.                     int startParenEntityId = currentEntityId;
  886.                     switch (GetToken(false)) {
  887.                         case Token.PCDATA:
  888.                            
  889.                             {
  890.                                 ParticleContentValidator pcv = new ParticleContentValidator(XmlSchemaContentType.Mixed);
  891.                                 pcv.Start();
  892.                                 pcv.OpenGroup();
  893.                                
  894.                                 ParseElementMixedContent(pcv, startParenEntityId);
  895.                                
  896.                                 elementDecl.ContentValidator = pcv.Finish(true);
  897.                                 goto End;
  898.                             }
  899.                             break;
  900.                         case Token.None:
  901.                            
  902.                             {
  903.                                 ParticleContentValidator pcv = null;
  904.                                 pcv = new ParticleContentValidator(XmlSchemaContentType.ElementOnly);
  905.                                 pcv.Start();
  906.                                 pcv.OpenGroup();
  907.                                
  908.                                 ParseElementOnlyContent(pcv, startParenEntityId);
  909.                                
  910.                                 elementDecl.ContentValidator = pcv.Finish(true);
  911.                                 goto End;
  912.                             }
  913.                             break;
  914.                         default:
  915.                             goto UnexpectedError;
  916.                             break;
  917.                     }
  918.                     break;
  919.                 default:
  920.                     goto UnexpectedError;
  921.                     break;
  922.             }
  923.             End:
  924.             if (GetToken(false) != Token.GreaterThan) {
  925.                 ThrowUnexpectedToken(curPos, ">");
  926.             }
  927.             return;
  928.             UnexpectedError:
  929.            
  930.             OnUnexpectedError();
  931.         }
  932.        
  933.         private void ParseElementOnlyContent(ParticleContentValidator pcv, int startParenEntityId)
  934.         {
  935.             Token parsingSchema = Token.None;
  936.             int connectorEntityId = startParenEntityId;
  937.             int contentEntityId = -1;
  938.            
  939.             for (;;) {
  940.                 switch (GetToken(false)) {
  941.                     case Token.QName:
  942.                        
  943.                         pcv.AddName(GetNameQualified(true), null);
  944.                        
  945.                         if (validate) {
  946.                             contentEntityId = currentEntityId;
  947.                             if (connectorEntityId > contentEntityId) {
  948.                                 // entity repl.text ending with connector
  949.                                 SendValidationEvent(curPos, XmlSeverityType.Error, Res.Sch_ParEntityRefNesting, string.Empty);
  950.                             }
  951.                         }
  952.                         ParseHowMany(pcv);
  953.                         break;
  954.                     case Token.LeftParen:
  955.                         pcv.OpenGroup();
  956.                         if (validate) {
  957.                             contentEntityId = currentEntityId;
  958.                             if (connectorEntityId > contentEntityId) {
  959.                                 // entity repl.text ending with connector
  960.                                 SendValidationEvent(curPos, XmlSeverityType.Error, Res.Sch_ParEntityRefNesting, string.Empty);
  961.                             }
  962.                         }
  963.                         ParseElementOnlyContent(pcv, currentEntityId);
  964.                         break;
  965.                     case Token.GreaterThan:
  966.                         Throw(curPos, Res.Xml_InvalidContentModel);
  967.                         return;
  968.                     default:
  969.                         goto UnexpectedError;
  970.                         break;
  971.                 }
  972.                
  973.                 switch (GetToken(false)) {
  974.                     case Token.Comma:
  975.                         if (parsingSchema == Token.Or) {
  976.                             Throw(curPos, Res.Xml_InvalidContentModel);
  977.                         }
  978.                         pcv.AddSequence();
  979.                         parsingSchema = Token.Comma;
  980.                         if (validate) {
  981.                             connectorEntityId = currentEntityId;
  982.                             if (connectorEntityId > contentEntityId) {
  983.                                 // entity repl.text starting with connector
  984.                                 SendValidationEvent(curPos, XmlSeverityType.Error, Res.Sch_ParEntityRefNesting, string.Empty);
  985.                             }
  986.                         }
  987.                         break;
  988.                     case Token.Or:
  989.                         if (parsingSchema == Token.Comma) {
  990.                             Throw(curPos, Res.Xml_InvalidContentModel);
  991.                         }
  992.                         pcv.AddChoice();
  993.                         parsingSchema = Token.Or;
  994.                         if (validate) {
  995.                             connectorEntityId = currentEntityId;
  996.                             if (connectorEntityId > contentEntityId) {
  997.                                 // entity repl.text starting with connector
  998.                                 SendValidationEvent(curPos, XmlSeverityType.Error, Res.Sch_ParEntityRefNesting, string.Empty);
  999.                             }
  1000.                         }
  1001.                         break;
  1002.                     case Token.RightParen:
  1003.                         pcv.CloseGroup();
  1004.                         if (validate && currentEntityId != startParenEntityId) {
  1005.                             SendValidationEvent(curPos, XmlSeverityType.Error, Res.Sch_ParEntityRefNesting, string.Empty);
  1006.                         }
  1007.                         ParseHowMany(pcv);
  1008.                         return;
  1009.                     case Token.GreaterThan:
  1010.                         Throw(curPos, Res.Xml_InvalidContentModel);
  1011.                         return;
  1012.                     default:
  1013.                         goto UnexpectedError;
  1014.                         break;
  1015.                 }
  1016.             }
  1017.             UnexpectedError:
  1018.            
  1019.             OnUnexpectedError();
  1020.         }
  1021.        
  1022.         private void ParseHowMany(ParticleContentValidator pcv)
  1023.         {
  1024.             switch (GetToken(false)) {
  1025.                 case Token.Star:
  1026.                     pcv.AddStar();
  1027.                     return;
  1028.                 case Token.QMark:
  1029.                     pcv.AddQMark();
  1030.                     return;
  1031.                 case Token.Plus:
  1032.                     pcv.AddPlus();
  1033.                     return;
  1034.                 default:
  1035.                     return;
  1036.             }
  1037.         }
  1038.        
  1039.         private void ParseElementMixedContent(ParticleContentValidator pcv, int startParenEntityId)
  1040.         {
  1041.             bool hasNames = false;
  1042.             int connectorEntityId = -1;
  1043.             int contentEntityId = currentEntityId;
  1044.            
  1045.             for (;;) {
  1046.                 switch (GetToken(false)) {
  1047.                     case Token.RightParen:
  1048.                         pcv.CloseGroup();
  1049.                         if (validate && currentEntityId != startParenEntityId) {
  1050.                             SendValidationEvent(curPos, XmlSeverityType.Error, Res.Sch_ParEntityRefNesting, string.Empty);
  1051.                         }
  1052.                         if (GetToken(false) == Token.Star && hasNames) {
  1053.                             pcv.AddStar();
  1054.                         }
  1055.                         else if (hasNames) {
  1056.                             ThrowUnexpectedToken(curPos, "*");
  1057.                         }
  1058.                         return;
  1059.                     case Token.Or:
  1060.                         if (!hasNames) {
  1061.                             hasNames = true;
  1062.                         }
  1063.                         else {
  1064.                             pcv.AddChoice();
  1065.                         }
  1066.                         if (validate) {
  1067.                             connectorEntityId = currentEntityId;
  1068.                             if (contentEntityId < connectorEntityId) {
  1069.                                 // entity repl.text starting with connector
  1070.                                 SendValidationEvent(curPos, XmlSeverityType.Error, Res.Sch_ParEntityRefNesting, string.Empty);
  1071.                             }
  1072.                         }
  1073.                        
  1074.                         if (GetToken(false) != Token.QName) {
  1075.                             goto default;
  1076.                         }
  1077.                        
  1078.                         XmlQualifiedName name = GetNameQualified(true);
  1079.                         if (pcv.Exists(name) && validate) {
  1080.                             SendValidationEvent(XmlSeverityType.Error, Res.Sch_DupElement, name.ToString());
  1081.                         }
  1082.                         pcv.AddName(name, null);
  1083.                        
  1084.                         if (validate) {
  1085.                             contentEntityId = currentEntityId;
  1086.                             if (contentEntityId < connectorEntityId) {
  1087.                                 // entity repl.text ending with connector
  1088.                                 SendValidationEvent(curPos, XmlSeverityType.Error, Res.Sch_ParEntityRefNesting, string.Empty);
  1089.                             }
  1090.                         }
  1091.                         continue;
  1092.                     default:
  1093.                         OnUnexpectedError();
  1094.                         break;
  1095.                 }
  1096.             }
  1097.         }
  1098.        
  1099.         private void ParseEntityDecl()
  1100.         {
  1101.             bool isParamEntity = false;
  1102.             SchemaEntity entity = null;
  1103.            
  1104.             // get entity name and type
  1105.             switch (GetToken(true)) {
  1106.                 case Token.Percent:
  1107.                     isParamEntity = true;
  1108.                     if (GetToken(true) != Token.Name) {
  1109.                         goto UnexpectedError;
  1110.                     }
  1111.                     goto case Token.Name;
  1112.                     break;
  1113.                 case Token.Name:
  1114.                     // create entity object
  1115.                     XmlQualifiedName entityName = GetNameQualified(false);
  1116.                     entity = new SchemaEntity(entityName, isParamEntity);
  1117.                    
  1118.                     entity.BaseURI = BaseUriStr;
  1119.                     entity.DeclaredURI = (externalDtdBaseUri.Length == 0) ? documentBaseUri : externalDtdBaseUri;
  1120.                    
  1121.                     if (isParamEntity) {
  1122.                         if (schemaInfo.ParameterEntities[entityName] == null) {
  1123.                             schemaInfo.ParameterEntities.Add(entityName, entity);
  1124.                         }
  1125.                     }
  1126.                     else {
  1127.                         if (schemaInfo.GeneralEntities[entityName] == null) {
  1128.                             schemaInfo.GeneralEntities.Add(entityName, entity);
  1129.                         }
  1130.                     }
  1131.                     entity.DeclaredInExternal = !ParsingInternalSubset;
  1132.                     entity.IsProcessed = true;
  1133.                     break;
  1134.                 default:
  1135.                     goto UnexpectedError;
  1136.                     break;
  1137.             }
  1138.            
  1139.             Token token = GetToken(true);
  1140.             switch (token) {
  1141.                 case Token.PUBLIC:
  1142.                 case Token.SYSTEM:
  1143.                     string systemId;
  1144.                     string publicId;
  1145.                     ParseExternalId(token, Token.EntityDecl, out publicId, out systemId);
  1146.                     entity.IsExternal = true;
  1147.                     entity.Url = systemId;
  1148.                     entity.Pubid = publicId;
  1149.                    
  1150.                     if (GetToken(false) == Token.NData) {
  1151.                         if (isParamEntity) {
  1152.                             ThrowUnexpectedToken(curPos - 5, ">");
  1153.                             // 5 == strlen("NDATA")
  1154.                         }
  1155.                         if (!whitespaceSeen) {
  1156.                             Throw(curPos - 5, Res.Xml_ExpectingWhiteSpace, "NDATA");
  1157.                         }
  1158.                        
  1159.                         if (GetToken(true) != Token.Name) {
  1160.                             goto UnexpectedError;
  1161.                         }
  1162.                        
  1163.                         entity.NData = GetNameQualified(false);
  1164.                         string notationName = entity.NData.Name;
  1165.                         if (schemaInfo.Notations[notationName] == null) {
  1166.                             if (undeclaredNotations == null) {
  1167.                                 undeclaredNotations = new Hashtable();
  1168.                             }
  1169.                             UndeclaredNotation un = new UndeclaredNotation(notationName, LineNo, LinePos - notationName.Length);
  1170.                             UndeclaredNotation loggedUn = (UndeclaredNotation)undeclaredNotations[notationName];
  1171.                             if (loggedUn != null) {
  1172.                                 un.next = loggedUn.next;
  1173.                                 loggedUn.next = un;
  1174.                             }
  1175.                             else {
  1176.                                 undeclaredNotations.Add(notationName, un);
  1177.                             }
  1178.                         }
  1179.                     }
  1180.                     break;
  1181.                 case Token.Literal:
  1182.                     entity.Text = GetValue();
  1183.                     entity.Line = (int)literalLineInfo.lineNo;
  1184.                     entity.Pos = (int)literalLineInfo.linePos;
  1185.                     break;
  1186.                 default:
  1187.                     goto UnexpectedError;
  1188.                     break;
  1189.             }
  1190.            
  1191.             if (GetToken(false) == Token.GreaterThan) {
  1192.                 entity.IsProcessed = false;
  1193.                 return;
  1194.             }
  1195.             UnexpectedError:
  1196.            
  1197.             OnUnexpectedError();
  1198.         }
  1199.        
  1200.         private void ParseNotationDecl()
  1201.         {
  1202.             // notation name
  1203.             if (GetToken(true) != Token.Name) {
  1204.                 OnUnexpectedError();
  1205.             }
  1206.            
  1207.             SchemaNotation notation = null;
  1208.             XmlQualifiedName notationName = GetNameQualified(false);
  1209.             if (schemaInfo.Notations[notationName.Name] == null) {
  1210.                 if (undeclaredNotations != null) {
  1211.                     undeclaredNotations.Remove(notationName.Name);
  1212.                 }
  1213.                 notation = new SchemaNotation(notationName);
  1214.                 schemaInfo.Notations.Add(notation.Name.Name, notation);
  1215.                
  1216.             }
  1217.             else {
  1218.                 // duplicate notation
  1219.                 if (validate) {
  1220.                     SendValidationEvent(curPos - notationName.Name.Length, XmlSeverityType.Error, Res.Sch_DupNotation, notationName.Name);
  1221.                 }
  1222.             }
  1223.            
  1224.             // public / system id
  1225.             Token token = GetToken(true);
  1226.             if (token == Token.SYSTEM || token == Token.PUBLIC) {
  1227.                 string notationPublicId;
  1228.                 string notationSystemId;
  1229.                 ParseExternalId(token, Token.NOTATION, out notationPublicId, out notationSystemId);
  1230.                 if (notation != null) {
  1231.                     notation.SystemLiteral = notationSystemId;
  1232.                     notation.Pubid = notationPublicId;
  1233.                 }
  1234.             }
  1235.             else {
  1236.                 OnUnexpectedError();
  1237.             }
  1238.            
  1239.             if (GetToken(false) != Token.GreaterThan)
  1240.                 OnUnexpectedError();
  1241.         }
  1242.        
  1243.         private void ParseComment()
  1244.         {
  1245.             SaveParsingBuffer();
  1246.             try {
  1247.                 if (SaveInternalSubsetValue) {
  1248.                     readerAdapter.ParseComment(internalSubsetValueSb);
  1249.                     internalSubsetValueSb.Append("-->");
  1250.                 }
  1251.                 else {
  1252.                     readerAdapter.ParseComment(null);
  1253.                 }
  1254.             }
  1255.             catch (XmlException e) {
  1256.                 if (e.ResString == Res.Xml_UnexpectedEOF && currentEntityId != 0) {
  1257.                     SendValidationEvent(XmlSeverityType.Error, Res.Sch_ParEntityRefNesting, null);
  1258.                 }
  1259.                 else {
  1260.                     throw;
  1261.                 }
  1262.             }
  1263.             LoadParsingBuffer();
  1264.         }
  1265.        
  1266.         private void ParsePI()
  1267.         {
  1268.             SaveParsingBuffer();
  1269.             if (SaveInternalSubsetValue) {
  1270.                 readerAdapter.ParsePI(internalSubsetValueSb);
  1271.                 internalSubsetValueSb.Append("?>");
  1272.             }
  1273.             else {
  1274.                 readerAdapter.ParsePI(null);
  1275.             }
  1276.             LoadParsingBuffer();
  1277.         }
  1278.        
  1279.         private void ParseCondSection()
  1280.         {
  1281.             int csEntityId = currentEntityId;
  1282.            
  1283.             switch (GetToken(false)) {
  1284.                 case Token.INCLUDE:
  1285.                     if (GetToken(false) != Token.RightBracket) {
  1286.                         goto default;
  1287.                     }
  1288.                     if (validate && csEntityId != currentEntityId) {
  1289.                         SendValidationEvent(curPos, XmlSeverityType.Error, Res.Sch_ParEntityRefNesting, string.Empty);
  1290.                     }
  1291.                    
  1292.                     if (validate) {
  1293.                         if (condSectionEntityIds == null) {
  1294.                             condSectionEntityIds = new int[CondSectionEntityIdsInitialSize];
  1295.                         }
  1296.                         else if (condSectionEntityIds.Length == condSectionDepth) {
  1297.                             int[] tmp = new int[condSectionEntityIds.Length * 2];
  1298.                             Array.Copy(condSectionEntityIds, 0, tmp, 0, condSectionEntityIds.Length);
  1299.                             condSectionEntityIds = tmp;
  1300.                         }
  1301.                         condSectionEntityIds[condSectionDepth] = csEntityId;
  1302.                     }
  1303.                     condSectionDepth++;
  1304.                     break;
  1305.                 case Token.IGNORE:
  1306.                     if (GetToken(false) != Token.RightBracket) {
  1307.                         goto default;
  1308.                     }
  1309.                     if (validate && csEntityId != currentEntityId) {
  1310.                         SendValidationEvent(curPos, XmlSeverityType.Error, Res.Sch_ParEntityRefNesting, string.Empty);
  1311.                     }
  1312.                     // the content of the ignore section is parsed & skipped by scanning function
  1313.                     if (GetToken(false) != Token.CondSectionEnd) {
  1314.                         goto default;
  1315.                     }
  1316.                     if (validate && csEntityId != currentEntityId) {
  1317.                         SendValidationEvent(curPos, XmlSeverityType.Error, Res.Sch_ParEntityRefNesting, string.Empty);
  1318.                     }
  1319.                     break;
  1320.                 default:
  1321.                     OnUnexpectedError();
  1322.                     break;
  1323.             }
  1324.         }
  1325.        
  1326.         private void ParseExternalId(Token idTokenType, Token declType, out string publicId, out string systemId)
  1327.         {
  1328.             LineInfo keywordLineInfo = new LineInfo(LineNo, LinePos - 6);
  1329.             publicId = null;
  1330.             systemId = null;
  1331.            
  1332.             if (GetToken(true) != Token.Literal) {
  1333.                 ThrowUnexpectedToken(curPos, "\"", "'");
  1334.             }
  1335.            
  1336.             if (idTokenType == Token.SYSTEM) {
  1337.                 systemId = GetValue();
  1338.                
  1339.                 if (systemId.IndexOf('#') >= 0) {
  1340.                     Throw(curPos - systemId.Length - 1, Res.Xml_FragmentId, new string[] {systemId.Substring(systemId.IndexOf('#')), systemId});
  1341.                 }
  1342.                
  1343.                 if (declType == Token.DOCTYPE && !freeFloatingDtd) {
  1344.                     literalLineInfo.linePos++;
  1345.                     readerAdapter.OnSystemId(systemId, keywordLineInfo, literalLineInfo);
  1346.                 }
  1347.             }
  1348.             else {
  1349.                 Debug.Assert(idTokenType == Token.PUBLIC);
  1350.                 publicId = GetValue();
  1351.                
  1352.                 // verify if it contains chars valid for public ids
  1353.                 int i;
  1354.                 if ((i = xmlCharType.IsPublicId(publicId)) >= 0) {
  1355.                     ThrowInvalidChar(curPos - 1 - publicId.Length + i, publicId[i]);
  1356.                 }
  1357.                
  1358.                 if (declType == Token.DOCTYPE && !freeFloatingDtd) {
  1359.                     literalLineInfo.linePos++;
  1360.                     readerAdapter.OnPublicId(publicId, keywordLineInfo, literalLineInfo);
  1361.                    
  1362.                     if (GetToken(false) == Token.Literal) {
  1363.                         if (!whitespaceSeen) {
  1364.                             Throw(Res.Xml_ExpectingWhiteSpace, new string(literalQuoteChar, 1), (int)literalLineInfo.lineNo, (int)literalLineInfo.linePos);
  1365.                         }
  1366.                         systemId = GetValue();
  1367.                         literalLineInfo.linePos++;
  1368.                         readerAdapter.OnSystemId(systemId, keywordLineInfo, literalLineInfo);
  1369.                     }
  1370.                     else {
  1371.                         ThrowUnexpectedToken(curPos, "\"", "'");
  1372.                     }
  1373.                 }
  1374.                 else {
  1375.                     if (GetToken(false) == Token.Literal) {
  1376.                         if (!whitespaceSeen) {
  1377.                             Throw(Res.Xml_ExpectingWhiteSpace, new string(literalQuoteChar, 1), (int)literalLineInfo.lineNo, (int)literalLineInfo.linePos);
  1378.                         }
  1379.                         systemId = GetValue();
  1380.                     }
  1381.                     else if (declType != Token.NOTATION) {
  1382.                         ThrowUnexpectedToken(curPos, "\"", "'");
  1383.                     }
  1384.                 }
  1385.             }
  1386.         }
  1387.         //
  1388.         // Scanning methods - works directly with parsing buffer
  1389.         //
  1390.         private Token GetToken(bool needWhiteSpace)
  1391.         {
  1392.             whitespaceSeen = false;
  1393.             for (;;) {
  1394.                 switch (chars[curPos]) {
  1395.                     case (char)0:
  1396.                         if (curPos == charsUsed) {
  1397.                             goto ReadData;
  1398.                         }
  1399.                         else {
  1400.                             ThrowInvalidChar(curPos, chars[curPos]);
  1401.                         }
  1402.                         break;
  1403.                     case (char)10:
  1404.                         whitespaceSeen = true;
  1405.                         curPos++;
  1406.                         readerAdapter.OnNewLine(curPos);
  1407.                         continue;
  1408.                     case (char)13:
  1409.                         whitespaceSeen = true;
  1410.                         if (chars[curPos + 1] == (char)10) {
  1411.                             if (normalize) {
  1412.                                 SaveParsingBuffer();
  1413.                                 // EOL normalization of 0xD 0xA
  1414.                                 readerAdapter.CurrentPosition++;
  1415.                             }
  1416.                             curPos += 2;
  1417.                         }
  1418.                         else if (curPos + 1 < charsUsed || readerAdapter.IsEof) {
  1419.                             chars[curPos] = (char)10;
  1420.                             // EOL normalization of 0xD
  1421.                             curPos++;
  1422.                         }
  1423.                         else {
  1424.                             goto ReadData;
  1425.                         }
  1426.                         readerAdapter.OnNewLine(curPos);
  1427.                         continue;
  1428.                     case (char)9:
  1429.                     case (char)32:
  1430.                         whitespaceSeen = true;
  1431.                         curPos++;
  1432.                         continue;
  1433.                     case '%':
  1434.                         if (charsUsed - curPos < 2) {
  1435.                             goto ReadData;
  1436.                         }
  1437.                         if (!xmlCharType.IsWhiteSpace(chars[curPos + 1])) {
  1438.                             if (IgnoreEntityReferences) {
  1439.                                 curPos++;
  1440.                             }
  1441.                             else {
  1442.                                 HandleEntityReference(true, false, false);
  1443.                             }
  1444.                             continue;
  1445.                         }
  1446.                         goto default;
  1447.                         break;
  1448.                     default:
  1449.                         if (needWhiteSpace && !whitespaceSeen && scanningFunction != ScanningFunction.ParamEntitySpace) {
  1450.                             Throw(curPos, Res.Xml_ExpectingWhiteSpace, ParseUnexpectedToken(curPos));
  1451.                         }
  1452.                         tokenStartPos = curPos;
  1453.                         SwitchAgain:
  1454.                         switch (scanningFunction) {
  1455.                             case ScanningFunction.Name:
  1456.                                 return ScanNameExpected();
  1457.                             case ScanningFunction.QName:
  1458.                                 return ScanQNameExpected();
  1459.                             case ScanningFunction.Nmtoken:
  1460.                                 return ScanNmtokenExpected();
  1461.                             case ScanningFunction.SubsetContent:
  1462.                                 return ScanSubsetContent();
  1463.                             case ScanningFunction.Doctype1:
  1464.                                 return ScanDoctype1();
  1465.                             case ScanningFunction.Doctype2:
  1466.                                 return ScanDoctype2();
  1467.                             case ScanningFunction.Element1:
  1468.                                 return ScanElement1();
  1469.                             case ScanningFunction.Element2:
  1470.                                 return ScanElement2();
  1471.                             case ScanningFunction.Element3:
  1472.                                 return ScanElement3();
  1473.                             case ScanningFunction.Element4:
  1474.                                 return ScanElement4();
  1475.                             case ScanningFunction.Element5:
  1476.                                 return ScanElement5();
  1477.                             case ScanningFunction.Element6:
  1478.                                 return ScanElement6();
  1479.                             case ScanningFunction.Element7:
  1480.                                 return ScanElement7();
  1481.                             case ScanningFunction.Attlist1:
  1482.                                 return ScanAttlist1();
  1483.                             case ScanningFunction.Attlist2:
  1484.                                 return ScanAttlist2();
  1485.                             case ScanningFunction.Attlist3:
  1486.                                 return ScanAttlist3();
  1487.                             case ScanningFunction.Attlist4:
  1488.                                 return ScanAttlist4();
  1489.                             case ScanningFunction.Attlist5:
  1490.                                 return ScanAttlist5();
  1491.                             case ScanningFunction.Attlist6:
  1492.                                 return ScanAttlist6();
  1493.                             case ScanningFunction.Attlist7:
  1494.                                 return ScanAttlist7();
  1495.                             case ScanningFunction.Notation1:
  1496.                                 return ScanNotation1();
  1497.                             case ScanningFunction.SystemId:
  1498.                                 return ScanSystemId();
  1499.                             case ScanningFunction.PublicId1:
  1500.                                 return ScanPublicId1();
  1501.                             case ScanningFunction.PublicId2:
  1502.                                 return ScanPublicId2();
  1503.                             case ScanningFunction.Entity1:
  1504.                                 return ScanEntity1();
  1505.                             case ScanningFunction.Entity2:
  1506.                                 return ScanEntity2();
  1507.                             case ScanningFunction.Entity3:
  1508.                                 return ScanEntity3();
  1509.                             case ScanningFunction.CondSection1:
  1510.                                 return ScanCondSection1();
  1511.                             case ScanningFunction.CondSection2:
  1512.                                 return ScanCondSection2();
  1513.                             case ScanningFunction.CondSection3:
  1514.                                 return ScanCondSection3();
  1515.                             case ScanningFunction.ClosingTag:
  1516.                                 return ScanClosingTag();
  1517.                             case ScanningFunction.ParamEntitySpace:
  1518.                                 whitespaceSeen = true;
  1519.                                 scanningFunction = savedScanningFunction;
  1520.                                 goto SwitchAgain;
  1521.                                 break;
  1522.                             default:
  1523.                                 Debug.Assert(false);
  1524.                                 return Token.None;
  1525.                         }
  1526.                         break;
  1527.                 }
  1528.                 ReadData:
  1529.                 if (readerAdapter.IsEof || ReadData() == 0) {
  1530.                     if (HandleEntityEnd(false)) {
  1531.                         continue;
  1532.                     }
  1533.                     if (scanningFunction == ScanningFunction.SubsetContent) {
  1534.                         return Token.Eof;
  1535.                     }
  1536.                     else {
  1537.                         Throw(curPos, Res.Xml_IncompleteDtdContent);
  1538.                     }
  1539.                 }
  1540.             }
  1541.         }
  1542.        
  1543.         private Token ScanSubsetContent()
  1544.         {
  1545.             for (;;) {
  1546.                 switch (chars[curPos]) {
  1547.                     case '<':
  1548.                         switch (chars[curPos + 1]) {
  1549.                             case '!':
  1550.                                 switch (chars[curPos + 2]) {
  1551.                                     case 'E':
  1552.                                         if (chars[curPos + 3] == 'L') {
  1553.                                             if (charsUsed - curPos < 9) {
  1554.                                                 goto ReadData;
  1555.                                             }
  1556.                                             if (chars[curPos + 4] != 'E' || chars[curPos + 5] != 'M' || chars[curPos + 6] != 'E' || chars[curPos + 7] != 'N' || chars[curPos + 8] != 'T') {
  1557.                                                 Throw(curPos, Res.Xml_ExpectDtdMarkup);
  1558.                                             }
  1559.                                             curPos += 9;
  1560.                                             scanningFunction = ScanningFunction.QName;
  1561.                                             nextScaningFunction = ScanningFunction.Element1;
  1562.                                             return Token.ElementDecl;
  1563.                                         }
  1564.                                         else if (chars[curPos + 3] == 'N') {
  1565.                                             if (charsUsed - curPos < 8) {
  1566.                                                 goto ReadData;
  1567.                                             }
  1568.                                             if (chars[curPos + 4] != 'T' || chars[curPos + 5] != 'I' || chars[curPos + 6] != 'T' || chars[curPos + 7] != 'Y') {
  1569.                                                 Throw(curPos, Res.Xml_ExpectDtdMarkup);
  1570.                                             }
  1571.                                             curPos += 8;
  1572.                                             scanningFunction = ScanningFunction.Entity1;
  1573.                                             return Token.EntityDecl;
  1574.                                         }
  1575.                                         else {
  1576.                                             if (charsUsed - curPos < 4) {
  1577.                                                 goto ReadData;
  1578.                                             }
  1579.                                             Throw(curPos, Res.Xml_ExpectDtdMarkup);
  1580.                                             return Token.None;
  1581.                                         }
  1582.                                         break;
  1583.                                     case 'A':
  1584.                                        
  1585.                                         if (charsUsed - curPos < 9) {
  1586.                                             goto ReadData;
  1587.                                         }
  1588.                                         if (chars[curPos + 3] != 'T' || chars[curPos + 4] != 'T' || chars[curPos + 5] != 'L' || chars[curPos + 6] != 'I' || chars[curPos + 7] != 'S' || chars[curPos + 8] != 'T') {
  1589.                                             Throw(curPos, Res.Xml_ExpectDtdMarkup);
  1590.                                         }
  1591.                                         curPos += 9;
  1592.                                         scanningFunction = ScanningFunction.QName;
  1593.                                         nextScaningFunction = ScanningFunction.Attlist1;
  1594.                                         return Token.AttlistDecl;
  1595.                                     case 'N':
  1596.                                        
  1597.                                         if (charsUsed - curPos < 10) {
  1598.                                             goto ReadData;
  1599.                                         }
  1600.                                         if (chars[curPos + 3] != 'O' || chars[curPos + 4] != 'T' || chars[curPos + 5] != 'A' || chars[curPos + 6] != 'T' || chars[curPos + 7] != 'I' || chars[curPos + 8] != 'O' || chars[curPos + 9] != 'N') {
  1601.                                             Throw(curPos, Res.Xml_ExpectDtdMarkup);
  1602.                                         }
  1603.                                         curPos += 10;
  1604.                                         scanningFunction = ScanningFunction.Name;
  1605.                                         nextScaningFunction = ScanningFunction.Notation1;
  1606.                                         return Token.NotationDecl;
  1607.                                     case '[':
  1608.                                        
  1609.                                         curPos += 3;
  1610.                                         scanningFunction = ScanningFunction.CondSection1;
  1611.                                         return Token.CondSectionStart;
  1612.                                     case '-':
  1613.                                         if (chars[curPos + 3] == '-') {
  1614.                                             curPos += 4;
  1615.                                             return Token.Comment;
  1616.                                         }
  1617.                                         else {
  1618.                                             if (charsUsed - curPos < 4) {
  1619.                                                 goto ReadData;
  1620.                                             }
  1621.                                             Throw(curPos, Res.Xml_ExpectDtdMarkup);
  1622.                                             break;
  1623.                                         }
  1624.                                         break;
  1625.                                     default:
  1626.                                         if (charsUsed - curPos < 3) {
  1627.                                             goto ReadData;
  1628.                                         }
  1629.                                         Throw(curPos + 2, Res.Xml_ExpectDtdMarkup);
  1630.                                         break;
  1631.                                 }
  1632.                                 break;
  1633.                             case '?':
  1634.                                 curPos += 2;
  1635.                                 return Token.PI;
  1636.                             default:
  1637.                                 if (charsUsed - curPos < 2) {
  1638.                                     goto ReadData;
  1639.                                 }
  1640.                                 Throw(curPos, Res.Xml_ExpectDtdMarkup);
  1641.                                 return Token.None;
  1642.                         }
  1643.                         break;
  1644.                     case ']':
  1645.                         if (charsUsed - curPos < 2 && !readerAdapter.IsEof) {
  1646.                             goto ReadData;
  1647.                         }
  1648.                         if (chars[curPos + 1] != ']') {
  1649.                             curPos++;
  1650.                             scanningFunction = ScanningFunction.ClosingTag;
  1651.                             return Token.RightBracket;
  1652.                         }
  1653.                         if (charsUsed - curPos < 3 && !readerAdapter.IsEof) {
  1654.                             goto ReadData;
  1655.                         }
  1656.                         if (chars[curPos + 1] == ']' && chars[curPos + 2] == '>') {
  1657.                             curPos += 3;
  1658.                             return Token.CondSectionEnd;
  1659.                         }
  1660.                         goto default;
  1661.                         break;
  1662.                     default:
  1663.                         if (charsUsed - curPos == 0) {
  1664.                             goto ReadData;
  1665.                         }
  1666.                         Throw(curPos, Res.Xml_ExpectDtdMarkup);
  1667.                         break;
  1668.                 }
  1669.                 ReadData:
  1670.                 if (ReadData() == 0) {
  1671.                     Throw(charsUsed, Res.Xml_IncompleteDtdContent);
  1672.                 }
  1673.             }
  1674.         }
  1675.        
  1676.         private Token ScanNameExpected()
  1677.         {
  1678.             ScanName();
  1679.             scanningFunction = nextScaningFunction;
  1680.             return Token.Name;
  1681.         }
  1682.        
  1683.         private Token ScanQNameExpected()
  1684.         {
  1685.             ScanQName();
  1686.             scanningFunction = nextScaningFunction;
  1687.             return Token.QName;
  1688.         }
  1689.        
  1690.         private Token ScanNmtokenExpected()
  1691.         {
  1692.             ScanNmtoken();
  1693.             scanningFunction = nextScaningFunction;
  1694.             return Token.Nmtoken;
  1695.         }
  1696.        
  1697.         private Token ScanDoctype1()
  1698.         {
  1699.             switch (chars[curPos]) {
  1700.                 case 'P':
  1701.                     if (!EatPublicKeyword()) {
  1702.                         Throw(curPos, Res.Xml_ExpectExternalOrClose);
  1703.                     }
  1704.                     nextScaningFunction = ScanningFunction.Doctype2;
  1705.                     scanningFunction = ScanningFunction.PublicId1;
  1706.                     return Token.PUBLIC;
  1707.                 case 'S':
  1708.                     if (!EatSystemKeyword()) {
  1709.                         Throw(curPos, Res.Xml_ExpectExternalOrClose);
  1710.                     }
  1711.                     nextScaningFunction = ScanningFunction.Doctype2;
  1712.                     scanningFunction = ScanningFunction.SystemId;
  1713.                     return Token.SYSTEM;
  1714.                 case '[':
  1715.                     curPos++;
  1716.                     scanningFunction = ScanningFunction.SubsetContent;
  1717.                     return Token.LeftBracket;
  1718.                 case '>':
  1719.                     curPos++;
  1720.                     scanningFunction = ScanningFunction.SubsetContent;
  1721.                     return Token.GreaterThan;
  1722.                 default:
  1723.                     Throw(curPos, Res.Xml_ExpectExternalOrClose);
  1724.                     return Token.None;
  1725.             }
  1726.         }
  1727.        
  1728.         private Token ScanDoctype2()
  1729.         {
  1730.             switch (chars[curPos]) {
  1731.                 case '[':
  1732.                     curPos++;
  1733.                     scanningFunction = ScanningFunction.SubsetContent;
  1734.                     return Token.LeftBracket;
  1735.                 case '>':
  1736.                     curPos++;
  1737.                     scanningFunction = ScanningFunction.SubsetContent;
  1738.                     return Token.GreaterThan;
  1739.                 default:
  1740.                     Throw(curPos, Res.Xml_ExpectSubOrClose);
  1741.                     return Token.None;
  1742.             }
  1743.         }
  1744.        
  1745.         private Token ScanClosingTag()
  1746.         {
  1747.             if (chars[curPos] != '>') {
  1748.                 ThrowUnexpectedToken(curPos, ">");
  1749.             }
  1750.             curPos++;
  1751.             scanningFunction = ScanningFunction.SubsetContent;
  1752.             return Token.GreaterThan;
  1753.         }
  1754.        
  1755.         private Token ScanElement1()
  1756.         {
  1757.             for (;;) {
  1758.                 switch (chars[curPos]) {
  1759.                     case '(':
  1760.                         scanningFunction = ScanningFunction.Element2;
  1761.                         curPos++;
  1762.                         return Token.LeftParen;
  1763.                     case 'E':
  1764.                         if (charsUsed - curPos < 5) {
  1765.                             goto ReadData;
  1766.                         }
  1767.                         if (chars[curPos + 1] == 'M' && chars[curPos + 2] == 'P' && chars[curPos + 3] == 'T' && chars[curPos + 4] == 'Y') {
  1768.                             curPos += 5;
  1769.                             scanningFunction = ScanningFunction.ClosingTag;
  1770.                             return Token.EMPTY;
  1771.                         }
  1772.                         goto default;
  1773.                         break;
  1774.                     case 'A':
  1775.                         if (charsUsed - curPos < 3) {
  1776.                             goto ReadData;
  1777.                         }
  1778.                         if (chars[curPos + 1] == 'N' && chars[curPos + 2] == 'Y') {
  1779.                             curPos += 3;
  1780.                             scanningFunction = ScanningFunction.ClosingTag;
  1781.                             return Token.ANY;
  1782.                         }
  1783.                         goto default;
  1784.                         break;
  1785.                     default:
  1786.                         Throw(curPos, Res.Xml_InvalidContentModel);
  1787.                         break;
  1788.                 }
  1789.                 ReadData:
  1790.                 if (ReadData() == 0) {
  1791.                     Throw(curPos, Res.Xml_IncompleteDtdContent);
  1792.                 }
  1793.             }
  1794.         }
  1795.        
  1796.         private Token ScanElement2()
  1797.         {
  1798.             if (chars[curPos] == '#') {
  1799.                 while (charsUsed - curPos < 7) {
  1800.                     if (ReadData() == 0) {
  1801.                         Throw(curPos, Res.Xml_IncompleteDtdContent);
  1802.                     }
  1803.                 }
  1804.                 if (chars[curPos + 1] == 'P' && chars[curPos + 2] == 'C' && chars[curPos + 3] == 'D' && chars[curPos + 4] == 'A' && chars[curPos + 5] == 'T' && chars[curPos + 6] == 'A') {
  1805.                     curPos += 7;
  1806.                     scanningFunction = ScanningFunction.Element6;
  1807.                     return Token.PCDATA;
  1808.                 }
  1809.                 else {
  1810.                     Throw(curPos + 1, Res.Xml_ExpectPcData);
  1811.                 }
  1812.             }
  1813.            
  1814.             scanningFunction = ScanningFunction.Element3;
  1815.             return Token.None;
  1816.         }
  1817.        
  1818.         private Token ScanElement3()
  1819.         {
  1820.             switch (chars[curPos]) {
  1821.                 case '(':
  1822.                     curPos++;
  1823.                     return Token.LeftParen;
  1824.                 case '>':
  1825.                     curPos++;
  1826.                     scanningFunction = ScanningFunction.SubsetContent;
  1827.                     return Token.GreaterThan;
  1828.                 default:
  1829.                     ScanQName();
  1830.                     scanningFunction = ScanningFunction.Element4;
  1831.                     return Token.QName;
  1832.             }
  1833.         }
  1834.        
  1835.         private Token ScanElement4()
  1836.         {
  1837.             scanningFunction = ScanningFunction.Element5;
  1838.            
  1839.             Token t;
  1840.             switch (chars[curPos]) {
  1841.                 case '*':
  1842.                     t = Token.Star;
  1843.                     break;
  1844.                 case '?':
  1845.                     t = Token.QMark;
  1846.                     break;
  1847.                 case '+':
  1848.                     t = Token.Plus;
  1849.                     break;
  1850.                 default:
  1851.                     return Token.None;
  1852.             }
  1853.             if (whitespaceSeen) {
  1854.                 Throw(curPos, Res.Xml_ExpectNoWhitespace);
  1855.             }
  1856.             curPos++;
  1857.             return t;
  1858.         }
  1859.        
  1860.         private Token ScanElement5()
  1861.         {
  1862.             switch (chars[curPos]) {
  1863.                 case ',':
  1864.                     curPos++;
  1865.                     scanningFunction = ScanningFunction.Element3;
  1866.                     return Token.Comma;
  1867.                 case '|':
  1868.                     curPos++;
  1869.                     scanningFunction = ScanningFunction.Element3;
  1870.                     return Token.Or;
  1871.                 case ')':
  1872.                     curPos++;
  1873.                     scanningFunction = ScanningFunction.Element4;
  1874.                     return Token.RightParen;
  1875.                 case '>':
  1876.                     curPos++;
  1877.                     scanningFunction = ScanningFunction.SubsetContent;
  1878.                     return Token.GreaterThan;
  1879.                 default:
  1880.                     Throw(curPos, Res.Xml_ExpectOp);
  1881.                     return Token.None;
  1882.             }
  1883.         }
  1884.        
  1885.         private Token ScanElement6()
  1886.         {
  1887.             switch (chars[curPos]) {
  1888.                 case ')':
  1889.                     curPos++;
  1890.                     scanningFunction = ScanningFunction.Element7;
  1891.                     return Token.RightParen;
  1892.                 case '|':
  1893.                     curPos++;
  1894.                     nextScaningFunction = ScanningFunction.Element6;
  1895.                     scanningFunction = ScanningFunction.QName;
  1896.                     return Token.Or;
  1897.                 default:
  1898.                     ThrowUnexpectedToken(curPos, ")", "|");
  1899.                     return Token.None;
  1900.             }
  1901.         }
  1902.        
  1903.         private Token ScanElement7()
  1904.         {
  1905.             scanningFunction = ScanningFunction.ClosingTag;
  1906.             if (chars[curPos] == '*' && !whitespaceSeen) {
  1907.                 curPos++;
  1908.                 return Token.Star;
  1909.             }
  1910.             return Token.None;
  1911.         }
  1912.        
  1913.         private Token ScanAttlist1()
  1914.         {
  1915.             switch (chars[curPos]) {
  1916.                 case '>':
  1917.                     curPos++;
  1918.                     scanningFunction = ScanningFunction.SubsetContent;
  1919.                     return Token.GreaterThan;
  1920.                 default:
  1921.                     if (!whitespaceSeen) {
  1922.                         Throw(curPos, Res.Xml_ExpectingWhiteSpace, ParseUnexpectedToken(curPos));
  1923.                     }
  1924.                     ScanQName();
  1925.                     scanningFunction = ScanningFunction.Attlist2;
  1926.                     return Token.QName;
  1927.             }
  1928.         }
  1929.        
  1930.         private Token ScanAttlist2()
  1931.         {
  1932.             for (;;) {
  1933.                 switch (chars[curPos]) {
  1934.                     case '(':
  1935.                         curPos++;
  1936.                         scanningFunction = ScanningFunction.Nmtoken;
  1937.                         nextScaningFunction = ScanningFunction.Attlist5;
  1938.                         return Token.LeftParen;
  1939.                     case 'C':
  1940.                         if (charsUsed - curPos < 5)
  1941.                             goto ReadData;
  1942.                         if (chars[curPos + 1] != 'D' || chars[curPos + 2] != 'A' || chars[curPos + 3] != 'T' || chars[curPos + 4] != 'A') {
  1943.                             Throw(curPos, Res.Xml_InvalidAttributeType1);
  1944.                         }
  1945.                         curPos += 5;
  1946.                         scanningFunction = ScanningFunction.Attlist6;
  1947.                         return Token.CDATA;
  1948.                     case 'E':
  1949.                         if (charsUsed - curPos < 9)
  1950.                             goto ReadData;
  1951.                         scanningFunction = ScanningFunction.Attlist6;
  1952.                         if (chars[curPos + 1] != 'N' || chars[curPos + 2] != 'T' || chars[curPos + 3] != 'I' || chars[curPos + 4] != 'T') {
  1953.                             Throw(curPos, Res.Xml_InvalidAttributeType);
  1954.                         }
  1955.                         switch (chars[curPos + 5]) {
  1956.                             case 'I':
  1957.                                 if (chars[curPos + 6] != 'E' || chars[curPos + 7] != 'S') {
  1958.                                     Throw(curPos, Res.Xml_InvalidAttributeType);
  1959.                                 }
  1960.                                 curPos += 8;
  1961.                                 return Token.ENTITIES;
  1962.                             case 'Y':
  1963.                                 curPos += 6;
  1964.                                 return Token.ENTITY;
  1965.                             default:
  1966.                                 Throw(curPos, Res.Xml_InvalidAttributeType);
  1967.                                 break;
  1968.                         }
  1969.                         break;
  1970.                     case 'I':
  1971.                         if (charsUsed - curPos < 6)
  1972.                             goto ReadData;
  1973.                         scanningFunction = ScanningFunction.Attlist6;
  1974.                         if (chars[curPos + 1] != 'D') {
  1975.                             Throw(curPos, Res.Xml_InvalidAttributeType);
  1976.                         }
  1977.                        
  1978.                         if (chars[curPos + 2] != 'R') {
  1979.                             curPos += 2;
  1980.                             return Token.ID;
  1981.                         }
  1982.                        
  1983.                         if (chars[curPos + 3] != 'E' || chars[curPos + 4] != 'F') {
  1984.                             Throw(curPos, Res.Xml_InvalidAttributeType);
  1985.                         }
  1986.                        
  1987.                         if (chars[curPos + 5] != 'S') {
  1988.                             curPos += 5;
  1989.                             return Token.IDREF;
  1990.                         }
  1991.                         else {
  1992.                             curPos += 6;
  1993.                             return Token.IDREFS;
  1994.                         }
  1995.                         break;
  1996.                     case 'N':
  1997.                         if (charsUsed - curPos < 8 && !readerAdapter.IsEof) {
  1998.                             goto ReadData;
  1999.                         }
  2000.                         switch (chars[curPos + 1]) {
  2001.                             case 'O':
  2002.                                 if (chars[curPos + 2] != 'T' || chars[curPos + 3] != 'A' || chars[curPos + 4] != 'T' || chars[curPos + 5] != 'I' || chars[curPos + 6] != 'O' || chars[curPos + 7] != 'N') {
  2003.                                     Throw(curPos, Res.Xml_InvalidAttributeType);
  2004.                                 }
  2005.                                 curPos += 8;
  2006.                                 scanningFunction = ScanningFunction.Attlist3;
  2007.                                 return Token.NOTATION;
  2008.                             case 'M':
  2009.                                 if (chars[curPos + 2] != 'T' || chars[curPos + 3] != 'O' || chars[curPos + 4] != 'K' || chars[curPos + 5] != 'E' || chars[curPos + 6] != 'N') {
  2010.                                     Throw(curPos, Res.Xml_InvalidAttributeType);
  2011.                                 }
  2012.                                 scanningFunction = ScanningFunction.Attlist6;
  2013.                                
  2014.                                 if (chars[curPos + 7] == 'S') {
  2015.                                     curPos += 8;
  2016.                                     return Token.NMTOKENS;
  2017.                                 }
  2018.                                 else {
  2019.                                     curPos += 7;
  2020.                                     return Token.NMTOKEN;
  2021.                                 }
  2022.                                 break;
  2023.                             default:
  2024.                                 Throw(curPos, Res.Xml_InvalidAttributeType);
  2025.                                 break;
  2026.                         }
  2027.                         break;
  2028.                     default:
  2029.                         Throw(curPos, Res.Xml_InvalidAttributeType);
  2030.                         break;
  2031.                 }
  2032.                 ReadData:
  2033.                
  2034.                 if (ReadData() == 0) {
  2035.                     Throw(curPos, Res.Xml_IncompleteDtdContent);
  2036.                 }
  2037.             }
  2038.         }
  2039.        
  2040.         private Token ScanAttlist3()
  2041.         {
  2042.             if (chars[curPos] == '(') {
  2043.                 curPos++;
  2044.                 scanningFunction = ScanningFunction.Name;
  2045.                 nextScaningFunction = ScanningFunction.Attlist4;
  2046.                 return Token.LeftParen;
  2047.             }
  2048.             else {
  2049.                 ThrowUnexpectedToken(curPos, "(");
  2050.                 return Token.None;
  2051.             }
  2052.         }
  2053.        
  2054.         private Token ScanAttlist4()
  2055.         {
  2056.             switch (chars[curPos]) {
  2057.                 case ')':
  2058.                     curPos++;
  2059.                     scanningFunction = ScanningFunction.Attlist6;
  2060.                     return Token.RightParen;
  2061.                 case '|':
  2062.                     curPos++;
  2063.                     scanningFunction = ScanningFunction.Name;
  2064.                     nextScaningFunction = ScanningFunction.Attlist4;
  2065.                     return Token.Or;
  2066.                 default:
  2067.                     ThrowUnexpectedToken(curPos, ")", "|");
  2068.                     return Token.None;
  2069.             }
  2070.         }
  2071.        
  2072.         private Token ScanAttlist5()
  2073.         {
  2074.             switch (chars[curPos]) {
  2075.                 case ')':
  2076.                     curPos++;
  2077.                     scanningFunction = ScanningFunction.Attlist6;
  2078.                     return Token.RightParen;
  2079.                 case '|':
  2080.                     curPos++;
  2081.                     scanningFunction = ScanningFunction.Nmtoken;
  2082.                     nextScaningFunction = ScanningFunction.Attlist5;
  2083.                     return Token.Or;
  2084.                 default:
  2085.                     ThrowUnexpectedToken(curPos, ")", "|");
  2086.                     return Token.None;
  2087.                
  2088.             }
  2089.         }
  2090.        
  2091.         private Token ScanAttlist6()
  2092.         {
  2093.             for (;;) {
  2094.                 switch (chars[curPos]) {
  2095.                     case '"':
  2096.                     case '\'':
  2097.                         ScanLiteral(LiteralType.AttributeValue);
  2098.                         scanningFunction = ScanningFunction.Attlist1;
  2099.                         return Token.Literal;
  2100.                     case '#':
  2101.                         if (charsUsed - curPos < 6)
  2102.                             goto ReadData;
  2103.                         switch (chars[curPos + 1]) {
  2104.                             case 'R':
  2105.                                 if (charsUsed - curPos < 9)
  2106.                                     goto ReadData;
  2107.                                 if (chars[curPos + 2] != 'E' || chars[curPos + 3] != 'Q' || chars[curPos + 4] != 'U' || chars[curPos + 5] != 'I' || chars[curPos + 6] != 'R' || chars[curPos + 7] != 'E' || chars[curPos + 8] != 'D') {
  2108.                                     Throw(curPos, Res.Xml_ExpectAttType);
  2109.                                 }
  2110.                                 curPos += 9;
  2111.                                 scanningFunction = ScanningFunction.Attlist1;
  2112.                                 return Token.REQUIRED;
  2113.                             case 'I':
  2114.                                 if (charsUsed - curPos < 8)
  2115.                                     goto ReadData;
  2116.                                 if (chars[curPos + 2] != 'M' || chars[curPos + 3] != 'P' || chars[curPos + 4] != 'L' || chars[curPos + 5] != 'I' || chars[curPos + 6] != 'E' || chars[curPos + 7] != 'D') {
  2117.                                     Throw(curPos, Res.Xml_ExpectAttType);
  2118.                                 }
  2119.                                 curPos += 8;
  2120.                                 scanningFunction = ScanningFunction.Attlist1;
  2121.                                 return Token.IMPLIED;
  2122.                             case 'F':
  2123.                                 if (chars[curPos + 2] != 'I' || chars[curPos + 3] != 'X' || chars[curPos + 4] != 'E' || chars[curPos + 5] != 'D') {
  2124.                                     Throw(curPos, Res.Xml_ExpectAttType);
  2125.                                 }
  2126.                                 curPos += 6;
  2127.                                 scanningFunction = ScanningFunction.Attlist7;
  2128.                                 return Token.FIXED;
  2129.                             default:
  2130.                                 Throw(curPos, Res.Xml_ExpectAttType);
  2131.                                 break;
  2132.                         }
  2133.                         break;
  2134.                     default:
  2135.                         Throw(curPos, Res.Xml_ExpectAttType);
  2136.                         break;
  2137.                 }
  2138.                 ReadData:
  2139.                 if (ReadData() == 0) {
  2140.                     Throw(curPos, Res.Xml_IncompleteDtdContent);
  2141.                 }
  2142.             }
  2143.         }
  2144.        
  2145.         private Token ScanAttlist7()
  2146.         {
  2147.             switch (chars[curPos]) {
  2148.                 case '"':
  2149.                 case '\'':
  2150.                     ScanLiteral(LiteralType.AttributeValue);
  2151.                     scanningFunction = ScanningFunction.Attlist1;
  2152.                     return Token.Literal;
  2153.                 default:
  2154.                     Debug.Assert(false, "We should never get to this point.");
  2155.                     ThrowUnexpectedToken(curPos, "\"", "'");
  2156.                     return Token.None;
  2157.             }
  2158.         }
  2159.        
  2160.         private Token ScanLiteral(LiteralType literalType)
  2161.         {
  2162.             Debug.Assert(chars[curPos] == '"' || chars[curPos] == '\'');
  2163.            
  2164.             char quoteChar = chars[curPos];
  2165.             char replaceChar = (literalType == LiteralType.AttributeValue) ? (char)32 : (char)10;
  2166.             int startQuoteEntityId = currentEntityId;
  2167.            
  2168.             literalLineInfo.Set(LineNo, LinePos);
  2169.            
  2170.             curPos++;
  2171.             tokenStartPos = curPos;
  2172.            
  2173.             stringBuilder.Length = 0;
  2174.            
  2175.             for (;;) {
  2176.                 unsafe {
  2177.                     while ((xmlCharType.charProperties[chars[curPos]] & XmlCharType.fAttrValue) != 0 && chars[curPos] != '%') {
  2178.                         curPos++;
  2179.                     }
  2180.                 }
  2181.                
  2182.                 if (chars[curPos] == quoteChar && currentEntityId == startQuoteEntityId) {
  2183.                     if (stringBuilder.Length > 0) {
  2184.                         stringBuilder.Append(chars, tokenStartPos, curPos - tokenStartPos);
  2185.                     }
  2186.                     curPos++;
  2187.                     literalQuoteChar = quoteChar;
  2188.                     return Token.Literal;
  2189.                 }
  2190.                
  2191.                 int tmp1 = curPos - tokenStartPos;
  2192.                 if (tmp1 > 0) {
  2193.                     stringBuilder.Append(chars, tokenStartPos, tmp1);
  2194.                     tokenStartPos = curPos;
  2195.                 }
  2196.                
  2197.                 switch (chars[curPos]) {
  2198.                     case '"':
  2199.                     case '\'':
  2200.                     case '>':
  2201.                         curPos++;
  2202.                         continue;
  2203.                     case (char)10:
  2204.                         // eol
  2205.                         curPos++;
  2206.                         if (normalize) {
  2207.                             stringBuilder.Append(replaceChar);
  2208.                             // For attributes: CDATA normalization of 0xA
  2209.                             tokenStartPos = curPos;
  2210.                         }
  2211.                         readerAdapter.OnNewLine(curPos);
  2212.                         continue;
  2213.                     case (char)13:
  2214.                         if (chars[curPos + 1] == (char)10) {
  2215.                             if (normalize) {
  2216.                                 if (literalType == LiteralType.AttributeValue) {
  2217.                                     stringBuilder.Append(readerAdapter.IsEntityEolNormalized ? " " : " ");
  2218.                                     // CDATA normalization of 0xD 0xA
  2219.                                 }
  2220.                                 else {
  2221.                                     stringBuilder.Append(readerAdapter.IsEntityEolNormalized ? "\r\n" : "\n");
  2222.                                     // EOL normalization of 0xD 0xA
  2223.                                 }
  2224.                                 tokenStartPos = curPos + 2;
  2225.                                
  2226.                                 SaveParsingBuffer();
  2227.                                 // EOL normalization of 0xD 0xA in internal subset value
  2228.                                 readerAdapter.CurrentPosition++;
  2229.                             }
  2230.                             curPos += 2;
  2231.                         }
  2232.                         else if (curPos + 1 == charsUsed) {
  2233.                             goto ReadData;
  2234.                         }
  2235.                         else {
  2236.                             curPos++;
  2237.                             if (normalize) {
  2238.                                 stringBuilder.Append(replaceChar);
  2239.                                 // For attributes: CDATA normalization of 0xD and 0xD 0xA
  2240.                                 tokenStartPos = curPos;
  2241.                                 // For entities: EOL normalization of 0xD and 0xD 0xA
  2242.                             }
  2243.                         }
  2244.                         readerAdapter.OnNewLine(curPos);
  2245.                         continue;
  2246.                     case (char)9:
  2247.                         // tab
  2248.                         if (literalType == LiteralType.AttributeValue && normalize) {
  2249.                             stringBuilder.Append((char)32);
  2250.                             // For attributes: CDATA normalization of 0x9
  2251.                             tokenStartPos++;
  2252.                         }
  2253.                         curPos++;
  2254.                         continue;
  2255.                     case '<':
  2256.                         // attribute values cannot contain '<'
  2257.                         if (literalType == LiteralType.AttributeValue) {
  2258.                             Throw(curPos, Res.Xml_BadAttributeChar, XmlException.BuildCharExceptionStr('<'));
  2259.                         }
  2260.                         curPos++;
  2261.                         continue;
  2262.                     case '%':
  2263.                         // parameter entity reference
  2264.                         if (literalType != LiteralType.EntityReplText) {
  2265.                             curPos++;
  2266.                             continue;
  2267.                         }
  2268.                         HandleEntityReference(true, true, literalType == LiteralType.AttributeValue);
  2269.                         tokenStartPos = curPos;
  2270.                         continue;
  2271.                     case '&':
  2272.                         // general entity reference
  2273.                         if (literalType == LiteralType.SystemOrPublicID) {
  2274.                             curPos++;
  2275.                             continue;
  2276.                         }
  2277.                         if (curPos + 1 == charsUsed) {
  2278.                             goto ReadData;
  2279.                         }
  2280.                         // numeric characters reference
  2281.                         if (chars[curPos + 1] == '#') {
  2282.                             SaveParsingBuffer();
  2283.                             int endPos = readerAdapter.ParseNumericCharRef(SaveInternalSubsetValue ? internalSubsetValueSb : null);
  2284.                             LoadParsingBuffer();
  2285.                             stringBuilder.Append(chars, curPos, endPos - curPos);
  2286.                             readerAdapter.CurrentPosition = endPos;
  2287.                             tokenStartPos = endPos;
  2288.                             curPos = endPos;
  2289.                             continue;
  2290.                         }
  2291.                         else {
  2292.                             // general entity reference
  2293.                             SaveParsingBuffer();
  2294.                             if (literalType == LiteralType.AttributeValue) {
  2295.                                 int endPos = readerAdapter.ParseNamedCharRef(true, SaveInternalSubsetValue ? internalSubsetValueSb : null);
  2296.                                 LoadParsingBuffer();
  2297.                                
  2298.                                 if (endPos >= 0) {
  2299.                                     stringBuilder.Append(chars, curPos, endPos - curPos);
  2300.                                     readerAdapter.CurrentPosition = endPos;
  2301.                                     tokenStartPos = endPos;
  2302.                                     curPos = endPos;
  2303.                                     continue;
  2304.                                 }
  2305.                                 else {
  2306.                                     HandleEntityReference(false, true, true);
  2307.                                     tokenStartPos = curPos;
  2308.                                 }
  2309.                                 continue;
  2310.                             }
  2311.                             else {
  2312.                                 int endPos = readerAdapter.ParseNamedCharRef(false, null);
  2313.                                 LoadParsingBuffer();
  2314.                                
  2315.                                 if (endPos >= 0) {
  2316.                                     tokenStartPos = curPos;
  2317.                                     curPos = endPos;
  2318.                                     continue;
  2319.                                 }
  2320.                                 else {
  2321.                                     stringBuilder.Append('&');
  2322.                                     curPos++;
  2323.                                     tokenStartPos = curPos;
  2324.                                     // Bypass general entities in entity values
  2325.                                     XmlQualifiedName entityName = ScanEntityName();
  2326.                                     VerifyEntityReference(entityName, false, false, false);
  2327.                                 }
  2328.                                 continue;
  2329.                             }
  2330.                         }
  2331.                         break;
  2332.                     default:
  2333.                         // end of buffer
  2334.                         if (curPos == charsUsed) {
  2335.                             goto ReadData;
  2336.                         }
  2337.                         // surrogate chars
  2338.                         else {
  2339.                             char ch = chars[curPos];
  2340.                             if (ch >= 55296 && ch <= 56319) {
  2341.                                 if (curPos + 1 == charsUsed) {
  2342.                                     goto ReadData;
  2343.                                 }
  2344.                                 curPos++;
  2345.                                 if (chars[curPos] >= 56320 && chars[curPos] <= 57343) {
  2346.                                     curPos++;
  2347.                                     continue;
  2348.                                 }
  2349.                             }
  2350.                             ThrowInvalidChar(curPos, ch);
  2351.                             return Token.None;
  2352.                         }
  2353.                         break;
  2354.                 }
  2355.                 ReadData:
  2356.                
  2357.                 Debug.Assert(curPos - tokenStartPos == 0);
  2358.                
  2359.                 // read new characters into the buffer
  2360.                 if (readerAdapter.IsEof || ReadData() == 0) {
  2361.                     if (literalType == LiteralType.SystemOrPublicID || !HandleEntityEnd(true)) {
  2362.                         Throw(curPos, Res.Xml_UnclosedQuote);
  2363.                     }
  2364.                 }
  2365.                 tokenStartPos = curPos;
  2366.             }
  2367.         }
  2368.        
  2369.         private XmlQualifiedName ScanEntityName()
  2370.         {
  2371.             try {
  2372.                 ScanName();
  2373.             }
  2374.             catch (XmlException e) {
  2375.                 Throw(Res.Xml_ErrorParsingEntityName, string.Empty, e.LineNumber, e.LinePosition);
  2376.             }
  2377.            
  2378.             if (chars[curPos] != ';') {
  2379.                 ThrowUnexpectedToken(curPos, ";");
  2380.             }
  2381.             XmlQualifiedName entityName = GetNameQualified(false);
  2382.             curPos++;
  2383.            
  2384.             return entityName;
  2385.         }
  2386.        
  2387.         private Token ScanNotation1()
  2388.         {
  2389.             switch (chars[curPos]) {
  2390.                 case 'P':
  2391.                     if (!EatPublicKeyword()) {
  2392.                         Throw(curPos, Res.Xml_ExpectExternalOrClose);
  2393.                     }
  2394.                     nextScaningFunction = ScanningFunction.ClosingTag;
  2395.                     scanningFunction = ScanningFunction.PublicId1;
  2396.                     return Token.PUBLIC;
  2397.                 case 'S':
  2398.                     if (!EatSystemKeyword()) {
  2399.                         Throw(curPos, Res.Xml_ExpectExternalOrClose);
  2400.                     }
  2401.                     nextScaningFunction = ScanningFunction.ClosingTag;
  2402.                     scanningFunction = ScanningFunction.SystemId;
  2403.                     return Token.SYSTEM;
  2404.                 default:
  2405.                     Throw(curPos, Res.Xml_ExpectExternalOrPublicId);
  2406.                     return Token.None;
  2407.             }
  2408.         }
  2409.        
  2410.         private Token ScanSystemId()
  2411.         {
  2412.             if (chars[curPos] != '"' && chars[curPos] != '\'') {
  2413.                 ThrowUnexpectedToken(curPos, "\"", "'");
  2414.             }
  2415.            
  2416.             ScanLiteral(LiteralType.SystemOrPublicID);
  2417.            
  2418.             scanningFunction = nextScaningFunction;
  2419.             return Token.Literal;
  2420.         }
  2421.        
  2422.         private Token ScanEntity1()
  2423.         {
  2424.             if (chars[curPos] == '%') {
  2425.                 curPos++;
  2426.                 nextScaningFunction = ScanningFunction.Entity2;
  2427.                 scanningFunction = ScanningFunction.Name;
  2428.                 return Token.Percent;
  2429.             }
  2430.             else {
  2431.                 ScanName();
  2432.                 scanningFunction = ScanningFunction.Entity2;
  2433.                 return Token.Name;
  2434.             }
  2435.         }
  2436.        
  2437.         private Token ScanEntity2()
  2438.         {
  2439.             switch (chars[curPos]) {
  2440.                 case 'P':
  2441.                     if (!EatPublicKeyword()) {
  2442.                         Throw(curPos, Res.Xml_ExpectExternalOrClose);
  2443.                     }
  2444.                     nextScaningFunction = ScanningFunction.Entity3;
  2445.                     scanningFunction = ScanningFunction.PublicId1;
  2446.                     return Token.PUBLIC;
  2447.                 case 'S':
  2448.                     if (!EatSystemKeyword()) {
  2449.                         Throw(curPos, Res.Xml_ExpectExternalOrClose);
  2450.                     }
  2451.                     nextScaningFunction = ScanningFunction.Entity3;
  2452.                     scanningFunction = ScanningFunction.SystemId;
  2453.                     return Token.SYSTEM;
  2454.                 case '"':
  2455.                 case '\'':
  2456.                    
  2457.                     ScanLiteral(LiteralType.EntityReplText);
  2458.                     scanningFunction = ScanningFunction.ClosingTag;
  2459.                     return Token.Literal;
  2460.                 default:
  2461.                     Throw(curPos, Res.Xml_ExpectExternalIdOrEntityValue);
  2462.                     return Token.None;
  2463.             }
  2464.         }
  2465.        
  2466.         private Token ScanEntity3()
  2467.         {
  2468.             if (chars[curPos] == 'N') {
  2469.                 while (charsUsed - curPos < 5) {
  2470.                     if (ReadData() == 0) {
  2471.                         goto End;
  2472.                     }
  2473.                 }
  2474.                 if (chars[curPos + 1] == 'D' && chars[curPos + 2] == 'A' && chars[curPos + 3] == 'T' && chars[curPos + 4] == 'A') {
  2475.                     curPos += 5;
  2476.                     scanningFunction = ScanningFunction.Name;
  2477.                     nextScaningFunction = ScanningFunction.ClosingTag;
  2478.                     return Token.NData;
  2479.                 }
  2480.             }
  2481.             End:
  2482.             scanningFunction = ScanningFunction.ClosingTag;
  2483.             return Token.None;
  2484.         }
  2485.        
  2486.         private Token ScanPublicId1()
  2487.         {
  2488.             if (chars[curPos] != '"' && chars[curPos] != '\'') {
  2489.                 ThrowUnexpectedToken(curPos, "\"", "'");
  2490.             }
  2491.            
  2492.             ScanLiteral(LiteralType.SystemOrPublicID);
  2493.            
  2494.             scanningFunction = ScanningFunction.PublicId2;
  2495.             return Token.Literal;
  2496.         }
  2497.        
  2498.         private Token ScanPublicId2()
  2499.         {
  2500.             if (chars[curPos] != '"' && chars[curPos] != '\'') {
  2501.                 scanningFunction = nextScaningFunction;
  2502.                 return Token.None;
  2503.             }
  2504.            
  2505.             ScanLiteral(LiteralType.SystemOrPublicID);
  2506.             scanningFunction = nextScaningFunction;
  2507.            
  2508.             return Token.Literal;
  2509.         }
  2510.        
  2511.         private Token ScanCondSection1()
  2512.         {
  2513.             if (chars[curPos] != 'I') {
  2514.                 Throw(curPos, Res.Xml_ExpectIgnoreOrInclude);
  2515.             }
  2516.             curPos++;
  2517.            
  2518.             for (;;) {
  2519.                 if (charsUsed - curPos < 5) {
  2520.                     goto ReadData;
  2521.                 }
  2522.                 switch (chars[curPos]) {
  2523.                     case 'N':
  2524.                         if (charsUsed - curPos < 6) {
  2525.                             goto ReadData;
  2526.                         }
  2527.                         if (chars[curPos + 1] != 'C' || chars[curPos + 2] != 'L' || chars[curPos + 3] != 'U' || chars[curPos + 4] != 'D' || chars[curPos + 5] != 'E' || xmlCharType.IsNameChar(chars[curPos + 6])) {
  2528.                             goto default;
  2529.                         }
  2530.                         nextScaningFunction = ScanningFunction.SubsetContent;
  2531.                         scanningFunction = ScanningFunction.CondSection2;
  2532.                         curPos += 6;
  2533.                         return Token.INCLUDE;
  2534.                     case 'G':
  2535.                         if (chars[curPos + 1] != 'N' || chars[curPos + 2] != 'O' || chars[curPos + 3] != 'R' || chars[curPos + 4] != 'E' || xmlCharType.IsNameChar(chars[curPos + 5])) {
  2536.                             goto default;
  2537.                         }
  2538.                         nextScaningFunction = ScanningFunction.CondSection3;
  2539.                         scanningFunction = ScanningFunction.CondSection2;
  2540.                         curPos += 5;
  2541.                         return Token.IGNORE;
  2542.                     default:
  2543.                         Throw(curPos - 1, Res.Xml_ExpectIgnoreOrInclude);
  2544.                         return Token.None;
  2545.                 }
  2546.                 ReadData:
  2547.                 if (ReadData() == 0) {
  2548.                     Throw(curPos, Res.Xml_IncompleteDtdContent);
  2549.                 }
  2550.             }
  2551.         }
  2552.        
  2553.         private Token ScanCondSection2()
  2554.         {
  2555.             if (chars[curPos] != '[') {
  2556.                 ThrowUnexpectedToken(curPos, "[");
  2557.             }
  2558.             curPos++;
  2559.             scanningFunction = nextScaningFunction;
  2560.             return Token.RightBracket;
  2561.         }
  2562.        
  2563.         private Token ScanCondSection3()
  2564.         {
  2565.             int ignoreSectionDepth = 0;
  2566.            
  2567.             // skip ignored part
  2568.             for (;;) {
  2569.                 unsafe {
  2570.                     while ((xmlCharType.charProperties[chars[curPos]] & XmlCharType.fText) != 0 && chars[curPos] != ']') {
  2571.                         curPos++;
  2572.                     }
  2573.                 }
  2574.                
  2575.                 switch (chars[curPos]) {
  2576.                     case '"':
  2577.                     case '\'':
  2578.                     case (char)9:
  2579.                     case '&':
  2580.                         curPos++;
  2581.                         continue;
  2582.                     case (char)10:
  2583.                         // eol
  2584.                         curPos++;
  2585.                         readerAdapter.OnNewLine(curPos);
  2586.                         continue;
  2587.                     case (char)13:
  2588.                         Debug.Assert(!ParsingInternalSubset);
  2589.                         // no need to normalize
  2590.                         if (chars[curPos + 1] == (char)10) {
  2591.                             curPos += 2;
  2592.                         }
  2593.                         else if (curPos + 1 < charsUsed || readerAdapter.IsEof) {
  2594.                             curPos++;
  2595.                         }
  2596.                         else {
  2597.                             goto ReadData;
  2598.                         }
  2599.                         readerAdapter.OnNewLine(curPos);
  2600.                         continue;
  2601.                     case '<':
  2602.                         if (charsUsed - curPos < 3) {
  2603.                             goto ReadData;
  2604.                         }
  2605.                         if (chars[curPos + 1] != '!' || chars[curPos + 2] != '[') {
  2606.                             curPos++;
  2607.                             continue;
  2608.                         }
  2609.                         ignoreSectionDepth++;
  2610.                         curPos += 3;
  2611.                         continue;
  2612.                     case ']':
  2613.                         if (charsUsed - curPos < 3) {
  2614.                             goto ReadData;
  2615.                         }
  2616.                         if (chars[curPos + 1] != ']' || chars[curPos + 2] != '>') {
  2617.                             curPos++;
  2618.                             continue;
  2619.                         }
  2620.                         if (ignoreSectionDepth > 0) {
  2621.                             ignoreSectionDepth--;
  2622.                             curPos += 3;
  2623.                             continue;
  2624.                         }
  2625.                         else {
  2626.                             curPos += 3;
  2627.                             scanningFunction = ScanningFunction.SubsetContent;
  2628.                             return Token.CondSectionEnd;
  2629.                         }
  2630.                         break;
  2631.                     default:
  2632.                         // end of buffer
  2633.                         if (curPos == charsUsed) {
  2634.                             goto ReadData;
  2635.                         }
  2636.                         // surrogate chars
  2637.                         else {
  2638.                             char ch = chars[curPos];
  2639.                             if (ch >= 55296 && ch <= 56319) {
  2640.                                 if (curPos + 1 == charsUsed) {
  2641.                                     goto ReadData;
  2642.                                 }
  2643.                                 curPos++;
  2644.                                 if (chars[curPos] >= 56320 && chars[curPos] <= 57343) {
  2645.                                     curPos++;
  2646.                                     continue;
  2647.                                 }
  2648.                             }
  2649.                             ThrowInvalidChar(curPos, ch);
  2650.                             return Token.None;
  2651.                         }
  2652.                         break;
  2653.                 }
  2654.                 ReadData:
  2655.                
  2656.                 // read new characters into the buffer
  2657.                 if (readerAdapter.IsEof || ReadData() == 0) {
  2658.                     if (HandleEntityEnd(false)) {
  2659.                         continue;
  2660.                     }
  2661.                     Throw(curPos, Res.Xml_UnclosedConditionalSection);
  2662.                 }
  2663.                 tokenStartPos = curPos;
  2664.             }
  2665.         }
  2666.        
  2667.         private void ScanName()
  2668.         {
  2669.             ScanQName(false);
  2670.         }
  2671.        
  2672.         private void ScanQName()
  2673.         {
  2674.             ScanQName(supportNamespaces);
  2675.         }
  2676.        
  2677.         private void ScanQName(bool isQName)
  2678.         {
  2679.             tokenStartPos = curPos;
  2680.             int colonOffset = -1;
  2681.            
  2682.             for (;;) {
  2683.                 unsafe {
  2684.                     if ((xmlCharType.charProperties[chars[curPos]] & XmlCharType.fNCStartName) == 0 && chars[curPos] != ':') {
  2685.                         if (curPos == charsUsed) {
  2686.                             if (ReadDataInName()) {
  2687.                                 continue;
  2688.                             }
  2689.                             Throw(curPos, Res.Xml_UnexpectedEOF, "Name");
  2690.                         }
  2691.                         else if (chars[curPos] != ':' || supportNamespaces) {
  2692.                             Throw(curPos, Res.Xml_BadStartNameChar, XmlException.BuildCharExceptionStr(chars[curPos]));
  2693.                         }
  2694.                     }
  2695.                 }
  2696.                 curPos++;
  2697.                 ContinueName:
  2698.                
  2699.                 unsafe {
  2700.                     while ((xmlCharType.charProperties[chars[curPos]] & XmlCharType.fNCName) != 0) {
  2701.                         curPos++;
  2702.                     }
  2703.                 }
  2704.                
  2705.                 if (chars[curPos] == ':') {
  2706.                     if (isQName) {
  2707.                         if (colonOffset != -1) {
  2708.                             Throw(curPos, Res.Xml_BadNameChar, XmlException.BuildCharExceptionStr(':'));
  2709.                         }
  2710.                         colonOffset = curPos - tokenStartPos;
  2711.                         curPos++;
  2712.                         continue;
  2713.                     }
  2714.                     else {
  2715.                         curPos++;
  2716.                         goto ContinueName;
  2717.                     }
  2718.                 }
  2719.                 // end of buffer
  2720.                 else if (charsUsed - curPos == 0) {
  2721.                     if (ReadDataInName()) {
  2722.                         goto ContinueName;
  2723.                     }
  2724.                     if (tokenStartPos == curPos) {
  2725.                         Throw(curPos, Res.Xml_UnexpectedEOF, "Name");
  2726.                     }
  2727.                 }
  2728.                 // end of name
  2729.                 colonPos = (colonOffset == -1) ? -1 : tokenStartPos + colonOffset;
  2730.                 return;
  2731.             }
  2732.         }
  2733.        
  2734.         private bool ReadDataInName()
  2735.         {
  2736.             int offset = curPos - tokenStartPos;
  2737.             curPos = tokenStartPos;
  2738.             bool newDataRead = (ReadData() != 0);
  2739.             tokenStartPos = curPos;
  2740.             curPos += offset;
  2741.             return newDataRead;
  2742.         }
  2743.        
  2744.         private void ScanNmtoken()
  2745.         {
  2746.             tokenStartPos = curPos;
  2747.            
  2748.             for (;;) {
  2749.                 unsafe {
  2750.                     while ((xmlCharType.charProperties[chars[curPos]] & XmlCharType.fNCName) != 0 || chars[curPos] == ':') {
  2751.                         curPos++;
  2752.                     }
  2753.                 }
  2754.                
  2755.                 if (chars[curPos] != 0) {
  2756.                     if (curPos - tokenStartPos == 0) {
  2757.                         Throw(curPos, Res.Xml_BadNameChar, XmlException.BuildCharExceptionStr(chars[curPos]));
  2758.                     }
  2759.                     return;
  2760.                 }
  2761.                
  2762.                 int len = curPos - tokenStartPos;
  2763.                 curPos = tokenStartPos;
  2764.                 if (ReadData() == 0) {
  2765.                     if (len > 0) {
  2766.                         tokenStartPos = curPos;
  2767.                         curPos += len;
  2768.                         return;
  2769.                     }
  2770.                     Throw(curPos, Res.Xml_UnexpectedEOF, "NmToken");
  2771.                 }
  2772.                 tokenStartPos = curPos;
  2773.                 curPos += len;
  2774.             }
  2775.         }
  2776.        
  2777.         private bool EatPublicKeyword()
  2778.         {
  2779.             Debug.Assert(chars[curPos] == 'P');
  2780.             while (charsUsed - curPos < 6) {
  2781.                 if (ReadData() == 0) {
  2782.                     return false;
  2783.                 }
  2784.             }
  2785.             if (chars[curPos + 1] != 'U' || chars[curPos + 2] != 'B' || chars[curPos + 3] != 'L' || chars[curPos + 4] != 'I' || chars[curPos + 5] != 'C') {
  2786.                 return false;
  2787.             }
  2788.             curPos += 6;
  2789.             return true;
  2790.         }
  2791.        
  2792.         private bool EatSystemKeyword()
  2793.         {
  2794.             Debug.Assert(chars[curPos] == 'S');
  2795.             while (charsUsed - curPos < 6) {
  2796.                 if (ReadData() == 0) {
  2797.                     return false;
  2798.                 }
  2799.             }
  2800.             if (chars[curPos + 1] != 'Y' || chars[curPos + 2] != 'S' || chars[curPos + 3] != 'T' || chars[curPos + 4] != 'E' || chars[curPos + 5] != 'M') {
  2801.                 return false;
  2802.             }
  2803.             curPos += 6;
  2804.             return true;
  2805.         }
  2806.        
  2807.         //
  2808.         // Scanned data getters
  2809.         //
  2810.         private XmlQualifiedName GetNameQualified(bool canHavePrefix)
  2811.         {
  2812.             Debug.Assert(curPos - tokenStartPos > 0);
  2813.             if (colonPos == -1) {
  2814.                 return new XmlQualifiedName(nameTable.Add(chars, tokenStartPos, curPos - tokenStartPos));
  2815.             }
  2816.             else {
  2817.                 if (canHavePrefix) {
  2818.                     return new XmlQualifiedName(nameTable.Add(chars, colonPos + 1, curPos - colonPos - 1), nameTable.Add(chars, tokenStartPos, colonPos - tokenStartPos));
  2819.                 }
  2820.                 else {
  2821.                     Throw(tokenStartPos, Res.Xml_ColonInLocalName, GetNameString());
  2822.                     return null;
  2823.                 }
  2824.             }
  2825.         }
  2826.        
  2827.         private string GetNameString()
  2828.         {
  2829.             Debug.Assert(curPos - tokenStartPos > 0);
  2830.             return new string(chars, tokenStartPos, curPos - tokenStartPos);
  2831.         }
  2832.        
  2833.         private string GetNmtokenString()
  2834.         {
  2835.             return GetNameString();
  2836.         }
  2837.        
  2838.         private string GetValue()
  2839.         {
  2840.             if (stringBuilder.Length == 0) {
  2841.                 return new string(chars, tokenStartPos, curPos - tokenStartPos - 1);
  2842.             }
  2843.             else {
  2844.                 return stringBuilder.ToString();
  2845.             }
  2846.         }
  2847.        
  2848.         private string GetValueWithStrippedSpaces()
  2849.         {
  2850.             Debug.Assert(curPos == 0 || chars[curPos - 1] == '"' || chars[curPos - 1] == '\'');
  2851.             if (stringBuilder.Length == 0) {
  2852.                 int len = curPos - tokenStartPos - 1;
  2853.                 XmlComplianceUtil.StripSpaces(chars, tokenStartPos, ref len);
  2854.                 return new string(chars, tokenStartPos, len);
  2855.             }
  2856.             else {
  2857.                 return XmlComplianceUtil.StripSpaces(stringBuilder.ToString());
  2858.             }
  2859.         }
  2860.         //
  2861.         // Parsing buffer maintainance methods
  2862.         //
  2863.         int ReadData()
  2864.         {
  2865.             SaveParsingBuffer();
  2866.             int charsRead = readerAdapter.ReadData();
  2867.             LoadParsingBuffer();
  2868.             return charsRead;
  2869.         }
  2870.        
  2871.         private void LoadParsingBuffer()
  2872.         {
  2873.             chars = readerAdapter.ParsingBuffer;
  2874.             charsUsed = readerAdapter.ParsingBufferLength;
  2875.             curPos = readerAdapter.CurrentPosition;
  2876.         }
  2877.        
  2878.         private void SaveParsingBuffer()
  2879.         {
  2880.             SaveParsingBuffer(curPos);
  2881.         }
  2882.        
  2883.         private void SaveParsingBuffer(int internalSubsetValueEndPos)
  2884.         {
  2885.             if (SaveInternalSubsetValue) {
  2886.                 Debug.Assert(internalSubsetValueSb != null);
  2887.                
  2888.                 int readerCurPos = readerAdapter.CurrentPosition;
  2889.                 if (internalSubsetValueEndPos - readerCurPos > 0) {
  2890.                     internalSubsetValueSb.Append(chars, readerCurPos, internalSubsetValueEndPos - readerCurPos);
  2891.                 }
  2892.             }
  2893.             readerAdapter.CurrentPosition = curPos;
  2894.         }
  2895.        
  2896.         //
  2897.         // Entity handling
  2898.         //
  2899.         private bool HandleEntityReference(bool paramEntity, bool inLiteral, bool inAttribute)
  2900.         {
  2901.             Debug.Assert(chars[curPos] == '&' || chars[curPos] == '%');
  2902.             curPos++;
  2903.             return HandleEntityReference(ScanEntityName(), paramEntity, inLiteral, inAttribute);
  2904.         }
  2905.        
  2906.         private bool HandleEntityReference(XmlQualifiedName entityName, bool paramEntity, bool inLiteral, bool inAttribute)
  2907.         {
  2908.             Debug.Assert(chars[curPos - 1] == ';');
  2909.            
  2910.             SaveParsingBuffer();
  2911.             if (paramEntity && ParsingInternalSubset && !ParsingTopLevelMarkup) {
  2912.                 Throw(curPos - entityName.Name.Length - 1, Res.Xml_InvalidParEntityRef);
  2913.             }
  2914.            
  2915.             SchemaEntity entity = VerifyEntityReference(entityName, paramEntity, true, inAttribute);
  2916.             if (entity == null) {
  2917.                 return false;
  2918.             }
  2919.             if (entity.IsProcessed) {
  2920.                 Throw(curPos - entityName.Name.Length - 1, paramEntity ? Res.Xml_RecursiveParEntity : Res.Xml_RecursiveGenEntity, entityName.Name);
  2921.             }
  2922.            
  2923.             int newEntityId = nextEntityId++;
  2924.            
  2925.             if (entity.IsExternal) {
  2926.                 if (!readerAdapter.PushEntity(entity, newEntityId)) {
  2927.                     return false;
  2928.                 }
  2929.                 externalEntitiesDepth++;
  2930.             }
  2931.             else {
  2932.                 if (entity.Text.Length == 0) {
  2933.                     return false;
  2934.                 }
  2935.                 if (!readerAdapter.PushEntity(entity, newEntityId)) {
  2936.                     return false;
  2937.                 }
  2938.             }
  2939.             currentEntityId = newEntityId;
  2940.            
  2941.             if (paramEntity && !inLiteral && scanningFunction != ScanningFunction.ParamEntitySpace) {
  2942.                 savedScanningFunction = scanningFunction;
  2943.                 scanningFunction = ScanningFunction.ParamEntitySpace;
  2944.             }
  2945.            
  2946.             LoadParsingBuffer();
  2947.             return true;
  2948.         }
  2949.        
  2950.         private bool HandleEntityEnd(bool inLiteral)
  2951.         {
  2952.             SaveParsingBuffer();
  2953.            
  2954.             SchemaEntity oldEntity;
  2955.             if (!readerAdapter.PopEntity(out oldEntity, out currentEntityId)) {
  2956.                 return false;
  2957.             }
  2958.             LoadParsingBuffer();
  2959.            
  2960.             if (oldEntity == null) {
  2961.                 // external subset popped
  2962.                 Debug.Assert(!ParsingInternalSubset || freeFloatingDtd);
  2963.                 Debug.Assert(currentEntityId == 0);
  2964.                 if (scanningFunction == ScanningFunction.ParamEntitySpace) {
  2965.                     scanningFunction = savedScanningFunction;
  2966.                 }
  2967.                 return false;
  2968.             }
  2969.            
  2970.             if (oldEntity.IsExternal) {
  2971.                 externalEntitiesDepth--;
  2972.             }
  2973.            
  2974.             if (!inLiteral && scanningFunction != ScanningFunction.ParamEntitySpace) {
  2975.                 savedScanningFunction = scanningFunction;
  2976.                 scanningFunction = ScanningFunction.ParamEntitySpace;
  2977.             }
  2978.            
  2979.             return true;
  2980.         }
  2981.        
  2982.         private SchemaEntity VerifyEntityReference(XmlQualifiedName entityName, bool paramEntity, bool mustBeDeclared, bool inAttribute)
  2983.         {
  2984.             Debug.Assert(chars[curPos - 1] == ';');
  2985.            
  2986.             SchemaEntity entity;
  2987.             if (paramEntity) {
  2988.                 entity = (SchemaEntity)schemaInfo.ParameterEntities[entityName];
  2989.             }
  2990.             else {
  2991.                 entity = (SchemaEntity)schemaInfo.GeneralEntities[entityName];
  2992.             }
  2993.            
  2994.             if (entity == null) {
  2995.                 if (paramEntity) {
  2996.                     if (validate) {
  2997.                         SendValidationEvent(curPos - entityName.Name.Length - 1, XmlSeverityType.Error, Res.Xml_UndeclaredParEntity, entityName.Name);
  2998.                     }
  2999.                 }
  3000.                 else if (mustBeDeclared) {
  3001.                     if (!ParsingInternalSubset) {
  3002.                         SendValidationEvent(curPos - entityName.Name.Length - 1, XmlSeverityType.Error, Res.Xml_UndeclaredEntity, entityName.Name);
  3003.                     }
  3004.                     else {
  3005.                         Throw(curPos - entityName.Name.Length - 1, Res.Xml_UndeclaredEntity, entityName.Name);
  3006.                     }
  3007.                 }
  3008.                 return null;
  3009.             }
  3010.            
  3011.             if (!entity.NData.IsEmpty) {
  3012.                 Throw(curPos - entityName.Name.Length - 1, Res.Xml_UnparsedEntityRef, entityName.Name);
  3013.             }
  3014.            
  3015.             if (inAttribute && entity.IsExternal) {
  3016.                 Throw(curPos - entityName.Name.Length - 1, Res.Xml_ExternalEntityInAttValue, entityName.Name);
  3017.             }
  3018.            
  3019.             return entity;
  3020.         }
  3021.        
  3022.         //
  3023.         // Helper methods and properties
  3024.         //
  3025.         private void SendValidationEvent(int pos, XmlSeverityType severity, string code, string arg)
  3026.         {
  3027.             Debug.Assert(validate);
  3028.             SendValidationEvent(severity, new XmlSchemaException(code, arg, BaseUriStr, (int)LineNo, (int)LinePos + (pos - curPos)));
  3029.         }
  3030.        
  3031.         private void SendValidationEvent(XmlSeverityType severity, string code, string arg)
  3032.         {
  3033.             Debug.Assert(validate);
  3034.             SendValidationEvent(severity, new XmlSchemaException(code, arg, BaseUriStr, (int)LineNo, (int)LinePos));
  3035.         }
  3036.        
  3037.         private void SendValidationEvent(XmlSeverityType severity, XmlSchemaException e)
  3038.         {
  3039.             Debug.Assert(validate);
  3040.             readerAdapter.SendValidationEvent(severity, e);
  3041.         }
  3042.        
  3043.         private bool IsAttributeValueType(Token token)
  3044.         {
  3045.             return (int)token >= (int)Token.CDATA && (int)token <= (int)Token.NOTATION;
  3046.         }
  3047.        
  3048.         private int LineNo {
  3049.             get { return readerAdapter.LineNo; }
  3050.         }
  3051.        
  3052.         private int LinePos {
  3053.             get { return curPos - readerAdapter.LineStartPosition; }
  3054.         }
  3055.        
  3056.         private string BaseUriStr {
  3057.             get {
  3058.                 Uri tmp = readerAdapter.BaseUri;
  3059.                 return (tmp != null) ? tmp.ToString() : string.Empty;
  3060.             }
  3061.         }
  3062.        
  3063.         private void OnUnexpectedError()
  3064.         {
  3065.             Debug.Assert(false, "This is an unexpected error that should have been handled in the ScanXXX methods.");
  3066.             Throw(curPos, Res.Xml_InternalError);
  3067.         }
  3068.        
  3069.         void Throw(int curPos, string res)
  3070.         {
  3071.             Throw(curPos, res, string.Empty);
  3072.         }
  3073.        
  3074.         void Throw(int curPos, string res, string arg)
  3075.         {
  3076.             this.curPos = curPos;
  3077.             Uri baseUri = readerAdapter.BaseUri;
  3078.             readerAdapter.Throw(new XmlException(res, arg, (int)LineNo, (int)LinePos, baseUri == null ? null : baseUri.ToString()));
  3079.         }
  3080.         void Throw(int curPos, string res, string[] args)
  3081.         {
  3082.             this.curPos = curPos;
  3083.             Uri baseUri = readerAdapter.BaseUri;
  3084.             readerAdapter.Throw(new XmlException(res, args, (int)LineNo, (int)LinePos, baseUri == null ? null : baseUri.ToString()));
  3085.         }
  3086.        
  3087.         void Throw(string res, string arg, int lineNo, int linePos)
  3088.         {
  3089.             Uri baseUri = readerAdapter.BaseUri;
  3090.             readerAdapter.Throw(new XmlException(res, arg, (int)lineNo, (int)linePos, baseUri == null ? null : baseUri.ToString()));
  3091.         }
  3092.        
  3093.         void ThrowInvalidChar(int pos, char invChar)
  3094.         {
  3095.             Throw(pos, Res.Xml_InvalidCharacter, XmlException.BuildCharExceptionStr(invChar));
  3096.         }
  3097.        
  3098.         private void ThrowUnexpectedToken(int pos, string expectedToken)
  3099.         {
  3100.             ThrowUnexpectedToken(pos, expectedToken, null);
  3101.         }
  3102.        
  3103.         private void ThrowUnexpectedToken(int pos, string expectedToken1, string expectedToken2)
  3104.         {
  3105.             string unexpectedToken = ParseUnexpectedToken(pos);
  3106.             if (expectedToken2 != null) {
  3107.                 Throw(curPos, Res.Xml_UnexpectedTokens2, new string[3] {unexpectedToken, expectedToken1, expectedToken2});
  3108.             }
  3109.             else {
  3110.                 Throw(curPos, Res.Xml_UnexpectedTokenEx, new string[2] {unexpectedToken, expectedToken1});
  3111.             }
  3112.         }
  3113.        
  3114.         private string ParseUnexpectedToken(int startPos)
  3115.         {
  3116.             if (xmlCharType.IsNCNameChar(chars[startPos])) {
  3117.                 int endPos = startPos + 1;
  3118.                 while (xmlCharType.IsNCNameChar(chars[endPos])) {
  3119.                     endPos++;
  3120.                 }
  3121.                 return new string(chars, startPos, endPos - startPos);
  3122.             }
  3123.             else {
  3124.                 Debug.Assert(startPos < charsUsed);
  3125.                 return new string(chars, startPos, 1);
  3126.             }
  3127.         }
  3128.     }
  3129. }

Developer Fusion