mod pres;
mod sheet;
mod text;
pub use pres::{Presentation, Slide};
pub use sheet::{Cell, Column, Sheet, SheetDocument, Value};
pub use text::TextDocument;
use crate::xml::{Element, Name, Ns};
use crate::{Error, Meta, Package, Styles};
pub struct Document {
pub package: Package,
pub content: Element,
pub styles_part: Option<Element>,
pub styles: Styles,
pub meta: Meta,
}
impl Document {
pub fn read(bytes: &[u8], wanted: &'static [&'static str]) -> Result<Self, Error> {
let package = Package::read(bytes)?;
package.expect_media_type(wanted)?;
let content = package.xml("content.xml")?;
let styles_part = package.optional_xml("styles.xml")?;
let styles = Styles::collect(Some(&content), styles_part.as_ref());
let meta = match package.optional_xml("meta.xml")? {
Some(part) => Meta::read(&part),
None => Meta::default(),
};
Ok(Self {
package,
content,
styles_part,
styles,
meta,
})
}
pub fn body(&self) -> Option<&Element> {
self.content.child(&Ns::Office, "body")
}
pub fn body_of(&self, local: &str) -> Option<&Element> {
self.body()?.child(&Ns::Office, local)
}
pub fn body_path(&self, local: &str) -> Option<Vec<usize>> {
let (at_body, body) = self
.content
.elements_indexed()
.find(|(_, e)| e.is(&Ns::Office, "body"))?;
let (at_part, _) = body
.elements_indexed()
.find(|(_, e)| e.is(&Ns::Office, local))?;
Some(vec![at_body, at_part])
}
pub fn name(&self, ns: &Ns, local: &str) -> Name {
self.content.name_for(ns, local)
}
pub fn declares(&self, ns: &Ns) -> bool {
self.content.declares(ns)
}
pub fn version(&self) -> Option<&str> {
self.content.attr(&Ns::Office, "version")
}
pub fn picture(&self, href: &str) -> Option<&[u8]> {
let path = href.strip_prefix("./").unwrap_or(href);
if path.contains("://") {
return None;
}
self.package.part(path).map(|p| p.data.as_slice())
}
pub fn write(&mut self) -> Result<Vec<u8>, Error> {
let content = crate::xml::serialize(&self.content);
self.package.set_part("content.xml", content);
if let Some(styles) = &self.styles_part {
let bytes = crate::xml::serialize(styles);
self.package.set_part("styles.xml", bytes);
}
self.package.write()
}
pub fn write_verified(&mut self) -> Result<Vec<u8>, Error> {
let bytes = self.write()?;
let written = Package::read(&bytes)?;
if written.xml("content.xml")? != self.content {
return Err(Error::Unfaithful("content.xml"));
}
if let Some(styles) = &self.styles_part
&& written.optional_xml("styles.xml")?.as_ref() != Some(styles)
{
return Err(Error::Unfaithful("styles.xml"));
}
Ok(bytes)
}
}