?? dcodlzw.c
字號:
/* Fichier: dcodlzw.c Auteur: David Bourgin Date de creation: 14/2/94 Date de derniere mise a jour: 12/10/95 Dessein: Exemple de decodage LZW avec comme donnees a decompresser le contenu d'un fichier.*/#include <stdio.h>/* Pour les routines printf,fgetc,fputc. */#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#define BAD_DATA_CODE 4#define DICTIONARY_OVERFLOW 5/* 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_ecrire=0, val_a_lire=0;unsigned char nb_bits_a_ecrire=0, nb_bits_a_lire=0;typedef struct s_chainage_dic { unsigned int carac; struct s_chainage_dic *precedent; } t_chainage_dic,*p_chainage_dic;#define CARAC_CHAINAGE(dic) ((*(dic)).carac)#define PREC_CHAINAGE(dic) ((*(dic)).precedent)#define CODAGE_TYPE_GIF/* Implique l'inclusion des codes des marqueurs code_initialisation et code_fin_information. Pour invalider cette option, mettre la ligne #define... en commentaire. */#ifdef CODAGE_TYPE_GIF#define AUTO_DIC_REINIT/* Si cette macro est definie, le dictionnaire est toujours augmente (quitte a creer une erreur de debordement!). Si au contraire, cette macro est indefinie, le dictionnaire n'est plus mis a jour des que celui-ci atteint sa capacite maximale. C'est la reception du code 'code_initialisation' qui forcera le dictionnaire a etre vide. Pour invalider cette option, mettre la ligne #define... en commentaire. Cette macro est observee que si CODAGE_TYPE_GIF est defini, ce qui explique la presence des lignes #ifdef... et #endif... */#endifunsigned int index_dic;/* Nombre de mots deja reconnus dans le dictionnaire. */unsigned char nb_bits_decodage;/* Nombre de bits en decodage. */#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_sortie,/* Nombre de bits pour chaque donnee en sortie. Avec nb_bits_sortie=1, on peut compresser/decompresser des images monochromes et avec nb_bits_sortie=8, on peut coder des images en 256 couleurs ou des fichiers quelconques. */ nb_bits_decodage_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_chainage_dic dictionnaire[1<<EXP2_DIC_MAX];void init_dictionnaire1()/* Parametres en sortie: Aucun. Action: Initialise le dictionnaire qui va servir au chainage LZW. 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_sortie=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_sortie==1) nb_bits_decodage_min=3; else nb_bits_decodage_min=nb_bits_sortie+1; code_initialisation=1<<(nb_bits_decodage_min-1);#ifdef CODAGE_TYPE_GIF code_fin_information=code_initialisation+1;#else code_fin_information=code_initialisation-1;#endif for (i=0;i<index_dic_max;i++) { if ((dictionnaire[i]=(p_chainage_dic)malloc(sizeof(t_chainage_dic)))==NULL) { while (i) { i--; free(dictionnaire[i]); } fclose(f_source); fclose(f_dest); exit(BAD_MEM_ALLOC); } if (i<code_initialisation) CARAC_CHAINAGE(dictionnaire[i])=i; PREC_CHAINAGE(dictionnaire[i])=NULL; } index_dic=code_fin_information+1; nb_bits_decodage=nb_bits_decodage_min;}void init_dictionnaire2()/* Parametres en sortie: Aucun. Action: Reinitialise le dictionnaire qui va servir au chainage LZW. Ce dictionnaire doit deja avoir ete initialise par 'init_dictionnaire1'. Erreurs: Aucune.*/{ register unsigned int i; for (i=code_initialisation;(i<index_dic_max)&&(dictionnaire[i]!=NULL);i++) PREC_CHAINAGE(dictionnaire[i])=NULL; index_dic=code_fin_information+1; nb_bits_decodage=nb_bits_decodage_min;}void supprimer_dictionnaire()/* Parametres en sortie: Aucun. Action: Supprime le dictionnaire qui a servi au chainage LZW. Erreurs: Aucune si le dictionnaire a ete initialise par 'init_dictionnaire1'.*/{ register unsigned int i; for (i=0;(i<index_dic_max)&&(dictionnaire[i]!=NULL);i++) free(dictionnaire[i]);}void ecrire_sortie(valeur)/* Parametres en sortie: Aucune. Action: Ecrit nb_bits_sortie via la fonction ecrire_octet. Erreurs: Une erreur d'entree/sortie peut perturber le deroulement de l'algorithme.*/unsigned int valeur;{ val_a_ecrire=(val_a_ecrire << nb_bits_sortie) | valeur; nb_bits_a_ecrire += nb_bits_sortie; 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_sortie()/* 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_sortie. 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_chainage(chainage,carac)/* Parametres en sortie: 'carac' peut avoir ete modifie. Action: Envoie la chane dans le flux de sortie donne par le 'chainage' du dictionnaire LZW. 'carac' contient en fin de routine le premier caractere de la chaine. Erreurs: Aucune (sauf debordement possible de la pile operationnelle allouee par le programme qui doit permettre au moins 8*INDEX_DIC_MAX octets, ce qui correspond a un cas de figure exceptionnel.*/p_chainage_dic chainage;unsigned int *carac;{ if (PREC_CHAINAGE(chainage)!=NULL) { ecrire_chainage(PREC_CHAINAGE(chainage),carac); ecrire_sortie(CARAC_CHAINAGE(chainage)); } else { ecrire_sortie(CARAC_CHAINAGE(chainage)); *carac=CARAC_CHAINAGE(chainage); }}unsigned int ecrire_chaine(code_prec,code_actuel,premier_carac)/* Parametres en sortie: Renvoie un octet. Action: Ecrit la chaine d'octets associee a 'code_actuel' et renvoie le premier caractere de cette chaine. Erreurs: Aucune.*/unsigned int code_prec,code_actuel;unsigned int premier_carac;{ unsigned int carac; if (code_actuel<index_dic) ecrire_chainage(dictionnaire[code_actuel],&carac); else { ecrire_chainage(dictionnaire[code_prec],&carac); ecrire_sortie(premier_carac); } return carac;}void ajouter_chaine(code,premier_carac)/* Parametres en sortie: Aucun. Action: Ajoute au dictionnaire la chaine avec le 'code' donne. Erreurs: Aucune.*/unsigned int code;unsigned int premier_carac;{ CARAC_CHAINAGE(dictionnaire[index_dic])=premier_carac; PREC_CHAINAGE(dictionnaire[index_dic])=dictionnaire[code]; index_dic++; if (index_dic+1==(1<<nb_bits_decodage)) nb_bits_decodage++;}unsigned int lire_code_gd()/* Parametres en sortie: Renvoie la valeur d'un code. Action: Renvoie la valeur codee sur 'nb_bits_decodage' bits dans le flux de codes d'entree. 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 code_lu; while (nb_bits_a_lire<nb_bits_decodage) { val_a_lire=(val_a_lire<<8)|lire_octet(); nb_bits_a_lire += 8; } nb_bits_a_lire -= nb_bits_decodage; code_lu=val_a_lire>>nb_bits_a_lire; val_a_lire &= ((1<<nb_bits_a_lire)-1); return code_lu;}unsigned int lire_code_dg()/* Parametres en sortie: Renvoie la valeur d'un code. Action: Renvoie la valeur codee sur 'nb_bits_decodage' bits dans le flux de codes d'entree. 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 code_lu; while (nb_bits_a_lire<nb_bits_decodage) { val_a_lire |= ((unsigned long int)lire_octet())<<nb_bits_a_lire; nb_bits_a_lire += 8; } nb_bits_a_lire -= nb_bits_decodage; code_lu=val_a_lire & ((1<<nb_bits_decodage)-1); val_a_lire >>= nb_bits_decodage; return code_lu;}void decodagelzw()/* Parametres en sortie: Aucun. Action: Decompresse suivant la methode de LZW tous les octets lus par les fonctions 'lire_code_??'. (ou '??' est 'gd' ou 'dg' selon la facon dont vous stockiez les bits dans le flux compresse. Erreurs: Une erreur d'entree/sortie peut perturber le deroulement de l'algorithme.*/{ unsigned int code_prec,code_actuel; unsigned int premier_carac; if (!fin_des_donnees()) { init_dictionnaire1(); code_actuel=lire_code_gd();#ifdef CODAGE_TYPE_GIF if (code_actuel!=code_initialisation) { fprintf(stderr,"Fichier de codes invalide!\n"); supprimer_dictionnaire(); fclose(f_source); fclose(f_dest); exit(BAD_DATA_CODE); } if ((code_actuel=lire_code_gd())<code_initialisation) { premier_carac=ecrire_chaine(code_prec,code_actuel,premier_carac); code_prec=code_actuel; code_actuel=lire_code_gd(); } while (code_actuel!=code_fin_information) { if (code_actuel==code_initialisation) { init_dictionnaire2(); code_actuel=lire_code_gd(); if (code_actuel<code_initialisation) { premier_carac=ecrire_chaine(code_prec,code_actuel,premier_carac); code_prec=code_actuel; code_actuel=lire_code_gd(); } } else { if (code_actuel>index_dic) { fprintf(stderr,"Fichier de codes invalide!\n"); fclose(f_source); fclose(f_dest); exit(BAD_DATA_CODE); }#ifdef AUTO_DIC_REINIT if (index_dic==index_dic_max) { fprintf(stderr,"Depassement de capacite du dictionnaire!\n"); fclose(f_source); fclose(f_dest); exit(DICTIONARY_OVERFLOW); } premier_carac=ecrire_chaine(code_prec,code_actuel,premier_carac); ajouter_chaine(code_prec,premier_carac); code_prec=code_actuel; code_actuel=lire_code_gd();#else premier_carac=ecrire_chaine(code_prec,code_actuel,premier_carac); if (index_dic<index_dic_max) ajouter_chaine(code_prec,premier_carac); code_prec=code_actuel; code_actuel=lire_code_gd();#endif } } supprimer_dictionnaire();#else code_prec=code_actuel; premier_carac=ecrire_chaine(code_prec,code_actuel,premier_carac); while ((!fin_des_donnees())||(nb_bits_a_lire>=nb_bits_decodage)) { code_actuel=lire_code_gd(); if (code_actuel>index_dic) { fprintf(stderr,"Fichier de codes invalide!\n"); fclose(f_source); fclose(f_dest); exit(BAD_DATA_CODE); } premier_carac=ecrire_chaine(code_prec,code_actuel,premier_carac); if (index_dic==index_dic_max-2) { init_dictionnaire2(); if ((!fin_des_donnees())||(nb_bits_a_lire>=nb_bits_decodage)) { code_prec=(code_actuel=lire_code_gd()); premier_carac=ecrire_chaine(code_prec,code_actuel,premier_carac); } } else ajouter_chaine(code_prec,premier_carac); code_prec=code_actuel; } supprimer_dictionnaire();#endif completer_sortie(); }}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 LZW\n"); printf("telle qu'elle est exposee dans 'La Video et Les Imprimantes sur PC'\n"); printf("\nUsage: dcodlzw 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 { decodagelzw(); fclose(f_source); fclose(f_dest); } printf("Execution de dcodlzw achevee.\n"); return (NO_ERROR);}
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -