parsing more of the pdf structure

This commit is contained in:
Jacob Lifshay 2025-12-26 01:13:52 -08:00
parent 83631cc4c6
commit e0993fdb4a
Signed by: programmerjake
SSH key fingerprint: SHA256:HnFTLGpSm4Q4Fj502oCFisjZSoakwEuTsJJMSke63RQ
9 changed files with 1549 additions and 100 deletions

View file

@ -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)]