|
|
1.1 root 1: ;
2: ; Copyright (C) 1990-1992 Mark Adler, Richard B. Wales, and Jean-loup Gailly.
3: ; Permission is granted to any individual or institution to use, copy, or
4: ; redistribute this software so long as all of the original files are included
5: ; unmodified, that it is not sold for profit, and that this copyright notice
6: ; is retained.
7: ;
8: ; match.asm by Jean-loup Gailly.
9:
10: ; match.asm, optimized version of longest_match() in deflate.c
11: ; Must be assembled with masm -ml. To be used only with C large model.
12: ; (For compact model, follow the instructions given below.)
13: ; This file is only optional. If you don't have masm or tasm, use the
14: ; C version (add -DNO_ASM to CFLAGS in makefile.msc and remove match.obj
15: ; from OBJI). If you have reduced WSIZE in zip.h, then change its value
16: ; below.
17: ;
18: ; Turbo C 2.0 does not support static allocation of more than 64K bytes per
19: ; file, and does not have SS == DS. So TC and BC++ users must use:
20: ; tasm -ml -DDYN_ALLOC -DSS_NEQ_DS match;
21: ;
22: ; To simplify the code, the option -DDYN_ALLOC is supported for OS/2
23: ; only if the arrays are guaranteed to have zero offset (allocated by
24: ; halloc). We also require SS==DS. This is satisfied for MSC but not Turbo C.
25:
26: name match
27:
28: ; define LCODE as follows:
29: ; model: compact large (small and medium not supported here)
30: ; LCODE 0 1
31:
32: LCODE equ 1
33: DYN_ALLOC equ 1
34: SS_NEQ_DS equ 1
35: ; For Turbo C, define SS_NEQ_DS as 1, but for MSC you can leave it undefined.
36: ; The code is a little better when SS_NEQ_DS is not defined.
37:
38: ifndef DYN_ALLOC
39: extrn _prev : word
40: extrn _window : byte
41: prev equ _prev ; offset part
42: window equ _window
43: endif
44:
45: _DATA segment word public 'DATA'
46: extrn _match_start : word
47: extrn _prev_length : word
48: extrn _good_match : word
49: extrn _strstart : word
50: extrn _max_chain_length : word
51: ifdef DYN_ALLOC
52: extrn _prev : word
53: extrn _window : word
54: prev equ 0 ; offset forced to zero
55: window equ 0
56: window_seg equ _window[2]
57: window_off equ 0
58: else
59: wseg dw seg _window
60: window_seg equ wseg
61: window_off equ offset _window
62: endif
63: _DATA ends
64:
65: DGROUP group _DATA
66:
67: if LCODE
68: extrn _exit : far
69: else
70: extrn _exit : near
71: endif
72:
73: _TEXT segment word public 'CODE'
74: assume cs: _TEXT, ds: DGROUP
75:
76: public _match_init
77: public _longest_match
78:
79: MIN_MATCH equ 3
80: MAX_MATCH equ 258
81: WSIZE equ 8192 ; keep in sync with zip.h !
82: WMASK equ (WSIZE-1)
83: MIN_LOOKAHEAD equ (MAX_MATCH+MIN_MATCH+1)
84: MAX_DIST equ (WSIZE-MIN_LOOKAHEAD)
85:
86: prev_ptr dw seg _prev ; pointer to the prev array
87: ifdef SS_NEQ_DS
88: match_start dw 0 ; copy of _match_start if SS != DS
89: endif
90:
91: ; initialize or check the variables used in match.asm.
92:
93: if LCODE
94: _match_init proc far
95: else
96: _match_init proc near
97: endif
98: ifdef SS_NEQ_DS
99: ma_start equ cs:match_start ; does not work on OS/2
100: else
101: assume ss: DGROUP
102: ma_start equ ss:_match_start
103: mov ax,ds
104: mov bx,ss
105: cmp ax,bx ; SS == DS?
106: jne error
107: endif
108: ifdef DYN_ALLOC
109: mov ax,_window[0] ; force zero offset
110: add ax,15
111: mov cx,4
112: shr ax,cl
113: add _window[2],ax
114: mov _window[0],0
115:
116: mov ax,_prev[0] ; force zero offset
117: add ax,15
118: mov cx,4
119: shr ax,cl
120: add _prev[2],ax
121: mov _prev[0],0
122: ifdef SS_NEQ_DS
123: mov ax,_prev[2] ; segment value
124: mov cs:prev_ptr,ax ; ugly write to code, crash on OS/2
125: prev_seg equ cs:prev_ptr
126: else
127: prev_seg equ ss:_prev[2] ; works on OS/2 if SS == DS
128: endif
129: else
130: prev_seg equ cs:prev_ptr
131: endif
132: ret
133: error: call _exit
134:
135: _match_init endp
136:
137: ; -----------------------------------------------------------------------
138: ; Set match_start to the longest match starting at the given string and
139: ; return its length. Matches shorter or equal to prev_length are discarded,
140: ; in which case the result is equal to prev_length and match_start is
141: ; garbage.
142: ; IN assertions: cur_match is the head of the hash chain for the current
143: ; string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
144:
145: ; int longest_match(cur_match)
146:
147: if LCODE
148: _longest_match proc far
149: else
150: _longest_match proc near
151: endif
152: push bp
153: mov bp,sp
154: push di
155: push si
156: push ds
157:
158: if LCODE
159: cur_match equ word ptr [bp+6]
160: else
161: cur_match equ word ptr [bp+4]
162: endif
163: ; window equ es:window (es:0 for DYN_ALLOC)
164: ; prev equ ds:prev
165: ; match equ es:si
166: ; scan equ es:di
167: ; chain_length equ bp
168: ; best_len equ bx
169: ; limit equ dx
170:
171: mov si,cur_match ; use bp before it is destroyed
172: mov bp,_max_chain_length ; chain_length = max_chain_length
173: mov di,_strstart
174: mov dx,di
175: sub dx,MAX_DIST ; limit = strstart-MAX_DIST
176: jae limit_ok
177: sub dx,dx ; limit = NIL
178: limit_ok:
179: add di,2+window_off ; di = offset(window + strstart + 2)
180: mov bx,_prev_length ; best_len = prev_length
181: mov es,window_seg
182: mov ax,es:[bx+di-3] ; ax = scan[best_len-1..best_len]
183: mov cx,es:[di-2] ; cx = scan[0..1]
184: cmp bx,_good_match ; do we have a good match already?
185: mov ds,prev_seg ; (does not destroy the flags)
186: assume ds: nothing
187: jb do_scan ; good match?
188: shr bp,1 ; chain_length >>= 2
189: shr bp,1
190: jmp short do_scan
191:
192: even ; align destination of branch
193: long_loop:
194: ; at this point, ds:di == scan+2, ds:si == cur_match
195: mov ax,[bx+di-3] ; ax = scan[best_len-1..best_len]
196: mov cx,[di-2] ; cx = scan[0..1]
197: mov ds,prev_seg ; reset ds to address the prev array
198: short_loop:
199: dec bp ; --chain_length
200: jz the_end
201: ; at this point, di == scan+2, si = cur_match,
202: ; ax = scan[best_len-1..best_len] and cx = scan[0..1]
203: if (WSIZE-32768)
204: and si,WMASK
205: endif
206: shl si,1 ; cur_match as word index
207: mov si,prev[si] ; cur_match = prev[cur_match]
208: cmp si,dx ; cur_match <= limit ?
209: jbe the_end
210: do_scan:
211: cmp ax,word ptr es:window[bx+si-1] ; check match at best_len-1
212: jne short_loop
213: cmp cx,word ptr es:window[si] ; check min_match_length match
214: jne short_loop
215:
216: lea si,window[si+2] ; si = match
217: mov ax,di ; ax = scan+2
218: mov cx,es
219: mov ds,cx ; ds = es = window
220: mov cx,(MAX_MATCH-2)/2 ; scan for at most MAX_MATCH bytes
221: repe cmpsw ; loop until mismatch
222: je maxmatch ; match of length MAX_MATCH?
223: mismatch:
224: mov cl,[di-2] ; mismatch on first or second byte?
225: sub cl,[si-2] ; cl = 0 if first bytes equal
226: xchg ax,di ; di = scan+2, ax = end of scan
227: sub ax,di ; ax = len
228: sub si,ax ; si = cur_match + 2 + offset(window)
229: sub si,2+window_off ; si = cur_match
230: sub cl,1 ; set carry if cl == 0 (can't use DEC)
231: adc ax,0 ; ax = carry ? len+1 : len
232: cmp ax,bx ; len > best_len ?
233: jle long_loop
234: mov ma_start,si ; match_start = cur_match
235: mov bx,ax ; bx = best_len = len
236: cmp ax,MAX_MATCH ; len >= MAX_MATCH ?
237: jl long_loop
238: the_end:
239: pop ds
240: assume ds: DGROUP
241: ifdef SS_NEQ_DS
242: mov ax,ma_start ; garbage if no match found
243: mov ds:_match_start,ax
244: endif
245: pop si
246: pop di
247: pop bp
248: mov ax,bx ; result = ax = best_len
249: ret
250: maxmatch: ; come here if maximum match
251: cmpsb ; increment si and di
252: jmp mismatch ; force match_length = MAX_LENGTH
253:
254: _longest_match endp
255:
256: _TEXT ends
257: end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.