OSDN Git Service

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