docx_reader/documents/
content_types.rs1use serde::{Deserialize, Serialize};
2use std::collections::BTreeMap;
3use std::io::Read;
4use xml::reader::{EventReader, XmlEvent};
5
6use crate::reader::{FromXML, ReaderError};
7
8#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
9pub struct ContentTypes {
10 types: BTreeMap<String, String>,
11 web_extension_count: usize,
12 custom_xml_count: usize,
13 header_count: usize,
14 footer_count: usize,
15}
16
17impl ContentTypes {
18 pub fn new() -> ContentTypes {
19 Default::default()
20 }
21
22 pub fn add_content(mut self, path: impl Into<String>, namespace: impl Into<String>) -> Self {
23 self.types.insert(path.into(), namespace.into());
24 self
25 }
26
27 pub fn set_default(mut self) -> ContentTypes {
28 self.types.insert(
29 "/_rels/.rels".to_owned(),
30 "application/vnd.openxmlformats-package.relationships+xml".to_owned(),
31 );
32 self.types.insert(
33 "/docProps/app.xml".to_owned(),
34 "application/vnd.openxmlformats-officedocument.extended-properties+xml".to_owned(),
35 );
36 self.types.insert(
37 "/docProps/core.xml".to_owned(),
38 "application/vnd.openxmlformats-package.core-properties+xml".to_owned(),
39 );
40 self.types.insert(
41 "/word/_rels/document.xml.rels".to_owned(),
42 "application/vnd.openxmlformats-package.relationships+xml".to_owned(),
43 );
44 self.types.insert(
45 "/word/settings.xml".to_owned(),
46 "application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml"
47 .to_owned(),
48 );
49 self.types.insert(
50 "/word/fontTable.xml".to_owned(),
51 "application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml"
52 .to_owned(),
53 );
54 self.types.insert(
55 "/word/document.xml".to_owned(),
56 "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"
57 .to_owned(),
58 );
59 self.types.insert(
60 "/word/styles.xml".to_owned(),
61 "application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml".to_owned(),
62 );
63 self.types.insert(
64 "/word/comments.xml".to_owned(),
65 "application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml"
66 .to_owned(),
67 );
68 self.types.insert(
69 "/word/numbering.xml".to_owned(),
70 "application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml"
71 .to_owned(),
72 );
73 self.types.insert(
74 "/word/commentsExtended.xml".to_owned(),
75 "application/vnd.openxmlformats-officedocument.wordprocessingml.commentsExtended+xml"
76 .to_owned(),
77 );
78 self.types.insert(
79 "/docProps/custom.xml".to_owned(),
80 "application/vnd.openxmlformats-officedocument.custom-properties+xml".to_owned(),
81 );
82 self
83 }
84
85 pub fn add_taskpanes(mut self) -> Self {
86 self.types.insert(
87 "/word/webextensions/taskpanes.xml".to_owned(),
88 "application/vnd.ms-office.webextensiontaskpanes+xml".to_owned(),
89 );
90 self
91 }
92
93 pub fn add_web_extensions(mut self) -> Self {
94 self.types.insert(
95 format!(
96 "/word/webextensions/webextension{}.xml",
97 self.web_extension_count
98 ),
99 "application/vnd.ms-office.webextension+xml".to_owned(),
100 );
101 self.web_extension_count += 1;
102 self
103 }
104
105 pub fn add_custom_xml(mut self) -> Self {
106 self.types.insert(
107 format!("/customXml/itemProps{}.xml", self.web_extension_count),
108 "application/vnd.openxmlformats-officedocument.customXmlProperties+xml".to_owned(),
109 );
110 self.custom_xml_count += 1;
111 self
112 }
113
114 pub fn add_header(mut self) -> Self {
115 self.header_count += 1;
116 self.types.insert(
117 format!("/word/header{}.xml", self.header_count),
118 "application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml".to_owned(),
119 );
120 self
121 }
122
123 pub fn add_footer(mut self) -> Self {
124 self.footer_count += 1;
125 self.types.insert(
126 format!("/word/footer{}.xml", self.footer_count),
127 "application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml".to_owned(),
128 );
129 self
130 }
131}
132
133impl Default for ContentTypes {
134 fn default() -> Self {
135 ContentTypes {
136 types: BTreeMap::new(),
137 web_extension_count: 1,
138 custom_xml_count: 1,
139 header_count: 0,
140 footer_count: 0,
141 }
142 }
143}
144
145impl FromXML for ContentTypes {
146 fn from_xml<R: Read>(reader: R) -> Result<Self, ReaderError> {
147 let parser = EventReader::new(reader);
148 let mut s = Self::default();
149 let mut depth = 0;
150 for e in parser {
151 match e {
152 Ok(XmlEvent::StartElement { attributes, .. }) => {
153 if depth == 1 {
154 let namespace = attributes[0].value.clone();
155 let path = attributes[1].value.clone();
156 s = s.add_content(path, namespace);
157 }
158 depth += 1;
159 }
160 Ok(XmlEvent::EndElement { .. }) => {
161 depth -= 1;
162 }
163 Err(_) => {}
164 _ => {}
165 }
166 }
167 Ok(s)
168 }
169}