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