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