// LoadCodecs.h #ifndef __LOAD_CODECS_H #define __LOAD_CODECS_H /* Client application uses LoadCodecs.* to load plugins to CCodecs object, that contains 3 lists of plugins: 1) Formats - internal and external archive handlers 2) Codecs - external codecs 3) Hashers - external hashers EXTERNAL_CODECS --------------- if EXTERNAL_CODECS is defined, then the code tries to load external plugins from DLL files (shared libraries). There are two types of executables in 7-Zip: 1) Executable that uses external plugins must be compiled with EXTERNAL_CODECS defined: - 7z.exe, 7zG.exe, 7zFM.exe Note: EXTERNAL_CODECS is used also in CPP/7zip/Common/CreateCoder.h that code is used in plugin module (7z.dll). 2) Standalone modules are compiled without EXTERNAL_CODECS: - SFX modules: 7z.sfx, 7zCon.sfx - standalone versions of console 7-Zip: 7za.exe, 7zr.exe if EXTERNAL_CODECS is defined, CCodecs class implements interfaces: - ICompressCodecsInfo : for Codecs - IHashers : for Hashers The client application can send CCodecs object to each plugin module. And plugin module can use ICompressCodecsInfo or IHashers interface to access another plugins. There are 2 ways to send (ICompressCodecsInfo * compressCodecsInfo) to plugin 1) for old versions: a) request ISetCompressCodecsInfo from created archive handler. b) call ISetCompressCodecsInfo::SetCompressCodecsInfo(compressCodecsInfo) 2) for new versions: a) request "SetCodecs" function from DLL file b) call SetCodecs(compressCodecsInfo) function from DLL file */ #include "../../../Common/MyBuffer.h" #include "../../../Common/MyCom.h" #include "../../../Common/MyString.h" #include "../../../Common/ComTry.h" #ifdef EXTERNAL_CODECS #include "../../../Windows/DLL.h" #endif #include "../../ICoder.h" #include "../../Archive/IArchive.h" #ifdef EXTERNAL_CODECS struct CDllCodecInfo { unsigned LibIndex; UInt32 CodecIndex; bool EncoderIsAssigned; bool DecoderIsAssigned; CLSID Encoder; CLSID Decoder; }; struct CDllHasherInfo { unsigned LibIndex; UInt32 HasherIndex; }; #endif struct CArcExtInfo { UString Ext; UString AddExt; CArcExtInfo() {} CArcExtInfo(const UString &ext): Ext(ext) {} CArcExtInfo(const UString &ext, const UString &addExt): Ext(ext), AddExt(addExt) {} }; struct CArcInfoEx { UInt32 Flags; Func_CreateInArchive CreateInArchive; Func_IsArc IsArcFunc; UString Name; CObjectVector Exts; #ifndef _SFX Func_CreateOutArchive CreateOutArchive; bool UpdateEnabled; bool NewInterface; // UInt32 Version; UInt32 SignatureOffset; CObjectVector Signatures; #ifdef NEW_FOLDER_INTERFACE UStringVector AssociateExts; #endif #endif #ifdef EXTERNAL_CODECS int LibIndex; UInt32 FormatIndex; CLSID ClassID; #endif bool Flags_KeepName() const { return (Flags & NArcInfoFlags::kKeepName) != 0; } bool Flags_FindSignature() const { return (Flags & NArcInfoFlags::kFindSignature) != 0; } bool Flags_AltStreams() const { return (Flags & NArcInfoFlags::kAltStreams) != 0; } bool Flags_NtSecure() const { return (Flags & NArcInfoFlags::kNtSecure) != 0; } bool Flags_SymLinks() const { return (Flags & NArcInfoFlags::kSymLinks) != 0; } bool Flags_HardLinks() const { return (Flags & NArcInfoFlags::kHardLinks) != 0; } bool Flags_UseGlobalOffset() const { return (Flags & NArcInfoFlags::kUseGlobalOffset) != 0; } bool Flags_StartOpen() const { return (Flags & NArcInfoFlags::kStartOpen) != 0; } bool Flags_BackwardOpen() const { return (Flags & NArcInfoFlags::kBackwardOpen) != 0; } bool Flags_PreArc() const { return (Flags & NArcInfoFlags::kPreArc) != 0; } bool Flags_PureStartOpen() const { return (Flags & NArcInfoFlags::kPureStartOpen) != 0; } UString GetMainExt() const { if (Exts.IsEmpty()) return UString(); return Exts[0].Ext; } int FindExtension(const UString &ext) const; /* UString GetAllExtensions() const { UString s; for (int i = 0; i < Exts.Size(); i++) { if (i > 0) s += ' '; s += Exts[i].Ext; } return s; } */ void AddExts(const UString &ext, const UString &addExt); bool IsSplit() const { return StringsAreEqualNoCase_Ascii(Name, "Split"); } // bool IsRar() const { return StringsAreEqualNoCase_Ascii(Name, "Rar"); } CArcInfoEx(): Flags(0), CreateInArchive(NULL), IsArcFunc(NULL) #ifndef _SFX , CreateOutArchive(NULL) , UpdateEnabled(false) , NewInterface(false) // , Version(0) , SignatureOffset(0) #endif #ifdef EXTERNAL_CODECS , LibIndex(-1) #endif {} }; #ifdef NEW_FOLDER_INTERFACE struct CCodecIcons { struct CIconPair { UString Ext; int IconIndex; }; CObjectVector IconPairs; void LoadIcons(HMODULE m); bool FindIconIndex(const UString &ext, int &iconIndex) const; }; #endif #ifdef EXTERNAL_CODECS struct CCodecLib #ifdef NEW_FOLDER_INTERFACE : public CCodecIcons #endif { NWindows::NDLL::CLibrary Lib; FString Path; Func_CreateObject CreateObject; Func_GetMethodProperty GetMethodProperty; Func_CreateDecoder CreateDecoder; Func_CreateEncoder CreateEncoder; Func_SetCodecs SetCodecs; CMyComPtr ComHashers; #ifdef NEW_FOLDER_INTERFACE void LoadIcons() { CCodecIcons::LoadIcons((HMODULE)Lib); } #endif CCodecLib(): CreateObject(NULL), GetMethodProperty(NULL), CreateDecoder(NULL), CreateEncoder(NULL), SetCodecs(NULL) {} }; #endif class CCodecs: #ifdef EXTERNAL_CODECS public ICompressCodecsInfo, public IHashers, #else public IUnknown, #endif public CMyUnknownImp { CLASS_NO_COPY(CCodecs); public: #ifdef EXTERNAL_CODECS CObjectVector Libs; FString MainDll_ErrorPath; void CloseLibs(); class CReleaser { CLASS_NO_COPY(CReleaser); /* CCodecsReleaser object releases CCodecs links. 1) CCodecs is COM object that is deleted when all links to that object will be released/ 2) CCodecs::Libs[i] can hold (ICompressCodecsInfo *) link to CCodecs object itself. To break that reference loop, we must close all CCodecs::Libs in CCodecsReleaser desttructor. */ CCodecs *_codecs; public: CReleaser(): _codecs(NULL) {} void Set(CCodecs *codecs) { _codecs = codecs; } ~CReleaser() { if (_codecs) _codecs->CloseLibs(); } }; bool NeedSetLibCodecs; // = false, if we don't need to set codecs for archive handler via ISetCompressCodecsInfo HRESULT LoadCodecs(); HRESULT LoadFormats(); HRESULT LoadDll(const FString &path, bool needCheckDll, bool *loadedOK = NULL); HRESULT LoadDllsFromFolder(const FString &folderPrefix); HRESULT CreateArchiveHandler(const CArcInfoEx &ai, bool outHandler, void **archive) const { return Libs[ai.LibIndex].CreateObject(&ai.ClassID, outHandler ? &IID_IOutArchive : &IID_IInArchive, (void **)archive); } #endif #ifdef NEW_FOLDER_INTERFACE CCodecIcons InternalIcons; #endif CObjectVector Formats; #ifdef EXTERNAL_CODECS CRecordVector Codecs; CRecordVector Hashers; #endif bool CaseSensitiveChange; bool CaseSensitive; CCodecs(): #ifdef EXTERNAL_CODECS NeedSetLibCodecs(true), #endif CaseSensitiveChange(false), CaseSensitive(false) {} ~CCodecs() { // OutputDebugStringA("~CCodecs"); } const wchar_t *GetFormatNamePtr(int formatIndex) const { return formatIndex < 0 ? L"#" : (const wchar_t *)Formats[formatIndex].Name; } HRESULT Load(); #ifndef _SFX int FindFormatForArchiveName(const UString &arcPath) const; int FindFormatForExtension(const UString &ext) const; int FindFormatForArchiveType(const UString &arcType) const; bool FindFormatForArchiveType(const UString &arcType, CIntVector &formatIndices) const; #endif #ifdef EXTERNAL_CODECS MY_UNKNOWN_IMP2(ICompressCodecsInfo, IHashers) STDMETHOD(GetNumMethods)(UInt32 *numMethods); STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value); STDMETHOD(CreateDecoder)(UInt32 index, const GUID *iid, void **coder); STDMETHOD(CreateEncoder)(UInt32 index, const GUID *iid, void **coder); STDMETHOD_(UInt32, GetNumHashers)(); STDMETHOD(GetHasherProp)(UInt32 index, PROPID propID, PROPVARIANT *value); STDMETHOD(CreateHasher)(UInt32 index, IHasher **hasher); #else MY_UNKNOWN_IMP #endif // EXTERNAL_CODECS #ifdef EXTERNAL_CODECS int GetCodec_LibIndex(UInt32 index) const; bool GetCodec_DecoderIsAssigned(UInt32 index) const; bool GetCodec_EncoderIsAssigned(UInt32 index) const; UInt32 GetCodec_NumStreams(UInt32 index); HRESULT GetCodec_Id(UInt32 index, UInt64 &id); AString GetCodec_Name(UInt32 index); int GetHasherLibIndex(UInt32 index); UInt64 GetHasherId(UInt32 index); AString GetHasherName(UInt32 index); UInt32 GetHasherDigestSize(UInt32 index); #endif HRESULT CreateInArchive(unsigned formatIndex, CMyComPtr &archive) const { const CArcInfoEx &ai = Formats[formatIndex]; #ifdef EXTERNAL_CODECS if (ai.LibIndex < 0) #endif { COM_TRY_BEGIN archive = ai.CreateInArchive(); return S_OK; COM_TRY_END } #ifdef EXTERNAL_CODECS return CreateArchiveHandler(ai, false, (void **)&archive); #endif } #ifndef _SFX HRESULT CreateOutArchive(unsigned formatIndex, CMyComPtr &archive) const { const CArcInfoEx &ai = Formats[formatIndex]; #ifdef EXTERNAL_CODECS if (ai.LibIndex < 0) #endif { COM_TRY_BEGIN archive = ai.CreateOutArchive(); return S_OK; COM_TRY_END } #ifdef EXTERNAL_CODECS return CreateArchiveHandler(ai, true, (void **)&archive); #endif } int FindOutFormatFromName(const UString &name) const { FOR_VECTOR (i, Formats) { const CArcInfoEx &arc = Formats[i]; if (!arc.UpdateEnabled) continue; if (arc.Name.IsEqualTo_NoCase(name)) return i; } return -1; } #endif // _SFX }; #ifdef EXTERNAL_CODECS #define CREATE_CODECS_OBJECT \ CCodecs *codecs = new CCodecs; \ CExternalCodecs __externalCodecs; \ __externalCodecs.GetCodecs = codecs; \ __externalCodecs.GetHashers = codecs; \ CCodecs::CReleaser codecsReleaser; \ codecsReleaser.Set(codecs); #else #define CREATE_CODECS_OBJECT \ CCodecs *codecs = new CCodecs; \ CMyComPtr __codecsRef = codecs; #endif #endif