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
+184
View File
@@ -0,0 +1,184 @@
using System;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace BaseNcoding
{
public abstract class Base
{
public uint CharsCount { get; }
public double BitsPerChars => (double)BlockBitsCount / BlockCharsCount;
public int BlockBitsCount { get; protected set; }
public int BlockCharsCount { get; protected set; }
public string Alphabet { get; }
public char Special { get; }
public abstract bool HasSpecial { get; }
public Encoding Encoding { get; set; }
public bool Parallel { get; set; }
protected readonly int[] InvAlphabet;
public Base(uint charsCount, string alphabet, char special, Encoding encoding = null, bool parallel = false)
{
if (alphabet.Length != charsCount)
throw new ArgumentException($"Base string should contain {charsCount} chars");
for (int i = 0; i < charsCount; i++)
for (int j = i + 1; j < charsCount; j++)
if (alphabet[i] == alphabet[j])
throw new ArgumentException("Base string should contain distinct chars");
if (alphabet.Contains(special))
throw new ArgumentException("Base string should not contain special char");
CharsCount = charsCount;
Alphabet = alphabet;
Special = special;
int bitsPerChar = LogBase2(charsCount);
BlockBitsCount = Lcm(bitsPerChar, 8);
BlockCharsCount = BlockBitsCount / bitsPerChar;
InvAlphabet = new int[Alphabet.Max() + 1];
for (int i = 0; i < InvAlphabet.Length; i++)
InvAlphabet[i] = -1;
for (int i = 0; i < charsCount; i++)
InvAlphabet[Alphabet[i]] = i;
Encoding = encoding ?? Encoding.UTF8;
Parallel = parallel;
}
public virtual string EncodeString(string data)
{
return Encode(Encoding.GetBytes(data));
}
public abstract string Encode(byte[] data);
public string DecodeToString(string data)
{
return Encoding.GetString(Decode(Regex.Replace(data, @"\r\n?|\n", "")));
}
public abstract byte[] Decode(string data);
/// <summary>
/// From: http://stackoverflow.com/a/600306/1046374
/// </summary>
/// <param name="x"></param>
/// <returns></returns>
public static bool IsPowerOf2(uint x)
{
uint xint = x;
if (x - xint != 0)
return false;
return (xint & (xint - 1)) == 0;
}
/// <summary>
/// From: http://stackoverflow.com/a/13569863/1046374
/// </summary>
public static int Lcm(int a, int b)
{
int num1, num2;
if (a > b)
{
num1 = a;
num2 = b;
}
else
{
num1 = b;
num2 = a;
}
for (int i = 1; i <= num2; i++)
{
int mult = num1 * i;
if (mult % num2 == 0)
return mult;
}
return num2;
}
private static int LogBase2(uint x)
{
int r = 0;
while ((x >>= 1) != 0)
r++;
return r;
}
private static int LogBaseN(uint x, uint n)
{
int r = 0;
while ((x /= n) != 0)
r++;
return r;
}
public static int GetOptimalBitsCount2(uint charsCount, out uint charsCountInBits,
uint maxBitsCount = 64, bool base2BitsCount = false)
{
int result = 0;
charsCountInBits = 0;
int n1 = LogBase2(charsCount);
double charsCountLog = Math.Log(2, charsCount);
double maxRatio = 0;
for (int n = n1; n <= maxBitsCount; n++)
{
if (base2BitsCount && n % 8 != 0)
continue;
uint l1 = (uint)Math.Ceiling(n * charsCountLog);
double ratio = (double)n / l1;
if (ratio > maxRatio)
{
maxRatio = ratio;
result = n;
charsCountInBits = l1;
}
}
return result;
}
protected static int GetOptimalBitsCount(uint charsCount, out uint charsCountInBits,
uint maxBitsCount = 64, uint radix = 2)
{
int result = 0;
charsCountInBits = 0;
int n0 = LogBaseN(charsCount, radix);
double charsCountLog = Math.Log(radix, charsCount);
double maxRatio = 0;
for (int n = n0; n <= maxBitsCount; n++)
{
uint k = (uint)Math.Ceiling(n * charsCountLog);
double ratio = (double)n / k;
if (ratio > maxRatio)
{
maxRatio = ratio;
result = n;
charsCountInBits = k;
}
}
return result;
}
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: dddac6b0e9d7d75489cf3110fcc3a611
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+41
View File
@@ -0,0 +1,41 @@
using System.Text;
namespace BaseNcoding
{
public class Base256 : Base
{
public const string DefaultAlphabet = "!#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁł";
public const char DefaultSpecial = (char)0;
public override bool HasSpecial => false;
public Base256(string alphabet = DefaultAlphabet, char special = DefaultSpecial,
Encoding textEncoding = null)
: base(256, alphabet, special, textEncoding)
{
}
public override string Encode(byte[] data)
{
var result = new char[data.Length];
for (int i = 0; i < data.Length; i++)
result[i] = Alphabet[data[i]];
return new string(result);
}
public override byte[] Decode(string data)
{
unchecked
{
byte[] result = new byte[data.Length];
for (int i = 0; i < data.Length; i++)
result[i] = (byte)InvAlphabet[data[i]];
return result;
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b84ecd8bc32acb7448d64c9bb045948d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+203
View File
@@ -0,0 +1,203 @@
using System.Text;
namespace BaseNcoding
{
public class Base32 : Base
{
public const string DefaultAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
public const char DefaultSpecial = '>';
public override bool HasSpecial => true;
public Base32(string alphabet = DefaultAlphabet, char special = DefaultSpecial, Encoding textEncoding = null)
: base(32, alphabet, special, textEncoding)
{
}
public override string Encode(byte[] data)
{
int dataLength = data.Length;
StringBuilder result = new StringBuilder((dataLength + 4) / 5 * 8);
byte x1, x2;
int i;
int length5 = (dataLength / 5) * 5;
for (i = 0; i < length5; i += 5)
{
x1 = data[i];
result.Append(Alphabet[x1 >> 3]);
x2 = data[i + 1];
result.Append(Alphabet[((x1 << 2) & 0x1C) | (x2 >> 6)]);
result.Append(Alphabet[(x2 >> 1) & 0x1F]);
x1 = data[i + 2];
result.Append(Alphabet[((x2 << 4) & 0x10) | (x1 >> 4)]);
x2 = data[i + 3];
result.Append(Alphabet[((x1 << 1) & 0x1E) | (x2 >> 7)]);
result.Append(Alphabet[(x2 >> 2) & 0x1F]);
x1 = data[i + 4];
result.Append(Alphabet[((x2 << 3) & 0x18) | (x1 >> 5)]);
result.Append(Alphabet[x1 & 0x1F]);
}
switch (dataLength - length5)
{
case 1:
x1 = data[i];
result.Append(Alphabet[x1 >> 3]);
result.Append(Alphabet[(x1 << 2) & 0x1C]);
result.Append(Special, 6);
break;
case 2:
x1 = data[i];
result.Append(Alphabet[x1 >> 3]);
x2 = data[i + 1];
result.Append(Alphabet[((x1 << 2) & 0x1C) | (x2 >> 6)]);
result.Append(Alphabet[(x2 >> 1) & 0x1F]);
result.Append(Alphabet[(x2 << 4) & 0x10]);
result.Append(Special, 4);
break;
case 3:
x1 = data[i];
result.Append(Alphabet[x1 >> 3]);
x2 = data[i + 1];
result.Append(Alphabet[((x1 << 2) & 0x1C) | (x2 >> 6)]);
result.Append(Alphabet[(x2 >> 1) & 0x1F]);
x1 = data[i + 2];
result.Append(Alphabet[((x2 << 4) & 0x10) | (x1 >> 4)]);
result.Append(Alphabet[(x1 << 1) & 0x1E]);
result.Append(Special, 3);
break;
case 4:
x1 = data[i];
result.Append(Alphabet[x1 >> 3]);
x2 = data[i + 1];
result.Append(Alphabet[((x1 << 2) & 0x1C) | (x2 >> 6)]);
result.Append(Alphabet[(x2 >> 1) & 0x1F]);
x1 = data[i + 2];
result.Append(Alphabet[((x2 << 4) & 0x10) | (x1 >> 4)]);
x2 = data[i + 3];
result.Append(Alphabet[((x1 << 1) & 0x1E) | (x2 >> 7)]);
result.Append(Alphabet[(x2 >> 2) & 0x1F]);
result.Append(Alphabet[(x2 << 3) & 0x18]);
result.Append(Special);
break;
}
return result.ToString();
}
public override byte[] Decode(string data)
{
unchecked
{
if (string.IsNullOrEmpty(data))
return new byte[0];
int additionalBytes = 0, diff = 0, tempLen = 0;
int lastSpecialInd = data.Length;
while (data[lastSpecialInd - 1] == Special)
lastSpecialInd--;
int tailLength = data.Length - lastSpecialInd;
switch (tailLength)
{
case 6:
additionalBytes = 4;
break;
case 4:
additionalBytes = 3;
break;
case 3:
additionalBytes = 2;
break;
case 1:
additionalBytes = 1;
break;
}
diff = tailLength - additionalBytes;
tailLength = additionalBytes;
tempLen = data.Length - diff;
byte[] result = new byte[(tempLen + 7) / 8 * 5 - tailLength];
int length5 = result.Length / 5 * 5;
int x1, x2, x3, x4, x5, x6, x7, x8;
int i, srcInd = 0;
for (i = 0; i < length5; i += 5)
{
x1 = InvAlphabet[data[srcInd++]];
x2 = InvAlphabet[data[srcInd++]];
x3 = InvAlphabet[data[srcInd++]];
x4 = InvAlphabet[data[srcInd++]];
x5 = InvAlphabet[data[srcInd++]];
x6 = InvAlphabet[data[srcInd++]];
x7 = InvAlphabet[data[srcInd++]];
x8 = InvAlphabet[data[srcInd++]];
result[i] = (byte)((x1 << 3) | ((x2 >> 2) & 0x07));
result[i + 1] = (byte)((x2 << 6) | ((x3 << 1) & 0x3E) | ((x4 >> 4) & 0x01));
result[i + 2] = (byte)((x4 << 4) | ((x5 >> 1) & 0xF));
result[i + 3] = (byte)((x5 << 7) | ((x6 << 2) & 0x7C) | ((x7 >> 3) & 0x03));
result[i + 4] = (byte)((x7 << 5) | (x8 & 0x1F));
}
switch (tailLength)
{
case 4:
x1 = InvAlphabet[data[srcInd++]];
x2 = InvAlphabet[data[srcInd++]];
result[i] = (byte)((x1 << 3) | ((x2 >> 2) & 0x07));
break;
case 3:
x1 = InvAlphabet[data[srcInd++]];
x2 = InvAlphabet[data[srcInd++]];
x3 = InvAlphabet[data[srcInd++]];
x4 = InvAlphabet[data[srcInd++]];
result[i] = (byte)((x1 << 3) | ((x2 >> 2) & 0x07));
result[i + 1] = (byte)((x2 << 6) | ((x3 << 1) & 0x3E) | ((x4 >> 4) & 0x01));
break;
case 2:
x1 = InvAlphabet[data[srcInd++]];
x2 = InvAlphabet[data[srcInd++]];
x3 = InvAlphabet[data[srcInd++]];
x4 = InvAlphabet[data[srcInd++]];
x5 = InvAlphabet[data[srcInd++]];
result[i] = (byte)((x1 << 3) | ((x2 >> 2) & 0x07));
result[i + 1] = (byte)((x2 << 6) | ((x3 << 1) & 0x3E) | ((x4 >> 4) & 0x01));
result[i + 2] = (byte)((x4 << 4) | ((x5 >> 1) & 0xF));
break;
case 1:
x1 = InvAlphabet[data[srcInd++]];
x2 = InvAlphabet[data[srcInd++]];
x3 = InvAlphabet[data[srcInd++]];
x4 = InvAlphabet[data[srcInd++]];
x5 = InvAlphabet[data[srcInd++]];
x6 = InvAlphabet[data[srcInd++]];
x7 = InvAlphabet[data[srcInd++]];
result[i] = (byte)((x1 << 3) | ((x2 >> 2) & 0x07));
result[i + 1] = (byte)((x2 << 6) | ((x3 << 1) & 0x3E) | ((x4 >> 4) & 0x01));
result[i + 2] = (byte)((x4 << 4) | ((x5 >> 1) & 0xF));
result[i + 3] = (byte)((x5 << 7) | ((x6 << 2) & 0x7C) | ((x7 >> 3) & 0x03));
break;
}
return result;
}
}
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 126c83fbe81b32444ade8272d29789b1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+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));
}
}
}
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b591d6746a6fd9b45a0174c0c22d292b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+181
View File
@@ -0,0 +1,181 @@
using System;
using System.IO;
using System.Text;
namespace BaseNcoding
{
public class Base85 : Base
{
public const string DefaultAlphabet = "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstu";
public const char DefaultSpecial = (char)0;
private static readonly uint[] Pow85 = { 85 * 85 * 85 * 85, 85 * 85 * 85, 85 * 85, 85, 1 };
public const string Prefix = "<~";
public const string Postfix = "~>";
public override bool HasSpecial => false;
public bool PrefixPostfix { get; set; }
public Base85(string alphabet = DefaultAlphabet, char special = DefaultSpecial, bool prefixPostfix = false, Encoding textEncoding = null)
: base(85, alphabet, special, textEncoding)
{
PrefixPostfix = prefixPostfix;
BlockBitsCount = 32;
BlockCharsCount = 5;
}
public override string Encode(byte[] data)
{
unchecked
{
byte[] encodedBlock = new byte[5];
int decodedBlockLength = 4;
int resultLength = data.Length * (encodedBlock.Length / decodedBlockLength);
if (PrefixPostfix)
resultLength += Prefix.Length + Postfix.Length;
char[] result = new char[resultLength];
int resultInd = 0;
if (PrefixPostfix)
CopyString(Prefix, result, ref resultInd);
int count = 0;
uint tuple = 0;
foreach (byte b in data)
{
if (count >= decodedBlockLength - 1)
{
tuple |= b;
if (tuple == 0)
result[resultInd++] = 'z';
else
EncodeBlock(encodedBlock.Length, result, ref resultInd, encodedBlock, tuple);
tuple = 0;
count = 0;
}
else
{
tuple |= (uint)(b << (24 - count * 8));
count++;
}
}
if (count > 0)
EncodeBlock(count + 1, result, ref resultInd, encodedBlock, tuple);
if (PrefixPostfix)
CopyString(Postfix, result, ref resultInd);
return new string(result);
}
}
public override byte[] Decode(string data)
{
unchecked
{
string dataWithoutPrefixPostfix = data;
if (PrefixPostfix)
{
if (!dataWithoutPrefixPostfix.StartsWith(Prefix) || !dataWithoutPrefixPostfix.EndsWith(Postfix))
{
throw new Exception("ASCII85 encoded data should begin with '" + Prefix + "' and end with '" + Postfix + "'");
}
dataWithoutPrefixPostfix = dataWithoutPrefixPostfix.Substring(Prefix.Length, dataWithoutPrefixPostfix.Length - Prefix.Length - Postfix.Length);
}
MemoryStream ms = new MemoryStream();
int count = 0;
uint tuple = 0;
int encodedBlockLength = 5;
byte[] decodedBlock = new byte[4];
foreach (char c in dataWithoutPrefixPostfix)
{
bool processChar;
switch (c)
{
case 'z':
if (count != 0)
{
throw new Exception("The character 'z' is invalid inside an ASCII85 block.");
}
decodedBlock[0] = 0;
decodedBlock[1] = 0;
decodedBlock[2] = 0;
decodedBlock[3] = 0;
ms.Write(decodedBlock, 0, decodedBlock.Length);
processChar = false;
break;
default:
processChar = true;
break;
}
if (processChar)
{
tuple += (uint)InvAlphabet[c] * Pow85[count];
count++;
if (count == encodedBlockLength)
{
DecodeBlock(decodedBlock.Length, decodedBlock, tuple);
ms.Write(decodedBlock, 0, decodedBlock.Length);
tuple = 0;
count = 0;
}
}
}
if (count != 0)
{
if (count == 1)
{
throw new Exception("The last block of ASCII85 data cannot be a single byte.");
}
count--;
tuple += Pow85[count];
DecodeBlock(count, decodedBlock, tuple);
for (int i = 0; i < count; i++)
{
ms.WriteByte(decodedBlock[i]);
}
}
return ms.ToArray();
}
}
private static void CopyString(string source, char[] dest, ref int destInd)
{
for (int i = 0; i < source.Length; i++)
dest[destInd++] = source[i];
}
private void EncodeBlock(int count, char[] result, ref int resultInd, byte[] encodedBlock, uint tuple)
{
unchecked
{
for (int i = encodedBlock.Length - 1; i >= 0; i--)
{
uint quotient = tuple % 85;
uint remainder = tuple - quotient * 85;
tuple = quotient;
encodedBlock[i] = (byte)remainder;
}
for (int i = 0; i < count; i++)
result[resultInd++] = Alphabet[encodedBlock[i]];
}
}
private void DecodeBlock(int bytes, byte[] decodedBlock, uint tuple)
{
unchecked
{
for (int i = 0; i < bytes; i++)
decodedBlock[i] = (byte)(tuple >> 24 - i * 8);
}
}
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bb00dc9d3e90a49439d967614c88ded8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+99
View File
@@ -0,0 +1,99 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace BaseNcoding
{
public class Base91 : Base
{
public const string DefaultAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!#$%&()*+,./:;<=>?@[]^_`{|}~\"";
public const char DefaultSpecial = (char)0;
public override bool HasSpecial => false;
public Base91(string alphabet = DefaultAlphabet, char special = DefaultSpecial, Encoding textEncoding = null)
: base(91, alphabet, special, textEncoding)
{
BlockBitsCount = 13;
BlockCharsCount = 2;
}
public override string Encode(byte[] data)
{
StringBuilder result = new StringBuilder(data.Length);
int ebq = 0, en = 0;
for (int i = 0; i < data.Length; ++i)
{
ebq |= (data[i] & 255) << en;
en += 8;
if (en > 13)
{
int ev = ebq & 8191;
if (ev > 88)
{
ebq >>= 13;
en -= 13;
}
else
{
ev = ebq & 16383;
ebq >>= 14;
en -= 14;
}
int quotient = Math.DivRem(ev, 91, out int remainder);
result.Append(Alphabet[remainder]);
result.Append(Alphabet[quotient]);
}
}
if (en > 0)
{
int quotient = Math.DivRem(ebq, 91, out int remainder);
result.Append(Alphabet[remainder]);
if (en > 7 || ebq > 90)
result.Append(Alphabet[quotient]);
}
return result.ToString();
}
public override byte[] Decode(string data)
{
unchecked
{
int dbq = 0, dn = 0, dv = -1;
List<byte> result = new List<byte>(data.Length);
for (int i = 0; i < data.Length; ++i)
{
if (InvAlphabet[data[i]] == -1)
continue;
if (dv == -1)
dv = InvAlphabet[data[i]];
else
{
dv += InvAlphabet[data[i]] * 91;
dbq |= dv << dn;
dn += (dv & 8191) > 88 ? 13 : 14;
do
{
result.Add((byte)dbq);
dbq >>= 8;
dn -= 8;
}
while (dn > 7);
dv = -1;
}
}
if (dv != -1)
result.Add((byte)(dbq | dv << dn));
return result.ToArray();
}
}
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 445180477b0318d48b58549426fd8ba9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+261
View File
@@ -0,0 +1,261 @@
using System;
using System.Numerics;
using System.Text;
namespace BaseNcoding
{
public class BaseBigN : Base
{
private BigInteger[] _powN;
public bool ReverseOrder { get; }
public uint BlockMaxBitsCount { get; }
public bool MaxCompression { get; }
public override bool HasSpecial => false;
public BaseBigN(string alphabet, uint blockMaxBitsCount = 64,
Encoding encoding = null, bool reverseOrder = false, bool parallel = false,
bool maxCompression = false)
: base((uint)alphabet.Length, alphabet, '\0', encoding, parallel)
{
BlockMaxBitsCount = blockMaxBitsCount;
BlockBitsCount = GetOptimalBitsCount(CharsCount, out var charsCountInBits, BlockMaxBitsCount, 2);
BlockCharsCount = (int)charsCountInBits;
PreparePowN(BlockCharsCount);
ReverseOrder = reverseOrder;
MaxCompression = maxCompression;
}
public override string Encode(byte[] data)
{
if (data == null || data.Length == 0)
return "";
int blockBitsCount, blockCharsCount;
if (!MaxCompression)
{
blockBitsCount = BlockBitsCount;
blockCharsCount = BlockCharsCount;
}
else
{
blockBitsCount = data.Length * 8;
blockCharsCount = (int)Math.Ceiling(blockBitsCount * Math.Log(2, Alphabet.Length));
PreparePowN(blockCharsCount);
}
int data8 = data.Length * 8;
int mainBitsLength = data8 / blockBitsCount * blockBitsCount;
int tailBitsLength = data8 - mainBitsLength;
int mainCharsCount = mainBitsLength * blockCharsCount / blockBitsCount;
int tailCharsCount = (tailBitsLength * blockCharsCount + blockBitsCount - 1) / blockBitsCount;
int totalCharsCount = mainCharsCount + tailCharsCount;
int iterationCount = mainCharsCount / blockCharsCount;
var result = new char[totalCharsCount];
if (!Parallel)
EncodeBlock(data, result, 0, iterationCount, blockBitsCount, blockCharsCount);
else
{
int processorCount = Math.Min(iterationCount, Environment.ProcessorCount);
System.Threading.Tasks.Parallel.For(0, processorCount, i =>
{
int beginInd = i * iterationCount / processorCount;
int endInd = (i + 1) * iterationCount / processorCount;
EncodeBlock(data, result, beginInd, endInd, blockBitsCount, blockCharsCount);
});
}
if (tailBitsLength != 0)
{
BigInteger bits = GetBitsN(data, mainBitsLength, tailBitsLength);
BitsToChars(result, mainCharsCount, tailCharsCount, bits);
}
return new string(result);
}
public override byte[] Decode(string data)
{
if (string.IsNullOrEmpty(data))
return new byte[0];
int blockBitsCount, blockCharsCount;
if (!MaxCompression)
{
blockBitsCount = BlockBitsCount;
blockCharsCount = BlockCharsCount;
}
else
{
blockCharsCount = data.Length;
blockBitsCount = (int)(blockCharsCount / Math.Log(2, Alphabet.Length)) / 8 * 8;
PreparePowN(blockCharsCount);
}
int totalBitsLength = ((data.Length - 1) * blockBitsCount / blockCharsCount + 8) / 8 * 8;
int mainBitsLength = totalBitsLength / blockBitsCount * blockBitsCount;
int tailBitsLength = totalBitsLength - mainBitsLength;
int mainCharsCount = mainBitsLength * blockCharsCount / blockBitsCount;
int tailCharsCount = (tailBitsLength * blockCharsCount + blockBitsCount - 1) / blockBitsCount;
BigInteger tailBits = CharsToBits(data, mainCharsCount, tailCharsCount);
if (tailBits >> tailBitsLength != 0)
{
totalBitsLength += 8;
mainBitsLength = totalBitsLength / blockBitsCount * blockBitsCount;
tailBitsLength = totalBitsLength - mainBitsLength;
mainCharsCount = mainBitsLength * blockCharsCount / blockBitsCount;
tailCharsCount = (tailBitsLength * blockCharsCount + blockBitsCount - 1) / blockBitsCount;
}
int iterationCount = mainCharsCount / blockCharsCount;
byte[] result = new byte[totalBitsLength / 8];
if (!Parallel)
{
DecodeBlock(data, result, 0, iterationCount, blockBitsCount, blockCharsCount);
}
else
{
int processorCount = Math.Min(iterationCount, Environment.ProcessorCount);
System.Threading.Tasks.Parallel.For(0, processorCount, i =>
{
int beginInd = i * iterationCount / processorCount;
int endInd = (i + 1) * iterationCount / processorCount;
DecodeBlock(data, result, beginInd, endInd, blockBitsCount, blockCharsCount);
});
}
if (tailCharsCount != 0)
{
BigInteger bits = CharsToBits(data, mainCharsCount, tailCharsCount);
AddBitsN(result, bits, mainBitsLength, tailBitsLength);
}
return result;
}
private void EncodeBlock(byte[] src, char[] dst, int beginInd, int endInd, int blockBitsCount, int blockCharsCount)
{
for (int ind = beginInd; ind < endInd; ind++)
{
int charInd = ind * blockCharsCount;
int bitInd = ind * blockBitsCount;
BigInteger bits = GetBitsN(src, bitInd, blockBitsCount);
BitsToChars(dst, charInd, blockCharsCount, bits);
}
}
private void DecodeBlock(string src, byte[] dst, int beginInd, int endInd, int blockBitsCount, int blockCharsCount)
{
for (int ind = beginInd; ind < endInd; ind++)
{
int charInd = ind * blockCharsCount;
int bitInd = ind * blockBitsCount;
BigInteger bits = CharsToBits(src, charInd, blockCharsCount);
AddBitsN(dst, bits, bitInd, blockBitsCount);
}
}
private static BigInteger GetBitsN(byte[] data, int bitPos, int bitsCount)
{
BigInteger result = 0;
int currentBytePos = Math.DivRem(bitPos, 8, out int currentBitInBytePos);
int shift = 8 - currentBitInBytePos;
int xLength = Math.Min(bitsCount, shift);
if (xLength != 0)
{
result = new BigInteger((data[currentBytePos] >> shift - xLength) & ((1 << shift) - 1)) << bitsCount - xLength;
currentBytePos += Math.DivRem(currentBitInBytePos + xLength, 8, out currentBitInBytePos);
int x2Length = bitsCount - xLength;
if (x2Length > 8)
x2Length = 8;
while (x2Length > 0)
{
xLength += x2Length;
result |= (BigInteger)(data[currentBytePos] >> 8 - x2Length) << bitsCount - xLength;
currentBytePos += Math.DivRem(currentBitInBytePos + x2Length, 8, out currentBitInBytePos);
x2Length = bitsCount - xLength;
if (x2Length > 8)
x2Length = 8;
}
}
return result;
}
private static void AddBitsN(byte[] data, BigInteger value, int bitPos, int bitsCount)
{
int currentBytePos = Math.DivRem(bitPos, 8, out int currentBitInBytePos);
int shift = 8 - currentBitInBytePos;
int xLength = Math.Min(bitsCount, shift);
if (xLength != 0)
{
data[currentBytePos] |= (byte) ((byte) (value >> bitsCount - shift) & ((1 << shift) - 1));
currentBytePos += Math.DivRem(currentBitInBytePos + xLength, 8, out currentBitInBytePos);
int x2Length = bitsCount - xLength;
if (x2Length > 8)
x2Length = 8;
while (x2Length > 0)
{
xLength += x2Length;
var bitsCountMinusXLength = bitsCount - xLength;
data[currentBytePos] |= (byte)((value >> (bitsCountMinusXLength - 8 + x2Length)) & 0xFF);
currentBytePos += Math.DivRem(currentBitInBytePos + x2Length, 8, out currentBitInBytePos);
x2Length = bitsCountMinusXLength;
if (x2Length > 8)
x2Length = 8;
}
}
}
private void BitsToChars(char[] chars, int ind, int count, BigInteger block)
{
BigInteger quotient = block;
for (int i = 0; i < count; i++)
{
quotient = BigInteger.DivRem(quotient, CharsCount, out BigInteger remainder);
chars[ind + (!ReverseOrder ? i : count - 1 - i)] = Alphabet[(int)remainder];
}
}
private BigInteger CharsToBits(string data, int ind, int count)
{
BigInteger result = 0;
for (int i = 0; i < count; i++)
result += InvAlphabet[data[ind + (!ReverseOrder ? i : count - 1 - i)]] * _powN[_powN.Length - 1 - i];
return result;
}
private void PreparePowN(int blockCharsCount)
{
_powN = new BigInteger[blockCharsCount];
BigInteger pow = 1;
for (int i = 0; i < blockCharsCount - 1; i++)
{
_powN[blockCharsCount - 1 - i] = pow;
pow *= CharsCount;
}
if (blockCharsCount > 0)
_powN[0] = pow;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0a06acee1a2bf3d4aae0b2a2b83cb5d4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+228
View File
@@ -0,0 +1,228 @@
using System;
using System.Text;
namespace BaseNcoding
{
public class BaseN : Base
{
private readonly ulong[] _powN;
public uint BlockMaxBitsCount { get; }
public override bool HasSpecial => false;
public bool ReverseOrder { get; }
public BaseN(string alphabet, uint blockMaxBitsCount = 32,
Encoding encoding = null, bool reverseOrder = false, bool parallel = false)
: base((uint)alphabet.Length, alphabet, '\0', encoding, parallel)
{
BlockMaxBitsCount = blockMaxBitsCount;
BlockBitsCount = GetOptimalBitsCount(CharsCount, out var charsCountInBits, blockMaxBitsCount);
BlockCharsCount = (int)charsCountInBits;
_powN = new ulong[BlockCharsCount];
ulong pow = 1;
for (int i = 0; i < BlockCharsCount - 1; i++)
{
_powN[BlockCharsCount - 1 - i] = pow;
pow *= CharsCount;
}
_powN[0] = pow;
ReverseOrder = reverseOrder;
}
public override string Encode(byte[] data)
{
if (data == null || data.Length == 0)
return "";
int mainBitsLength = data.Length * 8 / BlockBitsCount * BlockBitsCount;
int tailBitsLength = data.Length * 8 - mainBitsLength;
int mainCharsCount = mainBitsLength * BlockCharsCount / BlockBitsCount;
int tailCharsCount = (tailBitsLength * BlockCharsCount + BlockBitsCount - 1) / BlockBitsCount;
int totalCharsCount = mainCharsCount + tailCharsCount;
int iterationCount = mainCharsCount / BlockCharsCount;
var result = new char[totalCharsCount];
if (!Parallel)
{
EncodeBlock(data, result, 0, iterationCount);
}
else
{
int processorCount = Math.Min(iterationCount, Environment.ProcessorCount);
System.Threading.Tasks.Parallel.For(0, processorCount, i =>
{
int beginInd = i * iterationCount / processorCount;
int endInd = (i + 1) * iterationCount / processorCount;
EncodeBlock(data, result, beginInd, endInd);
});
}
if (tailBitsLength != 0)
{
ulong bits = GetBits64(data, mainBitsLength, tailBitsLength);
BitsToChars(result, mainCharsCount, tailCharsCount, bits);
}
return new string(result);
}
public override byte[] Decode(string data)
{
if (string.IsNullOrEmpty(data))
return new byte[0];
int totalBitsLength = ((data.Length - 1) * BlockBitsCount / BlockCharsCount + 8) / 8 * 8;
int mainBitsLength = totalBitsLength / BlockBitsCount * BlockBitsCount;
int tailBitsLength = totalBitsLength - mainBitsLength;
int mainCharsCount = mainBitsLength * BlockCharsCount / BlockBitsCount;
int tailCharsCount = (tailBitsLength * BlockCharsCount + BlockBitsCount - 1) / BlockBitsCount;
ulong tailBits = CharsToBits(data, mainCharsCount, tailCharsCount);
if (tailBits >> tailBitsLength != 0)
{
totalBitsLength += 8;
mainBitsLength = totalBitsLength / BlockBitsCount * BlockBitsCount;
tailBitsLength = totalBitsLength - mainBitsLength;
mainCharsCount = mainBitsLength * BlockCharsCount / BlockBitsCount;
tailCharsCount = (tailBitsLength * BlockCharsCount + BlockBitsCount - 1) / BlockBitsCount;
}
int iterationCount = mainCharsCount / BlockCharsCount;
byte[] result = new byte[totalBitsLength / 8];
if (!Parallel)
{
DecodeBlock(data, result, 0, iterationCount);
}
else
{
int processorCount = Math.Min(iterationCount, Environment.ProcessorCount);
System.Threading.Tasks.Parallel.For(0, processorCount, i =>
{
int beginInd = i * iterationCount / processorCount;
int endInd = (i + 1) * iterationCount / processorCount;
DecodeBlock(data, result, beginInd, endInd);
});
}
if (tailCharsCount != 0)
{
ulong bits = CharsToBits(data, mainCharsCount, tailCharsCount);
AddBits64(result, bits, mainBitsLength, tailBitsLength);
}
return result;
}
private void EncodeBlock(byte[] src, char[] dst, int beginInd, int endInd)
{
for (int ind = beginInd; ind < endInd; ind++)
{
int charInd = ind * BlockCharsCount;
int bitInd = ind * BlockBitsCount;
ulong bits = GetBits64(src, bitInd, BlockBitsCount);
BitsToChars(dst, charInd, BlockCharsCount, bits);
}
}
private void DecodeBlock(string src, byte[] dst, int beginInd, int endInd)
{
for (int ind = beginInd; ind < endInd; ind++)
{
int charInd = ind * BlockCharsCount;
int bitInd = ind * BlockBitsCount;
ulong bits = CharsToBits(src, charInd, BlockCharsCount);
AddBits64(dst, bits, bitInd, BlockBitsCount);
}
}
private static ulong GetBits64(byte[] data, int bitPos, int bitsCount)
{
ulong result = 0;
int currentBytePos = Math.DivRem(bitPos, 8, out int currentBitInBytePos);
int xLength = Math.Min(bitsCount, 8 - currentBitInBytePos);
if (xLength != 0)
{
result = ((ulong)data[currentBytePos] << 56 + currentBitInBytePos) >> 64 - xLength << bitsCount - xLength;
currentBytePos += Math.DivRem(currentBitInBytePos + xLength, 8, out currentBitInBytePos);
int x2Length = bitsCount - xLength;
if (x2Length > 8)
x2Length = 8;
while (x2Length > 0)
{
xLength += x2Length;
result |= (ulong)data[currentBytePos] >> 8 - x2Length << bitsCount - xLength;
currentBytePos += Math.DivRem(currentBitInBytePos + x2Length, 8, out currentBitInBytePos);
x2Length = bitsCount - xLength;
if (x2Length > 8)
x2Length = 8;
}
}
return result;
}
private static void AddBits64(byte[] data, ulong value, int bitPos, int bitsCount)
{
unchecked
{
int currentBytePos = Math.DivRem(bitPos, 8, out int currentBitInBytePos);
int xLength = Math.Min(bitsCount, 8 - currentBitInBytePos);
if (xLength != 0)
{
byte x1 = (byte)(value << 64 - bitsCount >> 56 + currentBitInBytePos);
data[currentBytePos] |= x1;
currentBytePos += Math.DivRem(currentBitInBytePos + xLength, 8, out currentBitInBytePos);
int x2Length = bitsCount - xLength;
if (x2Length > 8)
x2Length = 8;
while (x2Length > 0)
{
xLength += x2Length;
byte x2 = (byte)(value >> bitsCount - xLength << 8 - x2Length);
data[currentBytePos] |= x2;
currentBytePos += Math.DivRem(currentBitInBytePos + x2Length, 8, out currentBitInBytePos);
x2Length = bitsCount - xLength;
if (x2Length > 8)
x2Length = 8;
}
}
}
}
private void BitsToChars(char[] chars, int ind, int count, ulong block)
{
ulong result = block;
for (int i = 0; i < count; i++)
{
ulong quotient = result / CharsCount;
ulong remainder = result - quotient * CharsCount;
result = quotient;
chars[ind + (!ReverseOrder ? i : count - 1 - i)] = Alphabet[(int)remainder];
}
}
private ulong CharsToBits(string data, int ind, int count)
{
ulong result = 0;
for (int i = 0; i < count; i++)
result += (ulong)InvAlphabet[data[ind + (!ReverseOrder ? i : count - 1 - i)]] * _powN[BlockCharsCount - 1 - i];
return result;
}
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8d996e73fb18bfd45be33725dcf13786
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,48 @@
using System;
using System.Text;
namespace BaseNcoding
{
public static class StringGenerator
{
private const string LettersAndDigits = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
public static string GetAlphabet(int charsCount)
{
var result = new StringBuilder(charsCount);
int i = 0;
int count = 0;
do
{
char c = (char)i;
if (!char.IsControl(c) && !char.IsWhiteSpace(c))
{
result.Append(c);
count++;
}
i++;
}
while (count < charsCount);
return result.ToString();
}
public static string GetRandom(int size, bool onlyLettersAndDigits)
{
Random r = new Random();
if (onlyLettersAndDigits)
{
var result = new char[size];
for (int i = 0; i < size; i++)
result[i] = LettersAndDigits[r.Next(LettersAndDigits.Length)];
return new string(result);
}
var data = new byte[size];
for (int i = 0; i < size; i++)
data[i] = (byte) r.Next(32, 127);
var encoding = new ASCIIEncoding();
return encoding.GetString(data);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b72d6d0bcd1a9e846ad04cc26014bbcd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: