diff --git a/Cargo.lock b/Cargo.lock index b68274d..ad34ffc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,7 +4,7 @@ version = 3 [[package]] name = "acridotheres_core" -version = "0.1.0" +version = "0.1.1" dependencies = [ "chrono", "crc32fast", diff --git a/Cargo.toml b/Cargo.toml index 6ab71ce..b3b1edd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = 'acridotheres_core' -version = '0.1.0' +version = '0.1.1' edition = '2021' [lib] diff --git a/src/file.rs b/src/file.rs index 46becb0..6225a4d 100644 --- a/src/file.rs +++ b/src/file.rs @@ -2,7 +2,7 @@ use std::{ cmp::min, fs::{FileTimes, OpenOptions}, io::{Read, Seek, Write}, - time::SystemTime, + mem::drop }; use chrono::{DateTime, Utc}; @@ -15,44 +15,49 @@ pub struct Times { } #[derive(Debug)] -pub struct FileReader<'a> { - path: &'a str, +pub struct FileReader { + path: String, file: std::fs::File, pos: u64, } -impl<'a> FileReader<'a> { - pub fn new(path: &'a str) -> Self { +impl<'a> FileReader { + pub fn new(path: &'a String) -> Self { let mut file = OpenOptions::new().read(true).open(path).unwrap(); file.rewind().unwrap(); - Self { path, file, pos: 0 } + Self { path: path.to_owned(), file, pos: 0 } + } + + pub fn close(self) { + self.file.sync_all().unwrap(); + drop(self); } pub fn export( &mut self, - offset: u64, - len: u64, + offset: &u64, + len: &u64, target: &mut FileWriter, - modified: DateTime, - buffer_size: u64, + modified: &DateTime, + buffer_size: &u64, ) { let pos_before = self.get_position(); self.seek(offset); - let mut buf = vec![0; buffer_size as usize]; - let mut remaining = len; + let mut buf = vec![0; *buffer_size as usize]; + let mut remaining = *len; while remaining > 0 { - let to_read = min(buffer_size as u64, remaining) as usize; + let to_read = min(*buffer_size as u64, remaining) as usize; let read = self.read(&mut buf[..to_read]); target.write(read); remaining -= to_read as u64; } - let time = FileTimes::new().set_modified(modified.into()); - target.set_times(time); + let time = FileTimes::new().set_modified(modified.to_owned().into()); + target.set_times(&time); - self.seek(pos_before); + self.seek(&pos_before); } pub fn get_times(&self) -> Times { @@ -60,28 +65,28 @@ impl<'a> FileReader<'a> { Times { created: metadata .created() - .unwrap_or_else(|_| SystemTime::now()) + .unwrap_or_else(|_| metadata.modified().unwrap().into()) .into(), accessed: metadata.accessed().unwrap().into(), modified: metadata.modified().unwrap().into(), } } - pub fn get_path(&self) -> &str { - self.path + pub fn get_path(&self) -> &String { + &self.path } - pub fn seek(&mut self, pos: u64) { - self.file.seek(std::io::SeekFrom::Start(pos)).unwrap(); - self.pos = pos; + pub fn seek(&mut self, pos: &u64) { + self.file.seek(std::io::SeekFrom::Start(*pos)).unwrap(); + self.pos = *pos; } pub fn rewind(&mut self) { - self.seek(0); + self.seek(&0); } - pub fn jump(&mut self, offset: i128) { - self.seek((self.pos as i128 + offset) as u64); + pub fn jump(&mut self, offset: &i128) { + self.seek(&((self.pos as i128 + offset) as u64)); } pub fn get_position(&self) -> u64 { @@ -98,14 +103,14 @@ impl<'a> FileReader<'a> { buf } - pub fn read_utf8(&mut self, len: u64) -> String { - let mut buf = vec![0; len as usize]; + pub fn read_utf8(&mut self, len: &u64) -> String { + let mut buf = vec![0; *len as usize]; self.read(&mut buf); String::from_utf8(buf).unwrap() } - pub fn read_u8array(&mut self, len: u64) -> Vec { - let mut buf = vec![0; len as usize]; + pub fn read_u8array(&mut self, len: &u64) -> Vec { + let mut buf = vec![0; *len as usize]; self.read(&mut buf); buf } @@ -166,15 +171,15 @@ impl<'a> FileReader<'a> { } #[derive(Debug)] -pub struct FileWriter<'a> { - path: &'a str, +pub struct FileWriter { + path: String, file: std::fs::File, pos: u64, } -impl<'a> FileWriter<'a> { - pub fn new(path: &'a str, append: bool) -> Self { - if append { +impl<'a> FileWriter { + pub fn new(path: &'a String, append: &bool) -> Self { + if *append { let mut file = OpenOptions::new() .write(true) .create(true) @@ -183,7 +188,7 @@ impl<'a> FileWriter<'a> { .unwrap(); file.rewind().unwrap(); return Self { - path, + path: path.to_owned(), pos: file.metadata().unwrap().len(), file, }; @@ -196,32 +201,33 @@ impl<'a> FileWriter<'a> { .unwrap(); file.rewind().unwrap(); - Self { path, file, pos: 0 } + Self { path: path.to_owned(), file, pos: 0 } } - pub fn close(&mut self) { + pub fn close(self) { self.file.sync_all().unwrap(); + drop(self); } - pub fn set_times(&self, times: FileTimes) { - self.file.set_times(times).unwrap(); + pub fn set_times(&self, times: &FileTimes) { + self.file.set_times(*times).unwrap(); } - pub fn get_path(&self) -> &str { - self.path + pub fn get_path(&self) -> &String { + &self.path } - pub fn seek(&mut self, pos: u64) { - self.file.seek(std::io::SeekFrom::Start(pos)).unwrap(); - self.pos = pos; + pub fn seek(&mut self, pos: &u64) { + self.file.seek(std::io::SeekFrom::Start(*pos)).unwrap(); + self.pos = *pos; } pub fn rewind(&mut self) { - self.seek(0); + self.seek(&0); } - pub fn jump(&mut self, offset: i128) { - self.seek((self.pos as i128 + offset) as u64); + pub fn jump(&mut self, offset: &i128) { + self.seek(&((self.pos as i128 + offset) as u64)); } pub fn get_position(&self) -> u64 { @@ -237,7 +243,7 @@ impl<'a> FileWriter<'a> { self.pos += buf.len() as u64; } - pub fn write_utf8(&mut self, s: &str) { + pub fn write_utf8(&mut self, s: &String) { self.write(s.as_bytes()); } @@ -245,39 +251,39 @@ impl<'a> FileWriter<'a> { self.write(buf.as_slice()); } - pub fn write_u8(&mut self, n: u8) { + pub fn write_u8(&mut self, n: &u8) { self.write(&n.to_le_bytes()); } - pub fn write_u16le(&mut self, n: u16) { + pub fn write_u16le(&mut self, n: &u16) { self.write(&n.to_le_bytes()); } - pub fn write_u16be(&mut self, n: u16) { + pub fn write_u16be(&mut self, n: &u16) { self.write(&n.to_be_bytes()); } - pub fn write_u32le(&mut self, n: u32) { + pub fn write_u32le(&mut self, n: &u32) { self.write(&n.to_le_bytes()); } - pub fn write_u32be(&mut self, n: u32) { + pub fn write_u32be(&mut self, n: &u32) { self.write(&n.to_be_bytes()); } - pub fn write_u64le(&mut self, n: u64) { + pub fn write_u64le(&mut self, n: &u64) { self.write(&n.to_le_bytes()); } - pub fn write_u64be(&mut self, n: u64) { + pub fn write_u64be(&mut self, n: &u64) { self.write(&n.to_be_bytes()); } - pub fn write_u128le(&mut self, n: u128) { + pub fn write_u128le(&mut self, n: &u128) { self.write(&n.to_le_bytes()); } - pub fn write_u128be(&mut self, n: u128) { + pub fn write_u128be(&mut self, n: &u128) { self.write(&n.to_be_bytes()); } } diff --git a/src/formats/zip/parser.rs b/src/formats/zip/parser.rs index 4fcb11a..5eb3eea 100644 --- a/src/formats/zip/parser.rs +++ b/src/formats/zip/parser.rs @@ -18,25 +18,25 @@ pub fn metadata<'a>(file: &mut FileReader) -> ZipArchiveMetadata<'a> { } pub fn get_file(file: &mut FileReader, entry: &ZipFileEntry) -> Vec { - file.seek(entry.file.offset); - file.read_u8array(entry.uncompressed_size as u64) + file.seek(&entry.file.offset); + file.read_u8array(&(entry.uncompressed_size as u64)) } pub fn extract( file: &mut FileReader, entries: &Vec, - buffer_size: u64, + buffer_size: &u64, path_rewriter: &dyn Fn(&str) -> String, ) { for entry in entries { let path = path_rewriter(&entry.file.path); if !entry.file.is_directory { - let mut target = FileWriter::new(&path, false); + let mut target = FileWriter::new(&path, &false); file.export( - entry.file.offset, - entry.file.size, + &entry.file.offset, + &entry.file.size, &mut target, - entry.file.modified, + &entry.file.modified.into(), buffer_size, ); } else { @@ -86,17 +86,17 @@ fn read_local_files<'a>(file: &mut FileReader) -> (Vec>, u32) { let lastmod_time = file.read_u16le(); let lastmod_date = file.read_u16le(); let crc32 = file.read_u32le(); - let size_compressed = file.read_u32le(); + let size_compressed = file.read_u32le() as i128; let size_uncompressed = file.read_u32le(); - let name_length = file.read_u16le(); - let extra_length = file.read_u16le(); - let name = file.read_utf8(name_length as u64); - let extra = file.read_u8array(extra_length as u64); + let name_length = file.read_u16le() as u64; + let extra_length = file.read_u16le() as u64; + let name = file.read_utf8(&name_length); + let extra = file.read_u8array(&extra_length); files.push(ZipFileEntry { file: FileEntry { offset: file.get_position(), size: size_compressed as u64, - modified: msdos::parse(lastmod_date, lastmod_time), + modified: msdos::parse(&lastmod_date, &lastmod_time).into(), is_directory: name.ends_with('/'), path: name, }, @@ -107,14 +107,14 @@ fn read_local_files<'a>(file: &mut FileReader) -> (Vec>, u32) { checksum: crc32, extra_field: extra, }); - file.jump(size_compressed as i128); + file.jump(&size_compressed); signature = file.read_u32le(); } (files, signature) } -pub fn check_integrity(source: &mut FileReader, file: &ZipFileEntry, buffer_size: u64) -> bool { - let hash = crc32::hash(source, file.file.offset, file.file.size, buffer_size); +pub fn check_integrity(source: &mut FileReader, file: &ZipFileEntry, buffer_size: &u64) -> bool { + let hash = crc32::hash(source, &file.file.offset, &file.file.size, buffer_size); hash == file.checksum } diff --git a/src/formats/zip/writer.rs b/src/formats/zip/writer.rs index 7139986..b87ce9f 100644 --- a/src/formats/zip/writer.rs +++ b/src/formats/zip/writer.rs @@ -1,13 +1,13 @@ use crate::{helpers::datetime::msdos, types::ZipArchiveData, FileWriter}; -pub fn write(target: &mut FileWriter, data: &mut ZipArchiveData, buffer_size: u64) { +pub fn write(target: &mut FileWriter, data: &mut ZipArchiveData, buffer_size: &u64) { for file in &mut data.files { target.write(b"PK\x03\x04"); let version: u16 = 20; let bit_flag: u16 = 0; let compression_method: u16 = 0; - let last_modified = msdos::serialize(file.file.modified); + let last_modified = msdos::serialize(&file.file.modified.into()); let lastmod_time = last_modified.1; let lastmod_date = last_modified.0; let crc32 = file.checksum; @@ -18,24 +18,24 @@ pub fn write(target: &mut FileWriter, data: &mut ZipArchiveData, buffer_size: u6 let name = &file.file.path; let extra: &Vec = &vec![]; - target.write_u16le(version); - target.write_u16le(bit_flag); - target.write_u16le(compression_method); - target.write_u16le(lastmod_time); - target.write_u16le(lastmod_date); - target.write_u32le(crc32); - target.write_u32le(size_compressed); - target.write_u32le(size_uncompressed); - target.write_u16le(name_length); - target.write_u16le(extra_field_length); + target.write_u16le(&version); + target.write_u16le(&bit_flag); + target.write_u16le(&compression_method); + target.write_u16le(&lastmod_time); + target.write_u16le(&lastmod_date); + target.write_u32le(&crc32); + target.write_u32le(&size_compressed); + target.write_u32le(&size_uncompressed); + target.write_u16le(&name_length); + target.write_u16le(&extra_field_length); target.write_utf8(name); target.write_u8array(extra); file.file.source.export( - file.file.offset, - file.file.size, + &file.file.offset, + &file.file.size, target, - file.file.modified, + &file.file.modified.into(), buffer_size, ); } diff --git a/src/helpers/datetime/msdos.rs b/src/helpers/datetime/msdos.rs index d9b89b7..c01238c 100644 --- a/src/helpers/datetime/msdos.rs +++ b/src/helpers/datetime/msdos.rs @@ -1,8 +1,8 @@ -use chrono::{DateTime, Utc}; +use chrono::{DateTime, Local}; // https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-dosdatetimetofiletime -pub fn parse(date: u16, time: u16) -> DateTime { +pub fn parse(date: &u16, time: &u16) -> DateTime { let y = (date >> 9) + 1980; let m = (date >> 5) & 0x0F; let d = date & 0x1F; @@ -22,7 +22,7 @@ pub fn parse(date: u16, time: u16) -> DateTime { .into() } -pub fn serialize(datetime: DateTime) -> (u16, u16) { +pub fn serialize(datetime: &DateTime) -> (u16, u16) { let date = datetime.format("%Y-%m-%d").to_string(); let time = datetime.format("%H:%M:%S").to_string(); diff --git a/src/helpers/hash/crc32.rs b/src/helpers/hash/crc32.rs index fbfe8fc..a1a7ade 100644 --- a/src/helpers/hash/crc32.rs +++ b/src/helpers/hash/crc32.rs @@ -4,22 +4,22 @@ use crc32fast::Hasher; use crate::FileReader; -pub fn hash(file: &mut FileReader, offset: u64, size: u64, buffer_size: u64) -> u32 { +pub fn hash(file: &mut FileReader, offset: &u64, size: &u64, buffer_size: &u64) -> u32 { let pos_before = file.get_position(); file.seek(offset); let mut hasher = Hasher::new(); - let mut buf = vec![0; buffer_size as usize]; + let mut buf = vec![0; *buffer_size as usize]; - let mut remaining = size; + let mut remaining = *size; while remaining > 0 { - let to_read = min(buffer_size as u64, remaining) as usize; + let to_read = min(*buffer_size as u64, remaining) as usize; let read = file.read(&mut buf[..to_read]); hasher.update(&read); remaining -= to_read as u64; } - file.seek(pos_before); + file.seek(&pos_before); hasher.finalize() } diff --git a/src/types.rs b/src/types.rs index c82385d..9e497ba 100644 --- a/src/types.rs +++ b/src/types.rs @@ -3,13 +3,13 @@ use chrono::{DateTime, Utc}; use crate::FileReader; #[derive(Debug)] -pub struct ArchiveMetadata<'a> { - pub format: &'a str, +pub struct ArchiveMetadata { + pub format: &'static str, } #[derive(Debug)] pub struct ZipArchiveMetadata<'a> { - pub archive: ArchiveMetadata<'a>, + pub archive: ArchiveMetadata, pub files: Vec>, } @@ -40,7 +40,7 @@ pub struct File<'a> { pub size: u64, pub modified: DateTime, pub is_directory: bool, - pub source: &'a mut FileReader<'a>, + pub source: &'a mut FileReader, } #[derive(Debug)] diff --git a/tests/zip.rs b/tests/zip.rs index 55db37a..5c81c3a 100644 --- a/tests/zip.rs +++ b/tests/zip.rs @@ -2,7 +2,7 @@ use corelib::{self, helpers::hash::crc32, File, FileReader, FileWriter, ZipArchi #[test] fn sample_000() { - let mut file = FileReader::new("tests/samples/zip/000.zip"); + let mut file = FileReader::new(&"tests/samples/zip/000.zip".to_string()); let metadata = corelib::formats::zip::parser::metadata(&mut file); assert_eq!(metadata.files.len(), 1); @@ -14,7 +14,6 @@ fn sample_000() { metadata.files[0].file.modified.to_rfc3339(), "2024-07-11T18:14:42+00:00" ); - //println!("{:#?}", metadata); let test_txt = corelib::formats::zip::parser::get_file(&mut file, &metadata.files[0]); assert_eq!(String::from_utf8(test_txt).unwrap(), "Hello, world!\n"); @@ -22,13 +21,13 @@ fn sample_000() { assert!(corelib::formats::zip::parser::check_integrity( &mut file, &metadata.files[0], - 1024 + &1024 )); } #[test] fn sample_001() { - let mut file = FileReader::new("tests/samples/zip/001.zip"); + let mut file = FileReader::new(&"tests/samples/zip/001.zip".to_string()); let metadata = corelib::formats::zip::parser::metadata(&mut file); assert_eq!(metadata.files.len(), 2); @@ -56,7 +55,7 @@ fn sample_001() { std::fs::create_dir_all("tests/samples/zip/001").unwrap(); - corelib::formats::zip::parser::extract(&mut file, &metadata.files, 1024, &|path| { + corelib::formats::zip::parser::extract(&mut file, &metadata.files, &1024, &|path| { format!("tests/samples/zip/001/{}", path) }); @@ -76,18 +75,18 @@ fn sample_001() { assert!(corelib::formats::zip::parser::check_integrity( &mut file, &metadata.files[0], - 1024 + &1024 )); assert!(corelib::formats::zip::parser::check_integrity( &mut file, &metadata.files[1], - 1024 + &1024 )); } #[test] fn sample_002() { - let mut file = FileReader::new("tests/samples/zip/002.zip"); + let mut file = FileReader::new(&"tests/samples/zip/002.zip".to_string()); let metadata = corelib::formats::zip::parser::metadata(&mut file); assert_eq!(metadata.files.len(), 3); @@ -123,7 +122,7 @@ fn sample_002() { std::fs::create_dir_all("tests/samples/zip/002").unwrap(); - corelib::formats::zip::parser::extract(&mut file, &metadata.files, 1024, &|path| { + corelib::formats::zip::parser::extract(&mut file, &metadata.files, &1024, &|path| { format!("tests/samples/zip/002/{}", path) }); @@ -143,53 +142,53 @@ fn sample_002() { assert!(corelib::formats::zip::parser::check_integrity( &mut file, &metadata.files[0], - 1024 + &1024 )); assert!(corelib::formats::zip::parser::check_integrity( &mut file, &metadata.files[1], - 1024 + &1024 )); assert!(corelib::formats::zip::parser::check_integrity( &mut file, &metadata.files[2], - 1024 + &1024 )); } #[test] fn create_000() { - let mut output = FileWriter::new("tests/samples/zip/c000.zip", false); + let mut output = FileWriter::new(&"tests/samples/zip/c000.zip".to_string(), &false); std::fs::create_dir_all("tests/samples/zip/c000").unwrap(); - { - let mut test_txt = FileWriter::new("tests/samples/zip/c000/test.txt", false); - test_txt.write(b"Hello, world!\n"); - test_txt.close(); - - let mut input = FileReader::new("tests/samples/zip/c000/test.txt"); - let size = input.get_size(); - corelib::formats::zip::writer::write( - &mut output, - &mut ZipArchiveData { - files: vec![ZipFile { - checksum: crc32::hash(&mut input, 0, size, 1024), - file: File { - path: "test.txt".to_string(), - offset: 0, - size, - modified: input.get_times().modified, - is_directory: false, - source: &mut input, - }, - }], - }, - 1024, - ); - } // that test_txt dies here, that shit caused bugs as fuck + let mut test_txt = FileWriter::new(&"tests/samples/zip/c000/test.txt".to_string(), &false); + test_txt.write(b"Hello, world!\n"); + test_txt.close(); + + let mut input = FileReader::new(&"tests/samples/zip/c000/test.txt".to_string()); + let size = input.get_size(); + corelib::formats::zip::writer::write( + &mut output, + &mut ZipArchiveData { + files: vec![ZipFile { + checksum: crc32::hash(&mut input, &0, &size, &1024), + file: File { + path: "test.txt".to_string(), + offset: 0, + size, + modified: input.get_times().modified, + is_directory: false, + source: &mut input, + }, + }], + }, + &1024, + ); + input.close(); + output.close(); - let mut file = FileReader::new("tests/samples/zip/c000.zip"); + let mut file = FileReader::new(&"tests/samples/zip/c000.zip".to_string()); let metadata = corelib::formats::zip::parser::metadata(&mut file); assert_eq!(metadata.files.len(), 1); @@ -206,7 +205,7 @@ fn create_000() { assert!(corelib::formats::zip::parser::check_integrity( &mut file, &metadata.files[0], - 1024 + &1024 )); std::fs::remove_file("tests/samples/zip/c000.zip").unwrap();