-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtools.c
More file actions
523 lines (480 loc) · 13.7 KB
/
tools.c
File metadata and controls
523 lines (480 loc) · 13.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
/**
* Polytech Marseille
* Case 925 - 163, avenue de Luminy
* 13288 Marseille CEDEX 9
*
* Ce fichier est l'oeuvre d'eleves de Polytech Marseille. Il ne peut etre
* reproduit, utilise ou modifie sans l'avis express de ses auteurs.
*/
/**
* @author PORET Tanguy <tanguy.poret@etu.univ-amu.fr>
* @author DI-GIOVANI Hugo <hugo.DI-GIOVANNI@etu.univ-amu.fr>
*
* @version 0.0.1 / 27-11-2016
*/
/**
* @file tools.c
* @brief Regroupe les fonctions utilitaires
*
*/
#include "tools.h"
#include "arbre.h"
#include <assert.h>
#include <time.h>
/* Déclaration dans le .c en static car on en veut pas que ces variables
* soient visibles ailleurs que dans ce fichier. */
static char glb_stat_tampon;
static int gbl_stat_compteur_tampon;
void afficher_ordre(t_arbre* arbre);
void debug_compression(const char *fal, const char *nf)
{
/* Longueur du fichier.
* Attention: un fichier excédant la longueur que peut contenir cette
* variable entrainera un résultat inconnu. */
long int tailleFichier = 0;
// Utilisé pour parcourir le fichier
long int i;
// caractère actuel
unsigned char c;
// Contient l'arbre de Gallager, son ordre, etc.
t_arbre arbre;
// Pointeur sur le fichier à lire.
FILE *pfl = fopen(fal, "r");
FILE *pfe = fopen(nf, "w");
// Test de l'ouverture du fichier
if (pfl == NULL)
{
perror ("Erreur d'ouverture du fichier.");
}
else if (pfe == NULL)
{
/* Si impossible de créer un fichier pour écrire,
* on ferme celui qui a été ouvert pour la lecture. */
fclose(pfl);
perror ("Erreur d'ouverture du fichier.");
}
else
{
fseek (pfl, 0, SEEK_END); // non-portable
tailleFichier = ftell(pfl);
rewind(pfl); // Important, remet le curseur en début de fichier
printf ("Le fichier contient: %ld caractères.\n", tailleFichier);
// Création de l'arbre de base (racine + feuille EOF et caractère inconnu)
init_arbre(&arbre);
/* On s'assure que les glb_stat_tampon soient réinitialisé (cas de plusieurs
* compression effectué d'affilé. */
init_tampon();
// Lecture du complète du fichier.
for (i = 0; i < tailleFichier; i++)
{
/* getc à la place de fgetc car est parfois implémenté en tant que
* macro, ce qui peut induire un gain de performance. */
c = getc(pfl);
// Opérations sur l'arbre d'Huffman
tpn code = arbre.caracteres[(int)c];
// Si le code n'est pas présent dans l'arbre
if (code == TPN_NULL)
{
ajouter_au_tampon(arbre.pfi, pfe);
ajouter_char_au_tampon(c, pfe);
ajout_feuille(&arbre, c);
}
// On doit rééquilibrer l'arbre et incrémenter de 1 succésivement
else
{
ajouter_au_tampon(code, pfe);
incrementer_element(&arbre, code);
}
// Affiche l'ordre de Gallager
afficher_ordre(&arbre);
}
ajouter_au_tampon(arbre.pffe, pfe);
clear_tampon(pfe);
liberer_arbre(arbre.racine);
fclose(pfl);
fclose(pfe);
}
}
/** @brief Compresse le fichier vers un autre
*
* Le fichier va être compression via l'algorithme de Huffman adaptatif.
*
* @param fal chaine de caractère étant le nom du fichier à lire
* @param nf chaine de caractère étant le nom du fichier à sauvegarder
* TODO: faire en sorte que la fonction soit portable (lecture taille fichier)
*/
void compression(const char *fal, const char *nf)
{
time_t debut, fin;
time(&debut); // On stock le temps de début
/* Longueur du fichier.
* Attention: un fichier excédant la longueur que peut contenir cette
* variable entrainera un résultat inconnu. */
long int tailleFichier = 0;
// Utilisé pour parcourir le fichier
long int i;
// caractère actuel
unsigned char c;
// Contient l'arbre de Gallager, son ordre, etc.
t_arbre arbre;
// Pointeur sur le fichier à lire.
FILE *pfl = fopen(fal, "r");
FILE *pfe = fopen(nf, "w");
// Test de l'ouverture du fichier
if (pfl == NULL)
{
perror ("Erreur d'ouverture du fichier.");
}
else if (pfe == NULL)
{
/* Si impossible de créer un fichier pour écrire,
* on ferme celui qui a été ouvert pour la lecture. */
fclose(pfl);
perror ("Erreur d'ouverture du fichier.");
}
else
{
fseek (pfl, 0, SEEK_END); // non-portable
tailleFichier = ftell(pfl);
rewind(pfl); // Important, remet le curseur en début de fichier
printf ("Le fichier contient: %ld caractères.\n", tailleFichier);
// Création de l'arbre de base (racine + feuille EOF et caractère inconnu)
init_arbre(&arbre);
/* On s'assure que les glb_stat_tampon soient réinitialisé (cas de plusieurs
* compression effectué d'affilé. */
init_tampon();
// Lecture du complète du fichier.
for (i = 0; i < tailleFichier; i++)
{
/* getc à la place de fgetc car est parfois implémenté en tant que
* macro, ce qui peut induire un gain de performance. */
c = getc(pfl);
// Opérations sur l'arbre d'Huffman
tpn code = arbre.caracteres[(int)c];
// Si le code n'est pas présent dans l'arbre
if (code == TPN_NULL)
{
ajouter_au_tampon(arbre.pfi, pfe);
ajouter_char_au_tampon(c, pfe);
ajout_feuille(&arbre, c);
}
// On doit rééquilibrer l'arbre et incrémenter de 1 succésivement
else
{
ajouter_au_tampon(code, pfe);
incrementer_element(&arbre, code);
}
}
ajouter_au_tampon(arbre.pffe, pfe);
clear_tampon(pfe);
liberer_arbre(arbre.racine);
fclose(pfl);
long int tailleCompresse = ftell(pfe);
fclose(pfe);
time(&fin);
double temps = difftime(fin, debut);
printf("Fichier %s\n", fal);
printf("Temps de compression: %.3f secondes, compresse a %.3f%%, vitesse moyenne: %.3fko/s", \
temps, (1.f-(double)tailleCompresse/(double)tailleFichier)*100.f, (tailleCompresse/1000.f)/temps);
}
}
/** @brief Décompresse le fichier vers un autre
*
* Le fichier va être décompressé via l'algorithme de Huffman adaptatif.
*
* @param fal chaine de caractère étant le nom du fichier à lire
* @param nf chaine de caractère étant le nom du fichier à sauvegarder
* TODO: faire en sorte que la fonction soit portable (lecture taille fichier)
*/
void decompression(const char *fal, const char *nf)
{
time_t debut, fin;
time(&debut); // On stock le temps de début
/* Longueur du fichier.
* Attention: un fichier excédant la longueur que peut contenir cette
* variable entrainera un résultat inconnu. */
long int tailleFichier = 0;
// Utilisé pour parcourir le fichier
long int i = 0;
// Utilisé pour buffer
int j = (sizeof(char)*8)-1;
// caractère actuel
unsigned char carac;
// Contient l'arbre de Gallager, son ordre, etc.
t_arbre arbre;
tpn feuille;
// Pointeur sur le fichier à lire.
FILE *pfl = fopen(fal, "r");
FILE *pfe = fopen(nf, "w");
// Test de l'ouverture du fichier
if (pfl == NULL)
{
perror ("Erreur d'ouverture du fichier.");
}
else if (pfe == NULL)
{
/* Si impossible de créer un fichier pour écrire,
* on ferme celui qui a été ouvert pour la lecture. */
fclose(pfl);
perror ("Erreur d'ouverture du fichier.");
}
else
{
// Si la feuille est le caractère inconnu, on lit
// les 8 prochains bit et création du noeud avec le char
// et maintient de l'ordre
// Si la feuille est un caractère, on incrémente ce dernier
// Si la feuille mène à la fin de fichier, on stop la lecture.
// Variante, stop à la fin de fichier et si on a lu caractère
// de fin, decompression OK sinon ERREUR (fichier corrompu)
fseek (pfl, 0, SEEK_END); // non-portable
tailleFichier = ftell(pfl);
rewind(pfl); // Important, remet le curseur en début de fichier
printf ("Le fichier contient: %ld caractères.\n", tailleFichier);
// Création de l'arbre de base (racine + feuille EOF et caractère inconnu)
init_arbre(&arbre);
if (tailleFichier != 0)
{
carac = getc(pfl);
tailleFichier++;
}
// Lecture du complète du fichier.
while (i < tailleFichier)
{
// On lit un caractère et on décode son binaire pour
// tomber sur une feuille de l'arbre de Gallager.
// Tant que pas tombé sur feuille et buffer pas vide
feuille = arbre.racine;
while (!est_feuille(feuille) && i < tailleFichier)
{
if (j < 0)
{
// Rempli buffer
carac = getc(pfl);
j = (sizeof(char)*8)-1;
i++;
}
if (carac&(1u<<j))
{
// Aller à droite
feuille = feuille->fd;
}
else
{
// Aller à gauche
feuille = feuille->fg;
}
j--;
}
// Si la feuille est le caractère inconnu, on lit
// les 8 prochains bit et création du noeud avec le char
// et maintient de l'ordre
if (feuille->val == UNKNOWN_CHAR)
{
// Lire 8 prochain bit
int compteurChar = (sizeof(char)*8)-1;
char charLu = 0;
while (compteurChar >= 0 && i < tailleFichier)
{
if (j < 0)
{
carac = getc(pfl);
j = (sizeof(char)*8)-1;
i++;
}
if (carac&(1u<<j))
{
charLu = charLu|(1u<<compteurChar);
compteurChar--;
j--;
}
else
{
compteurChar--;
j--;
}
}
// charLu contient le char a ajouter
putc(charLu, pfe);
ajout_feuille(&arbre, charLu);
}
else if (feuille->val == FAKE_EOF)
{
// Arrete tout
i = tailleFichier;
}
// Si la feuille est un caractère, on incrémente ce dernier
else
{
putc((char)feuille->val, pfe);
incrementer_element(&arbre, feuille);
}
}
liberer_arbre(arbre.racine);
fclose(pfl);
fclose(pfe);
time(&fin);
printf("Temps de decompression: %3f secondes.", difftime(fin, debut));
}
}
/** @brief Retourne 1 si le fichier existe
*
* @param nom le chemin complet vers le fichier
*/
int fichier_existe(const char * const nom)
{
FILE* file = fopen(nom, "r");
int existe = file != NULL ? 1 : 0;
if (file != NULL) fclose(file);
return existe;
}
/** @brief Initialise les variables global static
*
*/
void init_tampon()
{
glb_stat_tampon = 0;
gbl_stat_compteur_tampon = 0;
}
/** @brief Ajoute le bit en paramètre au tampon puis verifie si le tampon est plein.
*
* @param bit Valeur du bit à ajouter (doit être 0 ou 1)
* @param nf pointeur du fichier où l'on écrit le tampon
*/
void ajouter_bit_tampon(int bit, FILE *nf)
{
assert(bit == 1 || bit == 0);
glb_stat_tampon = glb_stat_tampon << 1;
glb_stat_tampon = glb_stat_tampon | bit;
gbl_stat_compteur_tampon++;
if(gbl_stat_compteur_tampon == 8){
//printf("DEBUG: le glb_stat_tampon est plein ! vidage du glb_stat_tampon dans le fichier de sortie ...\n");
putc(glb_stat_tampon, nf);
init_tampon();
}
}
/** @brief Ajoute une lettre (char) au tampon
*
* @param carac le caractère à mettre dans le tampon
* @param nf pointeur du fichier où l'on écrit le tampon
*/
void ajouter_char_au_tampon(char carac, FILE *nf)
{
int i;
//printf("Ecriture char: ");
for(i=(sizeof(char)*8)-1; i>=0; i--)
{
if (carac&(1u<<i))
{
ajouter_bit_tampon(1, nf);
//printf("1");
}
else
{
ajouter_bit_tampon(0, nf);
//printf("0");
}
}
//printf(" fin ecrit\n");
}
/** @brief Ajoute au tampon la séquence binaire d'une lettre
*
* Ecrit la séquence binaire correspondant à la lettre
* dans le tampon.
*
* @param carac le caractère à mettre dans le tampon
* @param nf pointeur du fichier où l'on écrit le tampon
* TODO: Reprendre la fonction
*/
void ajouter_au_tampon(tpn arbre, FILE *nf)
{
tpn tmp;
int chemin[512];
int taille_tab = 0;
//on récupère le chemin binaire en partant de la feuille
//et en remontant jusqu'a la racine.
while (arbre->parent!=NULL)
{
tmp = arbre;
arbre = arbre->parent;
if (arbre->fg == tmp)
{
chemin[taille_tab]=0;
taille_tab++;
}
else if(arbre->fd == tmp)
{
chemin[taille_tab]=1;
taille_tab++;
}
}
//boucle qui écrit dans le glb_stat_tampon le chemin dans l'ordre
//car on écrit le chemin de la racine vers la feuille.
//cependant il a été récupéré de la feuille à la racine.
//printf("Parcours...\n");
while(taille_tab!=0)
{
taille_tab--;
ajouter_bit_tampon(chemin[taille_tab], nf);
//printf("%d", chemin[taille_tab]);
}
//printf(" fin parcours.\n");
}
/** @brief Vide le tampon en rajoutant du bourrage si besoin
*
* @param nf pointeur du fichier où l'on écrit le tampon
*/
void clear_tampon(FILE *nf)
{
//printf("DEBUG: ajout de bits de bourrage au glb_stat_tampon et vidage du glb_stat_tampon dans le fichier de sortie\n");
glb_stat_tampon = glb_stat_tampon << (8 - gbl_stat_compteur_tampon);
gbl_stat_compteur_tampon = 8;
putc(glb_stat_tampon, nf);
init_tampon();
}
void afficher_ordre(t_arbre* arbre)
{
int indice = 0;
printf("Affichage ordre et +\n");
while (arbre->ordres[indice] != TPN_NULL && indice < 515)
{
//printf("%d->%d(%c) ordre: %d, p: %d\n", indice, arbre->ordres[indice]->val, (char)arbre->ordres[indice]->val, arbre->ordres[indice]->ord_gal, arbre->ordres[indice]->poids);
indice++;
}
printf("\n");
}
/** @brief Affiche l'arbre
*
* Cette fonction affiche l'arbre ainsi que des informations sur celui-ci
* à condition qu'il n'a pas de poids > 999.
*
* @param arbre prend un pointeur d'arbre en paramètre
* TODO:
*/
/* FONCTION MISE DE COTE
void debug(tpn arbre)
{
int profondeur;
system(CLEAR); //netoie le terminal (compatible windows / linux)
printf("\t-------------------------\n");
printf("\t| DEBUG ARBRE |\n");
printf("\t-------------------------\n\n");
//test pour savoir si un des 2 fils à un ordre > 999.
if (arbre->fg->poids > 999 || arbre->fd->poids > 999){
printf("Arbre non compatible avec la fonction de debug.\n raison: poids d'un des noeuds superieur a 999");
}else{
if (arbre!=NULL){
//test de profondeur
profondeur = profondeur(arbre);
printf("Profondeur de l'arbre: %d \n\n", profondeur);
int i=1;
for (i=1; i<=profondeur; i++)
{
printf("\n");
}
} else {
printf("Arbre vide\n");
}
}
}
*/