Skip to main content

rspamd_base32/
decode.rs

1//! Base32 decoding routines
2use crate::alphabet::{Alphabet, ZBASE32, EncodeOrder};
3
4#[cfg(any(feature = "alloc", feature = "std", test))]
5use core::fmt;
6#[cfg(any(feature = "std", test))]
7use std::error;
8
9/// Potential decoding errors
10#[derive(Clone, Debug, PartialEq, Eq)]
11pub enum DecodeError {
12    /// An invalid byte was found in the input. The offset and offending byte are provided.
13    InvalidByte(usize, u8),
14    /// The length of the input is invalid.
15    InvalidLength(usize),
16}
17
18impl fmt::Display for DecodeError {
19    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
20        match *self {
21            DecodeError::InvalidByte(index, byte) => {
22                write!(f, "Invalid byte {}, offset {}.", byte, index)
23            }
24            DecodeError::InvalidLength(sz) => write!(f, "Encoded text cannot have a 5-bit remainder: length = {}", sz),
25        }
26    }
27}
28
29#[cfg(any(feature = "std", test))]
30impl error::Error for DecodeError {
31    fn description(&self) -> &str {
32        match *self {
33            DecodeError::InvalidByte(_, _) => "invalid byte",
34            DecodeError::InvalidLength(_) => "invalid length",
35        }
36    }
37
38    fn cause(&self) -> Option<&dyn error::Error> {
39        None
40    }
41}
42
43///Decode base32 using the default alphabet
44///Returns a `Result` containing a `Vec<u8>`.
45///
46///# Example
47///
48///```rust
49///extern crate rspamd_base32;
50///
51///fn main() {
52///    let bytes = rspamd_base32::decode("em3ags7p").unwrap();
53///    println!("{:?}", bytes);
54///    // Prints 'hello'
55///}
56///```
57#[cfg(any(feature = "alloc", feature = "std", test))]
58pub fn decode<T: AsRef<[u8]>>(input: T) -> Result<Vec<u8>, DecodeError> {
59    decode_alphabet(input, &ZBASE32)
60}
61
62///Decode from string reference as octets using the specified [Alphabet].
63///Returns a `Result` containing a `Vec<u8>`.
64///
65///# Example
66///
67///```rust
68///extern crate rspamd_base32;
69///
70///fn main() {
71///    let bytes = rspamd_base32::decode_alphabet(
72///        "NBSWY3DP",
73///        &rspamd_base32::alphabet::RFC,
74///    ).unwrap();
75///    println!("{:?}", bytes);
76///    // Prints 'hello'
77///}
78///```
79#[cfg(any(feature = "alloc", feature = "std", test))]
80pub fn decode_alphabet<T: AsRef<[u8]>>(
81    input: T,
82    alphabet: &Alphabet,
83) -> Result<Vec<u8>, DecodeError> {
84    let mut buffer = Vec::<u8>::with_capacity(
85        decoded_len(input.as_ref().len()).expect("integer multiplication overflow"));
86
87    decode_alphabet_vec(input, &mut buffer, &alphabet).map(|_| buffer)
88}
89
90///Decode from string reference as octets.
91///Writes into the supplied `Vec`, which may allocate if its internal buffer isn't big enough.
92///Returns a `Result` containing an empty tuple, aka `()`.
93///
94///# Example
95///
96///```rust
97///extern crate rspamd_base32;
98///
99///
100///fn main() {
101///    let mut buffer = Vec::<u8>::new();
102///    // with the default engine
103///    rspamd_base32::decode_alphabet_vec(
104///        "em3ags7p",
105///        &mut buffer,
106///        &rspamd_base32::alphabet::ZBASE32
107///    ).unwrap();
108///    println!("{:?}", buffer);
109///}
110///```
111#[cfg(any(feature = "alloc", feature = "std", test))]
112pub fn decode_alphabet_vec<T: AsRef<[u8]>>(
113    input: T,
114    buffer: &mut Vec<u8>,
115    alphabet: &Alphabet,
116) -> Result<(), DecodeError> {
117    let input_bytes = input.as_ref();
118
119    let estimate = decoded_len(input_bytes.len()).expect("integer multiplication overflow");
120    buffer.resize(estimate, 0);
121
122    let mut processed_bits = 0;
123    let mut acc = 0_u32;
124    let mut o = 0_usize;
125    let mut i = o;
126
127    if alphabet.encode_order == EncodeOrder::OrderInversed {
128        for c in input_bytes {
129            if processed_bits >= 8 {
130                // Emit from left to right
131                processed_bits -= 8;
132                buffer[o] = (acc & 0xFF) as u8;
133                o = o + 1;
134                acc = acc >> 8;
135            }
136            let decoded = alphabet.decode_bytes[*c as usize];
137            if decoded == 0xff {
138                return Err(DecodeError::InvalidByte(i, *c));
139            }
140
141            acc = ((decoded as u32) << processed_bits) | acc;
142            processed_bits = processed_bits + 5;
143            i = i + 1;
144        }
145        if processed_bits > 0 {
146            buffer[o] = (acc & 0xFF) as u8;
147            o = o + 1;
148        }
149    }
150    else {
151        for c in input_bytes {
152            let decoded = alphabet.decode_bytes[*c as usize];
153            if decoded == 0xff {
154                return Err(DecodeError::InvalidByte(i, *c));
155            }
156
157            acc = (acc << 5) | decoded as u32;
158            processed_bits = processed_bits + 5;
159
160            if processed_bits >= 8 {
161                processed_bits = processed_bits - 8;
162                // Emit from right to left
163                buffer[o] = ((acc >> processed_bits) & 0xFF) as u8;
164                o = o + 1;
165                acc = acc & ((1 << processed_bits) - 1);
166            }
167
168            i = i + 1;
169        }
170    }
171
172    buffer.resize(o, 0);
173
174    Ok(())
175}
176
177fn decoded_len(bytes_len : usize) -> Option<usize> {
178    let full_chunks = bytes_len / 8;
179    let remainder = bytes_len % 8;
180    full_chunks.checked_mul(5).and_then(|c| c.checked_add(remainder))
181}
182
183#[cfg(test)]
184mod tests {
185    use crate::encode::*;
186    use crate::decode::*;
187    use crate::alphabet::*;
188
189    #[test]
190    fn simple_decode_zbase() {
191        assert_eq!(
192            "test123".as_bytes(),
193            decode("wm3g84fg13cy").expect("undecoded!"),
194        );
195        assert_eq!(
196            "hello".as_bytes(),
197            decode("em3ags7p").expect("undecoded"),
198        );
199    }
200
201    #[test]
202    fn simple_encode_decode_zbase() {
203        assert_eq!("test123".as_bytes(),
204            decode(encode("test123")).expect("undecoded"));
205    }
206
207    #[test]
208    fn simple_decode_rfc() {
209        assert_eq!(
210            "test123".as_bytes(),
211            decode_alphabet("ORSXG5BRGIZQ", &RFC).expect("undecoded!"),
212        );
213        assert_eq!(
214            "hello".as_bytes(),
215            decode_alphabet("NBSWY3DP", &RFC).expect("undecoded"),
216        );
217    }
218
219    #[test]
220    fn simple_encode_decode_rfc() {
221        assert_eq!("test123".as_bytes(),
222                   decode_alphabet(encode_alphabet("test123", &RFC),
223                                   &RFC).expect("undecoded"));
224    }
225}