| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266 |
- ;
- ; Command & Conquer Red Alert(tm)
- ; Copyright 2025 Electronic Arts Inc.
- ;
- ; This program is free software: you can redistribute it and/or modify
- ; it under the terms of the GNU General Public License as published by
- ; the Free Software Foundation, either version 3 of the License, or
- ; (at your option) any later version.
- ;
- ; This program is distributed in the hope that it will be useful,
- ; but WITHOUT ANY WARRANTY; without even the implied warranty of
- ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ; GNU General Public License for more details.
- ;
- ; You should have received a copy of the GNU General Public License
- ; along with this program. If not, see <http://www.gnu.org/licenses/>.
- ;
- ;****************************************************************************
- ;*
- ;* C O N F I D E N T I A L -- W E S T W O O D S T U D I O S
- ;*
- ;*---------------------------------------------------------------------------
- ;*
- ;* FILE
- ;* lcwcomp.asm
- ;*
- ;* DESCRIPTION
- ;* LCW compression code. (32-Bit protected mode)
- ;*
- ;* PROGRAMMER
- ;* Louis Castle
- ;* Denzil E. Long, Jr.
- ;*
- ;* DATE
- ;* January 26, 1995
- ;*
- ;*---------------------------------------------------------------------------
- ;*
- ;* PUBLIC
- ;* LCW_Compress - LCW compress a buffer of memory.
- ;*
- ;****************************************************************************
- IDEAL
- P386
- MODEL USE32 FLAT
- LOCALS ??
- CODESEG
- ;****************************************************************************
- ;*
- ;* NAME
- ;* LCW_Compress - LCW compress a buffer of memory.
- ;*
- ;* SYNOPSIS
- ;* Size = LCW_Compress(Source, Dest, Length)
- ;*
- ;* long LCW_Compress(void *, void *, long);
- ;*
- ;* FUNCTION
- ;*
- ;* INPUTS
- ;* Source - Pointer to data to compress.
- ;* Dest - Pointer to buffer to put compressed data.
- ;* Length - Length in bytes of data to compress.
- ;*
- ;* RESULT
- ;* Size - Size in bytes of compresed data.
- ;*
- ;****************************************************************************
- GLOBAL C LCW_Compress:NEAR
- PROC LCW_Compress C NEAR USES ebx ecx edx esi edi
- ARG source:DWORD
- ARG dest:DWORD
- ARG datasize:DWORD
- LOCAL inlen:DWORD
- LOCAL a1stdest:DWORD
- LOCAL a1stsrc:DWORD
- LOCAL lenoff:DWORD
- LOCAL ndest:DWORD
- LOCAL count:DWORD
- LOCAL matchoff:DWORD
- LOCAL end_of_data:DWORD
- mov esi,[source]
- mov edi,[dest]
- mov edx,[datasize]
- cld ;Forward direction
- mov ebx,esi
- add ebx,edx
- mov [end_of_data],ebx ;Save end of source address
- mov [inlen],1 ;Set the in-length flag
- mov [a1stdest],edi ;Save original dest
- mov [a1stsrc],esi ;Save original source
- mov [lenoff],edi ;Save offset length
- mov al,081h ;First byte is always a len
- stosb ;Write out a len of 1
- lodsb ;Get the byte
- stosb ;Save it
- ??loop:
- mov [ndest],edi ;Save offset of compressed data
- mov edi,[a1stsrc] ;Get address of first byte
- mov [count],1 ;Set the count of run to 0
- ??searchloop:
- sub eax,eax
- mov al,[esi] ;Get the current byte of data
- cmp al,[esi + 64]
- jne short ??notrunlength
- mov ebx,edi
- mov edi,esi
- mov ecx,[end_of_data]
- sub ecx,edi
- repe scasb
- dec edi
- mov ecx,edi
- sub ecx,esi
- cmp ecx,65
- jb short ??notlongenough
- mov [inlen],0 ;Clear the in-length flag
- mov esi,edi
- mov edi,[ndest]
- mov ah,al
- mov al,0FEh
- stosb
- xchg ecx,eax
- stosw
- mov al,ch
- stosb
- mov [ndest],edi ;Save offset of compressed data
- mov edi,ebx
- jmp ??searchloop
- ??notlongenough:
- mov edi,ebx
- ??notrunlength:
- ??oploop:
- mov ecx,esi ;Address of the last byte +1
- sub ecx,edi ;Total number of bytes left
- jz short ??searchdone
- repne scasb ;Look for a match
- jne short ??searchdone ;If we don't find one we're done
- mov ebx,[count]
- mov ah,[esi+ebx-1]
- cmp ah,[edi+ebx-2]
- jne ??oploop
- mov edx,esi ;Save address for the next search
- mov ebx,edi ;Save address for the length calc
- dec edi ;Back up one for compare
- mov ecx,[end_of_data] ;Get the end of data
- sub ecx,esi ;Sub current source for max len
- repe cmpsb ;See how many bytes match
- jne short ??notend
- inc edi
- ??notend:
- mov esi,edx
- mov eax,edi ;Get the dest
- sub eax,ebx ;Sub the start for total bytes that match
- mov edi,ebx ;Restore dest
- cmp eax,[count] ;See if its better than before
- jb ??searchloop ;If not keep looking
- mov [count],eax ;If so keep the count
- dec ebx ;Back it up for the actual match offset
- mov [matchoff],ebx ;Save the offset for later
- jmp ??searchloop ;Loop until we searched it all
- ??searchdone:
- mov ecx,[count] ;Get the count of the longest run
- mov edi,[ndest] ;Get the paragraph of our compressed data
- cmp ecx,2 ;See if its not enough run to matter
- jbe short ??lenin ;If its 0,1, or 2 its too small
- cmp ecx,10 ;If not, see if it would fit in a short
- ja short ??medrun ;If not, see if its a medium run
- mov eax,esi ;If its short get the current address
- sub eax,[matchoff] ;Sub the offset of the match
- cmp eax,0FFFh ;If its less than 12 bits its a short
- ja short ??medrun ;If its not, its a medium
- ??shortrun:
- mov bl,cl ;Get the length (3-10)
- sub bl,3 ;Sub 3 for a 3 bit number 0-7
- shl bl,4
- add ah,bl
- xchg ah,al
- jmp short ??srunnxt ;Do the run fixup code
- ??medrun:
- cmp ecx,64 ;See if its a short run
- ja short ??longrun ;If not, oh well at least its long
- sub cl,3 ;Back down 3 to keep it in 6 bits
- or cl,0C0h ;The highest bits are always on
- mov al,cl ;Put it in al for the stosb
- stosb ;Store it
- jmp short ??medrunnxt ;Do the run fixup code
- ??lenin:
- cmp [inlen],0 ;Is it doing a length?
- jnz short ??len ;If so, skip code
- ??lenin1:
- mov [lenoff],edi ;Save the length code offset
- mov al,80h ;Set the length to 0
- stosb ;Save it
- ??len:
- mov ebx,[lenoff] ;Get the offset of the length code
- cmp [BYTE PTR ebx],0BFh ;See if its maxed out
- je ??lenin1 ;If so put out a new len code
- ??stolen:
- inc [BYTE PTR ebx] ;Inc the count code
- lodsb ;Get the byte
- stosb ;Store it
- mov [inlen],1 ;We are now in a length so save it
- jmp short ??nxt ;Do the next code
- ??longrun:
- mov al,0FFh ;Its a long so set a code of FF
- stosb ;Store it
- mov eax,[count] ;Send out the count
- stosw ;Store it
- ??medrunnxt:
- mov eax,[matchoff] ;Get the offset
- sub eax,[a1stsrc] ;Make it relative tot he start of data
- ??srunnxt:
- stosw ;Store it
- add esi,[count] ;Add in the length of the run to the source
- mov [inlen],0 ;Set the in leght flag to false
- ??nxt:
- cmp esi,[end_of_data] ;See if we did the whole pic
- jae short ??out ;If so, cool! were done
- jmp ??loop
- ??out:
- mov eax,080h ;Remember to send an end of data code
- stosb ;Store it
- mov eax,edi ;Get the last compressed address
- sub eax,[a1stdest] ;Sub the first for the compressed size
- ret
- ENDP LCW_Compress
- END
|