This commit is contained in:
CroakFang
2022-12-13 22:47:31 +08:00
parent 9e7b10c1a5
commit df178687ba
40 changed files with 5401 additions and 15 deletions
+170
View File
@@ -0,0 +1,170 @@
using System;
using System.Text;
namespace BaseNcoding
{
public class Base64 : Base
{
public const string DefaultAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
public const char DefaultSpecial = '=';
public override bool HasSpecial => true;
public Base64(string alphabet = DefaultAlphabet, char special = DefaultSpecial,
Encoding textEncoding = null, bool parallel = false)
: base(64, alphabet, special, textEncoding, parallel)
{
}
public override string Encode(byte[] data)
{
int resultLength = (data.Length + 2) / 3 * 4;
char[] result = new char[resultLength];
int length3 = data.Length / 3;
if (!Parallel)
{
EncodeBlock(data, result, 0, length3);
}
else
{
int processorCount = Math.Min(length3, Environment.ProcessorCount);
System.Threading.Tasks.Parallel.For(0, processorCount, i =>
{
int beginInd = i * length3 / processorCount;
int endInd = (i + 1) * length3 / processorCount;
EncodeBlock(data, result, beginInd, endInd);
});
}
int ind;
int x1, x2;
int srcInd, dstInd;
switch (data.Length - length3 * 3)
{
case 1:
ind = length3;
srcInd = ind * 3;
dstInd = ind * 4;
x1 = data[srcInd];
result[dstInd] = Alphabet[x1 >> 2];
result[dstInd + 1] = Alphabet[(x1 << 4) & 0x30];
result[dstInd + 2] = Special;
result[dstInd + 3] = Special;
break;
case 2:
ind = length3;
srcInd = ind * 3;
dstInd = ind * 4;
x1 = data[srcInd];
x2 = data[srcInd + 1];
result[dstInd] = Alphabet[x1 >> 2];
result[dstInd + 1] = Alphabet[((x1 << 4) & 0x30) | (x2 >> 4)];
result[dstInd + 2] = Alphabet[(x2 << 2) & 0x3C];
result[dstInd + 3] = Special;
break;
}
return new string(result);
}
public override byte[] Decode(string data)
{
unchecked
{
if (string.IsNullOrEmpty(data))
return new byte[0];
int lastSpecialInd = data.Length;
while (data[lastSpecialInd - 1] == Special)
lastSpecialInd--;
int tailLength = data.Length - lastSpecialInd;
int resultLength = (data.Length + 3) / 4 * 3 - tailLength;
byte[] result = new byte[resultLength];
int length4 = (data.Length - tailLength) / 4;
if (!Parallel)
{
DecodeBlock(data, result, 0, length4);
}
else
{
int processorCount = Math.Min(length4, Environment.ProcessorCount);
System.Threading.Tasks.Parallel.For(0, processorCount, i =>
{
int beginInd = i * length4 / processorCount;
int endInd = (i + 1) * length4 / processorCount;
DecodeBlock(data, result, beginInd, endInd);
});
}
int ind;
int x1, x2, x3;
int srcInd, dstInd;
switch (tailLength)
{
case 2:
ind = length4;
srcInd = ind * 4;
dstInd = ind * 3;
x1 = InvAlphabet[data[srcInd]];
x2 = InvAlphabet[data[srcInd + 1]];
result[dstInd] = (byte)((x1 << 2) | ((x2 >> 4) & 0x3));
break;
case 1:
ind = length4;
srcInd = ind * 4;
dstInd = ind * 3;
x1 = InvAlphabet[data[srcInd]];
x2 = InvAlphabet[data[srcInd + 1]];
x3 = InvAlphabet[data[srcInd + 2]];
result[dstInd] = (byte)((x1 << 2) | ((x2 >> 4) & 0x3));
result[dstInd + 1] = (byte)((x2 << 4) | ((x3 >> 2) & 0xF));
break;
}
return result;
}
}
private void EncodeBlock(byte[] src, char[] dst, int beginInd, int endInd)
{
for (int ind = beginInd; ind < endInd; ind++)
{
int srcInd = ind * 3;
int dstInd = ind * 4;
byte x1 = src[srcInd];
byte x2 = src[srcInd + 1];
byte x3 = src[srcInd + 2];
dst[dstInd] = Alphabet[x1 >> 2];
dst[dstInd + 1] = Alphabet[((x1 << 4) & 0x30) | (x2 >> 4)];
dst[dstInd + 2] = Alphabet[((x2 << 2) & 0x3C) | (x3 >> 6)];
dst[dstInd + 3] = Alphabet[x3 & 0x3F];
}
}
private void DecodeBlock(string src, byte[] dst, int beginInd, int endInd)
{
unchecked
{
for (int ind = beginInd; ind < endInd; ind++)
{
int srcInd = ind * 4;
int dstInd = ind * 3;
int x1 = InvAlphabet[src[srcInd]];
int x2 = InvAlphabet[src[srcInd + 1]];
int x3 = InvAlphabet[src[srcInd + 2]];
int x4 = InvAlphabet[src[srcInd + 3]];
dst[dstInd] = (byte)((x1 << 2) | ((x2 >> 4) & 0x3));
dst[dstInd + 1] = (byte)((x2 << 4) | ((x3 >> 2) & 0xF));
dst[dstInd + 2] = (byte)((x3 << 6) | (x4 & 0x3F));
}
}
}
}
}