diff --git a/Cargo.toml b/Cargo.toml index 7874400..511d1f1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,15 @@ [package] name = "libfar" +description = "Library for interacting with FAR archives" version = "0.1.0" edition = "2021" authors = ["husky (fekhesk)"] +homepage = "https://gitlab.com/realmicrosoft/libfar-rs" +repository = "https://gitlab.com/realmicrosoft/libfar-rs" +license = "MIT" +readme = "README.md" +keywords = ["far", "archive", "library", "EA"] +categories = ["encoding", "filesystem", "game development", "parsing tools"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/README.md b/README.md new file mode 100644 index 0000000..5147b7b --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +# LibFar-rs +## Rust library for interacting with FAR archives. + +check rust docs for more info. \ No newline at end of file diff --git a/src/farlib.rs b/src/farlib.rs index 30b084e..ca252d8 100644 --- a/src/farlib.rs +++ b/src/farlib.rs @@ -1,17 +1,44 @@ use std::io::{BufReader, Read}; +/// Struct containing information about a file, without reading the actual data of the file. +/// This should be used in cases where file information is needed to be retrieved quickly +/// (e.g. when listing files in an archive). pub struct FarFileInfo { pub name: String, pub size: u32, offset: u32, } +/// Struct containing a file, whether or not it's in an archive. +/// This should be used when creating a file from a buffer, or when getting files from an archive. +/// +/// Should be created by calling `FarFile::new_from_archive` if extracting from an archive, or +/// `FarFile::new_from_file` if reading from a buffer. +/// +/// # Examples +/// ``` +/// // buffer is a Vec containing the contents of a file +/// // fileA_name is the name of the file +/// use libfar::farlib::FarFile; +/// let fileA = FarFile::new_from_file(fileA_name, buffer.len() as u32, buffer); +/// +/// // archive_buf is a Vec containing the contents of a .far file +/// // fileB_name is the name of the file that we got from reading the manifest +/// // fileB_size is the size of the file that we got from reading the manifest +/// // fileB_offset is the offset of the file that we got from reading the manifest +/// let fileB = FarFile::new_from_archive(fileB_name, fileB_size, fileB_offset, archive_buf); +/// ``` pub struct FarFile { pub name: String, pub size: u32, pub data: Vec, } +/// Struct containing information about an archive. +/// +/// Should be created by one of two ways: +/// 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 pub struct FarArchive { pub version: u32, pub file_count: u32, @@ -20,6 +47,17 @@ pub struct FarArchive { } impl FarFile { + /// Creates a new FarFile struct from an offset, size, and archive buffer. + /// + /// # Examples + /// ``` + /// // archive_buf is a Vec containing the contents of a .far file + /// // file_name is the name of the file that we got from reading the manifest + /// // file_size is the size of the file that we got from reading the manifest + /// // file_offset is the offset of the file that we got from reading the manifest + /// use libfar::farlib::FarFile; + /// let file = FarFile::new_from_archive(file_name, file_size, file_offset, archive_buf); + /// ``` pub fn new_from_archive(name : String, size : u32, offset : u32, original_file : &Vec) -> FarFile { let mut reader = BufReader::new(&original_file[offset as usize..(offset + size) as usize]); let mut data = Vec::new(); @@ -31,6 +69,15 @@ impl FarFile { } } + /// Creates a new FarFile struct from a size, and data buffer. + /// + /// # Examples + /// ``` + /// // buffer is a Vec containing the contents of a file + /// // file_name is the name of the file + /// use libfar::farlib::FarFile; + /// let file = FarFile::new_from_file(file_name, buffer.len() as u32, buffer); + /// ``` pub fn new_from_file(name : String, size : u32, data : Vec) -> FarFile { FarFile { name, @@ -41,6 +88,29 @@ impl FarFile { } impl FarArchive { + /// Creates a new FarArchive struct from a list of FarFile structs. + /// Important when creating a new archive. + /// + /// # Examples + /// ``` + /// // file_names is a Vec containing the names of the files + /// use std::fs; + /// use libfar::farlib; + /// let mut file_list = Vec::new(); + /// for file in file_names { + /// let file_name = file.split("/").last().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 = farlib::FarFile { + /// name: file_name.to_string(), + /// size: file_size as u32, + /// data: file_data + /// }; + /// file_list.push(file_obj); + /// } + /// + /// let archive = farlib::FarArchive::new_from_files(file_list); + /// ``` pub fn new_from_files(files : Vec) -> FarArchive { let mut file_list = Vec::new(); let mut file_data = Vec::new(); @@ -62,6 +132,22 @@ impl FarArchive { } } + /// Loads file data into a FarArchive struct, used if a FarFileInfo struct is not sufficient. + /// + /// # Examples + /// ``` + /// // buffer is a Vec containing the contents of a .far file + /// use libfar::farlib; + /// let test = farlib::test(&buffer); + /// match test { + /// Ok(archive) => { + /// let archive = archive.load_file_data(&buffer); + /// } + /// Err(e) => { + /// println!("{} is not a valid archive: {}", archive_name, e); + /// } + /// } + /// ``` pub fn load_file_data(self, original_file : &Vec) -> FarArchive { let mut new_file_data = Vec::new(); for i in 0..self.file_list.len() { @@ -80,6 +166,20 @@ impl FarArchive { } } + /// Creates a buffer representing the contents of a FarArchive struct. + /// Can be written to a file to create a .far archive. + /// + /// # Examples + /// ``` + /// // archive is a FarArchive struct + /// // archive_name is the name of the file we will write the archive to + /// use std::fs; + /// use std::io::Write; + /// use libfar::farlib; + /// let buffer = archive.to_vec(); + /// let mut file = fs::File::create(archive_name.clone()).expect("Failed to create file"); + /// file.write_all(&*archive_obj.to_vec()).expect("Failed to write file"); + /// ``` pub fn to_vec(self) -> Vec { // write header let mut header = Vec::new(); @@ -128,7 +228,24 @@ impl FarArchive { } } -// test for FAR!byAZ +/// Tests if a buffer is a valid FarArchive. +/// Returns a FarArchive struct if it is, or an error if it is not. +/// +/// # Examples +/// ``` +/// use std::fs; +/// use libfar::farlib; +/// let buffer = fs::read("test.far").expect("Failed to read file"); +/// let test = farlib::test(&buffer); +/// match test { +/// Ok(archive) => { +/// println!("test.far is a valid archive"); +/// }, +/// Err(e) => { +/// println!("test.far is not a valid archive: {}", e); +/// } +/// } +/// ``` pub fn test(file : &Vec) -> Result { let mut reader = BufReader::new(&file[..]); let mut magic = [0u8; 8]; @@ -149,7 +266,7 @@ pub fn test(file : &Vec) -> Result { }) } -pub fn list_files(file : &Vec) -> Result, String> { +fn list_files(file : &Vec) -> Result, String> { // manifest offset is at 12 bytes (u32) let mut reader = BufReader::new(&file[12..]); let mut offset = [0u8; 4];