1#![allow(clippy::single_match)]
2
3use std::io::Read;
4use std::str::FromStr;
5
6use xml::attribute::OwnedAttribute;
7use xml::reader::{EventReader, XmlEvent};
8
9use super::Run;
10
11use crate::escape::replace_escaped;
12use crate::types::BreakType;
13use crate::{reader::*, FieldCharType};
14
15#[derive(PartialEq, Debug)]
16enum TextState {
17 Idle,
18 Text,
19 Delete,
20}
21
22fn read_field_char(attributes: &[OwnedAttribute]) -> Result<FieldChar, ReaderError> {
23 let mut t: Option<FieldCharType> = None;
24 let mut dirty = false;
25 for a in attributes {
26 let local_name = &a.name.local_name;
27 match local_name.as_str() {
28 "fldCharType" => {
29 if let Ok(ty) = FieldCharType::from_str(&a.value) {
30 t = Some(ty);
31 }
32 }
33 "dirty" => {
34 dirty = !is_false(&a.value);
35 }
36 _ => {}
37 }
38 }
39
40 if let Some(t) = t {
41 let mut f = FieldChar::new(t);
42 if dirty {
43 f = f.dirty();
44 }
45 Ok(f)
46 } else {
47 Err(ReaderError::XMLReadError)
48 }
49}
50
51impl ElementReader for Run {
52 fn read<R: Read>(
53 r: &mut EventReader<R>,
54 _attrs: &[OwnedAttribute],
55 ) -> Result<Self, ReaderError> {
56 let mut run = Run::new();
57 let mut text_state = TextState::Idle;
58 loop {
59 let e = r.next();
60 match e {
61 Ok(XmlEvent::StartElement {
62 attributes, name, ..
63 }) => {
64 match name.prefix.as_deref() {
65 Some("w") => {
66 let e = XMLElement::from_str(&name.local_name).unwrap();
67
68 ignore::ignore_element(e.clone(), XMLElement::RunPropertyChange, r);
69
70 match e {
71 XMLElement::Tab => {
72 run = run.add_tab();
73 }
74 XMLElement::PTab => {
75 if let Ok(v) = PositionalTab::read(r, &attributes) {
76 run = run.add_ptab(v);
77 }
78 }
79 XMLElement::Sym => {
80 if let Some(font) = read(&attributes, "font") {
81 if let Some(char) = read(&attributes, "char") {
82 let sym = Sym::new(font, char);
83 run = run.add_sym(sym);
84 }
85 }
86 }
87 XMLElement::RunProperty => {
88 let p = RunProperty::read(r, &attributes)?;
89 run = run.set_property(p);
90 }
91 XMLElement::Text => text_state = TextState::Text,
92 XMLElement::DeleteText => text_state = TextState::Delete,
93 XMLElement::Break => {
94 if let Some(a) = attributes.first() {
95 run = run.add_break(BreakType::from_str(&a.value)?)
96 } else {
97 run = run.add_break(BreakType::TextWrapping)
98 }
99 }
100 XMLElement::Drawing => {
101 if let Ok(drawing) = Drawing::read(r, &attributes) {
102 run = run.add_drawing(drawing);
103 }
104 }
105 XMLElement::FieldChar => {
106 if let Ok(f) = read_field_char(&attributes) {
107 run.children.push(RunChild::FieldChar(f));
108 }
109 }
110 XMLElement::InstrText => loop {
111 let e = r.next();
112 match e {
113 Ok(XmlEvent::Characters(c)) => {
114 run.children.push(RunChild::InstrTextString(c));
115 break;
116 }
117 Ok(XmlEvent::EndElement { name, .. }) => {
118 let e = XMLElement::from_str(&name.local_name).unwrap();
119 match e {
120 XMLElement::Run => {
121 return Ok(run);
122 }
123 _ => {}
124 }
125 }
126 Err(_) => return Err(ReaderError::XMLReadError),
127 _ => {}
128 }
129 },
130 _ => {}
131 }
132 }
133 Some("mc") => {
134 let e = McXMLElement::from_str(&name.local_name).unwrap();
135 match e {
136 McXMLElement::Fallback => {
137 let _ = McFallback::read(r, &attributes)?;
138 }
139 _ => {}
140 }
141 }
142 Some("v") => {
143 let e = VXMLElement::from_str(&name.local_name).unwrap();
144 match e {
145 VXMLElement::Shape => {
147 if let Ok(shape) = Shape::read(r, &attributes) {
148 run.children.push(RunChild::Shape(Box::new(shape)));
149 }
150 }
151 _ => {}
152 }
153 }
154 _ => {}
155 };
156 }
157 Ok(XmlEvent::Characters(c)) => match text_state {
158 TextState::Delete => {
159 run = run.add_delete_text_without_escape(replace_escaped(&c));
160 }
161 TextState::Text => {
162 run = run.add_text_without_escape(replace_escaped(&c));
163 }
164 _ => {}
165 },
166 Ok(XmlEvent::Whitespace(c)) => match text_state {
167 TextState::Delete => {
168 run = run.add_delete_text_without_escape(replace_escaped(&c));
169 }
170 TextState::Text => {
171 run = run.add_text_without_escape(replace_escaped(&c));
172 }
173 _ => {}
174 },
175 Ok(XmlEvent::EndElement { name, .. }) => {
176 let e = XMLElement::from_str(&name.local_name).unwrap();
177 match e {
178 XMLElement::Run => {
179 return Ok(run);
180 }
181 XMLElement::DeleteText | XMLElement::Text => text_state = TextState::Idle,
182 _ => {}
183 }
184 }
185 Err(_) => return Err(ReaderError::XMLReadError),
186 _ => {}
187 }
188 }
189 }
190}
191
192#[cfg(test)]
193mod tests {
194
195 use super::*;
196 #[cfg(test)]
197 use pretty_assertions::assert_eq;
198
199 #[test]
200 fn test_read_size_color() {
201 let c = r#"<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
202 <w:r><w:rPr><w:color w:val="C9211E"/><w:sz w:val="30"/><w:szCs w:val="30"/></w:rPr><w:t>H</w:t></w:r>
203</w:document>"#;
204 let mut parser = EventReader::new(c.as_bytes());
205 let run = Run::read(&mut parser, &[]).unwrap();
206 assert_eq!(
207 run,
208 Run {
209 children: vec![RunChild::Text(Text::new("H"))],
210 run_property: RunProperty {
211 sz: Some(Sz::new(30)),
212 sz_cs: Some(SzCs::new(30)),
213 color: Some(Color::new("C9211E")),
214 ..RunProperty::default()
215 },
216 }
217 );
218 }
219
220 #[test]
221 fn test_read_tab() {
222 let c = r#"<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
223 <w:r><w:tab /></w:r>
224</w:document>"#;
225 let mut parser = EventReader::new(c.as_bytes());
226 let run = Run::read(&mut parser, &[]).unwrap();
227 assert_eq!(
228 run,
229 Run {
230 children: vec![RunChild::Tab(Tab::new())],
231 run_property: RunProperty::default(),
232 }
233 );
234 }
235
236 #[test]
237 fn test_read_br() {
238 let c = r#"<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
239 <w:r><w:br w:type="page" /></w:r>
240</w:document>"#;
241 let mut parser = EventReader::new(c.as_bytes());
242 let run = Run::read(&mut parser, &[]).unwrap();
243 assert_eq!(
244 run,
245 Run {
246 children: vec![RunChild::Break(Break::new(BreakType::Page))],
247 run_property: RunProperty::default(),
248 }
249 );
250 }
251
252 #[test]
253 fn test_read_empty_br() {
254 let c = r#"<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
255 <w:r><w:br /></w:r>
256</w:document>"#;
257 let mut parser = EventReader::new(c.as_bytes());
258 let run = Run::read(&mut parser, &[]).unwrap();
259 assert_eq!(
260 run,
261 Run {
262 children: vec![RunChild::Break(Break::new(BreakType::TextWrapping))],
263 run_property: RunProperty::default(),
264 }
265 );
266 }
267
268 #[test]
269 fn test_read_italic_false() {
270 let c = r#"<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
271 <w:r><w:rPr>
272 <w:b w:val="true"/>
273 <w:i w:val="false"/>
274 </w:rPr></w:r>
275</w:document>"#;
276 let mut parser = EventReader::new(c.as_bytes());
277 let run = Run::read(&mut parser, &[]).unwrap();
278 assert_eq!(
279 run,
280 Run {
281 children: vec![],
282 run_property: RunProperty {
283 bold: Some(Bold::new()),
284 bold_cs: Some(BoldCs::new()),
285 italic: Some(Italic::new().disable()),
286 italic_cs: Some(ItalicCs::new().disable()),
287 ..RunProperty::default()
288 },
289 }
290 );
291 }
292
293 #[test]
294 fn test_read_italic_0() {
295 let c = r#"<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
296 <w:r><w:rPr>
297 <w:b w:val="1"/>
298 <w:i w:val="0"/>
299 </w:rPr></w:r>
300</w:document>"#;
301 let mut parser = EventReader::new(c.as_bytes());
302 let run = Run::read(&mut parser, &[]).unwrap();
303 assert_eq!(
304 run,
305 Run {
306 children: vec![],
307 run_property: RunProperty {
308 bold: Some(Bold::new()),
309 bold_cs: Some(BoldCs::new()),
310 italic: Some(Italic::new().disable()),
311 italic_cs: Some(ItalicCs::new().disable()),
312 ..RunProperty::default()
313 },
314 }
315 );
316 }
317}