diff --git a/Cargo.toml b/Cargo.toml index c9109eeb..4fadc85a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,3 +13,4 @@ Library to support the reading and writing of zip files. flate2 = "^0.2" bzip2 = "^0.2" time = "*" +podio = "^0.0" diff --git a/src/lib.rs b/src/lib.rs index 0adde68d..0fb6df0a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,6 +8,7 @@ extern crate time; extern crate flate2; extern crate bzip2; +extern crate podio; pub use read::ZipArchive; pub use write::ZipWriter; diff --git a/src/read.rs b/src/read.rs index 4e3845f7..9fa476cb 100644 --- a/src/read.rs +++ b/src/read.rs @@ -12,7 +12,7 @@ use flate2; use flate2::FlateReadExt; use bzip2::reader::BzDecompressor; use util; -use util::ReadIntExt; +use podio::{ReadPodExt, LittleEndian}; use types::ZipFileData; /// Wrapper for reading the contents of a ZIP file. @@ -171,30 +171,30 @@ impl ZipArchive fn central_header_to_zip_file(reader: &mut R) -> ZipResult { // Parse central header - let signature = try!(reader.read_le_u32()); + let signature = try!(reader.read_u32::()); if signature != spec::CENTRAL_DIRECTORY_HEADER_SIGNATURE { return Err(ZipError::InvalidArchive("Invalid Central Directory header")) } - try!(reader.read_le_u16()); - try!(reader.read_le_u16()); - let flags = try!(reader.read_le_u16()); + try!(reader.read_u16::()); + try!(reader.read_u16::()); + let flags = try!(reader.read_u16::()); let encrypted = flags & 1 == 1; let is_utf8 = flags & (1 << 11) != 0; - 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 usize; - let extra_field_length = try!(reader.read_le_u16()) as usize; - let file_comment_length = try!(reader.read_le_u16()) as usize; - try!(reader.read_le_u16()); - try!(reader.read_le_u16()); - try!(reader.read_le_u32()); - let offset = try!(reader.read_le_u32()) as u64; + let compression_method = try!(reader.read_u16::()); + let last_mod_time = try!(reader.read_u16::()); + let last_mod_date = try!(reader.read_u16::()); + let crc32 = try!(reader.read_u32::()); + let compressed_size = try!(reader.read_u32::()); + let uncompressed_size = try!(reader.read_u32::()); + let file_name_length = try!(reader.read_u16::()) as usize; + let extra_field_length = try!(reader.read_u16::()) as usize; + let file_comment_length = try!(reader.read_u16::()) as usize; + try!(reader.read_u16::()); + try!(reader.read_u16::()); + try!(reader.read_u32::()); + let offset = try!(reader.read_u32::()) as u64; let file_name_raw = try!(reader.read_exact(file_name_length)); let extra_field = try!(reader.read_exact(extra_field_length)); let file_comment_raw = try!(reader.read_exact(file_comment_length)); @@ -215,15 +215,15 @@ fn central_header_to_zip_file(reader: &mut R) -> ZipResult()); if signature != spec::LOCAL_FILE_HEADER_SIGNATURE { return Err(ZipError::InvalidArchive("Invalid local file header")) } try!(reader.seek(io::SeekFrom::Current(22))); - let file_name_length = try!(reader.read_le_u16()) as u64; - let extra_field_length = try!(reader.read_le_u16()) as u64; + let file_name_length = try!(reader.read_u16::()) as u64; + let extra_field_length = try!(reader.read_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; @@ -256,8 +256,8 @@ fn parse_extra_field(_file: &mut ZipFileData, data: &[u8]) -> ZipResult<()> while (reader.position() as usize) < data.len() { - let kind = try!(reader.read_le_u16()); - let len = try!(reader.read_le_u16()); + let kind = try!(reader.read_u16::()); + let len = try!(reader.read_u16::()); match kind { _ => try!(reader.seek(io::SeekFrom::Current(len as i64))), diff --git a/src/spec.rs b/src/spec.rs index 4c9f651f..dd3b812f 100644 --- a/src/spec.rs +++ b/src/spec.rs @@ -2,7 +2,7 @@ use std::io; use std::io::prelude::*; use result::{ZipResult, ZipError}; use std::iter::range_step_inclusive; -use util::{ReadIntExt, WriteIntExt}; +use podio::{ReadPodExt, WritePodExt, LittleEndian}; pub static LOCAL_FILE_HEADER_SIGNATURE : u32 = 0x04034b50; pub static CENTRAL_DIRECTORY_HEADER_SIGNATURE : u32 = 0x02014b50; @@ -23,18 +23,18 @@ impl CentralDirectoryEnd { pub fn parse(reader: &mut T) -> ZipResult { - let magic = try!(reader.read_le_u32()); + let magic = try!(reader.read_u32::()); if magic != CENTRAL_DIRECTORY_END_SIGNATURE { return Err(ZipError::InvalidArchive("Invalid digital signature header")) } - let disk_number = try!(reader.read_le_u16()); - let disk_with_central_directory = try!(reader.read_le_u16()); - let number_of_files_on_this_disk = try!(reader.read_le_u16()); - let number_of_files = try!(reader.read_le_u16()); - let central_directory_size = try!(reader.read_le_u32()); - let central_directory_offset = try!(reader.read_le_u32()); - let zip_file_comment_length = try!(reader.read_le_u16()) as usize; + let disk_number = try!(reader.read_u16::()); + let disk_with_central_directory = try!(reader.read_u16::()); + let number_of_files_on_this_disk = try!(reader.read_u16::()); + let number_of_files = try!(reader.read_u16::()); + let central_directory_size = try!(reader.read_u32::()); + let central_directory_offset = try!(reader.read_u32::()); + let zip_file_comment_length = try!(reader.read_u16::()) as usize; let zip_file_comment = try!(reader.read_exact(zip_file_comment_length)); Ok(CentralDirectoryEnd @@ -59,10 +59,10 @@ impl CentralDirectoryEnd for pos in range_step_inclusive(file_length - header_size, search_upper_bound, -1) { try!(reader.seek(io::SeekFrom::Start(pos as u64))); - if try!(reader.read_le_u32()) == CENTRAL_DIRECTORY_END_SIGNATURE + if try!(reader.read_u32::()) == CENTRAL_DIRECTORY_END_SIGNATURE { try!(reader.seek(io::SeekFrom::Current(bytes_between_magic_and_comment_size))); - let comment_length = try!(reader.read_le_u16()) as i64; + let comment_length = try!(reader.read_u16::()) as i64; if file_length - pos - header_size == comment_length { try!(reader.seek(io::SeekFrom::Start(pos as u64))); @@ -75,14 +75,14 @@ impl CentralDirectoryEnd pub fn write(&self, writer: &mut T) -> ZipResult<()> { - try!(writer.write_le_u32(CENTRAL_DIRECTORY_END_SIGNATURE)); - try!(writer.write_le_u16(self.disk_number)); - try!(writer.write_le_u16(self.disk_with_central_directory)); - try!(writer.write_le_u16(self.number_of_files_on_this_disk)); - try!(writer.write_le_u16(self.number_of_files)); - try!(writer.write_le_u32(self.central_directory_size)); - try!(writer.write_le_u32(self.central_directory_offset)); - try!(writer.write_le_u16(self.zip_file_comment.len() as u16)); + try!(writer.write_u32::(CENTRAL_DIRECTORY_END_SIGNATURE)); + try!(writer.write_u16::(self.disk_number)); + try!(writer.write_u16::(self.disk_with_central_directory)); + try!(writer.write_u16::(self.number_of_files_on_this_disk)); + try!(writer.write_u16::(self.number_of_files)); + try!(writer.write_u32::(self.central_directory_size)); + try!(writer.write_u32::(self.central_directory_offset)); + try!(writer.write_u16::(self.zip_file_comment.len() as u16)); try!(writer.write_all(self.zip_file_comment.as_slice())); Ok(()) } diff --git a/src/util.rs b/src/util.rs index a02e76e6..5697f989 100644 --- a/src/util.rs +++ b/src/util.rs @@ -40,82 +40,3 @@ pub fn tm_to_msdos_date(time: Tm) -> u16 { (time.tm_mday | ((time.tm_mon + 1) << 5) | ((time.tm_year - 80) << 9)) as u16 } - -/// Additional integer write methods for a io::Read -pub trait WriteIntExt { - /// Write a u32 in little-endian mode - fn write_le_u32(&mut self, u32) -> io::Result<()>; - /// Write a u16 in little-endian mode - fn write_le_u16(&mut self, u16) -> io::Result<()>; -} - -impl WriteIntExt for W { - fn write_le_u32(&mut self, val: u32) -> io::Result<()> { - let mut buf = [0u8; 4]; - let v = val; - buf[0] = ((v >> 0) & 0xFF) as u8; - buf[1] = ((v >> 8) & 0xFF) as u8; - buf[2] = ((v >> 16) & 0xFF) as u8; - buf[3] = ((v >> 24) & 0xFF) as u8; - self.write_all(&buf) - } - - fn write_le_u16(&mut self, val: u16) -> io::Result<()> { - let mut buf = [0u8; 2]; - let v = val; - buf[0] = ((v >> 0) & 0xFF) as u8; - buf[1] = ((v >> 8) & 0xFF) as u8; - self.write_all(&buf) - } -} -/// Additional integer write methods for a io::Read -pub trait ReadIntExt { - /// Read a u32 in little-endian mode - fn read_le_u32(&mut self) -> io::Result; - /// Read a u16 in little-endian mode - fn read_le_u16(&mut self) -> io::Result; - /// Read exactly n bytes - fn read_exact(&mut self, usize) -> io::Result>; -} - -fn fill_exact(reader: &mut R, buf: &mut [u8]) -> io::Result<()> { - let mut idx = 0; - while idx < buf.len() { - match reader.read(&mut buf[idx..]) { - Err(v) => return Err(v), - Ok(0) => return Err(io::Error::new(io::ErrorKind::ResourceUnavailable, "Could not fill the buffer", None)), - Ok(i) => idx += i, - } - } - Ok(()) -} - -impl ReadIntExt for R { - fn read_le_u32(&mut self) -> io::Result { - let mut buf = [0u8; 4]; - try!(fill_exact(self, &mut buf)); - - Ok( - buf[0] as u32 - | ((buf[1] as u32) << 8) - | ((buf[2] as u32) << 16) - | ((buf[3] as u32) << 24) - ) - } - - fn read_le_u16(&mut self) -> io::Result { - let mut buf = [0u8; 2]; - try!(fill_exact(self, &mut buf)); - - Ok( - buf[0] as u16 - | ((buf[1] as u16) << 8) - ) - } - - fn read_exact(&mut self, n: usize) -> io::Result> { - let mut res = vec![0u8; n]; - try!(fill_exact(self, &mut res)); - Ok(res) - } -} diff --git a/src/write.rs b/src/write.rs index 0772249c..906f909d 100644 --- a/src/write.rs +++ b/src/write.rs @@ -18,7 +18,7 @@ use flate2::write::DeflateEncoder; use bzip2; use bzip2::writer::BzCompressor; use util; -use util::WriteIntExt; +use podio::{WritePodExt, LittleEndian}; enum GenericZipWriter { @@ -285,19 +285,19 @@ impl GenericZipWriter fn write_local_file_header(writer: &mut T, file: &ZipFileData) -> ZipResult<()> { - try!(writer.write_le_u32(spec::LOCAL_FILE_HEADER_SIGNATURE)); - try!(writer.write_le_u16(20)); + try!(writer.write_u32::(spec::LOCAL_FILE_HEADER_SIGNATURE)); + try!(writer.write_u16::(20)); 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))); - try!(writer.write_le_u16(util::tm_to_msdos_date(file.last_modified_time))); - 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.as_bytes().len() as u16)); + try!(writer.write_u16::(flag)); + try!(writer.write_u16::(file.compression_method as u16)); + try!(writer.write_u16::(util::tm_to_msdos_time(file.last_modified_time))); + try!(writer.write_u16::(util::tm_to_msdos_date(file.last_modified_time))); + try!(writer.write_u32::(file.crc32)); + try!(writer.write_u32::(file.compressed_size as u32)); + try!(writer.write_u32::(file.uncompressed_size as u32)); + try!(writer.write_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_u16::(extra_field.len() as u16)); try!(writer.write_all(file.file_name.as_bytes())); try!(writer.write_all(extra_field.as_slice())); @@ -308,33 +308,33 @@ fn update_local_file_header(writer: &mut T, file: &ZipFileDat { static CRC32_OFFSET : u64 = 14; try!(writer.seek(io::SeekFrom::Start(file.header_start + CRC32_OFFSET))); - 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_u32::(file.crc32)); + try!(writer.write_u32::(file.compressed_size as u32)); + try!(writer.write_u32::(file.uncompressed_size as u32)); Ok(()) } fn write_central_directory_header(writer: &mut T, file: &ZipFileData) -> ZipResult<()> { - try!(writer.write_le_u32(spec::CENTRAL_DIRECTORY_HEADER_SIGNATURE)); - try!(writer.write_le_u16(0x14FF)); - try!(writer.write_le_u16(20)); + try!(writer.write_u32::(spec::CENTRAL_DIRECTORY_HEADER_SIGNATURE)); + try!(writer.write_u16::(0x14FF)); + try!(writer.write_u16::(20)); 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))); - try!(writer.write_le_u16(util::tm_to_msdos_date(file.last_modified_time))); - 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.as_bytes().len() as u16)); + try!(writer.write_u16::(flag)); + try!(writer.write_u16::(file.compression_method as u16)); + try!(writer.write_u16::(util::tm_to_msdos_time(file.last_modified_time))); + try!(writer.write_u16::(util::tm_to_msdos_date(file.last_modified_time))); + try!(writer.write_u32::(file.crc32)); + try!(writer.write_u32::(file.compressed_size as u32)); + try!(writer.write_u32::(file.uncompressed_size as u32)); + try!(writer.write_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_u16::(extra_field.len() as u16)); + try!(writer.write_u16::(0)); + try!(writer.write_u16::(0)); + try!(writer.write_u16::(0)); + try!(writer.write_u32::(0)); + try!(writer.write_u32::(file.header_start as u32)); try!(writer.write_all(file.file_name.as_bytes())); try!(writer.write_all(extra_field.as_slice()));