1use super::{
4 contracts::{BackendFault, OperationError, Status, Step},
5 incremental_decoder::DecoderState,
6 ordinary::{OneShotError, map_operation_error},
7 specifications::{Base64, Codec},
8};
9
10#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
15pub struct LegacyAsciiWhitespace;
16
17pub const ASCII_WHITESPACE: LegacyAsciiWhitespace = LegacyAsciiWhitespace;
19
20#[derive(Clone, Debug, Eq, PartialEq)]
25pub struct LegacyWhitespaceDecoder {
26 inner: DecoderState,
27}
28
29impl LegacyAsciiWhitespace {
30 pub fn decoder<S: Codec>(&self, codec: &Base64<S>) -> LegacyWhitespaceDecoder {
32 LegacyWhitespaceDecoder {
33 inner: DecoderState::new_legacy_ascii_whitespace(codec.settings()),
34 }
35 }
36
37 pub fn validate<S: Codec>(&self, codec: &Base64<S>, input: &[u8]) -> Result<(), OneShotError> {
39 self.decoded_len(codec, input).map(|_| ())
40 }
41
42 pub fn decoded_len<S: Codec>(
44 &self,
45 codec: &Base64<S>,
46 input: &[u8],
47 ) -> Result<usize, OneShotError> {
48 measure(self.decoder(codec), input)
49 }
50
51 pub fn decode_into<S: Codec>(
55 &self,
56 codec: &Base64<S>,
57 input: &[u8],
58 output: &mut [u8],
59 ) -> Result<usize, OneShotError> {
60 let required = self.decoded_len(codec, input)?;
61 if output.len() < required {
62 return Err(OneShotError::OutputTooSmall {
63 required,
64 available: output.len(),
65 });
66 }
67 decode_validated(self.decoder(codec), input, &mut output[..required])?;
68 Ok(required)
69 }
70}
71
72impl LegacyWhitespaceDecoder {
73 pub fn update(&mut self, input: &[u8], output: &mut [u8]) -> Result<Step, OperationError> {
75 self.inner.update(input, output)
76 }
77
78 pub fn finish(&mut self, output: &mut [u8]) -> Result<Step, OperationError> {
80 self.inner.finish(output)
81 }
82
83 pub fn reset(&mut self) {
85 self.inner.reset();
86 }
87
88 #[must_use]
90 pub const fn source_position(&self) -> usize {
91 self.inner.source_position()
92 }
93
94 #[cfg(test)]
95 pub(crate) fn set_source_position_for_test(&mut self, source_position: usize) {
96 self.inner.set_source_position_for_test(source_position);
97 }
98}
99
100fn measure(mut decoder: LegacyWhitespaceDecoder, input: &[u8]) -> Result<usize, OneShotError> {
101 let mut input_offset = 0;
102 let mut output_len = 0usize;
103 let mut scratch = [0u8; 3];
104 while input_offset < input.len() {
105 let step = decoder
106 .update(&input[input_offset..], &mut scratch)
107 .map_err(map_operation_error)?;
108 let progress = step.progress();
109 if progress.input_consumed() == 0 && progress.output_produced() == 0 {
110 return Err(OneShotError::Backend(BackendFault::ImpossibleState));
111 }
112 input_offset += progress.input_consumed();
113 output_len = output_len
114 .checked_add(progress.output_produced())
115 .ok_or(OneShotError::LengthOverflow)?;
116 }
117 finish_measurement(&mut decoder, output_len, &mut scratch)
118}
119
120fn finish_measurement(
121 decoder: &mut LegacyWhitespaceDecoder,
122 mut output_len: usize,
123 scratch: &mut [u8; 3],
124) -> Result<usize, OneShotError> {
125 loop {
126 let step = decoder.finish(scratch).map_err(map_operation_error)?;
127 output_len = output_len
128 .checked_add(step.progress().output_produced())
129 .ok_or(OneShotError::LengthOverflow)?;
130 match step.status() {
131 Status::Complete => return Ok(output_len),
132 Status::OutputFull(_) if step.progress().output_produced() != 0 => {}
133 Status::OutputFull(_) | Status::NeedInput => {
134 return Err(OneShotError::Backend(BackendFault::ImpossibleState));
135 }
136 }
137 }
138}
139
140fn decode_validated(
141 mut decoder: LegacyWhitespaceDecoder,
142 input: &[u8],
143 output: &mut [u8],
144) -> Result<(), OneShotError> {
145 let mut input_offset = 0;
146 let mut output_offset = 0;
147 while input_offset < input.len() {
148 let step = decoder
149 .update(&input[input_offset..], &mut output[output_offset..])
150 .map_err(map_operation_error)?;
151 let progress = step.progress();
152 if progress.input_consumed() == 0 && progress.output_produced() == 0 {
153 return Err(OneShotError::Backend(BackendFault::ImpossibleState));
154 }
155 input_offset += progress.input_consumed();
156 output_offset += progress.output_produced();
157 }
158 loop {
159 let step = decoder
160 .finish(&mut output[output_offset..])
161 .map_err(map_operation_error)?;
162 output_offset += step.progress().output_produced();
163 match step.status() {
164 Status::Complete => return Ok(()),
165 Status::OutputFull(_) if step.progress().output_produced() != 0 => {}
166 Status::OutputFull(_) | Status::NeedInput => {
167 return Err(OneShotError::Backend(BackendFault::ImpossibleState));
168 }
169 }
170 }
171}