common: Add the yencode module.
[gps-watch.git] / src / common / yencode.rs
1 /*
2  * Copyright (c) 2017 Tilman Sauerbeck (tilman at code-monkey de)
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files (the
6  * "Software"), to deal in the Software without restriction, including
7  * without limitation the rights to use, copy, modify, merge, publish,
8  * distribute, sublicense, and/or sell copies of the Software, and to
9  * permit persons to whom the Software is furnished to do so, subject to
10  * the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be
13  * included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  */
23
24 use buffer::Buffer;
25 use crc32::Crc32;
26 use fmt::fmt_x32;
27
28 pub struct Yencode<'a> {
29     buffer: &'a mut Buffer,
30     crc: Crc32,
31 }
32
33 impl<'a> Yencode<'a> {
34     pub fn new(buffer: &mut Buffer) -> Yencode {
35         Yencode {
36             buffer: buffer,
37             crc: Crc32::new(),
38         }
39     }
40
41     pub fn start(&mut self, filename: &[u8]) {
42         self.buffer.write(b"=ybegin name=");
43         self.buffer.write(filename);
44         self.buffer.write(b"\n");
45     }
46
47     fn encode_line(&mut self, input_buf: &[u8], output_buf: &mut [u8]) {
48         let mut output_buf_offset = 0;
49
50         for input in input_buf {
51             let mut c : u8 = *input;
52             c += 42;
53
54             match c {
55                 b'\0' | b'\n' | b'\r' | b'=' => {
56                     output_buf[output_buf_offset] = b'=';
57                     output_buf_offset += 1;
58
59                     c += 64;
60                 },
61                 _ => {
62                 }
63             }
64
65             output_buf[output_buf_offset] = c;
66             output_buf_offset += 1;
67         }
68
69         output_buf[output_buf_offset] = b'\n';
70         output_buf_offset += 1;
71
72         if output_buf[0] == b'.' {
73             self.buffer.write(b".");
74         }
75
76         self.buffer.write(&output_buf[0..output_buf_offset]);
77     }
78
79     pub fn data(&mut self, buf: &[u8]) {
80         self.crc.update(buf);
81
82         const INPUT_BYTES_PER_LINE : usize = 128;
83
84         for chunk in buf.chunks(INPUT_BYTES_PER_LINE) {
85             let mut linebuf = [0u8; INPUT_BYTES_PER_LINE << 1];
86
87             self.encode_line(chunk, &mut linebuf);
88         }
89     }
90
91     pub fn finish(&mut self) {
92         let mut yend = [b' '; 23];
93
94         yend[0..].copy_from_slice(b"=yend crc32=xxxxxxxx\n.\n");
95
96         fmt_x32(&mut yend[12..], self.crc.finish());
97
98         self.buffer.write(&yend);
99     }
100 }