CnC_Remastered_Collection

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

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