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();
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::Drawing => {
98 if let Ok(drawing) = Drawing::read(r, &attributes) {
99 run = run.add_drawing(drawing);
100 }
101 }
102 XMLElement::FieldChar => {
103 if let Ok(f) = read_field_char(&attributes) {
104 run.children.push(RunChild::FieldChar(f));
105 }
106 }
107 XMLElement::InstrText => loop {
108 let e = r.next();
109 match e {
110 Ok(XmlEvent::Characters(c)) => {
111 run.children.push(RunChild::InstrTextString(c));
112 break;
113 }
114 Ok(XmlEvent::EndElement { name, .. }) => {
115 let e = XMLElement::from_str(&name.local_name).unwrap();
116 match e {
117 XMLElement::Run => {
118 return Ok(run);
119 }
120 _ => {}
121 }
122 }
123 Err(_) => return Err(ReaderError::XMLReadError),
124 _ => {}
125 }
126 },
127 _ => {}
128 }
129 }
130 Some("mc") => {
131 let e = McXMLElement::from_str(&name.local_name).unwrap();
132 match e {
133 McXMLElement::Fallback => {
134 let _ = McFallback::read(r, &attributes)?;
135 }
136 _ => {}
137 }
138 }
139 Some("v") => {
140 let e = VXMLElement::from_str(&name.local_name).unwrap();
141 match e {
142 VXMLElement::Shape => {
144 if let Ok(shape) = Shape::read(r, &attributes) {
145 run.children.push(RunChild::Shape(Box::new(shape)));
146 }
147 }
148 _ => {}
149 }
150 }
151 _ => {}
152 };
153 }
154 Ok(XmlEvent::Characters(c)) => match text_state {
155 TextState::Delete => {
156 run = run.add_delete_text_without_escape(replace_escaped(&c));
157 }
158 TextState::Text => {
159 run = run.add_text_without_escape(replace_escaped(&c));
160 }
161 _ => {}
162 },
163 Ok(XmlEvent::Whitespace(c)) => match text_state {
164 TextState::Delete => {
165 run = run.add_delete_text_without_escape(replace_escaped(&c));
166 }
167 TextState::Text => {
168 run = run.add_text_without_escape(replace_escaped(&c));
169 }
170 _ => {}
171 },
172 Ok(XmlEvent::EndElement { name, .. }) => {
173 let e = XMLElement::from_str(&name.local_name).unwrap();
174 match e {
175 XMLElement::Run => {
176 return Ok(run);
177 }
178 XMLElement::DeleteText | XMLElement::Text => text_state = TextState::Idle,
179 _ => {}
180 }
181 }
182 Err(_) => return Err(ReaderError::XMLReadError),
183 _ => {}
184 }
185 }
186 }
187}
188
189#[cfg(test)]
190mod tests {
191
192 use super::*;
193 #[cfg(test)]
194 use pretty_assertions::assert_eq;
195
196 #[test]
197 fn test_read_size_color() {
198 let c = r#"<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
199 <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>
200</w:document>"#;
201 let mut parser = EventReader::new(c.as_bytes());
202 let run = Run::read(&mut parser, &[]).unwrap();
203 assert_eq!(
204 run,
205 Run {
206 children: vec![RunChild::Text(Text::new("H"))],
207 run_property: RunProperty {
208 sz: Some(Sz::new(30)),
209 sz_cs: Some(SzCs::new(30)),
210 color: Some(Color::new("C9211E")),
211 ..RunProperty::default()
212 },
213 }
214 );
215 }
216
217 #[test]
218 fn test_read_tab() {
219 let c = r#"<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
220 <w:r><w:tab /></w:r>
221</w:document>"#;
222 let mut parser = EventReader::new(c.as_bytes());
223 let run = Run::read(&mut parser, &[]).unwrap();
224 assert_eq!(
225 run,
226 Run {
227 children: vec![RunChild::Tab(Tab::new())],
228 run_property: RunProperty::default(),
229 }
230 );
231 }
232
233 #[test]
234 fn test_read_br() {
235 let c = r#"<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
236 <w:r><w:br w:type="page" /></w:r>
237</w:document>"#;
238 let mut parser = EventReader::new(c.as_bytes());
239 let run = Run::read(&mut parser, &[]).unwrap();
240 assert_eq!(
241 run,
242 Run {
243 children: vec![RunChild::Break(Break::new(BreakType::Page))],
244 run_property: RunProperty::default(),
245 }
246 );
247 }
248
249 #[test]
250 fn test_read_empty_br() {
251 let c = r#"<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
252 <w:r><w:br /></w:r>
253</w:document>"#;
254 let mut parser = EventReader::new(c.as_bytes());
255 let run = Run::read(&mut parser, &[]).unwrap();
256 assert_eq!(
257 run,
258 Run {
259 children: vec![RunChild::Break(Break::new(BreakType::TextWrapping))],
260 run_property: RunProperty::default(),
261 }
262 );
263 }
264
265 #[test]
266 fn test_read_italic_false() {
267 let c = r#"<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
268 <w:r><w:rPr>
269 <w:b w:val="true"/>
270 <w:i w:val="false"/>
271 </w:rPr></w:r>
272</w:document>"#;
273 let mut parser = EventReader::new(c.as_bytes());
274 let run = Run::read(&mut parser, &[]).unwrap();
275 assert_eq!(
276 run,
277 Run {
278 children: vec![],
279 run_property: RunProperty {
280 bold: Some(Bold::new()),
281 bold_cs: Some(BoldCs::new()),
282 italic: Some(Italic::new().disable()),
283 italic_cs: Some(ItalicCs::new().disable()),
284 ..RunProperty::default()
285 },
286 }
287 );
288 }
289
290 #[test]
291 fn test_read_italic_0() {
292 let c = r#"<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
293 <w:r><w:rPr>
294 <w:b w:val="1"/>
295 <w:i w:val="0"/>
296 </w:rPr></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![],
304 run_property: RunProperty {
305 bold: Some(Bold::new()),
306 bold_cs: Some(BoldCs::new()),
307 italic: Some(Italic::new().disable()),
308 italic_cs: Some(ItalicCs::new().disable()),
309 ..RunProperty::default()
310 },
311 }
312 );
313 }
314
315 #[test]
316 fn test_read_on_off_values() {
317 let c = r#"<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
318 <w:r><w:rPr>
319 <w:b w:val="off"/>
320 <w:i w:val="on"/>
321 </w:rPr></w:r>
322</w:document>"#;
323 let mut parser = EventReader::new(c.as_bytes());
324 let run = Run::read(&mut parser, &[]).unwrap();
325 assert_eq!(
326 run,
327 Run {
328 children: vec![],
329 run_property: RunProperty {
330 bold: Some(Bold::new().disable()),
331 bold_cs: Some(BoldCs::new().disable()),
332 italic: Some(Italic::new()),
333 italic_cs: Some(ItalicCs::new()),
334 ..RunProperty::default()
335 },
336 }
337 );
338 }
339
340 #[test]
341 fn test_read_fit_text() {
342 let c = r#"<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
343 <w:r><w:rPr>
344 <w:fitText w:val="840" w:id="1266434317"/>
345 </w:rPr></w:r>
346</w:document>"#;
347 let mut parser = EventReader::new(c.as_bytes());
348 let run = Run::read(&mut parser, &[]).unwrap();
349 assert_eq!(
350 run,
351 Run {
352 children: vec![],
353 run_property: RunProperty {
354 fit_text: Some(FitText::new(840).id(1266434317)),
355 ..RunProperty::default()
356 },
357 }
358 );
359 }
360}