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