use std::{ffi::CString, path::Path};
use crate::{ffi, XmpError, XmpErrorType, XmpMeta, XmpResult};
pub struct XmpFile {
f: *mut ffi::CXmpFile,
}
impl Drop for XmpFile {
fn drop(&mut self) {
unsafe {
ffi::CXmpFileDrop(self.f);
}
}
}
impl XmpFile {
pub fn new() -> XmpResult<XmpFile> {
let mut err = ffi::CXmpError::default();
let f = unsafe { ffi::CXmpFileNew(&mut err) };
XmpError::raise_from_c(&err)?;
Ok(XmpFile { f })
}
pub fn open_file<P: AsRef<Path>>(&mut self, path: P, flags: OpenFileOptions) -> XmpResult<()> {
if let Some(c_path) = path_to_cstr(path.as_ref()) {
let mut err = ffi::CXmpError::default();
unsafe {
ffi::CXmpFileOpen(self.f, &mut err, c_path.as_ptr(), flags.options);
}
XmpError::raise_from_c(&err)
} else {
Err(XmpError {
error_type: XmpErrorType::BadParam,
debug_message: "Could not convert path to C string".to_owned(),
})
}
}
pub fn xmp(&mut self) -> Option<XmpMeta> {
unsafe {
let m = ffi::CXmpFileGetXmp(self.f);
if m.is_null() {
None
} else {
Some(XmpMeta { m: Some(m) })
}
}
}
pub fn can_put_xmp(&self, meta: &XmpMeta) -> bool {
if let Some(m) = meta.m {
unsafe { ffi::CXmpFileCanPutXmp(self.f, m) != 0 }
} else {
false
}
}
pub fn put_xmp(&mut self, meta: &XmpMeta) -> XmpResult<()> {
if let Some(m) = meta.m {
let mut err = ffi::CXmpError::default();
unsafe { ffi::CXmpFilePutXmp(self.f, &mut err, m) };
XmpError::raise_from_c(&err)
} else {
Err(crate::xmp_meta::no_cpp_toolkit())
}
}
pub fn close(&mut self) {
let _ = self.try_close();
}
pub fn try_close(&mut self) -> XmpResult<()> {
let mut err = ffi::CXmpError::default();
unsafe { ffi::CXmpFileClose(self.f, &mut err) };
XmpError::raise_from_c(&err)
}
}
#[derive(Default)]
pub struct OpenFileOptions {
pub(crate) options: u32,
}
impl OpenFileOptions {
pub fn for_read(mut self) -> Self {
self.options |= 0x00000001;
self
}
pub fn for_update(mut self) -> Self {
self.options |= 0x00000002;
self
}
pub fn only_xmp(mut self) -> Self {
self.options |= 0x00000004;
self
}
pub fn force_given_handler(mut self) -> Self {
self.options |= 0x00000008;
self
}
pub fn strict(mut self) -> Self {
self.options |= 0x00000010;
self
}
pub fn use_smart_handler(mut self) -> Self {
self.options |= 0x00000020;
self
}
pub fn use_packet_scanning(mut self) -> Self {
self.options |= 0x00000040;
self
}
pub fn limited_scanning(mut self) -> Self {
self.options |= 0x00000080;
self
}
pub fn repair_file(mut self) -> Self {
self.options |= 0x00000100;
self
}
pub fn optimize_file_layout(mut self) -> Self {
self.options |= 0x00000200;
self
}
}
fn path_to_cstr(path: &Path) -> Option<CString> {
path.to_str()
.and_then(|path_str| CString::new(path_str).ok())
}