Fill the provided buffer with data decoded from Base64. Enough Base64 input data must remain to fill the entire buffer. # Returns - `Ok(bytes)` if the expected amount of data was read - `Err(Error::InvalidLength)` if the exact amount of data couldn't be read
(&mut self, out: &'o mut [u8])
| 105 | /// - `Ok(bytes)` if the expected amount of data was read |
| 106 | /// - `Err(Error::InvalidLength)` if the exact amount of data couldn't be read |
| 107 | pub fn decode<'o>(&mut self, out: &'o mut [u8]) -> Result<&'o [u8], Error> { |
| 108 | if self.is_finished() { |
| 109 | return Err(InvalidLength); |
| 110 | } |
| 111 | |
| 112 | let mut out_pos = 0; |
| 113 | |
| 114 | while out_pos < out.len() { |
| 115 | // If there's data in the block buffer, use it |
| 116 | if !self.block_buffer.is_empty() { |
| 117 | let out_rem = out.len().checked_sub(out_pos).ok_or(InvalidLength)?; |
| 118 | let bytes = self.block_buffer.take(out_rem)?; |
| 119 | out[out_pos..][..bytes.len()].copy_from_slice(bytes); |
| 120 | out_pos = out_pos.checked_add(bytes.len()).ok_or(InvalidLength)?; |
| 121 | } |
| 122 | |
| 123 | // Advance the line reader if necessary |
| 124 | if self.line.is_empty() && !self.line_reader.is_empty() { |
| 125 | self.advance_line()?; |
| 126 | } |
| 127 | |
| 128 | // Attempt to decode a stride of block-aligned data |
| 129 | let in_blocks = self.line.len() / 4; |
| 130 | let out_rem = out.len().checked_sub(out_pos).ok_or(InvalidLength)?; |
| 131 | let out_blocks = out_rem / 3; |
| 132 | let blocks = cmp::min(in_blocks, out_blocks); |
| 133 | let in_aligned = self.line.take(blocks.checked_mul(4).ok_or(InvalidLength)?); |
| 134 | |
| 135 | if !in_aligned.is_empty() { |
| 136 | let out_buf = &mut out[out_pos..][..blocks.checked_mul(3).ok_or(InvalidLength)?]; |
| 137 | let decoded_len = self.perform_decode(in_aligned, out_buf)?.len(); |
| 138 | out_pos = out_pos.checked_add(decoded_len).ok_or(InvalidLength)?; |
| 139 | } |
| 140 | |
| 141 | if out_pos < out.len() { |
| 142 | if self.is_finished() { |
| 143 | // If we're out of input then we've been requested to decode |
| 144 | // more data than is actually available. |
| 145 | return Err(InvalidLength); |
| 146 | } else { |
| 147 | // If we still have data available but haven't completely |
| 148 | // filled the output slice, we're in a situation where |
| 149 | // either the input or output isn't block-aligned, so fill |
| 150 | // the internal block buffer. |
| 151 | self.fill_block_buffer()?; |
| 152 | } |
| 153 | } |
| 154 | } |
| 155 | |
| 156 | self.remaining_len = self |
| 157 | .remaining_len |
| 158 | .checked_sub(out.len()) |
| 159 | .ok_or(InvalidLength)?; |
| 160 | |
| 161 | Ok(out) |
| 162 | } |
| 163 | |
| 164 | /// Decode all remaining Base64 data, placing the result into `buf`. |