251 lines
7.1 KiB
C
251 lines
7.1 KiB
C
#include "compressor.h"
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
|
||
// --- Алгоритм Run-Length Encoding (RLE) ---
|
||
|
||
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;
|
||
}
|
||
|
||
FILE *outfile = fopen(output_file_name, "wb");
|
||
if (!outfile) {
|
||
perror("Error opening output file");
|
||
fclose(infile);
|
||
return -1;
|
||
}
|
||
|
||
unsigned char current_byte, previous_byte;
|
||
size_t count = 0;
|
||
|
||
// Читаємо перший байт
|
||
if (fread(&previous_byte, 1, 1, infile) != 1) {
|
||
fclose(infile);
|
||
fclose(outfile);
|
||
return 0; // Порожній файл
|
||
}
|
||
|
||
count = 1; // Ініціалізуємо лічильник
|
||
|
||
// Читаємо залишок файлу
|
||
while (fread(¤t_byte, 1, 1, infile) == 1) {
|
||
if (current_byte == previous_byte && count < 255) {
|
||
count++; // Збільшуємо лічильник
|
||
} else {
|
||
// Записуємо попередній символ і його кількість
|
||
fwrite(&previous_byte, 1, 1, outfile);
|
||
fwrite(&count, 1, 1, outfile);
|
||
previous_byte = current_byte;
|
||
count = 1;
|
||
}
|
||
}
|
||
|
||
// Записуємо останній символ
|
||
fwrite(&previous_byte, 1, 1, outfile);
|
||
fwrite(&count, 1, 1, outfile);
|
||
|
||
fclose(infile);
|
||
fclose(outfile);
|
||
|
||
return 1; // Повертаємо успішний результат
|
||
}
|
||
|
||
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;
|
||
}
|
||
|
||
FILE *outfile = fopen(output_file_name, "wb");
|
||
if (!outfile) {
|
||
perror("Error opening output file");
|
||
fclose(infile);
|
||
return -1;
|
||
}
|
||
|
||
unsigned char current_byte;
|
||
size_t count;
|
||
|
||
// Декомпресія файлу
|
||
while (fread(¤t_byte, 1, 1, infile) == 1) {
|
||
fread(&count, 1, 1, infile);
|
||
for (size_t i = 0; i < count; i++) {
|
||
fwrite(¤t_byte, 1, 1, outfile);
|
||
}
|
||
}
|
||
|
||
fclose(infile);
|
||
fclose(outfile);
|
||
|
||
return 1; // Повертаємо успішний результат
|
||
}
|
||
|
||
|
||
// --- Алгоритм Хаффмана (Huffman Coding) ---
|
||
|
||
typedef struct Node {
|
||
unsigned char symbol;
|
||
size_t frequency;
|
||
struct Node *left, *right;
|
||
} Node;
|
||
|
||
// Структура для кодів Хаффмана
|
||
typedef struct {
|
||
unsigned char symbol;
|
||
char *code;
|
||
} HuffmanCode;
|
||
|
||
// Функція для порівняння вузлів для використання в черзі
|
||
int compare_nodes(const void *a, const void *b) {
|
||
return ((Node*)a)->frequency - ((Node*)b)->frequency;
|
||
}
|
||
|
||
// Створення дерева Хаффмана
|
||
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]]++;
|
||
}
|
||
|
||
// Створюємо список вузлів
|
||
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));
|
||
nodes[node_count]->symbol = (unsigned char)i;
|
||
nodes[node_count]->frequency = freq[i];
|
||
nodes[node_count]->left = nodes[node_count]->right = NULL;
|
||
node_count++;
|
||
}
|
||
}
|
||
|
||
// Сортуємо вузли по частоті
|
||
qsort(nodes, node_count, sizeof(Node*), compare_nodes);
|
||
|
||
// Побудова дерева
|
||
while (node_count > 1) {
|
||
Node* left = nodes[0];
|
||
Node* right = nodes[1];
|
||
|
||
Node* parent = malloc(sizeof(Node));
|
||
parent->symbol = 0;
|
||
parent->frequency = left->frequency + right->frequency;
|
||
parent->left = left;
|
||
parent->right = right;
|
||
|
||
// Зміщуємо вузли в черзі
|
||
memmove(nodes, nodes + 2, (node_count - 2) * sizeof(Node*));
|
||
nodes[node_count - 2] = parent;
|
||
node_count--;
|
||
|
||
qsort(nodes, node_count, sizeof(Node*), compare_nodes);
|
||
}
|
||
|
||
return nodes[0]; // Повертаємо корінь дерева
|
||
}
|
||
|
||
// Функція для рекурсивного запису бітових кодів з дерева Хаффмана
|
||
void generate_huffman_codes(Node* root, HuffmanCode* codes, char* current_code, int depth) {
|
||
if (!root) return;
|
||
|
||
if (root->left == NULL && root->right == NULL) {
|
||
current_code[depth] = '\0';
|
||
codes[root->symbol].symbol = root->symbol;
|
||
codes[root->symbol].code = strdup(current_code);
|
||
}
|
||
|
||
current_code[depth] = '0';
|
||
generate_huffman_codes(root->left, codes, current_code, depth + 1);
|
||
|
||
current_code[depth] = '1';
|
||
generate_huffman_codes(root->right, codes, current_code, depth + 1);
|
||
}
|
||
|
||
// Функція для стиснення за допомогою Хаффмана
|
||
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;
|
||
}
|
||
|
||
fseek(infile, 0, SEEK_END);
|
||
size_t file_size = ftell(infile);
|
||
fseek(infile, 0, SEEK_SET);
|
||
|
||
unsigned char* data = malloc(file_size);
|
||
if (!data) {
|
||
fclose(infile);
|
||
return -1;
|
||
}
|
||
|
||
fread(data, 1, file_size, infile);
|
||
fclose(infile);
|
||
|
||
// Створюємо дерево Хаффмана
|
||
Node* root = create_huffman_tree(data, file_size);
|
||
|
||
// Генерація кодів Хаффмана
|
||
HuffmanCode codes[256];
|
||
for (int i = 0; i < 256; i++) {
|
||
codes[i].code = NULL;
|
||
}
|
||
|
||
char current_code[256];
|
||
generate_huffman_codes(root, codes, current_code, 0);
|
||
|
||
// Стиснення даних
|
||
FILE *outfile = fopen(output_file_name, "wb");
|
||
if (!outfile) {
|
||
free(data);
|
||
return -1;
|
||
}
|
||
|
||
for (size_t i = 0; i < file_size; i++) {
|
||
unsigned char symbol = data[i];
|
||
const char* code = codes[symbol].code;
|
||
for (size_t j = 0; code[j] != '\0'; j++) {
|
||
// Записуємо біт в файл
|
||
fputc(code[j] == '1' ? 1 : 0, outfile);
|
||
}
|
||
}
|
||
|
||
fclose(outfile);
|
||
free(data);
|
||
|
||
return 1; // Повертаємо успішний результат
|
||
}
|
||
|
||
// Функція для декомпресії за допомогою Хаффмана
|
||
int decompress_1(const char* input_file_name, const char* output_file_name) {
|
||
FILE* input = fopen(input_file_name, "rb");
|
||
if (!input) return -1;
|
||
|
||
// Načítanie kódovacej tabuľky a ďalších informácií
|
||
// (toto bude závisieť od vašej implementácie, kde ukladáte tieto informácie)
|
||
HuffmanTree* tree = load_huffman_tree(input);
|
||
if (!tree) return -1;
|
||
|
||
FILE* output = fopen(output_file_name, "wb");
|
||
if (!output) {
|
||
fclose(input);
|
||
return -1;
|
||
}
|
||
|
||
// Dekódovanie dát a zapisovanie do výstupného súboru
|
||
decode_huffman(input, output, tree);
|
||
|
||
fclose(input);
|
||
fclose(output);
|
||
|
||
return 0;
|
||
}
|
||
|