mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-10-30 21:17:55 -06:00
fix(create): refuse an indexed colour space whose base is indexed before following it
Image export parsed an Indexed colour space's base before checking whether that base was itself Indexed. A base that refers back to the same array recursed until the stack overflowed. The base is now checked first; since Indexed is the only colour space that recurses, this also ends any cycle.
This commit is contained in:
@@ -383,10 +383,17 @@ fn space(doc: &Document, cs: Option<&Object>) -> Result<Space, String> {
|
||||
Some(b"CalGray") => Ok(Space::Gray),
|
||||
Some(b"CalRGB") => Ok(Space::Rgb),
|
||||
Some(b"Indexed" | b"I") => {
|
||||
let base = space(doc, a.get(1))?;
|
||||
if matches!(base, Space::Indexed(..)) {
|
||||
// Checked before recursing: Indexed is the only space that recurses, so refusing
|
||||
// an Indexed base here also ends a cyclic base reference.
|
||||
let nested = match a.get(1).map(|b| doc.resolve(b)).as_deref() {
|
||||
Some(Object::Array(b)) => matches!(b.first().and_then(Object::as_name), Some(b"Indexed" | b"I")),
|
||||
Some(Object::Name(n)) => matches!(n.as_slice(), b"Indexed" | b"I"),
|
||||
_ => false,
|
||||
};
|
||||
if nested {
|
||||
return Err("nested indexed colour spaces aren't valid".into());
|
||||
}
|
||||
let base = space(doc, a.get(1))?;
|
||||
let hival = match a.get(2).map(|value| doc.resolve(value)).as_deref() {
|
||||
Some(Object::Int(value)) if (0..=255).contains(value) => *value as u8,
|
||||
_ => return Err("an indexed colour space with an invalid hival".into()),
|
||||
|
||||
@@ -1181,3 +1181,19 @@ fn a_jpeg_with_an_exif_orientation_becomes_an_upright_page() {
|
||||
let img = image_of(&doc, 1);
|
||||
assert_eq!((img.int(b"Width"), img.int(b"Height")), (Some(60), Some(20)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_cyclic_indexed_colour_space_is_refused() {
|
||||
let mut doc = from_images(&[("flat.png".into(), png_bytes(false))]).unwrap();
|
||||
// 5 0 obj [/Indexed 5 0 R 255 <00>]: the base is the indexed space itself.
|
||||
let cs = doc.add(Object::Null);
|
||||
doc.set(cs, Object::Array(vec![Object::name("Indexed"), Object::Ref(cs), Object::Int(255), Object::String(PdfString::literal(vec![0]))]));
|
||||
with_image(&mut doc, |_| {
|
||||
let mut dict = image_dict(1, 1, "DeviceGray", 8);
|
||||
dict.set(b"ColorSpace".to_vec(), Object::Ref(cs));
|
||||
Stream::from_raw(dict, vec![0])
|
||||
});
|
||||
let out = extract_images(&doc, &[0], 0);
|
||||
assert!(out.images.is_empty());
|
||||
assert_eq!(out.skipped.len(), 1, "{:?}", out.skipped);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user