muter/codec/codecs/
bubblebabble.rs

1#![allow(unknown_lints)]
2#![allow(bare_trait_objects)]
3
4use codec::helpers::codecs::FilteredDecoder;
5use codec::Codec;
6use codec::CodecSettings;
7use codec::CodecTransform;
8use codec::Direction;
9use codec::Error;
10use codec::FlushState;
11use codec::Status;
12use codec::TransformableCodec;
13use std::cmp;
14use std::collections::BTreeMap;
15use std::io;
16
17pub const V: [u8; 6] = *b"aeiouy";
18pub const C: [u8; 17] = *b"bcdfghklmnprstvzx";
19
20pub const REVV: [i8; 256] = [
21    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
22    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
23    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
24    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
25    -1, 0, -1, -1, -1, 1, -1, -1, -1, 2, -1, -1, -1, -1, -1, 3, -1, -1, -1, -1, -1, 4, -1, -1, -1,
26    5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
27    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
28    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
29    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
30    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
31    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
32];
33pub const REVC: [i8; 256] = [
34    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
35    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
36    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
37    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
38    -1, -1, 0, 1, 2, -1, 3, 4, 5, -1, -1, 6, 7, 8, 9, -1, 10, -1, 11, 12, 13, -1, 14, -1, 16, -1,
39    15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
40    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
41    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
42    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
43    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
44    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
45];
46
47#[derive(Default)]
48pub struct TransformFactory {}
49
50impl TransformFactory {
51    pub fn new() -> Self {
52        TransformFactory {}
53    }
54}
55
56impl CodecTransform for TransformFactory {
57    fn factory(&self, r: Box<io::BufRead>, s: CodecSettings) -> Result<Box<io::BufRead>, Error> {
58        match s.dir {
59            Direction::Forward => Ok(Encoder::new().into_bufread(r, s.bufsize)),
60            Direction::Reverse => Ok(Decoder::new(s.strict).into_bufread(r, s.bufsize)),
61        }
62    }
63
64    fn options(&self) -> BTreeMap<String, String> {
65        BTreeMap::new()
66    }
67
68    fn can_reverse(&self) -> bool {
69        true
70    }
71
72    fn name(&self) -> &'static str {
73        "bubblebabble"
74    }
75}
76
77pub struct Encoder {
78    started: bool,
79    finished: bool,
80    c: usize,
81}
82
83impl Encoder {
84    fn new() -> Self {
85        Encoder {
86            started: false,
87            finished: false,
88            c: 1,
89        }
90    }
91
92    fn transform_chunk(inp: &[u8], outp: &mut [u8], c: usize) -> usize {
93        let inp = &inp[0..2];
94        let outp = &mut outp[0..6];
95
96        let c = c % 36;
97
98        outp[0] = V[(((inp[0] as usize >> 6) & 0x3) + c) % 6];
99        outp[1] = C[(inp[0] as usize >> 2) & 0xf];
100        outp[2] = V[((inp[0] as usize & 0x3) + (c / 6)) % 6];
101        outp[3] = C[(inp[1] as usize >> 4) & 0xf];
102        outp[4] = b'-';
103        outp[5] = C[(inp[1] as usize) & 0xf];
104
105        (c * 5) + (inp[0] as usize * 7) + (inp[1] as usize)
106    }
107
108    fn transform_final_chunk(inp: &[u8], outp: &mut [u8], c: usize) {
109        let outp = &mut outp[0..4];
110
111        let c = c % 36;
112
113        if inp.is_empty() {
114            outp[0] = V[c % 6];
115            outp[1] = C[16];
116            outp[2] = V[c / 6];
117        } else {
118            let d = inp[0];
119            outp[0] = V[(((d as usize >> 6) & 0x3) + c) % 6];
120            outp[1] = C[(d as usize >> 2) & 0xf];
121            outp[2] = V[((d as usize & 0x3) + (c / 6)) % 6];
122        }
123        outp[3] = b'x';
124    }
125}
126
127impl Codec for Encoder {
128    fn transform(&mut self, inp: &[u8], outp: &mut [u8], f: FlushState) -> Result<Status, Error> {
129        let (inp, outp, extra) = if !self.started {
130            if outp.is_empty() {
131                return Ok(Status::SeqError(0, 0));
132            }
133            self.started = true;
134            outp[0] = b'x';
135            (inp, &mut outp[1..], 1)
136        } else {
137            (inp, outp, 0)
138        };
139
140        let (is, os) = (2, 6);
141        let chunks = cmp::min(inp.len() / is, outp.len() / os);
142
143        if chunks == 0 {
144            return match (f, self.finished, inp.len(), outp.len()) {
145                (FlushState::Finish, false, _, len) if len >= 4 => {
146                    Self::transform_final_chunk(inp, outp, self.c);
147                    self.finished = true;
148                    Ok(Status::StreamEnd(0, 4 + extra))
149                }
150                (FlushState::Finish, true, _, _) => Ok(Status::StreamEnd(0, extra)),
151                (_, _, _, _) => Ok(Status::SeqError(0, extra)),
152            };
153        }
154        let (il, ol) = (inp.len(), outp.len());
155        self.c = (0..chunks).fold(self.c, |c, i| {
156            Self::transform_chunk(&inp[i * is..il], &mut outp[i * os..ol], c)
157        });
158        Ok(Status::Ok(chunks * is, chunks * os + extra))
159    }
160
161    fn chunk_size(&self) -> usize {
162        2
163    }
164
165    fn buffer_size(&self) -> usize {
166        7
167    }
168}
169
170#[derive(Default)]
171pub struct Decoder {
172    c: usize,
173    started: bool,
174    finished: bool,
175    strict: bool,
176}
177
178impl Decoder {
179    fn new(strict: bool) -> Self {
180        Self {
181            c: 1,
182            started: false,
183            finished: false,
184            strict,
185        }
186    }
187
188    fn transform_chunk(inp: &[u8], outp: &mut [u8], c: usize) -> Result<usize, Error> {
189        let inp = &inp[0..6];
190        let outp = &mut outp[0..2];
191
192        let c = c % 36;
193        let d = [
194            REVV[inp[0] as usize],
195            REVC[inp[1] as usize],
196            REVV[inp[2] as usize],
197            REVC[inp[3] as usize],
198            REVC[inp[5] as usize],
199        ];
200        if d.iter().any(|x| *x < 0) || inp[4] != b'-' {
201            return Err(Error::InvalidSequence(
202                "bubblebabble".to_string(),
203                inp.to_vec(),
204            ));
205        }
206        let ax = ((d[0] as u8) + 36 - (c as u8)) % 6;
207        let bx = d[1] as u8;
208        let cx = ((d[2] as u8) + 6 - ((c as u8) / 6)) % 6;
209        if ax >= 4 || cx >= 4 || bx >= 16 {
210            return Err(Error::InvalidSequence(
211                "bubblebabble".to_string(),
212                inp.to_vec(),
213            ));
214        }
215        outp[0] = (ax << 6) | (bx << 2) | cx;
216        outp[1] = ((d[3] as u8) << 4) | (d[4] as u8);
217        Ok((c * 5) + (outp[0] as usize * 7) + (outp[1] as usize))
218    }
219
220    fn transform_final_chunk(inp: &[u8], outp: &mut [u8], c: usize) -> Result<usize, Error> {
221        let inp = &inp[0..4];
222        let outp = &mut outp[0..1];
223
224        let c = c % 36;
225        let d = [
226            REVV[inp[0] as usize],
227            REVC[inp[1] as usize],
228            REVV[inp[2] as usize],
229        ];
230        if d.iter().any(|x| *x < 0) || inp[3] != b'x' {
231            return Err(Error::InvalidSequence(
232                "bubblebabble".to_string(),
233                inp.to_vec(),
234            ));
235        }
236
237        if d[1] == 16 {
238            if ((d[0] as u8) != ((c as u8) % 6)) || ((d[2] as u8) != ((c as u8) / 6)) {
239                return Err(Error::InvalidSequence(
240                    "bubblebabble".to_string(),
241                    inp.to_vec(),
242                ));
243            }
244            return Ok(0);
245        }
246
247        let ax = ((d[0] as u8) + 36 - (c as u8)) % 6;
248        let bx = d[1] as u8;
249        let cx = ((d[2] as u8) + 6 - ((c as u8) / 6)) % 6;
250        if ax >= 4 || cx >= 4 || bx >= 16 {
251            return Err(Error::InvalidSequence(
252                "bubblebabble".to_string(),
253                inp.to_vec(),
254            ));
255        }
256        outp[0] = (ax << 6) | (bx << 2) | cx;
257        Ok(1)
258    }
259}
260
261impl FilteredDecoder for Decoder {
262    fn strict(&self) -> bool {
263        self.strict
264    }
265
266    fn filter_byte(&self, b: u8) -> bool {
267        REVV[b as usize] != -1 || REVC[b as usize] != -1 || b == b'-'
268    }
269
270    fn internal_transform(
271        &mut self,
272        inp: &[u8],
273        outp: &mut [u8],
274        f: FlushState,
275    ) -> Result<Status, Error> {
276        let (inp, outp, extra) = if !self.started {
277            if inp.is_empty() {
278                return Ok(Status::SeqError(0, 0));
279            }
280            self.started = true;
281            if inp[0] != b'x' {
282                return Err(Error::InvalidSequence(
283                    "bubblebabble".to_string(),
284                    inp.to_vec(),
285                ));
286            }
287            (&inp[1..], outp, 1)
288        } else {
289            (inp, outp, 0)
290        };
291
292        let (is, os) = (6, 2);
293        let chunks = cmp::min(inp.len() / is, outp.len() / os);
294
295        if chunks == 0 {
296            return match (f, self.finished, inp.len(), outp.len()) {
297                (FlushState::Finish, false, 4, len) if len >= 2 => {
298                    let count = Self::transform_final_chunk(inp, outp, self.c)?;
299                    self.finished = true;
300                    Ok(Status::StreamEnd(4 + extra, count))
301                }
302                (FlushState::Finish, true, _, _) => Ok(Status::StreamEnd(extra, 0)),
303                (_, _, _, _) => Ok(Status::SeqError(extra, 0)),
304            };
305        }
306
307        let (il, ol) = (inp.len(), outp.len());
308        self.c = (0..chunks).fold(Ok(self.c), |res, i| {
309            let c = res?;
310            Self::transform_chunk(&inp[i * is..il], &mut outp[i * os..ol], c)
311        })?;
312        Ok(Status::Ok(chunks * is + extra, chunks * os))
313    }
314}
315
316impl Codec for Decoder {
317    fn transform(&mut self, inp: &[u8], outp: &mut [u8], f: FlushState) -> Result<Status, Error> {
318        self.wrap_transform(inp, outp, f)
319    }
320
321    fn chunk_size(&self) -> usize {
322        7
323    }
324
325    fn buffer_size(&self) -> usize {
326        2
327    }
328}
329
330#[cfg(test)]
331mod tests {
332    use chain::Chain;
333    use codec::registry::CodecRegistry;
334    use codec::tests;
335
336    fn check(inp: &[u8], outp: &[u8]) {
337        let reg = CodecRegistry::new();
338        for i in vec![2, 3, 4, 5, 6, 7, 512] {
339            let c = Chain::new(&reg, "bubblebabble", i, true);
340            assert_eq!(c.transform(inp.to_vec()).unwrap(), outp);
341        }
342
343        for i in vec![6, 7, 8, 9, 10, 11, 512] {
344            let c = Chain::new(&reg, "-bubblebabble", i, true);
345            assert_eq!(c.transform(outp.to_vec()).unwrap(), inp);
346            let c = Chain::new(&reg, "-bubblebabble", i, false);
347            assert_eq!(c.transform(outp.to_vec()).unwrap(), inp);
348        }
349    }
350
351    #[test]
352    fn encodes_bytes() {
353        check(b"", b"xexax");
354        check(b"1234567890", b"xesef-disof-gytuf-katof-movif-baxux");
355        check(b"Pineapple", b"xigak-nyryk-humil-bosek-sonax");
356        // SHA-1 of "foo".
357        check(
358            b"\x0b\xee\xc7\xb5\xea\x3f\x0f\xdb\xc9\x5d\x0d\xd4\x7f\x3c\x5b\xc2\x75\xda\x8a\x33",
359            b"xedov-vycir-hopof-zofot-radoh-tofyt-gezuf-sikus-dotet-pydif-faxux",
360        );
361        // MD-5 of "foo".
362        check(
363            b"\xac\xbd\x18\xdb\x4c\xc2\xf8\x5c\xed\xef\x65\x4f\xcc\xc4\xa4\xd8",
364            b"xorar-takyt-rufys-davuh-suruv-zinog-zifos-genet-moxix",
365        );
366    }
367
368    #[test]
369    fn default_tests() {
370        tests::round_trip("bubblebabble");
371        tests::basic_configuration("bubblebabble");
372        tests::invalid_data("bubblebabble");
373    }
374}