@@ -17,7 +17,7 @@ internal struct HuffmanScanBuffer
1717 private ulong data ;
1818
1919 // The number of valid bits left to read in the buffer.
20- private int remain ;
20+ private int remainingBits ;
2121
2222 // Whether there is no more good data to pull from the stream for the current mcu.
2323 private bool badData ;
@@ -26,10 +26,9 @@ public HuffmanScanBuffer(DoubleBufferedStreamReader stream)
2626 {
2727 this . stream = stream ;
2828 this . data = 0ul ;
29- this . remain = 0 ;
29+ this . remainingBits = 0 ;
3030 this . Marker = JpegConstants . Markers . XFF ;
3131 this . MarkerPosition = 0 ;
32- this . BadMarker = false ;
3332 this . badData = false ;
3433 this . NoData = false ;
3534 }
@@ -44,11 +43,6 @@ public HuffmanScanBuffer(DoubleBufferedStreamReader stream)
4443 /// </summary>
4544 public long MarkerPosition { get ; private set ; }
4645
47- /// <summary>
48- /// Gets a value indicating whether a bad marker has been detected, I.E. One that is not between RST0 and RST7
49- /// </summary>
50- public bool BadMarker { get ; private set ; }
51-
5246 /// <summary>
5347 /// Gets a value indicating whether to continue reading the input stream.
5448 /// </summary>
@@ -57,7 +51,7 @@ public HuffmanScanBuffer(DoubleBufferedStreamReader stream)
5751 [ MethodImpl ( InliningOptions . ShortMethod ) ]
5852 public void CheckBits ( )
5953 {
60- if ( this . remain < 16 )
54+ if ( this . remainingBits < 16 )
6155 {
6256 this . FillBuffer ( ) ;
6357 }
@@ -67,27 +61,31 @@ public void CheckBits()
6761 public void Reset ( )
6862 {
6963 this . data = 0ul ;
70- this . remain = 0 ;
64+ this . remainingBits = 0 ;
7165 this . Marker = JpegConstants . Markers . XFF ;
7266 this . MarkerPosition = 0 ;
73- this . BadMarker = false ;
7467 this . badData = false ;
7568 this . NoData = false ;
7669 }
7770
71+ /// <summary>
72+ /// Whether a RST marker has been detected, I.E. One that is between RST0 and RST7
73+ /// </summary>
7874 [ MethodImpl ( InliningOptions . ShortMethod ) ]
79- public bool HasRestart ( )
80- {
81- byte m = this . Marker ;
82- return m >= JpegConstants . Markers . RST0 && m <= JpegConstants . Markers . RST7 ;
83- }
75+ public bool HasRestartMarker ( ) => HasRestart ( this . Marker ) ;
76+
77+ /// <summary>
78+ /// Whether a bad marker has been detected, I.E. One that is not between RST0 and RST7
79+ /// </summary>
80+ [ MethodImpl ( InliningOptions . ShortMethod ) ]
81+ public bool HasBadMarker ( ) => this . Marker != JpegConstants . Markers . XFF && ! this . HasRestartMarker ( ) ;
8482
8583 [ MethodImpl ( InliningOptions . ShortMethod ) ]
8684 public void FillBuffer ( )
8785 {
8886 // Attempt to load at least the minimum number of required bits into the buffer.
8987 // We fail to do so only if we hit a marker or reach the end of the input stream.
90- this . remain += 48 ;
88+ this . remainingBits += 48 ;
9189 this . data = ( this . data << 48 ) | this . GetBytes ( ) ;
9290 }
9391
@@ -101,17 +99,17 @@ public unsafe int DecodeHuffman(ref HuffmanTable h)
10199
102100 if ( size == JpegConstants . Huffman . SlowBits )
103101 {
104- ulong x = this . data << ( JpegConstants . Huffman . RegisterSize - this . remain ) ;
102+ ulong x = this . data << ( JpegConstants . Huffman . RegisterSize - this . remainingBits ) ;
105103 while ( x > h . MaxCode [ size ] )
106104 {
107105 size ++ ;
108106 }
109107
110108 v = ( int ) ( x >> ( JpegConstants . Huffman . RegisterSize - size ) ) ;
111- symbol = h . Values [ h . ValOffset [ size ] + v ] ;
109+ symbol = h . Values [ ( h . ValOffset [ size ] + v ) & 0xFF ] ;
112110 }
113111
114- this . remain -= size ;
112+ this . remainingBits -= size ;
115113
116114 return symbol ;
117115 }
@@ -124,10 +122,14 @@ public int Receive(int nbits)
124122 }
125123
126124 [ MethodImpl ( InliningOptions . ShortMethod ) ]
127- public int GetBits ( int nbits ) => ( int ) ExtractBits ( this . data , this . remain -= nbits , nbits ) ;
125+ private static bool HasRestart ( byte marker )
126+ => marker >= JpegConstants . Markers . RST0 && marker <= JpegConstants . Markers . RST7 ;
128127
129128 [ MethodImpl ( InliningOptions . ShortMethod ) ]
130- public int PeekBits ( int nbits ) => ( int ) ExtractBits ( this . data , this . remain - nbits , nbits ) ;
129+ public int GetBits ( int nbits ) => ( int ) ExtractBits ( this . data , this . remainingBits -= nbits , nbits ) ;
130+
131+ [ MethodImpl ( InliningOptions . ShortMethod ) ]
132+ public int PeekBits ( int nbits ) => ( int ) ExtractBits ( this . data , this . remainingBits - nbits , nbits ) ;
131133
132134 [ MethodImpl ( InliningOptions . ShortMethod ) ]
133135 private static ulong ExtractBits ( ulong value , int offset , int size ) => ( value >> offset ) & ( ulong ) ( ( 1 << size ) - 1 ) ;
@@ -149,22 +151,18 @@ private ulong GetBytes()
149151 int c = this . ReadStream ( ) ;
150152 while ( c == JpegConstants . Markers . XFF )
151153 {
152- // Loop here to discard any padding FF's on terminating marker,
154+ // Loop here to discard any padding FF bytes on terminating marker,
153155 // so that we can save a valid marker value.
154156 c = this . ReadStream ( ) ;
155157 }
156158
157- // We accept multiple FF's followed by a 0 as meaning a single FF data byte.
159+ // We accept multiple FF bytes followed by a 0 as meaning a single FF data byte.
158160 // This data pattern is not valid according to the standard.
159161 if ( c != 0 )
160162 {
161163 this . Marker = ( byte ) c ;
162164 this . badData = true ;
163- if ( ! this . HasRestart ( ) )
164- {
165- this . MarkerPosition = this . stream . Position - 2 ;
166- this . BadMarker = true ;
167- }
165+ this . MarkerPosition = this . stream . Position - 2 ;
168166 }
169167 }
170168
@@ -174,6 +172,42 @@ private ulong GetBytes()
174172 return temp ;
175173 }
176174
175+ [ MethodImpl ( InliningOptions . ShortMethod ) ]
176+ public bool FindNextMarker ( )
177+ {
178+ while ( true )
179+ {
180+ int b = this . stream . ReadByte ( ) ;
181+ if ( b == - 1 )
182+ {
183+ return false ;
184+ }
185+
186+ // Found a marker.
187+ if ( b == JpegConstants . Markers . XFF )
188+ {
189+ while ( b == JpegConstants . Markers . XFF )
190+ {
191+ // Loop here to discard any padding FF bytes on terminating marker.
192+ b = this . stream . ReadByte ( ) ;
193+ if ( b == - 1 )
194+ {
195+ return false ;
196+ }
197+ }
198+
199+ // Found a valid marker. Exit loop
200+ if ( b != 0 )
201+ {
202+ this . Marker = ( byte ) b ;
203+ this . badData = true ;
204+ this . MarkerPosition = this . stream . Position - 2 ;
205+ return true ;
206+ }
207+ }
208+ }
209+ }
210+
177211 [ MethodImpl ( InliningOptions . ShortMethod ) ]
178212 private int ReadStream ( )
179213 {
0 commit comments