📄 compress.cpp
字号:
// LZW compression
// note changes needed to compile with g++
#include <fstream.h>
#include <iostream.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include "chash.h"
// constants
const D = 4099, // hash function divisor
codes = 4096, // 2^12
ByteSize = 8,
excess = 4, // 12 - ByteSize
alpha = 256, // 2^ByteSize
mask1 = 255, // alpha - 1
mask2 = 15, // 2^excess - 1
mask = 15;
class Celement {
friend void Compress();
public:
operator unsigned long() const {return key;}
Celement& operator =(unsigned long y)
{key = y; return *this;}
private:
int code;
unsigned long key;
};
class Delement {
friend void Decompress();
friend void Output2(int);
private:
int prefix;
unsigned char suffix;
};
// globals
unsigned char s[codes]; // used to reconstruct text
int size, // size of reconstructed text
LeftOver, // left over bits from last code
status = 0; // 0 iff no left over bits
Delement ht[codes]; // dictionary
ifstream in;
ofstream out;
void SetFiles1(int argc, char* argv[])
{// Create input and Output1 streams.
char OutputFile[50], InputFile[50];
// see if file name provided
if (argc >= 2) strcpy(InputFile,argv[1]);
else {// name not provided, ask for it
cout << "Enter name of file to compress"
<< endl;
cout << "File name should have no extension"
<< endl;
cin >> InputFile;}
// name should not have an extension
if (strchr(InputFile,'.')) {
cerr << "File name has extension" << endl;
exit(1);}
// open files in binary mode
in.open(InputFile,ios::binary);
// in.open(InputFile); for g++
if (in.fail()) {cerr << "Cannot open " << InputFile
<< InputFile << endl;
exit(1);}
strcpy(OutputFile,InputFile);
strcat(OutputFile, ".zzz");
out.open(OutputFile,ios::binary);
// out.open(OutputFile); for g++
}
void Output1(unsigned long code);
void Compress()
{// Lempel-Ziv-Welch compressor.
// define and initialize the code dictionary
ChainHashTable<Celement, unsigned long> h(D);
Celement e;
for (int i = 0; i < alpha; i++) {// initialize
e.key = i;
e.code = i;
h.Insert(e);
}
int used = alpha; // number of codes used
// input and compress
unsigned char c;
in.get(c); // first character of input file
unsigned long pcode = c; // prefix code
if (!in.eof()) {// file length is > 1
do {// process rest of file
in.get(c);
if (in.eof()) break; // finished
unsigned long k = (pcode << ByteSize) + c;
// see if code for k is in the dictionary
if (h.Search(k, e)) pcode = e.code; // yes
else {// k not in table
Output1(pcode);
if (used < codes) // create new code
{e.code = used++;
e.key = (pcode << ByteSize) | c;
h.Insert(e);}
pcode = c;}
} while(true);
// output last code(s)
Output1(pcode);
if (status) {c = LeftOver << excess;
out.put(c);}
}
out.close();
in.close();
}
void Output1(unsigned long pcode)
{// Output1 8 bits, save rest in LeftOver.
unsigned char c,d;
if (status) {// 4 bits remain
d = pcode & mask1; // right ByteSize bits
c = (LeftOver << excess) | (pcode >> ByteSize);
out.put(c);
out.put(d);
status = 0;}
else {
LeftOver = pcode & mask2; // right excess bits
c = pcode >> excess;
out.put(c);
status = 1;}
}
void SetFiles2(int argc, char* argv[])
{// Determine file name.
char OutputFile[50], InputFile[50];
// see if file name provided
if (argc == 2) strcpy(OutputFile,argv[1]);
else {// name not provided, ask for it
cout << "Enter name of file to decompress"
<< endl;
cout << "Omit the extension .zzz" << endl;
cin >> OutputFile;}
// name should not have an extension
if (strchr(OutputFile,'.'))
{cerr << "File name has extension" << endl;
exit(1);}
strcpy(InputFile, OutputFile);
strcat(InputFile, ".zzz");
// open files in binary mode
in.open(InputFile,ios::binary);
// in.open(InputFile); for g++
if (in.fail()) {cerr << "Cannot open "
<< InputFile << endl;
exit(1);}
out.open(OutputFile,ios::binary);
// out.open(OutputFile); for g++
}
bool GetCode(int& code);
void Output2(int code);
void Decompress()
{// Decompress a compressed file.
int used = alpha; // codes used so far
// input and decompress
int pcode, // previous code
ccode; // current code
if (GetCode(pcode)){// file is not empty
s[0] = pcode; // character for pcode
out.put(s[0]); // output string for pcode
size = 0; // s[size] is first character of
// last string output
while(GetCode(ccode)) {// get another code
if (ccode < used) {// ccode is defined
Output2(ccode);
if (used < codes) {// create new code
ht[used].prefix = pcode;
ht[used++].suffix = s[size];}}
else {// special case, undefined code
ht[used].prefix = pcode;
ht[used++].suffix = s[size];
Output2(ccode);}
pcode = ccode;}
}
out.close();
in.close();
}
bool GetCode(int& code)
{// Put next code in compressed file into code.
// Return false if no more codes.
unsigned char c, d;
in.get(c); // input 8 bits
if (in.eof()) return false; // no more codes
// see if any left over bits from before
// if yes, concatenate with left over 4 bits
if (status) code = (LeftOver << ByteSize) | c;
else {// no left over bits, need four more bits
// to complete code
in.get(d); // another 8 bits
code = (c << excess) | (d >> excess);
LeftOver = d & mask;} // save 4 bits
status = 1 - status;
return true;
}
void Output2(int code)
{// Output string corresponding to code.
size = -1;
while (code >= alpha) {// suffix in dictionary
s[++size] = ht[code].suffix;
code = ht[code].prefix;
}
s[++size] = code; // code < alpha
// decompressed string is s[size] ... s[0]
for (int i = size; i >= 0; i--)
out.put(s[i]);
}
void main(int argc, char* argv[])
{
cout<<"please choose the operates you want:(1.compress files;2.decompress files)"<<endl;
char c;
cin>>c;
if(c=='1')
{
SetFiles1(argc, argv);
Compress();
}
else if(c=='2')
{
SetFiles2(argc, argv);
Decompress();
}
else
cout<<"wrong input!"<<endl;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -