1 /*******************************************************************************
\r
2 TPI - flexible but useless plug-in framework.
\r
3 Copyright (C) 2002-2009 Silky
\r
5 This library is free software; you can redistribute it and/or modify it under
\r
6 the terms of the GNU Lesser General Public License as published by the Free
\r
7 Software Foundation; either version 2.1 of the License, or (at your option)
\r
10 This library is distributed in the hope that it will be useful, but WITHOUT
\r
11 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
\r
12 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
\r
15 You should have received a copy of the GNU Lesser General Public License along
\r
16 with this library; if not, write to the Free Software Foundation, Inc.,
\r
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
\r
20 *******************************************************************************/
\r
22 //******************************************************************************
\r
24 //******************************************************************************
\r
26 #include "../../common/header/plugin.h"
\r
27 #include "../../common/header/plugin-extra.h"
\r
28 #include "../../common/library/library.h"
\r
29 #include <wx/config.h>
\r
30 #include <wx/stdpaths.h>
\r
31 #include <wx/xml/xml.h>
\r
32 #include <wx/tokenzr.h>
\r
34 #include <windows.h>
\r
36 #include "cuiWrapper.h"
\r
38 //******************************************************************************
\r
40 //******************************************************************************
\r
45 wxString szExeFileAlt;
\r
46 wxString szListCommand;
\r
52 wxString g_szCurrentArchive;
\r
53 wxArrayString g_asOutput;
\r
55 //******************************************************************************
\r
57 //******************************************************************************
\r
60 BOOL __stdcall DllMain(HMODULE, DWORD, void *)
\r
66 //******************************************************************************
\r
68 //******************************************************************************
\r
70 int myExecute(wxString szCommandLine, wxString * szOutput, wxString szCwd)
\r
73 wxString sz = ::wxGetCwd();
\r
74 ::wxSetWorkingDirectory(szCwd);
\r
75 FILE * fp = popen(szCommandLine.ToUTF8(), "r");
\r
76 ::wxSetWorkingDirectory(sz);
\r
79 ::wxLogError(L"Error :\n\nCommandLine:\n%s", szCommandLine.c_str());
\r
80 return TPI_ERROR_U_USE_LIBRARY;
\r
83 if (szOutput != NULL)
\r
88 memset(sz, 0, sizeof(sz));
\r
89 fread(sz, sizeof(char), sizeof(sz) - 1, fp);
\r
90 * szOutput += UTF82String(sz);
\r
92 // ::wxMessageBox(* szOutput);
\r
97 SECURITY_ATTRIBUTES sa;
\r
98 memset(& sa, 0, sizeof(SECURITY_ATTRIBUTES));
\r
99 sa.bInheritHandle = TRUE;
\r
100 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
101 HANDLE hRead, hWrite;
\r
102 if (! ::CreatePipe(& hRead, & hWrite, & sa, 0))
\r
104 return TPI_ERROR_U_USE_LIBRARY;
\r
107 memset(& si, 0, sizeof(STARTUPINFO));
\r
108 si.cb = sizeof(STARTUPINFO);
\r
109 si.dwFlags = STARTF_USESTDHANDLES;
\r
110 si.hStdOutput = hWrite;
\r
111 si.hStdError = hWrite;
\r
112 PROCESS_INFORMATION pi;
\r
113 if (! ::CreateProcess(NULL, szCommandLine.wchar_str(), NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, szCwd.IsEmpty() ? NULL : szCwd.wchar_str(), & si, & pi))
\r
115 return TPI_ERROR_U_USE_LIBRARY;
\r
117 ::CloseHandle(pi.hThread);
\r
119 if (szOutput != NULL)
\r
125 if (! ::PeekNamedPipe(hRead, NULL, 0, NULL, & dwSize, NULL))
\r
132 memset(sz, 0, sizeof(sz));
\r
133 ::ReadFile(hRead, & sz, sizeof(sz), & dwSize, NULL);
\r
134 * szOutput += UTF82String(sz);
\r
135 // ::MessageBoxA(NULL, sz, NULL, 0);
\r
137 else if (::WaitForSingleObject(pi.hProcess, 0) == WAIT_OBJECT_0)
\r
144 ::CloseHandle(pi.hProcess);
\r
145 ::CloseHandle(hRead);
\r
146 ::CloseHandle(hWrite);
\r
148 return TPI_ERROR_SUCCESS;
\r
151 PosInfo MakePosInfo(wxString szPrefix)
\r
154 g_LibInfo.node.GetPropVal(wxT("list-") + szPrefix + wxT("-s"), wxEmptyString).ToULong(& pi.nStart);
\r
155 g_LibInfo.node.GetPropVal(wxT("list-") + szPrefix + wxT("-c"), wxEmptyString).ToULong(& pi.nCount);
\r
156 g_LibInfo.node.GetPropVal(wxT("list-") + szPrefix + wxT("-l"), wxT("0")).ToULong(& pi.nLine);
\r
160 wxULongLong GetSize(PosInfo & pi, size_t uCurrent, wxArrayString & as)
\r
162 if (pi.nStart == 0 && pi.nCount == 0)
\r
167 wxULongLong_t nTemp;
\r
168 size_t nPos = uCurrent + pi.nLine;
\r
169 wxString sz = pi.nCount == 0 ? as[nPos].Mid(pi.nStart) : as[nPos].Mid(pi.nStart, pi.nCount);
\r
170 sz.ToULongLong(& nTemp);
\r
174 //******************************************************************************
\r
176 //******************************************************************************
\r
183 int __stdcall GetPluginInformation
\r
185 unsigned int _uInfoId,
\r
192 return TPI_ERROR_D_PARAMETER;
\r
196 case TPI_INFO_VERSION_MAJOR:
\r
197 case TPI_INFO_VERSION_MINOR:
\r
198 * (int *) _pPtr = 0;
\r
200 case TPI_INFO_VERSION_API:
\r
201 * (int *) _pPtr = 2;
\r
204 return TPI_ERROR_D_UNSUPPORTED;
\r
206 return TPI_ERROR_SUCCESS;
\r
209 int __stdcall GetFormatInformation(TPI_FORMATINFO * _fiInfo, bool _bFirst)
\r
211 static unsigned int s_uFileId;
\r
213 wxXmlDocument config(wxPathOnly(p.GetExecutablePath()) + wxT("/lib/cuiWrapper.xml"));
\r
214 // 一気に先頭のライブラリの情報を取得。
\r
215 wxXmlNode * xmlLibrary = config.GetRoot()->GetChildren();
\r
224 for (unsigned int i = 0; i < s_uFileId && xmlLibrary != NULL; i++)
\r
226 xmlLibrary = xmlLibrary->GetNext();
\r
230 if (xmlLibrary == NULL || xmlLibrary->GetName() != wxT("library"))
\r
233 return TPI_ERROR_S_ENDOFDATA;
\r
236 MakeFormatInfo(wxT("cuiWrapper"), _fiInfo, xmlLibrary, s_uFileId++);
\r
237 if (myExecute(xmlLibrary->GetPropVal(wxT("name"), wxEmptyString), NULL, wxEmptyString) != TPI_ERROR_SUCCESS)
\r
239 _fiInfo->llSupportedCommand = 0;
\r
242 return TPI_ERROR_SUCCESS;
\r
245 int __stdcall LoadPlugin
\r
247 const wxString & _szArcName,
\r
248 wxULongLong _llTypeId
\r
253 wxXmlDocument config(wxPathOnly(p.GetExecutablePath()) + wxT("/lib/cuiWrapper.xml"));
\r
254 if (! config.IsOk())
\r
256 return TPI_ERROR_UNDEFINED;
\r
258 // 一気に先頭のライブラリの情報を取得。
\r
259 wxXmlNode * xmlLibrary = config.GetRoot()->GetChildren();
\r
261 // 対象が存在するならば対応するライブラリを調査、
\r
262 // 対象が存在しないならば指示されたライブラリをロード。
\r
263 if (! ::wxFileExists(_szArcName))
\r
266 for (g_LibInfo.nLibIndex = 0; g_LibInfo.nLibIndex < _llTypeId && xmlLibrary != NULL; g_LibInfo.nLibIndex++)
\r
268 xmlLibrary = xmlLibrary->GetNext();
\r
270 if (xmlLibrary == NULL || xmlLibrary->GetName() != wxT("library"))
\r
273 return TPI_ERROR_UNDEFINED;
\r
275 g_LibInfo.szExeFile = xmlLibrary->GetPropVal(wxT("name"), wxEmptyString);
\r
276 g_LibInfo.szExeFileAlt = xmlLibrary->GetPropVal(wxT("name-alt"), wxEmptyString);
\r
277 g_LibInfo.node = * xmlLibrary;
\r
279 return TPI_ERROR_SUCCESS;
\r
282 // 無限ループに陥らないよう上限を設定。
\r
283 for (g_LibInfo.nLibIndex = 0; g_LibInfo.nLibIndex < 300 && xmlLibrary != NULL; g_LibInfo.nLibIndex++)
\r
286 g_LibInfo.szExeFile = xmlLibrary->GetPropVal(wxT("name"), wxEmptyString);
\r
287 g_LibInfo.szExeFileAlt = xmlLibrary->GetPropVal(wxT("name-alt"), wxEmptyString);
\r
288 g_LibInfo.node = * xmlLibrary;
\r
291 if (CheckArchive(_szArcName, NULL) == TPI_ERROR_SUCCESS)
\r
294 return TPI_ERROR_SUCCESS;
\r
297 xmlLibrary = xmlLibrary->GetNext();
\r
300 return TPI_ERROR_U_LOAD_LIBRARY;
\r
303 int __stdcall FreePlugin
\r
305 void * // _pReserved
\r
308 return TPI_ERROR_SUCCESS;
\r
311 int __stdcall CheckArchive
\r
313 const wxString & _szArcName,
\r
314 wxULongLong * _llFileCount
\r
317 wxFileName fnArchive(_szArcName);
\r
318 wxArrayString asExt = ::wxStringTokenize(g_LibInfo.node.GetPropVal(wxT("suffix"), wxEmptyString), wxT(";"));
\r
319 if (! g_LibInfo.node.HasProp(wxT("list")))
\r
321 return TPI_ERROR_ARC_UNSUPPORTED;
\r
324 for (size_t i = 0; i < asExt.GetCount(); i++)
\r
326 // .tar.XXXなど二重判定への対応。
\r
327 // if (asExt[i].IsSameAs(fnArchive.GetExt(), false))
\r
328 if (fnArchive.GetFullName().EndsWith(wxT('.') + asExt[i]))
\r
330 // 開いて確認。先行してデータを取得しておく。
\r
331 int nErrorCode = OpenArchive(_szArcName, NULL);
\r
334 if (_llFileCount != NULL)
\r
337 * _llFileCount = g_asOutput.GetCount();
\r
343 return TPI_ERROR_ARC_UNSUPPORTED;
\r
346 int __stdcall OpenArchive
\r
348 const wxString & _szArcName,
\r
352 if (g_szCurrentArchive != _szArcName)
\r
355 if (myExecute(g_LibInfo.szExeFile + wxT(" ") + MakeCommandLineSend(g_LibInfo.node.GetPropVal(wxT("list"), wxEmptyString), _szArcName, NULL, NULL, wxEmptyString), & szOutput, wxEmptyString) != TPI_ERROR_SUCCESS)
\r
357 return TPI_ERROR_U_USE_LIBRARY;
\r
359 g_szCurrentArchive = _szArcName;
\r
360 g_asOutput = ::wxStringTokenize(szOutput, wxT("\r\n"));
\r
361 g_asOutput.Shrink();
\r
363 if (_hArchive != NULL)
\r
365 * _hArchive = & g_asOutput;
\r
367 return g_asOutput.IsEmpty() ? TPI_ERROR_UNDEFINED : TPI_ERROR_SUCCESS;
\r
370 int __stdcall CloseArchive
\r
375 ((wxArrayString *) _hArchive)->Clear();
\r
376 return TPI_ERROR_SUCCESS;
\r
379 int __stdcall GetFileInformation
\r
382 TPI_FILEINFO * _fiInfo,
\r
386 static size_t s_uCurrentLine;
\r
387 static wxULongLong s_llFileId;
\r
388 if (_hArchive == NULL)
\r
390 return TPI_ERROR_UNDEFINED;
\r
392 wxArrayString asOutput = * (wxArrayString *) _hArchive;
\r
394 // XMLからの読み込みは初回に行う。
\r
395 static wxString szEndLine, szDateFormat;
\r
396 static unsigned long nProcessPerLine;
\r
397 static PosInfo piFName, piPSize, piUSize, piDate;
\r
401 wxString szStartLine = g_LibInfo.node.GetPropVal(wxT("list-line-s"), wxEmptyString);
\r
402 if (! szStartLine.IsEmpty())
\r
405 s_uCurrentLine = asOutput.Index(szStartLine) + 1;
\r
406 if (s_uCurrentLine == wxNOT_FOUND + 1)
\r
409 return TPI_ERROR_ARC_UNSUPPORTED;
\r
414 g_LibInfo.node.GetPropVal(wxT("list-line-c"), wxT("1")).ToULong(& nProcessPerLine);
\r
415 szEndLine = g_LibInfo.node.GetPropVal(wxT("list-line-e"), szStartLine);
\r
416 szDateFormat = g_LibInfo.node.GetPropVal(wxT("list-date-f"), wxDefaultDateTimeFormat);
\r
417 piFName = MakePosInfo(wxT("fname"));
\r
418 piPSize = MakePosInfo(wxT("psize"));
\r
419 piUSize = MakePosInfo(wxT("usize"));
\r
420 piDate = MakePosInfo(wxT("date"));
\r
423 if (s_uCurrentLine >= asOutput.GetCount())
\r
426 return TPI_ERROR_ARC_UNSUPPORTED;
\r
430 if (asOutput[s_uCurrentLine] == szEndLine)
\r
432 return TPI_ERROR_S_ENDOFDATA;
\r
436 _fiInfo->szStoredName = piFName.nCount == 0 ? asOutput[s_uCurrentLine + piFName.nLine].Mid(piFName.nStart) : asOutput[s_uCurrentLine + piFName.nLine].Mid(piFName.nStart, piFName.nCount);
\r
437 _fiInfo->szStoredName.Trim();
\r
438 _fiInfo->fnFileName = wxFileName::wxFileName(_fiInfo->szStoredName);
\r
441 _fiInfo->llPackedSize = GetSize(piPSize, s_uCurrentLine, asOutput);
\r
442 _fiInfo->llUnpackedSize = GetSize(piUSize, s_uCurrentLine, asOutput);
\r
445 if (piDate.nStart != 0 || piDate.nCount != 0)
\r
447 _fiInfo->tmModified.ParseFormat(piDate.nCount == 0 ? asOutput[s_uCurrentLine + piDate.nLine].Mid(piDate.nStart) : asOutput[s_uCurrentLine + piDate.nLine].Mid(piDate.nStart, piDate.nCount), szDateFormat);
\r
451 _fiInfo->llFileId = s_llFileId++;
\r
452 s_uCurrentLine += nProcessPerLine;
\r
454 return TPI_ERROR_SUCCESS;
\r
457 int __stdcall GetArchiveInformation
\r
460 TPI_ARCHIVEINFO * _aiInfo
\r
464 MakeFormatInfo(wxT("cuiWrapper"), & _aiInfo->fiInfo, & g_LibInfo.node, 0);
\r
465 return TPI_ERROR_SUCCESS;
\r
468 int __stdcall Command
\r
470 unsigned int _uCommand,
\r
471 TPI_SWITCHES * _swInfo,
\r
472 const wxString & _szArcName,
\r
473 const wxArrayString & _szFiles
\r
476 // xmlからコマンドラインを取得。
\r
477 wxString szPath, szCommandLine;
\r
480 if (! g_LibInfo.node.GetPropVal(
\r
481 _uCommand == TPI_COMMAND_ADD ? wxT("add") :
\r
482 _uCommand == TPI_COMMAND_EXTRACT ? wxT("extract") :
\r
483 _uCommand == TPI_COMMAND_DELETE ? wxT("delete") :
\r
484 _uCommand == TPI_COMMAND_UPDATE ? wxT("update") :
\r
485 _uCommand == TPI_COMMAND_TEST ? wxT("test") :
\r
486 _uCommand == TPI_COMMAND_REPAIR ? wxT("repair") :
\r
487 _uCommand == TPI_COMMAND_MOVE ? wxT("move") :
\r
488 _uCommand == TPI_COMMAND_SFX ? wxT("sfx") :
\r
489 _uCommand == TPI_COMMAND_UNSFX ? wxT("unsfx") : wxEmptyString, & szCommandLine))
\r
491 g_LibInfo.node.GetPropVal(
\r
492 _uCommand == TPI_COMMAND_ADD ? wxT("add-alt") :
\r
493 _uCommand == TPI_COMMAND_EXTRACT ? wxT("extract-alt") :
\r
494 _uCommand == TPI_COMMAND_DELETE ? wxT("delete-alt") :
\r
495 _uCommand == TPI_COMMAND_UPDATE ? wxT("update-alt") :
\r
496 _uCommand == TPI_COMMAND_TEST ? wxT("test-alt") :
\r
497 _uCommand == TPI_COMMAND_REPAIR ? wxT("repair-alt") :
\r
498 _uCommand == TPI_COMMAND_MOVE ? wxT("move-alt") :
\r
499 _uCommand == TPI_COMMAND_SFX ? wxT("sfx-alt") :
\r
500 _uCommand == TPI_COMMAND_UNSFX ? wxT("unsfx-alt") : wxEmptyString, & szCommandLine);
\r
503 if (szCommandLine.IsEmpty())
\r
505 return TPI_ERROR_U_USE_LIBRARY;
\r
508 // コマンドライン・レスポンスファイル作成。
\r
510 szResponceFileName = MakeResponceFile(_szFiles, g_LibInfo.node.GetPropVal(wxT("quote-resp"), wxT("1")) == wxT("1")),
\r
511 szCommandLineSend = MakeCommandLineSend(szCommandLine, _szArcName, _swInfo, _szFiles, szResponceFileName);
\r
515 int nErrorCode = myExecute(g_LibInfo.szExeFile + wxT(" ") + szCommandLineSend, & szOutput, _swInfo->fnDestinationDirectory.GetFullPath());
\r
518 ::wxRemoveFile(szResponceFileName);
\r
520 if (nErrorCode != TPI_ERROR_SUCCESS)
\r
522 ::wxLogError(L"Error :\n%x\n\nCommandLine:\n%s\n\nOutput:\n%s", nErrorCode, szCommandLineSend.c_str(), szOutput.c_str());
\r
527 int __stdcall SetCallbackProc
\r
529 TPI_PROC _prArcProc
\r
533 if (_prArcProc == NULL)
\r
535 return TPI_ERROR_D_PARAMETER;
\r
537 g_prProc = * _prArcProc;
\r
539 return TPI_ERROR_SUCCESS;
\r