From 1f566ebe0f03ce969d9a6aedd4b4ffcd89bdb747 Mon Sep 17 00:00:00 2001 From: Ivan Leichenko Date: Sat, 18 Jan 2025 13:15:16 +0100 Subject: [PATCH] 1 v 1 sk1 --- sk1/compressor.c | 85 ++++++++++++++++++++++++++++++++++++++---------- sk1/main.c | 2 +- 2 files changed, 68 insertions(+), 19 deletions(-) diff --git a/sk1/compressor.c b/sk1/compressor.c index 309c6be..ece92d1 100644 --- a/sk1/compressor.c +++ b/sk1/compressor.c @@ -3,6 +3,7 @@ #include #include #include +#include #define WINDOW_SIZE 4096 // Размер скользящего окна #define LOOKAHEAD_BUFFER_SIZE 15 // Размер буфера предпросмотра @@ -39,7 +40,7 @@ void swap_nodes(Node** a, Node** b) *b = temp; } -void heapify(MinHeap* heap, int idx) +void heapify(MinHeap* heap, int idx) { int smallest = idx; int left = 2 * idx + 1; @@ -147,14 +148,18 @@ void free_tree(Node* root) } } -int compress_2(const char* input_file_name, const char* output_file_name) +int compress_2(const char* input_file_name, const char* output_file_name) { FILE* input = fopen(input_file_name, "rb"); - if (!input) return -1; + if (!input) + { + return -1; + } int freq[MAX_TREE_NODES] = {0}; unsigned char buffer; + // Читаем файл и подсчитываем частоты символов while (fread(&buffer, 1, 1, input)) { freq[buffer]++; @@ -175,7 +180,9 @@ int compress_2(const char* input_file_name, const char* output_file_name) char code[MAX_TREE_NODES]; build_codes(heap->nodes[0], code, 0, codes); + // Вернемся в начало входного файла fseek(input, 0, SEEK_SET); + FILE* output = fopen(output_file_name, "wb"); if (!output) { @@ -183,14 +190,17 @@ int compress_2(const char* input_file_name, const char* output_file_name) return -1; } + // Записываем частоты символов fwrite(freq, sizeof(freq), 1, output); unsigned char out_buffer = 0; int bit_count = 0; + // Записываем закодированные данные while (fread(&buffer, 1, 1, input)) { char* symbol_code = codes[buffer]; + for (int i = 0; symbol_code[i] != '\0'; i++) { out_buffer <<= 1; @@ -200,7 +210,7 @@ int compress_2(const char* input_file_name, const char* output_file_name) } bit_count++; - if (bit_count == 8) + if (bit_count == 8) { fwrite(&out_buffer, 1, 1, output); bit_count = 0; @@ -215,6 +225,13 @@ int compress_2(const char* input_file_name, const char* output_file_name) fwrite(&out_buffer, 1, 1, output); } + fseek(input, 0, SEEK_END); + long sizeIN = ftell(input); + fseek(input, 0, SEEK_SET); + + // Записываем реальный размер входного файла для декомпрессии + fwrite(&sizeIN, sizeof(sizeIN), 1, output); + fseek(output, 0, SEEK_END); int sizeOUT = ftell(output); fseek(output, 0, SEEK_SET); @@ -230,7 +247,10 @@ int compress_2(const char* input_file_name, const char* output_file_name) int decompress_2(const char* input_file_name, const char* output_file_name) { FILE* input = fopen(input_file_name, "rb"); - if (!input) return -1; + if (!input) + { + return -1; + } int freq[MAX_TREE_NODES]; fread(freq, sizeof(freq), 1, input); @@ -238,7 +258,7 @@ int decompress_2(const char* input_file_name, const char* output_file_name) MinHeap* heap = create_min_heap(); for (int i = 0; i < MAX_TREE_NODES; i++) { - if (freq[i] > 0) + if (freq[i] > 0) { insert_min_heap(heap, create_node((unsigned char)i, freq[i])); } @@ -250,30 +270,55 @@ int decompress_2(const char* input_file_name, const char* output_file_name) if (!output) { fclose(input); + free_tree(heap->nodes[0]); + free(heap); return -1; } Node* root = heap->nodes[0]; Node* current = root; - unsigned char buffer; - while (fread(&buffer, 1, 1, input)) + // Перемещаемся к концу файла, чтобы прочитать оригинальный размер + fseek(input, -sizeof(long), SEEK_END); + long original_size; + fread(&original_size, sizeof(long), 1, input); + + // Вернемся к началу сжатых данных + long data_end = ftell(input) - sizeof(long); + fseek(input, sizeof(freq), SEEK_SET); + + long written_bytes = 0; + unsigned char buffer; + int bit_count = 0; + + while (ftell(input) < data_end || (bit_count > 0 && written_bytes < original_size)) { - for (int i = 7; i >= 0; i--) + if (bit_count == 0 && fread(&buffer, 1, 1, input) == 1) { - if ((buffer >> i) & 1) - { - current = current->right; - } - else - { - current = current->left; - } + bit_count = 8; + } + + if (bit_count > 0) + { + int bit = (buffer >> (bit_count - 1)) & 1; + bit_count--; + + current = bit ? current->right : current->left; if (!current->left && !current->right) { - fwrite(¤t->symbol, 1, 1, output); + if (written_bytes < original_size) + { + fwrite(¤t->symbol, 1, 1, output); + written_bytes++; + } current = root; + + // Остановимся, если записали все байты + if (written_bytes == original_size) + { + break; + } } } } @@ -290,6 +335,10 @@ int decompress_2(const char* input_file_name, const char* output_file_name) return sizeOUT; } + + + + // Функция для записи токена в файл в компактном формате void write_token(FILE *file, LZ77Token token) { diff --git a/sk1/main.c b/sk1/main.c index d77bef4..fe33b9b 100644 --- a/sk1/main.c +++ b/sk1/main.c @@ -50,4 +50,4 @@ int main(int argc, char* argv[]) } return 0; -} \ No newline at end of file +}