base64_string/
lib.rs

1//! base64-string
2//!
3//! Implementation of the Base64 hash made using Rust
4use std::char;
5use std::collections::HashMap;
6
7const BASE64ALPHABET: &str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
8
9/// Base64 encode string
10///
11/// # Example
12///
13/// ```rust
14/// let string = "Hi!";
15/// let result = base64_string::encode(string);
16/// assert_eq!(result, String::from("SGkh"));
17/// ```
18///
19pub fn encode(string: &str) -> String {
20    let chars: Vec<char> = string.chars().collect();
21    let alphabet: Vec<char> = BASE64ALPHABET.chars().collect();
22    let mut result = String::new();
23
24    let mut i = 0;
25
26    while i < chars.len() {
27        let chr1 = chars[i] as u32;
28        i += 1;
29
30        let chr2 = if i == chars.len() { 0 } else { chars[i] as u32 };
31        i += 1;
32
33        let chr3 = if i >= chars.len() { 0 } else { chars[i] as u32 };
34        i += 1;
35
36        let res1 = chr1 >> 2;
37        let res2 = ((chr1 & 3) << 4) | (chr2 >> 4);
38
39        let mut res3 = ((chr2 & 15) << 2) | (chr3 >> 6);
40        let mut res4 = chr3 & 63;
41
42        if chr2 == 0 {
43            res3 = 64;
44            res4 = 64;
45        } else if chr3 == 0 {
46            res4 = 64;
47        }
48
49        result.push(alphabet[res1 as usize]);
50        result.push(alphabet[res2 as usize]);
51        result.push(alphabet[res3 as usize]);
52        result.push(alphabet[res4 as usize]);
53    }
54
55    result
56}
57
58/// Base64 decode string
59///
60/// # Example
61///
62/// ```rust
63/// let string = "SGkh";
64/// let result = base64_string::decode(string);
65/// assert_eq!(result, String::from("Hi!"));
66/// ```
67///
68pub fn decode(string: &str) -> String {
69    let chars: Vec<char> = string.chars().collect();
70    let alphabet: Vec<char> = BASE64ALPHABET.chars().collect();
71    let mut alphabet_num = HashMap::new();
72    let mut result = String::new();
73
74    for (i, chr) in alphabet.iter().enumerate() {
75        alphabet_num.insert(chr, i as u32);
76    }
77
78    let mut i = 0;
79
80    while i < chars.len() {
81        let mut bits: u32 = 0;
82        let bytes;
83
84        bits |= alphabet_num[&chars[i]] << 18;
85        bits |= alphabet_num[&chars[i + 1]] << 12;
86
87        if alphabet_num[&chars[i + 2]] == 64 {
88            bytes = bits.to_be_bytes()[1..2].to_vec();
89        } else if alphabet_num[&chars[i + 3]] == 64 {
90            bits |= alphabet_num[&chars[i + 2]] << 6;
91            bytes = bits.to_be_bytes()[1..3].to_vec();
92        } else {
93            bits |= alphabet_num[&chars[i + 2]] << 6;
94            bits |= alphabet_num[&chars[i + 3]];
95            bytes = bits.to_be_bytes()[1..4].to_vec();
96        }
97
98        let characters = std::str::from_utf8(&bytes);
99        match characters {
100            Ok(characters) => result.push_str(characters),
101            Err(_) => result.push_str(&String::new()),
102        }
103
104        i += 4;
105    }
106
107    result
108}
109
110#[cfg(test)]
111mod tests {
112    use super::*;
113
114    #[test]
115    fn it_works() {
116        assert_eq!(encode("Hi!"), String::from("SGkh"));
117        assert_eq!(encode("Test"), String::from("VGVzdA=="));
118        assert_eq!(encode("Rust"), String::from("UnVzdA=="));
119        assert_eq!(
120            encode("Lorem ipsum dolor sit amet, consectetur adipiscing elit"),
121            String::from(
122                "TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdA=="
123            )
124        );
125
126        assert_eq!(decode("SGkh"), String::from("Hi!"));
127        assert_eq!(decode("VGVzdA=="), String::from("Test"));
128        assert_eq!(decode("UnVzdA=="), String::from("Rust"));
129        assert_eq!(
130            decode("TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdA=="),
131            String::from("Lorem ipsum dolor sit amet, consectetur adipiscing elit")
132        );
133    }
134}