use super::package::{PptError, Result};
use super::slide::{Slide, SlideFactory};
use super::parsers::PptRecordParser;
use super::persist::PersistMapping;
use super::super::OleFile;
use std::io::{Read, Seek};
pub struct Presentation {
powerpoint_document: Vec<u8>,
#[allow(dead_code)]
pub(crate) parser: PptRecordParser,
pub(crate) persist_mapping: PersistMapping,
}
impl Presentation {
pub(crate) fn from_ole<R: Read + Seek>(ole: &mut OleFile<R>) -> Result<Self> {
let powerpoint_document = Self::read_powerpoint_document(ole)?;
let mut parser = PptRecordParser::new();
parser.parse_document(&powerpoint_document)?;
let all_records = parser.find_records(crate::ole::consts::PptRecordType::Unknown);
let persist_mapping = PersistMapping::build_from_records(&all_records);
Ok(Self {
powerpoint_document,
parser,
persist_mapping,
})
}
fn read_powerpoint_document<R: Read + Seek>(ole: &mut OleFile<R>) -> Result<Vec<u8>> {
if let Ok(data) = ole.open_stream(&["PowerPoint Document"]) {
return Ok(data);
}
if let Ok(data) = ole.open_stream(&["PP97_DUALSTORAGE", "PowerPoint Document"]) {
return Ok(data);
}
Err(PptError::InvalidFormat("PowerPoint Document stream not found".to_string()))
}
pub fn slides(&self) -> Result<Vec<Slide<'_>>> {
let factory = SlideFactory::new(&self.powerpoint_document, &self.persist_mapping);
factory.slides()
.enumerate()
.map(|(idx, slide_result)| {
slide_result.map(|slide_data| {
Slide::from_slide_data(slide_data, idx + 1)
})
})
.collect()
}
#[inline]
pub fn slide_count(&self) -> usize {
let factory = SlideFactory::new(&self.powerpoint_document, &self.persist_mapping);
factory.slide_ids().len()
}
pub fn text(&self) -> Result<String> {
let slides = self.slides()?;
let text_parts: Vec<String> = slides.iter()
.filter_map(|slide| {
slide.text().ok().map(|s| s.to_string())
})
.filter(|text| !text.is_empty())
.collect();
Ok(if text_parts.is_empty() {
String::from("No text content found in presentation")
} else {
text_parts.join("\n\n")
})
}
}