lzopipe.cpp 15 KB

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