From 8921d3b5c2a53df8701fc7f2acc415f9d594ce4f Mon Sep 17 00:00:00 2001 From: Mathijs van de Nes Date: Sun, 14 Sep 2014 21:55:02 +0200 Subject: [PATCH] Added support for extra field and utf-8 filenames --- src/bin/write_sample.rs | 2 +- src/cp437.rs | 1 + src/spec.rs | 51 ++++++++++++++++++++++++++++++++--------- src/writer.rs | 21 ++++++++++------- 4 files changed, 55 insertions(+), 20 deletions(-) diff --git a/src/bin/write_sample.rs b/src/bin/write_sample.rs index 5b6b35fe..d692f0a1 100644 --- a/src/bin/write_sample.rs +++ b/src/bin/write_sample.rs @@ -18,7 +18,7 @@ fn doit(filename: &str) -> std::io::IoResult<()> let mut zip = zip::ZipWriter::new(file); - try!(zip.start_file("test/hello_world.txt", zip::types::Stored)); + try!(zip.start_file("test/☃.txt", zip::types::Stored)); try!(zip.write(b"Hello, World!\n")); try!(zip.start_file("test/lorem_ipsum.txt", zip::types::Deflated)); diff --git a/src/cp437.rs b/src/cp437.rs index 293be64f..363d622a 100644 --- a/src/cp437.rs +++ b/src/cp437.rs @@ -5,6 +5,7 @@ pub fn to_string(input: &[u8]) -> String input.iter().map(|c| to_char(*c)).collect() } +#[allow(dead_code)] pub fn from_string(input: &str) -> Vec { input.chars().map(|c| from_char(c)).collect() diff --git a/src/spec.rs b/src/spec.rs index 5bbed312..735cc729 100644 --- a/src/spec.rs +++ b/src/spec.rs @@ -40,7 +40,7 @@ pub fn central_header_to_zip_file(reader: &mut R) -> IoResult(reader: &mut R) -> IoResult(reader: &mut R) -> IoResult IoResult<()> +{ + let mut reader = io::BufReader::new(data); + while !reader.eof() + { + let kind = try!(reader.read_le_u16()); + let len = try!(reader.read_le_u16()); + debug!("Parsing extra block {:04x}", kind); + match kind + { + _ => try!(reader.seek(len as i64, io::SeekCur)), + } + } + Ok(()) +} + pub fn write_local_file_header(writer: &mut T, file: &ZipFile) -> IoResult<()> { try!(writer.write_le_u32(LOCAL_FILE_HEADER_SIGNATURE)); try!(writer.write_le_u16(20)); - let flag = if file.encrypted { 1 } else { 0 }; + let flag = if !file.file_name.is_ascii() { 1u16 << 11 } else { 0 }; try!(writer.write_le_u16(flag)); try!(writer.write_le_u16(file.compression_method as u16)); try!(writer.write_le_u16(util::tm_to_msdos_time(file.last_modified_time))); @@ -107,9 +125,11 @@ pub fn write_local_file_header(writer: &mut T, file: &ZipFile) -> IoR try!(writer.write_le_u32(file.crc32)); try!(writer.write_le_u32(file.compressed_size as u32)); try!(writer.write_le_u32(file.uncompressed_size as u32)); - try!(writer.write_le_u16(file.file_name.len() as u16)); - try!(writer.write_le_u16(0)); - try!(writer.write(::cp437::from_string(file.file_name.as_slice()).as_slice())); + try!(writer.write_le_u16(file.file_name.as_bytes().len() as u16)); + let extra_field = try!(build_extra_field(file)); + try!(writer.write_le_u16(extra_field.len() as u16)); + try!(writer.write(file.file_name.as_bytes())); + try!(writer.write(extra_field.as_slice())); Ok(()) } @@ -117,9 +137,9 @@ pub fn write_local_file_header(writer: &mut T, file: &ZipFile) -> IoR pub fn write_central_directory_header(writer: &mut T, file: &ZipFile) -> IoResult<()> { try!(writer.write_le_u32(CENTRAL_DIRECTORY_HEADER_SIGNATURE)); - try!(writer.write_le_u16(0x00FF)); + try!(writer.write_le_u16(0x14FF)); try!(writer.write_le_u16(20)); - let flag = if file.encrypted { 1 } else { 0 }; + let flag = if !file.file_name.is_ascii() { 1u16 << 11 } else { 0 }; try!(writer.write_le_u16(flag)); try!(writer.write_le_u16(file.compression_method as u16)); try!(writer.write_le_u16(util::tm_to_msdos_time(file.last_modified_time))); @@ -127,18 +147,27 @@ pub fn write_central_directory_header(writer: &mut T, file: &ZipFile) try!(writer.write_le_u32(file.crc32)); try!(writer.write_le_u32(file.compressed_size as u32)); try!(writer.write_le_u32(file.uncompressed_size as u32)); - try!(writer.write_le_u16(file.file_name.len() as u16)); - try!(writer.write_le_u16(0)); + try!(writer.write_le_u16(file.file_name.as_bytes().len() as u16)); + let extra_field = try!(build_extra_field(file)); + try!(writer.write_le_u16(extra_field.len() as u16)); try!(writer.write_le_u16(0)); try!(writer.write_le_u16(0)); try!(writer.write_le_u16(0)); try!(writer.write_le_u32(0)); try!(writer.write_le_u32(file.header_start as u32)); - try!(writer.write(::cp437::from_string(file.file_name.as_slice()).as_slice())); + try!(writer.write(file.file_name.as_bytes())); + try!(writer.write(extra_field.as_slice())); Ok(()) } +fn build_extra_field(_file: &ZipFile) -> IoResult> +{ + let writer = io::MemWriter::new(); + // Future work + Ok(writer.unwrap()) +} + pub struct CentralDirectoryEnd { pub disk_number: u16, diff --git a/src/writer.rs b/src/writer.rs index a335aa57..d4f5d1f7 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -106,13 +106,8 @@ impl ZipWriter { let writer = self.inner.get_plain(); let header_start = try!(writer.tell()); - try!(writer.seek(30 + name.len() as i64, io::SeekCur)); - self.stats.start = header_start + 30 + name.len() as u64; - self.stats.bytes_written = 0; - self.stats.crc32 = 0; - - self.files.push(ZipFile + let mut file = ZipFile { encrypted: false, compression_method: compression, @@ -123,8 +118,18 @@ impl ZipWriter file_name: String::from_str(name), file_comment: String::new(), header_start: header_start, - data_start: self.stats.start, - }); + data_start: 0, + }; + try!(spec::write_local_file_header(writer, &file)); + + let header_end = try!(writer.tell()); + self.stats.start = header_end; + file.data_start = header_end; + + self.stats.bytes_written = 0; + self.stats.crc32 = 0; + + self.files.push(file); } try!(self.inner.switch_to(compression));