1// 7zHandler.cpp
2
3#include "StdAfx.h"
4
5#include "../../../../C/CpuArch.h"
6
7#include "../../../Common/ComTry.h"
8#include "../../../Common/IntToString.h"
9
10#ifndef Z7_7Z_SET_PROPERTIES
11#include "../../../Windows/System.h"
12#endif
13
14#include "../Common/ItemNameUtils.h"
15
16#include "7zHandler.h"
17#include "7zProperties.h"
18
19#ifdef Z7_7Z_SET_PROPERTIES
20#ifdef Z7_EXTRACT_ONLY
21#include "../Common/ParseProperties.h"
22#endif
23#endif
24
25using namespace NWindows;
26using namespace NCOM;
27
28namespace NArchive {
29namespace N7z {
30
31CHandler::CHandler()
32{
33  #ifndef Z7_NO_CRYPTO
34  _isEncrypted = false;
35  _passwordIsDefined = false;
36  #endif
37
38  #ifdef Z7_EXTRACT_ONLY
39
40  _crcSize = 4;
41
42  #ifdef Z7_7Z_SET_PROPERTIES
43  _useMultiThreadMixer = true;
44  #endif
45
46  #endif
47}
48
49Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
50{
51  *numItems = _db.Files.Size();
52  return S_OK;
53}
54
55#ifdef Z7_SFX
56
57IMP_IInArchive_ArcProps_NO_Table
58
59Z7_COM7F_IMF(CHandler::GetNumberOfProperties(UInt32 *numProps))
60{
61  *numProps = 0;
62  return S_OK;
63}
64
65Z7_COM7F_IMF(CHandler::GetPropertyInfo(UInt32 /* index */,
66      BSTR * /* name */, PROPID * /* propID */, VARTYPE * /* varType */))
67{
68  return E_NOTIMPL;
69}
70
71#else
72
73static const Byte kArcProps[] =
74{
75  kpidHeadersSize,
76  kpidMethod,
77  kpidSolid,
78  kpidNumBlocks
79  // , kpidIsTree
80};
81
82IMP_IInArchive_ArcProps
83
84static inline char GetHex(unsigned value)
85{
86  return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10)));
87}
88
89static unsigned ConvertMethodIdToString_Back(char *s, UInt64 id)
90{
91  int len = 0;
92  do
93  {
94    s[--len] = GetHex((unsigned)id & 0xF); id >>= 4;
95    s[--len] = GetHex((unsigned)id & 0xF); id >>= 4;
96  }
97  while (id != 0);
98  return (unsigned)-len;
99}
100
101static void ConvertMethodIdToString(AString &res, UInt64 id)
102{
103  const unsigned kLen = 32;
104  char s[kLen];
105  unsigned len = kLen - 1;
106  s[len] = 0;
107  res += s + len - ConvertMethodIdToString_Back(s + len, id);
108}
109
110
111static char *GetStringForSizeValue(char *s, UInt32 val)
112{
113  for (unsigned i = 0; i < 32; i++)
114    if (((UInt32)1 << i) == val)
115    {
116      if (i >= 10)
117      {
118        *s++= (char)('0' + i / 10);
119        i %= 10;
120      }
121      *s++ = (char)('0' + i);
122      *s = 0;
123      return s;
124    }
125
126  char c = 'b';
127  if      ((val & ((1 << 20) - 1)) == 0) { val >>= 20; c = 'm'; }
128  else if ((val & ((1 << 10) - 1)) == 0) { val >>= 10; c = 'k'; }
129  s = ConvertUInt32ToString(val, s);
130  *s++ = c;
131  *s = 0;
132  return s;
133}
134
135
136static void GetLzma2String(char *s, unsigned d)
137{
138  if (d > 40)
139  {
140    *s = 0;
141    return;
142    // s = MyStpCpy(s, "unsup");
143  }
144  else if ((d & 1) == 0)
145    d = (d >> 1) + 12;
146  else
147  {
148    // s = GetStringForSizeValue(s, (UInt32)3 << ((d >> 1) + 11));
149    d = (d >> 1) + 1;
150    char c = 'k';
151    if (d >= 10)
152    {
153      c = 'm';
154      d -= 10;
155    }
156    s = ConvertUInt32ToString((UInt32)3 << d, s);
157    *s++ = c;
158    *s = 0;
159    return;
160  }
161  ConvertUInt32ToString(d, s);
162}
163
164
165/*
166static inline void AddHexToString(UString &res, Byte value)
167{
168  res += GetHex((Byte)(value >> 4));
169  res += GetHex((Byte)(value & 0xF));
170}
171*/
172
173static char *AddProp32(char *s, const char *name, UInt32 v)
174{
175  *s++ = ':';
176  s = MyStpCpy(s, name);
177  return ConvertUInt32ToString(v, s);
178}
179
180void CHandler::AddMethodName(AString &s, UInt64 id)
181{
182  AString name;
183  FindMethod(EXTERNAL_CODECS_VARS id, name);
184  if (name.IsEmpty())
185    ConvertMethodIdToString(s, id);
186  else
187    s += name;
188}
189
190#endif
191
192Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
193{
194  #ifndef Z7_SFX
195  COM_TRY_BEGIN
196  #endif
197  NCOM::CPropVariant prop;
198  switch (propID)
199  {
200    #ifndef Z7_SFX
201    case kpidMethod:
202    {
203      AString s;
204      const CParsedMethods &pm = _db.ParsedMethods;
205      FOR_VECTOR (i, pm.IDs)
206      {
207        UInt64 id = pm.IDs[i];
208        s.Add_Space_if_NotEmpty();
209        char temp[16];
210        if (id == k_LZMA2)
211        {
212          s += "LZMA2:";
213          GetLzma2String(temp, pm.Lzma2Prop);
214          s += temp;
215        }
216        else if (id == k_LZMA)
217        {
218          s += "LZMA:";
219          GetStringForSizeValue(temp, pm.LzmaDic);
220          s += temp;
221        }
222        /*
223        else if (id == k_ZSTD)
224        {
225          s += "ZSTD";
226        }
227        */
228        else
229          AddMethodName(s, id);
230      }
231      prop = s;
232      break;
233    }
234    case kpidSolid: prop = _db.IsSolid(); break;
235    case kpidNumBlocks: prop = (UInt32)_db.NumFolders; break;
236    case kpidHeadersSize:  prop = _db.HeadersSize; break;
237    case kpidPhySize:  prop = _db.PhySize; break;
238    case kpidOffset: if (_db.ArcInfo.StartPosition != 0) prop = _db.ArcInfo.StartPosition; break;
239    /*
240    case kpidIsTree: if (_db.IsTree) prop = true; break;
241    case kpidIsAltStream: if (_db.ThereAreAltStreams) prop = true; break;
242    case kpidIsAux: if (_db.IsTree) prop = true; break;
243    */
244    // case kpidError: if (_db.ThereIsHeaderError) prop = "Header error"; break;
245    #endif
246
247    case kpidWarningFlags:
248    {
249      UInt32 v = 0;
250      if (_db.StartHeaderWasRecovered) v |= kpv_ErrorFlags_HeadersError;
251      if (_db.UnsupportedFeatureWarning) v |= kpv_ErrorFlags_UnsupportedFeature;
252      if (v != 0)
253        prop = v;
254      break;
255    }
256
257    case kpidErrorFlags:
258    {
259      UInt32 v = 0;
260      if (!_db.IsArc) v |= kpv_ErrorFlags_IsNotArc;
261      if (_db.ThereIsHeaderError) v |= kpv_ErrorFlags_HeadersError;
262      if (_db.UnexpectedEnd) v |= kpv_ErrorFlags_UnexpectedEnd;
263      // if (_db.UnsupportedVersion) v |= kpv_ErrorFlags_Unsupported;
264      if (_db.UnsupportedFeatureError) v |= kpv_ErrorFlags_UnsupportedFeature;
265      prop = v;
266      break;
267    }
268
269    case kpidReadOnly:
270    {
271      if (!_db.CanUpdate())
272        prop = true;
273      break;
274    }
275  }
276  return prop.Detach(value);
277  #ifndef Z7_SFX
278  COM_TRY_END
279  #endif
280}
281
282static void SetFileTimeProp_From_UInt64Def(PROPVARIANT *prop, const CUInt64DefVector &v, unsigned index)
283{
284  UInt64 value;
285  if (v.GetItem(index, value))
286    PropVarEm_Set_FileTime64_Prec(prop, value, k_PropVar_TimePrec_100ns);
287}
288
289bool CHandler::IsFolderEncrypted(CNum folderIndex) const
290{
291  if (folderIndex == kNumNoIndex)
292    return false;
293  const size_t startPos = _db.FoCodersDataOffset[folderIndex];
294  const Byte *p = _db.CodersData + startPos;
295  const size_t size = _db.FoCodersDataOffset[folderIndex + 1] - startPos;
296  CInByte2 inByte;
297  inByte.Init(p, size);
298
299  CNum numCoders = inByte.ReadNum();
300  for (; numCoders != 0; numCoders--)
301  {
302    const Byte mainByte = inByte.ReadByte();
303    const unsigned idSize = (mainByte & 0xF);
304    const Byte *longID = inByte.GetPtr();
305    UInt64 id64 = 0;
306    for (unsigned j = 0; j < idSize; j++)
307      id64 = ((id64 << 8) | longID[j]);
308    inByte.SkipDataNoCheck(idSize);
309    if (id64 == k_AES)
310      return true;
311    if ((mainByte & 0x20) != 0)
312      inByte.SkipDataNoCheck(inByte.ReadNum());
313  }
314  return false;
315}
316
317Z7_COM7F_IMF(CHandler::GetNumRawProps(UInt32 *numProps))
318{
319  *numProps = 0;
320  return S_OK;
321}
322
323Z7_COM7F_IMF(CHandler::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID))
324{
325  *name = NULL;
326  *propID = kpidNtSecure;
327  return S_OK;
328}
329
330Z7_COM7F_IMF(CHandler::GetParent(UInt32 /* index */, UInt32 *parent, UInt32 *parentType))
331{
332  /*
333  const CFileItem &file = _db.Files[index];
334  *parentType = (file.IsAltStream ? NParentType::kAltStream : NParentType::kDir);
335  *parent = (UInt32)(Int32)file.Parent;
336  */
337  *parentType = NParentType::kDir;
338  *parent = (UInt32)(Int32)-1;
339  return S_OK;
340}
341
342Z7_COM7F_IMF(CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType))
343{
344  *data = NULL;
345  *dataSize = 0;
346  *propType = 0;
347
348  if (/* _db.IsTree && propID == kpidName ||
349      !_db.IsTree && */ propID == kpidPath)
350  {
351    if (_db.NameOffsets && _db.NamesBuf)
352    {
353      size_t offset = _db.NameOffsets[index];
354      size_t size = (_db.NameOffsets[index + 1] - offset) * 2;
355      if (size < ((UInt32)1 << 31))
356      {
357        *data = (const void *)(_db.NamesBuf + offset * 2);
358        *dataSize = (UInt32)size;
359        *propType = NPropDataType::kUtf16z;
360      }
361    }
362    return S_OK;
363  }
364  /*
365  if (propID == kpidNtSecure)
366  {
367    if (index < (UInt32)_db.SecureIDs.Size())
368    {
369      int id = _db.SecureIDs[index];
370      size_t offs = _db.SecureOffsets[id];
371      size_t size = _db.SecureOffsets[id + 1] - offs;
372      if (size >= 0)
373      {
374        *data = _db.SecureBuf + offs;
375        *dataSize = (UInt32)size;
376        *propType = NPropDataType::kRaw;
377      }
378    }
379  }
380  */
381  return S_OK;
382}
383
384#ifndef Z7_SFX
385
386HRESULT CHandler::SetMethodToProp(CNum folderIndex, PROPVARIANT *prop) const
387{
388  PropVariant_Clear(prop);
389  if (folderIndex == kNumNoIndex)
390    return S_OK;
391  // for (int ttt = 0; ttt < 1; ttt++) {
392  const unsigned kTempSize = 256;
393  char temp[kTempSize];
394  unsigned pos = kTempSize;
395  temp[--pos] = 0;
396
397  const size_t startPos = _db.FoCodersDataOffset[folderIndex];
398  const Byte *p = _db.CodersData + startPos;
399  const size_t size = _db.FoCodersDataOffset[folderIndex + 1] - startPos;
400  CInByte2 inByte;
401  inByte.Init(p, size);
402
403  // numCoders == 0 ???
404  CNum numCoders = inByte.ReadNum();
405  bool needSpace = false;
406
407  for (; numCoders != 0; numCoders--, needSpace = true)
408  {
409    if (pos < 32) // max size of property
410      break;
411    const Byte mainByte = inByte.ReadByte();
412    UInt64 id64 = 0;
413    const unsigned idSize = (mainByte & 0xF);
414    const Byte *longID = inByte.GetPtr();
415    for (unsigned j = 0; j < idSize; j++)
416      id64 = ((id64 << 8) | longID[j]);
417    inByte.SkipDataNoCheck(idSize);
418
419    if ((mainByte & 0x10) != 0)
420    {
421      inByte.ReadNum(); // NumInStreams
422      inByte.ReadNum(); // NumOutStreams
423    }
424
425    CNum propsSize = 0;
426    const Byte *props = NULL;
427    if ((mainByte & 0x20) != 0)
428    {
429      propsSize = inByte.ReadNum();
430      props = inByte.GetPtr();
431      inByte.SkipDataNoCheck(propsSize);
432    }
433
434    const char *name = NULL;
435    char s[32];
436    s[0] = 0;
437
438    if (id64 <= (UInt32)0xFFFFFFFF)
439    {
440      const UInt32 id = (UInt32)id64;
441      if (id == k_LZMA)
442      {
443        name = "LZMA";
444        if (propsSize == 5)
445        {
446          const UInt32 dicSize = GetUi32((const Byte *)props + 1);
447          char *dest = GetStringForSizeValue(s, dicSize);
448          UInt32 d = props[0];
449          if (d != 0x5D)
450          {
451            const UInt32 lc = d % 9;
452            d /= 9;
453            const UInt32 pb = d / 5;
454            const UInt32 lp = d % 5;
455            if (lc != 3) dest = AddProp32(dest, "lc", lc);
456            if (lp != 0) dest = AddProp32(dest, "lp", lp);
457            if (pb != 2) dest = AddProp32(dest, "pb", pb);
458          }
459        }
460      }
461      else if (id == k_LZMA2)
462      {
463        name = "LZMA2";
464        if (propsSize == 1)
465          GetLzma2String(s, props[0]);
466      }
467      else if (id == k_PPMD)
468      {
469        name = "PPMD";
470        if (propsSize == 5)
471        {
472          char *dest = s;
473          *dest++ = 'o';
474          dest = ConvertUInt32ToString(*props, dest);
475          dest = MyStpCpy(dest, ":mem");
476          GetStringForSizeValue(dest, GetUi32(props + 1));
477        }
478      }
479      else if (id == k_Delta)
480      {
481        name = "Delta";
482        if (propsSize == 1)
483          ConvertUInt32ToString((UInt32)props[0] + 1, s);
484      }
485      else if (id == k_ARM64)
486      {
487        name = "ARM64";
488        if (propsSize == 4)
489          ConvertUInt32ToString(GetUi32(props), s);
490        /*
491        else if (propsSize != 0)
492          MyStringCopy(s, "unsupported");
493        */
494      }
495      else if (id == k_BCJ2) name = "BCJ2";
496      else if (id == k_BCJ) name = "BCJ";
497      else if (id == k_AES)
498      {
499        name = "7zAES";
500        if (propsSize >= 1)
501        {
502          const Byte firstByte = props[0];
503          const UInt32 numCyclesPower = firstByte & 0x3F;
504          ConvertUInt32ToString(numCyclesPower, s);
505        }
506      }
507    }
508
509    if (name)
510    {
511      const unsigned nameLen = MyStringLen(name);
512      const unsigned propsLen = MyStringLen(s);
513      unsigned totalLen = nameLen + propsLen;
514      if (propsLen != 0)
515        totalLen++;
516      if (needSpace)
517        totalLen++;
518      if (totalLen + 5 >= pos)
519        break;
520      pos -= totalLen;
521      MyStringCopy(temp + pos, name);
522      if (propsLen != 0)
523      {
524        char *dest = temp + pos + nameLen;
525        *dest++ = ':';
526        MyStringCopy(dest, s);
527      }
528      if (needSpace)
529        temp[pos + totalLen - 1] = ' ';
530    }
531    else
532    {
533      AString methodName;
534      FindMethod(EXTERNAL_CODECS_VARS id64, methodName);
535      if (needSpace)
536        temp[--pos] = ' ';
537      if (methodName.IsEmpty())
538        pos -= ConvertMethodIdToString_Back(temp + pos, id64);
539      else
540      {
541        const unsigned len = methodName.Len();
542        if (len + 5 > pos)
543          break;
544        pos -= len;
545        for (unsigned i = 0; i < len; i++)
546          temp[pos + i] = methodName[i];
547      }
548    }
549  }
550
551  if (numCoders != 0 && pos >= 4)
552  {
553    temp[--pos] = ' ';
554    temp[--pos] = '.';
555    temp[--pos] = '.';
556    temp[--pos] = '.';
557  }
558
559  return PropVarEm_Set_Str(prop, temp + pos);
560  // }
561}
562
563#endif
564
565Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
566{
567  RINOK(PropVariant_Clear(value))
568  // COM_TRY_BEGIN
569  // NCOM::CPropVariant prop;
570
571  /*
572  const CRef2 &ref2 = _refs[index];
573  if (ref2.Refs.IsEmpty())
574    return E_FAIL;
575  const CRef &ref = ref2.Refs.Front();
576  */
577
578  const CFileItem &item = _db.Files[index];
579  const UInt32 index2 = index;
580
581  switch (propID)
582  {
583    case kpidIsDir: PropVarEm_Set_Bool(value, item.IsDir); break;
584    case kpidSize:
585    {
586      PropVarEm_Set_UInt64(value, item.Size);
587      // prop = ref2.Size;
588      break;
589    }
590    case kpidPackSize:
591    {
592      // prop = ref2.PackSize;
593      {
594        const CNum folderIndex = _db.FileIndexToFolderIndexMap[index2];
595        if (folderIndex != kNumNoIndex)
596        {
597          if (_db.FolderStartFileIndex[folderIndex] == (CNum)index2)
598            PropVarEm_Set_UInt64(value, _db.GetFolderFullPackSize(folderIndex));
599          /*
600          else
601            PropVarEm_Set_UInt64(value, 0);
602          */
603        }
604        else
605          PropVarEm_Set_UInt64(value, 0);
606      }
607      break;
608    }
609    // case kpidIsAux: prop = _db.IsItemAux(index2); break;
610    case kpidPosition:  { UInt64 v; if (_db.StartPos.GetItem(index2, v)) PropVarEm_Set_UInt64(value, v); break; }
611    case kpidCTime:  SetFileTimeProp_From_UInt64Def(value, _db.CTime, index2); break;
612    case kpidATime:  SetFileTimeProp_From_UInt64Def(value, _db.ATime, index2); break;
613    case kpidMTime:  SetFileTimeProp_From_UInt64Def(value, _db.MTime, index2); break;
614    case kpidAttrib:  if (_db.Attrib.ValidAndDefined(index2)) PropVarEm_Set_UInt32(value, _db.Attrib.Vals[index2]); break;
615    case kpidCRC:  if (item.CrcDefined) PropVarEm_Set_UInt32(value, item.Crc); break;
616    case kpidEncrypted:  PropVarEm_Set_Bool(value, IsFolderEncrypted(_db.FileIndexToFolderIndexMap[index2])); break;
617    case kpidIsAnti:  PropVarEm_Set_Bool(value, _db.IsItemAnti(index2)); break;
618    /*
619    case kpidIsAltStream:  prop = item.IsAltStream; break;
620    case kpidNtSecure:
621      {
622        int id = _db.SecureIDs[index];
623        size_t offs = _db.SecureOffsets[id];
624        size_t size = _db.SecureOffsets[id + 1] - offs;
625        if (size >= 0)
626        {
627          prop.SetBlob(_db.SecureBuf + offs, (ULONG)size);
628        }
629        break;
630      }
631    */
632
633    case kpidPath: return _db.GetPath_Prop(index, value);
634
635    #ifndef Z7_SFX
636
637    case kpidMethod: return SetMethodToProp(_db.FileIndexToFolderIndexMap[index2], value);
638    case kpidBlock:
639      {
640        const CNum folderIndex = _db.FileIndexToFolderIndexMap[index2];
641        if (folderIndex != kNumNoIndex)
642          PropVarEm_Set_UInt32(value, (UInt32)folderIndex);
643      }
644      break;
645   #ifdef Z7_7Z_SHOW_PACK_STREAMS_SIZES
646    case kpidPackedSize0:
647    case kpidPackedSize1:
648    case kpidPackedSize2:
649    case kpidPackedSize3:
650    case kpidPackedSize4:
651      {
652        const CNum folderIndex = _db.FileIndexToFolderIndexMap[index2];
653        if (folderIndex != kNumNoIndex)
654        {
655          if (_db.FolderStartFileIndex[folderIndex] == (CNum)index2 &&
656              _db.FoStartPackStreamIndex[folderIndex + 1] -
657              _db.FoStartPackStreamIndex[folderIndex] > (propID - kpidPackedSize0))
658          {
659            PropVarEm_Set_UInt64(value, _db.GetFolderPackStreamSize(folderIndex, propID - kpidPackedSize0));
660          }
661        }
662        else
663          PropVarEm_Set_UInt64(value, 0);
664      }
665      break;
666   #endif
667
668    #endif
669  }
670  // return prop.Detach(value);
671  return S_OK;
672  // COM_TRY_END
673}
674
675Z7_COM7F_IMF(CHandler::Open(IInStream *stream,
676    const UInt64 *maxCheckStartPosition,
677    IArchiveOpenCallback *openArchiveCallback))
678{
679  COM_TRY_BEGIN
680  Close();
681  #ifndef Z7_SFX
682  _fileInfoPopIDs.Clear();
683  #endif
684
685  try
686  {
687    CMyComPtr<IArchiveOpenCallback> openArchiveCallbackTemp = openArchiveCallback;
688
689    #ifndef Z7_NO_CRYPTO
690    CMyComPtr<ICryptoGetTextPassword> getTextPassword;
691    if (openArchiveCallback)
692      openArchiveCallbackTemp.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword);
693    #endif
694
695    CInArchive archive(
696          #ifdef Z7_7Z_SET_PROPERTIES
697          _useMultiThreadMixer
698          #else
699          true
700          #endif
701          );
702    _db.IsArc = false;
703    RINOK(archive.Open(stream, maxCheckStartPosition))
704    _db.IsArc = true;
705
706    HRESULT result = archive.ReadDatabase(
707        EXTERNAL_CODECS_VARS
708        _db
709        #ifndef Z7_NO_CRYPTO
710          , getTextPassword, _isEncrypted, _passwordIsDefined, _password
711        #endif
712        );
713    RINOK(result)
714
715    _inStream = stream;
716  }
717  catch(...)
718  {
719    Close();
720    // return E_INVALIDARG;
721    // return S_FALSE;
722    // we must return out_of_memory here
723    return E_OUTOFMEMORY;
724  }
725  // _inStream = stream;
726  #ifndef Z7_SFX
727  FillPopIDs();
728  #endif
729  return S_OK;
730  COM_TRY_END
731}
732
733Z7_COM7F_IMF(CHandler::Close())
734{
735  COM_TRY_BEGIN
736  _inStream.Release();
737  _db.Clear();
738  #ifndef Z7_NO_CRYPTO
739  _isEncrypted = false;
740  _passwordIsDefined = false;
741  _password.Wipe_and_Empty();
742  #endif
743  return S_OK;
744  COM_TRY_END
745}
746
747#ifdef Z7_7Z_SET_PROPERTIES
748#ifdef Z7_EXTRACT_ONLY
749
750Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps))
751{
752  COM_TRY_BEGIN
753
754  InitCommon();
755  _useMultiThreadMixer = true;
756
757  for (UInt32 i = 0; i < numProps; i++)
758  {
759    UString name = names[i];
760    name.MakeLower_Ascii();
761    if (name.IsEmpty())
762      return E_INVALIDARG;
763    const PROPVARIANT &value = values[i];
764    UInt32 number;
765    const unsigned index = ParseStringToUInt32(name, number);
766    if (index == 0)
767    {
768      if (name.IsEqualTo("mtf"))
769      {
770        RINOK(PROPVARIANT_to_bool(value, _useMultiThreadMixer))
771        continue;
772      }
773      {
774        HRESULT hres;
775        if (SetCommonProperty(name, value, hres))
776        {
777          RINOK(hres)
778          continue;
779        }
780      }
781      return E_INVALIDARG;
782    }
783  }
784  return S_OK;
785  COM_TRY_END
786}
787
788#endif
789#endif
790
791IMPL_ISetCompressCodecsInfo
792
793}}
794