private static bool jpeg_fill_bit_buffer(ref bitread_working_state state, int get_buffer, int bits_left, int nbits)
{
/* Attempt to load at least MIN_GET_BITS bits into get_buffer. */
/* (It is assumed that no request will be for more than that many bits.) */
/* We fail to do so only if we hit a marker or are forced to suspend. */
bool noMoreBytes = false;
if (state.cinfo.m_unread_marker == 0)
{
/* cannot advance past a marker */
while (bits_left < MIN_GET_BITS)
{
int c;
state.cinfo.m_src.GetByte(out c);
/* If it's 0xFF, check and discard stuffed zero byte */
if (c == 0xFF)
{
/* Loop here to discard any padding FF's on terminating marker,
* so that we can save a valid unread_marker value. NOTE: we will
* accept multiple FF's followed by a 0 as meaning a single FF data
* byte. This data pattern is not valid according to the standard.
*/
do
{
state.cinfo.m_src.GetByte(out c);
}
while (c == 0xFF);
if (c == 0)
{
/* Found FF/00, which represents an FF data byte */
c = 0xFF;
}
else
{
/* Oops, it's actually a marker indicating end of compressed data.
* Save the marker code for later use.
* Fine point: it might appear that we should save the marker into
* bitread working state, not straight into permanent state. But
* once we have hit a marker, we cannot need to suspend within the
* current MCU, because we will read no more bytes from the data
* source. So it is OK to update permanent state right away.
*/
state.cinfo.m_unread_marker = c;
/* See if we need to insert some fake zero bits. */
noMoreBytes = true;
break;
}
}
/* OK, load c into get_buffer */
get_buffer = (get_buffer << 8) | c;
bits_left += 8;
} /* end while */
}
else
noMoreBytes = true;
if (noMoreBytes)
{
/* We get here if we've read the marker that terminates the compressed
* data segment. There should be enough bits in the buffer register
* to satisfy the request; if so, no problem.
*/
if (nbits > bits_left)
{
/* Uh-oh. Report corrupted data to user and stuff zeroes into
* the data stream, so that we can produce some kind of image.
* We use a nonvolatile flag to ensure that only one warning message
* appears per data segment.
*/
huff_entropy_decoder entropy = (huff_entropy_decoder)state.cinfo.m_entropy;
if (!entropy.m_insufficient_data)
{
state.cinfo.WARNMS(J_MESSAGE_CODE.JWRN_HIT_MARKER);
entropy.m_insufficient_data = true;
}
/* Fill the buffer with zero bits */
get_buffer <<= MIN_GET_BITS - bits_left;
bits_left = MIN_GET_BITS;
}
}
/* Unload the local registers */
state.get_buffer = get_buffer;
state.bits_left = bits_left;
return true;
}