spreadsheet_mcp/diff/
sst.rs1use 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}