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__;
}
}
}