cpclib_common/
riff.rs

1use std::fmt::Display;
2use std::io::Write;
3use std::ops::Deref;
4
5#[derive(Clone, Debug, PartialEq, PartialOrd, Ord, Eq)]
6pub struct RiffCode(pub(crate) [u8; 4]);
7
8impl Deref for RiffCode {
9    type Target = [u8; 4];
10
11    fn deref(&self) -> &Self::Target {
12        &self.0
13    }
14}
15
16impl From<[u8; 4]> for RiffCode {
17    fn from(value: [u8; 4]) -> Self {
18        RiffCode::new(value)
19    }
20}
21
22impl From<&[u8]> for RiffCode {
23    fn from(value: &[u8]) -> Self {
24        assert_eq!(value.len(), 4);
25        RiffCode::new([value[0], value[1], value[2], value[3]])
26    }
27}
28
29impl From<&str> for RiffCode {
30    fn from(value: &str) -> Self {
31        let code = &value.as_bytes()[..4];
32        RiffCode::new([code[0], code[1], code[2], code[3]])
33    }
34}
35
36impl Display for RiffCode {
37    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
38        write!(
39            f,
40            "{}{}{}{}",
41            self.0[0] as char, self.0[1] as char, self.0[2] as char, self.0[3] as char
42        )
43    }
44}
45impl RiffCode {
46    pub const fn new(value: [u8; 4]) -> Self {
47        Self(value)
48    }
49
50    pub fn as_str(&self) -> &str {
51        unsafe { std::str::from_utf8_unchecked(&self.0) }
52    }
53}
54
55#[derive(Clone, Debug, PartialEq)]
56pub struct RiffLen(pub(crate) [u8; 4]);
57
58impl Deref for RiffLen {
59    type Target = [u8; 4];
60
61    fn deref(&self) -> &Self::Target {
62        &self.0
63    }
64}
65
66impl From<&[u8]> for RiffLen {
67    fn from(value: &[u8]) -> Self {
68        assert_eq!(4, value.len());
69        Self([value[0], value[1], value[2], value[3]])
70    }
71}
72
73impl From<u32> for RiffLen {
74    fn from(mut size: u32) -> Self {
75        let mut array = [0, 0, 0, 0];
76
77        for item in &mut array {
78            *item = (size % 256) as u8;
79            size /= 256;
80        }
81
82        Self(array)
83    }
84}
85
86impl From<usize> for RiffLen {
87    fn from(value: usize) -> Self {
88        Self::from(value as u32)
89    }
90}
91
92impl From<&RiffLen> for u32 {
93    fn from(val: &RiffLen) -> Self {
94        let mut size = 0;
95        for byte in val.0.iter().rev() {
96            size = size * 256 + *byte as u32;
97        }
98        size
99    }
100}
101
102impl From<&RiffLen> for usize {
103    fn from(val: &RiffLen) -> Self {
104        let size: u32 = val.into();
105        size as _
106    }
107}
108
109impl RiffLen {
110    pub fn increment(&self) -> Self {
111        let size: u32 = self.into();
112        Self::from(size + 1)
113    }
114
115    pub fn add(&self, value: usize) -> Self {
116        let size: u32 = self.into();
117        Self::from(size + value as u32)
118    }
119
120    pub fn decrement(&self) -> Self {
121        let size: u32 = self.into();
122        Self::from(size - 1)
123    }
124
125    pub fn value(&self) -> u32 {
126        self.into()
127    }
128}
129
130pub struct RiffContainer {
131    /// RIFF or LIST only
132    ckid: RiffCode
133}
134
135#[derive(Clone, Debug)]
136/// Raw chunk data.
137#[derive(PartialEq)]
138pub struct RiffChunk {
139    /// Identifier of the chunk
140    ckid: RiffCode,
141    /// Length of the chunk (always data.len())
142    cksz: RiffLen,
143    /// Content of the chunk (size included)
144    data: Vec<u8>
145}
146
147#[allow(missing_docs)]
148impl RiffChunk {
149    pub fn write_all<B: Write>(&self, buffer: &mut B) -> Result<(), std::io::Error> {
150        buffer.write_all(self.code().deref())?;
151        buffer.write_all(self.len().deref())?;
152        buffer.write_all(self.data())?;
153
154        Ok(())
155    }
156
157    pub fn from_buffer(file_content: &mut Vec<u8>) -> Self {
158        // get the code and length
159        let ckid: RiffCode = file_content.drain(0..4).as_slice().into();
160        let cksz: RiffLen = file_content.drain(0..4).as_slice().into();
161
162        // read the appropriate number of bytes
163        let data = if cksz.value() > 0 {
164            file_content.drain(0..cksz.value() as _).as_slice().to_vec()
165        }
166        else {
167            Vec::with_capacity(0)
168        };
169
170        assert_eq!(data.len(), cksz.value() as usize);
171
172        Self { ckid, cksz, data }
173    }
174
175    pub fn new<C: Into<RiffCode>>(code: C, data: Vec<u8>) -> Self {
176        Self {
177            ckid: code.into(),
178            cksz: data.len().into(),
179            data
180        }
181    }
182
183    pub fn code(&self) -> &RiffCode {
184        &(self.ckid)
185    }
186
187    pub fn len(&self) -> &RiffLen {
188        &self.cksz
189    }
190
191    pub fn data(&self) -> &[u8] {
192        &self.data
193    }
194
195    // todo increase the size
196    pub fn add_bytes(&mut self, data: &[u8]) {
197        self.data.extend_from_slice(data);
198        self.update_cksz();
199    }
200
201    pub fn set_byte(&mut self, address: u16, byte: u8) {
202        self.data[address as usize] = byte;
203    }
204
205    fn update_cksz(&mut self) {
206        self.cksz = self.data.len().into();
207    }
208}