1use crate::alphabet::{Alphabet, ZBASE32, EncodeOrder};
3
4#[cfg(any(feature = "alloc", feature = "std", test))]
5use std::{string::String, vec};
6
7pub fn encoded_len(bytes_len: usize) -> Option<usize> {
9 let min_bytes = bytes_len / 5;
10 let rem = bytes_len % 5;
11 min_bytes.checked_mul(8).and_then(|c| c.checked_add(rem * 2 + 1))
12}
13
14pub fn encode_alphabet_slice<T: AsRef<[u8]>>(
17 input: T,
18 output_buf: &mut [u8],
19 alphabet: &Alphabet,
20) -> usize {
21 let encode_table = alphabet.encode_symbols;
22 let input_bytes = input.as_ref();
23 let mut remain = -1_i32;
24 let mut o = 0_usize;
25
26 if alphabet.encode_order == EncodeOrder::OrderInversed {
27 for i in 0..input_bytes.len() {
28 remain = match i % 5 {
29 0 => {
30 let x = input_bytes[i] as i32;
32 output_buf[o] = encode_table[(x & 0x1F) as usize];
33 o = o + 1;
34 x >> 5
35 },
36 1 => {
37 let inp = input_bytes[i] as i32;
39 let x = remain | inp << 3;
40 output_buf[o] = encode_table[(x & 0x1F) as usize];
41 o = o + 1;
42 output_buf[o] = encode_table[(x >> 5 & 0x1F) as usize];
43 o = o + 1;
44 x >> 10
45 }
46 2 => {
47 let inp = input_bytes[i] as i32;
49 let x = remain | inp << 1;
50 output_buf[o] = encode_table[(x & 0x1F) as usize];
51 o = o + 1;
52 x >> 5
53 },
54 3 => {
55 let inp = input_bytes[i] as i32;
57 let x = remain | inp << 4;
58 output_buf[o] = encode_table[(x & 0x1F) as usize];
59 o = o + 1;
60 output_buf[o] = encode_table[(x >> 5 & 0x1F) as usize];
61 o = o + 1;
62 x >> 10 & 0x3
63 },
64 4 => {
65 let inp = input_bytes[i] as i32;
67 let x = remain | inp << 2;
68 output_buf[o] = encode_table[(x & 0x1F) as usize];
69 o = o + 1;
70 output_buf[o] = encode_table[(x >> 5 & 0x1F) as usize];
71 o = o + 1;
72 -1
73 },
74 _ => unreachable!("Impossible remainder"),
75 };
76 }
77 }
78 else {
79 for i in 0..input_bytes.len() {
80 remain = match i % 5 {
81 0 => {
82 let inp = input_bytes[i] as i32;
84 let x = inp >> 3;
85 output_buf[o] = encode_table[(x & 0x1F) as usize];
86 o = o + 1;
87 (inp & 7) << 2
88 },
89 1 => {
90 let inp = input_bytes[i] as i32;
92 let x = (remain << 6) | inp;
93 output_buf[o] = encode_table[(x >> 6 & 0x1F) as usize];
94 o = o + 1;
95 output_buf[o] = encode_table[(x >> 1 & 0x1F) as usize];
96 o = o + 1;
97 (x & 0x1) << 4
98 }
99 2 => {
100 let inp = input_bytes[i] as i32;
102 let x = (remain << 4) | inp;
103 output_buf[o] = encode_table[(x >> 4 & 0x1F) as usize];
104 o = o + 1;
105 (x & 15) << 1
106 },
107 3 => {
108 let inp = input_bytes[i] as i32;
110 let x = remain << 7 | inp;
111 output_buf[o] = encode_table[(x >> 7 & 0x1F) as usize];
112 o = o + 1;
113 output_buf[o] = encode_table[(x >> 2 & 0x1F) as usize];
114 o = o + 1;
115 (x & 3) << 3
116 },
117 4 => {
118 let inp = input_bytes[i] as i32;
120 let x = remain << 5 | inp;
121 output_buf[o] = encode_table[(x >> 5 & 0x1F) as usize];
122 o = o + 1;
123 output_buf[o] = encode_table[(x & 0x1F) as usize];
124 o = o + 1;
125 -1
126 },
127 _ => unreachable!("Impossible remainder"),
128 };
129 }
130 }
131
132 if remain >= 0 {
133 output_buf[o] = encode_table[(remain & 0x1F) as usize];
134 o = o + 1;
135 }
136
137 o
138}
139
140#[cfg(any(feature = "alloc", feature = "std", test))]
158pub fn encode_alphabet<T: AsRef<[u8]>>(input: T, alphabet: &Alphabet) -> String {
159 let encoded_size = encoded_len(input.as_ref().len())
160 .expect("usize overflow when calculating buffer size");
161 let mut buf = vec![0; encoded_size];
162 let enc_len = encode_alphabet_slice(input, &mut buf[..], alphabet);
163 String::from_utf8(buf[0..enc_len].to_owned()).expect("Invalid UTF8")
164}
165
166#[cfg(any(feature = "alloc", feature = "std", test))]
181pub fn encode<T: AsRef<[u8]>>(input: T) -> String {
182 encode_alphabet(input, &ZBASE32)
183}
184
185#[cfg(test)]
186mod tests {
187 use crate::encode::*;
188 use crate::alphabet::*;
189
190 #[test]
191 fn simple_encode_zbase() {
192 assert_eq!(
193 "wm3g84fg13cy",
194 encode("test123"),
195 );
196 assert_eq!(
197 "em3ags7p",
198 encode("hello"),
199 );
200 }
201 #[test]
202 fn empty_encode_zbase() {
203 assert_eq!(
204 "",
205 encode(""),
206 );
207 }
208 #[test]
209 fn series_encode_zbase() {
210 assert_eq!(
211 "bd",
212 encode("a"),
213 );
214 assert_eq!(
215 "bmay",
216 encode("aa"),
217 );
218 assert_eq!(
219 "bmang",
220 encode("aaa"),
221 );
222 assert_eq!(
223 "bmansob",
224 encode("aaaa"),
225 );
226 assert_eq!(
227 "bmansofc",
228 encode("aaaaa"),
229 );
230 assert_eq!(
231 "bmansofcbd",
232 encode("aaaaaa"),
233 );
234 assert_eq!(
235 "bmansofcbmay",
236 encode("aaaaaaa"),
237 );
238 assert_eq!(
239 "bmansofcbmang",
240 encode("aaaaaaaa"),
241 );
242 }
243 #[test]
244 fn simple_encode_rfc() {
245 assert_eq!(
246 "ORSXG5BRGIZQ",
247 encode_alphabet("test123", &RFC),
248 );
249 assert_eq!(
250 "NBSWY3DP",
251 encode_alphabet("hello", &RFC),
252 );
253 }
254 #[test]
255 fn empty_encode_rfc() {
256 assert_eq!(
257 "",
258 encode_alphabet("", &RFC),
259 );
260 }
261 #[test]
262 fn series_encode_rfc() {
263 assert_eq!(
264 "ME",
265 encode_alphabet("a", &RFC),
266 );
267 assert_eq!(
268 "MFQQ",
269 encode_alphabet("aa", &RFC),
270 );
271 assert_eq!(
272 "MFQWC",
273 encode_alphabet("aaa", &RFC),
274 );
275 assert_eq!(
276 "MFQWCYI",
277 encode_alphabet("aaaa", &RFC),
278 );
279 assert_eq!(
280 "MFQWCYLB",
281 encode_alphabet("aaaaa", &RFC),
282 );
283 assert_eq!(
284 "MFQWCYLBME",
285 encode_alphabet("aaaaaa", &RFC),
286 );
287 assert_eq!(
288 "MFQWCYLBMFQQ",
289 encode_alphabet("aaaaaaa", &RFC),
290 );
291 assert_eq!(
292 "MFQWCYLBMFQWC",
293 encode_alphabet("aaaaaaaa", &RFC),
294 );
295 }
296}