OSDN Git Service

763338464a0b9e75c781b28059b7c19ce47bb765
[tpi/lychee.git] / src / plugin / rarArc / rarArc.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 wxUSE_DYNLIB_CLASS 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/dynlib.h>\r
31 #include "rarArc.h"\r
32 \r
33 //******************************************************************************\r
34 //    Global varients\r
35 //******************************************************************************\r
36 \r
37 wxDynamicLibrary g_hLib;\r
38 TPI_PROC g_prProc;\r
39 char g_szComment[64001];\r
40 RAROpenArchiveDataEx g_oaInfo;\r
41 \r
42 //******************************************************************************\r
43 //    Callback Wrapper\r
44 //******************************************************************************\r
45 \r
46 int __stdcall CallbackProc(unsigned int msg, long p, long P1, long P2)\r
47 {\r
48         // 構造体を初期化。\r
49         static TPI_PROCESSINFO pi;\r
50         TPI_PROCESSINFO * piInfo = p == 0 ? & pi : (TPI_PROCESSINFO *) p;\r
51 \r
52         switch (msg)\r
53         {\r
54         case UCM_CHANGEVOLUME:\r
55                 switch (P2)\r
56                 {\r
57                 case RAR_VOL_ASK:\r
58                         // 分割書庫の次の部分を要求。\r
59                         piInfo->eMessage = TPI_MESSAGE_ASK;\r
60                         piInfo->eStatus  = TPI_PARAM_NEXTVOLUME;\r
61                         piInfo->szParam.Empty();\r
62                         break;\r
63                 case RAR_VOL_NOTIFY:\r
64                         // 分割部分の読み込みを開始。\r
65                         piInfo->eMessage = TPI_MESSAGE_STATUS;\r
66                         piInfo->eStatus  = TPI_STATUS_OPENARCHIVE;\r
67                         piInfo->fiInfo.fnFileName = wxFileName(UTF82String((char *) P1));\r
68                         break;\r
69                 default:\r
70                         return 1;\r
71                 }\r
72                 break;\r
73         case UCM_PROCESSDATA:\r
74                 piInfo->eMessage = TPI_MESSAGE_STATUS;\r
75                 piInfo->eStatus  = TPI_STATUS_INPROCESS;\r
76                 piInfo->nProcessedSize += P2;\r
77                 break;\r
78         case UCM_NEEDPASSWORD:\r
79                 piInfo->eMessage = TPI_MESSAGE_ASK;\r
80                 piInfo->eStatus  = TPI_PARAM_PASSWORD;\r
81                 piInfo->szParam.Empty();\r
82                 break;\r
83         default:\r
84                 return 1;\r
85         }\r
86 \r
87         // コールバック関数に送信。\r
88         if (g_prProc == NULL || g_prProc(TPI_NOTIFY_COMMON, piInfo) == TPI_CALLBACK_CONTINUE)\r
89         {\r
90                 if (msg != UCM_PROCESSDATA && P2 != RAR_VOL_NOTIFY)\r
91                 {\r
92                         strncpy((char *) P1, piInfo->szParam.char_str(), (msg == UCM_CHANGEVOLUME ? 1024 : P2) - 1);\r
93                 }\r
94                 return 1;\r
95         }\r
96         else\r
97         {\r
98                 return -1;\r
99         }\r
100 }\r
101 \r
102 //******************************************************************************\r
103 //    Inside Functions\r
104 //******************************************************************************\r
105 \r
106 int ErrorCodeConvert(int nErrorCode)\r
107 {\r
108         switch (nErrorCode)\r
109         {\r
110         case 0:                     return TPI_ERROR_SUCCESS;\r
111         case 1:                     return TPI_ERROR_SUCCESS;\r
112         case ERAR_END_ARCHIVE:      return TPI_ERROR_S_ENDOFDATA;\r
113         case ERAR_NO_MEMORY:        return TPI_ERROR_D_OUTOFMEMORY;\r
114         case ERAR_BAD_DATA:         return TPI_ERROR_ARC_BROKEN_MISC;\r
115         case ERAR_BAD_ARCHIVE:      return TPI_ERROR_ARC_UNSUPPORTED;\r
116         case ERAR_UNKNOWN_FORMAT:   return TPI_ERROR_ARC_ENCRYPTED;\r
117         case ERAR_EOPEN:            return TPI_ERROR_IO_ARC_OPEN;\r
118         case ERAR_ECREATE:          return TPI_ERROR_IO_FILE_OPEN;\r
119         case ERAR_ECLOSE:           return TPI_ERROR_IO_CLOSE;\r
120         case ERAR_EREAD:            return TPI_ERROR_IO_ARC_READ;\r
121         case ERAR_EWRITE:           return TPI_ERROR_IO_FILE_WRITE;\r
122         case ERAR_SMALL_BUF:        return TPI_ERROR_UNDEFINED;\r
123         case ERAR_UNKNOWN:          return TPI_ERROR_UNDEFINED;\r
124         case ERAR_MISSING_PASSWORD: return TPI_ERROR_ARC_ENCRYPTED;\r
125         default:                    return TPI_ERROR_UNDEFINED;\r
126         }\r
127 }\r
128 \r
129 //******************************************************************************\r
130 //    Functions\r
131 //******************************************************************************\r
132 \r
133 #ifdef __cplusplus\r
134 extern "C"\r
135 {\r
136 #endif\r
137 \r
138 int __stdcall GetPluginInformation\r
139 (\r
140         unsigned int _uInfoId,\r
141         wxULongLong_t,\r
142         void * _pPtr\r
143 )\r
144 {\r
145         if (_pPtr == NULL)\r
146         {\r
147                 return TPI_ERROR_D_PARAMETER;\r
148         }\r
149         switch (_uInfoId)\r
150         {\r
151         case TPI_INFO_VERSION_MAJOR:\r
152         case TPI_INFO_VERSION_MINOR:\r
153                 * (int *) _pPtr = 0;\r
154                 break;\r
155         case TPI_INFO_VERSION_API:\r
156                 * (int *) _pPtr = 2;\r
157                 break;\r
158         case TPI_INFO_HANDLE_ON_COMMAND:\r
159                 * (int *) _pPtr = 0;\r
160                 break;\r
161         default:\r
162                 return TPI_ERROR_D_UNSUPPORTED;\r
163         }\r
164         return TPI_ERROR_SUCCESS;\r
165 }\r
166 \r
167 int __stdcall GetFormatInformation(TPI_FORMATINFO * _fiInfo, bool _bFirst)\r
168 {\r
169         if (! _bFirst)\r
170         {\r
171                 return TPI_ERROR_S_ENDOFDATA;\r
172         }\r
173 \r
174         _fiInfo->szTypeName   = wxT("RAR");\r
175         _fiInfo->szSuffix     = wxT("rar");\r
176         _fiInfo->szEngineName = g_hLib.CanonicalizeName(wxT("unrar"));\r
177         _fiInfo->szTPIName    = wxT("rarArc");\r
178         _fiInfo->nTypeId      = 0;\r
179         _fiInfo->eSupportedCommand = TPI_COMMAND_EXTRACT | TPI_COMMAND_TEST;\r
180         _fiInfo->fArchive     = true;\r
181         _fiInfo->fComment     = true;\r
182         _fiInfo->fSFX         = true;\r
183         _fiInfo->fSolid       = true;\r
184         _fiInfo->fEncryptPassword = true;\r
185         _fiInfo->fMultiVolume = true;\r
186 \r
187         return TPI_ERROR_SUCCESS;\r
188 }\r
189 \r
190 int __stdcall LoadPlugin\r
191 (\r
192         const wxString &,\r
193         TPI_PROC _prProc,\r
194         wxULongLong_t\r
195 )\r
196 {\r
197         ::RemoveCwdFromSearchPath();\r
198         g_hLib.Load(g_hLib.CanonicalizeName(wxT("unrar")), wxDL_QUIET);\r
199         if (! g_hLib.IsLoaded())\r
200         {\r
201                 g_hLib.Unload();\r
202                 return TPI_ERROR_U_LOAD_LIBRARY;\r
203         }\r
204 \r
205         // コールバック関数を設定。\r
206         if (_prProc != NULL)\r
207         {\r
208                 g_prProc = * _prProc;\r
209         }\r
210         return TPI_ERROR_SUCCESS;\r
211 }\r
212 \r
213 int __stdcall FreePlugin\r
214 (\r
215         void * // _pReserved\r
216 )\r
217 {\r
218         g_hLib.Unload();\r
219         return TPI_ERROR_SUCCESS;\r
220 }\r
221 \r
222 int __stdcall OpenArchive\r
223 (\r
224         const wxString & _szArcName,\r
225         void * * _hArchive,\r
226         wxULongLong_t *\r
227 )\r
228 {\r
229         if (! g_hLib.HasSymbol(wxT("RAROpenArchiveEx")))\r
230         {\r
231                 return TPI_ERROR_U_USE_LIBRARY;\r
232         }\r
233         void * p = g_hLib.GetSymbol(wxT("RAROpenArchiveEx"));\r
234         if (! p)\r
235         {\r
236                 return TPI_ERROR_U_USE_LIBRARY;\r
237         }\r
238 \r
239         memset(& g_oaInfo, 0, sizeof(g_oaInfo));\r
240         g_oaInfo.ArcName    = NULL;\r
241 //      g_oaInfo.ArcNameW   = _szArcName.wchar_str();\r
242         g_oaInfo.ArcNameW   = (wchar_t *) malloc((_szArcName.Len() + 1) * sizeof(wchar_t));\r
243         wcscpy(g_oaInfo.ArcNameW, _szArcName.wchar_str());\r
244         g_oaInfo.OpenMode   = RAR_OM_LIST;\r
245         g_oaInfo.CmtBuf     = g_szComment;\r
246         g_oaInfo.CmtBufSize = sizeof(g_szComment) - 1;\r
247         g_oaInfo.Callback   = CallbackProc;\r
248         * _hArchive = ((void * (__stdcall *)(RAROpenArchiveDataEx *)) p)(& g_oaInfo);\r
249         free(g_oaInfo.ArcNameW);\r
250         return * _hArchive == NULL ? TPI_ERROR_UNDEFINED : ErrorCodeConvert(g_oaInfo.OpenResult);\r
251 }\r
252 \r
253 int __stdcall CloseArchive\r
254 (\r
255         void * _hArchive\r
256 )\r
257 {\r
258         if (! g_hLib.HasSymbol(wxT("RARCloseArchive")))\r
259         {\r
260                 return TPI_ERROR_U_USE_LIBRARY;\r
261         }\r
262         void * p = g_hLib.GetSymbol(wxT("RARCloseArchive"));\r
263         return (! p || _hArchive == NULL) ? TPI_ERROR_U_USE_LIBRARY : ErrorCodeConvert(((int (__stdcall *)(void *)) p)(_hArchive));\r
264 }\r
265 \r
266 int __stdcall GetFileInformation\r
267 (\r
268         void * _hArchive,\r
269         TPI_FILEINFO * _fiInfo,\r
270         bool _bFirst\r
271 )\r
272 {\r
273         static wxULongLong_t s_nFileId;\r
274         static void * pR, * pP;\r
275         int nErrorCode;\r
276 \r
277         if (_bFirst)\r
278         {\r
279                 s_nFileId = 0;\r
280                 pR = g_hLib.HasSymbol(wxT("RARReadHeaderEx")) ? g_hLib.GetSymbol(wxT("RARReadHeaderEx")) : NULL;\r
281                 pP = g_hLib.HasSymbol(wxT("RARProcessFileW")) ? g_hLib.GetSymbol(wxT("RARProcessFileW")) : NULL;\r
282                 if (! pR || ! pP)\r
283                 {\r
284                         return TPI_ERROR_U_USE_LIBRARY;\r
285                 }\r
286         }\r
287 \r
288         RARHeaderDataEx hdInfo;\r
289         char szComment[64001];\r
290         hdInfo.CmtBuf     = szComment;\r
291         hdInfo.CmtBufSize = sizeof(szComment) - 1;\r
292         nErrorCode = ErrorCodeConvert(((int (__stdcall *)(void *, RARHeaderDataEx *)) pR)(_hArchive, & hdInfo));\r
293         if (nErrorCode == TPI_ERROR_SUCCESS)\r
294         {\r
295                 if (hdInfo.HostOS == 3)\r
296                 {\r
297                         _fiInfo->wPermission = hdInfo.FileAttr;\r
298                 }\r
299                 else\r
300                 {\r
301                         _fiInfo->dwAttribute = hdInfo.FileAttr;\r
302                 }\r
303                 if (hdInfo.Flags & 0x04)\r
304                 {\r
305                         _fiInfo->dwAttribute |= TPI_ATTRIBUTE_ENCRYPTED;\r
306                 }\r
307                 _fiInfo->dwCRC32        = hdInfo.FileCRC;\r
308                 _fiInfo->nPackedSize    = hdInfo.PackSizeHigh;\r
309                 _fiInfo->nPackedSize    = _fiInfo->nPackedSize << 32;\r
310                 _fiInfo->nPackedSize   += hdInfo.PackSize;\r
311                 _fiInfo->nUnpackedSize  = hdInfo.UnpSizeHigh;\r
312                 _fiInfo->nUnpackedSize  = _fiInfo->nUnpackedSize << 32;\r
313                 _fiInfo->nUnpackedSize += hdInfo.UnpSize;\r
314                 _fiInfo->tmModify.SetFromDOS(hdInfo.FileTime);\r
315                 _fiInfo->eOSType        = hdInfo.HostOS;\r
316                 _fiInfo->szStoredName   = WC2String(hdInfo.FileNameW);\r
317                 _fiInfo->szMethod.Printf(wxT("%x"), hdInfo.Method);\r
318                 _fiInfo->szComment      = UTF82String(hdInfo.CmtBuf);\r
319                 _fiInfo->nFileId        = s_nFileId++;\r
320                 _fiInfo->fnFileName     = wxFileName(_fiInfo->szStoredName);\r
321 \r
322                 // 次のファイルへ。\r
323                 nErrorCode = ErrorCodeConvert(((int (__stdcall *)(void *, int, wchar_t *, wchar_t *)) pP)(_hArchive, RAR_SKIP, NULL, NULL));\r
324         }\r
325 \r
326         return nErrorCode;\r
327 }\r
328 \r
329 int __stdcall GetArchiveInformation\r
330 (\r
331         void *,\r
332         TPI_ARCHIVEINFO * _aiInfo\r
333 )\r
334 {\r
335         _aiInfo->fSolid         = (g_oaInfo.Flags & 0x0008) == 1;\r
336         _aiInfo->fEncryptHeader = (g_oaInfo.Flags & 0x0080) == 1;\r
337         _aiInfo->szComment      = UTF82String(g_szComment);\r
338         GetFormatInformation(& _aiInfo->fiInfo, true);\r
339         return TPI_ERROR_SUCCESS;\r
340 }\r
341 \r
342 int __stdcall Command\r
343 (\r
344         wxULongLong_t _eCommand,\r
345         TPI_SWITCHES * _swInfo,\r
346         void *,// _hArchive,\r
347         const wxArrayString & _szFiles\r
348 )\r
349 {\r
350         if (_eCommand != TPI_COMMAND_EXTRACT && _eCommand != TPI_COMMAND_TEST)\r
351         {\r
352                 return TPI_ERROR_U_USE_LIBRARY;\r
353         }\r
354 \r
355         // 開きなおす。\r
356         if (! g_hLib.HasSymbol(wxT("RAROpenArchiveEx")))\r
357         {\r
358                 return TPI_ERROR_U_USE_LIBRARY;\r
359         }\r
360         void * p = g_hLib.GetSymbol(wxT("RAROpenArchiveEx"));\r
361         if (! p)\r
362         {\r
363                 return TPI_ERROR_U_USE_LIBRARY;\r
364         }\r
365 \r
366         TPI_PROCESSINFO piInfo;\r
367         piInfo.eMessage = TPI_MESSAGE_STATUS;\r
368         piInfo.eStatus  = TPI_STATUS_OPENARCHIVE;\r
369         piInfo.fiInfo.fnFileName = wxFileName(_swInfo->szArcName);\r
370         if (g_prProc != NULL && g_prProc(TPI_NOTIFY_COMMON, & piInfo) != TPI_CALLBACK_CONTINUE)\r
371         {\r
372                 return TPI_ERROR_D_SKIPPED;\r
373         }\r
374         RAROpenArchiveDataEx oaInfo;\r
375         memset(& oaInfo, 0, sizeof(oaInfo));\r
376         oaInfo.ArcName    = NULL;\r
377 //      oaInfo.ArcNameW   = _swInfo->szArcName.wchar_str();\r
378         oaInfo.ArcNameW   = (wchar_t *) malloc((_swInfo->szArcName.Len() + 1) * sizeof(wchar_t));\r
379         wcscpy(oaInfo.ArcNameW, _swInfo->szArcName.wchar_str());\r
380         oaInfo.OpenMode   = RAR_OM_EXTRACT;\r
381         oaInfo.CmtBufSize = 0;\r
382         oaInfo.Callback   = CallbackProc;\r
383         oaInfo.UserData   = (long) & piInfo;\r
384         void * hArc = ((void * (__stdcall *)(RAROpenArchiveDataEx *)) p)(& oaInfo);\r
385         free(oaInfo.ArcNameW);\r
386         if (hArc == NULL)\r
387         {\r
388                 return TPI_ERROR_UNDEFINED;\r
389         }\r
390         int nErrorCode = ErrorCodeConvert(oaInfo.OpenResult);\r
391         if (nErrorCode != TPI_ERROR_SUCCESS)\r
392         {\r
393                 return nErrorCode;\r
394         }\r
395 \r
396         void\r
397                 * pS = g_hLib.HasSymbol(wxT("RARSetPassword"))  ? g_hLib.GetSymbol(wxT("RARSetPassword"))  : NULL,\r
398                 * pR = g_hLib.HasSymbol(wxT("RARReadHeaderEx")) ? g_hLib.GetSymbol(wxT("RARReadHeaderEx")) : NULL,\r
399                 * pP = g_hLib.HasSymbol(wxT("RARProcessFileW")) ? g_hLib.GetSymbol(wxT("RARProcessFileW")) : NULL;\r
400         if (! pR || ! pP)\r
401         {\r
402                 CloseArchive(hArc);\r
403                 return TPI_ERROR_U_USE_LIBRARY;\r
404         }\r
405         if (pS)\r
406         {\r
407                 ((void (__stdcall *)(void *, char *)) pS)(hArc, _swInfo->szPassword.char_str());\r
408         }\r
409 \r
410         RARHeaderDataEx hdInfo;\r
411         while (nErrorCode == TPI_ERROR_SUCCESS && ErrorCodeConvert(((int (__stdcall *)(void *, RARHeaderDataEx *)) pR)(hArc, & hdInfo)) == TPI_ERROR_SUCCESS)\r
412         {\r
413                 piInfo.fiInfo.fnFileName     = wxFileName(WC2String(hdInfo.FileNameW));\r
414                 piInfo.fnDestination         = wxFileName(_swInfo->fnDestinationDirectory.GetPathWithSep() + (_swInfo->fStoreDirectoryPathes ? piInfo.fiInfo.fnFileName.GetFullPath() : piInfo.fiInfo.fnFileName.GetFullName()));\r
415                 bool bSkip = _szFiles.GetCount() != 0 && _szFiles.Index(piInfo.fiInfo.fnFileName.GetFullPath()) == wxNOT_FOUND;\r
416                 if (! bSkip && _eCommand == TPI_COMMAND_EXTRACT)\r
417                 {\r
418                         // 処理するかどうか確認。\r
419                         piInfo.eMessage = TPI_MESSAGE_ASK;\r
420                         piInfo.eStatus  = TPI_PARAM_DEST;\r
421                         piInfo.fiInfo.nUnpackedSize  = hdInfo.UnpSizeHigh;\r
422                         piInfo.fiInfo.nUnpackedSize  = piInfo.fiInfo.nUnpackedSize << 32;\r
423                         piInfo.fiInfo.nUnpackedSize += hdInfo.UnpSize;\r
424                         piInfo.fiInfo.tmModify.SetFromDOS(hdInfo.FileTime);\r
425                         if (g_prProc != NULL && g_prProc(TPI_NOTIFY_COMMON, & piInfo) != TPI_CALLBACK_CONTINUE)\r
426                         {\r
427                                 nErrorCode = TPI_ERROR_D_SKIPPED;\r
428                                 break;\r
429                         }\r
430                         bSkip = ! piInfo.fnDestination.IsOk();\r
431                 }\r
432 \r
433                 if (! bSkip)\r
434                 {\r
435                         // 処理の開始を通知。\r
436                         piInfo.eMessage = TPI_MESSAGE_STATUS;\r
437                         piInfo.eStatus  = TPI_STATUS_BEGINPROCESS;\r
438                         if (g_prProc != NULL && g_prProc(TPI_NOTIFY_COMMON, & piInfo) != TPI_CALLBACK_CONTINUE)\r
439                         {\r
440                                 nErrorCode = TPI_ERROR_D_SKIPPED;\r
441                                 break;\r
442                         }\r
443                 }\r
444 \r
445                 nErrorCode = ErrorCodeConvert(((int (__stdcall *)(void *, int, wchar_t *, wchar_t *)) pP)(hArc, bSkip ? RAR_SKIP : _eCommand == TPI_COMMAND_EXTRACT ? RAR_EXTRACT : RAR_TEST, NULL, piInfo.fnDestination.GetFullPath().wchar_str()));\r
446 \r
447                 if (! bSkip)\r
448                 {\r
449                         // 処理の終了を通知。\r
450                         piInfo.eMessage = TPI_MESSAGE_STATUS;\r
451                         piInfo.eStatus  = TPI_STATUS_ENDPROCESS;\r
452                         if (g_prProc != NULL && g_prProc(TPI_NOTIFY_COMMON, & piInfo) != TPI_CALLBACK_CONTINUE)\r
453                         {\r
454                                 nErrorCode = TPI_ERROR_D_SKIPPED;\r
455                                 break;\r
456                         }\r
457                 }\r
458         }\r
459         CloseArchive(hArc);\r
460         return nErrorCode;\r
461 }\r
462 \r
463 #ifdef __cplusplus\r
464 }\r
465 #endif\r