Artifact Content

Not logged in

Artifact 10de0296b1be04cd0e0dda2965a5f5195347073d


// Archiver.cpp
//-- CArchiver -- common interface in 'Noah' for archiving routine --

#include "stdafx.h"
#include "Archiver.h"
#include "NoahApp.h"



CArcModule::CArcModule( const char* name, bool us )
	: m_dll(NULL)
{
	// SearchPathの前にカレントディレクトリをnoah.exeと同じ場所へ
	char prev_cur[MAX_PATH];
	::GetCurrentDirectory(MAX_PATH, prev_cur);
	kiSUtil::switchCurDirToExeDir();

	if( 0!=::SearchPath( NULL,name,NULL,MAX_PATH,m_name,NULL ) )
	{
		const char* xt=kiPath::ext(name);
		if( 0!=ki_strcmpi("dll",xt) )
		{
			// EXEの場合
			m_type = us ? EXEUS : EXE;
		}
		else
		{
			// DLLの場合
			m_dll = new kiArcDLLRaw(name);
			m_type = DLL;
			if(name<=xt-8&&xt[-6]=='G'&&xt[-5]=='C'&&xt[-4]=='A' )
				m_type = DLLGCA;
			else if(name==xt-6&&xt[-6]=='B'&&xt[-5]=='g'&&xt[-4]=='a' )
				m_type = DLLBGA;
		}
	}
	else
	{
		// ファイルが無いか、シェルのコマンドの場合
		// バッファオーバーフローの危険…(^^;
		ki_strcpy( m_name, name );
		m_type = SHLCMD;
	}

	// カレントを戻す
	::SetCurrentDirectory(prev_cur);
}

CArcModule::~CArcModule()
{
	delete m_dll;
}

int CArcModule::cmd( const char* cmd, bool mini )
{
	if( m_dll )
	{
		// アーカイバDLLモードなら簡単に終了
		char buf[1024];
		return m_dll->command( NULL, cmd, buf, sizeof(buf) );
	}

	// NTかどうかのチェック等
	kiPath tmpdir;
	static const bool isNT =
		(app()->osver().dwPlatformId==VER_PLATFORM_WIN32_NT);
	static const char* const closeShell =
		(isNT ? "cmd.exe /c " : "command.com /c ");

	// コマンド文字列作成
	kiVar theCmd( m_name );
	theCmd.quote();
	theCmd += ' ';
	theCmd += cmd;

	if( m_type==SHLCMD )
	{
		// シェルコマンドの場合
		theCmd = closeShell + theCmd;
	}
	else if( m_type==EXEUS )
	{
		// USモードの場合
		if( isNT )
		{
			::SetEnvironmentVariable( "NOAHCMD", theCmd );
			theCmd = "%NOAHCMD%";
		}

		// 切替バッチファイル生成
		myapp().get_tempdir(tmpdir);
		kiPath batname(tmpdir);
		batname += "ncmd.bat";
		kiFile bat;
		bat.open( batname,false );
		bat.write( "@CHCP 437\r\n@", 12 );
		bat.write( theCmd, theCmd.len() );
		bat.write( "\r\n@CHCP 932\r\n", 13 );

		theCmd  = closeShell;
		theCmd += batname;
	}

	// プロセス開始
	PROCESS_INFORMATION pi;
	STARTUPINFO si={sizeof(STARTUPINFO)};
	si.dwFlags    =STARTF_USESHOWWINDOW;
	si.wShowWindow=mini?SW_MINIMIZE:SW_SHOW;
	if( !::CreateProcess( NULL,const_cast<char*>((const char*)theCmd),
		NULL,NULL,FALSE,CREATE_NEW_PROCESS_GROUP|NORMAL_PRIORITY_CLASS,
		NULL,NULL, &si,&pi ) )
		return 0xffff;

	// 終了待機
	::CloseHandle( pi.hThread );
	while( WAIT_OBJECT_0 != ::WaitForSingleObject( pi.hProcess, 500 ) )
		kiWindow::msg();
	int ex;
	::GetExitCodeProcess( pi.hProcess, (DWORD*)&ex );
	::CloseHandle( pi.hProcess );

	// 後始末
	if( m_type==EXEUS )
		tmpdir.remove();
	return ex;
}

void CArcModule::ver( kiStr& str )
{
	// バージョン情報を整形して表示
	char *verstr="----", buf[200];
	if( m_dll )
	{
		if( WORD ver=m_dll->getVer() )
		{
			WORD sub=m_dll->getVerSub();
			::wsprintf( verstr=buf, "%d.%02d%c", ver/100, ver%100, (sub<100)?0:sub/100+'a'-1 );
		}
	}
	else if( m_type != NOTEXIST )
	{
		// 可能ならリソースからの取得を試みる
		if( CArchiver::GetVersionInfoStr( m_name, buf, sizeof(buf) ) )
			verstr = buf;
		else
			verstr = "OK!";
	}

	char ans[300];
	::wsprintf( ans, "%-12s %s", kiPath::name(m_name), verstr );
	str = ans;
}

bool CArcModule::lst_dll( const arcname& aname, aflArray& files, const char* wild )
{
	if( !m_dll )
		return false;
	kiPath nm(aname.basedir); nm+=aname.lname;
	HANDLE h = m_dll->openArc( app()->mainhwnd(), nm, M_CHECK_FILENAME_ONLY|M_ERROR_MESSAGE_OFF );
	if( !h ) return false;

	int ct=0;
	files.forcelen( 1 );
	if( 0==m_dll->findfirst( h, wild, &files[0].inf ) )
	{
		do
		{
			INDIVIDUALINFO& iii = files[ct].inf;
			files[ct].isfile =
				 ( *files[ct].inf.szAttribute!='d'
				&& !kiPath::endwithyen(files[ct].inf.szFileName)
				&& !(m_dll->getAttr( h )&FILE_ATTRIBUTE_DIRECTORY) );
			files.forcelen( 1+(++ct) );
		} while( 0==m_dll->findnext( h, &files[ct].inf ) );
	}
	files.forcelen( ct );

	m_dll->closeArc( h );
	return true;
}

int CArcModule::cnt( const kiPath& aname, kiPath& dname, const char* wild )
{
	int ans = aUnknown;

	if( m_dll )
		if( HANDLE h = m_dll->openArc( app()->mainhwnd(), aname, M_CHECK_FILENAME_ONLY|M_ERROR_MESSAGE_OFF ) )
		{
			INDIVIDUALINFO inf1st, inf;
			if( 0==m_dll->findfirst( h, wild, &inf1st ) )
			{
				for( const char* y=inf1st.szFileName; *y && *y!='\\' && *y!='/'; y=kiPath::next(y) );
				if( y!=inf1st.szFileName )
				{
					if( 0!=m_dll->findnext( h, &inf ) )
						ans = *y ? aSingleDir : aSingleFile;
					else if( *y && (y-inf1st.szFileName!=1 || inf1st.szFileName[0]!='.') )
					{
						ans = aSingleDir;
						do
							if( !ki_memcmp( inf1st.szFileName, inf.szFileName, (y-inf1st.szFileName)+1 ) )
							{
								ans = aUnknown;
								break;
							}
						while( 0==m_dll->findnext( h, &inf ) );
					}
					if( ans==aSingleDir )
						inf1st.szFileName[y-inf1st.szFileName]='\0', dname+=inf1st.szFileName;
				}
			}
			m_dll->closeArc( h );
		}

	return ans;
}

bool CArcModule::lst_exe( const char* lstcmd, aflArray& files,
	const char* BL, int BSL, const char* EL, int SL, int dx )
	// BeginLine, BeginSkipLine, EndLine, SkipLine, delta-x
{
	files.forcelen(0);

	// 作業変数
	const int BLLEN = ki_strlen(BL);
	const int ELLEN = ki_strlen(EL);
	int /*ct=0,*/ step=BSL;

	// EXE以外のものではダメ
	if( m_type!=EXE && m_type!=EXEUS )
		return false;

	// コマンド文字列作成
	kiVar theCmd( m_name );
	theCmd.quote();
	theCmd += ' ';
	theCmd += lstcmd;

	// パイプ作成(両方とも継承ON。DupHanするの面倒いので…(^^;)
	HANDLE rp, wp;
	SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES),NULL,TRUE};
	::CreatePipe( &rp, &wp, &sa, 4096 );

	// プロセス開始
	PROCESS_INFORMATION pi;
	STARTUPINFO si = {sizeof(STARTUPINFO)};
	si.dwFlags     = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
	si.wShowWindow = SW_MINIMIZE;
	si.hStdOutput  = si.hStdError = wp;
	BOOL ok = 
		::CreateProcess( NULL,const_cast<char*>((const char*)theCmd),NULL,
			NULL, TRUE, CREATE_NEW_PROCESS_GROUP|NORMAL_PRIORITY_CLASS,
			NULL, NULL, &si,&pi );
	::CloseHandle( wp );

	// 失敗したらパイプを閉じて即終了
	if( !ok )
	{
		::CloseHandle( rp );
		return false;
	}
	::CloseHandle( pi.hThread );

	// 解析作業etc(バッファのサイズはパイプのサイズの倍以上でなくてはならない)
	char buf[8192], *end=buf;
	for( bool endpr=false; !endpr; )
	{
		// 終了待機
		endpr = (WAIT_OBJECT_0==::WaitForSingleObject(pi.hProcess,500));
		kiWindow::msg();

		// パイプから読みとり
		DWORD red;
		::PeekNamedPipe( rp, NULL, 0, NULL, &red, NULL );
		if( red==0 )
			continue;
		::ReadFile( rp, end, buf+sizeof(buf)-end, &red, NULL );
		end += red;

		// 行に分解
		char *lss=buf;
		for( char *ls, *le=buf; le<end; ++le )
		{
			// 行末を探す
			for( lss=ls=le; le<end; ++le )
				if( *le=='\n' )
					break;
			if( le==end )
				break;

			// 先頭行スキップ処理
			if( *BL )
			{
				if( BLLEN<=le-ls && ki_memcmp(BL,ls,BLLEN) )
					BL = "";
			}
			// 行ステップ処理
			else if( --step<=0 )
			{
				step = SL;

				// 終端行処理
				if( ELLEN==0 )
					{ if( le-ls<=1 ) break; }
				else if( ELLEN<=le-ls && ki_memcmp(EL,ls,ELLEN) )
					break;

				// 文字スキップ処理
				if( dx>=0 )
					ls += dx;
				// 引数ブロックスキップ処理
				else
				{
					for( ;ls<le;++ls )
						if( *ls!=' ' && *ls!='\t' && *ls!='\r' )
							break;
					for( int t=dx; ++t; )
					{
						for( ;ls<le;++ls )
							if( *ls==' ' || *ls=='\t' && *ls=='\r' )
								break;
						for( ;ls<le;++ls )
							if( *ls!=' ' && *ls!='\t' && *ls!='\r' )
								break;
					}
				}
				// ファイル名コピー
				if( ls<le )
				{
					arcfile af; ki_memzero(&af, sizeof(af));
					af.inf.dwOriginalSize = 0xffffffff;
//					ki_memzero( &files[ct].inf, sizeof(files[ct].inf) );
//					files[ct].inf.dwOriginalSize = 0xffffffff;

					int i=0;
					bool prev_is_space=false;
					while( i<FNAME_MAX32 && ls<le )
					{
						if( *ls==' ' )
						{
							if( prev_is_space )
								break;
							prev_is_space = true;
						}
						else if( *ls=='\t' || *ls=='\r' )
							break;
						else
							prev_is_space = false;

						af.inf.szFileName[i++] = *ls++;
//						files[ct].inf.szFileName[i++] = *ls++;
					}
					if( prev_is_space )
						--i;
					if( i )
					{
/*
						files[ct].inf.szFileName[i] = '\0';
						files[ct].isfile = true;
						files.forcelen( 1+(++ct) );
*/
						af.inf.szFileName[i] = '\0';
						af.isfile = true;
						files.add(af);
					}
				}
			}
		}
		// バッファシフト
		if( lss != buf )
			ki_memmov( buf, lss, end-lss ), end=buf+(end-lss);
		else if( end==buf+sizeof(buf) )
			end = buf;
	}

	// お終い
	::CloseHandle( pi.hProcess );
	::CloseHandle( rp );
	return true;
}

/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
// バージョン情報リソース取得

bool CArchiver::GetVersionInfoStr( char* name, char* buf, size_t cbBuf )
{
	static bool old = mycnf().oldver();
	if( old )
		return false;

	DWORD dummy = 0;
	DWORD siz = ::GetFileVersionInfoSize( name, &dummy );
	if( siz == 0 )
		return false;

	bool got = false;
	BYTE* vbuf = new BYTE[siz];
	if( 0 != ::GetFileVersionInfo( name, 0, siz, vbuf ) )
	{
		WORD* tr = NULL;
		UINT cbTr = 0;

		// 最初に見つけた言語とコードページで情報取得
		if( ::VerQueryValue( vbuf,
			"\\VarFileInfo\\Translation", (void**)&tr, &cbTr )
		 && cbTr >= 4 )
		{
			char blockname[500]="";
			::wsprintf( blockname,
				"\\StringFileInfo\\%04x%04x\\ProductVersion",
				tr[0], tr[1] );

			char* inf = NULL;
			UINT cbInf = 0;
			if( ::VerQueryValue( vbuf, blockname, (void**)&inf, &cbInf )
			 && cbInf < cbBuf-1 )
			{
				for( char* v=buf; *inf && cbInf; ++inf,--cbInf )
					if( *inf != ' ' )
						*v++ = (*inf==',' ? '.' : *inf);
				*v = '\0';
				got = true;
			}
		}
		else
		{
			void* fi = NULL;
			UINT cbFi = 0;
			VS_FIXEDFILEINFO vffi;
			if( ::VerQueryValue( vbuf, "\\", &fi, &cbFi )
			 && sizeof(vffi)<=cbFi )
			{
				ki_memcpy( &vffi, fi, sizeof(vffi) );
				if( vffi.dwFileVersionLS >= 0x10000 )
					::wsprintf( buf, "%d.%d.%d", vffi.dwFileVersionMS>>16,
						vffi.dwFileVersionMS&0xffff, vffi.dwFileVersionLS>>16 );
				else
					::wsprintf( buf, "%d.%d", vffi.dwFileVersionMS>>16,
						vffi.dwFileVersionMS&0xffff );
				got = true;
			}
		}
	}

	delete [] vbuf;
	return got;
}