fix(create): preserve version-four PCX compatibility

This commit is contained in:
Dylan M. Taylor committed 2026-11-14 23:59:16 -05:00
1 parent e9f7aeaeee
commit 0a11922520
2 files changed
+27 -3

No files matched your search

+14 -3
View File
@@ -562,7 +562,11 @@ fn pcx(name: &str, bytes: &[u8]) -> Result<Embedded, CreateError> {
// is black/white and an indexed file without its VGA palette is interpreted as gray.
// The shared reader owns all RLE, plane unpacking and palette application.
let has_vga = bytes.len().checked_sub(769).is_some_and(|at| at >= 128 && bytes.get(at) == Some(&0x0C));
let normalize = (bits == 1 && planes == 1) || (bits == 8 && planes == 1 && !has_vga);
// The pinned decoder predates shared version-4 recognition. Its version byte is
// only a header acceptance check, not a switch for pixel or palette semantics.
// Keep this app's existing version-4 acceptance without replacing the shared pin.
let version_four = byte(1) == 4;
let normalize = version_four || (bits == 1 && planes == 1) || (bits == 8 && planes == 1 && !has_vga);
let mut input = std::borrow::Cow::Borrowed(bytes);
if normalize {
// Normalization must not add an unbounded copy of hostile compressed input.
@@ -572,11 +576,18 @@ fn pcx(name: &str, bytes: &[u8]) -> Result<Embedded, CreateError> {
let mut copy = Vec::new();
copy.try_reserve_exact(bytes.len()).map_err(|_| bad("not enough memory for this image"))?;
copy.extend_from_slice(bytes);
if bits == 1 {
if version_four && let Some(version) = copy.get_mut(1) {
*version = 5;
}
if bits == 1 && planes == 1 {
if let Some(palette) = copy.get_mut(16..22) {
palette.copy_from_slice(&[0, 0, 0, 255, 255, 255]);
}
} else if let Some(info) = copy.get_mut(68..70) {
} else if bits == 8
&& planes == 1
&& !has_vga
&& let Some(info) = copy.get_mut(68..70)
{
info.copy_from_slice(&2u16.to_le_bytes());
}
input = std::borrow::Cow::Owned(copy);
+13
View File
@@ -3144,3 +3144,16 @@ fn shared_pcx_rejects_zero_length_runs_and_oversized_planes() {
let rgba = pcx_header(5, 8, 4, 1, 1, 1);
assert!(super::pcx("rgba.pcx", &rgba).is_err(), "do not silently expand accepted layouts");
}
#[test]
fn shared_pcx_keeps_version_four_rgb_and_palette_pixels() {
let mut rgb = pcx_header(4, 8, 3, 1, 1, 1);
rgb.extend_from_slice(&[10, 20, 30]);
assert!(super::is_image(&rgb));
assert_eq!(super::pcx("windows.pcx", &rgb).unwrap().data, [10, 20, 30]);
let mut palette = pcx_header(4, 1, 2, 1, 1, 1);
palette[25..28].copy_from_slice(&[4, 5, 6]);
palette.extend_from_slice(&[0x80, 0x80]);
assert_eq!(super::pcx("windows.pcx", &palette).unwrap().data, [4, 5, 6]);
assert!(from_images(&[("windows.pcx".into(), rgb)]).is_ok());
}