OSDN Git Service

展開したファイルのサイズが常に0バイトになるバグを修正。
[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         // \8d\\91¢\91Ì\82ð\8f\89\8aú\89»\81B\r
64         TPI_PROCESSINFO * piInfo = (TPI_PROCESSINFO *) _lData;\r
65         piInfo->llProcessedSize = _nNow;\r
66 \r
67         // \83R\81[\83\8b\83o\83b\83N\8aÖ\90\94\82É\91\97\90M\81B\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,\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\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         bool b = fs.GetFirst(& szSPIName, wxT("*.spi"));\r
141         while (b)\r
142         {\r
143                 // SPI\82ð\83\8d\81[\83h\81B\r
144                 wxString szLibName = szSPIPath + szSPIName;\r
145                 g_hLib = ::LoadLibrary(szLibName.wchar_str());\r
146                 if (g_hLib == NULL)\r
147                 {\r
148                         b = fs.GetNext(& szSPIName);\r
149                         continue;\r
150                 }\r
151 \r
152                 // GetPluginInfo\82ð\8eÀ\8ds\81B\r
153                 FARPROC fpProc = ::GetProcAddress(g_hLib, "GetPluginInfo");\r
154                 char szPluginType[5]; // \8eí\97Þ4bytes + NULL\r
155                 if (fpProc == NULL\r
156                         || ((int (PASCAL *)(int, char *, int)) fpProc)(0, szPluginType, sizeof(szPluginType)) < 0\r
157                         || szPluginType[2] != 'A' || szPluginType[3] != 'M')\r
158                 {\r
159                         ::FreeLibrary(g_hLib);\r
160                         b = fs.GetNext(& szSPIName);\r
161                         continue;\r
162                 }\r
163 \r
164                 // \8f\91\8cÉ\82É\91Î\89\9e\82µ\82Ä\82¢\82é\82©\83`\83F\83b\83N\81B\r
165                 if (CheckArchive(_szArcName, NULL) == TPI_ERROR_SUCCESS)\r
166                 {\r
167                         // \91Î\89\9e\82µ\82Ä\82¢\82ê\82Î\8f\88\97\9d\82ð\8fI\97¹\81B\r
168                         return TPI_ERROR_SUCCESS;\r
169                 }\r
170 \r
171                 b = fs.GetNext(& szSPIName);\r
172         }\r
173         return TPI_ERROR_U_LOAD_LIBRARY;\r
174 }\r
175 \r
176 int __stdcall FreePlugin\r
177 (\r
178         void * // _pReserved\r
179 )\r
180 {\r
181         ::FreeLibrary(g_hLib);\r
182         return TPI_ERROR_SUCCESS;\r
183 }\r
184 \r
185 int __stdcall CheckArchive\r
186 (\r
187         const wxString & _szArcName,\r
188         int * _nFileCount\r
189 )\r
190 {\r
191         FARPROC fpProc = ::GetProcAddress(g_hLib, "IsSupported");\r
192         if (fpProc == NULL)\r
193         {\r
194                 return TPI_ERROR_U_USE_LIBRARY;\r
195         }\r
196 \r
197         wxFile hFile(_szArcName, wxFile::read);\r
198         if (! hFile.IsOpened())\r
199         {\r
200                 return TPI_ERROR_IO_ARC_OPEN;\r
201         }\r
202 \r
203         char buffer[2050];\r
204         ::ZeroMemory(buffer, sizeof(buffer));\r
205         if (hFile.Read(buffer, sizeof(buffer)) == wxInvalidOffset)\r
206         {\r
207                 hFile.Close();\r
208                 return TPI_ERROR_IO_ARC_READ;\r
209         }\r
210 \r
211         if (! ((BOOL (PASCAL *)(const char *, unsigned long)) fpProc)(_szArcName.ToUTF8(), (unsigned long) buffer))\r
212         {\r
213                 hFile.Close();\r
214                 return TPI_ERROR_D_UNSUPPORTED;\r
215         }\r
216         hFile.Close();\r
217 \r
218         fpProc = ::GetProcAddress(g_hLib, "GetArchiveInfo");\r
219         if (fpProc == NULL)\r
220         {\r
221                 return TPI_ERROR_U_USE_LIBRARY;\r
222         }\r
223 \r
224         HLOCAL hMemory;\r
225         int nReturnCode = ErrorCodeConvert(((int (PASCAL *)(const char *, long, unsigned int, HLOCAL *)) fpProc)(_szArcName.ToUTF8(), 0, 0, & hMemory));\r
226         if (nReturnCode == TPI_ERROR_SUCCESS)\r
227         {\r
228                 if (_nFileCount != NULL)\r
229                 {\r
230                         * _nFileCount = int(::LocalSize(hMemory) / sizeof(fileInfo));\r
231                 }\r
232                 ::LocalFree(hMemory);\r
233         }\r
234 \r
235         return nReturnCode;\r
236 }\r
237 \r
238 int __stdcall OpenArchive\r
239 (\r
240         const wxString & _szArcName,\r
241         void * * _hArchive\r
242 )\r
243 {\r
244         FARPROC fpProc = ::GetProcAddress(g_hLib, "GetArchiveInfo");\r
245         if (fpProc == NULL)\r
246         {\r
247                 return TPI_ERROR_U_USE_LIBRARY;\r
248         }\r
249 \r
250         int nReturnCode = ErrorCodeConvert(((int (PASCAL *)(const char *, long, unsigned int, HLOCAL *)) fpProc)(_szArcName.ToUTF8(), 0, 0, _hArchive));\r
251         if (nReturnCode != TPI_ERROR_SUCCESS)\r
252         {\r
253                 return nReturnCode;\r
254         }\r
255 \r
256         return * _hArchive == NULL ? TPI_ERROR_IO_ARC_OPEN : nReturnCode;\r
257 }\r
258 \r
259 int __stdcall CloseArchive\r
260 (\r
261         void * _hArchive\r
262 )\r
263 {\r
264         return ::LocalFree(_hArchive) == NULL ? TPI_ERROR_SUCCESS : TPI_ERROR_IO_ARC_CLOSE;\r
265 }\r
266 \r
267 int __stdcall GetFileInformation\r
268 (\r
269         void * _hArchive,\r
270         TPI_FILEINFO * _fiInfo,\r
271         bool _bFirst\r
272 )\r
273 {\r
274         static unsigned int uFileCount, uFilePointer;\r
275 \r
276         if (_bFirst)\r
277         {\r
278                 uFilePointer = 0;\r
279                 uFileCount = (unsigned int) (::LocalSize(_hArchive) / sizeof(fileInfo));\r
280         }\r
281 \r
282         if (uFilePointer > uFileCount)\r
283         {\r
284                 return TPI_ERROR_S_ENDOFDATA;\r
285         }\r
286 \r
287         fileInfo pfiInfo = ((fileInfo *) ::LocalLock(_hArchive))[uFilePointer];\r
288         if (pfiInfo.method[0] == 0)\r
289         {\r
290                 // \92\9a\94J\82È\83v\83\89\83O\83C\83\93\82Ì\82½\82ß\82Ì\90\94\8d\87\82í\82¹ (^^;\r
291                 uFileCount = uFilePointer;\r
292                 return TPI_ERROR_S_ENDOFDATA;\r
293         }\r
294 \r
295         _fiInfo->dwAttribute    = 0;\r
296         _fiInfo->dwCRC32        = pfiInfo.crc;\r
297         _fiInfo->llPackedSize   = pfiInfo.compsize;\r
298         _fiInfo->llUnpackedSize = pfiInfo.filesize;\r
299         _fiInfo->wCompressRatio = pfiInfo.compsize >= pfiInfo.filesize ? 1000 : (WORD) (1000 * pfiInfo.compsize / pfiInfo.filesize);\r
300         _fiInfo->llFileID       = uFilePointer++;\r
301         _fiInfo->tmModified     = pfiInfo.timestamp;\r
302         _fiInfo->szStoredName   = MB2String(pfiInfo.path) + MB2String(pfiInfo.filename);\r
303         _fiInfo->fnFileName     = wxFileName(_fiInfo->szStoredName);\r
304         _fiInfo->szMethod       = MB2String((char *) pfiInfo.method);\r
305         _fiInfo->pCustomInfo    = (void *) pfiInfo.position;\r
306         ::LocalUnlock(_hArchive);\r
307 \r
308         return TPI_ERROR_SUCCESS;\r
309 }\r
310 \r
311 int __stdcall GetArchiveInformation\r
312 (\r
313         void *,\r
314         TPI_ARCHIVEINFO * _aiInfo\r
315 )\r
316 {\r
317         // GetPluginInfo\82ð\8eÀ\8ds\81B\r
318         FARPROC fpProc = ::GetProcAddress(g_hLib, "GetPluginInfo");\r
319         if (fpProc != NULL)\r
320         {\r
321                 char szTemp[20];\r
322                 if (((int (PASCAL *)(int, char *, int)) fpProc)(2, szTemp, sizeof(szTemp)) > 0)\r
323                 {\r
324                         _aiInfo->fiInfo.szSuffix = MB2String(szTemp);\r
325                 }\r
326                 if (((int (PASCAL *)(int, char *, int)) fpProc)(3, szTemp, sizeof(szTemp)) > 0)\r
327                 {\r
328                         _aiInfo->fiInfo.szTypeName = MB2String(szTemp);\r
329                 }\r
330         }\r
331         _aiInfo->fiInfo.szTPIName = wxT("spiLibrary");\r
332         _aiInfo->fiInfo.llSupportedCommand = TPI_COMMAND_EXTRACT;\r
333 \r
334         return TPI_ERROR_SUCCESS;\r
335 }\r
336 \r
337 int __stdcall Command\r
338 (\r
339         unsigned int _uCommand,\r
340         TPI_SWITCHES * _swInfo,\r
341         const wxString & _szArcName,\r
342         const wxArrayString & _szFiles\r
343 )\r
344 {\r
345         if (_uCommand != TPI_COMMAND_EXTRACT)\r
346         {\r
347                 return TPI_ERROR_D_UNSUPPORTED;\r
348         }\r
349 \r
350         // \93W\8aJ\8f\88\97\9d\82Ì\82Ý\82ð\8ds\82¤\81B\r
351         FARPROC fpProc = ::GetProcAddress(g_hLib, "GetFile");\r
352         if (fpProc == NULL)\r
353         {\r
354                 return TPI_ERROR_U_USE_LIBRARY;\r
355         }\r
356 \r
357         // \8f\91\8cÉ\83n\83\93\83h\83\8b\82ð\8eæ\93¾\81B\r
358         void * hArchive;\r
359         int nErrorCode = OpenArchive(_szArcName, & hArchive);\r
360         if (nErrorCode != TPI_ERROR_SUCCESS)\r
361         {\r
362                 return nErrorCode;\r
363         }\r
364 \r
365         // \83R\81[\83\8b\83o\83b\83N\82ð\91\97\90M\81B\r
366         wxFileName _fnArcName(_szArcName);\r
367         TPI_PROCESSINFO piInfo;\r
368         piInfo.uMessage = TPI_MESSAGE_STATUS;\r
369         piInfo.uStatus  = TPI_STATUS_OPENARCHIVE;\r
370         piInfo.fiInfo.fnFileName = _fnArcName;\r
371         if (CallbackProc(0, 0, (long) & piInfo))\r
372         {\r
373                 return TPI_ERROR_D_SKIPPED;\r
374         }\r
375 \r
376         // \8f\88\97\9d\8eÀ\8ds\81B\r
377         piInfo.uStatus = TPI_STATUS_INPROCESS;\r
378         nErrorCode = GetFileInformation(hArchive, & piInfo.fiInfo, TRUE);\r
379         if (nErrorCode == TPI_ERROR_SUCCESS)\r
380         {\r
381                 do\r
382                 {\r
383                         // \83R\81[\83\8b\83o\83b\83N\82ð\91\97\90M\81B\r
384                         piInfo.uStatus = TPI_STATUS_BEGINPROCESS;\r
385                         if (CallbackProc(0, 0, (long) & piInfo))\r
386                         {\r
387                                 nErrorCode = TPI_ERROR_D_SKIPPED;\r
388                                 break;\r
389                         }\r
390                         piInfo.uStatus = TPI_STATUS_INPROCESS;\r
391 \r
392                         // \8f\88\97\9d\91Î\8fÛ\82©\82Ç\82¤\82©\94»\92è\81B\r
393                         if ((! _szFiles.IsEmpty()) && _szFiles.Index(piInfo.fiInfo.szStoredName) == wxNOT_FOUND)\r
394                         {\r
395                                 continue;\r
396                         }\r
397 \r
398                         // \8fo\97Í\96¼\8dì\90¬\81B\r
399                         wxString szTargetPath = _swInfo->fnDestinationDirectory.GetPathWithSep();\r
400                         if (_swInfo->fStoreDirectoryPathes)\r
401                         {\r
402                                 // \93W\8aJ\90æ\83f\83B\83\8c\83N\83g\83\8a\82ð\8dì\90¬\81B\r
403                                 szTargetPath += piInfo.fiInfo.fnFileName.GetFullPath();\r
404                                 wxFileName fnDest(szTargetPath);\r
405                                 if (! fnDest.Mkdir(0777, wxPATH_MKDIR_FULL) || ::wxDirExists(fnDest.GetFullPath()))\r
406                                 {\r
407                                         nErrorCode = TPI_ERROR_IO_DIR_WRITE;\r
408                                         break;\r
409                                 }\r
410                         }\r
411                         else\r
412                         {\r
413                                 szTargetPath += piInfo.fiInfo.fnFileName.GetFullName();\r
414                         }\r
415 \r
416                         // \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
417                         HLOCAL hMemory = NULL;\r
418                         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
419                         if (nErrorCode == TPI_ERROR_SUCCESS && hMemory == NULL)\r
420                         {\r
421                                 nErrorCode = TPI_ERROR_UNDEFINED;\r
422                         }\r
423                         if (nErrorCode != TPI_ERROR_SUCCESS)\r
424                         {\r
425                                 break;\r
426                         }\r
427 \r
428                         // \93W\8aJ\90æ\82É\8fo\97Í\81B\r
429                         wxFile hFile;\r
430                         // \8b­\90§\8fã\8f\91\82«\82·\82é\82Ì\82Å\92\8d\88Ó\81B\r
431                         if (! hFile.Create(szTargetPath, true))\r
432                         {\r
433                                 nErrorCode = TPI_ERROR_IO_FILE_OPEN;\r
434                                 break;\r
435                         }\r
436 \r
437                         bool bErrorOccured = hFile.Write(::LocalLock(hMemory), (size_t) piInfo.fiInfo.llUnpackedSize.GetValue()) != piInfo.fiInfo.llUnpackedSize;\r
438                         ::LocalUnlock(hMemory);\r
439                         ::LocalFree(hMemory);\r
440                         hFile.Close();\r
441                         if (bErrorOccured)\r
442                         {\r
443                                 nErrorCode = TPI_ERROR_IO_FILE_WRITE;\r
444                                 break;\r
445                         }\r
446                         nErrorCode = TPI_ERROR_SUCCESS;\r
447 \r
448                         // \83R\81[\83\8b\83o\83b\83N\82ð\91\97\90M\81B\r
449                         piInfo.uStatus = TPI_STATUS_ENDPROCESS;\r
450                         if (CallbackProc(0, 0, (long) & piInfo))\r
451                         {\r
452                                 nErrorCode = TPI_ERROR_D_SKIPPED;\r
453                                 break;\r
454                         }\r
455                 }\r
456                 while ((nErrorCode = GetFileInformation(hArchive, & piInfo.fiInfo, FALSE)) != TPI_ERROR_S_ENDOFDATA);\r
457                 if (nErrorCode == TPI_ERROR_S_ENDOFDATA)\r
458                 {\r
459                         // \8fI\92[\82É\92B\82µ\82½\8fê\8d\87\81B\r
460                         nErrorCode = TPI_ERROR_SUCCESS;\r
461                 }\r
462         }\r
463         CloseArchive(hArchive);\r
464 \r
465         return nErrorCode;\r
466 }\r
467 \r
468 int __stdcall SetCallbackProc\r
469 (\r
470         TPI_PROC _prArcProc\r
471 )\r
472 {\r
473         // \83|\83C\83\93\83^\82ð\95Û\91\81B\r
474         if (_prArcProc == NULL)\r
475         {\r
476                 return TPI_ERROR_D_PARAMETER;\r
477         }\r
478         g_prProc = * _prArcProc;\r
479 \r
480         return TPI_ERROR_SUCCESS;\r
481 }\r
482 \r
483 #ifdef __cplusplus\r
484 }\r
485 #endif\r