| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793 |
- // 7zHandler.cpp
- #include "StdAfx.h"
- #include "7zHandler.h"
- #include "7zProperties.h"
- #include "../../../Common/IntToString.h"
- #include "../../../Common/ComTry.h"
- #include "../../../Windows/Defs.h"
- #include "../Common/ItemNameUtils.h"
- #ifdef _7Z_VOL
- #include "../Common/MultiStream.h"
- #endif
- #ifdef __7Z_SET_PROPERTIES
- #ifdef EXTRACT_ONLY
- #include "../Common/ParseProperties.h"
- #endif
- #endif
- #ifdef COMPRESS_MT
- #include "../../../Windows/System.h"
- #endif
- using namespace NWindows;
- extern UString ConvertMethodIdToString(UInt64 id);
- namespace NArchive {
- namespace N7z {
- CHandler::CHandler()
- {
- _crcSize = 4;
- #ifdef EXTRACT_ONLY
- #ifdef COMPRESS_MT
- _numThreads = NWindows::NSystem::GetNumberOfProcessors();
- #endif
- #else
- Init();
- #endif
- }
- STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
- {
- *numItems =
- #ifdef _7Z_VOL
- _refs.Size();
- #else
- *numItems = _database.Files.Size();
- #endif
- return S_OK;
- }
- #ifdef _SFX
- IMP_IInArchive_ArcProps_NO
- STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 * /* numProperties */)
- {
- return E_NOTIMPL;
- }
- STDMETHODIMP CHandler::GetPropertyInfo(UInt32 /* index */,
- BSTR * /* name */, PROPID * /* propID */, VARTYPE * /* varType */)
- {
- return E_NOTIMPL;
- }
- #else
- STATPROPSTG kArcProps[] =
- {
- { NULL, kpidMethod, VT_BSTR},
- { NULL, kpidSolid, VT_BOOL},
- { NULL, kpidNumBlocks, VT_UI4}
- };
- STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
- {
- COM_TRY_BEGIN
- NWindows::NCOM::CPropVariant prop;
- switch(propID)
- {
- case kpidMethod:
- {
- UString resString;
- CRecordVector<UInt64> ids;
- int i;
- for (i = 0; i < _database.Folders.Size(); i++)
- {
- const CFolder &f = _database.Folders[i];
- for (int j = f.Coders.Size() - 1; j >= 0; j--)
- ids.AddToUniqueSorted(f.Coders[j].MethodID);
- }
- for (i = 0; i < ids.Size(); i++)
- {
- UInt64 id = ids[i];
- UString methodName;
- /* bool methodIsKnown = */ FindMethod(EXTERNAL_CODECS_VARS id, methodName);
- if (methodName.IsEmpty())
- methodName = ConvertMethodIdToString(id);
- if (!resString.IsEmpty())
- resString += L' ';
- resString += methodName;
- }
- prop = resString;
- break;
- }
- case kpidSolid: prop = _database.IsSolid(); break;
- case kpidNumBlocks: prop = (UInt32)_database.Folders.Size(); break;
- }
- prop.Detach(value);
- return S_OK;
- COM_TRY_END
- }
- IMP_IInArchive_ArcProps
- #endif
- static void MySetFileTime(bool timeDefined, FILETIME unixTime, NWindows::NCOM::CPropVariant &prop)
- {
- if (timeDefined)
- prop = unixTime;
- }
- #ifndef _SFX
- static UString ConvertUInt32ToString(UInt32 value)
- {
- wchar_t buffer[32];
- ConvertUInt64ToString(value, buffer);
- return buffer;
- }
- static UString GetStringForSizeValue(UInt32 value)
- {
- for (int i = 31; i >= 0; i--)
- if ((UInt32(1) << i) == value)
- return ConvertUInt32ToString(i);
- UString result;
- if (value % (1 << 20) == 0)
- {
- result += ConvertUInt32ToString(value >> 20);
- result += L"m";
- }
- else if (value % (1 << 10) == 0)
- {
- result += ConvertUInt32ToString(value >> 10);
- result += L"k";
- }
- else
- {
- result += ConvertUInt32ToString(value);
- result += L"b";
- }
- return result;
- }
- static const UInt64 k_Copy = 0x0;
- static const UInt64 k_LZMA = 0x030101;
- static const UInt64 k_PPMD = 0x030401;
- static wchar_t GetHex(Byte value)
- {
- return (wchar_t)((value < 10) ? (L'0' + value) : (L'A' + (value - 10)));
- }
- static inline UString GetHex2(Byte value)
- {
- UString result;
- result += GetHex((Byte)(value >> 4));
- result += GetHex((Byte)(value & 0xF));
- return result;
- }
- #endif
- static const UInt64 k_AES = 0x06F10701;
- #ifndef _SFX
- static inline UInt32 GetUInt32FromMemLE(const Byte *p)
- {
- return p[0] | (((UInt32)p[1]) << 8) | (((UInt32)p[2]) << 16) | (((UInt32)p[3]) << 24);
- }
- #endif
- bool CHandler::IsEncrypted(UInt32 index2) const
- {
- CNum folderIndex = _database.FileIndexToFolderIndexMap[index2];
- if (folderIndex != kNumNoIndex)
- {
- const CFolder &folderInfo = _database.Folders[folderIndex];
- for (int i = folderInfo.Coders.Size() - 1; i >= 0; i--)
- if (folderInfo.Coders[i].MethodID == k_AES)
- return true;
- }
- return false;
- }
- STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
- {
- COM_TRY_BEGIN
- NWindows::NCOM::CPropVariant prop;
-
- /*
- const CRef2 &ref2 = _refs[index];
- if (ref2.Refs.IsEmpty())
- return E_FAIL;
- const CRef &ref = ref2.Refs.Front();
- */
-
- #ifdef _7Z_VOL
- const CRef &ref = _refs[index];
- const CVolume &volume = _volumes[ref.VolumeIndex];
- const CArchiveDatabaseEx &_database = volume.Database;
- UInt32 index2 = ref.ItemIndex;
- const CFileItem &item = _database.Files[index2];
- #else
- const CFileItem &item = _database.Files[index];
- UInt32 index2 = index;
- #endif
- switch(propID)
- {
- case kpidPath:
- {
- if (!item.Name.IsEmpty())
- prop = NItemName::GetOSName(item.Name);
- break;
- }
- case kpidIsFolder:
- prop = item.IsDirectory;
- break;
- case kpidSize:
- {
- prop = item.UnPackSize;
- // prop = ref2.UnPackSize;
- break;
- }
- case kpidPosition:
- {
- /*
- if (ref2.Refs.Size() > 1)
- prop = ref2.StartPos;
- else
- */
- if (item.IsStartPosDefined)
- prop = item.StartPos;
- break;
- }
- case kpidPackedSize:
- {
- // prop = ref2.PackSize;
- {
- CNum folderIndex = _database.FileIndexToFolderIndexMap[index2];
- if (folderIndex != kNumNoIndex)
- {
- if (_database.FolderStartFileIndex[folderIndex] == (CNum)index2)
- prop = _database.GetFolderFullPackSize(folderIndex);
- /*
- else
- prop = (UInt64)0;
- */
- }
- else
- prop = (UInt64)0;
- }
- break;
- }
- case kpidLastAccessTime:
- MySetFileTime(item.IsLastAccessTimeDefined, item.LastAccessTime, prop);
- break;
- case kpidCreationTime:
- MySetFileTime(item.IsCreationTimeDefined, item.CreationTime, prop);
- break;
- case kpidLastWriteTime:
- MySetFileTime(item.IsLastWriteTimeDefined, item.LastWriteTime, prop);
- break;
- case kpidAttributes:
- if (item.AreAttributesDefined)
- prop = item.Attributes;
- break;
- case kpidCRC:
- if (item.IsFileCRCDefined)
- prop = item.FileCRC;
- break;
- case kpidEncrypted:
- {
- prop = IsEncrypted(index2);
- break;
- }
- #ifndef _SFX
- case kpidMethod:
- {
- CNum folderIndex = _database.FileIndexToFolderIndexMap[index2];
- if (folderIndex != kNumNoIndex)
- {
- const CFolder &folderInfo = _database.Folders[folderIndex];
- UString methodsString;
- for (int i = folderInfo.Coders.Size() - 1; i >= 0; i--)
- {
- const CCoderInfo &coderInfo = folderInfo.Coders[i];
- if (!methodsString.IsEmpty())
- methodsString += L' ';
- {
- UString methodName;
- bool methodIsKnown = FindMethod(
- EXTERNAL_CODECS_VARS
- coderInfo.MethodID, methodName);
- if (methodIsKnown)
- {
- methodsString += methodName;
- if (coderInfo.MethodID == k_LZMA)
- {
- if (coderInfo.Properties.GetCapacity() >= 5)
- {
- methodsString += L":";
- UInt32 dicSize = GetUInt32FromMemLE(
- ((const Byte *)coderInfo.Properties + 1));
- methodsString += GetStringForSizeValue(dicSize);
- }
- }
- else if (coderInfo.MethodID == k_PPMD)
- {
- if (coderInfo.Properties.GetCapacity() >= 5)
- {
- Byte order = *(const Byte *)coderInfo.Properties;
- methodsString += L":o";
- methodsString += ConvertUInt32ToString(order);
- methodsString += L":mem";
- UInt32 dicSize = GetUInt32FromMemLE(
- ((const Byte *)coderInfo.Properties + 1));
- methodsString += GetStringForSizeValue(dicSize);
- }
- }
- else if (coderInfo.MethodID == k_AES)
- {
- if (coderInfo.Properties.GetCapacity() >= 1)
- {
- methodsString += L":";
- const Byte *data = (const Byte *)coderInfo.Properties;
- Byte firstByte = *data++;
- UInt32 numCyclesPower = firstByte & 0x3F;
- methodsString += ConvertUInt32ToString(numCyclesPower);
- /*
- if ((firstByte & 0xC0) != 0)
- {
- methodsString += L":";
- return S_OK;
- UInt32 saltSize = (firstByte >> 7) & 1;
- UInt32 ivSize = (firstByte >> 6) & 1;
- if (coderInfo.Properties.GetCapacity() >= 2)
- {
- Byte secondByte = *data++;
- saltSize += (secondByte >> 4);
- ivSize += (secondByte & 0x0F);
- }
- }
- */
- }
- }
- else
- {
- if (coderInfo.Properties.GetCapacity() > 0)
- {
- methodsString += L":[";
- for (size_t bi = 0; bi < coderInfo.Properties.GetCapacity(); bi++)
- {
- if (bi > 5 && bi + 1 < coderInfo.Properties.GetCapacity())
- {
- methodsString += L"..";
- break;
- }
- else
- methodsString += GetHex2(coderInfo.Properties[bi]);
- }
- methodsString += L"]";
- }
- }
- }
- else
- {
- methodsString += ConvertMethodIdToString(coderInfo.MethodID);
- }
- }
- }
- prop = methodsString;
- }
- }
- break;
- case kpidBlock:
- {
- CNum folderIndex = _database.FileIndexToFolderIndexMap[index2];
- if (folderIndex != kNumNoIndex)
- prop = (UInt32)folderIndex;
- }
- break;
- case kpidPackedSize0:
- case kpidPackedSize1:
- case kpidPackedSize2:
- case kpidPackedSize3:
- case kpidPackedSize4:
- {
- CNum folderIndex = _database.FileIndexToFolderIndexMap[index2];
- if (folderIndex != kNumNoIndex)
- {
- const CFolder &folderInfo = _database.Folders[folderIndex];
- if (_database.FolderStartFileIndex[folderIndex] == (CNum)index2 &&
- folderInfo.PackStreams.Size() > (int)(propID - kpidPackedSize0))
- {
- prop = _database.GetFolderPackStreamSize(folderIndex, propID - kpidPackedSize0);
- }
- else
- prop = (UInt64)0;
- }
- else
- prop = (UInt64)0;
- }
- break;
- #endif
- case kpidIsAnti:
- prop = item.IsAnti;
- break;
- }
- prop.Detach(value);
- return S_OK;
- COM_TRY_END
- }
- #ifdef _7Z_VOL
- static const wchar_t *kExt = L"7z";
- static const wchar_t *kAfterPart = L".7z";
- class CVolumeName
- {
- bool _first;
- UString _unchangedPart;
- UString _changedPart;
- UString _afterPart;
- public:
- bool InitName(const UString &name)
- {
- _first = true;
- int dotPos = name.ReverseFind('.');
- UString basePart = name;
- if (dotPos >= 0)
- {
- UString ext = name.Mid(dotPos + 1);
- if (ext.CompareNoCase(kExt)==0 ||
- ext.CompareNoCase(L"EXE") == 0)
- {
- _afterPart = kAfterPart;
- basePart = name.Left(dotPos);
- }
- }
- int numLetters = 1;
- bool splitStyle = false;
- if (basePart.Right(numLetters) == L"1")
- {
- while (numLetters < basePart.Length())
- {
- if (basePart[basePart.Length() - numLetters - 1] != '0')
- break;
- numLetters++;
- }
- }
- else
- return false;
- _unchangedPart = basePart.Left(basePart.Length() - numLetters);
- _changedPart = basePart.Right(numLetters);
- return true;
- }
- UString GetNextName()
- {
- UString newName;
- // if (_newStyle || !_first)
- {
- int i;
- int numLetters = _changedPart.Length();
- for (i = numLetters - 1; i >= 0; i--)
- {
- wchar_t c = _changedPart[i];
- if (c == L'9')
- {
- c = L'0';
- newName = c + newName;
- if (i == 0)
- newName = UString(L'1') + newName;
- continue;
- }
- c++;
- newName = UString(c) + newName;
- i--;
- for (; i >= 0; i--)
- newName = _changedPart[i] + newName;
- break;
- }
- _changedPart = newName;
- }
- _first = false;
- return _unchangedPart + _changedPart + _afterPart;
- }
- };
- #endif
- STDMETHODIMP CHandler::Open(IInStream *stream,
- const UInt64 *maxCheckStartPosition,
- IArchiveOpenCallback *openArchiveCallback)
- {
- COM_TRY_BEGIN
- Close();
- #ifndef _SFX
- _fileInfoPopIDs.Clear();
- #endif
- try
- {
- CMyComPtr<IArchiveOpenCallback> openArchiveCallbackTemp = openArchiveCallback;
- #ifdef _7Z_VOL
- CVolumeName seqName;
- CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
- #endif
- #ifndef _NO_CRYPTO
- CMyComPtr<ICryptoGetTextPassword> getTextPassword;
- if (openArchiveCallback)
- {
- openArchiveCallbackTemp.QueryInterface(
- IID_ICryptoGetTextPassword, &getTextPassword);
- }
- #endif
- #ifdef _7Z_VOL
- if (openArchiveCallback)
- {
- openArchiveCallbackTemp.QueryInterface(IID_IArchiveOpenVolumeCallback, &openVolumeCallback);
- }
- for (;;)
- {
- CMyComPtr<IInStream> inStream;
- if (!_volumes.IsEmpty())
- {
- if (!openVolumeCallback)
- break;
- if(_volumes.Size() == 1)
- {
- UString baseName;
- {
- NCOM::CPropVariant prop;
- RINOK(openVolumeCallback->GetProperty(kpidName, &prop));
- if (prop.vt != VT_BSTR)
- break;
- baseName = prop.bstrVal;
- }
- seqName.InitName(baseName);
- }
- UString fullName = seqName.GetNextName();
- HRESULT result = openVolumeCallback->GetStream(fullName, &inStream);
- if (result == S_FALSE)
- break;
- if (result != S_OK)
- return result;
- if (!stream)
- break;
- }
- else
- inStream = stream;
- CInArchive archive;
- RINOK(archive.Open(inStream, maxCheckStartPosition));
- _volumes.Add(CVolume());
- CVolume &volume = _volumes.Back();
- CArchiveDatabaseEx &database = volume.Database;
- volume.Stream = inStream;
- volume.StartRef2Index = _refs.Size();
- HRESULT result = archive.ReadDatabase(database
- #ifndef _NO_CRYPTO
- , getTextPassword
- #endif
- );
- if (result != S_OK)
- {
- _volumes.Clear();
- return result;
- }
- database.Fill();
- for(int i = 0; i < database.Files.Size(); i++)
- {
- CRef refNew;
- refNew.VolumeIndex = _volumes.Size() - 1;
- refNew.ItemIndex = i;
- _refs.Add(refNew);
- /*
- const CFileItem &file = database.Files[i];
- int j;
- */
- /*
- for (j = _refs.Size() - 1; j >= 0; j--)
- {
- CRef2 &ref2 = _refs[j];
- const CRef &ref = ref2.Refs.Back();
- const CVolume &volume2 = _volumes[ref.VolumeIndex];
- const CArchiveDatabaseEx &database2 = volume2.Database;
- const CFileItem &file2 = database2.Files[ref.ItemIndex];
- if (file2.Name.CompareNoCase(file.Name) == 0)
- {
- if (!file.IsStartPosDefined)
- continue;
- if (file.StartPos != ref2.StartPos + ref2.UnPackSize)
- continue;
- ref2.Refs.Add(refNew);
- break;
- }
- }
- */
- /*
- j = -1;
- if (j < 0)
- {
- CRef2 ref2New;
- ref2New.Refs.Add(refNew);
- j = _refs.Add(ref2New);
- }
- CRef2 &ref2 = _refs[j];
- ref2.UnPackSize += file.UnPackSize;
- ref2.PackSize += database.GetFilePackSize(i);
- if (ref2.Refs.Size() == 1 && file.IsStartPosDefined)
- ref2.StartPos = file.StartPos;
- */
- }
- if (database.Files.Size() != 1)
- break;
- const CFileItem &file = database.Files.Front();
- if (!file.IsStartPosDefined)
- break;
- }
- #else
- CInArchive archive;
- RINOK(archive.Open(stream, maxCheckStartPosition));
- HRESULT result = archive.ReadDatabase(
- EXTERNAL_CODECS_VARS
- _database
- #ifndef _NO_CRYPTO
- , getTextPassword
- #endif
- );
- RINOK(result);
- _database.Fill();
- _inStream = stream;
- #endif
- }
- catch(...)
- {
- Close();
- return S_FALSE;
- }
- // _inStream = stream;
- #ifndef _SFX
- FillPopIDs();
- #endif
- return S_OK;
- COM_TRY_END
- }
- STDMETHODIMP CHandler::Close()
- {
- COM_TRY_BEGIN
- #ifdef _7Z_VOL
- _volumes.Clear();
- _refs.Clear();
- #else
- _inStream.Release();
- _database.Clear();
- #endif
- return S_OK;
- COM_TRY_END
- }
- #ifdef _7Z_VOL
- STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
- {
- if (index != 0)
- return E_INVALIDARG;
- *stream = 0;
- CMultiStream *streamSpec = new CMultiStream;
- CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
-
- UInt64 pos = 0;
- const UString *fileName;
- for (int i = 0; i < _refs.Size(); i++)
- {
- const CRef &ref = _refs[i];
- const CVolume &volume = _volumes[ref.VolumeIndex];
- const CArchiveDatabaseEx &database = volume.Database;
- const CFileItem &file = database.Files[ref.ItemIndex];
- if (i == 0)
- fileName = &file.Name;
- else
- if (fileName->Compare(file.Name) != 0)
- return S_FALSE;
- if (!file.IsStartPosDefined)
- return S_FALSE;
- if (file.StartPos != pos)
- return S_FALSE;
- CNum folderIndex = database.FileIndexToFolderIndexMap[ref.ItemIndex];
- if (folderIndex == kNumNoIndex)
- {
- if (file.UnPackSize != 0)
- return E_FAIL;
- continue;
- }
- if (database.NumUnPackStreamsVector[folderIndex] != 1)
- return S_FALSE;
- const CFolder &folder = database.Folders[folderIndex];
- if (folder.Coders.Size() != 1)
- return S_FALSE;
- const CCoderInfo &coder = folder.Coders.Front();
- if (coder.NumInStreams != 1 || coder.NumOutStreams != 1)
- return S_FALSE;
- if (coder.MethodID != k_Copy)
- return S_FALSE;
- pos += file.UnPackSize;
- CMultiStream::CSubStreamInfo subStreamInfo;
- subStreamInfo.Stream = volume.Stream;
- subStreamInfo.Pos = database.GetFolderStreamPos(folderIndex, 0);
- subStreamInfo.Size = file.UnPackSize;
- streamSpec->Streams.Add(subStreamInfo);
- }
- streamSpec->Init();
- *stream = streamTemp.Detach();
- return S_OK;
- }
- #endif
- #ifdef __7Z_SET_PROPERTIES
- #ifdef EXTRACT_ONLY
- STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties)
- {
- COM_TRY_BEGIN
- #ifdef COMPRESS_MT
- const UInt32 numProcessors = NSystem::GetNumberOfProcessors();
- _numThreads = numProcessors;
- #endif
- for (int i = 0; i < numProperties; i++)
- {
- UString name = names[i];
- name.MakeUpper();
- if (name.IsEmpty())
- return E_INVALIDARG;
- const PROPVARIANT &value = values[i];
- UInt32 number;
- int index = ParseStringToUInt32(name, number);
- if (index == 0)
- {
- if(name.Left(2).CompareNoCase(L"MT") == 0)
- {
- #ifdef COMPRESS_MT
- RINOK(ParseMtProp(name.Mid(2), value, numProcessors, _numThreads));
- #endif
- continue;
- }
- else
- return E_INVALIDARG;
- }
- }
- return S_OK;
- COM_TRY_END
- }
- #endif
- #endif
- IMPL_ISetCompressCodecsInfo
- }}
|