gcd_rs/
lib.rs

1pub mod composer;
2pub mod parser;
3
4use byteorder::ByteOrder;
5use serde::{Deserialize, Serialize};
6use std::fmt::{Display, Formatter};
7use std::io::{Error, ErrorKind, Result};
8
9mod version;
10pub use version::Version;
11
12mod part_number;
13pub use part_number::PartNumber;
14
15pub mod record;
16use record::main::MainRecord;
17
18use record::checksum;
19use record::checksum::ChecksumRecord;
20use record::descriptor;
21use record::descriptor::DescriptorRecord;
22use record::filler;
23use record::filler::FillerRecord;
24use record::firmware::FirmwareRecord;
25use record::main;
26use record::text;
27
28use self::record::text::TextRecord;
29
30const RECORD_HEADER_LEN: usize = 4;
31
32/// Alias for the only know Endian used by GCD files.
33///
34/// The only know GCD files are encoded using LittleEndian. But there is nothing
35/// requiring the file format to never use BigEndian
36///
37/// Functions in this lib accept the user to specify the Endian as a future
38/// proof.
39pub type GcdDefaultEndian = byteorder::LE;
40
41/// Known Record Headers, based on the current knowledge.
42#[derive(Debug, PartialEq, Hash, Eq, Copy, Clone, Serialize, Deserialize)]
43pub enum RecordHeader {
44    /// A one byte record that, if read, result in a 0 checksum.
45    Checksum, //always size 1
46    /// A 0-0xFFFF record with nothing but zeros, usually lining the next
47    /// record address.
48    Filler(u16),
49    /// Only two variations are known, a HWID and a PartNumber. Possibly
50    /// describing the file format itself.
51    MainHeader(u16),
52    /// Arbitrary data, usually containing valid ASCII text, mostly one line.
53    Text(u16),
54    /// Data information about the firmware, contains only the type.
55    ///
56    /// This will be later combine with DescriptorData
57    DescriptorType(u16),
58    /// Data information about the firmware, contain only the data.
59    ///
60    /// Need to be combined with DescriptorType to be interpreted.
61    DescriptorData(u16),
62    /// Mark the end of the file. Can only be the last header.
63    End, //always size 0
64    /// Header with Unknown ID, can be a Firmware block, if the ID is described
65    /// on the Descriptor header, or Unknown/Undefined Record.
66    Unknown { id: u16, len: u16 },
67}
68
69impl RecordHeader {
70    /// Return the id from the Header
71    pub const fn id(&self) -> u16 {
72        match self {
73            RecordHeader::Unknown { id, .. } => *id,
74            RecordHeader::Checksum => checksum::ID,
75            RecordHeader::Filler(_) => filler::ID,
76            RecordHeader::MainHeader(_) => main::ID,
77            RecordHeader::Text(_) => text::ID,
78            RecordHeader::DescriptorType(_) => descriptor::descriptor_type::ID,
79            RecordHeader::DescriptorData(_) => descriptor::descriptor_data::ID,
80            RecordHeader::End => 0xffff,
81        }
82    }
83    /// Return the len from the Header, obs: not the len of the Header itself
84    pub const fn len(&self) -> u16 {
85        match self {
86            RecordHeader::Unknown { len, .. } => *len,
87            RecordHeader::Checksum => 0x0001,
88            RecordHeader::Filler(len) => *len,
89            RecordHeader::MainHeader(len) => *len,
90            RecordHeader::Text(len) => *len,
91            RecordHeader::DescriptorType(len) => *len,
92            RecordHeader::DescriptorData(len) => *len,
93            RecordHeader::End => 0,
94        }
95    }
96    /// Create a header using the id and len values.
97    pub const fn from_value(id: u16, len: u16) -> Self {
98        match id {
99            checksum::ID if len == 1 => RecordHeader::Checksum,
100            filler::ID => RecordHeader::Filler(len),
101            main::ID => RecordHeader::MainHeader(len),
102            text::ID => RecordHeader::Text(len),
103            descriptor::descriptor_type::ID => {
104                RecordHeader::DescriptorType(len)
105            }
106            descriptor::descriptor_data::ID => {
107                RecordHeader::DescriptorData(len)
108            }
109            0xFFFF if len == 0 => RecordHeader::End,
110            _ => RecordHeader::Unknown { id, len },
111        }
112    }
113    /// Create the Header using raw bytes
114    pub fn from_raw<B: ByteOrder>(data: &[u8]) -> Result<(&[u8], Self)> {
115        if data.len() < 4 {
116            return Err(Error::new(
117                ErrorKind::InvalidData,
118                "Record hreader buffer too small",
119            ));
120        }
121        let id = B::read_u16(&data[..2]);
122        let len = B::read_u16(&data[2..]);
123        Ok((&data[4..], RecordHeader::from_value(id, len)))
124    }
125    /// Write the Header to the raw byte buffer.
126    pub fn to_raw<'a, B: ByteOrder>(
127        &self,
128        data: &'a mut [u8],
129    ) -> Result<&'a mut [u8]> {
130        if data.len() < 4 {
131            return Err(Error::new(
132                ErrorKind::InvalidData,
133                "Record hreader buffer too small",
134            ));
135        }
136        B::write_u16(data, self.id());
137        B::write_u16(&mut data[2..], self.len());
138        Ok(&mut data[4..])
139    }
140}
141
142/// All known Records.
143#[derive(Debug, PartialEq, Hash, Eq, Clone, Serialize, Deserialize)]
144pub enum Record {
145    Checksum(ChecksumRecord),
146    Filler(FillerRecord),
147    MainHeader(MainRecord),
148    Text(TextRecord),
149    Descriptor(DescriptorRecord),
150    FirmwareData(FirmwareRecord),
151    End,
152}
153
154impl Display for Record {
155    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
156        match self {
157            Record::Checksum(x) => write!(f, "{}", x),
158            Record::Filler(x) => write!(f, "{}", x),
159            Record::MainHeader(x) => write!(f, "{}", x),
160            Record::Text(x) => write!(f, "{}", x),
161            Record::Descriptor(x) => write!(f, "{}", x),
162            Record::FirmwareData(x) => write!(f, "{}", x),
163            Record::End => write!(f, "Record:End"),
164        }
165    }
166}