usaa24/sk1/compressor.c

251 lines
7.1 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 "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(&current_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(&current_byte, 1, 1, infile) == 1) {
fread(&count, 1, 1, infile);
for (size_t i = 0; i < count; i++) {
fwrite(&current_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;
}