/*************************************************************************************************************************************/
/* */
/* C O M P R E S S I O N " R U N - L E N G T H E N C O D I N G " ' RLE ' E T I N V E R S E : */
/* */
/* */
/* Nota : */
/* */
/* Ce module est inspire de 'v $xtc/RunLengthEncoding.11$I' */
/* qui a servi a sa mise au point... */
/* */
/* */
/* Principes : */
/* */
/* Kc --> K */
/* - */
/* */
/* KKc --> KK */
/* -- */
/* */
/* KKKc --> KKK */
/* --- */
/* */
/* KKKKc --> KKKK[0] */
/* ---- */
/* */
/* KKKKKc --> KKKK[1] */
/* ---- */
/* */
/* KKKKKKc --> KKKK[2] */
/* */
/* (...) */
/* */
/* KKKKK(...)K --> KKKK[255] */
/* ---- */
/* ----------- */
/* /|\ */
/* | */
/* | */
/* ------------- il y a au total 4+255=259 caracteres 'K'. */
/* */
/* */
/* (ou [n] represente un octet contenant en binaire */
/* la valeur n comprise entre 0 et 255) ce qui est donc */
/* plus optimise. Enfin, 'c' represente un caractere */
/* different de 'K' (on notera au passage que ce caractere */
/* 'c' n'apparait pas apres une chaine de 'K's de longueur */
/* maximale car, en effet, le caractere suivant le dernier */
/* 'K' peut etre un autre caractere 'K'...). */
/* */
/* */
/* Author of '$xrC/CompressionDeCompression_RunLengthEncoding.01$vv$I' : */
/* */
/* Jean-Francois Colonna (LACTAMME, 20151227143859). */
/* */
/*************************************************************************************************************************************/
/*************************************************************************************************************************************/
/* */
/* D E F I N I T I O N G E N E R A L E S : */
/* */
/*************************************************************************************************************************************/
Logical RLE_EditerLesChaines=FAUX;
/* Indicateurs de controle des editions... */
#define INFINI \
32000 \
/* A cause de 'v $xrC/CompressionDeCompression_Compression.01$vv$I EntierCourt', la */ \
/* valeur 2000000000 a du etre reduite considerablement, tout en etant positive dans */ \
/* tous les cas... */
#define NOMBRE_D_OCTETS_POUR_LES_NOMBRES_DE_REPETITIONS \
(1)
#define BASE_DE_NUMERATION_DES_NOMBRES_DE_REPETITIONS \
(256)
#define BORNE_INFERIEURE_DE_REPETITIONS \
(4)
#define BORNE_SUPERIEURE_DE_REPETITIONS \
(BASE_DE_NUMERATION_DES_NOMBRES_DE_REPETITIONS-1)
/* Definitions des bornes : */
/* */
/* INFERIEUR a partir de laquelle on compacte, */
/* SUPERIEUR limite superieure du compactage a cause de la capacite d'un octet. */
/* */
/* On notera que si l'on utilise plus d'un octet pour stocker les nombres de repetitions, */
/* la borne inferieure doit etre augmentee, mais comment et de combien ? */
#define RLE_INDEXN \
NombreVersIndex(RLE_LongueurChainesNonCompressees)
Entier RLE_LongueurChainesNonCompressees;
Entier RLE_1_LongueurChainesNonCompressees;
Entier RLE_2_LongueurChainesNonCompressees;
/* On notera qu'a priori, aucune des chaines utilisees n'a de caractere de fin. Cela */
/* vient du fait que ces chaines peuvent contenir 256 codes differents et qu'alors le */
/* code '0x00' habituel ne peut etre utilise. La fin d'une chaine est donc reperee via */
/* son dernier caractere d'index 'INDEXN'... */
Entier RLE_Directe_LongueurAvant;
Entier RLE_Directe_1_LongueurAvant;
Entier RLE_Directe_2_LongueurAvant;
Entier RLE_Directe_LongueurApres;
Entier RLE_Directe_1_LongueurApres;
Entier RLE_Directe_2_LongueurApres;
Entier RLE_Inverse_LongueurAvant;
Entier RLE_Inverse_1_LongueurAvant;
Entier RLE_Inverse_2_LongueurAvant;
Entier RLE_Inverse_LongueurApres;
Entier RLE_Inverse_1_LongueurApres;
Entier RLE_Inverse_2_LongueurApres;
/* Afin de faciliter des verifications de coherence... */
CHAR *RLE_1_ChaineA;
CHAR *RLE_2_ChaineA;
/* Definition de la chaine Argument a permuter... */
CHAR *RLE_1_ChaineC;
CHAR *RLE_2_ChaineC;
Entier RLE_1_LongueurChaineC;
Entier RLE_2_LongueurChaineC;
/* Definition de la version permutee de 'ChaineACompresser'... */
CHAR *RLE_1_ChaineR;
CHAR *RLE_2_ChaineR;
/* Definition de la chaine "depermutee" qui doit donc etre identique a 'ChaineACompresser'. */
/*************************************************************************************************************************************/
/* */
/* E D I T I O N S D I V E R S E S : */
/* */
/*************************************************************************************************************************************/
#define D_RLE_EDITION_D_UNE_CHAINE(Message,ChaineA,IndexDernierCaractereChaineA) \
{ \
if (RLE_EditerLesChaines == VRAI) \
{ \
Entier IndexCaractere; \
\
printf("RLE/%s : ",Message); \
\
for (IndexCaractere=INDEX0 ; IndexCaractere <= IndexDernierCaractereChaineA ; IndexCaractere++) \
{ \
printf(FORMAT_CARACTERE,ACCES_CHAINE(ChaineA,IndexCaractere)); \
} \
\
printf("\n"); \
} \
else \
{ \
} \
}
/*************************************************************************************************************************************/
/* */
/* I N I T I A L I S A T I O N D E L A C H A I N E A T R A I T E R : */
/* */
/*************************************************************************************************************************************/
#define D_RLE________Debut(ChaineR,ChaineA,LongueurChaineA) \
{ \
Entier IndexCaractere; \
\
RLE_LongueurChainesNonCompressees = LongueurChaineA; \
/* ATTENTION : en toute generalite dans 'ChaineA' les 256 codes possibles peuvent */ \
/* etre presents et donc 'strlen(...)' ne peut pas fonctionner systematiquement. C'est */ \
/* pourquoi un parametre de longueur 'LongueurChaineA' doit apparaitre explicitement... */ \
\
ChaineR = MALLOC(RLE_LongueurChainesNonCompressees*sizeof(CHAR)); \
\
for (IndexCaractere=INDEX0 ; IndexCaractere <= RLE_INDEXN ; IndexCaractere++) \
{ \
ACCES_CHAINE(ChaineR,IndexCaractere) = ACCES_CHAINE(ChaineA,IndexCaractere); \
} \
}
#define D_RLE________Fin__(ChaineA) \
{ \
CALLs(free(ChaineA)); \
}
/*************************************************************************************************************************************/
/* */
/* C O M P R E S S I O N D ' U N E C H A I N E : */
/* */
/*************************************************************************************************************************************/
#define LONGUEUR_MAXIMALE_DES_BUFFERS(longueur) \
DIVISION_PAR_EXCES((BORNE_INFERIEURE_DE_REPETITIONS+1)*longueur,BORNE_INFERIEURE_DE_REPETITIONS) \
/* En effet, le pire cas est celui ou le fichier contient des suites de quatre caracteres */ \
/* identiques et par exemple : */ \
/* */ \
/* AAAABBBB... --> AAAA[0]BBBB[0]... */ \
/* */ \
/* et ainsi, 4 caracteres en donne 5... */
#define D_RLE_StoreCompression(ChaineR,IndexChaineR,valeur,LongueurChaineR,LongueurChaineA) \
{ \
if (IndexChaineR <= NombreVersIndex(LONGUEUR_MAXIMALE_DES_BUFFERS(LongueurChaineA))) \
{ \
ACCES_CHAINE(ChaineR,IndexChaineR) = (valeur); \
\
IndexChaineR++; \
} \
else \
{ \
fprintf(stderr,"Erreur de compression/decompression (debordement de capacite) -1-\n"); \
} \
\
LongueurChaineR++; \
}
#define D_RLE_StoreRepetition(Chaine,IndexChaine,nombre,LongueurChaineR,LongueurChaineA) \
{ \
Entier compteur; \
Entier quotient=(nombre); \
Entier reste; \
\
for (compteur=1 ; compteur<=NOMBRE_D_OCTETS_POUR_LES_NOMBRES_DE_REPETITIONS ; compteur++) \
{ \
reste = quotient % BASE_DE_NUMERATION_DES_NOMBRES_DE_REPETITIONS; \
quotient = quotient / BASE_DE_NUMERATION_DES_NOMBRES_DE_REPETITIONS; \
\
D_RLE_StoreCompression(Chaine,IndexChaine,(CHAR)reste,LongueurChaineR,LongueurChaineA); \
} \
\
if (quotient != 0) \
{ \
fprintf(stderr,"Erreur de compression (debordement de capacite de repetition) -1-\n"); \
} \
else \
{ \
} \
}
#define D_RLE_DirecteDebut(ChaineR) \
{ \
RLE_Directe_LongueurAvant = RLE_LongueurChainesNonCompressees; \
\
ChaineR = MALLOC(LONGUEUR_MAXIMALE_DES_BUFFERS(RLE_LongueurChainesNonCompressees)*sizeof(CHAR)); \
}
#define D_RLE_Directe(ChaineR,LongueurChaineR,ChaineA) \
{ \
CHAR CaracterePrecedent=0; \
Logical CaracterePrecedentExiste=FAUX; \
Entier CompteurDeRepetitions=1; \
Entier IndexChaineA; \
Entier IndexChaineR=INDEX0; \
\
LongueurChaineR = 0; \
\
for (IndexChaineA=INDEX0 ; IndexChaineA<=NombreVersIndex(RLE_LongueurChainesNonCompressees) ; IndexChaineA++) \
{ \
CHAR CaractereCourant=ACCES_CHAINE(ChaineA,IndexChaineA); \
\
if (CaracterePrecedentExiste == FAUX) \
{ \
CaracterePrecedent = CaractereCourant; \
CaracterePrecedentExiste = VRAI; \
\
D_RLE_StoreCompression(ChaineR,IndexChaineR \
,CaractereCourant \
,LongueurChaineR \
,RLE_LongueurChainesNonCompressees \
); \
} \
else \
{ \
if ( (CaractereCourant == CaracterePrecedent) \
&& (CompteurDeRepetitions \
< (BORNE_SUPERIEURE_DE_REPETITIONS+BORNE_INFERIEURE_DE_REPETITIONS) \
) \
) \
{ \
CompteurDeRepetitions++; \
\
if ( (CompteurDeRepetitions > 1) \
&& (CompteurDeRepetitions <= BORNE_INFERIEURE_DE_REPETITIONS) \
) \
{ \
D_RLE_StoreCompression(ChaineR,IndexChaineR \
,CaractereCourant \
,LongueurChaineR \
,RLE_LongueurChainesNonCompressees \
); \
} \
else \
{ \
} \
\
if ( (CompteurDeRepetitions >= BORNE_INFERIEURE_DE_REPETITIONS) \
&& (IndexChaineA \
== NombreVersIndex(RLE_LongueurChainesNonCompressees)) \
) \
{ \
D_RLE_StoreRepetition(ChaineR,IndexChaineR \
,CompteurDeRepetitions-BORNE_INFERIEURE_DE_REPETITIONS \
,LongueurChaineR \
,RLE_LongueurChainesNonCompressees \
); \
} \
else \
{ \
} \
} \
else \
{ \
if (CompteurDeRepetitions >= BORNE_INFERIEURE_DE_REPETITIONS) \
{ \
D_RLE_StoreRepetition(ChaineR,IndexChaineR \
,CompteurDeRepetitions-BORNE_INFERIEURE_DE_REPETITIONS \
,LongueurChaineR \
,RLE_LongueurChainesNonCompressees \
); \
} \
else \
{ \
} \
\
D_RLE_StoreCompression(ChaineR,IndexChaineR \
,CaractereCourant \
,LongueurChaineR \
,RLE_LongueurChainesNonCompressees \
); \
\
CaracterePrecedent = CaractereCourant; \
CompteurDeRepetitions = 1; \
} \
} \
} \
\
D_RLE_EDITION_D_UNE_CHAINE("TransformationDirecte",ChaineR,NombreVersIndex(LongueurChaineR)); \
\
RLE_Directe_LongueurApres = LongueurChaineR; \
}
#define D_RLE_DirecteFin__() \
{ \
}
/*************************************************************************************************************************************/
/* */
/* D E C O M P R E S S I O N D ' U N E C H A I N E : */
/* */
/*************************************************************************************************************************************/
#define D_RLE_StoreDecompression(ChaineR,IndexChaineR,valeur) \
{ \
mEGAL(ACCES_CHAINE(ChaineR,IndexChaineR),valeur); \
\
mINCR(IndexChaineR); \
}
#define D_RLE_GetRepetition(ChaineA,IndexChaineA,NombreDeCaracteres) \
{ \
Entier compteur; \
Entier facteur; \
\
mEGAL(facteur,1); \
mEGAL(NombreDeCaracteres,0); \
\
DoIn(compteur,1,NOMBRE_D_OCTETS_POUR_LES_NOMBRES_DE_REPETITIONS) \
{ \
CHAR caractere; \
\
mEGAL(caractere,ACCES_CHAINE(ChaineA,IndexChaineA)); \
mEGAL(NombreDeCaracteres,mADD2(NombreDeCaracteres,mMUL2(caractere,facteur))); \
mEGAL(facteur,mMUL2(BASE_DE_NUMERATION_DES_NOMBRES_DE_REPETITIONS,facteur)); \
\
Test(mIFLT(compteur,NOMBRE_D_OCTETS_POUR_LES_NOMBRES_DE_REPETITIONS)) \
{ \
mINCR(IndexChaineA); \
} \
ATes \
{ \
} \
ETes \
} \
EDoI \
}
#define D_RLE_RepeatStoreDecompression(ChaineR,IndexChaineR,ChaineA,IndexChaineA,valeur) \
{ \
Entier nombre; \
Entier NombreDeCaracteres_ADupliquer; \
\
D_RLE_GetRepetition(ChaineA,IndexChaineA,NombreDeCaracteres_ADupliquer); \
\
DoIn(nombre,1,NombreDeCaracteres_ADupliquer) \
{ \
D_RLE_StoreDecompression(ChaineR,IndexChaineR,valeur); \
} \
EDoI \
}
#define CARACTERE_PRECEDENT_INDEFINI \
INFINI
\
#define D_RLE_InverseDebut(ChaineA) \
{ \
ChaineA = MALLOC(RLE_LongueurChainesNonCompressees*sizeof(CHAR)); \
}
#define D_RLE_Inverse(ChaineR,ChaineA,LongueurChaineA) \
{ \
Entier iterer; \
Entier CaracterePrecedent; \
/* ATTENTION : doit etre un 'int' et non pas un 'CHAR' a cause de la valeur 'INFINI'... */ \
Entier CompteurDeRepetitions; \
Entier DimensionImageEffective; \
Entier IndexChaineA; \
Entier IndexChaineR; \
\
RLE_Inverse_LongueurAvant = LongueurChaineA; \
\
mEGAL(iterer,VRAI); \
mEGAL(CaracterePrecedent,CARACTERE_PRECEDENT_INDEFINI); \
mEGAL(CompteurDeRepetitions,1); \
mEGAL(DimensionImageEffective,0); \
mEGAL(IndexChaineA,INDEX0); \
mEGAL(IndexChaineR,INDEX0); \
\
Tant(mIFEQ(iterer,VRAI)) \
{ \
CHAR CaractereCourant; \
\
mEGAL(CaractereCourant,ACCES_CHAINE(ChaineA,IndexChaineA)); \
\
Test(mIFLE(CompteurDeRepetitions,BORNE_INFERIEURE_DE_REPETITIONS)) \
{ \
Test(mIFEQ(CompteurDeRepetitions,BORNE_INFERIEURE_DE_REPETITIONS)) \
{ \
D_RLE_RepeatStoreDecompression(ChaineR,IndexChaineR \
,ChaineA,IndexChaineA \
,CaracterePrecedent \
); \
mEGAL(CaracterePrecedent,CARACTERE_PRECEDENT_INDEFINI); \
mEGAL(CompteurDeRepetitions,1); \
} \
ATes \
{ \
Test(mIFEQ(CaractereCourant,CaracterePrecedent)) \
{ \
mINCR(CompteurDeRepetitions); \
} \
ATes \
{ \
mEGAL(CaracterePrecedent,CaractereCourant); \
mEGAL(CompteurDeRepetitions,1); \
} \
ETes \
\
D_RLE_StoreDecompression(ChaineR,IndexChaineR,CaractereCourant); \
} \
ETes \
} \
ATes \
{ \
fprintf(stderr,"Erreur de decompression -1-\n"); \
} \
ETes \
\
mINCR(IndexChaineA); \
\
Test(mIFLE(IndexChaineA,NombreVersIndex(LongueurChaineA))) \
{ \
} \
ATes \
{ \
mEGAL(iterer,FAUX); \
} \
ETes \
} \
ETan \
\
RLE_Inverse_LongueurApres = IndexVersNombre(mSOUS(IndexChaineR,1)); \
}
#define D_RLE_InverseFin__(ChaineA1,ChaineA2) \
{ \
CALLs(free(ChaineA1)); \
CALLs(free(ChaineA2)); \
}
/*************************************************************************************************************************************/
/* */
/* V E R I F I C A T I O N D U P R O C E S S U S C O M P L E T : */
/* */
/*************************************************************************************************************************************/
void F_RLE_Verifications(CHAR *ChaineA1,CHAR *ChaineA2)
{
Entier IndexCaractere;
for (IndexCaractere=INDEX0 ; IndexCaractere <= RLE_INDEXN ; IndexCaractere++)
{
if (ACCES_CHAINE(ChaineA1,IndexCaractere) != ACCES_CHAINE(ChaineA2,IndexCaractere))
{
fprintf(stderr
,"ERREUR(RLE) : chaine retablie ('0x%02x') # chaine a traiter ('0x%02x').\n"
,ACCES_CHAINE(ChaineA1,IndexCaractere)
,ACCES_CHAINE(ChaineA2,IndexCaractere)
);
}
else
{
}
}
D_RLE_EDITION_D_UNE_CHAINE("Verification 1",ChaineA1,RLE_INDEXN);
D_RLE_EDITION_D_UNE_CHAINE("Verification 2",ChaineA2,RLE_INDEXN);
}