408 lines
10 KiB
C#
408 lines
10 KiB
C#
//
|
|
// System.Xml.XmlNodeReader2.cs - splitted XmlNodeReader that manages entities.
|
|
//
|
|
// Author:
|
|
// Duncan Mak (duncan@ximian.com)
|
|
// Atsushi Enomoto (ginga@kit.hi-ho.ne.jp)
|
|
//
|
|
// (C) Ximian, Inc.
|
|
// (C) Atsushi Enomoto
|
|
//
|
|
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining
|
|
// a copy of this software and associated documentation files (the
|
|
// "Software"), to deal in the Software without restriction, including
|
|
// without limitation the rights to use, copy, modify, merge, publish,
|
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
|
// permit persons to whom the Software is furnished to do so, subject to
|
|
// the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be
|
|
// included in all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
//
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Xml;
|
|
using System.Xml.Schema;
|
|
using System.Text;
|
|
using Mono.Xml;
|
|
|
|
namespace System.Xml
|
|
{
|
|
public class XmlNodeReader : XmlReader, IHasXmlParserContext, IXmlNamespaceResolver
|
|
{
|
|
XmlReader entity;
|
|
XmlNodeReaderImpl source;
|
|
bool entityInsideAttribute;
|
|
bool insideAttribute;
|
|
|
|
#region Constructor
|
|
|
|
public XmlNodeReader (XmlNode node)
|
|
{
|
|
source = new XmlNodeReaderImpl (node);
|
|
}
|
|
|
|
private XmlNodeReader (XmlNodeReaderImpl entityContainer, bool insideAttribute)
|
|
{
|
|
source = new XmlNodeReaderImpl (entityContainer);
|
|
this.entityInsideAttribute = insideAttribute;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Properties
|
|
|
|
private XmlReader Current {
|
|
get { return entity != null && entity.ReadState != ReadState.Initial ? entity : source; }
|
|
}
|
|
|
|
public override int AttributeCount {
|
|
get { return Current.AttributeCount; }
|
|
}
|
|
|
|
public override string BaseURI {
|
|
get { return Current.BaseURI; }
|
|
}
|
|
|
|
public override bool CanReadBinaryContent {
|
|
get { return true; }
|
|
}
|
|
|
|
/*
|
|
public override bool CanReadValueChunk {
|
|
get { return true; }
|
|
}
|
|
*/
|
|
|
|
public override bool CanResolveEntity {
|
|
get { return true; }
|
|
}
|
|
|
|
public override int Depth {
|
|
get {
|
|
// On EndEntity, depth is the same as that
|
|
// of EntityReference.
|
|
if (entity != null && entity.ReadState == ReadState.Interactive)
|
|
return source.Depth + entity.Depth + 1;
|
|
else
|
|
return source.Depth;
|
|
}
|
|
}
|
|
|
|
public override bool EOF {
|
|
get { return source.EOF; }
|
|
}
|
|
|
|
public override bool HasAttributes {
|
|
get { return Current.HasAttributes; }
|
|
}
|
|
|
|
public override bool HasValue {
|
|
get { return Current.HasValue; }
|
|
}
|
|
|
|
public override bool IsDefault {
|
|
get { return Current.IsDefault; }
|
|
}
|
|
|
|
public override bool IsEmptyElement {
|
|
get { return Current.IsEmptyElement; }
|
|
}
|
|
|
|
|
|
public override string LocalName {
|
|
get { return Current.LocalName; }
|
|
}
|
|
|
|
public override string Name {
|
|
get { return Current.Name; }
|
|
}
|
|
|
|
public override string NamespaceURI {
|
|
get { return Current.NamespaceURI; }
|
|
}
|
|
|
|
public override XmlNameTable NameTable {
|
|
get { return Current.NameTable; }
|
|
}
|
|
|
|
public override XmlNodeType NodeType {
|
|
get {
|
|
if (entity != null)
|
|
return entity.ReadState == ReadState.Initial ?
|
|
source.NodeType :
|
|
entity.EOF ? XmlNodeType.EndEntity :
|
|
entity.NodeType;
|
|
else
|
|
return source.NodeType;
|
|
}
|
|
}
|
|
|
|
XmlParserContext IHasXmlParserContext.ParserContext {
|
|
get { return ((IHasXmlParserContext) Current).ParserContext; }
|
|
}
|
|
|
|
public override string Prefix {
|
|
get { return Current.Prefix; }
|
|
}
|
|
|
|
|
|
public override ReadState ReadState {
|
|
get { return entity != null ? ReadState.Interactive : source.ReadState; }
|
|
}
|
|
|
|
public override IXmlSchemaInfo SchemaInfo {
|
|
get { return entity != null ? entity.SchemaInfo : source.SchemaInfo; }
|
|
}
|
|
|
|
public override string Value {
|
|
get { return Current.Value; }
|
|
}
|
|
|
|
public override string XmlLang {
|
|
get { return Current.XmlLang; }
|
|
}
|
|
|
|
public override XmlSpace XmlSpace {
|
|
get { return Current.XmlSpace; }
|
|
}
|
|
#endregion
|
|
|
|
#region Methods
|
|
|
|
// If current entityReference is a child of an attribute,
|
|
// then MoveToAttribute simply means that we no more need this entity Current.
|
|
// Otherwise, this invokation means that
|
|
// it is expected to move to resolved (maybe) element's attribute.
|
|
//
|
|
// This rule applies to many methods like MoveTo*Attribute().
|
|
|
|
public override void Close ()
|
|
{
|
|
if (entity != null)
|
|
entity.Close ();
|
|
source.Close ();
|
|
}
|
|
|
|
public override string GetAttribute (int attributeIndex)
|
|
{
|
|
return Current.GetAttribute (attributeIndex);
|
|
}
|
|
|
|
public override string GetAttribute (string name)
|
|
{
|
|
return Current.GetAttribute (name);
|
|
}
|
|
|
|
public override string GetAttribute (string name, string namespaceURI)
|
|
{
|
|
return Current.GetAttribute (name, namespaceURI);
|
|
}
|
|
|
|
IDictionary<string, string> IXmlNamespaceResolver.GetNamespacesInScope (XmlNamespaceScope scope)
|
|
{
|
|
return ((IXmlNamespaceResolver) Current).GetNamespacesInScope (scope);
|
|
}
|
|
|
|
public override string LookupNamespace (string prefix)
|
|
{
|
|
return Current.LookupNamespace (prefix);
|
|
}
|
|
|
|
string IXmlNamespaceResolver.LookupPrefix (string ns)
|
|
{
|
|
return ((IXmlNamespaceResolver) Current).LookupPrefix (ns);
|
|
}
|
|
|
|
public override void MoveToAttribute (int attributeIndex)
|
|
{
|
|
if (entity != null && entityInsideAttribute) {
|
|
entity.Close ();
|
|
entity = null;
|
|
}
|
|
Current.MoveToAttribute (attributeIndex);
|
|
insideAttribute = true;
|
|
}
|
|
|
|
public override bool MoveToAttribute (string name)
|
|
{
|
|
if (entity != null && !entityInsideAttribute)
|
|
return entity.MoveToAttribute (name);
|
|
if (!source.MoveToAttribute (name))
|
|
return false;
|
|
if (entity != null && entityInsideAttribute) {
|
|
entity.Close ();
|
|
entity = null;
|
|
}
|
|
insideAttribute = true;
|
|
return true;
|
|
}
|
|
|
|
public override bool MoveToAttribute (string name, string namespaceURI)
|
|
{
|
|
if (entity != null && !entityInsideAttribute)
|
|
return entity.MoveToAttribute (name, namespaceURI);
|
|
if (!source.MoveToAttribute (name, namespaceURI))
|
|
return false;
|
|
if (entity != null && entityInsideAttribute) {
|
|
entity.Close ();
|
|
entity = null;
|
|
}
|
|
insideAttribute = true;
|
|
return true;
|
|
}
|
|
|
|
public override bool MoveToElement ()
|
|
{
|
|
if (entity != null && entityInsideAttribute)
|
|
entity = null;
|
|
if (!Current.MoveToElement ())
|
|
return false;
|
|
insideAttribute = false;
|
|
return true;
|
|
}
|
|
|
|
public override bool MoveToFirstAttribute ()
|
|
{
|
|
if (entity != null && !entityInsideAttribute)
|
|
return entity.MoveToFirstAttribute ();
|
|
if (!source.MoveToFirstAttribute ())
|
|
return false;
|
|
if (entity != null && entityInsideAttribute) {
|
|
entity.Close ();
|
|
entity = null;
|
|
}
|
|
insideAttribute = true;
|
|
return true;
|
|
}
|
|
|
|
public override bool MoveToNextAttribute ()
|
|
{
|
|
if (entity != null && !entityInsideAttribute)
|
|
return entity.MoveToNextAttribute ();
|
|
if (!source.MoveToNextAttribute ())
|
|
return false;
|
|
if (entity != null && entityInsideAttribute) {
|
|
entity.Close ();
|
|
entity = null;
|
|
}
|
|
insideAttribute = true;
|
|
return true;
|
|
}
|
|
|
|
public override bool Read ()
|
|
{
|
|
insideAttribute = false;
|
|
if (entity != null && (entityInsideAttribute || entity.EOF))
|
|
entity = null;
|
|
if (entity != null) {
|
|
entity.Read ();
|
|
return true; // either success or EndEntity
|
|
}
|
|
else
|
|
return source.Read ();
|
|
}
|
|
|
|
public override bool ReadAttributeValue ()
|
|
{
|
|
if (entity != null && entityInsideAttribute) {
|
|
if (entity.EOF)
|
|
entity = null;
|
|
else {
|
|
entity.Read ();
|
|
return true; // either success or EndEntity
|
|
}
|
|
}
|
|
return Current.ReadAttributeValue ();
|
|
}
|
|
|
|
public override int ReadContentAsBase64 (byte [] buffer, int index, int count)
|
|
{
|
|
// return base.ReadContentAsBase64 (
|
|
// buffer, offset, length);
|
|
// FIXME: This is problematic wrt end of entity.
|
|
if (entity != null)
|
|
return entity.ReadContentAsBase64 (
|
|
buffer, index, count);
|
|
else
|
|
return source.ReadContentAsBase64 (
|
|
buffer, index, count);
|
|
}
|
|
|
|
public override int ReadContentAsBinHex (byte [] buffer, int index, int count)
|
|
{
|
|
// return base.ReadContentAsBinHex (
|
|
// buffer, offset, length);
|
|
// FIXME: This is problematic wrt end of entity.
|
|
if (entity != null)
|
|
return entity.ReadContentAsBinHex (
|
|
buffer, index, count);
|
|
else
|
|
return source.ReadContentAsBinHex (
|
|
buffer, index, count);
|
|
}
|
|
|
|
public override int ReadElementContentAsBase64 (byte [] buffer, int index, int count)
|
|
{
|
|
// return base.ReadElementContentAsBase64 (
|
|
// buffer, index, count);
|
|
// FIXME: This is problematic wrt end of entity.
|
|
if (entity != null)
|
|
return entity.ReadElementContentAsBase64 (
|
|
buffer, index, count);
|
|
else
|
|
return source.ReadElementContentAsBase64 (
|
|
buffer, index, count);
|
|
}
|
|
|
|
public override int ReadElementContentAsBinHex (
|
|
byte [] buffer, int index, int count)
|
|
{
|
|
// return base.ReadElementContentAsBinHex (
|
|
// buffer, index, count);
|
|
// FIXME: This is problematic wrt end of entity.
|
|
if (entity != null)
|
|
return entity.ReadElementContentAsBinHex (
|
|
buffer, index, count);
|
|
else
|
|
return source.ReadElementContentAsBinHex (
|
|
buffer, index, count);
|
|
}
|
|
|
|
public override string ReadString ()
|
|
{
|
|
return base.ReadString ();
|
|
}
|
|
|
|
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");
|
|
entity = new XmlNodeReader (source, insideAttribute);
|
|
}
|
|
}
|
|
|
|
public override void Skip ()
|
|
{
|
|
if (entity != null && entityInsideAttribute)
|
|
entity = null;
|
|
Current.Skip ();
|
|
}
|
|
#endregion
|
|
}
|
|
}
|