DotNext by .NET Foundation and Contributors

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

 Base64Decoder

public struct Base64Decoder : IResettable
Represents base64 decoder suitable for decoding large base64-encoded binary data using streaming approach.
using DotNext.Runtime; using System; using System.Buffers; using System.Buffers.Text; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading; namespace DotNext.Buffers.Text { [StructLayout(LayoutKind.Auto)] [DebuggerDisplay("NeedMoreData = {NeedMoreData}")] public struct Base64Decoder : IResettable { private const int MaxBufferedChars = 3; private const int GotPaddingFlag = -1; private ulong reservedBuffer; private int reservedBufferSize; private const char PaddingChar = '='; private const byte PaddingByte = 61; public bool NeedMoreData { [IsReadOnly] get { return reservedBufferSize > 0; } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] private Span<char> CharBuffer { get { return MemoryMarshal.CreateSpan(ref Unsafe.As<ulong, char>(ref reservedBuffer), 4); } } private ReadOnlySpan<char> BufferedChars { [IsReadOnly] get { return MemoryMarshal.CreateReadOnlySpan(ref Intrinsics.InToRef<ulong, char>(ref reservedBuffer), reservedBufferSize); } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] [UnscopedRef] private Span<byte> ByteBuffer { get { return Span.AsBytes(ref reservedBuffer); } } private ReadOnlySpan<byte> BufferedBytes { [IsReadOnly] get { return MemoryMarshal.CreateReadOnlySpan(ref Intrinsics.InToRef<ulong, byte>(ref reservedBuffer), reservedBufferSize); } } public void Reset() { reservedBufferSize = 0; } [IsReadOnly] private int GetMaxDecodedLength(int length) { return Base64.GetMaxDecodedFromUtf8Length(length) + reservedBufferSize; } private bool DecodeFromUtf16Core([ScopedRef] ReadOnlySpan<char> chars, ref BufferWriterSlim<byte> writer) { int bytesWritten = chars.Length & 3; if (bytesWritten != 0) { bytesWritten = chars.Length - bytesWritten; ReadOnlySpan<char> readOnlySpan = chars.Slice(bytesWritten); readOnlySpan.CopyTo(CharBuffer); reservedBufferSize = readOnlySpan.Length; chars = chars.Slice(0, bytesWritten); } else { int length = chars.Length; if (length >= 1 && chars[length - 1] == '=') reservedBufferSize = -1; else reservedBufferSize = 0; } bool num = Convert.TryFromBase64Chars(chars, writer.InternalGetSpan(chars.Length), out bytesWritten); if (num) writer.Advance(bytesWritten); return num; } private unsafe bool DecodeFromUtf16Buffered([ScopedRef] ReadOnlySpan<char> chars, ref BufferWriterSlim<byte> bytes) { if (NeedMoreData) { Span<char> span = new Span<char>(stackalloc byte[8], 4); SpanWriter<char> spanWriter = new SpanWriter<char>(span); spanWriter.Write(BufferedChars); chars = chars.Slice(spanWriter.Write(chars)); if (!DecodeFromUtf16Core(chars, ref bytes)) return false; } if (!chars.IsEmpty) return DecodeFromUtf16Core(chars, ref bytes); return true; } public void DecodeFromUtf16([ScopedRef] ReadOnlySpan<char> chars, [Nullable(1)] IBufferWriter<byte> bytes) { ArgumentNullException.ThrowIfNull((object)bytes, "bytes"); if (reservedBufferSize != -1) { int maxDecodedLength = GetMaxDecodedLength(chars.Length); BufferWriterSlim<byte> bytes2 = new BufferWriterSlim<byte>(bytes.GetSpan(maxDecodedLength), null); if (DecodeFromUtf16Buffered(chars, ref bytes2)) { bytes.Advance(bytes2.WrittenCount); return; } } throw new FormatException(ExceptionMessages.MalformedBase64); } public MemoryOwner<byte> DecodeFromUtf16([ScopedRef] ReadOnlySpan<char> chars, [Nullable(2)] MemoryAllocator<byte> allocator = null) { if (reservedBufferSize != -1) { BufferWriterSlim<byte> bytes = new BufferWriterSlim<byte>(GetMaxDecodedLength(chars.Length), allocator); if (DecodeFromUtf16Buffered(chars, ref bytes)) return bytes.DetachOrCopyBuffer(); bytes.Dispose(); } throw new FormatException(ExceptionMessages.MalformedBase64); } public void DecodeFromUtf16(ReadOnlySpan<char> chars, ref BufferWriterSlim<byte> bytes) { if (reservedBufferSize == -1 || !DecodeFromUtf16Buffered(chars, ref bytes)) throw new FormatException(ExceptionMessages.MalformedBase64); } [NullableContext(2)] [AsyncIteratorStateMachine(typeof(<DecodeFromUtf16Async>d__22))] [return: Nullable(new byte[] { 1, 0 })] public static IAsyncEnumerable<ReadOnlyMemory<byte>> DecodeFromUtf16Async([Nullable(new byte[] { 1, 0 })] IAsyncEnumerable<ReadOnlyMemory<char>> chars, MemoryAllocator<byte> allocator = null, [EnumeratorCancellation] CancellationToken token = default(CancellationToken)) { <DecodeFromUtf16Async>d__22 <DecodeFromUtf16Async>d__ = new <DecodeFromUtf16Async>d__22(-2); <DecodeFromUtf16Async>d__.<>3__chars = chars; <DecodeFromUtf16Async>d__.<>3__allocator = allocator; <DecodeFromUtf16Async>d__.<>3__token = token; return <DecodeFromUtf16Async>d__; } private bool DecodeFromUtf8Core([ScopedRef] ReadOnlySpan<byte> chars, ref BufferWriterSlim<byte> bytes) { int maxDecodedFromUtf8Length = Base64.GetMaxDecodedFromUtf8Length(chars.Length); Span<byte> span = bytes.InternalGetSpan(maxDecodedFromUtf8Length); int num = default(int); switch (Base64.DecodeFromUtf8(chars, span, ref num, ref maxDecodedFromUtf8Length, (chars.Length & 3) == 0)) { default: return false; case OperationStatus.Done: { int length = chars.Length; reservedBufferSize = ((length >= 1 && chars[length - 1] == 61) ? (-1) : 0); break; } case OperationStatus.DestinationTooSmall: reservedBufferSize = 0; break; case OperationStatus.NeedMoreData: reservedBufferSize = chars.Length - num; chars.Slice(num).CopyTo(ByteBuffer); break; } bytes.Advance(maxDecodedFromUtf8Length); return true; } private unsafe bool DecodeFromUtf8Buffered([ScopedRef] ReadOnlySpan<byte> chars, ref BufferWriterSlim<byte> bytes) { if (NeedMoreData) { Span<byte> span = new Span<byte>(stackalloc byte[4], 4); SpanWriter<byte> spanWriter = new SpanWriter<byte>(span); spanWriter.Write(BufferedBytes); chars = chars.Slice(spanWriter.Write(chars)); if (!DecodeFromUtf8Core(chars, ref bytes)) return false; } if (!chars.IsEmpty) return DecodeFromUtf8Core(chars, ref bytes); return true; } public void DecodeFromUtf8(ReadOnlySpan<byte> chars, [Nullable(1)] IBufferWriter<byte> bytes) { ArgumentNullException.ThrowIfNull((object)bytes, "bytes"); if (reservedBufferSize != -1) { int maxDecodedLength = GetMaxDecodedLength(chars.Length); BufferWriterSlim<byte> bytes2 = new BufferWriterSlim<byte>(bytes.GetSpan(maxDecodedLength), null); if (DecodeFromUtf8Buffered(chars, ref bytes2)) { bytes.Advance(bytes2.WrittenCount); return; } } throw new FormatException(ExceptionMessages.MalformedBase64); } public MemoryOwner<byte> DecodeFromUtf8(ReadOnlySpan<byte> chars, [Nullable(2)] MemoryAllocator<byte> allocator = null) { if (reservedBufferSize != -1) { BufferWriterSlim<byte> bytes = new BufferWriterSlim<byte>(GetMaxDecodedLength(chars.Length), allocator); if (DecodeFromUtf8Buffered(chars, ref bytes)) return bytes.DetachOrCopyBuffer(); bytes.Dispose(); } throw new FormatException(ExceptionMessages.MalformedBase64); } public void DecodeFromUtf8(ReadOnlySpan<byte> chars, ref BufferWriterSlim<byte> bytes) { if (reservedBufferSize == -1 || !DecodeFromUtf8Buffered(chars, ref bytes)) throw new FormatException(ExceptionMessages.MalformedBase64); } [NullableContext(2)] [AsyncIteratorStateMachine(typeof(<DecodeFromUtf8Async>d__29))] [return: Nullable(new byte[] { 1, 0 })] public static IAsyncEnumerable<ReadOnlyMemory<byte>> DecodeFromUtf8Async([Nullable(new byte[] { 1, 0 })] IAsyncEnumerable<ReadOnlyMemory<byte>> utf8Chars, MemoryAllocator<byte> allocator = null, [EnumeratorCancellation] CancellationToken token = default(CancellationToken)) { <DecodeFromUtf8Async>d__29 <DecodeFromUtf8Async>d__ = new <DecodeFromUtf8Async>d__29(-2); <DecodeFromUtf8Async>d__.<>3__utf8Chars = utf8Chars; <DecodeFromUtf8Async>d__.<>3__allocator = allocator; <DecodeFromUtf8Async>d__.<>3__token = token; return <DecodeFromUtf8Async>d__; } } }