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