;/* inffas32.asm is a hand tuned assembler version of inffast.c -- fast decoding

; *

; * inffas32.asm is derivated from inffas86.c, with translation of assembly code

; *

; * Copyright (C) 1995-2003 Mark Adler

; * For conditions of distribution and use, see copyright notice in zlib.h

; *

; * Copyright (C) 2003 Chris Anderson <christop@charm.net>

; * Please use the copyright conditions above.

; *

; * Mar-13-2003 -- Most of this is derived from inffast.S which is derived from

; * the gcc -S output of zlib-1.2.0/inffast.c.  Zlib-1.2.0 is in beta release at

; * the moment.  I have successfully compiled and tested this code with gcc2.96,

; * gcc3.2, icc5.0, msvc6.0.  It is very close to the speed of inffast.S

; * compiled with gcc -DNO_MMX, but inffast.S is still faster on the P3 with MMX

; * enabled.  I will attempt to merge the MMX code into this version.  Newer

; * versions of this and inffast.S can be found at

; * http://www.eetbeetee.com/zlib/ and http://www.charm.net/~christop/zlib/

; * 

; * 2005 : modification by Gilles Vollant

; */

; For Visual C++ 4.x and higher and ML 6.x and higher

;   ml.exe is in directory \MASM611C of Win95 DDK

;   ml.exe is also distributed in http://www.masm32.com/masmdl.htm

;    and in VC++2003 toolkit at http://msdn.microsoft.com/visualc/vctoolkit2003/

;

;

;   compile with command line option

;   ml  /coff /Zi /c /Flinffas32.lst inffas32.asm



;   if you define NO_GZIP (see inflate.h), compile with

;   ml  /coff /Zi /c /Flinffas32.lst /DNO_GUNZIP inffas32.asm





; zlib122sup is 0 fort zlib 1.2.2.1 and lower

; zlib122sup is 8 fort zlib 1.2.2.2 and more (with addition of dmax and head 

;        in inflate_state in inflate.h)

zlib1222sup      equ    8





IFDEF GUNZIP

  INFLATE_MODE_TYPE    equ 11

  INFLATE_MODE_BAD     equ 26

ELSE

  IFNDEF NO_GUNZIP

    INFLATE_MODE_TYPE    equ 11

    INFLATE_MODE_BAD     equ 26

  ELSE

    INFLATE_MODE_TYPE    equ 3

    INFLATE_MODE_BAD     equ 17

  ENDIF

ENDIF





; 75 "inffast.S"

;FILE "inffast.S"



;;;GLOBAL _inflate_fast



;;;SECTION .text







	.586p

	.mmx



	name	inflate_fast_x86

	.MODEL	FLAT



_DATA			segment

inflate_fast_use_mmx:

	dd	1





_TEXT			segment

PUBLIC _inflate_fast



ALIGN 4

_inflate_fast:

	jmp inflate_fast_entry







ALIGN 4

	db	'Fast decoding Code from Chris Anderson'

	db	0



ALIGN 4

invalid_literal_length_code_msg:

	db	'invalid literal/length code'

	db	0



ALIGN 4

invalid_distance_code_msg:

	db	'invalid distance code'

	db	0



ALIGN 4

invalid_distance_too_far_msg:

	db	'invalid distance too far back'

	db	0





ALIGN 4

inflate_fast_mask:

dd	0

dd	1

dd	3

dd	7

dd	15

dd	31

dd	63

dd	127

dd	255

dd	511

dd	1023

dd	2047

dd	4095

dd	8191

dd	16383

dd	32767

dd	65535

dd	131071

dd	262143

dd	524287

dd	1048575

dd	2097151

dd	4194303

dd	8388607

dd	16777215

dd	33554431

dd	67108863

dd	134217727

dd	268435455

dd	536870911

dd	1073741823

dd	2147483647

dd	4294967295





mode_state	 equ	0	;/* state->mode	*/

wsize_state	 equ	(32+zlib1222sup)	;/* state->wsize */

write_state	 equ	(36+4+zlib1222sup)	;/* state->write */

window_state	 equ	(40+4+zlib1222sup)	;/* state->window */

hold_state	 equ	(44+4+zlib1222sup)	;/* state->hold	*/

bits_state	 equ	(48+4+zlib1222sup)	;/* state->bits	*/

lencode_state	 equ	(64+4+zlib1222sup)	;/* state->lencode */

distcode_state	 equ	(68+4+zlib1222sup)	;/* state->distcode */

lenbits_state	 equ	(72+4+zlib1222sup)	;/* state->lenbits */

distbits_state	 equ	(76+4+zlib1222sup)	;/* state->distbits */





;;SECTION .text

; 205 "inffast.S"

;GLOBAL	inflate_fast_use_mmx



;SECTION .data





; GLOBAL inflate_fast_use_mmx:object

;.size inflate_fast_use_mmx, 4

; 226 "inffast.S"

;SECTION .text



ALIGN 4

inflate_fast_entry:

	push  edi

	push  esi

	push  ebp

	push  ebx

	pushfd

	sub  esp,64

	cld









	mov  esi, [esp+88]

	mov  edi, [esi+28]















	mov  edx, [esi+4]

	mov  eax, [esi+0]



	add  edx,eax

	sub  edx,11



	mov  [esp+44],eax

	mov  [esp+20],edx



	mov  ebp, [esp+92]

	mov  ecx, [esi+16]

	mov  ebx, [esi+12]



	sub  ebp,ecx

	neg  ebp

	add  ebp,ebx



	sub  ecx,257

	add  ecx,ebx



	mov  [esp+60],ebx

	mov  [esp+40],ebp

	mov  [esp+16],ecx

; 285 "inffast.S"

	mov  eax, [edi+lencode_state]

	mov  ecx, [edi+distcode_state]



	mov  [esp+8],eax

	mov  [esp+12],ecx



	mov  eax,1

	mov  ecx, [edi+lenbits_state]

	shl  eax,cl

	dec  eax

	mov  [esp+0],eax



	mov  eax,1

	mov  ecx, [edi+distbits_state]

	shl  eax,cl

	dec  eax

	mov  [esp+4],eax



	mov  eax, [edi+wsize_state]

	mov  ecx, [edi+write_state]

	mov  edx, [edi+window_state]



	mov  [esp+52],eax

	mov  [esp+48],ecx

	mov  [esp+56],edx



	mov  ebp, [edi+hold_state]

	mov  ebx, [edi+bits_state]

; 321 "inffast.S"

	mov  esi, [esp+44]

	mov  ecx, [esp+20]

	cmp  ecx,esi

	ja   L_align_long



	add  ecx,11

	sub  ecx,esi

	mov  eax,12

	sub  eax,ecx

	lea  edi, [esp+28]

	rep movsb

	mov  ecx,eax

	xor  eax,eax

	rep stosb

	lea  esi, [esp+28]

	mov  [esp+20],esi

	jmp  L_is_aligned





L_align_long:

	test  esi,3

	jz   L_is_aligned

	xor  eax,eax

	mov  al, [esi]

	inc  esi

	mov  ecx,ebx

	add  ebx,8

	shl  eax,cl

	or  ebp,eax

	jmp L_align_long



L_is_aligned:

	mov  edi, [esp+60]

; 366 "inffast.S"

L_check_mmx:

	cmp  dword ptr [inflate_fast_use_mmx],2

	je   L_init_mmx

	ja   L_do_loop



	push  eax

	push  ebx

	push  ecx

	push  edx

	pushfd

	mov  eax, [esp]

	xor  dword ptr [esp],0200000h









	popfd

	pushfd

	pop  edx

	xor  edx,eax

	jz   L_dont_use_mmx

	xor  eax,eax

	cpuid

	cmp  ebx,0756e6547h

	jne  L_dont_use_mmx

	cmp  ecx,06c65746eh

	jne  L_dont_use_mmx

	cmp  edx,049656e69h

	jne  L_dont_use_mmx

	mov  eax,1

	cpuid

	shr  eax,8

	and  eax,15

	cmp  eax,6

	jne  L_dont_use_mmx

	test  edx,0800000h

	jnz  L_use_mmx

	jmp  L_dont_use_mmx

L_use_mmx:

	mov  dword ptr [inflate_fast_use_mmx],2

	jmp  L_check_mmx_pop

L_dont_use_mmx:

	mov  dword ptr [inflate_fast_use_mmx],3

L_check_mmx_pop:

	pop  edx

	pop  ecx

	pop  ebx

	pop  eax

	jmp  L_check_mmx

; 426 "inffast.S"

ALIGN 4

L_do_loop:

; 437 "inffast.S"

	cmp  bl,15

	ja   L_get_length_code



	xor  eax,eax

	lodsw

	mov  cl,bl

	add  bl,16

	shl  eax,cl

	or  ebp,eax



L_get_length_code:

	mov  edx, [esp+0]

	mov  ecx, [esp+8]

	and  edx,ebp

	mov  eax, [ecx+edx*4]



L_dolen:













	mov  cl,ah

	sub  bl,ah

	shr  ebp,cl













	test  al,al

	jnz   L_test_for_length_base



	shr  eax,16

	stosb



L_while_test:





	cmp  [esp+16],edi

	jbe  L_break_loop



	cmp  [esp+20],esi

	ja   L_do_loop

	jmp  L_break_loop



L_test_for_length_base:

; 502 "inffast.S"

	mov  edx,eax

	shr  edx,16

	mov  cl,al



	test  al,16

	jz   L_test_for_second_level_length

	and  cl,15

	jz   L_save_len

	cmp  bl,cl

	jae  L_add_bits_to_len



	mov  ch,cl

	xor  eax,eax

	lodsw

	mov  cl,bl

	add  bl,16

	shl  eax,cl

	or  ebp,eax

	mov  cl,ch



L_add_bits_to_len:

	mov  eax,1

	shl  eax,cl

	dec  eax

	sub  bl,cl

	and  eax,ebp

	shr  ebp,cl

	add  edx,eax



L_save_len:

	mov  [esp+24],edx





L_decode_distance:

; 549 "inffast.S"

	cmp  bl,15

	ja   L_get_distance_code



	xor  eax,eax

	lodsw

	mov  cl,bl

	add  bl,16

	shl  eax,cl

	or  ebp,eax



L_get_distance_code:

	mov  edx, [esp+4]

	mov  ecx, [esp+12]

	and  edx,ebp

	mov  eax, [ecx+edx*4]





L_dodist:

	mov  edx,eax

	shr  edx,16

	mov  cl,ah

	sub  bl,ah

	shr  ebp,cl

; 584 "inffast.S"

	mov  cl,al



	test  al,16

	jz  L_test_for_second_level_dist

	and  cl,15

	jz  L_check_dist_one

	cmp  bl,cl

	jae  L_add_bits_to_dist



	mov  ch,cl

	xor  eax,eax

	lodsw

	mov  cl,bl

	add  bl,16

	shl  eax,cl

	or  ebp,eax

	mov  cl,ch



L_add_bits_to_dist:

	mov  eax,1

	shl  eax,cl

	dec  eax

	sub  bl,cl

	and  eax,ebp

	shr  ebp,cl

	add  edx,eax

	jmp  L_check_window



L_check_window:

; 625 "inffast.S"

	mov  [esp+44],esi

	mov  eax,edi

	sub  eax, [esp+40]



	cmp  eax,edx

	jb   L_clip_window



	mov  ecx, [esp+24]

	mov  esi,edi

	sub  esi,edx



	sub  ecx,3

	mov  al, [esi]

	mov  [edi],al

	mov  al, [esi+1]

	mov  dl, [esi+2]

	add  esi,3

	mov  [edi+1],al

	mov  [edi+2],dl

	add  edi,3

	rep movsb



	mov  esi, [esp+44]

	jmp  L_while_test



ALIGN 4

L_check_dist_one:

	cmp  edx,1

	jne  L_check_window

	cmp  [esp+40],edi

	je  L_check_window



	dec  edi

	mov  ecx, [esp+24]

	mov  al, [edi]

	sub  ecx,3



	mov  [edi+1],al

	mov  [edi+2],al

	mov  [edi+3],al

	add  edi,4

	rep stosb



	jmp  L_while_test



ALIGN 4

L_test_for_second_level_length:









	test  al,64

	jnz   L_test_for_end_of_block



	mov  eax,1

	shl  eax,cl

	dec  eax

	and  eax,ebp

	add  eax,edx

	mov  edx, [esp+8]

	mov  eax, [edx+eax*4]

	jmp  L_dolen



ALIGN 4

L_test_for_second_level_dist:









	test  al,64

	jnz   L_invalid_distance_code



	mov  eax,1

	shl  eax,cl

	dec  eax

	and  eax,ebp

	add  eax,edx

	mov  edx, [esp+12]

	mov  eax, [edx+eax*4]

	jmp  L_dodist



ALIGN 4

L_clip_window:

; 721 "inffast.S"

	mov  ecx,eax

	mov  eax, [esp+52]

	neg  ecx

	mov  esi, [esp+56]



	cmp  eax,edx

	jb   L_invalid_distance_too_far



	add  ecx,edx

	cmp  dword ptr [esp+48],0

	jne  L_wrap_around_window



	sub  eax,ecx

	add  esi,eax

; 749 "inffast.S"

	mov  eax, [esp+24]

	cmp  eax,ecx

	jbe  L_do_copy1



	sub  eax,ecx

	rep movsb

	mov  esi,edi

	sub  esi,edx

	jmp  L_do_copy1



	cmp  eax,ecx

	jbe  L_do_copy1



	sub  eax,ecx

	rep movsb

	mov  esi,edi

	sub  esi,edx

	jmp  L_do_copy1



L_wrap_around_window:

; 793 "inffast.S"

	mov  eax, [esp+48]

	cmp  ecx,eax

	jbe  L_contiguous_in_window



	add  esi, [esp+52]

	add  esi,eax

	sub  esi,ecx

	sub  ecx,eax





	mov  eax, [esp+24]

	cmp  eax,ecx

	jbe  L_do_copy1



	sub  eax,ecx

	rep movsb

	mov  esi, [esp+56]

	mov  ecx, [esp+48]

	cmp  eax,ecx

	jbe  L_do_copy1



	sub  eax,ecx

	rep movsb

	mov  esi,edi

	sub  esi,edx

	jmp  L_do_copy1



L_contiguous_in_window:

; 836 "inffast.S"

	add  esi,eax

	sub  esi,ecx





	mov  eax, [esp+24]

	cmp  eax,ecx

	jbe  L_do_copy1



	sub  eax,ecx

	rep movsb

	mov  esi,edi

	sub  esi,edx



L_do_copy1:

; 862 "inffast.S"

	mov  ecx,eax

	rep movsb



	mov  esi, [esp+44]

	jmp  L_while_test

; 878 "inffast.S"

ALIGN 4

L_init_mmx:

	emms











	movd mm0,ebp

	mov  ebp,ebx

; 896 "inffast.S"

	movd mm4,[esp+0]

	movq mm3,mm4

	movd mm5,[esp+4]

	movq mm2,mm5

	pxor mm1,mm1

	mov  ebx, [esp+8]

	jmp  L_do_loop_mmx



ALIGN 4

L_do_loop_mmx:

	psrlq mm0,mm1



	cmp  ebp,32

	ja  L_get_length_code_mmx



	movd mm6,ebp

	movd mm7,[esi]

	add  esi,4

	psllq mm7,mm6

	add  ebp,32

	por mm0,mm7



L_get_length_code_mmx:

	pand mm4,mm0

	movd eax,mm4

	movq mm4,mm3

	mov  eax, [ebx+eax*4]



L_dolen_mmx:

	movzx  ecx,ah

	movd mm1,ecx

	sub  ebp,ecx



	test  al,al

	jnz L_test_for_length_base_mmx



	shr  eax,16

	stosb



L_while_test_mmx:





	cmp  [esp+16],edi

	jbe L_break_loop



	cmp  [esp+20],esi

	ja L_do_loop_mmx

	jmp L_break_loop



L_test_for_length_base_mmx:



	mov  edx,eax

	shr  edx,16



	test  al,16

	jz  L_test_for_second_level_length_mmx

	and  eax,15

	jz L_decode_distance_mmx



	psrlq mm0,mm1

	movd mm1,eax

	movd ecx,mm0

	sub  ebp,eax

	and  ecx, [inflate_fast_mask+eax*4]

	add  edx,ecx



L_decode_distance_mmx:

	psrlq mm0,mm1



	cmp  ebp,32

	ja L_get_dist_code_mmx



	movd mm6,ebp

	movd mm7,[esi]

	add  esi,4

	psllq mm7,mm6

	add  ebp,32

	por mm0,mm7



L_get_dist_code_mmx:

	mov  ebx, [esp+12]

	pand mm5,mm0

	movd eax,mm5

	movq mm5,mm2

	mov  eax, [ebx+eax*4]



L_dodist_mmx:



	movzx  ecx,ah

	mov  ebx,eax

	shr  ebx,16

	sub  ebp,ecx

	movd mm1,ecx



	test  al,16

	jz L_test_for_second_level_dist_mmx

	and  eax,15

	jz L_check_dist_one_mmx



L_add_bits_to_dist_mmx:

	psrlq mm0,mm1

	movd mm1,eax

	movd ecx,mm0

	sub  ebp,eax

	and  ecx, [inflate_fast_mask+eax*4]

	add  ebx,ecx



L_check_window_mmx:

	mov  [esp+44],esi

	mov  eax,edi

	sub  eax, [esp+40]



	cmp  eax,ebx

	jb L_clip_window_mmx



	mov  ecx,edx

	mov  esi,edi

	sub  esi,ebx



	sub  ecx,3

	mov  al, [esi]

	mov  [edi],al

	mov  al, [esi+1]

	mov  dl, [esi+2]

	add  esi,3

	mov  [edi+1],al

	mov  [edi+2],dl

	add  edi,3

	rep movsb



	mov  esi, [esp+44]

	mov  ebx, [esp+8]

	jmp  L_while_test_mmx



ALIGN 4

L_check_dist_one_mmx:

	cmp  ebx,1

	jne  L_check_window_mmx

	cmp  [esp+40],edi

	je   L_check_window_mmx



	dec  edi

	mov  ecx,edx

	mov  al, [edi]

	sub  ecx,3



	mov  [edi+1],al

	mov  [edi+2],al

	mov  [edi+3],al

	add  edi,4

	rep stosb



	mov  ebx, [esp+8]

	jmp  L_while_test_mmx



ALIGN 4

L_test_for_second_level_length_mmx:

	test  al,64

	jnz L_test_for_end_of_block



	and  eax,15

	psrlq mm0,mm1

	movd ecx,mm0

	and  ecx, [inflate_fast_mask+eax*4]

	add  ecx,edx

	mov  eax, [ebx+ecx*4]

	jmp L_dolen_mmx



ALIGN 4

L_test_for_second_level_dist_mmx:

	test  al,64

	jnz L_invalid_distance_code



	and  eax,15

	psrlq mm0,mm1

	movd ecx,mm0

	and  ecx, [inflate_fast_mask+eax*4]

	mov  eax, [esp+12]

	add  ecx,ebx

	mov  eax, [eax+ecx*4]

	jmp  L_dodist_mmx



ALIGN 4

L_clip_window_mmx:



	mov  ecx,eax

	mov  eax, [esp+52]

	neg  ecx

	mov  esi, [esp+56]



	cmp  eax,ebx

	jb  L_invalid_distance_too_far



	add  ecx,ebx

	cmp  dword ptr [esp+48],0

	jne  L_wrap_around_window_mmx



	sub  eax,ecx

	add  esi,eax



	cmp  edx,ecx

	jbe  L_do_copy1_mmx



	sub  edx,ecx

	rep movsb

	mov  esi,edi

	sub  esi,ebx

	jmp  L_do_copy1_mmx



	cmp  edx,ecx

	jbe  L_do_copy1_mmx



	sub  edx,ecx

	rep movsb

	mov  esi,edi

	sub  esi,ebx

	jmp  L_do_copy1_mmx



L_wrap_around_window_mmx:



	mov  eax, [esp+48]

	cmp  ecx,eax

	jbe  L_contiguous_in_window_mmx



	add  esi, [esp+52]

	add  esi,eax

	sub  esi,ecx

	sub  ecx,eax





	cmp  edx,ecx

	jbe  L_do_copy1_mmx



	sub  edx,ecx

	rep movsb

	mov  esi, [esp+56]

	mov  ecx, [esp+48]

	cmp  edx,ecx

	jbe  L_do_copy1_mmx



	sub  edx,ecx

	rep movsb

	mov  esi,edi

	sub  esi,ebx

	jmp  L_do_copy1_mmx



L_contiguous_in_window_mmx:



	add  esi,eax

	sub  esi,ecx





	cmp  edx,ecx

	jbe  L_do_copy1_mmx



	sub  edx,ecx

	rep movsb

	mov  esi,edi

	sub  esi,ebx



L_do_copy1_mmx:





	mov  ecx,edx

	rep movsb



	mov  esi, [esp+44]

	mov  ebx, [esp+8]

	jmp  L_while_test_mmx

; 1174 "inffast.S"

L_invalid_distance_code:











	mov  ecx, invalid_distance_code_msg

	mov  edx,INFLATE_MODE_BAD

	jmp  L_update_stream_state



L_test_for_end_of_block:











	test  al,32

	jz  L_invalid_literal_length_code



	mov  ecx,0

	mov  edx,INFLATE_MODE_TYPE

	jmp  L_update_stream_state



L_invalid_literal_length_code:











	mov  ecx, invalid_literal_length_code_msg

	mov  edx,INFLATE_MODE_BAD

	jmp  L_update_stream_state



L_invalid_distance_too_far:







	mov  esi, [esp+44]

	mov  ecx, invalid_distance_too_far_msg

	mov  edx,INFLATE_MODE_BAD

	jmp  L_update_stream_state



L_update_stream_state:



	mov  eax, [esp+88]

	test  ecx,ecx

	jz  L_skip_msg

	mov  [eax+24],ecx

L_skip_msg:

	mov  eax, [eax+28]

	mov  [eax+mode_state],edx

	jmp  L_break_loop



ALIGN 4

L_break_loop:

; 1243 "inffast.S"

	cmp  dword ptr [inflate_fast_use_mmx],2

	jne  L_update_next_in







	mov  ebx,ebp



L_update_next_in:

; 1266 "inffast.S"

	mov  eax, [esp+88]

	mov  ecx,ebx

	mov  edx, [eax+28]

	shr  ecx,3

	sub  esi,ecx

	shl  ecx,3

	sub  ebx,ecx

	mov  [eax+12],edi

	mov  [edx+bits_state],ebx

	mov  ecx,ebx



	lea  ebx, [esp+28]

	cmp  [esp+20],ebx

	jne  L_buf_not_used



	sub  esi,ebx

	mov  ebx, [eax+0]

	mov  [esp+20],ebx

	add  esi,ebx

	mov  ebx, [eax+4]

	sub  ebx,11

	add  [esp+20],ebx



L_buf_not_used:

	mov  [eax+0],esi



	mov  ebx,1

	shl  ebx,cl

	dec  ebx











	cmp  dword ptr [inflate_fast_use_mmx],2

	jne  L_update_hold







	psrlq mm0,mm1

	movd ebp,mm0



	emms



L_update_hold:







	and  ebp,ebx

	mov  [edx+hold_state],ebp









	mov  ebx, [esp+20]

	cmp  ebx,esi

	jbe  L_last_is_smaller



	sub  ebx,esi

	add  ebx,11

	mov  [eax+4],ebx

	jmp  L_fixup_out

L_last_is_smaller:

	sub  esi,ebx

	neg  esi

	add  esi,11

	mov  [eax+4],esi









L_fixup_out:



	mov  ebx, [esp+16]

	cmp  ebx,edi

	jbe  L_end_is_smaller



	sub  ebx,edi

	add  ebx,257

	mov  [eax+16],ebx

	jmp  L_done

L_end_is_smaller:

	sub  edi,ebx

	neg  edi

	add  edi,257

	mov  [eax+16],edi











L_done:

	add  esp,64

	popfd

	pop  ebx

	pop  ebp

	pop  esi

	pop  edi

	ret



_TEXT	ends

end

