1use crate::error::{Result, WmoError};
2use crate::types::ChunkId;
3use std::io::{Read, Seek, SeekFrom, Write};
4
5fn read_exact_or_eof<R: Read>(reader: &mut R, buf: &mut [u8]) -> Result<()> {
7 match reader.read_exact(buf) {
8 Ok(()) => Ok(()),
9 Err(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => Err(WmoError::UnexpectedEof),
10 Err(e) => Err(WmoError::Io(e)),
11 }
12}
13
14#[derive(Debug, Clone, Copy)]
16pub struct ChunkHeader {
17 pub id: ChunkId,
19 pub size: u32,
21}
22
23impl ChunkHeader {
24 pub const SIZE: usize = 8;
26
27 pub fn read<R: Read>(reader: &mut R) -> Result<Self> {
29 let mut id_bytes = [0u8; 4];
30 read_exact_or_eof(reader, &mut id_bytes)?;
31
32 id_bytes.reverse();
35
36 let mut size_bytes = [0u8; 4];
37 read_exact_or_eof(reader, &mut size_bytes)?;
38 let size = u32::from_le_bytes(size_bytes);
39
40 Ok(Self {
41 id: ChunkId(id_bytes),
42 size,
43 })
44 }
45
46 pub fn write<W: Write>(&self, writer: &mut W) -> Result<()> {
48 let mut id_bytes = self.id.0;
51 id_bytes.reverse();
52 writer.write_all(&id_bytes)?;
53 writer.write_all(&self.size.to_le_bytes())?;
54 Ok(())
55 }
56}
57
58#[derive(Debug)]
60pub struct Chunk {
61 pub header: ChunkHeader,
63 pub data_position: u64,
65}
66
67impl Chunk {
68 pub fn read<R: Read + Seek>(reader: &mut R) -> Result<Self> {
70 let header = ChunkHeader::read(reader)?;
71 let data_position = reader.stream_position()?;
72
73 reader.seek(SeekFrom::Current(header.size as i64))?;
75
76 Ok(Self {
77 header,
78 data_position,
79 })
80 }
81
82 pub fn read_expected<R: Read + Seek>(reader: &mut R, expected_id: ChunkId) -> Result<Self> {
84 let chunk = Self::read(reader)?;
85
86 if chunk.header.id != expected_id {
87 return Err(WmoError::InvalidMagic {
88 expected: *expected_id.as_bytes(),
89 found: chunk.header.id.0,
90 });
91 }
92
93 Ok(chunk)
94 }
95
96 pub fn seek_to_data<S: Seek>(&self, seeker: &mut S) -> Result<()> {
98 seeker.seek(SeekFrom::Start(self.data_position))?;
99 Ok(())
100 }
101
102 pub fn read_data<R: Read + Seek>(&self, reader: &mut R) -> Result<Vec<u8>> {
104 self.seek_to_data(reader)?;
105
106 let mut data = vec![0; self.header.size as usize];
107 reader.read_exact(&mut data)?;
108
109 Ok(data)
110 }
111}