//RLE (komprimerare dekomprimerare)
//Implementerat av Fredrik Angenete
#include
#include
#include
//Skapar pekarlista som hanterar bytes
class Element { //Pekarlista
public:
Element *next; //Nästa element
char data; //Lagrad byte
Element(Element *n, char d) : next(n), data(d) {}
};
//Lägger ny byte sist i listan
void PutLast(Element *& first, char d)
{
if (!first) //Om listan tom lägg först
first = new Element(NULL, d);
else{ //Annars lägg sist
Element *list;
for (list=first; list->next; list=list->next)
;
list->next=new Element(NULL, d);
}
}
//Sparar sekvens från lista till fil
void Save(Element *list, char *fileName)
{
ofstream file(fileName, ios::out|ios::binary);//Skrivbar fil, betraktas som binär
while (list!=NULL){ //Läser igenom hela listan
file.put(list->data); //Skriver till aktuell fil
list=list->next;
}
file.close();
}
//Laddar sekvens från fil och lagrar i listan
Element *Load(Element *list, char *fileName)
{
char ch; //Lagrar aktuell byte
ifstream file(fileName, ios::in|ios::binary);//Läsbar fil, betraktas som binär
while (file.get(ch)) //Hämtar byte från fil
PutLast(list,ch); //Lagrar sist i listan
return list; //Returnerar listan
}
//Packar sekvens
Element *Pack(Element *list)
{
Element *packed=NULL; //Lista för packad sekvens
Element *sweep=NULL; //Lista för svep av olika bytes
Element *temp; //Temporär variabel för kontroll av bytes. Ligger och släpar en byte efter
bool sweepstop; //Flagga om svepstopp detekterat
char controlByte,totalBytes; //Räknare för värde på aktuell kontrollbyte samt totalt antal räknade bytes i svep
sweep=temp=list; //Initerar listor. Låter sweep och temp släpa.
list=list->next; //Framförhållning
while (list!=NULL){ //Kollar igenom listan
sweepstop=false; //Intierar svepflagga
//Packbart svep
if (temp->data==list->data){ //Kontroll om svep av lika byte
controlByte=-1; //Sätter kontrollbyten till -1
while (list!=NULL && !sweepstop){ //Repetera till listan eller svepet slut
if (temp->data==list->data){ //Om lika bytes så:
list=list->next; //Stegar upp listan
controlByte--; //Stega upp räknaren för svepet
if (controlByte==-128){ //Om 128 byte räknade:
PutLast(packed,controlByte);// Repetera kontrollbyte
controlByte=0;
}
}
else sweepstop=true; //Sätter ner flagga om svepet slut
}
PutLast(packed,controlByte); //Skriver antalet lika bytes till packade listan
PutLast(packed,temp->data); //Skriver vilken byte som upprepats
}
//Opackbart svep
else if (!sweepstop){ //Om ej svep av samma byte detekterat -> svep av olika bytes
controlByte=totalBytes=1; //Sätter räknaren
sweep=temp; //Sätter sveplistan att starta på byte där svepet börjar
while (list!=NULL && !sweepstop){ //Repetera till listan slut eller svepstopp
if (temp->data!=list->data){ //Om nästföljande byte olika:
controlByte++; // Stega upp räknaren för svep med olika bytes
totalBytes++; // Håller reda på totala antalet i svepet
temp=list; // Låter temporära listan släpa en byte
list=list->next; // Framförhållning
if (controlByte==127){ // Om räknat 127 tal i svepet:
PutLast(packed,controlByte);// Repetera kontrollbyte
controlByte=0; // Nollställ kontrollbytens värde
}
}
else if (temp->data==list->data){ //Om samma tecken detekterat:
list=temp; // Flytta listan ett steg bakåt
sweepstop=true; // Flagga för svepstopp sätts
controlByte--; // Kontrollbyten stegas ner ett värde då den sista byten inte hör till samma svep
totalBytes--; // Totala antalet bytes i svepet räknas ner }
}
}
PutLast(packed,controlByte); //Skriver kontrollbyte för opackbart svep till packade listan
while (sweep!=NULL){ //Skriver opackbart svep till listan
PutLast(packed,sweep->data); //Lägger sist till packed-listan
sweep=sweep->next; //Löper igenom listan
totalBytes--;
if (totalBytes==0) sweep=NULL; //Om räknaren=0 har hela det opackbara svepet lagrats till listan
}
}
if (list!=NULL){ //Stegar upp listan om den inte är slut
temp=list; //Låter temp släpa ett steg i listan
list=list->next; //Framförhållning
}
}
return packed; //Returnerar packad sekvens
}
//Packar upp packad sekvens
Element *Unpack(Element *list)
{
Element *unpacked=NULL; //Initierar opackad lista
int counter; //Räknare för antalet bytes som skall packas upp
while (list!=NULL) //Repetera till sekvensen slut
{ //Packbart svep
if (list->data<0){ //Detektera kontrollbyte för packbart svep
counter=list->data; //Ladda kontrollbyte till räknaren
while (list->data==-128){ //Addera repeterade kontrollbytes
list=list->next; //Kolla nästa
if (list->data!=0) //Om 0 -> 128 bytes i svepet
counter+=list->data; //Addera nästa kontrollbyte till räknaren
}
list=list->next; //Hämta vilket tecken som upprepats
while (counter!=0) //Repetera till alla tecken lagrade
{
PutLast(unpacked,list->data); //Skriver tecknet till listan
counter++; //Stega ner räknaren
}
list=list->next; //Stega till nästa kontrolltecken
}
else{//Opackbart svep //Om kontrollbyte för opackbart svep
counter=list->data; //Sätt räknaren till antalet i det opackbara svepet
while (list->data==127){ //Addera repeterade kontrollbytes
list=list->next;
if (list->data!=0) //Om 0 -> 127 bytes i svepet
counter+=list->data;
}
while (counter!=0){ //Repetera till hela svepet av olika tecken lagrat
list=list->next; //Stegar till nästa tecken i svepet
PutLast(unpacked,list->data); //Skriver till listan för opackad sekvens
counter--; //Stegar ner räknaren
}
if (list!=NULL) list=list->next; //Stegar till nästa svep
}
}
return unpacked; //Returnerar opackad sekvens
}
//Huvudprogram
int main()
{
char *fileName, *outFileName; //Variabler för aktuella filer
char svar; //Svarsvariabel för alternativen i programmet
Element *list=NULL; //Initerar listan
bool fel=true;
while (true)
{
Element *first=NULL; //Sätter startvärde i listan
//Interface
cout << "RLE (komprimerare och dekomprimerare)\n\n";
cout << "Valj nagot av foljande alternativ:\n" << endl;
cout << "1:Packa fil." << endl;
cout << "2:Packa upp fil." << endl;
cout << "3:Avsluta." << endl;
cout << "Kommando: ";
cin >> svar; //Lagrar kommando
cout << endl;
//Välja alternativ
if (svar=='1'){
bool fel=true;
while (fel){
cout << "Valj fil som du vill packa:" << endl << endl;
cout << "1:Dokument.doc" << endl;
cout << "2:Bild.gif" << endl;
cout << "3:Tecken.txt" << endl;
cout << "Kommando: ";
cin >> svar;
switch (svar){
case '1':fileName="Dokument.doc";
fel=false;
break;
case '2':fileName="Bild.gif";
fel=false;
break;
case '3':fileName="Tecken.txt";
fel=false;
break;
default : cout << "Felaktigt kommando!" << endl; fel=true;
}
}
cout << "Laddar. Ha overseende med att det kan ta en stund." << endl;
list=Load(first,fileName); //Hämtar opackad sekvens från fil och lagrar i listan
cout << "Packar." << endl;
list=Pack(list); //Packar sekvensen, lagrar till listan
fileName = "SenastPackad.txt"; //Fil för senast packade
cout << "Sparar." << endl;
Save(list,fileName); //Skriver till utskriftfil
cout << "Den packade filen har sparats till '" << fileName << "'." << endl;
cout << "\n\n"; //Kosmetika
}
else if (svar=='2'){
//Alternativ
bool fel=true;
while (fel){
cout << "Valj fil som du vill packa upp:" << endl << endl;
cout << "1:PackadDoc.txt" << endl;
cout << "2:PackadGif.txt" << endl;
cout << "3:PackadTxt.txt" << endl;
cout << "Kommando: ";
cin >> svar;
switch (svar){
case '1':fileName="PackadDoc.txt";
outFileName="OutDoc.doc";
fel=false;
break;
case '2':fileName="PackadGif.txt";
outFileName="OutGif.gif";
fel=false;
break;
case '3':fileName="PackadTxt.txt";
outFileName="OutTxt.txt";
fel=false;
break;
default : cout << "Felaktigt kommando!" << endl; fel=true;
}
}
cout << "Laddar. Ha overseende med att det kan ta en stund." << endl;
list=Load(first,fileName); //Laddar packad sekvens till listan
cout << "Packar upp." << endl;
list=Unpack(list); //Packar upp listan, lagrar
cout << "Sparar fil." << endl;
Save(list,outFileName); //Skriver utskriftfil
cout << "Den upp-packade filen har fatt namnet '" << outFileName << "'." << endl;
cout << "\n\n"; //Kosmetika
}
else if (svar=='3') return 0; //Avsluta
else cout << "Felaktigt kommando!" << endl;//Vid felaktigt inmatat kommando
}
return 0;
}