fix a lot of stuff and generally make things better

This commit is contained in:
husky 2023-09-25 13:41:03 -07:00
parent 20bac182c3
commit 86c3c6d62a
No known key found for this signature in database
GPG key ID: 6B3D8CB511646891
2 changed files with 52 additions and 38 deletions

View file

@ -1,3 +1,7 @@
#[cfg(test)]
mod tests;
use std::collections::HashMap;
use std::io::{BufReader, Read}; use std::io::{BufReader, Read};
/// Struct containing information about a file, without reading the actual data of the file. /// Struct containing information about a file, without reading the actual data of the file.
@ -25,8 +29,8 @@ pub struct FarFileInfo {
/// let file_a = FarFile::new_from_file(filename, buffer); /// let file_a = FarFile::new_from_file(filename, buffer);
/// ///
/// let filename_b = "file_in_archive.jpg"; /// let filename_b = "file_in_archive.jpg";
/// let size_b = 12345; /// let size_b = 0;
/// let offset_b = 67890; /// let offset_b = 0;
/// let archive_buf = Vec::new(); // buffer containing the contents of the archive /// let archive_buf = Vec::new(); // buffer containing the contents of the archive
/// let file_b = FarFile::new_from_archive(filename_b, size_b, offset_b, &archive_buf); /// let file_b = FarFile::new_from_archive(filename_b, size_b, offset_b, &archive_buf);
/// ``` /// ```
@ -40,18 +44,20 @@ pub struct FarFile {
/// ///
/// Should be created by one of two ways: /// Should be created by one of two ways:
/// 1. Calling `FarArchive::new_from_files` if creating an archive from a list of FarFile structs /// 1. Calling `FarArchive::new_from_files` if creating an archive from a list of FarFile structs
/// 2. Calling `farlib::test(buffer)` if loading an archive from a file/buffer /// 2. Calling `read_archive(buffer)` if loading an archive from a file/buffer
pub struct FarArchive { pub struct FarArchive {
pub version: u32, pub version: u32,
pub file_count: u32, pub file_count: u32,
pub file_list: Vec<FarFileInfo>, pub file_list: Vec<FarFileInfo>,
pub file_data: Vec<FarFile>, pub file_data: Vec<FarFile>,
pub file_index: HashMap<String, usize>,
} }
impl FarFile { impl FarFile {
/// Creates a new FarFile struct from an offset, size, and archive buffer. /// Creates a new FarFile struct from an offset, size, and archive buffer.
pub fn new_from_archive(name: impl ToString, size: u32, offset: u32, original_file: &[u8]) -> FarFile { pub fn new_from_archive(name: impl ToString, size: u32, offset: u32, original_file: &[u8]) -> FarFile {
let mut reader = BufReader::new(&original_file[offset as usize..(offset + size) as usize]); const HEADER_SIZE: usize = 16;
let mut reader = BufReader::new(&original_file[HEADER_SIZE + offset as usize..HEADER_SIZE + (offset + size) as usize]);
let mut data = Vec::new(); let mut data = Vec::new();
reader.read_to_end(&mut data).expect("Failed to read file data"); reader.read_to_end(&mut data).expect("Failed to read file data");
FarFile { FarFile {
@ -81,32 +87,22 @@ impl FarArchive {
/// use std::fs; /// use std::fs;
/// use libfar::*; /// use libfar::*;
/// let mut file_list = Vec::new(); /// let mut file_list = Vec::new();
/// let file_names = fs::read_dir("files").expect("Failed to read directory");
/// for file in file_names {
/// let file_name = file.clone().unwrap().path().file_name().unwrap().to_str().unwrap();
/// let file_size = fs::metadata(file.clone()).expect("Failed to get file size").len();
/// let file_data = fs::read(file.clone()).expect("Failed to read file");
/// let file_obj = FarFile {
/// name: file_name.to_string(),
/// size: file_size as u32,
/// data: file_data
/// };
/// file_list.push(file_obj);
/// }
/// ///
/// let archive = FarArchive::new_from_files(file_list); /// let archive = FarArchive::new_from_files(file_list);
/// ``` /// ```
pub fn new_from_files(files: Vec<FarFile>) -> FarArchive { pub fn new_from_files(files: Vec<FarFile>) -> FarArchive {
let mut file_list = Vec::new(); let mut file_list = Vec::new();
let mut file_data = Vec::new(); let mut file_data = Vec::new();
let mut file_index = HashMap::new();
let mut offset = 0; let mut offset = 0;
for file in files { for (i, file) in files.into_iter().enumerate() {
offset += &file.size;
file_list.push(FarFileInfo { file_list.push(FarFileInfo {
name: file.name.clone(), name: file.name.clone(),
size: file.size, size: file.size,
offset, offset,
}); });
offset += &file.size;
file_index.insert(file.name.clone(), i);
file_data.push(file); file_data.push(file);
} }
FarArchive { FarArchive {
@ -114,6 +110,7 @@ impl FarArchive {
file_count: file_list.len() as u32, file_count: file_list.len() as u32,
file_list, file_list,
file_data, file_data,
file_index,
} }
} }
@ -124,19 +121,20 @@ impl FarArchive {
/// // buffer is a Vec<u8> containing the contents of a .far file /// // buffer is a Vec<u8> containing the contents of a .far file
/// use std::fs; /// use std::fs;
/// use libfar::*; /// use libfar::*;
/// let buffer = fs::read("test.far").expect("Failed to read file"); /// let buffer = vec![]; // buffer containing the contents of a .far file
/// let test = test(&buffer); /// let test = read_archive(&buffer);
/// match test { /// match test {
/// Ok(archive) => { /// Ok(mut archive) => {
/// let archive = archive.load_file_data(&buffer); /// archive.load_file_data(&buffer);
/// } /// }
/// Err(e) => { /// Err(e) => {
/// panic!("test.far is not a valid archive: {}", e); /// panic!("test.far is not a valid archive: {:?}", e);
/// } /// }
/// } /// }
/// ``` /// ```
pub fn load_file_data(self, original_file: &[u8]) -> FarArchive { pub fn load_file_data(&mut self, original_file: &[u8]) {
let mut new_file_data = Vec::new(); let mut new_file_data = Vec::new();
let mut new_file_index = HashMap::new();
for i in 0..self.file_list.len() { for i in 0..self.file_list.len() {
new_file_data.push(FarFile::new_from_archive( new_file_data.push(FarFile::new_from_archive(
self.file_list[i].name.clone(), self.file_list[i].name.clone(),
@ -144,13 +142,10 @@ impl FarArchive {
self.file_list[i].offset, self.file_list[i].offset,
original_file, original_file,
)); ));
new_file_index.insert(self.file_list[i].name.clone(), i);
} }
FarArchive { self.file_data = new_file_data;
version: self.version, self.file_index = new_file_index;
file_count: self.file_count,
file_list: self.file_list,
file_data: new_file_data,
}
} }
/// Creates a buffer representing the contents of a FarArchive struct. /// Creates a buffer representing the contents of a FarArchive struct.
@ -164,9 +159,7 @@ impl FarArchive {
/// use std::io::Write; /// use std::io::Write;
/// use libfar::*; /// use libfar::*;
/// let archive: FarArchive = unimplemented!("Create a FarArchive struct"); /// let archive: FarArchive = unimplemented!("Create a FarArchive struct");
/// let buffer = archive.to_vec(); /// let buffer = archive.to_vec(); // buffer containing the contents of the archive
/// let mut file = fs::File::create("test.far").expect("Failed to create file");
/// file.write_all(&buffer).expect("Failed to write to file");
/// ``` /// ```
pub fn to_vec(self) -> Vec<u8> { pub fn to_vec(self) -> Vec<u8> {
// write header // write header
@ -223,18 +216,18 @@ impl FarArchive {
/// ``` /// ```
/// use std::fs; /// use std::fs;
/// use libfar::*; /// use libfar::*;
/// let buffer = fs::read("test.far").expect("Failed to read file"); /// let buffer = vec![]; // buffer containing the contents of a .far file
/// let test = test(&buffer); /// let archive = read_archive(&buffer);
/// match test { /// match archive {
/// Ok(archive) => { /// Ok(archive) => {
/// println!("test.far is a valid archive"); /// println!("test.far is a valid archive");
/// }, /// },
/// Err(e) => { /// Err(e) => {
/// println!("test.far is not a valid archive: {}", e); /// println!("test.far is not a valid archive: {:?}", e);
/// } /// }
/// } /// }
/// ``` /// ```
pub fn test(file: &[u8]) -> Result<FarArchive, FarError> { pub fn read_archive(file: &[u8]) -> Result<FarArchive, FarError> {
let mut reader = BufReader::new(file); let mut reader = BufReader::new(file);
let mut magic = [0u8; 8]; let mut magic = [0u8; 8];
reader.read_exact(&mut magic).unwrap(); reader.read_exact(&mut magic).unwrap();
@ -251,6 +244,7 @@ pub fn test(file: &[u8]) -> Result<FarArchive, FarError> {
file_count: files.len() as u32, file_count: files.len() as u32,
file_list: files, file_list: files,
file_data: vec![], file_data: vec![],
file_index: Default::default(),
}) })
} }
@ -293,6 +287,7 @@ fn list_files(file: &[u8]) -> Result<Vec<FarFileInfo>, FarReadError> {
} }
/// Enum representing possible errors when reading a FarArchive. /// Enum representing possible errors when reading a FarArchive.
#[derive(Debug, Clone)]
pub enum FarError { pub enum FarError {
/// The file is not a valid Far archive. /// The file is not a valid Far archive.
InvalidFile, InvalidFile,
@ -301,6 +296,7 @@ pub enum FarError {
} }
/// Struct representing the location at which a FarArchive could no longer be read, and the associated error. /// Struct representing the location at which a FarArchive could no longer be read, and the associated error.
#[derive(Debug, Clone)]
pub struct FarReadError { pub struct FarReadError {
pub offset: u32, pub offset: u32,
pub error: String, pub error: String,

18
src/tests.rs Normal file
View file

@ -0,0 +1,18 @@
use super::*;
#[test]
fn can_read_our_own_archives() {
let file_data: Vec<u8> = vec![1,2,3,4,5];
let file_name = "test_file";
let file = FarFile::new_from_file(file_name, file_data.clone());
let archive = FarArchive::new_from_files(vec![file]);
let archive_data = archive.to_vec();
let mut archive = read_archive(&archive_data).expect("could not read archive");
archive.load_file_data(&archive_data);
let new_file = archive.file_index.get(file_name).expect("could not get file");
let new_file = &archive.file_data[*new_file];
assert_eq!(new_file.data, file_data);
}