using System.Collections.Generic;
static void Main(string[] args)
var stringAsArray = Encoding.UTF8.GetBytes("hello world");
for (int i = 0; i < loopCount; i++)
var encoded = Base91.Encode("hello world");
var decoded = Base91.Decode(encoded);
Console.WriteLine("Base91 "+ (e - n));
for (int i = 0; i < loopCount; i++)
var encoded = Ascii85.Encode(stringAsArray);
var decoded = Ascii85.Decode(encoded);
Console.WriteLine("Base85 "+ (e - n));
for (int i = 0; i < loopCount; i++)
var encoded = Convert.ToBase64String(stringAsArray);
var decoded = Convert.FromBase64String(encoded);
Console.WriteLine("Base64 "+ (e - n));
private static char[] EncodeTable = new char[]
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '!', '#', '$',
'%', '&', '(', ')', '*', '+', ',', '.', '/', ':', ';', '<', '=',
'>', '?', '@', '[', ']', '^', '_', '`', '{', '|', '}', '~', '"'
private static Dictionary<byte, int> DecodeTable;
private static void InitDecodeTable()
DecodeTable = new Dictionary<byte, int>();
for (int i = 0; i < 255; i++)
DecodeTable[(byte)i] = -1;
for (int i = 0; i < EncodeTable.Length; i++)
DecodeTable[(byte)EncodeTable[i]] = i;
public static string Encode(string input)
StringBuilder output = new StringBuilder();
for (int i = 0; i < input.Length; i++)
b |= (byte)input[i] << n;
output.Append((char)EncodeTable[v % 91]);
output.Append((char)EncodeTable[v / 91]);
output.Append((char)EncodeTable[b % 91]);
output.Append((char)EncodeTable[b / 91]);
return output.ToString();
public static string Decode(string input)
StringBuilder output = new StringBuilder();
for (int i = 0; i < input.Length; i++)
c = DecodeTable[(byte)input[i]];
n += (v & 8191) > 88 ? 13 : 14;
output.Append((char)(b & 255));
output.Append((char)((b | v << n) & 255));
return output.ToString();
public static class Ascii85
public static string Encode(byte[] bytes)
throw new ArgumentNullException("bytes");
StringBuilder sb = new StringBuilder(bytes.Length * 5 / 4);
foreach (byte b in bytes)
value |= ((uint) b) << (24 - (count * 8));
EncodeValue(sb, value, 0);
EncodeValue(sb, value, 4 - count);
public static byte[] Decode(string encoded)
throw new ArgumentNullException("encoded");
using (MemoryStream stream = new MemoryStream(encoded.Length * 4 / 5))
foreach (char ch in encoded)
if (ch == 'z' && count == 0)
DecodeValue(stream, value, 0);
else if (ch < c_firstCharacter || ch > c_lastCharacter)
checked { value += (uint) (s_powersOf85[count] * (ch - c_firstCharacter)); }
catch (OverflowException ex)
throw new FormatException("The current group of characters decodes to a value greater than UInt32.MaxValue.", ex);
DecodeValue(stream, value, 0);
throw new FormatException("The final Ascii85 block must contain more than one character.");
for (int padding = count; padding < 5; padding++)
checked { value += 84 * s_powersOf85[padding]; }
catch (OverflowException ex)
throw new FormatException("The current group of characters decodes to a value greater than UInt32.MaxValue.", ex);
DecodeValue(stream, value, 5 - count);
private static void EncodeValue(StringBuilder sb, uint value, int paddingBytes)
char[] encoded = new char[5];
for (int index = 4; index >= 0; index--)
encoded[index] = (char) ((value % 85) + c_firstCharacter);
Array.Resize(ref encoded, 5 - paddingBytes);
private static void DecodeValue(Stream stream, uint value, int paddingChars)
stream.WriteByte((byte) (value >> 24));
stream.WriteByte((byte) ((value >> 16) & 0xFF));
stream.WriteByte(((byte) ((value >> 8) & 0xFF)));
stream.WriteByte((byte) (value & 0xFF));
const char c_firstCharacter = '!';
const char c_lastCharacter = 'u';
static readonly uint[] s_powersOf85 = new uint[] { 85u * 85u * 85u * 85u, 85u * 85u * 85u, 85u * 85u, 85u, 1 };