bb_bmap_parser/
bmap.rs

1use crate::xml::HashType;
2
3use thiserror::Error;
4
5#[derive(Copy, Clone, Debug, PartialEq, Eq)]
6#[non_exhaustive]
7pub enum HashValue {
8    Sha256([u8; 32]),
9}
10
11impl HashValue {
12    pub fn to_type(&self) -> HashType {
13        match self {
14            HashValue::Sha256(_) => HashType::Sha256,
15        }
16    }
17
18    pub fn as_slice(&self) -> &[u8] {
19        match self {
20            HashValue::Sha256(v) => v,
21        }
22    }
23}
24
25#[derive(Clone, Debug, PartialEq, Eq)]
26pub struct BlockRange {
27    offset: u64,
28    length: u64,
29    checksum: HashValue,
30}
31
32impl BlockRange {
33    pub fn checksum(&self) -> HashValue {
34        self.checksum
35    }
36
37    pub fn offset(&self) -> u64 {
38        self.offset
39    }
40
41    pub fn length(&self) -> u64 {
42        self.length
43    }
44}
45
46#[derive(Clone, Debug)]
47pub struct Bmap {
48    image_size: u64,
49    block_size: u64,
50    blocks: u64,
51    mapped_blocks: u64,
52    checksum_type: HashType,
53    blockmap: Vec<BlockRange>,
54}
55
56impl Bmap {
57    pub fn builder() -> BmapBuilder {
58        BmapBuilder::default()
59    }
60
61    /// Build from a .bmap xml file
62    pub fn from_xml(xml: &str) -> Result<Self, crate::xml::XmlError> {
63        crate::xml::from_xml(xml)
64    }
65
66    /// Image size in bytes
67    pub fn image_size(&self) -> u64 {
68        self.image_size
69    }
70
71    /// block size in bytes
72    pub const fn block_size(&self) -> u64 {
73        self.block_size
74    }
75
76    /// number of blocks in the image
77    pub fn blocks(&self) -> u64 {
78        self.blocks
79    }
80
81    /// number of mapped blocks in the image
82    pub fn mapped_blocks(&self) -> u64 {
83        self.mapped_blocks
84    }
85
86    /// checksum type used
87    pub fn checksum_type(&self) -> HashType {
88        self.checksum_type
89    }
90
91    /// Iterator over the block map
92    pub fn block_map(&self) -> impl ExactSizeIterator<Item = &BlockRange> {
93        self.blockmap.iter()
94    }
95
96    /// Total mapped size in bytes
97    pub fn total_mapped_size(&self) -> u64 {
98        self.block_size * self.mapped_blocks
99    }
100}
101
102#[derive(Clone, Debug, Error)]
103pub enum BmapBuilderError {
104    #[error("Image size missing")]
105    MissingImageSize,
106    #[error("Block size missing")]
107    MissingBlockSize,
108    #[error("Blocks missing")]
109    MissingBlocks,
110    #[error("Mapped blocks missing")]
111    MissingMappedBlocks,
112    #[error("Checksum type missing")]
113    MissingChecksumType,
114    #[error("No block ranges")]
115    NoBlockRanges,
116}
117
118#[derive(Clone, Debug, Default)]
119pub struct BmapBuilder {
120    image_size: Option<u64>,
121    block_size: Option<u64>,
122    blocks: Option<u64>,
123    checksum_type: Option<HashType>,
124    mapped_blocks: Option<u64>,
125    blockmap: Vec<BlockRange>,
126}
127
128impl BmapBuilder {
129    pub fn image_size(&mut self, size: u64) -> &mut Self {
130        self.image_size = Some(size);
131        self
132    }
133
134    pub fn block_size(&mut self, block_size: u64) -> &mut Self {
135        self.block_size = Some(block_size);
136        self
137    }
138
139    pub fn blocks(&mut self, blocks: u64) -> &mut Self {
140        self.blocks = Some(blocks);
141        self
142    }
143
144    pub fn mapped_blocks(&mut self, blocks: u64) -> &mut Self {
145        self.mapped_blocks = Some(blocks);
146        self
147    }
148
149    pub fn checksum_type(&mut self, checksum_type: HashType) -> &mut Self {
150        self.checksum_type = Some(checksum_type);
151        self
152    }
153
154    pub fn add_block_range(&mut self, start: u64, end: u64, checksum: HashValue) -> &mut Self {
155        let bs = self.block_size.expect("Blocksize needs to be set first");
156        let total = self.image_size.expect("Image size needs to be set first");
157        let offset = start * bs;
158        let length = (total - offset).min((end - start + 1) * bs);
159        self.add_byte_range(offset, length, checksum)
160    }
161
162    pub fn add_byte_range(&mut self, offset: u64, length: u64, checksum: HashValue) -> &mut Self {
163        let range = BlockRange {
164            offset,
165            length,
166            checksum,
167        };
168        self.blockmap.push(range);
169        self
170    }
171
172    pub fn build(self) -> Result<Bmap, BmapBuilderError> {
173        let image_size = self.image_size.ok_or(BmapBuilderError::MissingImageSize)?;
174        let block_size = self.block_size.ok_or(BmapBuilderError::MissingBlockSize)?;
175        let blocks = self.blocks.ok_or(BmapBuilderError::MissingBlocks)?;
176        let mapped_blocks = self
177            .mapped_blocks
178            .ok_or(BmapBuilderError::MissingMappedBlocks)?;
179        let checksum_type = self
180            .checksum_type
181            .ok_or(BmapBuilderError::MissingChecksumType)?;
182        let blockmap = self.blockmap;
183
184        Ok(Bmap {
185            image_size,
186            block_size,
187            blocks,
188            mapped_blocks,
189            checksum_type,
190            blockmap,
191        })
192    }
193}
194
195#[cfg(test)]
196mod test {
197    use super::*;
198
199    #[test]
200    fn hashes() {
201        let h = HashValue::Sha256([0; 32]);
202        assert_eq!(HashType::Sha256, h.to_type());
203    }
204}