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