// LoadCodecs.cpp #include "StdAfx.h" #include "../../../../C/7zVersion.h" #include "../../../Common/MyCom.h" #include "../../../Common/StringToInt.h" #include "../../../Common/StringConvert.h" #include "../../../Windows/PropVariant.h" #include "LoadCodecs.h" using namespace NWindows; #ifdef NEW_FOLDER_INTERFACE #include "../../../Common/StringToInt.h" #endif #include "../../ICoder.h" #include "../../Common/RegisterArc.h" #ifdef EXTERNAL_CODECS #include "../../../Windows/FileFind.h" #include "../../../Windows/DLL.h" #ifdef NEW_FOLDER_INTERFACE #include "../../../Windows/ResourceString.h" static const UINT kIconTypesResId = 100; #endif #ifdef _WIN32 #include "../../../Windows/FileName.h" #include "../../../Windows/Registry.h" #endif using namespace NFile; #ifdef _WIN32 extern HINSTANCE g_hInstance; #endif #define kCodecsFolderName FTEXT("Codecs") #define kFormatsFolderName FTEXT("Formats") static CFSTR kMainDll = FTEXT("7z.dll"); #ifdef _WIN32 static LPCTSTR kRegistryPath = TEXT("Software") TEXT(STRING_PATH_SEPARATOR) TEXT("7-zip"); static LPCWSTR kProgramPathValue = L"Path"; static LPCWSTR kProgramPath2Value = L"Path" #ifdef _WIN64 L"64"; #else L"32"; #endif static bool ReadPathFromRegistry(HKEY baseKey, LPCWSTR value, FString &path) { NRegistry::CKey key; if (key.Open(baseKey, kRegistryPath, KEY_READ) == ERROR_SUCCESS) { UString pathU; if (key.QueryValue(value, pathU) == ERROR_SUCCESS) { path = us2fs(pathU); NName::NormalizeDirPathPrefix(path); return NFind::DoesFileExist(path + kMainDll); } } return false; } #endif // _WIN32 #endif // EXTERNAL_CODECS static const unsigned kNumArcsMax = 48; static unsigned g_NumArcs = 0; static const CArcInfo *g_Arcs[kNumArcsMax]; void RegisterArc(const CArcInfo *arcInfo) throw() { if (g_NumArcs < kNumArcsMax) { g_Arcs[g_NumArcs] = arcInfo; g_NumArcs++; } } static void SplitString(const UString &srcString, UStringVector &destStrings) { destStrings.Clear(); UString s; unsigned len = srcString.Len(); if (len == 0) return; for (unsigned i = 0; i < len; i++) { wchar_t c = srcString[i]; if (c == L' ') { if (!s.IsEmpty()) { destStrings.Add(s); s.Empty(); } } else s += c; } if (!s.IsEmpty()) destStrings.Add(s); } int CArcInfoEx::FindExtension(const UString &ext) const { FOR_VECTOR (i, Exts) if (ext.IsEqualToNoCase(Exts[i].Ext)) return i; return -1; } void CArcInfoEx::AddExts(const UString &ext, const UString &addExt) { UStringVector exts, addExts; SplitString(ext, exts); SplitString(addExt, addExts); FOR_VECTOR (i, exts) { CArcExtInfo extInfo; extInfo.Ext = exts[i]; if (i < addExts.Size()) { extInfo.AddExt = addExts[i]; if (extInfo.AddExt == L"*") extInfo.AddExt.Empty(); } Exts.Add(extInfo); } } #ifndef _SFX static bool ParseSignatures(const Byte *data, unsigned size, CObjectVector<CByteBuffer> &signatures) { signatures.Clear(); while (size > 0) { unsigned len = *data++; size--; if (len > size) return false; signatures.AddNew().CopyFrom(data, len); data += len; size -= len; } return true; } #endif // _SFX #ifdef EXTERNAL_CODECS static FString GetBaseFolderPrefixFromRegistry() { FString moduleFolderPrefix = NDLL::GetModuleDirPrefix(); #ifdef _WIN32 if (!NFind::DoesFileExist(moduleFolderPrefix + kMainDll) && !NFind::DoesDirExist(moduleFolderPrefix + kCodecsFolderName) && !NFind::DoesDirExist(moduleFolderPrefix + kFormatsFolderName)) { FString path; if (ReadPathFromRegistry(HKEY_CURRENT_USER, kProgramPath2Value, path)) return path; if (ReadPathFromRegistry(HKEY_LOCAL_MACHINE, kProgramPath2Value, path)) return path; if (ReadPathFromRegistry(HKEY_CURRENT_USER, kProgramPathValue, path)) return path; if (ReadPathFromRegistry(HKEY_LOCAL_MACHINE, kProgramPathValue, path)) return path; } #endif return moduleFolderPrefix; } static HRESULT GetCoderClass(Func_GetMethodProperty getMethodProperty, UInt32 index, PROPID propId, CLSID &clsId, bool &isAssigned) { NCOM::CPropVariant prop; isAssigned = false; RINOK(getMethodProperty(index, propId, &prop)); if (prop.vt == VT_BSTR) { if (::SysStringByteLen(prop.bstrVal) != sizeof(GUID)) return E_FAIL; isAssigned = true; clsId = *(const GUID *)prop.bstrVal; } else if (prop.vt != VT_EMPTY) return E_FAIL; return S_OK; } HRESULT CCodecs::LoadCodecs() { CCodecLib &lib = Libs.Back(); lib.GetMethodProperty = (Func_GetMethodProperty)lib.Lib.GetProc("GetMethodProperty"); if (lib.GetMethodProperty) { UInt32 numMethods = 1; Func_GetNumberOfMethods getNumberOfMethodsFunc = (Func_GetNumberOfMethods)lib.Lib.GetProc("GetNumberOfMethods"); if (getNumberOfMethodsFunc) { RINOK(getNumberOfMethodsFunc(&numMethods)); } for (UInt32 i = 0; i < numMethods; i++) { CDllCodecInfo info; info.LibIndex = Libs.Size() - 1; info.CodecIndex = i; RINOK(GetCoderClass(lib.GetMethodProperty, i, NMethodPropID::kEncoder, info.Encoder, info.EncoderIsAssigned)); RINOK(GetCoderClass(lib.GetMethodProperty, i, NMethodPropID::kDecoder, info.Decoder, info.DecoderIsAssigned)); Codecs.Add(info); } } Func_GetHashers getHashers = (Func_GetHashers)lib.Lib.GetProc("GetHashers"); if (getHashers) { RINOK(getHashers(&lib.Hashers)); if (lib.Hashers) { UInt32 numMethods = lib.Hashers->GetNumHashers(); for (UInt32 i = 0; i < numMethods; i++) { CDllHasherInfo info; info.LibIndex = Libs.Size() - 1; info.HasherIndex = i; Hashers.Add(info); } } } return S_OK; } static HRESULT GetProp( Func_GetHandlerProperty getProp, Func_GetHandlerProperty2 getProp2, UInt32 index, PROPID propID, NCOM::CPropVariant &prop) { if (getProp2) return getProp2(index, propID, &prop);; return getProp(propID, &prop); } static HRESULT GetProp_Bool( Func_GetHandlerProperty getProp, Func_GetHandlerProperty2 getProp2, UInt32 index, PROPID propID, bool &res) { res = false; NCOM::CPropVariant prop; RINOK(GetProp(getProp, getProp2, index, propID, prop)); if (prop.vt == VT_BOOL) res = VARIANT_BOOLToBool(prop.boolVal); else if (prop.vt != VT_EMPTY) return E_FAIL; return S_OK; } static HRESULT GetProp_UInt32( Func_GetHandlerProperty getProp, Func_GetHandlerProperty2 getProp2, UInt32 index, PROPID propID, UInt32 &res, bool &defined) { res = 0; defined = false; NCOM::CPropVariant prop; RINOK(GetProp(getProp, getProp2, index, propID, prop)); if (prop.vt == VT_UI4) { res = prop.ulVal; defined = true; } else if (prop.vt != VT_EMPTY) return E_FAIL; return S_OK; } static HRESULT GetProp_String( Func_GetHandlerProperty getProp, Func_GetHandlerProperty2 getProp2, UInt32 index, PROPID propID, UString &res) { res.Empty(); NCOM::CPropVariant prop; RINOK(GetProp(getProp, getProp2, index, propID, prop)); if (prop.vt == VT_BSTR) res = prop.bstrVal; else if (prop.vt != VT_EMPTY) return E_FAIL; return S_OK; } static HRESULT GetProp_RawData( Func_GetHandlerProperty getProp, Func_GetHandlerProperty2 getProp2, UInt32 index, PROPID propID, CByteBuffer &bb) { bb.Free(); NCOM::CPropVariant prop; RINOK(GetProp(getProp, getProp2, index, propID, prop)); if (prop.vt == VT_BSTR) { UINT len = ::SysStringByteLen(prop.bstrVal); bb.CopyFrom((const Byte *)prop.bstrVal, len); } else if (prop.vt != VT_EMPTY) return E_FAIL; return S_OK; } static const UInt32 kArcFlagsPars[] = { NArchive::NHandlerPropID::kKeepName, NArcInfoFlags::kKeepName, NArchive::NHandlerPropID::kAltStreams, NArcInfoFlags::kAltStreams, NArchive::NHandlerPropID::kNtSecure, NArcInfoFlags::kNtSecure }; HRESULT CCodecs::LoadFormats() { const NDLL::CLibrary &lib = Libs.Back().Lib; Func_GetHandlerProperty getProp = NULL; Func_GetHandlerProperty2 getProp2 = (Func_GetHandlerProperty2)lib.GetProc("GetHandlerProperty2"); Func_GetIsArc getIsArc = (Func_GetIsArc)lib.GetProc("GetIsArc"); UInt32 numFormats = 1; if (getProp2) { Func_GetNumberOfFormats getNumberOfFormats = (Func_GetNumberOfFormats)lib.GetProc("GetNumberOfFormats"); if (getNumberOfFormats) { RINOK(getNumberOfFormats(&numFormats)); } } else { getProp = (Func_GetHandlerProperty)lib.GetProc("GetHandlerProperty"); if (!getProp) return S_OK; } for (UInt32 i = 0; i < numFormats; i++) { CArcInfoEx item; item.LibIndex = Libs.Size() - 1; item.FormatIndex = i; RINOK(GetProp_String(getProp, getProp2, i, NArchive::NHandlerPropID::kName, item.Name)); { NCOM::CPropVariant prop; if (GetProp(getProp, getProp2, i, NArchive::NHandlerPropID::kClassID, prop) != S_OK) continue; if (prop.vt != VT_BSTR) continue; if (::SysStringByteLen(prop.bstrVal) != sizeof(GUID)) return E_FAIL; item.ClassID = *(const GUID *)prop.bstrVal; prop.Clear(); } UString ext, addExt; RINOK(GetProp_String(getProp, getProp2, i, NArchive::NHandlerPropID::kExtension, ext)); RINOK(GetProp_String(getProp, getProp2, i, NArchive::NHandlerPropID::kAddExtension, addExt)); item.AddExts(ext, addExt); GetProp_Bool(getProp, getProp2, i, NArchive::NHandlerPropID::kUpdate, item.UpdateEnabled); bool flags_Defined = false; RINOK(GetProp_UInt32(getProp, getProp2, i, NArchive::NHandlerPropID::kFlags, item.Flags, flags_Defined)); item.NewInterface = flags_Defined; if (!flags_Defined) // && item.UpdateEnabled { // support for DLL version before 9.31: for (unsigned j = 0; j < ARRAY_SIZE(kArcFlagsPars); j += 2) { bool val = false; GetProp_Bool(getProp, getProp2, i, kArcFlagsPars[j], val); if (val) item.Flags |= kArcFlagsPars[j + 1]; } } CByteBuffer sig; RINOK(GetProp_RawData(getProp, getProp2, i, NArchive::NHandlerPropID::kSignature, sig)); if (sig.Size() != 0) item.Signatures.Add(sig); else { RINOK(GetProp_RawData(getProp, getProp2, i, NArchive::NHandlerPropID::kMultiSignature, sig)); ParseSignatures(sig, (unsigned)sig.Size(), item.Signatures); } bool signatureOffset_Defined; RINOK(GetProp_UInt32(getProp, getProp2, i, NArchive::NHandlerPropID::kSignatureOffset, item.SignatureOffset, signatureOffset_Defined)); // bool version_Defined; // RINOK(GetProp_UInt32(getProp, getProp2, i, NArchive::NHandlerPropID::kVersion, item.Version, version_Defined)); if (getIsArc) getIsArc(i, &item.IsArcFunc); Formats.Add(item); } return S_OK; } #ifdef NEW_FOLDER_INTERFACE void CCodecIcons::LoadIcons(HMODULE m) { UString iconTypes; MyLoadString(m, kIconTypesResId, iconTypes); UStringVector pairs; SplitString(iconTypes, pairs); FOR_VECTOR (i, pairs) { const UString &s = pairs[i]; int pos = s.Find(L':'); CIconPair iconPair; iconPair.IconIndex = -1; if (pos < 0) pos = s.Len(); else { UString num = s.Ptr(pos + 1); if (!num.IsEmpty()) { const wchar_t *end; iconPair.IconIndex = ConvertStringToUInt32(num, &end); if (*end != 0) continue; } } iconPair.Ext = s.Left(pos); IconPairs.Add(iconPair); } } bool CCodecIcons::FindIconIndex(const UString &ext, int &iconIndex) const { iconIndex = -1; FOR_VECTOR (i, IconPairs) { const CIconPair &pair = IconPairs[i]; if (ext.IsEqualToNoCase(pair.Ext)) { iconIndex = pair.IconIndex; return true; } } return false; } #endif // EXTERNAL_CODECS #ifdef _7ZIP_LARGE_PAGES extern "C" { extern SIZE_T g_LargePageSize; } #endif HRESULT CCodecs::LoadDll(const FString &dllPath, bool needCheckDll) { if (needCheckDll) { NDLL::CLibrary library; if (!library.LoadEx(dllPath, LOAD_LIBRARY_AS_DATAFILE)) return S_OK; } Libs.Add(CCodecLib()); CCodecLib &lib = Libs.Back(); lib.Path = dllPath; bool used = false; HRESULT res = S_OK; if (lib.Lib.Load(dllPath)) { #ifdef NEW_FOLDER_INTERFACE lib.LoadIcons(); #endif #ifdef _7ZIP_LARGE_PAGES if (g_LargePageSize != 0) { Func_SetLargePageMode setLargePageMode = (Func_SetLargePageMode)lib.Lib.GetProc("SetLargePageMode"); if (setLargePageMode) setLargePageMode(); } #endif if (CaseSensitiveChange) { Func_SetCaseSensitive setCaseSensitive = (Func_SetCaseSensitive)lib.Lib.GetProc("SetCaseSensitive"); if (setCaseSensitive) setCaseSensitive(CaseSensitive ? 1 : 0); } lib.CreateObject = (Func_CreateObject)lib.Lib.GetProc("CreateObject"); if (lib.CreateObject) { unsigned startSize = Codecs.Size() + Hashers.Size(); res = LoadCodecs(); used = (startSize != Codecs.Size() + Hashers.Size()); if (res == S_OK) { startSize = Formats.Size(); res = LoadFormats(); if (startSize != Formats.Size()) used = true; } } } if (!used) Libs.DeleteBack(); return res; } HRESULT CCodecs::LoadDllsFromFolder(const FString &folderPrefix) { NFile::NFind::CEnumerator enumerator(folderPrefix + FCHAR_ANY_MASK); NFile::NFind::CFileInfo fi; while (enumerator.Next(fi)) { if (fi.IsDir()) continue; RINOK(LoadDll(folderPrefix + fi.Name, true)); } return S_OK; } #endif HRESULT CCodecs::Load() { #ifdef NEW_FOLDER_INTERFACE InternalIcons.LoadIcons(g_hInstance); #endif Formats.Clear(); #ifdef EXTERNAL_CODECS Codecs.Clear(); Hashers.Clear(); #endif for (UInt32 i = 0; i < g_NumArcs; i++) { const CArcInfo &arc = *g_Arcs[i]; CArcInfoEx item; item.Name.SetFromAscii(arc.Name); item.CreateInArchive = arc.CreateInArchive; item.IsArcFunc = arc.IsArc; item.Flags = arc.Flags; { UString e, ae; if (arc.Ext) e.SetFromAscii(arc.Ext); if (arc.AddExt) ae.SetFromAscii(arc.AddExt); item.AddExts(e, ae); } #ifndef _SFX item.CreateOutArchive = arc.CreateOutArchive; item.UpdateEnabled = (arc.CreateOutArchive != NULL); item.SignatureOffset = arc.SignatureOffset; // item.Version = MY_VER_MIX; item.NewInterface = true; if (arc.IsMultiSignature()) ParseSignatures(arc.Signature, arc.SignatureSize, item.Signatures); else item.Signatures.AddNew().CopyFrom(arc.Signature, arc.SignatureSize); #endif Formats.Add(item); } #ifdef EXTERNAL_CODECS const FString baseFolder = GetBaseFolderPrefixFromRegistry(); RINOK(LoadDll(baseFolder + kMainDll, false)); RINOK(LoadDllsFromFolder(baseFolder + kCodecsFolderName FSTRING_PATH_SEPARATOR)); RINOK(LoadDllsFromFolder(baseFolder + kFormatsFolderName FSTRING_PATH_SEPARATOR)); #endif return S_OK; } #ifndef _SFX int CCodecs::FindFormatForArchiveName(const UString &arcPath) const { int slashPos = arcPath.ReverseFind(WCHAR_PATH_SEPARATOR); int dotPos = arcPath.ReverseFind(L'.'); if (dotPos < 0 || dotPos < slashPos) return -1; const UString ext = arcPath.Ptr(dotPos + 1); if (ext.IsEmpty()) return -1; if (ext.IsEqualToNoCase(L"exe")) return -1; FOR_VECTOR (i, Formats) { const CArcInfoEx &arc = Formats[i]; /* if (!arc.UpdateEnabled) continue; */ if (arc.FindExtension(ext) >= 0) return i; } return -1; } int CCodecs::FindFormatForExtension(const UString &ext) const { if (ext.IsEmpty()) return -1; FOR_VECTOR (i, Formats) if (Formats[i].FindExtension(ext) >= 0) return i; return -1; } int CCodecs::FindFormatForArchiveType(const UString &arcType) const { FOR_VECTOR (i, Formats) if (Formats[i].Name.IsEqualToNoCase(arcType)) return i; return -1; } bool CCodecs::FindFormatForArchiveType(const UString &arcType, CIntVector &formatIndices) const { formatIndices.Clear(); for (unsigned pos = 0; pos < arcType.Len();) { int pos2 = arcType.Find('.', pos); if (pos2 < 0) pos2 = arcType.Len(); const UString name = arcType.Mid(pos, pos2 - pos); if (name.IsEmpty()) return false; int index = FindFormatForArchiveType(name); if (index < 0 && name != L"*") { formatIndices.Clear(); return false; } formatIndices.Add(index); pos = pos2 + 1; } return true; } #endif // _SFX #ifdef EXTERNAL_CODECS // #define EXPORT_CODECS #ifdef EXPORT_CODECS extern unsigned g_NumCodecs; STDAPI CreateCoder2(bool encode, UInt32 index, const GUID *iid, void **outObject); STDAPI GetMethodProperty(UInt32 codecIndex, PROPID propID, PROPVARIANT *value); #define NUM_EXPORT_CODECS g_NumCodecs extern unsigned g_NumHashers; STDAPI CreateHasher(UInt32 index, IHasher **hasher); STDAPI GetHasherProp(UInt32 codecIndex, PROPID propID, PROPVARIANT *value); #define NUM_EXPORT_HASHERS g_NumHashers #else // EXPORT_CODECS #define NUM_EXPORT_CODECS 0 #define NUM_EXPORT_HASHERS 0 #endif // EXPORT_CODECS STDMETHODIMP CCodecs::GetNumberOfMethods(UInt32 *numMethods) { *numMethods = NUM_EXPORT_CODECS #ifdef EXTERNAL_CODECS + Codecs.Size() #endif ; return S_OK; } STDMETHODIMP CCodecs::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) { #ifdef EXPORT_CODECS if (index < g_NumCodecs) return GetMethodProperty(index, propID, value); #endif #ifdef EXTERNAL_CODECS const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS]; if (propID == NMethodPropID::kDecoderIsAssigned || propID == NMethodPropID::kEncoderIsAssigned) { NCOM::CPropVariant prop; prop = (propID == NMethodPropID::kDecoderIsAssigned) ? ci.DecoderIsAssigned : ci.EncoderIsAssigned; prop.Detach(value); return S_OK; } return Libs[ci.LibIndex].GetMethodProperty(ci.CodecIndex, propID, value); #else return E_FAIL; #endif } STDMETHODIMP CCodecs::CreateDecoder(UInt32 index, const GUID *iid, void **coder) { #ifdef EXPORT_CODECS if (index < g_NumCodecs) return CreateCoder2(false, index, iid, coder); #endif #ifdef EXTERNAL_CODECS const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS]; if (ci.DecoderIsAssigned) return Libs[ci.LibIndex].CreateObject(&ci.Decoder, iid, (void **)coder); return S_OK; #else return E_FAIL; #endif } STDMETHODIMP CCodecs::CreateEncoder(UInt32 index, const GUID *iid, void **coder) { #ifdef EXPORT_CODECS if (index < g_NumCodecs) return CreateCoder2(true, index, iid, coder); #endif #ifdef EXTERNAL_CODECS const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS]; if (ci.EncoderIsAssigned) return Libs[ci.LibIndex].CreateObject(&ci.Encoder, iid, (void **)coder); return S_OK; #else return E_FAIL; #endif } STDMETHODIMP_(UInt32) CCodecs::GetNumHashers() { return NUM_EXPORT_HASHERS #ifdef EXTERNAL_CODECS + Hashers.Size() #endif ; } STDMETHODIMP CCodecs::GetHasherProp(UInt32 index, PROPID propID, PROPVARIANT *value) { #ifdef EXPORT_CODECS if (index < g_NumHashers) return ::GetHasherProp(index, propID, value); #endif #ifdef EXTERNAL_CODECS const CDllHasherInfo &ci = Hashers[index - NUM_EXPORT_HASHERS]; return Libs[ci.LibIndex].Hashers->GetHasherProp(ci.HasherIndex, propID, value); #else return E_FAIL; #endif } STDMETHODIMP CCodecs::CreateHasher(UInt32 index, IHasher **hasher) { #ifdef EXPORT_CODECS if (index < g_NumHashers) return CreateHasher(index, hasher); #endif #ifdef EXTERNAL_CODECS const CDllHasherInfo &ci = Hashers[index - NUM_EXPORT_HASHERS]; return Libs[ci.LibIndex].Hashers->CreateHasher(ci.HasherIndex, hasher); #else return E_FAIL; #endif } int CCodecs::GetCodecLibIndex(UInt32 index) { #ifdef EXPORT_CODECS if (index < g_NumCodecs) return -1; #endif #ifdef EXTERNAL_CODECS const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS]; return ci.LibIndex; #else return -1; #endif } int CCodecs::GetHasherLibIndex(UInt32 index) { #ifdef EXPORT_CODECS if (index < g_NumHashers) return -1; #endif #ifdef EXTERNAL_CODECS const CDllHasherInfo &ci = Hashers[index - NUM_EXPORT_HASHERS]; return ci.LibIndex; #else return -1; #endif } bool CCodecs::GetCodecEncoderIsAssigned(UInt32 index) { #ifdef EXPORT_CODECS if (index < g_NumCodecs) { NCOM::CPropVariant prop; if (GetProperty(index, NMethodPropID::kEncoder, &prop) == S_OK) if (prop.vt != VT_EMPTY) return true; return false; } #endif #ifdef EXTERNAL_CODECS const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS]; return ci.EncoderIsAssigned; #else return false; #endif } HRESULT CCodecs::GetCodecId(UInt32 index, UInt64 &id) { NCOM::CPropVariant prop; RINOK(GetProperty(index, NMethodPropID::kID, &prop)); if (prop.vt != VT_UI8) return E_INVALIDARG; id = prop.uhVal.QuadPart; return S_OK; } UString CCodecs::GetCodecName(UInt32 index) { UString s; NCOM::CPropVariant prop; if (GetProperty(index, NMethodPropID::kName, &prop) == S_OK) if (prop.vt == VT_BSTR) s = prop.bstrVal; return s; } UInt64 CCodecs::GetHasherId(UInt32 index) { NCOM::CPropVariant prop; RINOK(GetHasherProp(index, NMethodPropID::kID, &prop)); if (prop.vt != VT_UI8) return 0; return prop.uhVal.QuadPart; } UString CCodecs::GetHasherName(UInt32 index) { UString s; NCOM::CPropVariant prop; if (GetHasherProp(index, NMethodPropID::kName, &prop) == S_OK) if (prop.vt == VT_BSTR) s = prop.bstrVal; return s; } UInt32 CCodecs::GetHasherDigestSize(UInt32 index) { NCOM::CPropVariant prop; RINOK(GetHasherProp(index, NMethodPropID::kDigestSize, &prop)); if (prop.vt != VT_UI4) return 0; return prop.ulVal; } #endif // EXTERNAL_CODECS