Base64Encoder
using System;
using System.IO;
namespace Org.BouncyCastle.Utilities.Encoders
{
public class Base64Encoder : IEncoder
{
protected readonly byte[] encodingTable = new byte[64] {
65,
66,
67,
68,
69,
70,
71,
72,
73,
74,
75,
76,
77,
78,
79,
80,
81,
82,
83,
84,
85,
86,
87,
88,
89,
90,
97,
98,
99,
100,
101,
102,
103,
104,
105,
106,
107,
108,
109,
110,
111,
112,
113,
114,
115,
116,
117,
118,
119,
120,
121,
122,
48,
49,
50,
51,
52,
53,
54,
55,
56,
57,
43,
47
};
protected byte padding = 61;
protected readonly byte[] decodingTable = new byte[128];
protected void InitialiseDecodingTable()
{
Arrays.Fill(decodingTable, byte.MaxValue);
for (int i = 0; i < encodingTable.Length; i++) {
decodingTable[encodingTable[i]] = (byte)i;
}
}
public Base64Encoder()
{
InitialiseDecodingTable();
}
public int Encode(byte[] inBuf, int inOff, int inLen, byte[] outBuf, int outOff)
{
return Encode(inBuf.AsSpan(inOff, inLen), outBuf.AsSpan(outOff));
}
public int Encode(ReadOnlySpan<byte> input, Span<byte> output)
{
int num = 0;
int num2 = input.Length - 2;
int num3 = 0;
while (num < num2) {
uint num5 = input[num++];
uint num7 = input[num++];
uint num9 = input[num++];
output[num3++] = encodingTable[(num5 >> 2) & 63];
output[num3++] = encodingTable[((num5 << 4) | (num7 >> 4)) & 63];
output[num3++] = encodingTable[((num7 << 2) | (num9 >> 6)) & 63];
output[num3++] = encodingTable[num9 & 63];
}
switch (input.Length - num) {
case 1: {
uint num23 = input[num++];
output[num3++] = encodingTable[(num23 >> 2) & 63];
output[num3++] = encodingTable[(num23 << 4) & 63];
output[num3++] = padding;
output[num3++] = padding;
break;
}
case 2: {
uint num15 = input[num++];
uint num17 = input[num++];
output[num3++] = encodingTable[(num15 >> 2) & 63];
output[num3++] = encodingTable[((num15 << 4) | (num17 >> 4)) & 63];
output[num3++] = encodingTable[(num17 << 2) & 63];
output[num3++] = padding;
break;
}
}
return num3;
}
public int Encode(byte[] buf, int off, int len, Stream outStream)
{
return Encode(buf.AsSpan(off, len), outStream);
}
public unsafe int Encode(ReadOnlySpan<byte> data, Stream outStream)
{
Span<byte> output = new Span<byte>(stackalloc byte[72], 72);
int result = (data.Length + 2) / 3 * 4;
while (!data.IsEmpty) {
int num = System.Math.Min(54, data.Length);
int length = Encode(data.Slice(0, num), output);
outStream.Write(output.Slice(0, length));
int num2 = num;
data = data.Slice(num2, data.Length - num2);
}
return result;
}
private bool Ignore(char c)
{
if (c != '\n' && c != '\r' && c != '\t')
return c == ' ';
return true;
}
public int Decode(byte[] data, int off, int length, Stream outStream)
{
return Decode(data.AsSpan(off, length), outStream);
}
public unsafe int Decode(ReadOnlySpan<byte> data, Stream outStream)
{
Span<byte> span = new Span<byte>(stackalloc byte[54], 54);
int num = 0;
int num2 = 0;
int num3 = data.Length;
while (num3 > 0 && Ignore((char)data[num3 - 1])) {
num3--;
}
int num4 = num3 - 4;
int num5;
for (num5 = NextI(data, 0, num4); num5 < num4; num5 = NextI(data, num5, num4)) {
byte b = decodingTable[data[num5++]];
num5 = NextI(data, num5, num4);
byte b2 = decodingTable[data[num5++]];
num5 = NextI(data, num5, num4);
byte b3 = decodingTable[data[num5++]];
num5 = NextI(data, num5, num4);
byte b4 = decodingTable[data[num5++]];
if ((b | b2 | b3 | b4) >= 128)
throw new IOException("invalid characters encountered in base64 data");
span[num++] = (byte)((b << 2) | (b2 >> 4));
span[num++] = (byte)((b2 << 4) | (b3 >> 2));
span[num++] = (byte)((b3 << 6) | b4);
if (num == span.Length) {
outStream.Write(span);
num = 0;
}
num2 += 3;
}
if (num > 0)
outStream.Write(span.Slice(0, num));
int num13 = NextI(data, num5, num3);
int num14 = NextI(data, num13 + 1, num3);
int num15 = NextI(data, num14 + 1, num3);
int index = NextI(data, num15 + 1, num3);
return num2 + DecodeLastBlock(outStream, (char)data[num13], (char)data[num14], (char)data[num15], (char)data[index]);
}
private int NextI(ReadOnlySpan<byte> data, int i, int finish)
{
while (i < finish && Ignore((char)data[i])) {
i++;
}
return i;
}
public unsafe int DecodeString(string data, Stream outStream)
{
int num = 0;
int num2 = data.Length;
while (num2 > 0 && Ignore(data[num2 - 1])) {
num2--;
}
int num3 = num2 - 4;
int num4 = NextI(data, 0, num3);
Span<byte> span = new Span<byte>(stackalloc byte[3], 3);
while (num4 < num3) {
byte b = decodingTable[data[num4++]];
num4 = NextI(data, num4, num3);
byte b2 = decodingTable[data[num4++]];
num4 = NextI(data, num4, num3);
byte b3 = decodingTable[data[num4++]];
num4 = NextI(data, num4, num3);
byte b4 = decodingTable[data[num4++]];
if ((b | b2 | b3 | b4) >= 128)
throw new IOException("invalid characters encountered in base64 data");
span[0] = (byte)((b << 2) | (b2 >> 4));
span[1] = (byte)((b2 << 4) | (b3 >> 2));
span[2] = (byte)((b3 << 6) | b4);
outStream.Write(span);
num += 3;
num4 = NextI(data, num4, num3);
}
return num + DecodeLastBlock(outStream, data[num2 - 4], data[num2 - 3], data[num2 - 2], data[num2 - 1]);
}
private unsafe int DecodeLastBlock(Stream outStream, char c1, char c2, char c3, char c4)
{
if (c3 == padding) {
if (c4 != padding)
throw new IOException("invalid characters encountered at end of base64 data");
byte b = decodingTable[c1];
byte b2 = decodingTable[c2];
if ((b | b2) >= 128)
throw new IOException("invalid characters encountered at end of base64 data");
outStream.WriteByte((byte)((b << 2) | (b2 >> 4)));
return 1;
}
if (c4 == padding) {
byte b3 = decodingTable[c1];
byte b4 = decodingTable[c2];
byte b5 = decodingTable[c3];
if ((b3 | b4 | b5) >= 128)
throw new IOException("invalid characters encountered at end of base64 data");
byte* intPtr = stackalloc byte[2];
*intPtr = (byte)((b3 << 2) | (b4 >> 4));
intPtr[1] = (byte)((b4 << 4) | (b5 >> 2));
Span<byte> span = new Span<byte>(intPtr, 2);
outStream.Write(span);
return 2;
}
byte b6 = decodingTable[c1];
byte b7 = decodingTable[c2];
byte b8 = decodingTable[c3];
byte b9 = decodingTable[c4];
if ((b6 | b7 | b8 | b9) >= 128)
throw new IOException("invalid characters encountered at end of base64 data");
byte* intPtr2 = stackalloc byte[3];
*intPtr2 = (byte)((b6 << 2) | (b7 >> 4));
intPtr2[1] = (byte)((b7 << 4) | (b8 >> 2));
intPtr2[2] = (byte)((b8 << 6) | b9);
Span<byte> span2 = new Span<byte>(intPtr2, 3);
outStream.Write(span2);
return 3;
}
private int NextI(string data, int i, int finish)
{
while (i < finish && Ignore(data[i])) {
i++;
}
return i;
}
}
}