use std::path::{Path, PathBuf};
use crate::content::BinaryValue;
pub const TEXT_EXTRACTION_ERROR: &str = "TextExtractionError";
const STRIP_LENGTH: usize = 6;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum BinaryTextFallback {
Marker,
Skip,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct BinaryTextPolicy {
fallback: BinaryTextFallback,
pre_extracted_text_directory: Option<PathBuf>,
}
impl BinaryTextPolicy {
#[must_use]
pub const fn new(fallback: BinaryTextFallback) -> Self {
Self {
fallback,
pre_extracted_text_directory: None,
}
}
#[must_use]
pub fn with_pre_extracted_text_directory(mut self, directory: PathBuf) -> Self {
self.pre_extracted_text_directory = Some(directory);
self
}
#[must_use]
pub const fn fallback(&self) -> BinaryTextFallback {
self.fallback
}
#[must_use]
pub fn pre_extracted_text_directory(&self) -> Option<&Path> {
self.pre_extracted_text_directory.as_deref()
}
#[must_use]
pub fn text_of(&self, value: &BinaryValue, has_mime_type: bool) -> Option<String> {
if !has_mime_type {
return None;
}
if let BinaryValue::External { blob_identifier } = value
&& let Some(text) = self.pre_extracted_text(blob_identifier)
{
return Some(text);
}
match self.fallback {
BinaryTextFallback::Marker => Some(TEXT_EXTRACTION_ERROR.to_owned()),
BinaryTextFallback::Skip => None,
}
}
fn pre_extracted_text(&self, blob_identifier: &str) -> Option<String> {
let directory = self.pre_extracted_text_directory.as_ref()?;
let identity = blob_identifier.split('#').next()?;
if identity.len() <= STRIP_LENGTH {
return None;
}
let mut path = directory.clone();
for level in 0..STRIP_LENGTH / 2 {
path.push(&identity[level * 2..level * 2 + 2]);
}
path.push(identity);
std::fs::read_to_string(path).ok()
}
}