base64_ng/v2/web/
one_shot.rs1use super::{ForgivingBase64, ForgivingError};
4use crate::v2::{BackendFault, Progress, Status};
5
6impl ForgivingBase64 {
7 pub fn validate(self, input: &str) -> Result<(), ForgivingError> {
9 self.decoded_len(input).map(|_| ())
10 }
11
12 pub fn decoded_len(self, input: &str) -> Result<usize, ForgivingError> {
14 measure(input)
15 }
16
17 pub fn decode_into(self, input: &str, output: &mut [u8]) -> Result<usize, ForgivingError> {
22 let required = self.decoded_len(input)?;
23 if output.len() < required {
24 return Err(ForgivingError::OutputTooSmall {
25 required,
26 available: output.len(),
27 });
28 }
29 decode_validated(input, &mut output[..required])?;
30 Ok(required)
31 }
32}
33
34fn measure(input: &str) -> Result<usize, ForgivingError> {
35 let mut decoder = ForgivingBase64.decoder();
36 let mut offset = 0;
37 let mut total = 0usize;
38 let mut scratch = [0u8; 3];
39 while offset < input.len() {
40 let step = decoder.update(&input[offset..], &mut scratch)?;
41 let progress = step.progress();
42 require_progress(progress)?;
43 offset += progress.input_consumed();
44 total = total
45 .checked_add(progress.output_produced())
46 .ok_or(ForgivingError::PositionOverflow)?;
47 }
48 loop {
49 let step = decoder.finish(&mut scratch)?;
50 total = total
51 .checked_add(step.progress().output_produced())
52 .ok_or(ForgivingError::PositionOverflow)?;
53 match step.status() {
54 Status::Complete => return Ok(total),
55 Status::OutputFull(_) => require_output_progress(step.progress())?,
56 Status::NeedInput => return Err(impossible_state()),
57 }
58 }
59}
60
61fn decode_validated(input: &str, output: &mut [u8]) -> Result<(), ForgivingError> {
62 let mut decoder = ForgivingBase64.decoder();
63 let mut input_offset = 0;
64 let mut output_offset = 0;
65 while input_offset < input.len() {
66 let step = decoder.update(&input[input_offset..], &mut output[output_offset..])?;
67 let progress = step.progress();
68 require_progress(progress)?;
69 input_offset += progress.input_consumed();
70 output_offset += progress.output_produced();
71 }
72 loop {
73 let step = decoder.finish(&mut output[output_offset..])?;
74 output_offset += step.progress().output_produced();
75 match step.status() {
76 Status::Complete => return Ok(()),
77 Status::OutputFull(_) => require_output_progress(step.progress())?,
78 Status::NeedInput => return Err(impossible_state()),
79 }
80 }
81}
82
83fn require_progress(progress: Progress) -> Result<(), ForgivingError> {
84 if progress.input_consumed() == 0 && progress.output_produced() == 0 {
85 Err(impossible_state())
86 } else {
87 Ok(())
88 }
89}
90
91fn require_output_progress(progress: Progress) -> Result<(), ForgivingError> {
92 if progress.output_produced() == 0 {
93 Err(impossible_state())
94 } else {
95 Ok(())
96 }
97}
98
99const fn impossible_state() -> ForgivingError {
100 ForgivingError::Backend(BackendFault::ImpossibleState)
101}