#include "../game/q_shared.h"
#include "../qcommon/qcommon.h"

#include "zip.h"
#include "deflate.h"

#ifdef _TIMING
int		totalDeflateTime[Z_MAX_COMPRESSION + 1];
int		totalDeflateCount[Z_MAX_COMPRESSION + 1];
#endif

// If you use the zlib library in a product, an acknowledgment is welcome
// in the documentation of your product. If for some reason you cannot
// include such an acknowledgment, I would appreciate that you keep this
// copyright string in the executable of your product.
const char deflate_copyright[] = "Deflate 1.1.3 Copyright 1995-1998 Jean-loup Gailly ";

static const char *deflate_error = "OK";

//  ALGORITHM
// 
//  The "deflation" process depends on being able to identify portions
//  of the input text which are identical to earlier input (within a
//  sliding window trailing behind the input currently being processed).
// 
//  The most straightforward technique turns out to be the fastest for
//  most input files: try all possible matches and select the longest.
//  The key feature of this algorithm is that insertions into the string
//  dictionary are very simple and thus fast, and deletions are avoided
//  completely. Insertions are performed at each input character, whereas
//  string matches are performed only when the previous match ends. So it
//  is preferable to spend more time in matches to allow very fast string
//  insertions and avoid deletions. The matching algorithm for small
//  strings is inspired from that of Rabin & Karp. A brute force approach
//  is used to find longer strings when a small match has been found.
//  A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
//  (by Leonid Broukhis).
//
// ACKNOWLEDGEMENTS
//
//  The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
//  I found it in 'freeze' written by Leonid Broukhis.
//  Thanks to many people for bug reports and testing.
//
// REFERENCES
//
//  Deutsch, L.P.,"DEFLATE Compressed Data Format Specification".
//  Available in ftp://ds.internic.net/rfc/rfc1951.txt
//
//  A description of the Rabin and Karp algorithm is given in the book
//     "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
//
//  Fiala,E.R., and Greene,D.H.
//     Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595

// ===============================================================================
//  A word is an index in the character window. We use short instead of int to
//  save space in the various tables. ulong is used only for parameter passing.

//  The static literal tree. Since the bit lengths are imposed, there is no
//  need for the L_CODES extra codes used during heap construction. However
//  The codes 286 and 287 are needed to build a canonical tree (see _tr_init
//  below).
static const ct_data static_ltree[L_CODES + 2] = 
{
	{{  12 }, { 8 }}, {{ 140 }, { 8 }}, {{  76 }, { 8 }}, {{ 204 }, { 8 }}, {{  44 }, { 8 }},
	{{ 172 }, { 8 }}, {{ 108 }, { 8 }}, {{ 236 }, { 8 }}, {{  28 }, { 8 }}, {{ 156 }, { 8 }},
	{{  92 }, { 8 }}, {{ 220 }, { 8 }}, {{  60 }, { 8 }}, {{ 188 }, { 8 }}, {{ 124 }, { 8 }},
	{{ 252 }, { 8 }}, {{   2 }, { 8 }}, {{ 130 }, { 8 }}, {{  66 }, { 8 }}, {{ 194 }, { 8 }},
	{{  34 }, { 8 }}, {{ 162 }, { 8 }}, {{  98 }, { 8 }}, {{ 226 }, { 8 }}, {{  18 }, { 8 }},
	{{ 146 }, { 8 }}, {{  82 }, { 8 }}, {{ 210 }, { 8 }}, {{  50 }, { 8 }}, {{ 178 }, { 8 }},
	{{ 114 }, { 8 }}, {{ 242 }, { 8 }}, {{  10 }, { 8 }}, {{ 138 }, { 8 }}, {{  74 }, { 8 }},
	{{ 202 }, { 8 }}, {{  42 }, { 8 }}, {{ 170 }, { 8 }}, {{ 106 }, { 8 }}, {{ 234 }, { 8 }},
	{{  26 }, { 8 }}, {{ 154 }, { 8 }}, {{  90 }, { 8 }}, {{ 218 }, { 8 }}, {{  58 }, { 8 }},
	{{ 186 }, { 8 }}, {{ 122 }, { 8 }}, {{ 250 }, { 8 }}, {{   6 }, { 8 }}, {{ 134 }, { 8 }},
	{{  70 }, { 8 }}, {{ 198 }, { 8 }}, {{  38 }, { 8 }}, {{ 166 }, { 8 }}, {{ 102 }, { 8 }},
	{{ 230 }, { 8 }}, {{  22 }, { 8 }}, {{ 150 }, { 8 }}, {{  86 }, { 8 }}, {{ 214 }, { 8 }},
	{{  54 }, { 8 }}, {{ 182 }, { 8 }}, {{ 118 }, { 8 }}, {{ 246 }, { 8 }}, {{  14 }, { 8 }},
	{{ 142 }, { 8 }}, {{  78 }, { 8 }}, {{ 206 }, { 8 }}, {{  46 }, { 8 }}, {{ 174 }, { 8 }},
	{{ 110 }, { 8 }}, {{ 238 }, { 8 }}, {{  30 }, { 8 }}, {{ 158 }, { 8 }}, {{  94 }, { 8 }},
	{{ 222 }, { 8 }}, {{  62 }, { 8 }}, {{ 190 }, { 8 }}, {{ 126 }, { 8 }}, {{ 254 }, { 8 }},
	{{   1 }, { 8 }}, {{ 129 }, { 8 }}, {{  65 }, { 8 }}, {{ 193 }, { 8 }}, {{  33 }, { 8 }},
	{{ 161 }, { 8 }}, {{  97 }, { 8 }}, {{ 225 }, { 8 }}, {{  17 }, { 8 }}, {{ 145 }, { 8 }},
	{{  81 }, { 8 }}, {{ 209 }, { 8 }}, {{  49 }, { 8 }}, {{ 177 }, { 8 }}, {{ 113 }, { 8 }},
	{{ 241 }, { 8 }}, {{   9 }, { 8 }}, {{ 137 }, { 8 }}, {{  73 }, { 8 }}, {{ 201 }, { 8 }},
	{{  41 }, { 8 }}, {{ 169 }, { 8 }}, {{ 105 }, { 8 }}, {{ 233 }, { 8 }}, {{  25 }, { 8 }},
	{{ 153 }, { 8 }}, {{  89 }, { 8 }}, {{ 217 }, { 8 }}, {{  57 }, { 8 }}, {{ 185 }, { 8 }},
	{{ 121 }, { 8 }}, {{ 249 }, { 8 }}, {{   5 }, { 8 }}, {{ 133 }, { 8 }}, {{  69 }, { 8 }},
	{{ 197 }, { 8 }}, {{  37 }, { 8 }}, {{ 165 }, { 8 }}, {{ 101 }, { 8 }}, {{ 229 }, { 8 }},
	{{  21 }, { 8 }}, {{ 149 }, { 8 }}, {{  85 }, { 8 }}, {{ 213 }, { 8 }}, {{  53 }, { 8 }},
	{{ 181 }, { 8 }}, {{ 117 }, { 8 }}, {{ 245 }, { 8 }}, {{  13 }, { 8 }}, {{ 141 }, { 8 }},
	{{  77 }, { 8 }}, {{ 205 }, { 8 }}, {{  45 }, { 8 }}, {{ 173 }, { 8 }}, {{ 109 }, { 8 }},
	{{ 237 }, { 8 }}, {{  29 }, { 8 }}, {{ 157 }, { 8 }}, {{  93 }, { 8 }}, {{ 221 }, { 8 }},
	{{  61 }, { 8 }}, {{ 189 }, { 8 }}, {{ 125 }, { 8 }}, {{ 253 }, { 8 }}, {{  19 }, { 9 }},
	{{ 275 }, { 9 }}, {{ 147 }, { 9 }}, {{ 403 }, { 9 }}, {{  83 }, { 9 }}, {{ 339 }, { 9 }},
	{{ 211 }, { 9 }}, {{ 467 }, { 9 }}, {{  51 }, { 9 }}, {{ 307 }, { 9 }}, {{ 179 }, { 9 }},
	{{ 435 }, { 9 }}, {{ 115 }, { 9 }}, {{ 371 }, { 9 }}, {{ 243 }, { 9 }}, {{ 499 }, { 9 }},
	{{  11 }, { 9 }}, {{ 267 }, { 9 }}, {{ 139 }, { 9 }}, {{ 395 }, { 9 }}, {{  75 }, { 9 }},
	{{ 331 }, { 9 }}, {{ 203 }, { 9 }}, {{ 459 }, { 9 }}, {{  43 }, { 9 }}, {{ 299 }, { 9 }},
	{{ 171 }, { 9 }}, {{ 427 }, { 9 }}, {{ 107 }, { 9 }}, {{ 363 }, { 9 }}, {{ 235 }, { 9 }},
	{{ 491 }, { 9 }}, {{  27 }, { 9 }}, {{ 283 }, { 9 }}, {{ 155 }, { 9 }}, {{ 411 }, { 9 }},
	{{  91 }, { 9 }}, {{ 347 }, { 9 }}, {{ 219 }, { 9 }}, {{ 475 }, { 9 }}, {{  59 }, { 9 }},
	{{ 315 }, { 9 }}, {{ 187 }, { 9 }}, {{ 443 }, { 9 }}, {{ 123 }, { 9 }}, {{ 379 }, { 9 }},
	{{ 251 }, { 9 }}, {{ 507 }, { 9 }}, {{   7 }, { 9 }}, {{ 263 }, { 9 }}, {{ 135 }, { 9 }},
	{{ 391 }, { 9 }}, {{  71 }, { 9 }}, {{ 327 }, { 9 }}, {{ 199 }, { 9 }}, {{ 455 }, { 9 }},
	{{  39 }, { 9 }}, {{ 295 }, { 9 }}, {{ 167 }, { 9 }}, {{ 423 }, { 9 }}, {{ 103 }, { 9 }},
	{{ 359 }, { 9 }}, {{ 231 }, { 9 }}, {{ 487 }, { 9 }}, {{  23 }, { 9 }}, {{ 279 }, { 9 }},
	{{ 151 }, { 9 }}, {{ 407 }, { 9 }}, {{  87 }, { 9 }}, {{ 343 }, { 9 }}, {{ 215 }, { 9 }},
	{{ 471 }, { 9 }}, {{  55 }, { 9 }}, {{ 311 }, { 9 }}, {{ 183 }, { 9 }}, {{ 439 }, { 9 }},
	{{ 119 }, { 9 }}, {{ 375 }, { 9 }}, {{ 247 }, { 9 }}, {{ 503 }, { 9 }}, {{  15 }, { 9 }},
	{{ 271 }, { 9 }}, {{ 143 }, { 9 }}, {{ 399 }, { 9 }}, {{  79 }, { 9 }}, {{ 335 }, { 9 }},
	{{ 207 }, { 9 }}, {{ 463 }, { 9 }}, {{  47 }, { 9 }}, {{ 303 }, { 9 }}, {{ 175 }, { 9 }},
	{{ 431 }, { 9 }}, {{ 111 }, { 9 }}, {{ 367 }, { 9 }}, {{ 239 }, { 9 }}, {{ 495 }, { 9 }},
	{{  31 }, { 9 }}, {{ 287 }, { 9 }}, {{ 159 }, { 9 }}, {{ 415 }, { 9 }}, {{  95 }, { 9 }},
	{{ 351 }, { 9 }}, {{ 223 }, { 9 }}, {{ 479 }, { 9 }}, {{  63 }, { 9 }}, {{ 319 }, { 9 }},
	{{ 191 }, { 9 }}, {{ 447 }, { 9 }}, {{ 127 }, { 9 }}, {{ 383 }, { 9 }}, {{ 255 }, { 9 }},
	{{ 511 }, { 9 }}, {{   0 }, { 7 }}, {{  64 }, { 7 }}, {{  32 }, { 7 }}, {{  96 }, { 7 }},
	{{  16 }, { 7 }}, {{  80 }, { 7 }}, {{  48 }, { 7 }}, {{ 112 }, { 7 }}, {{   8 }, { 7 }},
	{{  72 }, { 7 }}, {{  40 }, { 7 }}, {{ 104 }, { 7 }}, {{  24 }, { 7 }}, {{  88 }, { 7 }},
	{{  56 }, { 7 }}, {{ 120 }, { 7 }}, {{   4 }, { 7 }}, {{  68 }, { 7 }}, {{  36 }, { 7 }},
	{{ 100 }, { 7 }}, {{  20 }, { 7 }}, {{  84 }, { 7 }}, {{  52 }, { 7 }}, {{ 116 }, { 7 }},
	{{   3 }, { 8 }}, {{ 131 }, { 8 }}, {{  67 }, { 8 }}, {{ 195 }, { 8 }}, {{  35 }, { 8 }},
	{{ 163 }, { 8 }}, {{  99 }, { 8 }}, {{ 227 }, { 8 }}	 	 	    	   	   		  
};

// The static distance tree. (Actually a trivial tree since all codes use 5 bits.)
static const ct_data static_dtree[D_CODES] = 
{
	{{  0 }, { 5 }}, {{ 16 }, { 5 }}, {{  8 },{ 5 }}, {{ 24 },{ 5 }}, {{  4 },{ 5 }},
	{{ 20 }, { 5 }}, {{ 12 }, { 5 }}, {{ 28 },{ 5 }}, {{  2 },{ 5 }}, {{ 18 },{ 5 }},
	{{ 10 }, { 5 }}, {{ 26 }, { 5 }}, {{  6 },{ 5 }}, {{ 22 },{ 5 }}, {{ 14 },{ 5 }},
	{{ 30 }, { 5 }}, {{  1 }, { 5 }}, {{ 17 },{ 5 }}, {{  9 },{ 5 }}, {{ 25 },{ 5 }},
	{{  5 }, { 5 }}, {{ 21 }, { 5 }}, {{ 13 },{ 5 }}, {{ 29 },{ 5 }}, {{  3 },{ 5 }},
	{{ 19 }, { 5 }}, {{ 11 }, { 5 }}, {{ 27 },{ 5 }}, {{  7 },{ 5 }}, {{ 23 },{ 5 }}
};

// Distance codes. The first 256 values correspond to the distances
// 3 .. 258, the last 256 values correspond to the top 8 bits of
// the 15 bit distances.
static const byte tr_dist_code[DIST_CODE_LEN] = 
{
	 0,  1,  2,  3,  4,  4,  5,  5,  6,  6,  6,  6,  7,  7,  7,  7,  8,  8,  8,  8,
	 8,  8,  8,  8,  9,  9,  9,  9,  9,  9,  9,  9, 10, 10, 10, 10, 10, 10, 10, 10,
	10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
	11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
	12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13,
	13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
	13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
	14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
	14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
	14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15,
	15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
	15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
	15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,  0,  0, 16, 17,
	18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22,
	23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
	24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
	26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
	26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27,
	27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
	27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
	28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
	28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
	28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
	29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
	29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
	29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29
};

// length code for each normalized match length (0 == MIN_MATCH)
static const byte tr_length_code[MAX_MATCH - MIN_MATCH + 1] = 
{
	 0,  1,  2,  3,  4,  5,  6,  7,  8,  8,  9,  9, 10, 10, 11, 11, 12, 12, 12, 12,
	13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16,
	17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19,
	19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
	21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22,
	22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,
	23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
	24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
	25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
	25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26,
	26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
	26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
	27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28
};

// First normalized length for each code (0 = MIN_MATCH)
static const int base_length[LENGTH_CODES] = 
{
	0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56,
	64, 80, 96, 112, 128, 160, 192, 224, 0
};

// First normalized distance for each code (0 = distance of 1)
static const int base_dist[D_CODES] = 
{
    0,     1,     2,     3,     4,     6,     8,    12,    16,    24,
   32,    48,    64,    96,   128,   192,   256,   384,   512,   768,
 1024,  1536,  2048,  3072,  4096,  6144,  8192, 12288, 16384, 24576
};

// Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
// For deflate_fast() (levels <= 3) good is ignored and lazy has a different
// meaning.
static block_state deflate_stored(deflate_state *s, EFlush flush);
static block_state deflate_fast(deflate_state *s, EFlush flush);
static block_state deflate_slow(deflate_state *s, EFlush flush);

// Values for max_lazy_match, good_match and max_chain_length, depending on
// the desired pack level (0..9). The values given below have been tuned to
// exclude worst case performance for pathological files. Better values may be
// found for specific files.
static const config configuration_table[10] = 
{
  // good lazy nice chain
	{ 0,    0,   0,    0, deflate_stored },		// store only

	{ 4,    4,   8,    4, deflate_fast },		// maximum speed, no lazy matches
	{ 4,    5,  16,    8, deflate_fast },
	{ 4,    6,  32,   32, deflate_fast },
		  
	{ 4,    4,  16,   16, deflate_slow },		// lazy matches
	{ 8,   16,  32,   32, deflate_slow },
	{ 8,   16, 128,  128, deflate_slow },
	{ 8,   32, 128,  256, deflate_slow },
	{ 32, 128, 258, 1024, deflate_slow },
	{ 32, 258, 258, 4096, deflate_slow }		// maximum compression
}; 

// extra bits for each length code
static ulong extra_lbits[LENGTH_CODES] = 
{
	0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0
};

// Extra bits for distance codes
const ulong extra_dbits[D_CODES] = 
{ 
	0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,	7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13
};

// extra bits for each bit length code
static ulong extra_blbits[BL_CODES] = 
{
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7
};

// The lengths of the bit length codes are sent in order of decreasing
// probability, to avoid transmitting the lengths for unused bit length codes.
static const byte bl_order[BL_CODES] = 
{
	16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
};

static static_tree_desc static_l_desc = 
{
	static_ltree, extra_lbits, LITERALS + 1, L_CODES, MAX_WBITS
};

static static_tree_desc static_d_desc = 
{
	static_dtree, extra_dbits, 0, D_CODES, MAX_WBITS
};

static static_tree_desc static_bl_desc = 
{
	NULL, extra_blbits, 0, BL_CODES, MAX_BL_BITS
};

// ===============================================================================
// Output bytes to the output stream. Inlined for speed
// ===============================================================================

inline void put_byte(deflate_state *s, const byte c)
{
	s->pending_buf[s->pending++] = c;
}

// Fixme: write as 1 short
inline void put_short(deflate_state *s, const word w)
{
	s->pending_buf[s->pending++] = (byte)(w & 0xff);
	s->pending_buf[s->pending++] = (byte)(w >> 8);
}

inline void put_shortMSB(deflate_state *s, const word w)
{
	s->pending_buf[s->pending++] = (byte)(w >> 8);
	s->pending_buf[s->pending++] = (byte)(w & 0xff);
}   

inline void put_longMSB(deflate_state *s, const ulong l)
{
    s->pending_buf[s->pending++] = (byte)(l >> 24);
    s->pending_buf[s->pending++] = (byte)(l >> 16);
    s->pending_buf[s->pending++] = (byte)(l >> 8);
    s->pending_buf[s->pending++] = (byte)(l & 0xff);
}   

// ===============================================================================
// Send a value on a given number of bits.
// IN assertion: length <= 16 and value fits in length bits.
// ===============================================================================

static void send_bits(deflate_state *s, const ulong val, const ulong len)
{
	assert(len <= 16);
	assert(val <= 65536);

	if(s->bi_valid > (BUF_SIZE - len)) 
	{
		s->bi_buf |= val << s->bi_valid;
		put_short(s, s->bi_buf);
		s->bi_buf = (word)(val >> (BUF_SIZE - s->bi_valid));
		s->bi_valid += len - BUF_SIZE;
	}
	else
	{
		s->bi_buf |= val << s->bi_valid;
		s->bi_valid += len;
	}
}

// ===============================================================================
// Initialize a new block.
// ===============================================================================

static void init_block(deflate_state *s)
{
    int		n;						// iterates over tree elements

    // Initialize the trees.
    for(n = 0; n < L_CODES;  n++) 
	{
		s->dyn_ltree[n].fc.freq = 0;
	}
    for(n = 0; n < D_CODES;  n++) 
	{
		s->dyn_dtree[n].fc.freq = 0;
	}
    for(n = 0; n < BL_CODES; n++) 
	{
		s->bl_tree[n].fc.freq = 0;
	}
    s->dyn_ltree[END_BLOCK].fc.freq = 1;
    s->opt_len = 0;
	s->static_len = 0;
    s->last_lit = 0;
	s->matches = 0;
}

// ===============================================================================
// Initialize the tree data structures for a new zlib stream.
// ===============================================================================

static void tr_init(deflate_state *s)
{
    s->l_desc.dyn_tree = s->dyn_ltree;
    s->l_desc.stat_desc = &static_l_desc;

    s->d_desc.dyn_tree = s->dyn_dtree;
    s->d_desc.stat_desc = &static_d_desc;

    s->bl_desc.dyn_tree = s->bl_tree;
    s->bl_desc.stat_desc = &static_bl_desc;

    s->bi_buf = 0;
    s->bi_valid = 0;
	// enough lookahead for inflate
    s->last_eob_len = 8; 

    // Initialize the first block of the first file:
    init_block(s);
}

// ===============================================================================
// Compares to subtrees, using the tree depth as tie breaker when
// the subtrees have equal frequency. This minimizes the worst case length.
// ===============================================================================

static bool smaller(ct_data *tree, ulong son, ulong daughter, byte *depth)
{
	if(tree[son].fc.freq < tree[daughter].fc.freq)
	{
		return(true);
	}
	if((tree[son].fc.freq == tree[daughter].fc.freq) && (depth[son] <= depth[daughter]))
	{
		return(true);
	}
	return(false);
}

// ===============================================================================
// Restore the heap property by moving down the tree starting at node k,
// exchanging a node with the smallest of its two sons if necessary, stopping
// when the heap property is re-established (each father smaller than its
// two sons).
// ===============================================================================

static void pqdownheap(deflate_state *s, ct_data *tree, ulong node)
{
    ulong	base; 
    ulong	sibling;				// left son of node

	base = s->heap[node];
	sibling = node << 1;

    while(sibling <= s->heap_len) 
	{
        // Set sibling to the smallest of the two children
        if((sibling < s->heap_len) && smaller(tree, s->heap[sibling + 1], s->heap[sibling], s->depth)) 
		{
            sibling++;
        }
        // Exit if base is smaller than both sons
        if(smaller(tree, base, s->heap[sibling], s->depth)) 
		{
			break;
		}
        // Exchange base with the smallest son
        s->heap[node] = s->heap[sibling];  
		node = sibling;

        // And continue down the tree, setting sibling to the left son of base
        sibling <<= 1;
    }
    s->heap[node] = base;
}

// ===============================================================================
// Compute the optimal bit lengths for a tree and update the total bit length
// for the current block.
// IN assertion: the fields freq and dad are set, heap[heap_max] and
//    above are the tree nodes sorted by increasing frequency.
// OUT assertions: the field len is set to the optimal bit length, the
//     array bl_count contains the frequencies for each bit length.
//     The length opt_len is updated; static_len is also updated if stree is
//     not null.
// ===============================================================================

static void gen_bitlen(deflate_state *s, tree_desc *desc)
{
    const ct_data	*stree;
    const ulong		*extra;
    ulong			base;
    ulong			max_length;
    ulong			heapIdx;		// heap index
    ulong			n, m;			// iterate over the tree elements
    ulong			bits;			// bit length
    ulong			xbits;			// extra bits
    word			freq;			// frequency
    ulong			overflow;		// number of elements with bit length too large

    stree = desc->stat_desc->static_tree;
    extra = desc->stat_desc->extra_bits;
    base = desc->stat_desc->extra_base;
    max_length = desc->stat_desc->max_length;
	overflow = 0;

    for(bits = 0; bits <= MAX_WBITS; bits++) 
	{
		s->bl_count[bits] = 0;
	}

    // In a first pass, compute the optimal bit lengths (which may
    // overflow in the case of the bit length tree).
	// root of the heap
    desc->dyn_tree[s->heap[s->heap_max]].dl.len = 0;

    for(heapIdx = s->heap_max + 1; heapIdx < HEAP_SIZE; heapIdx++) 
	{
        n = s->heap[heapIdx];
        bits = desc->dyn_tree[desc->dyn_tree[n].dl.dad].dl.len + 1;
        if(bits > max_length)
		{
			bits = max_length;
			overflow++;
		}
        // We overwrite tree[n].dl.dad which is no longer needed
        desc->dyn_tree[n].dl.len = (word)bits;

		// not a leaf node
        if(n > desc->max_code) 
		{
			continue; 
		}

        s->bl_count[bits]++;
        xbits = 0;
        if(n >= base) 
		{
			xbits = extra[n - base];
		}
        freq = desc->dyn_tree[n].fc.freq;
        s->opt_len += freq * (bits + xbits);
        if(stree) 
		{
			s->static_len += freq * (stree[n].dl.len + xbits);
		}
    }
    if(!overflow) 
	{
		return;
	}

    // Find the first bit length which could increase
    do 
	{
        bits = max_length - 1;
        while(!s->bl_count[bits]) 
		{
			bits--;
		}
		// move one leaf down the tree
        s->bl_count[bits]--;      
		// move one overflow item as its brother
        s->bl_count[bits + 1] += 2;
        // The brother of the overflow item also moves one step up,
        // but this does not affect bl_count[max_length]
        s->bl_count[max_length]--;
        overflow -= 2;
    } 
	while(overflow > 0);

    // Now recompute all bit lengths, scanning in increasing frequency.
    // heapIdx is still equal to HEAP_SIZE. (It is simpler to reconstruct all
    // lengths instead of fixing only the wrong ones. This idea is taken
    // from 'ar' written by Haruhiko Okumura.)
    for(bits = max_length; bits; bits--) 
	{
        n = s->bl_count[bits];
        while(n) 
		{
            m = s->heap[--heapIdx];
            if(m > desc->max_code) 
			{
				continue;
			}
            if(desc->dyn_tree[m].dl.len != bits) 
			{
                s->opt_len += (bits - desc->dyn_tree[m].dl.len) * desc->dyn_tree[m].fc.freq;
                desc->dyn_tree[m].dl.len = (word)bits;
            }
            n--;
        }
    }
}

// ===============================================================================
// Flush the bit buffer and align the output on a byte boundary
// ===============================================================================

static void bi_windup(deflate_state *s)
{
    if(s->bi_valid > 8) 
	{
        put_short(s, s->bi_buf);
    } 
	else if(s->bi_valid > 0) 
	{
        put_byte(s, (byte)s->bi_buf);
    }
    s->bi_buf = 0;
    s->bi_valid = 0;
}

// ===============================================================================
// Reverse the first len bits of a code, using straightforward code (a faster
// method would use a table)
// ===============================================================================

static ulong bi_reverse(ulong code, ulong len)
{
    ulong	res;

	assert(1 <= len);
	assert(len <= 15);

    res = 0;
    do 
	{
        res |= code & 1;
        code >>= 1;
		res <<= 1;
    } 
	while(--len > 0);

    return(res >> 1);
}

// ===============================================================================
// Generate the codes for a given tree and bit counts (which need not be optimal).
// IN assertion: the array bl_count contains the bit length statistics for
// the given tree and the field len is set for all tree elements.
// OUT assertion: the field code is set for all tree elements of non zero code length.
// ===============================================================================

static void gen_codes(ct_data *tree, ulong max_code, word *bl_count)
{
    word	next_code[MAX_WBITS + 1];	// next code value for each bit length
    word	code;						// running code value
    ulong	bits;						// bit index
    ulong	codes;						// code index
	ulong	len;

    // The distribution counts are first used to generate the code values
    // without bit reversal.
	code = 0;
    for(bits = 1; bits <= MAX_WBITS; bits++) 
	{
		code = (word)((code + bl_count[bits - 1]) << 1);
        next_code[bits] = code;
    }

    // Check that the bit counts in bl_count are consistent. The last code
    // must be all ones.
    for(codes = 0; codes <= max_code; codes++) 
	{
        len = tree[codes].dl.len;

        if(!len) 
		{
			continue;
		}
        // Now reverse the bits
        tree[codes].fc.code = (word)bi_reverse(next_code[len]++, len);
    }
}

// ===============================================================================
// Construct one Huffman tree and assigns the code bit strings and lengths.
// Update the total bit length for the current block.
// IN assertion: the field freq is set for all tree elements.
// OUT assertions: the fields len and code are set to the optimal bit length
//     and corresponding code. The length opt_len is updated; static_len is
//     also updated if stree is not null. The field max_code is set.
// ===============================================================================

static void build_tree(deflate_state *s, tree_desc *desc)
{
    ct_data			*tree;
    const ct_data	*stree;
    ulong			elems;
    ulong			n, m;	 		// iterate over heap elements
    ulong			max_code;		// largest code with non zero frequency
    ulong			node;			// new node being created

    tree = desc->dyn_tree;
    stree = desc->stat_desc->static_tree;
    elems = desc->stat_desc->elems;
	max_code = 0;

    // Construct the initial heap, with least frequent element in
    // heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
    // heap[0] is not used.
    s->heap_len = 0;
	s->heap_max = HEAP_SIZE;

    for(n = 0; n < elems; n++) 
	{
        if(tree[n].fc.freq) 
		{
			max_code = n;
            s->heap[++s->heap_len] = n;
            s->depth[n] = 0;
        } 
		else 
		{
            tree[n].dl.len = 0;
        }
    }

    // The pkzip format requires that at least one distance code exists,
    // and that at least one bit should be sent even if there is only one
    // possible code. So to avoid special checks later on we force at least
    // two codes of non zero frequency.
    while(s->heap_len < 2) 
	{
		s->heap[++s->heap_len] = (max_code < 2 ? ++max_code : 0);
        node = s->heap[s->heap_len];
        tree[node].fc.freq = 1;
        s->depth[node] = 0;
        s->opt_len--; 
		if(stree) 
		{
			s->static_len -= stree[node].dl.len;
		}
        // node is 0 or 1 so it does not have extra bits
    }
    desc->max_code = max_code;

    // The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
    // establish sub-heaps of increasing lengths:
    for(n = s->heap_len >> 1; n >= 1; n--) 
	{
		pqdownheap(s, tree, n);
	}

    // Construct the Huffman tree by repeatedly combining the least two
    // frequent nodes.

	// next internal node of the tree
    node = elems;              
    do 
	{
	    n = s->heap[SMALLEST];
		s->heap[SMALLEST] = s->heap[s->heap_len--];
		pqdownheap(s, tree, SMALLEST);
        m = s->heap[SMALLEST];						// m = node of next least frequency

        s->heap[--s->heap_max] = n;					// keep the nodes sorted by frequency
        s->heap[--s->heap_max] = m;

        // Create a new node father of n and m
        tree[node].fc.freq = (word)(tree[n].fc.freq + tree[m].fc.freq);
		if(s->depth[n] > s->depth[m])
		{
			s->depth[node] = s->depth[n];
		}
		else
		{
			s->depth[node] = s->depth[m];
			s->depth[node]++;
		}
		tree[m].dl.dad = (word)node;
        tree[n].dl.dad = (word)node;

        // and insert the new node in the heap
        s->heap[SMALLEST] = node++;
        pqdownheap(s, tree, SMALLEST);
    } 
	while(s->heap_len >= 2);

    s->heap[--s->heap_max] = s->heap[SMALLEST];

    // At this point, the fields freq and dad are set. We can now
    // generate the bit lengths.
    gen_bitlen(s, desc);

    // The field len is now set, we can generate the bit codes
    gen_codes (tree, max_code, s->bl_count);
}

// ===============================================================================
// Scan a literal or distance tree to determine the frequencies of the codes
// in the bit length tree.
// ===============================================================================

static void scan_tree (deflate_state *s, ct_data *tree, ulong max_code)
{
    ulong 	n;						// iterates over all tree elements
    ulong	prevlen;				// last emitted length
    ulong	curlen;					// length of current code
    ulong	nextlen;				// length of next code
    ulong	count;					// repeat count of the current code
    ulong	max_count;				// max repeat count
    ulong	min_count;				// min repeat count

    prevlen = 0xffff;
    nextlen = tree[0].dl.len;
    count = 0;
    max_count = 7;
    min_count = 4;

    if(!nextlen) 
	{
		max_count = 138;
		min_count = 3;
	}
	// guard
    tree[max_code + 1].dl.len = (word)prevlen; 

    for(n = 0; n <= max_code; n++) 
	{
        curlen = nextlen; 
		nextlen = tree[n + 1].dl.len;
        if((++count < max_count) && (curlen == nextlen)) 
		{
            continue;
        }
		else if(count < min_count) 
		{
            s->bl_tree[curlen].fc.freq += (word)count;
        } 
		else if(curlen) 
		{
            if(curlen != prevlen) 
			{
				s->bl_tree[curlen].fc.freq++;
			}
            s->bl_tree[REP_3_6].fc.freq++;
        } 
		else if(count <= 10) 
		{
            s->bl_tree[REPZ_3_10].fc.freq++;
        } 
		else 
		{
            s->bl_tree[REPZ_11_138].fc.freq++;
        }
        count = 0; 
		prevlen = curlen;
        if(!nextlen) 
		{
            max_count = 138;
			min_count = 3;
        } 
		else if(curlen == nextlen) 
		{
            max_count = 6;
			min_count = 3;
        } 
		else 
		{
            max_count = 7;
			min_count = 4;
        }
    }
}

// ===============================================================================
// Send a literal or distance tree in compressed form, using the codes in bl_tree.
// ===============================================================================

static void send_tree(deflate_state *s, ct_data *tree, ulong max_code)
{
    ulong	n;						// iterates over all tree elements
    ulong	prevlen;				// last emitted length
    ulong	curlen;					// length of current code
    ulong	nextlen;				// length of next code
    ulong	count;					// repeat count of the current code
    ulong	max_count;				// max repeat count
    ulong	min_count;				// min repeat count

    prevlen = 0xffff;
    nextlen = tree[0].dl.len;
    count = 0;
    max_count = 7;
    min_count = 4;

    if(!nextlen)
	{
		max_count = 138;
		min_count = 3;
	}

    for(n = 0; n <= max_code; n++) 
	{
        curlen = nextlen; 
		nextlen = tree[n + 1].dl.len;
        if((++count < max_count) && (curlen == nextlen))
		{
            continue;
        } 
		else if(count < min_count) 
		{
            do 
			{ 
				send_bits(s, s->bl_tree[curlen].fc.code, s->bl_tree[curlen].dl.len);
			} 
			while(--count);

        } 
		else if(curlen) 
		{
            if(curlen != prevlen) 
			{
				send_bits(s, s->bl_tree[curlen].fc.code, s->bl_tree[curlen].dl.len);
				count--;
            }
			send_bits(s, s->bl_tree[REP_3_6].fc.code, s->bl_tree[REP_3_6].dl.len);
			send_bits(s, count - 3, 2);

        } 
		else if(count <= 10) 
		{
			send_bits(s, s->bl_tree[REPZ_3_10].fc.code, s->bl_tree[REPZ_3_10].dl.len);
			send_bits(s, count - 3, 3);

        } 
		else 
		{
			send_bits(s, s->bl_tree[REPZ_11_138].fc.code, s->bl_tree[REPZ_11_138].dl.len);
			send_bits(s, count - 11, 7);
        }
        count = 0; 
		prevlen = curlen;
        if(!nextlen) 
		{
            max_count = 138;
			min_count = 3;
        } 
		else if(curlen == nextlen) 
		{
            max_count = 6;
			min_count = 3;
        } 
		else 
		{
            max_count = 7;
			min_count = 4;
        }
    }
}

// ===============================================================================
// Construct the Huffman tree for the bit lengths and return the index in
// bl_order of the last bit length code to send.
// ===============================================================================

static ulong build_bl_tree(deflate_state *s)
{
    ulong	max_blindex;			// index of last bit length code of non zero freq

    // Determine the bit length frequencies for literal and distance trees
    scan_tree(s, s->dyn_ltree, s->l_desc.max_code);
    scan_tree(s, s->dyn_dtree, s->d_desc.max_code);

    // Build the bit length tree
    build_tree(s, &s->bl_desc);
    // opt_len now includes the length of the tree representations, except
    // the lengths of the bit lengths codes and the 5+5+4 bits for the counts.

    // Determine the number of bit length codes to send. The pkzip format
    // requires that at least 4 bit length codes be sent. (appnote.txt says
    // 3 but the actual value used is 4.)
    for(max_blindex = BL_CODES - 1; max_blindex >= 3; max_blindex--) 
	{
        if(s->bl_tree[bl_order[max_blindex]].dl.len)
		{
			break;
		}
    }
    // Update opt_len to include the bit length tree and counts
    s->opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4;
    return(max_blindex);
}

// ===========================================================================
// Send the header for a block using dynamic Huffman trees: the counts, the
// lengths of the bit length codes, the literal tree and the distance tree.
// IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
// ===========================================================================

static void send_all_trees(deflate_state *s, ulong lcodes, ulong dcodes, ulong blcodes)
{
    ulong	rank;				// index in bl_order

	// not +255 as stated in appnote.txt
    send_bits(s, lcodes - 257, 5); 
    send_bits(s, dcodes - 1, 5);
	// not -3 as stated in appnote.txt
    send_bits(s, blcodes - 4, 4); 

    for(rank = 0; rank < blcodes; rank++) 
	{
        send_bits(s, s->bl_tree[bl_order[rank]].dl.len, 3);
    }

	// literal tree
    send_tree(s, (ct_data *)s->dyn_ltree, lcodes - 1); 
	// distance tree
    send_tree(s, (ct_data *)s->dyn_dtree, dcodes - 1); 
}

// ===========================================================================
// Send the block data compressed using the given Huffman trees
// ===========================================================================

static void compress_block(deflate_state *s, const ct_data *ltree, const ct_data *dtree)
{
    ulong	dist;					// distance of matched string
    ulong	lenCount;				// match length or unmatched char (if dist == 0)
    ulong	lenIdx;					// running index in l_buf
    ulong	code;					// the code to send
    ulong	extra;					// number of extra bits to send

	lenIdx = 0;
    if(s->last_lit) 
	{
		do 
		{
			dist = s->d_buf[lenIdx];
			lenCount = s->l_buf[lenIdx++];
			if(!dist) 
			{
				// send a literal byte
				send_bits(s, ltree[lenCount].fc.code, ltree[lenCount].dl.len);
			} 
			else 
			{
				// Here, lenCount is the match length - MIN_MATCH
				code = tr_length_code[lenCount];
				// send the length code
				send_bits(s, ltree[code + LITERALS + 1].fc.code, ltree[code + LITERALS + 1].dl.len);
				extra = extra_lbits[code];
				if(extra) 
				{
					lenCount -= base_length[code];
					// send the extra length bits
					send_bits(s, lenCount, extra);       
				}
				// dist is now the match distance - 1
				dist--; 
				code = (dist < 256 ? tr_dist_code[dist] : tr_dist_code[256 + (dist >> 7)]);

				// send the distance code
				send_bits(s, dtree[code].fc.code, dtree[code].dl.len);
				extra = extra_dbits[code];
				if(extra) 
				{
					dist -= base_dist[code];
					// send the extra distance bits
					send_bits(s, dist, extra);   
				}
			}
		} 
		while(lenIdx < s->last_lit);
	}

	send_bits(s, ltree[END_BLOCK].fc.code, ltree[END_BLOCK].dl.len);
    s->last_eob_len = ltree[END_BLOCK].dl.len;
}

// ===========================================================================
// Send a stored block
// ===========================================================================

static void tr_stored_block(deflate_state *s, const byte *buf, ulong stored_len, bool eof)
{
	// send block type
    send_bits(s, (STORED_BLOCK << 1) + (ulong)eof, 3);

	// align on byte boundary
    bi_windup(s);        
	// enough lookahead for inflate
    s->last_eob_len = 8; 

	put_short(s, (word)stored_len);   
	put_short(s, (word)~stored_len);

    while(stored_len--)
	{
        put_byte(s, *buf++);
    }
}

// ===========================================================================
// Determine the best encoding for the current block: dynamic trees, static
// trees or store, and output the encoded block to the zip file.
// ===========================================================================

static void tr_flush_block(deflate_state *s, const byte *buf, ulong stored_len, bool eof)
{
    ulong	opt_lenb;
    ulong	static_lenb;
    ulong	max_blindex;			// index of last bit length code of non zero freq

    max_blindex = 0;

    // Build the Huffman trees unless a stored block is forced
    if(s->level > 0) 
	{
		// Construct the literal and distance trees
		build_tree(s, &s->l_desc);
		build_tree(s, &s->d_desc);
		// At this point, opt_len and static_len are the total bit lengths of
		// the compressed block data, excluding the tree representations.

		// Build the bit length tree for the above two trees, and get the index
		// in bl_order of the last bit length code to send.
		max_blindex = build_bl_tree(s);

		// Determine the best encoding. Compute first the block length in bytes
		opt_lenb = (s->opt_len + 3 + 7) >> 3;
		static_lenb = (s->static_len + 3 + 7) >> 3;

		if(static_lenb <= opt_lenb) 
		{
			opt_lenb = static_lenb;
		}
    } 
	else 
	{
		static_lenb = stored_len + 5;
		// force a stored block
		opt_lenb = static_lenb;		
    }

    if(stored_len + 4 <= opt_lenb && buf) 
	{
		// 4: two words for the lengths
        // The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
        // Otherwise we can't have processed more than WSIZE input bytes since
        // the last block flush, because compression would have been
        // successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
        // transform a block into a stored block.
        tr_stored_block(s, buf, stored_len, eof);

    } 
	else if(static_lenb == opt_lenb) 
	{
        send_bits(s, (STATIC_TREES << 1) + (ulong)eof, 3);
        compress_block(s, static_ltree, static_dtree);
    } 
	else 
	{
        send_bits(s, (DYN_TREES << 1) + (ulong)eof, 3);
        send_all_trees(s, s->l_desc.max_code + 1, s->d_desc.max_code + 1, max_blindex + 1);
        compress_block(s, s->dyn_ltree, s->dyn_dtree);
    }

    // The above check is made mod 2^32, for files larger than 512 MB
    // and uLong implemented on 32 bits.
    init_block(s);

    if(eof) 
	{
        bi_windup(s);
    }
}

// ===============================================================================
// ===============================================================================

inline bool tr_tally_lit(deflate_state *s, byte c)
{
	s->d_buf[s->last_lit] = 0;
	s->l_buf[s->last_lit++] = c;
	s->dyn_ltree[c].fc.freq++;

	return(s->last_lit == LIT_BUFSIZE - 1);
}

// ===============================================================================
// ===============================================================================

inline bool tr_tally_dist(deflate_state *s, ulong dist, ulong len)
{ 
	assert(dist < 65536);
	assert(len < 256);

	dist &= 0xffff;
	len &= 0xff;

    s->d_buf[s->last_lit] = (word)dist;
    s->l_buf[s->last_lit++] = (byte)len;
    dist--;
    s->dyn_ltree[tr_length_code[len] + LITERALS + 1].fc.freq++;
    s->dyn_dtree[(dist < 256 ? tr_dist_code[dist] : tr_dist_code[256 + (dist >> 7)])].fc.freq++;

    return(s->last_lit == LIT_BUFSIZE - 1);
}

// ===============================================================================
// Insert string str in the dictionary and set match_head to the previous head
// of the hash chain (the most recent string with same hash key). Return
// the previous length of the hash chain.
// If this file is compiled with -DFASTEST, the compression level is forced
// to 1, and no hash chains are maintained.
// IN  assertion: all calls to to INSERT_STRING are made with consecutive
//    input characters and the first MIN_MATCH bytes of str are valid
//    (except for the last MIN_MATCH-1 bytes of the input file).
// ===============================================================================

inline void insert_string(deflate_state *s, ulong str, ulong &match_head)
{
	s->ins_h = ((s->ins_h << HASH_SHIFT) ^ s->window[str + (MIN_MATCH - 1)]) & HASH_MASK;
	match_head = s->head[s->ins_h];
    s->prev[str & WINDOW_MASK] = s->head[s->ins_h]; 
    s->head[s->ins_h] = (word)str;
}

// ===========================================================================
// Initialize the "longest match" routines for a new zlib stream
// ===========================================================================

static void lm_init(deflate_state *s)
{
    s->head[HASH_SIZE - 1] = NULL;
    memset(s->head, 0, (HASH_SIZE - 1) * sizeof(*s->head));

    // Set the default configuration parameters:
    s->max_lazy_match = configuration_table[s->level].max_lazy;
    s->good_match = configuration_table[s->level].good_length;
    s->nice_match = configuration_table[s->level].nice_length;
    s->max_chain_length = configuration_table[s->level].max_chain;

    s->strstart = 0;
    s->block_start = 0;
    s->lookahead = 0;
	s->prev_length = MIN_MATCH - 1;
    s->match_length = MIN_MATCH - 1;
    s->match_available = 0;
    s->ins_h = 0;
}

// ===========================================================================
// Set match_start to the longest match starting at the given string and
// return its length. Matches shorter or equal to prev_length are discarded,
// in which case the result is equal to prev_length and match_start is
// garbage.
// IN assertions: cur_match is the head of the hash chain for the current
//  string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
// OUT assertion: the match length is not greater than s->lookahead.
// ===========================================================================

inline byte *qcmp(byte *scan, byte *match, ulong count)
{
	byte	*retval;
	_asm
	{
		push	esi
		push	edi
		push	ecx

		mov		esi, [scan]
		mov		edi, [match]
		mov		ecx, [count]
		repe	cmpsb

		pop		ecx
		pop		edi
		mov		[retval], esi
		pop		esi
	}
	return(--retval);
}

static ulong longest_match(deflate_state *s, ulong cur_match)
{
	ulong	chain_length;			// max hash chain length
	ulong	limit;
	byte	*scan;					// current string
	byte	*match;					// matched string
	ulong	len;					// length of current match
	ulong	best_len;				// best match length so far
	ulong	nice_match;				// stop if match long enough
    byte	scan_end1;
    byte	scan_end;

	chain_length = s->max_chain_length;
	scan = s->window + s->strstart;
	best_len = s->prev_length;
	nice_match = s->nice_match;

    // Stop when cur_match becomes <= limit. To simplify the code,
    // we prevent matches with the string of window index 0.
	limit = s->strstart > (WINDOW_SIZE - MIN_LOOKAHEAD) ? s->strstart - (WINDOW_SIZE - MIN_LOOKAHEAD) : NULL;

    scan_end1 = scan[best_len - 1];
    scan_end = scan[best_len];

    // Do not waste too much time if we already have a good match:
    if(s->prev_length >= s->good_match) 
	{
        chain_length >>= 2;
    }
    // Do not look for matches beyond the end of the input. This is necessary
    // to make deflate deterministic.
    if(nice_match > s->lookahead) 
	{
		nice_match = s->lookahead;
	}
    do 
	{
        match = s->window + cur_match;

        // Skip to next match if the match length cannot increase
        // or if the match length is less than 2:
        if((match[best_len] != scan_end) || (match[best_len - 1] != scan_end1) || (match[0] != scan[0]) || (match[1] != scan[1]))
		{
			continue;
		}

        // The check at best_len-1 can be removed because it will be made
        // again later. (This heuristic is not always a win.)
        // It is not necessary to compare scan[2] and match[2] since they
        // are always equal when the other bytes match, given that
        // the hash keys are equal
		scan = qcmp(scan + 3, match + 3, MAX_MATCH - 2);

        len = scan - (s->window + s->strstart);
        scan = s->window + s->strstart;

        if(len > best_len) 
		{
            s->match_start = cur_match;
            best_len = len;
            if(len >= nice_match) 
			{
				break;
			}
            scan_end1 = scan[best_len - 1];
            scan_end = scan[best_len];
        }
    } while((cur_match = s->prev[cur_match & WINDOW_MASK]) > limit && --chain_length);

    if(best_len <= s->lookahead) 
	{
		return(best_len);
	}
    return(s->lookahead);
}

// ===========================================================================
// Flush as much pending output as possible. All deflate() output goes
// through this function so some applications may wish to modify it
// to avoid allocating a large z->next_out buffer and copying into it.
// (See also read_buf()).
// ===========================================================================

static void flush_pending(z_stream *z)
{
    ulong	len = z->dstate->pending;

    if(len > z->avail_out) 
	{
		len = z->avail_out;
	}
    if(!len) 
	{
		return;
	}
	assert(len <= MAX_BLOCK_SIZE + 5);
	assert(z->dstate->pending_out + len <= z->dstate->pending_buf + MAX_BLOCK_SIZE + 5);

    memcpy(z->next_out, z->dstate->pending_out, len);
    z->next_out += len;
	z->total_out += len;
    z->dstate->pending_out += len;
    z->avail_out -= len;
    z->dstate->pending -= len;
    if(!z->dstate->pending) 
	{
        z->dstate->pending_out = z->dstate->pending_buf;
    }
}

// ===========================================================================
// Read a new buffer from the current input stream, update the adler32
// and total number of bytes read.  All deflate() input goes through
// this function so some applications may wish to modify it to avoid
// allocating a large z->next_in buffer and copying from it.
// (See also flush_pending()).
// ===========================================================================

static ulong read_buf(z_stream *z, byte *buf, ulong size)
{
    ulong	len;

    len = z->avail_in;
    if(len > size)
	{
		len = size;
	}
    if(!len) 
	{
		return(0);
	}
    z->avail_in -= len;

	if(!z->dstate->noheader)
	{
        z->dstate->adler = adler32(z->dstate->adler, z->next_in, len);
	}
    memcpy(buf, z->next_in, len);
    z->next_in += len;
    return(len);
}

// ===========================================================================
// Fill the window when the lookahead becomes insufficient.
// Updates strstart and lookahead.
//
// IN assertion: lookahead < MIN_LOOKAHEAD
// OUT assertions: strstart <= BIG_WINDOW_SIZE - MIN_LOOKAHEAD
//    At least one byte has been read, or avail_in == 0; reads are
//    performed for at least two bytes (required for the zip translate_eol
//    option -- not supported here).
// ===========================================================================

static void fill_window(deflate_state *s)
{
	ulong		n, m;
	word		*p;
    ulong		more;				// Amount of free space at the end of the window.

    do 
	{
        more = BIG_WINDOW_SIZE - s->lookahead - s->strstart;

		if(s->strstart >= WINDOW_SIZE + (WINDOW_SIZE - MIN_LOOKAHEAD)) 
		{
            memcpy(s->window, s->window + WINDOW_SIZE, WINDOW_SIZE);
            s->match_start -= WINDOW_SIZE;
			// Make strstart >= MAX_DIST
            s->strstart -= WINDOW_SIZE;					
            s->block_start -= WINDOW_SIZE;

			// Slide the hash table (could be avoided with 32 bit values
            // at the expense of memory usage). We slide even when level == 0
            // to keep the hash table consistent if we switch back to level > 0
            // later. (Using level 0 permanently is not an optimal usage of
            // zlib, so we don't care about this pathological case.)
			n = HASH_SIZE;
			p = &s->head[n];
			do
			{
				m = *--p;
				*p = (word)(m >= WINDOW_SIZE ? m - WINDOW_SIZE : 0);
			}
			while(--n);

			n = WINDOW_SIZE;
			p = &s->prev[n];
			do
			{
				m = *--p;
				*p = (word)(m >= WINDOW_SIZE ? m - WINDOW_SIZE : 0);
				// If n is not on any hash chain, prev[n] is garbage but
				// its value will never be used.
			}
			while(--n);

            more += WINDOW_SIZE;
        }
		if(!s->z->avail_in)
		{
			return;
		}

        // If there was no sliding:
        //    strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
        //    more == BIG_WINDOW_SIZE - lookahead - strstart
        // => more >= BIG_WINDOW_SIZE - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
        // => more >= BIG_WINDOW_SIZE- 2*WSIZE + 2
        // If there was sliding, more >= WSIZE. So in all cases, more >= 2.
        n = read_buf(s->z, s->window + s->strstart + s->lookahead, more);
        s->lookahead += n;

        // Initialize the hash value now that we have some input:
        if(s->lookahead >= MIN_MATCH) 
		{
			s->ins_h = ((s->window[s->strstart] << HASH_SHIFT) ^ s->window[s->strstart + 1]) & HASH_MASK;
        }
        // If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
        // but this is not important since only literal bytes will be emitted.
    } 
	while(s->lookahead < MIN_LOOKAHEAD && s->z->avail_in);
}

// ===========================================================================
// Flush the current block, with given end-of-file flag.
// IN assertion: strstart is set to the end of the current match.
// ===========================================================================

inline void flush_block_only(deflate_state *s, bool eof)
{
	if(s->block_start >= 0)
	{
		tr_flush_block(s, &s->window[s->block_start], s->strstart - s->block_start, eof);
	}
	else
	{
		tr_flush_block(s, 0, s->strstart - s->block_start, eof);
	}
   s->block_start = s->strstart;
   flush_pending(s->z);
}

// ===========================================================================
// Copy without compression as much as possible from the input stream, return
// the current block state.
// This function does not insert new strings in the dictionary since
// uncompressible data is probably not useful. This function is used
// only for the level=0 compression option.
// NOTE: this function should be optimized to avoid extra copying from
// window to pending_buf.
// ===========================================================================

static block_state deflate_stored(deflate_state *s, EFlush flush)
{
    // Stored blocks are limited to 0xffff bytes, pending_buf is limited
    // to pending_buf_size, and each stored block has a 5 byte header:
    ulong	max_start;

    // Copy as much as possible from input to output:
    while(true) 
	{
        // Fill the window as much as possible
        if(s->lookahead <= 1) 
		{
            fill_window(s);
            if(!s->lookahead && (flush == Z_NO_FLUSH))
			{
				return(NEED_MORE);
			}
            if(!s->lookahead) 
			{
				// flush the current block
				break;
			}
        }
		s->strstart += s->lookahead;
		s->lookahead = 0;

		// Emit a stored block if pending_buf will be full
		max_start = s->block_start + MAX_BLOCK_SIZE;
        if(!s->strstart || (s->strstart >= max_start))
		{
			// strstart == 0 is possible when wraparound on 16-bit machine
			s->lookahead = s->strstart - max_start;
			s->strstart = max_start;
			flush_block_only(s, false);
			if(!s->z->avail_out)
			{
				return(NEED_MORE);
			}
		}
		// Flush if we may have to slide, otherwise block_start may become
        // negative and the data will be gone:
		if(s->strstart - s->block_start >= WINDOW_SIZE - MIN_LOOKAHEAD) 
		{
			flush_block_only(s, false);
			if(!s->z->avail_out)
			{
				return(NEED_MORE);
			}
		}
    }
	flush_block_only(s, flush == Z_FINISH);
	if(!s->z->avail_out)
	{
		return((flush == Z_FINISH) ? FINISH_STARTED : NEED_MORE);
	}
    return(flush == Z_FINISH ? FINISH_DONE : BLOCK_DONE);
}

// ===========================================================================
// Compress as much as possible from the input stream, return the current block state.
// This function does not perform lazy evaluation of matches and inserts
// new strings in the dictionary only for unmatched strings or for short
// matches. It is used only for the fast compression options.
// ===========================================================================

static block_state deflate_fast(deflate_state *s, EFlush flush)
{
    ulong		hash_head;			// head of the hash chain
    bool		bflush;	 			// set if current block must be flushed

    hash_head = 0;
    while(true)
	{
        // Make sure that we always have enough lookahead, except
        // at the end of the input file. We need MAX_MATCH bytes
        // for the next match, plus MIN_MATCH bytes to insert the
        // string following the next match.
        if(s->lookahead < MIN_LOOKAHEAD) 
		{
            fill_window(s);
            if((s->lookahead < MIN_LOOKAHEAD) && (flush == Z_NO_FLUSH))
			{
		        return(NEED_MORE);
			}
            if(!s->lookahead) 
			{
				// flush the current block
				break; 
			}
        }

        // Insert the string window[strstart .. strstart+2] in the
        // dictionary, and set hash_head to the head of the hash chain:
        if(s->lookahead >= MIN_MATCH) 
		{
            insert_string(s, s->strstart, hash_head);
        }

        // Find the longest match, discarding those <= prev_length.
        // At this point we have always match_length < MIN_MATCH
        if(hash_head && (s->strstart - hash_head <= WINDOW_SIZE - MIN_LOOKAHEAD)) 
		{
            // To simplify the code, we prevent matches with the string
            // of window index 0 (in particular we have to avoid a match
            // of the string with itself at the start of the input file).
			s->match_length = longest_match(s, hash_head);
            // longest_match() sets match_start
        }
        if(s->match_length >= MIN_MATCH) 
		{
			s->z->quality++;

            bflush = tr_tally_dist(s, s->strstart - s->match_start, s->match_length - MIN_MATCH);
            s->lookahead -= s->match_length;

            // Insert new strings in the hash table only if the match length
            // is not too large. This saves time but degrades compression.
            if((s->match_length <= s->max_lazy_match) && (s->lookahead >= MIN_MATCH))
			{
				// string at strstart already in hash table
                s->match_length--; 
                do 
				{
                    // strstart never exceeds WSIZE-MAX_MATCH, so there are
                    // always MIN_MATCH bytes ahead.
                    s->strstart++;
                    insert_string(s, s->strstart, hash_head);
                } 
				while(--s->match_length);
                s->strstart++; 
            } 
			else
			{
				s->z->quality++;

                s->strstart += s->match_length;
                s->match_length = 0;
				s->ins_h = ((s->window[s->strstart] << HASH_SHIFT) ^ s->window[s->strstart + 1]) & HASH_MASK;
                // If lookahead < MIN_MATCH, ins_h is garbage, but it does not
                // matter since it will be recomputed at next deflate call.
            }
        } 
		else 
		{
            // No match, output a literal byte
            bflush = tr_tally_lit(s, s->window[s->strstart]);
            s->lookahead--;
            s->strstart++; 
        }
        if(bflush) 
		{
			flush_block_only(s, false);
			if(!s->z->avail_out)
			{
				return(NEED_MORE);
			}
		}
    }
	flush_block_only(s, flush == Z_FINISH);
	if(!s->z->avail_out)
	{
		return(flush == Z_FINISH ? FINISH_STARTED : NEED_MORE);
	}
    return(flush == Z_FINISH ? FINISH_DONE : BLOCK_DONE);
}

// ===========================================================================
// Same as above, but achieves better compression. We use a lazy
// evaluation for matches: a match is finally adopted only if there is
// no better match at the next window position.
// ===========================================================================

static block_state deflate_slow(deflate_state *s, EFlush flush)
{
    ulong		hash_head;			// head of hash chain
	ulong		max_insert;
    bool		bflush;				// set if current block must be flushed

    hash_head = 0;
    // Process the input block.
    while(true) 
	{
        // Make sure that we always have enough lookahead, except
        // at the end of the input file. We need MAX_MATCH bytes
        // for the next match, plus MIN_MATCH bytes to insert the
        // string following the next match.
        if(s->lookahead < MIN_LOOKAHEAD) 
		{
            fill_window(s);
            if((s->lookahead < MIN_LOOKAHEAD) && (flush == Z_NO_FLUSH))
			{
				return(NEED_MORE);
			}
            if(!s->lookahead) 
			{
				// flush the current block
				break; 
			}
        }

        // Insert the string window[strstart .. strstart+2] in the
        // dictionary, and set hash_head to the head of the hash chain:
        if(s->lookahead >= MIN_MATCH) 
		{
            insert_string(s, s->strstart, hash_head);
        }

        // Find the longest match, discarding those <= prev_length.
        s->prev_length = s->match_length;
		s->prev_match = s->match_start;
        s->match_length = MIN_MATCH - 1;

        if(hash_head && (s->prev_length < s->max_lazy_match) && (s->strstart - hash_head <= WINDOW_SIZE - MIN_LOOKAHEAD)) 
		{
            // To simplify the code, we prevent matches with the string
            // of window index 0 (in particular we have to avoid a match
            // of the string with itself at the start of the input file).
			// longest_match() sets match_start
			s->match_length = longest_match(s, hash_head);

            if((s->match_length <= 5) && ((s->match_length == MIN_MATCH) && (s->strstart - s->match_start > TOO_FAR))) 
			{
                // If prev_match is also MIN_MATCH, match_start is garbage
                // but we will ignore the current match anyway.
                s->match_length = MIN_MATCH - 1;
            }
        }
        // If there was a match at the previous step and the current
        // match is not better, output the previous match:
        if((s->prev_length >= MIN_MATCH) && (s->match_length <= s->prev_length))
		{
            // Do not insert strings in hash table beyond this.
			max_insert = s->strstart + s->lookahead - MIN_MATCH;

            bflush = tr_tally_dist(s, s->strstart - 1 - s->prev_match, s->prev_length - MIN_MATCH);

            // Insert in hash table all strings up to the end of the match.
            // strstart-1 and strstart are already inserted. If there is not
            // enough lookahead, the last two strings are not inserted in
            // the hash table.
            s->lookahead -= s->prev_length - 1;
            s->prev_length -= 2;
            do 
			{
                if(++s->strstart <= max_insert) 
				{
                    insert_string(s, s->strstart, hash_head);
                }
            } 
			while(--s->prev_length);

            s->match_available = 0;
            s->match_length = MIN_MATCH - 1;
            s->strstart++;

            if(bflush) 
			{
				flush_block_only(s, false);
				if(!s->z->avail_out)
				{
					return(NEED_MORE);
				}
			}
        } 
		else if(s->match_available)
		{
            // If there was no match at the previous position, output a
            // single literal. If there was a match but the current match
            // is longer, truncate the previous match to a single literal.
		    bflush = tr_tally_lit(s, s->window[s->strstart - 1]);
		    if(bflush) 
			{
                flush_block_only(s, false);
            }
            s->strstart++;
            s->lookahead--;
            if(!s->z->avail_out) 
			{
				return(NEED_MORE);
			}
        } 
		else 
		{
            // There is no previous match to compare with, wait for
            // the next step to decide.
            s->match_available = 1;
            s->strstart++;
            s->lookahead--;
        }
    }
    if(s->match_available) 
	{
        bflush = tr_tally_lit(s, s->window[s->strstart - 1]);
        s->match_available = 0;
    }
	flush_block_only(s, flush == Z_FINISH);
	if(!s->z->avail_out)
	{
		return(flush == Z_FINISH ? FINISH_STARTED : NEED_MORE);
	}
    return(flush == Z_FINISH ? FINISH_DONE : BLOCK_DONE);
}

// -------------------------------------------------------------------------------------------------
// Controlling routines
// -------------------------------------------------------------------------------------------------

EStatus deflateInit(z_stream *z, ELevel level, int noWrap)
{
    deflate_state	*s;

	assert(z);

    deflate_error = "OK";
    if((level < Z_STORE_COMPRESSION) || (level > Z_MAX_COMPRESSION)) 
	{
		deflate_error = "Invalid compression level";
        return(Z_STREAM_ERROR);
    }
    s = (deflate_state *)Z_Malloc(sizeof(deflate_state), TAG_DEFLATE, qtrue);
    z->dstate = (deflate_state *)s;
    s->z = z;

  	// undocumented feature: suppress zlib header
	s->noheader = noWrap;
    s->level = level;

	z->total_out = 0;
	z->quality = 0;

    s->pending = 0;
    s->pending_out = s->pending_buf;

    s->status = s->noheader ? BUSY_STATE : INIT_STATE;
    s->adler = 1;
    s->last_flush = Z_NO_FLUSH;

    tr_init(s);
    lm_init(s);
	return(Z_OK);
}

// ===========================================================================
// Copy the source state to the destination state.
// To simplify the source, this is not supported for 16-bit MSDOS (which
// doesn't have enough memory anyway to duplicate compression states).
// ===========================================================================

EStatus deflateCopy(z_stream *dest, z_stream *source)
{
    deflate_state	*ds;
    deflate_state	*ss;

	assert(source);
	assert(dest);
	assert(source->dstate);
	assert(!dest->dstate);

    *dest = *source;

    ss = source->dstate;
    ds = (deflate_state *)Z_Malloc(sizeof(deflate_state), TAG_DEFLATE, qtrue);
    dest->dstate = ds;
    *ds = *ss;
    ds->z = dest;

    ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);

    ds->l_desc.dyn_tree = ds->dyn_ltree;
    ds->d_desc.dyn_tree = ds->dyn_dtree;
    ds->bl_desc.dyn_tree = ds->bl_tree;

    return(Z_OK);
}

// ===========================================================================
// ===========================================================================

EStatus deflate(z_stream *z, EFlush flush)
{
    EFlush			old_flush;		// value of flush param for previous deflate call
    deflate_state	*s;
	ulong			header;
	ulong			level_flags;

	assert(z);
	assert(z->dstate);

    if((flush > Z_FINISH) || (flush < Z_NO_FLUSH)) 
	{
		deflate_error = "Invalid flush type"; 
        return(Z_STREAM_ERROR);
    }
    s = z->dstate;

    if(!z->next_out || (!z->next_in && z->avail_in) || (s->status == FINISH_STATE && flush != Z_FINISH)) 
	{
		deflate_error = "Invalid output data"; 
		return (Z_STREAM_ERROR);
    }
    if(!z->avail_out)
	{
		deflate_error = "No output space"; 
		return (Z_BUF_ERROR);
	}

    old_flush = s->last_flush;
    s->last_flush = flush;

    // Write the zlib header
    if(s->status == INIT_STATE) 
	{
		header = (ZF_DEFLATED + ((MAX_WBITS - 8) << 4)) << 8;
        level_flags = (s->level - 1) >> 1;

        if(level_flags > 3)
		{
			level_flags = 3;
		}
        header |= (level_flags << 6);

        header += 31 - (header % 31);

        s->status = BUSY_STATE;
        put_shortMSB(s, (word)header);
		s->adler = 1;
    }

	// Flush as much pending output as possible
	if(s->pending)
	{
        flush_pending(z);
        if(!z->avail_out)
		{
			// 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:
			s->last_flush = Z_NEED_MORE;
			return(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(!z->avail_in && (flush <= old_flush) && (flush != Z_FINISH))
	{
		deflate_error = "No available input"; 
		return(Z_BUF_ERROR);
    }

    // User must not provide more input after the first FINISH
    if((s->status == FINISH_STATE) && z->avail_in)
	{        
		deflate_error = "Trying to finish while input available"; 
		return(Z_BUF_ERROR);
    }

    // Start a new block or continue the current one.
    if(z->avail_in || s->lookahead || ((flush != Z_NO_FLUSH) && (s->status != FINISH_STATE)))
	{
        block_state	bstate;

		bstate = (*(configuration_table[s->level].func))(s, flush);

        if((bstate == FINISH_STARTED) || (bstate == FINISH_DONE))
		{
            s->status = FINISH_STATE;
        }
        if((bstate == NEED_MORE) || (bstate == FINISH_STARTED))
		{
			if(!z->avail_out) 
			{
				// avoid BUF_ERROR next call, see above
				s->last_flush = Z_NEED_MORE; 
			}
			return(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 == BLOCK_DONE) 
		{
			// FULL_FLUSH or SYNC_FLUSH
            tr_stored_block(s, NULL, 0, false);

            flush_pending(z);
			if(!z->avail_out)
			{
				// avoid BUF_ERROR at next call, see above
				s->last_flush = Z_NEED_MORE; 
				return(Z_OK);
			}
		}
	}

    if(flush != Z_FINISH)
	{
		return(Z_OK);
	}
    if(s->noheader) 
	{
		return(Z_STREAM_END);
	}

    // Write the zlib trailer (adler32)
    put_longMSB(s, s->adler);
    flush_pending(z);

    // If avail_out is zero, the application will call deflate again
    // to flush the rest. Write the trailer only once!
    s->noheader = -1; 
    return(!!s->pending ? Z_OK : Z_STREAM_END);
}

// ===========================================================================
// ===========================================================================

EStatus deflateEnd(z_stream *z)
{
    int		status;

	assert(z);
	assert(z->dstate);

    status = z->dstate->status;
    if((status != INIT_STATE) && (status != BUSY_STATE) && (status != FINISH_STATE))
	{
		deflate_error = "Invalid state while ending";
		return(Z_STREAM_ERROR);
    }

    Z_Free(z->dstate);
    z->dstate = NULL;

	if(status == BUSY_STATE)
	{
		deflate_error = "Ending while in busy state";
		return(Z_DATA_ERROR);
	}
    return(Z_OK);
}

// ===========================================================================
// ===========================================================================

const char *deflateError(void)
{
	return(deflate_error);
}

// ===============================================================================
// External calls
// ===============================================================================

bool DeflateFile(byte *src, ulong uncompressedSize, byte *dst, ulong maxCompressedSize, ulong *compressedSize, ELevel level, int noWrap)
{
	z_stream	z = { 0 };

	if(deflateInit(&z, level, noWrap) != Z_OK)
	{
		return(false);
	}

	z.next_in = src;
	z.avail_in = uncompressedSize;
	z.next_out = dst;
	z.avail_out = maxCompressedSize;
#ifdef _TIMING
	int temp = timeGetTime();
#endif
	if(deflate(&z, Z_FINISH) != Z_STREAM_END)
	{
		deflateEnd(&z);
		return(false);
	}
#ifdef _TIMING
	totalDeflateTime[level] += timeGetTime() - temp;
	totalDeflateCount[level]++;
#endif
	if(deflateEnd(&z) != Z_OK)
	{
		return(false);
	}
	*compressedSize = z.total_out;
	return(true);
}

// end