quick_search/crates/quicksearch-core/src/extract/office.rs

70 lines
2.6 KiB
Rust
Raw Normal View History

//! Office document extraction: DOCX, XLSX, PPTX, ODT, ODP, ODS.
//!
//! Delegates to [`crate::document_extraction`] — a single entry point based
//! on file extension rather than MIME. We translate the MIME to the
//! extension expected by that module.
use std::ffi::OsString;
use std::path::Path;
use crate::document_extraction::extract_document_text;
use super::{ExtractError, ExtractedContent, Extractor};
pub struct OfficeExtractor;
fn mime_to_ext(mime: &str) -> Option<&'static str> {
match mime {
"application/msword" => Some("doc"),
"application/vnd.openxmlformats-officedocument.wordprocessingml.document" => Some("docx"),
"application/vnd.ms-excel" => Some("xls"),
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" => Some("xlsx"),
"application/vnd.ms-powerpoint" => Some("ppt"),
"application/vnd.openxmlformats-officedocument.presentationml.presentation" => Some("pptx"),
"application/vnd.oasis.opendocument.text" => Some("odt"),
"application/vnd.oasis.opendocument.spreadsheet" => Some("ods"),
"application/vnd.oasis.opendocument.presentation" => Some("odp"),
_ => None,
}
}
impl Extractor for OfficeExtractor {
fn supports(&self, mime: &str) -> bool {
mime_to_ext(mime).is_some()
}
fn extract(&self, path: &Path) -> Result<ExtractedContent, ExtractError> {
// Recompute the extension from MIME at call time by asking the path.
// Using the filesystem extension directly is more robust than round-
// tripping through MIME: `.docm` has the same MIME as `.docx` but
// `extract_document_text` looks up by extension.
let ext = path
.extension()
.and_then(|s| s.to_str())
.map(|s| s.to_ascii_lowercase())
.unwrap_or_default();
let text = extract_document_text(&OsString::from(path.as_os_str()), &ext)
.map_err(|e| format!("office extractor {}: {}", path.display(), e))?;
Ok(ExtractedContent::with_text(text))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn supports_docx_and_friends() {
let e = OfficeExtractor;
for m in [
"application/msword",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"application/vnd.oasis.opendocument.text",
] {
assert!(e.supports(m), "should support {}", m);
}
assert!(!e.supports("image/png"));
}
}