C++で圧縮プログラム

白い時空
記事: 18
登録日時: 15年前
住所: 埼玉県さいたま市

C++で圧縮プログラム

投稿記事 by 白い時空 » 14年前

最近STLの参考書を借りて読んだ&圧縮プログラムに興味があったので、
DXライブラリ本家にあるLZSS風圧縮をC++で書き換えてみました。
ここ:http://homepage2.nifty.com/natupaji/DxL ... press.html

圧縮プログラム

CODE:

#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;
}
※atexit((void (*)())getchar);はGUIでドラッグアンドドロップで使用したときにコマンドプロンプトがすぐに消えるのを防ぐためです。


stringクラスとSTLの活用によって、本家よりかなり縮まって、簡単に書けました。本家のプログラムは圧縮は320行、解凍は250行程度あったりします。本家との互換性はないです。

しかし、istreambuf_iterator、ostreambuf_iterator、insert_iteratorなんかはネットで検索しても解説しているサイトがほとんど無いですね。借りてみて正解でした。

コメントはまだありません。