use super::presentation::Presentation;
use super::super::{OleError, OleFile};
use std::fs::File;
use std::io::{self, Read, Seek};
use std::path::Path;
#[derive(Debug)]
pub enum PptError {
Io(io::Error),
Ole(OleError),
InvalidFormat(String),
StreamNotFound(String),
Corrupted(String),
}
impl From<io::Error> for PptError {
fn from(err: io::Error) -> Self {
PptError::Io(err)
}
}
impl From<OleError> for PptError {
fn from(err: OleError) -> Self {
PptError::Ole(err)
}
}
impl std::fmt::Display for PptError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
PptError::Io(e) => write!(f, "IO error: {}", e),
PptError::Ole(e) => write!(f, "OLE error: {}", e),
PptError::InvalidFormat(s) => write!(f, "Invalid format: {}", s),
PptError::StreamNotFound(s) => write!(f, "Stream not found: {}", s),
PptError::Corrupted(s) => write!(f, "Corrupted file: {}", s),
}
}
}
impl std::error::Error for PptError {}
pub type Result<T> = std::result::Result<T, PptError>;
pub struct Package<R: Read + Seek = File> {
ole: OleFile<R>,
}
impl Package<File> {
pub fn open<P: AsRef<Path>>(path: P) -> Result<Self> {
let file = File::open(path)?;
Package::from_reader(file)
}
}
impl<R: Read + Seek> Package<R> {
pub fn from_reader(reader: R) -> Result<Self> {
let ole = OleFile::open(reader)?;
if !ole.exists(&["PowerPoint Document"]) {
return Err(PptError::InvalidFormat(
"Not a valid PowerPoint document: PowerPoint Document stream not found".to_string(),
));
}
Ok(Self { ole })
}
pub fn presentation(&mut self) -> Result<Presentation> {
Presentation::from_ole(&mut self.ole)
}
#[inline]
pub fn ole_file(&mut self) -> &mut OleFile<R> {
&mut self.ole
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_open_package() {
let result = Package::open("test.ppt");
assert!(result.is_ok());
}
#[test]
#[ignore] fn test_invalid_file() {
std::fs::write("test_invalid.tmp", b"Not a PPT file").unwrap();
let result = Package::open("test_invalid.tmp");
assert!(result.is_err());
std::fs::remove_file("test_invalid.tmp").ok();
}
}