forgiving_base64.rs 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. //! <https://infra.spec.whatwg.org/#forgiving-base64-decode>
  2. use alloc::vec::Vec;
  3. use core::fmt;
  4. #[derive(Debug)]
  5. pub struct InvalidBase64(InvalidBase64Details);
  6. impl fmt::Display for InvalidBase64 {
  7. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  8. match self.0 {
  9. InvalidBase64Details::UnexpectedSymbol(code_point) => {
  10. write!(f, "symbol with codepoint {} not expected", code_point)
  11. }
  12. InvalidBase64Details::AlphabetSymbolAfterPadding => {
  13. write!(f, "alphabet symbol present after padding")
  14. }
  15. InvalidBase64Details::LoneAlphabetSymbol => write!(f, "lone alphabet symbol present"),
  16. InvalidBase64Details::Padding => write!(f, "incorrect padding"),
  17. }
  18. }
  19. }
  20. #[cfg(feature = "std")]
  21. impl std::error::Error for InvalidBase64 {}
  22. #[derive(Debug)]
  23. enum InvalidBase64Details {
  24. UnexpectedSymbol(u8),
  25. AlphabetSymbolAfterPadding,
  26. LoneAlphabetSymbol,
  27. Padding,
  28. }
  29. #[derive(Debug)]
  30. pub enum DecodeError<E> {
  31. InvalidBase64(InvalidBase64),
  32. WriteError(E),
  33. }
  34. impl<E: fmt::Display> fmt::Display for DecodeError<E> {
  35. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  36. match self {
  37. Self::InvalidBase64(inner) => write!(f, "base64 not valid: {}", inner),
  38. Self::WriteError(err) => write!(f, "write error: {}", err),
  39. }
  40. }
  41. }
  42. #[cfg(feature = "std")]
  43. impl<E: std::error::Error> std::error::Error for DecodeError<E> {}
  44. impl<E> From<InvalidBase64Details> for DecodeError<E> {
  45. fn from(e: InvalidBase64Details) -> Self {
  46. Self::InvalidBase64(InvalidBase64(e))
  47. }
  48. }
  49. pub(crate) enum Impossible {}
  50. impl From<DecodeError<Impossible>> for InvalidBase64 {
  51. fn from(e: DecodeError<Impossible>) -> Self {
  52. match e {
  53. DecodeError::InvalidBase64(e) => e,
  54. DecodeError::WriteError(e) => match e {},
  55. }
  56. }
  57. }
  58. /// `input` is assumed to be in an ASCII-compatible encoding
  59. pub fn decode_to_vec(input: &[u8]) -> Result<Vec<u8>, InvalidBase64> {
  60. let mut v = Vec::new();
  61. {
  62. let mut decoder = Decoder::new(|bytes| {
  63. v.extend_from_slice(bytes);
  64. Ok(())
  65. });
  66. decoder.feed(input)?;
  67. decoder.finish()?;
  68. }
  69. Ok(v)
  70. }
  71. /// <https://infra.spec.whatwg.org/#forgiving-base64-decode>
  72. pub struct Decoder<F, E>
  73. where
  74. F: FnMut(&[u8]) -> Result<(), E>,
  75. {
  76. write_bytes: F,
  77. bit_buffer: u32,
  78. buffer_bit_length: u8,
  79. padding_symbols: u8,
  80. }
  81. impl<F, E> Decoder<F, E>
  82. where
  83. F: FnMut(&[u8]) -> Result<(), E>,
  84. {
  85. pub fn new(write_bytes: F) -> Self {
  86. Self {
  87. write_bytes,
  88. bit_buffer: 0,
  89. buffer_bit_length: 0,
  90. padding_symbols: 0,
  91. }
  92. }
  93. /// Feed to the decoder partial input in an ASCII-compatible encoding
  94. pub fn feed(&mut self, input: &[u8]) -> Result<(), DecodeError<E>> {
  95. for &byte in input.iter() {
  96. let value = BASE64_DECODE_TABLE[byte as usize];
  97. if value < 0 {
  98. // A character that’s not part of the alphabet
  99. // Remove ASCII whitespace
  100. if matches!(byte, b' ' | b'\t' | b'\n' | b'\r' | b'\x0C') {
  101. continue;
  102. }
  103. if byte == b'=' {
  104. self.padding_symbols = self.padding_symbols.saturating_add(1);
  105. continue;
  106. }
  107. return Err(InvalidBase64Details::UnexpectedSymbol(byte).into());
  108. }
  109. if self.padding_symbols > 0 {
  110. return Err(InvalidBase64Details::AlphabetSymbolAfterPadding.into());
  111. }
  112. self.bit_buffer <<= 6;
  113. self.bit_buffer |= value as u32;
  114. // 18 before incrementing means we’ve just reached 24
  115. if self.buffer_bit_length < 18 {
  116. self.buffer_bit_length += 6;
  117. } else {
  118. // We’ve accumulated four times 6 bits, which equals three times 8 bits.
  119. let byte_buffer = [
  120. (self.bit_buffer >> 16) as u8,
  121. (self.bit_buffer >> 8) as u8,
  122. self.bit_buffer as u8,
  123. ];
  124. (self.write_bytes)(&byte_buffer).map_err(DecodeError::WriteError)?;
  125. self.buffer_bit_length = 0;
  126. // No need to reset bit_buffer,
  127. // since next time we’re only gonna read relevant bits.
  128. }
  129. }
  130. Ok(())
  131. }
  132. /// Call this to signal the end of the input
  133. pub fn finish(mut self) -> Result<(), DecodeError<E>> {
  134. match (self.buffer_bit_length, self.padding_symbols) {
  135. (0, 0) => {
  136. // A multiple of four of alphabet symbols, and nothing else.
  137. }
  138. (12, 2) | (12, 0) => {
  139. // A multiple of four of alphabet symbols, followed by two more symbols,
  140. // optionally followed by two padding characters (which make a total multiple of four).
  141. let byte_buffer = [(self.bit_buffer >> 4) as u8];
  142. (self.write_bytes)(&byte_buffer).map_err(DecodeError::WriteError)?;
  143. }
  144. (18, 1) | (18, 0) => {
  145. // A multiple of four of alphabet symbols, followed by three more symbols,
  146. // optionally followed by one padding character (which make a total multiple of four).
  147. let byte_buffer = [(self.bit_buffer >> 10) as u8, (self.bit_buffer >> 2) as u8];
  148. (self.write_bytes)(&byte_buffer).map_err(DecodeError::WriteError)?;
  149. }
  150. (6, _) => return Err(InvalidBase64Details::LoneAlphabetSymbol.into()),
  151. _ => return Err(InvalidBase64Details::Padding.into()),
  152. }
  153. Ok(())
  154. }
  155. }
  156. /// Generated by `make_base64_decode_table.py` based on "Table 1: The Base 64 Alphabet"
  157. /// at <https://tools.ietf.org/html/rfc4648#section-4>
  158. ///
  159. /// Array indices are the byte value of symbols.
  160. /// Array values are their positions in the base64 alphabet,
  161. /// or -1 for symbols not in the alphabet.
  162. /// The position contributes 6 bits to the decoded bytes.
  163. #[rustfmt::skip]
  164. const BASE64_DECODE_TABLE: [i8; 256] = [
  165. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  166. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  167. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
  168. 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
  169. -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
  170. 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
  171. -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
  172. 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
  173. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  174. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  175. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  176. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  177. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  178. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  179. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  180. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  181. ];