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