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 }