mod dto;
mod error;
pub use dto::{WpdDocument, WpdEvent, WpdMetadata};
pub use error::WpdError;
#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))]
mod imp {
use crate::{WpdDocument, WpdError, dto};
use std::ffi::CStr;
use std::os::raw::{c_char, c_int, c_uchar, c_ulong};
use std::{ptr, slice};
unsafe extern "C" {
fn xberg_wpd_is_supported(data: *const c_uchar, len: c_ulong) -> c_int;
fn xberg_wpd_extract_document(
data: *const c_uchar,
len: c_ulong,
out_buf: *mut *mut c_char,
out_len: *mut c_ulong,
out_err: *mut *mut c_char,
) -> c_int;
fn xberg_wpd_free_string(s: *mut c_char);
#[cfg(test)]
fn xberg_wpd_self_test_separation() -> c_int;
#[cfg(test)]
fn xberg_wpd_self_test_features() -> c_int;
}
pub fn is_supported(data: &[u8]) -> bool {
if data.is_empty() || data.len() > u32::MAX as usize {
return false;
}
unsafe { xberg_wpd_is_supported(data.as_ptr(), data.len() as c_ulong) != 0 }
}
pub fn extract_document(data: &[u8]) -> Result<WpdDocument, WpdError> {
if data.is_empty() || data.len() > u32::MAX as usize {
return Err(WpdError::InvalidArgs);
}
let mut out: *mut c_char = ptr::null_mut();
let mut out_len: c_ulong = 0;
let mut out_err: *mut c_char = ptr::null_mut();
let code = unsafe {
xberg_wpd_extract_document(
data.as_ptr(),
data.len() as c_ulong,
&mut out,
&mut out_len,
&mut out_err,
)
};
if !out_err.is_null() {
let detail = unsafe {
let msg = CStr::from_ptr(out_err).to_string_lossy().into_owned();
xberg_wpd_free_string(out_err);
msg
};
tracing::warn!(code, error = %detail, "libwpd raised an exception during extraction");
}
if code != 0 {
if !out.is_null() {
unsafe { xberg_wpd_free_string(out) };
}
return Err(WpdError::from_code(code));
}
if out.is_null() {
return Err(WpdError::Internal);
}
let bytes = unsafe {
let bytes = slice::from_raw_parts(out as *const u8, out_len as usize).to_vec();
xberg_wpd_free_string(out);
bytes
};
dto::decode(&bytes)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn collector_separates_asides_from_body() {
assert_eq!(unsafe { xberg_wpd_self_test_separation() }, 1);
}
#[test]
fn collector_captures_links_tables_fields_and_notes() {
assert_eq!(unsafe { xberg_wpd_self_test_features() }, 1);
}
}
}
#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
mod imp {
pub fn is_supported(_data: &[u8]) -> bool {
false
}
pub fn extract_document(_data: &[u8]) -> Result<super::WpdDocument, super::WpdError> {
Err(super::WpdError::UnsupportedPlatform)
}
}
pub use imp::{extract_document, is_supported};