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, Debug, PartialEq, Eq)]
10pub enum DecodeError {
11 InvalidByte(usize, u8),
19 InvalidLength(usize),
22 InvalidLastSymbol(usize, u8),
27 InvalidPadding,
30}
31
32impl fmt::Display for DecodeError {
33 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
34 match *self {
35 Self::InvalidByte(index, byte) => {
36 write!(f, "Invalid symbol {}, offset {}.", byte, index)
37 }
38 Self::InvalidLength(len) => write!(f, "Invalid input length: {}", len),
39 Self::InvalidLastSymbol(index, byte) => {
40 write!(f, "Invalid last symbol {}, offset {}.", byte, index)
41 }
42 Self::InvalidPadding => write!(f, "Invalid padding"),
43 }
44 }
45}
46
47#[cfg(any(feature = "std", test))]
48impl error::Error for DecodeError {}
49
50#[derive(Clone, Debug, PartialEq, Eq)]
52pub enum DecodeSliceError {
53 DecodeError(DecodeError),
55 OutputSliceTooSmall,
57}
58
59impl fmt::Display for DecodeSliceError {
60 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61 match self {
62 Self::DecodeError(e) => write!(f, "DecodeError: {}", e),
63 Self::OutputSliceTooSmall => write!(f, "Output slice too small"),
64 }
65 }
66}
67
68#[cfg(any(feature = "std", test))]
69impl error::Error for DecodeSliceError {
70 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
71 match self {
72 DecodeSliceError::DecodeError(e) => Some(e),
73 DecodeSliceError::OutputSliceTooSmall => None,
74 }
75 }
76}
77
78impl From<DecodeError> for DecodeSliceError {
79 fn from(e: DecodeError) -> Self {
80 DecodeSliceError::DecodeError(e)
81 }
82}
83
84#[deprecated(since = "0.21.0", note = "Use Engine::decode")]
88#[cfg(any(feature = "alloc", test))]
89pub fn decode<T: AsRef<[u8]>>(input: T) -> Result<Vec<u8>, DecodeError> {
90 STANDARD.decode(input)
91}
92
93#[deprecated(since = "0.21.0", note = "Use Engine::decode")]
98#[cfg(any(feature = "alloc", test))]
99pub fn decode_engine<E: Engine, T: AsRef<[u8]>>(
100 input: T,
101 engine: &E,
102) -> Result<Vec<u8>, DecodeError> {
103 engine.decode(input)
104}
105
106#[cfg(any(feature = "alloc", test))]
110#[deprecated(since = "0.21.0", note = "Use Engine::decode_vec")]
111pub fn decode_engine_vec<E: Engine, T: AsRef<[u8]>>(
112 input: T,
113 buffer: &mut Vec<u8>,
114 engine: &E,
115) -> Result<(), DecodeError> {
116 engine.decode_vec(input, buffer)
117}
118
119#[deprecated(since = "0.21.0", note = "Use Engine::decode_slice")]
123pub fn decode_engine_slice<E: Engine, T: AsRef<[u8]>>(
124 input: T,
125 output: &mut [u8],
126 engine: &E,
127) -> Result<usize, DecodeSliceError> {
128 engine.decode_slice(input, output)
129}
130
131pub fn decoded_len_estimate(encoded_len: usize) -> usize {
150 STANDARD
151 .internal_decoded_len_estimate(encoded_len)
152 .decoded_len_estimate()
153}
154
155#[cfg(test)]
156mod tests {
157 use super::*;
158 use crate::{
159 alphabet,
160 engine::{general_purpose, Config, GeneralPurpose},
161 tests::{assert_encode_sanity, random_engine},
162 };
163 use rand::{
164 distributions::{Distribution, Uniform},
165 Rng, SeedableRng,
166 };
167
168 #[test]
169 fn decode_into_nonempty_vec_doesnt_clobber_existing_prefix() {
170 let mut orig_data = Vec::new();
171 let mut encoded_data = String::new();
172 let mut decoded_with_prefix = Vec::new();
173 let mut decoded_without_prefix = Vec::new();
174 let mut prefix = Vec::new();
175
176 let prefix_len_range = Uniform::new(0, 1000);
177 let input_len_range = Uniform::new(0, 1000);
178
179 let mut rng = rand::rngs::SmallRng::from_entropy();
180
181 for _ in 0..10_000 {
182 orig_data.clear();
183 encoded_data.clear();
184 decoded_with_prefix.clear();
185 decoded_without_prefix.clear();
186 prefix.clear();
187
188 let input_len = input_len_range.sample(&mut rng);
189
190 for _ in 0..input_len {
191 orig_data.push(rng.gen());
192 }
193
194 let engine = random_engine(&mut rng);
195 engine.encode_string(&orig_data, &mut encoded_data);
196 assert_encode_sanity(&encoded_data, engine.config().encode_padding(), input_len);
197
198 let prefix_len = prefix_len_range.sample(&mut rng);
199
200 for _ in 0..prefix_len {
202 prefix.push(rng.gen());
203 }
204
205 decoded_with_prefix.resize(prefix_len, 0);
206 decoded_with_prefix.copy_from_slice(&prefix);
207
208 engine
210 .decode_vec(&encoded_data, &mut decoded_with_prefix)
211 .unwrap();
212 engine
214 .decode_vec(&encoded_data, &mut decoded_without_prefix)
215 .unwrap();
216
217 assert_eq!(
218 prefix_len + decoded_without_prefix.len(),
219 decoded_with_prefix.len()
220 );
221 assert_eq!(orig_data, decoded_without_prefix);
222
223 prefix.append(&mut decoded_without_prefix);
225
226 assert_eq!(prefix, decoded_with_prefix);
227 }
228 }
229
230 #[test]
231 fn decode_slice_doesnt_clobber_existing_prefix_or_suffix() {
232 do_decode_slice_doesnt_clobber_existing_prefix_or_suffix(|e, input, output| {
233 e.decode_slice(input, output).unwrap()
234 })
235 }
236
237 #[test]
238 fn decode_slice_unchecked_doesnt_clobber_existing_prefix_or_suffix() {
239 do_decode_slice_doesnt_clobber_existing_prefix_or_suffix(|e, input, output| {
240 e.decode_slice_unchecked(input, output).unwrap()
241 })
242 }
243
244 #[test]
245 fn decode_engine_estimation_works_for_various_lengths() {
246 let engine = GeneralPurpose::new(&alphabet::STANDARD, general_purpose::NO_PAD);
247 for num_prefix_quads in 0..100 {
248 for suffix in &["AA", "AAA", "AAAA"] {
249 let mut prefix = "AAAA".repeat(num_prefix_quads);
250 prefix.push_str(suffix);
251 let res = engine.decode(prefix);
253 assert!(res.is_ok());
254 }
255 }
256 }
257
258 #[test]
259 fn decode_slice_output_length_errors() {
260 for num_quads in 1..100 {
261 let input = "AAAA".repeat(num_quads);
262 let mut vec = vec![0; (num_quads - 1) * 3];
263 assert_eq!(
264 DecodeSliceError::OutputSliceTooSmall,
265 STANDARD.decode_slice(&input, &mut vec).unwrap_err()
266 );
267 vec.push(0);
268 assert_eq!(
269 DecodeSliceError::OutputSliceTooSmall,
270 STANDARD.decode_slice(&input, &mut vec).unwrap_err()
271 );
272 vec.push(0);
273 assert_eq!(
274 DecodeSliceError::OutputSliceTooSmall,
275 STANDARD.decode_slice(&input, &mut vec).unwrap_err()
276 );
277 vec.push(0);
278 assert_eq!(
280 num_quads * 3,
281 STANDARD.decode_slice(&input, &mut vec).unwrap()
282 );
283 }
284 }
285
286 fn do_decode_slice_doesnt_clobber_existing_prefix_or_suffix<
287 F: Fn(&GeneralPurpose, &[u8], &mut [u8]) -> usize,
288 >(
289 call_decode: F,
290 ) {
291 let mut orig_data = Vec::new();
292 let mut encoded_data = String::new();
293 let mut decode_buf = Vec::new();
294 let mut decode_buf_copy: Vec<u8> = Vec::new();
295
296 let input_len_range = Uniform::new(0, 1000);
297
298 let mut rng = rand::rngs::SmallRng::from_entropy();
299
300 for _ in 0..10_000 {
301 orig_data.clear();
302 encoded_data.clear();
303 decode_buf.clear();
304 decode_buf_copy.clear();
305
306 let input_len = input_len_range.sample(&mut rng);
307
308 for _ in 0..input_len {
309 orig_data.push(rng.gen());
310 }
311
312 let engine = random_engine(&mut rng);
313 engine.encode_string(&orig_data, &mut encoded_data);
314 assert_encode_sanity(&encoded_data, engine.config().encode_padding(), input_len);
315
316 for _ in 0..5000 {
318 decode_buf.push(rng.gen());
319 }
320
321 decode_buf_copy.extend(decode_buf.iter());
323
324 let offset = 1000;
325
326 let decode_bytes_written =
328 call_decode(&engine, encoded_data.as_bytes(), &mut decode_buf[offset..]);
329
330 assert_eq!(orig_data.len(), decode_bytes_written);
331 assert_eq!(
332 orig_data,
333 &decode_buf[offset..(offset + decode_bytes_written)]
334 );
335 assert_eq!(&decode_buf_copy[0..offset], &decode_buf[0..offset]);
336 assert_eq!(
337 &decode_buf_copy[offset + decode_bytes_written..],
338 &decode_buf[offset + decode_bytes_written..]
339 );
340 }
341 }
342}
343
344#[allow(deprecated)]
345#[cfg(test)]
346mod coverage_gaming {
347 use super::*;
348 use std::error::Error;
349
350 #[test]
351 fn decode_error() {
352 let _ = format!("{:?}", DecodeError::InvalidPadding.clone());
353 let _ = format!(
354 "{} {} {} {}",
355 DecodeError::InvalidByte(0, 0),
356 DecodeError::InvalidLength(0),
357 DecodeError::InvalidLastSymbol(0, 0),
358 DecodeError::InvalidPadding,
359 );
360 }
361
362 #[test]
363 fn decode_slice_error() {
364 let _ = format!("{:?}", DecodeSliceError::OutputSliceTooSmall.clone());
365 let _ = format!(
366 "{} {}",
367 DecodeSliceError::OutputSliceTooSmall,
368 DecodeSliceError::DecodeError(DecodeError::InvalidPadding)
369 );
370 let _ = DecodeSliceError::OutputSliceTooSmall.source();
371 let _ = DecodeSliceError::DecodeError(DecodeError::InvalidPadding).source();
372 }
373
374 #[test]
375 fn deprecated_fns() {
376 let _ = decode("");
377 let _ = decode_engine("", &crate::prelude::BASE64_STANDARD);
378 let _ = decode_engine_vec("", &mut Vec::new(), &crate::prelude::BASE64_STANDARD);
379 let _ = decode_engine_slice("", &mut [], &crate::prelude::BASE64_STANDARD);
380 }
381
382 #[test]
383 fn decoded_len_est() {
384 assert_eq!(3, decoded_len_estimate(4));
385 }
386}