/// <summary>
/// Performs data compression with the deflate algorithm
/// </summary>
internal int deflate(ZStream strm, FlushStrategy f)
{
int old_flush;
int internalFlush = (int)f;
if (internalFlush > (int)FlushStrategy.Z_FINISH || internalFlush < 0)
{
return (int)ZLibResultCode.Z_STREAM_ERROR;
}
if (strm.next_out == null || (strm.next_in == null && strm.avail_in != 0) || (status == DeflateState.FINISH_STATE && internalFlush != (int)FlushStrategy.Z_FINISH))
{
strm.msg = ZLibUtil.z_errmsg[(int)ZLibResultCode.Z_NEED_DICT - ((int)ZLibResultCode.Z_STREAM_ERROR)];
return (int)ZLibResultCode.Z_STREAM_ERROR;
}
if (strm.avail_out == 0)
{
strm.msg = ZLibUtil.z_errmsg[(int)ZLibResultCode.Z_NEED_DICT - ((int)ZLibResultCode.Z_BUF_ERROR)];
return (int)ZLibResultCode.Z_DATA_ERROR;
}
this.strm = strm; // just in case
old_flush = last_flush;
last_flush = internalFlush;
// Write the zlib header
if (status == DeflateState.INIT_STATE)
{
int header = (Z_DEFLATED + ((w_bits - 8) << 4)) << 8;
int level_flags = ((level - 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 = DeflateState.BUSY_STATE;
putShortMSB(header);
// Save the adler32 of the preset dictionary:
if (strstart != 0)
{
putShortMSB((int)(ZLibUtil.URShift(strm.adler, 16)));
putShortMSB((int)(strm.adler & 0xffff));
}
strm.adler = Adler32.GetAdler32Checksum(0, null, 0, 0);
}
// Flush as much pending output as possible
if (pending != 0)
{
strm.flush_pending();
if (strm.avail_out == 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 (int)ZLibResultCode.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 (int)ZLibResultCode.Z_STREAM_END instead of Z_BUFF_ERROR.
}
else if (strm.avail_in == 0 && internalFlush <= old_flush && internalFlush != (int)FlushStrategy.Z_FINISH)
{
strm.msg = ZLibUtil.z_errmsg[(int)ZLibResultCode.Z_NEED_DICT - ((int)ZLibResultCode.Z_BUF_ERROR)];
return (int)ZLibResultCode.Z_DATA_ERROR;
}
// User must not provide more input after the first FINISH:
if (status == DeflateState.FINISH_STATE && strm.avail_in != 0)
{
strm.msg = ZLibUtil.z_errmsg[(int)ZLibResultCode.Z_NEED_DICT - ((int)ZLibResultCode.Z_BUF_ERROR)];
return (int)ZLibResultCode.Z_DATA_ERROR;
}
// Start a new block or continue the current one.
if (strm.avail_in != 0 || lookahead != 0 || (internalFlush != (int)FlushStrategy.Z_NO_FLUSH && status != DeflateState.FINISH_STATE))
{
int bstate = - 1;
switch (config_table[level].func)
{
case STORED:
bstate = deflate_stored(internalFlush);
break;
case FAST:
bstate = deflate_fast(internalFlush);
break;
case SLOW:
bstate = deflate_slow(internalFlush);
break;
default:
break;
}
if (bstate == FinishStarted || bstate == FinishDone)
{
status = DeflateState.FINISH_STATE;
}
if (bstate == NeedMore || bstate == FinishStarted)
{
if (strm.avail_out == 0)
{
last_flush = -1; // avoid BUF_ERROR next call, see above
}
return (int)ZLibResultCode.Z_OK;
// If internalFlush != Z_NO_FLUSH && _avail_out == 0, the next call
// of deflate should use the same internalFlush parameter to make sure
// that the internalFlush 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 == BlockDone)
{
if (internalFlush == (int)FlushStrategy.Z_PARTIAL_FLUSH)
{
_tr_align();
}
else
{
// FULL_FLUSH or SYNC_FLUSH
_tr_stored_block(0, 0, false);
// For a full internalFlush, this empty block will be recognized
// as a special marker by inflate_sync().
if (internalFlush == (int)FlushStrategy.Z_FULL_FLUSH)
{
for (int i = 0; i < hash_size; i++)
// forget history
head[i] = 0;
}
}
strm.flush_pending();
if (strm.avail_out == 0)
{
last_flush = -1; // avoid BUF_ERROR at next call, see above
return (int)ZLibResultCode.Z_OK;
}
}
}
if (internalFlush != (int)FlushStrategy.Z_FINISH)
return (int)ZLibResultCode.Z_OK;
if (NoHeader != 0)
return (int)ZLibResultCode.Z_STREAM_END;
// Write the zlib trailer (adler32)
putShortMSB((int) (ZLibUtil.URShift(strm.adler, 16)));
putShortMSB((int) (strm.adler & 0xffff));
strm.flush_pending();
// If _avail_out is zero, the application will call deflate again
// to internalFlush the rest.
NoHeader = - 1; // WritePos the trailer only once!
return pending != 0 ? (int)ZLibResultCode.Z_OK : (int)ZLibResultCode.Z_STREAM_END;
}