use std::{cmp::Ordering, ffi::CStr, fmt, slice};
use crate::QPdf;
#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Hash)]
pub enum QPdfObjectType {
Uninitialized,
Reserved,
Null,
Boolean,
Integer,
Real,
String,
Name,
Array,
Dictionary,
Stream,
Operator,
InlineImage,
}
impl QPdfObjectType {
fn from_qpdf_enum(obj_t: qpdf_sys::qpdf_object_type_e) -> Self {
match obj_t {
qpdf_sys::qpdf_object_type_e_ot_uninitialized => QPdfObjectType::Uninitialized,
qpdf_sys::qpdf_object_type_e_ot_reserved => QPdfObjectType::Reserved,
qpdf_sys::qpdf_object_type_e_ot_null => QPdfObjectType::Null,
qpdf_sys::qpdf_object_type_e_ot_boolean => QPdfObjectType::Boolean,
qpdf_sys::qpdf_object_type_e_ot_integer => QPdfObjectType::Integer,
qpdf_sys::qpdf_object_type_e_ot_real => QPdfObjectType::Real,
qpdf_sys::qpdf_object_type_e_ot_string => QPdfObjectType::String,
qpdf_sys::qpdf_object_type_e_ot_name => QPdfObjectType::Name,
qpdf_sys::qpdf_object_type_e_ot_array => QPdfObjectType::Array,
qpdf_sys::qpdf_object_type_e_ot_dictionary => QPdfObjectType::Dictionary,
qpdf_sys::qpdf_object_type_e_ot_stream => QPdfObjectType::Stream,
qpdf_sys::qpdf_object_type_e_ot_operator => QPdfObjectType::Operator,
qpdf_sys::qpdf_object_type_e_ot_inlineimage => QPdfObjectType::InlineImage,
_ => panic!("Unexpected object type!"),
}
}
}
pub trait QPdfObjectLike {
fn as_object(&self) -> &QPdfObject;
fn owner(&self) -> QPdf {
self.as_object().owner.clone()
}
fn get_type(&self) -> QPdfObjectType {
self.as_object().get_type()
}
fn to_binary(&self) -> String {
self.as_object().to_binary()
}
fn is_operator(&self) -> bool {
self.as_object().is_operator()
}
fn is_scalar(&self) -> bool {
self.as_object().is_scalar()
}
fn is_indirect(&self) -> bool {
self.as_object().is_indirect()
}
fn as_bool(&self) -> bool {
self.as_object().as_bool()
}
fn as_name(&self) -> String {
self.as_object().as_name()
}
fn as_string(&self) -> String {
self.as_object().as_string()
}
fn as_binary_string(&self) -> Vec<u8> {
self.as_object().as_binary_string()
}
fn get_id(&self) -> u32 {
self.as_object().get_id()
}
fn get_generation(&self) -> u32 {
self.as_object().get_generation()
}
fn into_indirect(self) -> QPdfObject
where
Self: Sized + Into<QPdfObject>,
{
let obj: QPdfObject = self.into();
obj.into_indirect()
}
}
pub struct QPdfObject {
pub(crate) owner: QPdf,
pub(crate) inner: qpdf_sys::qpdf_oh,
}
impl QPdfObject {
pub(crate) fn new(owner: QPdf, inner: qpdf_sys::qpdf_oh) -> Self {
QPdfObject { owner, inner }
}
}
impl QPdfObjectLike for QPdfObject {
fn as_object(&self) -> &QPdfObject {
self
}
fn get_type(&self) -> QPdfObjectType {
unsafe { QPdfObjectType::from_qpdf_enum(qpdf_sys::qpdf_oh_get_type_code(self.owner.inner(), self.inner)) }
}
fn to_binary(&self) -> String {
unsafe {
CStr::from_ptr(qpdf_sys::qpdf_oh_unparse_binary(self.owner.inner(), self.inner))
.to_string_lossy()
.into_owned()
}
}
fn is_operator(&self) -> bool {
unsafe { qpdf_sys::qpdf_oh_is_operator(self.owner.inner(), self.inner) != 0 }
}
fn is_scalar(&self) -> bool {
unsafe { qpdf_sys::qpdf_oh_is_scalar(self.owner.inner(), self.inner) != 0 }
}
fn is_indirect(&self) -> bool {
unsafe { qpdf_sys::qpdf_oh_is_indirect(self.owner.inner(), self.inner) != 0 }
}
fn as_bool(&self) -> bool {
unsafe { qpdf_sys::qpdf_oh_get_bool_value(self.owner.inner(), self.inner) != 0 }
}
fn as_name(&self) -> String {
unsafe {
CStr::from_ptr(qpdf_sys::qpdf_oh_get_name(self.owner.inner(), self.inner))
.to_string_lossy()
.into_owned()
}
}
fn as_string(&self) -> String {
unsafe {
CStr::from_ptr(qpdf_sys::qpdf_oh_get_utf8_value(self.owner.inner(), self.inner))
.to_string_lossy()
.into_owned()
}
}
fn as_binary_string(&self) -> Vec<u8> {
unsafe {
let mut length = 0;
let data = qpdf_sys::qpdf_oh_get_binary_string_value(self.owner.inner(), self.inner, &mut length);
slice::from_raw_parts(data as *const u8, length as _).to_vec()
}
}
fn get_id(&self) -> u32 {
unsafe { qpdf_sys::qpdf_oh_get_object_id(self.owner.inner(), self.inner) as _ }
}
fn get_generation(&self) -> u32 {
unsafe { qpdf_sys::qpdf_oh_get_generation(self.owner.inner(), self.inner) as _ }
}
fn into_indirect(self) -> QPdfObject {
unsafe {
QPdfObject::new(
self.owner.clone(),
qpdf_sys::qpdf_make_indirect_object(self.owner.inner(), self.inner),
)
}
}
}
impl AsRef<QPdfObject> for QPdfObject {
fn as_ref(&self) -> &QPdfObject {
self
}
}
impl fmt::Debug for QPdfObject {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "QpdfObject {{ {self} }}")
}
}
impl Clone for QPdfObject {
fn clone(&self) -> Self {
unsafe {
QPdfObject {
owner: self.owner.clone(),
inner: qpdf_sys::qpdf_oh_new_object(self.owner.inner(), self.inner),
}
}
}
}
impl PartialEq for QPdfObject {
fn eq(&self, other: &Self) -> bool {
self.inner == other.inner
}
}
impl PartialOrd for QPdfObject {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.inner.partial_cmp(&other.inner)
}
}
impl Drop for QPdfObject {
fn drop(&mut self) {
unsafe {
qpdf_sys::qpdf_oh_release(self.owner.inner(), self.inner);
}
}
}
impl fmt::Display for QPdfObject {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
unsafe {
write!(
f,
"{}",
CStr::from_ptr(qpdf_sys::qpdf_oh_unparse(self.owner.inner(), self.inner)).to_string_lossy()
)
}
}
}