From 51694e1f0b2730915e0a57ec6d8de503cf06ef9a Mon Sep 17 00:00:00 2001 From: Igor Tolmachev Date: Thu, 27 Jun 2024 16:15:00 +0900 Subject: Create file driver and implement file reader --- src/zip/file_driver.rs | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 src/zip/file_driver.rs (limited to 'src/zip/file_driver.rs') diff --git a/src/zip/file_driver.rs b/src/zip/file_driver.rs new file mode 100644 index 0000000..47b4242 --- /dev/null +++ b/src/zip/file_driver.rs @@ -0,0 +1,99 @@ +use crate::driver::FileDriver; +use crate::zip::{ZipError, ZipFileInfo, ZipResult}; +use std::io::{ + Error as IoError, ErrorKind as IoErrorKind, Read, Result as IoResult, Seek, SeekFrom, Take, + Write, +}; + +pub struct ZipFile<'d, Io> { + io: &'d mut Io, + info: &'d ZipFileInfo, + + bounds: (u64, u64), + cursor: u64, +} + +impl<'d, Io> FileDriver for ZipFile<'d, Io> { + type Io = Io; + type FileInfo = ZipFileInfo; + + fn info(&self) -> &Self::FileInfo { + self.info + } +} + +impl<'d, Io: Read + Seek> ZipFile<'d, Io> { + pub fn new(io: &'d mut Io, info: &'d ZipFileInfo) -> ZipResult { + io.seek(SeekFrom::Start(info.header_pointer))?; + let buf = { + let mut buf = [0; 30]; + io.read(&mut buf)?; + buf + }; + if u32::from_le_bytes(buf[..4].try_into().unwrap()) != 0x04034b50 { + return Err(ZipError::InvalidFileHeaderSignature.into()); + } + let data_pointer = info.header_pointer + + 30 + + u16::from_le_bytes(buf[26..28].try_into().unwrap()) as u64 + + u16::from_le_bytes(buf[28..30].try_into().unwrap()) as u64; + io.seek(SeekFrom::Start(data_pointer))?; + + Ok(Self { + io, + info, + + bounds: (data_pointer, data_pointer + info.compressed_size), + cursor: data_pointer, + }) + } +} + +impl<'d, Io: Read> Read for ZipFile<'d, Io> { + fn read(&mut self, buf: &mut [u8]) -> IoResult { + let upper = buf.len().min((self.bounds.1 - self.cursor) as usize); + self.cursor += upper as u64; + self.io.read(&mut buf[..upper]) + } +} + +impl<'d, Io: Write> Write for ZipFile<'d, Io> { + fn write(&mut self, buf: &[u8]) -> IoResult { + todo!() + } + + fn flush(&mut self) -> IoResult<()> { + todo!() + } +} + +impl<'d, Io: Seek> Seek for ZipFile<'d, Io> { + fn seek(&mut self, pos: SeekFrom) -> IoResult { + self.cursor = match pos { + SeekFrom::Start(offset) => self.bounds.0 + offset, + SeekFrom::End(offset) => { + let cursor = self.bounds.1.saturating_add_signed(offset); + if cursor < self.bounds.0 { + return Err(IoError::new( + IoErrorKind::InvalidInput, + ZipError::NegativeFileOffset, + )); + } + cursor + } + SeekFrom::Current(offset) => { + let cursor = self.cursor.saturating_add_signed(offset); + if cursor < self.bounds.0 { + return Err(IoError::new( + IoErrorKind::InvalidInput, + ZipError::NegativeFileOffset, + )); + } + cursor + } + } + .min(self.bounds.1); + + Ok(self.io.seek(SeekFrom::Start(self.cursor))? - self.bounds.0) + } +} -- cgit v1.2.3