docx_rust/
app.rs

1//! Application-Defined File Properties part
2//!
3//! The corresponding ZIP item is `/docProps/app.xml`.
4
5use hard_xml::{XmlRead, XmlResult, XmlWrite, XmlWriter};
6use std::borrow::Cow;
7use std::io::Write;
8
9use crate::schema::{SCHEMAS_EXTENDED, SCHEMA_DOC_PROPS_V_TYPES, SCHEMA_XML};
10
11#[derive(Debug, XmlRead, XmlWrite, Clone)]
12pub enum App<'a> {
13    #[xml(tag = "Properties")]
14    AppNoApNamespace(AppNoApNamespace<'a>),
15    #[xml(tag = "ap:Properties")]
16    AppWithApNamespace(AppWithApNamespace<'a>),
17}
18
19#[derive(Debug, XmlRead, Clone)]
20#[xml(tag = "Properties")]
21pub struct AppNoApNamespace<'a> {
22    #[xml(flatten_text = "Template")]
23    pub template: Option<Cow<'a, str>>,
24    #[xml(flatten_text = "TotalTime")]
25    pub total_time: Option<Cow<'a, str>>,
26    #[xml(flatten_text = "Pages")]
27    pub pages: Option<Cow<'a, str>>,
28    #[xml(flatten_text = "Words")]
29    pub words: Option<Cow<'a, str>>,
30    #[xml(flatten_text = "Characters")]
31    pub characters: Option<Cow<'a, str>>,
32    #[xml(flatten_text = "Application")]
33    pub application: Option<Cow<'a, str>>,
34    #[xml(flatten_text = "DocSecurity")]
35    pub doc_security: Option<Cow<'a, str>>,
36    #[xml(flatten_text = "Lines")]
37    pub lines: Option<Cow<'a, str>>,
38    #[xml(flatten_text = "Paragraphs")]
39    pub paragraphs: Option<Cow<'a, str>>,
40    #[xml(flatten_text = "ScaleCrop")]
41    pub scale_crop: Option<Cow<'a, str>>,
42    #[xml(flatten_text = "Company")]
43    pub company: Option<Cow<'a, str>>,
44    #[xml(flatten_text = "LinksUpToDate")]
45    pub links_up_to_date: Option<Cow<'a, str>>,
46    #[xml(flatten_text = "CharactersWithSpaces")]
47    pub characters_with_spaces: Option<Cow<'a, str>>,
48    #[xml(flatten_text = "SharedDoc")]
49    pub shared_doc: Option<Cow<'a, str>>,
50    #[xml(flatten_text = "HyperlinksChanged")]
51    pub hyperlinks_changed: Option<Cow<'a, str>>,
52    #[xml(flatten_text = "AppVersion")]
53    pub app_version: Option<Cow<'a, str>>,
54}
55
56#[derive(Debug, XmlRead, Clone)]
57#[xml(tag = "ap:Properties")]
58pub struct AppWithApNamespace<'a> {
59    #[xml(flatten_text = "ap:Template")]
60    pub template: Option<Cow<'a, str>>,
61    #[xml(flatten_text = "ap:TotalTime")]
62    pub total_time: Option<Cow<'a, str>>,
63    #[xml(flatten_text = "ap:Pages")]
64    pub pages: Option<Cow<'a, str>>,
65    #[xml(flatten_text = "ap:Words")]
66    pub words: Option<Cow<'a, str>>,
67    #[xml(flatten_text = "ap:Characters")]
68    pub characters: Option<Cow<'a, str>>,
69    #[xml(flatten_text = "ap:Application")]
70    pub application: Option<Cow<'a, str>>,
71    #[xml(flatten_text = "ap:DocSecurity")]
72    pub doc_security: Option<Cow<'a, str>>,
73    #[xml(flatten_text = "ap:Lines")]
74    pub lines: Option<Cow<'a, str>>,
75    #[xml(flatten_text = "ap:Paragraphs")]
76    pub paragraphs: Option<Cow<'a, str>>,
77    #[xml(flatten_text = "ap:ScaleCrop")]
78    pub scale_crop: Option<Cow<'a, str>>,
79    #[xml(flatten_text = "ap:Company")]
80    pub company: Option<Cow<'a, str>>,
81    #[xml(flatten_text = "ap:LinksUpToDate")]
82    pub links_up_to_date: Option<Cow<'a, str>>,
83    #[xml(flatten_text = "ap:CharactersWithSpaces")]
84    pub characters_with_spaces: Option<Cow<'a, str>>,
85    #[xml(flatten_text = "ap:SharedDoc")]
86    pub shared_doc: Option<Cow<'a, str>>,
87    #[xml(flatten_text = "ap:HyperlinksChanged")]
88    pub hyperlinks_changed: Option<Cow<'a, str>>,
89    #[xml(flatten_text = "ap:AppVersion")]
90    pub app_version: Option<Cow<'a, str>>,
91}
92
93impl Default for AppNoApNamespace<'static> {
94    fn default() -> AppNoApNamespace<'static> {
95        AppNoApNamespace {
96            template: Some("Normal.dotm".into()),
97            total_time: Some("1".into()),
98            pages: Some("1".into()),
99            words: Some("0".into()),
100            characters: Some("0".into()),
101            application: Some("docx-rs".into()),
102            doc_security: Some("0".into()),
103            lines: Some("0".into()),
104            paragraphs: Some("1".into()),
105            scale_crop: Some("false".into()),
106            company: Some("MS".into()),
107            links_up_to_date: Some("false".into()),
108            characters_with_spaces: Some("25".into()),
109            shared_doc: Some("false".into()),
110            hyperlinks_changed: Some("false".into()),
111            app_version: Some("12.0000".into()),
112        }
113    }
114}
115
116impl Default for AppWithApNamespace<'static> {
117    fn default() -> AppWithApNamespace<'static> {
118        AppWithApNamespace {
119            template: Some("Normal.dotm".into()),
120            total_time: Some("1".into()),
121            pages: Some("1".into()),
122            words: Some("0".into()),
123            characters: Some("0".into()),
124            application: Some("docx-rs".into()),
125            doc_security: Some("0".into()),
126            lines: Some("0".into()),
127            paragraphs: Some("1".into()),
128            scale_crop: Some("false".into()),
129            company: Some("MS".into()),
130            links_up_to_date: Some("false".into()),
131            characters_with_spaces: Some("25".into()),
132            shared_doc: Some("false".into()),
133            hyperlinks_changed: Some("false".into()),
134            app_version: Some("12.0000".into()),
135        }
136    }
137}
138
139impl<'a> XmlWrite for AppNoApNamespace<'a> {
140    fn to_writer<W: Write>(&self, writer: &mut XmlWriter<W>) -> XmlResult<()> {
141        let AppNoApNamespace {
142            template,
143            total_time,
144            pages,
145            words,
146            characters,
147            application,
148            doc_security,
149            lines,
150            paragraphs,
151            scale_crop,
152            company,
153            links_up_to_date,
154            characters_with_spaces,
155            shared_doc,
156            hyperlinks_changed,
157            app_version,
158        } = self;
159
160        log::debug!("[App] Started writing.");
161
162        let _ = write!(writer.inner, "{}", SCHEMA_XML);
163
164        writer.write_element_start("Properties")?;
165
166        writer.write_attribute("xmlns", SCHEMAS_EXTENDED)?;
167        writer.write_attribute("xmlns:vt", SCHEMA_DOC_PROPS_V_TYPES)?;
168
169        if template.is_none()
170            && total_time.is_none()
171            && pages.is_none()
172            && words.is_none()
173            && characters.is_none()
174            && application.is_none()
175            && doc_security.is_none()
176            && lines.is_none()
177            && paragraphs.is_none()
178            && scale_crop.is_none()
179            && company.is_none()
180            && links_up_to_date.is_none()
181            && characters_with_spaces.is_none()
182            && shared_doc.is_none()
183            && hyperlinks_changed.is_none()
184            && app_version.is_none()
185        {
186            writer.write_element_end_empty()?;
187        } else {
188            writer.write_element_end_open()?;
189            if let Some(val) = template {
190                writer.write_flatten_text("Template", val, false)?;
191            }
192            if let Some(val) = total_time {
193                writer.write_flatten_text("TotalTime", val, false)?;
194            }
195            if let Some(val) = pages {
196                writer.write_flatten_text("Pages", val, false)?;
197            }
198            if let Some(val) = words {
199                writer.write_flatten_text("Words", val, false)?;
200            }
201            if let Some(val) = characters {
202                writer.write_flatten_text("Characters", val, false)?;
203            }
204            if let Some(val) = application {
205                writer.write_flatten_text("Application", val, false)?;
206            }
207            if let Some(val) = doc_security {
208                writer.write_flatten_text("DocSecurity", val, false)?;
209            }
210            if let Some(val) = lines {
211                writer.write_flatten_text("Lines", val, false)?;
212            }
213            if let Some(val) = paragraphs {
214                writer.write_flatten_text("Paragraphs", val, false)?;
215            }
216            if let Some(val) = scale_crop {
217                writer.write_flatten_text("ScaleCrop", val, false)?;
218            }
219            if let Some(val) = company {
220                writer.write_flatten_text("Company", val, false)?;
221            }
222            if let Some(val) = links_up_to_date {
223                writer.write_flatten_text("LinksUpToDate", val, false)?;
224            }
225            if let Some(val) = characters_with_spaces {
226                writer.write_flatten_text("CharactersWithSpaces", val, false)?;
227            }
228            if let Some(val) = shared_doc {
229                writer.write_flatten_text("SharedDoc", val, false)?;
230            }
231            if let Some(val) = hyperlinks_changed {
232                writer.write_flatten_text("HyperlinksChanged", val, false)?;
233            }
234            if let Some(val) = app_version {
235                writer.write_flatten_text("AppVersion", val, false)?;
236            }
237            writer.write_element_end_close("Properties")?;
238        }
239
240        log::debug!("[App] Finished writing.");
241
242        Ok(())
243    }
244}
245
246impl<'a> XmlWrite for AppWithApNamespace<'a> {
247    fn to_writer<W: Write>(&self, writer: &mut XmlWriter<W>) -> XmlResult<()> {
248        let AppWithApNamespace {
249            template,
250            total_time,
251            pages,
252            words,
253            characters,
254            application,
255            doc_security,
256            lines,
257            paragraphs,
258            scale_crop,
259            company,
260            links_up_to_date,
261            characters_with_spaces,
262            shared_doc,
263            hyperlinks_changed,
264            app_version,
265        } = self;
266
267        log::debug!("[App] Started writing.");
268
269        let _ = write!(writer.inner, "{}", SCHEMA_XML);
270
271        writer.write_element_start("ap:Properties")?;
272
273        writer.write_attribute("xmlns", SCHEMAS_EXTENDED)?;
274        writer.write_attribute("xmlns:vt", SCHEMA_DOC_PROPS_V_TYPES)?;
275
276        if template.is_none()
277            && total_time.is_none()
278            && pages.is_none()
279            && words.is_none()
280            && characters.is_none()
281            && application.is_none()
282            && doc_security.is_none()
283            && lines.is_none()
284            && paragraphs.is_none()
285            && scale_crop.is_none()
286            && company.is_none()
287            && links_up_to_date.is_none()
288            && characters_with_spaces.is_none()
289            && shared_doc.is_none()
290            && hyperlinks_changed.is_none()
291            && app_version.is_none()
292        {
293            writer.write_element_end_empty()?;
294        } else {
295            writer.write_element_end_open()?;
296            if let Some(val) = template {
297                writer.write_flatten_text("ap:Template", val, false)?;
298            }
299            if let Some(val) = total_time {
300                writer.write_flatten_text("ap:TotalTime", val, false)?;
301            }
302            if let Some(val) = pages {
303                writer.write_flatten_text("ap:Pages", val, false)?;
304            }
305            if let Some(val) = words {
306                writer.write_flatten_text("ap:Words", val, false)?;
307            }
308            if let Some(val) = characters {
309                writer.write_flatten_text("ap:Characters", val, false)?;
310            }
311            if let Some(val) = application {
312                writer.write_flatten_text("ap:Application", val, false)?;
313            }
314            if let Some(val) = doc_security {
315                writer.write_flatten_text("ap:DocSecurity", val, false)?;
316            }
317            if let Some(val) = lines {
318                writer.write_flatten_text("ap:Lines", val, false)?;
319            }
320            if let Some(val) = paragraphs {
321                writer.write_flatten_text("ap:Paragraphs", val, false)?;
322            }
323            if let Some(val) = scale_crop {
324                writer.write_flatten_text("ap:ScaleCrop", val, false)?;
325            }
326            if let Some(val) = company {
327                writer.write_flatten_text("ap:Company", val, false)?;
328            }
329            if let Some(val) = links_up_to_date {
330                writer.write_flatten_text("ap:LinksUpToDate", val, false)?;
331            }
332            if let Some(val) = characters_with_spaces {
333                writer.write_flatten_text("ap:CharactersWithSpaces", val, false)?;
334            }
335            if let Some(val) = shared_doc {
336                writer.write_flatten_text("ap:SharedDoc", val, false)?;
337            }
338            if let Some(val) = hyperlinks_changed {
339                writer.write_flatten_text("ap:HyperlinksChanged", val, false)?;
340            }
341            if let Some(val) = app_version {
342                writer.write_flatten_text("ap:AppVersion", val, false)?;
343            }
344            writer.write_element_end_close("ap:Properties")?;
345        }
346
347        log::debug!("[App] Finished writing.");
348
349        Ok(())
350    }
351}