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   CLSID Encoder;
72   CLSID Decoder;
73 };
74 
75 struct CDllHasherInfo
76 {
77   unsigned LibIndex;
78   UInt32 HasherIndex;
79 };
80 
81 #endif
82 
83 struct CArcExtInfo
84 {
85   UString Ext;
86   UString AddExt;
87 
CArcExtInfoCArcExtInfo88   CArcExtInfo() {}
CArcExtInfoCArcExtInfo89   CArcExtInfo(const UString &ext): Ext(ext) {}
CArcExtInfoCArcExtInfo90   CArcExtInfo(const UString &ext, const UString &addExt): Ext(ext), AddExt(addExt) {}
91 };
92 
93 
94 struct CArcInfoEx
95 {
96   UInt32 Flags;
97 
98   Func_CreateInArchive CreateInArchive;
99   Func_IsArc IsArcFunc;
100 
101   UString Name;
102   CObjectVector<CArcExtInfo> Exts;
103 
104   #ifndef _SFX
105     Func_CreateOutArchive CreateOutArchive;
106     bool UpdateEnabled;
107     bool NewInterface;
108     // UInt32 Version;
109     UInt32 SignatureOffset;
110     CObjectVector<CByteBuffer> Signatures;
111     #ifdef NEW_FOLDER_INTERFACE
112       UStringVector AssociateExts;
113     #endif
114   #endif
115 
116   #ifdef EXTERNAL_CODECS
117     int LibIndex;
118     UInt32 FormatIndex;
119     CLSID ClassID;
120   #endif
121 
Flags_KeepNameCArcInfoEx122   bool Flags_KeepName() const { return (Flags & NArcInfoFlags::kKeepName) != 0; }
Flags_FindSignatureCArcInfoEx123   bool Flags_FindSignature() const { return (Flags & NArcInfoFlags::kFindSignature) != 0; }
124 
Flags_AltStreamsCArcInfoEx125   bool Flags_AltStreams() const { return (Flags & NArcInfoFlags::kAltStreams) != 0; }
Flags_NtSecureCArcInfoEx126   bool Flags_NtSecure() const { return (Flags & NArcInfoFlags::kNtSecure) != 0; }
Flags_SymLinksCArcInfoEx127   bool Flags_SymLinks() const { return (Flags & NArcInfoFlags::kSymLinks) != 0; }
Flags_HardLinksCArcInfoEx128   bool Flags_HardLinks() const { return (Flags & NArcInfoFlags::kHardLinks) != 0; }
129 
Flags_UseGlobalOffsetCArcInfoEx130   bool Flags_UseGlobalOffset() const { return (Flags & NArcInfoFlags::kUseGlobalOffset) != 0; }
Flags_StartOpenCArcInfoEx131   bool Flags_StartOpen() const { return (Flags & NArcInfoFlags::kStartOpen) != 0; }
Flags_BackwardOpenCArcInfoEx132   bool Flags_BackwardOpen() const { return (Flags & NArcInfoFlags::kBackwardOpen) != 0; }
Flags_PreArcCArcInfoEx133   bool Flags_PreArc() const { return (Flags & NArcInfoFlags::kPreArc) != 0; }
Flags_PureStartOpenCArcInfoEx134   bool Flags_PureStartOpen() const { return (Flags & NArcInfoFlags::kPureStartOpen) != 0; }
135 
GetMainExtCArcInfoEx136   UString GetMainExt() const
137   {
138     if (Exts.IsEmpty())
139       return UString();
140     return Exts[0].Ext;
141   }
142   int FindExtension(const UString &ext) const;
143 
144   /*
145   UString GetAllExtensions() const
146   {
147     UString s;
148     for (int i = 0; i < Exts.Size(); i++)
149     {
150       if (i > 0)
151         s += ' ';
152       s += Exts[i].Ext;
153     }
154     return s;
155   }
156   */
157 
158   void AddExts(const UString &ext, const UString &addExt);
159 
IsSplitCArcInfoEx160   bool IsSplit() const { return StringsAreEqualNoCase_Ascii(Name, "Split"); }
161   // bool IsRar() const { return StringsAreEqualNoCase_Ascii(Name, "Rar"); }
162 
CArcInfoExCArcInfoEx163   CArcInfoEx():
164       Flags(0),
165       CreateInArchive(NULL),
166       IsArcFunc(NULL)
167       #ifndef _SFX
168       , CreateOutArchive(NULL)
169       , UpdateEnabled(false)
170       , NewInterface(false)
171       // , Version(0)
172       , SignatureOffset(0)
173       #endif
174       #ifdef EXTERNAL_CODECS
175       , LibIndex(-1)
176       #endif
177   {}
178 };
179 
180 #ifdef NEW_FOLDER_INTERFACE
181 
182 struct CCodecIcons
183 {
184   struct CIconPair
185   {
186     UString Ext;
187     int IconIndex;
188   };
189   CObjectVector<CIconPair> IconPairs;
190 
191   void LoadIcons(HMODULE m);
192   bool FindIconIndex(const UString &ext, int &iconIndex) const;
193 };
194 
195 #endif
196 
197 #ifdef EXTERNAL_CODECS
198 
199 struct CCodecLib
200   #ifdef NEW_FOLDER_INTERFACE
201     : public CCodecIcons
202   #endif
203 {
204   NWindows::NDLL::CLibrary Lib;
205   FString Path;
206 
207   Func_CreateObject CreateObject;
208   Func_GetMethodProperty GetMethodProperty;
209   Func_CreateDecoder CreateDecoder;
210   Func_CreateEncoder CreateEncoder;
211   Func_SetCodecs SetCodecs;
212 
213   CMyComPtr<IHashers> ComHashers;
214 
215   #ifdef NEW_FOLDER_INTERFACE
LoadIconsCCodecLib216   void LoadIcons() { CCodecIcons::LoadIcons((HMODULE)Lib); }
217   #endif
218 
CCodecLibCCodecLib219   CCodecLib():
220       CreateObject(NULL),
221       GetMethodProperty(NULL),
222       CreateDecoder(NULL),
223       CreateEncoder(NULL),
224       SetCodecs(NULL)
225       {}
226 };
227 
228 #endif
229 
230 
231 class CCodecs:
232   #ifdef EXTERNAL_CODECS
233     public ICompressCodecsInfo,
234     public IHashers,
235   #else
236     public IUnknown,
237   #endif
238   public CMyUnknownImp
239 {
240   CLASS_NO_COPY(CCodecs);
241 public:
242   #ifdef EXTERNAL_CODECS
243 
244   CObjectVector<CCodecLib> Libs;
245   FString MainDll_ErrorPath;
246 
247   void CloseLibs();
248 
249   class CReleaser
250   {
251     CLASS_NO_COPY(CReleaser);
252 
253     /* CCodecsReleaser object releases CCodecs links.
254          1) CCodecs is COM object that is deleted when all links to that object will be released/
255          2) CCodecs::Libs[i] can hold (ICompressCodecsInfo *) link to CCodecs object itself.
256        To break that reference loop, we must close all CCodecs::Libs in CCodecsReleaser desttructor. */
257 
258     CCodecs *_codecs;
259 
260     public:
CReleaser()261     CReleaser(): _codecs(NULL) {}
Set(CCodecs * codecs)262     void Set(CCodecs *codecs) { _codecs = codecs; }
~CReleaser()263     ~CReleaser() { if (_codecs) _codecs->CloseLibs(); }
264   };
265 
266   bool NeedSetLibCodecs; // = false, if we don't need to set codecs for archive handler via ISetCompressCodecsInfo
267 
268   HRESULT LoadCodecs();
269   HRESULT LoadFormats();
270   HRESULT LoadDll(const FString &path, bool needCheckDll, bool *loadedOK = NULL);
271   HRESULT LoadDllsFromFolder(const FString &folderPrefix);
272 
CreateArchiveHandler(const CArcInfoEx & ai,bool outHandler,void ** archive)273   HRESULT CreateArchiveHandler(const CArcInfoEx &ai, bool outHandler, void **archive) const
274   {
275     return Libs[ai.LibIndex].CreateObject(&ai.ClassID, outHandler ? &IID_IOutArchive : &IID_IInArchive, (void **)archive);
276   }
277 
278   #endif
279 
280   #ifdef NEW_FOLDER_INTERFACE
281   CCodecIcons InternalIcons;
282   #endif
283 
284   CObjectVector<CArcInfoEx> Formats;
285 
286   #ifdef EXTERNAL_CODECS
287   CRecordVector<CDllCodecInfo> Codecs;
288   CRecordVector<CDllHasherInfo> Hashers;
289   #endif
290 
291   bool CaseSensitiveChange;
292   bool CaseSensitive;
293 
CCodecs()294   CCodecs():
295       #ifdef EXTERNAL_CODECS
296       NeedSetLibCodecs(true),
297       #endif
298       CaseSensitiveChange(false),
299       CaseSensitive(false)
300       {}
301 
~CCodecs()302   ~CCodecs()
303   {
304     // OutputDebugStringA("~CCodecs");
305   }
306 
GetFormatNamePtr(int formatIndex)307   const wchar_t *GetFormatNamePtr(int formatIndex) const
308   {
309     return formatIndex < 0 ? L"#" : (const wchar_t *)Formats[formatIndex].Name;
310   }
311 
312   HRESULT Load();
313 
314   #ifndef _SFX
315   int FindFormatForArchiveName(const UString &arcPath) const;
316   int FindFormatForExtension(const UString &ext) const;
317   int FindFormatForArchiveType(const UString &arcType) const;
318   bool FindFormatForArchiveType(const UString &arcType, CIntVector &formatIndices) const;
319   #endif
320 
321   #ifdef EXTERNAL_CODECS
322 
323   MY_UNKNOWN_IMP2(ICompressCodecsInfo, IHashers)
324 
325   STDMETHOD(GetNumMethods)(UInt32 *numMethods);
326   STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value);
327   STDMETHOD(CreateDecoder)(UInt32 index, const GUID *iid, void **coder);
328   STDMETHOD(CreateEncoder)(UInt32 index, const GUID *iid, void **coder);
329 
330   STDMETHOD_(UInt32, GetNumHashers)();
331   STDMETHOD(GetHasherProp)(UInt32 index, PROPID propID, PROPVARIANT *value);
332   STDMETHOD(CreateHasher)(UInt32 index, IHasher **hasher);
333 
334   #else
335 
336   MY_UNKNOWN_IMP
337 
338   #endif // EXTERNAL_CODECS
339 
340 
341   #ifdef EXTERNAL_CODECS
342 
343   int GetCodec_LibIndex(UInt32 index) const;
344   bool GetCodec_DecoderIsAssigned(UInt32 index) const;
345   bool GetCodec_EncoderIsAssigned(UInt32 index) const;
346   UInt32 GetCodec_NumStreams(UInt32 index);
347   HRESULT GetCodec_Id(UInt32 index, UInt64 &id);
348   AString GetCodec_Name(UInt32 index);
349 
350   int GetHasherLibIndex(UInt32 index);
351   UInt64 GetHasherId(UInt32 index);
352   AString GetHasherName(UInt32 index);
353   UInt32 GetHasherDigestSize(UInt32 index);
354 
355   #endif
356 
CreateInArchive(unsigned formatIndex,CMyComPtr<IInArchive> & archive)357   HRESULT CreateInArchive(unsigned formatIndex, CMyComPtr<IInArchive> &archive) const
358   {
359     const CArcInfoEx &ai = Formats[formatIndex];
360     #ifdef EXTERNAL_CODECS
361     if (ai.LibIndex < 0)
362     #endif
363     {
364       COM_TRY_BEGIN
365       archive = ai.CreateInArchive();
366       return S_OK;
367       COM_TRY_END
368     }
369     #ifdef EXTERNAL_CODECS
370     return CreateArchiveHandler(ai, false, (void **)&archive);
371     #endif
372   }
373 
374   #ifndef _SFX
375 
CreateOutArchive(unsigned formatIndex,CMyComPtr<IOutArchive> & archive)376   HRESULT CreateOutArchive(unsigned formatIndex, CMyComPtr<IOutArchive> &archive) const
377   {
378     const CArcInfoEx &ai = Formats[formatIndex];
379     #ifdef EXTERNAL_CODECS
380     if (ai.LibIndex < 0)
381     #endif
382     {
383       COM_TRY_BEGIN
384       archive = ai.CreateOutArchive();
385       return S_OK;
386       COM_TRY_END
387     }
388 
389     #ifdef EXTERNAL_CODECS
390     return CreateArchiveHandler(ai, true, (void **)&archive);
391     #endif
392   }
393 
FindOutFormatFromName(const UString & name)394   int FindOutFormatFromName(const UString &name) const
395   {
396     FOR_VECTOR (i, Formats)
397     {
398       const CArcInfoEx &arc = Formats[i];
399       if (!arc.UpdateEnabled)
400         continue;
401       if (arc.Name.IsEqualTo_NoCase(name))
402         return i;
403     }
404     return -1;
405   }
406 
407   #endif // _SFX
408 };
409 
410 #ifdef EXTERNAL_CODECS
411   #define CREATE_CODECS_OBJECT \
412     CCodecs *codecs = new CCodecs; \
413     CExternalCodecs __externalCodecs; \
414     __externalCodecs.GetCodecs = codecs; \
415     __externalCodecs.GetHashers = codecs; \
416     CCodecs::CReleaser codecsReleaser; \
417     codecsReleaser.Set(codecs);
418 #else
419   #define CREATE_CODECS_OBJECT \
420     CCodecs *codecs = new CCodecs; \
421     CMyComPtr<IUnknown> __codecsRef = codecs;
422 #endif
423 
424 #endif
425