diff --git a/src/bin/extract.rs b/src/bin/extract.rs index cfec8953..1d9df0f0 100644 --- a/src/bin/extract.rs +++ b/src/bin/extract.rs @@ -35,7 +35,7 @@ fn main() fn write_file(zipcontainer: &zip::ZipReader, 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(); } diff --git a/src/bin/write_sample.rs b/src/bin/write_sample.rs index d20a88be..a87dc4e9 100644 --- a/src/bin/write_sample.rs +++ b/src/bin/write_sample.rs @@ -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(); diff --git a/src/lib.rs b/src/lib.rs index ec1962ee..8d1e4838 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,3 +22,4 @@ mod types; pub mod compression; mod writer; mod cp437; +pub mod result; diff --git a/src/reader.rs b/src/reader.rs index f418ea1b..850320aa 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -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 files: Vec, } -fn unsupported_zip_error(detail: &str) -> IoResult +fn unsupported_zip_error(detail: &'static str) -> ZipResult { - Err(IoError - { - kind: io::OtherIoError, - desc: "This ZIP file is not supported", - detail: Some(detail.to_string()), - }) + Err(::result::UnsupportedZipFile(detail)) } impl ZipReader { /// Opens a ZIP file and parses the content headers. - pub fn new(mut reader: T) -> IoResult> + pub fn new(mut reader: T) -> ZipResult> { let footer = try!(spec::CentralDirectoryEnd::find_and_parse(&mut reader)); @@ -79,21 +74,13 @@ impl ZipReader /// 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> + /// May return `ReaderUnavailable` if there is another reader borrowed. + pub fn read_file(&self, file: &ZipFile) -> ZipResult> { 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; diff --git a/src/reader_spec.rs b/src/reader_spec.rs index 70c4aaa9..48035652 100644 --- a/src/reader_spec.rs +++ b/src/reader_spec.rs @@ -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(reader: &mut R) -> IoResult +pub fn central_header_to_zip_file(reader: &mut R) -> ZipResult { // 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(reader: &mut R) -> IoResult(reader: &mut R) -> IoResult IoResult<()> +fn parse_extra_field(_file: &mut ZipFile, data: &[u8]) -> ZipResult<()> { let mut reader = io::BufReader::new(data); while !reader.eof() diff --git a/src/result.rs b/src/result.rs new file mode 100644 index 00000000..3bf30d0e --- /dev/null +++ b/src/result.rs @@ -0,0 +1,65 @@ +//! Error types that can be emitted from this library + +use std::io; +use std::error; + +pub type ZipResult = Result; + +/// 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 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 + { + 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, + } + } +} diff --git a/src/spec.rs b/src/spec.rs index b938dfe3..c8292574 100644 --- a/src/spec.rs +++ b/src/spec.rs @@ -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(reader: &mut T) -> IoResult + pub fn parse(reader: &mut T) -> ZipResult { 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(reader: &mut T) -> IoResult + pub fn find_and_parse(reader: &mut T) -> ZipResult { 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(&self, writer: &mut T) -> IoResult<()> + pub fn write(&self, writer: &mut T) -> ZipResult<()> { try!(writer.write_le_u32(CENTRAL_DIRECTORY_END_SIGNATURE)); try!(writer.write_le_u16(self.disk_number)); diff --git a/src/writer.rs b/src/writer.rs index e89a1d6e..17edeffa 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -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 /// 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() -> IoResult -{ - Err(IoError { kind: io::Closed, desc: "This writer has been closed", detail: None }) -} - impl Writer for ZipWriter { - 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 ZipWriter } /// 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 ZipWriter 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 ZipWriter /// 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 + pub fn finish(mut self) -> ZipResult { 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 Drop for ZipWriter impl GenericZipWriter { - 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(()) diff --git a/src/writer_spec.rs b/src/writer_spec.rs index 54bf2e2a..f3735fe5 100644 --- a/src/writer_spec.rs +++ b/src/writer_spec.rs @@ -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(writer: &mut T, file: &ZipFile) -> IoResult<()> +pub fn write_local_file_header(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(writer: &mut T, file: &ZipFile) -> IoR Ok(()) } -pub fn update_local_file_header(writer: &mut T, file: &ZipFile) -> IoResult<()> +pub fn update_local_file_header(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(writer: &mut T, file: &ZipFile) Ok(()) } -pub fn write_central_directory_header(writer: &mut T, file: &ZipFile) -> IoResult<()> +pub fn write_central_directory_header(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(writer: &mut T, file: &ZipFile) Ok(()) } -fn build_extra_field(_file: &ZipFile) -> IoResult> +fn build_extra_field(_file: &ZipFile) -> ZipResult> { let writer = io::MemWriter::new(); // Future work