/* * LZSS level compressor * * This wasn't the main compressor after a while, so this might not be * compatible with the latest release of GEMINI. But it's the core code for * compressing data, used in the level editor. */ #include #include #include #define MAX_SIZE (96*16/8) typedef unsigned char byte; typedef unsigned short word; FILE *file; int fileSize; byte text[65536], original[65536], buffer[65536]; int originalPos, bufferPos, searchPos, pos, len; /* * Clean up the text-file content */ char textToOriginal() { int i, j, hex, digit; i = 0; j = 0; do { hex = 0; while ((text[i] < '0' || text[i] > '9') && text[i] != '$') i++; if (text[i] == '$') { hex = 1; i++; } original[j] = 0; if (hex) { do { digit = 0; if (text[i] >= '0' && text[i] <= '9') { digit = 1; original[j] = (original[j] << 4) + text[i] - '0'; } if (text[i] >= 'A' && text[i] <= 'F') { digit = 1; original[j] = (original[j] << 4) + (text[i] - 'A' + 10); } if (text[i] >= 'a' && text[i] <= 'f') { digit = 1; original[j] = (original[j] << 4) + (text[i] - 'a' + 10); } i++; } while (digit); } else while (text[i] >= '0' && text[i] <= '9') { original[j] = original[j] * 10 + text[i] - '0'; i++; } j++; } while (j < MAX_SIZE && i < fileSize); return (i < fileSize); } /* * Match the bytes after searchPos to the bytes after originalPos */ void match() { int span, ofs; span = originalPos - searchPos; if (originalPos + span >= MAX_SIZE) span = MAX_SIZE - originalPos; do { ofs = 0; do { if (!memcmp(original + searchPos + ofs, original + originalPos, span)) { pos = originalPos - (searchPos + ofs); len = span; return; } ofs++; } while (ofs + span < 129 && ofs + span < originalPos); span--; } while (span >= 2); pos = 0; len = 0; } int main(int argc, char **argv) { int patterns, rawCopies, i; /* Read input file */ if (argc < 2) { puts("No file input."); return 0; } if (!(file = fopen(argv[1], "rb"))) { puts("Input file not found."); return 0; } fileSize = fread(text, 1, 65536, file); if (fileSize < MAX_SIZE) { fclose(file); puts("File does not contain enough data."); return 0; } fclose(file); if (!textToOriginal()) { puts("Not enough data to compress."); return 0; } puts("\nLoaded data info:"); printf("\tSize: %d bytes\n", MAX_SIZE); /* Compress */ patterns = 0; rawCopies = 0; buffer[0] = original[0]; buffer[1] = original[1]; originalPos = 2; bufferPos = 2; do { searchPos = originalPos - 129; if (searchPos < 0) searchPos = 0; match(); if (len >= 2) { buffer[bufferPos] = (pos - 2) | 0x80; bufferPos++; buffer[bufferPos] = len; bufferPos++; originalPos += len; patterns++; } else { buffer[bufferPos] = 0; bufferPos++; buffer[bufferPos] = original[originalPos]; bufferPos++; originalPos++; rawCopies++; } } while (originalPos < MAX_SIZE); puts("Compressed data info:"); printf("\tSize: %d bytes\n", bufferPos); printf("\tRatio: %6.1f%\n", 100.0f * bufferPos / MAX_SIZE); printf("\tPattern matches: %d\n", patterns); printf("\tNo matches: %d\n", rawCopies); /* Write data */ if (!(file = fopen("out", "wb"))) { puts("Couldn't write compressed data."); return 0; } fprintf(file, "\t.dw\t%d", bufferPos); for (i = 0; i < bufferPos; i++) { if (!(i & 15)) fprintf(file, "\n\t.db\t"); fprintf(file, "$%02X", buffer[i]); if ((i & 15) < 15 && i < bufferPos - 1) fprintf(file, ","); } fclose(file); puts("Compressed data successfully."); original[0] = buffer[0]; original[1] = buffer[1]; originalPos = 2; bufferPos = 2; do { if ((buffer[bufferPos] & 0x80)) { patterns = buffer[bufferPos] & 0x7F; bufferPos++; rawCopies = buffer[bufferPos]; bufferPos++; do { original[originalPos] = original[originalPos - patterns - 2]; originalPos++; rawCopies--; } while (rawCopies); } else { bufferPos++; original[originalPos] = buffer[bufferPos]; originalPos++; bufferPos++; } } while (originalPos < MAX_SIZE); for (i = 0; i < MAX_SIZE; i++) printf("%d ", original[i]); return 0; }