Artifact Content

Not logged in

Artifact 764020530952f7eeb5a79f8e11ade0a8407ab589


     1  // NoahAM.cpp
     2  //-- control many archiver routines --
     3  
     4  #include "stdafx.h"
     5  #include "resource.h"
     6  #include "NoahApp.h"
     7  #include "NoahAM.h"
     8  #include "ArcDLL.h"
     9  #include "ArcAce.h"
    10  #include "ArcMsc.h"
    11  #include "ArcB2e.h"
    12  #include "ArcCpt.h"
    13  
    14  //----------------------------------------------//
    15  //------ 実働部隊のデータで初期化しておく ------//
    16  //----------------------------------------------//
    17  
    18  void CNoahArchiverManager::init()
    19  {
    20  	const char* kl = mycnf().kill();
    21  	static int dead[128];
    22  	while( *kl ) dead[ 0x7f & (*(kl++)) ] = 1;
    23  
    24  	// 初期対応形式
    25  	if( !dead['L'] )	m_AList.add( new CArcLzh );
    26  	if( !dead['7'] )	m_AList.add( new CArc7z ),
    27  						m_AList.add( new CArc7zZip );
    28  	if( !dead['Z'] )	m_AList.add( new CArcUnZip );
    29  	if( !dead['z'] )	m_AList.add( new CArcZip );
    30  	if( !dead['T'] )	m_AList.add( new CArcTar );
    31  	if( !dead['C'] )	m_AList.add( new CArcCab );
    32  	if( !dead['R'] )	m_AList.add( new CArcRar );
    33  	if( !dead['A'] )	m_AList.add( new CArcArj );
    34  	if( !dead['B'] )	m_AList.add( new CArcBga );
    35  	if( !dead['Y'] )	m_AList.add( new CArcYz1 );
    36  	if( !dead['G'] )	m_AList.add( new CArcGca );
    37  	if( !dead['a'] )	m_AList.add( new CArcAce );
    38  	if( !dead['M'] )	m_AList.add( new CArcMsc );
    39  	if( !dead['c'] )	m_AList.add( new CArcCpt );
    40  
    41  	// 拡張スクリプトロード
    42  	char prev_cur[MAX_PATH];
    43  	::GetCurrentDirectory(MAX_PATH, prev_cur);
    44  	::SetCurrentDirectory( CArcB2e::init_b2e_path() );
    45  	kiFindFile find;
    46  	find.begin( "*.b2e" );
    47  	WIN32_FIND_DATA fd;
    48  	for( int t=0; find.next(&fd); t++ )
    49  		m_AList.add( new CArcB2e(fd.cFileName) );
    50  	m_b2e = (t>1);
    51  	::SetCurrentDirectory(prev_cur);
    52  }
    53  
    54  //----------------------------------------------//
    55  //------------ ファイルリストを記憶 ------------//
    56  //----------------------------------------------//
    57  
    58  unsigned long CNoahArchiverManager::set_files( const cCharArray& files )
    59  {
    60  	//-- クリア
    61  	m_FName.empty();
    62  	m_BasePathList.empty();
    63  
    64  	//-- 基底パスを取得( 出来るだけ利用範囲を広げるため、8.3形式で )
    65  	if( files.len() != 0 )
    66  	{
    67  		char spath[MAX_PATH];
    68  		m_BasePath =
    69  			( 0!=::GetShortPathName( files[0], spath, MAX_PATH ) )
    70  			? spath : "";
    71  		if( !m_BasePath.beDirOnly() )
    72  		{
    73  			m_BasePath.beSpecialPath( kiPath::Cur );
    74  			m_BasePath.beBackSlash( true );
    75  		}
    76  	}
    77  
    78  	//-- 短いファイル名と長いのを両方取得しておく
    79  	m_FName.alloc( files.len() );
    80  	m_BasePathList.alloc( files.len() );
    81  	for( unsigned int i=0,c=0; i!=files.len(); i++ )
    82  		if( kiFindFile::findfirst( files[i], &m_FName[c] ) )
    83  		{
    84  			if( m_FName[c].cAlternateFileName[0] == '\0' )
    85  				::lstrcpy(m_FName[c].cAlternateFileName,m_FName[c].cFileName);
    86  			m_BasePathList[c] = files[i];
    87  			if( !m_BasePathList[c].beDirOnly() )
    88  			{
    89  				m_BasePathList[c].beSpecialPath( kiPath::Cur );
    90  				m_BasePathList[c].beBackSlash( true );
    91  			}
    92  			++c;
    93  		}
    94  	m_FName.forcelen( c );
    95  	m_BasePathList.forcelen( c );
    96  	return c;
    97  }
    98  
    99  //----------------------------------------------//
   100  //--- ファイルリストに解凍ルーチンを割り当て ---//
   101  //----------------------------------------------//
   102  
   103  // 指定された拡張子に対応しているルーチンを線形探索
   104  CArchiver* CNoahArchiverManager::fromExt( const char* ext )
   105  {
   106  	kiStr tmp = ext;
   107  	tmp.lower();
   108  
   109  	for( unsigned int i=0; i!=m_AList.len(); i++ )
   110  		if( m_AList[i]->extCheck( tmp ) 
   111  		 && (m_AList[i]->ability() & aMelt) )
   112  			return m_AList[i];
   113  	return NULL;
   114  }
   115  
   116  bool CNoahArchiverManager::map_melters( int mode ) // 1:cmp 2:mlt 3:must_mlt
   117  {
   118  	// クリア
   119  	m_Melters.empty();
   120  
   121  #define attrb (m_FName[ct].dwFileAttributes)
   122  #define lname (m_FName[ct].cFileName)
   123  #define sname (m_FName[ct].cAlternateFileName[0]==0 ? m_FName[ct].cFileName : m_FName[ct].cAlternateFileName)
   124  
   125  	kiPath fnm;
   126  	const char* ext;
   127  	for( unsigned int ct=0, bad=0; ct!=file_num(); ct++ )
   128  	{
   129  //		fnm = m_BasePath, fnm += sname;
   130  		fnm = m_BasePathList[ct], fnm += sname;
   131  
   132  		//-- 0byteファイル / ディレクトリは弾く
   133  		if( !(attrb & FILE_ATTRIBUTE_DIRECTORY) && 0!=kiFile::getSize( fnm, 0 ) )
   134  		{
   135  			//-- まず対応拡張子かどうかで候補Aを一つ選出
   136  			CArchiver* x = fromExt( ext=kiPath::ext(lname) );
   137  
   138  			//-- 候補Aで、ファイル内容によるチェック
   139  			if( x && x->check( fnm ) )
   140  			{
   141  				m_Melters.add( x );
   142  				continue;
   143  			}
   144  
   145  			//-- 候補Aが内容チェック不可なものだったらそれを使う
   146  			if( x && !(x->ability() & aCheck) )
   147  			{
   148  				m_Melters.add( x );
   149  				continue;
   150  			}
   151  
   152  			//-- 候補Aがダメなら、その他の内容チェック可能なルーチン全てで試す
   153  			if( mode!=1 || 0==ki_strcmpi( "exe", ext ) )
   154  			{
   155  				for( unsigned long j=0; j!=m_AList.len(); j++ )
   156  					if( m_AList[j]!=x && m_AList[j]->check( fnm ) )
   157  					{
   158  						m_Melters.add( m_AList[j] );
   159  						break;
   160  					}
   161  				if( m_Melters.len() == ct+1 )
   162  					continue;
   163  			}
   164  		}
   165  
   166  		//-- チェックの結果、解凍不能でしたとさ
   167  		if( mode!=3 )
   168  			return false; //-- 解凍専用モードでなければ終了
   169  		m_Melters.add( NULL ), bad++;
   170  	}
   171  #undef sname
   172  #undef lname
   173  #undef attrb
   174  
   175  	return (ct!=bad);
   176  }
   177  
   178  //----------------------------------------------//
   179  //--- ファイルリストに圧縮ルーチンを割り当て ---//
   180  //----------------------------------------------//
   181  
   182  bool CNoahArchiverManager::map_compressor( const char* ext, const char* method, bool sfx )
   183  {
   184  	int m;
   185  	m_Method = -1;
   186  	m_Sfx    = sfx;
   187  
   188  	for( unsigned int i=0; i!=m_AList.len(); i++ )
   189  		if( -1 != (m=m_AList[i]->cancompressby(ext,method,sfx)) )
   190  			if( m!=-2 ) // 完全一致
   191  			{
   192  				m_Compressor = m_AList[i];
   193  				m_Method = m;
   194  				break;
   195  			}
   196  			else if( m_Method == -1 ) // 形式名のみ一致した最初のモノ
   197  			{
   198  				m_Compressor = m_AList[i];
   199  				m_Method = m_AList[i]->cmp_mhd_default();
   200  			}
   201  	return (m_Method != -1);
   202  }
   203  
   204  //----------------------------------------------//
   205  //------------ バージョン情報文字列 ------------//
   206  //----------------------------------------------//
   207  
   208  void CNoahArchiverManager::get_version( kiStr& str )
   209  {
   210  	kiStr tmp;
   211  	for( unsigned int i=0; i!=m_AList.len(); i++ )
   212  		if( m_AList[i]->ver( tmp ) )
   213  			str+=tmp, str+="\r\n";
   214  }
   215  
   216  //----------------------------------------------//
   217  //--------------- 圧縮形式リスト ---------------//
   218  //----------------------------------------------//
   219  
   220  static unsigned int find( const cCharArray& x, const char* o )
   221  {
   222  	for( unsigned int i=0; i!=x.len(); i++ )
   223  		if( 0==ki_strcmp( x[i], o ) )
   224  			return i;
   225  	return 0xffffffff;
   226  }
   227  
   228  static unsigned int find( const StrArray& x, const char* o )
   229  {
   230  	for( unsigned int i=0; i!=x.len(); i++ )
   231  		if( x[i]==o )
   232  			return i;
   233  	return 0xffffffff;
   234  }
   235  
   236  void CNoahArchiverManager::get_cmpmethod(
   237  		const char* set,
   238  		int& def_mhd,
   239  		StrArray& mhd_list,
   240  		bool need_ext,
   241  		cCharArray* ext_list )
   242  {
   243  	def_mhd = -1;
   244  
   245  	const char* x;
   246  	for( unsigned int i=0; i!=m_AList.len(); i++ )
   247  	{
   248  		if( *(x = m_AList[i]->cmp_ext())=='\0' )
   249  			continue;
   250  		if( need_ext )
   251  		{
   252  			if( -1 == find( *ext_list, x ) )
   253  				ext_list->add( x );
   254  		}
   255  		if( 0 == ki_strcmp( set, x ) )
   256  		{
   257  			if( mhd_list.len()==0 )
   258  			{
   259  				def_mhd = m_AList[i]->cmp_mhd_default();
   260  				for( unsigned int j=0; j!=m_AList[i]->cmp_mhd_list().len(); j++ )
   261  					mhd_list.add( (m_AList[i]->cmp_mhd_list())[j] );
   262  			}
   263  			else
   264  			{
   265  				for( unsigned int j=0; j!=m_AList[i]->cmp_mhd_list().len(); j++ )
   266  					if( -1 == find( mhd_list, (m_AList[i]->cmp_mhd_list())[j] ) )
   267  						mhd_list.add( (m_AList[i]->cmp_mhd_list())[j] );
   268  			}
   269  		}
   270  	}
   271  
   272  	if( def_mhd == -1 )
   273  		def_mhd = 0;
   274  }
   275  
   276  //----------------------------------------------//
   277  //--------------- 書庫一覧モード ---------------//
   278  //----------------------------------------------//
   279  
   280  #include "SubDlg.h"
   281  
   282  void CNoahArchiverManager::do_listing( kiPath& destdir )
   283  {
   284  	kiWindow* mptr = app()->mainwnd();
   285  	kiPath ddir;
   286  	int    mdf = mycnf().mkdir();
   287  	bool   rmn = mycnf().mnonum();
   288  	destdir.beBackSlash( true );
   289  
   290  	//-- ダイアログの個数カウンタをクリア
   291  	kiArray<CArcViewDlg*> views;
   292  	CArcViewDlg::clear();
   293  
   294  	//-- ダイアログ起動
   295  	for( unsigned int i=0; i!=m_FName.len(); i++ )
   296  	{
   297  		if( !m_Melters[i] )
   298  			continue;
   299  
   300  		arcname an(
   301  			m_BasePathList[i],
   302  //			m_BasePath,
   303  			m_FName[i].cAlternateFileName[0]==0 ? m_FName[i].cFileName : m_FName[i].cAlternateFileName,
   304  			m_FName[i].cFileName );
   305  		ddir = destdir;
   306  
   307  		if( mdf )
   308  			generate_dirname( m_FName[i].cFileName, ddir, rmn );
   309  
   310  		CArcViewDlg* x = new CArcViewDlg( m_Melters[i],an,ddir );
   311  		views.add( x );
   312  		x->createModeless( NULL );
   313  	}
   314  
   315  	//-- 全部終了するまで待機
   316  	kiWindow::msgLoop( kiWindow::GET );
   317  
   318  	//-- お終い
   319  	app()->setMainWnd( mptr );
   320  	for( i=0; i!=views.len(); i++ )
   321  		delete views[i];
   322  }
   323  
   324  //----------------------------------------------//
   325  //----------------- 解凍作業 -------------------//
   326  //----------------------------------------------//
   327  
   328  void CNoahArchiverManager::do_melting( kiPath& destdir )
   329  {
   330  	//-- 設定ロード
   331  	const int  mdf = mycnf().mkdir();  // Make Directory Flag( 0:no 1:no1file 2: noddir 3:yes )
   332  	const bool rmn = mycnf().mnonum(); // Remove NuMber ?
   333  
   334  	//-- 出力先
   335  	destdir.beBackSlash( true );
   336  	destdir.mkdir(), destdir.beShortPath();
   337  
   338  	for( unsigned int i=0; i!=m_FName.len(); i++ )
   339  		if( m_Melters[i] )
   340  		{
   341  			//-- 出力先
   342  
   343  			int mk=2; // 0:no 1:yes 2:???
   344  			kiPath ddir( destdir ), dnm;
   345  			if( mdf==0 )
   346  				mk=0;
   347  			else if( mdf==3 )
   348  				mk=1;
   349  			else
   350  			{
   351  				kiPath anm(m_BasePathList[i]);
   352  //				kiPath anm(m_BasePath);
   353  				anm+=m_FName[i].cFileName;
   354  				int c = m_Melters[i]->contents( anm, dnm );
   355  				if( c==aSingleDir || (c==aSingleFile && mdf==1) )
   356  					mk=0; // 2重フォルダ防止処理(強)
   357  				else if( c==aMulti )
   358  					mk=1;
   359  			}
   360  			if( mk )
   361  			{
   362  				generate_dirname( m_FName[i].cFileName, ddir, rmn );
   363  				if( mk==2 && kiSUtil::exist(ddir) )
   364  					mk=1;
   365  				ddir+='\\';
   366  				ddir.mkdir();
   367  				ddir.beShortPath();
   368  			}
   369  
   370  			//-- 解凍!
   371  
   372  			arcname an( m_BasePathList[i],
   373  //			arcname an( m_BasePath,
   374  				m_FName[i].cAlternateFileName[0]==0 ? m_FName[i].cFileName : m_FName[i].cAlternateFileName,
   375  				m_FName[i].cFileName );
   376  			int result = m_Melters[i]->melt( an, ddir );
   377  			if( result<0x8000 )
   378  			{
   379  				if( mk==2 ) // 2重フォルダ防止処理(弱)
   380  					break_ddir( ddir, mdf==2 );
   381  				else if( mk==0 && dnm.len() ) // 2重フォルダ防止処理(強)
   382  					if( dnm.len()<=1 || dnm[1]!=':' ) // 絶対パスは開かない
   383  						ddir+=dnm, ddir+='\\';
   384  				// 出力先を開くかも
   385  				myapp().open_folder( ddir, 1 );
   386  			}
   387  			else if( result!=0x8020 )
   388  			{
   389  				//エラー!
   390  				char str[255];
   391  				wsprintf( str, "%s\nError No: [%x]",
   392  					(const char*)kiStr().loadRsrc( IDS_M_ERROR ), result );
   393  				app()->msgBox( str );
   394  			}
   395  		}
   396  }
   397  
   398  void CNoahArchiverManager::generate_dirname( const char* src, kiPath& dst, bool rmn )
   399  {
   400  	// srcで示された書庫名からディレクトリ名を生成し、
   401  	// dstへ足す。rmn==trueなら末尾の数字も削除
   402  
   403  	// 一番左の . と左から二番目の . を探す
   404  	const char *fdot=NULL, *sdot=NULL, *tail;
   405  	for( tail=src; *tail; tail=kiStr::next(tail) )
   406  		if( *tail=='.' )
   407  			sdot=fdot, fdot=tail;
   408  
   409  	// .tar.xxx か、.xxx.gz/.xxx.z/.xxx.bz2 なら二つ削除
   410  	if( fdot )
   411  	{
   412  		tail = fdot;
   413  		if( sdot )
   414  			if( 0==::lstrcmpi(fdot,".gz")
   415  			 || 0==::lstrcmpi(fdot,".z")
   416  			 || 0==::lstrcmpi(fdot,".bz2")
   417  			 || (sdot+4==fdot
   418  			 && (sdot[1]=='t'||sdot[1]=='T')
   419  			 && (sdot[2]=='a'||sdot[2]=='A')
   420  			 && (sdot[3]=='r'||sdot[3]=='R')
   421  			))
   422  				tail = sdot;
   423  	}
   424  
   425  	// 末尾の数字と'-'と'_'と'.'削除。半角スペースも。
   426  	bool del[256];
   427  	ki_memzero( del, sizeof(del) );
   428  	if( rmn )
   429  	{
   430  		del['-'] = del['_'] = del['.'] = true;
   431  		for( char c='0'; c<='9'; ++c )
   432  			del[c] = true;
   433  	}
   434  	del[' '] = true;
   435  
   436  	const char* mjs=NULL;
   437  	for( const char *x=src; x<tail; x=kiStr::next(x) )
   438  		if( !del[(unsigned char)(*x)] )
   439  			mjs = NULL;
   440  		else if( !mjs )
   441  			mjs = x;
   442  	if( mjs && mjs!=src )
   443  		tail = mjs;
   444  
   445  	// 空になってしまったら "noahmelt" という名前にしてしまう。
   446  	if( src==tail )
   447  		dst += "noahmelt";
   448  	else
   449  		while( src!=tail )
   450  			dst += *src++;
   451  }
   452  
   453  bool CNoahArchiverManager::break_ddir( kiPath& dir, bool onlydir )
   454  {
   455  // 2重フォルダ or 単一ファイル 状態を解消
   456  //
   457  // 素直に格納ファイル名を一度走査するのが本当なんですが、
   458  // 特に巨大書庫の時速度低下が激しいのと、FindFirst系を
   459  // サポートしたDLLや内蔵エンジン以外に対応できないという
   460  // 欠点があるため、相変わらず Noah 2.xx と同じ手法です。
   461  
   462  //-- 中に1個しか入ってないことを確認 -----------------
   463  	char wild[MAX_PATH];
   464  	ki_strcpy( wild, dir );
   465  	ki_strcat( wild, "*.*" );
   466  	kiFindFile find;
   467  	if( !find.begin( wild ) )
   468  		return false;
   469  	WIN32_FIND_DATA fd,fd2,fd3;
   470  	find.next( &fd );
   471  	if( find.next( &fd2 ) )
   472  		return false;
   473  	find.close();
   474  //----------------------------------------------------
   475  
   476  //-- to:最終移動先ファイル名。ついでに、カレントDirは消せない問題の回避策 -----
   477  	kiPath to(dir); to.beBackSlash( false ), to.beDirOnly();
   478  	::SetCurrentDirectory( to );
   479  	to += fd.cFileName;
   480  //-------------------------------------------------------------------------
   481  
   482  //-- ファイルだった場合 --------------------------------------
   483  	if( !(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) )
   484  	{
   485  		if( !onlydir )
   486  		{
   487  			// now 現在のファイル名
   488  			kiStr now=dir; now+=fd.cFileName;
   489  
   490  			// now -> to 移動
   491  			if( ::MoveFile( now, to ) )
   492  			{
   493  				dir.remove();
   494  				dir.beBackSlash( false ), dir.beDirOnly();
   495  				return true;
   496  			}
   497  		}
   498  	}
   499  //-- フォルダだった場合 ----------------------------------------
   500  	else
   501  	{
   502  		// 'base/aaa/aaa/' だと中のaaaを外にmoveできない。
   503  		// よって、回避策。-> 'base/aaa_noah_tmp_178116/aaa/'
   504  
   505  		dir.beBackSlash( false );
   506  		kiFindFile::findfirst( dir, &fd3 );
   507  		kiPath dirx( dir ); dirx+="_noah_tmp_178116";
   508  
   509  		if( ::MoveFile( dir, dirx ) )
   510  		{
   511  			// now 現在のファイル名
   512  			kiStr now( dirx ); now+='\\', now+=fd.cFileName;
   513  
   514  			// ディレクトリを移動
   515  			if( ::MoveFile( now, to ) )
   516  			{
   517  				dirx.remove();
   518  				dir=to, dir.beBackSlash( true );
   519  				return true;
   520  			}
   521  			else
   522  			{
   523  				// 'base/aaa_noah_tmp_178116/aaa/' -> 'base/aaa/aaa/'
   524  				dir.beDirOnly(), dir+=fd3.cFileName;
   525  				::MoveFile( dirx, dir );
   526  			}
   527  		}
   528  
   529  		dir.beBackSlash( true );
   530  	}
   531  //------------------------------------------------------------
   532  	return false;
   533  }
   534  
   535  //----------------------------------------------//
   536  //----------------- 圧縮作業 -------------------//
   537  //----------------------------------------------//
   538  
   539  void CNoahArchiverManager::do_compressing( kiPath& destdir, bool each )
   540  {
   541  	int result = 0xffff, tr;
   542  
   543  	// 出力先を確実に作っておく
   544  	destdir.beBackSlash( true );
   545  	destdir.mkdir();
   546  	destdir.beShortPath();
   547  
   548  	// 個別圧縮モードか、Archiving不可の形式なら一個ずつ
   549  	if( each || !(m_Compressor->ability() & aArchive) )
   550  	{
   551  		wfdArray templist;
   552  
   553  		for( unsigned int i=0; i!=m_FName.len(); i++ )
   554  		{
   555  			templist.empty();
   556  			templist.add( m_FName[i] );
   557  			tr = m_Compressor->compress( m_BasePath,templist,destdir,m_Method,m_Sfx );
   558  			if( tr<0x8000 || tr==0x8020 )
   559  				result = tr;
   560  		}
   561  	}
   562  	else
   563  		result = m_Compressor->compress( m_BasePath,m_FName,destdir,m_Method,m_Sfx );
   564  
   565  	// 開くかも
   566  	if( result<0x8000 )
   567  		myapp().open_folder( destdir, 2 );
   568  	else if( result!=0x8020 )
   569  	{
   570  		//エラー!
   571  		char str[255];
   572  		wsprintf( str, "%s\nError No: [%x]", "Compression Error", result );
   573  		app()->msgBox( str );
   574  	}
   575  }