OSDN Git Service

LoadPluginの_llSubOptionを_llTypeIdに、TPI_FILEINFO::llFileIDをllFileIdにリネーム。
[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 <wx/config.h>\r
30 #include <wx/stdpaths.h>\r
31 #include <wx/xml/xml.h>\r
32 #include <wx/tokenzr.h>\r
33 #ifdef __WINDOWS__\r
34 #include <windows.h>\r
35 #endif\r
36 #include "cuiWrapper.h"\r
37 \r
38 //******************************************************************************\r
39 //    Global varients\r
40 //******************************************************************************\r
41 \r
42 struct g_LibInfo\r
43 {\r
44         wxString szExeFile;\r
45         wxString szExeFileAlt;\r
46         wxString szListCommand;\r
47         int nLibIndex;\r
48         wxXmlNode node;\r
49 }       g_LibInfo;\r
50 \r
51 TPI_PROC g_prProc;\r
52 wxString g_szCurrentArchive;\r
53 wxArrayString g_asOutput;\r
54 \r
55 //******************************************************************************\r
56 //    Entry\r
57 //******************************************************************************\r
58 \r
59 #ifdef __WINDOWS__\r
60 BOOL __stdcall DllMain(HMODULE, DWORD, void *)\r
61 {\r
62         return TRUE;\r
63 }\r
64 #endif\r
65 \r
66 //******************************************************************************\r
67 //    Inside Functions\r
68 //******************************************************************************\r
69 \r
70 int myExecute(wxString szCommandLine, wxString * szOutput, wxString szCwd)\r
71 {\r
72 #ifdef __LINUX__\r
73         wxString sz = ::wxGetCwd();\r
74         ::wxSetWorkingDirectory(szCwd);\r
75         FILE * fp = popen(szCommandLine.ToUTF8(), "r");\r
76         ::wxSetWorkingDirectory(sz);\r
77         if (fp == NULL)\r
78         {\r
79                 ::wxLogError(L"Error :\n\nCommandLine:\n%s", szCommandLine.c_str());\r
80                 return TPI_ERROR_U_USE_LIBRARY;\r
81         }\r
82 \r
83         if (szOutput != NULL)\r
84         {\r
85                 char sz[32769];\r
86                 while (! feof(fp))\r
87                 {\r
88                         memset(sz, 0, sizeof(sz));\r
89                         fread(sz, sizeof(char), sizeof(sz) - 1, fp);\r
90                         * szOutput += UTF82String(sz);\r
91                 }\r
92 //              ::wxMessageBox(* szOutput);\r
93         }\r
94 \r
95         pclose(fp);\r
96 #else\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
103         {\r
104                 return TPI_ERROR_U_USE_LIBRARY;\r
105         }\r
106         STARTUPINFO si;\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
114         {\r
115                 return TPI_ERROR_U_USE_LIBRARY;\r
116         }\r
117         ::CloseHandle(pi.hThread);\r
118 \r
119         if (szOutput != NULL)\r
120         {\r
121                 char sz[32768];\r
122                 while (true)\r
123                 {\r
124                         DWORD dwSize = 0;\r
125                         if (! ::PeekNamedPipe(hRead, NULL, 0, NULL, & dwSize, NULL))\r
126                         {\r
127                                 continue;\r
128                         }\r
129 \r
130                         if (dwSize > 0)\r
131                         {\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
136                         }\r
137                         else if (::WaitForSingleObject(pi.hProcess, 0) == WAIT_OBJECT_0)\r
138                         {\r
139                                 break;\r
140                         }\r
141                 }\r
142         }\r
143 \r
144         ::CloseHandle(pi.hProcess);\r
145         ::CloseHandle(hRead);\r
146         ::CloseHandle(hWrite);\r
147 #endif\r
148         return TPI_ERROR_SUCCESS;\r
149 }\r
150 \r
151 PosInfo MakePosInfo(wxString szPrefix)\r
152 {\r
153         PosInfo pi;\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
157         return pi;\r
158 }\r
159 \r
160 wxULongLong GetSize(PosInfo & pi, size_t uCurrent, wxArrayString & as)\r
161 {\r
162         if (pi.nStart == 0 && pi.nCount == 0)\r
163         {\r
164                 return 0;\r
165         }\r
166 \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
171         return nTemp;\r
172 }\r
173 \r
174 //******************************************************************************\r
175 //    Functions\r
176 //******************************************************************************\r
177 \r
178 #ifdef __cplusplus\r
179 extern "C"\r
180 {\r
181 #endif\r
182 \r
183 int __stdcall GetPluginInformation\r
184 (\r
185         unsigned int _uInfoId,\r
186         wxULongLong,\r
187         void * _pPtr\r
188 )\r
189 {\r
190         if (_pPtr == NULL)\r
191         {\r
192                 return TPI_ERROR_D_PARAMETER;\r
193         }\r
194         switch (_uInfoId)\r
195         {\r
196         case TPI_INFO_VERSION_MAJOR:\r
197         case TPI_INFO_VERSION_MINOR:\r
198                 * (int *) _pPtr = 0;\r
199                 break;\r
200         case TPI_INFO_VERSION_API:\r
201                 * (int *) _pPtr = 2;\r
202                 break;\r
203         default:\r
204                 return TPI_ERROR_D_UNSUPPORTED;\r
205         }\r
206         return TPI_ERROR_SUCCESS;\r
207 }\r
208 \r
209 int __stdcall GetFormatInformation(TPI_FORMATINFO * _fiInfo, bool _bFirst)\r
210 {\r
211         static unsigned int s_uFileId;\r
212         wxStandardPaths p;\r
213         wxXmlDocument config(wxPathOnly(p.GetExecutablePath()) + wxT("/lib/cuiWrapper.xml"));\r
214         // 一気に先頭のライブラリの情報を取得。\r
215         wxXmlNode * xmlLibrary = config.GetRoot()->GetChildren();\r
216 \r
217         if (_bFirst)\r
218         {\r
219                 // xml解析開始。\r
220                 s_uFileId = 0;\r
221         }\r
222         else\r
223         {\r
224                 for (unsigned int i = 0; i < s_uFileId && xmlLibrary != NULL; i++)\r
225                 {\r
226                         xmlLibrary = xmlLibrary->GetNext();\r
227                 }\r
228         }\r
229 \r
230         if (xmlLibrary == NULL || xmlLibrary->GetName() != wxT("library"))\r
231         {\r
232                 // 終端に達した場合。\r
233                 return TPI_ERROR_S_ENDOFDATA;\r
234         }\r
235 \r
236         MakeFormatInfo(wxT("cuiWrapper"), _fiInfo, xmlLibrary, s_uFileId++);\r
237         if (myExecute(xmlLibrary->GetPropVal(wxT("name"), wxEmptyString), NULL, wxEmptyString) != TPI_ERROR_SUCCESS)\r
238         {\r
239                 _fiInfo->llSupportedCommand = 0;\r
240         }\r
241 \r
242         return TPI_ERROR_SUCCESS;\r
243 }\r
244 \r
245 int __stdcall LoadPlugin\r
246 (\r
247         const wxString & _szArcName,\r
248         wxULongLong _llTypeId\r
249 )\r
250 {\r
251         // xml解析開始。\r
252         wxStandardPaths p;\r
253         wxXmlDocument config(wxPathOnly(p.GetExecutablePath()) + wxT("/lib/cuiWrapper.xml"));\r
254         if (! config.IsOk())\r
255         {\r
256                 return TPI_ERROR_UNDEFINED;\r
257         }\r
258         // 一気に先頭のライブラリの情報を取得。\r
259         wxXmlNode * xmlLibrary = config.GetRoot()->GetChildren();\r
260 \r
261         // 対象が存在するならば対応するライブラリを調査、\r
262         // 対象が存在しないならば指示されたライブラリをロード。\r
263         if (! ::wxFileExists(_szArcName))\r
264         {\r
265                 // 適当な位置まで移動。\r
266                 for (g_LibInfo.nLibIndex = 0; g_LibInfo.nLibIndex < _llTypeId && xmlLibrary != NULL; g_LibInfo.nLibIndex++)\r
267                 {\r
268                         xmlLibrary = xmlLibrary->GetNext();\r
269                 }\r
270                 if (xmlLibrary == NULL || xmlLibrary->GetName() != wxT("library"))\r
271                 {\r
272                         // xml文法エラー。\r
273                         return TPI_ERROR_UNDEFINED;\r
274                 }\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
278 \r
279                 return TPI_ERROR_SUCCESS;\r
280         }\r
281 \r
282         // 無限ループに陥らないよう上限を設定。\r
283         for (g_LibInfo.nLibIndex = 0; g_LibInfo.nLibIndex < 300 && xmlLibrary != NULL; g_LibInfo.nLibIndex++)\r
284         {\r
285                 // ライブラリをロード。\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
289 \r
290                 // 書庫に対応しているかチェック。\r
291                 if (CheckArchive(_szArcName, NULL) == TPI_ERROR_SUCCESS)\r
292                 {\r
293                         // 対応していれば処理を終了。\r
294                         return TPI_ERROR_SUCCESS;\r
295                 }\r
296 \r
297                 xmlLibrary = xmlLibrary->GetNext();\r
298         }\r
299 \r
300         return TPI_ERROR_U_LOAD_LIBRARY;\r
301 }\r
302 \r
303 int __stdcall FreePlugin\r
304 (\r
305         void * // _pReserved\r
306 )\r
307 {\r
308         return TPI_ERROR_SUCCESS;\r
309 }\r
310 \r
311 int __stdcall CheckArchive\r
312 (\r
313         const wxString & _szArcName,\r
314         wxULongLong * _llFileCount\r
315 )\r
316 {\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
320         {\r
321                 return TPI_ERROR_ARC_UNSUPPORTED;\r
322         }\r
323 \r
324         for (size_t i = 0; i < asExt.GetCount(); i++)\r
325         {\r
326                 // .tar.XXXなど二重判定への対応。\r
327 //              if (asExt[i].IsSameAs(fnArchive.GetExt(), false))\r
328                 if (fnArchive.GetFullName().EndsWith(wxT('.') + asExt[i]))\r
329                 {\r
330                         // 開いて確認。先行してデータを取得しておく。\r
331                         int nErrorCode = OpenArchive(_szArcName, NULL);\r
332 \r
333                         // 対応。\r
334                         if (_llFileCount != NULL)\r
335                         {\r
336                                 // ファイル数は多めに取っておく。\r
337                                 * _llFileCount = g_asOutput.GetCount();\r
338                         }\r
339                         return nErrorCode;\r
340                 }\r
341         }\r
342 \r
343         return TPI_ERROR_ARC_UNSUPPORTED;\r
344 }\r
345 \r
346 int __stdcall OpenArchive\r
347 (\r
348         const wxString & _szArcName,\r
349         void * * _hArchive\r
350 )\r
351 {\r
352         if (g_szCurrentArchive != _szArcName)\r
353         {\r
354                 wxString szOutput;\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
356                 {\r
357                         return TPI_ERROR_U_USE_LIBRARY;\r
358                 }\r
359                 g_szCurrentArchive = _szArcName;\r
360                 g_asOutput = ::wxStringTokenize(szOutput, wxT("\r\n"));\r
361                 g_asOutput.Shrink();\r
362         }\r
363         if (_hArchive != NULL)\r
364         {\r
365                 * _hArchive = & g_asOutput;\r
366         }\r
367         return g_asOutput.IsEmpty() ? TPI_ERROR_UNDEFINED : TPI_ERROR_SUCCESS;\r
368 }\r
369 \r
370 int __stdcall CloseArchive\r
371 (\r
372         void * _hArchive\r
373 )\r
374 {\r
375         ((wxArrayString *) _hArchive)->Clear();\r
376         return TPI_ERROR_SUCCESS;\r
377 }\r
378 \r
379 int __stdcall GetFileInformation\r
380 (\r
381         void * _hArchive,\r
382         TPI_FILEINFO * _fiInfo,\r
383         bool _bFirst\r
384 )\r
385 {\r
386         static size_t s_uCurrentLine;\r
387         static wxULongLong s_llFileId;\r
388         if (_hArchive == NULL)\r
389         {\r
390                 return TPI_ERROR_UNDEFINED;\r
391         }\r
392         wxArrayString asOutput = * (wxArrayString *) _hArchive;\r
393 \r
394         // XMLからの読み込みは初回に行う。\r
395         static wxString szEndLine, szDateFormat;\r
396         static unsigned long nProcessPerLine;\r
397         static PosInfo piFName, piPSize, piUSize, piDate;\r
398         if (_bFirst)\r
399         {\r
400                 s_llFileId = 0;\r
401                 wxString szStartLine = g_LibInfo.node.GetPropVal(wxT("list-line-s"), wxEmptyString);\r
402                 if (! szStartLine.IsEmpty())\r
403                 {\r
404                         // 開始行の次の行にセット。\r
405                         s_uCurrentLine = asOutput.Index(szStartLine) + 1;\r
406                         if (s_uCurrentLine == wxNOT_FOUND + 1)\r
407                         {\r
408                                 // 書庫が読み込めなかった?\r
409                                 return TPI_ERROR_ARC_UNSUPPORTED;\r
410                         }\r
411                 }\r
412 \r
413                 // 初期設定。\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
421         }\r
422 \r
423         if (s_uCurrentLine >= asOutput.GetCount())\r
424         {\r
425                 // 書庫が読み込めなかった?\r
426                 return TPI_ERROR_ARC_UNSUPPORTED;\r
427         }\r
428 \r
429         // 最終行かどうか確認。\r
430         if (asOutput[s_uCurrentLine] == szEndLine)\r
431         {\r
432                 return TPI_ERROR_S_ENDOFDATA;\r
433         }\r
434 \r
435         // ファイル名を取得。\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
439 \r
440         // サイズ取得。\r
441         _fiInfo->llPackedSize   = GetSize(piPSize, s_uCurrentLine, asOutput);\r
442         _fiInfo->llUnpackedSize = GetSize(piUSize, s_uCurrentLine, asOutput);\r
443 \r
444         // 更新時刻取得。\r
445         if (piDate.nStart != 0 || piDate.nCount != 0)\r
446         {\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
448         }\r
449 \r
450         // 最後に次の行へ進めておく。\r
451         _fiInfo->llFileId = s_llFileId++;\r
452         s_uCurrentLine += nProcessPerLine;\r
453 \r
454         return TPI_ERROR_SUCCESS;\r
455 }\r
456 \r
457 int __stdcall GetArchiveInformation\r
458 (\r
459         void *,\r
460         TPI_ARCHIVEINFO * _aiInfo\r
461 )\r
462 {\r
463         // 形式に関する情報を取得。\r
464         MakeFormatInfo(wxT("cuiWrapper"), & _aiInfo->fiInfo, & g_LibInfo.node, 0);\r
465         return TPI_ERROR_SUCCESS;\r
466 }\r
467 \r
468 int __stdcall Command\r
469 (\r
470         unsigned int _uCommand,\r
471         TPI_SWITCHES * _swInfo,\r
472         const wxString & _szArcName,\r
473         const wxArrayString & _szFiles\r
474 )\r
475 {\r
476         // xmlからコマンドラインを取得。\r
477         wxString szPath, szCommandLine;\r
478 \r
479         // APIアドレス取得。\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
490         {\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
501         }\r
502 \r
503         if (szCommandLine.IsEmpty())\r
504         {\r
505                 return TPI_ERROR_U_USE_LIBRARY;\r
506         }\r
507 \r
508         // コマンドライン・レスポンスファイル作成。\r
509         wxString\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
512 \r
513         // コマンドライン実行。\r
514         wxString szOutput;\r
515         int nErrorCode = myExecute(g_LibInfo.szExeFile + wxT(" ") + szCommandLineSend, & szOutput, _swInfo->fnDestinationDirectory.GetFullPath());\r
516 \r
517         // レスポンスファイル削除。\r
518         ::wxRemoveFile(szResponceFileName);\r
519 \r
520         if (nErrorCode != TPI_ERROR_SUCCESS)\r
521         {\r
522                 ::wxLogError(L"Error :\n%x\n\nCommandLine:\n%s\n\nOutput:\n%s", nErrorCode, szCommandLineSend.c_str(), szOutput.c_str());\r
523         }\r
524         return nErrorCode;\r
525 }\r
526 \r
527 int __stdcall SetCallbackProc\r
528 (\r
529         TPI_PROC _prArcProc\r
530 )\r
531 {\r
532         // ポインタを保存。\r
533         if (_prArcProc == NULL)\r
534         {\r
535                 return TPI_ERROR_D_PARAMETER;\r
536         }\r
537         g_prProc = * _prArcProc;\r
538 \r
539         return TPI_ERROR_SUCCESS;\r
540 }\r
541 \r
542 #ifdef __cplusplus\r
543 }\r
544 #endif\r