summaryrefslogtreecommitdiff
path: root/utils/xbox/xcompress/xcompress.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'utils/xbox/xcompress/xcompress.cpp')
-rw-r--r--utils/xbox/xcompress/xcompress.cpp357
1 files changed, 357 insertions, 0 deletions
diff --git a/utils/xbox/xcompress/xcompress.cpp b/utils/xbox/xcompress/xcompress.cpp
new file mode 100644
index 0000000..df87f00
--- /dev/null
+++ b/utils/xbox/xcompress/xcompress.cpp
@@ -0,0 +1,357 @@
+//========= 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);
+
+} \ No newline at end of file