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(®, "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(®, "-bubblebabble", i, true);
345 assert_eq!(c.transform(outp.to_vec()).unwrap(), inp);
346 let c = Chain::new(®, "-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 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 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}