usaa24/sk1/compressor.c

291 lines
7.7 KiB
C
Raw Normal View History

2024-12-24 18:40:18 +00:00
#include "compressor.h"
2024-12-24 15:08:56 +00:00
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
2024-12-24 18:40:18 +00:00
// --- Алгоритм Run-Length Encoding (RLE) ---
2024-12-24 15:08:56 +00:00
2024-12-24 18:40:18 +00:00
int compress_2(const char* input_file_name, const char* output_file_name) {
FILE *infile = fopen(input_file_name, "rb");
if (!infile) {
perror("Error opening input file");
return -1;
2024-12-24 15:08:56 +00:00
}
2024-12-24 18:40:18 +00:00
FILE *outfile = fopen(output_file_name, "wb");
if (!outfile) {
perror("Error opening output file");
fclose(infile);
return -1;
2024-12-24 15:08:56 +00:00
}
2024-12-24 18:40:18 +00:00
unsigned char current_byte, previous_byte;
size_t count = 0;
2024-12-24 18:41:40 +00:00
2024-12-24 18:40:18 +00:00
if (fread(&previous_byte, 1, 1, infile) != 1) {
fclose(infile);
fclose(outfile);
return 0; // Порожній файл
}
2024-12-24 15:08:56 +00:00
2024-12-24 20:02:31 +00:00
count = 1;
2024-12-24 15:08:56 +00:00
2024-12-24 18:40:18 +00:00
while (fread(&current_byte, 1, 1, infile) == 1) {
if (current_byte == previous_byte && count < 255) {
2024-12-24 20:02:31 +00:00
count++;
2024-12-24 18:40:18 +00:00
} else {
fwrite(&previous_byte, 1, 1, outfile);
fwrite(&count, 1, 1, outfile);
previous_byte = current_byte;
count = 1;
}
2024-12-24 15:08:56 +00:00
}
2024-12-24 18:40:18 +00:00
fwrite(&previous_byte, 1, 1, outfile);
fwrite(&count, 1, 1, outfile);
2024-12-24 15:08:56 +00:00
2024-12-24 18:40:18 +00:00
fclose(infile);
fclose(outfile);
2024-12-24 20:02:31 +00:00
return 1;
2024-12-24 15:08:56 +00:00
}
2024-12-24 18:40:18 +00:00
int decompress_2(const char* input_file_name, const char* output_file_name) {
FILE *infile = fopen(input_file_name, "rb");
if (!infile) {
perror("Error opening input file");
return -1;
2024-12-24 15:08:56 +00:00
}
2024-12-24 18:40:18 +00:00
FILE *outfile = fopen(output_file_name, "wb");
if (!outfile) {
perror("Error opening output file");
fclose(infile);
return -1;
2024-12-24 15:08:56 +00:00
}
2024-12-24 18:40:18 +00:00
unsigned char current_byte;
2024-12-24 20:02:31 +00:00
unsigned char count;
2024-12-24 15:08:56 +00:00
2024-12-24 18:40:18 +00:00
while (fread(&current_byte, 1, 1, infile) == 1) {
2024-12-24 20:02:31 +00:00
if (fread(&count, 1, 1, infile) != 1) {
perror("Malformed input file");
fclose(infile);
fclose(outfile);
return -1;
}
2024-12-24 18:40:18 +00:00
for (size_t i = 0; i < count; i++) {
fwrite(&current_byte, 1, 1, outfile);
2024-12-24 15:08:56 +00:00
}
}
2024-12-24 18:40:18 +00:00
fclose(infile);
fclose(outfile);
2024-12-24 15:08:56 +00:00
2024-12-24 20:02:31 +00:00
return 1;
2024-12-24 18:40:18 +00:00
}
2024-12-24 15:08:56 +00:00
2024-12-24 18:40:18 +00:00
// --- Алгоритм Хаффмана (Huffman Coding) ---
2024-12-24 15:08:56 +00:00
2024-12-24 18:41:40 +00:00
typedef struct Node {
2024-12-24 18:40:18 +00:00
unsigned char symbol;
size_t frequency;
struct Node *left, *right;
} Node;
2024-12-24 18:41:40 +00:00
typedef struct {
unsigned char symbol;
char *code;
} HuffmanCode;
2024-12-24 18:40:18 +00:00
int compare_nodes(const void *a, const void *b) {
2024-12-24 20:02:31 +00:00
return (*(Node**)a)->frequency - (*(Node**)b)->frequency;
2024-12-24 15:08:56 +00:00
}
2024-12-24 18:41:40 +00:00
Node* create_huffman_tree(unsigned char *data, size_t size) {
size_t freq[256] = {0};
for (size_t i = 0; i < size; i++) {
freq[data[i]]++;
}
2024-12-24 18:40:18 +00:00
2024-12-24 18:41:40 +00:00
Node *nodes[256];
size_t node_count = 0;
for (int i = 0; i < 256; i++) {
if (freq[i] > 0) {
nodes[node_count] = malloc(sizeof(Node));
2024-12-24 20:02:31 +00:00
if (!nodes[node_count]) {
perror("Memory allocation failed");
return NULL;
}
2024-12-24 18:41:40 +00:00
nodes[node_count]->symbol = (unsigned char)i;
nodes[node_count]->frequency = freq[i];
nodes[node_count]->left = nodes[node_count]->right = NULL;
node_count++;
}
2024-12-24 15:08:56 +00:00
}
2024-12-24 18:41:40 +00:00
while (node_count > 1) {
2024-12-24 20:02:31 +00:00
qsort(nodes, node_count, sizeof(Node*), compare_nodes);
2024-12-24 18:41:40 +00:00
Node* left = nodes[0];
Node* right = nodes[1];
2024-12-24 15:08:56 +00:00
2024-12-24 18:40:18 +00:00
Node* parent = malloc(sizeof(Node));
2024-12-24 20:02:31 +00:00
if (!parent) {
perror("Memory allocation failed");
return NULL;
}
2024-12-24 18:41:40 +00:00
parent->symbol = 0;
parent->frequency = left->frequency + right->frequency;
2024-12-24 18:40:18 +00:00
parent->left = left;
parent->right = right;
2024-12-24 18:41:40 +00:00
memmove(nodes, nodes + 2, (node_count - 2) * sizeof(Node*));
nodes[node_count - 2] = parent;
node_count--;
2024-12-24 15:08:56 +00:00
}
2024-12-24 20:02:31 +00:00
return nodes[0];
2024-12-24 18:41:40 +00:00
}
void generate_huffman_codes(Node* root, HuffmanCode* codes, char* current_code, int depth) {
if (!root) return;
2024-12-24 18:40:18 +00:00
2024-12-24 18:41:40 +00:00
if (root->left == NULL && root->right == NULL) {
current_code[depth] = '\0';
codes[root->symbol].symbol = root->symbol;
codes[root->symbol].code = strdup(current_code);
2024-12-24 20:02:31 +00:00
return;
2024-12-24 18:41:40 +00:00
}
current_code[depth] = '0';
generate_huffman_codes(root->left, codes, current_code, depth + 1);
2024-12-24 20:02:31 +00:00
2024-12-24 18:41:40 +00:00
current_code[depth] = '1';
generate_huffman_codes(root->right, codes, current_code, depth + 1);
2024-12-24 15:08:56 +00:00
}
2024-12-24 20:02:31 +00:00
void serialize_huffman_tree(Node* root, FILE* outfile) {
if (!root) return;
if (root->left == NULL && root->right == NULL) {
fputc('L', outfile);
fputc(root->symbol, outfile);
} else {
fputc('I', outfile);
serialize_huffman_tree(root->left, outfile);
serialize_huffman_tree(root->right, outfile);
}
}
Node* rebuild_huffman_tree(unsigned char* tree_data, size_t size) {
(void)size; // Позначаємо параметр як тимчасово невикористаний
size_t index = 0;
Node* build_tree_recursively(unsigned char* data, size_t* index) {
if (data[*index] == 'L') { // Лист (Leaf)
(*index)++;
Node* leaf = malloc(sizeof(Node));
if (!leaf) {
perror("Memory allocation failed");
return NULL;
}
leaf->symbol = data[*index];
leaf->frequency = 0; // частота не потрібна для декомпресії
leaf->left = leaf->right = NULL;
(*index)++;
return leaf;
} else if (data[*index] == 'I') { // Вузол (Internal)
(*index)++;
Node* internal = malloc(sizeof(Node));
if (!internal) {
perror("Memory allocation failed");
return NULL;
}
internal->symbol = 0; // внутрішні вузли не мають символів
internal->frequency = 0;
internal->left = build_tree_recursively(data, index);
internal->right = build_tree_recursively(data, index);
return internal;
}
return NULL;
}
return build_tree_recursively(tree_data, &index);
}
void free_huffman_tree(Node* root) {
if (!root) return;
free_huffman_tree(root->left);
free_huffman_tree(root->right);
free(root);
}
2024-12-24 18:40:18 +00:00
int compress_1(const char* input_file_name, const char* output_file_name) {
FILE *infile = fopen(input_file_name, "rb");
if (!infile) {
perror("Error opening input file");
return -1;
2024-12-24 15:08:56 +00:00
}
2024-12-24 18:40:18 +00:00
fseek(infile, 0, SEEK_END);
size_t file_size = ftell(infile);
fseek(infile, 0, SEEK_SET);
2024-12-24 15:08:56 +00:00
2024-12-24 18:41:40 +00:00
unsigned char* data = malloc(file_size);
if (!data) {
2024-12-24 18:40:18 +00:00
fclose(infile);
2024-12-24 20:02:31 +00:00
perror("Memory allocation failed");
2024-12-24 18:40:18 +00:00
return -1;
2024-12-24 15:08:56 +00:00
}
2024-12-24 18:41:40 +00:00
fread(data, 1, file_size, infile);
2024-12-24 18:40:18 +00:00
fclose(infile);
2024-12-24 15:08:56 +00:00
2024-12-24 18:41:40 +00:00
Node* root = create_huffman_tree(data, file_size);
2024-12-24 20:02:31 +00:00
if (!root) {
free(data);
return -1;
2024-12-24 15:08:56 +00:00
}
2024-12-24 20:02:31 +00:00
HuffmanCode codes[256] = {0};
2024-12-24 18:41:40 +00:00
char current_code[256];
generate_huffman_codes(root, codes, current_code, 0);
2024-12-24 15:08:56 +00:00
2024-12-24 18:41:40 +00:00
FILE *outfile = fopen(output_file_name, "wb");
if (!outfile) {
free(data);
2024-12-24 20:02:31 +00:00
free_huffman_tree(root);
2024-12-24 18:41:40 +00:00
return -1;
2024-12-24 15:08:56 +00:00
}
2024-12-24 20:02:31 +00:00
serialize_huffman_tree(root, outfile);
2024-12-24 18:41:40 +00:00
for (size_t i = 0; i < file_size; i++) {
2024-12-24 20:02:31 +00:00
const char* code = codes[data[i]].code;
2024-12-24 18:41:40 +00:00
for (size_t j = 0; code[j] != '\0'; j++) {
2024-12-24 20:02:31 +00:00
fputc(code[j], outfile);
2024-12-24 18:41:40 +00:00
}
}
2024-12-24 18:40:18 +00:00
2024-12-24 18:41:40 +00:00
fclose(outfile);
free(data);
2024-12-24 20:02:31 +00:00
free_huffman_tree(root);
2024-12-24 18:40:18 +00:00
2024-12-24 20:02:31 +00:00
for (int i = 0; i < 256; i++) {
free(codes[i].code);
2024-12-24 18:52:32 +00:00
}
2024-12-24 20:02:31 +00:00
return 1;
2024-12-24 15:08:56 +00:00
}
2024-12-24 18:52:32 +00:00
2024-12-24 20:02:31 +00:00
// Декомпресія (приклад потребує уточнень залежно від специфіки формату)
int decompress_1(const char* input_file_name, const char* output_file_name) {
(void)input_file_name;
(void)output_file_name;
return -1; // Поки що не реалізовано.
}