@@ -1853,6 +1853,9 @@ private bool TryReadChunk(Span<byte> buffer, out PngChunk chunk)
18531853 return false ;
18541854 }
18551855
1856+ // Capture the current position so we can revert back to it if we fail to read a valid chunk.
1857+ long position = this . currentStream . Position ;
1858+
18561859 if ( ! this . TryReadChunkLength ( buffer , out int length ) )
18571860 {
18581861 // IEND
@@ -1871,7 +1874,48 @@ private bool TryReadChunk(Span<byte> buffer, out PngChunk chunk)
18711874 }
18721875 }
18731876
1874- PngChunkType type = this . ReadChunkType ( buffer ) ;
1877+ PngChunkType type ;
1878+
1879+ // Loop until we get a chunk type that is valid.
1880+ while ( true )
1881+ {
1882+ type = this . ReadChunkType ( buffer ) ;
1883+ if ( ! IsValidChunkType ( type ) )
1884+ {
1885+ // The chunk type is invalid.
1886+ // Revert back to the next byte past the previous position and try again.
1887+ this . currentStream . Position = ++ position ;
1888+
1889+ // If we are now at the end of the stream, we're done.
1890+ if ( this . currentStream . Position >= this . currentStream . Length )
1891+ {
1892+ chunk = default ;
1893+ return false ;
1894+ }
1895+
1896+ // Read the next chunk’s length.
1897+ if ( ! this . TryReadChunkLength ( buffer , out length ) )
1898+ {
1899+ chunk = default ;
1900+ return false ;
1901+ }
1902+
1903+ while ( length < 0 )
1904+ {
1905+ if ( ! this . TryReadChunkLength ( buffer , out length ) )
1906+ {
1907+ chunk = default ;
1908+ return false ;
1909+ }
1910+ }
1911+
1912+ // Continue to try reading the next chunk.
1913+ continue ;
1914+ }
1915+
1916+ // We have a valid chunk type.
1917+ break ;
1918+ }
18751919
18761920 // If we're reading color metadata only we're only interested in the IHDR and tRNS chunks.
18771921 // We can skip most other chunk data in the stream for better performance.
@@ -1888,7 +1932,7 @@ private bool TryReadChunk(Span<byte> buffer, out PngChunk chunk)
18881932
18891933 // A chunk might report a length that exceeds the length of the stream.
18901934 // Take the minimum of the two values to ensure we don't read past the end of the stream.
1891- long position = this . currentStream . Position ;
1935+ position = this . currentStream . Position ;
18921936 chunk = new PngChunk (
18931937 length : ( int ) Math . Min ( length , this . currentStream . Length - position ) ,
18941938 type : type ,
@@ -1906,6 +1950,32 @@ private bool TryReadChunk(Span<byte> buffer, out PngChunk chunk)
19061950 return true ;
19071951 }
19081952
1953+ /// <summary>
1954+ /// Determines whether the 4-byte chunk type is valid (all ASCII letters).
1955+ /// </summary>
1956+ /// <param name="type">The chunk type.</param>
1957+ [ MethodImpl ( InliningOptions . ShortMethod ) ]
1958+ private static bool IsValidChunkType ( PngChunkType type )
1959+ {
1960+ uint value = ( uint ) type ;
1961+ byte b0 = ( byte ) ( value >> 24 ) ;
1962+ byte b1 = ( byte ) ( value >> 16 ) ;
1963+ byte b2 = ( byte ) ( value >> 8 ) ;
1964+ byte b3 = ( byte ) value ;
1965+ return IsAsciiLetter ( b0 ) && IsAsciiLetter ( b1 ) && IsAsciiLetter ( b2 ) && IsAsciiLetter ( b3 ) ;
1966+ }
1967+
1968+ /// <summary>
1969+ /// Returns a value indicating whether the given byte is an ASCII letter.
1970+ /// </summary>
1971+ /// <param name="b">The byte to check.</param>
1972+ /// <returns>
1973+ /// <see langword="true"/> if the byte is an ASCII letter; otherwise, <see langword="false"/>.
1974+ /// </returns>
1975+ [ MethodImpl ( InliningOptions . ShortMethod ) ]
1976+ private static bool IsAsciiLetter ( byte b )
1977+ => ( b >= ( byte ) 'A' && b <= ( byte ) 'Z' ) || ( b >= ( byte ) 'a' && b <= ( byte ) 'z' ) ;
1978+
19091979 /// <summary>
19101980 /// Validates the png chunk.
19111981 /// </summary>
0 commit comments