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.
357 lines
8.7 KiB
357 lines
8.7 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
#include <windows.h> |
|
#include <stdlib.h> |
|
#include <stdio.h> |
|
#include <conio.h> |
|
#include <assert.h> |
|
#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] <inputfile> <outputfile> [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); |
|
|
|
} |