gcd_rs/
parser.rs

1//! Parse an existing GCD file.
2
3use byteorder::ByteOrder;
4use std::io::{Error, ErrorKind, Read, Result};
5
6use crate::record::checksum::ChecksumRecord;
7use crate::record::descriptor::descriptor_data::DescriptorDecoded;
8use crate::record::descriptor::{DescriptorRecord, DescriptorTypeRecord};
9use crate::record::filler::FillerRecord;
10use crate::record::firmware::FirmwareRecord;
11use crate::record::main::MainRecord;
12use crate::record::text::TextRecord;
13use crate::{GcdDefaultEndian, Record, RecordHeader};
14
15use std::marker::PhantomData;
16
17//Parser state, acusing if data is out of order in the file
18// T  => TextRecord
19// M  => MainRecord
20// DT => DescriptorTypeRecord
21// DD => DescriptorDataRecord
22// FD => FirmwareDataRecord
23// E  => EndRecord
24//
25// File: C* M C* (DT DD FD* C*)+ E
26#[derive(Debug, PartialEq, Copy, Clone)]
27enum ParseState {
28    TextGlobal,
29    Main,
30    DescriptorType,
31    DescriptorData,
32    FirmwareData,
33    End,
34}
35
36struct ReadCheckSum<F> {
37    file: F,
38    sum: u8,
39}
40
41impl<F> Read for ReadCheckSum<F>
42where
43    F: std::io::Read,
44{
45    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
46        let read = self.file.read(buf)?;
47        for byte in buf[0..read].iter() {
48            self.sum = self.sum.wrapping_add(*byte);
49        }
50        Ok(read)
51    }
52}
53
54impl<F> ReadCheckSum<F>
55where
56    F: std::io::Read,
57{
58    fn new(file: F) -> Self {
59        ReadCheckSum { file, sum: 0 }
60    }
61}
62
63impl<F> ReadCheckSum<F> {
64    const fn sum(&self) -> u8 {
65        self.sum
66    }
67}
68
69// information extracted from Descriptor used to process the firmware chunk
70#[derive(Default)]
71struct FirmwareData {
72    // id of the firmware record
73    id: u16,
74    // xor key used to decode the firmware, 0 is no key
75    xor_key: u8,
76    // firmware total lenght
77    lenght: u32,
78    // firmware len that need to be consumend before the end
79    lenght_left: u32,
80}
81
82pub struct Parser<F, B = GcdDefaultEndian>
83where
84    F: std::io::Read,
85    B: ByteOrder,
86{
87    state: ParseState,
88    file: ReadCheckSum<F>,
89    descriptor_type: DescriptorTypeRecord,
90    firmware: FirmwareData,
91    endian: PhantomData<B>,
92}
93
94impl<F, B> Parser<F, B>
95where
96    F: std::io::Read,
97    B: ByteOrder,
98{
99    pub fn new(file: F) -> Result<Self> {
100        let state = ParseState::TextGlobal;
101        let mut file = ReadCheckSum::new(file);
102
103        let mut header_sign = [0u8; 8];
104        file.read_exact(&mut header_sign)?;
105        match &header_sign[..6] {
106            b"GARMIN" => {}
107            _ => {
108                return Err(Error::new(
109                    ErrorKind::InvalidData,
110                    "Invalid/Unknown Header Signature",
111                ))
112            }
113        }
114
115        let header_version = B::read_u16(&header_sign[6..]);
116        match header_version {
117            100 => {}
118            _ => {
119                return Err(Error::new(
120                    ErrorKind::InvalidData,
121                    "Invalid/Unknown Header Version",
122                ))
123            }
124        }
125
126        Ok(Self {
127            state,
128            file,
129            descriptor_type: Default::default(),
130            firmware: Default::default(),
131            endian: PhantomData,
132        })
133    }
134
135    /// Read the next available record
136    pub fn read_record(&mut self) -> Result<Record> {
137        //loop until error or return a record
138        loop {
139            if let ParseState::End = self.state {
140                //TODO check if there is more data after the End Record and return
141                //Err if there is.
142                return Err(Error::new(
143                    ErrorKind::InvalidData,
144                    "Unable to read after End Record",
145                ));
146            }
147
148            let state = self.state; //avoid multiple borrows
149            let record = self.parse_record()?;
150
151            //check if we are allowed to receive this record on the current state
152            match (state, record) {
153                //CheckPoint and Filler are allowed at any state
154                (_, RecordHeader::Checksum) => {
155                    //Check Point, verify the sum
156                    return Ok(Record::Checksum(self.parse_checksum()?));
157                }
158                (_, RecordHeader::Filler(len)) => {
159                    return Ok(Record::Filler(self.parse_filler(len)?))
160                }
161
162                //Didn't Received the MainHeader yet
163                (ParseState::TextGlobal, RecordHeader::Text(len)) => {
164                    return Ok(Record::Text(self.parse_text(len)?));
165                }
166                (ParseState::TextGlobal, RecordHeader::MainHeader(len)) => {
167                    //Main Header, change state so we refuse a second one
168                    self.state = ParseState::Main;
169                    return Ok(Record::MainHeader(
170                        self.parse_main_header(len)?,
171                    ));
172                }
173
174                //Received MainHeader
175                (ParseState::Main, RecordHeader::DescriptorType(len)) => {
176                    //first firmware block, no more global data
177                    self.state = ParseState::DescriptorType;
178                    //at this state descriptor_type is sure to be NONE
179                    self.descriptor_type = self.parse_descriptor_type(len)?;
180                }
181                (ParseState::Main, RecordHeader::Text(len)) => {
182                    // Text(after Main Header)
183                    return Ok(Record::Text(self.parse_text(len)?));
184                }
185
186                //Received the firmware descriptor type
187                (
188                    ParseState::DescriptorType,
189                    RecordHeader::DescriptorData(len),
190                ) => {
191                    self.state = ParseState::DescriptorData;
192                    //at this state is garantied that descriptor_type is Some()
193                    return Ok(Record::Descriptor(
194                        self.parse_descriptor_data(len)?,
195                    ));
196                }
197
198                //received the firmware descriptor type and data
199                (
200                    ParseState::DescriptorData,
201                    RecordHeader::DescriptorType(len),
202                ) => {
203                    //received a new firmware, Firmware Data Record missing
204                    self.state = ParseState::DescriptorType;
205                    //TODO: allow Firmware Data Record missing?
206                    //is garantied that self.firmware in Some at this state
207                    self.check_firmware_end()?;
208                    self.descriptor_type = self.parse_descriptor_type(len)?;
209                }
210                (
211                    ParseState::DescriptorData,
212                    RecordHeader::Unknown { id, len },
213                ) => {
214                    //first data chunk received
215                    self.state = ParseState::FirmwareData;
216                    //send this data chunk
217                    return Ok(Record::FirmwareData(
218                        self.parse_firmware_data(id, len)?,
219                    ));
220                }
221                (ParseState::DescriptorData, RecordHeader::Text(len)) => {
222                    //firmware text, no firmware data received yet
223                    return Ok(Record::Text(self.parse_text(len)?));
224                }
225                (ParseState::DescriptorData, RecordHeader::End) => {
226                    //firmware block only had descriptor
227                    //current block don't have data or text
228                    self.state = ParseState::End;
229                    //end this firmware
230                    self.check_firmware_end()?;
231                    return Ok(Record::End);
232                }
233
234                // text or firmware data
235                (ParseState::FirmwareData, RecordHeader::Text(len)) => {
236                    let text = self.parse_text(len)?;
237                    return Ok(Record::Text(text));
238                }
239                (
240                    ParseState::FirmwareData,
241                    RecordHeader::Unknown { id, len },
242                ) => {
243                    //second or more data chunk received
244                    //send this data chunk
245                    return Ok(Record::FirmwareData(
246                        self.parse_firmware_data(id, len)?,
247                    ));
248                }
249                (ParseState::FirmwareData, RecordHeader::End) => {
250                    //not more Firmware Data
251                    self.state = ParseState::End;
252                    //end this firmware
253                    self.check_firmware_end()?;
254                    return Ok(Record::End);
255                }
256                (
257                    ParseState::FirmwareData,
258                    RecordHeader::DescriptorType(len),
259                ) => {
260                    //received a new firmware after receiving a firmware
261                    //block, with at least text
262                    self.state = ParseState::DescriptorType;
263                    //end this firmware
264                    self.check_firmware_end()?;
265                    self.parse_descriptor_type(len)?;
266                }
267
268                (state, record) => {
269                    return Err(Error::new(
270                        ErrorKind::InvalidInput,
271                        format!(
272                            "State {:?} record received {:?}",
273                            state, record
274                        ),
275                    ));
276                }
277            }
278        }
279    }
280
281    fn parse_record(&mut self) -> Result<RecordHeader> {
282        let mut header = [0; 4];
283        self.file.read_exact(&mut header)?;
284        let (_, ret) = RecordHeader::from_raw::<B>(&mut header)?;
285        Ok(ret)
286    }
287
288    fn parse_checksum(&mut self) -> Result<ChecksumRecord> {
289        let mut data = [0];
290        self.file.read_exact(&mut data)?;
291        let checksum = self.file.sum();
292        return Ok(ChecksumRecord::new(&data, checksum)?);
293    }
294
295    fn parse_filler(&mut self, lenght: u16) -> Result<FillerRecord> {
296        let mut data = vec![0; lenght as usize];
297        self.file.read_exact(&mut data)?;
298        return Ok(FillerRecord::new(&data)?);
299    }
300
301    fn parse_main_header(&mut self, lenght: u16) -> Result<MainRecord> {
302        MainRecord::new::<ReadCheckSum<F>, B>(&mut self.file, lenght)
303    }
304
305    fn parse_text(&mut self, lenght: u16) -> Result<TextRecord> {
306        TextRecord::new(&mut self.file, lenght)
307    }
308
309    fn parse_descriptor_type(
310        &mut self,
311        lenght: u16,
312    ) -> Result<DescriptorTypeRecord> {
313        DescriptorTypeRecord::new::<ReadCheckSum<F>, B>(&mut self.file, lenght)
314    }
315
316    fn parse_descriptor_data(&mut self, lenght: u16) -> Result<DescriptorRecord>
317    where
318        F: std::io::Read,
319    {
320        let descriptor = DescriptorRecord::new::<ReadCheckSum<F>, B>(
321            &mut self.file,
322            lenght,
323            &self.descriptor_type,
324        )?;
325
326        //find extract necessary data
327        let mut firmware_id = None;
328        let mut firmware_lenght = None;
329        let mut xor_key = None;
330        //TODO make a more elegant data extraction
331        for desc in descriptor.iter() {
332            match desc.decode() {
333                Some(DescriptorDecoded::FirmwareId(x)) => {
334                    firmware_id = Some(x);
335                }
336                Some(DescriptorDecoded::FirmwareLen(x)) => {
337                    firmware_lenght = Some(x);
338                }
339                Some(DescriptorDecoded::XorKey(x)) => {
340                    xor_key = Some(x);
341                }
342                Some(DescriptorDecoded::Firmware2000P1Len(x))
343                | Some(DescriptorDecoded::Firmware2000P2Len(x))
344                | Some(DescriptorDecoded::Firmware2000P3Len(x)) => {
345                    //TODO is the size for each part?
346                    //each part is separated? in sequence?
347                    firmware_lenght = Some(x);
348                }
349                Some(_) => {}
350                None => {}
351            }
352        }
353        //TODO check if those values exist on Firmware Descriptor Type parsing
354        match firmware_id {
355            None => {
356                return Err(Error::new(
357                    ErrorKind::InvalidData,
358                    "Firmware Id not found",
359                ))
360            }
361            Some(x) => self.firmware.id = x,
362        }
363        match firmware_lenght {
364            None => {
365                return Err(Error::new(
366                    ErrorKind::InvalidData,
367                    "Firmware Lenght not found",
368                ))
369            }
370            Some(x) => self.firmware.lenght = x,
371        }
372        self.firmware.xor_key = xor_key.unwrap_or(0);
373        self.firmware.lenght_left = self.firmware.lenght;
374        Ok(descriptor)
375    }
376
377    fn parse_firmware_data(
378        &mut self,
379        record_id: u16,
380        record_len: u16,
381    ) -> Result<FirmwareRecord>
382    where
383        F: std::io::Read,
384    {
385        if record_id != self.firmware.id {
386            return Err(Error::new(
387                ErrorKind::InvalidInput,
388                format!(
389                    "Firmware id expected {:#x} found {:#x}",
390                    self.firmware.id, record_id,
391                ),
392            ));
393        }
394        //subtract the current consumed firmware chunk
395        if self.firmware.lenght_left < record_len as u32 {
396            return Err(Error::new(
397                ErrorKind::InvalidInput,
398                "Firmware Chunk is bigger than expected",
399            ));
400        }
401        self.firmware.lenght_left -= record_len as u32;
402        //send chunk to handle
403        let mut buf = vec![0u8; record_len as usize];
404        self.file.read_exact(&mut buf)?;
405        if self.firmware.xor_key != 0 {
406            buf.iter_mut().for_each(|x| *x = *x ^ self.firmware.xor_key);
407        }
408        match self.firmware.id {
409            // TrueType font file, XORed with 0x76
410            0x05A5 => buf.iter_mut().for_each(|x| *x = *x ^ 0x76),
411            _ => {}
412        }
413        Ok(FirmwareRecord::new(buf, record_id))
414    }
415
416    fn check_firmware_end(&mut self) -> Result<()> {
417        //check if the firmware was fully received
418        if self.firmware.lenght_left != 0 {
419            return Err(Error::new(
420                ErrorKind::InvalidInput,
421                format!(
422                    "Firmware Chunk too small, received {} from {} bytes",
423                    self.firmware.lenght - self.firmware.lenght_left,
424                    self.firmware.lenght
425                ),
426            ));
427        }
428        Ok(())
429    }
430}