use std::{
fs::File,
io::{self, Read, Seek},
path::Path,
};
use byteorder::{BigEndian, ByteOrder};
use crate::MultiFilePackReadError;
pub struct MultiFilePackReadStream {
file: File,
file_count: u64,
file_size: u64,
}
impl MultiFilePackReadStream {
pub fn new<P>(file_path: P) -> Result<MultiFilePackReadStream, io::Error>
where
P: AsRef<Path>,
{
let mut file = File::open(file_path)?;
let file_size = file.metadata()?.len();
let mut buf: [u8; 8] = [0; 8];
file.read_exact(&mut buf)?;
let file_count = BigEndian::read_u64(&buf);
Ok(MultiFilePackReadStream {
file,
file_count,
file_size,
})
}
pub fn get_file_count(&self) -> u64 {
self.file_count
}
pub fn get_file_in_vector(
&mut self,
index: u64,
vec: &mut Vec<u8>,
) -> Result<(), MultiFilePackReadError> {
if index >= self.file_count {
return Err(MultiFilePackReadError::IndexOutOfBounds);
}
let mut buf_file_index: [u8; 16] = [0; 16];
self.file.seek(io::SeekFrom::Start(8 + index * 16))?;
self.file.read_exact(&mut buf_file_index)?;
let file_start = BigEndian::read_u64(&buf_file_index[0..8]);
let file_length = BigEndian::read_u64(&buf_file_index[8..16]);
if file_start > self.file_size
|| file_length > self.file_size
|| file_start + file_length > self.file_size
{
return Err(MultiFilePackReadError::IoError(
"Invalid size found in file index entry".to_string(),
));
}
vec.resize(file_length as usize, 0);
self.file.seek(io::SeekFrom::Start(file_start))?;
self.file.read_exact(vec)?;
Ok(())
}
pub fn get_file(&mut self, index: u64) -> Result<Vec<u8>, MultiFilePackReadError> {
let mut data: Vec<u8> = Vec::new();
self.get_file_in_vector(index, &mut data)?;
Ok(data)
}
pub fn close(self) {}
}