micropdf 0.16.0

A pure Rust PDF library - A pure Rust PDF library with fz_/pdf_ API compatibility
//! C FFI for cpdf font operations.

use super::document::{CPDF_DOCS, CPDF_RANGES};
use super::{clear_error, set_error};
use crate::cpdf::fonts;
use crate::ffi::Handle;

#[unsafe(no_mangle)]
pub extern "C" fn cpdf_listFontsJSON(doc: Handle, range_h: Handle, len_out: *mut usize) -> *mut u8 {
    clear_error();
    let d = match CPDF_DOCS.get(doc) {
        Some(arc) => arc,
        None => {
            set_error(1, &format!("invalid handle: {doc}"));
            return std::ptr::null_mut();
        }
    };
    let r = match CPDF_RANGES.get(range_h) {
        Some(arc) => arc.lock().unwrap().clone(),
        None => {
            set_error(1, &format!("invalid range: {range_h}"));
            return std::ptr::null_mut();
        }
    };
    let guard = d.lock().unwrap();
    match fonts::list_fonts_json(&guard, &r) {
        Ok(json) => {
            let bytes = json.into_bytes();
            let len = bytes.len();
            let ptr = unsafe {
                let layout = std::alloc::Layout::from_size_align_unchecked(len, 1);
                let p = std::alloc::alloc(layout);
                if p.is_null() {
                    set_error(1, "alloc failed");
                    return std::ptr::null_mut();
                }
                std::ptr::copy_nonoverlapping(bytes.as_ptr(), p, len);
                p
            };
            if !len_out.is_null() {
                unsafe {
                    *len_out = len;
                }
            }
            ptr
        }
        Err(e) => {
            set_error(1, &e.to_string());
            std::ptr::null_mut()
        }
    }
}

#[unsafe(no_mangle)]
pub extern "C" fn cpdf_removeFonts(doc: Handle) -> Handle {
    clear_error();
    let d = match CPDF_DOCS.get(doc) {
        Some(arc) => arc.lock().unwrap().clone(),
        None => {
            set_error(1, &format!("invalid handle: {doc}"));
            return 0;
        }
    };
    match fonts::remove_fonts(d) {
        Ok(doc) => CPDF_DOCS.insert(doc),
        Err(e) => {
            set_error(1, &e.to_string());
            0
        }
    }
}

#[unsafe(no_mangle)]
pub extern "C" fn cpdf_missingFontsJSON(
    doc: Handle,
    range_h: Handle,
    len_out: *mut usize,
) -> *mut u8 {
    clear_error();
    let d = match CPDF_DOCS.get(doc) {
        Some(arc) => arc,
        None => {
            set_error(1, &format!("invalid handle: {doc}"));
            return std::ptr::null_mut();
        }
    };
    let r = match CPDF_RANGES.get(range_h) {
        Some(arc) => arc.lock().unwrap().clone(),
        None => {
            set_error(1, &format!("invalid range: {range_h}"));
            return std::ptr::null_mut();
        }
    };
    let guard = d.lock().unwrap();
    match fonts::missing_fonts(&guard, &r) {
        Ok(info) => {
            let json = match serde_json::to_string_pretty(&info) {
                Ok(j) => j,
                Err(e) => {
                    set_error(1, &e.to_string());
                    return std::ptr::null_mut();
                }
            };
            let bytes = json.into_bytes();
            let len = bytes.len();
            let ptr = unsafe {
                let layout = std::alloc::Layout::from_size_align_unchecked(len, 1);
                let p = std::alloc::alloc(layout);
                if p.is_null() {
                    set_error(1, "alloc failed");
                    return std::ptr::null_mut();
                }
                std::ptr::copy_nonoverlapping(bytes.as_ptr(), p, len);
                p
            };
            if !len_out.is_null() {
                unsafe {
                    *len_out = len;
                }
            }
            ptr
        }
        Err(e) => {
            set_error(1, &e.to_string());
            std::ptr::null_mut()
        }
    }
}