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
use crate::format::{FileInfo, Format, FormatStep};
use std::collections::HashMap;
use std::io::{Error, ErrorKind, Read, Result, Seek, SeekFrom};
#[derive(Debug)]
pub struct Archive<R> {
inner: R,
files: HashMap<String, FileInfo>,
}
impl<R> Archive<R>
where
R: Read + Seek,
{
pub fn new(mut inner: R) -> Result<Self> {
let mut fmt = Format::new();
loop {
match fmt.next()? {
FormatStep::Read(s, ref mut buf) => {
inner.seek(s)?;
inner.read_exact(buf)?;
}
FormatStep::Done(filesvec) => {
let mut files = HashMap::with_capacity(filesvec.len());
for f in filesvec.into_iter() {
files.insert(f.path.clone(), f);
}
return Ok(Archive { inner, files });
}
}
}
}
pub fn list(&self) -> impl Iterator<Item = &FileInfo> {
self.files.values()
}
fn find(&self, path: &str) -> Result<&FileInfo> {
self.files
.get(path)
.ok_or_else(|| Error::new(ErrorKind::NotFound, "file not found"))
}
pub fn load(&mut self, path: &str) -> Result<Vec<u8>> {
explode::explode(&self.load_compressed(path)?)
.map_err(|e| Error::new(ErrorKind::InvalidData, e))
}
pub fn load_compressed(&mut self, path: &str) -> Result<Vec<u8>> {
let info = self.find(path)?;
let size = info.size;
let offset = info.offset;
let mut ret = vec![0; size];
self.inner.seek(SeekFrom::Start(offset))?;
self.inner.read_exact(&mut ret)?;
Ok(ret)
}
}
#[cfg(test)]
mod tests {
use super::Archive;
use crate::examples::EXAMPLES;
use std::io::Cursor;
#[test]
fn archive_new() {
for (arcdata, _files) in EXAMPLES {
let c = Cursor::new(arcdata);
let _ar = Archive::new(c).unwrap();
}
}
#[test]
fn archive_list() {
for (arcdata, files) in EXAMPLES {
let c = Cursor::new(arcdata);
let ar = Archive::new(c).unwrap();
for file in ar.list() {
let i = files.iter().find(|(name, _)| *name == file.path);
if i.is_none() {
panic!("unexpected file {:?}", file.path);
}
}
}
}
#[test]
fn archive_load() {
for (arcdata, files) in EXAMPLES {
let c = Cursor::new(arcdata);
let mut ar = Archive::new(c).unwrap();
for (fname, contents) in files.iter() {
let ours = ar.load(fname).unwrap();
assert_eq!(ours, *contents);
}
}
}
}