use super::datatypes::*; use super::file::{FileInfo, FileReader, FileWriter}; use crate::io::{ArchiveRead, ArchiveWrite}; use crate::result::{ArchiveError, ArchiveResult}; use crate::utils::ReadHelper; use chrono::{NaiveDate, NaiveDateTime, NaiveTime}; use std::collections::HashMap; use std::fs::File; use std::io::Read; use std::io::{Seek, SeekFrom, Write}; pub struct Reader { reader: R, files: HashMap, comment: String, } impl ArchiveRead for Reader { type Reader = R; type FileInfo = FileInfo; type FileReader = FileReader; fn new(mut reader: Self::Reader) -> ArchiveResult { let cd_size: u64; let cd_offset: u64; let cd_entries: u64; let (eocd_offset, eocd, comment) = EndOfCentralDirectoryRecord::find(&mut reader)?; if let Some((eocd64_offset, eocd64, eocd64_extensible)) = Zip64EndOfCentralDirectoryRecord::find(&mut reader, eocd_offset)? { cd_size = eocd64.size_of_cd_records; cd_offset = eocd64.offset_of_cd_entries; cd_entries = eocd64.entries_in_cd; } else { cd_size = eocd.size_of_cd_records as u64; cd_offset = eocd.offset_of_cd_entries as u64; cd_entries = eocd.entries_in_cd as u64; } let mut buf = vec![0; cd_size as usize]; reader.seek(SeekFrom::Start(cd_offset))?; reader.read(&mut buf)?; let mut buf: &[u8] = &buf; let mut files = HashMap::with_capacity(cd_entries as usize); for entry_number in 0..cd_entries { let cd = CentralDirectoryRecord::read(&mut buf)?; let file_name = String::from_utf8(buf.read2vec(cd.file_name_length as usize)?).or( Err(ArchiveError::IncorrectString { location: "file_name", }), )?; let mut extra_field: &[u8] = &buf.read2vec(cd.extra_field_length as usize)?; let file_comment = String::from_utf8(buf.read2vec(cd.file_comment_length as usize)?) .or(Err(ArchiveError::IncorrectString { location: "file_comment", }))?; let mut uncompressed_size: u64 = cd.uncompressed_size as u64; let mut compressed_size: u64 = cd.compressed_size as u64; let mut header_offset: u64 = cd.header_offset as u64; while extra_field.len() > 0 { let header = u16::from_le_bytes(extra_field.read2buf()?); let size = u16::from_le_bytes(extra_field.read2buf()?); let mut data: &[u8] = &extra_field.read2vec(size as usize)?; match header { 0x0001 => { if uncompressed_size == 0xFFFFFFFF { uncompressed_size = u64::from_le_bytes(data.read2buf()?); } if compressed_size == 0xFFFFFFFF { compressed_size = u64::from_le_bytes(data.read2buf()?); } if header_offset == 0xFFFFFFFF { header_offset = u64::from_le_bytes(data.read2buf()?); } } _ => {} }; } let year = ((cd.last_mod_file_date >> 9) & 0x7F) + 1980; let month = (cd.last_mod_file_date >> 5) & 0xF; let day = cd.last_mod_file_date & 0x1F; let hour = (cd.last_mod_file_time >> 11) & 0x1F; let min = (cd.last_mod_file_time >> 5) & 0x3F; let sec = (cd.last_mod_file_time & 0x1F) * 2; files.insert( file_name.clone(), FileInfo::new( entry_number, cd.version_made_by, cd.version_needed, super::file::GeneralPurposeBitFlag {}, cd.compression_method.try_into()?, NaiveDateTime::new( NaiveDate::from_ymd_opt(year as i32, month as u32, day as u32) .ok_or(ArchiveError::IncorrectDate { year, month, day })?, NaiveTime::from_hms_opt(hour as u32, min as u32, sec as u32) .ok_or(ArchiveError::IncorrectTime { hour, min, sec })?, ), cd.crc32, compressed_size, uncompressed_size, file_name, file_comment, header_offset, ), ); } Ok(Self { reader, files, comment, }) } fn files(&self) -> ArchiveResult> { todo!() } fn open_file(&self, name: &str) -> ArchiveResult { todo!() } } impl Reader {} pub struct Writer { writer: W, } impl ArchiveWrite for Writer { type Writer = W; type FileInfo = FileInfo; type FileWriter = FileWriter; fn new(writer: Self::Writer) -> ArchiveResult { todo!() } fn create_file(&self, name: &str) -> ArchiveResult { todo!() } } impl Writer {}