OSDN Git Service

微修正。
[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: spiLibrary.cpp,v 1.9 2009/08/23 04:25:53 sirakaba Exp $\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/dynlib.h>\r
30 #include <wx/file.h>\r
31 #include <wx/config.h>\r
32 #include <wx/wfstream.h>\r
33 #include <wx/stdpaths.h>\r
34 #include <wx/filesys.h>\r
35 #include <wx/dir.h>\r
36 #include <windows.h>\r
37 #include <imagehlp.h>\r
38 #include "spiLibrary.h"\r
39 \r
40 //******************************************************************************\r
41 //    Global varients\r
42 //******************************************************************************\r
43 \r
44 HMODULE g_hLib;\r
45 TPI_PROC g_prProc;\r
46 \r
47 //******************************************************************************\r
48 //    Entry\r
49 //******************************************************************************\r
50 \r
51 #ifdef __LINUX__\r
52 void __attribute__((destructor)) Detach(void)\r
53 {\r
54         ::FreeLibrary(g_hLib);\r
55 }\r
56 \r
57 #else\r
58 BOOL __stdcall DllMain(HMODULE, DWORD fdwReason, void *)\r
59 {\r
60         switch (fdwReason)\r
61         {\r
62         case DLL_PROCESS_DETACH:\r
63                 ::FreeLibrary(g_hLib);\r
64                 break;\r
65         }\r
66         return TRUE;\r
67 }\r
68 #endif\r
69 \r
70 //******************************************************************************\r
71 //    Callback Wrapper\r
72 //******************************************************************************\r
73 \r
74 int __stdcall CallbackProc(int _nNow, int _nMax, long _lData)\r
75 {\r
76         // \8d\\91¢\91Ì\82ð\8f\89\8aú\89»\81B\r
77         TPI_PROCESSINFO piInfo;\r
78         piInfo.uMessage = TPI_MESSAGE_STATUS;\r
79         piInfo.uStatus  = _nNow == 0     ? TPI_STATUS_BEGINPROCESS\r
80                                         : _nNow == _nMax ? TPI_STATUS_ENDPROCESS\r
81                                         : _nNow <  0     ? TPI_STATUS_OPENARCHIVE : TPI_STATUS_INPROCESS;\r
82         piInfo.llProcessedSize       = _nNow;\r
83         piInfo.fiInfo.llUnpackedSize = _nMax;\r
84         piInfo.fiInfo.fnFileName = * (wxFileName *) _lData;\r
85 \r
86         // \83R\81[\83\8b\83o\83b\83N\8aÖ\90\94\82É\91\97\90M\81B\r
87         return g_prProc != NULL && g_prProc(TPI_NOTIFY_COMMON, & piInfo) == TPI_CALLBACK_CANCEL;\r
88 }\r
89 \r
90 //******************************************************************************\r
91 //    Inside Functions\r
92 //******************************************************************************\r
93 \r
94 int SpiErrorCodeConvert(int nSpiErrorCode)\r
95 {\r
96         switch (nSpiErrorCode)\r
97         {\r
98         case -1: return TPI_ERROR_U_USE_LIBRARY;\r
99         case 0:  return TPI_ERROR_SUCCESS;\r
100         case 1:  return TPI_ERROR_D_SKIPPED;\r
101         case 2:  return TPI_ERROR_ARC_UNSUPPORTED;\r
102         case 3:  return TPI_ERROR_ARC_BROKEN_MISC;\r
103         case 4:  return TPI_ERROR_D_OUTOFMEMORY;\r
104         case 5:  return TPI_ERROR_D_USEMEMORY;\r
105         case 6:  return TPI_ERROR_IO_ARC_READ;\r
106         default: return TPI_ERROR_UNDEFINED;\r
107         }\r
108 }\r
109 \r
110 //******************************************************************************\r
111 //    Functions\r
112 //******************************************************************************\r
113 \r
114 #ifdef __cplusplus\r
115 extern "C"\r
116 {\r
117 #endif\r
118 \r
119 int __stdcall GetPluginInformation\r
120 (\r
121         unsigned int _uInfoId,\r
122         wxULongLong,\r
123         void * _pPtr\r
124 )\r
125 {\r
126         if (_pPtr == NULL)\r
127         {\r
128                 return TPI_ERROR_D_PARAMETER;\r
129         }\r
130         switch (LOWORD(_uInfoId))\r
131         {\r
132         case TPI_INFO_VERSION_MAJOR:\r
133         case TPI_INFO_VERSION_MINOR:\r
134                 * (int *) _pPtr = 0;\r
135                 break;\r
136         case TPI_INFO_VERSION_API:\r
137                 * (int *) _pPtr = 2;\r
138                 break;\r
139         default:\r
140                 return TPI_ERROR_D_PARAMETER;\r
141         }\r
142         return TPI_ERROR_SUCCESS;\r
143 }\r
144 \r
145 int __stdcall GetFormatInformation(TPI_FORMATINFO *, bool)\r
146 {\r
147         return TPI_ERROR_D_UNSUPPORTED;\r
148 }\r
149 \r
150 int __stdcall LoadPlugin\r
151 (\r
152         const wxString & _szArcName,\r
153         wxULongLong\r
154 )\r
155 {\r
156         wxStandardPaths p;\r
157         wxString szSPIPath = wxPathOnly(p.GetExecutablePath()) + wxT("/lib/"), szSPIName = wxEmptyString;\r
158         wxDir fs(szSPIPath);\r
159         bool b = fs.GetFirst(& szSPIName, wxT("*.spi"));\r
160         while (b)\r
161         {\r
162                 // SPI\82ð\83\8d\81[\83h\81B\r
163                 wxString szLibName = szSPIPath + szSPIName;\r
164                 g_hLib = ::LoadLibraryA(szLibName.ToUTF8());\r
165                 if (g_hLib == NULL)\r
166                 {\r
167                         b = fs.GetNext(& szSPIName);\r
168                         continue;\r
169                 }\r
170 \r
171                 // GetPluginInfo\82ð\8eÀ\8ds\81B\r
172                 FARPROC fpProc = ::GetProcAddress(g_hLib, "GetPluginInfo");\r
173                 char szPluginType[5]; // \8eí\97Þ4bytes + NULL\r
174                 if (fpProc == NULL\r
175                         || ((int (PASCAL *)(int, char *, int)) fpProc)(0, szPluginType, sizeof(szPluginType)) < 0\r
176                         || szPluginType[2] != 'A' || szPluginType[3] != 'M')\r
177                 {\r
178                         ::FreeLibrary(g_hLib);\r
179                         b = fs.GetNext(& szSPIName);\r
180                         continue;\r
181                 }\r
182 \r
183                 // \8f\91\8cÉ\82É\91Î\89\9e\82µ\82Ä\82¢\82é\82©\83`\83F\83b\83N\81B\r
184                 if (CheckArchive(_szArcName, NULL) == TPI_ERROR_SUCCESS)\r
185                 {\r
186                         // \91Î\89\9e\82µ\82Ä\82¢\82ê\82Î\8f\88\97\9d\82ð\8fI\97¹\81B\r
187                         return TPI_ERROR_SUCCESS;\r
188                 }\r
189 \r
190                 b = fs.GetNext(& szSPIName);\r
191         }\r
192         return TPI_ERROR_U_LOAD_LIBRARY;\r
193 }\r
194 \r
195 int __stdcall FreePlugin\r
196 (\r
197         void * // _pReserved\r
198 )\r
199 {\r
200         ::FreeLibrary(g_hLib);\r
201         return TPI_ERROR_SUCCESS;\r
202 }\r
203 \r
204 int __stdcall CheckArchive\r
205 (\r
206         const wxString & _szArcName,\r
207         int * _nFileCount\r
208 )\r
209 {\r
210         FARPROC fpProc = ::GetProcAddress(g_hLib, "IsSupported");\r
211         if (fpProc == NULL)\r
212         {\r
213                 return TPI_ERROR_U_USE_LIBRARY;\r
214         }\r
215 \r
216         wxFile hFile(_szArcName, wxFile::read);\r
217         if (! hFile.IsOpened())\r
218         {\r
219                 return TPI_ERROR_IO_ARC_OPEN;\r
220         }\r
221 \r
222         char buffer[2050];\r
223         ::ZeroMemory(buffer, sizeof(buffer));\r
224         if (hFile.Read(buffer, sizeof(buffer)) == wxInvalidOffset)\r
225         {\r
226                 hFile.Close();\r
227                 return TPI_ERROR_IO_ARC_READ;\r
228         }\r
229 \r
230         if (! ((BOOL (PASCAL *)(const char *, unsigned long)) fpProc)(_szArcName.ToUTF8(), (unsigned long) buffer))\r
231         {\r
232                 hFile.Close();\r
233                 return TPI_ERROR_D_UNSUPPORTED;\r
234         }\r
235         hFile.Close();\r
236 \r
237         fpProc = ::GetProcAddress(g_hLib, "GetArchiveInfo");\r
238         if (fpProc == NULL)\r
239         {\r
240                 return TPI_ERROR_U_USE_LIBRARY;\r
241         }\r
242 \r
243         HLOCAL hMemory;\r
244         int nReturnCode = SpiErrorCodeConvert(((int (PASCAL *)(const char *, long, unsigned int, HLOCAL *)) fpProc)(_szArcName.ToUTF8(), 0, 0, & hMemory));\r
245         if (nReturnCode == TPI_ERROR_SUCCESS)\r
246         {\r
247                 if (_nFileCount != NULL)\r
248                 {\r
249                         * _nFileCount = int(::LocalSize(hMemory) / sizeof(fileInfo));\r
250                 }\r
251                 ::LocalFree(hMemory);\r
252         }\r
253 \r
254         return nReturnCode;\r
255 }\r
256 \r
257 int __stdcall OpenArchive\r
258 (\r
259         const wxString & _szArcName,\r
260         void * * _hArchive\r
261 )\r
262 {\r
263         FARPROC fpProc = ::GetProcAddress(g_hLib, "GetArchiveInfo");\r
264         if (fpProc == NULL)\r
265         {\r
266                 return TPI_ERROR_U_USE_LIBRARY;\r
267         }\r
268 \r
269         int nReturnCode = SpiErrorCodeConvert(((int (PASCAL *)(const char *, long, unsigned int, HLOCAL *)) fpProc)(_szArcName.ToUTF8(), 0, 0, _hArchive));\r
270         if (nReturnCode != TPI_ERROR_SUCCESS)\r
271         {\r
272                 return nReturnCode;\r
273         }\r
274 \r
275         return * _hArchive == NULL ? TPI_ERROR_IO_ARC_OPEN : nReturnCode;\r
276 }\r
277 \r
278 int __stdcall CloseArchive\r
279 (\r
280         void * _hArchive\r
281 )\r
282 {\r
283         return ::LocalFree(_hArchive) == NULL ? TPI_ERROR_SUCCESS : TPI_ERROR_IO_ARC_CLOSE;\r
284 }\r
285 \r
286 int __stdcall GetFileInformation\r
287 (\r
288         void * _hArchive,\r
289         TPI_FILEINFO * _fiInfo,\r
290         bool _bFirst\r
291 )\r
292 {\r
293         static unsigned int uFileCount, uFilePointer;\r
294 \r
295         if (_bFirst)\r
296         {\r
297                 uFilePointer = 0;\r
298                 uFileCount = (unsigned int) (::LocalSize(_hArchive) / sizeof(fileInfo));\r
299         }\r
300 \r
301         if (uFilePointer > uFileCount)\r
302         {\r
303                 return TPI_ERROR_S_ENDOFDATA;\r
304         }\r
305 \r
306         fileInfo pfiInfo = ((fileInfo *) ::LocalLock(_hArchive))[uFilePointer];\r
307         if (pfiInfo.method[0] == 0)\r
308         {\r
309                 // \92\9a\94J\82È\83v\83\89\83O\83C\83\93\82Ì\82½\82ß\82Ì\90\94\8d\87\82í\82¹ (^^;\r
310                 uFileCount = uFilePointer;\r
311                 return TPI_ERROR_S_ENDOFDATA;\r
312         }\r
313 \r
314         _fiInfo->dwAttribute    = 0;\r
315         _fiInfo->dwCRC32        = pfiInfo.crc;\r
316         _fiInfo->llPackedSize   = pfiInfo.compsize;\r
317         _fiInfo->llUnpackedSize = pfiInfo.filesize;\r
318         _fiInfo->wCompressRatio = pfiInfo.compsize >= pfiInfo.filesize ? 1000 : (WORD) (1000 * pfiInfo.compsize / pfiInfo.filesize);\r
319         _fiInfo->llFileID       = uFilePointer++;\r
320         _fiInfo->tmModified     = pfiInfo.timestamp;\r
321         _fiInfo->szStoredName   = MB2String(pfiInfo.path) + MB2String(pfiInfo.filename);\r
322         _fiInfo->fnFileName     = wxFileName(_fiInfo->szStoredName);\r
323         _fiInfo->szMethod       = MB2String((char *) pfiInfo.method);\r
324         _fiInfo->pCustomInfo    = (void *) pfiInfo.position;\r
325         ::LocalUnlock(_hArchive);\r
326 \r
327         return TPI_ERROR_SUCCESS;\r
328 }\r
329 \r
330 int __stdcall GetArchiveInformation\r
331 (\r
332         void *,\r
333         TPI_ARCHIVEINFO * _aiInfo\r
334 )\r
335 {\r
336         // GetPluginInfo\82ð\8eÀ\8ds\81B\r
337         FARPROC fpProc = ::GetProcAddress(g_hLib, "GetPluginInfo");\r
338         if (fpProc != NULL)\r
339         {\r
340                 char szTemp[20];\r
341                 if (((int (PASCAL *)(int, char *, int)) fpProc)(2, szTemp, sizeof(szTemp)) > 0)\r
342                 {\r
343                         _aiInfo->fiInfo.szSuffix = MB2String(szTemp);\r
344                 }\r
345                 if (((int (PASCAL *)(int, char *, int)) fpProc)(3, szTemp, sizeof(szTemp)) > 0)\r
346                 {\r
347                         _aiInfo->fiInfo.szTypeName = MB2String(szTemp);\r
348                 }\r
349         }\r
350         _aiInfo->fiInfo.szTPIName    = wxT("spiLibrary");\r
351         _aiInfo->fiInfo.llSupportedCommand = TPI_COMMAND_EXTRACT;\r
352 \r
353         return TPI_ERROR_SUCCESS;\r
354 }\r
355 \r
356 int __stdcall Command\r
357 (\r
358         unsigned int _uCommand,\r
359         TPI_SWITCHES * _swInfo,\r
360         const wxString & _szArcName,\r
361         const wxArrayString & _szFiles\r
362 )\r
363 {\r
364         if (_uCommand != TPI_COMMAND_EXTRACT)\r
365         {\r
366                 return TPI_ERROR_D_UNSUPPORTED;\r
367         }\r
368 \r
369         // \93W\8aJ\8f\88\97\9d\82Ì\82Ý\82ð\8ds\82¤\81B\r
370         FARPROC fpProc = ::GetProcAddress(g_hLib, "GetFile");\r
371         if (fpProc == NULL)\r
372         {\r
373                 return TPI_ERROR_U_USE_LIBRARY;\r
374         }\r
375 \r
376         // \8f\91\8cÉ\83n\83\93\83h\83\8b\82ð\8eæ\93¾\81B\r
377         void * hArchive;\r
378         int nErrorCode = OpenArchive(_szArcName, & hArchive);\r
379         if (nErrorCode != TPI_ERROR_SUCCESS)\r
380         {\r
381                 return nErrorCode;\r
382         }\r
383 \r
384         // \83R\81[\83\8b\83o\83b\83N\82ð\91\97\90M\81B\95Ö\8bX\8fã-1\82ð\91\97\90M\81B\r
385         wxFileName _fnArcName(_szArcName);\r
386         if (CallbackProc(-1, 0, (long) & _fnArcName))\r
387         {\r
388                 return TPI_ERROR_D_SKIPPED;\r
389         }\r
390 \r
391         // \8f\88\97\9d\8eÀ\8ds\81B\r
392         TPI_FILEINFO fiInfo;\r
393         nErrorCode = GetFileInformation(hArchive, & fiInfo, TRUE);\r
394         if (nErrorCode == TPI_ERROR_SUCCESS)\r
395         {\r
396                 do\r
397                 {\r
398                         // \83R\81[\83\8b\83o\83b\83N\82ð\91\97\90M\81B\r
399                         if (CallbackProc(0, fiInfo.llUnpackedSize.ToULong(), (long) & fiInfo.fnFileName))\r
400                         {\r
401                                 nErrorCode = TPI_ERROR_D_SKIPPED;\r
402                                 break;\r
403                         }\r
404 \r
405                         // \8f\88\97\9d\91Î\8fÛ\82©\82Ç\82¤\82©\94»\92è\81B\r
406                         if ((! _szFiles.IsEmpty()) && _szFiles.Index(fiInfo.szStoredName) == wxNOT_FOUND)\r
407                         {\r
408                                 continue;\r
409                         }\r
410 \r
411                         // \8fo\97Í\96¼\8dì\90¬\81B\r
412                         wxString szTargetPath = _swInfo->fnDestinationDirectory.GetPathWithSep();\r
413                         if (_swInfo->fStoreDirectoryPathes)\r
414                         {\r
415                                 // \93W\8aJ\90æ\83f\83B\83\8c\83N\83g\83\8a\82ð\8dì\90¬\81B\r
416                                 szTargetPath += fiInfo.fnFileName.GetFullPath();\r
417                                 wxFileName fnDest(szTargetPath);\r
418                                 if (! fnDest.Mkdir(0777, wxPATH_MKDIR_FULL) || ::wxDirExists(fnDest.GetFullPath()))\r
419                                 {\r
420                                         nErrorCode = TPI_ERROR_IO_DIR_WRITE;\r
421                                         break;\r
422                                 }\r
423                         }\r
424                         else\r
425                         {\r
426                                 szTargetPath += fiInfo.fnFileName.GetFullName();\r
427                         }\r
428 \r
429                         // \83t\83@\83C\83\8b\8fo\97Í\82É\82Í\91Î\89\9e\82µ\82Ä\82È\82¢\82Ì\82Å\83\81\83\82\83\8a\8fo\97Í\82Å\91ã\8ds\81B\r
430                         HLOCAL hMemory = NULL;\r
431                         nErrorCode = SpiErrorCodeConvert(((int (PASCAL *)(const char *, long, char *, unsigned int, FARPROC, long)) fpProc)(_szArcName.ToUTF8(), (long) fiInfo.pCustomInfo, (char *) & hMemory, 0x0100, (FARPROC) CallbackProc, (long) & fiInfo.fnFileName));\r
432                         if (nErrorCode == TPI_ERROR_SUCCESS && hMemory == NULL)\r
433                         {\r
434                                 nErrorCode = TPI_ERROR_UNDEFINED;\r
435                         }\r
436                         if (nErrorCode != TPI_ERROR_SUCCESS)\r
437                         {\r
438                                 break;\r
439                         }\r
440 \r
441                         // \93W\8aJ\90æ\82É\8fo\97Í\81B\r
442                         wxFile hFile;\r
443                         // \8b­\90§\8fã\8f\91\82«\82·\82é\82Ì\82Å\92\8d\88Ó\81B\r
444                         if (! hFile.Create(szTargetPath, true))\r
445                         {\r
446                                 nErrorCode = TPI_ERROR_IO_FILE_OPEN;\r
447                                 break;\r
448                         }\r
449 \r
450                         bool bErrorOccured = hFile.Write(::LocalLock(hMemory), (size_t) fiInfo.llUnpackedSize.GetValue()) != fiInfo.llUnpackedSize;\r
451                         ::LocalUnlock(hMemory);\r
452                         ::LocalFree(hMemory);\r
453                         hFile.Close();\r
454                         if (bErrorOccured)\r
455                         {\r
456                                 nErrorCode = TPI_ERROR_IO_FILE_WRITE;\r
457                                 break;\r
458                         }\r
459                         nErrorCode = TPI_ERROR_SUCCESS;\r
460 \r
461                         // \83R\81[\83\8b\83o\83b\83N\82ð\91\97\90M\81B\r
462                         if (CallbackProc(fiInfo.llUnpackedSize.ToULong(), fiInfo.llUnpackedSize.ToULong(), (long) & fiInfo.fnFileName))\r
463                         {\r
464                                 nErrorCode = TPI_ERROR_D_SKIPPED;\r
465                                 break;\r
466                         }\r
467                 }\r
468                 while ((nErrorCode = GetFileInformation(hArchive, & fiInfo, FALSE)) != TPI_ERROR_S_ENDOFDATA);\r
469                 if (nErrorCode == TPI_ERROR_S_ENDOFDATA)\r
470                 {\r
471                         // \8fI\92[\82É\92B\82µ\82½\8fê\8d\87\81B\r
472                         nErrorCode = TPI_ERROR_SUCCESS;\r
473                 }\r
474         }\r
475         CloseArchive(hArchive);\r
476 \r
477         return nErrorCode;\r
478 }\r
479 \r
480 int __stdcall SetCallbackProc\r
481 (\r
482         TPI_PROC _prArcProc\r
483 )\r
484 {\r
485         // \83|\83C\83\93\83^\82ð\95Û\91\81B\r
486         if (_prArcProc == NULL)\r
487         {\r
488                 return TPI_ERROR_D_PARAMETER;\r
489         }\r
490         g_prProc = * _prArcProc;\r
491 \r
492         return TPI_ERROR_SUCCESS;\r
493 }\r
494 \r
495 #ifdef __cplusplus\r
496 }\r
497 #endif\r