@@ -50,6 +50,9 @@ class SoftimageInput final : public ImageInput {
5050 std::vector<softimage_pvt::ChannelPacket> m_channel_packets;
5151 std::string m_filename;
5252 std::vector<fpos_t > m_scanline_markers;
53+ // Maps absolute channel index (0=R,1=G,2=B,3=A) to sequential output
54+ // offset within the scanline buffer. Initialized to -1 (unused).
55+ int m_channel_map[4 ];
5356};
5457
5558
@@ -76,6 +79,7 @@ SoftimageInput::init()
7679 m_filename.clear ();
7780 m_channel_packets.clear ();
7881 m_scanline_markers.clear ();
82+ std::fill (m_channel_map, m_channel_map + 4 , -1 );
7983}
8084
8185
@@ -110,7 +114,6 @@ SoftimageInput::open(const std::string& name, ImageSpec& spec)
110114
111115 // Get the ChannelPackets
112116 ChannelPacket curPacket;
113- int nchannels = 0 ;
114117 std::vector<std::string> encodings;
115118 do {
116119 // Read the next packet into curPacket and store it off
@@ -126,13 +129,31 @@ SoftimageInput::open(const std::string& name, ImageSpec& spec)
126129 close ();
127130 return false ;
128131 }
132+ if (curPacket.channelCode == 0 ) {
133+ errorfmt (" Channel packet with no channels" );
134+ close ();
135+ return false ;
136+ }
129137 m_channel_packets.push_back (curPacket);
130138
131- // Add the number of channels in this packet to nchannels
132- nchannels += curPacket.channels ().size ();
133139 encodings.push_back (encoding_name (m_channel_packets.back ().type ));
140+
141+ if (m_channel_packets.size () > 4 ) {
142+ errorfmt (" Too many channel packets" );
143+ close ();
144+ return false ;
145+ }
134146 } while (curPacket.chained );
135147
148+ // Build channel map: absolute RGBA index -> sequential output offset
149+ int nchannels = 0 ;
150+ {
151+ for (auto & cp : m_channel_packets)
152+ for (int ch : cp.channels ())
153+ if (m_channel_map[ch] == -1 )
154+ m_channel_map[ch] = nchannels++;
155+ }
156+
136157 // Get the depth per pixel per channel
137158 TypeDesc chanType = TypeDesc::UINT8;
138159 if (curPacket.size == 16 )
@@ -175,6 +196,8 @@ SoftimageInput::read_native_scanline(int subimage, int miplevel, int y,
175196 lock_guard lock (*this );
176197 if (!seek_subimage (subimage, miplevel))
177198 return false ;
199+ if (y < 0 || y >= m_spec.height )
200+ return false ;
178201
179202 bool result = false ;
180203 if (y == (int )m_scanline_markers.size () - 1 ) {
@@ -271,9 +294,14 @@ SoftimageInput::read_next_scanline(void* data)
271294 ok = read_pixels_pure_run_length (cp, data);
272295 } else if (type == MIXED_RUN_LENGTH) {
273296 ok = read_pixels_mixed_run_length (cp, data);
297+ } else {
298+ errorfmt (" Unsupported channel packet encoding {:d} in \" {}\" " ,
299+ int (cp.type ), m_filename);
300+ close ();
301+ return false ;
274302 }
275303 if (!ok) {
276- errorfmt (" Failed to read channel packed type {:d} from \" {}\" " ,
304+ errorfmt (" Failed to read channel packet type {:d} from \" {}\" " ,
277305 int (cp.type ), m_filename);
278306 close ();
279307 return false ;
@@ -307,7 +335,8 @@ SoftimageInput::read_pixels_uncompressed(
307335 // read the data into the correct place
308336 if (fread (&scanlineData[(pixelX * pixelChannelSize
309337 * m_spec.nchannels )
310- + (channel * pixelChannelSize)
338+ + (m_channel_map[channel]
339+ * pixelChannelSize)
311340 + curByte],
312341 1 , 1 , m_fd)
313342 != 1 )
@@ -345,6 +374,12 @@ SoftimageInput::read_pixels_pure_run_length(
345374 if (fread (&curCount, 1 , 1 , m_fd) != 1 )
346375 return false ;
347376
377+ // Zero-length run is malformed
378+ if (curCount == 0 ) {
379+ errorfmt (" Invalid RLE data" );
380+ return false ;
381+ }
382+
348383 // Clamp to avoid writing past the end of the scanline buffer
349384 if (linePixelCount + curCount > m_pic_header.width )
350385 curCount = m_pic_header.width - linePixelCount;
@@ -353,7 +388,7 @@ SoftimageInput::read_pixels_pure_run_length(
353388 // data pointer is set so we're supposed to write data there
354389 size_t pixelSize = pixelChannelSize * channels.size ();
355390 uint8_t * pixelData = new uint8_t [pixelSize];
356- if (fread (pixelData, pixelSize, 1 , m_fd) != pixelSize)
391+ if (fread (pixelData, 1 , pixelSize , m_fd) != pixelSize)
357392 return false ;
358393
359394 // Now we've got the pixel value we need to push it into the data
@@ -370,7 +405,8 @@ SoftimageInput::read_pixels_pure_run_length(
370405 // put the data into the correct place
371406 scanlineData[(pixelX * pixelChannelSize
372407 * m_spec.nchannels )
373- + (channels[curChan] * pixelChannelSize)
408+ + (m_channel_map[channels[curChan]]
409+ * pixelChannelSize)
374410 + curByte]
375411 = pixelData[(curChan * pixelChannelSize) + curByte];
376412 }
@@ -432,12 +468,12 @@ SoftimageInput::read_pixels_mixed_run_length(
432468 curByte = ((pixelChannelSize)-1 ) - curByte;
433469
434470 // read the data into the correct place
435- if (fread (
436- &scanlineData[(pixelX * pixelChannelSize
437- * m_spec. nchannels )
438- + (channel * pixelChannelSize)
439- + curByte],
440- 1 , 1 , m_fd)
471+ if (fread (&scanlineData[(pixelX * pixelChannelSize
472+ * m_spec. nchannels )
473+ + (m_channel_map[channel]
474+ * pixelChannelSize)
475+ + curByte],
476+ 1 , 1 , m_fd)
441477 != 1 )
442478 return false ;
443479 }
@@ -472,6 +508,12 @@ SoftimageInput::read_pixels_mixed_run_length(
472508 longCount = curCount - 127 ;
473509 }
474510
511+ // Zero-length run is malformed
512+ if (longCount == 0 ) {
513+ errorfmt (" Invalid RLE data" );
514+ return false ;
515+ }
516+
475517 // Clamp to avoid writing past the end of the scanline buffer
476518 if (linePixelCount + longCount > m_pic_header.width )
477519 longCount = m_pic_header.width - linePixelCount;
@@ -500,7 +542,8 @@ SoftimageInput::read_pixels_mixed_run_length(
500542 // put the data into the correct place
501543 scanlineData[(pixelX * pixelChannelSize
502544 * m_spec.nchannels )
503- + (channels[curChan] * pixelChannelSize)
545+ + (m_channel_map[channels[curChan]]
546+ * pixelChannelSize)
504547 + curByte]
505548 = pixelData[(curChan * pixelChannelSize)
506549 + curByte];
0 commit comments