base64/lib.rs
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//! # `Read` and `Write`
47//!
48//! To map a `Read` of b64 bytes to the decoded bytes, wrap a reader (file, network socket, etc)
49//! with `base64::read::DecoderReader`. To write raw bytes and have them b64 encoded on the fly,
50//! wrap a writer with `base64::write::EncoderWriter`. There is some performance overhead (15% or
51//! so) because of the necessary buffer shuffling -- still fast enough that almost nobody cares.
52//! Also, these implementations do not heap allocate.
53//!
54//! # Panics
55//!
56//! If length calculations result in overflowing `usize`, a panic will result.
57//!
58//! The `_slice` flavors of encode or decode will panic if the provided output slice is too small,
59
60#![cfg_attr(feature = "cargo-clippy", allow(clippy::cast_lossless))]
61#![deny(
62 missing_docs,
63 trivial_casts,
64 trivial_numeric_casts,
65 unused_extern_crates,
66 unused_import_braces,
67 unused_results,
68 variant_size_differences,
69 warnings
70)]
71#![forbid(unsafe_code)]
72#![cfg_attr(not(any(feature = "std", test)), no_std)]
73
74#[cfg(all(feature = "alloc", not(any(feature = "std", test))))]
75extern crate alloc;
76#[cfg(any(feature = "std", test))]
77extern crate std as alloc;
78
79mod chunked_encoder;
80pub mod display;
81#[cfg(any(feature = "std", test))]
82pub mod read;
83mod tables;
84#[cfg(any(feature = "std", test))]
85pub mod write;
86
87mod encode;
88pub use crate::encode::encode_config_slice;
89#[cfg(any(feature = "alloc", feature = "std", test))]
90pub use crate::encode::{encode, encode_config, encode_config_buf};
91
92mod decode;
93#[cfg(any(feature = "alloc", feature = "std", test))]
94pub use crate::decode::{decode, decode_config, decode_config_buf};
95pub use crate::decode::{decode_config_slice, DecodeError};
96
97#[cfg(test)]
98mod tests;
99
100/// Available encoding character sets
101#[derive(Clone, Copy, Debug)]
102pub enum CharacterSet {
103 /// The standard character set (uses `+` and `/`).
104 ///
105 /// See [RFC 3548](https://tools.ietf.org/html/rfc3548#section-3).
106 Standard,
107 /// The URL safe character set (uses `-` and `_`).
108 ///
109 /// See [RFC 3548](https://tools.ietf.org/html/rfc3548#section-4).
110 UrlSafe,
111 /// The `crypt(3)` character set (uses `./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`).
112 ///
113 /// Not standardized, but folk wisdom on the net asserts that this alphabet is what crypt uses.
114 Crypt,
115 /// The bcrypt character set (uses `./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789`).
116 Bcrypt,
117 /// The character set used in IMAP-modified UTF-7 (uses `+` and `,`).
118 ///
119 /// See [RFC 3501](https://tools.ietf.org/html/rfc3501#section-5.1.3)
120 ImapMutf7,
121 /// The character set used in BinHex 4.0 files.
122 ///
123 /// See [BinHex 4.0 Definition](http://files.stairways.com/other/binhex-40-specs-info.txt)
124 BinHex,
125}
126
127impl CharacterSet {
128 fn encode_table(self) -> &'static [u8; 64] {
129 match self {
130 CharacterSet::Standard => tables::STANDARD_ENCODE,
131 CharacterSet::UrlSafe => tables::URL_SAFE_ENCODE,
132 CharacterSet::Crypt => tables::CRYPT_ENCODE,
133 CharacterSet::Bcrypt => tables::BCRYPT_ENCODE,
134 CharacterSet::ImapMutf7 => tables::IMAP_MUTF7_ENCODE,
135 CharacterSet::BinHex => tables::BINHEX_ENCODE,
136 }
137 }
138
139 fn decode_table(self) -> &'static [u8; 256] {
140 match self {
141 CharacterSet::Standard => tables::STANDARD_DECODE,
142 CharacterSet::UrlSafe => tables::URL_SAFE_DECODE,
143 CharacterSet::Crypt => tables::CRYPT_DECODE,
144 CharacterSet::Bcrypt => tables::BCRYPT_DECODE,
145 CharacterSet::ImapMutf7 => tables::IMAP_MUTF7_DECODE,
146 CharacterSet::BinHex => tables::BINHEX_DECODE,
147 }
148 }
149}
150
151/// Contains configuration parameters for base64 encoding
152#[derive(Clone, Copy, Debug)]
153pub struct Config {
154 /// Character set to use
155 char_set: CharacterSet,
156 /// True to pad output with `=` characters
157 pad: bool,
158 /// True to ignore excess nonzero bits in the last few symbols, otherwise an error is returned.
159 decode_allow_trailing_bits: bool,
160}
161
162impl Config {
163 /// Create a new `Config`.
164 pub const fn new(char_set: CharacterSet, pad: bool) -> Config {
165 Config {
166 char_set,
167 pad,
168 decode_allow_trailing_bits: false,
169 }
170 }
171
172 /// Sets whether to pad output with `=` characters.
173 pub const fn pad(self, pad: bool) -> Config {
174 Config { pad, ..self }
175 }
176
177 /// Sets whether to emit errors for nonzero trailing bits.
178 ///
179 /// This is useful when implementing
180 /// [forgiving-base64 decode](https://infra.spec.whatwg.org/#forgiving-base64-decode).
181 pub const fn decode_allow_trailing_bits(self, allow: bool) -> Config {
182 Config {
183 decode_allow_trailing_bits: allow,
184 ..self
185 }
186 }
187}
188
189/// Standard character set with padding.
190pub const STANDARD: Config = Config {
191 char_set: CharacterSet::Standard,
192 pad: true,
193 decode_allow_trailing_bits: false,
194};
195
196/// Standard character set without padding.
197pub const STANDARD_NO_PAD: Config = Config {
198 char_set: CharacterSet::Standard,
199 pad: false,
200 decode_allow_trailing_bits: false,
201};
202
203/// URL-safe character set with padding
204pub const URL_SAFE: Config = Config {
205 char_set: CharacterSet::UrlSafe,
206 pad: true,
207 decode_allow_trailing_bits: false,
208};
209
210/// URL-safe character set without padding
211pub const URL_SAFE_NO_PAD: Config = Config {
212 char_set: CharacterSet::UrlSafe,
213 pad: false,
214 decode_allow_trailing_bits: false,
215};
216
217/// As per `crypt(3)` requirements
218pub const CRYPT: Config = Config {
219 char_set: CharacterSet::Crypt,
220 pad: false,
221 decode_allow_trailing_bits: false,
222};
223
224/// Bcrypt character set
225pub const BCRYPT: Config = Config {
226 char_set: CharacterSet::Bcrypt,
227 pad: false,
228 decode_allow_trailing_bits: false,
229};
230
231/// IMAP modified UTF-7 requirements
232pub const IMAP_MUTF7: Config = Config {
233 char_set: CharacterSet::ImapMutf7,
234 pad: false,
235 decode_allow_trailing_bits: false,
236};
237
238/// BinHex character set
239pub const BINHEX: Config = Config {
240 char_set: CharacterSet::BinHex,
241 pad: false,
242 decode_allow_trailing_bits: false,
243};
244
245const PAD_BYTE: u8 = b'=';