Skip to main content

spreadsheet_mcp/diff/
sst.rs

1use anyhow::{Result, anyhow};
2use quick_xml::events::Event;
3use quick_xml::reader::Reader;
4use std::io::BufRead;
5
6pub struct Sst {
7    strings: Vec<String>,
8}
9
10impl Sst {
11    pub fn from_reader<R: BufRead>(reader: R) -> Result<Self> {
12        let mut reader = Reader::from_reader(reader);
13
14        let mut strings = Vec::new();
15        let mut buf = Vec::new();
16        let mut current_string = String::new();
17        let mut inside_si = false;
18
19        loop {
20            match reader.read_event_into(&mut buf) {
21                Ok(Event::Start(ref e)) => {
22                    if e.name().as_ref() == b"si" {
23                        inside_si = true;
24                        current_string.clear();
25                    } else if inside_si && e.name().as_ref() == b"t" {
26                        let text = read_text_content(&mut reader, b"t")?;
27                        current_string.push_str(&text);
28                    }
29                }
30                Ok(Event::End(ref e)) => {
31                    if e.name().as_ref() == b"si" {
32                        inside_si = false;
33                        strings.push(current_string.clone());
34                    }
35                }
36                Ok(Event::Eof) => break,
37                Err(e) => return Err(e.into()),
38                _ => (),
39            }
40            buf.clear();
41        }
42
43        Ok(Self { strings })
44    }
45
46    pub fn get(&self, idx: usize) -> Option<&str> {
47        self.strings.get(idx).map(|s| s.as_str())
48    }
49}
50
51fn read_text_content<R: BufRead>(reader: &mut Reader<R>, end_tag: &[u8]) -> Result<String> {
52    let mut text = String::new();
53    let mut buf = Vec::new();
54    loop {
55        match reader.read_event_into(&mut buf)? {
56            Event::Text(e) => text.push_str(&e.unescape()?),
57            Event::CData(e) => text.push_str(&String::from_utf8_lossy(&e)),
58            Event::End(e) if e.name().as_ref() == end_tag => break,
59            Event::Eof => return Err(anyhow!("Unexpected EOF reading text")),
60            _ => (),
61        }
62        buf.clear();
63    }
64    Ok(text)
65}