usaa24/sk1/compressor.c

322 lines
9.1 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_TREE_HT 256
// A Huffman tree node
struct MinHeapNode {
unsigned char data;
unsigned freq;
struct MinHeapNode *left, *right;
};
// A MinHeap
struct MinHeap {
unsigned size;
unsigned capacity;
struct MinHeapNode** array;
};
// 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;
}
// Function to create a MinHeap
struct MinHeap* createMinHeap(unsigned capacity) {
struct MinHeap* minHeap = (struct MinHeap*)malloc(sizeof(struct MinHeap));
minHeap->size = 0;
minHeap->capacity = capacity;
minHeap->array = (struct MinHeapNode**)malloc(minHeap->capacity * sizeof(struct MinHeapNode*));
return minHeap;
}
// Swap function
void swapMinHeapNode(struct MinHeapNode** a, struct MinHeapNode** b) {
struct MinHeapNode* t = *a;
*a = *b;
*b = t;
}
// 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
if (left < minHeap->size && minHeap->array[left]->freq < minHeap->array[smallest]->freq)
smallest = left;
if (right < minHeap->size && minHeap->array[right]->freq < minHeap->array[smallest]->freq)
smallest = right;
if (smallest != idx) {
swapMinHeapNode(&minHeap->array[smallest], &minHeap->array[idx]);
minHeapify(minHeap, smallest);
}
}
// Extract minimum value node from heap
struct MinHeapNode* extractMin(struct MinHeap* minHeap) {
struct MinHeapNode* temp = minHeap->array[0];
minHeap->array[0] = minHeap->array[minHeap->size - 1];
--minHeap->size;
minHeapify(minHeap, 0);
return temp;
}
// Insert a new node to MinHeap
void insertMinHeap(struct MinHeap* minHeap, struct MinHeapNode* minHeapNode) {
++minHeap->size;
int i = minHeap->size - 1;
while (i && minHeapNode->freq < minHeap->array[(i - 1) / 2]->freq) {
minHeap->array[i] = minHeap->array[(i - 1) / 2];
i = (i - 1) / 2;
}
minHeap->array[i] = minHeapNode;
}
// Build the MinHeap
void buildMinHeap(struct 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);
}
// 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 (int i = 0; i < minHeap->size; ++i) {
free(minHeap->array[i]);
}
free(minHeap->array);
free(minHeap);
}
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);
while (!isSizeOne(minHeap)) {
left = extractMin(minHeap);
right = extractMin(minHeap);
top = createNode('$', left->freq + right->freq);
top->left = left;
top->right = right;
insertMinHeap(minHeap, top);
}
return extractMin(minHeap);
}
// Print Huffman Codes to a map
void storeCodes(struct MinHeapNode* root, char** codes, char* currentCode, int top) {
if (!root) return;
if (root->left) {
currentCode[top] = '0';
storeCodes(root->left, codes, currentCode, top + 1);
}
if (root->right) {
currentCode[top] = '1';
storeCodes(root->right, codes, currentCode, top + 1);
}
if (!(root->left) && !(root->right)) {
currentCode[top] = '\0';
codes[root->data] = strdup(currentCode); // Ensure memory is allocated
}
}
// Updated compressFile function
void storeCodes(struct MinHeapNode* root, char** codes, char* currentCode, int top) {
if (!root) return;
if (root->left) {
currentCode[top] = '0';
storeCodes(root->left, codes, currentCode, top + 1);
}
if (root->right) {
currentCode[top] = '1';
storeCodes(root->right, codes, currentCode, top + 1);
}
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
}
}
// Исправление для 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");
return -1;
}
int freq[256] = {0};
unsigned char buffer;
// 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;
for (int i = 0; i < 256; i++) {
if (freq[i] > 0) {
data[size] = (unsigned char)i;
frequencies[size] = freq[i];
size++;
}
}
struct MinHeap* minHeap = createAndBuildMinHeap(data, frequencies, size); // Создаем кучу
struct MinHeapNode* root = buildHuffmanTree(data, frequencies, size);
char* codes[256] = {0};
char currentCode[MAX_TREE_HT] = {0}; // Initialize to avoid garbage values
storeCodes(root, codes, currentCode, 0);
FILE* outputFile = fopen(output_file_name, "wb");
if (!outputFile) {
perror("Error opening output file");
fclose(inputFile);
return -1;
}
// Write codes to output file
fwrite(freq, sizeof(int), 256, outputFile);
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;
}
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;
}
}
}
if (bitCount > 0) {
byte <<= (8 - bitCount);
fwrite(&byte, sizeof(unsigned char), 1, outputFile);
}
fclose(inputFile);
fclose(outputFile);
freeMinHeap(minHeap); // Free the min heap memory
freeHuffmanCodes(codes); // Free Huffman codes
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) {
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) {
perror("Error opening output file");
fclose(inputFile);
return -1;
}
struct MinHeapNode* current = root;
unsigned char buffer;
int bitCount = 0;
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;
if (!(current->left) && !(current->right)) {
fwrite(&current->data, sizeof(unsigned char), 1, outputFile);
current = root;
}
}
}
fclose(inputFile);
fclose(outputFile);
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);