usaa24/sk1/compressor.c

200 lines
6.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 {
unsigned char symbol;
size_t frequency;
} HuffmanSymbol;
typedef struct Node {
HuffmanSymbol symbol;
struct Node *left, *right;
} Node;
// Функція для порівняння вузлів для використання в черзі
int compare_nodes(const void *a, const void *b) {
return ((Node*)a)->symbol.frequency - ((Node*)b)->symbol.frequency;
}
// Створення дерева Хаффмана
Node* create_huffman_tree(HuffmanSymbol* symbols, size_t n) {
// Використовуємо чергу для побудови дерева Хаффмана
qsort(symbols, n, sizeof(HuffmanSymbol), compare_nodes);
// Створюємо чергу вузлів для побудови дерева
Node** queue = malloc(n * sizeof(Node*));
for (size_t i = 0; i < n; i++) {
queue[i] = malloc(sizeof(Node));
queue[i]->symbol = symbols[i];
queue[i]->left = queue[i]->right = NULL;
}
size_t queue_size = n;
// Побудова дерева Хаффмана
while (queue_size > 1) {
// Зливаємо два найменші елементи
Node* left = queue[0];
Node* right = queue[1];
Node* parent = malloc(sizeof(Node));
parent->symbol.symbol = 0; // Спільний символ
parent->symbol.frequency = left->symbol.frequency + right->symbol.frequency;
parent->left = left;
parent->right = right;
// Видаляємо перші два елементи з черги та додаємо новий
memmove(queue, queue + 2, (queue_size - 2) * sizeof(Node*));
queue[queue_size - 2] = parent;
queue_size--;
qsort(queue, queue_size, sizeof(Node*), compare_nodes);
}
Node* root = queue[0];
free(queue);
return root;
}
// Функція для стиснення з використанням дерева Хаффмана
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* buffer = malloc(file_size);
if (!buffer) {
fclose(infile);
return -1;
}
fread(buffer, 1, file_size, infile);
fclose(infile);
// Підрахунок частоти кожного байта
size_t frequencies[256] = {0};
for (size_t i = 0; i < file_size; i++) {
frequencies[buffer[i]]++;
}
HuffmanSymbol symbols[256];
size_t num_symbols = 0;
for (int i = 0; i < 256; i++) {
if (frequencies[i] > 0) {
symbols[num_symbols].symbol = (unsigned char)i;
symbols[num_symbols].frequency = frequencies[i];
num_symbols++;
}
}
Node* huffman_tree = create_huffman_tree(symbols, num_symbols);
// Тут треба реалізувати кодування та запис бітових кодів в файл
// Оскільки це складніше, я залишаю це як заготовку для подальшої реалізації
free(buffer);
return 1;
}
int decompress_1(const char* input_file_name, const char* output_file_name) {
// Реалізація декомпресії за допомогою Хаффмана буде складною
// і потребує зберігання дерев або довжини кодування кожного символу
return 0;
}