use alloc::vec::Vec;
use core::marker::PhantomData;
use crate::{Error, Result};
use super::{Kind, LastChars};
struct Decoder<'a, 'e> {
bytes: &'a [u8],
index: usize,
len: usize,
allows_line_separators: bool,
must_or_can_use_pad: bool,
allows_invalid_chars: bool,
last_chars: &'a LastChars,
phantom_data: PhantomData<&'e ()>,
}
impl<'a, 'e> Decoder<'a, 'e> {
fn new(bytes: &'a [u8], allows_line_separators: bool, must_or_can_use_pad: bool, allows_invalid_chars: bool, last_chars: &'a LastChars)
-> Self {
Self {
bytes,
index: 0,
len: bytes.len(),
allows_line_separators,
must_or_can_use_pad,
allows_invalid_chars,
last_chars,
phantom_data: PhantomData,
}
}
fn decode_bits(&mut self) -> Result<'e, Option<(u8, bool)>> {
loop {
if self.index >= self.len {
return Ok(None);
}
let byte = self.bytes[self.index];
self.index += 1;
match byte {
b'A'...b'Z' => return Ok(Some((byte - b'A', false))),
b'a'...b'z' => return Ok(Some((byte - b'a' + 26, false))),
b'0'...b'9' => return Ok(Some((byte - b'0' + 52, false))),
b'=' => match self.index > 1 && self.must_or_can_use_pad {
true => return Ok(Some((0, true))),
false => return Err(Error::new("Invalid pad char: '='").into()),
},
b'\r' | b'\n' | b' ' => match self.allows_line_separators {
true => {
match byte {
b' ' => (),
b'\r' => {
if self.index >= self.len || self.bytes[self.index] != b'\n' {
return Err(Error::new(alloc::format!("Invalid line separator: {:?}", &byte)).into());
}
self.index += 1;
},
_ => (),
};
match self.index < self.len {
true => match self.bytes[self.index] {
b'\r' | b'\n' => return Err(Error::new("Duplicate line separators").into()),
_ => (),
},
false => return Ok(None),
};
},
false => return Err(Error::new(alloc::format!("Invalid line separator: {:02x}", byte)).into()),
},
_ => {
if self.last_chars.first == byte as char {
return Ok(Some((62, false)));
} else if self.last_chars.last == byte as char {
return Ok(Some((63, false)));
} else {
match self.allows_invalid_chars {
true => (),
false => return Err(Error::new(alloc::format!("Invalid byte: {:?}", byte)).into()),
};
}
},
};
}
}
fn has_more_bytes(&self) -> bool {
self.index < self.len
}
}
pub fn decode<'a, B>(bytes: B, kind: Kind) -> Result<'a, Vec<u8>> where B: AsRef<[u8]> {
let bytes = bytes.as_ref();
let mut result = Vec::with_capacity(kind.estimate_decoding_capacity(bytes));
let must_use_pad = kind.must_use_pad();
let mut decoder = Decoder::new(
bytes, kind.line_separators().is_some(), must_use_pad || kind.can_use_pad(), kind.allows_invalid_chars(), kind.last_chars()
);
loop {
let first_bits = match decoder.decode_bits()? {
Some((first_bits, is_pad_char)) => match is_pad_char {
true => return Err(Error::new("Invalid pad character at first byte").into()),
false => first_bits,
},
None => break,
};
let second_bits = match decoder.decode_bits()? {
Some((second_bits, is_pad_char)) => match is_pad_char {
true => return Err(Error::new("Invalid pad character at second byte").into()),
false => {
result.push((first_bits << 2) | (second_bits >> 4));
second_bits
},
},
None => return Err(Error::new("Missing second byte").into()),
};
let (third_bits, third_byte_is_pad_char) = match decoder.decode_bits()? {
Some((third_bits, is_pad_char)) => {
if is_pad_char == false {
result.push((second_bits << 4) | (third_bits >> 2));
}
(third_bits, is_pad_char)
},
None => match must_use_pad {
true => return Err(Error::new("Missing pad char '=' for third byte").into()),
false => break,
},
};
match decoder.decode_bits()? {
Some((fourth_bits, is_pad_char)) => {
match third_byte_is_pad_char {
true => if is_pad_char == false {
return Err(Error::new("Invalid character after first pad character").into());
},
false => if is_pad_char == false {
result.push((third_bits << 6) | fourth_bits);
},
};
if is_pad_char {
match decoder.has_more_bytes() {
true => return Err(Error::new("Invalid character after ending").into()),
false => break,
};
}
},
None => match must_use_pad {
true => return Err(Error::new("Missing pad char '=' for fourth byte").into()),
false => break,
},
};
}
Ok(result)
}
pub fn decode_standard<'a, B>(bytes: B) -> Result<'a, Vec<u8>> where B: AsRef<[u8]> {
decode(bytes, Kind::Standard)
}
pub fn decode_imap<'a, B>(bytes: B) -> Result<'a, Vec<u8>> where B: AsRef<[u8]> {
decode(bytes, Kind::IMAP)
}
pub fn decode_mime<'a, B>(bytes: B) -> Result<'a, Vec<u8>> where B: AsRef<[u8]> {
decode(bytes, Kind::MIME)
}
pub fn decode_url<'a, B>(bytes: B) -> Result<'a, Vec<u8>> where B: AsRef<[u8]> {
decode(bytes, Kind::URL)
}
pub fn decode_freenet_url<'a, B>(bytes: B) -> Result<'a, Vec<u8>> where B: AsRef<[u8]> {
decode(bytes, Kind::FreenetURL)
}