office2pdf 0.5.0

Convert DOCX, XLSX, and PPTX files to PDF using pure Rust
Documentation
use std::cell::Cell;
use std::collections::HashSet;

pub(in super::super) struct BidiContext {
    bidi_indices: HashSet<usize>,
    cursor: Cell<usize>,
}

impl BidiContext {
    pub(in super::super) fn from_xml(xml: Option<&str>) -> Self {
        let bidi_indices = xml.map(Self::scan).unwrap_or_default();
        Self {
            bidi_indices,
            cursor: Cell::new(0),
        }
    }

    pub(in super::super) fn next_is_bidi(&self) -> bool {
        let index = self.cursor.get();
        self.cursor.set(index + 1);
        self.bidi_indices.contains(&index)
    }

    fn scan(xml: &str) -> HashSet<usize> {
        let mut reader = quick_xml::Reader::from_str(xml);
        let mut buffer: Vec<u8> = Vec::new();
        let mut result: HashSet<usize> = HashSet::new();
        let mut paragraph_index: usize = 0;
        let mut in_paragraph_properties = false;
        let mut in_body = false;

        loop {
            match reader.read_event_into(&mut buffer) {
                Ok(quick_xml::events::Event::Start(ref element))
                | Ok(quick_xml::events::Event::Empty(ref element)) => {
                    match element.local_name().as_ref() {
                        b"body" => in_body = true,
                        b"pPr" if in_body => in_paragraph_properties = true,
                        b"bidi" if in_paragraph_properties => {
                            result.insert(paragraph_index);
                        }
                        _ => {}
                    }
                }
                Ok(quick_xml::events::Event::End(ref element)) => {
                    match element.local_name().as_ref() {
                        b"body" => in_body = false,
                        b"p" if in_body => {
                            paragraph_index += 1;
                            in_paragraph_properties = false;
                        }
                        b"pPr" => in_paragraph_properties = false,
                        _ => {}
                    }
                }
                Ok(quick_xml::events::Event::Eof) => break,
                Err(_) => break,
                _ => {}
            }
            buffer.clear();
        }

        result
    }
}