Artifact Content

Not logged in

Artifact 10de0296b1be04cd0e0dda2965a5f5195347073d


     1  // Archiver.cpp
     2  //-- CArchiver -- common interface in 'Noah' for archiving routine --
     3  
     4  #include "stdafx.h"
     5  #include "Archiver.h"
     6  #include "NoahApp.h"
     7  
     8  
     9  
    10  CArcModule::CArcModule( const char* name, bool us )
    11  	: m_dll(NULL)
    12  {
    13  	// SearchPathの前にカレントディレクトリをnoah.exeと同じ場所へ
    14  	char prev_cur[MAX_PATH];
    15  	::GetCurrentDirectory(MAX_PATH, prev_cur);
    16  	kiSUtil::switchCurDirToExeDir();
    17  
    18  	if( 0!=::SearchPath( NULL,name,NULL,MAX_PATH,m_name,NULL ) )
    19  	{
    20  		const char* xt=kiPath::ext(name);
    21  		if( 0!=ki_strcmpi("dll",xt) )
    22  		{
    23  			// EXEの場合
    24  			m_type = us ? EXEUS : EXE;
    25  		}
    26  		else
    27  		{
    28  			// DLLの場合
    29  			m_dll = new kiArcDLLRaw(name);
    30  			m_type = DLL;
    31  			if(name<=xt-8&&xt[-6]=='G'&&xt[-5]=='C'&&xt[-4]=='A' )
    32  				m_type = DLLGCA;
    33  			else if(name==xt-6&&xt[-6]=='B'&&xt[-5]=='g'&&xt[-4]=='a' )
    34  				m_type = DLLBGA;
    35  		}
    36  	}
    37  	else
    38  	{
    39  		// ファイルが無いか、シェルのコマンドの場合
    40  		// バッファオーバーフローの危険…(^^;
    41  		ki_strcpy( m_name, name );
    42  		m_type = SHLCMD;
    43  	}
    44  
    45  	// カレントを戻す
    46  	::SetCurrentDirectory(prev_cur);
    47  }
    48  
    49  CArcModule::~CArcModule()
    50  {
    51  	delete m_dll;
    52  }
    53  
    54  int CArcModule::cmd( const char* cmd, bool mini )
    55  {
    56  	if( m_dll )
    57  	{
    58  		// アーカイバDLLモードなら簡単に終了
    59  		char buf[1024];
    60  		return m_dll->command( NULL, cmd, buf, sizeof(buf) );
    61  	}
    62  
    63  	// NTかどうかのチェック等
    64  	kiPath tmpdir;
    65  	static const bool isNT =
    66  		(app()->osver().dwPlatformId==VER_PLATFORM_WIN32_NT);
    67  	static const char* const closeShell =
    68  		(isNT ? "cmd.exe /c " : "command.com /c ");
    69  
    70  	// コマンド文字列作成
    71  	kiVar theCmd( m_name );
    72  	theCmd.quote();
    73  	theCmd += ' ';
    74  	theCmd += cmd;
    75  
    76  	if( m_type==SHLCMD )
    77  	{
    78  		// シェルコマンドの場合
    79  		theCmd = closeShell + theCmd;
    80  	}
    81  	else if( m_type==EXEUS )
    82  	{
    83  		// USモードの場合
    84  		if( isNT )
    85  		{
    86  			::SetEnvironmentVariable( "NOAHCMD", theCmd );
    87  			theCmd = "%NOAHCMD%";
    88  		}
    89  
    90  		// 切替バッチファイル生成
    91  		myapp().get_tempdir(tmpdir);
    92  		kiPath batname(tmpdir);
    93  		batname += "ncmd.bat";
    94  		kiFile bat;
    95  		bat.open( batname,false );
    96  		bat.write( "@CHCP 437\r\n@", 12 );
    97  		bat.write( theCmd, theCmd.len() );
    98  		bat.write( "\r\n@CHCP 932\r\n", 13 );
    99  
   100  		theCmd  = closeShell;
   101  		theCmd += batname;
   102  	}
   103  
   104  	// プロセス開始
   105  	PROCESS_INFORMATION pi;
   106  	STARTUPINFO si={sizeof(STARTUPINFO)};
   107  	si.dwFlags    =STARTF_USESHOWWINDOW;
   108  	si.wShowWindow=mini?SW_MINIMIZE:SW_SHOW;
   109  	if( !::CreateProcess( NULL,const_cast<char*>((const char*)theCmd),
   110  		NULL,NULL,FALSE,CREATE_NEW_PROCESS_GROUP|NORMAL_PRIORITY_CLASS,
   111  		NULL,NULL, &si,&pi ) )
   112  		return 0xffff;
   113  
   114  	// 終了待機
   115  	::CloseHandle( pi.hThread );
   116  	while( WAIT_OBJECT_0 != ::WaitForSingleObject( pi.hProcess, 500 ) )
   117  		kiWindow::msg();
   118  	int ex;
   119  	::GetExitCodeProcess( pi.hProcess, (DWORD*)&ex );
   120  	::CloseHandle( pi.hProcess );
   121  
   122  	// 後始末
   123  	if( m_type==EXEUS )
   124  		tmpdir.remove();
   125  	return ex;
   126  }
   127  
   128  void CArcModule::ver( kiStr& str )
   129  {
   130  	// バージョン情報を整形して表示
   131  	char *verstr="----", buf[200];
   132  	if( m_dll )
   133  	{
   134  		if( WORD ver=m_dll->getVer() )
   135  		{
   136  			WORD sub=m_dll->getVerSub();
   137  			::wsprintf( verstr=buf, "%d.%02d%c", ver/100, ver%100, (sub<100)?0:sub/100+'a'-1 );
   138  		}
   139  	}
   140  	else if( m_type != NOTEXIST )
   141  	{
   142  		// 可能ならリソースからの取得を試みる
   143  		if( CArchiver::GetVersionInfoStr( m_name, buf, sizeof(buf) ) )
   144  			verstr = buf;
   145  		else
   146  			verstr = "OK!";
   147  	}
   148  
   149  	char ans[300];
   150  	::wsprintf( ans, "%-12s %s", kiPath::name(m_name), verstr );
   151  	str = ans;
   152  }
   153  
   154  bool CArcModule::lst_dll( const arcname& aname, aflArray& files, const char* wild )
   155  {
   156  	if( !m_dll )
   157  		return false;
   158  	kiPath nm(aname.basedir); nm+=aname.lname;
   159  	HANDLE h = m_dll->openArc( app()->mainhwnd(), nm, M_CHECK_FILENAME_ONLY|M_ERROR_MESSAGE_OFF );
   160  	if( !h ) return false;
   161  
   162  	int ct=0;
   163  	files.forcelen( 1 );
   164  	if( 0==m_dll->findfirst( h, wild, &files[0].inf ) )
   165  	{
   166  		do
   167  		{
   168  			INDIVIDUALINFO& iii = files[ct].inf;
   169  			files[ct].isfile =
   170  				 ( *files[ct].inf.szAttribute!='d'
   171  				&& !kiPath::endwithyen(files[ct].inf.szFileName)
   172  				&& !(m_dll->getAttr( h )&FILE_ATTRIBUTE_DIRECTORY) );
   173  			files.forcelen( 1+(++ct) );
   174  		} while( 0==m_dll->findnext( h, &files[ct].inf ) );
   175  	}
   176  	files.forcelen( ct );
   177  
   178  	m_dll->closeArc( h );
   179  	return true;
   180  }
   181  
   182  int CArcModule::cnt( const kiPath& aname, kiPath& dname, const char* wild )
   183  {
   184  	int ans = aUnknown;
   185  
   186  	if( m_dll )
   187  		if( HANDLE h = m_dll->openArc( app()->mainhwnd(), aname, M_CHECK_FILENAME_ONLY|M_ERROR_MESSAGE_OFF ) )
   188  		{
   189  			INDIVIDUALINFO inf1st, inf;
   190  			if( 0==m_dll->findfirst( h, wild, &inf1st ) )
   191  			{
   192  				for( const char* y=inf1st.szFileName; *y && *y!='\\' && *y!='/'; y=kiPath::next(y) );
   193  				if( y!=inf1st.szFileName )
   194  				{
   195  					if( 0!=m_dll->findnext( h, &inf ) )
   196  						ans = *y ? aSingleDir : aSingleFile;
   197  					else if( *y && (y-inf1st.szFileName!=1 || inf1st.szFileName[0]!='.') )
   198  					{
   199  						ans = aSingleDir;
   200  						do
   201  							if( !ki_memcmp( inf1st.szFileName, inf.szFileName, (y-inf1st.szFileName)+1 ) )
   202  							{
   203  								ans = aUnknown;
   204  								break;
   205  							}
   206  						while( 0==m_dll->findnext( h, &inf ) );
   207  					}
   208  					if( ans==aSingleDir )
   209  						inf1st.szFileName[y-inf1st.szFileName]='\0', dname+=inf1st.szFileName;
   210  				}
   211  			}
   212  			m_dll->closeArc( h );
   213  		}
   214  
   215  	return ans;
   216  }
   217  
   218  bool CArcModule::lst_exe( const char* lstcmd, aflArray& files,
   219  	const char* BL, int BSL, const char* EL, int SL, int dx )
   220  	// BeginLine, BeginSkipLine, EndLine, SkipLine, delta-x
   221  {
   222  	files.forcelen(0);
   223  
   224  	// 作業変数
   225  	const int BLLEN = ki_strlen(BL);
   226  	const int ELLEN = ki_strlen(EL);
   227  	int /*ct=0,*/ step=BSL;
   228  
   229  	// EXE以外のものではダメ
   230  	if( m_type!=EXE && m_type!=EXEUS )
   231  		return false;
   232  
   233  	// コマンド文字列作成
   234  	kiVar theCmd( m_name );
   235  	theCmd.quote();
   236  	theCmd += ' ';
   237  	theCmd += lstcmd;
   238  
   239  	// パイプ作成(両方とも継承ON。DupHanするの面倒いので…(^^;)
   240  	HANDLE rp, wp;
   241  	SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES),NULL,TRUE};
   242  	::CreatePipe( &rp, &wp, &sa, 4096 );
   243  
   244  	// プロセス開始
   245  	PROCESS_INFORMATION pi;
   246  	STARTUPINFO si = {sizeof(STARTUPINFO)};
   247  	si.dwFlags     = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
   248  	si.wShowWindow = SW_MINIMIZE;
   249  	si.hStdOutput  = si.hStdError = wp;
   250  	BOOL ok = 
   251  		::CreateProcess( NULL,const_cast<char*>((const char*)theCmd),NULL,
   252  			NULL, TRUE, CREATE_NEW_PROCESS_GROUP|NORMAL_PRIORITY_CLASS,
   253  			NULL, NULL, &si,&pi );
   254  	::CloseHandle( wp );
   255  
   256  	// 失敗したらパイプを閉じて即終了
   257  	if( !ok )
   258  	{
   259  		::CloseHandle( rp );
   260  		return false;
   261  	}
   262  	::CloseHandle( pi.hThread );
   263  
   264  	// 解析作業etc(バッファのサイズはパイプのサイズの倍以上でなくてはならない)
   265  	char buf[8192], *end=buf;
   266  	for( bool endpr=false; !endpr; )
   267  	{
   268  		// 終了待機
   269  		endpr = (WAIT_OBJECT_0==::WaitForSingleObject(pi.hProcess,500));
   270  		kiWindow::msg();
   271  
   272  		// パイプから読みとり
   273  		DWORD red;
   274  		::PeekNamedPipe( rp, NULL, 0, NULL, &red, NULL );
   275  		if( red==0 )
   276  			continue;
   277  		::ReadFile( rp, end, buf+sizeof(buf)-end, &red, NULL );
   278  		end += red;
   279  
   280  		// 行に分解
   281  		char *lss=buf;
   282  		for( char *ls, *le=buf; le<end; ++le )
   283  		{
   284  			// 行末を探す
   285  			for( lss=ls=le; le<end; ++le )
   286  				if( *le=='\n' )
   287  					break;
   288  			if( le==end )
   289  				break;
   290  
   291  			// 先頭行スキップ処理
   292  			if( *BL )
   293  			{
   294  				if( BLLEN<=le-ls && ki_memcmp(BL,ls,BLLEN) )
   295  					BL = "";
   296  			}
   297  			// 行ステップ処理
   298  			else if( --step<=0 )
   299  			{
   300  				step = SL;
   301  
   302  				// 終端行処理
   303  				if( ELLEN==0 )
   304  					{ if( le-ls<=1 ) break; }
   305  				else if( ELLEN<=le-ls && ki_memcmp(EL,ls,ELLEN) )
   306  					break;
   307  
   308  				// 文字スキップ処理
   309  				if( dx>=0 )
   310  					ls += dx;
   311  				// 引数ブロックスキップ処理
   312  				else
   313  				{
   314  					for( ;ls<le;++ls )
   315  						if( *ls!=' ' && *ls!='\t' && *ls!='\r' )
   316  							break;
   317  					for( int t=dx; ++t; )
   318  					{
   319  						for( ;ls<le;++ls )
   320  							if( *ls==' ' || *ls=='\t' && *ls=='\r' )
   321  								break;
   322  						for( ;ls<le;++ls )
   323  							if( *ls!=' ' && *ls!='\t' && *ls!='\r' )
   324  								break;
   325  					}
   326  				}
   327  				// ファイル名コピー
   328  				if( ls<le )
   329  				{
   330  					arcfile af; ki_memzero(&af, sizeof(af));
   331  					af.inf.dwOriginalSize = 0xffffffff;
   332  //					ki_memzero( &files[ct].inf, sizeof(files[ct].inf) );
   333  //					files[ct].inf.dwOriginalSize = 0xffffffff;
   334  
   335  					int i=0;
   336  					bool prev_is_space=false;
   337  					while( i<FNAME_MAX32 && ls<le )
   338  					{
   339  						if( *ls==' ' )
   340  						{
   341  							if( prev_is_space )
   342  								break;
   343  							prev_is_space = true;
   344  						}
   345  						else if( *ls=='\t' || *ls=='\r' )
   346  							break;
   347  						else
   348  							prev_is_space = false;
   349  
   350  						af.inf.szFileName[i++] = *ls++;
   351  //						files[ct].inf.szFileName[i++] = *ls++;
   352  					}
   353  					if( prev_is_space )
   354  						--i;
   355  					if( i )
   356  					{
   357  /*
   358  						files[ct].inf.szFileName[i] = '\0';
   359  						files[ct].isfile = true;
   360  						files.forcelen( 1+(++ct) );
   361  */
   362  						af.inf.szFileName[i] = '\0';
   363  						af.isfile = true;
   364  						files.add(af);
   365  					}
   366  				}
   367  			}
   368  		}
   369  		// バッファシフト
   370  		if( lss != buf )
   371  			ki_memmov( buf, lss, end-lss ), end=buf+(end-lss);
   372  		else if( end==buf+sizeof(buf) )
   373  			end = buf;
   374  	}
   375  
   376  	// お終い
   377  	::CloseHandle( pi.hProcess );
   378  	::CloseHandle( rp );
   379  	return true;
   380  }
   381  
   382  /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
   383  // バージョン情報リソース取得
   384  
   385  bool CArchiver::GetVersionInfoStr( char* name, char* buf, size_t cbBuf )
   386  {
   387  	static bool old = mycnf().oldver();
   388  	if( old )
   389  		return false;
   390  
   391  	DWORD dummy = 0;
   392  	DWORD siz = ::GetFileVersionInfoSize( name, &dummy );
   393  	if( siz == 0 )
   394  		return false;
   395  
   396  	bool got = false;
   397  	BYTE* vbuf = new BYTE[siz];
   398  	if( 0 != ::GetFileVersionInfo( name, 0, siz, vbuf ) )
   399  	{
   400  		WORD* tr = NULL;
   401  		UINT cbTr = 0;
   402  
   403  		// 最初に見つけた言語とコードページで情報取得
   404  		if( ::VerQueryValue( vbuf,
   405  			"\\VarFileInfo\\Translation", (void**)&tr, &cbTr )
   406  		 && cbTr >= 4 )
   407  		{
   408  			char blockname[500]="";
   409  			::wsprintf( blockname,
   410  				"\\StringFileInfo\\%04x%04x\\ProductVersion",
   411  				tr[0], tr[1] );
   412  
   413  			char* inf = NULL;
   414  			UINT cbInf = 0;
   415  			if( ::VerQueryValue( vbuf, blockname, (void**)&inf, &cbInf )
   416  			 && cbInf < cbBuf-1 )
   417  			{
   418  				for( char* v=buf; *inf && cbInf; ++inf,--cbInf )
   419  					if( *inf != ' ' )
   420  						*v++ = (*inf==',' ? '.' : *inf);
   421  				*v = '\0';
   422  				got = true;
   423  			}
   424  		}
   425  		else
   426  		{
   427  			void* fi = NULL;
   428  			UINT cbFi = 0;
   429  			VS_FIXEDFILEINFO vffi;
   430  			if( ::VerQueryValue( vbuf, "\\", &fi, &cbFi )
   431  			 && sizeof(vffi)<=cbFi )
   432  			{
   433  				ki_memcpy( &vffi, fi, sizeof(vffi) );
   434  				if( vffi.dwFileVersionLS >= 0x10000 )
   435  					::wsprintf( buf, "%d.%d.%d", vffi.dwFileVersionMS>>16,
   436  						vffi.dwFileVersionMS&0xffff, vffi.dwFileVersionLS>>16 );
   437  				else
   438  					::wsprintf( buf, "%d.%d", vffi.dwFileVersionMS>>16,
   439  						vffi.dwFileVersionMS&0xffff );
   440  				got = true;
   441  			}
   442  		}
   443  	}
   444  
   445  	delete [] vbuf;
   446  	return got;
   447  }