From 2e8baed7994ac41b6cf4cfc2e41f2a25db222c38 Mon Sep 17 00:00:00 2001 From: Mathijs van de Nes Date: Tue, 24 Feb 2015 12:59:25 +0100 Subject: [PATCH 01/17] Initial io conversion - Convert most of the writer code to Write instead of Writer - Add ioconverter module to convert between old and new IO - Fix reader for new flate2 --- Cargo.toml | 4 +- examples/write_sample.rs | 6 ++- src/ioconverter.rs | 89 ++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 3 +- src/reader.rs | 5 ++- src/result.rs | 19 ++++++++- src/util.rs | 12 +++++- src/writer.rs | 85 +++++++++++++++++++++++--------------- src/writer_spec.rs | 1 + 9 files changed, 183 insertions(+), 41 deletions(-) create mode 100644 src/ioconverter.rs diff --git a/Cargo.toml b/Cargo.toml index 8ee375e5..04829961 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "zip" -version = "0.0.12" +version = "0.1.0" authors = ["Mathijs van de Nes "] license = "MIT" repository = "https://github.com/mvdnes/zip-rs.git" @@ -10,6 +10,6 @@ Library to support the reading and writing of zip files. """ [dependencies] -flate2 = "^0.1" +flate2 = "*" bzip2 = "*" time = "*" diff --git a/examples/write_sample.rs b/examples/write_sample.rs index 9d1d43da..923c66e0 100644 --- a/examples/write_sample.rs +++ b/examples/write_sample.rs @@ -1,4 +1,6 @@ -#![feature(old_io, old_path, env)] +#![feature(io, fs, old_path, env)] + +use std::io::prelude::*; extern crate zip; @@ -22,7 +24,7 @@ fn main() fn doit(filename: &str) -> zip::result::ZipResult<()> { let path = Path::new(filename); - let file = std::old_io::File::create(&path).unwrap(); + let file = std::fs::File::create(&path).unwrap(); let mut zip = zip::ZipWriter::new(file); diff --git a/src/ioconverter.rs b/src/ioconverter.rs new file mode 100644 index 00000000..6dafcab2 --- /dev/null +++ b/src/ioconverter.rs @@ -0,0 +1,89 @@ +use std::io; +use std::io::prelude::*; +use std::old_io; +use std::cell::RefCell; + +pub struct IoConverter { + inner: RefCell, + eofs: usize, +} + +impl IoConverter { + pub fn new(inner: T) -> IoConverter { + IoConverter { inner: RefCell::new(inner), eofs: 0, } + } + pub fn into_inner(self) -> T { + self.inner.into_inner() + } +} + +impl Writer for IoConverter { + fn write_all(&mut self, buf: &[u8]) -> old_io::IoResult<()> { + match self.inner.borrow_mut().write_all(buf) { + Ok(()) => Ok(()), + Err(..) => Err(old_io::standard_error(old_io::OtherIoError)), + } + } +} + +impl Write for IoConverter { + fn write(&mut self, buf: &[u8]) -> io::Result { + match self.inner.borrow_mut().write_all(buf) { + Ok(()) => Ok(buf.len()), + Err(..) => Err(io::Error::new(io::ErrorKind::Other, "Some writing error", None)), + } + } + fn flush(&mut self) -> io::Result<()> { + match self.inner.borrow_mut().flush() { + Ok(()) => Ok(()), + Err(..) => Err(io::Error::new(io::ErrorKind::Other, "Some flushing error", None)), + } + } +} + +impl old_io::Seek for IoConverter { + fn tell(&self) -> old_io::IoResult { + match self.inner.borrow_mut().seek(io::SeekFrom::Current(0)) { + Ok(v) => Ok(v), + Err(..) => Err(old_io::standard_error(old_io::OtherIoError)), + } + } + fn seek(&mut self, pos: i64, style: old_io::SeekStyle) -> old_io::IoResult<()> { + let new_pos = match style { + old_io::SeekSet => io::SeekFrom::Start(pos as u64), + old_io::SeekEnd => io::SeekFrom::End(pos), + old_io::SeekCur => io::SeekFrom::Current(pos), + }; + match self.inner.borrow_mut().seek(new_pos) { + Ok(..) => Ok(()), + Err(..) => Err(old_io::standard_error(old_io::OtherIoError)), + } + } +} + +impl Read for IoConverter { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + match self.inner.borrow_mut().read(buf) { + Ok(v) => Ok(v), + Err(ref e) if e.kind == old_io::EndOfFile => Ok(0), + Err(..) => Err(io::Error::new(io::ErrorKind::Other, "Some reading error", None)), + } + } +} + +impl Reader for IoConverter { + fn read(&mut self, buf: &mut [u8]) -> old_io::IoResult { + match self.inner.borrow_mut().read(buf) { + Ok(0) => { + if self.eofs >= 2 { + Err(old_io::standard_error(old_io::EndOfFile)) + } else { + self.eofs += 1; + Ok(0) + } + }, + Ok(v) => Ok(v), + Err(..) => Err(old_io::standard_error(old_io::OtherIoError)), + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 15f2f472..04841ed7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,7 +3,7 @@ #![feature(unsafe_destructor)] #![warn(missing_docs)] -#![feature(core, collections, old_io, std_misc)] +#![feature(core, collections, old_io, std_misc, io)] extern crate time; extern crate flate2; @@ -25,3 +25,4 @@ pub mod compression; mod writer; mod cp437; pub mod result; +mod ioconverter; diff --git a/src/reader.rs b/src/reader.rs index 83138a89..ff2c0a9f 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -7,8 +7,9 @@ use result::{ZipResult, ZipError}; use std::old_io; use std::cell::{RefCell, BorrowState}; use std::collections::HashMap; -use flate2::FlateReader; +use flate2::FlateReadExt; use bzip2::reader::BzDecompressor; +use ioconverter::IoConverter; /// Wrapper for reading the contents of a ZIP file. /// @@ -117,7 +118,7 @@ impl ZipReader }, CompressionMethod::Deflated => { - let deflate_reader = limit_reader.deflate_decode(); + let deflate_reader = IoConverter::new(IoConverter::new(limit_reader).deflate_decode()); Box::new( Crc32Reader::new( deflate_reader, diff --git a/src/result.rs b/src/result.rs index 9575bfa2..2d1a5c91 100644 --- a/src/result.rs +++ b/src/result.rs @@ -1,6 +1,7 @@ //! Error types that can be emitted from this library use std::old_io::IoError; +use std::io; use std::error; use std::fmt; @@ -11,8 +12,11 @@ pub type ZipResult = Result; #[derive(Debug)] pub enum ZipError { + /// An Error caused by old I/O + OldIo(IoError), + /// An Error caused by I/O - Io(IoError), + Io(io::Error), /// This file is probably not a zipfile. The argument is enclosed. InvalidZipFile(&'static str), @@ -33,6 +37,9 @@ impl ZipError match *self { + ZipError::OldIo(ref io_err) => { + ("OldIo Error: ".to_string() + io_err.description()).into_cow() + }, ZipError::Io(ref io_err) => { ("Io Error: ".to_string() + io_err.description()).into_cow() }, @@ -49,6 +56,14 @@ impl ZipError impl error::FromError for ZipError { fn from_error(err: IoError) -> ZipError + { + ZipError::OldIo(err) + } +} + +impl error::FromError for ZipError +{ + fn from_error(err: io::Error) -> ZipError { ZipError::Io(err) } @@ -68,6 +83,7 @@ impl error::Error for ZipError { match *self { + ZipError::OldIo(ref io_err) => io_err.description(), ZipError::Io(ref io_err) => io_err.description(), ZipError::InvalidZipFile(..) => "Invalid Zip File", ZipError::UnsupportedZipFile(..) => "Unsupported Zip File", @@ -79,6 +95,7 @@ impl error::Error for ZipError { match *self { + ZipError::OldIo(ref io_err) => Some(io_err as &error::Error), ZipError::Io(ref io_err) => Some(io_err as &error::Error), _ => None, } diff --git a/src/util.rs b/src/util.rs index 5184ee77..12b0ea58 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,6 +1,8 @@ use time; use time::Tm; use std::cell::RefMut; +use std::io; +use std::io::prelude::*; pub fn msdos_datetime_to_tm(time: u16, date: u16) -> Tm { @@ -45,7 +47,7 @@ pub struct RefMutReader<'a, R:'a> inner: RefMut<'a, R>, } -impl<'a, R: Reader> RefMutReader<'a, R> +impl<'a, R> RefMutReader<'a, R> { pub fn new(inner: RefMut<'a, R>) -> RefMutReader<'a, R> { @@ -53,6 +55,14 @@ impl<'a, R: Reader> RefMutReader<'a, R> } } +impl<'a, R: Read> Read for RefMutReader<'a, R> +{ + fn read(&mut self, buf: &mut [u8]) -> io::Result + { + self.inner.read(buf) + } +} + impl<'a, R: Reader> Reader for RefMutReader<'a, R> { fn read(&mut self, buf: &mut [u8]) -> ::std::old_io::IoResult diff --git a/src/writer.rs b/src/writer.rs index bb1dc258..b873b0d9 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -5,21 +5,25 @@ use writer_spec; use crc32; use result::{ZipResult, ZipError}; use std::default::Default; -use std::old_io; +use std::io; +use std::io::Seek; +use std::io::prelude::*; +use std::old_io::Writer; use std::mem; use time; use flate2; -use flate2::FlateWriter; -use flate2::writer::DeflateEncoder; +use flate2::FlateWriteExt; +use flate2::write::DeflateEncoder; use bzip2; use bzip2::writer::BzCompressor; +use ioconverter::IoConverter; enum GenericZipWriter { Closed, Storer(W), Deflater(DeflateEncoder), - Bzip2(BzCompressor), + Bzip2(IoConverter>>), } /// Generator for ZIP files. @@ -27,13 +31,15 @@ enum GenericZipWriter /// ``` /// fn doit() -> zip::result::ZipResult<()> /// { +/// use std::io::Write; +/// /// // For this example we write to a buffer, but normally you should use a File -/// let mut buf = [0u8; 65536]; -/// let w = std::old_io::BufWriter::new(&mut buf); +/// let mut buf: &mut [u8] = &mut [0u8; 65536]; +/// let mut w = std::io::Cursor::new(buf); /// let mut zip = zip::ZipWriter::new(w); /// /// try!(zip.start_file("hello_world.txt", zip::CompressionMethod::Stored)); -/// try!(zip.write_all(b"Hello, World!")); +/// try!(zip.write(b"Hello, World!")); /// /// // Optionally finish the zip. (this is also done on drop) /// try!(zip.finish()); @@ -58,18 +64,27 @@ struct ZipWriterStats bytes_written: u64, } -impl Writer for ZipWriter +impl Write for ZipWriter { - fn write_all(&mut self, buf: &[u8]) -> old_io::IoResult<()> + fn write(&mut self, buf: &[u8]) -> io::Result { - if self.files.len() == 0 { return Err(old_io::IoError { kind: old_io::OtherIoError, desc: "No file has been started", detail: None, }) } + if self.files.len() == 0 { return Err(io::Error::new(io::ErrorKind::Other, "No file has been started", None)) } self.stats.update(buf); match self.inner { - GenericZipWriter::Storer(ref mut w) => w.write_all(buf), - GenericZipWriter::Deflater(ref mut w) => w.write_all(buf), - GenericZipWriter::Bzip2(ref mut w) => w.write_all(buf), - GenericZipWriter::Closed => Err(old_io::standard_error(old_io::Closed)), + GenericZipWriter::Storer(ref mut w) => w.write(buf), + GenericZipWriter::Deflater(ref mut w) => w.write(buf), + GenericZipWriter::Bzip2(ref mut w) => w.write(buf), + GenericZipWriter::Closed => Err(io::Error::new(io::ErrorKind::BrokenPipe, "ZipWriter was already closed", None)), + } + } + + fn flush(&mut self) -> io::Result<()> + { + match self.finalize() { + Ok(..) => Ok(()), + Err(ZipError::Io(io_err)) => Err(io_err), + Err(..) => Err(io::Error::new(io::ErrorKind::Other, "Error occured during finalization", None)), } } } @@ -83,7 +98,7 @@ impl ZipWriterStats } } -impl ZipWriter +impl ZipWriter { /// Initializes the ZipWriter. /// @@ -105,7 +120,7 @@ impl ZipWriter { let writer = self.inner.get_plain(); - let header_start = try!(writer.tell()); + let header_start = try!(writer.seek(io::SeekFrom::Current(0))); let mut file = ZipFile { @@ -120,9 +135,11 @@ impl ZipWriter header_start: header_start, data_start: 0, }; - try!(writer_spec::write_local_file_header(writer, &file)); + let mut conv_w = IoConverter::new(writer); + try!(writer_spec::write_local_file_header(&mut conv_w, &file)); + let writer = conv_w.into_inner(); - let header_end = try!(writer.tell()); + let header_end = try!(writer.seek(io::SeekFrom::Current(0))); self.stats.start = header_end; file.data_start = header_end; @@ -149,10 +166,12 @@ impl ZipWriter }; file.crc32 = self.stats.crc32; file.uncompressed_size = self.stats.bytes_written; - file.compressed_size = try!(writer.tell()) - self.stats.start; + file.compressed_size = try!(writer.seek(io::SeekFrom::Current(0))) - self.stats.start; - try!(writer_spec::update_local_file_header(writer, file)); - try!(writer.seek(0, old_io::SeekEnd)); + let mut conv_w = IoConverter::new(writer); + try!(writer_spec::update_local_file_header(&mut conv_w, file)); + let writer = conv_w.into_inner(); + try!(writer.seek(io::SeekFrom::End(0))); Ok(()) } @@ -174,12 +193,14 @@ impl ZipWriter { let writer = self.inner.get_plain(); - let central_start = try!(writer.tell()); + let central_start = try!(writer.seek(io::SeekFrom::Current(0))); + let mut conv_w = IoConverter::new(writer); for file in self.files.iter() { - try!(writer_spec::write_central_directory_header(writer, file)); + try!(writer_spec::write_central_directory_header(&mut conv_w, file)); } - let central_size = try!(writer.tell()) - central_start; + let writer = conv_w.into_inner(); + let central_size = try!(writer.seek(io::SeekFrom::Current(0))) - central_start; let footer = spec::CentralDirectoryEnd { @@ -192,7 +213,7 @@ impl ZipWriter zip_file_comment: b"zip-rs".to_vec(), }; - try!(footer.write(writer)); + try!(footer.write(&mut IoConverter::new(writer))); } Ok(()) @@ -200,20 +221,20 @@ impl ZipWriter } #[unsafe_destructor] -impl Drop for ZipWriter +impl Drop for ZipWriter { fn drop(&mut self) { if !self.inner.is_closed() { if let Err(e) = self.finalize() { - let _ = write!(&mut old_io::stdio::stderr(), "ZipWriter drop failed: {:?}", e); + let _ = write!(&mut ::std::old_io::stdio::stderr(), "ZipWriter drop failed: {:?}", e); } } } } -impl GenericZipWriter +impl GenericZipWriter { fn switch_to(&mut self, compression: CompressionMethod) -> ZipResult<()> { @@ -221,15 +242,15 @@ impl GenericZipWriter { GenericZipWriter::Storer(w) => w, GenericZipWriter::Deflater(w) => try!(w.finish()), - GenericZipWriter::Bzip2(w) => match w.into_inner() { Ok(r) => r, Err((_, err)) => try!(Err(err)) }, - GenericZipWriter::Closed => try!(Err(old_io::standard_error(old_io::Closed))), + GenericZipWriter::Bzip2(w) => match w.into_inner().into_inner() { Ok(r) => r.into_inner(), Err((_, err)) => try!(Err(err)) }, + GenericZipWriter::Closed => try!(Err(io::Error::new(io::ErrorKind::BrokenPipe, "ZipWriter was already closed", None))), }; *self = match compression { CompressionMethod::Stored => GenericZipWriter::Storer(bare), - CompressionMethod::Deflated => GenericZipWriter::Deflater(bare.deflate_encode(flate2::CompressionLevel::Default)), - CompressionMethod::Bzip2 => GenericZipWriter::Bzip2(BzCompressor::new(bare, bzip2::CompressionLevel::Default)), + CompressionMethod::Deflated => GenericZipWriter::Deflater(bare.deflate_encode(flate2::Compression::Default)), + CompressionMethod::Bzip2 => GenericZipWriter::Bzip2(IoConverter::new(BzCompressor::new(IoConverter::new(bare), bzip2::CompressionLevel::Default))), _ => return Err(ZipError::UnsupportedZipFile("Unsupported compression")), }; diff --git a/src/writer_spec.rs b/src/writer_spec.rs index 5df725b4..2827fc5a 100644 --- a/src/writer_spec.rs +++ b/src/writer_spec.rs @@ -1,4 +1,5 @@ use std::old_io; +use std::io::prelude::*; use std::ascii::AsciiExt; use types::ZipFile; use result::ZipResult; From af22baf13b8574da0c1ea44a4694d798d7af57ba Mon Sep 17 00:00:00 2001 From: Mathijs van de Nes Date: Tue, 24 Feb 2015 14:36:00 +0100 Subject: [PATCH 02/17] Convert writer_spec to new IO --- src/util.rs | 28 ++++++++++++++++++++++++++++ src/writer.rs | 21 +++++++-------------- src/writer_spec.rs | 17 +++++++++-------- 3 files changed, 44 insertions(+), 22 deletions(-) diff --git a/src/util.rs b/src/util.rs index 12b0ea58..0ceb133a 100644 --- a/src/util.rs +++ b/src/util.rs @@ -70,3 +70,31 @@ impl<'a, R: Reader> Reader for RefMutReader<'a, R> self.inner.read(buf) } } + +/// 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) + } +} diff --git a/src/writer.rs b/src/writer.rs index b873b0d9..af1c4521 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -6,7 +6,6 @@ use crc32; use result::{ZipResult, ZipError}; use std::default::Default; use std::io; -use std::io::Seek; use std::io::prelude::*; use std::old_io::Writer; use std::mem; @@ -64,7 +63,7 @@ struct ZipWriterStats bytes_written: u64, } -impl Write for ZipWriter +impl Write for ZipWriter { fn write(&mut self, buf: &[u8]) -> io::Result { @@ -98,7 +97,7 @@ impl ZipWriterStats } } -impl ZipWriter +impl ZipWriter { /// Initializes the ZipWriter. /// @@ -135,9 +134,7 @@ impl ZipWriter header_start: header_start, data_start: 0, }; - let mut conv_w = IoConverter::new(writer); - try!(writer_spec::write_local_file_header(&mut conv_w, &file)); - let writer = conv_w.into_inner(); + try!(writer_spec::write_local_file_header(writer, &file)); let header_end = try!(writer.seek(io::SeekFrom::Current(0))); self.stats.start = header_end; @@ -168,9 +165,7 @@ impl ZipWriter file.uncompressed_size = self.stats.bytes_written; file.compressed_size = try!(writer.seek(io::SeekFrom::Current(0))) - self.stats.start; - let mut conv_w = IoConverter::new(writer); - try!(writer_spec::update_local_file_header(&mut conv_w, file)); - let writer = conv_w.into_inner(); + try!(writer_spec::update_local_file_header(writer, file)); try!(writer.seek(io::SeekFrom::End(0))); Ok(()) } @@ -194,12 +189,10 @@ impl ZipWriter let writer = self.inner.get_plain(); let central_start = try!(writer.seek(io::SeekFrom::Current(0))); - let mut conv_w = IoConverter::new(writer); for file in self.files.iter() { - try!(writer_spec::write_central_directory_header(&mut conv_w, file)); + try!(writer_spec::write_central_directory_header(writer, file)); } - let writer = conv_w.into_inner(); let central_size = try!(writer.seek(io::SeekFrom::Current(0))) - central_start; let footer = spec::CentralDirectoryEnd @@ -221,7 +214,7 @@ impl ZipWriter } #[unsafe_destructor] -impl Drop for ZipWriter +impl Drop for ZipWriter { fn drop(&mut self) { @@ -234,7 +227,7 @@ impl Drop for ZipWriter } } -impl GenericZipWriter +impl GenericZipWriter { fn switch_to(&mut self, compression: CompressionMethod) -> ZipResult<()> { diff --git a/src/writer_spec.rs b/src/writer_spec.rs index 2827fc5a..62e2540b 100644 --- a/src/writer_spec.rs +++ b/src/writer_spec.rs @@ -1,12 +1,13 @@ -use std::old_io; +use std::io; use std::io::prelude::*; use std::ascii::AsciiExt; use types::ZipFile; use result::ZipResult; use spec; use util; +use util::WriteIntExt; -pub fn write_local_file_header(writer: &mut T, file: &ZipFile) -> ZipResult<()> +pub fn write_local_file_header(writer: &mut T, file: &ZipFile) -> ZipResult<()> { try!(writer.write_le_u32(spec::LOCAL_FILE_HEADER_SIGNATURE)); try!(writer.write_le_u16(20)); @@ -27,17 +28,17 @@ pub fn write_local_file_header(writer: &mut T, file: &ZipFile) -> Zip Ok(()) } -pub fn update_local_file_header(writer: &mut T, file: &ZipFile) -> ZipResult<()> +pub fn update_local_file_header(writer: &mut T, file: &ZipFile) -> ZipResult<()> { - static CRC32_OFFSET : i64 = 14; - try!(writer.seek(file.header_start as i64 + CRC32_OFFSET, old_io::SeekSet)); + 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)); Ok(()) } -pub fn write_central_directory_header(writer: &mut T, file: &ZipFile) -> ZipResult<()> +pub fn write_central_directory_header(writer: &mut T, file: &ZipFile) -> ZipResult<()> { try!(writer.write_le_u32(spec::CENTRAL_DIRECTORY_HEADER_SIGNATURE)); try!(writer.write_le_u16(0x14FF)); @@ -66,7 +67,7 @@ pub fn write_central_directory_header(writer: &mut T, file: &ZipFile) fn build_extra_field(_file: &ZipFile) -> ZipResult> { - let writer = old_io::MemWriter::new(); + let writer = Vec::new(); // Future work - Ok(writer.into_inner()) + Ok(writer) } From 69b38b3ce54079e6057369e4aa1733e65688839b Mon Sep 17 00:00:00 2001 From: Mathijs van de Nes Date: Tue, 24 Feb 2015 14:37:46 +0100 Subject: [PATCH 03/17] Update Write for spec --- src/spec.rs | 4 +++- src/writer.rs | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/spec.rs b/src/spec.rs index f97e7247..2bc0f96d 100644 --- a/src/spec.rs +++ b/src/spec.rs @@ -1,6 +1,8 @@ use std::old_io; +use std::io::prelude::*; use result::{ZipResult, ZipError}; use std::iter::range_step_inclusive; +use util::WriteIntExt; pub static LOCAL_FILE_HEADER_SIGNATURE : u32 = 0x04034b50; pub static CENTRAL_DIRECTORY_HEADER_SIGNATURE : u32 = 0x02014b50; @@ -72,7 +74,7 @@ impl CentralDirectoryEnd Err(ZipError::UnsupportedZipFile("Could not find central directory end")) } - pub fn write(&self, writer: &mut T) -> ZipResult<()> + 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)); diff --git a/src/writer.rs b/src/writer.rs index af1c4521..5bf2a4ad 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -206,7 +206,7 @@ impl ZipWriter zip_file_comment: b"zip-rs".to_vec(), }; - try!(footer.write(&mut IoConverter::new(writer))); + try!(footer.write(writer)); } Ok(()) From bb89f577c5c5186066c41bee354053506bfcfb03 Mon Sep 17 00:00:00 2001 From: Mathijs van de Nes Date: Tue, 24 Feb 2015 16:02:16 +0100 Subject: [PATCH 04/17] Convert reader to new IO --- src/crc32.rs | 16 +++++--------- src/reader.rs | 27 ++++++++++++----------- src/reader_spec.rs | 25 +++++++++++---------- src/spec.rs | 17 +++++++------- src/util.rs | 55 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 97 insertions(+), 43 deletions(-) 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) + } +} From 6d2a63e406ebc07f28630f4d32250badac24975e Mon Sep 17 00:00:00 2001 From: Mathijs van de Nes Date: Tue, 24 Feb 2015 16:16:08 +0100 Subject: [PATCH 05/17] Fix tests and examples --- examples/extract.rs | 18 +++++++++--------- examples/extract_lorem.rs | 10 ++++++---- src/reader.rs | 8 +++++--- 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/examples/extract.rs b/examples/extract.rs index 3c230fa7..5b13531f 100644 --- a/examples/extract.rs +++ b/examples/extract.rs @@ -1,8 +1,9 @@ -#![feature(old_path, old_io, env)] +#![feature(old_path, io, fs, env)] extern crate zip; -use std::old_io; +use std::io; +use std::fs; fn main() { @@ -13,7 +14,7 @@ fn main() return; } let fname = Path::new(&*args[1]); - let file = old_io::File::open(&fname).unwrap(); + let file = fs::File::open(&fname).unwrap(); let zipcontainer = zip::ZipReader::new(file).unwrap(); @@ -25,7 +26,7 @@ fn main() let comment = &file.file_comment; if comment.len() > 0 { println!(" File comment: {}", comment); } - old_io::fs::mkdir_recursive(&outpath.dir_path(), old_io::USER_DIR).unwrap(); + fs::create_dir_all(&outpath.dir_path()).unwrap(); if (&*file.file_name).ends_with("/") { create_directory(outpath); @@ -36,17 +37,16 @@ fn main() } } -fn write_file(zipcontainer: &zip::ZipReader, file: &zip::ZipFile, outpath: Path) +fn write_file(zipcontainer: &zip::ZipReader, file: &zip::ZipFile, outpath: Path) { - let mut outfile = old_io::File::create(&outpath); + let mut outfile = fs::File::create(&outpath).unwrap(); let mut reader = zipcontainer.read_file(file).unwrap(); - old_io::util::copy(&mut reader, &mut outfile).unwrap(); - old_io::fs::chmod(&outpath, old_io::USER_FILE).unwrap(); + io::copy(&mut reader, &mut outfile).unwrap(); } fn create_directory(outpath: Path) { - old_io::fs::mkdir_recursive(&outpath, old_io::USER_DIR).unwrap(); + fs::create_dir_all(&outpath).unwrap(); } fn sanitize_filename(filename: &str) -> Path diff --git a/examples/extract_lorem.rs b/examples/extract_lorem.rs index 1bab70f0..f9169363 100644 --- a/examples/extract_lorem.rs +++ b/examples/extract_lorem.rs @@ -1,4 +1,6 @@ -#![feature(old_path, old_io, env)] +#![feature(old_path, io, fs, env)] + +use std::io::prelude::*; extern crate zip; @@ -11,7 +13,7 @@ fn main() return; } let fname = Path::new(&*args[1]); - let file = std::old_io::File::open(&fname).unwrap(); + let file = std::fs::File::open(&fname).unwrap(); let zipcontainer = zip::ZipReader::new(file).unwrap(); @@ -21,7 +23,7 @@ fn main() None => { println!("File test/lorem_ipsum.txt not found"); return } }; - let data = zipcontainer.read_file(file).unwrap().read_to_end().unwrap(); - let contents = String::from_utf8(data).unwrap(); + let mut contents = String::new(); + zipcontainer.read_file(file).unwrap().read_to_string(&mut contents).unwrap(); println!("{}", contents); } diff --git a/src/reader.rs b/src/reader.rs index f03e9f39..ca8725d6 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -17,10 +17,12 @@ use ioconverter::IoConverter; /// ``` /// fn doit() -> zip::result::ZipResult<()> /// { +/// use std::io::prelude::*; +/// /// // For demonstration purposes we read from an empty buffer. /// // Normally a File object would be used. -/// let buf = [0u8; 128]; -/// let mut reader = std::old_io::BufReader::new(&buf); +/// let buf: &[u8] = &[0u8; 128]; +/// let mut reader = std::io::Cursor::new(buf); /// /// let zip = try!(zip::ZipReader::new(reader)); /// @@ -28,7 +30,7 @@ use ioconverter::IoConverter; /// { /// println!("Filename: {}", file.file_name); /// let mut file_reader = try!(zip.read_file(file)); -/// let first_byte = try!(file_reader.read_byte()); +/// let first_byte = try!(file_reader.bytes().next().unwrap()); /// println!("{}", first_byte); /// } /// Ok(()) From f382cf85b9be1d1c7c5b0cdca3d5c12145b791cb Mon Sep 17 00:00:00 2001 From: Mathijs van de Nes Date: Tue, 24 Feb 2015 18:46:01 +0100 Subject: [PATCH 06/17] Some more cleanup --- src/ioconverter.rs | 34 +++------------------------------- src/util.rs | 14 +------------- src/writer.rs | 1 - 3 files changed, 4 insertions(+), 45 deletions(-) diff --git a/src/ioconverter.rs b/src/ioconverter.rs index 6dafcab2..d3eb2b5d 100644 --- a/src/ioconverter.rs +++ b/src/ioconverter.rs @@ -5,12 +5,11 @@ use std::cell::RefCell; pub struct IoConverter { inner: RefCell, - eofs: usize, } impl IoConverter { pub fn new(inner: T) -> IoConverter { - IoConverter { inner: RefCell::new(inner), eofs: 0, } + IoConverter { inner: RefCell::new(inner), } } pub fn into_inner(self) -> T { self.inner.into_inner() @@ -41,27 +40,7 @@ impl Write for IoConverter { } } -impl old_io::Seek for IoConverter { - fn tell(&self) -> old_io::IoResult { - match self.inner.borrow_mut().seek(io::SeekFrom::Current(0)) { - Ok(v) => Ok(v), - Err(..) => Err(old_io::standard_error(old_io::OtherIoError)), - } - } - fn seek(&mut self, pos: i64, style: old_io::SeekStyle) -> old_io::IoResult<()> { - let new_pos = match style { - old_io::SeekSet => io::SeekFrom::Start(pos as u64), - old_io::SeekEnd => io::SeekFrom::End(pos), - old_io::SeekCur => io::SeekFrom::Current(pos), - }; - match self.inner.borrow_mut().seek(new_pos) { - Ok(..) => Ok(()), - Err(..) => Err(old_io::standard_error(old_io::OtherIoError)), - } - } -} - -impl Read for IoConverter { +impl Read for IoConverter { fn read(&mut self, buf: &mut [u8]) -> io::Result { match self.inner.borrow_mut().read(buf) { Ok(v) => Ok(v), @@ -74,14 +53,7 @@ impl Read for IoConverter { impl Reader for IoConverter { fn read(&mut self, buf: &mut [u8]) -> old_io::IoResult { match self.inner.borrow_mut().read(buf) { - Ok(0) => { - if self.eofs >= 2 { - Err(old_io::standard_error(old_io::EndOfFile)) - } else { - self.eofs += 1; - Ok(0) - } - }, + Ok(0) if buf.len() > 0 => Err(old_io::standard_error(old_io::EndOfFile)), Ok(v) => Ok(v), Err(..) => Err(old_io::standard_error(old_io::OtherIoError)), } diff --git a/src/util.rs b/src/util.rs index 03ec9686..a606d0b9 100644 --- a/src/util.rs +++ b/src/util.rs @@ -63,14 +63,6 @@ impl<'a, R: Read> Read for RefMutReader<'a, R> } } -impl<'a, R: Reader> Reader for RefMutReader<'a, R> -{ - fn read(&mut self, buf: &mut [u8]) -> ::std::old_io::IoResult - { - self.inner.read(buf) - } -} - /// Additional integer write methods for a io::Read pub trait WriteIntExt { /// Write a u32 in little-endian mode @@ -110,16 +102,12 @@ pub trait ReadIntExt { 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(0) => return Err(io::Error::new(io::ErrorKind::ResourceUnavailable, "Could not fill the buffer", None)), 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(()) } diff --git a/src/writer.rs b/src/writer.rs index 5bf2a4ad..03e265bd 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -7,7 +7,6 @@ use result::{ZipResult, ZipError}; use std::default::Default; use std::io; use std::io::prelude::*; -use std::old_io::Writer; use std::mem; use time; use flate2; From 518b40aabc00c1bb11ac105b05dd0117561a3ea5 Mon Sep 17 00:00:00 2001 From: Mathijs van de Nes Date: Tue, 24 Feb 2015 18:46:59 +0100 Subject: [PATCH 07/17] Do not use collections feature --- src/lib.rs | 2 +- src/writer.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 04841ed7..44618990 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,7 +3,7 @@ #![feature(unsafe_destructor)] #![warn(missing_docs)] -#![feature(core, collections, old_io, std_misc, io)] +#![feature(core, old_io, std_misc, io)] extern crate time; extern crate flate2; diff --git a/src/writer.rs b/src/writer.rs index 03e265bd..ed053d3e 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -128,7 +128,7 @@ impl ZipWriter crc32: 0, compressed_size: 0, uncompressed_size: 0, - file_name: String::from_str(name), + file_name: name.to_string(), file_comment: String::new(), header_start: header_start, data_start: 0, From 51c55d30b3352270e4d1cbfd1482035f56f0a2c7 Mon Sep 17 00:00:00 2001 From: Mathijs van de Nes Date: Tue, 24 Feb 2015 18:50:33 +0100 Subject: [PATCH 08/17] Remove RefCell from IoConverter Seek is removed, so dynamic borrow checking is no longer needed --- src/ioconverter.rs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/ioconverter.rs b/src/ioconverter.rs index d3eb2b5d..4a0e258d 100644 --- a/src/ioconverter.rs +++ b/src/ioconverter.rs @@ -1,24 +1,23 @@ use std::io; use std::io::prelude::*; use std::old_io; -use std::cell::RefCell; pub struct IoConverter { - inner: RefCell, + inner: T, } impl IoConverter { pub fn new(inner: T) -> IoConverter { - IoConverter { inner: RefCell::new(inner), } + IoConverter { inner: inner, } } pub fn into_inner(self) -> T { - self.inner.into_inner() + self.inner } } impl Writer for IoConverter { fn write_all(&mut self, buf: &[u8]) -> old_io::IoResult<()> { - match self.inner.borrow_mut().write_all(buf) { + match self.inner.write_all(buf) { Ok(()) => Ok(()), Err(..) => Err(old_io::standard_error(old_io::OtherIoError)), } @@ -27,13 +26,13 @@ impl Writer for IoConverter { impl Write for IoConverter { fn write(&mut self, buf: &[u8]) -> io::Result { - match self.inner.borrow_mut().write_all(buf) { + match self.inner.write_all(buf) { Ok(()) => Ok(buf.len()), Err(..) => Err(io::Error::new(io::ErrorKind::Other, "Some writing error", None)), } } fn flush(&mut self) -> io::Result<()> { - match self.inner.borrow_mut().flush() { + match self.inner.flush() { Ok(()) => Ok(()), Err(..) => Err(io::Error::new(io::ErrorKind::Other, "Some flushing error", None)), } @@ -42,7 +41,7 @@ impl Write for IoConverter { impl Read for IoConverter { fn read(&mut self, buf: &mut [u8]) -> io::Result { - match self.inner.borrow_mut().read(buf) { + match self.inner.read(buf) { Ok(v) => Ok(v), Err(ref e) if e.kind == old_io::EndOfFile => Ok(0), Err(..) => Err(io::Error::new(io::ErrorKind::Other, "Some reading error", None)), @@ -52,7 +51,7 @@ impl Read for IoConverter { impl Reader for IoConverter { fn read(&mut self, buf: &mut [u8]) -> old_io::IoResult { - match self.inner.borrow_mut().read(buf) { + match self.inner.read(buf) { Ok(0) if buf.len() > 0 => Err(old_io::standard_error(old_io::EndOfFile)), Ok(v) => Ok(v), Err(..) => Err(old_io::standard_error(old_io::OtherIoError)), From b4ccb46389dc0295ddd24c1097ccc388d9eb69e8 Mon Sep 17 00:00:00 2001 From: Mathijs van de Nes Date: Tue, 24 Feb 2015 19:06:19 +0100 Subject: [PATCH 09/17] Close the writer on flush --- src/writer.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/writer.rs b/src/writer.rs index ed053d3e..481dbc88 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -79,7 +79,9 @@ impl Write for ZipWriter fn flush(&mut self) -> io::Result<()> { - match self.finalize() { + let result = self.finalize(); + self.inner = GenericZipWriter::Closed; + match result { Ok(..) => Ok(()), Err(ZipError::Io(io_err)) => Err(io_err), Err(..) => Err(io::Error::new(io::ErrorKind::Other, "Error occured during finalization", None)), From f88349104ad82b00b926b2d7c824bd8e9be463ed Mon Sep 17 00:00:00 2001 From: Mathijs van de Nes Date: Tue, 24 Feb 2015 20:42:43 +0100 Subject: [PATCH 10/17] Remove almost all old_io code --- Cargo.toml | 5 +++- src/ioconverter.rs | 60 ---------------------------------------------- src/lib.rs | 1 - src/reader.rs | 3 +-- src/result.rs | 17 ------------- src/writer.rs | 7 +++--- 6 files changed, 8 insertions(+), 85 deletions(-) delete mode 100644 src/ioconverter.rs diff --git a/Cargo.toml b/Cargo.toml index 04829961..4aa332f1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,5 +11,8 @@ Library to support the reading and writing of zip files. [dependencies] flate2 = "*" -bzip2 = "*" time = "*" + +[dependencies.bzip2] +git = "https://github.com/mvdnes/bzip2-rs" +branch = "new_io" diff --git a/src/ioconverter.rs b/src/ioconverter.rs deleted file mode 100644 index 4a0e258d..00000000 --- a/src/ioconverter.rs +++ /dev/null @@ -1,60 +0,0 @@ -use std::io; -use std::io::prelude::*; -use std::old_io; - -pub struct IoConverter { - inner: T, -} - -impl IoConverter { - pub fn new(inner: T) -> IoConverter { - IoConverter { inner: inner, } - } - pub fn into_inner(self) -> T { - self.inner - } -} - -impl Writer for IoConverter { - fn write_all(&mut self, buf: &[u8]) -> old_io::IoResult<()> { - match self.inner.write_all(buf) { - Ok(()) => Ok(()), - Err(..) => Err(old_io::standard_error(old_io::OtherIoError)), - } - } -} - -impl Write for IoConverter { - fn write(&mut self, buf: &[u8]) -> io::Result { - match self.inner.write_all(buf) { - Ok(()) => Ok(buf.len()), - Err(..) => Err(io::Error::new(io::ErrorKind::Other, "Some writing error", None)), - } - } - fn flush(&mut self) -> io::Result<()> { - match self.inner.flush() { - Ok(()) => Ok(()), - Err(..) => Err(io::Error::new(io::ErrorKind::Other, "Some flushing error", None)), - } - } -} - -impl Read for IoConverter { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - match self.inner.read(buf) { - Ok(v) => Ok(v), - Err(ref e) if e.kind == old_io::EndOfFile => Ok(0), - Err(..) => Err(io::Error::new(io::ErrorKind::Other, "Some reading error", None)), - } - } -} - -impl Reader for IoConverter { - fn read(&mut self, buf: &mut [u8]) -> old_io::IoResult { - match self.inner.read(buf) { - Ok(0) if buf.len() > 0 => Err(old_io::standard_error(old_io::EndOfFile)), - Ok(v) => Ok(v), - Err(..) => Err(old_io::standard_error(old_io::OtherIoError)), - } - } -} diff --git a/src/lib.rs b/src/lib.rs index 44618990..41824950 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,4 +25,3 @@ pub mod compression; mod writer; mod cp437; pub mod result; -mod ioconverter; diff --git a/src/reader.rs b/src/reader.rs index ca8725d6..b3b12b0b 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -10,7 +10,6 @@ use std::cell::{RefCell, BorrowState}; use std::collections::HashMap; use flate2::FlateReadExt; use bzip2::reader::BzDecompressor; -use ioconverter::IoConverter; /// Wrapper for reading the contents of a ZIP file. /// @@ -130,7 +129,7 @@ impl ZipReader }, CompressionMethod::Bzip2 => { - let bzip2_reader = IoConverter::new(BzDecompressor::new(IoConverter::new(limit_reader))); + let bzip2_reader = BzDecompressor::new(limit_reader); Box::new( Crc32Reader::new( bzip2_reader, diff --git a/src/result.rs b/src/result.rs index 2d1a5c91..0041d1c0 100644 --- a/src/result.rs +++ b/src/result.rs @@ -1,6 +1,5 @@ //! Error types that can be emitted from this library -use std::old_io::IoError; use std::io; use std::error; use std::fmt; @@ -12,9 +11,6 @@ pub type ZipResult = Result; #[derive(Debug)] pub enum ZipError { - /// An Error caused by old I/O - OldIo(IoError), - /// An Error caused by I/O Io(io::Error), @@ -37,9 +33,6 @@ impl ZipError match *self { - ZipError::OldIo(ref io_err) => { - ("OldIo Error: ".to_string() + io_err.description()).into_cow() - }, ZipError::Io(ref io_err) => { ("Io Error: ".to_string() + io_err.description()).into_cow() }, @@ -53,14 +46,6 @@ impl ZipError } } -impl error::FromError for ZipError -{ - fn from_error(err: IoError) -> ZipError - { - ZipError::OldIo(err) - } -} - impl error::FromError for ZipError { fn from_error(err: io::Error) -> ZipError @@ -83,7 +68,6 @@ impl error::Error for ZipError { match *self { - ZipError::OldIo(ref io_err) => io_err.description(), ZipError::Io(ref io_err) => io_err.description(), ZipError::InvalidZipFile(..) => "Invalid Zip File", ZipError::UnsupportedZipFile(..) => "Unsupported Zip File", @@ -95,7 +79,6 @@ impl error::Error for ZipError { match *self { - ZipError::OldIo(ref io_err) => Some(io_err as &error::Error), ZipError::Io(ref io_err) => Some(io_err as &error::Error), _ => None, } diff --git a/src/writer.rs b/src/writer.rs index 481dbc88..4281b6e6 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -14,14 +14,13 @@ use flate2::FlateWriteExt; use flate2::write::DeflateEncoder; use bzip2; use bzip2::writer::BzCompressor; -use ioconverter::IoConverter; enum GenericZipWriter { Closed, Storer(W), Deflater(DeflateEncoder), - Bzip2(IoConverter>>), + Bzip2(BzCompressor), } /// Generator for ZIP files. @@ -236,7 +235,7 @@ impl GenericZipWriter { GenericZipWriter::Storer(w) => w, GenericZipWriter::Deflater(w) => try!(w.finish()), - GenericZipWriter::Bzip2(w) => match w.into_inner().into_inner() { Ok(r) => r.into_inner(), Err((_, err)) => try!(Err(err)) }, + GenericZipWriter::Bzip2(w) => match w.into_inner() { Ok(r) => r, Err((_, err)) => try!(Err(err)) }, GenericZipWriter::Closed => try!(Err(io::Error::new(io::ErrorKind::BrokenPipe, "ZipWriter was already closed", None))), }; @@ -244,7 +243,7 @@ impl GenericZipWriter { CompressionMethod::Stored => GenericZipWriter::Storer(bare), CompressionMethod::Deflated => GenericZipWriter::Deflater(bare.deflate_encode(flate2::Compression::Default)), - CompressionMethod::Bzip2 => GenericZipWriter::Bzip2(IoConverter::new(BzCompressor::new(IoConverter::new(bare), bzip2::CompressionLevel::Default))), + CompressionMethod::Bzip2 => GenericZipWriter::Bzip2(BzCompressor::new(bare, bzip2::CompressionLevel::Default)), _ => return Err(ZipError::UnsupportedZipFile("Unsupported compression")), }; From bfc370eda316d2aa26de74d88fad7c1f78b5bcbf Mon Sep 17 00:00:00 2001 From: Mathijs van de Nes Date: Wed, 25 Feb 2015 12:13:13 +0100 Subject: [PATCH 11/17] Update for new bzip2 --- Cargo.toml | 5 +---- src/writer.rs | 6 +++--- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4aa332f1..04829961 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,8 +11,5 @@ Library to support the reading and writing of zip files. [dependencies] flate2 = "*" +bzip2 = "*" time = "*" - -[dependencies.bzip2] -git = "https://github.com/mvdnes/bzip2-rs" -branch = "new_io" diff --git a/src/writer.rs b/src/writer.rs index 4281b6e6..6a067208 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -15,7 +15,7 @@ use flate2::write::DeflateEncoder; use bzip2; use bzip2::writer::BzCompressor; -enum GenericZipWriter +enum GenericZipWriter { Closed, Storer(W), @@ -46,7 +46,7 @@ enum GenericZipWriter /// /// println!("Result: {:?}", doit()); /// ``` -pub struct ZipWriter +pub struct ZipWriter { inner: GenericZipWriter, files: Vec, @@ -243,7 +243,7 @@ impl GenericZipWriter { CompressionMethod::Stored => GenericZipWriter::Storer(bare), CompressionMethod::Deflated => GenericZipWriter::Deflater(bare.deflate_encode(flate2::Compression::Default)), - CompressionMethod::Bzip2 => GenericZipWriter::Bzip2(BzCompressor::new(bare, bzip2::CompressionLevel::Default)), + CompressionMethod::Bzip2 => GenericZipWriter::Bzip2(BzCompressor::new(bare, bzip2::Compress::Default)), _ => return Err(ZipError::UnsupportedZipFile("Unsupported compression")), }; From 5f35da5ca49c80532c093d73f8ac61a7b00713dc Mon Sep 17 00:00:00 2001 From: Mathijs van de Nes Date: Thu, 26 Feb 2015 11:53:05 +0100 Subject: [PATCH 12/17] Wrap the files() iterator This way we can change the inner API without breaking the outer --- src/reader.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/reader.rs b/src/reader.rs index b3b12b0b..fbb06c85 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -44,6 +44,18 @@ pub struct ZipReader names_map: HashMap, } +pub struct ZipFileIterator<'a> +{ + inner: ::std::slice::Iter<'a, ZipFile>, +} + +impl<'a> Iterator for ZipFileIterator<'a> { + type Item = &'a ZipFile; + fn next(&mut self) -> Option<&'a ZipFile> { + self.inner.next() + } +} + fn unsupported_zip_error(detail: &'static str) -> ZipResult { Err(ZipError::UnsupportedZipFile(detail)) @@ -76,9 +88,9 @@ impl ZipReader } /// An iterator over the information of all contained files. - pub fn files(&self) -> ::std::slice::Iter + pub fn files(&self) -> ZipFileIterator { - (&*self.files).iter() + ZipFileIterator { inner: (&*self.files).iter(), } } /// Search for a file entry by name From 8bc33dcc57cfe50a990161e73bd44b6d5a9dc9fe Mon Sep 17 00:00:00 2001 From: Mathijs van de Nes Date: Thu, 26 Feb 2015 11:53:34 +0100 Subject: [PATCH 13/17] Remove deprecated function alltogether --- src/reader.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/reader.rs b/src/reader.rs index fbb06c85..52bd00df 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -160,11 +160,4 @@ impl ZipReader { self.inner.into_inner() } - - /// Deprecated method equal to `into_inner()` - #[deprecated="renamed to into_inner()"] - pub fn unwrap(self) -> T - { - self.into_inner() - } } From b65f729bbea9f6638b213ac00e684aa7d9615d15 Mon Sep 17 00:00:00 2001 From: Mathijs van de Nes Date: Sat, 28 Feb 2015 14:35:21 +0100 Subject: [PATCH 14/17] Make the reader and writer mod public --- src/lib.rs | 4 ++-- src/reader.rs | 3 +++ src/writer.rs | 2 ++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 41824950..d241509c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,9 +19,9 @@ mod spec; mod reader_spec; mod writer_spec; mod crc32; -mod reader; +pub mod reader; mod types; pub mod compression; -mod writer; +pub mod writer; mod cp437; pub mod result; diff --git a/src/reader.rs b/src/reader.rs index 52bd00df..5bb0f856 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -1,3 +1,5 @@ +//! Structs for reading a ZIP archive + use crc32::Crc32Reader; use types::ZipFile; use compression::CompressionMethod; @@ -44,6 +46,7 @@ pub struct ZipReader names_map: HashMap, } +/// Iterator over the files contained in a zip archive pub struct ZipFileIterator<'a> { inner: ::std::slice::Iter<'a, ZipFile>, diff --git a/src/writer.rs b/src/writer.rs index 6a067208..e31775ca 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -1,3 +1,5 @@ +//! Structs for creating a new zip archive + use compression::CompressionMethod; use types::ZipFile; use spec; From e67f019517b7a6bb4c65800fe708e3831a821dda Mon Sep 17 00:00:00 2001 From: Mathijs van de Nes Date: Sat, 28 Feb 2015 14:35:51 +0100 Subject: [PATCH 15/17] Implement size_hint on our iterator wrapper --- src/reader.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/reader.rs b/src/reader.rs index 5bb0f856..1bae6bff 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -57,6 +57,9 @@ impl<'a> Iterator for ZipFileIterator<'a> { fn next(&mut self) -> Option<&'a ZipFile> { self.inner.next() } + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } } fn unsupported_zip_error(detail: &'static str) -> ZipResult From d9b83af57c1327963b37bcbb64e5eda9c3e64b71 Mon Sep 17 00:00:00 2001 From: Mathijs van de Nes Date: Sun, 1 Mar 2015 11:32:40 +0100 Subject: [PATCH 16/17] Large refactoring, mostly of the reader - Combined reader and reader_spec into read - Alter the iteration protocol for a zip archive - Modify some names --- examples/extract.rs | 22 +-- examples/extract_lorem.rs | 12 +- src/compression.rs | 2 +- src/lib.rs | 14 +- src/read.rs | 308 ++++++++++++++++++++++++++++++++++++ src/reader.rs | 169 -------------------- src/reader_spec.rs | 107 ------------- src/result.rs | 22 +-- src/spec.rs | 4 +- src/types.rs | 3 +- src/util.rs | 22 --- src/{writer.rs => write.rs} | 8 +- src/writer_spec.rs | 10 +- 13 files changed, 356 insertions(+), 347 deletions(-) create mode 100644 src/read.rs delete mode 100644 src/reader.rs delete mode 100644 src/reader_spec.rs rename src/{writer.rs => write.rs} (98%) diff --git a/examples/extract.rs b/examples/extract.rs index 5b13531f..7e32f987 100644 --- a/examples/extract.rs +++ b/examples/extract.rs @@ -16,32 +16,34 @@ fn main() let fname = Path::new(&*args[1]); let file = fs::File::open(&fname).unwrap(); - let zipcontainer = zip::ZipReader::new(file).unwrap(); + let mut archive = zip::ZipArchive::new(file).unwrap(); - for file in zipcontainer.files() + for i in 1..archive.len() { - let outpath = sanitize_filename(&*file.file_name); + let mut file = archive.by_index(i).unwrap(); + let outpath = sanitize_filename(file.name()); println!("{}", outpath.display()); - let comment = &file.file_comment; - if comment.len() > 0 { println!(" File comment: {}", comment); } + { + let comment = file.comment(); + if comment.len() > 0 { println!(" File comment: {}", comment); } + } fs::create_dir_all(&outpath.dir_path()).unwrap(); - if (&*file.file_name).ends_with("/") { + if (&*file.name()).ends_with("/") { create_directory(outpath); } else { - write_file(&zipcontainer, file, outpath); + write_file(&mut file, outpath); } } } -fn write_file(zipcontainer: &zip::ZipReader, file: &zip::ZipFile, outpath: Path) +fn write_file(reader: &mut zip::read::ZipFileReader, outpath: Path) { let mut outfile = fs::File::create(&outpath).unwrap(); - let mut reader = zipcontainer.read_file(file).unwrap(); - io::copy(&mut reader, &mut outfile).unwrap(); + io::copy(reader, &mut outfile).unwrap(); } fn create_directory(outpath: Path) diff --git a/examples/extract_lorem.rs b/examples/extract_lorem.rs index f9169363..e9aff77e 100644 --- a/examples/extract_lorem.rs +++ b/examples/extract_lorem.rs @@ -13,17 +13,17 @@ fn main() return; } let fname = Path::new(&*args[1]); - let file = std::fs::File::open(&fname).unwrap(); + let zipfile = std::fs::File::open(&fname).unwrap(); - let zipcontainer = zip::ZipReader::new(file).unwrap(); + let mut archive = zip::ZipArchive::new(zipfile).unwrap(); - let file = match zipcontainer.get("test/lorem_ipsum.txt") + let mut file = match archive.by_name("test/lorem_ipsum.txt") { - Some(file) => file, - None => { println!("File test/lorem_ipsum.txt not found"); return } + Ok(file) => file, + Err(..) => { println!("File test/lorem_ipsum.txt not found"); return } }; let mut contents = String::new(); - zipcontainer.read_file(file).unwrap().read_to_string(&mut contents).unwrap(); + file.read_to_string(&mut contents).unwrap(); println!("{}", contents); } diff --git a/src/compression.rs b/src/compression.rs index 67adeb7a..df7cc644 100644 --- a/src/compression.rs +++ b/src/compression.rs @@ -37,5 +37,5 @@ pub enum CompressionMethod /// PPMd version I, Rev 1 PPMdI1 = 98, /// Unknown (invalid) compression - Unknown = 100000, + Unknown = 10000, } diff --git a/src/lib.rs b/src/lib.rs index d241509c..f4454bc6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,25 +3,23 @@ #![feature(unsafe_destructor)] #![warn(missing_docs)] -#![feature(core, old_io, std_misc, io)] +#![feature(core, old_io, io)] extern crate time; extern crate flate2; extern crate bzip2; -pub use reader::ZipReader; -pub use writer::ZipWriter; +pub use read::ZipArchive; +pub use write::ZipWriter; pub use compression::CompressionMethod; -pub use types::ZipFile; mod util; mod spec; -mod reader_spec; mod writer_spec; mod crc32; -pub mod reader; mod types; -pub mod compression; -pub mod writer; +pub mod read; +mod compression; +pub mod write; mod cp437; pub mod result; diff --git a/src/read.rs b/src/read.rs new file mode 100644 index 00000000..db2abcee --- /dev/null +++ b/src/read.rs @@ -0,0 +1,308 @@ +//! Structs for reading a ZIP archive + +use crc32::Crc32Reader; +use compression::CompressionMethod; +use spec; +use result::{ZipResult, ZipError}; +use std::io; +use std::io::prelude::*; +use std::collections::HashMap; +use std::num::FromPrimitive; +use flate2; +use flate2::FlateReadExt; +use bzip2::reader::BzDecompressor; +use util; +use util::ReadIntExt; +use types::ZipFileData; + +/// Wrapper for reading the contents of a ZIP file. +/// +/// ``` +/// fn doit() -> zip::result::ZipResult<()> +/// { +/// use std::io::prelude::*; +/// +/// // For demonstration purposes we read from an empty buffer. +/// // Normally a File object would be used. +/// let buf: &[u8] = &[0u8; 128]; +/// let mut reader = std::io::Cursor::new(buf); +/// +/// let mut zip = try!(zip::ZipArchive::new(reader)); +/// +/// for i in 1..zip.len() +/// { +/// let mut file = zip.by_index(i).unwrap(); +/// println!("Filename: {}", file.name()); +/// let first_byte = try!(file.bytes().next().unwrap()); +/// println!("{}", first_byte); +/// } +/// Ok(()) +/// } +/// +/// println!("Result: {:?}", doit()); +/// ``` +pub struct ZipArchive +{ + reader: R, + files: Vec, + names_map: HashMap, +} + +enum ZipFileReader<'a> { + Stored(Crc32Reader>), + Deflated(Crc32Reader>>), + Bzip2(Crc32Reader>>), +} + +/// A struct for reading a zip file +pub struct ZipFile<'a> { + data: &'a ZipFileData, + reader: ZipFileReader<'a>, +} + +fn unsupported_zip_error(detail: &'static str) -> ZipResult +{ + Err(ZipError::UnsupportedArchive(detail)) +} + +impl ZipArchive +{ + /// Opens a Zip archive and parses the central directory + pub fn new(mut reader: R) -> ZipResult> { + let footer = try!(spec::CentralDirectoryEnd::find_and_parse(&mut reader)); + + 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 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(io::SeekFrom::Start(directory_start))); + for _ in (0 .. number_of_files) + { + let file = try!(central_header_to_zip_file(&mut reader)); + names_map.insert(file.file_name.clone(), files.len()); + files.push(file); + } + + Ok(ZipArchive { reader: reader, files: files, names_map: names_map }) + } + + /// Number of files contained in this zip. + /// + /// ``` + /// fn iter() { + /// let mut zip = zip::ZipArchive::new(std::io::Cursor::new(vec![])).unwrap(); + /// + /// for i in 1..zip.len() { + /// let mut file = zip.by_index(i).unwrap(); + /// // Do something with file i + /// } + /// } + /// ``` + pub fn len(&self) -> usize + { + self.files.len() + } + + /// Search for a file entry by name + pub fn by_name<'a>(&'a mut self, name: &str) -> ZipResult> + { + let index = match self.names_map.get(name) { + Some(index) => *index, + None => { return Err(ZipError::FileNotFound); }, + }; + self.by_index(index) + } + + /// Get a contained file by index + pub fn by_index<'a>(&'a mut self, file_number: usize) -> ZipResult> + { + if file_number >= self.files.len() { return Err(ZipError::FileNotFound); } + let ref data = self.files[file_number]; + let pos = data.data_start as u64; + + if data.encrypted + { + return unsupported_zip_error("Encrypted files are not supported") + } + + try!(self.reader.seek(io::SeekFrom::Start(pos))); + let limit_reader = (self.reader.by_ref() as &mut Read).take(data.compressed_size as u64); + + let reader = match data.compression_method + { + CompressionMethod::Stored => + { + ZipFileReader::Stored(Crc32Reader::new( + limit_reader, + data.crc32)) + }, + CompressionMethod::Deflated => + { + let deflate_reader = limit_reader.deflate_decode(); + ZipFileReader::Deflated(Crc32Reader::new( + deflate_reader, + data.crc32)) + }, + CompressionMethod::Bzip2 => + { + let bzip2_reader = BzDecompressor::new(limit_reader); + ZipFileReader::Bzip2(Crc32Reader::new( + bzip2_reader, + data.crc32)) + }, + _ => return unsupported_zip_error("Compression method not supported"), + }; + Ok(ZipFile { reader: reader, data: data }) + } + + /// Unwrap and return the inner reader object + /// + /// The position of the reader is undefined. + pub fn into_inner(self) -> R + { + self.reader + } +} + +fn central_header_to_zip_file(reader: &mut R) -> ZipResult +{ + // Parse central header + let signature = try!(reader.read_le_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()); + 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 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)); + + let file_name = match is_utf8 + { + true => String::from_utf8_lossy(&*file_name_raw).into_owned(), + false => ::cp437::to_string(&*file_name_raw), + }; + let file_comment = match is_utf8 + { + true => String::from_utf8_lossy(&*file_comment_raw).into_owned(), + false => ::cp437::to_string(&*file_comment_raw), + }; + + // Remember end of central header + let return_position = try!(reader.seek(io::SeekFrom::Current(0))); + + // Parse local header + try!(reader.seek(io::SeekFrom::Start(offset))); + let signature = try!(reader.read_le_u32()); + 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 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 mut result = ZipFileData + { + encrypted: encrypted, + compression_method: FromPrimitive::from_u16(compression_method).unwrap_or(CompressionMethod::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, + header_start: offset as u64, + data_start: data_start, + }; + + try!(parse_extra_field(&mut result, &*extra_field)); + + // Go back after the central header + try!(reader.seek(io::SeekFrom::Start(return_position))); + + Ok(result) +} + +fn parse_extra_field(_file: &mut ZipFileData, data: &[u8]) -> ZipResult<()> +{ + 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(io::SeekFrom::Current(len as i64))), + }; + } + Ok(()) +} + +/// Methods for retreiving information on zip files +impl<'a> ZipFile<'a> { + fn get_reader(&mut self) -> &mut Read { + match self.reader { + ZipFileReader::Stored(ref mut r) => r as &mut Read, + ZipFileReader::Deflated(ref mut r) => r as &mut Read, + ZipFileReader::Bzip2(ref mut r) => r as &mut Read, + } + } + /// Get the name of the file + pub fn name(&self) -> &str { + &*self.data.file_name + } + /// Get the comment of the file + pub fn comment(&self) -> &str { + &*self.data.file_comment + } + /// Get the compression method used to store the file + pub fn compression(&self) -> CompressionMethod { + self.data.compression_method + } + /// Get the size of the file in the archive + pub fn compressed_size(&self) -> u64 { + self.data.compressed_size + } + /// Get the size of the file when uncompressed + pub fn size(&self) -> u64 { + self.data.uncompressed_size + } + /// Get the time the file was last modified + pub fn last_modified(&self) -> ::time::Tm { + self.data.last_modified_time + } +} + +impl<'a> Read for ZipFile<'a> { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.get_reader().read(buf) + } +} diff --git a/src/reader.rs b/src/reader.rs deleted file mode 100644 index 1bae6bff..00000000 --- a/src/reader.rs +++ /dev/null @@ -1,169 +0,0 @@ -//! Structs for reading a ZIP archive - -use crc32::Crc32Reader; -use types::ZipFile; -use compression::CompressionMethod; -use spec; -use reader_spec; -use result::{ZipResult, ZipError}; -use std::io; -use std::io::prelude::*; -use std::cell::{RefCell, BorrowState}; -use std::collections::HashMap; -use flate2::FlateReadExt; -use bzip2::reader::BzDecompressor; - -/// Wrapper for reading the contents of a ZIP file. -/// -/// ``` -/// fn doit() -> zip::result::ZipResult<()> -/// { -/// use std::io::prelude::*; -/// -/// // For demonstration purposes we read from an empty buffer. -/// // Normally a File object would be used. -/// let buf: &[u8] = &[0u8; 128]; -/// let mut reader = std::io::Cursor::new(buf); -/// -/// let zip = try!(zip::ZipReader::new(reader)); -/// -/// for file in zip.files() -/// { -/// println!("Filename: {}", file.file_name); -/// let mut file_reader = try!(zip.read_file(file)); -/// let first_byte = try!(file_reader.bytes().next().unwrap()); -/// println!("{}", first_byte); -/// } -/// Ok(()) -/// } -/// -/// println!("Result: {:?}", doit()); -/// ``` -pub struct ZipReader -{ - inner: RefCell, - files: Vec, - names_map: HashMap, -} - -/// Iterator over the files contained in a zip archive -pub struct ZipFileIterator<'a> -{ - inner: ::std::slice::Iter<'a, ZipFile>, -} - -impl<'a> Iterator for ZipFileIterator<'a> { - type Item = &'a ZipFile; - fn next(&mut self) -> Option<&'a ZipFile> { - self.inner.next() - } - fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() - } -} - -fn unsupported_zip_error(detail: &'static str) -> ZipResult -{ - Err(ZipError::UnsupportedZipFile(detail)) -} - -impl ZipReader -{ - /// Opens a ZIP file and parses the content headers. - pub fn new(mut reader: T) -> ZipResult> - { - let footer = try!(spec::CentralDirectoryEnd::find_and_parse(&mut reader)); - - 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 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(io::SeekFrom::Start(directory_start))); - for _ in (0 .. number_of_files) - { - let file = try!(reader_spec::central_header_to_zip_file(&mut reader)); - names_map.insert(file.file_name.clone(), files.len()); - files.push(file); - } - - Ok(ZipReader { inner: RefCell::new(reader), files: files, names_map: names_map }) - } - - /// An iterator over the information of all contained files. - pub fn files(&self) -> ZipFileIterator - { - ZipFileIterator { inner: (&*self.files).iter(), } - } - - /// Search for a file entry by name - pub fn get(&self, name: &str) -> Option<&ZipFile> - { - self.names_map.get(name).map(|index| &self.files[*index]) - } - - /// 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> - { - 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 u64; - - if file.encrypted - { - return unsupported_zip_error("Encrypted files are not supported") - } - - try!(inner_reader.seek(io::SeekFrom::Start(pos))); - let refmut_reader = ::util::RefMutReader::new(inner_reader); - let limit_reader = refmut_reader.take(file.compressed_size as u64); - - let reader = match file.compression_method - { - CompressionMethod::Stored => - { - Box::new( - Crc32Reader::new( - limit_reader, - file.crc32)) - as Box - }, - CompressionMethod::Deflated => - { - let deflate_reader = limit_reader.deflate_decode(); - Box::new( - Crc32Reader::new( - deflate_reader, - file.crc32)) - as Box - }, - CompressionMethod::Bzip2 => - { - let bzip2_reader = BzDecompressor::new(limit_reader); - Box::new( - Crc32Reader::new( - bzip2_reader, - file.crc32)) - as Box - }, - _ => return unsupported_zip_error("Compression method not supported"), - }; - Ok(reader) - } - - /// Unwrap and return the inner reader object - /// - /// The position of the reader is undefined. - pub fn into_inner(self) -> T - { - self.inner.into_inner() - } -} diff --git a/src/reader_spec.rs b/src/reader_spec.rs deleted file mode 100644 index e807c51e..00000000 --- a/src/reader_spec.rs +++ /dev/null @@ -1,107 +0,0 @@ -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 -{ - // Parse central header - let signature = try!(reader.read_le_u32()); - if signature != spec::CENTRAL_DIRECTORY_HEADER_SIGNATURE - { - return Err(ZipError::InvalidZipFile("Invalid Central Directory header")) - } - - try!(reader.read_le_u16()); - try!(reader.read_le_u16()); - let flags = try!(reader.read_le_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 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)); - - let file_name = match is_utf8 - { - true => String::from_utf8_lossy(&*file_name_raw).into_owned(), - false => ::cp437::to_string(&*file_name_raw), - }; - let file_comment = match is_utf8 - { - true => String::from_utf8_lossy(&*file_comment_raw).into_owned(), - false => ::cp437::to_string(&*file_comment_raw), - }; - - // Remember end of central header - let return_position = try!(reader.seek(io::SeekFrom::Current(0))); - - // Parse local header - try!(reader.seek(io::SeekFrom::Start(offset))); - let signature = try!(reader.read_le_u32()); - if signature != spec::LOCAL_FILE_HEADER_SIGNATURE - { - return Err(ZipError::InvalidZipFile("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 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 mut result = ZipFile - { - encrypted: encrypted, - compression_method: FromPrimitive::from_u16(compression_method).unwrap_or(CompressionMethod::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, - header_start: offset as u64, - data_start: data_start, - }; - - try!(parse_extra_field(&mut result, &*extra_field)); - - // Go back after the central header - try!(reader.seek(io::SeekFrom::Start(return_position))); - - Ok(result) -} - -fn parse_extra_field(_file: &mut ZipFile, data: &[u8]) -> ZipResult<()> -{ - 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(io::SeekFrom::Current(len as i64))), - }; - } - Ok(()) -} diff --git a/src/result.rs b/src/result.rs index 0041d1c0..31cde8e4 100644 --- a/src/result.rs +++ b/src/result.rs @@ -14,14 +14,14 @@ pub enum ZipError /// An Error caused by I/O Io(io::Error), - /// This file is probably not a zipfile. The argument is enclosed. - InvalidZipFile(&'static str), + /// This file is probably not a zip archive + InvalidArchive(&'static str), - /// This file is unsupported. The reason is enclosed. - UnsupportedZipFile(&'static str), + /// This archive is not supported + UnsupportedArchive(&'static str), - /// The ZipReader is not available. - ReaderUnavailable, + /// The requested file could not be found in the archive + FileNotFound, } impl ZipError @@ -36,10 +36,10 @@ impl ZipError ZipError::Io(ref io_err) => { ("Io Error: ".to_string() + io_err.description()).into_cow() }, - ZipError::InvalidZipFile(msg) | ZipError::UnsupportedZipFile(msg) => { + ZipError::InvalidArchive(msg) | ZipError::UnsupportedArchive(msg) => { (self.description().to_string() + ": " + msg).into_cow() }, - ZipError::ReaderUnavailable => { + ZipError::FileNotFound => { self.description().into_cow() }, } @@ -69,9 +69,9 @@ impl error::Error for ZipError match *self { ZipError::Io(ref io_err) => io_err.description(), - ZipError::InvalidZipFile(..) => "Invalid Zip File", - ZipError::UnsupportedZipFile(..) => "Unsupported Zip File", - ZipError::ReaderUnavailable => "No reader available", + ZipError::InvalidArchive(..) => "Invalid Zip archive", + ZipError::UnsupportedArchive(..) => "Unsupported Zip archive", + ZipError::FileNotFound => "Specified file not found in archive", } } diff --git a/src/spec.rs b/src/spec.rs index e2163de4..4c9f651f 100644 --- a/src/spec.rs +++ b/src/spec.rs @@ -26,7 +26,7 @@ impl CentralDirectoryEnd let magic = try!(reader.read_le_u32()); if magic != CENTRAL_DIRECTORY_END_SIGNATURE { - return Err(ZipError::UnsupportedZipFile("Invalid digital signature header")) + 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()); @@ -70,7 +70,7 @@ impl CentralDirectoryEnd } } } - Err(ZipError::UnsupportedZipFile("Could not find central directory end")) + Err(ZipError::InvalidArchive("Could not find central directory end")) } pub fn write(&self, writer: &mut T) -> ZipResult<()> diff --git a/src/types.rs b/src/types.rs index 71a88e5d..51d72b34 100644 --- a/src/types.rs +++ b/src/types.rs @@ -2,9 +2,8 @@ use time; -#[derive(Clone)] /// Structure representing a ZIP file. -pub struct ZipFile +pub struct ZipFileData { /// True if the file is encrypted. pub encrypted: bool, diff --git a/src/util.rs b/src/util.rs index a606d0b9..2285fe53 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,6 +1,5 @@ use time; use time::Tm; -use std::cell::RefMut; use std::io; use std::io::prelude::*; @@ -42,27 +41,6 @@ pub fn tm_to_msdos_date(time: Tm) -> u16 (time.tm_mday | ((time.tm_mon + 1) << 5) | ((time.tm_year - 80) << 9)) as u16 } -pub struct RefMutReader<'a, R:'a> -{ - inner: RefMut<'a, R>, -} - -impl<'a, R> RefMutReader<'a, R> -{ - pub fn new(inner: RefMut<'a, R>) -> RefMutReader<'a, R> - { - RefMutReader { inner: inner, } - } -} - -impl<'a, R: Read> Read for RefMutReader<'a, R> -{ - fn read(&mut self, buf: &mut [u8]) -> io::Result - { - self.inner.read(buf) - } -} - /// Additional integer write methods for a io::Read pub trait WriteIntExt { /// Write a u32 in little-endian mode diff --git a/src/writer.rs b/src/write.rs similarity index 98% rename from src/writer.rs rename to src/write.rs index e31775ca..32f46077 100644 --- a/src/writer.rs +++ b/src/write.rs @@ -1,7 +1,7 @@ //! Structs for creating a new zip archive use compression::CompressionMethod; -use types::ZipFile; +use types::ZipFileData; use spec; use writer_spec; use crc32; @@ -51,7 +51,7 @@ enum GenericZipWriter pub struct ZipWriter { inner: GenericZipWriter, - files: Vec, + files: Vec, stats: ZipWriterStats, } @@ -123,7 +123,7 @@ impl ZipWriter let writer = self.inner.get_plain(); let header_start = try!(writer.seek(io::SeekFrom::Current(0))); - let mut file = ZipFile + let mut file = ZipFileData { encrypted: false, compression_method: compression, @@ -246,7 +246,7 @@ impl GenericZipWriter CompressionMethod::Stored => GenericZipWriter::Storer(bare), CompressionMethod::Deflated => GenericZipWriter::Deflater(bare.deflate_encode(flate2::Compression::Default)), CompressionMethod::Bzip2 => GenericZipWriter::Bzip2(BzCompressor::new(bare, bzip2::Compress::Default)), - _ => return Err(ZipError::UnsupportedZipFile("Unsupported compression")), + _ => return Err(ZipError::UnsupportedArchive("Unsupported compression")), }; Ok(()) diff --git a/src/writer_spec.rs b/src/writer_spec.rs index 62e2540b..73f5eb37 100644 --- a/src/writer_spec.rs +++ b/src/writer_spec.rs @@ -1,13 +1,13 @@ use std::io; use std::io::prelude::*; use std::ascii::AsciiExt; -use types::ZipFile; +use types::ZipFileData; use result::ZipResult; use spec; use util; use util::WriteIntExt; -pub fn write_local_file_header(writer: &mut T, file: &ZipFile) -> ZipResult<()> +pub 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)); @@ -28,7 +28,7 @@ pub fn write_local_file_header(writer: &mut T, file: &ZipFile) -> ZipR Ok(()) } -pub fn update_local_file_header(writer: &mut T, file: &ZipFile) -> ZipResult<()> +pub fn update_local_file_header(writer: &mut T, file: &ZipFileData) -> ZipResult<()> { static CRC32_OFFSET : u64 = 14; try!(writer.seek(io::SeekFrom::Start(file.header_start + CRC32_OFFSET))); @@ -38,7 +38,7 @@ pub fn update_local_file_header(writer: &mut T, file: &ZipFil Ok(()) } -pub fn write_central_directory_header(writer: &mut T, file: &ZipFile) -> ZipResult<()> +pub 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)); @@ -65,7 +65,7 @@ pub fn write_central_directory_header(writer: &mut T, file: &ZipFile) Ok(()) } -fn build_extra_field(_file: &ZipFile) -> ZipResult> +fn build_extra_field(_file: &ZipFileData) -> ZipResult> { let writer = Vec::new(); // Future work From b16da115701e8f7ad5de8f84ae0a5275957a519f Mon Sep 17 00:00:00 2001 From: Mathijs van de Nes Date: Sun, 1 Mar 2015 11:53:26 +0100 Subject: [PATCH 17/17] Small updates to write module --- src/lib.rs | 1 - src/write.rs | 78 +++++++++++++++++++++++++++++++++++++++++++--- src/writer_spec.rs | 73 ------------------------------------------- 3 files changed, 73 insertions(+), 79 deletions(-) delete mode 100644 src/writer_spec.rs diff --git a/src/lib.rs b/src/lib.rs index f4454bc6..3bd8f736 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,7 +15,6 @@ pub use compression::CompressionMethod; mod util; mod spec; -mod writer_spec; mod crc32; mod types; pub mod read; diff --git a/src/write.rs b/src/write.rs index 32f46077..e3920cdc 100644 --- a/src/write.rs +++ b/src/write.rs @@ -3,19 +3,22 @@ use compression::CompressionMethod; use types::ZipFileData; use spec; -use writer_spec; use crc32; use result::{ZipResult, ZipError}; use std::default::Default; use std::io; use std::io::prelude::*; use std::mem; +use std::error::Error; +use std::ascii::AsciiExt; use time; use flate2; use flate2::FlateWriteExt; use flate2::write::DeflateEncoder; use bzip2; use bzip2::writer::BzCompressor; +use util; +use util::WriteIntExt; enum GenericZipWriter { @@ -85,7 +88,7 @@ impl Write for ZipWriter match result { Ok(..) => Ok(()), Err(ZipError::Io(io_err)) => Err(io_err), - Err(..) => Err(io::Error::new(io::ErrorKind::Other, "Error occured during finalization", None)), + Err(zip_err) => Err(io::Error::new(io::ErrorKind::Other, "A zip error occured", Some(zip_err.description().to_string()))), } } } @@ -136,7 +139,7 @@ impl ZipWriter header_start: header_start, data_start: 0, }; - try!(writer_spec::write_local_file_header(writer, &file)); + try!(write_local_file_header(writer, &file)); let header_end = try!(writer.seek(io::SeekFrom::Current(0))); self.stats.start = header_end; @@ -167,7 +170,7 @@ impl ZipWriter file.uncompressed_size = self.stats.bytes_written; file.compressed_size = try!(writer.seek(io::SeekFrom::Current(0))) - self.stats.start; - try!(writer_spec::update_local_file_header(writer, file)); + try!(update_local_file_header(writer, file)); try!(writer.seek(io::SeekFrom::End(0))); Ok(()) } @@ -193,7 +196,7 @@ impl ZipWriter let central_start = try!(writer.seek(io::SeekFrom::Current(0))); for file in self.files.iter() { - try!(writer_spec::write_central_directory_header(writer, file)); + try!(write_central_directory_header(writer, file)); } let central_size = try!(writer.seek(io::SeekFrom::Current(0))) - central_start; @@ -279,3 +282,68 @@ 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)); + 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)); + let extra_field = try!(build_extra_field(file)); + try!(writer.write_le_u16(extra_field.len() as u16)); + try!(writer.write_all(file.file_name.as_bytes())); + try!(writer.write_all(extra_field.as_slice())); + + Ok(()) +} + +fn update_local_file_header(writer: &mut T, file: &ZipFileData) -> ZipResult<()> +{ + 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)); + 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)); + 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)); + 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_all(file.file_name.as_bytes())); + try!(writer.write_all(extra_field.as_slice())); + + Ok(()) +} + +fn build_extra_field(_file: &ZipFileData) -> ZipResult> +{ + let writer = Vec::new(); + // Future work + Ok(writer) +} diff --git a/src/writer_spec.rs b/src/writer_spec.rs deleted file mode 100644 index 73f5eb37..00000000 --- a/src/writer_spec.rs +++ /dev/null @@ -1,73 +0,0 @@ -use std::io; -use std::io::prelude::*; -use std::ascii::AsciiExt; -use types::ZipFileData; -use result::ZipResult; -use spec; -use util; -use util::WriteIntExt; - -pub 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)); - 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)); - let extra_field = try!(build_extra_field(file)); - try!(writer.write_le_u16(extra_field.len() as u16)); - try!(writer.write_all(file.file_name.as_bytes())); - try!(writer.write_all(extra_field.as_slice())); - - Ok(()) -} - -pub fn update_local_file_header(writer: &mut T, file: &ZipFileData) -> ZipResult<()> -{ - 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)); - Ok(()) -} - -pub 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)); - 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)); - 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_all(file.file_name.as_bytes())); - try!(writer.write_all(extra_field.as_slice())); - - Ok(()) -} - -fn build_extra_field(_file: &ZipFileData) -> ZipResult> -{ - let writer = Vec::new(); - // Future work - Ok(writer) -}