• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
27 extern UString ConvertMethodIdToString(UInt64 id);
28 
29 namespace NArchive {
30 namespace N7z {
31 
CHandler()32 CHandler::CHandler()
33 {
34   _crcSize = 4;
35 
36   #ifndef _NO_CRYPTO
37   _passwordIsDefined = false;
38   #endif
39 
40   #ifdef EXTRACT_ONLY
41   #ifdef __7Z_SET_PROPERTIES
42   _numThreads = NSystem::GetNumberOfProcessors();
43   #endif
44   #else
45   Init();
46   #endif
47 }
48 
GetNumberOfItems(UInt32 * numItems)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
58 
GetNumberOfProperties(UInt32 *)59 STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 * /* numProperties */)
60 {
61   return E_NOTIMPL;
62 }
63 
GetPropertyInfo(UInt32,BSTR *,PROPID *,VARTYPE *)64 STDMETHODIMP CHandler::GetPropertyInfo(UInt32 /* index */,
65       BSTR * /* name */, PROPID * /* propID */, VARTYPE * /* varType */)
66 {
67   return E_NOTIMPL;
68 }
69 
70 
71 #else
72 
73 STATPROPSTG kArcProps[] =
74 {
75   { NULL, kpidMethod, VT_BSTR},
76   { NULL, kpidSolid, VT_BOOL},
77   { NULL, kpidNumBlocks, VT_UI4},
78   { NULL, kpidPhySize, VT_UI8},
79   { NULL, kpidHeadersSize, VT_UI8},
80   { NULL, kpidOffset, VT_UI8}
81 };
82 
GetArchiveProperty(PROPID propID,PROPVARIANT * value)83 STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
84 {
85   COM_TRY_BEGIN
86   NCOM::CPropVariant prop;
87   switch(propID)
88   {
89     case kpidMethod:
90     {
91       UString resString;
92       CRecordVector<UInt64> ids;
93       int i;
94       for (i = 0; i < _db.Folders.Size(); i++)
95       {
96         const CFolder &f = _db.Folders[i];
97         for (int j = f.Coders.Size() - 1; j >= 0; j--)
98           ids.AddToUniqueSorted(f.Coders[j].MethodID);
99       }
100 
101       for (i = 0; i < ids.Size(); i++)
102       {
103         UInt64 id = ids[i];
104         UString methodName;
105         /* bool methodIsKnown = */ FindMethod(EXTERNAL_CODECS_VARS id, methodName);
106         if (methodName.IsEmpty())
107           methodName = ConvertMethodIdToString(id);
108         if (!resString.IsEmpty())
109           resString += L' ';
110         resString += methodName;
111       }
112       prop = resString;
113       break;
114     }
115     case kpidSolid: prop = _db.IsSolid(); break;
116     case kpidNumBlocks: prop = (UInt32)_db.Folders.Size(); break;
117     case kpidHeadersSize:  prop = _db.HeadersSize; break;
118     case kpidPhySize:  prop = _db.PhySize; break;
119     case kpidOffset: if (_db.ArchiveInfo.StartPosition != 0) prop = _db.ArchiveInfo.StartPosition; break;
120   }
121   prop.Detach(value);
122   return S_OK;
123   COM_TRY_END
124 }
125 
126 IMP_IInArchive_ArcProps
127 
128 #endif
129 
SetPropFromUInt64Def(CUInt64DefVector & v,int index,NCOM::CPropVariant & prop)130 static void SetPropFromUInt64Def(CUInt64DefVector &v, int index, NCOM::CPropVariant &prop)
131 {
132   UInt64 value;
133   if (v.GetItem(index, value))
134   {
135     FILETIME ft;
136     ft.dwLowDateTime = (DWORD)value;
137     ft.dwHighDateTime = (DWORD)(value >> 32);
138     prop = ft;
139   }
140 }
141 
142 #ifndef _SFX
143 
ConvertUInt32ToString(UInt32 value)144 static UString ConvertUInt32ToString(UInt32 value)
145 {
146   wchar_t buffer[32];
147   ConvertUInt64ToString(value, buffer);
148   return buffer;
149 }
150 
GetStringForSizeValue(UInt32 value)151 static UString GetStringForSizeValue(UInt32 value)
152 {
153   for (int i = 31; i >= 0; i--)
154     if ((UInt32(1) << i) == value)
155       return ConvertUInt32ToString(i);
156   UString result;
157   if (value % (1 << 20) == 0)
158   {
159     result += ConvertUInt32ToString(value >> 20);
160     result += L"m";
161   }
162   else if (value % (1 << 10) == 0)
163   {
164     result += ConvertUInt32ToString(value >> 10);
165     result += L"k";
166   }
167   else
168   {
169     result += ConvertUInt32ToString(value);
170     result += L"b";
171   }
172   return result;
173 }
174 
175 static const UInt64 k_Copy = 0x0;
176 static const UInt64 k_Delta = 3;
177 static const UInt64 k_LZMA2 = 0x21;
178 static const UInt64 k_LZMA  = 0x030101;
179 static const UInt64 k_PPMD  = 0x030401;
180 
GetHex(Byte value)181 static wchar_t GetHex(Byte value)
182 {
183   return (wchar_t)((value < 10) ? (L'0' + value) : (L'A' + (value - 10)));
184 }
AddHexToString(UString & res,Byte value)185 static inline void AddHexToString(UString &res, Byte value)
186 {
187   res += GetHex((Byte)(value >> 4));
188   res += GetHex((Byte)(value & 0xF));
189 }
190 
191 #endif
192 
IsEncrypted(UInt32 index2) const193 bool CHandler::IsEncrypted(UInt32 index2) const
194 {
195   CNum folderIndex = _db.FileIndexToFolderIndexMap[index2];
196   if (folderIndex != kNumNoIndex)
197     return _db.Folders[folderIndex].IsEncrypted();
198   return false;
199 }
200 
GetProperty(UInt32 index,PROPID propID,PROPVARIANT * value)201 STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID,  PROPVARIANT *value)
202 {
203   COM_TRY_BEGIN
204   NCOM::CPropVariant prop;
205 
206   /*
207   const CRef2 &ref2 = _refs[index];
208   if (ref2.Refs.IsEmpty())
209     return E_FAIL;
210   const CRef &ref = ref2.Refs.Front();
211   */
212 
213   const CFileItem &item = _db.Files[index];
214   UInt32 index2 = index;
215 
216   switch(propID)
217   {
218     case kpidPath:
219       if (!item.Name.IsEmpty())
220         prop = NItemName::GetOSName(item.Name);
221       break;
222     case kpidIsDir:  prop = item.IsDir; break;
223     case kpidSize:
224     {
225       prop = item.Size;
226       // prop = ref2.Size;
227       break;
228     }
229     case kpidPackSize:
230     {
231       // prop = ref2.PackSize;
232       {
233         CNum folderIndex = _db.FileIndexToFolderIndexMap[index2];
234         if (folderIndex != kNumNoIndex)
235         {
236           if (_db.FolderStartFileIndex[folderIndex] == (CNum)index2)
237             prop = _db.GetFolderFullPackSize(folderIndex);
238           /*
239           else
240             prop = (UInt64)0;
241           */
242         }
243         else
244           prop = (UInt64)0;
245       }
246       break;
247     }
248     case kpidPosition:  { UInt64 v; if (_db.StartPos.GetItem(index2, v)) prop = v; break; }
249     case kpidCTime:  SetPropFromUInt64Def(_db.CTime, index2, prop); break;
250     case kpidATime:  SetPropFromUInt64Def(_db.ATime, index2, prop); break;
251     case kpidMTime:  SetPropFromUInt64Def(_db.MTime, index2, prop); break;
252     case kpidAttrib:  if (item.AttribDefined) prop = item.Attrib; break;
253     case kpidCRC:  if (item.CrcDefined) prop = item.Crc; break;
254     case kpidEncrypted:  prop = IsEncrypted(index2); break;
255     case kpidIsAnti:  prop = _db.IsItemAnti(index2); break;
256     #ifndef _SFX
257     case kpidMethod:
258       {
259         CNum folderIndex = _db.FileIndexToFolderIndexMap[index2];
260         if (folderIndex != kNumNoIndex)
261         {
262           const CFolder &folderInfo = _db.Folders[folderIndex];
263           UString methodsString;
264           for (int i = folderInfo.Coders.Size() - 1; i >= 0; i--)
265           {
266             const CCoderInfo &coder = folderInfo.Coders[i];
267             if (!methodsString.IsEmpty())
268               methodsString += L' ';
269 
270             UString methodName, propsString;
271             bool methodIsKnown = FindMethod(
272               EXTERNAL_CODECS_VARS
273               coder.MethodID, methodName);
274 
275             if (!methodIsKnown)
276               methodsString += ConvertMethodIdToString(coder.MethodID);
277             else
278             {
279               methodsString += methodName;
280               if (coder.MethodID == k_Delta && coder.Props.GetCapacity() == 1)
281                 propsString = ConvertUInt32ToString((UInt32)coder.Props[0] + 1);
282               else if (coder.MethodID == k_LZMA && coder.Props.GetCapacity() == 5)
283               {
284                 UInt32 dicSize = GetUi32((const Byte *)coder.Props + 1);
285                 propsString = GetStringForSizeValue(dicSize);
286               }
287               else if (coder.MethodID == k_LZMA2 && coder.Props.GetCapacity() == 1)
288               {
289                 Byte p = coder.Props[0];
290                 UInt32 dicSize = (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11));
291                 propsString = GetStringForSizeValue(dicSize);
292               }
293               else if (coder.MethodID == k_PPMD && coder.Props.GetCapacity() == 5)
294               {
295                 Byte order = *(const Byte *)coder.Props;
296                 propsString = L'o';
297                 propsString += ConvertUInt32ToString(order);
298                 propsString += L":mem";
299                 UInt32 dicSize = GetUi32((const Byte *)coder.Props + 1);
300                 propsString += GetStringForSizeValue(dicSize);
301               }
302               else if (coder.MethodID == k_AES && coder.Props.GetCapacity() >= 1)
303               {
304                 const Byte *data = (const Byte *)coder.Props;
305                 Byte firstByte = *data++;
306                 UInt32 numCyclesPower = firstByte & 0x3F;
307                 propsString = ConvertUInt32ToString(numCyclesPower);
308                 /*
309                 if ((firstByte & 0xC0) != 0)
310                 {
311                   UInt32 saltSize = (firstByte >> 7) & 1;
312                   UInt32 ivSize = (firstByte >> 6) & 1;
313                   if (coder.Props.GetCapacity() >= 2)
314                   {
315                     Byte secondByte = *data++;
316                     saltSize += (secondByte >> 4);
317                     ivSize += (secondByte & 0x0F);
318                   }
319                 }
320                 */
321               }
322             }
323             if (!propsString.IsEmpty())
324             {
325               methodsString += L':';
326               methodsString += propsString;
327             }
328             else if (coder.Props.GetCapacity() > 0)
329             {
330               methodsString += L":[";
331               for (size_t bi = 0; bi < coder.Props.GetCapacity(); bi++)
332               {
333                 if (bi > 5 && bi + 1 < coder.Props.GetCapacity())
334                 {
335                   methodsString += L"..";
336                   break;
337                 }
338                 else
339                   AddHexToString(methodsString, coder.Props[bi]);
340               }
341               methodsString += L']';
342             }
343           }
344           prop = methodsString;
345         }
346       }
347       break;
348     case kpidBlock:
349       {
350         CNum folderIndex = _db.FileIndexToFolderIndexMap[index2];
351         if (folderIndex != kNumNoIndex)
352           prop = (UInt32)folderIndex;
353       }
354       break;
355     case kpidPackedSize0:
356     case kpidPackedSize1:
357     case kpidPackedSize2:
358     case kpidPackedSize3:
359     case kpidPackedSize4:
360       {
361         CNum folderIndex = _db.FileIndexToFolderIndexMap[index2];
362         if (folderIndex != kNumNoIndex)
363         {
364           const CFolder &folderInfo = _db.Folders[folderIndex];
365           if (_db.FolderStartFileIndex[folderIndex] == (CNum)index2 &&
366               folderInfo.PackStreams.Size() > (int)(propID - kpidPackedSize0))
367           {
368             prop = _db.GetFolderPackStreamSize(folderIndex, propID - kpidPackedSize0);
369           }
370           else
371             prop = (UInt64)0;
372         }
373         else
374           prop = (UInt64)0;
375       }
376       break;
377     #endif
378   }
379   prop.Detach(value);
380   return S_OK;
381   COM_TRY_END
382 }
383 
Open(IInStream * stream,const UInt64 * maxCheckStartPosition,IArchiveOpenCallback * openArchiveCallback)384 STDMETHODIMP CHandler::Open(IInStream *stream,
385     const UInt64 *maxCheckStartPosition,
386     IArchiveOpenCallback *openArchiveCallback)
387 {
388   COM_TRY_BEGIN
389   Close();
390   #ifndef _SFX
391   _fileInfoPopIDs.Clear();
392   #endif
393   try
394   {
395     CMyComPtr<IArchiveOpenCallback> openArchiveCallbackTemp = openArchiveCallback;
396 
397     #ifndef _NO_CRYPTO
398     CMyComPtr<ICryptoGetTextPassword> getTextPassword;
399     if (openArchiveCallback)
400     {
401       openArchiveCallbackTemp.QueryInterface(
402           IID_ICryptoGetTextPassword, &getTextPassword);
403     }
404     #endif
405     CInArchive archive;
406     RINOK(archive.Open(stream, maxCheckStartPosition));
407     #ifndef _NO_CRYPTO
408     _passwordIsDefined = false;
409     UString password;
410     #endif
411     HRESULT result = archive.ReadDatabase(
412       EXTERNAL_CODECS_VARS
413       _db
414       #ifndef _NO_CRYPTO
415       , getTextPassword, _passwordIsDefined
416       #endif
417       );
418     RINOK(result);
419     _db.Fill();
420     _inStream = stream;
421   }
422   catch(...)
423   {
424     Close();
425     return S_FALSE;
426   }
427   // _inStream = stream;
428   #ifndef _SFX
429   FillPopIDs();
430   #endif
431   return S_OK;
432   COM_TRY_END
433 }
434 
Close()435 STDMETHODIMP CHandler::Close()
436 {
437   COM_TRY_BEGIN
438   _inStream.Release();
439   _db.Clear();
440   return S_OK;
441   COM_TRY_END
442 }
443 
444 #ifdef __7Z_SET_PROPERTIES
445 #ifdef EXTRACT_ONLY
446 
SetProperties(const wchar_t ** names,const PROPVARIANT * values,Int32 numProperties)447 STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties)
448 {
449   COM_TRY_BEGIN
450   const UInt32 numProcessors = NSystem::GetNumberOfProcessors();
451   _numThreads = numProcessors;
452 
453   for (int i = 0; i < numProperties; i++)
454   {
455     UString name = names[i];
456     name.MakeUpper();
457     if (name.IsEmpty())
458       return E_INVALIDARG;
459     const PROPVARIANT &value = values[i];
460     UInt32 number;
461     int index = ParseStringToUInt32(name, number);
462     if (index == 0)
463     {
464       if(name.Left(2).CompareNoCase(L"MT") == 0)
465       {
466         RINOK(ParseMtProp(name.Mid(2), value, numProcessors, _numThreads));
467         continue;
468       }
469       else
470         return E_INVALIDARG;
471     }
472   }
473   return S_OK;
474   COM_TRY_END
475 }
476 
477 #endif
478 #endif
479 
480 IMPL_ISetCompressCodecsInfo
481 
482 }}
483