//! # Configs //! //! There isn't just one type of Base64; that would be too simple. You need to choose a character //! set (standard, URL-safe, etc) and padding suffix (yes/no). //! The `Config` struct encapsulates this info. There are some common configs included: `STANDARD`, //! `URL_SAFE`, etc. You can also make your own `Config` if needed. //! //! The functions that don't have `config` in the name (e.g. `encode()` and `decode()`) use the //! `STANDARD` config . //! //! The functions that write to a slice (the ones that end in `_slice`) are generally the fastest //! because they don't need to resize anything. If it fits in your workflow and you care about //! performance, keep using the same buffer (growing as need be) and use the `_slice` methods for //! the best performance. //! //! # Encoding //! //! Several different encoding functions are available to you depending on your desire for //! convenience vs performance. //! //! | Function | Output | Allocates | //! | ----------------------- | ---------------------------- | ------------------------------ | //! | `encode` | Returns a new `String` | Always | //! | `encode_config` | Returns a new `String` | Always | //! | `encode_config_buf` | Appends to provided `String` | Only if `String` needs to grow | //! | `encode_config_slice` | Writes to provided `&[u8]` | Never | //! //! All of the encoding functions that take a `Config` will pad as per the config. //! //! # Decoding //! //! Just as for encoding, there are different decoding functions available. //! //! | Function | Output | Allocates | //! | ----------------------- | ----------------------------- | ------------------------------ | //! | `decode` | Returns a new `Vec` | Always | //! | `decode_config` | Returns a new `Vec` | Always | //! | `decode_config_buf` | Appends to provided `Vec` | Only if `Vec` needs to grow | //! | `decode_config_slice` | Writes to provided `&[u8]` | Never | //! //! Unlike encoding, where all possible input is valid, decoding can fail (see `DecodeError`). //! //! Input can be invalid because it has invalid characters or invalid padding. (No padding at all is //! valid, but excess padding is not.) Whitespace in the input is invalid. //! //! # `Read` and `Write` //! //! To map a `Read` of b64 bytes to the decoded bytes, wrap a reader (file, network socket, etc) //! with `base64::read::DecoderReader`. To write raw bytes and have them b64 encoded on the fly, //! wrap a writer with `base64::write::EncoderWriter`. There is some performance overhead (15% or //! so) because of the necessary buffer shuffling -- still fast enough that almost nobody cares. //! Also, these implementations do not heap allocate. //! //! # Panics //! //! If length calculations result in overflowing `usize`, a panic will result. //! //! The `_slice` flavors of encode or decode will panic if the provided output slice is too small, #![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)] #![cfg_attr(not(any(feature = "std", test)), no_std)] #[cfg(all(feature = "alloc", not(any(feature = "std", test))))] extern crate alloc; #[cfg(any(feature = "std", test))] extern crate std as alloc; mod chunked_encoder; pub mod display; #[cfg(any(feature = "std", test))] pub mod read; mod tables; #[cfg(any(feature = "std", test))] pub mod write; mod encode; pub use crate::encode::encode_config_slice; #[cfg(any(feature = "alloc", feature = "std", test))] pub use crate::encode::{encode, encode_config, encode_config_buf}; mod decode; #[cfg(any(feature = "alloc", feature = "std", test))] pub use crate::decode::{decode, decode_config, decode_config_buf}; pub use crate::decode::{decode_config_slice, DecodeError}; #[cfg(test)] mod tests; /// Available encoding character sets #[derive(Clone, Copy, Debug)] pub enum CharacterSet { /// The standard character set (uses `+` and `/`). /// /// See [RFC 3548](https://tools.ietf.org/html/rfc3548#section-3). Standard, /// The URL safe character set (uses `-` and `_`). /// /// See [RFC 3548](https://tools.ietf.org/html/rfc3548#section-4). UrlSafe, /// The `crypt(3)` character set (uses `./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`). /// /// Not standardized, but folk wisdom on the net asserts that this alphabet is what crypt uses. Crypt, /// The bcrypt character set (uses `./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789`). Bcrypt, /// The character set used in IMAP-modified UTF-7 (uses `+` and `,`). /// /// See [RFC 3501](https://tools.ietf.org/html/rfc3501#section-5.1.3) ImapMutf7, /// The character set used in BinHex 4.0 files. /// /// See [BinHex 4.0 Definition](http://files.stairways.com/other/binhex-40-specs-info.txt) BinHex, } impl CharacterSet { fn encode_table(self) -> &'static [u8; 64] { match self { CharacterSet::Standard => tables::STANDARD_ENCODE, CharacterSet::UrlSafe => tables::URL_SAFE_ENCODE, CharacterSet::Crypt => tables::CRYPT_ENCODE, CharacterSet::Bcrypt => tables::BCRYPT_ENCODE, CharacterSet::ImapMutf7 => tables::IMAP_MUTF7_ENCODE, CharacterSet::BinHex => tables::BINHEX_ENCODE, } } fn decode_table(self) -> &'static [u8; 256] { match self { CharacterSet::Standard => tables::STANDARD_DECODE, CharacterSet::UrlSafe => tables::URL_SAFE_DECODE, CharacterSet::Crypt => tables::CRYPT_DECODE, CharacterSet::Bcrypt => tables::BCRYPT_DECODE, CharacterSet::ImapMutf7 => tables::IMAP_MUTF7_DECODE, CharacterSet::BinHex => tables::BINHEX_DECODE, } } } /// Contains configuration parameters for base64 encoding #[derive(Clone, Copy, Debug)] pub struct Config { /// Character set to use char_set: CharacterSet, /// True to pad output with `=` characters pad: bool, /// True to ignore excess nonzero bits in the last few symbols, otherwise an error is returned. decode_allow_trailing_bits: bool, } impl Config { /// Create a new `Config`. pub const fn new(char_set: CharacterSet, pad: bool) -> Config { Config { char_set, pad, decode_allow_trailing_bits: false, } } /// Sets whether to pad output with `=` characters. pub const fn pad(self, pad: bool) -> Config { Config { pad, ..self } } /// Sets whether to emit errors for nonzero trailing bits. /// /// This is useful when implementing /// [forgiving-base64 decode](https://infra.spec.whatwg.org/#forgiving-base64-decode). pub const fn decode_allow_trailing_bits(self, allow: bool) -> Config { Config { decode_allow_trailing_bits: allow, ..self } } } /// Standard character set with padding. pub const STANDARD: Config = Config { char_set: CharacterSet::Standard, pad: true, decode_allow_trailing_bits: false, }; /// Standard character set without padding. pub const STANDARD_NO_PAD: Config = Config { char_set: CharacterSet::Standard, pad: false, decode_allow_trailing_bits: false, }; /// URL-safe character set with padding pub const URL_SAFE: Config = Config { char_set: CharacterSet::UrlSafe, pad: true, decode_allow_trailing_bits: false, }; /// URL-safe character set without padding pub const URL_SAFE_NO_PAD: Config = Config { char_set: CharacterSet::UrlSafe, pad: false, decode_allow_trailing_bits: false, }; /// As per `crypt(3)` requirements pub const CRYPT: Config = Config { char_set: CharacterSet::Crypt, pad: false, decode_allow_trailing_bits: false, }; /// Bcrypt character set pub const BCRYPT: Config = Config { char_set: CharacterSet::Bcrypt, pad: false, decode_allow_trailing_bits: false, }; /// IMAP modified UTF-7 requirements pub const IMAP_MUTF7: Config = Config { char_set: CharacterSet::ImapMutf7, pad: false, decode_allow_trailing_bits: false, }; /// BinHex character set pub const BINHEX: Config = Config { char_set: CharacterSet::BinHex, pad: false, decode_allow_trailing_bits: false, }; const PAD_BYTE: u8 = b'=';