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;