1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196

static CHAR_TABLE: [char; 256] =
    ['\u{0}', '\u{0}', '\u{0}', '\u{0}', '\u{0}', '\u{0}', '\u{0}', '\u{0}', '\u{0}', '\u{0}',
     '\u{0}', '\u{0}', '\u{0}', '\u{0}', '\u{0}', '\u{0}', '\u{0}', '\u{0}', '\u{0}', '\u{0}',
     '\u{0}', '\u{0}', '\u{0}', '\u{0}', '\u{0}', '\u{0}', '\u{0}', '\u{0}', '\u{0}', '\u{0}',
     '\u{0}', '\u{0}', ' ', '!', '"', '#', '¤', '%', '&', '\'', '(', ')', '*', '+', ',', '-',
     '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
     '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q',
     'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', '`', 'a', 'b', 'c',
     'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u',
     'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', '\u{0}', '\u{0}', '\u{0}', '\u{0}', '\u{0}',
     '\u{0}', '\u{0}', '\u{0}', '\u{0}', '\u{0}', '\u{0}', '\u{0}', '\u{0}', '\u{0}', '\u{0}',
     '\u{0}', '\u{0}', '\u{0}', '\u{0}', '\u{0}', '\u{0}', '\u{0}', '\u{0}', '\u{0}', '\u{0}',
     '\u{0}', '\u{0}', '\u{0}', '\u{0}', '\u{0}', '\u{0}', '\u{0}', '\u{0}', '\u{00A0}',
     '\u{00A1}', '\u{00A2}', '\u{00A3}', '\u{0}', '\u{00A5}', '\u{0}', '\u{00A7}', '\u{00A4}',
     '\u{2018}', '\u{201C}', '\u{00AB}', '\u{2190}', '\u{2191}', '\u{2193}', '\u{2193}',
     '\u{00B0}', '\u{00B1}', '\u{00B2}', '\u{00B3}', '\u{00D7}', '\u{00B5}', '\u{00B6}',
     '\u{00B7}', '\u{00F7}', '\u{2019}', '\u{201D}', '\u{00BB}', '\u{00BC}', '\u{00BD}',
     '\u{00BE}', '\u{00BF}', '\u{0}', '\u{0300}', '\u{0301}', '\u{0302}', '\u{0303}', '\u{0304}',
     '\u{0306}', '\u{0307}', '\u{0308}', '\u{0}', '\u{030A}', '\u{0327}', '\u{0}', '\u{030B}',
     '\u{0328}', '\u{030C}', '\u{2015}', '\u{00B9}', '\u{00AE}', '\u{00A9}', '\u{2122}',
     '\u{266A}', '\u{00AC}', '\u{00A6}', '\u{0}', '\u{0}', '\u{0}', '\u{0}', '\u{215B}',
     '\u{215C}', '\u{215D}', '\u{215E}', '\u{2126}', '\u{00C6}', '\u{0110}', '\u{00AA}',
     '\u{0126}', '\u{0}', '\u{0132}', '\u{013F}', '\u{0141}', '\u{00D8}', '\u{0152}', '\u{00BA}',
     '\u{00DE}', '\u{0166}', '\u{014A}', '\u{0149}', '\u{0138}', '\u{00E6}', '\u{0111}',
     '\u{00F0}', '\u{0127}', '\u{0131}', '\u{0133}', '\u{0140}', '\u{0142}', '\u{00F8}',
     '\u{0153}', '\u{00DF}', '\u{00FE}', '\u{0167}', '\u{014B}', '\u{00AD}'];

static CHAR_DIA_TABLE: [[char; 26 * 2 + 6]; 15] =
    [//0xC1
     ['À', '#', '#', '#', 'È', '#', '#', '#', 'Ì', '#', '#', '#', '#', '#', 'Ò', '#', '#',
      '#', '#', '#', 'Ù', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', 'à', '#', '#',
      '#', 'è', '#', '#', '#', 'ì', '#', '#', '#', '#', '#', 'ò', '#', '#', '#', '#', '#',
      'ù', '#', '#', '#', '#', '#'],
     //0xC2
     ['Á', '#', 'Ć', '#', 'É', '#', '#', '#', 'Í', '#', '#', 'Ĺ', '#', 'Ń', 'Ó', '#', '#',
      'Ŕ', 'Ś', '#', 'Ú', '#', '#', '#', 'Ý', 'Ź', '#', '#', '#', '#', '#', '#', 'á', '#',
      'ć', '#', 'é', '#', 'ģ', '#', 'í', '#', '#', 'ĺ', '#', 'ń', 'ó', '#', '#', 'ŕ',
      'ś', '#', 'ú', '#', '#', '#', 'ý', 'ź'],
     //0xC3
     ['Â', '#', 'Ĉ', '#', 'Ê', '#', 'Ĝ', 'Ĥ', 'Î', 'Ĵ', '#', '#', '#', '#', 'Ô', '#',
      '#', '#', 'Ŝ', '#', 'Û', '#', 'Ŵ', '#', 'Ŷ', '#', '#', '#', '#', '#', '#', '#', 'â',
      '#', 'ĉ', '#', 'ê', '#', 'ĝ', 'ĥ', 'î', 'ĵ', '#', '#', '#', '#', 'ô', '#', '#', '#',
      'ŝ', '#', 'û', '#', 'ŵ', '#', 'ŷ', '#'],
     //0xC4
     ['Ã', '#', '#', '#', '#', '#', '#', '#', 'Ĩ', '#', '#', '#', '#', 'Ñ', 'Õ', '#', '#',
      '#', '#', '#', 'Ũ', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', 'ã', '#', '#',
      '#', '#', '#', '#', '#', 'ĩ', '#', '#', '#', '#', 'ñ', 'õ', '#', '#', '#', '#', '#',
      'ũ', '#', '#', '#', '#', '#'],
     //0xC5
     ['Ā', '#', '#', '#', 'Ē', '#', '#', '#', 'Ī', '#', '#', '#', '#', '#', 'Ō', '#', '#',
      '#', '#', '#', 'Ū', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', 'ā', '#', '#',
      '#', 'ē', '#', '#', '#', 'ī', '#', '#', '#', '#', '#', 'ō', '#', '#', '#', '#', '#',
      'ū', '#', '#', '#', '#', '#'],
     //0xC6
     ['Ă', '#', '#', '#', '#', '#', 'Ğ', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#',
      '#', '#', 'Ŭ', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', 'ă', '#', '#', '#',
      '#', '#', 'ğ', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', 'ŭ', '#',
      '#', '#', '#', '#'],
     //0xC7
     ['#', '#', 'Ċ', '#', 'Ė', '#', 'Ġ', '#', 'İ', '#', '#', '#', '#', '#', '#', '#', '#',
      '#', '#', '#', '#', '#', '#', '#', '#', 'Ż', '#', '#', '#', '#', '#', '#', '#', '#', 'ċ',
      '#', 'ė', '#', 'ġ', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#',
      '#', '#', '#', '#', 'ż'],
     //0xC8
     ['Ä', '#', '#', '#', 'Ë', '#', '#', '#', 'Ï', '#', '#', '#', '#', '#', 'Ö', '#', '#',
      '#', '#', '#', 'Ü', '#', '#', '#', 'Ÿ', '#', '#', '#', '#', '#', '#', '#', 'ä', '#',
      '#', '#', 'ë', '#', '#', '#', 'ï', '#', '#', '#', '#', '#', 'ö', '#', '#', '#', '#',
      '#', 'ü', '#', '#', '#', 'ÿ', '#'],
     //0xC9 (dummy)
     ['#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#',
      '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#',
      '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#',
      '#', '#', '#', '#'],
     //0xCA
     ['Å', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#',
      '#', '#', 'Ů', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', 'å', '#', '#', '#',
      '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', 'ů', '#',
      '#', '#', '#', '#'],
     //0xCB
     ['#', '#', 'Ç', '#', '#', '#', 'Ģ', '#', '#', '#', 'Ķ', 'Ļ', '#', 'Ņ', '#', '#', '#',
      'Ŗ', 'Ş', 'Ţ', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#',
      'ç', '#', '#', '#', '#', '#', '#', '#', 'ķ', 'ļ', '#', 'ņ', '#', '#', '#', 'ŗ', 'ş',
      'ţ', '#', '#', '#', '#', '#', '#'],
     //0xCC (dummy)
     ['#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#',
      '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#',
      '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#',
      '#', '#', '#', '#'],
     //0xCD
     ['#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', 'Ő', '#', '#', '#',
      '#', '#', 'Ű', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#',
      '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', 'ő', '#', '#', '#', '#', '#', 'ű', '#',
      '#', '#', '#', '#'],
     //0xCE
     ['Ą', '#', '#', '#', 'Ę', '#', '#', '#', 'Į', '#', '#', '#', '#', '#', '#', '#', '#',
      '#', '#', '#', 'Ų', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', 'ą', '#', '#',
      '#', 'ę', '#', '#', '#', 'į', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#',
      'ų', '#', '#', '#', '#', '#'],
     //0xCF
     ['#', '#', 'Č', 'Ď', 'Ě', '#', '#', '#', '#', '#', '#', 'Ľ', '#', 'Ň', '#', '#', '#',
      'Ř', 'Š', 'Ť', '#', '#', '#', '#', '#', 'Ž', '#', '#', '#', '#', '#', '#', '#', '#',
      'č', 'ď', 'ě', '#', '#', '#', '#', '#', '#', 'ľ', '#', 'ň', '#', '#', '#', 'ř', 'š',
      'ť', '#', '#', '#', '#', '#', 'ž']];

pub fn decode(data: &[u8]) -> String {
    let mut res = String::from("");
    let mut i = 0;
    loop {
        if i >= data.len() {
            break;
        }
        let c = data[i];
        if c >= 0xC1 && c <= 0xCF {
            let next = data[i + 1];
            let ch = CHAR_DIA_TABLE[(c - 0xC1) as usize][(next - 0x41) as usize];
            i += 1;
            res.push(ch);
        } else {
            res.push(CHAR_TABLE[c as usize]);
        }
        i += 1;
    }
    return res;
}

pub fn encode(data: &str) -> Vec<u8> {
    let mut res = vec![];
    for c in data.chars() {
        let mut val = 0u8;
        if c == '\n' {
            val = 0x8a;
        }
        if val == 0 {
            for (v, ch) in CHAR_TABLE.iter().enumerate() {
                if c == *ch {
                    val = v as u8;
                    break;
                }
            }
        }
        if val == 0 {
            let mut found = false;
            for i in 0..CHAR_DIA_TABLE.len() {
                let table = CHAR_DIA_TABLE[i];
                for j in 0..table.len() {
                    if c == table[j] {
                        res.push((i + 0xC1) as u8);
                        val = (j + 0x41) as u8;
                        found = true;
                        break;
                    }
                }
                if found {
                    break;
                }
            }
        }
        if val == 0 {
            val = 0x20; // default to space
        }
        res.push(val);
    }
    return res;
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_encode() {
        let in1 = "aeiouyéèûāż";
        let in2 = "AEIOUYÉÈÛĀĊ";
        let out1 = vec![0x61, 0x65, 0x69, 0x6F, 0x75, 0x79, 0xC2, 0x65, 0xC1, 0x65, 0xC3, 0x75,
                        0xC5, 0x61, 0xC7, 0x7A];
        let out2 = vec![0x41, 0x45, 0x49, 0x4F, 0x55, 0x59, 0xC2, 0x45, 0xC1, 0x45, 0xC3, 0x55,
                        0xC5, 0x41, 0xC7, 0x43];

        assert_eq!(encode(in1), out1);
        assert_eq!(encode(in2), out2);
    }

    #[test]
    fn test_decode() {
        let in1 = vec![0x61, 0x65, 0x69, 0x6F, 0x75, 0x79, 0xC2, 0x65, 0xC1, 0x65, 0xC3, 0x75,
                       0xC5, 0x61, 0xC7, 0x7A];
        let in2 = vec![0x41, 0x45, 0x49, 0x4F, 0x55, 0x59, 0xC2, 0x45, 0xC1, 0x45, 0xC3, 0x55,
                       0xC5, 0x41, 0xC7, 0x43];
        let out1 = "aeiouyéèûāż";
        let out2 = "AEIOUYÉÈÛĀĊ";

        assert_eq!(decode(&in1), out1);
        assert_eq!(decode(&in2), out2);
    }
}