diff --git a/examples/extract.rs b/examples/extract.rs index 5b13531f..7e32f987 100644 --- a/examples/extract.rs +++ b/examples/extract.rs @@ -16,32 +16,34 @@ fn main() let fname = Path::new(&*args[1]); let file = fs::File::open(&fname).unwrap(); - let zipcontainer = zip::ZipReader::new(file).unwrap(); + let mut archive = zip::ZipArchive::new(file).unwrap(); - for file in zipcontainer.files() + for i in 1..archive.len() { - let outpath = sanitize_filename(&*file.file_name); + let mut file = archive.by_index(i).unwrap(); + let outpath = sanitize_filename(file.name()); println!("{}", outpath.display()); - let comment = &file.file_comment; - if comment.len() > 0 { println!(" File comment: {}", comment); } + { + let comment = file.comment(); + if comment.len() > 0 { println!(" File comment: {}", comment); } + } fs::create_dir_all(&outpath.dir_path()).unwrap(); - if (&*file.file_name).ends_with("/") { + if (&*file.name()).ends_with("/") { create_directory(outpath); } else { - write_file(&zipcontainer, file, outpath); + write_file(&mut file, outpath); } } } -fn write_file(zipcontainer: &zip::ZipReader, file: &zip::ZipFile, outpath: Path) +fn write_file(reader: &mut zip::read::ZipFileReader, outpath: Path) { let mut outfile = fs::File::create(&outpath).unwrap(); - let mut reader = zipcontainer.read_file(file).unwrap(); - io::copy(&mut reader, &mut outfile).unwrap(); + io::copy(reader, &mut outfile).unwrap(); } fn create_directory(outpath: Path) diff --git a/examples/extract_lorem.rs b/examples/extract_lorem.rs index f9169363..e9aff77e 100644 --- a/examples/extract_lorem.rs +++ b/examples/extract_lorem.rs @@ -13,17 +13,17 @@ fn main() return; } let fname = Path::new(&*args[1]); - let file = std::fs::File::open(&fname).unwrap(); + let zipfile = std::fs::File::open(&fname).unwrap(); - let zipcontainer = zip::ZipReader::new(file).unwrap(); + let mut archive = zip::ZipArchive::new(zipfile).unwrap(); - let file = match zipcontainer.get("test/lorem_ipsum.txt") + let mut file = match archive.by_name("test/lorem_ipsum.txt") { - Some(file) => file, - None => { println!("File test/lorem_ipsum.txt not found"); return } + Ok(file) => file, + Err(..) => { println!("File test/lorem_ipsum.txt not found"); return } }; let mut contents = String::new(); - zipcontainer.read_file(file).unwrap().read_to_string(&mut contents).unwrap(); + file.read_to_string(&mut contents).unwrap(); println!("{}", contents); } diff --git a/src/compression.rs b/src/compression.rs index 67adeb7a..df7cc644 100644 --- a/src/compression.rs +++ b/src/compression.rs @@ -37,5 +37,5 @@ pub enum CompressionMethod /// PPMd version I, Rev 1 PPMdI1 = 98, /// Unknown (invalid) compression - Unknown = 100000, + Unknown = 10000, } diff --git a/src/lib.rs b/src/lib.rs index d241509c..f4454bc6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,25 +3,23 @@ #![feature(unsafe_destructor)] #![warn(missing_docs)] -#![feature(core, old_io, std_misc, io)] +#![feature(core, old_io, io)] extern crate time; extern crate flate2; extern crate bzip2; -pub use reader::ZipReader; -pub use writer::ZipWriter; +pub use read::ZipArchive; +pub use write::ZipWriter; pub use compression::CompressionMethod; -pub use types::ZipFile; mod util; mod spec; -mod reader_spec; mod writer_spec; mod crc32; -pub mod reader; mod types; -pub mod compression; -pub mod writer; +pub mod read; +mod compression; +pub mod write; mod cp437; pub mod result; diff --git a/src/read.rs b/src/read.rs new file mode 100644 index 00000000..db2abcee --- /dev/null +++ b/src/read.rs @@ -0,0 +1,308 @@ +//! Structs for reading a ZIP archive + +use crc32::Crc32Reader; +use compression::CompressionMethod; +use spec; +use result::{ZipResult, ZipError}; +use std::io; +use std::io::prelude::*; +use std::collections::HashMap; +use std::num::FromPrimitive; +use flate2; +use flate2::FlateReadExt; +use bzip2::reader::BzDecompressor; +use util; +use util::ReadIntExt; +use types::ZipFileData; + +/// Wrapper for reading the contents of a ZIP file. +/// +/// ``` +/// fn doit() -> zip::result::ZipResult<()> +/// { +/// use std::io::prelude::*; +/// +/// // For demonstration purposes we read from an empty buffer. +/// // Normally a File object would be used. +/// let buf: &[u8] = &[0u8; 128]; +/// let mut reader = std::io::Cursor::new(buf); +/// +/// let mut zip = try!(zip::ZipArchive::new(reader)); +/// +/// for i in 1..zip.len() +/// { +/// let mut file = zip.by_index(i).unwrap(); +/// println!("Filename: {}", file.name()); +/// let first_byte = try!(file.bytes().next().unwrap()); +/// println!("{}", first_byte); +/// } +/// Ok(()) +/// } +/// +/// println!("Result: {:?}", doit()); +/// ``` +pub struct ZipArchive +{ + reader: R, + files: Vec, + names_map: HashMap, +} + +enum ZipFileReader<'a> { + Stored(Crc32Reader>), + Deflated(Crc32Reader>>), + Bzip2(Crc32Reader>>), +} + +/// A struct for reading a zip file +pub struct ZipFile<'a> { + data: &'a ZipFileData, + reader: ZipFileReader<'a>, +} + +fn unsupported_zip_error(detail: &'static str) -> ZipResult +{ + Err(ZipError::UnsupportedArchive(detail)) +} + +impl ZipArchive +{ + /// Opens a Zip archive and parses the central directory + pub fn new(mut reader: R) -> ZipResult> { + let footer = try!(spec::CentralDirectoryEnd::find_and_parse(&mut reader)); + + if footer.disk_number != footer.disk_with_central_directory { return unsupported_zip_error("Support for multi-disk files is not implemented") } + + let directory_start = footer.central_directory_offset as u64; + let number_of_files = footer.number_of_files_on_this_disk as usize; + + let mut files = Vec::with_capacity(number_of_files); + let mut names_map = HashMap::new(); + + try!(reader.seek(io::SeekFrom::Start(directory_start))); + for _ in (0 .. number_of_files) + { + let file = try!(central_header_to_zip_file(&mut reader)); + names_map.insert(file.file_name.clone(), files.len()); + files.push(file); + } + + Ok(ZipArchive { reader: reader, files: files, names_map: names_map }) + } + + /// Number of files contained in this zip. + /// + /// ``` + /// fn iter() { + /// let mut zip = zip::ZipArchive::new(std::io::Cursor::new(vec![])).unwrap(); + /// + /// for i in 1..zip.len() { + /// let mut file = zip.by_index(i).unwrap(); + /// // Do something with file i + /// } + /// } + /// ``` + pub fn len(&self) -> usize + { + self.files.len() + } + + /// Search for a file entry by name + pub fn by_name<'a>(&'a mut self, name: &str) -> ZipResult> + { + let index = match self.names_map.get(name) { + Some(index) => *index, + None => { return Err(ZipError::FileNotFound); }, + }; + self.by_index(index) + } + + /// Get a contained file by index + pub fn by_index<'a>(&'a mut self, file_number: usize) -> ZipResult> + { + if file_number >= self.files.len() { return Err(ZipError::FileNotFound); } + let ref data = self.files[file_number]; + let pos = data.data_start as u64; + + if data.encrypted + { + return unsupported_zip_error("Encrypted files are not supported") + } + + try!(self.reader.seek(io::SeekFrom::Start(pos))); + let limit_reader = (self.reader.by_ref() as &mut Read).take(data.compressed_size as u64); + + let reader = match data.compression_method + { + CompressionMethod::Stored => + { + ZipFileReader::Stored(Crc32Reader::new( + limit_reader, + data.crc32)) + }, + CompressionMethod::Deflated => + { + let deflate_reader = limit_reader.deflate_decode(); + ZipFileReader::Deflated(Crc32Reader::new( + deflate_reader, + data.crc32)) + }, + CompressionMethod::Bzip2 => + { + let bzip2_reader = BzDecompressor::new(limit_reader); + ZipFileReader::Bzip2(Crc32Reader::new( + bzip2_reader, + data.crc32)) + }, + _ => return unsupported_zip_error("Compression method not supported"), + }; + Ok(ZipFile { reader: reader, data: data }) + } + + /// Unwrap and return the inner reader object + /// + /// The position of the reader is undefined. + pub fn into_inner(self) -> R + { + self.reader + } +} + +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(ZipError::InvalidArchive("Invalid Central Directory header")) + } + + try!(reader.read_le_u16()); + try!(reader.read_le_u16()); + let flags = try!(reader.read_le_u16()); + let encrypted = flags & 1 == 1; + let is_utf8 = flags & (1 << 11) != 0; + let compression_method = try!(reader.read_le_u16()); + let last_mod_time = try!(reader.read_le_u16()); + let last_mod_date = try!(reader.read_le_u16()); + let crc32 = try!(reader.read_le_u32()); + let compressed_size = try!(reader.read_le_u32()); + let uncompressed_size = try!(reader.read_le_u32()); + let file_name_length = try!(reader.read_le_u16()) as usize; + let extra_field_length = try!(reader.read_le_u16()) as usize; + let file_comment_length = try!(reader.read_le_u16()) as usize; + try!(reader.read_le_u16()); + try!(reader.read_le_u16()); + try!(reader.read_le_u32()); + let offset = try!(reader.read_le_u32()) as u64; + let file_name_raw = try!(reader.read_exact(file_name_length)); + let extra_field = try!(reader.read_exact(extra_field_length)); + let file_comment_raw = try!(reader.read_exact(file_comment_length)); + + let file_name = match is_utf8 + { + true => String::from_utf8_lossy(&*file_name_raw).into_owned(), + false => ::cp437::to_string(&*file_name_raw), + }; + let file_comment = match is_utf8 + { + true => String::from_utf8_lossy(&*file_comment_raw).into_owned(), + false => ::cp437::to_string(&*file_comment_raw), + }; + + // Remember end of central header + let return_position = try!(reader.seek(io::SeekFrom::Current(0))); + + // Parse local header + try!(reader.seek(io::SeekFrom::Start(offset))); + let signature = try!(reader.read_le_u32()); + if signature != spec::LOCAL_FILE_HEADER_SIGNATURE + { + return Err(ZipError::InvalidArchive("Invalid local file header")) + } + + try!(reader.seek(io::SeekFrom::Current(22))); + let file_name_length = try!(reader.read_le_u16()) as u64; + let extra_field_length = try!(reader.read_le_u16()) as u64; + let magic_and_header = 4 + 22 + 2 + 2; + let data_start = offset as u64 + magic_and_header + file_name_length + extra_field_length; + + // Construct the result + let mut result = ZipFileData + { + encrypted: encrypted, + compression_method: FromPrimitive::from_u16(compression_method).unwrap_or(CompressionMethod::Unknown), + last_modified_time: util::msdos_datetime_to_tm(last_mod_time, last_mod_date), + crc32: crc32, + compressed_size: compressed_size as u64, + uncompressed_size: uncompressed_size as u64, + file_name: file_name, + file_comment: file_comment, + header_start: offset as u64, + data_start: data_start, + }; + + try!(parse_extra_field(&mut result, &*extra_field)); + + // Go back after the central header + try!(reader.seek(io::SeekFrom::Start(return_position))); + + Ok(result) +} + +fn parse_extra_field(_file: &mut ZipFileData, data: &[u8]) -> ZipResult<()> +{ + let mut reader = io::Cursor::new(data); + + while (reader.position() as usize) < data.len() + { + let kind = try!(reader.read_le_u16()); + let len = try!(reader.read_le_u16()); + match kind + { + _ => try!(reader.seek(io::SeekFrom::Current(len as i64))), + }; + } + Ok(()) +} + +/// Methods for retreiving information on zip files +impl<'a> ZipFile<'a> { + fn get_reader(&mut self) -> &mut Read { + match self.reader { + ZipFileReader::Stored(ref mut r) => r as &mut Read, + ZipFileReader::Deflated(ref mut r) => r as &mut Read, + ZipFileReader::Bzip2(ref mut r) => r as &mut Read, + } + } + /// Get the name of the file + pub fn name(&self) -> &str { + &*self.data.file_name + } + /// Get the comment of the file + pub fn comment(&self) -> &str { + &*self.data.file_comment + } + /// Get the compression method used to store the file + pub fn compression(&self) -> CompressionMethod { + self.data.compression_method + } + /// Get the size of the file in the archive + pub fn compressed_size(&self) -> u64 { + self.data.compressed_size + } + /// Get the size of the file when uncompressed + pub fn size(&self) -> u64 { + self.data.uncompressed_size + } + /// Get the time the file was last modified + pub fn last_modified(&self) -> ::time::Tm { + self.data.last_modified_time + } +} + +impl<'a> Read for ZipFile<'a> { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.get_reader().read(buf) + } +} diff --git a/src/reader.rs b/src/reader.rs deleted file mode 100644 index 1bae6bff..00000000 --- a/src/reader.rs +++ /dev/null @@ -1,169 +0,0 @@ -//! Structs for reading a ZIP archive - -use crc32::Crc32Reader; -use types::ZipFile; -use compression::CompressionMethod; -use spec; -use reader_spec; -use result::{ZipResult, ZipError}; -use std::io; -use std::io::prelude::*; -use std::cell::{RefCell, BorrowState}; -use std::collections::HashMap; -use flate2::FlateReadExt; -use bzip2::reader::BzDecompressor; - -/// Wrapper for reading the contents of a ZIP file. -/// -/// ``` -/// fn doit() -> zip::result::ZipResult<()> -/// { -/// use std::io::prelude::*; -/// -/// // For demonstration purposes we read from an empty buffer. -/// // Normally a File object would be used. -/// let buf: &[u8] = &[0u8; 128]; -/// let mut reader = std::io::Cursor::new(buf); -/// -/// let zip = try!(zip::ZipReader::new(reader)); -/// -/// for file in zip.files() -/// { -/// println!("Filename: {}", file.file_name); -/// let mut file_reader = try!(zip.read_file(file)); -/// let first_byte = try!(file_reader.bytes().next().unwrap()); -/// println!("{}", first_byte); -/// } -/// Ok(()) -/// } -/// -/// println!("Result: {:?}", doit()); -/// ``` -pub struct ZipReader -{ - inner: RefCell, - files: Vec, - names_map: HashMap, -} - -/// Iterator over the files contained in a zip archive -pub struct ZipFileIterator<'a> -{ - inner: ::std::slice::Iter<'a, ZipFile>, -} - -impl<'a> Iterator for ZipFileIterator<'a> { - type Item = &'a ZipFile; - fn next(&mut self) -> Option<&'a ZipFile> { - self.inner.next() - } - fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() - } -} - -fn unsupported_zip_error(detail: &'static str) -> ZipResult -{ - Err(ZipError::UnsupportedZipFile(detail)) -} - -impl ZipReader -{ - /// Opens a ZIP file and parses the content headers. - pub fn new(mut reader: T) -> ZipResult> - { - let footer = try!(spec::CentralDirectoryEnd::find_and_parse(&mut reader)); - - if footer.disk_number != footer.disk_with_central_directory { return unsupported_zip_error("Support for multi-disk files is not implemented") } - - let directory_start = footer.central_directory_offset as u64; - let number_of_files = footer.number_of_files_on_this_disk as usize; - - let mut files = Vec::with_capacity(number_of_files); - let mut names_map = HashMap::new(); - - try!(reader.seek(io::SeekFrom::Start(directory_start))); - for _ in (0 .. number_of_files) - { - let file = try!(reader_spec::central_header_to_zip_file(&mut reader)); - names_map.insert(file.file_name.clone(), files.len()); - files.push(file); - } - - Ok(ZipReader { inner: RefCell::new(reader), files: files, names_map: names_map }) - } - - /// An iterator over the information of all contained files. - pub fn files(&self) -> ZipFileIterator - { - ZipFileIterator { inner: (&*self.files).iter(), } - } - - /// Search for a file entry by name - pub fn get(&self, name: &str) -> Option<&ZipFile> - { - self.names_map.get(name).map(|index| &self.files[*index]) - } - - /// Gets a reader for a contained zipfile. - /// - /// May return `ReaderUnavailable` if there is another reader borrowed. - pub fn read_file<'a>(&'a self, file: &ZipFile) -> ZipResult> - { - let mut inner_reader = match self.inner.borrow_state() - { - BorrowState::Unused => self.inner.borrow_mut(), - _ => return Err(ZipError::ReaderUnavailable), - }; - let pos = file.data_start as u64; - - if file.encrypted - { - return unsupported_zip_error("Encrypted files are not supported") - } - - try!(inner_reader.seek(io::SeekFrom::Start(pos))); - let refmut_reader = ::util::RefMutReader::new(inner_reader); - let limit_reader = refmut_reader.take(file.compressed_size as u64); - - let reader = match file.compression_method - { - CompressionMethod::Stored => - { - Box::new( - Crc32Reader::new( - limit_reader, - file.crc32)) - as Box - }, - CompressionMethod::Deflated => - { - let deflate_reader = limit_reader.deflate_decode(); - Box::new( - Crc32Reader::new( - deflate_reader, - file.crc32)) - as Box - }, - CompressionMethod::Bzip2 => - { - let bzip2_reader = BzDecompressor::new(limit_reader); - Box::new( - Crc32Reader::new( - bzip2_reader, - file.crc32)) - as Box - }, - _ => return unsupported_zip_error("Compression method not supported"), - }; - Ok(reader) - } - - /// Unwrap and return the inner reader object - /// - /// The position of the reader is undefined. - pub fn into_inner(self) -> T - { - self.inner.into_inner() - } -} diff --git a/src/reader_spec.rs b/src/reader_spec.rs deleted file mode 100644 index e807c51e..00000000 --- a/src/reader_spec.rs +++ /dev/null @@ -1,107 +0,0 @@ -use std::io; -use std::io::prelude::*; -use std::num::FromPrimitive; -use result::{ZipResult, ZipError}; -use types::ZipFile; -use compression::CompressionMethod; -use spec; -use util; -use util::ReadIntExt; - -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(ZipError::InvalidZipFile("Invalid Central Directory header")) - } - - try!(reader.read_le_u16()); - try!(reader.read_le_u16()); - let flags = try!(reader.read_le_u16()); - let encrypted = flags & 1 == 1; - let is_utf8 = flags & (1 << 11) != 0; - let compression_method = try!(reader.read_le_u16()); - let last_mod_time = try!(reader.read_le_u16()); - let last_mod_date = try!(reader.read_le_u16()); - let crc32 = try!(reader.read_le_u32()); - let compressed_size = try!(reader.read_le_u32()); - let uncompressed_size = try!(reader.read_le_u32()); - let file_name_length = try!(reader.read_le_u16()) as usize; - let extra_field_length = try!(reader.read_le_u16()) as usize; - let file_comment_length = try!(reader.read_le_u16()) as usize; - try!(reader.read_le_u16()); - try!(reader.read_le_u16()); - try!(reader.read_le_u32()); - let offset = try!(reader.read_le_u32()) as u64; - let file_name_raw = try!(reader.read_exact(file_name_length)); - let extra_field = try!(reader.read_exact(extra_field_length)); - let file_comment_raw = try!(reader.read_exact(file_comment_length)); - - let file_name = match is_utf8 - { - true => String::from_utf8_lossy(&*file_name_raw).into_owned(), - false => ::cp437::to_string(&*file_name_raw), - }; - let file_comment = match is_utf8 - { - true => String::from_utf8_lossy(&*file_comment_raw).into_owned(), - false => ::cp437::to_string(&*file_comment_raw), - }; - - // Remember end of central header - let return_position = try!(reader.seek(io::SeekFrom::Current(0))); - - // Parse local header - try!(reader.seek(io::SeekFrom::Start(offset))); - let signature = try!(reader.read_le_u32()); - if signature != spec::LOCAL_FILE_HEADER_SIGNATURE - { - return Err(ZipError::InvalidZipFile("Invalid local file header")) - } - - try!(reader.seek(io::SeekFrom::Current(22))); - let file_name_length = try!(reader.read_le_u16()) as u64; - let extra_field_length = try!(reader.read_le_u16()) as u64; - let magic_and_header = 4 + 22 + 2 + 2; - let data_start = offset as u64 + magic_and_header + file_name_length + extra_field_length; - - // Construct the result - let mut result = ZipFile - { - encrypted: encrypted, - compression_method: FromPrimitive::from_u16(compression_method).unwrap_or(CompressionMethod::Unknown), - last_modified_time: util::msdos_datetime_to_tm(last_mod_time, last_mod_date), - crc32: crc32, - compressed_size: compressed_size as u64, - uncompressed_size: uncompressed_size as u64, - file_name: file_name, - file_comment: file_comment, - header_start: offset as u64, - data_start: data_start, - }; - - try!(parse_extra_field(&mut result, &*extra_field)); - - // Go back after the central header - try!(reader.seek(io::SeekFrom::Start(return_position))); - - Ok(result) -} - -fn parse_extra_field(_file: &mut ZipFile, data: &[u8]) -> ZipResult<()> -{ - let mut reader = io::Cursor::new(data); - - while (reader.position() as usize) < data.len() - { - let kind = try!(reader.read_le_u16()); - let len = try!(reader.read_le_u16()); - match kind - { - _ => try!(reader.seek(io::SeekFrom::Current(len as i64))), - }; - } - Ok(()) -} diff --git a/src/result.rs b/src/result.rs index 0041d1c0..31cde8e4 100644 --- a/src/result.rs +++ b/src/result.rs @@ -14,14 +14,14 @@ pub enum ZipError /// An Error caused by I/O Io(io::Error), - /// This file is probably not a zipfile. The argument is enclosed. - InvalidZipFile(&'static str), + /// This file is probably not a zip archive + InvalidArchive(&'static str), - /// This file is unsupported. The reason is enclosed. - UnsupportedZipFile(&'static str), + /// This archive is not supported + UnsupportedArchive(&'static str), - /// The ZipReader is not available. - ReaderUnavailable, + /// The requested file could not be found in the archive + FileNotFound, } impl ZipError @@ -36,10 +36,10 @@ impl ZipError ZipError::Io(ref io_err) => { ("Io Error: ".to_string() + io_err.description()).into_cow() }, - ZipError::InvalidZipFile(msg) | ZipError::UnsupportedZipFile(msg) => { + ZipError::InvalidArchive(msg) | ZipError::UnsupportedArchive(msg) => { (self.description().to_string() + ": " + msg).into_cow() }, - ZipError::ReaderUnavailable => { + ZipError::FileNotFound => { self.description().into_cow() }, } @@ -69,9 +69,9 @@ impl error::Error for ZipError match *self { ZipError::Io(ref io_err) => io_err.description(), - ZipError::InvalidZipFile(..) => "Invalid Zip File", - ZipError::UnsupportedZipFile(..) => "Unsupported Zip File", - ZipError::ReaderUnavailable => "No reader available", + ZipError::InvalidArchive(..) => "Invalid Zip archive", + ZipError::UnsupportedArchive(..) => "Unsupported Zip archive", + ZipError::FileNotFound => "Specified file not found in archive", } } diff --git a/src/spec.rs b/src/spec.rs index e2163de4..4c9f651f 100644 --- a/src/spec.rs +++ b/src/spec.rs @@ -26,7 +26,7 @@ impl CentralDirectoryEnd let magic = try!(reader.read_le_u32()); if magic != CENTRAL_DIRECTORY_END_SIGNATURE { - return Err(ZipError::UnsupportedZipFile("Invalid digital signature header")) + return Err(ZipError::InvalidArchive("Invalid digital signature header")) } let disk_number = try!(reader.read_le_u16()); let disk_with_central_directory = try!(reader.read_le_u16()); @@ -70,7 +70,7 @@ impl CentralDirectoryEnd } } } - Err(ZipError::UnsupportedZipFile("Could not find central directory end")) + Err(ZipError::InvalidArchive("Could not find central directory end")) } pub fn write(&self, writer: &mut T) -> ZipResult<()> diff --git a/src/types.rs b/src/types.rs index 71a88e5d..51d72b34 100644 --- a/src/types.rs +++ b/src/types.rs @@ -2,9 +2,8 @@ use time; -#[derive(Clone)] /// Structure representing a ZIP file. -pub struct ZipFile +pub struct ZipFileData { /// True if the file is encrypted. pub encrypted: bool, diff --git a/src/util.rs b/src/util.rs index a606d0b9..2285fe53 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,6 +1,5 @@ use time; use time::Tm; -use std::cell::RefMut; use std::io; use std::io::prelude::*; @@ -42,27 +41,6 @@ pub fn tm_to_msdos_date(time: Tm) -> u16 (time.tm_mday | ((time.tm_mon + 1) << 5) | ((time.tm_year - 80) << 9)) as u16 } -pub struct RefMutReader<'a, R:'a> -{ - inner: RefMut<'a, R>, -} - -impl<'a, R> RefMutReader<'a, R> -{ - pub fn new(inner: RefMut<'a, R>) -> RefMutReader<'a, R> - { - RefMutReader { inner: inner, } - } -} - -impl<'a, R: Read> Read for RefMutReader<'a, R> -{ - fn read(&mut self, buf: &mut [u8]) -> io::Result - { - self.inner.read(buf) - } -} - /// Additional integer write methods for a io::Read pub trait WriteIntExt { /// Write a u32 in little-endian mode diff --git a/src/writer.rs b/src/write.rs similarity index 98% rename from src/writer.rs rename to src/write.rs index e31775ca..32f46077 100644 --- a/src/writer.rs +++ b/src/write.rs @@ -1,7 +1,7 @@ //! Structs for creating a new zip archive use compression::CompressionMethod; -use types::ZipFile; +use types::ZipFileData; use spec; use writer_spec; use crc32; @@ -51,7 +51,7 @@ enum GenericZipWriter pub struct ZipWriter { inner: GenericZipWriter, - files: Vec, + files: Vec, stats: ZipWriterStats, } @@ -123,7 +123,7 @@ impl ZipWriter let writer = self.inner.get_plain(); let header_start = try!(writer.seek(io::SeekFrom::Current(0))); - let mut file = ZipFile + let mut file = ZipFileData { encrypted: false, compression_method: compression, @@ -246,7 +246,7 @@ impl GenericZipWriter CompressionMethod::Stored => GenericZipWriter::Storer(bare), CompressionMethod::Deflated => GenericZipWriter::Deflater(bare.deflate_encode(flate2::Compression::Default)), CompressionMethod::Bzip2 => GenericZipWriter::Bzip2(BzCompressor::new(bare, bzip2::Compress::Default)), - _ => return Err(ZipError::UnsupportedZipFile("Unsupported compression")), + _ => return Err(ZipError::UnsupportedArchive("Unsupported compression")), }; Ok(()) diff --git a/src/writer_spec.rs b/src/writer_spec.rs index 62e2540b..73f5eb37 100644 --- a/src/writer_spec.rs +++ b/src/writer_spec.rs @@ -1,13 +1,13 @@ use std::io; use std::io::prelude::*; use std::ascii::AsciiExt; -use types::ZipFile; +use types::ZipFileData; use result::ZipResult; use spec; use util; use util::WriteIntExt; -pub fn write_local_file_header(writer: &mut T, file: &ZipFile) -> ZipResult<()> +pub fn write_local_file_header(writer: &mut T, file: &ZipFileData) -> ZipResult<()> { try!(writer.write_le_u32(spec::LOCAL_FILE_HEADER_SIGNATURE)); try!(writer.write_le_u16(20)); @@ -28,7 +28,7 @@ pub fn write_local_file_header(writer: &mut T, file: &ZipFile) -> ZipR Ok(()) } -pub fn update_local_file_header(writer: &mut T, file: &ZipFile) -> ZipResult<()> +pub fn update_local_file_header(writer: &mut T, file: &ZipFileData) -> ZipResult<()> { static CRC32_OFFSET : u64 = 14; try!(writer.seek(io::SeekFrom::Start(file.header_start + CRC32_OFFSET))); @@ -38,7 +38,7 @@ pub fn update_local_file_header(writer: &mut T, file: &ZipFil Ok(()) } -pub fn write_central_directory_header(writer: &mut T, file: &ZipFile) -> ZipResult<()> +pub fn write_central_directory_header(writer: &mut T, file: &ZipFileData) -> ZipResult<()> { try!(writer.write_le_u32(spec::CENTRAL_DIRECTORY_HEADER_SIGNATURE)); try!(writer.write_le_u16(0x14FF)); @@ -65,7 +65,7 @@ pub fn write_central_directory_header(writer: &mut T, file: &ZipFile) Ok(()) } -fn build_extra_field(_file: &ZipFile) -> ZipResult> +fn build_extra_field(_file: &ZipFileData) -> ZipResult> { let writer = Vec::new(); // Future work