use super::super::Handle;
use super::refcount::with_obj;
use super::types::{PDF_OBJECTS, PdfObj, PdfObjHandle, PdfObjType};
#[unsafe(no_mangle)]
pub extern "C" fn pdf_copy_array(_ctx: Handle, _doc: Handle, array: PdfObjHandle) -> PdfObjHandle {
let copied = with_obj(array, None, |o| match &o.obj_type {
PdfObjType::Array(arr) => {
let mut new_arr = PdfObj::new_array(arr.len());
if let PdfObjType::Array(ref mut new_vec) = new_arr.obj_type {
for item in arr {
new_vec.push(item.clone());
}
}
Some(new_arr)
}
_ => None,
});
match copied {
Some(obj) => PDF_OBJECTS.insert(obj),
None => 0,
}
}
#[unsafe(no_mangle)]
pub extern "C" fn pdf_copy_dict(_ctx: Handle, _doc: Handle, dict: PdfObjHandle) -> PdfObjHandle {
let copied = with_obj(dict, None, |o| match &o.obj_type {
PdfObjType::Dict(entries) => {
let mut new_dict = PdfObj::new_dict(entries.len());
if let PdfObjType::Dict(ref mut new_entries) = new_dict.obj_type {
for (k, v) in entries {
new_entries.push((k.clone(), v.clone()));
}
}
Some(new_dict)
}
_ => None,
});
match copied {
Some(obj) => PDF_OBJECTS.insert(obj),
None => 0,
}
}
fn deep_copy_obj_inner(obj: &PdfObj) -> PdfObj {
let new_type = match &obj.obj_type {
PdfObjType::Null => PdfObjType::Null,
PdfObjType::Bool(b) => PdfObjType::Bool(*b),
PdfObjType::Int(i) => PdfObjType::Int(*i),
PdfObjType::Real(r) => PdfObjType::Real(*r),
PdfObjType::Name(s) => PdfObjType::Name(s.clone()),
PdfObjType::String(s) => PdfObjType::String(s.clone()),
PdfObjType::Array(arr) => PdfObjType::Array(arr.iter().map(deep_copy_obj_inner).collect()),
PdfObjType::Dict(entries) => PdfObjType::Dict(
entries
.iter()
.map(|(k, v)| (k.clone(), deep_copy_obj_inner(v)))
.collect(),
),
PdfObjType::Indirect { num, generation } => PdfObjType::Indirect {
num: *num,
generation: *generation,
},
PdfObjType::Stream { dict, data } => PdfObjType::Stream {
dict: Box::new(deep_copy_obj_inner(dict)),
data: data.clone(),
},
};
PdfObj {
obj_type: new_type,
marked: false,
dirty: false,
parent_num: 0,
refs: 1,
}
}
#[unsafe(no_mangle)]
pub extern "C" fn pdf_deep_copy_obj(_ctx: Handle, _doc: Handle, obj: PdfObjHandle) -> PdfObjHandle {
let copied = with_obj(obj, None, |o| Some(deep_copy_obj_inner(o)));
match copied {
Some(new_obj) => PDF_OBJECTS.insert(new_obj),
None => 0,
}
}
#[cfg(test)]
mod tests {
use super::super::create::{pdf_new_dict, pdf_new_indirect, pdf_new_name, pdf_new_string};
use super::super::refcount::pdf_drop_obj;
use super::super::types::{PDF_OBJECTS, PdfObj, PdfObjType};
use super::*;
use std::ffi::CString;
#[test]
fn test_pdf_copy_array_non_array() {
let int_obj = super::super::create::pdf_new_int(0, 42);
let result = pdf_copy_array(0, 0, int_obj);
assert_eq!(result, 0);
}
#[test]
fn test_pdf_copy_dict_non_dict() {
let int_obj = super::super::create::pdf_new_int(0, 42);
let result = pdf_copy_dict(0, 0, int_obj);
assert_eq!(result, 0);
}
#[test]
fn test_pdf_deep_copy_indirect() {
let indirect = pdf_new_indirect(0, 0, 10, 2);
let copy = pdf_deep_copy_obj(0, 0, indirect);
assert_ne!(copy, 0);
pdf_drop_obj(0, copy);
pdf_drop_obj(0, indirect);
}
#[test]
fn test_pdf_deep_copy_stream() {
let stream_dict = PdfObj::new_dict(0);
let stream_obj = PdfObj {
obj_type: PdfObjType::Stream {
dict: Box::new(stream_dict),
data: vec![1, 2, 3],
},
marked: false,
dirty: false,
parent_num: 0,
refs: 1,
};
let handle = PDF_OBJECTS.insert(stream_obj);
let copy = pdf_deep_copy_obj(0, 0, handle);
assert_ne!(copy, 0);
pdf_drop_obj(0, copy);
pdf_drop_obj(0, handle);
}
#[test]
fn test_pdf_deep_copy_with_name_and_string() {
let dict = pdf_new_dict(0, 0, 2);
let key = pdf_new_name(0, CString::new("Key").unwrap().as_ptr());
let val = pdf_new_string(0, b"value".as_ptr() as *const i8, 5);
super::super::dict::pdf_dict_put(0, dict, key, val);
let copy = pdf_deep_copy_obj(0, 0, dict);
assert_ne!(copy, 0);
pdf_drop_obj(0, copy);
pdf_drop_obj(0, dict);
}
}