Skip to content

Commit 18de7aa

Browse files
committed
Add SGI Image (.rgb) decoder
1 parent 09d37b8 commit 18de7aa

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+761
-1
lines changed

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@ publish = false
88
include = ["src", "tests/reference.rs"]
99

1010
[features]
11-
default = ["pcx", "xbm", "xpm"]
11+
default = ["pcx", "xbm", "xpm", "sgi"]
1212
pcx = ["dep:pcx"]
1313
xbm = []
1414
xpm = ["dep:image-x11r6colors"]
15+
sgi = []
1516

1617
[dependencies]
1718
image = { version = "0.25.5", default-features = false }

fuzz/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,7 @@ path = "fuzzers/fuzzer_script_xbm.rs"
3333
[[bin]]
3434
name = "fuzzer_script_xpm"
3535
path = "fuzzers/fuzzer_script_xpm.rs"
36+
37+
[[bin]]
38+
name = "fuzzer_script_sgi"
39+
path = "fuzzers/fuzzer_script_sgi.rs"

fuzz/fuzzers/fuzzer_script_sgi.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#![no_main]
2+
#[macro_use] extern crate libfuzzer_sys;
3+
4+
use std::io::Cursor;
5+
use image::ImageDecoder;
6+
7+
fuzz_target!(|data: &[u8]| {
8+
let reader = Cursor::new(data);
9+
let Ok(mut decoder) = image_extras::sgi::SgiDecoder::new(reader) else {
10+
return;
11+
};
12+
let mut limits = image::Limits::default();
13+
limits.max_alloc = Some(1024 * 1024); // 1 MiB
14+
if limits.reserve(decoder.total_bytes()).is_err() {
15+
return;
16+
}
17+
if decoder.set_limits(limits).is_err() {
18+
return;
19+
}
20+
let _ = std::hint::black_box(image::DynamicImage::from_decoder(decoder));
21+
});

src/lib.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ pub mod xbm;
2424
#[cfg(feature = "xpm")]
2525
pub mod xpm;
2626

27+
#[cfg(feature = "sgi")]
28+
pub mod sgi;
29+
2730
/// Register all enabled extra formats with the image crate.
2831
pub fn register() {
2932
image::hooks::register_decoding_hook(
@@ -47,4 +50,38 @@ pub fn register() {
4750
Box::new(|r| Ok(Box::new(xpm::XpmDecoder::new(r)?))),
4851
);
4952
image::hooks::register_format_detection_hook("xpm".into(), b"/* XPM */", None);
53+
54+
// SGI RGB images generally show up with a .rgb ending (whether or not they
55+
// have 3 channels), and sometimes .bw (when grayscale) and .rgba. The
56+
// extensions .sgi and .iris, while unambiguous, do not seem to have been
57+
// used much. The extension .rgb is also used for a variety of other files,
58+
// including bare image data, so to be sure it would be best to check both
59+
// extension and leading bytes
60+
image::hooks::register_decoding_hook(
61+
"bw".into(),
62+
Box::new(|r| Ok(Box::new(sgi::SgiDecoder::new(r)?))),
63+
);
64+
image::hooks::register_decoding_hook(
65+
"rgb".into(),
66+
Box::new(|r| Ok(Box::new(sgi::SgiDecoder::new(r)?))),
67+
);
68+
image::hooks::register_decoding_hook(
69+
"rgba".into(),
70+
Box::new(|r| Ok(Box::new(sgi::SgiDecoder::new(r)?))),
71+
);
72+
image::hooks::register_decoding_hook(
73+
"sgi".into(),
74+
Box::new(|r| Ok(Box::new(sgi::SgiDecoder::new(r)?))),
75+
);
76+
image::hooks::register_decoding_hook(
77+
"iris".into(),
78+
Box::new(|r| Ok(Box::new(sgi::SgiDecoder::new(r)?))),
79+
);
80+
// The main signature bytes technically just 01 da, but this is short and
81+
// the following storage and bpc fields are constrained well enough to
82+
// efficiently match them as well
83+
image::hooks::register_format_detection_hook("sgi".into(), b"\x01\xda\x00\x01", None);
84+
image::hooks::register_format_detection_hook("sgi".into(), b"\x01\xda\x01\x01", None);
85+
image::hooks::register_format_detection_hook("sgi".into(), b"\x01\xda\x00\x02", None);
86+
image::hooks::register_format_detection_hook("sgi".into(), b"\x01\xda\x01\x02", None);
5087
}

0 commit comments

Comments
 (0)