1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
use std::fs::File as StdFile;
use std::slice::Iter;
use constants::{BLOCK_SIZE, CHUNK_HEADER_SIZE};
use convert::TryInto;
use headers::ChunkType;
pub type ChunkIter<'a> = Iter<'a, Chunk>;
#[derive(Debug, Default)]
pub struct File {
chunks: Vec<Chunk>,
}
impl File {
pub fn new() -> Self {
Self { chunks: Vec::new() }
}
pub fn checksum(&self) -> u32 {
0
}
pub fn num_blocks(&self) -> u32 {
self.chunks
.iter()
.fold(0, |sum, chunk| sum + chunk.num_blocks())
}
pub fn num_chunks(&self) -> u32 {
self.chunks
.len()
.try_into()
.expect("number of chunks doesn't fit into u32")
}
pub fn add_chunk(&mut self, chunk: Chunk) {
self.chunks.push(chunk);
}
pub fn chunk_iter(&self) -> ChunkIter {
self.chunks.iter()
}
}
#[derive(Debug)]
pub enum Chunk {
Raw {
file: StdFile,
offset: u64,
num_blocks: u32,
},
Fill { fill: [u8; 4], num_blocks: u32 },
DontCare { num_blocks: u32 },
Crc32 { crc: u32 },
}
impl Chunk {
pub fn sparse_size(&self) -> u32 {
let body_size = match *self {
Chunk::Raw { num_blocks, .. } => num_blocks * BLOCK_SIZE,
Chunk::Fill { .. } | Chunk::Crc32 { .. } => 4,
Chunk::DontCare { .. } => 0,
};
u32::from(CHUNK_HEADER_SIZE) + body_size
}
pub fn raw_size(&self) -> u32 {
self.num_blocks() * BLOCK_SIZE
}
pub fn num_blocks(&self) -> u32 {
match *self {
Chunk::Raw { num_blocks, .. } |
Chunk::Fill { num_blocks, .. } |
Chunk::DontCare { num_blocks } => num_blocks,
Chunk::Crc32 { .. } => 0,
}
}
pub fn chunk_type(&self) -> ChunkType {
match *self {
Chunk::Raw { .. } => ChunkType::Raw,
Chunk::Fill { .. } => ChunkType::Fill,
Chunk::DontCare { .. } => ChunkType::DontCare,
Chunk::Crc32 { .. } => ChunkType::Crc32,
}
}
}