1 // LoadCodecs.h
2 
3 #ifndef __LOAD_CODECS_H
4 #define __LOAD_CODECS_H
5 
6 /*
7 Client application uses LoadCodecs.* to load plugins to
8 CCodecs object, that contains 3 lists of plugins:
9   1) Formats - internal and external archive handlers
10   2) Codecs  - external codecs
11   3) Hashers - external hashers
12 
13 EXTERNAL_CODECS
14 ---------------
15 
16   if EXTERNAL_CODECS is defined, then the code tries to load external
17   plugins from DLL files (shared libraries).
18 
19   There are two types of executables in 7-Zip:
20 
21   1) Executable that uses external plugins must be compiled
22      with EXTERNAL_CODECS defined:
23        - 7z.exe, 7zG.exe, 7zFM.exe
24 
25      Note: EXTERNAL_CODECS is used also in CPP/7zip/Common/CreateCoder.h
26            that code is used in plugin module (7z.dll).
27 
28   2) Standalone modules are compiled without EXTERNAL_CODECS:
29     - SFX modules: 7z.sfx, 7zCon.sfx
30     - standalone versions of console 7-Zip: 7za.exe, 7zr.exe
31 
32   if EXTERNAL_CODECS is defined, CCodecs class implements interfaces:
33     - ICompressCodecsInfo : for Codecs
34     - IHashers            : for Hashers
35 
36   The client application can send CCodecs object to each plugin module.
37   And plugin module can use ICompressCodecsInfo or IHashers interface to access
38   another plugins.
39 
40   There are 2 ways to send (ICompressCodecsInfo * compressCodecsInfo) to plugin
41     1) for old versions:
42         a) request ISetCompressCodecsInfo from created archive handler.
43         b) call ISetCompressCodecsInfo::SetCompressCodecsInfo(compressCodecsInfo)
44     2) for new versions:
45         a) request "SetCodecs" function from DLL file
46         b) call SetCodecs(compressCodecsInfo) function from DLL file
47 */
48 
49 #include "../../../Common/MyBuffer.h"
50 #include "../../../Common/MyCom.h"
51 #include "../../../Common/MyString.h"
52 #include "../../../Common/ComTry.h"
53 
54 #ifdef EXTERNAL_CODECS
55 #include "../../../Windows/DLL.h"
56 #endif
57 
58 #include "../../ICoder.h"
59 
60 #include "../../Archive/IArchive.h"
61 
62 
63 #ifdef EXTERNAL_CODECS
64 
65 struct CDllCodecInfo
66 {
67   unsigned LibIndex;
68   UInt32 CodecIndex;
69   bool EncoderIsAssigned;
70   bool DecoderIsAssigned;
71   bool IsFilter;
72   bool IsFilter_Assigned;
73   CLSID Encoder;
74   CLSID Decoder;
75 };
76 
77 struct CDllHasherInfo
78 {
79   unsigned LibIndex;
80   UInt32 HasherIndex;
81 };
82 
83 #endif
84 
85 struct CArcExtInfo
86 {
87   UString Ext;
88   UString AddExt;
89 
CArcExtInfoCArcExtInfo90   CArcExtInfo() {}
CArcExtInfoCArcExtInfo91   CArcExtInfo(const UString &ext): Ext(ext) {}
CArcExtInfoCArcExtInfo92   CArcExtInfo(const UString &ext, const UString &addExt): Ext(ext), AddExt(addExt) {}
93 };
94 
95 
96 struct CArcInfoEx
97 {
98   UInt32 Flags;
99 
100   Func_CreateInArchive CreateInArchive;
101   Func_IsArc IsArcFunc;
102 
103   UString Name;
104   CObjectVector<CArcExtInfo> Exts;
105 
106   #ifndef _SFX
107     Func_CreateOutArchive CreateOutArchive;
108     bool UpdateEnabled;
109     bool NewInterface;
110     // UInt32 Version;
111     UInt32 SignatureOffset;
112     CObjectVector<CByteBuffer> Signatures;
113     #ifdef NEW_FOLDER_INTERFACE
114       UStringVector AssociateExts;
115     #endif
116   #endif
117 
118   #ifdef EXTERNAL_CODECS
119     int LibIndex;
120     UInt32 FormatIndex;
121     CLSID ClassID;
122   #endif
123 
CompareCArcInfoEx124   int Compare(const CArcInfoEx &a) const
125   {
126     int res = Name.Compare(a.Name);
127     if (res != 0)
128       return res;
129     #ifdef EXTERNAL_CODECS
130     return MyCompare(LibIndex, a.LibIndex);
131     #else
132     return 0;
133     #endif
134     /*
135     if (LibIndex < a.LibIndex) return -1;
136     if (LibIndex > a.LibIndex) return 1;
137     return 0;
138     */
139   }
140 
Flags_KeepNameCArcInfoEx141   bool Flags_KeepName() const { return (Flags & NArcInfoFlags::kKeepName) != 0; }
Flags_FindSignatureCArcInfoEx142   bool Flags_FindSignature() const { return (Flags & NArcInfoFlags::kFindSignature) != 0; }
143 
Flags_AltStreamsCArcInfoEx144   bool Flags_AltStreams() const { return (Flags & NArcInfoFlags::kAltStreams) != 0; }
Flags_NtSecureCArcInfoEx145   bool Flags_NtSecure() const { return (Flags & NArcInfoFlags::kNtSecure) != 0; }
Flags_SymLinksCArcInfoEx146   bool Flags_SymLinks() const { return (Flags & NArcInfoFlags::kSymLinks) != 0; }
Flags_HardLinksCArcInfoEx147   bool Flags_HardLinks() const { return (Flags & NArcInfoFlags::kHardLinks) != 0; }
148 
Flags_UseGlobalOffsetCArcInfoEx149   bool Flags_UseGlobalOffset() const { return (Flags & NArcInfoFlags::kUseGlobalOffset) != 0; }
Flags_StartOpenCArcInfoEx150   bool Flags_StartOpen() const { return (Flags & NArcInfoFlags::kStartOpen) != 0; }
Flags_BackwardOpenCArcInfoEx151   bool Flags_BackwardOpen() const { return (Flags & NArcInfoFlags::kBackwardOpen) != 0; }
Flags_PreArcCArcInfoEx152   bool Flags_PreArc() const { return (Flags & NArcInfoFlags::kPreArc) != 0; }
Flags_PureStartOpenCArcInfoEx153   bool Flags_PureStartOpen() const { return (Flags & NArcInfoFlags::kPureStartOpen) != 0; }
Flags_ByExtOnlyOpenCArcInfoEx154   bool Flags_ByExtOnlyOpen() const { return (Flags & NArcInfoFlags::kByExtOnlyOpen) != 0; }
Flags_HashHandlerCArcInfoEx155   bool Flags_HashHandler() const { return (Flags & NArcInfoFlags::kHashHandler) != 0; }
156 
GetMainExtCArcInfoEx157   UString GetMainExt() const
158   {
159     if (Exts.IsEmpty())
160       return UString();
161     return Exts[0].Ext;
162   }
163   int FindExtension(const UString &ext) const;
164 
165   /*
166   UString GetAllExtensions() const
167   {
168     UString s;
169     for (int i = 0; i < Exts.Size(); i++)
170     {
171       if (i > 0)
172         s += ' ';
173       s += Exts[i].Ext;
174     }
175     return s;
176   }
177   */
178 
179   void AddExts(const UString &ext, const UString &addExt);
180 
IsSplitCArcInfoEx181   bool IsSplit() const { return StringsAreEqualNoCase_Ascii(Name, "Split"); }
182   // bool IsRar() const { return StringsAreEqualNoCase_Ascii(Name, "Rar"); }
183 
CArcInfoExCArcInfoEx184   CArcInfoEx():
185       Flags(0),
186       CreateInArchive(NULL),
187       IsArcFunc(NULL)
188       #ifndef _SFX
189       , CreateOutArchive(NULL)
190       , UpdateEnabled(false)
191       , NewInterface(false)
192       // , Version(0)
193       , SignatureOffset(0)
194       #endif
195       #ifdef EXTERNAL_CODECS
196       , LibIndex(-1)
197       #endif
198   {}
199 };
200 
201 #ifdef NEW_FOLDER_INTERFACE
202 
203 struct CCodecIcons
204 {
205   struct CIconPair
206   {
207     UString Ext;
208     int IconIndex;
209   };
210   CObjectVector<CIconPair> IconPairs;
211 
212   void LoadIcons(HMODULE m);
213   bool FindIconIndex(const UString &ext, int &iconIndex) const;
214 };
215 
216 #endif
217 
218 #ifdef EXTERNAL_CODECS
219 
220 struct CCodecLib
221   #ifdef NEW_FOLDER_INTERFACE
222     : public CCodecIcons
223   #endif
224 {
225   NWindows::NDLL::CLibrary Lib;
226   FString Path;
227 
228   Func_CreateObject CreateObject;
229   Func_GetMethodProperty GetMethodProperty;
230   Func_CreateDecoder CreateDecoder;
231   Func_CreateEncoder CreateEncoder;
232   Func_SetCodecs SetCodecs;
233 
234   CMyComPtr<IHashers> ComHashers;
235 
236   #ifdef NEW_FOLDER_INTERFACE
LoadIconsCCodecLib237   void LoadIcons() { CCodecIcons::LoadIcons((HMODULE)Lib); }
238   #endif
239 
CCodecLibCCodecLib240   CCodecLib():
241       CreateObject(NULL),
242       GetMethodProperty(NULL),
243       CreateDecoder(NULL),
244       CreateEncoder(NULL),
245       SetCodecs(NULL)
246       {}
247 };
248 
249 #endif
250 
251 struct CCodecError
252 {
253   FString Path;
254   HRESULT ErrorCode;
255   AString Message;
CCodecErrorCCodecError256   CCodecError(): ErrorCode(0) {}
257 };
258 
259 
260 struct CCodecInfoUser
261 {
262   // unsigned LibIndex;
263   // UInt32 CodecIndex;
264   // UInt64 id;
265   bool EncoderIsAssigned;
266   bool DecoderIsAssigned;
267   bool IsFilter;
268   bool IsFilter_Assigned;
269   UInt32 NumStreams;
270   AString Name;
271 };
272 
273 
274 class CCodecs:
275   #ifdef EXTERNAL_CODECS
276     public ICompressCodecsInfo,
277     public IHashers,
278   #else
279     public IUnknown,
280   #endif
281   public CMyUnknownImp
282 {
283   CLASS_NO_COPY(CCodecs);
284 public:
285   #ifdef EXTERNAL_CODECS
286 
287   CObjectVector<CCodecLib> Libs;
288   FString MainDll_ErrorPath;
289   CObjectVector<CCodecError> Errors;
290 
291   void AddLastError(const FString &path);
292   void CloseLibs();
293 
294   class CReleaser
295   {
296     CLASS_NO_COPY(CReleaser);
297 
298     /* CCodecsReleaser object releases CCodecs links.
299          1) CCodecs is COM object that is deleted when all links to that object will be released/
300          2) CCodecs::Libs[i] can hold (ICompressCodecsInfo *) link to CCodecs object itself.
301        To break that reference loop, we must close all CCodecs::Libs in CCodecsReleaser desttructor. */
302 
303     CCodecs *_codecs;
304 
305     public:
CReleaser()306     CReleaser(): _codecs(NULL) {}
Set(CCodecs * codecs)307     void Set(CCodecs *codecs) { _codecs = codecs; }
~CReleaser()308     ~CReleaser() { if (_codecs) _codecs->CloseLibs(); }
309   };
310 
311   bool NeedSetLibCodecs; // = false, if we don't need to set codecs for archive handler via ISetCompressCodecsInfo
312 
313   HRESULT LoadCodecs();
314   HRESULT LoadFormats();
315   HRESULT LoadDll(const FString &path, bool needCheckDll, bool *loadedOK = NULL);
316   HRESULT LoadDllsFromFolder(const FString &folderPrefix);
317 
CreateArchiveHandler(const CArcInfoEx & ai,bool outHandler,void ** archive)318   HRESULT CreateArchiveHandler(const CArcInfoEx &ai, bool outHandler, void **archive) const
319   {
320     return Libs[(unsigned)ai.LibIndex].CreateObject(&ai.ClassID, outHandler ? &IID_IOutArchive : &IID_IInArchive, (void **)archive);
321   }
322 
323   #endif
324 
325   #ifdef NEW_FOLDER_INTERFACE
326   CCodecIcons InternalIcons;
327   #endif
328 
329   CObjectVector<CArcInfoEx> Formats;
330 
331   #ifdef EXTERNAL_CODECS
332   CRecordVector<CDllCodecInfo> Codecs;
333   CRecordVector<CDllHasherInfo> Hashers;
334   #endif
335 
336   bool CaseSensitiveChange;
337   bool CaseSensitive;
338 
CCodecs()339   CCodecs():
340       #ifdef EXTERNAL_CODECS
341       NeedSetLibCodecs(true),
342       #endif
343       CaseSensitiveChange(false),
344       CaseSensitive(false)
345       {}
346 
~CCodecs()347   ~CCodecs()
348   {
349     // OutputDebugStringA("~CCodecs");
350   }
351 
GetFormatNamePtr(int formatIndex)352   const wchar_t *GetFormatNamePtr(int formatIndex) const
353   {
354     return formatIndex < 0 ? L"#" : (const wchar_t *)Formats[(unsigned)formatIndex].Name;
355   }
356 
357   HRESULT Load();
358 
359   #ifndef _SFX
360   int FindFormatForArchiveName(const UString &arcPath) const;
361   int FindFormatForExtension(const UString &ext) const;
362   int FindFormatForArchiveType(const UString &arcType) const;
363   bool FindFormatForArchiveType(const UString &arcType, CIntVector &formatIndices) const;
364   #endif
365 
366   #ifdef EXTERNAL_CODECS
367 
368   MY_UNKNOWN_IMP2(ICompressCodecsInfo, IHashers)
369 
370   STDMETHOD(GetNumMethods)(UInt32 *numMethods);
371   STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value);
372   STDMETHOD(CreateDecoder)(UInt32 index, const GUID *iid, void **coder);
373   STDMETHOD(CreateEncoder)(UInt32 index, const GUID *iid, void **coder);
374 
375   STDMETHOD_(UInt32, GetNumHashers)();
376   STDMETHOD(GetHasherProp)(UInt32 index, PROPID propID, PROPVARIANT *value);
377   STDMETHOD(CreateHasher)(UInt32 index, IHasher **hasher);
378 
379   #else
380 
381   MY_UNKNOWN_IMP
382 
383   #endif // EXTERNAL_CODECS
384 
385 
386   #ifdef EXTERNAL_CODECS
387 
388   int GetCodec_LibIndex(UInt32 index) const;
389   bool GetCodec_DecoderIsAssigned(UInt32 index) const;
390   bool GetCodec_EncoderIsAssigned(UInt32 index) const;
391   bool GetCodec_IsFilter(UInt32 index, bool &isAssigned) const;
392   UInt32 GetCodec_NumStreams(UInt32 index);
393   HRESULT GetCodec_Id(UInt32 index, UInt64 &id);
394   AString GetCodec_Name(UInt32 index);
395 
396   int GetHasherLibIndex(UInt32 index);
397   UInt64 GetHasherId(UInt32 index);
398   AString GetHasherName(UInt32 index);
399   UInt32 GetHasherDigestSize(UInt32 index);
400 
401   void GetCodecsErrorMessage(UString &s);
402 
403   #endif
404 
CreateInArchive(unsigned formatIndex,CMyComPtr<IInArchive> & archive)405   HRESULT CreateInArchive(unsigned formatIndex, CMyComPtr<IInArchive> &archive) const
406   {
407     const CArcInfoEx &ai = Formats[formatIndex];
408     #ifdef EXTERNAL_CODECS
409     if (ai.LibIndex < 0)
410     #endif
411     {
412       COM_TRY_BEGIN
413       archive = ai.CreateInArchive();
414       return S_OK;
415       COM_TRY_END
416     }
417     #ifdef EXTERNAL_CODECS
418     return CreateArchiveHandler(ai, false, (void **)&archive);
419     #endif
420   }
421 
422   #ifndef _SFX
423 
CreateOutArchive(unsigned formatIndex,CMyComPtr<IOutArchive> & archive)424   HRESULT CreateOutArchive(unsigned formatIndex, CMyComPtr<IOutArchive> &archive) const
425   {
426     const CArcInfoEx &ai = Formats[formatIndex];
427     #ifdef EXTERNAL_CODECS
428     if (ai.LibIndex < 0)
429     #endif
430     {
431       COM_TRY_BEGIN
432       archive = ai.CreateOutArchive();
433       return S_OK;
434       COM_TRY_END
435     }
436 
437     #ifdef EXTERNAL_CODECS
438     return CreateArchiveHandler(ai, true, (void **)&archive);
439     #endif
440   }
441 
FindOutFormatFromName(const UString & name)442   int FindOutFormatFromName(const UString &name) const
443   {
444     FOR_VECTOR (i, Formats)
445     {
446       const CArcInfoEx &arc = Formats[i];
447       if (!arc.UpdateEnabled)
448         continue;
449       if (arc.Name.IsEqualTo_NoCase(name))
450         return (int)i;
451     }
452     return -1;
453   }
454 
455   void Get_CodecsInfoUser_Vector(CObjectVector<CCodecInfoUser> &v);
456 
457   #endif // _SFX
458 };
459 
460 #ifdef EXTERNAL_CODECS
461   #define CREATE_CODECS_OBJECT \
462     CCodecs *codecs = new CCodecs; \
463     CExternalCodecs __externalCodecs; \
464     __externalCodecs.GetCodecs = codecs; \
465     __externalCodecs.GetHashers = codecs; \
466     CCodecs::CReleaser codecsReleaser; \
467     codecsReleaser.Set(codecs);
468 #else
469   #define CREATE_CODECS_OBJECT \
470     CCodecs *codecs = new CCodecs; \
471     CMyComPtr<IUnknown> __codecsRef = codecs;
472 #endif
473 
474 #endif
475