use super::records::PptRecord;
use super::package::Result;
use super::super::consts::PptRecordType;
#[derive(Debug, Clone)]
pub struct EscherTextboxWrapper {
data: Vec<u8>,
child_records: Vec<PptRecord>,
text: String,
}
impl EscherTextboxWrapper {
pub fn new(data: Vec<u8>) -> Result<Self> {
let child_records = Self::find_child_records(&data)?;
let text = Self::extract_text_from_records(&child_records)?;
if text.is_empty() && !child_records.is_empty() {
return Err(super::package::PptError::InvalidFormat(
"No text records found in Escher textbox data".to_string()
));
}
Ok(Self {
data,
child_records,
text,
})
}
fn find_child_records(data: &[u8]) -> Result<Vec<PptRecord>> {
let mut records = Vec::new();
let mut offset = 0;
while offset + 8 <= data.len() {
match PptRecord::parse(data, offset) {
Ok((record, consumed)) => {
records.push(record);
offset += consumed;
if consumed == 0 {
break; }
}
Err(_) => {
offset += 1;
if offset + 8 > data.len() {
break;
}
}
}
}
Ok(records)
}
fn extract_text_from_records(records: &[PptRecord]) -> Result<String> {
let mut text_parts = Vec::new();
for record in records {
match record.record_type {
PptRecordType::TextCharsAtom | PptRecordType::TextBytesAtom => {
if let Ok(text) = record.extract_text()
&& !text.is_empty() {
text_parts.push(text);
}
}
_ => {}
}
}
Ok(text_parts.join("\n"))
}
pub fn text(&self) -> &str {
&self.text
}
pub fn child_records(&self) -> &[PptRecord] {
&self.child_records
}
pub fn find_style_text_prop_atom(&self) -> Option<&PptRecord> {
self.child_records
.iter()
.find(|r| r.record_type == PptRecordType::StyleTextPropAtom)
}
pub fn data(&self) -> &[u8] {
&self.data
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_escher_textbox_wrapper_creation() {
let mut data = Vec::new();
data.extend_from_slice(&[0xA0, 0x0F]); data.extend_from_slice(&[0x0A, 0x00, 0x00, 0x00]); data.extend_from_slice(&[0x00, 0x00]);
data.extend_from_slice(&[
0x48, 0x00, 0x65, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6F, 0x00, ]);
let wrapper = EscherTextboxWrapper::new(data).unwrap();
assert!(wrapper.text().contains("Hello") || !wrapper.text().is_empty());
assert!(!wrapper.child_records().is_empty());
}
}