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 "../../common/library/xmldoc.h"
\r
30 #include <wx/tokenzr.h>
\r
31 #include <wx/process.h>
\r
32 #include <wx/txtstrm.h>
\r
33 #include "cuiWrapper.h"
\r
35 //******************************************************************************
\r
37 //******************************************************************************
\r
42 wxString szExeFileAlt;
\r
43 wxString szListCommand;
\r
44 wxULongLong_t nLibIndex;
\r
50 //******************************************************************************
\r
52 //******************************************************************************
\r
54 int myExecute(const wxString & szCommandLine, bool fWine)
\r
57 FILE * fp = popen(fWine ? (wxT("wine ") + szCommandLine).ToUTF8() : szCommandLine.ToUTF8(), "r");
\r
60 wxLogError(L"Error :\n\nCommandLine:\n%s", szCommandLine.c_str());
\r
61 return TPI_ERROR_U_USE_LIBRARY;
\r
64 // 127を返した場合はコマンドが存在しない。
\r
65 int nErrorCode = pclose(fp);
\r
66 return (WIFEXITED(nErrorCode) && WEXITSTATUS(nErrorCode) != 127) ? TPI_ERROR_SUCCESS : TPI_ERROR_U_USE_LIBRARY;
\r
69 PROCESS_INFORMATION pi;
\r
70 memset(& si, 0, sizeof(STARTUPINFO));
\r
71 si.cb = sizeof(STARTUPINFO);
\r
72 if (! ::CreateProcess(NULL, szCommandLine.wchar_str(), NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, & si, & pi))
\r
74 return TPI_ERROR_U_USE_LIBRARY;
\r
76 ::CloseHandle(pi.hThread);
\r
77 ::CloseHandle(pi.hProcess);
\r
78 return TPI_ERROR_SUCCESS;
\r
82 PosInfo MakePosInfo(const wxString & szPrefix)
\r
85 pi.nStart = myGetAttributeInt(& g_LibInfo.node, wxT("list-") + szPrefix + wxT("-s"));
\r
86 pi.nCount = myGetAttributeInt(& g_LibInfo.node, wxT("list-") + szPrefix + wxT("-c"));
\r
87 pi.nLine = myGetAttributeInt(& g_LibInfo.node, wxT("list-") + szPrefix + wxT("-l"));
\r
91 wxULongLong_t GetSize(const PosInfo & pi, const wxArrayString & as)
\r
93 if (pi.nStart == 0 && pi.nCount == 0)
\r
98 wxULongLong_t nTemp = 0;
\r
101 as[pi.nLine].Mid(pi.nStart) :
\r
102 as[pi.nLine].Mid(pi.nStart, pi.nCount);
\r
103 sz.ToULongLong(& nTemp);
\r
107 //******************************************************************************
\r
109 //******************************************************************************
\r
116 int __stdcall GetPluginInformation
\r
118 unsigned int _uInfoId,
\r
125 return TPI_ERROR_D_PARAMETER;
\r
129 case TPI_INFO_VERSION_MAJOR:
\r
130 case TPI_INFO_VERSION_MINOR:
\r
131 * (int *) _pPtr = 0;
\r
133 case TPI_INFO_VERSION_API:
\r
134 * (int *) _pPtr = 2;
\r
137 return TPI_ERROR_D_UNSUPPORTED;
\r
139 return TPI_ERROR_SUCCESS;
\r
142 int __stdcall GetFormatInformation(TPI_FORMATINFO * _fiInfo, bool _bFirst)
\r
144 static wxULongLong_t s_nFileId;
\r
145 static wxXmlDocument xmlDoc(myMakeXMLName(wxT("cuiWrapper")));
\r
146 static wxXmlNode * xmlLibrary;
\r
151 xmlLibrary = myGetFirstLib(& xmlDoc);
\r
155 xmlLibrary = myGetNextLib(xmlLibrary);
\r
157 if (xmlLibrary == NULL)
\r
160 return TPI_ERROR_S_ENDOFDATA;
\r
163 MakeFormatInfo(xmlLibrary, wxT("cuiWrapper"), _fiInfo, s_nFileId++);
\r
164 wxString szExeFile = xmlLibrary->GetAttribute(wxT("name"), wxEmptyString);
\r
165 if (myExecute(szExeFile, szExeFile.EndsWith(wxT(".exe"))) != TPI_ERROR_SUCCESS)
\r
167 _fiInfo->eSupportedCommand = 0;
\r
169 return TPI_ERROR_SUCCESS;
\r
172 int __stdcall LoadPlugin
\r
174 const wxString & _szArcName,
\r
176 wxULongLong_t _nTypeId
\r
180 wxXmlDocument xmlDoc(myMakeXMLName(wxT("cuiWrapper")));
\r
181 wxXmlNode * xmlLibrary;
\r
184 if (_prProc != NULL)
\r
186 g_prProc = * _prProc;
\r
189 // 対象が存在するならば対応するライブラリを調査、
\r
190 // 対象が存在しないならば指示されたライブラリをロード。
\r
191 if (! ::wxFileExists(_szArcName))
\r
193 xmlLibrary = myGetFirstLib(& xmlDoc, _nTypeId);
\r
194 if (xmlLibrary == NULL)
\r
197 return TPI_ERROR_UNDEFINED;
\r
199 g_LibInfo.szExeFile = xmlLibrary->GetAttribute(wxT("name"), wxEmptyString);
\r
200 g_LibInfo.szExeFileAlt = xmlLibrary->GetAttribute(wxT("name-alt"), wxEmptyString);
\r
201 g_LibInfo.node = * xmlLibrary;
\r
202 g_LibInfo.nLibIndex = _nTypeId;
\r
203 return TPI_ERROR_SUCCESS;
\r
206 // 無限ループに陥らないよう上限を設定。
\r
207 xmlLibrary = myGetFirstLib(& xmlDoc);
\r
208 for (g_LibInfo.nLibIndex = 0; g_LibInfo.nLibIndex < 300 && xmlLibrary != NULL; g_LibInfo.nLibIndex++)
\r
211 wxFileName fnArchive(_szArcName);
\r
212 wxArrayString asExt = ::wxStringTokenize(xmlLibrary->GetAttribute(wxT("suffix"), wxEmptyString), wxT(";"));
\r
213 if (xmlLibrary->HasAttribute(wxT("list")))
\r
215 for (size_t i = 0; i < asExt.GetCount(); i++)
\r
217 // .tar.XXXなど二重判定への対応。
\r
218 // if (asExt[i].IsSameAs(fnArchive.GetExt(), false))
\r
219 if (fnArchive.GetFullName().EndsWith(wxT('.') + asExt[i]))
\r
222 g_LibInfo.szExeFile = xmlLibrary->GetAttribute(wxT("name"), wxEmptyString);
\r
223 g_LibInfo.szExeFileAlt = xmlLibrary->GetAttribute(wxT("name-alt"), wxEmptyString);
\r
224 g_LibInfo.node = * xmlLibrary;
\r
225 g_LibInfo.nLibIndex = _nTypeId;
\r
226 return TPI_ERROR_SUCCESS;
\r
230 xmlLibrary = myGetNextLib(xmlLibrary);
\r
232 return TPI_ERROR_U_LOAD_LIBRARY;
\r
235 int __stdcall FreePlugin
\r
237 void * // _pReserved
\r
240 return TPI_ERROR_SUCCESS;
\r
243 int __stdcall OpenArchive
\r
245 const wxString & _szArcName,
\r
246 void * * _hArchive,
\r
250 wxString szCommandLine = g_LibInfo.szExeFile + wxT(" ") + MakeCommandLineSend(g_LibInfo.node.GetAttribute(wxT("list"), wxEmptyString), _szArcName);
\r
252 wxProcess * p = ::wxProcess::Open(g_LibInfo.szExeFile.EndsWith(wxT(".exe")) ? (wxT("wine ") + szCommandLine) : szCommandLine, wxEXEC_ASYNC);
\r
254 wxProcess * p = ::wxProcess::Open(szCommandLine, wxEXEC_ASYNC);
\r
258 wxLogError(L"Error :\n\nCommandLine:\n%s", szCommandLine.c_str());
\r
259 return TPI_ERROR_U_USE_LIBRARY;
\r
263 wxInputStream * is = p->GetInputStream();
\r
264 wxTextInputStream tis(* is);
\r
265 wxString szStartLine = g_LibInfo.node.GetAttribute(wxT("list-line-s"), wxEmptyString);
\r
266 if (! szStartLine.IsEmpty())
\r
269 while (! is->Eof() && tis.ReadLine() != szStartLine);
\r
273 ::wxSafeShowMessage(wxEmptyString, wxT("Unsupported archive!"));
\r
275 return TPI_ERROR_ARC_UNSUPPORTED;
\r
279 * _hArchive = (void *) is;
\r
280 return is->Eof() ? TPI_ERROR_UNDEFINED : TPI_ERROR_SUCCESS;
\r
283 int __stdcall CloseArchive
\r
288 return TPI_ERROR_SUCCESS;
\r
291 int __stdcall GetFileInformation
\r
294 TPI_FILEINFO * _fiInfo,
\r
298 static size_t s_nCurrentLine;
\r
299 static wxULongLong_t s_nFileId;
\r
300 if (_hArchive == NULL)
\r
302 return TPI_ERROR_UNDEFINED;
\r
304 wxInputStream * is = (wxInputStream *) _hArchive;
\r
305 wxTextInputStream tis(* is);
\r
307 // XMLからの読み込みは初回に行う。
\r
308 static wxString szEndLine, szDateFormat;
\r
309 static wxULongLong_t nProcessPerLine;
\r
310 static PosInfo piFName, piPSize, piUSize, piDate;
\r
315 nProcessPerLine = myGetAttributeInt(& g_LibInfo.node, wxT("list-line-c"), 1);
\r
316 szEndLine = g_LibInfo.node.GetAttribute(wxT("list-line-e"), g_LibInfo.node.GetAttribute(wxT("list-line-s"), wxEmptyString));
\r
317 szDateFormat = g_LibInfo.node.GetAttribute(wxT("list-date-f"), wxDefaultDateTimeFormat);
\r
318 piFName = MakePosInfo(wxT("fname"));
\r
319 piPSize = MakePosInfo(wxT("psize"));
\r
320 piUSize = MakePosInfo(wxT("usize"));
\r
321 piDate = MakePosInfo(wxT("date"));
\r
326 // 空行で終わるとき以外はエラーとする。
\r
327 return szEndLine.IsEmpty() ? TPI_ERROR_S_ENDOFDATA : TPI_ERROR_ARC_UNSUPPORTED;
\r
332 as.Add(tis.ReadLine());
\r
333 if (as[0] == szEndLine)
\r
335 return TPI_ERROR_S_ENDOFDATA;
\r
337 for (int i = 1; i < nProcessPerLine; i++)
\r
339 as.Add(tis.ReadLine());
\r
343 _fiInfo->szStoredName =
\r
344 piFName.nCount == 0 ?
\r
345 as[piFName.nLine].Mid(piFName.nStart) :
\r
346 as[piFName.nLine].Mid(piFName.nStart, piFName.nCount);
\r
347 _fiInfo->szStoredName.Trim();
\r
348 _fiInfo->fnFileName = wxFileName(_fiInfo->szStoredName, wxPATH_DOS);
\r
351 _fiInfo->nPackedSize = GetSize(piPSize, as);
\r
352 _fiInfo->nUnpackedSize = GetSize(piUSize, as);
\r
355 if (piDate.nStart != 0 || piDate.nCount != 0)
\r
357 _fiInfo->tmModify.ParseFormat(
\r
358 piDate.nCount == 0 ?
\r
359 as[piDate.nLine].Mid(piDate.nStart) :
\r
360 as[piDate.nLine].Mid(piDate.nStart, piDate.nCount),
\r
366 _fiInfo->nFileId = s_nFileId++;
\r
367 return TPI_ERROR_SUCCESS;
\r
370 int __stdcall GetArchiveInformation
\r
373 TPI_ARCHIVEINFO * _aiInfo
\r
377 MakeFormatInfo(& g_LibInfo.node, wxT("cuiWrapper"), & _aiInfo->fiInfo, 0);
\r
378 return TPI_ERROR_SUCCESS;
\r
381 int __stdcall Command
\r
383 wxULongLong_t _eCommand,
\r
384 TPI_SWITCHES * _swInfo,
\r
385 const wxString & _szArcName,
\r
386 const wxArrayString & _szFiles
\r
389 // xmlからコマンドラインを取得。
\r
390 wxString szPath, szCommandLine;
\r
393 if (! g_LibInfo.node.GetAttribute(
\r
394 _eCommand == TPI_COMMAND_CREATE ? wxT("create") :
\r
395 _eCommand == TPI_COMMAND_ADD ? wxT("add") :
\r
396 _eCommand == TPI_COMMAND_EXTRACT ? wxT("extract") :
\r
397 _eCommand == TPI_COMMAND_DELETE ? wxT("delete") :
\r
398 _eCommand == TPI_COMMAND_UPDATE ? wxT("update") :
\r
399 _eCommand == TPI_COMMAND_TEST ? wxT("test") :
\r
400 _eCommand == TPI_COMMAND_REPAIR ? wxT("repair") :
\r
401 _eCommand == TPI_COMMAND_MOVE ? wxT("move") :
\r
402 _eCommand == TPI_COMMAND_SFX ? wxT("sfx") :
\r
403 _eCommand == TPI_COMMAND_UNSFX ? wxT("unsfx") : wxEmptyString, & szCommandLine))
\r
405 g_LibInfo.node.GetAttribute(
\r
406 _eCommand == TPI_COMMAND_CREATE ? wxT("create-alt") :
\r
407 _eCommand == TPI_COMMAND_ADD ? wxT("add-alt") :
\r
408 _eCommand == TPI_COMMAND_EXTRACT ? wxT("extract-alt") :
\r
409 _eCommand == TPI_COMMAND_DELETE ? wxT("delete-alt") :
\r
410 _eCommand == TPI_COMMAND_UPDATE ? wxT("update-alt") :
\r
411 _eCommand == TPI_COMMAND_TEST ? wxT("test-alt") :
\r
412 _eCommand == TPI_COMMAND_REPAIR ? wxT("repair-alt") :
\r
413 _eCommand == TPI_COMMAND_MOVE ? wxT("move-alt") :
\r
414 _eCommand == TPI_COMMAND_SFX ? wxT("sfx-alt") :
\r
415 _eCommand == TPI_COMMAND_UNSFX ? wxT("unsfx-alt") : wxEmptyString, & szCommandLine);
\r
418 if (szCommandLine.IsEmpty())
\r
420 return TPI_ERROR_U_USE_LIBRARY;
\r
423 // コマンドライン・レスポンスファイル作成。
\r
425 szResponceFileName = MakeResponceFile(_szFiles, myGetAttributeBool(& g_LibInfo.node, wxT("quote-resp"), true)),
\r
426 szCommandLineSend = g_LibInfo.szExeFile + wxT(" ") + MakeCommandLineSend(szCommandLine, _szArcName, _swInfo, _szFiles, szResponceFileName),
\r
430 ::wxSetWorkingDirectory(_swInfo->fnDestinationDirectory.GetFullPath());
\r
432 wxProcess * p = ::wxProcess::Open(g_LibInfo.szExeFile.EndsWith(wxT(".exe")) ? (wxT("wine ") + szCommandLineSend) : szCommandLineSend, wxEXEC_ASYNC);
\r
434 wxProcess * p = ::wxProcess::Open(szCommandLineSend, wxEXEC_ASYNC);
\r
436 ::wxSetWorkingDirectory(sz);
\r
439 ::wxRemoveFile(szResponceFileName);
\r
440 wxLogError(L"CommandLine:\n%s", szCommandLineSend.c_str());
\r
441 return TPI_ERROR_U_USE_LIBRARY;
\r
444 TPI_PROCESSINFO piInfo;
\r
445 piInfo.eMessage = TPI_MESSAGE_STATUS;
\r
446 piInfo.eStatus = TPI_STATUS_INPROCESS;
\r
447 piInfo.nProcessedSize = 0;
\r
451 wxInputStream * is = p->GetInputStream();
\r
452 while (! is->Eof())
\r
455 if (g_prProc != NULL && g_prProc(TPI_NOTIFY_COMMON, & piInfo) == TPI_CALLBACK_CANCEL)
\r
457 p->Kill(p->GetPid(), wxSIGKILL);
\r
459 ::wxRemoveFile(szResponceFileName);
\r
460 return TPI_ERROR_D_SKIPPED;
\r
463 if (! is->CanRead())
\r
469 is->Read(sz, sizeof(sz));
\r
470 szOutput += UTF82String(sz);
\r
472 // ::wxMessageBox(szOutput);
\r
475 ::wxRemoveFile(szResponceFileName);
\r
476 return TPI_ERROR_SUCCESS;
\r