gcd_rs/
composer.rs

1//! Compose new GCD file
2
3use crate::record::checksum::{self, ChecksumRecord};
4use crate::record::descriptor::DescriptorRecord;
5use crate::record::filler::FillerRecord;
6use crate::record::firmware::FirmwareRecord;
7use crate::record::text::TextRecord;
8use crate::{
9    GcdDefaultEndian, MainRecord, Record, RecordHeader, RECORD_HEADER_LEN,
10};
11use byteorder::ByteOrder;
12use std::io::{Result, Write};
13use std::marker::PhantomData;
14
15#[derive(Debug, PartialEq, Eq, Clone, Copy)]
16struct WriteCheckSum<F> {
17    file: F,
18    sum: u8,
19}
20impl<F> Write for WriteCheckSum<F>
21where
22    F: std::io::Write,
23{
24    fn write(&mut self, buf: &[u8]) -> Result<usize> {
25        let len = self.file.write(buf)?;
26        for byte in buf.iter() {
27            self.sum = self.sum.wrapping_add(*byte);
28        }
29        Ok(len)
30    }
31
32    fn flush(&mut self) -> Result<()> {
33        self.file.flush()
34    }
35}
36impl<F> WriteCheckSum<F>
37where
38    F: std::io::Write,
39{
40    fn new(file: F) -> Self {
41        WriteCheckSum { file, sum: 0 }
42    }
43}
44
45impl<F> WriteCheckSum<F> {
46    const fn sum(&self) -> u8 {
47        self.sum
48    }
49}
50
51pub struct Composer<F, B = GcdDefaultEndian>
52where
53    F: std::io::Write,
54    B: ByteOrder,
55{
56    file: WriteCheckSum<F>,
57    endian: PhantomData<B>,
58}
59
60impl<F, B> Composer<F, B>
61where
62    F: std::io::Write,
63    B: ByteOrder,
64{
65    pub fn new(file: F) -> Result<Self> {
66        //write signature and version (100)
67        let mut sign = [0; 8];
68        let mut file = WriteCheckSum::new(file);
69        sign[..6].copy_from_slice(b"GARMIN");
70        B::write_u16(&mut sign[6..], 100);
71        file.write_all(&sign)?;
72        Ok(Composer {
73            file,
74            endian: PhantomData,
75        })
76    }
77
78    /// Write a record composed without any encoding
79    pub fn write_record_raw(&mut self, id: u16, data: &[u8]) -> Result<()> {
80        self.write_record_header(RecordHeader::Unknown {
81            id,
82            len: data.len() as u16,
83        })?;
84        self.file.write_all(&data)
85    }
86    /// Write a record, encoding its data
87    pub fn write_record(&mut self, record: &Record) -> Result<()> {
88        match record {
89            Record::Checksum(_) => self.write_check_point(),
90            Record::Filler(filler) => self.write_filler(filler),
91            Record::MainHeader(header) => self.write_main(header),
92            Record::Text(cop) => self.write_text(cop),
93            Record::Descriptor(desc) => self.write_descriptor(desc),
94            Record::FirmwareData(firm) => self.write_firmware(firm),
95            Record::End => self.write_end(),
96        }
97    }
98
99    fn write_record_header(&mut self, header: RecordHeader) -> Result<()> {
100        let mut data = [0; 4];
101        B::write_u16(&mut data[..2], header.id());
102        B::write_u16(&mut data[2..], header.len());
103        self.file.write_all(&data)
104    }
105    fn write_end(&mut self) -> Result<()> {
106        self.write_record_header(RecordHeader::End)
107    }
108    fn write_firmware(&mut self, record: &FirmwareRecord) -> Result<()> {
109        let mut data = vec![0; record.len() as usize + RECORD_HEADER_LEN];
110        record.record_to_raw::<B>(&mut data)?;
111        self.file.write_all(&data)
112    }
113    fn write_check_point(&mut self) -> Result<()> {
114        let mut data = [0; checksum::LEN as usize + RECORD_HEADER_LEN];
115        ChecksumRecord::record_to_raw::<B>(&mut data, self.file.sum())?;
116        self.file.write_all(&data)
117    }
118    fn write_filler(&mut self, filler: &FillerRecord) -> Result<()> {
119        let mut data = vec![0; filler.len() as usize + RECORD_HEADER_LEN];
120        filler.record_to_raw::<B>(&mut data)?;
121        self.file.write_all(&data)
122    }
123    fn write_main(&mut self, main: &MainRecord) -> Result<()> {
124        let mut data = vec![0; main.len() as usize + RECORD_HEADER_LEN];
125        main.record_to_raw::<B>(&mut data)?;
126        self.file.write_all(&data)
127    }
128    fn write_text(&mut self, text: &TextRecord) -> Result<()> {
129        let mut data = vec![0; text.len() as usize + RECORD_HEADER_LEN];
130        text.record_to_raw::<B>(&mut data)?;
131        self.file.write_all(&data)
132    }
133    fn write_descriptor<'a>(
134        &mut self,
135        descriptor: &DescriptorRecord,
136    ) -> Result<()> {
137        let desc_type_len = descriptor.record_type_len() as usize;
138        let desc_data_len = descriptor.record_data_len() as usize;
139        let mut data =
140            vec![0; desc_type_len + desc_data_len + (RECORD_HEADER_LEN * 2)];
141
142        let data_current = descriptor.record_type_to_raw::<B>(&mut data)?;
143        descriptor.record_data_to_raw::<B>(data_current)?;
144        self.file.write_all(&data)
145    }
146}
147
148#[cfg(test)]
149mod tests {
150    //use byteorder::{BigEndian, LittleEndian, ReadBytesExt};
151    use crate::composer::{Composer, WriteCheckSum};
152    use crate::record::descriptor::descriptor_data;
153    use crate::record::descriptor::descriptor_data::DescriptorData;
154    use crate::record::descriptor::descriptor_type;
155    use crate::record::descriptor::DescriptorRecord;
156    use crate::record::filler::FillerRecord;
157    use crate::record::main::{self, MainRecord};
158    use crate::record::text::TextRecord;
159    use byteorder::{ByteOrder, BE, LE};
160    use std::io::{Cursor, Result, Write};
161
162    fn composer<B: ByteOrder>() -> Result<Composer<Cursor<Vec<u8>>, B>> {
163        let file = Cursor::new(Vec::new());
164        Composer::new(file)
165    }
166
167    fn extend_u16<B: ByteOrder>(vec: &mut Vec<u8>, x: u16) {
168        let mut buf = [0u8; 2];
169        B::write_u16(&mut buf, x);
170        vec.extend(buf.iter())
171    }
172
173    #[test]
174    fn check_sum() {
175        let mut file = WriteCheckSum::new(Cursor::new(vec![0u8; 11]));
176        file.write_all(&[0x1]).unwrap();
177        file.write_all(&[0x2]).unwrap();
178        file.write_all(&[0x3, 0x4]).unwrap();
179        file.write_all(&[0x1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1])
180            .unwrap();
181        assert_eq!(file.sum().wrapping_neg(), 244);
182    }
183
184    fn check_main<B: ByteOrder>(header: &MainRecord, data: &[u8]) {
185        let mut composer = composer::<B>().unwrap();
186        composer.write_main(header).unwrap();
187
188        let mut result = vec![b'G', b'A', b'R', b'M', b'I', b'N'];
189        extend_u16::<B>(&mut result, 100); //header version
190        extend_u16::<B>(&mut result, 0x03);
191        extend_u16::<B>(&mut result, data.len() as u16); //record len
192        result.extend(data.iter());
193        assert_eq!(composer.file.file.get_ref(), &result);
194    }
195
196    #[test]
197    fn write_main() {
198        let main_header_hwid = MainRecord::DefaultHWID;
199        let main_header_pn = MainRecord::DefaultPartNumber;
200
201        let mut default_hwid_le = [0; 2];
202        let mut default_hwid_be = [0; 2];
203        LE::write_u16(&mut default_hwid_le, main::DEFAULT_HWID);
204        BE::write_u16(&mut default_hwid_be, main::DEFAULT_HWID);
205        check_main::<LE>(&main_header_hwid, &default_hwid_le);
206        check_main::<BE>(&main_header_hwid, &default_hwid_be);
207
208        let mut default_pn_le = [0; 9];
209        let mut default_pn_be = [0; 9];
210        LE::write_uint128(&mut default_pn_le, main::DEFAULT_PART_NUMBER, 9);
211        BE::write_uint128(&mut default_pn_be, main::DEFAULT_PART_NUMBER, 9);
212        check_main::<LE>(&main_header_pn, &default_pn_le);
213        check_main::<BE>(&main_header_pn, &default_pn_be);
214    }
215
216    fn check_text<B: ByteOrder>(text: &TextRecord) {
217        let mut composer = composer::<B>().unwrap();
218        composer.write_text(text).unwrap();
219        composer.write_end().unwrap();
220
221        let mut result = vec![b'G', b'A', b'R', b'M', b'I', b'N'];
222        extend_u16::<B>(&mut result, 100); //header version
223        extend_u16::<B>(&mut result, 0x05); //record id
224        extend_u16::<B>(&mut result, text.len() as u16); //record len
225        result.extend(text.value());
226        extend_u16::<B>(&mut result, 0xffff); //record end id
227        extend_u16::<B>(&mut result, 0x0000); //record end len
228        assert_eq!(composer.file.file.get_ref(), &result);
229    }
230
231    #[test]
232    fn write_text() {
233        let text = TextRecord::Simple("The text is XXXXXXXXX".to_string());
234        check_text::<LE>(&text);
235        check_text::<BE>(&text);
236        let text = TextRecord::Blob(b"The text is YYYYYYYYY".to_vec());
237        check_text::<LE>(&text);
238        check_text::<BE>(&text);
239    }
240
241    fn check_filler<B: ByteOrder>(len: u16) {
242        let mut composer = composer::<B>().unwrap();
243        let filler = FillerRecord::Zeros(len);
244        composer.write_filler(&filler).unwrap();
245
246        let mut result = vec![b'G', b'A', b'R', b'M', b'I', b'N'];
247        extend_u16::<B>(&mut result, 100); //header version
248        extend_u16::<B>(&mut result, 0x02); //record id
249        extend_u16::<B>(&mut result, len); //record len
250        result.extend(vec![0u8; len as usize].iter());
251        assert_eq!(composer.file.file.get_ref(), &result);
252    }
253
254    #[test]
255    fn write_filler() {
256        check_filler::<LE>(100);
257        check_filler::<BE>(100);
258    }
259
260    fn check_checkpoint<B: ByteOrder>() {
261        let mut composer = composer::<B>().unwrap();
262        composer.write_check_point().unwrap();
263
264        let mut result = vec![b'G', b'A', b'R', b'M', b'I', b'N'];
265        extend_u16::<B>(&mut result, 100); //header version
266        extend_u16::<B>(&mut result, 0x01); //record id
267        extend_u16::<B>(&mut result, 1); //record len
268        result.push(0xDC); //checksum value
269        assert_eq!(composer.file.file.get_ref(), &result);
270    }
271
272    #[test]
273    fn write_checksum() {
274        check_checkpoint::<LE>();
275        check_checkpoint::<BE>();
276    }
277
278    fn check_descriptor<B: ByteOrder>(desc: &DescriptorRecord) {
279        // generate using the compositor
280        let mut composer = composer::<B>().unwrap();
281        composer.write_descriptor(desc).unwrap();
282
283        // generate manualy
284        let desc_type_len = desc.record_type_len();
285        let desc_data_len = desc.record_data_len();
286        let mut result = vec![0;
287            8 + //sig
288            4 + // desc type header
289            desc_type_len as usize + // desc type body
290            4 + // desc data header
291            desc_data_len as usize //desc data body
292        ];
293
294        {
295            //manually generate the file on the result vec
296            //file signature
297            let mut result_current = result.as_mut_slice();
298            result_current[..6].copy_from_slice(b"GARMIN");
299            result_current = &mut result_current[6..];
300            B::write_u16(result_current, 100); //header version
301            result_current = &mut result_current[2..];
302
303            //write descriptor type record
304            B::write_u16(result_current, descriptor_type::ID); //record id
305            result_current = &mut result_current[2..];
306            B::write_u16(result_current, desc_type_len); //record len
307            result_current = &mut result_current[2..];
308            for descriptor in desc.iter() {
309                result_current = descriptor
310                    .descriptor_type()
311                    .to_raw::<B>(result_current)
312                    .unwrap();
313            }
314
315            //write decriptor data record
316            B::write_u16(result_current, descriptor_data::ID); //record id
317            result_current = &mut result_current[2..];
318            B::write_u16(result_current, desc_data_len); //record len
319            result_current = &mut result_current[2..];
320            for descriptor in desc.iter() {
321                result_current =
322                    descriptor.to_raw::<B>(result_current).unwrap();
323            }
324        }
325
326        assert_eq!(composer.file.file.get_ref().as_slice(), result.as_slice());
327    }
328
329    #[test]
330    fn write_descriptor() {
331        let descriptor = DescriptorRecord::Simple(vec![
332            DescriptorData::U8 { id: 1, data: 0 },
333            DescriptorData::U16 { id: 1, data: 0 },
334            DescriptorData::U32 { id: 1, data: 0 },
335            DescriptorData::U64 { id: 1, data: 0 },
336            DescriptorData::Other {
337                id: 1,
338                data: vec![0, 1, 2],
339            },
340            DescriptorData::End,
341        ]);
342        check_descriptor::<LE>(&descriptor.clone());
343        check_descriptor::<BE>(&descriptor);
344    }
345}