DotNext by .NET Foundation and Contributors

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

 Base64Decoder

public struct Base64Decoder
Represents base64 decoder suitable for decoding large base64-encoded binary data using streaming approach.
using DotNext.IO; using System; using System.Buffers; using System.Buffers.Text; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading; namespace DotNext.Buffers.Text { [StructLayout(LayoutKind.Auto)] [DebuggerDisplay("NeedMoreData = {NeedMoreData}")] public struct Base64Decoder { private const int DecodingBufferSize = 258; private ulong reservedBuffer; private int reservedBufferSize; public bool NeedMoreData { [IsReadOnly] get { return reservedBufferSize > 0; } } public void Reset() { reservedBufferSize = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static Span<char> AsChars(ref ulong value) { return MemoryMarshal.CreateSpan(ref Unsafe.As<ulong, char>(ref value), 4); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static ReadOnlySpan<char> AsChars([In] [IsReadOnly] ref ulong value, int length) { return MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As<ulong, char>(ref Unsafe.AsRef(ref value)), length); } private bool DecodeFromUtf16Core<TWriter>(ReadOnlySpan<char> chars, ref TWriter writer) where TWriter : IBufferWriter<byte> { int bytesWritten = chars.Length & 3; if (bytesWritten > 0) { bytesWritten = chars.Length - bytesWritten; ReadOnlySpan<char> readOnlySpan = chars.Slice(bytesWritten); readOnlySpan.CopyTo(AsChars(ref reservedBuffer)); reservedBufferSize = readOnlySpan.Length; chars = chars.Slice(0, bytesWritten); } else Reset(); if (!Convert.TryFromBase64Chars(chars, ((IBufferWriter<byte>)writer).GetSpan(chars.Length), out bytesWritten)) return false; ((IBufferWriter<byte>)writer).Advance(bytesWritten); return true; } [SkipLocalsInit] private unsafe bool CopyAndDecodeFromUtf16<TWriter>(ReadOnlySpan<char> chars, ref TWriter writer) where TWriter : IBufferWriter<byte> { int num = reservedBufferSize + chars.Length; MemoryRental<char> memoryRental; if ((uint)num > (uint)MemoryRental<char>.StackallocThreshold) memoryRental = new MemoryRental<char>(num, true); else { int num2 = num; memoryRental = new Span<char>((void*)stackalloc byte[(int)checked(unchecked((ulong)(uint)num2) * 2)], num2); } MemoryRental<char> memoryRental2 = memoryRental; try { AsChars(ref reservedBuffer, reservedBufferSize).CopyTo(memoryRental2.Span); chars.CopyTo(memoryRental2.Span.Slice(reservedBufferSize)); return DecodeFromUtf16Core(memoryRental2.Span, ref writer); } finally { memoryRental2.Dispose(); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] private bool DecodeFromUtf16<TWriter>(ReadOnlySpan<char> chars, ref TWriter writer) where TWriter : IBufferWriter<byte> { if (!NeedMoreData) return DecodeFromUtf16Core(chars, ref writer); return CopyAndDecodeFromUtf16(chars, ref writer); } public void DecodeFromUtf16(ReadOnlySpan<char> chars, [System.Runtime.CompilerServices.Nullable(1)] IBufferWriter<byte> output) { ArgumentNullException.ThrowIfNull((object)output, "output"); if (!DecodeFromUtf16(chars, ref output)) throw new FormatException(ExceptionMessages.MalformedBase64); } public void DecodeFromUtf16([In] [IsReadOnly] ref ReadOnlySequence<char> chars, [System.Runtime.CompilerServices.Nullable(1)] IBufferWriter<byte> output) { ArgumentNullException.ThrowIfNull((object)output, "output"); ReadOnlySequence<char>.Enumerator enumerator = chars.GetEnumerator(); do { if (!enumerator.MoveNext()) return; } while (DecodeFromUtf16(enumerator.Current.Span, ref output)); throw new FormatException(ExceptionMessages.MalformedBase64); } public MemoryOwner<byte> DecodeFromUtf16(ReadOnlySpan<char> chars, [System.Runtime.CompilerServices.Nullable(2)] MemoryAllocator<byte> allocator = null) { MemoryOwnerWrapper<byte> writer = new MemoryOwnerWrapper<byte>(allocator); if (chars.IsEmpty || DecodeFromUtf16(chars, ref writer)) return writer.Buffer; writer.Buffer.Dispose(); throw new FormatException(ExceptionMessages.MalformedBase64); } [SkipLocalsInit] private unsafe void DecodeFromUtf16Core<TConsumer>(ReadOnlySpan<char> chars, TConsumer output) where TConsumer : IReadOnlySpanConsumer<byte> { Span<byte> output2 = new Span<byte>((void*)stackalloc byte[258], 258); while (true) { ReadOnlySpan<char> input = chars.TrimLength(344); if (<DecodeFromUtf16Core>g__Decode|14_0<TConsumer>(input, output2, out int consumedChars, out int producedBytes)) Reset(); else { reservedBufferSize = input.Length - consumedChars; input.Slice(consumedChars).CopyTo(AsChars(ref reservedBuffer)); } if (consumedChars <= 0 || producedBytes <= 0) break; ((IReadOnlySpanConsumer<byte>)output).Invoke((ReadOnlySpan<byte>)output2.Slice(0, producedBytes)); chars = chars.Slice(consumedChars); } } [SkipLocalsInit] private unsafe void CopyAndDecodeFromUtf16<TConsumer>(ReadOnlySpan<char> chars, TConsumer output) where TConsumer : IReadOnlySpanConsumer<byte> { int num = reservedBufferSize + chars.Length; MemoryRental<char> memoryRental; if ((uint)num > (uint)MemoryRental<char>.StackallocThreshold) memoryRental = new MemoryRental<char>(num, true); else { int num2 = num; memoryRental = new Span<char>((void*)stackalloc byte[(int)checked(unchecked((ulong)(uint)num2) * 2)], num2); } MemoryRental<char> memoryRental2 = memoryRental; try { AsChars(ref reservedBuffer, reservedBufferSize).CopyTo(memoryRental2.Span); chars.CopyTo(memoryRental2.Span.Slice(reservedBufferSize)); DecodeFromUtf16Core(memoryRental2.Span, output); } finally { memoryRental2.Dispose(); } } [System.Runtime.CompilerServices.NullableContext(1)] public void DecodeFromUtf16<TConsumer>([System.Runtime.CompilerServices.Nullable(0)] ReadOnlySpan<char> chars, TConsumer output) where TConsumer : IReadOnlySpanConsumer<byte> { if (NeedMoreData) CopyAndDecodeFromUtf16(chars, output); else DecodeFromUtf16Core(chars, output); } [System.Runtime.CompilerServices.NullableContext(1)] public void DecodeFromUtf16<[System.Runtime.CompilerServices.Nullable(2)] TArg>([System.Runtime.CompilerServices.Nullable(0)] ReadOnlySpan<char> chars, ReadOnlySpanAction<byte, TArg> callback, TArg arg) { DecodeFromUtf16(chars, new DelegatingReadOnlySpanConsumer<byte, TArg>(callback, arg)); } [CLSCompliant(false)] public void DecodeFromUtf16<[System.Runtime.CompilerServices.Nullable(2)] TArg>(ReadOnlySpan<char> chars, [System.Runtime.CompilerServices.Nullable(new byte[] { 0, 0, 1 })] IntPtr callback, [System.Runtime.CompilerServices.Nullable(1)] TArg arg) { DecodeFromUtf16(chars, new ReadOnlySpanConsumer<byte, TArg>(callback, arg)); } [System.Runtime.CompilerServices.NullableContext(2)] [AsyncIteratorStateMachine(typeof(<DecodeFromUtf16Async>d__19))] [return: System.Runtime.CompilerServices.Nullable(new byte[] { 1, 0 })] public static IAsyncEnumerable<ReadOnlyMemory<byte>> DecodeFromUtf16Async([System.Runtime.CompilerServices.Nullable(new byte[] { 1, 0 })] IAsyncEnumerable<ReadOnlyMemory<char>> chars, MemoryAllocator<byte> allocator = null, [EnumeratorCancellation] CancellationToken token = default(CancellationToken)) { <DecodeFromUtf16Async>d__19 <DecodeFromUtf16Async>d__ = new <DecodeFromUtf16Async>d__19(-2); <DecodeFromUtf16Async>d__.<>3__chars = chars; <DecodeFromUtf16Async>d__.<>3__allocator = allocator; <DecodeFromUtf16Async>d__.<>3__token = token; return <DecodeFromUtf16Async>d__; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static ReadOnlySpan<byte> AsReadOnlyBytes([In] [IsReadOnly] ref ulong value, int length) { return MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As<ulong, byte>(ref Unsafe.AsRef(ref value)), length); } private bool DecodeFromUtf8Core<TWriter>(ReadOnlySpan<byte> utf8Chars, ref TWriter writer) where TWriter : IBufferWriter<byte> { int bytesWritten = Base64.GetMaxDecodedFromUtf8Length(utf8Chars.Length); Span<byte> span = ((IBufferWriter<byte>)writer).GetSpan(bytesWritten); int bytesConsumed; OperationStatus operationStatus = Base64.DecodeFromUtf8(utf8Chars, span, out bytesConsumed, out bytesWritten, (utf8Chars.Length & 3) == 0); if ((uint)operationStatus > 1) { if (operationStatus != OperationStatus.NeedMoreData) return false; reservedBufferSize = utf8Chars.Length - bytesConsumed; utf8Chars.Slice(bytesConsumed).CopyTo(Span.AsBytes(ref reservedBuffer)); } else Reset(); ((IBufferWriter<byte>)writer).Advance(bytesWritten); return true; } [SkipLocalsInit] private unsafe bool CopyAndDecodeFromUtf8<TWriter>(ReadOnlySpan<byte> utf8Chars, ref TWriter writer) where TWriter : IBufferWriter<byte> { int num = reservedBufferSize + utf8Chars.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); utf8Chars.CopyTo(memoryRental2.Span.Slice(reservedBufferSize)); return DecodeFromUtf8Core(memoryRental2.Span, ref writer); } finally { memoryRental2.Dispose(); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] private bool DecodeFromUtf8<TWriter>(ReadOnlySpan<byte> utf8Chars, ref TWriter writer) where TWriter : IBufferWriter<byte> { if (!NeedMoreData) return DecodeFromUtf8Core(utf8Chars, ref writer); return CopyAndDecodeFromUtf8(utf8Chars, ref writer); } public void DecodeFromUtf8(ReadOnlySpan<byte> utf8Chars, [System.Runtime.CompilerServices.Nullable(1)] IBufferWriter<byte> output) { ArgumentNullException.ThrowIfNull((object)output, "output"); if (!DecodeFromUtf8(utf8Chars, ref output)) throw new FormatException(ExceptionMessages.MalformedBase64); } public void DecodeFromUtf8([In] [IsReadOnly] ref ReadOnlySequence<byte> utf8Chars, [System.Runtime.CompilerServices.Nullable(1)] IBufferWriter<byte> output) { ArgumentNullException.ThrowIfNull((object)output, "output"); ReadOnlySequence<byte>.Enumerator enumerator = utf8Chars.GetEnumerator(); do { if (!enumerator.MoveNext()) return; } while (DecodeFromUtf8(enumerator.Current.Span, ref output)); throw new FormatException(ExceptionMessages.MalformedBase64); } public MemoryOwner<byte> DecodeFromUtf8(ReadOnlySpan<byte> utf8Chars, [System.Runtime.CompilerServices.Nullable(2)] MemoryAllocator<byte> allocator = null) { MemoryOwnerWrapper<byte> writer = new MemoryOwnerWrapper<byte>(allocator); if (utf8Chars.IsEmpty || DecodeFromUtf8(utf8Chars, ref writer)) return writer.Buffer; writer.Buffer.Dispose(); throw new FormatException(ExceptionMessages.MalformedBase64); } [SkipLocalsInit] private unsafe void DecodeFromUtf8Core<TConsumer>(ReadOnlySpan<byte> utf8Chars, TConsumer output) where TConsumer : IReadOnlySpanConsumer<byte> { Span<byte> bytes = new Span<byte>((void*)stackalloc byte[258], 258); while (true) { int bytesConsumed; int bytesWritten; OperationStatus operationStatus = Base64.DecodeFromUtf8(utf8Chars, bytes, out bytesConsumed, out bytesWritten, (utf8Chars.Length & 3) == 0); if ((uint)operationStatus > 1) { if (operationStatus != OperationStatus.NeedMoreData) break; reservedBufferSize = utf8Chars.Length - bytesConsumed; utf8Chars.Slice(bytesConsumed).CopyTo(Span.AsBytes(ref reservedBuffer)); } else Reset(); if (bytesWritten <= 0 || bytesConsumed <= 0) return; ((IReadOnlySpanConsumer<byte>)output).Invoke((ReadOnlySpan<byte>)bytes.Slice(0, bytesWritten)); utf8Chars = utf8Chars.Slice(bytesConsumed); } throw new FormatException(ExceptionMessages.MalformedBase64); } [SkipLocalsInit] private unsafe void CopyAndDecodeFromUtf8<TConsumer>(ReadOnlySpan<byte> utf8Chars, TConsumer output) where TConsumer : IReadOnlySpanConsumer<byte> { int num = reservedBufferSize + utf8Chars.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); utf8Chars.CopyTo(memoryRental2.Span.Slice(reservedBufferSize)); DecodeFromUtf8Core(memoryRental2.Span, output); } finally { memoryRental2.Dispose(); } } [System.Runtime.CompilerServices.NullableContext(1)] public void DecodeFromUtf8<TConsumer>([System.Runtime.CompilerServices.Nullable(0)] ReadOnlySpan<byte> utf8Chars, TConsumer output) where TConsumer : IReadOnlySpanConsumer<byte> { if (NeedMoreData) CopyAndDecodeFromUtf8(utf8Chars, output); else DecodeFromUtf8Core(utf8Chars, output); } [System.Runtime.CompilerServices.NullableContext(1)] public void DecodeFromUtf8<[System.Runtime.CompilerServices.Nullable(2)] TArg>([System.Runtime.CompilerServices.Nullable(0)] ReadOnlySpan<byte> utf8Chars, ReadOnlySpanAction<byte, TArg> output, TArg arg) { DecodeFromUtf8(utf8Chars, new DelegatingReadOnlySpanConsumer<byte, TArg>(output, arg)); } [CLSCompliant(false)] public void DecodeFromUtf8<[System.Runtime.CompilerServices.Nullable(2)] TArg>(ReadOnlySpan<byte> utf8Chars, [System.Runtime.CompilerServices.Nullable(new byte[] { 0, 0, 1 })] IntPtr output, [System.Runtime.CompilerServices.Nullable(1)] TArg arg) { DecodeFromUtf8(utf8Chars, new ReadOnlySpanConsumer<byte, TArg>(output, arg)); } public void DecodeFromUtf8(ReadOnlySpan<byte> utf8Chars, [System.Runtime.CompilerServices.Nullable(1)] Stream output) { DecodeFromUtf8(utf8Chars, (StreamConsumer)output); } [System.Runtime.CompilerServices.NullableContext(2)] [AsyncIteratorStateMachine(typeof(<DecodeFromUtf8Async>d__33))] [return: System.Runtime.CompilerServices.Nullable(new byte[] { 1, 0 })] public static IAsyncEnumerable<ReadOnlyMemory<byte>> DecodeFromUtf8Async([System.Runtime.CompilerServices.Nullable(new byte[] { 1, 0 })] IAsyncEnumerable<ReadOnlyMemory<byte>> utf8Chars, MemoryAllocator<byte> allocator = null, [EnumeratorCancellation] CancellationToken token = default(CancellationToken)) { <DecodeFromUtf8Async>d__33 <DecodeFromUtf8Async>d__ = new <DecodeFromUtf8Async>d__33(-2); <DecodeFromUtf8Async>d__.<>3__utf8Chars = utf8Chars; <DecodeFromUtf8Async>d__.<>3__allocator = allocator; <DecodeFromUtf8Async>d__.<>3__token = token; return <DecodeFromUtf8Async>d__; } } }