parsing more of the pdf structure
This commit is contained in:
parent
83631cc4c6
commit
e0993fdb4a
9 changed files with 1549 additions and 100 deletions
|
|
@ -28,11 +28,23 @@ pub struct PdfString {
|
|||
|
||||
impl std::fmt::Debug for PdfString {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let Self { pos, bytes } = self;
|
||||
f.debug_struct("PdfString")
|
||||
.field("pos", pos)
|
||||
.field("bytes", &format_args!("b\"{}\"", bytes.escape_ascii()))
|
||||
.finish()
|
||||
let Self { pos, bytes: _ } = self;
|
||||
write!(f, "PdfString(at {pos}, {})", self.bytes_debug())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct PdfStringBytesDebug<'a>(&'a [u8]);
|
||||
|
||||
impl<'a> fmt::Display for PdfStringBytesDebug<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "b\"{}\"", self.0.escape_ascii())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> fmt::Debug for PdfStringBytesDebug<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Display::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -49,6 +61,9 @@ impl PdfString {
|
|||
pub fn bytes(&self) -> &ArcOrRef<'static, [u8]> {
|
||||
&self.bytes
|
||||
}
|
||||
pub fn bytes_debug(&self) -> PdfStringBytesDebug<'_> {
|
||||
PdfStringBytesDebug(&self.bytes)
|
||||
}
|
||||
}
|
||||
|
||||
impl GetPdfInputPosition for PdfString {
|
||||
|
|
@ -57,6 +72,50 @@ impl GetPdfInputPosition for PdfString {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub struct PdfDate {
|
||||
text: PdfString,
|
||||
}
|
||||
|
||||
impl fmt::Debug for PdfDate {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let Self { text } = self;
|
||||
let pos = text.pos();
|
||||
write!(f, "PdfDate(at {pos}, {})", text.bytes_debug())
|
||||
}
|
||||
}
|
||||
|
||||
impl IsPdfNull for PdfDate {
|
||||
fn is_pdf_null(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl PdfParse for PdfDate {
|
||||
fn type_name() -> Cow<'static, str> {
|
||||
Cow::Borrowed("date")
|
||||
}
|
||||
fn parse(object: PdfObject) -> Result<Self, PdfParseError> {
|
||||
Self::try_new(PdfString::parse(object)?)
|
||||
}
|
||||
}
|
||||
|
||||
impl PdfDate {
|
||||
pub fn try_new(text: PdfString) -> Result<Self, PdfParseError> {
|
||||
// TODO: check syntax
|
||||
Ok(Self { text })
|
||||
}
|
||||
pub fn text(&self) -> &PdfString {
|
||||
&self.text
|
||||
}
|
||||
}
|
||||
|
||||
impl GetPdfInputPosition for PdfDate {
|
||||
fn get_pdf_input_position(&self) -> PdfInputPosition {
|
||||
self.text.pos()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct PdfName {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
|
|
@ -138,12 +197,19 @@ impl fmt::Display for PdfName {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Default)]
|
||||
#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord, Default)]
|
||||
pub struct PdfBoolean {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
value: bool,
|
||||
}
|
||||
|
||||
impl fmt::Debug for PdfBoolean {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let Self { pos, value } = *self;
|
||||
write!(f, "PdfBoolean(at {pos}, {value})")
|
||||
}
|
||||
}
|
||||
|
||||
impl PdfBoolean {
|
||||
pub fn new(pos: impl Into<PdfInputPositionNoCompare>, value: bool) -> Self {
|
||||
Self {
|
||||
|
|
@ -165,12 +231,19 @@ impl GetPdfInputPosition for PdfBoolean {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Default)]
|
||||
#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord, Default)]
|
||||
pub struct PdfInteger {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
value: i128,
|
||||
}
|
||||
|
||||
impl fmt::Debug for PdfInteger {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let Self { pos, value } = *self;
|
||||
write!(f, "PdfInteger(at {pos}, {value})")
|
||||
}
|
||||
}
|
||||
|
||||
impl PdfInteger {
|
||||
pub fn new(pos: impl Into<PdfInputPositionNoCompare>, value: i128) -> Self {
|
||||
Self {
|
||||
|
|
@ -192,12 +265,19 @@ impl GetPdfInputPosition for PdfInteger {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Default)]
|
||||
#[derive(Clone, Copy, PartialEq, PartialOrd, Default)]
|
||||
pub struct PdfReal {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
value: f64,
|
||||
}
|
||||
|
||||
impl fmt::Debug for PdfReal {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let Self { pos, value } = *self;
|
||||
write!(f, "PdfReal(at {pos}, {value})")
|
||||
}
|
||||
}
|
||||
|
||||
impl PdfReal {
|
||||
pub fn new(pos: impl Into<PdfInputPositionNoCompare>, value: f64) -> Self {
|
||||
Self {
|
||||
|
|
@ -219,6 +299,114 @@ impl GetPdfInputPosition for PdfReal {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum PdfNumber {
|
||||
Integer(PdfInteger),
|
||||
Real(PdfReal),
|
||||
}
|
||||
|
||||
impl fmt::Debug for PdfNumber {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Integer(v) => v.fmt(f),
|
||||
Self::Real(v) => v.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PdfNumber {
|
||||
pub fn pos(self) -> PdfInputPosition {
|
||||
match self {
|
||||
Self::Integer(v) => v.pos(),
|
||||
Self::Real(v) => v.pos(),
|
||||
}
|
||||
}
|
||||
pub fn as_f64(self) -> f64 {
|
||||
match self {
|
||||
Self::Integer(v) => v.value as f64,
|
||||
Self::Real(v) => v.value,
|
||||
}
|
||||
}
|
||||
pub fn as_f32(self) -> f32 {
|
||||
match self {
|
||||
Self::Integer(v) => v.value as f32,
|
||||
Self::Real(v) => v.value as f32,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for PdfNumber {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
match (self, other) {
|
||||
(Self::Integer(this), Self::Integer(other)) => Some(this.cmp(other)),
|
||||
_ => self.as_f64().partial_cmp(&other.as_f64()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for PdfNumber {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.partial_cmp(other).is_some_and(|v| v.is_eq())
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for PdfNumber {
|
||||
fn default() -> Self {
|
||||
PdfNumber::Integer(PdfInteger::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl PdfObjectDirect {
|
||||
pub fn number(&self) -> Option<PdfNumber> {
|
||||
match *self {
|
||||
PdfObjectDirect::Integer(v) => Some(PdfNumber::Integer(v)),
|
||||
PdfObjectDirect::Real(v) => Some(PdfNumber::Real(v)),
|
||||
PdfObjectDirect::Boolean(_)
|
||||
| PdfObjectDirect::String(_)
|
||||
| PdfObjectDirect::Name(_)
|
||||
| PdfObjectDirect::Array(_)
|
||||
| PdfObjectDirect::Dictionary(_)
|
||||
| PdfObjectDirect::Stream(_)
|
||||
| PdfObjectDirect::Null(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PdfObjectNonNull {
|
||||
pub fn number(&self) -> Option<PdfNumber> {
|
||||
match *self {
|
||||
PdfObjectNonNull::Integer(v) => Some(PdfNumber::Integer(v)),
|
||||
PdfObjectNonNull::Real(v) => Some(PdfNumber::Real(v)),
|
||||
PdfObjectNonNull::Boolean(_)
|
||||
| PdfObjectNonNull::String(_)
|
||||
| PdfObjectNonNull::Name(_)
|
||||
| PdfObjectNonNull::Array(_)
|
||||
| PdfObjectNonNull::Dictionary(_)
|
||||
| PdfObjectNonNull::Stream(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IsPdfNull for PdfNumber {
|
||||
fn is_pdf_null(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl PdfParse for PdfNumber {
|
||||
fn type_name() -> Cow<'static, str> {
|
||||
Cow::Borrowed("number")
|
||||
}
|
||||
fn parse(object: PdfObject) -> Result<Self, PdfParseError> {
|
||||
let object = PdfObjectDirect::from(object);
|
||||
object.number().ok_or(PdfParseError::InvalidType {
|
||||
pos: object.pos(),
|
||||
ty: object.type_name(),
|
||||
expected_ty: "number",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! make_pdf_object {
|
||||
(
|
||||
$(
|
||||
|
|
@ -239,12 +427,24 @@ macro_rules! make_pdf_object {
|
|||
}
|
||||
}
|
||||
|
||||
impl IsPdfNull for PdfObjectNonNull {
|
||||
fn is_pdf_null(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum PdfObjectDirect {
|
||||
$($Variant($ty),)*
|
||||
Null(PdfNull),
|
||||
}
|
||||
|
||||
impl IsPdfNull for PdfObjectDirect {
|
||||
fn is_pdf_null(&self) -> bool {
|
||||
self.is_null()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for PdfObjectDirect {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
|
|
@ -261,6 +461,12 @@ macro_rules! make_pdf_object {
|
|||
Indirect(PdfObjectIndirect),
|
||||
}
|
||||
|
||||
impl IsPdfNull for PdfObject {
|
||||
fn is_pdf_null(&self) -> bool {
|
||||
self.is_null()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for PdfObject {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
|
|
@ -308,14 +514,20 @@ macro_rules! make_pdf_object {
|
|||
}
|
||||
}
|
||||
|
||||
$(impl crate::pdf::parse::PdfParse for $ty {
|
||||
$(impl IsPdfNull for $ty {
|
||||
fn is_pdf_null(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl PdfParse for $ty {
|
||||
fn type_name() -> Cow<'static, str> {
|
||||
Cow::Borrowed($type_name)
|
||||
}
|
||||
fn $parse(object: PdfObject) -> Result<Self, crate::pdf::parse::PdfParseError> {
|
||||
fn $parse(object: PdfObject) -> Result<Self, PdfParseError> {
|
||||
match PdfObjectDirect::from(object) {
|
||||
PdfObjectDirect::$Variant(v) => Ok(v),
|
||||
object => Err(crate::pdf::parse::PdfParseError::InvalidType {
|
||||
object => Err(PdfParseError::InvalidType {
|
||||
pos: object.get_pdf_input_position(),
|
||||
ty: object.type_name(),
|
||||
expected_ty: $type_name,
|
||||
|
|
@ -445,7 +657,7 @@ macro_rules! make_pdf_object {
|
|||
}
|
||||
|
||||
const _: () = {
|
||||
fn _assert_parsable<T: crate::pdf::parse::PdfParse>() {}
|
||||
fn _assert_parsable<T: PdfParse>() {}
|
||||
|
||||
$(let _ = _assert_parsable::<$ty>;)*
|
||||
let _ = _assert_parsable::<PdfNull>;
|
||||
|
|
@ -470,15 +682,21 @@ make_pdf_object! {
|
|||
Name(PdfName),
|
||||
#[parse = parse, type_name = "array"]
|
||||
Array(PdfArray),
|
||||
#[parse = parse, type_name = "dictionary"]
|
||||
#[parse =, type_name = "dictionary"]
|
||||
Dictionary(PdfDictionary),
|
||||
#[parse =, type_name = "stream"]
|
||||
Stream(PdfStream),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct PdfNull(PdfInputPositionNoCompare);
|
||||
|
||||
impl fmt::Debug for PdfNull {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "PdfNull(at {})", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl PdfNull {
|
||||
pub fn new(pos: impl Into<PdfInputPositionNoCompare>) -> Self {
|
||||
Self(pos.into())
|
||||
|
|
@ -521,13 +739,27 @@ impl From<PdfObjectIndirect> for PdfObject {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
pub struct PdfObjectIdentifier {
|
||||
pub pos: PdfInputPositionNoCompare,
|
||||
pub object_number: NonZero<u32>,
|
||||
pub generation_number: u16,
|
||||
}
|
||||
|
||||
impl fmt::Debug for PdfObjectIdentifier {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let Self {
|
||||
pos,
|
||||
object_number,
|
||||
generation_number,
|
||||
} = *self;
|
||||
write!(
|
||||
f,
|
||||
"PdfObjectIdentifier(at {pos}, {object_number}, {generation_number})"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl GetPdfInputPosition for PdfObjectIdentifier {
|
||||
fn get_pdf_input_position(&self) -> PdfInputPosition {
|
||||
self.pos.0
|
||||
|
|
@ -545,12 +777,18 @@ impl fmt::Debug for PdfObjectIndirect {
|
|||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let Self {
|
||||
objects: _,
|
||||
id,
|
||||
id:
|
||||
PdfObjectIdentifier {
|
||||
pos,
|
||||
object_number,
|
||||
generation_number,
|
||||
},
|
||||
final_id: _,
|
||||
} = self;
|
||||
f.debug_struct("PdfObjectIndirect")
|
||||
.field("id", id)
|
||||
.finish_non_exhaustive()
|
||||
} = *self;
|
||||
write!(
|
||||
f,
|
||||
"PdfObjectIndirect(at {pos}, {object_number}, {generation_number})"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -627,13 +865,31 @@ impl From<PdfObjectIndirect> for PdfObjectDirect {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PdfDictionary {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
fields: Arc<BTreeMap<PdfName, PdfObject>>,
|
||||
pub trait IsPdfNull {
|
||||
fn is_pdf_null(&self) -> bool;
|
||||
}
|
||||
|
||||
impl PdfDictionary {
|
||||
impl<T: IsPdfNull> IsPdfNull for Option<T> {
|
||||
fn is_pdf_null(&self) -> bool {
|
||||
self.as_ref().is_none_or(IsPdfNull::is_pdf_null)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PdfDictionary<T = PdfObject> {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
fields: Arc<BTreeMap<PdfName, T>>,
|
||||
}
|
||||
|
||||
impl<T> Clone for PdfDictionary<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
pos: self.pos,
|
||||
fields: self.fields.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PdfDictionary<T> {
|
||||
pub fn new(pos: impl Into<PdfInputPositionNoCompare>) -> Self {
|
||||
Self {
|
||||
pos: pos.into(),
|
||||
|
|
@ -642,23 +898,26 @@ impl PdfDictionary {
|
|||
}
|
||||
pub fn from_fields(
|
||||
pos: impl Into<PdfInputPositionNoCompare>,
|
||||
mut fields: Arc<BTreeMap<PdfName, PdfObject>>,
|
||||
) -> Self {
|
||||
if fields.values().any(|v| matches!(v, PdfObject::Null(_))) {
|
||||
Arc::make_mut(&mut fields).retain(|_k, v| !matches!(v, PdfObject::Null(_)));
|
||||
mut fields: Arc<BTreeMap<PdfName, T>>,
|
||||
) -> Self
|
||||
where
|
||||
T: IsPdfNull + Clone,
|
||||
{
|
||||
if fields.values().any(T::is_pdf_null) {
|
||||
Arc::make_mut(&mut fields).retain(|_k, v| !v.is_pdf_null());
|
||||
}
|
||||
Self {
|
||||
pos: pos.into(),
|
||||
fields,
|
||||
}
|
||||
}
|
||||
pub fn fields(&self) -> &Arc<BTreeMap<PdfName, PdfObject>> {
|
||||
pub fn fields(&self) -> &Arc<BTreeMap<PdfName, T>> {
|
||||
&self.fields
|
||||
}
|
||||
pub fn into_fields(self) -> Arc<BTreeMap<PdfName, PdfObject>> {
|
||||
pub fn into_fields(self) -> Arc<BTreeMap<PdfName, T>> {
|
||||
self.fields
|
||||
}
|
||||
pub fn iter(&self) -> std::collections::btree_map::Iter<'_, PdfName, PdfObject> {
|
||||
pub fn iter(&self) -> std::collections::btree_map::Iter<'_, PdfName, T> {
|
||||
self.fields.iter()
|
||||
}
|
||||
pub fn contains_key<Q: ?Sized>(&self, key: &Q) -> bool
|
||||
|
|
@ -668,75 +927,122 @@ impl PdfDictionary {
|
|||
{
|
||||
self.fields.contains_key(key)
|
||||
}
|
||||
pub fn get<Q: ?Sized>(&self, key: &Q) -> Option<&PdfObject>
|
||||
pub fn get<Q: ?Sized>(&self, key: &Q) -> Option<&T>
|
||||
where
|
||||
PdfName: std::borrow::Borrow<Q>,
|
||||
Q: Ord,
|
||||
{
|
||||
self.fields.get(key)
|
||||
}
|
||||
pub fn get_or_null<Q: ?Sized>(&self, key: &Q) -> PdfObject
|
||||
pub fn get_or_null<Q: ?Sized>(&self, key: &Q) -> T
|
||||
where
|
||||
PdfName: std::borrow::Borrow<Q>,
|
||||
Q: Ord,
|
||||
T: Clone + From<PdfNull>,
|
||||
{
|
||||
self.get(key)
|
||||
.cloned()
|
||||
.unwrap_or(PdfObject::Null(PdfNull(self.pos)))
|
||||
.unwrap_or_else(|| PdfNull(self.pos).into())
|
||||
}
|
||||
pub fn pos(&self) -> PdfInputPosition {
|
||||
self.pos.0
|
||||
}
|
||||
}
|
||||
|
||||
impl GetPdfInputPosition for PdfDictionary {
|
||||
impl<T> GetPdfInputPosition for PdfDictionary<T> {
|
||||
fn get_pdf_input_position(&self) -> PdfInputPosition {
|
||||
self.pos.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for PdfDictionary {
|
||||
impl<T> Default for PdfDictionary<T> {
|
||||
fn default() -> Self {
|
||||
Self::new(PdfInputPosition::empty())
|
||||
}
|
||||
}
|
||||
|
||||
impl FromIterator<(PdfName, PdfObject)> for PdfDictionary {
|
||||
fn from_iter<T: IntoIterator<Item = (PdfName, PdfObject)>>(iter: T) -> Self {
|
||||
impl<T: IsPdfNull> FromIterator<(PdfName, T)> for PdfDictionary<T> {
|
||||
fn from_iter<I: IntoIterator<Item = (PdfName, T)>>(iter: I) -> Self {
|
||||
Self {
|
||||
pos: PdfInputPositionNoCompare::empty(),
|
||||
fields: Arc::new(BTreeMap::from_iter(
|
||||
iter.into_iter()
|
||||
.filter(|(_name, value)| !matches!(value, PdfObject::Null(_))),
|
||||
.filter(|(_name, value)| !value.is_pdf_null()),
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoIterator for PdfDictionary {
|
||||
type Item = (PdfName, PdfObject);
|
||||
type IntoIter = std::collections::btree_map::IntoIter<PdfName, PdfObject>;
|
||||
impl<T: Clone> IntoIterator for PdfDictionary<T> {
|
||||
type Item = (PdfName, T);
|
||||
type IntoIter = std::collections::btree_map::IntoIter<PdfName, T>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
Arc::unwrap_or_clone(self.fields).into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoIterator for &'a PdfDictionary {
|
||||
type Item = (&'a PdfName, &'a PdfObject);
|
||||
type IntoIter = std::collections::btree_map::Iter<'a, PdfName, PdfObject>;
|
||||
impl<'a, T> IntoIterator for &'a PdfDictionary<T> {
|
||||
type Item = (&'a PdfName, &'a T);
|
||||
type IntoIter = std::collections::btree_map::Iter<'a, PdfName, T>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.fields.iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for PdfDictionary {
|
||||
impl<T: fmt::Debug> fmt::Debug for PdfDictionary<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_map().entries(self).finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> IsPdfNull for PdfDictionary<T> {
|
||||
fn is_pdf_null(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PdfParse> PdfParse for PdfDictionary<T> {
|
||||
fn type_name() -> Cow<'static, str> {
|
||||
if TypeId::of::<T>() == TypeId::of::<PdfObject>() {
|
||||
Cow::Borrowed("dictionary")
|
||||
} else {
|
||||
Cow::Owned(format!("PdfDictionary<{}>", T::type_name()))
|
||||
}
|
||||
}
|
||||
fn parse(object: PdfObject) -> Result<Self, PdfParseError> {
|
||||
let object = PdfObjectDirect::from(object);
|
||||
let PdfObjectDirect::Dictionary(object) = object else {
|
||||
return Err(PdfParseError::InvalidType {
|
||||
pos: object.pos(),
|
||||
ty: object.type_name(),
|
||||
expected_ty: "dictionary",
|
||||
});
|
||||
};
|
||||
if let Some(retval) = <dyn std::any::Any>::downcast_ref::<Self>(&object) {
|
||||
return Ok(retval.clone());
|
||||
}
|
||||
let pos = object.pos;
|
||||
let fields = Result::from_iter(object.fields.iter().filter_map(|(name, value)| {
|
||||
match T::parse(value.clone()) {
|
||||
Ok(value) => {
|
||||
if value.is_pdf_null() {
|
||||
None
|
||||
} else {
|
||||
Some(Ok((name.clone(), value)))
|
||||
}
|
||||
}
|
||||
Err(e) => Some(Err(e)),
|
||||
}
|
||||
}))?;
|
||||
Ok(Self {
|
||||
pos,
|
||||
fields: Arc::new(fields),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct PdfArray {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
|
|
@ -869,9 +1175,15 @@ impl fmt::Debug for PdfArray {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct MaybeArray<T>(pub Arc<[T]>);
|
||||
|
||||
impl<T: fmt::Debug> fmt::Debug for MaybeArray<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> std::ops::Deref for MaybeArray<T> {
|
||||
type Target = Arc<[T]>;
|
||||
|
||||
|
|
@ -901,12 +1213,138 @@ impl<'a, T> IntoIterator for &'a MaybeArray<T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub struct PdfPoint {
|
||||
pub pos: PdfInputPositionNoCompare,
|
||||
pub x: f32,
|
||||
pub y: f32,
|
||||
}
|
||||
|
||||
impl fmt::Debug for PdfPoint {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let Self { pos, x, y } = *self;
|
||||
write!(f, "PdfPoint(at {pos}, {x}, {y})")
|
||||
}
|
||||
}
|
||||
|
||||
impl PdfPoint {
|
||||
pub fn parse(x: PdfObject, y: PdfObject) -> Result<Self, PdfParseError> {
|
||||
Ok(Self {
|
||||
pos: x.pos().into(),
|
||||
x: PdfParse::parse(x)?,
|
||||
y: PdfParse::parse(y)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl GetPdfInputPosition for PdfPoint {
|
||||
fn get_pdf_input_position(&self) -> PdfInputPosition {
|
||||
self.pos.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct PdfRectangle {
|
||||
/// the corner with the smaller x and y coordinates
|
||||
smaller: PdfPoint,
|
||||
/// the corner with the larger x and y coordinates
|
||||
larger: PdfPoint,
|
||||
}
|
||||
|
||||
impl PdfRectangle {
|
||||
pub fn new(mut smaller: PdfPoint, mut larger: PdfPoint) -> Self {
|
||||
// `pos` follows the `x` coordinate
|
||||
if smaller.x.is_nan() {
|
||||
smaller.pos = larger.pos;
|
||||
} else if larger.x.is_nan() {
|
||||
larger.pos = smaller.pos;
|
||||
} else if larger.x < smaller.x {
|
||||
std::mem::swap(&mut smaller.pos, &mut larger.pos);
|
||||
}
|
||||
Self {
|
||||
smaller: PdfPoint {
|
||||
pos: smaller.pos,
|
||||
x: smaller.x.min(larger.x),
|
||||
y: smaller.y.min(larger.y),
|
||||
},
|
||||
larger: PdfPoint {
|
||||
pos: larger.pos,
|
||||
x: smaller.x.max(larger.x),
|
||||
y: smaller.y.max(larger.y),
|
||||
},
|
||||
}
|
||||
}
|
||||
/// return the corner with the smaller x and y coordinates
|
||||
pub fn smaller(&self) -> PdfPoint {
|
||||
self.smaller
|
||||
}
|
||||
/// return the corner with the larger x and y coordinates
|
||||
pub fn larger(&self) -> PdfPoint {
|
||||
self.larger
|
||||
}
|
||||
}
|
||||
|
||||
impl GetPdfInputPosition for PdfRectangle {
|
||||
fn get_pdf_input_position(&self) -> PdfInputPosition {
|
||||
self.smaller.get_pdf_input_position()
|
||||
}
|
||||
}
|
||||
|
||||
impl IsPdfNull for PdfRectangle {
|
||||
fn is_pdf_null(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl PdfParse for PdfRectangle {
|
||||
fn type_name() -> Cow<'static, str> {
|
||||
Cow::Borrowed("rectangle")
|
||||
}
|
||||
|
||||
fn parse(object: PdfObject) -> Result<Self, PdfParseError> {
|
||||
let object = object.into();
|
||||
let PdfObjectDirect::Array(array) = &object else {
|
||||
return Err(PdfParseError::InvalidType {
|
||||
pos: object.pos(),
|
||||
ty: object.type_name(),
|
||||
expected_ty: "rectangle",
|
||||
});
|
||||
};
|
||||
let [lower_left_x, lower_left_y, upper_right_x, upper_right_y] = &**array.elements() else {
|
||||
return Err(PdfParseError::InvalidType {
|
||||
pos: object.pos(),
|
||||
ty: object.type_name(),
|
||||
expected_ty: "rectangle",
|
||||
});
|
||||
};
|
||||
Ok(Self::new(
|
||||
PdfPoint::parse(lower_left_x.clone(), lower_left_y.clone())?,
|
||||
PdfPoint::parse(upper_right_x.clone(), upper_right_y.clone())?,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum PdfFileSpecification {
|
||||
String(PdfString),
|
||||
Dictionary(PdfDictionary),
|
||||
}
|
||||
|
||||
impl fmt::Debug for PdfFileSpecification {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::String(v) => v.fmt(f),
|
||||
Self::Dictionary(v) => v.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IsPdfNull for PdfFileSpecification {
|
||||
fn is_pdf_null(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl PdfParse for PdfFileSpecification {
|
||||
fn type_name() -> Cow<'static, str> {
|
||||
Cow::Borrowed("file specification")
|
||||
|
|
@ -925,6 +1363,7 @@ impl PdfParse for PdfFileSpecification {
|
|||
}
|
||||
|
||||
pdf_parse! {
|
||||
#[pdf]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct PdfStreamDictionary<Rest = PdfDictionary> {
|
||||
#[pdf(name = PdfStreamDictionary::LENGTH_NAME)]
|
||||
|
|
@ -1200,6 +1639,12 @@ impl<Rest> GetPdfInputPosition for PdfStream<Rest> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<Rest> IsPdfNull for PdfStream<Rest> {
|
||||
fn is_pdf_null(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl<Rest: PdfParse> PdfParse for PdfStream<Rest> {
|
||||
fn type_name() -> Cow<'static, str> {
|
||||
if TypeId::of::<Rest>() == TypeId::of::<PdfDictionary>() {
|
||||
|
|
@ -1252,6 +1697,7 @@ impl<Rest: PdfParse> PdfParse for PdfStream<Rest> {
|
|||
}
|
||||
|
||||
pdf_parse! {
|
||||
#[pdf(name)]
|
||||
#[derive(Clone, Copy, Debug, Hash, Default, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum PdfObjectStreamType {
|
||||
#[pdf(name = "ObjStm")]
|
||||
|
|
@ -1261,6 +1707,7 @@ pdf_parse! {
|
|||
}
|
||||
|
||||
pdf_parse! {
|
||||
#[pdf]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct PdfObjectStreamDictionary {
|
||||
#[pdf(name = Self::TYPE_NAME)]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue