fix a lot of stuff and generally make things better
This commit is contained in:
parent
20bac182c3
commit
86c3c6d62a
2 changed files with 52 additions and 38 deletions
72
src/lib.rs
72
src/lib.rs
|
@ -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
18
src/tests.rs
Normal 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);
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue