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 //! # Panics 47 //! 48 //! If length calculations result in overflowing `usize`, a panic will result. 49 //! 50 //! The `_slice` flavors of encode or decode will panic if the provided output slice is too small, 51 52 #![cfg_attr(feature = "cargo-clippy", allow(clippy::cast_lossless))] 53 #![deny( 54 missing_docs, 55 trivial_casts, 56 trivial_numeric_casts, 57 unused_extern_crates, 58 unused_import_braces, 59 unused_results, 60 variant_size_differences, 61 warnings 62 )] 63 #![forbid(unsafe_code)] 64 #![cfg_attr(not(any(feature = "std", test)), no_std)] 65 66 #[cfg(all(feature = "alloc", not(any(feature = "std", test))))] 67 extern crate alloc; 68 #[cfg(any(feature = "std", test))] 69 extern crate std as alloc; 70 71 #[cfg(test)] 72 #[macro_use] 73 extern crate doc_comment; 74 75 #[cfg(test)] 76 doctest!("../README.md"); 77 78 mod chunked_encoder; 79 pub mod display; 80 mod tables; 81 #[cfg(any(feature = "std", test))] 82 pub mod write; 83 84 mod encode; 85 pub use crate::encode::encode_config_slice; 86 #[cfg(any(feature = "alloc", feature = "std", test))] 87 pub use crate::encode::{encode, encode_config, encode_config_buf}; 88 89 mod decode; 90 #[cfg(any(feature = "alloc", feature = "std", test))] 91 pub use crate::decode::{decode, decode_config, decode_config_buf}; 92 pub use crate::decode::{decode_config_slice, DecodeError}; 93 94 #[cfg(test)] 95 mod tests; 96 97 /// Available encoding character sets 98 #[derive(Clone, Copy, Debug)] 99 pub enum CharacterSet { 100 /// The standard character set (uses `+` and `/`). 101 /// 102 /// See [RFC 3548](https://tools.ietf.org/html/rfc3548#section-3). 103 Standard, 104 /// The URL safe character set (uses `-` and `_`). 105 /// 106 /// See [RFC 3548](https://tools.ietf.org/html/rfc3548#section-4). 107 UrlSafe, 108 /// The `crypt(3)` character set (uses `./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`). 109 /// 110 /// Not standardized, but folk wisdom on the net asserts that this alphabet is what crypt uses. 111 Crypt, 112 } 113 114 impl CharacterSet { encode_table(self) -> &'static [u8; 64]115 fn encode_table(self) -> &'static [u8; 64] { 116 match self { 117 CharacterSet::Standard => tables::STANDARD_ENCODE, 118 CharacterSet::UrlSafe => tables::URL_SAFE_ENCODE, 119 CharacterSet::Crypt => tables::CRYPT_ENCODE, 120 } 121 } 122 decode_table(self) -> &'static [u8; 256]123 fn decode_table(self) -> &'static [u8; 256] { 124 match self { 125 CharacterSet::Standard => tables::STANDARD_DECODE, 126 CharacterSet::UrlSafe => tables::URL_SAFE_DECODE, 127 CharacterSet::Crypt => tables::CRYPT_DECODE, 128 } 129 } 130 } 131 132 /// Contains configuration parameters for base64 encoding 133 #[derive(Clone, Copy, Debug)] 134 pub struct Config { 135 /// Character set to use 136 char_set: CharacterSet, 137 /// True to pad output with `=` characters 138 pad: bool, 139 /// True to ignore excess nonzero bits in the last few symbols, otherwise an error is returned. 140 decode_allow_trailing_bits: bool, 141 } 142 143 impl Config { 144 /// Create a new `Config`. new(char_set: CharacterSet, pad: bool) -> Config145 pub fn new(char_set: CharacterSet, pad: bool) -> Config { 146 Config { 147 char_set, 148 pad, 149 decode_allow_trailing_bits: false, 150 } 151 } 152 153 /// Sets whether to pad output with `=` characters. pad(self, pad: bool) -> Config154 pub fn pad(self, pad: bool) -> Config { 155 Config { pad, ..self } 156 } 157 158 /// Sets whether to emit errors for nonzero trailing bits. 159 /// 160 /// This is useful when implementing 161 /// [forgiving-base64 decode](https://infra.spec.whatwg.org/#forgiving-base64-decode). decode_allow_trailing_bits(self, allow: bool) -> Config162 pub fn decode_allow_trailing_bits(self, allow: bool) -> Config { 163 Config { 164 decode_allow_trailing_bits: allow, 165 ..self 166 } 167 } 168 } 169 170 /// Standard character set with padding. 171 pub const STANDARD: Config = Config { 172 char_set: CharacterSet::Standard, 173 pad: true, 174 decode_allow_trailing_bits: false, 175 }; 176 177 /// Standard character set without padding. 178 pub const STANDARD_NO_PAD: Config = Config { 179 char_set: CharacterSet::Standard, 180 pad: false, 181 decode_allow_trailing_bits: false, 182 }; 183 184 /// URL-safe character set with padding 185 pub const URL_SAFE: Config = Config { 186 char_set: CharacterSet::UrlSafe, 187 pad: true, 188 decode_allow_trailing_bits: false, 189 }; 190 191 /// URL-safe character set without padding 192 pub const URL_SAFE_NO_PAD: Config = Config { 193 char_set: CharacterSet::UrlSafe, 194 pad: false, 195 decode_allow_trailing_bits: false, 196 }; 197 198 /// As per `crypt(3)` requirements 199 pub const CRYPT: Config = Config { 200 char_set: CharacterSet::Crypt, 201 pad: false, 202 decode_allow_trailing_bits: false, 203 }; 204