Encodage du fichier compressé

This commit is contained in:
Mattéo Delabre 2016-10-27 18:20:18 +02:00
parent 948f73027b
commit d647fc5452
3 changed files with 135 additions and 35 deletions

View File

@ -3,6 +3,12 @@
#include "huftree.h" #include "huftree.h"
void compress(const char* filepath); #define COMPRESS_OK 0
#define COMPRESS_READ_ERROR 1
#define COMPRESS_WRITE_ERROR 2
#define COMPRESS_OPEN_INPUT_ERROR 3
#define COMPRESS_OPEN_OUTPUT_ERROR 4
int compress(const char*, const char*);
#endif #endif

View File

@ -1,6 +1,8 @@
#include "compress.h" #include "compress.h"
#include "common.h" #include "common.h"
#include "buffer.h"
#include "display.h" #include "display.h"
#include "assert.h"
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
@ -8,13 +10,21 @@
/** /**
* Calculer un tableau de fréquences d'apparition des * Calculer un tableau de fréquences d'apparition des
* caractères ASCII dans le fichier de chemin donné * caractères ASCII dans le fichier donné. Le fichier
* donné doit être ouvert au moins en lecture
* *
* (résultat à libérer avec `free`) * (résultat à libérer avec `free`)
*/ */
static double* _createFrequencies(const char*); static double* _createFrequencies(FILE*);
double* _createFrequencies(const char* filepath) { /**
* Encoder le fichier d'entrée vers le fichier de sortie
* en suivant les étiquettes passées. Les étiquettes
* peuvent être calculées avec labelTree()
*/
void _encodeFromTable(char**, FILE*, FILE*);
double* _createFrequencies(FILE* file) {
double* frequencies = malloc(NUM_CHARS * sizeof(*frequencies)); double* frequencies = malloc(NUM_CHARS * sizeof(*frequencies));
int totalChars = 0; int totalChars = 0;
@ -22,29 +32,15 @@ double* _createFrequencies(const char* filepath) {
frequencies[i] = 0; frequencies[i] = 0;
} }
// Ouverture du fichier en lecture seule, et comptage int current;
// des occurences de chaque caractère ASCII ainsi que
// du nombre total de caractères
FILE* file = fopen(filepath, "r");
if (file == NULL) {
fprintf(
stderr, "Impossible d'ouvrir '%s' : %s\n",
filepath, strerror(errno)
);
exit(1);
}
char current;
// Lecture du fichier caractère par caractère et comptage
while ((current = fgetc(file)) != EOF) { while ((current = fgetc(file)) != EOF) {
frequencies[(size_t) current]++; assert(current >= 0 && current < NUM_CHARS);
frequencies[current]++;
totalChars++; totalChars++;
} }
fclose(file);
// Conversion des effectifs des caractères en fréquences // Conversion des effectifs des caractères en fréquences
for (size_t i = 0; i < NUM_CHARS; i++) { for (size_t i = 0; i < NUM_CHARS; i++) {
frequencies[i] /= totalChars; frequencies[i] /= totalChars;
@ -53,11 +49,53 @@ double* _createFrequencies(const char* filepath) {
return frequencies; return frequencies;
} }
void compress(const char* filepath) { void _encodeFromTable(char** labels, FILE* input, FILE* output) {
printVerbose("Compression du fichier '%s'...\n", filepath); Buffer buffer = createBuffer(output);
printVerbose("Calcul des fréquences d'apparition des caractères.\n"); int current;
double* frequencies = _createFrequencies(filepath); // Lecture du fichier d'entrée caractère par caractère
while ((current = fgetc(input)) != EOF) {
assert(current >= 0 && current < NUM_CHARS);
char* label = labels[current];
assert(label != NULL);
// Ajout du label dans le buffer, caractère par caractère
// vidant progressivement le buffer
while (*label != '\0') {
pushToBuffer(*label == '1', &buffer);
label++;
}
}
// Écriture du dernier octet dans le fichier
// (pas toujours plein)
flushBuffer(&buffer);
}
int compress(const char* inputpath, const char* outputpath) {
// FIXME: gérer le fichier vide
// FIXME: gérer les fichiers avec un seul type de caractère
printVerbose(
"Compression du fichier '%s' en '%s'...\n",
inputpath, outputpath
);
// Ouverture de l'entrée en lecture et la sortie en écriture
FILE* input;
FILE* output;
if ((input = fopen(inputpath, "r")) == NULL) {
return COMPRESS_OPEN_INPUT_ERROR;
}
if ((output = fopen(outputpath, "w")) == NULL) {
return COMPRESS_OPEN_OUTPUT_ERROR;
}
// Comptage des caractères et calcul des fréquences d'apparition
printVerbose("Calcul des fréquences d'apparition des caractères.\n");
double* frequencies = _createFrequencies(input);
if (isVerbose()) { if (isVerbose()) {
printFrequenciesTable(frequencies, NUM_CHARS); printFrequenciesTable(frequencies, NUM_CHARS);
@ -76,12 +114,23 @@ void compress(const char* filepath) {
printVerbose("\nÉtiquetage des feuilles de l'arbre.\n"); printVerbose("\nÉtiquetage des feuilles de l'arbre.\n");
char** labels = createTreeLabels(tree); char** labels = createTreeLabels(tree);
freeTree(tree);
if (isVerbose()) { if (isVerbose()) {
printLabelsTable(labels, NUM_CHARS); printLabelsTable(labels, NUM_CHARS);
} }
printVerbose("\nÉcriture de l'arbre dans la sortie.\n");
writeTree(tree, output);
printVerbose("Écriture des données compressées du fichier.\n");
rewind(input);
_encodeFromTable(labels, input, output);
freeTree(tree);
freeTreeLabels(labels); freeTreeLabels(labels);
labels = NULL; labels = NULL;
fclose(input);
fclose(output);
return COMPRESS_OK;
} }

View File

@ -2,6 +2,7 @@
#include "compress.h" #include "compress.h"
#include <argp.h> #include <argp.h>
#include <locale.h> #include <locale.h>
#include <string.h>
/** /**
* Définition de la configuration de Argp, qui affichera * Définition de la configuration de Argp, qui affichera
@ -75,16 +76,60 @@ int main(int argc, char** argv) {
// Passage en mode verbeux si demandé // Passage en mode verbeux si demandé
setVerbose(args.verbose); setVerbose(args.verbose);
// Compression de chaque fichier en argument // Compression des fichiers en argument
char** filepath = args.files; char** files = args.files;
while (*filepath != NULL) { while (*files != NULL) {
compress(*filepath); char* input = *files;
filepath++;
// Ligne de séparation entre les différents fichier // Compression du fichier xx en xx.huf
if (*filepath != NULL) { // TODO: rendre le nom du fichier de sortie configurable
char* output = malloc((strlen(input) + 5) * sizeof(*output));
strcpy(output, input);
strcat(output, ".huf");
switch (compress(input, output)) {
case COMPRESS_READ_ERROR:
fprintf(
stderr,
"Erreur : impossible de lire le fichier '%s' - %s\n",
input, strerror(errno)
);
return COMPRESS_READ_ERROR;
case COMPRESS_WRITE_ERROR:
fprintf(
stderr,
"Erreur : impossible d'écrire dans le fichier '%s' - %s\n",
output, strerror(errno)
);
return COMPRESS_WRITE_ERROR;
case COMPRESS_OPEN_INPUT_ERROR:
fprintf(
stderr,
"Erreur : impossible d'ouvrir le fichier '%s' - %s\n",
input, strerror(errno)
);
return COMPRESS_OPEN_INPUT_ERROR;
case COMPRESS_OPEN_OUTPUT_ERROR:
fprintf(
stderr,
"Erreur : impossible d'ouvrir le fichier '%s' - %s\n",
output, strerror(errno)
);
return COMPRESS_OPEN_OUTPUT_ERROR;
}
free(output);
files++;
// Ligne de séparation entre les différents fichiers
if (*files != NULL) {
printVerbose("\n"); printVerbose("\n");
} }
} }
return EXIT_SUCCESS;
} }