Richard Boegli's CnC_Generals_Zero_Hour Fork WIP
This is documentation of Richard Boegil's Zero Hour Fork
 
Loading...
Searching...
No Matches
lcw.cpp
Go to the documentation of this file.
1/*
2** Command & Conquer Generals Zero Hour(tm)
3** Copyright 2025 Electronic Arts Inc.
4**
5** This program is free software: you can redistribute it and/or modify
6** it under the terms of the GNU General Public License as published by
7** the Free Software Foundation, either version 3 of the License, or
8** (at your option) any later version.
9**
10** This program is distributed in the hope that it will be useful,
11** but WITHOUT ANY WARRANTY; without even the implied warranty of
12** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13** GNU General Public License for more details.
14**
15** You should have received a copy of the GNU General Public License
16** along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/***********************************************************************************************
20 *** 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 ***
21 ***********************************************************************************************
22 * *
23 * Project Name : Command & Conquer *
24 * *
25 * $Archive:: /G/wwlib/lcw.cpp $*
26 * *
27 * $Author:: Neal_k $*
28 * *
29 * $Modtime:: 10/04/99 10:25a $*
30 * *
31 * $Revision:: 4 $*
32 * *
33 *---------------------------------------------------------------------------------------------*
34 * Functions: *
35 * LCW_Comp -- Performes LCW compression on a block of data. *
36 * LCW_Uncomp -- Decompress an LCW encoded data block. *
37 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
38
39#include "always.h"
40#include "lcw.h"
41
42/***************************************************************************
43 * LCW_Uncomp -- Decompress an LCW encoded data block. *
44 * *
45 * Uncompress data to the following codes in the format b = byte, w = word *
46 * n = byte code pulled from compressed data. *
47 * *
48 * Command code, n |Description *
49 * ------------------------------------------------------------------------*
50 * n=0xxxyyyy,yyyyyyyy |short copy back y bytes and run x+3 from dest *
51 * n=10xxxxxx,n1,n2,...,nx+1|med length copy the next x+1 bytes from source*
52 * n=11xxxxxx,w1 |med copy from dest x+3 bytes from offset w1 *
53 * n=11111111,w1,w2 |long copy from dest w1 bytes from offset w2 *
54 * n=11111110,w1,b1 |long run of byte b1 for w1 bytes *
55 * n=10000000 |end of data reached *
56 * *
57 * *
58 * INPUT: *
59 * void * source ptr *
60 * void * destination ptr *
61 * unsigned long length of uncompressed data *
62 * *
63 * *
64 * OUTPUT: *
65 * unsigned long # of destination bytes written *
66 * *
67 * WARNINGS: *
68 * 3rd argument is dummy. It exists to provide cross-platform *
69 * compatibility. Note therefore that this implementation does not *
70 * check for corrupt source data by testing the uncompressed length. *
71 * *
72 * HISTORY: *
73 * 03/20/1995 IML : Created. *
74 *=========================================================================*/
75int LCW_Uncomp(void const * source, void * dest, unsigned long )
76{
77 unsigned char * source_ptr, * dest_ptr, * copy_ptr;
78 unsigned char op_code, data;
79 unsigned count;
80 unsigned * word_dest_ptr;
81 unsigned word_data;
82
83 /* Copy the source and destination ptrs. */
84 source_ptr = (unsigned char*) source;
85 dest_ptr = (unsigned char*) dest;
86
87 for (;;) {
88
89 /* Read in the operation code. */
90 op_code = *source_ptr++;
91
92 if (!(op_code & 0x80)) {
93
94 /* Do a short copy from destination. */
95 count = (op_code >> 4) + 3;
96 copy_ptr = dest_ptr - ((unsigned) *source_ptr++ + (((unsigned) op_code & 0x0f) << 8));
97
98 while (count--) *dest_ptr++ = *copy_ptr++;
99
100 } else {
101
102 if (!(op_code & 0x40)) {
103
104 if (op_code == 0x80) {
105
106 /* Return # of destination bytes written. */
107 return ((unsigned long) (dest_ptr - (unsigned char*) dest));
108
109 } else {
110
111 /* Do a medium copy from source. */
112 count = op_code & 0x3f;
113
114 while (count--) *dest_ptr++ = *source_ptr++;
115 }
116
117 } else {
118
119 if (op_code == 0xfe) {
120
121 /* Do a long run. */
122 count = *source_ptr + ((unsigned) *(source_ptr + 1) << 8);
123 word_data = data = *(source_ptr + 2);
124 word_data = (word_data << 24) + (word_data << 16) + (word_data << 8) + word_data;
125 source_ptr += 3;
126
127 copy_ptr = dest_ptr + 4 - ((unsigned) dest_ptr & 0x3);
128 count -= (copy_ptr - dest_ptr);
129 while (dest_ptr < copy_ptr) *dest_ptr++ = data;
130
131 word_dest_ptr = (unsigned*) dest_ptr;
132
133 dest_ptr += (count & 0xfffffffc);
134
135 while (word_dest_ptr < (unsigned*) dest_ptr) {
136 *word_dest_ptr = word_data;
137 *(word_dest_ptr + 1) = word_data;
138 word_dest_ptr += 2;
139 }
140
141 copy_ptr = dest_ptr + (count & 0x3);
142 while (dest_ptr < copy_ptr) *dest_ptr++ = data;
143
144 } else {
145
146 if (op_code == 0xff) {
147
148 /* Do a long copy from destination. */
149 count = *source_ptr + ((unsigned) *(source_ptr + 1) << 8);
150 copy_ptr = (unsigned char*) dest + *(source_ptr + 2) + ((unsigned) *(source_ptr + 3) << 8);
151 source_ptr += 4;
152
153 while (count--) *dest_ptr++ = *copy_ptr++;
154
155 } else {
156
157 /* Do a medium copy from destination. */
158 count = (op_code & 0x3f) + 3;
159 copy_ptr = (unsigned char*) dest + *source_ptr + ((unsigned) *(source_ptr + 1) << 8);
160 source_ptr += 2;
161
162 while (count--) *dest_ptr++ = *copy_ptr++;
163 }
164 }
165 }
166 }
167 }
168}
169
170
171#if defined(_MSC_VER)
172
173
174/***********************************************************************************************
175 * LCW_Comp -- Performes LCW compression on a block of data. *
176 * *
177 * This routine will compress a block of data using the LCW compression method. LCW has *
178 * the primary characteristic of very fast uncompression at the expense of very slow *
179 * compression times. *
180 * *
181 * INPUT: source -- Pointer to the source data to compress. *
182 * *
183 * dest -- Pointer to the destination location to store the compressed data *
184 * to. *
185 * *
186 * datasize -- The size (in bytes) of the source data to compress. *
187 * *
188 * OUTPUT: Returns with the number of bytes of output data stored into the destination *
189 * buffer. *
190 * *
191 * WARNINGS: Be sure that the destination buffer is big enough. The maximum size required *
192 * for the destination buffer is (datasize + datasize/128). *
193 * *
194 * HISTORY: *
195 * 05/20/1997 JLB : Created. *
196 *=============================================================================================*/
197/*ARGSUSED*/
198int LCW_Comp(void const * source, void * dest, int datasize)
199{
200 int retval = 0;
201#ifdef _WINDOWS
202 long inlen = 0;
203 long a1stdest = 0;
204 long a1stsrc = 0;
205 long lenoff = 0;
206 long ndest = 0;
207 long count = 0;
208 long matchoff = 0;
209 long end_of_data =0;
210#ifdef _DEBUG
211 inlen = inlen;
212 a1stdest = a1stdest;
213 a1stsrc = a1stsrc;
214 lenoff = lenoff;
215 ndest = ndest;
216 count = count;
217 matchoff = matchoff;
218 end_of_data = end_of_data;
219#endif
220
221 __asm {
222 cld // make sure all string commands are forward
223 mov edi,[dest]
224 mov esi,[source]
225 mov edx,[datasize] // get length of data to compress
226
227// compress data to the following codes in the format b = byte, w = word
228// n = byte code pulled from compressed data
229// Bit field of n command description
230// n=0xxxyyyy,yyyyyyyy short run back y bytes and run x+3
231// n=10xxxxxx,n1,n2,...,nx+1 med length copy the next x+1 bytes
232// n=11xxxxxx,w1 med run run x+3 bytes from offset w1
233// n=11111111,w1,w2 long run run w1 bytes from offset w2
234// n=10000000 end end of data reached
235
236 mov ebx,esi
237 add ebx,edx
238 mov [end_of_data],ebx
239 mov [inlen],1 //; set the in-length flag
240 mov [a1stdest],edi //; save original dest offset for size calc
241 mov [a1stsrc],esi //; save offset of first byte of data
242 mov [lenoff],edi //; save the offset of the legth of this len
243 sub eax,eax
244 mov al,081h //; the first byte is always a len
245 stosb //; write out a len of 1
246 lodsb //; get the byte
247 stosb //; save it
248 }
249
250loopstart:
251 __asm {
252 mov [ndest],edi //; save offset of compressed data
253 mov edi,[a1stsrc] //; get the offset to the first byte of data
254 mov [count],1 //; set the count of run to 0
255 }
256searchloop:
257 __asm {
258 sub eax,eax
259 mov al,[esi] //; get the current byte of data
260 cmp al,[esi+64]
261 jne short notrunlength
262
263 mov ebx,edi
264
265 mov edi,esi
266 mov ecx,[end_of_data]
267 sub ecx,edi
268 repe scasb
269 dec edi
270 mov ecx,edi
271 sub ecx,esi
272 cmp ecx,65
273 jb short notlongenough
274
275 mov [inlen],0 //; clear the in-length flag
276// mov [DWORD PTR inlen],0 //; clear the in-length flag
277 mov esi,edi
278 mov edi,[ndest] //; get the offset of our compressed data
279
280 mov ah,al
281 mov al,0FEh
282 stosb
283 xchg ecx,eax
284 stosw
285 mov al,ch
286 stosb
287
288 mov [ndest],edi //; save offset of compressed data
289 mov edi,ebx
290 jmp searchloop
291 }
292notlongenough:
293 __asm {
294 mov edi,ebx
295 }
296notrunlength:
297oploop:
298 __asm {
299 mov ecx,esi //; get the address of the last byte +1
300 sub ecx,edi //; get the total number of bytes left to comp
301 jz short searchdone
302
303 repne scasb //; look for a match
304 jne short searchdone //; if we don't find one we're done
305
306 mov ebx,[count]
307 mov ah,[esi+ebx-1]
308 cmp ah,[edi+ebx-2]
309
310 jne oploop
311
312 mov edx,esi //; save this spot for the next search
313 mov ebx,edi //; save this spot for the length calc
314 dec edi //; back up one for compare
315 mov ecx,[end_of_data] //; get the end of data
316 sub ecx,esi //; sub current source for max len
317
318 repe cmpsb //; see how many bytes match
319
320 jne short notend //; if found mismatch then di - bx = match count
321
322 inc edi //; else cx = 0 and di + 1 - bx = match count
323 }
324notend:
325 __asm {
326 mov esi,edx //; restore si
327 mov eax,edi //; get the dest
328 sub eax,ebx //; sub the start for total bytes that match
329 mov edi,ebx //; restore dest
330 cmp eax,[count] //; see if its better than before
331 jb searchloop //; if not keep looking
332
333 mov [count],eax //; if so keep the count
334 dec ebx //; back it up for the actual match offset
335 mov [matchoff],ebx //; save the offset for later
336 jmp searchloop //; loop until we searched it all
337 }
338searchdone:
339 __asm {
340 mov ecx,[count] //; get the count of the longest run
341 mov edi,[ndest] //; get the offset of our compressed data
342 cmp ecx,2 //; see if its not enough run to matter
343 jbe short lenin //; if its 0,1, or 2 its too small
344
345 cmp ecx,10 //; if not, see if it would fit in a short
346 ja short medrun //; if not, see if its a medium run
347
348 mov eax,esi //; if its short get the current address
349 sub eax,[matchoff] //; sub the offset of the match
350 cmp eax,0FFFh //; if its less than 12 bits its a short
351 ja short medrun //; if its not, its a medium
352 }
353//shortrun:
354 __asm {
355 sub ebx,ebx
356 mov bl,cl //; get the length (3-10)
357 sub bl,3 //; sub 3 for a 3 bit number 0-7
358 shl bl,4 //; shift it left 4
359 add ah,bl //; add in the length for the high nibble
360 xchg ah,al //; reverse the bytes for a word store
361 jmp short srunnxt //; do the run fixup code
362 }
363medrun:
364 __asm {
365 cmp ecx,64 //; see if its a short run
366 ja short longrun //; if not, oh well at least its long
367
368 sub cl,3 //; back down 3 to keep it in 6 bits
369 or cl,0C0h //; the highest bits are always on
370 mov al,cl //; put it in al for the stosb
371 stosb //; store it
372 jmp short medrunnxt //; do the run fixup code
373 }
374lenin:
375 __asm {
376 cmp [inlen],0 //; is it doing a length?
377// cmp [DWORD PTR inlen],0 //; is it doing a length?
378 jnz short len //; if so, skip code
379 }
380lenin1:
381 __asm {
382 mov [lenoff],edi //; save the length code offset
383 mov al,80h //; set the length to 0
384 stosb //; save it
385 }
386len:
387 __asm {
388 mov ebx,[lenoff] //; get the offset of the length code
389 cmp [ebx],0BFh //; see if its maxed out
390// cmp [BYTE PTR ebx],0BFh //; see if its maxed out
391 je lenin1 //; if so put out a new len code
392 }
393//stolen:
394 __asm {
395 inc [ebx] //; inc the count code
396// inc [BYTE PTR ebx] //; inc the count code
397 lodsb //; get the byte
398 stosb //; store it
399 mov [inlen],1 //; we are now in a length so save it
400// mov [DWORD PTR inlen],1 //; we are now in a length so save it
401 jmp short nxt //; do the next code
402 }
403longrun:
404 __asm {
405 mov al,0ffh //; its a long so set a code of FF
406 stosb //; store it
407
408 mov eax,[count] //; send out the count
409 stosw //; store it
410 }
411medrunnxt:
412 __asm {
413 mov eax,[matchoff] //; get the offset
414 sub eax,[a1stsrc] //; make it relative tot he start of data
415 }
416srunnxt:
417 __asm {
418 stosw //; store it
419 //; this code common to all runs
420 add esi,[count] //; add in the length of the run to the source
421 mov [inlen],0 //; set the in leght flag to false
422// mov [DWORD PTR inlen],0 //; set the in leght flag to false
423 }
424nxt:
425 __asm {
426 cmp esi,[end_of_data] //; see if we did the whole pic
427 jae short outofhere //; if so, cool! were done
428
429 jmp loopstart
430 }
431outofhere:
432 __asm {
433 mov ax,080h //; remember to send an end of data code
434 stosb //; store it
435 mov eax,edi //; get the last compressed address
436 sub eax,[a1stdest] //; sub the first for the compressed size
437 mov [retval],eax
438 }
439#endif
440 return(retval);
441}
442#endif
443
444
int __cdecl LCW_Comp(void const *source, void *dest, int length)
void add(float *sum, float *addend)
int LCW_Uncomp(void const *source, void *dest, unsigned long)
Definition lcw.cpp:75