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
use byteorder::{ReadBytesExt, LE};
use std::io::{Read, Seek, SeekFrom};
mod tag;
pub use tag::{Tag, TagType};
pub const HEADER_MAGIC: u32 = 0xE85250D6;
pub const SEARCH_END: u64 = 32768;
pub const ALIGNMENT: usize = 8;
#[derive(Debug, Copy, Clone)]
pub struct Header {
pub magic: u32,
pub architecture: u32,
pub header_length: u32,
pub checksum: u32,
}
impl Header {
pub fn is_valid(&self) -> bool {
if self.magic != HEADER_MAGIC {
return false;
}
self.checksum
.wrapping_add(self.magic)
.wrapping_add(self.architecture)
.wrapping_add(self.header_length)
== 0
}
}
pub fn find_header<R: Read + Seek>(mut image: R) -> std::io::Result<Option<(u64, Header)>> {
for offset in (0..SEARCH_END).step_by(ALIGNMENT) {
image.seek(SeekFrom::Start(offset))?;
let magic = image.read_u32::<LE>()?;
if magic == HEADER_MAGIC {
let header = Header {
magic,
architecture: image.read_u32::<LE>()?,
header_length: image.read_u32::<LE>()?,
checksum: image.read_u32::<LE>()?,
};
if header.is_valid() {
return Ok(Some((offset, header)));
}
}
}
Ok(None)
}
#[derive(Debug, Clone)]
pub struct TagIter<R> {
done: bool,
data: R,
}
impl<R: Read> TagIter<R> {
pub fn new(data: R) -> Self {
Self { done: false, data }
}
}
impl<R: Read> Iterator for TagIter<R> {
type Item = std::io::Result<Tag>;
fn next(&mut self) -> Option<Self::Item> {
if self.done {
return None;
}
let tag = match Tag::from_reader(&mut self.data) {
Ok(t) => t,
Err(e) => return Some(Err(e)),
};
if tag == Tag::End {
self.done = true;
}
Some(Ok(tag))
}
}