xref: /third_party/lzma/CPP/7zip/UI/Common/LoadCodecs.h (revision 370b324c)
1// LoadCodecs.h
2
3#ifndef ZIP7_INC_LOAD_CODECS_H
4#define ZIP7_INC_LOAD_CODECS_H
5
6/*
7Client application uses LoadCodecs.* to load plugins to
8CCodecs 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
13Z7_EXTERNAL_CODECS
14---------------
15
16  if Z7_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 Z7_EXTERNAL_CODECS defined:
23       - 7z.exe, 7zG.exe, 7zFM.exe
24
25     Note: Z7_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 Z7_EXTERNAL_CODECS:
29    - SFX modules: 7z.sfx, 7zCon.sfx
30    - standalone versions of console 7-Zip: 7za.exe, 7zr.exe
31
32  if Z7_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 Z7_EXTERNAL_CODECS
55#include "../../../Windows/DLL.h"
56#endif
57
58#include "../../ICoder.h"
59
60#include "../../Archive/IArchive.h"
61
62
63#ifdef Z7_EXTERNAL_CODECS
64
65struct 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
77struct CDllHasherInfo
78{
79  unsigned LibIndex;
80  UInt32 HasherIndex;
81};
82
83#endif
84
85struct CArcExtInfo
86{
87  UString Ext;
88  UString AddExt;
89
90  CArcExtInfo() {}
91  CArcExtInfo(const UString &ext): Ext(ext) {}
92  CArcExtInfo(const UString &ext, const UString &addExt): Ext(ext), AddExt(addExt) {}
93};
94
95
96struct CArcInfoEx
97{
98  UInt32 Flags;
99  UInt32 TimeFlags;
100
101  Func_CreateInArchive CreateInArchive;
102  Func_IsArc IsArcFunc;
103
104  UString Name;
105  CObjectVector<CArcExtInfo> Exts;
106
107  #ifndef Z7_SFX
108    Func_CreateOutArchive CreateOutArchive;
109    bool UpdateEnabled;
110    bool NewInterface;
111    // UInt32 Version;
112    UInt32 SignatureOffset;
113    CObjectVector<CByteBuffer> Signatures;
114    /*
115    #ifdef NEW_FOLDER_INTERFACE
116      UStringVector AssociateExts;
117    #endif
118    */
119  #endif
120
121  #ifdef Z7_EXTERNAL_CODECS
122    int LibIndex;
123    UInt32 FormatIndex;
124    CLSID ClassID;
125  #endif
126
127  int Compare(const CArcInfoEx &a) const
128  {
129    const int res = Name.Compare(a.Name);
130    if (res != 0)
131      return res;
132    #ifdef Z7_EXTERNAL_CODECS
133    return MyCompare(LibIndex, a.LibIndex);
134    #else
135    return 0;
136    #endif
137    /*
138    if (LibIndex < a.LibIndex) return -1;
139    if (LibIndex > a.LibIndex) return 1;
140    return 0;
141    */
142  }
143
144  bool Flags_KeepName() const { return (Flags & NArcInfoFlags::kKeepName) != 0; }
145  bool Flags_FindSignature() const { return (Flags & NArcInfoFlags::kFindSignature) != 0; }
146
147  bool Flags_AltStreams() const { return (Flags & NArcInfoFlags::kAltStreams) != 0; }
148  bool Flags_NtSecurity() const { return (Flags & NArcInfoFlags::kNtSecure) != 0; }
149  bool Flags_SymLinks() const { return (Flags & NArcInfoFlags::kSymLinks) != 0; }
150  bool Flags_HardLinks() const { return (Flags & NArcInfoFlags::kHardLinks) != 0; }
151
152  bool Flags_UseGlobalOffset() const { return (Flags & NArcInfoFlags::kUseGlobalOffset) != 0; }
153  bool Flags_StartOpen() const { return (Flags & NArcInfoFlags::kStartOpen) != 0; }
154  bool Flags_BackwardOpen() const { return (Flags & NArcInfoFlags::kBackwardOpen) != 0; }
155  bool Flags_PreArc() const { return (Flags & NArcInfoFlags::kPreArc) != 0; }
156  bool Flags_PureStartOpen() const { return (Flags & NArcInfoFlags::kPureStartOpen) != 0; }
157  bool Flags_ByExtOnlyOpen() const { return (Flags & NArcInfoFlags::kByExtOnlyOpen) != 0; }
158  bool Flags_HashHandler() const { return (Flags & NArcInfoFlags::kHashHandler) != 0; }
159
160  bool Flags_CTime() const { return (Flags & NArcInfoFlags::kCTime) != 0; }
161  bool Flags_ATime() const { return (Flags & NArcInfoFlags::kATime) != 0; }
162  bool Flags_MTime() const { return (Flags & NArcInfoFlags::kMTime) != 0; }
163
164  bool Flags_CTime_Default() const { return (Flags & NArcInfoFlags::kCTime_Default) != 0; }
165  bool Flags_ATime_Default() const { return (Flags & NArcInfoFlags::kATime_Default) != 0; }
166  bool Flags_MTime_Default() const { return (Flags & NArcInfoFlags::kMTime_Default) != 0; }
167
168  UInt32 Get_TimePrecFlags() const
169  {
170    return (TimeFlags >> NArcInfoTimeFlags::kTime_Prec_Mask_bit_index) &
171      (((UInt32)1 << NArcInfoTimeFlags::kTime_Prec_Mask_num_bits) - 1);
172  }
173
174  UInt32 Get_DefaultTimePrec() const
175  {
176    return (TimeFlags >> NArcInfoTimeFlags::kTime_Prec_Default_bit_index) &
177      (((UInt32)1 << NArcInfoTimeFlags::kTime_Prec_Default_num_bits) - 1);
178  }
179
180
181  UString GetMainExt() const
182  {
183    if (Exts.IsEmpty())
184      return UString();
185    return Exts[0].Ext;
186  }
187  int FindExtension(const UString &ext) const;
188
189  bool Is_7z()    const { return Name.IsEqualTo_Ascii_NoCase("7z"); }
190  bool Is_Split() const { return Name.IsEqualTo_Ascii_NoCase("Split"); }
191  bool Is_Xz()    const { return Name.IsEqualTo_Ascii_NoCase("xz"); }
192  bool Is_BZip2() const { return Name.IsEqualTo_Ascii_NoCase("bzip2"); }
193  bool Is_GZip()  const { return Name.IsEqualTo_Ascii_NoCase("gzip"); }
194  bool Is_Tar()   const { return Name.IsEqualTo_Ascii_NoCase("tar"); }
195  bool Is_Zip()   const { return Name.IsEqualTo_Ascii_NoCase("zip"); }
196  bool Is_Rar()   const { return Name.IsEqualTo_Ascii_NoCase("rar"); }
197  bool Is_Zstd()  const { return Name.IsEqualTo_Ascii_NoCase("zstd"); }
198
199  /*
200  UString GetAllExtensions() const
201  {
202    UString s;
203    for (int i = 0; i < Exts.Size(); i++)
204    {
205      if (i > 0)
206        s.Add_Space();
207      s += Exts[i].Ext;
208    }
209    return s;
210  }
211  */
212
213  void AddExts(const UString &ext, const UString &addExt);
214
215
216  CArcInfoEx():
217      Flags(0),
218      TimeFlags(0),
219      CreateInArchive(NULL),
220      IsArcFunc(NULL)
221      #ifndef Z7_SFX
222      , CreateOutArchive(NULL)
223      , UpdateEnabled(false)
224      , NewInterface(false)
225      // , Version(0)
226      , SignatureOffset(0)
227      #endif
228      #ifdef Z7_EXTERNAL_CODECS
229      , LibIndex(-1)
230      #endif
231  {}
232};
233
234
235#ifdef Z7_EXTERNAL_CODECS
236
237struct CCodecLib
238{
239  NWindows::NDLL::CLibrary Lib;
240  FString Path;
241
242  Func_CreateObject CreateObject;
243  Func_GetMethodProperty GetMethodProperty;
244  Func_CreateDecoder CreateDecoder;
245  Func_CreateEncoder CreateEncoder;
246  Func_SetCodecs SetCodecs;
247
248  CMyComPtr<IHashers> ComHashers;
249
250  UInt32 Version;
251
252  /*
253  #ifdef NEW_FOLDER_INTERFACE
254  CCodecIcons CodecIcons;
255  void LoadIcons() { CodecIcons.LoadIcons((HMODULE)Lib); }
256  #endif
257  */
258
259  CCodecLib():
260      CreateObject(NULL),
261      GetMethodProperty(NULL),
262      CreateDecoder(NULL),
263      CreateEncoder(NULL),
264      SetCodecs(NULL),
265      Version(0)
266      {}
267};
268
269#endif
270
271struct CCodecError
272{
273  FString Path;
274  HRESULT ErrorCode;
275  AString Message;
276  CCodecError(): ErrorCode(0) {}
277};
278
279
280struct CCodecInfoUser
281{
282  // unsigned LibIndex;
283  // UInt32 CodecIndex;
284  // UInt64 id;
285  bool EncoderIsAssigned;
286  bool DecoderIsAssigned;
287  bool IsFilter;
288  bool IsFilter_Assigned;
289  UInt32 NumStreams;
290  AString Name;
291};
292
293
294class CCodecs Z7_final:
295  #ifdef Z7_EXTERNAL_CODECS
296    public ICompressCodecsInfo,
297    public IHashers,
298  #else
299    public IUnknown,
300  #endif
301  public CMyUnknownImp
302{
303#ifdef Z7_EXTERNAL_CODECS
304  Z7_IFACES_IMP_UNK_2(ICompressCodecsInfo, IHashers)
305#else
306  Z7_COM_UNKNOWN_IMP_0
307#endif // Z7_EXTERNAL_CODECS
308
309  Z7_CLASS_NO_COPY(CCodecs)
310public:
311  #ifdef Z7_EXTERNAL_CODECS
312
313  CObjectVector<CCodecLib> Libs;
314  FString MainDll_ErrorPath;
315  CObjectVector<CCodecError> Errors;
316
317  void AddLastError(const FString &path);
318  void CloseLibs();
319
320  class CReleaser
321  {
322    Z7_CLASS_NO_COPY(CReleaser)
323
324    /* CCodecsReleaser object releases CCodecs links.
325         1) CCodecs is COM object that is deleted when all links to that object will be released/
326         2) CCodecs::Libs[i] can hold (ICompressCodecsInfo *) link to CCodecs object itself.
327       To break that reference loop, we must close all CCodecs::Libs in CCodecsReleaser desttructor. */
328
329    CCodecs *_codecs;
330
331    public:
332    CReleaser(): _codecs(NULL) {}
333    void Set(CCodecs *codecs) { _codecs = codecs; }
334    ~CReleaser() { if (_codecs) _codecs->CloseLibs(); }
335  };
336
337  bool NeedSetLibCodecs; // = false, if we don't need to set codecs for archive handler via ISetCompressCodecsInfo
338
339  HRESULT LoadCodecs();
340  HRESULT LoadFormats();
341  HRESULT LoadDll(const FString &path, bool needCheckDll, bool *loadedOK = NULL);
342  HRESULT LoadDllsFromFolder(const FString &folderPrefix);
343
344  HRESULT CreateArchiveHandler(const CArcInfoEx &ai, bool outHandler, void **archive) const
345  {
346    return Libs[(unsigned)ai.LibIndex].CreateObject(&ai.ClassID, outHandler ? &IID_IOutArchive : &IID_IInArchive, (void **)archive);
347  }
348
349  #endif
350
351  /*
352  #ifdef NEW_FOLDER_INTERFACE
353  CCodecIcons InternalIcons;
354  #endif
355  */
356
357  CObjectVector<CArcInfoEx> Formats;
358
359  #ifdef Z7_EXTERNAL_CODECS
360  CRecordVector<CDllCodecInfo> Codecs;
361  CRecordVector<CDllHasherInfo> Hashers;
362  #endif
363
364  bool CaseSensitive_Change;
365  bool CaseSensitive;
366
367  CCodecs():
368      #ifdef Z7_EXTERNAL_CODECS
369      NeedSetLibCodecs(true),
370      #endif
371      CaseSensitive_Change(false),
372      CaseSensitive(false)
373      {}
374
375  ~CCodecs()
376  {
377    // OutputDebugStringA("~CCodecs");
378  }
379
380  const wchar_t *GetFormatNamePtr(int formatIndex) const
381  {
382    return formatIndex < 0 ? L"#" : (const wchar_t *)Formats[(unsigned)formatIndex].Name;
383  }
384
385  HRESULT Load();
386
387  #ifndef Z7_SFX
388  int FindFormatForArchiveName(const UString &arcPath) const;
389  int FindFormatForExtension(const UString &ext) const;
390  int FindFormatForArchiveType(const UString &arcType) const;
391  bool FindFormatForArchiveType(const UString &arcType, CIntVector &formatIndices) const;
392  #endif
393
394  #ifdef Z7_EXTERNAL_CODECS
395
396  int GetCodec_LibIndex(UInt32 index) const;
397  bool GetCodec_DecoderIsAssigned(UInt32 index) const;
398  bool GetCodec_EncoderIsAssigned(UInt32 index) const;
399  bool GetCodec_IsFilter(UInt32 index, bool &isAssigned) const;
400  UInt32 GetCodec_NumStreams(UInt32 index);
401  HRESULT GetCodec_Id(UInt32 index, UInt64 &id);
402  AString GetCodec_Name(UInt32 index);
403
404  int GetHasherLibIndex(UInt32 index);
405  UInt64 GetHasherId(UInt32 index);
406  AString GetHasherName(UInt32 index);
407  UInt32 GetHasherDigestSize(UInt32 index);
408
409  void GetCodecsErrorMessage(UString &s);
410
411  #endif
412
413  HRESULT CreateInArchive(unsigned formatIndex, CMyComPtr<IInArchive> &archive) const
414  {
415    const CArcInfoEx &ai = Formats[formatIndex];
416    #ifdef Z7_EXTERNAL_CODECS
417    if (ai.LibIndex < 0)
418    #endif
419    {
420      COM_TRY_BEGIN
421      archive = ai.CreateInArchive();
422      return S_OK;
423      COM_TRY_END
424    }
425    #ifdef Z7_EXTERNAL_CODECS
426    return CreateArchiveHandler(ai, false, (void **)&archive);
427    #endif
428  }
429
430  #ifndef Z7_SFX
431
432  HRESULT CreateOutArchive(unsigned formatIndex, CMyComPtr<IOutArchive> &archive) const
433  {
434    const CArcInfoEx &ai = Formats[formatIndex];
435    #ifdef Z7_EXTERNAL_CODECS
436    if (ai.LibIndex < 0)
437    #endif
438    {
439      COM_TRY_BEGIN
440      archive = ai.CreateOutArchive();
441      return S_OK;
442      COM_TRY_END
443    }
444
445    #ifdef Z7_EXTERNAL_CODECS
446    return CreateArchiveHandler(ai, true, (void **)&archive);
447    #endif
448  }
449
450  int FindOutFormatFromName(const UString &name) const
451  {
452    FOR_VECTOR (i, Formats)
453    {
454      const CArcInfoEx &arc = Formats[i];
455      if (!arc.UpdateEnabled)
456        continue;
457      if (arc.Name.IsEqualTo_NoCase(name))
458        return (int)i;
459    }
460    return -1;
461  }
462
463  void Get_CodecsInfoUser_Vector(CObjectVector<CCodecInfoUser> &v);
464
465  #endif // Z7_SFX
466};
467
468#ifdef Z7_EXTERNAL_CODECS
469  #define CREATE_CODECS_OBJECT \
470    CCodecs *codecs = new CCodecs; \
471    CExternalCodecs _externalCodecs; \
472    _externalCodecs.GetCodecs = codecs; \
473    _externalCodecs.GetHashers = codecs; \
474    CCodecs::CReleaser codecsReleaser; \
475    codecsReleaser.Set(codecs);
476#else
477  #define CREATE_CODECS_OBJECT \
478    CCodecs *codecs = new CCodecs; \
479    CMyComPtr<IUnknown> _codecsRef = codecs;
480#endif
481
482#endif
483