1 use crate::{tables, Config};
2 
3 #[cfg(any(feature = "alloc", feature = "std", test))]
4 use crate::STANDARD;
5 #[cfg(any(feature = "alloc", feature = "std", test))]
6 use alloc::vec::Vec;
7 use core::fmt;
8 #[cfg(any(feature = "std", test))]
9 use std::error;
10 
11 // decode logic operates on chunks of 8 input bytes without padding
12 const INPUT_CHUNK_LEN: usize = 8;
13 const DECODED_CHUNK_LEN: usize = 6;
14 // we read a u64 and write a u64, but a u64 of input only yields 6 bytes of output, so the last
15 // 2 bytes of any output u64 should not be counted as written to (but must be available in a
16 // slice).
17 const DECODED_CHUNK_SUFFIX: usize = 2;
18 
19 // how many u64's of input to handle at a time
20 const CHUNKS_PER_FAST_LOOP_BLOCK: usize = 4;
21 const INPUT_BLOCK_LEN: usize = CHUNKS_PER_FAST_LOOP_BLOCK * INPUT_CHUNK_LEN;
22 // includes the trailing 2 bytes for the final u64 write
23 const DECODED_BLOCK_LEN: usize =
24     CHUNKS_PER_FAST_LOOP_BLOCK * DECODED_CHUNK_LEN + DECODED_CHUNK_SUFFIX;
25 
26 /// Errors that can occur while decoding.
27 #[derive(Clone, Debug, PartialEq, Eq)]
28 pub enum DecodeError {
29     /// An invalid byte was found in the input. The offset and offending byte are provided.
30     InvalidByte(usize, u8),
31     /// The length of the input is invalid.
32     InvalidLength,
33     /// The last non-padding input symbol's encoded 6 bits have nonzero bits that will be discarded.
34     /// This is indicative of corrupted or truncated Base64.
35     /// Unlike InvalidByte, which reports symbols that aren't in the alphabet, this error is for
36     /// symbols that are in the alphabet but represent nonsensical encodings.
37     InvalidLastSymbol(usize, u8),
38 }
39 
40 impl fmt::Display for DecodeError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result41     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
42         match *self {
43             DecodeError::InvalidByte(index, byte) => {
44                 write!(f, "Invalid byte {}, offset {}.", byte, index)
45             }
46             DecodeError::InvalidLength => write!(f, "Encoded text cannot have a 6-bit remainder."),
47             DecodeError::InvalidLastSymbol(index, byte) => {
48                 write!(f, "Invalid last symbol {}, offset {}.", byte, index)
49             }
50         }
51     }
52 }
53 
54 #[cfg(any(feature = "std", test))]
55 impl error::Error for DecodeError {
description(&self) -> &str56     fn description(&self) -> &str {
57         match *self {
58             DecodeError::InvalidByte(_, _) => "invalid byte",
59             DecodeError::InvalidLength => "invalid length",
60             DecodeError::InvalidLastSymbol(_, _) => "invalid last symbol",
61         }
62     }
63 
cause(&self) -> Option<&dyn error::Error>64     fn cause(&self) -> Option<&dyn error::Error> {
65         None
66     }
67 }
68 
69 ///Decode from string reference as octets.
70 ///Returns a Result containing a Vec<u8>.
71 ///Convenience `decode_config(input, base64::STANDARD);`.
72 ///
73 ///# Example
74 ///
75 ///```rust
76 ///extern crate base64;
77 ///
78 ///fn main() {
79 ///    let bytes = base64::decode("aGVsbG8gd29ybGQ=").unwrap();
80 ///    println!("{:?}", bytes);
81 ///}
82 ///```
83 #[cfg(any(feature = "alloc", feature = "std", test))]
decode<T: AsRef<[u8]>>(input: T) -> Result<Vec<u8>, DecodeError>84 pub fn decode<T: AsRef<[u8]>>(input: T) -> Result<Vec<u8>, DecodeError> {
85     decode_config(input, STANDARD)
86 }
87 
88 ///Decode from string reference as octets.
89 ///Returns a Result containing a Vec<u8>.
90 ///
91 ///# Example
92 ///
93 ///```rust
94 ///extern crate base64;
95 ///
96 ///fn main() {
97 ///    let bytes = base64::decode_config("aGVsbG8gd29ybGR+Cg==", base64::STANDARD).unwrap();
98 ///    println!("{:?}", bytes);
99 ///
100 ///    let bytes_url = base64::decode_config("aGVsbG8gaW50ZXJuZXR-Cg==", base64::URL_SAFE).unwrap();
101 ///    println!("{:?}", bytes_url);
102 ///}
103 ///```
104 #[cfg(any(feature = "alloc", feature = "std", test))]
decode_config<T: AsRef<[u8]>>(input: T, config: Config) -> Result<Vec<u8>, DecodeError>105 pub fn decode_config<T: AsRef<[u8]>>(input: T, config: Config) -> Result<Vec<u8>, DecodeError> {
106     let mut buffer = Vec::<u8>::with_capacity(input.as_ref().len() * 4 / 3);
107 
108     decode_config_buf(input, config, &mut buffer).map(|_| buffer)
109 }
110 
111 ///Decode from string reference as octets.
112 ///Writes into the supplied buffer to avoid allocation.
113 ///Returns a Result containing an empty tuple, aka ().
114 ///
115 ///# Example
116 ///
117 ///```rust
118 ///extern crate base64;
119 ///
120 ///fn main() {
121 ///    let mut buffer = Vec::<u8>::new();
122 ///    base64::decode_config_buf("aGVsbG8gd29ybGR+Cg==", base64::STANDARD, &mut buffer).unwrap();
123 ///    println!("{:?}", buffer);
124 ///
125 ///    buffer.clear();
126 ///
127 ///    base64::decode_config_buf("aGVsbG8gaW50ZXJuZXR-Cg==", base64::URL_SAFE, &mut buffer)
128 ///        .unwrap();
129 ///    println!("{:?}", buffer);
130 ///}
131 ///```
132 #[cfg(any(feature = "alloc", feature = "std", test))]
decode_config_buf<T: AsRef<[u8]>>( input: T, config: Config, buffer: &mut Vec<u8>, ) -> Result<(), DecodeError>133 pub fn decode_config_buf<T: AsRef<[u8]>>(
134     input: T,
135     config: Config,
136     buffer: &mut Vec<u8>,
137 ) -> Result<(), DecodeError> {
138     let input_bytes = input.as_ref();
139 
140     let starting_output_len = buffer.len();
141 
142     let num_chunks = num_chunks(input_bytes);
143     let decoded_len_estimate = num_chunks
144         .checked_mul(DECODED_CHUNK_LEN)
145         .and_then(|p| p.checked_add(starting_output_len))
146         .expect("Overflow when calculating output buffer length");
147     buffer.resize(decoded_len_estimate, 0);
148 
149     let bytes_written;
150     {
151         let buffer_slice = &mut buffer.as_mut_slice()[starting_output_len..];
152         bytes_written = decode_helper(input_bytes, num_chunks, config, buffer_slice)?;
153     }
154 
155     buffer.truncate(starting_output_len + bytes_written);
156 
157     Ok(())
158 }
159 
160 /// Decode the input into the provided output slice.
161 ///
162 /// This will not write any bytes past exactly what is decoded (no stray garbage bytes at the end).
163 ///
164 /// If you don't know ahead of time what the decoded length should be, size your buffer with a
165 /// conservative estimate for the decoded length of an input: 3 bytes of output for every 4 bytes of
166 /// input, rounded up, or in other words `(input_len + 3) / 4 * 3`.
167 ///
168 /// If the slice is not large enough, this will panic.
decode_config_slice<T: AsRef<[u8]>>( input: T, config: Config, output: &mut [u8], ) -> Result<usize, DecodeError>169 pub fn decode_config_slice<T: AsRef<[u8]>>(
170     input: T,
171     config: Config,
172     output: &mut [u8],
173 ) -> Result<usize, DecodeError> {
174     let input_bytes = input.as_ref();
175 
176     decode_helper(input_bytes, num_chunks(input_bytes), config, output)
177 }
178 
179 /// Return the number of input chunks (including a possibly partial final chunk) in the input
num_chunks(input: &[u8]) -> usize180 fn num_chunks(input: &[u8]) -> usize {
181     input
182         .len()
183         .checked_add(INPUT_CHUNK_LEN - 1)
184         .expect("Overflow when calculating number of chunks in input")
185         / INPUT_CHUNK_LEN
186 }
187 
188 /// Helper to avoid duplicating num_chunks calculation, which is costly on short inputs.
189 /// Returns the number of bytes written, or an error.
190 // We're on the fragile edge of compiler heuristics here. If this is not inlined, slow. If this is
191 // inlined(always), a different slow. plain ol' inline makes the benchmarks happiest at the moment,
192 // but this is fragile and the best setting changes with only minor code modifications.
193 #[inline]
decode_helper( input: &[u8], num_chunks: usize, config: Config, output: &mut [u8], ) -> Result<usize, DecodeError>194 fn decode_helper(
195     input: &[u8],
196     num_chunks: usize,
197     config: Config,
198     output: &mut [u8],
199 ) -> Result<usize, DecodeError> {
200     let char_set = config.char_set;
201     let decode_table = char_set.decode_table();
202 
203     let remainder_len = input.len() % INPUT_CHUNK_LEN;
204 
205     // Because the fast decode loop writes in groups of 8 bytes (unrolled to
206     // CHUNKS_PER_FAST_LOOP_BLOCK times 8 bytes, where possible) and outputs 8 bytes at a time (of
207     // which only 6 are valid data), we need to be sure that we stop using the fast decode loop
208     // soon enough that there will always be 2 more bytes of valid data written after that loop.
209     let trailing_bytes_to_skip = match remainder_len {
210         // if input is a multiple of the chunk size, ignore the last chunk as it may have padding,
211         // and the fast decode logic cannot handle padding
212         0 => INPUT_CHUNK_LEN,
213         // 1 and 5 trailing bytes are illegal: can't decode 6 bits of input into a byte
214         1 | 5 => return Err(DecodeError::InvalidLength),
215         // This will decode to one output byte, which isn't enough to overwrite the 2 extra bytes
216         // written by the fast decode loop. So, we have to ignore both these 2 bytes and the
217         // previous chunk.
218         2 => INPUT_CHUNK_LEN + 2,
219         // If this is 3 unpadded chars, then it would actually decode to 2 bytes. However, if this
220         // is an erroneous 2 chars + 1 pad char that would decode to 1 byte, then it should fail
221         // with an error, not panic from going past the bounds of the output slice, so we let it
222         // use stage 3 + 4.
223         3 => INPUT_CHUNK_LEN + 3,
224         // This can also decode to one output byte because it may be 2 input chars + 2 padding
225         // chars, which would decode to 1 byte.
226         4 => INPUT_CHUNK_LEN + 4,
227         // Everything else is a legal decode len (given that we don't require padding), and will
228         // decode to at least 2 bytes of output.
229         _ => remainder_len,
230     };
231 
232     // rounded up to include partial chunks
233     let mut remaining_chunks = num_chunks;
234 
235     let mut input_index = 0;
236     let mut output_index = 0;
237 
238     {
239         let length_of_fast_decode_chunks = input.len().saturating_sub(trailing_bytes_to_skip);
240 
241         // Fast loop, stage 1
242         // manual unroll to CHUNKS_PER_FAST_LOOP_BLOCK of u64s to amortize slice bounds checks
243         if let Some(max_start_index) = length_of_fast_decode_chunks.checked_sub(INPUT_BLOCK_LEN) {
244             while input_index <= max_start_index {
245                 let input_slice = &input[input_index..(input_index + INPUT_BLOCK_LEN)];
246                 let output_slice = &mut output[output_index..(output_index + DECODED_BLOCK_LEN)];
247 
248                 decode_chunk(
249                     &input_slice[0..],
250                     input_index,
251                     decode_table,
252                     &mut output_slice[0..],
253                 )?;
254                 decode_chunk(
255                     &input_slice[8..],
256                     input_index + 8,
257                     decode_table,
258                     &mut output_slice[6..],
259                 )?;
260                 decode_chunk(
261                     &input_slice[16..],
262                     input_index + 16,
263                     decode_table,
264                     &mut output_slice[12..],
265                 )?;
266                 decode_chunk(
267                     &input_slice[24..],
268                     input_index + 24,
269                     decode_table,
270                     &mut output_slice[18..],
271                 )?;
272 
273                 input_index += INPUT_BLOCK_LEN;
274                 output_index += DECODED_BLOCK_LEN - DECODED_CHUNK_SUFFIX;
275                 remaining_chunks -= CHUNKS_PER_FAST_LOOP_BLOCK;
276             }
277         }
278 
279         // Fast loop, stage 2 (aka still pretty fast loop)
280         // 8 bytes at a time for whatever we didn't do in stage 1.
281         if let Some(max_start_index) = length_of_fast_decode_chunks.checked_sub(INPUT_CHUNK_LEN) {
282             while input_index < max_start_index {
283                 decode_chunk(
284                     &input[input_index..(input_index + INPUT_CHUNK_LEN)],
285                     input_index,
286                     decode_table,
287                     &mut output
288                         [output_index..(output_index + DECODED_CHUNK_LEN + DECODED_CHUNK_SUFFIX)],
289                 )?;
290 
291                 output_index += DECODED_CHUNK_LEN;
292                 input_index += INPUT_CHUNK_LEN;
293                 remaining_chunks -= 1;
294             }
295         }
296     }
297 
298     // Stage 3
299     // If input length was such that a chunk had to be deferred until after the fast loop
300     // because decoding it would have produced 2 trailing bytes that wouldn't then be
301     // overwritten, we decode that chunk here. This way is slower but doesn't write the 2
302     // trailing bytes.
303     // However, we still need to avoid the last chunk (partial or complete) because it could
304     // have padding, so we always do 1 fewer to avoid the last chunk.
305     for _ in 1..remaining_chunks {
306         decode_chunk_precise(
307             &input[input_index..],
308             input_index,
309             decode_table,
310             &mut output[output_index..(output_index + DECODED_CHUNK_LEN)],
311         )?;
312 
313         input_index += INPUT_CHUNK_LEN;
314         output_index += DECODED_CHUNK_LEN;
315     }
316 
317     // always have one more (possibly partial) block of 8 input
318     debug_assert!(input.len() - input_index > 1 || input.is_empty());
319     debug_assert!(input.len() - input_index <= 8);
320 
321     // Stage 4
322     // Finally, decode any leftovers that aren't a complete input block of 8 bytes.
323     // Use a u64 as a stack-resident 8 byte buffer.
324     let mut leftover_bits: u64 = 0;
325     let mut morsels_in_leftover = 0;
326     let mut padding_bytes = 0;
327     let mut first_padding_index: usize = 0;
328     let mut last_symbol = 0_u8;
329     let start_of_leftovers = input_index;
330     for (i, b) in input[start_of_leftovers..].iter().enumerate() {
331         // '=' padding
332         if *b == 0x3D {
333             // There can be bad padding in a few ways:
334             // 1 - Padding with non-padding characters after it
335             // 2 - Padding after zero or one non-padding characters before it
336             //     in the current quad.
337             // 3 - More than two characters of padding. If 3 or 4 padding chars
338             //     are in the same quad, that implies it will be caught by #2.
339             //     If it spreads from one quad to another, it will be caught by
340             //     #2 in the second quad.
341 
342             if i % 4 < 2 {
343                 // Check for case #2.
344                 let bad_padding_index = start_of_leftovers
345                     + if padding_bytes > 0 {
346                         // If we've already seen padding, report the first padding index.
347                         // This is to be consistent with the faster logic above: it will report an
348                         // error on the first padding character (since it doesn't expect to see
349                         // anything but actual encoded data).
350                         first_padding_index
351                     } else {
352                         // haven't seen padding before, just use where we are now
353                         i
354                     };
355                 return Err(DecodeError::InvalidByte(bad_padding_index, *b));
356             }
357 
358             if padding_bytes == 0 {
359                 first_padding_index = i;
360             }
361 
362             padding_bytes += 1;
363             continue;
364         }
365 
366         // Check for case #1.
367         // To make '=' handling consistent with the main loop, don't allow
368         // non-suffix '=' in trailing chunk either. Report error as first
369         // erroneous padding.
370         if padding_bytes > 0 {
371             return Err(DecodeError::InvalidByte(
372                 start_of_leftovers + first_padding_index,
373                 0x3D,
374             ));
375         }
376         last_symbol = *b;
377 
378         // can use up to 8 * 6 = 48 bits of the u64, if last chunk has no padding.
379         // To minimize shifts, pack the leftovers from left to right.
380         let shift = 64 - (morsels_in_leftover + 1) * 6;
381         // tables are all 256 elements, lookup with a u8 index always succeeds
382         let morsel = decode_table[*b as usize];
383         if morsel == tables::INVALID_VALUE {
384             return Err(DecodeError::InvalidByte(start_of_leftovers + i, *b));
385         }
386 
387         leftover_bits |= (morsel as u64) << shift;
388         morsels_in_leftover += 1;
389     }
390 
391     let leftover_bits_ready_to_append = match morsels_in_leftover {
392         0 => 0,
393         2 => 8,
394         3 => 16,
395         4 => 24,
396         6 => 32,
397         7 => 40,
398         8 => 48,
399         _ => unreachable!(
400             "Impossible: must only have 0 to 8 input bytes in last chunk, with no invalid lengths"
401         ),
402     };
403 
404     // if there are bits set outside the bits we care about, last symbol encodes trailing bits that
405     // will not be included in the output
406     let mask = !0 >> leftover_bits_ready_to_append;
407     if !config.decode_allow_trailing_bits && (leftover_bits & mask) != 0 {
408         // last morsel is at `morsels_in_leftover` - 1
409         return Err(DecodeError::InvalidLastSymbol(
410             start_of_leftovers + morsels_in_leftover - 1,
411             last_symbol,
412         ));
413     }
414 
415     let mut leftover_bits_appended_to_buf = 0;
416     while leftover_bits_appended_to_buf < leftover_bits_ready_to_append {
417         // `as` simply truncates the higher bits, which is what we want here
418         let selected_bits = (leftover_bits >> (56 - leftover_bits_appended_to_buf)) as u8;
419         output[output_index] = selected_bits;
420         output_index += 1;
421 
422         leftover_bits_appended_to_buf += 8;
423     }
424 
425     Ok(output_index)
426 }
427 
428 #[inline]
write_u64(output: &mut [u8], value: u64)429 fn write_u64(output: &mut [u8], value: u64) {
430     output[..8].copy_from_slice(&value.to_be_bytes());
431 }
432 
433 /// Decode 8 bytes of input into 6 bytes of output. 8 bytes of output will be written, but only the
434 /// first 6 of those contain meaningful data.
435 ///
436 /// `input` is the bytes to decode, of which the first 8 bytes will be processed.
437 /// `index_at_start_of_input` is the offset in the overall input (used for reporting errors
438 /// accurately)
439 /// `decode_table` is the lookup table for the particular base64 alphabet.
440 /// `output` will have its first 8 bytes overwritten, of which only the first 6 are valid decoded
441 /// data.
442 // yes, really inline (worth 30-50% speedup)
443 #[inline(always)]
decode_chunk( input: &[u8], index_at_start_of_input: usize, decode_table: &[u8; 256], output: &mut [u8], ) -> Result<(), DecodeError>444 fn decode_chunk(
445     input: &[u8],
446     index_at_start_of_input: usize,
447     decode_table: &[u8; 256],
448     output: &mut [u8],
449 ) -> Result<(), DecodeError> {
450     let mut accum: u64;
451 
452     let morsel = decode_table[input[0] as usize];
453     if morsel == tables::INVALID_VALUE {
454         return Err(DecodeError::InvalidByte(index_at_start_of_input, input[0]));
455     }
456     accum = (morsel as u64) << 58;
457 
458     let morsel = decode_table[input[1] as usize];
459     if morsel == tables::INVALID_VALUE {
460         return Err(DecodeError::InvalidByte(
461             index_at_start_of_input + 1,
462             input[1],
463         ));
464     }
465     accum |= (morsel as u64) << 52;
466 
467     let morsel = decode_table[input[2] as usize];
468     if morsel == tables::INVALID_VALUE {
469         return Err(DecodeError::InvalidByte(
470             index_at_start_of_input + 2,
471             input[2],
472         ));
473     }
474     accum |= (morsel as u64) << 46;
475 
476     let morsel = decode_table[input[3] as usize];
477     if morsel == tables::INVALID_VALUE {
478         return Err(DecodeError::InvalidByte(
479             index_at_start_of_input + 3,
480             input[3],
481         ));
482     }
483     accum |= (morsel as u64) << 40;
484 
485     let morsel = decode_table[input[4] as usize];
486     if morsel == tables::INVALID_VALUE {
487         return Err(DecodeError::InvalidByte(
488             index_at_start_of_input + 4,
489             input[4],
490         ));
491     }
492     accum |= (morsel as u64) << 34;
493 
494     let morsel = decode_table[input[5] as usize];
495     if morsel == tables::INVALID_VALUE {
496         return Err(DecodeError::InvalidByte(
497             index_at_start_of_input + 5,
498             input[5],
499         ));
500     }
501     accum |= (morsel as u64) << 28;
502 
503     let morsel = decode_table[input[6] as usize];
504     if morsel == tables::INVALID_VALUE {
505         return Err(DecodeError::InvalidByte(
506             index_at_start_of_input + 6,
507             input[6],
508         ));
509     }
510     accum |= (morsel as u64) << 22;
511 
512     let morsel = decode_table[input[7] as usize];
513     if morsel == tables::INVALID_VALUE {
514         return Err(DecodeError::InvalidByte(
515             index_at_start_of_input + 7,
516             input[7],
517         ));
518     }
519     accum |= (morsel as u64) << 16;
520 
521     write_u64(output, accum);
522 
523     Ok(())
524 }
525 
526 /// Decode an 8-byte chunk, but only write the 6 bytes actually decoded instead of including 2
527 /// trailing garbage bytes.
528 #[inline]
decode_chunk_precise( input: &[u8], index_at_start_of_input: usize, decode_table: &[u8; 256], output: &mut [u8], ) -> Result<(), DecodeError>529 fn decode_chunk_precise(
530     input: &[u8],
531     index_at_start_of_input: usize,
532     decode_table: &[u8; 256],
533     output: &mut [u8],
534 ) -> Result<(), DecodeError> {
535     let mut tmp_buf = [0_u8; 8];
536 
537     decode_chunk(
538         input,
539         index_at_start_of_input,
540         decode_table,
541         &mut tmp_buf[..],
542     )?;
543 
544     output[0..6].copy_from_slice(&tmp_buf[0..6]);
545 
546     Ok(())
547 }
548 
549 #[cfg(test)]
550 mod tests {
551     use super::*;
552     use crate::{
553         encode::encode_config_buf,
554         encode::encode_config_slice,
555         tests::{assert_encode_sanity, random_config},
556     };
557 
558     use rand::{
559         distributions::{Distribution, Uniform},
560         FromEntropy, Rng,
561     };
562 
563     #[test]
decode_chunk_precise_writes_only_6_bytes()564     fn decode_chunk_precise_writes_only_6_bytes() {
565         let input = b"Zm9vYmFy"; // "foobar"
566         let mut output = [0_u8, 1, 2, 3, 4, 5, 6, 7];
567         decode_chunk_precise(&input[..], 0, tables::STANDARD_DECODE, &mut output).unwrap();
568         assert_eq!(&vec![b'f', b'o', b'o', b'b', b'a', b'r', 6, 7], &output);
569     }
570 
571     #[test]
decode_chunk_writes_8_bytes()572     fn decode_chunk_writes_8_bytes() {
573         let input = b"Zm9vYmFy"; // "foobar"
574         let mut output = [0_u8, 1, 2, 3, 4, 5, 6, 7];
575         decode_chunk(&input[..], 0, tables::STANDARD_DECODE, &mut output).unwrap();
576         assert_eq!(&vec![b'f', b'o', b'o', b'b', b'a', b'r', 0, 0], &output);
577     }
578 
579     #[test]
decode_into_nonempty_vec_doesnt_clobber_existing_prefix()580     fn decode_into_nonempty_vec_doesnt_clobber_existing_prefix() {
581         let mut orig_data = Vec::new();
582         let mut encoded_data = String::new();
583         let mut decoded_with_prefix = Vec::new();
584         let mut decoded_without_prefix = Vec::new();
585         let mut prefix = Vec::new();
586 
587         let prefix_len_range = Uniform::new(0, 1000);
588         let input_len_range = Uniform::new(0, 1000);
589 
590         let mut rng = rand::rngs::SmallRng::from_entropy();
591 
592         for _ in 0..10_000 {
593             orig_data.clear();
594             encoded_data.clear();
595             decoded_with_prefix.clear();
596             decoded_without_prefix.clear();
597             prefix.clear();
598 
599             let input_len = input_len_range.sample(&mut rng);
600 
601             for _ in 0..input_len {
602                 orig_data.push(rng.gen());
603             }
604 
605             let config = random_config(&mut rng);
606             encode_config_buf(&orig_data, config, &mut encoded_data);
607             assert_encode_sanity(&encoded_data, config, input_len);
608 
609             let prefix_len = prefix_len_range.sample(&mut rng);
610 
611             // fill the buf with a prefix
612             for _ in 0..prefix_len {
613                 prefix.push(rng.gen());
614             }
615 
616             decoded_with_prefix.resize(prefix_len, 0);
617             decoded_with_prefix.copy_from_slice(&prefix);
618 
619             // decode into the non-empty buf
620             decode_config_buf(&encoded_data, config, &mut decoded_with_prefix).unwrap();
621             // also decode into the empty buf
622             decode_config_buf(&encoded_data, config, &mut decoded_without_prefix).unwrap();
623 
624             assert_eq!(
625                 prefix_len + decoded_without_prefix.len(),
626                 decoded_with_prefix.len()
627             );
628             assert_eq!(orig_data, decoded_without_prefix);
629 
630             // append plain decode onto prefix
631             prefix.append(&mut decoded_without_prefix);
632 
633             assert_eq!(prefix, decoded_with_prefix);
634         }
635     }
636 
637     #[test]
decode_into_slice_doesnt_clobber_existing_prefix_or_suffix()638     fn decode_into_slice_doesnt_clobber_existing_prefix_or_suffix() {
639         let mut orig_data = Vec::new();
640         let mut encoded_data = String::new();
641         let mut decode_buf = Vec::new();
642         let mut decode_buf_copy: Vec<u8> = Vec::new();
643 
644         let input_len_range = Uniform::new(0, 1000);
645 
646         let mut rng = rand::rngs::SmallRng::from_entropy();
647 
648         for _ in 0..10_000 {
649             orig_data.clear();
650             encoded_data.clear();
651             decode_buf.clear();
652             decode_buf_copy.clear();
653 
654             let input_len = input_len_range.sample(&mut rng);
655 
656             for _ in 0..input_len {
657                 orig_data.push(rng.gen());
658             }
659 
660             let config = random_config(&mut rng);
661             encode_config_buf(&orig_data, config, &mut encoded_data);
662             assert_encode_sanity(&encoded_data, config, input_len);
663 
664             // fill the buffer with random garbage, long enough to have some room before and after
665             for _ in 0..5000 {
666                 decode_buf.push(rng.gen());
667             }
668 
669             // keep a copy for later comparison
670             decode_buf_copy.extend(decode_buf.iter());
671 
672             let offset = 1000;
673 
674             // decode into the non-empty buf
675             let decode_bytes_written =
676                 decode_config_slice(&encoded_data, config, &mut decode_buf[offset..]).unwrap();
677 
678             assert_eq!(orig_data.len(), decode_bytes_written);
679             assert_eq!(
680                 orig_data,
681                 &decode_buf[offset..(offset + decode_bytes_written)]
682             );
683             assert_eq!(&decode_buf_copy[0..offset], &decode_buf[0..offset]);
684             assert_eq!(
685                 &decode_buf_copy[offset + decode_bytes_written..],
686                 &decode_buf[offset + decode_bytes_written..]
687             );
688         }
689     }
690 
691     #[test]
decode_into_slice_fits_in_precisely_sized_slice()692     fn decode_into_slice_fits_in_precisely_sized_slice() {
693         let mut orig_data = Vec::new();
694         let mut encoded_data = String::new();
695         let mut decode_buf = Vec::new();
696 
697         let input_len_range = Uniform::new(0, 1000);
698 
699         let mut rng = rand::rngs::SmallRng::from_entropy();
700 
701         for _ in 0..10_000 {
702             orig_data.clear();
703             encoded_data.clear();
704             decode_buf.clear();
705 
706             let input_len = input_len_range.sample(&mut rng);
707 
708             for _ in 0..input_len {
709                 orig_data.push(rng.gen());
710             }
711 
712             let config = random_config(&mut rng);
713             encode_config_buf(&orig_data, config, &mut encoded_data);
714             assert_encode_sanity(&encoded_data, config, input_len);
715 
716             decode_buf.resize(input_len, 0);
717 
718             // decode into the non-empty buf
719             let decode_bytes_written =
720                 decode_config_slice(&encoded_data, config, &mut decode_buf[..]).unwrap();
721 
722             assert_eq!(orig_data.len(), decode_bytes_written);
723             assert_eq!(orig_data, decode_buf);
724         }
725     }
726 
727     #[test]
detect_invalid_last_symbol_two_bytes()728     fn detect_invalid_last_symbol_two_bytes() {
729         let decode =
730             |input, forgiving| decode_config(input, STANDARD.decode_allow_trailing_bits(forgiving));
731 
732         // example from https://github.com/marshallpierce/rust-base64/issues/75
733         assert!(decode("iYU=", false).is_ok());
734         // trailing 01
735         assert_eq!(
736             Err(DecodeError::InvalidLastSymbol(2, b'V')),
737             decode("iYV=", false)
738         );
739         assert_eq!(Ok(vec![137, 133]), decode("iYV=", true));
740         // trailing 10
741         assert_eq!(
742             Err(DecodeError::InvalidLastSymbol(2, b'W')),
743             decode("iYW=", false)
744         );
745         assert_eq!(Ok(vec![137, 133]), decode("iYV=", true));
746         // trailing 11
747         assert_eq!(
748             Err(DecodeError::InvalidLastSymbol(2, b'X')),
749             decode("iYX=", false)
750         );
751         assert_eq!(Ok(vec![137, 133]), decode("iYV=", true));
752 
753         // also works when there are 2 quads in the last block
754         assert_eq!(
755             Err(DecodeError::InvalidLastSymbol(6, b'X')),
756             decode("AAAAiYX=", false)
757         );
758         assert_eq!(Ok(vec![0, 0, 0, 137, 133]), decode("AAAAiYX=", true));
759     }
760 
761     #[test]
detect_invalid_last_symbol_one_byte()762     fn detect_invalid_last_symbol_one_byte() {
763         // 0xFF -> "/w==", so all letters > w, 0-9, and '+', '/' should get InvalidLastSymbol
764 
765         assert!(decode("/w==").is_ok());
766         // trailing 01
767         assert_eq!(Err(DecodeError::InvalidLastSymbol(1, b'x')), decode("/x=="));
768         assert_eq!(Err(DecodeError::InvalidLastSymbol(1, b'z')), decode("/z=="));
769         assert_eq!(Err(DecodeError::InvalidLastSymbol(1, b'0')), decode("/0=="));
770         assert_eq!(Err(DecodeError::InvalidLastSymbol(1, b'9')), decode("/9=="));
771         assert_eq!(Err(DecodeError::InvalidLastSymbol(1, b'+')), decode("/+=="));
772         assert_eq!(Err(DecodeError::InvalidLastSymbol(1, b'/')), decode("//=="));
773 
774         // also works when there are 2 quads in the last block
775         assert_eq!(
776             Err(DecodeError::InvalidLastSymbol(5, b'x')),
777             decode("AAAA/x==")
778         );
779     }
780 
781     #[test]
detect_invalid_last_symbol_every_possible_three_symbols()782     fn detect_invalid_last_symbol_every_possible_three_symbols() {
783         let mut base64_to_bytes = ::std::collections::HashMap::new();
784 
785         let mut bytes = [0_u8; 2];
786         for b1 in 0_u16..256 {
787             bytes[0] = b1 as u8;
788             for b2 in 0_u16..256 {
789                 bytes[1] = b2 as u8;
790                 let mut b64 = vec![0_u8; 4];
791                 assert_eq!(4, encode_config_slice(&bytes, STANDARD, &mut b64[..]));
792                 let mut v = ::std::vec::Vec::with_capacity(2);
793                 v.extend_from_slice(&bytes[..]);
794 
795                 assert!(base64_to_bytes.insert(b64, v).is_none());
796             }
797         }
798 
799         // every possible combination of symbols must either decode to 2 bytes or get InvalidLastSymbol
800 
801         let mut symbols = [0_u8; 4];
802         for &s1 in STANDARD.char_set.encode_table().iter() {
803             symbols[0] = s1;
804             for &s2 in STANDARD.char_set.encode_table().iter() {
805                 symbols[1] = s2;
806                 for &s3 in STANDARD.char_set.encode_table().iter() {
807                     symbols[2] = s3;
808                     symbols[3] = b'=';
809 
810                     match base64_to_bytes.get(&symbols[..]) {
811                         Some(bytes) => {
812                             assert_eq!(Ok(bytes.to_vec()), decode_config(&symbols, STANDARD))
813                         }
814                         None => assert_eq!(
815                             Err(DecodeError::InvalidLastSymbol(2, s3)),
816                             decode_config(&symbols[..], STANDARD)
817                         ),
818                     }
819                 }
820             }
821         }
822     }
823 
824     #[test]
detect_invalid_last_symbol_every_possible_two_symbols()825     fn detect_invalid_last_symbol_every_possible_two_symbols() {
826         let mut base64_to_bytes = ::std::collections::HashMap::new();
827 
828         for b in 0_u16..256 {
829             let mut b64 = vec![0_u8; 4];
830             assert_eq!(4, encode_config_slice(&[b as u8], STANDARD, &mut b64[..]));
831             let mut v = ::std::vec::Vec::with_capacity(1);
832             v.push(b as u8);
833 
834             assert!(base64_to_bytes.insert(b64, v).is_none());
835         }
836 
837         // every possible combination of symbols must either decode to 1 byte or get InvalidLastSymbol
838 
839         let mut symbols = [0_u8; 4];
840         for &s1 in STANDARD.char_set.encode_table().iter() {
841             symbols[0] = s1;
842             for &s2 in STANDARD.char_set.encode_table().iter() {
843                 symbols[1] = s2;
844                 symbols[2] = b'=';
845                 symbols[3] = b'=';
846 
847                 match base64_to_bytes.get(&symbols[..]) {
848                     Some(bytes) => {
849                         assert_eq!(Ok(bytes.to_vec()), decode_config(&symbols, STANDARD))
850                     }
851                     None => assert_eq!(
852                         Err(DecodeError::InvalidLastSymbol(1, s2)),
853                         decode_config(&symbols[..], STANDARD)
854                     ),
855                 }
856             }
857         }
858     }
859 
860     #[test]
decode_imap()861     fn decode_imap() {
862         assert_eq!(
863             decode_config(b"+,,+", crate::IMAP_MUTF7),
864             decode_config(b"+//+", crate::STANDARD_NO_PAD)
865         );
866     }
867 }
868