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:
parent
a525bd4e34
commit
2e8baed799
9 changed files with 183 additions and 41 deletions
|
@ -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 = "*"
|
||||
|
|
|
@ -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
89
src/ioconverter.rs
Normal 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)),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
12
src/util.rs
12
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<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>
|
||||
|
|
|
@ -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")),
|
||||
};
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use std::old_io;
|
||||
use std::io::prelude::*;
|
||||
use std::ascii::AsciiExt;
|
||||
use types::ZipFile;
|
||||
use result::ZipResult;
|
||||
|
|
Loading…
Add table
Reference in a new issue