6
#include "7zProperties.h"
8
#include "../../../Common/IntToString.h"
9
#include "../../../Common/ComTry.h"
10
#include "../../../Windows/Defs.h"
12
#include "../Common/ItemNameUtils.h"
14
#include "../Common/MultiStream.h"
17
#ifdef __7Z_SET_PROPERTIES
19
#include "../Common/ParseProperties.h"
24
#include "../../../Windows/System.h"
27
using namespace NWindows;
29
extern UString ConvertMethodIdToString(UInt64 id);
40
_numThreads = NWindows::NSystem::GetNumberOfProcessors();
47
STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
53
*numItems = _database.Files.Size();
60
IMP_IInArchive_ArcProps_NO
62
STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 * /* numProperties */)
67
STDMETHODIMP CHandler::GetPropertyInfo(UInt32 /* index */,
68
BSTR * /* name */, PROPID * /* propID */, VARTYPE * /* varType */)
76
STATPROPSTG kArcProps[] =
78
{ NULL, kpidMethod, VT_BSTR},
79
{ NULL, kpidSolid, VT_BOOL},
80
{ NULL, kpidNumBlocks, VT_UI4}
83
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
86
NWindows::NCOM::CPropVariant prop;
92
CRecordVector<UInt64> ids;
94
for (i = 0; i < _database.Folders.Size(); i++)
96
const CFolder &f = _database.Folders[i];
97
for (int j = f.Coders.Size() - 1; j >= 0; j--)
98
ids.AddToUniqueSorted(f.Coders[j].MethodID);
101
for (i = 0; i < ids.Size(); i++)
105
/* bool methodIsKnown = */ FindMethod(EXTERNAL_CODECS_VARS id, methodName);
106
if (methodName.IsEmpty())
107
methodName = ConvertMethodIdToString(id);
108
if (!resString.IsEmpty())
110
resString += methodName;
115
case kpidSolid: prop = _database.IsSolid(); break;
116
case kpidNumBlocks: prop = (UInt32)_database.Folders.Size(); break;
123
IMP_IInArchive_ArcProps
127
static void MySetFileTime(bool timeDefined, FILETIME unixTime, NWindows::NCOM::CPropVariant &prop)
135
static UString ConvertUInt32ToString(UInt32 value)
138
ConvertUInt64ToString(value, buffer);
142
static UString GetStringForSizeValue(UInt32 value)
144
for (int i = 31; i >= 0; i--)
145
if ((UInt32(1) << i) == value)
146
return ConvertUInt32ToString(i);
148
if (value % (1 << 20) == 0)
150
result += ConvertUInt32ToString(value >> 20);
153
else if (value % (1 << 10) == 0)
155
result += ConvertUInt32ToString(value >> 10);
160
result += ConvertUInt32ToString(value);
166
static const UInt64 k_Copy = 0x0;
167
static const UInt64 k_LZMA = 0x030101;
168
static const UInt64 k_PPMD = 0x030401;
170
static wchar_t GetHex(Byte value)
172
return (wchar_t)((value < 10) ? (L'0' + value) : (L'A' + (value - 10)));
174
static inline UString GetHex2(Byte value)
177
result += GetHex((Byte)(value >> 4));
178
result += GetHex((Byte)(value & 0xF));
184
static const UInt64 k_AES = 0x06F10701;
187
static inline UInt32 GetUInt32FromMemLE(const Byte *p)
189
return p[0] | (((UInt32)p[1]) << 8) | (((UInt32)p[2]) << 16) | (((UInt32)p[3]) << 24);
193
bool CHandler::IsEncrypted(UInt32 index2) const
195
CNum folderIndex = _database.FileIndexToFolderIndexMap[index2];
196
if (folderIndex != kNumNoIndex)
198
const CFolder &folderInfo = _database.Folders[folderIndex];
199
for (int i = folderInfo.Coders.Size() - 1; i >= 0; i--)
200
if (folderInfo.Coders[i].MethodID == k_AES)
206
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
209
NWindows::NCOM::CPropVariant prop;
212
const CRef2 &ref2 = _refs[index];
213
if (ref2.Refs.IsEmpty())
215
const CRef &ref = ref2.Refs.Front();
219
const CRef &ref = _refs[index];
220
const CVolume &volume = _volumes[ref.VolumeIndex];
221
const CArchiveDatabaseEx &_database = volume.Database;
222
UInt32 index2 = ref.ItemIndex;
223
const CFileItem &item = _database.Files[index2];
225
const CFileItem &item = _database.Files[index];
226
UInt32 index2 = index;
233
if (!item.Name.IsEmpty())
234
prop = NItemName::GetOSName(item.Name);
238
prop = item.IsDirectory;
242
prop = item.UnPackSize;
243
// prop = ref2.UnPackSize;
249
if (ref2.Refs.Size() > 1)
250
prop = ref2.StartPos;
253
if (item.IsStartPosDefined)
254
prop = item.StartPos;
259
// prop = ref2.PackSize;
261
CNum folderIndex = _database.FileIndexToFolderIndexMap[index2];
262
if (folderIndex != kNumNoIndex)
264
if (_database.FolderStartFileIndex[folderIndex] == (CNum)index2)
265
prop = _database.GetFolderFullPackSize(folderIndex);
276
case kpidLastAccessTime:
277
MySetFileTime(item.IsLastAccessTimeDefined, item.LastAccessTime, prop);
279
case kpidCreationTime:
280
MySetFileTime(item.IsCreationTimeDefined, item.CreationTime, prop);
282
case kpidLastWriteTime:
283
MySetFileTime(item.IsLastWriteTimeDefined, item.LastWriteTime, prop);
286
if (item.AreAttributesDefined)
287
prop = item.Attributes;
290
if (item.IsFileCRCDefined)
295
prop = IsEncrypted(index2);
301
CNum folderIndex = _database.FileIndexToFolderIndexMap[index2];
302
if (folderIndex != kNumNoIndex)
304
const CFolder &folderInfo = _database.Folders[folderIndex];
305
UString methodsString;
306
for (int i = folderInfo.Coders.Size() - 1; i >= 0; i--)
308
const CCoderInfo &coderInfo = folderInfo.Coders[i];
309
if (!methodsString.IsEmpty())
310
methodsString += L' ';
314
bool methodIsKnown = FindMethod(
316
coderInfo.MethodID, methodName);
320
methodsString += methodName;
321
if (coderInfo.MethodID == k_LZMA)
323
if (coderInfo.Properties.GetCapacity() >= 5)
325
methodsString += L":";
326
UInt32 dicSize = GetUInt32FromMemLE(
327
((const Byte *)coderInfo.Properties + 1));
328
methodsString += GetStringForSizeValue(dicSize);
331
else if (coderInfo.MethodID == k_PPMD)
333
if (coderInfo.Properties.GetCapacity() >= 5)
335
Byte order = *(const Byte *)coderInfo.Properties;
336
methodsString += L":o";
337
methodsString += ConvertUInt32ToString(order);
338
methodsString += L":mem";
339
UInt32 dicSize = GetUInt32FromMemLE(
340
((const Byte *)coderInfo.Properties + 1));
341
methodsString += GetStringForSizeValue(dicSize);
344
else if (coderInfo.MethodID == k_AES)
346
if (coderInfo.Properties.GetCapacity() >= 1)
348
methodsString += L":";
349
const Byte *data = (const Byte *)coderInfo.Properties;
350
Byte firstByte = *data++;
351
UInt32 numCyclesPower = firstByte & 0x3F;
352
methodsString += ConvertUInt32ToString(numCyclesPower);
354
if ((firstByte & 0xC0) != 0)
356
methodsString += L":";
358
UInt32 saltSize = (firstByte >> 7) & 1;
359
UInt32 ivSize = (firstByte >> 6) & 1;
360
if (coderInfo.Properties.GetCapacity() >= 2)
362
Byte secondByte = *data++;
363
saltSize += (secondByte >> 4);
364
ivSize += (secondByte & 0x0F);
372
if (coderInfo.Properties.GetCapacity() > 0)
374
methodsString += L":[";
375
for (size_t bi = 0; bi < coderInfo.Properties.GetCapacity(); bi++)
377
if (bi > 5 && bi + 1 < coderInfo.Properties.GetCapacity())
379
methodsString += L"..";
383
methodsString += GetHex2(coderInfo.Properties[bi]);
385
methodsString += L"]";
391
methodsString += ConvertMethodIdToString(coderInfo.MethodID);
395
prop = methodsString;
401
CNum folderIndex = _database.FileIndexToFolderIndexMap[index2];
402
if (folderIndex != kNumNoIndex)
403
prop = (UInt32)folderIndex;
406
case kpidPackedSize0:
407
case kpidPackedSize1:
408
case kpidPackedSize2:
409
case kpidPackedSize3:
410
case kpidPackedSize4:
412
CNum folderIndex = _database.FileIndexToFolderIndexMap[index2];
413
if (folderIndex != kNumNoIndex)
415
const CFolder &folderInfo = _database.Folders[folderIndex];
416
if (_database.FolderStartFileIndex[folderIndex] == (CNum)index2 &&
417
folderInfo.PackStreams.Size() > (int)(propID - kpidPackedSize0))
419
prop = _database.GetFolderPackStreamSize(folderIndex, propID - kpidPackedSize0);
440
static const wchar_t *kExt = L"7z";
441
static const wchar_t *kAfterPart = L".7z";
446
UString _unchangedPart;
447
UString _changedPart;
450
bool InitName(const UString &name)
453
int dotPos = name.ReverseFind('.');
454
UString basePart = name;
457
UString ext = name.Mid(dotPos + 1);
458
if (ext.CompareNoCase(kExt)==0 ||
459
ext.CompareNoCase(L"EXE") == 0)
461
_afterPart = kAfterPart;
462
basePart = name.Left(dotPos);
467
bool splitStyle = false;
468
if (basePart.Right(numLetters) == L"1")
470
while (numLetters < basePart.Length())
472
if (basePart[basePart.Length() - numLetters - 1] != '0')
479
_unchangedPart = basePart.Left(basePart.Length() - numLetters);
480
_changedPart = basePart.Right(numLetters);
484
UString GetNextName()
487
// if (_newStyle || !_first)
490
int numLetters = _changedPart.Length();
491
for (i = numLetters - 1; i >= 0; i--)
493
wchar_t c = _changedPart[i];
497
newName = c + newName;
499
newName = UString(L'1') + newName;
503
newName = UString(c) + newName;
506
newName = _changedPart[i] + newName;
509
_changedPart = newName;
512
return _unchangedPart + _changedPart + _afterPart;
518
STDMETHODIMP CHandler::Open(IInStream *stream,
519
const UInt64 *maxCheckStartPosition,
520
IArchiveOpenCallback *openArchiveCallback)
525
_fileInfoPopIDs.Clear();
529
CMyComPtr<IArchiveOpenCallback> openArchiveCallbackTemp = openArchiveCallback;
533
CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
537
CMyComPtr<ICryptoGetTextPassword> getTextPassword;
538
if (openArchiveCallback)
540
openArchiveCallbackTemp.QueryInterface(
541
IID_ICryptoGetTextPassword, &getTextPassword);
545
if (openArchiveCallback)
547
openArchiveCallbackTemp.QueryInterface(IID_IArchiveOpenVolumeCallback, &openVolumeCallback);
551
CMyComPtr<IInStream> inStream;
552
if (!_volumes.IsEmpty())
554
if (!openVolumeCallback)
556
if(_volumes.Size() == 1)
560
NCOM::CPropVariant prop;
561
RINOK(openVolumeCallback->GetProperty(kpidName, &prop));
562
if (prop.vt != VT_BSTR)
564
baseName = prop.bstrVal;
566
seqName.InitName(baseName);
569
UString fullName = seqName.GetNextName();
570
HRESULT result = openVolumeCallback->GetStream(fullName, &inStream);
571
if (result == S_FALSE)
582
RINOK(archive.Open(inStream, maxCheckStartPosition));
584
_volumes.Add(CVolume());
585
CVolume &volume = _volumes.Back();
586
CArchiveDatabaseEx &database = volume.Database;
587
volume.Stream = inStream;
588
volume.StartRef2Index = _refs.Size();
590
HRESULT result = archive.ReadDatabase(database
601
for(int i = 0; i < database.Files.Size(); i++)
604
refNew.VolumeIndex = _volumes.Size() - 1;
605
refNew.ItemIndex = i;
608
const CFileItem &file = database.Files[i];
612
for (j = _refs.Size() - 1; j >= 0; j--)
614
CRef2 &ref2 = _refs[j];
615
const CRef &ref = ref2.Refs.Back();
616
const CVolume &volume2 = _volumes[ref.VolumeIndex];
617
const CArchiveDatabaseEx &database2 = volume2.Database;
618
const CFileItem &file2 = database2.Files[ref.ItemIndex];
619
if (file2.Name.CompareNoCase(file.Name) == 0)
621
if (!file.IsStartPosDefined)
623
if (file.StartPos != ref2.StartPos + ref2.UnPackSize)
625
ref2.Refs.Add(refNew);
635
ref2New.Refs.Add(refNew);
636
j = _refs.Add(ref2New);
638
CRef2 &ref2 = _refs[j];
639
ref2.UnPackSize += file.UnPackSize;
640
ref2.PackSize += database.GetFilePackSize(i);
641
if (ref2.Refs.Size() == 1 && file.IsStartPosDefined)
642
ref2.StartPos = file.StartPos;
645
if (database.Files.Size() != 1)
647
const CFileItem &file = database.Files.Front();
648
if (!file.IsStartPosDefined)
653
RINOK(archive.Open(stream, maxCheckStartPosition));
654
HRESULT result = archive.ReadDatabase(
671
// _inStream = stream;
679
STDMETHODIMP CHandler::Close()
694
STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
699
CMultiStream *streamSpec = new CMultiStream;
700
CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
703
const UString *fileName;
704
for (int i = 0; i < _refs.Size(); i++)
706
const CRef &ref = _refs[i];
707
const CVolume &volume = _volumes[ref.VolumeIndex];
708
const CArchiveDatabaseEx &database = volume.Database;
709
const CFileItem &file = database.Files[ref.ItemIndex];
711
fileName = &file.Name;
713
if (fileName->Compare(file.Name) != 0)
715
if (!file.IsStartPosDefined)
717
if (file.StartPos != pos)
719
CNum folderIndex = database.FileIndexToFolderIndexMap[ref.ItemIndex];
720
if (folderIndex == kNumNoIndex)
722
if (file.UnPackSize != 0)
726
if (database.NumUnPackStreamsVector[folderIndex] != 1)
728
const CFolder &folder = database.Folders[folderIndex];
729
if (folder.Coders.Size() != 1)
731
const CCoderInfo &coder = folder.Coders.Front();
732
if (coder.NumInStreams != 1 || coder.NumOutStreams != 1)
734
if (coder.MethodID != k_Copy)
737
pos += file.UnPackSize;
738
CMultiStream::CSubStreamInfo subStreamInfo;
739
subStreamInfo.Stream = volume.Stream;
740
subStreamInfo.Pos = database.GetFolderStreamPos(folderIndex, 0);
741
subStreamInfo.Size = file.UnPackSize;
742
streamSpec->Streams.Add(subStreamInfo);
745
*stream = streamTemp.Detach();
751
#ifdef __7Z_SET_PROPERTIES
754
STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties)
758
const UInt32 numProcessors = NSystem::GetNumberOfProcessors();
759
_numThreads = numProcessors;
762
for (int i = 0; i < numProperties; i++)
764
UString name = names[i];
768
const PROPVARIANT &value = values[i];
770
int index = ParseStringToUInt32(name, number);
773
if(name.Left(2).CompareNoCase(L"MT") == 0)
776
RINOK(ParseMtProp(name.Mid(2), value, numProcessors, _numThreads));
791
IMPL_ISetCompressCodecsInfo