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 #[must_use]
923 pub const fn encode_array<const INPUT_LEN: usize, const OUTPUT_LEN: usize>(
924 &self,
925 input: &[u8; INPUT_LEN],
926 ) -> [u8; OUTPUT_LEN] {
927 let Some(required) = checked_encoded_len(INPUT_LEN, PAD) else {
928 panic!("encoded base64 length overflows usize");
929 };
930 assert!(
931 required == OUTPUT_LEN,
932 "base64 output array has incorrect length"
933 );
934
935 let mut output = [0u8; OUTPUT_LEN];
936 let mut read = 0;
937 let mut write = 0;
938 while INPUT_LEN - read >= 3 {
939 let b0 = input[read];
940 let b1 = input[read + 1];
941 let b2 = input[read + 2];
942
943 output[write] = encode_base64_value::<A>(b0 >> 2);
944 output[write + 1] = encode_base64_value::<A>(((b0 & 0b0000_0011) << 4) | (b1 >> 4));
945 output[write + 2] = encode_base64_value::<A>(((b1 & 0b0000_1111) << 2) | (b2 >> 6));
946 output[write + 3] = encode_base64_value::<A>(b2 & 0b0011_1111);
947
948 read += 3;
949 write += 4;
950 }
951
952 match INPUT_LEN - read {
953 0 => {}
954 1 => {
955 let b0 = input[read];
956 output[write] = encode_base64_value::<A>(b0 >> 2);
957 output[write + 1] = encode_base64_value::<A>((b0 & 0b0000_0011) << 4);
958 write += 2;
959 if PAD {
960 output[write] = b'=';
961 output[write + 1] = b'=';
962 }
963 }
964 2 => {
965 let b0 = input[read];
966 let b1 = input[read + 1];
967 output[write] = encode_base64_value::<A>(b0 >> 2);
968 output[write + 1] = encode_base64_value::<A>(((b0 & 0b0000_0011) << 4) | (b1 >> 4));
969 output[write + 2] = encode_base64_value::<A>((b1 & 0b0000_1111) << 2);
970 if PAD {
971 output[write + 3] = b'=';
972 }
973 }
974 _ => unreachable!(),
975 }
976
977 output
978 }
979
980 pub fn encode_slice(&self, input: &[u8], output: &mut [u8]) -> Result<usize, EncodeError> {
982 let required = checked_encoded_len(input.len(), PAD).ok_or(EncodeError::LengthOverflow)?;
983 if output.len() < required {
984 return Err(EncodeError::OutputTooSmall {
985 required,
986 available: output.len(),
987 });
988 }
989
990 let mut read = 0;
991 let mut write = 0;
992 while read + 3 <= input.len() {
993 let b0 = input[read];
994 let b1 = input[read + 1];
995 let b2 = input[read + 2];
996
997 output[write] = encode_base64_value::<A>(b0 >> 2);
998 output[write + 1] = encode_base64_value::<A>(((b0 & 0b0000_0011) << 4) | (b1 >> 4));
999 output[write + 2] = encode_base64_value::<A>(((b1 & 0b0000_1111) << 2) | (b2 >> 6));
1000 output[write + 3] = encode_base64_value::<A>(b2 & 0b0011_1111);
1001
1002 read += 3;
1003 write += 4;
1004 }
1005
1006 match input.len() - read {
1007 0 => {}
1008 1 => {
1009 let b0 = input[read];
1010 output[write] = encode_base64_value::<A>(b0 >> 2);
1011 output[write + 1] = encode_base64_value::<A>((b0 & 0b0000_0011) << 4);
1012 write += 2;
1013 if PAD {
1014 output[write] = b'=';
1015 output[write + 1] = b'=';
1016 write += 2;
1017 }
1018 }
1019 2 => {
1020 let b0 = input[read];
1021 let b1 = input[read + 1];
1022 output[write] = encode_base64_value::<A>(b0 >> 2);
1023 output[write + 1] = encode_base64_value::<A>(((b0 & 0b0000_0011) << 4) | (b1 >> 4));
1024 output[write + 2] = encode_base64_value::<A>((b1 & 0b0000_1111) << 2);
1025 write += 3;
1026 if PAD {
1027 output[write] = b'=';
1028 write += 1;
1029 }
1030 }
1031 _ => unreachable!(),
1032 }
1033
1034 Ok(write)
1035 }
1036
1037 #[cfg(feature = "alloc")]
1039 pub fn encode_vec(&self, input: &[u8]) -> Result<alloc::vec::Vec<u8>, EncodeError> {
1040 let required = checked_encoded_len(input.len(), PAD).ok_or(EncodeError::LengthOverflow)?;
1041 let mut output = alloc::vec![0; required];
1042 let written = self.encode_slice(input, &mut output)?;
1043 output.truncate(written);
1044 Ok(output)
1045 }
1046
1047 #[cfg(feature = "alloc")]
1062 pub fn encode_string(&self, input: &[u8]) -> Result<alloc::string::String, EncodeError> {
1063 let output = self.encode_vec(input)?;
1064 match alloc::string::String::from_utf8(output) {
1065 Ok(output) => Ok(output),
1066 Err(_) => unreachable!("base64 encoder produced non-UTF-8 output"),
1067 }
1068 }
1069
1070 pub fn encode_in_place<'a>(
1087 &self,
1088 buffer: &'a mut [u8],
1089 input_len: usize,
1090 ) -> Result<&'a mut [u8], EncodeError> {
1091 if input_len > buffer.len() {
1092 return Err(EncodeError::InputTooLarge {
1093 input_len,
1094 buffer_len: buffer.len(),
1095 });
1096 }
1097
1098 let required = checked_encoded_len(input_len, PAD).ok_or(EncodeError::LengthOverflow)?;
1099 if buffer.len() < required {
1100 return Err(EncodeError::OutputTooSmall {
1101 required,
1102 available: buffer.len(),
1103 });
1104 }
1105
1106 let mut read = input_len;
1107 let mut write = required;
1108
1109 match input_len % 3 {
1110 0 => {}
1111 1 => {
1112 read -= 1;
1113 let b0 = buffer[read];
1114 if PAD {
1115 write -= 4;
1116 buffer[write] = encode_base64_value::<A>(b0 >> 2);
1117 buffer[write + 1] = encode_base64_value::<A>((b0 & 0b0000_0011) << 4);
1118 buffer[write + 2] = b'=';
1119 buffer[write + 3] = b'=';
1120 } else {
1121 write -= 2;
1122 buffer[write] = encode_base64_value::<A>(b0 >> 2);
1123 buffer[write + 1] = encode_base64_value::<A>((b0 & 0b0000_0011) << 4);
1124 }
1125 }
1126 2 => {
1127 read -= 2;
1128 let b0 = buffer[read];
1129 let b1 = buffer[read + 1];
1130 if PAD {
1131 write -= 4;
1132 buffer[write] = encode_base64_value::<A>(b0 >> 2);
1133 buffer[write + 1] =
1134 encode_base64_value::<A>(((b0 & 0b0000_0011) << 4) | (b1 >> 4));
1135 buffer[write + 2] = encode_base64_value::<A>((b1 & 0b0000_1111) << 2);
1136 buffer[write + 3] = b'=';
1137 } else {
1138 write -= 3;
1139 buffer[write] = encode_base64_value::<A>(b0 >> 2);
1140 buffer[write + 1] =
1141 encode_base64_value::<A>(((b0 & 0b0000_0011) << 4) | (b1 >> 4));
1142 buffer[write + 2] = encode_base64_value::<A>((b1 & 0b0000_1111) << 2);
1143 }
1144 }
1145 _ => unreachable!(),
1146 }
1147
1148 while read > 0 {
1149 read -= 3;
1150 write -= 4;
1151 let b0 = buffer[read];
1152 let b1 = buffer[read + 1];
1153 let b2 = buffer[read + 2];
1154
1155 buffer[write] = encode_base64_value::<A>(b0 >> 2);
1156 buffer[write + 1] = encode_base64_value::<A>(((b0 & 0b0000_0011) << 4) | (b1 >> 4));
1157 buffer[write + 2] = encode_base64_value::<A>(((b1 & 0b0000_1111) << 2) | (b2 >> 6));
1158 buffer[write + 3] = encode_base64_value::<A>(b2 & 0b0011_1111);
1159 }
1160
1161 debug_assert_eq!(write, 0);
1162 Ok(&mut buffer[..required])
1163 }
1164
1165 pub fn decode_slice(&self, input: &[u8], output: &mut [u8]) -> Result<usize, DecodeError> {
1170 if input.is_empty() {
1171 return Ok(0);
1172 }
1173
1174 if PAD {
1175 decode_padded::<A>(input, output)
1176 } else {
1177 decode_unpadded::<A>(input, output)
1178 }
1179 }
1180
1181 #[cfg(feature = "alloc")]
1185 pub fn decode_vec(&self, input: &[u8]) -> Result<alloc::vec::Vec<u8>, DecodeError> {
1186 let required = validate_decode::<A, PAD>(input)?;
1187 let mut output = alloc::vec![0; required];
1188 let written = match self.decode_slice(input, &mut output) {
1189 Ok(written) => written,
1190 Err(err) => {
1191 output.fill(0);
1192 return Err(err);
1193 }
1194 };
1195 output.truncate(written);
1196 Ok(output)
1197 }
1198
1199 pub fn decode_in_place<'a>(&self, buffer: &'a mut [u8]) -> Result<&'a mut [u8], DecodeError> {
1211 let len = Self::decode_slice_to_start(buffer)?;
1212 Ok(&mut buffer[..len])
1213 }
1214
1215 fn decode_slice_to_start(buffer: &mut [u8]) -> Result<usize, DecodeError> {
1216 let input_len = buffer.len();
1217 let mut read = 0;
1218 let mut write = 0;
1219 while read + 4 <= input_len {
1220 let chunk = [
1221 buffer[read],
1222 buffer[read + 1],
1223 buffer[read + 2],
1224 buffer[read + 3],
1225 ];
1226 let written = decode_chunk::<A, PAD>(&chunk, &mut buffer[write..])
1227 .map_err(|err| err.with_index_offset(read))?;
1228 read += 4;
1229 write += written;
1230 if written < 3 {
1231 if read != input_len {
1232 return Err(DecodeError::InvalidPadding { index: read - 4 });
1233 }
1234 return Ok(write);
1235 }
1236 }
1237
1238 let rem = input_len - read;
1239 if rem == 0 {
1240 return Ok(write);
1241 }
1242 if PAD {
1243 return Err(DecodeError::InvalidLength);
1244 }
1245 let mut tail = [0u8; 3];
1246 tail[..rem].copy_from_slice(&buffer[read..input_len]);
1247 decode_tail_unpadded::<A>(&tail[..rem], &mut buffer[write..])
1248 .map_err(|err| err.with_index_offset(read))
1249 .map(|n| write + n)
1250 }
1251}
1252
1253#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1255pub enum EncodeError {
1256 LengthOverflow,
1258 InputTooLarge {
1260 input_len: usize,
1262 buffer_len: usize,
1264 },
1265 OutputTooSmall {
1267 required: usize,
1269 available: usize,
1271 },
1272}
1273
1274impl core::fmt::Display for EncodeError {
1275 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1276 match self {
1277 Self::LengthOverflow => f.write_str("base64 output length overflows usize"),
1278 Self::InputTooLarge {
1279 input_len,
1280 buffer_len,
1281 } => write!(
1282 f,
1283 "base64 input length {input_len} exceeds buffer length {buffer_len}"
1284 ),
1285 Self::OutputTooSmall {
1286 required,
1287 available,
1288 } => write!(
1289 f,
1290 "base64 output buffer too small: required {required}, available {available}"
1291 ),
1292 }
1293 }
1294}
1295
1296#[cfg(feature = "std")]
1297impl std::error::Error for EncodeError {}
1298
1299#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1301pub enum DecodeError {
1302 InvalidLength,
1304 InvalidByte {
1306 index: usize,
1308 byte: u8,
1310 },
1311 InvalidPadding {
1313 index: usize,
1315 },
1316 OutputTooSmall {
1318 required: usize,
1320 available: usize,
1322 },
1323}
1324
1325impl core::fmt::Display for DecodeError {
1326 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1327 match self {
1328 Self::InvalidLength => f.write_str("invalid base64 input length"),
1329 Self::InvalidByte { index, byte } => {
1330 write!(f, "invalid base64 byte 0x{byte:02x} at index {index}")
1331 }
1332 Self::InvalidPadding { index } => write!(f, "invalid base64 padding at index {index}"),
1333 Self::OutputTooSmall {
1334 required,
1335 available,
1336 } => write!(
1337 f,
1338 "base64 decode output buffer too small: required {required}, available {available}"
1339 ),
1340 }
1341 }
1342}
1343
1344impl DecodeError {
1345 fn with_index_offset(self, offset: usize) -> Self {
1346 match self {
1347 Self::InvalidByte { index, byte } => Self::InvalidByte {
1348 index: index + offset,
1349 byte,
1350 },
1351 Self::InvalidPadding { index } => Self::InvalidPadding {
1352 index: index + offset,
1353 },
1354 Self::InvalidLength | Self::OutputTooSmall { .. } => self,
1355 }
1356 }
1357}
1358
1359#[cfg(feature = "std")]
1360impl std::error::Error for DecodeError {}
1361
1362fn decode_padded<A: Alphabet>(input: &[u8], output: &mut [u8]) -> Result<usize, DecodeError> {
1363 if !input.len().is_multiple_of(4) {
1364 return Err(DecodeError::InvalidLength);
1365 }
1366 let required = decoded_len_padded(input)?;
1367 if output.len() < required {
1368 return Err(DecodeError::OutputTooSmall {
1369 required,
1370 available: output.len(),
1371 });
1372 }
1373
1374 let mut read = 0;
1375 let mut write = 0;
1376 while read < input.len() {
1377 let written = decode_chunk::<A, true>(&input[read..read + 4], &mut output[write..])
1378 .map_err(|err| err.with_index_offset(read))?;
1379 read += 4;
1380 write += written;
1381 if written < 3 && read != input.len() {
1382 return Err(DecodeError::InvalidPadding { index: read - 4 });
1383 }
1384 }
1385 Ok(write)
1386}
1387
1388#[cfg(feature = "alloc")]
1389fn validate_decode<A: Alphabet, const PAD: bool>(input: &[u8]) -> Result<usize, DecodeError> {
1390 if input.is_empty() {
1391 return Ok(0);
1392 }
1393
1394 if PAD {
1395 validate_padded::<A>(input)
1396 } else {
1397 validate_unpadded::<A>(input)
1398 }
1399}
1400
1401#[cfg(feature = "alloc")]
1402fn validate_padded<A: Alphabet>(input: &[u8]) -> Result<usize, DecodeError> {
1403 if !input.len().is_multiple_of(4) {
1404 return Err(DecodeError::InvalidLength);
1405 }
1406 let required = decoded_len_padded(input)?;
1407
1408 let mut read = 0;
1409 while read < input.len() {
1410 let written = validate_chunk::<A, true>(&input[read..read + 4])
1411 .map_err(|err| err.with_index_offset(read))?;
1412 read += 4;
1413 if written < 3 && read != input.len() {
1414 return Err(DecodeError::InvalidPadding { index: read - 4 });
1415 }
1416 }
1417
1418 Ok(required)
1419}
1420
1421#[cfg(feature = "alloc")]
1422fn validate_unpadded<A: Alphabet>(input: &[u8]) -> Result<usize, DecodeError> {
1423 let required = decoded_len_unpadded(input)?;
1424
1425 let mut read = 0;
1426 while read + 4 <= input.len() {
1427 validate_chunk::<A, false>(&input[read..read + 4])
1428 .map_err(|err| err.with_index_offset(read))?;
1429 read += 4;
1430 }
1431 validate_tail_unpadded::<A>(&input[read..]).map_err(|err| err.with_index_offset(read))?;
1432
1433 Ok(required)
1434}
1435
1436fn decode_unpadded<A: Alphabet>(input: &[u8], output: &mut [u8]) -> Result<usize, DecodeError> {
1437 let required = decoded_len_unpadded(input)?;
1438 if output.len() < required {
1439 return Err(DecodeError::OutputTooSmall {
1440 required,
1441 available: output.len(),
1442 });
1443 }
1444
1445 let mut read = 0;
1446 let mut write = 0;
1447 while read + 4 <= input.len() {
1448 let written = decode_chunk::<A, false>(&input[read..read + 4], &mut output[write..])
1449 .map_err(|err| err.with_index_offset(read))?;
1450 read += 4;
1451 write += written;
1452 }
1453 decode_tail_unpadded::<A>(&input[read..], &mut output[write..])
1454 .map_err(|err| err.with_index_offset(read))
1455 .map(|n| write + n)
1456}
1457
1458fn decoded_len_padded(input: &[u8]) -> Result<usize, DecodeError> {
1459 if input.is_empty() {
1460 return Ok(0);
1461 }
1462 if !input.len().is_multiple_of(4) {
1463 return Err(DecodeError::InvalidLength);
1464 }
1465 let mut padding = 0;
1466 if input[input.len() - 1] == b'=' {
1467 padding += 1;
1468 }
1469 if input[input.len() - 2] == b'=' {
1470 padding += 1;
1471 }
1472 if padding == 0
1473 && let Some(index) = input.iter().position(|byte| *byte == b'=')
1474 {
1475 return Err(DecodeError::InvalidPadding { index });
1476 }
1477 if padding > 0 {
1478 let first_pad = input.len() - padding;
1479 if let Some(index) = input[..first_pad].iter().position(|byte| *byte == b'=') {
1480 return Err(DecodeError::InvalidPadding { index });
1481 }
1482 }
1483 Ok(input.len() / 4 * 3 - padding)
1484}
1485
1486fn decoded_len_unpadded(input: &[u8]) -> Result<usize, DecodeError> {
1487 if input.len() % 4 == 1 {
1488 return Err(DecodeError::InvalidLength);
1489 }
1490 if let Some(index) = input.iter().position(|byte| *byte == b'=') {
1491 return Err(DecodeError::InvalidPadding { index });
1492 }
1493 Ok(decoded_capacity(input.len()))
1494}
1495
1496#[cfg(feature = "alloc")]
1497fn validate_chunk<A: Alphabet, const PAD: bool>(input: &[u8]) -> Result<usize, DecodeError> {
1498 debug_assert_eq!(input.len(), 4);
1499 let _v0 = decode_byte::<A>(input[0], 0)?;
1500 let v1 = decode_byte::<A>(input[1], 1)?;
1501
1502 match (input[2], input[3]) {
1503 (b'=', b'=') if PAD => {
1504 if v1 & 0b0000_1111 != 0 {
1505 return Err(DecodeError::InvalidPadding { index: 1 });
1506 }
1507 Ok(1)
1508 }
1509 (b'=', _) if PAD => Err(DecodeError::InvalidPadding { index: 2 }),
1510 (_, b'=') if PAD => {
1511 let v2 = decode_byte::<A>(input[2], 2)?;
1512 if v2 & 0b0000_0011 != 0 {
1513 return Err(DecodeError::InvalidPadding { index: 2 });
1514 }
1515 Ok(2)
1516 }
1517 (b'=', _) | (_, b'=') => Err(DecodeError::InvalidPadding {
1518 index: input.iter().position(|byte| *byte == b'=').unwrap_or(0),
1519 }),
1520 _ => {
1521 decode_byte::<A>(input[2], 2)?;
1522 decode_byte::<A>(input[3], 3)?;
1523 Ok(3)
1524 }
1525 }
1526}
1527
1528fn decode_chunk<A: Alphabet, const PAD: bool>(
1529 input: &[u8],
1530 output: &mut [u8],
1531) -> Result<usize, DecodeError> {
1532 debug_assert_eq!(input.len(), 4);
1533 let v0 = decode_byte::<A>(input[0], 0)?;
1534 let v1 = decode_byte::<A>(input[1], 1)?;
1535
1536 match (input[2], input[3]) {
1537 (b'=', b'=') if PAD => {
1538 if output.is_empty() {
1539 return Err(DecodeError::OutputTooSmall {
1540 required: 1,
1541 available: output.len(),
1542 });
1543 }
1544 if v1 & 0b0000_1111 != 0 {
1545 return Err(DecodeError::InvalidPadding { index: 1 });
1546 }
1547 output[0] = (v0 << 2) | (v1 >> 4);
1548 Ok(1)
1549 }
1550 (b'=', _) if PAD => Err(DecodeError::InvalidPadding { index: 2 }),
1551 (_, b'=') if PAD => {
1552 if output.len() < 2 {
1553 return Err(DecodeError::OutputTooSmall {
1554 required: 2,
1555 available: output.len(),
1556 });
1557 }
1558 let v2 = decode_byte::<A>(input[2], 2)?;
1559 if v2 & 0b0000_0011 != 0 {
1560 return Err(DecodeError::InvalidPadding { index: 2 });
1561 }
1562 output[0] = (v0 << 2) | (v1 >> 4);
1563 output[1] = (v1 << 4) | (v2 >> 2);
1564 Ok(2)
1565 }
1566 (b'=', _) | (_, b'=') => Err(DecodeError::InvalidPadding {
1567 index: input.iter().position(|byte| *byte == b'=').unwrap_or(0),
1568 }),
1569 _ => {
1570 if output.len() < 3 {
1571 return Err(DecodeError::OutputTooSmall {
1572 required: 3,
1573 available: output.len(),
1574 });
1575 }
1576 let v2 = decode_byte::<A>(input[2], 2)?;
1577 let v3 = decode_byte::<A>(input[3], 3)?;
1578 output[0] = (v0 << 2) | (v1 >> 4);
1579 output[1] = (v1 << 4) | (v2 >> 2);
1580 output[2] = (v2 << 6) | v3;
1581 Ok(3)
1582 }
1583 }
1584}
1585
1586#[cfg(feature = "alloc")]
1587fn validate_tail_unpadded<A: Alphabet>(input: &[u8]) -> Result<(), DecodeError> {
1588 match input.len() {
1589 0 => Ok(()),
1590 2 => {
1591 decode_byte::<A>(input[0], 0)?;
1592 let v1 = decode_byte::<A>(input[1], 1)?;
1593 if v1 & 0b0000_1111 != 0 {
1594 return Err(DecodeError::InvalidPadding { index: 1 });
1595 }
1596 Ok(())
1597 }
1598 3 => {
1599 decode_byte::<A>(input[0], 0)?;
1600 decode_byte::<A>(input[1], 1)?;
1601 let v2 = decode_byte::<A>(input[2], 2)?;
1602 if v2 & 0b0000_0011 != 0 {
1603 return Err(DecodeError::InvalidPadding { index: 2 });
1604 }
1605 Ok(())
1606 }
1607 _ => Err(DecodeError::InvalidLength),
1608 }
1609}
1610
1611fn decode_tail_unpadded<A: Alphabet>(
1612 input: &[u8],
1613 output: &mut [u8],
1614) -> Result<usize, DecodeError> {
1615 match input.len() {
1616 0 => Ok(0),
1617 2 => {
1618 if output.is_empty() {
1619 return Err(DecodeError::OutputTooSmall {
1620 required: 1,
1621 available: output.len(),
1622 });
1623 }
1624 let v0 = decode_byte::<A>(input[0], 0)?;
1625 let v1 = decode_byte::<A>(input[1], 1)?;
1626 if v1 & 0b0000_1111 != 0 {
1627 return Err(DecodeError::InvalidPadding { index: 1 });
1628 }
1629 output[0] = (v0 << 2) | (v1 >> 4);
1630 Ok(1)
1631 }
1632 3 => {
1633 if output.len() < 2 {
1634 return Err(DecodeError::OutputTooSmall {
1635 required: 2,
1636 available: output.len(),
1637 });
1638 }
1639 let v0 = decode_byte::<A>(input[0], 0)?;
1640 let v1 = decode_byte::<A>(input[1], 1)?;
1641 let v2 = decode_byte::<A>(input[2], 2)?;
1642 if v2 & 0b0000_0011 != 0 {
1643 return Err(DecodeError::InvalidPadding { index: 2 });
1644 }
1645 output[0] = (v0 << 2) | (v1 >> 4);
1646 output[1] = (v1 << 4) | (v2 >> 2);
1647 Ok(2)
1648 }
1649 _ => Err(DecodeError::InvalidLength),
1650 }
1651}
1652
1653fn decode_byte<A: Alphabet>(byte: u8, index: usize) -> Result<u8, DecodeError> {
1654 A::decode(byte).ok_or(DecodeError::InvalidByte { index, byte })
1655}
1656
1657#[cfg(test)]
1658mod tests {
1659 use super::*;
1660
1661 #[test]
1662 fn encodes_standard_vectors() {
1663 let vectors = [
1664 (&b""[..], &b""[..]),
1665 (&b"f"[..], &b"Zg=="[..]),
1666 (&b"fo"[..], &b"Zm8="[..]),
1667 (&b"foo"[..], &b"Zm9v"[..]),
1668 (&b"foob"[..], &b"Zm9vYg=="[..]),
1669 (&b"fooba"[..], &b"Zm9vYmE="[..]),
1670 (&b"foobar"[..], &b"Zm9vYmFy"[..]),
1671 ];
1672 for (input, expected) in vectors {
1673 let mut output = [0u8; 16];
1674 let written = STANDARD.encode_slice(input, &mut output).unwrap();
1675 assert_eq!(&output[..written], expected);
1676 }
1677 }
1678
1679 #[test]
1680 fn decodes_standard_vectors() {
1681 let vectors = [
1682 (&b""[..], &b""[..]),
1683 (&b"Zg=="[..], &b"f"[..]),
1684 (&b"Zm8="[..], &b"fo"[..]),
1685 (&b"Zm9v"[..], &b"foo"[..]),
1686 (&b"Zm9vYg=="[..], &b"foob"[..]),
1687 (&b"Zm9vYmE="[..], &b"fooba"[..]),
1688 (&b"Zm9vYmFy"[..], &b"foobar"[..]),
1689 ];
1690 for (input, expected) in vectors {
1691 let mut output = [0u8; 16];
1692 let written = STANDARD.decode_slice(input, &mut output).unwrap();
1693 assert_eq!(&output[..written], expected);
1694 }
1695 }
1696
1697 #[test]
1698 fn supports_unpadded_url_safe() {
1699 let mut encoded = [0u8; 16];
1700 let written = URL_SAFE_NO_PAD
1701 .encode_slice(b"\xfb\xff", &mut encoded)
1702 .unwrap();
1703 assert_eq!(&encoded[..written], b"-_8");
1704
1705 let mut decoded = [0u8; 2];
1706 let written = URL_SAFE_NO_PAD
1707 .decode_slice(&encoded[..written], &mut decoded)
1708 .unwrap();
1709 assert_eq!(&decoded[..written], b"\xfb\xff");
1710 }
1711
1712 #[test]
1713 fn decodes_in_place() {
1714 let mut buffer = *b"Zm9vYmFy";
1715 let decoded = STANDARD_NO_PAD.decode_in_place(&mut buffer).unwrap();
1716 assert_eq!(decoded, b"foobar");
1717 }
1718
1719 #[test]
1720 fn rejects_non_canonical_padding_bits() {
1721 let mut output = [0u8; 4];
1722 assert_eq!(
1723 STANDARD.decode_slice(b"Zh==", &mut output),
1724 Err(DecodeError::InvalidPadding { index: 1 })
1725 );
1726 assert_eq!(
1727 STANDARD.decode_slice(b"Zm9=", &mut output),
1728 Err(DecodeError::InvalidPadding { index: 2 })
1729 );
1730 }
1731}