File: System\Net\Mime\WriteStateInfoBase.cs
Web Access
Project: src\src\libraries\System.Net.Mail\src\System.Net.Mail.csproj (System.Net.Mail)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
namespace System.Net.Mime
{
    internal class WriteStateInfoBase
    {
        protected readonly byte[]? _header;
        protected readonly byte[]? _footer;
        protected readonly int _maxLineLength;
 
        protected byte[] _buffer;
        protected int _currentLineLength;
        protected int _currentBufferUsed;
 
        //1024 was originally set in the encoding streams
        protected const int DefaultBufferSize = 1024;
 
        internal WriteStateInfoBase()
        {
            _header = Array.Empty<byte>();
            _footer = Array.Empty<byte>();
            _maxLineLength = EncodedStreamFactory.DefaultMaxLineLength;
 
            _buffer = new byte[DefaultBufferSize];
            _currentLineLength = 0;
            _currentBufferUsed = 0;
        }
 
        internal WriteStateInfoBase(int bufferSize, byte[]? header, byte[]? footer, int maxLineLength)
            : this(bufferSize, header, footer, maxLineLength, 0)
        {
        }
 
        internal WriteStateInfoBase(int bufferSize, byte[]? header, byte[]? footer, int maxLineLength, int mimeHeaderLength)
        {
            _buffer = new byte[bufferSize];
            _header = header;
            _footer = footer;
            _maxLineLength = maxLineLength;
            // Account for header name, if any.  e.g. "Subject: "
            _currentLineLength = mimeHeaderLength;
            _currentBufferUsed = 0;
        }
 
        internal int FooterLength => _footer!.Length;
        internal byte[]? Footer => _footer;
        internal byte[]? Header => _header;
        internal byte[] Buffer => _buffer;
        internal int Length => _currentBufferUsed;
        internal int CurrentLineLength => _currentLineLength;
 
        // Make sure there is enough space in the buffer to write at least this many more bytes.
        // This should be called before ANY direct write to Buffer.
        private void EnsureSpaceInBuffer(int moreBytes)
        {
            int newsize = Buffer.Length;
            while (_currentBufferUsed + moreBytes >= newsize)
            {
                newsize *= 2;
            }
 
            if (newsize > Buffer.Length)
            {
                //try to resize- if the machine doesn't have the memory to resize just let it throw
                byte[] tempBuffer = new byte[newsize];
 
                _buffer.CopyTo(tempBuffer, 0);
                _buffer = tempBuffer;
            }
        }
 
        internal void Append(byte aByte)
        {
            EnsureSpaceInBuffer(1);
            Buffer[_currentBufferUsed++] = aByte;
            _currentLineLength++;
        }
 
        internal void Append(ReadOnlySpan<byte> bytes)
        {
            EnsureSpaceInBuffer(bytes.Length);
            bytes.CopyTo(_buffer.AsSpan(Length));
            _currentLineLength += bytes.Length;
            _currentBufferUsed += bytes.Length;
        }
 
        internal void AppendCRLF(bool includeSpace)
        {
            AppendFooter();
 
            //add soft line break
            Append("\r\n"u8);
            _currentLineLength = 0; // New Line
            if (includeSpace)
            {
                //add whitespace to new line (RFC 2045, soft CRLF must be followed by whitespace char)
                //space selected for parity with other MS email clients
                Append((byte)' ');
            }
 
            AppendHeader();
        }
 
        internal void AppendHeader()
        {
            if (Header != null && Header.Length != 0)
            {
                Append(Header);
            }
        }
 
        internal void AppendFooter()
        {
            if (Footer != null && Footer.Length != 0)
            {
                Append(Footer);
            }
        }
 
        internal int MaxLineLength => _maxLineLength;
 
        internal void Reset()
        {
            _currentBufferUsed = 0;
            _currentLineLength = 0;
        }
 
        internal void BufferFlushed()
        {
            _currentBufferUsed = 0;
        }
    }
}