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 ckid: RiffCode
133}
134
135#[derive(Clone, Debug)]
136#[derive(PartialEq)]
138pub struct RiffChunk {
139 ckid: RiffCode,
141 cksz: RiffLen,
143 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 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 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 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}