internal int Deflate(FlushType flush)
{
int old_flush;
if (_codec.OutputBuffer == null ||
(_codec.InputBuffer == null && _codec.AvailableBytesIn != 0) ||
(status == FINISH_STATE && flush != FlushType.Finish))
{
_codec.Message = _ErrorMessage[ZlibConstants.Z_NEED_DICT - (ZlibConstants.Z_STREAM_ERROR)];
throw new ZlibException(String.Format("Something is fishy. [{0}]", _codec.Message));
}
if (_codec.AvailableBytesOut == 0)
{
_codec.Message = _ErrorMessage[ZlibConstants.Z_NEED_DICT - (ZlibConstants.Z_BUF_ERROR)];
throw new ZlibException("OutputBuffer is full (AvailableBytesOut == 0)");
}
old_flush = last_flush;
last_flush = (int)flush;
// Write the zlib (rfc1950) header bytes
if (status == INIT_STATE)
{
int header = (Z_DEFLATED + ((w_bits - 8) << 4)) << 8;
int level_flags = (((int)compressionLevel - 1) & 0xff) >> 1;
if (level_flags > 3)
level_flags = 3;
header |= (level_flags << 6);
if (strstart != 0)
header |= PRESET_DICT;
header += 31 - (header % 31);
status = BUSY_STATE;
//putShortMSB(header);
unchecked
{
pending[pendingCount++] = (byte)(header >> 8);
pending[pendingCount++] = (byte)header;
}
// Save the adler32 of the preset dictionary:
if (strstart != 0)
{
pending[pendingCount++] = (byte)((_codec._Adler32 & 0xFF000000) >> 24);
pending[pendingCount++] = (byte)((_codec._Adler32 & 0x00FF0000) >> 16);
pending[pendingCount++] = (byte)((_codec._Adler32 & 0x0000FF00) >> 8);
pending[pendingCount++] = (byte)(_codec._Adler32 & 0x000000FF);
}
_codec._Adler32 = Adler.Adler32(0, null, 0, 0);
}
// Flush as much pending output as possible
if (pendingCount != 0)
{
_codec.flush_pending();
if (_codec.AvailableBytesOut == 0)
{
//System.out.println(" avail_out==0");
// Since avail_out is 0, deflate will be called again with
// more output space, but possibly with both pending and
// avail_in equal to zero. There won't be anything to do,
// but this is not an error situation so make sure we
// return OK instead of BUF_ERROR at next call of deflate:
last_flush = -1;
return ZlibConstants.Z_OK;
}
// Make sure there is something to do and avoid duplicate consecutive
// flushes. For repeated and useless calls with Z_FINISH, we keep
// returning Z_STREAM_END instead of Z_BUFF_ERROR.
}
else if (_codec.AvailableBytesIn == 0 &&
(int)flush <= old_flush &&
flush != FlushType.Finish)
{
// workitem 8557
//
// Not sure why this needs to be an error. pendingCount == 0, which
// means there's nothing to deflate. And the caller has not asked
// for a FlushType.Finish, but... that seems very non-fatal. We
// can just say "OK" and do nothing.
// _codec.Message = z_errmsg[ZlibConstants.Z_NEED_DICT - (ZlibConstants.Z_BUF_ERROR)];
// throw new ZlibException("AvailableBytesIn == 0 && flush<=old_flush && flush != FlushType.Finish");
return ZlibConstants.Z_OK;
}
// User must not provide more input after the first FINISH:
if (status == FINISH_STATE && _codec.AvailableBytesIn != 0)
{
_codec.Message = _ErrorMessage[ZlibConstants.Z_NEED_DICT - (ZlibConstants.Z_BUF_ERROR)];
throw new ZlibException("status == FINISH_STATE && _codec.AvailableBytesIn != 0");
}
// Start a new block or continue the current one.
if (_codec.AvailableBytesIn != 0 || lookahead != 0 || (flush != FlushType.None && status != FINISH_STATE))
{
BlockState bstate = DeflateFunction(flush);
if (bstate == BlockState.FinishStarted || bstate == BlockState.FinishDone)
{
status = FINISH_STATE;
}
if (bstate == BlockState.NeedMore || bstate == BlockState.FinishStarted)
{
if (_codec.AvailableBytesOut == 0)
{
last_flush = -1; // avoid BUF_ERROR next call, see above
}
return ZlibConstants.Z_OK;
// If flush != Z_NO_FLUSH && avail_out == 0, the next call
// of deflate should use the same flush parameter to make sure
// that the flush is complete. So we don't have to output an
// empty block here, this will be done at next call. This also
// ensures that for a very small output buffer, we emit at most
// one empty block.
}
if (bstate == BlockState.BlockDone)
{
if (flush == FlushType.Partial)
{
_tr_align();
}
else
{
// FlushType.Full or FlushType.Sync
_tr_stored_block(0, 0, false);
// For a full flush, this empty block will be recognized
// as a special marker by inflate_sync().
if (flush == FlushType.Full)
{
// clear hash (forget the history)
for (int i = 0; i < hash_size; i++)
head[i] = 0;
}
}
_codec.flush_pending();
if (_codec.AvailableBytesOut == 0)
{
last_flush = -1; // avoid BUF_ERROR at next call, see above
return ZlibConstants.Z_OK;
}
}
}
if (flush != FlushType.Finish)
return ZlibConstants.Z_OK;
if (!WantRfc1950HeaderBytes || Rfc1950BytesEmitted)
return ZlibConstants.Z_STREAM_END;
// Write the zlib trailer (adler32)
pending[pendingCount++] = (byte)((_codec._Adler32 & 0xFF000000) >> 24);
pending[pendingCount++] = (byte)((_codec._Adler32 & 0x00FF0000) >> 16);
pending[pendingCount++] = (byte)((_codec._Adler32 & 0x0000FF00) >> 8);
pending[pendingCount++] = (byte)(_codec._Adler32 & 0x000000FF);
//putShortMSB((int)(SharedUtils.URShift(_codec._Adler32, 16)));
//putShortMSB((int)(_codec._Adler32 & 0xffff));
_codec.flush_pending();
// If avail_out is zero, the application will call deflate again
// to flush the rest.
Rfc1950BytesEmitted = true; // write the trailer only once!
return pendingCount != 0 ? ZlibConstants.Z_OK : ZlibConstants.Z_STREAM_END;
}