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
use std::{ 
    fs::File,
    io::{ Read, Seek, SeekFrom, BufReader },
    cell::RefCell,
};

use crate::{
	arc::Archive,
	sec::Sector,
	error::ParseError,
};
use super::*;

/// Cache inner reading using a file handle.

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: &Archive) -> crate::Result<Vec<u8>> {
        let expanded_header = archive.id > std::u16::MAX.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;
		let header_len = if expanded_header { SECTOR_EXPANDED_HEADER_SIZE } else { SECTOR_HEADER_SIZE };
		let data_len = if expanded_header { SECTOR_EXPANDED_DATA_SIZE } else { SECTOR_DATA_SIZE };

		loop {
			let offset = current_sector as usize * SECTOR_SIZE;
			
			if remaining >= data_len {
                self.handle.borrow_mut().seek(SeekFrom::Start(offset as u64))?;
                self.handle.borrow_mut().read_exact(&mut data_block)?;
					
				let sector = match Sector::new(&data_block, expanded_header) {
					Ok(sector) => sector,
					Err(_) => return Err(ParseError::Sector(archive.sector).into())
				};
				sector.header.validate(archive.id, chunk, archive.index_id)?;

				current_sector = sector.header.next;

				remaining -= data_len;
				data[current..current + data_len].copy_from_slice(sector.data_block);
				current += data_len;
			} else {
				if remaining == 0 { break; }

				let mut data_block = vec![0; remaining + header_len];

                self.handle.borrow_mut().seek(SeekFrom::Start(offset as u64))?;
				self.handle.borrow_mut().read_exact(&mut data_block)?;
				
				let sector = match Sector::new(&data_block, expanded_header) {
					Ok(sector) => sector,
					Err(_) => return Err(ParseError::Sector(archive.sector).into())
				};
				sector.header.validate(archive.id, chunk, archive.index_id)?;

				data[current..current + remaining].copy_from_slice(sector.data_block);
				break;
			}

			chunk += 1;
		}

		Ok(data)
    }
}