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
This commit is contained in:
Mathijs van de Nes 2015-02-24 12:59:25 +01:00
parent a525bd4e34
commit 2e8baed799
9 changed files with 183 additions and 41 deletions

View file

@ -1,7 +1,7 @@
[package] [package]
name = "zip" name = "zip"
version = "0.0.12" version = "0.1.0"
authors = ["Mathijs van de Nes <git@mathijs.vd-nes.nl>"] authors = ["Mathijs van de Nes <git@mathijs.vd-nes.nl>"]
license = "MIT" license = "MIT"
repository = "https://github.com/mvdnes/zip-rs.git" repository = "https://github.com/mvdnes/zip-rs.git"
@ -10,6 +10,6 @@ Library to support the reading and writing of zip files.
""" """
[dependencies] [dependencies]
flate2 = "^0.1" flate2 = "*"
bzip2 = "*" bzip2 = "*"
time = "*" time = "*"

View file

@ -1,4 +1,6 @@
#![feature(old_io, old_path, env)] #![feature(io, fs, old_path, env)]
use std::io::prelude::*;
extern crate zip; extern crate zip;
@ -22,7 +24,7 @@ fn main()
fn doit(filename: &str) -> zip::result::ZipResult<()> fn doit(filename: &str) -> zip::result::ZipResult<()>
{ {
let path = Path::new(filename); 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); let mut zip = zip::ZipWriter::new(file);

89
src/ioconverter.rs Normal file
View file

@ -0,0 +1,89 @@
use std::io;
use std::io::prelude::*;
use std::old_io;
use std::cell::RefCell;
pub struct IoConverter<T> {
inner: RefCell<T>,
eofs: usize,
}
impl<T> IoConverter<T> {
pub fn new(inner: T) -> IoConverter<T> {
IoConverter { inner: RefCell::new(inner), eofs: 0, }
}
pub fn into_inner(self) -> T {
self.inner.into_inner()
}
}
impl<W: Write> Writer for IoConverter<W> {
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<W: Writer> Write for IoConverter<W> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
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<W: io::Seek> old_io::Seek for IoConverter<W> {
fn tell(&self) -> old_io::IoResult<u64> {
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<R: old_io::Reader> Read for IoConverter<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
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<R: Read> Reader for IoConverter<R> {
fn read(&mut self, buf: &mut [u8]) -> old_io::IoResult<usize> {
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)),
}
}
}

View file

@ -3,7 +3,7 @@
#![feature(unsafe_destructor)] #![feature(unsafe_destructor)]
#![warn(missing_docs)] #![warn(missing_docs)]
#![feature(core, collections, old_io, std_misc)] #![feature(core, collections, old_io, std_misc, io)]
extern crate time; extern crate time;
extern crate flate2; extern crate flate2;
@ -25,3 +25,4 @@ pub mod compression;
mod writer; mod writer;
mod cp437; mod cp437;
pub mod result; pub mod result;
mod ioconverter;

View file

@ -7,8 +7,9 @@ use result::{ZipResult, ZipError};
use std::old_io; use std::old_io;
use std::cell::{RefCell, BorrowState}; use std::cell::{RefCell, BorrowState};
use std::collections::HashMap; use std::collections::HashMap;
use flate2::FlateReader; use flate2::FlateReadExt;
use bzip2::reader::BzDecompressor; use bzip2::reader::BzDecompressor;
use ioconverter::IoConverter;
/// Wrapper for reading the contents of a ZIP file. /// Wrapper for reading the contents of a ZIP file.
/// ///
@ -117,7 +118,7 @@ impl<T: Reader+Seek> ZipReader<T>
}, },
CompressionMethod::Deflated => CompressionMethod::Deflated =>
{ {
let deflate_reader = limit_reader.deflate_decode(); let deflate_reader = IoConverter::new(IoConverter::new(limit_reader).deflate_decode());
Box::new( Box::new(
Crc32Reader::new( Crc32Reader::new(
deflate_reader, deflate_reader,

View file

@ -1,6 +1,7 @@
//! Error types that can be emitted from this library //! Error types that can be emitted from this library
use std::old_io::IoError; use std::old_io::IoError;
use std::io;
use std::error; use std::error;
use std::fmt; use std::fmt;
@ -11,8 +12,11 @@ pub type ZipResult<T> = Result<T, ZipError>;
#[derive(Debug)] #[derive(Debug)]
pub enum ZipError pub enum ZipError
{ {
/// An Error caused by old I/O
OldIo(IoError),
/// An Error caused by I/O /// An Error caused by I/O
Io(IoError), Io(io::Error),
/// This file is probably not a zipfile. The argument is enclosed. /// This file is probably not a zipfile. The argument is enclosed.
InvalidZipFile(&'static str), InvalidZipFile(&'static str),
@ -33,6 +37,9 @@ impl ZipError
match *self match *self
{ {
ZipError::OldIo(ref io_err) => {
("OldIo Error: ".to_string() + io_err.description()).into_cow()
},
ZipError::Io(ref io_err) => { ZipError::Io(ref io_err) => {
("Io Error: ".to_string() + io_err.description()).into_cow() ("Io Error: ".to_string() + io_err.description()).into_cow()
}, },
@ -49,6 +56,14 @@ impl ZipError
impl error::FromError<IoError> for ZipError impl error::FromError<IoError> for ZipError
{ {
fn from_error(err: IoError) -> ZipError fn from_error(err: IoError) -> ZipError
{
ZipError::OldIo(err)
}
}
impl error::FromError<io::Error> for ZipError
{
fn from_error(err: io::Error) -> ZipError
{ {
ZipError::Io(err) ZipError::Io(err)
} }
@ -68,6 +83,7 @@ impl error::Error for ZipError
{ {
match *self match *self
{ {
ZipError::OldIo(ref io_err) => io_err.description(),
ZipError::Io(ref io_err) => io_err.description(), ZipError::Io(ref io_err) => io_err.description(),
ZipError::InvalidZipFile(..) => "Invalid Zip File", ZipError::InvalidZipFile(..) => "Invalid Zip File",
ZipError::UnsupportedZipFile(..) => "Unsupported Zip File", ZipError::UnsupportedZipFile(..) => "Unsupported Zip File",
@ -79,6 +95,7 @@ impl error::Error for ZipError
{ {
match *self match *self
{ {
ZipError::OldIo(ref io_err) => Some(io_err as &error::Error),
ZipError::Io(ref io_err) => Some(io_err as &error::Error), ZipError::Io(ref io_err) => Some(io_err as &error::Error),
_ => None, _ => None,
} }

View file

@ -1,6 +1,8 @@
use time; use time;
use time::Tm; use time::Tm;
use std::cell::RefMut; use std::cell::RefMut;
use std::io;
use std::io::prelude::*;
pub fn msdos_datetime_to_tm(time: u16, date: u16) -> Tm 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>, 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> 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<usize>
{
self.inner.read(buf)
}
}
impl<'a, R: Reader> Reader for RefMutReader<'a, R> impl<'a, R: Reader> Reader for RefMutReader<'a, R>
{ {
fn read(&mut self, buf: &mut [u8]) -> ::std::old_io::IoResult<usize> fn read(&mut self, buf: &mut [u8]) -> ::std::old_io::IoResult<usize>

View file

@ -5,21 +5,25 @@ use writer_spec;
use crc32; use crc32;
use result::{ZipResult, ZipError}; use result::{ZipResult, ZipError};
use std::default::Default; 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 std::mem;
use time; use time;
use flate2; use flate2;
use flate2::FlateWriter; use flate2::FlateWriteExt;
use flate2::writer::DeflateEncoder; use flate2::write::DeflateEncoder;
use bzip2; use bzip2;
use bzip2::writer::BzCompressor; use bzip2::writer::BzCompressor;
use ioconverter::IoConverter;
enum GenericZipWriter<W> enum GenericZipWriter<W>
{ {
Closed, Closed,
Storer(W), Storer(W),
Deflater(DeflateEncoder<W>), Deflater(DeflateEncoder<W>),
Bzip2(BzCompressor<W>), Bzip2(IoConverter<BzCompressor<IoConverter<W>>>),
} }
/// Generator for ZIP files. /// Generator for ZIP files.
@ -27,13 +31,15 @@ enum GenericZipWriter<W>
/// ``` /// ```
/// fn doit() -> zip::result::ZipResult<()> /// fn doit() -> zip::result::ZipResult<()>
/// { /// {
/// use std::io::Write;
///
/// // For this example we write to a buffer, but normally you should use a File /// // For this example we write to a buffer, but normally you should use a File
/// let mut buf = [0u8; 65536]; /// let mut buf: &mut [u8] = &mut [0u8; 65536];
/// let w = std::old_io::BufWriter::new(&mut buf); /// let mut w = std::io::Cursor::new(buf);
/// let mut zip = zip::ZipWriter::new(w); /// let mut zip = zip::ZipWriter::new(w);
/// ///
/// try!(zip.start_file("hello_world.txt", zip::CompressionMethod::Stored)); /// 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) /// // Optionally finish the zip. (this is also done on drop)
/// try!(zip.finish()); /// try!(zip.finish());
@ -58,18 +64,27 @@ struct ZipWriterStats
bytes_written: u64, bytes_written: u64,
} }
impl<W: Writer+Seek> Writer for ZipWriter<W> impl<W: Write+Seek> Write for ZipWriter<W>
{ {
fn write_all(&mut self, buf: &[u8]) -> old_io::IoResult<()> fn write(&mut self, buf: &[u8]) -> io::Result<usize>
{ {
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); self.stats.update(buf);
match self.inner match self.inner
{ {
GenericZipWriter::Storer(ref mut w) => w.write_all(buf), GenericZipWriter::Storer(ref mut w) => w.write(buf),
GenericZipWriter::Deflater(ref mut w) => w.write_all(buf), GenericZipWriter::Deflater(ref mut w) => w.write(buf),
GenericZipWriter::Bzip2(ref mut w) => w.write_all(buf), GenericZipWriter::Bzip2(ref mut w) => w.write(buf),
GenericZipWriter::Closed => Err(old_io::standard_error(old_io::Closed)), 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<W: Writer+Seek> ZipWriter<W> impl<W: Write+Seek> ZipWriter<W>
{ {
/// Initializes the ZipWriter. /// Initializes the ZipWriter.
/// ///
@ -105,7 +120,7 @@ impl<W: Writer+Seek> ZipWriter<W>
{ {
let writer = self.inner.get_plain(); 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 let mut file = ZipFile
{ {
@ -120,9 +135,11 @@ impl<W: Writer+Seek> ZipWriter<W>
header_start: header_start, header_start: header_start,
data_start: 0, 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; self.stats.start = header_end;
file.data_start = header_end; file.data_start = header_end;
@ -149,10 +166,12 @@ impl<W: Writer+Seek> ZipWriter<W>
}; };
file.crc32 = self.stats.crc32; file.crc32 = self.stats.crc32;
file.uncompressed_size = self.stats.bytes_written; 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)); let mut conv_w = IoConverter::new(writer);
try!(writer.seek(0, old_io::SeekEnd)); 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(()) Ok(())
} }
@ -174,12 +193,14 @@ impl<W: Writer+Seek> ZipWriter<W>
{ {
let writer = self.inner.get_plain(); 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() 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 let footer = spec::CentralDirectoryEnd
{ {
@ -192,7 +213,7 @@ impl<W: Writer+Seek> ZipWriter<W>
zip_file_comment: b"zip-rs".to_vec(), zip_file_comment: b"zip-rs".to_vec(),
}; };
try!(footer.write(writer)); try!(footer.write(&mut IoConverter::new(writer)));
} }
Ok(()) Ok(())
@ -200,20 +221,20 @@ impl<W: Writer+Seek> ZipWriter<W>
} }
#[unsafe_destructor] #[unsafe_destructor]
impl<W: Writer+Seek> Drop for ZipWriter<W> impl<W: Write+Seek> Drop for ZipWriter<W>
{ {
fn drop(&mut self) fn drop(&mut self)
{ {
if !self.inner.is_closed() if !self.inner.is_closed()
{ {
if let Err(e) = self.finalize() { 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<W: Writer+Seek> GenericZipWriter<W> impl<W: Write+Seek> GenericZipWriter<W>
{ {
fn switch_to(&mut self, compression: CompressionMethod) -> ZipResult<()> fn switch_to(&mut self, compression: CompressionMethod) -> ZipResult<()>
{ {
@ -221,15 +242,15 @@ impl<W: Writer+Seek> GenericZipWriter<W>
{ {
GenericZipWriter::Storer(w) => w, GenericZipWriter::Storer(w) => w,
GenericZipWriter::Deflater(w) => try!(w.finish()), GenericZipWriter::Deflater(w) => try!(w.finish()),
GenericZipWriter::Bzip2(w) => match w.into_inner() { Ok(r) => r, Err((_, err)) => try!(Err(err)) }, GenericZipWriter::Bzip2(w) => match w.into_inner().into_inner() { Ok(r) => r.into_inner(), Err((_, err)) => try!(Err(err)) },
GenericZipWriter::Closed => try!(Err(old_io::standard_error(old_io::Closed))), GenericZipWriter::Closed => try!(Err(io::Error::new(io::ErrorKind::BrokenPipe, "ZipWriter was already closed", None))),
}; };
*self = match compression *self = match compression
{ {
CompressionMethod::Stored => GenericZipWriter::Storer(bare), CompressionMethod::Stored => GenericZipWriter::Storer(bare),
CompressionMethod::Deflated => GenericZipWriter::Deflater(bare.deflate_encode(flate2::CompressionLevel::Default)), CompressionMethod::Deflated => GenericZipWriter::Deflater(bare.deflate_encode(flate2::Compression::Default)),
CompressionMethod::Bzip2 => GenericZipWriter::Bzip2(BzCompressor::new(bare, bzip2::CompressionLevel::Default)), CompressionMethod::Bzip2 => GenericZipWriter::Bzip2(IoConverter::new(BzCompressor::new(IoConverter::new(bare), bzip2::CompressionLevel::Default))),
_ => return Err(ZipError::UnsupportedZipFile("Unsupported compression")), _ => return Err(ZipError::UnsupportedZipFile("Unsupported compression")),
}; };

View file

@ -1,4 +1,5 @@
use std::old_io; use std::old_io;
use std::io::prelude::*;
use std::ascii::AsciiExt; use std::ascii::AsciiExt;
use types::ZipFile; use types::ZipFile;
use result::ZipResult; use result::ZipResult;