Pārlūkot izejas kodu

2003-08-10 Atsushi Enomoto <[email protected]>

	* DTDObjectModel.cs : added XmlResolver related members. Added
	  invalid entity recursion logic. Added encodingdecl check on textdecl.
	* DTDValidatingReader.cs : It now implements IHasXmlParserContext.
	* XmlChar.cs : IsPubidChar() should not allow TAB(&#9;).
	* XmlDocumentType.cs : 1) internal CreateDocumentType() was now changed
	  to receive DTDObjectModel to support other than XmlTextReader.
	  2) Most of its public member is now based on DTDObjectModel.
	* XmlDocument.cs : 1) Synchronous change with XmlDocumentType.
	  2) ReadNode() now considers XmlParserContext's DTDObjectModel for
	  other than XmlTextReader (such as XmlValidatingReader).
	* XmlNode.cs : code cleanup only.
	* XmlParserInput.cs : added HasPEBuffer, used to check illegal nesting.
	* XmlTextReader.cs : 1) Illegal entity reference check logic was moved
	  from ReadContent() to SetEntityReferenceProperties(). 2) Indentation
	  change on ReadEntityReference(). 3) ReadAttribute() now checks
	  reference to external entity reference. 4) Added textdecl encoding
	  check. 5) DTDObjectModel fields are now set correctly. 6) added
	  PERef markup nest check. 7) If PEDecl was not found, it might be WFC
	  violation, not only be VC violation. 8) ReadEntityDecl() now receives
	  its declared entity itself, and this method checks IsInternalSubset.
	* XmlValidatingReader.cs : 1) Added GetInternalPerserContext().
	  2) ValidationType.None should be the same as Auto, not DTD (in the
	  future it should keep xml schema's default values).

	Pending Stuff in XmlTextReader which breaks some NUnit tests;
	  1) SetEntityReferenceProperies() has check for illegal references.
	  2) ReadAttribute(bool) has similar check for illegal references.

svn path=/trunk/mcs/; revision=17218
Atsushi Eno 22 gadi atpakaļ
vecāks
revīzija
cd0ee00b63

+ 30 - 0
mcs/class/System.XML/System.Xml/ChangeLog

@@ -1,3 +1,33 @@
+2003-08-10  Atsushi Enomoto <[email protected]>
+
+	* DTDObjectModel.cs : added XmlResolver related members. Added
+	  invalid entity recursion logic. Added encodingdecl check on textdecl.
+	* DTDValidatingReader.cs : It now implements IHasXmlParserContext.
+	* XmlChar.cs : IsPubidChar() should not allow TAB(&#9;).
+	* XmlDocumentType.cs : 1) internal CreateDocumentType() was now changed
+	  to receive DTDObjectModel to support other than XmlTextReader. 
+	  2) Most of its public member is now based on DTDObjectModel.
+	* XmlDocument.cs : 1) Synchronous change with XmlDocumentType.
+	  2) ReadNode() now considers XmlParserContext's DTDObjectModel for
+	  other than XmlTextReader (such as XmlValidatingReader).
+	* XmlNode.cs : code cleanup only.
+	* XmlParserInput.cs : added HasPEBuffer, used to check illegal nesting.
+	* XmlTextReader.cs : 1) Illegal entity reference check logic was moved 
+	  from ReadContent() to SetEntityReferenceProperties(). 2) Indentation
+	  change on ReadEntityReference(). 3) ReadAttribute() now checks
+	  reference to external entity reference. 4) Added textdecl encoding
+	  check. 5) DTDObjectModel fields are now set correctly. 6) added
+	  PERef markup nest check. 7) If PEDecl was not found, it might be WFC
+	  violation, not only be VC violation. 8) ReadEntityDecl() now receives
+	  its declared entity itself, and this method checks IsInternalSubset.
+	* XmlValidatingReader.cs : 1) Added GetInternalPerserContext().
+	  2) ValidationType.None should be the same as Auto, not DTD (in the
+	  future it should keep xml schema's default values).
+
+	Pending Stuff in XmlTextReader which breaks some NUnit tests;
+	  1) SetEntityReferenceProperies() has check for illegal references.
+	  2) ReadAttribute(bool) has similar check for illegal references.
+
 2003-08-09  Atsushi Enomoto <[email protected]>
 
 	* DTDAutomata.cs : Fixed (modified or added) TryEndElement() of choice,

+ 82 - 8
mcs/class/System.XML/System.Xml/DTDObjectModel.cs

@@ -8,6 +8,7 @@
 //
 using System;
 using System.Collections;
+using System.Collections.Specialized;
 using System.Globalization;
 using System.IO;
 using System.Text;
@@ -25,6 +26,7 @@ namespace Mono.Xml
 		DTDEntityDeclarationCollection entityDecls;
 		DTDNotationDeclarationCollection notationDecls;
 		ArrayList validationErrors;
+		XmlResolver resolver;
 
 		public DTDObjectModel ()
 		{
@@ -55,6 +57,14 @@ namespace Mono.Xml
 			return decl.EntityValue;
 		}
 
+		internal XmlResolver Resolver {
+			get { return resolver; }
+		}
+
+		public XmlResolver XmlResolver {
+			set { resolver = value; }
+		}
+
 		private DTDAutomataFactory factory;
 		public DTDAutomataFactory Factory {
 			get { return factory; }
@@ -396,6 +406,8 @@ namespace Mono.Xml
 	{
 		private DTDObjectModel root;
 		public string BaseURI;
+		public int LineNumber;
+		public int LinePosition;
 
 		internal void SetRoot (DTDObjectModel root)
 		{
@@ -605,21 +617,75 @@ namespace Mono.Xml
 		public string NotationName;
 		public string LiteralEntityValue;
 		public bool IsInternalSubset;
+		public StringCollection ReferencingEntities = new StringCollection ();
+		bool scanned;
+		bool recursed;
 
 		public string EntityValue {
 			get {
 				if (entityValue == null) {
-					if (SystemId == null)
+					if (NotationName != null)
+						entityValue = "";
+					else if (SystemId == null)
 						entityValue = LiteralEntityValue;
 					else {
 						// FIXME: should use specified XmlUrlResolver.
-						entityValue = ResolveExternalEntity (new XmlUrlResolver ());
+						entityValue = ResolveExternalEntity (Root.Resolver);
 					}
+					// Check illegal recursion.
+					ScanEntityValue (new StringCollection ());
 				}
 				return entityValue;
 			}
 		}
 
+		public void ScanEntityValue (StringCollection refs)
+		{
+			// To modify this code, beware nesting between this and EntityValue.
+			string value = EntityValue;
+
+			if (recursed)
+				throw new XmlException ("Entity recursion was found.");
+			recursed = true;
+
+			if (scanned) {
+				foreach (string referenced in refs)
+					if (this.ReferencingEntities.Contains (referenced))
+						throw new XmlException (String.Format (
+							"Nested entity was found between {0} and {1}",
+							referenced, Name));
+				recursed = false;
+				return;
+			}
+
+			int len = value.Length;
+			int start = 0;
+			for (int i=0; i<len; i++) {
+				switch (value [i]) {
+				case '&':
+					start = i+1;
+					break;
+				case ';':
+					if (start == 0)
+						break;
+					string name = value.Substring (start, i - start);
+					this.ReferencingEntities.Add (name);
+					DTDEntityDeclaration decl = Root.EntityDecls [name];
+					if (decl != null) {
+						refs.Add (Name);
+						decl.ScanEntityValue (refs);
+						foreach (string str in decl.ReferencingEntities)
+							ReferencingEntities.Add (str);
+						refs.Remove (Name);
+					}
+					start = 0;
+					break;
+				}
+			}
+			scanned = true;
+			recursed = false;
+		}
+
 		private string ResolveExternalEntity (XmlResolver resolver)
 		{
 			if (resolver == null)
@@ -637,14 +703,16 @@ namespace Mono.Xml
 
 			bool checkTextDecl = true;
 			while (reader.Peek () != -1) {
-				sb.Append (reader.Read ());
+				sb.Append ((char) reader.Read ());
 				if (checkTextDecl && sb.Length == 6) {
 					if (sb.ToString () == "<?xml ") {
 						// Skip Text declaration.
 						sb.Length = 0;
 						StringBuilder textdecl = new StringBuilder ();
-						while (reader.Peek () == '>' || reader.Peek () == -1)
-							textdecl.Append (reader.Read ());
+						while (reader.Peek () != '>' && reader.Peek () != -1)
+							textdecl.Append ((char) reader.Read ());
+						if (textdecl.ToString ().IndexOf ("encoding") < 0)
+							throw new XmlException ("Text declaration must have encoding specification: " + BaseURI);
 						if (textdecl.ToString ().IndexOf ("standalone") >= 0)
 							throw new XmlException ("Text declaration cannot have standalone declaration: " + BaseURI);
 					}
@@ -711,11 +779,17 @@ namespace Mono.Xml
 			string absPath = absUri.ToString ();
 
 			try {
-				TextReader tw = new XmlStreamReader (absUri.ToString (), false, resolver, BaseURI);
+				XmlStreamReader tw = new XmlStreamReader (absUri.ToString (), false, resolver, BaseURI);
 				string s = tw.ReadToEnd ();
 				if (s.StartsWith ("<?xml")) {
-					int end = s.IndexOf (">" + 1);
-					if (s.IndexOf ("standal0ne", end) >= 0)
+					int end = s.IndexOf (">") + 1;
+					if (end < 0)
+						throw new XmlException (this as IXmlLineInfo,
+							"Inconsistent text declaration markup.");
+					if (s.IndexOf ("encoding", 0, end) < 0)
+						throw new XmlException (this as IXmlLineInfo,
+							"Text declaration must not omit encoding specification.");
+					if (s.IndexOf ("standalone", 0, end) >= 0)
 						throw new XmlException (this as IXmlLineInfo,
 							"Text declaration cannot have standalone declaration.");
 					resolvedValue = s.Substring (end);

+ 21 - 15
mcs/class/System.XML/System.Xml/DTDValidatingReader.cs

@@ -8,7 +8,7 @@ using System.Xml.Schema;
 
 namespace Mono.Xml
 {
-	public class DTDValidatingReader : XmlReader, IXmlLineInfo
+	public class DTDValidatingReader : XmlReader, IXmlLineInfo, IHasXmlParserContext
 	{
 		public DTDValidatingReader (XmlReader reader)
 			: this (reader, null)
@@ -764,18 +764,6 @@ namespace Mono.Xml
 				throw new InvalidOperationException ("The current node is not an Entity Reference");
 			DTDEntityDeclaration entity = DTD != null ? DTD.EntityDecls [reader.Name] as DTDEntityDeclaration : null;
 
-			XmlParserContext ctx = null;
-			if (sourceTextReader != null)
-				ctx = sourceTextReader.GetInternalParserContext ();
-			else if (reader is XmlNodeReader)
-				ctx = ((XmlNodeReader) reader).GetInternalParserContext ();
-			else if (reader is IHasXmlParserContext)
-				ctx = ((IHasXmlParserContext) reader).ParserContext;
-
-			if (ctx == null)
-				throw new NotSupportedException (
-					"Entity resolution from non-XmlTextReader XmlReader could not be supported.");
-
 			XmlNodeType xmlReaderNodeType =
 				(currentAttribute != null) ? XmlNodeType.Attribute : XmlNodeType.Element;
 
@@ -783,11 +771,11 @@ namespace Mono.Xml
 			if (entity != null && entity.SystemId != null) {
 				Uri baseUri = entity.BaseURI == null ? null : new Uri (entity.BaseURI);
 				Stream stream = resolver.GetEntity (resolver.ResolveUri (baseUri, entity.SystemId), null, typeof (Stream)) as Stream;
-				nextEntityReader = new XmlTextReader (stream, xmlReaderNodeType, ctx);
+				nextEntityReader = new XmlTextReader (stream, xmlReaderNodeType, ParserContext);
 			} else {
 				string replacementText =
 					(entity != null) ? entity.EntityValue : String.Empty;
-				nextEntityReader = new XmlTextReader (replacementText, xmlReaderNodeType, ctx);
+				nextEntityReader = new XmlTextReader (replacementText, xmlReaderNodeType, ParserContext);
 			}
 			nextEntityReader.XmlResolver = resolver;
 			nextEntityReader.MaybeTextDecl = true;
@@ -936,6 +924,24 @@ namespace Mono.Xml
 			}
 		}
 
+		public XmlParserContext ParserContext {
+			get {
+				XmlParserContext ctx = null;
+				if (sourceTextReader != null)
+					ctx = sourceTextReader.GetInternalParserContext ();
+				else if (reader is XmlNodeReader)
+					ctx = ((XmlNodeReader) reader).GetInternalParserContext ();
+				else if (reader is IHasXmlParserContext)
+					ctx = ((IHasXmlParserContext) reader).ParserContext;
+
+				if (ctx == null)
+					throw new NotSupportedException (
+						"Cannot get parser context from specified XmlReader. To support this XmlReader, implement IHasXmlParserContext interface on the reader.");
+
+				return ctx;
+			}
+		}
+
 		public override string Prefix {
 			get {
 				if (currentTextValue != null)

+ 1 - 1
mcs/class/System.XML/System.Xml/XmlChar.cs

@@ -97,7 +97,7 @@ namespace System.Xml
 
 		internal static bool IsPubidChar(int ch)
 		{
-			return IsWhitespace(ch) | ('a' <= ch && ch <= 'z') | ('A' <= ch && ch <= 'Z') | ('0' <= ch && ch <= '9') | "-'()+,./:=?;!*#@$_%".IndexOf((char)ch) >= 0;
+			return (IsWhitespace(ch) && ch != '\t') | ('a' <= ch && ch <= 'z') | ('A' <= ch && ch <= 'Z') | ('0' <= ch && ch <= '9') | "-'()+,./:=?;!*#@$_%".IndexOf((char)ch) >= 0;
 		}
 
 		internal static bool IsPubid (string str)

+ 21 - 8
mcs/class/System.XML/System.Xml/XmlDocument.cs

@@ -268,9 +268,9 @@ namespace System.Xml
 			return new XmlDocumentType (name, publicId, systemId, internalSubset, this);
 		}
 
-		private XmlDocumentType CreateDocumentType (XmlTextReader reader)
+		private XmlDocumentType CreateDocumentType (DTDObjectModel dtd)
 		{
-			return new XmlDocumentType (reader, this);
+			return new XmlDocumentType (dtd, this);
 		}
 
 		public XmlElement CreateElement (string name)
@@ -800,15 +800,28 @@ namespace System.Xml
 					break;
 
 				case XmlNodeType.DocumentType:
-					// hack ;-)
+					if(currentNode != null)
+						throw new XmlException (reader as IXmlLineInfo, "XmlDocumentType at invalid position.");
+
+					DTDObjectModel dtd = null;
 					XmlTextReader xtReader = reader as XmlTextReader;
-					if(xtReader == null)
-						newNode = CreateDocumentType (reader.Name, reader ["PUBLIC"], reader ["SYSTEM"], reader.Value);
+					if (xtReader != null)
+						dtd = xtReader.DTD;
+					XmlNodeReader xnReader = reader as XmlNodeReader;
+					if (xnReader != null)
+						dtd = xnReader.GetInternalParserContext ().Dtd;
+					XmlValidatingReader xvReader = reader as XmlValidatingReader;
+					if (xvReader != null)
+						dtd = xvReader.GetInternalParserContext ().Dtd;
+					IHasXmlParserContext ctxReader = reader as IHasXmlParserContext;
+					if (ctxReader != null)
+						dtd = ctxReader.ParserContext.Dtd;
+
+					if (dtd != null)
+						newNode = CreateDocumentType (dtd);
 					else
-						newNode = CreateDocumentType (xtReader);
+						newNode = CreateDocumentType (reader.Name, reader ["PUBLIC"], reader ["SYSTEM"], reader.Value);
 
-					if(currentNode != null)
-						throw new XmlException (reader as IXmlLineInfo, "XmlDocumentType at invalid position.");
 					break;
 
 				case XmlNodeType.EntityReference:

+ 15 - 24
mcs/class/System.XML/System.Xml/XmlDocumentType.cs

@@ -16,10 +16,10 @@ namespace System.Xml
 	public class XmlDocumentType  : XmlLinkedNode
 	{
 		// Fields
-		string name;            // name of the document type
-		string publicId;        // public identifier on the DOCTYPE
-		string systemId;        // system identifier on the DOCTYPE
-		string internalSubset;  // value of the DTD internal subset
+//		string name;            // name of the document type
+//		string publicId;        // public identifier on the DOCTYPE
+//		string systemId;        // system identifier on the DOCTYPE
+//		string internalSubset;  // value of the DTD internal subset
 		internal XmlNamedNodeMap entities;
 		internal XmlNamedNodeMap notations;
 		DTDObjectModel dtd;
@@ -30,11 +30,6 @@ namespace System.Xml
 						    XmlDocument doc)
 			: base (doc)
 		{
-			this.name = name;
-			this.publicId = publicId;
-			this.systemId = systemId;
-			this.internalSubset = internalSubset;
-
 			XmlTextReader xtr = new XmlTextReader (BaseURI, new StringReader (""), doc.NameTable);
 			xtr.XmlResolver = doc.Resolver;
 			xtr.GenerateDTDObjectModel (name, publicId, systemId, internalSubset);
@@ -43,15 +38,10 @@ namespace System.Xml
 			ImportFromDTD ();
 		}
 
-		internal XmlDocumentType (XmlTextReader reader, XmlDocument doc)
+		internal XmlDocumentType (DTDObjectModel dtd, XmlDocument doc)
 			: base (doc)
 		{
-			this.name = reader.Name;
-			this.publicId = reader ["PUBLIC"];
-			this.systemId = reader ["SYSTEM"];
-			this.internalSubset = reader.Value;
-			this.dtd = reader.DTD;
-
+			this.dtd = dtd;
 			ImportFromDTD ();
 		}
 
@@ -86,7 +76,7 @@ namespace System.Xml
 			
 		public string InternalSubset
 		{
-			get { return internalSubset; }
+			get { return dtd.InternalSubset; }
 		}
 
 		public override bool IsReadOnly
@@ -96,12 +86,12 @@ namespace System.Xml
 
 		public override string LocalName
 		{
-			get { return name; }
+			get { return dtd.Name; }
 		}
 
 		public override string Name
 		{
-			get { return name; }
+			get { return dtd.Name; }
 		}
 
 		public override XmlNodeType NodeType
@@ -116,20 +106,21 @@ namespace System.Xml
 
 		public string PublicId
 		{
-			get { return publicId; }
+			get { return dtd.PublicId; }
 		}
 
 		public string SystemId
 		{
-			get { return systemId; }
+			get { return dtd.SystemId; }
 		}
 
 		// Methods
 		public override XmlNode CloneNode (bool deep)
 		{
 			// deep is ignored
-			return new XmlDocumentType (name, publicId, systemId,
-						    internalSubset, OwnerDocument);
+//			return new XmlDocumentType (Name, PublicId, SystemId,
+//						    InternalSubset, OwnerDocument);
+			return new XmlDocumentType (dtd, OwnerDocument);
 		}
 		
 		public override void WriteContentTo (XmlWriter w)
@@ -139,7 +130,7 @@ namespace System.Xml
 
 		public override void WriteTo (XmlWriter w)
 		{
-			w.WriteDocType (name, publicId, systemId, internalSubset);
+			w.WriteDocType (Name, PublicId, SystemId, InternalSubset);
 		}
 	}
 }

+ 1 - 8
mcs/class/System.XML/System.Xml/XmlNode.cs

@@ -254,7 +254,6 @@ namespace System.Xml
 
 		public abstract XmlNode CloneNode (bool deep);
 
-		[MonoTODO]
 		public XPathNavigator CreateNavigator ()
 		{
 			XmlDocument document = this.NodeType == XmlNodeType.Document ?
@@ -347,7 +346,6 @@ namespace System.Xml
 			return InsertBefore (newChild, argNode);
 		}
 
-		[MonoTODO("If inserted node is entity reference, then check conforming entity. Wait for DTD implementation.")]
 		public virtual XmlNode InsertBefore (XmlNode newChild, XmlNode refChild)
 		{
 			XmlDocument ownerDoc = (NodeType == XmlNodeType.Document) ? (XmlDocument)this : OwnerDocument;
@@ -552,7 +550,7 @@ namespace System.Xml
 			return SelectNodes (xpath, null);
 		}
 
-		[MonoTODO]
+		[MonoTODO ("return nodes in document order")]
 		public XmlNodeList SelectNodes (string xpath, XmlNamespaceManager nsmgr)
 		{
 			XPathNavigator nav = CreateNavigator ();
@@ -586,11 +584,6 @@ namespace System.Xml
 			return ((XmlDocumentNavigator) iter.Current).Node;
 		}
 
-//		internal void SetParentNode (XmlNode parent)
-//		{
-//			parentNode = parent;
-//		}
-
 		[MonoTODO]
 		public virtual bool Supports (string feature, string version)
 		{

+ 12 - 0
mcs/class/System.XML/System.Xml/XmlParserInput.cs

@@ -125,6 +125,18 @@ namespace Mono.Xml.Native
 			get { return this.currentMarkup; }
 		}
 
+		private char [] wsChars = new char [] {' ', '\r', '\n', '\t'};
+		public bool HasPEBuffer {
+			get {
+				if (peBuffer.Length == 0)
+					return false;
+				else if (peBuffer.ToString ().Trim (wsChars).Length == 0)
+					return false;
+				else
+					return true;
+			}
+		}
+
 		public int LineNumber {
 			get { return line; }
 		}

+ 66 - 40
mcs/class/System.XML/System.Xml/XmlTextReader.cs

@@ -19,6 +19,7 @@
 
 using System;
 using System.Collections;
+using System.Collections.Specialized;
 using System.IO;
 using System.Text;
 using System.Xml.Schema;
@@ -1010,16 +1011,9 @@ namespace System.Xml
 				popScope = false;
 			}
 
-			if (returnEntityReference) {
+			if (returnEntityReference)
 				SetEntityReferenceProperties ();
-				if (DTD == null)
-					throw new XmlException (this as IXmlLineInfo,
-						"Entity reference is not allowed without document type declaration.");
-				else if((!DTD.InternalSubsetHasPEReference || 
-					isStandalone || resolver == null) && DTD.EntityDecls [name] == null)
-					throw new XmlException (this as IXmlLineInfo,
-						"Required entity declaration for '" + name + "' was not found.");
-			} else {
+			else {
     				switch (PeekChar ()) {
 				case '<':
 					ReadChar ();
@@ -1061,6 +1055,18 @@ namespace System.Xml
 
 		private void SetEntityReferenceProperties ()
 		{
+/*
+			if (resolver != null) {
+				if (DTD == null)
+					throw new XmlException (this as IXmlLineInfo,
+						"Entity reference is not allowed without document type declaration.");
+				else if((!DTD.InternalSubsetHasPEReference || isStandalone) &&
+					DTD.EntityDecls [entityReferenceName] == null)
+					throw new XmlException (this as IXmlLineInfo,
+						"Required entity declaration for '" + entityReferenceName + "' was not found.");
+				string dummy = DTD.EntityDecls [entityReferenceName].EntityValue;
+			}
+*/
 			SetProperties (
 				XmlNodeType.EntityReference, // nodeType
 				entityReferenceName, // name
@@ -1358,23 +1364,23 @@ namespace System.Xml
 				throw new XmlException (this as IXmlLineInfo,
 					"Invalid entity reference name was found.");
 
-				char predefined = XmlChar.GetPredefinedEntity (name);
-				if (predefined != 0)
-					AppendValueChar (predefined);
-				else {
-					if (ignoreEntityReferences) {
-						AppendValueChar ('&');
-
-						foreach (char ch2 in name) {
-							AppendValueChar (ch2);
-						}
+			char predefined = XmlChar.GetPredefinedEntity (name);
+			if (predefined != 0)
+				AppendValueChar (predefined);
+			else {
+				if (ignoreEntityReferences) {
+					AppendValueChar ('&');
 
-						AppendValueChar (';');
-					} else {
-						returnEntityReference = true;
-						entityReferenceName = name;
+					foreach (char ch2 in name) {
+						AppendValueChar (ch2);
 					}
+
+					AppendValueChar (';');
+				} else {
+					returnEntityReference = true;
+					entityReferenceName = name;
 				}
+			}
 		}
 
 		// The reader is positioned on the first character of
@@ -1444,9 +1450,7 @@ namespace System.Xml
 					if (XmlChar.GetPredefinedEntity (entName) == 0) {
 						DTDEntityDeclaration entDecl = 
 							DTD == null ? null : DTD.EntityDecls [entName];
-						// In this point, XML 1.0 spec is tricky. Its WFC constraints 
-						// allow non-declared entity, while prohibiting external entity reference.
-						if (entDecl == null || !entDecl.IsInternalSubset)
+						if (entDecl == null || entDecl.SystemId != null)
 							throw new XmlException (this as IXmlLineInfo,
 								"Reference to external entities is not allowed in attribute value.");
 					}
@@ -1553,8 +1557,8 @@ namespace System.Xml
 						message = "Version 1.0 declaration is required in Text Declaration.";
 					currentCheck = 1;
 				}
-				if (orderedAttributes.Count > currentCheck && orderedAttributes [currentCheck] as string != "encoding")
-					message = "Invalid Text Declaration markup was found.";
+				if (orderedAttributes.Count <= currentCheck || orderedAttributes [currentCheck] as string != "encoding")
+					message = "Invalid Text Declaration markup was found. encoding specification is required.";
 			}
 			if (message != null)
 				throw new XmlException (this as IXmlLineInfo, message);
@@ -1699,8 +1703,8 @@ namespace System.Xml
 			currentState = XmlNodeType.DocumentType;
 
 			string doctypeName = null;
-			string publicId = String.Empty;
-			string systemId = String.Empty;
+			string publicId = null;
+			string systemId = null;
 			int intSubsetStartLine = 0;
 			int intSubsetStartColumn = 0;
 
@@ -1765,6 +1769,10 @@ namespace System.Xml
 			parserContext.Dtd = new DTDObjectModel ();	// merges both internal and external subsets in the meantime,
 			DTD.BaseURI = BaseURI;
 			DTD.Name = name;
+			DTD.PublicId = publicId;
+			DTD.SystemId = systemId;
+			DTD.InternalSubset = internalSubset;
+			DTD.XmlResolver = resolver;
 			int originalParserDepth = parserInputStack.Count;
 			if (internalSubset != null && internalSubset.Length > 0) {
 				XmlParserInput original = currentInput;
@@ -1787,7 +1795,6 @@ namespace System.Xml
 				} while (nodeType != XmlNodeType.None || parserInputStack.Count > originalParserDepth + 1);
 				PopParserInput ();
 			}
-			// TODO: Check entity nesting
 
 			return DTD;
 		}
@@ -2002,7 +2009,18 @@ namespace System.Xml
 				// It affects on entity references' well-formedness
 				if (this.parserInputStack.Count == 0)
 					DTD.InternalSubsetHasPEReference = true;
-				TryExpandPERef ();
+				ReadChar ();
+				string peName = ReadName ();
+				Expect (';');
+				currentInput.InsertParameterEntityBuffer (GetPEValue (peName));
+				int currentLine = currentInput.LineNumber;
+				int currentColumn = currentInput.LinePosition;
+				while (currentInput.HasPEBuffer)
+					CompileDTDSubset ();
+				if (currentInput.LineNumber != currentLine ||
+					currentInput.LinePosition != currentColumn)
+					throw new XmlException (this as IXmlLineInfo,
+						"Incorrectly nested parameter entity.");
 				break;
 			case '<':
 				ReadChar ();
@@ -2060,7 +2078,7 @@ namespace System.Xml
 							TryExpandPERef ();
 							SkipWhitespace ();
 							if (XmlChar.IsNameChar (PeekChar ()))
-							ReadParameterEntityDecl ();
+								ReadParameterEntityDecl ();
 							else
 								throw new XmlException (this as IXmlLineInfo,"expected name character");
 						}
@@ -2420,8 +2438,12 @@ namespace System.Xml
 				this.parameterEntities [peName] as DTDParameterEntityDeclaration;
 			if (peDecl != null)
 				return peDecl.Value;
-				DTD.AddError (new XmlSchemaException (
-					"Parameter entity " + peName + " not found.", null));
+			// See XML 1.0 section 4.1 for both WFC and VC.
+			if ((DTD.SystemId == null && !DTD.InternalSubsetHasPEReference) || this.isStandalone)
+				throw new XmlException (this as IXmlLineInfo,
+					"Parameter entity " + peName + " not found.");
+			DTD.AddError (new XmlSchemaException (
+				"Parameter entity " + peName + " not found.", null));
 			return "";
 		}
 
@@ -2484,7 +2506,7 @@ namespace System.Xml
 			}
 			else {
 				// literal entity
-				decl.LiteralEntityValue = ReadEntityValueDecl ();
+				ReadEntityValueDecl (decl);
 			}
 			SkipWhitespace ();
 			// This expanding is only allowed as a non-validating parser.
@@ -2494,7 +2516,7 @@ namespace System.Xml
 			return decl;
 		}
 
-		private string ReadEntityValueDecl ()
+		private void ReadEntityValueDecl (DTDEntityDeclaration decl)
 		{
 			SkipWhitespace ();
 			// quotation char will be finally removed on unescaping
@@ -2511,8 +2533,10 @@ namespace System.Xml
 					ReadChar ();
 					string name = ReadName ();
 					Expect (';');
+					if (decl.IsInternalSubset)
+						throw new XmlException (this as IXmlLineInfo,
+							"Parameter entity is not allowed in internal subset entity '" + name + "'");
 					valueBuffer.Append (GetPEValue (name));
-					continue;
 					break;
 				case -1:
 					throw new XmlException ("unexpected end of stream.");
@@ -2526,7 +2550,7 @@ namespace System.Xml
 			ClearValueBuffer ();
 
 			Expect (quoteChar);
-			return value;
+			decl.LiteralEntityValue = value;
 		}
 
 		private DTDAttListDeclaration ReadAttListDecl ()
@@ -2627,7 +2651,9 @@ namespace System.Xml
 				case 'O':
 					Expect ("OTATION");
 					def.Datatype = XmlSchemaDatatype.FromName ("NOTATION");
-					SkipWhitespace ();
+					if (!SkipWhitespace ())
+						throw new XmlException (this as IXmlLineInfo,
+							"Whitespace is required between name and content in DTD attribute definition.");
 					Expect ('(');
 					SkipWhitespace ();
 					def.EnumeratedNotations.Add (ReadName ());		// notation name

+ 11 - 6
mcs/class/System.XML/System.Xml/XmlValidatingReader.cs

@@ -25,6 +25,7 @@ namespace System.Xml {
 		XmlResolver resolver;
 		ValidationType validationType;
 		XmlSchemaCollection schemas;
+		DTDValidatingReader dtdReader;
 
 		#endregion // Fields
 
@@ -283,6 +284,12 @@ namespace System.Xml {
 			return validatingReader.GetAttribute (localName, namespaceName);
 		}
 
+		internal XmlParserContext GetInternalParserContext ()
+		{
+			return dtdReader != null ?
+				dtdReader.ParserContext : null;
+		}
+
 		bool IXmlLineInfo.HasLineInfo ()
 		{
 			IXmlLineInfo info = validatingReader as IXmlLineInfo;
@@ -337,19 +344,17 @@ namespace System.Xml {
 			if (ReadState == ReadState.Initial) {
 				switch (ValidationType) {
 				case ValidationType.Auto:
+				case ValidationType.None:
 					if (schemas.Count > 0)
 						goto case ValidationType.Schema;
 					else
 						goto case ValidationType.DTD;
-				case ValidationType.None:
-					validatingReader = // new XmlSchemaValidatingReader (
-						new DTDValidatingReader (sourceReader, this);
-					break;
 				case ValidationType.DTD:
-					validatingReader = new DTDValidatingReader (sourceReader, this);
+					validatingReader = dtdReader = new DTDValidatingReader (sourceReader, this);
 					break;
 				case ValidationType.Schema:
-//					validatingReader = new XmlSchemaValidatingReader (sourceReader, this);
+//					dtdReader = new DTDValidatingReader (sourceReader, this);
+//					validatingReader = new XmlSchemaValidatingReader (dtdReader, this);
 //					break;
 				case ValidationType.XDR:
 					throw new NotImplementedException ();