123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477 |
- ;===========================================================================
- ; Copyright (c) 1990-2008 Info-ZIP. All rights reserved.
- ;
- ; See the accompanying file LICENSE, version 2007-Mar-04 or later
- ; (the contents of which are also included in zip.h) for terms of use.
- ; If, for some reason, all these files are missing, the Info-ZIP license
- ; also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
- ;===========================================================================
- ;
- ; match.asm by Jean-loup Gailly.
- ; match.asm, optimized version of longest_match() in deflate.c
- ; Must be assembled with masm -ml. To be used only with C compact model
- ; or large model. (For large model, assemble with -D__LARGE__).
- ; This file is only optional. If you don't have masm or tasm, use the
- ; C version (add -DNO_ASM to CFLAGS in makefile.msc and remove match.obj
- ; from OBJI). If you have reduced WSIZE in zip.h, then make sure this is
- ; assembled with an equivalent -DWSIZE=<whatever>.
- ;
- ; The code has been prepared for two different C compiler calling conventions
- ; and contains some support for dynamically allocated working space.
- ; The different environments are selected by two conditional flags:
- ; DYN_ALLOC : select support for malloc'ed working space
- ; SS_NEQ_DS : relaxes assumption that stack and default data segments
- ; are identical
- ; When SS_NEQ_DS is defined, the code segment is used to store some
- ; local variables. This (bad) coding practice is very likely to break any
- ; `segment protection scheme', it will most probably only work for real
- ; mode programs.
- ;
- ; Turbo C 2.0 does not support static allocation of more than 64K bytes per
- ; file, and does not have SS == DS. So TC and BC++ users must use:
- ; tasm -ml -DDYN_ALLOC -DSS_NEQ_DS match;
- ;
- ; To simplify the code, the option -DDYN_ALLOC is supported for OS/2
- ; only if the arrays are guaranteed to have zero offset (allocated by
- ; halloc). We also require SS==DS. This is satisfied for MSC but not Turbo C.
- ;
- ; Per default, test code is included to check if the above requirements are
- ; fulfilled. This test code can be disabled by defining the compile time
- ; option flag NO_SECURE_TESTS when compiling for a production executable.
- ; This shortens the code size (but the performance gain is neglectable).
- ; The security tests should remain enabled, when a new C compiler
- ; and/or a new set of compilation options is tried.
- name match
- ; Do NOT assemble this source if external crc32 routine from zlib gets used.
- ;
- ifndef USE_ZLIB
- ifdef DEBUG
- VERBOSE_INFO EQU 1
- else
- ifdef _AS_MSG_
- VERBOSE_INFO EQU 1
- else
- VERBOSE_INFO EQU 0
- endif
- endif
- ifndef __SMALL__
- ifndef __COMPACT__
- ifndef __MEDIUM__
- ifndef __LARGE__
- ifndef __HUGE__
- ; __SMALL__ EQU 1
- endif
- endif
- endif
- endif
- endif
- ifdef __HUGE__
- ; .MODEL Huge
- ifndef @CodeSize
- @CodeSize EQU 1
- endif
- ifndef @DataSize
- @DataSize EQU 1
- endif
- Save_DS EQU 1
- if VERBOSE_INFO
- if1
- %out Assembling for C, Huge memory model
- endif
- endif
- else
- ifdef __LARGE__
- ; .MODEL Large
- ifndef @CodeSize
- @CodeSize EQU 1
- endif
- ifndef @DataSize
- @DataSize EQU 1
- endif
- if VERBOSE_INFO
- if1
- %out Assembling for C, Large memory model
- endif
- endif
- else
- ifdef __COMPACT__
- ; .MODEL Compact
- ifndef @CodeSize
- @CodeSize EQU 0
- endif
- ifndef @DataSize
- @DataSize EQU 1
- endif
- if VERBOSE_INFO
- if1
- %out Assembling for C, Compact memory model
- endif
- endif
- else
- ifdef __MEDIUM__
- ; .MODEL Medium
- ifndef @CodeSize
- @CodeSize EQU 1
- endif
- ifndef @DataSize
- @DataSize EQU 0
- endif
- if VERBOSE_INFO
- if1
- %out Assembling for C, Medium memory model
- endif
- endif
- else
- ; .MODEL Small
- ifndef @CodeSize
- @CodeSize EQU 0
- endif
- ifndef @DataSize
- @DataSize EQU 0
- endif
- if VERBOSE_INFO
- if1
- %out Assembling for C, Small memory model
- endif
- endif
- endif
- endif
- endif
- endif
- if @CodeSize
- LCOD_OFS EQU 2
- else
- LCOD_OFS EQU 0
- endif
- IF @DataSize
- LDAT_OFS EQU 2
- else
- LDAT_OFS EQU 0
- endif
- ifdef Save_DS
- ; (di,si,ds)+(size, return address)
- SAVE_REGS EQU 6+(4+LCOD_OFS)
- else
- ; (di,si)+(size, return address)
- SAVE_REGS EQU 4+(4+LCOD_OFS)
- endif
- ;
- ; Selection of the supported CPU instruction set and initialization
- ; of CPU type related macros:
- ;
- ifdef __586
- Use_286_code EQU 1
- Align_Size EQU 16 ; paragraph alignment on Pentium
- Alig_PARA EQU 1 ; paragraph aligned code segment
- else
- ifdef __486
- Use_286_code EQU 1
- Align_Size EQU 4 ; dword alignment on 32 bit processors
- Alig_PARA EQU 1 ; paragraph aligned code segment
- else
- ifdef __386
- Use_286_code EQU 1
- Align_Size EQU 4 ; dword alignment on 32 bit processors
- Alig_PARA EQU 1 ; paragraph aligned code segment
- else
- ifdef __286
- Use_286_code EQU 1
- Align_Size EQU 2 ; word alignment on 16 bit processors
- Alig_PARA EQU 0 ; word aligned code segment
- else
- ifdef __186
- Use_186_code EQU 1
- Align_Size EQU 2 ; word alignment on 16 bit processors
- Alig_PARA EQU 0 ; word aligned code segment
- else
- Align_Size EQU 2 ; word alignment on 16 bit processors
- Alig_PARA EQU 0 ; word aligned code segment
- endif ;?__186
- endif ;?__286
- endif ;?__386
- endif ;?__486
- endif ;?__586
- ifdef Use_286_code
- .286
- Have_80x86 EQU 1
- else
- ifdef Use_186_code
- .186
- Have_80x86 EQU 1
- else
- .8086
- Have_80x86 EQU 0
- endif ;?Use_186_code
- endif ;?Use_286_code
- ifndef DYN_ALLOC
- extrn _prev : word
- extrn _window : byte
- prev equ _prev ; offset part
- window equ _window
- endif
- _DATA segment word public 'DATA'
- extrn _nice_match : word
- extrn _match_start : word
- extrn _prev_length : word
- extrn _good_match : word
- extrn _strstart : word
- extrn _max_chain_length : word
- ifdef DYN_ALLOC
- extrn _prev : word
- extrn _window : word
- prev equ 0 ; offset forced to zero
- window equ 0
- window_seg equ _window[2]
- window_off equ 0
- else
- wseg dw seg _window
- window_seg equ wseg
- window_off equ offset _window
- endif
- _DATA ends
- DGROUP group _DATA
- if @CodeSize
- if Alig_PARA
- MATCH_TEXT SEGMENT PARA PUBLIC 'CODE'
- else
- MATCH_TEXT SEGMENT WORD PUBLIC 'CODE'
- endif
- assume cs: MATCH_TEXT, ds: DGROUP
- else ;!@CodeSize
- if Alig_PARA
- _TEXT segment para public 'CODE'
- else
- _TEXT segment word public 'CODE'
- endif
- assume cs: _TEXT, ds: DGROUP
- endif ;?@CodeSize
- public _match_init
- public _longest_match
- ifndef WSIZE
- WSIZE equ 32768 ; keep in sync with zip.h !
- endif
- MIN_MATCH equ 3
- MAX_MATCH equ 258
- MIN_LOOKAHEAD equ (MAX_MATCH+MIN_MATCH+1)
- MAX_DIST equ (WSIZE-MIN_LOOKAHEAD)
- ifdef DYN_ALLOC
- ifdef SS_NEQ_DS
- prev_ptr dw seg _prev ; pointer to the prev array
- endif
- else
- prev_ptr dw seg _prev ; pointer to the prev array
- endif
- ifdef SS_NEQ_DS
- match_start dw 0 ; copy of _match_start if SS != DS
- nice_match dw 0 ; copy of _nice_match if SS != DS
- endif
- ; initialize or check the variables used in match.asm.
- if @CodeSize
- _match_init proc far ; 'proc far' for large model
- else
- _match_init proc near ; 'proc near' for compact model
- endif
- ifdef SS_NEQ_DS
- ma_start equ cs:match_start ; does not work on OS/2
- nice equ cs:nice_match
- else
- assume ss: DGROUP
- ma_start equ ss:_match_start
- nice equ ss:_nice_match
- ifndef NO_SECURE_TESTS
- mov ax,ds
- mov bx,ss
- cmp ax,bx ; SS == DS?
- jne fatal_err
- endif
- endif
- ifdef DYN_ALLOC
- ifndef NO_SECURE_TESTS
- cmp _prev[0],0 ; verify zero offset
- jne fatal_err
- cmp _window[0],0
- jne fatal_err
- endif
- ifdef SS_NEQ_DS
- mov ax,_prev[2] ; segment value
- mov cs:prev_ptr,ax ; ugly write to code, crash on OS/2
- prev_seg equ cs:prev_ptr
- else
- prev_seg equ ss:_prev[2] ; works on OS/2 if SS == DS
- endif
- else
- prev_seg equ cs:prev_ptr
- endif
- ret
- ifndef NO_SECURE_TESTS
- if @CodeSize
- extrn _exit : far ; 'far' for large model
- else
- extrn _exit : near ; 'near' for compact model
- endif
- fatal_err: ; (quiet) emergency stop:
- call _exit ; incompatible "global vars interface"
- endif
- _match_init endp
- ; -----------------------------------------------------------------------
- ; 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
- ; int longest_match(cur_match)
- align Align_Size
- if @CodeSize
- _longest_match proc far ; 'proc far' for large model
- else
- _longest_match proc near ; 'proc near' for compact model
- endif
- push bp
- mov bp,sp
- push di
- push si
- push ds
- if @CodeSize
- cur_match equ word ptr [bp+6] ; [bp+6] for large model
- else
- cur_match equ word ptr [bp+4] ; [bp+4] for compact model
- endif
- ; window equ es:window (es:0 for DYN_ALLOC)
- ; prev equ ds:prev
- ; match equ es:si
- ; scan equ es:di
- ; chain_length equ bp
- ; best_len equ bx
- ; limit equ dx
- mov si,cur_match ; use bp before it is destroyed
- ifdef SS_NEQ_DS
- mov ax,_nice_match
- mov nice,ax ; ugly write to code, crash on OS/2
- endif
- mov dx,_strstart
- mov bp,_max_chain_length ; chain_length = max_chain_length
- mov di,dx
- sub dx,MAX_DIST ; limit = strstart-MAX_DIST
- cld ; string ops increment si and di
- jae limit_ok
- sub dx,dx ; limit = NIL
- limit_ok:
- add di,2+window_off ; di = offset(window + strstart + 2)
- mov bx,_prev_length ; best_len = prev_length
- mov es,window_seg
- mov ax,es:[bx+di-3] ; ax = scan[best_len-1..best_len]
- mov cx,es:[di-2] ; cx = scan[0..1]
- cmp bx,_good_match ; do we have a good match already?
- mov ds,prev_seg ; (does not destroy the flags)
- assume ds: nothing
- jb do_scan ; good match?
- if Have_80x86
- shr bp,2 ; chain_length >>= 2
- else
- shr bp,1 ; chain_length >>= 2
- shr bp,1
- endif
- jmp short do_scan
- align Align_Size ; align destination of branch
- long_loop:
- ; at this point, ds:di == scan+2, ds:si == cur_match
- mov ax,[bx+di-3] ; ax = scan[best_len-1..best_len]
- mov cx,[di-2] ; cx = scan[0..1]
- mov ds,prev_seg ; reset ds to address the prev array
- short_loop:
- ; at this point, di == scan+2, si = cur_match,
- ; ax = scan[best_len-1..best_len] and cx = scan[0..1]
- if (WSIZE-32768)
- and si,WSIZE-1 ; not needed if WSIZE=32768
- endif
- shl si,1 ; cur_match as word index
- dec bp ; --chain_length
- mov si,prev[si] ; cur_match = prev[cur_match]
- jz the_end
- cmp si,dx ; cur_match <= limit ?
- jbe the_end
- do_scan:
- cmp ax,word ptr es:window[bx+si-1] ; check match at best_len-1
- jne short_loop
- cmp cx,word ptr es:window[si] ; check min_match_length match
- jne short_loop
- mov cx,es
- add si,2+window_off ; si = match
- mov ds,cx ; ds = es = window
- mov cx,(MAX_MATCH-2)/2 ; scan for at most MAX_MATCH bytes
- mov ax,di ; ax = scan+2
- repe cmpsw ; loop until mismatch
- je maxmatch ; match of length MAX_MATCH?
- mismatch:
- mov cl,[di-2] ; mismatch on first or second byte?
- xchg ax,di ; di = scan+2, ax = end of scan
- sub cl,[si-2] ; cl = 0 if first bytes equal
- sub ax,di ; ax = len
- sub si,2+window_off ; si = cur_match + len
- sub si,ax ; si = cur_match
- sub cl,1 ; set carry if cl == 0 (can't use DEC)
- adc ax,0 ; ax = carry ? len+1 : len
- cmp ax,bx ; len > best_len ?
- jle long_loop
- mov ma_start,si ; match_start = cur_match
- mov bx,ax ; bx = best_len = len
- cmp ax,nice ; len >= nice_match ?
- jl long_loop
- the_end:
- pop ds
- assume ds: DGROUP
- ifdef SS_NEQ_DS
- mov ax,ma_start ; garbage if no match found
- mov ds:_match_start,ax
- endif
- pop si
- pop di
- pop bp
- mov ax,bx ; result = ax = best_len
- ret
- maxmatch: ; come here if maximum match
- cmpsb ; increment si and di
- jmp mismatch ; force match_length = MAX_LENGTH
- _longest_match endp
- if @CodeSize
- MATCH_TEXT ENDS
- else
- _TEXT ENDS
- endif
- ;
- endif ;!USE_ZLIB
- ;
- end
|