Skip to main content

rightkit_tauri_shell/
b64.rs

1//! Minimal standard base64 for moving binary clipboard payloads across the JSON IPC boundary.
2
3const ALPHA: &[u8; 64] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
4
5pub fn encode(data: &[u8]) -> String {
6    let mut out = String::with_capacity(data.len().div_ceil(3) * 4);
7    for chunk in data.chunks(3) {
8        let n = (u32::from(chunk[0]) << 16)
9            | (u32::from(*chunk.get(1).unwrap_or(&0)) << 8)
10            | u32::from(*chunk.get(2).unwrap_or(&0));
11        out.push(ALPHA[(n >> 18) as usize & 63] as char);
12        out.push(ALPHA[(n >> 12) as usize & 63] as char);
13        out.push(if chunk.len() > 1 {
14            ALPHA[(n >> 6) as usize & 63] as char
15        } else {
16            '='
17        });
18        out.push(if chunk.len() > 2 {
19            ALPHA[n as usize & 63] as char
20        } else {
21            '='
22        });
23    }
24    out
25}
26
27pub fn decode(s: &str) -> Option<Vec<u8>> {
28    let mut out = Vec::with_capacity(s.len() / 4 * 3);
29    let (mut acc, mut bits) = (0u32, 0u32);
30    for c in s.bytes().filter(|c| !c.is_ascii_whitespace()) {
31        if c == b'=' {
32            break;
33        }
34        let v = ALPHA.iter().position(|a| *a == c)? as u32;
35        acc = (acc << 6) | v;
36        bits += 6;
37        if bits >= 8 {
38            bits -= 8;
39            out.push((acc >> bits) as u8);
40            acc &= (1 << bits) - 1;
41        }
42    }
43    Some(out)
44}