; ; 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 . ; ;**************************************************************************** ;* ;* 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