parse content streams into a list of operators
This commit is contained in:
parent
13dcea1dab
commit
aba6368948
5 changed files with 1541 additions and 408 deletions
|
|
@ -34,7 +34,7 @@ impl std::fmt::Debug for PdfString {
|
|||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct PdfStringBytesDebug<'a>(&'a [u8]);
|
||||
pub struct PdfStringBytesDebug<'a>(pub &'a [u8]);
|
||||
|
||||
impl<'a> fmt::Display for PdfStringBytesDebug<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
|
|
@ -407,6 +407,81 @@ impl PdfParse for PdfNumber {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum PdfStringOrNumber {
|
||||
String(PdfString),
|
||||
Number(PdfNumber),
|
||||
}
|
||||
|
||||
impl fmt::Debug for PdfStringOrNumber {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::String(v) => v.fmt(f),
|
||||
Self::Number(v) => v.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PdfStringOrNumber {
|
||||
pub fn pos(self) -> PdfInputPosition {
|
||||
match self {
|
||||
Self::String(v) => v.pos(),
|
||||
Self::Number(v) => v.pos(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PdfObjectDirect {
|
||||
pub fn string_or_number(&self) -> Option<PdfStringOrNumber> {
|
||||
match *self {
|
||||
PdfObjectDirect::Integer(v) => Some(PdfStringOrNumber::Number(PdfNumber::Integer(v))),
|
||||
PdfObjectDirect::Real(v) => Some(PdfStringOrNumber::Number(PdfNumber::Real(v))),
|
||||
PdfObjectDirect::String(ref v) => Some(PdfStringOrNumber::String(v.clone())),
|
||||
PdfObjectDirect::Boolean(_)
|
||||
| PdfObjectDirect::Name(_)
|
||||
| PdfObjectDirect::Array(_)
|
||||
| PdfObjectDirect::Dictionary(_)
|
||||
| PdfObjectDirect::Stream(_)
|
||||
| PdfObjectDirect::Null(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PdfObjectNonNull {
|
||||
pub fn string_or_number(&self) -> Option<PdfStringOrNumber> {
|
||||
match *self {
|
||||
PdfObjectNonNull::Integer(v) => Some(PdfStringOrNumber::Number(PdfNumber::Integer(v))),
|
||||
PdfObjectNonNull::Real(v) => Some(PdfStringOrNumber::Number(PdfNumber::Real(v))),
|
||||
PdfObjectNonNull::String(ref v) => Some(PdfStringOrNumber::String(v.clone())),
|
||||
PdfObjectNonNull::Boolean(_)
|
||||
| PdfObjectNonNull::Name(_)
|
||||
| PdfObjectNonNull::Array(_)
|
||||
| PdfObjectNonNull::Dictionary(_)
|
||||
| PdfObjectNonNull::Stream(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IsPdfNull for PdfStringOrNumber {
|
||||
fn is_pdf_null(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl PdfParse for PdfStringOrNumber {
|
||||
fn type_name() -> Cow<'static, str> {
|
||||
Cow::Borrowed("string or number")
|
||||
}
|
||||
fn parse(object: PdfObject) -> Result<Self, PdfParseError> {
|
||||
let object = PdfObjectDirect::from(object);
|
||||
object.string_or_number().ok_or(PdfParseError::InvalidType {
|
||||
pos: object.pos(),
|
||||
ty: object.type_name(),
|
||||
expected_ty: "string or number",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! make_pdf_object {
|
||||
(
|
||||
$(
|
||||
|
|
@ -818,34 +893,35 @@ impl PdfObjectIndirect {
|
|||
}
|
||||
}
|
||||
pub fn get(&self) -> PdfObjectDirect {
|
||||
if let Some(objects) = self.objects.upgrade() {
|
||||
if let Some(objects) = objects.inner.get() {
|
||||
let final_id = self.final_id.get().copied();
|
||||
let limit = if final_id.is_some() { 1 } else { 1000usize };
|
||||
let mut id = final_id.unwrap_or(self.id);
|
||||
for _ in 0..limit {
|
||||
if let Some(object) = objects.objects.get(&self.id) {
|
||||
let retval = match object {
|
||||
PdfObject::Boolean(v) => PdfObjectDirect::Boolean(*v),
|
||||
PdfObject::Integer(v) => PdfObjectDirect::Integer(*v),
|
||||
PdfObject::Real(v) => PdfObjectDirect::Real(*v),
|
||||
PdfObject::String(v) => PdfObjectDirect::String(v.clone()),
|
||||
PdfObject::Name(v) => PdfObjectDirect::Name(v.clone()),
|
||||
PdfObject::Array(v) => PdfObjectDirect::Array(v.clone()),
|
||||
PdfObject::Dictionary(v) => PdfObjectDirect::Dictionary(v.clone()),
|
||||
PdfObject::Stream(v) => PdfObjectDirect::Stream(v.clone()),
|
||||
PdfObject::Null(v) => PdfObjectDirect::Null(*v),
|
||||
PdfObject::Indirect(v) => {
|
||||
id = v.id;
|
||||
continue;
|
||||
}
|
||||
};
|
||||
// we could be racing with another thread, so set can fail but that's not a problem
|
||||
let _ = self.final_id.set(id);
|
||||
return retval;
|
||||
} else {
|
||||
return PdfObjectDirect::Null(PdfNull::new(id.pos));
|
||||
}
|
||||
let Some(objects) = self.objects.upgrade() else {
|
||||
panic!("PdfObjects is no longer available");
|
||||
};
|
||||
if let Some(objects) = objects.inner.get() {
|
||||
let final_id = self.final_id.get().copied();
|
||||
let limit = if final_id.is_some() { 1 } else { 1000usize };
|
||||
let mut id = final_id.unwrap_or(self.id);
|
||||
for _ in 0..limit {
|
||||
if let Some(object) = objects.objects.get(&self.id) {
|
||||
let retval = match object {
|
||||
PdfObject::Boolean(v) => PdfObjectDirect::Boolean(*v),
|
||||
PdfObject::Integer(v) => PdfObjectDirect::Integer(*v),
|
||||
PdfObject::Real(v) => PdfObjectDirect::Real(*v),
|
||||
PdfObject::String(v) => PdfObjectDirect::String(v.clone()),
|
||||
PdfObject::Name(v) => PdfObjectDirect::Name(v.clone()),
|
||||
PdfObject::Array(v) => PdfObjectDirect::Array(v.clone()),
|
||||
PdfObject::Dictionary(v) => PdfObjectDirect::Dictionary(v.clone()),
|
||||
PdfObject::Stream(v) => PdfObjectDirect::Stream(v.clone()),
|
||||
PdfObject::Null(v) => PdfObjectDirect::Null(*v),
|
||||
PdfObject::Indirect(v) => {
|
||||
id = v.id;
|
||||
continue;
|
||||
}
|
||||
};
|
||||
// we could be racing with another thread, so set can fail but that's not a problem
|
||||
let _ = self.final_id.set(id);
|
||||
return retval;
|
||||
} else {
|
||||
return PdfObjectDirect::Null(PdfNull::new(id.pos));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1213,21 +1289,150 @@ impl<'a, T> IntoIterator for &'a MaybeArray<T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum NameOr<T> {
|
||||
Name(PdfName),
|
||||
Value(T),
|
||||
}
|
||||
|
||||
impl<T> NameOr<T> {
|
||||
pub fn into_resolved<E>(self, resolve: impl FnOnce(PdfName) -> Result<T, E>) -> Result<T, E> {
|
||||
match self {
|
||||
Self::Name(name) => resolve(name),
|
||||
Self::Value(v) => Ok(v),
|
||||
}
|
||||
}
|
||||
pub fn replace_with_resolved<E>(
|
||||
&mut self,
|
||||
resolve: impl FnOnce(&PdfName) -> Result<T, E>,
|
||||
) -> Result<&mut T, E> {
|
||||
match self {
|
||||
Self::Name(name) => {
|
||||
*self = Self::Value(resolve(name)?);
|
||||
let Self::Value(v) = self else {
|
||||
unreachable!();
|
||||
};
|
||||
Ok(v)
|
||||
}
|
||||
Self::Value(v) => Ok(v),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: fmt::Debug> fmt::Debug for NameOr<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Name(v) => v.fmt(f),
|
||||
Self::Value(v) => v.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: GetPdfInputPosition> GetPdfInputPosition for NameOr<T> {
|
||||
fn get_pdf_input_position(&self) -> PdfInputPosition {
|
||||
match self {
|
||||
Self::Name(v) => v.pos(),
|
||||
Self::Value(v) => v.get_pdf_input_position(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: IsPdfNull> IsPdfNull for NameOr<T> {
|
||||
fn is_pdf_null(&self) -> bool {
|
||||
match self {
|
||||
Self::Name(_) => false,
|
||||
Self::Value(v) => v.is_pdf_null(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PdfParse> PdfParse for NameOr<T> {
|
||||
fn type_name() -> Cow<'static, str> {
|
||||
Cow::Owned(format!("NameOr<{}>", T::type_name()))
|
||||
}
|
||||
fn parse(object: PdfObject) -> Result<Self, PdfParseError> {
|
||||
Ok(match PdfObjectDirect::from(object) {
|
||||
PdfObjectDirect::Name(name) => Self::Name(name),
|
||||
object => Self::Value(T::parse(object.into())?),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub struct PdfPoint {
|
||||
pub struct PdfMatrix {
|
||||
pub pos: PdfInputPositionNoCompare,
|
||||
pub elements: [f32; 6],
|
||||
}
|
||||
|
||||
impl fmt::Debug for PdfMatrix {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let Self { pos, elements } = *self;
|
||||
write!(f, "PdfMatrix(at {pos}, {elements:?})")
|
||||
}
|
||||
}
|
||||
|
||||
impl IsPdfNull for PdfMatrix {
|
||||
fn is_pdf_null(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl PdfParse for PdfMatrix {
|
||||
fn type_name() -> Cow<'static, str> {
|
||||
Cow::Borrowed("matrix")
|
||||
}
|
||||
fn parse(object: PdfObject) -> Result<Self, PdfParseError> {
|
||||
Ok(Self {
|
||||
pos: object.pos().into(),
|
||||
elements: PdfParse::parse(object)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl PdfMatrix {
|
||||
pub fn parse_flat(
|
||||
a: PdfObject,
|
||||
b: PdfObject,
|
||||
c: PdfObject,
|
||||
d: PdfObject,
|
||||
e: PdfObject,
|
||||
f: PdfObject,
|
||||
) -> Result<Self, PdfParseError> {
|
||||
Ok(Self {
|
||||
pos: a.pos().into(),
|
||||
elements: [
|
||||
PdfParse::parse(a)?,
|
||||
PdfParse::parse(b)?,
|
||||
PdfParse::parse(c)?,
|
||||
PdfParse::parse(d)?,
|
||||
PdfParse::parse(e)?,
|
||||
PdfParse::parse(f)?,
|
||||
],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl GetPdfInputPosition for PdfMatrix {
|
||||
fn get_pdf_input_position(&self) -> PdfInputPosition {
|
||||
self.pos.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub struct PdfVec2D {
|
||||
pub pos: PdfInputPositionNoCompare,
|
||||
pub x: f32,
|
||||
pub y: f32,
|
||||
}
|
||||
|
||||
impl fmt::Debug for PdfPoint {
|
||||
impl fmt::Debug for PdfVec2D {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let Self { pos, x, y } = *self;
|
||||
write!(f, "PdfPoint(at {pos}, {x}, {y})")
|
||||
write!(f, "PdfVec2D(at {pos}, {x}, {y})")
|
||||
}
|
||||
}
|
||||
|
||||
impl PdfPoint {
|
||||
impl PdfVec2D {
|
||||
pub fn parse(x: PdfObject, y: PdfObject) -> Result<Self, PdfParseError> {
|
||||
Ok(Self {
|
||||
pos: x.pos().into(),
|
||||
|
|
@ -1237,7 +1442,7 @@ impl PdfPoint {
|
|||
}
|
||||
}
|
||||
|
||||
impl GetPdfInputPosition for PdfPoint {
|
||||
impl GetPdfInputPosition for PdfVec2D {
|
||||
fn get_pdf_input_position(&self) -> PdfInputPosition {
|
||||
self.pos.0
|
||||
}
|
||||
|
|
@ -1246,13 +1451,13 @@ impl GetPdfInputPosition for PdfPoint {
|
|||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct PdfRectangle {
|
||||
/// the corner with the smaller x and y coordinates
|
||||
smaller: PdfPoint,
|
||||
smaller: PdfVec2D,
|
||||
/// the corner with the larger x and y coordinates
|
||||
larger: PdfPoint,
|
||||
larger: PdfVec2D,
|
||||
}
|
||||
|
||||
impl PdfRectangle {
|
||||
pub fn new(mut smaller: PdfPoint, mut larger: PdfPoint) -> Self {
|
||||
pub fn new(mut smaller: PdfVec2D, mut larger: PdfVec2D) -> Self {
|
||||
// `pos` follows the `x` coordinate
|
||||
if smaller.x.is_nan() {
|
||||
smaller.pos = larger.pos;
|
||||
|
|
@ -1262,12 +1467,12 @@ impl PdfRectangle {
|
|||
std::mem::swap(&mut smaller.pos, &mut larger.pos);
|
||||
}
|
||||
Self {
|
||||
smaller: PdfPoint {
|
||||
smaller: PdfVec2D {
|
||||
pos: smaller.pos,
|
||||
x: smaller.x.min(larger.x),
|
||||
y: smaller.y.min(larger.y),
|
||||
},
|
||||
larger: PdfPoint {
|
||||
larger: PdfVec2D {
|
||||
pos: larger.pos,
|
||||
x: smaller.x.max(larger.x),
|
||||
y: smaller.y.max(larger.y),
|
||||
|
|
@ -1275,13 +1480,24 @@ impl PdfRectangle {
|
|||
}
|
||||
}
|
||||
/// return the corner with the smaller x and y coordinates
|
||||
pub fn smaller(&self) -> PdfPoint {
|
||||
pub fn smaller(&self) -> PdfVec2D {
|
||||
self.smaller
|
||||
}
|
||||
/// return the corner with the larger x and y coordinates
|
||||
pub fn larger(&self) -> PdfPoint {
|
||||
pub fn larger(&self) -> PdfVec2D {
|
||||
self.larger
|
||||
}
|
||||
pub fn parse_flat(
|
||||
lower_left_x: PdfObject,
|
||||
lower_left_y: PdfObject,
|
||||
upper_right_x: PdfObject,
|
||||
upper_right_y: PdfObject,
|
||||
) -> Result<Self, PdfParseError> {
|
||||
Ok(Self::new(
|
||||
PdfVec2D::parse(lower_left_x, lower_left_y)?,
|
||||
PdfVec2D::parse(upper_right_x, upper_right_y)?,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl GetPdfInputPosition for PdfRectangle {
|
||||
|
|
@ -1317,10 +1533,12 @@ impl PdfParse for PdfRectangle {
|
|||
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())?,
|
||||
))
|
||||
Self::parse_flat(
|
||||
lower_left_x.clone(),
|
||||
lower_left_y.clone(),
|
||||
upper_right_x.clone(),
|
||||
upper_right_y.clone(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1366,7 +1584,7 @@ pdf_parse! {
|
|||
#[pdf]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct PdfStreamDictionary<Rest = PdfDictionary> {
|
||||
#[pdf(name = PdfStreamDictionary::LENGTH_NAME)]
|
||||
#[pdf(name = "Length")]
|
||||
pub len: usize,
|
||||
#[pdf(name = "Filter")]
|
||||
pub filters: MaybeArray<PdfStreamFilter>,
|
||||
|
|
@ -1385,15 +1603,6 @@ pdf_parse! {
|
|||
}
|
||||
}
|
||||
|
||||
impl PdfStreamDictionary {
|
||||
pub const LENGTH_NAME: &str = "Length";
|
||||
pub(crate) fn parse_len_from_dictionary(
|
||||
dictionary: &PdfDictionary,
|
||||
) -> Result<usize, PdfParseError> {
|
||||
PdfParse::parse(dictionary.get_or_null(Self::LENGTH_NAME.as_bytes()))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct PdfStreamDictionaryFiltersAndParms<'a> {
|
||||
filters: std::iter::Enumerate<std::slice::Iter<'a, PdfStreamFilter>>,
|
||||
|
|
@ -1505,12 +1714,45 @@ impl<Rest: PdfParse> UnparsedPdfStreamDictionary<Rest> {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait PdfStreamContents: Sized + fmt::Debug + 'static {
|
||||
fn parse(
|
||||
data: &[u8],
|
||||
stream_pos: PdfInputPosition,
|
||||
objects: Arc<PdfObjects>,
|
||||
) -> Result<Self, PdfParseError>;
|
||||
fn parse_arc(
|
||||
data: Arc<[u8]>,
|
||||
stream_pos: PdfInputPosition,
|
||||
objects: Arc<PdfObjects>,
|
||||
) -> Result<Self, PdfParseError> {
|
||||
Self::parse(&*data, stream_pos, objects)
|
||||
}
|
||||
}
|
||||
|
||||
impl PdfStreamContents for Arc<[u8]> {
|
||||
fn parse(
|
||||
data: &[u8],
|
||||
_stream_pos: PdfInputPosition,
|
||||
_objects: Arc<PdfObjects>,
|
||||
) -> Result<Self, PdfParseError> {
|
||||
Ok(Arc::from(data))
|
||||
}
|
||||
fn parse_arc(
|
||||
data: Arc<[u8]>,
|
||||
_stream_pos: PdfInputPosition,
|
||||
_objects: Arc<PdfObjects>,
|
||||
) -> Result<Self, PdfParseError> {
|
||||
Ok(data.clone())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PdfStream<Rest = PdfDictionary> {
|
||||
pub struct PdfStream<Rest = PdfDictionary, Data: PdfStreamContents = Arc<[u8]>> {
|
||||
pos: PdfInputPositionNoCompare,
|
||||
dictionary: Arc<OnceLock<PdfStreamDictionary<Rest>>>,
|
||||
objects: std::sync::Weak<PdfObjects>,
|
||||
dictionary: PdfStreamDictionary<Rest>,
|
||||
encoded_data: Arc<[u8]>,
|
||||
decoded_data: Arc<OnceLock<Result<Arc<[u8]>, PdfParseError>>>,
|
||||
decoded_data: Arc<OnceLock<Result<Data, PdfParseError>>>,
|
||||
}
|
||||
|
||||
struct DumpBytes<'a>(&'a [u8]);
|
||||
|
|
@ -1542,25 +1784,30 @@ impl fmt::Display for DumpBytes<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<Rest: fmt::Debug> fmt::Debug for PdfStream<Rest> {
|
||||
impl<Rest: fmt::Debug, Data: PdfStreamContents> fmt::Debug for PdfStream<Rest, Data> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let Self {
|
||||
pos,
|
||||
objects: _,
|
||||
dictionary,
|
||||
encoded_data,
|
||||
decoded_data,
|
||||
} = self;
|
||||
let mut debug_struct = f.debug_struct("PdfStream");
|
||||
debug_struct.field("pos", pos);
|
||||
if let Some(dictionary) = dictionary.get() {
|
||||
debug_struct.field("dictionary", dictionary);
|
||||
} else {
|
||||
debug_struct.field("dictionary", &format_args!("<not-yet-parsed>"));
|
||||
}
|
||||
debug_struct.field("dictionary", dictionary);
|
||||
debug_struct.field("encoded_data", &DumpBytes(encoded_data));
|
||||
if let Some(decoded_data) = decoded_data.get() {
|
||||
match decoded_data {
|
||||
Ok(decoded_data) => debug_struct.field("decoded_data", &DumpBytes(decoded_data)),
|
||||
Ok(decoded_data) => {
|
||||
if let Some(decoded_data) =
|
||||
<dyn std::any::Any>::downcast_ref::<Arc<[u8]>>(decoded_data)
|
||||
{
|
||||
debug_struct.field("decoded_data", &DumpBytes(&**decoded_data))
|
||||
} else {
|
||||
debug_struct.field("decoded_data", decoded_data)
|
||||
}
|
||||
}
|
||||
Err(e) => debug_struct.field("decoded_data", &Err::<(), _>(e)),
|
||||
};
|
||||
} else {
|
||||
|
|
@ -1570,47 +1817,31 @@ impl<Rest: fmt::Debug> fmt::Debug for PdfStream<Rest> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<Rest> PdfStream<Rest> {
|
||||
impl<Rest, Data: PdfStreamContents> PdfStream<Rest, Data> {
|
||||
pub fn new(
|
||||
pos: impl Into<PdfInputPositionNoCompare>,
|
||||
objects: &Arc<PdfObjects>,
|
||||
dictionary: PdfStreamDictionary<Rest>,
|
||||
encoded_data: Arc<[u8]>,
|
||||
) -> Self {
|
||||
Self {
|
||||
pos: pos.into(),
|
||||
dictionary: Arc::new(OnceLock::from(dictionary)),
|
||||
objects: Arc::downgrade(objects),
|
||||
dictionary,
|
||||
encoded_data,
|
||||
decoded_data: Arc::new(OnceLock::new()),
|
||||
}
|
||||
}
|
||||
pub(crate) fn new_unparsed(
|
||||
pos: impl Into<PdfInputPositionNoCompare>,
|
||||
unparsed_dictionary: PdfDictionary,
|
||||
encoded_data: Arc<[u8]>,
|
||||
) -> (Self, UnparsedPdfStreamDictionary<Rest>) {
|
||||
let dictionary = Arc::new(OnceLock::new());
|
||||
(
|
||||
Self {
|
||||
pos: pos.into(),
|
||||
dictionary: dictionary.clone(),
|
||||
encoded_data,
|
||||
decoded_data: Arc::new(OnceLock::new()),
|
||||
},
|
||||
UnparsedPdfStreamDictionary {
|
||||
unparsed_dictionary,
|
||||
dictionary,
|
||||
},
|
||||
)
|
||||
}
|
||||
pub fn dictionary(&self) -> &PdfStreamDictionary<Rest> {
|
||||
self.dictionary
|
||||
.get()
|
||||
.expect("haven't finished parsing all pdf object definitions yet")
|
||||
&self.dictionary
|
||||
}
|
||||
pub fn encoded_data(&self) -> &Arc<[u8]> {
|
||||
&self.encoded_data
|
||||
}
|
||||
fn try_decode_data(&self) -> Result<Arc<[u8]>, PdfParseError> {
|
||||
fn try_decode_data(&self) -> Result<Data, PdfParseError> {
|
||||
let Some(objects) = self.objects.upgrade() else {
|
||||
panic!("PdfObjects is no longer available");
|
||||
};
|
||||
let dictionary = self.dictionary();
|
||||
let (data, filters) = if let Some(file) = &dictionary.file {
|
||||
todo!()
|
||||
|
|
@ -1618,7 +1849,7 @@ impl<Rest> PdfStream<Rest> {
|
|||
(&self.encoded_data, dictionary.filters_and_parms())
|
||||
};
|
||||
if filters.len() == 0 {
|
||||
return Ok(data.clone());
|
||||
return Data::parse_arc(data.clone(), self.pos.0, objects);
|
||||
}
|
||||
let mut data: &[u8] = data;
|
||||
let mut buffer;
|
||||
|
|
@ -1626,26 +1857,26 @@ impl<Rest> PdfStream<Rest> {
|
|||
buffer = filter.decode_stream_data(filter_parms.clone(), self.pos.0, &data)?;
|
||||
data = &buffer;
|
||||
}
|
||||
Ok(Arc::from(data))
|
||||
Data::parse(data, self.pos.0, objects)
|
||||
}
|
||||
pub fn decoded_data(&self) -> &Result<Arc<[u8]>, PdfParseError> {
|
||||
pub fn decoded_data(&self) -> &Result<Data, PdfParseError> {
|
||||
self.decoded_data.get_or_init(|| self.try_decode_data())
|
||||
}
|
||||
}
|
||||
|
||||
impl<Rest> GetPdfInputPosition for PdfStream<Rest> {
|
||||
impl<Rest, Data: PdfStreamContents> GetPdfInputPosition for PdfStream<Rest, Data> {
|
||||
fn get_pdf_input_position(&self) -> PdfInputPosition {
|
||||
self.pos.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<Rest> IsPdfNull for PdfStream<Rest> {
|
||||
impl<Rest, Data: PdfStreamContents> IsPdfNull for PdfStream<Rest, Data> {
|
||||
fn is_pdf_null(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl<Rest: PdfParse> PdfParse for PdfStream<Rest> {
|
||||
impl<Rest: PdfParse, Data: PdfStreamContents> PdfParse for PdfStream<Rest, Data> {
|
||||
fn type_name() -> Cow<'static, str> {
|
||||
if TypeId::of::<Rest>() == TypeId::of::<PdfDictionary>() {
|
||||
Cow::Borrowed("stream")
|
||||
|
|
@ -1655,38 +1886,56 @@ impl<Rest: PdfParse> PdfParse for PdfStream<Rest> {
|
|||
}
|
||||
fn parse(object: PdfObject) -> Result<Self, PdfParseError> {
|
||||
match PdfObjectDirect::from(object) {
|
||||
PdfObjectDirect::Stream(stream) => Ok(PdfStream {
|
||||
pos: stream.pos,
|
||||
dictionary: if let Some(dictionary) = <dyn std::any::Any>::downcast_ref::<
|
||||
Arc<OnceLock<PdfStreamDictionary<Rest>>>,
|
||||
>(&stream.dictionary)
|
||||
{
|
||||
dictionary.clone()
|
||||
} else {
|
||||
let PdfStreamDictionary {
|
||||
len,
|
||||
filters,
|
||||
decode_parms,
|
||||
file,
|
||||
file_filters,
|
||||
file_decode_parms,
|
||||
decoded_len,
|
||||
rest,
|
||||
} = stream.dictionary();
|
||||
Arc::new(OnceLock::from(PdfStreamDictionary {
|
||||
len: *len,
|
||||
filters: filters.clone(),
|
||||
decode_parms: decode_parms.clone(),
|
||||
file: file.clone(),
|
||||
file_filters: file_filters.clone(),
|
||||
file_decode_parms: file_decode_parms.clone(),
|
||||
decoded_len: *decoded_len,
|
||||
rest: Rest::parse(rest.clone().into())?,
|
||||
}))
|
||||
},
|
||||
encoded_data: stream.encoded_data,
|
||||
decoded_data: stream.decoded_data,
|
||||
}),
|
||||
PdfObjectDirect::Stream(stream) => {
|
||||
Ok(PdfStream {
|
||||
pos: stream.pos,
|
||||
dictionary: {
|
||||
let PdfStreamDictionary {
|
||||
len,
|
||||
filters,
|
||||
decode_parms,
|
||||
file,
|
||||
file_filters,
|
||||
file_decode_parms,
|
||||
decoded_len,
|
||||
rest,
|
||||
} = stream.dictionary;
|
||||
PdfStreamDictionary {
|
||||
len,
|
||||
filters,
|
||||
decode_parms,
|
||||
file,
|
||||
file_filters,
|
||||
file_decode_parms,
|
||||
decoded_len,
|
||||
rest: Rest::parse(rest.into())?,
|
||||
}
|
||||
},
|
||||
encoded_data: stream.encoded_data,
|
||||
decoded_data: if let Some(decoded_data) =
|
||||
<dyn std::any::Any>::downcast_ref(&stream.decoded_data)
|
||||
{
|
||||
Arc::clone(decoded_data)
|
||||
} else {
|
||||
let Some(objects) = stream.objects.upgrade() else {
|
||||
panic!("PdfObjects is no longer available");
|
||||
};
|
||||
Arc::new(
|
||||
stream
|
||||
.decoded_data
|
||||
.get()
|
||||
.cloned()
|
||||
.map(|data| {
|
||||
OnceLock::from(data.and_then(|data| {
|
||||
Data::parse_arc(data, stream.pos.0, objects)
|
||||
}))
|
||||
})
|
||||
.unwrap_or_default(),
|
||||
)
|
||||
},
|
||||
objects: stream.objects,
|
||||
})
|
||||
}
|
||||
object => Err(PdfParseError::InvalidType {
|
||||
pos: object.get_pdf_input_position(),
|
||||
ty: object.type_name(),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue