mirror of https://github.com/wwarthen/RomWBW.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
150 lines
4.6 KiB
150 lines
4.6 KiB
/* =====================================================================
|
|
* compress v1.1 - 251012 Paul de Bak, with help from Le Chat AI
|
|
*
|
|
* =====================================================================
|
|
* This RomWBW utility program will attempt to compress any file using
|
|
* a straightforward RLE approach.
|
|
*
|
|
* The output file will have the name of the input file with ".cmp"
|
|
* appended.
|
|
*
|
|
* =====================================================================
|
|
* To compile in Linux (or Windows using MinGW):
|
|
*
|
|
* gcc -o compress_upd(.exe) compress_upd.c
|
|
*
|
|
* =====================================================================
|
|
* Usage: compress(.exe) <input file>
|
|
*
|
|
* If compression is successful, an ouput file is created with the name
|
|
* of the input file + ".cmp".
|
|
*
|
|
* =====================================================================
|
|
* Program exit codes
|
|
* 0: Success. An output file is created.
|
|
* 1: Incorrect usage or input file not found.
|
|
* 2: Unable to create output file.
|
|
*
|
|
* =====================================================================
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
//#include <string.h>
|
|
//#include <libgen.h> // For basename function
|
|
|
|
#define VERSION "compress v1.1 - 251012 Paul de Bak & Le Chat AI"
|
|
#define MAX_COUNT 0x100 // Maximum count is 256
|
|
#define BUFFER_SIZE 65536
|
|
|
|
size_t calculate_original_size(FILE *input) {
|
|
fseek(input, 0, SEEK_END);
|
|
return ftell(input);
|
|
}
|
|
|
|
size_t calculate_compressed_size(FILE *input) {
|
|
uint8_t buffer[BUFFER_SIZE];
|
|
size_t size, compressed_size = 0;
|
|
while ((size = fread(buffer, 1, BUFFER_SIZE, input)) > 0) {
|
|
size_t i = 0;
|
|
while (i < size) {
|
|
uint8_t byte = buffer[i];
|
|
size_t count = 1;
|
|
// Count the number of repetitions of the current byte
|
|
while (i + count < size && buffer[i + count] == byte && count < MAX_COUNT) {
|
|
count++;
|
|
}
|
|
if (count >= 2) {
|
|
compressed_size += 3; // Two bytes + count
|
|
} else {
|
|
compressed_size += 1; // Single byte
|
|
}
|
|
i += count;
|
|
}
|
|
}
|
|
return compressed_size;
|
|
}
|
|
|
|
int compress_file(FILE *input, FILE *output) {
|
|
uint8_t buffer[BUFFER_SIZE];
|
|
size_t size;
|
|
uint8_t repeat_count;
|
|
while ((size = fread(buffer, 1, BUFFER_SIZE, input)) > 0) {
|
|
size_t i = 0;
|
|
while (i < size) {
|
|
uint8_t byte = buffer[i];
|
|
size_t count = 1;
|
|
// Count the number of repetitions of the current byte
|
|
while (i + count < size && buffer[i + count] == byte && count < MAX_COUNT) {
|
|
count++;
|
|
}
|
|
if (count >= 2) {
|
|
fwrite(&byte, 1, 1, output);
|
|
fwrite(&byte, 1, 1, output);
|
|
repeat_count = count - 1;
|
|
fwrite(&repeat_count, 1, 1, output);
|
|
} else {
|
|
fwrite(&byte, 1, 1, output);
|
|
}
|
|
i += count;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int main(int argc, char *argv[]) {
|
|
char *input_filename;
|
|
long free_bytes;
|
|
FILE *input;
|
|
size_t original_size;
|
|
size_t compressed_size;
|
|
char output_filename[256];
|
|
char *base_name;
|
|
char *dot;
|
|
FILE *output;
|
|
|
|
printf("\n%s\n\n", VERSION);
|
|
|
|
if (argc != 2) {
|
|
printf("Usage: %s <input file>\n", argv[0]);
|
|
printf("Example: %s RCZ80_ez512_std.upd\n", argv[0]);
|
|
return 1; // Error: Incorrect usage
|
|
}
|
|
|
|
input_filename = argv[1];
|
|
input = fopen(input_filename, "rb");
|
|
if (!input) {
|
|
fprintf(stderr, "Error: Input file '%s' not found\n", input_filename);
|
|
return 1; // Error: Input file not found
|
|
}
|
|
|
|
// Calculate the original file size
|
|
original_size = calculate_original_size(input);
|
|
rewind(input);
|
|
|
|
// Calculate the compressed size first
|
|
compressed_size = calculate_compressed_size(input);
|
|
rewind(input);
|
|
|
|
// Construct the output filename
|
|
snprintf(output_filename, sizeof(output_filename), "%s.cmp", input_filename);
|
|
|
|
printf("Compressing %s to %s...\n", input_filename, output_filename);
|
|
|
|
output = fopen(output_filename, "wb");
|
|
if (!output) {
|
|
fprintf(stderr, "Error: Unable to create output file '%s'\n", output_filename);
|
|
fclose(input);
|
|
return 2; // Error: Unable to create output file
|
|
}
|
|
|
|
compress_file(input, output);
|
|
|
|
fclose(input);
|
|
fclose(output);
|
|
|
|
printf("Compressed from %lu bytes to %lu bytes (%lu%% reduction)\n", original_size, compressed_size, (((original_size - compressed_size) * 100) / original_size));
|
|
|
|
return 0; // Success
|
|
}
|
|
|