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