Artifact Content

Not logged in

Artifact b142f0fccb14651d0680fd99e093ab2757ee6475


     1  
     2  #include "stdafx.h"
     3  #include "ArcMsc.h"
     4  #include "NoahApp.h"
     5  
     6  bool CArcMsc::header( kiFile& fp, unsigned long* siz, char* ext )
     7  {
     8  	// 読み出す
     9  	unsigned char p[14];
    10  	if( 14!=fp.read(p,14) )
    11  		return false;
    12  
    13  	// ヘッダ構造:SZDD芋'3A [ext3rd] [orisiz(dword)]
    14  	static const unsigned char head[9]={ 0x53,0x5A,0x44,0x44,0x88,0xF0,0x27,0x33,0x41 };//="SZDD芋'3A";
    15  
    16  	for( int i=0; i!=9; i++ )
    17  		if( p[i]!=head[i] )
    18  			return false;
    19  
    20  	if( ext )
    21  		*ext = (char)p[9];
    22  
    23  	DWORD x = p[10]+(p[11]<<8)+(p[12]<<16)+(p[13]<<24);
    24  	if( siz )
    25  		*siz=x;
    26  
    27  	// 原理的に、16倍という圧縮率は出ない
    28  	return (x <= fp.getSize()*16);
    29  }
    30  
    31  void CArcMsc::filename( char* oname, const char* ol, char ext )
    32  {
    33  	// コピー
    34  	ki_strcpy( oname, ol );
    35  
    36  	// 最後が '_' なら消しておく。
    37  	bool bIs_=false;
    38  	for( char* p=oname; *p; p=kiStr::next(p) ) 
    39  		bIs_ = (*p=='_');
    40  	if( bIs_ )
    41  		*(--p)='\0';
    42  
    43  
    44  	if( ext )
    45  	{
    46  		// 拡張子復元
    47  		*p++ = ext;
    48  		*p   = '\0';
    49  	}
    50  	else
    51  	{
    52  		// 拡張子自動補完
    53  		const char* x = kiPath::ext(oname);
    54  		if( ki_strlen(x)==2 )
    55  		{
    56  			::CharLower(oname);
    57  
    58  				 if( 0==ki_strcmp(x,"ex") )(*p++)='e';
    59  			else if( 0==ki_strcmp(x,"co") )(*p++)='m';
    60  			else if( 0==ki_strcmp(x,"sc") )(*p++)='r';
    61  
    62  			else if( 0==ki_strcmp(x,"dl") )(*p++)='l';
    63  			else if( 0==ki_strcmp(x,"oc") )(*p++)='x';
    64  			else if( 0==ki_strcmp(x,"dr") )(*p++)='v';
    65  			else if( 0==ki_strcmp(x,"vx") )(*p++)='d';
    66  			else if( 0==ki_strcmp(x,"38") )(*p++)='6';
    67  			else if( 0==ki_strcmp(x,"sy") )(*p++)='s';
    68  			else if( 0==ki_strcmp(x,"cp") )(*p++)='l';
    69  			else if( 0==ki_strcmp(x,"li") )(*p++)='b';
    70  			else if( 0==ki_strcmp(x,"tt") )(*p++)='f';
    71  
    72  			else if( 0==ki_strcmp(x,"ch") )(*p++)='m';
    73  			else if( 0==ki_strcmp(x,"hl") )(*p++)='p';
    74  			else if( 0==ki_strcmp(x,"cn") )(*p++)='t';
    75  			else if( 0==ki_strcmp(x,"da") )(*p++)='t';
    76  
    77  			else if( 0==ki_strcmp(x,"tx") )(*p++)='t';
    78  			else if( 0==ki_strcmp(x,"wr") )(*p++)='i';
    79  			else if( 0==ki_strcmp(x,"wa") )(*p++)='v';
    80  			else if( 0==ki_strcmp(x,"mi") )(*p++)='d';
    81  			else if( 0==ki_strcmp(x,"rm") )(*p++)='i';
    82  			else if( 0==ki_strcmp(x,"bm") )(*p++)='p';
    83  			else if( 0==ki_strcmp(x,"rl") )(*p++)='e';
    84  			else if( 0==ki_strcmp(x,"cu") )(*p++)='r';
    85  			else if( 0==ki_strcmp(x,"do") )(*p++)='c';
    86  			else if( 0==ki_strcmp(x,"ic") )(*p++)='o';
    87  			else if( 0==ki_strcmp(x,"re") )(*p++)='g';
    88  			else if( 0==ki_strcmp(x,"rt") )(*p++)='f';
    89  			else if( 0==ki_strcmp(x,"ht") )(*p++)='m';
    90  			else						   (*p++)='#';
    91  
    92  			*p = '\0';
    93  		}
    94  	}
    95  }
    96  
    97  bool CArcMsc::v_check( const kiPath& aname )
    98  {
    99  	kiFile fp;
   100  	if( fp.open( aname ) )
   101  		return header( fp,NULL,NULL );
   102  	return false;
   103  }
   104  
   105  bool CArcMsc::v_list( const arcname& aname, aflArray& files )
   106  {
   107  	kiPath fname(aname.basedir); fname+=aname.lname;
   108  
   109  	arcfile x;
   110  	kiFile fp;
   111  	char ext;
   112  	if( !fp.open( fname ) || !header( fp, &x.inf.dwOriginalSize, &ext ) )
   113  		return false;
   114  	ki_strcpy( x.inf.szMode, "-msc-" );
   115  	filename( x.inf.szFileName, aname.lname, ext );
   116  	x.inf.dwCompressedSize = fp.getSize();
   117  	x.isfile = true;
   118  
   119  	// TODO: 日時をどうする?
   120  
   121  	files.add( x );
   122  	return true;
   123  }
   124  
   125  int CArcMsc::v_melt( const arcname& aname, const kiPath& ddir, const aflArray* files )
   126  {
   127  	kiFile fp;
   128  	kiPath fname(aname.basedir); fname+=aname.lname;
   129  	kiPath oname(ddir);
   130  	char tmp[MAX_PATH];
   131  
   132  	// ヘッダ読み込み
   133  	char ext;
   134  	unsigned long alllen;
   135  	if( !fp.open( fname ) || !header(fp,&alllen,&ext) )
   136  		return 0xffff;
   137  	fp.close();
   138  	filename( tmp, aname.lname, ext );
   139  	oname += tmp;
   140  
   141  	// 書庫・出力先を開く
   142  	OFSTRUCT of;
   143  	of.cBytes = sizeof(of);
   144  	int FROM = ::LZOpenFile( const_cast<char*>((const char*)fname),&of,OF_READ );
   145  	int TO   = ::LZOpenFile( const_cast<char*>((const char*)oname),&of,OF_WRITE|OF_CREATE );
   146  	if( FROM<0 || TO<0 )
   147  		return 0xffff;
   148  	// 解凍
   149  	bool ans = (0<=::LZCopy( FROM,TO ));
   150  	// 終了
   151  	::LZClose( TO );
   152  	::LZClose( FROM );
   153  	return ans?0:0xffff;
   154  }
   155  
   156  int CArcMsc::v_compress( const kiPath& base, const wfdArray& files, const kiPath& ddir, int method, bool sfx )
   157  {
   158  	::SetCurrentDirectory( base );
   159  
   160  	// 元ファイルを開く
   161  	kiFile in;
   162  	if( !in.open( files[0].cFileName ) )
   163  		return 0xffff;
   164  
   165  	// ヘッダ情報・圧縮先ファイル名
   166  	char h_Ext3 = '\0';
   167  	unsigned long h_Len = in.getSize();
   168  
   169  	char aname[MAX_PATH];
   170  	ki_strcpy( aname, files[0].cFileName );
   171  	for( char *x=aname, *last=aname; *x; x=kiStr::next(x) )
   172  		last = x;
   173  	if( !IsDBCSLeadByte(*last) )
   174  		h_Ext3=*last;
   175  	*last = '_', *(last+1) = '\0';
   176  
   177  	// 圧縮先開く
   178  	::SetCurrentDirectory( ddir );
   179  
   180  	// 圧縮先を開く
   181  	kiFile out;
   182  	if( !out.open( aname, false ) )
   183  		return 0xffff;
   184  
   185  	// タイムスタンプコピー
   186  	FILETIME ct, at, mt;
   187  	::GetFileTime(in.getHandle(), &ct, &at, &mt);
   188  	::SetFileTime(out.getHandle(), &ct, &at, &mt);
   189  
   190  	// ヘッダ書き込み
   191  	unsigned char head[14]={ 0x53,0x5A,0x44,0x44,0x88,0xF0,0x27,0x33,0x41,(unsigned char)h_Ext3,
   192  							 (unsigned char)(h_Len&0xff),(unsigned char)((h_Len>>8)&0xff),
   193  							 (unsigned char)((h_Len>>16)&0xff),(unsigned char)((h_Len>>24)&0xff) };
   194  	out.write( head, 14 );
   195  
   196  	// 圧縮作業
   197  	CArcProgressDlg dlg( h_Len, true );
   198  	dlg.change( files[0].cFileName );
   199  	if( !do_lzss( in, out, dlg ) )
   200  	{
   201  		out.close();
   202  		::DeleteFile(aname);
   203  		return 0x8020;
   204  	}
   205  	return 0;
   206  }
   207  
   208  
   209  //-- 12bit LZSS -----------------------------------------------//
   210  
   211  
   212  #define N 4096 // slide窓のサイズ 2^12 bytes
   213  #define F 18   // 最長一致長 2^(16-12)+2 bytes
   214  
   215  static unsigned char window[N+F-1];
   216  static int dad[N+1], lson[N+1], rson[N+257];
   217  static int matchpos, matchlen;
   218  
   219  static void init_tree()
   220  {
   221  	//-- 木を初期化
   222  
   223  	int i;
   224  	for( i=N+1; i<=N+256; i++ ) // root: 0x00 -- 0xff
   225  		rson[i] = N;
   226  	for( i=0; i<N ; i++ )
   227  		 dad[i] = N;
   228  }
   229  
   230  static void insert_node( int r )
   231  {
   232  	//-- [位置r]から始まる[列str]を木に登録
   233  	unsigned char* str = window + r;
   234  	rson[r] = lson[r] = N;
   235  
   236  	//-- ついでに一致長・位置も記録する
   237  	matchlen = 2;
   238  
   239  	// 一文字目でrootを選ぶ
   240  	int i, p = N+1+str[0], cmp=1;
   241  	for(; ;)
   242  	{
   243  		if( cmp >= 0 )
   244  		{
   245  			// 右に進む
   246  			if( rson[p] != N )
   247  				p = rson[p];
   248  			// 右にはもうnodeがないのでそこに登録して終了
   249  			else
   250  			{
   251  				rson[p] = r;
   252  				 dad[r] = p;
   253  				return;
   254  			}
   255  		}
   256  		else
   257  		{
   258  			// 左に進む
   259  			if( lson[p] != N )
   260  				p = lson[p];
   261  			// 左にはもうnodeがないのでそこに登録して終了
   262  			else
   263  			{
   264  				lson[p] = r;
   265  				 dad[r] = p;
   266  				return;
   267  			}
   268  		}
   269  
   270  		// 現在のnodeとstrを比較( i==一致長 )
   271  		for( i=1; i<F; i++ )
   272  			if( cmp = str[i] - window[p+i] )
   273  				break;
   274  
   275  		// 今まで見つけたものの中で最長だったら記憶
   276  		if( i > matchlen )
   277  		{
   278  			matchpos = p;
   279  			if( (matchlen=i) == F )
   280  				break;
   281  		}
   282  	}
   283  
   284  	// [位置p]の列と長さFで一致した場合、ここに来る
   285  	// p の在ったところを r で置き換える
   286  
   287  	 dad[r] =  dad[p];
   288  	lson[r] = lson[p];
   289  	rson[r] = rson[p];
   290  	 dad[lson[p]] = r;
   291  	 dad[rson[p]] = r;
   292  
   293  	if( rson[dad[p]]==p )
   294  		rson[dad[p]] = r;
   295  	else
   296  		lson[dad[p]] = r;
   297  
   298  	dad[p] = N;
   299  }
   300  
   301  static void delete_node( int p )
   302  {
   303  	//-- [位置p]の要素を木から削除
   304  
   305  	if( dad[p] == N ) // 既に木に入ってないのでおしまい
   306  		return;
   307  
   308  	int q;
   309  
   310  	if( rson[p] == N )
   311  		q = lson[p]; // 唯一の子を上に持ち上げる
   312  	else if( lson[p] == N )
   313  		q = rson[p]; // 唯一の子を上に持ち上げる
   314  	else
   315  	{
   316  		q = lson[p];
   317  
   318  		if( rson[q] != N )
   319  		{
   320  			// 左の枝の最右、つまり自分より一つ小さいnodeを持ち上げる
   321  			do
   322  				q = rson[q];
   323  			while( rson[q] != N );
   324  
   325  			rson[dad[q]] = lson[q];
   326  			dad[lson[q]] = dad[q];
   327  			lson[q] = lson[p];
   328  			dad[lson[p]] = q;
   329  		}
   330  		rson[q] = rson[p];
   331  		dad[rson[p]] = q;
   332  	}
   333  
   334  	dad[q] = dad[p];
   335  	if( rson[dad[p]] == p )
   336  		rson[dad[p]] = q;
   337  	else
   338  		lson[dad[p]] = q;
   339  	dad[p] = N;
   340  }
   341  
   342  bool CArcMsc::do_lzss( kiFile& in, kiFile& out, CArcProgressDlg& dlg )
   343  {
   344  	int i, c, len, r, s;
   345  	unsigned char code[17]={0}, mask=1, codeptr=1;
   346  
   347  	s = 2;		// s = データ読込位置
   348  	r = N - 16;	// r = 木への挿入位置
   349  
   350  	// クリア
   351  	init_tree();
   352  	ki_memset( window+2, ' ', N-F );
   353  
   354  	// 先頭18bytes入力
   355  	for( len=0 ; len<F ; len++ )
   356  	{
   357  		if( -1 == (c = in.getc()) )
   358  			break;
   359  		window[r+len] = c;
   360  	}
   361  	window[0] = window[r+16];
   362  	window[1] = window[r+17];
   363  	if( len==0 )
   364  		return true;
   365  
   366  	// 木へ挿入
   367  	for( i=F ; i>=0 ; i-- )
   368  		insert_node( r-i );
   369  
   370  	// ループ
   371  	unsigned int total_read=18,prgr_read=0;
   372  
   373  	do
   374  	{
   375  		if( prgr_read > 5000 )
   376  		{
   377  			dlg.change( NULL, total_read+=prgr_read );
   378  			prgr_read-=5000;
   379  			if( !dlg.msgloop() )
   380  			{
   381  				prgr_read=0xffffffff;
   382  				break;
   383  			}
   384  		}
   385  
   386  		if( matchlen > len )
   387  			matchlen=len;
   388  
   389  		if( matchlen < 3 )	// 一致なし
   390  		{
   391  			matchlen = 1;
   392  			code[0] |= mask;
   393  			code[codeptr++] = window[r];
   394  		}
   395  		else				// 一致あり
   396  		{
   397  			// [pos&0xff] [pos&0xf00 | len-3]
   398  			code[codeptr++] = (unsigned char)matchpos;
   399  			code[codeptr++] = (unsigned char)(((matchpos>>4)&0xf0) | (matchlen-3));
   400  		}
   401  
   402  		if( (mask<<=1)==0 ) // code が 8Block になっていたら出力
   403  		{
   404  			out.write( code, codeptr );
   405  			// コードバッファ初期化
   406  			code[0] = 0;
   407  			codeptr = mask = 1;
   408  		}
   409  
   410  		// 出力した分読み込む
   411  		int lastmatchlen = matchlen;
   412  		for( i=0 ; i<lastmatchlen; i++ )
   413  		{
   414  			if( -1 == (c=in.getc()) )
   415  				break;
   416  			prgr_read++;
   417  
   418  			// [位置s]に一文字書き込み
   419  			delete_node( s );
   420  			window[s] = c;
   421  			if( s < F-1 ) window[ N+s ] = c;
   422  
   423  			s = (s+1) & (N-1); // s++
   424  			r = (r+1) & (N-1); // r++
   425  
   426  			// 木に[位置r]のデータを挿入
   427  			insert_node( r );
   428  		}
   429  
   430  		// EOF後処理
   431  		while( i++ < lastmatchlen )
   432  		{
   433  			delete_node( s );
   434  			s = (s+1) & (N-1); // s++
   435  			r = (r+1) & (N-1); // r++
   436  			if( --len )
   437  				insert_node( r );
   438  		}
   439  
   440  	} while( len > 0 );
   441  
   442  	if( prgr_read==0xffffffff )
   443  		return false;
   444  
   445  	// 8block境界に揃える
   446  	if( mask != 1 )
   447  	{
   448  		while( mask<<=1 )
   449  			code[codeptr++] = 0;
   450  		out.write( code, codeptr );
   451  	}
   452  
   453  	return true;
   454  }
   455