rcnb_rs/
decode.rs

1use crate::{SB, SC, SNB, SCNB, CRMAP, CCMAP, CNMAP, CBMAP};
2
3macro_rules! index_of_and_char_at {
4    ($rcnb:ident, $chars:expr, $index:expr) => {
5        {
6            let char = $chars.get($index);
7            if char.is_none() {
8                Some(&0usize)
9            } else {
10                $rcnb.get(char.unwrap())
11            }
12        }
13    };
14}
15
16fn decode_byte(chars: &[char]) -> u8 {
17    let mut nb = false;
18    let idx = (|| Some([index_of_and_char_at!(CRMAP, chars, 0)?, index_of_and_char_at!(CCMAP, chars, 1)?]))()
19        .or_else(|| {
20            nb = true;
21            (|| Some([index_of_and_char_at!(CNMAP, chars, 0)?, index_of_and_char_at!(CBMAP, chars, 1)?]))()
22        })
23        .expect("not rc/nb");
24    let result = if nb { idx[0] * SB as usize + idx[1] } else { idx[0] * SC as usize + idx[1] };
25    if result > 0x7E {
26        panic!("rc/nb overflow")
27    }
28
29    (if nb { result | 0x80 } else { result }) as u8
30}
31
32fn decode_short(chars: &[char]) -> usize {
33    let reverse = !CRMAP.contains_key(&chars[0]);
34    let what_is_idx = |order: &[usize; 4]| Some([
35        index_of_and_char_at!(CRMAP, chars, order[0])?,
36        index_of_and_char_at!(CCMAP, chars, order[1])?,
37        index_of_and_char_at!(CNMAP, chars, order[2])?,
38        index_of_and_char_at!(CBMAP, chars, order[3])?
39    ]);
40
41    let idx = if !reverse {
42        what_is_idx(&[0, 1, 2, 3])
43    } else {
44        what_is_idx(&[2, 3, 0, 1])
45    }.expect("not rcnb");
46
47    let result = idx[0] * SCNB as usize + idx[1] * SNB as usize + idx[2] * SB as usize + idx[3];
48
49    if result > 0x7FFF {
50        panic!("rcnb overflow")
51    }
52
53    if reverse { result | 0x8000 } else { result }
54}
55
56pub fn decode(s: &str) -> String {
57    let len = s.chars().count();
58    if (len & 1) != 0 {
59        panic!("invalid length")
60    }
61    let mut v = Vec::with_capacity(len / 2);
62
63    let mut i = 0;
64    let vc = s.chars().collect::<Vec<char>>();
65    while i < (len >> 2) {
66        let start = i * 4;
67        let short = decode_short(&vc[start..start + 4]);
68        v.push((short >> 8) as u8);
69        v.push((short & 0xFF) as u8);
70
71        i += 1;
72    }
73    if (len & 2) != 0 {
74        v.push(decode_byte(&vc[len-2..]))
75    }
76
77    unsafe { String::from_utf8_unchecked(v) }
78}