/programs/fs/kfar/trunk/zlib/adler32.asm |
---|
0,0 → 1,309 |
; adler32.asm -- compute the Adler-32 checksum of a data stream |
; Copyright (C) 1995-2011 Mark Adler |
; For conditions of distribution and use, see copyright notice in zlib.h |
BASE equ 65521 ;largest prime smaller than 65536 |
NMAX equ 5552 |
; NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 |
macro DO1 buf,i |
{ |
mov eax,buf |
add eax,i |
movzx eax,byte[eax] |
add [adler],eax |
mov eax,[adler] |
add [sum2],eax |
} |
macro DO2 buf,i |
{ |
DO1 buf,i |
DO1 buf,i+1 |
} |
macro DO4 buf,i |
{ |
DO2 buf,i |
DO2 buf,i+2 |
} |
macro DO8 buf,i |
{ |
DO4 buf,i |
DO4 buf,i+4 |
} |
macro DO16 buf |
{ |
DO8 buf,0 |
DO8 buf,8 |
} |
; use NO_DIVIDE if your processor does not do division in hardware -- |
; try it both ways to see which is faster |
; note that this assumes BASE is 65521, where 65536 % 65521 == 15 |
; (thank you to John Reiser for pointing this out) |
macro CHOP a |
{ |
if NO_DIVIDE eq 1 |
mov eax,a |
shr eax,16 |
and a,0xffff |
shl eax,4 |
add a,eax |
shr eax,4 |
sub a,eax |
end if |
} |
macro MOD28 a |
{ |
if NO_DIVIDE eq 1 |
local .end0 |
CHOP a |
cmp a,BASE |
jl .end0 ;if (..>=..) |
sub a,BASE |
.end0: |
else |
push eax ecx edx |
mov eax,a |
xor edx,edx |
mov ecx,BASE |
div ecx |
mov a,edx |
pop edx ecx eax |
end if |
} |
macro MOD a |
{ |
if NO_DIVIDE eq 1 |
CHOP a |
MOD28 a |
else |
push eax ecx edx |
mov eax,a |
xor edx,edx |
mov ecx,BASE |
div ecx |
mov a,edx |
pop edx ecx eax |
end if |
} |
macro MOD63 a |
{ |
if NO_DIVIDE eq 1 |
;this assumes a is not negative |
; z_off64_t tmp = a >> 32; |
; a &= 0xffffffff; |
; a += (tmp << 8) - (tmp << 5) + tmp; |
; tmp = a >> 16; |
; a &= 0xffff; |
; a += (tmp << 4) - tmp; |
; tmp = a >> 16; |
; a &= 0xffff; |
; a += (tmp << 4) - tmp; |
; if (a >= BASE) a -= BASE; |
else |
push eax ecx edx |
mov eax,a |
xor edx,edx |
mov ecx,BASE |
div ecx |
mov a,edx |
pop edx ecx eax |
end if |
} |
; ========================================================================= |
;uLong (adler, buf, len) |
; uLong adler |
; const Bytef *buf |
; uInt len |
align 4 |
proc adler32 uses ebx edx, adler:dword, buf:dword, len:dword |
locals |
sum2 dd ? ;uLong |
endl |
;zlib_debug 'adler32 adler = %d',[adler] |
; split Adler-32 into component sums |
mov eax,[adler] |
shr eax,16 |
mov [sum2],eax |
and [adler],0xffff |
mov ebx,[buf] |
; in case user likes doing a byte at a time, keep it fast |
cmp dword[len],1 |
jne .end0 ;if (..==..) |
movzx eax,byte[ebx] |
add [adler],eax |
cmp dword[adler],BASE |
jl @f ;if (..>=..) |
sub dword[adler],BASE |
@@: |
mov eax,[adler] |
add [sum2],eax |
cmp dword[sum2],BASE |
jl @f ;if (..>=..) |
sub dword[sum2],BASE |
@@: |
jmp .combine |
align 4 |
.end0: |
; initial Adler-32 value (deferred check for len == 1 speed) |
cmp ebx,Z_NULL |
jne @f ;if (..==0) |
xor eax,eax |
inc eax |
jmp .end_f |
align 4 |
@@: |
; in case short lengths are provided, keep it somewhat fast |
cmp dword[len],16 |
jge .end1 ;if (..<..) |
.cycle0: |
cmp dword[len],0 |
jne @f ;while (..) |
movzx eax,byte[ebx] |
inc ebx |
add [adler],eax |
mov eax,[adler] |
add [sum2],eax |
dec dword[len] |
jmp .cycle0 |
align 4 |
@@: |
cmp dword[adler],BASE |
jl @f ;if (..>=..) |
sub dword[adler],BASE |
@@: |
MOD28 dword[sum2] ;only added so many BASE's |
jmp .combine |
align 4 |
.end1: |
; do length NMAX blocks -- requires just one modulo operation |
.cycle3: |
cmp dword[len],NMAX |
jl .cycle3end ;while (..>=..) |
sub dword[len],NMAX |
mov edx,NMAX/16 ;NMAX is divisible by 16 |
.cycle1: ;do |
DO16 ebx ;16 sums unrolled |
add ebx,16 |
dec edx |
cmp edx,0 |
jg .cycle1 ;while (..) |
MOD [adler] |
MOD [sum2] |
jmp .cycle3 |
align 4 |
.cycle3end: |
; do remaining bytes (less than NMAX, still just one modulo) |
cmp dword[len],0 |
jne .end2 ;if (..) ;avoid modulos if none remaining |
@@: |
cmp dword[len],16 |
jl .cycle2 ;while (..>=..) |
sub dword[len],16 |
DO16 ebx |
add ebx,16 |
jmp @b |
align 4 |
.cycle2: |
cmp dword[len],0 |
jne @f ;while (..) |
movzx eax,byte[ebx] |
inc ebx |
add [adler],eax |
mov eax,[adler] |
add [sum2],eax |
dec dword[len] |
jmp .cycle2 |
align 4 |
@@: |
MOD [adler] |
MOD [sum2] |
.end2: |
; return recombined sums |
.combine: |
mov eax,[sum2] |
shl eax,16 |
or eax,[adler] |
.end_f: |
;zlib_debug ' adler32.ret = %d',eax |
ret |
endp |
; ========================================================================= |
;uLong (adler1, adler2, len2) |
; uLong adler1 |
; uLong adler2 |
; z_off64_t len2 |
align 4 |
proc adler32_combine_, adler1:dword, adler2:dword, len2:dword |
locals |
sum1 dd ? ;uLong |
sum2 dd ? ;uLong |
; unsigned rem; |
endl |
; for negative len, return invalid adler32 as a clue for debugging |
cmp dword[len2],0 |
jge @f ;if (..<0) |
mov eax,0xffffffff |
jmp .end_f |
@@: |
; the derivation of this formula is left as an exercise for the reader |
; MOD63(len2) ;assumes len2 >= 0 |
; rem = (unsigned)len2; |
; sum1 = adler1 & 0xffff; |
; sum2 = rem * sum1; |
; MOD(sum2); |
; sum1 += (adler2 & 0xffff) + BASE - 1; |
; sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; |
cmp dword[sum1],BASE |
jl @f ;if (..>=..) |
sub dword[sum1],BASE |
@@: |
cmp dword[sum1],BASE |
jl @f ;if (..>=..) |
sub dword[sum1],BASE |
@@: |
cmp dword[sum2],BASE shl 1 |
jl @f ;if (..>=..) |
sub dword[sum2],BASE shl 1 |
@@: |
cmp dword[sum2],BASE |
jl @f ;if (..>=..) |
sub dword[sum2],BASE |
@@: |
mov eax,[sum2] |
shl eax,16 |
or eax,[sum1] |
.end_f: |
ret |
endp |
; ========================================================================= |
;uLong (adler1, adler2, len2) |
; uLong adler1 |
; uLong adler2 |
; z_off_t len2 |
align 4 |
proc adler32_combine, adler1:dword, adler2:dword, len2:dword |
stdcall adler32_combine_, [adler1], [adler2], [len2] |
ret |
endp |
;uLong (adler1, adler2, len2) |
; uLong adler1 |
; uLong adler2 |
; z_off64_t len2 |
align 4 |
proc adler32_combine64, adler1:dword, adler2:dword, len2:dword |
stdcall adler32_combine_, [adler1], [adler2], [len2] |
ret |
endp |
/programs/fs/kfar/trunk/zlib/build.bat |
---|
0,0 → 1,5 |
@fasm.exe -m 32768 zlib.asm zlib.obj |
@kpack zlib.obj |
@fasm.exe -m 32768 example1.asm example1.kex |
@kpack example1.kex |
pause |
/programs/fs/kfar/trunk/zlib/crc32.asm |
---|
0,0 → 1,278 |
; crc32.asm -- compute the CRC-32 of a data stream |
; Copyright (C) 1995-2006, 2010, 2011, 2012 Mark Adler |
; For conditions of distribution and use, see copyright notice in zlib.inc |
; Thanks to Rodney Brown <rbrown64@csc.com.au> for his contribution of faster |
; CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing |
; tables for updating the shift register in one step with three exclusive-ors |
; instead of four steps with four exclusive-ors. This results in about a |
; factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. |
; Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore |
; protection on the static variables used to control the first-use generation |
; of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should |
; first call get_crc_table() to initialize the tables before allowing more than |
; one thread to use crc32(). |
; Definitions for doing the crc four data bytes at a time. |
TBLS equ 1 |
if DYNAMIC_CRC_TABLE eq 1 |
align 4 |
crc_table_empty dd 1 |
align 4 |
crc_table rd TBLS*256 |
; Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: |
; x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. |
; Polynomials over GF(2) are represented in binary, one bit per coefficient, |
; with the lowest powers in the most significant bit. Then adding polynomials |
; is just exclusive-or, and multiplying a polynomial by x is a right shift by |
; one. If we call the above polynomial p, and represent a byte as the |
; polynomial q, also with the lowest power in the most significant bit (so the |
; byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, |
; where a mod b means the remainder after dividing a by b. |
; This calculation is done using the shift-register method of multiplying and |
; taking the remainder. The register is initialized to zero, and for each |
; incoming bit, x^32 is added mod p to the register if the bit is a one (where |
; x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by |
; x (which is shifting right by one and adding x^32 mod p if the bit shifted |
; out is a one). We start with the highest power (least significant bit) of |
; q and repeat for all eight bits of q. |
; The first table is simply the CRC of all possible eight bit values. This is |
; all the information needed to generate CRCs on data a byte at a time for all |
; combinations of CRC register values and incoming bytes. The remaining tables |
; allow for word-at-a-time CRC calculation for both big-endian and little- |
; endian machines, where a word is four bytes. |
;void () |
align 4 |
proc make_crc_table uses ecx edx edi |
zlib_debug 'make_crc_table' |
; generate a crc for every 8-bit value |
xor edx, edx |
mov edi, crc_table |
.1: |
mov ecx, 8 |
mov eax, edx |
.2: |
shr eax, 1 |
jnc @f |
xor eax, 0xEDB88320 |
@@: |
loop .2 |
stosd |
inc dl |
jnz .1 |
mov dword[crc_table_empty],0 |
ret |
endp |
else ;!DYNAMIC_CRC_TABLE |
; ======================================================================== |
; Tables of CRC-32s of all single-byte values, made by make_crc_table(). |
;include 'crc32.inc' |
end if ;DYNAMIC_CRC_TABLE |
; ========================================================================= |
; This function can be used by asm versions of crc32() |
;const z_crc_t* () |
align 4 |
proc get_crc_table |
if DYNAMIC_CRC_TABLE eq 1 |
cmp dword[crc_table_empty],0 |
je @f ;if (..) |
call make_crc_table |
@@: |
end if ;DYNAMIC_CRC_TABLE |
mov eax,crc_table |
ret |
endp |
; ========================================================================= |
macro DO1 |
{ |
xor al,byte[esi] |
xor al,ah |
mov eax,[crc_table+eax*4] |
inc esi |
} |
macro DO8 |
{ |
DO1 |
DO1 |
DO1 |
DO1 |
DO1 |
DO1 |
DO1 |
DO1 |
} |
; ========================================================================= |
;unsigned long (crc, buf, len) |
; unsigned long crc |
; unsigned char *buf |
; uInt len |
align 4 |
proc calc_crc32 uses ecx esi, p1crc:dword, buf:dword, len:dword |
xor eax,eax |
mov esi,[buf] |
zlib_debug 'calc_crc32 buf = %d',esi |
cmp esi,Z_NULL |
je .end_f ;if (..==0) return 0 |
if DYNAMIC_CRC_TABLE eq 1 |
cmp dword[crc_table_empty],0 |
je @f ;if (..) |
call make_crc_table |
@@: |
end if |
mov eax,[p1crc] |
xor eax,0xffffffff |
mov [p1crc],eax |
mov ecx,[len] |
align 4 |
.cycle0: |
cmp ecx,8 |
jl @f |
DO8 |
sub ecx,8 |
jmp .cycle0 |
align 4 |
@@: |
cmp ecx,1 |
jl @f |
DO1 |
dec ecx |
jmp @b |
@@: |
mov eax,[p1crc] |
xor eax,0xffffffff |
.end_f: |
ret |
endp |
GF2_DIM equ 32 ;dimension of GF(2) vectors (length of CRC) |
; ========================================================================= |
;unsigned long (mat, vec) |
; unsigned long *mat |
; unsigned long vec |
align 4 |
proc gf2_matrix_times, mat:dword, vec:dword |
; unsigned long sum; |
; sum = 0; |
; while (vec) { |
; if (vec & 1) |
; sum ^= *mat; |
; vec >>= 1; |
; mat++; |
; } |
; return sum; |
ret |
endp |
; ========================================================================= |
;local void (square, mat) |
; unsigned long *square |
; unsigned long *mat |
align 4 |
proc gf2_matrix_square, square:dword, mat:dword |
; int n; |
; for (n = 0; n < GF2_DIM; n++) |
; square[n] = gf2_matrix_times(mat, mat[n]); |
ret |
endp |
; ========================================================================= |
;uLong (crc1, crc2, len2) |
; uLong crc1 |
; uLong crc2 |
; z_off64_t len2 |
align 4 |
proc crc32_combine_, crc1:dword, crc2:dword, len2:dword |
; int n; |
; unsigned long row; |
; unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */ |
; unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */ |
; degenerate case (also disallow negative lengths) |
; if (len2 <= 0) |
; return crc1; |
; put operator for one zero bit in odd |
; odd[0] = 0xedb88320UL; /* CRC-32 polynomial */ |
; row = 1; |
; for (n = 1; n < GF2_DIM; n++) { |
; odd[n] = row; |
; row <<= 1; |
; } |
; put operator for two zero bits in even |
; gf2_matrix_square(even, odd); |
; put operator for four zero bits in odd |
; gf2_matrix_square(odd, even); |
; apply len2 zeros to crc1 (first square will put the operator for one |
; zero byte, eight zero bits, in even) |
; do { |
; apply zeros operator for this bit of len2 |
; gf2_matrix_square(even, odd); |
; if (len2 & 1) |
; crc1 = gf2_matrix_times(even, crc1); |
; len2 >>= 1; |
; if no more bits set, then done |
; if (len2 == 0) |
; break; |
; another iteration of the loop with odd and even swapped |
; gf2_matrix_square(odd, even); |
; if (len2 & 1) |
; crc1 = gf2_matrix_times(odd, crc1); |
; len2 >>= 1; |
; if no more bits set, then done |
; } while (len2 != 0); |
; return combined crc |
; crc1 ^= crc2; |
; return crc1; |
ret |
endp |
; ========================================================================= |
;uLong (crc1, crc2, len2) |
; uLong crc1 |
; uLong crc2 |
; z_off_t len2 |
align 4 |
proc crc32_combine, crc1:dword, crc2:dword, len2:dword |
stdcall crc32_combine_, [crc1], [crc2], [len2] |
ret |
endp |
;uLong (crc1, crc2, len2) |
; uLong crc1 |
; uLong crc2 |
; z_off64_t len2 |
align 4 |
proc crc32_combine64, crc1:dword, crc2:dword, len2:dword |
stdcall crc32_combine_, [crc1], [crc2], [len2] |
ret |
endp |
/programs/fs/kfar/trunk/zlib/debug.inc |
---|
0,0 → 1,440 |
txt_zv db '*',0 |
txt_sp db ' ',0 |
txt_buf db '1234',0 |
rd 1 |
buf_param rb 80 |
macro cStr dest,txt |
{ |
local .end_t |
local .m_txt |
jmp .end_t |
align 4 |
.m_txt db txt,0 |
align 4 |
.end_t: |
if dest eq |
mov eax,.m_txt |
else |
mov dest,.m_txt |
end if |
} |
;for debug |
tz1 db 'next_in',13,10,0 |
tz2 db 'avail_in',13,10,0 |
tz3 db 'total_in',13,10,0 |
tz4 db 'next_out',13,10,0 |
tz5 db 'avail_out',13,10,0 |
tz6 db 'total_out',13,10,0 |
tz7 db 'msg',13,10,0 |
tz8 db 'state',13,10,0 |
tz9 db 'zalloc',13,10,0 |
tz10 db 'zfree',13,10,0 |
tz11 db 'opaque',13,10,0 |
tz12 db 'data_type',13,10,0 |
tz13 db 'adler',13,10,0 |
tz14 db 'reserved',13,10,0 |
sv_2: |
dd z_stream.next_in,4,tz1 |
dd z_stream.avail_in,2,tz2 |
dd z_stream.total_in,4,tz3 |
dd z_stream.next_out,4,tz4 |
dd z_stream.avail_out,2,tz5 |
dd z_stream.total_out,4,tz6 |
dd z_stream.msg,4,tz7 |
dd z_stream.state,4,tz8 |
dd z_stream.zalloc,4,tz9 |
dd z_stream.zfree,4,tz10 |
dd z_stream.opaque,4,tz11 |
dd z_stream.data_type,2,tz12 |
dd z_stream.adler,4,tz13 |
dd z_stream.reserved,4,tz14 |
dd 0,0 |
ta1 db 'strm',13,10,0 |
ta2 db 'status',13,10,0 |
ta3 db 'pending_buf',13,10,0 |
ta4 db 'pending_buf_size',13,10,0 |
ta5 db 'pending_out',13,10,0 |
ta6 db 'pending',13,10,0 |
ta7 db 'wrap',13,10,0 |
ta8 db 'gzhead',13,10,0 |
ta9 db 'gzindex',13,10,0 |
ta10 db 'method',13,10,0 |
ta11 db 'last_flush',13,10,0 |
ta12 db 'w_size',13,10,0 |
ta13 db 'w_bits',13,10,0 |
ta14 db 'w_mask',13,10,0 |
ta15 db 'window',13,10,0 |
ta16 db 'window_size',13,10,0 |
ta17 db 'prev',13,10,0 |
ta18 db 'head',13,10,0 |
ta19 db 'ins_h',13,10,0 |
ta20 db 'hash_size',13,10,0 |
ta21 db 'hash_bits',13,10,0 |
ta22 db 'hash_mask',13,10,0 |
ta23 db 'hash_shift',13,10,0 |
ta24 db 'block_start',13,10,0 |
ta25 db 'match_length',13,10,0 |
ta26 db 'prev_match',13,10,0 |
ta27 db 'match_available',13,10,0 |
ta28 db 'strstart',13,10,0 |
ta29 db 'match_start',13,10,0 |
ta30 db 'lookahead',13,10,0 |
ta31 db 'prev_length',13,10,0 |
ta32 db 'max_chain_length',13,10,0 |
ta33 db 'max_lazy_match',13,10,0 |
ta34 db 'level',13,10,0 |
ta35 db 'strategy',13,10,0 |
ta36 db 'good_match',13,10,0 |
ta37 db 'nice_match',13,10,0 |
ta38 db 'dyn_ltree',13,10,0 |
ta39 db 'dyn_dtree',13,10,0 |
ta40 db 'bl_tree',13,10,0 |
ta41 db 'l_desc',13,10,0 |
ta42 db 'd_desc',13,10,0 |
ta43 db 'bl_desc',13,10,0 |
ta44 db 'bl_count',13,10,0 |
ta45 db 'heap',13,10,0 |
ta46 db 'heap_len',13,10,0 |
ta47 db 'heap_max',13,10,0 |
ta48 db 'depth',13,10,0 |
ta49 db 'l_buf',13,10,0 |
ta50 db 'lit_bufsize',13,10,0 |
ta51 db 'last_lit',13,10,0 |
ta52 db 'd_buf',13,10,0 |
ta53 db 'opt_len',13,10,0 |
ta54 db 'static_len',13,10,0 |
ta55 db 'matches',13,10,0 |
ta56 db 'insert',13,10,0 |
; db 'compressed_len',13,10,0 |
; db 'bits_sent',13,10,0 |
ta59 db 'bi_buf',13,10,0 |
ta60 db 'bi_valid',13,10,0 |
ta61 db 'high_water',13,10,0 |
sv_3: |
dd deflate_state.strm,4,ta1 |
dd deflate_state.status,4,ta2 |
dd deflate_state.pending_buf,4,ta3 |
dd deflate_state.pending_buf_size,4,ta4 |
dd deflate_state.pending_out,4,ta5 |
dd deflate_state.pending,2,ta6 |
dd deflate_state.wrap,4,ta7 |
dd deflate_state.gzhead,4,ta8 |
dd deflate_state.gzindex,4,ta9 |
dd deflate_state.method,1,ta10 |
dd deflate_state.last_flush,4,ta11 |
dd deflate_state.w_size,4,ta12 |
dd deflate_state.w_bits,4,ta13 |
dd deflate_state.w_mask,4,ta14 |
dd deflate_state.window,4,ta15 |
dd deflate_state.window_size,4,ta16 |
dd deflate_state.prev,4,ta17 |
dd deflate_state.head,4,ta18 |
dd deflate_state.ins_h,4,ta19 |
dd deflate_state.hash_size,4,ta20 |
dd deflate_state.hash_bits,4,ta21 |
dd deflate_state.hash_mask,4,ta22 |
dd deflate_state.hash_shift,4,ta23 |
dd deflate_state.block_start,4,ta24 |
dd deflate_state.match_length,4,ta25 |
dd deflate_state.prev_match,4,ta26 |
dd deflate_state.match_available,4,ta27 |
dd deflate_state.strstart,4,ta28 |
dd deflate_state.match_start,4,ta29 |
dd deflate_state.lookahead,4,ta30 |
dd deflate_state.prev_length,4,ta31 |
dd deflate_state.max_chain_length,4,ta32 |
dd deflate_state.max_lazy_match,4,ta33 |
dd deflate_state.level,2,ta34 |
dd deflate_state.strategy,2,ta35 |
dd deflate_state.good_match,4,ta36 |
dd deflate_state.nice_match,4,ta37 |
dd deflate_state.dyn_ltree,((2*HEAP_SIZE) shl 16)+2,ta38 |
dd deflate_state.dyn_dtree,((2*(2*D_CODES+1)) shl 16)+2,ta39 |
dd deflate_state.bl_tree,((2*(2*BL_CODES+1)) shl 16)+2,ta40 |
dd deflate_state.l_desc,(3 shl 16)+4,ta41 |
dd deflate_state.d_desc,(3 shl 16)+4,ta42 |
dd deflate_state.bl_desc,(3 shl 16)+4,ta43 |
dd deflate_state.bl_count,((MAX_BITS+1) shl 16)+2,ta44 |
dd deflate_state.heap,((2*L_CODES+1) shl 16)+2,ta45 |
dd deflate_state.heap_len,4,ta46 |
dd deflate_state.heap_max,4,ta47 |
dd deflate_state.depth,((2*L_CODES+1) shl 16)+1,ta48 |
dd deflate_state.l_buf,4,ta49 |
dd deflate_state.lit_bufsize,4,ta50 |
dd deflate_state.last_lit,4,ta51 |
dd deflate_state.d_buf,4,ta52 |
dd deflate_state.opt_len,4,ta53 |
dd deflate_state.static_len,4,ta54 |
dd deflate_state.matches,4,ta55 |
dd deflate_state.insert,4,ta56 |
;if DEBUG eq 1 |
;dd deflate_state.compressed_len |
;dd deflate_state.bits_sent |
;end if |
dd deflate_state.bi_buf,2,ta59 |
dd deflate_state.bi_valid,4,ta60 |
dd deflate_state.high_water,4,ta61 |
dd 0,0 |
align 4 |
proc dbg_print, fun:dword, mes:dword |
pushad |
mov eax,SF_BOARD |
mov ebx,SSF_DEBUG_WRITE |
mov esi,[fun] |
cmp esi,0 |
je .end0 |
@@: |
mov cl,byte[esi] |
int 0x40 |
inc esi |
cmp byte[esi],0 |
jne @b |
mov cl,':' |
int 0x40 |
mov cl,' ' |
int 0x40 |
.end0: |
mov esi,[mes] |
cmp esi,0 |
je .end_f |
@@: |
mov cl,byte[esi] |
cmp cl,0 |
je .end_f |
int 0x40 |
inc esi |
jmp @b |
.end_f: |
popad |
ret |
endp |
;input: |
; zif - 1...8 |
align 4 |
proc hex_in_str, buf:dword,val:dword,zif:dword |
pushad |
mov edi,dword[buf] |
mov ecx,dword[zif] |
add edi,ecx |
dec edi |
mov ebx,dword[val] |
.cycle: |
mov al,bl |
and al,0xf |
cmp al,10 |
jl @f |
add al,'a'-'0'-10 |
@@: |
add al,'0' |
mov byte[edi],al |
dec edi |
shr ebx,4 |
loop .cycle |
popad |
ret |
endp |
;output: |
; eax = strlen |
align 4 |
proc strlen, str1:dword |
mov eax,[str1] |
@@: |
cmp byte[eax],0 |
je @f |
inc eax |
jmp @b |
@@: |
sub eax,[str1] |
ret |
endp |
align 4 |
proc str_format_dbg, buf:dword, fmt:dword, p1:dword |
pushad |
mov esi,[fmt] |
mov edi,[buf] |
mov ecx,80-1 |
.cycle0: |
lodsb |
cmp al,'%' |
jne .no_param |
lodsb |
dec ecx |
cmp al,0 |
je .cycle0end |
cmp al,'d' |
je @f |
cmp al,'u' |
je @f |
cmp al,'l' |
je .end1 |
jmp .end0 |
.end1: ;%lu %lx |
lodsb |
dec ecx |
cmp al,'u' |
jne .end0 |
@@: |
mov eax,[p1] |
stdcall convert_int_to_str,ecx |
xor al,al |
repne scasb |
dec edi |
.end0: |
loop .cycle0 |
.no_param: |
stosb |
cmp al,0 |
je .cycle0end |
loop .cycle0 |
.cycle0end: |
xor al,al |
stosb |
stdcall dbg_print,txt_sp,[buf] |
popad |
ret |
endp |
align 4 |
proc debug_fields, saddr:dword, form:dword |
locals |
nl_array dd ? |
endl |
pushad |
mov edi,[saddr] |
cmp edi,0 |
je .end_f |
mcall SF_BOARD,SSF_DEBUG_WRITE,13 |
mcall ,,10 |
mov eax,[form] |
align 4 |
.cycle0: |
mov ebx,[eax+4] |
mov ecx,ebx |
and ebx,0xffff |
cmp ebx,0 |
je .end_f |
mov esi,ebx |
shl ebx,1 |
shr ecx,16 |
cmp ecx,0 |
je .end0 |
;if array |
stdcall dbg_print,0,[eax+8] |
mov edx,61 ;size text line |
mov dword[nl_array],0 |
.cycle2: |
inc dword[nl_array] |
sub edx,ebx |
sub edx,2 ;': ' |
cmp edx,3 |
jg .cycle2 |
mov edx,edi |
add edx,[eax] |
push eax |
.nl_i: |
mov eax,[nl_array] |
mov byte[ebx+txt_buf],0 ;конец числа |
.cycle1: |
stdcall hex_in_str,txt_buf,[edx],ebx |
add edx,esi ;move next value |
push edi |
mov edi,txt_buf |
cmp byte[edi],'0' |
jne @f |
inc edi |
cmp byte[edi],'0' |
jne @f |
inc edi |
cmp byte[edi],'0' |
jne @f |
inc edi |
cmp byte[edi],'0' |
jne @f |
inc edi |
@@: |
cmp byte[edi],0 |
jne @f |
dec edi |
@@: |
stdcall dbg_print,edi,0 |
pop edi |
;stdcall dbg_print,txt_buf,0 |
dec eax |
jz .nl |
loop .cycle1 |
.nl: |
push ebx ecx |
mcall SF_BOARD,SSF_DEBUG_WRITE,13 |
mcall ,,10 |
pop ecx ebx |
dec ecx |
cmp ecx,0 |
jg .nl_i |
pop eax |
add eax,12 |
jmp .cycle0 |
.end0: |
mov edx,edi |
add edx,[eax] |
stdcall hex_in_str,txt_buf,[edx],ebx |
mov byte[ebx+txt_buf],0 ;конец числа |
stdcall dbg_print,txt_buf,[eax+8] |
add eax,12 |
jmp .cycle0 |
.end_f: |
mcall SF_BOARD,SSF_DEBUG_WRITE,13 |
mcall ,,10 |
popad |
ret |
endp |
;input: |
; eax - число |
; edi - буфер для строки |
; len - длинна буфера |
;output: |
align 4 |
proc convert_int_to_str, len:dword |
pushad |
mov esi,[len] |
add esi,edi |
dec esi |
call .str |
popad |
ret |
endp |
align 4 |
.str: |
mov ecx,0x0a |
cmp eax,ecx |
jb @f |
xor edx,edx |
div ecx |
push edx |
call .str |
pop eax |
@@: |
cmp edi,esi |
jge @f |
or al,0x30 |
stosb |
mov byte[edi],0 |
@@: |
ret |
/programs/fs/kfar/trunk/zlib/deflate.asm |
---|
0,0 → 1,2962 |
; deflate.asm -- compress data using the deflation algorithm |
; Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler |
; For conditions of distribution and use, see copyright notice in zlib.inc |
; 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). |
; A previous version of this file used a more sophisticated algorithm |
; (by Fiala and Greene) which is guaranteed to run in linear amortized |
; time, but has a larger average cost, uses more memory and is patented. |
; However the F&G algorithm may be faster for some highly redundant |
; files if the parameter max_chain_length (described below) is too large. |
; 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 http://tools.ietf.org/html/rfc1951 |
; 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 |
deflate_copyright db ' deflate 1.2.8 Copyright 1995-2013 Jean-loup Gailly and Mark Adler ',0 |
; 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. |
; =========================================================================== |
; Function prototypes. |
;enum block_state |
need_more equ 1 ;block not completed, need more input or more output |
block_done equ 2 ;block flush performed |
finish_started equ 3 ;finish started, need only more output at next deflate |
finish_done equ 4 ;finish done, accept no more input or output |
; =========================================================================== |
; Local data |
NIL equ 0 |
; Tail of hash chains |
TOO_FAR equ 4096 |
; Matches of length 3 are discarded if their distance exceeds TOO_FAR |
; 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. |
struct config_s ;config |
good_length dw ? ;uint_16 ;reduce lazy search above this match length |
max_lazy dw ? ;uint_16 ;do not perform lazy search above this match length |
nice_length dw ? ;uint_16 ;quit search above this match length |
max_chain dw ? ;uint_16 |
co_func dd ? ;compress_func |
ends |
align 16 |
configuration_table: |
config_s 0, 0, 0, 0, deflate_stored ;store only |
config_s 4, 4, 8, 4, deflate_fast ;max speed, no lazy matches |
if FASTEST eq 0 |
config_s 4, 5, 16, 8, deflate_fast |
config_s 4, 6, 32, 32, deflate_fast |
config_s 4, 4, 16, 16, deflate_slow ;lazy matches |
config_s 8, 16, 32, 32, deflate_slow |
config_s 8, 16, 128, 128, deflate_slow |
config_s 8, 32, 128, 256, deflate_slow |
config_s 32, 128, 258, 1024, deflate_slow |
config_s 32, 258, 258, 4096, deflate_slow ;max compression |
end if |
; 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. |
EQUAL equ 0 |
; result of memcmp for equal strings |
; rank Z_BLOCK between Z_NO_FLUSH and Z_PARTIAL_FLUSH |
macro RANK f, reg |
{ |
local .end0 |
xor reg,reg |
cmp f,4 |
jle .end0 |
sub reg,9 |
.end0: |
add reg,f |
add reg,f |
} |
; =========================================================================== |
; Update a hash value with the given input byte |
; IN assertion: all calls to to UPDATE_HASH are made with consecutive |
; input characters, so that a running hash key can be computed from the |
; previous key instead of complete recalculation each time. |
macro UPDATE_HASH s,h,c |
{ |
push ebx ecx |
mov ebx,h |
mov ecx,[s+deflate_state.hash_shift] |
shl ebx,cl |
xor ebx,c |
and ebx,[s+deflate_state.hash_mask] |
mov h,ebx |
pop ecx ebx |
} |
; =========================================================================== |
; 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). |
macro INSERT_STRING s, str, match_head |
{ |
mov eax,[s+deflate_state.window] |
add eax,str |
add eax,MIN_MATCH-1 |
movzx eax,byte[eax] |
UPDATE_HASH s, [s+deflate_state.ins_h], eax |
mov eax,[s+deflate_state.ins_h] |
shl eax,2 |
add eax,[s+deflate_state.head] |
mov eax,[eax] |
mov match_head,eax |
if FASTEST eq 0 |
push ebx |
mov ebx,[s+deflate_state.w_mask] |
and ebx,str |
add ebx,[s+deflate_state.prev] |
mov byte[ebx],al |
pop ebx |
end if |
mov eax,[s+deflate_state.ins_h] |
shl eax,2 |
add eax,[s+deflate_state.head] |
push str |
pop dword[eax] |
} |
; =========================================================================== |
; Initialize the hash table (avoiding 64K overflow for 16 bit systems). |
; prev[] will be initialized on the fly. |
macro CLEAR_HASH s |
{ |
mov eax,[s+deflate_state.hash_size] |
dec eax |
shl eax,2 |
add eax,[s+deflate_state.head] |
mov dword[eax],NIL |
mov eax,[s+deflate_state.hash_size] |
dec eax |
shl eax,2 ;sizeof(*s.head) |
stdcall zmemzero, [s+deflate_state.head], eax |
} |
align 4 |
proc deflateInit, strm:dword, level:dword |
stdcall deflateInit_, [strm], [level], ZLIB_VERSION, sizeof.z_stream |
ret |
endp |
; ========================================================================= |
;int (strm, level, version, stream_size) |
; z_streamp strm; |
; int level; |
; const char *version; |
; int stream_size; |
align 4 |
proc deflateInit_, strm:dword, level:dword, version:dword, stream_size:dword |
stdcall deflateInit2_, [strm], [level], Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,\ |
Z_DEFAULT_STRATEGY, [version], [stream_size] |
; To do: ignore strm->next_in if we use it as window |
ret |
endp |
align 4 |
proc deflateInit2, strm:dword, level:dword, method:dword, windowBits:dword, memLevel:dword, strategy:dword |
stdcall deflateInit2_, [strm],[level],[method],[windowBits],[memLevel],\ |
[strategy], ZLIB_VERSION, sizeof.z_stream |
ret |
endp |
; ========================================================================= |
;int (strm, level, method, windowBits, memLevel, strategy, |
; version, stream_size) |
; z_streamp strm; |
; int level; |
; int method; |
; int windowBits; |
; int memLevel; |
; int strategy; |
; const char *version; |
; int stream_size; |
align 4 |
proc deflateInit2_ uses ebx ecx edx edi, strm:dword, level:dword, method:dword,\ |
windowBits:dword, memLevel:dword, strategy:dword, version:dword, stream_size:dword |
locals |
wrap dd 1 ;int |
overlay dd ? ;uint_16p |
endl |
; We overlay pending_buf and d_buf+l_buf. This works since the average |
; output size for (length,distance) codes is <= 24 bits. |
mov eax,[version] |
cmp eax,Z_NULL |
je @f |
mov ebx,dword[ZLIB_VERSION] |
cmp dword[eax],ebx |
jne @f |
cmp dword[stream_size],sizeof.z_stream |
je .end0 |
@@: ;if (..==0 || ..[0]!=..[0] || ..!=..) |
mov eax,Z_VERSION_ERROR |
jmp .end_f |
.end0: |
mov ebx,[strm] |
cmp ebx,Z_NULL |
jne @f ;if (..==0) return .. |
mov eax,Z_STREAM_ERROR |
jmp .end_f |
@@: |
mov dword[ebx+z_stream.msg],Z_NULL |
cmp dword[ebx+z_stream.zalloc],0 |
jne @f ;if (..==0) |
if Z_SOLO eq 1 |
mov eax,Z_STREAM_ERROR |
jmp .end_f |
else |
mov dword[ebx+z_stream.zalloc],zcalloc |
mov dword[ebx+z_stream.opaque],0 |
end if |
@@: |
cmp dword[ebx+z_stream.zfree],0 |
jne @f ;if (..==0) |
if Z_SOLO eq 1 |
mov eax,Z_STREAM_ERROR |
jmp .end_f |
else |
mov dword[ebx+z_stream.zfree],zcfree |
end if |
@@: |
if FASTEST eq 1 |
cmp dword[level],0 |
je @f ;if (..!=0) |
mov dword[level],1 |
@@: |
else |
cmp dword[level],Z_DEFAULT_COMPRESSION |
jne @f ;if (..==0) |
mov dword[level],6 |
@@: |
end if |
cmp dword[windowBits],0 |
jge @f ;if (..<0) ;suppress zlib wrapper |
mov dword[wrap],0 |
neg dword[windowBits] |
inc dword[windowBits] |
jmp .end1 |
@@: |
if GZIP eq 1 |
cmp dword[windowBits],15 |
jle .end1 ;else if (..>15) |
mov dword[wrap],2 ;write gzip wrapper instead |
sub dword[windowBits],16 |
end if |
.end1: |
cmp dword[memLevel],1 |
jl .end2 |
cmp dword[memLevel],MAX_MEM_LEVEL |
jg .end2 |
cmp dword[method],Z_DEFLATED |
jne .end2 |
cmp dword[windowBits],8 |
jl .end2 |
cmp dword[windowBits],15 |
jg .end2 |
cmp dword[level],0 |
jl .end2 |
cmp dword[level],9 |
jg .end2 |
cmp dword[strategy],0 |
jl .end2 |
cmp dword[strategy],Z_FIXED |
jle @f |
.end2: ;if (..<.. || ..>.. || ..!=.. || ..<.. || ..>.. || ..<0 || ..>.. || ..<0 || ..>..) |
mov eax,Z_STREAM_ERROR |
jmp .end_f |
@@: |
cmp dword[windowBits],8 |
jne @f ;if (..==..) |
inc dword[windowBits] ;until 256-byte window bug fixed |
@@: |
ZALLOC ebx, 1, sizeof.deflate_state |
;eax = s |
cmp eax,Z_NULL |
jne @f ;if (..==0) |
mov eax,Z_MEM_ERROR |
jmp .end_f |
@@: |
mov edi,eax ;edi = s |
mov [ebx+z_stream.state],edi |
mov [edi+deflate_state.strm],ebx |
mov eax,[wrap] |
mov [edi+deflate_state.wrap],eax |
mov [edi+deflate_state.gzhead],Z_NULL |
mov ecx,[windowBits] |
mov [edi+deflate_state.w_bits],ecx |
xor eax,eax |
inc eax |
shl eax,cl |
mov [edi+deflate_state.w_size],eax |
dec eax |
mov [edi+deflate_state.w_mask],eax |
mov ecx,[memLevel] |
add ecx,7 |
mov [edi+deflate_state.hash_bits],ecx |
xor eax,eax |
inc eax |
shl eax,cl |
mov [edi+deflate_state.hash_size],eax |
dec eax |
mov [edi+deflate_state.hash_mask],eax |
add ecx,MIN_MATCH-1 |
xor edx,edx |
mov eax,ecx |
mov ecx,MIN_MATCH |
div ecx |
mov [edi+deflate_state.hash_shift],eax |
ZALLOC ebx, [edi+deflate_state.w_size], 2 ;2*sizeof(Byte) |
mov [edi+deflate_state.window],eax |
ZALLOC ebx, [edi+deflate_state.w_size], 4 ;sizeof(Pos) |
mov [edi+deflate_state.prev],eax |
ZALLOC ebx, [edi+deflate_state.hash_size], 4 ;sizeof(Pos) |
mov [edi+deflate_state.head],eax |
mov dword[edi+deflate_state.high_water],0 ;nothing written to s->window yet |
mov ecx,[memLevel] |
add ecx,6 |
xor eax,eax |
inc eax |
shl eax,cl |
mov [edi+deflate_state.lit_bufsize],eax ;16K elements by default |
ZALLOC ebx, eax, 4 ;sizeof(uint_16)+2 |
mov [overlay],eax |
mov [edi+deflate_state.pending_buf],eax |
mov eax,[edi+deflate_state.lit_bufsize] |
imul eax,4 ;sizeof(uint_16)+2 |
mov [edi+deflate_state.pending_buf_size],eax |
cmp dword[edi+deflate_state.window],Z_NULL |
je .end3 |
cmp dword[edi+deflate_state.prev],Z_NULL |
je .end3 |
cmp dword[edi+deflate_state.head],Z_NULL |
je .end3 |
cmp dword[edi+deflate_state.pending_buf],Z_NULL |
je .end3 |
jmp @f |
.end3: ;if (..==0 || ..==0 || ..==0 || ..==0) |
mov dword[edi+deflate_state.status],FINISH_STATE |
ERR_MSG Z_MEM_ERROR |
mov [ebx+z_stream.msg],eax |
stdcall deflateEnd, ebx |
mov eax,Z_MEM_ERROR |
jmp .end_f |
@@: |
mov eax,[edi+deflate_state.lit_bufsize] |
shr eax,1 ;/=sizeof(uint_16) |
add eax,[overlay] |
mov [edi+deflate_state.d_buf],eax |
mov eax,[edi+deflate_state.lit_bufsize] |
imul eax,3 ;1+sizeof(uint_16) |
add eax,[edi+deflate_state.pending_buf] |
mov [edi+deflate_state.l_buf],eax |
mov eax,[level] |
mov [edi+deflate_state.level],ax |
mov eax,[strategy] |
mov [edi+deflate_state.strategy],ax |
mov eax,[method] |
mov [edi+deflate_state.method],al |
stdcall deflateReset, ebx |
.end_f: |
zlib_debug 'deflateInit2_ strategy = %d',[strategy] |
ret |
endp |
; ========================================================================= |
;int (strm, dictionary, dictLength) |
; z_streamp strm; |
; const Bytef *dictionary; |
; uInt dictLength; |
align 4 |
proc deflateSetDictionary uses ebx edi, strm:dword, dictionary:dword, dictLength:dword |
locals |
; deflate_state *s; |
; uInt str, n; |
wrap dd ? ;int |
avail dd ? ;unsigned |
; z_const unsigned char *next; |
endl |
mov ebx,[strm] |
cmp ebx,Z_NULL |
je @f |
mov edi,[ebx+z_stream.state] |
cmp edi,Z_NULL |
je @f |
cmp dword[dictionary],Z_NULL |
je @f ;if (..==0 || ..==0 || ..==0) |
jmp .end0 |
@@: |
mov eax,Z_STREAM_ERROR |
jmp .end_f |
.end0: |
mov eax,[edi+deflate_state.wrap] |
mov [wrap],eax |
; if (wrap == 2 || (wrap == 1 && s->status != INIT_STATE) || s->lookahead) |
; return Z_STREAM_ERROR; |
; when using zlib wrappers, compute Adler-32 for provided dictionary |
; if (wrap == 1) |
; strm->adler = adler32(strm->adler, dictionary, dictLength); |
; s->wrap = 0; /* avoid computing Adler-32 in read_buf */ |
; if dictionary would fill window, just replace the history |
; if (dictLength >= s->w_size) { |
; if (wrap == 0) { /* already empty otherwise */ |
; CLEAR_HASH(s); |
; s->strstart = 0; |
; s->block_start = 0L; |
; s->insert = 0; |
; } |
; dictionary += dictLength - s->w_size; /* use the tail */ |
; dictLength = s->w_size; |
; } |
; insert dictionary into window and hash |
; avail = strm->avail_in; |
; next = strm->next_in; |
; strm->avail_in = dictLength; |
; strm->next_in = (z_const Bytef *)dictionary; |
; fill_window(s); |
; while (s->lookahead >= MIN_MATCH) { |
; str = s->strstart; |
; n = s->lookahead - (MIN_MATCH-1); |
; do { |
; UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); |
if FASTEST eq 0 |
; s->prev[str & s->w_mask] = s->head[s->ins_h]; |
end if |
; s->head[s->ins_h] = (Pos)str; |
; str++; |
; } while (--n); |
; s->strstart = str; |
; s->lookahead = MIN_MATCH-1; |
; fill_window(s); |
; } |
; s->strstart += s->lookahead; |
; s->block_start = (long)s->strstart; |
; s->insert = s->lookahead; |
; s->lookahead = 0; |
; s->match_length = s->prev_length = MIN_MATCH-1; |
; s->match_available = 0; |
; strm->next_in = next; |
; strm->avail_in = avail; |
; s->wrap = wrap; |
mov eax,Z_OK |
.end_f: |
ret |
endp |
; ========================================================================= |
;int (strm) |
; z_streamp strm; |
align 4 |
proc deflateResetKeep uses ebx edi, strm:dword |
; deflate_state *s; |
mov ebx,[strm] |
cmp ebx,Z_NULL |
je @f |
mov edi,[ebx+z_stream.state] |
cmp edi,Z_NULL |
je @f |
cmp dword[ebx+z_stream.zalloc],0 |
je @f |
cmp dword[ebx+z_stream.zfree],0 |
je @f ;if (..==0 || ..==0 || ..==0 || ..==0) |
jmp .end0 |
@@: |
mov eax,Z_STREAM_ERROR |
jmp .end_f |
.end0: |
mov dword[ebx+z_stream.total_out],0 |
mov dword[ebx+z_stream.total_in],0 |
mov dword[ebx+z_stream.msg],Z_NULL ;use zfree if we ever allocate msg dynamically |
mov word[ebx+z_stream.data_type],Z_UNKNOWN |
mov word[edi+deflate_state.pending],0 |
mov eax,[edi+deflate_state.pending_buf] |
mov [edi+deflate_state.pending_out],eax |
cmp dword[edi+deflate_state.wrap],0 |
jge @f ;if (..<0) |
neg dword[edi+deflate_state.wrap] |
inc dword[edi+deflate_state.wrap] ;was made negative by deflate(..., Z_FINISH) |
@@: |
mov eax,BUSY_STATE |
cmp dword[edi+deflate_state.wrap],0 |
je @f |
mov eax,INIT_STATE |
@@: |
mov dword[edi+deflate_state.status],eax |
stdcall adler32, 0, Z_NULL, 0 |
if GZIP eq 1 |
cmp dword[edi+deflate_state.wrap],2 |
jne @f |
stdcall calc_crc32, 0, Z_NULL, 0 |
@@: |
end if |
mov dword[ebx+z_stream.adler],eax |
mov dword[edi+deflate_state.last_flush],Z_NO_FLUSH |
stdcall _tr_init, edi |
mov eax,Z_OK |
.end_f: |
ret |
endp |
; ========================================================================= |
;int (strm) |
; z_streamp strm; |
align 4 |
proc deflateReset uses ebx, strm:dword |
mov ebx,[strm] |
;zlib_debug 'deflateReset' |
stdcall deflateResetKeep, ebx |
cmp eax,0 |
jne @f ;if (..==Z_OK) |
stdcall lm_init, [ebx+z_stream.state] |
@@: |
ret |
endp |
; ========================================================================= |
;int (strm, head) |
; z_streamp strm; |
; gz_headerp head; |
align 4 |
proc deflateSetHeader uses ebx, strm:dword, head:dword |
mov ebx,[strm] |
cmp ebx,Z_NULL |
je @f |
mov ebx,[ebx+z_stream.state] |
cmp ebx,Z_NULL |
jne .end0 |
@@: ;if (..==0 || ..==0) return .. |
mov eax,Z_STREAM_ERROR |
jmp .end_f |
.end0: |
cmp dword[ebx+deflate_state.wrap],2 |
je @f ;if (..!=..) return .. |
mov eax,Z_STREAM_ERROR |
jmp .end_f |
@@: |
mov eax,[head] |
mov [ebx+deflate_state.gzhead],eax |
mov eax,Z_OK |
.end_f: |
ret |
endp |
; ========================================================================= |
;int (strm, pending, bits) |
; unsigned *pending; |
; int *bits; |
; z_streamp strm; |
align 4 |
proc deflatePending uses ebx edi, strm:dword, pending:dword, bits:dword |
mov ebx,[strm] |
cmp ebx,Z_NULL |
je @f |
mov edi,[ebx+z_stream.state] |
cmp edi,Z_NULL |
jne .end0 |
@@: ;if (..==0 || ..==0) return .. |
mov eax,Z_STREAM_ERROR |
jmp .end_f |
.end0: |
cmp dword[pending],Z_NULL |
je @f ;if (..!=..) |
mov eax,[pending] |
movzx ebx,word[edi+deflate_state.pending] |
mov [eax],ebx |
@@: |
cmp dword[bits],Z_NULL |
je @f ;if (..!=..) |
mov eax,[bits] |
mov ebx,[edi+deflate_state.bi_valid] |
mov [eax],ebx |
@@: |
mov eax,Z_OK |
.end_f: |
ret |
endp |
; ========================================================================= |
;int (strm, bits, value) |
; z_streamp strm; |
; int bits; |
; int value; |
align 4 |
proc deflatePrime uses ebx edi, strm:dword, bits:dword, value:dword |
; int put; |
mov ebx,[strm] |
cmp ebx,Z_NULL |
je @f |
mov edi,[ebx+z_stream.state] ;s = strm.state |
cmp edi,Z_NULL |
jne .end0 |
@@: ;if (..==0 || ..==0) return .. |
mov eax,Z_STREAM_ERROR |
jmp .end_f |
.end0: |
; if ((Bytef *)(s->d_buf) < s->pending_out + ((Buf_size + 7) >> 3)) |
; return Z_BUF_ERROR; |
; do { |
; put = Buf_size - s->bi_valid; |
; if (put > bits) |
; put = bits; |
; s->bi_buf |= (uint_16)((value & ((1 << put) - 1)) << s->bi_valid); |
; s->bi_valid += put; |
; _tr_flush_bits(s); |
; value >>= put; |
; bits -= put; |
; } while (bits); |
mov eax,Z_OK |
.end_f: |
ret |
endp |
; ========================================================================= |
;int (strm, level, strategy) |
; z_streamp strm; |
; int level; |
; int strategy; |
align 4 |
proc deflateParams uses ebx edi, strm:dword, level:dword, strategy:dword |
; compress_func func; |
; int err = Z_OK; |
mov ebx,[strm] |
cmp ebx,Z_NULL |
je @f |
mov edi,[ebx+z_stream.state] ;s = strm.state |
cmp edi,Z_NULL |
jne .end0 |
@@: ;if (..==0 || ..==0) return .. |
mov eax,Z_STREAM_ERROR |
jmp .end_f |
.end0: |
if FASTEST eq 1 |
cmp dword[level],0 |
je @f ;if (..!=0) |
mov dword[level],1 |
@@: |
else |
cmp dword[level],Z_DEFAULT_COMPRESSION |
jne @f ;if (..==0) |
mov dword[level],6 |
@@: |
end if |
; if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { |
; return Z_STREAM_ERROR; |
; } |
; func = configuration_table[s->level].func; |
; if ((strategy != s->strategy || func != configuration_table[level].func) && |
; strm->total_in != 0) { |
; Flush the last buffer: |
; err = deflate(strm, Z_BLOCK); |
; if (err == Z_BUF_ERROR && s->pending == 0) |
; err = Z_OK; |
; } |
; if (s->level != level) { |
; s->level = level; |
; s->max_lazy_match = configuration_table[level].max_lazy; |
; s->good_match = configuration_table[level].good_length; |
; s->nice_match = configuration_table[level].nice_length; |
; s->max_chain_length = configuration_table[level].max_chain; |
; } |
; s->strategy = strategy; |
; return err; |
.end_f: |
ret |
endp |
; ========================================================================= |
;int (strm, good_length, max_lazy, nice_length, max_chain) |
; z_streamp strm; |
; int good_length; |
; int max_lazy; |
; int nice_length; |
; int max_chain; |
align 4 |
proc deflateTune uses ebx, strm:dword, good_length:dword, max_lazy:dword,\ |
nice_length:dword, max_chain:dword |
mov ebx,[strm] |
cmp ebx,Z_NULL |
je @f |
cmp dword[ebx+z_stream.state],Z_NULL |
jne .end0 |
@@: ;if (..==0 || ..==0) return .. |
mov eax,Z_STREAM_ERROR |
jmp .end_f |
.end0: |
mov ebx,[ebx+z_stream.state] ;s = strm.state |
mov eax,[good_length] |
mov [ebx+deflate_state.good_match],eax |
mov eax,[max_lazy] |
mov [ebx+deflate_state.max_lazy_match],eax |
mov eax,[nice_length] |
mov [ebx+deflate_state.nice_match],eax |
mov eax,[max_chain] |
mov [ebx+deflate_state.max_chain_length],eax |
mov eax,Z_OK |
.end_f: |
ret |
endp |
; ========================================================================= |
; For the default windowBits of 15 and memLevel of 8, this function returns |
; a close to exact, as well as small, upper bound on the compressed size. |
; They are coded as constants here for a reason--if the #define's are |
; changed, then this function needs to be changed as well. The return |
; value for 15 and 8 only works for those exact settings. |
; For any setting other than those defaults for windowBits and memLevel, |
; the value returned is a conservative worst case for the maximum expansion |
; resulting from using fixed blocks instead of stored blocks, which deflate |
; can emit on compressed data for some combinations of the parameters. |
; This function could be more sophisticated to provide closer upper bounds for |
; every combination of windowBits and memLevel. But even the conservative |
; upper bound of about 14% expansion does not seem onerous for output buffer |
; allocation. |
;uLong (strm, sourceLen) |
; z_streamp strm; |
; uLong sourceLen; |
align 4 |
proc deflateBound, strm:dword, sourceLen:dword |
; deflate_state *s; |
; uLong complen, wraplen; |
; Bytef *str; |
;zlib_debug 'deflateBound' |
; conservative upper bound for compressed data |
; complen = sourceLen + |
; ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 5; |
; if can't get parameters, return conservative bound plus zlib wrapper |
; if (strm == Z_NULL || strm->state == Z_NULL) |
; return complen + 6; |
; compute wrapper length |
; s = strm->state; |
; switch (s->wrap) { |
; case 0: /* raw deflate */ |
; wraplen = 0; |
; break; |
; case 1: /* zlib wrapper */ |
; wraplen = 6 + (s->strstart ? 4 : 0); |
; break; |
; case 2: /* gzip wrapper */ |
; wraplen = 18; |
; if (s->gzhead != Z_NULL) { /* user-supplied gzip header */ |
; if (s->gzhead->extra != Z_NULL) |
; wraplen += 2 + s->gzhead->extra_len; |
; str = s->gzhead->name; |
; if (str != Z_NULL) |
; do { |
; wraplen++; |
; } while (*str++); |
; str = s->gzhead->comment; |
; if (str != Z_NULL) |
; do { |
; wraplen++; |
; } while (*str++); |
; if (s->gzhead->hcrc) |
; wraplen += 2; |
; } |
; break; |
; default: /* for compiler happiness */ |
; wraplen = 6; |
; } |
; if not default parameters, return conservative bound |
; if (s->w_bits != 15 || s->hash_bits != 8 + 7) |
; return complen + wraplen; |
; default settings: return tight bound for that case |
; return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + |
; (sourceLen >> 25) + 13 - 6 + wraplen; |
.end_f: |
ret |
endp |
; ========================================================================= |
; Put a short in the pending buffer. The 16-bit value is put in MSB order. |
; IN assertion: the stream state is correct and there is enough room in |
; pending_buf. |
;void (s, b) |
; deflate_state *s; |
; uInt b; |
align 4 |
proc putShortMSB uses ebx ecx, s:dword, b:dword |
mov ebx,[s] |
mov ecx,[b] |
put_byte ebx, ch |
put_byte ebx, cl |
ret |
endp |
; ========================================================================= |
; 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 strm->next_out buffer and copying into it. |
; (See also read_buf()). |
;void (strm) |
; z_streamp strm; |
align 4 |
proc flush_pending uses eax ebx ecx edx, strm:dword |
;ecx - len |
;edx - deflate_state *s |
;ebx - strm |
;zlib_debug 'flush_pending' |
mov ebx,[strm] |
mov edx,[ebx+z_stream.state] |
stdcall _tr_flush_bits, edx |
movzx ecx,word[edx+deflate_state.pending] |
cmp cx,[ebx+z_stream.avail_out] |
jle @f ;if (..>..) |
movzx ecx,word[ebx+z_stream.avail_out] |
@@: |
cmp ecx,0 |
je @f |
stdcall zmemcpy, [ebx+z_stream.next_out], [edx+deflate_state.pending_out], ecx |
add [ebx+z_stream.next_out],ecx |
add [edx+deflate_state.pending_out],ecx |
add [ebx+z_stream.total_out],ecx |
sub [ebx+z_stream.avail_out],cx |
sub [edx+deflate_state.pending],cx |
cmp word[edx+deflate_state.pending],0 |
jne @f ;if (..==0) |
mov eax,[edx+deflate_state.pending_buf] |
mov [edx+deflate_state.pending_out],eax |
@@: |
ret |
endp |
; ========================================================================= |
;int (strm, flush) |
; z_streamp strm; |
; int flush; |
align 4 |
proc deflate uses ebx ecx edx edi esi, strm:dword, flush:dword |
locals |
old_flush dd ? ;int ;value of flush param for previous deflate call |
val dd ? |
endl |
mov ebx,[strm] |
zlib_debug 'deflate strm = %d',ebx |
cmp ebx,Z_NULL |
je @f |
mov edi,[ebx+z_stream.state] ;s = strm.state |
cmp edi,Z_NULL |
je @f |
cmp dword[flush],Z_BLOCK |
jg @f |
cmp dword[flush],0 |
jl @f ;if (..==0 || ..==0 || ..>.. || ..<0) |
jmp .end10 |
@@: |
mov eax,Z_STREAM_ERROR |
jmp .end_f |
.end10: |
cmp dword[ebx+z_stream.next_out],Z_NULL |
je .beg0 |
cmp dword[ebx+z_stream.next_in],Z_NULL |
jne @f |
cmp word[ebx+z_stream.avail_in],0 |
jne .beg0 |
@@: |
cmp dword[edi+deflate_state.status],FINISH_STATE |
jne .end0 |
cmp dword[flush],Z_FINISH |
je .end0 |
.beg0: ;if (..==0 || (..==0 && ..!=0) || (..=.. && ..!=..)) |
ERR_RETURN ebx, Z_STREAM_ERROR |
jmp .end_f |
.end0: |
cmp word[ebx+z_stream.avail_out],0 |
jne @f ;if (..==0) |
ERR_RETURN ebx, Z_BUF_ERROR |
jmp .end_f |
@@: |
mov dword[edi+deflate_state.strm],ebx ;just in case |
mov eax,[edi+deflate_state.last_flush] |
mov [old_flush],eax |
mov eax,[flush] |
mov [edi+deflate_state.last_flush],eax |
; Write the header |
cmp dword[edi+deflate_state.status],INIT_STATE |
jne .end2 ;if (..==..) |
if GZIP eq 1 |
cmp dword[edi+deflate_state.wrap],2 |
jne .end1 ;if (..==..) |
stdcall calc_crc32, 0, Z_NULL, 0 |
mov [ebx+z_stream.adler],eax |
put_byte edi, 31 |
put_byte edi, 139 |
put_byte edi, 8 |
cmp dword[edi+deflate_state.gzhead],Z_NULL |
jne .end3 ;if (..==0) |
put_byte edi, 0 |
put_dword edi, 0 |
xor cl,cl |
cmp word[edi+deflate_state.level],2 |
jge @f |
mov cl,4 |
@@: |
cmp word[edi+deflate_state.strategy],Z_HUFFMAN_ONLY |
jl @f |
mov cl,4 |
@@: |
cmp word[edi+deflate_state.level],9 |
jne @f |
mov cl,2 |
@@: ;..==.. ? 2 : (..>=.. || ..<.. ? 4 : 0) |
put_byte edi, cl |
put_byte edi, OS_CODE |
mov dword[edi+deflate_state.status],BUSY_STATE |
jmp .end2 |
.end3: ;else |
mov edx,[edi+deflate_state.gzhead] |
xor cl,cl |
cmp [edx+gz_header.text],0 |
je @f |
inc cl |
@@: |
cmp [edx+gz_header.hcrc],0 |
je @f |
add cl,2 |
@@: |
cmp [edx+gz_header.extra],Z_NULL |
je @f |
add cl,4 |
@@: |
cmp [edx+gz_header.name],Z_NULL |
je @f |
add cl,8 |
@@: |
cmp [edx+gz_header.comment],Z_NULL |
je @f |
add cl,16 |
@@: |
put_byte edi, cl |
mov ecx,[edx+gz_header.time] |
put_dword edi, ecx |
xor cl,cl |
cmp word[edi+deflate_state.level],2 |
jge @f |
mov cl,4 |
@@: |
cmp word[edi+deflate_state.strategy],Z_HUFFMAN_ONLY |
jl @f |
mov cl,4 |
@@: |
cmp word[edi+deflate_state.level],9 |
jne @f |
mov cl,2 |
@@: ;..==.. ? 2 : (..>=.. || ..<.. ? 4 : 0) |
put_byte edi, cl |
mov ecx,[edx+gz_header.os] |
put_byte edi, cl |
cmp dword[edx+gz_header.extra],Z_NULL |
je @f ;if (..!=0) |
mov ecx,[edx+gz_header.extra_len] |
put_byte edi, cl |
put_byte edi, ch |
@@: |
cmp dword[edx+gz_header.hcrc],0 |
je @f ;if (..) |
movzx eax,word[edi+deflate_state.pending] |
stdcall calc_crc32, [ebx+z_stream.adler],\ |
[edi+deflate_state.pending_buf], eax |
mov [ebx+z_stream.adler],eax |
@@: |
mov dword[edi+deflate_state.gzindex],0 |
mov dword[edi+deflate_state.status],EXTRA_STATE |
jmp .end2 |
.end1: ;else |
end if |
mov edx,[edi+deflate_state.w_bits] |
sub edx,8 |
shl edx,4 |
add edx,Z_DEFLATED |
shl edx,8 ;edx = header |
;esi = level_flags |
mov esi,3 |
cmp word[edi+deflate_state.strategy],Z_HUFFMAN_ONLY |
jl @f |
cmp word[edi+deflate_state.level],2 |
jge @f ;if (..>=.. || ..<..) |
xor esi,esi |
jmp .end4 |
@@: |
cmp word[edi+deflate_state.level],6 |
jge @f ;else if (..<..) |
mov esi,1 |
jmp .end4 |
@@: |
;;cmp word[edi+deflate_state.level],6 |
jne .end4 ;else if (..==..) |
mov esi,2 |
.end4: |
shl esi,6 |
or edx,esi |
cmp dword[edi+deflate_state.strstart],0 |
je @f ;if (..!=0) |
or edx,PRESET_DICT |
@@: |
mov esi,edx |
mov eax,edx |
xor edx,edx |
mov ecx,31 |
div ecx |
add esi,31 |
sub esi,edx ;esi = header |
mov dword[edi+deflate_state.status],BUSY_STATE |
stdcall putShortMSB, edi, esi |
; Save the adler32 of the preset dictionary: |
cmp dword[edi+deflate_state.strstart],0 |
je @f ;if (..!=0) |
mov ecx,[ebx+z_stream.adler] |
bswap ecx |
put_dword edi, ecx |
@@: |
stdcall calc_crc32, 0, Z_NULL, 0 |
mov [ebx+z_stream.adler],eax |
.end2: |
if GZIP eq 1 |
mov edx,[edi+deflate_state.gzhead] |
cmp dword[edi+deflate_state.status],EXTRA_STATE |
jne .end5 ;if (..==..) |
cmp dword[edx+gz_header.extra],Z_NULL |
je .end21 ;if (..!=..) |
movzx esi,word[edi+deflate_state.pending] |
;esi = beg ;start of bytes to update crc |
movzx ecx,word[edx+gz_header.extra_len] |
.cycle0: ;while (..<..) |
cmp dword[edi+deflate_state.gzindex],ecx |
jge .cycle0end |
movzx eax,word[edi+deflate_state.pending] |
cmp eax,[edi+deflate_state.pending_buf_size] |
jne .end24 ;if (..==..) |
mov dword[edx+gz_header.hcrc],0 |
je @f |
cmp [edi+deflate_state.pending],si |
jle @f ;if (.. && ..>..) |
movzx ecx,word[edi+deflate_state.pending] |
sub ecx,esi |
mov eax,[edi+deflate_state.pending_buf] |
add eax,esi |
stdcall calc_crc32, [ebx+z_stream.adler], eax, ecx |
mov [ebx+z_stream.adler],eax |
@@: |
stdcall flush_pending, ebx |
movzx esi,word[edi+deflate_state.pending] |
cmp esi,[edi+deflate_state.pending_buf_size] |
je .cycle0end ;if (..==..) break |
.end24: |
push ebx |
mov ebx,[edi+deflate_state.gzindex] |
add ebx,[edx+gz_header.extra] |
mov bl,[ebx] |
put_byte edi, bl |
pop ebx |
inc dword[edi+deflate_state.gzindex] |
jmp .cycle0 |
.cycle0end: |
mov dword[edx+gz_header.hcrc],0 |
je @f |
cmp [edi+deflate_state.pending],si |
jle @f ;if (.. && ..>..) |
movzx ecx,word[edi+deflate_state.pending] |
sub ecx,esi |
mov eax,[edi+deflate_state.pending_buf] |
add eax,esi |
stdcall calc_crc32, [ebx+z_stream.adler], eax, ecx |
mov [ebx+z_stream.adler],eax |
@@: |
mov eax,[edx+gz_header.extra_len] |
cmp dword[edi+deflate_state.gzindex],eax |
jne .end5 ;if (..==..) |
mov dword[edi+deflate_state.gzindex],0 |
mov dword[edi+deflate_state.status],NAME_STATE |
jmp .end5 |
.end21: ;else |
mov dword[edi+deflate_state.status],NAME_STATE |
.end5: |
cmp dword[edi+deflate_state.status],NAME_STATE |
jne .end6 ;if (..==..) |
cmp dword[edx+gz_header.name],Z_NULL |
je .end22 ;if (..!=..) |
movzx esi,word[edi+deflate_state.pending] |
;esi = beg ;start of bytes to update crc |
.cycle1: ;do |
movzx eax,word[edi+deflate_state.pending] |
cmp eax,[edi+deflate_state.pending_buf_size] |
jne .end25 ;if (..==..) |
mov dword[edx+gz_header.hcrc],0 |
je @f |
cmp [edi+deflate_state.pending],si |
jle @f ;if (.. && ..>..) |
movzx ecx,word[edi+deflate_state.pending] |
sub ecx,esi |
mov eax,[edi+deflate_state.pending_buf] |
add eax,esi |
stdcall calc_crc32, [ebx+z_stream.adler], eax, ecx |
mov [ebx+z_stream.adler],eax |
@@: |
stdcall flush_pending, ebx |
movzx esi,word[edi+deflate_state.pending] |
movzx eax,word[edi+deflate_state.pending] |
cmp eax,[edi+deflate_state.pending_buf_size] |
jne .end25 ;if (..==..) |
mov dword[val],1 |
jmp .cycle1end |
.end25: |
push ebx |
mov ebx,[edi+deflate_state.gzindex] |
add ebx,[edx+gz_header.name] |
movzx ebx,byte[ebx] |
mov [val],ebx |
inc dword[edi+deflate_state.gzindex] |
put_byte edi, bl |
pop ebx |
cmp dword[val],0 |
jne .cycle1 ;while (val != 0) |
.cycle1end: |
mov dword[edx+gz_header.hcrc],0 |
je @f |
cmp [edi+deflate_state.pending],si |
jle @f ;if (.. && ..>..) |
movzx ecx,word[edi+deflate_state.pending] |
sub ecx,esi |
mov eax,[edi+deflate_state.pending_buf] |
add eax,esi |
stdcall calc_crc32, [ebx+z_stream.adler], eax, ecx |
mov [ebx+z_stream.adler],eax |
@@: |
cmp dword[val],0 |
jne .end6 ;if (val == 0) |
mov dword[edi+deflate_state.gzindex],0 |
mov dword[edi+deflate_state.status],COMMENT_STATE |
jmp .end6 |
.end22: ;else |
mov dword[edi+deflate_state.status],COMMENT_STATE; |
.end6: |
cmp dword[edi+deflate_state.status],COMMENT_STATE |
jne .end7 ;if (..==..) |
cmp dword[edx+gz_header.comment],Z_NULL |
je .end23 ;if (..!=..) |
movzx esi,word[edi+deflate_state.pending] |
;esi = beg ;start of bytes to update crc |
.cycle2: ;do |
movzx eax,word[edi+deflate_state.pending] |
cmp eax,[edi+deflate_state.pending_buf_size] |
jne .end26 ;if (..==..) |
mov dword[edx+gz_header.hcrc],0 |
je @f |
cmp [edi+deflate_state.pending],si |
jle @f ;if (.. && ..>..) |
movzx ecx,word[edi+deflate_state.pending] |
sub ecx,esi |
mov eax,[edi+deflate_state.pending_buf] |
add eax,esi |
stdcall calc_crc32, [ebx+z_stream.adler], eax, ecx |
mov [ebx+z_stream.adler],eax |
@@: |
stdcall flush_pending, ebx |
movzx esi,word[edi+deflate_state.pending] |
movzx eax,word[edi+deflate_state.pending] |
cmp eax,[edi+deflate_state.pending_buf_size] |
jne .end26 ;if (..==..) |
mov dword[val],1 |
jmp .cycle2end |
.end26: |
push ebx |
mov ebx,[edi+deflate_state.gzindex] |
add ebx,[edx+gz_header.comment] |
movzx ebx,byte[ebx] |
mov [val],ebx |
inc dword[edi+deflate_state.gzindex] |
put_byte edi, bl |
pop ebx |
cmp dword[val],0 |
jne .cycle2 ;while (val != 0) |
.cycle2end: |
mov dword[edx+gz_header.hcrc],0 |
je @f |
cmp [edi+deflate_state.pending],si |
jle @f ;if (.. && ..>..) |
movzx ecx,word[edi+deflate_state.pending] |
sub ecx,esi |
mov eax,[edi+deflate_state.pending_buf] |
add eax,esi |
stdcall calc_crc32, [ebx+z_stream.adler], eax, ecx |
mov [ebx+z_stream.adler],eax |
@@: |
cmp dword[val],0 |
jne .end7 ;if (val == 0) |
mov dword[edi+deflate_state.status],HCRC_STATE |
jmp .end7 |
.end23: ;else |
mov dword[edi+deflate_state.status],HCRC_STATE |
.end7: |
cmp dword[edi+deflate_state.status],HCRC_STATE |
jne .end8 ;if (..==..) |
cmp dword[edx+gz_header.hcrc],0 |
je .end9 ;if (..) |
movzx ecx,word[edi+deflate_state.pending] |
add ecx,2 |
cmp ecx,[edi+deflate_state.pending_buf_size] |
jle @f ;if (..>..) |
stdcall flush_pending, ebx |
@@: |
movzx ecx,word[edi+deflate_state.pending] |
add ecx,2 |
cmp ecx,[edi+deflate_state.pending_buf_size] |
jg @f ;if (..<=..) |
mov ecx,[ebx+z_stream.adler] |
put_byte edi, cl |
put_byte edi, ch |
stdcall calc_crc32, 0, Z_NULL, 0 |
mov [ebx+z_stream.adler],eax |
mov dword[edi+deflate_state.status],BUSY_STATE |
@@: |
jmp .end8 |
.end9: ;else |
mov dword[edi+deflate_state.status],BUSY_STATE |
.end8: |
end if |
; Flush as much pending output as possible |
cmp word[edi+deflate_state.pending],0 |
je .end13 ;if (..!=0) |
stdcall flush_pending, ebx |
cmp word[ebx+z_stream.avail_out],0 |
jne @f ;if (..==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: |
mov dword[edi+deflate_state.last_flush],-1 |
mov eax,Z_OK |
jmp .end_f |
@@: |
; 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_BUF_ERROR. |
jmp @f |
.end13: |
cmp word[ebx+z_stream.avail_in],0 |
jne @f |
RANK dword[old_flush],esi |
RANK dword[flush],eax |
cmp eax,esi |
jg @f |
cmp dword[flush],Z_FINISH |
je @f ;else if (..==0 && ..<=.. && ..!=..) |
ERR_RETURN ebx, Z_BUF_ERROR |
jmp .end_f |
@@: |
; User must not provide more input after the first FINISH: |
cmp dword[edi+deflate_state.status],FINISH_STATE |
jne @f |
cmp word[ebx+z_stream.avail_in],0 |
je @f ;if (..==.. && ..!=0) |
ERR_RETURN ebx, Z_BUF_ERROR |
jmp .end_f |
@@: |
; Start a new block or continue the current one. |
cmp word[ebx+z_stream.avail_in],0 |
jne @f |
cmp dword[edi+deflate_state.lookahead],0 |
jne @f |
cmp dword[flush],Z_NO_FLUSH |
je .end11 |
cmp dword[edi+deflate_state.status],FINISH_STATE |
je .end11 |
@@: ;if (..!=0 || ..!=0 || (..!=.. && ..!=..)) |
;edx = bstate |
cmp word[edi+deflate_state.strategy],Z_HUFFMAN_ONLY |
jne @f |
stdcall deflate_huff, edi, [flush] |
jmp .end20 |
@@: |
cmp word[edi+deflate_state.strategy],Z_RLE |
jne @f |
stdcall deflate_rle, edi, [flush] |
jmp .end20 |
@@: |
movzx eax,word[edi+deflate_state.level] |
imul eax,sizeof.config_s |
add eax,configuration_table+config_s.co_func |
stdcall dword[eax], edi, [flush] |
.end20: |
mov edx,eax |
cmp edx,finish_started |
je @f |
cmp edx,finish_done |
je @f |
jmp .end18 |
@@: ;if (..==.. || ..==..) |
mov dword[edi+deflate_state.status],FINISH_STATE |
.end18: |
cmp edx,need_more |
je @f |
cmp edx,finish_started |
je @f |
jmp .end19 |
@@: ;if (..==.. || ..==..) |
cmp word[ebx+z_stream.avail_out],0 |
jne @f ;if (..==0) |
mov dword[edi+deflate_state.last_flush],-1 ;avoid BUF_ERROR next call, see above |
@@: |
mov eax,Z_OK |
jmp .end_f |
; 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. |
.end19: |
cmp edx,block_done |
jne .end11 ;if (..==..) |
cmp dword[flush],Z_PARTIAL_FLUSH |
jne @f ;if (..==..) |
stdcall _tr_align, edi |
jmp .end16 |
@@: |
cmp dword[flush],Z_BLOCK |
je .end16 ;else if (..!=..) ;FULL_FLUSH or SYNC_FLUSH |
stdcall _tr_stored_block, edi, 0, 0, 0 |
; For a full flush, this empty block will be recognized |
; as a special marker by inflate_sync(). |
cmp dword[flush],Z_FULL_FLUSH |
jne .end16 ;if (..==..) |
CLEAR_HASH edi ;forget history |
cmp dword[edi+deflate_state.lookahead],0 |
jne .end16 ;if (..==0) |
mov dword[edi+deflate_state.strstart],0 |
mov dword[edi+deflate_state.block_start],0 |
mov dword[edi+deflate_state.insert],0 |
.end16: |
stdcall flush_pending, ebx |
cmp word[ebx+z_stream.avail_out],0 |
jne .end11 ;if (..==0) |
mov dword[edi+deflate_state.last_flush],-1 ;avoid BUF_ERROR at next call, see above |
mov eax,Z_OK |
jmp .end_f |
.end11: |
cmp word[ebx+z_stream.avail_out],0 |
jg @f |
zlib_debug 'bug2' ;Assert(..>0) |
@@: |
cmp dword[flush],Z_FINISH |
je @f ;if (..!=0) |
mov eax,Z_OK |
jmp .end_f |
@@: |
cmp dword[edi+deflate_state.wrap],0 |
jg @f ;if (..<=0) |
mov eax,Z_STREAM_END |
jmp .end_f |
@@: |
; Write the trailer |
if GZIP eq 1 |
cmp dword[edi+deflate_state.wrap],2 |
jne @f ;if (..==..) |
mov ecx,[ebx+z_stream.adler] |
put_dword edi, ecx |
mov ecx,[ebx+z_stream.total_in] |
put_dword edi, ecx |
jmp .end17 |
@@: ;else |
end if |
mov ecx,[ebx+z_stream.adler] |
bswap ecx |
put_dword edi, ecx |
.end17: |
stdcall flush_pending, ebx |
; If avail_out is zero, the application will call deflate again |
; to flush the rest. |
cmp word[edi+deflate_state.pending],0 |
jle @f ;if (..>0) ;write the trailer only once! |
neg word[edi+deflate_state.pending] |
inc word[edi+deflate_state.pending] |
@@: |
mov eax,Z_OK |
cmp word[edi+deflate_state.pending],0 |
je .end_f |
mov eax,Z_STREAM_END |
.end_f: |
zlib_debug ' deflate.ret = %d',eax |
ret |
endp |
; ========================================================================= |
;int (strm) |
; z_streamp strm; |
align 4 |
proc deflateEnd uses ebx ecx edx, strm:dword |
mov ebx,[strm] |
zlib_debug 'deflateEnd' |
cmp ebx,Z_NULL |
je @f |
mov edx,[ebx+z_stream.state] |
cmp edx,Z_NULL |
jne .end0 |
@@: ;if (..==0 || ..==0) return .. |
mov eax,Z_STREAM_ERROR |
jmp .end_f |
.end0: |
mov ecx,[edx+deflate_state.status] |
cmp ecx,INIT_STATE |
je @f |
cmp ecx,EXTRA_STATE |
je @f |
cmp ecx,NAME_STATE |
je @f |
cmp ecx,COMMENT_STATE |
je @f |
cmp ecx,HCRC_STATE |
je @f |
cmp ecx,BUSY_STATE |
je @f |
cmp ecx,FINISH_STATE |
je @f ;if (..!=.. && ..!=.. && ..!=.. && ..!=.. && ..!=.. && ..!=.. && ..!=..) |
mov eax,Z_STREAM_ERROR |
jmp .end_f |
@@: |
; Deallocate in reverse order of allocations: |
TRY_FREE ebx, dword[edx+deflate_state.pending_buf] |
TRY_FREE ebx, dword[edx+deflate_state.head] |
TRY_FREE ebx, dword[edx+deflate_state.prev] |
TRY_FREE ebx, dword[edx+deflate_state.window] |
ZFREE ebx, dword[ebx+z_stream.state] |
mov dword[ebx+z_stream.state],Z_NULL |
mov eax,Z_DATA_ERROR |
cmp ecx,BUSY_STATE |
je .end_f |
mov eax,Z_OK |
.end_f: |
ret |
endp |
; ========================================================================= |
; 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). |
;int (dest, source) |
; z_streamp dest; |
; z_streamp source; |
align 4 |
proc deflateCopy uses edx edi esi, dest:dword, source:dword |
locals |
overlay dd ? ;uint_16p |
endl |
;edi = ds; deflate_state* |
;esi = ss; deflate_state* |
mov esi,[source] |
cmp esi,Z_NULL |
je @f |
mov edx,[dest] |
cmp edx,Z_NULL |
je @f |
mov esi,[esi+z_stream.state] |
cmp esi,Z_NULL |
jne .end0 |
@@: ;if (..==0 || ..==0 || ..==0) |
mov eax,Z_STREAM_ERROR |
jmp .end_f |
.end0: |
stdcall zmemcpy, edx, [source], sizeof.z_stream |
ZALLOC edx, 1, sizeof.deflate_state |
cmp eax,0 |
jne @f ;if (..==0) return .. |
mov eax,Z_MEM_ERROR |
jmp .end_f |
@@: |
mov edi,eax |
mov [edx+z_stream.state],eax |
stdcall zmemcpy, edi, esi, sizeof.deflate_state |
mov dword[edi+deflate_state.strm],edx |
ZALLOC edx, [edi+deflate_state.w_size], 2 ;2*sizeof.db |
mov dword[edi+deflate_state.window],eax |
ZALLOC edx, [edi+deflate_state.w_size], 4 ;sizeof.dd |
mov dword[edi+deflate_state.prev],eax |
ZALLOC edx, [edi+deflate_state.hash_size], 4 ;sizeof.dd |
mov dword[edi+deflate_state.head],eax |
ZALLOC edx, [edi+deflate_state.lit_bufsize], 4 ;sizeof.dw+2 |
mov [overlay],eax |
mov dword[edi+deflate_state.pending_buf],eax |
cmp dword[edi+deflate_state.window],Z_NULL |
je @f |
cmp dword[edi+deflate_state.prev],Z_NULL |
je @f |
cmp dword[edi+deflate_state.head],Z_NULL |
je @f |
cmp dword[edi+deflate_state.pending_buf],Z_NULL |
jne .end1 |
@@: ;if (..==0 || ..==0 || ..==0 || ..==0) |
stdcall deflateEnd, edx |
mov eax,Z_MEM_ERROR |
jmp .end_f |
.end1: |
; following zmemcpy do not work for 16-bit MSDOS |
mov eax,[edi+deflate_state.w_size] |
shl eax,1 ;*= 2*sizeof.db |
stdcall zmemcpy, [edi+deflate_state.window], [esi+deflate_state.window], eax |
; zmemcpy((voidpf)ds->prev, (voidpf)ss->prev, ds->w_size * sizeof(Pos)); |
; zmemcpy((voidpf)ds->head, (voidpf)ss->head, ds->hash_size * sizeof(Pos)); |
; zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); |
; ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); |
; ds->d_buf = overlay + ds->lit_bufsize/sizeof(uint_16); |
; ds->l_buf = ds->pending_buf + (1+sizeof(uint_16))*ds->lit_bufsize; |
mov eax,edi |
add eax,deflate_state.dyn_ltree |
mov [edi+deflate_state.l_desc.dyn_tree],eax |
add eax,deflate_state.dyn_dtree-deflate_state.dyn_ltree |
mov [edi+deflate_state.d_desc.dyn_tree],eax |
add eax,deflate_state.bl_tree-deflate_state.dyn_dtree |
mov [edi+deflate_state.bl_desc.dyn_tree],eax |
mov eax,Z_OK |
.end_f: |
ret |
endp |
; =========================================================================== |
; 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 strm->next_in buffer and copying from it. |
; (See also flush_pending()). |
;int (strm, buf, size) |
; z_streamp strm; |
; Bytef *buf; |
; unsigned size; |
align 4 |
proc read_buf uses ebx ecx, strm:dword, buf:dword, size:dword |
mov ebx,[strm] |
movzx eax,word[ebx+z_stream.avail_in] |
cmp eax,[size] |
jle @f ;if (..>..) |
mov eax,[size] |
@@: |
cmp eax,0 |
jg @f |
xor eax,eax |
jmp .end_f ;if (..==0) return 0 |
@@: |
sub [ebx+z_stream.avail_in],ax |
stdcall zmemcpy, [buf],[ebx+z_stream.next_in],eax |
mov ecx,[ebx+z_stream.state] |
cmp [ecx+deflate_state.wrap],1 |
jne @f ;if (..==..) |
push eax |
stdcall adler32, [ebx+z_stream.adler], [buf], eax |
mov [ebx+z_stream.adler],eax |
pop eax |
jmp .end0 |
@@: |
if GZIP eq 1 |
cmp [ecx+deflate_state.wrap],2 |
jne .end0 ;else if (..==..) |
push eax |
stdcall calc_crc32, [ebx+z_stream.adler], [buf], eax |
mov [ebx+z_stream.adler],eax |
pop eax |
end if |
.end0: |
add [ebx+z_stream.next_in],eax |
add [ebx+z_stream.total_in],eax |
.end_f: |
;zlib_debug ' read_buf.ret = %d',eax |
ret |
endp |
; =========================================================================== |
; Initialize the "longest match" routines for a new zlib stream |
;void (s) |
; deflate_state *s |
align 4 |
proc lm_init uses eax ebx edi, s:dword |
mov edi,[s] |
mov eax,[edi+deflate_state.w_size] |
shl eax,1 |
mov [edi+deflate_state.window_size],eax |
CLEAR_HASH edi |
; Set the default configuration parameters: |
movzx eax,word[edi+deflate_state.level] |
imul eax,sizeof.config_s |
add eax,configuration_table |
movzx ebx,word[eax+config_s.max_lazy] |
mov [edi+deflate_state.max_lazy_match],ebx |
movzx ebx,word[eax+config_s.good_length] |
mov [edi+deflate_state.good_match],ebx |
movzx ebx,word[eax+config_s.nice_length] |
mov [edi+deflate_state.nice_match],ebx |
movzx ebx,word[eax+config_s.max_chain] |
mov [edi+deflate_state.max_chain_length],ebx |
mov dword[edi+deflate_state.strstart],0 |
mov dword[edi+deflate_state.block_start],0 |
mov dword[edi+deflate_state.lookahead],0 |
mov dword[edi+deflate_state.insert],0 |
mov dword[edi+deflate_state.prev_length],MIN_MATCH-1 |
mov dword[edi+deflate_state.match_length],MIN_MATCH-1 |
mov dword[edi+deflate_state.match_available],0 |
mov dword[edi+deflate_state.ins_h],0 |
if FASTEST eq 0 |
;if ASMV |
; call match_init ;initialize the asm code |
;end if |
end if |
ret |
endp |
;uInt (s, cur_match) |
; deflate_state *s; |
; IPos cur_match; /* current match */ |
align 4 |
proc longest_match uses ebx ecx edx edi esi, s:dword, cur_match:dword |
if FASTEST eq 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. |
;#ifndef ASMV |
; For 80x86 and 680x0, an optimized version will be provided in match.asm or |
; match.S. The code will be functionally equivalent. |
; unsigned chain_length = s->max_chain_length;/* max hash chain length */ |
; register Bytef *scan = s->window + s->strstart; /* current string */ |
; register Bytef *match; /* matched string */ |
; register int len; /* length of current match */ |
; int best_len = s->prev_length; /* best match length so far */ |
; int nice_match = s->nice_match; /* stop if match long enough */ |
; IPos limit = s->strstart > (IPos)MAX_DIST(s) ? |
; s->strstart - (IPos)MAX_DIST(s) : NIL; |
; Stop when cur_match becomes <= limit. To simplify the code, |
; we prevent matches with the string of window index 0. |
; Posf *prev = s->prev; |
; uInt wmask = s->w_mask; |
if UNALIGNED_OK eq 1 |
; Compare two bytes at a time. Note: this is not always beneficial. |
; Try with and without -DUNALIGNED_OK to check. |
; register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; |
; register uint_16 scan_start = *(uint_16p*)scan; |
; register uint_16 scan_end = *(uint_16p*)(scan+best_len-1); |
else |
; register Bytef *strend = s->window + s->strstart + MAX_MATCH; |
; register Byte scan_end1 = scan[best_len-1]; |
; register Byte scan_end = scan[best_len]; |
end if |
; The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. |
; It is easy to get rid of this optimization if necessary. |
; Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); |
; 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 ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; |
; Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); |
; do { |
; Assert(cur_match < s->strstart, "no future"); |
; match = s->window + cur_match; |
; Skip to next match if the match length cannot increase |
; or if the match length is less than 2. Note that the checks below |
; for insufficient lookahead only occur occasionally for performance |
; reasons. Therefore uninitialized memory will be accessed, and |
; conditional jumps will be made that depend on those values. |
; However the length of the match is limited to the lookahead, so |
; the output of deflate is not affected by the uninitialized values. |
if ((UNALIGNED_OK eq 1) & MAX_MATCH == 258) |
; This code assumes sizeof(unsigned short) == 2. Do not use |
; UNALIGNED_OK if your compiler uses a different size. |
; if (*(uint_16p*)(match+best_len-1) != scan_end || |
; *(uint_16p*)match != scan_start) continue; |
; 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 and that HASH_BITS >= 8. Compare 2 bytes at a time at |
; strstart+3, +5, ... up to strstart+257. We check for insufficient |
; lookahead only every 4th comparison; the 128th check will be made |
; at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is |
; necessary to put more guard bytes at the end of the window, or |
; to check more often for insufficient lookahead. |
; Assert(scan[2] == match[2], "scan[2]?"); |
; scan++, match++; |
; do { |
; } while (*(uint_16p*)(scan+=2) == *(uint_16p*)(match+=2) && |
; *(uint_16p*)(scan+=2) == *(uint_16p*)(match+=2) && |
; *(uint_16p*)(scan+=2) == *(uint_16p*)(match+=2) && |
; *(uint_16p*)(scan+=2) == *(uint_16p*)(match+=2) && |
; scan < strend); |
; The funny "do {}" generates better code on most compilers |
; Here, scan <= window+strstart+257 |
; Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); |
; if (*scan == *match) scan++; |
; len = (MAX_MATCH - 1) - (int)(strend-scan); |
; scan = strend - (MAX_MATCH-1); |
else ;UNALIGNED_OK |
; if (match[best_len] != scan_end || |
; match[best_len-1] != scan_end1 || |
; *match != *scan || |
; *++match != 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 and that HASH_BITS >= 8. |
; scan += 2, match++; |
; Assert(*scan == *match, "match[2]?"); |
; We check for insufficient lookahead only every 8th comparison; |
; the 256th check will be made at strstart+258. |
; do { |
; } while (*++scan == *++match && *++scan == *++match && |
; *++scan == *++match && *++scan == *++match && |
; *++scan == *++match && *++scan == *++match && |
; *++scan == *++match && *++scan == *++match && |
; scan < strend); |
; Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); |
; len = MAX_MATCH - (int)(strend - scan); |
; scan = strend - MAX_MATCH; |
end if ;UNALIGNED_OK |
; if (len > best_len) { |
; s->match_start = cur_match; |
; best_len = len; |
; if (len >= nice_match) break; |
if UNALIGNED_OK eq 1 |
; scan_end = *(uint_16p*)(scan+best_len-1); |
else |
; scan_end1 = scan[best_len-1]; |
; scan_end = scan[best_len]; |
end if |
; } |
; } while ((cur_match = prev[cur_match & wmask]) > limit |
; && --chain_length != 0); |
; if ((uInt)best_len <= s->lookahead) return (uInt)best_len; |
; return s->lookahead; |
;end if /* ASMV */ |
else ;FASTEST |
; --------------------------------------------------------------------------- |
; Optimized version for FASTEST only |
mov edx,[s] |
;zlib_debug 'longest_match' |
; The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. |
; It is easy to get rid of this optimization if necessary. |
if MAX_MATCH <> 258 |
cmp dword[edx+deflate_state.hash_bits],8 |
jge @f |
zlib_debug 'Code too clever' ;Assert(..>=.. && ..==..) |
@@: |
end if |
mov eax,[edx+deflate_state.window_size] |
sub eax,MIN_LOOKAHEAD |
cmp [edx+deflate_state.strstart],eax |
jle @f |
zlib_debug 'need lookahead' ;Assert(..<=..) |
@@: |
mov eax,[edx+deflate_state.strstart] |
cmp [cur_match],eax |
jl @f |
zlib_debug 'no future' ;Assert(..<..) |
@@: |
mov esi,[edx+deflate_state.window] |
mov edi,esi |
add esi,[cur_match] |
add edi,[edx+deflate_state.strstart] |
;edi = scan |
;esi = match |
; Return failure if the match length is less than 2: |
lodsw |
cmp ax,word[edi] |
je @f ;if (word[edi] != word[esi]) return |
mov eax,MIN_MATCH-1 |
jmp .end_f |
@@: |
; 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 and that HASH_BITS >= 8. |
add edi,2 |
mov al,byte[edi] |
cmp al,byte[esi] |
je @f |
zlib_debug 'match[2]?' ;Assert(..==..) |
@@: |
; We check for insufficient lookahead only every 8th comparison; |
; the 256th check will be made at strstart+258. |
mov ebx,edi |
mov ecx,MAX_MATCH |
align 4 |
@@: |
lodsb |
scasb |
loope @b |
mov eax,[edx+deflate_state.window_size] |
dec eax |
add eax,[edx+deflate_state.window] |
cmp edi,eax |
jle @f |
zlib_debug 'wild scan' ;Assert(..<=..) |
@@: |
sub edi,ebx |
;edi = len |
cmp edi,MIN_MATCH |
jge @f ;if (..<..) |
mov eax,MIN_MATCH-1 |
jmp .end_f |
@@: |
mov eax,[cur_match] |
mov [edx+deflate_state.match_start],eax |
mov eax,[edx+deflate_state.lookahead] |
cmp edi,eax |
jg @f ;if (len <= s.lookahead) ? len : s.lookahead |
mov eax,edi |
@@: |
end if ;FASTEST |
.end_f: |
;zlib_debug ' longest_match.ret = %d',eax |
ret |
endp |
; =========================================================================== |
; Check that the match at match_start is indeed a match. |
;void (s, start, match, length) |
; deflate_state *s; |
; IPos start, match; |
; int length; |
align 4 |
proc check_match, s:dword, start:dword, p3match:dword, length:dword |
if DEBUG eq 1 |
; check that the match is indeed a match |
; if (zmemcmp(s->window + match, |
; s->window + start, length) != EQUAL) { |
; fprintf(stderr, " start %u, match %u, length %d\n", |
; start, match, length); |
; do { |
; fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); |
; } while (--length != 0); |
; z_error("invalid match"); |
; } |
; if (z_verbose > 1) { |
; fprintf(stderr,"\\[%d,%d]", start-match, length); |
; do { putc(s->window[start++], stderr); } while (--length != 0); |
; } |
end if ;DEBUG |
ret |
endp |
; =========================================================================== |
; Fill the window when the lookahead becomes insufficient. |
; Updates strstart and lookahead. |
; IN assertion: lookahead < MIN_LOOKAHEAD |
; OUT assertions: strstart <= 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). |
;void (s) |
; deflate_state *s |
align 4 |
proc fill_window, s:dword |
pushad |
;esi = p, str, curr |
;ebx = more ;Amount of free space at the end of the window. |
;Объем свободного пространства в конце окна. |
;ecx = wsize ;uInt |
;edx = s.strm |
;zlib_debug 'fill_window' |
mov edi,[s] |
cmp dword[edi+deflate_state.lookahead],MIN_LOOKAHEAD |
jl @f |
zlib_debug 'already enough lookahead' ;Assert(..<..) |
@@: |
mov ecx,[edi+deflate_state.w_size] |
mov edx,[edi+deflate_state.strm] |
.cycle0: ;do |
;zlib_debug 'do' |
mov ebx,[edi+deflate_state.window_size] |
sub ebx,[edi+deflate_state.lookahead] |
sub ebx,[edi+deflate_state.strstart] |
; If the window is almost full and there is insufficient lookahead, |
; move the upper half to the lower one to make room in the upper half. |
MAX_DIST edi |
add eax,ecx |
cmp [edi+deflate_state.strstart],eax |
jl .end0 ;if (..>=..) |
push ecx |
mov eax,[edi+deflate_state.window] |
add eax,ecx |
stdcall zmemcpy, [edi+deflate_state.window], eax |
sub [edi+deflate_state.match_start],ecx |
sub [edi+deflate_state.strstart],ecx ;we now have strstart >= MAX_DIST |
sub [edi+deflate_state.block_start],ecx |
; 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.) |
push ebx ecx |
;ebx = wsize |
;ecx = n |
mov ebx,ecx |
mov ecx,[edi+deflate_state.hash_size] |
mov esi,ecx |
shl esi,2 |
add esi,[edi+deflate_state.head] |
.cycle1: ;do |
sub esi,4 |
mov eax,[esi] |
mov dword[esi],NIL |
cmp eax,ebx |
jl @f |
sub eax,ebx |
mov dword[esi],eax |
@@: |
loop .cycle1 ;while (..) |
mov ecx,ebx |
if FASTEST eq 0 |
mov esi,ecx |
shl esi,2 |
add esi,[edi+deflate_state.prev] |
.cycle2: ;do |
sub esi,4 |
mov eax,[esi] |
mov dword[esi],NIL |
cmp eax,ebx |
jl @f |
sub eax,ebx |
mov dword[esi],eax |
@@: |
; If n is not on any hash chain, prev[n] is garbage but |
; its value will never be used. |
loop .cycle2 ;while (..) |
end if |
pop ecx ebx |
add ebx,ecx |
.end0: |
cmp word[edx+z_stream.avail_in],0 |
je .cycle0end ;if (..==0) break |
; If there was no sliding: |
; strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && |
; more == window_size - lookahead - strstart |
; => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) |
; => more >= window_size - 2*WSIZE + 2 |
; In the BIG_MEM or MMAP case (not yet supported), |
; window_size == input_size + MIN_LOOKAHEAD && |
; strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. |
; Otherwise, window_size == 2*WSIZE so more >= 2. |
; If there was sliding, more >= WSIZE. So in all cases, more >= 2. |
cmp ebx,2 |
jge @f |
zlib_debug 'more < 2' ;Assert(..>=..) |
@@: |
mov eax,[edi+deflate_state.window] |
add eax,[edi+deflate_state.strstart] |
add eax,[edi+deflate_state.lookahead] |
stdcall read_buf, edx, eax, ebx |
add [edi+deflate_state.lookahead],eax |
; Initialize the hash value now that we have some input: |
mov eax,[edi+deflate_state.lookahead] |
add eax,[edi+deflate_state.insert] |
cmp eax,MIN_MATCH |
jl .end1 ;if (..>=..) |
mov esi,[edi+deflate_state.strstart] |
sub esi,[edi+deflate_state.insert] |
;esi = str |
mov eax,[edi+deflate_state.window] |
add eax,esi |
mov [edi+deflate_state.ins_h],eax |
inc eax |
movzx eax,byte[eax] |
UPDATE_HASH edi, [edi+deflate_state.ins_h], eax |
if MIN_MATCH <> 3 |
; Call UPDATE_HASH() MIN_MATCH-3 more times |
end if |
.cycle3: ;while (..) |
cmp dword[edi+deflate_state.insert],0 |
je .end1 |
mov eax,esi |
add eax,MIN_MATCH-1 |
add eax,[edi+deflate_state.window] |
movzx eax,byte[eax] |
UPDATE_HASH edi, [edi+deflate_state.ins_h], eax |
if FASTEST eq 0 |
mov eax,[edi+deflate_state.ins_h] |
shl eax,2 |
add eax,[edi+deflate_state.head] |
push ebx |
mov ebx,[edi+deflate_state.w_mask] |
and ebx,esi |
shl ebx,2 |
add ebx,[edi+deflate_state.prev] |
mov eax,[eax] |
mov [ebx],eax |
pop ebx |
end if |
mov eax,[edi+deflate_state.ins_h] |
shl eax,2 |
add eax,[edi+deflate_state.head] |
mov [eax],esi |
inc esi |
dec dword[edi+deflate_state.insert] |
mov eax,[edi+deflate_state.lookahead] |
add eax,[edi+deflate_state.insert] |
cmp eax,MIN_MATCH |
jl .end1 ;if (..<..) break |
jmp .cycle3 |
.end1: |
; 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. |
cmp dword[edi+deflate_state.lookahead],MIN_LOOKAHEAD |
jge .cycle0end |
cmp word[edx+z_stream.avail_in],0 |
jne .cycle0 |
.cycle0end: ;while (..<.. && ..!=..) |
; If the WIN_INIT bytes after the end of the current data have never been |
; written, then zero those bytes in order to avoid memory check reports of |
; the use of uninitialized (or uninitialised as Julian writes) bytes by |
; the longest match routines. Update the high water mark for the next |
; time through here. WIN_INIT is set to MAX_MATCH since the longest match |
; routines allow scanning to strstart + MAX_MATCH, ignoring lookahead. |
mov eax,[edi+deflate_state.window_size] |
cmp [edi+deflate_state.high_water],eax |
jge .end2 ;if (..<..) |
mov esi,[edi+deflate_state.lookahead] |
add esi,[edi+deflate_state.strstart] |
;esi = curr |
cmp [edi+deflate_state.high_water],esi |
jge .end3 ;if (..<..) |
; Previous high water mark below current data -- zero WIN_INIT |
; bytes or up to end of window, whichever is less. |
mov eax,[edi+deflate_state.window_size] |
sub eax,esi |
cmp eax,WIN_INIT |
jle @f ;if (..>..) |
mov eax,WIN_INIT |
@@: |
mov edx,[edi+deflate_state.window] |
add edx,esi |
stdcall zmemzero, edx, eax |
add eax,esi |
mov [edi+deflate_state.high_water],eax |
jmp .end2 |
.end3: ;else if (..<..) |
mov eax,esi |
add eax,WIN_INIT |
cmp [edi+deflate_state.high_water],eax |
jge .end2 |
; High water mark at or above current data, but below current data |
; plus WIN_INIT -- zero out to current data plus WIN_INIT, or up |
; to end of window, whichever is less. |
;eax = esi+WIN_INIT |
sub eax,[edi+deflate_state.high_water] |
mov edx,[edi+deflate_state.window_size] |
sub edx,[edi+deflate_state.high_water] |
cmp eax,edx ;if (..>..) |
jle @f |
mov eax,edx |
@@: |
mov edx,[edi+deflate_state.window] |
add edx,[edi+deflate_state.high_water] |
stdcall zmemzero, edx, eax |
add [edi+deflate_state.high_water],eax |
.end2: |
mov eax,[edi+deflate_state.window_size] |
sub eax,MIN_LOOKAHEAD |
cmp [edi+deflate_state.strstart],eax |
jle @f |
zlib_debug 'not enough room for search' ;Assert(..<=..) |
@@: |
popad |
ret |
endp |
; =========================================================================== |
; Flush the current block, with given end-of-file flag. |
; IN assertion: strstart is set to the end of the current match. |
macro FLUSH_BLOCK_ONLY s, last |
{ |
local .end0 |
push dword last |
mov eax,[s+deflate_state.strstart] |
sub eax,[s+deflate_state.block_start] |
push eax |
xor eax,eax |
cmp dword[s+deflate_state.block_start],0 |
jl .end0 |
mov eax,[s+deflate_state.block_start] |
add eax,[s+deflate_state.window] |
.end0: |
stdcall _tr_flush_block, s, eax |
mov eax,[s+deflate_state.strstart] |
mov [s+deflate_state.block_start],eax |
stdcall flush_pending, [s+deflate_state.strm] |
; Tracev((stderr,"[FLUSH]")); |
} |
; Same but force premature exit if necessary. |
macro FLUSH_BLOCK s, last |
{ |
local .end0 |
FLUSH_BLOCK_ONLY s, last |
mov eax,[s+deflate_state.strm] |
cmp word[eax+z_stream.avail_out],0 |
jne .end0 ;if (..==0) |
if last eq 1 |
mov eax,finish_started |
else |
mov eax,need_more |
end if |
jmp .end_f |
.end0: |
} |
; =========================================================================== |
; 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. |
;block_state (s, flush) |
; deflate_state *s; |
; int flush; |
align 4 |
proc deflate_stored uses ebx ecx edi, s:dword, flush:dword |
; Stored blocks are limited to 0xffff bytes, pending_buf is limited |
; to pending_buf_size, and each stored block has a 5 byte header: |
mov edi,[s] |
zlib_debug 'deflate_stored' |
mov ecx,0xffff |
mov eax,[edi+deflate_state.pending_buf_size] |
sub eax,5 |
cmp ecx,eax |
jle @f ;if (..>..) |
mov ecx,eax |
@@: |
;ecx = max_block_size |
; Copy as much as possible from input to output: |
.cycle0: ;for (;;) { |
; Fill the window as much as possible: |
cmp dword[edi+deflate_state.lookahead],1 |
jg .end0 ;if (..<=..) |
; Assert(s->strstart < s->w_size+MAX_DIST(s) || |
; s->block_start >= (long)s->w_size, "slide too late"); |
stdcall fill_window, edi |
cmp dword[edi+deflate_state.lookahead],0 |
jne @f |
cmp dword[flush],Z_NO_FLUSH |
jne @f ;if (..==0 && ..==..) |
mov eax,need_more |
jmp .end_f |
@@: |
cmp dword[edi+deflate_state.lookahead],0 |
je .cycle0end ;if (..==0) break ;flush the current block |
.end0: |
; Assert(s->block_start >= 0, "block gone"); |
mov eax,[edi+deflate_state.lookahead] |
add [edi+deflate_state.strstart],eax |
mov dword[edi+deflate_state.lookahead],0 |
; Emit a stored block if pending_buf will be full: |
mov ebx,[edi+deflate_state.block_start] |
add ebx,ecx |
cmp dword[edi+deflate_state.strstart],0 |
je @f |
cmp [edi+deflate_state.strstart],ebx |
jl .end1 |
@@: ;if (..==0 || ..>=..) |
; strstart == 0 is possible when wraparound on 16-bit machine |
mov eax,[edi+deflate_state.strstart] |
sub eax,ebx |
mov [edi+deflate_state.lookahead],eax |
mov [edi+deflate_state.strstart],ebx |
FLUSH_BLOCK edi, 0 |
.end1: |
; Flush if we may have to slide, otherwise block_start may become |
; negative and the data will be gone: |
MAX_DIST edi |
mov ebx,[edi+deflate_state.strstart] |
sub ebx,[edi+deflate_state.block_start] |
cmp ebx,eax |
jl .cycle0 ;if (..>=..) |
FLUSH_BLOCK edi, 0 |
jmp .cycle0 |
align 4 |
.cycle0end: |
mov dword[edi+deflate_state.insert],0 |
cmp dword[flush],Z_FINISH |
jne @f ;if (..==..) |
FLUSH_BLOCK edi, 1 |
mov eax,finish_done |
jmp .end_f |
@@: |
mov eax,[edi+deflate_state.block_start] |
cmp [edi+deflate_state.strstart],eax |
jle @f ;if (..>..) |
FLUSH_BLOCK edi, 0 |
@@: |
mov eax,block_done |
.end_f: |
ret |
endp |
; =========================================================================== |
; 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. |
;block_state (s, flush) |
; deflate_state *s |
; int flush |
align 4 |
proc deflate_fast uses ebx ecx edi, s:dword, flush:dword |
locals |
bflush dd ? ;int ;set if current block must be flushed |
endl |
;ecx = hash_head ;IPos ;head of the hash chain |
mov edi,[s] |
zlib_debug 'deflate_fast' |
.cycle0: ;for (..) |
; 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. |
cmp dword[edi+deflate_state.lookahead],MIN_LOOKAHEAD |
jge .end0 ;if (..<..) |
stdcall fill_window, edi |
cmp dword[edi+deflate_state.lookahead],MIN_LOOKAHEAD |
jge @f ;if (..<.. && ..==..) |
cmp dword[flush],Z_NO_FLUSH |
jne @f |
mov eax,need_more |
jmp .end_f |
align 4 |
@@: |
cmp dword[edi+deflate_state.lookahead],0 |
je .cycle0end ;if (..==0) break ;flush the current block |
align 4 |
.end0: |
; Insert the string window[strstart .. strstart+2] in the |
; dictionary, and set hash_head to the head of the hash chain: |
mov ecx,NIL |
cmp dword[edi+deflate_state.lookahead],MIN_MATCH |
jl @f ;if (..>=..) |
INSERT_STRING edi, [edi+deflate_state.strstart], ecx |
@@: |
; Find the longest match, discarding those <= prev_length. |
; At this point we have always match_length < MIN_MATCH |
cmp ecx,NIL |
je @f |
MAX_DIST edi |
mov ebx,[edi+deflate_state.strstart] |
sub ebx,ecx |
cmp ebx,eax |
jg @f ;if (..!=0 && ..<=..) |
; 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). |
stdcall longest_match, edi, ecx |
mov [edi+deflate_state.match_length],eax |
; longest_match() sets match_start |
@@: |
cmp dword[edi+deflate_state.match_length],MIN_MATCH |
jl .end1 ;if (..>=..) |
stdcall check_match, edi, [edi+deflate_state.strstart], [edi+deflate_state.match_start], [edi+deflate_state.match_length] |
mov eax,[edi+deflate_state.strstart] |
sub eax,[edi+deflate_state.match_start] |
mov ebx,[edi+deflate_state.match_length] |
sub ebx,MIN_MATCH |
_tr_tally_dist edi, eax, ebx, [bflush] |
mov eax,[edi+deflate_state.match_length] |
sub [edi+deflate_state.lookahead],eax |
; Insert new strings in the hash table only if the match length |
; is not too large. This saves time but degrades compression. |
if FASTEST eq 0 |
;;mov eax,[edi+deflate_state.match_length] |
cmp eax,[edi+deflate_state.max_insert_length] |
jg .end3 |
cmp dword[edi+deflate_state.lookahead],MIN_MATCH |
jl .end3 ;if (..<=.. && ..>=..) |
dec dword[edi+deflate_state.match_length] ;string at strstart already in table |
.cycle1: ;do { |
inc dword[edi+deflate_state.strstart] |
INSERT_STRING edi, [edi+deflate_state.strstart], ecx |
; strstart never exceeds WSIZE-MAX_MATCH, so there are |
; always MIN_MATCH bytes ahead. |
dec dword[edi+deflate_state.match_length] |
cmp dword[edi+deflate_state.match_length],0 |
jne .cycle1 ;while (..!=0) |
inc dword[edi+deflate_state.strstart] |
jmp .end2 |
.end3: ;else |
end if |
mov eax,[edi+deflate_state.match_length] |
add [edi+deflate_state.strstart],eax |
mov dword[edi+deflate_state.match_length],0 |
mov eax,[edi+deflate_state.window] |
add eax,[edi+deflate_state.strstart] |
mov [edi+deflate_state.ins_h],eax |
inc eax |
movzx eax,byte[eax] |
UPDATE_HASH edi, [edi+deflate_state.ins_h], eax |
if MIN_MATCH <> 3 |
; Call UPDATE_HASH() MIN_MATCH-3 more times |
end if |
; If lookahead < MIN_MATCH, ins_h is garbage, but it does not |
; matter since it will be recomputed at next deflate call. |
jmp .end2 |
.end1: ;else |
; No match, output a literal byte |
mov eax,[edi+deflate_state.window] |
add eax,[edi+deflate_state.strstart] |
movzx eax,byte[eax] |
Tracevv eax, |
_tr_tally_lit edi, eax, [bflush] |
dec dword[edi+deflate_state.lookahead] |
inc dword[edi+deflate_state.strstart] |
.end2: |
cmp dword[bflush],0 |
je .cycle0 ;if (..) |
FLUSH_BLOCK edi, 0 |
jmp .cycle0 |
align 4 |
.cycle0end: |
mov eax,[edi+deflate_state.strstart] |
cmp eax,MIN_MATCH-1 |
jl @f |
mov eax,MIN_MATCH-1 |
@@: |
mov [edi+deflate_state.insert],eax |
cmp dword[flush],Z_FINISH |
jne @f ;if (..==..) |
FLUSH_BLOCK edi, 1 |
mov eax,finish_done |
jmp .end_f |
@@: |
cmp dword[edi+deflate_state.last_lit],0 |
je @f ;if (..) |
FLUSH_BLOCK edi, 0 |
@@: |
mov eax,block_done |
.end_f: |
ret |
endp |
; =========================================================================== |
; 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. |
;block_state (s, flush) |
; deflate_state *s |
; int flush |
align 4 |
proc deflate_slow uses ebx ecx edx edi, s:dword, flush:dword |
locals |
bflush dd ? ;int ;set if current block must be flushed |
endl |
;ecx = hash_head ;IPos ;head of the hash chain |
mov edi,[s] |
zlib_debug 'deflate_slow' |
; Process the input block. |
.cycle0: ;for (;;) |
; 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. |
cmp dword[edi+deflate_state.lookahead],MIN_LOOKAHEAD |
jge .end0 ;if (..<..) |
stdcall fill_window, edi |
cmp dword[edi+deflate_state.lookahead],MIN_LOOKAHEAD |
jge @f ;if (..<.. && ..==..) |
cmp dword[flush],Z_NO_FLUSH |
jne @f |
mov eax,need_more |
jmp .end_f |
align 4 |
@@: |
cmp dword[edi+deflate_state.lookahead],0 |
je .cycle0end ;if (..==0) break ;flush the current block |
align 4 |
.end0: |
; Insert the string window[strstart .. strstart+2] in the |
; dictionary, and set hash_head to the head of the hash chain: |
mov ecx,NIL |
cmp dword[edi+deflate_state.lookahead],MIN_MATCH |
jl @f ;if (..>=..) |
INSERT_STRING edi, [edi+deflate_state.strstart], ecx |
@@: |
; Find the longest match, discarding those <= prev_length. |
mov eax,[edi+deflate_state.match_length] |
mov [edi+deflate_state.prev_length],eax |
mov eax,[edi+deflate_state.match_start] |
mov [edi+deflate_state.prev_match],eax |
mov dword[edi+deflate_state.match_length],MIN_MATCH-1 |
cmp ecx,NIL |
je @f |
mov eax,[edi+deflate_state.prev_length] |
cmp eax,[edi+deflate_state.max_lazy_match] |
jge @f |
MAX_DIST edi |
mov ebx,[edi+deflate_state.strstart] |
sub ebx,ecx |
cmp ebx,eax |
jg .end1 ;if (..!=0 && ..<.. && ..<=..) |
; 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). |
stdcall longest_match, edi, ecx |
mov [edi+deflate_state.match_length],eax |
; longest_match() sets match_start |
cmp dword[edi+deflate_state.match_length],5 |
jg .end1 |
cmp word[edi+deflate_state.strategy],Z_FILTERED |
jne .end1 |
; if (..<=.. && (..==.. |
;#if TOO_FAR <= 32767 |
; || (s->match_length == MIN_MATCH && |
; s->strstart - s->match_start > TOO_FAR) |
;end if |
; )) |
; If prev_match is also MIN_MATCH, match_start is garbage |
; but we will ignore the current match anyway. |
mov dword[edi+deflate_state.match_length],MIN_MATCH-1 |
.end1: |
; If there was a match at the previous step and the current |
; match is not better, output the previous match: |
mov eax,[edi+deflate_state.prev_length] |
cmp eax,MIN_MATCH |
jl .end2: |
cmp [edi+deflate_state.match_length],eax |
jg .end2: ;if (..>=.. && ..<=..) |
mov edx,[edi+deflate_state.strstart] |
add edx,[edi+deflate_state.lookahead] |
sub edx,MIN_MATCH |
;edx = max_insert |
; Do not insert strings in hash table beyond this. |
mov eax,[edi+deflate_state.strstart] |
dec eax |
stdcall check_match, edi, eax, [edi+deflate_state.prev_match], [edi+deflate_state.prev_length] |
mov eax,[edi+deflate_state.strstart] |
dec eax |
sub eax,[edi+deflate_state.prev_match] |
mov ebx,[edi+deflate_state.prev_length] |
sub ebx,MIN_MATCH |
_tr_tally_dist edi, eax, ebx, [bflush] |
; 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. |
mov eax,[edi+deflate_state.prev_length] |
dec eax |
sub [edi+deflate_state.lookahead],eax |
sub dword[edi+deflate_state.prev_length],2 |
.cycle1: ;do |
inc dword[edi+deflate_state.strstart] |
cmp [edi+deflate_state.strstart],edx |
jg @f ;if (..<=..) |
INSERT_STRING edi, [edi+deflate_state.strstart], ecx |
@@: |
dec dword[edi+deflate_state.prev_length] |
cmp dword[edi+deflate_state.prev_length],0 |
jne .cycle1 ;while (..!=0) |
mov dword[edi+deflate_state.match_available],0 |
mov dword[edi+deflate_state.match_length],MIN_MATCH-1 |
inc dword[edi+deflate_state.strstart] |
cmp dword[bflush],0 |
je .cycle0 ;if (..) |
FLUSH_BLOCK edi, 0 |
jmp .cycle0 |
.end2: ;else if (..) |
cmp dword[edi+deflate_state.match_available],0 |
je .end3 |
; 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. |
mov eax,[edi+deflate_state.strstart] |
dec eax |
add eax,[edi+deflate_state.window] |
movzx eax,byte[eax] |
Tracevv eax, |
_tr_tally_lit edi, eax, [bflush] |
cmp dword[bflush],0 |
je @f ;if (..) |
FLUSH_BLOCK_ONLY edi, 0 |
@@: |
inc dword[edi+deflate_state.strstart] |
dec dword[edi+deflate_state.lookahead] |
mov eax,[edi+deflate_state.strm] |
cmp word[eax+z_stream.avail_out],0 |
jne .cycle0 ;if (..==0) return .. |
mov eax,need_more |
jmp .end_f |
jmp .cycle0 ;.end4 |
.end3: ;else |
; There is no previous match to compare with, wait for |
; the next step to decide. |
mov dword[edi+deflate_state.match_available],1 |
inc dword[edi+deflate_state.strstart] |
dec dword[edi+deflate_state.lookahead] |
;.end4: |
jmp .cycle0 |
.cycle0end: |
cmp dword[flush],Z_NO_FLUSH |
jne @f |
zlib_debug 'no flush?' ;Assert (..!=..) |
@@: |
cmp dword[edi+deflate_state.match_available],0 |
je @f ;if (..) |
mov eax,[edi+deflate_state.strstart] |
dec eax |
add eax,[edi+deflate_state.window] |
movzx eax,byte[eax] |
Tracevv eax, |
_tr_tally_lit edi, eax, [bflush] |
mov dword[edi+deflate_state.match_available],0 |
@@: |
mov eax,[edi+deflate_state.strstart] |
cmp eax,MIN_MATCH-1 |
jl @f |
mov eax,MIN_MATCH-1 |
@@: |
mov [edi+deflate_state.insert],eax |
cmp dword[flush],Z_FINISH |
jne @f ;if (..==..) |
FLUSH_BLOCK edi, 1 |
mov eax,finish_done |
jmp .end_f |
@@: |
cmp dword[edi+deflate_state.last_lit],0 |
je @f ;if (..) |
FLUSH_BLOCK edi, 0 |
@@: |
mov eax,block_done |
.end_f: |
ret |
endp |
; =========================================================================== |
; For Z_RLE, simply look for runs of bytes, generate matches only of distance |
; one. Do not maintain a hash table. (It will be regenerated if this run of |
; deflate switches away from Z_RLE.) |
;block_state (s, flush) |
; deflate_state *s; |
; int flush; |
align 4 |
proc deflate_rle uses ecx edx edi esi, s:dword, flush:dword |
locals |
bflush dd ? ;int ;set if current block must be flushed |
; uInt prev; /* byte at distance one to match */ |
; Bytef *scan, *strend; /* scan goes up to strend for length of run */ |
endl |
mov edx,[s] |
zlib_debug 'deflate_rle' |
.cycle0: ;for (;;) |
; Make sure that we always have enough lookahead, except |
; at the end of the input file. We need MAX_MATCH bytes |
; for the longest run, plus one for the unrolled loop. |
cmp dword[edx+deflate_state.lookahead],MAX_MATCH |
jg .end0 ;if (..<=..) |
stdcall fill_window, edx |
cmp dword[edx+deflate_state.lookahead],MAX_MATCH |
jg @f |
cmp dword[flush],Z_NO_FLUSH |
jne @f ;if (..<=.. && ..==..) |
mov eax,need_more |
jmp .end_f |
align 4 |
@@: |
cmp dword[edx+deflate_state.lookahead],0 |
je .cycle0end ;flush the current block |
align 4 |
.end0: |
; See how many times the previous byte repeats |
mov dword[edx+deflate_state.match_length],0 |
cmp dword[edx+deflate_state.lookahead],MIN_MATCH |
jl .end1 |
cmp dword[edx+deflate_state.strstart],0 |
jle .end1 ;if (..>=.. && ..>..) |
mov esi,[edx+deflate_state.window] |
add esi,[edx+deflate_state.strstart] |
dec esi |
lodsb |
mov edi,esi |
scasb |
jnz .end2 |
scasb |
jnz .end2 |
scasb |
jnz .end2 ;if (..==.. && ..==.. && ..==..) |
;edi = scan |
; al = prev |
;ecx = strend-scan |
mov ecx,MAX_MATCH-2 |
repz scasb |
sub edi,[edx+deflate_state.window] |
sub edi,[edx+deflate_state.strstart] |
mov [edx+deflate_state.match_length],edi |
mov eax,[edx+deflate_state.lookahead] |
cmp [edx+deflate_state.match_length],eax |
jle .end2 |
mov [edx+deflate_state.match_length],eax |
.end2: |
mov eax,[edx+deflate_state.window_size] |
dec eax |
add eax,[edx+deflate_state.window] |
cmp edi,eax |
jle .end1 |
zlib_debug 'wild scan' ;Assert(..<=..) |
.end1: |
; Emit match if have run of MIN_MATCH or longer, else emit literal |
cmp dword[edx+deflate_state.match_length],MIN_MATCH |
jl @f ;if (..>=..) |
push dword[edx+deflate_state.match_length] |
mov eax,[edx+deflate_state.strstart] |
dec eax |
stdcall check_match, edx, [edx+deflate_state.strstart], eax |
mov eax,[edx+deflate_state.match_length] |
sub eax,MIN_MATCH |
_tr_tally_dist edx, 1, eax, [bflush] |
mov eax,[edx+deflate_state.match_length] |
sub [edx+deflate_state.lookahead],eax |
add [edx+deflate_state.strstart],eax |
mov dword[edx+deflate_state.match_length],0 |
jmp .end3 |
@@: ;else |
; No match, output a literal byte |
mov eax,[edx+deflate_state.strstart] |
add eax,[edx+deflate_state.window] |
movzx eax,byte[eax] |
Tracevv eax, |
_tr_tally_lit edx, eax, [bflush] |
dec dword[edx+deflate_state.lookahead] |
inc dword[edx+deflate_state.strstart] |
.end3: |
cmp dword[bflush],0 |
je .cycle0 ;if (..) |
FLUSH_BLOCK edx, 0 |
jmp .cycle0 |
align 4 |
.cycle0end: |
mov dword[edx+deflate_state.insert],0 |
cmp dword[flush],Z_FINISH |
jne @f ;if (..==..) |
FLUSH_BLOCK edx, 1 |
mov eax,finish_done |
jmp .end_f |
@@: |
cmp dword[edx+deflate_state.last_lit],0 |
je @f ;if (..) |
FLUSH_BLOCK edx, 0 |
@@: |
mov eax,block_done |
.end_f: |
ret |
endp |
; =========================================================================== |
; For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table. |
; (It will be regenerated if this run of deflate switches away from Huffman.) |
;block_state (s, flush) |
; deflate_state *s; |
; int flush; |
align 4 |
proc deflate_huff uses ebx edi, s:dword, flush:dword |
locals |
bflush dd ? ;int ;set if current block must be flushed |
endl |
mov edi,[s] |
zlib_debug 'deflate_huff' |
.cycle0: ;for (;;) |
; Make sure that we have a literal to write. |
cmp dword[edi+deflate_state.lookahead],0 |
jne .end0 ;if (..==0) |
stdcall fill_window, edi |
cmp dword[edi+deflate_state.lookahead],0 |
jne .end0 ;if (..==0) |
cmp dword[flush],Z_NO_FLUSH |
jne @f ;if (..==..) |
mov eax,need_more |
jmp .end_f |
align 4 |
@@: |
jmp .cycle0end ;flush the current block |
align 4 |
.end0: |
; Output a literal byte |
mov dword[edi+deflate_state.match_length],0 |
mov eax,[edi+deflate_state.strstart] |
add eax,[edi+deflate_state.window] |
movzx eax,byte[eax] |
Tracevv eax, |
_tr_tally_lit edi, eax, [bflush] |
dec dword[edi+deflate_state.lookahead] |
inc dword[edi+deflate_state.strstart] |
cmp dword[bflush],0 |
je @f ;if (..) |
FLUSH_BLOCK edi, 0 |
@@: |
jmp .cycle0 |
align 4 |
.cycle0end: |
mov dword[edi+deflate_state.insert],0 |
cmp dword[flush],Z_FINISH |
jne @f ;if (..==..) |
FLUSH_BLOCK edi, 1 |
mov eax,finish_done |
jmp .end_f |
@@: |
cmp dword[edi+deflate_state.last_lit],0 |
je @f ;if (..) |
FLUSH_BLOCK edi, 0 |
@@: |
mov eax,block_done |
.end_f: |
ret |
endp |
/programs/fs/kfar/trunk/zlib/deflate.inc |
---|
0,0 → 1,353 |
; deflate.inc -- internal compression state |
; Copyright (C) 1995-2012 Jean-loup Gailly |
; For conditions of distribution and use, see copyright notice in zlib.inc |
; WARNING: this file should *not* be used by applications. It is |
; part of the implementation of the compression library and is |
; subject to change. Applications should only use zlib.inc. |
include 'zutil.inc' |
; =========================================================================== |
; Internal compression state. |
LENGTH_CODES equ 29 |
; number of length codes, not counting the special END_BLOCK code |
LITERALS equ 256 |
; number of literal bytes 0..255 |
L_CODES equ (LITERALS+1+LENGTH_CODES) |
; number of Literal or Length codes, including the END_BLOCK code |
D_CODES equ 30 |
; number of distance codes |
BL_CODES equ 19 |
; number of codes used to transfer the bit lengths |
HEAP_SIZE equ (2*L_CODES+1) |
; maximum heap size |
MAX_BITS equ 15 |
; All codes must not exceed MAX_BITS bits |
Buf_size equ 16 |
; size of bit buffer in bi_buf |
INIT_STATE equ 42 |
EXTRA_STATE equ 69 |
NAME_STATE equ 73 |
COMMENT_STATE equ 91 |
HCRC_STATE equ 103 |
BUSY_STATE equ 113 |
FINISH_STATE equ 800 |
; Stream status |
; Data structure describing a single value and its code string. |
struct ct_data ;ct_data_s |
fc dw ? ;union |
;uint_16 freq ;frequency count |
;uint_16 code ;bit string |
dale dw ? ;union |
;uint_16 dad ;father node in Huffman tree |
;uint_16 len ;length of bit string |
ends |
Freq equ ct_data.fc ;.freq |
Code equ ct_data.fc ;.code |
Dad equ ct_data.dale ;.dad |
Len equ ct_data.dale ;.len |
struct tree_desc ;tree_desc_s |
dyn_tree dd ? ;ct_data * ;the dynamic tree |
max_code dd ? ;int ;largest code with non zero frequency |
stat_desc dd ? ;static_tree_desc * ;the corresponding static tree |
ends |
; A Pos is an index in the character window. We use short instead of int to |
; save space in the various tables. IPos is used only for parameter passing. |
struct deflate_state ;internal_state |
strm dd ? ;z_streamp ;pointer back to this zlib stream |
status dd ? ;int ;as the name implies |
pending_buf dd ? ;Bytef *;output still pending |
pending_buf_size dd ? ;ulg ;size of pending_buf |
pending_out dd ? ;Bytef * ;next pending byte to output to the stream |
pending dw ? ;uInt ;nb of bytes in the pending buffer |
wrap dd ? ;int ;bit 0 true for zlib, bit 1 true for gzip |
gzhead dd ? ;gz_headerp ;gzip header information to write |
gzindex dd ? ;uInt ;where in extra, name, or comment |
method db ? ;Byte ;can only be DEFLATED |
last_flush dd ? ;int ;value of flush param for previous deflate call |
; used by deflate.asm: |
w_size dd ? ;uInt ;LZ77 window size (32K by default) |
w_bits dd ? ;uInt ;log2(w_size) (8..16) |
w_mask dd ? ;uInt ;w_size - 1 |
window dd ? ;Bytef * |
; Sliding window. Input bytes are read into the second half of the window, |
; and move to the first half later to keep a dictionary of at least wSize |
; bytes. With this organization, matches are limited to a distance of |
; wSize-MAX_MATCH bytes, but this ensures that IO is always |
; performed with a length multiple of the block size. Also, it limits |
; the window size to 64K, which is quite useful on MSDOS. |
; To do: use the user input buffer as sliding window. |
window_size dd ? ;ulg |
; Actual size of window: 2*wSize, except when the user input buffer |
; is directly used as sliding window. |
prev dd ? ;Posf * |
; Link to older string with same hash index. To limit the size of this |
; array to 64K, this link is maintained only for the last 32K strings. |
; An index in this array is thus a window index modulo 32K. |
head dd ? ;Posf * ;Heads of the hash chains or NIL. |
ins_h dd ? ;uInt ;hash index of string to be inserted |
hash_size dd ? ;uInt ;number of elements in hash table |
hash_bits dd ? ;uInt ;log2(hash_size) |
hash_mask dd ? ;uInt ;hash_size-1 |
hash_shift dd ? ;uInt |
; Number of bits by which ins_h must be shifted at each input |
; step. It must be such that after MIN_MATCH steps, the oldest |
; byte no longer takes part in the hash key, that is: |
; hash_shift * MIN_MATCH >= hash_bits |
block_start dd ? ;long |
; Window position at the beginning of the current output block. Gets |
; negative when the window is moved backwards. |
match_length dd ? ;uInt ;length of best match |
prev_match dd ? ;IPos ;previous match |
match_available dd ? ;int ;set if previous match exists |
strstart dd ? ;uInt ;start of string to insert |
match_start dd ? ;uInt ;start of matching string |
lookahead dd ? ;uInt ;number of valid bytes ahead in window |
prev_length dd ? ;uInt |
; Length of the best match at previous step. Matches not greater than this |
; are discarded. This is used in the lazy match evaluation. |
max_chain_length dd ? ;uInt |
; To speed up deflation, hash chains are never searched beyond this |
; length. A higher limit improves compression ratio but degrades the |
; speed. |
max_lazy_match dd ? ;uInt |
; Attempt to find a better match only when the current match is strictly |
; smaller than this value. This mechanism is used only for compression |
; levels >= 4. |
;# define max_insert_length max_lazy_match |
; Insert new strings in the hash table only if the match length is not |
; greater than this length. This saves time but degrades compression. |
; max_insert_length is used only for compression levels <= 3. |
level dw ? ;int ;compression level (1..9) |
strategy dw ? ;int ;favor or force Huffman coding |
good_match dd ? ;uInt |
; Use a faster search when the previous match is longer than this |
nice_match dd ? ;int ;Stop searching when current match exceeds this |
; used by trees.asm: |
; Didn't use ct_data typedef below to suppress compiler warning |
dyn_ltree rb sizeof.ct_data * HEAP_SIZE ;literal and length tree |
dyn_dtree rb sizeof.ct_data * (2*D_CODES+1) ;distance tree |
bl_tree rb sizeof.ct_data * (2*BL_CODES+1) ;Huffman tree for bit lengths |
l_desc tree_desc ;desc. for literal tree |
d_desc tree_desc ;desc. for distance tree |
bl_desc tree_desc ;desc. for bit length tree |
bl_count rw MAX_BITS+1 ;uint_16[] |
; number of codes at each bit length for an optimal tree |
heap rw 2*L_CODES+1 ;int[] ;heap used to build the Huffman trees |
heap_len dd ? ;int ;number of elements in the heap |
heap_max dd ? ;int ;element of largest frequency |
; The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. |
; The same heap array is used to build all trees. |
depth rb 2*L_CODES+1 ;uch[] |
; Depth of each subtree used as tie breaker for trees of equal frequency |
l_buf dd ? ;uchf * ;buffer for literals or lengths |
lit_bufsize dd ? ;uInt |
; Size of match buffer for literals/lengths. There are 4 reasons for |
; limiting lit_bufsize to 64K: |
; - frequencies can be kept in 16 bit counters |
; - if compression is not successful for the first block, all input |
; data is still in the window so we can still emit a stored block even |
; when input comes from standard input. (This can also be done for |
; all blocks if lit_bufsize is not greater than 32K.) |
; - if compression is not successful for a file smaller than 64K, we can |
; even emit a stored file instead of a stored block (saving 5 bytes). |
; This is applicable only for zip (not gzip or zlib). |
; - creating new Huffman trees less frequently may not provide fast |
; adaptation to changes in the input data statistics. (Take for |
; example a binary file with poorly compressible code followed by |
; a highly compressible string table.) Smaller buffer sizes give |
; fast adaptation but have of course the overhead of transmitting |
; trees more frequently. |
; - I can't count above 4 |
last_lit dd ? ;uInt ;running index in l_buf |
d_buf dd ? ;uint_16p |
; Buffer for distances. To simplify the code, d_buf and l_buf have |
; the same number of elements. To use different lengths, an extra flag |
; array would be necessary. |
opt_len dd ? ;ulg ;bit length of current block with optimal trees |
static_len dd ? ;ulg ;bit length of current block with static trees |
matches dd ? ;uInt ;number of string matches in current block |
insert dd ? ;uInt ;bytes at end of window left to insert |
if DEBUG eq 1 |
compressed_len dd ? ;ulg ;total bit length of compressed file mod 2^32 |
bits_sent dd ? ;ulg ;bit length of compressed data sent mod 2^32 |
end if |
bi_buf dw ? ;uint_16 |
; Output buffer. bits are inserted starting at the bottom (least |
; significant bits). |
bi_valid dd ? ;int |
; Number of valid bits in bi_buf. All bits above the last valid bit |
; are always zero. |
high_water dd ? ;ulg |
; High water mark offset in window for initialized bytes -- bytes above |
; this are set to zero in order to avoid memory check warnings when |
; longest match routines access bytes past the input. This is then |
; updated to the new high water mark. |
ends |
; Output a byte on the stream. |
; IN assertion: there is enough room in pending_buf. |
macro put_byte s, c |
{ |
;xor eax,eax |
;mov al,c |
;zlib_debug '(%d)',eax |
movzx eax,word[s+deflate_state.pending] |
add eax,[s+deflate_state.pending_buf] |
mov byte[eax],c |
inc word[s+deflate_state.pending] |
} |
macro put_dword s, d |
{ |
;mov eax,d |
;zlib_debug '(%d)',eax |
movzx eax,word[s+deflate_state.pending] |
add eax,[s+deflate_state.pending_buf] |
mov dword[eax],d |
add word[s+deflate_state.pending],4 |
} |
MIN_LOOKAHEAD equ (MAX_MATCH+MIN_MATCH+1) |
; Minimum amount of lookahead, except at the end of the input file. |
; See deflate.asm for comments about the MIN_MATCH+1. |
macro MAX_DIST s |
{ |
mov eax,[s+deflate_state.w_size] |
sub eax,MIN_LOOKAHEAD |
} |
; In order to simplify the code, particularly on 16 bit machines, match |
; distances are limited to MAX_DIST instead of WSIZE. |
WIN_INIT equ MAX_MATCH |
; Number of bytes after end of data in window to initialize in order to avoid |
; memory checker errors from longest match routines |
macro d_code dist |
{ |
;if (dist < 256) _dist_code[dist] |
;else _dist_code[ 256+(dist>>7) ] |
local .end0 |
mov eax,dist |
cmp eax,256 |
jl .end0 |
shr eax,7 |
add eax,256 |
.end0: |
movzx eax,byte[eax+_dist_code] |
} |
; Mapping from a distance to a distance code. dist is the distance - 1 and |
; must not have side effects. _dist_code[256] and _dist_code[257] are never |
; used. |
macro _tr_tally_lit s, c, flush |
{ |
local .end0 |
if DEBUG eq 0 |
; Inline versions of _tr_tally for speed: |
if c eq eax |
else |
mov eax,c |
end if |
push ecx |
mov ecx,[s+deflate_state.last_lit] |
shl ecx,1 |
add ecx,[s+deflate_state.d_buf] |
mov word[ecx],0 |
mov ecx,[s+deflate_state.last_lit] |
add ecx,[s+deflate_state.l_buf] |
mov byte[ecx],al |
inc dword[s+deflate_state.last_lit] |
and eax,0xff |
imul eax,sizeof.ct_data |
add eax,s |
inc word[eax+deflate_state.dyn_ltree+Freq] |
xor eax,eax |
mov ecx,[s+deflate_state.lit_bufsize] |
dec ecx |
cmp [s+deflate_state.last_lit],ecx |
jne .end0 |
inc eax ;flush = (..==..) |
.end0: |
mov flush, eax |
pop ecx |
else |
stdcall _tr_tally, s, 0, c |
mov flush, eax |
end if |
} |
macro _tr_tally_dist s, distance, length, flush |
{ |
if 0 ;;;DEBUG eq 0 |
push ecx |
; uch len = (length) |
if distance eq eax |
else |
mov eax,distance |
end if |
mov ecx,[s+deflate_state.last_lit] |
shl ecx,1 |
add ecx,[s+deflate_state.d_buf] |
mov word[ecx],ax |
mov ecx,[s+deflate_state.last_lit] |
add ecx,[s+deflate_state.l_buf] |
mov byte[ecx],length |
inc dword[s+deflate_state.last_lit] |
dec eax |
; s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; |
; s->dyn_dtree[d_code(dist)].Freq++; |
; flush = (s->last_lit == s->lit_bufsize-1); |
pop ecx |
else |
stdcall _tr_tally, s, distance, length |
mov flush, eax |
end if |
} |
/programs/fs/kfar/trunk/zlib/example1.asm |
---|
0,0 → 1,287 |
use32 ; ¢ª«îç¨âì 32-¡¨âë© à¥¦¨¬ áᥬ¡«¥à |
org 0x0 ; ¤à¥á æ¨ï á ã«ï |
db 'MENUET01' |
dd 1,START,I_END,MEM,STACKTOP,0,cur_dir_path |
include '../../../../proc32.inc' |
include '../../../../macros.inc' |
include '../../../../KOSfuncs.inc' |
include '../../../../develop/libraries/box_lib/load_lib.mac' |
include 'deflate.inc' |
include 'debug.inc' |
include 'zlib.inc' |
@use_library |
align 4 |
m0size dd 90 ;à §¬¥à ¤ ëå ¤«ï 㯠ª®¢ª¨ |
m1size dd 1024 ;à §¬¥à ¡ãä¥à ¤ ëå ¤«ï 㯠ª®¢ª¨ |
m2size dd 0 ;à §¬¥à à ᯠª®¢ ëå ¤ ëå |
align 4 |
m0: ;¤ ë¥ ¤«ï 㯠ª®¢ª¨ |
file 'zlib.txt' |
align 4 |
m1 rb 1024 ;¡ãä¥à ¤«ï 㯠ª®¢ ëå ¤ ëå |
m2 dd 0 ;㪠§ ⥫ì à ᯠª®¢ ë¥ ¤ ë¥ |
buf rb 1024 ;¡ãä¥à ¤«ï ¢ë¢®¤ ᦠâëå ¤ ëå ¢ ®ª® |
strategy dd Z_DEFAULT_STRATEGY ;áâà ⥣¨ï ᦠâ¨ï |
align 4 |
START: |
load_libraries l_libs_start,load_lib_end |
mov ebp,lib0 |
.test_lib_open: |
cmp dword [ebp+ll_struc_size-4],0 |
jz @f |
mcall SF_TERMINATE_PROCESS ;exit not correct |
@@: |
add ebp,ll_struc_size |
cmp ebp,load_lib_end |
jl .test_lib_open |
; mcall SF_SYS_MISC, SSF_HEAP_INIT |
call test_code |
align 4 |
red: ; ¯¥à¥à¨á®¢ âì ®ª® |
call draw_window ; ¢ë§ë¢ ¥¬ ¯à®æ¥¤ãàã ®âà¨á®¢ª¨ ®ª |
align 4 |
still: |
mcall SF_WAIT_EVENT |
cmp eax,1 ; ¯¥à¥à¨á®¢ âì ®ª® ? |
je red |
cmp eax,2 ; ¦ â ª« ¢¨è ? |
je key |
cmp eax,3 ; ¦ â ª®¯ª ? |
je button |
jmp still |
align 4 |
key: |
mcall SF_GET_KEY |
cmp ah,178 ;Up |
jne @f |
cmp dword[strategy],0 |
jle @f |
dec dword[strategy] |
call test_code |
call draw_window |
@@: |
cmp ah,177 ;Down |
jne @f |
cmp dword[strategy],4 |
jge @f |
inc dword[strategy] |
call test_code |
call draw_window |
@@: |
cmp ah,176 ;Left |
jne @f |
cmp dword[m0size],8 |
jl @f |
dec dword[m0size] |
call test_code |
call draw_window |
@@: |
cmp ah,179 ;Right |
jne @f |
inc dword[m0size] |
call test_code |
call draw_window |
@@: |
jmp still ; ¢¥àãâìáï ª ç «ã 横« |
;--------------------------------------------------------------------- |
align 4 |
button: |
mcall SF_GET_BUTTON |
cmp ah,1 |
jne still |
.exit: |
mcall SF_SYS_MISC,SSF_MEM_FREE,[m2] |
mcall SF_TERMINATE_PROCESS ; ¨ ç¥ ª®¥æ ¯à®£à ¬¬ë |
align 4 |
draw_window: |
mcall SF_REDRAW, SSF_BEGIN_DRAW ; äãªæ¨ï 12: á®®¡é¨âì ® ç «¥ ®âà¨á®¢ª¨ |
mcall SF_STYLE_SETTINGS, SSF_GET_COLORS, sc,sizeof.system_colors |
mov edx, [sc.work] ; 梥â ä® |
or edx, 0x33000000 ; ¨ ⨯ ®ª 3 |
mcall SF_CREATE_WINDOW, <50,600>, <50,180>, , ,title |
cStr edx,'Strategy:' |
mcall SF_DRAW_TEXT, <10,10>,0x40f0,,9 |
cStr edx,'Input size:' |
mcall , <10,20>,,,11 |
cStr edx,'Compr. size:' |
mcall , <10,30>,,,12 |
cStr edx,'Outp. size:' |
mcall , <10,120>,,,11 |
mcall SF_DRAW_NUMBER, (1 shl 16)+1, strategy, <90,10>, 0 |
mcall , (5 shl 16)+1, m0size, <90,20> |
mcall , (5 shl 16)+1, m1size, <90,30> |
mcall , (5 shl 16)+1, m2size, <90,120> |
;mov ecx,(1 shl 31) |
mov esi,[m2size] |
cmp esi,95 |
jle @f |
mov esi,95 |
@@: |
mcall SF_DRAW_TEXT, <10,130>, 0, [m2] |
mov esi,7 |
mov ebx,(10 shl 16)+45 ;(x shl 16)+y |
mov edx,buf |
.cycle1: ;rows |
mcall SF_DRAW_TEXT,, (1 shl 31) |
add ebx,10 |
add edx,32*3 |
dec esi |
jnz .cycle1 |
mcall SF_REDRAW, SSF_END_DRAW ; äãªæ¨ï 12.2, § ª®ç¨«¨ à¨á®¢ âì |
ret |
align 4 |
test_code: |
stdcall [deflateInit2], my_strm,\ |
-1, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, [strategy] |
;âà ⥣¨ï: |
; Z_DEFAULT_STRATEGY, Z_FILTERED, Z_HUFFMAN_ONLY, Z_RLE, Z_FIXED |
mov eax,my_strm |
mov [eax+z_stream.next_in],m0 ;ãáâ ¢«¨¢ ¥¬ ¯ ¬ïâì ¤«ï ᦠâ¨ï |
mov ecx,[m0size] |
mov word[eax+z_stream.avail_in],cx ;à §¬¥à ᦨ¬ ¥¬ë¦ ¤ ëå |
mov [eax+z_stream.next_out],m1 ;ãáâ ¢«¨¢ ¥¬ ¡ãä¥à ¤«ï ᦠâ¨ï |
mov word[eax+z_stream.avail_out],1024 ;à §¬¥à ¡ãä¥à ¤«ï ᦠâ¨ï |
;call print_z_struct |
stdcall [deflate], my_strm, Z_FINISH ;Z_NO_FLUSH |
;call print_z_struct |
;à §¬¥à ᦠâëå ¤ ëå: 1024-word[eax+z_stream.avail_out] |
mov eax,my_strm |
mov ecx,1024 |
sub cx,word[eax+z_stream.avail_out] |
mov [m1size],ecx |
;assert(ret != Z_STREAM_ERROR) |
;while (strm.avail_out == 0) |
mov ebx,[m1size] |
mov esi,m1 |
mov edi,buf |
mov edx,7 |
.cycle1: ;rows |
mov ecx,32 |
.cycle0: ;cols |
stdcall hex_in_str, edi,[esi],2 |
add edi,2 |
inc esi |
mov byte[edi],' ' ;format space |
dec ebx |
jz .cycle1end ;if end file |
inc edi |
loop .cycle0 |
mov byte[edi-1],0 |
dec edx |
jnz .cycle1 |
.cycle1end: |
mov byte[edi],0 |
mcall SF_SYS_MISC,SSF_MEM_FREE,[m2] |
mov eax,[m1size] |
sub eax,2 ;;; 2? or 6? |
mov [m2size],eax |
mov eax,m1 |
add eax,2 |
stdcall [deflate_unpack],eax,m2size |
mov [m2],eax |
mov ecx,[m0size] ;;; ??? |
mov [m2size],ecx |
ret |
align 4 |
proc print_z_struct uses eax ebx |
mov eax,my_strm |
mov ebx,[eax+z_stream.state] |
stdcall debug_fields,eax,sv_2 |
stdcall debug_fields,ebx,sv_3 |
ret |
endp |
sc system_colors |
title db 'Zlib test, press on [Up], [Down], [Left], [Right]',0 |
align 4 |
import_archiver: |
deflate_unpack dd sz_deflate_unpack |
dd 0,0 |
sz_deflate_unpack db 'deflate_unpack',0 |
align 4 |
import_zlib: |
; dd sz_lib_init |
deflateInit dd sz_deflateInit |
deflateInit2 dd sz_deflateInit2 |
deflateReset dd sz_deflateReset |
deflate dd sz_deflate |
deflateEnd dd sz_deflateEnd |
dd 0,0 |
; sz_lib_init db 'lib_init',0 |
sz_deflateInit db 'deflateInit',0 |
sz_deflateInit2 db 'deflateInit2',0 |
sz_deflateReset db 'deflateReset',0 |
sz_deflate db 'deflate',0 |
sz_deflateEnd db 'deflateEnd',0 |
;-------------------------------------------------- |
system_dir_0 db '/sys/lib/' |
lib_name_0 db 'archiver.obj',0 |
system_dir_1 db '/sys/lib/' |
lib_name_1 db 'zlib.obj',0 |
err_message_found_lib0 db 'Sorry I cannot load library archiver.obj',0 |
err_message_found_lib1 db 'Sorry I cannot load library zlib.obj',0 |
head_f_i: |
head_f_l db 'System error',0 |
err_message_import0 db 'Error on load import library archiver.obj',0 |
err_message_import1 db 'Error on load import library zlib.obj',0 |
l_libs_start: |
lib0 l_libs lib_name_0, cur_dir_path, library_path, system_dir_0,\ |
err_message_found_lib0, head_f_l, import_archiver,err_message_import0, head_f_i |
lib1 l_libs lib_name_1, cur_dir_path, library_path, system_dir_1,\ |
err_message_found_lib1, head_f_l, import_zlib, err_message_import1, head_f_i |
load_lib_end: |
;--------------------------------------------------------------------- |
align 16 |
I_END: |
my_strm z_stream |
rd 4096 |
align 16 |
STACKTOP: |
cur_dir_path: |
rb 4096 |
library_path: |
rb 4096 |
MEM: |
/programs/fs/kfar/trunk/zlib/trees.asm |
---|
0,0 → 1,2096 |
; trees.asm -- output deflated data using Huffman coding |
; Copyright (C) 1995-2012 Jean-loup Gailly |
; detect_data_type() function provided freely by Cosmin Truta, 2006 |
; For conditions of distribution and use, see copyright notice in zlib.h |
; ALGORITHM |
; The "deflation" process uses several Huffman trees. The more |
; common source values are represented by shorter bit sequences. |
; Each code tree is stored in a compressed form which is itself |
; a Huffman encoding of the lengths of all the code strings (in |
; ascending order by source values). The actual code strings are |
; reconstructed from the lengths in the inflate process, as described |
; in the deflate specification. |
; REFERENCES |
; Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". |
; Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc |
; Storer, James A. |
; Data Compression: Methods and Theory, pp. 49-50. |
; Computer Science Press, 1988. ISBN 0-7167-8156-5. |
; Sedgewick, R. |
; Algorithms, p290. |
; Addison-Wesley, 1983. ISBN 0-201-06672-6. |
; =========================================================================== |
; Constants |
MAX_BL_BITS equ 7 |
; Bit length codes must not exceed MAX_BL_BITS bits |
END_BLOCK equ 256 |
; end of block literal code |
REP_3_6 equ 16 |
; repeat previous bit length 3-6 times (2 bits of repeat count) |
REPZ_3_10 equ 17 |
; repeat a zero length 3-10 times (3 bits of repeat count) |
REPZ_11_138 equ 18 |
; repeat a zero length 11-138 times (7 bits of repeat count) |
align 4 |
extra_lbits dd \ ;int [LENGTH_CODES] ;extra bits for each length code |
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 |
align 4 |
extra_dbits dd \ ;int [D_CODES] ;extra bits for each distance code |
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 |
align 4 |
extra_blbits dd \ ;int [BL_CODES] ;extra bits for each bit length code |
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7 |
align 4 |
bl_order db 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 |
; The lengths of the bit length codes are sent in order of decreasing |
; probability, to avoid transmitting the lengths for unused bit length codes. |
; =========================================================================== |
; Local data. These are initialized only once. |
DIST_CODE_LEN equ 512 ;see definition of array dist_code below |
if GEN_TREES_H eq 1 ;| !(STDC) |
; non ANSI compilers may not accept trees.inc |
align 4 |
static_ltree rb sizeof.ct_data * (L_CODES+2) |
; 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). |
align 4 |
static_dtree rb sizeof.ct_data * D_CODES |
; The static distance tree. (Actually a trivial tree since all codes use |
; 5 bits.) |
align 4 |
_dist_code rb DIST_CODE_LEN ;uch[] |
; 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. |
align 4 |
_length_code rb MAX_MATCH-MIN_MATCH+1 ;uch[] |
; length code for each normalized match length (0 == MIN_MATCH) |
align 4 |
base_length rd LENGTH_CODES ;int[] |
; First normalized length for each code (0 = MIN_MATCH) |
align 4 |
base_dist rd D_CODES ;int[] |
; First normalized distance for each code (0 = distance of 1) |
else |
include 'trees.inc' |
end if ;GEN_TREES_H |
struct static_tree_desc ;_s |
static_tree dd ? ;const ct_data * ;static tree or NULL |
extra_bits dd ? ;const intf * ;extra bits for each code or NULL |
extra_base dd ? ;int ;base index for extra_bits |
elems dd ? ;int ;max number of elements in the tree |
max_length dd ? ;int ;max bit length for the codes |
ends |
align 4 |
static_l_desc static_tree_desc static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS |
align 4 |
static_d_desc static_tree_desc static_dtree, extra_dbits, 0, D_CODES, MAX_BITS |
align 4 |
static_bl_desc static_tree_desc 0, extra_blbits, 0, BL_CODES, MAX_BL_BITS |
; =========================================================================== |
; Local (static) routines in this file. |
macro send_code s, c, tree |
{ |
if DEBUG eq 1 |
; if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)) |
end if |
push eax ebx |
if c eq eax |
else |
mov eax,c |
end if |
imul eax,sizeof.ct_data |
add eax,tree |
movzx ebx,word[eax+Len] |
push ebx |
movzx ebx,word[eax+Code] |
push ebx |
stdcall send_bits, s ;tree[c].Code, tree[c].Len |
pop ebx eax |
} |
; Send a code of the given tree[c] and tree must not have side effects |
; =========================================================================== |
; Output a short LSB first on the stream. |
; IN assertion: there is enough room in pendingBuf. |
macro put_short s, w |
{ |
movzx eax,word[s+deflate_state.pending] |
add eax,[s+deflate_state.pending_buf] |
mov word[eax],w |
add word[s+deflate_state.pending],2 |
} |
; =========================================================================== |
; Send a value on a given number of bits. |
; IN assertion: length <= 16 and value fits in length bits. |
;void (s, value, length) |
; deflate_state* s |
; int value ;value to send |
; int length ;number of bits |
align 4 |
proc send_bits uses eax ecx edi, s:dword, value:dword, length:dword |
; Tracevv((stderr," l %2d v %4x ", length, value)); |
;zlib_debug 'send_bits value = %d',[value] |
;if DEBUG eq 1 |
mov eax,[length] |
cmp eax,0 |
jle @f |
cmp eax,15 |
jle .end1 |
@@: |
zlib_debug 'invalid length' ;Assert(..>0 && ..<=15) |
.end1: |
mov edi,[s] |
add [edi+deflate_state.bits_sent],eax |
; If not enough room in bi_buf, use (valid) bits from bi_buf and |
; (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) |
; unused bits in value. |
mov ecx,Buf_size |
sub ecx,eax |
cmp [edi+deflate_state.bi_valid],ecx |
jle @f ;if (..>..) |
mov eax,[value] |
mov ecx,[edi+deflate_state.bi_valid] |
shl eax,cl |
or [edi+deflate_state.bi_buf],ax |
mov cx,[edi+deflate_state.bi_buf] |
put_short edi, cx |
mov eax,[value] |
mov ecx,Buf_size |
sub ecx,[edi+deflate_state.bi_valid] |
shr eax,cl |
mov [edi+deflate_state.bi_buf],ax |
mov eax,[length] |
sub eax,Buf_size |
jmp .end0 |
@@: ;else |
mov eax,[value] |
mov ecx,[edi+deflate_state.bi_valid] |
shl eax,cl |
or [edi+deflate_state.bi_buf],ax |
mov eax,[length] |
.end0: |
add [edi+deflate_state.bi_valid],eax |
;else ;!DEBUG |
;{ int len = length; |
; if (s->bi_valid > (int)Buf_size - len) { |
; int val = value; |
; s->bi_buf |= (uint_16)val << s->bi_valid; |
; put_short(s, s->bi_buf); |
; s->bi_buf = (uint_16)val >> (Buf_size - s->bi_valid); |
; s->bi_valid += len - Buf_size; |
; } else { |
; s->bi_buf |= (uint_16)(value) << s->bi_valid; |
; s->bi_valid += len; |
; } |
;} |
;end if ;DEBUG |
ret |
endp |
; the arguments must not have side effects |
; =========================================================================== |
; Initialize the various 'constant' tables. |
;int static_init_done = 0 |
;void () |
align 4 |
proc tr_static_init |
if GEN_TREES_H eq 1 |
; int n ;iterates over tree elements |
; int bits ;bit counter |
; int length ;length value |
; int code ;code value |
; int dist ;distance index |
; uint_16 bl_count[MAX_BITS+1]; |
; number of codes at each bit length for an optimal tree |
; if (static_init_done) return; |
; For some embedded targets, global variables are not initialized: |
;if NO_INIT_GLOBAL_POINTERS |
; static_l_desc.static_tree = static_ltree; |
; static_l_desc.extra_bits = extra_lbits; |
; static_d_desc.static_tree = static_dtree; |
; static_d_desc.extra_bits = extra_dbits; |
; static_bl_desc.extra_bits = extra_blbits; |
;end if |
; Initialize the mapping length (0..255) -> length code (0..28) |
; length = 0; |
; for (code = 0; code < LENGTH_CODES-1; code++) { |
; base_length[code] = length; |
; for (n = 0; n < (1<<extra_lbits[code]); n++) { |
; _length_code[length++] = (uch)code; |
; } |
; } |
; Assert (length == 256, "tr_static_init: length != 256"); |
; Note that the length 255 (match length 258) can be represented |
; in two different ways: code 284 + 5 bits or code 285, so we |
; overwrite length_code[255] to use the best encoding: |
; _length_code[length-1] = (uch)code; |
; Initialize the mapping dist (0..32K) -> dist code (0..29) |
; dist = 0; |
; for (code = 0 ; code < 16; code++) { |
; base_dist[code] = dist; |
; for (n = 0; n < (1<<extra_dbits[code]); n++) { |
; _dist_code[dist++] = (uch)code; |
; } |
; } |
; Assert (dist == 256, "tr_static_init: dist != 256"); |
; dist >>= 7; /* from now on, all distances are divided by 128 */ |
; for ( ; code < D_CODES; code++) { |
; base_dist[code] = dist << 7; |
; for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { |
; _dist_code[256 + dist++] = (uch)code; |
; } |
; } |
; Assert (dist == 256, "tr_static_init: 256+dist != 512"); |
; Construct the codes of the static literal tree |
; for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; |
; n = 0; |
; while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; |
; while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; |
; while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; |
; while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; |
; Codes 286 and 287 do not exist, but we must include them in the |
; tree construction to get a canonical Huffman tree (longest code |
; all ones) |
; gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); |
; The static distance tree is trivial: |
; for (n = 0; n < D_CODES; n++) { |
; static_dtree[n].Len = 5; |
; static_dtree[n].Code = bi_reverse((unsigned)n, 5); |
; } |
; static_init_done = 1; |
if GEN_TREES_H eq 1 |
call gen_trees_header |
end if |
end if ;(GEN_TREES_H) | !(STDC) |
ret |
endp |
; =========================================================================== |
; Genererate the file trees.h describing the static trees. |
;# define SEPARATOR(i, last, width) \ |
; ((i) == (last)? "\n};\n\n" : \ |
; ((i) % (width) == (width)-1 ? ",\n" : ", ")) |
;void () |
align 4 |
proc gen_trees_header |
; FILE *header = fopen("trees.inc", "w"); |
; int i; |
; Assert (header != NULL, "Can't open trees.inc"); |
; fprintf(header, |
; "/* header created automatically with -DGEN_TREES_H */\n\n"); |
; fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); |
; for (i = 0; i < L_CODES+2; i++) { |
; fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, |
; static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); |
; } |
; fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); |
; for (i = 0; i < D_CODES; i++) { |
; fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, |
; static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); |
; } |
; fprintf(header, "const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {\n"); |
; for (i = 0; i < DIST_CODE_LEN; i++) { |
; fprintf(header, "%2u%s", _dist_code[i], |
; SEPARATOR(i, DIST_CODE_LEN-1, 20)); |
; } |
; fprintf(header, |
; "const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); |
; for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { |
; fprintf(header, "%2u%s", _length_code[i], |
; SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); |
; } |
; fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); |
; for (i = 0; i < LENGTH_CODES; i++) { |
; fprintf(header, "%1u%s", base_length[i], |
; SEPARATOR(i, LENGTH_CODES-1, 20)); |
; } |
; fprintf(header, "local const int base_dist[D_CODES] = {\n"); |
; for (i = 0; i < D_CODES; i++) { |
; fprintf(header, "%5u%s", base_dist[i], |
; SEPARATOR(i, D_CODES-1, 10)); |
; } |
; fclose(header); |
ret |
endp |
; =========================================================================== |
; Initialize the tree data structures for a new zlib stream. |
;void (s) |
; deflate_state* s; |
align 4 |
proc _tr_init uses eax edi, s:dword |
mov edi,[s] |
;zlib_debug '_tr_init' |
call tr_static_init |
mov eax,edi |
add eax,deflate_state.dyn_ltree |
mov [edi+deflate_state.l_desc.dyn_tree],eax |
mov [edi+deflate_state.l_desc.stat_desc],static_l_desc |
add eax,deflate_state.dyn_dtree-deflate_state.dyn_ltree |
mov [edi+deflate_state.d_desc.dyn_tree],eax |
mov [edi+deflate_state.d_desc.stat_desc],static_d_desc |
add eax,deflate_state.bl_tree-deflate_state.dyn_dtree |
mov [edi+deflate_state.bl_desc.dyn_tree],eax |
mov [edi+deflate_state.bl_desc.stat_desc],static_bl_desc; |
mov word[edi+deflate_state.bi_buf],0 |
mov dword[edi+deflate_state.bi_valid],0 |
if DEBUG eq 1 |
mov dword[edi+deflate_state.compressed_len],0 |
mov dword[edi+deflate_state.bits_sent],0 |
end if |
; Initialize the first block of the first file: |
stdcall init_block,edi |
ret |
endp |
; =========================================================================== |
; Initialize a new block. |
;void (s) |
; deflate_state* s |
align 4 |
proc init_block uses eax ecx edi, s:dword |
; int n ;iterates over tree elements |
mov edi,[s] |
; Initialize the trees. |
mov eax,edi |
add eax,deflate_state.dyn_ltree+Freq |
mov ecx,L_CODES |
@@: |
mov word[eax],0 |
add eax,sizeof.ct_data |
loop @b |
mov eax,edi |
add eax,deflate_state.dyn_dtree+Freq |
mov ecx,D_CODES |
@@: |
mov word[eax],0 |
add eax,sizeof.ct_data |
loop @b |
mov eax,edi |
add eax,deflate_state.bl_tree+Freq |
mov ecx,BL_CODES |
@@: |
mov word[eax],0 |
add eax,sizeof.ct_data |
loop @b |
mov ecx,sizeof.ct_data*END_BLOCK+deflate_state.dyn_ltree+Freq |
mov word[ecx+edi],1 |
mov dword[edi+deflate_state.static_len],0 |
mov dword[edi+deflate_state.opt_len],0 |
mov dword[edi+deflate_state.matches],0 |
mov dword[edi+deflate_state.last_lit],0 |
ret |
endp |
SMALLEST equ 1 |
; Index within the heap array of least frequent node in the Huffman tree |
; =========================================================================== |
; Remove the smallest element from the heap and recreate the heap with |
; one less element. Updates heap and heap_len. |
macro pqremove s, tree, top |
{ |
mov eax,s |
add eax,deflate_state.heap+2*SMALLEST |
movzx top,word[eax] |
push ebx |
mov ebx,[s+deflate_state.heap_len] |
mov bx,[s+deflate_state.heap+2*ebx] |
mov word[eax],bx |
dec dword[s+deflate_state.heap_len] |
pop ebx |
stdcall pqdownheap, s, tree, SMALLEST |
} |
; =========================================================================== |
; Compares to subtrees, using the tree depth as tie breaker when |
; the subtrees have equal frequency. This minimizes the worst case length. |
macro smaller tree, n, m, depth, m_end |
{ |
;if (..<.. || (..==.. && depth[n] <= depth[m])) |
local .end0 |
movzx eax,n |
imul eax,sizeof.ct_data |
add eax,tree |
mov ax,word[eax+Freq] |
movzx ebx,m |
imul ebx,sizeof.ct_data |
add ebx,tree |
mov bx,word[ebx+Freq] |
cmp ax,bx |
jl .end0 |
jne m_end |
movzx eax,n |
add eax,depth |
mov al,byte[eax] |
movzx ebx,m |
add ebx,depth |
mov bl,byte[ebx] |
cmp al,bl |
jg m_end |
.end0: |
} |
; =========================================================================== |
; 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). |
;void (s, tree, k) |
; deflate_state* s |
; ct_data* tree ;the tree to restore |
; int k ;node to move down |
align 4 |
proc pqdownheap, s:dword, tree:dword, k:dword |
locals |
v dw ? |
endl |
pushad |
mov edi,[s] |
mov eax,[k] |
;zlib_debug 'pqdownheap k = %d',eax |
mov esi,eax |
shl esi,1 |
mov ax,[edi+deflate_state.heap+2*eax] |
mov [v],ax |
;esi = j ;left son of k |
.cycle0: ;while (..<=..) |
cmp esi,[edi+deflate_state.heap_len] |
jg .cycle0end |
; Set j to the smallest of the two sons: |
;;cmp esi,[edi+deflate_state.heap_len] |
jge .end1 ;if (..<.. && |
mov ecx,edi |
add ecx,deflate_state.depth |
mov edx,esi |
shl edx,1 |
add edx,edi |
add edx,deflate_state.heap |
smaller [tree], word[edx+2], word[edx], ecx, .end1 |
inc esi |
.end1: |
; Exit if v is smaller than both sons |
mov ecx,edi |
add ecx,deflate_state.depth |
mov dx,[edi+deflate_state.heap+2*esi] |
smaller [tree], [v], dx, ecx, .end2 |
jmp .cycle0end ;break |
.end2: |
; Exchange v with the smallest son |
mov dx,[edi+deflate_state.heap+2*esi] |
mov eax,[k] |
mov [edi+deflate_state.heap+2*eax],dx |
mov [k],esi |
; And continue down the tree, setting j to the left son of k |
shl esi,1 |
jmp .cycle0 |
.cycle0end: |
mov eax,[k] |
mov bx,[v] |
mov [edi+deflate_state.heap+2*eax],bx |
popad |
ret |
endp |
; =========================================================================== |
; 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. |
;void (s, desc) |
; deflate_state* s |
; tree_desc* desc ;the tree descriptor |
align 4 |
proc gen_bitlen, s:dword, desc:dword |
locals |
tree dd ? ;ct_data* ;= desc.dyn_tree |
max_code dd ? ;int ;= desc.max_code |
stree dd ? ;ct_data* ;= desc.stat_desc.static_tree |
extra dd ? ;intf* ;= desc.stat_desc.extra_bits |
base dd ? ;int ;= desc.stat_desc.extra_base |
max_length dd ? ;int ;= desc.stat_desc.max_length |
h dd ? ;int ;heap index |
m dd ? ;int ;iterate over the tree elements |
bits dd ? ;int ;bit length |
xbits dd ? ;int ;extra bits |
f dw ? ;uint_16 ;frequency |
overflow dd 0 ;int ;number of elements with bit length too large |
endl |
pushad |
;zlib_debug 'gen_bitlen' |
mov edi,[s] |
mov edx,[desc] |
mov eax,[edx+tree_desc.dyn_tree] |
mov [tree],eax |
mov eax,[edx+tree_desc.max_code] |
mov [max_code],eax |
mov ebx,[edx+tree_desc.stat_desc] |
mov eax,[ebx+static_tree_desc.static_tree] |
mov [stree],eax |
mov eax,[ebx+static_tree_desc.extra_bits] |
mov [extra],eax |
mov eax,[ebx+static_tree_desc.extra_base] |
mov [base],eax |
mov eax,[ebx+static_tree_desc.max_length] |
mov [max_length],eax |
xor ecx,ecx |
.cycle0: |
cmp ecx,MAX_BITS |
jg .cycle0end ;for (..;..<=..;..) |
mov word[edi+deflate_state.bl_count+2*ecx],0 |
inc ecx |
jmp .cycle0 |
align 4 |
.cycle0end: |
; In a first pass, compute the optimal bit lengths (which may |
; overflow in the case of the bit length tree). |
mov eax,[edi+deflate_state.heap_max] |
movzx eax,word[edi+deflate_state.heap+2*eax] |
imul eax,sizeof.ct_data |
add eax,[tree] |
mov word[eax+Len],0 ;root of the heap |
mov eax,[edi+deflate_state.heap_max] |
inc eax |
mov [h],eax |
.cycle1: |
cmp dword[h],HEAP_SIZE |
jge .cycle1end ;for (..;..<..;..) |
mov eax,[h] |
movzx ecx,word[edi+deflate_state.heap+2*eax] |
;ecx = n |
mov eax,sizeof.ct_data |
imul eax,ecx |
add eax,[tree] |
movzx eax,word[eax+Dad] |
imul eax,sizeof.ct_data |
add eax,[tree] |
movzx eax,word[eax+Len] |
inc eax |
mov [bits],eax ;bits = tree[tree[n].Dad].Len + 1 |
mov eax,[max_length] |
cmp [bits],eax |
jle @f ;if (..>..) |
mov [bits],eax |
inc dword[overflow] |
@@: |
mov esi,[bits] |
mov eax,sizeof.ct_data |
imul eax,ecx |
add eax,[tree] |
mov word[eax+Len],si |
; We overwrite tree[n].Dad which is no longer needed |
cmp ecx,[max_code] |
jle @f |
inc dword[h] |
jmp .cycle1 ;if (..>..) continue ;not a leaf node |
@@: |
mov eax,[bits] |
shl eax,1 ;*= sizeof.uint_16 |
inc word[eax+edi+deflate_state.bl_count] |
mov dword[xbits],0 |
cmp ecx,[base] |
jl @f ;if (..>=..) |
mov eax,ecx |
sub eax,[base] |
shl eax,2 ;*= sizeof.dd |
add eax,[extra] |
mov eax,[eax] |
mov [xbits],eax |
@@: |
mov eax,sizeof.ct_data |
imul eax,ecx |
add eax,[tree] |
movzx eax,word[eax+Freq] |
mov [f],ax |
mov esi,[bits] |
add esi,[xbits] |
imul eax,esi |
add [edi+deflate_state.opt_len],eax |
cmp dword[stree],0 |
je @f ;if (..) |
movzx eax,word[f] |
mov esi,sizeof.ct_data |
imul esi,ecx |
add esi,[tree] |
movzx esi,word[esi+Len] |
add esi,[xbits] |
imul eax,esi |
add [edi+deflate_state.static_len],eax |
@@: |
inc dword[h] |
jmp .cycle1 |
align 4 |
.cycle1end: |
cmp dword[overflow],0 |
je .end_f ;if (..==0) return |
; Trace((stderr,"\nbit length overflow\n")); |
; This happens for example on obj2 and pic of the Calgary corpus |
; Find the first bit length which could increase: |
.cycle2: ;do |
mov eax,[max_length] |
dec eax |
mov [bits],eax |
shl eax,1 ;*= sizeof.dw |
add eax,edi |
add eax,deflate_state.bl_count |
@@: |
cmp word[eax],0 |
jne @f ;while (..==0) bits-- |
dec dword[bits] |
sub eax,2 |
jmp @b |
@@: |
dec word[eax] ;move one leaf down the tree |
add word[eax+2],2 ;move one overflow item as its brother |
mov eax,[max_length] |
dec word[edi+deflate_state.bl_count+2*eax] |
; The brother of the overflow item also moves one step up, |
; but this does not affect bl_count[max_length] |
sub dword[overflow],2 |
cmp dword[overflow],0 |
jg .cycle2 ;while (..>0) |
; Now recompute all bit lengths, scanning in increasing frequency. |
; h 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.) |
mov eax,[max_length] |
mov [bits],eax |
.cycle3: |
cmp dword[bits],0 |
je .end_f ;for (..;..!=0;..) |
mov eax,[bits] |
shl eax,1 ;*= sizeof.dw |
movzx ecx,word[eax+edi+deflate_state.bl_count] |
.cycle4: ;while (..!=0) |
cmp ecx,0 |
je .cycle4end |
dec dword[h] |
mov eax,[h] |
movzx eax,word[edi+deflate_state.heap+2*eax] |
mov [m],eax ;m = s.heap[--h] |
cmp eax,[max_code] |
jle @f ;if (..>..) continue |
dec ecx |
jmp .cycle4 |
@@: |
mov esi,[m] |
imul esi,sizeof.ct_data |
add esi,[tree] ;esi = &tree[m] |
mov eax,[bits] |
cmp word[esi+Len],ax |
je @f ;if (..!=..) |
; Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); |
movzx ebx,word[esi+Len] |
sub eax,ebx |
movzx ebx,word[esi+Freq] |
imul eax,ebx ;eax = (bits - tree[m].Len) * tree[m].Freq |
add [edi+deflate_state.opt_len],eax |
mov eax,[bits] |
mov word[esi+Len],ax |
@@: |
dec ecx |
jmp .cycle4 |
.cycle4end: |
dec dword[bits] |
jmp .cycle3 |
.end_f: |
popad |
ret |
endp |
; =========================================================================== |
; 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. |
;void (tree, max_code, bl_count) |
; ct_data *tree ;the tree to decorate |
; int max_code ;largest code with non zero frequency |
; uint_16p bl_count ;number of codes at each bit length |
align 4 |
proc gen_codes uses eax ebx ecx edx edi, tree:dword, max_code:dword, bl_count:dword |
locals |
u_code dw 0 ;uint_16 ;running code value |
bits dd 1 ;int ;bit index |
next_code rw MAX_BITS+1 ;uint_16[] ;next code value for each bit length |
endl |
; The distribution counts are first used to generate the code values |
; without bit reversal. |
;zlib_debug 'gen_codes' |
mov ebx,ebp |
sub ebx,2*(MAX_BITS+1) |
.cycle0: ;for (..;..<=..;..) |
cmp dword[bits],MAX_BITS |
jg .cycle0end |
mov eax,[bits] |
dec eax |
shl eax,1 |
add eax,[bl_count] |
mov ax,word[eax] |
add ax,[u_code] |
shl ax,1 ;ax = (u_code + bl_count[bits-1]) << 1 |
mov [u_code],ax |
mov ecx,[bits] |
mov word[ebx+2*ecx],ax ;next_code[bits] = u_code |
inc dword[bits] |
jmp .cycle0 |
.cycle0end: |
; Check that the bit counts in bl_count are consistent. The last code |
; must be all ones. |
mov eax,[bl_count] |
mov ax,word[eax+2*MAX_BITS] |
add ax,[u_code] |
dec ax |
cmp ax,(1 shl MAX_BITS)-1 |
je @f |
zlib_debug 'inconsistent bit counts' ;Assert(..==..) |
@@: |
; Tracev((stderr,"\ngen_codes: max_code %d ", max_code)); |
xor ecx,ecx ;n = 0 |
.cycle1: ;for (..;..<=..;..) |
cmp ecx,[max_code] |
jg .cycle1end |
mov edx,sizeof.ct_data |
imul edx,ecx |
add edx,[tree] ;edx = &tree[n] |
movzx edi,word[edx+Len] |
cmp edi,0 |
jne @f ;if (..==0) continue |
inc ecx |
jmp .cycle1 |
@@: |
; Now reverse the bits |
movzx eax,word[ebx+2*edi] |
stdcall bi_reverse, eax, edi |
mov word[edx+Code],ax |
inc word[ebx+2*edi] |
; Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ", |
; n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1)); |
inc ecx |
jmp .cycle1 |
.cycle1end: |
ret |
endp |
; =========================================================================== |
; 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. |
;void (s, desc) |
; deflate_state* s |
; tree_desc *desc ;the tree descriptor |
align 4 |
proc build_tree uses eax ebx ecx edx edi, s:dword, desc:dword |
locals |
tree dd ? ;ct_data* ;= desc.dyn_tree |
stree dd ? ;ct_data* ;= desc.stat_desc.static_tree |
elems dd ? ;int ;= desc.stat_desc.elems |
m dd ? ;int ;iterate over heap elements |
max_code dd -1 ;int ;largest code with non zero frequency |
node dd ? ;int ;new node being created |
endl |
; 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. |
mov ebx,[desc] |
mov eax,[ebx+tree_desc.dyn_tree] |
mov [tree],eax |
mov ecx,[ebx+tree_desc.stat_desc] |
mov eax,[ecx+static_tree_desc.static_tree] |
mov [stree],eax |
mov ecx,[ecx+static_tree_desc.elems] |
mov [elems],ecx |
mov edi,[s] |
;zlib_debug 'build_tree cycle0 ecx = %d',ecx |
mov dword[edi+deflate_state.heap_len],0 |
mov dword[edi+deflate_state.heap_max],HEAP_SIZE |
cmp ecx,0 |
jle .cycle0end |
xor edx,edx |
.cycle0: ;for (..;..<..;..) |
mov eax,edx |
imul eax,sizeof.ct_data |
add eax,[tree] |
cmp word[eax+Freq],0 |
je @f ;if (..!=0) |
inc dword[edi+deflate_state.heap_len] |
mov eax,[edi+deflate_state.heap_len] |
mov [max_code],edx |
mov [edi+deflate_state.heap+2*eax],dx |
mov eax,edx |
add eax,edi |
add eax,deflate_state.depth |
mov byte[eax],0 |
jmp .end0 |
align 4 |
@@: ;else |
mov word[eax+Len],0 |
.end0: |
inc edx |
loop .cycle0 |
align 4 |
.cycle0end: |
; 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. |
.cycle1: ;while (..<..) |
cmp dword[edi+deflate_state.heap_len],2 |
jge .cycle1end |
inc dword[edi+deflate_state.heap_len] |
xor eax,eax |
cmp dword[max_code],2 |
jge @f |
inc dword[max_code] |
mov eax,[max_code] |
@@: |
mov ecx,[edi+deflate_state.heap_len] |
mov [edi+deflate_state.heap+2*ecx],ax |
mov [node],eax |
imul eax,sizeof.ct_data |
add eax,[tree] |
mov word[eax+Freq],1 |
mov eax,[node] |
mov byte[edi+deflate_state.depth+eax],0 |
dec dword[edi+deflate_state.opt_len] |
cmp dword[stree],0 |
je .cycle1 ;if (..) |
mov eax,[node] |
imul eax,sizeof.ct_data |
add eax,[stree] |
movzx eax,word[eax+Len] |
sub [edi+deflate_state.static_len],eax |
; node is 0 or 1 so it does not have extra bits |
jmp .cycle1 |
align 4 |
.cycle1end: |
mov eax,[max_code] |
mov [ebx+tree_desc.max_code],eax |
; The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, |
; establish sub-heaps of increasing lengths: |
mov ecx,[edi+deflate_state.heap_len] |
shr ecx,1 |
.cycle2: ;for (..;..>=..;..) |
cmp ecx,1 |
jl .cycle2end |
stdcall pqdownheap, edi, [tree], ecx |
dec ecx |
jmp .cycle2 |
align 4 |
.cycle2end: |
; Construct the Huffman tree by repeatedly combining the least two |
; frequent nodes. |
mov eax,[elems] |
mov [node],eax ;next internal node of the tree |
.cycle3: ;do |
pqremove edi, [tree], ecx ;n = node of least frequency |
movzx edx,word[eax] |
mov [m],edx ;m = node of next least frequency |
mov eax,[edi+deflate_state.heap_max] |
dec eax |
mov [edi+deflate_state.heap+2*eax],cx ;keep the nodes sorted by frequency |
dec eax |
mov [edi+deflate_state.heap_max],eax |
mov [edi+deflate_state.heap+2*eax],dx |
; Create a new node father of n and m |
;;mov edx,[m] |
imul edx,sizeof.ct_data |
add edx,[tree] |
mov ax,word[edx+Freq] |
mov edx,ecx |
imul edx,sizeof.ct_data |
add edx,[tree] |
add ax,word[edx+Freq] |
mov edx,[node] |
imul edx,sizeof.ct_data |
add edx,[tree] |
mov word[edx+Freq],ax |
mov eax,ecx |
add eax,edi |
add eax,deflate_state.depth |
mov al,byte[eax] |
mov edx,[m] |
add edx,edi |
add edx,deflate_state.depth |
mov ah,byte[edx] |
cmp al,ah |
jl @f ;if (al>=ah) al=al : al=ah |
mov al,ah |
@@: |
inc al |
mov edx,[node] |
add edx,edi |
add edx,deflate_state.depth |
mov byte[edx],al |
mov eax,[node] |
mov edx,[m] |
imul edx,sizeof.ct_data |
add edx,[tree] |
mov [edx+Dad],ax |
mov edx,ecx |
imul edx,sizeof.ct_data |
add edx,[tree] |
mov [edx+Dad],ax |
;if DUMP_BL_TREE eq 1 |
; if (tree == s->bl_tree) { |
; fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", |
; node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); |
; } |
;end if |
; and insert the new node in the heap |
mov ecx,[node] |
mov [edi+deflate_state.heap+2*SMALLEST],cx |
inc dword[node] |
stdcall pqdownheap, edi, [tree], SMALLEST |
cmp dword[edi+deflate_state.heap_len],2 |
jge .cycle3 ;while (..>=..) |
mov cx,[edi+deflate_state.heap+2*SMALLEST] |
dec dword[edi+deflate_state.heap_max] |
mov eax,[edi+deflate_state.heap_max] |
mov [edi+deflate_state.heap+2*eax],cx |
; At this point, the fields freq and dad are set. We can now |
; generate the bit lengths. |
stdcall gen_bitlen, edi, [desc] |
; The field len is now set, we can generate the bit codes |
mov eax,edi |
add eax,deflate_state.bl_count |
stdcall gen_codes, [tree], [max_code], eax |
ret |
endp |
; =========================================================================== |
; Scan a literal or distance tree to determine the frequencies of the codes |
; in the bit length tree. |
;void (s, tree, max_code) |
; deflate_state* s |
; ct_data *tree ;the tree to be scanned |
; int max_code ;and its largest code of non zero frequency |
align 4 |
proc scan_tree uses eax ebx ecx edi, s:dword, tree:dword, max_code:dword |
locals |
n dd ? ;int ;iterates over all tree elements |
prevlen dd -1 ;int ;last emitted length |
curlen dd ? ;int ;length of current code |
nextlen dd ? ;int ;= tree[0].Len ;length of next code |
count dd 0 ;int ;repeat count of the current code |
max_count dd 7 ;int ;max repeat count |
min_count dd 4 ;int ;min repeat count |
endl |
mov edi,[s] |
;zlib_debug 'scan_tree' |
mov eax,[tree] |
movzx eax,word[eax+Len] |
mov [nextlen],eax |
cmp eax,0 |
jne @f ;if (..==0) |
mov dword[max_count],138 |
mov dword[min_count],3 |
@@: |
mov eax,[max_code] |
inc eax |
imul eax,sizeof.ct_data |
add eax,[tree] |
mov word[eax+Len],0xffff ;guard |
xor ecx,ecx |
.cycle0: |
cmp ecx,[max_code] |
jg .cycle0end ;for (..;..<=..;..) |
mov eax,[nextlen] |
mov [curlen],eax |
mov eax,ecx |
inc eax |
imul eax,sizeof.ct_data |
add eax,[tree] |
movzx eax,word[eax+Len] |
mov [nextlen],eax |
inc dword[count] |
mov ebx,[count] |
cmp ebx,[max_count] |
jge .end0 |
mov eax,[nextlen] |
cmp [curlen],eax |
jne .end0 ;if (..<.. && ..==..) |
inc ecx |
jmp .cycle0 ;continue |
.end0: |
cmp ebx,[min_count] |
jge .end1 ;else if (..<..) |
mov eax,[curlen] |
imul eax,sizeof.ct_data |
add eax,edi |
add eax,deflate_state.bl_tree+Freq |
add word[eax],bx |
jmp .end4 |
.end1: |
cmp dword[curlen],0 |
je .end2 ;else if (..!=0) |
mov eax,[curlen] |
cmp eax,[prevlen] |
je @f ;if (..!=..) |
imul eax,sizeof.ct_data |
add eax,edi |
add eax,deflate_state.bl_tree+Freq |
inc word[eax] |
@@: |
mov eax,REP_3_6 |
imul eax,sizeof.ct_data |
add eax,edi |
add eax,deflate_state.bl_tree+Freq |
inc word[eax] |
jmp .end4 |
.end2: |
cmp ebx,10 |
jg .end3 ;else if (..<=..) |
mov eax,REPZ_3_10 |
imul eax,sizeof.ct_data |
add eax,edi |
add eax,deflate_state.bl_tree+Freq |
inc word[eax] |
jmp .end4 |
.end3: ;else |
mov eax,REPZ_11_138 |
imul eax,sizeof.ct_data |
add eax,edi |
add eax,deflate_state.bl_tree+Freq |
inc word[eax] |
.end4: |
mov dword[curlen],0 |
mov eax,[curlen] |
mov [prevlen],eax |
mov [nextlen],eax |
cmp eax,0 |
jne .end5 ;if (..==0) |
mov dword[max_count],138 |
mov dword[min_count],3 |
jmp .end7 |
.end5: |
mov eax,[curlen] |
cmp eax,[nextlen] |
jne .end6 ;else if (..==..) |
mov dword[max_count],6 |
mov dword[min_count],3 |
jmp .end7 |
.end6: ;else |
mov dword[max_count],7 |
mov dword[min_count],4 |
.end7: |
inc ecx |
jmp .cycle0 |
.cycle0end: |
ret |
endp |
; =========================================================================== |
; Send a literal or distance tree in compressed form, using the codes in |
; bl_tree. |
;void (s, tree, max_code) |
; deflate_state* s |
; ct_data *tree ;the tree to be scanned |
; int max_code ;and its largest code of non zero frequency |
align 4 |
proc send_tree uses eax ebx ecx edi, s:dword, tree:dword, max_code:dword |
locals |
n dd ? ;int ;iterates over all tree elements |
prevlen dd -1 ;int ;last emitted length |
curlen dd ? ;int ;length of current code |
nextlen dd ? ;int ;= tree[0].Len ;length of next code |
count dd 0 ;int ;repeat count of the current code |
max_count dd 7 ;int ;max repeat count |
min_count dd 4 ;int ;min repeat count |
endl |
mov edi,[s] |
;zlib_debug 'send_tree' |
; *** tree[max_code+1].Len = -1 ;guard already set |
mov eax,[tree] |
movzx eax,word[eax+Len] |
mov [nextlen],eax |
cmp eax,0 |
jne @f ;if (..==0) |
mov dword[max_count],138 |
mov dword[min_count],3 |
@@: |
xor ecx,ecx |
.cycle0: ;for (..;..<=..;..) |
cmp ecx,[max_code] |
jg .cycle0end |
mov eax,[nextlen] |
mov [curlen],eax |
mov eax,ecx |
inc eax |
imul eax,sizeof.ct_data |
add eax,[tree] |
movzx eax,word[eax+Len] |
mov [nextlen],eax |
inc dword[count] |
mov ebx,[count] |
cmp ebx,[max_count] |
jge .end0 |
mov eax,[nextlen] |
cmp [curlen],eax |
jne .end0 ;if (..<.. && ..==..) |
inc ecx |
jmp .cycle0 ;continue |
.end0: |
cmp ebx,[min_count] |
jge .end1 ;else if (..<..) |
@@: ;do |
mov ebx,edi |
add ebx,deflate_state.bl_tree |
send_code edi, [curlen], ebx |
dec dword[count] |
cmp dword[count],0 |
jne @b ;while (..!=0) |
jmp .end4 |
align 4 |
.end1: |
cmp dword[curlen],0 |
je .end2 ;else if (..!=0) |
mov eax,[curlen] |
cmp eax,[prevlen] |
je @f ;if (..!=..) |
mov ebx,edi |
add ebx,deflate_state.bl_tree |
send_code edi, eax, ebx |
dec dword[count] |
@@: |
cmp dword[count],3 |
jl @f |
cmp dword[count],6 |
jle .end8 |
@@: |
zlib_debug ' 3_6?' ;Assert(..>=.. && ..<=..) |
.end8: |
mov ebx,edi |
add ebx,deflate_state.bl_tree |
send_code edi, REP_3_6, ebx |
mov ebx,[count] |
sub ebx,3 |
stdcall send_bits, edi, ebx, 2 |
jmp .end4 |
.end2: |
cmp ebx,10 |
jg .end3 ;else if (..<=..) |
mov ebx,edi |
add ebx,deflate_state.bl_tree |
send_code edi, REPZ_3_10, ebx |
mov ebx,[count] |
sub ebx,3 |
stdcall send_bits, edi, ebx, 3 |
jmp .end4 |
.end3: ;else |
mov ebx,edi |
add ebx,deflate_state.bl_tree |
send_code edi, REPZ_11_138, ebx |
mov ebx,[count] |
sub ebx,11 |
stdcall send_bits, edi, ebx, 7 |
.end4: |
mov dword[curlen],0 |
mov eax,[curlen] |
mov [prevlen],eax |
mov [nextlen],eax |
cmp eax,0 |
jne .end5 ;if (..==0) |
mov dword[max_count],138 |
mov dword[min_count],3 |
jmp .end7 |
.end5: |
mov eax,[curlen] |
cmp eax,[nextlen] |
jne .end6 ;else if (..==..) |
mov dword[max_count],6 |
mov dword[min_count],3 |
jmp .end7 |
.end6: ;else |
mov dword[max_count],7 |
mov dword[min_count],4 |
.end7: |
inc ecx |
jmp .cycle0 |
align 4 |
.cycle0end: |
ret |
endp |
; =========================================================================== |
; Construct the Huffman tree for the bit lengths and return the index in |
; bl_order of the last bit length code to send. |
;int (s) |
; deflate_state* s |
align 4 |
proc build_bl_tree uses edi, s:dword |
locals |
max_blindex dd ? ;int ;index of last bit length code of non zero freq |
endl |
mov edi,[s] |
; Determine the bit length frequencies for literal and distance trees |
mov eax,edi |
add eax,deflate_state.dyn_ltree |
stdcall scan_tree, edi, eax, [edi+deflate_state.l_desc.max_code] |
mov eax,edi |
add eax,deflate_state.dyn_dtree |
stdcall scan_tree, edi, eax, [edi+deflate_state.d_desc.max_code] |
; Build the bit length tree: |
mov eax,edi |
add eax,deflate_state.bl_desc |
stdcall build_tree, edi, eax |
; 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.) |
mov dword[max_blindex],BL_CODES-1 |
.cycle0: ;for (..;..>=..;..) |
cmp dword[max_blindex],3 |
jl .cycle0end |
dec dword[max_blindex] |
mov eax,[max_blindex] |
add eax,bl_order |
movzx eax,byte[eax] |
imul eax,sizeof.ct_data |
add eax,edi |
add eax,deflate_state.bl_tree+Len |
cmp word[eax],0 |
jne .cycle0end ;if (..!=0) break |
jmp .cycle0 |
.cycle0end: |
; Update opt_len to include the bit length tree and counts |
mov eax,[max_blindex] |
inc eax |
imul eax,3 |
add eax,5+5+4 |
add [edi+deflate_state.opt_len],eax |
; Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", s->opt_len, s->static_len)); |
mov eax,[max_blindex] |
ret |
endp |
; =========================================================================== |
; 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. |
;void (s, lcodes, dcodes, blcodes) |
; deflate_state* s |
; int lcodes, dcodes, blcodes ;number of codes for each tree |
align 4 |
proc send_all_trees uses eax ebx ecx edi, s:dword, lcodes:dword, dcodes:dword, blcodes:dword |
;ecx = index in bl_order |
;zlib_debug 'send_all_trees' |
cmp dword[lcodes],257 |
jl @f |
cmp dword[dcodes],1 |
jl @f |
cmp dword[blcodes],4 |
jge .end0 |
@@: |
zlib_debug 'not enough codes' ;Assert(..>=.. && ..>=.. && ..>=..) |
.end0: |
cmp dword[lcodes],L_CODES |
jg @f |
cmp dword[dcodes],D_CODES |
jg @f |
cmp dword[blcodes],BL_CODES |
jle .end1 |
@@: |
zlib_debug 'too many codes' ;Assert(..<=.. && ..<=.. && ..<=..) |
.end1: |
; Tracev((stderr, "\nbl counts: ")); |
mov edi,[s] |
mov eax,[lcodes] |
sub eax,257 |
stdcall send_bits, edi, eax, 5 ;not +255 as stated in appnote.txt |
mov eax,[dcodes] |
dec eax |
stdcall send_bits, edi, eax, 5 |
mov eax,[blcodes] |
sub eax,4 |
stdcall send_bits, edi, eax, 4 ;not -3 as stated in appnote.txt |
xor ecx,ecx |
.cycle0: |
cmp ecx,[blcodes] |
jge .cycle0end ;for (..;..<..;..) |
; Tracev((stderr, "\nbl code %2d ", bl_order[ecx])); |
mov eax,ecx |
add eax,bl_order |
movzx eax,byte[eax] |
imul eax,sizeof.ct_data |
mov ebx,edi |
add ebx,deflate_state.bl_tree+Len |
add ebx,eax |
stdcall send_bits, edi, ebx, 3 |
inc ecx |
jmp .cycle0 |
align 4 |
.cycle0end: |
; Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); |
mov ebx,[lcodes] |
dec ebx |
mov eax,edi |
add eax,deflate_state.dyn_ltree |
stdcall send_tree, edi, eax, ebx ;literal tree |
; Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); |
mov ebx,[dcodes] |
dec ebx |
add eax,deflate_state.dyn_dtree-deflate_state.dyn_ltree |
stdcall send_tree, edi, eax, ebx ;distance tree |
; Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); |
ret |
endp |
; =========================================================================== |
; Send a stored block |
;void (s, buf, stored_len, last) |
; deflate_state* s |
; charf *buf ;input block |
; ulg stored_len ;length of input block |
; int last ;one if this is the last block for a file |
align 4 |
proc _tr_stored_block uses eax edi, s:dword, buf:dword, stored_len:dword, last:dword |
mov edi,[s] |
mov eax,[last] |
add eax,STORED_BLOCK shl 1 |
stdcall send_bits, edi, eax, 3 ;send block type |
if DEBUG eq 1 |
mov eax,[edi+deflate_state.compressed_len] |
add eax,3+7 |
and eax,not 7 |
mov [edi+deflate_state.compressed_len],eax |
mov eax,[stored_len] |
add eax,4 |
shl eax,3 |
add [edi+deflate_state.compressed_len],eax |
end if |
stdcall copy_block, edi, [buf], [stored_len], 1 ;with header |
ret |
endp |
; =========================================================================== |
; Flush the bits in the bit buffer to pending output (leaves at most 7 bits) |
;void (s) |
; deflate_state* s; |
align 4 |
proc _tr_flush_bits, s:dword |
stdcall bi_flush, [s] |
ret |
endp |
; =========================================================================== |
; Send one empty static block to give enough lookahead for inflate. |
; This takes 10 bits, of which 7 may remain in the bit buffer. |
;void (s) |
; deflate_state* s |
align 4 |
proc _tr_align uses edi, s:dword |
mov edi,[s] |
stdcall send_bits, edi, STATIC_TREES shl 1, 3 |
send_code edi, END_BLOCK, static_ltree |
if DEBUG eq 1 |
add [edi+deflate_state.compressed_len],10 ;3 for block type, 7 for EOB |
end if |
stdcall bi_flush, edi |
ret |
endp |
; =========================================================================== |
; Determine the best encoding for the current block: dynamic trees, static |
; trees or store, and output the encoded block to the zip file. |
;void (s, buf, stored_len, last) |
; deflate_state* s |
; charf *buf ;input block, or NULL if too old |
; ulg stored_len ;length of input block |
; int last ;one if this is the last block for a file |
align 4 |
proc _tr_flush_block uses eax ebx edi, s:dword, buf:dword, stored_len:dword, last:dword |
locals |
opt_lenb dd ? ;ulg |
static_lenb dd ? ;opt_len and static_len in bytes |
max_blindex dd 0 ;int ;index of last bit length code of non zero freq |
endl |
; Build the Huffman trees unless a stored block is forced |
mov edi,[s] |
;zlib_debug '_tr_flush_block' |
cmp word[edi+deflate_state.level],0 |
jle .end0 ;if (..>0) |
; Check if the file is binary or text |
mov ebx,[edi+deflate_state.strm] |
cmp word[ebx+z_stream.data_type],Z_UNKNOWN |
jne @f ;if (..==..) |
stdcall detect_data_type, edi |
mov [ebx+z_stream.data_type],ax |
@@: |
; Construct the literal and distance trees |
mov eax,edi |
add eax,deflate_state.l_desc |
stdcall build_tree, edi, eax |
; Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, s->static_len)); |
mov eax,edi |
add eax,deflate_state.d_desc |
stdcall build_tree, edi, eax |
; Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, s->static_len)); |
; 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. |
stdcall build_bl_tree, edi |
mov [max_blindex],eax |
; Determine the best encoding. Compute the block lengths in bytes. |
mov eax,[edi+deflate_state.opt_len] |
add eax,3+7 |
shr eax,3 |
mov [opt_lenb],eax |
mov eax,[edi+deflate_state.static_len] |
add eax,3+7 |
shr eax,3 |
mov [static_lenb],eax |
; Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", |
; opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, |
; s->last_lit)); |
cmp eax,[opt_lenb] |
jg .end1 ;if (..<=..) |
mov [opt_lenb],eax |
jmp .end1 |
.end0: ;else |
cmp dword[buf],0 |
jne @f |
zlib_debug 'lost buf' ;Assert(..!=0) |
@@: |
mov eax,[stored_len] |
add eax,5 |
mov [static_lenb],eax |
mov [opt_lenb],eax ;force a stored block |
.end1: |
if FORCE_STORED eq 1 |
cmp dword[buf],0 |
je .end2 ;if (..!=0) ;force stored block |
else |
mov eax,[stored_len] |
add eax,4 |
cmp eax,[opt_lenb] |
jg .end2 |
cmp dword[buf],0 |
je .end2 ;if (..<=.. && ..!=0) |
;4: two words for the lengths |
end if |
; 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. |
stdcall _tr_stored_block, edi, [buf], [stored_len], [last] |
jmp .end4 |
.end2: |
if FORCE_STATIC eq 1 |
cmp dword[static_lenb],0 |
jl .end3 ;else if (..>=0) ;force static trees |
else |
cmp word[edi+deflate_state.strategy],Z_FIXED |
je @f |
mov eax,[opt_lenb] |
cmp [static_lenb],eax |
je @f ;else if (..==.. || ..==..) |
jmp .end3 |
@@: |
end if |
mov eax,STATIC_TREES shl 1 |
add eax,[last] |
stdcall send_bits, edi, eax, 3 |
stdcall compress_block, edi, static_ltree, static_dtree |
if DEBUG eq 1 |
mov eax,[edi+deflate_state.static_len] |
add eax,3 |
add [edi+deflate_state.compressed_len],eax |
end if |
jmp .end4 |
.end3: ;else |
mov eax,DYN_TREES shl 1 |
add eax,[last] |
stdcall send_bits, edi, eax, 3 |
mov eax,[max_blindex] |
inc eax |
push eax |
mov eax,[edi+deflate_state.d_desc.max_code] |
inc eax |
push eax |
mov eax,[edi+deflate_state.l_desc.max_code] |
inc eax |
stdcall send_all_trees, edi, eax ;, ..., ... |
mov eax,edi |
add eax,deflate_state.dyn_dtree |
push eax |
add eax,deflate_state.dyn_ltree-deflate_state.dyn_dtree |
stdcall compress_block, edi, eax ;, ... |
if DEBUG eq 1 |
mov eax,[edi+deflate_state.opt_len] |
add eax,3 |
add [edi+deflate_state.compressed_len],eax |
end if |
.end4: |
; Assert (s->compressed_len == s->bits_sent, "bad compressed size"); |
; The above check is made mod 2^32, for files larger than 512 MB |
; and uLong implemented on 32 bits. |
stdcall init_block,edi |
cmp dword[last],0 |
je @f ;if (..) |
stdcall bi_windup,edi |
if DEBUG eq 1 |
add [edi+deflate_state.compressed_len],7 ;align on byte boundary |
end if |
@@: |
; Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, |
; s->compressed_len-7*last)); |
ret |
endp |
; =========================================================================== |
; Save the match info and tally the frequency counts. Return true if |
; the current block must be flushed. |
;int (s, dist, lc) |
; deflate_state* s |
; unsigned dist ;distance of matched string |
; unsigned lc ;match length-MIN_MATCH or unmatched char (if dist==0) |
align 4 |
proc _tr_tally uses ebx edi, s:dword, dist:dword, lc:dword |
mov edi,[s] |
;zlib_debug '_tr_tally' |
mov eax,[edi+deflate_state.last_lit] |
shl eax,1 |
add eax,[edi+deflate_state.d_buf] |
mov ebx,[dist] |
mov word[eax],bx |
mov eax,[edi+deflate_state.last_lit] |
add eax,[edi+deflate_state.l_buf] |
mov ebx,[lc] |
mov byte[eax],bl |
inc dword[edi+deflate_state.last_lit] |
cmp dword[dist],0 |
jne @f ;if (..==0) |
; lc is the unmatched char |
mov eax,[lc] |
imul eax,sizeof.ct_data |
add eax,edi |
inc word[eax+deflate_state.dyn_ltree+Freq] |
jmp .end0 |
@@: ;else |
inc dword[edi+deflate_state.matches] |
; Here, lc is the match length - MIN_MATCH |
dec dword[dist] ;dist = match distance - 1 |
MAX_DIST edi |
cmp word[dist],ax |
jge @f |
cmp word[lc],MAX_MATCH-MIN_MATCH |
jg @f |
d_code [dist] |
cmp ax,D_CODES |
jl .end2 |
@@: |
zlib_debug '_tr_tally: bad match' ;Assert(..<.. && ..<=.. && ..<..) |
.end2: |
mov eax,[lc] |
add eax,_length_code |
movzx eax,byte[eax] |
add eax,LITERALS+1 |
imul eax,sizeof.ct_data |
add eax,edi |
add eax,deflate_state.dyn_ltree+Freq |
inc word[eax] |
d_code [dist] |
imul eax,sizeof.ct_data |
add eax,edi |
add eax,deflate_state.dyn_dtree+Freq |
inc word[eax] |
.end0: |
if TRUNCATE_BLOCK eq 1 |
; Try to guess if it is profitable to stop the current block here |
mov eax,[edi+deflate_state.last_lit] |
and eax,0x1fff |
cmp eax,0 |
jne .end1 |
cmp word[edi+deflate_state.level],2 |
jle .end1 ;if (..==.. && ..>..) |
; Compute an upper bound for the compressed length |
; ulg out_length = (ulg)s->last_lit*8L; |
; ulg in_length = (ulg)((long)s->strstart - s->block_start); |
; int dcode; |
; for (dcode = 0; dcode < D_CODES; dcode++) { |
; out_length += (ulg)s->dyn_dtree[dcode].Freq * |
; (5L+extra_dbits[dcode]); |
; } |
; out_length >>= 3; |
; Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", |
; s->last_lit, in_length, out_length, |
; 100L - out_length*100L/in_length)); |
; if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; |
.end1: |
end if |
mov ebx,[edi+deflate_state.last_lit] |
mov edi,[edi+deflate_state.lit_bufsize] |
dec edi |
xor eax,eax |
cmp ebx,edi |
jne @f |
inc eax ;return (..==..) |
@@: |
; We avoid equality with lit_bufsize because of wraparound at 64K |
; on 16 bit machines and because stored blocks are restricted to |
; 64K-1 bytes. |
ret |
endp |
; =========================================================================== |
; Send the block data compressed using the given Huffman trees |
;void (s, ltree, dtree) |
; deflate_state* s; |
; ct_data *ltree ;literal tree |
; ct_data *dtree ;distance tree |
align 4 |
proc compress_block uses eax edi, s:dword, ltree:dword, dtree:dword |
locals |
dist dd ? ;unsigned ;distance of matched string |
lc dd ? ;int ;match length or unmatched char (if dist == 0) |
lx dd 0 ;unsigned ;running index in l_buf |
u_code dd ? ;unsigned ;the code to send |
extra dd ? ;int ;number of extra bits to send |
endl |
mov edi,[s] |
cmp dword[edi+deflate_state.last_lit],0 |
je .end0 ;if (..!=0) |
.cycle0: ; do |
mov eax,[lx] |
shl eax,1 |
add eax,[edi+deflate_state.d_buf] |
movzx eax,word[eax] |
mov [dist],eax |
mov eax,[lx] |
add eax,[edi+deflate_state.l_buf] |
movzx eax,byte[eax] |
mov [lc],eax |
inc dword[lx] |
cmp dword[dist],0 |
jne @f ;if (..==0) |
send_code edi, [lc], [ltree] ;send a literal byte |
; Tracecv(isgraph(lc), (stderr," '%c' ", lc)); |
jmp .end1 |
@@: ;else |
; Here, lc is the match length - MIN_MATCH |
mov eax,[lc] |
add eax,_length_code |
movzx eax,byte[eax] |
mov [u_code],eax |
add eax,LITERALS+1 |
send_code edi, eax, [ltree] ;send the length code |
mov eax,[u_code] |
shl eax,2 |
add eax,extra_lbits |
mov eax,[eax] |
mov [extra],eax |
cmp eax,0 |
je @f ;if (..!=0) |
mov eax,[u_code] |
shl eax,2 |
add eax,base_length |
mov eax,[eax] |
sub [lc],eax |
stdcall send_bits, edi, [lc], [extra] ;send the extra length bits |
@@: |
dec dword[dist] ;dist is now the match distance - 1 |
d_code [dist] |
mov [u_code],eax |
cmp eax,D_CODES |
jl @f |
zlib_debug 'bad d_code' ;Assert(..<..) |
@@: |
send_code edi, [u_code], [dtree] ;send the distance code |
mov eax,[u_code] |
shl eax,2 |
add eax,extra_dbits |
mov eax,[eax] |
mov [extra],eax |
cmp eax,0 |
je .end1 ;if (..!=0) |
mov eax,[u_code] |
shl eax,2 |
add eax,base_dist |
mov eax,[eax] |
sub [dist],eax |
stdcall send_bits, edi, [dist], [extra] ;send the extra distance bits |
.end1: ;literal or match pair ? |
; Check that the overlay between pending_buf and d_buf+l_buf is ok: |
mov eax,[lx] |
shl eax,1 |
add eax,[edi+deflate_state.lit_bufsize] |
cmp word[edi+deflate_state.pending],ax |
jl @f |
zlib_debug 'pendingBuf overflow' ;Assert(..<..) |
@@: |
mov eax,[edi+deflate_state.last_lit] |
cmp [lx],eax |
jl .cycle0 ;while (..<..) |
align 4 |
.end0: |
send_code edi, END_BLOCK, [ltree] |
ret |
endp |
; =========================================================================== |
; Check if the data type is TEXT or BINARY, using the following algorithm: |
; - TEXT if the two conditions below are satisfied: |
; a) There are no non-portable control characters belonging to the |
; "black list" (0..6, 14..25, 28..31). |
; b) There is at least one printable character belonging to the |
; "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255). |
; - BINARY otherwise. |
; - The following partially-portable control characters form a |
; "gray list" that is ignored in this detection algorithm: |
; (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}). |
; IN assertion: the fields Freq of dyn_ltree are set. |
;int (s) |
; deflate_state* s |
align 4 |
proc detect_data_type uses ebx ecx edi, s:dword |
; black_mask is the bit mask of black-listed bytes |
; set bits 0..6, 14..25, and 28..31 |
; 0xf3ffc07f = binary 11110011111111111100000001111111 |
locals |
black_mask dd 0xf3ffc07f |
; int n; |
endl |
mov edi,[s] |
;zlib_debug 'detect_data_type' |
; Check for non-textual ("black-listed") bytes. |
xor ecx,ecx |
mov ebx,edi |
add ebx,deflate_state.dyn_ltree+Freq |
.cycle0: |
cmp ecx,31 |
jg .cycle0end ;for (..;..<=..;..,..) |
bt dword[black_mask],0 |
jnc @f |
cmp word[ebx],0 |
je @f ;if (..&.. && ..!=0) |
mov eax,Z_BINARY |
jmp .end_f |
@@: |
shr dword[black_mask],1 |
add ebx,sizeof.ct_data |
inc ecx |
jmp .cycle0 |
.cycle0end: |
; Check for textual ("white-listed") bytes. |
mov ebx,edi |
add ebx,deflate_state.dyn_ltree+Freq+9*sizeof.ct_data |
cmp word[ebx],0 |
jne @f |
add ebx,sizeof.ct_data |
cmp word[ebx],0 |
jne @f |
add ebx,3*sizeof.ct_data |
cmp word[ebx],0 |
je .end0 |
@@: ;if (..!=0 || ..!=0 || ..!= 0) |
mov eax,Z_TEXT |
jmp .end_f |
.end0: |
mov ecx,32 |
mov ebx,edi |
add ebx,deflate_state.dyn_ltree+Freq |
.cycle1: |
cmp ecx,LITERALS |
jge .cycle1end ;for (..;..<..;..,..) |
cmp word[ebx],0 |
je @f ;if (..!=0) |
mov eax,Z_TEXT |
jmp .end_f |
@@: |
add ebx,sizeof.ct_data |
inc ecx |
jmp .cycle1 |
.cycle1end: |
; There are no "black-listed" or "white-listed" bytes: |
; this stream either is empty or has tolerated ("gray-listed") bytes only. |
mov eax,Z_BINARY |
.end_f: |
ret |
endp |
; =========================================================================== |
; Reverse the first len bits of a code, using straightforward code (a faster |
; method would use a table) |
; IN assertion: 1 <= len <= 15 |
;unsigned (code, len) |
; unsigned code ;the value to invert |
; int len ;its bit length |
align 4 |
proc bi_reverse uses ebx, p1code:dword, len:dword |
;zlib_debug 'bi_reverse' |
xor eax,eax |
@@: ;do |
mov ebx,[p1code] |
and ebx,1 |
or eax,ebx |
shr dword[p1code],1 |
shl eax,1 |
dec dword[len] |
cmp dword[len],0 |
jg @b ;while (..>..) |
shl eax,1 |
ret |
endp |
; =========================================================================== |
; Flush the bit buffer, keeping at most 7 bits in it. |
;void (s) |
; deflate_state* s |
align 4 |
proc bi_flush uses eax ecx edi, s:dword |
mov edi,[s] |
cmp dword[edi+deflate_state.bi_valid],16 |
jne @f ;if (..==..) |
mov cx,[edi+deflate_state.bi_buf] |
put_short edi,cx |
mov word[edi+deflate_state.bi_buf],0 |
mov dword[edi+deflate_state.bi_valid],0 |
jmp .end0 |
@@: ;else if (..>=..) |
cmp dword[edi+deflate_state.bi_valid],8 |
jl .end0 |
mov cl,byte[edi+deflate_state.bi_buf] |
put_byte edi,cl |
shr word[edi+deflate_state.bi_buf],8 |
sub dword[edi+deflate_state.bi_valid],8 |
.end0: |
ret |
endp |
; =========================================================================== |
; Flush the bit buffer and align the output on a byte boundary |
;void (s) |
; deflate_state* s |
align 4 |
proc bi_windup uses eax ecx edi, s:dword |
mov edi,[s] |
cmp dword[edi+deflate_state.bi_valid],8 |
jle @f ;if (..>..) |
mov cx,[edi+deflate_state.bi_buf] |
put_short edi, cx |
jmp .end0 |
@@: ;else if (..>0) |
cmp dword[edi+deflate_state.bi_valid],0 |
jle .end0 |
mov cl,byte[edi+deflate_state.bi_buf] |
put_byte edi, cl |
.end0: |
mov word[edi+deflate_state.bi_buf],0 |
mov dword[edi+deflate_state.bi_valid],0 |
if DEBUG eq 1 |
mov eax,[edi+deflate_state.bits_sent] |
add eax,7 |
and eax,not 7 |
mov [edi+deflate_state.bits_sent],eax |
end if |
ret |
endp |
; =========================================================================== |
; Copy a stored block, storing first the length and its |
; one's complement if requested. |
;void (s, buf, len, header) |
; deflate_state* s |
; charf *buf ;the input data |
; unsigned len ;its length |
; int header ;true if block header must be written |
align 4 |
proc copy_block uses eax ebx ecx edi esi, s:dword, buf:dword, len:dword, p4header:dword |
mov edi,[s] |
stdcall bi_windup,edi ;align on byte boundary |
cmp dword[p4header],0 |
je @f ;if (..) |
mov ecx,[len] |
put_short edi, cx |
not cx |
put_short edi, cx |
if DEBUG eq 1 |
add dword[edi+deflate_state.bits_sent],2*16 |
end if |
@@: |
if DEBUG eq 1 |
mov ecx,[len] |
shl ecx,3 |
add [edi+deflate_state.bits_sent],ecx |
end if |
mov ecx,[len] |
mov esi,[buf] |
@@: ;while (len--) |
lodsb |
mov bl,al |
put_byte edi, bl |
loop @b |
ret |
endp |
/programs/fs/kfar/trunk/zlib/trees.inc |
---|
0,0 → 1,139 |
;ct_data[L_CODES+2] |
align 4 |
static_ltree dw \ |
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 |
;ct_data[D_CODES] |
align 4 |
static_dtree dw \ |
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 |
;uch[DIST_CODE_LEN] |
align 4 |
_dist_code db \ |
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 |
;uch[MAX_MATCH-MIN_MATCH+1] |
align 4 |
_length_code db \ |
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 |
;int[LENGTH_CODES] |
align 4 |
base_length dd \ |
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 |
;int[D_CODES] |
align 4 |
base_dist dd \ |
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 |
/programs/fs/kfar/trunk/zlib/zconf.inc |
---|
0,0 → 1,165 |
; zconf.inc -- configuration of the zlib compression library |
; Copyright (C) 1995-2013 Jean-loup Gailly. |
; For conditions of distribution and use, see copyright notice in zlib.inc |
; Compile with -DMAXSEG_64K if the alloc function cannot allocate more |
; than 64k bytes at a time (needed on systems with 16-bit int). |
;if MSDOS |
;# define UNALIGNED_OK |
;end if |
; Maximum value for memLevel in deflateInit2 |
MAX_MEM_LEVEL equ 9 |
; Maximum value for windowBits in deflateInit2 and inflateInit2. |
; WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files |
; created by gzip. (Files created by minigzip can still be extracted by |
; gzip.) |
MAX_WBITS equ 15 ;32K LZ77 window |
; The memory requirements for deflate are (in bytes): |
; (1 << (windowBits+2)) + (1 << (memLevel+9)) |
; that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) |
; plus a few kilobytes for small objects. For example, if you want to reduce |
; the default memory requirements from 256K to 128K, compile with |
; make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" |
; Of course this will generally degrade compression (there's no free lunch). |
; The memory requirements for inflate are (in bytes) 1 << windowBits |
; that is, 32K for windowBits=15 (default value) plus a few kilobytes |
; for small objects. |
; /* Type declarations */ |
;#ifndef OF /* function prototypes */ |
;# ifdef STDC |
;# define OF(args) args |
;# else |
;# define OF(args) () |
;# endif |
;end if |
;#ifndef Z_ARG /* function prototypes for stdarg */ |
;# if defined(STDC) || defined(Z_HAVE_STDARG_H) |
;# define Z_ARG(args) args |
;# else |
;# define Z_ARG(args) () |
;# endif |
;end if |
; The following definitions for FAR are needed only for MSDOS mixed |
; model programming (small or medium model with some far allocations). |
; This was tested only with MSC; for other MSDOS compilers you may have |
; to define NO_MEMCPY in zutil.h. If you don't need the mixed model, |
; just define FAR to be empty. |
;#if defined(WINDOWS) || defined(WIN32) |
; If building or using zlib as a DLL, define ZLIB_DLL. |
; This is not mandatory, but it offers a little performance increase. |
;# ifdef ZLIB_DLL |
;# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) |
;# ifdef ZLIB_INTERNAL |
;# define ZEXTERN extern __declspec(dllexport) |
;# else |
;# define ZEXTERN extern __declspec(dllimport) |
;# endif |
;# endif |
;# endif /* ZLIB_DLL */ |
; If building or using zlib with the WINAPI/WINAPIV calling convention, |
; define ZLIB_WINAPI. |
; Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. |
;#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC) |
;# include <limits.h> |
;# if (UINT_MAX == 0xffffffffUL) |
;# define Z_U4 unsigned |
;# elif (ULONG_MAX == 0xffffffffUL) |
;# define Z_U4 unsigned long |
;# elif (USHRT_MAX == 0xffffffffUL) |
;# define Z_U4 unsigned short |
;# endif |
;end if |
;if Z_U4 |
; typedef Z_U4 z_crc_t; |
;else |
; typedef unsigned long z_crc_t; |
;end if |
;if HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ |
;# define Z_HAVE_UNISTD_H |
;end if |
;if HAVE_STDARG_H /* may be set to #if 1 by ./configure */ |
;# define Z_HAVE_STDARG_H |
;end if |
;if STDC |
;# ifndef Z_SOLO |
;# include <sys/types.h> /* for off_t */ |
;# endif |
;end if |
;#if defined(STDC) || defined(Z_HAVE_STDARG_H) |
;# ifndef Z_SOLO |
;# include <stdarg.h> /* for va_list */ |
;# endif |
;end if |
; a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and |
; "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even |
; though the former does not conform to the LFS document), but considering |
; both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as |
; equivalently requesting no 64-bit operations |
;#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 |
;# undef _LARGEFILE64_SOURCE |
;end if |
;#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H) |
;# define Z_HAVE_UNISTD_H |
;end if |
;#ifndef Z_SOLO |
;# if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) |
;# include <unistd.h> /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ |
;# ifdef VMS |
;# include <unixio.h> /* for off_t */ |
;# endif |
;# ifndef z_off_t |
;# define z_off_t off_t |
;# endif |
;# endif |
;end if |
;#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0 |
;# define Z_LFS64 |
;end if |
;#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64) |
;# define Z_LARGE64 |
;end if |
;#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64) |
;# define Z_WANT64 |
;end if |
;#if !defined(SEEK_SET) && !defined(Z_SOLO) |
;# define SEEK_SET 0 /* Seek from beginning of file. */ |
;# define SEEK_CUR 1 /* Seek from current position. */ |
;# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ |
;end if |
;# define z_off_t long |
;#if !defined(_WIN32) && defined(Z_LARGE64) |
;# define z_off64_t off64_t |
;else |
;# if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO) |
;# define z_off64_t __int64 |
;# else |
;# define z_off64_t z_off_t |
;# endif |
;end if |
/programs/fs/kfar/trunk/zlib/zlib.asm |
---|
0,0 → 1,179 |
format MS COFF |
public EXPORTS |
section '.flat' code readable align 16 |
include '../../../../proc32.inc' |
include '../../../../macros.inc' |
include '../../../../KOSfuncs.inc' |
FASTEST equ 1 |
GEN_TREES_H equ 0 |
DEBUG equ 0 |
DYNAMIC_CRC_TABLE equ 1 |
; define NO_GZIP when compiling if you want to disable gzip header and |
; trailer creation by deflate(). NO_GZIP would be used to avoid linking in |
; the crc code when it is not needed. For shared libraries, gzip encoding |
; should be left enabled. |
GZIP equ 1 |
macro zlib_debug fmt,p1 |
{ |
local .end_t |
local .m_fmt |
jmp .end_t |
.m_fmt db fmt,13,10,0 |
align 4 |
.end_t: |
if p1 eq |
stdcall dbg_print,0,.m_fmt |
else |
stdcall str_format_dbg, buf_param,.m_fmt,p1 |
end if |
} |
include 'zlib.inc' |
include 'deflate.inc' |
include 'zutil.asm' |
include 'crc32.asm' |
include 'adler32.asm' |
include 'trees.asm' |
include 'deflate.asm' |
align 4 |
buf_param rb 80 |
align 4 |
proc dbg_print, fun:dword, mes:dword |
pushad |
mov eax,SF_BOARD |
mov ebx,SSF_DEBUG_WRITE |
mov esi,[fun] |
cmp esi,0 |
je .end0 |
@@: |
mov cl,byte[esi] |
int 0x40 |
inc esi |
cmp byte[esi],0 |
jne @b |
mov cl,':' |
int 0x40 |
mov cl,' ' |
int 0x40 |
.end0: |
mov esi,[mes] |
cmp esi,0 |
je .end_f |
@@: |
mov cl,byte[esi] |
cmp cl,0 |
je .end_f |
int 0x40 |
inc esi |
jmp @b |
.end_f: |
popad |
ret |
endp |
align 4 |
proc str_format_dbg, buf:dword, fmt:dword, p1:dword |
pushad |
mov esi,[fmt] |
mov edi,[buf] |
mov ecx,80-1 |
.cycle0: |
lodsb |
cmp al,'%' |
jne .no_param |
lodsb |
dec ecx |
cmp al,0 |
je .cycle0end |
cmp al,'d' |
je @f |
cmp al,'u' |
je @f |
cmp al,'l' |
je .end1 |
jmp .end0 |
.end1: ;%lu %lx |
lodsb |
dec ecx |
cmp al,'u' |
jne .end0 |
@@: |
mov eax,[p1] |
stdcall convert_int_to_str,ecx |
xor al,al |
repne scasb |
dec edi |
.end0: |
loop .cycle0 |
.no_param: |
stosb |
cmp al,0 |
je .cycle0end |
loop .cycle0 |
.cycle0end: |
xor al,al |
stosb |
stdcall dbg_print,0,[buf] |
popad |
ret |
endp |
;input: |
; eax - число |
; edi - буфер для строки |
; len - длинна буфера |
;output: |
align 4 |
proc convert_int_to_str, len:dword |
pushad |
mov esi,[len] |
add esi,edi |
dec esi |
call .str |
popad |
ret |
endp |
align 4 |
.str: |
mov ecx,0x0a |
cmp eax,ecx |
jb @f |
xor edx,edx |
div ecx |
push edx |
call .str |
pop eax |
@@: |
cmp edi,esi |
jge @f |
or al,0x30 |
stosb |
mov byte[edi],0 |
@@: |
ret |
; export table |
align 4 |
EXPORTS: |
dd adeflateInit, deflateInit |
dd adeflateInit2, deflateInit2 |
dd adeflateReset, deflateReset |
dd adeflate, deflate |
dd adeflateEnd, deflateEnd |
dd 0 |
; exported names |
adeflateInit db 'deflateInit',0 |
adeflateInit2 db 'deflateInit2',0 |
adeflateReset db 'deflateReset',0 |
adeflate db 'deflate',0 |
adeflateEnd db 'deflateEnd',0 |
/programs/fs/kfar/trunk/zlib/zlib.inc |
---|
0,0 → 1,262 |
; zlib.inc -- interface of the 'zlib' general purpose compression library |
; version 1.2.8, April 28th, 2013 |
; Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler |
; This software is provided 'as-is', without any express or implied |
; warranty. In no event will the authors be held liable for any damages |
; arising from the use of this software. |
; Permission is granted to anyone to use this software for any purpose, |
; including commercial applications, and to alter it and redistribute it |
; freely, subject to the following restrictions: |
; 1. The origin of this software must not be misrepresented; you must not |
; claim that you wrote the original software. If you use this software |
; in a product, an acknowledgment in the product documentation would be |
; appreciated but is not required. |
; 2. Altered source versions must be plainly marked as such, and must not be |
; misrepresented as being the original software. |
; 3. This notice may not be removed or altered from any source distribution. |
; Jean-loup Gailly Mark Adler |
; jloup@gzip.org madler@alumni.caltech.edu |
; The data format used by the zlib library is described by RFCs (Request for |
; Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 |
; (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). |
include 'zconf.inc' |
align 4 |
ZLIB_VERSION db '1.2.8',0 |
ZLIB_VERNUM equ 0x1280 |
ZLIB_VER_MAJOR equ 1 |
ZLIB_VER_MINOR equ 2 |
ZLIB_VER_REVISION equ 8 |
ZLIB_VER_SUBREVISION equ 0 |
; The 'zlib' compression library provides in-memory compression and |
; decompression functions, including integrity checks of the uncompressed data. |
; This version of the library supports only one compression method (deflation) |
; but other algorithms will be added later and will have the same stream |
; interface. |
; Compression can be done in a single step if the buffers are large enough, |
; or can be done by repeated calls of the compression function. In the latter |
; case, the application must provide more input and/or consume the output |
; (providing more output space) before each call. |
; The compressed data format used by default by the in-memory functions is |
; the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped |
; around a deflate stream, which is itself documented in RFC 1951. |
; The library also supports reading and writing files in gzip (.gz) format |
; with an interface similar to that of stdio using the functions that start |
; with "gz". The gzip format is different from the zlib format. gzip is a |
; gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. |
; This library can optionally read and write gzip streams in memory as well. |
; The zlib format was designed to be compact and fast for use in memory |
; and on communications channels. The gzip format was designed for single- |
; file compression on file systems, has a larger header than zlib to maintain |
; directory information, and uses a different, slower check method than zlib. |
; The library does not install any signal handler. The decoder checks |
; the consistency of the compressed data, so the library should never crash |
; even in case of corrupted input. |
struct z_stream ;z_stream_s |
next_in dd ? ;z_const Bytef * ;next input byte |
avail_in dw ? ;uInt ;number of bytes available at next_in |
total_in dd ? ;uLong ;total number of input bytes read so far |
next_out dd ? ;Bytef * ;next output byte should be put there |
avail_out dw ? ;uInt ;remaining free space at next_out |
total_out dd ? ;uLong ;total number of bytes output so far |
msg dd ? ;z_const char * ;last error message, NULL if no error |
state dd ? ;deflate_state* ;not visible by applications |
zalloc dd ? ;alloc_func ;used to allocate the internal state |
zfree dd ? ;free_func ;used to free the internal state |
opaque dd ? ;voidpf ;private data object passed to zalloc and zfree |
data_type dw ? ;int ;best guess about the data type: binary or text |
adler dd ? ;uLong ;adler32 value of the uncompressed data |
reserved dd ? ;uLong ;reserved for future use |
ends |
; gzip header information passed to and from zlib routines. See RFC 1952 |
; for more details on the meanings of these fields. |
struct gz_header ;_s |
text dd ? ;int ;true if compressed data believed to be text |
time dd ? ;uLong ;modification time |
xflags dd ? ;int ;extra flags (not used when writing a gzip file) |
os dd ? ;int ;operating system |
extra dd ? ;Bytef* ;pointer to extra field or Z_NULL if none |
extra_len dd ? ;uInt ;extra field length (valid if extra != Z_NULL) |
extra_max dd ? ;uInt ;space at extra (only when reading header) |
name dd ? ;Bytef* ;pointer to zero-terminated file name or Z_NULL |
name_max dd ? ;uInt ;space at name (only when reading header) |
comment dd ? ;Bytef* ;pointer to zero-terminated comment or Z_NULL |
comm_max dd ? ;uInt ;space at comment (only when reading header) |
hcrc dd ? ;int ;true if there was or will be a header crc |
done dd ? ;int ;true when done reading gzip header (not used |
;when writing a gzip file) |
ends |
; The application must update next_in and avail_in when avail_in has dropped |
; to zero. It must update next_out and avail_out when avail_out has dropped |
; to zero. The application must initialize zalloc, zfree and opaque before |
; calling the init function. All other fields are set by the compression |
; library and must not be updated by the application. |
; The opaque value provided by the application will be passed as the first |
; parameter for calls of zalloc and zfree. This can be useful for custom |
; memory management. The compression library attaches no meaning to the |
; opaque value. |
; zalloc must return Z_NULL if there is not enough memory for the object. |
; If zlib is used in a multi-threaded application, zalloc and zfree must be |
; thread safe. |
; On 16-bit systems, the functions zalloc and zfree must be able to allocate |
; exactly 65536 bytes, but will not be required to allocate more than this if |
; the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, pointers |
; returned by zalloc for objects of exactly 65536 bytes *must* have their |
; offset normalized to zero. The default allocation function provided by this |
; library ensures this (see zutil.c). To reduce memory requirements and avoid |
; any allocation of 64K objects, at the expense of compression ratio, compile |
; the library with -DMAX_WBITS=14 (see zconf.h). |
; The fields total_in and total_out can be used for statistics or progress |
; reports. After compression, total_in holds the total size of the |
; uncompressed data and may be saved for use in the decompressor (particularly |
; if the decompressor wants to decompress everything in a single step). |
; constants |
Z_NO_FLUSH equ 0 |
Z_PARTIAL_FLUSH equ 1 |
Z_SYNC_FLUSH equ 2 |
Z_FULL_FLUSH equ 3 |
Z_FINISH equ 4 |
Z_BLOCK equ 5 |
Z_TREES equ 6 |
; Allowed flush values; see deflate() and inflate() below for details |
Z_OK equ 0 |
Z_STREAM_END equ 1 |
Z_NEED_DICT equ 2 |
Z_ERRNO equ (-1) |
Z_STREAM_ERROR equ (-2) |
Z_DATA_ERROR equ (-3) |
Z_MEM_ERROR equ (-4) |
Z_BUF_ERROR equ (-5) |
Z_VERSION_ERROR equ (-6) |
; Return codes for the compression/decompression functions. Negative values |
; are errors, positive values are used for special but normal events. |
Z_NO_COMPRESSION equ 0 |
Z_BEST_SPEED equ 1 |
Z_BEST_COMPRESSION equ 9 |
Z_DEFAULT_COMPRESSION equ (-1) |
; compression levels |
Z_FILTERED equ 1 |
Z_HUFFMAN_ONLY equ 2 |
Z_RLE equ 3 |
Z_FIXED equ 4 |
Z_DEFAULT_STRATEGY equ 0 |
; compression strategy; see deflateInit2() below for details |
Z_BINARY equ 0 |
Z_TEXT equ 1 |
Z_ASCII equ Z_TEXT ;for compatibility with 1.2.2 and earlier |
Z_UNKNOWN equ 2 |
; Possible values of the data_type field (though see inflate()) |
Z_DEFLATED equ 8 |
; The deflate compression method (the only one supported in this version) |
Z_NULL equ 0 ;for initializing zalloc, zfree, opaque |
zlib_version equ zlibVersion |
; for compatibility with versions < 1.0.2 |
; various hacks, don't look :) |
; deflateInit and inflateInit are macros to allow checking the zlib version |
; and the compiler's view of z_stream: |
;int inflateBackInit_ OF((z_streamp strm, int windowBits, |
; unsigned char FAR *window, |
; const char *version, |
; int stream_size)); |
;#define inflateInit(strm) \ |
; inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) |
;#define inflateInit2(strm, windowBits) \ |
; inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ |
; (int)sizeof(z_stream)) |
;#define inflateBackInit(strm, windowBits, window) \ |
; inflateBackInit_((strm), (windowBits), (window), \ |
; ZLIB_VERSION, (int)sizeof(z_stream)) |
;#ifndef Z_SOLO |
; gzgetc() macro and its supporting function and exposed data structure. Note |
; that the real internal state is much larger than the exposed structure. |
; This abbreviated structure exposes just enough for the gzgetc() macro. The |
; user should not mess with these exposed elements, since their names or |
; behavior could change in the future, perhaps even capriciously. They can |
; only be used by the gzgetc() macro. You have been warned. |
;struct gzFile_s { |
; unsigned have; |
; unsigned char *next; |
; z_off64_t pos; |
;}; |
;int gzgetc_ OF((gzFile file)); /* backward compatibility */ |
;if Z_PREFIX_SET |
;# undef z_gzgetc |
;# define z_gzgetc(g) \ |
; ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g)) |
;#else |
;# define gzgetc(g) \ |
; ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g)) |
;end if |
; provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or |
; change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if |
; both are true, the application gets the *64 functions, and the regular |
; functions are changed to 64 bits) -- in case these are set on systems |
; without large file support, _LFS64_LARGEFILE must also be true |
; undocumented functions |
;const char * zError OF((int)); |
;int inflateSyncPoint OF((z_streamp)); |
;const z_crc_t FAR * get_crc_table OF((void)); |
;int inflateUndermine OF((z_streamp, int)); |
;int inflateResetKeep OF((z_streamp)); |
;#if defined(_WIN32) && !defined(Z_SOLO) |
;gzFile gzopen_w OF((const wchar_t *path, |
; const char *mode)); |
;end if |
;#if defined(STDC) || defined(Z_HAVE_STDARG_H) |
;# ifndef Z_SOLO |
;int ZEXPORTVA gzvprintf Z_ARG((gzFile file, |
; const char *format, |
; va_list va)); |
;# endif |
;end if |
/programs/fs/kfar/trunk/zlib/zlib.txt |
---|
0,0 → 1,1405 |
zlib.inc -- interface of the 'zlib' general purpose compression library |
version 1.2.8, April 28th, 2013 |
Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler |
basic functions |
const char * zlibVersion OF((void)); |
The application can compare zlibVersion and ZLIB_VERSION for consistency. |
If the first character differs, the library code actually used is not |
compatible with the zlib.h header file used by the application. This check |
is automatically made by deflateInit and inflateInit. |
int deflateInit OF((z_streamp strm, int level)); |
Initializes the internal stream state for compression. The fields |
zalloc, zfree and opaque must be initialized before by the caller. If |
zalloc and zfree are set to Z_NULL, deflateInit updates them to use default |
allocation functions. |
The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: |
1 gives best speed, 9 gives best compression, 0 gives no compression at all |
(the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION |
requests a default compromise between speed and compression (currently |
equivalent to level 6). |
deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough |
memory, Z_STREAM_ERROR if level is not a valid compression level, or |
Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible |
with the version assumed by the caller (ZLIB_VERSION). msg is set to null |
if there is no error message. deflateInit does not perform any compression: |
this will be done by deflate(). |
int deflate OF((z_streamp strm, int flush)); |
deflate compresses as much data as possible, and stops when the input |
buffer becomes empty or the output buffer becomes full. It may introduce |
some output latency (reading input without producing any output) except when |
forced to flush. |
The detailed semantics are as follows. deflate performs one or both of the |
following actions: |
- Compress more input starting at next_in and update next_in and avail_in |
accordingly. If not all input can be processed (because there is not |
enough room in the output buffer), next_in and avail_in are updated and |
processing will resume at this point for the next call of deflate(). |
- Provide more output starting at next_out and update next_out and avail_out |
accordingly. This action is forced if the parameter flush is non zero. |
Forcing flush frequently degrades the compression ratio, so this parameter |
should be set only when necessary (in interactive applications). Some |
output may be provided even if flush is not set. |
Before the call of deflate(), the application should ensure that at least |
one of the actions is possible, by providing more input and/or consuming more |
output, and updating avail_in or avail_out accordingly; avail_out should |
never be zero before the call. The application can consume the compressed |
output when it wants, for example when the output buffer is full (avail_out |
== 0), or after each call of deflate(). If deflate returns Z_OK and with |
zero avail_out, it must be called again after making room in the output |
buffer because there might be more output pending. |
Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to |
decide how much data to accumulate before producing output, in order to |
maximize compression. |
If the parameter flush is set to Z_SYNC_FLUSH, all pending output is |
flushed to the output buffer and the output is aligned on a byte boundary, so |
that the decompressor can get all input data available so far. (In |
particular avail_in is zero after the call if enough output space has been |
provided before the call.) Flushing may degrade compression for some |
compression algorithms and so it should be used only when necessary. This |
completes the current deflate block and follows it with an empty stored block |
that is three bits plus filler bits to the next byte, followed by four bytes |
(00 00 ff ff). |
If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the |
output buffer, but the output is not aligned to a byte boundary. All of the |
input data so far will be available to the decompressor, as for Z_SYNC_FLUSH. |
This completes the current deflate block and follows it with an empty fixed |
codes block that is 10 bits long. This assures that enough bytes are output |
in order for the decompressor to finish the block before the empty fixed code |
block. |
If flush is set to Z_BLOCK, a deflate block is completed and emitted, as |
for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to |
seven bits of the current block are held to be written as the next byte after |
the next deflate block is completed. In this case, the decompressor may not |
be provided enough bits at this point in order to complete decompression of |
the data provided so far to the compressor. It may need to wait for the next |
block to be emitted. This is for advanced applications that need to control |
the emission of deflate blocks. |
If flush is set to Z_FULL_FLUSH, all output is flushed as with |
Z_SYNC_FLUSH, and the compression state is reset so that decompression can |
restart from this point if previous compressed data has been damaged or if |
random access is desired. Using Z_FULL_FLUSH too often can seriously degrade |
compression. |
If deflate returns with avail_out == 0, this function must be called again |
with the same value of the flush parameter and more output space (updated |
avail_out), until the flush is complete (deflate returns with non-zero |
avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that |
avail_out is greater than six to avoid repeated flush markers due to |
avail_out == 0 on return. |
If the parameter flush is set to Z_FINISH, pending input is processed, |
pending output is flushed and deflate returns with Z_STREAM_END if there was |
enough output space; if deflate returns with Z_OK, this function must be |
called again with Z_FINISH and more output space (updated avail_out) but no |
more input data, until it returns with Z_STREAM_END or an error. After |
deflate has returned Z_STREAM_END, the only possible operations on the stream |
are deflateReset or deflateEnd. |
Z_FINISH can be used immediately after deflateInit if all the compression |
is to be done in a single step. In this case, avail_out must be at least the |
value returned by deflateBound (see below). Then deflate is guaranteed to |
return Z_STREAM_END. If not enough output space is provided, deflate will |
not return Z_STREAM_END, and it must be called again as described above. |
deflate() sets strm->adler to the adler32 checksum of all input read |
so far (that is, total_in bytes). |
deflate() may update strm->data_type if it can make a good guess about |
the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered |
binary. This field is only for information purposes and does not affect the |
compression algorithm in any manner. |
deflate() returns Z_OK if some progress has been made (more input |
processed or more output produced), Z_STREAM_END if all input has been |
consumed and all output has been produced (only when flush is set to |
Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example |
if next_in or next_out was Z_NULL), Z_BUF_ERROR if no progress is possible |
(for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not |
fatal, and deflate() can be called again with more input and more output |
space to continue compressing. |
int deflateEnd OF((z_streamp strm)); |
All dynamically allocated data structures for this stream are freed. |
This function discards any unprocessed input and does not flush any pending |
output. |
deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the |
stream state was inconsistent, Z_DATA_ERROR if the stream was freed |
prematurely (some input or output was discarded). In the error case, msg |
may be set but then points to a static string (which must not be |
deallocated). |
int inflateInit OF((z_streamp strm)); |
Initializes the internal stream state for decompression. The fields |
next_in, avail_in, zalloc, zfree and opaque must be initialized before by |
the caller. If next_in is not Z_NULL and avail_in is large enough (the |
exact value depends on the compression method), inflateInit determines the |
compression method from the zlib header and allocates all data structures |
accordingly; otherwise the allocation will be deferred to the first call of |
inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to |
use default allocation functions. |
inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough |
memory, Z_VERSION_ERROR if the zlib library version is incompatible with the |
version assumed by the caller, or Z_STREAM_ERROR if the parameters are |
invalid, such as a null pointer to the structure. msg is set to null if |
there is no error message. inflateInit does not perform any decompression |
apart from possibly reading the zlib header if present: actual decompression |
will be done by inflate(). (So next_in and avail_in may be modified, but |
next_out and avail_out are unused and unchanged.) The current implementation |
of inflateInit() does not process any header information -- that is deferred |
until inflate() is called. |
int inflate OF((z_streamp strm, int flush)); |
inflate decompresses as much data as possible, and stops when the input |
buffer becomes empty or the output buffer becomes full. It may introduce |
some output latency (reading input without producing any output) except when |
forced to flush. |
The detailed semantics are as follows. inflate performs one or both of the |
following actions: |
- Decompress more input starting at next_in and update next_in and avail_in |
accordingly. If not all input can be processed (because there is not |
enough room in the output buffer), next_in is updated and processing will |
resume at this point for the next call of inflate(). |
- Provide more output starting at next_out and update next_out and avail_out |
accordingly. inflate() provides as much output as possible, until there is |
no more input data or no more space in the output buffer (see below about |
the flush parameter). |
Before the call of inflate(), the application should ensure that at least |
one of the actions is possible, by providing more input and/or consuming more |
output, and updating the next_* and avail_* values accordingly. The |
application can consume the uncompressed output when it wants, for example |
when the output buffer is full (avail_out == 0), or after each call of |
inflate(). If inflate returns Z_OK and with zero avail_out, it must be |
called again after making room in the output buffer because there might be |
more output pending. |
The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH, |
Z_BLOCK, or Z_TREES. Z_SYNC_FLUSH requests that inflate() flush as much |
output as possible to the output buffer. Z_BLOCK requests that inflate() |
stop if and when it gets to the next deflate block boundary. When decoding |
the zlib or gzip format, this will cause inflate() to return immediately |
after the header and before the first block. When doing a raw inflate, |
inflate() will go ahead and process the first block, and will return when it |
gets to the end of that block, or when it runs out of data. |
The Z_BLOCK option assists in appending to or combining deflate streams. |
Also to assist in this, on return inflate() will set strm->data_type to the |
number of unused bits in the last byte taken from strm->next_in, plus 64 if |
inflate() is currently decoding the last block in the deflate stream, plus |
128 if inflate() returned immediately after decoding an end-of-block code or |
decoding the complete header up to just before the first byte of the deflate |
stream. The end-of-block will not be indicated until all of the uncompressed |
data from that block has been written to strm->next_out. The number of |
unused bits may in general be greater than seven, except when bit 7 of |
data_type is set, in which case the number of unused bits will be less than |
eight. data_type is set as noted here every time inflate() returns for all |
flush options, and so can be used to determine the amount of currently |
consumed input in bits. |
The Z_TREES option behaves as Z_BLOCK does, but it also returns when the |
end of each deflate block header is reached, before any actual data in that |
block is decoded. This allows the caller to determine the length of the |
deflate block header for later use in random access within a deflate block. |
256 is added to the value of strm->data_type when inflate() returns |
immediately after reaching the end of the deflate block header. |
inflate() should normally be called until it returns Z_STREAM_END or an |
error. However if all decompression is to be performed in a single step (a |
single call of inflate), the parameter flush should be set to Z_FINISH. In |
this case all pending input is processed and all pending output is flushed; |
avail_out must be large enough to hold all of the uncompressed data for the |
operation to complete. (The size of the uncompressed data may have been |
saved by the compressor for this purpose.) The use of Z_FINISH is not |
required to perform an inflation in one step. However it may be used to |
inform inflate that a faster approach can be used for the single inflate() |
call. Z_FINISH also informs inflate to not maintain a sliding window if the |
stream completes, which reduces inflate's memory footprint. If the stream |
does not complete, either because not all of the stream is provided or not |
enough output space is provided, then a sliding window will be allocated and |
inflate() can be called again to continue the operation as if Z_NO_FLUSH had |
been used. |
In this implementation, inflate() always flushes as much output as |
possible to the output buffer, and always uses the faster approach on the |
first call. So the effects of the flush parameter in this implementation are |
on the return value of inflate() as noted below, when inflate() returns early |
when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of |
memory for a sliding window when Z_FINISH is used. |
If a preset dictionary is needed after this call (see inflateSetDictionary |
below), inflate sets strm->adler to the Adler-32 checksum of the dictionary |
chosen by the compressor and returns Z_NEED_DICT; otherwise it sets |
strm->adler to the Adler-32 checksum of all output produced so far (that is, |
total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described |
below. At the end of the stream, inflate() checks that its computed adler32 |
checksum is equal to that saved by the compressor and returns Z_STREAM_END |
only if the checksum is correct. |
inflate() can decompress and check either zlib-wrapped or gzip-wrapped |
deflate data. The header type is detected automatically, if requested when |
initializing with inflateInit2(). Any information contained in the gzip |
header is not retained, so applications that need that information should |
instead use raw inflate, see inflateInit2() below, or inflateBack() and |
perform their own processing of the gzip header and trailer. When processing |
gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output |
producted so far. The CRC-32 is checked against the gzip trailer. |
inflate() returns Z_OK if some progress has been made (more input processed |
or more output produced), Z_STREAM_END if the end of the compressed data has |
been reached and all uncompressed output has been produced, Z_NEED_DICT if a |
preset dictionary is needed at this point, Z_DATA_ERROR if the input data was |
corrupted (input stream not conforming to the zlib format or incorrect check |
value), Z_STREAM_ERROR if the stream structure was inconsistent (for example |
next_in or next_out was Z_NULL), Z_MEM_ERROR if there was not enough memory, |
Z_BUF_ERROR if no progress is possible or if there was not enough room in the |
output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and |
inflate() can be called again with more input and more output space to |
continue decompressing. If Z_DATA_ERROR is returned, the application may |
then call inflateSync() to look for a good compression block if a partial |
recovery of the data is desired. |
int inflateEnd OF((z_streamp strm)); |
All dynamically allocated data structures for this stream are freed. |
This function discards any unprocessed input and does not flush any pending |
output. |
inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state |
was inconsistent. In the error case, msg may be set but then points to a |
static string (which must not be deallocated). |
Advanced functions |
The following functions are needed only in some special applications. |
int deflateInit2 OF((z_streamp strm, |
int level, |
int method, |
int windowBits, |
int memLevel, |
int strategy)); |
This is another version of deflateInit with more compression options. The |
fields next_in, zalloc, zfree and opaque must be initialized before by the |
caller. |
The method parameter is the compression method. It must be Z_DEFLATED in |
this version of the library. |
The windowBits parameter is the base two logarithm of the window size |
(the size of the history buffer). It should be in the range 8..15 for this |
version of the library. Larger values of this parameter result in better |
compression at the expense of memory usage. The default value is 15 if |
deflateInit is used instead. |
windowBits can also be -8..-15 for raw deflate. In this case, -windowBits |
determines the window size. deflate() will then generate raw deflate data |
with no zlib header or trailer, and will not compute an adler32 check value. |
windowBits can also be greater than 15 for optional gzip encoding. Add |
16 to windowBits to write a simple gzip header and trailer around the |
compressed data instead of a zlib wrapper. The gzip header will have no |
file name, no extra data, no comment, no modification time (set to zero), no |
header crc, and the operating system will be set to 255 (unknown). If a |
gzip stream is being written, strm->adler is a crc32 instead of an adler32. |
The memLevel parameter specifies how much memory should be allocated |
for the internal compression state. memLevel=1 uses minimum memory but is |
slow and reduces compression ratio; memLevel=9 uses maximum memory for |
optimal speed. The default value is 8. See zconf.h for total memory usage |
as a function of windowBits and memLevel. |
The strategy parameter is used to tune the compression algorithm. Use the |
value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a |
filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no |
string match), or Z_RLE to limit match distances to one (run-length |
encoding). Filtered data consists mostly of small values with a somewhat |
random distribution. In this case, the compression algorithm is tuned to |
compress them better. The effect of Z_FILTERED is to force more Huffman |
coding and less string matching; it is somewhat intermediate between |
Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as |
fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data. The |
strategy parameter only affects the compression ratio but not the |
correctness of the compressed output even if it is not set appropriately. |
Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler |
decoder for special applications. |
deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough |
memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid |
method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is |
incompatible with the version assumed by the caller (ZLIB_VERSION). msg is |
set to null if there is no error message. deflateInit2 does not perform any |
compression: this will be done by deflate(). |
int deflateSetDictionary OF((z_streamp strm, |
const Bytef *dictionary, |
uInt dictLength)); |
Initializes the compression dictionary from the given byte sequence |
without producing any compressed output. When using the zlib format, this |
function must be called immediately after deflateInit, deflateInit2 or |
deflateReset, and before any call of deflate. When doing raw deflate, this |
function must be called either before any call of deflate, or immediately |
after the completion of a deflate block, i.e. after all input has been |
consumed and all output has been delivered when using any of the flush |
options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH. The |
compressor and decompressor must use exactly the same dictionary (see |
inflateSetDictionary). |
The dictionary should consist of strings (byte sequences) that are likely |
to be encountered later in the data to be compressed, with the most commonly |
used strings preferably put towards the end of the dictionary. Using a |
dictionary is most useful when the data to be compressed is short and can be |
predicted with good accuracy; the data can then be compressed better than |
with the default empty dictionary. |
Depending on the size of the compression data structures selected by |
deflateInit or deflateInit2, a part of the dictionary may in effect be |
discarded, for example if the dictionary is larger than the window size |
provided in deflateInit or deflateInit2. Thus the strings most likely to be |
useful should be put at the end of the dictionary, not at the front. In |
addition, the current implementation of deflate will use at most the window |
size minus 262 bytes of the provided dictionary. |
Upon return of this function, strm->adler is set to the adler32 value |
of the dictionary; the decompressor may later use this value to determine |
which dictionary has been used by the compressor. (The adler32 value |
applies to the whole dictionary even if only a subset of the dictionary is |
actually used by the compressor.) If a raw deflate was requested, then the |
adler32 value is not computed and strm->adler is not set. |
deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a |
parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is |
inconsistent (for example if deflate has already been called for this stream |
or if not at a block boundary for raw deflate). deflateSetDictionary does |
not perform any compression: this will be done by deflate(). |
int deflateCopy OF((z_streamp dest, |
z_streamp source)); |
Sets the destination stream as a complete copy of the source stream. |
This function can be useful when several compression strategies will be |
tried, for example when there are several ways of pre-processing the input |
data with a filter. The streams that will be discarded should then be freed |
by calling deflateEnd. Note that deflateCopy duplicates the internal |
compression state which can be quite large, so this strategy is slow and can |
consume lots of memory. |
deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not |
enough memory, Z_STREAM_ERROR if the source stream state was inconsistent |
(such as zalloc being Z_NULL). msg is left unchanged in both source and |
destination. |
int deflateReset OF((z_streamp strm)); |
This function is equivalent to deflateEnd followed by deflateInit, |
but does not free and reallocate all the internal compression state. The |
stream will keep the same compression level and any other attributes that |
may have been set by deflateInit2. |
deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source |
stream state was inconsistent (such as zalloc or state being Z_NULL). |
int deflateParams OF((z_streamp strm, |
int level, |
int strategy)); |
Dynamically update the compression level and compression strategy. The |
interpretation of level and strategy is as in deflateInit2. This can be |
used to switch between compression and straight copy of the input data, or |
to switch to a different kind of input data requiring a different strategy. |
If the compression level is changed, the input available so far is |
compressed with the old level (and may be flushed); the new level will take |
effect only at the next call of deflate(). |
Before the call of deflateParams, the stream state must be set as for |
a call of deflate(), since the currently available input may have to be |
compressed and flushed. In particular, strm->avail_out must be non-zero. |
deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source |
stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR if |
strm->avail_out was zero. |
int deflateTune OF((z_streamp strm, |
int good_length, |
int max_lazy, |
int nice_length, |
int max_chain)); |
Fine tune deflate's internal compression parameters. This should only be |
used by someone who understands the algorithm used by zlib's deflate for |
searching for the best matching string, and even then only by the most |
fanatic optimizer trying to squeeze out the last compressed bit for their |
specific input data. Read the deflate.c source code for the meaning of the |
max_lazy, good_length, nice_length, and max_chain parameters. |
deflateTune() can be called after deflateInit() or deflateInit2(), and |
returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. |
uLong deflateBound OF((z_streamp strm, |
uLong sourceLen)); |
deflateBound() returns an upper bound on the compressed size after |
deflation of sourceLen bytes. It must be called after deflateInit() or |
deflateInit2(), and after deflateSetHeader(), if used. This would be used |
to allocate an output buffer for deflation in a single pass, and so would be |
called before deflate(). If that first deflate() call is provided the |
sourceLen input bytes, an output buffer allocated to the size returned by |
deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed |
to return Z_STREAM_END. Note that it is possible for the compressed size to |
be larger than the value returned by deflateBound() if flush options other |
than Z_FINISH or Z_NO_FLUSH are used. |
int deflatePending OF((z_streamp strm, |
unsigned *pending, |
int *bits)); |
deflatePending() returns the number of bytes and bits of output that have |
been generated, but not yet provided in the available output. The bytes not |
provided would be due to the available output space having being consumed. |
The number of bits of output not provided are between 0 and 7, where they |
await more bits to join them in order to fill out a full byte. If pending |
or bits are Z_NULL, then those values are not set. |
deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source |
stream state was inconsistent. |
int deflatePrime OF((z_streamp strm, |
int bits, |
int value)); |
deflatePrime() inserts bits in the deflate output stream. The intent |
is that this function is used to start off the deflate output with the bits |
leftover from a previous deflate stream when appending to it. As such, this |
function can only be used for raw deflate, and must be used before the first |
deflate() call after a deflateInit2() or deflateReset(). bits must be less |
than or equal to 16, and that many of the least significant bits of value |
will be inserted in the output. |
deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough |
room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the |
source stream state was inconsistent. |
int deflateSetHeader OF((z_streamp strm, |
gz_headerp head)); |
deflateSetHeader() provides gzip header information for when a gzip |
stream is requested by deflateInit2(). deflateSetHeader() may be called |
after deflateInit2() or deflateReset() and before the first call of |
deflate(). The text, time, os, extra field, name, and comment information |
in the provided gz_header structure are written to the gzip header (xflag is |
ignored -- the extra flags are set according to the compression level). The |
caller must assure that, if not Z_NULL, name and comment are terminated with |
a zero byte, and that if extra is not Z_NULL, that extra_len bytes are |
available there. If hcrc is true, a gzip header crc is included. Note that |
the current versions of the command-line version of gzip (up through version |
1.3.x) do not support header crc's, and will report that it is a "multi-part |
gzip file" and give up. |
If deflateSetHeader is not used, the default gzip header has text false, |
the time set to zero, and os set to 255, with no extra, name, or comment |
fields. The gzip header is returned to the default state by deflateReset(). |
deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source |
stream state was inconsistent. |
int inflateInit2 OF((z_streamp strm, |
int windowBits)); |
This is another version of inflateInit with an extra parameter. The |
fields next_in, avail_in, zalloc, zfree and opaque must be initialized |
before by the caller. |
The windowBits parameter is the base two logarithm of the maximum window |
size (the size of the history buffer). It should be in the range 8..15 for |
this version of the library. The default value is 15 if inflateInit is used |
instead. windowBits must be greater than or equal to the windowBits value |
provided to deflateInit2() while compressing, or it must be equal to 15 if |
deflateInit2() was not used. If a compressed stream with a larger window |
size is given as input, inflate() will return with the error code |
Z_DATA_ERROR instead of trying to allocate a larger window. |
windowBits can also be zero to request that inflate use the window size in |
the zlib header of the compressed stream. |
windowBits can also be -8..-15 for raw inflate. In this case, -windowBits |
determines the window size. inflate() will then process raw deflate data, |
not looking for a zlib or gzip header, not generating a check value, and not |
looking for any check values for comparison at the end of the stream. This |
is for use with other formats that use the deflate compressed data format |
such as zip. Those formats provide their own check values. If a custom |
format is developed using the raw deflate format for compressed data, it is |
recommended that a check value such as an adler32 or a crc32 be applied to |
the uncompressed data as is done in the zlib, gzip, and zip formats. For |
most applications, the zlib format should be used as is. Note that comments |
above on the use in deflateInit2() applies to the magnitude of windowBits. |
windowBits can also be greater than 15 for optional gzip decoding. Add |
32 to windowBits to enable zlib and gzip decoding with automatic header |
detection, or add 16 to decode only the gzip format (the zlib format will |
return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a |
crc32 instead of an adler32. |
inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough |
memory, Z_VERSION_ERROR if the zlib library version is incompatible with the |
version assumed by the caller, or Z_STREAM_ERROR if the parameters are |
invalid, such as a null pointer to the structure. msg is set to null if |
there is no error message. inflateInit2 does not perform any decompression |
apart from possibly reading the zlib header if present: actual decompression |
will be done by inflate(). (So next_in and avail_in may be modified, but |
next_out and avail_out are unused and unchanged.) The current implementation |
of inflateInit2() does not process any header information -- that is |
deferred until inflate() is called. |
int inflateSetDictionary OF((z_streamp strm, |
const Bytef *dictionary, |
uInt dictLength)); |
Initializes the decompression dictionary from the given uncompressed byte |
sequence. This function must be called immediately after a call of inflate, |
if that call returned Z_NEED_DICT. The dictionary chosen by the compressor |
can be determined from the adler32 value returned by that call of inflate. |
The compressor and decompressor must use exactly the same dictionary (see |
deflateSetDictionary). For raw inflate, this function can be called at any |
time to set the dictionary. If the provided dictionary is smaller than the |
window and there is already data in the window, then the provided dictionary |
will amend what's there. The application must insure that the dictionary |
that was used for compression is provided. |
inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a |
parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is |
inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the |
expected one (incorrect adler32 value). inflateSetDictionary does not |
perform any decompression: this will be done by subsequent calls of |
inflate(). |
int inflateGetDictionary OF((z_streamp strm, |
Bytef *dictionary, |
uInt *dictLength)); |
Returns the sliding dictionary being maintained by inflate. dictLength is |
set to the number of bytes in the dictionary, and that many bytes are copied |
to dictionary. dictionary must have enough space, where 32768 bytes is |
always enough. If inflateGetDictionary() is called with dictionary equal to |
Z_NULL, then only the dictionary length is returned, and nothing is copied. |
Similary, if dictLength is Z_NULL, then it is not set. |
inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the |
stream state is inconsistent. |
int inflateSync OF((z_streamp strm)); |
Skips invalid compressed data until a possible full flush point (see above |
for the description of deflate with Z_FULL_FLUSH) can be found, or until all |
available input is skipped. No output is provided. |
inflateSync searches for a 00 00 FF FF pattern in the compressed data. |
All full flush points have this pattern, but not all occurrences of this |
pattern are full flush points. |
inflateSync returns Z_OK if a possible full flush point has been found, |
Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point |
has been found, or Z_STREAM_ERROR if the stream structure was inconsistent. |
In the success case, the application may save the current current value of |
total_in which indicates where valid compressed data was found. In the |
error case, the application may repeatedly call inflateSync, providing more |
input each time, until success or end of the input data. |
int inflateCopy OF((z_streamp dest, |
z_streamp source)); |
Sets the destination stream as a complete copy of the source stream. |
This function can be useful when randomly accessing a large stream. The |
first pass through the stream can periodically record the inflate state, |
allowing restarting inflate at those points when randomly accessing the |
stream. |
inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not |
enough memory, Z_STREAM_ERROR if the source stream state was inconsistent |
(such as zalloc being Z_NULL). msg is left unchanged in both source and |
destination. |
int inflateReset OF((z_streamp strm)); |
This function is equivalent to inflateEnd followed by inflateInit, |
but does not free and reallocate all the internal decompression state. The |
stream will keep attributes that may have been set by inflateInit2. |
inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source |
stream state was inconsistent (such as zalloc or state being Z_NULL). |
int inflateReset2 OF((z_streamp strm, |
int windowBits)); |
This function is the same as inflateReset, but it also permits changing |
the wrap and window size requests. The windowBits parameter is interpreted |
the same as it is for inflateInit2. |
inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source |
stream state was inconsistent (such as zalloc or state being Z_NULL), or if |
the windowBits parameter is invalid. |
int inflatePrime OF((z_streamp strm, |
int bits, |
int value)); |
This function inserts bits in the inflate input stream. The intent is |
that this function is used to start inflating at a bit position in the |
middle of a byte. The provided bits will be used before any bytes are used |
from next_in. This function should only be used with raw inflate, and |
should be used before the first inflate() call after inflateInit2() or |
inflateReset(). bits must be less than or equal to 16, and that many of the |
least significant bits of value will be inserted in the input. |
If bits is negative, then the input stream bit buffer is emptied. Then |
inflatePrime() can be called again to put bits in the buffer. This is used |
to clear out bits leftover after feeding inflate a block description prior |
to feeding inflate codes. |
inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source |
stream state was inconsistent. |
long inflateMark OF((z_streamp strm)); |
This function returns two values, one in the lower 16 bits of the return |
value, and the other in the remaining upper bits, obtained by shifting the |
return value down 16 bits. If the upper value is -1 and the lower value is |
zero, then inflate() is currently decoding information outside of a block. |
If the upper value is -1 and the lower value is non-zero, then inflate is in |
the middle of a stored block, with the lower value equaling the number of |
bytes from the input remaining to copy. If the upper value is not -1, then |
it is the number of bits back from the current bit position in the input of |
the code (literal or length/distance pair) currently being processed. In |
that case the lower value is the number of bytes already emitted for that |
code. |
A code is being processed if inflate is waiting for more input to complete |
decoding of the code, or if it has completed decoding but is waiting for |
more output space to write the literal or match data. |
inflateMark() is used to mark locations in the input data for random |
access, which may be at bit positions, and to note those cases where the |
output of a code may span boundaries of random access blocks. The current |
location in the input stream can be determined from avail_in and data_type |
as noted in the description for the Z_BLOCK flush parameter for inflate. |
inflateMark returns the value noted above or -1 << 16 if the provided |
source stream state was inconsistent. |
int inflateGetHeader OF((z_streamp strm, |
gz_headerp head)); |
inflateGetHeader() requests that gzip header information be stored in the |
provided gz_header structure. inflateGetHeader() may be called after |
inflateInit2() or inflateReset(), and before the first call of inflate(). |
As inflate() processes the gzip stream, head->done is zero until the header |
is completed, at which time head->done is set to one. If a zlib stream is |
being decoded, then head->done is set to -1 to indicate that there will be |
no gzip header information forthcoming. Note that Z_BLOCK or Z_TREES can be |
used to force inflate() to return immediately after header processing is |
complete and before any actual data is decompressed. |
The text, time, xflags, and os fields are filled in with the gzip header |
contents. hcrc is set to true if there is a header CRC. (The header CRC |
was valid if done is set to one.) If extra is not Z_NULL, then extra_max |
contains the maximum number of bytes to write to extra. Once done is true, |
extra_len contains the actual extra field length, and extra contains the |
extra field, or that field truncated if extra_max is less than extra_len. |
If name is not Z_NULL, then up to name_max characters are written there, |
terminated with a zero unless the length is greater than name_max. If |
comment is not Z_NULL, then up to comm_max characters are written there, |
terminated with a zero unless the length is greater than comm_max. When any |
of extra, name, or comment are not Z_NULL and the respective field is not |
present in the header, then that field is set to Z_NULL to signal its |
absence. This allows the use of deflateSetHeader() with the returned |
structure to duplicate the header. However if those fields are set to |
allocated memory, then the application will need to save those pointers |
elsewhere so that they can be eventually freed. |
If inflateGetHeader is not used, then the header information is simply |
discarded. The header is always checked for validity, including the header |
CRC if present. inflateReset() will reset the process to discard the header |
information. The application would need to call inflateGetHeader() again to |
retrieve the header from the next gzip stream. |
inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source |
stream state was inconsistent. |
int inflateBackInit OF((z_streamp strm, int windowBits, |
unsigned char FAR *window)); |
Initialize the internal stream state for decompression using inflateBack() |
calls. The fields zalloc, zfree and opaque in strm must be initialized |
before the call. If zalloc and zfree are Z_NULL, then the default library- |
derived memory allocation routines are used. windowBits is the base two |
logarithm of the window size, in the range 8..15. window is a caller |
supplied buffer of that size. Except for special applications where it is |
assured that deflate was used with small window sizes, windowBits must be 15 |
and a 32K byte window must be supplied to be able to decompress general |
deflate streams. |
See inflateBack() for the usage of these routines. |
inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of |
the parameters are invalid, Z_MEM_ERROR if the internal state could not be |
allocated, or Z_VERSION_ERROR if the version of the library does not match |
the version of the header file. |
typedef unsigned (*in_func) OF((void FAR *, |
z_const unsigned char FAR * FAR *)); |
typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); |
int inflateBack OF((z_streamp strm, |
in_func in, void FAR *in_desc, |
out_func out, void FAR *out_desc)); |
inflateBack() does a raw inflate with a single call using a call-back |
interface for input and output. This is potentially more efficient than |
inflate() for file i/o applications, in that it avoids copying between the |
output and the sliding window by simply making the window itself the output |
buffer. inflate() can be faster on modern CPUs when used with large |
buffers. inflateBack() trusts the application to not change the output |
buffer passed by the output function, at least until inflateBack() returns. |
inflateBackInit() must be called first to allocate the internal state |
and to initialize the state with the user-provided window buffer. |
inflateBack() may then be used multiple times to inflate a complete, raw |
deflate stream with each call. inflateBackEnd() is then called to free the |
allocated state. |
A raw deflate stream is one with no zlib or gzip header or trailer. |
This routine would normally be used in a utility that reads zip or gzip |
files and writes out uncompressed files. The utility would decode the |
header and process the trailer on its own, hence this routine expects only |
the raw deflate stream to decompress. This is different from the normal |
behavior of inflate(), which expects either a zlib or gzip header and |
trailer around the deflate stream. |
inflateBack() uses two subroutines supplied by the caller that are then |
called by inflateBack() for input and output. inflateBack() calls those |
routines until it reads a complete deflate stream and writes out all of the |
uncompressed data, or until it encounters an error. The function's |
parameters and return types are defined above in the in_func and out_func |
typedefs. inflateBack() will call in(in_desc, &buf) which should return the |
number of bytes of provided input, and a pointer to that input in buf. If |
there is no input available, in() must return zero--buf is ignored in that |
case--and inflateBack() will return a buffer error. inflateBack() will call |
out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() |
should return zero on success, or non-zero on failure. If out() returns |
non-zero, inflateBack() will return with an error. Neither in() nor out() |
are permitted to change the contents of the window provided to |
inflateBackInit(), which is also the buffer that out() uses to write from. |
The length written by out() will be at most the window size. Any non-zero |
amount of input may be provided by in(). |
For convenience, inflateBack() can be provided input on the first call by |
setting strm->next_in and strm->avail_in. If that input is exhausted, then |
in() will be called. Therefore strm->next_in must be initialized before |
calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called |
immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in |
must also be initialized, and then if strm->avail_in is not zero, input will |
initially be taken from strm->next_in[0 .. strm->avail_in - 1]. |
The in_desc and out_desc parameters of inflateBack() is passed as the |
first parameter of in() and out() respectively when they are called. These |
descriptors can be optionally used to pass any information that the caller- |
supplied in() and out() functions need to do their job. |
On return, inflateBack() will set strm->next_in and strm->avail_in to |
pass back any unused input that was provided by the last in() call. The |
return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR |
if in() or out() returned an error, Z_DATA_ERROR if there was a format error |
in the deflate stream (in which case strm->msg is set to indicate the nature |
of the error), or Z_STREAM_ERROR if the stream was not properly initialized. |
In the case of Z_BUF_ERROR, an input or output error can be distinguished |
using strm->next_in which will be Z_NULL only if in() returned an error. If |
strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning |
non-zero. (in() will always be called before out(), so strm->next_in is |
assured to be defined if out() returns non-zero.) Note that inflateBack() |
cannot return Z_OK. |
int inflateBackEnd OF((z_streamp strm)); |
All memory allocated by inflateBackInit() is freed. |
inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream |
state was inconsistent. |
uLong zlibCompileFlags OF((void)); |
Return flags indicating compile-time options. |
Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: |
1.0: size of uInt |
3.2: size of uLong |
5.4: size of voidpf (pointer) |
7.6: size of z_off_t |
Compiler, assembler, and debug options: |
8: DEBUG |
9: ASMV or ASMINF -- use ASM code |
10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention |
11: 0 (reserved) |
One-time table building (smaller code, but not thread-safe if true): |
12: BUILDFIXED -- build static block decoding tables when needed |
13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed |
14,15: 0 (reserved) |
Library content (indicates missing functionality): |
16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking |
deflate code when not needed) |
17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect |
and decode gzip streams (to avoid linking crc code) |
18-19: 0 (reserved) |
Operation variations (changes in library functionality): |
20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate |
21: FASTEST -- deflate algorithm with only one, lowest compression level |
22,23: 0 (reserved) |
The sprintf variant used by gzprintf (zero is best): |
24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format |
25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! |
26: 0 = returns value, 1 = void -- 1 means inferred string length returned |
Remainder: |
27-31: 0 (reserved) |
#ifndef Z_SOLO |
utility functions |
The following utility functions are implemented on top of the basic |
stream-oriented functions. To simplify the interface, some default options |
are assumed (compression level and memory usage, standard memory allocation |
functions). The source code of these utility functions can be modified if |
you need special options. |
int compress OF((Bytef *dest, uLongf *destLen, |
const Bytef *source, uLong sourceLen)); |
Compresses the source buffer into the destination buffer. sourceLen is |
the byte length of the source buffer. Upon entry, destLen is the total size |
of the destination buffer, which must be at least the value returned by |
compressBound(sourceLen). Upon exit, destLen is the actual size of the |
compressed buffer. |
compress returns Z_OK if success, Z_MEM_ERROR if there was not |
enough memory, Z_BUF_ERROR if there was not enough room in the output |
buffer. |
int compress2 OF((Bytef *dest, uLongf *destLen, |
const Bytef *source, uLong sourceLen, |
int level)); |
Compresses the source buffer into the destination buffer. The level |
parameter has the same meaning as in deflateInit. sourceLen is the byte |
length of the source buffer. Upon entry, destLen is the total size of the |
destination buffer, which must be at least the value returned by |
compressBound(sourceLen). Upon exit, destLen is the actual size of the |
compressed buffer. |
compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough |
memory, Z_BUF_ERROR if there was not enough room in the output buffer, |
Z_STREAM_ERROR if the level parameter is invalid. |
uLong compressBound OF((uLong sourceLen)); |
compressBound() returns an upper bound on the compressed size after |
compress() or compress2() on sourceLen bytes. It would be used before a |
compress() or compress2() call to allocate the destination buffer. |
int uncompress OF((Bytef *dest, uLongf *destLen, |
const Bytef *source, uLong sourceLen)); |
Decompresses the source buffer into the destination buffer. sourceLen is |
the byte length of the source buffer. Upon entry, destLen is the total size |
of the destination buffer, which must be large enough to hold the entire |
uncompressed data. (The size of the uncompressed data must have been saved |
previously by the compressor and transmitted to the decompressor by some |
mechanism outside the scope of this compression library.) Upon exit, destLen |
is the actual size of the uncompressed buffer. |
uncompress returns Z_OK if success, Z_MEM_ERROR if there was not |
enough memory, Z_BUF_ERROR if there was not enough room in the output |
buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. In |
the case where there is not enough room, uncompress() will fill the output |
buffer with the uncompressed data up to that point. |
gzip file access functions |
This library supports reading and writing files in gzip (.gz) format with |
an interface similar to that of stdio, using the functions that start with |
"gz". The gzip format is different from the zlib format. gzip is a gzip |
wrapper, documented in RFC 1952, wrapped around a deflate stream. |
typedef struct gzFile_s *gzFile; ;semi-opaque gzip file descriptor |
gzFile gzopen OF((const char *path, const char *mode)); |
Opens a gzip (.gz) file for reading or writing. The mode parameter is as |
in fopen ("rb" or "wb") but can also include a compression level ("wb9") or |
a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only |
compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F' |
for fixed code compression as in "wb9F". (See the description of |
deflateInit2 for more information about the strategy parameter.) 'T' will |
request transparent writing or appending with no compression and not using |
the gzip format. |
"a" can be used instead of "w" to request that the gzip stream that will |
be written be appended to the file. "+" will result in an error, since |
reading and writing to the same gzip file is not supported. The addition of |
"x" when writing will create the file exclusively, which fails if the file |
already exists. On systems that support it, the addition of "e" when |
reading or writing will set the flag to close the file on an execve() call. |
These functions, as well as gzip, will read and decode a sequence of gzip |
streams in a file. The append function of gzopen() can be used to create |
such a file. (Also see gzflush() for another way to do this.) When |
appending, gzopen does not test whether the file begins with a gzip stream, |
nor does it look for the end of the gzip streams to begin appending. gzopen |
will simply append a gzip stream to the existing file. |
gzopen can be used to read a file which is not in gzip format; in this |
case gzread will directly read from the file without decompression. When |
reading, this will be detected automatically by looking for the magic two- |
byte gzip header. |
gzopen returns NULL if the file could not be opened, if there was |
insufficient memory to allocate the gzFile state, or if an invalid mode was |
specified (an 'r', 'w', or 'a' was not provided, or '+' was provided). |
errno can be checked to determine if the reason gzopen failed was that the |
file could not be opened. |
gzFile gzdopen OF((int fd, const char *mode)); |
gzdopen associates a gzFile with the file descriptor fd. File descriptors |
are obtained from calls like open, dup, creat, pipe or fileno (if the file |
has been previously opened with fopen). The mode parameter is as in gzopen. |
The next call of gzclose on the returned gzFile will also close the file |
descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor |
fd. If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd, |
mode);. The duplicated descriptor should be saved to avoid a leak, since |
gzdopen does not close fd if it fails. If you are using fileno() to get the |
file descriptor from a FILE *, then you will have to use dup() to avoid |
double-close()ing the file descriptor. Both gzclose() and fclose() will |
close the associated file descriptor, so they need to have different file |
descriptors. |
gzdopen returns NULL if there was insufficient memory to allocate the |
gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not |
provided, or '+' was provided), or if fd is -1. The file descriptor is not |
used until the next gz* read, write, seek, or close operation, so gzdopen |
will not detect if fd is invalid (unless fd is -1). |
int gzbuffer OF((gzFile file, unsigned size)); |
Set the internal buffer size used by this library's functions. The |
default buffer size is 8192 bytes. This function must be called after |
gzopen() or gzdopen(), and before any other calls that read or write the |
file. The buffer memory allocation is always deferred to the first read or |
write. Two buffers are allocated, either both of the specified size when |
writing, or one of the specified size and the other twice that size when |
reading. A larger buffer size of, for example, 64K or 128K bytes will |
noticeably increase the speed of decompression (reading). |
The new buffer size also affects the maximum length for gzprintf(). |
gzbuffer() returns 0 on success, or -1 on failure, such as being called |
too late. |
int gzsetparams OF((gzFile file, int level, int strategy)); |
Dynamically update the compression level or strategy. See the description |
of deflateInit2 for the meaning of these parameters. |
gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not |
opened for writing. |
int gzread OF((gzFile file, voidp buf, unsigned len)); |
Reads the given number of uncompressed bytes from the compressed file. If |
the input file is not in gzip format, gzread copies the given number of |
bytes into the buffer directly from the file. |
After reaching the end of a gzip stream in the input, gzread will continue |
to read, looking for another gzip stream. Any number of gzip streams may be |
concatenated in the input file, and will all be decompressed by gzread(). |
If something other than a gzip stream is encountered after a gzip stream, |
that remaining trailing garbage is ignored (and no error is returned). |
gzread can be used to read a gzip file that is being concurrently written. |
Upon reaching the end of the input, gzread will return with the available |
data. If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then |
gzclearerr can be used to clear the end of file indicator in order to permit |
gzread to be tried again. Z_OK indicates that a gzip stream was completed |
on the last gzread. Z_BUF_ERROR indicates that the input file ended in the |
middle of a gzip stream. Note that gzread does not return -1 in the event |
of an incomplete gzip stream. This error is deferred until gzclose(), which |
will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip |
stream. Alternatively, gzerror can be used before gzclose to detect this |
case. |
gzread returns the number of uncompressed bytes actually read, less than |
len for end of file, or -1 for error. |
int gzwrite OF((gzFile file, |
voidpc buf, unsigned len)); |
Writes the given number of uncompressed bytes into the compressed file. |
gzwrite returns the number of uncompressed bytes written or 0 in case of |
error. |
int ZEXPORTVA gzprintf Z_ARG((gzFile file, const char *format, ...)); |
Converts, formats, and writes the arguments to the compressed file under |
control of the format string, as in fprintf. gzprintf returns the number of |
uncompressed bytes actually written, or 0 in case of error. The number of |
uncompressed bytes written is limited to 8191, or one less than the buffer |
size given to gzbuffer(). The caller should assure that this limit is not |
exceeded. If it is exceeded, then gzprintf() will return an error (0) with |
nothing written. In this case, there may also be a buffer overflow with |
unpredictable consequences, which is possible only if zlib was compiled with |
the insecure functions sprintf() or vsprintf() because the secure snprintf() |
or vsnprintf() functions were not available. This can be determined using |
zlibCompileFlags(). |
int gzputs OF((gzFile file, const char *s)); |
Writes the given null-terminated string to the compressed file, excluding |
the terminating null character. |
gzputs returns the number of characters written, or -1 in case of error. |
char * gzgets OF((gzFile file, char *buf, int len)); |
Reads bytes from the compressed file until len-1 characters are read, or a |
newline character is read and transferred to buf, or an end-of-file |
condition is encountered. If any characters are read or if len == 1, the |
string is terminated with a null character. If no characters are read due |
to an end-of-file or len < 1, then the buffer is left untouched. |
gzgets returns buf which is a null-terminated string, or it returns NULL |
for end-of-file or in case of error. If there was an error, the contents at |
buf are indeterminate. |
int gzputc OF((gzFile file, int c)); |
Writes c, converted to an unsigned char, into the compressed file. gzputc |
returns the value that was written, or -1 in case of error. |
int gzgetc OF((gzFile file)); |
Reads one byte from the compressed file. gzgetc returns this byte or -1 |
in case of end of file or error. This is implemented as a macro for speed. |
As such, it does not do all of the checking the other functions do. I.e. |
it does not check to see if file is NULL, nor whether the structure file |
points to has been clobbered or not. |
int gzungetc OF((int c, gzFile file)); |
Push one character back onto the stream to be read as the first character |
on the next read. At least one character of push-back is allowed. |
gzungetc() returns the character pushed, or -1 on failure. gzungetc() will |
fail if c is -1, and may fail if a character has been pushed but not read |
yet. If gzungetc is used immediately after gzopen or gzdopen, at least the |
output buffer size of pushed characters is allowed. (See gzbuffer above.) |
The pushed character will be discarded if the stream is repositioned with |
gzseek() or gzrewind(). |
int gzflush OF((gzFile file, int flush)); |
Flushes all pending output into the compressed file. The parameter flush |
is as in the deflate() function. The return value is the zlib error number |
(see function gzerror below). gzflush is only permitted when writing. |
If the flush parameter is Z_FINISH, the remaining data is written and the |
gzip stream is completed in the output. If gzwrite() is called again, a new |
gzip stream will be started in the output. gzread() is able to read such |
concatented gzip streams. |
gzflush should be called only when strictly necessary because it will |
degrade compression if called too often. |
z_off_t gzseek OF((gzFile file, |
z_off_t offset, int whence)); |
Sets the starting position for the next gzread or gzwrite on the given |
compressed file. The offset represents a number of bytes in the |
uncompressed data stream. The whence parameter is defined as in lseek(2); |
the value SEEK_END is not supported. |
If the file is opened for reading, this function is emulated but can be |
extremely slow. If the file is opened for writing, only forward seeks are |
supported; gzseek then compresses a sequence of zeroes up to the new |
starting position. |
gzseek returns the resulting offset location as measured in bytes from |
the beginning of the uncompressed stream, or -1 in case of error, in |
particular if the file is opened for writing and the new starting position |
would be before the current position. |
int gzrewind OF((gzFile file)); |
Rewinds the given file. This function is supported only for reading. |
gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) |
z_off_t gztell OF((gzFile file)); |
Returns the starting position for the next gzread or gzwrite on the given |
compressed file. This position represents a number of bytes in the |
uncompressed data stream, and is zero when starting, even if appending or |
reading a gzip stream from the middle of a file using gzdopen(). |
gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) |
z_off_t gzoffset OF((gzFile file)); |
Returns the current offset in the file being read or written. This offset |
includes the count of bytes that precede the gzip stream, for example when |
appending or when using gzdopen() for reading. When reading, the offset |
does not include as yet unused buffered input. This information can be used |
for a progress indicator. On error, gzoffset() returns -1. |
int gzeof OF((gzFile file)); |
Returns true (1) if the end-of-file indicator has been set while reading, |
false (0) otherwise. Note that the end-of-file indicator is set only if the |
read tried to go past the end of the input, but came up short. Therefore, |
just like feof(), gzeof() may return false even if there is no more data to |
read, in the event that the last read request was for the exact number of |
bytes remaining in the input file. This will happen if the input file size |
is an exact multiple of the buffer size. |
If gzeof() returns true, then the read functions will return no more data, |
unless the end-of-file indicator is reset by gzclearerr() and the input file |
has grown since the previous end of file was detected. |
int gzdirect OF((gzFile file)); |
Returns true (1) if file is being copied directly while reading, or false |
(0) if file is a gzip stream being decompressed. |
If the input file is empty, gzdirect() will return true, since the input |
does not contain a gzip stream. |
If gzdirect() is used immediately after gzopen() or gzdopen() it will |
cause buffers to be allocated to allow reading the file to determine if it |
is a gzip file. Therefore if gzbuffer() is used, it should be called before |
gzdirect(). |
When writing, gzdirect() returns true (1) if transparent writing was |
requested ("wT" for the gzopen() mode), or false (0) otherwise. (Note: |
gzdirect() is not needed when writing. Transparent writing must be |
explicitly requested, so the application already knows the answer. When |
linking statically, using gzdirect() will include all of the zlib code for |
gzip file reading and decompression, which may not be desired.) |
int gzclose OF((gzFile file)); |
Flushes all pending output if necessary, closes the compressed file and |
deallocates the (de)compression state. Note that once file is closed, you |
cannot call gzerror with file, since its structures have been deallocated. |
gzclose must not be called more than once on the same file, just as free |
must not be called more than once on the same allocation. |
gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a |
file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the |
last read ended in the middle of a gzip stream, or Z_OK on success. |
int gzclose_r OF((gzFile file)); |
int gzclose_w OF((gzFile file)); |
Same as gzclose(), but gzclose_r() is only for use when reading, and |
gzclose_w() is only for use when writing or appending. The advantage to |
using these instead of gzclose() is that they avoid linking in zlib |
compression or decompression code that is not used when only reading or only |
writing respectively. If gzclose() is used, then both compression and |
decompression code will be included the application when linking to a static |
zlib library. |
const char * gzerror OF((gzFile file, int *errnum)); |
Returns the error message for the last error which occurred on the given |
compressed file. errnum is set to zlib error number. If an error occurred |
in the file system and not in the compression library, errnum is set to |
Z_ERRNO and the application may consult errno to get the exact error code. |
The application must not modify the returned string. Future calls to |
this function may invalidate the previously returned string. If file is |
closed, then the string previously returned by gzerror will no longer be |
available. |
gzerror() should be used to distinguish errors from end-of-file for those |
functions above that do not distinguish those cases in their return values. |
void gzclearerr OF((gzFile file)); |
Clears the error and end-of-file flags for file. This is analogous to the |
clearerr() function in stdio. This is useful for continuing to read a gzip |
file that is being written concurrently. |
end if ;!Z_SOLO |
checksum functions |
These functions are not related to compression but are exported |
anyway because they might be useful in applications using the compression |
library. |
uLong adler32 OF((uLong adler, const Bytef *buf, uInt len)); |
Update a running Adler-32 checksum with the bytes buf[0..len-1] and |
return the updated checksum. If buf is Z_NULL, this function returns the |
required initial value for the checksum. |
An Adler-32 checksum is almost as reliable as a CRC32 but can be computed |
much faster. |
Usage example: |
uLong adler = adler32(0L, Z_NULL, 0); |
while (read_buffer(buffer, length) != EOF) { |
adler = adler32(adler, buffer, length); |
} |
if (adler != original_adler) error(); |
uLong adler32_combine OF((uLong adler1, uLong adler2, |
z_off_t len2)); |
Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 |
and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for |
each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of |
seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. Note |
that the z_off_t type (like off_t) is a signed integer. If len2 is |
negative, the result has no meaning or utility. |
uLong crc32 OF((uLong crc, const Bytef *buf, uInt len)); |
Update a running CRC-32 with the bytes buf[0..len-1] and return the |
updated CRC-32. If buf is Z_NULL, this function returns the required |
initial value for the crc. Pre- and post-conditioning (one's complement) is |
performed within this function so it shouldn't be done by the application. |
Usage example: |
uLong crc = crc32(0L, Z_NULL, 0); |
while (read_buffer(buffer, length) != EOF) { |
crc = crc32(crc, buffer, length); |
} |
if (crc != original_crc) error(); |
uLong crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); |
Combine two CRC-32 check values into one. For two sequences of bytes, |
seq1 and seq2 with lengths len1 and len2, CRC-32 check values were |
calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 |
check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and |
len2. |
/programs/fs/kfar/trunk/zlib/zutil.asm |
---|
0,0 → 1,203 |
; zutil.asm -- target dependent utility functions for the compression library |
; Copyright (C) 1995-2005, 2010, 2011, 2012 Jean-loup Gailly. |
; For conditions of distribution and use, see copyright notice in zlib.inc |
align 4 |
z_errmsg dd ze0,ze1,ze2,ze3,ze4,ze5,ze6,ze7,ze8,ze9 |
ze0 db 'need dictionary',0 ;Z_NEED_DICT 2 |
ze1 db 'stream end',0 ;Z_STREAM_END 1 |
ze2 db '',0 ;Z_OK 0 |
ze3 db 'file error',0 ;Z_ERRNO (-1) |
ze4 db 'stream error',0 ;Z_STREAM_ERROR (-2) |
ze5 db 'data error',0 ;Z_DATA_ERROR (-3) |
ze6 db 'insufficient memory',0 ;Z_MEM_ERROR (-4) |
ze7 db 'buffer error',0 ;Z_BUF_ERROR (-5) |
ze8 db 'incompatible version',0 ;Z_VERSION_ERROR (-6) |
ze9 db '',0 |
;const char * () |
align 4 |
proc zlibVersion |
mov eax,ZLIB_VERSION; |
ret |
endp |
;uLong () |
align 4 |
proc zlibCompileFlags |
; uLong flags; |
; flags = 0; |
; switch ((int)(sizeof(uInt))) { |
; case 2: break; |
; case 4: flags += 1; break; |
; case 8: flags += 2; break; |
; default: flags += 3; |
; } |
; switch ((int)(sizeof(uLong))) { |
; case 2: break; |
; case 4: flags += 1 << 2; break; |
; case 8: flags += 2 << 2; break; |
; default: flags += 3 << 2; |
; } |
; switch ((int)(sizeof(voidpf))) { |
; case 2: break; |
; case 4: flags += 1 << 4; break; |
; case 8: flags += 2 << 4; break; |
; default: flags += 3 << 4; |
; } |
; switch ((int)(sizeof(z_off_t))) { |
; case 2: break; |
; case 4: flags += 1 << 6; break; |
; case 8: flags += 2 << 6; break; |
; default: flags += 3 << 6; |
; } |
;if DEBUG |
; flags += 1 << 8; |
;end if |
;#if defined(ASMV) || defined(ASMINF) |
; flags += 1 << 9; |
;end if |
if ZLIB_WINAPI eq 1 |
; flags += 1 << 10; |
end if |
if BUILDFIXED eq 1 |
; flags += 1 << 12; |
end if |
if DYNAMIC_CRC_TABLE eq 1 |
; flags += 1 << 13; |
end if |
if NO_GZCOMPRESS eq 1 |
; flags += 1L << 16; |
end if |
if NO_GZIP eq 1 |
; flags += 1L << 17; |
end if |
if PKZIP_BUG_WORKAROUND eq 1 |
; flags += 1L << 20; |
end if |
if FASTEST eq 1 |
; flags += 1L << 21; |
end if |
;#if defined(STDC) || defined(Z_HAVE_STDARG_H) |
;# ifdef NO_vsnprintf |
; flags += 1L << 25; |
;# ifdef HAS_vsprintf_void |
; flags += 1L << 26; |
;# endif |
;# else |
;# ifdef HAS_vsnprintf_void |
; flags += 1L << 26; |
;# endif |
;# endif |
;#else |
; flags += 1L << 24; |
;# ifdef NO_snprintf |
; flags += 1L << 25; |
;# ifdef HAS_sprintf_void |
; flags += 1L << 26; |
;# endif |
;# else |
;# ifdef HAS_snprintf_void |
; flags += 1L << 26; |
;# endif |
;# endif |
;end if |
; return flags; |
ret |
endp |
;if DEBUG |
;# define verbose 0 |
;int z_verbose = verbose; |
;void (m) |
; char *m; |
align 4 |
proc z_error, m:dword |
; fprintf(stderr, "%s\n", m); |
; exit(1); |
ret |
endp |
;end if |
; exported to allow conversion of error code to string for compress() and |
; uncompress() |
;const char * (err) |
; int err; |
align 4 |
proc zError, err:dword |
; return ERR_MSG(err); |
ret |
endp |
;#ifndef HAVE_MEMCPY |
;void (dest, source, len) |
; Bytef* dest; |
; const Bytef* source; |
; uInt len; |
align 4 |
proc zmemcpy uses ecx edi esi, dest:dword, source:dword, len:dword |
mov ecx,[len] |
cmp ecx,0 |
jle @f |
mov edi,[dest] |
mov esi,[source] |
rep movsb |
jmp .end0 |
@@: |
zlib_debug 'zmemcpy size = %d',ecx |
.end0: |
ret |
endp |
;int (s1, s2, len) |
; const Bytef* s1; |
; const Bytef* s2; |
; uInt len; |
align 4 |
proc zmemcmp, s1:dword, s2:dword, len:dword |
; uInt j; |
; for (j = 0; j < len; j++) { |
; if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; |
; } |
; return 0; |
ret |
endp |
;void (dest, len) |
; Bytef* dest; |
; uInt len; |
align 4 |
proc zmemzero, dest:dword, len:dword |
; if (len == 0) return; |
; do { |
; *dest++ = 0; /* ??? to be unrolled */ |
; } while (--len != 0); |
ret |
endp |
;end if |
;#ifndef Z_SOLO |
;voidpf (voidpf opaque, unsigned items, unsigned size) |
align 4 |
proc zcalloc uses ebx ecx, opaque:dword, items:dword, size:dword |
mov ecx,[size] |
imul ecx,[items] |
mcall SF_SYS_MISC, SSF_MEM_ALLOC |
ret |
endp |
;void (voidpf opaque, voidpf ptr) |
align 4 |
proc zcfree uses eax ebx ecx, opaque:dword, p2ptr:dword |
mcall SF_SYS_MISC, SSF_MEM_FREE, [p2ptr] |
ret |
endp |
;end if /* !Z_SOLO */ |
/programs/fs/kfar/trunk/zlib/zutil.inc |
---|
0,0 → 1,88 |
; zutil.inc -- internal interface and configuration of the compression library |
; Copyright (C) 1995-2013 Jean-loup Gailly. |
; For conditions of distribution and use, see copyright notice in zlib.inc |
; WARNING: this file should *not* be used by applications. It is |
; part of the implementation of the compression library and is |
; subject to change. Applications should only use zlib.inc. |
macro ERR_MSG err |
{ |
mov ecx,Z_NEED_DICT-err |
mov ecx,[4*ecx+z_errmsg] |
} |
macro ERR_RETURN strm,err |
{ |
ERR_MSG err |
mov [strm+z_stream.msg],ecx |
mov eax,err |
} |
; To be used only when the state is known to be valid |
; /* common constants */ |
;#ifndef DEF_WBITS |
;# define DEF_WBITS MAX_WBITS |
;end if |
; default windowBits for decompression. MAX_WBITS is for compression only |
;#if MAX_MEM_LEVEL >= 8 |
DEF_MEM_LEVEL equ 8 |
;#else |
;# define DEF_MEM_LEVEL MAX_MEM_LEVEL |
;end if |
; default memLevel |
STORED_BLOCK equ 0 |
STATIC_TREES equ 1 |
DYN_TREES equ 2 |
; The three kinds of block type |
MIN_MATCH equ 3 |
MAX_MATCH equ 258 |
; The minimum and maximum match lengths |
PRESET_DICT equ 0x20 ;preset dictionary flag in zlib header |
; /* common defaults */ |
OS_CODE equ 0x03 ;assume Unix |
; /* functions */ |
; Diagnostic functions |
;if DEBUG eq 1 |
;# define Trace(x) {if (z_verbose>=0) fprintf x ;} |
;# define Tracev(x) {if (z_verbose>0) fprintf x ;} |
macro Tracevv mes1, mes2 |
{ |
;zlib_debug 'Tracevv = %d', mes1 |
} |
;# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} |
;# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} |
;end if |
macro ZALLOC strm, items, size |
{ |
stdcall dword[strm+z_stream.zalloc], [strm+z_stream.opaque], items, size |
} |
macro ZFREE strm, p2addr |
{ |
stdcall dword[strm+z_stream.zfree], dword[strm+z_stream.opaque], p2addr |
} |
macro TRY_FREE s, p |
{ |
local .end0 |
cmp p,0 |
je .end0 |
ZFREE s, p |
.end0: |
} |
; Reverse the bytes in a 32-bit value |
macro ZSWAP32 q |
{ |
bswap q |
} |