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