home *** CD-ROM | disk | FTP | other *** search
- /* Fichier: codlzw.c
- Auteur: David Bourgin
- Date de creation: 25/2/94
- Date de derniere mise a jour: 12/10/95
- Dessein: Exemple de codage LZW avec comme donnees a compresser le contenu d'un fichier.
- */
-
- #include <stdio.h>
- /* Pour les routines printf,fgetc,fputc. */
- #include <malloc.h>
- /* Pour les routines malloc et free. */
- #include <stdlib.h>
- /* Pour la routine exit. */
-
- /* 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 1
-
- /* 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 long int val_a_lire=0,
- val_a_ecrire=0;
- unsigned char nb_bits_a_lire=0,
- nb_bits_a_ecrire=0;
-
- typedef struct s_val_dic { unsigned int carac;
- unsigned int code;
- struct s_val_dic *ptr_gauche,
- *ptr_droit;
- } t_val_dic,*p_val_dic;
- #define CARAC_VAL_DIC(ptr_dic) ((*(ptr_dic)).carac)
- #define CODE_VAL_DIC(ptr_dic) ((*(ptr_dic)).code)
- #define PGAUCHE_VAL_DIC(ptr_dic) ((*(ptr_dic)).ptr_gauche)
- #define PDROIT_VAL_DIC(ptr_dic) ((*(ptr_dic)).ptr_droit)
-
- #define CODAGE_TYPE_GIF
- /* Implique l'inclusion des codes des marqueurs code_initialisation et code_fin_information.
- Pour invalider cette option, mettez la ligne #define... en commentaire. */
-
- unsigned int index_dic;
- /* Nombre de mots deja reconnus dans le dictionnaire. */
- unsigned char nb_bits_codage;
- /* Nombre de bits en codage. */
-
- #define EXP2_DIC_MAX 12
- /* 2^EXP2_DIC_MAX donne le nombre maximum de mots dans le dictionnaire durant *toutes* les compressions.
- Valeurs possibles: 3 a 25.
- Attention: Au-dela de 12, vous pouvez avoir des erreurs d'allocations de memoire
- selon votre compilateur et votre ordinateur. */
- unsigned int index_dic_max;
- /* index_dic_max donne le nombre maximum de mots dans le dictionnaire durant *une* compression.
- Cette constante est limitee entre code_fin_information et 2^EXP2_DIC_MAX. */
- unsigned char nb_bits_entree,
- /* Nombre de bits pour chaque donnee en entree.
- Avec nb_bits_entree=1, on peut compresser/decompresser des images monochromes
- et avec nb_bits_entree=8, on peut coder des images en 256 couleurs ou des fichiers quelconques. */
- nb_bits_codage_min;
- /* Nombre de bits pour coder code_initialisation. */
- unsigned int code_initialisation;
- unsigned int code_fin_information;
- /* code_initialisation et code_fin_information sont deux codes consecutifs
- qui arrivent juste apres le dernier mot connu du dictionnaire initial. */
-
- p_val_dic dictionnaire[1<<EXP2_DIC_MAX];
-
- void init_dictionnaire1()
- /* Parametres en sortie: Aucun.
- Action: Initialisation premiere du dictionnaire au debut d'un codage.
- Erreurs: Aucune s'il y a assez de place memoire.
- */
- { register unsigned int i;
-
- index_dic_max=1<<12; /* Attention: Valeurs possibles: 2^3 a 2^EXP2_DIC_MAX. */
- nb_bits_entree=8; /* Attention: Valeurs possibles 1 a EXP2_DIC_MAX-1
- (en general, pour des images a fixer a 1 ou 4 ou 8 si on a
- une image monochrome ou en 16 couleurs ou en 256 couleurs). */
- if (nb_bits_entree==1)
- nb_bits_codage_min=3;
- else nb_bits_codage_min=nb_bits_entree+1;
- code_initialisation=1<<(nb_bits_codage_min-1);
- #ifdef CODAGE_TYPE_GIF
- code_fin_information=code_initialisation+1;
- #else
- code_fin_information=code_initialisation-1;
- #endif
- for (i=0;i<=code_fin_information;i++)
- { if ((dictionnaire[i]=(p_val_dic)malloc(sizeof(t_val_dic)))==NULL)
- { while (i)
- { i--;
- free(dictionnaire[i]);
- }
- exit(BAD_MEM_ALLOC);
- }
- CARAC_VAL_DIC(dictionnaire[i])=i;
- CODE_VAL_DIC(dictionnaire[i])=i;
- PGAUCHE_VAL_DIC(dictionnaire[i])=NULL;
- PDROIT_VAL_DIC(dictionnaire[i])=NULL;
- }
- for (;i<index_dic_max;i++)
- dictionnaire[i]=NULL;
- index_dic=code_fin_information+1;
- nb_bits_codage=nb_bits_codage_min;
- }
-
- void init_dictionnaire2()
- /* Parametres en sortie: Aucun.
- Action: Initialisation du dictionnaire en cours de codage.
- Erreurs: Aucune.
- */
- { register unsigned int i;
-
- for (i=0;i<index_dic_max;i++)
- { PGAUCHE_VAL_DIC(dictionnaire[i])=NULL;
- PDROIT_VAL_DIC(dictionnaire[i])=NULL;
- }
- index_dic=code_fin_information+1;
- nb_bits_codage=nb_bits_codage_min;
- }
-
- void supprimer_dictionnaire()
- /* Parametres en sortie: Aucun.
- Action: Supprime le dictionnaire de codage de la memoire dynamique.
- Erreurs: Aucune.
- */
- { register unsigned int i;
-
- for (i=0;(i<index_dic_max)&&(dictionnaire[i]!=NULL);i++)
- free(dictionnaire[i]);
- }
-
- p_val_dic trouver_noeud(noeud_courant,symbole)
- /* Parametres en sortie: Renvoie un noeud de l'arborescence du dictionnaire.
- Action: Recherche 'symbole' a partir de 'noeud_courant'.
- Cette recherche se fait a partir du pointeur gauche du 'noeud_courant'
- (si le pointeur gauche ne valait pas NULL) puis se deplace
- sur tous les pointeurs droits jusqu'a atteindre le noeud contenant 'symbole'
- ou le dernier noeud dont le pointeur droit est NULL.
- Erreurs: Si le symbole n'a pas ete trouve, (noeud_courant=noeud retourne) ou (CHAR_DIC_VAL(noeud retourne)#symbole).
- Le 'noeud_courant' passe a cette routine ne doit jamais valoir NULL.
- */
- p_val_dic noeud_courant;
- unsigned int symbole;
- { p_val_dic nouveau_noeud;
-
- if (PGAUCHE_VAL_DIC(noeud_courant)==NULL)
- return noeud_courant;
- else { nouveau_noeud=PGAUCHE_VAL_DIC(noeud_courant);
- while ((CARAC_VAL_DIC(nouveau_noeud)!=symbole)&&(PDROIT_VAL_DIC(nouveau_noeud)!=NULL))
- nouveau_noeud=PDROIT_VAL_DIC(nouveau_noeud);
- return nouveau_noeud;
- }
- }
-
- void ajouter_noeud(noeud_courant,nouveau_noeud,symbole)
- /* Parametres en sortie: Aucun.
- Action: Cree un nouveau_noeud dans l'arborescence du dictionnaire.
- L'appel a cette routine intervient normalement apres un appel a trouver_noeud.
- Erreurs: Aucune.
- */
- p_val_dic noeud_courant,nouveau_noeud;
- unsigned int symbole;
- { if (dictionnaire[index_dic]==NULL)
- { if ((dictionnaire[index_dic]=(p_val_dic)malloc(sizeof(t_val_dic)))==NULL)
- { supprimer_dictionnaire();
- exit(BAD_MEM_ALLOC);
- }
- CODE_VAL_DIC(dictionnaire[index_dic])=index_dic;
- PGAUCHE_VAL_DIC(dictionnaire[index_dic])=NULL;
- PDROIT_VAL_DIC(dictionnaire[index_dic])=NULL;
- }
- CARAC_VAL_DIC(dictionnaire[index_dic])=symbole;
- if (noeud_courant==nouveau_noeud)
- PGAUCHE_VAL_DIC(nouveau_noeud)=dictionnaire[index_dic];
- else PDROIT_VAL_DIC(nouveau_noeud)=dictionnaire[index_dic];
- index_dic++;
- if (index_dic==(1 << nb_bits_codage))
- nb_bits_codage++;
- }
-
- #define dictionnaire_sature() (index_dic==index_dic_max)
-
- void ecrire_code_gd(valeur)
- /* Parametres en sortie: Aucun.
- Action: Envoie la 'valeur' codee sur 'nb_bits_codage' bits dans le flux de codes de sortie.
- Les bits sont inscrits de gauche a droite. Exemple: aaabbbbcccc est ecrit:
- Bits 7 6 5 4 3 2 1 0
- Octet 1 a a a b b b b c
- Octet 2 c c c ? ? ? ? ?
- Erreurs: Une erreur d'entree/sortie peut perturber le deroulement de l'algorithme.
- */
- unsigned int valeur;
- { val_a_ecrire=(val_a_ecrire << nb_bits_codage) | valeur;
- nb_bits_a_ecrire += nb_bits_codage;
- while (nb_bits_a_ecrire>=8)
- { nb_bits_a_ecrire -= 8;
- ecrire_octet((unsigned char)(val_a_ecrire >> nb_bits_a_ecrire));
- val_a_ecrire &= ((1<< nb_bits_a_ecrire)-1);
- }
- }
-
- void completer_codage_gd()
- /* Parametres en sortie: Aucune.
- Action: Complete le dernier octet a ecrire par des bits a 0, si necessaire.
- Cette procedure est a considerer avec la procedure ecrire_code_gd.
- Erreurs: Une erreur d'entree/sortie peut perturber le deroulement de l'algorithme.
- */
- { if (nb_bits_a_ecrire>0)
- ecrire_octet((unsigned char)(val_a_ecrire << (8-nb_bits_a_ecrire)));
- val_a_ecrire=nb_bits_a_ecrire=0;
- }
-
- void ecrire_code_dg(valeur)
- /* Parametres en sortie: Aucun.
- Action: Envoie la 'valeur' codee sur 'nb_bits_codage' bits dans le flux de codes de sortie
- Les bits sont inscrits de droite a gauche. Exemple: aaabbbbcccc est ecrit:
- Bits 7 6 5 4 3 2 1 0
- Octet 1 c b b b b a a a
- Octet 2 ? ? ? ? ? c c c
- Erreurs: Une erreur d'entree/sortie peut perturber le deroulement de l'algorithme.
- */
- unsigned int valeur;
- { val_a_ecrire |= ((unsigned long int)valeur) << nb_bits_a_ecrire;
- nb_bits_a_ecrire += nb_bits_codage;
- while (nb_bits_a_ecrire>=8)
- { nb_bits_a_ecrire -= 8;
- ecrire_octet((unsigned char)(val_a_ecrire&0xFF));
- val_a_ecrire = (val_a_ecrire>>8)&((1<< nb_bits_a_ecrire)-1);
- }
- }
-
- void completer_codage_dg()
- /* Parametres en sortie: Aucune.
- Action: Complete le dernier octet a ecrire par des bits a 0, si necessaire.
- Cette procedure est a considerer avec la procedure ecrire_code_dg.
- Erreurs: Une erreur d'entree/sortie peut perturber le deroulement de l'algorithme.
- */
- { if (nb_bits_a_ecrire>0)
- ecrire_octet((unsigned char)val_a_ecrire);
- val_a_ecrire=nb_bits_a_ecrire=0;
- }
-
- unsigned int lire_entree()
- /* Parametres en sortie: Aucune.
- Action: Lit nb_bits_entree via la fonction lire_octet.
- Erreurs: Une erreur d'entree/sortie peut perturber le deroulement de l'algorithme.
- */
- { unsigned int code_lu;
-
- while (nb_bits_a_lire<nb_bits_entree)
- { val_a_lire=(val_a_lire<<8)|lire_octet();
- nb_bits_a_lire += 8;
- }
- nb_bits_a_lire -= nb_bits_entree;
- code_lu=val_a_lire>>nb_bits_a_lire;
- val_a_lire &= ((1<<nb_bits_a_lire)-1);
- return code_lu;
- }
-
- #define fin_entree() ((nb_bits_a_lire<nb_bits_entree)&&fin_des_donnees())
-
- void codagelzw()
- /* Parametres en sortie: Aucun.
- Action: Compresse suivant la methode de LZW tous les octets lus par la fonction lire_entree.
- Erreurs: Une erreur d'entree/sortie peut perturber le deroulement de l'algorithme.
- */
- { p_val_dic noeud_courant,nouveau_noeud;
- unsigned int symbole;
-
- if (!fin_entree())
- { init_dictionnaire1();
- #ifdef CODAGE_TYPE_GIF
- ecrire_code_gd(code_initialisation);
- #endif
- noeud_courant=dictionnaire[lire_entree()];
- while (!fin_entree())
- { symbole=lire_entree();
- nouveau_noeud=trouver_noeud(noeud_courant,symbole);
- if ((nouveau_noeud!=noeud_courant)&&(CARAC_VAL_DIC(nouveau_noeud)==symbole))
- noeud_courant=nouveau_noeud;
- else { ecrire_code_gd(CODE_VAL_DIC(noeud_courant));
- ajouter_noeud(noeud_courant,nouveau_noeud,symbole);
- if dictionnaire_sature()
- {
- #ifdef CODAGE_TYPE_GIF
- ecrire_code_gd(code_initialisation);
- #endif
- init_dictionnaire2();
- }
- noeud_courant=dictionnaire[symbole];
- }
- }
- ecrire_code_gd(CODE_VAL_DIC(noeud_courant));
- #ifdef CODAGE_TYPE_GIF
- ecrire_code_gd(code_fin_information);
- #endif
- completer_codage_gd();
- supprimer_dictionnaire();
- }
- }
-
- void aide()
- /* Parametres en sortie: Aucun.
- Action: Affiche l'aide du programme et termine son execution.
- Erreurs: Aucune.
- */
- { printf("Cet utilitaire permet de compresser un fichier par la methode de LZW\n");
- printf("telle qu'elle est exposee dans 'La Video et Les Imprimantes sur PC'\n");
- printf("\nUsage: codlzw source destination\n");
- printf("source: Nom du fichier a compresser\n");
- printf("destination: Nom du fichier compresse\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 { codagelzw();
- fclose(f_source);
- fclose(f_dest);
- }
- printf("Execution de codlzw achevee.\n");
- return (NO_ERROR);
- }
-