codetics_ocpp_ws/
base64.rs1const ALPHABET: &[u8; 64] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
7
8pub fn encode(input: &[u8]) -> String {
9 let mut out = String::with_capacity(input.len().div_ceil(3) * 4);
10 for chunk in input.chunks(3) {
11 let b = [
12 chunk[0],
13 *chunk.get(1).unwrap_or(&0),
14 *chunk.get(2).unwrap_or(&0),
15 ];
16 let n = (b[0] as u32) << 16 | (b[1] as u32) << 8 | b[2] as u32;
17 out.push(ALPHABET[(n >> 18) as usize & 63] as char);
18 out.push(ALPHABET[(n >> 12) as usize & 63] as char);
19 out.push(if chunk.len() > 1 {
20 ALPHABET[(n >> 6) as usize & 63] as char
21 } else {
22 '='
23 });
24 out.push(if chunk.len() > 2 {
25 ALPHABET[n as usize & 63] as char
26 } else {
27 '='
28 });
29 }
30 out
31}
32
33pub fn decode(input: &str) -> Option<Vec<u8>> {
34 let s = input.trim().as_bytes();
35 if !s.len().is_multiple_of(4) {
36 return None;
37 }
38 let val = |c: u8| -> Option<u32> {
39 Some(match c {
40 b'A'..=b'Z' => c - b'A',
41 b'a'..=b'z' => c - b'a' + 26,
42 b'0'..=b'9' => c - b'0' + 52,
43 b'+' => 62,
44 b'/' => 63,
45 _ => return None,
46 } as u32)
47 };
48 let mut out = Vec::with_capacity(s.len() / 4 * 3);
49 let chunks = s.len() / 4;
50 for (i, c) in s.as_chunks::<4>().0.iter().enumerate() {
51 let last = i + 1 == chunks;
52 let pad = if last {
53 c.iter().rev().take_while(|&&b| b == b'=').count()
54 } else {
55 0
56 };
57 if pad > 2 || (!last && c.contains(&b'=')) {
58 return None;
59 }
60 let mut n = 0u32;
61 for (j, &b) in c.iter().enumerate() {
62 let v = if j >= 4 - pad { 0 } else { val(b)? };
63 n = n << 6 | v;
64 }
65 out.push((n >> 16) as u8);
66 if pad < 2 {
67 out.push((n >> 8) as u8);
68 }
69 if pad < 1 {
70 out.push(n as u8);
71 }
72 }
73 Some(out)
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79
80 #[test]
81 fn rfc4648_vectors() {
82 for (raw, enc) in [
83 ("", ""),
84 ("f", "Zg=="),
85 ("fo", "Zm8="),
86 ("foo", "Zm9v"),
87 ("foob", "Zm9vYg=="),
88 ("fooba", "Zm9vYmE="),
89 ("foobar", "Zm9vYmFy"),
90 ] {
91 assert_eq!(encode(raw.as_bytes()), enc);
92 assert_eq!(decode(enc).unwrap(), raw.as_bytes());
93 }
94 assert!(decode("Zm9").is_none());
95 assert!(decode("Z=9v").is_none());
96 assert!(decode("Zm9v!A==").is_none());
97 }
98
99 #[test]
100 fn ocpp_basic_auth_example() {
101 let mut creds = b"AL1000:".to_vec();
103 creds.extend_from_slice(&[0, 1, 2, 3, 4, 5, 6, 7]);
104 creds.extend_from_slice(&[0xFF; 12]);
105 assert_eq!(encode(&creds), "QUwxMDAwOgABAgMEBQYH////////////////");
106 }
107}