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 or URL-safe), padding suffix (yes/no), and line wrap (line length, line ending). 5 //! The `Config` struct encapsulates this info. There are some common configs included: `STANDARD`, 6 //! `MIME`, 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, line wrap, etc, as per the config. 29 //! 30 //! # Decoding 31 //! 32 //! Just as for encoding, there are different decoding functions available. 33 //! 34 //! Note that all decode functions that take a config will allocate a copy of the input if you 35 //! specify a config that requires whitespace to be stripped. If you care about speed, don't use 36 //! formats that line wrap and then require whitespace stripping. 37 //! 38 //! | Function | Output | Allocates | 39 //! | ----------------------- | ----------------------------- | ------------------------------ | 40 //! | `decode` | Returns a new `Vec<u8>` | Always | 41 //! | `decode_config` | Returns a new `Vec<u8>` | Always | 42 //! | `decode_config_buf` | Appends to provided `Vec<u8>` | Only if `Vec` needs to grow | 43 //! | `decode_config_slice` | Writes to provided `&[u8]` | Never | 44 //! 45 //! Unlike encoding, where all possible input is valid, decoding can fail (see `DecodeError`). 46 //! 47 //! Input can be invalid because it has invalid characters or invalid padding. (No padding at all is 48 //! valid, but excess padding is not.) 49 //! 50 //! Whitespace in the input is invalid unless `strip_whitespace` is enabled in the `Config` used. 51 //! 52 //! # Panics 53 //! 54 //! If length calculations result in overflowing `usize`, a panic will result. 55 //! 56 //! The `_slice` flavors of encode or decode will panic if the provided output slice is too small, 57 58 #![deny( 59 missing_docs, trivial_casts, trivial_numeric_casts, unused_extern_crates, unused_import_braces, 60 unused_results, variant_size_differences, warnings 61 )] 62 63 extern crate byteorder; 64 65 mod chunked_encoder; 66 pub mod display; 67 mod line_wrap; 68 mod tables; 69 70 use line_wrap::{line_wrap, line_wrap_parameters}; 71 72 mod encode; 73 pub use encode::{encode, encode_config, encode_config_buf, encode_config_slice}; 74 75 mod decode; 76 pub use decode::{decode, decode_config, decode_config_buf, decode_config_slice, DecodeError}; 77 78 #[cfg(test)] 79 mod tests; 80 81 /// Available encoding character sets 82 #[derive(Clone, Copy, Debug)] 83 pub enum CharacterSet { 84 /// The standard character set (uses `+` and `/`) 85 Standard, 86 /// The URL safe character set (uses `-` and `_`) 87 UrlSafe, 88 /// The `crypt(3)` character set (uses `./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`) 89 Crypt, 90 } 91 92 impl CharacterSet { encode_table(&self) -> &'static [u8; 64]93 fn encode_table(&self) -> &'static [u8; 64] { 94 match *self { 95 CharacterSet::Standard => tables::STANDARD_ENCODE, 96 CharacterSet::UrlSafe => tables::URL_SAFE_ENCODE, 97 CharacterSet::Crypt => tables::CRYPT_ENCODE, 98 } 99 } 100 decode_table(&self) -> &'static [u8; 256]101 fn decode_table(&self) -> &'static [u8; 256] { 102 match *self { 103 CharacterSet::Standard => tables::STANDARD_DECODE, 104 CharacterSet::UrlSafe => tables::URL_SAFE_DECODE, 105 CharacterSet::Crypt => tables::CRYPT_DECODE, 106 } 107 } 108 } 109 110 /// Line ending used in optional line wrapping. 111 #[derive(Clone, Copy, Debug)] 112 pub enum LineEnding { 113 /// Unix-style \n 114 LF, 115 /// Windows-style \r\n 116 CRLF, 117 } 118 119 impl LineEnding { len(&self) -> usize120 fn len(&self) -> usize { 121 match *self { 122 LineEnding::LF => 1, 123 LineEnding::CRLF => 2, 124 } 125 } 126 } 127 128 /// Line wrap configuration. 129 #[derive(Clone, Copy, Debug)] 130 pub enum LineWrap { 131 /// Don't wrap. 132 NoWrap, 133 /// Wrap lines with the specified length and line ending. The length must be > 0. 134 Wrap(usize, LineEnding), 135 } 136 137 /// Contains configuration parameters for base64 encoding 138 #[derive(Clone, Copy, Debug)] 139 pub struct Config { 140 /// Character set to use 141 char_set: CharacterSet, 142 /// True to pad output with `=` characters 143 pad: bool, 144 /// Remove whitespace before decoding, at the cost of an allocation. Whitespace is defined 145 /// according to POSIX-locale `isspace`, meaning \n \r \f \t \v and space. 146 strip_whitespace: bool, 147 /// ADT signifying whether to linewrap output, and if so by how many characters and with what 148 /// ending 149 line_wrap: LineWrap, 150 } 151 152 impl Config { 153 /// Create a new `Config`. new( char_set: CharacterSet, pad: bool, strip_whitespace: bool, input_line_wrap: LineWrap, ) -> Config154 pub fn new( 155 char_set: CharacterSet, 156 pad: bool, 157 strip_whitespace: bool, 158 input_line_wrap: LineWrap, 159 ) -> Config { 160 let line_wrap = match input_line_wrap { 161 LineWrap::Wrap(0, _) => LineWrap::NoWrap, 162 _ => input_line_wrap, 163 }; 164 165 Config { 166 char_set, 167 pad, 168 strip_whitespace, 169 line_wrap, 170 } 171 } 172 } 173 174 /// Standard character set with padding. 175 pub const STANDARD: Config = Config { 176 char_set: CharacterSet::Standard, 177 pad: true, 178 strip_whitespace: false, 179 line_wrap: LineWrap::NoWrap, 180 }; 181 182 /// Standard character set without padding. 183 pub const STANDARD_NO_PAD: Config = Config { 184 char_set: CharacterSet::Standard, 185 pad: false, 186 strip_whitespace: false, 187 line_wrap: LineWrap::NoWrap, 188 }; 189 190 /// As per standards for MIME encoded messages 191 pub const MIME: Config = Config { 192 char_set: CharacterSet::Standard, 193 pad: true, 194 strip_whitespace: true, 195 line_wrap: LineWrap::Wrap(76, LineEnding::CRLF), 196 }; 197 198 /// URL-safe character set with padding 199 pub const URL_SAFE: Config = Config { 200 char_set: CharacterSet::UrlSafe, 201 pad: true, 202 strip_whitespace: false, 203 line_wrap: LineWrap::NoWrap, 204 }; 205 206 /// URL-safe character set without padding 207 pub const URL_SAFE_NO_PAD: Config = Config { 208 char_set: CharacterSet::UrlSafe, 209 pad: false, 210 strip_whitespace: false, 211 line_wrap: LineWrap::NoWrap, 212 }; 213 214 /// As per `crypt(3)` requirements 215 pub const CRYPT: Config = Config { 216 char_set: CharacterSet::Crypt, 217 pad: false, 218 strip_whitespace: false, 219 line_wrap: LineWrap::NoWrap, 220 }; 221