| 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))] |
| 241 | extern crate alloc; |
| 242 | |
| 243 | // has to be included at top level because of the way rstest_reuse defines its macros |
| 244 | #[cfg (test)] |
| 245 | use rstest_reuse; |
| 246 | |
| 247 | mod chunked_encoder; |
| 248 | pub mod display; |
| 249 | #[cfg (any(feature = "std" , test))] |
| 250 | pub mod read; |
| 251 | #[cfg (any(feature = "std" , test))] |
| 252 | pub mod write; |
| 253 | |
| 254 | pub mod engine; |
| 255 | pub use engine::Engine; |
| 256 | |
| 257 | pub mod alphabet; |
| 258 | |
| 259 | mod encode; |
| 260 | #[allow (deprecated)] |
| 261 | #[cfg (any(feature = "alloc" , test))] |
| 262 | pub use crate::encode::{encode, encode_engine, encode_engine_string}; |
| 263 | #[allow (deprecated)] |
| 264 | pub use crate::encode::{encode_engine_slice, encoded_len, EncodeSliceError}; |
| 265 | |
| 266 | mod decode; |
| 267 | #[allow (deprecated)] |
| 268 | #[cfg (any(feature = "alloc" , test))] |
| 269 | pub use crate::decode::{decode, decode_engine, decode_engine_vec}; |
| 270 | #[allow (deprecated)] |
| 271 | pub use crate::decode::{decode_engine_slice, decoded_len_estimate, DecodeError, DecodeSliceError}; |
| 272 | |
| 273 | pub mod prelude; |
| 274 | |
| 275 | #[cfg (test)] |
| 276 | mod tests; |
| 277 | |
| 278 | const PAD_BYTE: u8 = b'=' ; |
| 279 | |