use crate::common::{Error, Result};
use std::io::{Read, Seek};
pub struct Package<R> {
archive: zip::ZipArchive<R>,
manifest: super::manifest::Manifest,
mimetype: String,
}
impl<R: Read + Seek> Package<R> {
pub fn from_reader(reader: R) -> Result<Self> {
let mut archive = zip::ZipArchive::new(reader)
.map_err(|_| Error::InvalidFormat("Invalid ZIP archive".to_string()))?;
let mimetype = Self::read_mimetype(&mut archive)?;
let manifest = super::manifest::Manifest::from_archive(&mut archive)?;
Ok(Self {
archive,
manifest,
mimetype,
})
}
fn read_mimetype(archive: &mut zip::ZipArchive<R>) -> Result<String> {
let mut mimetype_file = archive.by_name("mimetype")
.map_err(|_| Error::InvalidFormat("No mimetype file found in ODF package".to_string()))?;
let mut content = String::new();
mimetype_file.read_to_string(&mut content)?;
Ok(content.trim().to_string())
}
pub fn mimetype(&self) -> &str {
&self.mimetype
}
pub fn get_file(&mut self, path: &str) -> Result<Vec<u8>> {
let mut file = self.archive.by_name(path)
.map_err(|_| Error::InvalidFormat(format!("File not found: {}", path)))?;
let mut content = Vec::new();
file.read_to_end(&mut content)?;
Ok(content)
}
pub fn has_file(&mut self, path: &str) -> bool {
self.archive.by_name(path).is_ok()
}
pub fn manifest(&self) -> &super::manifest::Manifest {
&self.manifest
}
#[allow(dead_code)]
pub fn files(&mut self) -> Result<Vec<String>> {
let mut files = Vec::new();
for i in 0..self.archive.len() {
let file = self.archive.by_index(i)?;
files.push(file.name().to_string());
}
Ok(files)
}
}