diff --git a/sk1/compressor.c b/sk1/compressor.c index 2ab8526..c8a1af5 100644 --- a/sk1/compressor.c +++ b/sk1/compressor.c @@ -1,58 +1,72 @@ #include #include #include +#include -#define MAX_TREE_HT 256 +#define MAX_TREE_NODES 256 -// A Huffman tree node -struct MinHeapNode { +// Structure to represent a tree node +typedef struct HuffmanNode { unsigned char data; - unsigned freq; - struct MinHeapNode *left, *right; -}; + unsigned frequency; + struct HuffmanNode* left; + struct HuffmanNode* right; +} HuffmanNode; -// A MinHeap -struct MinHeap { +// A structure to represent the Min Heap (Priority Queue) +typedef struct MinHeap { unsigned size; unsigned capacity; - struct MinHeapNode** array; -}; + HuffmanNode** array; +} MinHeap; // Function to create a new node -struct MinHeapNode* createNode(unsigned char data, unsigned freq) { - struct MinHeapNode* temp = (struct MinHeapNode*)malloc(sizeof(struct MinHeapNode)); - temp->data = data; - temp->freq = freq; - temp->left = temp->right = NULL; - return temp; +HuffmanNode* newNode(unsigned char data, unsigned frequency) { + HuffmanNode* node = (HuffmanNode*)malloc(sizeof(HuffmanNode)); + if (!node) { + perror("Failed to allocate memory for new node"); + exit(EXIT_FAILURE); + } + node->data = data; + node->frequency = frequency; + node->left = node->right = NULL; + return node; } // Function to create a MinHeap -struct MinHeap* createMinHeap(unsigned capacity) { - struct MinHeap* minHeap = (struct MinHeap*)malloc(sizeof(struct MinHeap)); +MinHeap* createMinHeap(unsigned capacity) { + MinHeap* minHeap = (MinHeap*)malloc(sizeof(MinHeap)); + if (!minHeap) { + perror("Failed to allocate memory for MinHeap"); + exit(EXIT_FAILURE); + } minHeap->size = 0; minHeap->capacity = capacity; - minHeap->array = (struct MinHeapNode**)malloc(minHeap->capacity * sizeof(struct MinHeapNode*)); + minHeap->array = (HuffmanNode**)malloc(capacity * sizeof(HuffmanNode*)); + if (!minHeap->array) { + perror("Failed to allocate memory for MinHeap array"); + exit(EXIT_FAILURE); + } return minHeap; } -// Swap function -void swapMinHeapNode(struct MinHeapNode** a, struct MinHeapNode** b) { - struct MinHeapNode* t = *a; +// Function to swap two min heap nodes +void swapMinHeapNode(HuffmanNode** a, HuffmanNode** b) { + HuffmanNode* temp = *a; *a = *b; - *b = t; + *b = temp; } -// MinHeapify function -void minHeapify(struct MinHeap* minHeap, unsigned idx) { - unsigned smallest = idx; // Changed to unsigned - unsigned left = 2 * idx + 1; // Changed to unsigned - unsigned right = 2 * idx + 2; // Changed to unsigned +// Function to min heapify +void minHeapify(MinHeap* minHeap, int idx) { + int smallest = idx; + int left = 2 * idx + 1; + int right = 2 * idx + 2; - if (left < minHeap->size && minHeap->array[left]->freq < minHeap->array[smallest]->freq) + if (left < minHeap->size && minHeap->array[left]->frequency < minHeap->array[smallest]->frequency) smallest = left; - if (right < minHeap->size && minHeap->array[right]->freq < minHeap->array[smallest]->freq) + if (right < minHeap->size && minHeap->array[right]->frequency < minHeap->array[smallest]->frequency) smallest = right; if (smallest != idx) { @@ -61,9 +75,14 @@ void minHeapify(struct MinHeap* minHeap, unsigned idx) { } } -// Extract minimum value node from heap -struct MinHeapNode* extractMin(struct MinHeap* minHeap) { - struct MinHeapNode* temp = minHeap->array[0]; +// Check if the size of heap is one +int isSizeOne(MinHeap* minHeap) { + return (minHeap->size == 1); +} + +// Extract the minimum node from heap +HuffmanNode* extractMin(MinHeap* minHeap) { + HuffmanNode* temp = minHeap->array[0]; minHeap->array[0] = minHeap->array[minHeap->size - 1]; --minHeap->size; minHeapify(minHeap, 0); @@ -71,237 +90,200 @@ struct MinHeapNode* extractMin(struct MinHeap* minHeap) { } // Insert a new node to MinHeap -void insertMinHeap(struct MinHeap* minHeap, struct MinHeapNode* minHeapNode) { +void insertMinHeap(MinHeap* minHeap, HuffmanNode* node) { ++minHeap->size; int i = minHeap->size - 1; - while (i && minHeapNode->freq < minHeap->array[(i - 1) / 2]->freq) { + while (i && node->frequency < minHeap->array[(i - 1) / 2]->frequency) { minHeap->array[i] = minHeap->array[(i - 1) / 2]; i = (i - 1) / 2; } - minHeap->array[i] = minHeapNode; + minHeap->array[i] = node; } -// Build the MinHeap -void buildMinHeap(struct MinHeap* minHeap) { +// Build a min heap of given capacity +void buildMinHeap(MinHeap* minHeap) { int n = minHeap->size - 1; for (int i = (n - 1) / 2; i >= 0; --i) minHeapify(minHeap, i); } -// Check if size is 1 -int isSizeOne(struct MinHeap* minHeap) { - return (minHeap->size == 1); -} +// Function to build the Huffman tree +HuffmanNode* buildHuffmanTree(unsigned char* data, unsigned* freq, int size) { + HuffmanNode *left, *right, *top; + + MinHeap* minHeap = createMinHeap(size); -// Create and build a MinHeap -struct MinHeap* createAndBuildMinHeap(unsigned char data[], int freq[], int size) { - struct MinHeap* minHeap = createMinHeap(size); for (int i = 0; i < size; ++i) - minHeap->array[i] = createNode(data[i], freq[i]); - minHeap->size = size; - buildMinHeap(minHeap); - return minHeap; -} -void freeMinHeap(struct MinHeap* minHeap) { - for (unsigned i = 0; i < minHeap->size; ++i) { // Changed to unsigned - free(minHeap->array[i]); - } - free(minHeap->array); - free(minHeap); -} + insertMinHeap(minHeap, newNode(data[i], freq[data[i]])); -void freeHuffmanCodes(char* codes[256]) { - for (int i = 0; i < 256; ++i) { - if (codes[i]) { - free(codes[i]); - } - } -} -// Build Huffman Tree -struct MinHeapNode* buildHuffmanTree(unsigned char data[], int freq[], int size) { - struct MinHeapNode *left, *right, *top; - struct MinHeap* minHeap = createAndBuildMinHeap(data, freq, size); + buildMinHeap(minHeap); while (!isSizeOne(minHeap)) { left = extractMin(minHeap); right = extractMin(minHeap); - top = createNode('$', left->freq + right->freq); + top = newNode('$', left->frequency + right->frequency); top->left = left; top->right = right; insertMinHeap(minHeap, top); } + return extractMin(minHeap); } -// Print Huffman Codes to a map - - - -// Updated compressFile function -void storeCodes(struct MinHeapNode* root, char** codes, char* currentCode, int top) { - if (!root) return; - +// Function to generate the Huffman codes for each character +void generateCodes(HuffmanNode* root, char* arr, int top, char** codes) { if (root->left) { - currentCode[top] = '0'; - storeCodes(root->left, codes, currentCode, top + 1); + arr[top] = '0'; + generateCodes(root->left, arr, top + 1, codes); } + if (root->right) { - currentCode[top] = '1'; - storeCodes(root->right, codes, currentCode, top + 1); + arr[top] = '1'; + generateCodes(root->right, arr, top + 1, codes); } - if (!(root->left) && !(root->right)) { - currentCode[top] = '\0'; - codes[root->data] = (char*)malloc(strlen(currentCode) + 1); // Use malloc instead of strdup - strcpy(codes[root->data], currentCode); // Copy the string + + if (!root->left && !root->right) { + arr[top] = '\0'; // Null terminate the string + codes[root->data] = strdup(arr); } } -// Исправление для minHeap в compressFile -int compressFile(const char* input_file_name, const char* output_file_name) { - FILE* inputFile = fopen(input_file_name, "rb"); - if (!inputFile) { - perror("Error opening input file"); +// Function to compress a file +int compress_1(const char* input_file, const char* output_file) { + FILE* input = fopen(input_file, "rb"); + FILE* output = fopen(output_file, "wb"); + if (!input || !output) { + perror("Error opening file"); return -1; } - int freq[256] = {0}; - unsigned char buffer; + unsigned freq[256] = {0}; + unsigned char data; + while (fread(&data, sizeof(data), 1, input) == 1) + freq[data]++; - // Count frequency of each byte - while (fread(&buffer, sizeof(unsigned char), 1, inputFile)) { - freq[buffer]++; - } - rewind(inputFile); - - unsigned char data[256]; - int frequencies[256], size = 0; + unsigned char unique_data[256]; + int unique_count = 0; for (int i = 0; i < 256; i++) { if (freq[i] > 0) { - data[size] = (unsigned char)i; - frequencies[size] = freq[i]; - size++; + unique_data[unique_count++] = i; } } - struct MinHeap* minHeap = createAndBuildMinHeap(data, frequencies, size); // Create heap - struct MinHeapNode* root = buildHuffmanTree(data, frequencies, size); + HuffmanNode* root = buildHuffmanTree(unique_data, freq, unique_count); + char* codes[256] = {0}; - char currentCode[MAX_TREE_HT] = {0}; // Initialize to avoid garbage values - storeCodes(root, codes, currentCode, 0); + char arr[256]; + generateCodes(root, arr, 0, codes); - FILE* outputFile = fopen(output_file_name, "wb"); - if (!outputFile) { - perror("Error opening output file"); - fclose(inputFile); - return -1; + fwrite(&unique_count, sizeof(int), 1, output); + for (int i = 0; i < unique_count; i++) { + unsigned char symbol = unique_data[i]; + fwrite(&symbol, sizeof(unsigned char), 1, output); + fwrite(&freq[symbol], sizeof(unsigned), 1, output); } - // Write codes to output file - fwrite(freq, sizeof(int), 256, outputFile); + fseek(input, 0, SEEK_SET); - unsigned char byte = 0; - int bitCount = 0; - while (fread(&buffer, sizeof(unsigned char), 1, inputFile)) { - char* code = codes[buffer]; - if (!code) { - fprintf(stderr, "Error: Undefined code for byte %u\n", buffer); - fclose(inputFile); - fclose(outputFile); - return -1; - } + unsigned char buffer = 0; + int bit_count = 0; + size_t total_bits = 0; + + while (fread(&data, sizeof(data), 1, input) == 1) { + char* code = codes[data]; for (int i = 0; code[i] != '\0'; i++) { - byte = (byte << 1) | (code[i] - '0'); - bitCount++; - if (bitCount == 8) { - fwrite(&byte, sizeof(unsigned char), 1, outputFile); - byte = 0; - bitCount = 0; + unsigned char bit = code[i] - '0'; + buffer = (buffer << 1) | bit; + bit_count++; + total_bits++; + + if (bit_count == 8) { + fwrite(&buffer, sizeof(unsigned char), 1, output); + bit_count = 0; + buffer = 0; } } } - if (bitCount > 0) { - byte <<= (8 - bitCount); - fwrite(&byte, sizeof(unsigned char), 1, outputFile); + + if (bit_count > 0) { + buffer <<= (8 - bit_count); + fwrite(&buffer, sizeof(unsigned char), 1, output); } - fclose(inputFile); - fclose(outputFile); + fwrite(&total_bits, sizeof(size_t), 1, output); // Write total bits used - freeMinHeap(minHeap); // Free the min heap memory - freeHuffmanCodes(codes); // Free Huffman codes + fclose(input); + fclose(output); return 0; } - -// Decompress the file -int decompressFile(const char* input_file_name, const char* output_file_name) { - FILE* inputFile = fopen(input_file_name, "rb"); - if (!inputFile) { +// Function to decompress the compressed file +int decompress_1(const char* input_file_name, const char* output_file_name) { + FILE* input = fopen(input_file_name, "rb"); + if (!input) { perror("Error opening input file"); return -1; } - - int freq[256]; - fread(freq, sizeof(int), 256, inputFile); - - unsigned char data[256]; - int frequencies[256], size = 0; - for (int i = 0; i < 256; i++) { - if (freq[i] > 0) { - data[size] = (unsigned char)i; - frequencies[size] = freq[i]; - size++; - } - } - - struct MinHeapNode* root = buildHuffmanTree(data, frequencies, size); - - FILE* outputFile = fopen(output_file_name, "wb"); - if (!outputFile) { + FILE* output = fopen(output_file_name, "wb"); + if (!output) { perror("Error opening output file"); - fclose(inputFile); + fclose(input); return -1; } - struct MinHeapNode* current = root; - unsigned char buffer; - while (fread(&buffer, sizeof(unsigned char), 1, inputFile)) { - for (int i = 7; i >= 0; i--) { - int bit = (buffer >> i) & 1; - if (bit == 0) - current = current->left; - else - current = current->right; + int unique_count; + if (fread(&unique_count, sizeof(int), 1, input) != 1) { + perror("Error reading from input file"); + fclose(input); + fclose(output); + return -1; + } - if (!(current->left) && !(current->right)) { - fwrite(¤t->data, sizeof(unsigned char), 1, outputFile); + unsigned char unique_data[256]; + unsigned freq[256] = {0}; + for (int i = 0; i < unique_count; i++) { + if (fread(&unique_data[i], sizeof(unsigned char), 1, input) != 1 || + fread(&freq[unique_data[i]], sizeof(unsigned), 1, input) != 1) { + perror("Error reading from input file"); + fclose(input); + fclose(output); + return -1; + } + } + + HuffmanNode* root = buildHuffmanTree(unique_data, freq, unique_count); + + size_t total_bits; + fseek(input, -sizeof(size_t), SEEK_END); + fread(&total_bits, sizeof(size_t), 1, input); + + fseek(input, sizeof(int) + unique_count * (sizeof(unsigned char) + sizeof(unsigned)), SEEK_SET); + + HuffmanNode* current = root; + unsigned char byte; + size_t bits_read = 0; + + while (bits_read < total_bits && fread(&byte, sizeof(byte), 1, input) == 1) { + for (int i = 7; i >= 0 && bits_read < total_bits; i--, bits_read++) { + if (byte & (1 << i)) { + current = current->right; + } else { + current = current->left; + } + + if (!current->left && !current->right) { + fwrite(¤t->data, sizeof(current->data), 1, output); current = root; } } } - fclose(inputFile); - fclose(outputFile); + fclose(input); + fclose(output); + return 0; } - - - -int compress_1(const char* input_file_name, const char* output_file_name){ - if(compressFile(input_file_name, output_file_name) == 0){ - printf("Succsses!"); - } - return 0; -} - -int decompress_1(const char* input_file_name, const char* output_file_name){ - if(decompressFile(input_file_name, output_file_name) == 0){ - printf("Succsses!"); - } - return 0; - -} 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); \ No newline at end of file