fix(xfa): leave a 16-byte BMP header to the decoder; test core headers and a huge colour count

Review follow-up: the repair reads the 40-byte header's compression and
colour count, which a 16-byte OS/2 header does not have. New cases pin
a 12-byte core header (3-byte palette entries) and a biClrUsed of u32::MAX.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SqmHYx8FiWM5PcsoiErgp9
This commit is contained in:
KenM76
2026-10-27 05:03:47 -04:00
co-authored by Claude Opus 5.5
parent 38c9482191
commit de9ab5370e
2 changed files with 20 additions and 0 deletions
+3
View File
@@ -74,6 +74,9 @@ fn bmp_pixel_offset_repair(data: &[u8]) -> Option<u32> {
let (bpp, masks, used, entry) = if info_size == 12 {
// BITMAPCOREHEADER: 16-bit fields, no colour count, 3-byte table entries.
(le16(24)?, 0, 0, 3)
} else if info_size < 40 {
// OS/2's 16-byte header ends before the colour count; leave it to the decoder.
return None;
} else {
// BI_BITFIELDS and BI_ALPHABITFIELDS put their masks after a 40-byte header; the larger
// headers hold them inside.
+17
View File
@@ -1825,6 +1825,23 @@ fn a_bmp_whose_pixel_offset_points_into_its_headers_is_read_from_after_them() {
fields[10..14].copy_from_slice(&0u32.to_le_bytes());
fields.splice(54..54, [0u8; 12]);
assert_eq!(bmp_with_pixel_offset(&fields).get(10..14), Some(&66u32.to_le_bytes()[..]));
// A colour count no file could hold: left alone.
let mut huge = tiny_bmp(true);
huge[46..50].copy_from_slice(&u32::MAX.to_le_bytes());
huge[10..14].copy_from_slice(&0u32.to_le_bytes());
assert_eq!(bmp_with_pixel_offset(&huge).as_ref(), &huge[..]);
// A 12-byte core header: 16-bit fields and 3-byte palette entries, `1 << bpp` of them.
let mut core = b"BM".to_vec();
core.extend_from_slice(&[0; 8]);
core.extend_from_slice(&0u32.to_le_bytes());
core.extend_from_slice(&12u32.to_le_bytes());
for v in [2u16, 1, 1, 1] {
core.extend_from_slice(&v.to_le_bytes());
}
core.extend_from_slice(&[0, 0, 255, 255, 0, 0, 0b0100_0000, 0, 0, 0]);
assert_eq!(bmp_with_pixel_offset(&core).get(10..14), Some(&32u32.to_le_bytes()[..]));
let d = decode(&bmp_with_pixel_offset(&core)).unwrap();
assert_eq!(d.samples, vec![255, 0, 0, 0, 0, 255], "core header");
}
/// Designer forms often carry BMP and TIFF pictures, declared as `image/bmp` and `image/tif`