update tp-huffman

This commit is contained in:
2024-10-24 16:29:20 +02:00
parent a65075b162
commit af83ce0117
34 changed files with 1745 additions and 0 deletions

49
tp-huffman/Makefile Normal file
View File

@@ -0,0 +1,49 @@
# CC=gcc or clang or gcc-14 (on OSX)
CC=gcc
# Math, big numbers and SDL2 fonts
LDLIBS=-lm
# The DEBUG_LEVEL (OFF, CRITICAL, ERROR, WARNING, INFO, TRACE)
# is set by default to WARNING in error.h.
# To set it on the command line, force compilation and set it.
# Example: make -B CFLAGS="-DDEBUG_LEVEL=INFO" to see all debug messages
# above the 'INFO' level.
# clang 14.0.3 does implement the C23 feature __VA_OPTS__ but issues a spurious
# warning. The -Wno-gnu-zero-variadic-macro-arguments disables this warning.
# This flag is ignored by gcc (which implements __VA_OPTS__ without any warning).
ifeq ($(shell uname -s), Darwin)
override CFLAGS += -std=gnu2x -MMD -Wall -pedantic -Wextra -Wshadow -Wpointer-arith \
-Wcast-qual -Wstrict-prototypes -Wmissing-prototypes -Wno-gnu-zero-variadic-macro-arguments
endif
ifeq ($(shell uname -s), Linux)
override CFLAGS += -std=gnu2x -MMD -Wall -pedantic -Wextra -Wshadow -Wpointer-arith \
-Wcast-qual -Wstrict-prototypes -Wmissing-prototypes
endif
SOURCES := $(wildcard *.c)
OBJECTS := $(SOURCES:%.c=%.o)
DEPS := $(SOURCES:%.c=%.d)
OBJECTS_NO_SOURCE = dequeue.o
# Compilation in debug mode by default, to use gdb and valgrind. Warnings produce an error.
all: CFLAGS += -g -O0 -Werror -Wno-unused-parameter -Wno-unused-function
all: tp
# Once the program works, optimized mode (and no error in case of warning).
nowerror: CFLAGS += -O3 -Wunused-parameter
nowerror: tp
# Add parser.o scan.o if bison/flex interface.
tp: $(OBJECTS) $(OBJECTS_NO_SOURCE)
$(CC) -o $@ $(LDFLAGS) $(CFLAGS) $^ $(LDLIBS)
# Include dependancies generated by gcc -MMD.
-include $(DEPS)
# Clean all.
.PHONY: clean
clean:
rm -f $(OBJECTS) $(DEPS) tp TAGS core

19
tp-huffman/alloc.c Normal file
View File

@@ -0,0 +1,19 @@
/**
* @file alloc.c
* @brief Fonctions d'allocation mémoire.
*/
#include "alloc.h"
void check_null(const char *function, char *file, int line, int n, ...) {
va_list ap;
char *s;
va_start(ap, n);
for (int i = 0; i < n; i++) {
void *p = va_arg(ap, void *);
s = va_arg(ap, char *);
if (p == NULL)
PRINT_ERROR(KO, "CRITICAL", function, file, line, "%s is NULL.", s);
}
}

1
tp-huffman/alloc.d Normal file
View File

@@ -0,0 +1 @@
alloc.o: alloc.c alloc.h error.h

182
tp-huffman/alloc.h Normal file
View File

@@ -0,0 +1,182 @@
/**
* @file alloc.h
* @brief Macros et fonctions d'allocation mémoire.
*
* @details Les macros MALLOC(), CALLOC() et REALLOC() définies dans ce fichier
* permettent d'allouer de la mémoire dynamiquement, en vérifiant que
* l'allocation a réussi. En cas d'échec, elles affichent un message d'erreur
* sur la sortie erreur, en indiquant la fonction, le fichier et la ligne où
* l'allocation a échoué, et quittent le programme.
*
* La fonction multiple_free() permet de libérer plusieurs pointeurs en
* un seul appel (mais attention, aucun de ces pointeurs ne doit être `NULL`, et
* tous doivent avoir été alloués dynamiquement avant cette libération).
*
* La macro CHECK_NULL() permet de vérifier qu'un ou plusieurs pointeurs ne sont
* pas `NULL`.
*
* La fonction check_null() n'est pas destinée à être utilisée directement, mais
* est utilisée par la macro CHECK_NULL().
*/
#ifndef ALLOC_H_
#define ALLOC_H_
#include "error.h"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
/**
* @brief Macro pour allouer de la mémoire en utilisant la fonction malloc().
* @param p Pointeur à allouer.
* @param num_objects Nombre d'objets à allouer.
*
* @details
* Alloue de la mémoire permettant de stocker `num_objects`, chacun de type
* `*p`.
*
* **Exemple d'utilisation :**
* ```
* backmove *p;
* MALLOC(p, 10); // Alloue un tableau de 10 backmove.
* ```
*
* Si l'allocation échoue, affiche un message d'erreur et quitte le programme.
*
* @attention
* Le pointeur `p` doit avoir été déclaré, mais ne pas pointer vers une zone
* déjà allouée dynamiquement (sous peine de créer une fuite mémoire).
* Si `p` pointe déjà vers une zone allouée dynamiquement, il faut utiliser
* REALLOC.
*
* @see REALLOC()
*/
#define MALLOC(p, num_objects) \
do { \
void *tmp = malloc(sizeof *(p) * (num_objects)); \
if (!tmp) { \
FATAL("Malloc error."); \
} \
(p) = tmp; \
} while (0)
/**
* @brief Macro pour allouer de la mémoire en utilisant la fonction calloc().
* @param p Pointeur à allouer.
* @param num_objects Nombre d'objets à allouer.
*
* @details
* Alloue de la mémoire initialisée à 0, permettant de stocker `num_objects`,
* chacun de type `*p`.
*
* **Exemple d'utilisation :**
* ```
* backmove *p;
* CALLOC(p, 10); // Alloue un tableau de 10 backmove, initialisé à 0.
* ```
*
* Si l'allocation échoue, affiche un message d'erreur et quitte le programme.
*
* @attention
* Le pointeur `p` doit avoir été déclaré, mais ne pas pointer vers une zone
* déjà allouée dynamiquement (sous peine de créer une fuite mémoire).
* Si `p` pointe déjà vers une zone allouée dynamiquement, il faut utiliser
* REALLOC.
*
* @sa REALLOC()
*/
#define CALLOC(p, num_objects) \
do { \
void *tmp = calloc((num_objects), sizeof *(p)); \
if (!tmp) { \
FATAL("Calloc error."); \
} \
(p) = tmp; \
} \
while (0)
/**
* @brief Macro pour réallouer de la mémoire en utilisant la fonction realloc().
* @param p Pointeur à allouer.
* @param num_objects Nouveau nombre d'objets à allouer.
*
* Ré-alloue la mémoire pointée par un pointeur p, dont la valeur doit avoir été
* retournée précédemment par une fonction d'allocation dynamique (malloc,
* calloc, realloc ou une des macros de ce fichier).
*
* Si l'allocation échoue, affiche un message d'erreur et quitte le programme.
*
* **Exemple d'utilisation :**
* ```
* backmove *p;
* MALLOC(p, 10); // Alloue un tableau de 10 backmove.
* // ...
* REALLOC(p, 20); // Ré-alloue un tableau de 20 backmove en copiant le tableau
* // précédent en début ce nouveay tableau, et affecte à p
* // l'adresse de la première case de ce tableau.
* ```
*
* Si l'allocation échoue, affiche un message d'erreur et quitte le programme.
*
* @attention
* Le pointeur `p` doit avoir été déclaré et pointer vers une zone
* déjà allouée dynamiquement.
*
* @sa MALLOC(), CALLOC()
*/
#define REALLOC(p, num_objects) \
do { \
void *tmp = realloc((p), sizeof *(p) * (num_objects)); \
if (!tmp) { \
FATAL("Realloc error."); \
} \
(p) = tmp; \
} while (0)
/**
* @brief Macro permettant de tester si un ou plusieurs pointeurs sont NULL.
* @param n Nombre de pointeurs à tester.
* @param ... Pointeurs à tester, en alternance avec des chaînes de caractères.
*
* Il doit y avoir un pointeur à tester pour chaque chaîne de caractères, et
* inversement.
*
* La chaîne de caractères qui suit chaque pointeur permet de personnaliser le
* message d'erreur.
*
* @details
* **Exemple d'utilisation :**
* ```
* CHECK_NULL(3, p1, "Name1", p2, "Name2", p3, "Name3");
* ```
* Ici, 3 est le nombre de pointeurs à vérifier, et p1, p2, p3 sont les
* pointeurs. Si `p1` et `p3` sont NULL, la macro affichera un message d'erreur
* de la forme :
***
[CRITICAL] Name1 is NULL!\n
[CRITICAL] Name3 is NULL!
***
* @sa check_null()
*/
#define CHECK_NULL(n, ...) \
check_null \
(__func__, __FILE__, __LINE__, \
n __VA_OPT__( , ) __VA_ARGS__)
/**
* @brief Ne pas utiliser cette fonction directement, mais à la place la macro
* ::CHECK_NULL(), qui indique dans le message la position de l'erreur dans le
* source.
*
* @sa CHECK_NULL()
*/
void check_null(const char *function, char *file, int line, int n, ...);
#endif // ALLOC_H_

BIN
tp-huffman/alloc.o Normal file

Binary file not shown.

138
tp-huffman/binheap.c Normal file
View File

@@ -0,0 +1,138 @@
#include "binheap.h"
/*************************/
/* Fonctions auxiliaires */
/*************************/
/* La fonction de comparaison pour les tas d'entiers */
bool fcmp_int(void *x, void *y) {
return *(int *)x < *(int *)y;
}
/* Fonctions de navigation dans un arbre représenté par un tableau */
int left_binheap(int i) {
return i*2+1;
}
int right_binheap(int i) {
return i*2+2;
}
int parent_binheap(int i) {
return (i-1)/2;
}
bool isvalid_binheap(binheap *p, int i) {
return i < p->size_heap;
}
/* Modification de la taille du tableau */
static void grow_binheap(binheap *p) {
p->size_array *= 2;
p->array = realloc(p->array, p->size_array * sizeof(void *));
if (p->array == NULL) {
ERROR("Erreur d'allocation mémoire\n");
exit(EXIT_FAILURE);
}
}
static void shrink_binheap(binheap *p) {
p->size_array /= 2;
p->array = realloc(p->array, p->size_array * sizeof(void *));
if (p->array == NULL) {
ERROR("Erreur d'allocation mémoire\n");
exit(EXIT_FAILURE);
}
}
/************************/
/* Fonctions primitives */
/************************/
/* Création d'un tas vide */
binheap *create_binheap(bool (*fc)(void *, void *)) {
binheap *p = malloc(sizeof(binheap));
if (p == NULL) {
ERROR("Erreur d'allocation mémoire\n");
exit(EXIT_FAILURE);
}
p->array = malloc(1 * sizeof(void *));
if (p->array == NULL) {
ERROR("Erreur d'allocation mémoire\n");
exit(EXIT_FAILURE);
}
p->size_array = 1;
p->size_heap = 0;
p->fc = fc;
return p;
}
/* Suppression */
void delete_binheap(binheap *p) {
if (p != NULL) {
if (p->array != NULL) {
free(p->array);
}
free(p);
}
}
/* Test du vide */
bool isempty_binheap(binheap *p) {
return p == NULL || p->size_heap == 0;
}
/* Récupération de la taille */
int getsize_binheap(binheap *p) {
return p->size_heap;
}
/* Insertion d'une valeur */
void push_binheap(binheap *p, void *val) {
if (p->size_heap == p->size_array) {
grow_binheap(p);
}
p->array[p->size_heap] = val;
p->size_heap++;
int i = p->size_heap - 1;
while (i > 0 && p->fc(p->array[i], p->array[parent_binheap(i)])) {
void *temp = p->array[i];
p->array[i] = p->array[parent_binheap(i)];
p->array[parent_binheap(i)] = temp;
i = parent_binheap(i);
}
}
/* Récupération du minimum sans le retirer */
void *peekmin_binheap(binheap *p) {
if (isempty_binheap(p)) {
return NULL;
}
return p->array[0];
}
/* Récupération du minimum en le retirant */
void *popmin_binheap(binheap *p) {
if (isempty_binheap(p)) {
return NULL;
}
void *min = p->array[0];
p->size_heap--;
p->array[0] = p->array[p->size_heap];
int i = 0;
while (isvalid_binheap(p, left_binheap(i))) {
int j = left_binheap(i);
if (isvalid_binheap(p, right_binheap(i)) && p->fc(p->array[right_binheap(i)], p->array[j])) {
j = right_binheap(i);
}
if (p->fc(p->array[j], p->array[i])) {
void *temp = p->array[i];
p->array[i] = p->array[j];
p->array[j] = temp;
i = j;
} else {
break;
}
}
if (p->size_heap < p->size_array / 4) {
shrink_binheap(p);
}
return min;
}

1
tp-huffman/binheap.d Normal file
View File

@@ -0,0 +1 @@
binheap.o: binheap.c binheap.h alloc.h error.h

82
tp-huffman/binheap.h Normal file
View File

@@ -0,0 +1,82 @@
/************************************************************************/
/** Files de priorité: implémentation d'une tas binaire par un tableau **/
/************************************************************************/
#ifndef BINHEAP_H_
#define BINHEAP_H_
#include "alloc.h"
#include <stdbool.h>
#include <stdio.h>
// On travaille avec des tas génériques: le type des valeurs n'est pas fixé
// Pour ce faire, les éléments du tas seront des pointeurs génériques (void *).
// Le tas ne contiendra donc pas directement les valeurs mais des pointeurs
// sur celles-ci.
//
// Puisque le type des valeurs n'est pas fixé, la fonction de comparaison qui
// sert à ordonner les éléments du tas est un paramètre de ce tas. On utilise
// pour cela des pointeurs de fonctions: un des champs du type sera un pointeur
// sur une fonction qui associe un Booléen à deux éléments de type void * (qui
// indique si le premier est considéré comme "plus petit" que le deuxième).
typedef struct {
// Tableau stockant des pointeurs vers chaque valeur du tas
void **array;
// Taille totale du tableau
int size_array;
// Taille du tas (nombres de case utilisées dans le tableau)
int size_heap;
// Pointeur sur la fonction de comparaison utilisée par le tas
bool (*fc)(void *, void *);
} binheap;
/*************************/
/* Fonctions auxiliaires */
/*************************/
/* La fonction de comparaison pour les tas d'entiers */
bool fcmp_int(void *x, void *y);
// Déjà écrite dans binheap.c
/* Fonctions de navigation dans un arbre représenté par un tableau */
int left_binheap(int i);
// Retourne l'indice du fils gauche du noeud à l'indice i
int right_binheap(int i); // Fils droit
// Retourne l'indice du fils droit du noeud à l'indice i
int parent_binheap(int i); // Parent
// Retourne l'indice du parent du noeud à l'indice i
bool isvalid_binheap(binheap *p, int i);
// Teste si l'indice i correspond à un noeud est valide dans le tas p
/************************/
/* Fonctions primitives */
/************************/
/* Création d'un tas vide */
binheap *create_binheap(bool (*)(void *, void *));
// Le paramètre est un pointeur de fonction
// Il faut lui donner l'adresse de la fonction de comparaison à utiliser
// Par exemple, pour créer un tas d'entier on appellera la primitive avec
// l'adresse de la fonction fcmp_int ci-dessus:
// p = create_binheap(&fcmp_int);
/* Suppression */
void delete_binheap(binheap *);
/* Test du vide */
bool isempty_binheap(binheap *);
/* Taille */
int getsize_binheap(binheap *);
/* Insertion d'une valeur */
void push_binheap(binheap *, void *);
/* Récupération du minimum sans le retirer */
void *peekmin_binheap(binheap *);
/* Récupération du minimum en le retirant */
void *popmin_binheap(binheap *);
#endif

BIN
tp-huffman/binheap.o Normal file

Binary file not shown.

92
tp-huffman/dequeue.h Normal file
View File

@@ -0,0 +1,92 @@
/******************************************************/
/** Implémentation des tuyaux étendus par un tableau **/
/******************************************************/
// Ce module permet de manipuler des tuyaux, et même en fait une extension du
// type vu en cours d'algorithmique. En plus de pouvoir ajouter ou retirer un
// élément à gauche ou à droite du tuyau, on peut aussi lire la i-ème valeur à
// partir de la gauche ou de la droite (en revanche, on ne peut pas écrire "au
// milieu" d'un tuyau). Voir les fonctions leftread et rightread.
//
// Ces tuyaux étendus sont implémentés par un tableau dynamique. Les fonctions
// auxiliaires grow_dequeue et shrink_dequeue permettent de modifier la taille
// du tableau en conséquence. La fonction print_dequeue permet d'afficher le
// contenu du tuyau.
//
// Une version compilée Linux de ce module vous est fournie : dequeue.o.
#ifndef DEQUEUE_H_
#define DEQUEUE_H_
#include <stdbool.h>
/**********************/
/* Définition du type */
/**********************/
typedef struct {
int *array; // Tableau des valeurs
int size_array; // Taille du tableau des valeurs
int left; // Indice de la valeur à gauche du tuyau (si non-vide).
int right; // Indice qui suit celui de la valeur à droite du tuyau (si
// non-vide).
bool empty; // Booléen indiquant si le tuyau est vide.
} dequeue;
/*************************/
/* Fonctions auxiliaires */
/*************************/
// Double la taille du tableau utilisé dans la représentation.
void grow_dequeue(dequeue *);
// Divise par deux la taille du tableau utilisé dans la représentation
// (on supposera que seulement la moitié des cases sont utilisées dans
// la représentation).
void shrink_dequeue(dequeue *);
/************************/
/* Fonctions primitives */
/************************/
// Création
dequeue *create_dequeue(void);
// Suppression
void delete_dequeue(dequeue *);
// Taille
int getsize_dequeue(dequeue *p);
// Test du vide
bool isempty_dequeue(dequeue *);
// Insertion
void leftinsert(int, dequeue *);
void rightinsert(int, dequeue *);
// Lecture
// Les deux fonctions suivantes étendent le type abstrait tuyau vu en TD.
// En effet, elles permettent de lire la i-ème valeur à partir de la gauche ou
// de la droite, ce qui n'était pas possible avec le type abstrait tuyau.
// Lit la ième valeur en partant de la gauche (la première à gauche a pour
// indice 0).
int leftread(dequeue *, int i);
// Lit la ième valeur en partant de la droite (la première à droite a pour
// indice 0).
int rightread(dequeue *, int i);
// Suppression
int leftpull(dequeue *);
int rightpull(dequeue *);
// Affichage d'un tuyau
// Cette primitive est déjà écrite. Utilisez-la pour vos tests.
void print_dequeue(dequeue *p);
#endif // DEQUEUE_H_

1
tp-huffman/dequeue.o Symbolic link
View File

@@ -0,0 +1 @@
dequeue_x86-64.o

BIN
tp-huffman/dequeue_arm64.o Normal file

Binary file not shown.

BIN
tp-huffman/dequeue_x86-64.o Normal file

Binary file not shown.

58
tp-huffman/error.h Normal file
View File

@@ -0,0 +1,58 @@
#ifndef ERROR_H_
#define ERROR_H_
#define ATTENTION "\xe2\x9d\x97"
#define HINT "\xe2\x9c\xa8"
#define OK "\xE2\x9C\x85"
#define KO "\xE2\x9D\x8C"
// In X mode, all messages more severe than X are printed.
// clang-format off
enum debug_level {OFF, CRITICAL, ERROR, WARNING, INFO, DEBUG, TRACE};
enum msg_level {CRITICAL_L, ERROR_L, WARNING_L, INFO_L, DEBUG_L, TRACE_L};
// clang-format on
#ifndef DEBUG_LEVEL
#define DEBUG_LEVEL INFO
#endif
// __VA_OPTS__ requires C2x. Clang issues spurious warning.
#define PRINT_ERROR(symbol, name, function, file, line, msg, ...) \
do { \
fprintf(stderr, \
"\n" symbol \
" [" \
name \
"]" \
" - Function %s (%s:%d) -\n " \
msg "\n", \
function, file, line \
__VA_OPT__( , ) __VA_ARGS__); \
} while (0)
#define FATAL(msg, ...) \
do { \
PRINT_ERROR(ATTENTION, "FATAL", __func__, __FILE__, __LINE__, msg __VA_OPT__( , ) __VA_ARGS__); \
exit(EXIT_FAILURE); \
} while (0)
#define PRINT_DEBUG(symbol, name, level, msg, ...) \
do { \
if ((int)DEBUG_LEVEL > (int)level) \
PRINT_ERROR(symbol, name, __func__, __FILE__, __LINE__, msg __VA_OPT__( , ) __VA_ARGS__); \
} while (0)
#define TRACE(msg, ...) PRINT_DEBUG(OK, "TRACE", TRACE_L, msg, __VA_ARGS__)
#define DEBUG(msg, ...) PRINT_DEBUG(HINT, "DEBUG", DEBUG_L, msg, __VA_ARGS__)
#define INFO(msg, ...) PRINT_DEBUG(HINT, "INFO", INFO_L, msg, __VA_ARGS__)
#define WARNING(msg, ...) PRINT_DEBUG(ATTENTION, "WARNING", WARNING_L, msg, __VA_ARGS__)
#define ERROR(msg, ...) PRINT_DEBUG(ATTENTION, "ERROR", ERROR_L, msg, __VA_ARGS__)
#define CRITICAL(msg, ...) PRINT_DEBUG(KO, "CRITICAL", CRITICAL_L, msg, __VA_ARGS__)
#endif // ERROR_H_

59
tp-huffman/huffcomp.c Normal file
View File

@@ -0,0 +1,59 @@
/************************************/
/** Codage de Huffman: Compression **/
/************************************/
#include "huffcomp.h"
/**********************************/
/* Fonctions manipulant les codes */
/**********************************/
/* Construction du tableau des codes à partir de l'arbre de Huffman */
huffcode **create_huffdict(huffnode *tree) {
// À écrire
return NULL;
}
/* Suppression du tableau de code */
void delete_huffdict(huffcode **dict) {
// À écrire
}
/***********************************************/
/** Fonction pour la compression d'un fichier **/
/***********************************************/
/* Écriture d'un unsigned int sur 4 octets dans un fichier */
void write_size(FILE *output, unsigned int size) {
// À écrire
}
/* Insertion d'un code à droite d'un tuyau servant de tampon */
void insert_code_in_buffer(dequeue *buffer, huffcode *code) {
// À écrire
}
/* Calcule l'octet correspondant aux 8 derniers éléments d'un tuyau servant de
* tampon */
int buffer_to_byte(dequeue *buffer) {
// À écrire
return 0;
}
/* Procédure de compression */
void compress_file(FILE *in, FILE *out) {
/* Phase 1: calcul de la taille de l'arbre et du dictionnaire à partir du
* fichier source */
// À écrire
/* Phase 2: écriture de la taille du fichier original */
// À écrire
/* Phase 3: écriture de l'arbre en représentation préfixe */
// À écrire
/* Phase 4: écriture du codage */
}

2
tp-huffman/huffcomp.d Normal file
View File

@@ -0,0 +1,2 @@
huffcomp.o: huffcomp.c huffcomp.h alloc.h error.h dequeue.h hufftree.h \
binheap.h

71
tp-huffman/huffcomp.h Normal file
View File

@@ -0,0 +1,71 @@
/************************************/
/** Codage de Huffman: Compression **/
/************************************/
#ifndef HUFFCOMP_H_
#define HUFFCOMP_H_
#include "alloc.h"
#include "dequeue.h"
#include "hufftree.h"
#include <stdbool.h>
#include <stdio.h>
/************************************************/
/* Type utilisé pour stocker un code de Huffman */
/************************************************/
// Type pour représenter un seul code
typedef struct {
// Le nombre de bits dans le code (un code n'aura jamais plus de 256 bits).
unsigned char size;
// Le tableau qui stocke le code : les valeurs sont toutes 0 ou 1.
unsigned char *code;
} huffcode;
// Le dictionnaire contiendra tous les codes.
// Il sera de type huffcode **, et pointera vers 256 cases.
// Chacun de ses éléments sera donc de type huffcode *.
// Pour les valeurs i ayant un code, la ième case contient ce code
// Pour les valeurs i n'ayant pas de code (de fréquence nulle), la ième case
// contient NULL.
/********************************************/
/* Fonction de construction du dictionnaire */
/********************************************/
// Construction du dictionnaire à partir de l'arbre de Huffman.
huffcode **create_huffdict(huffnode *tree);
// Suppression du dictionnaire
void delete_huffdict(huffcode **dict);
/***********************************************/
/** Fonction pour la compression d'un fichier **/
/***********************************************/
// Écriture d'un unsigned int sur 4 octets dans un fichier.
// output doit être ouvert en écriture.
void write_size(FILE *output, unsigned int size);
// Insertion de tous les bits d'un code à droite d'un tuyau tampon.
// Le tuyau est supposé contenir une séquence de 0 et de 1.
void insert_code_in_buffer(dequeue *buffer, huffcode *code);
// Calcule l'octet correspondant aux 8 premiers bits à gauche d'un tuyau tampon.
// Le tuyau est supposé contenir une séquence de bits (0 ou 1) de longueur au
// moins 8 Les 8 bits lus doivent être supprimés du tuyau.
int buffer_to_byte(dequeue *buffer);
// Fonction de compression du fichier input dans output.
// input doit être ouvert en lecture.
// output doit être ouvert en écriture.
// Le fichier output devra contenir dans l'ordre :
// 1) La taille de input codée sur 4 octets
// 2) La sauvegarde de l'arbre de Huffman obtenu à partir de input.
// 3) Le codage de input.
void compress_file(FILE *input, FILE *output);
#endif

BIN
tp-huffman/huffcomp.o Normal file

Binary file not shown.

34
tp-huffman/huffdecomp.c Normal file
View File

@@ -0,0 +1,34 @@
#include "huffdecomp.h"
/**************************************************/
/**************************************************/
/** Fonctions pour la décompression d'un fichier **/
/**************************************************/
/**************************************************/
/* Lecture de la taille du fichier décompressé dans le fichier compressé */
unsigned int read_size(FILE *in) {
// À écrire
return 0;
}
// Décodage d'une valeur à partir d'un arbre de Huffman
int read_huffcode(FILE *in, dequeue *deq, huffnode *thetree) {
// À écrire
return 0;
}
/* Décompression */
void decompress_file(FILE *in, FILE *out) {
/* Phase 1: lecture de la taille du fichier décompressé */
// À écrire
/* Phase 2: lecture de l'arbre de Huffman */
// À écrire
/* Phase 3: décodage */
// À écrire
}

2
tp-huffman/huffdecomp.d Normal file
View File

@@ -0,0 +1,2 @@
huffdecomp.o: huffdecomp.c huffdecomp.h alloc.h error.h dequeue.h \
hufftree.h binheap.h

40
tp-huffman/huffdecomp.h Normal file
View File

@@ -0,0 +1,40 @@
/**************************************/
/** Codage de Huffman: Décompression **/
/**************************************/
#ifndef HUFFDECOMP_H_
#define HUFFDECOMP_H_
#include "alloc.h"
#include "dequeue.h"
#include "hufftree.h"
#include <stdbool.h>
#include <stdio.h>
// Lecture de la taille du fichier décompressé dans le fichier compressé.
// Le fichier doit être ouvert en lecture.
// La taille est codée sur les 4 premiers octets.
unsigned int read_size(FILE *in);
// Lecture d'un code de Huffman à partir du buffer et du fichier compressé.
// Le fichier doit être ouvert en lecture.
//
// Lit un code entier et retourne la valeur qui lui est associée par l'arbre de
// Huffman.
//
// Tant que le buffer est non-vide, c'est dans celui-ci qu'on lit.
//
// Si le buffer est vide, on lit un octet dans le fichier pour insérer ses 8
// bits dans le buffer.
//
// Le buffer est potentiellement non-vide à la fin de la lecture d'un code. Les
// bits qui restent dans le buffer font partie du prochain code à lire.
int read_huffcode(FILE *in, dequeue *deq, huffnode *thetree);
// Procédure de décompression.
// Le flux in doit être ouvert en lecture.
// Le flux out doit être ouvert en écriture.
// Décompresse le fichier in et écrit la version décompressée dans out.
void decompress_file(FILE *in, FILE *out);
#endif

BIN
tp-huffman/huffdecomp.o Normal file

Binary file not shown.

85
tp-huffman/hufftree.c Normal file
View File

@@ -0,0 +1,85 @@
#include "hufftree.h"
/************************************/
/* Primitives des arbres de Huffman */
/************************************/
/* Création d'une feuille */
huffnode *create_huffleaf(int byte, int freq) {
// À écrire
return NULL;
}
/* Fusion de deux arbres avec un nouveau noeud racine */
huffnode *merge_hufftree(huffnode *pl, huffnode *pr) {
// À écrire
return NULL;
}
/* Teste si un noeud est une feuille */
bool isleaf_huffnode(huffnode *p) {
// À écrire
return true;
}
/* Retourne la valeur de l'octet correspondant à un noeud */
int getbyte_huffnode(huffnode *p) {
// À écrire
return 0;
}
/* Retournent les fils d'un noeud */
huffnode *getleft_huffnode(huffnode *p) {
// À écrire
return NULL;
}
huffnode *getright_huffnode(huffnode *p) {
// À écrire
return NULL;
}
/* Libération d'un arbre */
void free_hufftree(huffnode *p) {
// À écrire
}
/**********************************************/
/* Fonctions manipulant les arbres de Huffman */
/**********************************************/
/* Comparaison de deux arbres */
bool compare_hufftree(void *p1, void *p2) {
// À écrire
return true;
}
/* Création de l'arbre de Huffman à partir du fichier à compresser */
huffnode *datafile_to_hufftree(FILE *input) {
/* Phase 1: création du tableau de fréquences */
// À écrire
/* Phase 2: intialisation de la file de priorité à partir du tableau de
* fréquences */
// À écrire
/* Phase 3: création de l'arbre de Huffman à partir de la file de priorités */
// À écrire
return NULL;
}
/* Écriture de l'arbre de Huffman dans le futur fichier compressé */
void save_hufftree(huffnode *p, FILE *f) {
// À écrire
}
/* Lecture de l'arbre de Huffman dans le fichier compressé */
huffnode *read_hufftree(FILE *f) {
// À écrire
return NULL;
}

1
tp-huffman/hufftree.d Normal file
View File

@@ -0,0 +1 @@
hufftree.o: hufftree.c hufftree.h alloc.h error.h binheap.h

98
tp-huffman/hufftree.h Normal file
View File

@@ -0,0 +1,98 @@
/**************************************/
/** Les arbres de Huffman **/
/** Implémentation par des pointeurs **/
/**************************************/
#ifndef HUFFTREE_H_
#define HUFFTREE_H_
#include "alloc.h"
#include "binheap.h"
#include <stdbool.h>
#include <stdio.h>
/*******************************************/
/* Type utilisé pour les arbres de Huffman */
/*******************************************/
// Chaque objet correspond à un noeud de l'arbre.
// On identifie un arbre avec un pointeur vers son noeud racine.
//
// Cela explique pourquoi les fonctions manipulant les arbres prennent en
// argument un pointeur vers un noeud, et que leur nom se termine soit par
// _huffnode, soit par _hufftree.
typedef struct huffnode {
// Fréquence
int freq;
// Octet codé par le noeud (significatif seulement si le noeud est une
// feuille)
int byte;
// Enfant gauche (NULL si pas de fils gauche)
struct huffnode *leftchild;
// Enfant droit (NULL si pas de fils droit)
struct huffnode *rightchild;
} huffnode;
/************************************/
/* Primitives des arbres de Huffman */
/************************************/
// Création d'une feuille.
// Les paramètres servent à initialiser les champs byte et freq (dans cet
// ordre).
huffnode *create_huffleaf(int byte, int freq);
// Fusion de deux arbres non-vides en utilisant un nouveau noeud racine.
// La fréquence du nouveau noeud sera la somme de celles de ses deux enfants
// Le champ byte du nouveau noeud n'est pas significatif (car ce n'est pas une
// feuille).
huffnode *merge_hufftree(huffnode *pl, huffnode *pr);
// Teste si un arbre est réduit à une seule feuille.
// On doit tester si les deux enfants du noeud racine sont NULL
bool isleaf_huffnode(huffnode *p);
// Retourne la valeur de l'octet codé dans un noeud.
// Ne doit être utilisé que sur les feuilles.
int getbyte_huffnode(huffnode *p);
// Retourne les enfants gauche et droit d'un noeud.
huffnode *getleft_huffnode(huffnode *p);
huffnode *getright_huffnode(huffnode *p);
// Libération complète d'un arbre de Huffman.
void free_hufftree(huffnode *p);
/**********************************************/
/* Fonctions manipulant les arbres de Huffman */
/**********************************************/
// Fonction de comparaison entre deux arbres de Huffman à utiliser pour le tas
// binaire. Les deux paramètres sont donc donnés par des void *. Il faut les
// convertir ces pointeurs de façon appropriée dans la fonction
// compare_hufftree.
//
// Le plus petit de deux arbres est celui dont la racine a la plus petite
// fréquence.
bool compare_hufftree(void *p1, void *p2);
// Création de l'arbre de Huffman à partir du fichier à compresser.
// Le fichier doit être ouvert en lecture.
// L'algorithme est basé sur les files de priorités.
huffnode *datafile_to_hufftree(FILE *input);
// Écriture de l'arbre de Huffman dans le futur fichier compressé.
// Le fichier doit être ouvert en lecture.
// On stocke l'arbre par une représentation préfixe.
void save_hufftree(huffnode *p, FILE *output);
// Lecture de l'arbre de Huffman dans un fichier.
// Le fichier doit être ouvert en lecture.
// La tête de lecture doit être positionnée au début du codage de l'arbre.
huffnode *read_hufftree(FILE *in);
#endif

BIN
tp-huffman/hufftree.o Normal file

Binary file not shown.

312
tp-huffman/main.c Normal file
View File

@@ -0,0 +1,312 @@
#include "alloc.h"
#include "binheap.h"
#include "error.h"
#include "huffcomp.h"
#include "huffdecomp.h"
#include "hufftree.h"
#include "testprint.h"
#include <getopt.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
void test_heap(int *tab, int size);
/********************************/
/* Fonction main pour les tests */
/********************************/
// clang-format off
static struct option long_options[] = {
{"help" , no_argument, NULL, 'h'},
{"tree" , no_argument , NULL, 'T'},
{"dict" , no_argument , NULL, 'D'},
{"decomp" , no_argument, NULL, 'd'},
{"heap" , optional_argument, NULL, 'H'},
{"output" , required_argument, NULL, 'o'},
{"seed" , required_argument, NULL, 's'},
//
{NULL, 0, NULL, 0}};
// clang-format on
#define DEFAULT_HEAP_SIZE 10
int size_heap = DEFAULT_HEAP_SIZE;
int seed = -1;
bool decompress_mode = false, test_binheap_mode = false, huffdict = false,
hufftree = false;
char *outfilename = NULL;
static void usage(char *progname) {
printf("\nUsage: %s [options]\n\n", progname);
printf("Options disponibles :\n"
"\t--help ou -h :"
"\n\t\tAffiche cette aide.\n"
"\n"
"\t--tree ou -T:"
"\n\t\tAffiche l'arbre de Huffman en cas de compression (ce n'est pas "
"fait par défaut).\n"
"\n"
"\t--dict ou -D:"
"\n\t\tAffiche le dictionnaire en cas de compression (ce n'est pas "
"fait par "
"défaut).\n"
"\n"
"\t--heap=<entier>ou -H<entier>:"
"\n\t\tTeste les fonctions de tas sur un tas de taille <entier> (%d "
"par défaut).\n"
"\n"
"\t--output=<nom_fichier> ou -o<nom_fichier> :"
"\n\t\tDéfinit le nom du fichier de sortie pour la décompression.\n"
"\n"
"\t--seed=<entier> ou -s<entier> :"
"\n\t\tDéfinit la graine du générateur aléatoire pour générer un "
"tableau.\n"
"\n",
DEFAULT_HEAP_SIZE);
}
static void parse_argv(int argc, char *argv[]) {
for (;;) {
int c = getopt_long(argc, argv, "hTdDs:o:H::", long_options, NULL);
if (c == -1)
break; // fin de lecture des options
switch (c) {
case 'h':
usage(argv[0]);
exit(EXIT_SUCCESS);
case 'H':
test_binheap_mode = true;
size_heap = (optarg == NULL) ? DEFAULT_HEAP_SIZE : atoi(optarg);
break;
case 's':
seed = atoi(optarg);
if (seed <= -1) {
ERROR("La graine doit être positive\n");
usage(argv[0]);
exit(EXIT_FAILURE);
}
break;
case 'd':
decompress_mode = true;
break;
case 'D':
huffdict = true;
break;
case 'T':
hufftree = true;
break;
case 'o':
outfilename = strdup(optarg);
break;
default:
break;
}
}
}
int main(int argc, char *argv[]) {
parse_argv(argc, argv);
// Initialisation du générateur de nombres aléatoires
// Voir man 3 srandom.
if (seed == -1) {
seed = time(NULL) % 1000;
INFO("Pour rejouer avec les mêmes tirages aléatoires: %s --seed=%d",
argv[0], seed);
}
srandom(seed);
// Vous pouvez ajouter des tests pour les tas binaires et les arbres de
// Huffman.
//
// Pensez à utiliser les fonctions disponibles dans testprint.h
// pour afficher les tas binaires et les arbres de Huffman
// printf("binheap null - \n"); print_binheap(NULL);
// binheap *heap = create_binheap(fcmp_int);
// print_binheap(heap);
// int v10 = 10;
// push_binheap(heap, &v10);
// print_binheap(heap);
// int v5 = 5;
// push_binheap(heap, &v5);
// print_binheap(heap);
// int v7 = 7;
// push_binheap(heap, &v7);
// push_binheap(heap, &v7);
// print_binheap(heap);
// popmin_binheap(heap);
// print_binheap(heap);
// popmin_binheap(heap);
// print_binheap(heap);
// Test de binheap. Dans ce cas, on ne fait pas de compression/décompression.
if (test_binheap_mode) {
INFO("TEST DES TAS BINAIRES");
INFO("---------------------\n");
int *array = random_array(size_heap, 100);
INFO("\nTableau avant tri:");
print_array(array, size_heap);
test_heap(array, size_heap);
INFO("\nTableau après tri:");
print_array(array, size_heap);
free(array);
return EXIT_SUCCESS;
}
// Ici, compression ou décompression.
// La compression du fichier f est faite dans un fichier f.huff.
// La décompression du fichier f.huff est faite dans le fichier f.
if (!decompress_mode) {
// Compression : tous les arguments suivants de main sont considérés comme
// des noms de fichiers à compresser.
for (int i = optind; i < argc; i++) {
struct stat b;
if (stat(argv[i], &b) != 0) {
ERROR("Impossible de calculer la taille du fichier \"%s\"", argv[i]);
continue;
}
if (b.st_size == 0) {
WARNING("Fichier \"%s\" de taille nulle", argv[i]);
continue;
}
INFO("Compression du fichier \"%s\" de taille %lld", argv[i],
(long long)b.st_size);
FILE *infile = fopen(argv[i], "r");
if (infile == NULL) {
ERROR("Impossible d'ouvrir le fichier à compresser \"%s\"", argv[i]);
continue;
}
huffnode *t = datafile_to_hufftree(infile);
// Arbre de Huffman
if (hufftree) {
INFO("Arbre de Huffman");
print_hufftree(t);
}
huffcode **d = create_huffdict(t);
if (huffdict) {
INFO("Affichage du dictionnaire");
print_huffdict(d);
}
// Création éventuelle du nom de fichier de sortie
if (outfilename == NULL) {
MALLOC(outfilename, strlen(argv[i]) + 6);
strcpy(outfilename, argv[i]);
strcpy(outfilename + strlen(outfilename), ".huff");
}
FILE *outfile = fopen(outfilename, "w");
if (outfile == NULL) {
ERROR("Impossible d'ouvrir le fichier de sortie \"%s\"", outfilename);
continue;
}
INFO("Fichier compressé -> \"%s\"", outfilename);
// Appel de la fonction de compression
compress_file(infile, outfile);
free(outfilename);
// Fermeture des fichiers
fclose(infile);
fclose(outfile);
}
}
if (decompress_mode) {
// Décompression : tous les arguments suivants de main sont considérés comme
// des noms de fichiers à décompresser.
for (int i = optind; i < argc; i++) {
FILE *infile = fopen(argv[i], "r");
if (infile == NULL) {
ERROR("Impossible d'ouvrir le fichier d'entrée à décompresser \"%s\"",
argv[i]);
continue;
}
INFO("Décompression de %s", argv[i]);
// Création éventuelle du nom de fichier de sortie
if (outfilename == NULL) {
MALLOC(outfilename, strlen(argv[i]) + 8);
strcpy(outfilename, argv[i]);
strcpy(outfilename + strlen(outfilename), ".dehuff");
}
// Ouverture du fichier de sortie
FILE *outfile = fopen(outfilename, "w");
if (outfile == NULL) {
ERROR("Impossible d'ouvrir le fichier de sortie \"%s\"", outfilename);
continue;
}
// Appel de la fonction de décompression
decompress_file(infile, outfile);
free(outfilename);
// Fermeture des fichiers
fclose(infile);
fclose(outfile);
}
}
return EXIT_SUCCESS;
}
// Implémentation du tri par les tas
void test_heap(int *tab, int size) {
int i;
int temp[size];
for (i = 0; i < size; i++) {
temp[i] = tab[i];
}
binheap *p = create_binheap(&fcmp_int);
printf("\nTest de push_binheap");
printf("\n********************\n\n");
for (i = 0; i < size; i++) {
printf("Push de %d\n", temp[i]);
push_binheap(p, temp + i);
print_binheap(p);
}
printf("\n");
printf("\nTest de pop_binheap");
printf("\n*******************\n\n");
if (p == NULL) {
WARNING("Essai de pop sur un tas NULL, rien ne se passe\n");
return;
}
for (i = 0; i < size; i++) {
tab[i] = *(int *)popmin_binheap(p);
printf("Élément supprimé: %d\n", tab[i]);
print_binheap(p);
}
}

2
tp-huffman/main.d Normal file
View File

@@ -0,0 +1,2 @@
main.o: main.c alloc.h error.h binheap.h huffcomp.h dequeue.h hufftree.h \
huffdecomp.h testprint.h

BIN
tp-huffman/main.o Normal file

Binary file not shown.

340
tp-huffman/testprint.c Normal file
View File

@@ -0,0 +1,340 @@
#include "testprint.h"
#include "alloc.h"
#include <math.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BAR "-" // un tiret
typedef char *string;
// Type utilisé pour représenter les arbres de Huffman en utilisant
// des tableaux (plus pratique pour écrire la fonction d'affichage)
typedef struct {
bool *array_af;
int *array_val;
int size;
} arraytree;
// Affichage d'un tableau d'entiers
void print_array(int *tab, int size) {
int i;
printf("{");
for (i = 0; i < size - 1; i++) {
printf("%d, ", tab[i]);
}
printf("%d}\n", tab[size - 1]);
}
// Affichage d'un tableau de pointeurs sur des entiers
void print_point_array(int **tab, int size) {
int i;
printf("{");
for (i = 0; i < size - 1; i++) {
printf("%d, ", *tab[i]);
}
printf("%d}\n", *tab[size - 1]);
}
// Génération d'un tableau d'entiers aléatoire
int *random_array(int size, int max) {
int *array;
MALLOC(array, size);
int i;
for (i = 0; i < size; i++) {
array[i] = random() % (max + 1);
}
return array;
}
// Génération d'un tas à partir d'un tableau d'entiers
binheap *array_to_binheap(int *array, int size) {
binheap *heap = create_binheap(&fcmp_int);
int i;
for (i = 0; i < size; i++) {
push_binheap(heap, (void *)(array + i));
}
return heap;
}
// Affiche n fois le même la chaîne s
static void rule(int n, string s) {
for (int i = 0; i < n; i++)
printf("%s", s);
}
// Affichage d'un tas binaire
void print_binheap(binheap *p) {
rule(10, BAR);
printf("\n");
if (p == NULL) {
printf("Trying to print a NULL tree\n\n");
return;
}
int h = 0; // Calcul de la hauteur de l'arbre (=nombre de lignes)
int j = p->size_heap;
while (j > 0) {
h++;
j = j >> 1;
}
int s = 1; // nombre de caractères avant le milieu du pattern
int B = 1; // B = nombre de patterns dans la ligne
j = 0; // j = nombre d'éléments déjà affichés
int sons = 0;
int y;
for (y = h - 1; y >= 0; y--, B <<= 1) {
// On part du haut de l'arbre
int pm = (s + 1) * (1 << y) - 1;
int lb = (s + 1) * (1 << (y - 1)) - 1;
int ep = 2 * pm + 1 - 2 * s;
// ligne avec les éléments
rule(pm - s, " ");
for (int b = 0; b < B && (j < p->size_heap); b++) {
// printf(" "); // cas pair
printf("%03i ", ((int *)p->array[j])[0]);
j++;
if (b < B - 1)
rule(ep - 1, " "); // -1 pour l'espace terminal
}
printf("\n");
if (y == 0)
break; // fini si dernière ligne d'éléments
// ligne avec les branchements
rule(lb, " ");
for (int b = 0; b < B; b++) {
if (right_binheap(sons) < p->size_heap) {
printf("");
rule(lb, "");
printf("");
rule(lb, "");
printf("");
if (b < B - 1)
rule(pm, " ");
} else if (left_binheap(sons) < p->size_heap) {
printf("");
rule(lb, "");
printf("");
if (b < B - 1)
rule(pm + 2, " ");
}
sons++;
}
printf("\n");
}
rule(10, BAR);
printf("\n\n");
}
// Affichage d'un arbre de Huffman
static int maxoftwo(int a, int b) {
if (a < b) {
return b;
} else {
return a;
}
}
static int hufftree_maxsize(huffnode *n) {
if (n == NULL) {
return 0;
} else {
return 2 * maxoftwo(hufftree_maxsize(n->leftchild),
hufftree_maxsize(n->rightchild)) +
1;
}
}
static void hufftree_fillarray(huffnode *n, int *arrayval, bool *arraytv,
int pos) {
if (n != NULL) {
arrayval[pos] = n->byte;
arraytv[pos] = true;
hufftree_fillarray(n->leftchild, arrayval, arraytv, 2 * pos + 1);
hufftree_fillarray(n->rightchild, arrayval, arraytv, 2 * pos + 2);
}
}
static arraytree *hufftree_to_array(huffnode *n) {
int size = hufftree_maxsize(n);
// printf("%d\n",size);
arraytree *new;
MALLOC(new, 1);
MALLOC(new->array_af, size);
MALLOC(new->array_val, size);
new->size = size;
int i;
for (i = 0; i < size; i++) {
new->array_af[i] = false;
}
hufftree_fillarray(n, new->array_val, new->array_af, 0);
return new;
}
void print_hufftree(huffnode *n) {
arraytree *p = hufftree_to_array(n);
rule(10, BAR);
printf("\n");
if (p == NULL) {
WARNING("Essai d'affichage d'un arbre de Huffman NULL\n\n");
return;
}
if (p->size == 0) {
WARNING("Essai d'affichage d'un arbre de Huffman vide\n\n");
return;
}
if (p->size == 1) {
printf(" %c\n", n->byte);
rule(10, BAR);
printf("\n\n");
return;
}
int h = 0; // Calcul de la hauteur de l'arbre (=nombre de lignes)
int j = p->size;
while (j > 0) {
h++;
j = j >> 1;
}
int s = 0; // nombre de caractères avant le milieu du pattern
int B = 1; // B = nombre de patterns dans la ligne
j = 1; // j = nombre d'éléments déjà affichés
int mine1 = 1;
int sons = 0;
int y;
for (y = h - 1; y >= 0; y--, B <<= 1) {
// On part du haut de l'arbre
int pm = (s + 1) * (1 << y) - 1;
int lb = (s + 1) * (1 << (y - 1)) - 1;
int ep = 2 * pm + 1 - 2 * s;
// ligne avec les éléments
if (y != h - 1) {
rule(pm - s, " ");
for (int b = 0; b < B && (mine1 < p->size); b++) {
// printf(" "); // cas pair
if (p->array_af[mine1] && mine1 % 2 == 1) {
printf("│0");
} else if (p->array_af[mine1] && mine1 % 2 == 0) {
printf("│1");
} else {
printf(" ");
}
mine1++;
if (b < B - 1)
rule(ep - 1, " "); // -1 pour l'espace terminal
}
printf("\n");
rule(pm - s, " ");
for (int b = 0; b < B && (j < p->size); b++) {
// printf(" "); // cas pair
if (p->array_af[j] && !p->array_af[2 * j + 1] &&
!p->array_af[2 * j + 2]) {
char thechar = (char)p->array_val[j];
if (thechar == '\n') {
printf("");
} else if (thechar == ' ') {
printf("");
} else {
printf("%c ", (char)p->array_val[j]);
}
} else if (p->array_af[j]) {
printf("");
} else {
printf(" ");
}
j++;
if (b < B - 1)
rule(ep - 1, " "); // -1 pour l'espace terminal
}
printf("\n");
if (y == 0)
break; // fini si dernière ligne d'éléments
}
// ligne avec les branchements
rule(lb, " ");
for (int b = 0; b < B; b++) {
if (p->array_af[2 * sons + 1] && p->array_af[2 * sons + 2]) {
printf("");
rule(lb, "");
printf("");
rule(lb, "");
printf("");
if (b < B - 1)
rule(pm, " ");
} else if (p->array_af[2 * sons + 1]) {
printf("");
rule(lb, "");
printf("");
rule(lb + 1, " ");
if (b < B - 1)
rule(pm, " ");
} else if (p->array_af[2 * sons + 2]) {
rule(lb + 1, " ");
printf("");
rule(lb, "");
printf("");
if (b < B - 1)
rule(pm, " ");
} else {
rule(2 * lb + 3, " ");
if (b < B - 1)
rule(pm, " ");
}
sons++;
}
printf("\n");
}
rule(10, BAR);
printf("\n\n");
}
/* Affichage d'un code de Huffman */
void print_code(huffcode *e) {
CHECK_NULL(2, e, "The code entry", e->code, "The array in the code entry");
int i;
for (i = 0; i < e->size; i++) {
printf("%d", e->code[i]);
}
printf("\n");
}
/* Affichage d'un tableau de codes de Huffman */
void print_huffdict(huffcode **codes) {
int i;
for (i = 0; i < 256; i++) {
if (codes[i] != NULL) {
printf("Valeur: %3d ", i);
if (i == '\n') {
printf("ASCII: ⏎ Code: ");
} else if (i == ' ') {
printf("ASCII: ␠ Code: ");
} else {
printf("ASCII: %c Code: ", i);
}
print_code(codes[i]);
printf("\n");
}
}
}

2
tp-huffman/testprint.d Normal file
View File

@@ -0,0 +1,2 @@
testprint.o: testprint.c testprint.h alloc.h error.h binheap.h huffcomp.h \
dequeue.h hufftree.h huffdecomp.h

74
tp-huffman/testprint.h Normal file
View File

@@ -0,0 +1,74 @@
/******************************************/
/******************************************/
/** Fonctions d'affichage pour les tests **/
/******************************************/
/******************************************/
#ifndef TESTPRINT_H_
#define TESTPRINT_H_
#include "alloc.h"
#include "binheap.h"
#include "huffcomp.h"
#include "huffdecomp.h"
#include "hufftree.h"
#include <stdbool.h>
#include <stdio.h>
/************/
/* Tableaux */
/************/
// Affichage d'un tableau d'entiers.
void print_array(int *tab, int size);
// Affichage d'un tableau de pointeurs sur des entiers.
void print_point_array(int **tab, int size);
// Génération d'un tableau d'entiers aléatoire.
// Les entiers générés sont compris entre 0 et max.
int *random_array(int size, int max);
/****************/
/* Tas binaires */
/****************/
// Génération d'un tas à partir d'un tableau d'entiers.
//
// Attention, les éléments dans le tas seront des pointeurs vers
// les éléments du tableau pris en entrée. Il ne faut donc plus
// modifier les valeurs référencées par les pointeurs dans le
// tableau (sous peine de casser le tas).
binheap *array_to_binheap(int *array, int size);
// Affichage d'un tas binaire.
//
// Prévu pour un tas dont les éléments sont des pointeurs vers des entiers.
// On peut en construire un avec les fonctions précédentes.
// Attention à ne pas afficher des tas "trop gros". Ils sont trop larges
// pour un terminal et les retours à la ligne rendent l'affichage illisible.
void print_binheap(binheap *);
/*********************/
/* Arbres de Huffman */
/*********************/
// Affichage d'un arbre de Huffman.
//
// À nouveau, l'affichage n'est lisible que pour de "petits" arbres de Huffman.
// Faites attention à tester vos fonctions sur des fichiers qui ne contiennent
// pas beaucoup de caractères distincts (afin de minimiser la taille des
// arbres).
void print_hufftree(huffnode *);
/*******************/
/* Code de Huffman */
/*******************/
// Affichage d'un code de Huffman.
void print_code(huffcode *e);
// Affichage d'un tableau de codes de Huffman.
void print_huffdict(huffcode **dict);
#endif

BIN
tp-huffman/testprint.o Normal file

Binary file not shown.

BIN
tp-huffman/tp Executable file

Binary file not shown.