From eba5bf1f39d9cd9ac18be616a03255f4e9ce0732 Mon Sep 17 00:00:00 2001 From: Yurii Chechur Date: Tue, 24 Dec 2024 20:02:31 +0000 Subject: [PATCH] Update sk1/compressor.c --- sk1/compressor.c | 182 +++++++++++++++++++++++++++++------------------ 1 file changed, 111 insertions(+), 71 deletions(-) diff --git a/sk1/compressor.c b/sk1/compressor.c index 470c4bb..75464e4 100644 --- a/sk1/compressor.c +++ b/sk1/compressor.c @@ -22,21 +22,18 @@ int compress_2(const char* input_file_name, const char* output_file_name) { 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; // Ініціалізуємо лічильник + count = 1; - // Читаємо залишок файлу while (fread(¤t_byte, 1, 1, infile) == 1) { if (current_byte == previous_byte && count < 255) { - count++; // Збільшуємо лічильник + count++; } else { - // Записуємо попередній символ і його кількість fwrite(&previous_byte, 1, 1, outfile); fwrite(&count, 1, 1, outfile); previous_byte = current_byte; @@ -44,14 +41,13 @@ int compress_2(const char* input_file_name, const char* output_file_name) { } } - // Записуємо останній символ fwrite(&previous_byte, 1, 1, outfile); fwrite(&count, 1, 1, outfile); fclose(infile); fclose(outfile); - - return 1; // Повертаємо успішний результат + + return 1; } int decompress_2(const char* input_file_name, const char* output_file_name) { @@ -69,11 +65,16 @@ int decompress_2(const char* input_file_name, const char* output_file_name) { } unsigned char current_byte; - size_t count; + unsigned char count; - // Декомпресія файлу while (fread(¤t_byte, 1, 1, infile) == 1) { - fread(&count, 1, 1, infile); + if (fread(&count, 1, 1, infile) != 1) { + perror("Malformed input file"); + fclose(infile); + fclose(outfile); + return -1; + } + for (size_t i = 0; i < count; i++) { fwrite(¤t_byte, 1, 1, outfile); } @@ -82,10 +83,9 @@ int decompress_2(const char* input_file_name, const char* output_file_name) { fclose(infile); fclose(outfile); - return 1; // Повертаємо успішний результат + return 1; } - // --- Алгоритм Хаффмана (Huffman Coding) --- typedef struct Node { @@ -94,31 +94,31 @@ typedef struct Node { 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; + 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)); + if (!nodes[node_count]) { + perror("Memory allocation failed"); + return NULL; + } nodes[node_count]->symbol = (unsigned char)i; nodes[node_count]->frequency = freq[i]; nodes[node_count]->left = nodes[node_count]->right = NULL; @@ -126,32 +126,31 @@ Node* create_huffman_tree(unsigned char *data, size_t size) { } } - // Сортуємо вузли по частоті - qsort(nodes, node_count, sizeof(Node*), compare_nodes); - - // Побудова дерева while (node_count > 1) { + qsort(nodes, node_count, sizeof(Node*), compare_nodes); + Node* left = nodes[0]; Node* right = nodes[1]; Node* parent = malloc(sizeof(Node)); + if (!parent) { + perror("Memory allocation failed"); + return NULL; + } + 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]; // Повертаємо корінь дерева + return nodes[0]; } -// Функція для рекурсивного запису бітових кодів з дерева Хаффмана void generate_huffman_codes(Node* root, HuffmanCode* codes, char* current_code, int depth) { if (!root) return; @@ -159,16 +158,72 @@ void generate_huffman_codes(Node* root, HuffmanCode* codes, char* current_code, current_code[depth] = '\0'; codes[root->symbol].symbol = root->symbol; codes[root->symbol].code = strdup(current_code); + return; } 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); } -// Функція для стиснення за допомогою Хаффмана +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); +} + int compress_1(const char* input_file_name, const char* output_file_name) { FILE *infile = fopen(input_file_name, "rb"); if (!infile) { @@ -183,68 +238,53 @@ int compress_1(const char* input_file_name, const char* output_file_name) { unsigned char* data = malloc(file_size); if (!data) { fclose(infile); + perror("Memory allocation failed"); 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) { + if (!root) { free(data); return -1; } + HuffmanCode codes[256] = {0}; + char current_code[256]; + generate_huffman_codes(root, codes, current_code, 0); + + FILE *outfile = fopen(output_file_name, "wb"); + if (!outfile) { + free(data); + free_huffman_tree(root); + return -1; + } + + serialize_huffman_tree(root, outfile); + for (size_t i = 0; i < file_size; i++) { - unsigned char symbol = data[i]; - const char* code = codes[symbol].code; + const char* code = codes[data[i]].code; for (size_t j = 0; code[j] != '\0'; j++) { - // Записуємо біт в файл - fputc(code[j] == '1' ? 1 : 0, outfile); + fputc(code[j], outfile); } } fclose(outfile); free(data); + free_huffman_tree(root); - 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; + for (int i = 0; i < 256; i++) { + free(codes[i].code); } - // Dekódovanie dát a zapisovanie do výstupného súboru - decode_huffman(input, output, tree); - - fclose(input); - fclose(output); - - return 0; + return 1; } +// Декомпресія (приклад потребує уточнень залежно від специфіки формату) +int decompress_1(const char* input_file_name, const char* output_file_name) { + (void)input_file_name; + (void)output_file_name; + return -1; // Поки що не реалізовано. +}