@@ -91,6 +91,11 @@ public ExrDecoderCore(ExrDecoderOptions options)
9191 /// </summary>
9292 private ExrHeaderAttributes HeaderAttributes { get ; set ; }
9393
94+ /// <summary>
95+ /// Gets or sets the earliest valid stream position for a scanline chunk.
96+ /// </summary>
97+ private long MinimumChunkOffset { get ; set ; }
98+
9499 /// <inheritdoc />
95100 protected override Image < TPixel > Decode < TPixel > ( BufferedReadStream stream , CancellationToken cancellationToken )
96101 {
@@ -175,11 +180,7 @@ private void DecodeFloatingPointPixelData<TPixel>(BufferedReadStream stream, Buf
175180 ulong rowOffset = this . ReadUnsignedLong ( stream ) ;
176181 long nextRowOffsetPosition = stream . Position ;
177182
178- if ( rowOffset >= ( ulong ) stream . Length )
179- {
180- ExrThrowHelper . ThrowInvalidImageContentException ( "EXR row offset is outside the bounds of the stream." ) ;
181- }
182-
183+ this . ValidateChunkOffset ( rowOffset , stream ) ;
183184 stream . Position = ( long ) rowOffset ;
184185 uint rowStartIndex = this . ReadUnsignedInteger ( stream ) ;
185186
@@ -258,11 +259,7 @@ private void DecodeUnsignedIntPixelData<TPixel>(BufferedReadStream stream, Buffe
258259 ulong rowOffset = this . ReadUnsignedLong ( stream ) ;
259260 long nextRowOffsetPosition = stream . Position ;
260261
261- if ( rowOffset >= ( ulong ) stream . Length )
262- {
263- ExrThrowHelper . ThrowInvalidImageContentException ( "EXR row offset is outside the bounds of the stream." ) ;
264- }
265-
262+ this . ValidateChunkOffset ( rowOffset , stream ) ;
266263 stream . Position = ( long ) rowOffset ;
267264 uint rowStartIndex = this . ReadUnsignedInteger ( stream ) ;
268265
@@ -634,6 +631,9 @@ private ExrHeaderAttributes ReadExrHeader(BufferedReadStream stream)
634631 this . Height = ( int ) height ;
635632 this . Channels = this . HeaderAttributes . Channels ;
636633 this . Compression = this . HeaderAttributes . Compression ;
634+ uint rowsPerBlock = ExrUtils . RowsPerBlock ( this . Compression ) ;
635+ long chunkCount = ( this . Height + ( long ) rowsPerBlock - 1 ) / rowsPerBlock ;
636+ this . MinimumChunkOffset = stream . Position + ( chunkCount * sizeof ( ulong ) ) ;
637637 this . PixelType = this . ValidateChannels ( ) ;
638638 this . ImageDataType = this . DetermineImageDataType ( ) ;
639639
@@ -899,6 +899,19 @@ private static string ReadString(BufferedReadStream stream)
899899 _ => false ,
900900 } ;
901901
902+ /// <summary>
903+ /// Validates a scanline chunk offset read from the EXR offset table.
904+ /// </summary>
905+ /// <param name="chunkOffset">The chunk offset to validate.</param>
906+ /// <param name="stream">The stream containing the image data.</param>
907+ private void ValidateChunkOffset ( ulong chunkOffset , BufferedReadStream stream )
908+ {
909+ if ( chunkOffset < ( ulong ) this . MinimumChunkOffset || chunkOffset >= ( ulong ) stream . Length )
910+ {
911+ ExrThrowHelper . ThrowInvalidImageContentException ( "EXR chunk offset is outside the bounds of the stream." ) ;
912+ }
913+ }
914+
902915 /// <summary>
903916 /// Determines whether this image has alpha channel.
904917 /// </summary>
0 commit comments