From 0bc50dc5e08f9c8ef84c550b8bc5574ad74b5a05 Mon Sep 17 00:00:00 2001 From: Larry Gritz Date: Sat, 11 Apr 2026 19:04:16 -0700 Subject: [PATCH] fix(softimage): Various fixes for malformed channel packets * Fix bugs when channel order isn't strictly R,G,B,A by using a `m_channel_map`. * Detect malformed file with too many channel packets. * Gracefully handle duplicate channel bits across packets by not thinking that there are duplicate channels. * Guard against channel packets that contain no channels. Assisted-by: Claude Code / Opus 4.6 (mostly for analysis/identification of the potential problems; touching the code only for the out-of-order channels fix) Signed-off-by: Larry Gritz --- src/softimage.imageio/softimageinput.cpp | 48 ++++++++++++++++++------ 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/src/softimage.imageio/softimageinput.cpp b/src/softimage.imageio/softimageinput.cpp index 48724b4dff..8bf9772048 100644 --- a/src/softimage.imageio/softimageinput.cpp +++ b/src/softimage.imageio/softimageinput.cpp @@ -50,6 +50,9 @@ class SoftimageInput final : public ImageInput { std::vector m_channel_packets; std::string m_filename; std::vector m_scanline_markers; + // Maps absolute channel index (0=R,1=G,2=B,3=A) to sequential output + // offset within the scanline buffer. Initialized to -1 (unused). + int m_channel_map[4]; }; @@ -76,6 +79,7 @@ SoftimageInput::init() m_filename.clear(); m_channel_packets.clear(); m_scanline_markers.clear(); + std::fill(m_channel_map, m_channel_map + 4, -1); } @@ -110,7 +114,6 @@ SoftimageInput::open(const std::string& name, ImageSpec& spec) // Get the ChannelPackets ChannelPacket curPacket; - int nchannels = 0; std::vector encodings; do { // Read the next packet into curPacket and store it off @@ -126,13 +129,31 @@ SoftimageInput::open(const std::string& name, ImageSpec& spec) close(); return false; } + if (curPacket.channelCode == 0) { + errorfmt("Channel packet with no channels"); + close(); + return false; + } m_channel_packets.push_back(curPacket); - // Add the number of channels in this packet to nchannels - nchannels += curPacket.channels().size(); encodings.push_back(encoding_name(m_channel_packets.back().type)); + + if (m_channel_packets.size() > 4) { + errorfmt("Too many channel packets"); + close(); + return false; + } } while (curPacket.chained); + // Build channel map: absolute RGBA index -> sequential output offset + int nchannels = 0; + { + for (auto& cp : m_channel_packets) + for (int ch : cp.channels()) + if (m_channel_map[ch] == -1) + m_channel_map[ch] = nchannels++; + } + // Get the depth per pixel per channel TypeDesc chanType = TypeDesc::UINT8; if (curPacket.size == 16) @@ -307,7 +328,8 @@ SoftimageInput::read_pixels_uncompressed( //read the data into the correct place if (fread(&scanlineData[(pixelX * pixelChannelSize * m_spec.nchannels) - + (channel * pixelChannelSize) + + (m_channel_map[channel] + * pixelChannelSize) + curByte], 1, 1, m_fd) != 1) @@ -370,7 +392,8 @@ SoftimageInput::read_pixels_pure_run_length( //put the data into the correct place scanlineData[(pixelX * pixelChannelSize * m_spec.nchannels) - + (channels[curChan] * pixelChannelSize) + + (m_channel_map[channels[curChan]] + * pixelChannelSize) + curByte] = pixelData[(curChan * pixelChannelSize) + curByte]; } @@ -432,12 +455,12 @@ SoftimageInput::read_pixels_mixed_run_length( curByte = ((pixelChannelSize)-1) - curByte; //read the data into the correct place - if (fread( - &scanlineData[(pixelX * pixelChannelSize - * m_spec.nchannels) - + (channel * pixelChannelSize) - + curByte], - 1, 1, m_fd) + if (fread(&scanlineData[(pixelX * pixelChannelSize + * m_spec.nchannels) + + (m_channel_map[channel] + * pixelChannelSize) + + curByte], + 1, 1, m_fd) != 1) return false; } @@ -500,7 +523,8 @@ SoftimageInput::read_pixels_mixed_run_length( //put the data into the correct place scanlineData[(pixelX * pixelChannelSize * m_spec.nchannels) - + (channels[curChan] * pixelChannelSize) + + (m_channel_map[channels[curChan]] + * pixelChannelSize) + curByte] = pixelData[(curChan * pixelChannelSize) + curByte];