Skip to main content

rustbasic_core/
base64.rs

1pub mod engine {
2    pub mod general_purpose {
3        pub struct Standard;
4
5        impl Standard {
6            /// Encodes a byte array to a Base64 string.
7            pub fn encode<T: AsRef<[u8]>>(&self, bytes: T) -> String {
8                super::super::encode(bytes.as_ref())
9            }
10
11            /// Decodes a Base64 string to a byte array.
12            pub fn decode<T: AsRef<str>>(&self, s: T) -> Result<Vec<u8>, super::super::DecodeError> {
13                super::super::decode(s.as_ref())
14            }
15        }
16
17        pub const STANDARD: Standard = Standard;
18    }
19}
20
21#[derive(Debug)]
22pub struct DecodeError;
23
24impl std::fmt::Display for DecodeError {
25    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26        write!(f, "Format Base64 tidak valid")
27    }
28}
29
30impl std::error::Error for DecodeError {}
31
32/// Encode a byte slice as standard Base64 with padding.
33pub fn encode(input: &[u8]) -> String {
34    const CHARS: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
35    let mut output = String::with_capacity((input.len() + 2) / 3 * 4);
36    for chunk in input.chunks(3) {
37        let b0 = chunk[0] as usize;
38        let b1 = chunk.get(1).map(|&b| b as usize).unwrap_or(0);
39        let b2 = chunk.get(2).map(|&b| b as usize).unwrap_or(0);
40
41        output.push(CHARS[b0 >> 2] as char);
42        output.push(CHARS[((b0 & 3) << 4) | (b1 >> 4)] as char);
43
44        if chunk.len() > 1 {
45            output.push(CHARS[((b1 & 15) << 2) | (b2 >> 6)] as char);
46        } else {
47            output.push('=');
48        }
49
50        if chunk.len() > 2 {
51            output.push(CHARS[b2 & 63] as char);
52        } else {
53            output.push('=');
54        }
55    }
56    output
57}
58
59/// Decode a standard Base64 string (ignoring padding).
60pub fn decode(input: &str) -> Result<Vec<u8>, DecodeError> {
61    let input = input.trim_end_matches('=');
62    let mut output = Vec::with_capacity(input.len() * 3 / 4);
63    let mut buffer = 0u32;
64    let mut bits = 0;
65
66    for &c in input.as_bytes() {
67        let val = match c {
68            b'A'..=b'Z' => c - b'A',
69            b'a'..=b'z' => c - b'a' + 26,
70            b'0'..=b'9' => c - b'0' + 52,
71            b'+' => 62,
72            b'/' => 63,
73            _ => return Err(DecodeError),
74        } as u32;
75
76        buffer = (buffer << 6) | val;
77        bits += 6;
78
79        if bits >= 8 {
80            bits -= 8;
81            output.push((buffer >> bits) as u8);
82        }
83    }
84    Ok(output)
85}