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