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]
name = "zip"
version = "0.0.12"
version = "0.1.0"
authors = ["Mathijs van de Nes <git@mathijs.vd-nes.nl>"]
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 = "*"

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;
@ -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);

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)]
#![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;

View file

@ -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<T: Reader+Seek> ZipReader<T>
},
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,

View file

@ -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<T> = Result<T, ZipError>;
#[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<IoError> for 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)
}
@ -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,
}

View file

@ -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<usize>
{
self.inner.read(buf)
}
}
impl<'a, R: Reader> Reader for RefMutReader<'a, R>
{
fn read(&mut self, buf: &mut [u8]) -> ::std::old_io::IoResult<usize>

View file

@ -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<W>
{
Closed,
Storer(W),
Deflater(DeflateEncoder<W>),
Bzip2(BzCompressor<W>),
Bzip2(IoConverter<BzCompressor<IoConverter<W>>>),
}
/// Generator for ZIP files.
@ -27,13 +31,15 @@ enum GenericZipWriter<W>
/// ```
/// 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<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);
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<W: Writer+Seek> ZipWriter<W>
impl<W: Write+Seek> ZipWriter<W>
{
/// Initializes the ZipWriter.
///
@ -105,7 +120,7 @@ impl<W: Writer+Seek> ZipWriter<W>
{
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<W: Writer+Seek> ZipWriter<W>
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<W: Writer+Seek> ZipWriter<W>
};
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<W: Writer+Seek> ZipWriter<W>
{
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<W: Writer+Seek> ZipWriter<W>
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<W: Writer+Seek> ZipWriter<W>
}
#[unsafe_destructor]
impl<W: Writer+Seek> Drop for ZipWriter<W>
impl<W: Write+Seek> Drop for ZipWriter<W>
{
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<W: Writer+Seek> GenericZipWriter<W>
impl<W: Write+Seek> GenericZipWriter<W>
{
fn switch_to(&mut self, compression: CompressionMethod) -> ZipResult<()>
{
@ -221,15 +242,15 @@ impl<W: Writer+Seek> GenericZipWriter<W>
{
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")),
};

View file

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