264 lines
6.3 KiB
C
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;
|
|
}
|