DotNext by .NET Foundation and Contributors

<PackageReference Include="DotNext" Version="4.8.1" />

 Base64Encoder

public struct Base64Encoder
Represents base64 encoder suitable for encoding large binary data using streaming approach.
using DotNext.IO; using DotNext.Text; using System; using System.Buffers; using System.Buffers.Text; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; using System.Text.Unicode; using System.Threading; namespace DotNext.Buffers.Text { [StructLayout(LayoutKind.Auto)] [DebuggerDisplay("BufferedDataSize = {BufferedDataSize}, BufferedData = {BufferedData}")] public struct Base64Encoder { public const int MaxBufferedDataSize = 2; public const int MaxCharsToFlush = 4; public const int MaxInputSize = 1610612733; private const int DecodingBufferSize = 258; private const int EncodingBufferSize = 344; private ushort reservedBuffer; private int reservedBufferSize; public bool HasBufferedData { [IsReadOnly] get { return reservedBufferSize > 0; } } public int BufferedDataSize { [IsReadOnly] get { return reservedBufferSize; } } [System.Runtime.CompilerServices.Nullable(1)] [ExcludeFromCodeCoverage] [DebuggerBrowsable(DebuggerBrowsableState.Never)] private string BufferedData { [IsReadOnly] get { ReadOnlySpan<byte> bytes = AsReadOnlyBytes(ref reservedBuffer, reservedBufferSize); if (!bytes.IsEmpty) return Convert.ToBase64String(bytes, Base64FormattingOptions.None); return string.Empty; } } [IsReadOnly] public int GetBufferedData([LifetimeAnnotation(false, true)] Span<byte> output) { AsReadOnlyBytes(ref reservedBuffer, reservedBufferSize).CopyTo(output); return reservedBufferSize; } public void Reset() { reservedBufferSize = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static ReadOnlySpan<byte> AsReadOnlyBytes([In] [IsReadOnly] ref ushort value, int length) { return MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As<ushort, byte>(ref Unsafe.AsRef(ref value)), length); } private void EncodeToCharsCore<TWriter>([LifetimeAnnotation(false, true)] ReadOnlySpan<byte> bytes, [LifetimeAnnotation(true, false)] ref TWriter writer, bool flush) where TWriter : IBufferWriter<char> { int charsWritten = bytes.Length % 3; if ((charsWritten == 0) | flush) Reset(); else { charsWritten = bytes.Length - charsWritten; ReadOnlySpan<byte> readOnlySpan = bytes.Slice(charsWritten); readOnlySpan.CopyTo(Span.AsBytes(ref reservedBuffer)); reservedBufferSize = readOnlySpan.Length; bytes = bytes.Slice(0, charsWritten); } Convert.TryToBase64Chars(bytes, ((IBufferWriter<char>)writer).GetSpan(Base64.GetMaxEncodedToUtf8Length(bytes.Length)), out charsWritten, Base64FormattingOptions.None); ((IBufferWriter<char>)writer).Advance(charsWritten); } [SkipLocalsInit] private unsafe void CopyAndEncodeToChars<TWriter>([LifetimeAnnotation(false, true)] ReadOnlySpan<byte> bytes, [LifetimeAnnotation(true, false)] ref TWriter writer, bool flush) where TWriter : IBufferWriter<char> { int num = reservedBufferSize + bytes.Length; MemoryRental<byte> memoryRental; if ((uint)num > (uint)MemoryRental<byte>.StackallocThreshold) memoryRental = new MemoryRental<byte>(num, true); else { int num2 = num; memoryRental = new Span<byte>((void*)stackalloc byte[(int)(uint)num2], num2); } MemoryRental<byte> memoryRental2 = memoryRental; try { AsReadOnlyBytes(ref reservedBuffer, reservedBufferSize).CopyTo(memoryRental2.Span); bytes.CopyTo(memoryRental2.Span.Slice(reservedBufferSize)); EncodeToCharsCore(memoryRental2.Span, ref writer, flush); } finally { memoryRental2.Dispose(); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void EncodeToChars<TWriter>([LifetimeAnnotation(false, true)] ReadOnlySpan<byte> bytes, [LifetimeAnnotation(true, false)] ref TWriter writer, bool flush) where TWriter : IBufferWriter<char> { if (HasBufferedData) CopyAndEncodeToChars(bytes, ref writer, flush); else EncodeToCharsCore(bytes, ref writer, flush); } public void EncodeToChars([LifetimeAnnotation(false, true)] ReadOnlySpan<byte> bytes, [System.Runtime.CompilerServices.Nullable(1)] IBufferWriter<char> output, bool flush = false) { ArgumentNullException.ThrowIfNull((object)output, "output"); if (bytes.Length >= 1610612733) throw new ArgumentException(ExceptionMessages.LargeBuffer, "bytes"); EncodeToChars(bytes, ref output, flush); } public MemoryOwner<char> EncodeToChars([LifetimeAnnotation(false, true)] ReadOnlySpan<byte> bytes, [System.Runtime.CompilerServices.Nullable(2)] MemoryAllocator<char> allocator = null, bool flush = false) { if (bytes.Length >= 1610612733) throw new ArgumentException(ExceptionMessages.LargeBuffer, "bytes"); MemoryOwnerWrapper<char> writer = new MemoryOwnerWrapper<char>(allocator); EncodeToChars(bytes, ref writer, flush); return writer.Buffer; } [SkipLocalsInit] private unsafe void EncodeToCharsCore<TConsumer>([LifetimeAnnotation(false, true)] ReadOnlySpan<byte> bytes, TConsumer output, bool flush) where TConsumer : IReadOnlySpanConsumer<char> { Span<char> span = new Span<char>((void*)stackalloc byte[688], 344); int producedChars; while (true) { ReadOnlySpan<byte> input = bytes.TrimLength(258); if (<EncodeToCharsCore>g__Encode|21_0<TConsumer>(input, span, out int consumedBytes, out producedChars)) Reset(); else { reservedBufferSize = input.Length - consumedBytes; input.Slice(consumedBytes).CopyTo(Span.AsBytes(ref reservedBuffer)); } if (consumedBytes <= 0 || producedChars <= 0) break; ((IReadOnlySpanConsumer<char>)output).Invoke((ReadOnlySpan<char>)span.Slice(0, producedChars)); bytes = bytes.Slice(consumedBytes); } if (HasBufferedData & flush) { Convert.TryToBase64Chars(AsReadOnlyBytes(ref reservedBuffer, reservedBufferSize), span, out producedChars, Base64FormattingOptions.None); Reset(); ((IReadOnlySpanConsumer<char>)output).Invoke((ReadOnlySpan<char>)span.Slice(0, producedChars)); } } [SkipLocalsInit] private unsafe void CopyAndEncodeToChars<TConsumer>([LifetimeAnnotation(false, true)] ReadOnlySpan<byte> bytes, TConsumer output, bool flush) where TConsumer : IReadOnlySpanConsumer<char> { int num = reservedBufferSize + bytes.Length; MemoryRental<byte> memoryRental; if ((uint)num > (uint)MemoryRental<char>.StackallocThreshold) memoryRental = new MemoryRental<byte>(num, true); else { int num2 = num; memoryRental = new Span<byte>((void*)stackalloc byte[(int)(uint)num2], num2); } MemoryRental<byte> memoryRental2 = memoryRental; try { AsReadOnlyBytes(ref reservedBuffer, reservedBufferSize).CopyTo(memoryRental2.Span); bytes.CopyTo(memoryRental2.Span.Slice(reservedBufferSize)); EncodeToCharsCore(memoryRental2.Span, output, flush); } finally { memoryRental2.Dispose(); } } [System.Runtime.CompilerServices.NullableContext(1)] public void EncodeToChars<TConsumer>([LifetimeAnnotation(false, true)] [System.Runtime.CompilerServices.Nullable(0)] ReadOnlySpan<byte> bytes, TConsumer output, bool flush = false) where TConsumer : IReadOnlySpanConsumer<char> { if (HasBufferedData) CopyAndEncodeToChars(bytes, output, flush); else EncodeToCharsCore(bytes, output, flush); } [System.Runtime.CompilerServices.NullableContext(1)] public void EncodeToChars<[System.Runtime.CompilerServices.Nullable(2)] TArg>([LifetimeAnnotation(false, true)] [System.Runtime.CompilerServices.Nullable(0)] ReadOnlySpan<byte> bytes, ReadOnlySpanAction<char, TArg> output, TArg arg, bool flush = false) { EncodeToChars(bytes, new DelegatingReadOnlySpanConsumer<char, TArg>(output, arg), flush); } [CLSCompliant(false)] public void EncodeToChars<[System.Runtime.CompilerServices.Nullable(2)] TArg>([LifetimeAnnotation(false, true)] ReadOnlySpan<byte> bytes, [System.Runtime.CompilerServices.Nullable(new byte[] { 0, 0, 1 })] IntPtr output, [System.Runtime.CompilerServices.Nullable(1)] TArg arg, bool flush = false) { EncodeToChars(bytes, new ReadOnlySpanConsumer<char, TArg>(output, arg), flush); } public void EncodeToChars([LifetimeAnnotation(false, true)] ReadOnlySpan<byte> bytes, [System.Runtime.CompilerServices.Nullable(1)] TextWriter output, bool flush = false) { EncodeToChars(bytes, (TextConsumer)output, flush); } public void EncodeToChars([LifetimeAnnotation(false, true)] ReadOnlySpan<byte> bytes, [System.Runtime.CompilerServices.Nullable(1)] StringBuilder output, bool flush = false) { EncodeToChars(bytes, (StringBuilderConsumer)output, flush); } [System.Runtime.CompilerServices.NullableContext(2)] [AsyncIteratorStateMachine(typeof(<EncodeToCharsAsync>d__28))] [return: System.Runtime.CompilerServices.Nullable(new byte[] { 1, 0 })] public static IAsyncEnumerable<ReadOnlyMemory<char>> EncodeToCharsAsync([System.Runtime.CompilerServices.Nullable(new byte[] { 1, 0 })] IAsyncEnumerable<ReadOnlyMemory<byte>> bytes, MemoryAllocator<char> allocator = null, [EnumeratorCancellation] CancellationToken token = default(CancellationToken)) { <EncodeToCharsAsync>d__28 <EncodeToCharsAsync>d__ = new <EncodeToCharsAsync>d__28(-2); <EncodeToCharsAsync>d__.<>3__bytes = bytes; <EncodeToCharsAsync>d__.<>3__allocator = allocator; <EncodeToCharsAsync>d__.<>3__token = token; return <EncodeToCharsAsync>d__; } public unsafe int Flush([LifetimeAnnotation(false, true)] Span<char> output) { int charsWritten; if (reservedBufferSize == 0 || output.IsEmpty) charsWritten = 0; else { Span<byte> output2 = new Span<byte>(stackalloc byte[4], 4); charsWritten = Flush(output2); Utf8.ToUtf16(output2.Slice(0, charsWritten), output, out int _, out charsWritten, true, true); } return charsWritten; } private void EncodeToUtf8Core<TWriter>([LifetimeAnnotation(false, true)] ReadOnlySpan<byte> bytes, [LifetimeAnnotation(true, false)] ref TWriter writer, bool flush) where TWriter : IBufferWriter<byte> { int bytesWritten = Base64.GetMaxEncodedToUtf8Length(bytes.Length); Span<byte> span = ((IBufferWriter<byte>)writer).GetSpan(bytesWritten); int bytesConsumed; OperationStatus operationStatus = Base64.EncodeToUtf8(bytes, span, out bytesConsumed, out bytesWritten, (bytes.Length % 3 == 0) | flush); if ((uint)operationStatus > 1) { if (operationStatus == OperationStatus.NeedMoreData) { reservedBufferSize = bytes.Length - bytesConsumed; bytes.Slice(bytesConsumed).CopyTo(Span.AsBytes(ref reservedBuffer)); } } else Reset(); ((IBufferWriter<byte>)writer).Advance(bytesWritten); } [SkipLocalsInit] private unsafe void CopyAndEncodeToUtf8<TWriter>([LifetimeAnnotation(false, true)] ReadOnlySpan<byte> bytes, [LifetimeAnnotation(true, false)] ref TWriter writer, bool flush) where TWriter : IBufferWriter<byte> { int num = reservedBufferSize + bytes.Length; MemoryRental<byte> memoryRental; if ((uint)num > (uint)MemoryRental<byte>.StackallocThreshold) memoryRental = new MemoryRental<byte>(num, true); else { int num2 = num; memoryRental = new Span<byte>((void*)stackalloc byte[(int)(uint)num2], num2); } MemoryRental<byte> memoryRental2 = memoryRental; try { AsReadOnlyBytes(ref reservedBuffer, reservedBufferSize).CopyTo(memoryRental2.Span); bytes.CopyTo(memoryRental2.Span.Slice(reservedBufferSize)); EncodeToUtf8Core(memoryRental2.Span, ref writer, flush); } finally { memoryRental2.Dispose(); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void EncodeToUtf8<TWriter>([LifetimeAnnotation(false, true)] ReadOnlySpan<byte> bytes, [LifetimeAnnotation(true, false)] ref TWriter writer, bool flush) where TWriter : IBufferWriter<byte> { if (HasBufferedData) CopyAndEncodeToUtf8(bytes, ref writer, flush); else EncodeToUtf8Core(bytes, ref writer, flush); } public void EncodeToUtf8([LifetimeAnnotation(false, true)] ReadOnlySpan<byte> bytes, [System.Runtime.CompilerServices.Nullable(1)] IBufferWriter<byte> output, bool flush = false) { ArgumentNullException.ThrowIfNull((object)output, "output"); if (bytes.Length > 1610612733) throw new ArgumentException(ExceptionMessages.LargeBuffer, "bytes"); EncodeToUtf8(bytes, ref output, flush); } public MemoryOwner<byte> EncodeToUtf8([LifetimeAnnotation(false, true)] ReadOnlySpan<byte> bytes, [System.Runtime.CompilerServices.Nullable(2)] MemoryAllocator<byte> allocator = null, bool flush = false) { if (bytes.Length > 1610612733) throw new ArgumentException(ExceptionMessages.LargeBuffer, "bytes"); MemoryOwnerWrapper<byte> writer = new MemoryOwnerWrapper<byte>(allocator); EncodeToUtf8(bytes, ref writer, flush); return writer.Buffer; } [SkipLocalsInit] private unsafe void EncodeToUtf8Core<TConsumer>([LifetimeAnnotation(false, true)] ReadOnlySpan<byte> bytes, TConsumer output, bool flush) where TConsumer : IReadOnlySpanConsumer<byte> { Span<byte> utf = new Span<byte>((void*)stackalloc byte[344], 344); int bytesConsumed; int bytesWritten; while (true) { OperationStatus operationStatus = Base64.EncodeToUtf8(bytes, utf, out bytesConsumed, out bytesWritten, bytes.Length % 3 == 0); if ((uint)operationStatus > 1) { if (operationStatus == OperationStatus.NeedMoreData) { reservedBufferSize = bytes.Length - bytesConsumed; bytes.Slice(bytesConsumed).CopyTo(Span.AsBytes(ref reservedBuffer)); } } else Reset(); if (bytesWritten <= 0 || bytesConsumed <= 0) break; ((IReadOnlySpanConsumer<byte>)output).Invoke((ReadOnlySpan<byte>)utf.Slice(0, bytesWritten)); bytes = bytes.Slice(bytesConsumed); } if (HasBufferedData & flush) { Base64.EncodeToUtf8(AsReadOnlyBytes(ref reservedBuffer, reservedBufferSize), utf, out bytesConsumed, out bytesWritten, true); Reset(); ((IReadOnlySpanConsumer<byte>)output).Invoke((ReadOnlySpan<byte>)utf.Slice(0, bytesWritten)); } } [SkipLocalsInit] private unsafe void CopyAndEncodeToUtf8<TConsumer>([LifetimeAnnotation(false, true)] ReadOnlySpan<byte> bytes, TConsumer output, bool flush) where TConsumer : IReadOnlySpanConsumer<byte> { int num = reservedBufferSize + bytes.Length; MemoryRental<byte> memoryRental; if ((uint)num > (uint)MemoryRental<byte>.StackallocThreshold) memoryRental = new MemoryRental<byte>(num, true); else { int num2 = num; memoryRental = new Span<byte>((void*)stackalloc byte[(int)(uint)num2], num2); } MemoryRental<byte> memoryRental2 = memoryRental; try { AsReadOnlyBytes(ref reservedBuffer, reservedBufferSize).CopyTo(memoryRental2.Span); bytes.CopyTo(memoryRental2.Span.Slice(reservedBufferSize)); EncodeToUtf8Core(memoryRental2.Span, output, flush); } finally { memoryRental2.Dispose(); } } [System.Runtime.CompilerServices.NullableContext(1)] public void EncodeToUtf8<TConsumer>([LifetimeAnnotation(false, true)] [System.Runtime.CompilerServices.Nullable(0)] ReadOnlySpan<byte> bytes, TConsumer output, bool flush = false) where TConsumer : IReadOnlySpanConsumer<byte> { if (HasBufferedData) CopyAndEncodeToUtf8(bytes, output, flush); else EncodeToUtf8Core(bytes, output, flush); } [System.Runtime.CompilerServices.NullableContext(1)] public void EncodeToUtf8<[System.Runtime.CompilerServices.Nullable(2)] TArg>([LifetimeAnnotation(false, true)] [System.Runtime.CompilerServices.Nullable(0)] ReadOnlySpan<byte> bytes, ReadOnlySpanAction<byte, TArg> output, TArg arg, bool flush = false) { EncodeToUtf8(bytes, new DelegatingReadOnlySpanConsumer<byte, TArg>(output, arg), flush); } [CLSCompliant(false)] public void EncodeToUtf8<[System.Runtime.CompilerServices.Nullable(2)] TArg>([LifetimeAnnotation(false, true)] ReadOnlySpan<byte> bytes, [System.Runtime.CompilerServices.Nullable(new byte[] { 0, 0, 1 })] IntPtr output, [System.Runtime.CompilerServices.Nullable(1)] TArg arg, bool flush = false) { EncodeToUtf8(bytes, new ReadOnlySpanConsumer<byte, TArg>(output, arg), flush); } public void EncodeToUtf8([LifetimeAnnotation(false, true)] ReadOnlySpan<byte> bytes, [System.Runtime.CompilerServices.Nullable(1)] Stream output, bool flush = false) { EncodeToUtf8(bytes, (StreamConsumer)output, flush); } [System.Runtime.CompilerServices.NullableContext(2)] [AsyncIteratorStateMachine(typeof(<EncodeToUtf8Async>d__41))] [return: System.Runtime.CompilerServices.Nullable(new byte[] { 1, 0 })] public static IAsyncEnumerable<ReadOnlyMemory<byte>> EncodeToUtf8Async([System.Runtime.CompilerServices.Nullable(new byte[] { 1, 0 })] IAsyncEnumerable<ReadOnlyMemory<byte>> bytes, MemoryAllocator<byte> allocator = null, [EnumeratorCancellation] CancellationToken token = default(CancellationToken)) { <EncodeToUtf8Async>d__41 <EncodeToUtf8Async>d__ = new <EncodeToUtf8Async>d__41(-2); <EncodeToUtf8Async>d__.<>3__bytes = bytes; <EncodeToUtf8Async>d__.<>3__allocator = allocator; <EncodeToUtf8Async>d__.<>3__token = token; return <EncodeToUtf8Async>d__; } public int Flush([LifetimeAnnotation(false, true)] Span<byte> output) { int bytesWritten; if (reservedBufferSize != 0 && !output.IsEmpty) { Base64.EncodeToUtf8(AsReadOnlyBytes(ref reservedBuffer, reservedBufferSize), output, out int bytesConsumed, out bytesWritten, true); reservedBufferSize -= bytesConsumed; return bytesWritten; } bytesWritten = 0; return bytesWritten; } } }