/*************************************************************************************************************************************/
/*                                                                                                                                   */
/*        C O D A G E   D E   H U F F M A N   ' HUF '   E T   I N V E R S E  :                                                       */
/*                                                                                                                                   */
/*                                                                                                                                   */
/*        Nota :                                                                                                                     */
/*                                                                                                                                   */
/*                    Ce module est inspire de 'v $xtc/HuffmanCoding.01$I'                                                           */
/*                  qui a servi a sa mise au point...                                                                                */
/*                                                                                                                                   */
/*                                                                                                                                   */
/*        Author of '$xrC/CompressionDeCompression_HuffmanCoding.01$vv$I' :                                                          */
/*                                                                                                                                   */
/*                    Jean-Francois Colonna (LACTAMME, 20151227143815).                                                              */
/*                                                                                                                                   */
/*************************************************************************************************************************************/

/*************************************************************************************************************************************/
/*                                                                                                                                   */
/*        D E F I N I T I O N   G E N E R A L E S  :                                                                                 */
/*                                                                                                                                   */
/*************************************************************************************************************************************/
Logical   HUF_Utiliser=VRAI;

Logical   HUF_EditerFrequences=FAUX;
Logical   HUF_EditerArbre=FAUX;
Logical   HUF_EditerCodesDeHuffman=FAUX;
                                        /* Indicateurs de controle des editions...                                                   */

#define   PREMIER_CARACTERE                                                                                                             \
                    INDEX0
#define   DERNIER_CARACTERE                                                                                                             \
                    MASKO
#define   NOMBRE_DE_CARACTERES                                                                                                          \
                    ((DERNIER_CARACTERE-PREMIER_CARACTERE)+1)

/*************************************************************************************************************************************/
/*                                                                                                                                   */
/*        S T R U C T U R E S   F R E Q U E N T I E L L E S   D E S   C A R A C T E R E S  :                                         */
/*                                                                                                                                   */
/*************************************************************************************************************************************/
Entier    HUF_FrequencesDOccurenceDesCaracteres[NOMBRE_DE_CARACTERES];
Entier    HUF_DefinitionRedondanteDesCodesDesCaracteres[NOMBRE_DE_CARACTERES];
Entier    HUF_NumerosDesNoeudsDeRangementDesCaracteres[NOMBRE_DE_CARACTERES];
Entier    HUF_PremierCaractere=PREMIER_CARACTERE;
Entier    HUF_DernierCaractere=DERNIER_CARACTERE;
                                        /* On notera que tout est defini en 'int' afin d'eviter des debordements et des problemes    */
                                        /* de signe. On notera de plus que la definition des codes de caracteres n'est pas           */
                                        /* redondante avec les index d'acces a cause des permutations qui sont effectuees sur        */
                                        /* ces tableaux...                                                                           */
#define   HUF_TYPE_CaractereAssociesAuCodeBinaire                                                                                       \
                    CHAR
#define   HUF_TYPE_LongueurDuCodeBinaire                                                                                                \
                    CHAR
#define   HUF_TYPE_CodeBinaire                                                                                                          \
                    Entier
#define   HUF_SIZE_CodeBinaire                                                                                                          \
                    (HUF_NombreDeCodes                                                                                                  \
                     *(SIZEOF(HUF_TYPE_CaractereAssociesAuCodeBinaire)                                                                  \
                      +SIZEOF(HUF_TYPE_LongueurDuCodeBinaire)                                                                           \
                      +SIZEOF(HUF_TYPE_CodeBinaire)                                                                                     \
                       )                                                                                                                \
                     +SIZEOF(HUF_NombreDeCodes)                                                                                         \
                     )
HUF_TYPE_CaractereAssociesAuCodeBinaire HUF_CaractereAssociesAuCodeBinaire[NOMBRE_DE_CARACTERES];
HUF_TYPE_LongueurDuCodeBinaire          HUF_LongueurDuCodeBinaire[NOMBRE_DE_CARACTERES];
HUF_TYPE_CodeBinaire                    HUF_CodeBinaire[NOMBRE_DE_CARACTERES];
                                        /* Definition des codes entropiques de Huffman.                                              */
Entier    HUF_NombreDeCodes;
HUF_TYPE_CaractereAssociesAuCodeBinaire HUF_CaractereAssociesAuCodeBinaireCompacte[NOMBRE_DE_CARACTERES];
HUF_TYPE_LongueurDuCodeBinaire          HUF_LongueurDuCodeBinaireCompacte[NOMBRE_DE_CARACTERES];
HUF_TYPE_CodeBinaire                    HUF_CodeBinaireCompacte[NOMBRE_DE_CARACTERES];
                                        /* Definition des codes entropiques de Huffman apres compactage.                             */

Entier    HUF_NombreDeBitsApresCodage;
Entier    HUF_NombreDOctetsApresDecodage;
                                        /* Afin de faciliter l'exploitation des resultats...                                         */

Entier    HUF_Codage_LongueurAvant;
Entier    HUF_Codage_LongueurApres;
Entier    HUF_Decodage_LongueurAvant;
Entier    HUF_Decodage_LongueurApres;
                                        /* Afin de faciliter des verifications de coherence...                                       */

#define   NOEUD_INEXISTANT                                                                                                              \
                    (INDEX0-1)
#define   CARACTERE_INUTILISE                                                                                                           \
                    0
#define   CODE_DE_HUFFMAN_INUTILISE                                                                                                     \
                    0

/*************************************************************************************************************************************/
/*                                                                                                                                   */
/*        A N A L Y S E   F R E Q U E N T I E L L E   D E S   C A R A C T E R E S  :                                                 */
/*                                                                                                                                   */
/*************************************************************************************************************************************/
void      F_HUF_GenerationFrequences(CHAR chaine[],Entier longueur)
          {
          Entier    index;

          HUF_Codage_LongueurAvant = longueur;

          for       (index=INDEX0 ; index<=NombreVersIndex(longueur) ; index++)
                    {
                    HUF_FrequencesDOccurenceDesCaracteres[chaine[index]]++;
                                        /* La "frequence" est obtenu par un simple comptage des caracteres...                        */
                    }
          }

#define   D_HUF_Permutation(tableau,index1,index2)                                                                                      \
                    {                                                                                                                   \
                    Entier    SauvegardeTemporaire=tableau[index1];                                                                     \
                    tableau[index1] = tableau[index2];                                                                                  \
                    tableau[index2] = SauvegardeTemporaire;                                                                             \
                    }

void      F_HUF_TriCroissantDesFrequencesDesCaracteres()
          {
          Entier    index_de_fin;

          for       (index_de_fin=(HUF_DernierCaractere-1) ; index_de_fin>=HUF_PremierCaractere ; index_de_fin--)
                    {
                    Entier    index_de_debut;

                    for       (index_de_debut=HUF_PremierCaractere ; index_de_debut<=index_de_fin ; index_de_debut++)
                              {
                              if        (HUF_FrequencesDOccurenceDesCaracteres[index_de_debut]
                                        > HUF_FrequencesDOccurenceDesCaracteres[index_de_debut+1]
                                         )
                                        {
                                        D_HUF_Permutation(HUF_FrequencesDOccurenceDesCaracteres
                                                         ,index_de_debut
                                                         ,index_de_debut+1
                                                          );
                                        D_HUF_Permutation(HUF_DefinitionRedondanteDesCodesDesCaracteres
                                                         ,index_de_debut
                                                         ,index_de_debut+1
                                                          );
                                        D_HUF_Permutation(HUF_NumerosDesNoeudsDeRangementDesCaracteres
                                                         ,index_de_debut
                                                         ,index_de_debut+1
                                                          );
                                        /* Cette echange conserve l'ordre des elements possedant la meme "clef"...                   */
                                        }
                              else
                                        {
                                        }
                              }
                    }

          for       (index_de_fin=HUF_PremierCaractere ; index_de_fin<=HUF_DernierCaractere ; index_de_fin++)
                    {
                    if        (HUF_FrequencesDOccurenceDesCaracteres[index_de_fin] == CARACTERE_INUTILISE)
                              {
                              HUF_PremierCaractere = index_de_fin+1;
                                        /* Afin de ne parcourir que les entrees utiles (dont les frequences sont donc differentes    */
                                        /* de 'CARACTERE_INUTILISE'...). On notera que 'DernierCaractere' ne bouge pas ; il vaut     */
                                        /* en effet toujours 'DERNIER_CARACTERE'...                                                  */
                              }
                    else
                              {
                              }
                    }
          }

#define   CARACTERE_INEXISTANT                                                                                                          \
                    (PREMIER_CARACTERE-1)

#define   PREMIER_CARACTERE_EDITABLE                                                                                                    \
                    0x20
#define   DERNIER_CARACTERE_EDITABLE                                                                                                    \
                    0x7e

void      F_HUF_EditionDesFrequencesDesCaracteres()
          {
          Entier    index;

          if        (HUF_EditerFrequences == VRAI)
                    {
                    printf("HUF/Frequences :\n");

                    for       (index=HUF_PremierCaractere ; index<=HUF_DernierCaractere ; index++)
                              {
                              if        (HUF_FrequencesDOccurenceDesCaracteres[index] != CARACTERE_INUTILISE)
                                        {
                                        if        (HUF_DefinitionRedondanteDesCodesDesCaracteres[index] > CARACTERE_INEXISTANT)
                                                  {
                                                  if   (    ((CHAR)HUF_DefinitionRedondanteDesCodesDesCaracteres[index]
                                                            >= PREMIER_CARACTERE_EDITABLE
                                                             )
                                                       &&   ((CHAR)HUF_DefinitionRedondanteDesCodesDesCaracteres[index]
                                                            <= DERNIER_CARACTERE_EDITABLE
                                                             )
                                                        )
                                                       {
                                                       printf("caractere='%c' (0x%02"For16") frequence=%"For10" noeud=%"For10"\n"
                                                             ,(CHAR)HUF_DefinitionRedondanteDesCodesDesCaracteres[index]
                                                             ,HUF_DefinitionRedondanteDesCodesDesCaracteres[index]
                                                             ,HUF_FrequencesDOccurenceDesCaracteres[index]
                                                             ,HUF_NumerosDesNoeudsDeRangementDesCaracteres[index]
                                                              );
                                                       }
                                                  else
                                                       {
                                                       printf("caractere=    (0x%02"For16") frequence=%"For10" noeud=%"For10"\n"
                                                             ,HUF_DefinitionRedondanteDesCodesDesCaracteres[index]
                                                             ,HUF_FrequencesDOccurenceDesCaracteres[index]
                                                             ,HUF_NumerosDesNoeudsDeRangementDesCaracteres[index]
                                                              );
                                                       }
                                        /* Cas des "vrais" caracteres...                                                             */
                                                  }
                                        else
                                                  {
                                                  printf("*                 frequence=%"For10" noeud=%"For10"\n"
                                                        ,HUF_FrequencesDOccurenceDesCaracteres[index]
                                                        ,HUF_NumerosDesNoeudsDeRangementDesCaracteres[index]
                                                         );
                                        /* Cas des caracteres de type "cumul"...                                                     */
                                                  }
                                        }
                              else
                                        {
                                        }
                              }
                    }
          else
                    {
                    }
          }

/*************************************************************************************************************************************/
/*                                                                                                                                   */
/*        G E S T I O N   D E   L ' A R B R E   D E S   C O D E S   D E   H U F F M A N  :                                           */
/*                                                                                                                                   */
/*************************************************************************************************************************************/
#define   NOMBRE_MAXIMAL_DE_NOEUDS_DE_L_ARBRE                                                                                           \
                    (2*NOMBRE_DE_CARACTERES)
#define   PREMIER_NOEUD_DE_L_ARBRE                                                                                                      \
                    INDEX0
#define   DERNIER_NOEUD_DE_L_ARBRE                                                                                                      \
                    NombreVersIndex(HUF_IdentiteDuNoeudCourantDeLArbre)
#define   SUIVANT_INEXISTANT                                                                                                            \
                    (PREMIER_NOEUD_DE_L_ARBRE-1)

#define   HUF_TYPE_ArbreCaracteresEnChaqueNoeud                                                                                         \
                    Entier
#define   HUF_TYPE_ArbreChainageAGauche                                                                                                 \
                    Entier
#define   HUF_TYPE_ArbreChainageADroite                                                                                                 \
                    Entier
                                        /* On notera qu'en theorie le nombre d'octets necessaires devrait etre au plus :             */
                                        /*                                                                                           */
                                        /*                  ArbreCaracteresEnChaqueNoeud  1                                          */
                                        /*                  ArbreChainageAGauche          2                                          */
                                        /*                  ArbreChainageADroite          2                                          */
                                        /*                                                                                           */
                                        /* mais qu'a cause des fonctions de mesure c'est actuellement (le 20160103103543)            */
                                        /* difficile a mettre en place...                                                            */
#define   HUF_SIZE_Arbre                                                                                                                \
                    (HUF_IdentiteDuNoeudCourantDeLArbre                                                                                 \
                     *(SIZEOF(HUF_TYPE_ArbreCaracteresEnChaqueNoeud)                                                                    \
                      +SIZEOF(HUF_TYPE_ArbreChainageAGauche)                                                                            \
                      +SIZEOF(HUF_TYPE_ArbreChainageADroite)                                                                            \
                       )                                                                                                                \
                     )                                                                                                                  \
                                        /* On notera que 'ArbreFrequenceDesNoeuds' est inutile pour la mesure de 'K'...              */
Entier    HUF_ArbreFrequenceDesNoeuds[NOMBRE_MAXIMAL_DE_NOEUDS_DE_L_ARBRE];

HUF_TYPE_ArbreCaracteresEnChaqueNoeud   HUF_ArbreCaracteresEnChaqueNoeud[NOMBRE_MAXIMAL_DE_NOEUDS_DE_L_ARBRE];
HUF_TYPE_ArbreChainageAGauche           HUF_ArbreChainageAGauche[NOMBRE_MAXIMAL_DE_NOEUDS_DE_L_ARBRE];
HUF_TYPE_ArbreChainageADroite           HUF_ArbreChainageADroite[NOMBRE_MAXIMAL_DE_NOEUDS_DE_L_ARBRE];

#define   HUF_SIZE_IdentiteDuNoeudCourantDeLArbre                                                                                       \
                    SIZEOF(HUF_IdentiteDuNoeudCourantDeLArbre)
Entier    HUF_IdentiteDuNoeudCourantDeLArbre=PREMIER_NOEUD_DE_L_ARBRE;
Entier    HUF_RacineDeLArbre;
                                        /* Definition de l'arbre de codage...                                                        */

#define   D_HUF_MiseAJourArbre(frequence,caractere,ChainageAGauche,ChainageADroite)                                                     \
                                        /* On notera qu'a GAUCHE se trouve la FREQUENCE MINIMALE...                                  */ \
                    {                                                                                                                   \
                    HUF_ArbreFrequenceDesNoeuds[HUF_IdentiteDuNoeudCourantDeLArbre] = frequence;                                        \
                    HUF_ArbreCaracteresEnChaqueNoeud[HUF_IdentiteDuNoeudCourantDeLArbre] = caractere;                                   \
                    HUF_ArbreChainageAGauche[HUF_IdentiteDuNoeudCourantDeLArbre] = ChainageAGauche;                                     \
                    HUF_ArbreChainageADroite[HUF_IdentiteDuNoeudCourantDeLArbre] = ChainageADroite;                                     \
                                                                                                                                        \
                    if        (HUF_IdentiteDuNoeudCourantDeLArbre < NombreVersIndex(NOMBRE_MAXIMAL_DE_NOEUDS_DE_L_ARBRE))               \
                              {                                                                                                         \
                              HUF_IdentiteDuNoeudCourantDeLArbre++;                                                                     \
                              }                                                                                                         \
                    else                                                                                                                \
                              {                                                                                                         \
                              fprintf(stderr,"ERREUR(HUF) : Debordement de l'arbre.\n");                                                \
                              }                                                                                                         \
                    }

void      F_HUF_GenerationDeLArbre()
          {
          Logical   ItererLaGenerationDeLArbre=VRAI;

          while     (ItererLaGenerationDeLArbre == VRAI)
                    {
                    Entier    index;
                    Entier    IndexFrequenceMinimaleGauche,FrequenceMinimaleGauche,CaractereGauche,NoeudFilsGauche;
                    Entier    IndexFrequenceMinimaleDroite,FrequenceMinimaleDroite,CaractereDroite,NoeudFilsDroite;
                    Entier    SommeDesFrequencesEnUnNoeud=0;

                    F_HUF_TriCroissantDesFrequencesDesCaracteres();
                    F_HUF_EditionDesFrequencesDesCaracteres();
                                        /* Tri destine a garantir l'ordre des frequences...                                          */

                    index=HUF_PremierCaractere;

                    while     (         (HUF_FrequencesDOccurenceDesCaracteres[index] == CARACTERE_INUTILISE)
                              &&        (index < HUF_DernierCaractere)
                               )
                              {
                              index++;
                              }

                    IndexFrequenceMinimaleGauche = index;

                    FrequenceMinimaleGauche= HUF_FrequencesDOccurenceDesCaracteres[IndexFrequenceMinimaleGauche];
                    CaractereGauche = HUF_DefinitionRedondanteDesCodesDesCaracteres[IndexFrequenceMinimaleGauche];

                    if        (CaractereGauche != CARACTERE_INEXISTANT)
                              {
                              NoeudFilsGauche = HUF_IdentiteDuNoeudCourantDeLArbre;
                              HUF_NumerosDesNoeudsDeRangementDesCaracteres[IndexFrequenceMinimaleGauche]
                              = NoeudFilsGauche;

                              D_HUF_MiseAJourArbre(FrequenceMinimaleGauche
                                                  ,CaractereGauche
                                                  ,SUIVANT_INEXISTANT
                                                  ,SUIVANT_INEXISTANT
                                                   );
                                        /* Creation d'une feuille de l'arbre (noeud donnant donc un caractere).                      */
                              }
                    else
                              {
                              NoeudFilsGauche = HUF_NumerosDesNoeudsDeRangementDesCaracteres[IndexFrequenceMinimaleGauche];
                                        /* Cas d'un noeud de cumul de l'arbre deja genere.                                           */
                              }

                    SommeDesFrequencesEnUnNoeud = SommeDesFrequencesEnUnNoeud + FrequenceMinimaleGauche;

                    HUF_DefinitionRedondanteDesCodesDesCaracteres[IndexFrequenceMinimaleGauche] = CARACTERE_INEXISTANT;
                    HUF_FrequencesDOccurenceDesCaracteres[IndexFrequenceMinimaleGauche] = CARACTERE_INUTILISE;
                                        /* Ainsi, ce caractere dont la frequence va etre cumule un peu plus loin disparait en        */
                                        /* quelque sorte de la liste des caracteres a traiter (via donc une frequence nulle).        */

                    index=HUF_PremierCaractere;

                    while     (         (HUF_FrequencesDOccurenceDesCaracteres[index] == CARACTERE_INUTILISE)
                              &&        (index < HUF_DernierCaractere)
                               )
                              {
                              index++;
                              }

                    IndexFrequenceMinimaleDroite = index;

                    if        (IndexFrequenceMinimaleGauche != IndexFrequenceMinimaleDroite)
                              {
                              FrequenceMinimaleDroite = HUF_FrequencesDOccurenceDesCaracteres[IndexFrequenceMinimaleDroite];
                              CaractereDroite = HUF_DefinitionRedondanteDesCodesDesCaracteres[IndexFrequenceMinimaleDroite];

                              if        (FrequenceMinimaleGauche > FrequenceMinimaleDroite)
                                        {
                                        fprintf(stderr
                                               ,"ERREUR(HUF) : FreqMinGauche=%"For10" > FreqMinDroite=%"For10"\n"
                                               ,FrequenceMinimaleGauche
                                               ,FrequenceMinimaleDroite
                                                );
                                        }
                              else
                                        {
                                        }

                              if        (CaractereDroite != CARACTERE_INEXISTANT)
                                        {
                                        NoeudFilsDroite = HUF_IdentiteDuNoeudCourantDeLArbre;
                                        HUF_NumerosDesNoeudsDeRangementDesCaracteres[IndexFrequenceMinimaleDroite]
                                        = NoeudFilsDroite;

                                        D_HUF_MiseAJourArbre(FrequenceMinimaleDroite
                                                            ,CaractereDroite
                                                            ,SUIVANT_INEXISTANT
                                                            ,SUIVANT_INEXISTANT
                                                             );
                                        /* Creation d'une feuille de l'arbre (noeud donnant donc un caractere).                      */
                                        }
                              else
                                        {
                                        NoeudFilsDroite = HUF_NumerosDesNoeudsDeRangementDesCaracteres[IndexFrequenceMinimaleDroite];
                                        /* Cas d'un noeud de cumul de l'arbre deja genere.                                           */
                                        }

                              SommeDesFrequencesEnUnNoeud = SommeDesFrequencesEnUnNoeud + FrequenceMinimaleDroite;

                              HUF_DefinitionRedondanteDesCodesDesCaracteres[IndexFrequenceMinimaleDroite] = CARACTERE_INEXISTANT;
                              HUF_FrequencesDOccurenceDesCaracteres[IndexFrequenceMinimaleDroite] = SommeDesFrequencesEnUnNoeud;
                                        /* Ainsi, ce caractere dont la frequence vient d'etre cumule est remplace par ce cumul...    */

                              HUF_NumerosDesNoeudsDeRangementDesCaracteres[IndexFrequenceMinimaleDroite]
                              = HUF_IdentiteDuNoeudCourantDeLArbre;

                              D_HUF_MiseAJourArbre(SommeDesFrequencesEnUnNoeud
                                                  ,CARACTERE_INEXISTANT
                                                  ,NoeudFilsGauche
                                                  ,NoeudFilsDroite
                                                   );
                                        /* Creation d'un noeud de cumul de l'arbre.                                                  */

                              }
                    else
                              {
                              ItererLaGenerationDeLArbre = FAUX;
                              }
                    }
          HUF_RacineDeLArbre = HUF_IdentiteDuNoeudCourantDeLArbre-1;
          }

void      F_HUF_EditionDeLArbre()
          {
          if        (HUF_EditerArbre == VRAI)
                    {
                    Entier    index;

                    printf("HUF/EditionDeLArbre :\n");

                    for       (index=PREMIER_NOEUD_DE_L_ARBRE ; index<=DERNIER_NOEUD_DE_L_ARBRE ; index++)
                              {
                              printf("noeud=%04"For10"     frequence=%08"For10""
                                    ,index
                                    ,HUF_ArbreFrequenceDesNoeuds[index]
                                     );

                              if        (HUF_ArbreCaracteresEnChaqueNoeud[index] != CARACTERE_INEXISTANT)
                                        {
                                        printf("       caractere=0x%02"For16""
                                              ,HUF_ArbreCaracteresEnChaqueNoeud[index]
                                               );
                                        }
                              else
                                        {
                                        printf("       *             ");
                                        }

                              if        (HUF_ArbreChainageAGauche[index] != NOEUD_INEXISTANT)
                                        {
                                        printf("      ChainageAGauche=%04"For10""
                                              ,HUF_ArbreChainageAGauche[index]
                                               );
                                        }
                              else
                                        {
                                        }

                              if        (HUF_ArbreChainageADroite[index] != NOEUD_INEXISTANT)
                                        {
                                        printf("     ChainageADroite=%04"For10""
                                              ,HUF_ArbreChainageADroite[index]
                                               );
                                        }
                              else
                                        {
                                        }

                              printf("\n");
                              }
                    }
          else
                    {
                    }
          }

#define   GAUCHE                                                                                                                        \
                    1
#define   DROITE                                                                                                                        \
                    0

#define   BASE2                                                                                                                         \
                    2

void      F_HUF_ParcoursRecursifDeLArbre(Entier racine,Entier CodeBinaire,Entier LongueurCodeBinaire)
          {
          if        (racine != NOEUD_INEXISTANT)
                    {
                    if        (         (HUF_ArbreChainageAGauche[racine] != NOEUD_INEXISTANT)
                              &&        (HUF_ArbreChainageADroite[racine] != NOEUD_INEXISTANT)
                               )
                              {
                              if        (LongueurCodeBinaire < (NBITMO-1))
                                        {
                                        F_HUF_ParcoursRecursifDeLArbre(HUF_ArbreChainageAGauche[racine]
                                                                      ,(BASE2*CodeBinaire)+GAUCHE
                                                                      ,LongueurCodeBinaire+1
                                                                       );
                                        F_HUF_ParcoursRecursifDeLArbre(HUF_ArbreChainageADroite[racine]
                                                                      ,(BASE2*CodeBinaire)+DROITE
                                                                      ,LongueurCodeBinaire+1
                                                                       );
                                        }
                              else
                                        {
                                        fprintf(stderr,"ERREUR(HUF) : Un code binaire est trop long.\n");
                                        }
                              }
                    else
                              {
                              Entier    caractere=HUF_ArbreCaracteresEnChaqueNoeud[racine];
                              Entier    longueur=COND((LongueurCodeBinaire == 0),1,LongueurCodeBinaire);
                                        /* Le forcage de la longueur 1 est destine au cas ou l'arbre se reduit a sa racine, ce qui   */
                                        /* signifie que la chaine de caracteres ne possede qu'une suite de caracteres identiques.    */

                              HUF_LongueurDuCodeBinaire[caractere] = longueur;
                              HUF_CodeBinaire[caractere] = CodeBinaire;

                              if        (caractere != HUF_CaractereAssociesAuCodeBinaire[caractere])
                                        {
                                        fprintf(stderr,"ERREUR(HUF) : Les tables de Huffman sont incoherentes.\n");
                                        }
                              else
                                        {
                                        }
                              }
                    }
          else
                    {
                    }
          }

void      F_HUF_CompactageDesCodesDeHuffman()
          {
          Entier    index_1;

          HUF_NombreDeCodes = 0;

          for       (index_1=PREMIER_CARACTERE ; index_1<=DERNIER_CARACTERE ; index_1++)
                    {
                    Entier    LongueurCodeBinaire=HUF_LongueurDuCodeBinaire[index_1];

                    if        (LongueurCodeBinaire != CODE_DE_HUFFMAN_INUTILISE)
                              {
                              Entier    index_2;

                              HUF_NombreDeCodes++;

                              index_2=NombreVersIndex(HUF_NombreDeCodes);
                              HUF_CaractereAssociesAuCodeBinaireCompacte[index_2] = HUF_CaractereAssociesAuCodeBinaire[index_1];
                              HUF_LongueurDuCodeBinaireCompacte[index_2] = HUF_LongueurDuCodeBinaire[index_1];
                              HUF_CodeBinaireCompacte[index_2] = HUF_CodeBinaire[index_1];
                              }
                    else
                              {
                              }
                    }
          }

void      F_HUF_DeCompactageDesCodesDeHuffman()
          {
          Entier    index_1;

          DoIn(index_1,PREMIER_CARACTERE,DERNIER_CARACTERE)
                    {
                    mEGAL(ACCES_CHAINE(HUF_CaractereAssociesAuCodeBinaire,index_1),index_1);
                    mEGAL(ACCES_CHAINE(HUF_LongueurDuCodeBinaire,index_1),CODE_DE_HUFFMAN_INUTILISE);
                    mEGAL(HUF_CodeBinaire[index_1],CODE_DE_HUFFMAN_INUTILISE);
                    }
          EDoI

          DoIn(index_1,INDEX0,NombreVersIndex(HUF_NombreDeCodes))
                    {
                    Entier    index_2;

                    mEGAL(index_2,HUF_CaractereAssociesAuCodeBinaireCompacte[index_1]);

                    mEGAL(ACCES_CHAINE(HUF_CaractereAssociesAuCodeBinaire,index_2),index_2);
                    mEGAL(ACCES_CHAINE(HUF_LongueurDuCodeBinaire,index_2),HUF_LongueurDuCodeBinaireCompacte[index_1]);
                    mEGAL(HUF_CodeBinaire[index_2],HUF_CodeBinaireCompacte[index_1]);
                    }
          EDoI
          }

/*************************************************************************************************************************************/
/*                                                                                                                                   */
/*        I N T I A L I S A T I O N S   D I V E R S E S  :                                                                           */
/*                                                                                                                                   */
/*************************************************************************************************************************************/
void      F_HUF_Initialisations()
          {
          Entier    index;

          HUF_PremierCaractere=PREMIER_CARACTERE;
          HUF_DernierCaractere=DERNIER_CARACTERE;
          HUF_IdentiteDuNoeudCourantDeLArbre=PREMIER_NOEUD_DE_L_ARBRE;

          for       (index=HUF_PremierCaractere ; index<=HUF_DernierCaractere ; index++)
                    {
                    HUF_FrequencesDOccurenceDesCaracteres[index] = 0;
                    HUF_DefinitionRedondanteDesCodesDesCaracteres[index] = index;
                    HUF_NumerosDesNoeudsDeRangementDesCaracteres[index] = NOEUD_INEXISTANT;

                    HUF_CaractereAssociesAuCodeBinaire[index] = index;
                    HUF_LongueurDuCodeBinaire[index] = CODE_DE_HUFFMAN_INUTILISE;
                    HUF_CodeBinaire[index] = CODE_DE_HUFFMAN_INUTILISE;
                    }
          }

/*************************************************************************************************************************************/
/*                                                                                                                                   */
/*        E D I T I O N   D E S   C O D E S   D E   H U F F M A N  :                                                                 */
/*                                                                                                                                   */
/*************************************************************************************************************************************/
void      F_HUF_EditionDesCodesDeHuffman()
          {
          if        (HUF_EditerCodesDeHuffman == VRAI)
                    {
                    Entier    index_1;

                    printf("HUF/EditionDesCodesDeHuffman :\n");

                    for       (index_1=PREMIER_CARACTERE ; index_1<=DERNIER_CARACTERE ; index_1++)
                              {
                              Entier    LongueurCodeBinaire=HUF_LongueurDuCodeBinaire[index_1];

                              if        (LongueurCodeBinaire != CODE_DE_HUFFMAN_INUTILISE)
                                        {
                                        CHAR      caractere=HUF_CaractereAssociesAuCodeBinaire[index_1];
                                        Entier    reste=HUF_CodeBinaire[index_1];
                                        Entier    PuissanceDe2=1;

                                        Entier    index_2;

                                        if        (         (caractere >= PREMIER_CARACTERE_EDITABLE)
                                                  &&        (caractere <= DERNIER_CARACTERE_EDITABLE)
                                                   )
                                                  {
                                                  printf("'%c' (0x%02x) --> "
                                                        ,caractere
                                                        ,caractere
                                                         );
                                                  }
                                        else
                                                  {
                                                  printf("    (0x%02x) --> "
                                                        ,caractere
                                                         );
                                                  }

                                        for       (index_2=1 ; index_2<=LongueurCodeBinaire ; index_2++)
                                                  {
                                                  PuissanceDe2 = BASE2*PuissanceDe2;
                                                  }

                                        for       (index_2=1 ; index_2<=LongueurCodeBinaire ; index_2++)
                                                  {
                                                  PuissanceDe2 = PuissanceDe2/BASE2;
                                                  printf("%1"For10,reste/PuissanceDe2);
                                                  reste = reste%PuissanceDe2;
                                                  }

                                        printf("\n");
                                        }
                              else
                                        {
                                        }
                              }
                    }
          else
                    {
                    }
          }

/*************************************************************************************************************************************/
/*                                                                                                                                   */
/*        C O M P A C T A G E   D ' U N E   C H A I N E   D E   C A R A C T E R E S  :                                               */
/*                                                                                                                                   */
/*************************************************************************************************************************************/
#define   D_HUF_StoreBit(Bit,IndexBit,Chaine)                                                                                           \
                    {                                                                                                                   \
                    Entier    IndexBitDansChaine;                                                                                       \
                    CHAR      Octet;                                                                                                    \
                    CHAR      MasqueRangementBit;                                                                                       \
                    Entier    IndexBitDansOctet;                                                                                        \
                                                                                                                                        \
                    IndexBitDansChaine = IndexBit/NBITOC;                                                                               \
                    IndexBitDansOctet = IndexBit%NBITOC;                                                                                \
                                                                                                                                        \
                    Octet = Chaine[IndexBitDansChaine];                                                                                 \
                    MasqueRangementBit = Bit << ((NBITOC-IndexBitDansOctet)-1);                                                         \
                    Chaine[IndexBitDansChaine] = Octet | MasqueRangementBit;                                                            \
                    }

void      F_HUF_Directe(CHAR ChaineB[],CHAR ChaineA[],Entier longueurA)
          {
          Entier    NombreDeBitsDansChaineB=0;
          Entier    IndexBitCourant=0;
          Entier    IndexDeChaineA;

          for       (IndexDeChaineA=INDEX0 ; IndexDeChaineA<=NombreVersIndex(longueurA) ; IndexDeChaineA++)
                    {
                    CHAR      CaractereCourant=ChaineA[IndexDeChaineA];
                    Entier    IndexHUF=PREMIER_CARACTERE;
                    Logical   iterer=VRAI;

                    while     (iterer == VRAI)
                              {
                              if        (IndexHUF <= DERNIER_CARACTERE)
                                        {
                                        if        (CaractereCourant == HUF_CaractereAssociesAuCodeBinaire[IndexHUF])
                                                  {
                                        /* Le caractere courant a ete retrouve dans les tables de codage entropique de Huffman :     */
                                                  Entier    LongueurCodeBinaire=HUF_LongueurDuCodeBinaire[IndexHUF];
                                                  Entier    reste=HUF_CodeBinaire[IndexHUF];
                                                  Entier    IndexCodeBinaire;
                                                  Entier    PuissanceDe2=1;

                                                  for       (IndexCodeBinaire=1
                                                            ; IndexCodeBinaire<=LongueurCodeBinaire
                                                            ; IndexCodeBinaire++
                                                             )
                                                            {
                                                            PuissanceDe2 = BASE2*PuissanceDe2;
                                                            }

                                                  for       (IndexCodeBinaire=1
                                                            ; IndexCodeBinaire<=LongueurCodeBinaire
                                                            ; IndexCodeBinaire++
                                                             )
                                                            {
                                                            Entier    BitCourant;

                                                            PuissanceDe2 = PuissanceDe2/BASE2;
                                                            BitCourant = reste/PuissanceDe2;
                                                            reste = reste%PuissanceDe2;

                                                            D_HUF_StoreBit(BitCourant,IndexBitCourant,ChaineB);
                                        /* Mise en place des bits codant le caractere courant 'CaractereCourant'...                  */

                                                            IndexBitCourant++;
                                                            NombreDeBitsDansChaineB++;
                                                            }

                                                  iterer=FAUX;
                                                  }
                                        else
                                                  {
                                                  IndexHUF++;
                                        /* Il faut poursuivre la recherche du caractere courant dans le code de Huffman...           */
                                                  }
                                        }
                              else
                                        {
                                        fprintf(stderr,"ERREUR(HUF) : Le caractere '0x02x' n'est pas dans l'arbre.\n");
                                        iterer=FAUX;
                                        }
                              }
                    }

          HUF_NombreDeBitsApresCodage = NombreDeBitsDansChaineB;

          HUF_Codage_LongueurApres = DIVISION_PAR_EXCES(HUF_NombreDeBitsApresCodage,NBITOC);
          }

/*************************************************************************************************************************************/
/*                                                                                                                                   */
/*        D E C O M P A C T A G E   D ' U N E   C H A I N E   D E   C A R A C T E R E S  :                                           */
/*                                                                                                                                   */
/*************************************************************************************************************************************/
#define   D_HUF_LoadBit(Bit,IndexBit,Chaine)                                                                                            \
                    {                                                                                                                   \
                    Entier    IndexBitDansChaine;                                                                                       \
                    Entier    IndexBitDansOctet;                                                                                        \
                    Entier    decalage;                                                                                                 \
                    CHAR      Octet;                                                                                                    \
                    Entier    MasqueExtractionBit;                                                                                      \
                                                                                                                                        \
                    mEGAL(IndexBitDansChaine,mDIVI(IndexBit,NBITOC));                                                                   \
                    mEGAL(IndexBitDansOctet,mREST(IndexBit,NBITOC));                                                                    \
                                                                                                                                        \
                    mEGAL(decalage,mSOUS(mSOUS(NBITOC,IndexBitDansOctet),1));                                                           \
                                                                                                                                        \
                    mEGAL(Octet,ACCES_CHAINE(Chaine,IndexBitDansChaine));                                                               \
                    mEGAL(MasqueExtractionBit,mDECG(BIT,decalage));                                                                     \
                    mEGAL(Bit,(Entier)mDECD(mETLO(Octet,MasqueExtractionBit),decalage));                                                \
                    }

void      F_HUF_Inverse(CHAR ChaineR[],CHAR ChaineB[],Entier NombreDeBitsDansChaineB)
          {
          Entier    NombreDOctetssDansChaineR;
          Entier    IndexBitCourant;
          Entier    IndexChaineR;
          Entier    NoeudCourantDeLArbre;

          HUF_Decodage_LongueurAvant = DIVISION_PAR_EXCES(NombreDeBitsDansChaineB,NBITOC);

          mEGAL(NombreDOctetssDansChaineR,0);
          mEGAL(IndexChaineR,INDEX0);
          mEGAL(NoeudCourantDeLArbre,HUF_RacineDeLArbre);

          DoIn(IndexBitCourant,INDEX0,NombreVersIndex(NombreDeBitsDansChaineB))
                    {
                    Entier    BitCourant;

                    D_HUF_LoadBit(BitCourant,IndexBitCourant,ChaineB);

                    Test      (         mIFEQ(HUF_ArbreChainageAGauche[NoeudCourantDeLArbre],NOEUD_INEXISTANT)
                              &&        mIFEQ(HUF_ArbreChainageADroite[NoeudCourantDeLArbre],NOEUD_INEXISTANT)
                               )
                              {
                                        /* Cas ou l'arbre n'a qu'un noeud (sa racine est une feuille), ce qui se rencontre dans      */
                                        /* le cas ou la chaine 'A' contient des caracteres tous identiques...                        */
                              }
                    ATes
                              {
                              Choi(BitCourant)
                                        /* La valeur du bit courant indique si l'on doit tourner a GAUCHE ou bien a DROITE...        */
                                        {
                                        Case(GAUCHE)
                                                  {
                                                  mEGAL(NoeudCourantDeLArbre,HUF_ArbreChainageAGauche[NoeudCourantDeLArbre]);
                                                  break;
                                                  }
                                        ECas

                                        Case(DROITE)
                                                  {
                                                  mEGAL(NoeudCourantDeLArbre,HUF_ArbreChainageADroite[NoeudCourantDeLArbre]);
                                                  break;
                                                  }
                                        ECas

                                        Defo
                                                  {
                                                  fprintf(stderr,"ERREUR(HUF) : un bit vaut %"For10".\n",BitCourant);
                                                  }
                                        EDef
                                        }
                              ECho
                              }
                    ETes

                    Test      (         mIFEQ(HUF_ArbreChainageAGauche[NoeudCourantDeLArbre],NOEUD_INEXISTANT)
                              &&        mIFEQ(HUF_ArbreChainageADroite[NoeudCourantDeLArbre],NOEUD_INEXISTANT)
                               )
                              {
                              mEGAL(ACCES_CHAINE(ChaineR,IndexChaineR),HUF_ArbreCaracteresEnChaqueNoeud[NoeudCourantDeLArbre]);
                                        /* Cas ou l'on est tombe sur une feuille de l'arbre : elle donne le caractere qui etait      */
                                        /* code par la suite courante de bits...                                                     */
                              mINCR(IndexChaineR);
                              mINCR(NombreDOctetssDansChaineR);

                              mEGAL(NoeudCourantDeLArbre,HUF_RacineDeLArbre);
                                        /* Et on repart de la racine de l'arbre...                                                   */
                              }
                    ATes
                              {
                              }
                    ETes
                    }
          EDoI

          mEGAL(HUF_NombreDOctetsApresDecodage,NombreDOctetssDansChaineR);

          HUF_Decodage_LongueurApres = HUF_NombreDOctetsApresDecodage;
          }

/*************************************************************************************************************************************/
/*                                                                                                                                   */
/*        V A L I D A T I O N   D U   C O M P A C T A G E / D E C O M P A C T A G E                                                  */
/*        D ' U N E   C H A I N E   D E   C A R A C T E R E S  :                                                                     */
/*                                                                                                                                   */
/*************************************************************************************************************************************/
void      F_HUF_Verifications(CHAR Chaine1[],Entier LongueurChaine1,CHAR Chaine2[],Entier LongueurChaine2)
          {
          Entier    index;

          if        (LongueurChaine1 == LongueurChaine2)
                    {
                    for       (index=INDEX0 ; index<=NombreVersIndex(MIN2(LongueurChaine1,LongueurChaine2)) ; index++)
                              {
                              if        (Chaine1[index] != Chaine2[index])
                                        {
                                        fprintf(stderr,"ERREUR(HUF) : '0x%02x' et '0x%02x' de rang %"For10"  different.\n"
                                               ,Chaine1[index]
                                               ,Chaine2[index]
                                               ,index
                                                );
                                        }
                              else
                                        {
                                        }
                              }
                    }
          else
                    {
                    fprintf(stderr
                           ,"ERREUR(HUF) : Les deux chaines n'ont pas la meme longueur (%"For10"#%"For10").\n"
                           ,LongueurChaine1
                           ,LongueurChaine2
                            );
                    }
          }

/*************************************************************************************************************************************/
/*                                                                                                                                   */
/*        I N I T I A L I S A T I O N S   A S S O C I E E S   A   C H A Q U E   C H A I N E   D E   T E S T  :                       */
/*                                                                                                                                   */
/*************************************************************************************************************************************/
#ifndef   HUF_FIN_DE_CHAINE
#         define    HUF_FIN_DE_CHAINE                                                                                                   \
                              1                                                                                                         \
                                        /* Le '+1' est destine a pouvoir introduire, si besoin est, une "fin de chaine"...           */
#else
#endif

#define   D_HUF________Debut(ChaineB,ChaineR,ChaineA,LongueurChaineA)                                                                   \
                    {                                                                                                                   \
                    Entier    index_1;                                                                                                  \
                    Entier    longueur=LongueurChaineA+HUF_FIN_DE_CHAINE;                                                               \
                                        /* Le '+1' est destine a pouvoir introduire, si besoin est, une "fin de chaine"...           */ \
                                                                                                                                        \
                    ChaineB = MALLOC(longueur*sizeof(CHAR));                                                                            \
                    ChaineR = MALLOC(longueur*sizeof(CHAR));                                                                            \
                                                                                                                                        \
                    for       (index_1=1 ; index_1<=longueur ; index_1++)                                                               \
                              {                                                                                                         \
                              Entier    index_2=NombreVersIndex(index_1);                                                               \
                                                                                                                                        \
                              ChaineB[index_2] = 0;                                                                                     \
                              ChaineR[index_2] = 0;                                                                                     \
                                        /* On notera que cela met donc implicitement une "fin de chaine" (0)...                      */ \
                              }                                                                                                         \
                    }

#define   D_HUF________Fin__(ChaineA1,ChaineA2)                                                                                         \
                    {                                                                                                                   \
                    CALLs(free(ChaineA1));                                                                                              \
                    CALLs(free(ChaineA2));                                                                                              \
                    }



Copyright © Jean-François Colonna, 2016-2021.
Copyright © CMAP (Centre de Mathématiques APpliquées) UMR CNRS 7641 / Ecole Polytechnique, 2016-2021.