@@ -1853,6 +1853,9 @@ private bool TryReadChunk(Span<byte> buffer, out PngChunk chunk)
1853
1853
return false ;
1854
1854
}
1855
1855
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
+
1856
1859
if ( ! this . TryReadChunkLength ( buffer , out int length ) )
1857
1860
{
1858
1861
// IEND
@@ -1871,7 +1874,48 @@ private bool TryReadChunk(Span<byte> buffer, out PngChunk chunk)
1871
1874
}
1872
1875
}
1873
1876
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
+ }
1875
1919
1876
1920
// If we're reading color metadata only we're only interested in the IHDR and tRNS chunks.
1877
1921
// 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)
1888
1932
1889
1933
// A chunk might report a length that exceeds the length of the stream.
1890
1934
// 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 ;
1892
1936
chunk = new PngChunk (
1893
1937
length : ( int ) Math . Min ( length , this . currentStream . Length - position ) ,
1894
1938
type : type ,
@@ -1906,6 +1950,32 @@ private bool TryReadChunk(Span<byte> buffer, out PngChunk chunk)
1906
1950
return true ;
1907
1951
}
1908
1952
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
+
1909
1979
/// <summary>
1910
1980
/// Validates the png chunk.
1911
1981
/// </summary>
0 commit comments