chromium_base64_rs/
decode.rs

1/// Decode base64 data into [`Vec<u8>`]
2pub fn base64_decode(data: &[u8]) -> Vec<u8> {
3    let length = data.len();
4
5    let mut data = data.to_vec();
6    if length % 4 == 0 {
7        // '='
8        if data[length - 1] == 61 && data[length - 2] == 61 {
9            data.truncate(length - 2);
10        } else if data[length - 1] == 61 {
11            data.truncate(length - 1);
12        }
13    }
14
15    let allowed_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".as_bytes();
16    let atob_lookup = |ch: i32| {
17        for (i, k) in allowed_chars.iter().enumerate() {
18            if ch == *k as i32 {
19                return i as i32
20            }
21        }
22
23        unreachable!()
24    };
25
26    let mut output: Vec<u8> = Vec::new();
27
28    let mut buffer: i32 = 0;
29    let mut accumulated_bits = 0;
30
31    for ch in data {
32        buffer <<= 6;
33        buffer |= atob_lookup(ch.into());
34
35        accumulated_bits += 6;
36
37        if accumulated_bits == 24 {
38            output.push(((buffer & 0xff0000) >> 16) as u8);
39            output.push(((buffer & 0xff00) >> 8) as u8);
40            output.push((buffer & 0xff) as u8);
41
42            buffer = 0;
43            accumulated_bits = 0;
44        }
45    }
46
47    if accumulated_bits == 12 {
48        buffer >>= 4;
49        output.push(buffer as u8);
50    } else if accumulated_bits == 18 {
51        buffer >>= 2;
52        output.push(((buffer & 0xff00) >> 8) as u8);
53        output.push((buffer & 0xff) as u8);
54    }
55
56    return output;
57}
58
59/// uses [`base64_decode`] and converts the result to [`String`]
60pub fn base64_decode_to_string(data: &[u8]) -> String {
61    return String::from_utf8_lossy(base64_decode(data).as_slice()).to_string()
62}