use std::ffi::OsStr;
use std::fs::File;
use std::io::{Cursor, Read, Seek};
use std::path::Path;
use zip::result::ZipError;
use zip::ZipArchive;
use errors::Result;
use io::{InputHandle, IoProvider, OpenResult};
use status::StatusBackend;
pub struct ZipBundle<R: Read + Seek> {
zip: ZipArchive<R>
}
impl<R: Read + Seek> ZipBundle<R> {
pub fn new (reader: R) -> Result<ZipBundle<R>> {
Ok(ZipBundle {
zip: ZipArchive::new(reader)?
})
}
}
impl ZipBundle<File> {
pub fn open (path: &Path) -> Result<ZipBundle<File>> {
Self::new(File::open(path)?)
}
}
impl<R: Read + Seek> IoProvider for ZipBundle<R> {
fn input_open_name(&mut self, name: &OsStr, _status: &mut StatusBackend) -> OpenResult<InputHandle> {
let namestr = match name.to_str() {
Some(s) => s,
None => return OpenResult::NotAvailable
};
let mut zipitem = match self.zip.by_name (namestr) {
Ok(f) => f,
Err(e) => {
return match e {
ZipError::Io(sube) => OpenResult::Err(sube.into()),
ZipError::FileNotFound => OpenResult::NotAvailable,
_ => OpenResult::Err(e.into()),
}
}
};
let mut buf = Vec::with_capacity(zipitem.size() as usize);
if let Err(e) = zipitem.read_to_end(&mut buf) {
return OpenResult::Err(e.into());
}
OpenResult::Ok(InputHandle::new(name, Cursor::new(buf)))
}
}