GD Leen
Below is a decompressor and recompressor for GD Leen. This has been updated to compile with GCC, below that is the original unmodified file.
//------------------------------------------------//
// Decompressor and Recompressor: GDLeen ver 1.0 //
// //
// Coded By: John C. (Bongo`) //
// Feb 15th, 2005 //
// Revised By: Matthew Callis //
// October 30th, 2011 //
// Compiled with gcc //
//------------------------------------------------//
#include <stdio.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define LRAM(x) *(long *)&ram[x]
#define WRAM(x) *(unsigned int *)&ram[x]
char ram[0x30000];
char *comp;
char *buffer;
long iOffset;
unsigned int iLoop;
unsigned int iHeader;
char fil1[260] = "gdleen.smc";
char fil2[260] = { 0 };
FILE *f1;
FILE *f2;
char Decompress(unsigned int value);
char Recompress(unsigned int value);
long Snes2Pc(long Offset);
long FileSize(FILE *tf);
void usage(void){
printf("Usage:\n");
printf(" gdleen\n");
printf(" -d Decompress\n");
printf(" -r Recompress\n");
exit(8);
}
int main(int argc, char *argv[]){
printf("GD Leen Compression Tool\n\n");
// Start coding
// Switch thru data
while((argc > 1) && (argv[1][0] == '-')){
switch(argv[1][1]){
case 'd':
printf("Decompressing...\n");
iLoop = -1;
while(++iLoop < 0x100){
Decompress(iLoop);
}
break;
case 'r':
printf("Recompressing...\n");
Recompress(0x0F);
ram[0x00] = 2;
break;
case '3':
case 27 :
ram[0x00] = 3;
break;
default:
printf("Wrong Argument: %s\n", argv[1]);
ram[0x00] = 0;
usage();
}
++argv;
--argc;
}
return 0;
}
// Decompress the ROM data
char Decompress(unsigned int value){
// Open the file(s)
f1 = fopen(fil1, "rb");
if(!f1){
printf("Error opening SOURCE file...");
return -1;
}
// Does the ROM have a header?
iHeader = FileSize(f1) & 0x0200;
// Make the file name
sprintf(fil2, "GD_%03d.dat", value);
f2 = fopen(fil2, "wb");
if(!f2){
printf("Error opening DESTINATION file...");
return -1;
}
// Print it
printf("Dumping... %s\n", fil2);
// Load to the pointer data [offset]
fseek(f1, Snes2Pc(0xE674 + value), SEEK_SET);
iOffset = fgetc(f1);
iOffset <<= 16;
fseek(f1, Snes2Pc(0xE724 + value), SEEK_SET);
WRAM(0x14) = fgetc(f1);
// Y index into pointer table
WRAM(0x14) <<= 1;
// Set the ROM address conversion
fseek(f1, Snes2Pc(iOffset + (0x8000 + WRAM(0x14))), SEEK_SET);
fread(&ram[0x14], 1, 2, f1);
iOffset += (WRAM(0x14) + 0x8000);
iOffset = Snes2Pc(iOffset);
fseek(f1, iOffset, SEEK_SET);
// Init start of compresion buffer
WRAM(0x00) = 0;
// Where the decompressed data goes.
comp = &ram[0x10000];
// Load the data size, 16-bits
fread(&ram[0xF100], 1, 2, f1);
// Negative value test
// BMI $56 [$E663]
iOffset = ftell(f1);
ram[0x10] = fgetc(f1);
// Deternmine which routine is wanted
if(ram[0x10] < 0){
// Store all static data to file
while(WRAM(0xF100)){
comp[WRAM(0x00)] = fgetc(f1);
WRAM(0x00) += 1;
WRAM(0xF100) -= 1;
}
}
else{
// Hight BIT was NOT set!
// Get back to the data
fseek(f1, iOffset, SEEK_SET);
// Loop through the routine
while(WRAM(0x00) < WRAM(0xF100)){
// counter
ram[ 0xF104 ] = 8;
// test BYTE
ram[ 0xF106 ] = fgetc(f1);
// Loop through 8 BITS
while(ram[ 0xF104 ]--){
// Test for compression
if(!(ram[ 0xF106 ] & 0x80)){
// We DON'T have compression
comp[ WRAM(0x00) ] = fgetc(f1);
WRAM(0x00) += 1;
}
else{
// We have compression
// Get starting BYTE
ram[ 0x10 ] = fgetc(f1);
// Set copy amount
ram[ 0xF105 ] = (ram[ 0x10 ] & 0x0F) + 3;
// Get the high BYTE of copy offset
// Original routine: LSR x 4, XBA
WRAM(0x12) = (ram[ 0x10 ] & 0xF0);
WRAM(0x12) <<= 4; // XBA
WRAM(0x12) += fgetc(f1);
WRAM(0x12) ^= 0xFFFF;
WRAM(0x12) += WRAM(0x00);
// Copy the data
while(ram[ 0xF105 ]--){
comp[ WRAM(0x00) ] = comp[WRAM(0x12)];
WRAM(0x00) += 1;
WRAM(0x12) += 1;
}
}
// Shift and adjust Test BYTE
ram[ 0xF106 ] <<= 1;
}
}
}
// Store the data to the file
fwrite(comp, 1, WRAM(0x00), f2);
return 0;
}
// Recompress the ROM data
char Recompress(unsigned int value){
unsigned int cmpMax, cmpMaxPosi, cmpMost;
char *bit_ptr;
// Open the file(s)
f1 = fopen(fil1, "rb+");
if(!f1){
printf("Error opening DESTINATION file...");
return -1;
}
// Make the file name
sprintf(fil2, "GD_%03d.dat", value);
f2 = fopen(fil2, "rb");
if(!f2){
printf("Error opening SOURCE file...");
return -1;
}
// Print it
printf("Now inserting... %s", fil2);
// Load to the pointer data [offset]
fseek(f1, Snes2Pc(0xE674 + value), SEEK_SET);
iOffset = fgetc(f1);
iOffset <<= 16;
fseek(f1, Snes2Pc(0xE724 + value), SEEK_SET);
WRAM(0x14) = fgetc(f1);
// Y index into pointer table
WRAM(0x14) <<= 1;
// Set the ROM address conversion
fseek(f1, Snes2Pc(iOffset + (0x8000 + WRAM(0x14))), SEEK_SET);
fread(&ram[0x14], 1, 2, f1);
iOffset += (WRAM(0x14) + 0x8000);
iOffset = Snes2Pc(iOffset);
fseek(f1, iOffset, SEEK_SET);
// Init start of compresion buffer
WRAM(0x00) = 0;
WRAM(0x02) = 0;
// Where the decompressed data goes.
comp = &ram[0x10000];
buffer = &ram[0x20000];
// bit_ptr is the position of each control code that is compiled for each 8-bit stream of data compressed or not.
bit_ptr = &buffer[ WRAM(0x02) ];
// where data is stored for the ROM
WRAM(0x02) += 1;
// Load the data size
WRAM(0xF100) = FileSize(f2) & 0xFFFF;
// I don't like -1 values returned to me
if(WRAM(0xF100) == 0xFFFF) return -1;
// Ok, now load up the data to compress
// Clear the data and ROM buffers
memset(comp, 0, 0xFFFF);
memset(buffer, 0, 0xFFFF);
// load up the data
fread(comp, 1, WRAM(0xF100), f2);
fclose(f2);
// Loop through the routine
while (WRAM(0x00) < WRAM(0xF100)){
// counter
ram[ 0xF104 ] = 8;
// Do the compression testing!
// Loop through 8 BITS
while(ram[ 0xF104 ]--){
// Test for compression capabilities!
if(WRAM(0x00) >= 0xFFF){
cmpMax = (WRAM(0x00) - 0xFFF);
}
else{
cmpMax = 0;
}
// The best possible match found
cmpMost = 0;
// Test for compression
// If you have ever done a "search" for a data string match in a hex editor or what have you, this is basically the same thing
while(cmpMax < WRAM(0x00)){
if(comp[cmpMax] == comp[WRAM(0x00)]){
WRAM(0x10) = 0;
// Loop through the matches
while(comp[cmpMax + WRAM(0x10)] == comp[WRAM(0x00) + WRAM(0x10)] && WRAM(0x10) < 18 && (WRAM(0x00) + WRAM(0x10)) < WRAM(0xF100)){
WRAM(0x10) += 1;
}
// Test for best finds
if(WRAM(0x10) > cmpMost){
cmpMost = WRAM(0x10);
cmpMaxPosi = cmpMax;
// Do we already have a max find?
if(cmpMost >= 18){
cmpMost = 18;
break;
}
}
}
// Increment test position
cmpMax++;
}
// Compress what we have or store Static data
if(cmpMost > 2){
// We can compress this data!
// It takes 2 bytes to form a compression pointer
// Anything 2 bytes or less is a waste of time compressing
// Calculate offsets!
WRAM(0x04) = cmpMaxPosi - WRAM(0x00);
WRAM(0x04) ^= 0xFFFF;
ram[0x06] = WRAM(0x04) >> 8;
ram[0x06] = (ram[0x06] << 4) + (cmpMost - 3);
WRAM(0x04) &= 0xFF;
buffer[ WRAM(0x02) ] = ram[ 0x06 ];
WRAM(0x02) += 1;
buffer[ WRAM(0x02) ] = WRAM(0x04);
WRAM(0x02) += 1;
// Get past the compressed data
WRAM(0x00) += cmpMost;
// Adjust the control code
*bit_ptr <<= 1;
*bit_ptr |= 1;
}
else{
// It's static data...
buffer[ WRAM(0x02) ] = comp[ WRAM(0x00) ];
WRAM(0x02) += 1;
WRAM(0x00) += 1;
// Adjust the control code
*bit_ptr <<= 1;
}
}
// Set a new control code location
bit_ptr = &buffer[ WRAM(0x02) ];
WRAM(0x02) += 1;
}
// Store the data to the file
// Test to see if it was worth compressing!
// If the RAW size is better than the compressed size
if(WRAM(0x02) > WRAM(0xF100)){
// Store all static data
// Change this value to a variable used per data block
if((iOffset + WRAM(0x02)) <= 0xAA8F2){
fseek(f1, iOffset, SEEK_SET); // Start of data
fwrite(&ram[0xF100], 1, 2, f1); // Store data size
fputc(0xFF, f1); // store RAW data flag
fwrite(comp, 1, WRAM(0xF100), f1); // store RAW data
}
else{
printf("Error: Data size greater than ROM allows...\n Data will not be compressed!");
}
}
// Store compressed data
else{
// Change this value to a variable used per data block
if((iOffset + WRAM(0x02)) <= 0xAA8F2){
fseek(f1, iOffset, SEEK_SET); // start of the data
fwrite(&ram[0xF100], 1, 2, f1); // Store data size
fwrite(buffer, 1, WRAM(0x02), f1); // store to ROM
}
else{
printf("Error: Data size greater than ROM allows...\n Data will not be compressed!");
}
}
return 0;
}
// Load the program data Bank
long Snes2Pc(long Offset){
long snesOffset;
// SNES to ROM
snesOffset = (((Offset | 0x800000) - 0x800000) & 0xFF0000) >> 1;
snesOffset += ((Offset & 0xFFFF) - 0x8000) + iHeader;
return snesOffset;
}
// Get the length of the file
long FileSize(FILE *tf){
long fileSize;
long offset;
// Test file
if(!tf) return -1;
// Get orinal offset
offset = ftell(tf);
// Get size
fseek(tf, 0, SEEK_END);
fileSize = ftell(tf);
fseek(tf, offset, SEEK_SET);
return fileSize;
}
GD_Leen_Compression_Original.c
Compression scheme research and work done by Bongo`.