use super::document::CPDF_DOCS;
use super::{clear_error, set_error};
use crate::cpdf::encryption::{self, EncryptionMethod};
use crate::ffi::Handle;
use std::ffi::{CStr, c_char, c_int};
macro_rules! get_doc_clone {
($handle:expr) => {
match CPDF_DOCS.get($handle) {
Some(arc) => arc.lock().unwrap().clone(),
None => {
set_error(1, &format!("invalid document handle: {}", $handle));
return 0;
}
}
};
}
macro_rules! get_doc_ref {
($handle:expr) => {
match CPDF_DOCS.get($handle) {
Some(arc) => arc,
None => {
set_error(1, &format!("invalid document handle: {}", $handle));
return 0;
}
}
};
}
macro_rules! ok_or_error {
($result:expr) => {
match $result {
Ok(doc) => CPDF_DOCS.insert(doc),
Err(e) => {
set_error(1, &e.to_string());
0
}
}
};
}
#[unsafe(no_mangle)]
pub extern "C" fn cpdf_encrypted(doc: Handle) -> c_int {
clear_error();
let d = get_doc_ref!(doc);
let guard = d.lock().unwrap();
if encryption::is_encrypted(&guard) {
1
} else {
0
}
}
#[unsafe(no_mangle)]
pub extern "C" fn cpdf_hasPermission(doc: Handle, password: *const c_char, perm_bit: u32) -> c_int {
clear_error();
let d = get_doc_ref!(doc);
let guard = d.lock().unwrap();
let pw = if password.is_null() {
""
} else {
unsafe { CStr::from_ptr(password) }.to_str().unwrap_or("")
};
match encryption::has_permission(&guard, pw, perm_bit) {
Ok(true) => 1,
Ok(false) => 0,
Err(e) => {
set_error(1, &e.to_string());
0
}
}
}
#[unsafe(no_mangle)]
pub extern "C" fn cpdf_encrypt(
doc: Handle,
method_code: c_int,
user_pw: *const c_char,
owner_pw: *const c_char,
perms_bits: u32,
) -> Handle {
clear_error();
let d = get_doc_clone!(doc);
let method = match EncryptionMethod::from_code(method_code) {
Ok(m) => m,
Err(e) => {
set_error(1, &e.to_string());
return 0;
}
};
let upw = if user_pw.is_null() {
""
} else {
unsafe { CStr::from_ptr(user_pw) }.to_str().unwrap_or("")
};
let opw = if owner_pw.is_null() {
""
} else {
unsafe { CStr::from_ptr(owner_pw) }.to_str().unwrap_or("")
};
ok_or_error!(encryption::encrypt(d, method, upw, opw, perms_bits))
}
#[unsafe(no_mangle)]
pub extern "C" fn cpdf_decrypt(doc: Handle, password: *const c_char) -> Handle {
clear_error();
let d = get_doc_ref!(doc);
let guard = d.lock().unwrap();
let pw = if password.is_null() {
""
} else {
unsafe { CStr::from_ptr(password) }.to_str().unwrap_or("")
};
ok_or_error!(encryption::decrypt(&guard, pw))
}
#[unsafe(no_mangle)]
pub extern "C" fn cpdf_decryptIfNeeded(doc: Handle, password: *const c_char) -> Handle {
clear_error();
let d = get_doc_clone!(doc);
let pw = if password.is_null() {
""
} else {
unsafe { CStr::from_ptr(password) }.to_str().unwrap_or("")
};
ok_or_error!(encryption::decrypt_if_needed(d, pw))
}