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 
CHandler()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 
GetNumberOfItems(UInt32 * numItems)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 
GetNumberOfProperties(UInt32 * numProps)60 STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProps)
61 {
62   *numProps = 0;
63   return S_OK;
64 }
65 
GetPropertyInfo(UInt32,BSTR *,PROPID *,VARTYPE *)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 
GetHex(unsigned value)85 static inline char GetHex(unsigned value)
86 {
87   return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10)));
88 }
89 
ConvertMethodIdToString_Back(char * s,UInt64 id)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 
ConvertMethodIdToString(AString & res,UInt64 id)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 
GetStringForSizeValue(char * s,UInt32 val)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 
AddProp32(char * s,const char * name,UInt32 v)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 
AddMethodName(AString & s,UInt64 id)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 
GetArchiveProperty(PROPID propID,PROPVARIANT * value)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 
SetFileTimeProp_From_UInt64Def(PROPVARIANT * prop,const CUInt64DefVector & v,int index)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 
IsFolderEncrypted(CNum folderIndex) const255 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 
GetNumRawProps(UInt32 * numProps)283 STDMETHODIMP CHandler::GetNumRawProps(UInt32 *numProps)
284 {
285   *numProps = 0;
286   return S_OK;
287 }
288 
GetRawPropInfo(UInt32,BSTR * name,PROPID * propID)289 STDMETHODIMP CHandler::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID)
290 {
291   *name = NULL;
292   *propID = kpidNtSecure;
293   return S_OK;
294 }
295 
GetParent(UInt32,UInt32 * parent,UInt32 * parentType)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 
GetRawProp(UInt32 index,PROPID propID,const void ** data,UInt32 * dataSize,UInt32 * propType)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 
SetMethodToProp(CNum folderIndex,PROPVARIANT * prop) const352 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 
GetProperty(UInt32 index,PROPID propID,PROPVARIANT * value)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   const 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 (_db.Attrib.ValidAndDefined(index2)) PropVarEm_Set_UInt32(value, _db.Attrib.Vals[index2]); 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 
Open(IInStream * stream,const UInt64 * maxCheckStartPosition,IArchiveOpenCallback * openArchiveCallback)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 
Close()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 
SetProperties(const wchar_t * const * names,const PROPVARIANT * values,UInt32 numProps)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