usaa24/sk1/compressor.c

251 lines
7.6 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#define WINDOW_SIZE 4096
#define LOOKAHEAD_BUFFER_SIZE 18
typedef struct {
uint16_t offset;
uint8_t length;
uint8_t next_char;
} LZ77Triple;
int lz77_compress(const char *input_filename, const char *output_filename) {
// Open the input file in binary read mode
FILE *input_file = fopen(input_filename, "rb");
if (!input_file) {
perror("Error opening input file");
return -1;
}
// Open the output file in binary write mode
FILE *output_file = fopen(output_filename, "wb");
if (!output_file) {
perror("Error opening output file");
fclose(input_file);
return -2;
}
uint8_t *window = (uint8_t *)malloc(WINDOW_SIZE + LOOKAHEAD_BUFFER_SIZE);
if (!window) {
perror("Memory allocation failed");
fclose(input_file);
fclose(output_file);
return -3;
}
size_t window_start = 0;
size_t lookahead_start = 0;
size_t bytes_read;
// Initialize the window with data from the input file
bytes_read = fread(window + WINDOW_SIZE, 1, LOOKAHEAD_BUFFER_SIZE, input_file);
while (bytes_read > 0) {
size_t best_match_offset = 0;
size_t best_match_length = 0;
// Search for the best match within the sliding window
for (size_t i = window_start; i < WINDOW_SIZE + lookahead_start; i++) {
size_t match_length = 0;
while (match_length < bytes_read &&
window[i + match_length] == window[WINDOW_SIZE + match_length]) {
match_length++;
if (match_length >= LOOKAHEAD_BUFFER_SIZE) {
break;
}
}
if (match_length > best_match_length) {
best_match_length = match_length;
best_match_offset = WINDOW_SIZE + lookahead_start - i;
}
}
// Create a triple and write it to the output file
LZ77Triple triple;
triple.offset = (uint16_t)best_match_offset;
triple.length = (uint8_t)best_match_length;
triple.next_char = window[WINDOW_SIZE + best_match_length];
// Write the triple to the output file
fwrite(&triple, sizeof(LZ77Triple), 1, output_file);
// Slide the window
window_start = (window_start + best_match_length + 1) % WINDOW_SIZE;
lookahead_start = (lookahead_start + best_match_length + 1) % LOOKAHEAD_BUFFER_SIZE;
// Read new byte into the lookahead buffer
bytes_read = fread(window + WINDOW_SIZE, 1, LOOKAHEAD_BUFFER_SIZE - lookahead_start, input_file);
}
// Cleanup and close files
fclose(input_file);
fclose(output_file);
free(window);
return 0;
}
int lz77_decompress(const char *input_filename, const char *output_filename) {
FILE *input = fopen(input_filename, "rb");
FILE *output = fopen(output_filename, "wb");
if (!input || !output) {
if (input) fclose(input);
if (output) fclose(output);
return -1; // Помилка відкриття файлу
}
size_t buffer_size = 4096; // Максимальний розмір вікна
unsigned char *window = malloc(buffer_size);
size_t window_size = 0; // Розмір заповненої частини вікна
size_t window_pos = 0; // Поточна позиція в межах вікна
if (!window) {
fclose(input);
fclose(output);
return -1; // Помилка пам'яті
}
while (!feof(input)) {
unsigned char flag;
if (fread(&flag, 1, 1, input) != 1) break;
for (int i = 0; i < 8 && !feof(input); i++) {
if (flag & (1 << i)) { // Літеральний символ
unsigned char literal;
if (fread(&literal, 1, 1, input) != 1) break;
fputc(literal, output);
// Додати символ у вікно
window[window_pos] = literal;
window_pos = (window_pos + 1) % buffer_size;
if (window_size < buffer_size) window_size++;
} else { // Посилання
unsigned short offset_length;
if (fread(&offset_length, 2, 1, input) != 1) break;
size_t offset = offset_length >> 4;
size_t length = (offset_length & 0xF) + 3;
for (size_t j = 0; j < length; j++) {
unsigned char byte = window[(window_pos - offset + buffer_size) % buffer_size];
fputc(byte, output);
// Додати байт у вікно
window[window_pos] = byte;
window_pos = (window_pos + 1) % buffer_size;
if (window_size < buffer_size) window_size++;
}
}
}
}
free(window);
fclose(input);
fclose(output);
return 0; // Успішна декомпресія
}
void rle_compress(const char *input_filename, const char *output_filename) {
FILE *input_file = fopen(input_filename, "rb");
if (!input_file) {
perror("Error opening input file");
return;
}
FILE *output_file = fopen(output_filename, "wb");
if (!output_file) {
perror("Error opening output file");
fclose(input_file);
return;
}
uint8_t current_byte, previous_byte;
uint8_t count = 1;
if (fread(&previous_byte, 1, 1, input_file) != 1) {
printf("Input file is empty or read error occurred.\n");
fclose(input_file);
fclose(output_file);
return;
}
while (fread(&current_byte, 1, 1, input_file) == 1) {
if (current_byte == previous_byte && count < 255) {
count++;
} else {
fwrite(&previous_byte, 1, 1, output_file);
fwrite(&count, 1, 1, output_file);
printf("Writing byte: %c with count: %d\n", previous_byte, count);
previous_byte = current_byte;
count = 1;
}
}
fwrite(&previous_byte, 1, 1, output_file);
fwrite(&count, 1, 1, output_file);
printf("Writing byte: %c with count: %d\n", previous_byte, count);
fclose(input_file);
fclose(output_file);
}
int rle_decompress(const char *input_filename, const char *output_filename) {
// Open the input file in binary read mode
FILE *input_file = fopen(input_filename, "rb");
if (!input_file) {
perror("Error opening input file");
return -1;
}
// Open the output file in binary write mode
FILE *output_file = fopen(output_filename, "wb");
if (!output_file) {
perror("Error opening output file");
fclose(input_file);
return -2;
}
uint8_t byte;
uint8_t count;
size_t decompressed_size = 0;
// Read [byte, count] pairs from the input file
while (fread(&byte, 1, 1, input_file) == 1) {
if (fread(&count, 1, 1, input_file) != 1) {
// Handle malformed input file
fprintf(stderr, "Error: Malformed input file\n");
fclose(input_file);
fclose(output_file);
return -3;
}
// Write 'count' occurrences of 'byte' to the output file
for (uint8_t i = 0; i < count; i++) {
if (fwrite(&byte, 1, 1, output_file) != 1) {
perror("Error writing to output file");
fclose(input_file);
fclose(output_file);
return -4;
}
decompressed_size++;
}
}
// Clean up and close files
fclose(input_file);
fclose(output_file);
return (int)decompressed_size;
}