Support de la décompression
This commit is contained in:
parent
ef8d547f6b
commit
deb22164d4
4
Makefile
4
Makefile
|
@ -6,7 +6,7 @@ OUT=out/
|
||||||
|
|
||||||
# Configuration du compilateur
|
# Configuration du compilateur
|
||||||
CC=gcc
|
CC=gcc
|
||||||
CFLAGS=-Wall -std=c99 -I$(INC)
|
CFLAGS=-Wall -std=c99 -I$(INC) -g
|
||||||
|
|
||||||
# Objets et exécutables à construire
|
# Objets et exécutables à construire
|
||||||
PROG=huffman
|
PROG=huffman
|
||||||
|
@ -29,6 +29,8 @@ $(OUT)$(PROG): $(OBJECTS)
|
||||||
$(OUT)buffer.o: $(SRC)buffer.c $(INC)buffer.h
|
$(OUT)buffer.o: $(SRC)buffer.c $(INC)buffer.h
|
||||||
$(OUT)compress.o: $(SRC)compress.c $(INC)compress.h $(INC)common.h \
|
$(OUT)compress.o: $(SRC)compress.c $(INC)compress.h $(INC)common.h \
|
||||||
$(INC)display.h
|
$(INC)display.h
|
||||||
|
$(OUT)decompress.o: $(SRC)decompress.c $(INC)decompress.h $(INC)buffer.h \
|
||||||
|
$(INC)display.h $(INC)huftree.h
|
||||||
$(OUT)display.o: $(SRC)display.c $(INC)display.h $(INC)common.h
|
$(OUT)display.o: $(SRC)display.c $(INC)display.h $(INC)common.h
|
||||||
$(OUT)huftree.o: $(SRC)huftree.c $(INC)huftree.h $(INC)common.h
|
$(OUT)huftree.o: $(SRC)huftree.c $(INC)huftree.h $(INC)common.h
|
||||||
$(OUT)main.o: $(SRC)main.c $(INC)compress.h $(INC)common.h
|
$(OUT)main.o: $(SRC)main.c $(INC)compress.h $(INC)common.h
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
#ifndef __IN303_DECOMPRESS_H__
|
||||||
|
#define __IN303_DECOMPRESS_H__
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
void decompress(FILE* source, FILE* dest);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,54 @@
|
||||||
|
#include "huftree.h"
|
||||||
|
#include "buffer.h"
|
||||||
|
#include "display.h"
|
||||||
|
#include "decompress.h"
|
||||||
|
|
||||||
|
void decompress(FILE* source, FILE* dest) {
|
||||||
|
// ÉTAPE 1 : lecture du nombre de caractères originel. Cela permet
|
||||||
|
// d'ignorer les bits d'alignement en fin de fichier
|
||||||
|
size_t original_count = 0;
|
||||||
|
fread(&original_count, sizeof(size_t), 1, source);
|
||||||
|
printVerbose("Lecture du nombre de caractères : %d.\n", original_count);
|
||||||
|
|
||||||
|
// ÉTAPE 2 : reconstruction de l'arbre à partir des données linéarisées
|
||||||
|
printVerbose("Reconstruction de l'arbre de Huffman.\n");
|
||||||
|
ReadBuffer input = createReadBuffer(source);
|
||||||
|
HufTree tree = readTree(&input);
|
||||||
|
|
||||||
|
if (isVerbose()) {
|
||||||
|
printTree(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ÉTAPE 3 : lecture des données compressées et interprétation grâce
|
||||||
|
// à l'arbre de Huffman reconstitué
|
||||||
|
printVerbose("\nLecture et interprétation des données compressées.\n");
|
||||||
|
char next_bit = getBuffer(&input);
|
||||||
|
size_t wrote_count = 0;
|
||||||
|
|
||||||
|
while (next_bit != -1 && wrote_count < original_count) {
|
||||||
|
HufTree current = tree;
|
||||||
|
|
||||||
|
// Descente dans l'arbre, allant à gauche si un '0' est rencontré
|
||||||
|
// ou à droite si un '1' est rencontré. Arrêt dès l'arrivée sur
|
||||||
|
// une feuille
|
||||||
|
while (
|
||||||
|
next_bit != -1 &&
|
||||||
|
current->child_l != NULL && current->child_r != NULL
|
||||||
|
) {
|
||||||
|
if (next_bit == 0) {
|
||||||
|
current = current->child_l;
|
||||||
|
} else {
|
||||||
|
current = current->child_r;
|
||||||
|
}
|
||||||
|
|
||||||
|
next_bit = getBuffer(&input);
|
||||||
|
}
|
||||||
|
|
||||||
|
// La valeur de la feuille trouvée est le caractère compressé :
|
||||||
|
// on l'écrit dans le fichier
|
||||||
|
fputc(current->name, dest);
|
||||||
|
wrote_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
freeTree(tree);
|
||||||
|
}
|
15
src/main.c
15
src/main.c
|
@ -1,6 +1,7 @@
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
#include "compress.h"
|
#include "compress.h"
|
||||||
|
#include "decompress.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <argp.h>
|
#include <argp.h>
|
||||||
|
@ -72,10 +73,7 @@ static error_t parse_opt(int key, char* arg, struct argp_state* state) {
|
||||||
|
|
||||||
case ARGP_KEY_END:
|
case ARGP_KEY_END:
|
||||||
if (state->arg_num < 1) {
|
if (state->arg_num < 1) {
|
||||||
argp_error(
|
argp_error(state, "Fichier d'entrée manquant");
|
||||||
state, "Fichier d'entrée manquant (le premier argument "
|
|
||||||
" est obligatoire)"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -102,7 +100,7 @@ static struct argp_option options[] = {
|
||||||
{
|
{
|
||||||
.name = "decompress",
|
.name = "decompress",
|
||||||
.key = 'd',
|
.key = 'd',
|
||||||
.doc = "Décompresse SOURCE vers DEST"
|
.doc = "Décompresse SOURCE vers DEST au lieu de compresser"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "verbose",
|
.name = "verbose",
|
||||||
|
@ -116,8 +114,8 @@ static struct argp argp = {
|
||||||
.options = options,
|
.options = options,
|
||||||
.parser = parse_opt,
|
.parser = parse_opt,
|
||||||
.args_doc = "SOURCE [DEST]",
|
.args_doc = "SOURCE [DEST]",
|
||||||
.doc = "Compresse ou décompresse SOURCE vers DEST en utilisant "
|
.doc = "Compresse SOURCE vers DEST (par défaut, vers la sortie standard) "
|
||||||
"l'algorithme de Huffman (par défaut, compresse SOURCE vers DEST)."
|
"en utilisant l'algorithme de Huffman"
|
||||||
};
|
};
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
|
@ -147,8 +145,7 @@ int main(int argc, char** argv) {
|
||||||
if (args.compress) {
|
if (args.compress) {
|
||||||
compress(args.source, args.dest);
|
compress(args.source, args.dest);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Décompression non-implémentée.\n");
|
decompress(args.source, args.dest);
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fermeture des flux et sortie
|
// Fermeture des flux et sortie
|
||||||
|
|
Loading…
Reference in New Issue