1#![allow(clippy::single_match)]
2
3use std::io::Read;
4use std::str::FromStr;
5
6use super::Run;
7
8use crate::escape::replace_escaped;
9use crate::types::BreakType;
10use crate::{reader::*, FieldCharType};
11
12#[derive(PartialEq, Debug)]
13enum TextState {
14 Idle,
15 Text,
16 Delete,
17}
18
19fn read_field_char(attributes: &[OwnedAttribute]) -> Result<FieldChar, ReaderError> {
20 let mut t: Option<FieldCharType> = None;
21 let mut dirty = false;
22 for a in attributes {
23 let local_name = &a.name.local_name;
24 match local_name.as_str() {
25 "fldCharType" => {
26 if let Ok(ty) = FieldCharType::from_str(&a.value) {
27 t = Some(ty);
28 }
29 }
30 "dirty" => {
31 dirty = !is_false(&a.value);
32 }
33 _ => {}
34 }
35 }
36
37 if let Some(t) = t {
38 let mut f = FieldChar::new(t);
39 if dirty {
40 f = f.dirty();
41 }
42 Ok(f)
43 } else {
44 Err(ReaderError::XMLReadError)
45 }
46}
47
48impl ElementReader for Run {
49 fn read<R: Read>(
50 r: &mut EventReader<R>,
51 _attrs: &[OwnedAttribute],
52 ) -> Result<Self, ReaderError> {
53 let mut run = Run::new();
54 let mut text_state = TextState::Idle;
55 loop {
56 let e = r.next_event();
57 match e {
58 Ok(XmlEvent::StartElement {
59 attributes, name, ..
60 }) => {
61 match name.prefix.as_deref() {
62 Some("w") => {
63 let e = XMLElement::from_str(&name.local_name).unwrap();
64
65 ignore::ignore_element(e.clone(), XMLElement::RunPropertyChange, r);
66
67 match e {
68 XMLElement::Tab => {
69 run = run.add_tab();
70 }
71 XMLElement::PTab => {
72 if let Ok(v) = PositionalTab::read(r, &attributes) {
73 run = run.add_ptab(v);
74 }
75 }
76 XMLElement::Sym => {
77 if let Some(font) = read(&attributes, "font") {
78 if let Some(char) = read(&attributes, "char") {
79 let sym = Sym::new(font, char);
80 run = run.add_sym(sym);
81 }
82 }
83 }
84 XMLElement::RunProperty => {
85 let p = RunProperty::read(r, &attributes)?;
86 run = run.set_property(p);
87 }
88 XMLElement::Text => text_state = TextState::Text,
89 XMLElement::DeleteText => text_state = TextState::Delete,
90 XMLElement::Break => {
91 if let Some(a) = attributes.first() {
92 run = run.add_break(BreakType::from_str(&a.value)?)
93 } else {
94 run = run.add_break(BreakType::TextWrapping)
95 }
96 }
97 XMLElement::CarriageReturn => {
98 run = run.add_carriage_return();
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_event();
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_theme_color() {
222 let c = r#"<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
225 <w:r><w:rPr><w:color w:val="2E74B5" w:themeColor="accent1" w:themeShade="BF"/></w:rPr><w:t>H</w:t></w:r>
226</w:document>"#;
227 let mut parser = EventReader::new(c.as_bytes());
228 let run = Run::read(&mut parser, &[]).unwrap();
229 assert_eq!(
230 run,
231 Run {
232 children: vec![RunChild::Text(Text::new("H"))],
233 run_property: RunProperty {
234 color: Some(
235 Color::new("2E74B5")
236 .theme_color(crate::ThemeColor::Accent1)
237 .theme_shade("BF")
238 ),
239 ..RunProperty::default()
240 },
241 }
242 );
243 }
244
245 #[test]
246 fn test_read_tab() {
247 let c = r#"<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
248 <w:r><w:tab /></w:r>
249</w:document>"#;
250 let mut parser = EventReader::new(c.as_bytes());
251 let run = Run::read(&mut parser, &[]).unwrap();
252 assert_eq!(
253 run,
254 Run {
255 children: vec![RunChild::Tab(Tab::new())],
256 run_property: RunProperty::default(),
257 }
258 );
259 }
260
261 #[test]
262 fn test_read_br() {
263 let c = r#"<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
264 <w:r><w:br w:type="page" /></w:r>
265</w:document>"#;
266 let mut parser = EventReader::new(c.as_bytes());
267 let run = Run::read(&mut parser, &[]).unwrap();
268 assert_eq!(
269 run,
270 Run {
271 children: vec![RunChild::Break(Break::new(BreakType::Page))],
272 run_property: RunProperty::default(),
273 }
274 );
275 }
276
277 #[test]
278 fn test_read_empty_br() {
279 let c = r#"<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
280 <w:r><w:br /></w:r>
281</w:document>"#;
282 let mut parser = EventReader::new(c.as_bytes());
283 let run = Run::read(&mut parser, &[]).unwrap();
284 assert_eq!(
285 run,
286 Run {
287 children: vec![RunChild::Break(Break::new(BreakType::TextWrapping))],
288 run_property: RunProperty::default(),
289 }
290 );
291 }
292
293 #[test]
294 fn test_read_cr() {
295 let c = r#"<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
296 <w:r><w:cr /></w:r>
297</w:document>"#;
298 let mut parser = EventReader::new(c.as_bytes());
299 let run = Run::read(&mut parser, &[]).unwrap();
300 assert_eq!(
301 run,
302 Run {
303 children: vec![RunChild::CarriageReturn(CarriageReturn::new())],
304 run_property: RunProperty::default(),
305 }
306 );
307 }
308
309 #[test]
310 fn test_read_italic_false() {
311 let c = r#"<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
312 <w:r><w:rPr>
313 <w:b w:val="true"/>
314 <w:i w:val="false"/>
315 </w:rPr></w:r>
316</w:document>"#;
317 let mut parser = EventReader::new(c.as_bytes());
318 let run = Run::read(&mut parser, &[]).unwrap();
319 assert_eq!(
320 run,
321 Run {
322 children: vec![],
323 run_property: RunProperty {
324 bold: Some(Bold::new()),
325 bold_cs: Some(BoldCs::new()),
326 italic: Some(Italic::new().disable()),
327 italic_cs: Some(ItalicCs::new().disable()),
328 ..RunProperty::default()
329 },
330 }
331 );
332 }
333
334 #[test]
335 fn test_read_italic_0() {
336 let c = r#"<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
337 <w:r><w:rPr>
338 <w:b w:val="1"/>
339 <w:i w:val="0"/>
340 </w:rPr></w:r>
341</w:document>"#;
342 let mut parser = EventReader::new(c.as_bytes());
343 let run = Run::read(&mut parser, &[]).unwrap();
344 assert_eq!(
345 run,
346 Run {
347 children: vec![],
348 run_property: RunProperty {
349 bold: Some(Bold::new()),
350 bold_cs: Some(BoldCs::new()),
351 italic: Some(Italic::new().disable()),
352 italic_cs: Some(ItalicCs::new().disable()),
353 ..RunProperty::default()
354 },
355 }
356 );
357 }
358
359 #[test]
360 fn test_read_on_off_values() {
361 let c = r#"<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
362 <w:r><w:rPr>
363 <w:b w:val="off"/>
364 <w:i w:val="on"/>
365 </w:rPr></w:r>
366</w:document>"#;
367 let mut parser = EventReader::new(c.as_bytes());
368 let run = Run::read(&mut parser, &[]).unwrap();
369 assert_eq!(
370 run,
371 Run {
372 children: vec![],
373 run_property: RunProperty {
374 bold: Some(Bold::new().disable()),
375 bold_cs: Some(BoldCs::new().disable()),
376 italic: Some(Italic::new()),
377 italic_cs: Some(ItalicCs::new()),
378 ..RunProperty::default()
379 },
380 }
381 );
382 }
383
384 #[test]
385 fn test_read_fit_text() {
386 let c = r#"<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
387 <w:r><w:rPr>
388 <w:fitText w:val="840" w:id="1266434317"/>
389 </w:rPr></w:r>
390</w:document>"#;
391 let mut parser = EventReader::new(c.as_bytes());
392 let run = Run::read(&mut parser, &[]).unwrap();
393 assert_eq!(
394 run,
395 Run {
396 children: vec![],
397 run_property: RunProperty {
398 fit_text: Some(FitText::new(840).id(1266434317)),
399 ..RunProperty::default()
400 },
401 }
402 );
403 }
404}