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.c

GD_Leen_Compression_Original.c

Compression scheme research and work done by Bongo`.