use std::alloc::{alloc, dealloc, Layout};
static mut RESULT_BUF: *mut u8 = std::ptr::null_mut();
static mut RESULT_LEN: usize = 0;
static mut ERROR_BUF: *mut u8 = std::ptr::null_mut();
static mut ERROR_LEN: usize = 0;
#[no_mangle]
pub extern "C" fn forme_alloc(size: usize, align: usize) -> *mut u8 {
let layout = match Layout::from_size_align(size, align) {
Ok(l) => l,
Err(_) => return std::ptr::null_mut(),
};
unsafe { alloc(layout) }
}
#[no_mangle]
pub unsafe extern "C" fn forme_dealloc(ptr: *mut u8, size: usize, align: usize) {
if ptr.is_null() || size == 0 {
return;
}
let layout = match Layout::from_size_align(size, align) {
Ok(l) => l,
Err(_) => return,
};
dealloc(ptr, layout);
}
#[no_mangle]
pub unsafe extern "C" fn forme_render_pdf(ptr: *const u8, len: usize) -> i32 {
free_result_buf();
free_error_buf();
let json_bytes = std::slice::from_raw_parts(ptr, len);
let json_str = match std::str::from_utf8(json_bytes) {
Ok(s) => s,
Err(e) => {
set_error(&format!("Invalid UTF-8: {e}"));
return 1;
}
};
match crate::render_json(json_str) {
Ok(pdf_bytes) => {
let len = pdf_bytes.len();
let layout = Layout::from_size_align(len, 1).unwrap();
let buf = alloc(layout);
std::ptr::copy_nonoverlapping(pdf_bytes.as_ptr(), buf, len);
RESULT_BUF = buf;
RESULT_LEN = len;
0
}
Err(e) => {
set_error(&e.to_string());
1
}
}
}
#[no_mangle]
pub unsafe extern "C" fn forme_certify_pdf(
pdf_ptr: *const u8,
pdf_len: usize,
config_ptr: *const u8,
config_len: usize,
) -> i32 {
free_result_buf();
free_error_buf();
let pdf_bytes = std::slice::from_raw_parts(pdf_ptr, pdf_len);
let config_bytes = std::slice::from_raw_parts(config_ptr, config_len);
let config_str = match std::str::from_utf8(config_bytes) {
Ok(s) => s,
Err(e) => {
set_error(&format!("Invalid UTF-8 in config: {e}"));
return 1;
}
};
let config: crate::model::CertificationConfig = match serde_json::from_str(config_str) {
Ok(c) => c,
Err(e) => {
set_error(&format!("Invalid certification config JSON: {e}"));
return 1;
}
};
match crate::certify_pdf(pdf_bytes, &config) {
Ok(certified_bytes) => {
let len = certified_bytes.len();
let layout = Layout::from_size_align(len, 1).unwrap();
let buf = alloc(layout);
std::ptr::copy_nonoverlapping(certified_bytes.as_ptr(), buf, len);
RESULT_BUF = buf;
RESULT_LEN = len;
0
}
Err(e) => {
set_error(&e.to_string());
1
}
}
}
#[no_mangle]
pub extern "C" fn forme_get_result_ptr() -> *const u8 {
unsafe { RESULT_BUF }
}
#[no_mangle]
pub extern "C" fn forme_get_result_len() -> usize {
unsafe { RESULT_LEN }
}
#[no_mangle]
pub extern "C" fn forme_get_error_ptr() -> *const u8 {
unsafe { ERROR_BUF }
}
#[no_mangle]
pub extern "C" fn forme_get_error_len() -> usize {
unsafe { ERROR_LEN }
}
#[no_mangle]
pub extern "C" fn forme_free_result() {
unsafe { free_result_buf() }
}
fn set_error(msg: &str) {
let bytes = msg.as_bytes();
let len = bytes.len();
let layout = Layout::from_size_align(len, 1).unwrap();
unsafe {
let buf = alloc(layout);
std::ptr::copy_nonoverlapping(bytes.as_ptr(), buf, len);
ERROR_BUF = buf;
ERROR_LEN = len;
}
}
unsafe fn free_result_buf() {
if !RESULT_BUF.is_null() && RESULT_LEN > 0 {
let layout = Layout::from_size_align(RESULT_LEN, 1).unwrap();
dealloc(RESULT_BUF, layout);
RESULT_BUF = std::ptr::null_mut();
RESULT_LEN = 0;
}
}
unsafe fn free_error_buf() {
if !ERROR_BUF.is_null() && ERROR_LEN > 0 {
let layout = Layout::from_size_align(ERROR_LEN, 1).unwrap();
dealloc(ERROR_BUF, layout);
ERROR_BUF = std::ptr::null_mut();
ERROR_LEN = 0;
}
}