docx_rs/reader/
run.rs

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                                // Experimental For now support only imageData in shape
146                                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}