#[cfg(test)] mod tests; use crate::workbook::DocProperties; use crate::{Result, XmlWritable, XmlWriter}; use indexmap::{indexmap, IndexMap, IndexSet}; pub(crate) struct App<'a> { pub heading_pairs: IndexMap, pub part_names: IndexSet, pub properties: &'a DocProperties, } impl XmlWritable for App<'_> { fn write_xml(&self, w: &mut W) -> Result<()> { let attrs = indexmap! { "xmlns" => "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties", "xmlns:vt" => "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes", }; let tag = "Properties"; w.start_tag_with_attrs(tag, attrs)?; self.write_application(w)?; self.write_doc_security(w)?; self.write_scale_crop(w)?; self.write_heading_pairs(w)?; self.write_titles_of_parts(w)?; self.write_manager(w)?; self.write_company(w)?; self.write_links_up_to_date(w)?; self.write_shared_doc(w)?; self.write_hyperlink_base(w)?; self.write_hyperlinks_changed(w)?; self.write_app_version(w)?; w.end_tag(tag)?; Ok(()) } } impl App<'_> { fn write_application(&self, w: &mut W) -> Result<()> { w.tag_with_text("Application", "Microsoft Excel") } fn write_doc_security(&self, w: &mut W) -> Result<()> { w.tag_with_text("DocSecurity", "0") } fn write_scale_crop(&self, w: &mut W) -> Result<()> { w.tag_with_text("ScaleCrop", "false") } fn write_heading_pairs(&self, w: &mut W) -> Result<()> { let tag = "HeadingPairs"; w.start_tag(tag)?; self.write_vt_vector_heading_pairs(w)?; w.end_tag(tag)?; Ok(()) } fn write_vt_vector_heading_pairs( &self, w: &mut W, ) -> Result<()> { let tag = "vt:vector"; let attrs = indexmap! { "size" => format!("{}", self.heading_pairs.len() * 2), "baseType" => "variant".to_string(), }; w.start_tag_with_attrs(tag, attrs)?; for (key, value) in self.heading_pairs.iter() { self.write_vt_variant(w, key, value)?; } w.end_tag(tag)?; Ok(()) } fn write_vt_variant( &self, w: &mut W, key: &str, value: &str, ) -> Result<()> { let tag = "vt:variant"; { w.start_tag(tag)?; self.write_vt_lpstr(w, key)?; w.end_tag(tag)?; } { w.start_tag(tag)?; self.write_vt_i4(w, value)?; w.end_tag(tag)?; } Ok(()) } fn write_vt_lpstr( &self, w: &mut W, string: &str, ) -> Result<()> { w.tag_with_text("vt:lpstr", string) } fn write_vt_i4( &self, w: &mut W, string: &str, ) -> Result<()> { w.tag_with_text("vt:i4", string) } fn write_titles_of_parts( &self, w: &mut W, ) -> Result<()> { let tag = "TitlesOfParts"; w.start_tag(tag)?; self.write_vt_vector_lpstr_named_parts(w)?; w.end_tag(tag)?; Ok(()) } fn write_vt_vector_lpstr_named_parts( &self, w: &mut W, ) -> Result<()> { let attrs = indexmap! { "size" => format!("{}", self.part_names.len()), "baseType" => "lpstr".to_string(), }; let tag = "vt:vector"; w.start_tag_with_attrs(tag, attrs)?; for name in self.part_names.iter() { self.write_vt_lpstr(w, name)?; } w.end_tag(tag)?; Ok(()) } fn write_manager(&self, w: &mut W) -> Result<()> { if !self.properties.manager.is_empty() { w.tag_with_text("manager", &self.properties.manager)?; } Ok(()) } fn write_company(&self, w: &mut W) -> Result<()> { w.tag_with_text("Company", &self.properties.company) } fn write_links_up_to_date( &self, w: &mut W, ) -> Result<()> { w.tag_with_text("LinksUpToDate", "false") } fn write_shared_doc(&self, w: &mut W) -> Result<()> { w.tag_with_text("SharedDoc", "false") } fn write_hyperlink_base(&self, w: &mut W) -> Result<()> { if !self.properties.hyperlink_base.is_empty() { w.tag_with_text( "HyperlinkBase", &self.properties.hyperlink_base, )?; } Ok(()) } fn write_hyperlinks_changed( &self, w: &mut W, ) -> Result<()> { w.tag_with_text("HyperlinksChanged", "false") } fn write_app_version(&self, w: &mut W) -> Result<()> { w.tag_with_text("AppVersion", "12.0000") } }