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
use std::{
fs::File,
io::{ Read, Seek, SeekFrom, BufReader },
cell::RefCell,
};
use crate::{
arc::ArchiveRef,
sec::{ Sector, SectorHeaderSize },
error::ParseError,
sec::SECTOR_SIZE,
};
use super::Store;
#[derive(Debug)]
pub struct FileStore {
handle: RefCell<BufReader<File>>
}
impl Store for FileStore {
#[inline]
fn new(main_file: File) -> crate::Result<Self> {
Ok(Self { handle: RefCell::new(BufReader::new(main_file)) })
}
#[inline]
fn read(&self, archive: &ArchiveRef) -> crate::Result<Vec<u8>> {
let header_size = SectorHeaderSize::from_archive(archive);
let (header_len, data_len) = header_size.clone().into();
let mut current_sector = archive.sector;
let mut data = vec![0; archive.length];
let mut remaining = archive.length;
let mut data_block = vec![0; SECTOR_SIZE];
let mut current = 0;
let mut chunk = 0;
loop {
let offset = current_sector as usize * SECTOR_SIZE;
if remaining >= data_len {
let mut handle = self.handle.borrow_mut();
handle.seek(SeekFrom::Start(offset as u64))?;
handle.read_exact(&mut data_block)?;
match Sector::new(&data_block, &header_size) {
Ok(sector) => {
sector.header.validate(archive.id, chunk, archive.index_id)?;
current_sector = sector.header.next;
data[current..current + data_len].copy_from_slice(sector.data_block);
},
Err(_) => return Err(ParseError::Sector(archive.sector).into())
};
remaining -= data_len;
current += data_len;
} else {
if remaining == 0 { break; }
let mut data_block = vec![0; remaining + header_len];
let mut handle = self.handle.borrow_mut();
handle.seek(SeekFrom::Start(offset as u64))?;
handle.read_exact(&mut data_block)?;
match Sector::new(&data_block, &header_size) {
Ok(sector) => {
sector.header.validate(archive.id, chunk, archive.index_id)?;
data[current..current + remaining].copy_from_slice(sector.data_block);
break;
},
Err(_) => return Err(ParseError::Sector(archive.sector).into())
};
}
chunk += 1;
}
Ok(data)
}
}