📄 dcodhuff.c
字号:
/* Fichier: dcodhuff.c Auteur: David Bourgin Date de creation: 15/2/94 Date de derniere mise a jour: 24/7/95 Dessein: Exemple de decodage Huffman avec comme donnees a decompresser le contenu d'un fichier.*/#include <stdio.h>/* Pour les routines printf,fgetc,fputc */#include <memory.h>/* Pour la routine memset */#include <stdlib.h>/* Pour la routine exit */#include <malloc.h>/* Pour les routines malloc et free *//* Codes d'erreur renvoyes a l'appelant */#define NO_ERROR 0#define BAD_FILE_NAME 1#define BAD_ARGUMENT 2#define BAD_MEM_ALLOC 3/* Constantes pratiques */#define FALSE 0#define TRUE 1typedef struct s_arbre { unsigned int octet; /* Un octet est volontairement code comme un entier non signe pour qu'un noeud fictif puisse depasser la valeur 255 */ struct s_arbre *ptr_gauche, *ptr_droit; } t_arbre,*p_arbre;#define OCTET_ARBRE(ptr_arbre) ((*(ptr_arbre)).octet)#define PGAUCHE_ARBRE(ptr_arbre) ((*(ptr_arbre)).ptr_gauche)#define PDROIT_ARBRE(ptr_arbre) ((*(ptr_arbre)).ptr_droit)typedef struct { unsigned char bits[32], nb_bits, presence; } t_val_bin;#define BITS_VAL_BIN(x) ((x).bits)#define NB_BITS_VAL_BIN(x) ((x).nb_bits)#define PRESENCE_VAL_BIN(x) ((x).presence)/* Variables globales */FILE *f_source,*f_dest; /* Puisque fgetc=EOF uniquement apres un acces alors statut_octet_stocke vaut TRUE si un octet a ete engrange par fgetc ou FALSE s'il n'y aucun octet valide, deja lu et non traite dans val_octet_stocke */int statut_octet_stocke=FALSE;int val_octet_stocke;/* Pseudo procedures */#define fin_des_donnees() (statut_octet_stocke?FALSE:!(statut_octet_stocke=((val_octet_stocke=fgetc(f_source))!=EOF)))#define lire_octet() (statut_octet_stocke?statut_octet_stocke=FALSE,(unsigned char)val_octet_stocke:(unsigned char)fgetc(f_source))#define ecrire_octet(octet) ((void)fputc((octet),f_dest))unsigned char nb_bits_a_lire=0;unsigned int val_a_lire=0;unsigned char lire_code_1_bit()/* Parametres en sortie: Renvoie un entier non signe sur 1 bit valide (a droite de l'entier) Action: Lit dans le fichier des donnees en entree le prochain bit Erreurs: Une erreur d'entree/sortie peut perturber le deroulement de l'algorithme La source des donnees doit disposer de suffisamment de bits restants a lire*/{ unsigned int resultat; if (nb_bits_a_lire) { nb_bits_a_lire--; resultat=(val_a_lire >> nb_bits_a_lire) & 1; } else { val_a_lire=lire_octet(); nb_bits_a_lire=7; resultat=(val_a_lire >> 7) & 1; } val_a_lire &= 127; return resultat;}unsigned int lire_code_n_bits(n)/* Parametres en sortie: Renvoie un entier non signe sur 'n' bits valides (a droite de l'entier) Action: Lit dans le fichier des donnees en entree les n prochains bits Erreurs: Une erreur d'entree/sortie peut perturber le deroulement de l'algorithme La source des donnees doit disposer de suffisamment de bits restants a lire*/unsigned char n;{ unsigned int resultat; while ((nb_bits_a_lire<n)&&(!fin_des_donnees())) { val_a_lire = (val_a_lire << 8)+lire_octet(); nb_bits_a_lire += 8; } nb_bits_a_lire -= n; resultat=val_a_lire >> nb_bits_a_lire; val_a_lire &= ((1<<nb_bits_a_lire)-1); return resultat;}void lire_en_tete(table_codes)/* Parametres en sortie: Le contenu de 'table_codes' est modifie Action: Reconstruit le tableau de codage binaire a partir de l'en-tete Erreurs: Une erreur d'entree/sortie peut perturber le deroulement de l'algorithme*/t_val_bin table_codes[257];{ register unsigned int i,j; char num_octet; (void)memset((char *)table_codes,0,257*sizeof(*table_codes)); /* == Decodage de la premiere partie de l'en-tete == */ if (lire_code_1_bit()) /* Premier bit=0 => Octets presents codes sur n*8 bits =1 => Octets presents codes sur 256 bits */ for (i=0;i<=255;i++) PRESENCE_VAL_BIN(table_codes[i])=lire_code_1_bit(); else { i=lire_code_n_bits(5)+1; while (i) { PRESENCE_VAL_BIN(table_codes[lire_code_n_bits(8)])=1; i--; } } PRESENCE_VAL_BIN(table_codes[256])=1; /* La presence de l'octet fictif 256 est forcee! */ /* == Decodage de la seconde partie de l'en-tete == */ for (i=0;i<=256;i++) if PRESENCE_VAL_BIN(table_codes[i]) { if (lire_code_1_bit()) /* Premier bit=0 => 5 bits de longueur binaire-1 suivi du mot binaire =1 => 8 bits de longueur binaire-1 suivi du mot binaire */ j=lire_code_n_bits(8)+1; else j=lire_code_n_bits(5)+1; NB_BITS_VAL_BIN(table_codes[i])=j; /* Lecture du mot binaire */ num_octet=(j+7) >> 3; if (j & 7) { /* Lire les bits ne formant pas un octet */ num_octet--; BITS_VAL_BIN(table_codes[i])[num_octet]=(unsigned char)lire_code_n_bits(j & 7); } while (num_octet) { /* Lire les bits format un octet */ num_octet--; BITS_VAL_BIN(table_codes[i])[num_octet]=(unsigned char)lire_code_n_bits(8); } }}void supprimer_arbre(arbre)/* Parametres en sortie: Aucun Action: Supprime la memoire allouee a un arbre Erreurs: Aucune si l'arbre a ete construit par allocations dynamiques!*/p_arbre arbre;{ if (arbre!=NULL) { supprimer_arbre(PGAUCHE_ARBRE(arbre)); supprimer_arbre(PDROIT_ARBRE(arbre)); free(arbre); }}p_arbre coder_arbre(table_codes)/* Parametres en sortie: Un arbre binaire est renvoye Action: Renvoie l'arbre binaire de decodage de 'table_codes' Erreurs: Aucune*/t_val_bin table_codes[257];{ register unsigned int i; unsigned int j; p_arbre ptr_arbre,noeud_courant; if ((ptr_arbre=(p_arbre)malloc(sizeof(t_arbre)))==NULL) exit(BAD_MEM_ALLOC); OCTET_ARBRE(ptr_arbre)=257; PGAUCHE_ARBRE(ptr_arbre)=NULL; PDROIT_ARBRE(ptr_arbre)=NULL; for (i=0;i<=256;i++) { for (noeud_courant=ptr_arbre,j=NB_BITS_VAL_BIN(table_codes[i]);j;j--) { if (BITS_VAL_BIN(table_codes[i])[(j-1) >> 3] & (1 << ((j-1) & 7))) if (PGAUCHE_ARBRE(noeud_courant)==NULL) { if ((PGAUCHE_ARBRE(noeud_courant)=(p_arbre)malloc(sizeof(t_arbre)))==NULL) { supprimer_arbre(ptr_arbre); exit(BAD_MEM_ALLOC); } noeud_courant=PGAUCHE_ARBRE(noeud_courant); PGAUCHE_ARBRE(noeud_courant)=NULL; PDROIT_ARBRE(noeud_courant)=NULL; } else noeud_courant=PGAUCHE_ARBRE(noeud_courant); else if (PDROIT_ARBRE(noeud_courant)==NULL) { if ((PDROIT_ARBRE(noeud_courant)=(p_arbre)malloc(sizeof(t_arbre)))==NULL) { supprimer_arbre(ptr_arbre); exit(BAD_MEM_ALLOC); } noeud_courant=PDROIT_ARBRE(noeud_courant); PGAUCHE_ARBRE(noeud_courant)=NULL; PDROIT_ARBRE(noeud_courant)=NULL; } else noeud_courant=PDROIT_ARBRE(noeud_courant); if (j==1) OCTET_ARBRE(noeud_courant)=i; else OCTET_ARBRE(noeud_courant)=257; } } return (ptr_arbre);}void decodagehuff()/* Parametres en sortie: Aucun Action: Decompresse suivant la methode de Huffman tous les octets lus par les fonctions lire_code_1_bit et lire_code_n_bits Erreurs: Une erreur d'entree/sortie peut perturber le deroulement de l'algorithme*/{ t_val_bin table_codage[257]; p_arbre ptr_arbre,noeud_courant; if (!fin_des_donnees()) /* Y a-t-il des donnees a compresser? */ { lire_en_tete(table_codage); ptr_arbre=coder_arbre(table_codage); do { noeud_courant=ptr_arbre; while (OCTET_ARBRE(noeud_courant)==257) if (lire_code_1_bit()) /* Bit=1 => Aller a gauche dans le noeud courant de l'arbre =0 => Aller a droite dans le noeud courant de l'arbre */ noeud_courant=PGAUCHE_ARBRE(noeud_courant); else noeud_courant=PDROIT_ARBRE(noeud_courant); if (OCTET_ARBRE(noeud_courant)<=255) ecrire_octet(OCTET_ARBRE(noeud_courant)); } while (OCTET_ARBRE(noeud_courant)!=256); supprimer_arbre(ptr_arbre); }}void aide()/* Parametres en sortie: Aucun Action: Affiche l'aide du programme et termine son execution Erreurs: Aucune*/{ printf("Cet utilitaire permet de decompresser un fichier par la methode de Huffman\n"); printf("telle qu'elle est exposee dans 'La Video et Les Imprimantes sur PC'\n"); printf("\nUsage: dcodhuff source destination\n"); printf("source: Nom du fichier a decompresser\n"); printf("destination: Nom du fichier decompresse\n");}int main(argc,argv)/* Parametres en sortie: Renvoie un code d'erreur (0=Aucune) Action: Procedure principale Erreurs: Detectee, traitee et un code d'erreur est renvoye si necessaire*/int argc;char *argv[];{ if (argc!=3) { aide(); exit(BAD_ARGUMENT); } else if ((f_source=fopen(argv[1],"rb"))==NULL) { aide(); exit(BAD_FILE_NAME); } else if ((f_dest=fopen(argv[2],"wb"))==NULL) { aide(); exit(BAD_FILE_NAME); } else { decodagehuff(); fclose(f_source); fclose(f_dest); } printf("Execution de dcodhuff achevee.\n"); return (NO_ERROR);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -