LCWCOMP.ASM 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. ;
  2. ; Copyright 2020 Electronic Arts Inc.
  3. ;
  4. ; TiberianDawn.DLL and RedAlert.dll and corresponding source code is free
  5. ; software: you can redistribute it and/or modify it under the terms of
  6. ; the GNU General Public License as published by the Free Software Foundation,
  7. ; either version 3 of the License, or (at your option) any later version.
  8. ; TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed
  9. ; in the hope that it will be useful, but with permitted additional restrictions
  10. ; under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT
  11. ; distributed with this program. You should have received a copy of the
  12. ; GNU General Public License along with permitted additional restrictions
  13. ; with this program. If not, see [https://github.com/electronicarts/CnC_Remastered_Collection]>.
  14. ; $Header: g:/library/wwlib32/misc/rcs/lcwcomp.asm 1.1 1994/04/11 15:31:10 jeff_wilson Exp $
  15. ;***************************************************************************
  16. ;** C O N F I D E N T I A L --- W E S T W O O D A S S O C I A T E S **
  17. ;***************************************************************************
  18. ;* *
  19. ;* Project Name : Library routine *
  20. ;* *
  21. ;* File Name : COMPRESS.ASM *
  22. ;* *
  23. ;* Programmer : Louis Castle *
  24. ;* *
  25. ;* Last Update : 20 August, 1990 [CY] *
  26. ;* *
  27. ;*-------------------------------------------------------------------------*
  28. ;* Functions: *
  29. ;* *
  30. ; ULONG LCW_Compress(BYTE *source,BYTE *dest, ULONG length); *
  31. ;* *
  32. ;* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - *
  33. ;IDEAL
  34. ;P386
  35. ;MODEL USE32 FLAT
  36. .MODEL FLAT
  37. ;GLOBAL LCW_Compress :NEAR
  38. externdef C LCW_Compress:near
  39. ;CODESEG
  40. .code
  41. ; ----------------------------------------------------------------
  42. ;
  43. ; Here are prototypes for the routines defined within this module:
  44. ;
  45. ; ULONG LCW_Compress(BYTE *source,BYTE *dest, ULONG length);
  46. ;
  47. ; ----------------------------------------------------------------
  48. ;***********************************************************
  49. ;
  50. ; ULONG LCW_Compress(BYTE *source, BYTE *dest, ULONG length)
  51. ;
  52. ; returns the size of the compressed data in bytes
  53. ;
  54. ;*
  55. LCW_Compress proc C source:DWORD, dest:DWORD, datasize:DWORD
  56. ;USES ebx,ecx,edx,edi,esi
  57. ;ARG source:DWORD
  58. ;ARG dest:DWORD
  59. ;ARG datasize:DWORD
  60. LOCAL inlen:DWORD
  61. LOCAL a1stdest:DWORD
  62. LOCAL a1stsrc:DWORD
  63. LOCAL lenoff:DWORD
  64. LOCAL ndest:DWORD
  65. LOCAL count:DWORD
  66. LOCAL matchoff:DWORD
  67. LOCAL end_of_data:DWORD
  68. pushad
  69. cld
  70. mov edi,[dest]
  71. mov esi,[source]
  72. mov edx,[datasize] ; get length of data to compress
  73. ; mov ax,ds
  74. ; mov es,ax
  75. ;
  76. ; compress data to the following codes in the format b = byte, w = word
  77. ; n = byte code pulled from compressed data
  78. ; Bit field of n command description
  79. ; n=0xxxyyyy,yyyyyyyy short run back y bytes and run x+3
  80. ; n=10xxxxxx,n1,n2,...,nx+1 med length copy the next x+1 bytes
  81. ; n=11xxxxxx,w1 med run run x+3 bytes from offset w1
  82. ; n=11111111,w1,w2 long run run w1 bytes from offset w2
  83. ; n=10000000 end end of data reached
  84. ;
  85. cld ; make sure all string commands are forward
  86. mov ebx,esi
  87. add ebx,edx
  88. mov [end_of_data],ebx
  89. mov [inlen],1 ; set the in-length flag
  90. mov [a1stdest],edi ; save original dest offset for size calc
  91. mov [a1stsrc],esi ; save offset of first byte of data
  92. mov [lenoff],edi ; save the offset of the legth of this len
  93. sub eax,eax
  94. mov al,081h ; the first byte is always a len
  95. stosb ; write out a len of 1
  96. lodsb ; get the byte
  97. stosb ; save it
  98. _loop:
  99. mov [ndest],edi ; save offset of compressed data
  100. mov edi,[a1stsrc] ; get the offset to the first byte of data
  101. mov [count],1 ; set the count of run to 0
  102. searchloop:
  103. sub eax,eax
  104. mov al,[esi] ; get the current byte of data
  105. cmp al,[esi+64]
  106. jne short notrunlength
  107. mov ebx,edi
  108. mov edi,esi
  109. mov ecx,[end_of_data]
  110. sub ecx,edi
  111. repe scasb
  112. dec edi
  113. mov ecx,edi
  114. sub ecx,esi
  115. cmp ecx,65
  116. jb short notlongenough
  117. mov [DWORD PTR inlen],0 ; clear the in-length flag
  118. mov esi,edi
  119. mov edi,[ndest] ; get the offset of our compressed data
  120. mov ah,al
  121. mov al,0FEh
  122. stosb
  123. xchg ecx,eax
  124. stosw
  125. mov al,ch
  126. stosb
  127. mov [ndest],edi ; save offset of compressed data
  128. mov edi,ebx
  129. jmp searchloop
  130. notlongenough:
  131. mov edi,ebx
  132. notrunlength:
  133. oploop:
  134. mov ecx,esi ; get the address of the last byte +1
  135. sub ecx,edi ; get the total number of bytes left to comp
  136. jz short searchdone
  137. repne scasb ; look for a match
  138. jne short searchdone ; if we don't find one we're done
  139. mov ebx,[count]
  140. mov ah,[esi+ebx-1]
  141. cmp ah,[edi+ebx-2]
  142. jne oploop
  143. mov edx,esi ; save this spot for the next search
  144. mov ebx,edi ; save this spot for the length calc
  145. dec edi ; back up one for compare
  146. mov ecx,[end_of_data] ; get the end of data
  147. sub ecx,esi ; sub current source for max len
  148. repe cmpsb ; see how many bytes match
  149. ; start of change MH 9-24-91
  150. jne short notend ; if found mismatch then di - bx = match count
  151. inc edi ; else cx = 0 and di + 1 - bx = match count
  152. notend:
  153. ; end of change MH 9-24-91
  154. mov esi,edx ; restore si
  155. mov eax,edi ; get the dest
  156. sub eax,ebx ; sub the start for total bytes that match
  157. mov edi,ebx ; restore dest
  158. cmp eax,[count] ; see if its better than before
  159. jb searchloop ; if not keep looking
  160. mov [count],eax ; if so keep the count
  161. dec ebx ; back it up for the actual match offset
  162. mov [matchoff],ebx ; save the offset for later
  163. jmp searchloop ; loop until we searched it all
  164. searchdone:
  165. mov ecx,[count] ; get the count of the longest run
  166. mov edi,[ndest] ; get the offset of our compressed data
  167. cmp ecx,2 ; see if its not enough run to matter
  168. jbe short lenin ; if its 0,1, or 2 its too small
  169. cmp ecx,10 ; if not, see if it would fit in a short
  170. ja short medrun ; if not, see if its a medium run
  171. mov eax,esi ; if its short get the current address
  172. sub eax,[matchoff] ; sub the offset of the match
  173. cmp eax,0FFFh ; if its less than 12 bits its a short
  174. ja short medrun ; if its not, its a medium
  175. shortrun:
  176. sub ebx,ebx
  177. mov bl,cl ; get the length (3-10)
  178. sub bl,3 ; sub 3 for a 3 bit number 0-7
  179. shl bl,4 ; shift it left 4
  180. add ah,bl ; add in the length for the high nibble
  181. xchg ah,al ; reverse the bytes for a word store
  182. jmp short srunnxt ; do the run fixup code
  183. medrun:
  184. cmp ecx,64 ; see if its a short run
  185. ja short longrun ; if not, oh well at least its long
  186. sub cl,3 ; back down 3 to keep it in 6 bits
  187. or cl,0C0h ; the highest bits are always on
  188. mov al,cl ; put it in al for the stosb
  189. stosb ; store it
  190. jmp short medrunnxt ; do the run fixup code
  191. lenin:
  192. cmp [DWORD PTR inlen],0 ; is it doing a length?
  193. jnz short len ; if so, skip code
  194. lenin1:
  195. mov [lenoff],edi ; save the length code offset
  196. mov al,80h ; set the length to 0
  197. stosb ; save it
  198. len:
  199. mov ebx,[lenoff] ; get the offset of the length code
  200. cmp BYTE PTR [ebx],0BFh ; see if its maxed out
  201. je lenin1 ; if so put out a new len code
  202. stolen:
  203. inc BYTE PTR [ebx] ; inc the count code
  204. lodsb ; get the byte
  205. stosb ; store it
  206. mov DWORD PTR [inlen],1 ; we are now in a length so save it
  207. jmp short nxt ; do the next code
  208. longrun:
  209. mov al,0ffh ; its a long so set a code of FF
  210. stosb ; store it
  211. mov eax,[count] ; send out the count
  212. stosw ; store it
  213. medrunnxt:
  214. mov eax,[matchoff] ; get the offset
  215. sub eax,[a1stsrc] ; make it relative tot he start of data
  216. srunnxt:
  217. stosw ; store it
  218. ; this code common to all runs
  219. add esi,[count] ; add in the length of the run to the source
  220. mov DWORD PTR [inlen],0 ; set the in leght flag to false
  221. ;=======================================================================
  222. nxt:
  223. cmp esi,[end_of_data] ; see if we did the whole pic
  224. jae short _out ; if so, cool! were done
  225. jmp _loop
  226. _out:
  227. mov ax,080h ; remember to send an end of data code
  228. stosb ; store it
  229. mov eax,edi ; get the last compressed address
  230. sub eax,[a1stdest] ; sub the first for the compressed size
  231. popad
  232. ret
  233. LCW_Compress endp
  234. END