OSDN Git Service

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