Skip to content

Instantly share code, notes, and snippets.

@bwindels
Created February 20, 2018 22:28
Show Gist options
  • Save bwindels/777a1b5b13cd54bcd67dca3c925ca7bb to your computer and use it in GitHub Desktop.
Save bwindels/777a1b5b13cd54bcd67dca3c925ca7bb to your computer and use it in GitHub Desktop.
In-place base64 decoder
fn main() {
const ENCODED : &'static [u8] = b"aGVsbG8gd29ybGQ=";
//const ENCODED : &'static [u8] = b"aGVlbGxvIHdvcmxk";
let mut encoded = [0u8; 16];
assert_eq!(ENCODED.len(), encoded.len());
for i in 0..ENCODED.len() {
encoded[i] = ENCODED[i];
}
let decoded = base64_decode(encoded.as_mut()).unwrap();
println!("{}", std::str::from_utf8(decoded).unwrap());
}
fn base64_decode<'a>(src: &'a mut [u8]) -> Option<&'a mut [u8]> {
let mut previous_6bit = 0u8;
let mut first_padding_idx : Option<usize> = None;
for i in 0..src.len() {
let current = src[i];
let decoded_6bit = match current {
65...90 => Some(current - 65),// A-Z,
97...122 => Some(current - 97 + 26),// a-z,
48...57 => Some(current + 4), //0-9 (after 2x26 comes 52 which is 48 + 4)
43 => Some(62), // +,
47 => Some(63), // /,
61 => {
first_padding_idx = first_padding_idx.or(Some(i));
Some(0)
}, // = (padding)
_ => None //invalid character
}?;
let decoded_8bit = match i % 4 {
0 => None,
1 => Some(previous_6bit << 2 | (decoded_6bit & 0b11_0000) >> 4),
2 => Some(previous_6bit << 4 | (decoded_6bit & 0b11_1100) >> 2),
3 => Some(previous_6bit << 6 | (decoded_6bit & 0b11_1111)),
_ => panic!("wtf")
};
if let Some(d) = decoded_8bit {
let index = i - (i / 4) - 1;
src[index] = d;
}
previous_6bit = decoded_6bit;
}
let old_len = first_padding_idx.unwrap_or(src.len());
let new_len = old_len - (old_len / 4);
Some(&mut src[0 .. new_len])
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment