1use {
7 crate::koly::UdifChecksum,
8 anyhow::Result,
9 byteorder::{ReadBytesExt, WriteBytesExt, BE},
10 std::io::{Read, Write},
11};
12
13#[derive(Clone, Debug, Eq, PartialEq)]
14pub struct BlkxTable {
15 pub version: u32,
17 pub sector_number: u64,
19 pub sector_count: u64,
21 pub data_offset: u64,
23 pub buffers_needed: u32,
26 pub block_descriptors: u32,
28 pub reserved: [u8; 24],
29 pub checksum: UdifChecksum,
30 pub chunks: Vec<BlkxChunk>,
32}
33
34impl Default for BlkxTable {
35 fn default() -> Self {
36 Self {
37 version: 1,
38 sector_number: 0,
39 sector_count: 0,
40 data_offset: 0,
41 buffers_needed: 2056,
43 block_descriptors: 0,
44 reserved: [0; 24],
45 checksum: UdifChecksum::default(),
46 chunks: vec![],
47 }
48 }
49}
50
51impl BlkxTable {
52 pub fn new(index: u32, sector: u64, checksum: u32) -> Self {
53 Self {
54 block_descriptors: index,
55 sector_number: sector,
56 checksum: UdifChecksum::new(checksum),
57 ..Default::default()
58 }
59 }
60
61 pub fn add_chunk(&mut self, mut chunk: BlkxChunk) {
62 chunk.sector_number = self.sector_count;
63 self.sector_count += chunk.sector_count;
64 self.chunks.push(chunk);
65 }
66
67 pub fn read_from<R: Read>(r: &mut R) -> Result<Self> {
68 let mut signature = [0; 4];
69 r.read_exact(&mut signature)?;
70 anyhow::ensure!(&signature == b"mish");
71 let version = r.read_u32::<BE>()?;
72 let sector_number = r.read_u64::<BE>()?;
73 let sector_count = r.read_u64::<BE>()?;
74 let data_offset = r.read_u64::<BE>()?;
75 let buffers_needed = r.read_u32::<BE>()?;
76 let block_descriptors = r.read_u32::<BE>()?;
77 let mut reserved = [0; 24];
78 r.read_exact(&mut reserved)?;
79 let checksum = UdifChecksum::read_from(r)?;
80 let num_chunks = r.read_u32::<BE>()?;
81 let mut chunks = Vec::with_capacity(num_chunks as _);
82 for _ in 0..num_chunks {
83 chunks.push(BlkxChunk::read_from(r)?);
84 }
85 Ok(Self {
86 version,
87 sector_number,
88 sector_count,
89 data_offset,
90 buffers_needed,
91 block_descriptors,
92 reserved,
93 checksum,
94 chunks,
95 })
96 }
97
98 pub fn write_to<W: Write>(&self, w: &mut W) -> Result<()> {
99 w.write_all(b"mish")?;
100 w.write_u32::<BE>(self.version)?;
101 w.write_u64::<BE>(self.sector_number)?;
102 w.write_u64::<BE>(self.sector_count)?;
103 w.write_u64::<BE>(self.data_offset)?;
104 w.write_u32::<BE>(self.buffers_needed)?;
105 w.write_u32::<BE>(self.block_descriptors)?;
106 w.write_all(&self.reserved)?;
107 self.checksum.write_to(w)?;
108 w.write_u32::<BE>(self.chunks.len() as u32)?;
109 for chunk in &self.chunks {
110 chunk.write_to(w)?;
111 }
112 Ok(())
113 }
114}
115
116#[derive(Clone, Copy, Debug, Eq, PartialEq)]
117pub struct BlkxChunk {
118 pub r#type: u32,
120 pub comment: u32,
121 pub sector_number: u64,
122 pub sector_count: u64,
123 pub compressed_offset: u64,
124 pub compressed_length: u64,
125}
126
127impl Default for BlkxChunk {
128 fn default() -> Self {
129 Self {
130 r#type: ChunkType::Raw as _,
131 comment: 0,
132 sector_number: 0,
133 sector_count: 0,
134 compressed_offset: 0,
135 compressed_length: 0,
136 }
137 }
138}
139
140impl BlkxChunk {
141 pub fn new(
142 ty: ChunkType,
143 sector_number: u64,
144 sector_count: u64,
145 compressed_offset: u64,
146 compressed_length: u64,
147 ) -> Self {
148 Self {
149 r#type: ty as _,
150 sector_number,
151 sector_count,
152 compressed_offset,
153 compressed_length,
154 ..Default::default()
155 }
156 }
157
158 pub fn term(sector_number: u64, compressed_offset: u64) -> Self {
159 Self::new(ChunkType::Term, sector_number, 0, compressed_offset, 0)
160 }
161
162 pub fn read_from<R: Read>(r: &mut R) -> Result<Self> {
163 let r#type = r.read_u32::<BE>()?;
164 let comment = r.read_u32::<BE>()?;
165 let sector_number = r.read_u64::<BE>()?;
166 let sector_count = r.read_u64::<BE>()?;
167 let compressed_offset = r.read_u64::<BE>()?;
168 let compressed_length = r.read_u64::<BE>()?;
169 Ok(Self {
170 r#type,
171 comment,
172 sector_number,
173 sector_count,
174 compressed_offset,
175 compressed_length,
176 })
177 }
178
179 pub fn write_to<W: Write>(&self, w: &mut W) -> Result<()> {
180 w.write_u32::<BE>(self.r#type)?;
181 w.write_u32::<BE>(self.comment)?;
182 w.write_u64::<BE>(self.sector_number)?;
183 w.write_u64::<BE>(self.sector_count)?;
184 w.write_u64::<BE>(self.compressed_offset)?;
185 w.write_u64::<BE>(self.compressed_length)?;
186 Ok(())
187 }
188
189 pub fn ty(self) -> Option<ChunkType> {
190 ChunkType::from_u32(self.r#type)
191 }
192}
193
194#[repr(u32)]
196#[derive(Clone, Copy, Debug, Eq, PartialEq)]
197pub enum ChunkType {
198 Zero = 0x0000_0000,
199 Raw = 0x0000_0001,
200 Ignore = 0x0000_0002,
201 Comment = 0x7fff_fffe,
202 Adc = 0x8000_0004,
203 Zlib = 0x8000_0005,
204 Bzlib = 0x8000_0006,
205 Lzfse = 0x8000_0007,
206 Term = 0xffff_ffff,
207}
208
209impl ChunkType {
210 pub fn from_u32(ty: u32) -> Option<Self> {
211 Some(match ty {
212 x if x == ChunkType::Zero as u32 => ChunkType::Zero,
213 x if x == ChunkType::Raw as u32 => ChunkType::Raw,
214 x if x == ChunkType::Ignore as u32 => ChunkType::Ignore,
215 x if x == ChunkType::Comment as u32 => ChunkType::Comment,
216 x if x == ChunkType::Adc as u32 => ChunkType::Adc,
217 x if x == ChunkType::Zlib as u32 => ChunkType::Zlib,
218 x if x == ChunkType::Bzlib as u32 => ChunkType::Bzlib,
219 x if x == ChunkType::Lzfse as u32 => ChunkType::Lzfse,
220 x if x == ChunkType::Term as u32 => ChunkType::Term,
221 _ => return None,
222 })
223 }
224}