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#[derive(Clone, PartialEq, Eq)]
10pub enum DecodeError {
11 InvalidByte(usize, u8),
19 InvalidLength(usize),
22 InvalidLastSymbol {
30 offset: usize,
32 symbol: u8,
34 symbol_value: u8,
40 },
41 InvalidPadding,
44}
45
46impl fmt::Display for DecodeError {
47 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
48 match *self {
49 Self::InvalidByte(index, byte) => {
50 write!(f, "Invalid symbol {}, offset {}.", byte, index)
51 }
52 Self::InvalidLength(len) => write!(f, "Invalid input length: {}", len),
53 Self::InvalidLastSymbol {
54 offset,
55 symbol,
56 symbol_value,
57 } => {
58 write!(
59 f,
60 "Invalid last symbol {:#4x} ('{}') at offset {}, decoded as {:#010b}.",
61 symbol,
62 core::str::from_utf8(&[symbol])
66 .ok()
67 .and_then(|s| s.chars().next())
68 .unwrap_or(core::char::REPLACEMENT_CHARACTER),
70 offset,
71 symbol_value
72 )
73 }
74 Self::InvalidPadding => write!(f, "Invalid padding"),
75 }
76 }
77}
78
79impl fmt::Debug for DecodeError {
80 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81 write!(f, "{}", self)
83 }
84}
85
86#[cfg(any(feature = "std", test))]
87impl error::Error for DecodeError {}
88
89#[derive(Clone, Debug, PartialEq, Eq)]
91pub enum DecodeSliceError {
92 DecodeError(DecodeError),
94 OutputSliceTooSmall,
96}
97
98impl fmt::Display for DecodeSliceError {
99 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
100 match self {
101 Self::DecodeError(e) => write!(f, "DecodeError: {}", e),
102 Self::OutputSliceTooSmall => write!(f, "Output slice too small"),
103 }
104 }
105}
106
107#[cfg(any(feature = "std", test))]
108impl error::Error for DecodeSliceError {
109 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
110 match self {
111 DecodeSliceError::DecodeError(e) => Some(e),
112 DecodeSliceError::OutputSliceTooSmall => None,
113 }
114 }
115}
116
117impl From<DecodeError> for DecodeSliceError {
118 fn from(e: DecodeError) -> Self {
119 DecodeSliceError::DecodeError(e)
120 }
121}
122
123#[deprecated(since = "0.21.0", note = "Use Engine::decode")]
127#[cfg(any(feature = "alloc", test))]
128pub fn decode<T: AsRef<[u8]>>(input: T) -> Result<Vec<u8>, DecodeError> {
129 STANDARD.decode(input)
130}
131
132#[deprecated(since = "0.21.0", note = "Use Engine::decode")]
137#[cfg(any(feature = "alloc", test))]
138pub fn decode_engine<E: Engine, T: AsRef<[u8]>>(
139 input: T,
140 engine: &E,
141) -> Result<Vec<u8>, DecodeError> {
142 engine.decode(input)
143}
144
145#[cfg(any(feature = "alloc", test))]
149#[deprecated(since = "0.21.0", note = "Use Engine::decode_vec")]
150pub fn decode_engine_vec<E: Engine, T: AsRef<[u8]>>(
151 input: T,
152 buffer: &mut Vec<u8>,
153 engine: &E,
154) -> Result<(), DecodeError> {
155 engine.decode_vec(input, buffer)
156}
157
158#[deprecated(since = "0.21.0", note = "Use Engine::decode_slice")]
162pub fn decode_engine_slice<E: Engine, T: AsRef<[u8]>>(
163 input: T,
164 output: &mut [u8],
165 engine: &E,
166) -> Result<usize, DecodeSliceError> {
167 engine.decode_slice(input, output)
168}
169
170#[must_use]
189pub fn decoded_len_estimate(encoded_len: usize) -> usize {
190 STANDARD
191 .internal_decoded_len_estimate(encoded_len)
192 .decoded_len_estimate()
193}
194
195#[cfg(test)]
196mod tests {
197 use super::*;
198 use crate::{
199 alphabet,
200 engine::{general_purpose, GeneralPurpose},
201 tests::{assert_encode_sanity, random_engine},
202 };
203 use rand::distr::{Distribution, Uniform};
204 use rand::{rngs, RngExt};
205
206 #[test]
207 fn decode_into_nonempty_vec_doesnt_clobber_existing_prefix() {
208 let mut orig_data = Vec::new();
209 let mut encoded_data = String::new();
210 let mut decoded_with_prefix = Vec::new();
211 let mut decoded_without_prefix = Vec::new();
212 let mut prefix = Vec::new();
213
214 let prefix_len_range = Uniform::new(0, 1000).unwrap();
215 let input_len_range = Uniform::new(0, 1000).unwrap();
216
217 let mut rng = rand::make_rng::<rngs::SmallRng>();
218
219 for _ in 0..10_000 {
220 orig_data.clear();
221 encoded_data.clear();
222 decoded_with_prefix.clear();
223 decoded_without_prefix.clear();
224 prefix.clear();
225
226 let input_len = input_len_range.sample(&mut rng);
227
228 for _ in 0..input_len {
229 orig_data.push(rng.random());
230 }
231
232 let engine = random_engine(&mut rng);
233 engine.encode_string(&orig_data, &mut encoded_data);
234 assert_encode_sanity(&encoded_data, &engine, input_len);
235
236 let prefix_len = prefix_len_range.sample(&mut rng);
237
238 for _ in 0..prefix_len {
240 prefix.push(rng.random());
241 }
242
243 decoded_with_prefix.resize(prefix_len, 0);
244 decoded_with_prefix.copy_from_slice(&prefix);
245
246 engine
248 .decode_vec(&encoded_data, &mut decoded_with_prefix)
249 .unwrap();
250 engine
252 .decode_vec(&encoded_data, &mut decoded_without_prefix)
253 .unwrap();
254
255 assert_eq!(
256 prefix_len + decoded_without_prefix.len(),
257 decoded_with_prefix.len()
258 );
259 assert_eq!(orig_data, decoded_without_prefix);
260
261 prefix.append(&mut decoded_without_prefix);
263
264 assert_eq!(prefix, decoded_with_prefix);
265 }
266 }
267
268 #[test]
269 fn decode_slice_doesnt_clobber_existing_prefix_or_suffix() {
270 do_decode_slice_doesnt_clobber_existing_prefix_or_suffix(|e, input, output| {
271 e.decode_slice(input, output).unwrap()
272 })
273 }
274
275 #[test]
276 fn decode_slice_unchecked_doesnt_clobber_existing_prefix_or_suffix() {
277 do_decode_slice_doesnt_clobber_existing_prefix_or_suffix(|e, input, output| {
278 e.decode_slice_unchecked(input, output).unwrap()
279 })
280 }
281
282 #[test]
283 fn decode_engine_estimation_works_for_various_lengths() {
284 let engine = GeneralPurpose::new(&alphabet::STANDARD, general_purpose::NO_PAD);
285 for num_prefix_quads in 0..100 {
286 for suffix in &["AA", "AAA", "AAAA"] {
287 let mut prefix = "AAAA".repeat(num_prefix_quads);
288 prefix.push_str(suffix);
289 let res = engine.decode(prefix);
291 assert!(res.is_ok());
292 }
293 }
294 }
295
296 #[test]
297 fn decode_slice_output_length_errors() {
298 for num_quads in 1..100 {
299 let input = "AAAA".repeat(num_quads);
300 let mut vec = vec![0; (num_quads - 1) * 3];
301 assert_eq!(
302 DecodeSliceError::OutputSliceTooSmall,
303 STANDARD.decode_slice(&input, &mut vec).unwrap_err()
304 );
305 vec.push(0);
306 assert_eq!(
307 DecodeSliceError::OutputSliceTooSmall,
308 STANDARD.decode_slice(&input, &mut vec).unwrap_err()
309 );
310 vec.push(0);
311 assert_eq!(
312 DecodeSliceError::OutputSliceTooSmall,
313 STANDARD.decode_slice(&input, &mut vec).unwrap_err()
314 );
315 vec.push(0);
316 assert_eq!(
318 num_quads * 3,
319 STANDARD.decode_slice(&input, &mut vec).unwrap()
320 );
321 }
322 }
323
324 #[test]
325 fn invalid_last_symbol_debug() {
326 let err = DecodeError::InvalidLastSymbol {
327 offset: 100,
328 symbol: b'W',
329 symbol_value: 0x16,
330 };
331
332 assert_eq!(
333 "Invalid last symbol 0x57 ('W') at offset 100, decoded as 0b00010110.",
334 format!("{:?}", err)
335 );
336 }
337
338 fn do_decode_slice_doesnt_clobber_existing_prefix_or_suffix<
339 F: Fn(&GeneralPurpose, &[u8], &mut [u8]) -> usize,
340 >(
341 call_decode: F,
342 ) {
343 let mut orig_data = Vec::new();
344 let mut encoded_data = String::new();
345 let mut decode_buf = Vec::new();
346 let mut decode_buf_copy: Vec<u8> = Vec::new();
347
348 let input_len_range = Uniform::new(0, 1000).unwrap();
349
350 let mut rng = rand::make_rng::<rngs::SmallRng>();
351
352 for _ in 0..10_000 {
353 orig_data.clear();
354 encoded_data.clear();
355 decode_buf.clear();
356 decode_buf_copy.clear();
357
358 let input_len = input_len_range.sample(&mut rng);
359
360 for _ in 0..input_len {
361 orig_data.push(rng.random());
362 }
363
364 let engine = random_engine(&mut rng);
365 engine.encode_string(&orig_data, &mut encoded_data);
366 assert_encode_sanity(&encoded_data, &engine, input_len);
367
368 for _ in 0..5000 {
370 decode_buf.push(rng.random());
371 }
372
373 decode_buf_copy.extend(decode_buf.iter());
375
376 let offset = 1000;
377
378 let decode_bytes_written =
380 call_decode(&engine, encoded_data.as_bytes(), &mut decode_buf[offset..]);
381
382 assert_eq!(orig_data.len(), decode_bytes_written);
383 assert_eq!(
384 orig_data,
385 &decode_buf[offset..(offset + decode_bytes_written)]
386 );
387 assert_eq!(&decode_buf_copy[0..offset], &decode_buf[0..offset]);
388 assert_eq!(
389 &decode_buf_copy[offset + decode_bytes_written..],
390 &decode_buf[offset + decode_bytes_written..]
391 );
392 }
393 }
394}
395
396#[allow(deprecated)]
397#[cfg(test)]
398mod coverage_gaming {
399 use super::*;
400 use std::error::Error;
401
402 #[test]
403 fn decode_error() {
404 let _ = format!("{:?}", DecodeError::InvalidPadding.clone());
405 let _ = format!(
406 "{} {} {} {}",
407 DecodeError::InvalidByte(0, 0),
408 DecodeError::InvalidLength(0),
409 DecodeError::InvalidLastSymbol {
410 offset: 0,
411 symbol: 0,
412 symbol_value: 0,
413 },
414 DecodeError::InvalidPadding,
415 );
416 }
417
418 #[test]
419 fn decode_slice_error() {
420 let _ = format!("{:?}", DecodeSliceError::OutputSliceTooSmall.clone());
421 let _ = format!(
422 "{} {}",
423 DecodeSliceError::OutputSliceTooSmall,
424 DecodeSliceError::DecodeError(DecodeError::InvalidPadding)
425 );
426 let _ = DecodeSliceError::OutputSliceTooSmall.source();
427 let _ = DecodeSliceError::DecodeError(DecodeError::InvalidPadding).source();
428 }
429
430 #[test]
431 fn deprecated_fns() {
432 let _ = decode("");
433 let _ = decode_engine("", &crate::prelude::BASE64_STANDARD);
434 let _ = decode_engine_vec("", &mut Vec::new(), &crate::prelude::BASE64_STANDARD);
435 let _ = decode_engine_slice("", &mut [], &crate::prelude::BASE64_STANDARD);
436 }
437
438 #[test]
439 fn decoded_len_est() {
440 assert_eq!(3, decoded_len_estimate(4));
441 }
442}