namespace System.Xml
{
+ // FIXME: this implementation requires somewhat significant change
+ // to expand entities and merge sequential text and entity references
+ // especially to handle whitespace-only entities (such as bug #372839).
+ //
+ // To do it, we have to read ahead the next node when the input is
+ // text, whitespace or significant whitespace and check if the next
+ // node is EntityReference. If it is entref, then it have to merge
+ // the input entity if it is a text.
+ //
+ // This "read ahead" operation may result in proceeding to the next
+ // element, which badly affects IXmlNamespaceResolverimplementation.
+ // So we cannot fix this in simple way.
+
[PermissionSet (SecurityAction.InheritanceDemand, Unrestricted = true)]
public class XmlTextReader : XmlReader,
IXmlLineInfo, IXmlNamespaceResolver, IHasXmlParserContext
{
XmlTextReader entity;
- XmlTextReaderImpl source;
+ XmlTextReaderImpl source; // dtd2xsd expects this field's existence.
bool entityInsideAttribute;
bool insideAttribute;
- string cachedAttributeValue;
- bool attributeValueConsumed;
+ Stack<string> entityNameStack;
protected XmlTextReader ()
{
source = new XmlTextReaderImpl (baseURI, xmlFragment, fragType, context);
}
- internal XmlTextReader (bool dummy, string url, XmlNodeType fragType, XmlParserContext context)
+ internal XmlTextReader (bool dummy, XmlResolver resolver, string url, XmlNodeType fragType, XmlParserContext context)
{
- source = new XmlTextReaderImpl (dummy, url, fragType, context);
+ source = new XmlTextReaderImpl (dummy, resolver, url, fragType, context);
}
private XmlTextReader (XmlTextReaderImpl entityContainer, bool insideAttribute)
public override XmlNodeType NodeType {
get {
- if (Current == entity)
- return entity.EOF ? XmlNodeType.EndEntity : entity.NodeType;
+ if (entity != null)
+ return entity.ReadState == ReadState.Initial ?
+ source.NodeType :
+ entity.EOF ? XmlNodeType.EndEntity :
+ entity.NodeType;
else
return source.NodeType;
}
}
internal ConformanceLevel Conformance {
+ get { return source.Conformance; }
set {
if (entity != null)
entity.Conformance = value;
source.SetNameTable (nameTable);
}
+ internal void SkipTextDeclaration ()
+ {
+ if (entity != null)
+ entity.SkipTextDeclaration ();
+ else
+ source.SkipTextDeclaration ();
+ }
+
// overrides
public override void Close ()
public override void MoveToAttribute (int i)
{
- if (entity != null && entityInsideAttribute) {
- entity.Close ();
- entity = null;
- }
+ if (entity != null && entityInsideAttribute)
+ CloseEntity ();
Current.MoveToAttribute (i);
insideAttribute = true;
}
return entity.MoveToAttribute (name);
if (!source.MoveToAttribute (name))
return false;
- if (entity != null && entityInsideAttribute) {
- entity.Close ();
- entity = null;
- }
+ if (entity != null && entityInsideAttribute)
+ CloseEntity ();
insideAttribute = true;
return true;
}
return entity.MoveToAttribute (localName, namespaceName);
if (!source.MoveToAttribute (localName, namespaceName))
return false;
- if (entity != null && entityInsideAttribute) {
- entity.Close ();
- entity = null;
- }
+ if (entity != null && entityInsideAttribute)
+ CloseEntity ();
insideAttribute = true;
return true;
}
public override bool MoveToElement ()
{
- if (entity != null && entityInsideAttribute) {
- entity.Close ();
- entity = null;
- }
+ if (entity != null && entityInsideAttribute)
+ CloseEntity ();
if (!Current.MoveToElement ())
return false;
insideAttribute = false;
return entity.MoveToFirstAttribute ();
if (!source.MoveToFirstAttribute ())
return false;
- if (entity != null && entityInsideAttribute) {
- entity.Close ();
- entity = null;
- }
+ if (entity != null && entityInsideAttribute)
+ CloseEntity ();
insideAttribute = true;
return true;
}
return entity.MoveToNextAttribute ();
if (!source.MoveToNextAttribute ())
return false;
- if (entity != null && entityInsideAttribute) {
- entity.Close ();
- entity = null;
- }
+ if (entity != null && entityInsideAttribute)
+ CloseEntity ();
insideAttribute = true;
return true;
}
{
insideAttribute = false;
- if (entity != null && (entityInsideAttribute || entity.EOF)) {
- entity.Close ();
- entity = null;
- }
+ if (entity != null && (entityInsideAttribute || entity.EOF))
+ CloseEntity ();
if (entity != null) {
if (entity.Read ())
return true;
if (EntityHandling == EntityHandling.ExpandEntities) {
// EndEntity must be skipped
- entity.Close ();
- entity = null;
+ CloseEntity ();
return Read ();
}
else
public override bool ReadAttributeValue ()
{
if (entity != null && entityInsideAttribute) {
- if (entity.EOF) {
- entity.Close ();
- entity = null;
- }
+ if (entity.EOF)
+ CloseEntity ();
else {
entity.Read ();
return true; // either success or EndEntity
public void ResetState ()
{
if (entity != null)
- entity.ResetState ();
+ CloseEntity ();
source.ResetState ();
}
- public override void ResolveEntity ()
+ public override
+ void ResolveEntity ()
{
if (entity != null)
entity.ResolveEntity ();
else {
if (source.NodeType != XmlNodeType.EntityReference)
throw new InvalidOperationException ("The current node is not an Entity Reference");
- XmlTextReaderImpl entReader =
- ParserContext.Dtd.GenerateEntityContentReader (source.Name, ParserContext);
+ XmlTextReaderImpl entReader = null;
+ if (ParserContext.Dtd != null)
+ entReader = ParserContext.Dtd.GenerateEntityContentReader (source.Name, ParserContext);
if (entReader == null)
throw new XmlException (this as IXmlLineInfo, this.BaseURI, String.Format ("Reference to undeclared entity '{0}'.", source.Name));
+ if (entityNameStack == null)
+ entityNameStack = new Stack<string> ();
+ else if (entityNameStack.Contains (Name))
+ throw new XmlException (String.Format ("General entity '{0}' has an invalid recursive reference to itself.", Name));
+ entityNameStack.Push (Name);
entity = new XmlTextReader (
entReader, insideAttribute);
+ entity.entityNameStack = entityNameStack;
entity.CopyProperties (this);
}
}
+ void CloseEntity ()
+ {
+ entity.Close ();
+ entity = null;
+ entityNameStack.Pop ();
+ }
+
public override void Skip ()
{
base.Skip ();
}
- [MonoTODO ("Check how expanded entity is handled here.")]
+ [MonoTODO] // FIXME: Check how expanded entity is handled here.
public TextReader GetRemainder ()
{
if (entity != null) {
entity.Close ();
entity = null;
+ entityNameStack.Pop ();
}
return source.GetRemainder ();
}
return true;
}
- [MonoTODO ("Check how expanded entity is handled here.")]
+ [MonoTODO] // FIXME: Check how expanded entity is handled here.
public int ReadBase64 (byte [] buffer, int offset, int length)
{
if (entity != null)
return source.ReadBase64 (buffer, offset, length);
}
- [MonoTODO ("Check how expanded entity is handled here.")]
+ [MonoTODO] // FIXME: Check how expanded entity is handled here.
public int ReadBinHex (byte [] buffer, int offset, int length)
{
if (entity != null)
return source.ReadBinHex (buffer, offset, length);
}
- [MonoTODO ("Check how expanded entity is handled here.")]
+ [MonoTODO] // FIXME: Check how expanded entity is handled here.
public int ReadChars (char [] buffer, int offset, int length)
{
if (entity != null)
}
- [MonoTODO ("Check how expanded entity is handled here.")]
+ [MonoTODO] // FIXME: Check how expanded entity is handled here.
public override int ReadContentAsBase64 (byte [] buffer, int offset, int length)
{
if (entity != null)
return source.ReadContentAsBase64 (buffer, offset, length);
}
- [MonoTODO ("Check how expanded entity is handled here.")]
+ [MonoTODO] // FIXME: Check how expanded entity is handled here.
public override int ReadContentAsBinHex (byte [] buffer, int offset, int length)
{
if (entity != null)
return source.ReadContentAsBinHex (buffer, offset, length);
}
- [MonoTODO ("Check how expanded entity is handled here.")]
+ [MonoTODO] // FIXME: Check how expanded entity is handled here.
public override int ReadElementContentAsBase64 (byte [] buffer, int offset, int length)
{
if (entity != null)
return source.ReadElementContentAsBase64 (buffer, offset, length);
}
- [MonoTODO ("Check how expanded entity is handled here.")]
+ [MonoTODO] // FIXME: Check how expanded entity is handled here.
public override int ReadElementContentAsBinHex (byte [] buffer, int offset, int length)
{
if (entity != null)