use crate::common::codepages;
use crate::error::Result;
use crate::vba::decompressor;
use crate::vba::project::ModuleType;
#[derive(Debug, Clone)]
pub struct VbaModule {
pub name: String,
pub stream_name: String,
pub source_code: String,
pub module_type: ModuleType,
pub is_private: bool,
}
impl VbaModule {
pub fn extract_source(
stream_data: &[u8],
text_offset: u32,
codepage: u16,
) -> Result<String> {
let offset = text_offset as usize;
if offset >= stream_data.len() {
return Ok(String::new());
}
let compressed = &stream_data[offset..];
let decompressed = decompressor::decompress_stream(compressed)?;
let source = if let Some(encoding) = codepages::codepage_to_encoding(codepage) {
let (decoded, _, _) = encoding.decode(&decompressed);
decoded.into_owned()
} else {
String::from_utf8_lossy(&decompressed).into_owned()
};
Ok(source)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_extract_source_empty_stream() {
let result = VbaModule::extract_source(&[], 0, 1252);
assert!(result.is_err() || result.unwrap().is_empty());
}
#[test]
fn test_extract_source_offset_beyond_stream() {
let data = vec![0x01, 0x02, 0x03];
let result = VbaModule::extract_source(&data, 100, 1252);
assert!(result.is_ok());
assert_eq!(result.unwrap(), "");
}
}