match.asm 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477
  1. ;===========================================================================
  2. ; Copyright (c) 1990-2008 Info-ZIP. All rights reserved.
  3. ;
  4. ; See the accompanying file LICENSE, version 2007-Mar-04 or later
  5. ; (the contents of which are also included in zip.h) for terms of use.
  6. ; If, for some reason, all these files are missing, the Info-ZIP license
  7. ; also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
  8. ;===========================================================================
  9. ;
  10. ; match.asm by Jean-loup Gailly.
  11. ; match.asm, optimized version of longest_match() in deflate.c
  12. ; Must be assembled with masm -ml. To be used only with C compact model
  13. ; or large model. (For large model, assemble with -D__LARGE__).
  14. ; This file is only optional. If you don't have masm or tasm, use the
  15. ; C version (add -DNO_ASM to CFLAGS in makefile.msc and remove match.obj
  16. ; from OBJI). If you have reduced WSIZE in zip.h, then make sure this is
  17. ; assembled with an equivalent -DWSIZE=<whatever>.
  18. ;
  19. ; The code has been prepared for two different C compiler calling conventions
  20. ; and contains some support for dynamically allocated working space.
  21. ; The different environments are selected by two conditional flags:
  22. ; DYN_ALLOC : select support for malloc'ed working space
  23. ; SS_NEQ_DS : relaxes assumption that stack and default data segments
  24. ; are identical
  25. ; When SS_NEQ_DS is defined, the code segment is used to store some
  26. ; local variables. This (bad) coding practice is very likely to break any
  27. ; `segment protection scheme', it will most probably only work for real
  28. ; mode programs.
  29. ;
  30. ; Turbo C 2.0 does not support static allocation of more than 64K bytes per
  31. ; file, and does not have SS == DS. So TC and BC++ users must use:
  32. ; tasm -ml -DDYN_ALLOC -DSS_NEQ_DS match;
  33. ;
  34. ; To simplify the code, the option -DDYN_ALLOC is supported for OS/2
  35. ; only if the arrays are guaranteed to have zero offset (allocated by
  36. ; halloc). We also require SS==DS. This is satisfied for MSC but not Turbo C.
  37. ;
  38. ; Per default, test code is included to check if the above requirements are
  39. ; fulfilled. This test code can be disabled by defining the compile time
  40. ; option flag NO_SECURE_TESTS when compiling for a production executable.
  41. ; This shortens the code size (but the performance gain is neglectable).
  42. ; The security tests should remain enabled, when a new C compiler
  43. ; and/or a new set of compilation options is tried.
  44. name match
  45. ; Do NOT assemble this source if external crc32 routine from zlib gets used.
  46. ;
  47. ifndef USE_ZLIB
  48. ifdef DEBUG
  49. VERBOSE_INFO EQU 1
  50. else
  51. ifdef _AS_MSG_
  52. VERBOSE_INFO EQU 1
  53. else
  54. VERBOSE_INFO EQU 0
  55. endif
  56. endif
  57. ifndef __SMALL__
  58. ifndef __COMPACT__
  59. ifndef __MEDIUM__
  60. ifndef __LARGE__
  61. ifndef __HUGE__
  62. ; __SMALL__ EQU 1
  63. endif
  64. endif
  65. endif
  66. endif
  67. endif
  68. ifdef __HUGE__
  69. ; .MODEL Huge
  70. ifndef @CodeSize
  71. @CodeSize EQU 1
  72. endif
  73. ifndef @DataSize
  74. @DataSize EQU 1
  75. endif
  76. Save_DS EQU 1
  77. if VERBOSE_INFO
  78. if1
  79. %out Assembling for C, Huge memory model
  80. endif
  81. endif
  82. else
  83. ifdef __LARGE__
  84. ; .MODEL Large
  85. ifndef @CodeSize
  86. @CodeSize EQU 1
  87. endif
  88. ifndef @DataSize
  89. @DataSize EQU 1
  90. endif
  91. if VERBOSE_INFO
  92. if1
  93. %out Assembling for C, Large memory model
  94. endif
  95. endif
  96. else
  97. ifdef __COMPACT__
  98. ; .MODEL Compact
  99. ifndef @CodeSize
  100. @CodeSize EQU 0
  101. endif
  102. ifndef @DataSize
  103. @DataSize EQU 1
  104. endif
  105. if VERBOSE_INFO
  106. if1
  107. %out Assembling for C, Compact memory model
  108. endif
  109. endif
  110. else
  111. ifdef __MEDIUM__
  112. ; .MODEL Medium
  113. ifndef @CodeSize
  114. @CodeSize EQU 1
  115. endif
  116. ifndef @DataSize
  117. @DataSize EQU 0
  118. endif
  119. if VERBOSE_INFO
  120. if1
  121. %out Assembling for C, Medium memory model
  122. endif
  123. endif
  124. else
  125. ; .MODEL Small
  126. ifndef @CodeSize
  127. @CodeSize EQU 0
  128. endif
  129. ifndef @DataSize
  130. @DataSize EQU 0
  131. endif
  132. if VERBOSE_INFO
  133. if1
  134. %out Assembling for C, Small memory model
  135. endif
  136. endif
  137. endif
  138. endif
  139. endif
  140. endif
  141. if @CodeSize
  142. LCOD_OFS EQU 2
  143. else
  144. LCOD_OFS EQU 0
  145. endif
  146. IF @DataSize
  147. LDAT_OFS EQU 2
  148. else
  149. LDAT_OFS EQU 0
  150. endif
  151. ifdef Save_DS
  152. ; (di,si,ds)+(size, return address)
  153. SAVE_REGS EQU 6+(4+LCOD_OFS)
  154. else
  155. ; (di,si)+(size, return address)
  156. SAVE_REGS EQU 4+(4+LCOD_OFS)
  157. endif
  158. ;
  159. ; Selection of the supported CPU instruction set and initialization
  160. ; of CPU type related macros:
  161. ;
  162. ifdef __586
  163. Use_286_code EQU 1
  164. Align_Size EQU 16 ; paragraph alignment on Pentium
  165. Alig_PARA EQU 1 ; paragraph aligned code segment
  166. else
  167. ifdef __486
  168. Use_286_code EQU 1
  169. Align_Size EQU 4 ; dword alignment on 32 bit processors
  170. Alig_PARA EQU 1 ; paragraph aligned code segment
  171. else
  172. ifdef __386
  173. Use_286_code EQU 1
  174. Align_Size EQU 4 ; dword alignment on 32 bit processors
  175. Alig_PARA EQU 1 ; paragraph aligned code segment
  176. else
  177. ifdef __286
  178. Use_286_code EQU 1
  179. Align_Size EQU 2 ; word alignment on 16 bit processors
  180. Alig_PARA EQU 0 ; word aligned code segment
  181. else
  182. ifdef __186
  183. Use_186_code EQU 1
  184. Align_Size EQU 2 ; word alignment on 16 bit processors
  185. Alig_PARA EQU 0 ; word aligned code segment
  186. else
  187. Align_Size EQU 2 ; word alignment on 16 bit processors
  188. Alig_PARA EQU 0 ; word aligned code segment
  189. endif ;?__186
  190. endif ;?__286
  191. endif ;?__386
  192. endif ;?__486
  193. endif ;?__586
  194. ifdef Use_286_code
  195. .286
  196. Have_80x86 EQU 1
  197. else
  198. ifdef Use_186_code
  199. .186
  200. Have_80x86 EQU 1
  201. else
  202. .8086
  203. Have_80x86 EQU 0
  204. endif ;?Use_186_code
  205. endif ;?Use_286_code
  206. ifndef DYN_ALLOC
  207. extrn _prev : word
  208. extrn _window : byte
  209. prev equ _prev ; offset part
  210. window equ _window
  211. endif
  212. _DATA segment word public 'DATA'
  213. extrn _nice_match : word
  214. extrn _match_start : word
  215. extrn _prev_length : word
  216. extrn _good_match : word
  217. extrn _strstart : word
  218. extrn _max_chain_length : word
  219. ifdef DYN_ALLOC
  220. extrn _prev : word
  221. extrn _window : word
  222. prev equ 0 ; offset forced to zero
  223. window equ 0
  224. window_seg equ _window[2]
  225. window_off equ 0
  226. else
  227. wseg dw seg _window
  228. window_seg equ wseg
  229. window_off equ offset _window
  230. endif
  231. _DATA ends
  232. DGROUP group _DATA
  233. if @CodeSize
  234. if Alig_PARA
  235. MATCH_TEXT SEGMENT PARA PUBLIC 'CODE'
  236. else
  237. MATCH_TEXT SEGMENT WORD PUBLIC 'CODE'
  238. endif
  239. assume cs: MATCH_TEXT, ds: DGROUP
  240. else ;!@CodeSize
  241. if Alig_PARA
  242. _TEXT segment para public 'CODE'
  243. else
  244. _TEXT segment word public 'CODE'
  245. endif
  246. assume cs: _TEXT, ds: DGROUP
  247. endif ;?@CodeSize
  248. public _match_init
  249. public _longest_match
  250. ifndef WSIZE
  251. WSIZE equ 32768 ; keep in sync with zip.h !
  252. endif
  253. MIN_MATCH equ 3
  254. MAX_MATCH equ 258
  255. MIN_LOOKAHEAD equ (MAX_MATCH+MIN_MATCH+1)
  256. MAX_DIST equ (WSIZE-MIN_LOOKAHEAD)
  257. ifdef DYN_ALLOC
  258. ifdef SS_NEQ_DS
  259. prev_ptr dw seg _prev ; pointer to the prev array
  260. endif
  261. else
  262. prev_ptr dw seg _prev ; pointer to the prev array
  263. endif
  264. ifdef SS_NEQ_DS
  265. match_start dw 0 ; copy of _match_start if SS != DS
  266. nice_match dw 0 ; copy of _nice_match if SS != DS
  267. endif
  268. ; initialize or check the variables used in match.asm.
  269. if @CodeSize
  270. _match_init proc far ; 'proc far' for large model
  271. else
  272. _match_init proc near ; 'proc near' for compact model
  273. endif
  274. ifdef SS_NEQ_DS
  275. ma_start equ cs:match_start ; does not work on OS/2
  276. nice equ cs:nice_match
  277. else
  278. assume ss: DGROUP
  279. ma_start equ ss:_match_start
  280. nice equ ss:_nice_match
  281. ifndef NO_SECURE_TESTS
  282. mov ax,ds
  283. mov bx,ss
  284. cmp ax,bx ; SS == DS?
  285. jne fatal_err
  286. endif
  287. endif
  288. ifdef DYN_ALLOC
  289. ifndef NO_SECURE_TESTS
  290. cmp _prev[0],0 ; verify zero offset
  291. jne fatal_err
  292. cmp _window[0],0
  293. jne fatal_err
  294. endif
  295. ifdef SS_NEQ_DS
  296. mov ax,_prev[2] ; segment value
  297. mov cs:prev_ptr,ax ; ugly write to code, crash on OS/2
  298. prev_seg equ cs:prev_ptr
  299. else
  300. prev_seg equ ss:_prev[2] ; works on OS/2 if SS == DS
  301. endif
  302. else
  303. prev_seg equ cs:prev_ptr
  304. endif
  305. ret
  306. ifndef NO_SECURE_TESTS
  307. if @CodeSize
  308. extrn _exit : far ; 'far' for large model
  309. else
  310. extrn _exit : near ; 'near' for compact model
  311. endif
  312. fatal_err: ; (quiet) emergency stop:
  313. call _exit ; incompatible "global vars interface"
  314. endif
  315. _match_init endp
  316. ; -----------------------------------------------------------------------
  317. ; Set match_start to the longest match starting at the given string and
  318. ; return its length. Matches shorter or equal to prev_length are discarded,
  319. ; in which case the result is equal to prev_length and match_start is
  320. ; garbage.
  321. ; IN assertions: cur_match is the head of the hash chain for the current
  322. ; string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
  323. ; int longest_match(cur_match)
  324. align Align_Size
  325. if @CodeSize
  326. _longest_match proc far ; 'proc far' for large model
  327. else
  328. _longest_match proc near ; 'proc near' for compact model
  329. endif
  330. push bp
  331. mov bp,sp
  332. push di
  333. push si
  334. push ds
  335. if @CodeSize
  336. cur_match equ word ptr [bp+6] ; [bp+6] for large model
  337. else
  338. cur_match equ word ptr [bp+4] ; [bp+4] for compact model
  339. endif
  340. ; window equ es:window (es:0 for DYN_ALLOC)
  341. ; prev equ ds:prev
  342. ; match equ es:si
  343. ; scan equ es:di
  344. ; chain_length equ bp
  345. ; best_len equ bx
  346. ; limit equ dx
  347. mov si,cur_match ; use bp before it is destroyed
  348. ifdef SS_NEQ_DS
  349. mov ax,_nice_match
  350. mov nice,ax ; ugly write to code, crash on OS/2
  351. endif
  352. mov dx,_strstart
  353. mov bp,_max_chain_length ; chain_length = max_chain_length
  354. mov di,dx
  355. sub dx,MAX_DIST ; limit = strstart-MAX_DIST
  356. cld ; string ops increment si and di
  357. jae limit_ok
  358. sub dx,dx ; limit = NIL
  359. limit_ok:
  360. add di,2+window_off ; di = offset(window + strstart + 2)
  361. mov bx,_prev_length ; best_len = prev_length
  362. mov es,window_seg
  363. mov ax,es:[bx+di-3] ; ax = scan[best_len-1..best_len]
  364. mov cx,es:[di-2] ; cx = scan[0..1]
  365. cmp bx,_good_match ; do we have a good match already?
  366. mov ds,prev_seg ; (does not destroy the flags)
  367. assume ds: nothing
  368. jb do_scan ; good match?
  369. if Have_80x86
  370. shr bp,2 ; chain_length >>= 2
  371. else
  372. shr bp,1 ; chain_length >>= 2
  373. shr bp,1
  374. endif
  375. jmp short do_scan
  376. align Align_Size ; align destination of branch
  377. long_loop:
  378. ; at this point, ds:di == scan+2, ds:si == cur_match
  379. mov ax,[bx+di-3] ; ax = scan[best_len-1..best_len]
  380. mov cx,[di-2] ; cx = scan[0..1]
  381. mov ds,prev_seg ; reset ds to address the prev array
  382. short_loop:
  383. ; at this point, di == scan+2, si = cur_match,
  384. ; ax = scan[best_len-1..best_len] and cx = scan[0..1]
  385. if (WSIZE-32768)
  386. and si,WSIZE-1 ; not needed if WSIZE=32768
  387. endif
  388. shl si,1 ; cur_match as word index
  389. dec bp ; --chain_length
  390. mov si,prev[si] ; cur_match = prev[cur_match]
  391. jz the_end
  392. cmp si,dx ; cur_match <= limit ?
  393. jbe the_end
  394. do_scan:
  395. cmp ax,word ptr es:window[bx+si-1] ; check match at best_len-1
  396. jne short_loop
  397. cmp cx,word ptr es:window[si] ; check min_match_length match
  398. jne short_loop
  399. mov cx,es
  400. add si,2+window_off ; si = match
  401. mov ds,cx ; ds = es = window
  402. mov cx,(MAX_MATCH-2)/2 ; scan for at most MAX_MATCH bytes
  403. mov ax,di ; ax = scan+2
  404. repe cmpsw ; loop until mismatch
  405. je maxmatch ; match of length MAX_MATCH?
  406. mismatch:
  407. mov cl,[di-2] ; mismatch on first or second byte?
  408. xchg ax,di ; di = scan+2, ax = end of scan
  409. sub cl,[si-2] ; cl = 0 if first bytes equal
  410. sub ax,di ; ax = len
  411. sub si,2+window_off ; si = cur_match + len
  412. sub si,ax ; si = cur_match
  413. sub cl,1 ; set carry if cl == 0 (can't use DEC)
  414. adc ax,0 ; ax = carry ? len+1 : len
  415. cmp ax,bx ; len > best_len ?
  416. jle long_loop
  417. mov ma_start,si ; match_start = cur_match
  418. mov bx,ax ; bx = best_len = len
  419. cmp ax,nice ; len >= nice_match ?
  420. jl long_loop
  421. the_end:
  422. pop ds
  423. assume ds: DGROUP
  424. ifdef SS_NEQ_DS
  425. mov ax,ma_start ; garbage if no match found
  426. mov ds:_match_start,ax
  427. endif
  428. pop si
  429. pop di
  430. pop bp
  431. mov ax,bx ; result = ax = best_len
  432. ret
  433. maxmatch: ; come here if maximum match
  434. cmpsb ; increment si and di
  435. jmp mismatch ; force match_length = MAX_LENGTH
  436. _longest_match endp
  437. if @CodeSize
  438. MATCH_TEXT ENDS
  439. else
  440. _TEXT ENDS
  441. endif
  442. ;
  443. endif ;!USE_ZLIB
  444. ;
  445. end