OSDN Git Service

efcd6f02b2ccc2441c6ca126fd681aff076c6801
[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 #define MYUSE_LIBPATH 1\r
27 #include "../../common/header/plugin.h"\r
28 #include "../../common/header/plugin-extra.h"\r
29 #include "../../common/library/library.h"\r
30 #include <wx/file.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         case TPI_INFO_HANDLE_ON_COMMAND:\r
106                 * (int *) _pPtr = 1;\r
107                 break;\r
108         default:\r
109                 return TPI_ERROR_D_PARAMETER;\r
110         }\r
111         return TPI_ERROR_SUCCESS;\r
112 }\r
113 \r
114 int __stdcall GetFormatInformation(TPI_FORMATINFO *, bool)\r
115 {\r
116         return TPI_ERROR_D_UNSUPPORTED;\r
117 }\r
118 \r
119 int __stdcall LoadPlugin\r
120 (\r
121         const wxString & _szArcName,\r
122         TPI_PROC _prProc,\r
123         wxULongLong_t\r
124 )\r
125 {\r
126         // ファイルを開く。\r
127         char buffer[2050];\r
128         {\r
129                 wxFile hFile;\r
130                 if (! hFile.Exists(_szArcName) || ! hFile.Open(_szArcName, wxFile::read))\r
131                 {\r
132                         return TPI_ERROR_IO_ARC_OPEN;\r
133                 }\r
134 \r
135                 // 最初の2KBを読み込み。\r
136                 ::ZeroMemory(buffer, sizeof(buffer));\r
137                 if (hFile.Read(buffer, sizeof(buffer)) == wxInvalidOffset)\r
138                 {\r
139                         return TPI_ERROR_IO_ARC_READ;\r
140                 }\r
141         }\r
142 \r
143         wxString szSPIName;\r
144         wxDir fs(g_szLibPath);\r
145         if (fs.GetFirst(& szSPIName, wxT("*.spi")))\r
146         {\r
147                 do\r
148                 {\r
149                         // SPIをロード。\r
150                         g_hLib = ::LoadLibrary((g_szLibPath + szSPIName).wchar_str());\r
151                         if (g_hLib == NULL)\r
152                         {\r
153                                 continue;\r
154                         }\r
155 \r
156                         // GetPluginInfoを実行。\r
157                         FARPROC fpProc = ::GetProcAddress(g_hLib, "GetPluginInfo");\r
158                         char szPluginType[5]; // 種類4bytes + NULL\r
159                         if (fpProc == NULL\r
160                                 || ((int (PASCAL *)(int, char *, int)) fpProc)(0, szPluginType, sizeof(szPluginType)) <= 0\r
161                                 || szPluginType[2] != 'A' || szPluginType[3] != 'M')\r
162                         {\r
163                                 ::FreeLibrary(g_hLib);\r
164                                 continue;\r
165                         }\r
166 \r
167                         // 書庫に対応しているかチェック。\r
168                         fpProc = ::GetProcAddress(g_hLib, "IsSupported");\r
169                         if (fpProc == NULL)\r
170                         {\r
171                                 ::FreeLibrary(g_hLib);\r
172                                 continue;\r
173                         }\r
174 \r
175                         if (((BOOL (PASCAL *)(const char *, unsigned long)) fpProc)(_szArcName.ToUTF8(), (unsigned long) buffer))\r
176                         {\r
177                                 // コールバック関数を設定。\r
178                                 if (_prProc != NULL)\r
179                                 {\r
180                                         g_prProc = * _prProc;\r
181                                 }\r
182                                 return TPI_ERROR_SUCCESS;\r
183                         }\r
184                 }\r
185                 while (fs.GetNext(& szSPIName));\r
186         }\r
187         return TPI_ERROR_U_LOAD_LIBRARY;\r
188 }\r
189 \r
190 int __stdcall FreePlugin\r
191 (\r
192         void * // _pReserved\r
193 )\r
194 {\r
195         ::FreeLibrary(g_hLib);\r
196         return TPI_ERROR_SUCCESS;\r
197 }\r
198 \r
199 int __stdcall OpenArchive\r
200 (\r
201         const wxString & _szArcName,\r
202         void * * _hArchive,\r
203         wxULongLong_t * _nFileCount\r
204 )\r
205 {\r
206         FARPROC fpProc = ::GetProcAddress(g_hLib, "GetArchiveInfo");\r
207         if (fpProc == NULL)\r
208         {\r
209                 return TPI_ERROR_U_USE_LIBRARY;\r
210         }\r
211 \r
212         int nReturnCode = ErrorCodeConvert(((int (PASCAL *)(const char *, long, unsigned int, HLOCAL *)) fpProc)(_szArcName.ToUTF8(), 0, 0, _hArchive));\r
213         if (nReturnCode != TPI_ERROR_SUCCESS)\r
214         {\r
215                 return nReturnCode;\r
216         }\r
217         if (_nFileCount != NULL)\r
218         {\r
219                 * _nFileCount = ::LocalSize(* _hArchive) / sizeof(fileInfo);\r
220         }\r
221         return * _hArchive == NULL ? TPI_ERROR_IO_ARC_OPEN : nReturnCode;\r
222 }\r
223 \r
224 int __stdcall CloseArchive\r
225 (\r
226         void * _hArchive\r
227 )\r
228 {\r
229         return ::LocalFree(_hArchive) == NULL ? TPI_ERROR_SUCCESS : TPI_ERROR_IO_ARC_CLOSE;\r
230 }\r
231 \r
232 int __stdcall GetFileInformation\r
233 (\r
234         void * _hArchive,\r
235         TPI_FILEINFO * _fiInfo,\r
236         bool _bFirst\r
237 )\r
238 {\r
239         static wxULongLong_t nFileCount, nFilePointer;\r
240 \r
241         if (_bFirst)\r
242         {\r
243                 nFilePointer = 0;\r
244                 nFileCount = ::LocalSize(_hArchive) / sizeof(fileInfo);\r
245         }\r
246 \r
247         if (nFilePointer > nFileCount)\r
248         {\r
249                 return TPI_ERROR_S_ENDOFDATA;\r
250         }\r
251 \r
252         fileInfo pfiInfo = ((fileInfo *) ::LocalLock(_hArchive))[nFilePointer];\r
253         if (pfiInfo.method[0] == 0)\r
254         {\r
255                 // 丁寧なプラグインのための数合わせ (^^;\r
256                 nFileCount = nFilePointer;\r
257                 return TPI_ERROR_S_ENDOFDATA;\r
258         }\r
259 \r
260         _fiInfo->dwAttribute    = 0;\r
261         _fiInfo->dwCRC32        = pfiInfo.crc;\r
262         _fiInfo->nPackedSize    = pfiInfo.compsize;\r
263         _fiInfo->nUnpackedSize  = pfiInfo.filesize;\r
264         _fiInfo->wCompressRatio = pfiInfo.compsize >= pfiInfo.filesize ? 1000 : (WORD) (1000 * pfiInfo.compsize / pfiInfo.filesize);\r
265         _fiInfo->nFileId        = nFilePointer++;\r
266         _fiInfo->tmModify       = pfiInfo.timestamp;\r
267         _fiInfo->szStoredName   = MB2String(pfiInfo.path) + MB2String(pfiInfo.filename);\r
268         _fiInfo->fnFileName     = wxFileName(_fiInfo->szStoredName);\r
269         _fiInfo->szMethod       = MB2String((char *) pfiInfo.method);\r
270         _fiInfo->pCustomInfo    = (void *) pfiInfo.position;\r
271         ::LocalUnlock(_hArchive);\r
272 \r
273         return TPI_ERROR_SUCCESS;\r
274 }\r
275 \r
276 int __stdcall GetArchiveInformation\r
277 (\r
278         void *,\r
279         TPI_ARCHIVEINFO * _aiInfo\r
280 )\r
281 {\r
282         // GetPluginInfoを実行。\r
283         FARPROC fpProc = ::GetProcAddress(g_hLib, "GetPluginInfo");\r
284         if (fpProc != NULL)\r
285         {\r
286                 char szTemp[513];\r
287                 memset(szTemp, 0, sizeof(szTemp));\r
288                 if (((int (PASCAL *)(int, char *, int)) fpProc)(1, szTemp, sizeof(szTemp) - 1) > 0)\r
289                 {\r
290                         _aiInfo->fiInfo.szEngineName = MB2String(szTemp);\r
291                 }\r
292                 if (((int (PASCAL *)(int, char *, int)) fpProc)(2, szTemp, sizeof(szTemp) - 1) > 0)\r
293                 {\r
294                         _aiInfo->fiInfo.szSuffix = MB2String(szTemp);\r
295                 }\r
296                 if (((int (PASCAL *)(int, char *, int)) fpProc)(3, szTemp, sizeof(szTemp) - 1) > 0)\r
297                 {\r
298                         _aiInfo->fiInfo.szTypeName = MB2String(szTemp);\r
299                 }\r
300         }\r
301         _aiInfo->fiInfo.szTPIName = wxT("spiLibrary");\r
302         _aiInfo->fiInfo.eSupportedCommand = TPI_COMMAND_EXTRACT;\r
303 \r
304         return TPI_ERROR_SUCCESS;\r
305 }\r
306 \r
307 int __stdcall Command\r
308 (\r
309         wxULongLong_t _eCommand,\r
310         TPI_SWITCHES * _swInfo,\r
311         void * _hArchive,\r
312         const wxArrayString & _szFiles\r
313 )\r
314 {\r
315         if (_eCommand != TPI_COMMAND_EXTRACT)\r
316         {\r
317                 return TPI_ERROR_D_UNSUPPORTED;\r
318         }\r
319 \r
320         // 展開処理のみを行う。\r
321         FARPROC fpProc = ::GetProcAddress(g_hLib, "GetFile");\r
322         if (fpProc == NULL)\r
323         {\r
324                 return TPI_ERROR_U_USE_LIBRARY;\r
325         }\r
326 \r
327         // コールバックを送信。\r
328         wxFileName _fnArcName(_swInfo->szArcName);\r
329         TPI_PROCESSINFO piInfo;\r
330         piInfo.eMessage = TPI_MESSAGE_STATUS;\r
331         piInfo.eStatus  = TPI_STATUS_OPENARCHIVE;\r
332         piInfo.fiInfo.fnFileName = _fnArcName;\r
333         if (CallbackProc(0, 0, (long) & piInfo))\r
334         {\r
335                 return TPI_ERROR_D_SKIPPED;\r
336         }\r
337 \r
338         // 処理実行。\r
339         piInfo.eStatus = TPI_STATUS_INPROCESS;\r
340         int nErrorCode = GetFileInformation(_hArchive, & piInfo.fiInfo, true);\r
341         if (nErrorCode == TPI_ERROR_SUCCESS)\r
342         {\r
343                 do\r
344                 {\r
345                         // 処理対象かどうか判定。\r
346                         if ((! _szFiles.IsEmpty()) && _szFiles.Index(piInfo.fiInfo.szStoredName) == wxNOT_FOUND)\r
347                         {\r
348                                 continue;\r
349                         }\r
350 \r
351                         // 処理を行うか確認。\r
352                         piInfo.eMessage = TPI_MESSAGE_ASK;\r
353                         piInfo.eStatus = TPI_PARAM_DEST;\r
354                         piInfo.fnDestination = wxFileName(_swInfo->fnDestinationDirectory.GetPathWithSep() + (_swInfo->fStoreDirectoryPathes ? piInfo.fiInfo.fnFileName.GetFullPath() : piInfo.fiInfo.fnFileName.GetFullName()));\r
355                         if (CallbackProc(0, 0, (long) & piInfo))\r
356                         {\r
357                                 nErrorCode = TPI_ERROR_D_SKIPPED;\r
358                                 break;\r
359                         }\r
360                         if (! piInfo.fnDestination.IsOk())\r
361                         {\r
362                                 continue;\r
363                         }\r
364 \r
365                         // 出力先作成。\r
366                         if (! piInfo.fnDestination.Mkdir(0777, wxPATH_MKDIR_FULL))\r
367                         {\r
368                                 nErrorCode = TPI_ERROR_IO_DIR_WRITE;\r
369                                 break;\r
370                         }\r
371 \r
372                         // コールバックを送信。\r
373                         piInfo.eMessage = TPI_MESSAGE_STATUS;\r
374                         piInfo.eStatus = TPI_STATUS_BEGINPROCESS;\r
375                         if (CallbackProc(0, 0, (long) & piInfo))\r
376                         {\r
377                                 nErrorCode = TPI_ERROR_D_SKIPPED;\r
378                                 break;\r
379                         }\r
380                         piInfo.eStatus = TPI_STATUS_INPROCESS;\r
381 \r
382                         // ファイル出力には対応してないのでメモリ出力で代行。\r
383                         HLOCAL hMemory = NULL;\r
384                         nErrorCode = ErrorCodeConvert(((int (PASCAL *)(const char *, long, char *, unsigned int, FARPROC, long)) fpProc)(_swInfo->szArcName.ToUTF8(), (long) piInfo.fiInfo.pCustomInfo, (char *) & hMemory, 0x0100, (FARPROC) CallbackProc, (long) & piInfo));\r
385                         if (nErrorCode == TPI_ERROR_SUCCESS && hMemory == NULL)\r
386                         {\r
387                                 nErrorCode = TPI_ERROR_UNDEFINED;\r
388                         }\r
389                         if (nErrorCode != TPI_ERROR_SUCCESS)\r
390                         {\r
391                                 break;\r
392                         }\r
393 \r
394                         // 展開先に出力。\r
395                         bool bErrorOccured;\r
396                         {\r
397                                 wxFile hFile;\r
398                                 if (! hFile.Create(piInfo.fnDestination.GetFullPath()))\r
399                                 {\r
400                                         nErrorCode = TPI_ERROR_IO_FILE_OPEN;\r
401                                         break;\r
402                                 }\r
403 \r
404                                 bErrorOccured = hFile.Write(::LocalLock(hMemory), piInfo.fiInfo.nUnpackedSize) != piInfo.fiInfo.nUnpackedSize;\r
405                                 ::LocalUnlock(hMemory);\r
406                                 ::LocalFree(hMemory);\r
407                         }\r
408 \r
409                         if (bErrorOccured)\r
410                         {\r
411                                 nErrorCode = TPI_ERROR_IO_FILE_WRITE;\r
412                                 break;\r
413                         }\r
414                         nErrorCode = TPI_ERROR_SUCCESS;\r
415 \r
416                         // コールバックを送信。\r
417                         piInfo.eStatus = TPI_STATUS_ENDPROCESS;\r
418                         if (CallbackProc(0, 0, (long) & piInfo))\r
419                         {\r
420                                 nErrorCode = TPI_ERROR_D_SKIPPED;\r
421                                 break;\r
422                         }\r
423                 }\r
424                 while ((nErrorCode = GetFileInformation(_hArchive, & piInfo.fiInfo, false)) != TPI_ERROR_S_ENDOFDATA);\r
425                 if (nErrorCode == TPI_ERROR_S_ENDOFDATA)\r
426                 {\r
427                         // 終端に達した場合。\r
428                         nErrorCode = TPI_ERROR_SUCCESS;\r
429                 }\r
430         }\r
431 \r
432         return nErrorCode;\r
433 }\r
434 \r
435 #ifdef __cplusplus\r
436 }\r
437 #endif\r