spyne_encoding/transfer/
base64.rs1static LOOKUP: &[u8; 64] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
2static REVERSE_LOOKUP: [u8; 128] = reverse_lookup();
3const fn reverse_lookup() -> [u8; 128] {
4 let mut rl: [u8; 128] = [0xFF; 128];
5 let mut idx: usize = 0;
6 while idx < 64 {
7 rl[LOOKUP[idx] as usize] = idx as u8;
8 idx += 1;
9 }
10
11 rl
12}
13
14pub fn encode(bytes: &[u8]) -> String {
15 let mut buffer = String::new();
16 encode_into(bytes, &mut buffer);
17
18 buffer
19}
20
21pub fn encode_into(bytes: &[u8], buffer: &mut String) {
22 let mut chunks = bytes.chunks_exact(3);
23 chunks.by_ref().for_each(|ch| {
24 let byte_num = (ch[0] as u32) << 16 | (ch[1] as u32) << 8 | ch[2] as u32;
25 let chunk1 = (byte_num >> 18) & 0x3F;
26 let chunk2 = (byte_num >> 12) & 0x3F;
27 let chunk3 = (byte_num >> 6) & 0x3F;
28 let chunk4 = (byte_num) & 0x3F;
29
30 [chunk1, chunk2, chunk3, chunk4].iter()
31 .for_each(|ch| {
32 buffer.push(LOOKUP[*ch as usize] as char);
33 });
34 });
35 let remainder = chunks.remainder();
36 match remainder.len() {
37 1 => {
38 let chunk1 = (remainder[0] >> 2) & 0x3F;
39 let chunk2 = (remainder[0] & 0x3) << 4;
40 [chunk1, chunk2].iter()
41 .for_each(|ch| {
42 buffer.push(LOOKUP[*ch as usize] as char);
43 });
44 buffer.push_str("==");
45 },
46 2 => {
47 let byte_num = (remainder[0] as u16) << 8 | remainder[1] as u16;
48 let chunk1 = (byte_num >> 10) & 0x3F;
49 let chunk2 = (byte_num >> 4) & 0x3F;
50 let chunk3 = ((byte_num) & 0xF) << 2;
51 [chunk1, chunk2, chunk3].iter()
52 .for_each(|ch| {
53 buffer.push(LOOKUP[*ch as usize] as char);
54 });
55 buffer.push('=');
56 },
57 _ => unreachable!()
58 }
59}
60
61pub fn decode(string: String) -> Vec<u8> {
62 let mut buffer = Vec::new();
63 decode_into(string, &mut buffer);
64
65 buffer
66}
67
68pub fn decode_into(string: String, buffer: &mut Vec<u8>) {
69 let string_bytes = string.as_bytes();
70 let len = string_bytes.len();
71 let mut chunks = string_bytes[..len - 4].chunks_exact(4);
72 chunks.by_ref().for_each(|ch| {
73 let chunk1 = REVERSE_LOOKUP[ch[0] as usize];
74 let chunk2 = REVERSE_LOOKUP[ch[1] as usize];
75 let chunk3 = REVERSE_LOOKUP[ch[2] as usize];
76 let chunk4 = REVERSE_LOOKUP[ch[3] as usize];
77 let byte_num = (chunk1 as u32) << 18 | (chunk2 as u32) << 12 | (chunk3 as u32) << 6 | chunk4 as u32;
78 let byte1 = ((byte_num >> 16) & 0xFF) as u8;
79 let byte2 = ((byte_num >> 8) & 0xFF) as u8;
80 let byte3 = (byte_num & 0xFF) as u8;
81 buffer.extend([byte1, byte2, byte3]);
82 });
83 let last_chunk = &string_bytes[len - 4..len];
84 if last_chunk[2] == b'=' && last_chunk[3] == b'=' {
85 let chunk1 = REVERSE_LOOKUP[last_chunk[0] as usize];
86 let chunk2 = REVERSE_LOOKUP[last_chunk[1] as usize];
87 let byte_num = ((chunk1 as u32) << 6 | chunk2 as u32) >> 4;
88 let byte1 = (byte_num & 0xFF) as u8;
89 buffer.push(byte1);
90 }
91 else if last_chunk[3] == b'=' {
92 let chunk1 = REVERSE_LOOKUP[last_chunk[0] as usize];
93 let chunk2 = REVERSE_LOOKUP[last_chunk[1] as usize];
94 let chunk3 = REVERSE_LOOKUP[last_chunk[2] as usize];
95 let byte_num = ((chunk1 as u32) << 12 | (chunk2 as u32) << 6 | chunk3 as u32) >> 2;
96 let byte1 = ((byte_num >> 8) & 0xFF) as u8;
97 let byte2 = (byte_num & 0xFF) as u8;
98 buffer.extend([byte1, byte2]);
99 }
100 else {
101 let chunk1 = REVERSE_LOOKUP[last_chunk[0] as usize];
102 let chunk2 = REVERSE_LOOKUP[last_chunk[1] as usize];
103 let chunk3 = REVERSE_LOOKUP[last_chunk[2] as usize];
104 let chunk4 = REVERSE_LOOKUP[last_chunk[3] as usize];
105 let byte_num = (chunk1 as u32) << 18 | (chunk2 as u32) << 12 | (chunk3 as u32) << 6 | chunk4 as u32;
106 let byte1 = ((byte_num >> 16) & 0xFF) as u8;
107 let byte2 = ((byte_num >> 8) & 0xFF) as u8;
108 let byte3 = (byte_num & 0xFF) as u8;
109 buffer.extend([byte1, byte2, byte3]);
110 }
111}
112
113#[cfg(test)]
114mod test {
115 use crate::transfer::base64::{decode, encode};
116
117 #[test]
118 fn test_base64_encoder() {
119 let encoded = encode(b"hello");
120 assert_eq!(encoded, "aGVsbG8=");
121 let decoded = decode("aGVsbG8=".to_string());
122 assert_eq!(decoded, b"hello");
123 }
124}