Code:
// not needed for ports to other systems
#include <stdafx.h>
#include <windows.h>
// include all of the following in all target environments
// using <cstring> instead of <string> to be compatible with newer g++
#include <cstring>
#include <fstream>
#include <iostream>
#include <stdio.h>
// if this isn't included, you would have to type 'std::ifstream' instead of just 'ifstream' for example
// lazy way to do it, but it's a small program
using namespace std;
// declare constant variables
const char *MAGIC_HEADER = "BPE ";
// function prototypes
static int xgetc(unsigned char **in, unsigned char *inl);
int yukes_bpe(unsigned char *in, int insz, unsigned char *out, int outsz, int fill_outsz);
// only include for windows versions to use the function that most computer geeks that use the console HATE :)
void ClearScreen();
// program start function
int main(int argc, char* argv[])
{
// declare and initialize the variables used in this function
// will be used to make sure it has the 'magic' of a BPE file
char *magic = new char[4];
// our input buffer
char *inbuffer;
// our output buffer
char *outbuffer;
// used to calculate the compressed size
char *readzsize = new char[4];
// used to calculate the uncompressed size
char *readsize = new char[4];
// compressed size
int zsize;
// uncompressed size
int size;
// difference between size and zsize or (size - zsize)
int fillsize;
// make sure that there are three arguments passed to the program, which are:
// the program name, the input file name, and the output filename
if (argc != 3)
{
// comes here if there are not three arguments
// only include this function call on Windows, to make geeks mad that you cleared out the console contents :)
ClearScreen();
// obligatory fancy ASCII art to show what a geek you are
cout << "\n================================================================";
cout << "\n+++++++++++++==== == == ==== == ==++++++++++++++====";
cout << "\n================== == === ==== == ==== ===================";
cout << "\n=+++++++++++++==== == === ==== == ==== ==++++++++++++++===";
cout << "\n=================== ==== ==== == ==== ===================";
cout << "\n==+++++++++++++===== ===== == ====++++++++++++++==";
cout << "\n=================== ==== ==== == =========================";
cout << "\n===+++++++++++++== == === ==== == ==========++++++++++++++=";
cout << "\n================== == === ==== == =========================";
cout << "\n=== ========= ==== == ==== == ===========++++++++++++++";
cout << "\n== === =======================================================";
cout << "\n= ================================ ===========================";
cout << "\n= ======== = ==== ==== === == === === = ==== ==";
cout << "\n= ======== = == = == = === ======= == == = =";
cout << "\n= ======== ======= ===== === === == = == = === ===";
cout << "\n= ======== ======= ====== === === == = == = ==== ==";
cout << "\n== === == ======= = == = === === == = == = == = =";
cout << "\n=== === ======== ==== === == === === = === ==";
cout << "\n================================================================";
// gives program info and usage instructions
cout << "\n\nYukes BPE Decompress example program";
cout << "\nby Brien L. Johnson of XHP Creations";
// 'argv[0]' is the first argument, which is the name of the program
cout << "\n\nUsage: " << argv[0] << " <inputfile> <outputfile>";
cout << "\n\nWebsite: ";
cout << "\nhttp://www.xhpcreations.com";
cout << "\n\nSpecial thanks to Luigi Auriemmma for yuke_bpe.c source code!\n\n";
// return any code that says it didn't complete the task, in this case we use -1 to show an error
return -1;
}
else
{
// comes here if there are three arguments
// open an input filestream named 'file' in binary mode with the second argument value 'argv[1]'
ifstream file(argv[1], ios::in|ios::binary);
// checks if the file is open
if (file.is_open())
{
// make sure the starting file position is at the beginning of file
file.seekg(0, ios::beg);
// read the contents of the first four bytes into 'magic'
file.read(magic, 4);
// use a compare to make sure the first four bytes (char*) of 'magic' match our constant 'MAGIC_HEADER'
if (memcmp(magic, MAGIC_HEADER, 4) != 0)
{
// if they don't match, insult the user for opening a file that isn't a BPE file
cout << "Open a BPE file, you numbskull!";
// return error code
return -1;
}
// continue code since they opened a BPE file
// set the file position to the 8th byte
file.seekg(8, ios::beg);
// read the contents of the next four bytes into 'readzsize'
file.read(readzsize, 4);
// set the file position to the 12th byte
file.seekg(12, ios::beg);
// read the contents of the next four bytes into 'readsize'
file.read(readsize, 4);
// set the value of 'zsize' using the four bytes in 'readzsize'
memcpy(&zsize, readzsize, sizeof(long));
// set the value of 'size' using the four bytes in 'readsize'
memcpy(&size, readsize, sizeof(long));
// they are only four bytes in size, but we can delete 'readzsize' and 'readsize'
// and free the HUGE amount of memory they are using :)
delete[] readzsize;
delete[] readsize;
// initialize input buffer 'inbuffer' to the size of 'zsize', our compressed size
inbuffer = new char[zsize];
// set the file position to the 16th byte
file.seekg(16, ios::beg);
// read the contents of the file of 'zsize' number of bytes into the input buffer 'inbuffer'
file.read(inbuffer, zsize);
// calculate the fillsize
fillsize = size - zsize;
// the all important closing of the file
file.close();
}
else
{
// if the file can't open, we of course assume they are an idiot and insult them again
cout << "\nUnable to open " << argv[1] << " you numbskull. Does the file exist?\n";
// return error code
return -1;
}
// initialize output buffer 'outbuffer' to the size of 'size', our uncompressed size
outbuffer = new char[size];
// call the function which uncompresses the input buffer to the output buffer
// 'inbuffer' and 'outbuffer' are not unsigned, which the function requires, so we cast them correctly
// with 'reinterpret_cast<unsigned char*>'
int x = yukes_bpe((reinterpret_cast<unsigned char*>(inbuffer)), zsize, (reinterpret_cast<unsigned char*>(outbuffer)), size, fillsize);
// open an output filestream named 'file2' in binary mode with the third argument value 'argv[2]'
ofstream file2(argv[2], ios_base::out|ios_base::binary);
// checks if the file is open
if (file2.is_open())
{
// if the file opened, write the changed contents of the output buffer 'outbuffer' to disk
file2.write(outbuffer, size);
// let the person know the file saved correctly
cout << "\nSuccessfully saved " << argv[2] << " to disk.\n";
// return successful code
return 0;
}
else
{
// let the person know that the file couldn't be saved and they were probably an idiot again
cout << "\nCannot write " << argv[2] << " to disk, you knucklehead. Do you have the file opened in your hex editor?\n";
// return an error code
return -1;
}
}
}
// the following two functions for Yukes BPE decompression were written by Luigi Auriemma
static int xgetc(unsigned char **in, unsigned char *inl) {
int ret;
if(*in >= inl) return(-1);
ret = **in;
(*in)++;
return(ret);
}
int yukes_bpe(unsigned char *in, int insz, unsigned char *out, int outsz, int fill_outsz) {
unsigned char stack[512 + 4096];
int c,
count,
i,
size,
n;
unsigned char *inl,
*o,
*outl;
inl = in + insz;
o = out;
outl = out + outsz;
count = 0;
for(;;) {
i = 0;
do {
if((c = xgetc(&in, inl)) < 0) break;
if(c > 127) {
c -= 127;
while((c > 0) && (i < 256)) {
stack[i * 2] = i;
c--;
i++;
}
}
c++;
while((c > 0) && (i < 256)) {
if((n = xgetc(&in, inl)) < 0) break;
stack[i * 2] = n;
if(i != n) {
if((n = xgetc(&in, inl)) < 0) break;
stack[(i * 2) + 1] = n;
}
c--;
i++;
}
} while(i < 256);
if((n = xgetc(&in, inl)) < 0) break;
size = n;
if((n = xgetc(&in, inl)) < 0) break;
size |= (n << 8);
while(size || count) {
if(count) {
count--;
n = stack[count + 512];
} else {
if((n = xgetc(&in, inl)) < 0) break;
size--;
}
c = stack[n * 2];
if(n == c) {
if(o >= outl) return(-1);
*o++ = n;
} else {
if((count + 512 + 2) > sizeof(stack)) return(-1);
stack[count + 512] = stack[(n * 2) + 1];
stack[count + 512 + 1] = c;
count += 2;
}
}
}
if(fill_outsz) { // this is what is wanted by the format
memset(o, 0, outl - o);
o = outl;
}
return(o - out);
}
// the dreaded ClearScreen function which clears all the contents out of the console window, and
// of course it must be included in my program :)
void ClearScreen()
{
HANDLE hStdOut;
CONSOLE_SCREEN_BUFFER_INFO csbi;
DWORD count;
DWORD cellCount;
COORD homeCoords = { 0, 0 };
hStdOut = GetStdHandle( STD_OUTPUT_HANDLE );
if (hStdOut == INVALID_HANDLE_VALUE) return;
// get the number of cells in the current buffer
if (!GetConsoleScreenBufferInfo( hStdOut, &csbi )) return;
cellCount = csbi.dwSize.X *csbi.dwSize.Y;
// fill the entire buffer with spaces
if (!FillConsoleOutputCharacter(
hStdOut,
(TCHAR) ' ',
cellCount,
homeCoords,
&count
)) return;
// fill the entire buffer with the current colors and attributes
if (!FillConsoleOutputAttribute(
hStdOut,
csbi.wAttributes,
cellCount,
homeCoords,
&count
)) return;
// move the cursor home
SetConsoleCursorPosition( hStdOut, homeCoords );
}