1//! Correct, fast, and configurable [base64][] decoding and encoding. Base64
2//! transports binary data efficiently in contexts where only plain text is
3//! allowed.
4//!
5//! [base64]: https://developer.mozilla.org/en-US/docs/Glossary/Base64
6//!
7//! # Usage
8//!
9//! Use an [`Engine`] to decode or encode base64, configured with the base64
10//! alphabet and padding behavior best suited to your application.
11//!
12//! ## Engine setup
13//!
14//! There is more than one way to encode a stream of bytes as “base64”.
15//! Different applications use different encoding
16//! [alphabets][alphabet::Alphabet] and
17//! [padding behaviors][engine::general_purpose::GeneralPurposeConfig].
18//!
19//! ### Encoding alphabet
20//!
21//! Almost all base64 [alphabets][alphabet::Alphabet] use `A-Z`, `a-z`, and
22//! `0-9`, which gives nearly 64 characters (26 + 26 + 10 = 62), but they differ
23//! in their choice of their final 2.
24//!
25//! Most applications use the [standard][alphabet::STANDARD] alphabet specified
26//! in [RFC 4648][rfc-alphabet]. If that’s all you need, you can get started
27//! quickly by using the pre-configured
28//! [`STANDARD`][engine::general_purpose::STANDARD] engine, which is also available
29//! in the [`prelude`] module as shown here, if you prefer a minimal `use`
30//! footprint.
31//!
32#![cfg_attr(feature = "alloc", doc = "```")]
33#![cfg_attr(not(feature = "alloc"), doc = "```ignore")]
34//! use base64::prelude::*;
35//!
36//! # fn main() -> Result<(), base64::DecodeError> {
37//! assert_eq!(BASE64_STANDARD.decode(b"+uwgVQA=")?, b"\xFA\xEC\x20\x55\0");
38//! assert_eq!(BASE64_STANDARD.encode(b"\xFF\xEC\x20\x55\0"), "/+wgVQA=");
39//! # Ok(())
40//! # }
41//! ```
42//!
43//! [rfc-alphabet]: https://datatracker.ietf.org/doc/html/rfc4648#section-4
44//!
45//! Other common alphabets are available in the [`alphabet`] module.
46//!
47//! #### URL-safe alphabet
48//!
49//! The standard alphabet uses `+` and `/` as its two non-alphanumeric tokens,
50//! which cannot be safely used in URL’s without encoding them as `%2B` and
51//! `%2F`.
52//!
53//! To avoid that, some applications use a [“URL-safe” alphabet][alphabet::URL_SAFE],
54//! which uses `-` and `_` instead. To use that alternative alphabet, use the
55//! [`URL_SAFE`][engine::general_purpose::URL_SAFE] engine. This example doesn't
56//! use [`prelude`] to show what a more explicit `use` would look like.
57//!
58#![cfg_attr(feature = "alloc", doc = "```")]
59#![cfg_attr(not(feature = "alloc"), doc = "```ignore")]
60//! use base64::{engine::general_purpose::URL_SAFE, Engine as _};
61//!
62//! # fn main() -> Result<(), base64::DecodeError> {
63//! assert_eq!(URL_SAFE.decode(b"-uwgVQA=")?, b"\xFA\xEC\x20\x55\0");
64//! assert_eq!(URL_SAFE.encode(b"\xFF\xEC\x20\x55\0"), "_-wgVQA=");
65//! # Ok(())
66//! # }
67//! ```
68//!
69//! ### Padding characters
70//!
71//! Each base64 character represents 6 bits (2⁶ = 64) of the original binary
72//! data, and every 3 bytes of input binary data will encode to 4 base64
73//! characters (8 bits × 3 = 6 bits × 4 = 24 bits).
74//!
75//! When the input is not an even multiple of 3 bytes in length, [canonical][]
76//! base64 encoders insert padding characters at the end, so that the output
77//! length is always a multiple of 4:
78//!
79//! [canonical]: https://datatracker.ietf.org/doc/html/rfc4648#section-3.5
80//!
81#![cfg_attr(feature = "alloc", doc = "```")]
82#![cfg_attr(not(feature = "alloc"), doc = "```ignore")]
83//! use base64::{engine::general_purpose::STANDARD, Engine as _};
84//!
85//! assert_eq!(STANDARD.encode(b""), "");
86//! assert_eq!(STANDARD.encode(b"f"), "Zg==");
87//! assert_eq!(STANDARD.encode(b"fo"), "Zm8=");
88//! assert_eq!(STANDARD.encode(b"foo"), "Zm9v");
89//! ```
90//!
91//! Canonical encoding ensures that base64 encodings will be exactly the same,
92//! byte-for-byte, regardless of input length. But the `=` padding characters
93//! aren’t necessary for decoding, and they may be omitted by using a
94//! [`NO_PAD`][engine::general_purpose::NO_PAD] configuration:
95//!
96#![cfg_attr(feature = "alloc", doc = "```")]
97#![cfg_attr(not(feature = "alloc"), doc = "```ignore")]
98//! use base64::{engine::general_purpose::STANDARD_NO_PAD, Engine as _};
99//!
100//! assert_eq!(STANDARD_NO_PAD.encode(b""), "");
101//! assert_eq!(STANDARD_NO_PAD.encode(b"f"), "Zg");
102//! assert_eq!(STANDARD_NO_PAD.encode(b"fo"), "Zm8");
103//! assert_eq!(STANDARD_NO_PAD.encode(b"foo"), "Zm9v");
104//! ```
105//!
106//! The pre-configured `NO_PAD` engines will reject inputs containing padding
107//! `=` characters. To encode without padding and still accept padding while
108//! decoding, create an [engine][engine::general_purpose::GeneralPurpose] with
109//! that [padding mode][engine::DecodePaddingMode].
110//!
111#![cfg_attr(feature = "alloc", doc = "```")]
112#![cfg_attr(not(feature = "alloc"), doc = "```ignore")]
113//! # use base64::{engine::general_purpose::STANDARD_NO_PAD, Engine as _};
114//! assert_eq!(STANDARD_NO_PAD.decode(b"Zm8="), Err(base64::DecodeError::InvalidPadding));
115//! ```
116//!
117//! ### Further customization
118//!
119//! Decoding and encoding behavior can be customized by creating an
120//! [engine][engine::GeneralPurpose] with an [alphabet][alphabet::Alphabet] and
121//! [padding configuration][engine::GeneralPurposeConfig]:
122//!
123#![cfg_attr(feature = "alloc", doc = "```")]
124#![cfg_attr(not(feature = "alloc"), doc = "```ignore")]
125//! use base64::{engine, alphabet, Engine as _};
126//!
127//! // bizarro-world base64: +/ as the first symbols instead of the last
128//! let alphabet =
129//! alphabet::Alphabet::new("+/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")
130//! .unwrap();
131//!
132//! // a very weird config that encodes with padding but requires no padding when decoding...?
133//! let crazy_config = engine::GeneralPurposeConfig::new()
134//! .with_decode_allow_trailing_bits(true)
135//! .with_encode_padding(true)
136//! .with_decode_padding_mode(engine::DecodePaddingMode::RequireNone);
137//!
138//! let crazy_engine = engine::GeneralPurpose::new(&alphabet, crazy_config);
139//!
140//! let encoded = crazy_engine.encode(b"abc 123");
141//!
142//! ```
143//!
144//! ## Memory allocation
145//!
146//! The [decode][Engine::decode()] and [encode][Engine::encode()] engine methods
147//! allocate memory for their results – `decode` returns a `Vec<u8>` and
148//! `encode` returns a `String`. To instead decode or encode into a buffer that
149//! you allocated, use one of the alternative methods:
150//!
151//! #### Decoding
152//!
153//! | Method | Output | Allocates memory |
154//! | -------------------------- | ----------------------------- | ----------------------------- |
155//! | [`Engine::decode`] | returns a new `Vec<u8>` | always |
156//! | [`Engine::decode_vec`] | appends to provided `Vec<u8>` | if `Vec` lacks capacity |
157//! | [`Engine::decode_slice`] | writes to provided `&[u8]` | never
158//!
159//! #### Encoding
160//!
161//! | Method | Output | Allocates memory |
162//! | -------------------------- | ---------------------------- | ------------------------------ |
163//! | [`Engine::encode`] | returns a new `String` | always |
164//! | [`Engine::encode_string`] | appends to provided `String` | if `String` lacks capacity |
165//! | [`Engine::encode_slice`] | writes to provided `&[u8]` | never |
166//!
167//! ## Input and output
168//!
169//! The `base64` crate can [decode][Engine::decode()] and
170//! [encode][Engine::encode()] values in memory, or
171//! [`DecoderReader`][read::DecoderReader] and
172//! [`EncoderWriter`][write::EncoderWriter] provide streaming decoding and
173//! encoding for any [readable][std::io::Read] or [writable][std::io::Write]
174//! byte stream.
175//!
176//! #### Decoding
177//!
178#![cfg_attr(feature = "std", doc = "```")]
179#![cfg_attr(not(feature = "std"), doc = "```ignore")]
180//! # use std::io;
181//! use base64::{engine::general_purpose::STANDARD, read::DecoderReader};
182//!
183//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
184//! let mut input = io::stdin();
185//! let mut decoder = DecoderReader::new(&mut input, &STANDARD);
186//! io::copy(&mut decoder, &mut io::stdout())?;
187//! # Ok(())
188//! # }
189//! ```
190//!
191//! #### Encoding
192//!
193#![cfg_attr(feature = "std", doc = "```")]
194#![cfg_attr(not(feature = "std"), doc = "```ignore")]
195//! # use std::io;
196//! use base64::{engine::general_purpose::STANDARD, write::EncoderWriter};
197//!
198//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
199//! let mut output = io::stdout();
200//! let mut encoder = EncoderWriter::new(&mut output, &STANDARD);
201//! io::copy(&mut io::stdin(), &mut encoder)?;
202//! # Ok(())
203//! # }
204//! ```
205//!
206//! #### Display
207//!
208//! If you only need a base64 representation for implementing the
209//! [`Display`][std::fmt::Display] trait, use
210//! [`Base64Display`][display::Base64Display]:
211//!
212//! ```
213//! use base64::{display::Base64Display, engine::general_purpose::STANDARD};
214//!
215//! let value = Base64Display::new(b"\0\x01\x02\x03", &STANDARD);
216//! assert_eq!("base64: AAECAw==", format!("base64: {}", value));
217//! ```
218//!
219//! # Panics
220//!
221//! If length calculations result in overflowing `usize`, a panic will result.
222
223#![cfg_attr(feature = "cargo-clippy", allow(clippy::cast_lossless))]
224#![deny(
225 missing_docs,
226 trivial_casts,
227 trivial_numeric_casts,
228 unused_extern_crates,
229 unused_import_braces,
230 unused_results,
231 variant_size_differences,
232 warnings
233)]
234#![forbid(unsafe_code)]
235// Allow globally until https://github.com/rust-lang/rust-clippy/issues/8768 is resolved.
236// The desired state is to allow it only for the rstest_reuse import.
237#![allow(clippy::single_component_path_imports)]
238#![cfg_attr(not(any(feature = "std", test)), no_std)]
239
240#[cfg(any(feature = "alloc", test))]
241extern crate alloc;
242
243// has to be included at top level because of the way rstest_reuse defines its macros
244#[cfg(test)]
245use rstest_reuse;
246
247mod chunked_encoder;
248pub mod display;
249#[cfg(any(feature = "std", test))]
250pub mod read;
251#[cfg(any(feature = "std", test))]
252pub mod write;
253
254pub mod engine;
255pub use engine::Engine;
256
257pub mod alphabet;
258
259mod encode;
260#[allow(deprecated)]
261#[cfg(any(feature = "alloc", test))]
262pub use crate::encode::{encode, encode_engine, encode_engine_string};
263#[allow(deprecated)]
264pub use crate::encode::{encode_engine_slice, encoded_len, EncodeSliceError};
265
266mod decode;
267#[allow(deprecated)]
268#[cfg(any(feature = "alloc", test))]
269pub use crate::decode::{decode, decode_engine, decode_engine_vec};
270#[allow(deprecated)]
271pub use crate::decode::{decode_engine_slice, decoded_len_estimate, DecodeError, DecodeSliceError};
272
273pub mod prelude;
274
275#[cfg(test)]
276mod tests;
277
278const PAD_BYTE: u8 = b'=';
279