1use crate::engine::{general_purpose::STANDARD, DecodeEstimate, Engine};
2#[cfg(any(feature = "alloc", test))]
3use alloc::vec::Vec;
4use core::fmt;
5#[cfg(any(feature = "std", test))]
6use std::error;
7
8/// Errors that can occur while decoding.
9#[derive(Clone, Debug, PartialEq, Eq)]
10pub enum DecodeError {
11 /// An invalid byte was found in the input. The offset and offending byte are provided.
12 /// Padding characters (`=`) interspersed in the encoded form will be treated as invalid bytes.
13 InvalidByte(usize, u8),
14 /// The length of the input is invalid.
15 /// A typical cause of this is stray trailing whitespace or other separator bytes.
16 /// In the case where excess trailing bytes have produced an invalid length *and* the last byte
17 /// is also an invalid base64 symbol (as would be the case for whitespace, etc), `InvalidByte`
18 /// will be emitted instead of `InvalidLength` to make the issue easier to debug.
19 InvalidLength,
20 /// The last non-padding input symbol's encoded 6 bits have nonzero bits that will be discarded.
21 /// This is indicative of corrupted or truncated Base64.
22 /// Unlike `InvalidByte`, which reports symbols that aren't in the alphabet, this error is for
23 /// symbols that are in the alphabet but represent nonsensical encodings.
24 InvalidLastSymbol(usize, u8),
25 /// The nature of the padding was not as configured: absent or incorrect when it must be
26 /// canonical, or present when it must be absent, etc.
27 InvalidPadding,
28}
29
30impl fmt::Display for DecodeError {
31 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
32 match *self {
33 Self::InvalidByte(index: usize, byte: u8) => write!(f, "Invalid byte {}, offset {}.", byte, index),
34 Self::InvalidLength => write!(f, "Encoded text cannot have a 6-bit remainder."),
35 Self::InvalidLastSymbol(index: usize, byte: u8) => {
36 write!(f, "Invalid last symbol {}, offset {}.", byte, index)
37 }
38 Self::InvalidPadding => write!(f, "Invalid padding"),
39 }
40 }
41}
42
43#[cfg(any(feature = "std", test))]
44impl error::Error for DecodeError {}
45
46/// Errors that can occur while decoding into a slice.
47#[derive(Clone, Debug, PartialEq, Eq)]
48pub enum DecodeSliceError {
49 /// A [DecodeError] occurred
50 DecodeError(DecodeError),
51 /// The provided slice _may_ be too small.
52 ///
53 /// The check is conservative (assumes the last triplet of output bytes will all be needed).
54 OutputSliceTooSmall,
55}
56
57impl fmt::Display for DecodeSliceError {
58 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59 match self {
60 Self::DecodeError(e: &DecodeError) => write!(f, "DecodeError: {}", e),
61 Self::OutputSliceTooSmall => write!(f, "Output slice too small"),
62 }
63 }
64}
65
66#[cfg(any(feature = "std", test))]
67impl error::Error for DecodeSliceError {
68 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
69 match self {
70 DecodeSliceError::DecodeError(e: &DecodeError) => Some(e),
71 DecodeSliceError::OutputSliceTooSmall => None,
72 }
73 }
74}
75
76impl From<DecodeError> for DecodeSliceError {
77 fn from(e: DecodeError) -> Self {
78 DecodeSliceError::DecodeError(e)
79 }
80}
81
82/// Decode base64 using the [`STANDARD` engine](STANDARD).
83///
84/// See [Engine::decode].
85#[deprecated(since = "0.21.0", note = "Use Engine::decode")]
86#[cfg(any(feature = "alloc", test))]
87pub fn decode<T: AsRef<[u8]>>(input: T) -> Result<Vec<u8>, DecodeError> {
88 STANDARD.decode(input)
89}
90
91/// Decode from string reference as octets using the specified [Engine].
92///
93/// See [Engine::decode].
94///Returns a `Result` containing a `Vec<u8>`.
95#[deprecated(since = "0.21.0", note = "Use Engine::decode")]
96#[cfg(any(feature = "alloc", test))]
97pub fn decode_engine<E: Engine, T: AsRef<[u8]>>(
98 input: T,
99 engine: &E,
100) -> Result<Vec<u8>, DecodeError> {
101 engine.decode(input)
102}
103
104/// Decode from string reference as octets.
105///
106/// See [Engine::decode_vec].
107#[cfg(any(feature = "alloc", test))]
108#[deprecated(since = "0.21.0", note = "Use Engine::decode_vec")]
109pub fn decode_engine_vec<E: Engine, T: AsRef<[u8]>>(
110 input: T,
111 buffer: &mut Vec<u8>,
112 engine: &E,
113) -> Result<(), DecodeError> {
114 engine.decode_vec(input, buffer)
115}
116
117/// Decode the input into the provided output slice.
118///
119/// See [Engine::decode_slice].
120#[deprecated(since = "0.21.0", note = "Use Engine::decode_slice")]
121pub fn decode_engine_slice<E: Engine, T: AsRef<[u8]>>(
122 input: T,
123 output: &mut [u8],
124 engine: &E,
125) -> Result<usize, DecodeSliceError> {
126 engine.decode_slice(input, output)
127}
128
129/// Returns a conservative estimate of the decoded size of `encoded_len` base64 symbols (rounded up
130/// to the next group of 3 decoded bytes).
131///
132/// The resulting length will be a safe choice for the size of a decode buffer, but may have up to
133/// 2 trailing bytes that won't end up being needed.
134///
135/// # Examples
136///
137/// ```
138/// use base64::decoded_len_estimate;
139///
140/// assert_eq!(3, decoded_len_estimate(1));
141/// assert_eq!(3, decoded_len_estimate(2));
142/// assert_eq!(3, decoded_len_estimate(3));
143/// assert_eq!(3, decoded_len_estimate(4));
144/// // start of the next quad of encoded symbols
145/// assert_eq!(6, decoded_len_estimate(5));
146/// ```
147pub fn decoded_len_estimate(encoded_len: usize) -> usize {
148 STANDARD
149 .internal_decoded_len_estimate(input_len:encoded_len)
150 .decoded_len_estimate()
151}
152
153#[cfg(test)]
154mod tests {
155 use super::*;
156 use crate::{
157 alphabet,
158 engine::{general_purpose, Config, GeneralPurpose},
159 tests::{assert_encode_sanity, random_engine},
160 };
161 use rand::{
162 distributions::{Distribution, Uniform},
163 Rng, SeedableRng,
164 };
165
166 #[test]
167 fn decode_into_nonempty_vec_doesnt_clobber_existing_prefix() {
168 let mut orig_data = Vec::new();
169 let mut encoded_data = String::new();
170 let mut decoded_with_prefix = Vec::new();
171 let mut decoded_without_prefix = Vec::new();
172 let mut prefix = Vec::new();
173
174 let prefix_len_range = Uniform::new(0, 1000);
175 let input_len_range = Uniform::new(0, 1000);
176
177 let mut rng = rand::rngs::SmallRng::from_entropy();
178
179 for _ in 0..10_000 {
180 orig_data.clear();
181 encoded_data.clear();
182 decoded_with_prefix.clear();
183 decoded_without_prefix.clear();
184 prefix.clear();
185
186 let input_len = input_len_range.sample(&mut rng);
187
188 for _ in 0..input_len {
189 orig_data.push(rng.gen());
190 }
191
192 let engine = random_engine(&mut rng);
193 engine.encode_string(&orig_data, &mut encoded_data);
194 assert_encode_sanity(&encoded_data, engine.config().encode_padding(), input_len);
195
196 let prefix_len = prefix_len_range.sample(&mut rng);
197
198 // fill the buf with a prefix
199 for _ in 0..prefix_len {
200 prefix.push(rng.gen());
201 }
202
203 decoded_with_prefix.resize(prefix_len, 0);
204 decoded_with_prefix.copy_from_slice(&prefix);
205
206 // decode into the non-empty buf
207 engine
208 .decode_vec(&encoded_data, &mut decoded_with_prefix)
209 .unwrap();
210 // also decode into the empty buf
211 engine
212 .decode_vec(&encoded_data, &mut decoded_without_prefix)
213 .unwrap();
214
215 assert_eq!(
216 prefix_len + decoded_without_prefix.len(),
217 decoded_with_prefix.len()
218 );
219 assert_eq!(orig_data, decoded_without_prefix);
220
221 // append plain decode onto prefix
222 prefix.append(&mut decoded_without_prefix);
223
224 assert_eq!(prefix, decoded_with_prefix);
225 }
226 }
227
228 #[test]
229 fn decode_slice_doesnt_clobber_existing_prefix_or_suffix() {
230 do_decode_slice_doesnt_clobber_existing_prefix_or_suffix(|e, input, output| {
231 e.decode_slice(input, output).unwrap()
232 })
233 }
234
235 #[test]
236 fn decode_slice_unchecked_doesnt_clobber_existing_prefix_or_suffix() {
237 do_decode_slice_doesnt_clobber_existing_prefix_or_suffix(|e, input, output| {
238 e.decode_slice_unchecked(input, output).unwrap()
239 })
240 }
241
242 #[test]
243 fn decode_engine_estimation_works_for_various_lengths() {
244 let engine = GeneralPurpose::new(&alphabet::STANDARD, general_purpose::NO_PAD);
245 for num_prefix_quads in 0..100 {
246 for suffix in &["AA", "AAA", "AAAA"] {
247 let mut prefix = "AAAA".repeat(num_prefix_quads);
248 prefix.push_str(suffix);
249 // make sure no overflow (and thus a panic) occurs
250 let res = engine.decode(prefix);
251 assert!(res.is_ok());
252 }
253 }
254 }
255
256 #[test]
257 fn decode_slice_output_length_errors() {
258 for num_quads in 1..100 {
259 let input = "AAAA".repeat(num_quads);
260 let mut vec = vec![0; (num_quads - 1) * 3];
261 assert_eq!(
262 DecodeSliceError::OutputSliceTooSmall,
263 STANDARD.decode_slice(&input, &mut vec).unwrap_err()
264 );
265 vec.push(0);
266 assert_eq!(
267 DecodeSliceError::OutputSliceTooSmall,
268 STANDARD.decode_slice(&input, &mut vec).unwrap_err()
269 );
270 vec.push(0);
271 assert_eq!(
272 DecodeSliceError::OutputSliceTooSmall,
273 STANDARD.decode_slice(&input, &mut vec).unwrap_err()
274 );
275 vec.push(0);
276 // now it works
277 assert_eq!(
278 num_quads * 3,
279 STANDARD.decode_slice(&input, &mut vec).unwrap()
280 );
281 }
282 }
283
284 fn do_decode_slice_doesnt_clobber_existing_prefix_or_suffix<
285 F: Fn(&GeneralPurpose, &[u8], &mut [u8]) -> usize,
286 >(
287 call_decode: F,
288 ) {
289 let mut orig_data = Vec::new();
290 let mut encoded_data = String::new();
291 let mut decode_buf = Vec::new();
292 let mut decode_buf_copy: Vec<u8> = Vec::new();
293
294 let input_len_range = Uniform::new(0, 1000);
295
296 let mut rng = rand::rngs::SmallRng::from_entropy();
297
298 for _ in 0..10_000 {
299 orig_data.clear();
300 encoded_data.clear();
301 decode_buf.clear();
302 decode_buf_copy.clear();
303
304 let input_len = input_len_range.sample(&mut rng);
305
306 for _ in 0..input_len {
307 orig_data.push(rng.gen());
308 }
309
310 let engine = random_engine(&mut rng);
311 engine.encode_string(&orig_data, &mut encoded_data);
312 assert_encode_sanity(&encoded_data, engine.config().encode_padding(), input_len);
313
314 // fill the buffer with random garbage, long enough to have some room before and after
315 for _ in 0..5000 {
316 decode_buf.push(rng.gen());
317 }
318
319 // keep a copy for later comparison
320 decode_buf_copy.extend(decode_buf.iter());
321
322 let offset = 1000;
323
324 // decode into the non-empty buf
325 let decode_bytes_written =
326 call_decode(&engine, encoded_data.as_bytes(), &mut decode_buf[offset..]);
327
328 assert_eq!(orig_data.len(), decode_bytes_written);
329 assert_eq!(
330 orig_data,
331 &decode_buf[offset..(offset + decode_bytes_written)]
332 );
333 assert_eq!(&decode_buf_copy[0..offset], &decode_buf[0..offset]);
334 assert_eq!(
335 &decode_buf_copy[offset + decode_bytes_written..],
336 &decode_buf[offset + decode_bytes_written..]
337 );
338 }
339 }
340}
341