use crate::extractors::rtf::encoding::parse_rtf_control_word;
pub struct RtfImage {
pub format: &'static str,
pub data: Vec<u8>,
}
pub(crate) fn extract_pict_image(chars: &mut std::iter::Peekable<std::str::Chars>) -> (String, Option<RtfImage>) {
let mut metadata = String::new();
let mut image_type: Option<&str> = None;
let mut format: &str = "jpeg";
let mut depth = 0;
let mut hex_chars = String::new();
let mut _has_bin = false;
while let Some(&ch) = chars.peek() {
match ch {
'{' => {
depth += 1;
chars.next();
}
'}' => {
if depth == 0 {
break;
}
depth -= 1;
chars.next();
}
'\\' => {
chars.next();
let (control_word, value) = parse_rtf_control_word(chars);
match control_word.as_str() {
"jpegblip" => {
image_type = Some("jpg");
format = "jpeg";
}
"pngblip" => {
image_type = Some("png");
format = "png";
}
"wmetafile" => {
image_type = Some("wmf");
format = "wmf";
}
"dibitmap" => {
image_type = Some("bmp");
format = "bmp";
}
"picwgoal" | "pichgoal" => {}
"bin" => {
if let Some(count) = value {
let count = count.max(0) as usize;
for _ in 0..count {
chars.next();
}
_has_bin = true;
}
}
_ => {}
}
}
' ' | '\r' | '\n' => {
chars.next();
}
_ => {
if ch.is_ascii_hexdigit() {
hex_chars.push(ch);
}
chars.next();
}
}
}
if let Some(itype) = image_type {
metadata.push_str("image.");
metadata.push_str(itype);
}
if metadata.is_empty() {
metadata.push_str("image.jpg");
}
let image = if !hex_chars.is_empty() {
match hex::decode(&hex_chars) {
Ok(data) if !data.is_empty() => Some(RtfImage { format, data }),
_ => None,
}
} else {
None
};
(metadata, image)
}