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