base64/
lib.rs

1#![allow(dead_code)]
2
3const CHARMAP: [u8; 65] = [
4    0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
5    0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
6    0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
7    0x59, 0x5A, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
8    0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E,
9    0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76,
10    0x77, 0x78, 0x79, 0x7A, 0x30, 0x31, 0x32, 0x33,
11    0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2B, 0x2F,
12    0x3D // << extra byte for padding
13];
14
15fn lookup(c: u8) -> u8 {
16    match CHARMAP.iter().position(|x| *x == c) {
17        Some(f) => {
18            if f == 64 { 0 } else { f as u8 }
19        },
20        None => 0
21    }
22}
23
24pub fn encode(bytes: &[u8]) -> String {
25    let mut encoded_data: Vec<u8> = Vec::new();
26    for chunk in bytes.chunks(3) {
27        let tmp_chunk: [u8; 3] = [
28            { if chunk.len() < 1 { 0 } else { chunk[0] } },
29            { if chunk.len() < 2 { 0 } else { chunk[1] } },
30            { if chunk.len() < 3 { 0 } else { chunk[2] } },
31        ];
32        let word: u32 =
33            ((tmp_chunk[0] as u32) << 16) |
34            ((tmp_chunk[1] as u32) << 8) |
35             (tmp_chunk[2] as u32);
36        let out_chunk: [u8; 4] = [
37            (word >> 18) as u8,
38            (word << 14 >> 26) as u8,
39            (word << 20 >> 26) as u8,
40            (word << 26 >> 26) as u8,
41        ];
42        encoded_data.push(out_chunk[0]);
43        encoded_data.push(out_chunk[1]);
44        encoded_data.push(out_chunk[2]);
45        encoded_data.push(out_chunk[3]);
46    }
47    let pad_size = 3 - (bytes.len() % 3);
48    if pad_size != 3 {
49        for i in 0..pad_size {
50            let position: usize = (encoded_data.len() - 1 - i) as usize;
51            encoded_data[position] = 64;
52        }
53    }
54    encoded_data.iter().map(|c| CHARMAP[*c as usize] as char).collect()
55}
56
57pub fn decode(string: &String) -> Vec<u8> {
58    let mut decoded_data: Vec<u8> = Vec::new();
59    let bytes = string.as_bytes();
60    for chunk in bytes.chunks(4) {
61        let restored_chunk: [u8; 4] = [
62            { lookup(chunk[0]) },
63            { lookup(chunk[1]) },
64            { lookup(chunk[2]) },
65            { lookup(chunk[3]) },
66        ];
67        let word: u32 =
68            ((restored_chunk[0] as u32) << 18) |
69            ((restored_chunk[1] as u32) << 12) |
70            ((restored_chunk[2] as u32) << 6) |
71             (restored_chunk[3] as u32);
72        let out_chunk: [u8; 3] = [
73            (word <<  8 >> 24) as u8,
74            (word << 16 >> 24) as u8,
75            (word << 24 >> 24) as u8,
76        ];
77        if out_chunk[0] != 0 { decoded_data.push(out_chunk[0]); };
78        if out_chunk[1] != 0 { decoded_data.push(out_chunk[1]); };
79        if out_chunk[2] != 0 { decoded_data.push(out_chunk[2]); };
80    }
81    decoded_data
82}