LZWPIPE.CPP (14784B)
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: /CounterStrike/LZWPIPE.CPP 1 3/03/97 10:25a Joe_bostic $ */ 17 /*********************************************************************************************** 18 *** 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 *** 19 *********************************************************************************************** 20 * * 21 * Project Name : Command & Conquer * 22 * * 23 * File Name : LZWPIPE.CPP * 24 * * 25 * Programmer : Joe L. Bostic * 26 * * 27 * Start Date : 06/30/96 * 28 * * 29 * Last Update : July 4, 1996 [JLB] * 30 * * 31 *---------------------------------------------------------------------------------------------* 32 * Functions: * 33 * LZWPipe::Flush -- Flushes any partially accumulated block. * 34 * LZWPipe::LZWPipe -- Constructor for the LZW processor pipe. * 35 * LZWPipe::Put -- Send some data through the LZW processor pipe. * 36 * LZWPipe::~LZWPipe -- Deconstructor for the LZW pipe object. * 37 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 38 39 40 #include "lzwpipe.h" 41 #include "lzw.h" 42 #include "buff.h" 43 #include <string.h> 44 #include <assert.h> 45 46 47 /*********************************************************************************************** 48 * LZWPipe::LZWPipe -- Constructor for the LZW processor pipe. * 49 * * 50 * This will initialize the LZWPipe object so that it is prepared for compression or * 51 * decompression as indicated. * 52 * * 53 * INPUT: decrypt -- Should decompression be performed? * 54 * * 55 * blocksize-- The size of the data blocks to process. * 56 * * 57 * OUTPUT: none * 58 * * 59 * WARNINGS: none * 60 * * 61 * HISTORY: * 62 * 07/04/1996 JLB : Created. * 63 *=============================================================================================*/ 64 LZWPipe::LZWPipe(CompControl control, int blocksize) : 65 Control(control), 66 Counter(0), 67 Buffer(NULL), 68 Buffer2(NULL), 69 BlockSize(blocksize) 70 { 71 SafetyMargin = BlockSize; 72 // SafetyMargin = BlockSize/128+1; 73 Buffer = new char[BlockSize+SafetyMargin]; 74 Buffer2 = new char[BlockSize+SafetyMargin]; 75 BlockHeader.CompCount = 0xFFFF; 76 } 77 78 79 /*********************************************************************************************** 80 * LZWPipe::~LZWPipe -- Deconstructor for the LZW pipe object. * 81 * * 82 * This will free any buffers it may have allocated. * 83 * * 84 * INPUT: none * 85 * * 86 * OUTPUT: none * 87 * * 88 * WARNINGS: none * 89 * * 90 * HISTORY: * 91 * 07/04/1996 JLB : Created. * 92 *=============================================================================================*/ 93 LZWPipe::~LZWPipe(void) 94 { 95 delete [] Buffer; 96 Buffer = NULL; 97 98 delete [] Buffer2; 99 Buffer2 = NULL; 100 } 101 102 103 /*********************************************************************************************** 104 * LZWPipe::Put -- Send some data through the LZW processor pipe. * 105 * * 106 * This routine will take the data requested and process it (decompression or compression). * 107 * It does this by accumulating the necessary bytes to make a whole block. Then the block * 108 * is processed and the entire contents are flushed to the next pipe segment in the chain. * 109 * * 110 * INPUT: source -- Pointer to the data to be fed to this LZW processor. * 111 * * 112 * length -- The number of bytes received. * 113 * * 114 * OUTPUT: Returns with the actual number of bytes output at the far distant final link in * 115 * the pipe chain. * 116 * * 117 * WARNINGS: The compression process may be slow as well as consuming two buffers. * 118 * * 119 * HISTORY: * 120 * 07/04/1996 JLB : Created. * 121 *=============================================================================================*/ 122 int LZWPipe::Put(void const * source, int slen) 123 { 124 if (source == NULL || slen < 1) { 125 return(Pipe::Put(source, slen)); 126 } 127 128 assert(Buffer != NULL); 129 130 int total = 0; 131 132 /* 133 ** Copy as much as can fit into the buffer from the source data supplied. 134 */ 135 if (Control == DECOMPRESS) { 136 137 while (slen > 0) { 138 139 /* 140 ** First check to see if we are in the block header accumulation phase. 141 ** When a whole block header has been accumulated, only then will the regular 142 ** data processing begin for the block. 143 */ 144 if (BlockHeader.CompCount == 0xFFFF) { 145 int len = (slen < ((int)sizeof(BlockHeader)-Counter)) ? slen : (sizeof(BlockHeader)-Counter); 146 memmove(&Buffer[Counter], source, len); 147 source = ((char *)source) + len; 148 slen -= len; 149 Counter += len; 150 151 /* 152 ** A whole block header has been accumulated. Store it for safekeeping. 153 */ 154 if (Counter == sizeof(BlockHeader)) { 155 memmove(&BlockHeader, Buffer, sizeof(BlockHeader)); 156 Counter = 0; 157 } 158 } 159 160 /* 161 ** Fill the buffer with compressed data until there is enough to make a whole 162 ** data block. 163 */ 164 if (slen > 0) { 165 int len = (slen < (BlockHeader.CompCount-Counter)) ? slen : (BlockHeader.CompCount-Counter); 166 167 memmove(&Buffer[Counter], source, len); 168 slen -= len; 169 source = ((char *)source) + len; 170 Counter += len; 171 172 /* 173 ** If an entire block has been accumulated, then uncompress it and feed it 174 ** through the pipe. 175 */ 176 if (Counter == BlockHeader.CompCount) { 177 LZW_Uncompress(Buffer, Buffer2); 178 total += Pipe::Put(Buffer2, BlockHeader.UncompCount); 179 Counter = 0; 180 BlockHeader.CompCount = 0xFFFF; 181 } 182 } 183 } 184 185 } else { 186 187 /* 188 ** If the buffer already contains some data, then any new data must be stored 189 ** into the staging buffer until a full set has been accumulated. 190 */ 191 if (Counter > 0) { 192 int tocopy = (slen < (BlockSize-Counter)) ? slen : (BlockSize-Counter); 193 memmove(&Buffer[Counter], source, tocopy); 194 source = ((char *)source) + tocopy; 195 slen -= tocopy; 196 Counter += tocopy; 197 198 if (Counter == BlockSize) { 199 int len = LZW_Compress(::Buffer(Buffer, BlockSize), Buffer2); 200 201 BlockHeader.CompCount = (unsigned short)len; 202 BlockHeader.UncompCount = (unsigned short)BlockSize; 203 total += Pipe::Put(&BlockHeader, sizeof(BlockHeader)); 204 total += Pipe::Put(Buffer2, len); 205 Counter = 0; 206 } 207 } 208 209 /* 210 ** Process the source data in whole block chunks until there is insufficient 211 ** source data left for a whole data block. 212 */ 213 while (slen >= BlockSize) { 214 int len = LZW_Compress(::Buffer((void*)source, BlockSize), Buffer2); 215 216 source = ((char *)source) + BlockSize; 217 slen -= BlockSize; 218 219 BlockHeader.CompCount = (unsigned short)len; 220 BlockHeader.UncompCount = (unsigned short)BlockSize; 221 total += Pipe::Put(&BlockHeader, sizeof(BlockHeader)); 222 total += Pipe::Put(Buffer2, len); 223 } 224 225 /* 226 ** If there is any remaining data, then it is stored into the buffer 227 ** until a full data block has been accumulated. 228 */ 229 if (slen > 0) { 230 memmove(Buffer, source, slen); 231 Counter = slen; 232 } 233 } 234 235 return(total); 236 } 237 238 239 /*********************************************************************************************** 240 * LZWPipe::Flush -- Flushes any partially accumulated block. * 241 * * 242 * This routine is called when any buffered data must be flushed out the pipe. For the * 243 * compression process, this will generate the sub-sized compressed block. For * 244 * decompression, this routine should not have any data in the buffer. In such a case, it * 245 * means that the data source was prematurely truncated. In such a case, just dump the * 246 * accumulated data through the pipe. * 247 * * 248 * INPUT: none * 249 * * 250 * OUTPUT: Returns with the actual number of data bytes output to the distant final link in * 251 * the pipe chain. * 252 * * 253 * WARNINGS: none * 254 * * 255 * HISTORY: * 256 * 07/04/1996 JLB : Created. * 257 *=============================================================================================*/ 258 int LZWPipe::Flush(void) 259 { 260 assert(Buffer != NULL); 261 262 int total = 0; 263 264 /* 265 ** If there is accumulated data, then it must processed. 266 */ 267 if (Counter > 0) { 268 if (Control == DECOMPRESS) { 269 270 /* 271 ** If the accumulated data is insufficient to make a block header, then 272 ** this means the data has been truncated. Just dump the data through 273 ** as if were already decompressed. 274 */ 275 if (BlockHeader.CompCount == 0xFFFF) { 276 total += Pipe::Put(Buffer, Counter); 277 Counter = 0; 278 } 279 280 /* 281 ** There appears to be a partial block accumulated in the buffer. It would 282 ** be disastrous to try to decompress the data since there wouldn't be 283 ** the special end of data code that LZW decompression needs. In this 284 ** case, dump the data out as if it were already decompressed. 285 */ 286 if (Counter > 0) { 287 total += Pipe::Put(&BlockHeader, sizeof(BlockHeader)); 288 total += Pipe::Put(Buffer, Counter); 289 Counter = 0; 290 BlockHeader.CompCount = 0xFFFF; 291 } 292 293 } else { 294 295 /* 296 ** A partial block in the compression process is a normal occurrence. Just 297 ** compress the partial block and output normally. 298 */ 299 int len = LZW_Compress(::Buffer(Buffer, Counter), Buffer2); 300 301 BlockHeader.CompCount = (unsigned short)len; 302 BlockHeader.UncompCount = (unsigned short)Counter; 303 total += Pipe::Put(&BlockHeader, sizeof(BlockHeader)); 304 total += Pipe::Put(Buffer2, len); 305 Counter = 0; 306 } 307 } 308 309 total += Pipe::Flush(); 310 return(total); 311 } 312