-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy patharchive_block.rs
125 lines (110 loc) · 3.51 KB
/
archive_block.rs
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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
use head_block::HeadBlock;
use nom;
use util::get_bit_at;
use vint::vint;
/// Archive header which can exist once for each
/// .rar archive file.
#[derive(PartialEq, Debug, Default)]
pub struct ArchiveBlock {
pub head: HeadBlock,
pub flags: ArchiveFlags,
pub volume_number: u64,
}
impl ArchiveBlock {
/// Parse a byte slice and returns an ArchiveBlock and the not consumed byte slice.
/// When an error occours this function returns a nom error.
pub fn parse(inp: &[u8]) -> nom::IResult<&[u8], ArchiveBlock> {
// get the base header
let (input, head) = HeadBlock::parse(inp)?;
// check if the defined type is archive header
if head.typ != ::head_block::Typ::MainArchive {
return Err(nom::Err::Error(error_position!(inp, nom::ErrorKind::IsNot)));
}
// get the archive flags
let (mut input, flags) = vint(input)?;
let flags = ArchiveFlags::from(flags);
// create the archive struct
let mut archive = ArchiveBlock {
head,
flags,
volume_number: 0,
};
// check for volumne number
if archive.flags.volume_number {
let (i, n) = vint(input)?;
input = i;
archive.volume_number = n;
}
// check for a data area
if archive.head.flags.extra_area {
// _ holds locator data - no processed right now
let (i, _) = take!(input, archive.head.extra_area_size)?;
input = i;
}
Ok((input, archive))
}
}
#[test]
fn test_archive() {
// test a success case
let data = [
0xF3, 0xE1, 0x82, 0xEB, 0x0B, 0x01, 0x05, 0x07, 0x00, 0x06, 0x01, 0x01, 0x80, 0x80, 0x80,
0x00, 0x8C, 0x0D, 0x88, 0xE2,
];
let mut flags = ::head_block::Flags::default();
flags.extra_area = true;
flags.skip = true;
let mut arc = ArchiveBlock {
head: HeadBlock::new(4091642603, 11, ::head_block::Typ::MainArchive, flags),
flags: ArchiveFlags::default(),
volume_number: 0,
};
arc.head.extra_area_size = 7;
assert_eq!(
ArchiveBlock::parse(&data),
Ok((&[0x8C, 0x0D, 0x88, 0xE2][..], arc))
);
// test a wrong header type
let data = [
0xF3, 0xE1, 0x82, 0xEB, 0x0B, 0x02, 0x05, 0x07, 0x00, 0x06, 0x01, 0x01, 0x80, 0x80, 0x80,
0x00, 0x8C, 0x0D, 0x88, 0xE2,
];
assert_eq!(
ArchiveBlock::parse(&data),
Err(nom::Err::Error(error_position!(
&data[..],
nom::ErrorKind::IsNot
)))
);
}
/// Archive header flags which define main
/// flags for the archive header
#[derive(PartialEq, Debug, Default)]
pub struct ArchiveFlags {
pub multivolume: bool, // Volume. Archive is a part of multivolume set.
pub volume_number: bool, // Volume number field is present. This flag is present in all volumes except first.
pub solid: bool, // Solid archive.
pub recovery: bool, // 0x0008 Recovery record is present.
pub locked: bool, // Locked archive.
}
impl From<u64> for ArchiveFlags {
fn from(i: u64) -> Self {
let mut f = ArchiveFlags::default();
if get_bit_at(i, 0) {
f.multivolume = true;
}
if get_bit_at(i, 1) {
f.volume_number = true;
}
if get_bit_at(i, 2) {
f.solid = true;
}
if get_bit_at(i, 3) {
f.recovery = true;
}
if get_bit_at(i, 4) {
f.locked = true;
}
f
}
}