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