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(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     unsafe_code
63 )]
64 
65 extern crate byteorder;
66 
67 mod chunked_encoder;
68 pub mod display;
69 mod tables;
70 pub mod write;
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     ///
86     /// See [RFC 3548](https://tools.ietf.org/html/rfc3548#section-3).
87     Standard,
88     /// The URL safe character set (uses `-` and `_`).
89     ///
90     /// See [RFC 3548](https://tools.ietf.org/html/rfc3548#section-4).
91     UrlSafe,
92     /// The `crypt(3)` character set (uses `./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`).
93     ///
94     /// Not standardized, but folk wisdom on the net asserts that this alphabet is what crypt uses.
95     Crypt,
96 }
97 
98 impl CharacterSet {
encode_table(self) -> &'static [u8; 64]99     fn encode_table(self) -> &'static [u8; 64] {
100         match self {
101             CharacterSet::Standard => tables::STANDARD_ENCODE,
102             CharacterSet::UrlSafe => tables::URL_SAFE_ENCODE,
103             CharacterSet::Crypt => tables::CRYPT_ENCODE,
104         }
105     }
106 
decode_table(self) -> &'static [u8; 256]107     fn decode_table(self) -> &'static [u8; 256] {
108         match self {
109             CharacterSet::Standard => tables::STANDARD_DECODE,
110             CharacterSet::UrlSafe => tables::URL_SAFE_DECODE,
111             CharacterSet::Crypt => tables::CRYPT_DECODE,
112         }
113     }
114 }
115 
116 /// Contains configuration parameters for base64 encoding
117 #[derive(Clone, Copy, Debug)]
118 pub struct Config {
119     /// Character set to use
120     char_set: CharacterSet,
121     /// True to pad output with `=` characters
122     pad: bool,
123     /// True to ignore excess nonzero bits in the last few symbols, otherwise an error is returned.
124     decode_allow_trailing_bits: bool,
125 }
126 
127 impl Config {
128     /// Create a new `Config`.
new(char_set: CharacterSet, pad: bool) -> Config129     pub fn new(char_set: CharacterSet, pad: bool) -> Config {
130         Config { char_set, pad, decode_allow_trailing_bits: false }
131     }
132 
133     /// Sets whether to pad output with `=` characters.
pad(self, pad: bool) -> Config134     pub fn pad(self, pad: bool) -> Config {
135         Config { pad, ..self }
136     }
137 
138     /// Sets whether to emit errors for nonzero trailing bits.
139     ///
140     /// This is useful when implementing
141     /// [forgiving-base64 decode](https://infra.spec.whatwg.org/#forgiving-base64-decode).
decode_allow_trailing_bits(self, allow: bool) -> Config142     pub fn decode_allow_trailing_bits(self, allow: bool) -> Config {
143         Config { decode_allow_trailing_bits: allow, ..self }
144     }
145 }
146 
147 /// Standard character set with padding.
148 pub const STANDARD: Config = Config {
149     char_set: CharacterSet::Standard,
150     pad: true,
151     decode_allow_trailing_bits: false,
152 };
153 
154 /// Standard character set without padding.
155 pub const STANDARD_NO_PAD: Config = Config {
156     char_set: CharacterSet::Standard,
157     pad: false,
158     decode_allow_trailing_bits: false,
159 };
160 
161 /// URL-safe character set with padding
162 pub const URL_SAFE: Config = Config {
163     char_set: CharacterSet::UrlSafe,
164     pad: true,
165     decode_allow_trailing_bits: false,
166 };
167 
168 /// URL-safe character set without padding
169 pub const URL_SAFE_NO_PAD: Config = Config {
170     char_set: CharacterSet::UrlSafe,
171     pad: false,
172     decode_allow_trailing_bits: false,
173 };
174 
175 /// As per `crypt(3)` requirements
176 pub const CRYPT: Config = Config {
177     char_set: CharacterSet::Crypt,
178     pad: false,
179     decode_allow_trailing_bits: false,
180 };
181