File: System\Xml\XmlSigningNodeWriter.cs
Web Access
Project: src\src\libraries\System.Private.DataContractSerialization\src\System.Private.DataContractSerialization.csproj (System.Private.DataContractSerialization)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Diagnostics;
using System.IO;
using System.Runtime.Serialization;
using System.Text;
 
namespace System.Xml
{
    internal sealed class XmlSigningNodeWriter : XmlNodeWriter
    {
        private XmlNodeWriter _writer = null!; // initialized by SetOutput
        private XmlCanonicalWriter _signingWriter = null!; // initialized by SetOutput
        private byte[] _chars = null!; // initialized by SetOutput
        private byte[]? _base64Chars;
        private readonly bool _text;
 
        public XmlSigningNodeWriter(bool text)
        {
            _text = text;
        }
 
        public void SetOutput(XmlNodeWriter writer, Stream stream, bool includeComments, string[]? inclusivePrefixes)
        {
            _writer = writer;
            _signingWriter ??= new XmlCanonicalWriter();
            _signingWriter.SetOutput(stream, includeComments, inclusivePrefixes);
            _chars = new byte[XmlConverter.MaxPrimitiveChars];
            _base64Chars = null;
        }
 
        public XmlNodeWriter NodeWriter
        {
            get
            {
                return _writer;
            }
            set
            {
                _writer = value;
            }
        }
 
        public XmlCanonicalWriter CanonicalWriter
        {
            get
            {
                return _signingWriter;
            }
        }
 
        public override void Flush()
        {
            _writer.Flush();
            _signingWriter.Flush();
        }
 
        public override void Close()
        {
            _writer.Close();
            _signingWriter.Close();
        }
 
        public override void WriteDeclaration()
        {
            _writer.WriteDeclaration();
            _signingWriter.WriteDeclaration();
        }
 
        public override void WriteComment(string text)
        {
            _writer.WriteComment(text);
            _signingWriter.WriteComment(text);
        }
 
        public override void WriteCData(string text)
        {
            _writer.WriteCData(text);
            _signingWriter.WriteEscapedText(text);
        }
 
        public override void WriteStartElement(string? prefix, string localName)
        {
            Debug.Assert(prefix != null);
            _writer.WriteStartElement(prefix, localName);
            _signingWriter.WriteStartElement(prefix, localName);
        }
 
        public override void WriteStartElement(byte[] prefixBuffer, int prefixOffset, int prefixLength,
                                               byte[] localNameBuffer, int localNameOffset, int localNameLength)
        {
            _writer.WriteStartElement(prefixBuffer, prefixOffset, prefixLength, localNameBuffer, localNameOffset, localNameLength);
            _signingWriter.WriteStartElement(prefixBuffer, prefixOffset, prefixLength, localNameBuffer, localNameOffset, localNameLength);
        }
 
        public override void WriteStartElement(string? prefix, XmlDictionaryString localName)
        {
            Debug.Assert(prefix != null);
            _writer.WriteStartElement(prefix, localName);
            _signingWriter.WriteStartElement(prefix, localName.Value);
        }
 
        public override void WriteEndStartElement(bool isEmpty)
        {
            _writer.WriteEndStartElement(isEmpty);
            _signingWriter.WriteEndStartElement(isEmpty);
        }
 
        public override void WriteEndElement(string? prefix, string localName)
        {
            Debug.Assert(prefix != null);
            _writer.WriteEndElement(prefix, localName);
            _signingWriter.WriteEndElement(prefix, localName);
        }
 
        public override void WriteXmlnsAttribute(string? prefix, string ns)
        {
            Debug.Assert(prefix != null);
            _writer.WriteXmlnsAttribute(prefix, ns);
            _signingWriter.WriteXmlnsAttribute(prefix, ns);
        }
 
        public override void WriteXmlnsAttribute(byte[] prefixBuffer, int prefixOffset, int prefixLength,
                                                 byte[] nsBuffer, int nsOffset, int nsLength)
        {
            _writer.WriteXmlnsAttribute(prefixBuffer, prefixOffset, prefixLength, nsBuffer, nsOffset, nsLength);
            _signingWriter.WriteXmlnsAttribute(prefixBuffer, prefixOffset, prefixLength, nsBuffer, nsOffset, nsLength);
        }
 
        public override void WriteXmlnsAttribute(string? prefix, XmlDictionaryString ns)
        {
            Debug.Assert(prefix != null);
            _writer.WriteXmlnsAttribute(prefix, ns);
            _signingWriter.WriteXmlnsAttribute(prefix, ns.Value);
        }
 
        public override void WriteStartAttribute(string prefix, string localName)
        {
            _writer.WriteStartAttribute(prefix, localName);
            _signingWriter.WriteStartAttribute(prefix, localName);
        }
 
        public override void WriteStartAttribute(byte[] prefixBuffer, int prefixOffset, int prefixLength,
                                                 byte[] localNameBuffer, int localNameOffset, int localNameLength)
        {
            _writer.WriteStartAttribute(prefixBuffer, prefixOffset, prefixLength, localNameBuffer, localNameOffset, localNameLength);
            _signingWriter.WriteStartAttribute(prefixBuffer, prefixOffset, prefixLength, localNameBuffer, localNameOffset, localNameLength);
        }
 
        public override void WriteStartAttribute(string prefix, XmlDictionaryString localName)
        {
            _writer.WriteStartAttribute(prefix, localName);
            _signingWriter.WriteStartAttribute(prefix, localName.Value);
        }
 
        public override void WriteEndAttribute()
        {
            _writer.WriteEndAttribute();
            _signingWriter.WriteEndAttribute();
        }
 
        public override void WriteCharEntity(int ch)
        {
            _writer.WriteCharEntity(ch);
            _signingWriter.WriteCharEntity(ch);
        }
 
        public override void WriteEscapedText(string value)
        {
            _writer.WriteEscapedText(value);
            _signingWriter.WriteEscapedText(value);
        }
 
        public override void WriteEscapedText(char[] chars, int offset, int count)
        {
            _writer.WriteEscapedText(chars, offset, count);
            _signingWriter.WriteEscapedText(chars, offset, count);
        }
 
        public override void WriteEscapedText(XmlDictionaryString value)
        {
            _writer.WriteEscapedText(value);
            _signingWriter.WriteEscapedText(value.Value);
        }
 
        public override void WriteEscapedText(byte[] chars, int offset, int count)
        {
            _writer.WriteEscapedText(chars, offset, count);
            _signingWriter.WriteEscapedText(chars, offset, count);
        }
 
        public override void WriteText(string value)
        {
            _writer.WriteText(value);
            _signingWriter.WriteText(value);
        }
 
        public override void WriteText(char[] chars, int offset, int count)
        {
            _writer.WriteText(chars, offset, count);
            _signingWriter.WriteText(chars, offset, count);
        }
 
        public override void WriteText(byte[] chars, int offset, int count)
        {
            _writer.WriteText(chars, offset, count);
            _signingWriter.WriteText(chars, offset, count);
        }
 
        public override void WriteText(XmlDictionaryString value)
        {
            _writer.WriteText(value);
            _signingWriter.WriteText(value.Value);
        }
 
        public override void WriteInt32Text(int value)
        {
            int count = XmlConverter.ToChars(value, _chars, 0);
            if (_text)
                _writer.WriteText(_chars, 0, count);
            else
                _writer.WriteInt32Text(value);
            _signingWriter.WriteText(_chars, 0, count);
        }
 
        public override void WriteInt64Text(long value)
        {
            int count = XmlConverter.ToChars(value, _chars, 0);
            if (_text)
                _writer.WriteText(_chars, 0, count);
            else
                _writer.WriteInt64Text(value);
            _signingWriter.WriteText(_chars, 0, count);
        }
 
        public override void WriteBoolText(bool value)
        {
            int count = XmlConverter.ToChars(value, _chars, 0);
            if (_text)
                _writer.WriteText(_chars, 0, count);
            else
                _writer.WriteBoolText(value);
            _signingWriter.WriteText(_chars, 0, count);
        }
 
        public override void WriteUInt64Text(ulong value)
        {
            int count = XmlConverter.ToChars(value, _chars, 0);
            if (_text)
                _writer.WriteText(_chars, 0, count);
            else
                _writer.WriteUInt64Text(value);
            _signingWriter.WriteText(_chars, 0, count);
        }
 
        public override void WriteFloatText(float value)
        {
            int count = XmlConverter.ToChars(value, _chars, 0);
            if (_text)
                _writer.WriteText(_chars, 0, count);
            else
                _writer.WriteFloatText(value);
            _signingWriter.WriteText(_chars, 0, count);
        }
 
        public override void WriteDoubleText(double value)
        {
            int count = XmlConverter.ToChars(value, _chars, 0);
            if (_text)
                _writer.WriteText(_chars, 0, count);
            else
                _writer.WriteDoubleText(value);
            _signingWriter.WriteText(_chars, 0, count);
        }
 
        public override void WriteDecimalText(decimal value)
        {
            int count = XmlConverter.ToChars(value, _chars, 0);
            if (_text)
                _writer.WriteText(_chars, 0, count);
            else
                _writer.WriteDecimalText(value);
            _signingWriter.WriteText(_chars, 0, count);
        }
 
        public override void WriteDateTimeText(DateTime value)
        {
            int count = XmlConverter.ToChars(value, _chars, 0);
            if (_text)
                _writer.WriteText(_chars, 0, count);
            else
                _writer.WriteDateTimeText(value);
            _signingWriter.WriteText(_chars, 0, count);
        }
 
        public override void WriteUniqueIdText(UniqueId value)
        {
            string s = XmlConverter.ToString(value);
            if (_text)
                _writer.WriteText(s);
            else
                _writer.WriteUniqueIdText(value);
            _signingWriter.WriteText(s);
        }
 
        public override void WriteTimeSpanText(TimeSpan value)
        {
            string s = XmlConverter.ToString(value);
            if (_text)
                _writer.WriteText(s);
            else
                _writer.WriteTimeSpanText(value);
            _signingWriter.WriteText(s);
        }
 
        public override void WriteGuidText(Guid value)
        {
            string s = XmlConverter.ToString(value);
            if (_text)
                _writer.WriteText(s);
            else
                _writer.WriteGuidText(value);
            _signingWriter.WriteText(s);
        }
 
        public override void WriteStartListText()
        {
            _writer.WriteStartListText();
        }
 
        public override void WriteListSeparator()
        {
            _writer.WriteListSeparator();
            _signingWriter.WriteText(' ');
        }
 
        public override void WriteEndListText()
        {
            _writer.WriteEndListText();
        }
 
        public override void WriteBase64Text(byte[] trailBytes, int trailByteCount, byte[] buffer, int offset, int count)
        {
            if (trailByteCount > 0)
                WriteBase64Text(trailBytes, 0, trailByteCount);
            WriteBase64Text(buffer, offset, count);
            if (!_text)
            {
                _writer.WriteBase64Text(trailBytes, trailByteCount, buffer, offset, count);
            }
        }
 
        private void WriteBase64Text(byte[] buffer, int offset, int count)
        {
            _base64Chars ??= new byte[512];
            Base64Encoding encoding = DataContractSerializer.Base64Encoding;
            while (count >= 3)
            {
                int byteCount = Math.Min(_base64Chars.Length / 4 * 3, count - count % 3);
                int charCount = byteCount / 3 * 4;
                encoding.GetChars(buffer, offset, byteCount, _base64Chars, 0);
                _signingWriter.WriteText(_base64Chars, 0, charCount);
                if (_text)
                {
                    _writer.WriteText(_base64Chars, 0, charCount);
                }
                offset += byteCount;
                count -= byteCount;
            }
            if (count > 0)
            {
                encoding.GetChars(buffer, offset, count, _base64Chars, 0);
                _signingWriter.WriteText(_base64Chars, 0, 4);
                if (_text)
                {
                    _writer.WriteText(_base64Chars, 0, 4);
                }
            }
        }
 
        public override void WriteQualifiedName(string prefix, XmlDictionaryString localName)
        {
            _writer.WriteQualifiedName(prefix, localName);
            if (prefix.Length != 0)
            {
                _signingWriter.WriteText(prefix);
                _signingWriter.WriteText(":");
            }
            _signingWriter.WriteText(localName.Value);
        }
    }
}