//! Correct, fast, and configurable [base64][] decoding and encoding. Base64 //! transports binary data efficiently in contexts where only plain text is //! allowed. //! //! [base64]: https://developer.mozilla.org/en-US/docs/Glossary/Base64 //! //! # Usage //! //! Use an [`Engine`] to decode or encode base64, configured with the base64 //! alphabet and padding behavior best suited to your application. //! //! ## Engine setup //! //! There is more than one way to encode a stream of bytes as “base64”. //! Different applications use different encoding //! [alphabets][alphabet::Alphabet] and //! [padding behaviors][engine::general_purpose::GeneralPurposeConfig]. //! //! ### Encoding alphabet //! //! Almost all base64 [alphabets][alphabet::Alphabet] use `A-Z`, `a-z`, and //! `0-9`, which gives nearly 64 characters (26 + 26 + 10 = 62), but they differ //! in their choice of their final 2. //! //! Most applications use the [standard][alphabet::STANDARD] alphabet specified //! in [RFC 4648][rfc-alphabet]. If that’s all you need, you can get started //! quickly by using the pre-configured //! [`STANDARD`][engine::general_purpose::STANDARD] engine, which is also available //! in the [`prelude`] module as shown here, if you prefer a minimal `use` //! footprint. //! #![cfg_attr(feature = "alloc", doc = "```")] #![cfg_attr(not(feature = "alloc"), doc = "```ignore")] //! use base64::prelude::*; //! //! # fn main() -> Result<(), base64::DecodeError> { //! assert_eq!(BASE64_STANDARD.decode(b"+uwgVQA=")?, b"\xFA\xEC\x20\x55\0"); //! assert_eq!(BASE64_STANDARD.encode(b"\xFF\xEC\x20\x55\0"), "/+wgVQA="); //! # Ok(()) //! # } //! ``` //! //! [rfc-alphabet]: https://datatracker.ietf.org/doc/html/rfc4648#section-4 //! //! Other common alphabets are available in the [`alphabet`] module. //! //! #### URL-safe alphabet //! //! The standard alphabet uses `+` and `/` as its two non-alphanumeric tokens, //! which cannot be safely used in URL’s without encoding them as `%2B` and //! `%2F`. //! //! To avoid that, some applications use a [“URL-safe” alphabet][alphabet::URL_SAFE], //! which uses `-` and `_` instead. To use that alternative alphabet, use the //! [`URL_SAFE`][engine::general_purpose::URL_SAFE] engine. This example doesn't //! use [`prelude`] to show what a more explicit `use` would look like. //! #![cfg_attr(feature = "alloc", doc = "```")] #![cfg_attr(not(feature = "alloc"), doc = "```ignore")] //! use base64::{engine::general_purpose::URL_SAFE, Engine as _}; //! //! # fn main() -> Result<(), base64::DecodeError> { //! assert_eq!(URL_SAFE.decode(b"-uwgVQA=")?, b"\xFA\xEC\x20\x55\0"); //! assert_eq!(URL_SAFE.encode(b"\xFF\xEC\x20\x55\0"), "_-wgVQA="); //! # Ok(()) //! # } //! ``` //! //! ### Padding characters //! //! Each base64 character represents 6 bits (2⁶ = 64) of the original binary //! data, and every 3 bytes of input binary data will encode to 4 base64 //! characters (8 bits × 3 = 6 bits × 4 = 24 bits). //! //! When the input is not an even multiple of 3 bytes in length, [canonical][] //! base64 encoders insert padding characters at the end, so that the output //! length is always a multiple of 4: //! //! [canonical]: https://datatracker.ietf.org/doc/html/rfc4648#section-3.5 //! #![cfg_attr(feature = "alloc", doc = "```")] #![cfg_attr(not(feature = "alloc"), doc = "```ignore")] //! use base64::{engine::general_purpose::STANDARD, Engine as _}; //! //! assert_eq!(STANDARD.encode(b""), ""); //! assert_eq!(STANDARD.encode(b"f"), "Zg=="); //! assert_eq!(STANDARD.encode(b"fo"), "Zm8="); //! assert_eq!(STANDARD.encode(b"foo"), "Zm9v"); //! ``` //! //! Canonical encoding ensures that base64 encodings will be exactly the same, //! byte-for-byte, regardless of input length. But the `=` padding characters //! aren’t necessary for decoding, and they may be omitted by using a //! [`NO_PAD`][engine::general_purpose::NO_PAD] configuration: //! #![cfg_attr(feature = "alloc", doc = "```")] #![cfg_attr(not(feature = "alloc"), doc = "```ignore")] //! use base64::{engine::general_purpose::STANDARD_NO_PAD, Engine as _}; //! //! assert_eq!(STANDARD_NO_PAD.encode(b""), ""); //! assert_eq!(STANDARD_NO_PAD.encode(b"f"), "Zg"); //! assert_eq!(STANDARD_NO_PAD.encode(b"fo"), "Zm8"); //! assert_eq!(STANDARD_NO_PAD.encode(b"foo"), "Zm9v"); //! ``` //! //! The pre-configured `NO_PAD` engines will reject inputs containing padding //! `=` characters. To encode without padding and still accept padding while //! decoding, create an [engine][engine::general_purpose::GeneralPurpose] with //! that [padding mode][engine::DecodePaddingMode]. //! #![cfg_attr(feature = "alloc", doc = "```")] #![cfg_attr(not(feature = "alloc"), doc = "```ignore")] //! # use base64::{engine::general_purpose::STANDARD_NO_PAD, Engine as _}; //! assert_eq!(STANDARD_NO_PAD.decode(b"Zm8="), Err(base64::DecodeError::InvalidPadding)); //! ``` //! //! ### Further customization //! //! Decoding and encoding behavior can be customized by creating an //! [engine][engine::GeneralPurpose] with an [alphabet][alphabet::Alphabet] and //! [padding configuration][engine::GeneralPurposeConfig]: //! #![cfg_attr(feature = "alloc", doc = "```")] #![cfg_attr(not(feature = "alloc"), doc = "```ignore")] //! use base64::{engine, alphabet, Engine as _}; //! //! // bizarro-world base64: +/ as the first symbols instead of the last //! let alphabet = //! alphabet::Alphabet::new("+/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") //! .unwrap(); //! //! // a very weird config that encodes with padding but requires no padding when decoding...? //! let crazy_config = engine::GeneralPurposeConfig::new() //! .with_decode_allow_trailing_bits(true) //! .with_encode_padding(true) //! .with_decode_padding_mode(engine::DecodePaddingMode::RequireNone); //! //! let crazy_engine = engine::GeneralPurpose::new(&alphabet, crazy_config); //! //! let encoded = crazy_engine.encode(b"abc 123"); //! //! ``` //! //! ## Memory allocation //! //! The [decode][Engine::decode()] and [encode][Engine::encode()] engine methods //! allocate memory for their results – `decode` returns a `Vec` and //! `encode` returns a `String`. To instead decode or encode into a buffer that //! you allocated, use one of the alternative methods: //! //! #### Decoding //! //! | Method | Output | Allocates memory | //! | -------------------------- | ----------------------------- | ----------------------------- | //! | [`Engine::decode`] | returns a new `Vec` | always | //! | [`Engine::decode_vec`] | appends to provided `Vec` | if `Vec` lacks capacity | //! | [`Engine::decode_slice`] | writes to provided `&[u8]` | never //! //! #### Encoding //! //! | Method | Output | Allocates memory | //! | -------------------------- | ---------------------------- | ------------------------------ | //! | [`Engine::encode`] | returns a new `String` | always | //! | [`Engine::encode_string`] | appends to provided `String` | if `String` lacks capacity | //! | [`Engine::encode_slice`] | writes to provided `&[u8]` | never | //! //! ## Input and output //! //! The `base64` crate can [decode][Engine::decode()] and //! [encode][Engine::encode()] values in memory, or //! [`DecoderReader`][read::DecoderReader] and //! [`EncoderWriter`][write::EncoderWriter] provide streaming decoding and //! encoding for any [readable][std::io::Read] or [writable][std::io::Write] //! byte stream. //! //! #### Decoding //! #![cfg_attr(feature = "std", doc = "```")] #![cfg_attr(not(feature = "std"), doc = "```ignore")] //! # use std::io; //! use base64::{engine::general_purpose::STANDARD, read::DecoderReader}; //! //! # fn main() -> Result<(), Box> { //! let mut input = io::stdin(); //! let mut decoder = DecoderReader::new(&mut input, &STANDARD); //! io::copy(&mut decoder, &mut io::stdout())?; //! # Ok(()) //! # } //! ``` //! //! #### Encoding //! #![cfg_attr(feature = "std", doc = "```")] #![cfg_attr(not(feature = "std"), doc = "```ignore")] //! # use std::io; //! use base64::{engine::general_purpose::STANDARD, write::EncoderWriter}; //! //! # fn main() -> Result<(), Box> { //! let mut output = io::stdout(); //! let mut encoder = EncoderWriter::new(&mut output, &STANDARD); //! io::copy(&mut io::stdin(), &mut encoder)?; //! # Ok(()) //! # } //! ``` //! //! #### Display //! //! If you only need a base64 representation for implementing the //! [`Display`][std::fmt::Display] trait, use //! [`Base64Display`][display::Base64Display]: //! //! ``` //! use base64::{display::Base64Display, engine::general_purpose::STANDARD}; //! //! let value = Base64Display::new(b"\0\x01\x02\x03", &STANDARD); //! assert_eq!("base64: AAECAw==", format!("base64: {}", value)); //! ``` //! //! # Panics //! //! If length calculations result in overflowing `usize`, a panic will result. #![cfg_attr(feature = "cargo-clippy", allow(clippy::cast_lossless))] #![deny( missing_docs, trivial_casts, trivial_numeric_casts, unused_extern_crates, unused_import_braces, unused_results, variant_size_differences, warnings )] #![forbid(unsafe_code)] // Allow globally until https://github.com/rust-lang/rust-clippy/issues/8768 is resolved. // The desired state is to allow it only for the rstest_reuse import. #![allow(clippy::single_component_path_imports)] #![cfg_attr(not(any(feature = "std", test)), no_std)] #[cfg(any(feature = "alloc", test))] extern crate alloc; // has to be included at top level because of the way rstest_reuse defines its macros #[cfg(test)] use rstest_reuse; mod chunked_encoder; pub mod display; #[cfg(any(feature = "std", test))] pub mod read; #[cfg(any(feature = "std", test))] pub mod write; pub mod engine; pub use engine::Engine; pub mod alphabet; mod encode; #[allow(deprecated)] #[cfg(any(feature = "alloc", test))] pub use crate::encode::{encode, encode_engine, encode_engine_string}; #[allow(deprecated)] pub use crate::encode::{encode_engine_slice, encoded_len, EncodeSliceError}; mod decode; #[allow(deprecated)] #[cfg(any(feature = "alloc", test))] pub use crate::decode::{decode, decode_engine, decode_engine_vec}; #[allow(deprecated)] pub use crate::decode::{decode_engine_slice, decoded_len_estimate, DecodeError, DecodeSliceError}; pub mod prelude; #[cfg(test)] mod tests; const PAD_BYTE: u8 = b'=';