Skip to content

Commit 27ef806

Browse files
authored
Merge pull request #248
pdf-image: validate decoded samples during decode
2 parents 53d2278 + f98195a commit 27ef806

2 files changed

Lines changed: 31 additions & 32 deletions

File tree

crates/pdf-image/src/decoded_samples.rs

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,20 +24,41 @@ impl DecodedSamples {
2424
objects: &dyn ObjectResolver,
2525
metadata: &ImageMetadata,
2626
) -> Result<Self, PdfImageError> {
27-
if let Some(decoded_samples) = Self::decode_preconverted_jpx(raw_data, metadata) {
28-
return Ok(decoded_samples);
29-
}
27+
let decoded_samples = if let Some(decoded_samples) =
28+
Self::decode_preconverted_jpx(raw_data, metadata)
29+
{
30+
decoded_samples
31+
} else if let Some(decoded_samples) = Self::decode_preconverted_dct(raw_data, metadata) {
32+
decoded_samples
33+
} else {
34+
match metadata.color_space.as_ref() {
35+
Some(ColorSpace::Indexed(indexed)) => {
36+
Self::decode_indexed(dictionary, raw_data, objects, metadata, indexed)
37+
}
38+
_ => Self::decode_direct(dictionary, raw_data, objects, metadata),
39+
}?
40+
};
3041

31-
if let Some(decoded_samples) = Self::decode_preconverted_dct(raw_data, metadata) {
32-
return Ok(decoded_samples);
42+
decoded_samples.validate(metadata)?;
43+
Ok(decoded_samples)
44+
}
45+
46+
/// Ensures the decoded component stream is large enough for the declared dimensions.
47+
fn validate(&self, metadata: &ImageMetadata) -> Result<(), PdfImageError> {
48+
if self.num_color_components == 0 {
49+
return Err(PdfImageError::InvalidColorComponentCount);
3350
}
3451

35-
match metadata.color_space.as_ref() {
36-
Some(ColorSpace::Indexed(indexed)) => {
37-
Self::decode_indexed(dictionary, raw_data, objects, metadata, indexed)
38-
}
39-
_ => Self::decode_direct(dictionary, raw_data, objects, metadata),
52+
let num_pixels = metadata.width.saturating_mul(metadata.height);
53+
let expected_bytes = num_pixels.saturating_mul(self.num_color_components);
54+
if self.image_data.len() < expected_bytes {
55+
return Err(PdfImageError::TruncatedImageData {
56+
expected_bytes,
57+
actual_bytes: self.image_data.len(),
58+
});
4059
}
60+
61+
Ok(())
4162
}
4263

4364
/// Uses DCT decoder output as display samples when the JPEG decoder already converted color.

crates/pdf-image/src/image_xobject.rs

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,6 @@ impl ImageXObject {
9595
metadata: &ImageMetadata,
9696
) -> Result<Self, PdfImageError> {
9797
let decoded_samples = DecodedSamples::decode(dictionary, raw_data, objects, metadata)?;
98-
Self::validate_decoded_samples(metadata, &decoded_samples)?;
9998
let (data, pixel_format) = Self::assemble_pixel_data(metadata, &decoded_samples, soft_mask);
10099

101100
Ok(Self {
@@ -108,27 +107,6 @@ impl ImageXObject {
108107
})
109108
}
110109

111-
/// Ensures the decoded component stream is large enough for the declared dimensions.
112-
fn validate_decoded_samples(
113-
metadata: &ImageMetadata,
114-
decoded_samples: &DecodedSamples,
115-
) -> Result<(), PdfImageError> {
116-
if decoded_samples.num_color_components == 0 {
117-
return Err(PdfImageError::InvalidColorComponentCount);
118-
}
119-
120-
let num_pixels = metadata.width.saturating_mul(metadata.height);
121-
let expected_bytes = num_pixels.saturating_mul(decoded_samples.num_color_components);
122-
if decoded_samples.image_data.len() < expected_bytes {
123-
return Err(PdfImageError::TruncatedImageData {
124-
expected_bytes,
125-
actual_bytes: decoded_samples.image_data.len(),
126-
});
127-
}
128-
129-
Ok(())
130-
}
131-
132110
/// Builds the final pixel buffer and pixel format after optional soft-mask application.
133111
fn assemble_pixel_data(
134112
metadata: &ImageMetadata,

0 commit comments

Comments
 (0)