/*************************************************************************************************************************************/ /* */ /* 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); }