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)
{
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::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 file = std::io::File::create(&path).unwrap();

View file

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

View file

@ -3,15 +3,15 @@ use types::ZipFile;
use compression;
use spec;
use reader_spec;
use result::ZipResult;
use std::io;
use std::io::{IoResult, IoError};
use std::cell::RefCell;
use flate2::FlateReader;
/// 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.
/// // Normally a File object would be used.
@ -38,20 +38,15 @@ pub struct ZipReader<T>
files: Vec<ZipFile>,
}
fn unsupported_zip_error<T>(detail: &str) -> IoResult<T>
fn unsupported_zip_error<T>(detail: &'static str) -> ZipResult<T>
{
Err(IoError
{
kind: io::OtherIoError,
desc: "This ZIP file is not supported",
detail: Some(detail.to_string()),
})
Err(::result::UnsupportedZipFile(detail))
}
impl<T: Reader+Seek> ZipReader<T>
{
/// 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));
@ -79,21 +74,13 @@ impl<T: Reader+Seek> ZipReader<T>
/// Gets a reader for a contained zipfile.
///
/// Possible errors:
///
/// * `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>>
/// May return `ReaderUnavailable` if there is another reader borrowed.
pub fn read_file(&self, file: &ZipFile) -> ZipResult<Box<Reader>>
{
let mut inner_reader = match self.inner.try_borrow_mut()
{
Some(reader) => reader,
None => return Err(IoError
{
kind: io::ResourceUnavailable,
desc: "There is already a ZIP reader active",
detail: None
}),
None => return Err(::result::ReaderUnavailable),
};
let pos = file.data_start as i64;

View file

@ -1,20 +1,17 @@
use std::io;
use std::io::{IoResult, IoError};
use result::ZipResult;
use compression;
use types::ZipFile;
use spec;
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
let signature = try!(reader.read_le_u32());
if signature != spec::CENTRAL_DIRECTORY_HEADER_SIGNATURE
{
return Err(IoError {
kind: io::MismatchedFileTypeForOperation,
desc: "Invalid central directory header",
detail: None })
return Err(::result::InvalidZipFile("Invalid Central Directory header"))
}
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());
if signature != spec::LOCAL_FILE_HEADER_SIGNATURE
{
return Err(IoError {
kind: io::MismatchedFileTypeForOperation,
desc: "Invalid local file header",
detail: None })
return Err(::result::InvalidZipFile("Invalid local file header"))
}
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)
}
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);
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::{IoResult, IoError};
use result::ZipResult;
use std::iter::range_step_inclusive;
pub static LOCAL_FILE_HEADER_SIGNATURE : u32 = 0x04034b50;
@ -19,15 +19,12 @@ pub struct 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());
if magic != CENTRAL_DIRECTORY_END_SIGNATURE
{
return Err(IoError {
kind: io::MismatchedFileTypeForOperation,
desc: "Invalid digital signature header",
detail: None })
return Err(::result::UnsupportedZipFile("Invalid digital signature header"))
}
let disk_number = 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 bytes_between_magic_and_comment_size = header_size - 6;
@ -72,15 +69,10 @@ impl CentralDirectoryEnd
}
}
}
Err(IoError
{
kind: io::MismatchedFileTypeForOperation,
desc: "Could not find central directory end",
detail: None
})
Err(::result::UnsupportedZipFile("Could not find central directory end"))
}
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_u16(self.disk_number));

View file

@ -3,9 +3,9 @@ use types::ZipFile;
use spec;
use writer_spec;
use crc32;
use result::ZipResult;
use std::default::Default;
use std::io;
use std::io::{IoResult, IoError};
use std::mem;
use time;
use flate2;
@ -22,7 +22,7 @@ enum GenericZipWriter<W>
/// 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
/// let mut buf = [0u8, ..65536];
@ -55,22 +55,17 @@ struct ZipWriterStats
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>
{
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);
match self.inner
{
Storer(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.
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());
@ -138,7 +133,7 @@ impl<W: Writer+Seek> ZipWriter<W>
Ok(())
}
fn finish_file(&mut self) -> IoResult<()>
fn finish_file(&mut self) -> ZipResult<()>
{
try!(self.inner.switch_to(compression::Stored));
let writer = self.inner.get_plain();
@ -159,16 +154,16 @@ impl<W: Writer+Seek> ZipWriter<W>
/// Finish the last file and write all other zip-structures
///
/// 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.
pub fn finish(mut self) -> IoResult<W>
pub fn finish(mut self) -> ZipResult<W>
{
try!(self.finalize());
let inner = mem::replace(&mut self.inner, Closed);
Ok(inner.unwrap())
}
fn finalize(&mut self) -> IoResult<()>
fn finalize(&mut self) -> ZipResult<()>
{
try!(self.finish_file());
@ -218,20 +213,20 @@ impl<W: Writer+Seek> Drop for ZipWriter<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)
{
Storer(w) => w,
Deflater(w) => try!(w.finish()),
Closed => return writer_closed_error(),
Closed => try!(Err(io::standard_error(io::Closed))),
};
*self = match compression
{
compression::Stored => Storer(bare),
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(())

View file

@ -1,10 +1,10 @@
use std::io;
use std::io::IoResult;
use types::ZipFile;
use result::ZipResult;
use spec;
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_u16(20));
@ -25,7 +25,7 @@ pub fn write_local_file_header<T: Writer>(writer: &mut T, file: &ZipFile) -> IoR
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;
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(())
}
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_u16(0x14FF));
@ -62,7 +62,7 @@ pub fn write_central_directory_header<T: Writer>(writer: &mut T, file: &ZipFile)
Ok(())
}
fn build_extra_field(_file: &ZipFile) -> IoResult<Vec<u8>>
fn build_extra_field(_file: &ZipFile) -> ZipResult<Vec<u8>>
{
let writer = io::MemWriter::new();
// Future work