domain_core/utils/
base32.rs

1//! Decoding and encoding of Base32.
2
3use std::fmt;
4use bytes::{BufMut, Bytes, BytesMut};
5use super::base64::DecodeError;
6
7
8//------------ Convenience Functions -----------------------------------------
9
10pub fn decode_hex(s: &str) -> Result<Bytes, DecodeError> {
11    let mut decoder = Decoder::new_hex();
12    for ch in s.chars() {
13        decoder.push(ch)?;
14    }
15    decoder.finalize()
16}
17
18
19pub fn display_hex<B, W>(bytes: &B, f: &mut W) -> fmt::Result
20where B: AsRef<[u8]> + ?Sized, W: fmt::Write {
21    fn ch(i: u8) -> char {
22        ENCODE_HEX_ALPHABET[i as usize]
23    }
24
25    for chunk in bytes.as_ref().chunks(5) {
26        f.write_char(ch(chunk[0] >> 3))?; // 0
27        if chunk.len() == 1 {
28            f.write_char(ch((chunk[0] & 0x07) << 2))?; // 1
29            break;
30        }
31        f.write_char(ch((chunk[0] & 0x07) << 2 | chunk[1] >> 6))?; // 1
32        f.write_char(ch((chunk[1] & 0x3F) >> 1))?; // 2
33        if chunk.len() == 2 {
34            f.write_char(ch((chunk[1] & 0x01) << 4))?; // 3
35            break;
36        }
37        f.write_char(ch((chunk[1] & 0x01) << 4 | chunk[2] >> 4))?; // 3
38        if chunk.len() == 3 {
39            f.write_char(ch((chunk[2] & 0x0F) << 1))?; // 4
40            break;
41        }
42        f.write_char(ch((chunk[2] & 0x0F) << 1 | chunk[3] >> 7))?; // 4
43        f.write_char(ch((chunk[3] & 0x7F) >> 2))?; // 5
44        if chunk.len() == 4 {
45            f.write_char(ch((chunk[3] & 0x03) << 3))?; // 6
46            break;
47        }
48        f.write_char(ch((chunk[3] & 0x03) << 3 | chunk[4] >> 5))?; // 6
49        f.write_char(ch(chunk[4] & 0x1F))?; // 7
50    }
51    Ok(())
52}
53
54
55//------------ Decoder -------------------------------------------------------
56
57/// A base32 decoder.
58///
59/// This doesn’t do padding.
60pub struct Decoder {
61    /// The alphabet we are using.
62    alphabet: &'static [u8; 128],
63
64    /// A buffer for up to four characters.
65    ///
66    /// We only keep `u8`s here because only ASCII characters are used by
67    /// Base64.
68    buf: [u8; 8],
69
70    /// The index in `buf` where we place the next character.
71    next: usize,
72
73    /// The target or an error if something went wrong.
74    target: Result<BytesMut, DecodeError>,
75}
76
77impl Decoder {
78    pub fn new_hex() -> Self {
79        Decoder {
80            alphabet: &DECODE_HEX_ALPHABET,
81            buf: [0; 8],
82            next: 0,
83            target: Ok(BytesMut::new())
84        }
85    }
86
87    pub fn finalize(mut self) -> Result<Bytes, DecodeError> {
88        if let Err(err) = self.target {
89            return Err(err)
90        }
91
92        match self.next {
93            0 => { }
94            1 | 3 | 6 => return Err(DecodeError::IncompleteInput),
95            2 => {
96                self.reserve(1);
97                self.octet_0();
98            }
99            4 => {
100                self.reserve(2);
101                self.octet_0();
102                self.octet_1();
103            }
104            5 => {
105                self.reserve(3);
106                self.octet_0();
107                self.octet_1();
108                self.octet_2();
109            }
110            7 => {
111                self.reserve(4);
112                self.octet_0();
113                self.octet_1();
114                self.octet_2();
115                self.octet_3();
116            }
117            _ => unreachable!()
118        }
119        self.target.map(BytesMut::freeze)
120    }
121
122    pub fn push(&mut self, ch: char) -> Result<(), DecodeError> {
123        if ch > (127 as char) {
124            return Err(DecodeError::IllegalChar(ch))
125        }
126        let val = self.alphabet[ch as usize];
127        if val == 0xFF {
128            return Err(DecodeError::IllegalChar(ch))
129        }
130        self.buf[self.next] = val;
131        self.next += 1;
132
133        if self.next == 8 {
134            self.reserve(5);
135            self.octet_0();
136            self.octet_1();
137            self.octet_2();
138            self.octet_3();
139            self.octet_4();
140            self.next = 0;
141        }
142        Ok(())
143    }
144}
145
146impl Decoder {
147    fn octet_0(&mut self) {
148        let ch = self.buf[0] << 3 | self.buf[1] >> 2;
149        self.append(ch)
150    }
151
152    fn octet_1(&mut self) {
153        let ch = self.buf[1] << 6 | self.buf[2] << 1 | self.buf[3] >> 4;
154        self.append(ch)
155    }
156
157    fn octet_2(&mut self) {
158        let ch = self.buf[3] << 4 | self.buf[4] >> 1;
159        self.append(ch)
160    }
161
162    fn octet_3(&mut self) {
163        let ch = self.buf[4] << 7 | self.buf[5] << 2 | self.buf[6] >> 3;
164        self.append(ch)
165    }
166
167    fn octet_4(&mut self) {
168        let ch = self.buf[6] << 5 | self.buf[7];
169        self.append(ch)
170    }
171
172    fn append(&mut self, value: u8) {
173        self.target.as_mut().unwrap().put_u8(value);
174    }
175
176    fn reserve(&mut self, len: usize) {
177        let target = self.target.as_mut().unwrap();
178        if target.remaining_mut() < len {
179            target.reserve(len)
180        }
181    }
182}
183
184
185//------------ Constants -----------------------------------------------------
186
187/// The alphabet used for decoding “base32hex.”
188///
189/// This maps encoding characters into their values. A value of 0xFF stands in
190/// for illegal characters. We only provide the first 128 characters since the
191/// alphabet will only use ASCII characters.
192const DECODE_HEX_ALPHABET: [u8; 128] = [
193    0xFF, 0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF, 0xFF,  // 0x00 .. 0x07
194    0xFF, 0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF, 0xFF,  // 0x08 .. 0x0F
195
196    0xFF, 0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF, 0xFF,  // 0x10 .. 0x17
197    0xFF, 0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF, 0xFF,  // 0x18 .. 0x1F
198
199    0xFF, 0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF, 0xFF,  // 0x20 .. 0x27
200    0xFF, 0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF, 0xFF,  // 0x28 .. 0x2F
201
202    0x00, 0x01, 0x02, 0x03,   0x04, 0x05, 0x06, 0x07,  // 0x30 .. 0x37
203    0x08, 0x09, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF, 0xFF,  // 0x38 .. 0x3F
204
205    0xFF, 0x0a, 0x0b, 0x0c, 0x0d,   0x0e, 0x0f, 0x10,  // 0x40 .. 0x47
206    0x11, 0x12, 0x13, 0x14, 0x15,   0x16, 0x17, 0x18,  // 0x48 .. 0x4F
207
208    0x19, 0x1a, 0x1b, 0x1c, 0x1d,   0x1e, 0x1f, 0xFF,  // 0x50 .. 0x57
209    0xFF, 0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF, 0xFF,  // 0x58 .. 0x5F
210
211    0xFF, 0x0a, 0x0b, 0x0c, 0x0d,   0x0e, 0x0f, 0x10,  // 0x60 .. 0x67
212    0x11, 0x12, 0x13, 0x14, 0x15,   0x16, 0x17, 0x18,  // 0x68 .. 0x6F
213
214    0x19, 0x1a, 0x1b, 0x1c, 0x1d,   0x1e, 0x1f, 0xFF,  // 0x70 .. 0x77
215    0xFF, 0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF, 0xFF,  // 0x78 .. 0x7F
216];
217
218
219const ENCODE_HEX_ALPHABET: [char; 32] = [
220    '0', '1', '2', '3',   '4', '5', '6', '7',   // 0x00 .. 0x07
221    '8', '9', 'A', 'B',   'C', 'D', 'E', 'F',   // 0x08 .. 0x0F
222
223    'G', 'H', 'I', 'J',   'K', 'L', 'M', 'N',   // 0x10 .. 0x17
224    'O', 'P', 'Q', 'R',   'S', 'T', 'U', 'V',   // 0x18 .. 0x1F
225];
226
227
228//============ Test ==========================================================
229
230#[cfg(test)]
231mod test {
232    use super::*;
233
234    #[test]
235    fn test_decode_hex() {
236        assert_eq!(decode_hex("").unwrap().as_ref(), b"");
237        assert_eq!(decode_hex("CO").unwrap().as_ref(), b"f");
238        assert_eq!(decode_hex("CPNG").unwrap().as_ref(), b"fo");
239        assert_eq!(decode_hex("CPNMU").unwrap().as_ref(), b"foo");
240        assert_eq!(decode_hex("CPNMUOG").unwrap().as_ref(), b"foob");
241        assert_eq!(decode_hex("CPNMUOJ1").unwrap().as_ref(), b"fooba");
242        assert_eq!(decode_hex("CPNMUOJ1E8").unwrap().as_ref(), b"foobar");
243        assert_eq!(decode_hex("co").unwrap().as_ref(), b"f");
244        assert_eq!(decode_hex("cpng").unwrap().as_ref(), b"fo");
245        assert_eq!(decode_hex("cpnmu").unwrap().as_ref(), b"foo");
246        assert_eq!(decode_hex("cpnmuog").unwrap().as_ref(), b"foob");
247        assert_eq!(decode_hex("cpnmuoj1").unwrap().as_ref(), b"fooba");
248        assert_eq!(decode_hex("cpnmuoj1e8").unwrap().as_ref(), b"foobar");
249    }
250
251    #[test]
252    fn test_display_hex() {
253        fn fmt(s: &[u8]) -> String {
254            let mut out = String::new();
255            display_hex(s, &mut out).unwrap();
256            out
257        }
258
259        assert_eq!(fmt(b""), "");
260        assert_eq!(fmt(b"f"), "CO");
261        assert_eq!(fmt(b"fo"), "CPNG");
262        assert_eq!(fmt(b"foo"), "CPNMU");
263        assert_eq!(fmt(b"foob"), "CPNMUOG");
264        assert_eq!(fmt(b"fooba"), "CPNMUOJ1");
265        assert_eq!(fmt(b"foobar"), "CPNMUOJ1E8");
266    }
267}
268