// 7zHandler.cpp | |
#include "StdAfx.h" | |
#include "../../../../C/CpuArch.h" | |
#include "../../../Common/ComTry.h" | |
#include "../../../Common/IntToString.h" | |
#ifndef __7Z_SET_PROPERTIES | |
#include "../../../Windows/System.h" | |
#endif | |
#include "../Common/ItemNameUtils.h" | |
#include "7zHandler.h" | |
#include "7zProperties.h" | |
#ifdef __7Z_SET_PROPERTIES | |
#ifdef EXTRACT_ONLY | |
#include "../Common/ParseProperties.h" | |
#endif | |
#endif | |
using namespace NWindows; | |
using namespace NCOM; | |
namespace NArchive { | |
namespace N7z { | |
CHandler::CHandler() | |
{ | |
#ifndef _NO_CRYPTO | |
_isEncrypted = false; | |
_passwordIsDefined = false; | |
#endif | |
#ifdef EXTRACT_ONLY | |
_crcSize = 4; | |
#ifdef __7Z_SET_PROPERTIES | |
_numThreads = NSystem::GetNumberOfProcessors(); | |
#endif | |
#endif | |
} | |
STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) | |
{ | |
*numItems = _db.Files.Size(); | |
return S_OK; | |
} | |
#ifdef _SFX | |
IMP_IInArchive_ArcProps_NO_Table | |
STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProps) | |
{ | |
*numProps = 0; | |
return S_OK; | |
} | |
STDMETHODIMP CHandler::GetPropertyInfo(UInt32 /* index */, | |
BSTR * /* name */, PROPID * /* propID */, VARTYPE * /* varType */) | |
{ | |
return E_NOTIMPL; | |
} | |
#else | |
static const Byte kArcProps[] = | |
{ | |
kpidHeadersSize, | |
kpidMethod, | |
kpidSolid, | |
kpidNumBlocks | |
// , kpidIsTree | |
}; | |
IMP_IInArchive_ArcProps | |
static inline char GetHex(unsigned value) | |
{ | |
return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10))); | |
} | |
static unsigned ConvertMethodIdToString_Back(char *s, UInt64 id) | |
{ | |
int len = 0; | |
do | |
{ | |
s[--len] = GetHex((unsigned)id & 0xF); id >>= 4; | |
s[--len] = GetHex((unsigned)id & 0xF); id >>= 4; | |
} | |
while (id != 0); | |
return (unsigned)-len; | |
} | |
static void ConvertMethodIdToString(AString &res, UInt64 id) | |
{ | |
const unsigned kLen = 32; | |
char s[kLen]; | |
unsigned len = kLen - 1; | |
s[len] = 0; | |
res += s + len - ConvertMethodIdToString_Back(s + len, id); | |
} | |
static unsigned GetStringForSizeValue(char *s, UInt32 val) | |
{ | |
unsigned i; | |
for (i = 0; i <= 31; i++) | |
if (((UInt32)1 << i) == val) | |
{ | |
if (i < 10) | |
{ | |
s[0] = (char)('0' + i); | |
s[1] = 0; | |
return 1; | |
} | |
if (i < 20) { s[0] = '1'; s[1] = (char)('0' + i - 10); } | |
else if (i < 30) { s[0] = '2'; s[1] = (char)('0' + i - 20); } | |
else { s[0] = '3'; s[1] = (char)('0' + i - 30); } | |
s[2] = 0; | |
return 2; | |
} | |
char c = 'b'; | |
if ((val & ((1 << 20) - 1)) == 0) { val >>= 20; c = 'm'; } | |
else if ((val & ((1 << 10) - 1)) == 0) { val >>= 10; c = 'k'; } | |
::ConvertUInt32ToString(val, s); | |
unsigned pos = MyStringLen(s); | |
s[pos++] = c; | |
s[pos] = 0; | |
return pos; | |
} | |
/* | |
static inline void AddHexToString(UString &res, Byte value) | |
{ | |
res += GetHex((Byte)(value >> 4)); | |
res += GetHex((Byte)(value & 0xF)); | |
} | |
*/ | |
static char *AddProp32(char *s, const char *name, UInt32 v) | |
{ | |
*s++ = ':'; | |
s = MyStpCpy(s, name); | |
::ConvertUInt32ToString(v, s); | |
return s + MyStringLen(s); | |
} | |
void CHandler::AddMethodName(AString &s, UInt64 id) | |
{ | |
UString methodName; | |
FindMethod(EXTERNAL_CODECS_VARS id, methodName); | |
if (methodName.IsEmpty()) | |
{ | |
for (unsigned i = 0; i < methodName.Len(); i++) | |
if (methodName[i] >= 0x80) | |
{ | |
methodName.Empty(); | |
break; | |
} | |
} | |
if (methodName.IsEmpty()) | |
ConvertMethodIdToString(s, id); | |
else | |
for (unsigned i = 0; i < methodName.Len(); i++) | |
s += (char)methodName[i]; | |
} | |
#endif | |
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) | |
{ | |
#ifndef _SFX | |
COM_TRY_BEGIN | |
#endif | |
NCOM::CPropVariant prop; | |
switch (propID) | |
{ | |
#ifndef _SFX | |
case kpidMethod: | |
{ | |
AString s; | |
const CParsedMethods &pm = _db.ParsedMethods; | |
FOR_VECTOR (i, pm.IDs) | |
{ | |
UInt64 id = pm.IDs[i]; | |
if (!s.IsEmpty()) | |
s += ' '; | |
char temp[16]; | |
if (id == k_LZMA2) | |
{ | |
s += "LZMA2:"; | |
if ((pm.Lzma2Prop & 1) == 0) | |
ConvertUInt32ToString((pm.Lzma2Prop >> 1) + 12, temp); | |
else | |
GetStringForSizeValue(temp, 3 << ((pm.Lzma2Prop >> 1) + 11)); | |
s += temp; | |
} | |
else if (id == k_LZMA) | |
{ | |
s += "LZMA:"; | |
GetStringForSizeValue(temp, pm.LzmaDic); | |
s += temp; | |
} | |
else | |
AddMethodName(s, id); | |
} | |
prop = s; | |
break; | |
} | |
case kpidSolid: prop = _db.IsSolid(); break; | |
case kpidNumBlocks: prop = (UInt32)_db.NumFolders; break; | |
case kpidHeadersSize: prop = _db.HeadersSize; break; | |
case kpidPhySize: prop = _db.PhySize; break; | |
case kpidOffset: if (_db.ArcInfo.StartPosition != 0) prop = _db.ArcInfo.StartPosition; break; | |
/* | |
case kpidIsTree: if (_db.IsTree) prop = true; break; | |
case kpidIsAltStream: if (_db.ThereAreAltStreams) prop = true; break; | |
case kpidIsAux: if (_db.IsTree) prop = true; break; | |
*/ | |
// case kpidError: if (_db.ThereIsHeaderError) prop = "Header error"; break; | |
#endif | |
case kpidWarningFlags: | |
{ | |
UInt32 v = 0; | |
if (_db.StartHeaderWasRecovered) v |= kpv_ErrorFlags_HeadersError; | |
if (_db.UnsupportedFeatureWarning) v |= kpv_ErrorFlags_UnsupportedFeature; | |
if (v != 0) | |
prop = v; | |
break; | |
} | |
case kpidErrorFlags: | |
{ | |
UInt32 v = 0; | |
if (!_db.IsArc) v |= kpv_ErrorFlags_IsNotArc; | |
if (_db.ThereIsHeaderError) v |= kpv_ErrorFlags_HeadersError; | |
if (_db.UnexpectedEnd) v |= kpv_ErrorFlags_UnexpectedEnd; | |
// if (_db.UnsupportedVersion) v |= kpv_ErrorFlags_Unsupported; | |
if (_db.UnsupportedFeatureError) v |= kpv_ErrorFlags_UnsupportedFeature; | |
prop = v; | |
break; | |
} | |
} | |
prop.Detach(value); | |
return S_OK; | |
#ifndef _SFX | |
COM_TRY_END | |
#endif | |
} | |
static void SetFileTimeProp_From_UInt64Def(PROPVARIANT *prop, const CUInt64DefVector &v, int index) | |
{ | |
UInt64 value; | |
if (v.GetItem(index, value)) | |
PropVarEm_Set_FileTime64(prop, value); | |
} | |
bool CHandler::IsFolderEncrypted(CNum folderIndex) const | |
{ | |
if (folderIndex == kNumNoIndex) | |
return false; | |
size_t startPos = _db.FoCodersDataOffset[folderIndex]; | |
const Byte *p = _db.CodersData + startPos; | |
size_t size = _db.FoCodersDataOffset[folderIndex + 1] - startPos; | |
CInByte2 inByte; | |
inByte.Init(p, size); | |
CNum numCoders = inByte.ReadNum(); | |
for (; numCoders != 0; numCoders--) | |
{ | |
Byte mainByte = inByte.ReadByte(); | |
unsigned idSize = (mainByte & 0xF); | |
const Byte *longID = inByte.GetPtr(); | |
UInt64 id64 = 0; | |
for (unsigned j = 0; j < idSize; j++) | |
id64 = ((id64 << 8) | longID[j]); | |
inByte.SkipDataNoCheck(idSize); | |
if (id64 == k_AES) | |
return true; | |
if ((mainByte & 0x20) != 0) | |
inByte.SkipDataNoCheck(inByte.ReadNum()); | |
} | |
return false; | |
} | |
STDMETHODIMP CHandler::GetNumRawProps(UInt32 *numProps) | |
{ | |
*numProps = 0; | |
return S_OK; | |
} | |
STDMETHODIMP CHandler::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID) | |
{ | |
*name = NULL; | |
*propID = kpidNtSecure; | |
return S_OK; | |
} | |
STDMETHODIMP CHandler::GetParent(UInt32 /* index */, UInt32 *parent, UInt32 *parentType) | |
{ | |
/* | |
const CFileItem &file = _db.Files[index]; | |
*parentType = (file.IsAltStream ? NParentType::kAltStream : NParentType::kDir); | |
*parent = (UInt32)(Int32)file.Parent; | |
*/ | |
*parentType = NParentType::kDir; | |
*parent = (UInt32)(Int32)-1; | |
return S_OK; | |
} | |
STDMETHODIMP CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType) | |
{ | |
*data = NULL; | |
*dataSize = 0; | |
*propType = 0; | |
if (/* _db.IsTree && propID == kpidName || | |
!_db.IsTree && */ propID == kpidPath) | |
{ | |
if (_db.NameOffsets && _db.NamesBuf) | |
{ | |
size_t offset = _db.NameOffsets[index]; | |
size_t size = (_db.NameOffsets[index + 1] - offset) * 2; | |
if (size < ((UInt32)1 << 31)) | |
{ | |
*data = (const void *)(_db.NamesBuf + offset * 2); | |
*dataSize = (UInt32)size; | |
*propType = NPropDataType::kUtf16z; | |
} | |
} | |
return S_OK; | |
} | |
/* | |
if (propID == kpidNtSecure) | |
{ | |
if (index < (UInt32)_db.SecureIDs.Size()) | |
{ | |
int id = _db.SecureIDs[index]; | |
size_t offs = _db.SecureOffsets[id]; | |
size_t size = _db.SecureOffsets[id + 1] - offs; | |
if (size >= 0) | |
{ | |
*data = _db.SecureBuf + offs; | |
*dataSize = (UInt32)size; | |
*propType = NPropDataType::kRaw; | |
} | |
} | |
} | |
*/ | |
return S_OK; | |
} | |
#ifndef _SFX | |
HRESULT CHandler::SetMethodToProp(CNum folderIndex, PROPVARIANT *prop) const | |
{ | |
PropVariant_Clear(prop); | |
if (folderIndex == kNumNoIndex) | |
return S_OK; | |
// for (int ttt = 0; ttt < 1; ttt++) { | |
const unsigned kTempSize = 256; | |
char temp[kTempSize]; | |
unsigned pos = kTempSize; | |
temp[--pos] = 0; | |
size_t startPos = _db.FoCodersDataOffset[folderIndex]; | |
const Byte *p = _db.CodersData + startPos; | |
size_t size = _db.FoCodersDataOffset[folderIndex + 1] - startPos; | |
CInByte2 inByte; | |
inByte.Init(p, size); | |
// numCoders == 0 ??? | |
CNum numCoders = inByte.ReadNum(); | |
bool needSpace = false; | |
for (; numCoders != 0; numCoders--, needSpace = true) | |
{ | |
if (pos < 32) // max size of property | |
break; | |
Byte mainByte = inByte.ReadByte(); | |
unsigned idSize = (mainByte & 0xF); | |
const Byte *longID = inByte.GetPtr(); | |
UInt64 id64 = 0; | |
for (unsigned j = 0; j < idSize; j++) | |
id64 = ((id64 << 8) | longID[j]); | |
inByte.SkipDataNoCheck(idSize); | |
if ((mainByte & 0x10) != 0) | |
{ | |
inByte.ReadNum(); // NumInStreams | |
inByte.ReadNum(); // NumOutStreams | |
} | |
CNum propsSize = 0; | |
const Byte *props = NULL; | |
if ((mainByte & 0x20) != 0) | |
{ | |
propsSize = inByte.ReadNum(); | |
props = inByte.GetPtr(); | |
inByte.SkipDataNoCheck(propsSize); | |
} | |
const char *name = NULL; | |
char s[32]; | |
s[0] = 0; | |
if (id64 <= (UInt32)0xFFFFFFFF) | |
{ | |
UInt32 id = (UInt32)id64; | |
if (id == k_LZMA) | |
{ | |
name = "LZMA"; | |
if (propsSize == 5) | |
{ | |
UInt32 dicSize = GetUi32((const Byte *)props + 1); | |
char *dest = s + GetStringForSizeValue(s, dicSize); | |
UInt32 d = props[0]; | |
if (d != 0x5D) | |
{ | |
UInt32 lc = d % 9; | |
d /= 9; | |
UInt32 pb = d / 5; | |
UInt32 lp = d % 5; | |
if (lc != 3) dest = AddProp32(dest, "lc", lc); | |
if (lp != 0) dest = AddProp32(dest, "lp", lp); | |
if (pb != 2) dest = AddProp32(dest, "pb", pb); | |
} | |
} | |
} | |
else if (id == k_LZMA2) | |
{ | |
name = "LZMA2"; | |
if (propsSize == 1) | |
{ | |
Byte p = props[0]; | |
if ((p & 1) == 0) | |
ConvertUInt32ToString((UInt32)((p >> 1) + 12), s); | |
else | |
GetStringForSizeValue(s, 3 << ((p >> 1) + 11)); | |
} | |
} | |
else if (id == k_PPMD) | |
{ | |
name = "PPMD"; | |
if (propsSize == 5) | |
{ | |
Byte order = *props; | |
char *dest = s; | |
*dest++ = 'o'; | |
ConvertUInt32ToString(order, dest); | |
dest += MyStringLen(dest); | |
dest = MyStpCpy(dest, ":mem"); | |
GetStringForSizeValue(dest, GetUi32(props + 1)); | |
} | |
} | |
else if (id == k_Delta) | |
{ | |
name = "Delta"; | |
if (propsSize == 1) | |
ConvertUInt32ToString((UInt32)props[0] + 1, s); | |
} | |
else if (id == k_BCJ2) name = "BCJ2"; | |
else if (id == k_BCJ) name = "BCJ"; | |
else if (id == k_AES) | |
{ | |
name = "7zAES"; | |
if (propsSize >= 1) | |
{ | |
Byte firstByte = props[0]; | |
UInt32 numCyclesPower = firstByte & 0x3F; | |
ConvertUInt32ToString(numCyclesPower, s); | |
} | |
} | |
} | |
if (name) | |
{ | |
unsigned nameLen = MyStringLen(name); | |
unsigned propsLen = MyStringLen(s); | |
unsigned totalLen = nameLen + propsLen; | |
if (propsLen != 0) | |
totalLen++; | |
if (needSpace) | |
totalLen++; | |
if (totalLen + 5 >= pos) | |
break; | |
pos -= totalLen; | |
MyStringCopy(temp + pos, name); | |
if (propsLen != 0) | |
{ | |
char *dest = temp + pos + nameLen; | |
*dest++ = ':'; | |
MyStringCopy(dest, s); | |
} | |
if (needSpace) | |
temp[pos + totalLen - 1] = ' '; | |
} | |
else | |
{ | |
UString methodName; | |
FindMethod(EXTERNAL_CODECS_VARS id64, methodName); | |
if (methodName.IsEmpty()) | |
{ | |
for (unsigned j = 0; j < methodName.Len(); j++) | |
if (methodName[j] >= 0x80) | |
{ | |
methodName.Empty(); | |
break; | |
} | |
} | |
if (needSpace) | |
temp[--pos] = ' '; | |
if (methodName.IsEmpty()) | |
pos -= ConvertMethodIdToString_Back(temp + pos, id64); | |
else | |
{ | |
unsigned len = methodName.Len(); | |
if (len + 5 > pos) | |
break; | |
pos -= len; | |
for (unsigned i = 0; i < len; i++) | |
temp[pos + i] = (char)methodName[i]; | |
} | |
} | |
} | |
if (numCoders != 0 && pos >= 4) | |
{ | |
temp[--pos] = ' '; | |
temp[--pos] = '.'; | |
temp[--pos] = '.'; | |
temp[--pos] = '.'; | |
} | |
return PropVarEm_Set_Str(prop, temp + pos); | |
// } | |
} | |
#endif | |
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) | |
{ | |
PropVariant_Clear(value); | |
// COM_TRY_BEGIN | |
// NCOM::CPropVariant prop; | |
/* | |
const CRef2 &ref2 = _refs[index]; | |
if (ref2.Refs.IsEmpty()) | |
return E_FAIL; | |
const CRef &ref = ref2.Refs.Front(); | |
*/ | |
const CFileItem &item = _db.Files[index]; | |
UInt32 index2 = index; | |
switch(propID) | |
{ | |
case kpidIsDir: PropVarEm_Set_Bool(value, item.IsDir); break; | |
case kpidSize: | |
{ | |
PropVarEm_Set_UInt64(value, item.Size); | |
// prop = ref2.Size; | |
break; | |
} | |
case kpidPackSize: | |
{ | |
// prop = ref2.PackSize; | |
{ | |
CNum folderIndex = _db.FileIndexToFolderIndexMap[index2]; | |
if (folderIndex != kNumNoIndex) | |
{ | |
if (_db.FolderStartFileIndex[folderIndex] == (CNum)index2) | |
PropVarEm_Set_UInt64(value, _db.GetFolderFullPackSize(folderIndex)); | |
/* | |
else | |
PropVarEm_Set_UInt64(value, 0); | |
*/ | |
} | |
else | |
PropVarEm_Set_UInt64(value, 0); | |
} | |
break; | |
} | |
// case kpidIsAux: prop = _db.IsItemAux(index2); break; | |
case kpidPosition: { UInt64 v; if (_db.StartPos.GetItem(index2, v)) PropVarEm_Set_UInt64(value, v); break; } | |
case kpidCTime: SetFileTimeProp_From_UInt64Def(value, _db.CTime, index2); break; | |
case kpidATime: SetFileTimeProp_From_UInt64Def(value, _db.ATime, index2); break; | |
case kpidMTime: SetFileTimeProp_From_UInt64Def(value, _db.MTime, index2); break; | |
case kpidAttrib: if (item.AttribDefined) PropVarEm_Set_UInt32(value, item.Attrib); break; | |
case kpidCRC: if (item.CrcDefined) PropVarEm_Set_UInt32(value, item.Crc); break; | |
case kpidEncrypted: PropVarEm_Set_Bool(value, IsFolderEncrypted(_db.FileIndexToFolderIndexMap[index2])); break; | |
case kpidIsAnti: PropVarEm_Set_Bool(value, _db.IsItemAnti(index2)); break; | |
/* | |
case kpidIsAltStream: prop = item.IsAltStream; break; | |
case kpidNtSecure: | |
{ | |
int id = _db.SecureIDs[index]; | |
size_t offs = _db.SecureOffsets[id]; | |
size_t size = _db.SecureOffsets[id + 1] - offs; | |
if (size >= 0) | |
{ | |
prop.SetBlob(_db.SecureBuf + offs, (ULONG)size); | |
} | |
break; | |
} | |
*/ | |
case kpidPath: return _db.GetPath_Prop(index, value); | |
#ifndef _SFX | |
case kpidMethod: return SetMethodToProp(_db.FileIndexToFolderIndexMap[index2], value); | |
case kpidBlock: | |
{ | |
CNum folderIndex = _db.FileIndexToFolderIndexMap[index2]; | |
if (folderIndex != kNumNoIndex) | |
PropVarEm_Set_UInt32(value, (UInt32)folderIndex); | |
} | |
break; | |
case kpidPackedSize0: | |
case kpidPackedSize1: | |
case kpidPackedSize2: | |
case kpidPackedSize3: | |
case kpidPackedSize4: | |
{ | |
/* | |
CNum folderIndex = _db.FileIndexToFolderIndexMap[index2]; | |
if (folderIndex != kNumNoIndex) | |
{ | |
const CFolder &folderInfo = _db.Folders[folderIndex]; | |
if (_db.FolderStartFileIndex[folderIndex] == (CNum)index2 && | |
folderInfo.PackStreams.Size() > (int)(propID - kpidPackedSize0)) | |
{ | |
prop = _db.GetFolderPackStreamSize(folderIndex, propID - kpidPackedSize0); | |
} | |
else | |
prop = (UInt64)0; | |
} | |
else | |
prop = (UInt64)0; | |
*/ | |
} | |
break; | |
#endif | |
} | |
// prop.Detach(value); | |
return S_OK; | |
// COM_TRY_END | |
} | |
STDMETHODIMP CHandler::Open(IInStream *stream, | |
const UInt64 *maxCheckStartPosition, | |
IArchiveOpenCallback *openArchiveCallback) | |
{ | |
COM_TRY_BEGIN | |
Close(); | |
#ifndef _SFX | |
_fileInfoPopIDs.Clear(); | |
#endif | |
try | |
{ | |
CMyComPtr<IArchiveOpenCallback> openArchiveCallbackTemp = openArchiveCallback; | |
#ifndef _NO_CRYPTO | |
CMyComPtr<ICryptoGetTextPassword> getTextPassword; | |
if (openArchiveCallback) | |
openArchiveCallbackTemp.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword); | |
#endif | |
CInArchive archive; | |
_db.IsArc = false; | |
RINOK(archive.Open(stream, maxCheckStartPosition)); | |
_db.IsArc = true; | |
HRESULT result = archive.ReadDatabase( | |
EXTERNAL_CODECS_VARS | |
_db | |
#ifndef _NO_CRYPTO | |
, getTextPassword, _isEncrypted, _passwordIsDefined | |
#endif | |
); | |
RINOK(result); | |
_inStream = stream; | |
} | |
catch(...) | |
{ | |
Close(); | |
// return E_INVALIDARG; | |
// we must return out_of_memory here | |
return S_FALSE; | |
} | |
// _inStream = stream; | |
#ifndef _SFX | |
FillPopIDs(); | |
#endif | |
return S_OK; | |
COM_TRY_END | |
} | |
STDMETHODIMP CHandler::Close() | |
{ | |
COM_TRY_BEGIN | |
_inStream.Release(); | |
_db.Clear(); | |
#ifndef _NO_CRYPTO | |
_isEncrypted = false; | |
_passwordIsDefined = false; | |
#endif | |
return S_OK; | |
COM_TRY_END | |
} | |
#ifdef __7Z_SET_PROPERTIES | |
#ifdef EXTRACT_ONLY | |
STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps) | |
{ | |
COM_TRY_BEGIN | |
const UInt32 numProcessors = NSystem::GetNumberOfProcessors(); | |
_numThreads = numProcessors; | |
for (UInt32 i = 0; i < numProps; i++) | |
{ | |
UString name = names[i]; | |
name.MakeLower_Ascii(); | |
if (name.IsEmpty()) | |
return E_INVALIDARG; | |
const PROPVARIANT &value = values[i]; | |
UInt32 number; | |
int index = ParseStringToUInt32(name, number); | |
if (index == 0) | |
{ | |
if (name.IsPrefixedBy(L"mt")) | |
{ | |
RINOK(ParseMtProp(name.Ptr(2), value, numProcessors, _numThreads)); | |
continue; | |
} | |
else | |
return E_INVALIDARG; | |
} | |
} | |
return S_OK; | |
COM_TRY_END | |
} | |
#endif | |
#endif | |
IMPL_ISetCompressCodecsInfo | |
}} |