From 614f55490e057ad67ae0cc241b3df604e7b633d6 Mon Sep 17 00:00:00 2001 From: Avi Weinstock Date: Sat, 26 Mar 2022 15:24:57 +0100 Subject: [PATCH 1/3] Add specification structures. --- src/read.rs | 73 ++++-------- src/spec.rs | 319 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/write.rs | 130 +++++++++------------ 3 files changed, 396 insertions(+), 126 deletions(-) diff --git a/src/read.rs b/src/read.rs index c619f24c0..d76a780ff 100644 --- a/src/read.rs +++ b/src/read.rs @@ -640,70 +640,43 @@ pub(crate) fn central_header_to_zip_file( archive_offset: u64, ) -> ZipResult { let central_header_start = reader.seek(io::SeekFrom::Current(0))?; - // Parse central header - let signature = reader.read_u32::()?; - if signature != spec::CENTRAL_DIRECTORY_HEADER_SIGNATURE { - return Err(ZipError::InvalidArchive("Invalid Central Directory header")); - } - - let version_made_by = reader.read_u16::()?; - let _version_to_extract = reader.read_u16::()?; - let flags = reader.read_u16::()?; - let encrypted = flags & 1 == 1; - let is_utf8 = flags & (1 << 11) != 0; - let using_data_descriptor = flags & (1 << 3) != 0; - let compression_method = reader.read_u16::()?; - let last_mod_time = reader.read_u16::()?; - let last_mod_date = reader.read_u16::()?; - let crc32 = reader.read_u32::()?; - let compressed_size = reader.read_u32::()?; - let uncompressed_size = reader.read_u32::()?; - let file_name_length = reader.read_u16::()? as usize; - let extra_field_length = reader.read_u16::()? as usize; - let file_comment_length = reader.read_u16::()? as usize; - let _disk_number = reader.read_u16::()?; - let _internal_file_attributes = reader.read_u16::()?; - let external_file_attributes = reader.read_u32::()?; - let offset = reader.read_u32::()? as u64; - let mut file_name_raw = vec![0; file_name_length]; - reader.read_exact(&mut file_name_raw)?; - let mut extra_field = vec![0; extra_field_length]; - reader.read_exact(&mut extra_field)?; - let mut file_comment_raw = vec![0; file_comment_length]; - reader.read_exact(&mut file_comment_raw)?; + let central_header = spec::CentralDirectoryHeader::parse(reader)?; - let file_name = match is_utf8 { - true => String::from_utf8_lossy(&*file_name_raw).into_owned(), - false => file_name_raw.clone().from_cp437(), + let file_name = match central_header.flags.is_utf8() { + true => String::from_utf8_lossy(&*central_header.file_name_raw).into_owned(), + false => central_header.file_name_raw.clone().from_cp437(), }; - let file_comment = match is_utf8 { - true => String::from_utf8_lossy(&*file_comment_raw).into_owned(), - false => file_comment_raw.from_cp437(), + let file_comment = match central_header.flags.is_utf8() { + true => String::from_utf8_lossy(&*central_header.file_comment_raw).into_owned(), + false => central_header.file_comment_raw.clone().from_cp437(), }; // Construct the result let mut result = ZipFileData { - system: System::from_u8((version_made_by >> 8) as u8), - version_made_by: version_made_by as u8, - encrypted, - using_data_descriptor, + system: System::from_u8((central_header.version_made_by >> 8) as u8), + version_made_by: central_header.version_made_by as u8, + encrypted: central_header.flags.encrypted(), + using_data_descriptor: central_header.flags.using_data_descriptor(), compression_method: { #[allow(deprecated)] - CompressionMethod::from_u16(compression_method) + CompressionMethod::from_u16(central_header.compression_method) }, compression_level: None, - last_modified_time: DateTime::from_msdos(last_mod_date, last_mod_time), - crc32, - compressed_size: compressed_size as u64, - uncompressed_size: uncompressed_size as u64, + last_modified_time: DateTime::from_msdos( + central_header.last_mod_date, + central_header.last_mod_time, + ), + crc32: central_header.crc32, + compressed_size: central_header.compressed_size as u64, + uncompressed_size: central_header.uncompressed_size as u64, file_name, - file_name_raw, - extra_field, + file_name_raw: central_header.file_name_raw, + extra_field: central_header.extra_field, file_comment, - header_start: offset, + header_start: central_header.offset as u64, central_header_start, data_start: AtomicU64::new(0), - external_attributes: external_file_attributes, + external_attributes: central_header.external_file_attributes, large_file: false, aes_mode: None, }; diff --git a/src/spec.rs b/src/spec.rs index 3ffcf7323..1f826b936 100644 --- a/src/spec.rs +++ b/src/spec.rs @@ -1,3 +1,4 @@ +#![allow(missing_docs, dead_code)] use crate::result::{ZipError, ZipResult}; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use std::io; @@ -8,10 +9,12 @@ pub const CENTRAL_DIRECTORY_HEADER_SIGNATURE: u32 = 0x02014b50; const CENTRAL_DIRECTORY_END_SIGNATURE: u32 = 0x06054b50; pub const ZIP64_CENTRAL_DIRECTORY_END_SIGNATURE: u32 = 0x06064b50; const ZIP64_CENTRAL_DIRECTORY_END_LOCATOR_SIGNATURE: u32 = 0x07064b50; +pub const DATA_DESCRIPTOR_SIGNATURE: u32 = 0x08074b50; pub const ZIP64_BYTES_THR: u64 = u32::MAX as u64; pub const ZIP64_ENTRY_THR: usize = u16::MAX as usize; +#[derive(Clone, Debug, PartialEq)] pub struct CentralDirectoryEnd { pub disk_number: u16, pub disk_with_central_directory: u16, @@ -23,6 +26,10 @@ pub struct CentralDirectoryEnd { } impl CentralDirectoryEnd { + pub fn len(&self) -> usize { + 22 + self.zip_file_comment.len() + } + pub fn parse(reader: &mut T) -> ZipResult { let magic = reader.read_u32::()?; if magic != CENTRAL_DIRECTORY_END_SIGNATURE { @@ -205,3 +212,315 @@ impl Zip64CentralDirectoryEnd { Ok(()) } } + +#[derive(Copy, Clone, Debug, PartialEq)] +pub struct GeneralPurposeBitFlags(pub u16); + +impl GeneralPurposeBitFlags { + #[inline] + pub fn encrypted(&self) -> bool { + self.0 & 1 == 1 + } + + #[inline] + pub fn is_utf8(&self) -> bool { + self.0 & (1 << 11) != 0 + } + + #[inline] + pub fn using_data_descriptor(&self) -> bool { + self.0 & (1 << 3) != 0 + } + + #[inline] + pub fn set_using_data_descriptor(&mut self, b: bool) { + self.0 &= !(1 << 3); + if b { + self.0 |= 1 << 3; + } + } +} + +#[derive(Clone, Debug, PartialEq)] +pub struct CentralDirectoryHeader { + pub version_made_by: u16, + pub version_to_extract: u16, + pub flags: GeneralPurposeBitFlags, + pub compression_method: u16, + pub last_mod_time: u16, + pub last_mod_date: u16, + pub crc32: u32, + pub compressed_size: u32, + pub uncompressed_size: u32, + pub disk_number: u16, + pub internal_file_attributes: u16, + pub external_file_attributes: u32, + pub offset: u32, + pub file_name_raw: Vec, + pub extra_field: Vec, + pub file_comment_raw: Vec, +} + +impl CentralDirectoryHeader { + pub fn len(&self) -> usize { + 46 + self.file_name_raw.len() + self.extra_field.len() + self.file_comment_raw.len() + } + pub fn parse(reader: &mut R) -> ZipResult { + let signature = reader.read_u32::()?; + if signature != CENTRAL_DIRECTORY_HEADER_SIGNATURE { + return Err(ZipError::InvalidArchive("Invalid Central Directory header")); + } + + let version_made_by = reader.read_u16::()?; + let version_to_extract = reader.read_u16::()?; + let flags = reader.read_u16::()?; + let compression_method = reader.read_u16::()?; + let last_mod_time = reader.read_u16::()?; + let last_mod_date = reader.read_u16::()?; + let crc32 = reader.read_u32::()?; + let compressed_size = reader.read_u32::()?; + let uncompressed_size = reader.read_u32::()?; + let file_name_length = reader.read_u16::()?; + let extra_field_length = reader.read_u16::()?; + let file_comment_length = reader.read_u16::()?; + let disk_number = reader.read_u16::()?; + let internal_file_attributes = reader.read_u16::()?; + let external_file_attributes = reader.read_u32::()?; + let offset = reader.read_u32::()?; + let mut file_name_raw = vec![0; file_name_length as usize]; + reader.read_exact(&mut file_name_raw)?; + let mut extra_field = vec![0; extra_field_length as usize]; + reader.read_exact(&mut extra_field)?; + let mut file_comment_raw = vec![0; file_comment_length as usize]; + reader.read_exact(&mut file_comment_raw)?; + + Ok(CentralDirectoryHeader { + version_made_by, + version_to_extract, + flags: GeneralPurposeBitFlags(flags), + compression_method, + last_mod_time, + last_mod_date, + crc32, + compressed_size, + uncompressed_size, + disk_number, + internal_file_attributes, + external_file_attributes, + offset, + file_name_raw, + extra_field, + file_comment_raw, + }) + } + + pub fn write(&self, writer: &mut T) -> ZipResult<()> { + writer.write_u32::(CENTRAL_DIRECTORY_HEADER_SIGNATURE)?; + writer.write_u16::(self.version_made_by)?; + writer.write_u16::(self.version_to_extract)?; + writer.write_u16::(self.flags.0)?; + writer.write_u16::(self.compression_method)?; + writer.write_u16::(self.last_mod_time)?; + writer.write_u16::(self.last_mod_date)?; + writer.write_u32::(self.crc32)?; + writer.write_u32::(self.compressed_size)?; + writer.write_u32::(self.uncompressed_size)?; + writer.write_u16::(self.file_name_raw.len() as u16)?; + writer.write_u16::(self.extra_field.len() as u16)?; + writer.write_u16::(self.file_comment_raw.len() as u16)?; + writer.write_u16::(self.disk_number)?; + writer.write_u16::(self.internal_file_attributes)?; + writer.write_u32::(self.external_file_attributes)?; + writer.write_u32::(self.offset)?; + writer.write_all(&self.file_name_raw)?; + writer.write_all(&self.extra_field)?; + writer.write_all(&self.file_comment_raw)?; + Ok(()) + } +} + +#[derive(Clone, Debug, PartialEq)] +pub struct LocalFileHeader { + pub version_to_extract: u16, + pub flags: GeneralPurposeBitFlags, + pub compression_method: u16, + pub last_mod_time: u16, + pub last_mod_date: u16, + pub crc32: u32, + pub compressed_size: u32, + pub uncompressed_size: u32, + pub file_name_raw: Vec, + pub extra_field: Vec, +} + +impl LocalFileHeader { + pub fn len(&self) -> usize { + 30 + self.file_name_raw.len() + self.extra_field.len() + } + + pub fn parse(reader: &mut R) -> ZipResult { + let signature = reader.read_u32::()?; + if signature != LOCAL_FILE_HEADER_SIGNATURE { + return Err(ZipError::InvalidArchive("Invalid local file header")); + } + + let version_to_extract = reader.read_u16::()?; + let flags = reader.read_u16::()?; + let compression_method = reader.read_u16::()?; + let last_mod_time = reader.read_u16::()?; + let last_mod_date = reader.read_u16::()?; + let crc32 = reader.read_u32::()?; + let compressed_size = reader.read_u32::()?; + let uncompressed_size = reader.read_u32::()?; + let file_name_length = reader.read_u16::()?; + let extra_field_length = reader.read_u16::()?; + + let mut file_name_raw = vec![0; file_name_length as usize]; + reader.read_exact(&mut file_name_raw)?; + let mut extra_field = vec![0; extra_field_length as usize]; + reader.read_exact(&mut extra_field)?; + + Ok(LocalFileHeader { + version_to_extract, + flags: GeneralPurposeBitFlags(flags), + compression_method, + last_mod_time, + last_mod_date, + crc32, + compressed_size, + uncompressed_size, + file_name_raw, + extra_field, + }) + } + + pub fn write(&self, writer: &mut T) -> ZipResult<()> { + writer.write_u32::(LOCAL_FILE_HEADER_SIGNATURE)?; + writer.write_u16::(self.version_to_extract)?; + writer.write_u16::(self.flags.0)?; + writer.write_u16::(self.compression_method)?; + writer.write_u16::(self.last_mod_time)?; + writer.write_u16::(self.last_mod_date)?; + writer.write_u32::(self.crc32)?; + writer.write_u32::(self.compressed_size)?; + writer.write_u32::(self.uncompressed_size)?; + writer.write_u16::(self.file_name_raw.len() as u16)?; + writer.write_u16::(self.extra_field.len() as u16)?; + writer.write_all(&self.file_name_raw)?; + writer.write_all(&self.extra_field)?; + Ok(()) + } +} + +#[derive(Copy, Clone, Debug, PartialEq)] +pub struct DataDescriptor { + pub crc32: u32, + pub compressed_size: u32, + pub uncompressed_size: u32, +} + +impl DataDescriptor { + pub fn read(reader: &mut T) -> ZipResult { + let first_word = reader.read_u32::()?; + let crc32 = if first_word == DATA_DESCRIPTOR_SIGNATURE { + reader.read_u32::()? + } else { + first_word + }; + let compressed_size = reader.read_u32::()?; + let uncompressed_size = reader.read_u32::()?; + Ok(DataDescriptor { + crc32, + compressed_size, + uncompressed_size, + }) + } + + pub fn write(&self, writer: &mut T) -> ZipResult<()> { + writer.write_u32::(DATA_DESCRIPTOR_SIGNATURE)?; + writer.write_u32::(self.crc32)?; + writer.write_u32::(self.compressed_size)?; + writer.write_u32::(self.uncompressed_size)?; + Ok(()) + } +} + +#[cfg(test)] +mod test { + use super::{ + CentralDirectoryHeader, DataDescriptor, GeneralPurposeBitFlags, LocalFileHeader, ZipResult, + }; + use std::io::Cursor; + #[test] + fn test_cdh_roundtrip() -> ZipResult<()> { + let cdh1 = CentralDirectoryHeader { + version_made_by: 1, + version_to_extract: 2, + flags: GeneralPurposeBitFlags(3), + compression_method: 4, + last_mod_time: 5, + last_mod_date: 6, + crc32: 7, + compressed_size: 8, + uncompressed_size: 9, + disk_number: 10, + internal_file_attributes: 11, + external_file_attributes: 12, + offset: 13, + file_name_raw: b"a".to_vec(), + extra_field: b"bb".to_vec(), + file_comment_raw: b"ccc".to_vec(), + }; + let mut bytes = Vec::new(); + { + let mut cursor = Cursor::new(&mut bytes); + cdh1.write(&mut cursor)?; + } + let cdh2 = CentralDirectoryHeader::parse(&mut &bytes[..])?; + assert_eq!(cdh1, cdh2); + Ok(()) + } + + #[test] + fn test_lfh_roundtrip() -> ZipResult<()> { + let lfh1 = LocalFileHeader { + version_to_extract: 1, + flags: GeneralPurposeBitFlags(2), + compression_method: 3, + last_mod_time: 4, + last_mod_date: 5, + crc32: 6, + compressed_size: 7, + uncompressed_size: 8, + file_name_raw: b"a".to_vec(), + extra_field: b"bb".to_vec(), + }; + let mut bytes = Vec::new(); + { + let mut cursor = Cursor::new(&mut bytes); + lfh1.write(&mut cursor)?; + } + let lfh2 = LocalFileHeader::parse(&mut &bytes[..])?; + assert_eq!(lfh1, lfh2); + Ok(()) + } + + #[test] + fn test_dd_roundtrip() -> ZipResult<()> { + let dd1 = DataDescriptor { + crc32: 1, + compressed_size: 2, + uncompressed_size: 3, + }; + let mut bytes = Vec::new(); + { + let mut cursor = Cursor::new(&mut bytes); + dd1.write(&mut cursor)?; + } + let dd2 = DataDescriptor::read(&mut &bytes[..])?; + assert_eq!(dd1, dd2); + let dd3 = DataDescriptor::read(&mut &bytes[4..])?; + assert_eq!(dd1, dd3); + Ok(()) + } +} diff --git a/src/write.rs b/src/write.rs index 3d0e01703..2e398b910 100644 --- a/src/write.rs +++ b/src/write.rs @@ -998,44 +998,38 @@ fn clamp_opt(value: T, range: RangeInclusive) -> Option { } fn write_local_file_header(writer: &mut T, file: &ZipFileData) -> ZipResult<()> { - // local file header signature - writer.write_u32::(spec::LOCAL_FILE_HEADER_SIGNATURE)?; - // version needed to extract - writer.write_u16::(file.version_needed())?; - // general purpose bit flag - let flag = if !file.file_name.is_ascii() { + let flags = if !file.file_name.is_ascii() { 1u16 << 11 } else { 0 }; - writer.write_u16::(flag)?; - // Compression method #[allow(deprecated)] - writer.write_u16::(file.compression_method.to_u16())?; - // last mod file time and last mod file date - writer.write_u16::(file.last_modified_time.timepart())?; - writer.write_u16::(file.last_modified_time.datepart())?; - // crc-32 - writer.write_u32::(file.crc32)?; - // compressed size and uncompressed size - if file.large_file { - writer.write_u32::(spec::ZIP64_BYTES_THR as u32)?; - writer.write_u32::(spec::ZIP64_BYTES_THR as u32)?; + let compression_method = file.compression_method.to_u16(); + let compressed_size = file.compressed_size.min(spec::ZIP64_BYTES_THR) as u32; + let uncompressed_size = file.uncompressed_size.min(spec::ZIP64_BYTES_THR) as u32; + + let mut extra_field = if file.large_file { + let mut zip64_extra_field = vec![0; 20]; + write_local_zip64_extra_field(&mut zip64_extra_field, file)?; + zip64_extra_field } else { - writer.write_u32::(file.compressed_size as u32)?; - writer.write_u32::(file.uncompressed_size as u32)?; - } - // file name length - writer.write_u16::(file.file_name.as_bytes().len() as u16)?; - // extra field length - let extra_field_length = if file.large_file { 20 } else { 0 } + file.extra_field.len() as u16; - writer.write_u16::(extra_field_length)?; - // file name - writer.write_all(file.file_name.as_bytes())?; - // zip64 extra field - if file.large_file { - write_local_zip64_extra_field(writer, file)?; - } + Vec::new() + }; + extra_field.extend_from_slice(&file.extra_field[..]); + + let local_file_header = spec::LocalFileHeader { + version_to_extract: file.version_needed(), + flags: spec::GeneralPurposeBitFlags(flags), + compression_method, + last_mod_time: file.last_modified_time.timepart(), + last_mod_date: file.last_modified_time.datepart(), + crc32: file.crc32, + compressed_size, + uncompressed_size, + file_name_raw: file.file_name.as_bytes().to_vec(), + extra_field, + }; + local_file_header.write(writer)?; Ok(()) } @@ -1070,56 +1064,40 @@ fn write_central_directory_header(writer: &mut T, file: &ZipFileData) let zip64_extra_field_length = write_central_zip64_extra_field(&mut zip64_extra_field.as_mut(), file)?; - // central file header signature - writer.write_u32::(spec::CENTRAL_DIRECTORY_HEADER_SIGNATURE)?; - // version made by - let version_made_by = (file.system as u16) << 8 | (file.version_made_by as u16); - writer.write_u16::(version_made_by)?; - // version needed to extract - writer.write_u16::(file.version_needed())?; - // general puprose bit flag - let flag = if !file.file_name.is_ascii() { + let flags = if !file.file_name.is_ascii() { 1u16 << 11 } else { 0 }; - writer.write_u16::(flag)?; - // compression method #[allow(deprecated)] - writer.write_u16::(file.compression_method.to_u16())?; - // last mod file time + date - writer.write_u16::(file.last_modified_time.timepart())?; - writer.write_u16::(file.last_modified_time.datepart())?; - // crc-32 - writer.write_u32::(file.crc32)?; - // compressed size - writer.write_u32::(file.compressed_size.min(spec::ZIP64_BYTES_THR) as u32)?; - // uncompressed size - writer.write_u32::(file.uncompressed_size.min(spec::ZIP64_BYTES_THR) as u32)?; - // file name length - writer.write_u16::(file.file_name.as_bytes().len() as u16)?; - // extra field length - writer.write_u16::(zip64_extra_field_length + file.extra_field.len() as u16)?; - // file comment length - writer.write_u16::(0)?; - // disk number start - writer.write_u16::(0)?; - // internal file attribytes - writer.write_u16::(0)?; - // external file attributes - writer.write_u32::(file.external_attributes)?; - // relative offset of local header - writer.write_u32::(file.header_start.min(spec::ZIP64_BYTES_THR) as u32)?; - // file name - writer.write_all(file.file_name.as_bytes())?; - // zip64 extra field - writer.write_all(&zip64_extra_field[..zip64_extra_field_length as usize])?; - // extra field - writer.write_all(&file.extra_field)?; - // file comment - // + let compression_method = file.compression_method.to_u16(); + let compressed_size = file.compressed_size.min(spec::ZIP64_BYTES_THR) as u32; + let uncompressed_size = file.uncompressed_size.min(spec::ZIP64_BYTES_THR) as u32; + let offset = file.header_start.min(spec::ZIP64_BYTES_THR) as u32; + + let mut extra_field = zip64_extra_field[..zip64_extra_field_length as usize].to_vec(); + extra_field.extend_from_slice(&file.extra_field[..]); + + let header = spec::CentralDirectoryHeader { + version_made_by: (file.system as u16) << 8 | (file.version_made_by as u16), + version_to_extract: file.version_needed(), + flags: spec::GeneralPurposeBitFlags(flags), + compression_method, + last_mod_time: file.last_modified_time.timepart(), + last_mod_date: file.last_modified_time.datepart(), + crc32: file.crc32, + compressed_size, + uncompressed_size, + disk_number: 0, + internal_file_attributes: 0, + external_file_attributes: file.external_attributes, + offset, + file_name_raw: file.file_name.as_bytes().to_vec(), + extra_field, + file_comment_raw: Vec::new(), + }; - Ok(()) + header.write(writer) } fn validate_extra_data(file: &ZipFileData) -> ZipResult<()> { From 2dc118c8f09adfeea05c514c22238db88595c0b6 Mon Sep 17 00:00:00 2001 From: Rouven Spreckels Date: Sat, 26 Mar 2022 15:31:02 +0100 Subject: [PATCH 2/3] Fix extra field. --- src/types.rs | 4 +--- src/write.rs | 16 ++++++++-------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/types.rs b/src/types.rs index ff4e24090..e31d15bc6 100644 --- a/src/types.rs +++ b/src/types.rs @@ -357,9 +357,7 @@ impl ZipFileData { } pub fn zip64_extension(&self) -> bool { - self.uncompressed_size > 0xFFFFFFFF - || self.compressed_size > 0xFFFFFFFF - || self.header_start > 0xFFFFFFFF + self.large_file || self.header_start > crate::spec::ZIP64_BYTES_THR } pub fn version_needed(&self) -> u16 { diff --git a/src/write.rs b/src/write.rs index 2e398b910..f0104b08c 100644 --- a/src/write.rs +++ b/src/write.rs @@ -1005,17 +1005,17 @@ fn write_local_file_header(writer: &mut T, file: &ZipFileData) -> ZipR }; #[allow(deprecated)] let compression_method = file.compression_method.to_u16(); - let compressed_size = file.compressed_size.min(spec::ZIP64_BYTES_THR) as u32; - let uncompressed_size = file.uncompressed_size.min(spec::ZIP64_BYTES_THR) as u32; - let mut extra_field = if file.large_file { - let mut zip64_extra_field = vec![0; 20]; - write_local_zip64_extra_field(&mut zip64_extra_field, file)?; - zip64_extra_field + let (compressed_size, uncompressed_size) = if file.large_file { + (spec::ZIP64_BYTES_THR as u32, spec::ZIP64_BYTES_THR as u32) } else { - Vec::new() + (file.compressed_size as u32, file.uncompressed_size as u32) }; - extra_field.extend_from_slice(&file.extra_field[..]); + let mut extra_field = Vec::new(); + if file.large_file { + extra_field.reserve(20); + write_local_zip64_extra_field(&mut extra_field, file)?; + } let local_file_header = spec::LocalFileHeader { version_to_extract: file.version_needed(), From 30aeaf275340ead5d5b1a71273d0b7cf68a6d1ce Mon Sep 17 00:00:00 2001 From: Chris Hennick <4961925+Pr0methean@users.noreply.github.com> Date: Wed, 1 May 2024 16:14:57 -0700 Subject: [PATCH 3/3] chore: WIP: fix merge --- src/read.rs | 8 +------- src/read/stream.rs | 4 ++-- src/write.rs | 6 ++++-- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/read.rs b/src/read.rs index 8027f0780..997dfdd69 100644 --- a/src/read.rs +++ b/src/read.rs @@ -770,13 +770,7 @@ pub(crate) fn central_header_to_zip_file( } /// Parse a central directory entry to collect the information for the file. -fn central_header_to_zip_file_inner( - reader: &mut R, - archive_offset: u64, - central_header_start: u64, -) -> ZipResult { -/// Parse a central directory entry to collect the information for the file. -fn central_header_to_zip_file_inner( +fn central_header_to_zip_file_inner( reader: &mut R, archive_offset: u64, central_header_start: u64, diff --git a/src/read/stream.rs b/src/read/stream.rs index f99a0e5a1..fc2cdb4bd 100644 --- a/src/read/stream.rs +++ b/src/read/stream.rs @@ -1,5 +1,5 @@ use std::fs; -use std::io::{self, Read}; +use std::io::{self, Read, Seek}; use std::path::{Path, PathBuf}; use super::{ @@ -20,7 +20,7 @@ impl ZipStreamReader { } } -impl ZipStreamReader { +impl ZipStreamReader { fn parse_central_directory(&mut self) -> ZipResult> { // Give archive_offset and central_header_start dummy value 0, since // they are not used in the output. diff --git a/src/write.rs b/src/write.rs index a75048caa..0cb00a4d2 100644 --- a/src/write.rs +++ b/src/write.rs @@ -1562,7 +1562,9 @@ fn write_central_directory_header(writer: &mut T, file: &ZipFileData) let offset = file.header_start.min(spec::ZIP64_BYTES_THR) as u32; let mut extra_field = zip64_extra_field[..zip64_extra_field_length as usize].to_vec(); - extra_field.extend_from_slice(&file.extra_field[..]); + if let Some(extra) = file.extra_field { + extra_field.extend_from_slice(extra); + } #[allow(deprecated)] writer.write_u16::(file.compression_method.to_u16())?; // last mod file time + date @@ -1609,7 +1611,7 @@ fn write_central_directory_header(writer: &mut T, file: &ZipFileData) let header = spec::CentralDirectoryHeader { version_made_by: (file.system as u16) << 8 | (file.version_made_by as u16), version_to_extract: file.version_needed(), - flags: spec::GeneralPurposeBitFlags(flags), + flags: spec::GeneralPurposeBitFlags(flag), compression_method, last_mod_time: file.last_modified_time.timepart(), last_mod_date: file.last_modified_time.datepart(),