//========= Copyright Valve Corporation, All rights reserved. ============// #include #include #include #include #include #include "../../../public/jcalg1.h" #define DEFAULT_BLOCK_READ_SIZE (512*1024) #define BLOCK_SIZE (16*1024) #define WINDOW_SIZE (16*1024) static unsigned g_BlockReadSize = DEFAULT_BLOCK_READ_SIZE; static void * __stdcall jcalgAlloc(DWORD size) { return malloc(size); } static bool __stdcall jcalgDealloc(void* pointer) { free(pointer); return true; } void decompress( char* filenameIn, char* filenameOut ) { FILE* hIn = fopen( filenameIn, "rb" ); if( !hIn ) { printf("Failed to open input file: %s\n",filenameIn); return; } FILE* hOut = fopen( filenameOut, "wb+" ); if( !hIn ) { printf("Failed to open output file: %s\n",filenameOut); fclose(hIn); return; } char* inputBuffer = (char*)malloc( g_BlockReadSize ); xCompressHeader header; fread(&header,1,sizeof(header), hIn ); fseek(hIn, 0, SEEK_SET); char* outputBuffer = (char *)malloc( header.nDecompressionBufferSize ); for(;;) { // Read in a buffer full of compressed data. unsigned bytesRead = (unsigned)fread(inputBuffer,1,g_BlockReadSize, hIn ); if( !bytesRead ) break; unsigned outputBufferLength; xCompressHeader* header = (xCompressHeader*)inputBuffer; if( header->nMagic == xCompressHeader::MAGIC && header->VERSION == xCompressHeader::VERSION ) { printf("Found header:\n" "\t%i Version\n" "\t%i Uncompressed Size\n" "\t%i ReadBlockSize\n" "\t%i DecompressionBufferSize\n",header->nVersion, header->nUncompressedFileSize,header->nReadBlockSize,header->nDecompressionBufferSize ); outputBufferLength = JCALG1_Decompress_Formatted_Buffer( bytesRead - sizeof(*header), inputBuffer + sizeof(*header), g_BlockReadSize * 8, outputBuffer ); } else { outputBufferLength = JCALG1_Decompress_Formatted_Buffer( bytesRead, inputBuffer, g_BlockReadSize * 8, outputBuffer ); } assert(0xFFFFFFFF != outputBufferLength ); fwrite( outputBuffer,1,outputBufferLength, hOut); printf("block:%u\n", outputBufferLength); } free(inputBuffer); free(outputBuffer); fclose(hIn); fclose(hOut); } void compressSimple(char* filenameIn, char* filenameOut ) { FILE* hIn = fopen( filenameIn, "rb" ); if( !hIn ) { printf("Failed to open input file: %s\n",filenameIn); return; } fseek(hIn, 0, SEEK_END); unsigned uncompressedSize = ftell(hIn); fseek(hIn, 0, SEEK_SET); char* uncompressedData = (char*)malloc( uncompressedSize ); fread( uncompressedData,1,uncompressedSize, hIn ); fclose(hIn); char* compressedData = (char*)malloc( uncompressedSize * 4 + sizeof( xCompressSimpleHeader )); int compressedSize = JCALG1_Compress( uncompressedData, uncompressedSize, compressedData + sizeof( xCompressSimpleHeader ), uncompressedSize, jcalgAlloc, jcalgDealloc, NULL, true); xCompressSimpleHeader* header = (xCompressSimpleHeader*)compressedData; header->nMagic = xCompressSimpleHeader::MAGIC; header->nUncompressedSize = uncompressedSize; compressedSize += sizeof( xCompressSimpleHeader ); printf("uncompressed size: %uk, compressedSize = %uk\n",uncompressedSize/1024, compressedSize / 1024); FILE* hOut = fopen( filenameOut, "wb+" ); if( !hIn ) { printf("Failed to open output file: %s\n",filenameOut); fclose(hIn); return; } fwrite( compressedData, 1, compressedSize, hOut ); fclose( hOut ); } void decompressSimple(char* filenameIn, char* filenameOut ) { FILE* hIn = fopen( filenameIn, "rb" ); if( !hIn ) { printf("Failed to open input file: %s\n",filenameIn); return; } fseek(hIn, 0, SEEK_END); unsigned compressedSize = ftell(hIn); fseek(hIn, 0, SEEK_SET); char* compressedData = (char*)malloc( compressedSize ); fread( compressedData,1,compressedSize, hIn ); fclose(hIn); char* decompressedData = (char*)malloc( ((xCompressSimpleHeader*)compressedData)->nUncompressedSize ); unsigned decompressedSize = JCALG1_Decompress_Simple_Buffer( compressedData, decompressedData ); FILE* hOut = fopen( filenameOut, "wb+" ); if( !hIn ) { printf("Failed to open output file: %s\n",filenameOut); fclose(hIn); return; } fwrite( decompressedData, 1, decompressedSize, hOut ); fclose( hOut ); } int main( int argc, char* argv[] ) { if( argc < 4 || argc > 5) { puts("USAGE: xcompress [c|d|cs|ds] [readsizekb]"); puts("\nIf cs is specified, a 'simple' archive is created. (unaligned and decompresses the entire thing to a buffer)"); return EXIT_FAILURE; } if( !strcmpi(argv[1],"d") ) { decompress( argv[2], argv[3] ); return EXIT_SUCCESS; } if( !strcmpi(argv[1],"cs") ) { compressSimple(argv[2], argv[3]); return EXIT_SUCCESS; } if( !strcmpi(argv[1],"ds") ) { decompressSimple(argv[2], argv[3]); return EXIT_SUCCESS; } FILE* hIn = fopen( argv[2], "rb" ); if( !hIn ) { printf("Failed to open input file: %s\n",argv[2]); return EXIT_FAILURE; } fseek( hIn, 0, SEEK_END ); unsigned nInputLength = ftell( hIn ); fseek( hIn, 0, SEEK_SET ); // Grab if( argc >= 5 ) { g_BlockReadSize = atoi(argv[4]) * 1024; if( g_BlockReadSize <= 0 ) { printf("Invalid block read size! %s\n", argv[4]); return EXIT_FAILURE; } } printf("\nOptimized for read block size: %u\n",g_BlockReadSize); FILE* hOut = fopen( argv[3], "wb+" ); if( !hIn ) { printf("Failed to open output file: %s\n",argv[3]); fclose(hIn); return EXIT_FAILURE; } unsigned char inputBuffer[BLOCK_SIZE]; unsigned char outputBuffer[BLOCK_SIZE * 2]; unsigned bytesThisBlock = 0, // Total output bytes this block inputBytesThisBlock = 0, // Total input bytes this block totalBytes = 0, inputBytes = 0; // Set up and write out the header; xCompressHeader header; header.nMagic = xCompressHeader::MAGIC; header.nVersion = xCompressHeader::VERSION; header.nUncompressedFileSize = nInputLength; header.nReadBlockSize = g_BlockReadSize; header.nDecompressionBufferSize = 0; header.nWindowSize = WINDOW_SIZE; totalBytes = bytesThisBlock = inputBytesThisBlock = sizeof(header); fwrite(&header,1,sizeof(header),hOut); while(1) { // Read an input buffer full of data: size_t bytesRead = fread(inputBuffer,1,sizeof(inputBuffer),hIn); if( !bytesRead ) break; inputBytes += (unsigned)bytesRead; unsigned compressedSize = JCALG1_Compress( inputBuffer, (unsigned)bytesRead, outputBuffer + sizeof(short), 16384, jcalgAlloc, jcalgDealloc, NULL, true); unsigned outputBufferSize; // If we couldn't compress this block, just write it out: if( compressedSize == 0 ) { outputBufferSize = (unsigned)(bytesRead + sizeof(unsigned short)); *((unsigned short*)outputBuffer) = ((unsigned short)bytesRead) | 0x8000; memcpy(outputBuffer+2,inputBuffer,bytesRead); } // Tag the compression header onto this block: else { outputBufferSize = compressedSize + sizeof(unsigned short); *((unsigned short*)outputBuffer) = compressedSize; } // Do we have enough room in this chunk to fit this buffer? if( bytesThisBlock + outputBufferSize > g_BlockReadSize ) { // no, first align it: while( bytesThisBlock < g_BlockReadSize ) { char b = 0; fwrite( &b, 1, sizeof(b), hOut ); bytesThisBlock++; totalBytes++; } // Compute the minimum size of the decompression buffer: if( inputBytesThisBlock > header.nDecompressionBufferSize ) { header.nDecompressionBufferSize = inputBytesThisBlock; } // Start a new block: bytesThisBlock = 0; inputBytesThisBlock = 0; } // Write the chunk out: fwrite(outputBuffer,1, outputBufferSize, hOut); inputBytesThisBlock += bytesRead; bytesThisBlock+=outputBufferSize; totalBytes+=outputBufferSize; static int counter =0; counter++; if( counter % 4 == 0 ) { printf("\r \rInput:%uk Output:%uk (%0.1f%%)",inputBytes / 1024,totalBytes / 1024, ( (double)totalBytes / (double)inputBytes ) * 100); fflush(stdout); } } // Grab the last block (may be the only block)Compute the minimum size of the decompression buffer: if( inputBytesThisBlock > header.nDecompressionBufferSize ) { header.nDecompressionBufferSize = inputBytesThisBlock; inputBytesThisBlock = 0; } unsigned short terminator = 0; fwrite(&terminator, 1, sizeof(terminator), hOut ); // Align the file to a 2k boundary. while( ( ftell(hOut) % 2048 ) != 0) { fwrite(&terminator,1,1,hOut); } // Write the header out again, this time with ideal decompression size: header.nDecompressionBufferSize += 128; fseek( hOut, 0, SEEK_SET ); fwrite(&header,1,sizeof(header),hOut); printf("\n"); fclose(hIn); fclose(hOut); }