// LoadCodecs.h #ifndef ZIP7_INC_LOAD_CODECS_H #define ZIP7_INC_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 Z7_EXTERNAL_CODECS --------------- if Z7_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 Z7_EXTERNAL_CODECS defined: - 7z.exe, 7zG.exe, 7zFM.exe Note: Z7_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 Z7_EXTERNAL_CODECS: - SFX modules: 7z.sfx, 7zCon.sfx - standalone versions of console 7-Zip: 7za.exe, 7zr.exe if Z7_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 Z7_EXTERNAL_CODECS #include "../../../Windows/DLL.h" #endif #include "../../ICoder.h" #include "../../Archive/IArchive.h" #ifdef Z7_EXTERNAL_CODECS struct CDllCodecInfo { unsigned LibIndex; UInt32 CodecIndex; bool EncoderIsAssigned; bool DecoderIsAssigned; bool IsFilter; bool IsFilter_Assigned; 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; UInt32 TimeFlags; Func_CreateInArchive CreateInArchive; Func_IsArc IsArcFunc; UString Name; CObjectVector Exts; #ifndef Z7_SFX Func_CreateOutArchive CreateOutArchive; bool UpdateEnabled; bool NewInterface; // UInt32 Version; UInt32 SignatureOffset; CObjectVector Signatures; /* #ifdef NEW_FOLDER_INTERFACE UStringVector AssociateExts; #endif */ #endif #ifdef Z7_EXTERNAL_CODECS int LibIndex; UInt32 FormatIndex; CLSID ClassID; #endif int Compare(const CArcInfoEx &a) const { const int res = Name.Compare(a.Name); if (res != 0) return res; #ifdef Z7_EXTERNAL_CODECS return MyCompare(LibIndex, a.LibIndex); #else return 0; #endif /* if (LibIndex < a.LibIndex) return -1; if (LibIndex > a.LibIndex) return 1; return 0; */ } 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_NtSecurity() 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; } bool Flags_ByExtOnlyOpen() const { return (Flags & NArcInfoFlags::kByExtOnlyOpen) != 0; } bool Flags_HashHandler() const { return (Flags & NArcInfoFlags::kHashHandler) != 0; } bool Flags_CTime() const { return (Flags & NArcInfoFlags::kCTime) != 0; } bool Flags_ATime() const { return (Flags & NArcInfoFlags::kATime) != 0; } bool Flags_MTime() const { return (Flags & NArcInfoFlags::kMTime) != 0; } bool Flags_CTime_Default() const { return (Flags & NArcInfoFlags::kCTime_Default) != 0; } bool Flags_ATime_Default() const { return (Flags & NArcInfoFlags::kATime_Default) != 0; } bool Flags_MTime_Default() const { return (Flags & NArcInfoFlags::kMTime_Default) != 0; } UInt32 Get_TimePrecFlags() const { return (TimeFlags >> NArcInfoTimeFlags::kTime_Prec_Mask_bit_index) & (((UInt32)1 << NArcInfoTimeFlags::kTime_Prec_Mask_num_bits) - 1); } UInt32 Get_DefaultTimePrec() const { return (TimeFlags >> NArcInfoTimeFlags::kTime_Prec_Default_bit_index) & (((UInt32)1 << NArcInfoTimeFlags::kTime_Prec_Default_num_bits) - 1); } UString GetMainExt() const { if (Exts.IsEmpty()) return UString(); return Exts[0].Ext; } int FindExtension(const UString &ext) const; bool Is_7z() const { return Name.IsEqualTo_Ascii_NoCase("7z"); } bool Is_Split() const { return Name.IsEqualTo_Ascii_NoCase("Split"); } bool Is_Xz() const { return Name.IsEqualTo_Ascii_NoCase("xz"); } bool Is_BZip2() const { return Name.IsEqualTo_Ascii_NoCase("bzip2"); } bool Is_GZip() const { return Name.IsEqualTo_Ascii_NoCase("gzip"); } bool Is_Tar() const { return Name.IsEqualTo_Ascii_NoCase("tar"); } bool Is_Zip() const { return Name.IsEqualTo_Ascii_NoCase("zip"); } bool Is_Rar() const { return Name.IsEqualTo_Ascii_NoCase("rar"); } bool Is_Zstd() const { return Name.IsEqualTo_Ascii_NoCase("zstd"); } /* UString GetAllExtensions() const { UString s; for (int i = 0; i < Exts.Size(); i++) { if (i > 0) s.Add_Space(); s += Exts[i].Ext; } return s; } */ void AddExts(const UString &ext, const UString &addExt); CArcInfoEx(): Flags(0), TimeFlags(0), CreateInArchive(NULL), IsArcFunc(NULL) #ifndef Z7_SFX , CreateOutArchive(NULL) , UpdateEnabled(false) , NewInterface(false) // , Version(0) , SignatureOffset(0) #endif #ifdef Z7_EXTERNAL_CODECS , LibIndex(-1) #endif {} }; #ifdef Z7_EXTERNAL_CODECS struct CCodecLib { NWindows::NDLL::CLibrary Lib; FString Path; Func_CreateObject CreateObject; Func_GetMethodProperty GetMethodProperty; Func_CreateDecoder CreateDecoder; Func_CreateEncoder CreateEncoder; Func_SetCodecs SetCodecs; CMyComPtr ComHashers; UInt32 Version; /* #ifdef NEW_FOLDER_INTERFACE CCodecIcons CodecIcons; void LoadIcons() { CodecIcons.LoadIcons((HMODULE)Lib); } #endif */ CCodecLib(): CreateObject(NULL), GetMethodProperty(NULL), CreateDecoder(NULL), CreateEncoder(NULL), SetCodecs(NULL), Version(0) {} }; #endif struct CCodecError { FString Path; HRESULT ErrorCode; AString Message; CCodecError(): ErrorCode(0) {} }; struct CCodecInfoUser { // unsigned LibIndex; // UInt32 CodecIndex; // UInt64 id; bool EncoderIsAssigned; bool DecoderIsAssigned; bool IsFilter; bool IsFilter_Assigned; UInt32 NumStreams; AString Name; }; class CCodecs Z7_final: #ifdef Z7_EXTERNAL_CODECS public ICompressCodecsInfo, public IHashers, #else public IUnknown, #endif public CMyUnknownImp { #ifdef Z7_EXTERNAL_CODECS Z7_IFACES_IMP_UNK_2(ICompressCodecsInfo, IHashers) #else Z7_COM_UNKNOWN_IMP_0 #endif // Z7_EXTERNAL_CODECS Z7_CLASS_NO_COPY(CCodecs) public: #ifdef Z7_EXTERNAL_CODECS CObjectVector Libs; FString MainDll_ErrorPath; CObjectVector Errors; void AddLastError(const FString &path); void CloseLibs(); class CReleaser { Z7_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[(unsigned)ai.LibIndex].CreateObject(&ai.ClassID, outHandler ? &IID_IOutArchive : &IID_IInArchive, (void **)archive); } #endif /* #ifdef NEW_FOLDER_INTERFACE CCodecIcons InternalIcons; #endif */ CObjectVector Formats; #ifdef Z7_EXTERNAL_CODECS CRecordVector Codecs; CRecordVector Hashers; #endif bool CaseSensitive_Change; bool CaseSensitive; CCodecs(): #ifdef Z7_EXTERNAL_CODECS NeedSetLibCodecs(true), #endif CaseSensitive_Change(false), CaseSensitive(false) {} ~CCodecs() { // OutputDebugStringA("~CCodecs"); } const wchar_t *GetFormatNamePtr(int formatIndex) const { return formatIndex < 0 ? L"#" : (const wchar_t *)Formats[(unsigned)formatIndex].Name; } HRESULT Load(); #ifndef Z7_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 Z7_EXTERNAL_CODECS int GetCodec_LibIndex(UInt32 index) const; bool GetCodec_DecoderIsAssigned(UInt32 index) const; bool GetCodec_EncoderIsAssigned(UInt32 index) const; bool GetCodec_IsFilter(UInt32 index, bool &isAssigned) 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); void GetCodecsErrorMessage(UString &s); #endif HRESULT CreateInArchive(unsigned formatIndex, CMyComPtr &archive) const { const CArcInfoEx &ai = Formats[formatIndex]; #ifdef Z7_EXTERNAL_CODECS if (ai.LibIndex < 0) #endif { COM_TRY_BEGIN archive = ai.CreateInArchive(); return S_OK; COM_TRY_END } #ifdef Z7_EXTERNAL_CODECS return CreateArchiveHandler(ai, false, (void **)&archive); #endif } #ifndef Z7_SFX HRESULT CreateOutArchive(unsigned formatIndex, CMyComPtr &archive) const { const CArcInfoEx &ai = Formats[formatIndex]; #ifdef Z7_EXTERNAL_CODECS if (ai.LibIndex < 0) #endif { COM_TRY_BEGIN archive = ai.CreateOutArchive(); return S_OK; COM_TRY_END } #ifdef Z7_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 (int)i; } return -1; } void Get_CodecsInfoUser_Vector(CObjectVector &v); #endif // Z7_SFX }; #ifdef Z7_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