ctoolbox/formats/
base64.rs1use std::collections::HashMap;
2
3use anyhow::{Result, anyhow};
4use base64::Engine;
5use base64::prelude::BASE64_STANDARD;
6
7use crate::bail_if_none;
8
9pub fn bytes_to_standard_base64(bytes: &[u8]) -> String {
12 BASE64_STANDARD.encode(bytes)
13}
14
15pub fn standard_base64_to_bytes(base64: String) -> Result<Vec<u8>> {
16 BASE64_STANDARD
17 .decode(base64)
18 .map_err(|e| anyhow!("Failed to decode base64: {e}"))
19}
20
21pub fn standard_base64_to_decimal(base64: String) -> Result<Vec<u8>> {
23 let alphabet = base64::alphabet::STANDARD.as_str();
24
25 let index: HashMap<u8, u8> = alphabet
27 .chars()
28 .enumerate()
29 .map(|(i, c)| (u8::try_from(c).unwrap(), u8::try_from(i).unwrap()))
30 .collect();
31
32 let mut out = Vec::new();
33 for byte in base64.bytes() {
35 if byte == 61 {
36 out.push(64);
37 } else {
38 out.push(bail_if_none!(index.get(&byte).copied()));
39 }
40 }
41 Ok(out)
42}
43
44pub fn decimal_to_standard_base64(decimal: Vec<u8>) -> Result<String> {
45 let alphabet = base64::alphabet::STANDARD.as_str();
46 let mut out = String::new();
47
48 for &value in &decimal {
49 let v = value;
50 if v == 64 {
51 out.push('=');
52 continue;
53 }
54 out.push(bail_if_none!(alphabet.chars().nth(usize::from(v))));
55 }
56
57 Ok(out)
58}
59
60#[cfg(test)]
61mod tests {
62 use crate::formats::assert_string_ok_eq;
63 use crate::utilities::{assert_vec_u8_eq, assert_vec_u8_ok_eq};
64
65 use super::*;
66
67 #[crate::ctb_test]
68 fn test_bytes_to_standard_base64() {
69 let input = b"Hello, world!";
70 let expected = "SGVsbG8sIHdvcmxkIQ==";
71 let result = bytes_to_standard_base64(input);
72 assert_eq!(result, expected);
73 }
74
75 #[crate::ctb_test]
76 fn test_standard_base64_to_bytes() {
77 let input = "SGVsbG8sIHdvcmxkIQ==".to_string();
78 let expected = b"Hello, world!";
79 let result = standard_base64_to_bytes(input).unwrap();
80 assert_vec_u8_eq(expected, &result);
81 }
82
83 #[crate::ctb_test]
84 fn test_base64_to_decimal() {
85 let input = "SGVsbG8sIHdvcmxkIQ==";
86 let expected = vec![
87 18, 6, 21, 44, 27, 6, 60, 44, 8, 7, 29, 47, 28, 38, 49, 36, 8, 16,
88 64, 64,
89 ];
90 let result = standard_base64_to_decimal(input.to_string());
91 assert_vec_u8_ok_eq(&expected, result);
92 }
93
94 #[crate::ctb_test]
95 fn test_decimal_to_base64() {
96 let input = vec![
97 18, 6, 21, 44, 27, 6, 60, 44, 8, 7, 29, 47, 28, 38, 49, 36, 8, 16,
98 64, 64,
99 ];
100 let expected = "SGVsbG8sIHdvcmxkIQ==";
101 let result = decimal_to_standard_base64(input);
102 assert_string_ok_eq(expected, result);
103 }
104}