docx_reader/reader/
run.rsuse std::io::Read;
use std::str::FromStr;
use xml::attribute::OwnedAttribute;
use xml::reader::{EventReader, XmlEvent};
use crate::escape::replace_escaped;
use crate::types::BreakType;
use crate::{reader::*, FieldCharType};
use super::Run;
#[derive(PartialEq, Debug)]
enum TextState {
Idle,
Text,
Delete,
}
fn read_field_char(attributes: &[OwnedAttribute]) -> Result<FieldChar, ReaderError> {
let mut t: Option<FieldCharType> = None;
let mut dirty = false;
for a in attributes {
let local_name = &a.name.local_name;
match local_name.as_str() {
"fldCharType" => {
if let Ok(ty) = FieldCharType::from_str(&a.value) {
t = Some(ty);
}
}
"dirty" => {
dirty = !is_false(&a.value);
}
_ => {}
}
}
if let Some(t) = t {
let mut f = FieldChar::new(t);
if dirty {
f = f.dirty();
}
Ok(f)
} else {
Err(ReaderError::XMLReadError)
}
}
impl ElementReader for Run {
fn read<R: Read>(
r: &mut EventReader<R>,
_attrs: &[OwnedAttribute],
) -> Result<Self, ReaderError> {
let mut run = Run::new();
let mut text_state = TextState::Idle;
loop {
let e = r.next();
match e {
Ok(XmlEvent::StartElement {
attributes, name, ..
}) => {
match name.prefix.as_deref() {
Some("w") => {
let e = XMLElement::from_str(&name.local_name).unwrap();
ignore::ignore_element(e.clone(), XMLElement::RunPropertyChange, r);
match e {
XMLElement::Tab => {
run = run.add_tab();
}
XMLElement::Sym => {
if let Some(font) = read(&attributes, "font") {
if let Some(char) = read(&attributes, "char") {
let sym = Sym::new(font, char);
run = run.add_sym(sym);
}
}
}
XMLElement::RunProperty => {
let p = RunProperty::read(r, &attributes)?;
run = run.set_property(p);
}
XMLElement::Text => text_state = TextState::Text,
XMLElement::DeleteText => text_state = TextState::Delete,
XMLElement::Break => {
if let Some(a) = &attributes.get(0) {
run = run.add_break(BreakType::from_str(&a.value)?)
} else {
run = run.add_break(BreakType::TextWrapping)
}
}
XMLElement::Drawing => {
if let Ok(drawing) = Drawing::read(r, &attributes) {
run = run.add_drawing(drawing);
}
}
XMLElement::FieldChar => {
if let Ok(f) = read_field_char(&attributes) {
run.children.push(RunChild::FieldChar(f));
}
}
XMLElement::InstrText => loop {
let e = r.next();
match e {
Ok(XmlEvent::Characters(c)) => {
run.children.push(RunChild::InstrTextString(c));
break;
}
Ok(XmlEvent::EndElement { name, .. }) => {
let e = XMLElement::from_str(&name.local_name).unwrap();
match e {
XMLElement::Run => {
return Ok(run);
}
_ => {}
}
}
Err(_) => return Err(ReaderError::XMLReadError),
_ => {}
}
},
_ => {}
}
}
Some("mc") => {
let e = McXMLElement::from_str(&name.local_name).unwrap();
match e {
McXMLElement::Fallback => {
let _ = McFallback::read(r, &attributes)?;
}
_ => {}
}
}
Some("v") => {
let e = VXMLElement::from_str(&name.local_name).unwrap();
match e {
VXMLElement::Shape => {
if let Ok(shape) = Shape::read(r, &attributes) {
run.children.push(RunChild::Shape(Box::new(shape)));
}
}
_ => {}
}
}
_ => {}
};
}
Ok(XmlEvent::Characters(c)) => match text_state {
TextState::Delete => {
run = run.add_delete_text_without_escape(replace_escaped(&c));
}
TextState::Text => {
run = run.add_text_without_escape(replace_escaped(&c));
}
_ => {}
},
Ok(XmlEvent::Whitespace(c)) => match text_state {
TextState::Delete => {
run = run.add_delete_text_without_escape(replace_escaped(&c));
}
TextState::Text => {
run = run.add_text_without_escape(replace_escaped(&c));
}
_ => {}
},
Ok(XmlEvent::EndElement { name, .. }) => {
let e = XMLElement::from_str(&name.local_name).unwrap();
match e {
XMLElement::Run => {
return Ok(run);
}
XMLElement::DeleteText | XMLElement::Text => text_state = TextState::Idle,
_ => {}
}
}
Err(_) => return Err(ReaderError::XMLReadError),
_ => {}
}
}
}
}