| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165 |
- //! <https://infra.spec.whatwg.org/#forgiving-base64-decode>
- #[derive(Debug)]
- pub struct InvalidBase64(InvalidBase64Details);
- #[derive(Debug)]
- enum InvalidBase64Details {
- UnexpectedSymbol(u8),
- AlphabetSymbolAfterPadding,
- LoneAlphabetSymbol,
- Padding,
- }
- #[derive(Debug)]
- pub enum DecodeError<E> {
- InvalidBase64(InvalidBase64),
- WriteError(E),
- }
- impl<E> From<InvalidBase64Details> for DecodeError<E> {
- fn from(e: InvalidBase64Details) -> Self {
- DecodeError::InvalidBase64(InvalidBase64(e))
- }
- }
- pub(crate) enum Impossible {}
- impl From<DecodeError<Impossible>> for InvalidBase64 {
- fn from(e: DecodeError<Impossible>) -> Self {
- match e {
- DecodeError::InvalidBase64(e) => e,
- DecodeError::WriteError(e) => match e {},
- }
- }
- }
- /// `input` is assumed to be in an ASCII-compatible encoding
- pub fn decode_to_vec(input: &[u8]) -> Result<Vec<u8>, InvalidBase64> {
- let mut v = Vec::new();
- {
- let mut decoder = Decoder::new(|bytes| Ok(v.extend_from_slice(bytes)));
- decoder.feed(input)?;
- decoder.finish()?;
- }
- Ok(v)
- }
- /// <https://infra.spec.whatwg.org/#forgiving-base64-decode>
- pub struct Decoder<F, E>
- where
- F: FnMut(&[u8]) -> Result<(), E>,
- {
- write_bytes: F,
- bit_buffer: u32,
- buffer_bit_length: u8,
- padding_symbols: u8,
- }
- impl<F, E> Decoder<F, E>
- where
- F: FnMut(&[u8]) -> Result<(), E>,
- {
- pub fn new(write_bytes: F) -> Self {
- Self {
- write_bytes,
- bit_buffer: 0,
- buffer_bit_length: 0,
- padding_symbols: 0,
- }
- }
- /// Feed to the decoder partial input in an ASCII-compatible encoding
- pub fn feed(&mut self, input: &[u8]) -> Result<(), DecodeError<E>> {
- for &byte in input.iter() {
- let value = BASE64_DECODE_TABLE[byte as usize];
- if value < 0 {
- // A character that’s not part of the alphabet
- // Remove ASCII whitespace
- if matches!(byte, b' ' | b'\t' | b'\n' | b'\r' | b'\x0C') {
- continue;
- }
- if byte == b'=' {
- self.padding_symbols = self.padding_symbols.saturating_add(1);
- continue;
- }
- Err(InvalidBase64Details::UnexpectedSymbol(byte))?
- }
- if self.padding_symbols > 0 {
- Err(InvalidBase64Details::AlphabetSymbolAfterPadding)?
- }
- self.bit_buffer <<= 6;
- self.bit_buffer |= value as u32;
- // 18 before incrementing means we’ve just reached 24
- if self.buffer_bit_length < 18 {
- self.buffer_bit_length += 6;
- } else {
- // We’ve accumulated four times 6 bits, which equals three times 8 bits.
- let byte_buffer = [
- (self.bit_buffer >> 16) as u8,
- (self.bit_buffer >> 8) as u8,
- self.bit_buffer as u8,
- ];
- (self.write_bytes)(&byte_buffer).map_err(DecodeError::WriteError)?;
- self.buffer_bit_length = 0;
- // No need to reset bit_buffer,
- // since next time we’re only gonna read relevant bits.
- }
- }
- Ok(())
- }
- /// Call this to signal the end of the input
- pub fn finish(mut self) -> Result<(), DecodeError<E>> {
- match (self.buffer_bit_length, self.padding_symbols) {
- (0, 0) => {
- // A multiple of four of alphabet symbols, and nothing else.
- }
- (12, 2) | (12, 0) => {
- // A multiple of four of alphabet symbols, followed by two more symbols,
- // optionally followed by two padding characters (which make a total multiple of four).
- let byte_buffer = [(self.bit_buffer >> 4) as u8];
- (self.write_bytes)(&byte_buffer).map_err(DecodeError::WriteError)?;
- }
- (18, 1) | (18, 0) => {
- // A multiple of four of alphabet symbols, followed by three more symbols,
- // optionally followed by one padding character (which make a total multiple of four).
- let byte_buffer = [(self.bit_buffer >> 10) as u8, (self.bit_buffer >> 2) as u8];
- (self.write_bytes)(&byte_buffer).map_err(DecodeError::WriteError)?;
- }
- (6, _) => Err(InvalidBase64Details::LoneAlphabetSymbol)?,
- _ => Err(InvalidBase64Details::Padding)?,
- }
- Ok(())
- }
- }
- /// Generated by `make_base64_decode_table.py` based on "Table 1: The Base 64 Alphabet"
- /// at <https://tools.ietf.org/html/rfc4648#section-4>
- ///
- /// Array indices are the byte value of symbols.
- /// Array values are their positions in the base64 alphabet,
- /// or -1 for symbols not in the alphabet.
- /// The position contributes 6 bits to the decoded bytes.
- #[rustfmt::skip]
- const BASE64_DECODE_TABLE: [i8; 256] = [
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
- 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
- -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
- 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
- -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
- 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- ];
|