2
0
Эх сурвалжийг харах

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 жил өмнө
parent
commit
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]>
 2003-08-09  Atsushi Enomoto <[email protected]>
 
 
 	* DTDAutomata.cs : Fixed (modified or added) TryEndElement() of choice,
 	* 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;
 using System.Collections;
 using System.Collections;
+using System.Collections.Specialized;
 using System.Globalization;
 using System.Globalization;
 using System.IO;
 using System.IO;
 using System.Text;
 using System.Text;
@@ -25,6 +26,7 @@ namespace Mono.Xml
 		DTDEntityDeclarationCollection entityDecls;
 		DTDEntityDeclarationCollection entityDecls;
 		DTDNotationDeclarationCollection notationDecls;
 		DTDNotationDeclarationCollection notationDecls;
 		ArrayList validationErrors;
 		ArrayList validationErrors;
+		XmlResolver resolver;
 
 
 		public DTDObjectModel ()
 		public DTDObjectModel ()
 		{
 		{
@@ -55,6 +57,14 @@ namespace Mono.Xml
 			return decl.EntityValue;
 			return decl.EntityValue;
 		}
 		}
 
 
+		internal XmlResolver Resolver {
+			get { return resolver; }
+		}
+
+		public XmlResolver XmlResolver {
+			set { resolver = value; }
+		}
+
 		private DTDAutomataFactory factory;
 		private DTDAutomataFactory factory;
 		public DTDAutomataFactory Factory {
 		public DTDAutomataFactory Factory {
 			get { return factory; }
 			get { return factory; }
@@ -396,6 +406,8 @@ namespace Mono.Xml
 	{
 	{
 		private DTDObjectModel root;
 		private DTDObjectModel root;
 		public string BaseURI;
 		public string BaseURI;
+		public int LineNumber;
+		public int LinePosition;
 
 
 		internal void SetRoot (DTDObjectModel root)
 		internal void SetRoot (DTDObjectModel root)
 		{
 		{
@@ -605,21 +617,75 @@ namespace Mono.Xml
 		public string NotationName;
 		public string NotationName;
 		public string LiteralEntityValue;
 		public string LiteralEntityValue;
 		public bool IsInternalSubset;
 		public bool IsInternalSubset;
+		public StringCollection ReferencingEntities = new StringCollection ();
+		bool scanned;
+		bool recursed;
 
 
 		public string EntityValue {
 		public string EntityValue {
 			get {
 			get {
 				if (entityValue == null) {
 				if (entityValue == null) {
-					if (SystemId == null)
+					if (NotationName != null)
+						entityValue = "";
+					else if (SystemId == null)
 						entityValue = LiteralEntityValue;
 						entityValue = LiteralEntityValue;
 					else {
 					else {
 						// FIXME: should use specified XmlUrlResolver.
 						// FIXME: should use specified XmlUrlResolver.
-						entityValue = ResolveExternalEntity (new XmlUrlResolver ());
+						entityValue = ResolveExternalEntity (Root.Resolver);
 					}
 					}
+					// Check illegal recursion.
+					ScanEntityValue (new StringCollection ());
 				}
 				}
 				return entityValue;
 				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)
 		private string ResolveExternalEntity (XmlResolver resolver)
 		{
 		{
 			if (resolver == null)
 			if (resolver == null)
@@ -637,14 +703,16 @@ namespace Mono.Xml
 
 
 			bool checkTextDecl = true;
 			bool checkTextDecl = true;
 			while (reader.Peek () != -1) {
 			while (reader.Peek () != -1) {
-				sb.Append (reader.Read ());
+				sb.Append ((char) reader.Read ());
 				if (checkTextDecl && sb.Length == 6) {
 				if (checkTextDecl && sb.Length == 6) {
 					if (sb.ToString () == "<?xml ") {
 					if (sb.ToString () == "<?xml ") {
 						// Skip Text declaration.
 						// Skip Text declaration.
 						sb.Length = 0;
 						sb.Length = 0;
 						StringBuilder textdecl = new StringBuilder ();
 						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)
 						if (textdecl.ToString ().IndexOf ("standalone") >= 0)
 							throw new XmlException ("Text declaration cannot have standalone declaration: " + BaseURI);
 							throw new XmlException ("Text declaration cannot have standalone declaration: " + BaseURI);
 					}
 					}
@@ -711,11 +779,17 @@ namespace Mono.Xml
 			string absPath = absUri.ToString ();
 			string absPath = absUri.ToString ();
 
 
 			try {
 			try {
-				TextReader tw = new XmlStreamReader (absUri.ToString (), false, resolver, BaseURI);
+				XmlStreamReader tw = new XmlStreamReader (absUri.ToString (), false, resolver, BaseURI);
 				string s = tw.ReadToEnd ();
 				string s = tw.ReadToEnd ();
 				if (s.StartsWith ("<?xml")) {
 				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,
 						throw new XmlException (this as IXmlLineInfo,
 							"Text declaration cannot have standalone declaration.");
 							"Text declaration cannot have standalone declaration.");
 					resolvedValue = s.Substring (end);
 					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
 namespace Mono.Xml
 {
 {
-	public class DTDValidatingReader : XmlReader, IXmlLineInfo
+	public class DTDValidatingReader : XmlReader, IXmlLineInfo, IHasXmlParserContext
 	{
 	{
 		public DTDValidatingReader (XmlReader reader)
 		public DTDValidatingReader (XmlReader reader)
 			: this (reader, null)
 			: this (reader, null)
@@ -764,18 +764,6 @@ namespace Mono.Xml
 				throw new InvalidOperationException ("The current node is not an Entity Reference");
 				throw new InvalidOperationException ("The current node is not an Entity Reference");
 			DTDEntityDeclaration entity = DTD != null ? DTD.EntityDecls [reader.Name] as DTDEntityDeclaration : null;
 			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 =
 			XmlNodeType xmlReaderNodeType =
 				(currentAttribute != null) ? XmlNodeType.Attribute : XmlNodeType.Element;
 				(currentAttribute != null) ? XmlNodeType.Attribute : XmlNodeType.Element;
 
 
@@ -783,11 +771,11 @@ namespace Mono.Xml
 			if (entity != null && entity.SystemId != null) {
 			if (entity != null && entity.SystemId != null) {
 				Uri baseUri = entity.BaseURI == null ? null : new Uri (entity.BaseURI);
 				Uri baseUri = entity.BaseURI == null ? null : new Uri (entity.BaseURI);
 				Stream stream = resolver.GetEntity (resolver.ResolveUri (baseUri, entity.SystemId), null, typeof (Stream)) as Stream;
 				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 {
 			} else {
 				string replacementText =
 				string replacementText =
 					(entity != null) ? entity.EntityValue : String.Empty;
 					(entity != null) ? entity.EntityValue : String.Empty;
-				nextEntityReader = new XmlTextReader (replacementText, xmlReaderNodeType, ctx);
+				nextEntityReader = new XmlTextReader (replacementText, xmlReaderNodeType, ParserContext);
 			}
 			}
 			nextEntityReader.XmlResolver = resolver;
 			nextEntityReader.XmlResolver = resolver;
 			nextEntityReader.MaybeTextDecl = true;
 			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 {
 		public override string Prefix {
 			get {
 			get {
 				if (currentTextValue != null)
 				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)
 		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)
 		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);
 			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)
 		public XmlElement CreateElement (string name)
@@ -800,15 +800,28 @@ namespace System.Xml
 					break;
 					break;
 
 
 				case XmlNodeType.DocumentType:
 				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;
 					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
 					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;
 					break;
 
 
 				case XmlNodeType.EntityReference:
 				case XmlNodeType.EntityReference:

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

@@ -16,10 +16,10 @@ namespace System.Xml
 	public class XmlDocumentType  : XmlLinkedNode
 	public class XmlDocumentType  : XmlLinkedNode
 	{
 	{
 		// Fields
 		// 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 entities;
 		internal XmlNamedNodeMap notations;
 		internal XmlNamedNodeMap notations;
 		DTDObjectModel dtd;
 		DTDObjectModel dtd;
@@ -30,11 +30,6 @@ namespace System.Xml
 						    XmlDocument doc)
 						    XmlDocument doc)
 			: base (doc)
 			: base (doc)
 		{
 		{
-			this.name = name;
-			this.publicId = publicId;
-			this.systemId = systemId;
-			this.internalSubset = internalSubset;
-
 			XmlTextReader xtr = new XmlTextReader (BaseURI, new StringReader (""), doc.NameTable);
 			XmlTextReader xtr = new XmlTextReader (BaseURI, new StringReader (""), doc.NameTable);
 			xtr.XmlResolver = doc.Resolver;
 			xtr.XmlResolver = doc.Resolver;
 			xtr.GenerateDTDObjectModel (name, publicId, systemId, internalSubset);
 			xtr.GenerateDTDObjectModel (name, publicId, systemId, internalSubset);
@@ -43,15 +38,10 @@ namespace System.Xml
 			ImportFromDTD ();
 			ImportFromDTD ();
 		}
 		}
 
 
-		internal XmlDocumentType (XmlTextReader reader, XmlDocument doc)
+		internal XmlDocumentType (DTDObjectModel dtd, XmlDocument doc)
 			: base (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 ();
 			ImportFromDTD ();
 		}
 		}
 
 
@@ -86,7 +76,7 @@ namespace System.Xml
 			
 			
 		public string InternalSubset
 		public string InternalSubset
 		{
 		{
-			get { return internalSubset; }
+			get { return dtd.InternalSubset; }
 		}
 		}
 
 
 		public override bool IsReadOnly
 		public override bool IsReadOnly
@@ -96,12 +86,12 @@ namespace System.Xml
 
 
 		public override string LocalName
 		public override string LocalName
 		{
 		{
-			get { return name; }
+			get { return dtd.Name; }
 		}
 		}
 
 
 		public override string Name
 		public override string Name
 		{
 		{
-			get { return name; }
+			get { return dtd.Name; }
 		}
 		}
 
 
 		public override XmlNodeType NodeType
 		public override XmlNodeType NodeType
@@ -116,20 +106,21 @@ namespace System.Xml
 
 
 		public string PublicId
 		public string PublicId
 		{
 		{
-			get { return publicId; }
+			get { return dtd.PublicId; }
 		}
 		}
 
 
 		public string SystemId
 		public string SystemId
 		{
 		{
-			get { return systemId; }
+			get { return dtd.SystemId; }
 		}
 		}
 
 
 		// Methods
 		// Methods
 		public override XmlNode CloneNode (bool deep)
 		public override XmlNode CloneNode (bool deep)
 		{
 		{
 			// deep is ignored
 			// 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)
 		public override void WriteContentTo (XmlWriter w)
@@ -139,7 +130,7 @@ namespace System.Xml
 
 
 		public override void WriteTo (XmlWriter w)
 		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);
 		public abstract XmlNode CloneNode (bool deep);
 
 
-		[MonoTODO]
 		public XPathNavigator CreateNavigator ()
 		public XPathNavigator CreateNavigator ()
 		{
 		{
 			XmlDocument document = this.NodeType == XmlNodeType.Document ?
 			XmlDocument document = this.NodeType == XmlNodeType.Document ?
@@ -347,7 +346,6 @@ namespace System.Xml
 			return InsertBefore (newChild, argNode);
 			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)
 		public virtual XmlNode InsertBefore (XmlNode newChild, XmlNode refChild)
 		{
 		{
 			XmlDocument ownerDoc = (NodeType == XmlNodeType.Document) ? (XmlDocument)this : OwnerDocument;
 			XmlDocument ownerDoc = (NodeType == XmlNodeType.Document) ? (XmlDocument)this : OwnerDocument;
@@ -552,7 +550,7 @@ namespace System.Xml
 			return SelectNodes (xpath, null);
 			return SelectNodes (xpath, null);
 		}
 		}
 
 
-		[MonoTODO]
+		[MonoTODO ("return nodes in document order")]
 		public XmlNodeList SelectNodes (string xpath, XmlNamespaceManager nsmgr)
 		public XmlNodeList SelectNodes (string xpath, XmlNamespaceManager nsmgr)
 		{
 		{
 			XPathNavigator nav = CreateNavigator ();
 			XPathNavigator nav = CreateNavigator ();
@@ -586,11 +584,6 @@ namespace System.Xml
 			return ((XmlDocumentNavigator) iter.Current).Node;
 			return ((XmlDocumentNavigator) iter.Current).Node;
 		}
 		}
 
 
-//		internal void SetParentNode (XmlNode parent)
-//		{
-//			parentNode = parent;
-//		}
-
 		[MonoTODO]
 		[MonoTODO]
 		public virtual bool Supports (string feature, string version)
 		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; }
 			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 {
 		public int LineNumber {
 			get { return line; }
 			get { return line; }
 		}
 		}

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

@@ -19,6 +19,7 @@
 
 
 using System;
 using System;
 using System.Collections;
 using System.Collections;
+using System.Collections.Specialized;
 using System.IO;
 using System.IO;
 using System.Text;
 using System.Text;
 using System.Xml.Schema;
 using System.Xml.Schema;
@@ -1010,16 +1011,9 @@ namespace System.Xml
 				popScope = false;
 				popScope = false;
 			}
 			}
 
 
-			if (returnEntityReference) {
+			if (returnEntityReference)
 				SetEntityReferenceProperties ();
 				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 ()) {
     				switch (PeekChar ()) {
 				case '<':
 				case '<':
 					ReadChar ();
 					ReadChar ();
@@ -1061,6 +1055,18 @@ namespace System.Xml
 
 
 		private void SetEntityReferenceProperties ()
 		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 (
 			SetProperties (
 				XmlNodeType.EntityReference, // nodeType
 				XmlNodeType.EntityReference, // nodeType
 				entityReferenceName, // name
 				entityReferenceName, // name
@@ -1358,23 +1364,23 @@ namespace System.Xml
 				throw new XmlException (this as IXmlLineInfo,
 				throw new XmlException (this as IXmlLineInfo,
 					"Invalid entity reference name was found.");
 					"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
 		// The reader is positioned on the first character of
@@ -1444,9 +1450,7 @@ namespace System.Xml
 					if (XmlChar.GetPredefinedEntity (entName) == 0) {
 					if (XmlChar.GetPredefinedEntity (entName) == 0) {
 						DTDEntityDeclaration entDecl = 
 						DTDEntityDeclaration entDecl = 
 							DTD == null ? null : DTD.EntityDecls [entName];
 							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,
 							throw new XmlException (this as IXmlLineInfo,
 								"Reference to external entities is not allowed in attribute value.");
 								"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.";
 						message = "Version 1.0 declaration is required in Text Declaration.";
 					currentCheck = 1;
 					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)
 			if (message != null)
 				throw new XmlException (this as IXmlLineInfo, message);
 				throw new XmlException (this as IXmlLineInfo, message);
@@ -1699,8 +1703,8 @@ namespace System.Xml
 			currentState = XmlNodeType.DocumentType;
 			currentState = XmlNodeType.DocumentType;
 
 
 			string doctypeName = null;
 			string doctypeName = null;
-			string publicId = String.Empty;
-			string systemId = String.Empty;
+			string publicId = null;
+			string systemId = null;
 			int intSubsetStartLine = 0;
 			int intSubsetStartLine = 0;
 			int intSubsetStartColumn = 0;
 			int intSubsetStartColumn = 0;
 
 
@@ -1765,6 +1769,10 @@ namespace System.Xml
 			parserContext.Dtd = new DTDObjectModel ();	// merges both internal and external subsets in the meantime,
 			parserContext.Dtd = new DTDObjectModel ();	// merges both internal and external subsets in the meantime,
 			DTD.BaseURI = BaseURI;
 			DTD.BaseURI = BaseURI;
 			DTD.Name = name;
 			DTD.Name = name;
+			DTD.PublicId = publicId;
+			DTD.SystemId = systemId;
+			DTD.InternalSubset = internalSubset;
+			DTD.XmlResolver = resolver;
 			int originalParserDepth = parserInputStack.Count;
 			int originalParserDepth = parserInputStack.Count;
 			if (internalSubset != null && internalSubset.Length > 0) {
 			if (internalSubset != null && internalSubset.Length > 0) {
 				XmlParserInput original = currentInput;
 				XmlParserInput original = currentInput;
@@ -1787,7 +1795,6 @@ namespace System.Xml
 				} while (nodeType != XmlNodeType.None || parserInputStack.Count > originalParserDepth + 1);
 				} while (nodeType != XmlNodeType.None || parserInputStack.Count > originalParserDepth + 1);
 				PopParserInput ();
 				PopParserInput ();
 			}
 			}
-			// TODO: Check entity nesting
 
 
 			return DTD;
 			return DTD;
 		}
 		}
@@ -2002,7 +2009,18 @@ namespace System.Xml
 				// It affects on entity references' well-formedness
 				// It affects on entity references' well-formedness
 				if (this.parserInputStack.Count == 0)
 				if (this.parserInputStack.Count == 0)
 					DTD.InternalSubsetHasPEReference = true;
 					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;
 				break;
 			case '<':
 			case '<':
 				ReadChar ();
 				ReadChar ();
@@ -2060,7 +2078,7 @@ namespace System.Xml
 							TryExpandPERef ();
 							TryExpandPERef ();
 							SkipWhitespace ();
 							SkipWhitespace ();
 							if (XmlChar.IsNameChar (PeekChar ()))
 							if (XmlChar.IsNameChar (PeekChar ()))
-							ReadParameterEntityDecl ();
+								ReadParameterEntityDecl ();
 							else
 							else
 								throw new XmlException (this as IXmlLineInfo,"expected name character");
 								throw new XmlException (this as IXmlLineInfo,"expected name character");
 						}
 						}
@@ -2420,8 +2438,12 @@ namespace System.Xml
 				this.parameterEntities [peName] as DTDParameterEntityDeclaration;
 				this.parameterEntities [peName] as DTDParameterEntityDeclaration;
 			if (peDecl != null)
 			if (peDecl != null)
 				return peDecl.Value;
 				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 "";
 			return "";
 		}
 		}
 
 
@@ -2484,7 +2506,7 @@ namespace System.Xml
 			}
 			}
 			else {
 			else {
 				// literal entity
 				// literal entity
-				decl.LiteralEntityValue = ReadEntityValueDecl ();
+				ReadEntityValueDecl (decl);
 			}
 			}
 			SkipWhitespace ();
 			SkipWhitespace ();
 			// This expanding is only allowed as a non-validating parser.
 			// This expanding is only allowed as a non-validating parser.
@@ -2494,7 +2516,7 @@ namespace System.Xml
 			return decl;
 			return decl;
 		}
 		}
 
 
-		private string ReadEntityValueDecl ()
+		private void ReadEntityValueDecl (DTDEntityDeclaration decl)
 		{
 		{
 			SkipWhitespace ();
 			SkipWhitespace ();
 			// quotation char will be finally removed on unescaping
 			// quotation char will be finally removed on unescaping
@@ -2511,8 +2533,10 @@ namespace System.Xml
 					ReadChar ();
 					ReadChar ();
 					string name = ReadName ();
 					string name = ReadName ();
 					Expect (';');
 					Expect (';');
+					if (decl.IsInternalSubset)
+						throw new XmlException (this as IXmlLineInfo,
+							"Parameter entity is not allowed in internal subset entity '" + name + "'");
 					valueBuffer.Append (GetPEValue (name));
 					valueBuffer.Append (GetPEValue (name));
-					continue;
 					break;
 					break;
 				case -1:
 				case -1:
 					throw new XmlException ("unexpected end of stream.");
 					throw new XmlException ("unexpected end of stream.");
@@ -2526,7 +2550,7 @@ namespace System.Xml
 			ClearValueBuffer ();
 			ClearValueBuffer ();
 
 
 			Expect (quoteChar);
 			Expect (quoteChar);
-			return value;
+			decl.LiteralEntityValue = value;
 		}
 		}
 
 
 		private DTDAttListDeclaration ReadAttListDecl ()
 		private DTDAttListDeclaration ReadAttListDecl ()
@@ -2627,7 +2651,9 @@ namespace System.Xml
 				case 'O':
 				case 'O':
 					Expect ("OTATION");
 					Expect ("OTATION");
 					def.Datatype = XmlSchemaDatatype.FromName ("NOTATION");
 					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 ('(');
 					Expect ('(');
 					SkipWhitespace ();
 					SkipWhitespace ();
 					def.EnumeratedNotations.Add (ReadName ());		// notation name
 					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;
 		XmlResolver resolver;
 		ValidationType validationType;
 		ValidationType validationType;
 		XmlSchemaCollection schemas;
 		XmlSchemaCollection schemas;
+		DTDValidatingReader dtdReader;
 
 
 		#endregion // Fields
 		#endregion // Fields
 
 
@@ -283,6 +284,12 @@ namespace System.Xml {
 			return validatingReader.GetAttribute (localName, namespaceName);
 			return validatingReader.GetAttribute (localName, namespaceName);
 		}
 		}
 
 
+		internal XmlParserContext GetInternalParserContext ()
+		{
+			return dtdReader != null ?
+				dtdReader.ParserContext : null;
+		}
+
 		bool IXmlLineInfo.HasLineInfo ()
 		bool IXmlLineInfo.HasLineInfo ()
 		{
 		{
 			IXmlLineInfo info = validatingReader as IXmlLineInfo;
 			IXmlLineInfo info = validatingReader as IXmlLineInfo;
@@ -337,19 +344,17 @@ namespace System.Xml {
 			if (ReadState == ReadState.Initial) {
 			if (ReadState == ReadState.Initial) {
 				switch (ValidationType) {
 				switch (ValidationType) {
 				case ValidationType.Auto:
 				case ValidationType.Auto:
+				case ValidationType.None:
 					if (schemas.Count > 0)
 					if (schemas.Count > 0)
 						goto case ValidationType.Schema;
 						goto case ValidationType.Schema;
 					else
 					else
 						goto case ValidationType.DTD;
 						goto case ValidationType.DTD;
-				case ValidationType.None:
-					validatingReader = // new XmlSchemaValidatingReader (
-						new DTDValidatingReader (sourceReader, this);
-					break;
 				case ValidationType.DTD:
 				case ValidationType.DTD:
-					validatingReader = new DTDValidatingReader (sourceReader, this);
+					validatingReader = dtdReader = new DTDValidatingReader (sourceReader, this);
 					break;
 					break;
 				case ValidationType.Schema:
 				case ValidationType.Schema:
-//					validatingReader = new XmlSchemaValidatingReader (sourceReader, this);
+//					dtdReader = new DTDValidatingReader (sourceReader, this);
+//					validatingReader = new XmlSchemaValidatingReader (dtdReader, this);
 //					break;
 //					break;
 				case ValidationType.XDR:
 				case ValidationType.XDR:
 					throw new NotImplementedException ();
 					throw new NotImplementedException ();