Esta é uma pré-visualização de arquivo. Entre para ver o arquivo original
compactador/descompactador.cpp
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <stdio.h>
#include <list>
#include <queue>
#include <deque>
#include <algorithm>
#include <time.h>
#include <conio.h>
#include "lebit.cpp"
using namespace std;
struct pnodo
{
struct nodo *ptr;
};
const pnodo null = { 0 };
struct nodo
{
char caractere;
int frequencia;
pnodo esq, dir, pai;
};
bool operator==(const pnodo &n1, const pnodo &n2)
{
return n1.ptr->caractere == n2.ptr->caractere;
}
bool operator!=(const pnodo &n1, const pnodo &n2)
{
return n1.ptr != n2.ptr;
}
bool operator>(const pnodo &n1, const pnodo &n2)
{
return n1.ptr->frequencia > n2.ptr->frequencia;
}
pnodo gera_arvore(priority_queue<pnodo, deque<pnodo>, greater<pnodo> >& fila)
{
pnodo e1, e2, aux;
while(!fila.empty())
{
e1 = fila.top(); fila.pop();
if(fila.empty()) break;
e2 = fila.top(); fila.pop();
aux.ptr = new nodo;
(aux.ptr)->frequencia = (e1.ptr)->frequencia + (e2.ptr)->frequencia;
(aux.ptr)->esq = e1; (aux.ptr)->dir = e2;
(aux.ptr)->pai = null;
(e1.ptr)->pai = aux; (e2.ptr)->pai = aux;
(aux.ptr)->caractere = 0;
fila.push(aux);
}
return e1;
}
int main ()
{
pnodo raiz;
FILE *ent, *sai;
ent = fopen("teste_sai.bin", "rb");
if (ent == NULL)
{
cout <<"Nao pude abrir o arquivo";
exit(1);
}
sai = fopen("descompactado.txt", "w");
if (sai == NULL)
{
cout <<"Nao pude criar o arquivo de saida.";
exit(1);
}
int numPares;
fread(&numPares, sizeof(int), 1, ent);
cout << numPares << endl;
priority_queue< pnodo, deque<pnodo>, greater<pnodo> > fila;
char carac;
int freq;
pnodo aux;
for (int x = 0; x < numPares; x++)
{
fread(&carac, sizeof(char), 1, ent);
fread(&freq, sizeof(int), 1, ent);
cout << carac << " " << freq << endl;
aux.ptr = new nodo;
aux.ptr -> caractere = carac;
aux.ptr -> frequencia = freq;
aux.ptr -> esq = null;
aux.ptr -> dir = null;
fila.push(aux);
}
raiz = gera_arvore(fila);
int numbit;
fread(&numbit, sizeof(int), 1, ent);
cout << numbit << endl;
pnodo aux1 = raiz;
byte bit;
for (int x = 0;x < numbit; x++)
{
//ler bit do arquivo de entrada
bit = le_bit(ent);
//escreve o bit
cout<<(int)bit;
if (bit == 1)
{
aux1 = aux1.ptr -> esq;
}
else
{
aux1 = aux1.ptr -> dir;
}
//escreve o caractere no arquivo
if (!(aux1.ptr -> dir != null) && !(aux1.ptr -> esq != null))
{
fwrite(&(aux1.ptr->caractere), sizeof(char), 1, sai);
aux1 = raiz;
}
}
fcloseall();
cout <<"\nFim da operaçao.";
getch();
//o texto descompactado so pode ser visto abrindo o arquivo descompactado.txt
}
compactador/descompactado.txt
compactador/teste.txt
abracadabra
compactador/teste_sai.bin
compactador/lebit.cpp
typedef unsigned char byte;
byte le_bit (FILE *f){
static byte buffer; //Não perde o valor da variável após encerrar a função (static BUFFER)
static int cont=0; //local com escopo global
if(cont==0){
fread(&buffer, sizeof(byte),1,f);
cont=8;
}
byte res=(byte)(buffer<<(8-cont))>>7;
--cont;
return res; //simplificando: return (byte)(buffer<<(8-cont--))>>7;
}
compactador/principal.cpp
//
// Compactador Huffman
// Código desenvolvido pelo Prof. Marcos Vinícius da Silva
// baseado no livro "Algorithms in C++" de Robert Sedgewick
//
// Versão para Visual Studio
//
//Comente esta linha para gerar o código sem saída de depuração
#define DEBUG
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <stdio.h>
#include <list>
#include <queue>
#include <deque>
#include <algorithm>
#include <conio.h>
#include <time.h>
static char nome_arquivo_entrada[]="teste.txt";
#ifndef DEBUG
using namespace std;
struct pnodo
{
struct nodo *ptr;
};
const pnodo null = { 0 };
struct nodo
{
char caractere;
int frequencia;
pnodo esq, dir, pai;
};
bool operator==(const pnodo &n1, const pnodo &n2)
{
return n1.ptr->caractere == n2.ptr->caractere;
}
bool operator!=(const pnodo &n1, const pnodo &n2)
{
return n1.ptr != n2.ptr;
}
bool operator>(const pnodo &n1, const pnodo &n2)
{
return n1.ptr->frequencia > n2.ptr->frequencia;
}
list<pnodo> conta_frequencia(ifstream &f)
{
list<pnodo> l;
list<pnodo>::iterator pos;
pnodo aux;
aux.ptr = new nodo;
f.get(aux.ptr->caractere);
while(!f.eof())
{
aux.ptr->esq = aux.ptr->dir = null;
pos = find(l.begin(), l.end(), aux);
if(pos != l.end())
{
(*pos).ptr->frequencia++;
delete aux.ptr;
}
else {
aux.ptr->frequencia = 1;
l.insert(l.end(), aux);
}
aux.ptr = new nodo;
f.get(aux.ptr->caractere);
}
delete aux.ptr;
return l;
}
void copia_lista(const list<pnodo>& lista,
priority_queue<pnodo, deque<pnodo>, greater<pnodo> >& fila)
{
list<pnodo>::const_iterator i;
i = lista.begin();
while(i != lista.end())
{
fila.push(*i);
i++;
}
}
pnodo gera_arvore(priority_queue<pnodo, deque<pnodo>, greater<pnodo> >& fila)
{
pnodo e1, e2, aux;
while(!fila.empty())
{
e1 = fila.top(); fila.pop();
if(fila.empty()) break;
e2 = fila.top(); fila.pop();
aux.ptr = new nodo;
(aux.ptr)->frequencia = (e1.ptr)->frequencia + (e2.ptr)->frequencia;
(aux.ptr)->esq = e1; (aux.ptr)->dir = e2;
(aux.ptr)->pai = null;
(e1.ptr)->pai = aux; (e2.ptr)->pai = aux;
(aux.ptr)->caractere = 0;
fila.push(aux);
}
return e1;
}
void grava_frequencias(list<pnodo> &freqs, FILE *arq)
{
list<pnodo>::iterator i = freqs.begin();
while(i!=freqs.end())
{
char c = (*i).ptr->caractere;
int f = (*i).ptr->frequencia;
fwrite(&c, sizeof(char), 1, arq);
fwrite(&f, sizeof(int), 1, arq);
i++;
}
}
void escreve_bit(FILE *f, unsigned char bit)
{
static unsigned char valor=0, cont=1;
if(cont < sizeof(char)*8)
{
valor = (unsigned char) (valor << 1) | bit;
cont++;
}
else
{
valor = (unsigned char) (valor << 1) | bit;
fwrite(&valor, sizeof(char), 1, f);
cont=1; valor=0;
}
}
list<unsigned char> obtem_codigo(char c, list<pnodo> &arv)
{
list<pnodo>::iterator pos;
list<unsigned char> bits;
unsigned char bit;
nodo aux;
pnodo paux;
aux.caractere = c;
paux.ptr = &aux;
pos = find (arv.begin(), arv.end(), paux);
paux = *pos;
bits.clear();
while((paux.ptr->pai != null))
{
if(!(paux != paux.ptr->pai.ptr->esq))
bit = 1;
else
bit = 0;
bits.insert(bits.begin(), bit);
paux = paux.ptr->pai;
}
return bits;
}
unsigned int codifica_arquivo(list<pnodo> &arv, ifstream &ent, FILE *sai)
{
list<unsigned char> codigo;
list<unsigned char>::iterator i;
unsigned int contabits=0;
char c;
ent.close();
ent.open(nome_arquivo_entrada);
ent.get(c);
while( ! ent.eof() ) {
codigo = obtem_codigo(c, arv);
i = codigo.begin();
while(i != codigo.end()) {
contabits++;
escreve_bit(sai, *i++);
}
ent.get(c);
}
for(unsigned int i=0; i<8-(contabits%8); i++) { // completa o ultimo byte
escreve_bit(sai, 0);
}
return contabits;
}
int main()
{
list<pnodo> freqs;
priority_queue< pnodo, deque<pnodo>, greater<pnodo> > fp;
FILE *arq_sai;
pnodo raiz;
long tamanho1=0, bits=0;
int num_nodos;
clock_t ini, fim;
ini = clock();
ifstream arq_ent(nome_arquivo_entrada);
if (! arq_ent.is_open() ) {
cout << "Não pude abrir o arquivo de entrada teste.txt";
getch();
exit(1);
}
arq_sai = fopen("teste_sai.bin", "wb");
if (arq_sai == NULL) {
cout << "Não pude abrir o arquivo de saida teste_sai.bin";
getch();
exit(1);
}
freqs = conta_frequencia(arq_ent);
copia_lista(freqs, fp);
raiz = gera_arvore(fp);
num_nodos = freqs.size();
fwrite(&num_nodos, sizeof(int), 1, arq_sai);
grava_frequencias(freqs, arq_sai);
tamanho1 = ftell(arq_sai);
fwrite(&bits, sizeof(int), 1, arq_sai); // reserva espaço para o número de bits escritos
bits = codifica_arquivo(freqs, arq_ent, arq_sai);
fseek(arq_sai, tamanho1, SEEK_SET); // posiciona no local com o numero de bytes da codificacao
fwrite(&bits, sizeof(int), 1, arq_sai); // grava o tamanho da codificacao (em bits)
fcloseall();
fim = clock();
cout << "Tempo gasto: "<<(fim-ini)/CLOCKS_PER_SEC;
getch();
return 0;
}
#endif
//
//
//
#ifdef DEBUG
using namespace std;
struct pnodo
{
struct nodo *ptr;
};
const pnodo null = { 0 };
struct nodo
{
char caractere;
int frequencia;
pnodo esq, dir, pai;
};
bool operator==(const pnodo &n1, const pnodo &n2)
{
return n1.ptr->caractere == n2.ptr->caractere;
}
bool operator!=(const pnodo &n1, const pnodo &n2)
{
return n1.ptr != n2.ptr;
}
bool operator>(const pnodo &n1, const pnodo &n2)
{
return n1.ptr->frequencia > n2.ptr->frequencia;
}
ostream& operator<<(ostream &o, const list<pnodo> &l)
{
list<pnodo>::const_iterator i;
i = l.begin();
while(i != l.end())
{
o << (*i).ptr->caractere << " : " << (*i).ptr->frequencia << endl;
i++;
}
return o;
}
ostream& operator<<(ostream &o, priority_queue<pnodo, deque<pnodo>, greater<pnodo> > pq)
{
while(!pq.empty())
{
o << pq.top().ptr->caractere << "\t";
pq.pop();
}
return o;
}
list<pnodo> conta_frequencia(ifstream &f)
{
list<pnodo> l;
list<pnodo>::iterator pos;
pnodo aux;
aux.ptr = new nodo;
f.get(aux.ptr->caractere);
while(!f.eof())
{
aux.ptr->esq = aux.ptr->dir = null;
pos = find(l.begin(), l.end(), aux);
if(pos != l.end())
{
(*pos).ptr->frequencia++;
delete aux.ptr;
}
else {
aux.ptr->frequencia = 1;
l.insert(l.end(), aux);
}
aux.ptr = new nodo;
f.get(aux.ptr->caractere);
}
delete aux.ptr;
return l;
}
void copia_lista(const list<pnodo>& lista,
priority_queue<pnodo, deque<pnodo>, greater<pnodo> >& fila)
{
list<pnodo>::const_iterator i;
i = lista.begin();
while(i != lista.end())
{
fila.push(*i);
i++;
}
}
pnodo gera_arvore(priority_queue<pnodo, deque<pnodo>, greater<pnodo> >& fila)
{
pnodo e1, e2, aux;
while(!fila.empty())
{
e1 = fila.top(); fila.pop();
if(fila.empty()) break;
e2 = fila.top(); fila.pop();
aux.ptr = new nodo;
(aux.ptr)->frequencia = (e1.ptr)->frequencia + (e2.ptr)->frequencia;
(aux.ptr)->esq = e1; (aux.ptr)->dir = e2;
(aux.ptr)->pai = null;
(e1.ptr)->pai = aux; (e2.ptr)->pai = aux;
(aux.ptr)->caractere = 0;
fila.push(aux);
}
return e1;
}
void imprime_arvore(pnodo r, int nivel)
{
if(r.ptr)
{
imprime_arvore((r.ptr)->esq, nivel+1);
for(int i=0; i<nivel; i++) cout << '\t'; // indentação
if (!(r.ptr->esq != null) && !(r.ptr->dir!=null)) // escreve a raiz
cout << (r.ptr)->caractere << endl;
else
cout << (r.ptr)->frequencia << endl;
imprime_arvore((r.ptr)->dir, nivel+1);
}
}
void grava_frequencias(list<pnodo> &freqs, FILE *arq)
{
list<pnodo>::iterator i = freqs.begin();
while(i!=freqs.end())
{
char c = (*i).ptr->caractere;
int f = (*i).ptr->frequencia;
fwrite(&c, sizeof(char), 1, arq);
fwrite(&f, sizeof(int), 1, arq);
i++;
}
}
void escreve_bit(FILE *f, unsigned char bit)
{
static unsigned char valor=0, cont=1;
if(cont < sizeof(char)*8)
{
valor = (unsigned char) (valor << 1) | bit;
cont++;
}
else
{
valor = (unsigned char) (valor << 1) | bit;
fwrite(&valor, sizeof(char), 1, f);
cont=1; valor=0;
}
}
list<unsigned char> obtem_codigo(char c, list<pnodo> &arv)
{
list<pnodo>::iterator pos;
list<unsigned char> bits;
unsigned char bit;
nodo aux;
pnodo paux;
aux.caractere = c;
paux.ptr = &aux;
pos = find (arv.begin(), arv.end(), paux);
paux = *pos;
bits.clear();
while((paux.ptr->pai != null))
{
if(!(paux != paux.ptr->pai.ptr->esq))
bit = 1;
else
bit = 0;
bits.insert(bits.begin(), bit);
paux = paux.ptr->pai;
}
return bits;
}
unsigned int codifica_arquivo(list<pnodo> &arv, ifstream &ent, FILE *sai)
{
list<unsigned char> codigo;
list<unsigned char>::iterator i;
unsigned int contabits=0;
char c;
ent.close();
ent.open(nome_arquivo_entrada);
ent.get(c);
while( ! ent.eof() ) {
codigo = obtem_codigo(c, arv);
i = codigo.begin();
cout << " ";
while(i != codigo.end()) {
contabits++;
cout<<(int)*i;
escreve_bit(sai, *i++);
}
ent.get(c);
}
for(unsigned int i=0; i<8-(contabits%8); i++) { // completa o ultimo byte
escreve_bit(sai, 0);
}
return contabits;
}
int main()
{
list<pnodo> freqs;
priority_queue< pnodo, deque<pnodo>, greater<pnodo> > fp;
FILE *arq_sai;
pnodo raiz;
long tamanho1=0, bits=0;
int num_nodos;
ifstream arq_ent(nome_arquivo_entrada);
if (! arq_ent.is_open() ) {
cout << "Não pude abrir o arquivo de entrada teste.txt";
getch();
exit(1);
}
arq_sai = fopen("teste_sai.bin", "wb");
if (arq_sai == NULL) {
cout << "Não pude abrir o arquivo de saida teste_sai.bin";
getch();
exit(1);
}
freqs = conta_frequencia(arq_ent);
cout << freqs; //depuração
copia_lista(freqs, fp);
cout << endl << "Fila: \t" << fp << endl << endl; //depuração
raiz = gera_arvore(fp);
imprime_arvore(raiz, 0); //depuração
num_nodos = freqs.size();
fwrite(&num_nodos, sizeof(int), 1, arq_sai);
grava_frequencias(freqs, arq_sai);
tamanho1 = ftell(arq_sai);
cout << "\nBytes do Código: "<<ftell(arq_sai); //depuração
cout << endl; // debug
fwrite(&bits, sizeof(int), 1, arq_sai); // reserva espaço para o número de bits escritos
bits = codifica_arquivo(freqs, arq_ent, arq_sai);
cout << "\nNúmero de Bits Codificados: " << bits << endl;
cout << "\nTamanho total do arquivo compactado: "<<ftell(arq_sai)<<" bytes";
fseek(arq_sai, tamanho1, SEEK_SET); // posiciona no local com o numero de bytes da codificacao
fwrite(&bits, sizeof(int), 1, arq_sai); // grava o tamanho da codificacao (em bits)
fcloseall();
getch();
return 0;
}
#endif