use std::io::{Error, ErrorKind, Result};
fn base64_map(input: u8) -> Result<u8> {
match input {
43 => Ok(62), 47 => Ok(63), 48 => Ok(52), 49 => Ok(53), 50 => Ok(54), 51 => Ok(55), 52 => Ok(56), 53 => Ok(57), 54 => Ok(58), 55 => Ok(59), 56 => Ok(60), 57 => Ok(61), 65 => Ok(0), 66 => Ok(1), 67 => Ok(2), 68 => Ok(3), 69 => Ok(4), 70 => Ok(5), 71 => Ok(6), 72 => Ok(7), 73 => Ok(8), 74 => Ok(9), 75 => Ok(10), 76 => Ok(11), 77 => Ok(12), 78 => Ok(13), 79 => Ok(14), 80 => Ok(15), 81 => Ok(16), 82 => Ok(17), 83 => Ok(18), 84 => Ok(19), 85 => Ok(20), 86 => Ok(21), 87 => Ok(22), 88 => Ok(23), 89 => Ok(24), 90 => Ok(25), 97 => Ok(26), 98 => Ok(27), 99 => Ok(28), 100 => Ok(29), 101 => Ok(30), 102 => Ok(31), 103 => Ok(32), 104 => Ok(33), 105 => Ok(34), 106 => Ok(35), 107 => Ok(36), 108 => Ok(37), 109 => Ok(38), 110 => Ok(39), 111 => Ok(40), 112 => Ok(41), 113 => Ok(42), 114 => Ok(43), 115 => Ok(44), 116 => Ok(45), 117 => Ok(46), 118 => Ok(47), 119 => Ok(48), 120 => Ok(49), 121 => Ok(50), 122 => Ok(51), _ => Err(Error::new(ErrorKind::InvalidData, "invalid base64")),
}
}
#[derive(Debug)]
pub struct Decoder {
tmp: [u8; 4],
pub nb: u8,
}
impl Decoder {
pub fn new() -> Decoder {
Decoder { tmp: [0; 4], nb: 0 }
}
}
impl Default for Decoder {
fn default() -> Self {
Self::new()
}
}
pub fn get_decoded_buffer_size(encoded_len: u32) -> u32 {
return ((encoded_len * 3) + (encoded_len % 4)) / 4;
}
pub fn decode_rfc4648(decoder: &mut Decoder, input: &[u8], output: &mut [u8], decoded_bytes: &mut u32) -> Result<()>
{
let mut i = input;
let mut offset = 0;
let mut stop = false;
while !i.is_empty() {
while decoder.nb < 4 {
if !i.is_empty() && (base64_map(i[0]).is_ok() || i[0] == b'=') {
decoder.tmp[decoder.nb as usize] = i[0];
decoder.nb += 1;
} else {
while decoder.nb > 0
&& decoder.nb < 4
{
decoder.tmp[decoder.nb as usize] = b'=';
decoder.nb += 1;
}
stop = true;
break;
}
i = &i[1..];
}
if decoder.nb == 4 {
decoder.tmp[0] = base64_map(decoder.tmp[0])?;
decoder.tmp[1] = base64_map(decoder.tmp[1])?;
if decoder.tmp[2] == b'=' {
output[offset] = (decoder.tmp[0] << 2) | (decoder.tmp[1] >> 4);
offset += 1;
} else {
decoder.tmp[2] = base64_map(decoder.tmp[2])?;
if decoder.tmp[3] == b'=' {
output[offset] = (decoder.tmp[0] << 2) | (decoder.tmp[1] >> 4);
output[offset + 1] = (decoder.tmp[1] << 4) | (decoder.tmp[2] >> 2);
offset += 2;
} else {
decoder.tmp[3] = base64_map(decoder.tmp[3])?;
output[offset] = (decoder.tmp[0] << 2) | (decoder.tmp[1] >> 4);
output[offset + 1] = (decoder.tmp[1] << 4) | (decoder.tmp[2] >> 2);
output[offset + 2] = (decoder.tmp[2] << 6) | decoder.tmp[3];
offset += 3;
}
}
decoder.nb = 0;
}
if stop {
break;
}
}
*decoded_bytes = offset as u32;
return Ok(());
}
pub fn decode_rfc2045(decoder: &mut Decoder, input: &[u8], output: &mut [u8], decoded_bytes: &mut u32) -> Result<()>
{
let mut i = input;
let mut offset = 0;
while !i.is_empty() {
while decoder.nb < 4 && !i.is_empty() {
if base64_map(i[0]).is_ok() || i[0] == b'=' {
decoder.tmp[decoder.nb as usize] = i[0];
decoder.nb += 1;
}
i = &i[1..];
}
if decoder.nb == 4 {
decoder.tmp[0] = base64_map(decoder.tmp[0])?;
decoder.tmp[1] = base64_map(decoder.tmp[1])?;
if decoder.tmp[2] == b'=' {
output[offset] = (decoder.tmp[0] << 2) | (decoder.tmp[1] >> 4);
offset += 1;
} else {
decoder.tmp[2] = base64_map(decoder.tmp[2])?;
if decoder.tmp[3] == b'=' {
output[offset] = (decoder.tmp[0] << 2) | (decoder.tmp[1] >> 4);
output[offset + 1] = (decoder.tmp[1] << 4) | (decoder.tmp[2] >> 2);
offset += 2;
} else {
decoder.tmp[3] = base64_map(decoder.tmp[3])?;
output[offset] = (decoder.tmp[0] << 2) | (decoder.tmp[1] >> 4);
output[offset + 1] = (decoder.tmp[1] << 4) | (decoder.tmp[2] >> 2);
output[offset + 2] = (decoder.tmp[2] << 6) | decoder.tmp[3];
offset += 3;
}
}
decoder.nb = 0;
}
}
*decoded_bytes = offset as u32;
return Ok(());
}