From 7df03b54f99e3ec2288e83ec4c7a8bea06e5bf09 Mon Sep 17 00:00:00 2001 From: Mathijs van de Nes Date: Wed, 10 Sep 2014 17:27:24 +0200 Subject: [PATCH] Removed some unneeded structs and simplified parse --- src/bin/extract.rs | 2 + src/reader.rs | 32 +------ src/spec.rs | 218 ++++++++++++++------------------------------- src/types.rs | 5 ++ 4 files changed, 73 insertions(+), 184 deletions(-) diff --git a/src/bin/extract.rs b/src/bin/extract.rs index d4b80afb..e84f4054 100644 --- a/src/bin/extract.rs +++ b/src/bin/extract.rs @@ -11,6 +11,8 @@ fn main() for file in zipcontainer.files() { println!("{}", file.file_name_string()); + let comment = file.file_comment_string(); + if comment.len() > 0 { println!(" File comment: {}", comment); } if file.uncompressed_size == 0 { continue } diff --git a/src/reader.rs b/src/reader.rs index 2cd7a2c7..9e413728 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -39,42 +39,12 @@ impl ZipReader try!(reader.seek(directory_start, io::SeekSet)); for i in range(0, number_of_files) { - files.push(try!(ZipReader::parse_directory(&mut reader))); + files.push(try!(spec::central_header_to_zip_file(&mut reader))); } Ok(ZipReader { inner: RefCell::new(reader), files: files }) } - fn parse_directory(reader: &mut T) -> IoResult - { - let cdh = try!(spec::CentralDirectoryHeader::parse(reader)); - // Remember position - let pos = try!(reader.tell()) as i64; - let result = ZipReader::parse_file(reader, cdh); - // Jump back for next directory - try!(reader.seek(pos, io::SeekSet)); - result - } - - fn parse_file(reader: &mut T, central: spec::CentralDirectoryHeader) -> IoResult - { - try!(reader.seek(central.file_offset as i64, io::SeekSet)); - let local = try!(spec::LocalFileHeader::parse(reader)); - - Ok(ZipFile - { - encrypted: central.encrypted, - compression_method: central.compression_method, - last_modified_time: central.last_modified_time, - crc32: central.crc32, - compressed_size: central.compressed_size as u64, - uncompressed_size: central.uncompressed_size as u64, - file_name: central.file_name.clone(), - file_comment: central.file_comment.clone(), - data_start: local.header_end, - }) - } - pub fn files(&self) -> ::std::slice::Items { self.files.as_slice().iter() diff --git a/src/spec.rs b/src/spec.rs index 9dd86056..5c943c84 100644 --- a/src/spec.rs +++ b/src/spec.rs @@ -1,174 +1,85 @@ use std::io; use std::io::{IoResult, IoError}; use std::iter::range_step_inclusive; -use time::Tm; use types; +use types::ZipFile; use util; static LOCAL_FILE_HEADER_SIGNATURE : u32 = 0x04034b50; static CENTRAL_DIRECTORY_HEADER_SIGNATURE : u32 = 0x02014b50; static CENTRAL_DIRECTORY_END_SIGNATURE : u32 = 0x06054b50; -pub struct LocalFileHeader +pub fn central_header_to_zip_file(reader: &mut R) -> IoResult { - pub extract_version: u16, - - // general purpose flags - pub encrypted: bool, // bit 0 - // bit 1 & 2 unused - pub has_descriptor: bool, // bit 3 - // bit 4 unused - pub is_compressed_patch: bool, // bit 5 - pub strong_encryption: bool, // bit 6 - // bit 7 - 10 unused - pub is_utf8: bool, // bit 11 - // bit 12 unused - pub is_masked: bool, // bit 13 - // bit 14 & 15 unused - - pub compression_method: types::CompressionMethod, - pub last_modified: Tm, - pub crc32: u32, - pub compressed_size: u32, - pub uncompressed_size: u32, - pub file_name: Vec, - pub extra_field: Vec, - pub header_end: u64, -} - - -impl LocalFileHeader -{ - pub fn parse(reader: &mut T) -> IoResult + // Parse central header + let signature = try!(reader.read_le_u32()); + if signature != CENTRAL_DIRECTORY_HEADER_SIGNATURE { - let signature = try!(reader.read_le_u32()); - if signature != LOCAL_FILE_HEADER_SIGNATURE - { - return Err(IoError { - kind: io::MismatchedFileTypeForOperation, - desc: "Invalid local file header", - detail: None }) - } - let version = try!(reader.read_le_u16()); - let flags = try!(reader.read_le_u16()); - let compression_method = try!(reader.read_le_u16()); - let last_mod_time = try!(reader.read_le_u16()); - let last_mod_date = try!(reader.read_le_u16()); - let crc = try!(reader.read_le_u32()); - let compressed_size = try!(reader.read_le_u32()); - let uncompressed_size = try!(reader.read_le_u32()); - let file_name_length = try!(reader.read_le_u16()); - let extra_field_length = try!(reader.read_le_u16()); - let file_name = try!(reader.read_exact(file_name_length as uint)); - let extra_field = try!(reader.read_exact(extra_field_length as uint)); - let header_end = try!(reader.tell()); - - Ok(LocalFileHeader - { - extract_version: version, - encrypted: (flags & (1 << 0)) != 0, - has_descriptor: (flags & (1 << 3)) != 0, - is_compressed_patch: (flags & (1 << 5)) != 0, - strong_encryption: (flags & (1 << 6)) != 0, - is_utf8: (flags & (1 << 11)) != 0, - is_masked: (flags & (1 << 13)) != 0, - compression_method: FromPrimitive::from_u16(compression_method).unwrap_or(types::Unknown), - last_modified: util::msdos_datetime_to_tm(last_mod_time, last_mod_date), - crc32: crc, - compressed_size: compressed_size, - uncompressed_size: uncompressed_size, - file_name: file_name, - extra_field: extra_field, - header_end: header_end, - }) + return Err(IoError { + kind: io::MismatchedFileTypeForOperation, + desc: "Invalid central directory header", + detail: None }) } -} -pub struct CentralDirectoryHeader -{ - pub made_by: u16, - pub version_needed: u16, + try!(reader.read_le_u16()); + try!(reader.read_le_u16()); + let flags = try!(reader.read_le_u16()); + let encrypted = flags & 1 == 1; + let compression_method = try!(reader.read_le_u16()); + let last_mod_time = try!(reader.read_le_u16()); + let last_mod_date = try!(reader.read_le_u16()); + let crc32 = try!(reader.read_le_u32()); + let compressed_size = try!(reader.read_le_u32()); + let uncompressed_size = try!(reader.read_le_u32()); + let file_name_length = try!(reader.read_le_u16()) as uint; + let extra_field_length = try!(reader.read_le_u16()) as uint; + let file_comment_length = try!(reader.read_le_u16()) as uint; + try!(reader.read_le_u16()); + try!(reader.read_le_u16()); + try!(reader.read_le_u32()); + let offset = try!(reader.read_le_u32()) as i64; + let file_name = try!(reader.read_exact(file_name_length)); + try!(reader.read_exact(extra_field_length)); + let file_comment = try!(reader.read_exact(file_comment_length)); - // general purpose flags - pub encrypted: bool, // bit 0 - // bit 1 & 2 unused - pub has_descriptor: bool, // bit 3 - // bit 4 unused - pub is_compressed_patch: bool, // bit 5 - pub strong_encryption: bool, // bit 6 - // bit 7 - 10 unused - pub is_utf8: bool, // bit 11 - // bit 12 unused - pub is_masked: bool, // bit 13 - // bit 14 & 15 unused + // Remember end of central header + let return_position = try!(reader.tell()) as i64; - pub compression_method: types::CompressionMethod, - pub last_modified_time: Tm, - pub crc32: u32, - pub compressed_size: u32, - pub uncompressed_size: u32, - pub file_name: Vec, - pub extra_field: Vec, - pub file_comment: Vec, - pub disk_number: u16, - pub file_offset: u32, -} - -impl CentralDirectoryHeader -{ - pub fn parse(reader: &mut T) -> IoResult + // Parse local header + try!(reader.seek(offset, io::SeekSet)); + let signature = try!(reader.read_le_u32()); + if signature != LOCAL_FILE_HEADER_SIGNATURE { - let signature = try!(reader.read_le_u32()); - if signature != CENTRAL_DIRECTORY_HEADER_SIGNATURE - { - return Err(IoError { - kind: io::MismatchedFileTypeForOperation, - desc: "Invalid central directory header", - detail: None }) - } - - let made_by = try!(reader.read_le_u16()); - let version_needed = try!(reader.read_le_u16()); - let flags = try!(reader.read_le_u16()); - let compression = try!(reader.read_le_u16()); - let last_mod_time = try!(reader.read_le_u16()); - let last_mod_date = try!(reader.read_le_u16()); - let crc = try!(reader.read_le_u32()); - let compressed_size = try!(reader.read_le_u32()); - let uncompressed_size = try!(reader.read_le_u32()); - let file_name_length = try!(reader.read_le_u16()) as uint; - let extra_field_length = try!(reader.read_le_u16()) as uint; - let file_comment_length = try!(reader.read_le_u16()) as uint; - let disk_number = try!(reader.read_le_u16()); - try!(reader.read_le_u16()); // internal file attribute - try!(reader.read_le_u32()); // external file attribute - let offset = try!(reader.read_le_u32()); - let file_name = try!(reader.read_exact(file_name_length)); - let extra_field = try!(reader.read_exact(extra_field_length)); - let file_comment = try!(reader.read_exact(file_comment_length)); - - Ok(CentralDirectoryHeader - { - made_by: made_by, - version_needed: version_needed, - encrypted: flags & (1 << 0) != 0, - has_descriptor: flags & (1 << 3) != 0, - is_compressed_patch: flags & (1 << 5) != 0, - strong_encryption: flags & (1 << 6) != 0, - is_utf8: flags & (1 << 11) != 0, - is_masked: flags & (1 << 13) != 0, - compression_method: FromPrimitive::from_u16(compression).unwrap_or(types::Unknown), - last_modified_time: util::msdos_datetime_to_tm(last_mod_time, last_mod_date), - crc32: crc, - compressed_size: compressed_size, - uncompressed_size: uncompressed_size, - file_name: file_name, - extra_field: extra_field, - file_comment: file_comment, - disk_number: disk_number, - file_offset: offset, - }) + return Err(IoError { + kind: io::MismatchedFileTypeForOperation, + desc: "Invalid local file header", + detail: None }) } + + try!(reader.seek(22, io::SeekCur)); + let file_name_length = try!(reader.read_le_u16()) as u64; + let extra_field_length = try!(reader.read_le_u16()) as u64; + let magic_and_header = 4 + 22 + 2 + 2; + let data_start = offset as u64 + magic_and_header + file_name_length + extra_field_length; + + // Construct the result + let result = ZipFile + { + encrypted: encrypted, + compression_method: FromPrimitive::from_u16(compression_method).unwrap_or(types::Unknown), + last_modified_time: util::msdos_datetime_to_tm(last_mod_time, last_mod_date), + crc32: crc32, + compressed_size: compressed_size as u64, + uncompressed_size: uncompressed_size as u64, + file_name: file_name, + file_comment: file_comment, + data_start: data_start, + }; + + // Go back after the central header + try!(reader.seek(return_position, io::SeekSet)); + + Ok(result) } pub struct CentralDirectoryEnd @@ -214,6 +125,7 @@ impl CentralDirectoryEnd zip_file_comment: zip_file_comment, }) } + pub fn find_and_parse(reader: &mut T) -> IoResult { let header_size = 22; diff --git a/src/types.rs b/src/types.rs index 71e967a5..013be7ac 100644 --- a/src/types.rs +++ b/src/types.rs @@ -42,4 +42,9 @@ impl ZipFile { String::from_utf8_lossy(self.file_name.as_slice()).into_string() } + + pub fn file_comment_string(&self) -> String + { + String::from_utf8_lossy(self.file_comment.as_slice()).into_string() + } }