usaa25/sk1/compressor.c
2026-01-21 00:03:03 +01:00

264 lines
6.3 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include "compressor.h"
struct node {
unsigned char znak;
int pocet;
struct node *left;
struct node *right;
};
struct node* vytvor_node(unsigned char c, int p) {
struct node* n = malloc(sizeof(struct node));
n->znak = c;
n->pocet = p;
n->left = NULL;
n->right = NULL;
return n;
}
int compress_file(char *input, char *output) {
FILE *f = fopen(input, "rb");
if(!f) {
printf("Neviem otvorit subor\n");
return 1;
}
fseek(f, 0, SEEK_END);
long velkost = ftell(f);
fseek(f, 0, SEEK_SET);
unsigned char *data = malloc(velkost);
fread(data, 1, velkost, f);
fclose(f);
int frekvencia[256];
int i;
for(i=0;i<256;i++) frekvencia[i]=0;
for(i=0;i<velkost;i++) frekvencia[data[i]]++;
struct node* pole[256];
int n=0;
for(i=0;i<256;i++){
if(frekvencia[i]>0){
pole[n] = vytvor_node(i, frekvencia[i]);
n++;
}
}
for(i=0;i<n-1;i++){
for(int j=0;j<n-i-1;j++){
if(pole[j]->pocet > pole[j+1]->pocet){
struct node* tmp = pole[j];
pole[j] = pole[j+1];
pole[j+1] = tmp;
}
}
}
while(n>1){
struct node* left = pole[0];
struct node* right = pole[1];
struct node* parent = vytvor_node(0, left->pocet + right->pocet);
parent->left = left;
parent->right = right;
for(i=0;i<n-2;i++){
pole[i] = pole[i+2];
}
n = n-2;
int vlozene=0;
for(i=0;i<n;i++){
if(parent->pocet < pole[i]->pocet){
for(int j=n;j>i;j--){
pole[j] = pole[j-1];
}
pole[i] = parent;
vlozene=1;
break;
}
}
if(!vlozene) pole[n] = parent;
n++;
}
struct node* root = pole[0];
unsigned int kody[256];
unsigned char dlzky[256];
for(i=0;i<256;i++){
kody[i]=0;
dlzky[i]=0;
}
struct node* zasobnik[512];
unsigned int kod_zasobnik[512];
unsigned char dlzka_zasobnik[512];
int top=0;
zasobnik[top] = root;
kod_zasobnik[top] = 0;
dlzka_zasobnik[top] = 0;
top++;
while(top>0){
top--;
struct node* aktualny = zasobnik[top];
unsigned int kod = kod_zasobnik[top];
unsigned char dlzka = dlzka_zasobnik[top];
if(!aktualny->left && !aktualny->right){
kody[aktualny->znak] = kod;
dlzky[aktualny->znak] = dlzka>0 ? dlzka : 1;
}else{
if(aktualny->left){
zasobnik[top] = aktualny->left;
kod_zasobnik[top] = kod<<1;
dlzka_zasobnik[top] = dlzka+1;
top++;
}
if(aktualny->right){
zasobnik[top] = aktualny->right;
kod_zasobnik[top] = (kod<<1)|1;
dlzka_zasobnik[top] = dlzka+1;
top++;
}
}
}
unsigned char* vystup = malloc(velkost*2);
long pos=0;
unsigned char bajt=0;
int bit_pos=0;
for(i=0;i<velkost;i++){
unsigned int kod = kody[data[i]];
unsigned char dlzka = dlzky[data[i]];
for(int j=dlzka-1;j>=0;j--){
if((kod>>j)&1){
bajt |= (1<<(7-bit_pos));
}
bit_pos++;
if(bit_pos==8){
vystup[pos++] = bajt;
bajt=0;
bit_pos=0;
}
}
}
if(bit_pos>0) vystup[pos++]=bajt;
FILE *fout = fopen(output, "wb");
fwrite(&velkost, sizeof(long), 1, fout);
fwrite(frekvencia, sizeof(int), 256, fout);
fwrite(vystup, 1, pos, fout);
fclose(fout);
printf("Komprimovane: %ld -> %ld\n", velkost, pos+sizeof(long)+256*sizeof(int));
free(data);
free(vystup);
return 0;
}
int decompress_file(char *input, char *output) {
FILE *f = fopen(input, "rb");
if(!f){
printf("Neviem otvorit subor\n");
return 1;
}
long velkost;
int frekvencia[256];
fread(&velkost, sizeof(long), 1, f);
fread(frekvencia, sizeof(int), 256, f);
struct node* pole[256];
int n=0;
int i;
for(i=0;i<256;i++){
if(frekvencia[i]>0){
pole[n] = vytvor_node(i, frekvencia[i]);
n++;
}
}
for(i=0;i<n-1;i++){
for(int j=0;j<n-i-1;j++){
if(pole[j]->pocet > pole[j+1]->pocet){
struct node* tmp = pole[j];
pole[j] = pole[j+1];
pole[j+1] = tmp;
}
}
}
while(n>1){
struct node* left = pole[0];
struct node* right = pole[1];
struct node* parent = vytvor_node(0, left->pocet + right->pocet);
parent->left = left;
parent->right = right;
for(i=0;i<n-2;i++){
pole[i] = pole[i+2];
}
n = n-2;
int vlozene=0;
for(i=0;i<n;i++){
if(parent->pocet < pole[i]->pocet){
for(int j=n;j>i;j--){
pole[j] = pole[j-1];
}
pole[i] = parent;
vlozene=1;
break;
}
}
if(!vlozene) pole[n] = parent;
n++;
}
struct node* root = pole[0];
fseek(f, 0, SEEK_END);
long total = ftell(f);
long komp_velkost = total - sizeof(long) - 256*sizeof(int);
fseek(f, sizeof(long) + 256*sizeof(int), SEEK_SET);
unsigned char *komp_data = malloc(komp_velkost);
fread(komp_data, 1, komp_velkost, f);
fclose(f);
unsigned char *vystup = malloc(velkost);
long vystup_pos=0;
struct node* aktualny = root;
for(i=0;i<komp_velkost && vystup_pos<velkost;i++){
for(int bit=7;bit>=0 && vystup_pos<velkost;bit--){
if((komp_data[i]>>bit)&1){
aktualny = aktualny->right;
}else{
aktualny = aktualny->left;
}
if(!aktualny->left && !aktualny->right){
vystup[vystup_pos++] = aktualny->znak;
aktualny = root;
}
}
}
FILE *fout = fopen(output, "wb");
fwrite(vystup, 1, velkost, fout);
fclose(fout);
printf("Dekomprimovane: %ld\n", velkost);
free(komp_data);
free(vystup);
return 0;
}