1#![cfg_attr(not(feature = "std"), no_std)]
2#![forbid(unsafe_code)]
3#![deny(missing_docs)]
4#![deny(clippy::all)]
5#![deny(clippy::pedantic)]
6#![allow(clippy::missing_errors_doc)]
7
8#[cfg(feature = "alloc")]
46extern crate alloc;
47
48#[cfg(feature = "stream")]
49pub mod stream {
50 use super::{Alphabet, DecodeError, EncodeError, Engine};
80 use std::collections::VecDeque;
81 use std::io::{self, Read, Write};
82
83 pub struct Encoder<W, A, const PAD: bool>
85 where
86 A: Alphabet,
87 {
88 inner: W,
89 engine: Engine<A, PAD>,
90 pending: [u8; 2],
91 pending_len: usize,
92 }
93
94 impl<W, A, const PAD: bool> Encoder<W, A, PAD>
95 where
96 A: Alphabet,
97 {
98 #[must_use]
100 pub const fn new(inner: W, engine: Engine<A, PAD>) -> Self {
101 Self {
102 inner,
103 engine,
104 pending: [0; 2],
105 pending_len: 0,
106 }
107 }
108
109 #[must_use]
111 pub const fn get_ref(&self) -> &W {
112 &self.inner
113 }
114
115 pub fn get_mut(&mut self) -> &mut W {
117 &mut self.inner
118 }
119
120 #[must_use]
124 pub fn into_inner(self) -> W {
125 self.inner
126 }
127 }
128
129 impl<W, A, const PAD: bool> Encoder<W, A, PAD>
130 where
131 W: Write,
132 A: Alphabet,
133 {
134 pub fn finish(mut self) -> io::Result<W> {
136 self.write_pending_final()?;
137 self.inner.flush()?;
138 Ok(self.inner)
139 }
140
141 fn write_pending_final(&mut self) -> io::Result<()> {
142 if self.pending_len == 0 {
143 return Ok(());
144 }
145
146 let mut encoded = [0u8; 4];
147 let written = self
148 .engine
149 .encode_slice(&self.pending[..self.pending_len], &mut encoded)
150 .map_err(encode_error_to_io)?;
151 self.inner.write_all(&encoded[..written])?;
152 self.pending_len = 0;
153 Ok(())
154 }
155 }
156
157 impl<W, A, const PAD: bool> Write for Encoder<W, A, PAD>
158 where
159 W: Write,
160 A: Alphabet,
161 {
162 fn write(&mut self, input: &[u8]) -> io::Result<usize> {
163 if input.is_empty() {
164 return Ok(0);
165 }
166
167 let mut consumed = 0;
168 if self.pending_len > 0 {
169 let needed = 3 - self.pending_len;
170 if input.len() < needed {
171 self.pending[self.pending_len..self.pending_len + input.len()]
172 .copy_from_slice(input);
173 self.pending_len += input.len();
174 return Ok(input.len());
175 }
176
177 let mut chunk = [0u8; 3];
178 chunk[..self.pending_len].copy_from_slice(&self.pending[..self.pending_len]);
179 chunk[self.pending_len..].copy_from_slice(&input[..needed]);
180
181 let mut encoded = [0u8; 4];
182 let written = self
183 .engine
184 .encode_slice(&chunk, &mut encoded)
185 .map_err(encode_error_to_io)?;
186 self.inner.write_all(&encoded[..written])?;
187 self.pending_len = 0;
188 consumed += needed;
189 }
190
191 let remaining = &input[consumed..];
192 let full_len = remaining.len() / 3 * 3;
193 let mut offset = 0;
194 let mut encoded = [0u8; 1024];
195 while offset < full_len {
196 let mut take = core::cmp::min(full_len - offset, 768);
197 take -= take % 3;
198 debug_assert!(take > 0);
199
200 let written = self
201 .engine
202 .encode_slice(&remaining[offset..offset + take], &mut encoded)
203 .map_err(encode_error_to_io)?;
204 self.inner.write_all(&encoded[..written])?;
205 offset += take;
206 }
207
208 let tail = &remaining[full_len..];
209 self.pending[..tail.len()].copy_from_slice(tail);
210 self.pending_len = tail.len();
211
212 Ok(input.len())
213 }
214
215 fn flush(&mut self) -> io::Result<()> {
216 self.inner.flush()
217 }
218 }
219
220 fn encode_error_to_io(err: EncodeError) -> io::Error {
221 io::Error::new(io::ErrorKind::InvalidInput, err)
222 }
223
224 pub struct Decoder<W, A, const PAD: bool>
226 where
227 A: Alphabet,
228 {
229 inner: W,
230 engine: Engine<A, PAD>,
231 pending: [u8; 4],
232 pending_len: usize,
233 finished: bool,
234 }
235
236 impl<W, A, const PAD: bool> Decoder<W, A, PAD>
237 where
238 A: Alphabet,
239 {
240 #[must_use]
242 pub const fn new(inner: W, engine: Engine<A, PAD>) -> Self {
243 Self {
244 inner,
245 engine,
246 pending: [0; 4],
247 pending_len: 0,
248 finished: false,
249 }
250 }
251
252 #[must_use]
254 pub const fn get_ref(&self) -> &W {
255 &self.inner
256 }
257
258 pub fn get_mut(&mut self) -> &mut W {
260 &mut self.inner
261 }
262
263 #[must_use]
267 pub fn into_inner(self) -> W {
268 self.inner
269 }
270 }
271
272 impl<W, A, const PAD: bool> Decoder<W, A, PAD>
273 where
274 W: Write,
275 A: Alphabet,
276 {
277 pub fn finish(mut self) -> io::Result<W> {
279 self.write_pending_final()?;
280 self.inner.flush()?;
281 Ok(self.inner)
282 }
283
284 fn write_pending_final(&mut self) -> io::Result<()> {
285 if self.pending_len == 0 {
286 return Ok(());
287 }
288
289 let mut decoded = [0u8; 3];
290 let written = self
291 .engine
292 .decode_slice(&self.pending[..self.pending_len], &mut decoded)
293 .map_err(decode_error_to_io)?;
294 self.inner.write_all(&decoded[..written])?;
295 self.pending_len = 0;
296 Ok(())
297 }
298
299 fn write_full_quad(&mut self, input: [u8; 4]) -> io::Result<()> {
300 let mut decoded = [0u8; 3];
301 let written = self
302 .engine
303 .decode_slice(&input, &mut decoded)
304 .map_err(decode_error_to_io)?;
305 self.inner.write_all(&decoded[..written])?;
306 if written < 3 {
307 self.finished = true;
308 }
309 Ok(())
310 }
311 }
312
313 impl<W, A, const PAD: bool> Write for Decoder<W, A, PAD>
314 where
315 W: Write,
316 A: Alphabet,
317 {
318 fn write(&mut self, input: &[u8]) -> io::Result<usize> {
319 if input.is_empty() {
320 return Ok(0);
321 }
322 if self.finished {
323 return Err(trailing_input_after_padding_error());
324 }
325
326 let mut consumed = 0;
327 if self.pending_len > 0 {
328 let needed = 4 - self.pending_len;
329 if input.len() < needed {
330 self.pending[self.pending_len..self.pending_len + input.len()]
331 .copy_from_slice(input);
332 self.pending_len += input.len();
333 return Ok(input.len());
334 }
335
336 let mut quad = [0u8; 4];
337 quad[..self.pending_len].copy_from_slice(&self.pending[..self.pending_len]);
338 quad[self.pending_len..].copy_from_slice(&input[..needed]);
339 self.write_full_quad(quad)?;
340 self.pending_len = 0;
341 consumed += needed;
342 if self.finished && consumed < input.len() {
343 return Err(trailing_input_after_padding_error());
344 }
345 }
346
347 let remaining = &input[consumed..];
348 let full_len = remaining.len() / 4 * 4;
349 let mut offset = 0;
350 while offset < full_len {
351 let quad = [
352 remaining[offset],
353 remaining[offset + 1],
354 remaining[offset + 2],
355 remaining[offset + 3],
356 ];
357 self.write_full_quad(quad)?;
358 offset += 4;
359 if self.finished && offset < remaining.len() {
360 return Err(trailing_input_after_padding_error());
361 }
362 }
363
364 let tail = &remaining[full_len..];
365 self.pending[..tail.len()].copy_from_slice(tail);
366 self.pending_len = tail.len();
367
368 Ok(input.len())
369 }
370
371 fn flush(&mut self) -> io::Result<()> {
372 self.inner.flush()
373 }
374 }
375
376 fn decode_error_to_io(err: DecodeError) -> io::Error {
377 io::Error::new(io::ErrorKind::InvalidInput, err)
378 }
379
380 fn trailing_input_after_padding_error() -> io::Error {
381 io::Error::new(
382 io::ErrorKind::InvalidInput,
383 "base64 decoder received trailing input after padding",
384 )
385 }
386
387 pub struct DecoderReader<R, A, const PAD: bool>
394 where
395 A: Alphabet,
396 {
397 inner: R,
398 engine: Engine<A, PAD>,
399 pending: [u8; 4],
400 pending_len: usize,
401 output: VecDeque<u8>,
402 finished: bool,
403 terminal_seen: bool,
404 }
405
406 impl<R, A, const PAD: bool> DecoderReader<R, A, PAD>
407 where
408 A: Alphabet,
409 {
410 #[must_use]
412 pub fn new(inner: R, engine: Engine<A, PAD>) -> Self {
413 Self {
414 inner,
415 engine,
416 pending: [0; 4],
417 pending_len: 0,
418 output: VecDeque::new(),
419 finished: false,
420 terminal_seen: false,
421 }
422 }
423
424 #[must_use]
426 pub const fn get_ref(&self) -> &R {
427 &self.inner
428 }
429
430 pub fn get_mut(&mut self) -> &mut R {
432 &mut self.inner
433 }
434
435 #[must_use]
437 pub fn into_inner(self) -> R {
438 self.inner
439 }
440 }
441
442 impl<R, A, const PAD: bool> Read for DecoderReader<R, A, PAD>
443 where
444 R: Read,
445 A: Alphabet,
446 {
447 fn read(&mut self, output: &mut [u8]) -> io::Result<usize> {
448 if output.is_empty() {
449 return Ok(0);
450 }
451
452 while self.output.is_empty() && !self.finished {
453 self.fill_output()?;
454 }
455
456 let mut written = 0;
457 while written < output.len() {
458 let Some(byte) = self.output.pop_front() else {
459 break;
460 };
461 output[written] = byte;
462 written += 1;
463 }
464
465 Ok(written)
466 }
467 }
468
469 impl<R, A, const PAD: bool> DecoderReader<R, A, PAD>
470 where
471 R: Read,
472 A: Alphabet,
473 {
474 fn fill_output(&mut self) -> io::Result<()> {
475 if self.terminal_seen {
476 self.finished = true;
477 return Ok(());
478 }
479
480 let mut input = [0u8; 4];
481 let read = self.inner.read(&mut input[..4 - self.pending_len])?;
482 if read == 0 {
483 self.finished = true;
484 self.push_final_pending()?;
485 return Ok(());
486 }
487
488 self.pending[self.pending_len..self.pending_len + read].copy_from_slice(&input[..read]);
489 self.pending_len += read;
490 if self.pending_len < 4 {
491 return Ok(());
492 }
493
494 let quad = self.pending;
495 self.pending_len = 0;
496 self.push_decoded(&quad)?;
497 if self.terminal_seen {
498 self.finished = true;
499 }
500 Ok(())
501 }
502
503 fn push_final_pending(&mut self) -> io::Result<()> {
504 if self.pending_len == 0 {
505 return Ok(());
506 }
507
508 let mut pending = [0u8; 4];
509 pending[..self.pending_len].copy_from_slice(&self.pending[..self.pending_len]);
510 let pending_len = self.pending_len;
511 self.pending_len = 0;
512 self.push_decoded(&pending[..pending_len])
513 }
514
515 fn push_decoded(&mut self, input: &[u8]) -> io::Result<()> {
516 let mut decoded = [0u8; 3];
517 let written = self
518 .engine
519 .decode_slice(input, &mut decoded)
520 .map_err(decode_error_to_io)?;
521 self.output.extend(&decoded[..written]);
522 if input.len() == 4 && written < 3 {
523 self.terminal_seen = true;
524 }
525 Ok(())
526 }
527 }
528
529 pub struct EncoderReader<R, A, const PAD: bool>
531 where
532 A: Alphabet,
533 {
534 inner: R,
535 engine: Engine<A, PAD>,
536 pending: [u8; 2],
537 pending_len: usize,
538 output: VecDeque<u8>,
539 finished: bool,
540 }
541
542 impl<R, A, const PAD: bool> EncoderReader<R, A, PAD>
543 where
544 A: Alphabet,
545 {
546 #[must_use]
548 pub fn new(inner: R, engine: Engine<A, PAD>) -> Self {
549 Self {
550 inner,
551 engine,
552 pending: [0; 2],
553 pending_len: 0,
554 output: VecDeque::new(),
555 finished: false,
556 }
557 }
558
559 #[must_use]
561 pub const fn get_ref(&self) -> &R {
562 &self.inner
563 }
564
565 pub fn get_mut(&mut self) -> &mut R {
567 &mut self.inner
568 }
569
570 #[must_use]
572 pub fn into_inner(self) -> R {
573 self.inner
574 }
575 }
576
577 impl<R, A, const PAD: bool> Read for EncoderReader<R, A, PAD>
578 where
579 R: Read,
580 A: Alphabet,
581 {
582 fn read(&mut self, output: &mut [u8]) -> io::Result<usize> {
583 if output.is_empty() {
584 return Ok(0);
585 }
586
587 while self.output.is_empty() && !self.finished {
588 self.fill_output()?;
589 }
590
591 let mut written = 0;
592 while written < output.len() {
593 let Some(byte) = self.output.pop_front() else {
594 break;
595 };
596 output[written] = byte;
597 written += 1;
598 }
599
600 Ok(written)
601 }
602 }
603
604 impl<R, A, const PAD: bool> EncoderReader<R, A, PAD>
605 where
606 R: Read,
607 A: Alphabet,
608 {
609 fn fill_output(&mut self) -> io::Result<()> {
610 let mut input = [0u8; 768];
611 let read = self.inner.read(&mut input)?;
612 if read == 0 {
613 self.finished = true;
614 self.push_final_pending()?;
615 return Ok(());
616 }
617
618 let mut consumed = 0;
619 if self.pending_len > 0 {
620 let needed = 3 - self.pending_len;
621 if read < needed {
622 self.pending[self.pending_len..self.pending_len + read]
623 .copy_from_slice(&input[..read]);
624 self.pending_len += read;
625 return Ok(());
626 }
627
628 let mut chunk = [0u8; 3];
629 chunk[..self.pending_len].copy_from_slice(&self.pending[..self.pending_len]);
630 chunk[self.pending_len..].copy_from_slice(&input[..needed]);
631 self.push_encoded(&chunk)?;
632 self.pending_len = 0;
633 consumed += needed;
634 }
635
636 let remaining = &input[consumed..read];
637 let full_len = remaining.len() / 3 * 3;
638 if full_len > 0 {
639 self.push_encoded(&remaining[..full_len])?;
640 }
641
642 let tail = &remaining[full_len..];
643 self.pending[..tail.len()].copy_from_slice(tail);
644 self.pending_len = tail.len();
645 Ok(())
646 }
647
648 fn push_final_pending(&mut self) -> io::Result<()> {
649 if self.pending_len == 0 {
650 return Ok(());
651 }
652
653 let mut pending = [0u8; 2];
654 pending[..self.pending_len].copy_from_slice(&self.pending[..self.pending_len]);
655 let pending_len = self.pending_len;
656 self.pending_len = 0;
657 self.push_encoded(&pending[..pending_len])
658 }
659
660 fn push_encoded(&mut self, input: &[u8]) -> io::Result<()> {
661 let mut encoded = [0u8; 1024];
662 let written = self
663 .engine
664 .encode_slice(input, &mut encoded)
665 .map_err(encode_error_to_io)?;
666 self.output.extend(&encoded[..written]);
667 Ok(())
668 }
669 }
670}
671
672pub const STANDARD: Engine<Standard, true> = Engine::new();
674
675pub const STANDARD_NO_PAD: Engine<Standard, false> = Engine::new();
677
678pub const URL_SAFE: Engine<UrlSafe, true> = Engine::new();
680
681pub const URL_SAFE_NO_PAD: Engine<UrlSafe, false> = Engine::new();
683
684pub const fn encoded_len(input_len: usize, padded: bool) -> Result<usize, EncodeError> {
699 match checked_encoded_len(input_len, padded) {
700 Some(len) => Ok(len),
701 None => Err(EncodeError::LengthOverflow),
702 }
703}
704
705#[must_use]
716pub const fn checked_encoded_len(input_len: usize, padded: bool) -> Option<usize> {
717 let groups = input_len / 3;
718 if groups > usize::MAX / 4 {
719 return None;
720 }
721 let full = groups * 4;
722 let rem = input_len % 3;
723 if rem == 0 {
724 Some(full)
725 } else if padded {
726 full.checked_add(4)
727 } else {
728 full.checked_add(rem + 1)
729 }
730}
731
732#[must_use]
743pub const fn decoded_capacity(encoded_len: usize) -> usize {
744 let rem = encoded_len % 4;
745 encoded_len / 4 * 3
746 + if rem == 2 {
747 1
748 } else if rem == 3 {
749 2
750 } else {
751 0
752 }
753}
754
755pub fn decoded_len(input: &[u8], padded: bool) -> Result<usize, DecodeError> {
769 if padded {
770 decoded_len_padded(input)
771 } else {
772 decoded_len_unpadded(input)
773 }
774}
775
776pub trait Alphabet {
778 const ENCODE: [u8; 64];
780
781 fn decode(byte: u8) -> Option<u8>;
783}
784
785#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
787pub struct Standard;
788
789impl Alphabet for Standard {
790 const ENCODE: [u8; 64] = *b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
791
792 #[inline]
793 fn decode(byte: u8) -> Option<u8> {
794 decode_ascii_base64(byte, Self::ENCODE[62], Self::ENCODE[63])
795 }
796}
797
798#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
800pub struct UrlSafe;
801
802impl Alphabet for UrlSafe {
803 const ENCODE: [u8; 64] = *b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
804
805 #[inline]
806 fn decode(byte: u8) -> Option<u8> {
807 decode_ascii_base64(byte, Self::ENCODE[62], Self::ENCODE[63])
808 }
809}
810
811#[inline]
812const fn encode_base64_value<A: Alphabet>(value: u8) -> u8 {
813 encode_ascii_base64(value, A::ENCODE[62], A::ENCODE[63])
814}
815
816#[inline]
817const fn encode_ascii_base64(value: u8, value_62_byte: u8, value_63_byte: u8) -> u8 {
818 let upper = mask_if(value < 26);
819 let lower = mask_if(value.wrapping_sub(26) < 26);
820 let digit = mask_if(value.wrapping_sub(52) < 10);
821 let value_62 = mask_if(value == 0x3e);
822 let value_63 = mask_if(value == 0x3f);
823
824 (value.wrapping_add(b'A') & upper)
825 | (value.wrapping_sub(26).wrapping_add(b'a') & lower)
826 | (value.wrapping_sub(52).wrapping_add(b'0') & digit)
827 | (value_62_byte & value_62)
828 | (value_63_byte & value_63)
829}
830
831#[inline]
832fn decode_ascii_base64(byte: u8, value_62_byte: u8, value_63_byte: u8) -> Option<u8> {
833 let upper = mask_if(byte.wrapping_sub(b'A') <= b'Z' - b'A');
834 let lower = mask_if(byte.wrapping_sub(b'a') <= b'z' - b'a');
835 let digit = mask_if(byte.wrapping_sub(b'0') <= b'9' - b'0');
836 let value_62 = mask_if(byte == value_62_byte);
837 let value_63 = mask_if(byte == value_63_byte);
838 let valid = upper | lower | digit | value_62 | value_63;
839
840 let decoded = (byte.wrapping_sub(b'A') & upper)
841 | (byte.wrapping_sub(b'a').wrapping_add(26) & lower)
842 | (byte.wrapping_sub(b'0').wrapping_add(52) & digit)
843 | (0x3e & value_62)
844 | (0x3f & value_63);
845
846 if valid == 0 { None } else { Some(decoded) }
847}
848
849#[inline]
850const fn mask_if(condition: bool) -> u8 {
851 0u8.wrapping_sub(condition as u8)
852}
853
854#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
856pub struct Engine<A, const PAD: bool> {
857 alphabet: core::marker::PhantomData<A>,
858}
859
860impl<A, const PAD: bool> Engine<A, PAD>
861where
862 A: Alphabet,
863{
864 #[must_use]
866 pub const fn new() -> Self {
867 Self {
868 alphabet: core::marker::PhantomData,
869 }
870 }
871
872 pub const fn encoded_len(&self, input_len: usize) -> Result<usize, EncodeError> {
874 encoded_len(input_len, PAD)
875 }
876
877 #[must_use]
879 pub const fn checked_encoded_len(&self, input_len: usize) -> Option<usize> {
880 checked_encoded_len(input_len, PAD)
881 }
882
883 pub fn decoded_len(&self, input: &[u8]) -> Result<usize, DecodeError> {
888 decoded_len(input, PAD)
889 }
890
891 pub fn decoded_len_legacy(&self, input: &[u8]) -> Result<usize, DecodeError> {
897 validate_legacy_decode::<A, PAD>(input)
898 }
899
900 #[must_use]
932 pub const fn encode_array<const INPUT_LEN: usize, const OUTPUT_LEN: usize>(
933 &self,
934 input: &[u8; INPUT_LEN],
935 ) -> [u8; OUTPUT_LEN] {
936 let Some(required) = checked_encoded_len(INPUT_LEN, PAD) else {
937 panic!("encoded base64 length overflows usize");
938 };
939 assert!(
940 required == OUTPUT_LEN,
941 "base64 output array has incorrect length"
942 );
943
944 let mut output = [0u8; OUTPUT_LEN];
945 let mut read = 0;
946 let mut write = 0;
947 while INPUT_LEN - read >= 3 {
948 let b0 = input[read];
949 let b1 = input[read + 1];
950 let b2 = input[read + 2];
951
952 output[write] = encode_base64_value::<A>(b0 >> 2);
953 output[write + 1] = encode_base64_value::<A>(((b0 & 0b0000_0011) << 4) | (b1 >> 4));
954 output[write + 2] = encode_base64_value::<A>(((b1 & 0b0000_1111) << 2) | (b2 >> 6));
955 output[write + 3] = encode_base64_value::<A>(b2 & 0b0011_1111);
956
957 read += 3;
958 write += 4;
959 }
960
961 match INPUT_LEN - read {
962 0 => {}
963 1 => {
964 let b0 = input[read];
965 output[write] = encode_base64_value::<A>(b0 >> 2);
966 output[write + 1] = encode_base64_value::<A>((b0 & 0b0000_0011) << 4);
967 write += 2;
968 if PAD {
969 output[write] = b'=';
970 output[write + 1] = b'=';
971 }
972 }
973 2 => {
974 let b0 = input[read];
975 let b1 = input[read + 1];
976 output[write] = encode_base64_value::<A>(b0 >> 2);
977 output[write + 1] = encode_base64_value::<A>(((b0 & 0b0000_0011) << 4) | (b1 >> 4));
978 output[write + 2] = encode_base64_value::<A>((b1 & 0b0000_1111) << 2);
979 if PAD {
980 output[write + 3] = b'=';
981 }
982 }
983 _ => unreachable!(),
984 }
985
986 output
987 }
988
989 pub fn encode_slice(&self, input: &[u8], output: &mut [u8]) -> Result<usize, EncodeError> {
991 let required = checked_encoded_len(input.len(), PAD).ok_or(EncodeError::LengthOverflow)?;
992 if output.len() < required {
993 return Err(EncodeError::OutputTooSmall {
994 required,
995 available: output.len(),
996 });
997 }
998
999 let mut read = 0;
1000 let mut write = 0;
1001 while read + 3 <= input.len() {
1002 let b0 = input[read];
1003 let b1 = input[read + 1];
1004 let b2 = input[read + 2];
1005
1006 output[write] = encode_base64_value::<A>(b0 >> 2);
1007 output[write + 1] = encode_base64_value::<A>(((b0 & 0b0000_0011) << 4) | (b1 >> 4));
1008 output[write + 2] = encode_base64_value::<A>(((b1 & 0b0000_1111) << 2) | (b2 >> 6));
1009 output[write + 3] = encode_base64_value::<A>(b2 & 0b0011_1111);
1010
1011 read += 3;
1012 write += 4;
1013 }
1014
1015 match input.len() - read {
1016 0 => {}
1017 1 => {
1018 let b0 = input[read];
1019 output[write] = encode_base64_value::<A>(b0 >> 2);
1020 output[write + 1] = encode_base64_value::<A>((b0 & 0b0000_0011) << 4);
1021 write += 2;
1022 if PAD {
1023 output[write] = b'=';
1024 output[write + 1] = b'=';
1025 write += 2;
1026 }
1027 }
1028 2 => {
1029 let b0 = input[read];
1030 let b1 = input[read + 1];
1031 output[write] = encode_base64_value::<A>(b0 >> 2);
1032 output[write + 1] = encode_base64_value::<A>(((b0 & 0b0000_0011) << 4) | (b1 >> 4));
1033 output[write + 2] = encode_base64_value::<A>((b1 & 0b0000_1111) << 2);
1034 write += 3;
1035 if PAD {
1036 output[write] = b'=';
1037 write += 1;
1038 }
1039 }
1040 _ => unreachable!(),
1041 }
1042
1043 Ok(write)
1044 }
1045
1046 #[cfg(feature = "alloc")]
1048 pub fn encode_vec(&self, input: &[u8]) -> Result<alloc::vec::Vec<u8>, EncodeError> {
1049 let required = checked_encoded_len(input.len(), PAD).ok_or(EncodeError::LengthOverflow)?;
1050 let mut output = alloc::vec![0; required];
1051 let written = self.encode_slice(input, &mut output)?;
1052 output.truncate(written);
1053 Ok(output)
1054 }
1055
1056 #[cfg(feature = "alloc")]
1071 pub fn encode_string(&self, input: &[u8]) -> Result<alloc::string::String, EncodeError> {
1072 let output = self.encode_vec(input)?;
1073 match alloc::string::String::from_utf8(output) {
1074 Ok(output) => Ok(output),
1075 Err(_) => unreachable!("base64 encoder produced non-UTF-8 output"),
1076 }
1077 }
1078
1079 pub fn encode_in_place<'a>(
1096 &self,
1097 buffer: &'a mut [u8],
1098 input_len: usize,
1099 ) -> Result<&'a mut [u8], EncodeError> {
1100 if input_len > buffer.len() {
1101 return Err(EncodeError::InputTooLarge {
1102 input_len,
1103 buffer_len: buffer.len(),
1104 });
1105 }
1106
1107 let required = checked_encoded_len(input_len, PAD).ok_or(EncodeError::LengthOverflow)?;
1108 if buffer.len() < required {
1109 return Err(EncodeError::OutputTooSmall {
1110 required,
1111 available: buffer.len(),
1112 });
1113 }
1114
1115 let mut read = input_len;
1116 let mut write = required;
1117
1118 match input_len % 3 {
1119 0 => {}
1120 1 => {
1121 read -= 1;
1122 let b0 = buffer[read];
1123 if PAD {
1124 write -= 4;
1125 buffer[write] = encode_base64_value::<A>(b0 >> 2);
1126 buffer[write + 1] = encode_base64_value::<A>((b0 & 0b0000_0011) << 4);
1127 buffer[write + 2] = b'=';
1128 buffer[write + 3] = b'=';
1129 } else {
1130 write -= 2;
1131 buffer[write] = encode_base64_value::<A>(b0 >> 2);
1132 buffer[write + 1] = encode_base64_value::<A>((b0 & 0b0000_0011) << 4);
1133 }
1134 }
1135 2 => {
1136 read -= 2;
1137 let b0 = buffer[read];
1138 let b1 = buffer[read + 1];
1139 if PAD {
1140 write -= 4;
1141 buffer[write] = encode_base64_value::<A>(b0 >> 2);
1142 buffer[write + 1] =
1143 encode_base64_value::<A>(((b0 & 0b0000_0011) << 4) | (b1 >> 4));
1144 buffer[write + 2] = encode_base64_value::<A>((b1 & 0b0000_1111) << 2);
1145 buffer[write + 3] = b'=';
1146 } else {
1147 write -= 3;
1148 buffer[write] = encode_base64_value::<A>(b0 >> 2);
1149 buffer[write + 1] =
1150 encode_base64_value::<A>(((b0 & 0b0000_0011) << 4) | (b1 >> 4));
1151 buffer[write + 2] = encode_base64_value::<A>((b1 & 0b0000_1111) << 2);
1152 }
1153 }
1154 _ => unreachable!(),
1155 }
1156
1157 while read > 0 {
1158 read -= 3;
1159 write -= 4;
1160 let b0 = buffer[read];
1161 let b1 = buffer[read + 1];
1162 let b2 = buffer[read + 2];
1163
1164 buffer[write] = encode_base64_value::<A>(b0 >> 2);
1165 buffer[write + 1] = encode_base64_value::<A>(((b0 & 0b0000_0011) << 4) | (b1 >> 4));
1166 buffer[write + 2] = encode_base64_value::<A>(((b1 & 0b0000_1111) << 2) | (b2 >> 6));
1167 buffer[write + 3] = encode_base64_value::<A>(b2 & 0b0011_1111);
1168 }
1169
1170 debug_assert_eq!(write, 0);
1171 Ok(&mut buffer[..required])
1172 }
1173
1174 pub fn decode_slice(&self, input: &[u8], output: &mut [u8]) -> Result<usize, DecodeError> {
1179 if input.is_empty() {
1180 return Ok(0);
1181 }
1182
1183 if PAD {
1184 decode_padded::<A>(input, output)
1185 } else {
1186 decode_unpadded::<A>(input, output)
1187 }
1188 }
1189
1190 pub fn decode_slice_legacy(
1196 &self,
1197 input: &[u8],
1198 output: &mut [u8],
1199 ) -> Result<usize, DecodeError> {
1200 let required = validate_legacy_decode::<A, PAD>(input)?;
1201 if output.len() < required {
1202 return Err(DecodeError::OutputTooSmall {
1203 required,
1204 available: output.len(),
1205 });
1206 }
1207 decode_legacy_to_slice::<A, PAD>(input, output)
1208 }
1209
1210 #[cfg(feature = "alloc")]
1214 pub fn decode_vec(&self, input: &[u8]) -> Result<alloc::vec::Vec<u8>, DecodeError> {
1215 let required = validate_decode::<A, PAD>(input)?;
1216 let mut output = alloc::vec![0; required];
1217 let written = match self.decode_slice(input, &mut output) {
1218 Ok(written) => written,
1219 Err(err) => {
1220 output.fill(0);
1221 return Err(err);
1222 }
1223 };
1224 output.truncate(written);
1225 Ok(output)
1226 }
1227
1228 #[cfg(feature = "alloc")]
1231 pub fn decode_vec_legacy(&self, input: &[u8]) -> Result<alloc::vec::Vec<u8>, DecodeError> {
1232 let required = validate_legacy_decode::<A, PAD>(input)?;
1233 let mut output = alloc::vec![0; required];
1234 let written = match self.decode_slice_legacy(input, &mut output) {
1235 Ok(written) => written,
1236 Err(err) => {
1237 output.fill(0);
1238 return Err(err);
1239 }
1240 };
1241 output.truncate(written);
1242 Ok(output)
1243 }
1244
1245 pub fn decode_in_place<'a>(&self, buffer: &'a mut [u8]) -> Result<&'a mut [u8], DecodeError> {
1257 let len = Self::decode_slice_to_start(buffer)?;
1258 Ok(&mut buffer[..len])
1259 }
1260
1261 pub fn decode_in_place_legacy<'a>(
1266 &self,
1267 buffer: &'a mut [u8],
1268 ) -> Result<&'a mut [u8], DecodeError> {
1269 let _required = validate_legacy_decode::<A, PAD>(buffer)?;
1270 let mut write = 0;
1271 let mut read = 0;
1272 while read < buffer.len() {
1273 let byte = buffer[read];
1274 if !is_legacy_whitespace(byte) {
1275 buffer[write] = byte;
1276 write += 1;
1277 }
1278 read += 1;
1279 }
1280 let len = Self::decode_slice_to_start(&mut buffer[..write])?;
1281 Ok(&mut buffer[..len])
1282 }
1283
1284 fn decode_slice_to_start(buffer: &mut [u8]) -> Result<usize, DecodeError> {
1285 let input_len = buffer.len();
1286 let mut read = 0;
1287 let mut write = 0;
1288 while read + 4 <= input_len {
1289 let chunk = [
1290 buffer[read],
1291 buffer[read + 1],
1292 buffer[read + 2],
1293 buffer[read + 3],
1294 ];
1295 let written = decode_chunk::<A, PAD>(&chunk, &mut buffer[write..])
1296 .map_err(|err| err.with_index_offset(read))?;
1297 read += 4;
1298 write += written;
1299 if written < 3 {
1300 if read != input_len {
1301 return Err(DecodeError::InvalidPadding { index: read - 4 });
1302 }
1303 return Ok(write);
1304 }
1305 }
1306
1307 let rem = input_len - read;
1308 if rem == 0 {
1309 return Ok(write);
1310 }
1311 if PAD {
1312 return Err(DecodeError::InvalidLength);
1313 }
1314 let mut tail = [0u8; 3];
1315 tail[..rem].copy_from_slice(&buffer[read..input_len]);
1316 decode_tail_unpadded::<A>(&tail[..rem], &mut buffer[write..])
1317 .map_err(|err| err.with_index_offset(read))
1318 .map(|n| write + n)
1319 }
1320}
1321
1322#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1324pub enum EncodeError {
1325 LengthOverflow,
1327 InputTooLarge {
1329 input_len: usize,
1331 buffer_len: usize,
1333 },
1334 OutputTooSmall {
1336 required: usize,
1338 available: usize,
1340 },
1341}
1342
1343impl core::fmt::Display for EncodeError {
1344 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1345 match self {
1346 Self::LengthOverflow => f.write_str("base64 output length overflows usize"),
1347 Self::InputTooLarge {
1348 input_len,
1349 buffer_len,
1350 } => write!(
1351 f,
1352 "base64 input length {input_len} exceeds buffer length {buffer_len}"
1353 ),
1354 Self::OutputTooSmall {
1355 required,
1356 available,
1357 } => write!(
1358 f,
1359 "base64 output buffer too small: required {required}, available {available}"
1360 ),
1361 }
1362 }
1363}
1364
1365#[cfg(feature = "std")]
1366impl std::error::Error for EncodeError {}
1367
1368#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1370pub enum DecodeError {
1371 InvalidLength,
1373 InvalidByte {
1375 index: usize,
1377 byte: u8,
1379 },
1380 InvalidPadding {
1382 index: usize,
1384 },
1385 OutputTooSmall {
1387 required: usize,
1389 available: usize,
1391 },
1392}
1393
1394impl core::fmt::Display for DecodeError {
1395 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1396 match self {
1397 Self::InvalidLength => f.write_str("invalid base64 input length"),
1398 Self::InvalidByte { index, byte } => {
1399 write!(f, "invalid base64 byte 0x{byte:02x} at index {index}")
1400 }
1401 Self::InvalidPadding { index } => write!(f, "invalid base64 padding at index {index}"),
1402 Self::OutputTooSmall {
1403 required,
1404 available,
1405 } => write!(
1406 f,
1407 "base64 decode output buffer too small: required {required}, available {available}"
1408 ),
1409 }
1410 }
1411}
1412
1413impl DecodeError {
1414 fn with_index_offset(self, offset: usize) -> Self {
1415 match self {
1416 Self::InvalidByte { index, byte } => Self::InvalidByte {
1417 index: index + offset,
1418 byte,
1419 },
1420 Self::InvalidPadding { index } => Self::InvalidPadding {
1421 index: index + offset,
1422 },
1423 Self::InvalidLength | Self::OutputTooSmall { .. } => self,
1424 }
1425 }
1426}
1427
1428#[cfg(feature = "std")]
1429impl std::error::Error for DecodeError {}
1430
1431fn validate_legacy_decode<A: Alphabet, const PAD: bool>(
1432 input: &[u8],
1433) -> Result<usize, DecodeError> {
1434 let mut chunk = [0u8; 4];
1435 let mut indexes = [0usize; 4];
1436 let mut chunk_len = 0;
1437 let mut required = 0;
1438 let mut terminal_seen = false;
1439
1440 for (index, byte) in input.iter().copied().enumerate() {
1441 if is_legacy_whitespace(byte) {
1442 continue;
1443 }
1444 if terminal_seen {
1445 return Err(DecodeError::InvalidPadding { index });
1446 }
1447
1448 chunk[chunk_len] = byte;
1449 indexes[chunk_len] = index;
1450 chunk_len += 1;
1451
1452 if chunk_len == 4 {
1453 let written =
1454 validate_chunk::<A, PAD>(&chunk).map_err(|err| map_chunk_error(err, &indexes))?;
1455 required += written;
1456 terminal_seen = written < 3;
1457 chunk_len = 0;
1458 }
1459 }
1460
1461 if chunk_len == 0 {
1462 return Ok(required);
1463 }
1464 if PAD {
1465 return Err(DecodeError::InvalidLength);
1466 }
1467
1468 validate_tail_unpadded::<A>(&chunk[..chunk_len])
1469 .map_err(|err| map_partial_chunk_error(err, &indexes, chunk_len))?;
1470 Ok(required + decoded_capacity(chunk_len))
1471}
1472
1473fn decode_legacy_to_slice<A: Alphabet, const PAD: bool>(
1474 input: &[u8],
1475 output: &mut [u8],
1476) -> Result<usize, DecodeError> {
1477 let mut chunk = [0u8; 4];
1478 let mut indexes = [0usize; 4];
1479 let mut chunk_len = 0;
1480 let mut write = 0;
1481 let mut terminal_seen = false;
1482
1483 for (index, byte) in input.iter().copied().enumerate() {
1484 if is_legacy_whitespace(byte) {
1485 continue;
1486 }
1487 if terminal_seen {
1488 return Err(DecodeError::InvalidPadding { index });
1489 }
1490
1491 chunk[chunk_len] = byte;
1492 indexes[chunk_len] = index;
1493 chunk_len += 1;
1494
1495 if chunk_len == 4 {
1496 let written = decode_chunk::<A, PAD>(&chunk, &mut output[write..])
1497 .map_err(|err| map_chunk_error(err, &indexes))?;
1498 write += written;
1499 terminal_seen = written < 3;
1500 chunk_len = 0;
1501 }
1502 }
1503
1504 if chunk_len == 0 {
1505 return Ok(write);
1506 }
1507 if PAD {
1508 return Err(DecodeError::InvalidLength);
1509 }
1510
1511 decode_tail_unpadded::<A>(&chunk[..chunk_len], &mut output[write..])
1512 .map_err(|err| map_partial_chunk_error(err, &indexes, chunk_len))
1513 .map(|n| write + n)
1514}
1515
1516#[inline]
1517const fn is_legacy_whitespace(byte: u8) -> bool {
1518 matches!(byte, b' ' | b'\t' | b'\r' | b'\n')
1519}
1520
1521fn map_chunk_error(err: DecodeError, indexes: &[usize; 4]) -> DecodeError {
1522 match err {
1523 DecodeError::InvalidByte { index, byte } => DecodeError::InvalidByte {
1524 index: indexes[index],
1525 byte,
1526 },
1527 DecodeError::InvalidPadding { index } => DecodeError::InvalidPadding {
1528 index: indexes[index],
1529 },
1530 DecodeError::InvalidLength | DecodeError::OutputTooSmall { .. } => err,
1531 }
1532}
1533
1534fn map_partial_chunk_error(err: DecodeError, indexes: &[usize; 4], len: usize) -> DecodeError {
1535 match err {
1536 DecodeError::InvalidByte { index, byte } if index < len => DecodeError::InvalidByte {
1537 index: indexes[index],
1538 byte,
1539 },
1540 DecodeError::InvalidPadding { index } if index < len => DecodeError::InvalidPadding {
1541 index: indexes[index],
1542 },
1543 DecodeError::InvalidByte { .. }
1544 | DecodeError::InvalidPadding { .. }
1545 | DecodeError::InvalidLength
1546 | DecodeError::OutputTooSmall { .. } => err,
1547 }
1548}
1549
1550fn decode_padded<A: Alphabet>(input: &[u8], output: &mut [u8]) -> Result<usize, DecodeError> {
1551 if !input.len().is_multiple_of(4) {
1552 return Err(DecodeError::InvalidLength);
1553 }
1554 let required = decoded_len_padded(input)?;
1555 if output.len() < required {
1556 return Err(DecodeError::OutputTooSmall {
1557 required,
1558 available: output.len(),
1559 });
1560 }
1561
1562 let mut read = 0;
1563 let mut write = 0;
1564 while read < input.len() {
1565 let written = decode_chunk::<A, true>(&input[read..read + 4], &mut output[write..])
1566 .map_err(|err| err.with_index_offset(read))?;
1567 read += 4;
1568 write += written;
1569 if written < 3 && read != input.len() {
1570 return Err(DecodeError::InvalidPadding { index: read - 4 });
1571 }
1572 }
1573 Ok(write)
1574}
1575
1576#[cfg(feature = "alloc")]
1577fn validate_decode<A: Alphabet, const PAD: bool>(input: &[u8]) -> Result<usize, DecodeError> {
1578 if input.is_empty() {
1579 return Ok(0);
1580 }
1581
1582 if PAD {
1583 validate_padded::<A>(input)
1584 } else {
1585 validate_unpadded::<A>(input)
1586 }
1587}
1588
1589#[cfg(feature = "alloc")]
1590fn validate_padded<A: Alphabet>(input: &[u8]) -> Result<usize, DecodeError> {
1591 if !input.len().is_multiple_of(4) {
1592 return Err(DecodeError::InvalidLength);
1593 }
1594 let required = decoded_len_padded(input)?;
1595
1596 let mut read = 0;
1597 while read < input.len() {
1598 let written = validate_chunk::<A, true>(&input[read..read + 4])
1599 .map_err(|err| err.with_index_offset(read))?;
1600 read += 4;
1601 if written < 3 && read != input.len() {
1602 return Err(DecodeError::InvalidPadding { index: read - 4 });
1603 }
1604 }
1605
1606 Ok(required)
1607}
1608
1609#[cfg(feature = "alloc")]
1610fn validate_unpadded<A: Alphabet>(input: &[u8]) -> Result<usize, DecodeError> {
1611 let required = decoded_len_unpadded(input)?;
1612
1613 let mut read = 0;
1614 while read + 4 <= input.len() {
1615 validate_chunk::<A, false>(&input[read..read + 4])
1616 .map_err(|err| err.with_index_offset(read))?;
1617 read += 4;
1618 }
1619 validate_tail_unpadded::<A>(&input[read..]).map_err(|err| err.with_index_offset(read))?;
1620
1621 Ok(required)
1622}
1623
1624fn decode_unpadded<A: Alphabet>(input: &[u8], output: &mut [u8]) -> Result<usize, DecodeError> {
1625 let required = decoded_len_unpadded(input)?;
1626 if output.len() < required {
1627 return Err(DecodeError::OutputTooSmall {
1628 required,
1629 available: output.len(),
1630 });
1631 }
1632
1633 let mut read = 0;
1634 let mut write = 0;
1635 while read + 4 <= input.len() {
1636 let written = decode_chunk::<A, false>(&input[read..read + 4], &mut output[write..])
1637 .map_err(|err| err.with_index_offset(read))?;
1638 read += 4;
1639 write += written;
1640 }
1641 decode_tail_unpadded::<A>(&input[read..], &mut output[write..])
1642 .map_err(|err| err.with_index_offset(read))
1643 .map(|n| write + n)
1644}
1645
1646fn decoded_len_padded(input: &[u8]) -> Result<usize, DecodeError> {
1647 if input.is_empty() {
1648 return Ok(0);
1649 }
1650 if !input.len().is_multiple_of(4) {
1651 return Err(DecodeError::InvalidLength);
1652 }
1653 let mut padding = 0;
1654 if input[input.len() - 1] == b'=' {
1655 padding += 1;
1656 }
1657 if input[input.len() - 2] == b'=' {
1658 padding += 1;
1659 }
1660 if padding == 0
1661 && let Some(index) = input.iter().position(|byte| *byte == b'=')
1662 {
1663 return Err(DecodeError::InvalidPadding { index });
1664 }
1665 if padding > 0 {
1666 let first_pad = input.len() - padding;
1667 if let Some(index) = input[..first_pad].iter().position(|byte| *byte == b'=') {
1668 return Err(DecodeError::InvalidPadding { index });
1669 }
1670 }
1671 Ok(input.len() / 4 * 3 - padding)
1672}
1673
1674fn decoded_len_unpadded(input: &[u8]) -> Result<usize, DecodeError> {
1675 if input.len() % 4 == 1 {
1676 return Err(DecodeError::InvalidLength);
1677 }
1678 if let Some(index) = input.iter().position(|byte| *byte == b'=') {
1679 return Err(DecodeError::InvalidPadding { index });
1680 }
1681 Ok(decoded_capacity(input.len()))
1682}
1683
1684fn validate_chunk<A: Alphabet, const PAD: bool>(input: &[u8]) -> Result<usize, DecodeError> {
1685 debug_assert_eq!(input.len(), 4);
1686 let _v0 = decode_byte::<A>(input[0], 0)?;
1687 let v1 = decode_byte::<A>(input[1], 1)?;
1688
1689 match (input[2], input[3]) {
1690 (b'=', b'=') if PAD => {
1691 if v1 & 0b0000_1111 != 0 {
1692 return Err(DecodeError::InvalidPadding { index: 1 });
1693 }
1694 Ok(1)
1695 }
1696 (b'=', _) if PAD => Err(DecodeError::InvalidPadding { index: 2 }),
1697 (_, b'=') if PAD => {
1698 let v2 = decode_byte::<A>(input[2], 2)?;
1699 if v2 & 0b0000_0011 != 0 {
1700 return Err(DecodeError::InvalidPadding { index: 2 });
1701 }
1702 Ok(2)
1703 }
1704 (b'=', _) | (_, b'=') => Err(DecodeError::InvalidPadding {
1705 index: input.iter().position(|byte| *byte == b'=').unwrap_or(0),
1706 }),
1707 _ => {
1708 decode_byte::<A>(input[2], 2)?;
1709 decode_byte::<A>(input[3], 3)?;
1710 Ok(3)
1711 }
1712 }
1713}
1714
1715fn decode_chunk<A: Alphabet, const PAD: bool>(
1716 input: &[u8],
1717 output: &mut [u8],
1718) -> Result<usize, DecodeError> {
1719 debug_assert_eq!(input.len(), 4);
1720 let v0 = decode_byte::<A>(input[0], 0)?;
1721 let v1 = decode_byte::<A>(input[1], 1)?;
1722
1723 match (input[2], input[3]) {
1724 (b'=', b'=') if PAD => {
1725 if output.is_empty() {
1726 return Err(DecodeError::OutputTooSmall {
1727 required: 1,
1728 available: output.len(),
1729 });
1730 }
1731 if v1 & 0b0000_1111 != 0 {
1732 return Err(DecodeError::InvalidPadding { index: 1 });
1733 }
1734 output[0] = (v0 << 2) | (v1 >> 4);
1735 Ok(1)
1736 }
1737 (b'=', _) if PAD => Err(DecodeError::InvalidPadding { index: 2 }),
1738 (_, b'=') if PAD => {
1739 if output.len() < 2 {
1740 return Err(DecodeError::OutputTooSmall {
1741 required: 2,
1742 available: output.len(),
1743 });
1744 }
1745 let v2 = decode_byte::<A>(input[2], 2)?;
1746 if v2 & 0b0000_0011 != 0 {
1747 return Err(DecodeError::InvalidPadding { index: 2 });
1748 }
1749 output[0] = (v0 << 2) | (v1 >> 4);
1750 output[1] = (v1 << 4) | (v2 >> 2);
1751 Ok(2)
1752 }
1753 (b'=', _) | (_, b'=') => Err(DecodeError::InvalidPadding {
1754 index: input.iter().position(|byte| *byte == b'=').unwrap_or(0),
1755 }),
1756 _ => {
1757 if output.len() < 3 {
1758 return Err(DecodeError::OutputTooSmall {
1759 required: 3,
1760 available: output.len(),
1761 });
1762 }
1763 let v2 = decode_byte::<A>(input[2], 2)?;
1764 let v3 = decode_byte::<A>(input[3], 3)?;
1765 output[0] = (v0 << 2) | (v1 >> 4);
1766 output[1] = (v1 << 4) | (v2 >> 2);
1767 output[2] = (v2 << 6) | v3;
1768 Ok(3)
1769 }
1770 }
1771}
1772
1773fn validate_tail_unpadded<A: Alphabet>(input: &[u8]) -> Result<(), DecodeError> {
1774 match input.len() {
1775 0 => Ok(()),
1776 2 => {
1777 decode_byte::<A>(input[0], 0)?;
1778 let v1 = decode_byte::<A>(input[1], 1)?;
1779 if v1 & 0b0000_1111 != 0 {
1780 return Err(DecodeError::InvalidPadding { index: 1 });
1781 }
1782 Ok(())
1783 }
1784 3 => {
1785 decode_byte::<A>(input[0], 0)?;
1786 decode_byte::<A>(input[1], 1)?;
1787 let v2 = decode_byte::<A>(input[2], 2)?;
1788 if v2 & 0b0000_0011 != 0 {
1789 return Err(DecodeError::InvalidPadding { index: 2 });
1790 }
1791 Ok(())
1792 }
1793 _ => Err(DecodeError::InvalidLength),
1794 }
1795}
1796
1797fn decode_tail_unpadded<A: Alphabet>(
1798 input: &[u8],
1799 output: &mut [u8],
1800) -> Result<usize, DecodeError> {
1801 match input.len() {
1802 0 => Ok(0),
1803 2 => {
1804 if output.is_empty() {
1805 return Err(DecodeError::OutputTooSmall {
1806 required: 1,
1807 available: output.len(),
1808 });
1809 }
1810 let v0 = decode_byte::<A>(input[0], 0)?;
1811 let v1 = decode_byte::<A>(input[1], 1)?;
1812 if v1 & 0b0000_1111 != 0 {
1813 return Err(DecodeError::InvalidPadding { index: 1 });
1814 }
1815 output[0] = (v0 << 2) | (v1 >> 4);
1816 Ok(1)
1817 }
1818 3 => {
1819 if output.len() < 2 {
1820 return Err(DecodeError::OutputTooSmall {
1821 required: 2,
1822 available: output.len(),
1823 });
1824 }
1825 let v0 = decode_byte::<A>(input[0], 0)?;
1826 let v1 = decode_byte::<A>(input[1], 1)?;
1827 let v2 = decode_byte::<A>(input[2], 2)?;
1828 if v2 & 0b0000_0011 != 0 {
1829 return Err(DecodeError::InvalidPadding { index: 2 });
1830 }
1831 output[0] = (v0 << 2) | (v1 >> 4);
1832 output[1] = (v1 << 4) | (v2 >> 2);
1833 Ok(2)
1834 }
1835 _ => Err(DecodeError::InvalidLength),
1836 }
1837}
1838
1839fn decode_byte<A: Alphabet>(byte: u8, index: usize) -> Result<u8, DecodeError> {
1840 A::decode(byte).ok_or(DecodeError::InvalidByte { index, byte })
1841}
1842
1843#[cfg(test)]
1844mod tests {
1845 use super::*;
1846
1847 #[test]
1848 fn encodes_standard_vectors() {
1849 let vectors = [
1850 (&b""[..], &b""[..]),
1851 (&b"f"[..], &b"Zg=="[..]),
1852 (&b"fo"[..], &b"Zm8="[..]),
1853 (&b"foo"[..], &b"Zm9v"[..]),
1854 (&b"foob"[..], &b"Zm9vYg=="[..]),
1855 (&b"fooba"[..], &b"Zm9vYmE="[..]),
1856 (&b"foobar"[..], &b"Zm9vYmFy"[..]),
1857 ];
1858 for (input, expected) in vectors {
1859 let mut output = [0u8; 16];
1860 let written = STANDARD.encode_slice(input, &mut output).unwrap();
1861 assert_eq!(&output[..written], expected);
1862 }
1863 }
1864
1865 #[test]
1866 fn decodes_standard_vectors() {
1867 let vectors = [
1868 (&b""[..], &b""[..]),
1869 (&b"Zg=="[..], &b"f"[..]),
1870 (&b"Zm8="[..], &b"fo"[..]),
1871 (&b"Zm9v"[..], &b"foo"[..]),
1872 (&b"Zm9vYg=="[..], &b"foob"[..]),
1873 (&b"Zm9vYmE="[..], &b"fooba"[..]),
1874 (&b"Zm9vYmFy"[..], &b"foobar"[..]),
1875 ];
1876 for (input, expected) in vectors {
1877 let mut output = [0u8; 16];
1878 let written = STANDARD.decode_slice(input, &mut output).unwrap();
1879 assert_eq!(&output[..written], expected);
1880 }
1881 }
1882
1883 #[test]
1884 fn supports_unpadded_url_safe() {
1885 let mut encoded = [0u8; 16];
1886 let written = URL_SAFE_NO_PAD
1887 .encode_slice(b"\xfb\xff", &mut encoded)
1888 .unwrap();
1889 assert_eq!(&encoded[..written], b"-_8");
1890
1891 let mut decoded = [0u8; 2];
1892 let written = URL_SAFE_NO_PAD
1893 .decode_slice(&encoded[..written], &mut decoded)
1894 .unwrap();
1895 assert_eq!(&decoded[..written], b"\xfb\xff");
1896 }
1897
1898 #[test]
1899 fn decodes_in_place() {
1900 let mut buffer = *b"Zm9vYmFy";
1901 let decoded = STANDARD_NO_PAD.decode_in_place(&mut buffer).unwrap();
1902 assert_eq!(decoded, b"foobar");
1903 }
1904
1905 #[test]
1906 fn rejects_non_canonical_padding_bits() {
1907 let mut output = [0u8; 4];
1908 assert_eq!(
1909 STANDARD.decode_slice(b"Zh==", &mut output),
1910 Err(DecodeError::InvalidPadding { index: 1 })
1911 );
1912 assert_eq!(
1913 STANDARD.decode_slice(b"Zm9=", &mut output),
1914 Err(DecodeError::InvalidPadding { index: 2 })
1915 );
1916 }
1917}