1// LoadCodecs.h
2
3#ifndef __LOAD_CODECS_H
4#define __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
13EXTERNAL_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
65struct CDllCodecInfo
66{
67  unsigned LibIndex;
68  UInt32 CodecIndex;
69  bool EncoderIsAssigned;
70  bool DecoderIsAssigned;
71  CLSID Encoder;
72  CLSID Decoder;
73};
74
75struct CDllHasherInfo
76{
77  unsigned LibIndex;
78  UInt32 HasherIndex;
79};
80
81#endif
82
83struct CArcExtInfo
84{
85  UString Ext;
86  UString AddExt;
87
88  CArcExtInfo() {}
89  CArcExtInfo(const UString &ext): Ext(ext) {}
90  CArcExtInfo(const UString &ext, const UString &addExt): Ext(ext), AddExt(addExt) {}
91};
92
93
94struct 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
122  bool Flags_KeepName() const { return (Flags & NArcInfoFlags::kKeepName) != 0; }
123  bool Flags_FindSignature() const { return (Flags & NArcInfoFlags::kFindSignature) != 0; }
124
125  bool Flags_AltStreams() const { return (Flags & NArcInfoFlags::kAltStreams) != 0; }
126  bool Flags_NtSecure() const { return (Flags & NArcInfoFlags::kNtSecure) != 0; }
127  bool Flags_SymLinks() const { return (Flags & NArcInfoFlags::kSymLinks) != 0; }
128  bool Flags_HardLinks() const { return (Flags & NArcInfoFlags::kHardLinks) != 0; }
129
130  bool Flags_UseGlobalOffset() const { return (Flags & NArcInfoFlags::kUseGlobalOffset) != 0; }
131  bool Flags_StartOpen() const { return (Flags & NArcInfoFlags::kStartOpen) != 0; }
132  bool Flags_BackwardOpen() const { return (Flags & NArcInfoFlags::kBackwardOpen) != 0; }
133  bool Flags_PreArc() const { return (Flags & NArcInfoFlags::kPreArc) != 0; }
134  bool Flags_PureStartOpen() const { return (Flags & NArcInfoFlags::kPureStartOpen) != 0; }
135
136  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
160  bool IsSplit() const { return StringsAreEqualNoCase_Ascii(Name, "Split"); }
161  // bool IsRar() const { return StringsAreEqualNoCase_Ascii(Name, "Rar"); }
162
163  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
182struct 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
199struct 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
216  void LoadIcons() { CCodecIcons::LoadIcons((HMODULE)Lib); }
217  #endif
218
219  CCodecLib():
220      CreateObject(NULL),
221      GetMethodProperty(NULL),
222      CreateDecoder(NULL),
223      CreateEncoder(NULL),
224      SetCodecs(NULL)
225      {}
226};
227
228#endif
229
230
231class 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);
241public:
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:
261    CReleaser(): _codecs(NULL) {}
262    void Set(CCodecs *codecs) { _codecs = codecs; }
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
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
294  CCodecs():
295      #ifdef EXTERNAL_CODECS
296      NeedSetLibCodecs(true),
297      #endif
298      CaseSensitiveChange(false),
299      CaseSensitive(false)
300      {}
301
302  ~CCodecs()
303  {
304    // OutputDebugStringA("~CCodecs");
305  }
306
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
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
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
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