Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Xml / System / Xml / schema / DtdParser.cs / 1305376 / DtdParser.cs
//------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //[....] //----------------------------------------------------------------------------- using System; using System.IO; using System.Text; using System.Xml.Schema; using System.Diagnostics; using System.Collections; using System.Collections.Generic; using System.Globalization; #if SILVERLIGHT using BufferBuilder=System.Xml.BufferBuilder; #else using BufferBuilder = System.Text.StringBuilder; #endif namespace System.Xml { internal class DtdParser : IDtdParser { // // Private types // enum Token { CDATA = XmlTokenizedType.CDATA, // == 0 ID = XmlTokenizedType.ID, // == 1 IDREF = XmlTokenizedType.IDREF, // == 2 IDREFS = XmlTokenizedType.IDREFS, // == 3 ENTITY = XmlTokenizedType.ENTITY, // == 4 ENTITIES = XmlTokenizedType.ENTITIES, // == 5 NMTOKEN = XmlTokenizedType.NMTOKEN, // == 6 NMTOKENS = XmlTokenizedType.NMTOKENS, // == 7 NOTATION = XmlTokenizedType.NOTATION, // == 8 None , PERef , AttlistDecl , ElementDecl , EntityDecl , NotationDecl , Comment , PI , CondSectionStart, CondSectionEnd , Eof , REQUIRED , IMPLIED , FIXED , QName , Name , Nmtoken , Quote, LeftParen , RightParen , GreaterThan , Or , LeftBracket , RightBracket , PUBLIC , SYSTEM , Literal , DOCTYPE , NData , Percent , Star , QMark , Plus , PCDATA , Comma , ANY , EMPTY , IGNORE , INCLUDE , } enum ScanningFunction { SubsetContent, Name, QName, Nmtoken, Doctype1, Doctype2, Element1, Element2, Element3, Element4, Element5, Element6, Element7, Attlist1, Attlist2, Attlist3, Attlist4, Attlist5, Attlist6, Attlist7, Entity1, Entity2, Entity3, Notation1, CondSection1, CondSection2, CondSection3, Literal, SystemId, PublicId1, PublicId2, ClosingTag, ParamEntitySpace, None, } enum LiteralType { AttributeValue, EntityReplText, SystemOrPublicID } #if !SILVERLIGHT class UndeclaredNotation { internal string name; internal int lineNo; internal int linePos; internal UndeclaredNotation next; internal UndeclaredNotation( string name, int lineNo, int linePos ) { this.name = name; this.lineNo = lineNo; this.linePos = linePos; this.next = null; } } #endif // // Fields // // connector to reader IDtdParserAdapter readerAdapter; #if !SILVERLIGHT IDtdParserAdapterWithValidation readerAdapterWithValidation; #endif // name table XmlNameTable nameTable; // final schema info SchemaInfo schemaInfo; // XmlCharType instance XmlCharType xmlCharType = XmlCharType.Instance; // system & public id string systemId = string.Empty; string publicId = string.Empty; // flags #if !SILVERLIGHT bool normalize = true; bool validate = false; bool supportNamespaces = true; bool v1Compat = false; #endif // cached character buffer char[] chars; int charsUsed; int curPos; // scanning function for the next token ScanningFunction scanningFunction; ScanningFunction nextScaningFunction; ScanningFunction savedScanningFunction; // this one is used only for adding spaces around parameter entities // flag if whitespace seen before token bool whitespaceSeen; // start position of the last token (for name and value) int tokenStartPos; // colon position (for name) int colonPos; // value of the internal subset BufferBuilder internalSubsetValueSb = null; // entities int externalEntitiesDepth = 0; int currentEntityId = 0; // free-floating DTD support bool freeFloatingDtd = false; bool hasFreeFloatingInternalSubset = false; // misc BufferBuilder stringBuilder; int condSectionDepth = 0; LineInfo literalLineInfo = new LineInfo( 0, 0 ); char literalQuoteChar = '"'; string documentBaseUri = string.Empty; string externalDtdBaseUri = string.Empty; #if !SILVERLIGHT DictionaryundeclaredNotations = null; int[] condSectionEntityIds = null; #endif const int CondSectionEntityIdsInitialSize = 2; // // Constructor // static DtdParser() { #if DEBUG // The absolute numbering is utilized in attribute type parsing Debug.Assert( (int)Token.CDATA == (int)XmlTokenizedType.CDATA && (int)XmlTokenizedType.CDATA == 0 ); Debug.Assert( (int)Token.ID == (int)XmlTokenizedType.ID && (int)XmlTokenizedType.ID == 1 ); Debug.Assert( (int)Token.IDREF == (int)XmlTokenizedType.IDREF && (int)XmlTokenizedType.IDREF == 2 ); Debug.Assert( (int)Token.IDREFS == (int)XmlTokenizedType.IDREFS && (int)XmlTokenizedType.IDREFS == 3 ); Debug.Assert( (int)Token.ENTITY == (int)XmlTokenizedType.ENTITY && (int)XmlTokenizedType.ENTITY == 4 ); Debug.Assert( (int)Token.ENTITIES == (int)XmlTokenizedType.ENTITIES && (int)XmlTokenizedType.ENTITIES == 5 ); Debug.Assert( (int)Token.NMTOKEN == (int)XmlTokenizedType.NMTOKEN && (int)XmlTokenizedType.NMTOKEN == 6 ); Debug.Assert( (int)Token.NMTOKENS == (int)XmlTokenizedType.NMTOKENS && (int)XmlTokenizedType.NMTOKENS == 7 ); Debug.Assert( (int)Token.NOTATION == (int)XmlTokenizedType.NOTATION && (int)XmlTokenizedType.NOTATION == 8 ); #endif } DtdParser() { } internal static IDtdParser Create() { return new DtdParser(); } // // Initialization methods // private void Initialize(IDtdParserAdapter readerAdapter) { Debug.Assert(readerAdapter != null); this.readerAdapter = readerAdapter; #if !SILVERLIGHT this.readerAdapterWithValidation = readerAdapter as IDtdParserAdapterWithValidation; #endif nameTable = readerAdapter.NameTable; #if !SILVERLIGHT IDtdParserAdapterWithValidation raWithValidation = readerAdapter as IDtdParserAdapterWithValidation; if (raWithValidation != null) { this.validate = raWithValidation.DtdValidation; } IDtdParserAdapterV1 raV1 = readerAdapter as IDtdParserAdapterV1; if (raV1 != null) { v1Compat = raV1.V1CompatibilityMode; this.normalize = raV1.Normalization; this.supportNamespaces = raV1.Namespaces; } #endif schemaInfo = new SchemaInfo(); #if !SILVERLIGHT schemaInfo.SchemaType = SchemaType.DTD; #endif stringBuilder = new BufferBuilder(); Uri baseUri = readerAdapter.BaseUri; if (baseUri != null) { documentBaseUri = baseUri.ToString(); } freeFloatingDtd = false; } private void InitializeFreeFloatingDtd(string baseUri, string docTypeName, string publicId, string systemId, string internalSubset, IDtdParserAdapter adapter) { Initialize(adapter); if ( docTypeName == null || docTypeName.Length == 0 ) { throw XmlConvert.CreateInvalidNameArgumentException( docTypeName, "docTypeName" ); } // check doctype name XmlConvert.VerifyName( docTypeName ); int colonPos = docTypeName.IndexOf( ':' ); if ( colonPos == -1 ) { schemaInfo.DocTypeName = new XmlQualifiedName( nameTable.Add( docTypeName ) ); } else { schemaInfo.DocTypeName = new XmlQualifiedName( nameTable.Add( docTypeName.Substring( 0, colonPos ) ), nameTable.Add( docTypeName.Substring( colonPos + 1 ) ) ); } int i; // check system id if ( systemId != null && systemId.Length > 0 ) { if ( ( i = xmlCharType.IsOnlyCharData( systemId ) ) >= 0 ) { ThrowInvalidChar( curPos, systemId, i ); } this.systemId = systemId; } // check public id if ( publicId != null && publicId.Length > 0 ) { if ( ( i = xmlCharType.IsPublicId( publicId ) ) >= 0 ) { ThrowInvalidChar( curPos, publicId, i ); } this.publicId = publicId; } // init free-floating internal subset if ( internalSubset != null && internalSubset.Length > 0 ) { readerAdapter.PushInternalDtd( baseUri, internalSubset ); hasFreeFloatingInternalSubset = true; } Uri baseUriOb = readerAdapter.BaseUri; if ( baseUriOb != null ) { documentBaseUri = baseUriOb.ToString(); } freeFloatingDtd = true; } // // IDtdParser interface // #region IDtdParser Members IDtdInfo IDtdParser.ParseInternalDtd(IDtdParserAdapter adapter, bool saveInternalSubset) { Initialize(adapter); Parse(saveInternalSubset); return schemaInfo; } IDtdInfo IDtdParser.ParseFreeFloatingDtd(string baseUri, string docTypeName, string publicId, string systemId, string internalSubset, IDtdParserAdapter adapter) { InitializeFreeFloatingDtd(baseUri, docTypeName, publicId, systemId, internalSubset, adapter); Parse(false); return schemaInfo; } #endregion // // Private properties // private bool ParsingInternalSubset { get { return externalEntitiesDepth == 0; } } private bool IgnoreEntityReferences { get { return scanningFunction == ScanningFunction.CondSection3; } } private bool SaveInternalSubsetValue { get { return readerAdapter.EntityStackLength == 0 && internalSubsetValueSb != null; } } private bool ParsingTopLevelMarkup { get { return scanningFunction == ScanningFunction.SubsetContent || ( scanningFunction == ScanningFunction.ParamEntitySpace && savedScanningFunction == ScanningFunction.SubsetContent ); } } private bool SupportNamespaces { get { #if SILVERLIGHT return true; #else return supportNamespaces; #endif } } private bool Normalize { get { #if SILVERLIGHT return true; #else return normalize; #endif } } // // Parsing methods // private void Parse( bool saveInternalSubset ) { if ( freeFloatingDtd ) { ParseFreeFloatingDtd(); } else { ParseInDocumentDtd( saveInternalSubset ); } schemaInfo.Finish(); #if !SILVERLIGHT // check undeclared forward references if ( validate && undeclaredNotations != null ) { foreach ( UndeclaredNotation un in undeclaredNotations.Values ) { UndeclaredNotation tmpUn = un; while ( tmpUn != null ) { SendValidationEvent( XmlSeverityType.Error, new XmlSchemaException( Res.Sch_UndeclaredNotation, un.name, BaseUriStr, (int)un.lineNo, (int)un.linePos ) ); tmpUn = tmpUn.next; } } } #endif } private void ParseInDocumentDtd( bool saveInternalSubset ) { LoadParsingBuffer(); scanningFunction = ScanningFunction.QName; nextScaningFunction = ScanningFunction.Doctype1; // doctype name if ( GetToken( false ) != Token.QName ) { OnUnexpectedError(); } schemaInfo.DocTypeName = GetNameQualified( true ); // SYSTEM or PUBLIC id Token token = GetToken( false ); if ( token == Token.SYSTEM || token == Token.PUBLIC ) { ParseExternalId( token, Token.DOCTYPE, out publicId, out systemId ); token = GetToken( false); } switch ( token ) { case Token.LeftBracket: if ( saveInternalSubset ) { SaveParsingBuffer(); // this will cause saving the internal subset right from the point after '[' internalSubsetValueSb = new BufferBuilder(); } ParseInternalSubset(); break; case Token.GreaterThan: break; default: OnUnexpectedError(); break; } SaveParsingBuffer(); if ( systemId != null && systemId.Length > 0 ) { ParseExternalSubset(); } } private void ParseFreeFloatingDtd() { if ( hasFreeFloatingInternalSubset ) { LoadParsingBuffer(); ParseInternalSubset(); SaveParsingBuffer(); } if ( systemId != null && systemId.Length > 0 ) { ParseExternalSubset(); } } private void ParseInternalSubset() { Debug.Assert( ParsingInternalSubset ); ParseSubset(); } private void ParseExternalSubset() { Debug.Assert( externalEntitiesDepth == 0 ); // push external subset if ( !readerAdapter.PushExternalSubset( systemId, publicId ) ) { return; } Uri baseUri = readerAdapter.BaseUri; if ( baseUri != null ) { externalDtdBaseUri = baseUri.ToString(); } externalEntitiesDepth++; LoadParsingBuffer(); // parse ParseSubset(); #if DEBUG Debug.Assert( readerAdapter.EntityStackLength == 0 || ( freeFloatingDtd && readerAdapter.EntityStackLength == 1 ) ); #endif } private void ParseSubset() { int startTagEntityId; for (;;) { Token token = GetToken( false ); startTagEntityId = currentEntityId; switch ( token ) { case Token.AttlistDecl: ParseAttlistDecl(); break; case Token.ElementDecl: ParseElementDecl(); break; case Token.EntityDecl: ParseEntityDecl(); break; case Token.NotationDecl: ParseNotationDecl(); break; case Token.Comment: ParseComment(); break; case Token.PI: ParsePI(); break; case Token.CondSectionStart: if ( ParsingInternalSubset ) { Throw( curPos - 3, Res.Xml_InvalidConditionalSection ); // 3==strlen(" 0 ) { condSectionDepth--; #if !SILVERLIGHT if ( validate && currentEntityId != condSectionEntityIds[condSectionDepth] ) { SendValidationEvent( curPos, XmlSeverityType.Error, Res.Sch_ParEntityRefNesting, string.Empty ); } #endif } else { Throw( curPos - 3, Res.Xml_UnexpectedCDataEnd ); } break; case Token.RightBracket: if ( ParsingInternalSubset ) { if ( condSectionDepth != 0 ) { Throw( curPos, Res.Xml_UnclosedConditionalSection ); } // append the rest to internal subset value but not the closing ']' if ( internalSubsetValueSb != null ) { Debug.Assert( curPos > 0 && chars[curPos-1] == ']' ); SaveParsingBuffer( curPos - 1 ); schemaInfo.InternalDtdSubset = internalSubsetValueSb.ToString(); internalSubsetValueSb = null; } // check '>' if ( GetToken( false ) != Token.GreaterThan ) { ThrowUnexpectedToken( curPos, ">" ); } #if DEBUG // check entity nesting Debug.Assert( readerAdapter.EntityStackLength == 0 || ( freeFloatingDtd && readerAdapter.EntityStackLength == 1 ) ); #endif } else { Throw( curPos, Res.Xml_ExpectDtdMarkup ); } return; case Token.Eof: if ( ParsingInternalSubset && !freeFloatingDtd ) { Throw( curPos, Res.Xml_IncompleteDtdContent ); } if ( condSectionDepth != 0 ) { Throw( curPos, Res.Xml_UnclosedConditionalSection ); } return; default: Debug.Assert( false ); break; } Debug.Assert( scanningFunction == ScanningFunction.SubsetContent ); if ( currentEntityId != startTagEntityId ) { #if SILVERLIGHT Throw(curPos, Res.Sch_ParEntityRefNesting); #else if ( validate ) { SendValidationEvent( curPos, XmlSeverityType.Error, Res.Sch_ParEntityRefNesting, string.Empty ); } else { if ( !v1Compat ) { Throw( curPos, Res.Sch_ParEntityRefNesting ); } } #endif } } } private void ParseAttlistDecl() { if (GetToken(true) != Token.QName) { goto UnexpectedError; } // element name XmlQualifiedName elementName = GetNameQualified(true); SchemaElementDecl elementDecl; if (!schemaInfo.ElementDecls.TryGetValue(elementName, out elementDecl)) { if (!schemaInfo.UndeclaredElementDecls.TryGetValue(elementName, out elementDecl)) { elementDecl = new SchemaElementDecl(elementName, elementName.Namespace); schemaInfo.UndeclaredElementDecls.Add(elementName, elementDecl); } } SchemaAttDef attrDef = null; for (; ; ) { switch (GetToken(false)) { case Token.QName: XmlQualifiedName attrName = GetNameQualified(true); attrDef = new SchemaAttDef(attrName, attrName.Namespace); attrDef.IsDeclaredInExternal = !ParsingInternalSubset; attrDef.LineNumber = (int)LineNo; attrDef.LinePosition = (int)LinePos - (curPos - tokenStartPos); break; case Token.GreaterThan: #if !SILVERLIGHT if ( v1Compat ) { // check xml:space and xml:lang // if ( attrDef != null && attrDef.Prefix.Length > 0 && attrDef.Prefix.Equals( "xml" ) && attrDef.Name.Name == "space" ) { attrDef.Reserved = SchemaAttDef.Reserve.XmlSpace; if ( attrDef.Datatype.TokenizedType != XmlTokenizedType.ENUMERATION ) { Throw( Res.Xml_EnumerationRequired, string.Empty, attrDef.LineNumber, attrDef.LinePosition ); } if ( validate ) { attrDef.CheckXmlSpace( readerAdapterWithValidation.ValidationEventHandling ); } } } #endif return; default: goto UnexpectedError; } bool attrDefAlreadyExists = (elementDecl.GetAttDef(attrDef.Name) != null); ParseAttlistType(attrDef, elementDecl, attrDefAlreadyExists); ParseAttlistDefault(attrDef, attrDefAlreadyExists); // check xml:space and xml:lang if (attrDef.Prefix.Length > 0 && attrDef.Prefix.Equals("xml")) { if ( attrDef.Name.Name == "space" ) { #if !SILVERLIGHT if ( v1Compat ) { // string val = attrDef.DefaultValueExpanded.Trim(); if ( val.Equals( "preserve" ) || val.Equals( "default" ) ) { attrDef.Reserved = SchemaAttDef.Reserve.XmlSpace; } } else { #endif attrDef.Reserved = SchemaAttDef.Reserve.XmlSpace; if ( attrDef.TokenizedType != XmlTokenizedType.ENUMERATION ) { Throw( Res.Xml_EnumerationRequired, string.Empty, attrDef.LineNumber, attrDef.LinePosition ); } #if !SILVERLIGHT if ( validate ) { attrDef.CheckXmlSpace( readerAdapterWithValidation.ValidationEventHandling ); } } #endif } else if ( attrDef.Name.Name == "lang" ) { attrDef.Reserved = SchemaAttDef.Reserve.XmlLang; } } // add attribute to element decl if (!attrDefAlreadyExists) { elementDecl.AddAttDef(attrDef); } } UnexpectedError: OnUnexpectedError(); } private void ParseAttlistType( SchemaAttDef attrDef, SchemaElementDecl elementDecl, bool ignoreErrors ) { Token token = GetToken( true ); if ( token != Token.CDATA ) { elementDecl.HasNonCDataAttribute = true; } if ( IsAttributeValueType( token ) ) { attrDef.TokenizedType = (XmlTokenizedType)(int)token; #if !SILVERLIGHT attrDef.SchemaType = XmlSchemaType.GetBuiltInSimpleType( attrDef.Datatype.TypeCode ); #endif switch ( token ) { case Token.NOTATION: break; case Token.ID: #if !SILVERLIGHT if ( validate && elementDecl.IsIdDeclared ) { SchemaAttDef idAttrDef = elementDecl.GetAttDef( attrDef.Name ); if ( ( idAttrDef == null || idAttrDef.Datatype.TokenizedType != XmlTokenizedType.ID ) && !ignoreErrors ) { SendValidationEvent( XmlSeverityType.Error, Res.Sch_IdAttrDeclared, elementDecl.Name.ToString() ); } } #endif elementDecl.IsIdDeclared = true; return; default: return; } #if !SILVERLIGHT // check notation constrains if ( validate ) { if (elementDecl.IsNotationDeclared && !ignoreErrors ) { SendValidationEvent( curPos - 8, XmlSeverityType.Error, Res.Sch_DupNotationAttribute, elementDecl.Name.ToString() ); // 8 == strlen("NOTATION") } else { if ( elementDecl.ContentValidator != null && elementDecl.ContentValidator.ContentType == XmlSchemaContentType.Empty && !ignoreErrors ) { SendValidationEvent( curPos - 8, XmlSeverityType.Error, Res.Sch_NotationAttributeOnEmptyElement, elementDecl.Name.ToString() );// 8 == strlen("NOTATION") } elementDecl.IsNotationDeclared = true; } } #endif if ( GetToken( true ) != Token.LeftParen ) { goto UnexpectedError; } // parse notation list if ( GetToken( false ) != Token.Name ) { goto UnexpectedError; } for (;;) { string notationName = GetNameString(); #if !SILVERLIGHT if ( !schemaInfo.Notations.ContainsKey(notationName) ) { AddUndeclaredNotation(notationName); } if ( validate && !v1Compat && attrDef.Values != null && attrDef.Values.Contains( notationName ) && !ignoreErrors ) { SendValidationEvent( XmlSeverityType.Error, new XmlSchemaException( Res.Xml_AttlistDuplNotationValue, notationName, BaseUriStr, (int)LineNo, (int)LinePos ) ); } attrDef.AddValue( notationName ); #endif switch ( GetToken( false ) ) { case Token.Or: if ( GetToken( false ) != Token.Name ) { goto UnexpectedError; } continue; case Token.RightParen: return; default: goto UnexpectedError; } } } else if ( token == Token.LeftParen ) { attrDef.TokenizedType = XmlTokenizedType.ENUMERATION; #if !SILVERLIGHT attrDef.SchemaType = XmlSchemaType.GetBuiltInSimpleType( attrDef.Datatype.TypeCode ); #endif // parse nmtoken list if ( GetToken( false ) != Token.Nmtoken ) goto UnexpectedError; #if !SILVERLIGHT attrDef.AddValue( GetNameString() ); #endif for (;;) { switch ( GetToken( false ) ) { case Token.Or: if ( GetToken( false ) != Token.Nmtoken ) goto UnexpectedError; string nmtoken = GetNmtokenString(); #if !SILVERLIGHT if ( validate && !v1Compat && attrDef.Values != null && attrDef.Values.Contains( nmtoken ) && !ignoreErrors ) { SendValidationEvent( XmlSeverityType.Error, new XmlSchemaException( Res.Xml_AttlistDuplEnumValue, nmtoken, BaseUriStr, (int)LineNo, (int)LinePos ) ); } attrDef.AddValue( nmtoken ); #endif break; case Token.RightParen: return; default: goto UnexpectedError; } } } else { goto UnexpectedError; } UnexpectedError: OnUnexpectedError(); } private void ParseAttlistDefault( SchemaAttDef attrDef, bool ignoreErrors ) { switch ( GetToken( true ) ) { case Token.REQUIRED: attrDef.Presence = SchemaDeclBase.Use.Required; return; case Token.IMPLIED: attrDef.Presence = SchemaDeclBase.Use.Implied; return; case Token.FIXED: attrDef.Presence = SchemaDeclBase.Use.Fixed; if ( GetToken( true ) != Token.Literal ) { goto UnexpectedError; } break; case Token.Literal: break; default: goto UnexpectedError; } #if !SILVERLIGHT if ( validate && attrDef.Datatype.TokenizedType == XmlTokenizedType.ID&& !ignoreErrors ) { SendValidationEvent( curPos, XmlSeverityType.Error, Res.Sch_AttListPresence, string.Empty ); } #endif if ( attrDef.TokenizedType != XmlTokenizedType.CDATA ) { // non-CDATA attribute type normalization - strip spaces attrDef.DefaultValueExpanded = GetValueWithStrippedSpaces(); } else { attrDef.DefaultValueExpanded = GetValue(); } attrDef.ValueLineNumber = (int)literalLineInfo.lineNo; attrDef.ValueLinePosition = (int)literalLineInfo.linePos + 1; #if !SILVERLIGHT DtdValidator.SetDefaultTypedValue( attrDef, readerAdapter ); #endif return; UnexpectedError: OnUnexpectedError(); } private void ParseElementDecl() { // element name if ( GetToken( true ) != Token.QName ) { goto UnexpectedError; } // get schema decl for element SchemaElementDecl elementDecl = null; XmlQualifiedName name = GetNameQualified( true ); if (schemaInfo.ElementDecls.TryGetValue(name, out elementDecl)) { #if !SILVERLIGHT if ( validate ) { SendValidationEvent( curPos - name.Name.Length, XmlSeverityType.Error, Res.Sch_DupElementDecl, GetNameString() ); } #endif } else { if ( schemaInfo.UndeclaredElementDecls.TryGetValue(name, out elementDecl ) ) { schemaInfo.UndeclaredElementDecls.Remove( name ); } else { elementDecl = new SchemaElementDecl( name, name.Namespace ); } schemaInfo.ElementDecls.Add( name, elementDecl ); } elementDecl.IsDeclaredInExternal = !ParsingInternalSubset; // content spec #if SILVERLIGHT switch ( GetToken( true ) ) { case Token.EMPTY: case Token.ANY: break; case Token.LeftParen: switch ( GetToken( false ) ) { case Token.PCDATA: ParseElementMixedContentNoValidation(); break; case Token.None: ParseElementOnlyContentNoValidation(); break; default: goto UnexpectedError; } break; default: goto UnexpectedError; } #else switch ( GetToken( true ) ) { case Token.EMPTY: elementDecl.ContentValidator = ContentValidator.Empty; break; case Token.ANY: elementDecl.ContentValidator = ContentValidator.Any; break; case Token.LeftParen: int startParenEntityId = currentEntityId; switch ( GetToken( false ) ) { case Token.PCDATA: { ParticleContentValidator pcv = new ParticleContentValidator( XmlSchemaContentType.Mixed ); pcv.Start(); pcv.OpenGroup(); ParseElementMixedContent( pcv, startParenEntityId ); elementDecl.ContentValidator = pcv.Finish( true ); break; } case Token.None: { ParticleContentValidator pcv = null; pcv = new ParticleContentValidator( XmlSchemaContentType.ElementOnly ); pcv.Start(); pcv.OpenGroup(); ParseElementOnlyContent( pcv, startParenEntityId ); elementDecl.ContentValidator = pcv.Finish( true ); break; } default: goto UnexpectedError; } break; default: goto UnexpectedError; } #endif if ( GetToken( false ) != Token.GreaterThan ) { ThrowUnexpectedToken( curPos, ">" ); } return; UnexpectedError: OnUnexpectedError(); } #if SILVERLIGHT // Element content model parsing methods without validation private class ParseElementOnlyContentNoValidation_LocalFrame { public ParseElementOnlyContentNoValidation_LocalFrame() { parsingSchema = Token.None; } public Token parsingSchema; } private void ParseElementOnlyContentNoValidation() { Stack localFrames = new Stack (); ParseElementOnlyContentNoValidation_LocalFrame currentFrame = new ParseElementOnlyContentNoValidation_LocalFrame(); localFrames.Push(currentFrame); RecursiveCall: Loop: switch ( GetToken( false ) ) { case Token.QName: GetNameQualified(true); ParseHowManyNoValidation(); break; case Token.LeftParen: // We could just do this: // ParseElementOnlyContentNoValidation(); // // But that would be a recursion - so we will simulate the call using our localFrames stack // instead. currentFrame = new ParseElementOnlyContentNoValidation_LocalFrame(); localFrames.Push(currentFrame); goto RecursiveCall; // And we should return here when we return from the recursion // but it's the samea s returning after the switch statement case Token.GreaterThan: Throw( curPos, Res.Xml_InvalidContentModel ); goto Return; default: goto UnexpectedError; } ReturnFromRecursiveCall: switch ( GetToken( false ) ) { case Token.Comma: if ( currentFrame.parsingSchema == Token.Or ) { Throw( curPos, Res.Xml_InvalidContentModel ); } currentFrame.parsingSchema = Token.Comma; break; case Token.Or: if ( currentFrame.parsingSchema == Token.Comma ) { Throw( curPos, Res.Xml_InvalidContentModel ); } currentFrame.parsingSchema = Token.Or; break; case Token.RightParen: ParseHowManyNoValidation(); goto Return; case Token.GreaterThan: Throw( curPos, Res.Xml_InvalidContentModel ); goto Return; default: goto UnexpectedError; } goto Loop; UnexpectedError: OnUnexpectedError(); Return: // This is equivalent to return; statement // we simulate it using our localFrames stack localFrames.Pop(); if (localFrames.Count > 0) { currentFrame = localFrames.Peek(); goto ReturnFromRecursiveCall; } else { return; } } private void ParseHowManyNoValidation() { GetToken( false ); } private void ParseElementMixedContentNoValidation() { bool hasNames = false; for (;;) { switch ( GetToken( false ) ) { case Token.RightParen: if ( GetToken( false ) != Token.Star && hasNames ) { ThrowUnexpectedToken( curPos, "*" ); } return; case Token.Or: if ( !hasNames ) { hasNames = true; } if ( GetToken( false ) != Token.QName ) { goto default; } GetNameQualified( true ); continue; default: OnUnexpectedError(); break; } } } #else // Element content model parsing methods with validation support private class ParseElementOnlyContent_LocalFrame { public ParseElementOnlyContent_LocalFrame(int startParentEntityIdParam) { startParenEntityId = startParentEntityIdParam; parsingSchema = Token.None; } // pcv doesn't need to be stored for each frame as it never changes public int startParenEntityId; public Token parsingSchema; } private void ParseElementOnlyContent( ParticleContentValidator pcv, int startParenEntityId ) { Stack localFrames = new Stack (); ParseElementOnlyContent_LocalFrame currentFrame = new ParseElementOnlyContent_LocalFrame(startParenEntityId); localFrames.Push(currentFrame); RecursiveCall: Loop: switch ( GetToken( false ) ) { case Token.QName: pcv.AddName( GetNameQualified(true), null ); ParseHowMany( pcv ); break; case Token.LeftParen: pcv.OpenGroup(); // We could just do this: // ParseElementOnlyContent( pcv, currentEntityId ); // // But that would be recursion - so we will simulate the call using our localFrames stack // instead. currentFrame = new ParseElementOnlyContent_LocalFrame(currentEntityId); localFrames.Push(currentFrame); goto RecursiveCall; // And we should return here when we return from recursion call // but it's the same as returning after the switch statement case Token.GreaterThan: Throw( curPos, Res.Xml_InvalidContentModel ); goto Return; default: goto UnexpectedError; } ReturnFromRecursiveCall: switch ( GetToken( false ) ) { case Token.Comma: if ( currentFrame.parsingSchema == Token.Or ) { Throw( curPos, Res.Xml_InvalidContentModel ); } pcv.AddSequence(); currentFrame.parsingSchema = Token.Comma; break; case Token.Or: if (currentFrame.parsingSchema == Token.Comma) { Throw( curPos, Res.Xml_InvalidContentModel ); } pcv.AddChoice(); currentFrame.parsingSchema = Token.Or; break; case Token.RightParen: pcv.CloseGroup(); if (validate && currentEntityId != currentFrame.startParenEntityId) { SendValidationEvent( curPos, XmlSeverityType.Error, Res.Sch_ParEntityRefNesting, string.Empty ); } ParseHowMany( pcv ); goto Return; case Token.GreaterThan: Throw( curPos, Res.Xml_InvalidContentModel ); goto Return; default: goto UnexpectedError; } goto Loop; UnexpectedError: OnUnexpectedError(); Return: // This is equivalent to return; statement // we simlate it using our localFrames stack localFrames.Pop(); if (localFrames.Count > 0) { currentFrame = (ParseElementOnlyContent_LocalFrame)localFrames.Peek(); goto ReturnFromRecursiveCall; } else { return; } } private void ParseHowMany( ParticleContentValidator pcv ) { switch ( GetToken( false ) ) { case Token.Star: pcv.AddStar(); return; case Token.QMark: pcv.AddQMark(); return; case Token.Plus: pcv.AddPlus(); return; default: return; } } private void ParseElementMixedContent( ParticleContentValidator pcv, int startParenEntityId ) { bool hasNames = false; int connectorEntityId = -1; int contentEntityId = currentEntityId; for (;;) { switch ( GetToken( false ) ) { case Token.RightParen: pcv.CloseGroup(); if ( validate && currentEntityId != startParenEntityId ) { SendValidationEvent( curPos, XmlSeverityType.Error, Res.Sch_ParEntityRefNesting, string.Empty ); } if ( GetToken( false ) == Token.Star && hasNames ) { pcv.AddStar(); } else if ( hasNames ) { ThrowUnexpectedToken( curPos, "*" ); } return; case Token.Or: if ( !hasNames ) { hasNames = true; } else { pcv.AddChoice(); } if ( validate ) { connectorEntityId = currentEntityId; if ( contentEntityId < connectorEntityId ) { // entity repl.text starting with connector SendValidationEvent( curPos, XmlSeverityType.Error, Res.Sch_ParEntityRefNesting, string.Empty ); } } if ( GetToken( false ) != Token.QName ) { goto default; } XmlQualifiedName name = GetNameQualified( true ); if ( pcv.Exists( name ) && validate ) { SendValidationEvent( XmlSeverityType.Error, Res.Sch_DupElement, name.ToString() ); } pcv.AddName( name, null ); if ( validate ) { contentEntityId = currentEntityId; if ( contentEntityId < connectorEntityId ) { // entity repl.text ending with connector SendValidationEvent( curPos, XmlSeverityType.Error, Res.Sch_ParEntityRefNesting, string.Empty ); } } continue; default: OnUnexpectedError(); break; } } } #endif // Element content model parsing methods with validation support private void ParseEntityDecl() { bool isParamEntity = false; SchemaEntity entity = null; // get entity name and type switch ( GetToken( true ) ) { case Token.Percent: isParamEntity = true; if ( GetToken( true ) != Token.Name ) { goto UnexpectedError; } goto case Token.Name; case Token.Name: // create entity object XmlQualifiedName entityName = GetNameQualified( false ); entity = new SchemaEntity( entityName, isParamEntity ); entity.BaseURI = BaseUriStr; entity.DeclaredURI = ( externalDtdBaseUri.Length == 0 ) ? documentBaseUri : externalDtdBaseUri; if ( isParamEntity ) { if ( !schemaInfo.ParameterEntities.ContainsKey( entityName ) ) { schemaInfo.ParameterEntities.Add( entityName, entity ); } } else { if ( !schemaInfo.GeneralEntities.ContainsKey( entityName ) ) { schemaInfo.GeneralEntities.Add( entityName, entity ); } } entity.DeclaredInExternal = !ParsingInternalSubset; entity.ParsingInProgress = true; break; default: goto UnexpectedError; } Token token = GetToken( true ); switch ( token ) { case Token.PUBLIC: case Token.SYSTEM: string systemId; string publicId; ParseExternalId( token, Token.EntityDecl, out publicId, out systemId ); entity.IsExternal = true; entity.Url = systemId; entity.Pubid = publicId; if ( GetToken( false ) == Token.NData ) { if ( isParamEntity ) { ThrowUnexpectedToken( curPos - 5, ">" ); // 5 == strlen("NDATA") } if ( !whitespaceSeen ) { Throw( curPos - 5, Res.Xml_ExpectingWhiteSpace, "NDATA" ); } if ( GetToken( true ) != Token.Name ) { goto UnexpectedError; } entity.NData = GetNameQualified( false ); #if !SILVERLIGHT string notationName = entity.NData.Name; if ( !schemaInfo.Notations.ContainsKey(notationName) ) { AddUndeclaredNotation(notationName); } #endif } break; case Token.Literal: entity.Text = GetValue(); entity.Line = (int)literalLineInfo.lineNo; entity.Pos = (int)literalLineInfo.linePos; break; default: goto UnexpectedError; } if ( GetToken( false ) == Token.GreaterThan ) { entity.ParsingInProgress = false; return; } UnexpectedError: OnUnexpectedError(); } private void ParseNotationDecl() { // notation name if ( GetToken( true ) != Token.Name ) { OnUnexpectedError(); } XmlQualifiedName notationName = GetNameQualified( false ); #if !SILVERLIGHT SchemaNotation notation = null; if ( !schemaInfo.Notations.ContainsKey( notationName.Name ) ) { if ( undeclaredNotations != null ) { undeclaredNotations.Remove( notationName.Name ); } notation = new SchemaNotation( notationName ); schemaInfo.Notations.Add(notation.Name.Name, notation); } else { // duplicate notation if ( validate ) { SendValidationEvent( curPos - notationName.Name.Length, XmlSeverityType.Error, Res.Sch_DupNotation, notationName.Name ); } } #endif // public / system id Token token = GetToken( true ); if ( token == Token.SYSTEM || token == Token.PUBLIC ) { string notationPublicId, notationSystemId; ParseExternalId( token, Token.NOTATION, out notationPublicId, out notationSystemId ); #if !SILVERLIGHT if ( notation != null ) { notation.SystemLiteral = notationSystemId; notation.Pubid = notationPublicId; } #endif } else { OnUnexpectedError(); } if ( GetToken( false ) != Token.GreaterThan ) OnUnexpectedError(); } #if !SILVERLIGHT private void AddUndeclaredNotation(string notationName) { if (undeclaredNotations == null) { undeclaredNotations = new Dictionary (); } UndeclaredNotation un = new UndeclaredNotation(notationName, LineNo, LinePos - notationName.Length); UndeclaredNotation loggedUn; if (undeclaredNotations.TryGetValue(notationName, out loggedUn)) { un.next = loggedUn.next; loggedUn.next = un; } else { undeclaredNotations.Add(notationName, un); } } #endif private void ParseComment() { SaveParsingBuffer(); #if !SILVERLIGHT try { #endif if ( SaveInternalSubsetValue ) { readerAdapter.ParseComment( internalSubsetValueSb ); internalSubsetValueSb.Append( "-->" ); } else { readerAdapter.ParseComment( null ); } #if !SILVERLIGHT } catch (XmlException e) { if ( e.ResString == Res.Xml_UnexpectedEOF && currentEntityId != 0 ) { SendValidationEvent( XmlSeverityType.Error, Res.Sch_ParEntityRefNesting, null ); } else { throw; } } #endif LoadParsingBuffer(); } private void ParsePI() { SaveParsingBuffer(); if ( SaveInternalSubsetValue ) { readerAdapter.ParsePI( internalSubsetValueSb ); internalSubsetValueSb.Append( "?>" ); } else { readerAdapter.ParsePI( null ); } LoadParsingBuffer(); } private void ParseCondSection() { int csEntityId = currentEntityId; switch ( GetToken( false ) ) { case Token.INCLUDE: if ( GetToken( false ) != Token.LeftBracket ) { goto default; } #if !SILVERLIGHT if ( validate && csEntityId != currentEntityId ) { SendValidationEvent( curPos, XmlSeverityType.Error, Res.Sch_ParEntityRefNesting, string.Empty ); } if ( validate ) { if ( condSectionEntityIds == null ) { condSectionEntityIds = new int[CondSectionEntityIdsInitialSize]; } else if ( condSectionEntityIds.Length == condSectionDepth ) { int[] tmp = new int[condSectionEntityIds.Length*2]; Array.Copy( condSectionEntityIds, 0, tmp, 0, condSectionEntityIds.Length ); condSectionEntityIds = tmp; } condSectionEntityIds[condSectionDepth] = csEntityId; } #endif condSectionDepth++; break; case Token.IGNORE: if ( GetToken( false ) != Token.LeftBracket ) { goto default; } #if !SILVERLIGHT if ( validate && csEntityId != currentEntityId ) { SendValidationEvent( curPos, XmlSeverityType.Error, Res.Sch_ParEntityRefNesting, string.Empty ); } #endif // the content of the ignore section is parsed & skipped by scanning function if ( GetToken( false ) != Token.CondSectionEnd ) { goto default; } #if !SILVERLIGHT if ( validate && csEntityId != currentEntityId ) { SendValidationEvent( curPos, XmlSeverityType.Error, Res.Sch_ParEntityRefNesting, string.Empty ); } #endif break; default: OnUnexpectedError(); break; } } private void ParseExternalId( Token idTokenType, Token declType, out string publicId, out string systemId ) { LineInfo keywordLineInfo = new LineInfo( LineNo, LinePos - 6 ); publicId = null; systemId = null; if ( GetToken( true ) != Token.Literal ) { ThrowUnexpectedToken( curPos, "\"", "'" ); } if ( idTokenType == Token.SYSTEM ) { systemId = GetValue(); if ( systemId.IndexOf( '#' ) >= 0 ) { Throw( curPos - systemId.Length - 1, Res.Xml_FragmentId, new string[] { systemId.Substring( systemId.IndexOf( '#' ) ), systemId } ); } if ( declType == Token.DOCTYPE && !freeFloatingDtd ) { literalLineInfo.linePos++; readerAdapter.OnSystemId( systemId, keywordLineInfo, literalLineInfo ); } } else { Debug.Assert( idTokenType == Token.PUBLIC ); publicId = GetValue(); // verify if it contains chars valid for public ids int i; if ( ( i = xmlCharType.IsPublicId( publicId ) ) >= 0 ) { ThrowInvalidChar( curPos - 1 - publicId.Length + i, publicId, i ); } if ( declType == Token.DOCTYPE && !freeFloatingDtd ) { literalLineInfo.linePos++; readerAdapter.OnPublicId( publicId, keywordLineInfo, literalLineInfo ); if ( GetToken( false ) == Token.Literal ) { if ( !whitespaceSeen ) { Throw( Res.Xml_ExpectingWhiteSpace, new string( literalQuoteChar, 1 ), (int)literalLineInfo.lineNo, (int)literalLineInfo.linePos ); } systemId = GetValue(); literalLineInfo.linePos++; readerAdapter.OnSystemId( systemId, keywordLineInfo, literalLineInfo ); } else { ThrowUnexpectedToken( curPos, "\"", "'" ); } } else { if ( GetToken( false ) == Token.Literal ) { if ( !whitespaceSeen ) { Throw( Res.Xml_ExpectingWhiteSpace, new string( literalQuoteChar, 1 ), (int)literalLineInfo.lineNo, (int)literalLineInfo.linePos ); } systemId = GetValue(); } else if ( declType != Token.NOTATION ) { ThrowUnexpectedToken( curPos, "\"", "'" ); } } } } // // Scanning methods - works directly with parsing buffer // private Token GetToken( bool needWhiteSpace ) { whitespaceSeen = false; for (;;) { switch ( chars[curPos] ) { case (char)0: if ( curPos == charsUsed ) { goto ReadData; } else { ThrowInvalidChar( chars, charsUsed, curPos ); } break; case (char)0xA: whitespaceSeen = true; curPos++; readerAdapter.OnNewLine( curPos ); continue; case (char)0xD: whitespaceSeen = true; if ( chars[curPos+1] == (char)0xA ) { if ( Normalize ) { SaveParsingBuffer(); // EOL normalization of 0xD 0xA readerAdapter.CurrentPosition++; } curPos += 2; } else if ( curPos+1 < charsUsed || readerAdapter.IsEof ) { chars[curPos] = (char)0xA; // EOL normalization of 0xD curPos++; } else { goto ReadData; } readerAdapter.OnNewLine( curPos ); continue; case (char)0x9: case (char)0x20: whitespaceSeen = true; curPos++; continue; case '%': if ( charsUsed - curPos < 2 ) { goto ReadData; } if ( !xmlCharType.IsWhiteSpace( chars[curPos+1] ) ) { if ( IgnoreEntityReferences ) { curPos++; } else { HandleEntityReference( true, false, false ); } continue; } goto default; default: if ( needWhiteSpace && !whitespaceSeen && scanningFunction != ScanningFunction.ParamEntitySpace ) { Throw( curPos, Res.Xml_ExpectingWhiteSpace, ParseUnexpectedToken( curPos ) ); } tokenStartPos = curPos; SwitchAgain: switch ( scanningFunction ) { case ScanningFunction.Name: return ScanNameExpected(); case ScanningFunction.QName: return ScanQNameExpected(); case ScanningFunction.Nmtoken: return ScanNmtokenExpected(); case ScanningFunction.SubsetContent: return ScanSubsetContent(); case ScanningFunction.Doctype1: return ScanDoctype1(); case ScanningFunction.Doctype2: return ScanDoctype2(); case ScanningFunction.Element1: return ScanElement1(); case ScanningFunction.Element2: return ScanElement2(); case ScanningFunction.Element3: return ScanElement3(); case ScanningFunction.Element4: return ScanElement4(); case ScanningFunction.Element5: return ScanElement5(); case ScanningFunction.Element6: return ScanElement6(); case ScanningFunction.Element7: return ScanElement7(); case ScanningFunction.Attlist1: return ScanAttlist1(); case ScanningFunction.Attlist2: return ScanAttlist2(); case ScanningFunction.Attlist3: return ScanAttlist3(); case ScanningFunction.Attlist4: return ScanAttlist4(); case ScanningFunction.Attlist5: return ScanAttlist5(); case ScanningFunction.Attlist6: return ScanAttlist6(); case ScanningFunction.Attlist7: return ScanAttlist7(); case ScanningFunction.Notation1: return ScanNotation1(); case ScanningFunction.SystemId: return ScanSystemId(); case ScanningFunction.PublicId1: return ScanPublicId1(); case ScanningFunction.PublicId2: return ScanPublicId2(); case ScanningFunction.Entity1: return ScanEntity1(); case ScanningFunction.Entity2: return ScanEntity2(); case ScanningFunction.Entity3: return ScanEntity3(); case ScanningFunction.CondSection1: return ScanCondSection1(); case ScanningFunction.CondSection2: return ScanCondSection2(); case ScanningFunction.CondSection3: return ScanCondSection3(); case ScanningFunction.ClosingTag: return ScanClosingTag(); case ScanningFunction.ParamEntitySpace: whitespaceSeen = true; scanningFunction = savedScanningFunction; goto SwitchAgain; default: Debug.Assert( false ); return Token.None; } } ReadData: if ( readerAdapter.IsEof || ReadData() == 0 ) { if ( HandleEntityEnd( false ) ) { continue; } if ( scanningFunction == ScanningFunction.SubsetContent ) { return Token.Eof; } else { Throw( curPos, Res.Xml_IncompleteDtdContent ); } } } } private Token ScanSubsetContent() { for (;;) { switch ( chars[curPos] ) { case '<': switch ( chars[curPos+1] ) { case '!': switch ( chars[curPos+2] ) { case 'E': if ( chars[curPos+3] == 'L' ) { if ( charsUsed - curPos < 9 ) { goto ReadData; } if ( chars[curPos+4] != 'E' || chars[curPos+5] != 'M' || chars[curPos+6] != 'E' || chars[curPos+7] != 'N' || chars[curPos+8] != 'T' ) { Throw( curPos, Res.Xml_ExpectDtdMarkup ); } curPos += 9; scanningFunction = ScanningFunction.QName; nextScaningFunction = ScanningFunction.Element1; return Token.ElementDecl; } else if ( chars[curPos+3] == 'N' ) { if ( charsUsed - curPos < 8 ) { goto ReadData; } if ( chars[curPos+4] != 'T' || chars[curPos+5] != 'I' || chars[curPos+6] != 'T' || chars[curPos+7] != 'Y' ) { Throw( curPos, Res.Xml_ExpectDtdMarkup ); } curPos += 8; scanningFunction = ScanningFunction.Entity1; return Token.EntityDecl; } else { if ( charsUsed - curPos < 4 ) { goto ReadData; } Throw( curPos, Res.Xml_ExpectDtdMarkup ); return Token.None; } case 'A': if ( charsUsed - curPos < 9 ) { goto ReadData; } 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' ) { Throw( curPos, Res.Xml_ExpectDtdMarkup ); } curPos += 9; scanningFunction = ScanningFunction.QName; nextScaningFunction = ScanningFunction.Attlist1; return Token.AttlistDecl; case 'N': if ( charsUsed - curPos < 10 ) { goto ReadData; } 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' ) { Throw( curPos, Res.Xml_ExpectDtdMarkup ); } curPos += 10; scanningFunction = ScanningFunction.Name; nextScaningFunction = ScanningFunction.Notation1; return Token.NotationDecl; case '[': curPos += 3; scanningFunction = ScanningFunction.CondSection1; return Token.CondSectionStart; case '-': if ( chars[curPos+3] == '-' ) { curPos += 4; return Token.Comment; } else { if ( charsUsed - curPos < 4 ) { goto ReadData; } Throw( curPos, Res.Xml_ExpectDtdMarkup ); break; } default: if ( charsUsed - curPos < 3 ) { goto ReadData; } Throw( curPos + 2, Res.Xml_ExpectDtdMarkup ); break; } break; case '?': curPos += 2; return Token.PI; default: if ( charsUsed - curPos < 2 ) { goto ReadData; } Throw( curPos, Res.Xml_ExpectDtdMarkup ); return Token.None; } break; case ']': if ( charsUsed - curPos < 2 && !readerAdapter.IsEof ) { goto ReadData; } if ( chars[curPos+1] != ']' ) { curPos++; scanningFunction = ScanningFunction.ClosingTag; return Token.RightBracket; } if ( charsUsed - curPos < 3 && !readerAdapter.IsEof ) { goto ReadData; } if ( chars[curPos+1] == ']' && chars[curPos+2] == '>' ) { curPos += 3; return Token.CondSectionEnd; } goto default; default: if ( charsUsed - curPos == 0 ) { goto ReadData; } Throw( curPos, Res.Xml_ExpectDtdMarkup ); break; } ReadData: if ( ReadData() == 0 ) { Throw( charsUsed, Res.Xml_IncompleteDtdContent ); } } } private Token ScanNameExpected() { ScanName(); scanningFunction = nextScaningFunction; return Token.Name; } private Token ScanQNameExpected() { ScanQName(); scanningFunction = nextScaningFunction; return Token.QName; } private Token ScanNmtokenExpected() { ScanNmtoken(); scanningFunction = nextScaningFunction; return Token.Nmtoken; } private Token ScanDoctype1() { switch ( chars[curPos] ) { case 'P': if ( !EatPublicKeyword() ) { Throw( curPos, Res.Xml_ExpectExternalOrClose ); } nextScaningFunction = ScanningFunction.Doctype2; scanningFunction = ScanningFunction.PublicId1; return Token.PUBLIC; case 'S': if ( !EatSystemKeyword() ) { Throw( curPos, Res.Xml_ExpectExternalOrClose ); } nextScaningFunction = ScanningFunction.Doctype2; scanningFunction = ScanningFunction.SystemId; return Token.SYSTEM; case '[': curPos++; scanningFunction = ScanningFunction.SubsetContent; return Token.LeftBracket; case '>': curPos++; scanningFunction = ScanningFunction.SubsetContent; return Token.GreaterThan; default: Throw( curPos, Res.Xml_ExpectExternalOrClose ); return Token.None; } } private Token ScanDoctype2() { switch ( chars[curPos] ) { case '[': curPos++; scanningFunction = ScanningFunction.SubsetContent; return Token.LeftBracket; case '>': curPos++; scanningFunction = ScanningFunction.SubsetContent; return Token.GreaterThan; default: Throw( curPos, Res.Xml_ExpectSubOrClose ); return Token.None; } } private Token ScanClosingTag() { if ( chars[curPos] != '>' ) { ThrowUnexpectedToken( curPos, ">" ); } curPos++; scanningFunction = ScanningFunction.SubsetContent; return Token.GreaterThan; } private Token ScanElement1() { for (;;) { switch ( chars[curPos] ) { case '(': scanningFunction = ScanningFunction.Element2; curPos++; return Token.LeftParen; case 'E': if ( charsUsed - curPos < 5 ) { goto ReadData; } if ( chars[curPos+1] == 'M' && chars[curPos+2] == 'P' && chars[curPos+3] == 'T' && chars[curPos+4] == 'Y' ) { curPos += 5; scanningFunction = ScanningFunction.ClosingTag; return Token.EMPTY; } goto default; case 'A': if ( charsUsed - curPos < 3 ) { goto ReadData; } if ( chars[curPos+1] == 'N' && chars[curPos+2] == 'Y' ) { curPos += 3; scanningFunction = ScanningFunction.ClosingTag; return Token.ANY; } goto default; default: Throw( curPos, Res.Xml_InvalidContentModel ); break; } ReadData: if ( ReadData() == 0 ) { Throw( curPos, Res.Xml_IncompleteDtdContent ); } } } private Token ScanElement2() { if ( chars[curPos] == '#' ) { while ( charsUsed - curPos < 7 ) { if ( ReadData() == 0 ) { Throw( curPos, Res.Xml_IncompleteDtdContent ); } } 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' ) { curPos += 7; scanningFunction = ScanningFunction.Element6; return Token.PCDATA; } else { Throw( curPos + 1, Res.Xml_ExpectPcData ); } } scanningFunction = ScanningFunction.Element3; return Token.None; } private Token ScanElement3() { switch ( chars[curPos] ) { case '(': curPos++; return Token.LeftParen; case '>': curPos++; scanningFunction = ScanningFunction.SubsetContent; return Token.GreaterThan; default: ScanQName(); scanningFunction = ScanningFunction.Element4; return Token.QName; } } private Token ScanElement4() { scanningFunction = ScanningFunction.Element5; Token t; switch ( chars[curPos] ) { case '*': t = Token.Star; break; case '?': t = Token.QMark; break; case '+': t = Token.Plus; break; default: return Token.None; } if ( whitespaceSeen ) { Throw( curPos, Res.Xml_ExpectNoWhitespace ); } curPos++; return t; } private Token ScanElement5() { switch ( chars[curPos] ) { case ',': curPos++; scanningFunction = ScanningFunction.Element3; return Token.Comma; case '|': curPos++; scanningFunction = ScanningFunction.Element3; return Token.Or; case ')': curPos++; scanningFunction = ScanningFunction.Element4; return Token.RightParen; case '>': curPos++; scanningFunction = ScanningFunction.SubsetContent; return Token.GreaterThan; default: Throw( curPos, Res.Xml_ExpectOp ); return Token.None; } } private Token ScanElement6() { switch ( chars[curPos] ) { case ')': curPos++; scanningFunction = ScanningFunction.Element7; return Token.RightParen; case '|': curPos++; nextScaningFunction = ScanningFunction.Element6; scanningFunction = ScanningFunction.QName; return Token.Or; default: ThrowUnexpectedToken( curPos, ")", "|" ); return Token.None; } } private Token ScanElement7() { scanningFunction = ScanningFunction.ClosingTag; if ( chars[curPos] == '*' && !whitespaceSeen ) { curPos++; return Token.Star; } return Token.None; } private Token ScanAttlist1() { switch ( chars[curPos] ) { case '>': curPos++; scanningFunction = ScanningFunction.SubsetContent; return Token.GreaterThan; default: if ( !whitespaceSeen ) { Throw( curPos, Res.Xml_ExpectingWhiteSpace, ParseUnexpectedToken( curPos ) ); } ScanQName(); scanningFunction = ScanningFunction.Attlist2; return Token.QName; } } private Token ScanAttlist2() { for (;;) { switch ( chars[curPos] ) { case '(': curPos++; scanningFunction = ScanningFunction.Nmtoken; nextScaningFunction = ScanningFunction.Attlist5; return Token.LeftParen; case 'C': if ( charsUsed - curPos < 5 ) goto ReadData; if ( chars[curPos+1] != 'D' || chars[curPos+2] != 'A' || chars[curPos+3] != 'T' || chars[curPos+4] != 'A' ) { Throw( curPos, Res.Xml_InvalidAttributeType1 ); } curPos += 5; scanningFunction = ScanningFunction.Attlist6; return Token.CDATA; case 'E': if ( charsUsed - curPos < 9 ) goto ReadData; scanningFunction = ScanningFunction.Attlist6; if ( chars[curPos+1] != 'N' || chars[curPos+2] != 'T' || chars[curPos+3] != 'I' || chars[curPos+4] != 'T' ) { Throw( curPos, Res.Xml_InvalidAttributeType ); } switch ( chars[curPos+5] ) { case 'I': if ( chars[curPos+6] != 'E' || chars[curPos+7] != 'S' ) { Throw( curPos, Res.Xml_InvalidAttributeType ); } curPos += 8; return Token.ENTITIES; case 'Y': curPos += 6; return Token.ENTITY; default: Throw( curPos, Res.Xml_InvalidAttributeType ); break; } break; case 'I': if ( charsUsed - curPos < 6 ) goto ReadData; scanningFunction = ScanningFunction.Attlist6; if ( chars[curPos+1] != 'D' ) { Throw( curPos, Res.Xml_InvalidAttributeType ); } if ( chars[curPos+2] != 'R' ) { curPos += 2; return Token.ID; } if ( chars[curPos+3] != 'E' || chars[curPos+4] != 'F' ) { Throw( curPos, Res.Xml_InvalidAttributeType ); } if ( chars[curPos+5] != 'S' ) { curPos += 5; return Token.IDREF; } else { curPos += 6; return Token.IDREFS; } case 'N': if ( charsUsed - curPos < 8 && !readerAdapter.IsEof ) { goto ReadData; } switch ( chars[curPos+1] ) { case 'O': 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' ) { Throw( curPos, Res.Xml_InvalidAttributeType ); } curPos += 8; scanningFunction = ScanningFunction.Attlist3; return Token.NOTATION; case 'M': if ( chars[curPos+2] != 'T' || chars[curPos+3] != 'O' || chars[curPos+4] != 'K' || chars[curPos+5] != 'E' || chars[curPos+6] != 'N' ) { Throw( curPos, Res.Xml_InvalidAttributeType ); } scanningFunction = ScanningFunction.Attlist6; if ( chars[curPos+7] == 'S' ) { curPos += 8; return Token.NMTOKENS; } else { curPos += 7; return Token.NMTOKEN; } default: Throw( curPos, Res.Xml_InvalidAttributeType ); break; } break; default: Throw( curPos, Res.Xml_InvalidAttributeType ); break; } ReadData: if ( ReadData() == 0 ) { Throw( curPos, Res.Xml_IncompleteDtdContent ); } } } private Token ScanAttlist3() { if ( chars[curPos] == '(' ) { curPos++; scanningFunction = ScanningFunction.Name; nextScaningFunction = ScanningFunction.Attlist4; return Token.LeftParen; } else { ThrowUnexpectedToken( curPos, "(" ); return Token.None; } } private Token ScanAttlist4() { switch ( chars[curPos] ) { case ')': curPos++; scanningFunction = ScanningFunction.Attlist6; return Token.RightParen; case '|': curPos++; scanningFunction = ScanningFunction.Name; nextScaningFunction = ScanningFunction.Attlist4; return Token.Or; default: ThrowUnexpectedToken( curPos, ")", "|" ); return Token.None; } } private Token ScanAttlist5() { switch ( chars[curPos] ) { case ')': curPos++; scanningFunction = ScanningFunction.Attlist6; return Token.RightParen; case '|': curPos++; scanningFunction = ScanningFunction.Nmtoken; nextScaningFunction = ScanningFunction.Attlist5; return Token.Or; default: ThrowUnexpectedToken( curPos, ")", "|" ); return Token.None; } } private Token ScanAttlist6() { for (;;) { switch ( chars[curPos] ) { case '"': case '\'': ScanLiteral( LiteralType.AttributeValue ); scanningFunction = ScanningFunction.Attlist1; return Token.Literal; case '#': if ( charsUsed - curPos < 6 ) goto ReadData; switch ( chars[curPos+1] ) { case 'R': if ( charsUsed - curPos < 9 ) goto ReadData; 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' ) { Throw( curPos, Res.Xml_ExpectAttType ); } curPos += 9; scanningFunction = ScanningFunction.Attlist1; return Token.REQUIRED; case 'I': if ( charsUsed - curPos < 8 ) goto ReadData; 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' ) { Throw( curPos, Res.Xml_ExpectAttType ); } curPos += 8; scanningFunction = ScanningFunction.Attlist1; return Token.IMPLIED; case 'F': if ( chars[curPos+2] != 'I' || chars[curPos+3] != 'X' || chars[curPos+4] != 'E' || chars[curPos+5] != 'D' ) { Throw( curPos, Res.Xml_ExpectAttType ); } curPos += 6; scanningFunction = ScanningFunction.Attlist7; return Token.FIXED; default: Throw( curPos, Res.Xml_ExpectAttType ); break; } break; default: Throw( curPos, Res.Xml_ExpectAttType ); break; } ReadData: if ( ReadData() == 0 ) { Throw( curPos, Res.Xml_IncompleteDtdContent ); } } } private Token ScanAttlist7() { switch ( chars[curPos] ) { case '"': case '\'': ScanLiteral( LiteralType.AttributeValue ); scanningFunction = ScanningFunction.Attlist1; return Token.Literal; default: ThrowUnexpectedToken( curPos, "\"", "'" ); return Token.None; } } private Token ScanLiteral( LiteralType literalType ) { Debug.Assert( chars[curPos] == '"' || chars[curPos] == '\'' ); char quoteChar = chars[curPos]; char replaceChar = ( literalType == LiteralType.AttributeValue ) ? (char)0x20 : (char)0xA; int startQuoteEntityId = currentEntityId; literalLineInfo.Set( LineNo, LinePos ); curPos++; tokenStartPos = curPos; #if SILVERLIGHT stringBuilder.Clear(); #else stringBuilder.Length = 0; #endif for (;;) { #if SILVERLIGHT while ( xmlCharType.IsAttributeValueChar( chars[curPos] ) && chars[curPos] != '%' ) { curPos++; } #else unsafe { while ( ( xmlCharType.charProperties[chars[curPos]] & XmlCharType.fAttrValue ) != 0 && chars[curPos] != '%' ) { curPos++; } } #endif if ( chars[curPos] == quoteChar && currentEntityId == startQuoteEntityId ) { if ( stringBuilder.Length > 0 ) { stringBuilder.Append( chars, tokenStartPos, curPos - tokenStartPos ); } curPos++; literalQuoteChar = quoteChar; return Token.Literal; } int tmp1 = curPos - tokenStartPos; if ( tmp1 > 0 ) { stringBuilder.Append( chars, tokenStartPos, tmp1 ); tokenStartPos = curPos; } switch ( chars[curPos] ) { case '"': case '\'': case '>': curPos++; continue; // eol case (char)0xA: curPos++; if ( Normalize ) { stringBuilder.Append( replaceChar ); // For attributes: CDATA normalization of 0xA tokenStartPos = curPos; } readerAdapter.OnNewLine( curPos ); continue; case (char)0xD: if ( chars[curPos+1] == (char)0xA ) { if ( Normalize ) { if ( literalType == LiteralType.AttributeValue ) { stringBuilder.Append( readerAdapter.IsEntityEolNormalized ? "\u0020\u0020" : "\u0020" ); // CDATA normalization of 0xD 0xA } else { stringBuilder.Append( readerAdapter.IsEntityEolNormalized ? "\u000D\u000A" : "\u000A" ); // EOL normalization of 0xD 0xA } tokenStartPos = curPos + 2; SaveParsingBuffer(); // EOL normalization of 0xD 0xA in internal subset value readerAdapter.CurrentPosition++; } curPos += 2; } else if ( curPos+1 == charsUsed ) { goto ReadData; } else { curPos++; if ( Normalize ) { stringBuilder.Append( replaceChar ); // For attributes: CDATA normalization of 0xD and 0xD 0xA tokenStartPos = curPos; // For entities: EOL normalization of 0xD and 0xD 0xA } } readerAdapter.OnNewLine( curPos ); continue; // tab case (char)0x9: if ( literalType == LiteralType.AttributeValue && Normalize ) { stringBuilder.Append( (char)0x20 ); // For attributes: CDATA normalization of 0x9 tokenStartPos++; } curPos++; continue; // attribute values cannot contain '<' case '<': if ( literalType == LiteralType.AttributeValue ) { Throw( curPos, Res.Xml_BadAttributeChar, XmlException.BuildCharExceptionArgs( '<', '\0' ) ); } curPos++; continue; // parameter entity reference case '%': if ( literalType != LiteralType.EntityReplText ) { curPos++; continue; } HandleEntityReference( true, true, literalType == LiteralType.AttributeValue ); tokenStartPos = curPos; continue; // general entity reference case '&': if ( literalType == LiteralType.SystemOrPublicID ) { curPos++; continue; } if ( curPos + 1 == charsUsed ) { goto ReadData; } // numeric characters reference if ( chars[curPos + 1] == '#' ) { SaveParsingBuffer(); int endPos = readerAdapter.ParseNumericCharRef( SaveInternalSubsetValue ? internalSubsetValueSb : null ); LoadParsingBuffer(); stringBuilder.Append( chars, curPos, endPos - curPos ); readerAdapter.CurrentPosition = endPos; tokenStartPos = endPos; curPos = endPos; continue; } else { // general entity reference SaveParsingBuffer(); if ( literalType == LiteralType.AttributeValue ) { int endPos = readerAdapter.ParseNamedCharRef( true, SaveInternalSubsetValue ? internalSubsetValueSb : null ); LoadParsingBuffer(); if ( endPos >= 0 ) { stringBuilder.Append( chars, curPos, endPos - curPos ); readerAdapter.CurrentPosition = endPos; tokenStartPos = endPos; curPos = endPos; continue; } else { HandleEntityReference( false, true, true ); tokenStartPos = curPos; } continue; } else { int endPos = readerAdapter.ParseNamedCharRef( false, null ); LoadParsingBuffer(); if ( endPos >= 0 ) { tokenStartPos = curPos; curPos = endPos; continue; } else { stringBuilder.Append( '&' ); curPos++; tokenStartPos = curPos; // Bypass general entities in entity values XmlQualifiedName entityName = ScanEntityName(); VerifyEntityReference( entityName, false, false, false ); } continue; } } default: // end of buffer if ( curPos == charsUsed ) { goto ReadData; } // surrogate chars else { char ch = chars[curPos]; if ( XmlCharType.IsHighSurrogate(ch) ) { if ( curPos + 1 == charsUsed ) { goto ReadData; } curPos++; if ( XmlCharType.IsLowSurrogate(chars[curPos]) ) { curPos++; continue; } } ThrowInvalidChar( chars, charsUsed, curPos ); return Token.None; } } ReadData: Debug.Assert( curPos - tokenStartPos == 0 ); // read new characters into the buffer if ( readerAdapter.IsEof || ReadData() == 0 ) { if ( literalType == LiteralType.SystemOrPublicID || !HandleEntityEnd( true ) ) { Throw( curPos, Res.Xml_UnclosedQuote ); } } tokenStartPos = curPos; } } private XmlQualifiedName ScanEntityName() { try { ScanName(); } catch ( XmlException e ) { Throw( Res.Xml_ErrorParsingEntityName, string.Empty, e.LineNumber, e.LinePosition ); } if ( chars[curPos] != ';' ) { ThrowUnexpectedToken( curPos, ";" ); } XmlQualifiedName entityName = GetNameQualified( false ); curPos++; return entityName; } private Token ScanNotation1() { switch ( chars[curPos] ) { case 'P': if ( !EatPublicKeyword() ) { Throw( curPos, Res.Xml_ExpectExternalOrClose ); } nextScaningFunction = ScanningFunction.ClosingTag; scanningFunction = ScanningFunction.PublicId1; return Token.PUBLIC; case 'S': if ( !EatSystemKeyword() ) { Throw( curPos, Res.Xml_ExpectExternalOrClose ); } nextScaningFunction = ScanningFunction.ClosingTag; scanningFunction = ScanningFunction.SystemId; return Token.SYSTEM; default: Throw( curPos, Res.Xml_ExpectExternalOrPublicId ); return Token.None; } } private Token ScanSystemId() { if ( chars[curPos] != '"' && chars[curPos] != '\'' ) { ThrowUnexpectedToken( curPos, "\"", "'" ); } ScanLiteral( LiteralType.SystemOrPublicID ); scanningFunction = nextScaningFunction; return Token.Literal; } private Token ScanEntity1() { if ( chars[curPos] == '%' ) { curPos++; nextScaningFunction = ScanningFunction.Entity2; scanningFunction = ScanningFunction.Name; return Token.Percent; } else { ScanName(); scanningFunction = ScanningFunction.Entity2; return Token.Name; } } private Token ScanEntity2() { switch ( chars[curPos] ) { case 'P': if ( !EatPublicKeyword() ) { Throw( curPos, Res.Xml_ExpectExternalOrClose ); } nextScaningFunction = ScanningFunction.Entity3; scanningFunction = ScanningFunction.PublicId1; return Token.PUBLIC; case 'S': if ( !EatSystemKeyword() ) { Throw( curPos, Res.Xml_ExpectExternalOrClose ); } nextScaningFunction = ScanningFunction.Entity3; scanningFunction = ScanningFunction.SystemId; return Token.SYSTEM; case '"': case '\'': ScanLiteral( LiteralType.EntityReplText ); scanningFunction = ScanningFunction.ClosingTag; return Token.Literal; default: Throw( curPos, Res.Xml_ExpectExternalIdOrEntityValue ); return Token.None; } } private Token ScanEntity3() { if ( chars[curPos] == 'N' ) { while ( charsUsed - curPos < 5 ) { if ( ReadData() == 0 ) { goto End; } } if ( chars[curPos+1] == 'D' && chars[curPos+2] == 'A' && chars[curPos+3] == 'T' && chars[curPos+4] == 'A' ) { curPos += 5; scanningFunction = ScanningFunction.Name; nextScaningFunction = ScanningFunction.ClosingTag; return Token.NData; } } End: scanningFunction = ScanningFunction.ClosingTag; return Token.None; } private Token ScanPublicId1() { if ( chars[curPos] != '"' && chars[curPos] != '\'' ) { ThrowUnexpectedToken( curPos, "\"", "'" ); } ScanLiteral( LiteralType.SystemOrPublicID ); scanningFunction = ScanningFunction.PublicId2; return Token.Literal; } private Token ScanPublicId2() { if ( chars[curPos] != '"' && chars[curPos] != '\'' ) { scanningFunction = nextScaningFunction; return Token.None; } ScanLiteral( LiteralType.SystemOrPublicID ); scanningFunction = nextScaningFunction; return Token.Literal; } private Token ScanCondSection1() { if ( chars[curPos] != 'I' ) { Throw( curPos, Res.Xml_ExpectIgnoreOrInclude ); } curPos++; for (;;) { if ( charsUsed - curPos < 5 ) { goto ReadData; } switch ( chars[curPos] ) { case 'N': if ( charsUsed - curPos < 6 ) { goto ReadData; } if ( chars[curPos+1] != 'C' || chars[curPos+2] != 'L' || chars[curPos+3] != 'U' || chars[curPos+4] != 'D' || chars[curPos+5] != 'E' || xmlCharType.IsNameSingleChar( chars[curPos+6] ) #if XML10_FIFTH_EDITION || xmlCharType.IsNCNameHighSurrogateChar( chars[curPos+6] ) #endif ) { goto default; } nextScaningFunction = ScanningFunction.SubsetContent; scanningFunction = ScanningFunction.CondSection2; curPos += 6; return Token.INCLUDE; case 'G': if ( chars[curPos+1] != 'N' || chars[curPos+2] != 'O' || chars[curPos+3] != 'R' || chars[curPos+4] != 'E' || xmlCharType.IsNameSingleChar( chars[curPos + 5] ) #if XML10_FIFTH_EDITION ||xmlCharType.IsNCNameHighSurrogateChar( chars[curPos+5] ) #endif ) { goto default; } nextScaningFunction = ScanningFunction.CondSection3; scanningFunction = ScanningFunction.CondSection2; curPos += 5; return Token.IGNORE; default: Throw( curPos - 1, Res.Xml_ExpectIgnoreOrInclude ); return Token.None; } ReadData: if ( ReadData() == 0 ) { Throw( curPos, Res.Xml_IncompleteDtdContent ); } } } private Token ScanCondSection2() { if ( chars[curPos] != '[' ) { ThrowUnexpectedToken( curPos, "[" ); } curPos++; scanningFunction = nextScaningFunction; return Token.LeftBracket; } private Token ScanCondSection3() { int ignoreSectionDepth = 0; // skip ignored part for (;;) { #if SILVERLIGHT while ( xmlCharType.IsTextChar(chars[curPos]) && chars[curPos] != ']' ) { curPos++; } #else unsafe { while ( ( xmlCharType.charProperties[chars[curPos]] & XmlCharType.fText ) != 0 && chars[curPos] != ']' ) { curPos++; } } #endif switch ( chars[curPos] ) { case '"': case '\'': case (char)0x9: case '&': curPos++; continue; // eol case (char)0xA: curPos++; readerAdapter.OnNewLine( curPos ); continue; case (char)0xD: if ( chars[curPos+1] == (char)0xA ) { curPos += 2; } else if ( curPos+1 < charsUsed || readerAdapter.IsEof ) { curPos++; } else { goto ReadData; } readerAdapter.OnNewLine( curPos ); continue; case '<': if ( charsUsed - curPos < 3 ) { goto ReadData; } if ( chars[curPos+1] != '!' || chars[curPos+2] != '[' ) { curPos++; continue; } ignoreSectionDepth++; curPos += 3; continue; case ']': if ( charsUsed - curPos < 3 ) { goto ReadData; } if ( chars[curPos+1] != ']' || chars[curPos+2] != '>' ) { curPos++; continue; } if ( ignoreSectionDepth > 0 ) { ignoreSectionDepth--; curPos += 3; continue; } else { curPos += 3; scanningFunction = ScanningFunction.SubsetContent; return Token.CondSectionEnd; } default: // end of buffer if ( curPos == charsUsed ) { goto ReadData; } // surrogate chars else { char ch = chars[curPos]; if ( XmlCharType.IsHighSurrogate(ch) ) { if ( curPos + 1 == charsUsed ) { goto ReadData; } curPos++; if ( XmlCharType.IsLowSurrogate(chars[curPos])) { curPos++; continue; } } ThrowInvalidChar( chars, charsUsed, curPos ); return Token.None; } } ReadData: // read new characters into the buffer if ( readerAdapter.IsEof || ReadData() == 0 ) { if ( HandleEntityEnd( false ) ) { continue; } Throw( curPos, Res.Xml_UnclosedConditionalSection ); } tokenStartPos = curPos; } } private void ScanName() { ScanQName( false ); } private void ScanQName() { ScanQName( SupportNamespaces ); } private void ScanQName( bool isQName ) { tokenStartPos = curPos; int colonOffset = -1; for (;;) { unsafe { #if SILVERLIGHT if ( xmlCharType.IsStartNCNameSingleChar(chars[curPos]) || chars[curPos] == ':' ) { #else if ( ( xmlCharType.charProperties[chars[curPos]] & XmlCharType.fNCStartNameSC ) != 0 || chars[curPos] == ':') { // if ( xmlCharType.IsStartNCNameSingleChar(chars[curPos]) || chars[curPos] == ':' ) { #endif curPos++; } #if XML10_FIFTH_EDITION else if ( curPos + 1 < charsUsed && xmlCharType.IsNCNameSurrogateChar(chars[curPos+1], chars[curPos])) { curPos += 2; } #endif else { if ( curPos + 1 >= charsUsed ) { if ( ReadDataInName() ) { continue; } Throw( curPos, Res.Xml_UnexpectedEOF, "Name" ); } else { Throw( curPos, Res.Xml_BadStartNameChar, XmlException.BuildCharExceptionArgs( chars, charsUsed, curPos ) ); } } } ContinueName: unsafe { for (;;) { #if SILVERLIGHT if ( xmlCharType.IsNCNameSingleChar( chars[curPos] ) ) { #else if ( ( xmlCharType.charProperties[chars[curPos]] & XmlCharType.fNCNameSC ) != 0 ) { // while ( xmlCharType.IsNCNameSingleChar(chars[curPos]) ) { #endif curPos++; } #if XML10_FIFTH_EDITION else if ( curPos + 1 < charsUsed && xmlCharType.IsNameSurrogateChar(chars[curPos + 1], chars[curPos]) ) { curPos += 2; } #endif else { break; } } } if ( chars[curPos] == ':' ) { if ( isQName ) { if ( colonOffset != -1 ) { Throw( curPos, Res.Xml_BadNameChar, XmlException.BuildCharExceptionArgs( ':', '\0' )); } colonOffset = curPos - tokenStartPos; curPos++; continue; } else { curPos++; goto ContinueName; } } // end of buffer else if ( curPos == charsUsed #if XML10_FIFTH_EDITION || ( curPos + 1 == charsUsed && xmlCharType.IsNCNameHighSurrogateChar( chars[curPos] ) ) #endif ) { if ( ReadDataInName() ) { goto ContinueName; } if ( tokenStartPos == curPos ) { Throw( curPos, Res.Xml_UnexpectedEOF, "Name" ); } } // end of name colonPos = ( colonOffset == -1 ) ? -1 : tokenStartPos + colonOffset; return; } } private bool ReadDataInName() { int offset = curPos - tokenStartPos; curPos = tokenStartPos; bool newDataRead = ( ReadData() != 0 ); tokenStartPos = curPos; curPos += offset; return newDataRead; } private void ScanNmtoken() { tokenStartPos = curPos; for (;;) { unsafe { for (;;) { #if SILVERLIGHT if ( xmlCharType.IsNCNameSingleChar(chars[curPos]) || chars[curPos] == ':' ) { #else if ((xmlCharType.charProperties[chars[curPos]] & XmlCharType.fNCNameSC) != 0 || chars[curPos] == ':') { // if ( xmlCharType.IsNCNameChar(chars[curPos]) || chars[curPos] == ':' ) { #endif curPos++; } #if XML10_FIFTH_EDITION else if (curPos + 1 < charsUsed && xmlCharType.IsNCNameSurrogateChar(chars[curPos + 1], chars[curPos])) { curPos += 2; } #endif else { break; } } } if ( curPos < charsUsed #if XML10_FIFTH_EDITION && ( !xmlCharType.IsNCNameHighSurrogateChar( chars[curPos] ) || curPos + 1 < charsUsed ) #endif ) { if ( curPos - tokenStartPos == 0 ) { Throw( curPos, Res.Xml_BadNameChar, XmlException.BuildCharExceptionArgs( chars, charsUsed, curPos ) ); } return; } int len = curPos - tokenStartPos; curPos = tokenStartPos; if ( ReadData() == 0 ) { if ( len > 0 ) { tokenStartPos = curPos; curPos += len; return; } Throw( curPos, Res.Xml_UnexpectedEOF, "NmToken" ); } tokenStartPos = curPos; curPos += len; } } private bool EatPublicKeyword() { Debug.Assert( chars[curPos] == 'P' ); while ( charsUsed - curPos < 6 ) { if ( ReadData() == 0 ) { return false; } } if ( chars[curPos+1] != 'U' || chars[curPos+2] != 'B' || chars[curPos+3] != 'L' || chars[curPos+4] != 'I' || chars[curPos+5] != 'C' ) { return false; } curPos += 6; return true; } private bool EatSystemKeyword() { Debug.Assert( chars[curPos] == 'S' ); while ( charsUsed - curPos < 6 ) { if ( ReadData() == 0 ) { return false; } } if ( chars[curPos+1] != 'Y' || chars[curPos+2] != 'S' || chars[curPos+3] != 'T' || chars[curPos+4] != 'E' || chars[curPos+5] != 'M' ) { return false; } curPos += 6; return true; } // // Scanned data getters // private XmlQualifiedName GetNameQualified( bool canHavePrefix ) { Debug.Assert( curPos - tokenStartPos > 0 ); if ( colonPos == -1 ) { return new XmlQualifiedName( nameTable.Add( chars, tokenStartPos, curPos - tokenStartPos ) ); } else { if ( canHavePrefix ) { return new XmlQualifiedName( nameTable.Add( chars, colonPos + 1, curPos - colonPos - 1 ), nameTable.Add( chars, tokenStartPos, colonPos - tokenStartPos ) ); } else { Throw( tokenStartPos, Res.Xml_ColonInLocalName, GetNameString() ); return null; } } } private string GetNameString() { Debug.Assert( curPos - tokenStartPos > 0 ); return new string( chars, tokenStartPos, curPos - tokenStartPos ); } private string GetNmtokenString() { return GetNameString(); } private string GetValue() { if ( stringBuilder.Length == 0 ) { return new string( chars, tokenStartPos, curPos - tokenStartPos - 1 ); } else { return stringBuilder.ToString(); } } private string GetValueWithStrippedSpaces() { Debug.Assert( curPos == 0 || chars[curPos-1] == '"' || chars[curPos-1] == '\'' ); // We cannot StripSpaces directly in the buffer - we need the original value inthe buffer intact so that the internal subset value is correct string val = ( stringBuilder.Length == 0 ) ? new string( chars, tokenStartPos, curPos - tokenStartPos - 1 ) : stringBuilder.ToString(); return StripSpaces( val ); } // // Parsing buffer maintainance methods // int ReadData() { SaveParsingBuffer(); int charsRead = readerAdapter.ReadData(); LoadParsingBuffer(); return charsRead; } private void LoadParsingBuffer() { chars = readerAdapter.ParsingBuffer; charsUsed = readerAdapter.ParsingBufferLength; curPos = readerAdapter.CurrentPosition; } private void SaveParsingBuffer() { SaveParsingBuffer( curPos ); } private void SaveParsingBuffer( int internalSubsetValueEndPos ) { if ( SaveInternalSubsetValue ) { Debug.Assert( internalSubsetValueSb != null ); int readerCurPos = readerAdapter.CurrentPosition; if ( internalSubsetValueEndPos - readerCurPos > 0 ) { internalSubsetValueSb.Append( chars, readerCurPos, internalSubsetValueEndPos - readerCurPos ); } } readerAdapter.CurrentPosition = curPos; } // // Entity handling // private bool HandleEntityReference( bool paramEntity, bool inLiteral, bool inAttribute ) { Debug.Assert( chars[curPos] == '&' || chars[curPos] == '%' ); curPos++; return HandleEntityReference( ScanEntityName(), paramEntity, inLiteral, inAttribute ); } private bool HandleEntityReference( XmlQualifiedName entityName, bool paramEntity, bool inLiteral, bool inAttribute ) { Debug.Assert( chars[curPos-1] == ';' ); SaveParsingBuffer(); if ( paramEntity && ParsingInternalSubset && !ParsingTopLevelMarkup ) { Throw( curPos - entityName.Name.Length - 1, Res.Xml_InvalidParEntityRef ); } SchemaEntity entity = VerifyEntityReference( entityName, paramEntity, true, inAttribute ); if ( entity == null ) { return false; } if ( entity.ParsingInProgress ) { Throw( curPos - entityName.Name.Length - 1, paramEntity ? Res.Xml_RecursiveParEntity : Res.Xml_RecursiveGenEntity, entityName.Name ); } int newEntityId; if ( entity.IsExternal ) { if ( !readerAdapter.PushEntity( entity, out newEntityId ) ) { return false; } externalEntitiesDepth++; } else { if ( entity.Text.Length == 0 ) { return false; } if ( !readerAdapter.PushEntity( entity, out newEntityId ) ) { return false; } } currentEntityId = newEntityId; if ( paramEntity && !inLiteral && scanningFunction != ScanningFunction.ParamEntitySpace ) { savedScanningFunction = scanningFunction; scanningFunction = ScanningFunction.ParamEntitySpace; } LoadParsingBuffer(); return true; } private bool HandleEntityEnd( bool inLiteral ) { SaveParsingBuffer(); IDtdEntityInfo oldEntity; if ( !readerAdapter.PopEntity( out oldEntity, out currentEntityId ) ) { return false; } LoadParsingBuffer(); if ( oldEntity == null ) { // external subset popped Debug.Assert( !ParsingInternalSubset || freeFloatingDtd ); Debug.Assert( currentEntityId == 0 ); if ( scanningFunction == ScanningFunction.ParamEntitySpace ) { scanningFunction = savedScanningFunction; } return false; } if ( oldEntity.IsExternal ) { externalEntitiesDepth--; } if ( !inLiteral && scanningFunction != ScanningFunction.ParamEntitySpace ) { savedScanningFunction = scanningFunction; scanningFunction = ScanningFunction.ParamEntitySpace; } return true; } private SchemaEntity VerifyEntityReference( XmlQualifiedName entityName, bool paramEntity, bool mustBeDeclared, bool inAttribute ) { Debug.Assert( chars[curPos-1] == ';' ); SchemaEntity entity; if ( paramEntity ) { schemaInfo.ParameterEntities.TryGetValue(entityName, out entity); } else { schemaInfo.GeneralEntities.TryGetValue(entityName, out entity); } if ( entity == null ) { if ( paramEntity ) { #if !SILVERLIGHT if ( validate ) { SendValidationEvent( curPos - entityName.Name.Length - 1, XmlSeverityType.Error, Res.Xml_UndeclaredParEntity, entityName.Name ); } #endif } else if ( mustBeDeclared ) { if ( !ParsingInternalSubset ) { #if !SILVERLIGHT if (validate) { SendValidationEvent( curPos - entityName.Name.Length - 1, XmlSeverityType.Error, Res.Xml_UndeclaredEntity, entityName.Name ); } #endif } else { Throw( curPos - entityName.Name.Length - 1, Res.Xml_UndeclaredEntity, entityName.Name ); } } return null; } if ( !entity.NData.IsEmpty ) { Throw( curPos - entityName.Name.Length - 1, Res.Xml_UnparsedEntityRef, entityName.Name ); } if ( inAttribute && entity.IsExternal ) { Throw( curPos - entityName.Name.Length - 1, Res.Xml_ExternalEntityInAttValue, entityName.Name ); } return entity; } // // Helper methods and properties // #if !SILVERLIGHT private void SendValidationEvent( int pos, XmlSeverityType severity, string code, string arg ) { Debug.Assert( validate ); SendValidationEvent( severity, new XmlSchemaException( code, arg, BaseUriStr, (int)LineNo, (int)LinePos + ( pos - curPos ) ) ); } private void SendValidationEvent( XmlSeverityType severity, string code, string arg ) { Debug.Assert( validate ); SendValidationEvent( severity, new XmlSchemaException( code, arg, BaseUriStr, (int)LineNo, (int)LinePos ) ); } private void SendValidationEvent( XmlSeverityType severity, XmlSchemaException e ) { Debug.Assert( validate ); IValidationEventHandling eventHandling = readerAdapterWithValidation.ValidationEventHandling; if ( eventHandling != null ) { eventHandling.SendEvent(e, severity); } } #endif private bool IsAttributeValueType( Token token ) { return (int)token >= (int)Token.CDATA && (int)token <= (int)Token.NOTATION; } private int LineNo { get { return readerAdapter.LineNo; } } private int LinePos { get { return curPos - readerAdapter.LineStartPosition; } } private string BaseUriStr { get { Uri tmp = readerAdapter.BaseUri; return ( tmp != null ) ? tmp.ToString() : string.Empty; } } private void OnUnexpectedError() { Debug.Assert( false, "This is an unexpected error that should have been handled in the ScanXXX methods." ); Throw( curPos, Res.Xml_InternalError ); } void Throw( int curPos, string res ) { Throw( curPos, res, string.Empty ); } void Throw( int curPos, string res, string arg ) { this.curPos = curPos; Uri baseUri = readerAdapter.BaseUri; readerAdapter.Throw( new XmlException( res, arg, (int)LineNo, (int)LinePos, baseUri == null ? null : baseUri.ToString() ) ); } void Throw( int curPos, string res, string[] args ) { this.curPos = curPos; Uri baseUri = readerAdapter.BaseUri; readerAdapter.Throw( new XmlException( res, args, (int)LineNo, (int)LinePos, baseUri == null ? null : baseUri.ToString() ) ); } void Throw( string res, string arg, int lineNo, int linePos ) { Uri baseUri = readerAdapter.BaseUri; readerAdapter.Throw( new XmlException( res, arg, (int)lineNo, (int)linePos, baseUri == null ? null : baseUri.ToString() ) ); } void ThrowInvalidChar( int pos, string data, int invCharPos ) { Throw( pos, Res.Xml_InvalidCharacter, XmlException.BuildCharExceptionArgs( data, invCharPos )); } void ThrowInvalidChar( char[] data, int length, int invCharPos ) { Throw( invCharPos, Res.Xml_InvalidCharacter, XmlException.BuildCharExceptionArgs( data, length, invCharPos ) ); } private void ThrowUnexpectedToken( int pos, string expectedToken ) { ThrowUnexpectedToken( pos, expectedToken, null ); } private void ThrowUnexpectedToken( int pos, string expectedToken1, string expectedToken2 ) { string unexpectedToken = ParseUnexpectedToken( pos ); if ( expectedToken2 != null ) { Throw( curPos, Res.Xml_UnexpectedTokens2, new string[3] { unexpectedToken, expectedToken1, expectedToken2 } ); } else { Throw( curPos, Res.Xml_UnexpectedTokenEx, new string[2] { unexpectedToken, expectedToken1 } ); } } private string ParseUnexpectedToken( int startPos ) { if ( xmlCharType.IsNCNameSingleChar( chars[startPos] ) #if XML10_FIFTH_EDITION || xmlCharType.IsNCNameHighSurrogateChar( chars[startPos] ) #endif ) { // postpone the proper surrogate checking to the loop below int endPos = startPos; for (;;) { if ( xmlCharType.IsNCNameSingleChar( chars[endPos] ) ) { endPos++; } #if XML10_FIFTH_EDITION else if ( chars[endPos] != 0 && // check for end of the buffer xmlCharType.IsNCNameSurrogateChar( chars[endPos], chars[endPos + 1] ) ) { endPos += 2; } #endif else { break; } } int len = endPos - startPos; return new string( chars, startPos, len > 0 ? len : 1 ); } else { Debug.Assert( startPos < charsUsed ); return new string( chars, startPos, 1 ); } } // StripSpaces removes spaces at the beginning and at the end of the value and replaces sequences of spaces with a single space // !!! This method exists in 2 copies, here and in the XmlTextReaderImplHelper.cs // If you're changing this one, please also fix the other one. // (This is necessary due to packaging) internal static string StripSpaces(string value) { int len = value.Length; if (len <= 0) { return string.Empty; } int startPos = 0; StringBuilder norValue = null; while (value[startPos] == 0x20) { startPos++; if (startPos == len) { return " "; } } int i; for (i = startPos; i < len; i++) { if (value[i] == 0x20) { int j = i + 1; while (j < len && value[j] == 0x20) { j++; } if (j == len) { if (norValue == null) { return value.Substring(startPos, i - startPos); } else { norValue.Append(value, startPos, i - startPos); return norValue.ToString(); } } if (j > i + 1) { if (norValue == null) { norValue = new StringBuilder(len); } norValue.Append(value, startPos, i - startPos + 1); startPos = j; i = j - 1; } } } if (norValue == null) { return (startPos == 0) ? value : value.Substring(startPos, len - startPos); } else { if (i > startPos) { norValue.Append(value, startPos, i - startPos); } return norValue.ToString(); } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // //[....] //----------------------------------------------------------------------------- using System; using System.IO; using System.Text; using System.Xml.Schema; using System.Diagnostics; using System.Collections; using System.Collections.Generic; using System.Globalization; #if SILVERLIGHT using BufferBuilder=System.Xml.BufferBuilder; #else using BufferBuilder = System.Text.StringBuilder; #endif namespace System.Xml { internal class DtdParser : IDtdParser { // // Private types // enum Token { CDATA = XmlTokenizedType.CDATA, // == 0 ID = XmlTokenizedType.ID, // == 1 IDREF = XmlTokenizedType.IDREF, // == 2 IDREFS = XmlTokenizedType.IDREFS, // == 3 ENTITY = XmlTokenizedType.ENTITY, // == 4 ENTITIES = XmlTokenizedType.ENTITIES, // == 5 NMTOKEN = XmlTokenizedType.NMTOKEN, // == 6 NMTOKENS = XmlTokenizedType.NMTOKENS, // == 7 NOTATION = XmlTokenizedType.NOTATION, // == 8 None , PERef , AttlistDecl , ElementDecl , EntityDecl , NotationDecl , Comment , PI , CondSectionStart, CondSectionEnd , Eof , REQUIRED , IMPLIED , FIXED , QName , Name , Nmtoken , Quote, LeftParen , RightParen , GreaterThan , Or , LeftBracket , RightBracket , PUBLIC , SYSTEM , Literal , DOCTYPE , NData , Percent , Star , QMark , Plus , PCDATA , Comma , ANY , EMPTY , IGNORE , INCLUDE , } enum ScanningFunction { SubsetContent, Name, QName, Nmtoken, Doctype1, Doctype2, Element1, Element2, Element3, Element4, Element5, Element6, Element7, Attlist1, Attlist2, Attlist3, Attlist4, Attlist5, Attlist6, Attlist7, Entity1, Entity2, Entity3, Notation1, CondSection1, CondSection2, CondSection3, Literal, SystemId, PublicId1, PublicId2, ClosingTag, ParamEntitySpace, None, } enum LiteralType { AttributeValue, EntityReplText, SystemOrPublicID } #if !SILVERLIGHT class UndeclaredNotation { internal string name; internal int lineNo; internal int linePos; internal UndeclaredNotation next; internal UndeclaredNotation( string name, int lineNo, int linePos ) { this.name = name; this.lineNo = lineNo; this.linePos = linePos; this.next = null; } } #endif // // Fields // // connector to reader IDtdParserAdapter readerAdapter; #if !SILVERLIGHT IDtdParserAdapterWithValidation readerAdapterWithValidation; #endif // name table XmlNameTable nameTable; // final schema info SchemaInfo schemaInfo; // XmlCharType instance XmlCharType xmlCharType = XmlCharType.Instance; // system & public id string systemId = string.Empty; string publicId = string.Empty; // flags #if !SILVERLIGHT bool normalize = true; bool validate = false; bool supportNamespaces = true; bool v1Compat = false; #endif // cached character buffer char[] chars; int charsUsed; int curPos; // scanning function for the next token ScanningFunction scanningFunction; ScanningFunction nextScaningFunction; ScanningFunction savedScanningFunction; // this one is used only for adding spaces around parameter entities // flag if whitespace seen before token bool whitespaceSeen; // start position of the last token (for name and value) int tokenStartPos; // colon position (for name) int colonPos; // value of the internal subset BufferBuilder internalSubsetValueSb = null; // entities int externalEntitiesDepth = 0; int currentEntityId = 0; // free-floating DTD support bool freeFloatingDtd = false; bool hasFreeFloatingInternalSubset = false; // misc BufferBuilder stringBuilder; int condSectionDepth = 0; LineInfo literalLineInfo = new LineInfo( 0, 0 ); char literalQuoteChar = '"'; string documentBaseUri = string.Empty; string externalDtdBaseUri = string.Empty; #if !SILVERLIGHT DictionaryundeclaredNotations = null; int[] condSectionEntityIds = null; #endif const int CondSectionEntityIdsInitialSize = 2; // // Constructor // static DtdParser() { #if DEBUG // The absolute numbering is utilized in attribute type parsing Debug.Assert( (int)Token.CDATA == (int)XmlTokenizedType.CDATA && (int)XmlTokenizedType.CDATA == 0 ); Debug.Assert( (int)Token.ID == (int)XmlTokenizedType.ID && (int)XmlTokenizedType.ID == 1 ); Debug.Assert( (int)Token.IDREF == (int)XmlTokenizedType.IDREF && (int)XmlTokenizedType.IDREF == 2 ); Debug.Assert( (int)Token.IDREFS == (int)XmlTokenizedType.IDREFS && (int)XmlTokenizedType.IDREFS == 3 ); Debug.Assert( (int)Token.ENTITY == (int)XmlTokenizedType.ENTITY && (int)XmlTokenizedType.ENTITY == 4 ); Debug.Assert( (int)Token.ENTITIES == (int)XmlTokenizedType.ENTITIES && (int)XmlTokenizedType.ENTITIES == 5 ); Debug.Assert( (int)Token.NMTOKEN == (int)XmlTokenizedType.NMTOKEN && (int)XmlTokenizedType.NMTOKEN == 6 ); Debug.Assert( (int)Token.NMTOKENS == (int)XmlTokenizedType.NMTOKENS && (int)XmlTokenizedType.NMTOKENS == 7 ); Debug.Assert( (int)Token.NOTATION == (int)XmlTokenizedType.NOTATION && (int)XmlTokenizedType.NOTATION == 8 ); #endif } DtdParser() { } internal static IDtdParser Create() { return new DtdParser(); } // // Initialization methods // private void Initialize(IDtdParserAdapter readerAdapter) { Debug.Assert(readerAdapter != null); this.readerAdapter = readerAdapter; #if !SILVERLIGHT this.readerAdapterWithValidation = readerAdapter as IDtdParserAdapterWithValidation; #endif nameTable = readerAdapter.NameTable; #if !SILVERLIGHT IDtdParserAdapterWithValidation raWithValidation = readerAdapter as IDtdParserAdapterWithValidation; if (raWithValidation != null) { this.validate = raWithValidation.DtdValidation; } IDtdParserAdapterV1 raV1 = readerAdapter as IDtdParserAdapterV1; if (raV1 != null) { v1Compat = raV1.V1CompatibilityMode; this.normalize = raV1.Normalization; this.supportNamespaces = raV1.Namespaces; } #endif schemaInfo = new SchemaInfo(); #if !SILVERLIGHT schemaInfo.SchemaType = SchemaType.DTD; #endif stringBuilder = new BufferBuilder(); Uri baseUri = readerAdapter.BaseUri; if (baseUri != null) { documentBaseUri = baseUri.ToString(); } freeFloatingDtd = false; } private void InitializeFreeFloatingDtd(string baseUri, string docTypeName, string publicId, string systemId, string internalSubset, IDtdParserAdapter adapter) { Initialize(adapter); if ( docTypeName == null || docTypeName.Length == 0 ) { throw XmlConvert.CreateInvalidNameArgumentException( docTypeName, "docTypeName" ); } // check doctype name XmlConvert.VerifyName( docTypeName ); int colonPos = docTypeName.IndexOf( ':' ); if ( colonPos == -1 ) { schemaInfo.DocTypeName = new XmlQualifiedName( nameTable.Add( docTypeName ) ); } else { schemaInfo.DocTypeName = new XmlQualifiedName( nameTable.Add( docTypeName.Substring( 0, colonPos ) ), nameTable.Add( docTypeName.Substring( colonPos + 1 ) ) ); } int i; // check system id if ( systemId != null && systemId.Length > 0 ) { if ( ( i = xmlCharType.IsOnlyCharData( systemId ) ) >= 0 ) { ThrowInvalidChar( curPos, systemId, i ); } this.systemId = systemId; } // check public id if ( publicId != null && publicId.Length > 0 ) { if ( ( i = xmlCharType.IsPublicId( publicId ) ) >= 0 ) { ThrowInvalidChar( curPos, publicId, i ); } this.publicId = publicId; } // init free-floating internal subset if ( internalSubset != null && internalSubset.Length > 0 ) { readerAdapter.PushInternalDtd( baseUri, internalSubset ); hasFreeFloatingInternalSubset = true; } Uri baseUriOb = readerAdapter.BaseUri; if ( baseUriOb != null ) { documentBaseUri = baseUriOb.ToString(); } freeFloatingDtd = true; } // // IDtdParser interface // #region IDtdParser Members IDtdInfo IDtdParser.ParseInternalDtd(IDtdParserAdapter adapter, bool saveInternalSubset) { Initialize(adapter); Parse(saveInternalSubset); return schemaInfo; } IDtdInfo IDtdParser.ParseFreeFloatingDtd(string baseUri, string docTypeName, string publicId, string systemId, string internalSubset, IDtdParserAdapter adapter) { InitializeFreeFloatingDtd(baseUri, docTypeName, publicId, systemId, internalSubset, adapter); Parse(false); return schemaInfo; } #endregion // // Private properties // private bool ParsingInternalSubset { get { return externalEntitiesDepth == 0; } } private bool IgnoreEntityReferences { get { return scanningFunction == ScanningFunction.CondSection3; } } private bool SaveInternalSubsetValue { get { return readerAdapter.EntityStackLength == 0 && internalSubsetValueSb != null; } } private bool ParsingTopLevelMarkup { get { return scanningFunction == ScanningFunction.SubsetContent || ( scanningFunction == ScanningFunction.ParamEntitySpace && savedScanningFunction == ScanningFunction.SubsetContent ); } } private bool SupportNamespaces { get { #if SILVERLIGHT return true; #else return supportNamespaces; #endif } } private bool Normalize { get { #if SILVERLIGHT return true; #else return normalize; #endif } } // // Parsing methods // private void Parse( bool saveInternalSubset ) { if ( freeFloatingDtd ) { ParseFreeFloatingDtd(); } else { ParseInDocumentDtd( saveInternalSubset ); } schemaInfo.Finish(); #if !SILVERLIGHT // check undeclared forward references if ( validate && undeclaredNotations != null ) { foreach ( UndeclaredNotation un in undeclaredNotations.Values ) { UndeclaredNotation tmpUn = un; while ( tmpUn != null ) { SendValidationEvent( XmlSeverityType.Error, new XmlSchemaException( Res.Sch_UndeclaredNotation, un.name, BaseUriStr, (int)un.lineNo, (int)un.linePos ) ); tmpUn = tmpUn.next; } } } #endif } private void ParseInDocumentDtd( bool saveInternalSubset ) { LoadParsingBuffer(); scanningFunction = ScanningFunction.QName; nextScaningFunction = ScanningFunction.Doctype1; // doctype name if ( GetToken( false ) != Token.QName ) { OnUnexpectedError(); } schemaInfo.DocTypeName = GetNameQualified( true ); // SYSTEM or PUBLIC id Token token = GetToken( false ); if ( token == Token.SYSTEM || token == Token.PUBLIC ) { ParseExternalId( token, Token.DOCTYPE, out publicId, out systemId ); token = GetToken( false); } switch ( token ) { case Token.LeftBracket: if ( saveInternalSubset ) { SaveParsingBuffer(); // this will cause saving the internal subset right from the point after '[' internalSubsetValueSb = new BufferBuilder(); } ParseInternalSubset(); break; case Token.GreaterThan: break; default: OnUnexpectedError(); break; } SaveParsingBuffer(); if ( systemId != null && systemId.Length > 0 ) { ParseExternalSubset(); } } private void ParseFreeFloatingDtd() { if ( hasFreeFloatingInternalSubset ) { LoadParsingBuffer(); ParseInternalSubset(); SaveParsingBuffer(); } if ( systemId != null && systemId.Length > 0 ) { ParseExternalSubset(); } } private void ParseInternalSubset() { Debug.Assert( ParsingInternalSubset ); ParseSubset(); } private void ParseExternalSubset() { Debug.Assert( externalEntitiesDepth == 0 ); // push external subset if ( !readerAdapter.PushExternalSubset( systemId, publicId ) ) { return; } Uri baseUri = readerAdapter.BaseUri; if ( baseUri != null ) { externalDtdBaseUri = baseUri.ToString(); } externalEntitiesDepth++; LoadParsingBuffer(); // parse ParseSubset(); #if DEBUG Debug.Assert( readerAdapter.EntityStackLength == 0 || ( freeFloatingDtd && readerAdapter.EntityStackLength == 1 ) ); #endif } private void ParseSubset() { int startTagEntityId; for (;;) { Token token = GetToken( false ); startTagEntityId = currentEntityId; switch ( token ) { case Token.AttlistDecl: ParseAttlistDecl(); break; case Token.ElementDecl: ParseElementDecl(); break; case Token.EntityDecl: ParseEntityDecl(); break; case Token.NotationDecl: ParseNotationDecl(); break; case Token.Comment: ParseComment(); break; case Token.PI: ParsePI(); break; case Token.CondSectionStart: if ( ParsingInternalSubset ) { Throw( curPos - 3, Res.Xml_InvalidConditionalSection ); // 3==strlen(" 0 ) { condSectionDepth--; #if !SILVERLIGHT if ( validate && currentEntityId != condSectionEntityIds[condSectionDepth] ) { SendValidationEvent( curPos, XmlSeverityType.Error, Res.Sch_ParEntityRefNesting, string.Empty ); } #endif } else { Throw( curPos - 3, Res.Xml_UnexpectedCDataEnd ); } break; case Token.RightBracket: if ( ParsingInternalSubset ) { if ( condSectionDepth != 0 ) { Throw( curPos, Res.Xml_UnclosedConditionalSection ); } // append the rest to internal subset value but not the closing ']' if ( internalSubsetValueSb != null ) { Debug.Assert( curPos > 0 && chars[curPos-1] == ']' ); SaveParsingBuffer( curPos - 1 ); schemaInfo.InternalDtdSubset = internalSubsetValueSb.ToString(); internalSubsetValueSb = null; } // check '>' if ( GetToken( false ) != Token.GreaterThan ) { ThrowUnexpectedToken( curPos, ">" ); } #if DEBUG // check entity nesting Debug.Assert( readerAdapter.EntityStackLength == 0 || ( freeFloatingDtd && readerAdapter.EntityStackLength == 1 ) ); #endif } else { Throw( curPos, Res.Xml_ExpectDtdMarkup ); } return; case Token.Eof: if ( ParsingInternalSubset && !freeFloatingDtd ) { Throw( curPos, Res.Xml_IncompleteDtdContent ); } if ( condSectionDepth != 0 ) { Throw( curPos, Res.Xml_UnclosedConditionalSection ); } return; default: Debug.Assert( false ); break; } Debug.Assert( scanningFunction == ScanningFunction.SubsetContent ); if ( currentEntityId != startTagEntityId ) { #if SILVERLIGHT Throw(curPos, Res.Sch_ParEntityRefNesting); #else if ( validate ) { SendValidationEvent( curPos, XmlSeverityType.Error, Res.Sch_ParEntityRefNesting, string.Empty ); } else { if ( !v1Compat ) { Throw( curPos, Res.Sch_ParEntityRefNesting ); } } #endif } } } private void ParseAttlistDecl() { if (GetToken(true) != Token.QName) { goto UnexpectedError; } // element name XmlQualifiedName elementName = GetNameQualified(true); SchemaElementDecl elementDecl; if (!schemaInfo.ElementDecls.TryGetValue(elementName, out elementDecl)) { if (!schemaInfo.UndeclaredElementDecls.TryGetValue(elementName, out elementDecl)) { elementDecl = new SchemaElementDecl(elementName, elementName.Namespace); schemaInfo.UndeclaredElementDecls.Add(elementName, elementDecl); } } SchemaAttDef attrDef = null; for (; ; ) { switch (GetToken(false)) { case Token.QName: XmlQualifiedName attrName = GetNameQualified(true); attrDef = new SchemaAttDef(attrName, attrName.Namespace); attrDef.IsDeclaredInExternal = !ParsingInternalSubset; attrDef.LineNumber = (int)LineNo; attrDef.LinePosition = (int)LinePos - (curPos - tokenStartPos); break; case Token.GreaterThan: #if !SILVERLIGHT if ( v1Compat ) { // check xml:space and xml:lang // if ( attrDef != null && attrDef.Prefix.Length > 0 && attrDef.Prefix.Equals( "xml" ) && attrDef.Name.Name == "space" ) { attrDef.Reserved = SchemaAttDef.Reserve.XmlSpace; if ( attrDef.Datatype.TokenizedType != XmlTokenizedType.ENUMERATION ) { Throw( Res.Xml_EnumerationRequired, string.Empty, attrDef.LineNumber, attrDef.LinePosition ); } if ( validate ) { attrDef.CheckXmlSpace( readerAdapterWithValidation.ValidationEventHandling ); } } } #endif return; default: goto UnexpectedError; } bool attrDefAlreadyExists = (elementDecl.GetAttDef(attrDef.Name) != null); ParseAttlistType(attrDef, elementDecl, attrDefAlreadyExists); ParseAttlistDefault(attrDef, attrDefAlreadyExists); // check xml:space and xml:lang if (attrDef.Prefix.Length > 0 && attrDef.Prefix.Equals("xml")) { if ( attrDef.Name.Name == "space" ) { #if !SILVERLIGHT if ( v1Compat ) { // string val = attrDef.DefaultValueExpanded.Trim(); if ( val.Equals( "preserve" ) || val.Equals( "default" ) ) { attrDef.Reserved = SchemaAttDef.Reserve.XmlSpace; } } else { #endif attrDef.Reserved = SchemaAttDef.Reserve.XmlSpace; if ( attrDef.TokenizedType != XmlTokenizedType.ENUMERATION ) { Throw( Res.Xml_EnumerationRequired, string.Empty, attrDef.LineNumber, attrDef.LinePosition ); } #if !SILVERLIGHT if ( validate ) { attrDef.CheckXmlSpace( readerAdapterWithValidation.ValidationEventHandling ); } } #endif } else if ( attrDef.Name.Name == "lang" ) { attrDef.Reserved = SchemaAttDef.Reserve.XmlLang; } } // add attribute to element decl if (!attrDefAlreadyExists) { elementDecl.AddAttDef(attrDef); } } UnexpectedError: OnUnexpectedError(); } private void ParseAttlistType( SchemaAttDef attrDef, SchemaElementDecl elementDecl, bool ignoreErrors ) { Token token = GetToken( true ); if ( token != Token.CDATA ) { elementDecl.HasNonCDataAttribute = true; } if ( IsAttributeValueType( token ) ) { attrDef.TokenizedType = (XmlTokenizedType)(int)token; #if !SILVERLIGHT attrDef.SchemaType = XmlSchemaType.GetBuiltInSimpleType( attrDef.Datatype.TypeCode ); #endif switch ( token ) { case Token.NOTATION: break; case Token.ID: #if !SILVERLIGHT if ( validate && elementDecl.IsIdDeclared ) { SchemaAttDef idAttrDef = elementDecl.GetAttDef( attrDef.Name ); if ( ( idAttrDef == null || idAttrDef.Datatype.TokenizedType != XmlTokenizedType.ID ) && !ignoreErrors ) { SendValidationEvent( XmlSeverityType.Error, Res.Sch_IdAttrDeclared, elementDecl.Name.ToString() ); } } #endif elementDecl.IsIdDeclared = true; return; default: return; } #if !SILVERLIGHT // check notation constrains if ( validate ) { if (elementDecl.IsNotationDeclared && !ignoreErrors ) { SendValidationEvent( curPos - 8, XmlSeverityType.Error, Res.Sch_DupNotationAttribute, elementDecl.Name.ToString() ); // 8 == strlen("NOTATION") } else { if ( elementDecl.ContentValidator != null && elementDecl.ContentValidator.ContentType == XmlSchemaContentType.Empty && !ignoreErrors ) { SendValidationEvent( curPos - 8, XmlSeverityType.Error, Res.Sch_NotationAttributeOnEmptyElement, elementDecl.Name.ToString() );// 8 == strlen("NOTATION") } elementDecl.IsNotationDeclared = true; } } #endif if ( GetToken( true ) != Token.LeftParen ) { goto UnexpectedError; } // parse notation list if ( GetToken( false ) != Token.Name ) { goto UnexpectedError; } for (;;) { string notationName = GetNameString(); #if !SILVERLIGHT if ( !schemaInfo.Notations.ContainsKey(notationName) ) { AddUndeclaredNotation(notationName); } if ( validate && !v1Compat && attrDef.Values != null && attrDef.Values.Contains( notationName ) && !ignoreErrors ) { SendValidationEvent( XmlSeverityType.Error, new XmlSchemaException( Res.Xml_AttlistDuplNotationValue, notationName, BaseUriStr, (int)LineNo, (int)LinePos ) ); } attrDef.AddValue( notationName ); #endif switch ( GetToken( false ) ) { case Token.Or: if ( GetToken( false ) != Token.Name ) { goto UnexpectedError; } continue; case Token.RightParen: return; default: goto UnexpectedError; } } } else if ( token == Token.LeftParen ) { attrDef.TokenizedType = XmlTokenizedType.ENUMERATION; #if !SILVERLIGHT attrDef.SchemaType = XmlSchemaType.GetBuiltInSimpleType( attrDef.Datatype.TypeCode ); #endif // parse nmtoken list if ( GetToken( false ) != Token.Nmtoken ) goto UnexpectedError; #if !SILVERLIGHT attrDef.AddValue( GetNameString() ); #endif for (;;) { switch ( GetToken( false ) ) { case Token.Or: if ( GetToken( false ) != Token.Nmtoken ) goto UnexpectedError; string nmtoken = GetNmtokenString(); #if !SILVERLIGHT if ( validate && !v1Compat && attrDef.Values != null && attrDef.Values.Contains( nmtoken ) && !ignoreErrors ) { SendValidationEvent( XmlSeverityType.Error, new XmlSchemaException( Res.Xml_AttlistDuplEnumValue, nmtoken, BaseUriStr, (int)LineNo, (int)LinePos ) ); } attrDef.AddValue( nmtoken ); #endif break; case Token.RightParen: return; default: goto UnexpectedError; } } } else { goto UnexpectedError; } UnexpectedError: OnUnexpectedError(); } private void ParseAttlistDefault( SchemaAttDef attrDef, bool ignoreErrors ) { switch ( GetToken( true ) ) { case Token.REQUIRED: attrDef.Presence = SchemaDeclBase.Use.Required; return; case Token.IMPLIED: attrDef.Presence = SchemaDeclBase.Use.Implied; return; case Token.FIXED: attrDef.Presence = SchemaDeclBase.Use.Fixed; if ( GetToken( true ) != Token.Literal ) { goto UnexpectedError; } break; case Token.Literal: break; default: goto UnexpectedError; } #if !SILVERLIGHT if ( validate && attrDef.Datatype.TokenizedType == XmlTokenizedType.ID&& !ignoreErrors ) { SendValidationEvent( curPos, XmlSeverityType.Error, Res.Sch_AttListPresence, string.Empty ); } #endif if ( attrDef.TokenizedType != XmlTokenizedType.CDATA ) { // non-CDATA attribute type normalization - strip spaces attrDef.DefaultValueExpanded = GetValueWithStrippedSpaces(); } else { attrDef.DefaultValueExpanded = GetValue(); } attrDef.ValueLineNumber = (int)literalLineInfo.lineNo; attrDef.ValueLinePosition = (int)literalLineInfo.linePos + 1; #if !SILVERLIGHT DtdValidator.SetDefaultTypedValue( attrDef, readerAdapter ); #endif return; UnexpectedError: OnUnexpectedError(); } private void ParseElementDecl() { // element name if ( GetToken( true ) != Token.QName ) { goto UnexpectedError; } // get schema decl for element SchemaElementDecl elementDecl = null; XmlQualifiedName name = GetNameQualified( true ); if (schemaInfo.ElementDecls.TryGetValue(name, out elementDecl)) { #if !SILVERLIGHT if ( validate ) { SendValidationEvent( curPos - name.Name.Length, XmlSeverityType.Error, Res.Sch_DupElementDecl, GetNameString() ); } #endif } else { if ( schemaInfo.UndeclaredElementDecls.TryGetValue(name, out elementDecl ) ) { schemaInfo.UndeclaredElementDecls.Remove( name ); } else { elementDecl = new SchemaElementDecl( name, name.Namespace ); } schemaInfo.ElementDecls.Add( name, elementDecl ); } elementDecl.IsDeclaredInExternal = !ParsingInternalSubset; // content spec #if SILVERLIGHT switch ( GetToken( true ) ) { case Token.EMPTY: case Token.ANY: break; case Token.LeftParen: switch ( GetToken( false ) ) { case Token.PCDATA: ParseElementMixedContentNoValidation(); break; case Token.None: ParseElementOnlyContentNoValidation(); break; default: goto UnexpectedError; } break; default: goto UnexpectedError; } #else switch ( GetToken( true ) ) { case Token.EMPTY: elementDecl.ContentValidator = ContentValidator.Empty; break; case Token.ANY: elementDecl.ContentValidator = ContentValidator.Any; break; case Token.LeftParen: int startParenEntityId = currentEntityId; switch ( GetToken( false ) ) { case Token.PCDATA: { ParticleContentValidator pcv = new ParticleContentValidator( XmlSchemaContentType.Mixed ); pcv.Start(); pcv.OpenGroup(); ParseElementMixedContent( pcv, startParenEntityId ); elementDecl.ContentValidator = pcv.Finish( true ); break; } case Token.None: { ParticleContentValidator pcv = null; pcv = new ParticleContentValidator( XmlSchemaContentType.ElementOnly ); pcv.Start(); pcv.OpenGroup(); ParseElementOnlyContent( pcv, startParenEntityId ); elementDecl.ContentValidator = pcv.Finish( true ); break; } default: goto UnexpectedError; } break; default: goto UnexpectedError; } #endif if ( GetToken( false ) != Token.GreaterThan ) { ThrowUnexpectedToken( curPos, ">" ); } return; UnexpectedError: OnUnexpectedError(); } #if SILVERLIGHT // Element content model parsing methods without validation private class ParseElementOnlyContentNoValidation_LocalFrame { public ParseElementOnlyContentNoValidation_LocalFrame() { parsingSchema = Token.None; } public Token parsingSchema; } private void ParseElementOnlyContentNoValidation() { Stack localFrames = new Stack (); ParseElementOnlyContentNoValidation_LocalFrame currentFrame = new ParseElementOnlyContentNoValidation_LocalFrame(); localFrames.Push(currentFrame); RecursiveCall: Loop: switch ( GetToken( false ) ) { case Token.QName: GetNameQualified(true); ParseHowManyNoValidation(); break; case Token.LeftParen: // We could just do this: // ParseElementOnlyContentNoValidation(); // // But that would be a recursion - so we will simulate the call using our localFrames stack // instead. currentFrame = new ParseElementOnlyContentNoValidation_LocalFrame(); localFrames.Push(currentFrame); goto RecursiveCall; // And we should return here when we return from the recursion // but it's the samea s returning after the switch statement case Token.GreaterThan: Throw( curPos, Res.Xml_InvalidContentModel ); goto Return; default: goto UnexpectedError; } ReturnFromRecursiveCall: switch ( GetToken( false ) ) { case Token.Comma: if ( currentFrame.parsingSchema == Token.Or ) { Throw( curPos, Res.Xml_InvalidContentModel ); } currentFrame.parsingSchema = Token.Comma; break; case Token.Or: if ( currentFrame.parsingSchema == Token.Comma ) { Throw( curPos, Res.Xml_InvalidContentModel ); } currentFrame.parsingSchema = Token.Or; break; case Token.RightParen: ParseHowManyNoValidation(); goto Return; case Token.GreaterThan: Throw( curPos, Res.Xml_InvalidContentModel ); goto Return; default: goto UnexpectedError; } goto Loop; UnexpectedError: OnUnexpectedError(); Return: // This is equivalent to return; statement // we simulate it using our localFrames stack localFrames.Pop(); if (localFrames.Count > 0) { currentFrame = localFrames.Peek(); goto ReturnFromRecursiveCall; } else { return; } } private void ParseHowManyNoValidation() { GetToken( false ); } private void ParseElementMixedContentNoValidation() { bool hasNames = false; for (;;) { switch ( GetToken( false ) ) { case Token.RightParen: if ( GetToken( false ) != Token.Star && hasNames ) { ThrowUnexpectedToken( curPos, "*" ); } return; case Token.Or: if ( !hasNames ) { hasNames = true; } if ( GetToken( false ) != Token.QName ) { goto default; } GetNameQualified( true ); continue; default: OnUnexpectedError(); break; } } } #else // Element content model parsing methods with validation support private class ParseElementOnlyContent_LocalFrame { public ParseElementOnlyContent_LocalFrame(int startParentEntityIdParam) { startParenEntityId = startParentEntityIdParam; parsingSchema = Token.None; } // pcv doesn't need to be stored for each frame as it never changes public int startParenEntityId; public Token parsingSchema; } private void ParseElementOnlyContent( ParticleContentValidator pcv, int startParenEntityId ) { Stack localFrames = new Stack (); ParseElementOnlyContent_LocalFrame currentFrame = new ParseElementOnlyContent_LocalFrame(startParenEntityId); localFrames.Push(currentFrame); RecursiveCall: Loop: switch ( GetToken( false ) ) { case Token.QName: pcv.AddName( GetNameQualified(true), null ); ParseHowMany( pcv ); break; case Token.LeftParen: pcv.OpenGroup(); // We could just do this: // ParseElementOnlyContent( pcv, currentEntityId ); // // But that would be recursion - so we will simulate the call using our localFrames stack // instead. currentFrame = new ParseElementOnlyContent_LocalFrame(currentEntityId); localFrames.Push(currentFrame); goto RecursiveCall; // And we should return here when we return from recursion call // but it's the same as returning after the switch statement case Token.GreaterThan: Throw( curPos, Res.Xml_InvalidContentModel ); goto Return; default: goto UnexpectedError; } ReturnFromRecursiveCall: switch ( GetToken( false ) ) { case Token.Comma: if ( currentFrame.parsingSchema == Token.Or ) { Throw( curPos, Res.Xml_InvalidContentModel ); } pcv.AddSequence(); currentFrame.parsingSchema = Token.Comma; break; case Token.Or: if (currentFrame.parsingSchema == Token.Comma) { Throw( curPos, Res.Xml_InvalidContentModel ); } pcv.AddChoice(); currentFrame.parsingSchema = Token.Or; break; case Token.RightParen: pcv.CloseGroup(); if (validate && currentEntityId != currentFrame.startParenEntityId) { SendValidationEvent( curPos, XmlSeverityType.Error, Res.Sch_ParEntityRefNesting, string.Empty ); } ParseHowMany( pcv ); goto Return; case Token.GreaterThan: Throw( curPos, Res.Xml_InvalidContentModel ); goto Return; default: goto UnexpectedError; } goto Loop; UnexpectedError: OnUnexpectedError(); Return: // This is equivalent to return; statement // we simlate it using our localFrames stack localFrames.Pop(); if (localFrames.Count > 0) { currentFrame = (ParseElementOnlyContent_LocalFrame)localFrames.Peek(); goto ReturnFromRecursiveCall; } else { return; } } private void ParseHowMany( ParticleContentValidator pcv ) { switch ( GetToken( false ) ) { case Token.Star: pcv.AddStar(); return; case Token.QMark: pcv.AddQMark(); return; case Token.Plus: pcv.AddPlus(); return; default: return; } } private void ParseElementMixedContent( ParticleContentValidator pcv, int startParenEntityId ) { bool hasNames = false; int connectorEntityId = -1; int contentEntityId = currentEntityId; for (;;) { switch ( GetToken( false ) ) { case Token.RightParen: pcv.CloseGroup(); if ( validate && currentEntityId != startParenEntityId ) { SendValidationEvent( curPos, XmlSeverityType.Error, Res.Sch_ParEntityRefNesting, string.Empty ); } if ( GetToken( false ) == Token.Star && hasNames ) { pcv.AddStar(); } else if ( hasNames ) { ThrowUnexpectedToken( curPos, "*" ); } return; case Token.Or: if ( !hasNames ) { hasNames = true; } else { pcv.AddChoice(); } if ( validate ) { connectorEntityId = currentEntityId; if ( contentEntityId < connectorEntityId ) { // entity repl.text starting with connector SendValidationEvent( curPos, XmlSeverityType.Error, Res.Sch_ParEntityRefNesting, string.Empty ); } } if ( GetToken( false ) != Token.QName ) { goto default; } XmlQualifiedName name = GetNameQualified( true ); if ( pcv.Exists( name ) && validate ) { SendValidationEvent( XmlSeverityType.Error, Res.Sch_DupElement, name.ToString() ); } pcv.AddName( name, null ); if ( validate ) { contentEntityId = currentEntityId; if ( contentEntityId < connectorEntityId ) { // entity repl.text ending with connector SendValidationEvent( curPos, XmlSeverityType.Error, Res.Sch_ParEntityRefNesting, string.Empty ); } } continue; default: OnUnexpectedError(); break; } } } #endif // Element content model parsing methods with validation support private void ParseEntityDecl() { bool isParamEntity = false; SchemaEntity entity = null; // get entity name and type switch ( GetToken( true ) ) { case Token.Percent: isParamEntity = true; if ( GetToken( true ) != Token.Name ) { goto UnexpectedError; } goto case Token.Name; case Token.Name: // create entity object XmlQualifiedName entityName = GetNameQualified( false ); entity = new SchemaEntity( entityName, isParamEntity ); entity.BaseURI = BaseUriStr; entity.DeclaredURI = ( externalDtdBaseUri.Length == 0 ) ? documentBaseUri : externalDtdBaseUri; if ( isParamEntity ) { if ( !schemaInfo.ParameterEntities.ContainsKey( entityName ) ) { schemaInfo.ParameterEntities.Add( entityName, entity ); } } else { if ( !schemaInfo.GeneralEntities.ContainsKey( entityName ) ) { schemaInfo.GeneralEntities.Add( entityName, entity ); } } entity.DeclaredInExternal = !ParsingInternalSubset; entity.ParsingInProgress = true; break; default: goto UnexpectedError; } Token token = GetToken( true ); switch ( token ) { case Token.PUBLIC: case Token.SYSTEM: string systemId; string publicId; ParseExternalId( token, Token.EntityDecl, out publicId, out systemId ); entity.IsExternal = true; entity.Url = systemId; entity.Pubid = publicId; if ( GetToken( false ) == Token.NData ) { if ( isParamEntity ) { ThrowUnexpectedToken( curPos - 5, ">" ); // 5 == strlen("NDATA") } if ( !whitespaceSeen ) { Throw( curPos - 5, Res.Xml_ExpectingWhiteSpace, "NDATA" ); } if ( GetToken( true ) != Token.Name ) { goto UnexpectedError; } entity.NData = GetNameQualified( false ); #if !SILVERLIGHT string notationName = entity.NData.Name; if ( !schemaInfo.Notations.ContainsKey(notationName) ) { AddUndeclaredNotation(notationName); } #endif } break; case Token.Literal: entity.Text = GetValue(); entity.Line = (int)literalLineInfo.lineNo; entity.Pos = (int)literalLineInfo.linePos; break; default: goto UnexpectedError; } if ( GetToken( false ) == Token.GreaterThan ) { entity.ParsingInProgress = false; return; } UnexpectedError: OnUnexpectedError(); } private void ParseNotationDecl() { // notation name if ( GetToken( true ) != Token.Name ) { OnUnexpectedError(); } XmlQualifiedName notationName = GetNameQualified( false ); #if !SILVERLIGHT SchemaNotation notation = null; if ( !schemaInfo.Notations.ContainsKey( notationName.Name ) ) { if ( undeclaredNotations != null ) { undeclaredNotations.Remove( notationName.Name ); } notation = new SchemaNotation( notationName ); schemaInfo.Notations.Add(notation.Name.Name, notation); } else { // duplicate notation if ( validate ) { SendValidationEvent( curPos - notationName.Name.Length, XmlSeverityType.Error, Res.Sch_DupNotation, notationName.Name ); } } #endif // public / system id Token token = GetToken( true ); if ( token == Token.SYSTEM || token == Token.PUBLIC ) { string notationPublicId, notationSystemId; ParseExternalId( token, Token.NOTATION, out notationPublicId, out notationSystemId ); #if !SILVERLIGHT if ( notation != null ) { notation.SystemLiteral = notationSystemId; notation.Pubid = notationPublicId; } #endif } else { OnUnexpectedError(); } if ( GetToken( false ) != Token.GreaterThan ) OnUnexpectedError(); } #if !SILVERLIGHT private void AddUndeclaredNotation(string notationName) { if (undeclaredNotations == null) { undeclaredNotations = new Dictionary (); } UndeclaredNotation un = new UndeclaredNotation(notationName, LineNo, LinePos - notationName.Length); UndeclaredNotation loggedUn; if (undeclaredNotations.TryGetValue(notationName, out loggedUn)) { un.next = loggedUn.next; loggedUn.next = un; } else { undeclaredNotations.Add(notationName, un); } } #endif private void ParseComment() { SaveParsingBuffer(); #if !SILVERLIGHT try { #endif if ( SaveInternalSubsetValue ) { readerAdapter.ParseComment( internalSubsetValueSb ); internalSubsetValueSb.Append( "-->" ); } else { readerAdapter.ParseComment( null ); } #if !SILVERLIGHT } catch (XmlException e) { if ( e.ResString == Res.Xml_UnexpectedEOF && currentEntityId != 0 ) { SendValidationEvent( XmlSeverityType.Error, Res.Sch_ParEntityRefNesting, null ); } else { throw; } } #endif LoadParsingBuffer(); } private void ParsePI() { SaveParsingBuffer(); if ( SaveInternalSubsetValue ) { readerAdapter.ParsePI( internalSubsetValueSb ); internalSubsetValueSb.Append( "?>" ); } else { readerAdapter.ParsePI( null ); } LoadParsingBuffer(); } private void ParseCondSection() { int csEntityId = currentEntityId; switch ( GetToken( false ) ) { case Token.INCLUDE: if ( GetToken( false ) != Token.LeftBracket ) { goto default; } #if !SILVERLIGHT if ( validate && csEntityId != currentEntityId ) { SendValidationEvent( curPos, XmlSeverityType.Error, Res.Sch_ParEntityRefNesting, string.Empty ); } if ( validate ) { if ( condSectionEntityIds == null ) { condSectionEntityIds = new int[CondSectionEntityIdsInitialSize]; } else if ( condSectionEntityIds.Length == condSectionDepth ) { int[] tmp = new int[condSectionEntityIds.Length*2]; Array.Copy( condSectionEntityIds, 0, tmp, 0, condSectionEntityIds.Length ); condSectionEntityIds = tmp; } condSectionEntityIds[condSectionDepth] = csEntityId; } #endif condSectionDepth++; break; case Token.IGNORE: if ( GetToken( false ) != Token.LeftBracket ) { goto default; } #if !SILVERLIGHT if ( validate && csEntityId != currentEntityId ) { SendValidationEvent( curPos, XmlSeverityType.Error, Res.Sch_ParEntityRefNesting, string.Empty ); } #endif // the content of the ignore section is parsed & skipped by scanning function if ( GetToken( false ) != Token.CondSectionEnd ) { goto default; } #if !SILVERLIGHT if ( validate && csEntityId != currentEntityId ) { SendValidationEvent( curPos, XmlSeverityType.Error, Res.Sch_ParEntityRefNesting, string.Empty ); } #endif break; default: OnUnexpectedError(); break; } } private void ParseExternalId( Token idTokenType, Token declType, out string publicId, out string systemId ) { LineInfo keywordLineInfo = new LineInfo( LineNo, LinePos - 6 ); publicId = null; systemId = null; if ( GetToken( true ) != Token.Literal ) { ThrowUnexpectedToken( curPos, "\"", "'" ); } if ( idTokenType == Token.SYSTEM ) { systemId = GetValue(); if ( systemId.IndexOf( '#' ) >= 0 ) { Throw( curPos - systemId.Length - 1, Res.Xml_FragmentId, new string[] { systemId.Substring( systemId.IndexOf( '#' ) ), systemId } ); } if ( declType == Token.DOCTYPE && !freeFloatingDtd ) { literalLineInfo.linePos++; readerAdapter.OnSystemId( systemId, keywordLineInfo, literalLineInfo ); } } else { Debug.Assert( idTokenType == Token.PUBLIC ); publicId = GetValue(); // verify if it contains chars valid for public ids int i; if ( ( i = xmlCharType.IsPublicId( publicId ) ) >= 0 ) { ThrowInvalidChar( curPos - 1 - publicId.Length + i, publicId, i ); } if ( declType == Token.DOCTYPE && !freeFloatingDtd ) { literalLineInfo.linePos++; readerAdapter.OnPublicId( publicId, keywordLineInfo, literalLineInfo ); if ( GetToken( false ) == Token.Literal ) { if ( !whitespaceSeen ) { Throw( Res.Xml_ExpectingWhiteSpace, new string( literalQuoteChar, 1 ), (int)literalLineInfo.lineNo, (int)literalLineInfo.linePos ); } systemId = GetValue(); literalLineInfo.linePos++; readerAdapter.OnSystemId( systemId, keywordLineInfo, literalLineInfo ); } else { ThrowUnexpectedToken( curPos, "\"", "'" ); } } else { if ( GetToken( false ) == Token.Literal ) { if ( !whitespaceSeen ) { Throw( Res.Xml_ExpectingWhiteSpace, new string( literalQuoteChar, 1 ), (int)literalLineInfo.lineNo, (int)literalLineInfo.linePos ); } systemId = GetValue(); } else if ( declType != Token.NOTATION ) { ThrowUnexpectedToken( curPos, "\"", "'" ); } } } } // // Scanning methods - works directly with parsing buffer // private Token GetToken( bool needWhiteSpace ) { whitespaceSeen = false; for (;;) { switch ( chars[curPos] ) { case (char)0: if ( curPos == charsUsed ) { goto ReadData; } else { ThrowInvalidChar( chars, charsUsed, curPos ); } break; case (char)0xA: whitespaceSeen = true; curPos++; readerAdapter.OnNewLine( curPos ); continue; case (char)0xD: whitespaceSeen = true; if ( chars[curPos+1] == (char)0xA ) { if ( Normalize ) { SaveParsingBuffer(); // EOL normalization of 0xD 0xA readerAdapter.CurrentPosition++; } curPos += 2; } else if ( curPos+1 < charsUsed || readerAdapter.IsEof ) { chars[curPos] = (char)0xA; // EOL normalization of 0xD curPos++; } else { goto ReadData; } readerAdapter.OnNewLine( curPos ); continue; case (char)0x9: case (char)0x20: whitespaceSeen = true; curPos++; continue; case '%': if ( charsUsed - curPos < 2 ) { goto ReadData; } if ( !xmlCharType.IsWhiteSpace( chars[curPos+1] ) ) { if ( IgnoreEntityReferences ) { curPos++; } else { HandleEntityReference( true, false, false ); } continue; } goto default; default: if ( needWhiteSpace && !whitespaceSeen && scanningFunction != ScanningFunction.ParamEntitySpace ) { Throw( curPos, Res.Xml_ExpectingWhiteSpace, ParseUnexpectedToken( curPos ) ); } tokenStartPos = curPos; SwitchAgain: switch ( scanningFunction ) { case ScanningFunction.Name: return ScanNameExpected(); case ScanningFunction.QName: return ScanQNameExpected(); case ScanningFunction.Nmtoken: return ScanNmtokenExpected(); case ScanningFunction.SubsetContent: return ScanSubsetContent(); case ScanningFunction.Doctype1: return ScanDoctype1(); case ScanningFunction.Doctype2: return ScanDoctype2(); case ScanningFunction.Element1: return ScanElement1(); case ScanningFunction.Element2: return ScanElement2(); case ScanningFunction.Element3: return ScanElement3(); case ScanningFunction.Element4: return ScanElement4(); case ScanningFunction.Element5: return ScanElement5(); case ScanningFunction.Element6: return ScanElement6(); case ScanningFunction.Element7: return ScanElement7(); case ScanningFunction.Attlist1: return ScanAttlist1(); case ScanningFunction.Attlist2: return ScanAttlist2(); case ScanningFunction.Attlist3: return ScanAttlist3(); case ScanningFunction.Attlist4: return ScanAttlist4(); case ScanningFunction.Attlist5: return ScanAttlist5(); case ScanningFunction.Attlist6: return ScanAttlist6(); case ScanningFunction.Attlist7: return ScanAttlist7(); case ScanningFunction.Notation1: return ScanNotation1(); case ScanningFunction.SystemId: return ScanSystemId(); case ScanningFunction.PublicId1: return ScanPublicId1(); case ScanningFunction.PublicId2: return ScanPublicId2(); case ScanningFunction.Entity1: return ScanEntity1(); case ScanningFunction.Entity2: return ScanEntity2(); case ScanningFunction.Entity3: return ScanEntity3(); case ScanningFunction.CondSection1: return ScanCondSection1(); case ScanningFunction.CondSection2: return ScanCondSection2(); case ScanningFunction.CondSection3: return ScanCondSection3(); case ScanningFunction.ClosingTag: return ScanClosingTag(); case ScanningFunction.ParamEntitySpace: whitespaceSeen = true; scanningFunction = savedScanningFunction; goto SwitchAgain; default: Debug.Assert( false ); return Token.None; } } ReadData: if ( readerAdapter.IsEof || ReadData() == 0 ) { if ( HandleEntityEnd( false ) ) { continue; } if ( scanningFunction == ScanningFunction.SubsetContent ) { return Token.Eof; } else { Throw( curPos, Res.Xml_IncompleteDtdContent ); } } } } private Token ScanSubsetContent() { for (;;) { switch ( chars[curPos] ) { case '<': switch ( chars[curPos+1] ) { case '!': switch ( chars[curPos+2] ) { case 'E': if ( chars[curPos+3] == 'L' ) { if ( charsUsed - curPos < 9 ) { goto ReadData; } if ( chars[curPos+4] != 'E' || chars[curPos+5] != 'M' || chars[curPos+6] != 'E' || chars[curPos+7] != 'N' || chars[curPos+8] != 'T' ) { Throw( curPos, Res.Xml_ExpectDtdMarkup ); } curPos += 9; scanningFunction = ScanningFunction.QName; nextScaningFunction = ScanningFunction.Element1; return Token.ElementDecl; } else if ( chars[curPos+3] == 'N' ) { if ( charsUsed - curPos < 8 ) { goto ReadData; } if ( chars[curPos+4] != 'T' || chars[curPos+5] != 'I' || chars[curPos+6] != 'T' || chars[curPos+7] != 'Y' ) { Throw( curPos, Res.Xml_ExpectDtdMarkup ); } curPos += 8; scanningFunction = ScanningFunction.Entity1; return Token.EntityDecl; } else { if ( charsUsed - curPos < 4 ) { goto ReadData; } Throw( curPos, Res.Xml_ExpectDtdMarkup ); return Token.None; } case 'A': if ( charsUsed - curPos < 9 ) { goto ReadData; } 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' ) { Throw( curPos, Res.Xml_ExpectDtdMarkup ); } curPos += 9; scanningFunction = ScanningFunction.QName; nextScaningFunction = ScanningFunction.Attlist1; return Token.AttlistDecl; case 'N': if ( charsUsed - curPos < 10 ) { goto ReadData; } 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' ) { Throw( curPos, Res.Xml_ExpectDtdMarkup ); } curPos += 10; scanningFunction = ScanningFunction.Name; nextScaningFunction = ScanningFunction.Notation1; return Token.NotationDecl; case '[': curPos += 3; scanningFunction = ScanningFunction.CondSection1; return Token.CondSectionStart; case '-': if ( chars[curPos+3] == '-' ) { curPos += 4; return Token.Comment; } else { if ( charsUsed - curPos < 4 ) { goto ReadData; } Throw( curPos, Res.Xml_ExpectDtdMarkup ); break; } default: if ( charsUsed - curPos < 3 ) { goto ReadData; } Throw( curPos + 2, Res.Xml_ExpectDtdMarkup ); break; } break; case '?': curPos += 2; return Token.PI; default: if ( charsUsed - curPos < 2 ) { goto ReadData; } Throw( curPos, Res.Xml_ExpectDtdMarkup ); return Token.None; } break; case ']': if ( charsUsed - curPos < 2 && !readerAdapter.IsEof ) { goto ReadData; } if ( chars[curPos+1] != ']' ) { curPos++; scanningFunction = ScanningFunction.ClosingTag; return Token.RightBracket; } if ( charsUsed - curPos < 3 && !readerAdapter.IsEof ) { goto ReadData; } if ( chars[curPos+1] == ']' && chars[curPos+2] == '>' ) { curPos += 3; return Token.CondSectionEnd; } goto default; default: if ( charsUsed - curPos == 0 ) { goto ReadData; } Throw( curPos, Res.Xml_ExpectDtdMarkup ); break; } ReadData: if ( ReadData() == 0 ) { Throw( charsUsed, Res.Xml_IncompleteDtdContent ); } } } private Token ScanNameExpected() { ScanName(); scanningFunction = nextScaningFunction; return Token.Name; } private Token ScanQNameExpected() { ScanQName(); scanningFunction = nextScaningFunction; return Token.QName; } private Token ScanNmtokenExpected() { ScanNmtoken(); scanningFunction = nextScaningFunction; return Token.Nmtoken; } private Token ScanDoctype1() { switch ( chars[curPos] ) { case 'P': if ( !EatPublicKeyword() ) { Throw( curPos, Res.Xml_ExpectExternalOrClose ); } nextScaningFunction = ScanningFunction.Doctype2; scanningFunction = ScanningFunction.PublicId1; return Token.PUBLIC; case 'S': if ( !EatSystemKeyword() ) { Throw( curPos, Res.Xml_ExpectExternalOrClose ); } nextScaningFunction = ScanningFunction.Doctype2; scanningFunction = ScanningFunction.SystemId; return Token.SYSTEM; case '[': curPos++; scanningFunction = ScanningFunction.SubsetContent; return Token.LeftBracket; case '>': curPos++; scanningFunction = ScanningFunction.SubsetContent; return Token.GreaterThan; default: Throw( curPos, Res.Xml_ExpectExternalOrClose ); return Token.None; } } private Token ScanDoctype2() { switch ( chars[curPos] ) { case '[': curPos++; scanningFunction = ScanningFunction.SubsetContent; return Token.LeftBracket; case '>': curPos++; scanningFunction = ScanningFunction.SubsetContent; return Token.GreaterThan; default: Throw( curPos, Res.Xml_ExpectSubOrClose ); return Token.None; } } private Token ScanClosingTag() { if ( chars[curPos] != '>' ) { ThrowUnexpectedToken( curPos, ">" ); } curPos++; scanningFunction = ScanningFunction.SubsetContent; return Token.GreaterThan; } private Token ScanElement1() { for (;;) { switch ( chars[curPos] ) { case '(': scanningFunction = ScanningFunction.Element2; curPos++; return Token.LeftParen; case 'E': if ( charsUsed - curPos < 5 ) { goto ReadData; } if ( chars[curPos+1] == 'M' && chars[curPos+2] == 'P' && chars[curPos+3] == 'T' && chars[curPos+4] == 'Y' ) { curPos += 5; scanningFunction = ScanningFunction.ClosingTag; return Token.EMPTY; } goto default; case 'A': if ( charsUsed - curPos < 3 ) { goto ReadData; } if ( chars[curPos+1] == 'N' && chars[curPos+2] == 'Y' ) { curPos += 3; scanningFunction = ScanningFunction.ClosingTag; return Token.ANY; } goto default; default: Throw( curPos, Res.Xml_InvalidContentModel ); break; } ReadData: if ( ReadData() == 0 ) { Throw( curPos, Res.Xml_IncompleteDtdContent ); } } } private Token ScanElement2() { if ( chars[curPos] == '#' ) { while ( charsUsed - curPos < 7 ) { if ( ReadData() == 0 ) { Throw( curPos, Res.Xml_IncompleteDtdContent ); } } 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' ) { curPos += 7; scanningFunction = ScanningFunction.Element6; return Token.PCDATA; } else { Throw( curPos + 1, Res.Xml_ExpectPcData ); } } scanningFunction = ScanningFunction.Element3; return Token.None; } private Token ScanElement3() { switch ( chars[curPos] ) { case '(': curPos++; return Token.LeftParen; case '>': curPos++; scanningFunction = ScanningFunction.SubsetContent; return Token.GreaterThan; default: ScanQName(); scanningFunction = ScanningFunction.Element4; return Token.QName; } } private Token ScanElement4() { scanningFunction = ScanningFunction.Element5; Token t; switch ( chars[curPos] ) { case '*': t = Token.Star; break; case '?': t = Token.QMark; break; case '+': t = Token.Plus; break; default: return Token.None; } if ( whitespaceSeen ) { Throw( curPos, Res.Xml_ExpectNoWhitespace ); } curPos++; return t; } private Token ScanElement5() { switch ( chars[curPos] ) { case ',': curPos++; scanningFunction = ScanningFunction.Element3; return Token.Comma; case '|': curPos++; scanningFunction = ScanningFunction.Element3; return Token.Or; case ')': curPos++; scanningFunction = ScanningFunction.Element4; return Token.RightParen; case '>': curPos++; scanningFunction = ScanningFunction.SubsetContent; return Token.GreaterThan; default: Throw( curPos, Res.Xml_ExpectOp ); return Token.None; } } private Token ScanElement6() { switch ( chars[curPos] ) { case ')': curPos++; scanningFunction = ScanningFunction.Element7; return Token.RightParen; case '|': curPos++; nextScaningFunction = ScanningFunction.Element6; scanningFunction = ScanningFunction.QName; return Token.Or; default: ThrowUnexpectedToken( curPos, ")", "|" ); return Token.None; } } private Token ScanElement7() { scanningFunction = ScanningFunction.ClosingTag; if ( chars[curPos] == '*' && !whitespaceSeen ) { curPos++; return Token.Star; } return Token.None; } private Token ScanAttlist1() { switch ( chars[curPos] ) { case '>': curPos++; scanningFunction = ScanningFunction.SubsetContent; return Token.GreaterThan; default: if ( !whitespaceSeen ) { Throw( curPos, Res.Xml_ExpectingWhiteSpace, ParseUnexpectedToken( curPos ) ); } ScanQName(); scanningFunction = ScanningFunction.Attlist2; return Token.QName; } } private Token ScanAttlist2() { for (;;) { switch ( chars[curPos] ) { case '(': curPos++; scanningFunction = ScanningFunction.Nmtoken; nextScaningFunction = ScanningFunction.Attlist5; return Token.LeftParen; case 'C': if ( charsUsed - curPos < 5 ) goto ReadData; if ( chars[curPos+1] != 'D' || chars[curPos+2] != 'A' || chars[curPos+3] != 'T' || chars[curPos+4] != 'A' ) { Throw( curPos, Res.Xml_InvalidAttributeType1 ); } curPos += 5; scanningFunction = ScanningFunction.Attlist6; return Token.CDATA; case 'E': if ( charsUsed - curPos < 9 ) goto ReadData; scanningFunction = ScanningFunction.Attlist6; if ( chars[curPos+1] != 'N' || chars[curPos+2] != 'T' || chars[curPos+3] != 'I' || chars[curPos+4] != 'T' ) { Throw( curPos, Res.Xml_InvalidAttributeType ); } switch ( chars[curPos+5] ) { case 'I': if ( chars[curPos+6] != 'E' || chars[curPos+7] != 'S' ) { Throw( curPos, Res.Xml_InvalidAttributeType ); } curPos += 8; return Token.ENTITIES; case 'Y': curPos += 6; return Token.ENTITY; default: Throw( curPos, Res.Xml_InvalidAttributeType ); break; } break; case 'I': if ( charsUsed - curPos < 6 ) goto ReadData; scanningFunction = ScanningFunction.Attlist6; if ( chars[curPos+1] != 'D' ) { Throw( curPos, Res.Xml_InvalidAttributeType ); } if ( chars[curPos+2] != 'R' ) { curPos += 2; return Token.ID; } if ( chars[curPos+3] != 'E' || chars[curPos+4] != 'F' ) { Throw( curPos, Res.Xml_InvalidAttributeType ); } if ( chars[curPos+5] != 'S' ) { curPos += 5; return Token.IDREF; } else { curPos += 6; return Token.IDREFS; } case 'N': if ( charsUsed - curPos < 8 && !readerAdapter.IsEof ) { goto ReadData; } switch ( chars[curPos+1] ) { case 'O': 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' ) { Throw( curPos, Res.Xml_InvalidAttributeType ); } curPos += 8; scanningFunction = ScanningFunction.Attlist3; return Token.NOTATION; case 'M': if ( chars[curPos+2] != 'T' || chars[curPos+3] != 'O' || chars[curPos+4] != 'K' || chars[curPos+5] != 'E' || chars[curPos+6] != 'N' ) { Throw( curPos, Res.Xml_InvalidAttributeType ); } scanningFunction = ScanningFunction.Attlist6; if ( chars[curPos+7] == 'S' ) { curPos += 8; return Token.NMTOKENS; } else { curPos += 7; return Token.NMTOKEN; } default: Throw( curPos, Res.Xml_InvalidAttributeType ); break; } break; default: Throw( curPos, Res.Xml_InvalidAttributeType ); break; } ReadData: if ( ReadData() == 0 ) { Throw( curPos, Res.Xml_IncompleteDtdContent ); } } } private Token ScanAttlist3() { if ( chars[curPos] == '(' ) { curPos++; scanningFunction = ScanningFunction.Name; nextScaningFunction = ScanningFunction.Attlist4; return Token.LeftParen; } else { ThrowUnexpectedToken( curPos, "(" ); return Token.None; } } private Token ScanAttlist4() { switch ( chars[curPos] ) { case ')': curPos++; scanningFunction = ScanningFunction.Attlist6; return Token.RightParen; case '|': curPos++; scanningFunction = ScanningFunction.Name; nextScaningFunction = ScanningFunction.Attlist4; return Token.Or; default: ThrowUnexpectedToken( curPos, ")", "|" ); return Token.None; } } private Token ScanAttlist5() { switch ( chars[curPos] ) { case ')': curPos++; scanningFunction = ScanningFunction.Attlist6; return Token.RightParen; case '|': curPos++; scanningFunction = ScanningFunction.Nmtoken; nextScaningFunction = ScanningFunction.Attlist5; return Token.Or; default: ThrowUnexpectedToken( curPos, ")", "|" ); return Token.None; } } private Token ScanAttlist6() { for (;;) { switch ( chars[curPos] ) { case '"': case '\'': ScanLiteral( LiteralType.AttributeValue ); scanningFunction = ScanningFunction.Attlist1; return Token.Literal; case '#': if ( charsUsed - curPos < 6 ) goto ReadData; switch ( chars[curPos+1] ) { case 'R': if ( charsUsed - curPos < 9 ) goto ReadData; 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' ) { Throw( curPos, Res.Xml_ExpectAttType ); } curPos += 9; scanningFunction = ScanningFunction.Attlist1; return Token.REQUIRED; case 'I': if ( charsUsed - curPos < 8 ) goto ReadData; 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' ) { Throw( curPos, Res.Xml_ExpectAttType ); } curPos += 8; scanningFunction = ScanningFunction.Attlist1; return Token.IMPLIED; case 'F': if ( chars[curPos+2] != 'I' || chars[curPos+3] != 'X' || chars[curPos+4] != 'E' || chars[curPos+5] != 'D' ) { Throw( curPos, Res.Xml_ExpectAttType ); } curPos += 6; scanningFunction = ScanningFunction.Attlist7; return Token.FIXED; default: Throw( curPos, Res.Xml_ExpectAttType ); break; } break; default: Throw( curPos, Res.Xml_ExpectAttType ); break; } ReadData: if ( ReadData() == 0 ) { Throw( curPos, Res.Xml_IncompleteDtdContent ); } } } private Token ScanAttlist7() { switch ( chars[curPos] ) { case '"': case '\'': ScanLiteral( LiteralType.AttributeValue ); scanningFunction = ScanningFunction.Attlist1; return Token.Literal; default: ThrowUnexpectedToken( curPos, "\"", "'" ); return Token.None; } } private Token ScanLiteral( LiteralType literalType ) { Debug.Assert( chars[curPos] == '"' || chars[curPos] == '\'' ); char quoteChar = chars[curPos]; char replaceChar = ( literalType == LiteralType.AttributeValue ) ? (char)0x20 : (char)0xA; int startQuoteEntityId = currentEntityId; literalLineInfo.Set( LineNo, LinePos ); curPos++; tokenStartPos = curPos; #if SILVERLIGHT stringBuilder.Clear(); #else stringBuilder.Length = 0; #endif for (;;) { #if SILVERLIGHT while ( xmlCharType.IsAttributeValueChar( chars[curPos] ) && chars[curPos] != '%' ) { curPos++; } #else unsafe { while ( ( xmlCharType.charProperties[chars[curPos]] & XmlCharType.fAttrValue ) != 0 && chars[curPos] != '%' ) { curPos++; } } #endif if ( chars[curPos] == quoteChar && currentEntityId == startQuoteEntityId ) { if ( stringBuilder.Length > 0 ) { stringBuilder.Append( chars, tokenStartPos, curPos - tokenStartPos ); } curPos++; literalQuoteChar = quoteChar; return Token.Literal; } int tmp1 = curPos - tokenStartPos; if ( tmp1 > 0 ) { stringBuilder.Append( chars, tokenStartPos, tmp1 ); tokenStartPos = curPos; } switch ( chars[curPos] ) { case '"': case '\'': case '>': curPos++; continue; // eol case (char)0xA: curPos++; if ( Normalize ) { stringBuilder.Append( replaceChar ); // For attributes: CDATA normalization of 0xA tokenStartPos = curPos; } readerAdapter.OnNewLine( curPos ); continue; case (char)0xD: if ( chars[curPos+1] == (char)0xA ) { if ( Normalize ) { if ( literalType == LiteralType.AttributeValue ) { stringBuilder.Append( readerAdapter.IsEntityEolNormalized ? "\u0020\u0020" : "\u0020" ); // CDATA normalization of 0xD 0xA } else { stringBuilder.Append( readerAdapter.IsEntityEolNormalized ? "\u000D\u000A" : "\u000A" ); // EOL normalization of 0xD 0xA } tokenStartPos = curPos + 2; SaveParsingBuffer(); // EOL normalization of 0xD 0xA in internal subset value readerAdapter.CurrentPosition++; } curPos += 2; } else if ( curPos+1 == charsUsed ) { goto ReadData; } else { curPos++; if ( Normalize ) { stringBuilder.Append( replaceChar ); // For attributes: CDATA normalization of 0xD and 0xD 0xA tokenStartPos = curPos; // For entities: EOL normalization of 0xD and 0xD 0xA } } readerAdapter.OnNewLine( curPos ); continue; // tab case (char)0x9: if ( literalType == LiteralType.AttributeValue && Normalize ) { stringBuilder.Append( (char)0x20 ); // For attributes: CDATA normalization of 0x9 tokenStartPos++; } curPos++; continue; // attribute values cannot contain '<' case '<': if ( literalType == LiteralType.AttributeValue ) { Throw( curPos, Res.Xml_BadAttributeChar, XmlException.BuildCharExceptionArgs( '<', '\0' ) ); } curPos++; continue; // parameter entity reference case '%': if ( literalType != LiteralType.EntityReplText ) { curPos++; continue; } HandleEntityReference( true, true, literalType == LiteralType.AttributeValue ); tokenStartPos = curPos; continue; // general entity reference case '&': if ( literalType == LiteralType.SystemOrPublicID ) { curPos++; continue; } if ( curPos + 1 == charsUsed ) { goto ReadData; } // numeric characters reference if ( chars[curPos + 1] == '#' ) { SaveParsingBuffer(); int endPos = readerAdapter.ParseNumericCharRef( SaveInternalSubsetValue ? internalSubsetValueSb : null ); LoadParsingBuffer(); stringBuilder.Append( chars, curPos, endPos - curPos ); readerAdapter.CurrentPosition = endPos; tokenStartPos = endPos; curPos = endPos; continue; } else { // general entity reference SaveParsingBuffer(); if ( literalType == LiteralType.AttributeValue ) { int endPos = readerAdapter.ParseNamedCharRef( true, SaveInternalSubsetValue ? internalSubsetValueSb : null ); LoadParsingBuffer(); if ( endPos >= 0 ) { stringBuilder.Append( chars, curPos, endPos - curPos ); readerAdapter.CurrentPosition = endPos; tokenStartPos = endPos; curPos = endPos; continue; } else { HandleEntityReference( false, true, true ); tokenStartPos = curPos; } continue; } else { int endPos = readerAdapter.ParseNamedCharRef( false, null ); LoadParsingBuffer(); if ( endPos >= 0 ) { tokenStartPos = curPos; curPos = endPos; continue; } else { stringBuilder.Append( '&' ); curPos++; tokenStartPos = curPos; // Bypass general entities in entity values XmlQualifiedName entityName = ScanEntityName(); VerifyEntityReference( entityName, false, false, false ); } continue; } } default: // end of buffer if ( curPos == charsUsed ) { goto ReadData; } // surrogate chars else { char ch = chars[curPos]; if ( XmlCharType.IsHighSurrogate(ch) ) { if ( curPos + 1 == charsUsed ) { goto ReadData; } curPos++; if ( XmlCharType.IsLowSurrogate(chars[curPos]) ) { curPos++; continue; } } ThrowInvalidChar( chars, charsUsed, curPos ); return Token.None; } } ReadData: Debug.Assert( curPos - tokenStartPos == 0 ); // read new characters into the buffer if ( readerAdapter.IsEof || ReadData() == 0 ) { if ( literalType == LiteralType.SystemOrPublicID || !HandleEntityEnd( true ) ) { Throw( curPos, Res.Xml_UnclosedQuote ); } } tokenStartPos = curPos; } } private XmlQualifiedName ScanEntityName() { try { ScanName(); } catch ( XmlException e ) { Throw( Res.Xml_ErrorParsingEntityName, string.Empty, e.LineNumber, e.LinePosition ); } if ( chars[curPos] != ';' ) { ThrowUnexpectedToken( curPos, ";" ); } XmlQualifiedName entityName = GetNameQualified( false ); curPos++; return entityName; } private Token ScanNotation1() { switch ( chars[curPos] ) { case 'P': if ( !EatPublicKeyword() ) { Throw( curPos, Res.Xml_ExpectExternalOrClose ); } nextScaningFunction = ScanningFunction.ClosingTag; scanningFunction = ScanningFunction.PublicId1; return Token.PUBLIC; case 'S': if ( !EatSystemKeyword() ) { Throw( curPos, Res.Xml_ExpectExternalOrClose ); } nextScaningFunction = ScanningFunction.ClosingTag; scanningFunction = ScanningFunction.SystemId; return Token.SYSTEM; default: Throw( curPos, Res.Xml_ExpectExternalOrPublicId ); return Token.None; } } private Token ScanSystemId() { if ( chars[curPos] != '"' && chars[curPos] != '\'' ) { ThrowUnexpectedToken( curPos, "\"", "'" ); } ScanLiteral( LiteralType.SystemOrPublicID ); scanningFunction = nextScaningFunction; return Token.Literal; } private Token ScanEntity1() { if ( chars[curPos] == '%' ) { curPos++; nextScaningFunction = ScanningFunction.Entity2; scanningFunction = ScanningFunction.Name; return Token.Percent; } else { ScanName(); scanningFunction = ScanningFunction.Entity2; return Token.Name; } } private Token ScanEntity2() { switch ( chars[curPos] ) { case 'P': if ( !EatPublicKeyword() ) { Throw( curPos, Res.Xml_ExpectExternalOrClose ); } nextScaningFunction = ScanningFunction.Entity3; scanningFunction = ScanningFunction.PublicId1; return Token.PUBLIC; case 'S': if ( !EatSystemKeyword() ) { Throw( curPos, Res.Xml_ExpectExternalOrClose ); } nextScaningFunction = ScanningFunction.Entity3; scanningFunction = ScanningFunction.SystemId; return Token.SYSTEM; case '"': case '\'': ScanLiteral( LiteralType.EntityReplText ); scanningFunction = ScanningFunction.ClosingTag; return Token.Literal; default: Throw( curPos, Res.Xml_ExpectExternalIdOrEntityValue ); return Token.None; } } private Token ScanEntity3() { if ( chars[curPos] == 'N' ) { while ( charsUsed - curPos < 5 ) { if ( ReadData() == 0 ) { goto End; } } if ( chars[curPos+1] == 'D' && chars[curPos+2] == 'A' && chars[curPos+3] == 'T' && chars[curPos+4] == 'A' ) { curPos += 5; scanningFunction = ScanningFunction.Name; nextScaningFunction = ScanningFunction.ClosingTag; return Token.NData; } } End: scanningFunction = ScanningFunction.ClosingTag; return Token.None; } private Token ScanPublicId1() { if ( chars[curPos] != '"' && chars[curPos] != '\'' ) { ThrowUnexpectedToken( curPos, "\"", "'" ); } ScanLiteral( LiteralType.SystemOrPublicID ); scanningFunction = ScanningFunction.PublicId2; return Token.Literal; } private Token ScanPublicId2() { if ( chars[curPos] != '"' && chars[curPos] != '\'' ) { scanningFunction = nextScaningFunction; return Token.None; } ScanLiteral( LiteralType.SystemOrPublicID ); scanningFunction = nextScaningFunction; return Token.Literal; } private Token ScanCondSection1() { if ( chars[curPos] != 'I' ) { Throw( curPos, Res.Xml_ExpectIgnoreOrInclude ); } curPos++; for (;;) { if ( charsUsed - curPos < 5 ) { goto ReadData; } switch ( chars[curPos] ) { case 'N': if ( charsUsed - curPos < 6 ) { goto ReadData; } if ( chars[curPos+1] != 'C' || chars[curPos+2] != 'L' || chars[curPos+3] != 'U' || chars[curPos+4] != 'D' || chars[curPos+5] != 'E' || xmlCharType.IsNameSingleChar( chars[curPos+6] ) #if XML10_FIFTH_EDITION || xmlCharType.IsNCNameHighSurrogateChar( chars[curPos+6] ) #endif ) { goto default; } nextScaningFunction = ScanningFunction.SubsetContent; scanningFunction = ScanningFunction.CondSection2; curPos += 6; return Token.INCLUDE; case 'G': if ( chars[curPos+1] != 'N' || chars[curPos+2] != 'O' || chars[curPos+3] != 'R' || chars[curPos+4] != 'E' || xmlCharType.IsNameSingleChar( chars[curPos + 5] ) #if XML10_FIFTH_EDITION ||xmlCharType.IsNCNameHighSurrogateChar( chars[curPos+5] ) #endif ) { goto default; } nextScaningFunction = ScanningFunction.CondSection3; scanningFunction = ScanningFunction.CondSection2; curPos += 5; return Token.IGNORE; default: Throw( curPos - 1, Res.Xml_ExpectIgnoreOrInclude ); return Token.None; } ReadData: if ( ReadData() == 0 ) { Throw( curPos, Res.Xml_IncompleteDtdContent ); } } } private Token ScanCondSection2() { if ( chars[curPos] != '[' ) { ThrowUnexpectedToken( curPos, "[" ); } curPos++; scanningFunction = nextScaningFunction; return Token.LeftBracket; } private Token ScanCondSection3() { int ignoreSectionDepth = 0; // skip ignored part for (;;) { #if SILVERLIGHT while ( xmlCharType.IsTextChar(chars[curPos]) && chars[curPos] != ']' ) { curPos++; } #else unsafe { while ( ( xmlCharType.charProperties[chars[curPos]] & XmlCharType.fText ) != 0 && chars[curPos] != ']' ) { curPos++; } } #endif switch ( chars[curPos] ) { case '"': case '\'': case (char)0x9: case '&': curPos++; continue; // eol case (char)0xA: curPos++; readerAdapter.OnNewLine( curPos ); continue; case (char)0xD: if ( chars[curPos+1] == (char)0xA ) { curPos += 2; } else if ( curPos+1 < charsUsed || readerAdapter.IsEof ) { curPos++; } else { goto ReadData; } readerAdapter.OnNewLine( curPos ); continue; case '<': if ( charsUsed - curPos < 3 ) { goto ReadData; } if ( chars[curPos+1] != '!' || chars[curPos+2] != '[' ) { curPos++; continue; } ignoreSectionDepth++; curPos += 3; continue; case ']': if ( charsUsed - curPos < 3 ) { goto ReadData; } if ( chars[curPos+1] != ']' || chars[curPos+2] != '>' ) { curPos++; continue; } if ( ignoreSectionDepth > 0 ) { ignoreSectionDepth--; curPos += 3; continue; } else { curPos += 3; scanningFunction = ScanningFunction.SubsetContent; return Token.CondSectionEnd; } default: // end of buffer if ( curPos == charsUsed ) { goto ReadData; } // surrogate chars else { char ch = chars[curPos]; if ( XmlCharType.IsHighSurrogate(ch) ) { if ( curPos + 1 == charsUsed ) { goto ReadData; } curPos++; if ( XmlCharType.IsLowSurrogate(chars[curPos])) { curPos++; continue; } } ThrowInvalidChar( chars, charsUsed, curPos ); return Token.None; } } ReadData: // read new characters into the buffer if ( readerAdapter.IsEof || ReadData() == 0 ) { if ( HandleEntityEnd( false ) ) { continue; } Throw( curPos, Res.Xml_UnclosedConditionalSection ); } tokenStartPos = curPos; } } private void ScanName() { ScanQName( false ); } private void ScanQName() { ScanQName( SupportNamespaces ); } private void ScanQName( bool isQName ) { tokenStartPos = curPos; int colonOffset = -1; for (;;) { unsafe { #if SILVERLIGHT if ( xmlCharType.IsStartNCNameSingleChar(chars[curPos]) || chars[curPos] == ':' ) { #else if ( ( xmlCharType.charProperties[chars[curPos]] & XmlCharType.fNCStartNameSC ) != 0 || chars[curPos] == ':') { // if ( xmlCharType.IsStartNCNameSingleChar(chars[curPos]) || chars[curPos] == ':' ) { #endif curPos++; } #if XML10_FIFTH_EDITION else if ( curPos + 1 < charsUsed && xmlCharType.IsNCNameSurrogateChar(chars[curPos+1], chars[curPos])) { curPos += 2; } #endif else { if ( curPos + 1 >= charsUsed ) { if ( ReadDataInName() ) { continue; } Throw( curPos, Res.Xml_UnexpectedEOF, "Name" ); } else { Throw( curPos, Res.Xml_BadStartNameChar, XmlException.BuildCharExceptionArgs( chars, charsUsed, curPos ) ); } } } ContinueName: unsafe { for (;;) { #if SILVERLIGHT if ( xmlCharType.IsNCNameSingleChar( chars[curPos] ) ) { #else if ( ( xmlCharType.charProperties[chars[curPos]] & XmlCharType.fNCNameSC ) != 0 ) { // while ( xmlCharType.IsNCNameSingleChar(chars[curPos]) ) { #endif curPos++; } #if XML10_FIFTH_EDITION else if ( curPos + 1 < charsUsed && xmlCharType.IsNameSurrogateChar(chars[curPos + 1], chars[curPos]) ) { curPos += 2; } #endif else { break; } } } if ( chars[curPos] == ':' ) { if ( isQName ) { if ( colonOffset != -1 ) { Throw( curPos, Res.Xml_BadNameChar, XmlException.BuildCharExceptionArgs( ':', '\0' )); } colonOffset = curPos - tokenStartPos; curPos++; continue; } else { curPos++; goto ContinueName; } } // end of buffer else if ( curPos == charsUsed #if XML10_FIFTH_EDITION || ( curPos + 1 == charsUsed && xmlCharType.IsNCNameHighSurrogateChar( chars[curPos] ) ) #endif ) { if ( ReadDataInName() ) { goto ContinueName; } if ( tokenStartPos == curPos ) { Throw( curPos, Res.Xml_UnexpectedEOF, "Name" ); } } // end of name colonPos = ( colonOffset == -1 ) ? -1 : tokenStartPos + colonOffset; return; } } private bool ReadDataInName() { int offset = curPos - tokenStartPos; curPos = tokenStartPos; bool newDataRead = ( ReadData() != 0 ); tokenStartPos = curPos; curPos += offset; return newDataRead; } private void ScanNmtoken() { tokenStartPos = curPos; for (;;) { unsafe { for (;;) { #if SILVERLIGHT if ( xmlCharType.IsNCNameSingleChar(chars[curPos]) || chars[curPos] == ':' ) { #else if ((xmlCharType.charProperties[chars[curPos]] & XmlCharType.fNCNameSC) != 0 || chars[curPos] == ':') { // if ( xmlCharType.IsNCNameChar(chars[curPos]) || chars[curPos] == ':' ) { #endif curPos++; } #if XML10_FIFTH_EDITION else if (curPos + 1 < charsUsed && xmlCharType.IsNCNameSurrogateChar(chars[curPos + 1], chars[curPos])) { curPos += 2; } #endif else { break; } } } if ( curPos < charsUsed #if XML10_FIFTH_EDITION && ( !xmlCharType.IsNCNameHighSurrogateChar( chars[curPos] ) || curPos + 1 < charsUsed ) #endif ) { if ( curPos - tokenStartPos == 0 ) { Throw( curPos, Res.Xml_BadNameChar, XmlException.BuildCharExceptionArgs( chars, charsUsed, curPos ) ); } return; } int len = curPos - tokenStartPos; curPos = tokenStartPos; if ( ReadData() == 0 ) { if ( len > 0 ) { tokenStartPos = curPos; curPos += len; return; } Throw( curPos, Res.Xml_UnexpectedEOF, "NmToken" ); } tokenStartPos = curPos; curPos += len; } } private bool EatPublicKeyword() { Debug.Assert( chars[curPos] == 'P' ); while ( charsUsed - curPos < 6 ) { if ( ReadData() == 0 ) { return false; } } if ( chars[curPos+1] != 'U' || chars[curPos+2] != 'B' || chars[curPos+3] != 'L' || chars[curPos+4] != 'I' || chars[curPos+5] != 'C' ) { return false; } curPos += 6; return true; } private bool EatSystemKeyword() { Debug.Assert( chars[curPos] == 'S' ); while ( charsUsed - curPos < 6 ) { if ( ReadData() == 0 ) { return false; } } if ( chars[curPos+1] != 'Y' || chars[curPos+2] != 'S' || chars[curPos+3] != 'T' || chars[curPos+4] != 'E' || chars[curPos+5] != 'M' ) { return false; } curPos += 6; return true; } // // Scanned data getters // private XmlQualifiedName GetNameQualified( bool canHavePrefix ) { Debug.Assert( curPos - tokenStartPos > 0 ); if ( colonPos == -1 ) { return new XmlQualifiedName( nameTable.Add( chars, tokenStartPos, curPos - tokenStartPos ) ); } else { if ( canHavePrefix ) { return new XmlQualifiedName( nameTable.Add( chars, colonPos + 1, curPos - colonPos - 1 ), nameTable.Add( chars, tokenStartPos, colonPos - tokenStartPos ) ); } else { Throw( tokenStartPos, Res.Xml_ColonInLocalName, GetNameString() ); return null; } } } private string GetNameString() { Debug.Assert( curPos - tokenStartPos > 0 ); return new string( chars, tokenStartPos, curPos - tokenStartPos ); } private string GetNmtokenString() { return GetNameString(); } private string GetValue() { if ( stringBuilder.Length == 0 ) { return new string( chars, tokenStartPos, curPos - tokenStartPos - 1 ); } else { return stringBuilder.ToString(); } } private string GetValueWithStrippedSpaces() { Debug.Assert( curPos == 0 || chars[curPos-1] == '"' || chars[curPos-1] == '\'' ); // We cannot StripSpaces directly in the buffer - we need the original value inthe buffer intact so that the internal subset value is correct string val = ( stringBuilder.Length == 0 ) ? new string( chars, tokenStartPos, curPos - tokenStartPos - 1 ) : stringBuilder.ToString(); return StripSpaces( val ); } // // Parsing buffer maintainance methods // int ReadData() { SaveParsingBuffer(); int charsRead = readerAdapter.ReadData(); LoadParsingBuffer(); return charsRead; } private void LoadParsingBuffer() { chars = readerAdapter.ParsingBuffer; charsUsed = readerAdapter.ParsingBufferLength; curPos = readerAdapter.CurrentPosition; } private void SaveParsingBuffer() { SaveParsingBuffer( curPos ); } private void SaveParsingBuffer( int internalSubsetValueEndPos ) { if ( SaveInternalSubsetValue ) { Debug.Assert( internalSubsetValueSb != null ); int readerCurPos = readerAdapter.CurrentPosition; if ( internalSubsetValueEndPos - readerCurPos > 0 ) { internalSubsetValueSb.Append( chars, readerCurPos, internalSubsetValueEndPos - readerCurPos ); } } readerAdapter.CurrentPosition = curPos; } // // Entity handling // private bool HandleEntityReference( bool paramEntity, bool inLiteral, bool inAttribute ) { Debug.Assert( chars[curPos] == '&' || chars[curPos] == '%' ); curPos++; return HandleEntityReference( ScanEntityName(), paramEntity, inLiteral, inAttribute ); } private bool HandleEntityReference( XmlQualifiedName entityName, bool paramEntity, bool inLiteral, bool inAttribute ) { Debug.Assert( chars[curPos-1] == ';' ); SaveParsingBuffer(); if ( paramEntity && ParsingInternalSubset && !ParsingTopLevelMarkup ) { Throw( curPos - entityName.Name.Length - 1, Res.Xml_InvalidParEntityRef ); } SchemaEntity entity = VerifyEntityReference( entityName, paramEntity, true, inAttribute ); if ( entity == null ) { return false; } if ( entity.ParsingInProgress ) { Throw( curPos - entityName.Name.Length - 1, paramEntity ? Res.Xml_RecursiveParEntity : Res.Xml_RecursiveGenEntity, entityName.Name ); } int newEntityId; if ( entity.IsExternal ) { if ( !readerAdapter.PushEntity( entity, out newEntityId ) ) { return false; } externalEntitiesDepth++; } else { if ( entity.Text.Length == 0 ) { return false; } if ( !readerAdapter.PushEntity( entity, out newEntityId ) ) { return false; } } currentEntityId = newEntityId; if ( paramEntity && !inLiteral && scanningFunction != ScanningFunction.ParamEntitySpace ) { savedScanningFunction = scanningFunction; scanningFunction = ScanningFunction.ParamEntitySpace; } LoadParsingBuffer(); return true; } private bool HandleEntityEnd( bool inLiteral ) { SaveParsingBuffer(); IDtdEntityInfo oldEntity; if ( !readerAdapter.PopEntity( out oldEntity, out currentEntityId ) ) { return false; } LoadParsingBuffer(); if ( oldEntity == null ) { // external subset popped Debug.Assert( !ParsingInternalSubset || freeFloatingDtd ); Debug.Assert( currentEntityId == 0 ); if ( scanningFunction == ScanningFunction.ParamEntitySpace ) { scanningFunction = savedScanningFunction; } return false; } if ( oldEntity.IsExternal ) { externalEntitiesDepth--; } if ( !inLiteral && scanningFunction != ScanningFunction.ParamEntitySpace ) { savedScanningFunction = scanningFunction; scanningFunction = ScanningFunction.ParamEntitySpace; } return true; } private SchemaEntity VerifyEntityReference( XmlQualifiedName entityName, bool paramEntity, bool mustBeDeclared, bool inAttribute ) { Debug.Assert( chars[curPos-1] == ';' ); SchemaEntity entity; if ( paramEntity ) { schemaInfo.ParameterEntities.TryGetValue(entityName, out entity); } else { schemaInfo.GeneralEntities.TryGetValue(entityName, out entity); } if ( entity == null ) { if ( paramEntity ) { #if !SILVERLIGHT if ( validate ) { SendValidationEvent( curPos - entityName.Name.Length - 1, XmlSeverityType.Error, Res.Xml_UndeclaredParEntity, entityName.Name ); } #endif } else if ( mustBeDeclared ) { if ( !ParsingInternalSubset ) { #if !SILVERLIGHT if (validate) { SendValidationEvent( curPos - entityName.Name.Length - 1, XmlSeverityType.Error, Res.Xml_UndeclaredEntity, entityName.Name ); } #endif } else { Throw( curPos - entityName.Name.Length - 1, Res.Xml_UndeclaredEntity, entityName.Name ); } } return null; } if ( !entity.NData.IsEmpty ) { Throw( curPos - entityName.Name.Length - 1, Res.Xml_UnparsedEntityRef, entityName.Name ); } if ( inAttribute && entity.IsExternal ) { Throw( curPos - entityName.Name.Length - 1, Res.Xml_ExternalEntityInAttValue, entityName.Name ); } return entity; } // // Helper methods and properties // #if !SILVERLIGHT private void SendValidationEvent( int pos, XmlSeverityType severity, string code, string arg ) { Debug.Assert( validate ); SendValidationEvent( severity, new XmlSchemaException( code, arg, BaseUriStr, (int)LineNo, (int)LinePos + ( pos - curPos ) ) ); } private void SendValidationEvent( XmlSeverityType severity, string code, string arg ) { Debug.Assert( validate ); SendValidationEvent( severity, new XmlSchemaException( code, arg, BaseUriStr, (int)LineNo, (int)LinePos ) ); } private void SendValidationEvent( XmlSeverityType severity, XmlSchemaException e ) { Debug.Assert( validate ); IValidationEventHandling eventHandling = readerAdapterWithValidation.ValidationEventHandling; if ( eventHandling != null ) { eventHandling.SendEvent(e, severity); } } #endif private bool IsAttributeValueType( Token token ) { return (int)token >= (int)Token.CDATA && (int)token <= (int)Token.NOTATION; } private int LineNo { get { return readerAdapter.LineNo; } } private int LinePos { get { return curPos - readerAdapter.LineStartPosition; } } private string BaseUriStr { get { Uri tmp = readerAdapter.BaseUri; return ( tmp != null ) ? tmp.ToString() : string.Empty; } } private void OnUnexpectedError() { Debug.Assert( false, "This is an unexpected error that should have been handled in the ScanXXX methods." ); Throw( curPos, Res.Xml_InternalError ); } void Throw( int curPos, string res ) { Throw( curPos, res, string.Empty ); } void Throw( int curPos, string res, string arg ) { this.curPos = curPos; Uri baseUri = readerAdapter.BaseUri; readerAdapter.Throw( new XmlException( res, arg, (int)LineNo, (int)LinePos, baseUri == null ? null : baseUri.ToString() ) ); } void Throw( int curPos, string res, string[] args ) { this.curPos = curPos; Uri baseUri = readerAdapter.BaseUri; readerAdapter.Throw( new XmlException( res, args, (int)LineNo, (int)LinePos, baseUri == null ? null : baseUri.ToString() ) ); } void Throw( string res, string arg, int lineNo, int linePos ) { Uri baseUri = readerAdapter.BaseUri; readerAdapter.Throw( new XmlException( res, arg, (int)lineNo, (int)linePos, baseUri == null ? null : baseUri.ToString() ) ); } void ThrowInvalidChar( int pos, string data, int invCharPos ) { Throw( pos, Res.Xml_InvalidCharacter, XmlException.BuildCharExceptionArgs( data, invCharPos )); } void ThrowInvalidChar( char[] data, int length, int invCharPos ) { Throw( invCharPos, Res.Xml_InvalidCharacter, XmlException.BuildCharExceptionArgs( data, length, invCharPos ) ); } private void ThrowUnexpectedToken( int pos, string expectedToken ) { ThrowUnexpectedToken( pos, expectedToken, null ); } private void ThrowUnexpectedToken( int pos, string expectedToken1, string expectedToken2 ) { string unexpectedToken = ParseUnexpectedToken( pos ); if ( expectedToken2 != null ) { Throw( curPos, Res.Xml_UnexpectedTokens2, new string[3] { unexpectedToken, expectedToken1, expectedToken2 } ); } else { Throw( curPos, Res.Xml_UnexpectedTokenEx, new string[2] { unexpectedToken, expectedToken1 } ); } } private string ParseUnexpectedToken( int startPos ) { if ( xmlCharType.IsNCNameSingleChar( chars[startPos] ) #if XML10_FIFTH_EDITION || xmlCharType.IsNCNameHighSurrogateChar( chars[startPos] ) #endif ) { // postpone the proper surrogate checking to the loop below int endPos = startPos; for (;;) { if ( xmlCharType.IsNCNameSingleChar( chars[endPos] ) ) { endPos++; } #if XML10_FIFTH_EDITION else if ( chars[endPos] != 0 && // check for end of the buffer xmlCharType.IsNCNameSurrogateChar( chars[endPos], chars[endPos + 1] ) ) { endPos += 2; } #endif else { break; } } int len = endPos - startPos; return new string( chars, startPos, len > 0 ? len : 1 ); } else { Debug.Assert( startPos < charsUsed ); return new string( chars, startPos, 1 ); } } // StripSpaces removes spaces at the beginning and at the end of the value and replaces sequences of spaces with a single space // !!! This method exists in 2 copies, here and in the XmlTextReaderImplHelper.cs // If you're changing this one, please also fix the other one. // (This is necessary due to packaging) internal static string StripSpaces(string value) { int len = value.Length; if (len <= 0) { return string.Empty; } int startPos = 0; StringBuilder norValue = null; while (value[startPos] == 0x20) { startPos++; if (startPos == len) { return " "; } } int i; for (i = startPos; i < len; i++) { if (value[i] == 0x20) { int j = i + 1; while (j < len && value[j] == 0x20) { j++; } if (j == len) { if (norValue == null) { return value.Substring(startPos, i - startPos); } else { norValue.Append(value, startPos, i - startPos); return norValue.ToString(); } } if (j > i + 1) { if (norValue == null) { norValue = new StringBuilder(len); } norValue.Append(value, startPos, i - startPos + 1); startPos = j; i = j - 1; } } } if (norValue == null) { return (startPos == 0) ? value : value.Substring(startPos, len - startPos); } else { if (i > startPos) { norValue.Append(value, startPos, i - startPos); } return norValue.ToString(); } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- XmlDocumentType.cs
- AbsoluteQuery.cs
- QueryPageSettingsEventArgs.cs
- BaseParagraph.cs
- QueryStringHandler.cs
- RegisteredDisposeScript.cs
- XmlSchemaInclude.cs
- ProgressBarRenderer.cs
- New.cs
- RefType.cs
- ModelPerspective.cs
- XmlCodeExporter.cs
- WebPartMenuStyle.cs
- _SingleItemRequestCache.cs
- FormViewDeletedEventArgs.cs
- SqlFormatter.cs
- SqlStream.cs
- FilterEventArgs.cs
- ExtentJoinTreeNode.cs
- HttpTransportManager.cs
- GridViewSelectEventArgs.cs
- ResourceWriter.cs
- Pair.cs
- ImageMetadata.cs
- DocumentApplicationJournalEntry.cs
- TabPanel.cs
- EventLogPermissionAttribute.cs
- DependencyProperty.cs
- SystemMulticastIPAddressInformation.cs
- AttributeUsageAttribute.cs
- BuildProviderAppliesToAttribute.cs
- PopOutPanel.cs
- IdlingCommunicationPool.cs
- StringBuilder.cs
- SoapProcessingBehavior.cs
- StaticFileHandler.cs
- Utils.cs
- PackageDigitalSignature.cs
- HostedBindingBehavior.cs
- DetailsView.cs
- Image.cs
- TypeResolver.cs
- BatchStream.cs
- TemplatePartAttribute.cs
- RootProfilePropertySettingsCollection.cs
- CustomGrammar.cs
- ClientScriptManager.cs
- ObjectStateEntry.cs
- HtmlWindow.cs
- MessageEventSubscriptionService.cs
- SystemGatewayIPAddressInformation.cs
- XmlExpressionDumper.cs
- InheritanceContextHelper.cs
- ResolveNameEventArgs.cs
- MenuEventArgs.cs
- RequestStatusBarUpdateEventArgs.cs
- __Error.cs
- Error.cs
- Point4DValueSerializer.cs
- SerializationStore.cs
- RectangleGeometry.cs
- EnumMember.cs
- TypeBuilderInstantiation.cs
- AdRotator.cs
- SmtpSpecifiedPickupDirectoryElement.cs
- PasswordBoxAutomationPeer.cs
- TransactionTable.cs
- WinFormsSecurity.cs
- FixedFlowMap.cs
- InvocationExpression.cs
- FormViewCommandEventArgs.cs
- SqlMethodTransformer.cs
- Geometry3D.cs
- Oid.cs
- DataGridViewLinkColumn.cs
- MimeTextImporter.cs
- WebBrowserNavigatingEventHandler.cs
- TemplatedAdorner.cs
- SafeEventLogWriteHandle.cs
- ProfileProvider.cs
- FrugalList.cs
- JulianCalendar.cs
- HopperCache.cs
- ExpressionWriter.cs
- ProfileParameter.cs
- AuthenticationModulesSection.cs
- Color.cs
- RecordBuilder.cs
- Type.cs
- SecurityRuntime.cs
- XmlSchemaAppInfo.cs
- KoreanCalendar.cs
- ZipIOCentralDirectoryFileHeader.cs
- SerializationException.cs
- RelationshipEndMember.cs
- WpfXamlType.cs
- WebBaseEventKeyComparer.cs
- PtsHost.cs
- FontFamilyConverter.cs
- DbProviderFactoriesConfigurationHandler.cs