From 1cbc1e9e6a0ede53b511d4d510b673d4edfc3a38 Mon Sep 17 00:00:00 2001 From: Mathijs van de Nes Date: Mon, 8 Sep 2014 20:14:22 +0000 Subject: [PATCH] Lots of additions --- src/bin/parse_head.rs | 10 ++- src/spec.rs | 182 +++++++++++++++++++++++++++++++++++++----- 2 files changed, 167 insertions(+), 25 deletions(-) diff --git a/src/bin/parse_head.rs b/src/bin/parse_head.rs index 30e27182..271d8ff0 100644 --- a/src/bin/parse_head.rs +++ b/src/bin/parse_head.rs @@ -2,8 +2,12 @@ extern crate zip; fn main() { - let mut stdin = std::io::stdin(); - let header = zip::spec::LocalFileHeader::parse(&mut stdin).unwrap(); + let args = std::os::args(); + let fname = Path::new(args[1].as_slice()); + let mut file = std::io::File::open(&fname); + + let header = zip::spec::LocalFileHeader::parse(&mut file).unwrap(); println!("{}", header); - println!("{}", String::from_utf8(header.file_name)); + println!("{:x}", header.crc32); + println!("{}", String::from_utf8(header.file_name.clone())); } diff --git a/src/spec.rs b/src/spec.rs index a0b72c77..0decf524 100644 --- a/src/spec.rs +++ b/src/spec.rs @@ -3,24 +3,10 @@ use std::io::{IoResult, IoError}; use time::Tm; use util; -/* - 4.3.7 Local file header: - - local file header signature 4 bytes (0x04034b50) - version needed to extract 2 bytes - general purpose bit flag 2 bytes - compression method 2 bytes - last mod file time 2 bytes - last mod file date 2 bytes - crc-32 4 bytes - compressed size 4 bytes - uncompressed size 4 bytes - file name length 2 bytes - extra field length 2 bytes - - file name (variable size) - extra field (variable size) -*/ +static LOCAL_FILE_HEADER_SIGNATURE : u32 = 0x04034b50; +static DATA_DESCRIPTOR_SIGNATURE : u32 = 0x08074b50; +static CENTRAL_DIRECTORY_HEADER_SIGNATURE : u32 = 0x02014b50; +static DIGITAL_SIGNATURE_SIGNATURE : u32 = 0x05054b50; #[deriving(FromPrimitive, Show)] pub enum CompressionMethod @@ -64,20 +50,27 @@ pub struct LocalFileHeader compression_method: CompressionMethod, last_modified: Tm, - crc32: u32, + pub crc32: u32, compressed_size: u32, uncompressed_size: u32, pub file_name: Vec, extra_field: Vec, + header_end: u64, } impl LocalFileHeader { - pub fn parse(reader: &mut T) -> IoResult + pub fn parse(reader: &mut T) -> IoResult { - let magic = try!(reader.read_le_u32()); - if magic != 0x04034b50 { return Err(IoError { kind: io::MismatchedFileTypeForOperation, desc: "Invalid local file header", detail: None }) } + 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()); @@ -90,6 +83,7 @@ impl LocalFileHeader 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 { @@ -107,6 +101,150 @@ impl LocalFileHeader uncompressed_size: uncompressed_size, file_name: file_name, extra_field: extra_field, + header_end: header_end, }) } } + +struct DataDescriptor +{ + compressed_size: u32, + uncompressed_size: u32, + crc32: u32, +} + +impl DataDescriptor +{ + pub fn parse(reader: &mut T) -> IoResult + { + let first = try!(reader.read_le_u32()); + let compressed = if first == DATA_DESCRIPTOR_SIGNATURE + { + try!(reader.read_le_u32()) + } + else + { + first + }; + + let uncompressed = try!(reader.read_le_u32()); + let crc = try!(reader.read_le_u32()); + + Ok(DataDescriptor + { + compressed_size: compressed, + uncompressed_size: uncompressed, + crc32: crc, + }) + } +} + +struct CentralDirectoryHeader +{ + made_by: u16, + version_needed: u16, + + // general purpose flags + encrypted: bool, // bit 0 + // bit 1 & 2 unused + has_descriptor: bool, // bit 3 + // bit 4 unused + is_compressed_patch: bool, // bit 5 + strong_encryption: bool, // bit 6 + // bit 7 - 10 unused + is_utf8: bool, // bit 11 + // bit 12 unused + is_masked: bool, // bit 13 + // bit 14 & 15 unused + + compression_method: CompressionMethod, + last_modified_time: Tm, + crc32: u32, + compressed_size: u32, + uncompressed_size: u32, + file_name: Vec, + extra_field: Vec, + file_comment: Vec, + disk_number: u16, + file_offset: u32, +} + +impl CentralDirectoryHeader +{ + pub fn parse(reader: &mut T) -> IoResult + { + 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(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, + }) + } +} + +struct DigitalSignature +{ + data: Vec, +} + +impl DigitalSignature +{ + pub fn parse(reader: &mut T) -> IoResult + { + let magic = try!(reader.read_le_u32()); + if magic != DIGITAL_SIGNATURE_SIGNATURE + { + return Err(IoError { + kind: io::MismatchedFileTypeForOperation, + desc: "Invalid digital signature header", + detail: None }) + } + let size = try!(reader.read_le_u16()) as uint; + let data = try!(reader.read_exact(size)); + Ok(DigitalSignature { data: data }) + } +}