1 //! # Configs 2 //! 3 //! There isn't just one type of Base64; that would be too simple. You need to choose a character 4 //! set (standard, URL-safe, etc) and padding suffix (yes/no). 5 //! The `Config` struct encapsulates this info. There are some common configs included: `STANDARD`, 6 //! `URL_SAFE`, etc. You can also make your own `Config` if needed. 7 //! 8 //! The functions that don't have `config` in the name (e.g. `encode()` and `decode()`) use the 9 //! `STANDARD` config . 10 //! 11 //! The functions that write to a slice (the ones that end in `_slice`) are generally the fastest 12 //! because they don't need to resize anything. If it fits in your workflow and you care about 13 //! performance, keep using the same buffer (growing as need be) and use the `_slice` methods for 14 //! the best performance. 15 //! 16 //! # Encoding 17 //! 18 //! Several different encoding functions are available to you depending on your desire for 19 //! convenience vs performance. 20 //! 21 //! | Function | Output | Allocates | 22 //! | ----------------------- | ---------------------------- | ------------------------------ | 23 //! | `encode` | Returns a new `String` | Always | 24 //! | `encode_config` | Returns a new `String` | Always | 25 //! | `encode_config_buf` | Appends to provided `String` | Only if `String` needs to grow | 26 //! | `encode_config_slice` | Writes to provided `&[u8]` | Never | 27 //! 28 //! All of the encoding functions that take a `Config` will pad as per the config. 29 //! 30 //! # Decoding 31 //! 32 //! Just as for encoding, there are different decoding functions available. 33 //! 34 //! | Function | Output | Allocates | 35 //! | ----------------------- | ----------------------------- | ------------------------------ | 36 //! | `decode` | Returns a new `Vec<u8>` | Always | 37 //! | `decode_config` | Returns a new `Vec<u8>` | Always | 38 //! | `decode_config_buf` | Appends to provided `Vec<u8>` | Only if `Vec` needs to grow | 39 //! | `decode_config_slice` | Writes to provided `&[u8]` | Never | 40 //! 41 //! Unlike encoding, where all possible input is valid, decoding can fail (see `DecodeError`). 42 //! 43 //! Input can be invalid because it has invalid characters or invalid padding. (No padding at all is 44 //! valid, but excess padding is not.) Whitespace in the input is invalid. 45 //! 46 //! # `Read` and `Write` 47 //! 48 //! To map a `Read` of b64 bytes to the decoded bytes, wrap a reader (file, network socket, etc) 49 //! with `base64::read::DecoderReader`. To write raw bytes and have them b64 encoded on the fly, 50 //! wrap a writer with `base64::write::EncoderWriter`. There is some performance overhead (15% or 51 //! so) because of the necessary buffer shuffling -- still fast enough that almost nobody cares. 52 //! Also, these implementations do not heap allocate. 53 //! 54 //! # Panics 55 //! 56 //! If length calculations result in overflowing `usize`, a panic will result. 57 //! 58 //! The `_slice` flavors of encode or decode will panic if the provided output slice is too small, 59 60 #![cfg_attr(feature = "cargo-clippy", allow(clippy::cast_lossless))] 61 #![deny( 62 missing_docs, 63 trivial_casts, 64 trivial_numeric_casts, 65 unused_extern_crates, 66 unused_import_braces, 67 unused_results, 68 variant_size_differences, 69 warnings 70 )] 71 #![forbid(unsafe_code)] 72 #![cfg_attr(not(any(feature = "std", test)), no_std)] 73 74 #[cfg(all(feature = "alloc", not(any(feature = "std", test))))] 75 extern crate alloc; 76 #[cfg(any(feature = "std", test))] 77 extern crate std as alloc; 78 79 mod chunked_encoder; 80 pub mod display; 81 #[cfg(any(feature = "std", test))] 82 pub mod read; 83 mod tables; 84 #[cfg(any(feature = "std", test))] 85 pub mod write; 86 87 mod encode; 88 pub use crate::encode::encode_config_slice; 89 #[cfg(any(feature = "alloc", feature = "std", test))] 90 pub use crate::encode::{encode, encode_config, encode_config_buf}; 91 92 mod decode; 93 #[cfg(any(feature = "alloc", feature = "std", test))] 94 pub use crate::decode::{decode, decode_config, decode_config_buf}; 95 pub use crate::decode::{decode_config_slice, DecodeError}; 96 97 #[cfg(test)] 98 mod tests; 99 100 /// Available encoding character sets 101 #[derive(Clone, Copy, Debug)] 102 pub enum CharacterSet { 103 /// The standard character set (uses `+` and `/`). 104 /// 105 /// See [RFC 3548](https://tools.ietf.org/html/rfc3548#section-3). 106 Standard, 107 /// The URL safe character set (uses `-` and `_`). 108 /// 109 /// See [RFC 3548](https://tools.ietf.org/html/rfc3548#section-4). 110 UrlSafe, 111 /// The `crypt(3)` character set (uses `./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`). 112 /// 113 /// Not standardized, but folk wisdom on the net asserts that this alphabet is what crypt uses. 114 Crypt, 115 /// The bcrypt character set (uses `./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789`). 116 Bcrypt, 117 /// The character set used in IMAP-modified UTF-7 (uses `+` and `,`). 118 /// 119 /// See [RFC 3501](https://tools.ietf.org/html/rfc3501#section-5.1.3) 120 ImapMutf7, 121 /// The character set used in BinHex 4.0 files. 122 /// 123 /// See [BinHex 4.0 Definition](http://files.stairways.com/other/binhex-40-specs-info.txt) 124 BinHex, 125 } 126 127 impl CharacterSet { encode_table(self) -> &'static [u8; 64]128 fn encode_table(self) -> &'static [u8; 64] { 129 match self { 130 CharacterSet::Standard => tables::STANDARD_ENCODE, 131 CharacterSet::UrlSafe => tables::URL_SAFE_ENCODE, 132 CharacterSet::Crypt => tables::CRYPT_ENCODE, 133 CharacterSet::Bcrypt => tables::BCRYPT_ENCODE, 134 CharacterSet::ImapMutf7 => tables::IMAP_MUTF7_ENCODE, 135 CharacterSet::BinHex => tables::BINHEX_ENCODE, 136 } 137 } 138 decode_table(self) -> &'static [u8; 256]139 fn decode_table(self) -> &'static [u8; 256] { 140 match self { 141 CharacterSet::Standard => tables::STANDARD_DECODE, 142 CharacterSet::UrlSafe => tables::URL_SAFE_DECODE, 143 CharacterSet::Crypt => tables::CRYPT_DECODE, 144 CharacterSet::Bcrypt => tables::BCRYPT_DECODE, 145 CharacterSet::ImapMutf7 => tables::IMAP_MUTF7_DECODE, 146 CharacterSet::BinHex => tables::BINHEX_DECODE, 147 } 148 } 149 } 150 151 /// Contains configuration parameters for base64 encoding 152 #[derive(Clone, Copy, Debug)] 153 pub struct Config { 154 /// Character set to use 155 char_set: CharacterSet, 156 /// True to pad output with `=` characters 157 pad: bool, 158 /// True to ignore excess nonzero bits in the last few symbols, otherwise an error is returned. 159 decode_allow_trailing_bits: bool, 160 } 161 162 impl Config { 163 /// Create a new `Config`. new(char_set: CharacterSet, pad: bool) -> Config164 pub const fn new(char_set: CharacterSet, pad: bool) -> Config { 165 Config { 166 char_set, 167 pad, 168 decode_allow_trailing_bits: false, 169 } 170 } 171 172 /// Sets whether to pad output with `=` characters. pad(self, pad: bool) -> Config173 pub const fn pad(self, pad: bool) -> Config { 174 Config { pad, ..self } 175 } 176 177 /// Sets whether to emit errors for nonzero trailing bits. 178 /// 179 /// This is useful when implementing 180 /// [forgiving-base64 decode](https://infra.spec.whatwg.org/#forgiving-base64-decode). decode_allow_trailing_bits(self, allow: bool) -> Config181 pub const fn decode_allow_trailing_bits(self, allow: bool) -> Config { 182 Config { 183 decode_allow_trailing_bits: allow, 184 ..self 185 } 186 } 187 } 188 189 /// Standard character set with padding. 190 pub const STANDARD: Config = Config { 191 char_set: CharacterSet::Standard, 192 pad: true, 193 decode_allow_trailing_bits: false, 194 }; 195 196 /// Standard character set without padding. 197 pub const STANDARD_NO_PAD: Config = Config { 198 char_set: CharacterSet::Standard, 199 pad: false, 200 decode_allow_trailing_bits: false, 201 }; 202 203 /// URL-safe character set with padding 204 pub const URL_SAFE: Config = Config { 205 char_set: CharacterSet::UrlSafe, 206 pad: true, 207 decode_allow_trailing_bits: false, 208 }; 209 210 /// URL-safe character set without padding 211 pub const URL_SAFE_NO_PAD: Config = Config { 212 char_set: CharacterSet::UrlSafe, 213 pad: false, 214 decode_allow_trailing_bits: false, 215 }; 216 217 /// As per `crypt(3)` requirements 218 pub const CRYPT: Config = Config { 219 char_set: CharacterSet::Crypt, 220 pad: false, 221 decode_allow_trailing_bits: false, 222 }; 223 224 /// Bcrypt character set 225 pub const BCRYPT: Config = Config { 226 char_set: CharacterSet::Bcrypt, 227 pad: false, 228 decode_allow_trailing_bits: false, 229 }; 230 231 /// IMAP modified UTF-7 requirements 232 pub const IMAP_MUTF7: Config = Config { 233 char_set: CharacterSet::ImapMutf7, 234 pad: false, 235 decode_allow_trailing_bits: false, 236 }; 237 238 /// BinHex character set 239 pub const BINHEX: Config = Config { 240 char_set: CharacterSet::BinHex, 241 pad: false, 242 decode_allow_trailing_bits: false, 243 }; 244 245 const PAD_BYTE: u8 = b'='; 246