diff --git a/README.md b/README.md index 69bf7bc..a5d3f6b 100644 --- a/README.md +++ b/README.md @@ -185,6 +185,9 @@ assert_eq!(kind.extension(), "foo"); - **xlsx** - `application/vnd.openxmlformats-officedocument.spreadsheetml.sheet` - **ppt** - `application/vnd.ms-powerpoint` - **pptx** - `application/vnd.openxmlformats-officedocument.presentationml.presentation` +- **odt** - `application/vnd.oasis.opendocument.text` +- **ods** - `application/vnd.oasis.opendocument.spreadsheet` +- **odp** - `application/vnd.oasis.opendocument.presentation` #### Font diff --git a/src/map.rs b/src/map.rs index e2108a0..83c8248 100644 --- a/src/map.rs +++ b/src/map.rs @@ -357,6 +357,25 @@ matcher_map!( "pptx", matchers::doc::is_pptx ), + // OpenDocument + ( + MatcherType::Doc, + "application/vnd.oasis.opendocument.text", + "odt", + matchers::odf::is_odt + ), + ( + MatcherType::Doc, + "application/vnd.oasis.opendocument.spreadsheet", + "ods", + matchers::odf::is_ods + ), + ( + MatcherType::Doc, + "application/vnd.oasis.opendocument.presentation", + "odp", + matchers::odf::is_odp + ), // Archive ( MatcherType::Archive, diff --git a/src/matchers/doc.rs b/src/matchers/doc.rs index ced49c4..991de7b 100644 --- a/src/matchers/doc.rs +++ b/src/matchers/doc.rs @@ -1,5 +1,7 @@ use core::convert::TryInto; +use super::compare_bytes; + #[allow(clippy::upper_case_acronyms)] #[derive(Debug, Eq, PartialEq)] enum DocType { @@ -123,24 +125,6 @@ fn ole2(buf: &[u8]) -> Option { Some(DocType::DOC) } -fn compare_bytes(slice: &[u8], sub_slice: &[u8], start_offset: usize) -> bool { - let sl = sub_slice.len(); - - if start_offset + sl > slice.len() { - return false; - } - - for (i, v) in slice.iter().skip(start_offset).take(sl).enumerate() { - let v2 = sub_slice[i]; - - if *v != v2 { - return false; - } - } - - true -} - fn check_msooml(buf: &[u8], offset: usize) -> Option { if compare_bytes(buf, &[b'w', b'o', b'r', b'd', b'/'], offset) { Some(DocType::DOCX) diff --git a/src/matchers/mod.rs b/src/matchers/mod.rs index 7086835..30ed410 100644 --- a/src/matchers/mod.rs +++ b/src/matchers/mod.rs @@ -5,5 +5,24 @@ pub mod book; pub mod doc; pub mod font; pub mod image; +pub mod odf; pub mod text; pub mod video; + +pub(crate) fn compare_bytes(slice: &[u8], sub_slice: &[u8], start_offset: usize) -> bool { + let sl = sub_slice.len(); + + if start_offset + sl > slice.len() { + return false; + } + + for (i, v) in slice.iter().skip(start_offset).take(sl).enumerate() { + let v2 = sub_slice[i]; + + if *v != v2 { + return false; + } + } + + true +} diff --git a/src/matchers/odf.rs b/src/matchers/odf.rs new file mode 100644 index 0000000..bc0a1de --- /dev/null +++ b/src/matchers/odf.rs @@ -0,0 +1,48 @@ +use super::compare_bytes; + +#[derive(Debug, Eq, PartialEq)] +enum DocType { + Text, + Spreadsheet, + Presentation, +} + +/// Returns whether a buffer is OpenDocument Text +pub fn is_odt(buf: &[u8]) -> bool { + odf(buf) == Some(DocType::Text) +} + +/// Returns whether a buffer is OpenDocument Spreadsheet +pub fn is_ods(buf: &[u8]) -> bool { + odf(buf) == Some(DocType::Spreadsheet) +} + +/// Returns whether a buffer is OpenDocument Presentation +pub fn is_odp(buf: &[u8]) -> bool { + odf(buf) == Some(DocType::Presentation) +} + +fn odf(buf: &[u8]) -> Option { + let signature = [b'P', b'K', 0x03, 0x04]; + + // start by checking for ZIP local file header signature + if !compare_bytes(buf, &signature, 0) { + return None; + } + + // Check mimetype + if !compare_bytes(buf, b"mimetype", 0x1E) { + return None; + } + + if compare_bytes(buf, b"vnd.oasis.opendocument.text", 0x32) { + return Some(DocType::Text); + } + if compare_bytes(buf, b"vnd.oasis.opendocument.spreadsheet", 0x32) { + return Some(DocType::Spreadsheet); + } + if compare_bytes(buf, b"vnd.oasis.opendocument.presentation", 0x32) { + return Some(DocType::Presentation); + } + None +} diff --git a/testdata/sample.odp b/testdata/sample.odp new file mode 100644 index 0000000..8c03690 Binary files /dev/null and b/testdata/sample.odp differ diff --git a/testdata/sample.ods b/testdata/sample.ods new file mode 100644 index 0000000..6a9eaa8 Binary files /dev/null and b/testdata/sample.ods differ diff --git a/testdata/sample.odt b/testdata/sample.odt new file mode 100644 index 0000000..49100b2 Binary files /dev/null and b/testdata/sample.odt differ diff --git a/tests/odf.rs b/tests/odf.rs new file mode 100644 index 0000000..7d8808f --- /dev/null +++ b/tests/odf.rs @@ -0,0 +1,25 @@ +mod common; + +test_format!( + Doc, + "application/vnd.oasis.opendocument.text", + "odt", + odt, + "sample.odt" +); + +test_format!( + Doc, + "application/vnd.oasis.opendocument.spreadsheet", + "ods", + ods, + "sample.ods" +); + +test_format!( + Doc, + "application/vnd.oasis.opendocument.presentation", + "odp", + odp, + "sample.odp" +);