DXライブラリ本家にあるLZSS風圧縮をC++で書き換えてみました。
ここ:http://homepage2.nifty.com/natupaji/DxL ... press.html
圧縮プログラム
#include
#include
#include
using namespace std;
void PutFileString(char path[],string& str){
ofstream output(path,ios::binary | ios::out | ios::trunc );
copy(str.begin(),str.end(),ostreambuf_iterator(output));
}
void GetFileString(char path[],string& str){
ifstream input(path,ios::binary | ios::in);
if(!input){
cout (input),istreambuf_iterator(),back_inserter(str));
}
void EncodeLZSS(string& org,string& press){
string::iterator itr;
char min_ch;//目印文字
int MaxBack,MaxEqual;
//出現が最小の文字を目印文字に
int cnt[256];
fill(cnt,cnt+256,0);
for(itr=org.begin();itr!=org.end() ;itr++){
cnt[(unsigned char)*itr]++;
}
min_ch = cnt - min_element(cnt,cnt+256);
//文字列初期化
press.clear();
//目印文字を最初に出力
press += min_ch;
// 全てのデータを圧縮するまで繰り返す
for(itr=org.begin();itr!=org.end();itr++){
MaxEqual = 3;
MaxBack = -1;
int Back,Equal;
// 最高で254バイト前まで調べる
for(Back = 1 ; Back
#include
#include
#include
using namespace std;
void PutFileString(char path[],string& str){
ofstream output(path,ios::binary | ios::out | ios::trunc );
copy(str.begin(),str.end(),ostreambuf_iterator(output));
}
void GetFileString(char path[],string& str){
ifstream input(path,ios::binary | ios::in);
if(!input){
cout (input),istreambuf_iterator(),back_inserter(str));
}
void DecodeLZSS(string& press,string& org){
string::iterator itr,itr2;
char min_ch;//目印文字
int Back,Equal;
//文字列初期化
org.clear();
//最初の文字が目印文字
min_ch = press[0];
// 全てのデータを圧縮するまで繰り返す
for(itr=press.begin()+1;itr!=press.end();itr++){
//目印文字なら復元処理
if(*itr == min_ch){
itr++;
//2連続ならそのまま表示
if(*itr==min_ch){
org += *itr;
}else{
//255ならmin_chと同数値に変更
if(*itr==(char)255){
*itr=min_ch;
}
Back = (unsigned char)*itr;
itr++;
Equal = (unsigned char)*itr;
org.append(org.end()-Back,org.end()-Back+Equal);
}
}else{
org += *itr;
}
}
}
int main(int argc,char **argv){
string org,press;
atexit((void (*)())getchar);
// ファイル名の指定がなかったら終了
if( argc != 2 ){
cout <<"ファイルパスがありません"<<endl;
return 0;
}
if(strcmp(argv[1]+strlen(argv[1])-5,".lzss") != 0){
cout <<"拡張子が違います"<<endl;
return 0;
}
//ファイルから文字列を取得
GetFileString(argv[1],org);
//圧縮
DecodeLZSS(org,press);
//文字列をファイルに保存
argv[1][strlen(argv[1])-5] = '\0';
PutFileString(argv[1],press);
cout <<"解凍完了(push key)"<<endl;
return 0;
}
stringクラスとSTLの活用によって、本家よりかなり縮まって、簡単に書けました。本家のプログラムは圧縮は320行、解凍は250行程度あったりします。本家との互換性はないです。
しかし、istreambuf_iterator、ostreambuf_iterator、insert_iteratorなんかはネットで検索しても解説しているサイトがほとんど無いですね。借りてみて正解でした。