/*************************************************************************************************************************************/ /* */ /* 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 " E T I N V E R S E : */ /* */ /* */ /* Nota : */ /* */ /* Ce programme est inspire de 'v $xtc/CompressionDecompression_RLE_1D.01$c'. */ /* Il y a une petite difference au sujet du compte des repetitions : */ /* */ /* */ /* $xtc/CompressionDecompression_RLE_1D.01$c */ /* */ /* Kc --> K */ /* - */ /* */ /* KKc --> KK */ /* -- */ /* */ /* KKKc --> KKK */ /* --- */ /* */ /* KKKKc --> KKKK[4] */ /* ---- */ /* */ /* KKKKKc --> KKKK[5] */ /* ---- */ /* */ /* KKKKKKc --> KKKK[6] */ /* ---- */ /* */ /* (...) */ /* */ /* KKKKK(...)K --> KKKK[255] */ /* ---- */ /* ----------- */ /* /|\ */ /* | */ /* | */ /* ------------- il n'y a que 255 caracteres 'K'. */ /* */ /* */ /* alors que : */ /* */ /* $KrC/CompressionDeCompressionRunLengthEncoding.11$vv$I */ /* */ /* 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 '$xtc/RunLengthEncoding.11$vv$I' : */ /* */ /* Jean-Francois COLONNA (LACTAMME, 20151223082146). */ /* */ /*************************************************************************************************************************************/ /*************************************************************************************************************************************/ /* */ /* D E F I N I T I O N G E N E R A L E S : */ /* */ /*************************************************************************************************************************************/ int RunLengthEncoding_EditerLesChaines=VRAI; int RunLengthEncoding_EditionsHexaDecimalesDesChaines=VRAI; /* Indicateurs de controle des editions... */ #define INFINI \ 2000000000 #define QUE_FAIRE(x) \ (0) #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)+QUE_FAIRE(NOMBRE_D_OCTETS_POUR_LES_NOMBRES_DE_REPETITIONS)) #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 ? */ #ifndef CHAR # define CHAR \ unsigned char \ /* Afin que tous les tests effectues fonctionnent correctement et que les relations */ \ /* d'odre soient bien celles que l'on attend, il est a priori necessaire que les */ \ /* caracteres soient non signes... */ #else #endif #ifndef FORMAT_CARACTERE # define FORMAT_CARACTERE \ COND((RunLengthEncoding_EditionsHexaDecimalesDesChaines == VRAI),"%02x ","%c") \ /* Format d'edition des caracteres des chaines... */ #else #endif #define RunLengthEncoding_INDEXN \ NombreVersIndex(RunLengthEncoding_LongueurChainesNonCompressees) int RunLengthEncoding_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'... */ #ifndef ACCES_CHAINE # define ACCES_CHAINE(Chaine,IndexCaractere) \ *(Chaine+IndexCaractere) \ /* Acces a une chaine quelconque... */ #else #endif CHAR *RunLengthEncoding_ChaineACompresser; /* Definition de la chaine Argument a permuter... */ CHAR *RunLengthEncoding_ChaineCompressee; int RunLengthEncoding_LongueurDeChaineCompressee; /* Definition de la version permutee de 'ChaineACompresser'... */ CHAR *RunLengthEncoding_ChaineDecompressee; /* 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 RunLengthEncoding_EDITION_D_UNE_CHAINE(ChaineA,IndexDernierCaractereChaineA) \ { \ if (RunLengthEncoding_EditerLesChaines == VRAI) \ { \ int IndexCaractere; \ \ 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 RunLengthEncoding_InitialisationChaineATraiter(ChaineR,ChaineA,LongueurChaineA) \ { \ int IndexCaractere; \ \ RunLengthEncoding_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 pramatre de longueur 'LongueurChaineA' doit apparaitre explicitement... */ \ \ ChaineR = malloc(RunLengthEncoding_LongueurChainesNonCompressees); \ \ for (IndexCaractere=INDEX0 ; IndexCaractere <= RunLengthEncoding_INDEXN ; IndexCaractere++) \ { \ ACCES_CHAINE(ChaineR,IndexCaractere) = ChaineA[IndexCaractere]; \ } \ } #define RunLengthEncoding_DesinitialisationChaineATraiter(ChaineA) \ { \ 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) \ (2*longueur) #define STORE_COMPRESSION_11(ChaineR,IndexChaineR,valeur,LongueurChaineR,LongueurChaineA) \ { \ ACCES_CHAINE(ChaineR,IndexChaineR) = (valeur); \ \ if (IndexChaineR < NombreVersIndex(LONGUEUR_MAXIMALE_DES_BUFFERS(LongueurChaineA))) \ { \ IndexChaineR++; \ } \ else \ { \ fprintf(stderr,"Erreur de compression/decompression (debordement de capacite) -1-\n"); \ } \ \ LongueurChaineR++; \ } #define STORE_REPETITION_11(Chaine,IndexChaine,nombre,LongueurChaineR,LongueurChaineA) \ { \ int compteur; \ int quotient=(nombre); \ int 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; \ \ STORE_COMPRESSION_11(Chaine,IndexChaine,(CHAR)reste,LongueurChaineR,LongueurChaineA); \ } \ \ if (quotient != 0) \ { \ fprintf(stderr,"Erreur de compression (debordement de capacite de repetition) -1-\n"); \ } \ else \ { \ } \ } #define RunLengthEncoding_InitialisationTransformationDirecte(ChaineR) \ { \ ChaineR=malloc(LONGUEUR_MAXIMALE_DES_BUFFERS(RunLengthEncoding_LongueurChainesNonCompressees)); \ } #define RunLengthEncoding_TransformationDirecte(ChaineR,ChaineA) \ { \ CHAR CaracterePrecedent=0; \ int CaracterePrecedentExiste=FAUX; \ int CompteurDeRepetitions=1; \ int IndexChaineA; \ int IndexChaineR=INDEX0; \ int LongueurChaineR = 0; \ \ for (IndexChaineA=INDEX0 \ ; IndexChaineA<=NombreVersIndex(RunLengthEncoding_LongueurChainesNonCompressees) \ ; IndexChaineA++ \ ) \ { \ CHAR CaractereCourant=ACCES_CHAINE(ChaineA,IndexChaineA); \ \ if (CaracterePrecedentExiste == FAUX) \ { \ CaracterePrecedent = CaractereCourant; \ CaracterePrecedentExiste = VRAI; \ \ STORE_COMPRESSION_11(ChaineR,IndexChaineR \ ,CaractereCourant \ ,LongueurChaineR \ ,RunLengthEncoding_LongueurChainesNonCompressees \ ); \ } \ else \ { \ if ( (CaractereCourant == CaracterePrecedent) \ && (CompteurDeRepetitions \ < (BORNE_SUPERIEURE_DE_REPETITIONS+BORNE_INFERIEURE_DE_REPETITIONS) \ ) \ ) \ { \ CompteurDeRepetitions++; \ \ if ( (CompteurDeRepetitions > 1) \ && (CompteurDeRepetitions <= BORNE_INFERIEURE_DE_REPETITIONS) \ ) \ { \ STORE_COMPRESSION_11(ChaineR,IndexChaineR \ ,CaractereCourant \ ,LongueurChaineR \ ,RunLengthEncoding_LongueurChainesNonCompressees \ ); \ } \ else \ { \ } \ \ if ( (CompteurDeRepetitions >= BORNE_INFERIEURE_DE_REPETITIONS) \ && (IndexChaineA \ == NombreVersIndex(RunLengthEncoding_LongueurChainesNonCompressees)) \ ) \ { \ STORE_REPETITION_11(ChaineR,IndexChaineR \ ,CompteurDeRepetitions-BORNE_INFERIEURE_DE_REPETITIONS \ ,LongueurChaineR \ ,RunLengthEncoding_LongueurChainesNonCompressees \ ); \ } \ else \ { \ } \ } \ else \ { \ if (CompteurDeRepetitions >= BORNE_INFERIEURE_DE_REPETITIONS) \ { \ STORE_REPETITION_11(ChaineR,IndexChaineR \ ,CompteurDeRepetitions-BORNE_INFERIEURE_DE_REPETITIONS \ ,LongueurChaineR \ ,RunLengthEncoding_LongueurChainesNonCompressees \ ); \ } \ else \ { \ } \ \ STORE_COMPRESSION_11(ChaineR,IndexChaineR \ ,CaractereCourant \ ,LongueurChaineR \ ,RunLengthEncoding_LongueurChainesNonCompressees \ ); \ \ CaracterePrecedent = CaractereCourant; \ CompteurDeRepetitions = 1; \ } \ } \ } \ \ RunLengthEncoding_LongueurDeChaineCompressee = LongueurChaineR; \ \ RunLengthEncoding_EDITION_D_UNE_CHAINE(ChaineR,NombreVersIndex(LongueurChaineR)); \ } #define RunLengthEncoding_DesinitialisationsTransformationDirecte() \ { \ } /*************************************************************************************************************************************/ /* */ /* D E C O M P R E S S I O N D ' U N E C H A I N E : */ /* */ /*************************************************************************************************************************************/ #define STORE_DECOMPRESSION_11(ChaineR,IndexChaineR,valeur) \ { \ ACCES_CHAINE(ChaineR,IndexChaineR)=valeur; \ \ IndexChaineR++; \ } #define GET_REPETITION_11(ChaineA,IndexChaineA,NombreDeCaracteres) \ { \ int compteur; \ int facteur=1; \ \ NombreDeCaracteres=0; \ \ for (compteur=1 ; compteur<=NOMBRE_D_OCTETS_POUR_LES_NOMBRES_DE_REPETITIONS ; compteur++) \ { \ CHAR caractere=ACCES_CHAINE(ChaineA,IndexChaineA); \ NombreDeCaracteres = NombreDeCaracteres+(caractere*facteur); \ facteur = BASE_DE_NUMERATION_DES_NOMBRES_DE_REPETITIONS*facteur; \ \ if (compteur < NOMBRE_D_OCTETS_POUR_LES_NOMBRES_DE_REPETITIONS) \ { \ IndexChaineA++; \ } \ else \ { \ } \ } \ } #define REPEAT_STORE_DECOMPRESSION_11(ChaineR,IndexChaineR,ChaineA,IndexChaineA,valeur) \ { \ int nombre; \ int NombreDeCaracteres_ADupliquer; \ \ GET_REPETITION_11(ChaineA,IndexChaineA,NombreDeCaracteres_ADupliquer); \ \ for (nombre=1 ; nombre <= NombreDeCaracteres_ADupliquer ; nombre++) \ { \ STORE_DECOMPRESSION_11(ChaineR,IndexChaineR,valeur); \ } \ } #define CARACTERE_PRECEDENT_INDEFINI \ INFINI \ #define RunLengthEncoding_InitialisationTransformationInverse(ChaineA) \ { \ ChaineA=malloc(RunLengthEncoding_LongueurChainesNonCompressees); \ } #define RunLengthEncoding_TransformationInverse(ChaineR,ChaineA) \ { \ int iterer=VRAI; \ int CaracterePrecedent=CARACTERE_PRECEDENT_INDEFINI; \ /* ATTENTION : doit etre un 'int' et non pas un 'CHAR' a cause de la valeur 'INFINI'... */ \ int CompteurDeRepetitions=1; \ int DimensionImageEffective=0; \ int IndexChaineA=INDEX0; \ int IndexChaineR=INDEX0; \ \ while (iterer == VRAI) \ { \ CHAR CaractereCourant=ACCES_CHAINE(ChaineA,IndexChaineA); \ \ if (CompteurDeRepetitions <= BORNE_INFERIEURE_DE_REPETITIONS) \ { \ if (CompteurDeRepetitions == BORNE_INFERIEURE_DE_REPETITIONS) \ { \ REPEAT_STORE_DECOMPRESSION_11(ChaineR,IndexChaineR \ ,ChaineA,IndexChaineA \ ,CaracterePrecedent \ ); \ CaracterePrecedent = CARACTERE_PRECEDENT_INDEFINI; \ CompteurDeRepetitions = 1; \ } \ else \ { \ if (CaractereCourant == CaracterePrecedent) \ { \ CompteurDeRepetitions++; \ } \ else \ { \ CaracterePrecedent = CaractereCourant; \ CompteurDeRepetitions = 1; \ } \ \ STORE_DECOMPRESSION_11(ChaineR,IndexChaineR,CaractereCourant); \ } \ } \ else \ { \ fprintf(stderr,"Erreur de decompression -1-\n"); \ } \ \ IndexChaineA++; \ \ if (IndexChaineA<=NombreVersIndex(RunLengthEncoding_LongueurDeChaineCompressee)) \ { \ } \ else \ { \ iterer = FAUX; \ } \ } \ } #define RunLengthEncoding_DesinitialisationsTransformationInverse(ChaineA1,ChaineA2) \ { \ free(ChaineA1); \ 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 RunLengthEncoding_Verifications(CHAR *ChaineA1,CHAR *ChaineA2) { int IndexCaractere; for (IndexCaractere=INDEX0 ; IndexCaractere <= RunLengthEncoding_INDEXN ; IndexCaractere++) { if (ACCES_CHAINE(ChaineA1,IndexCaractere) != ACCES_CHAINE(ChaineA2,IndexCaractere)) { fprintf(stderr ,"ERREUR(RunLengthEncoding) : chaine retablie ('0x%02x') # chaine a traiter ('0x%02x').\n" ,ACCES_CHAINE(ChaineA1,IndexCaractere) ,ACCES_CHAINE(ChaineA2,IndexCaractere) ); } else { } } RunLengthEncoding_EDITION_D_UNE_CHAINE(ChaineA1,RunLengthEncoding_INDEXN); RunLengthEncoding_EDITION_D_UNE_CHAINE(ChaineA2,RunLengthEncoding_INDEXN); }