pub mod image;
pub mod numbering;
pub mod sax;
pub(crate) mod semantic;
pub mod table;
pub mod text;
use std::path::Path;
#[must_use]
pub fn detect_format(path: &Path) -> Option<DocumentFormat> {
if let Some(ext) = path.extension().and_then(|e| e.to_str()) {
match ext.to_lowercase().as_str() {
"docx" => return Some(DocumentFormat::Docx),
"doc" => return Some(DocumentFormat::Doc),
_ => {}
}
}
if let Ok(bytes) = std::fs::read(path)
&& bytes.len() >= 8
{
if &bytes[0..4] == b"PK" {
return Some(DocumentFormat::Docx);
}
let ole2_magic: [u8; 8] = [0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1];
if bytes[0..8] == ole2_magic {
return Some(DocumentFormat::Doc);
}
}
None
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DocumentFormat {
Docx,
Doc,
}
impl std::fmt::Display for DocumentFormat {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Docx => write!(f, "DOCX"),
Self::Doc => write!(f, "DOC"),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::io::Write;
#[test]
fn detect_format_docx_extension() {
let path = Path::new("test.docx");
assert_eq!(detect_format(path), Some(DocumentFormat::Docx));
}
#[test]
fn detect_format_doc_extension() {
let path = Path::new("test.doc");
assert_eq!(detect_format(path), Some(DocumentFormat::Doc));
}
#[test]
fn detect_format_unknown_extension() {
let path = Path::new("test.pdf");
assert_eq!(detect_format(path), None);
}
#[test]
fn detect_format_docx_magic_bytes() {
let dir = std::env::temp_dir().join("easydoc_test_fmt1");
std::fs::create_dir_all(&dir).unwrap();
let path = dir.join("test.unknown");
let mut f = std::fs::File::create(&path).unwrap();
f.write_all(b"PK ").unwrap();
drop(f);
assert_eq!(detect_format(&path), Some(DocumentFormat::Docx));
std::fs::remove_file(&path).ok();
}
#[test]
fn detect_format_doc_magic_bytes() {
let dir = std::env::temp_dir().join("easydoc_test_fmt2");
std::fs::create_dir_all(&dir).unwrap();
let path = dir.join("test.unknown");
let mut f = std::fs::File::create(&path).unwrap();
f.write_all(&[0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1])
.unwrap();
drop(f);
assert_eq!(detect_format(&path), Some(DocumentFormat::Doc));
std::fs::remove_file(&path).ok();
}
#[test]
fn detect_format_short_file() {
let dir = std::env::temp_dir().join("easydoc_test_fmt3");
std::fs::create_dir_all(&dir).unwrap();
let path = dir.join("test.short");
std::fs::write(&path, b"AB").unwrap();
assert_eq!(detect_format(&path), None);
std::fs::remove_file(&path).ok();
}
#[test]
fn document_format_display() {
assert_eq!(format!("{}", DocumentFormat::Docx), "DOCX");
assert_eq!(format!("{}", DocumentFormat::Doc), "DOC");
}
#[test]
fn document_format_debug() {
assert_eq!(format!("{:?}", DocumentFormat::Docx), "Docx");
assert_eq!(format!("{:?}", DocumentFormat::Doc), "Doc");
}
#[test]
fn document_format_clone_eq() {
let f = DocumentFormat::Docx;
let f2 = f;
assert_eq!(f, f2);
}
}