1use crate::error::{format_err, Error, Result};
14
15pub const BLOCK_START: u32 = 0xAAAA_AAAA;
17pub const BLOCK_END: u32 = 0xBBBB_BBBB;
19pub const MAGIC: u32 = 0x5412_A91F;
21
22pub struct Reader<'a> {
24 data: &'a [u8],
25 pos: usize,
26 end: usize,
27 reference_ids: Option<std::sync::Arc<std::collections::BTreeMap<u32, String>>>,
29 pub wide_seen: bool,
31}
32
33impl<'a> Reader<'a> {
34 pub fn new(data: &'a [u8]) -> Self {
36 Reader {
37 data,
38 pos: 0,
39 end: data.len(),
40 reference_ids: None,
41 wide_seen: false,
42 }
43 }
44
45 pub fn set_reference_ids(
47 &mut self,
48 ids: std::sync::Arc<std::collections::BTreeMap<u32, String>>,
49 ) {
50 self.reference_ids = Some(ids);
51 }
52
53 pub fn pos(&self) -> usize {
55 self.pos
56 }
57
58 pub fn remaining(&self) -> usize {
60 self.end - self.pos
61 }
62
63 pub fn slice(&self, start: usize, end: usize) -> Result<&'a [u8]> {
65 self.data.get(start..end).ok_or(Error::Truncated {
66 at: start,
67 wanted: end.saturating_sub(start),
68 })
69 }
70
71 pub fn bytes(&mut self, n: usize) -> Result<&'a [u8]> {
73 if n > self.end - self.pos {
74 return Err(Error::Truncated {
75 at: self.pos,
76 wanted: n,
77 });
78 }
79 let s = &self.data[self.pos..self.pos + n];
80 self.pos += n;
81 Ok(s)
82 }
83
84 fn arr<const N: usize>(&mut self) -> Result<[u8; N]> {
85 Ok(self.bytes(N)?.try_into().unwrap())
86 }
87
88 pub fn u8(&mut self) -> Result<u8> {
90 Ok(self.arr::<1>()?[0])
91 }
92 pub fn bool(&mut self) -> Result<bool> {
94 Ok(self.u8()? != 0)
95 }
96 pub fn u32(&mut self) -> Result<u32> {
98 Ok(u32::from_le_bytes(self.arr()?))
99 }
100 pub fn i32(&mut self) -> Result<i32> {
102 Ok(i32::from_le_bytes(self.arr()?))
103 }
104 pub fn u64(&mut self) -> Result<u64> {
106 Ok(u64::from_le_bytes(self.arr()?))
107 }
108 pub fn i64(&mut self) -> Result<i64> {
110 Ok(i64::from_le_bytes(self.arr()?))
111 }
112 pub fn i16(&mut self) -> Result<i16> {
114 Ok(i16::from_le_bytes(self.bytes(2)?.try_into().unwrap()))
115 }
116
117 pub fn u16(&mut self) -> Result<u16> {
119 Ok(u16::from_le_bytes(self.bytes(2)?.try_into().unwrap()))
120 }
121
122 pub fn limit(&mut self, end: usize) -> Result<usize> {
125 if end > self.end || end < self.pos {
126 return format_err(format!(
127 "limit {end:#x} outside {:#x}..{:#x}",
128 self.pos, self.end
129 ));
130 }
131 Ok(std::mem::replace(&mut self.end, end))
132 }
133
134 pub fn unlimit(&mut self, end: usize) {
136 self.end = end;
137 }
138
139 pub fn set_pos(&mut self, pos: usize) {
141 self.pos = pos;
142 }
143
144 pub fn u32_at(&self, at: usize) -> Option<u32> {
146 self.data
147 .get(at..at + 4)
148 .map(|b| u32::from_le_bytes(b.try_into().unwrap()))
149 }
150
151 pub fn peek_u32(&self) -> Option<u32> {
153 self.data
154 .get(self.pos..self.pos + 4)
155 .filter(|_| self.pos + 4 <= self.end)
156 .map(|b| u32::from_le_bytes(b.try_into().unwrap()))
157 }
158
159 pub fn wstring(&mut self) -> Result<String> {
164 let n = self.u32()? as usize;
165 let b = self.bytes(n * 2)?;
166 let units: Vec<u16> = b
167 .chunks_exact(2)
168 .map(|c| u16::from_le_bytes([c[0], c[1]]))
169 .collect();
170 let end = units.iter().position(|&c| c == 0).unwrap_or(units.len());
171 Ok(String::from_utf16_lossy(&units[..end]))
172 }
173
174 pub fn f32(&mut self) -> Result<f32> {
176 Ok(f32::from_le_bytes(self.arr()?))
177 }
178 pub fn f32s<const N: usize>(&mut self) -> Result<[f32; N]> {
180 let mut out = [0.0; N];
181 for v in &mut out {
182 *v = self.f32()?;
183 }
184 Ok(out)
185 }
186
187 pub fn count(&mut self) -> Result<usize> {
189 let n = self.i32()?;
190 usize::try_from(n).map_err(|_| Error::Format(format!("negative count {n}")))
191 }
192
193 pub fn string(&mut self) -> Result<String> {
196 let n = self.u32()?;
197 if n & 0x8000_0000 != 0 {
198 let b = self.bytes((n & 0x7FFF_FFFF) as usize)?;
199 let end = b.iter().position(|&c| c == 0).unwrap_or(b.len());
200 Ok(match std::str::from_utf8(&b[..end]) {
202 Ok(s) => s.to_owned(),
203 Err(_) => b[..end].iter().map(|&c| c as char).collect(),
204 })
205 } else {
206 self.wide_seen = true;
207 let b = self.bytes(n as usize * 2)?;
208 let units: Vec<u16> = b
209 .chunks_exact(2)
210 .map(|c| u16::from_le_bytes([c[0], c[1]]))
211 .collect();
212 let end = units.iter().position(|&c| c == 0).unwrap_or(units.len());
213 Ok(String::from_utf16_lossy(&units[..end]))
214 }
215 }
216
217 pub fn external_ref(&mut self) -> Result<Option<String>> {
219 if let Some(ids) = self.reference_ids.clone() {
220 let at = self.pos;
221 let id = self.u32()?;
222 if id == u32::MAX {
223 return Ok(None);
224 }
225 return match ids.get(&id) {
226 Some(path) => Ok(Some(path.clone())),
227 None => format_err(format!("unknown reference id {id} at {at:#x}")),
228 };
229 }
230 if self.bool()? {
231 Ok(Some(self.string()?))
232 } else {
233 Ok(None)
234 }
235 }
236
237 pub fn block<T>(&mut self, f: impl FnOnce(&mut Self, u32) -> Result<T>) -> Result<T> {
239 let start = self.pos;
240 if self.u32()? != BLOCK_START {
241 return format_err(format!("expected block marker at {start:#x}"));
242 }
243 let size = self.u32()? as usize;
244 let version = self.u32()?;
245 let end = self.pos + size;
246 if size < 4 || end > self.end {
247 return format_err(format!("block at {start:#x} (size {size}) overruns parent"));
248 }
249 if u32::from_le_bytes(self.data[end - 4..end].try_into().unwrap()) != BLOCK_END {
250 return format_err(format!("block at {start:#x} lacks terminator"));
251 }
252 let outer_end = std::mem::replace(&mut self.end, end - 4);
253 let result = f(self, version);
254 let consumed = self.pos;
255 self.end = outer_end;
256 let value = result?;
257 if consumed != end - 4 {
258 return format_err(format!(
259 "block at {start:#x} has {} unread bytes",
260 end - 4 - consumed
261 ));
262 }
263 self.pos = end;
264 Ok(value)
265 }
266
267 pub fn skip_rest(&mut self) {
269 self.pos = self.end;
270 }
271
272 pub fn skip_block(&mut self) -> Result<()> {
274 self.block(|r, _| {
275 r.pos = r.end;
276 Ok(())
277 })
278 }
279}
280
281#[derive(Debug, Clone)]
283pub struct Header {
284 pub type_id: u32,
286 pub file_version: u32,
288 pub dependencies: Vec<String>,
290}
291
292pub fn parse<T>(
294 data: &[u8],
295 f: impl FnOnce(&mut Reader, &Header) -> Result<T>,
296) -> Result<(Header, T)> {
297 let mut r = Reader::new(data);
298 let out = r.block(|r, _| {
299 if r.u32()? != MAGIC {
300 return format_err("missing resource magic");
301 }
302 let type_id = r.u32()?;
303 let file_version = r.u32()?;
304 let n = r.count()?;
305 let mut dependencies = Vec::with_capacity(n);
306 for _ in 0..n {
307 dependencies.push(r.string()?);
308 r.u64()?; }
310 let header = Header {
311 type_id,
312 file_version,
313 dependencies,
314 };
315 let value = f(r, &header)?;
316 Ok((header, value))
317 })?;
318 if r.pos != data.len() {
319 return format_err(format!(
320 "{} trailing bytes after resource",
321 data.len() - r.pos
322 ));
323 }
324 Ok(out)
325}
326
327pub fn header(data: &[u8]) -> Result<Header> {
329 parse(data, |r, _| {
330 r.pos = r.end;
331 Ok(())
332 })
333 .map(|(h, ())| h)
334}
335
336#[derive(Default)]
339pub struct Writer {
340 pub data: Vec<u8>,
342 reference_ids: Option<std::collections::BTreeMap<String, u32>>,
344 pub wide_strings: bool,
346}
347
348impl Writer {
349 pub fn new() -> Self {
351 Self::default()
352 }
353
354 pub fn set_reference_ids(&mut self, ids: &std::collections::BTreeMap<u32, String>) {
356 self.reference_ids = Some(ids.iter().map(|(&id, p)| (p.clone(), id)).collect());
357 }
358
359 pub fn bytes(&mut self, b: &[u8]) {
361 self.data.extend_from_slice(b);
362 }
363 pub fn u8(&mut self, v: u8) {
365 self.data.push(v);
366 }
367 pub fn bool(&mut self, v: bool) {
369 self.data.push(v as u8);
370 }
371 pub fn i16(&mut self, v: i16) {
373 self.bytes(&v.to_le_bytes());
374 }
375 pub fn u16(&mut self, v: u16) {
377 self.bytes(&v.to_le_bytes());
378 }
379 pub fn u32(&mut self, v: u32) {
381 self.bytes(&v.to_le_bytes());
382 }
383 pub fn i32(&mut self, v: i32) {
385 self.bytes(&v.to_le_bytes());
386 }
387 pub fn i64(&mut self, v: i64) {
389 self.bytes(&v.to_le_bytes());
390 }
391 pub fn f32(&mut self, v: f32) {
393 self.bytes(&v.to_le_bytes());
394 }
395
396 pub fn count(&mut self, n: usize) {
398 self.i32(n as i32);
399 }
400
401 pub fn string(&mut self, s: &str) {
404 if self.wide_strings {
405 self.wstring(s);
406 return;
407 }
408 self.u32((s.len() as u32 + 1) | 0x8000_0000);
409 self.bytes(s.as_bytes());
410 self.u8(0);
411 }
412
413 pub fn wstring(&mut self, s: &str) {
415 let units: Vec<u16> = s.encode_utf16().chain([0]).collect();
416 self.u32(units.len() as u32);
417 for u in units {
418 self.u16(u);
419 }
420 }
421
422 pub fn external_ref(&mut self, path: Option<&str>) -> Result<()> {
425 if let Some(ids) = &self.reference_ids {
426 let id = match path {
427 None => u32::MAX,
428 Some(p) => *ids
429 .get(p)
430 .ok_or_else(|| Error::Format(format!("no reference id for {p}")))?,
431 };
432 self.u32(id);
433 return Ok(());
434 }
435 self.bool(path.is_some());
436 if let Some(p) = path {
437 self.string(p);
438 }
439 Ok(())
440 }
441
442 pub fn begin_block(&mut self, version: u32) -> usize {
444 self.u32(BLOCK_START);
445 let size_at = self.data.len();
446 self.u32(0);
447 self.u32(version);
448 size_at
449 }
450
451 pub fn end_block(&mut self, size_at: usize) {
454 self.u32(BLOCK_END);
455 let size = (self.data.len() - size_at - 8) as u32;
456 self.data[size_at..size_at + 4].copy_from_slice(&size.to_le_bytes());
457 }
458
459 pub fn block<T>(&mut self, version: u32, f: impl FnOnce(&mut Self) -> Result<T>) -> Result<T> {
461 let at = self.begin_block(version);
462 let out = f(self)?;
463 self.end_block(at);
464 Ok(out)
465 }
466}