home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
DP Tool Club 21
/
CD_ASCQ_21_040595.iso
/
dos
/
prg
/
c
/
complzw
/
lzwdico.h
< prev
next >
Wrap
C/C++ Source or Header
|
1995-01-30
|
6KB
|
161 lines
#ifndef LZWDICO_H
#define LZWDICO_H
//////////////////////////////////////////////////////////////////////////
// Ce fichier implémente le dictionnaire spécifique LZW décrit par Mark
// Nelson dans son livre "La compression de données", chez Dunod qu'il me
// semble indispensable de consulter : je n'ai ni le courage ni le talent
// pour reprendre ici toutes les explications ; sachez que la suite n'est
// que la transposition en C++ de ce que vous trouvez en C classique dans
// Nelson. Par conséquent, les algorythmes ont été recopiés pratiquement
// tels quels, en tirant simplement parti des outils "objet" développés
// pour simplifier et sécuriser le code (donc faciliter la mise au point).
//
// -> Dans Nelson, voyez spécialement les pages 227 à 235, puis 240 à 248.
//
// Avant le dictionnaire (classe LZWico), il nous faut cependant définir
// une classes LZWEntree décrivant la structure de chacune de ses entrées.
// Chaque entrée est un noeud étiqueté par un caractère (donnée privée CAR).
// La donnée CODE est le code de la chaîne se terminant à ce noeud, tandis
// que CODE_PARENT est celui de la chaîne parente (la précédente, sauf CAR).
// Pour remonter les noeuds, il suffit de suivre les codes parents qui sont
// des numéros d'entrées dans le dictionnaire ; en revanche pour descendre
// il faut réaliser un hachage : voir la fonction index dans le .cpp.
//////////////////////////////////////////////////////////////////////////
///////////////
class LZWEntree {
///////////////
public :
typedef unsigned int code ; // un alias pour la clarté
static const code RIEN ;
static const code FIN_FICHIER ;
static const code ALLONGER_CODE ;
static const code VIDER_DICO ;
static const code IGNORER_DICO ; // inutilisé à ce jour (une autre
// stratégie suite au débordement
// du dico, serait de l'ignorer en
// ne comprimant plus, au lieu de
// le vider ; j'avais prévu ce code
// à tout hasard)
// Constructeur
LZWEntree() : CODE( RIEN ), CODE_PARENT( RIEN )
{ } // CAR est sans importance ici
// Mise à jour ultérieure de l'entrée
void ajoute ( code c, code cparent,
unsigned char car = ( unsigned char )0 )
{ CODE = c ; CODE_PARENT = cparent ; CAR = car ; }
// Consultation des données de l'entrée
code leCode () const { return CODE ; }
code leParent () const { return CODE_PARENT ; }
unsigned char leCar () const { return CAR ; }
private :
code CODE, CODE_PARENT ;
unsigned char CAR ;
} ;
/////////////
class LZWDico {
/////////////
public :
// Constructeur et destructeur
LZWDico ( unsigned int nombre_bits_final ) ;
~LZWDico () ;
// Consultation de données internes
unsigned int nbits () const { return NOMBRE_BITS_ACTUEL ; }
LZWEntree::code tailleDico () const { return TAILLE_DICO ; }
// Renvoie une référence à la ième entrée (sans test sur i !)
LZWEntree & operator[] ( LZWEntree::code i ) { return DICO[ i ] ; }
LZWEntree::code codeSuivant () const { return CODE_LIBRE_SUIVANT ; }
static LZWEntree::code codeDepart () { return CODE_DEPART ; }
enum etatCode { ras, pluslong, troplong } ;
etatCode incrementer () ;
etatCode incrementer ( unsigned int & ancien_nombre_bits ) ;
void allongerCode() { NOMBRE_BITS_ACTUEL++ ; }
static LZWEntree::code maxval ( unsigned int nbits ) { return ( LZWEntree::code )( ( ( ( unsigned long ) 1 ) << nbits ) - 1 ) ; }
LZWEntree::code index ( LZWEntree::code cparent, unsigned char carfils ) const ;
void vider () ;
#ifdef DEPANNAGE
void lister () const ;
#endif
private :
static const unsigned int NOMBRE_BITS_MIN ; // voir le .cpp
static const unsigned int NOMBRE_BITS_MAX ;
unsigned int NOMBRE_BITS_ACTUEL ;
static const LZWEntree::code CODE_DEPART ;
LZWEntree::code CODE_LIMITE ;
const LZWEntree::code CODE_FINAL ;
LZWEntree::code CODE_LIBRE_SUIVANT ;
LZWEntree * DICO ; // tableau des entrées
const LZWEntree::code TAILLE_DICO ;
static LZWEntree::code premier ( unsigned int nbits ) ;
} ;
inline LZWDico::etatCode LZWDico::incrementer()
//
// Incrémente inconditionnellement la valeur du pro-
// chain code disponible, sans autre effet de bord.
// (Ne sert que pour la décompression)
{
CODE_LIBRE_SUIVANT++ ;
return ras ;
}
inline LZWDico::etatCode LZWDico::incrementer( unsigned int & ancien_nombre_bits )
//
// Incrémente le prochain code libre, mais avec des effets de bord en cascade :
// - si la longueur de code est épuisée, il faut l'augmenter ;
// - si elle ne peut plus être augmentée, il faut vider le dico.
// Dans tous les cas, on renvoie une valeur de type énuméré ren-
// dant compte de que qu'on a fait ; quand un code spécial devra
// être émis pour renseigner le décompresseur, il devra l'être
// avec l'ancienne longueur (qu'on aura peut-être changée ici mê-
// me), donc on la passe à l'appelant dans un argument référence.
// Cette fonction sert pendant la compression.
{
ancien_nombre_bits = NOMBRE_BITS_ACTUEL ;
CODE_LIBRE_SUIVANT++ ;
// Débordement irrémédiable : la longueur de code ne peut être augmentée
if( CODE_LIBRE_SUIVANT > CODE_FINAL )
{
vider() ; // rétablit la longueur de code initiale
return troplong ; // avis de vidage
}
// Saturation de la longueur de code, qu'il suffit d'augmenter
if( CODE_LIBRE_SUIVANT > CODE_LIMITE )
{
NOMBRE_BITS_ACTUEL++ ;
CODE_LIMITE = maxval( NOMBRE_BITS_ACTUEL ) ;
return pluslong ; // avis d'incrémentation de la longueur
}
return ras ; // rien à signaler (pas de débordement)
}
#endif