Added ZipResult/ZipError

This commit is contained in:
Mathijs van de Nes 2014-11-08 21:55:15 +01:00
parent 71dfafb583
commit 2163db4b25
9 changed files with 105 additions and 71 deletions

View file

@ -35,7 +35,7 @@ fn main()
fn write_file(zipcontainer: &zip::ZipReader<std::io::File>, file: &zip::ZipFile, outpath: Path) fn write_file(zipcontainer: &zip::ZipReader<std::io::File>, file: &zip::ZipFile, outpath: Path)
{ {
let mut outfile = std::io::File::create(&outpath); let mut outfile = std::io::File::create(&outpath);
let mut reader = zipcontainer.read_file(file); let mut reader = zipcontainer.read_file(file).unwrap();
std::io::util::copy(&mut reader, &mut outfile).unwrap(); std::io::util::copy(&mut reader, &mut outfile).unwrap();
std::io::fs::chmod(&outpath, std::io::USER_FILE).unwrap(); std::io::fs::chmod(&outpath, std::io::USER_FILE).unwrap();
} }

View file

@ -17,7 +17,7 @@ fn main()
} }
} }
fn doit(filename: &str) -> std::io::IoResult<()> fn doit(filename: &str) -> zip::result::ZipResult<()>
{ {
let path = Path::new(filename); let path = Path::new(filename);
let file = std::io::File::create(&path).unwrap(); let file = std::io::File::create(&path).unwrap();

View file

@ -22,3 +22,4 @@ mod types;
pub mod compression; pub mod compression;
mod writer; mod writer;
mod cp437; mod cp437;
pub mod result;

View file

@ -3,15 +3,15 @@ use types::ZipFile;
use compression; use compression;
use spec; use spec;
use reader_spec; use reader_spec;
use result::ZipResult;
use std::io; use std::io;
use std::io::{IoResult, IoError};
use std::cell::RefCell; use std::cell::RefCell;
use flate2::FlateReader; use flate2::FlateReader;
/// Wrapper for reading the contents of a ZIP file. /// Wrapper for reading the contents of a ZIP file.
/// ///
/// ``` /// ```
/// fn doit() -> std::io::IoResult<()> /// fn doit() -> zip::result::ZipResult<()>
/// { /// {
/// // For demonstration purposes we read from an empty buffer. /// // For demonstration purposes we read from an empty buffer.
/// // Normally a File object would be used. /// // Normally a File object would be used.
@ -38,20 +38,15 @@ pub struct ZipReader<T>
files: Vec<ZipFile>, files: Vec<ZipFile>,
} }
fn unsupported_zip_error<T>(detail: &str) -> IoResult<T> fn unsupported_zip_error<T>(detail: &'static str) -> ZipResult<T>
{ {
Err(IoError Err(::result::UnsupportedZipFile(detail))
{
kind: io::OtherIoError,
desc: "This ZIP file is not supported",
detail: Some(detail.to_string()),
})
} }
impl<T: Reader+Seek> ZipReader<T> impl<T: Reader+Seek> ZipReader<T>
{ {
/// Opens a ZIP file and parses the content headers. /// Opens a ZIP file and parses the content headers.
pub fn new(mut reader: T) -> IoResult<ZipReader<T>> pub fn new(mut reader: T) -> ZipResult<ZipReader<T>>
{ {
let footer = try!(spec::CentralDirectoryEnd::find_and_parse(&mut reader)); let footer = try!(spec::CentralDirectoryEnd::find_and_parse(&mut reader));
@ -79,21 +74,13 @@ impl<T: Reader+Seek> ZipReader<T>
/// Gets a reader for a contained zipfile. /// Gets a reader for a contained zipfile.
/// ///
/// Possible errors: /// May return `ReaderUnavailable` if there is another reader borrowed.
/// pub fn read_file(&self, file: &ZipFile) -> ZipResult<Box<Reader>>
/// * `ResourceUnavailable`: when another reader returned from this function is still active
/// * `OtherIoError`: if the file is encrypted or has an unsupported compression
pub fn read_file(&self, file: &ZipFile) -> IoResult<Box<Reader>>
{ {
let mut inner_reader = match self.inner.try_borrow_mut() let mut inner_reader = match self.inner.try_borrow_mut()
{ {
Some(reader) => reader, Some(reader) => reader,
None => return Err(IoError None => return Err(::result::ReaderUnavailable),
{
kind: io::ResourceUnavailable,
desc: "There is already a ZIP reader active",
detail: None
}),
}; };
let pos = file.data_start as i64; let pos = file.data_start as i64;

View file

@ -1,20 +1,17 @@
use std::io; use std::io;
use std::io::{IoResult, IoError}; use result::ZipResult;
use compression; use compression;
use types::ZipFile; use types::ZipFile;
use spec; use spec;
use util; use util;
pub fn central_header_to_zip_file<R: Reader+Seek>(reader: &mut R) -> IoResult<ZipFile> pub fn central_header_to_zip_file<R: Reader+Seek>(reader: &mut R) -> ZipResult<ZipFile>
{ {
// Parse central header // Parse central header
let signature = try!(reader.read_le_u32()); let signature = try!(reader.read_le_u32());
if signature != spec::CENTRAL_DIRECTORY_HEADER_SIGNATURE if signature != spec::CENTRAL_DIRECTORY_HEADER_SIGNATURE
{ {
return Err(IoError { return Err(::result::InvalidZipFile("Invalid Central Directory header"))
kind: io::MismatchedFileTypeForOperation,
desc: "Invalid central directory header",
detail: None })
} }
try!(reader.read_le_u16()); try!(reader.read_le_u16());
@ -58,10 +55,7 @@ pub fn central_header_to_zip_file<R: Reader+Seek>(reader: &mut R) -> IoResult<Zi
let signature = try!(reader.read_le_u32()); let signature = try!(reader.read_le_u32());
if signature != spec::LOCAL_FILE_HEADER_SIGNATURE if signature != spec::LOCAL_FILE_HEADER_SIGNATURE
{ {
return Err(IoError { return Err(::result::InvalidZipFile("Invalid local file header"))
kind: io::MismatchedFileTypeForOperation,
desc: "Invalid local file header",
detail: None })
} }
try!(reader.seek(22, io::SeekCur)); try!(reader.seek(22, io::SeekCur));
@ -93,7 +87,7 @@ pub fn central_header_to_zip_file<R: Reader+Seek>(reader: &mut R) -> IoResult<Zi
Ok(result) Ok(result)
} }
fn parse_extra_field(_file: &mut ZipFile, data: &[u8]) -> IoResult<()> fn parse_extra_field(_file: &mut ZipFile, data: &[u8]) -> ZipResult<()>
{ {
let mut reader = io::BufReader::new(data); let mut reader = io::BufReader::new(data);
while !reader.eof() while !reader.eof()

65
src/result.rs Normal file
View file

@ -0,0 +1,65 @@
//! Error types that can be emitted from this library
use std::io;
use std::error;
pub type ZipResult<T> = Result<T, ZipError>;
/// Error type for Zip
#[deriving(Show)]
pub enum ZipError
{
/// An Error caused by I/O
Io(io::IoError),
/// This file is probably not a zipfile. The argument is enclosed.
InvalidZipFile(&'static str),
/// This file is unsupported. The reason is enclosed.
UnsupportedZipFile(&'static str),
/// The ZipReader is not available.
ReaderUnavailable,
}
impl error::FromError<io::IoError> for ZipError
{
fn from_error(err: io::IoError) -> ZipError
{
Io(err)
}
}
impl error::Error for ZipError
{
fn description(&self) -> &str
{
match *self
{
Io(ref io_err) => io_err.description(),
InvalidZipFile(..) => "Invalid Zip File",
UnsupportedZipFile(..) => "Unsupported Zip File",
ReaderUnavailable => "No reader available",
}
}
fn detail(&self) -> Option<String>
{
match *self
{
Io(ref io_err) => io_err.detail(),
InvalidZipFile(detail) |
UnsupportedZipFile(detail) => Some(detail.to_string()),
ReaderUnavailable => None,
}
}
fn cause(&self) -> Option<&error::Error>
{
match *self
{
Io(ref io_err) => Some(io_err as &error::Error),
_ => None,
}
}
}

View file

@ -1,5 +1,5 @@
use std::io; use std::io;
use std::io::{IoResult, IoError}; use result::ZipResult;
use std::iter::range_step_inclusive; use std::iter::range_step_inclusive;
pub static LOCAL_FILE_HEADER_SIGNATURE : u32 = 0x04034b50; pub static LOCAL_FILE_HEADER_SIGNATURE : u32 = 0x04034b50;
@ -19,15 +19,12 @@ pub struct CentralDirectoryEnd
impl CentralDirectoryEnd impl CentralDirectoryEnd
{ {
pub fn parse<T: Reader>(reader: &mut T) -> IoResult<CentralDirectoryEnd> pub fn parse<T: Reader>(reader: &mut T) -> ZipResult<CentralDirectoryEnd>
{ {
let magic = try!(reader.read_le_u32()); let magic = try!(reader.read_le_u32());
if magic != CENTRAL_DIRECTORY_END_SIGNATURE if magic != CENTRAL_DIRECTORY_END_SIGNATURE
{ {
return Err(IoError { return Err(::result::UnsupportedZipFile("Invalid digital signature header"))
kind: io::MismatchedFileTypeForOperation,
desc: "Invalid digital signature header",
detail: None })
} }
let disk_number = try!(reader.read_le_u16()); let disk_number = try!(reader.read_le_u16());
let disk_with_central_directory = try!(reader.read_le_u16()); let disk_with_central_directory = try!(reader.read_le_u16());
@ -50,7 +47,7 @@ impl CentralDirectoryEnd
}) })
} }
pub fn find_and_parse<T: Reader+Seek>(reader: &mut T) -> IoResult<CentralDirectoryEnd> pub fn find_and_parse<T: Reader+Seek>(reader: &mut T) -> ZipResult<CentralDirectoryEnd>
{ {
let header_size = 22; let header_size = 22;
let bytes_between_magic_and_comment_size = header_size - 6; let bytes_between_magic_and_comment_size = header_size - 6;
@ -72,15 +69,10 @@ impl CentralDirectoryEnd
} }
} }
} }
Err(IoError Err(::result::UnsupportedZipFile("Could not find central directory end"))
{
kind: io::MismatchedFileTypeForOperation,
desc: "Could not find central directory end",
detail: None
})
} }
pub fn write<T: Writer>(&self, writer: &mut T) -> IoResult<()> pub fn write<T: Writer>(&self, writer: &mut T) -> ZipResult<()>
{ {
try!(writer.write_le_u32(CENTRAL_DIRECTORY_END_SIGNATURE)); try!(writer.write_le_u32(CENTRAL_DIRECTORY_END_SIGNATURE));
try!(writer.write_le_u16(self.disk_number)); try!(writer.write_le_u16(self.disk_number));

View file

@ -3,9 +3,9 @@ use types::ZipFile;
use spec; use spec;
use writer_spec; use writer_spec;
use crc32; use crc32;
use result::ZipResult;
use std::default::Default; use std::default::Default;
use std::io; use std::io;
use std::io::{IoResult, IoError};
use std::mem; use std::mem;
use time; use time;
use flate2; use flate2;
@ -22,7 +22,7 @@ enum GenericZipWriter<W>
/// Generator for ZIP files. /// Generator for ZIP files.
/// ///
/// ``` /// ```
/// fn doit() -> std::io::IoResult<()> /// fn doit() -> zip::result::ZipResult<()>
/// { /// {
/// // 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 = [0u8, ..65536];
@ -55,22 +55,17 @@ struct ZipWriterStats
bytes_written: u64, bytes_written: u64,
} }
fn writer_closed_error<T>() -> IoResult<T>
{
Err(IoError { kind: io::Closed, desc: "This writer has been closed", detail: None })
}
impl<W: Writer+Seek> Writer for ZipWriter<W> impl<W: Writer+Seek> Writer for ZipWriter<W>
{ {
fn write(&mut self, buf: &[u8]) -> IoResult<()> fn write(&mut self, buf: &[u8]) -> io::IoResult<()>
{ {
if self.files.len() == 0 { return Err(IoError { kind: io::OtherIoError, desc: "No file has been started", detail: None, }) } if self.files.len() == 0 { return Err(io::IoError { kind: io::OtherIoError, desc: "No file has been started", detail: None, }) }
self.stats.update(buf); self.stats.update(buf);
match self.inner match self.inner
{ {
Storer(ref mut w) => w.write(buf), Storer(ref mut w) => w.write(buf),
Deflater(ref mut w) => w.write(buf), Deflater(ref mut w) => w.write(buf),
Closed => writer_closed_error(), Closed => Err(io::standard_error(io::Closed)),
} }
} }
} }
@ -100,7 +95,7 @@ impl<W: Writer+Seek> ZipWriter<W>
} }
/// Start a new file for with the requested compression method. /// Start a new file for with the requested compression method.
pub fn start_file(&mut self, name: &str, compression: compression::CompressionMethod) -> IoResult<()> pub fn start_file(&mut self, name: &str, compression: compression::CompressionMethod) -> ZipResult<()>
{ {
try!(self.finish_file()); try!(self.finish_file());
@ -138,7 +133,7 @@ impl<W: Writer+Seek> ZipWriter<W>
Ok(()) Ok(())
} }
fn finish_file(&mut self) -> IoResult<()> fn finish_file(&mut self) -> ZipResult<()>
{ {
try!(self.inner.switch_to(compression::Stored)); try!(self.inner.switch_to(compression::Stored));
let writer = self.inner.get_plain(); let writer = self.inner.get_plain();
@ -161,14 +156,14 @@ impl<W: Writer+Seek> ZipWriter<W>
/// ///
/// This will return the writer, but one should normally not append any data to the end of the file. /// This will return the writer, but one should normally not append any data to the end of the file.
/// Note that the zipfile will also be finished on drop. /// Note that the zipfile will also be finished on drop.
pub fn finish(mut self) -> IoResult<W> pub fn finish(mut self) -> ZipResult<W>
{ {
try!(self.finalize()); try!(self.finalize());
let inner = mem::replace(&mut self.inner, Closed); let inner = mem::replace(&mut self.inner, Closed);
Ok(inner.unwrap()) Ok(inner.unwrap())
} }
fn finalize(&mut self) -> IoResult<()> fn finalize(&mut self) -> ZipResult<()>
{ {
try!(self.finish_file()); try!(self.finish_file());
@ -218,20 +213,20 @@ impl<W: Writer+Seek> Drop for ZipWriter<W>
impl<W: Writer+Seek> GenericZipWriter<W> impl<W: Writer+Seek> GenericZipWriter<W>
{ {
fn switch_to(&mut self, compression: compression::CompressionMethod) -> IoResult<()> fn switch_to(&mut self, compression: compression::CompressionMethod) -> ZipResult<()>
{ {
let bare = match mem::replace(self, Closed) let bare = match mem::replace(self, Closed)
{ {
Storer(w) => w, Storer(w) => w,
Deflater(w) => try!(w.finish()), Deflater(w) => try!(w.finish()),
Closed => return writer_closed_error(), Closed => try!(Err(io::standard_error(io::Closed))),
}; };
*self = match compression *self = match compression
{ {
compression::Stored => Storer(bare), compression::Stored => Storer(bare),
compression::Deflated => Deflater(bare.deflate_encode(flate2::Default)), compression::Deflated => Deflater(bare.deflate_encode(flate2::Default)),
_ => return Err(IoError { kind: io::OtherIoError, desc: "Unsupported compression requested", detail: None }), _ => return Err(::result::UnsupportedZipFile("Unsupported compression")),
}; };
Ok(()) Ok(())

View file

@ -1,10 +1,10 @@
use std::io; use std::io;
use std::io::IoResult;
use types::ZipFile; use types::ZipFile;
use result::ZipResult;
use spec; use spec;
use util; use util;
pub fn write_local_file_header<T: Writer>(writer: &mut T, file: &ZipFile) -> IoResult<()> pub fn write_local_file_header<T: Writer>(writer: &mut T, file: &ZipFile) -> ZipResult<()>
{ {
try!(writer.write_le_u32(spec::LOCAL_FILE_HEADER_SIGNATURE)); try!(writer.write_le_u32(spec::LOCAL_FILE_HEADER_SIGNATURE));
try!(writer.write_le_u16(20)); try!(writer.write_le_u16(20));
@ -25,7 +25,7 @@ pub fn write_local_file_header<T: Writer>(writer: &mut T, file: &ZipFile) -> IoR
Ok(()) Ok(())
} }
pub fn update_local_file_header<T: Writer+Seek>(writer: &mut T, file: &ZipFile) -> IoResult<()> pub fn update_local_file_header<T: Writer+Seek>(writer: &mut T, file: &ZipFile) -> ZipResult<()>
{ {
static CRC32_OFFSET : i64 = 14; static CRC32_OFFSET : i64 = 14;
try!(writer.seek(file.header_start as i64 + CRC32_OFFSET, io::SeekSet)); try!(writer.seek(file.header_start as i64 + CRC32_OFFSET, io::SeekSet));
@ -35,7 +35,7 @@ pub fn update_local_file_header<T: Writer+Seek>(writer: &mut T, file: &ZipFile)
Ok(()) Ok(())
} }
pub fn write_central_directory_header<T: Writer>(writer: &mut T, file: &ZipFile) -> IoResult<()> pub fn write_central_directory_header<T: Writer>(writer: &mut T, file: &ZipFile) -> ZipResult<()>
{ {
try!(writer.write_le_u32(spec::CENTRAL_DIRECTORY_HEADER_SIGNATURE)); try!(writer.write_le_u32(spec::CENTRAL_DIRECTORY_HEADER_SIGNATURE));
try!(writer.write_le_u16(0x14FF)); try!(writer.write_le_u16(0x14FF));
@ -62,7 +62,7 @@ pub fn write_central_directory_header<T: Writer>(writer: &mut T, file: &ZipFile)
Ok(()) Ok(())
} }
fn build_extra_field(_file: &ZipFile) -> IoResult<Vec<u8>> fn build_extra_field(_file: &ZipFile) -> ZipResult<Vec<u8>>
{ {
let writer = io::MemWriter::new(); let writer = io::MemWriter::new();
// Future work // Future work