diff --git a/src/crc32.rs b/src/crc32.rs index 26e64037..8f7503c8 100644 --- a/src/crc32.rs +++ b/src/crc32.rs @@ -1,6 +1,7 @@ //! Helper module to compute a CRC32 checksum -use std::old_io; +use std::io; +use std::io::prelude::*; static CRC32_TABLE : [u32; 256] = [ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, @@ -69,7 +70,7 @@ pub struct Crc32Reader check: u32, } -impl Crc32Reader +impl Crc32Reader { /// Get a new Crc32Reader which check the inner reader against checksum. pub fn new(inner: R, checksum: u32) -> Crc32Reader @@ -88,19 +89,14 @@ impl Crc32Reader } } -impl Reader for Crc32Reader +impl Read for Crc32Reader { - fn read(&mut self, buf: &mut [u8]) -> old_io::IoResult + fn read(&mut self, buf: &mut [u8]) -> io::Result { let count = match self.inner.read(buf) { + Ok(0) if !self.check_matches() => { return Err(io::Error::new(io::ErrorKind::Other, "Invalid checksum", None)) }, Ok(n) => n, - Err(ref e) if e.kind == old_io::EndOfFile => - { - return - if self.check_matches() { Err(e.clone()) } - else { Err(old_io::IoError { kind: old_io::OtherIoError, desc: "Invalid checksum", detail: None, }) } - }, Err(e) => return Err(e), }; self.crc = update(self.crc, &buf[0..count]); diff --git a/src/reader.rs b/src/reader.rs index ff2c0a9f..f03e9f39 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -4,7 +4,8 @@ use compression::CompressionMethod; use spec; use reader_spec; use result::{ZipResult, ZipError}; -use std::old_io; +use std::io; +use std::io::prelude::*; use std::cell::{RefCell, BorrowState}; use std::collections::HashMap; use flate2::FlateReadExt; @@ -47,7 +48,7 @@ fn unsupported_zip_error(detail: &'static str) -> ZipResult Err(ZipError::UnsupportedZipFile(detail)) } -impl ZipReader +impl ZipReader { /// Opens a ZIP file and parses the content headers. pub fn new(mut reader: T) -> ZipResult> @@ -56,13 +57,13 @@ impl ZipReader if footer.disk_number != footer.disk_with_central_directory { return unsupported_zip_error("Support for multi-disk files is not implemented") } - let directory_start = footer.central_directory_offset as i64; + let directory_start = footer.central_directory_offset as u64; let number_of_files = footer.number_of_files_on_this_disk as usize; let mut files = Vec::with_capacity(number_of_files); let mut names_map = HashMap::new(); - try!(reader.seek(directory_start, old_io::SeekSet)); + try!(reader.seek(io::SeekFrom::Start(directory_start))); for _ in (0 .. number_of_files) { let file = try!(reader_spec::central_header_to_zip_file(&mut reader)); @@ -88,23 +89,23 @@ impl ZipReader /// Gets a reader for a contained zipfile. /// /// May return `ReaderUnavailable` if there is another reader borrowed. - pub fn read_file<'a>(&'a self, file: &ZipFile) -> ZipResult> + pub fn read_file<'a>(&'a self, file: &ZipFile) -> ZipResult> { let mut inner_reader = match self.inner.borrow_state() { BorrowState::Unused => self.inner.borrow_mut(), _ => return Err(ZipError::ReaderUnavailable), }; - let pos = file.data_start as i64; + let pos = file.data_start as u64; if file.encrypted { return unsupported_zip_error("Encrypted files are not supported") } - try!(inner_reader.seek(pos, old_io::SeekSet)); + try!(inner_reader.seek(io::SeekFrom::Start(pos))); let refmut_reader = ::util::RefMutReader::new(inner_reader); - let limit_reader = old_io::util::LimitReader::new(refmut_reader, file.compressed_size as usize); + let limit_reader = refmut_reader.take(file.compressed_size as u64); let reader = match file.compression_method { @@ -114,25 +115,25 @@ impl ZipReader Crc32Reader::new( limit_reader, file.crc32)) - as Box + as Box }, CompressionMethod::Deflated => { - let deflate_reader = IoConverter::new(IoConverter::new(limit_reader).deflate_decode()); + let deflate_reader = limit_reader.deflate_decode(); Box::new( Crc32Reader::new( deflate_reader, file.crc32)) - as Box + as Box }, CompressionMethod::Bzip2 => { - let bzip2_reader = BzDecompressor::new(limit_reader); + let bzip2_reader = IoConverter::new(BzDecompressor::new(IoConverter::new(limit_reader))); Box::new( Crc32Reader::new( bzip2_reader, file.crc32)) - as Box + as Box }, _ => return unsupported_zip_error("Compression method not supported"), }; diff --git a/src/reader_spec.rs b/src/reader_spec.rs index 5e02f5bd..e807c51e 100644 --- a/src/reader_spec.rs +++ b/src/reader_spec.rs @@ -1,12 +1,14 @@ -use std::old_io; +use std::io; +use std::io::prelude::*; use std::num::FromPrimitive; use result::{ZipResult, ZipError}; use types::ZipFile; use compression::CompressionMethod; use spec; use util; +use util::ReadIntExt; -pub fn central_header_to_zip_file(reader: &mut R) -> ZipResult +pub fn central_header_to_zip_file(reader: &mut R) -> ZipResult { // Parse central header let signature = try!(reader.read_le_u32()); @@ -32,7 +34,7 @@ pub fn central_header_to_zip_file(reader: &mut R) -> ZipResult(reader: &mut R) -> ZipResult(reader: &mut R) -> ZipResult ZipResult<()> { - let mut reader = old_io::BufReader::new(data); - while !reader.eof() + let mut reader = io::Cursor::new(data); + + while (reader.position() as usize) < data.len() { let kind = try!(reader.read_le_u16()); let len = try!(reader.read_le_u16()); match kind { - _ => try!(reader.seek(len as i64, old_io::SeekCur)), - } + _ => try!(reader.seek(io::SeekFrom::Current(len as i64))), + }; } Ok(()) } diff --git a/src/spec.rs b/src/spec.rs index 2bc0f96d..e2163de4 100644 --- a/src/spec.rs +++ b/src/spec.rs @@ -1,8 +1,8 @@ -use std::old_io; +use std::io; use std::io::prelude::*; use result::{ZipResult, ZipError}; use std::iter::range_step_inclusive; -use util::WriteIntExt; +use util::{ReadIntExt, WriteIntExt}; pub static LOCAL_FILE_HEADER_SIGNATURE : u32 = 0x04034b50; pub static CENTRAL_DIRECTORY_HEADER_SIGNATURE : u32 = 0x02014b50; @@ -21,7 +21,7 @@ pub struct CentralDirectoryEnd impl CentralDirectoryEnd { - pub fn parse(reader: &mut T) -> ZipResult + pub fn parse(reader: &mut T) -> ZipResult { let magic = try!(reader.read_le_u32()); if magic != CENTRAL_DIRECTORY_END_SIGNATURE @@ -49,24 +49,23 @@ impl CentralDirectoryEnd }) } - pub fn find_and_parse(reader: &mut T) -> ZipResult + pub fn find_and_parse(reader: &mut T) -> ZipResult { let header_size = 22; let bytes_between_magic_and_comment_size = header_size - 6; - try!(reader.seek(0, old_io::SeekEnd)); - let file_length = try!(reader.tell()) as i64; + let file_length = try!(reader.seek(io::SeekFrom::End(0))) as i64; let search_upper_bound = ::std::cmp::max(0, file_length - header_size - ::std::u16::MAX as i64); for pos in range_step_inclusive(file_length - header_size, search_upper_bound, -1) { - try!(reader.seek(pos, old_io::SeekSet)); + try!(reader.seek(io::SeekFrom::Start(pos as u64))); if try!(reader.read_le_u32()) == CENTRAL_DIRECTORY_END_SIGNATURE { - try!(reader.seek(bytes_between_magic_and_comment_size, old_io::SeekCur)); + try!(reader.seek(io::SeekFrom::Current(bytes_between_magic_and_comment_size))); let comment_length = try!(reader.read_le_u16()) as i64; if file_length - pos - header_size == comment_length { - try!(reader.seek(pos, old_io::SeekSet)); + try!(reader.seek(io::SeekFrom::Start(pos as u64))); return CentralDirectoryEnd::parse(reader); } } diff --git a/src/util.rs b/src/util.rs index 0ceb133a..03ec9686 100644 --- a/src/util.rs +++ b/src/util.rs @@ -98,3 +98,58 @@ impl WriteIntExt for W { 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; + let mut tries = 0; + while idx < buf.len() { + match reader.read(&mut buf[idx..]) { + Err(v) => return Err(v), + Ok(i) => idx += i, + } + tries += 1; + if tries > 2*buf.len() { + return Err(io::Error::new(io::ErrorKind::ResourceUnavailable, "Could not fill the buffer", None)); + } + } + 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) + } +}