1use 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 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 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 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 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); extend_u16::<B>(&mut result, 0x03);
191 extend_u16::<B>(&mut result, data.len() as u16); 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); extend_u16::<B>(&mut result, 0x05); extend_u16::<B>(&mut result, text.len() as u16); result.extend(text.value());
226 extend_u16::<B>(&mut result, 0xffff); extend_u16::<B>(&mut result, 0x0000); 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); extend_u16::<B>(&mut result, 0x02); extend_u16::<B>(&mut result, len); 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); extend_u16::<B>(&mut result, 0x01); extend_u16::<B>(&mut result, 1); result.push(0xDC); 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 let mut composer = composer::<B>().unwrap();
281 composer.write_descriptor(desc).unwrap();
282
283 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 + 4 + desc_type_len as usize + 4 + desc_data_len as usize ];
293
294 {
295 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); result_current = &mut result_current[2..];
302
303 B::write_u16(result_current, descriptor_type::ID); result_current = &mut result_current[2..];
306 B::write_u16(result_current, desc_type_len); 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 B::write_u16(result_current, descriptor_data::ID); result_current = &mut result_current[2..];
318 B::write_u16(result_current, desc_data_len); 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}