OSDN Git Service

DllMainを削除。
[tpi/lychee.git] / src / plugin / spiLibrary / spiLibrary.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/file.h>\r
30 #include <wx/stdpaths.h>\r
31 #include <wx/dir.h>\r
32 #include <windows.h>\r
33 #include "spiLibrary.h"\r
34 \r
35 //******************************************************************************\r
36 //    Global varients\r
37 //******************************************************************************\r
38 \r
39 HMODULE g_hLib;\r
40 TPI_PROC g_prProc;\r
41 \r
42 //******************************************************************************\r
43 //    Callback Wrapper\r
44 //******************************************************************************\r
45 \r
46 int __stdcall CallbackProc(int _nNow, int, long _lData)\r
47 {\r
48         // 構造体を初期化。\r
49         TPI_PROCESSINFO * piInfo = (TPI_PROCESSINFO *) _lData;\r
50         piInfo->nProcessedSize = _nNow;\r
51 \r
52         // コールバック関数に送信。\r
53         return g_prProc != NULL && g_prProc(TPI_NOTIFY_COMMON, piInfo) == TPI_CALLBACK_CANCEL;\r
54 }\r
55 \r
56 //******************************************************************************\r
57 //    Inside Functions\r
58 //******************************************************************************\r
59 \r
60 int ErrorCodeConvert(int nErrorCode)\r
61 {\r
62         switch (nErrorCode)\r
63         {\r
64         case -1: return TPI_ERROR_U_USE_LIBRARY;\r
65         case 0:  return TPI_ERROR_SUCCESS;\r
66         case 1:  return TPI_ERROR_D_SKIPPED;\r
67         case 2:  return TPI_ERROR_ARC_UNSUPPORTED;\r
68         case 3:  return TPI_ERROR_ARC_BROKEN_MISC;\r
69         case 4:  return TPI_ERROR_D_OUTOFMEMORY;\r
70         case 5:  return TPI_ERROR_D_USEMEMORY;\r
71         case 6:  return TPI_ERROR_IO_ARC_READ;\r
72         default: return TPI_ERROR_UNDEFINED;\r
73         }\r
74 }\r
75 \r
76 //******************************************************************************\r
77 //    Functions\r
78 //******************************************************************************\r
79 \r
80 #ifdef __cplusplus\r
81 extern "C"\r
82 {\r
83 #endif\r
84 \r
85 int __stdcall GetPluginInformation\r
86 (\r
87         unsigned int _uInfoId,\r
88         wxULongLong_t,\r
89         void * _pPtr\r
90 )\r
91 {\r
92         if (_pPtr == NULL)\r
93         {\r
94                 return TPI_ERROR_D_PARAMETER;\r
95         }\r
96         switch (_uInfoId)\r
97         {\r
98         case TPI_INFO_VERSION_MAJOR:\r
99         case TPI_INFO_VERSION_MINOR:\r
100                 * (int *) _pPtr = 0;\r
101                 break;\r
102         case TPI_INFO_VERSION_API:\r
103                 * (int *) _pPtr = 2;\r
104                 break;\r
105         default:\r
106                 return TPI_ERROR_D_PARAMETER;\r
107         }\r
108         return TPI_ERROR_SUCCESS;\r
109 }\r
110 \r
111 int __stdcall GetFormatInformation(TPI_FORMATINFO *, bool)\r
112 {\r
113         return TPI_ERROR_D_UNSUPPORTED;\r
114 }\r
115 \r
116 int __stdcall LoadPlugin\r
117 (\r
118         const wxString & _szArcName,\r
119         wxULongLong_t\r
120 )\r
121 {\r
122         wxStandardPaths p;\r
123         wxString szSPIPath = wxPathOnly(p.GetExecutablePath()) + wxT("/lib/"), szSPIName;\r
124         wxDir fs(szSPIPath);\r
125         if (fs.GetFirst(& szSPIName, wxT("*.spi")))\r
126         {\r
127                 do\r
128                 {\r
129                         // SPIをロード。\r
130                         g_hLib = ::LoadLibrary((szSPIPath + szSPIName).wchar_str());\r
131                         if (g_hLib == NULL)\r
132                         {\r
133                                 continue;\r
134                         }\r
135 \r
136                         // GetPluginInfoを実行。\r
137                         FARPROC fpProc = ::GetProcAddress(g_hLib, "GetPluginInfo");\r
138                         char szPluginType[5]; // 種類4bytes + NULL\r
139                         if (fpProc == NULL\r
140                                 || ((int (PASCAL *)(int, char *, int)) fpProc)(0, szPluginType, sizeof(szPluginType)) <= 0\r
141                                 || szPluginType[2] != 'A' || szPluginType[3] != 'M')\r
142                         {\r
143                                 ::FreeLibrary(g_hLib);\r
144                                 continue;\r
145                         }\r
146 \r
147                         // 書庫に対応しているかチェック。\r
148                         if (CheckArchive(_szArcName, NULL) == TPI_ERROR_SUCCESS)\r
149                         {\r
150                                 // 対応していれば処理を終了。\r
151                                 return TPI_ERROR_SUCCESS;\r
152                         }\r
153                 }\r
154                 while (fs.GetNext(& szSPIName));\r
155         }\r
156         return TPI_ERROR_U_LOAD_LIBRARY;\r
157 }\r
158 \r
159 int __stdcall FreePlugin\r
160 (\r
161         void * // _pReserved\r
162 )\r
163 {\r
164         ::FreeLibrary(g_hLib);\r
165         return TPI_ERROR_SUCCESS;\r
166 }\r
167 \r
168 int __stdcall CheckArchive\r
169 (\r
170         const wxString & _szArcName,\r
171         wxULongLong_t * _llFileCount\r
172 )\r
173 {\r
174         FARPROC fpProc = ::GetProcAddress(g_hLib, "IsSupported");\r
175         if (fpProc == NULL)\r
176         {\r
177                 return TPI_ERROR_U_USE_LIBRARY;\r
178         }\r
179 \r
180         wxFile hFile(_szArcName, wxFile::read);\r
181         if (! hFile.IsOpened())\r
182         {\r
183                 return TPI_ERROR_IO_ARC_OPEN;\r
184         }\r
185 \r
186         char buffer[2050];\r
187         ::ZeroMemory(buffer, sizeof(buffer));\r
188         if (hFile.Read(buffer, sizeof(buffer)) == wxInvalidOffset)\r
189         {\r
190                 hFile.Close();\r
191                 return TPI_ERROR_IO_ARC_READ;\r
192         }\r
193 \r
194         if (! ((BOOL (PASCAL *)(const char *, unsigned long)) fpProc)(_szArcName.ToUTF8(), (unsigned long) buffer))\r
195         {\r
196                 hFile.Close();\r
197                 return TPI_ERROR_D_UNSUPPORTED;\r
198         }\r
199         hFile.Close();\r
200 \r
201         fpProc = ::GetProcAddress(g_hLib, "GetArchiveInfo");\r
202         if (fpProc == NULL)\r
203         {\r
204                 return TPI_ERROR_U_USE_LIBRARY;\r
205         }\r
206 \r
207         HLOCAL hMemory;\r
208         int nReturnCode = ErrorCodeConvert(((int (PASCAL *)(const char *, long, unsigned int, HLOCAL *)) fpProc)(_szArcName.ToUTF8(), 0, 0, & hMemory));\r
209         if (nReturnCode == TPI_ERROR_SUCCESS)\r
210         {\r
211                 if (_llFileCount != NULL)\r
212                 {\r
213                         * _llFileCount = ::LocalSize(hMemory) / sizeof(fileInfo);\r
214                 }\r
215                 ::LocalFree(hMemory);\r
216         }\r
217 \r
218         return nReturnCode;\r
219 }\r
220 \r
221 int __stdcall OpenArchive\r
222 (\r
223         const wxString & _szArcName,\r
224         void * * _hArchive\r
225 )\r
226 {\r
227         FARPROC fpProc = ::GetProcAddress(g_hLib, "GetArchiveInfo");\r
228         if (fpProc == NULL)\r
229         {\r
230                 return TPI_ERROR_U_USE_LIBRARY;\r
231         }\r
232 \r
233         int nReturnCode = ErrorCodeConvert(((int (PASCAL *)(const char *, long, unsigned int, HLOCAL *)) fpProc)(_szArcName.ToUTF8(), 0, 0, _hArchive));\r
234         if (nReturnCode != TPI_ERROR_SUCCESS)\r
235         {\r
236                 return nReturnCode;\r
237         }\r
238 \r
239         return * _hArchive == NULL ? TPI_ERROR_IO_ARC_OPEN : nReturnCode;\r
240 }\r
241 \r
242 int __stdcall CloseArchive\r
243 (\r
244         void * _hArchive\r
245 )\r
246 {\r
247         return ::LocalFree(_hArchive) == NULL ? TPI_ERROR_SUCCESS : TPI_ERROR_IO_ARC_CLOSE;\r
248 }\r
249 \r
250 int __stdcall GetFileInformation\r
251 (\r
252         void * _hArchive,\r
253         TPI_FILEINFO * _fiInfo,\r
254         bool _bFirst\r
255 )\r
256 {\r
257         static wxULongLong_t nFileCount, nFilePointer;\r
258 \r
259         if (_bFirst)\r
260         {\r
261                 nFilePointer = 0;\r
262                 nFileCount = ::LocalSize(_hArchive) / sizeof(fileInfo);\r
263         }\r
264 \r
265         if (nFilePointer > nFileCount)\r
266         {\r
267                 return TPI_ERROR_S_ENDOFDATA;\r
268         }\r
269 \r
270         fileInfo pfiInfo = ((fileInfo *) ::LocalLock(_hArchive))[nFilePointer];\r
271         if (pfiInfo.method[0] == 0)\r
272         {\r
273                 // 丁寧なプラグインのための数合わせ (^^;\r
274                 nFileCount = nFilePointer;\r
275                 return TPI_ERROR_S_ENDOFDATA;\r
276         }\r
277 \r
278         _fiInfo->dwAttribute    = 0;\r
279         _fiInfo->dwCRC32        = pfiInfo.crc;\r
280         _fiInfo->nPackedSize    = pfiInfo.compsize;\r
281         _fiInfo->nUnpackedSize  = pfiInfo.filesize;\r
282         _fiInfo->wCompressRatio = pfiInfo.compsize >= pfiInfo.filesize ? 1000 : (WORD) (1000 * pfiInfo.compsize / pfiInfo.filesize);\r
283         _fiInfo->nFileId        = nFilePointer++;\r
284         _fiInfo->tmModified     = pfiInfo.timestamp;\r
285         _fiInfo->szStoredName   = MB2String(pfiInfo.path) + MB2String(pfiInfo.filename);\r
286         _fiInfo->fnFileName     = wxFileName(_fiInfo->szStoredName);\r
287         _fiInfo->szMethod       = MB2String((char *) pfiInfo.method);\r
288         _fiInfo->pCustomInfo    = (void *) pfiInfo.position;\r
289         ::LocalUnlock(_hArchive);\r
290 \r
291         return TPI_ERROR_SUCCESS;\r
292 }\r
293 \r
294 int __stdcall GetArchiveInformation\r
295 (\r
296         void *,\r
297         TPI_ARCHIVEINFO * _aiInfo\r
298 )\r
299 {\r
300         // GetPluginInfoを実行。\r
301         FARPROC fpProc = ::GetProcAddress(g_hLib, "GetPluginInfo");\r
302         if (fpProc != NULL)\r
303         {\r
304                 char szTemp[20];\r
305                 if (((int (PASCAL *)(int, char *, int)) fpProc)(2, szTemp, sizeof(szTemp)) > 0)\r
306                 {\r
307                         _aiInfo->fiInfo.szSuffix = MB2String(szTemp);\r
308                 }\r
309                 if (((int (PASCAL *)(int, char *, int)) fpProc)(3, szTemp, sizeof(szTemp)) > 0)\r
310                 {\r
311                         _aiInfo->fiInfo.szTypeName = MB2String(szTemp);\r
312                 }\r
313         }\r
314         _aiInfo->fiInfo.szTPIName = wxT("spiLibrary");\r
315         _aiInfo->fiInfo.eSupportedCommand = TPI_COMMAND_EXTRACT;\r
316 \r
317         return TPI_ERROR_SUCCESS;\r
318 }\r
319 \r
320 int __stdcall Command\r
321 (\r
322         wxULongLong_t _eCommand,\r
323         TPI_SWITCHES * _swInfo,\r
324         const wxString & _szArcName,\r
325         const wxArrayString & _szFiles\r
326 )\r
327 {\r
328         if (_eCommand != TPI_COMMAND_EXTRACT)\r
329         {\r
330                 return TPI_ERROR_D_UNSUPPORTED;\r
331         }\r
332 \r
333         // 展開処理のみを行う。\r
334         FARPROC fpProc = ::GetProcAddress(g_hLib, "GetFile");\r
335         if (fpProc == NULL)\r
336         {\r
337                 return TPI_ERROR_U_USE_LIBRARY;\r
338         }\r
339 \r
340         // 書庫ハンドルを取得。\r
341         void * hArchive;\r
342         int nErrorCode = OpenArchive(_szArcName, & hArchive);\r
343         if (nErrorCode != TPI_ERROR_SUCCESS)\r
344         {\r
345                 return nErrorCode;\r
346         }\r
347 \r
348         // コールバックを送信。\r
349         wxFileName _fnArcName(_szArcName);\r
350         TPI_PROCESSINFO piInfo;\r
351         piInfo.eMessage = TPI_MESSAGE_STATUS;\r
352         piInfo.eStatus  = TPI_STATUS_OPENARCHIVE;\r
353         piInfo.fiInfo.fnFileName = _fnArcName;\r
354         if (CallbackProc(0, 0, (long) & piInfo))\r
355         {\r
356                 return TPI_ERROR_D_SKIPPED;\r
357         }\r
358 \r
359         // 処理実行。\r
360         piInfo.eStatus = TPI_STATUS_INPROCESS;\r
361         nErrorCode = GetFileInformation(hArchive, & piInfo.fiInfo, true);\r
362         if (nErrorCode == TPI_ERROR_SUCCESS)\r
363         {\r
364                 do\r
365                 {\r
366                         // コールバックを送信。\r
367                         piInfo.eStatus = TPI_STATUS_BEGINPROCESS;\r
368                         if (CallbackProc(0, 0, (long) & piInfo))\r
369                         {\r
370                                 nErrorCode = TPI_ERROR_D_SKIPPED;\r
371                                 break;\r
372                         }\r
373                         piInfo.eStatus = TPI_STATUS_INPROCESS;\r
374 \r
375                         // 処理対象かどうか判定。\r
376                         if ((! _szFiles.IsEmpty()) && _szFiles.Index(piInfo.fiInfo.szStoredName) == wxNOT_FOUND)\r
377                         {\r
378                                 continue;\r
379                         }\r
380 \r
381                         // 出力名作成。\r
382                         wxString szTargetPath = _swInfo->fnDestinationDirectory.GetPathWithSep();\r
383                         if (_swInfo->fStoreDirectoryPathes)\r
384                         {\r
385                                 // 展開先ディレクトリを作成。\r
386                                 szTargetPath += piInfo.fiInfo.fnFileName.GetFullPath();\r
387                                 wxFileName fnDest(szTargetPath);\r
388                                 if (! fnDest.Mkdir(0777, wxPATH_MKDIR_FULL) || ::wxDirExists(fnDest.GetFullPath()))\r
389                                 {\r
390                                         nErrorCode = TPI_ERROR_IO_DIR_WRITE;\r
391                                         break;\r
392                                 }\r
393                         }\r
394                         else\r
395                         {\r
396                                 szTargetPath += piInfo.fiInfo.fnFileName.GetFullName();\r
397                         }\r
398 \r
399                         // ファイル出力には対応してないのでメモリ出力で代行。\r
400                         HLOCAL hMemory = NULL;\r
401                         nErrorCode = ErrorCodeConvert(((int (PASCAL *)(const char *, long, char *, unsigned int, FARPROC, long)) fpProc)(_szArcName.ToUTF8(), (long) piInfo.fiInfo.pCustomInfo, (char *) & hMemory, 0x0100, (FARPROC) CallbackProc, (long) & piInfo));\r
402                         if (nErrorCode == TPI_ERROR_SUCCESS && hMemory == NULL)\r
403                         {\r
404                                 nErrorCode = TPI_ERROR_UNDEFINED;\r
405                         }\r
406                         if (nErrorCode != TPI_ERROR_SUCCESS)\r
407                         {\r
408                                 break;\r
409                         }\r
410 \r
411                         // 展開先に出力。\r
412                         wxFile hFile;\r
413                         // 強制上書きするので注意。\r
414                         if (! hFile.Create(szTargetPath, true))\r
415                         {\r
416                                 nErrorCode = TPI_ERROR_IO_FILE_OPEN;\r
417                                 break;\r
418                         }\r
419 \r
420                         bool bErrorOccured = hFile.Write(::LocalLock(hMemory), piInfo.fiInfo.nUnpackedSize) != piInfo.fiInfo.nUnpackedSize;\r
421                         ::LocalUnlock(hMemory);\r
422                         ::LocalFree(hMemory);\r
423                         hFile.Close();\r
424                         if (bErrorOccured)\r
425                         {\r
426                                 nErrorCode = TPI_ERROR_IO_FILE_WRITE;\r
427                                 break;\r
428                         }\r
429                         nErrorCode = TPI_ERROR_SUCCESS;\r
430 \r
431                         // コールバックを送信。\r
432                         piInfo.eStatus = TPI_STATUS_ENDPROCESS;\r
433                         if (CallbackProc(0, 0, (long) & piInfo))\r
434                         {\r
435                                 nErrorCode = TPI_ERROR_D_SKIPPED;\r
436                                 break;\r
437                         }\r
438                 }\r
439                 while ((nErrorCode = GetFileInformation(hArchive, & piInfo.fiInfo, false)) != TPI_ERROR_S_ENDOFDATA);\r
440                 if (nErrorCode == TPI_ERROR_S_ENDOFDATA)\r
441                 {\r
442                         // 終端に達した場合。\r
443                         nErrorCode = TPI_ERROR_SUCCESS;\r
444                 }\r
445         }\r
446         CloseArchive(hArchive);\r
447 \r
448         return nErrorCode;\r
449 }\r
450 \r
451 int __stdcall SetCallbackProc\r
452 (\r
453         TPI_PROC _prArcProc\r
454 )\r
455 {\r
456         // ポインタを保存。\r
457         if (_prArcProc == NULL)\r
458         {\r
459                 return TPI_ERROR_D_PARAMETER;\r
460         }\r
461         g_prProc = * _prArcProc;\r
462 \r
463         return TPI_ERROR_SUCCESS;\r
464 }\r
465 \r
466 #ifdef __cplusplus\r
467 }\r
468 #endif\r