///|
pub fn base64_encode(bytes : Bytes) -> String {
let table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
let len = bytes.length()
if len == 0 {
return ""
}
let builder = StringBuilder::StringBuilder(size_hint=(len + 2) / 3 * 4)
let mut i = 0
while i + 2 < len {
let b0 = bytes[i].to_int()
let b1 = bytes[i + 1].to_int()
let b2 = bytes[i + 2].to_int()
let triple = (b0 << 16) | (b1 << 8) | b2
let c0 = (triple >> 18) & 0x3F
let c1 = (triple >> 12) & 0x3F
let c2 = (triple >> 6) & 0x3F
let c3 = triple & 0x3F
builder.write_substring(table, c0, 1)
builder.write_substring(table, c1, 1)
builder.write_substring(table, c2, 1)
builder.write_substring(table, c3, 1)
i = i + 3
}
if i < len {
let rem = len - i
if rem == 1 {
let b0 = bytes[i].to_int()
let triple = b0 << 16
let c0 = (triple >> 18) & 0x3F
let c1 = (triple >> 12) & 0x3F
builder.write_substring(table, c0, 1)
builder.write_substring(table, c1, 1)
builder.write_string("==")
} else if rem == 2 {
let b0 = bytes[i].to_int()
let b1 = bytes[i + 1].to_int()
let triple = (b0 << 16) | (b1 << 8)
let c0 = (triple >> 18) & 0x3F
let c1 = (triple >> 12) & 0x3F
let c2 = (triple >> 6) & 0x3F
builder.write_substring(table, c0, 1)
builder.write_substring(table, c1, 1)
builder.write_substring(table, c2, 1)
builder.write_string("=")
}
}
builder.to_string()
}
///|
fn base64_char_value(ch : UInt16) -> Int {
if ch >= (65 : UInt16) && ch <= (90 : UInt16) {
ch.to_int() - 65
} else if ch >= (97 : UInt16) && ch <= (122 : UInt16) {
ch.to_int() - 97 + 26
} else if ch >= (48 : UInt16) && ch <= (57 : UInt16) {
ch.to_int() - 48 + 52
} else if ch == (43 : UInt16) {
62
} else if ch == (47 : UInt16) {
63
} else {
-1
}
}
///|
pub fn base64_decode(input : String) -> Bytes? {
let mut s = input
let rem = s.length() % 4
if rem == 1 {
return None
} else if rem == 2 {
s = s + "=="
} else if rem == 3 {
s = s + "="
}
let len = s.length()
if len == 0 {
return Some(Bytes::from_array([]))
}
let mut padding = 0
if s.at(len - 1) == (61 : UInt16) {
padding = padding + 1
if s.at(len - 2) == (61 : UInt16) {
padding = padding + 1
if s.at(len - 3) == (61 : UInt16) {
return None
}
}
}
let out_len = len / 4 * 3 - padding
let out : Array[Byte] = Array::make(out_len, (0 : Byte))
let mut out_idx = 0
let mut in_idx = 0
while in_idx < len {
let c0 = s.at(in_idx)
let c1 = s.at(in_idx + 1)
let c2 = s.at(in_idx + 2)
let c3 = s.at(in_idx + 3)
let is_last_quantum = in_idx + 4 == len
if is_last_quantum && padding > 0 {
let v0 = base64_char_value(c0)
let v1 = base64_char_value(c1)
if v0 < 0 || v1 < 0 {
return None
}
if padding == 1 {
let v2 = base64_char_value(c2)
if v2 < 0 || c3 != (61 : UInt16) {
return None
}
let triple = (v0 << 18) | (v1 << 12) | (v2 << 6)
if (triple & 0x3) != 0 {
return None
}
out[out_idx] = ((triple >> 16) & 0xFF).to_byte()
out[out_idx + 1] = ((triple >> 8) & 0xFF).to_byte()
out_idx = out_idx + 2
} else if padding == 2 {
if c2 != (61 : UInt16) || c3 != (61 : UInt16) {
return None
}
let triple = (v0 << 18) | (v1 << 12)
if (triple & 0xF) != 0 {
return None
}
out[out_idx] = ((triple >> 16) & 0xFF).to_byte()
out_idx = out_idx + 1
}
} else {
let v0 = base64_char_value(c0)
let v1 = base64_char_value(c1)
let v2 = base64_char_value(c2)
let v3 = base64_char_value(c3)
if v0 < 0 || v1 < 0 || v2 < 0 || v3 < 0 {
return None
}
let triple = (v0 << 18) | (v1 << 12) | (v2 << 6) | v3
out[out_idx] = ((triple >> 16) & 0xFF).to_byte()
out[out_idx + 1] = ((triple >> 8) & 0xFF).to_byte()
out[out_idx + 2] = (triple & 0xFF).to_byte()
out_idx = out_idx + 3
}
in_idx = in_idx + 4
}
Some(Bytes::from_array(out))
}