Encodage du fichier compressé
This commit is contained in:
parent
948f73027b
commit
d647fc5452
|
@ -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
|
||||||
|
|
103
src/compress.c
103
src/compress.c
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
59
src/main.c
59
src/main.c
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue