using System;
using System.Collections.Generic;
using System.Text;
/*
Base‑36 encoding/decoding in Mono‑compatible C#
----------------------------------------------
Base‑36 digits: 0–9, A–Z
Encoding:
- Convert string → bytes (UTF‑8)
- Convert bytes → big integer (base‑256)
- Convert big integer → Base‑36
Decoding:
- Convert Base‑36 → big integer
- Convert big integer → bytes (base‑256)
- Convert bytes → original UTF‑8 string
We implement our own big‑integer using List<uint> chunks (32‑bit).
*/
class Base36Codec
{
private const string Base36Digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
// Convert Base‑36 character → numeric value
private static int Base36Value(char c)
{
if (c >= '0' && c <= '9') return c - '0';
return c - 'A' + 10;
}
// Encode any string into Base‑36
public static string EncodeToBase36(string input)
{
byte[] bytes = Encoding.UTF8.GetBytes(input);
// Big integer stored as 32‑bit chunks (little‑endian)
List<uint> number = new List<uint>();
number.Add(0);
// Convert bytes → big integer (base‑256)
foreach (byte b in bytes) {
uint carry = b;
for (int i = 0; i < number.Count; i++) {
ulong value = (ulong)number[i] * 256UL + carry;
number[i] = (uint)(value & 0xFFFFFFFFUL);
carry = (uint)(value >> 32);
}
if (carry > 0)
number.Add(carry);
}
// Convert big integer → Base‑36
StringBuilder encoded = new StringBuilder();
while (!(number.Count == 1 && number[0] == 0)) {
uint remainder = 0;
for (int i = number.Count - 1; i >= 0; i--) {
ulong value = ((ulong)remainder << 32) | number[i];
number[i] = (uint)(value / 36UL);
remainder = (uint)(value % 36UL);
}
while (number.Count > 1 && number[number.Count - 1] == 0)
number.RemoveAt(number.Count - 1);
encoded.Append(Base36Digits[(int)remainder]);
}
// Reverse Base‑36 output
char[] arr = encoded.ToString().ToCharArray();
Array.Reverse(arr);
return new string(arr);
}
// Decode Base‑36 back into original string
public static string DecodeFromBase36(string encoded)
{
encoded = encoded.ToUpper();
// Big integer stored as 32‑bit chunks (little‑endian)
List<uint> number = new List<uint>();
number.Add(0);
// Convert Base‑36 → big integer
foreach (char c in encoded) {
int digit = Base36Value(c);
uint carry = (uint)digit;
for (int i = 0; i < number.Count; i++) {
ulong value = (ulong)number[i] * 36UL + carry;
number[i] = (uint)(value & 0xFFFFFFFFUL);
carry = (uint)(value >> 32);
}
if (carry > 0)
number.Add(carry);
}
// Convert big integer → bytes (base‑256)
List<byte> bytes = new List<byte>();
while (!(number.Count == 1 && number[0] == 0))
{
uint remainder = 0;
for (int i = number.Count - 1; i >= 0; i--) {
ulong value = ((ulong)remainder << 32) | number[i];
number[i] = (uint)(value / 256UL);
remainder = (uint)(value % 256UL);
}
while (number.Count > 1 && number[number.Count - 1] == 0)
number.RemoveAt(number.Count - 1);
bytes.Add((byte)remainder);
}
bytes.Reverse();
return Encoding.UTF8.GetString(bytes.ToArray());
}
static void Main()
{
string text = "Hello Universe!";
string encoded = EncodeToBase36(text);
string decoded = DecodeFromBase36(encoded);
Console.WriteLine("Original: " + text);
Console.WriteLine("Base-36 encoded: " + encoded);
Console.WriteLine("Decoded: " + decoded);
}
}
/*
run:
Original: Hello Universe!
Base-36 encoded: LP4N024HJ1YVBVD84Y8TYQP
Decoded: Hello Universe!
*/