e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
2649 lines
93 KiB
C#
2649 lines
93 KiB
C#
//------------------------------------------------------------
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//------------------------------------------------------------
|
|
namespace System.Xml
|
|
{
|
|
using System.Globalization;
|
|
using System.IO;
|
|
using System.Runtime;
|
|
using System.Runtime.Serialization;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
|
|
abstract class XmlBaseWriter : XmlDictionaryWriter, IFragmentCapableXmlDictionaryWriter
|
|
{
|
|
XmlNodeWriter writer;
|
|
NamespaceManager nsMgr;
|
|
Element[] elements;
|
|
int depth;
|
|
string attributeLocalName;
|
|
string attributeValue;
|
|
bool isXmlAttribute;
|
|
bool isXmlnsAttribute;
|
|
WriteState writeState;
|
|
DocumentState documentState;
|
|
byte[] trailBytes;
|
|
int trailByteCount;
|
|
XmlStreamNodeWriter nodeWriter;
|
|
XmlSigningNodeWriter signingWriter;
|
|
XmlUTF8NodeWriter textFragmentWriter;
|
|
XmlNodeWriter oldWriter;
|
|
Stream oldStream;
|
|
int oldNamespaceBoundary;
|
|
bool inList;
|
|
const string xmlnsNamespace = "http://www.w3.org/2000/xmlns/";
|
|
const string xmlNamespace = "http://www.w3.org/XML/1998/namespace";
|
|
static BinHexEncoding binhexEncoding;
|
|
static string[] prefixes = { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z" };
|
|
XmlBaseWriterNodeWriterAsyncHelper nodeWriterAsyncHelper;
|
|
|
|
protected XmlBaseWriter()
|
|
{
|
|
this.nsMgr = new NamespaceManager();
|
|
this.writeState = WriteState.Start;
|
|
this.documentState = DocumentState.None;
|
|
}
|
|
|
|
protected void SetOutput(XmlStreamNodeWriter writer)
|
|
{
|
|
this.inList = false;
|
|
this.writer = writer;
|
|
this.nodeWriter = writer;
|
|
this.writeState = WriteState.Start;
|
|
this.documentState = DocumentState.None;
|
|
this.nsMgr.Clear();
|
|
if (this.depth != 0)
|
|
{
|
|
this.elements = null;
|
|
this.depth = 0;
|
|
}
|
|
this.attributeLocalName = null;
|
|
this.attributeValue = null;
|
|
this.oldWriter = null;
|
|
this.oldStream = null;
|
|
}
|
|
|
|
public override void Flush()
|
|
{
|
|
if (IsClosed)
|
|
ThrowClosed();
|
|
|
|
writer.Flush();
|
|
}
|
|
|
|
public override void Close()
|
|
{
|
|
if (IsClosed)
|
|
return;
|
|
|
|
try
|
|
{
|
|
FinishDocument();
|
|
AutoComplete(WriteState.Closed);
|
|
writer.Flush();
|
|
}
|
|
finally
|
|
{
|
|
nsMgr.Close();
|
|
if (depth != 0)
|
|
{
|
|
elements = null;
|
|
depth = 0;
|
|
}
|
|
attributeValue = null;
|
|
attributeLocalName = null;
|
|
nodeWriter.Close();
|
|
if (signingWriter != null)
|
|
{
|
|
signingWriter.Close();
|
|
}
|
|
if (textFragmentWriter != null)
|
|
{
|
|
textFragmentWriter.Close();
|
|
}
|
|
oldWriter = null;
|
|
oldStream = null;
|
|
}
|
|
}
|
|
|
|
protected bool IsClosed
|
|
{
|
|
get { return writeState == WriteState.Closed; }
|
|
}
|
|
|
|
protected void ThrowClosed()
|
|
{
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlWriterClosed)));
|
|
}
|
|
|
|
static BinHexEncoding BinHexEncoding
|
|
{
|
|
get
|
|
{
|
|
if (binhexEncoding == null)
|
|
binhexEncoding = new BinHexEncoding();
|
|
return binhexEncoding;
|
|
}
|
|
}
|
|
|
|
public override string XmlLang
|
|
{
|
|
get
|
|
{
|
|
return nsMgr.XmlLang;
|
|
}
|
|
}
|
|
|
|
public override XmlSpace XmlSpace
|
|
{
|
|
get
|
|
{
|
|
return nsMgr.XmlSpace;
|
|
}
|
|
}
|
|
|
|
public override WriteState WriteState
|
|
{
|
|
get
|
|
{
|
|
return writeState;
|
|
}
|
|
}
|
|
|
|
public override void WriteXmlnsAttribute(string prefix, string ns)
|
|
{
|
|
if (IsClosed)
|
|
ThrowClosed();
|
|
|
|
if (ns == null)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("ns");
|
|
|
|
if (writeState != WriteState.Element)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlInvalidWriteState, "WriteXmlnsAttribute", WriteState.ToString())));
|
|
|
|
if (prefix == null)
|
|
{
|
|
prefix = nsMgr.LookupPrefix(ns);
|
|
if (prefix == null)
|
|
{
|
|
GeneratePrefix(ns, null);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
nsMgr.AddNamespaceIfNotDeclared(prefix, ns, null);
|
|
}
|
|
}
|
|
|
|
public override void WriteXmlnsAttribute(string prefix, XmlDictionaryString ns)
|
|
{
|
|
if (IsClosed)
|
|
ThrowClosed();
|
|
|
|
if (ns == null)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("ns");
|
|
|
|
if (writeState != WriteState.Element)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlInvalidWriteState, "WriteXmlnsAttribute", WriteState.ToString())));
|
|
|
|
if (prefix == null)
|
|
{
|
|
prefix = nsMgr.LookupPrefix(ns.Value);
|
|
if (prefix == null)
|
|
{
|
|
GeneratePrefix(ns.Value, ns);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
nsMgr.AddNamespaceIfNotDeclared(prefix, ns.Value, ns);
|
|
}
|
|
}
|
|
|
|
void StartAttribute(ref string prefix, string localName, string ns, XmlDictionaryString xNs)
|
|
{
|
|
if (IsClosed)
|
|
ThrowClosed();
|
|
|
|
if (writeState == WriteState.Attribute)
|
|
WriteEndAttribute();
|
|
|
|
if (localName == null || (localName.Length == 0 && prefix != "xmlns"))
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("localName"));
|
|
|
|
if (writeState != WriteState.Element)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlInvalidWriteState, "WriteStartAttribute", WriteState.ToString())));
|
|
|
|
if (prefix == null)
|
|
{
|
|
if (ns == xmlnsNamespace && localName != "xmlns")
|
|
prefix = "xmlns";
|
|
else if (ns == xmlNamespace)
|
|
prefix = "xml";
|
|
else
|
|
prefix = string.Empty;
|
|
}
|
|
|
|
// Normalize a (prefix,localName) of (null, "xmlns") to ("xmlns", string.Empty).
|
|
if (prefix.Length == 0 && localName == "xmlns")
|
|
{
|
|
prefix = "xmlns";
|
|
localName = string.Empty;
|
|
}
|
|
|
|
isXmlnsAttribute = false;
|
|
isXmlAttribute = false;
|
|
if (prefix == "xml")
|
|
{
|
|
if (ns != null && ns != xmlNamespace)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.XmlPrefixBoundToNamespace, "xml", xmlNamespace, ns), "ns"));
|
|
isXmlAttribute = true;
|
|
attributeValue = string.Empty;
|
|
attributeLocalName = localName;
|
|
}
|
|
else if (prefix == "xmlns")
|
|
{
|
|
if (ns != null && ns != xmlnsNamespace)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.XmlPrefixBoundToNamespace, "xmlns", xmlnsNamespace, ns), "ns"));
|
|
isXmlnsAttribute = true;
|
|
attributeValue = string.Empty;
|
|
attributeLocalName = localName;
|
|
}
|
|
else if (ns == null)
|
|
{
|
|
// A null namespace means the namespace of the given prefix.
|
|
if (prefix.Length == 0)
|
|
{
|
|
// An empty prefix on an attribute means no namespace (not the default namespace)
|
|
ns = string.Empty;
|
|
}
|
|
else
|
|
{
|
|
ns = nsMgr.LookupNamespace(prefix);
|
|
|
|
if (ns == null)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.XmlUndefinedPrefix, prefix), "prefix"));
|
|
}
|
|
}
|
|
else if (ns.Length == 0)
|
|
{
|
|
// An empty namespace means no namespace; prefix must be empty
|
|
if (prefix.Length != 0)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.XmlEmptyNamespaceRequiresNullPrefix), "prefix"));
|
|
}
|
|
else if (prefix.Length == 0)
|
|
{
|
|
// No prefix specified - try to find a prefix corresponding to the given namespace
|
|
prefix = nsMgr.LookupAttributePrefix(ns);
|
|
|
|
// If we didn't find anything with the right namespace, generate one.
|
|
if (prefix == null)
|
|
{
|
|
// Watch for special values
|
|
if (ns.Length == xmlnsNamespace.Length && ns == xmlnsNamespace)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.XmlSpecificBindingNamespace, "xmlns", ns)));
|
|
if (ns.Length == xmlNamespace.Length && ns == xmlNamespace)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.XmlSpecificBindingNamespace, "xml", ns)));
|
|
|
|
prefix = GeneratePrefix(ns, xNs);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
nsMgr.AddNamespaceIfNotDeclared(prefix, ns, xNs);
|
|
}
|
|
writeState = WriteState.Attribute;
|
|
}
|
|
|
|
public override void WriteStartAttribute(string prefix, string localName, string namespaceUri)
|
|
{
|
|
StartAttribute(ref prefix, localName, namespaceUri, null);
|
|
if (!isXmlnsAttribute)
|
|
{
|
|
writer.WriteStartAttribute(prefix, localName);
|
|
}
|
|
}
|
|
|
|
public override void WriteStartAttribute(string prefix, XmlDictionaryString localName, XmlDictionaryString namespaceUri)
|
|
{
|
|
StartAttribute(ref prefix, (localName != null ? localName.Value : null), (namespaceUri != null ? namespaceUri.Value : null), namespaceUri);
|
|
if (!isXmlnsAttribute)
|
|
{
|
|
writer.WriteStartAttribute(prefix, localName);
|
|
}
|
|
}
|
|
|
|
public override void WriteEndAttribute()
|
|
{
|
|
if (IsClosed)
|
|
ThrowClosed();
|
|
|
|
if (writeState != WriteState.Attribute)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlInvalidWriteState, "WriteEndAttribute", WriteState.ToString())));
|
|
|
|
FlushBase64();
|
|
try
|
|
{
|
|
if (isXmlAttribute)
|
|
{
|
|
if (attributeLocalName == "lang")
|
|
{
|
|
nsMgr.AddLangAttribute(attributeValue);
|
|
}
|
|
else if (attributeLocalName == "space")
|
|
{
|
|
if (attributeValue == "preserve")
|
|
{
|
|
nsMgr.AddSpaceAttribute(XmlSpace.Preserve);
|
|
}
|
|
else if (attributeValue == "default")
|
|
{
|
|
nsMgr.AddSpaceAttribute(XmlSpace.Default);
|
|
}
|
|
else
|
|
{
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.XmlInvalidXmlSpace, attributeValue)));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// XmlTextWriter specifically allows for other localNames
|
|
}
|
|
isXmlAttribute = false;
|
|
attributeLocalName = null;
|
|
attributeValue = null;
|
|
}
|
|
|
|
if (isXmlnsAttribute)
|
|
{
|
|
nsMgr.AddNamespaceIfNotDeclared(attributeLocalName, attributeValue, null);
|
|
isXmlnsAttribute = false;
|
|
attributeLocalName = null;
|
|
attributeValue = null;
|
|
}
|
|
else
|
|
{
|
|
writer.WriteEndAttribute();
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
writeState = WriteState.Element;
|
|
}
|
|
}
|
|
|
|
public override void WriteComment(string text)
|
|
{
|
|
if (IsClosed)
|
|
ThrowClosed();
|
|
|
|
if (writeState == WriteState.Attribute)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlInvalidWriteState, "WriteComment", WriteState.ToString())));
|
|
|
|
if (text == null)
|
|
{
|
|
text = string.Empty;
|
|
}
|
|
else if (text.IndexOf("--", StringComparison.Ordinal) != -1 || (text.Length > 0 && text[text.Length - 1] == '-'))
|
|
{
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.XmlInvalidCommentChars), "text"));
|
|
}
|
|
|
|
StartComment();
|
|
FlushBase64();
|
|
writer.WriteComment(text);
|
|
EndComment();
|
|
}
|
|
|
|
public override void WriteFullEndElement()
|
|
{
|
|
if (IsClosed)
|
|
ThrowClosed();
|
|
|
|
if (writeState == WriteState.Attribute)
|
|
WriteEndAttribute();
|
|
|
|
if (writeState != WriteState.Element && writeState != WriteState.Content)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlInvalidWriteState, "WriteFullEndElement", WriteState.ToString())));
|
|
|
|
AutoComplete(WriteState.Content);
|
|
WriteEndElement();
|
|
}
|
|
|
|
public override void WriteCData(string text)
|
|
{
|
|
if (IsClosed)
|
|
ThrowClosed();
|
|
|
|
if (writeState == WriteState.Attribute)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlInvalidWriteState, "WriteCData", WriteState.ToString())));
|
|
|
|
if (text == null)
|
|
text = string.Empty;
|
|
|
|
if (text.Length > 0)
|
|
{
|
|
StartContent();
|
|
FlushBase64();
|
|
writer.WriteCData(text);
|
|
EndContent();
|
|
}
|
|
}
|
|
|
|
public override void WriteDocType(string name, string pubid, string sysid, string subset)
|
|
{
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.XmlMethodNotSupported, "WriteDocType")));
|
|
}
|
|
|
|
void StartElement(ref string prefix, string localName, string ns, XmlDictionaryString xNs)
|
|
{
|
|
if (IsClosed)
|
|
ThrowClosed();
|
|
|
|
if (this.documentState == DocumentState.Epilog)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlOnlyOneRoot)));
|
|
if (localName == null)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("localName"));
|
|
if (localName.Length == 0)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.InvalidLocalNameEmpty), "localName"));
|
|
if (writeState == WriteState.Attribute)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlInvalidWriteState, "WriteStartElement", WriteState.ToString())));
|
|
|
|
FlushBase64();
|
|
AutoComplete(WriteState.Element);
|
|
Element element = EnterScope();
|
|
if (ns == null)
|
|
{
|
|
if (prefix == null)
|
|
prefix = string.Empty;
|
|
|
|
ns = nsMgr.LookupNamespace(prefix);
|
|
|
|
if (ns == null)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.XmlUndefinedPrefix, prefix), "prefix"));
|
|
}
|
|
else if (prefix == null)
|
|
{
|
|
prefix = nsMgr.LookupPrefix(ns);
|
|
|
|
if (prefix == null)
|
|
{
|
|
prefix = string.Empty;
|
|
nsMgr.AddNamespace(string.Empty, ns, xNs);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
nsMgr.AddNamespaceIfNotDeclared(prefix, ns, xNs);
|
|
}
|
|
element.Prefix = prefix;
|
|
element.LocalName = localName;
|
|
}
|
|
|
|
public override void WriteStartElement(string prefix, string localName, string namespaceUri)
|
|
{
|
|
StartElement(ref prefix, localName, namespaceUri, null);
|
|
writer.WriteStartElement(prefix, localName);
|
|
}
|
|
|
|
public override void WriteStartElement(string prefix, XmlDictionaryString localName, XmlDictionaryString namespaceUri)
|
|
{
|
|
StartElement(ref prefix, (localName != null ? localName.Value : null), (namespaceUri != null ? namespaceUri.Value : null), namespaceUri);
|
|
writer.WriteStartElement(prefix, localName);
|
|
}
|
|
|
|
public override void WriteEndElement()
|
|
{
|
|
if (IsClosed)
|
|
ThrowClosed();
|
|
|
|
if (depth == 0)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlInvalidDepth, "WriteEndElement", depth.ToString(CultureInfo.InvariantCulture))));
|
|
|
|
if (writeState == WriteState.Attribute)
|
|
WriteEndAttribute();
|
|
|
|
FlushBase64();
|
|
if (writeState == WriteState.Element)
|
|
{
|
|
nsMgr.DeclareNamespaces(writer);
|
|
writer.WriteEndStartElement(true);
|
|
}
|
|
else
|
|
{
|
|
Element element = elements[depth];
|
|
writer.WriteEndElement(element.Prefix, element.LocalName);
|
|
}
|
|
|
|
ExitScope();
|
|
writeState = WriteState.Content;
|
|
}
|
|
|
|
Element EnterScope()
|
|
{
|
|
nsMgr.EnterScope();
|
|
depth++;
|
|
if (elements == null)
|
|
{
|
|
elements = new Element[4];
|
|
}
|
|
else if (elements.Length == depth)
|
|
{
|
|
Element[] newElementNodes = new Element[depth * 2];
|
|
Array.Copy(elements, newElementNodes, depth);
|
|
elements = newElementNodes;
|
|
}
|
|
Element element = elements[depth];
|
|
if (element == null)
|
|
{
|
|
element = new Element();
|
|
elements[depth] = element;
|
|
}
|
|
return element;
|
|
}
|
|
|
|
void ExitScope()
|
|
{
|
|
elements[depth].Clear();
|
|
depth--;
|
|
if (depth == 0 && documentState == DocumentState.Document)
|
|
this.documentState = DocumentState.Epilog;
|
|
nsMgr.ExitScope();
|
|
}
|
|
|
|
protected void FlushElement()
|
|
{
|
|
if (this.writeState == WriteState.Element)
|
|
{
|
|
AutoComplete(WriteState.Content);
|
|
}
|
|
}
|
|
|
|
protected void StartComment()
|
|
{
|
|
FlushElement();
|
|
}
|
|
|
|
protected void EndComment()
|
|
{
|
|
}
|
|
|
|
protected void StartContent()
|
|
{
|
|
FlushElement();
|
|
if (depth == 0)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlIllegalOutsideRoot)));
|
|
}
|
|
|
|
protected void StartContent(char ch)
|
|
{
|
|
FlushElement();
|
|
if (depth == 0)
|
|
VerifyWhitespace(ch);
|
|
}
|
|
|
|
protected void StartContent(string s)
|
|
{
|
|
FlushElement();
|
|
if (depth == 0)
|
|
VerifyWhitespace(s);
|
|
}
|
|
|
|
protected void StartContent(char[] chars, int offset, int count)
|
|
{
|
|
FlushElement();
|
|
if (depth == 0)
|
|
VerifyWhitespace(chars, offset, count);
|
|
}
|
|
|
|
void VerifyWhitespace(char ch)
|
|
{
|
|
if (!IsWhitespace(ch))
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlIllegalOutsideRoot)));
|
|
}
|
|
|
|
void VerifyWhitespace(string s)
|
|
{
|
|
for (int i = 0; i < s.Length; i++)
|
|
if (!IsWhitespace(s[i]))
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlIllegalOutsideRoot)));
|
|
}
|
|
|
|
void VerifyWhitespace(char[] chars, int offset, int count)
|
|
{
|
|
for (int i = 0; i < count; i++)
|
|
if (!IsWhitespace(chars[offset + i]))
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlIllegalOutsideRoot)));
|
|
}
|
|
|
|
bool IsWhitespace(char ch)
|
|
{
|
|
return (ch == ' ' || ch == '\n' || ch == '\r' || ch == 't');
|
|
}
|
|
|
|
protected void EndContent()
|
|
{
|
|
}
|
|
|
|
void AutoComplete(WriteState writeState)
|
|
{
|
|
if (this.writeState == WriteState.Element)
|
|
{
|
|
EndStartElement();
|
|
}
|
|
this.writeState = writeState;
|
|
}
|
|
|
|
void EndStartElement()
|
|
{
|
|
nsMgr.DeclareNamespaces(writer);
|
|
writer.WriteEndStartElement(false);
|
|
}
|
|
|
|
public override string LookupPrefix(string ns)
|
|
{
|
|
if (ns == null)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("ns"));
|
|
|
|
if (IsClosed)
|
|
ThrowClosed();
|
|
|
|
return nsMgr.LookupPrefix(ns);
|
|
}
|
|
|
|
internal string LookupNamespace(string prefix)
|
|
{
|
|
if (prefix == null)
|
|
return null;
|
|
return nsMgr.LookupNamespace(prefix);
|
|
}
|
|
|
|
string GetQualifiedNamePrefix(string namespaceUri, XmlDictionaryString xNs)
|
|
{
|
|
string prefix = nsMgr.LookupPrefix(namespaceUri);
|
|
if (prefix == null)
|
|
{
|
|
if (writeState != WriteState.Attribute)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.XmlNamespaceNotFound, namespaceUri), "namespaceUri"));
|
|
|
|
prefix = GeneratePrefix(namespaceUri, xNs);
|
|
}
|
|
return prefix;
|
|
}
|
|
|
|
public override void WriteQualifiedName(string localName, string namespaceUri)
|
|
{
|
|
if (IsClosed)
|
|
ThrowClosed();
|
|
if (localName == null)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("localName"));
|
|
if (localName.Length == 0)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.InvalidLocalNameEmpty), "localName"));
|
|
if (namespaceUri == null)
|
|
namespaceUri = string.Empty;
|
|
string prefix = GetQualifiedNamePrefix(namespaceUri, null);
|
|
if (prefix.Length != 0)
|
|
{
|
|
WriteString(prefix);
|
|
WriteString(":");
|
|
}
|
|
WriteString(localName);
|
|
}
|
|
|
|
public override void WriteQualifiedName(XmlDictionaryString localName, XmlDictionaryString namespaceUri)
|
|
{
|
|
if (IsClosed)
|
|
ThrowClosed();
|
|
if (localName == null)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("localName"));
|
|
if (localName.Value.Length == 0)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.InvalidLocalNameEmpty), "localName"));
|
|
if (namespaceUri == null)
|
|
namespaceUri = XmlDictionaryString.Empty;
|
|
string prefix = GetQualifiedNamePrefix(namespaceUri.Value, namespaceUri);
|
|
|
|
FlushBase64();
|
|
if (attributeValue != null)
|
|
WriteAttributeText(string.Concat(prefix, ":", namespaceUri.Value));
|
|
|
|
if (!isXmlnsAttribute)
|
|
{
|
|
StartContent();
|
|
writer.WriteQualifiedName(prefix, localName);
|
|
EndContent();
|
|
}
|
|
}
|
|
|
|
public override void WriteStartDocument()
|
|
{
|
|
if (IsClosed)
|
|
ThrowClosed();
|
|
|
|
if (writeState != WriteState.Start)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlInvalidWriteState, "WriteStartDocument", WriteState.ToString())));
|
|
|
|
writeState = WriteState.Prolog;
|
|
documentState = DocumentState.Document;
|
|
writer.WriteDeclaration();
|
|
}
|
|
|
|
public override void WriteStartDocument(bool standalone)
|
|
{
|
|
if (IsClosed)
|
|
ThrowClosed();
|
|
|
|
WriteStartDocument();
|
|
}
|
|
|
|
|
|
public override void WriteProcessingInstruction(string name, string text)
|
|
{
|
|
if (IsClosed)
|
|
ThrowClosed();
|
|
|
|
if (name != "xml")
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.XmlProcessingInstructionNotSupported), "name"));
|
|
|
|
if (writeState != WriteState.Start)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlInvalidDeclaration)));
|
|
|
|
// The only thing the text can legitimately contain is version, encoding, and standalone.
|
|
// We only support version 1.0, we can only write whatever encoding we were supplied,
|
|
// and we don't support DTDs, so whatever values are supplied in the text argument are irrelevant.
|
|
writer.WriteDeclaration();
|
|
}
|
|
|
|
void FinishDocument()
|
|
{
|
|
if (this.writeState == WriteState.Attribute)
|
|
{
|
|
WriteEndAttribute();
|
|
}
|
|
|
|
while (this.depth > 0)
|
|
{
|
|
WriteEndElement();
|
|
}
|
|
}
|
|
|
|
public override void WriteEndDocument()
|
|
{
|
|
if (IsClosed)
|
|
ThrowClosed();
|
|
|
|
if (writeState == WriteState.Start || writeState == WriteState.Prolog)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlNoRootElement)));
|
|
|
|
FinishDocument();
|
|
writeState = WriteState.Start;
|
|
documentState = DocumentState.End;
|
|
}
|
|
|
|
protected int NamespaceBoundary
|
|
{
|
|
get
|
|
{
|
|
return nsMgr.NamespaceBoundary;
|
|
}
|
|
set
|
|
{
|
|
nsMgr.NamespaceBoundary = value;
|
|
}
|
|
}
|
|
|
|
public override void WriteEntityRef(string name)
|
|
{
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.XmlMethodNotSupported, "WriteEntityRef")));
|
|
}
|
|
|
|
public override void WriteName(string name)
|
|
{
|
|
if (IsClosed)
|
|
ThrowClosed();
|
|
|
|
WriteString(name);
|
|
}
|
|
|
|
public override void WriteNmToken(string name)
|
|
{
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.XmlMethodNotSupported, "WriteNmToken")));
|
|
}
|
|
|
|
public override void WriteWhitespace(string whitespace)
|
|
{
|
|
if (IsClosed)
|
|
ThrowClosed();
|
|
|
|
if (whitespace == null)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("whitespace");
|
|
|
|
for (int i = 0; i < whitespace.Length; ++i)
|
|
{
|
|
char c = whitespace[i];
|
|
if (c != ' ' &&
|
|
c != '\t' &&
|
|
c != '\n' &&
|
|
c != '\r')
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.XmlOnlyWhitespace), "whitespace"));
|
|
}
|
|
|
|
WriteString(whitespace);
|
|
}
|
|
|
|
public override void WriteString(string value)
|
|
{
|
|
if (IsClosed)
|
|
ThrowClosed();
|
|
|
|
if (value == null)
|
|
value = string.Empty;
|
|
|
|
if (value.Length > 0 || this.inList)
|
|
{
|
|
FlushBase64();
|
|
|
|
if (attributeValue != null)
|
|
WriteAttributeText(value);
|
|
|
|
if (!isXmlnsAttribute)
|
|
{
|
|
StartContent(value);
|
|
writer.WriteEscapedText(value);
|
|
EndContent();
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void WriteString(XmlDictionaryString value)
|
|
{
|
|
if (IsClosed)
|
|
ThrowClosed();
|
|
|
|
if (value == null)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("value");
|
|
|
|
if (value.Value.Length > 0)
|
|
{
|
|
FlushBase64();
|
|
|
|
if (attributeValue != null)
|
|
WriteAttributeText(value.Value);
|
|
|
|
if (!isXmlnsAttribute)
|
|
{
|
|
StartContent(value.Value);
|
|
writer.WriteEscapedText(value);
|
|
EndContent();
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void WriteChars(char[] chars, int offset, int count)
|
|
{
|
|
if (IsClosed)
|
|
ThrowClosed();
|
|
|
|
if (chars == null)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("chars"));
|
|
|
|
// Not checking upper bound because it will be caught by "count". This is what XmlTextWriter does.
|
|
if (offset < 0)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", SR.GetString(SR.ValueMustBeNonNegative)));
|
|
|
|
if (count < 0)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", SR.GetString(SR.ValueMustBeNonNegative)));
|
|
if (count > chars.Length - offset)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", SR.GetString(SR.SizeExceedsRemainingBufferSpace, chars.Length - offset)));
|
|
|
|
if (count > 0)
|
|
{
|
|
FlushBase64();
|
|
|
|
if (attributeValue != null)
|
|
WriteAttributeText(new string(chars, offset, count));
|
|
|
|
if (!isXmlnsAttribute)
|
|
{
|
|
StartContent(chars, offset, count);
|
|
writer.WriteEscapedText(chars, offset, count);
|
|
EndContent();
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void WriteRaw(string value)
|
|
{
|
|
if (IsClosed)
|
|
ThrowClosed();
|
|
|
|
if (value == null)
|
|
value = string.Empty;
|
|
|
|
if (value.Length > 0)
|
|
{
|
|
FlushBase64();
|
|
|
|
if (attributeValue != null)
|
|
WriteAttributeText(value);
|
|
|
|
if (!isXmlnsAttribute)
|
|
{
|
|
StartContent(value);
|
|
writer.WriteText(value);
|
|
EndContent();
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void WriteRaw(char[] chars, int offset, int count)
|
|
{
|
|
if (IsClosed)
|
|
ThrowClosed();
|
|
|
|
if (chars == null)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("chars"));
|
|
|
|
// Not checking upper bound because it will be caught by "count". This is what XmlTextWriter does.
|
|
if (offset < 0)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", SR.GetString(SR.ValueMustBeNonNegative)));
|
|
|
|
if (count < 0)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", SR.GetString(SR.ValueMustBeNonNegative)));
|
|
if (count > chars.Length - offset)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", SR.GetString(SR.SizeExceedsRemainingBufferSpace, chars.Length - offset)));
|
|
|
|
if (count > 0)
|
|
{
|
|
FlushBase64();
|
|
|
|
if (attributeValue != null)
|
|
WriteAttributeText(new string(chars, offset, count));
|
|
|
|
if (!isXmlnsAttribute)
|
|
{
|
|
StartContent(chars, offset, count);
|
|
writer.WriteText(chars, offset, count);
|
|
EndContent();
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void WriteCharEntity(char ch)
|
|
{
|
|
if (IsClosed)
|
|
ThrowClosed();
|
|
|
|
if (ch >= 0xd800 && ch <= 0xdfff)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.XmlMissingLowSurrogate), "ch"));
|
|
|
|
if (attributeValue != null)
|
|
WriteAttributeText(ch.ToString());
|
|
|
|
if (!isXmlnsAttribute)
|
|
{
|
|
StartContent(ch);
|
|
FlushBase64();
|
|
writer.WriteCharEntity(ch);
|
|
EndContent();
|
|
}
|
|
}
|
|
|
|
public override void WriteSurrogateCharEntity(char lowChar, char highChar)
|
|
{
|
|
if (IsClosed)
|
|
ThrowClosed();
|
|
|
|
SurrogateChar ch = new SurrogateChar(lowChar, highChar);
|
|
|
|
if (attributeValue != null)
|
|
{
|
|
char[] chars = new char[2] { highChar, lowChar };
|
|
WriteAttributeText(new string(chars));
|
|
}
|
|
|
|
if (!isXmlnsAttribute)
|
|
{
|
|
StartContent();
|
|
FlushBase64();
|
|
writer.WriteCharEntity(ch.Char);
|
|
EndContent();
|
|
}
|
|
}
|
|
|
|
public override void WriteValue(object value)
|
|
{
|
|
if (IsClosed)
|
|
ThrowClosed();
|
|
|
|
if (value == null)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("value"));
|
|
|
|
else if (value is object[])
|
|
{
|
|
WriteValue((object[])value);
|
|
}
|
|
else if (value is Array)
|
|
{
|
|
WriteValue((Array)value);
|
|
}
|
|
else if (value is IStreamProvider)
|
|
{
|
|
WriteValue((IStreamProvider)value);
|
|
}
|
|
else
|
|
{
|
|
WritePrimitiveValue(value);
|
|
}
|
|
}
|
|
|
|
protected void WritePrimitiveValue(object value)
|
|
{
|
|
if (IsClosed)
|
|
ThrowClosed();
|
|
|
|
if (value == null)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("value"));
|
|
|
|
if (value is ulong)
|
|
{
|
|
WriteValue((ulong)value);
|
|
}
|
|
else if (value is string)
|
|
{
|
|
WriteValue((string)value);
|
|
}
|
|
else if (value is int)
|
|
{
|
|
WriteValue((int)value);
|
|
}
|
|
else if (value is long)
|
|
{
|
|
WriteValue((long)value);
|
|
}
|
|
else if (value is bool)
|
|
{
|
|
WriteValue((bool)value);
|
|
}
|
|
else if (value is double)
|
|
{
|
|
WriteValue((double)value);
|
|
}
|
|
else if (value is DateTime)
|
|
{
|
|
WriteValue((DateTime)value);
|
|
}
|
|
else if (value is float)
|
|
{
|
|
WriteValue((float)value);
|
|
}
|
|
else if (value is decimal)
|
|
{
|
|
WriteValue((decimal)value);
|
|
}
|
|
else if (value is XmlDictionaryString)
|
|
{
|
|
WriteValue((XmlDictionaryString)value);
|
|
}
|
|
else if (value is UniqueId)
|
|
{
|
|
WriteValue((UniqueId)value);
|
|
}
|
|
else if (value is Guid)
|
|
{
|
|
WriteValue((Guid)value);
|
|
}
|
|
else if (value is TimeSpan)
|
|
{
|
|
WriteValue((TimeSpan)value);
|
|
}
|
|
else if (value.GetType().IsArray)
|
|
{
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.XmlNestedArraysNotSupported), "value"));
|
|
}
|
|
else
|
|
{
|
|
base.WriteValue(value);
|
|
}
|
|
}
|
|
|
|
public override void WriteValue(string value)
|
|
{
|
|
if (IsClosed)
|
|
ThrowClosed();
|
|
|
|
WriteString(value);
|
|
}
|
|
|
|
public override void WriteValue(int value)
|
|
{
|
|
if (IsClosed)
|
|
ThrowClosed();
|
|
|
|
FlushBase64();
|
|
if (attributeValue != null)
|
|
WriteAttributeText(XmlConverter.ToString(value));
|
|
|
|
if (!isXmlnsAttribute)
|
|
{
|
|
StartContent();
|
|
writer.WriteInt32Text(value);
|
|
EndContent();
|
|
}
|
|
}
|
|
|
|
public override void WriteValue(long value)
|
|
{
|
|
if (IsClosed)
|
|
ThrowClosed();
|
|
|
|
FlushBase64();
|
|
if (attributeValue != null)
|
|
WriteAttributeText(XmlConverter.ToString(value));
|
|
|
|
if (!isXmlnsAttribute)
|
|
{
|
|
StartContent();
|
|
writer.WriteInt64Text(value);
|
|
EndContent();
|
|
}
|
|
}
|
|
|
|
void WriteValue(ulong value)
|
|
{
|
|
if (IsClosed)
|
|
ThrowClosed();
|
|
|
|
FlushBase64();
|
|
if (attributeValue != null)
|
|
WriteAttributeText(XmlConverter.ToString(value));
|
|
|
|
if (!isXmlnsAttribute)
|
|
{
|
|
StartContent();
|
|
writer.WriteUInt64Text(value);
|
|
EndContent();
|
|
}
|
|
}
|
|
|
|
public override void WriteValue(bool value)
|
|
{
|
|
if (IsClosed)
|
|
ThrowClosed();
|
|
|
|
FlushBase64();
|
|
if (attributeValue != null)
|
|
WriteAttributeText(XmlConverter.ToString(value));
|
|
|
|
if (!isXmlnsAttribute)
|
|
{
|
|
StartContent();
|
|
writer.WriteBoolText(value);
|
|
EndContent();
|
|
}
|
|
}
|
|
|
|
public override void WriteValue(decimal value)
|
|
{
|
|
if (IsClosed)
|
|
ThrowClosed();
|
|
|
|
FlushBase64();
|
|
if (attributeValue != null)
|
|
WriteAttributeText(XmlConverter.ToString(value));
|
|
|
|
if (!isXmlnsAttribute)
|
|
{
|
|
StartContent();
|
|
writer.WriteDecimalText(value);
|
|
EndContent();
|
|
}
|
|
}
|
|
|
|
public override void WriteValue(float value)
|
|
{
|
|
if (IsClosed)
|
|
ThrowClosed();
|
|
|
|
FlushBase64();
|
|
if (attributeValue != null)
|
|
WriteAttributeText(XmlConverter.ToString(value));
|
|
|
|
if (!isXmlnsAttribute)
|
|
{
|
|
StartContent();
|
|
writer.WriteFloatText(value);
|
|
EndContent();
|
|
}
|
|
}
|
|
|
|
public override void WriteValue(double value)
|
|
{
|
|
if (IsClosed)
|
|
ThrowClosed();
|
|
|
|
FlushBase64();
|
|
if (attributeValue != null)
|
|
WriteAttributeText(XmlConverter.ToString(value));
|
|
|
|
if (!isXmlnsAttribute)
|
|
{
|
|
StartContent();
|
|
writer.WriteDoubleText(value);
|
|
EndContent();
|
|
}
|
|
}
|
|
|
|
public override void WriteValue(XmlDictionaryString value)
|
|
{
|
|
WriteString(value);
|
|
}
|
|
|
|
public override void WriteValue(DateTime value)
|
|
{
|
|
if (IsClosed)
|
|
ThrowClosed();
|
|
|
|
FlushBase64();
|
|
if (attributeValue != null)
|
|
WriteAttributeText(XmlConverter.ToString(value));
|
|
|
|
if (!isXmlnsAttribute)
|
|
{
|
|
StartContent();
|
|
writer.WriteDateTimeText(value);
|
|
EndContent();
|
|
}
|
|
}
|
|
|
|
public override void WriteValue(UniqueId value)
|
|
{
|
|
if (IsClosed)
|
|
ThrowClosed();
|
|
|
|
if (value == null)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("value");
|
|
|
|
FlushBase64();
|
|
if (attributeValue != null)
|
|
WriteAttributeText(XmlConverter.ToString(value));
|
|
|
|
if (!isXmlnsAttribute)
|
|
{
|
|
StartContent();
|
|
writer.WriteUniqueIdText(value);
|
|
EndContent();
|
|
}
|
|
}
|
|
|
|
public override void WriteValue(Guid value)
|
|
{
|
|
if (IsClosed)
|
|
ThrowClosed();
|
|
|
|
FlushBase64();
|
|
if (attributeValue != null)
|
|
WriteAttributeText(XmlConverter.ToString(value));
|
|
|
|
if (!isXmlnsAttribute)
|
|
{
|
|
StartContent();
|
|
writer.WriteGuidText(value);
|
|
EndContent();
|
|
}
|
|
}
|
|
|
|
public override void WriteValue(TimeSpan value)
|
|
{
|
|
if (IsClosed)
|
|
ThrowClosed();
|
|
|
|
FlushBase64();
|
|
if (attributeValue != null)
|
|
WriteAttributeText(XmlConverter.ToString(value));
|
|
|
|
if (!isXmlnsAttribute)
|
|
{
|
|
StartContent();
|
|
writer.WriteTimeSpanText(value);
|
|
EndContent();
|
|
}
|
|
}
|
|
|
|
public override void WriteBase64(byte[] buffer, int offset, int count)
|
|
{
|
|
if (IsClosed)
|
|
ThrowClosed();
|
|
|
|
EnsureBufferBounds(buffer, offset, count);
|
|
if (count > 0)
|
|
{
|
|
if (trailByteCount > 0)
|
|
{
|
|
while (trailByteCount < 3 && count > 0)
|
|
{
|
|
trailBytes[trailByteCount++] = buffer[offset++];
|
|
count--;
|
|
}
|
|
}
|
|
|
|
int totalByteCount = trailByteCount + count;
|
|
int actualByteCount = totalByteCount - (totalByteCount % 3);
|
|
|
|
if (trailBytes == null)
|
|
{
|
|
trailBytes = new byte[3];
|
|
}
|
|
|
|
if (actualByteCount >= 3)
|
|
{
|
|
if (attributeValue != null)
|
|
{
|
|
WriteAttributeText(XmlConverter.Base64Encoding.GetString(trailBytes, 0, trailByteCount));
|
|
WriteAttributeText(XmlConverter.Base64Encoding.GetString(buffer, offset, actualByteCount - trailByteCount));
|
|
}
|
|
|
|
if (!isXmlnsAttribute)
|
|
{
|
|
StartContent();
|
|
writer.WriteBase64Text(trailBytes, trailByteCount, buffer, offset, actualByteCount - trailByteCount);
|
|
EndContent();
|
|
}
|
|
trailByteCount = (totalByteCount - actualByteCount);
|
|
|
|
if (trailByteCount > 0)
|
|
{
|
|
int trailOffset = offset + count - trailByteCount;
|
|
for (int i = 0; i < trailByteCount; i++)
|
|
trailBytes[i] = buffer[trailOffset++];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Buffer.BlockCopy(buffer, offset, trailBytes, trailByteCount, count);
|
|
trailByteCount += count;
|
|
}
|
|
}
|
|
}
|
|
|
|
internal override IAsyncResult BeginWriteBase64(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
|
|
{
|
|
if (IsClosed)
|
|
ThrowClosed();
|
|
|
|
EnsureBufferBounds(buffer, offset, count);
|
|
|
|
return new WriteBase64AsyncResult(buffer, offset, count, this, callback, state);
|
|
}
|
|
|
|
internal override void EndWriteBase64(IAsyncResult result)
|
|
{
|
|
WriteBase64AsyncResult.End(result);
|
|
}
|
|
|
|
internal override AsyncCompletionResult WriteBase64Async(AsyncEventArgs<XmlWriteBase64AsyncArguments> state)
|
|
{
|
|
if (this.nodeWriterAsyncHelper == null)
|
|
{
|
|
this.nodeWriterAsyncHelper = new XmlBaseWriterNodeWriterAsyncHelper(this);
|
|
}
|
|
|
|
this.nodeWriterAsyncHelper.SetArguments(state);
|
|
|
|
if (this.nodeWriterAsyncHelper.StartAsync() == AsyncCompletionResult.Completed)
|
|
{
|
|
return AsyncCompletionResult.Completed;
|
|
}
|
|
|
|
return AsyncCompletionResult.Queued;
|
|
}
|
|
|
|
class WriteBase64AsyncResult : AsyncResult
|
|
{
|
|
static AsyncCompletion onComplete = new AsyncCompletion(OnComplete);
|
|
XmlBaseWriter writer;
|
|
byte[] buffer;
|
|
int offset;
|
|
int count;
|
|
int actualByteCount;
|
|
int totalByteCount;
|
|
|
|
public WriteBase64AsyncResult(byte[] buffer, int offset, int count, XmlBaseWriter writer, AsyncCallback callback, object state)
|
|
: base(callback, state)
|
|
{
|
|
this.writer = writer;
|
|
this.buffer = buffer;
|
|
this.offset = offset;
|
|
this.count = count;
|
|
|
|
bool completeSelf = true;
|
|
|
|
if (this.count > 0)
|
|
{
|
|
if (writer.trailByteCount > 0)
|
|
{
|
|
while (writer.trailByteCount < 3 && this.count > 0)
|
|
{
|
|
writer.trailBytes[writer.trailByteCount++] = buffer[this.offset++];
|
|
this.count--;
|
|
}
|
|
}
|
|
|
|
this.totalByteCount = writer.trailByteCount + this.count;
|
|
this.actualByteCount = totalByteCount - (totalByteCount % 3);
|
|
|
|
if (writer.trailBytes == null)
|
|
{
|
|
writer.trailBytes = new byte[3];
|
|
}
|
|
|
|
if (actualByteCount >= 3)
|
|
{
|
|
if (writer.attributeValue != null)
|
|
{
|
|
writer.WriteAttributeText(XmlConverter.Base64Encoding.GetString(writer.trailBytes, 0, writer.trailByteCount));
|
|
writer.WriteAttributeText(XmlConverter.Base64Encoding.GetString(buffer, this.offset, actualByteCount - writer.trailByteCount));
|
|
}
|
|
|
|
// StartContent/WriteBase64Text/EndContent will be called from HandleWriteBase64 as appropriate
|
|
completeSelf = HandleWriteBase64Text(null);
|
|
}
|
|
else
|
|
{
|
|
Buffer.BlockCopy(buffer, this.offset, writer.trailBytes, writer.trailByteCount, this.count);
|
|
writer.trailByteCount += this.count;
|
|
}
|
|
}
|
|
|
|
if (completeSelf)
|
|
{
|
|
this.Complete(true);
|
|
}
|
|
}
|
|
|
|
static bool OnComplete(IAsyncResult result)
|
|
{
|
|
WriteBase64AsyncResult thisPtr = (WriteBase64AsyncResult)result.AsyncState;
|
|
return thisPtr.HandleWriteBase64Text(result);
|
|
}
|
|
|
|
bool HandleWriteBase64Text(IAsyncResult result)
|
|
{
|
|
// in this code block if count > 0 && actualByteCount >= 3
|
|
if (!writer.isXmlnsAttribute)
|
|
{
|
|
if (result == null)
|
|
{
|
|
this.writer.StartContent();
|
|
result = this.writer.writer.BeginWriteBase64Text(this.writer.trailBytes,
|
|
this.writer.trailByteCount,
|
|
this.buffer,
|
|
this.offset,
|
|
this.actualByteCount - this.writer.trailByteCount,
|
|
PrepareAsyncCompletion(onComplete),
|
|
this);
|
|
|
|
if (!result.CompletedSynchronously)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
this.writer.writer.EndWriteBase64Text(result);
|
|
this.writer.EndContent();
|
|
}
|
|
|
|
this.writer.trailByteCount = (totalByteCount - actualByteCount);
|
|
if (this.writer.trailByteCount > 0)
|
|
{
|
|
int trailOffset = offset + count - this.writer.trailByteCount;
|
|
for (int i = 0; i < this.writer.trailByteCount; i++)
|
|
this.writer.trailBytes[i] = this.buffer[trailOffset++];
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public static void End(IAsyncResult result)
|
|
{
|
|
AsyncResult.End<WriteBase64AsyncResult>(result);
|
|
}
|
|
}
|
|
|
|
public override void WriteBinHex(byte[] buffer, int offset, int count)
|
|
{
|
|
if (IsClosed)
|
|
ThrowClosed();
|
|
|
|
EnsureBufferBounds(buffer, offset, count);
|
|
|
|
WriteRaw(BinHexEncoding.GetString(buffer, offset, count));
|
|
}
|
|
|
|
public override bool CanCanonicalize
|
|
{
|
|
get
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
protected bool Signing
|
|
{
|
|
get
|
|
{
|
|
return writer == signingWriter;
|
|
}
|
|
}
|
|
|
|
public override void StartCanonicalization(Stream stream, bool includeComments, string[] inclusivePrefixes)
|
|
{
|
|
if (IsClosed)
|
|
ThrowClosed();
|
|
if (Signing)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlCanonicalizationStarted)));
|
|
FlushElement();
|
|
if (signingWriter == null)
|
|
signingWriter = CreateSigningNodeWriter();
|
|
signingWriter.SetOutput(writer, stream, includeComments, inclusivePrefixes);
|
|
writer = signingWriter;
|
|
SignScope(signingWriter.CanonicalWriter);
|
|
}
|
|
|
|
public override void EndCanonicalization()
|
|
{
|
|
if (IsClosed)
|
|
ThrowClosed();
|
|
if (!Signing)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlCanonicalizationNotStarted)));
|
|
signingWriter.Flush();
|
|
writer = signingWriter.NodeWriter;
|
|
}
|
|
|
|
protected abstract XmlSigningNodeWriter CreateSigningNodeWriter();
|
|
|
|
public virtual bool CanFragment
|
|
{
|
|
get
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
public void StartFragment(Stream stream, bool generateSelfContainedTextFragment)
|
|
{
|
|
if (!CanFragment)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
|
|
if (IsClosed)
|
|
ThrowClosed();
|
|
if (stream == null)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("stream"));
|
|
if (oldStream != null || oldWriter != null)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException());
|
|
if (WriteState == WriteState.Attribute)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlInvalidWriteState, "StartFragment", WriteState.ToString())));
|
|
FlushElement();
|
|
writer.Flush();
|
|
|
|
oldNamespaceBoundary = NamespaceBoundary;
|
|
|
|
XmlStreamNodeWriter fragmentWriter = null;
|
|
if (generateSelfContainedTextFragment)
|
|
{
|
|
this.NamespaceBoundary = depth + 1;
|
|
if (textFragmentWriter == null)
|
|
textFragmentWriter = new XmlUTF8NodeWriter();
|
|
textFragmentWriter.SetOutput(stream, false, Encoding.UTF8);
|
|
fragmentWriter = textFragmentWriter;
|
|
}
|
|
|
|
if (Signing)
|
|
{
|
|
if (fragmentWriter != null)
|
|
{
|
|
oldWriter = signingWriter.NodeWriter;
|
|
signingWriter.NodeWriter = fragmentWriter;
|
|
}
|
|
else
|
|
{
|
|
oldStream = ((XmlStreamNodeWriter)signingWriter.NodeWriter).Stream;
|
|
((XmlStreamNodeWriter)signingWriter.NodeWriter).Stream = stream;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (fragmentWriter != null)
|
|
{
|
|
oldWriter = writer;
|
|
writer = fragmentWriter;
|
|
}
|
|
else
|
|
{
|
|
oldStream = nodeWriter.Stream;
|
|
nodeWriter.Stream = stream;
|
|
}
|
|
}
|
|
}
|
|
|
|
public void EndFragment()
|
|
{
|
|
if (IsClosed)
|
|
ThrowClosed();
|
|
if (oldStream == null && oldWriter == null)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException());
|
|
if (WriteState == WriteState.Attribute)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlInvalidWriteState, "EndFragment", WriteState.ToString())));
|
|
|
|
FlushElement();
|
|
writer.Flush();
|
|
|
|
if (Signing)
|
|
{
|
|
if (oldWriter != null)
|
|
signingWriter.NodeWriter = oldWriter;
|
|
else
|
|
((XmlStreamNodeWriter)signingWriter.NodeWriter).Stream = oldStream;
|
|
}
|
|
else
|
|
{
|
|
if (oldWriter != null)
|
|
writer = oldWriter;
|
|
else
|
|
nodeWriter.Stream = oldStream;
|
|
}
|
|
NamespaceBoundary = oldNamespaceBoundary;
|
|
oldWriter = null;
|
|
oldStream = null;
|
|
}
|
|
|
|
public void WriteFragment(byte[] buffer, int offset, int count)
|
|
{
|
|
if (!CanFragment)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
|
|
if (IsClosed)
|
|
ThrowClosed();
|
|
if (buffer == null)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("buffer"));
|
|
if (offset < 0)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", SR.GetString(SR.ValueMustBeNonNegative)));
|
|
if (count < 0)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", SR.GetString(SR.ValueMustBeNonNegative)));
|
|
if (count > buffer.Length - offset)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", SR.GetString(SR.SizeExceedsRemainingBufferSpace, buffer.Length - offset)));
|
|
if (WriteState == WriteState.Attribute)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlInvalidWriteState, "WriteFragment", WriteState.ToString())));
|
|
if (writer != nodeWriter)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException());
|
|
FlushElement();
|
|
FlushBase64();
|
|
nodeWriter.Flush();
|
|
nodeWriter.Stream.Write(buffer, offset, count);
|
|
}
|
|
|
|
void FlushBase64()
|
|
{
|
|
if (trailByteCount > 0)
|
|
{
|
|
FlushTrailBytes();
|
|
}
|
|
}
|
|
|
|
void FlushTrailBytes()
|
|
{
|
|
if (attributeValue != null)
|
|
WriteAttributeText(XmlConverter.Base64Encoding.GetString(trailBytes, 0, trailByteCount));
|
|
|
|
if (!isXmlnsAttribute)
|
|
{
|
|
StartContent();
|
|
writer.WriteBase64Text(trailBytes, trailByteCount, trailBytes, 0, 0);
|
|
EndContent();
|
|
}
|
|
trailByteCount = 0;
|
|
}
|
|
|
|
void WriteValue(object[] array)
|
|
{
|
|
FlushBase64();
|
|
StartContent();
|
|
writer.WriteStartListText();
|
|
this.inList = true;
|
|
for (int i = 0; i < array.Length; i++)
|
|
{
|
|
if (i != 0)
|
|
{
|
|
writer.WriteListSeparator();
|
|
}
|
|
WritePrimitiveValue(array[i]);
|
|
}
|
|
this.inList = false;
|
|
writer.WriteEndListText();
|
|
EndContent();
|
|
}
|
|
|
|
void WriteValue(Array array)
|
|
{
|
|
FlushBase64();
|
|
StartContent();
|
|
writer.WriteStartListText();
|
|
this.inList = true;
|
|
for (int i = 0; i < array.Length; i++)
|
|
{
|
|
if (i != 0)
|
|
{
|
|
writer.WriteListSeparator();
|
|
}
|
|
WritePrimitiveValue(array.GetValue(i));
|
|
}
|
|
this.inList = false;
|
|
writer.WriteEndListText();
|
|
EndContent();
|
|
}
|
|
|
|
protected void StartArray(int count)
|
|
{
|
|
FlushBase64();
|
|
if (this.documentState == DocumentState.Epilog)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlOnlyOneRoot)));
|
|
if (this.documentState == DocumentState.Document && count > 1 && depth == 0)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlOnlyOneRoot)));
|
|
if (writeState == WriteState.Attribute)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlInvalidWriteState, "WriteStartElement", WriteState.ToString())));
|
|
AutoComplete(WriteState.Content);
|
|
}
|
|
|
|
protected void EndArray()
|
|
{
|
|
}
|
|
|
|
void EnsureBufferBounds(byte[] buffer, int offset, int count)
|
|
{
|
|
if (buffer == null)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("buffer");
|
|
|
|
// Not checking upper bound because it will be caught by "count". This is what XmlTextWriter does.
|
|
if (offset < 0)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", SR.GetString(SR.ValueMustBeNonNegative)));
|
|
|
|
if (count < 0)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", SR.GetString(SR.ValueMustBeNonNegative)));
|
|
if (count > buffer.Length - offset)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", SR.GetString(SR.SizeExceedsRemainingBufferSpace, buffer.Length - offset)));
|
|
}
|
|
|
|
string GeneratePrefix(string ns, XmlDictionaryString xNs)
|
|
{
|
|
if (writeState != WriteState.Element && writeState != WriteState.Attribute)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlInvalidPrefixState, WriteState.ToString())));
|
|
|
|
string prefix = nsMgr.AddNamespace(ns, xNs);
|
|
|
|
if (prefix != null)
|
|
return prefix;
|
|
|
|
while (true)
|
|
{
|
|
int prefixId = elements[depth].PrefixId++;
|
|
prefix = string.Concat("d", depth.ToString(CultureInfo.InvariantCulture), "p", prefixId.ToString(CultureInfo.InvariantCulture));
|
|
|
|
if (nsMgr.LookupNamespace(prefix) == null)
|
|
{
|
|
nsMgr.AddNamespace(prefix, ns, xNs);
|
|
return prefix;
|
|
}
|
|
}
|
|
}
|
|
|
|
protected void SignScope(XmlCanonicalWriter signingWriter)
|
|
{
|
|
nsMgr.Sign(signingWriter);
|
|
}
|
|
|
|
void WriteAttributeText(string value)
|
|
{
|
|
if (attributeValue.Length == 0)
|
|
attributeValue = value;
|
|
else
|
|
attributeValue += value;
|
|
}
|
|
|
|
class Element
|
|
{
|
|
string prefix;
|
|
string localName;
|
|
int prefixId;
|
|
|
|
public string Prefix
|
|
{
|
|
get
|
|
{
|
|
return prefix;
|
|
}
|
|
set
|
|
{
|
|
prefix = value;
|
|
}
|
|
}
|
|
|
|
public string LocalName
|
|
{
|
|
get
|
|
{
|
|
return localName;
|
|
}
|
|
set
|
|
{
|
|
localName = value;
|
|
}
|
|
}
|
|
|
|
public int PrefixId
|
|
{
|
|
get
|
|
{
|
|
return prefixId;
|
|
}
|
|
set
|
|
{
|
|
prefixId = value;
|
|
}
|
|
}
|
|
|
|
public void Clear()
|
|
{
|
|
this.prefix = null;
|
|
this.localName = null;
|
|
this.prefixId = 0;
|
|
}
|
|
}
|
|
|
|
enum DocumentState : byte
|
|
{
|
|
None, // Not inside StartDocument/EndDocument - Allows multiple root elemnts
|
|
Document, // Inside StartDocument/EndDocument
|
|
Epilog, // EndDocument must be called
|
|
End // Nothing further to write
|
|
}
|
|
|
|
class NamespaceManager
|
|
{
|
|
Namespace[] namespaces;
|
|
Namespace lastNameSpace;
|
|
int nsCount;
|
|
int depth;
|
|
XmlAttribute[] attributes;
|
|
int attributeCount;
|
|
XmlSpace space;
|
|
string lang;
|
|
int namespaceBoundary;
|
|
int nsTop;
|
|
Namespace defaultNamespace;
|
|
|
|
public NamespaceManager()
|
|
{
|
|
defaultNamespace = new Namespace();
|
|
defaultNamespace.Depth = 0;
|
|
defaultNamespace.Prefix = string.Empty;
|
|
defaultNamespace.Uri = string.Empty;
|
|
defaultNamespace.UriDictionaryString = null;
|
|
}
|
|
|
|
public string XmlLang
|
|
{
|
|
get
|
|
{
|
|
return lang;
|
|
}
|
|
}
|
|
|
|
public XmlSpace XmlSpace
|
|
{
|
|
get
|
|
{
|
|
return space;
|
|
}
|
|
}
|
|
|
|
public void Clear()
|
|
{
|
|
if (this.namespaces == null)
|
|
{
|
|
this.namespaces = new Namespace[4];
|
|
this.namespaces[0] = defaultNamespace;
|
|
}
|
|
this.nsCount = 1;
|
|
this.nsTop = 0;
|
|
this.depth = 0;
|
|
this.attributeCount = 0;
|
|
this.space = XmlSpace.None;
|
|
this.lang = null;
|
|
this.lastNameSpace = null;
|
|
this.namespaceBoundary = 0;
|
|
}
|
|
|
|
public int NamespaceBoundary
|
|
{
|
|
get
|
|
{
|
|
return namespaceBoundary;
|
|
}
|
|
set
|
|
{
|
|
int i;
|
|
for (i = 0; i < nsCount; i++)
|
|
if (namespaces[i].Depth >= value)
|
|
break;
|
|
|
|
nsTop = i;
|
|
namespaceBoundary = value;
|
|
lastNameSpace = null;
|
|
}
|
|
}
|
|
|
|
public void Close()
|
|
{
|
|
if (depth == 0)
|
|
{
|
|
if (namespaces != null && namespaces.Length > 32)
|
|
namespaces = null;
|
|
if (attributes != null && attributes.Length > 4)
|
|
attributes = null;
|
|
}
|
|
else
|
|
{
|
|
namespaces = null;
|
|
attributes = null;
|
|
}
|
|
lang = null;
|
|
}
|
|
|
|
public void DeclareNamespaces(XmlNodeWriter writer)
|
|
{
|
|
int i = this.nsCount;
|
|
while (i > 0)
|
|
{
|
|
Namespace nameSpace = namespaces[i - 1];
|
|
if (nameSpace.Depth != depth)
|
|
break;
|
|
i--;
|
|
}
|
|
while (i < this.nsCount)
|
|
{
|
|
Namespace nameSpace = namespaces[i];
|
|
if (nameSpace.UriDictionaryString != null)
|
|
writer.WriteXmlnsAttribute(nameSpace.Prefix, nameSpace.UriDictionaryString);
|
|
else
|
|
writer.WriteXmlnsAttribute(nameSpace.Prefix, nameSpace.Uri);
|
|
i++;
|
|
}
|
|
}
|
|
|
|
public void EnterScope()
|
|
{
|
|
depth++;
|
|
}
|
|
|
|
public void ExitScope()
|
|
{
|
|
while (nsCount > 0)
|
|
{
|
|
Namespace nameSpace = namespaces[nsCount - 1];
|
|
if (nameSpace.Depth != depth)
|
|
break;
|
|
if (lastNameSpace == nameSpace)
|
|
lastNameSpace = null;
|
|
nameSpace.Clear();
|
|
nsCount--;
|
|
}
|
|
while (attributeCount > 0)
|
|
{
|
|
XmlAttribute attribute = attributes[attributeCount - 1];
|
|
if (attribute.Depth != depth)
|
|
break;
|
|
space = attribute.XmlSpace;
|
|
lang = attribute.XmlLang;
|
|
attribute.Clear();
|
|
attributeCount--;
|
|
}
|
|
depth--;
|
|
}
|
|
|
|
public void AddLangAttribute(string lang)
|
|
{
|
|
AddAttribute();
|
|
this.lang = lang;
|
|
}
|
|
|
|
public void AddSpaceAttribute(XmlSpace space)
|
|
{
|
|
AddAttribute();
|
|
this.space = space;
|
|
}
|
|
|
|
void AddAttribute()
|
|
{
|
|
if (attributes == null)
|
|
{
|
|
attributes = new XmlAttribute[1];
|
|
}
|
|
else if (attributes.Length == attributeCount)
|
|
{
|
|
XmlAttribute[] newAttributes = new XmlAttribute[attributeCount * 2];
|
|
Array.Copy(attributes, newAttributes, attributeCount);
|
|
attributes = newAttributes;
|
|
}
|
|
XmlAttribute attribute = attributes[attributeCount];
|
|
if (attribute == null)
|
|
{
|
|
attribute = new XmlAttribute();
|
|
attributes[attributeCount] = attribute;
|
|
}
|
|
attribute.XmlLang = this.lang;
|
|
attribute.XmlSpace = this.space;
|
|
attribute.Depth = depth;
|
|
attributeCount++;
|
|
}
|
|
|
|
public string AddNamespace(string uri, XmlDictionaryString uriDictionaryString)
|
|
{
|
|
if (uri.Length == 0)
|
|
{
|
|
// Empty namespace can only be bound to the empty prefix
|
|
AddNamespaceIfNotDeclared(string.Empty, uri, uriDictionaryString);
|
|
return string.Empty;
|
|
}
|
|
else
|
|
{
|
|
for (int i = 0; i < prefixes.Length; i++)
|
|
{
|
|
string prefix = prefixes[i];
|
|
bool declared = false;
|
|
for (int j = nsCount - 1; j >= nsTop; j--)
|
|
{
|
|
Namespace nameSpace = namespaces[j];
|
|
if (nameSpace.Prefix == prefix)
|
|
{
|
|
declared = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!declared)
|
|
{
|
|
AddNamespace(prefix, uri, uriDictionaryString);
|
|
return prefix;
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public void AddNamespaceIfNotDeclared(string prefix, string uri, XmlDictionaryString uriDictionaryString)
|
|
{
|
|
if (LookupNamespace(prefix) != uri)
|
|
{
|
|
AddNamespace(prefix, uri, uriDictionaryString);
|
|
}
|
|
}
|
|
|
|
public void AddNamespace(string prefix, string uri, XmlDictionaryString uriDictionaryString)
|
|
{
|
|
if (prefix.Length >= 3)
|
|
{
|
|
// Upper and lower case letter differ by a bit.
|
|
if ((prefix[0] & ~32) == 'X' && (prefix[1] & ~32) == 'M' && (prefix[2] & ~32) == 'L')
|
|
{
|
|
if (prefix == "xml" && uri == xmlNamespace)
|
|
return;
|
|
if (prefix == "xmlns" && uri == xmlnsNamespace)
|
|
return;
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.XmlReservedPrefix), "prefix"));
|
|
}
|
|
}
|
|
Namespace nameSpace;
|
|
for (int i = nsCount - 1; i >= 0; i--)
|
|
{
|
|
nameSpace = namespaces[i];
|
|
if (nameSpace.Depth != depth)
|
|
break;
|
|
if (nameSpace.Prefix == prefix)
|
|
{
|
|
if (nameSpace.Uri == uri)
|
|
return;
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.XmlPrefixBoundToNamespace, prefix, nameSpace.Uri, uri), "prefix"));
|
|
}
|
|
}
|
|
if (prefix.Length != 0 && uri.Length == 0)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.XmlEmptyNamespaceRequiresNullPrefix), "prefix"));
|
|
if (uri.Length == xmlnsNamespace.Length && uri == xmlnsNamespace)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.XmlSpecificBindingNamespace, "xmlns", uri)));
|
|
// The addressing namespace and the xmlNamespace are the same length, so add a quick check to try to disambiguate
|
|
if (uri.Length == xmlNamespace.Length && uri[18] == 'X' && uri == xmlNamespace)
|
|
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.XmlSpecificBindingNamespace, "xml", uri)));
|
|
|
|
if (namespaces.Length == nsCount)
|
|
{
|
|
Namespace[] newNamespaces = new Namespace[nsCount * 2];
|
|
Array.Copy(namespaces, newNamespaces, nsCount);
|
|
namespaces = newNamespaces;
|
|
}
|
|
nameSpace = namespaces[nsCount];
|
|
if (nameSpace == null)
|
|
{
|
|
nameSpace = new Namespace();
|
|
namespaces[nsCount] = nameSpace;
|
|
}
|
|
nameSpace.Depth = depth;
|
|
nameSpace.Prefix = prefix;
|
|
nameSpace.Uri = uri;
|
|
nameSpace.UriDictionaryString = uriDictionaryString;
|
|
nsCount++;
|
|
lastNameSpace = null;
|
|
}
|
|
|
|
public string LookupPrefix(string ns)
|
|
{
|
|
if (lastNameSpace != null && lastNameSpace.Uri == ns)
|
|
return lastNameSpace.Prefix;
|
|
int nsCount = this.nsCount;
|
|
for (int i = nsCount - 1; i >= nsTop; i--)
|
|
{
|
|
Namespace nameSpace = namespaces[i];
|
|
if (object.ReferenceEquals(nameSpace.Uri, ns))
|
|
{
|
|
string prefix = nameSpace.Prefix;
|
|
// Make sure that the prefix refers to the namespace in scope
|
|
bool declared = false;
|
|
for (int j = i + 1; j < nsCount; j++)
|
|
{
|
|
if (namespaces[j].Prefix == prefix)
|
|
{
|
|
declared = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!declared)
|
|
{
|
|
lastNameSpace = nameSpace;
|
|
return prefix;
|
|
}
|
|
}
|
|
}
|
|
for (int i = nsCount - 1; i >= nsTop; i--)
|
|
{
|
|
Namespace nameSpace = namespaces[i];
|
|
if (nameSpace.Uri == ns)
|
|
{
|
|
string prefix = nameSpace.Prefix;
|
|
// Make sure that the prefix refers to the namespace in scope
|
|
bool declared = false;
|
|
for (int j = i + 1; j < nsCount; j++)
|
|
{
|
|
if (namespaces[j].Prefix == prefix)
|
|
{
|
|
declared = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!declared)
|
|
{
|
|
lastNameSpace = nameSpace;
|
|
return prefix;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ns.Length == 0)
|
|
{
|
|
// Make sure the default binding is still valid
|
|
bool emptyPrefixUnassigned = true;
|
|
for (int i = nsCount - 1; i >= nsTop; i--)
|
|
{
|
|
if (namespaces[i].Prefix.Length == 0)
|
|
{
|
|
emptyPrefixUnassigned = false;
|
|
break;
|
|
}
|
|
}
|
|
if (emptyPrefixUnassigned)
|
|
return string.Empty;
|
|
}
|
|
|
|
if (ns == xmlnsNamespace)
|
|
return "xmlns";
|
|
if (ns == xmlNamespace)
|
|
return "xml";
|
|
return null;
|
|
}
|
|
|
|
public string LookupAttributePrefix(string ns)
|
|
{
|
|
if (lastNameSpace != null && lastNameSpace.Uri == ns && lastNameSpace.Prefix.Length != 0)
|
|
return lastNameSpace.Prefix;
|
|
|
|
int nsCount = this.nsCount;
|
|
for (int i = nsCount - 1; i >= nsTop; i--)
|
|
{
|
|
Namespace nameSpace = namespaces[i];
|
|
|
|
if (object.ReferenceEquals(nameSpace.Uri, ns))
|
|
{
|
|
string prefix = nameSpace.Prefix;
|
|
if (prefix.Length != 0)
|
|
{
|
|
// Make sure that the prefix refers to the namespace in scope
|
|
bool declared = false;
|
|
for (int j = i + 1; j < nsCount; j++)
|
|
{
|
|
if (namespaces[j].Prefix == prefix)
|
|
{
|
|
declared = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!declared)
|
|
{
|
|
lastNameSpace = nameSpace;
|
|
return prefix;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for (int i = nsCount - 1; i >= nsTop; i--)
|
|
{
|
|
Namespace nameSpace = namespaces[i];
|
|
if (nameSpace.Uri == ns)
|
|
{
|
|
string prefix = nameSpace.Prefix;
|
|
if (prefix.Length != 0)
|
|
{
|
|
// Make sure that the prefix refers to the namespace in scope
|
|
bool declared = false;
|
|
for (int j = i + 1; j < nsCount; j++)
|
|
{
|
|
if (namespaces[j].Prefix == prefix)
|
|
{
|
|
declared = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!declared)
|
|
{
|
|
lastNameSpace = nameSpace;
|
|
return prefix;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (ns.Length == 0)
|
|
return string.Empty;
|
|
return null;
|
|
}
|
|
|
|
public string LookupNamespace(string prefix)
|
|
{
|
|
int nsCount = this.nsCount;
|
|
if (prefix.Length == 0)
|
|
{
|
|
for (int i = nsCount - 1; i >= nsTop; i--)
|
|
{
|
|
Namespace nameSpace = namespaces[i];
|
|
if (nameSpace.Prefix.Length == 0)
|
|
return nameSpace.Uri;
|
|
}
|
|
return string.Empty;
|
|
}
|
|
if (prefix.Length == 1)
|
|
{
|
|
char prefixChar = prefix[0];
|
|
for (int i = nsCount - 1; i >= nsTop; i--)
|
|
{
|
|
Namespace nameSpace = namespaces[i];
|
|
if (nameSpace.PrefixChar == prefixChar)
|
|
return nameSpace.Uri;
|
|
}
|
|
return null;
|
|
}
|
|
for (int i = nsCount - 1; i >= nsTop; i--)
|
|
{
|
|
Namespace nameSpace = namespaces[i];
|
|
if (nameSpace.Prefix == prefix)
|
|
return nameSpace.Uri;
|
|
}
|
|
if (prefix == "xmlns")
|
|
return xmlnsNamespace;
|
|
if (prefix == "xml")
|
|
return xmlNamespace;
|
|
return null;
|
|
}
|
|
|
|
public void Sign(XmlCanonicalWriter signingWriter)
|
|
{
|
|
int nsCount = this.nsCount;
|
|
Fx.Assert(nsCount >= 1 && namespaces[0].Prefix.Length == 0 && namespaces[0].Uri.Length == 0, "");
|
|
for (int i = 1; i < nsCount; i++)
|
|
{
|
|
Namespace nameSpace = namespaces[i];
|
|
|
|
bool found = false;
|
|
for (int j = i + 1; j < nsCount && !found; j++)
|
|
{
|
|
found = (nameSpace.Prefix == namespaces[j].Prefix);
|
|
}
|
|
|
|
if (!found)
|
|
{
|
|
signingWriter.WriteXmlnsAttribute(nameSpace.Prefix, nameSpace.Uri);
|
|
}
|
|
}
|
|
}
|
|
|
|
class XmlAttribute
|
|
{
|
|
XmlSpace space;
|
|
string lang;
|
|
int depth;
|
|
|
|
public XmlAttribute()
|
|
{
|
|
}
|
|
|
|
public int Depth
|
|
{
|
|
get
|
|
{
|
|
return depth;
|
|
}
|
|
set
|
|
{
|
|
depth = value;
|
|
}
|
|
}
|
|
|
|
public string XmlLang
|
|
{
|
|
get
|
|
{
|
|
return lang;
|
|
}
|
|
set
|
|
{
|
|
lang = value;
|
|
}
|
|
}
|
|
|
|
public XmlSpace XmlSpace
|
|
{
|
|
get
|
|
{
|
|
return space;
|
|
}
|
|
set
|
|
{
|
|
space = value;
|
|
}
|
|
}
|
|
|
|
public void Clear()
|
|
{
|
|
this.lang = null;
|
|
}
|
|
}
|
|
|
|
class Namespace
|
|
{
|
|
string prefix;
|
|
string ns;
|
|
XmlDictionaryString xNs;
|
|
int depth;
|
|
char prefixChar;
|
|
|
|
public Namespace()
|
|
{
|
|
}
|
|
|
|
public void Clear()
|
|
{
|
|
this.prefix = null;
|
|
this.prefixChar = (char)0;
|
|
this.ns = null;
|
|
this.xNs = null;
|
|
this.depth = 0;
|
|
}
|
|
|
|
public int Depth
|
|
{
|
|
get
|
|
{
|
|
return depth;
|
|
}
|
|
set
|
|
{
|
|
depth = value;
|
|
}
|
|
}
|
|
|
|
public char PrefixChar
|
|
{
|
|
get
|
|
{
|
|
return prefixChar;
|
|
}
|
|
}
|
|
|
|
public string Prefix
|
|
{
|
|
get
|
|
{
|
|
return prefix;
|
|
}
|
|
set
|
|
{
|
|
if (value.Length == 1)
|
|
prefixChar = value[0];
|
|
else
|
|
prefixChar = (char)0;
|
|
prefix = value;
|
|
}
|
|
}
|
|
|
|
public string Uri
|
|
{
|
|
get
|
|
{
|
|
return ns;
|
|
}
|
|
set
|
|
{
|
|
ns = value;
|
|
}
|
|
}
|
|
|
|
public XmlDictionaryString UriDictionaryString
|
|
{
|
|
get
|
|
{
|
|
return xNs;
|
|
}
|
|
set
|
|
{
|
|
xNs = value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
class XmlBaseWriterNodeWriterAsyncHelper
|
|
{
|
|
static AsyncEventArgsCallback onWriteComplete;
|
|
|
|
XmlBaseWriter writer;
|
|
byte[] buffer;
|
|
int offset;
|
|
int count;
|
|
int actualByteCount;
|
|
int totalByteCount;
|
|
AsyncEventArgs<XmlNodeWriterWriteBase64TextArgs> nodeWriterAsyncState;
|
|
XmlNodeWriterWriteBase64TextArgs nodeWriterArgs;
|
|
AsyncEventArgs<XmlWriteBase64AsyncArguments> inputState;
|
|
|
|
public XmlBaseWriterNodeWriterAsyncHelper(XmlBaseWriter writer)
|
|
{
|
|
this.writer = writer;
|
|
}
|
|
|
|
public void SetArguments(AsyncEventArgs<XmlWriteBase64AsyncArguments> inputState)
|
|
{
|
|
Fx.Assert(inputState != null, "InputState cannot be null.");
|
|
this.inputState = inputState;
|
|
this.buffer = inputState.Arguments.Buffer;
|
|
this.offset = inputState.Arguments.Offset;
|
|
this.count = inputState.Arguments.Count;
|
|
}
|
|
|
|
public AsyncCompletionResult StartAsync()
|
|
{
|
|
bool completeSelf = true;
|
|
|
|
if (this.count > 0)
|
|
{
|
|
// Bytes that have been already been read.
|
|
if (this.writer.trailByteCount > 0)
|
|
{
|
|
// Copy over up to 3 trailing bytes into the trailBytes buffer.
|
|
while (this.writer.trailByteCount < 3 && this.count > 0)
|
|
{
|
|
this.writer.trailBytes[this.writer.trailByteCount++] = this.buffer[this.offset++];
|
|
this.count--;
|
|
}
|
|
}
|
|
|
|
this.totalByteCount = this.writer.trailByteCount + this.count;
|
|
this.actualByteCount = this.totalByteCount - (this.totalByteCount % 3);
|
|
|
|
if (this.writer.trailBytes == null)
|
|
{
|
|
this.writer.trailBytes = new byte[3];
|
|
}
|
|
|
|
if (actualByteCount >= 3)
|
|
{
|
|
if (this.writer.attributeValue != null)
|
|
{
|
|
this.writer.WriteAttributeText(XmlConverter.Base64Encoding.GetString(this.writer.trailBytes, 0, this.writer.trailByteCount));
|
|
this.writer.WriteAttributeText(XmlConverter.Base64Encoding.GetString(this.buffer, this.offset, actualByteCount - this.writer.trailByteCount));
|
|
}
|
|
|
|
// StartContent/WriteBase64Text/EndContent will be called from HandleWriteBase64 as appropriate
|
|
completeSelf = HandleWriteBase64Text(false);
|
|
}
|
|
else
|
|
{
|
|
Buffer.BlockCopy(this.buffer, this.offset, this.writer.trailBytes, this.writer.trailByteCount, this.count);
|
|
this.writer.trailByteCount += this.count;
|
|
}
|
|
}
|
|
|
|
if (completeSelf)
|
|
{
|
|
this.Clear();
|
|
return AsyncCompletionResult.Completed;
|
|
}
|
|
|
|
return AsyncCompletionResult.Queued;
|
|
}
|
|
|
|
static void OnWriteComplete(IAsyncEventArgs asyncEventArgs)
|
|
{
|
|
bool completeSelf = false;
|
|
Exception completionException = null;
|
|
XmlBaseWriterNodeWriterAsyncHelper thisPtr = (XmlBaseWriterNodeWriterAsyncHelper)asyncEventArgs.AsyncState;
|
|
AsyncEventArgs<XmlWriteBase64AsyncArguments> inputState = thisPtr.inputState;
|
|
|
|
try
|
|
{
|
|
if (asyncEventArgs.Exception != null)
|
|
{
|
|
completionException = asyncEventArgs.Exception;
|
|
completeSelf = true;
|
|
}
|
|
else
|
|
{
|
|
completeSelf = thisPtr.HandleWriteBase64Text(true);
|
|
}
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
if (Fx.IsFatal(exception))
|
|
{
|
|
throw;
|
|
}
|
|
|
|
completionException = exception;
|
|
completeSelf = true;
|
|
}
|
|
|
|
if (completeSelf)
|
|
{
|
|
thisPtr.Clear();
|
|
inputState.Complete(false, completionException);
|
|
}
|
|
}
|
|
|
|
bool HandleWriteBase64Text(bool isAsyncCallback)
|
|
{
|
|
Fx.Assert(this.count > 0 && this.actualByteCount >= 3, "HandleWriteBase64Text cannot be invoked with less than 3 bytes.");
|
|
if (!writer.isXmlnsAttribute)
|
|
{
|
|
if (!isAsyncCallback)
|
|
{
|
|
if (this.nodeWriterAsyncState == null)
|
|
{
|
|
this.nodeWriterAsyncState = new AsyncEventArgs<XmlNodeWriterWriteBase64TextArgs>();
|
|
this.nodeWriterArgs = new XmlNodeWriterWriteBase64TextArgs();
|
|
}
|
|
if (onWriteComplete == null)
|
|
{
|
|
onWriteComplete = new AsyncEventArgsCallback(OnWriteComplete);
|
|
}
|
|
|
|
this.writer.StartContent();
|
|
this.nodeWriterArgs.TrailBuffer = this.writer.trailBytes;
|
|
this.nodeWriterArgs.TrailCount = this.writer.trailByteCount;
|
|
this.nodeWriterArgs.Buffer = this.buffer;
|
|
this.nodeWriterArgs.Offset = this.offset;
|
|
this.nodeWriterArgs.Count = this.actualByteCount - this.writer.trailByteCount;
|
|
|
|
this.nodeWriterAsyncState.Set(onWriteComplete, this.nodeWriterArgs, this);
|
|
if (this.writer.writer.WriteBase64TextAsync(this.nodeWriterAsyncState) != AsyncCompletionResult.Completed)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
this.nodeWriterAsyncState.Complete(true);
|
|
}
|
|
|
|
this.writer.EndContent();
|
|
}
|
|
|
|
this.writer.trailByteCount = (this.totalByteCount - this.actualByteCount);
|
|
if (this.writer.trailByteCount > 0)
|
|
{
|
|
int trailOffset = offset + count - this.writer.trailByteCount;
|
|
for (int i = 0; i < this.writer.trailByteCount; i++)
|
|
this.writer.trailBytes[i] = this.buffer[trailOffset++];
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void Clear()
|
|
{
|
|
this.inputState = null;
|
|
this.buffer = null;
|
|
this.offset = 0;
|
|
this.count = 0;
|
|
this.actualByteCount = 0;
|
|
this.totalByteCount = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|