///|
/// Base64 encoding and decoding tables.
let base64table : Array[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', '+', '/',
]
// "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
///|
/// Base64 decode lookup table.
let base64table_dec : Bytes = [
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3f, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
0x3c, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04,
0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x1a,
0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
]
///|
/// Encodes a byte array into a Base64 string.
pub fn encode_bytes(input: Bytes) -> String {
let mut output = "";
let mut i = 0;
while i < input.length() {
let byte1 = input[i];
let byte2 = if i + 1 < input.length() { input[i + 1] } else { 0 };
let byte3 = if i + 2 < input.length() { input[i + 2] } else { 0 };
let index1 = (byte1 >> 2) & 0x3F;
let index2 = ((byte1 << 4) | (byte2 >> 4)) & 0x3F;
let index3 = ((byte2 << 2) | (byte3 >> 6)) & 0x3F;
let index4 = byte3 & 0x3F;
output += base64table[index1.to_int()].to_string();
output += base64table[index2.to_int()].to_string();
output += if i + 1 < input.length() { base64table[index3.to_int()].to_string() } else { "=" };
output += if i + 2 < input.length() { base64table[index4.to_int()].to_string() } else { "=" };
i += 3;
}
return output;
}
///|
/// Encodes a utf8 string into a Base64 string.
pub fn encode_utf8(input : String) -> String {
let bytes = @utf8.encode(input)
encode_bytes(bytes)
}
///|
/// Decodes a Base64 string to Bytes.
pub fn decode_bytes(input : String) -> Bytes {
let output : Array[Byte] = []
let mut i = 0
while i < input.length() {
let char1 = input[i]
let char2 = if i + 1 < input.length() { input[i + 1] } else { 'A' }
let char3 = if i + 2 < input.length() { input[i + 2] } else { 'A' }
let char4 = if i + 3 < input.length() { input[i + 3] } else { 'A' }
let byte1 = base64table_dec[char1.to_byte().to_int()]
let byte2 = base64table_dec[char2.to_byte().to_int()]
let byte3 = base64table_dec[char3.to_byte().to_int()]
let byte4 = base64table_dec[char4.to_byte().to_int()]
output.push((byte1 << 2) | (byte2 >> 4))
if char3 != '=' {
output.push(((byte2 & 0x0F) << 4) | (byte3 >> 2))
}
if char4 != '=' {
output.push(((byte3 & 0x03) << 6) | byte4)
}
i += 4
}
Bytes::from_array(output)
}
///|
/// Decodes a Base64 string to a utf8 string.
pub fn decode_utf8(input : String) -> String {
let bytes = decode_bytes(input)
@utf8.decode_lossy(bytes)
}
///|
/// Encodes a string to Base64URL
pub fn encode_url(input : String) -> String {
let base64 = encode_utf8(input)
base64
.replace_all(old="+", new="-")
.replace_all(old="/", new="_")
.replace_all(old="=", new="")
}
///|
/// Decodes a Base64URL string
pub fn decode_url(input : String) -> Bytes {
let mut base64 = input
.replace_all(old="-", new="+")
.replace_all(old="_", new="/")
let padding_needed = (4 - (base64.length() % 4)) % 4
for _ in 0..