const DEFAULT_ALPHABET: &[u8; 64] =
b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
pub fn encode_base64(s: &[u8], alphabet: Option<&[u8; 64]>, offset: usize) -> Option<Vec<u8>> {
let alphabet = alphabet.unwrap_or(DEFAULT_ALPHABET);
let mut res = Vec::with_capacity(s.len() * 4 / 3);
let chunks_offset = match offset % 3 {
1 => {
if s.len() < 2 {
return None;
}
let v: u32 = (u32::from(s[0]) << 8) | u32::from(s[1]);
res.push(alphabet[((v >> 6) & 0x3F) as usize]);
res.push(alphabet[(v & 0x3F) as usize]);
2
}
2 => {
if s.is_empty() {
return None;
}
res.push(alphabet[(s[0] & 0x3F) as usize]);
1
}
_ => 0,
};
let mut iter = s[chunks_offset..].chunks_exact(3);
for chunk in &mut iter {
let v: u32 = (u32::from(chunk[0]) << 16) | (u32::from(chunk[1]) << 8) | u32::from(chunk[2]);
res.push(alphabet[((v >> 18) & 0x3F) as usize]);
res.push(alphabet[((v >> 12) & 0x3F) as usize]);
res.push(alphabet[((v >> 6) & 0x3F) as usize]);
res.push(alphabet[(v & 0x3F) as usize]);
}
match iter.remainder() {
[a] => {
res.push(alphabet[((*a >> 2) & 0x3F) as usize]);
}
[a, b] => {
let v: u32 = (u32::from(*a) << 8) | u32::from(*b);
res.push(alphabet[((v >> 10) & 0x3F) as usize]);
res.push(alphabet[((v >> 4) & 0x3F) as usize]);
}
_ => (),
}
Some(res)
}