1 use std::collections::{HashMap, HashSet};
2 use std::iter::Iterator;
3
main()4 fn main() {
5 println!("pub const INVALID_VALUE: u8 = 255;");
6
7 // A-Z
8 let standard_alphabet: Vec<u8> = (0x41..0x5B)
9 // a-z
10 .chain(0x61..0x7B)
11 // 0-9
12 .chain(0x30..0x3A)
13 // +
14 .chain(0x2B..0x2C)
15 // /
16 .chain(0x2F..0x30)
17 .collect();
18 print_encode_table(&standard_alphabet, "STANDARD_ENCODE", 0);
19 print_decode_table(&standard_alphabet, "STANDARD_DECODE", 0);
20
21 // A-Z
22 let url_alphabet: Vec<u8> = (0x41..0x5B)
23 // a-z
24 .chain(0x61..0x7B)
25 // 0-9
26 .chain(0x30..0x3A)
27 // -
28 .chain(0x2D..0x2E)
29 // _
30 .chain(0x5F..0x60)
31 .collect();
32 print_encode_table(&url_alphabet, "URL_SAFE_ENCODE", 0);
33 print_decode_table(&url_alphabet, "URL_SAFE_DECODE", 0);
34
35 // ./0123456789
36 let crypt_alphabet: Vec<u8> = (b'.'..(b'9' + 1))
37 // A-Z
38 .chain(b'A'..(b'Z' + 1))
39 // a-z
40 .chain(b'a'..(b'z' + 1))
41 .collect();
42 print_encode_table(&crypt_alphabet, "CRYPT_ENCODE", 0);
43 print_decode_table(&crypt_alphabet, "CRYPT_DECODE", 0);
44
45 // ./
46 let bcrypt_alphabet: Vec<u8> = (b'.'..(b'/' + 1))
47 // A-Z
48 .chain(b'A'..(b'Z' + 1))
49 // a-z
50 .chain(b'a'..(b'z' + 1))
51 // 0-9
52 .chain(b'0'..(b'9' + 1))
53 .collect();
54 print_encode_table(&bcrypt_alphabet, "BCRYPT_ENCODE", 0);
55 print_decode_table(&bcrypt_alphabet, "BCRYPT_DECODE", 0);
56
57 // A-Z
58 let imap_alphabet: Vec<u8> = (0x41..0x5B)
59 // a-z
60 .chain(0x61..0x7B)
61 // 0-9
62 .chain(0x30..0x3A)
63 // +
64 .chain(0x2B..0x2C)
65 // ,
66 .chain(0x2C..0x2D)
67 .collect();
68 print_encode_table(&imap_alphabet, "IMAP_MUTF7_ENCODE", 0);
69 print_decode_table(&imap_alphabet, "IMAP_MUTF7_DECODE", 0);
70
71 // '!' - '-'
72 let binhex_alphabet: Vec<u8> = (0x21..0x2E)
73 // 0-9
74 .chain(0x30..0x3A)
75 // @-N
76 .chain(0x40..0x4F)
77 // P-V
78 .chain(0x50..0x57)
79 // X-[
80 .chain(0x58..0x5C)
81 // `-f
82 .chain(0x60..0x66)
83 // h-m
84 .chain(0x68..0x6E)
85 // p-r
86 .chain(0x70..0x73)
87 .collect();
88 print_encode_table(&binhex_alphabet, "BINHEX_ENCODE", 0);
89 print_decode_table(&binhex_alphabet, "BINHEX_DECODE", 0);
90 }
91
print_encode_table(alphabet: &[u8], const_name: &str, indent_depth: usize)92 fn print_encode_table(alphabet: &[u8], const_name: &str, indent_depth: usize) {
93 check_alphabet(alphabet);
94 println!("#[rustfmt::skip]");
95 println!(
96 "{:width$}pub const {}: &[u8; 64] = &[",
97 "",
98 const_name,
99 width = indent_depth
100 );
101
102 for (i, b) in alphabet.iter().enumerate() {
103 println!(
104 "{:width$}{}, // input {} (0x{:X}) => '{}' (0x{:X})",
105 "",
106 b,
107 i,
108 i,
109 String::from_utf8(vec![*b as u8]).unwrap(),
110 b,
111 width = indent_depth + 4
112 );
113 }
114
115 println!("{:width$}];", "", width = indent_depth);
116 }
117
print_decode_table(alphabet: &[u8], const_name: &str, indent_depth: usize)118 fn print_decode_table(alphabet: &[u8], const_name: &str, indent_depth: usize) {
119 check_alphabet(alphabet);
120 // map of alphabet bytes to 6-bit morsels
121 let mut input_to_morsel = HashMap::<u8, u8>::new();
122
123 // standard base64 alphabet bytes, in order
124 for (morsel, ascii_byte) in alphabet.iter().enumerate() {
125 // truncation cast is fine here
126 let _ = input_to_morsel.insert(*ascii_byte, morsel as u8);
127 }
128
129 println!("#[rustfmt::skip]");
130 println!(
131 "{:width$}pub const {}: &[u8; 256] = &[",
132 "",
133 const_name,
134 width = indent_depth
135 );
136 for ascii_byte in 0..256 {
137 let (value, comment) = match input_to_morsel.get(&(ascii_byte as u8)) {
138 None => (
139 "INVALID_VALUE".to_string(),
140 format!("input {} (0x{:X})", ascii_byte, ascii_byte),
141 ),
142 Some(v) => (
143 format!("{}", *v),
144 format!(
145 "input {} (0x{:X} char '{}') => {} (0x{:X})",
146 ascii_byte,
147 ascii_byte,
148 String::from_utf8(vec![ascii_byte as u8]).unwrap(),
149 *v,
150 *v
151 ),
152 ),
153 };
154
155 println!(
156 "{:width$}{}, // {}",
157 "",
158 value,
159 comment,
160 width = indent_depth + 4
161 );
162 }
163 println!("{:width$}];", "", width = indent_depth);
164 }
165
check_alphabet(alphabet: &[u8])166 fn check_alphabet(alphabet: &[u8]) {
167 assert_eq!(64, alphabet.len());
168 let mut set: HashSet<u8> = HashSet::new();
169 set.extend(alphabet);
170 assert_eq!(64, set.len());
171 }
172