diff options
author | Igor Pavlov <ipavlov@users.sourceforge.net> | 2010-06-04 04:00:00 +0400 |
---|---|---|
committer | Kornel LesiĆski <kornel@geekhood.net> | 2016-05-28 02:16:03 +0300 |
commit | 708873490ee36691d84cc06336aac87c5129f8a0 (patch) | |
tree | bbe6e5aa922a158e5810c1a2ff7c78927cc6d973 /CPP/7zip | |
parent | 3dacb5eb8afda99aad81f4723cb966c0fa91ba1d (diff) |
9.149.14
Diffstat (limited to 'CPP/7zip')
36 files changed, 1350 insertions, 411 deletions
diff --git a/CPP/7zip/Archive/7z/7zExtract.cpp b/CPP/7zip/Archive/7z/7zExtract.cpp index 6913d8fb..eb3ee502 100755 --- a/CPP/7zip/Archive/7z/7zExtract.cpp +++ b/CPP/7zip/Archive/7z/7zExtract.cpp @@ -138,7 +138,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, } } - extractCallback->SetTotal(importantTotalUnpacked); + RINOK(extractCallback->SetTotal(importantTotalUnpacked)); CDecoder decoder( #ifdef _ST_MODE diff --git a/CPP/7zip/Archive/7z/7zFolderInStream.cpp b/CPP/7zip/Archive/7z/7zFolderInStream.cpp index b029ae15..edd276bc 100755 --- a/CPP/7zip/Archive/7z/7zFolderInStream.cpp +++ b/CPP/7zip/Archive/7z/7zFolderInStream.cpp @@ -32,7 +32,6 @@ HRESULT CFolderInStream::OpenStream() _filePos = 0; while (_fileIndex < _numFiles) { - _currentSizeIsDefined = false; CMyComPtr<ISequentialInStream> stream; HRESULT result = _updateCallback->GetStream(_fileIndices[_fileIndex], &stream); if (result != S_OK && result != S_FALSE) @@ -40,26 +39,22 @@ HRESULT CFolderInStream::OpenStream() _fileIndex++; _inStreamWithHashSpec->SetStream(stream); _inStreamWithHashSpec->Init(); - if (!stream) + if (stream) { - RINOK(_updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); - Sizes.Add(0); - Processed.Add(result == S_OK); - AddDigest(); - continue; - } - CMyComPtr<IStreamGetSize> streamGetSize; - if (stream.QueryInterface(IID_IStreamGetSize, &streamGetSize) == S_OK) - { - if(streamGetSize) + _fileIsOpen = true; + CMyComPtr<IStreamGetSize> streamGetSize; + stream.QueryInterface(IID_IStreamGetSize, &streamGetSize); + if (streamGetSize) { - _currentSizeIsDefined = true; RINOK(streamGetSize->GetSize(&_currentSize)); + _currentSizeIsDefined = true; } + return S_OK; } - - _fileIsOpen = true; - return S_OK; + RINOK(_updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); + Sizes.Add(0); + Processed.Add(result == S_OK); + AddDigest(); } return S_OK; } @@ -74,6 +69,7 @@ HRESULT CFolderInStream::CloseStream() RINOK(_updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); _inStreamWithHashSpec->ReleaseStream(); _fileIsOpen = false; + _currentSizeIsDefined = false; Processed.Add(true); Sizes.Add(_filePos); AddDigest(); @@ -82,43 +78,40 @@ HRESULT CFolderInStream::CloseStream() STDMETHODIMP CFolderInStream::Read(void *data, UInt32 size, UInt32 *processedSize) { - UInt32 realProcessedSize = 0; - while ((_fileIndex < _numFiles || _fileIsOpen) && size > 0) + if (processedSize != 0) + *processedSize = 0; + while (size > 0) { if (_fileIsOpen) { - UInt32 localProcessedSize; - RINOK(_inStreamWithHash->Read( - ((Byte *)data) + realProcessedSize, size, &localProcessedSize)); - if (localProcessedSize == 0) + UInt32 processed2; + RINOK(_inStreamWithHash->Read(data, size, &processed2)); + if (processed2 == 0) { RINOK(CloseStream()); continue; } - realProcessedSize += localProcessedSize; - _filePos += localProcessedSize; - size -= localProcessedSize; + if (processedSize != 0) + *processedSize = processed2; + _filePos += processed2; break; } - else - { - RINOK(OpenStream()); - } + if (_fileIndex >= _numFiles) + break; + RINOK(OpenStream()); } - if (processedSize != 0) - *processedSize = realProcessedSize; return S_OK; } STDMETHODIMP CFolderInStream::GetSubStreamSize(UInt64 subStream, UInt64 *value) { *value = 0; - int subStreamIndex = (int)subStream; - if (subStreamIndex < 0 || subStream > Sizes.Size()) + int index2 = (int)subStream; + if (index2 < 0 || subStream > Sizes.Size()) return E_FAIL; - if (subStreamIndex < Sizes.Size()) + if (index2 < Sizes.Size()) { - *value= Sizes[subStreamIndex]; + *value = Sizes[index2]; return S_OK; } if (!_currentSizeIsDefined) diff --git a/CPP/7zip/Archive/7z/7zFolderInStream.h b/CPP/7zip/Archive/7z/7zFolderInStream.h index 68e2b27b..6df3672a 100755 --- a/CPP/7zip/Archive/7z/7zFolderInStream.h +++ b/CPP/7zip/Archive/7z/7zFolderInStream.h @@ -1,15 +1,13 @@ -// 7z/FolderInStream.h +// 7zFolderInStream.h -#ifndef __7Z_FOLDERINSTREAM_H -#define __7Z_FOLDERINSTREAM_H - -#include "7zItem.h" -#include "7zHeader.h" +#ifndef __7Z_FOLDER_IN_STREAM_H +#define __7Z_FOLDER_IN_STREAM_H +#include "../../ICoder.h" #include "../IArchive.h" #include "../Common/InStreamWithCRC.h" -#include "../../IStream.h" -#include "../../ICoder.h" + +#include "7zItem.h" namespace NArchive { namespace N7z { @@ -19,26 +17,14 @@ class CFolderInStream: public ICompressGetSubStreamSize, public CMyUnknownImp { -public: - - MY_UNKNOWN_IMP1(ICompressGetSubStreamSize) - - CFolderInStream(); - - STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); - - STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value); -private: CSequentialInStreamWithCRC *_inStreamWithHashSpec; CMyComPtr<ISequentialInStream> _inStreamWithHash; CMyComPtr<IArchiveUpdateCallback> _updateCallback; bool _currentSizeIsDefined; - UInt64 _currentSize; - bool _fileIsOpen; + UInt64 _currentSize; UInt64 _filePos; - const UInt32 *_fileIndices; UInt32 _numFiles; UInt32 _fileIndex; @@ -46,12 +32,18 @@ private: HRESULT OpenStream(); HRESULT CloseStream(); void AddDigest(); + public: - void Init(IArchiveUpdateCallback *updateCallback, - const UInt32 *fileIndices, UInt32 numFiles); CRecordVector<bool> Processed; CRecordVector<UInt32> CRCs; CRecordVector<UInt64> Sizes; + + MY_UNKNOWN_IMP1(ICompressGetSubStreamSize) + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); + STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value); + + CFolderInStream(); + void Init(IArchiveUpdateCallback *updateCallback, const UInt32 *fileIndices, UInt32 numFiles); UInt64 GetFullSize() const { UInt64 size = 0; diff --git a/CPP/7zip/Archive/7z/7zFolderOutStream.cpp b/CPP/7zip/Archive/7z/7zFolderOutStream.cpp index c5dbfa6d..22c4600e 100755 --- a/CPP/7zip/Archive/7z/7zFolderOutStream.cpp +++ b/CPP/7zip/Archive/7z/7zFolderOutStream.cpp @@ -14,13 +14,13 @@ CFolderOutStream::CFolderOutStream() } HRESULT CFolderOutStream::Init( - const CArchiveDatabaseEx *archiveDatabase, + const CArchiveDatabaseEx *db, UInt32 ref2Offset, UInt32 startIndex, const CBoolVector *extractStatuses, IArchiveExtractCallback *extractCallback, bool testMode, bool checkCrc) { - _db = archiveDatabase; + _db = db; _ref2Offset = ref2Offset; _startIndex = startIndex; @@ -121,6 +121,15 @@ STDMETHODIMP CFolderOutStream::Write(const void *data, UInt32 size, UInt32 *proc return S_OK; } +STDMETHODIMP CFolderOutStream::GetSubStreamSize(UInt64 subStream, UInt64 *value) +{ + *value = 0; + if ((int)subStream >= _extractStatuses->Size()) + return S_FALSE; + *value = _db->Files[_startIndex + (int)subStream].Size; + return S_OK; +} + HRESULT CFolderOutStream::FlushCorrupted(Int32 resultEOperationResult) { while (_currentIndex < _extractStatuses->Size()) diff --git a/CPP/7zip/Archive/7z/7zFolderOutStream.h b/CPP/7zip/Archive/7z/7zFolderOutStream.h index e6e05b85..f9bb1af4 100755 --- a/CPP/7zip/Archive/7z/7zFolderOutStream.h +++ b/CPP/7zip/Archive/7z/7zFolderOutStream.h @@ -3,17 +3,18 @@ #ifndef __7Z_FOLDER_OUT_STREAM_H #define __7Z_FOLDER_OUT_STREAM_H -#include "7zIn.h" - #include "../../IStream.h" #include "../IArchive.h" #include "../Common/OutStreamWithCRC.h" +#include "7zIn.h" + namespace NArchive { namespace N7z { class CFolderOutStream: public ISequentialOutStream, + public ICompressGetSubStreamSize, public CMyUnknownImp { COutStreamWithCRC *_crcStreamSpec; @@ -34,14 +35,15 @@ class CFolderOutStream: HRESULT CloseFileAndSetResult(); HRESULT ProcessEmptyFiles(); public: - MY_UNKNOWN_IMP - + MY_UNKNOWN_IMP1(ICompressGetSubStreamSize) + CFolderOutStream(); STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); + STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value); HRESULT Init( - const CArchiveDatabaseEx *archiveDatabase, + const CArchiveDatabaseEx *db, UInt32 ref2Offset, UInt32 startIndex, const CBoolVector *extractStatuses, IArchiveExtractCallback *extractCallback, diff --git a/CPP/7zip/Archive/Common/CoderMixer2.cpp b/CPP/7zip/Archive/Common/CoderMixer2.cpp index aed94f9c..0b06a489 100755 --- a/CPP/7zip/Archive/Common/CoderMixer2.cpp +++ b/CPP/7zip/Archive/Common/CoderMixer2.cpp @@ -87,7 +87,7 @@ CCoderInfo2::CCoderInfo2(UInt32 numInStreams, UInt32 numOutStreams): { InSizes.Reserve(NumInStreams); InSizePointers.Reserve(NumInStreams); - OutSizePointers.Reserve(NumOutStreams); + OutSizes.Reserve(NumOutStreams); OutSizePointers.Reserve(NumOutStreams); } diff --git a/CPP/7zip/Archive/Common/InStreamWithCRC.cpp b/CPP/7zip/Archive/Common/InStreamWithCRC.cpp index 1d9e5556..569a56f3 100755 --- a/CPP/7zip/Archive/Common/InStreamWithCRC.cpp +++ b/CPP/7zip/Archive/Common/InStreamWithCRC.cpp @@ -21,8 +21,10 @@ STDMETHODIMP CInStreamWithCRC::Read(void *data, UInt32 size, UInt32 *processedSi { UInt32 realProcessedSize; HRESULT result = _stream->Read(data, size, &realProcessedSize); + /* if (size > 0 && realProcessedSize == 0) _wasFinished = true; + */ _size += realProcessedSize; _crc = CrcUpdate(_crc, data, realProcessedSize); if(processedSize != NULL) diff --git a/CPP/7zip/Archive/Common/InStreamWithCRC.h b/CPP/7zip/Archive/Common/InStreamWithCRC.h index 0492a5f8..31b761e4 100755 --- a/CPP/7zip/Archive/Common/InStreamWithCRC.h +++ b/CPP/7zip/Archive/Common/InStreamWithCRC.h @@ -49,19 +49,19 @@ private: CMyComPtr<IInStream> _stream; UInt64 _size; UInt32 _crc; - bool _wasFinished; + // bool _wasFinished; public: void SetStream(IInStream *stream) { _stream = stream; } void Init() { _size = 0; - _wasFinished = false; + // _wasFinished = false; _crc = CRC_INIT_VAL; } void ReleaseStream() { _stream.Release(); } UInt32 GetCRC() const { return CRC_GET_DIGEST(_crc); } UInt64 GetSize() const { return _size; } - bool WasFinished() const { return _wasFinished; } + // bool WasFinished() const { return _wasFinished; } }; #endif diff --git a/CPP/7zip/Archive/DebHandler.cpp b/CPP/7zip/Archive/DebHandler.cpp index b9724c2a..82d2cde8 100755 --- a/CPP/7zip/Archive/DebHandler.cpp +++ b/CPP/7zip/Archive/DebHandler.cpp @@ -3,8 +3,6 @@ #include "StdAfx.h" #include "Common/ComTry.h" -#include "Common/Defs.h" -#include "Common/NewHandler.h" #include "Common/StringConvert.h" #include "Common/StringToInt.h" diff --git a/CPP/7zip/Archive/Iso/IsoHandler.cpp b/CPP/7zip/Archive/Iso/IsoHandler.cpp index 9c20fec3..dc20c240 100755 --- a/CPP/7zip/Archive/Iso/IsoHandler.cpp +++ b/CPP/7zip/Archive/Iso/IsoHandler.cpp @@ -3,9 +3,7 @@ #include "StdAfx.h" #include "Common/ComTry.h" -#include "Common/Defs.h" #include "Common/IntToString.h" -#include "Common/NewHandler.h" #include "Common/StringConvert.h" #include "Windows/PropVariant.h" @@ -26,7 +24,7 @@ using namespace NTime; namespace NArchive { namespace NIso { -STATPROPSTG kProps[] = +static STATPROPSTG kProps[] = { { NULL, kpidPath, VT_BSTR}, { NULL, kpidIsDir, VT_BOOL}, diff --git a/CPP/7zip/Archive/Iso/IsoRegister.cpp b/CPP/7zip/Archive/Iso/IsoRegister.cpp index 39f91198..67a09c76 100755 --- a/CPP/7zip/Archive/Iso/IsoRegister.cpp +++ b/CPP/7zip/Archive/Iso/IsoRegister.cpp @@ -8,6 +8,6 @@ static IInArchive *CreateArc() { return new NArchive::NIso::CHandler; } static CArcInfo g_ArcInfo = - { L"Iso", L"iso", 0, 0xE7, { 'C', 'D', '0', '0', '1', 0x1 }, 7, false, CreateArc, 0 }; + { L"Iso", L"iso img", 0, 0xE7, { 'C', 'D', '0', '0', '1', 0x1 }, 7, false, CreateArc, 0 }; REGISTER_ARC(Iso) diff --git a/CPP/7zip/Archive/LzhHandler.cpp b/CPP/7zip/Archive/LzhHandler.cpp index b9d953b9..a7fcd676 100755 --- a/CPP/7zip/Archive/LzhHandler.cpp +++ b/CPP/7zip/Archive/LzhHandler.cpp @@ -646,7 +646,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, totalUnPacked += item.Size; totalPacked += item.PackSize; } - extractCallback->SetTotal(totalUnPacked); + RINOK(extractCallback->SetTotal(totalUnPacked)); UInt64 currentTotalUnPacked = 0, currentTotalPacked = 0; UInt64 currentItemUnPacked, currentItemPacked; diff --git a/CPP/7zip/Archive/Nsis/NsisHandler.cpp b/CPP/7zip/Archive/Nsis/NsisHandler.cpp index 8005ddbc..818b0a88 100755 --- a/CPP/7zip/Archive/Nsis/NsisHandler.cpp +++ b/CPP/7zip/Archive/Nsis/NsisHandler.cpp @@ -6,7 +6,6 @@ #include "Common/ComTry.h" #include "Common/IntToString.h" -#include "Common/NewHandler.h" #include "Windows/PropVariant.h" diff --git a/CPP/7zip/Archive/NtfsHandler.cpp b/CPP/7zip/Archive/NtfsHandler.cpp index f88dd012..8670e164 100755 --- a/CPP/7zip/Archive/NtfsHandler.cpp +++ b/CPP/7zip/Archive/NtfsHandler.cpp @@ -1283,9 +1283,11 @@ HRESULT CDatabase::Open() { if (OpenCallback) { - // Sleep(0); UInt64 numFiles = Recs.Size(); - RINOK(OpenCallback->SetCompleted(&numFiles, &pos64)); + if ((numFiles & 0x3FF) == 0) + { + RINOK(OpenCallback->SetCompleted(&numFiles, &pos64)); + } } UInt32 readSize = kBufSize; UInt64 rem = mftSize - pos64; diff --git a/CPP/7zip/Archive/Rar/RarHandler.cpp b/CPP/7zip/Archive/Rar/RarHandler.cpp index b5decec8..8906614a 100755 --- a/CPP/7zip/Archive/Rar/RarHandler.cpp +++ b/CPP/7zip/Archive/Rar/RarHandler.cpp @@ -520,7 +520,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, lastIndex = index + 1; } - extractCallback->SetTotal(importantTotalUnPacked); + RINOK(extractCallback->SetTotal(importantTotalUnPacked)); UInt64 currentImportantTotalUnPacked = 0; UInt64 currentImportantTotalPacked = 0; UInt64 currentUnPackSize, currentPackSize; diff --git a/CPP/7zip/Archive/Tar/TarHandler.cpp b/CPP/7zip/Archive/Tar/TarHandler.cpp index 31e30573..e25463de 100755 --- a/CPP/7zip/Archive/Tar/TarHandler.cpp +++ b/CPP/7zip/Archive/Tar/TarHandler.cpp @@ -3,8 +3,6 @@ #include "StdAfx.h" #include "Common/ComTry.h" -#include "Common/Defs.h" -#include "Common/NewHandler.h" #include "Common/StringConvert.h" #include "Windows/PropVariant.h" @@ -23,7 +21,7 @@ using namespace NWindows; namespace NArchive { namespace NTar { -STATPROPSTG kProps[] = +static STATPROPSTG kProps[] = { { NULL, kpidPath, VT_BSTR}, { NULL, kpidIsDir, VT_BOOL}, diff --git a/CPP/7zip/Archive/Tar/TarIn.cpp b/CPP/7zip/Archive/Tar/TarIn.cpp index b8409195..939c6c0a 100755 --- a/CPP/7zip/Archive/Tar/TarIn.cpp +++ b/CPP/7zip/Archive/Tar/TarIn.cpp @@ -69,11 +69,20 @@ static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemE filled = false; - processedSize = NFileHeader::kRecordSize; - RINOK(ReadStream(stream, buf, &processedSize)); - if (processedSize == 0 || (processedSize == NFileHeader::kRecordSize && IsRecordLast(buf))) - return S_OK; - if (processedSize < NFileHeader::kRecordSize) + bool thereAreEmptyRecords = false; + for (;;) + { + processedSize = NFileHeader::kRecordSize; + RINOK(ReadStream(stream, buf, &processedSize)); + if (processedSize == 0) + return S_OK; + if (processedSize != NFileHeader::kRecordSize) + return S_FALSE; + if (!IsRecordLast(buf)) + break; + thereAreEmptyRecords = true; + } + if (thereAreEmptyRecords) return S_FALSE; ReadString(p, NFileHeader::kNameSize, item.Name); p += NFileHeader::kNameSize; diff --git a/CPP/7zip/Archive/Udf/UdfHandler.cpp b/CPP/7zip/Archive/Udf/UdfHandler.cpp index 42419a9d..c7085272 100755 --- a/CPP/7zip/Archive/Udf/UdfHandler.cpp +++ b/CPP/7zip/Archive/Udf/UdfHandler.cpp @@ -3,7 +3,6 @@ #include "StdAfx.h" #include "Common/ComTry.h" -#include "Common/NewHandler.h" #include "Windows/PropVariant.h" #include "Windows/Time.h" @@ -34,7 +33,7 @@ void UdfTimeToFileTime(const CTime &t, NWindows::NCOM::CPropVariant &prop) prop = ft; } -STATPROPSTG kProps[] = +static STATPROPSTG kProps[] = { { NULL, kpidPath, VT_BSTR}, { NULL, kpidIsDir, VT_BOOL}, @@ -44,7 +43,7 @@ STATPROPSTG kProps[] = { NULL, kpidATime, VT_FILETIME} }; -STATPROPSTG kArcProps[] = +static STATPROPSTG kArcProps[] = { { NULL, kpidComment, VT_BSTR}, { NULL, kpidClusterSize, VT_UI4}, diff --git a/CPP/7zip/Archive/Udf/UdfRegister.cpp b/CPP/7zip/Archive/Udf/UdfRegister.cpp index 5dc7db6a..1b08d120 100755 --- a/CPP/7zip/Archive/Udf/UdfRegister.cpp +++ b/CPP/7zip/Archive/Udf/UdfRegister.cpp @@ -8,6 +8,6 @@ static IInArchive *CreateArc() { return new NArchive::NUdf::CHandler; } static CArcInfo g_ArcInfo = - { L"Udf", L"iso", 0, 0xE0, { 0, 'N', 'S', 'R', '0' }, 5, false, CreateArc, 0 }; + { L"Udf", L"iso img", 0, 0xE0, { 0, 'N', 'S', 'R', '0' }, 5, false, CreateArc, 0 }; REGISTER_ARC(Udf) diff --git a/CPP/7zip/Archive/Wim/WimHandler.cpp b/CPP/7zip/Archive/Wim/WimHandler.cpp index 8093af77..8092a34c 100755 --- a/CPP/7zip/Archive/Wim/WimHandler.cpp +++ b/CPP/7zip/Archive/Wim/WimHandler.cpp @@ -2,18 +2,17 @@ #include "StdAfx.h" -#include "Common/IntToString.h" -#include "Common/Defs.h" +#include "../../../../C/CpuArch.h" + #include "Common/ComTry.h" +#include "Common/IntToString.h" #include "Common/StringToInt.h" #include "Common/UTFConvert.h" #include "Windows/PropVariant.h" -#include "../../Common/StreamUtils.h" #include "../../Common/ProgressUtils.h" - -#include "../../../../C/CpuArch.h" +#include "../../Common/StreamUtils.h" #include "WimHandler.h" @@ -28,17 +27,18 @@ namespace NWim { #define WIM_DETAILS -STATPROPSTG kProps[] = +static STATPROPSTG kProps[] = { { NULL, kpidPath, VT_BSTR}, { NULL, kpidIsDir, VT_BOOL}, { NULL, kpidSize, VT_UI8}, { NULL, kpidPackSize, VT_UI8}, - { NULL, kpidAttrib, VT_UI4}, - { NULL, kpidMethod, VT_BSTR}, { NULL, kpidMTime, VT_FILETIME}, { NULL, kpidCTime, VT_FILETIME}, - { NULL, kpidATime, VT_FILETIME} + { NULL, kpidATime, VT_FILETIME}, + { NULL, kpidAttrib, VT_UI4}, + { NULL, kpidMethod, VT_BSTR}, + { NULL, kpidShortName, VT_BSTR} #ifdef WIM_DETAILS , { NULL, kpidVolume, VT_UI4} @@ -47,14 +47,14 @@ STATPROPSTG kProps[] = #endif }; -STATPROPSTG kArcProps[] = +static STATPROPSTG kArcProps[] = { { NULL, kpidSize, VT_UI8}, { NULL, kpidPackSize, VT_UI8}, { NULL, kpidMethod, VT_BSTR}, { NULL, kpidCTime, VT_FILETIME}, { NULL, kpidMTime, VT_FILETIME}, - { NULL, kpidComment, VT_FILETIME}, + { NULL, kpidComment, VT_BSTR}, { NULL, kpidIsVolume, VT_BOOL}, { NULL, kpidVolume, VT_UI4}, { NULL, kpidNumVolumes, VT_UI4} @@ -87,49 +87,51 @@ static bool ParseNumber32(const AString &s, UInt32 &res) return true; } -void ParseTime(const CXmlItem &item, bool &defined, FILETIME &ft, const AString &s) +bool ParseTime(const CXmlItem &item, FILETIME &ft, const char *tag) { - defined = false; - int cTimeIndex = item.FindSubTag(s); - if (cTimeIndex >= 0) + int index = item.FindSubTag(tag); + if (index >= 0) { - const CXmlItem &timeItem = item.SubItems[cTimeIndex]; - UInt32 high = 0, low = 0; - if (ParseNumber32(timeItem.GetSubStringForTag("HIGHPART"), high) && - ParseNumber32(timeItem.GetSubStringForTag("LOWPART"), low)) + const CXmlItem &timeItem = item.SubItems[index]; + UInt32 low = 0, high = 0; + if (ParseNumber32(timeItem.GetSubStringForTag("LOWPART"), low) && + ParseNumber32(timeItem.GetSubStringForTag("HIGHPART"), high)) { - defined = true; - ft.dwHighDateTime = high; ft.dwLowDateTime = low; + ft.dwHighDateTime = high; + return true; } } + return false; } void CImageInfo::Parse(const CXmlItem &item) { - ParseTime(item, CTimeDefined, CTime, "CREATIONTIME"); - ParseTime(item, MTimeDefined, MTime, "LASTMODIFICATIONTIME"); + CTimeDefined = ParseTime(item, CTime, "CREATIONTIME"); + MTimeDefined = ParseTime(item, MTime, "LASTMODIFICATIONTIME"); NameDefined = ConvertUTF8ToUnicode(item.GetSubStringForTag("NAME"), Name); // IndexDefined = ParseNumber32(item.GetPropertyValue("INDEX"), Index); } -void CXml::Parse() +void CXml::ToUnicode(UString &s) { size_t size = Data.GetCapacity(); - if (size < 2 || (size & 1) != 0 || (size > 1 << 24)) + if (size < 2 || (size & 1) != 0 || size > (1 << 24)) return; const Byte *p = Data; if (Get16(p) != 0xFEFF) return; - UString s; - { - wchar_t *chars = s.GetBuffer((int)size / 2 + 1); - for (size_t i = 2; i < size; i += 2) - *chars++ = (wchar_t)Get16(p + i); - *chars = 0; - s.ReleaseBuffer(); - } + wchar_t *chars = s.GetBuffer((int)size / 2); + for (size_t i = 2; i < size; i += 2) + *chars++ = (wchar_t)Get16(p + i); + *chars = 0; + s.ReleaseBuffer(); +} +void CXml::Parse() +{ + UString s; + ToUnicode(s); AString utf; if (!ConvertUnicodeToUTF8(s, utf)) return; @@ -151,10 +153,9 @@ void CXml::Parse() } } -static const wchar_t *kStreamsNamePrefix = L"Files" WSTRING_PATH_SEPARATOR; -static const wchar_t *kMethodLZX = L"LZX"; -static const wchar_t *kMethodXpress = L"XPress"; -static const wchar_t *kMethodCopy = L"Copy"; +static const char *kMethodLZX = "LZX"; +static const char *kMethodXpress = "XPress"; +static const char *kMethodCopy = "Copy"; IMP_IInArchive_Props IMP_IInArchive_ArcProps @@ -165,22 +166,22 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) NWindows::NCOM::CPropVariant prop; const CImageInfo *image = NULL; - if (m_Xmls.Size() == 1) + if (_xmls.Size() == 1) { - const CXml &xml = m_Xmls[0]; + const CXml &xml = _xmls[0]; if (xml.Images.Size() == 1) image = &xml.Images[0]; } switch(propID) { - case kpidSize: prop = m_Database.GetUnpackSize(); break; - case kpidPackSize: prop = m_Database.GetPackSize(); break; + case kpidSize: prop = _db.GetUnpackSize(); break; + case kpidPackSize: prop = _db.GetPackSize(); break; case kpidCTime: - if (m_Xmls.Size() == 1) + if (_xmls.Size() == 1) { - const CXml &xml = m_Xmls[0]; + const CXml &xml = _xmls[0]; int index = -1; for (int i = 0; i < xml.Images.Size(); i++) { @@ -195,9 +196,9 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) break; case kpidMTime: - if (m_Xmls.Size() == 1) + if (_xmls.Size() == 1) { - const CXml &xml = m_Xmls[0]; + const CXml &xml = _xmls[0]; int index = -1; for (int i = 0; i < xml.Images.Size(); i++) { @@ -211,32 +212,43 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) } break; - case kpidComment: if (image != NULL && image->NameDefined) prop = image->Name; break; + case kpidComment: + if (image != NULL) + { + if (_xmlInComments) + { + UString s; + _xmls[0].ToUnicode(s); + prop = s; + } + else if (image->NameDefined) + prop = image->Name; + } + break; case kpidIsVolume: - if (m_Xmls.Size() > 0) + if (_xmls.Size() > 0) { - UInt16 volIndex = m_Xmls[0].VolIndex; - if (volIndex < m_Volumes.Size()) - prop = (m_Volumes[volIndex].Header.NumParts > 1); + UInt16 volIndex = _xmls[0].VolIndex; + if (volIndex < _volumes.Size()) + prop = (_volumes[volIndex].Header.NumParts > 1); } break; case kpidVolume: - if (m_Xmls.Size() > 0) + if (_xmls.Size() > 0) { - UInt16 volIndex = m_Xmls[0].VolIndex; - if (volIndex < m_Volumes.Size()) - prop = (UInt32)m_Volumes[volIndex].Header.PartNumber; + UInt16 volIndex = _xmls[0].VolIndex; + if (volIndex < _volumes.Size()) + prop = (UInt32)_volumes[volIndex].Header.PartNumber; } break; - case kpidNumVolumes: if (m_Volumes.Size() > 0) prop = (UInt32)(m_Volumes.Size() - 1); break; + case kpidNumVolumes: if (_volumes.Size() > 0) prop = (UInt32)(_volumes.Size() - 1); break; case kpidMethod: { bool lzx = false, xpress = false, copy = false; - for (int i = 0; i < m_Xmls.Size(); i++) + for (int i = 0; i < _xmls.Size(); i++) { - const CVolume &vol = m_Volumes[m_Xmls[i].VolIndex]; - const CHeader &header = vol.Header; + const CHeader &header = _volumes[_xmls[i].VolIndex].Header; if (header.IsCompressed()) if (header.IsLzxMode()) lzx = true; @@ -245,19 +257,19 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) else copy = true; } - UString res; + AString res; if (lzx) res = kMethodLZX; if (xpress) { if (!res.IsEmpty()) - res += L' '; + res += ' '; res += kMethodXpress; } if (copy) { if (!res.IsEmpty()) - res += L' '; + res += ' '; res += kMethodCopy; } prop = res; @@ -272,35 +284,41 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val { COM_TRY_BEGIN NWindows::NCOM::CPropVariant prop; - if (index < (UInt32)m_Database.Items.Size()) + if (index < (UInt32)_db.SortedItems.Size()) { - const CItem &item = m_Database.Items[index]; + int realIndex = _db.SortedItems[index]; + const CItem &item = _db.Items[realIndex]; const CStreamInfo *si = NULL; const CVolume *vol = NULL; if (item.StreamIndex >= 0) { - si = &m_Database.Streams[item.StreamIndex]; - vol = &m_Volumes[si->PartNumber]; + si = &_db.Streams[item.StreamIndex]; + vol = &_volumes[si->PartNumber]; } switch(propID) { case kpidPath: if (item.HasMetadata) - prop = item.Name; + prop = _db.GetItemPath(realIndex); else { - wchar_t sz[32]; + char sz[32]; ConvertUInt64ToString(item.StreamIndex, sz); - UString s = sz; - while (s.Length() < m_NameLenForStreams) - s = L'0' + s; - s = UString(kStreamsNamePrefix) + s; + AString s = sz; + while (s.Length() < _nameLenForStreams) + s = '0' + s; + /* + if (si->Resource.IsFree()) + prefix = "[Free]"; + */ + s = "[Files]" STRING_PATH_SEPARATOR + s; prop = s; - break; } break; - case kpidIsDir: prop = item.isDir(); break; + case kpidShortName: if (item.HasMetadata) prop = item.ShortName; break; + + case kpidIsDir: prop = item.IsDir(); break; case kpidAttrib: if (item.HasMetadata) prop = item.Attrib; break; case kpidCTime: if (item.HasMetadata) prop = item.CTime; break; case kpidATime: if (item.HasMetadata) prop = item.ATime; break; @@ -318,22 +336,21 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val } else { - index -= m_Database.Items.Size(); + index -= _db.SortedItems.Size(); { switch(propID) { case kpidPath: { - wchar_t sz[32]; - ConvertUInt64ToString(m_Xmls[index].VolIndex, sz); - UString s = (UString)sz + L".xml"; - prop = s; + char sz[32]; + ConvertUInt64ToString(_xmls[index].VolIndex, sz); + prop = (AString)"[" + (AString)sz + "].xml"; break; } case kpidIsDir: prop = false; break; case kpidPackSize: - case kpidSize: prop = (UInt64)m_Xmls[index].Data.GetCapacity(); break; - case kpidMethod: prop = L"Copy"; break; + case kpidSize: prop = (UInt64)_xmls[index].Data.GetCapacity(); break; + case kpidMethod: prop = kMethodCopy; break; } } } @@ -411,13 +428,13 @@ STDMETHODIMP CHandler::Open(IInStream *inStream, return res; } if (firstVolumeIndex >= 0) - if (!header.AreFromOnArchive(m_Volumes[firstVolumeIndex].Header)) + if (!header.AreFromOnArchive(_volumes[firstVolumeIndex].Header)) break; - if (m_Volumes.Size() > header.PartNumber && m_Volumes[header.PartNumber].Stream) + if (_volumes.Size() > header.PartNumber && _volumes[header.PartNumber].Stream) break; CXml xml; xml.VolIndex = header.PartNumber; - res = OpenArchive(curStream, header, xml.Data, m_Database); + res = _db.Open(curStream, header, xml.Data, openArchiveCallback); if (res != S_OK) { if (i == 1) @@ -427,22 +444,22 @@ STDMETHODIMP CHandler::Open(IInStream *inStream, return res; } - while (m_Volumes.Size() <= header.PartNumber) - m_Volumes.Add(CVolume()); - CVolume &volume = m_Volumes[header.PartNumber]; + while (_volumes.Size() <= header.PartNumber) + _volumes.Add(CVolume()); + CVolume &volume = _volumes[header.PartNumber]; volume.Header = header; volume.Stream = curStream; firstVolumeIndex = header.PartNumber; bool needAddXml = true; - if (m_Xmls.Size() != 0) - if (xml.Data == m_Xmls[0].Data) + if (_xmls.Size() != 0) + if (xml.Data == _xmls[0].Data) needAddXml = false; if (needAddXml) { xml.Parse(); - m_Xmls.Add(xml); + _xmls.Add(xml); } if (i == 1) @@ -462,11 +479,14 @@ STDMETHODIMP CHandler::Open(IInStream *inStream, } } - RINOK(SortDatabase(m_Database)); + _db.DetectPathMode(); + RINOK(_db.Sort(_db.SkipRoot)); wchar_t sz[32]; - ConvertUInt64ToString(m_Database.Streams.Size(), sz); - m_NameLenForStreams = MyStringLen(sz); + ConvertUInt64ToString(_db.Streams.Size(), sz); + _nameLenForStreams = MyStringLen(sz); + + _xmlInComments = (_xmls.Size() == 1 && !_db.ShowImageNumber); } catch(...) { @@ -478,10 +498,10 @@ STDMETHODIMP CHandler::Open(IInStream *inStream, STDMETHODIMP CHandler::Close() { - m_Database.Clear(); - m_Volumes.Clear(); - m_Xmls.Clear(); - m_NameLenForStreams = 0; + _db.Clear(); + _volumes.Clear(); + _xmls.Clear(); + _nameLenForStreams = 0; return S_OK; } @@ -492,7 +512,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, bool allFilesMode = (numItems == (UInt32)-1); if (allFilesMode) - numItems = m_Database.Items.Size() + m_Xmls.Size(); + numItems = _db.SortedItems.Size() + _xmls.Size(); if (numItems == 0) return S_OK; @@ -501,17 +521,17 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, for (i = 0; i < numItems; i++) { UInt32 index = allFilesMode ? i : indices[i]; - if (index < (UInt32)m_Database.Items.Size()) + if (index < (UInt32)_db.SortedItems.Size()) { - int streamIndex = m_Database.Items[index].StreamIndex; + int streamIndex = _db.Items[_db.SortedItems[index]].StreamIndex; if (streamIndex >= 0) { - const CStreamInfo &si = m_Database.Streams[streamIndex]; + const CStreamInfo &si = _db.Streams[streamIndex]; totalSize += si.Resource.UnpackSize; } } else - totalSize += m_Xmls[index - (UInt32)m_Database.Items.Size()].Data.GetCapacity(); + totalSize += _xmls[index - (UInt32)_db.SortedItems.Size()].Data.GetCapacity(); } RINOK(extractCallback->SetTotal(totalSize)); @@ -546,12 +566,12 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, CMyComPtr<ISequentialOutStream> realOutStream; RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); - if (index >= (UInt32)m_Database.Items.Size()) + if (index >= (UInt32)_db.SortedItems.Size()) { if (!testMode && !realOutStream) continue; RINOK(extractCallback->PrepareOperation(askMode)); - const CByteBuffer &data = m_Xmls[index - (UInt32)m_Database.Items.Size()].Data; + const CByteBuffer &data = _xmls[index - (UInt32)_db.SortedItems.Size()].Data; currentItemUnPacked = data.GetCapacity(); if (realOutStream) { @@ -562,7 +582,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, continue; } - const CItem &item = m_Database.Items[index]; + const CItem &item = _db.Items[_db.SortedItems[index]]; int streamIndex = item.StreamIndex; if (streamIndex < 0) { @@ -576,7 +596,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, continue; } - const CStreamInfo &si = m_Database.Streams[streamIndex]; + const CStreamInfo &si = _db.Streams[streamIndex]; currentItemUnPacked = si.Resource.UnpackSize; currentItemPacked = si.Resource.PackSize; @@ -587,7 +607,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, if (streamIndex != prevSuccessStreamIndex || realOutStream) { Byte digest[20]; - const CVolume &vol = m_Volumes[si.PartNumber]; + const CVolume &vol = _volumes[si.PartNumber]; HRESULT res = unpacker.Unpack(vol.Stream, si.Resource, vol.Header.IsLzxMode(), realOutStream, progress, digest); if (res == S_OK) @@ -611,7 +631,9 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) { - *numItems = m_Database.Items.Size() + m_Xmls.Size(); + *numItems = _db.SortedItems.Size(); + if (!_xmlInComments) + *numItems += _xmls.Size(); return S_OK; } diff --git a/CPP/7zip/Archive/Wim/WimHandler.h b/CPP/7zip/Archive/Wim/WimHandler.h index b7df3606..d105e548 100755 --- a/CPP/7zip/Archive/Wim/WimHandler.h +++ b/CPP/7zip/Archive/Wim/WimHandler.h @@ -6,7 +6,6 @@ #include "Common/MyCom.h" #include "Common/MyXml.h" -#include "../IArchive.h" #include "WimIn.h" namespace NArchive { @@ -40,25 +39,35 @@ struct CXml { CByteBuffer Data; UInt16 VolIndex; - CObjectVector<CImageInfo> Images; + void ToUnicode(UString &s); void Parse(); }; + class CHandler: public IInArchive, public CMyUnknownImp { + CDatabase _db; + CObjectVector<CVolume> _volumes; + CObjectVector<CXml> _xmls; + int _nameLenForStreams; + bool _xmlInComments; + public: MY_UNKNOWN_IMP1(IInArchive) INTERFACE_IInArchive(;) +}; -private: - CDatabase m_Database; - CObjectVector<CVolume> m_Volumes; - CObjectVector<CXml> m_Xmls; - int m_NameLenForStreams; +class COutHandler: + public IOutArchive, + public CMyUnknownImp +{ +public: + MY_UNKNOWN_IMP1(IOutArchive) + INTERFACE_IOutArchive(;) }; }} diff --git a/CPP/7zip/Archive/Wim/WimHandlerOut.cpp b/CPP/7zip/Archive/Wim/WimHandlerOut.cpp new file mode 100755 index 00000000..d51eb81a --- /dev/null +++ b/CPP/7zip/Archive/Wim/WimHandlerOut.cpp @@ -0,0 +1,647 @@ +// WimHandlerOut.cpp + +#include "StdAfx.h" + +#include "../../../../C/CpuArch.h" + +#include "Common/ComTry.h" +#include "Common/IntToString.h" + +#include "Windows/PropVariant.h" +#include "Windows/Time.h" + +#include "../../Common/LimitedStreams.h" +#include "../../Common/ProgressUtils.h" +#include "../../Common/StreamUtils.h" + +#include "../../Crypto/RandGen.h" +#include "../../Crypto/Sha1.h" + +#include "WimHandler.h" + +using namespace NWindows; + +namespace NArchive { +namespace NWim { + +struct CSha1Hash +{ + Byte Hash[kHashSize]; +}; + +struct CHashList +{ + CRecordVector<CSha1Hash> Digests; + CIntVector Sorted; + + int AddUnique(const CSha1Hash &h); +}; + +int CHashList::AddUnique(const CSha1Hash &h) +{ + int left = 0, right = Sorted.Size(); + while (left != right) + { + int mid = (left + right) / 2; + int index = Sorted[mid]; + UInt32 i; + const Byte *hash2 = Digests[index].Hash; + for (i = 0; i < kHashSize; i++) + if (h.Hash[i] != hash2[i]) + break; + if (i == kHashSize) + return index; + if (h.Hash[i] < hash2[i]) + right = mid; + else + left = mid + 1; + } + Sorted.Insert(left, Digests.Add(h)); + return -1; +} + +struct CUpdateItem +{ + UString Name; + UInt64 Size; + FILETIME CTime; + FILETIME ATime; + FILETIME MTime; + UInt32 Attrib; + bool IsDir; + int HashIndex; + + CUpdateItem(): HashIndex(-1) {} +}; + +struct CDir +{ + int Index; + UString Name; + CObjectVector<CDir> Dirs; + CIntVector Files; + + CDir(): Index(-1) {} + bool IsLeaf() const { return Index >= 0; } + UInt64 GetNumDirs() const; + UInt64 GetNumFiles() const; + CDir* AddDir(CObjectVector<CUpdateItem> &items, const UString &name, int index); +}; + +UInt64 CDir::GetNumDirs() const +{ + UInt64 num = Dirs.Size(); + for (int i = 0; i < Dirs.Size(); i++) + num += Dirs[i].GetNumDirs(); + return num; +} + +UInt64 CDir::GetNumFiles() const +{ + UInt64 num = Files.Size(); + for (int i = 0; i < Dirs.Size(); i++) + num += Dirs[i].GetNumFiles(); + return num; +} + +CDir* CDir::AddDir(CObjectVector<CUpdateItem> &items, const UString &name, int index) +{ + int left = 0, right = Dirs.Size(); + while (left != right) + { + int mid = (left + right) / 2; + CDir &d = Dirs[mid]; + int compare = name.CompareNoCase(d.IsLeaf() ? items[Dirs[mid].Index].Name : d.Name); + if (compare == 0) + { + if (index >= 0) + d.Index = index; + return &d; + } + if (compare < 0) + right = mid; + else + left = mid + 1; + } + Dirs.Insert(left, CDir()); + CDir &d = Dirs[left]; + d.Index = index; + if (index < 0) + d.Name = name; + return &d; +} + + +STDMETHODIMP COutHandler::GetFileTimeType(UInt32 *type) +{ + *type = NFileTimeType::kWindows; + return S_OK; +} + +static HRESULT GetTime(IArchiveUpdateCallback *callback, int index, PROPID propID, FILETIME &ft) +{ + ft.dwLowDateTime = ft.dwHighDateTime = 0; + NCOM::CPropVariant prop; + RINOK(callback->GetProperty(index, propID, &prop)); + if (prop.vt == VT_FILETIME) + ft = prop.filetime; + else if (prop.vt != VT_EMPTY) + return E_INVALIDARG; + return S_OK; +} + +#define Set16(p, d) SetUi16(p, d) +#define Set32(p, d) SetUi32(p, d) +#define Set64(p, d) SetUi64(p, d) + +void CResource::WriteTo(Byte *p) const +{ + Set64(p, PackSize); + p[7] = Flags; + Set64(p + 8, Offset); + Set64(p + 16, UnpackSize); +} + +void CHeader::WriteTo(Byte *p) const +{ + memcpy(p, kSignature, kSignatureSize); + Set32(p + 8, kHeaderSizeMax); + Set32(p + 0xC, Version); + Set32(p + 0x10, Flags); + Set32(p + 0x14, ChunkSize); + memcpy(p + 0x18, Guid, 16); + Set16(p + 0x28, PartNumber); + Set16(p + 0x2A, NumParts); + Set32(p + 0x2C, NumImages); + OffsetResource.WriteTo(p + 0x30); + XmlResource.WriteTo(p + 0x48); + MetadataResource.WriteTo(p + 0x60); + IntegrityResource.WriteTo(p + 0x7C); + Set32(p + 0x78, BootIndex); + memset(p + 0x94, 0, 60); +} + +void CStreamInfo::WriteTo(Byte *p) const +{ + Resource.WriteTo(p); + Set16(p + 0x18, PartNumber); + Set32(p + 0x1A, RefCount); + memcpy(p + 0x1E, Hash, kHashSize); +} + +class CInStreamWithSha1: + public ISequentialInStream, + public CMyUnknownImp +{ + CMyComPtr<ISequentialInStream> _stream; + UInt64 _size; + NCrypto::NSha1::CContext _sha; +public: + MY_UNKNOWN_IMP1(IInStream) + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); + + void SetStream(ISequentialInStream *stream) { _stream = stream; } + void Init() + { + _size = 0; + _sha.Init(); + } + void ReleaseStream() { _stream.Release(); } + UInt64 GetSize() const { return _size; } + void Final(Byte *digest) { _sha.Final(digest); } +}; + +STDMETHODIMP CInStreamWithSha1::Read(void *data, UInt32 size, UInt32 *processedSize) +{ + UInt32 realProcessedSize; + HRESULT result = _stream->Read(data, size, &realProcessedSize); + _size += realProcessedSize; + _sha.Update((const Byte *)data, realProcessedSize); + if (processedSize != NULL) + *processedSize = realProcessedSize; + return result; +} + +static void SetFileTimeToMem(Byte *p, const FILETIME &ft) +{ + Set32(p, ft.dwLowDateTime); + Set32(p + 4, ft.dwHighDateTime); +} + +static size_t WriteItem(const CUpdateItem &item, Byte *p, const Byte *hash) +{ + int fileNameLen = item.Name.Length() * 2; + int fileNameLen2 = (fileNameLen == 0 ? fileNameLen : fileNameLen + 2); + + size_t totalLen = ((kDirRecordSize + fileNameLen2 + 6) & ~7); + if (p) + { + memset(p, 0, totalLen); + Set64(p, totalLen); + Set64(p + 8, item.Attrib); + Set32(p + 0xC, (UInt32)(Int32)-1); // item.SecurityId + // Set64(p + 0x10, 0); // subdirOffset + SetFileTimeToMem(p + 0x28, item.CTime); + SetFileTimeToMem(p + 0x30, item.ATime); + SetFileTimeToMem(p + 0x38, item.MTime); + if (hash) + memcpy(p + 0x40, hash, kHashSize); + /* + else + memset(p + 0x40, 0, kHashSize); + */ + // Set16(p + 98, 0); // shortNameLen + Set16(p + 100, (UInt16)fileNameLen); + for (int i = 0; i * 2 < fileNameLen; i++) + Set16(p + kDirRecordSize + i * 2, item.Name[i]); + } + return totalLen; +} + +void WriteTree(const CDir &tree, CRecordVector<CSha1Hash> &digests, + CUpdateItem &defaultDirItem, + CObjectVector<CUpdateItem> &updateItems, Byte *dest, size_t &pos) +{ + int i; + for (i = 0; i < tree.Files.Size(); i++) + { + const CUpdateItem &ui = updateItems[tree.Files[i]]; + pos += WriteItem(ui, dest ? dest + pos : NULL, + ui.HashIndex >= 0 ? digests[ui.HashIndex].Hash : NULL); + } + + size_t posStart = pos; + for (i = 0; i < tree.Dirs.Size(); i++) + { + const CDir &subfolder = tree.Dirs[i]; + CUpdateItem *item = &defaultDirItem; + if (subfolder.IsLeaf()) + item = &updateItems[subfolder.Index]; + else + defaultDirItem.Name = subfolder.Name; + pos += WriteItem(*item, NULL, NULL); + } + + if (dest) + Set64(dest + pos, 0); + + pos += 8; + + for (i = 0; i < tree.Dirs.Size(); i++) + { + const CDir &subfolder = tree.Dirs[i]; + if (dest) + { + CUpdateItem *item = &defaultDirItem; + if (subfolder.IsLeaf()) + item = &updateItems[subfolder.Index]; + else + defaultDirItem.Name = subfolder.Name; + size_t len = WriteItem(*item, dest + posStart, NULL); + Set64(dest + posStart + 0x10, pos); + posStart += len; + } + WriteTree(subfolder, digests, defaultDirItem, updateItems, dest, pos); + } +} + +static void AddTag(AString &s, const char *name, const AString &value) +{ + s += "<"; + s += name; + s += ">"; + s += value; + s += "</"; + s += name; + s += ">"; +} + +static void AddTagUInt64(AString &s, const char *name, UInt64 value) +{ + char temp[32]; + ConvertUInt64ToString(value, temp); + AddTag(s, name, temp); +} + +static void ConvertUInt32ToHex(UInt32 value, char *s) +{ + for (int i = 0; i < 8; i++) + { + int t = value & 0xF; + value >>= 4; + s[7 - i] = (char)((t < 10) ? ('0' + t) : ('A' + (t - 10))); + } + s[8] = '\0'; +} + + +static AString TimeToXml(FILETIME &ft) +{ + AString res; + char temp[16] = { '0', 'x' }; + ConvertUInt32ToHex(ft.dwHighDateTime, temp + 2); + AddTag(res, "HIGHPART", temp); + ConvertUInt32ToHex(ft.dwLowDateTime, temp + 2); + AddTag(res, "LOWPART", temp); + return res; +} + +void CHeader::SetDefaultFields(bool useLZX) +{ + Version = kWimVersion; + Flags = NHeaderFlags::kRpFix; + ChunkSize = 0; + if (useLZX) + { + Flags |= NHeaderFlags::kCompression | NHeaderFlags::kLZX; + ChunkSize = kChunkSize; + } + g_RandomGenerator.Generate(Guid, 16); + PartNumber = 1; + NumParts = 1; + NumImages = 1; + BootIndex = 0; + OffsetResource.Clear(); + XmlResource.Clear(); + MetadataResource.Clear(); + IntegrityResource.Clear(); +} + +static HRESULT UpdateArchive(ISequentialOutStream *seqOutStream, + CDir &rootFolder, + CObjectVector<CUpdateItem> &updateItems, + IArchiveUpdateCallback *callback) +{ + CMyComPtr<IOutStream> outStream; + RINOK(seqOutStream->QueryInterface(IID_IOutStream, (void **)&outStream)); + if (!outStream) + return E_NOTIMPL; + + UInt64 complexity = 0; + + int i; + for (i = 0; i < updateItems.Size(); i++) + complexity += updateItems[i].Size; + + RINOK(callback->SetTotal(complexity)); + + NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder; + CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr<ICompressProgressInfo> progress = lps; + lps->Init(callback, true); + + complexity = 0; + + bool useCompression = false; + + CHeader header; + header.SetDefaultFields(useCompression); + Byte buf[kHeaderSizeMax]; + header.WriteTo(buf); + RINOK(WriteStream(outStream, buf, kHeaderSizeMax)); + + CHashList hashes; + CObjectVector<CStreamInfo> streams; + + UInt64 curPos = kHeaderSizeMax; + UInt64 unpackTotalSize = 0; + for (i = 0; i < updateItems.Size(); i++) + { + lps->InSize = lps->OutSize = complexity; + RINOK(lps->SetCur()); + + CUpdateItem &ui = updateItems[i]; + if (ui.IsDir || ui.Size == 0) + continue; + + CInStreamWithSha1 *inShaStreamSpec = new CInStreamWithSha1; + CMyComPtr<ISequentialInStream> inShaStream = inShaStreamSpec; + + { + CMyComPtr<ISequentialInStream> fileInStream; + HRESULT res = callback->GetStream(i, &fileInStream); + if (res != S_FALSE) + { + RINOK(res); + inShaStreamSpec->SetStream(fileInStream); + fileInStream.Release(); + inShaStreamSpec->Init(); + UInt64 offsetBlockSize = 0; + if (useCompression) + { + for (UInt64 t = kChunkSize; t < ui.Size; t += kChunkSize) + { + Byte buf[8]; + SetUi32(buf, (UInt32)t); + RINOK(WriteStream(outStream, buf, 4)); + offsetBlockSize += 4; + } + } + + RINOK(copyCoder->Code(inShaStream, outStream, NULL, NULL, progress)); + ui.Size = copyCoderSpec->TotalSize; + + CSha1Hash hash; + unpackTotalSize += ui.Size; + UInt64 packSize = offsetBlockSize + ui.Size; + inShaStreamSpec->Final(hash.Hash); + int index = hashes.AddUnique(hash); + if (index >= 0) + { + ui.HashIndex = index; + streams[index].RefCount++; + outStream->Seek(-(Int64)packSize, STREAM_SEEK_CUR, &curPos); + outStream->SetSize(curPos); + } + else + { + ui.HashIndex = hashes.Digests.Size() - 1; + CStreamInfo s; + s.Resource.PackSize = packSize; + s.Resource.Offset = curPos; + s.Resource.UnpackSize = ui.Size; + s.Resource.Flags = 0; + if (useCompression) + s.Resource.Flags = NResourceFlags::Compressed; + s.PartNumber = 1; + s.RefCount = 1; + memcpy(s.Hash, hash.Hash, kHashSize); + streams.Add(s); + curPos += packSize; + } + } + fileInStream.Release(); + complexity += ui.Size; + RINOK(callback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); + } + } + + + CUpdateItem ri; + FILETIME ft; + NTime::GetCurUtcFileTime(ft); + ri.MTime = ri.ATime = ri.CTime = ft; + ri.Attrib = FILE_ATTRIBUTE_DIRECTORY; + + const UInt32 kSecuritySize = 8; + size_t pos = kSecuritySize; + WriteTree(rootFolder, hashes.Digests, ri, updateItems, NULL, pos); + CByteBuffer meta; + meta.SetCapacity(pos); + // memset(meta, 0, kSecuritySize); + Set32((Byte *)meta, 0); // only if there is no security data, we can use 0 here. + Set32((Byte *)meta + 4, 0); // num security entries + pos = kSecuritySize; + WriteTree(rootFolder, hashes.Digests, ri, updateItems, (Byte *)meta, pos); + + { + NCrypto::NSha1::CContext sha; + sha.Init(); + sha.Update((const Byte *)meta, pos); + CSha1Hash digest; + sha.Final(digest.Hash); + + CStreamInfo s; + s.Resource.PackSize = pos; + s.Resource.Offset = curPos; + s.Resource.UnpackSize = pos; + s.Resource.Flags = NResourceFlags::kMetadata; + s.PartNumber = 1; + s.RefCount = 1; + memcpy(s.Hash, digest.Hash, kHashSize); + streams.Add(s); + RINOK(WriteStream(outStream, (const Byte *)meta, pos)); + meta.Free(); + curPos += pos; + } + + + header.OffsetResource.UnpackSize = header.OffsetResource.PackSize = (UInt64)streams.Size() * kStreamInfoSize; + header.OffsetResource.Offset = curPos; + header.OffsetResource.Flags = NResourceFlags::kMetadata; + + for (i = 0; i < streams.Size(); i++) + { + Byte buf[kStreamInfoSize]; + streams[i].WriteTo(buf); + RINOK(WriteStream(outStream, buf, kStreamInfoSize)); + curPos += kStreamInfoSize; + } + + AString xml = "<WIM>"; + AddTagUInt64(xml, "TOTALBYTES", curPos); + xml += "<IMAGE INDEX=\"1\"><NAME>1</NAME>"; + AddTagUInt64(xml, "DIRCOUNT", rootFolder.GetNumDirs()); + AddTagUInt64(xml, "FILECOUNT", rootFolder.GetNumFiles()); + AddTagUInt64(xml, "TOTALBYTES", unpackTotalSize); + NTime::GetCurUtcFileTime(ft); + AddTag(xml, "CREATIONTIME", TimeToXml(ft)); + AddTag(xml, "LASTMODIFICATIONTIME", TimeToXml(ft)); + xml += "</IMAGE></WIM>"; + + size_t xmlSize = (xml.Length() + 1) * 2; + meta.SetCapacity(xmlSize); + Set16((Byte *)meta, 0xFEFF); + for (i = 0; i < xml.Length(); i++) + Set16((Byte *)meta + 2 + i * 2, xml[i]); + RINOK(WriteStream(outStream, (const Byte *)meta, xmlSize)); + meta.Free(); + + header.XmlResource.UnpackSize = header.XmlResource.PackSize = xmlSize; + header.XmlResource.Offset = curPos; + header.XmlResource.Flags = NResourceFlags::kMetadata; + + outStream->Seek(0, STREAM_SEEK_SET, NULL); + header.WriteTo(buf); + return WriteStream(outStream, buf, kHeaderSizeMax); +} + +STDMETHODIMP COutHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, + IArchiveUpdateCallback *callback) +{ + COM_TRY_BEGIN + CObjectVector<CUpdateItem> updateItems; + CDir tree; + tree.Dirs.Add(CDir()); + CDir &rootFolder = tree.Dirs.Back(); + + for (UInt32 i = 0; i < numItems; i++) + { + CUpdateItem ui; + Int32 newData, newProps; + UInt32 indexInArchive; + if (!callback) + return E_FAIL; + RINOK(callback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArchive)); + + { + NCOM::CPropVariant prop; + RINOK(callback->GetProperty(i, kpidIsDir, &prop)); + if (prop.vt == VT_EMPTY) + ui.IsDir = false; + else if (prop.vt != VT_BOOL) + return E_INVALIDARG; + else + ui.IsDir = (prop.boolVal != VARIANT_FALSE); + } + + { + NCOM::CPropVariant prop; + RINOK(callback->GetProperty(i, kpidAttrib, &prop)); + if (prop.vt == VT_EMPTY) + ui.Attrib = (ui.IsDir ? FILE_ATTRIBUTE_DIRECTORY : 0); + else if (prop.vt != VT_UI4) + return E_INVALIDARG; + else + ui.Attrib = prop.ulVal; + } + + RINOK(GetTime(callback, i, kpidCTime, ui.CTime)); + RINOK(GetTime(callback, i, kpidATime, ui.ATime)); + RINOK(GetTime(callback, i, kpidMTime, ui.MTime)); + + { + NCOM::CPropVariant prop; + RINOK(callback->GetProperty(i, kpidSize, &prop)); + if (prop.vt != VT_UI8) + return E_INVALIDARG; + ui.Size = prop.uhVal.QuadPart; + } + + UString path; + NCOM::CPropVariant prop; + RINOK(callback->GetProperty(i, kpidPath, &prop)); + if (prop.vt == VT_BSTR) + path = prop.bstrVal; + else if (prop.vt != VT_EMPTY) + return E_INVALIDARG; + + CDir *curItem = &rootFolder; + int len = path.Length(); + UString fileName; + for (int j = 0; j < len; j++) + { + wchar_t c = path[j]; + if (c == WCHAR_PATH_SEPARATOR || c == L'/') + { + curItem = curItem->AddDir(updateItems, fileName, -1); + fileName.Empty(); + } + else + fileName += c; + } + + ui.Name = fileName; + updateItems.Add(ui); + if (ui.IsDir) + curItem->AddDir(updateItems, fileName, (int)i); + else + curItem->Files.Add(i); + } + return UpdateArchive(outStream, tree, updateItems, callback); + COM_TRY_END +} + +}} diff --git a/CPP/7zip/Archive/Wim/WimIn.cpp b/CPP/7zip/Archive/Wim/WimIn.cpp index 90c3c2c2..b65b4c44 100755 --- a/CPP/7zip/Archive/Wim/WimIn.cpp +++ b/CPP/7zip/Archive/Wim/WimIn.cpp @@ -18,11 +18,8 @@ #define Get32(p) GetUi32(p) #define Get64(p) GetUi64(p) -namespace NArchive{ -namespace NWim{ - -static const int kChunkSizeBits = 15; -static const UInt32 kChunkSize = (1 << kChunkSizeBits); +namespace NArchive { +namespace NWim { namespace NXpress { @@ -44,7 +41,7 @@ HRESULT CDecoder::CodeSpec(UInt32 outSize) { { Byte levels[kMainTableSize]; - for (int i = 0; i < kMainTableSize; i += 2) + for (unsigned i = 0; i < kMainTableSize; i += 2) { Byte b = m_InBitStream.DirectReadByte(); levels[i] = b & 0xF; @@ -128,12 +125,6 @@ HRESULT CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outS } -static void GetFileTimeFromMem(const Byte *p, FILETIME *ft) -{ - ft->dwLowDateTime = Get32(p); - ft->dwHighDateTime = Get32(p + 4); -} - HRESULT CUnpacker::Unpack(IInStream *inStream, const CResource &resource, bool lzxMode, ISequentialOutStream *outStream, ICompressProgressInfo *progress) { @@ -257,9 +248,6 @@ static HRESULT UnpackData(IInStream *inStream, const CResource &resource, bool l return unpacker.Unpack(inStream, resource, lzxMode, outStream, NULL, digest); } -static const UInt32 kSignatureSize = 8; -static const Byte kSignature[kSignatureSize] = { 'M', 'S', 'W', 'I', 'M', 0, 0, 0 }; - void CResource::Parse(const Byte *p) { Flags = p[7]; @@ -278,19 +266,152 @@ static void GetStream(const Byte *p, CStreamInfo &s) memcpy(s.Hash, p + 30, kHashSize); } -static HRESULT ParseDirItem(const Byte *base, size_t pos, size_t size, - const UString &prefix, CObjectVector<CItem> &items) +static const wchar_t *kLongPath = L"[LongPath]"; + +UString CDatabase::GetItemPath(const int index1) const { - for (;;) + int size = 0; + int index = index1; + int newLevel; + for (newLevel = 0;; newLevel = 1) + { + const CItem &item = Items[index]; + index = item.Parent; + if (index >= 0 || !SkipRoot) + size += item.Name.Length() + newLevel; + if (index < 0) + break; + if ((UInt32)size >= ((UInt32)1 << 16)) + return kLongPath; + } + + wchar_t temp[16]; + int imageLen = 0; + if (ShowImageNumber) { - if (pos + 8 > size) + ConvertUInt32ToString(-1 - index, temp); + imageLen = MyStringLen(temp); + size += imageLen + 1; + } + if ((UInt32)size >= ((UInt32)1 << 16)) + return kLongPath; + + UString path; + wchar_t *s = path.GetBuffer(size); + s[size] = 0; + if (ShowImageNumber) + { + memcpy(s, temp, imageLen * sizeof(wchar_t)); + s[imageLen] = WCHAR_PATH_SEPARATOR; + } + + index = index1; + + for (newLevel = 0;; newLevel = 1) + { + const CItem &item = Items[index]; + index = item.Parent; + if (index >= 0 || !SkipRoot) + { + if (newLevel) + s[--size] = WCHAR_PATH_SEPARATOR; + size -= item.Name.Length(); + memcpy(s + size, item.Name, sizeof(wchar_t) * item.Name.Length()); + } + if (index < 0) + { + path.ReleaseBuffer(); + return path; + } + } +} + +static void GetFileTimeFromMem(const Byte *p, FILETIME *ft) +{ + ft->dwLowDateTime = Get32(p); + ft->dwHighDateTime = Get32(p + 4); +} + +static HRESULT ReadName(const Byte *p, int size, UString &dest) +{ + if (size == 0) + return S_OK; + if (Get16(p + size) != 0) + return S_FALSE; + wchar_t *s = dest.GetBuffer(size / 2); + for (int i = 0; i <= size; i += 2) + *s++ = Get16(p + i); + dest.ReleaseBuffer(); + return S_OK; +} + +HRESULT CDatabase::ParseDirItem(size_t pos, int parent) +{ + if ((pos & 7) != 0) + return S_FALSE; + + int prevIndex = -1; + for (int numItems = 0;; numItems++) + { + if (OpenCallback) + { + UInt64 numFiles = Items.Size(); + if ((numFiles & 0x3FF) == 0) + { + RINOK(OpenCallback->SetCompleted(&numFiles, NULL)); + } + } + size_t rem = DirSize - pos; + if (pos < DirStartOffset || pos > DirSize || rem < 8) return S_FALSE; - const Byte *p = base + pos; - UInt64 length = Get64(p); - if (length == 0) + const Byte *p = DirData + pos; + UInt64 len = Get64(p); + if (len == 0) + { + if (parent < 0 && numItems != 1) + SkipRoot = false; + DirProcessed += 8; return S_OK; - if (pos + 102 > size || pos + length + 8 > size || length > ((UInt64)1 << 62)) + } + if ((len & 7) != 0 || len < 0x28 || rem < len) + return S_FALSE; + DirProcessed += (size_t)len; + if (DirProcessed > DirSize) + return S_FALSE; + if (Get64(p + 8) == 0) + { + if (prevIndex == -1) + return S_FALSE; + + UInt32 fileNameLen = Get16(p + 0x24); + if ((fileNameLen & 1) != 0 || ((0x26 + fileNameLen + 6) & ~7) != len) + return S_FALSE; + + UString name; + RINOK(ReadName(p + 0x26, fileNameLen, name)); + + CItem &prevItem = Items[prevIndex]; + if (name.IsEmpty() && !prevItem.HasStream()) + memcpy(prevItem.Hash, p + 0x10, kHashSize); + else + { + CItem item; + item.Name = prevItem.Name + L':' + name; + item.CTime = prevItem.CTime; + item.ATime = prevItem.ATime; + item.MTime = prevItem.MTime; + memcpy(item.Hash, p + 0x10, kHashSize); + item.Attrib = 0; + item.Order = Order++; + item.Parent = parent; + Items.Add(item); + } + pos += (size_t)len; + continue; + } + if (len < kDirRecordSize) return S_FALSE; + CItem item; item.Attrib = Get32(p + 8); // item.SecurityId = Get32(p + 0xC); @@ -300,43 +421,64 @@ static HRESULT ParseDirItem(const Byte *base, size_t pos, size_t size, GetFileTimeFromMem(p + 0x38, &item.MTime); memcpy(item.Hash, p + 0x40, kHashSize); - // UInt16 shortNameLen = Get16(p + 98); - UInt16 fileNameLen = Get16(p + 100); - - size_t tempPos = pos + 102; - if (tempPos + fileNameLen > size) + UInt32 shortNameLen = Get16(p + 98); + UInt32 fileNameLen = Get16(p + 100); + if ((shortNameLen & 1) != 0 || (fileNameLen & 1) != 0) return S_FALSE; + + UInt32 shortNameLen2 = (shortNameLen == 0 ? shortNameLen : shortNameLen + 2); + UInt32 fileNameLen2 = (fileNameLen == 0 ? fileNameLen : fileNameLen + 2); + + if (((kDirRecordSize + fileNameLen2 + shortNameLen2 + 6) & ~7) > len) + return S_FALSE; + + p += kDirRecordSize; - wchar_t *sz = item.Name.GetBuffer(prefix.Length() + fileNameLen / 2 + 1); - MyStringCopy(sz, (const wchar_t *)prefix); - sz += prefix.Length(); - for (UInt16 i = 0; i + 2 <= fileNameLen; i += 2) - *sz++ = Get16(base + tempPos + i); - *sz++ = '\0'; - item.Name.ReleaseBuffer(); - if (fileNameLen == 0 && item.isDir() && !item.HasStream()) + RINOK(ReadName(p, fileNameLen, item.Name)); + RINOK(ReadName(p + fileNameLen2, shortNameLen, item.ShortName)); + + if (parent < 0 && (shortNameLen || fileNameLen || !item.IsDir())) + SkipRoot = false; + + /* + // there are some extra data for some files. + p -= kDirRecordSize; + p += ((kDirRecordSize + fileNameLen2 + shortNameLen2 + 6) & ~7); + if (((kDirRecordSize + fileNameLen2 + shortNameLen2 + 6) & ~7) != len) + p = p; + */ + + /* + if (parent >= 0) { - item.Attrib = 0x10; // some swm archives have system/hidden attributes for root - item.Name.Delete(item.Name.Length() - 1); + UString s = GetItemPath(parent) + L"\\" + item.Name; + printf("\n%s %8x %S", item.IsDir() ? "D" : " ", (int)subdirOffset, (const wchar_t *)s); } - items.Add(item); - pos += (size_t)length; - if (item.isDir() && (subdirOffset != 0)) + */ + + if (fileNameLen == 0 && item.IsDir() && !item.HasStream()) + item.Attrib = 0x10; // some swm archives have system/hidden attributes for root + + item.Parent = parent; + prevIndex = Items.Add(item); + if (item.IsDir() && subdirOffset != 0) { - if (subdirOffset >= size) - return S_FALSE; - RINOK(ParseDirItem(base, (size_t)subdirOffset, size, item.Name + WCHAR_PATH_SEPARATOR, items)); + RINOK(ParseDirItem((size_t)subdirOffset, prevIndex)); } + Items[prevIndex].Order = Order++; + pos += (size_t)len; } } -static HRESULT ParseDir(const Byte *base, size_t size, - const UString &prefix, CObjectVector<CItem> &items) +HRESULT CDatabase::ParseImageDirs(const CByteBuffer &buf, int parent) { + DirData = buf; + DirSize = buf.GetCapacity(); + size_t pos = 0; - if (pos + 8 > size) + if (DirSize < 8) return S_FALSE; - const Byte *p = base + pos; + const Byte *p = DirData; UInt32 totalLength = Get32(p); // UInt32 numEntries = Get32(p + 4); pos += 8; @@ -346,7 +488,7 @@ static HRESULT ParseDir(const Byte *base, size_t size, UInt64 sum = 0; for (UInt32 i = 0; i < numEntries; i++) { - if (pos + 8 > size) + if (pos + 8 > DirSize) return S_FALSE; UInt64 len = Get64(p + pos); entryLens.Add(len); @@ -359,62 +501,23 @@ static HRESULT ParseDir(const Byte *base, size_t size, if (pos != totalLength) return S_FALSE; */ - pos = totalLength; - } - return ParseDirItem(base, pos, size, prefix, items); -} - -static int CompareHashRefs(const int *p1, const int *p2, void *param) -{ - const CRecordVector<CStreamInfo> &streams = *(const CRecordVector<CStreamInfo> *)param; - return memcmp(streams[*p1].Hash, streams[*p2].Hash, kHashSize); -} - -static int CompareStreamsByPos(const CStreamInfo *p1, const CStreamInfo *p2, void * /* param */) -{ - int res = MyCompare(p1->PartNumber, p2->PartNumber); - if (res != 0) - return res; - return MyCompare(p1->Resource.Offset, p2->Resource.Offset); -} - -int CompareItems(void *const *a1, void *const *a2, void * /* param */) -{ - const CItem &i1 = **((const CItem **)a1); - const CItem &i2 = **((const CItem **)a2); - - if (i1.isDir() != i2.isDir()) - return (i1.isDir()) ? 1 : -1; - if (i1.isDir()) - return -MyStringCompareNoCase(i1.Name, i2.Name); - - int res = MyCompare(i1.StreamIndex, i2.StreamIndex); - if (res != 0) - return res; - return MyStringCompareNoCase(i1.Name, i2.Name); -} - -static int FindHash(const CRecordVector<CStreamInfo> &streams, - const CRecordVector<int> &sortedByHash, const Byte *hash) -{ - int left = 0, right = streams.Size(); - while (left != right) - { - int mid = (left + right) / 2; - int streamIndex = sortedByHash[mid]; - UInt32 i; - const Byte *hash2 = streams[streamIndex].Hash; - for (i = 0; i < kHashSize; i++) - if (hash[i] != hash2[i]) - break; - if (i == kHashSize) - return streamIndex; - if (hash[i] < hash2[i]) - right = mid; + if (totalLength == 0) + pos = 8; + else if (totalLength < 8) + return S_FALSE; else - left = mid + 1; + pos = totalLength; } - return -1; + DirStartOffset = DirProcessed = pos; + RINOK(ParseDirItem(pos, parent)); + if (DirProcessed == DirSize) + return S_OK; + /* Original program writes additional 8 bytes (END_OF_ROOT_FOLDER), but + reference to that folder is empty */ + if (DirProcessed == DirSize - 8 && DirProcessed - DirStartOffset == 112 && + Get64(p + DirSize - 8) == 0) + return S_OK; + return S_FALSE; } HRESULT CHeader::Parse(const Byte *p) @@ -426,8 +529,8 @@ HRESULT CHeader::Parse(const Byte *p) Flags = Get32(p + 0x10); if (!IsSupported()) return S_FALSE; - UInt32 chunkSize = Get32(p + 0x14); - if (chunkSize != kChunkSize && chunkSize != 0) + ChunkSize = Get32(p + 0x14); + if (ChunkSize != kChunkSize && ChunkSize != 0) return S_FALSE; memcpy(Guid, p + 0x18, 16); PartNumber = Get16(p + 0x28); @@ -441,21 +544,20 @@ HRESULT CHeader::Parse(const Byte *p) GetResource(p + offset, OffsetResource); GetResource(p + offset + 0x18, XmlResource); GetResource(p + offset + 0x30, MetadataResource); - /* if (IsNewVersion()) { if (haderSize < 0xD0) return S_FALSE; - IntegrityResource.Parse(p + offset + 0x4C); BootIndex = Get32(p + 0x48); + IntegrityResource.Parse(p + offset + 0x4C); } - */ return S_OK; } +const Byte kSignature[kSignatureSize] = { 'M', 'S', 'W', 'I', 'M', 0, 0, 0 }; + HRESULT ReadHeader(IInStream *inStream, CHeader &h) { - const UInt32 kHeaderSizeMax = 0xD0; Byte p[kHeaderSizeMax]; RINOK(ReadStream_FALSE(inStream, p, kHeaderSizeMax)); if (memcmp(p, kSignature, kSignatureSize) != 0) @@ -463,33 +565,35 @@ HRESULT ReadHeader(IInStream *inStream, CHeader &h) return h.Parse(p); } -HRESULT ReadStreams(IInStream *inStream, const CHeader &h, CDatabase &db) +static HRESULT ReadStreams(IInStream *inStream, const CHeader &h, CDatabase &db) { CByteBuffer offsetBuf; RINOK(UnpackData(inStream, h.OffsetResource, h.IsLzxMode(), offsetBuf, NULL)); - for (size_t i = 0; i + kStreamInfoSize <= offsetBuf.GetCapacity(); i += kStreamInfoSize) + size_t i; + for (i = 0; offsetBuf.GetCapacity() - i >= kStreamInfoSize; i += kStreamInfoSize) { CStreamInfo s; GetStream((const Byte *)offsetBuf + i, s); if (s.PartNumber == h.PartNumber) db.Streams.Add(s); } - return S_OK; + return (i == offsetBuf.GetCapacity()) ? S_OK : S_FALSE; } -HRESULT OpenArchive(IInStream *inStream, const CHeader &h, CByteBuffer &xml, CDatabase &db) +HRESULT CDatabase::Open(IInStream *inStream, const CHeader &h, CByteBuffer &xml, IArchiveOpenCallback *openCallback) { + OpenCallback = openCallback; RINOK(UnpackData(inStream, h.XmlResource, h.IsLzxMode(), xml, NULL)); - - RINOK(ReadStreams(inStream, h, db)); + RINOK(ReadStreams(inStream, h, *this)); bool needBootMetadata = !h.MetadataResource.IsEmpty(); + Order = 0; if (h.PartNumber == 1) { int imageIndex = 1; - for (int j = 0; j < db.Streams.Size(); j++) + for (int i = 0; i < Streams.Size(); i++) { // if (imageIndex > 1) break; - const CStreamInfo &si = db.Streams[j]; + const CStreamInfo &si = Streams[i]; if (!si.Resource.IsMetadata() || si.PartNumber != h.PartNumber) continue; Byte hash[kHashSize]; @@ -497,11 +601,8 @@ HRESULT OpenArchive(IInStream *inStream, const CHeader &h, CByteBuffer &xml, CDa RINOK(UnpackData(inStream, si.Resource, h.IsLzxMode(), metadata, hash)); if (memcmp(hash, si.Hash, kHashSize) != 0) return S_FALSE; - wchar_t sz[16]; - ConvertUInt32ToString(imageIndex++, sz); - UString s = sz; - s += WCHAR_PATH_SEPARATOR; - RINOK(ParseDir(metadata, metadata.GetCapacity(), s, db.Items)); + NumImages++; + RINOK(ParseImageDirs(metadata, -(int)(++imageIndex))); if (needBootMetadata) if (h.MetadataResource.Offset == si.Resource.Offset) needBootMetadata = false; @@ -512,58 +613,114 @@ HRESULT OpenArchive(IInStream *inStream, const CHeader &h, CByteBuffer &xml, CDa { CByteBuffer metadata; RINOK(UnpackData(inStream, h.MetadataResource, h.IsLzxMode(), metadata, NULL)); - RINOK(ParseDir(metadata, metadata.GetCapacity(), L"0" WSTRING_PATH_SEPARATOR, db.Items)); + RINOK(ParseImageDirs(metadata, -1)); + NumImages++; } return S_OK; } -HRESULT SortDatabase(CDatabase &db) +static int CompareStreamsByPos(const CStreamInfo *p1, const CStreamInfo *p2, void * /* param */) { - db.Streams.Sort(CompareStreamsByPos, NULL); + int res = MyCompare(p1->PartNumber, p2->PartNumber); + if (res != 0) + return res; + return MyCompare(p1->Resource.Offset, p2->Resource.Offset); +} + +static int CompareHashRefs(const int *p1, const int *p2, void *param) +{ + const CRecordVector<CStreamInfo> &streams = *(const CRecordVector<CStreamInfo> *)param; + return memcmp(streams[*p1].Hash, streams[*p2].Hash, kHashSize); +} + +static int FindHash(const CRecordVector<CStreamInfo> &streams, + const CIntVector &sortedByHash, const Byte *hash) +{ + int left = 0, right = streams.Size(); + while (left != right) + { + int mid = (left + right) / 2; + int streamIndex = sortedByHash[mid]; + UInt32 i; + const Byte *hash2 = streams[streamIndex].Hash; + for (i = 0; i < kHashSize; i++) + if (hash[i] != hash2[i]) + break; + if (i == kHashSize) + return streamIndex; + if (hash[i] < hash2[i]) + right = mid; + else + left = mid + 1; + } + return -1; +} + +static int CompareItems(const int *a1, const int *a2, void *param) +{ + const CObjectVector<CItem> &items = ((CDatabase *)param)->Items; + const CItem &i1 = items[*a1]; + const CItem &i2 = items[*a2]; + + if (i1.IsDir() != i2.IsDir()) + return i1.IsDir() ? 1 : -1; + int res = MyCompare(i1.StreamIndex, i2.StreamIndex); + if (res != 0) + return res; + return MyCompare(i1.Order, i2.Order); +} + +HRESULT CDatabase::Sort(bool skipRootDir) +{ + Streams.Sort(CompareStreamsByPos, NULL); { - CRecordVector<int> sortedByHash; + CIntVector sortedByHash; { - for (int j = 0; j < db.Streams.Size(); j++) - sortedByHash.Add(j); - sortedByHash.Sort(CompareHashRefs, &db.Streams); + for (int i = 0; i < Streams.Size(); i++) + sortedByHash.Add(i); + sortedByHash.Sort(CompareHashRefs, &Streams); } - for (int i = 0; i < db.Items.Size(); i++) + for (int i = 0; i < Items.Size(); i++) { - CItem &item = db.Items[i]; + CItem &item = Items[i]; item.StreamIndex = -1; if (item.HasStream()) - item.StreamIndex = FindHash(db.Streams, sortedByHash, item.Hash); + item.StreamIndex = FindHash(Streams, sortedByHash, item.Hash); } } { CRecordVector<bool> used; - int j; - for (j = 0; j < db.Streams.Size(); j++) + int i; + for (i = 0; i < Streams.Size(); i++) { - const CStreamInfo &s = db.Streams[j]; + const CStreamInfo &s = Streams[i]; used.Add(s.Resource.IsMetadata() && s.PartNumber == 1); + // used.Add(false); } - for (int i = 0; i < db.Items.Size(); i++) + for (i = 0; i < Items.Size(); i++) { - CItem &item = db.Items[i]; + CItem &item = Items[i]; if (item.StreamIndex >= 0) used[item.StreamIndex] = true; } - for (j = 0; j < db.Streams.Size(); j++) - if (!used[j]) + for (i = 0; i < Streams.Size(); i++) + if (!used[i]) { CItem item; - item.StreamIndex = j; + item.StreamIndex = i; item.HasMetadata = false; - db.Items.Add(item); - } + Items.Add(item); + } } - - db.Items.Sort(CompareItems, NULL); + + SortedItems.Reserve(Items.Size()); + for (int i = (skipRootDir ? 1 : 0); i < Items.Size(); i++) + SortedItems.Add(i); + SortedItems.Sort(CompareItems, this); return S_OK; } diff --git a/CPP/7zip/Archive/Wim/WimIn.h b/CPP/7zip/Archive/Wim/WimIn.h index e51a301a..5bca71db 100755 --- a/CPP/7zip/Archive/Wim/WimIn.h +++ b/CPP/7zip/Archive/Wim/WimIn.h @@ -9,6 +9,8 @@ #include "../../Compress/CopyCoder.h" #include "../../Compress/LzxDecoder.h" +#include "../IArchive.h" + namespace NArchive { namespace NWim { @@ -56,7 +58,7 @@ public: } }; -const int kNumHuffmanBits = 16; +const unsigned kNumHuffmanBits = 16; const UInt32 kMatchMinLen = 3; const UInt32 kNumLenSlots = 16; const UInt32 kNumPosSlots = 16; @@ -85,8 +87,10 @@ public: namespace NResourceFlags { - const Byte Compressed = 4; + const Byte kFree = 1; const Byte kMetadata = 2; + const Byte Compressed = 4; + const Byte Spanned = 4; } struct CResource @@ -96,9 +100,18 @@ struct CResource UInt64 UnpackSize; Byte Flags; + void Clear() + { + PackSize = 0; + Offset = 0; + UnpackSize = 0; + Flags = 0; + } void Parse(const Byte *p); - bool IsCompressed() const { return (Flags & NResourceFlags::Compressed) != 0; } + void WriteTo(Byte *p) const; + bool IsFree() const { return (Flags & NResourceFlags::kFree) != 0; } bool IsMetadata() const { return (Flags & NResourceFlags::kMetadata) != 0; } + bool IsCompressed() const { return (Flags & NResourceFlags::Compressed) != 0; } bool IsEmpty() const { return (UnpackSize == 0); } }; @@ -111,30 +124,37 @@ namespace NHeaderFlags const UInt32 kLZX = 0x40000; } +const UInt32 kWimVersion = 0x010D00; +const UInt32 kHeaderSizeMax = 0xD0; +const UInt32 kSignatureSize = 8; +extern const Byte kSignature[kSignatureSize]; +const unsigned kChunkSizeBits = 15; +const UInt32 kChunkSize = (1 << kChunkSizeBits); + struct CHeader { - UInt32 Flags; UInt32 Version; - // UInt32 ChunkSize; + UInt32 Flags; + UInt32 ChunkSize; + Byte Guid[16]; UInt16 PartNumber; UInt16 NumParts; UInt32 NumImages; - Byte Guid[16]; CResource OffsetResource; CResource XmlResource; CResource MetadataResource; - /* CResource IntegrityResource; UInt32 BootIndex; - */ + void SetDefaultFields(bool useLZX); + + void WriteTo(Byte *p) const; HRESULT Parse(const Byte *p); bool IsCompressed() const { return (Flags & NHeaderFlags::kCompression) != 0; } bool IsSupported() const { return (!IsCompressed() || (Flags & NHeaderFlags::kLZX) != 0 || (Flags & NHeaderFlags::kXPRESS) != 0 ) ; } bool IsLzxMode() const { return (Flags & NHeaderFlags::kLZX) != 0; } bool IsSpanned() const { return (!IsCompressed() || (Flags & NHeaderFlags::kSpanned) != 0); } - bool IsNewVersion()const { return (Version > 0x010C00); } bool AreFromOnArchive(const CHeader &h) @@ -152,11 +172,16 @@ struct CStreamInfo UInt16 PartNumber; UInt32 RefCount; BYTE Hash[kHashSize]; + + void WriteTo(Byte *p) const; }; +const UInt32 kDirRecordSize = 102; + struct CItem { UString Name; + UString ShortName; UInt32 Attrib; // UInt32 SecurityId; BYTE Hash[kHashSize]; @@ -168,22 +193,39 @@ struct CItem // UInt16 NumStreams; // UInt16 ShortNameLen; int StreamIndex; + int Parent; + unsigned Order; bool HasMetadata; CItem(): HasMetadata(true), StreamIndex(-1) {} - bool isDir() const { return HasMetadata && ((Attrib & 0x10) != 0); } + bool IsDir() const { return HasMetadata && ((Attrib & 0x10) != 0); } bool HasStream() const { - for (int i = 0; i < kHashSize; i++) + for (unsigned i = 0; i < kHashSize; i++) if (Hash[i] != 0) return true; return false; } }; -struct CDatabase +class CDatabase { + const Byte *DirData; + size_t DirSize; + size_t DirProcessed; + size_t DirStartOffset; + int Order; + IArchiveOpenCallback *OpenCallback; + + HRESULT ParseDirItem(size_t pos, int parent); + HRESULT ParseImageDirs(const CByteBuffer &buf, int parent); + +public: CRecordVector<CStreamInfo> Streams; CObjectVector<CItem> Items; + CIntVector SortedItems; + int NumImages; + bool SkipRoot; + bool ShowImageNumber; UInt64 GetUnpackSize() const { @@ -205,12 +247,26 @@ struct CDatabase { Streams.Clear(); Items.Clear(); + SortedItems.Clear(); + NumImages = 0; + + SkipRoot = true; + ShowImageNumber = true; } + + UString GetItemPath(int index) const; + + HRESULT Open(IInStream *inStream, const CHeader &h, CByteBuffer &xml, IArchiveOpenCallback *openCallback); + + void DetectPathMode() + { + ShowImageNumber = (NumImages != 1); + } + + HRESULT Sort(bool skipRootDir); }; HRESULT ReadHeader(IInStream *inStream, CHeader &header); -HRESULT OpenArchive(IInStream *inStream, const CHeader &header, CByteBuffer &xml, CDatabase &database); -HRESULT SortDatabase(CDatabase &database); class CUnpacker { diff --git a/CPP/7zip/Archive/Wim/WimRegister.cpp b/CPP/7zip/Archive/Wim/WimRegister.cpp index 3c8e216f..8da91436 100755 --- a/CPP/7zip/Archive/Wim/WimRegister.cpp +++ b/CPP/7zip/Archive/Wim/WimRegister.cpp @@ -6,8 +6,13 @@ #include "WimHandler.h" static IInArchive *CreateArc() { return new NArchive::NWim::CHandler; } +#ifndef EXTRACT_ONLY +static IOutArchive *CreateArcOut() { return new NArchive::NWim::COutHandler; } +#else +#define CreateArcOut 0 +#endif static CArcInfo g_ArcInfo = - { L"Wim", L"wim swm", 0, 0xE6, { 'M', 'S', 'W', 'I', 'M', 0, 0, 0 }, 8, false, CreateArc, 0 }; + { L"wim", L"wim swm", 0, 0xE6, { 'M', 'S', 'W', 'I', 'M', 0, 0, 0 }, 8, false, CreateArc, CreateArcOut }; REGISTER_ARC(Wim) diff --git a/CPP/7zip/Archive/Zip/ZipHandler.h b/CPP/7zip/Archive/Zip/ZipHandler.h index 68dd60dc..fdb60aaf 100755 --- a/CPP/7zip/Archive/Zip/ZipHandler.h +++ b/CPP/7zip/Archive/Zip/ZipHandler.h @@ -63,8 +63,8 @@ private: Byte m_AesKeyMode; bool m_WriteNtfsTimeExtra; - bool m_ForseLocal; - bool m_ForseUtf8; + bool m_ForceLocal; + bool m_ForceUtf8; #ifndef _7ZIP_ST UInt32 _numThreads; @@ -88,8 +88,8 @@ private: m_IsAesMode = false; m_AesKeyMode = 3; // aes-256 m_WriteNtfsTimeExtra = true; - m_ForseLocal = false; - m_ForseUtf8 = false; + m_ForceLocal = false; + m_ForceUtf8 = false; #ifndef _7ZIP_ST _numThreads = NWindows::NSystem::GetNumberOfProcessors();; #endif diff --git a/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp b/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp index fa7a4480..a5e0f59d 100755 --- a/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp +++ b/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp @@ -189,11 +189,11 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt name += kSlash; bool tryUtf8 = true; - if (m_ForseLocal || !m_ForseUtf8) + if (m_ForceLocal || !m_ForceUtf8) { bool defaultCharWasUsed; ui.Name = UnicodeStringToMultiByte(name, CP_OEMCP, '_', defaultCharWasUsed); - tryUtf8 = (!m_ForseLocal && (defaultCharWasUsed || + tryUtf8 = (!m_ForceLocal && (defaultCharWasUsed || MultiByteToUnicodeString(ui.Name, CP_OEMCP) != name)); } @@ -512,15 +512,15 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *v } else if (name.CompareNoCase(L"CL") == 0) { - RINOK(SetBoolProperty(m_ForseLocal, prop)); - if (m_ForseLocal) - m_ForseUtf8 = false; + RINOK(SetBoolProperty(m_ForceLocal, prop)); + if (m_ForceLocal) + m_ForceUtf8 = false; } else if (name.CompareNoCase(L"CU") == 0) { - RINOK(SetBoolProperty(m_ForseUtf8, prop)); - if (m_ForseUtf8) - m_ForseLocal = false; + RINOK(SetBoolProperty(m_ForceUtf8, prop)); + if (m_ForceUtf8) + m_ForceLocal = false; } else return E_INVALIDARG; diff --git a/CPP/7zip/Bundles/Alone/makefile b/CPP/7zip/Bundles/Alone/makefile index 9dd02872..862d695a 100755 --- a/CPP/7zip/Bundles/Alone/makefile +++ b/CPP/7zip/Bundles/Alone/makefile @@ -97,7 +97,6 @@ AR_OBJS = \ $O\DeflateProps.obj \ $O\GzHandler.obj \ $O\LzmaHandler.obj \ - $O\PpmdHandler.obj \ $O\SplitHandler.obj \ $O\XzHandler.obj \ $O\ZHandler.obj \ diff --git a/CPP/7zip/Bundles/Fm/makefile b/CPP/7zip/Bundles/Fm/makefile index 8b01a739..74703a99 100755 --- a/CPP/7zip/Bundles/Fm/makefile +++ b/CPP/7zip/Bundles/Fm/makefile @@ -322,6 +322,7 @@ UDF_OBJS = \ WIM_OBJS = \ $O\WimHandler.obj \ + $O\WimHandlerOut.obj \ $O\WimIn.obj \ $O\WimRegister.obj \ diff --git a/CPP/7zip/Bundles/Format7zF/Format7z.dsp b/CPP/7zip/Bundles/Format7zF/Format7z.dsp index 4be37b86..4b24d0b9 100755 --- a/CPP/7zip/Bundles/Format7zF/Format7z.dsp +++ b/CPP/7zip/Bundles/Format7zF/Format7z.dsp @@ -2229,6 +2229,10 @@ SOURCE=..\..\Archive\Wim\WimHandler.h # End Source File # Begin Source File +SOURCE=..\..\Archive\Wim\WimHandlerOut.cpp +# End Source File +# Begin Source File + SOURCE=..\..\Archive\Wim\WimIn.cpp # End Source File # Begin Source File diff --git a/CPP/7zip/Bundles/Format7zF/makefile b/CPP/7zip/Bundles/Format7zF/makefile index b72468c0..5afa115e 100755 --- a/CPP/7zip/Bundles/Format7zF/makefile +++ b/CPP/7zip/Bundles/Format7zF/makefile @@ -173,6 +173,7 @@ UDF_OBJS = \ WIM_OBJS = \ $O\WimHandler.obj \ + $O\WimHandlerOut.obj \ $O\WimIn.obj \ $O\WimRegister.obj \ diff --git a/CPP/7zip/MyVersion.h b/CPP/7zip/MyVersion.h index 337e5725..d46b673b 100755 --- a/CPP/7zip/MyVersion.h +++ b/CPP/7zip/MyVersion.h @@ -1,8 +1,8 @@ #define MY_VER_MAJOR 9 -#define MY_VER_MINOR 13 +#define MY_VER_MINOR 14 #define MY_VER_BUILD 0 -#define MY_VERSION "9.13 beta" -#define MY_7ZIP_VERSION "7-Zip 9.13 beta" -#define MY_DATE "2010-04-15" +#define MY_VERSION "9.14 beta" +#define MY_7ZIP_VERSION "7-Zip 9.14 beta" +#define MY_DATE "2010-06-04" #define MY_COPYRIGHT "Copyright (c) 1999-2010 Igor Pavlov" #define MY_VERSION_COPYRIGHT_DATE MY_VERSION " " MY_COPYRIGHT " " MY_DATE diff --git a/CPP/7zip/UI/Common/PropIDUtils.cpp b/CPP/7zip/UI/Common/PropIDUtils.cpp index d8c0e7d6..daa57ef6 100755 --- a/CPP/7zip/UI/Common/PropIDUtils.cpp +++ b/CPP/7zip/UI/Common/PropIDUtils.cpp @@ -24,6 +24,27 @@ void ConvertUInt32ToHex(UInt32 value, wchar_t *s) s[8] = L'\0'; } +static const char g_WinAttrib[17] = "RHS8DAdNTsrCOnE_"; +/* +0 READONLY +1 HIDDEN +3 SYSTEM + +4 DIRECTORY +5 ARCHIVE +6 DEVICE +7 NORMAL +8 TEMPORARY +9 SPARSE_FILE +10 REPARSE_POINT +11 COMPRESSED +12 OFFLINE +13 NOT_CONTENT_INDEXED +14 ENCRYPTED + +16 VIRTUAL +*/ + #define MY_ATTR_CHAR(a, n, c) ((a )& (1 << (n))) ? c : L'-'; UString ConvertPropertyToString(const PROPVARIANT &prop, PROPID propID, bool full) @@ -55,16 +76,14 @@ UString ConvertPropertyToString(const PROPVARIANT &prop, PROPID propID, bool ful { if (prop.vt != VT_UI4) break; - UString res; UInt32 a = prop.ulVal; - if (NFile::NFind::NAttributes::IsReadOnly(a)) res += L'R'; - if (NFile::NFind::NAttributes::IsHidden(a)) res += L'H'; - if (NFile::NFind::NAttributes::IsSystem(a)) res += L'S'; - if (NFile::NFind::NAttributes::IsDir(a)) res += L'D'; - if (NFile::NFind::NAttributes::IsArchived(a)) res += L'A'; - if (NFile::NFind::NAttributes::IsCompressed(a)) res += L'C'; - if (NFile::NFind::NAttributes::IsEncrypted(a)) res += L'E'; - return res; + wchar_t sz[32]; + int pos = 0; + for (int i = 0; i < 16; i++) + if (a & (1 << i) && i != 7) + sz[pos++] = g_WinAttrib[i]; + sz[pos] = '\0'; + return sz; } case kpidPosixAttrib: { diff --git a/CPP/7zip/UI/Console/UserInputUtils.cpp b/CPP/7zip/UI/Console/UserInputUtils.cpp index 0e55a868..bae33478 100755 --- a/CPP/7zip/UI/Console/UserInputUtils.cpp +++ b/CPP/7zip/UI/Console/UserInputUtils.cpp @@ -26,6 +26,7 @@ NUserAnswerMode::EEnum ScanUserYesNoAllQuit(CStdOutStream *outStream) for (;;) { (*outStream) << kHelpQuestionMessage; + outStream->Flush(); AString scannedString = g_StdIn.ScanStringUntilNewLine(); scannedString.Trim(); if (!scannedString.IsEmpty()) diff --git a/CPP/7zip/UI/FileManager/PanelItemOpen.cpp b/CPP/7zip/UI/FileManager/PanelItemOpen.cpp index 15e01483..12206786 100755 --- a/CPP/7zip/UI/FileManager/PanelItemOpen.cpp +++ b/CPP/7zip/UI/FileManager/PanelItemOpen.cpp @@ -163,40 +163,51 @@ HRESULT CPanel::OpenParentArchiveFolder() return S_OK; } -static const wchar_t *kStartExtensions[] = -{ +static const char *kStartExtensions = #ifdef UNDER_CE - L"cab", + " cab" #endif - L"exe", L"bat", L"com", - L"chm", - L"msi", L"doc", L"xls", L"ppt", L"pps", L"wps", L"wpt", L"wks", L"xlr", L"wdb", + " exe bat com" + " chm" + " msi doc xls ppt pps wps wpt wks xlr wdb" - L"docx", L"docm", L"dotx", L"dotm", L"xlsx", L"xlsm", L"xltx", L"xltm", L"xlsb", - L"xlam", L"pptx", L"pptm", L"potx", L"potm", L"ppam", L"ppsx", L"ppsm", L"xsn", - L"msg", - L"dwf", + " docx docm dotx dotm xlsx xlsm xltx xltm xlsb" + " xlam pptx pptm potx potm ppam ppsx ppsm xsn" + " mpp" + " msg" + " dwf" - L"flv", L"swf", + " flv swf" - L"odt", L"ods", - L"wb3", - L"pdf" -}; + " odt ods" + " wb3" + " pdf" + " "; -static bool DoItemAlwaysStart(const UString &name) +static bool FindExt(const char *p, const UString &name) { int extPos = name.ReverseFind('.'); if (extPos < 0) return false; UString ext = name.Mid(extPos + 1); ext.MakeLower(); - for (int i = 0; i < sizeof(kStartExtensions) / sizeof(kStartExtensions[0]); i++) - if (ext.Compare(kStartExtensions[i]) == 0) + AString ext2 = UnicodeStringToMultiByte(ext); + for (int i = 0; p[i] != 0;) + { + int j; + for (j = i; p[j] != ' '; j++); + if (ext2.Length() == j - i && memcmp(p + i, (const char *)ext2, ext2.Length()) == 0) return true; + i = j + 1; + } return false; } +static bool DoItemAlwaysStart(const UString &name) +{ + return FindExt(kStartExtensions, name); +} + static UString GetQuotedString(const UString &s) { return UString(L'\"') + s + UString(L'\"'); diff --git a/CPP/7zip/UI/GUI/CompressDialog.cpp b/CPP/7zip/UI/GUI/CompressDialog.cpp index 75a1f9ed..25c20c29 100755 --- a/CPP/7zip/UI/GUI/CompressDialog.cpp +++ b/CPP/7zip/UI/GUI/CompressDialog.cpp @@ -229,6 +229,12 @@ static const CFormatInfo g_Formats[] = (1 << 0), 0, 0, false, false, false, false, false, false + }, + { + L"wim", + (1 << 0), + 0, 0, + false, false, false, false, false, false } }; @@ -1032,7 +1038,7 @@ void CCompressDialog::SetDictionary() if (i == 20 && j > 0) continue; UInt32 dictionary = (1 << i) + (j << (i - 1)); - if (dictionary >= (1 << 31)) + if (dictionary > (1 << 30)) continue; AddDictionarySize(dictionary); UInt64 decomprSize; |