blob: 350f7b76dbe09861ca8419e1309d4593b861eba6 [file] [log] [blame]
//! Efficient and customizable data-encoding functions
//!
//! This [crate] provides little-endian ASCII base-conversion encodings for
//! bases of size 2, 4, 8, 16, 32, and 64. It supports:
//!
//! - padded and unpadded encodings
//! - canonical encodings (e.g. trailing bits are checked)
//! - in-place encoding and decoding functions
//! - partial decoding functions (e.g. for error recovery)
//! - character translation (e.g. for case-insensitivity)
//! - most and least significant bit-order
//! - ignoring characters when decoding (e.g. for skipping newlines)
//! - wrapping the output when encoding
//!
//! The performance of the encoding and decoding functions are similar to
//! existing implementations (see how to run the benchmarks on [github]).
//!
//! This is the library documentation. If you are looking for the [binary], see
//! the installation instructions on [github].
//!
//! # Examples
//!
//! This crate provides predefined encodings as [constants]. These constants are
//! of type [`Encoding`]. This type provides encoding and decoding functions
//! with in-place or allocating variants. Here is an example using the
//! allocating encoding function of [base64]:
//!
//! ```rust
//! use data_encoding::BASE64;
//! assert_eq!(BASE64.encode(b"Hello world"), "SGVsbG8gd29ybGQ=");
//! ```
//!
//! Here is an example using the in-place decoding function of [base32]:
//!
//! ```rust
//! use data_encoding::BASE32;
//! let input = b"JBSWY3DPEB3W64TMMQ======";
//! let mut output = vec![0; BASE32.decode_len(input.len()).unwrap()];
//! let len = BASE32.decode_mut(input, &mut output).unwrap();
//! assert_eq!(&output[0 .. len], b"Hello world");
//! ```
//!
//! You are not limited to the predefined encodings. You may define your own
//! encodings (with the same correctness and performance properties as the
//! predefined ones) using the [`Specification`] type:
//!
//! ```rust
//! use data_encoding::Specification;
//! let hex = {
//! let mut spec = Specification::new();
//! spec.symbols.push_str("0123456789abcdef");
//! spec.encoding().unwrap()
//! };
//! assert_eq!(hex.encode(b"hello"), "68656c6c6f");
//! ```
//!
//! If you use the [`lazy_static`] crate, you can define a global encoding:
//!
//! ```rust,ignore
//! lazy_static! {
//! static ref HEX: Encoding = {
//! let mut spec = Specification::new();
//! spec.symbols.push_str("0123456789abcdef");
//! spec.translate.from.push_str("ABCDEF");
//! spec.translate.to.push_str("abcdef");
//! spec.encoding().unwrap()
//! };
//! }
//! ```
//!
//! You may also use the [macro] library to define a compile-time custom encoding:
//!
//! ```rust,ignore
//! const HEX: Encoding = new_encoding!{
//! symbols: "0123456789abcdef",
//! translate_from: "ABCDEF",
//! translate_to: "abcdef",
//! };
//! const BASE64: Encoding = new_encoding!{
//! symbols: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
//! padding: '=',
//! };
//! ```
//!
//! # Properties
//!
//! The [base16], [base32], [base32hex], [base64], and [base64url] predefined
//! encodings are conform to [RFC4648].
//!
//! In general, the encoding and decoding functions satisfy the following
//! properties:
//!
//! - They are deterministic: their output only depends on their input
//! - They have no side-effects: they do not modify a hidden mutable state
//! - They are correct: encoding then decoding gives the initial data
//! - They are canonical (unless [`is_canonical`] returns false): decoding then
//! encoding gives the initial data
//!
//! This last property is usually not satisfied by common base64 implementations
//! (like the `rustc-serialize` crate, the `base64` crate, or the `base64` GNU
//! program). This is a matter of choice and this crate has made the choice to
//! let the user choose. Support for canonical encoding as described by the
//! [RFC][canonical] is provided. But it is also possible to disable checking
//! trailing bits, to add characters translation, to decode concatenated padded
//! inputs, and to ignore some characters.
//!
//! Since the RFC specifies the encoding function on all inputs and the decoding
//! function on all possible encoded outputs, the differences between
//! implementations come from the decoding function which may be more or less
//! permissive. In this crate, the decoding function of canonical encodings
//! rejects all inputs that are not a possible output of the encoding function.
//! Here are some concrete examples of decoding differences between this crate,
//! the `rustc-serialize` crate, the `base64` crate, and the `base64` GNU
//! program:
//!
//! | Input | `data-encoding` | `rustc` | `base64` | GNU `base64` |
//! | ---------- | --------------- | -------- | -------- | ------------- |
//! | `AAB=` | `Trailing(2)` | `[0, 0]` | `[0, 0]` | `\x00\x00` |
//! | `AA\nB=` | `Length(4)` | `[0, 0]` | `Length` | `\x00\x00` |
//! | `AAB` | `Length(0)` | `[0, 0]` | `[0, 0]` | Invalid input |
//! | `A\rA\nB=` | `Length(4)` | `[0, 0]` | `Err(1)` | Invalid input |
//! | `-_\r\n` | `Symbol(0)` | `[251]` | `Err(0)` | Invalid input |
//! | `AA==AA==` | `[0, 0]` | `Err` | `Err(2)` | `\x00\x00` |
//!
//! We can summarize these discrepancies as follows:
//!
//! | Discrepancy | `data-encoding` | `rustc` | `base64` | GNU `base64` |
//! | ----------- | --------------- | ------- | -------- | ------------ |
//! | Check trailing bits | Yes | No | No | No |
//! | Ignored characters | None | `\r` and `\n` | None | `\n` |
//! | Translated characters | None | `-_` mapped to `+/` | None | None |
//! | Check padding | Yes | No | No | Yes |
//! | Support concatenated input | Yes | No | No | Yes |
//!
//! This crate permits to disable checking trailing bits. It permits to ignore
//! some characters. It permits to translate characters. It permits to use
//! unpadded encodings. However, for padded encodings, support for concatenated
//! inputs cannot be disabled. This is simply because it doesn't make sense to
//! use padding if it is not to support concatenated inputs.
//!
//! # Migration
//!
//! The [changelog] describes the changes between v1 and v2. Here are the
//! migration steps for common usage:
//!
//! | v1 | v2 |
//! | --------------------------- | --------------------------- |
//! | `use data_encoding::baseNN` | `use data_encoding::BASENN` |
//! | `baseNN::function` | `BASENN.method` |
//! | `baseNN::function_nopad` | `BASENN_NOPAD.method` |
//!
//! [`Encoding`]: struct.Encoding.html
//! [`Specification`]: struct.Specification.html
//! [`is_canonical`]: struct.Encoding.html#method.is_canonical
//! [`lazy_static`]: https://crates.io/crates/lazy_static
//! [RFC4648]: https://tools.ietf.org/html/rfc4648
//! [base16]: constant.HEXUPPER.html
//! [base32]: constant.BASE32.html
//! [base32hex]: constant.BASE32HEX.html
//! [base64]: constant.BASE64.html
//! [base64url]: constant.BASE64URL.html
//! [binary]: https://crates.io/crates/data-encoding-bin
//! [canonical]: https://tools.ietf.org/html/rfc4648#section-3.5
//! [changelog]:
//! https://github.com/ia0/data-encoding/blob/master/lib/CHANGELOG.md
//! [constants]: index.html#constants
//! [crate]: https://crates.io/crates/data-encoding
//! [github]: https://github.com/ia0/data-encoding
//! [macro]: https://crates.io/crates/data-encoding-macro
#![warn(unused_results, missing_docs)]
macro_rules! check {
($e: expr, $c: expr) => {
if !$c {
return Err($e);
}
};
}
trait Static<T: Copy>: Copy {
fn val(self) -> T;
}
macro_rules! define {
($name: ident: $type: ty = $val: expr) => {
#[derive(Copy, Clone)]
struct $name;
impl Static<$type> for $name {
fn val(self) -> $type {
$val
}
}
};
}
define!(Bf: bool = false);
define!(Bt: bool = true);
define!(N1: usize = 1);
define!(N2: usize = 2);
define!(N3: usize = 3);
define!(N4: usize = 4);
define!(N5: usize = 5);
define!(N6: usize = 6);
#[derive(Copy, Clone)]
struct On;
impl<T: Copy> Static<Option<T>> for On {
fn val(self) -> Option<T> {
None
}
}
#[derive(Copy, Clone)]
struct Os<T>(T);
impl<T: Copy> Static<Option<T>> for Os<T> {
fn val(self) -> Option<T> {
Some(self.0)
}
}
macro_rules! dispatch {
(let $var: ident: bool = $val: expr; $($body: tt)*) => {
match $val {
false => { let $var = Bf; dispatch!($($body)*) },
true => { let $var = Bt; dispatch!($($body)*) },
}
};
(let $var: ident: usize = $val: expr; $($body: tt)*) => {
match $val {
1 => { let $var = N1; dispatch!($($body)*) },
2 => { let $var = N2; dispatch!($($body)*) },
3 => { let $var = N3; dispatch!($($body)*) },
4 => { let $var = N4; dispatch!($($body)*) },
5 => { let $var = N5; dispatch!($($body)*) },
6 => { let $var = N6; dispatch!($($body)*) },
_ => panic!(),
}
};
(let $var: ident: Option<$type: ty> = $val: expr; $($body: tt)*) => {
match $val {
None => { let $var = On; dispatch!($($body)*) },
Some(x) => { let $var = Os(x); dispatch!($($body)*) },
}
};
($body: expr) => { $body };
}
unsafe fn chunk_unchecked(x: &[u8], n: usize, i: usize) -> &[u8] {
debug_assert!((i + 1) * n <= x.len());
let ptr = x.as_ptr().offset((n * i) as isize);
std::slice::from_raw_parts(ptr, n)
}
unsafe fn chunk_mut_unchecked(x: &mut [u8], n: usize, i: usize) -> &mut [u8] {
debug_assert!((i + 1) * n <= x.len());
let ptr = x.as_mut_ptr().offset((n * i) as isize);
std::slice::from_raw_parts_mut(ptr, n)
}
unsafe fn as_array(x: &[u8]) -> &[u8; 256] {
debug_assert_eq!(x.len(), 256);
&*(x.as_ptr() as *const [u8; 256])
}
fn div_ceil(x: usize, m: usize) -> usize {
(x + m - 1) / m
}
fn floor(x: usize, m: usize) -> usize {
x / m * m
}
fn vectorize<F: FnMut(usize)>(n: usize, bs: usize, mut f: F) {
for k in 0 .. n / bs {
for i in k * bs .. (k + 1) * bs {
f(i);
}
}
for i in floor(n, bs) .. n {
f(i);
}
}
/// Decoding error kind
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum DecodeKind {
/// Invalid length
Length,
/// Invalid symbol
Symbol,
/// Non-zero trailing bits
Trailing,
/// Invalid padding length
Padding,
}
/// Decoding error
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct DecodeError {
/// Error position
///
/// This position is always a valid input position and represents the first
/// encountered error.
pub position: usize,
/// Error kind
pub kind: DecodeKind,
}
impl std::error::Error for DecodeError {
fn description(&self) -> &str {
match self.kind {
DecodeKind::Length => "invalid length",
DecodeKind::Symbol => "invalid symbol",
DecodeKind::Trailing => "non-zero trailing bits",
DecodeKind::Padding => "invalid padding length",
}
}
}
impl std::fmt::Display for DecodeError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
use std::error::Error;
write!(f, "{} at {}", self.description(), self.position)
}
}
/// Decoding error with partial result
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct DecodePartial {
/// Number of bytes read from input
///
/// This number does not exceed the error position: `read <=
/// error.position`.
pub read: usize,
/// Number of bytes written to output
///
/// This number does not exceed the decoded length: `written <=
/// decode_len(read)`.
pub written: usize,
/// Decoding error
pub error: DecodeError,
}
const INVALID: u8 = 128;
const IGNORE: u8 = 129;
const PADDING: u8 = 130;
fn order(msb: bool, n: usize, i: usize) -> usize {
if msb {
n - 1 - i
} else {
i
}
}
fn enc(bit: usize) -> usize {
debug_assert!(1 <= bit && bit <= 6);
match bit {
1 | 2 | 4 => 1,
3 | 6 => 3,
5 => 5,
_ => unreachable!(),
}
}
fn dec(bit: usize) -> usize {
enc(bit) * 8 / bit
}
fn encode_len<B: Static<usize>>(bit: B, len: usize) -> usize {
div_ceil(8 * len, bit.val())
}
fn encode_block<B: Static<usize>, M: Static<bool>>(
bit: B, msb: M, symbols: &[u8; 256], input: &[u8], output: &mut [u8],
) {
debug_assert!(input.len() <= enc(bit.val()));
debug_assert_eq!(output.len(), encode_len(bit, input.len()));
let bit = bit.val();
let msb = msb.val();
let mut x = 0u64;
for i in 0 .. input.len() {
x |= (input[i] as u64) << 8 * order(msb, enc(bit), i);
}
for i in 0 .. output.len() {
let y = x >> bit * order(msb, dec(bit), i);
output[i] = symbols[y as usize % 256];
}
}
fn encode_mut<B: Static<usize>, M: Static<bool>>(
bit: B, msb: M, symbols: &[u8; 256], input: &[u8], output: &mut [u8],
) {
debug_assert_eq!(output.len(), encode_len(bit, input.len()));
let enc = enc(bit.val());
let dec = dec(bit.val());
let n = input.len() / enc;
let bs = match bit.val() {
5 => 2,
6 => 4,
_ => 1,
};
vectorize(n, bs, |i| {
let input = unsafe { chunk_unchecked(input, enc, i) };
let output = unsafe { chunk_mut_unchecked(output, dec, i) };
encode_block(bit, msb, symbols, input, output);
});
encode_block(bit, msb, symbols, &input[enc * n ..], &mut output[dec * n ..]);
}
// Fails if an input character does not translate to a symbol. The error is the
// lowest index of such character. The output is not written to.
fn decode_block<B: Static<usize>, M: Static<bool>>(
bit: B, msb: M, values: &[u8; 256], input: &[u8], output: &mut [u8],
) -> Result<(), usize> {
debug_assert!(output.len() <= enc(bit.val()));
debug_assert_eq!(input.len(), encode_len(bit, output.len()));
let bit = bit.val();
let msb = msb.val();
let mut x = 0u64;
for j in 0 .. input.len() {
let y = values[input[j] as usize];
check!(j, y < 1 << bit);
x |= (y as u64) << bit * order(msb, dec(bit), j);
}
for j in 0 .. output.len() {
output[j] = (x >> 8 * order(msb, enc(bit), j)) as u8;
}
Ok(())
}
// Fails if an input character does not translate to a symbol. The error `pos`
// is the lowest index of such character. The output is valid up to `pos / dec *
// enc` excluded.
fn decode_mut<B: Static<usize>, M: Static<bool>>(
bit: B, msb: M, values: &[u8; 256], input: &[u8], output: &mut [u8],
) -> Result<(), usize> {
debug_assert_eq!(input.len(), encode_len(bit, output.len()));
let enc = enc(bit.val());
let dec = dec(bit.val());
let n = input.len() / dec;
for i in 0 .. n {
let input = unsafe { chunk_unchecked(input, dec, i) };
let output = unsafe { chunk_mut_unchecked(output, enc, i) };
decode_block(bit, msb, values, input, output).map_err(|e| dec * i + e)?;
}
decode_block(bit, msb, values, &input[dec * n ..], &mut output[enc * n ..])
.map_err(|e| dec * n + e)
}
// Fails if there are non-zero trailing bits.
fn check_trail<B: Static<usize>, M: Static<bool>>(
bit: B, msb: M, ctb: bool, values: &[u8; 256], input: &[u8],
) -> Result<(), ()> {
if 8 % bit.val() == 0 || !ctb {
return Ok(());
}
let trail = bit.val() * input.len() % 8;
if trail == 0 {
return Ok(());
}
let mut mask = (1 << trail) - 1;
if !msb.val() {
mask <<= bit.val() - trail;
}
check!((), values[input[input.len() - 1] as usize] & mask == 0);
Ok(())
}
// Fails if the padding length is invalid. The error is the index of the first
// padding character.
fn check_pad<B: Static<usize>>(bit: B, values: &[u8; 256], input: &[u8]) -> Result<usize, usize> {
let bit = bit.val();
debug_assert_eq!(input.len(), dec(bit));
let is_pad = |x: &&u8| values[**x as usize] == PADDING;
let count = input.iter().rev().take_while(is_pad).count();
let len = input.len() - count;
check!(len, len > 0 && bit * len % 8 < bit);
Ok(len)
}
fn encode_base_len<B: Static<usize>>(bit: B, len: usize) -> usize {
encode_len(bit, len)
}
fn encode_base<B: Static<usize>, M: Static<bool>>(
bit: B, msb: M, symbols: &[u8; 256], input: &[u8], output: &mut [u8],
) {
debug_assert_eq!(output.len(), encode_base_len(bit, input.len()));
encode_mut(bit, msb, symbols, input, output);
}
fn encode_pad_len<B: Static<usize>, P: Static<Option<u8>>>(bit: B, pad: P, len: usize) -> usize {
match pad.val() {
None => encode_base_len(bit, len),
Some(_) => div_ceil(len, enc(bit.val())) * dec(bit.val()),
}
}
fn encode_pad<B: Static<usize>, M: Static<bool>, P: Static<Option<u8>>>(
bit: B, msb: M, symbols: &[u8; 256], spad: P, input: &[u8], output: &mut [u8],
) {
let pad = match spad.val() {
None => return encode_base(bit, msb, symbols, input, output),
Some(pad) => pad,
};
debug_assert_eq!(output.len(), encode_pad_len(bit, spad, input.len()));
let olen = encode_base_len(bit, input.len());
encode_base(bit, msb, symbols, input, &mut output[.. olen]);
for i in olen .. output.len() {
output[i] = pad;
}
}
fn encode_wrap_len<
'a,
B: Static<usize>,
P: Static<Option<u8>>,
W: Static<Option<(usize, &'a [u8])>>,
>(
bit: B, pad: P, wrap: W, ilen: usize,
) -> usize {
let olen = encode_pad_len(bit, pad, ilen);
match wrap.val() {
None => olen,
Some((col, end)) => olen + end.len() * div_ceil(olen, col),
}
}
fn encode_wrap_mut<
'a,
B: Static<usize>,
M: Static<bool>,
P: Static<Option<u8>>,
W: Static<Option<(usize, &'a [u8])>>,
>(
bit: B, msb: M, symbols: &[u8; 256], pad: P, wrap: W, input: &[u8], output: &mut [u8],
) {
let (col, end) = match wrap.val() {
None => return encode_pad(bit, msb, symbols, pad, input, output),
Some((col, end)) => (col, end),
};
debug_assert_eq!(output.len(), encode_wrap_len(bit, pad, wrap, input.len()));
debug_assert_eq!(col % dec(bit.val()), 0);
let col = col / dec(bit.val());
let enc = col * enc(bit.val());
let dec = col * dec(bit.val()) + end.len();
let olen = dec - end.len();
let n = input.len() / enc;
for i in 0 .. n {
let input = unsafe { chunk_unchecked(input, enc, i) };
let output = unsafe { chunk_mut_unchecked(output, dec, i) };
encode_base(bit, msb, symbols, input, &mut output[.. olen]);
output[olen ..].copy_from_slice(end);
}
if input.len() > enc * n {
let olen = dec * n + encode_pad_len(bit, pad, input.len() - enc * n);
encode_pad(bit, msb, symbols, pad, &input[enc * n ..], &mut output[dec * n .. olen]);
output[olen ..].copy_from_slice(end);
}
}
// Returns the longest valid input length and associated output length.
fn decode_wrap_len<B: Static<usize>, P: Static<bool>>(
bit: B, pad: P, len: usize,
) -> (usize, usize) {
let bit = bit.val();
if pad.val() {
(floor(len, dec(bit)), len / dec(bit) * enc(bit))
} else {
let trail = bit * len % 8;
(len - trail / bit, bit * len / 8)
}
}
// Fails with Length if length is invalid. The error is the largest valid
// length.
fn decode_pad_len<B: Static<usize>, P: Static<bool>>(
bit: B, pad: P, len: usize,
) -> Result<usize, DecodeError> {
let (ilen, olen) = decode_wrap_len(bit, pad, len);
check!(DecodeError { position: ilen, kind: DecodeKind::Length }, ilen == len);
Ok(olen)
}
// Fails with Length if length is invalid. The error is the largest valid
// length.
fn decode_base_len<B: Static<usize>>(bit: B, len: usize) -> Result<usize, DecodeError> {
decode_pad_len(bit, Bf, len)
}
// Fails with Symbol if an input character does not translate to a symbol. The
// error is the lowest index of such character.
// Fails with Trailing if there are non-zero trailing bits.
fn decode_base_mut<B: Static<usize>, M: Static<bool>>(
bit: B, msb: M, ctb: bool, values: &[u8; 256], input: &[u8], output: &mut [u8],
) -> Result<usize, DecodePartial> {
debug_assert_eq!(Ok(output.len()), decode_base_len(bit, input.len()));
let fail = |pos, kind| DecodePartial {
read: pos / dec(bit.val()) * dec(bit.val()),
written: pos / dec(bit.val()) * enc(bit.val()),
error: DecodeError { position: pos, kind },
};
decode_mut(bit, msb, values, input, output).map_err(|pos| fail(pos, DecodeKind::Symbol))?;
check_trail(bit, msb, ctb, values, input)
.map_err(|()| fail(input.len() - 1, DecodeKind::Trailing))?;
Ok(output.len())
}
// Fails with Symbol if an input character does not translate to a symbol. The
// error is the lowest index of such character.
// Fails with Padding if some padding length is invalid. The error is the index
// of the first padding character of the invalid padding.
// Fails with Trailing if there are non-zero trailing bits.
fn decode_pad_mut<B: Static<usize>, M: Static<bool>, P: Static<bool>>(
bit: B, msb: M, ctb: bool, values: &[u8; 256], pad: P, input: &[u8], output: &mut [u8],
) -> Result<usize, DecodePartial> {
if !pad.val() {
return decode_base_mut(bit, msb, ctb, values, input, output);
}
debug_assert_eq!(Ok(output.len()), decode_pad_len(bit, pad, input.len()));
let enc = enc(bit.val());
let dec = dec(bit.val());
let mut inpos = 0;
let mut outpos = 0;
let mut outend = output.len();
while inpos < input.len() {
match decode_base_mut(
bit,
msb,
ctb,
values,
&input[inpos ..],
&mut output[outpos .. outend],
) {
Ok(written) => {
if cfg!(debug_assertions) {
inpos = input.len();
}
outpos += written;
break;
}
Err(partial) => {
inpos += partial.read;
outpos += partial.written;
}
}
let inlen =
check_pad(bit, values, &input[inpos .. inpos + dec]).map_err(|pos| DecodePartial {
read: inpos,
written: outpos,
error: DecodeError { position: inpos + pos, kind: DecodeKind::Padding },
})?;
let outlen = decode_base_len(bit, inlen).unwrap();
let written = decode_base_mut(
bit,
msb,
ctb,
values,
&input[inpos .. inpos + inlen],
&mut output[outpos .. outpos + outlen],
)
.map_err(|partial| {
debug_assert_eq!(partial.read, 0);
debug_assert_eq!(partial.written, 0);
DecodePartial {
read: inpos,
written: outpos,
error: DecodeError {
position: inpos + partial.error.position,
kind: partial.error.kind,
},
}
})?;
debug_assert_eq!(written, outlen);
inpos += dec;
outpos += outlen;
outend -= enc - outlen;
}
debug_assert_eq!(inpos, input.len());
debug_assert_eq!(outpos, outend);
Ok(outend)
}
fn skip_ignore(values: &[u8; 256], input: &[u8], mut inpos: usize) -> usize {
while inpos < input.len() && values[input[inpos] as usize] == IGNORE {
inpos += 1;
}
inpos
}
// Returns next input and output position.
// Fails with Symbol if an input character does not translate to a symbol. The
// error is the lowest index of such character.
// Fails with Padding if some padding length is invalid. The error is the index
// of the first padding character of the invalid padding.
// Fails with Trailing if there are non-zero trailing bits.
fn decode_wrap_block<B: Static<usize>, M: Static<bool>, P: Static<bool>>(
bit: B, msb: M, ctb: bool, values: &[u8; 256], pad: P, input: &[u8], output: &mut [u8],
) -> Result<(usize, usize), DecodeError> {
let dec = dec(bit.val());
let mut buf = [0u8; 8];
let mut shift = [0usize; 8];
let mut bufpos = 0;
let mut inpos = 0;
while bufpos < dec {
inpos = skip_ignore(values, input, inpos);
if inpos == input.len() {
break;
}
shift[bufpos] = inpos;
buf[bufpos] = input[inpos];
bufpos += 1;
inpos += 1;
}
let olen = decode_pad_len(bit, pad, bufpos).map_err(|mut e| {
e.position = shift[e.position];
e
})?;
let written = decode_pad_mut(bit, msb, ctb, values, pad, &buf[.. bufpos], &mut output[.. olen])
.map_err(|partial| {
debug_assert_eq!(partial.read, 0);
debug_assert_eq!(partial.written, 0);
DecodeError { position: shift[partial.error.position], kind: partial.error.kind }
})?;
Ok((inpos, written))
}
// Fails with Symbol if an input character does not translate to a symbol. The
// error is the lowest index of such character.
// Fails with Padding if some padding length is invalid. The error is the index
// of the first padding character of the invalid padding.
// Fails with Trailing if there are non-zero trailing bits.
// Fails with Length if input length (without ignored characters) is invalid.
fn decode_wrap_mut<B: Static<usize>, M: Static<bool>, P: Static<bool>, I: Static<bool>>(
bit: B, msb: M, ctb: bool, values: &[u8; 256], pad: P, has_ignore: I, input: &[u8],
output: &mut [u8],
) -> Result<usize, DecodePartial> {
if !has_ignore.val() {
return decode_pad_mut(bit, msb, ctb, values, pad, input, output);
}
debug_assert_eq!(output.len(), decode_wrap_len(bit, pad, input.len()).1);
let mut inpos = 0;
let mut outpos = 0;
while inpos < input.len() {
let (inlen, outlen) = decode_wrap_len(bit, pad, input.len() - inpos);
match decode_pad_mut(
bit,
msb,
ctb,
values,
pad,
&input[inpos .. inpos + inlen],
&mut output[outpos .. outpos + outlen],
) {
Ok(written) => {
inpos += inlen;
outpos += written;
break;
}
Err(partial) => {
inpos += partial.read;
outpos += partial.written;
}
}
let (ipos, opos) =
decode_wrap_block(bit, msb, ctb, values, pad, &input[inpos ..], &mut output[outpos ..])
.map_err(|mut error| {
error.position += inpos;
DecodePartial { read: inpos, written: outpos, error }
})?;
inpos += ipos;
outpos += opos;
}
let inpos = skip_ignore(values, input, inpos);
if inpos == input.len() {
Ok(outpos)
} else {
Err(DecodePartial {
read: inpos,
written: outpos,
error: DecodeError { position: inpos, kind: DecodeKind::Length },
})
}
}
/// Order in which bits are read from a byte
///
/// The base-conversion encoding is always little-endian. This means that the
/// least significant *byte* is always first. However, we can still choose
/// whether, within a byte, this is the most significant or the least
/// significant *bit* that is first. If the terminology is confusing, testing on
/// an asymmetrical example should be enough to choose the correct value.
///
/// # Examples
///
/// In the following example, we can see that a base with the
/// `MostSignificantFirst` bit-order has the most significant bit first in the
/// encoded output. In particular, the output is in the same order as the bits
/// in the byte. The opposite happens with the `LeastSignificantFirst`
/// bit-order. The least significant bit is first and the output is in the
/// reverse order.
///
/// ```rust
/// use data_encoding::{BitOrder, Specification};
/// let mut spec = Specification::new();
/// spec.symbols.push_str("01");
/// // spec.bit_order = BitOrder::MostSignificantFirst; // default
/// let msb = spec.encoding().unwrap();
/// spec.bit_order = BitOrder::LeastSignificantFirst;
/// let lsb = spec.encoding().unwrap();
/// assert_eq!(msb.encode(&[0b01010011]), "01010011");
/// assert_eq!(lsb.encode(&[0b01010011]), "11001010");
/// ```
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum BitOrder {
/// Most significant bit first
///
/// This is the most common and most intuitive bit-order. In particular,
/// this is the bit-order used by [RFC4648] and thus the usual hexadecimal,
/// base64, base32, base64url, and base32hex encodings. This is the default
/// bit-order when [specifying](struct.Specification.html) a base.
///
/// [RFC4648]: https://tools.ietf.org/html/rfc4648
MostSignificantFirst,
/// Least significant bit first
///
/// # Examples
///
/// DNSCurve [base32] uses least significant bit first:
///
/// ```rust
/// use data_encoding::BASE32_DNSCURVE;
/// assert_eq!(BASE32_DNSCURVE.encode(&[0x64, 0x88]), "4321");
/// assert_eq!(BASE32_DNSCURVE.decode(b"4321").unwrap(), vec![0x64, 0x88]);
/// ```
///
/// [base32]: constant.BASE32_DNSCURVE.html
LeastSignificantFirst,
}
use crate::BitOrder::*;
#[doc(hidden)]
pub type InternalEncoding = std::borrow::Cow<'static, [u8]>;
/// Base-conversion encoding
///
/// See [Specification](struct.Specification.html) for technical details or how
/// to define a new one.
// Required fields:
// 0 - 256 (256) symbols
// 256 - 512 (256) values
// 512 - 513 ( 1) padding
// 513 - 514 ( 1) reserved(3),ctb(1),msb(1),bit(3)
// Optional fields:
// 514 - 515 ( 1) width
// 515 - * ( N) separator
// Invariants:
// - symbols is 2^bit unique characters repeated 2^(8-bit) times
// - values[128 ..] are INVALID
// - values[0 .. 128] are either INVALID, IGNORE, PADDING, or < 2^bit
// - padding is either < 128 or INVALID
// - values[padding] is PADDING if padding < 128
// - values and symbols are inverse
// - ctb is true if 8 % bit == 0
// - width is present if there is x such that values[x] is IGNORE
// - width % dec(bit) == 0
// - for all x in separator values[x] is IGNORE
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Encoding(pub InternalEncoding);
/// How to translate characters when decoding
///
/// The order matters. The first character of the `from` field is translated to
/// the first character of the `to` field. The second to the second. Etc.
///
/// See [Specification](struct.Specification.html) for more information.
#[derive(Debug, Clone)]
pub struct Translate {
/// Characters to translate from
pub from: String,
/// Characters to translate to
pub to: String,
}
/// How to wrap the output when encoding
///
/// See [Specification](struct.Specification.html) for more information.
#[derive(Debug, Clone)]
pub struct Wrap {
/// Wrapping width
///
/// Must be a multiple of:
///
/// - 8 for a bit-width of 1 (binary), 3 (octal), and 5 (base32)
/// - 4 for a bit-width of 2 (base4) and 6 (base64)
/// - 2 for a bit-width of 4 (hexadecimal)
///
/// Wrapping is disabled if null.
pub width: usize,
/// Wrapping characters
///
/// Wrapping is disabled if empty.
pub separator: String,
}
/// Base-conversion specification
///
/// It is possible to define custom encodings given a specification. To do so,
/// it is important to understand the theory first.
///
/// # Theory
///
/// Each subsection has an equivalent subsection in the [Practice](#practice)
/// section.
///
/// ## Basics
///
/// The main idea of a [base-conversion] encoding is to see `[u8]` as numbers
/// written in little-endian base256 and convert them in another little-endian
/// base. For performance reasons, this crate restricts this other base to be of
/// size 2 (binary), 4 (base4), 8 (octal), 16 (hexadecimal), 32 (base32), or 64
/// (base64). The converted number is written as `[u8]` although it doesn't use
/// all the 256 possible values of `u8`. This crate encodes to ASCII, so only
/// values smaller than 128 are allowed.
///
/// More precisely, we need the following elements:
///
/// - The bit-width N: 1 for binary, 2 for base4, 3 for octal, 4 for
/// hexadecimal, 5 for base32, and 6 for base64
/// - The [bit-order](enum.BitOrder.html): most or least significant bit first
/// - The symbols function S from [0, 2<sup>N</sup>) (called values and written
/// `uN`) to symbols (represented as `u8` although only ASCII symbols are
/// allowed, i.e. smaller than 128)
/// - The values partial function V from ASCII to [0, 2<sup>N</sup>), i.e. from
/// `u8` to `uN`
/// - Whether trailing bits are checked: trailing bits are leading zeros in
/// theory, but since numbers are little-endian they come last
///
/// For the encoding to be correct (i.e. encoding then decoding gives back the
/// initial input), V(S(i)) must be defined and equal to i for all i in [0,
/// 2<sup>N</sup>). For the encoding to be [canonical][canonical] (i.e.
/// different inputs decode to different outputs, or equivalently, decoding then
/// encoding gives back the initial input), trailing bits must be checked and if
/// V(i) is defined then S(V(i)) is equal to i for all i.
///
/// Encoding and decoding are given by the following pipeline:
///
/// ```text
/// [u8] <--1--> [[bit; 8]] <--2--> [[bit; N]] <--3--> [uN] <--4--> [u8]
/// 1: Map bit-order between each u8 and [bit; 8]
/// 2: Base conversion between base 2^8 and base 2^N (check trailing bits)
/// 3: Map bit-order between each [bit; N] and uN
/// 4: Map symbols/values between each uN and u8 (values must be defined)
/// ```
///
/// ## Extensions
///
/// All these extensions make the encoding not canonical.
///
/// ### Padding
///
/// Padding is useful if the following conditions are met:
///
/// - the bit-width is 3 (octal), 5 (base32), or 6 (base64)
/// - the length of the data to encode is not known in advance
///
/// Bases for which the bit-width N does not divide 8 may not concatenate
/// encoded data. This comes from the fact that it is not possible to make the
/// difference between trailing bits and encoding bits. Padding solves this
/// issue by adding a new character (which is not a symbol) to discriminate
/// between trailing bits and encoding bits. The idea is to work by blocks of
/// lcm(8, N) bits, where lcm(8, N) is the least common multiple of 8 and N.
/// When such block is not complete, it is padded.
///
/// To preserve correctness, the padding character must not be a symbol.
///
/// ### Ignore characters when decoding
///
/// Ignoring characters when decoding is useful if after encoding some
/// characters are added for convenience or any other reason (like wrapping). In
/// that case we want to first ignore thoses characters before decoding.
///
/// To preserve correctness, ignored characters must not contain symbols or the
/// padding character.
///
/// ### Wrap output when encoding
///
/// Wrapping output when encoding is useful if the output is meant to be printed
/// in a document where width is limited (typically 80-columns documents). In
/// that case, the wrapping width and the wrapping separator have to be defined.
///
/// To preserve correctness, the wrapping separator characters must be ignored
/// (see previous subsection). As such, wrapping separator characters must also
/// not contain symbols or the padding character.
///
/// ### Translate characters when decoding
///
/// Translating characters when decoding is useful when encoded data may be
/// copied by a humain instead of a machine. Humans tend to confuse some
/// characters for others. In that case we want to translate those characters
/// before decoding.
///
/// To preserve correctness, the characters we translate from must not contain
/// symbols or the padding character, and the characters we translate to must
/// only contain symbols or the padding character.
///
/// # Practice
///
/// ## Basics
///
/// ```rust
/// use data_encoding::{Encoding, Specification};
/// fn make_encoding(symbols: &str) -> Encoding {
/// let mut spec = Specification::new();
/// spec.symbols.push_str(symbols);
/// spec.encoding().unwrap()
/// }
/// let binary = make_encoding("01");
/// let octal = make_encoding("01234567");
/// let hexadecimal = make_encoding("0123456789abcdef");
/// assert_eq!(binary.encode(b"Bit"), "010000100110100101110100");
/// assert_eq!(octal.encode(b"Bit"), "20464564");
/// assert_eq!(hexadecimal.encode(b"Bit"), "426974");
/// ```
///
/// The `binary` base has 2 symbols `0` and `1` with value 0 and 1 respectively.
/// The `octal` base has 8 symbols `0` to `7` with value 0 to 7. The
/// `hexadecimal` base has 16 symbols `0` to `9` and `a` to `f` with value 0 to
/// 15. The following diagram gives the idea of how encoding works in the
/// previous example (note that we can actually write such diagram only because
/// the bit-order is most significant first):
///
/// ```text
/// [ octal] | 2 : 0 : 4 : 6 : 4 : 5 : 6 : 4 |
/// [ binary] |0 1 0 0 0 0 1 0|0 1 1 0 1 0 0 1|0 1 1 1 0 1 0 0|
/// [hexadecimal] | 4 : 2 | 6 : 9 | 7 : 4 |
/// ^-- LSB ^-- MSB
/// ```
///
/// Note that in theory, these little-endian numbers are read from right to left
/// (the most significant bit is at the right). Since leading zeros are
/// meaningless (in our usual decimal notation 0123 is the same as 123), it
/// explains why trailing bits must be zero. Trailing bits may occur when the
/// bit-width of a base does not divide 8. Only binary, base4, and hexadecimal
/// don't have trailing bits issues. So let's consider octal and base64, which
/// have trailing bits in similar circumstances:
///
/// ```rust
/// use data_encoding::{Specification, BASE64_NOPAD};
/// let octal = {
/// let mut spec = Specification::new();
/// spec.symbols.push_str("01234567");
/// spec.encoding().unwrap()
/// };
/// assert_eq!(BASE64_NOPAD.encode(b"B"), "Qg");
/// assert_eq!(octal.encode(b"B"), "204");
/// ```
///
/// We have the following diagram, where the base64 values are written between
/// parentheses:
///
/// ```text
/// [base64] | Q(16) : g(32) : [has 4 zero trailing bits]
/// [ octal] | 2 : 0 : 4 : [has 1 zero trailing bit ]
/// |0 1 0 0 0 0 1 0|0 0 0 0
/// [ ascii] | B |
/// ^-^-^-^-- leading zeros / trailing bits
/// ```
///
/// ## Extensions
///
/// ### Padding
///
/// For octal and base64, lcm(8, 3) == lcm(8, 6) == 24 bits or 3 bytes. For
/// base32, lcm(8, 5) is 40 bits or 5 bytes. Let's consider octal and base64:
///
/// ```rust
/// use data_encoding::{Specification, BASE64};
/// let octal = {
/// let mut spec = Specification::new();
/// spec.symbols.push_str("01234567");
/// spec.padding = Some('=');
/// spec.encoding().unwrap()
/// };
/// // We start encoding but we only have "B" for now.
/// assert_eq!(BASE64.encode(b"B"), "Qg==");
/// assert_eq!(octal.encode(b"B"), "204=====");
/// // Now we have "it".
/// assert_eq!(BASE64.encode(b"it"), "aXQ=");
/// assert_eq!(octal.encode(b"it"), "322720==");
/// // By concatenating everything, we may decode the original data.
/// assert_eq!(BASE64.decode(b"Qg==aXQ=").unwrap(), b"Bit");
/// assert_eq!(octal.decode(b"204=====322720==").unwrap(), b"Bit");
/// ```
///
/// We have the following diagrams:
///
/// ```text
/// [base64] | Q(16) : g(32) : = : = |
/// [ octal] | 2 : 0 : 4 : = : = : = : = : = |
/// |0 1 0 0 0 0 1 0|. . . . . . . .|. . . . . . . .|
/// [ ascii] | B | end of block aligned --^
/// ^-- beginning of block aligned
///
/// [base64] | a(26) : X(23) : Q(16) : = |
/// [ octal] | 3 : 2 : 2 : 7 : 2 : 0 : = : = |
/// |0 1 1 0 1 0 0 1|0 1 1 1 0 1 0 0|. . . . . . . .|
/// [ ascii] | i | t |
/// ```
///
/// ### Ignore characters when decoding
///
/// The typical use-case is to ignore newlines (`\r` and `\n`). But to keep the
/// example small, we will ignore spaces.
///
/// ```rust
/// let mut spec = data_encoding::HEXLOWER.specification();
/// spec.ignore.push_str(" \t");
/// let base = spec.encoding().unwrap();
/// assert_eq!(base.decode(b"42 69 74"), base.decode(b"426974"));
/// ```
///
/// ### Wrap output when encoding
///
/// The typical use-case is to wrap after 64 or 76 characters with a newline
/// (`\r\n` or `\n`). But to keep the example small, we will wrap after 8
/// characters with a space.
///
/// ```rust
/// let mut spec = data_encoding::BASE64.specification();
/// spec.wrap.width = 8;
/// spec.wrap.separator.push_str(" ");
/// let base64 = spec.encoding().unwrap();
/// assert_eq!(base64.encode(b"Hey you"), "SGV5IHlv dQ== ");
/// ```
///
/// Note that the output always ends with the separator.
///
/// ### Translate characters when decoding
///
/// The typical use-case is to translate lowercase to uppercase or reciprocally,
/// but it is also used for letters that look alike, like `O0` or `Il1`. Let's
/// illustrate both examples.
///
/// ```rust
/// let mut spec = data_encoding::HEXLOWER.specification();
/// spec.translate.from.push_str("ABCDEFOIl");
/// spec.translate.to.push_str("abcdef011");
/// let base = spec.encoding().unwrap();
/// assert_eq!(base.decode(b"BOIl"), base.decode(b"b011"));
/// ```
///
/// [base-conversion]:
/// https://en.wikipedia.org/wiki/Positional_notation#Base_conversion
/// [canonical]: https://tools.ietf.org/html/rfc4648#section-3.5
#[derive(Debug, Clone)]
pub struct Specification {
/// Symbols
///
/// The number of symbols must be 2, 4, 8, 16, 32, or 64. Symbols must be
/// ASCII characters (smaller than 128) and they must be unique.
pub symbols: String,
/// Bit-order
///
/// The default is to use most significant bit first since it is the most
/// common.
pub bit_order: BitOrder,
/// Check trailing bits
///
/// The default is to check trailing bits. This field is ignored when
/// unnecessary (i.e. for base2, base4, and base16).
pub check_trailing_bits: bool,
/// Padding
///
/// The default is to not use padding. The padding character must be ASCII
/// and must not be a symbol.
pub padding: Option<char>,
/// Characters to ignore when decoding
///
/// The default is to not ignore characters when decoding. The characters to
/// ignore must be ASCII and must not be symbols or the padding character.
pub ignore: String,
/// How to wrap the output when encoding
///
/// The default is to not wrap the output when encoding. The wrapping
/// characters must be ASCII and must not be symbols or the padding
/// character.
pub wrap: Wrap,
/// How to translate characters when decoding
///
/// The default is to not translate characters when decoding. The characters
/// to translate from must be ASCII and must not have already been assigned
/// a semantics. The characters to translate to must be ASCII and must have
/// been assigned a semantics (symbol, padding character, or ignored
/// character).
pub translate: Translate,
}
impl Specification {
/// Returns a default specification
pub fn new() -> Specification {
Specification {
symbols: String::new(),
bit_order: MostSignificantFirst,
check_trailing_bits: true,
padding: None,
ignore: String::new(),
wrap: Wrap { width: 0, separator: String::new() },
translate: Translate { from: String::new(), to: String::new() },
}
}
}
impl Encoding {
fn sym(&self) -> &[u8; 256] {
unsafe { as_array(&self.0[0 .. 256]) }
}
fn val(&self) -> &[u8; 256] {
unsafe { as_array(&self.0[256 .. 512]) }
}
fn pad(&self) -> Option<u8> {
if self.0[512] < 128 {
Some(self.0[512])
} else {
None
}
}
fn ctb(&self) -> bool {
self.0[513] & 0x10 != 0
}
fn msb(&self) -> bool {
self.0[513] & 0x8 != 0
}
fn bit(&self) -> usize {
(self.0[513] & 0x7) as usize
}
fn wrap(&self) -> Option<(usize, &[u8])> {
if self.0.len() <= 515 {
return None;
}
Some((self.0[514] as usize, &self.0[515 ..]))
}
fn has_ignore(&self) -> bool {
self.0.len() >= 515
}
/// Returns the encoded length of an input of length `len`
///
/// See [`encode_mut`] for when to use it.
///
/// [`encode_mut`]: struct.Encoding.html#method.encode_mut
pub fn encode_len(&self, len: usize) -> usize {
dispatch! {
let bit: usize = self.bit();
let pad: Option<u8> = self.pad();
let wrap: Option<(usize, &[u8])> = self.wrap();
encode_wrap_len(bit, pad, wrap, len)
}
}
/// Encodes `input` in `output`
///
/// # Panics
///
/// Panics if the `output` length does not match the result of
/// [`encode_len`] for the `input` length.
///
/// # Examples
///
/// ```rust
/// use data_encoding::BASE64;
/// # let mut buffer = vec![0; 100];
/// let input = b"Hello world";
/// let output = &mut buffer[0 .. BASE64.encode_len(input.len())];
/// BASE64.encode_mut(input, output);
/// assert_eq!(output, b"SGVsbG8gd29ybGQ=");
/// ```
///
/// [`encode_len`]: struct.Encoding.html#method.encode_len
pub fn encode_mut(&self, input: &[u8], output: &mut [u8]) {
assert_eq!(output.len(), self.encode_len(input.len()));
dispatch! {
let bit: usize = self.bit();
let msb: bool = self.msb();
let pad: Option<u8> = self.pad();
let wrap: Option<(usize, &[u8])> = self.wrap();
encode_wrap_mut(bit, msb, self.sym(), pad, wrap, input, output)
}
}
/// Returns encoded `input`
///
/// # Examples
///
/// ```rust
/// use data_encoding::BASE64;
/// assert_eq!(BASE64.encode(b"Hello world"), "SGVsbG8gd29ybGQ=");
/// ```
pub fn encode(&self, input: &[u8]) -> String {
let mut output = vec![0u8; self.encode_len(input.len())];
self.encode_mut(input, &mut output);
unsafe { String::from_utf8_unchecked(output) }
}
/// Returns the decoded length of an input of length `len`
///
/// See [`decode_mut`] for when to use it.
///
/// # Errors
///
/// Returns an error if `len` is invalid. The error kind is [`Length`] and
/// the [position] is the greatest valid input length.
///
/// [`decode_mut`]: struct.Encoding.html#method.decode_mut
/// [`Length`]: enum.DecodeKind.html#variant.Length
/// [position]: struct.DecodeError.html#structfield.position
pub fn decode_len(&self, len: usize) -> Result<usize, DecodeError> {
let (ilen, olen) = dispatch! {
let bit: usize = self.bit();
let pad: bool = self.pad().is_some();
decode_wrap_len(bit, pad, len)
};
check!(
DecodeError { position: ilen, kind: DecodeKind::Length },
self.has_ignore() || len == ilen
);
Ok(olen)
}
/// Decodes `input` in `output`
///
/// Returns the length of the decoded output. This length may be smaller
/// than the output length if the input contained padding or ignored
/// characters. The output bytes after the returned length are not
/// initialized and should not be read.
///
/// # Panics
///
/// Panics if the `output` length does not match the result of
/// [`decode_len`] for the `input` length. Also panics if `decode_len` fails
/// for the `input` length.
///
/// # Errors
///
/// Returns an error if `input` is invalid. See [`decode`] for more details.
/// The are two differences though:
///
/// - [`Length`] may be returned only if the encoding allows ignored
/// characters, because otherwise this is already checked by [`decode_len`].
/// - The [`read`] first bytes of the input have been successfully decoded
/// to the [`written`] first bytes of the output.
///
/// # Examples
///
/// ```rust
/// use data_encoding::BASE64;
/// # let mut buffer = vec![0; 100];
/// let input = b"SGVsbA==byB3b3JsZA==";
/// let output = &mut buffer[0 .. BASE64.decode_len(input.len()).unwrap()];
/// let len = BASE64.decode_mut(input, output).unwrap();
/// assert_eq!(&output[0 .. len], b"Hello world");
/// ```
///
/// [`decode_len`]: struct.Encoding.html#method.decode_len
/// [`decode`]: struct.Encoding.html#method.decode
/// [`Length`]: enum.DecodeKind.html#variant.Length
/// [`read`]: struct.DecodePartial.html#structfield.read
/// [`written`]: struct.DecodePartial.html#structfield.written
pub fn decode_mut(&self, input: &[u8], output: &mut [u8]) -> Result<usize, DecodePartial> {
assert_eq!(Ok(output.len()), self.decode_len(input.len()));
dispatch! {
let bit: usize = self.bit();
let msb: bool = self.msb();
let pad: bool = self.pad().is_some();
let has_ignore: bool = self.has_ignore();
decode_wrap_mut(bit, msb, self.ctb(), self.val(), pad, has_ignore,
input, output)
}
}
/// Returns decoded `input`
///
/// # Errors
///
/// Returns an error if `input` is invalid. The error kind can be:
///
/// - [`Length`] if the input length is invalid. The [position] is the
/// greatest valid input length.
/// - [`Symbol`] if the input contains an invalid character. The [position]
/// is the first invalid character.
/// - [`Trailing`] if the input has non-zero trailing bits. This is only
/// possible if the encoding checks trailing bits. The [position] is the
/// first character containing non-zero trailing bits.
/// - [`Padding`] if the input has an invalid padding length. This is only
/// possible if the encoding uses padding. The [position] is the first
/// padding character of the first padding of invalid length.
///
/// # Examples
///
/// ```rust
/// use data_encoding::BASE64;
/// assert_eq!(BASE64.decode(b"SGVsbA==byB3b3JsZA==").unwrap(), b"Hello world");
/// ```
///
/// [`Length`]: enum.DecodeKind.html#variant.Length
/// [`Symbol`]: enum.DecodeKind.html#variant.Symbol
/// [`Trailing`]: enum.DecodeKind.html#variant.Trailing
/// [`Padding`]: enum.DecodeKind.html#variant.Padding
/// [position]: struct.DecodeError.html#structfield.position
pub fn decode(&self, input: &[u8]) -> Result<Vec<u8>, DecodeError> {
let mut output = vec![0u8; self.decode_len(input.len())?];
let len = self.decode_mut(input, &mut output).map_err(|partial| partial.error)?;
output.truncate(len);
Ok(output)
}
/// Returns the bit-width
pub fn bit_width(&self) -> usize {
self.bit()
}
/// Returns whether the encoding is canonical
///
/// An encoding is not canonical if one of the following conditions holds:
///
/// - trailing bits are not checked
/// - padding is used
/// - characters are ignored
/// - characters are translated
pub fn is_canonical(&self) -> bool {
if !self.ctb() {
return false;
}
let bit = self.bit();
let sym = self.sym();
let val = self.val();
for i in 0 .. 256 {
if val[i] == INVALID {
continue;
}
if val[i] >= 1 << bit {
return false;
}
if sym[val[i] as usize] != i as u8 {
return false;
}
}
true
}
/// Returns the encoding specification
pub fn specification(&self) -> Specification {
let mut specification = Specification::new();
specification
.symbols
.push_str(std::str::from_utf8(&self.sym()[0 .. 1 << self.bit()]).unwrap());
specification.bit_order =
if self.msb() { MostSignificantFirst } else { LeastSignificantFirst };
specification.check_trailing_bits = self.ctb();
if let Some(pad) = self.pad() {
specification.padding = Some(pad as char);
}
for i in 0 .. 128u8 {
if self.val()[i as usize] != IGNORE {
continue;
}
specification.ignore.push(i as char);
}
if let Some((col, end)) = self.wrap() {
specification.wrap.width = col;
specification.wrap.separator = std::str::from_utf8(end).unwrap().to_owned();
}
for i in 0 .. 128u8 {
let canonical = if self.val()[i as usize] < 1 << self.bit() {
self.sym()[self.val()[i as usize] as usize]
} else if self.val()[i as usize] == PADDING {
self.pad().unwrap()
} else {
continue;
};
if i == canonical {
continue;
}
specification.translate.from.push(i as char);
specification.translate.to.push(canonical as char);
}
specification
}
#[doc(hidden)]
pub fn internal_new(implementation: &'static [u8]) -> Encoding {
Encoding(std::borrow::Cow::Borrowed(implementation))
}
#[doc(hidden)]
pub fn internal_implementation(&self) -> &[u8] {
&self.0
}
}
#[derive(Debug, Copy, Clone)]
enum SpecificationErrorImpl {
BadSize,
NotAscii,
Duplicate(u8),
ExtraPadding,
WrapLength,
WrapWidth(u8),
FromTo,
Undefined(u8),
}
use crate::SpecificationErrorImpl::*;
/// Specification error
#[derive(Debug, Copy, Clone)]
pub struct SpecificationError(SpecificationErrorImpl);
impl std::fmt::Display for SpecificationError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self.0 {
BadSize => write!(f, "invalid number of symbols"),
NotAscii => write!(f, "non-ascii character"),
Duplicate(c) => write!(f, "{:?} has conflicting definitions", c as char),
ExtraPadding => write!(f, "unnecessary padding"),
WrapLength => write!(f, "invalid wrap width or separator length"),
WrapWidth(x) => write!(f, "wrap width not a multiple of {}", x),
FromTo => write!(f, "translate from/to length mismatch"),
Undefined(c) => write!(f, "{:?} is undefined", c as char),
}
}
}
impl std::error::Error for SpecificationError {
fn description(&self) -> &str {
match self.0 {
BadSize => "invalid number of symbols",
NotAscii => "non-ascii character",
Duplicate(_) => "conflicting definitions",
ExtraPadding => "unnecessary padding",
WrapLength => "invalid wrap width or separator length",
WrapWidth(_) => "wrap width not a multiple",
FromTo => "translate from/to length mismatch",
Undefined(_) => "undefined character",
}
}
}
impl Specification {
/// Returns the specified encoding
///
/// # Errors
///
/// Returns an error if the specification is invalid.
pub fn encoding(&self) -> Result<Encoding, SpecificationError> {
let symbols = self.symbols.as_bytes();
let bit: usize = match symbols.len() {
2 => 1,
4 => 2,
8 => 3,
16 => 4,
32 => 5,
64 => 6,
_ => return Err(SpecificationError(BadSize)),
};
let mut values = [INVALID; 128];
let set = |v: &mut [u8; 128], i: u8, x: u8| {
check!(SpecificationError(NotAscii), i < 128);
if v[i as usize] == x {
return Ok(());
}
check!(SpecificationError(Duplicate(i)), v[i as usize] == INVALID);
Ok(v[i as usize] = x)
};
for v in 0 .. symbols.len() {
set(&mut values, symbols[v], v as u8)?;
}
let msb = self.bit_order == MostSignificantFirst;
let ctb = self.check_trailing_bits || 8 % bit == 0;
let pad = match self.padding {
None => None,
Some(pad) => {
check!(SpecificationError(ExtraPadding), 8 % bit != 0);
check!(SpecificationError(NotAscii), pad.len_utf8() == 1);
set(&mut values, pad as u8, PADDING)?;
Some(pad as u8)
}
};
for i in self.ignore.bytes() {
set(&mut values, i, IGNORE)?;
}
let wrap = if self.wrap.separator.is_empty() || self.wrap.width == 0 {
None
} else {
Some((self.wrap.width, self.wrap.separator.as_bytes()))
};
if let Some((col, end)) = wrap {
check!(SpecificationError(WrapLength), col < 256 && end.len() < 256);
check!(SpecificationError(WrapWidth(dec(bit) as u8)), col % dec(bit) == 0);
for i in end.iter() {
set(&mut values, *i, IGNORE)?;
}
}
let from = self.translate.from.as_bytes();
let to = self.translate.to.as_bytes();
check!(SpecificationError(FromTo), from.len() == to.len());
for i in 0 .. from.len() {
check!(SpecificationError(NotAscii), to[i] < 128);
let v = values[to[i] as usize];
check!(SpecificationError(Undefined(to[i])), v != INVALID);
set(&mut values, from[i], v)?;
}
let mut encoding = Vec::new();
for _ in 0 .. 256 / symbols.len() {
encoding.extend_from_slice(symbols);
}
encoding.extend_from_slice(&values);
encoding.extend_from_slice(&[INVALID; 128]);
match pad {
None => encoding.push(INVALID),
Some(pad) => encoding.push(pad),
}
encoding.push(bit as u8);
if msb {
encoding[513] |= 0x08;
}
if ctb {
encoding[513] |= 0x10;
}
if let Some((col, end)) = wrap {
encoding.push(col as u8);
encoding.extend_from_slice(end);
} else if values.contains(&IGNORE) {
encoding.push(0);
}
Ok(Encoding(std::borrow::Cow::Owned(encoding)))
}
}
/// Lowercase hexadecimal encoding
///
/// This encoding is a static version of:
///
/// ```rust
/// # use data_encoding::{Specification, HEXLOWER};
/// let mut spec = Specification::new();
/// spec.symbols.push_str("0123456789abcdef");
/// assert_eq!(HEXLOWER, spec.encoding().unwrap());
/// ```
///
/// # Examples
///
/// ```rust
/// use data_encoding::HEXLOWER;
/// let deadbeef = vec![0xde, 0xad, 0xbe, 0xef];
/// assert_eq!(HEXLOWER.decode(b"deadbeef").unwrap(), deadbeef);
/// assert_eq!(HEXLOWER.encode(&deadbeef), "deadbeef");
/// ```
pub const HEXLOWER: Encoding = HEXLOWER_IMPL;
const HEXLOWER_IMPL: Encoding = Encoding(std::borrow::Cow::Borrowed(&[
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54,
55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100,
101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51,
52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97,
98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48,
49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100,
101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51,
52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97,
98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48,
49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 97, 98, 99, 100, 101, 102, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 0, 1, 2,
3, 4, 5, 6, 7, 8, 9, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 10, 11, 12, 13, 14, 15, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 28,
]));
/// Lowercase hexadecimal encoding with case-insensitive decoding
///
/// This encoding is a static version of:
///
/// ```rust
/// # use data_encoding::{Specification, HEXLOWER_PERMISSIVE};
/// let mut spec = Specification::new();
/// spec.symbols.push_str("0123456789abcdef");
/// spec.translate.from.push_str("ABCDEF");
/// spec.translate.to.push_str("abcdef");
/// assert_eq!(HEXLOWER_PERMISSIVE, spec.encoding().unwrap());
/// ```
///
/// # Examples
///
/// ```rust
/// use data_encoding::HEXLOWER_PERMISSIVE;
/// let deadbeef = vec![0xde, 0xad, 0xbe, 0xef];
/// assert_eq!(HEXLOWER_PERMISSIVE.decode(b"DeadBeef").unwrap(), deadbeef);
/// assert_eq!(HEXLOWER_PERMISSIVE.encode(&deadbeef), "deadbeef");
/// ```
///
/// You can also define a shorter name:
///
/// ```rust
/// use data_encoding::{Encoding, HEXLOWER_PERMISSIVE};
/// const HEX: Encoding = HEXLOWER_PERMISSIVE;
/// ```
pub const HEXLOWER_PERMISSIVE: Encoding = HEXLOWER_PERMISSIVE_IMPL;
const HEXLOWER_PERMISSIVE_IMPL: Encoding = Encoding(std::borrow::Cow::Borrowed(&[
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54,
55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100,
101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51,
52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97,
98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48,
49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100,
101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51,
52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97,
98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48,
49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 97, 98, 99, 100, 101, 102, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 0, 1, 2,
3, 4, 5, 6, 7, 8, 9, 128, 128, 128, 128, 128, 128, 128, 10, 11, 12, 13, 14, 15, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 10, 11, 12, 13, 14, 15, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 28,
]));
/// Uppercase hexadecimal encoding
///
/// This encoding is a static version of:
///
/// ```rust
/// # use data_encoding::{Specification, HEXUPPER};
/// let mut spec = Specification::new();
/// spec.symbols.push_str("0123456789ABCDEF");
/// assert_eq!(HEXUPPER, spec.encoding().unwrap());
/// ```
///
/// It is compliant with [RFC4648] and known as "base16" or "hex".
///
/// # Examples
///
/// ```rust
/// use data_encoding::HEXUPPER;
/// let deadbeef = vec![0xde, 0xad, 0xbe, 0xef];
/// assert_eq!(HEXUPPER.decode(b"DEADBEEF").unwrap(), deadbeef);
/// assert_eq!(HEXUPPER.encode(&deadbeef), "DEADBEEF");
/// ```
///
/// [RFC4648]: https://tools.ietf.org/html/rfc4648#section-8
pub const HEXUPPER: Encoding = HEXUPPER_IMPL;
const HEXUPPER_IMPL: Encoding = Encoding(std::borrow::Cow::Borrowed(&[
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70, 48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 65, 66, 67, 68, 69, 70, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70, 48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 65, 66, 67, 68, 69, 70, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70, 48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 65, 66, 67, 68, 69, 70, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70, 48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 65, 66, 67, 68, 69, 70, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70, 48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 65, 66, 67, 68, 69, 70, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 128, 128, 128, 128, 128, 128, 128, 10, 11,
12, 13, 14, 15, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 28,
]));
/// Uppercase hexadecimal encoding with case-insensitive decoding
///
/// This encoding is a static version of:
///
/// ```rust
/// # use data_encoding::{Specification, HEXUPPER_PERMISSIVE};
/// let mut spec = Specification::new();
/// spec.symbols.push_str("0123456789ABCDEF");
/// spec.translate.from.push_str("abcdef");
/// spec.translate.to.push_str("ABCDEF");
/// assert_eq!(HEXUPPER_PERMISSIVE, spec.encoding().unwrap());
/// ```
///
/// # Examples
///
/// ```rust
/// use data_encoding::HEXUPPER_PERMISSIVE;
/// let deadbeef = vec![0xde, 0xad, 0xbe, 0xef];
/// assert_eq!(HEXUPPER_PERMISSIVE.decode(b"DeadBeef").unwrap(), deadbeef);
/// assert_eq!(HEXUPPER_PERMISSIVE.encode(&deadbeef), "DEADBEEF");
/// ```
pub const HEXUPPER_PERMISSIVE: Encoding = HEXUPPER_PERMISSIVE_IMPL;
const HEXUPPER_PERMISSIVE_IMPL: Encoding = Encoding(std::borrow::Cow::Borrowed(&[
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70, 48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 65, 66, 67, 68, 69, 70, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70, 48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 65, 66, 67, 68, 69, 70, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70, 48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 65, 66, 67, 68, 69, 70, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70, 48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 65, 66, 67, 68, 69, 70, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70, 48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 65, 66, 67, 68, 69, 70, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 128, 128, 128, 128, 128, 128, 128, 10, 11,
12, 13, 14, 15, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 10, 11, 12, 13, 14, 15, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 28,
]));
/// Padded base32 encoding
///
/// This encoding is a static version of:
///
/// ```rust
/// # use data_encoding::{Specification, BASE32};
/// let mut spec = Specification::new();
/// spec.symbols.push_str("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567");
/// spec.padding = Some('=');
/// assert_eq!(BASE32, spec.encoding().unwrap());
/// ```
///
/// It is conform to [RFC4648].
///
/// [RFC4648]: https://tools.ietf.org/html/rfc4648#section-6
pub const BASE32: Encoding = BASE32_IMPL;
const BASE32_IMPL: Encoding = Encoding(std::borrow::Cow::Borrowed(&[
65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88,
89, 90, 50, 51, 52, 53, 54, 55, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 50, 51, 52, 53, 54, 55, 65, 66, 67, 68, 69, 70, 71, 72,
73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 50, 51, 52, 53, 54, 55,
65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88,
89, 90, 50, 51, 52, 53, 54, 55, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 50, 51, 52, 53, 54, 55, 65, 66, 67, 68, 69, 70, 71, 72,
73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 50, 51, 52, 53, 54, 55,
65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88,
89, 90, 50, 51, 52, 53, 54, 55, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 50, 51, 52, 53, 54, 55, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 26, 27, 28, 29, 30, 31, 128, 128, 128, 128, 128, 130, 128, 128,
128, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 61, 29,
]));
/// Unpadded base32 encoding
///
/// This encoding is a static version of:
///
/// ```rust
/// # use data_encoding::{Specification, BASE32_NOPAD};
/// let mut spec = Specification::new();
/// spec.symbols.push_str("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567");
/// assert_eq!(BASE32_NOPAD, spec.encoding().unwrap());
/// ```
pub const BASE32_NOPAD: Encoding = BASE32_NOPAD_IMPL;
const BASE32_NOPAD_IMPL: Encoding = Encoding(std::borrow::Cow::Borrowed(&[
65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88,
89, 90, 50, 51, 52, 53, 54, 55, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 50, 51, 52, 53, 54, 55, 65, 66, 67, 68, 69, 70, 71, 72,
73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 50, 51, 52, 53, 54, 55,
65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88,
89, 90, 50, 51, 52, 53, 54, 55, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 50, 51, 52, 53, 54, 55, 65, 66, 67, 68, 69, 70, 71, 72,
73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 50, 51, 52, 53, 54, 55,
65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88,
89, 90, 50, 51, 52, 53, 54, 55, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 50, 51, 52, 53, 54, 55, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 26, 27, 28, 29, 30, 31, 128, 128, 128, 128, 128, 128, 128, 128,
128, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 29,
]));
/// Padded base32hex encoding
///
/// This encoding is a static version of:
///
/// ```rust
/// # use data_encoding::{Specification, BASE32HEX};
/// let mut spec = Specification::new();
/// spec.symbols.push_str("0123456789ABCDEFGHIJKLMNOPQRSTUV");
/// spec.padding = Some('=');
/// assert_eq!(BASE32HEX, spec.encoding().unwrap());
/// ```
///
/// It is conform to [RFC4648].
///
/// [RFC4648]: https://tools.ietf.org/html/rfc4648#section-7
pub const BASE32HEX: Encoding = BASE32HEX_IMPL;
const BASE32HEX_IMPL: Encoding = Encoding(std::borrow::Cow::Borrowed(&[
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78,
79, 80, 81, 82, 83, 84, 85, 86, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70,
71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78,
79, 80, 81, 82, 83, 84, 85, 86, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70,
71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78,
79, 80, 81, 82, 83, 84, 85, 86, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70,
71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 128, 128, 128, 130, 128, 128, 128, 10, 11,
12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 61, 29,
]));
/// Unpadded base32hex encoding
///
/// This encoding is a static version of:
///
/// ```rust
/// # use data_encoding::{Specification, BASE32HEX_NOPAD};
/// let mut spec = Specification::new();
/// spec.symbols.push_str("0123456789ABCDEFGHIJKLMNOPQRSTUV");
/// assert_eq!(BASE32HEX_NOPAD, spec.encoding().unwrap());
/// ```
pub const BASE32HEX_NOPAD: Encoding = BASE32HEX_NOPAD_IMPL;
const BASE32HEX_NOPAD_IMPL: Encoding = Encoding(std::borrow::Cow::Borrowed(&[
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78,
79, 80, 81, 82, 83, 84, 85, 86, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70,
71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78,
79, 80, 81, 82, 83, 84, 85, 86, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68,