Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

356 lines
8.7 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. #include <windows.h>
  3. #include <stdlib.h>
  4. #include <stdio.h>
  5. #include <conio.h>
  6. #include <assert.h>
  7. #include "../../../public/jcalg1.h"
  8. #define DEFAULT_BLOCK_READ_SIZE (512*1024)
  9. #define BLOCK_SIZE (16*1024)
  10. #define WINDOW_SIZE (16*1024)
  11. static unsigned g_BlockReadSize = DEFAULT_BLOCK_READ_SIZE;
  12. static void * __stdcall jcalgAlloc(DWORD size)
  13. {
  14. return malloc(size);
  15. }
  16. static bool __stdcall jcalgDealloc(void* pointer)
  17. {
  18. free(pointer);
  19. return true;
  20. }
  21. void decompress( char* filenameIn, char* filenameOut )
  22. {
  23. FILE* hIn = fopen( filenameIn, "rb" );
  24. if( !hIn )
  25. {
  26. printf("Failed to open input file: %s\n",filenameIn);
  27. return;
  28. }
  29. FILE* hOut = fopen( filenameOut, "wb+" );
  30. if( !hIn )
  31. {
  32. printf("Failed to open output file: %s\n",filenameOut);
  33. fclose(hIn);
  34. return;
  35. }
  36. char* inputBuffer = (char*)malloc( g_BlockReadSize );
  37. xCompressHeader header;
  38. fread(&header,1,sizeof(header), hIn );
  39. fseek(hIn, 0, SEEK_SET);
  40. char* outputBuffer = (char *)malloc( header.nDecompressionBufferSize );
  41. for(;;)
  42. {
  43. // Read in a buffer full of compressed data.
  44. unsigned bytesRead = (unsigned)fread(inputBuffer,1,g_BlockReadSize, hIn );
  45. if( !bytesRead )
  46. break;
  47. unsigned outputBufferLength;
  48. xCompressHeader* header = (xCompressHeader*)inputBuffer;
  49. if( header->nMagic == xCompressHeader::MAGIC
  50. && header->VERSION == xCompressHeader::VERSION )
  51. {
  52. printf("Found header:\n"
  53. "\t%i Version\n"
  54. "\t%i Uncompressed Size\n"
  55. "\t%i ReadBlockSize\n"
  56. "\t%i DecompressionBufferSize\n",header->nVersion, header->nUncompressedFileSize,header->nReadBlockSize,header->nDecompressionBufferSize );
  57. outputBufferLength = JCALG1_Decompress_Formatted_Buffer( bytesRead - sizeof(*header), inputBuffer + sizeof(*header), g_BlockReadSize * 8, outputBuffer );
  58. }
  59. else
  60. {
  61. outputBufferLength = JCALG1_Decompress_Formatted_Buffer( bytesRead, inputBuffer, g_BlockReadSize * 8, outputBuffer );
  62. }
  63. assert(0xFFFFFFFF != outputBufferLength );
  64. fwrite( outputBuffer,1,outputBufferLength, hOut);
  65. printf("block:%u\n", outputBufferLength);
  66. }
  67. free(inputBuffer);
  68. free(outputBuffer);
  69. fclose(hIn);
  70. fclose(hOut);
  71. }
  72. void compressSimple(char* filenameIn, char* filenameOut )
  73. {
  74. FILE* hIn = fopen( filenameIn, "rb" );
  75. if( !hIn )
  76. {
  77. printf("Failed to open input file: %s\n",filenameIn);
  78. return;
  79. }
  80. fseek(hIn, 0, SEEK_END);
  81. unsigned uncompressedSize = ftell(hIn);
  82. fseek(hIn, 0, SEEK_SET);
  83. char* uncompressedData = (char*)malloc( uncompressedSize );
  84. fread( uncompressedData,1,uncompressedSize, hIn );
  85. fclose(hIn);
  86. char* compressedData = (char*)malloc( uncompressedSize * 4 + sizeof( xCompressSimpleHeader ));
  87. int compressedSize = JCALG1_Compress(
  88. uncompressedData,
  89. uncompressedSize,
  90. compressedData + sizeof( xCompressSimpleHeader ),
  91. uncompressedSize,
  92. jcalgAlloc,
  93. jcalgDealloc,
  94. NULL,
  95. true);
  96. xCompressSimpleHeader* header = (xCompressSimpleHeader*)compressedData;
  97. header->nMagic = xCompressSimpleHeader::MAGIC;
  98. header->nUncompressedSize = uncompressedSize;
  99. compressedSize += sizeof( xCompressSimpleHeader );
  100. printf("uncompressed size: %uk, compressedSize = %uk\n",uncompressedSize/1024, compressedSize / 1024);
  101. FILE* hOut = fopen( filenameOut, "wb+" );
  102. if( !hIn )
  103. {
  104. printf("Failed to open output file: %s\n",filenameOut);
  105. fclose(hIn);
  106. return;
  107. }
  108. fwrite( compressedData, 1, compressedSize, hOut );
  109. fclose( hOut );
  110. }
  111. void decompressSimple(char* filenameIn, char* filenameOut )
  112. {
  113. FILE* hIn = fopen( filenameIn, "rb" );
  114. if( !hIn )
  115. {
  116. printf("Failed to open input file: %s\n",filenameIn);
  117. return;
  118. }
  119. fseek(hIn, 0, SEEK_END);
  120. unsigned compressedSize = ftell(hIn);
  121. fseek(hIn, 0, SEEK_SET);
  122. char* compressedData = (char*)malloc( compressedSize );
  123. fread( compressedData,1,compressedSize, hIn );
  124. fclose(hIn);
  125. char* decompressedData = (char*)malloc( ((xCompressSimpleHeader*)compressedData)->nUncompressedSize );
  126. unsigned decompressedSize = JCALG1_Decompress_Simple_Buffer( compressedData, decompressedData );
  127. FILE* hOut = fopen( filenameOut, "wb+" );
  128. if( !hIn )
  129. {
  130. printf("Failed to open output file: %s\n",filenameOut);
  131. fclose(hIn);
  132. return;
  133. }
  134. fwrite( decompressedData, 1, decompressedSize, hOut );
  135. fclose( hOut );
  136. }
  137. int main( int argc, char* argv[] )
  138. {
  139. if( argc < 4 || argc > 5)
  140. {
  141. puts("USAGE: xcompress [c|d|cs|ds] <inputfile> <outputfile> [readsizekb]");
  142. puts("\nIf cs is specified, a 'simple' archive is created. (unaligned and decompresses the entire thing to a buffer)");
  143. return EXIT_FAILURE;
  144. }
  145. if( !strcmpi(argv[1],"d") )
  146. {
  147. decompress( argv[2], argv[3] );
  148. return EXIT_SUCCESS;
  149. }
  150. if( !strcmpi(argv[1],"cs") )
  151. {
  152. compressSimple(argv[2], argv[3]);
  153. return EXIT_SUCCESS;
  154. }
  155. if( !strcmpi(argv[1],"ds") )
  156. {
  157. decompressSimple(argv[2], argv[3]);
  158. return EXIT_SUCCESS;
  159. }
  160. FILE* hIn = fopen( argv[2], "rb" );
  161. if( !hIn )
  162. {
  163. printf("Failed to open input file: %s\n",argv[2]);
  164. return EXIT_FAILURE;
  165. }
  166. fseek( hIn, 0, SEEK_END );
  167. unsigned nInputLength = ftell( hIn );
  168. fseek( hIn, 0, SEEK_SET );
  169. // Grab
  170. if( argc >= 5 )
  171. {
  172. g_BlockReadSize = atoi(argv[4]) * 1024;
  173. if( g_BlockReadSize <= 0 )
  174. {
  175. printf("Invalid block read size! %s\n", argv[4]);
  176. return EXIT_FAILURE;
  177. }
  178. }
  179. printf("\nOptimized for read block size: %u\n",g_BlockReadSize);
  180. FILE* hOut = fopen( argv[3], "wb+" );
  181. if( !hIn )
  182. {
  183. printf("Failed to open output file: %s\n",argv[3]);
  184. fclose(hIn);
  185. return EXIT_FAILURE;
  186. }
  187. unsigned char inputBuffer[BLOCK_SIZE];
  188. unsigned char outputBuffer[BLOCK_SIZE * 2];
  189. unsigned bytesThisBlock = 0, // Total output bytes this block
  190. inputBytesThisBlock = 0, // Total input bytes this block
  191. totalBytes = 0,
  192. inputBytes = 0;
  193. // Set up and write out the header;
  194. xCompressHeader header;
  195. header.nMagic = xCompressHeader::MAGIC;
  196. header.nVersion = xCompressHeader::VERSION;
  197. header.nUncompressedFileSize = nInputLength;
  198. header.nReadBlockSize = g_BlockReadSize;
  199. header.nDecompressionBufferSize = 0;
  200. header.nWindowSize = WINDOW_SIZE;
  201. totalBytes = bytesThisBlock = inputBytesThisBlock = sizeof(header);
  202. fwrite(&header,1,sizeof(header),hOut);
  203. while(1)
  204. {
  205. // Read an input buffer full of data:
  206. size_t bytesRead = fread(inputBuffer,1,sizeof(inputBuffer),hIn);
  207. if( !bytesRead )
  208. break;
  209. inputBytes += (unsigned)bytesRead;
  210. unsigned compressedSize = JCALG1_Compress(
  211. inputBuffer,
  212. (unsigned)bytesRead,
  213. outputBuffer + sizeof(short),
  214. 16384,
  215. jcalgAlloc,
  216. jcalgDealloc,
  217. NULL,
  218. true);
  219. unsigned outputBufferSize;
  220. // If we couldn't compress this block, just write it out:
  221. if( compressedSize == 0 )
  222. {
  223. outputBufferSize = (unsigned)(bytesRead + sizeof(unsigned short));
  224. *((unsigned short*)outputBuffer) = ((unsigned short)bytesRead) | 0x8000;
  225. memcpy(outputBuffer+2,inputBuffer,bytesRead);
  226. }
  227. // Tag the compression header onto this block:
  228. else
  229. {
  230. outputBufferSize = compressedSize + sizeof(unsigned short);
  231. *((unsigned short*)outputBuffer) = compressedSize;
  232. }
  233. // Do we have enough room in this chunk to fit this buffer?
  234. if( bytesThisBlock + outputBufferSize > g_BlockReadSize )
  235. {
  236. // no, first align it:
  237. while( bytesThisBlock < g_BlockReadSize )
  238. {
  239. char b = 0;
  240. fwrite( &b, 1, sizeof(b), hOut );
  241. bytesThisBlock++;
  242. totalBytes++;
  243. }
  244. // Compute the minimum size of the decompression buffer:
  245. if( inputBytesThisBlock > header.nDecompressionBufferSize )
  246. {
  247. header.nDecompressionBufferSize = inputBytesThisBlock;
  248. }
  249. // Start a new block:
  250. bytesThisBlock = 0;
  251. inputBytesThisBlock = 0;
  252. }
  253. // Write the chunk out:
  254. fwrite(outputBuffer,1, outputBufferSize, hOut);
  255. inputBytesThisBlock += bytesRead;
  256. bytesThisBlock+=outputBufferSize;
  257. totalBytes+=outputBufferSize;
  258. static int counter =0;
  259. counter++;
  260. if( counter % 4 == 0 )
  261. {
  262. printf("\r \rInput:%uk Output:%uk (%0.1f%%)",inputBytes / 1024,totalBytes / 1024, ( (double)totalBytes / (double)inputBytes ) * 100);
  263. fflush(stdout);
  264. }
  265. }
  266. // Grab the last block (may be the only block)Compute the minimum size of the decompression buffer:
  267. if( inputBytesThisBlock > header.nDecompressionBufferSize )
  268. {
  269. header.nDecompressionBufferSize = inputBytesThisBlock;
  270. inputBytesThisBlock = 0;
  271. }
  272. unsigned short terminator = 0;
  273. fwrite(&terminator, 1, sizeof(terminator), hOut );
  274. // Align the file to a 2k boundary.
  275. while( ( ftell(hOut) % 2048 ) != 0)
  276. {
  277. fwrite(&terminator,1,1,hOut);
  278. }
  279. // Write the header out again, this time with ideal decompression size:
  280. header.nDecompressionBufferSize += 128;
  281. fseek( hOut, 0, SEEK_SET );
  282. fwrite(&header,1,sizeof(header),hOut);
  283. printf("\n");
  284. fclose(hIn);
  285. fclose(hOut);
  286. }