OSDN Git Service

SetCallbackProcをLoadLibraryに統合。
[tpi/lychee.git] / src / plugin / cuiWrapper / cuiWrapper.cpp
1 /*******************************************************************************\r
2   TPI - flexible but useless plug-in framework.\r
3   Copyright (C) 2002-2009 Silky\r
4 \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
8   any later version.\r
9 \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
13   for more details.\r
14 \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
18 \r
19   $Id$\r
20 *******************************************************************************/\r
21 \r
22 //******************************************************************************\r
23 //    Includes\r
24 //******************************************************************************\r
25 \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
34 \r
35 //******************************************************************************\r
36 //    Global varients\r
37 //******************************************************************************\r
38 \r
39 struct g_LibInfo\r
40 {\r
41         wxString szExeFile;\r
42         wxString szExeFileAlt;\r
43         wxString szListCommand;\r
44         wxULongLong_t nLibIndex;\r
45         wxXmlNode node;\r
46 }       g_LibInfo;\r
47 \r
48 TPI_PROC g_prProc;\r
49 \r
50 //******************************************************************************\r
51 //    Inside Functions\r
52 //******************************************************************************\r
53 \r
54 int myExecute(const wxString & szCommandLine, bool fWine)\r
55 {\r
56 #ifdef __LINUX__\r
57         FILE * fp = popen(fWine ? (wxT("wine ") + szCommandLine).ToUTF8() : szCommandLine.ToUTF8(), "r");\r
58         if (fp == NULL)\r
59         {\r
60                 wxLogError(L"Error :\n\nCommandLine:\n%s", szCommandLine.c_str());\r
61                 return TPI_ERROR_U_USE_LIBRARY;\r
62         }\r
63 \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
67 #else\r
68         STARTUPINFO si;\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
73         {\r
74                 return TPI_ERROR_U_USE_LIBRARY;\r
75         }\r
76         ::CloseHandle(pi.hThread);\r
77         ::CloseHandle(pi.hProcess);\r
78         return TPI_ERROR_SUCCESS;\r
79 #endif\r
80 }\r
81 \r
82 PosInfo MakePosInfo(const wxString & szPrefix)\r
83 {\r
84         PosInfo pi;\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
88         return pi;\r
89 }\r
90 \r
91 wxULongLong_t GetSize(const PosInfo & pi, const wxArrayString & as)\r
92 {\r
93         if (pi.nStart == 0 && pi.nCount == 0)\r
94         {\r
95                 return 0;\r
96         }\r
97 \r
98         wxULongLong_t nTemp = 0;\r
99         wxString sz =\r
100                 pi.nCount == 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
104         return nTemp;\r
105 }\r
106 \r
107 //******************************************************************************\r
108 //    Functions\r
109 //******************************************************************************\r
110 \r
111 #ifdef __cplusplus\r
112 extern "C"\r
113 {\r
114 #endif\r
115 \r
116 int __stdcall GetPluginInformation\r
117 (\r
118         unsigned int _uInfoId,\r
119         wxULongLong_t,\r
120         void * _pPtr\r
121 )\r
122 {\r
123         if (_pPtr == NULL)\r
124         {\r
125                 return TPI_ERROR_D_PARAMETER;\r
126         }\r
127         switch (_uInfoId)\r
128         {\r
129         case TPI_INFO_VERSION_MAJOR:\r
130         case TPI_INFO_VERSION_MINOR:\r
131                 * (int *) _pPtr = 0;\r
132                 break;\r
133         case TPI_INFO_VERSION_API:\r
134                 * (int *) _pPtr = 2;\r
135                 break;\r
136         default:\r
137                 return TPI_ERROR_D_UNSUPPORTED;\r
138         }\r
139         return TPI_ERROR_SUCCESS;\r
140 }\r
141 \r
142 int __stdcall GetFormatInformation(TPI_FORMATINFO * _fiInfo, bool _bFirst)\r
143 {\r
144         static wxULongLong_t s_nFileId;\r
145         static wxXmlDocument xmlDoc(myMakeXMLName(wxT("cuiWrapper")));\r
146         static wxXmlNode * xmlLibrary;\r
147         if (_bFirst)\r
148         {\r
149                 // xml解析開始。\r
150                 s_nFileId = 0;\r
151                 xmlLibrary = myGetFirstLib(& xmlDoc);\r
152         }\r
153         else\r
154         {\r
155                 xmlLibrary = myGetNextLib(xmlLibrary);\r
156         }\r
157         if (xmlLibrary == NULL)\r
158         {\r
159                 // データの終端に達した場合。\r
160                 return TPI_ERROR_S_ENDOFDATA;\r
161         }\r
162 \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
166         {\r
167                 _fiInfo->eSupportedCommand = 0;\r
168         }\r
169         return TPI_ERROR_SUCCESS;\r
170 }\r
171 \r
172 int __stdcall LoadPlugin\r
173 (\r
174         const wxString & _szArcName,\r
175         TPI_PROC _prProc,\r
176         wxULongLong_t _nTypeId\r
177 )\r
178 {\r
179         // xml解析開始。\r
180         wxXmlDocument xmlDoc(myMakeXMLName(wxT("cuiWrapper")));\r
181         wxXmlNode * xmlLibrary;\r
182 \r
183         // コールバック関数を設定。\r
184         if (_prProc != NULL)\r
185         {\r
186                 g_prProc = * _prProc;\r
187         }\r
188 \r
189         // 対象が存在するならば対応するライブラリを調査、\r
190         // 対象が存在しないならば指示されたライブラリをロード。\r
191         if (! ::wxFileExists(_szArcName))\r
192         {\r
193                 xmlLibrary = myGetFirstLib(& xmlDoc, _nTypeId);\r
194                 if (xmlLibrary == NULL)\r
195                 {\r
196                         // xml文法エラー。\r
197                         return TPI_ERROR_UNDEFINED;\r
198                 }\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
204         }\r
205 \r
206         // 無限ループに陥らないよう上限を設定。\r
207         xmlLibrary = myGetFirstLib(& xmlDoc);\r
208         for (g_LibInfo.nLibIndex = 0; g_LibInfo.nLibIndex < 300 && xmlLibrary != NULL; g_LibInfo.nLibIndex++)\r
209         {\r
210                 // 書庫に対応しているかチェック。\r
211                 wxFileName fnArchive(_szArcName);\r
212                 wxArrayString asExt = ::wxStringTokenize(xmlLibrary->GetAttribute(wxT("suffix"), wxEmptyString), wxT(";"));\r
213                 if (xmlLibrary->HasAttribute(wxT("list")))\r
214                 {\r
215                         for (size_t i = 0; i < asExt.GetCount(); i++)\r
216                         {\r
217                                 // .tar.XXXなど二重判定への対応。\r
218 //                              if (asExt[i].IsSameAs(fnArchive.GetExt(), false))\r
219                                 if (fnArchive.GetFullName().EndsWith(wxT('.') + asExt[i]))\r
220                                 {\r
221                                         // ライブラリをロード。\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
227                                 }\r
228                         }\r
229                 }\r
230                 xmlLibrary = myGetNextLib(xmlLibrary);\r
231         }\r
232         return TPI_ERROR_U_LOAD_LIBRARY;\r
233 }\r
234 \r
235 int __stdcall FreePlugin\r
236 (\r
237         void * // _pReserved\r
238 )\r
239 {\r
240         return TPI_ERROR_SUCCESS;\r
241 }\r
242 \r
243 int __stdcall OpenArchive\r
244 (\r
245         const wxString & _szArcName,\r
246         void * * _hArchive,\r
247         wxULongLong_t *\r
248 )\r
249 {\r
250         wxString szCommandLine = g_LibInfo.szExeFile + wxT(" ") + MakeCommandLineSend(g_LibInfo.node.GetAttribute(wxT("list"), wxEmptyString), _szArcName);\r
251 #ifdef __LINUX__\r
252         wxProcess * p = ::wxProcess::Open(g_LibInfo.szExeFile.EndsWith(wxT(".exe")) ? (wxT("wine ") + szCommandLine) : szCommandLine, wxEXEC_ASYNC);\r
253 #else\r
254         wxProcess * p = ::wxProcess::Open(szCommandLine, wxEXEC_ASYNC);\r
255 #endif\r
256         if (p == NULL)\r
257         {\r
258                 wxLogError(L"Error :\n\nCommandLine:\n%s", szCommandLine.c_str());\r
259                 return TPI_ERROR_U_USE_LIBRARY;\r
260         }\r
261 \r
262         p->Redirect();\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
267         {\r
268                 // 開始行まで読み飛ばす。\r
269                 while (! is->Eof() && tis.ReadLine() != szStartLine);\r
270                 if (is->Eof())\r
271                 {\r
272                         // 書庫が読み込めなかった?\r
273                         ::wxSafeShowMessage(wxEmptyString, wxT("Unsupported archive!"));\r
274                         p->Detach();\r
275                         return TPI_ERROR_ARC_UNSUPPORTED;\r
276                 }\r
277         }\r
278 \r
279         * _hArchive = (void *) is;\r
280         return is->Eof() ? TPI_ERROR_UNDEFINED : TPI_ERROR_SUCCESS;\r
281 }\r
282 \r
283 int __stdcall CloseArchive\r
284 (\r
285         void *\r
286 )\r
287 {\r
288         return TPI_ERROR_SUCCESS;\r
289 }\r
290 \r
291 int __stdcall GetFileInformation\r
292 (\r
293         void * _hArchive,\r
294         TPI_FILEINFO * _fiInfo,\r
295         bool _bFirst\r
296 )\r
297 {\r
298         static size_t s_nCurrentLine;\r
299         static wxULongLong_t s_nFileId;\r
300         if (_hArchive == NULL)\r
301         {\r
302                 return TPI_ERROR_UNDEFINED;\r
303         }\r
304         wxInputStream * is = (wxInputStream *) _hArchive;\r
305         wxTextInputStream tis(* is);\r
306 \r
307         // XMLからの読み込みは初回に行う。\r
308         static wxString szEndLine, szDateFormat;\r
309         static wxULongLong_t nProcessPerLine;\r
310         static PosInfo piFName, piPSize, piUSize, piDate;\r
311         if (_bFirst)\r
312         {\r
313                 // 初期設定。\r
314                 s_nFileId = 0;\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
322         }\r
323 \r
324         if (is->Eof())\r
325         {\r
326                 // 空行で終わるとき以外はエラーとする。\r
327                 return szEndLine.IsEmpty() ? TPI_ERROR_S_ENDOFDATA : TPI_ERROR_ARC_UNSUPPORTED;\r
328         }\r
329 \r
330         // 必要な行数だけ取得。\r
331         wxArrayString as;\r
332         as.Add(tis.ReadLine());\r
333         if (as[0] == szEndLine)\r
334         {\r
335                 return TPI_ERROR_S_ENDOFDATA;\r
336         }\r
337         for (int i = 1; i < nProcessPerLine; i++)\r
338         {\r
339                 as.Add(tis.ReadLine());\r
340         }\r
341 \r
342         // ファイル名を取得。\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
349 \r
350         // サイズ取得。\r
351         _fiInfo->nPackedSize   = GetSize(piPSize, as);\r
352         _fiInfo->nUnpackedSize = GetSize(piUSize, as);\r
353 \r
354         // 更新時刻取得。\r
355         if (piDate.nStart != 0 || piDate.nCount != 0)\r
356         {\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
361                         szDateFormat\r
362                 );\r
363         }\r
364 \r
365         // 最後に次の行へ進めておく。\r
366         _fiInfo->nFileId = s_nFileId++;\r
367         return TPI_ERROR_SUCCESS;\r
368 }\r
369 \r
370 int __stdcall GetArchiveInformation\r
371 (\r
372         void *,\r
373         TPI_ARCHIVEINFO * _aiInfo\r
374 )\r
375 {\r
376         // 形式に関する情報を取得。\r
377         MakeFormatInfo(& g_LibInfo.node, wxT("cuiWrapper"), & _aiInfo->fiInfo, 0);\r
378         return TPI_ERROR_SUCCESS;\r
379 }\r
380 \r
381 int __stdcall Command\r
382 (\r
383         wxULongLong_t _eCommand,\r
384         TPI_SWITCHES * _swInfo,\r
385         const wxString & _szArcName,\r
386         const wxArrayString & _szFiles\r
387 )\r
388 {\r
389         // xmlからコマンドラインを取得。\r
390         wxString szPath, szCommandLine;\r
391 \r
392         // APIアドレス取得。\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
404         {\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
416         }\r
417 \r
418         if (szCommandLine.IsEmpty())\r
419         {\r
420                 return TPI_ERROR_U_USE_LIBRARY;\r
421         }\r
422 \r
423         // コマンドライン・レスポンスファイル作成。\r
424         wxString\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
427                 sz = ::wxGetCwd();\r
428 \r
429         // コマンドライン実行。\r
430         ::wxSetWorkingDirectory(_swInfo->fnDestinationDirectory.GetFullPath());\r
431 #ifdef __LINUX__\r
432         wxProcess * p = ::wxProcess::Open(g_LibInfo.szExeFile.EndsWith(wxT(".exe")) ? (wxT("wine ") + szCommandLineSend) : szCommandLineSend, wxEXEC_ASYNC);\r
433 #else\r
434         wxProcess * p = ::wxProcess::Open(szCommandLineSend, wxEXEC_ASYNC);\r
435 #endif\r
436         ::wxSetWorkingDirectory(sz);\r
437         if (p == NULL)\r
438         {\r
439                 ::wxRemoveFile(szResponceFileName);\r
440                 wxLogError(L"CommandLine:\n%s", szCommandLineSend.c_str());\r
441                 return TPI_ERROR_U_USE_LIBRARY;\r
442         }\r
443 \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
448 \r
449         p->Redirect();\r
450         wxString szOutput;\r
451         wxInputStream * is = p->GetInputStream();\r
452         while (! is->Eof())\r
453         {\r
454                 // コールバック関数に送信。\r
455                 if (g_prProc != NULL && g_prProc(TPI_NOTIFY_COMMON, & piInfo) == TPI_CALLBACK_CANCEL)\r
456                 {\r
457                         p->Kill(p->GetPid(), wxSIGKILL);\r
458                         p->Detach();\r
459                         ::wxRemoveFile(szResponceFileName);\r
460                         return TPI_ERROR_D_SKIPPED;\r
461                 }\r
462 \r
463                 if (! is->CanRead())\r
464                 {\r
465                         continue;\r
466                 }\r
467 \r
468                 char sz[8192];\r
469                 is->Read(sz, sizeof(sz));\r
470                 szOutput += UTF82String(sz);\r
471         }\r
472 //      ::wxMessageBox(szOutput);\r
473 \r
474         // レスポンスファイル削除。\r
475         ::wxRemoveFile(szResponceFileName);\r
476         return TPI_ERROR_SUCCESS;\r
477 }\r
478 \r
479 #ifdef __cplusplus\r
480 }\r
481 #endif\r