CnC_Remastered_Collection

Command and Conquer: Red Alert
Log | Files | Refs | README | LICENSE

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