source-engine/utils/xbox/xcompress/xcompress.cpp
FluorescentCIAAfricanAmerican 3bf9df6b27 1
2020-04-22 12:56:21 -04:00

357 lines
8.7 KiB
C++

//========= 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);
}