From f6444c32568553e0261ca0105083658f12be6284 Mon Sep 17 00:00:00 2001 From: Igor Pavlov Date: Tue, 22 Sep 2015 00:00:00 +0000 Subject: 15.07 --- CPP/7zip/Archive/7z/7zHandlerOut.cpp | 3 +- CPP/7zip/Archive/7z/7zUpdate.cpp | 8 +- CPP/7zip/Archive/ApmHandler.cpp | 88 +- CPP/7zip/Archive/Cab/CabBlockInStream.cpp | 11 +- CPP/7zip/Archive/Cab/CabBlockInStream.h | 6 + CPP/7zip/Archive/Cab/CabHandler.cpp | 125 ++- CPP/7zip/Archive/Chm/ChmHandler.cpp | 80 +- CPP/7zip/Archive/Chm/ChmIn.cpp | 150 ++-- CPP/7zip/Archive/Chm/ChmIn.h | 47 +- CPP/7zip/Archive/DmgHandler.cpp | 4 +- CPP/7zip/Archive/ElfHandler.cpp | 48 +- CPP/7zip/Archive/GptHandler.cpp | 386 ++++++++ CPP/7zip/Archive/HandlerCont.cpp | 230 +++++ CPP/7zip/Archive/HandlerCont.h | 90 ++ CPP/7zip/Archive/MachoHandler.cpp | 2 +- CPP/7zip/Archive/MbrHandler.cpp | 104 +-- CPP/7zip/Archive/MubHandler.cpp | 87 +- CPP/7zip/Archive/NtfsHandler.cpp | 4 +- CPP/7zip/Archive/QcowHandler.cpp | 611 +++++++++++++ CPP/7zip/Archive/Rar/RarVol.h | 94 +- CPP/7zip/Archive/RpmHandler.cpp | 64 +- CPP/7zip/Archive/Tar/TarRegister.cpp | 2 +- CPP/7zip/Archive/VdiHandler.cpp | 362 ++++++++ CPP/7zip/Archive/VhdHandler.cpp | 135 +-- CPP/7zip/Archive/VmdkHandler.cpp | 890 ++++++++++++++++++ CPP/7zip/Archive/Wim/WimHandler.cpp | 264 ++++-- CPP/7zip/Archive/Wim/WimHandler.h | 23 + CPP/7zip/Archive/Wim/WimHandlerOut.cpp | 291 ++++-- CPP/7zip/Archive/Wim/WimIn.cpp | 1191 ++++++++++++++++++------- CPP/7zip/Archive/Wim/WimIn.h | 345 ++++--- CPP/7zip/Archive/Wim/WimRegister.cpp | 2 +- CPP/7zip/Archive/XzHandler.cpp | 10 +- CPP/7zip/Archive/Zip/ZipUpdate.cpp | 94 +- CPP/7zip/Archive/Zip/ZipUpdate.h | 2 +- CPP/7zip/Bundles/Alone/Alone.dsp | 8 - CPP/7zip/Bundles/Alone/makefile | 1 - CPP/7zip/Bundles/Format7zF/Arc.mak | 8 +- CPP/7zip/Bundles/Format7zF/Format7z.dsp | 76 +- CPP/7zip/Compress/BZip2Decoder.cpp | 4 +- CPP/7zip/Compress/DeflateDecoder.cpp | 93 +- CPP/7zip/Compress/DeflateDecoder.h | 4 +- CPP/7zip/Compress/HuffmanDecoder.h | 247 ++++- CPP/7zip/Compress/LzhDecoder.cpp | 10 +- CPP/7zip/Compress/LzmsDecoder.cpp | 573 ++++++++++++ CPP/7zip/Compress/LzmsDecoder.h | 271 ++++++ CPP/7zip/Compress/Lzx.h | 68 +- CPP/7zip/Compress/Lzx86Converter.cpp | 90 -- CPP/7zip/Compress/Lzx86Converter.h | 45 - CPP/7zip/Compress/LzxDecoder.cpp | 626 ++++++++----- CPP/7zip/Compress/LzxDecoder.h | 249 ++++-- CPP/7zip/Compress/QuantumDecoder.cpp | 225 ++--- CPP/7zip/Compress/QuantumDecoder.h | 228 ++--- CPP/7zip/Compress/Rar2Decoder.cpp | 74 +- CPP/7zip/Compress/Rar3Decoder.cpp | 80 +- CPP/7zip/Compress/Rar5Decoder.cpp | 21 +- CPP/7zip/Compress/XpressDecoder.cpp | 129 +++ CPP/7zip/Compress/XpressDecoder.h | 13 + CPP/7zip/Guid.txt | 4 + CPP/7zip/UI/Agent/Agent.cpp | 3 + CPP/7zip/UI/Agent/Agent.h | 16 +- CPP/7zip/UI/Common/ArchiveExtractCallback.cpp | 22 +- CPP/7zip/UI/Common/ExtractingFilePath.cpp | 8 +- CPP/7zip/UI/Common/OpenArchive.h | 2 + CPP/7zip/UI/Console/Main.cpp | 2 +- CPP/7zip/UI/Console/OpenCallbackConsole.cpp | 4 +- CPP/7zip/UI/Console/OpenCallbackConsole.h | 4 +- CPP/7zip/UI/Far/Far.cpp | 15 +- CPP/7zip/UI/Far/FarUtils.cpp | 33 +- CPP/7zip/UI/FileManager/App.h | 2 +- CPP/7zip/UI/FileManager/ExtractCallback.cpp | 40 +- CPP/7zip/UI/FileManager/ExtractCallback.h | 11 +- CPP/7zip/UI/FileManager/LinkDialogRes.h | 8 +- CPP/7zip/UI/FileManager/MyLoadMenu.cpp | 34 +- CPP/7zip/UI/FileManager/Panel.h | 12 +- CPP/7zip/UI/FileManager/PanelItemOpen.cpp | 97 +- CPP/7zip/UI/FileManager/PanelItems.cpp | 18 +- CPP/7zip/UI/FileManager/PanelListNotify.cpp | 11 + CPP/7zip/UI/FileManager/resource.h | 3 + CPP/7zip/UI/FileManager/resource.rc | 2 + CPP/7zip/UI/GUI/ExtractDialogRes.h | 2 +- CPP/7zip/UI/GUI/GUI.cpp | 2 + CPP/7zip/UI/GUI/resource3.h | 14 +- 82 files changed, 7085 insertions(+), 2280 deletions(-) create mode 100644 CPP/7zip/Archive/GptHandler.cpp create mode 100644 CPP/7zip/Archive/HandlerCont.cpp create mode 100644 CPP/7zip/Archive/HandlerCont.h create mode 100644 CPP/7zip/Archive/QcowHandler.cpp create mode 100644 CPP/7zip/Archive/VdiHandler.cpp create mode 100644 CPP/7zip/Archive/VmdkHandler.cpp create mode 100644 CPP/7zip/Compress/LzmsDecoder.cpp create mode 100644 CPP/7zip/Compress/LzmsDecoder.h delete mode 100644 CPP/7zip/Compress/Lzx86Converter.cpp delete mode 100644 CPP/7zip/Compress/Lzx86Converter.h create mode 100644 CPP/7zip/Compress/XpressDecoder.cpp create mode 100644 CPP/7zip/Compress/XpressDecoder.h (limited to 'CPP/7zip') diff --git a/CPP/7zip/Archive/7z/7zHandlerOut.cpp b/CPP/7zip/Archive/7z/7zHandlerOut.cpp index 7ece4c68..41bd6520 100644 --- a/CPP/7zip/Archive/7z/7zHandlerOut.cpp +++ b/CPP/7zip/Archive/7z/7zHandlerOut.cpp @@ -282,7 +282,8 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt bool need_CTime = (Write_CTime.Def && Write_CTime.Val); bool need_ATime = (Write_ATime.Def && Write_ATime.Val); bool need_MTime = (Write_MTime.Def && Write_MTime.Val || !Write_MTime.Def); - if (db) + + if (db && !db->Files.IsEmpty()) { if (!Write_CTime.Def) need_CTime = !db->CTime.Defs.IsEmpty(); if (!Write_ATime.Def) need_ATime = !db->ATime.Defs.IsEmpty(); diff --git a/CPP/7zip/Archive/7z/7zUpdate.cpp b/CPP/7zip/Archive/7z/7zUpdate.cpp index 345cd627..c2478a29 100644 --- a/CPP/7zip/Archive/7z/7zUpdate.cpp +++ b/CPP/7zip/Archive/7z/7zUpdate.cpp @@ -118,11 +118,11 @@ static int Parse_EXE(const Byte *buf, size_t size, CFilterMode *filterMode) #define ELF_SIG 0x464C457F -#define ELF_CLASS_32 1 -#define ELF_CLASS_64 2 +#define ELF_CLASS_32 1 +#define ELF_CLASS_64 2 -#define ELF_DATA_2LSB 1 -#define ELF_DATA_2MSB 2 +#define ELF_DATA_2LSB 1 +#define ELF_DATA_2MSB 2 static UInt16 Get16(const Byte *p, Bool be) { if (be) return (UInt16)GetBe16(p); return (UInt16)GetUi16(p); } static UInt32 Get32(const Byte *p, Bool be) { if (be) return GetBe32(p); return GetUi32(p); } diff --git a/CPP/7zip/Archive/ApmHandler.cpp b/CPP/7zip/Archive/ApmHandler.cpp index d5a111e9..fcd686aa 100644 --- a/CPP/7zip/Archive/ApmHandler.cpp +++ b/CPP/7zip/Archive/ApmHandler.cpp @@ -7,16 +7,13 @@ #include "../../Common/ComTry.h" #include "../../Common/Defs.h" #include "../../Common/IntToString.h" -#include "../../Common/MyString.h" #include "../../Windows/PropVariant.h" -#include "../Common/LimitedStreams.h" -#include "../Common/ProgressUtils.h" #include "../Common/RegisterArc.h" #include "../Common/StreamUtils.h" -#include "../Compress/CopyCoder.h" +#include "HandlerCont.h" #define Get16(p) GetBe16(p) #define Get32(p) GetBe32(p) @@ -75,13 +72,9 @@ struct CItem } }; -class CHandler: - public IInArchive, - public IInArchiveGetStream, - public CMyUnknownImp +class CHandler: public CHandlerCont { CRecordVector _items; - CMyComPtr _stream; unsigned _blockSizeLog; UInt32 _numBlocks; UInt64 _phySize; @@ -89,11 +82,11 @@ class CHandler: HRESULT ReadTables(IInStream *stream); UInt64 BlocksToBytes(UInt32 i) const { return (UInt64)i << _blockSizeLog; } - UInt64 GetItemSize(const CItem &item) const { return BlocksToBytes(item.NumBlocks); } + + virtual UInt64 GetItemPos(UInt32 index) const { return BlocksToBytes(_items[index].StartBlock); } + virtual UInt64 GetItemSize(UInt32 index) const { return BlocksToBytes(_items[index].NumBlocks); } public: - MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) - INTERFACE_IInArchive(;) - STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); + INTERFACE_IInArchive_Cont(;) }; static const UInt32 kSectorSize = 512; @@ -300,7 +293,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val } case kpidSize: case kpidPackSize: - prop = GetItemSize(item); + prop = BlocksToBytes(item.NumBlocks); break; case kpidOffset: prop = BlocksToBytes(item.StartBlock); break; } @@ -309,73 +302,6 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val COM_TRY_END } -STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback) -{ - COM_TRY_BEGIN - bool allFilesMode = (numItems == (UInt32)(Int32)-1); - if (allFilesMode) - numItems = _items.Size(); - if (numItems == 0) - return S_OK; - UInt64 totalSize = 0; - UInt32 i; - for (i = 0; i < numItems; i++) - totalSize += GetItemSize(_items[allFilesMode ? i : indices[i]]); - extractCallback->SetTotal(totalSize); - - totalSize = 0; - - NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); - CMyComPtr copyCoder = copyCoderSpec; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(extractCallback, false); - - CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; - CMyComPtr inStream(streamSpec); - streamSpec->SetStream(_stream); - - for (i = 0; i < numItems; i++) - { - lps->InSize = totalSize; - lps->OutSize = totalSize; - RINOK(lps->SetCur()); - CMyComPtr outStream; - Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - Int32 index = allFilesMode ? i : indices[i]; - const CItem &item = _items[index]; - - RINOK(extractCallback->GetStream(index, &outStream, askMode)); - UInt64 size = GetItemSize(item); - totalSize += size; - if (!testMode && !outStream) - continue; - RINOK(extractCallback->PrepareOperation(askMode)); - - RINOK(_stream->Seek(BlocksToBytes(item.StartBlock), STREAM_SEEK_SET, NULL)); - streamSpec->Init(size); - RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)); - outStream.Release(); - RINOK(extractCallback->SetOperationResult(copyCoderSpec->TotalSize == size ? - NExtract::NOperationResult::kOK: - NExtract::NOperationResult::kDataError)); - } - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) -{ - COM_TRY_BEGIN - const CItem &item = _items[index]; - return CreateLimitedInStream(_stream, BlocksToBytes(item.StartBlock), GetItemSize(item), stream); - COM_TRY_END -} - static const Byte k_Signature[] = { kSig0, kSig1 }; REGISTER_ARC_I( diff --git a/CPP/7zip/Archive/Cab/CabBlockInStream.cpp b/CPP/7zip/Archive/Cab/CabBlockInStream.cpp index 625276f3..c193434f 100644 --- a/CPP/7zip/Archive/Cab/CabBlockInStream.cpp +++ b/CPP/7zip/Archive/Cab/CabBlockInStream.cpp @@ -29,15 +29,24 @@ CCabBlockInStream::~CCabBlockInStream() static UInt32 CheckSum(const Byte *p, UInt32 size) { UInt32 sum = 0; - for (UInt32 i = size >> 2; i != 0; i--) + + for (; size >= 8; size -= 8) + { + sum ^= GetUi32(p) ^ GetUi32(p + 4); + p += 8; + } + + if (size >= 4) { sum ^= GetUi32(p); p += 4; } + size &= 3; if (size > 2) sum ^= (UInt32)(*p++) << 16; if (size > 1) sum ^= (UInt32)(*p++) << 8; if (size > 0) sum ^= (UInt32)(*p++); + return sum; } diff --git a/CPP/7zip/Archive/Cab/CabBlockInStream.h b/CPP/7zip/Archive/Cab/CabBlockInStream.h index b795ed97..af89abb6 100644 --- a/CPP/7zip/Archive/Cab/CabBlockInStream.h +++ b/CPP/7zip/Archive/Cab/CabBlockInStream.h @@ -25,10 +25,16 @@ public: CCabBlockInStream(): _buf(0), ReservedSize(0), MsZip(false) {} ~CCabBlockInStream(); + bool Create(); + void InitForNewBlock() { _size = 0; _pos = 0; } + HRESULT PreRead(ISequentialInStream *stream, UInt32 &packSize, UInt32 &unpackSize); + UInt32 GetPackSizeAvail() const { return _size - _pos; } + const Byte *GetData() const { return _buf + _pos; } + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); }; diff --git a/CPP/7zip/Archive/Cab/CabHandler.cpp b/CPP/7zip/Archive/Cab/CabHandler.cpp index 4235ec34..711bfdf7 100644 --- a/CPP/7zip/Archive/Cab/CabHandler.cpp +++ b/CPP/7zip/Archive/Cab/CabHandler.cpp @@ -569,13 +569,14 @@ public: UInt64 folderSize, IArchiveExtractCallback *extractCallback, bool testMode); - HRESULT FlushCorrupted(); + HRESULT FlushCorrupted(unsigned folderIndex); HRESULT Unsupported(); UInt64 GetRemain() const { return m_FolderSize - m_PosInFolder; } UInt64 GetPosInFolder() const { return m_PosInFolder; } }; + void CFolderOutStream::Init( const CMvDatabaseEx *database, const CRecordVector *extractStatuses, @@ -600,6 +601,7 @@ void CFolderOutStream::Init( NumIdenticalFiles = 0; } + HRESULT CFolderOutStream::CloseFileWithResOp(Int32 resOp) { m_RealOutStream.Release(); @@ -608,6 +610,7 @@ HRESULT CFolderOutStream::CloseFileWithResOp(Int32 resOp) return m_ExtractCallback->SetOperationResult(resOp); } + HRESULT CFolderOutStream::CloseFile() { return CloseFileWithResOp(m_IsOk ? @@ -615,6 +618,7 @@ HRESULT CFolderOutStream::CloseFile() NExtract::NOperationResult::kDataError); } + HRESULT CFolderOutStream::OpenFile() { if (NumIdenticalFiles == 0) @@ -680,6 +684,7 @@ HRESULT CFolderOutStream::OpenFile() return m_ExtractCallback->PrepareOperation(askMode); } + HRESULT CFolderOutStream::WriteEmptyFiles() { if (m_FileIsOpen) @@ -699,13 +704,15 @@ HRESULT CFolderOutStream::WriteEmptyFiles() return S_OK; } -// This is Write function + HRESULT CFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *processedSize, bool isOK) { COM_TRY_BEGIN + UInt32 realProcessed = 0; if (processedSize) *processedSize = 0; + while (size != 0) { if (m_FileIsOpen) @@ -732,8 +739,10 @@ HRESULT CFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *processe size -= numBytesToWrite; m_RemainFileSize -= numBytesToWrite; m_PosInFolder += numBytesToWrite; + if (res != S_OK) return res; + if (m_RemainFileSize == 0) { RINOK(CloseFile()); @@ -754,17 +763,27 @@ HRESULT CFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *processe { RINOK(CloseFile()); } + RINOK(result); } + TempBufMode = false; } + if (realProcessed > 0) break; // with this break this function works as Write-Part } else { if (m_CurrentIndex >= m_ExtractStatuses->Size()) - return E_FAIL; + { + // we ignore extra data; + realProcessed += size; + if (processedSize) + *processedSize = realProcessed; + return S_OK; + // return E_FAIL; + } const CMvItem &mvItem = m_Database->Items[m_StartIndex + m_CurrentIndex]; const CItem &item = m_Database->Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex]; @@ -772,8 +791,10 @@ HRESULT CFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *processe m_RemainFileSize = item.Size; UInt32 fileOffset = item.Offset; + if (fileOffset < m_PosInFolder) return E_FAIL; + if (fileOffset > m_PosInFolder) { UInt32 numBytesToWrite = MyMin(fileOffset - (UInt32)m_PosInFolder, size); @@ -784,6 +805,7 @@ HRESULT CFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *processe size -= numBytesToWrite; m_PosInFolder += numBytesToWrite; } + if (fileOffset == m_PosInFolder) { RINOK(OpenFile()); @@ -793,21 +815,39 @@ HRESULT CFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *processe } } } + return WriteEmptyFiles(); + COM_TRY_END } + STDMETHODIMP CFolderOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize) { return Write2(data, size, processedSize, true); } -HRESULT CFolderOutStream::FlushCorrupted() + +HRESULT CFolderOutStream::FlushCorrupted(unsigned folderIndex) { + UInt64 remain = GetRemain(); + + if (remain == 0) + { + CMyComPtr callbackMessage; + m_ExtractCallback.QueryInterface(IID_IArchiveExtractCallbackMessage, &callbackMessage); + if (callbackMessage) + { + RINOK(callbackMessage->ReportExtractResult(NEventIndexType::kBlockIndex, folderIndex, NExtract::NOperationResult::kDataError)); + } + return S_OK; + } + const unsigned kBufSize = (1 << 10); Byte buf[kBufSize]; for (unsigned i = 0; i < kBufSize; i++) buf[i] = 0; + for (;;) { UInt64 remain = GetRemain(); @@ -819,6 +859,7 @@ HRESULT CFolderOutStream::FlushCorrupted() } } + HRESULT CFolderOutStream::Unsupported() { while (m_CurrentIndex < m_ExtractStatuses->Size()) @@ -838,6 +879,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testModeSpec, IArchiveExtractCallback *extractCallback) { COM_TRY_BEGIN + bool allFilesMode = (numItems == (UInt32)(Int32)-1); if (allFilesMode) numItems = m_Database.Items.Size(); @@ -883,10 +925,10 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, CMyComPtr deflateDecoder; NCompress::NLzx::CDecoder *lzxDecoderSpec = NULL; - CMyComPtr lzxDecoder; + CMyComPtr lzxDecoder; NCompress::NQuantum::CDecoder *quantumDecoderSpec = NULL; - CMyComPtr quantumDecoder; + CMyComPtr quantumDecoder; CCabBlockInStream *cabBlockInStreamSpec = new CCabBlockInStream(); CMyComPtr cabBlockInStream = cabBlockInStreamSpec; @@ -968,7 +1010,8 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, CFolderOutStream *cabFolderOutStream = new CFolderOutStream; CMyComPtr outStream(cabFolderOutStream); - const CFolder &folder = db.Folders[item.GetFolderIndex(db.Folders.Size())]; + unsigned folderIndex2 = item.GetFolderIndex(db.Folders.Size()); + const CFolder &folder = db.Folders[folderIndex2]; cabFolderOutStream->Init(&m_Database, &extractStatuses, startIndex2, curUnpack, extractCallback, testMode); @@ -980,6 +1023,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, { case NHeader::NMethod::kNone: break; + case NHeader::NMethod::kMSZip: if (!deflateDecoder) { @@ -988,14 +1032,16 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, } cabBlockInStreamSpec->MsZip = true; break; + case NHeader::NMethod::kLZX: if (!lzxDecoder) { lzxDecoderSpec = new NCompress::NLzx::CDecoder; lzxDecoder = lzxDecoderSpec; } - res = lzxDecoderSpec->SetParams(folder.MethodMinor); + res = lzxDecoderSpec->SetParams_and_Alloc(folder.MethodMinor); break; + case NHeader::NMethod::kQuantum: if (!quantumDecoder) { @@ -1004,6 +1050,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, } res = quantumDecoderSpec->SetParams(folder.MethodMinor); break; + default: res = E_INVALIDARG; break; @@ -1022,6 +1069,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, int locFolderIndex = item.GetFolderIndex(db.Folders.Size()); bool keepHistory = false; bool keepInputBuffer = false; + bool thereWasNotAlignedChunk = false; for (UInt32 bl = 0; cabFolderOutStream->GetRemain() != 0;) { @@ -1058,6 +1106,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, continue; } } + bl++; if (!keepInputBuffer) @@ -1079,19 +1128,39 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, lps->InSize = totalPacked; RINOK(lps->SetCur()); - UInt64 unpackRemain = cabFolderOutStream->GetRemain(); - const UInt32 kBlockSizeMax = (1 << 15); - if (unpackRemain > kBlockSizeMax) - unpackRemain = kBlockSizeMax; - if (unpackRemain > unpackSize) - unpackRemain = unpackSize; + + /* We don't try to reduce last block. + Note that LZX converts data with x86 filter. + and filter needs larger input data than reduced size. + It's simpler to decompress full chunk here. + also we need full block for quantum for more integrity checks */ + + if (unpackSize > kBlockSizeMax) + { + res = S_FALSE; + break; + } + + if (unpackSize != kBlockSizeMax) + { + if (thereWasNotAlignedChunk) + { + res = S_FALSE; + break; + } + thereWasNotAlignedChunk = true; + } + + UInt64 unpackSize64 = unpackSize; + UInt32 packSizeChunk = cabBlockInStreamSpec->GetPackSizeAvail(); switch (folder.GetMethod()) { case NHeader::NMethod::kNone: - res = copyCoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL); + res = copyCoder->Code(cabBlockInStream, outStream, NULL, &unpackSize64, NULL); break; + case NHeader::NMethod::kMSZip: deflateDecoderSpec->Set_KeepHistory(keepHistory); /* v9.31: now we follow MSZIP specification that requires to finish deflate stream at the end of each block. @@ -1100,7 +1169,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Maybe we also should ignore that error? Or we should extract full file and show the warning? */ deflateDecoderSpec->Set_NeedFinishInput(true); - res = deflateDecoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL); + res = deflateDecoder->Code(cabBlockInStream, outStream, NULL, &unpackSize64, NULL); if (res == S_OK) { if (!deflateDecoderSpec->IsFinished()) @@ -1108,16 +1177,24 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, if (!deflateDecoderSpec->IsFinalBlock()) res = S_FALSE; } - break; + case NHeader::NMethod::kLZX: lzxDecoderSpec->SetKeepHistory(keepHistory); - res = lzxDecoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL); + lzxDecoderSpec->KeepHistoryForNext = true; + + res = lzxDecoderSpec->Code(cabBlockInStreamSpec->GetData(), packSizeChunk, unpackSize); + + if (res == S_OK) + res = WriteStream(outStream, + lzxDecoderSpec->GetUnpackData(), + lzxDecoderSpec->GetUnpackSize()); break; + case NHeader::NMethod::kQuantum: - quantumDecoderSpec->SetKeepHistory(keepHistory); - res = quantumDecoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL); - break; + res = quantumDecoderSpec->Code(cabBlockInStreamSpec->GetData(), + packSizeChunk, outStream, unpackSize, keepHistory); + break; } if (res != S_OK) @@ -1135,17 +1212,21 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, RINOK(cabFolderOutStream->WriteEmptyFiles()); } } + if (res != S_OK || cabFolderOutStream->GetRemain() != 0) { - RINOK(cabFolderOutStream->FlushCorrupted()); + RINOK(cabFolderOutStream->FlushCorrupted(folderIndex2)); } + totalUnPacked += curUnpack; } return S_OK; + COM_TRY_END } + STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) { *numItems = m_Database.Items.Size(); diff --git a/CPP/7zip/Archive/Chm/ChmHandler.cpp b/CPP/7zip/Archive/Chm/ChmHandler.cpp index 3035ef9e..b1ab2996 100644 --- a/CPP/7zip/Archive/Chm/ChmHandler.cpp +++ b/CPP/7zip/Archive/Chm/ChmHandler.cpp @@ -144,7 +144,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val if (item.Section == 0) prop = "Copy"; else if (item.Section < m_Database.Sections.Size()) - prop = m_Database.Sections[(int)item.Section].GetMethodName(); + prop = m_Database.Sections[(unsigned)item.Section].GetMethodName(); break; } case kpidBlock: @@ -315,8 +315,9 @@ HRESULT CChmFolderOutStream::WriteEmptyFiles() HRESULT CChmFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *processedSize, bool isOK) { UInt32 realProcessed = 0; - if (processedSize != NULL) + if (processedSize) *processedSize = 0; + while(size != 0) { if (m_FileIsOpen) @@ -335,7 +336,7 @@ HRESULT CChmFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *proce } } realProcessed += numBytesToWrite; - if (processedSize != NULL) + if (processedSize) *processedSize = realProcessed; data = (const void *)((const Byte *)data + numBytesToWrite); size -= numBytesToWrite; @@ -359,23 +360,32 @@ HRESULT CChmFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *proce else { if (m_CurrentIndex >= m_NumFiles) - return E_FAIL; + { + realProcessed += size; + if (processedSize) + *processedSize = realProcessed; + return S_OK; + // return E_FAIL; + } + int fullIndex = m_StartIndex + m_CurrentIndex; m_RemainFileSize = m_Database->GetFileSize(fullIndex); UInt64 fileOffset = m_Database->GetFileOffset(fullIndex); if (fileOffset < m_PosInSection) return E_FAIL; + if (fileOffset > m_PosInSection) { UInt32 numBytesToWrite = (UInt32)MyMin(fileOffset - m_PosInSection, UInt64(size)); realProcessed += numBytesToWrite; - if (processedSize != NULL) + if (processedSize) *processedSize = realProcessed; data = (const void *)((const Byte *)data + numBytesToWrite); size -= numBytesToWrite; m_PosInSection += numBytesToWrite; m_PosInFolder += numBytesToWrite; } + if (fileOffset == m_PosInSection) { RINOK(OpenFile()); @@ -385,6 +395,7 @@ HRESULT CChmFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *proce } } } + return WriteEmptyFiles(); } @@ -430,7 +441,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, UInt64 currentTotalSize = 0; - NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); + NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder; CMyComPtr copyCoder = copyCoderSpec; UInt32 i; @@ -446,11 +457,13 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, { UInt64 currentItemSize = 0; UInt64 totalSize = 0; + if (m_Database.NewFormat) totalSize = m_Database.NewFormatString.Len(); else for (i = 0; i < numItems; i++) totalSize += m_Database.Items[allFilesMode ? i : indices[i]].Size; + extractCallback->SetTotal(totalSize); for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize) @@ -481,6 +494,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); continue; } + const CItem &item = m_Database.Items[index]; currentItemSize = item.Size; @@ -513,6 +527,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, } UInt64 lastFolderIndex = ((UInt64)0 - 1); + for (i = 0; i < numItems; i++) { UInt32 index = allFilesMode ? i : indices[i]; @@ -526,7 +541,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, currentTotalSize += item.Size; continue; } - const CSectionInfo §ion = m_Database.Sections[(int)item.Section]; + const CSectionInfo §ion = m_Database.Sections[(unsigned)item.Section]; if (section.IsLzx()) { const CLzxInfo &lzxInfo = section.Methods[0].LzxInfo; @@ -541,14 +556,17 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, RINOK(extractCallback->SetTotal(currentTotalSize)); - NCompress::NLzx::CDecoder *lzxDecoderSpec = 0; - CMyComPtr lzxDecoder; + NCompress::NLzx::CDecoder *lzxDecoderSpec = NULL; + CMyComPtr lzxDecoder; CChmFolderOutStream *chmFolderOutStream = 0; CMyComPtr outStream; currentTotalSize = 0; CRecordVector extractStatuses; + + CByteBuffer packBuf; + for (i = 0; i < numItems;) { RINOK(extractCallback->SetCompleted(¤tTotalSize)); @@ -560,6 +578,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 askMode= testMode ? NExtract::NAskMode::kTest : NExtract::NAskMode::kExtract; + if (item.IsDir()) { CMyComPtr realOutStream; @@ -595,7 +614,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, continue; } - const CSectionInfo §ion = m_Database.Sections[(int)sectionIndex]; + const CSectionInfo §ion = m_Database.Sections[(unsigned)sectionIndex]; if (!section.IsLzx()) { @@ -610,7 +629,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, const CLzxInfo &lzxInfo = section.Methods[0].LzxInfo; - if (chmFolderOutStream == 0) + if (!chmFolderOutStream) { chmFolderOutStream = new CChmFolderOutStream; outStream = chmFolderOutStream; @@ -618,7 +637,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, chmFolderOutStream->Init(&m_Database, extractCallback, testMode); - if (lzxDecoderSpec == NULL) + if (!lzxDecoderSpec) { lzxDecoderSpec = new NCompress::NLzx::CDecoder; lzxDecoder = lzxDecoderSpec; @@ -627,8 +646,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, UInt64 folderIndex = m_Database.GetFolder(index); UInt64 compressedPos = m_Database.ContentOffset + section.Offset; - UInt32 numDictBits = lzxInfo.GetNumDictBits(); - RINOK(lzxDecoderSpec->SetParams(numDictBits)); + RINOK(lzxDecoderSpec->SetParams_and_Alloc(lzxInfo.GetNumDictBits())); const CItem *lastItem = &item; extractStatuses.Clear(); @@ -645,10 +663,12 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, lastFolderIndex = m_Database.GetLastFolder(index); UInt64 folderSize = lzxInfo.GetFolderSize(); UInt64 unPackSize = folderSize; + if (extractStatuses.IsEmpty()) chmFolderOutStream->m_StartIndex = index + 1; else chmFolderOutStream->m_StartIndex = index; + if (limitFolderIndex == folderIndex) { for (; i < numItems; i++) @@ -671,6 +691,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, lastFolderIndex = m_Database.GetLastFolder(index); } } + unPackSize = MyMin(finishPos - startPos, unPackSize); chmFolderOutStream->m_FolderSize = folderSize; @@ -679,11 +700,13 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, chmFolderOutStream->m_ExtractStatuses = &extractStatuses; chmFolderOutStream->m_NumFiles = extractStatuses.Size(); chmFolderOutStream->m_CurrentIndex = 0; + try { UInt64 startBlock = lzxInfo.GetBlockIndexFromFolderIndex(folderIndex); const CResetTable &rt = lzxInfo.ResetTable; UInt32 numBlocks = (UInt32)rt.GetNumBlocks(unPackSize); + for (UInt32 b = 0; b < numBlocks; b++) { UInt64 completedSize = currentTotalSize + chmFolderOutStream->m_PosInSection - startPos; @@ -691,17 +714,35 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, UInt64 bCur = startBlock + b; if (bCur >= rt.ResetOffsets.Size()) return E_FAIL; - UInt64 offset = rt.ResetOffsets[(int)bCur]; + UInt64 offset = rt.ResetOffsets[(unsigned)bCur]; UInt64 compressedSize; rt.GetCompressedSizeOfBlock(bCur, compressedSize); - UInt64 rem = finishPos - chmFolderOutStream->m_PosInSection; - if (rem > rt.BlockSize) - rem = rt.BlockSize; + + // chm writes full blocks. So we don't need to use reduced size for last block + RINOK(m_Stream->Seek(compressedPos + offset, STREAM_SEEK_SET, NULL)); streamSpec->SetStream(m_Stream); streamSpec->Init(compressedSize); + lzxDecoderSpec->SetKeepHistory(b > 0); - HRESULT res = lzxDecoder->Code(inStream, outStream, NULL, &rem, NULL); + + size_t compressedSizeT = (size_t)compressedSize; + if (compressedSizeT != compressedSize) + throw 2; + packBuf.AllocAtLeast(compressedSizeT); + + HRESULT res = ReadStream_FALSE(inStream, packBuf, compressedSizeT); + + if (res == S_OK) + { + lzxDecoderSpec->KeepHistoryForNext = true; + res = lzxDecoderSpec->Code(packBuf, compressedSizeT, kBlockSize); // rt.BlockSize; + if (res == S_OK) + res = WriteStream(chmFolderOutStream, + lzxDecoderSpec->GetUnpackData(), + lzxDecoderSpec->GetUnpackSize()); + } + if (res != S_OK) { if (res != S_FALSE) @@ -714,6 +755,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, { RINOK(chmFolderOutStream->FlushCorrupted(unPackSize)); } + currentTotalSize += folderSize; if (folderIndex == lastFolderIndex) break; diff --git a/CPP/7zip/Archive/Chm/ChmIn.cpp b/CPP/7zip/Archive/Chm/ChmIn.cpp index e8da227d..d7556b89 100644 --- a/CPP/7zip/Archive/Chm/ChmIn.cpp +++ b/CPP/7zip/Archive/Chm/ChmIn.cpp @@ -4,6 +4,8 @@ // #include +#include "../../../../C/CpuArch.h" + #include "../../../Common/IntToString.h" #include "../../../Common/UTFConvert.h" @@ -11,6 +13,10 @@ #include "ChmIn.h" +#define Get16(p) GetUi16(p) +#define Get32(p) GetUi32(p) +#define Get64(p) GetUi64(p) + namespace NArchive { namespace NChm { @@ -168,38 +174,36 @@ Byte CInArchive::ReadByte() void CInArchive::Skip(size_t size) { - while (size-- != 0) - ReadByte(); + if (_inBuffer.Skip(size) != size) + throw CEnexpectedEndException(); } void CInArchive::ReadBytes(Byte *data, UInt32 size) { - for (UInt32 i = 0; i < size; i++) - data[i] = ReadByte(); + if (_inBuffer.ReadBytes(data, size) != size) + throw CEnexpectedEndException(); } UInt16 CInArchive::ReadUInt16() { - UInt16 val = 0; - for (int i = 0; i < 2; i++) - val |= ((UInt16)(ReadByte()) << (8 * i)); - return val; + Byte b0, b1; + if (!_inBuffer.ReadByte(b0)) throw CEnexpectedEndException(); + if (!_inBuffer.ReadByte(b1)) throw CEnexpectedEndException(); + return (UInt16)(((UInt16)b1 << 8) | b0); } UInt32 CInArchive::ReadUInt32() { - UInt32 val = 0; - for (int i = 0; i < 4; i++) - val |= ((UInt32)(ReadByte()) << (8 * i)); - return val; + Byte p[4]; + ReadBytes(p, 4); + return Get32(p); } UInt64 CInArchive::ReadUInt64() { - UInt64 val = 0; - for (int i = 0; i < 8; i++) - val |= ((UInt64)(ReadByte()) << (8 * i)); - return val; + Byte p[8]; + ReadBytes(p, 8); + return Get64(p); } UInt64 CInArchive::ReadEncInt() @@ -227,15 +231,10 @@ void CInArchive::ReadGUID(GUID &g) void CInArchive::ReadString(unsigned size, AString &s) { s.Empty(); - while (size-- != 0) + if (size != 0) { - char c = (char)ReadByte(); - if (c == 0) - { - Skip(size); - return; - } - s += c; + ReadBytes((Byte *)s.GetBuf(size), size); + s.ReleaseBuf_CalcLen(size); } } @@ -380,6 +379,7 @@ HRESULT CInArchive::OpenChm(IInStream *inStream, CDatabase &database) ReadUInt32(); // Chunk number of next listing chunk when reading // directory in sequence (-1 if this is the last listing chunk) unsigned numItems = 0; + for (;;) { UInt64 offset = _inBuffer.GetProcessedSize() - chunkPos; @@ -391,9 +391,16 @@ HRESULT CInArchive::OpenChm(IInStream *inStream, CDatabase &database) RINOK(ReadDirEntry(database)); numItems++; } + Skip(quickrefLength - 2); - if (ReadUInt16() != numItems) - return S_FALSE; + + unsigned rrr = ReadUInt16(); + if (rrr != numItems) + { + // Lazarus 9-26-2 chm contains 0 here. + if (rrr != 0) + return S_FALSE; + } } else Skip(dirChunkSize - 4); @@ -709,6 +716,14 @@ bool CFilesDatabase::Check() return true; } +static int inline GetLog(UInt32 num) +{ + for (int i = 0; i < 32; i++) + if (((UInt32)1 << i) == num) + return i; + return -1; +} + HRESULT CInArchive::OpenHighLevel(IInStream *inStream, CFilesDatabase &database) { { @@ -771,6 +786,7 @@ HRESULT CInArchive::OpenHighLevel(IInStream *inStream, CFilesDatabase &database) { // Control Data RINOK(DecompressStream(inStream, database, sectionPrefix + kControlData)); + FOR_VECTOR (mi, section.Methods) { CMethodInfo &method = section.Methods[mi]; @@ -785,27 +801,22 @@ HRESULT CInArchive::OpenHighLevel(IInStream *inStream, CFilesDatabase &database) li.Version = ReadUInt32(); if (li.Version != 2 && li.Version != 3) return S_FALSE; - li.ResetInterval = ReadUInt32(); - li.WindowSize = ReadUInt32(); + + { + int n = GetLog(ReadUInt32()); + if (n < 0 || n > 16) + return S_FALSE; + li.ResetIntervalBits = n; + } + + { + int n = GetLog(ReadUInt32()); + if (n < 0 || n > 16) + return S_FALSE; + li.WindowSizeBits = n; + } + li.CacheSize = ReadUInt32(); - if ( - li.ResetInterval != 1 && - li.ResetInterval != 2 && - li.ResetInterval != 4 && - li.ResetInterval != 8 && - li.ResetInterval != 16 && - li.ResetInterval != 32 && - li.ResetInterval != 64) - return S_FALSE; - if ( - li.WindowSize != 1 && - li.WindowSize != 2 && - li.WindowSize != 4 && - li.WindowSize != 8 && - li.WindowSize != 16 && - li.WindowSize != 32 && - li.WindowSize != 64) - return S_FALSE; numDWORDS -= 5; while (numDWORDS-- != 0) ReadUInt32(); @@ -835,6 +846,7 @@ HRESULT CInArchive::OpenHighLevel(IInStream *inStream, CFilesDatabase &database) RINOK(DecompressStream(inStream, database, transformPrefix + method.GetGuidString() + kResetTable)); CResetTable &rt = method.LzxInfo.ResetTable; + if (_chunkSize < 4) { if (_chunkSize != 0) @@ -844,7 +856,7 @@ HRESULT CInArchive::OpenHighLevel(IInStream *inStream, CFilesDatabase &database) return S_FALSE; rt.UncompressedSize = 0; rt.CompressedSize = 0; - rt.BlockSize = 0; + // rt.BlockSize = 0; } else { @@ -852,18 +864,45 @@ HRESULT CInArchive::OpenHighLevel(IInStream *inStream, CFilesDatabase &database) if (ver != 2 && ver != 3) return S_FALSE; UInt32 numEntries = ReadUInt32(); - if (ReadUInt32() != 8) // Size of table entry (bytes) + const unsigned kEntrySize = 8; + if (ReadUInt32() != kEntrySize) return S_FALSE; - if (ReadUInt32() != 0x28) // Len of table header + const unsigned kRtHeaderSize = 4 * 4 + 8 * 3; + if (ReadUInt32() != kRtHeaderSize) return S_FALSE; + if (kRtHeaderSize + kEntrySize * (UInt64)numEntries != _chunkSize) + return S_FALSE; + rt.UncompressedSize = ReadUInt64(); rt.CompressedSize = ReadUInt64(); - rt.BlockSize = ReadUInt64(); // 0x8000 block size for locations below - if (rt.BlockSize != 0x8000) + UInt64 blockSize = ReadUInt64(); + if (blockSize != kBlockSize) + return S_FALSE; + UInt64 numBlocks = (rt.UncompressedSize + kBlockSize + 1) / kBlockSize; + if (numEntries != numBlocks && + numEntries != numBlocks + 1) return S_FALSE; + rt.ResetOffsets.ClearAndReserve(numEntries); + for (UInt32 i = 0; i < numEntries; i++) - rt.ResetOffsets.AddInReserved(ReadUInt64()); + { + UInt64 v = ReadUInt64(); + if (i != 0 && v < rt.ResetOffsets[i - 1]) + return S_FALSE; + rt.ResetOffsets.AddInReserved(v); + } + + if (numEntries != 0) + if (rt.ResetOffsets[0] != 0) + return S_FALSE; + + if (numEntries == numBlocks + 1) + { + // Lazarus 9-26-2 chm contains additional entty + if (rt.ResetOffsets.Back() != rt.CompressedSize) + return S_FALSE; + } } } } @@ -896,14 +935,16 @@ HRESULT CInArchive::Open2(IInStream *inStream, if (_help2) { - const int kSignatureSize = 8; - UInt64 signature = ((UInt64)kSignature_ITLS << 32)| kSignature_ITOL; + const unsigned kSignatureSize = 8; + const UInt64 signature = ((UInt64)kSignature_ITLS << 32) | kSignature_ITOL; UInt64 limit = 1 << 18; + if (searchHeaderSizeLimit) if (limit > *searchHeaderSizeLimit) limit = *searchHeaderSizeLimit; UInt64 val = 0; + for (;;) { Byte b; @@ -919,6 +960,7 @@ HRESULT CInArchive::Open2(IInStream *inStream, return S_FALSE; } } + database.StartPosition += _inBuffer.GetProcessedSize() - kSignatureSize; RINOK(OpenHelp2(inStream, database)); if (database.NewFormat) diff --git a/CPP/7zip/Archive/Chm/ChmIn.h b/CPP/7zip/Archive/Chm/ChmIn.h index c4ce83ed..dc5e8263 100644 --- a/CPP/7zip/Archive/Chm/ChmIn.h +++ b/CPP/7zip/Archive/Chm/ChmIn.h @@ -36,12 +36,13 @@ struct CItem bool IsDir() const { - if (Name.Len() == 0) + if (Name.IsEmpty()) return false; return (Name.Back() == '/'); } }; + struct CDatabase { UInt64 StartPosition; @@ -73,11 +74,14 @@ struct CDatabase } }; + +const UInt32 kBlockSize = 1 << 15; + struct CResetTable { UInt64 UncompressedSize; UInt64 CompressedSize; - UInt64 BlockSize; + // unsigned BlockSizeBits; CRecordVector ResetOffsets; bool GetCompressedSizeOfBlocks(UInt64 blockIndex, UInt32 numBlocks, UInt64 &size) const @@ -91,39 +95,41 @@ struct CResetTable size = ResetOffsets[(unsigned)(blockIndex + numBlocks)] - startPos; return true; } + bool GetCompressedSizeOfBlock(UInt64 blockIndex, UInt64 &size) const { return GetCompressedSizeOfBlocks(blockIndex, 1, size); } + UInt64 GetNumBlocks(UInt64 size) const { - return (size + BlockSize - 1) / BlockSize; + return (size + kBlockSize - 1) / kBlockSize; } }; + struct CLzxInfo { UInt32 Version; - UInt32 ResetInterval; - UInt32 WindowSize; + + unsigned ResetIntervalBits; + unsigned WindowSizeBits; UInt32 CacheSize; + CResetTable ResetTable; - UInt32 GetNumDictBits() const + unsigned GetNumDictBits() const { if (Version == 2 || Version == 3) - { - for (unsigned i = 0; i <= 31; i++) - if (((UInt32)1 << i) >= WindowSize) - return 15 + i; - } + return 15 + WindowSizeBits; return 0; } - UInt64 GetFolderSize() const { return ResetTable.BlockSize * ResetInterval; } + UInt64 GetFolderSize() const { return kBlockSize << ResetIntervalBits; } UInt64 GetFolder(UInt64 offset) const { return offset / GetFolderSize(); } UInt64 GetFolderPos(UInt64 folderIndex) const { return folderIndex * GetFolderSize(); } - UInt64 GetBlockIndexFromFolderIndex(UInt64 folderIndex) const { return folderIndex * ResetInterval; } + UInt64 GetBlockIndexFromFolderIndex(UInt64 folderIndex) const { return folderIndex << ResetIntervalBits; } + bool GetOffsetOfFolder(UInt64 folderIndex, UInt64 &offset) const { UInt64 blockIndex = GetBlockIndexFromFolderIndex(folderIndex); @@ -132,24 +138,28 @@ struct CLzxInfo offset = ResetTable.ResetOffsets[(unsigned)blockIndex]; return true; } + bool GetCompressedSizeOfFolder(UInt64 folderIndex, UInt64 &size) const { UInt64 blockIndex = GetBlockIndexFromFolderIndex(folderIndex); - return ResetTable.GetCompressedSizeOfBlocks(blockIndex, ResetInterval, size); + return ResetTable.GetCompressedSizeOfBlocks(blockIndex, (UInt32)1 << ResetIntervalBits, size); } }; + struct CMethodInfo { GUID Guid; CByteBuffer ControlData; CLzxInfo LzxInfo; + bool IsLzx() const; bool IsDes() const; AString GetGuidString() const; UString GetName() const; }; + struct CSectionInfo { UInt64 Offset; @@ -203,19 +213,12 @@ public: CDatabase::Clear(); HighLevelClear(); } + void SetIndices(); void Sort(); bool Check(); }; -/* -class CProgressVirt -{ -public: - STDMETHOD(SetTotal)(const UInt64 *numFiles) PURE; - STDMETHOD(SetCompleted)(const UInt64 *numFiles) PURE; -}; -*/ class CInArchive { diff --git a/CPP/7zip/Archive/DmgHandler.cpp b/CPP/7zip/Archive/DmgHandler.cpp index 208f2a82..2a80e255 100644 --- a/CPP/7zip/Archive/DmgHandler.cpp +++ b/CPP/7zip/Archive/DmgHandler.cpp @@ -545,8 +545,8 @@ HRESULT CHandler::Open2(IInStream *stream) CChecksum masterChecksum; masterChecksum.Parse(buf + 0x160); - // UInt32 imageVariant = Get32(buf + 0x1E8); - // UInt64 numSectors = Get64(buf + 0x1EC); + // UInt32 imageVariant = Get32(buf + 0x1E8); + // UInt64 numSectors = Get64(buf + 0x1EC); // Byte reserved[0x12] const UInt32 RSRC_HEAD_SIZE = 0x100; diff --git a/CPP/7zip/Archive/ElfHandler.cpp b/CPP/7zip/Archive/ElfHandler.cpp index 089d1023..beca8036 100644 --- a/CPP/7zip/Archive/ElfHandler.cpp +++ b/CPP/7zip/Archive/ElfHandler.cpp @@ -226,25 +226,25 @@ void CSegment::Parse(const Byte *p, bool mode64, bool be) // Section types -#define SHT_NULL 0 -#define SHT_PROGBITS 1 -#define SHT_SYMTAB 2 -#define SHT_STRTAB 3 -#define SHT_RELA 4 -#define SHT_HASH 5 -#define SHT_DYNAMIC 6 -#define SHT_NOTE 7 -#define SHT_NOBITS 8 -#define SHT_REL 9 -#define SHT_SHLIB 10 -#define SHT_DYNSYM 11 -#define SHT_UNKNOWN12 12 -#define SHT_UNKNOWN13 13 -#define SHT_INIT_ARRAY 14 -#define SHT_FINI_ARRAY 15 -#define SHT_PREINIT_ARRAY 16 -#define SHT_GROUP 17 -#define SHT_SYMTAB_SHNDX 18 +#define SHT_NULL 0 +#define SHT_PROGBITS 1 +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define SHT_RELA 4 +#define SHT_HASH 5 +#define SHT_DYNAMIC 6 +#define SHT_NOTE 7 +#define SHT_NOBITS 8 +#define SHT_REL 9 +#define SHT_SHLIB 10 +#define SHT_DYNSYM 11 +#define SHT_UNKNOWN12 12 +#define SHT_UNKNOWN13 13 +#define SHT_INIT_ARRAY 14 +#define SHT_FINI_ARRAY 15 +#define SHT_PREINIT_ARRAY 16 +#define SHT_GROUP 17 +#define SHT_SYMTAB_SHNDX 18 static const CUInt32PCharPair g_SectTypes[] = @@ -554,11 +554,11 @@ static const CUInt32PCharPair g_OS[] = { 255, "Standalone" } }; -#define ET_NONE 0 -#define ET_REL 1 -#define ET_EXEC 2 -#define ET_DYN 3 -#define ET_CORE 4 +#define ET_NONE 0 +#define ET_REL 1 +#define ET_EXEC 2 +#define ET_DYN 3 +#define ET_CORE 4 static const char *g_Types[] = { diff --git a/CPP/7zip/Archive/GptHandler.cpp b/CPP/7zip/Archive/GptHandler.cpp new file mode 100644 index 00000000..2e0e7a57 --- /dev/null +++ b/CPP/7zip/Archive/GptHandler.cpp @@ -0,0 +1,386 @@ +// GptHandler.cpp + +#include "StdAfx.h" + +#include "../../../C/7zCrc.h" +#include "../../../C/CpuArch.h" + +#include "../../Common/ComTry.h" +#include "../../Common/IntToString.h" +#include "../../Common/MyBuffer.h" + +#include "../../Windows/PropVariantUtils.h" + +#include "../Common/RegisterArc.h" +#include "../Common/StreamUtils.h" + +#include "HandlerCont.h" + +#define Get16(p) GetUi16(p) +#define Get32(p) GetUi32(p) +#define Get64(p) GetUi64(p) + +using namespace NWindows; + +namespace NArchive { +namespace NGpt { + +#define SIGNATURE { 'E', 'F', 'I', ' ', 'P', 'A', 'R', 'T', 0, 0, 1, 0 } + +static const unsigned k_SignatureSize = 12; +static const Byte k_Signature[k_SignatureSize] = SIGNATURE; + +static const UInt32 kSectorSize = 512; + +static const CUInt32PCharPair g_PartitionFlags[] = +{ + { 0, "Sys" }, + { 1, "Ignore" }, + { 2, "Legacy" }, + { 60, "Win-Read-only" }, + { 62, "Win-Hidden" }, + { 63, "Win-Not-Automount" } +}; + +static const unsigned kNameLen = 36; + +struct CPartition +{ + Byte Type[16]; + Byte Id[16]; + UInt64 FirstLba; + UInt64 LastLba; + UInt64 Flags; + Byte Name[kNameLen * 2]; + + bool IsUnused() const + { + for (unsigned i = 0; i < 16; i++) + if (Type[i] != 0) + return false; + return true; + } + + UInt64 GetSize() const { return (LastLba - FirstLba + 1) * kSectorSize; } + UInt64 GetPos() const { return FirstLba * kSectorSize; } + UInt64 GetEnd() const { return (LastLba + 1) * kSectorSize; } + + void Parse(const Byte *p) + { + memcpy(Type, p, 16); + memcpy(Id, p + 16, 16); + FirstLba = Get64(p + 32); + LastLba = Get64(p + 40); + Flags = Get64(p + 48); + memcpy(Name, p + 56, kNameLen * 2); + } +}; + + +struct CPartType +{ + UInt32 Id; + const char *Ext; + const char *Type; +}; + +static const CPartType kPartTypes[] = +{ + // { 0x0, 0, "Unused" }, + { 0xC12A7328, 0, "EFI System" }, + { 0x024DEE41, 0, "MBR" }, + + { 0xE3C9E316, 0, "Windows MSR" }, + { 0xEBD0A0A2, 0, "Windows BDP" }, + { 0x5808C8AA, 0, "Windows LDM Metadata" }, + { 0xAF9B60A0, 0, "Windows LDM Data" }, + { 0xDE94BBA4, 0, "Windows Recovery" }, + // { 0x37AFFC90, 0, "IBM GPFS" }, + // { 0xE75CAF8F, 0, "Windows Storage Spaces" }, + + { 0x83BD6B9D, 0, "FreeBSD Boot" }, + { 0x516E7CB4, 0, "FreeBSD Data" }, + { 0x516E7CB5, 0, "FreeBSD Swap" }, + { 0x516E7CB6, "ufs", "FreeBSD UFS" }, + { 0x516E7CB8, 0, "FreeBSD Vinum" }, + { 0x516E7CB8, "zfs", "FreeBSD ZFS" }, + + { 0x48465300, "hfsx", "HFS+" }, +}; + +static int FindPartType(const Byte *guid) +{ + UInt32 val = Get32(guid); + for (unsigned i = 0; i < ARRAY_SIZE(kPartTypes); i++) + if (kPartTypes[i].Id == val) + return i; + return -1; +} + +static inline char GetHex(unsigned t) { return (char)(((t < 10) ? ('0' + t) : ('A' + (t - 10)))); } + +static void PrintHex(unsigned v, char *s) +{ + s[0] = GetHex((v >> 4) & 0xF); + s[1] = GetHex(v & 0xF); +} + +static void ConvertUInt16ToHex4Digits(UInt32 val, char *s) throw() +{ + PrintHex(val >> 8, s); + PrintHex(val & 0xFF, s + 2); +} + +static void GuidToString(const Byte *g, char *s) +{ + ConvertUInt32ToHex8Digits(Get32(g ), s); s += 8; *s++ = '-'; + ConvertUInt16ToHex4Digits(Get16(g + 4), s); s += 4; *s++ = '-'; + ConvertUInt16ToHex4Digits(Get16(g + 6), s); s += 4; *s++ = '-'; + for (unsigned i = 0; i < 8; i++) + { + if (i == 2) + *s++ = '-'; + PrintHex(g[8 + i], s); + s += 2; + } + *s = 0; +} + + +class CHandler: public CHandlerCont +{ + CRecordVector _items; + UInt64 _totalSize; + Byte Guid[16]; + + CByteBuffer _buffer; + + HRESULT Open2(IInStream *stream); + virtual UInt64 GetItemPos(UInt32 index) const { return _items[index].GetPos(); } + virtual UInt64 GetItemSize(UInt32 index) const { return _items[index].GetSize(); } +public: + INTERFACE_IInArchive_Cont(;) +}; + + +HRESULT CHandler::Open2(IInStream *stream) +{ + _buffer.Alloc(kSectorSize * 2); + RINOK(ReadStream_FALSE(stream, _buffer, kSectorSize * 2)); + + const Byte *buf = _buffer; + if (buf[0x1FE] != 0x55 || buf[0x1FF] != 0xAA) + return S_FALSE; + + buf += kSectorSize; + if (memcmp(buf, k_Signature, k_SignatureSize) != 0) + return S_FALSE; + { + // if (Get32(buf + 8) != 0x10000) return S_FALSE; // revision + UInt32 headerSize = Get32(buf + 12); // = 0x5C usually + if (headerSize > kSectorSize) + return S_FALSE; + UInt32 crc = Get32(buf + 0x10); + SetUi32(_buffer + kSectorSize + 0x10, 0); + if (CrcCalc(_buffer + kSectorSize, headerSize) != crc) + return S_FALSE; + } + // UInt32 reserved = Get32(buf + 0x14); + UInt64 curLba = Get64(buf + 0x18); + if (curLba != 1) + return S_FALSE; + UInt64 backupLba = Get64(buf + 0x20); + // UInt64 firstUsableLba = Get64(buf + 0x28); + // UInt64 lastUsableLba = Get64(buf + 0x30); + memcpy(Guid, buf + 0x38, 16); + UInt64 tableLba = Get64(buf + 0x48); + if (tableLba < 2) + return S_FALSE; + UInt32 numEntries = Get32(buf + 0x50); + UInt32 entrySize = Get32(buf + 0x54); // = 128 usually + UInt32 entriesCrc = Get32(buf + 0x58); + + if (entrySize < 128 + || entrySize > (1 << 12) + || numEntries > (1 << 16) + || tableLba < 2 + || tableLba >= ((UInt64)1 << (64 - 10))) + return S_FALSE; + + UInt32 tableSize = entrySize * numEntries; + UInt32 tableSizeAligned = (tableSize + kSectorSize - 1) & ~(kSectorSize - 1); + _buffer.Alloc(tableSizeAligned); + UInt64 tableOffset = tableLba * kSectorSize; + RINOK(stream->Seek(tableOffset, STREAM_SEEK_SET, NULL)); + RINOK(ReadStream_FALSE(stream, _buffer, tableSizeAligned)); + + if (CrcCalc(_buffer, tableSize) != entriesCrc) + return S_FALSE; + + _totalSize = tableOffset + tableSizeAligned; + + for (UInt32 i = 0; i < numEntries; i++) + { + CPartition item; + item.Parse(_buffer + i * entrySize); + if (item.IsUnused()) + continue; + UInt64 endPos = item.GetEnd(); + if (_totalSize < endPos) + _totalSize = endPos; + _items.Add(item); + } + + UInt64 end = (backupLba + 1) * kSectorSize; + if (_totalSize < end) + _totalSize = end; + + return S_OK; +} + +STDMETHODIMP CHandler::Open(IInStream *stream, + const UInt64 * /* maxCheckStartPosition */, + IArchiveOpenCallback * /* openArchiveCallback */) +{ + COM_TRY_BEGIN + Close(); + RINOK(Open2(stream)); + _stream = stream; + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::Close() +{ + _totalSize = 0; + memset(Guid, 0, sizeof(Guid)); + _items.Clear(); + _stream.Release(); + return S_OK; +} + +static const Byte kProps[] = +{ + kpidPath, + kpidSize, + kpidFileSystem, + kpidCharacts, + kpidOffset, + kpidId +}; + +static const Byte kArcProps[] = +{ + kpidId +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + switch (propID) + { + case kpidMainSubfile: + { + if (_items.Size() == 1) + prop = (UInt32)0; + break; + } + case kpidPhySize: prop = _totalSize; break; + case kpidId: + { + char s[48]; + GuidToString(Guid, s); + prop = s; + break; + } + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = _items.Size(); + return S_OK; +} + +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + + const CPartition &item = _items[index]; + + switch (propID) + { + case kpidPath: + { + UString s; + for (unsigned i = 0; i < kNameLen; i++) + { + wchar_t c = (wchar_t)Get16(item.Name + i * 2); + if (c == 0) + break; + s += c; + } + { + int typeIndex = FindPartType(item.Type); + s += L'.'; + const char *ext = "img"; + if (typeIndex >= 0 && kPartTypes[(unsigned)typeIndex].Ext) + ext = kPartTypes[(unsigned)typeIndex].Ext; + s.AddAscii(ext); + } + prop = s; + break; + } + + case kpidSize: + case kpidPackSize: prop = item.GetSize(); break; + case kpidOffset: prop = item.GetPos(); break; + + case kpidFileSystem: + { + char s[48]; + const char *res; + int typeIndex = FindPartType(item.Type); + if (typeIndex >= 0 && kPartTypes[(unsigned)typeIndex].Type) + res = kPartTypes[(unsigned)typeIndex].Type; + else + { + GuidToString(item.Type, s); + res = s; + } + prop = res; + break; + } + + case kpidId: + { + char s[48]; + GuidToString(item.Id, s); + prop = s; + break; + } + + case kpidCharacts: FLAGS64_TO_PROP(g_PartitionFlags, item.Flags, prop); break; + } + + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +REGISTER_ARC_I( + "GPT", "gpt mbr", NULL, 0xCB, + k_Signature, + kSectorSize, + 0, + NULL) + +}} diff --git a/CPP/7zip/Archive/HandlerCont.cpp b/CPP/7zip/Archive/HandlerCont.cpp new file mode 100644 index 00000000..23a184f2 --- /dev/null +++ b/CPP/7zip/Archive/HandlerCont.cpp @@ -0,0 +1,230 @@ +// HandlerCont.cpp + +#include "StdAfx.h" + +#include "../../Common/ComTry.h" + +#include "../Common/LimitedStreams.h" +#include "../Common/ProgressUtils.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/CopyCoder.h" + +#include "HandlerCont.h" + +namespace NArchive { + +STDMETHODIMP CHandlerCont::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + bool allFilesMode = (numItems == (UInt32)(Int32)-1); + if (allFilesMode) + { + RINOK(GetNumberOfItems(&numItems)); + } + if (numItems == 0) + return S_OK; + UInt64 totalSize = 0; + UInt32 i; + for (i = 0; i < numItems; i++) + totalSize += GetItemSize(allFilesMode ? i : indices[i]); + extractCallback->SetTotal(totalSize); + + totalSize = 0; + + NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); + CMyComPtr copyCoder = copyCoderSpec; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(extractCallback, false); + + CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; + CMyComPtr inStream(streamSpec); + streamSpec->SetStream(_stream); + + for (i = 0; i < numItems; i++) + { + lps->InSize = totalSize; + lps->OutSize = totalSize; + RINOK(lps->SetCur()); + CMyComPtr outStream; + Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + Int32 index = allFilesMode ? i : indices[i]; + + RINOK(extractCallback->GetStream(index, &outStream, askMode)); + UInt64 size = GetItemSize(index); + totalSize += size; + if (!testMode && !outStream) + continue; + RINOK(extractCallback->PrepareOperation(askMode)); + + RINOK(_stream->Seek(GetItemPos(index), STREAM_SEEK_SET, NULL)); + streamSpec->Init(size); + RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)); + outStream.Release(); + int opRes = NExtract::NOperationResult::kDataError; + if (copyCoderSpec->TotalSize == size) + opRes = NExtract::NOperationResult::kOK; + else if (copyCoderSpec->TotalSize < size) + opRes = NExtract::NOperationResult::kUnexpectedEnd; + RINOK(extractCallback->SetOperationResult(opRes)); + } + + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandlerCont::GetStream(UInt32 index, ISequentialInStream **stream) +{ + COM_TRY_BEGIN + // const CPartition &item = _items[index]; + return CreateLimitedInStream(_stream, GetItemPos(index), GetItemSize(index), stream); + COM_TRY_END +} + + + +STDMETHODIMP CHandlerImg::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) +{ + switch (seekOrigin) + { + case STREAM_SEEK_SET: break; + case STREAM_SEEK_CUR: offset += _virtPos; break; + case STREAM_SEEK_END: offset += _size; break; + default: return STG_E_INVALIDFUNCTION; + } + if (offset < 0) + return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; + _virtPos = offset; + if (newPosition) + *newPosition = offset; + return S_OK; +} + +static const Byte k_GDP_Signature[] = { 'E', 'F', 'I', ' ', 'P', 'A', 'R', 'T' }; + +static const char *GetImgExt(ISequentialInStream *stream) +{ + const size_t kHeaderSize = 1 << 10; + Byte buf[kHeaderSize]; + if (ReadStream_FAIL(stream, buf, kHeaderSize) == S_OK) + { + if (buf[0x1FE] == 0x55 && buf[0x1FF] == 0xAA) + { + if (memcmp(buf + 512, k_GDP_Signature, sizeof(k_GDP_Signature)) == 0) + return "gpt"; + return "mbr"; + } + } + return NULL; +} + +void CHandlerImg::CloseAtError() +{ + Stream.Release(); +} + +STDMETHODIMP CHandlerImg::Open(IInStream *stream, + const UInt64 * /* maxCheckStartPosition */, + IArchiveOpenCallback * openCallback) +{ + COM_TRY_BEGIN + { + Close(); + HRESULT res; + try + { + res = Open2(stream, openCallback); + if (res == S_OK) + { + CMyComPtr inStream; + HRESULT res2 = GetStream(0, &inStream); + if (res2 == S_OK && inStream) + _imgExt = GetImgExt(inStream); + return S_OK; + } + } + catch(...) + { + CloseAtError(); + throw; + } + CloseAtError(); + return res; + } + COM_TRY_END +} + +STDMETHODIMP CHandlerImg::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = 1; + return S_OK; +} + +STDMETHODIMP CHandlerImg::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + if (numItems == 0) + return S_OK; + if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) + return E_INVALIDARG; + + RINOK(extractCallback->SetTotal(_size)); + CMyComPtr outStream; + Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + RINOK(extractCallback->GetStream(0, &outStream, askMode)); + if (!testMode && !outStream) + return S_OK; + RINOK(extractCallback->PrepareOperation(askMode)); + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(extractCallback, false); + + int opRes = NExtract::NOperationResult::kDataError; + + CMyComPtr inStream; + HRESULT hres = GetStream(0, &inStream); + if (hres == S_FALSE) + hres = E_NOTIMPL; + + if (hres == S_OK && inStream) + { + NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); + CMyComPtr copyCoder = copyCoderSpec; + + hres = copyCoder->Code(inStream, outStream, NULL, &_size, progress); + if (hres == S_OK) + { + if (copyCoderSpec->TotalSize == _size) + opRes = NExtract::NOperationResult::kOK; + else if (copyCoderSpec->TotalSize < _size) + opRes = NExtract::NOperationResult::kUnexpectedEnd; + } + } + + inStream.Release(); + outStream.Release(); + + if (hres != S_OK) + { + if (hres == S_FALSE) + opRes = NExtract::NOperationResult::kDataError; + else if (hres == E_NOTIMPL) + opRes = NExtract::NOperationResult::kUnsupportedMethod; + else + return hres; + } + + return extractCallback->SetOperationResult(opRes); + COM_TRY_END +} + +} diff --git a/CPP/7zip/Archive/HandlerCont.h b/CPP/7zip/Archive/HandlerCont.h new file mode 100644 index 00000000..603a6511 --- /dev/null +++ b/CPP/7zip/Archive/HandlerCont.h @@ -0,0 +1,90 @@ +// HandlerCont.h + +#ifndef __HANDLER_CONT_H +#define __HANDLER_CONT_H + +#include "../../Common/MyCom.h" + +#include "IArchive.h" + +namespace NArchive { + +#define INTERFACE_IInArchive_Cont(x) \ + STDMETHOD(Open)(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *openCallback) MY_NO_THROW_DECL_ONLY x; \ + STDMETHOD(Close)() MY_NO_THROW_DECL_ONLY x; \ + STDMETHOD(GetNumberOfItems)(UInt32 *numItems) MY_NO_THROW_DECL_ONLY x; \ + STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value) MY_NO_THROW_DECL_ONLY x; \ + /* STDMETHOD(Extract)(const UInt32* indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) MY_NO_THROW_DECL_ONLY x; */ \ + STDMETHOD(GetArchiveProperty)(PROPID propID, PROPVARIANT *value) MY_NO_THROW_DECL_ONLY x; \ + STDMETHOD(GetNumberOfProperties)(UInt32 *numProps) MY_NO_THROW_DECL_ONLY x; \ + STDMETHOD(GetPropertyInfo)(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) MY_NO_THROW_DECL_ONLY x; \ + STDMETHOD(GetNumberOfArchiveProperties)(UInt32 *numProps) MY_NO_THROW_DECL_ONLY x; \ + STDMETHOD(GetArchivePropertyInfo)(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) MY_NO_THROW_DECL_ONLY x; \ + + +class CHandlerCont: + public IInArchive, + public IInArchiveGetStream, + public CMyUnknownImp +{ +protected: + CMyComPtr _stream; + + virtual UInt64 GetItemPos(UInt32 index) const = 0; + virtual UInt64 GetItemSize(UInt32 index) const = 0; +public: + MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) + INTERFACE_IInArchive_Cont(PURE) + + STDMETHOD(Extract)(const UInt32* indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) MY_NO_THROW_DECL_ONLY; + + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); +}; + + + +#define INTERFACE_IInArchive_Img(x) \ + /* STDMETHOD(Open)(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *openCallback) MY_NO_THROW_DECL_ONLY x; */ \ + STDMETHOD(Close)() MY_NO_THROW_DECL_ONLY x; \ + /* STDMETHOD(GetNumberOfItems)(UInt32 *numItems) MY_NO_THROW_DECL_ONLY x; */ \ + STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value) MY_NO_THROW_DECL_ONLY x; \ + /* STDMETHOD(Extract)(const UInt32* indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) MY_NO_THROW_DECL_ONLY x; */ \ + STDMETHOD(GetArchiveProperty)(PROPID propID, PROPVARIANT *value) MY_NO_THROW_DECL_ONLY x; \ + STDMETHOD(GetNumberOfProperties)(UInt32 *numProps) MY_NO_THROW_DECL_ONLY x; \ + STDMETHOD(GetPropertyInfo)(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) MY_NO_THROW_DECL_ONLY x; \ + STDMETHOD(GetNumberOfArchiveProperties)(UInt32 *numProps) MY_NO_THROW_DECL_ONLY x; \ + STDMETHOD(GetArchivePropertyInfo)(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) MY_NO_THROW_DECL_ONLY x; \ + + +class CHandlerImg: + public IInStream, + public IInArchive, + public IInArchiveGetStream, + public CMyUnknownImp +{ +protected: + UInt64 _virtPos; + UInt64 _posInArc; + UInt64 _size; + CMyComPtr Stream; + const char *_imgExt; + + virtual HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openCallback) = 0; + virtual void CloseAtError(); +public: + MY_UNKNOWN_IMP3(IInArchive, IInArchiveGetStream, IInStream) + INTERFACE_IInArchive_Img(PURE) + + STDMETHOD(Open)(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *openCallback); + STDMETHOD(GetNumberOfItems)(UInt32 *numItems); + STDMETHOD(Extract)(const UInt32* indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback); + + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream) = 0; + + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize) = 0; + STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); +}; + +} + +#endif diff --git a/CPP/7zip/Archive/MachoHandler.cpp b/CPP/7zip/Archive/MachoHandler.cpp index 00dc571b..9dae1e70 100644 --- a/CPP/7zip/Archive/MachoHandler.cpp +++ b/CPP/7zip/Archive/MachoHandler.cpp @@ -40,7 +40,7 @@ namespace NMacho { #define CPU_SUBTYPE_LIB64 (1 << 31) -#define CPU_SUBTYPE_POWERPC_970 100 +#define CPU_SUBTYPE_POWERPC_970 100 static const char * const k_PowerPc_SubTypes[] = { diff --git a/CPP/7zip/Archive/MbrHandler.cpp b/CPP/7zip/Archive/MbrHandler.cpp index c4e4cc60..5135e5f8 100644 --- a/CPP/7zip/Archive/MbrHandler.cpp +++ b/CPP/7zip/Archive/MbrHandler.cpp @@ -13,16 +13,13 @@ #include "../../Common/ComTry.h" #include "../../Common/IntToString.h" #include "../../Common/MyBuffer.h" -#include "../../Common/MyString.h" #include "../../Windows/PropVariant.h" -#include "../Common/LimitedStreams.h" -#include "../Common/ProgressUtils.h" #include "../Common/RegisterArc.h" #include "../Common/StreamUtils.h" -#include "../Compress/CopyCoder.h" +#include "HandlerCont.h" #ifdef SHOW_DEBUG_INFO #define PRF(x) x @@ -56,12 +53,15 @@ struct CChs #define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; } +// Chs in some MBRs contains only low bits of "Cyl number". So we disable check. +/* static int CompareChs(const CChs &c1, const CChs &c2) { RINOZ(MyCompare(c1.GetCyl(), c2.GetCyl())); RINOZ(MyCompare(c1.Head, c2.Head)); return MyCompare(c1.GetSector(), c2.GetSector()); } +*/ static void AddUIntToString(UInt32 val, AString &res) { @@ -112,12 +112,11 @@ struct CPartition return true; if (Status != 0 && Status != 0x80) return false; - return - BeginChs.Check() && - EndChs.Check() && - CompareChs(BeginChs, EndChs) <= 0 && - NumBlocks > 0 && - CheckLbaLimits(); + return BeginChs.Check() + && EndChs.Check() + // && CompareChs(BeginChs, EndChs) <= 0 + && NumBlocks > 0 + && CheckLbaLimits(); } #ifdef SHOW_DEBUG_INFO @@ -159,11 +158,12 @@ static const CPartType kPartTypes[] = { 0x1E, kFat, "FAT16-LBA-WIN95-Hidden" }, { 0x82, 0, "Solaris x86 / Linux swap" }, { 0x83, 0, "Linux" }, + { 0xA5, 0, "BSD slice" }, { 0xBE, 0, "Solaris 8 boot" }, { 0xBF, 0, "New Solaris x86" }, { 0xC2, 0, "Linux-Hidden" }, { 0xC3, 0, "Linux swap-Hidden" }, - { 0xEE, 0, "EFI-MBR" }, + { 0xEE, 0, "GPT" }, { 0xEE, 0, "EFI" } }; @@ -183,21 +183,17 @@ struct CItem CPartition Part; }; -class CHandler: - public IInArchive, - public IInArchiveGetStream, - public CMyUnknownImp +class CHandler: public CHandlerCont { - CMyComPtr _stream; CObjectVector _items; UInt64 _totalSize; CByteBuffer _buffer; + virtual UInt64 GetItemPos(UInt32 index) const { return _items[index].Part.GetPos(); } + virtual UInt64 GetItemSize(UInt32 index) const { return _items[index].Size; } HRESULT ReadTables(IInStream *stream, UInt32 baseLba, UInt32 lba, unsigned level); public: - MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) - INTERFACE_IInArchive(;) - STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); + INTERFACE_IInArchive_Cont(;) }; HRESULT CHandler::ReadTables(IInStream *stream, UInt32 baseLba, UInt32 lba, unsigned level) @@ -391,7 +387,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val const CItem &item = _items[index]; const CPartition &part = item.Part; - switch(propID) + switch (propID) { case kpidPath: { @@ -421,7 +417,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val prop = res; } break; - case kpidSize: prop = item.Size; break;; + case kpidSize: case kpidPackSize: prop = item.Size; break; case kpidOffset: prop = part.GetPos(); break; case kpidPrimary: if (item.IsReal) prop = item.IsPrim; break; @@ -433,72 +429,6 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val COM_TRY_END } -STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback) -{ - COM_TRY_BEGIN - bool allFilesMode = (numItems == (UInt32)(Int32)-1); - if (allFilesMode) - numItems = _items.Size(); - if (numItems == 0) - return S_OK; - UInt64 totalSize = 0; - UInt32 i; - for (i = 0; i < numItems; i++) - totalSize += _items[allFilesMode ? i : indices[i]].Size; - extractCallback->SetTotal(totalSize); - - totalSize = 0; - - NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); - CMyComPtr copyCoder = copyCoderSpec; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(extractCallback, false); - - CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; - CMyComPtr inStream(streamSpec); - streamSpec->SetStream(_stream); - - for (i = 0; i < numItems; i++) - { - lps->InSize = totalSize; - lps->OutSize = totalSize; - RINOK(lps->SetCur()); - CMyComPtr outStream; - Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - Int32 index = allFilesMode ? i : indices[i]; - const CItem &item = _items[index]; - const CPartition &part = item.Part; - RINOK(extractCallback->GetStream(index, &outStream, askMode)); - totalSize += item.Size; - if (!testMode && !outStream) - continue; - RINOK(extractCallback->PrepareOperation(askMode)); - - RINOK(_stream->Seek(part.GetPos(), STREAM_SEEK_SET, NULL)); - streamSpec->Init(item.Size); - RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)); - outStream.Release(); - RINOK(extractCallback->SetOperationResult(copyCoderSpec->TotalSize == item.Size ? - NExtract::NOperationResult::kOK: - NExtract::NOperationResult::kDataError)); - } - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) -{ - COM_TRY_BEGIN - const CItem &item = _items[index]; - return CreateLimitedInStream(_stream, item.Part.GetPos(), item.Size, stream); - COM_TRY_END -} - // 3, { 1, 1, 0 }, // 2, { 0x55, 0x1FF }, diff --git a/CPP/7zip/Archive/MubHandler.cpp b/CPP/7zip/Archive/MubHandler.cpp index a84c3120..05ea4d9f 100644 --- a/CPP/7zip/Archive/MubHandler.cpp +++ b/CPP/7zip/Archive/MubHandler.cpp @@ -10,12 +10,10 @@ #include "../../Windows/PropVariant.h" -#include "../Common/LimitedStreams.h" -#include "../Common/ProgressUtils.h" #include "../Common/RegisterArc.h" #include "../Common/StreamUtils.h" -#include "../Compress/CopyCoder.h" +#include "HandlerCont.h" static UInt32 Get32(const Byte *p, bool be) { if (be) return GetBe32(p); return GetUi32(p); } @@ -36,7 +34,7 @@ namespace NMub { #define MACH_CPU_SUBTYPE_LIB64 (1 << 31) -#define MACH_CPU_SUBTYPE_I386_ALL 3 +#define MACH_CPU_SUBTYPE_I386_ALL 3 struct CItem { @@ -49,12 +47,8 @@ struct CItem static const UInt32 kNumFilesMax = 10; -class CHandler: - public IInArchive, - public IInArchiveGetStream, - public CMyUnknownImp +class CHandler: public CHandlerCont { - CMyComPtr _stream; // UInt64 _startPos; UInt64 _phySize; UInt32 _numItems; @@ -62,10 +56,10 @@ class CHandler: CItem _items[kNumFilesMax]; HRESULT Open2(IInStream *stream); + virtual UInt64 GetItemPos(UInt32 index) const { return _items[index].Offset; } + virtual UInt64 GetItemSize(UInt32 index) const { return _items[index].Size; } public: - MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) - INTERFACE_IInArchive(;) - STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); + INTERFACE_IInArchive_Cont(;) }; static const Byte kArcProps[] = @@ -223,75 +217,6 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) return S_OK; } -STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback) -{ - COM_TRY_BEGIN - bool allFilesMode = (numItems == (UInt32)(Int32)-1); - if (allFilesMode) - numItems = _numItems; - if (numItems == 0) - return S_OK; - UInt64 totalSize = 0; - UInt32 i; - for (i = 0; i < numItems; i++) - totalSize += _items[allFilesMode ? i : indices[i]].Size; - extractCallback->SetTotal(totalSize); - - UInt64 currentTotalSize = 0; - - NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); - CMyComPtr copyCoder = copyCoderSpec; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(extractCallback, false); - - CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; - CMyComPtr inStream(streamSpec); - streamSpec->SetStream(_stream); - - for (i = 0; i < numItems; i++) - { - lps->InSize = lps->OutSize = currentTotalSize; - RINOK(lps->SetCur()); - CMyComPtr realOutStream; - Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - UInt32 index = allFilesMode ? i : indices[i]; - const CItem &item = _items[index]; - RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); - currentTotalSize += item.Size; - - if (!testMode && !realOutStream) - continue; - RINOK(extractCallback->PrepareOperation(askMode)); - if (testMode) - { - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); - continue; - } - RINOK(_stream->Seek(/* _startPos + */ item.Offset, STREAM_SEEK_SET, NULL)); - streamSpec->Init(item.Size); - RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress)); - realOutStream.Release(); - RINOK(extractCallback->SetOperationResult((copyCoderSpec->TotalSize == item.Size) ? - NExtract::NOperationResult::kOK: - NExtract::NOperationResult::kDataError)); - } - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) -{ - COM_TRY_BEGIN - const CItem &item = _items[index]; - return CreateLimitedInStream(_stream, /* _startPos + */ item.Offset, item.Size, stream); - COM_TRY_END -} - namespace NBe { static const Byte k_Signature[] = { diff --git a/CPP/7zip/Archive/NtfsHandler.cpp b/CPP/7zip/Archive/NtfsHandler.cpp index ee630a66..67cd385f 100644 --- a/CPP/7zip/Archive/NtfsHandler.cpp +++ b/CPP/7zip/Archive/NtfsHandler.cpp @@ -2514,8 +2514,8 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val attrib |= FILE_ATTRIBUTE_DIRECTORY; /* some system entries can contain extra flags (Index View). - // 0x10000000 (Directory) - // 0x20000000 FILE_ATTR_VIEW_INDEX_PRESENT MFT_RECORD_IS_VIEW_INDEX (Index View) + // 0x10000000 (Directory) + // 0x20000000 FILE_ATTR_VIEW_INDEX_PRESENT MFT_RECORD_IS_VIEW_INDEX (Index View) But we don't need them */ attrib &= 0xFFFF; diff --git a/CPP/7zip/Archive/QcowHandler.cpp b/CPP/7zip/Archive/QcowHandler.cpp new file mode 100644 index 00000000..42c0a511 --- /dev/null +++ b/CPP/7zip/Archive/QcowHandler.cpp @@ -0,0 +1,611 @@ +// QcowHandler.cpp + +#include "StdAfx.h" + +// #include + +#include "../../../C/CpuArch.h" + +#include "../../Common/ComTry.h" +#include "../../Common/IntToString.h" + +#include "../../Windows/PropVariant.h" + +#include "../Common/RegisterArc.h" +#include "../Common/StreamObjects.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/DeflateDecoder.h" + +#include "HandlerCont.h" + +#define Get32(p) GetBe32(p) +#define Get64(p) GetBe64(p) + +using namespace NWindows; + +namespace NArchive { +namespace NQcow { + +#define SIGNATURE { 'Q', 'F', 'I', 0xFB, 0, 0, 0 } + +static const Byte k_Signature[] = SIGNATURE; + +class CHandler: public CHandlerImg +{ + unsigned _clusterBits; + unsigned _numMidBits; + UInt64 _compressedFlag; + + CObjectVector _tables; + UInt64 _cacheCluster; + CByteBuffer _cache; + CByteBuffer _cacheCompressed; + + UInt64 _comprPos; + size_t _comprSize; + + UInt64 _phySize; + + CBufInStream *_bufInStreamSpec; + CMyComPtr _bufInStream; + + CBufPtrSeqOutStream *_bufOutStreamSpec; + CMyComPtr _bufOutStream; + + NCompress::NDeflate::NDecoder::CCOMCoder *_deflateDecoderSpec; + CMyComPtr _deflateDecoder; + + bool _needDeflate; + bool _isArc; + bool _unsupported; + + UInt32 _version; + UInt32 _cryptMethod; + + HRESULT Seek(UInt64 offset) + { + _posInArc = offset; + return Stream->Seek(offset, STREAM_SEEK_SET, NULL); + } + + HRESULT InitAndSeek() + { + _virtPos = 0; + return Seek(0); + } + + HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openCallback); + +public: + INTERFACE_IInArchive_Img(;) + + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); +}; + + +STDMETHODIMP CHandler::Read(void *data, UInt32 size, UInt32 *processedSize) +{ + if (processedSize) + *processedSize = 0; + if (_virtPos >= _size) + return S_OK; + { + UInt64 rem = _size - _virtPos; + if (size > rem) + size = (UInt32)rem; + if (size == 0) + return S_OK; + } + + for (;;) + { + UInt64 cluster = _virtPos >> _clusterBits; + size_t clusterSize = (size_t)1 << _clusterBits; + size_t lowBits = (size_t)_virtPos & (clusterSize - 1); + { + size_t rem = clusterSize - lowBits; + if (size > rem) + size = (UInt32)rem; + } + + if (cluster == _cacheCluster) + { + memcpy(data, _cache + lowBits, size); + _virtPos += size; + if (processedSize) + *processedSize = size; + return S_OK; + } + + UInt64 high = cluster >> _numMidBits; + + if (high < _tables.Size()) + { + const CByteBuffer &buffer = _tables[(unsigned)high]; + + if (buffer.Size() != 0) + { + size_t midBits = (size_t)cluster & (((size_t)1 << _numMidBits) - 1); + const Byte *p = (const Byte *)buffer + (midBits << 3); + UInt64 v = Get64(p); + + if (v != 0) + { + if ((v & _compressedFlag) != 0) + { + if (_version <= 1) + return E_FAIL; + unsigned numOffsetBits = (62 - (_clusterBits - 8)); + UInt64 offset = v & (((UInt64)1 << 62) - 1); + const size_t dataSize = ((size_t)(offset >> numOffsetBits) + 1) << 9; + offset &= ((UInt64)1 << numOffsetBits) - 1; + UInt64 sectorOffset = offset >> 9 << 9; + UInt64 offset2inCache = sectorOffset - _comprPos; + + if (sectorOffset >= _comprPos && offset2inCache < _comprSize) + { + if (offset2inCache != 0) + { + _comprSize -= (size_t)offset2inCache; + memmove(_cacheCompressed, _cacheCompressed + offset2inCache, _comprSize); + _comprPos = sectorOffset; + } + sectorOffset += _comprSize; + } + else + { + _comprPos = sectorOffset; + _comprSize = 0; + } + + // printf("\nDeflate"); + if (sectorOffset != _posInArc) + { + // printf("\nDeflate %12I64x %12I64x\n", sectorOffset, sectorOffset - _posInArc); + RINOK(Seek(sectorOffset)); + } + + if (_cacheCompressed.Size() < dataSize) + return E_FAIL; + size_t dataSize3 = dataSize - _comprSize; + size_t dataSize2 = dataSize3; + RINOK(ReadStream(Stream, _cacheCompressed + _comprSize, &dataSize2)); + _posInArc += dataSize2; + if (dataSize2 != dataSize3) + return E_FAIL; + _comprSize += dataSize2; + + const size_t kSectorMask = (1 << 9) - 1; + size_t offsetInSector = ((size_t)offset & kSectorMask); + _bufInStreamSpec->Init(_cacheCompressed + offsetInSector, dataSize - offsetInSector); + + _cacheCluster = (UInt64)(Int64)-1; + if (_cache.Size() < clusterSize) + return E_FAIL; + _bufOutStreamSpec->Init(_cache, clusterSize); + + // Do we need to use smaller block than clusterSize for last cluster? + UInt64 blockSize64 = clusterSize; + HRESULT res = _deflateDecoderSpec->Code(_bufInStream, _bufOutStream, NULL, &blockSize64, NULL); + + /* + if (_bufOutStreamSpec->GetPos() != clusterSize) + memset(_cache + _bufOutStreamSpec->GetPos(), 0, clusterSize - _bufOutStreamSpec->GetPos()); + */ + + if (res == S_OK) + if (!_deflateDecoderSpec->IsFinished() + || _bufOutStreamSpec->GetPos() != clusterSize) + res = S_FALSE; + + RINOK(res); + _cacheCluster = cluster; + + continue; + /* + memcpy(data, _cache + lowBits, size); + _virtPos += size; + if (processedSize) + *processedSize = size; + return S_OK; + */ + } + + // version 3 support zero clusters + if (((UInt32)v & 511) != 1) + { + v &= (_compressedFlag - 1); + v += lowBits; + if (v != _posInArc) + { + // printf("\n%12I64x\n", v - _posInArc); + RINOK(Seek(v)); + } + HRESULT res = Stream->Read(data, size, &size); + _posInArc += size; + _virtPos += size; + if (processedSize) + *processedSize = size; + return res; + } + } + } + } + + memset(data, 0, size); + _virtPos += size; + if (processedSize) + *processedSize = size; + return S_OK; + } +} + + +static const Byte kProps[] = +{ + kpidSize, + kpidPackSize +}; + +static const Byte kArcProps[] = +{ + kpidClusterSize, + kpidUnpackVer, + kpidMethod +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + + switch (propID) + { + case kpidMainSubfile: prop = (UInt32)0; break; + case kpidClusterSize: prop = (UInt32)1 << _clusterBits; break; + case kpidPhySize: if (_phySize != 0) prop = _phySize; break; + case kpidUnpackVer: prop = _version; break; + + case kpidMethod: + { + AString s; + + if (_needDeflate) + s = "Deflate"; + + if (_cryptMethod != 0) + { + s.Add_Space_if_NotEmpty(); + if (_cryptMethod == 1) + s += "AES"; + else + { + char temp[16]; + ConvertUInt32ToString(_cryptMethod, temp); + s += temp; + } + } + + if (!s.IsEmpty()) + prop = s; + + break; + } + + case kpidErrorFlags: + { + UInt32 v = 0; + if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;; + if (_unsupported) v |= kpv_ErrorFlags_UnsupportedMethod; + // if (_headerError) v |= kpv_ErrorFlags_HeadersError; + if (!Stream && v == 0 && _isArc) + v = kpv_ErrorFlags_HeadersError; + if (v != 0) + prop = v; + break; + } + } + + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + + switch (propID) + { + case kpidSize: prop = _size; break; + case kpidPackSize: prop = _phySize; break; + case kpidExtension: prop = (_imgExt ? _imgExt : "img"); break; + } + + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openCallback) +{ + const unsigned kHeaderSize = 18 * 4; + Byte buf[kHeaderSize]; + RINOK(ReadStream_FALSE(stream, buf, kHeaderSize)); + + if (memcmp(buf, k_Signature, 4) != 0) + return S_FALSE; + + _version = Get32(buf + 4); + if (_version < 1 || _version > 3) + return S_FALSE; + + const UInt64 backOffset = Get64(buf + 8); + // UInt32 backSize = Get32(buf + 0x10); + + UInt64 l1Offset = 0; + UInt32 l1Size = 0; + + if (_version == 1) + { + // _mTime = Get32(buf + 0x14); // is unused im most images + _size = Get64(buf + 0x18); + _clusterBits = buf[0x20]; + _numMidBits = buf[0x21]; + if (_clusterBits < 9 || _clusterBits > 30) + return S_FALSE; + if (_numMidBits < 1 || _numMidBits > 28) + return S_FALSE; + _cryptMethod = Get32(buf + 0x24); + l1Offset = Get64(buf + 0x28); + if (l1Offset < 0x30) + return S_FALSE; + unsigned numBits2 = (_clusterBits + _numMidBits); + UInt64 l1Size64 = (_size + (((UInt64)1 << numBits2) - 1)) >> numBits2; + if (l1Size64 > ((UInt32)1 << 31)) + return S_FALSE; + l1Size = (UInt32)l1Size64; + } + else + { + _clusterBits = Get32(buf + 0x14); + if (_clusterBits < 9 || _clusterBits > 30) + return S_FALSE; + _numMidBits = _clusterBits - 3; + _size = Get64(buf + 0x18); + _cryptMethod = Get32(buf + 0x20); + l1Size = Get32(buf + 0x24); + l1Offset = Get64(buf + 0x28); // must be aligned for cluster + + UInt64 refOffset = Get64(buf + 0x30); // must be aligned for cluster + UInt32 refClusters = Get32(buf + 0x38); + + // UInt32 numSnapshots = Get32(buf + 0x3C); + // UInt64 snapshotsOffset = Get64(buf + 0x40); // must be aligned for cluster + /* + if (numSnapshots != 0) + return S_FALSE; + */ + + if (refClusters != 0) + { + size_t numBytes = refClusters << _clusterBits; + /* + CByteBuffer refs; + refs.Alloc(numBytes); + RINOK(stream->Seek(refOffset, STREAM_SEEK_SET, NULL)); + RINOK(ReadStream_FALSE(stream, refs, numBytes)); + */ + UInt64 end = refOffset + numBytes; + if (_phySize < end) + _phySize = end; + /* + for (size_t i = 0; i < numBytes; i += 2) + { + UInt32 v = GetBe16((const Byte *)refs + (size_t)i); + if (v == 0) + continue; + } + */ + } + } + + _isArc = true; + + if (backOffset != 0) + { + _unsupported = true; + return S_FALSE; + } + + const size_t clusterSize = (size_t)1 << _clusterBits; + + CByteBuffer table; + { + size_t t1SizeBytes = (size_t)l1Size << 3; + if ((t1SizeBytes >> 3) != l1Size) + return S_FALSE; + table.Alloc(t1SizeBytes); + RINOK(stream->Seek(l1Offset, STREAM_SEEK_SET, NULL)); + RINOK(ReadStream_FALSE(stream, table, t1SizeBytes)); + + { + UInt64 end = l1Offset + t1SizeBytes; + // we need to uses align end for empty qcow files + end = (end + clusterSize - 1) >> _clusterBits << _clusterBits; + if (_phySize < end) + _phySize = end; + } + } + + if (openCallback) + { + UInt64 totalBytes = (UInt64)l1Size << (_numMidBits + 3); + RINOK(openCallback->SetTotal(NULL, &totalBytes)); + } + + _compressedFlag = (_version <= 1) ? ((UInt64)1 << 63) : ((UInt64)1 << 62); + const UInt64 offsetMask = _compressedFlag - 1; + + for (UInt32 i = 0; i < l1Size; i++) + { + if (openCallback) + { + UInt64 numBytes = (UInt64)i << (_numMidBits + 3); + RINOK(openCallback->SetCompleted(NULL, &numBytes)); + } + + UInt64 v = Get64((const Byte *)table + (size_t)i * 8); + v &= offsetMask; + CByteBuffer &buf = _tables.AddNew(); + if (v == 0) + continue; + + buf.Alloc((size_t)1 << (_numMidBits + 3)); + RINOK(stream->Seek(v, STREAM_SEEK_SET, NULL)); + RINOK(ReadStream_FALSE(stream, buf, clusterSize)); + UInt64 end = v + clusterSize; + if (_phySize < end) + _phySize = end; + + for (size_t k = 0; k < clusterSize; k += 8) + { + UInt64 v = Get64((const Byte *)buf + (size_t)k); + if (v == 0) + continue; + UInt64 offset = v & offsetMask; + size_t dataSize = clusterSize; + + if ((v & _compressedFlag) != 0) + { + if (_version <= 1) + { + unsigned numOffsetBits = (63 - _clusterBits); + dataSize = ((size_t)(offset >> numOffsetBits) + 1) << 9; + offset &= ((UInt64)1 << numOffsetBits) - 1; + dataSize = 0; + // offset >>= 9; + // offset <<= 9; + } + else + { + unsigned numOffsetBits = (62 - (_clusterBits - 8)); + dataSize = ((size_t)(offset >> numOffsetBits) + 1) << 9; + offset &= ((UInt64)1 << numOffsetBits) - 1; + offset >>= 9; + offset <<= 9; + } + _needDeflate = true; + } + else + { + UInt32 low = (UInt32)v & 511; + if (low != 0) + { + // version 3 support zero clusters + if (_version < 3 || low != 1) + { + _unsupported = true; + return S_FALSE; + } + } + } + + UInt64 end = offset + dataSize; + if (_phySize < end) + _phySize = end; + } + } + + if (_cryptMethod != 0) + _unsupported = true; + + if (_needDeflate && _version <= 1) // that case was not implemented + _unsupported = true; + + Stream = stream; + return S_OK; +} + + +STDMETHODIMP CHandler::Close() +{ + _tables.Clear(); + _phySize = 0; + _size = 0; + + _cacheCluster = (UInt64)(Int64)-1; + _comprPos = 0; + _comprSize = 0; + _needDeflate = false; + + _isArc = false; + _unsupported = false; + + _imgExt = NULL; + Stream.Release(); + return S_OK; +} + + +STDMETHODIMP CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream) +{ + COM_TRY_BEGIN + *stream = NULL; + + if (_unsupported) + return S_FALSE; + + if (_needDeflate) + { + if (_version <= 1) + return S_FALSE; + + if (!_bufInStream) + { + _bufInStreamSpec = new CBufInStream; + _bufInStream = _bufInStreamSpec; + } + + if (!_bufOutStream) + { + _bufOutStreamSpec = new CBufPtrSeqOutStream(); + _bufOutStream = _bufOutStreamSpec; + } + + if (!_deflateDecoder) + { + _deflateDecoderSpec = new NCompress::NDeflate::NDecoder::CCOMCoder(); + _deflateDecoder = _deflateDecoderSpec; + _deflateDecoderSpec->Set_NeedFinishInput(true); + } + + size_t clusterSize = (size_t)1 << _clusterBits; + _cache.AllocAtLeast(clusterSize); + _cacheCompressed.AllocAtLeast(clusterSize * 2); + } + + CMyComPtr streamTemp = this; + RINOK(InitAndSeek()); + *stream = streamTemp.Detach(); + return S_OK; + COM_TRY_END +} + + +REGISTER_ARC_I( + "QCOW", "qcow qcow2 qcow2c", NULL, 0xCA, + k_Signature, + 0, + 0, + NULL) + +}} diff --git a/CPP/7zip/Archive/Rar/RarVol.h b/CPP/7zip/Archive/Rar/RarVol.h index d0f91de6..2d2ce473 100644 --- a/CPP/7zip/Archive/Rar/RarVol.h +++ b/CPP/7zip/Archive/Rar/RarVol.h @@ -17,110 +17,110 @@ inline bool IsDigit(wchar_t c) class CVolumeName { - bool _first; - bool _newStyle; - UString _unchangedPart; - UString _changedPart; - UString _afterPart; + bool _needChangeForNext; + UString _before; + UString _changed; + UString _after; public: - CVolumeName(): _newStyle(true) {}; + CVolumeName(): _needChangeForNext(true) {}; bool InitName(const UString &name, bool newStyle = true) { - _first = true; - _newStyle = newStyle; + _needChangeForNext = true; + _after.Empty(); + UString base = name; int dotPos = name.ReverseFind_Dot(); - UString basePart = name; if (dotPos >= 0) { - UString ext = name.Ptr(dotPos + 1); + const UString ext = name.Ptr(dotPos + 1); if (ext.IsEqualTo_Ascii_NoCase("rar")) { - _afterPart = name.Ptr(dotPos); - basePart = name.Left(dotPos); + _after = name.Ptr(dotPos); + base.DeleteFrom(dotPos); } else if (ext.IsEqualTo_Ascii_NoCase("exe")) { - _afterPart.SetFromAscii(".rar"); - basePart = name.Left(dotPos); + _after.SetFromAscii(".rar"); + base.DeleteFrom(dotPos); } - else if (!_newStyle) + else if (!newStyle) { if (ext.IsEqualTo_Ascii_NoCase("000") || ext.IsEqualTo_Ascii_NoCase("001") || ext.IsEqualTo_Ascii_NoCase("r00") || ext.IsEqualTo_Ascii_NoCase("r01")) { - _afterPart.Empty(); - _first = false; - _changedPart = ext; - _unchangedPart = name.Left(dotPos + 1); + _changed = ext; + _before = name.Left(dotPos + 1); return true; } } } - if (!_newStyle) + if (newStyle) { - _afterPart.Empty(); - _unchangedPart = basePart; - _unchangedPart += L'.'; - _changedPart.SetFromAscii("r00"); - return true; - } + unsigned i = base.Len(); - if (basePart.IsEmpty()) - return false; - unsigned i = basePart.Len(); - - do - if (!IsDigit(basePart[i - 1])) - break; - while (--i); + for (; i != 0; i--) + if (!IsDigit(base[i - 1])) + break; + + if (i != base.Len()) + { + _before = base.Left(i); + _changed = base.Ptr(i); + return true; + } + } - _unchangedPart = basePart.Left(i); - _changedPart = basePart.Ptr(i); + _after.Empty(); + _before = base; + _before += L'.'; + _changed.SetFromAscii("r00"); + _needChangeForNext = false; return true; } /* void MakeBeforeFirstName() { - unsigned len = _changedPart.Len(); - _changedPart.Empty(); + unsigned len = _changed.Len(); + _changed.Empty(); for (unsigned i = 0; i < len; i++) - _changedPart += L'0'; + _changed += L'0'; } */ UString GetNextName() { - if (_newStyle || !_first) + if (_needChangeForNext) { - unsigned i = _changedPart.Len(); + unsigned i = _changed.Len(); + if (i == 0) + return UString(); for (;;) { - wchar_t c = _changedPart[--i]; + wchar_t c = _changed[--i]; if (c == L'9') { c = L'0'; - _changedPart.ReplaceOneCharAtPos(i, c); + _changed.ReplaceOneCharAtPos(i, c); if (i == 0) { - _changedPart.InsertAtFront(L'1'); + _changed.InsertAtFront(L'1'); break; } continue; } c++; - _changedPart.ReplaceOneCharAtPos(i, c); + _changed.ReplaceOneCharAtPos(i, c); break; } } - _first = false; - return _unchangedPart + _changedPart + _afterPart; + _needChangeForNext = true; + return _before + _changed + _after; } }; diff --git a/CPP/7zip/Archive/RpmHandler.cpp b/CPP/7zip/Archive/RpmHandler.cpp index 268e0837..f3ae78aa 100644 --- a/CPP/7zip/Archive/RpmHandler.cpp +++ b/CPP/7zip/Archive/RpmHandler.cpp @@ -4,21 +4,19 @@ #include "../../../C/CpuArch.h" +#include "../../Common/MyBuffer.h" #include "../../Common/ComTry.h" #include "../../Common/IntToString.h" -#include "../../Common/MyString.h" #include "../../Common/StringConvert.h" #include "../../Common/UTFConvert.h" #include "../../Windows/PropVariant.h" #include "../../Windows/TimeUtils.h" -#include "../Common/LimitedStreams.h" -#include "../Common/ProgressUtils.h" #include "../Common/RegisterArc.h" #include "../Common/StreamUtils.h" -#include "../Compress/CopyCoder.h" +#include "HandlerCont.h" // #define _SHOW_RPM_METADATA @@ -169,13 +167,8 @@ struct CEntry } }; -class CHandler: - public IInArchive, - public IInArchiveGetStream, - public CMyUnknownImp +class CHandler: public CHandlerCont { - CMyComPtr _stream; - UInt64 _headersSize; // is equal to start offset of payload data UInt64 _payloadSize; UInt64 _size; @@ -232,10 +225,11 @@ class CHandler: HRESULT ReadHeader(ISequentialInStream *stream, bool isMainHeader); HRESULT Open2(ISequentialInStream *stream); + + virtual UInt64 GetItemPos(UInt32) const { return _headersSize; } + virtual UInt64 GetItemSize(UInt32) const { return _size; } public: - MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) - INTERFACE_IInArchive(;) - STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); + INTERFACE_IInArchive_Cont(;) }; static const Byte kArcProps[] = @@ -728,50 +722,6 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) return S_OK; } -STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback) -{ - COM_TRY_BEGIN - if (numItems == 0) - return S_OK; - if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) - return E_INVALIDARG; - - RINOK(extractCallback->SetTotal(_size)); - - CMyComPtr outStream; - Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - RINOK(extractCallback->GetStream(0, &outStream, askMode)); - if (!testMode && !outStream) - return S_OK; - RINOK(extractCallback->PrepareOperation(askMode)); - - NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder; - CMyComPtr copyCoder = copyCoderSpec; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(extractCallback, false); - - RINOK(_stream->Seek(_headersSize, STREAM_SEEK_SET, NULL)); - RINOK(copyCoder->Code(_stream, outStream, NULL, &_size, progress)); - outStream.Release(); - Int32 opRes = NExtract::NOperationResult::kOK; - if (copyCoderSpec->TotalSize < _size) - opRes = NExtract::NOperationResult::kUnexpectedEnd; - return extractCallback->SetOperationResult(opRes); - COM_TRY_END -} - -STDMETHODIMP CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream) -{ - COM_TRY_BEGIN - return CreateLimitedInStream(_stream, _headersSize, _size, stream); - COM_TRY_END -} - static const Byte k_Signature[] = { 0xED, 0xAB, 0xEE, 0xDB}; REGISTER_ARC_I( diff --git a/CPP/7zip/Archive/Tar/TarRegister.cpp b/CPP/7zip/Archive/Tar/TarRegister.cpp index f7b256df..5014f04d 100644 --- a/CPP/7zip/Archive/Tar/TarRegister.cpp +++ b/CPP/7zip/Archive/Tar/TarRegister.cpp @@ -12,7 +12,7 @@ namespace NTar { static const Byte k_Signature[] = { 'u', 's', 't', 'a', 'r' }; REGISTER_ARC_IO( - "tar", "tar", 0, 0xEE, + "tar", "tar ova", 0, 0xEE, k_Signature, NFileHeader::kUstarMagic_Offset, NArcInfoFlags::kStartOpen | diff --git a/CPP/7zip/Archive/VdiHandler.cpp b/CPP/7zip/Archive/VdiHandler.cpp new file mode 100644 index 00000000..a8d3fe36 --- /dev/null +++ b/CPP/7zip/Archive/VdiHandler.cpp @@ -0,0 +1,362 @@ +// VdiHandler.cpp + +#include "StdAfx.h" + +// #include + +#include "../../../C/CpuArch.h" + +#include "../../Common/ComTry.h" +#include "../../Common/IntToString.h" +#include "../../Common/MyBuffer.h" + +#include "../../Windows/PropVariant.h" + +#include "../Common/RegisterArc.h" +#include "../Common/StreamUtils.h" + +#include "HandlerCont.h" + +#define Get32(p) GetUi32(p) +#define Get64(p) GetUi64(p) + +using namespace NWindows; + +namespace NArchive { +namespace NVdi { + +#define SIGNATURE { 0x7F, 0x10, 0xDA, 0xBE } + +static const Byte k_Signature[] = SIGNATURE; + +static const unsigned k_ClusterBits = 20; +static const UInt32 k_ClusterSize = (UInt32)1 << k_ClusterBits; +static const UInt32 k_UnusedCluster = 0xFFFFFFFF; + +// static const UInt32 kDiskType_Dynamic = 1; +// static const UInt32 kDiskType_Static = 2; + +static const char * const kDiskTypes[] = +{ + "0" + , "Dynamic" + , "Static" +}; + +class CHandler: public CHandlerImg +{ + UInt32 _dataOffset; + CByteBuffer _table; + UInt64 _phySize; + UInt32 _imageType; + bool _isArc; + bool _unsupported; + + HRESULT Seek(UInt64 offset) + { + _posInArc = offset; + return Stream->Seek(offset, STREAM_SEEK_SET, NULL); + } + + HRESULT InitAndSeek() + { + _virtPos = 0; + return Seek(0); + } + + HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openCallback); + +public: + INTERFACE_IInArchive_Img(;) + + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); +}; + + +STDMETHODIMP CHandler::Read(void *data, UInt32 size, UInt32 *processedSize) +{ + if (processedSize) + *processedSize = 0; + if (_virtPos >= _size) + return S_OK; + { + UInt64 rem = _size - _virtPos; + if (size > rem) + size = (UInt32)rem; + if (size == 0) + return S_OK; + } + + { + UInt64 cluster = _virtPos >> k_ClusterBits; + UInt32 lowBits = (UInt32)_virtPos & (k_ClusterSize - 1); + { + UInt32 rem = k_ClusterSize - lowBits; + if (size > rem) + size = rem; + } + + cluster <<= 2; + if (cluster < _table.Size()) + { + const Byte *p = (const Byte *)_table + (size_t)cluster; + UInt32 v = Get32(p); + if (v != k_UnusedCluster) + { + UInt64 offset = _dataOffset + ((UInt64)v << k_ClusterBits); + offset += lowBits; + if (offset != _posInArc) + { + RINOK(Seek(offset)); + } + HRESULT res = Stream->Read(data, size, &size); + _posInArc += size; + _virtPos += size; + if (processedSize) + *processedSize = size; + return res; + } + } + + memset(data, 0, size); + _virtPos += size; + if (processedSize) + *processedSize = size; + return S_OK; + } +} + + +static const Byte kProps[] = +{ + kpidSize, + kpidPackSize +}; + +static const Byte kArcProps[] = +{ + kpidHeadersSize, + kpidMethod +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + + switch (propID) + { + case kpidMainSubfile: prop = (UInt32)0; break; + case kpidPhySize: if (_phySize != 0) prop = _phySize; break; + case kpidHeadersSize: prop = _dataOffset; break; + + case kpidMethod: + { + char s[16]; + const char *ptr; + if (_imageType < ARRAY_SIZE(kDiskTypes)) + ptr = kDiskTypes[_imageType]; + else + { + ConvertUInt32ToString(_imageType, s); + ptr = s; + } + prop = ptr; + break; + } + + case kpidErrorFlags: + { + UInt32 v = 0; + if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;; + if (_unsupported) v |= kpv_ErrorFlags_UnsupportedMethod; + // if (_headerError) v |= kpv_ErrorFlags_HeadersError; + if (!Stream && v == 0 && _isArc) + v = kpv_ErrorFlags_HeadersError; + if (v != 0) + prop = v; + break; + } + } + + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + + switch (propID) + { + case kpidSize: prop = _size; break; + case kpidPackSize: prop = _phySize - _dataOffset; break; + case kpidExtension: prop = (_imgExt ? _imgExt : "img"); break; + } + + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +static bool IsEmptyGuid(const Byte *data) +{ + for (unsigned i = 0; i < 16; i++) + if (data[i] != 0) + return false; + return true; +} + + +HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback * /* openCallback */) +{ + const unsigned kHeaderSize = 512; + Byte buf[kHeaderSize]; + RINOK(ReadStream_FALSE(stream, buf, kHeaderSize)); + + if (memcmp(buf + 0x40, k_Signature, sizeof(k_Signature)) != 0) + return S_FALSE; + + UInt32 version = Get32(buf + 0x44); + if (version >= 0x20000) + return S_FALSE; + + UInt32 headerSize = Get32(buf + 0x48); + if (headerSize < 0x140 || headerSize > 0x1B8) + return S_FALSE; + + _imageType = Get32(buf + 0x4C); + _dataOffset = Get32(buf + 0x158); + + UInt32 tableOffset = Get32(buf + 0x154); + if (tableOffset < 0x200) + return S_FALSE; + + UInt32 sectorSize = Get32(buf + 0x168); + if (sectorSize != 0x200) + return S_FALSE; + + _size = Get64(buf + 0x170); + _isArc = true; + + if (_imageType > 2) + { + _unsupported = true; + return S_FALSE; + } + + if (_dataOffset < tableOffset) + return S_FALSE; + + UInt32 blockSize = Get32(buf + 0x178); + if (blockSize != ((UInt32)1 << k_ClusterBits)) + { + _unsupported = true; + return S_FALSE; + } + + UInt32 totalBlocks = Get32(buf + 0x180); + + { + UInt64 size2 = (UInt64)totalBlocks << k_ClusterBits; + if (size2 < _size) + { + _unsupported = true; + return S_FALSE; + } + /* + if (size2 > _size) + _size = size2; + */ + } + + if (headerSize >= 0x180) + { + if (!IsEmptyGuid(buf + 0x1A8) || + !IsEmptyGuid(buf + 0x1B8)) + { + _unsupported = true; + return S_FALSE; + } + } + + UInt32 numAllocatedBlocks = Get32(buf + 0x184); + + { + UInt32 tableReserved = _dataOffset - tableOffset; + if ((tableReserved >> 2) < totalBlocks) + return S_FALSE; + } + + _phySize = _dataOffset + ((UInt64)numAllocatedBlocks << k_ClusterBits); + + size_t numBytes = (size_t)totalBlocks * 4; + if ((numBytes >> 2) != totalBlocks) + { + _unsupported = true; + return S_FALSE; + } + + _table.Alloc(numBytes); + RINOK(stream->Seek(tableOffset, STREAM_SEEK_SET, NULL)); + RINOK(ReadStream_FALSE(stream, _table, numBytes)); + + const Byte *data = _table; + for (UInt32 i = 0; i < totalBlocks; i++) + { + UInt32 v = Get32(data + (size_t)i * 4); + if (v == k_UnusedCluster) + continue; + if (v >= numAllocatedBlocks) + return S_FALSE; + } + + Stream = stream; + return S_OK; +} + + +STDMETHODIMP CHandler::Close() +{ + _table.Free(); + _phySize = 0; + _size = 0; + _isArc = false; + _unsupported = false; + + _imgExt = NULL; + Stream.Release(); + return S_OK; +} + + +STDMETHODIMP CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream) +{ + COM_TRY_BEGIN + *stream = NULL; + if (_unsupported) + return S_FALSE; + CMyComPtr streamTemp = this; + RINOK(InitAndSeek()); + *stream = streamTemp.Detach(); + return S_OK; + COM_TRY_END +} + + +REGISTER_ARC_I( + "VDI", "vdi", NULL, 0xC9, + k_Signature, + 0x40, + 0, + NULL) + +}} diff --git a/CPP/7zip/Archive/VhdHandler.cpp b/CPP/7zip/Archive/VhdHandler.cpp index 7508adfa..d7c3ca95 100644 --- a/CPP/7zip/Archive/VhdHandler.cpp +++ b/CPP/7zip/Archive/VhdHandler.cpp @@ -10,11 +10,10 @@ #include "../../Windows/PropVariant.h" #include "../Common/LimitedStreams.h" -#include "../Common/ProgressUtils.h" #include "../Common/RegisterArc.h" #include "../Common/StreamUtils.h" -#include "../Compress/CopyCoder.h" +#include "HandlerCont.h" #define Get16(p) GetBe16(p) #define Get32(p) GetBe32(p) @@ -217,14 +216,8 @@ bool CDynHeader::Parse(const Byte *p) return CheckBlock(p, 1024, 0x24, 0x240 + 8 * 24); } -class CHandler: - public IInStream, - public IInArchive, - public IInArchiveGetStream, - public CMyUnknownImp +class CHandler: public CHandlerImg { - UInt64 _virtPos; - UInt64 _posInArc; UInt64 _posInArcLimit; UInt64 _startOffset; UInt64 _phySize; @@ -235,7 +228,7 @@ class CHandler: CByteBuffer BitMap; UInt32 BitMapTag; UInt32 NumUsedBlocks; - CMyComPtr Stream; + // CMyComPtr Stream; CMyComPtr ParentStream; CHandler *Parent; UString _errorMessage; @@ -309,14 +302,17 @@ class CHandler: HRESULT Open3(); HRESULT Open2(IInStream *stream, CHandler *child, IArchiveOpenCallback *openArchiveCallback, unsigned level); + HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openArchiveCallback) + { + return Open2(stream, NULL, openArchiveCallback, 0); + } + void CloseAtError(); public: - MY_UNKNOWN_IMP3(IInArchive, IInArchiveGetStream, IInStream) + INTERFACE_IInArchive_Img(;) - INTERFACE_IInArchive(;) STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); - STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); }; HRESULT CHandler::Seek(UInt64 offset) { return Stream->Seek(_startOffset + offset, STREAM_SEEK_SET, NULL); } @@ -360,6 +356,7 @@ HRESULT CHandler::Open3() Byte header[kHeaderSize]; RINOK(ReadStream_FALSE(Stream, header, kHeaderSize)); bool headerIsOK = Footer.Parse(header); + _size = Footer.CurrentSize; if (headerIsOK && !Footer.ThereIsDynamic()) { @@ -388,6 +385,7 @@ HRESULT CHandler::Open3() { if (!Footer.Parse(buf)) return S_FALSE; + _size = Footer.CurrentSize; if (Footer.ThereIsDynamic()) return S_FALSE; // we can't open Dynamic Archive backward. _posInArcLimit = Footer.CurrentSize; @@ -594,22 +592,6 @@ STDMETHODIMP CHandler::Read(void *data, UInt32 size, UInt32 *processedSize) return res; } -STDMETHODIMP CHandler::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) -{ - switch (seekOrigin) - { - case STREAM_SEEK_SET: break; - case STREAM_SEEK_CUR: offset += _virtPos; break; - case STREAM_SEEK_END: offset += Footer.CurrentSize; break; - default: return STG_E_INVALIDFUNCTION; - } - if (offset < 0) - return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; - _virtPos = offset; - if (newPosition) - *newPosition = offset; - return S_OK; -} enum { @@ -842,31 +824,7 @@ HRESULT CHandler::Open2(IInStream *stream, CHandler *child, IArchiveOpenCallback return S_OK; } -STDMETHODIMP CHandler::Open(IInStream *stream, - const UInt64 * /* maxCheckStartPosition */, - IArchiveOpenCallback * openArchiveCallback) -{ - COM_TRY_BEGIN - { - HRESULT res; - try - { - res = Open2(stream, NULL, openArchiveCallback, 0); - if (res == S_OK) - return S_OK; - } - catch(...) - { - Close(); - throw; - } - Close(); - return res; - } - COM_TRY_END -} - -STDMETHODIMP CHandler::Close() +void CHandler::CloseAtError() { _phySize = 0; Bat.Clear(); @@ -877,89 +835,40 @@ STDMETHODIMP CHandler::Close() Dyn.Clear(); _errorMessage.Empty(); // _unexpectedEnd = false; - return S_OK; + _imgExt = NULL; } -STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +STDMETHODIMP CHandler::Close() { - *numItems = 1; + CloseAtError(); return S_OK; } STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value) { - // COM_TRY_BEGIN + COM_TRY_BEGIN NCOM::CPropVariant prop; - switch(propID) + switch (propID) { case kpidSize: prop = Footer.CurrentSize; break; case kpidPackSize: prop = GetPackSize(); break; case kpidCTime: VhdTimeToFileTime(Footer.CTime, prop); break; + case kpidExtension: prop = (_imgExt ? _imgExt : "img"); break; + /* case kpidNumCyls: prop = Footer.NumCyls(); break; case kpidNumHeads: prop = Footer.NumHeads(); break; case kpidSectorsPerTrack: prop = Footer.NumSectorsPerTrack(); break; */ } + prop.Detach(value); return S_OK; - // COM_TRY_END -} - -STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback) -{ - COM_TRY_BEGIN - if (numItems == 0) - return S_OK; - if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) - return E_INVALIDARG; - - RINOK(extractCallback->SetTotal(Footer.CurrentSize)); - CMyComPtr outStream; - Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - RINOK(extractCallback->GetStream(0, &outStream, askMode)); - if (!testMode && !outStream) - return S_OK; - RINOK(extractCallback->PrepareOperation(askMode)); - - NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); - CMyComPtr copyCoder = copyCoderSpec; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(extractCallback, false); - - int res = NExtract::NOperationResult::kDataError; - CMyComPtr inStream; - HRESULT hres = GetStream(0, &inStream); - if (hres == S_FALSE) - res = NExtract::NOperationResult::kUnsupportedMethod; - else - { - RINOK(hres); - HRESULT hres = copyCoder->Code(inStream, outStream, NULL, NULL, progress); - if (hres == S_OK) - { - if (copyCoderSpec->TotalSize == Footer.CurrentSize) - res = NExtract::NOperationResult::kOK; - } - else - { - if (hres != S_FALSE) - { - RINOK(hres); - } - } - } - outStream.Release(); - return extractCallback->SetOperationResult(res); COM_TRY_END } + STDMETHODIMP CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream) { COM_TRY_BEGIN @@ -984,7 +893,7 @@ STDMETHODIMP CHandler::GetStream(UInt32 /* index */, ISequentialInStream **strea } REGISTER_ARC_I( - "VHD", "vhd", ".mbr", 0xDC, + "VHD", "vhd", NULL, 0xDC, kSignature, 0, NArcInfoFlags::kUseGlobalOffset, diff --git a/CPP/7zip/Archive/VmdkHandler.cpp b/CPP/7zip/Archive/VmdkHandler.cpp new file mode 100644 index 00000000..4b404e14 --- /dev/null +++ b/CPP/7zip/Archive/VmdkHandler.cpp @@ -0,0 +1,890 @@ +// VmdkHandler.cpp + +#include "StdAfx.h" + +// #include + +#include "../../../C/CpuArch.h" + +#include "../../Common/ComTry.h" +#include "../../Common/IntToString.h" + +#include "../../Windows/PropVariant.h" + +#include "../Common/RegisterArc.h" +#include "../Common/StreamObjects.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/ZlibDecoder.h" + +#include "HandlerCont.h" + +#define Get16(p) GetUi16(p) +#define Get32(p) GetUi32(p) +#define Get64(p) GetUi64(p) + +using namespace NWindows; + +namespace NArchive { +namespace NVmdk { + +#define SIGNATURE { 'K', 'D', 'M', 'V' } + +static const Byte k_Signature[] = SIGNATURE; + +static const UInt32 k_Flags_NL = (UInt32)1 << 0; +static const UInt32 k_Flags_RGD = (UInt32)1 << 1; +static const UInt32 k_Flags_ZeroGrain = (UInt32)1 << 2; +static const UInt32 k_Flags_Compressed = (UInt32)1 << 16; +static const UInt32 k_Flags_Marker = (UInt32)1 << 17; + +static const unsigned k_NumMidBits = 9; // num bits for index in Grain Table + +struct CHeader +{ + UInt32 flags; + UInt32 version; + + UInt64 capacity; + UInt64 grainSize; + UInt64 descriptorOffset; + UInt64 descriptorSize; + + UInt32 numGTEsPerGT; + UInt16 algo; + // Byte uncleanShutdown; + // UInt64 rgdOffset; + UInt64 gdOffset; + UInt64 overHead; + + bool Is_NL() const { return (flags & k_Flags_NL) != 0; }; + bool Is_ZeroGrain() const { return (flags & k_Flags_ZeroGrain) != 0; }; + bool Is_Compressed() const { return (flags & k_Flags_Compressed) != 0; }; + bool Is_Marker() const { return (flags & k_Flags_Marker) != 0; }; + + bool Parse(const Byte *buf); + + bool IsSameImageFor(const CHeader &h) const + { + return flags == h.flags + && version == h.version + && capacity == h.capacity + && grainSize == h.grainSize + && algo == h.algo; + } +}; + +bool CHeader::Parse(const Byte *buf) +{ + if (memcmp(buf, k_Signature, sizeof(k_Signature)) != 0) + return false; + + version = Get32(buf + 0x4); + flags = Get32(buf + 0x8); + capacity = Get64(buf + 0xC); + grainSize = Get64(buf + 0x14); + descriptorOffset = Get64(buf + 0x1C); + descriptorSize = Get64(buf + 0x24); + numGTEsPerGT = Get32(buf + 0x2C); + // rgdOffset = Get64(buf + 0x30); + gdOffset = Get64(buf + 0x38); + overHead = Get64(buf + 0x40); + // uncleanShutdown = buf[0x48]; + algo = Get16(buf + 0x4D); + + if (Is_NL() && Get32(buf + 0x49) != 0x0A0D200A) // do we need Is_NL() check here? + return false; + + return (numGTEsPerGT == (1 << k_NumMidBits)) && (version <= 3); +} + + +enum +{ + k_Marker_END_OF_STREAM = 0, + k_Marker_GRAIN_TABLE = 1, + k_Marker_GRAIN_DIR = 2, + k_Marker_FOOTER = 3 +}; + +struct CMarker +{ + UInt64 NumSectors; + UInt32 SpecSize; // = 0 for metadata sectors + UInt32 Type; + + void Parse(const Byte *p) + { + NumSectors = Get64(p); + SpecSize = Get32(p + 8); + Type = Get32(p + 12); + } +}; + + +struct CDescriptor +{ + AString CID; + AString parentCID; + AString createType; + + AStringVector Extents; + + void Clear() + { + CID.Empty(); + parentCID.Empty(); + createType.Empty(); + Extents.Clear(); + } + + void Parse(const Byte *p, size_t size); +}; + +static bool Str_to_ValName(const AString &s, AString &name, AString &val) +{ + name.Empty(); + val.Empty(); + int qu = s.Find('"'); + int eq = s.Find('='); + if (eq < 0 || (qu >= 0 && eq > qu)) + return false; + name = s.Left(eq); + name.Trim(); + val = s.Ptr(eq + 1); + val.Trim(); + return true; +} + +void CDescriptor::Parse(const Byte *p, size_t size) +{ + Clear(); + + AString s; + AString name; + AString val; + + for (size_t i = 0;; i++) + { + char c = p[i]; + if (i == size || c == 0 || c == 0xA || c == 0xD) + { + if (!s.IsEmpty() && s[0] != '#') + { + if (Str_to_ValName(s, name, val)) + { + if (name.IsEqualTo_Ascii_NoCase("CID")) + CID = val; + else if (name.IsEqualTo_Ascii_NoCase("parentCID")) + parentCID = val; + else if (name.IsEqualTo_Ascii_NoCase("createType")) + createType = val; + } + else + Extents.Add(s); + } + s.Empty(); + if (c == 0 || i >= size) + break; + } + else + s += (char)c; + } +} + + +class CHandler: public CHandlerImg +{ + unsigned _clusterBits; + + CObjectVector _tables; + UInt64 _cacheCluster; + CByteBuffer _cache; + CByteBuffer _cacheCompressed; + + UInt64 _phySize; + + UInt32 _zeroSector; + bool _needDeflate; + bool _isArc; + bool _unsupported; + // bool _headerError; + + CBufInStream *_bufInStreamSpec; + CMyComPtr _bufInStream; + + CBufPtrSeqOutStream *_bufOutStreamSpec; + CMyComPtr _bufOutStream; + + NCompress::NZlib::CDecoder *_zlibDecoderSpec; + CMyComPtr _zlibDecoder; + + CByteBuffer _descriptorBuf; + CDescriptor _descriptor; + + CHeader h; + + + HRESULT Seek(UInt64 offset) + { + _posInArc = offset; + return Stream->Seek(offset, STREAM_SEEK_SET, NULL); + } + + HRESULT InitAndSeek() + { + _virtPos = 0; + return Seek(0); + } + + HRESULT ReadForHeader(IInStream *stream, UInt64 sector, void *data, size_t numSectors); + virtual HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openCallback); + +public: + INTERFACE_IInArchive_Img(;) + + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); +}; + + +STDMETHODIMP CHandler::Read(void *data, UInt32 size, UInt32 *processedSize) +{ + if (processedSize) + *processedSize = 0; + if (_virtPos >= _size) + return S_OK; + { + UInt64 rem = _size - _virtPos; + if (size > rem) + size = (UInt32)rem; + if (size == 0) + return S_OK; + } + + for (;;) + { + const UInt64 cluster = _virtPos >> _clusterBits; + const size_t clusterSize = (size_t)1 << _clusterBits; + const size_t lowBits = (size_t)_virtPos & (clusterSize - 1); + { + size_t rem = clusterSize - lowBits; + if (size > rem) + size = (UInt32)rem; + } + + if (cluster == _cacheCluster) + { + memcpy(data, _cache + lowBits, size); + _virtPos += size; + if (processedSize) + *processedSize = size; + return S_OK; + } + + const UInt64 high = cluster >> k_NumMidBits; + + if (high < _tables.Size()) + { + const CByteBuffer &table = _tables[(unsigned)high]; + + if (table.Size() != 0) + { + const size_t midBits = (size_t)cluster & ((1 << k_NumMidBits) - 1); + const Byte *p = (const Byte *)table + (midBits << 2); + const UInt32 v = Get32(p); + + if (v != 0 && v != _zeroSector) + { + UInt64 offset = (UInt64)v << 9; + if (_needDeflate) + { + if (offset != _posInArc) + { + // printf("\n%12x %12x\n", (unsigned)offset, (unsigned)(offset - _posInArc)); + RINOK(Seek(offset)); + } + + const size_t kStartSize = 1 << 9; + { + size_t curSize = kStartSize; + HRESULT res = ReadStream(Stream, _cacheCompressed, &curSize); + _posInArc += curSize; + RINOK(res); + if (curSize != kStartSize) + return S_FALSE; + } + + if (Get64(_cacheCompressed) != (cluster << (_clusterBits - 9))) + return S_FALSE; + + UInt32 dataSize = Get32(_cacheCompressed + 8); + if (dataSize > ((UInt32)1 << 31)) + return S_FALSE; + + size_t dataSize2 = (size_t)dataSize + 12; + + if (dataSize2 > kStartSize) + { + dataSize2 = (dataSize2 + 511) & ~(size_t)511; + if (dataSize2 > _cacheCompressed.Size()) + return S_FALSE; + size_t curSize = dataSize2 - kStartSize; + const size_t curSize2 = curSize; + HRESULT res = ReadStream(Stream, _cacheCompressed + kStartSize, &curSize); + _posInArc += curSize; + RINOK(res); + if (curSize != curSize2) + return S_FALSE; + } + + _bufInStreamSpec->Init(_cacheCompressed + 12, dataSize); + + _cacheCluster = (UInt64)(Int64)-1; + if (_cache.Size() < clusterSize) + return E_FAIL; + _bufOutStreamSpec->Init(_cache, clusterSize); + + // Do we need to use smaller block than clusterSize for last cluster? + UInt64 blockSize64 = clusterSize; + HRESULT res = _zlibDecoderSpec->Code(_bufInStream, _bufOutStream, NULL, &blockSize64, NULL); + + // if (_bufOutStreamSpec->GetPos() != clusterSize) + // memset(_cache + _bufOutStreamSpec->GetPos(), 0, clusterSize - _bufOutStreamSpec->GetPos()); + + if (res == S_OK) + if (_bufOutStreamSpec->GetPos() != clusterSize + || _zlibDecoderSpec->GetInputProcessedSize() != dataSize) + res = S_FALSE; + + RINOK(res); + _cacheCluster = cluster; + + continue; + /* + memcpy(data, _cache + lowBits, size); + _virtPos += size; + if (processedSize) + *processedSize = size; + return S_OK; + */ + } + { + offset += lowBits; + if (offset != _posInArc) + { + // printf("\n%12x %12x\n", (unsigned)offset, (unsigned)(offset - _posInArc)); + RINOK(Seek(offset)); + } + HRESULT res = Stream->Read(data, size, &size); + _posInArc += size; + _virtPos += size; + if (processedSize) + *processedSize = size; + return res; + } + } + } + } + + memset(data, 0, size); + _virtPos += size; + if (processedSize) + *processedSize = size; + return S_OK; + } +} + + +static const Byte kProps[] = +{ + kpidSize, + kpidPackSize +}; + +static const Byte kArcProps[] = +{ + kpidClusterSize, + kpidHeadersSize, + kpidMethod, + kpidId, + kpidName, + kpidComment +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + + +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + + switch (propID) + { + case kpidMainSubfile: prop = (UInt32)0; break; + case kpidPhySize: if (_phySize != 0) prop = _phySize; break; + case kpidClusterSize: prop = (UInt32)1 << _clusterBits; break; + case kpidHeadersSize: prop = (h.overHead << 9); break; + case kpidMethod: + { + AString s; + + if (!_descriptor.createType.IsEmpty()) + s = _descriptor.createType; + + if (h.algo != 0) + { + s.Add_Space_if_NotEmpty(); + if (h.algo == 1) + s += "zlib"; + else + { + char temp[16]; + ConvertUInt32ToString(h.algo, temp); + s += temp; + } + } + + if (h.Is_Marker()) + { + s.Add_Space_if_NotEmpty(); + s += "Marker"; + } + + if (!s.IsEmpty()) + prop = s; + break; + } + + case kpidComment: + { + if (_descriptorBuf.Size() != 0) + { + AString s; + s.SetFrom_CalcLen((const char *)(const Byte *)_descriptorBuf, (unsigned)_descriptorBuf.Size()); + if (!s.IsEmpty() && s.Len() <= (1 << 16)) + prop = s; + } + break; + } + + case kpidId: + if (!_descriptor.CID.IsEmpty()) + { + prop = _descriptor.CID; + break; + } + + case kpidName: + { + if (_descriptor.Extents.Size() == 1) + { + const AString &s = _descriptor.Extents[0]; + if (!s.IsEmpty()) + { + if (s.Back() == '"') + { + AString s2 = s; + s2.DeleteBack(); + if (s2.Len() > 5 && StringsAreEqualNoCase_Ascii(s2.RightPtr(5), ".vmdk")) + { + int pos = s2.ReverseFind('"'); + if (pos >= 0) + { + s2.DeleteFrontal(pos + 1); + prop = s2; + } + } + } + } + } + break; + } + + case kpidErrorFlags: + { + UInt32 v = 0; + if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;; + if (_unsupported) v |= kpv_ErrorFlags_UnsupportedMethod; + // if (_headerError) v |= kpv_ErrorFlags_HeadersError; + if (!Stream && v == 0 && _isArc) + v = kpv_ErrorFlags_HeadersError; + if (v != 0) + prop = v; + break; + } + } + + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + + switch (propID) + { + case kpidSize: prop = _size; break; + case kpidPackSize: + { + UInt64 ov = (h.overHead << 9); + if (_phySize >= ov) + prop = _phySize - ov; + break; + } + case kpidExtension: prop = (_imgExt ? _imgExt : "img"); break; + } + + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +static int inline GetLog(UInt64 num) +{ + for (int i = 0; i < 64; i++) + if (((UInt64)1 << i) == num) + return i; + return -1; +} + + +HRESULT CHandler::ReadForHeader(IInStream *stream, UInt64 sector, void *data, size_t numSectors) +{ + sector <<= 9; + RINOK(stream->Seek(sector, STREAM_SEEK_SET, NULL)); + size_t size = numSectors << 9; + RINOK(ReadStream_FALSE(stream, data, size)); + UInt64 end = sector + size; + if (_phySize < end) + _phySize = end; + return S_OK; +} + + +HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openCallback) +{ + const unsigned kSectoreSize = 512; + Byte buf[kSectoreSize]; + size_t headerSize = kSectoreSize; + RINOK(ReadStream(stream, buf, &headerSize)); + + if (headerSize < sizeof(k_Signature)) + return S_FALSE; + if (memcmp(buf, k_Signature, sizeof(k_Signature)) != 0) + { + const char *kSignature_Descriptor = "# Disk DescriptorFile"; + size_t k_SigDesc_Size = strlen(kSignature_Descriptor); + if (headerSize >= k_SigDesc_Size) + if (memcmp(buf, kSignature_Descriptor, k_SigDesc_Size) == 0) + { + _unsupported = true; + _isArc = true; + // return E_NOTIMPL; + } + return S_FALSE; + } + + if (headerSize != kSectoreSize) + return S_FALSE; + + // CHeader h; + + if (!h.Parse(buf)) + return S_FALSE; + + if (h.descriptorSize != 0) + { + if (h.descriptorOffset < 1) + return S_FALSE; + if (h.descriptorSize > (1 << 20)) + return S_FALSE; + size_t numBytes = (size_t)h.descriptorSize << 9; + _descriptorBuf.Alloc(numBytes); + RINOK(ReadForHeader(stream, h.descriptorOffset, _descriptorBuf, (size_t)h.descriptorSize)); + if (h.descriptorOffset == 1 && h.Is_Marker() && Get64(_descriptorBuf) == 0) + { + // We check data as end marker. + // and if probably it's footer's copy of header, we don't want to open it. + return S_FALSE; + } + } + + if (h.gdOffset == (UInt64)(Int64)-1) + { + // Grain Dir is at end of file + UInt64 endPos; + RINOK(stream->Seek(0, STREAM_SEEK_END, &endPos)); + if ((endPos & 511) != 0) + return S_FALSE; + + const size_t kEndSize = 512 * 3; + Byte buf2[kEndSize]; + if (endPos < kEndSize) + return S_FALSE; + RINOK(stream->Seek(endPos - kEndSize, STREAM_SEEK_SET, NULL)); + RINOK(ReadStream_FALSE(stream, buf2, kEndSize)); + + CHeader h2; + if (!h2.Parse(buf2 + 512)) + return S_FALSE; + if (!h.IsSameImageFor(h2)) + return S_FALSE; + + h = h2; + + CMarker m; + m.Parse(buf2); + if (m.NumSectors != 1 || m.SpecSize != 0 || m.Type != k_Marker_FOOTER) + return S_FALSE; + m.Parse(buf2 + 512 * 2); + if (m.NumSectors != 0 || m.SpecSize != 0 || m.Type != k_Marker_END_OF_STREAM) + return S_FALSE; + _phySize = endPos; + } + + int grainSize_Log = GetLog(h.grainSize); + if (grainSize_Log < 3 || grainSize_Log > 30 - 9) // grain size must be >= 4 KB + return S_FALSE; + if (h.capacity >= ((UInt64)1 << (63 - 9))) + return S_FALSE; + if (h.overHead >= ((UInt64)1 << (63 - 9))) + return S_FALSE; + + _isArc = true; + _clusterBits = (9 + grainSize_Log); + _size = h.capacity << 9; + _needDeflate = (h.algo >= 1); + + if (h.Is_Compressed() ? (h.algo > 1 || !h.Is_Marker()) : (h.algo != 0)) + { + _unsupported = true; + _phySize = 0; + return S_FALSE; + } + + { + UInt64 overHeadBytes = h.overHead << 9; + if (_phySize < overHeadBytes) + _phySize = overHeadBytes; + } + + _zeroSector = 0; + if (h.Is_ZeroGrain()) + _zeroSector = 1; + + const UInt64 numSectorsPerGde = (UInt64)1 << (grainSize_Log + k_NumMidBits); + const UInt64 numGdeEntries = (h.capacity + numSectorsPerGde - 1) >> (grainSize_Log + k_NumMidBits); + CByteBuffer table; + + if (numGdeEntries != 0) + { + if (h.gdOffset == 0) + return S_FALSE; + + size_t numSectors = (size_t)((numGdeEntries + ((1 << (9 - 2)) - 1)) >> (9 - 2)); + size_t t1SizeBytes = numSectors << 9; + if ((t1SizeBytes >> 2) < numGdeEntries) + return S_FALSE; + table.Alloc(t1SizeBytes); + + if (h.Is_Marker()) + { + Byte buf2[1 << 9]; + if (ReadForHeader(stream, h.gdOffset - 1, buf2, 1) != S_OK) + return S_FALSE; + { + CMarker m; + m.Parse(buf2); + if (m.Type != k_Marker_GRAIN_DIR + || m.NumSectors != numSectors + || m.SpecSize != 0) + return S_FALSE; + } + } + + RINOK(ReadForHeader(stream, h.gdOffset, table, numSectors)); + } + + size_t clusterSize = (size_t)1 << _clusterBits; + + if (openCallback) + { + UInt64 totalBytes = (UInt64)numGdeEntries << (k_NumMidBits + 2); + RINOK(openCallback->SetTotal(NULL, &totalBytes)); + } + + UInt64 lastSector = 0; + UInt64 lastVirtCluster = 0; + size_t numProcessed_Prev = 0; + + for (size_t i = 0; i < numGdeEntries; i++) + { + UInt32 v = Get32((const Byte *)table + (size_t)i * 4); + CByteBuffer &buf = _tables.AddNew(); + if (v == 0 || v == _zeroSector) + continue; + + if (openCallback && ((i - numProcessed_Prev) & 0xFFF) == 0) + { + UInt64 numBytes = (UInt64)i << (k_NumMidBits + 2); + RINOK(openCallback->SetCompleted(NULL, &numBytes)); + numProcessed_Prev = i; + } + + const size_t k_NumSectors = (size_t)1 << (k_NumMidBits - 9 + 2); + + if (h.Is_Marker()) + { + Byte buf2[1 << 9]; + if (ReadForHeader(stream, v - 1, buf2, 1) != S_OK) + return S_FALSE; + { + CMarker m; + m.Parse(buf2); + if (m.Type != k_Marker_GRAIN_TABLE + || m.NumSectors != k_NumSectors + || m.SpecSize != 0) + return S_FALSE; + } + } + + const size_t k_NumMidItems = (size_t)1 << k_NumMidBits; + + buf.Alloc(k_NumMidItems * 4); + RINOK(ReadForHeader(stream, v, buf, k_NumSectors)); + + for (size_t k = 0; k < k_NumMidItems; k++) + { + UInt32 v = Get32((const Byte *)buf + (size_t)k * 4); + if (v == 0 || v == _zeroSector) + continue; + if (v < h.overHead) + return S_FALSE; + if (lastSector < v) + { + lastSector = v; + if (_needDeflate) + lastVirtCluster = ((UInt64)i << k_NumMidBits) + k; + } + } + } + + + if (!_needDeflate) + { + UInt64 end = ((UInt64)lastSector << 9) + clusterSize; + if (_phySize < end) + _phySize = end; + } + else if (lastSector != 0) + { + Byte buf[1 << 9]; + if (ReadForHeader(stream, lastSector, buf, 1) == S_OK) + { + UInt64 lba = Get64(buf); + if (lba == (lastVirtCluster << (_clusterBits - 9))) + { + UInt32 dataSize = Get32(buf + 8); + size_t dataSize2 = (size_t)dataSize + 12; + dataSize2 = (dataSize2 + 511) & ~(size_t)511; + UInt64 end = ((UInt64)lastSector << 9) + dataSize2; + if (_phySize < end) + _phySize = end; + } + } + } + + if (_descriptorBuf.Size() != 0) + { + _descriptor.Parse(_descriptorBuf, _descriptorBuf.Size()); + if (!_descriptor.parentCID.IsEmpty()) + if (!_descriptor.parentCID.IsEqualTo_Ascii_NoCase("ffffffff")) + _unsupported = true; + } + + Stream = stream; + return S_OK; +} + + +STDMETHODIMP CHandler::Close() +{ + _phySize = 0; + _size = 0; + _cacheCluster = (UInt64)(Int64)-1; + _zeroSector = 0; + _clusterBits = 0; + + _needDeflate = false; + _isArc = false; + _unsupported = false; + // _headerError = false; + + _tables.Clear(); + _descriptorBuf.Free(); + _descriptor.Clear(); + + _imgExt = NULL; + Stream.Release(); + return S_OK; +} + + +STDMETHODIMP CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream) +{ + COM_TRY_BEGIN + *stream = 0; + + if (_unsupported) + return S_FALSE; + + + if (_needDeflate) + { + if (!_bufInStream) + { + _bufInStreamSpec = new CBufInStream; + _bufInStream = _bufInStreamSpec; + } + + if (!_bufOutStream) + { + _bufOutStreamSpec = new CBufPtrSeqOutStream(); + _bufOutStream = _bufOutStreamSpec; + } + + if (!_zlibDecoder) + { + _zlibDecoderSpec = new NCompress::NZlib::CDecoder; + _zlibDecoder = _zlibDecoderSpec; + } + + size_t clusterSize = (size_t)1 << _clusterBits; + _cache.AllocAtLeast(clusterSize); + _cacheCompressed.AllocAtLeast(clusterSize * 2); + } + + CMyComPtr streamTemp = this; + RINOK(InitAndSeek()); + *stream = streamTemp.Detach(); + return S_OK; + COM_TRY_END +} + + +REGISTER_ARC_I( + "VMDK", "vmdk", NULL, 0xC8, + k_Signature, + 0, + 0, + NULL) + +}} diff --git a/CPP/7zip/Archive/Wim/WimHandler.cpp b/CPP/7zip/Archive/Wim/WimHandler.cpp index bca551a6..0c635eae 100644 --- a/CPP/7zip/Archive/Wim/WimHandler.cpp +++ b/CPP/7zip/Archive/Wim/WimHandler.cpp @@ -22,6 +22,8 @@ using namespace NWindows; namespace NArchive { namespace NWim { +#define FILES_DIR_NAME "[DELETED]" + // #define WIM_DETAILS static const Byte kProps[] = @@ -35,6 +37,7 @@ static const Byte kProps[] = kpidATime, kpidAttrib, kpidMethod, + kpidSolid, kpidShortName, kpidINode, kpidLinks, @@ -58,6 +61,7 @@ static const STATPROPSTG kArcProps[] = { NULL, kpidSize, VT_UI8}, { NULL, kpidPackSize, VT_UI8}, { NULL, kpidMethod, VT_BSTR}, + { NULL, kpidClusterSize, VT_UI4}, { NULL, kpidCTime, VT_FILETIME}, { NULL, kpidMTime, VT_FILETIME}, { NULL, kpidComment, VT_BSTR}, @@ -69,9 +73,16 @@ static const STATPROPSTG kArcProps[] = { (LPOLESTR)L"Boot Image", kpidBootImage, VT_UI4} }; -static const char *kMethodLZX = "LZX"; -static const char *kMethodXpress = "XPress"; -static const char *kMethodCopy = "Copy"; + +static const char * const k_Methods[] = +{ + "Copy" + , "XPress" + , "LZX" + , "LZMS" +}; + + IMP_IInArchive_Props IMP_IInArchive_ArcProps_WITH_NAME @@ -199,6 +210,18 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) } break; case kpidNumVolumes: if (_volumes.Size() > 0) prop = (UInt32)(_volumes.Size() - 1); break; + + case kpidClusterSize: + if (_xmls.Size() > 0) + { + UInt16 volIndex = _xmls[0].VolIndex; + if (volIndex < _volumes.Size()) + { + const CHeader &h = _volumes[volIndex].Header; + prop = (UInt32)1 << h.ChunkSizeBits; + } + } + break; case kpidName: if (_firstVolumeIndex >= 0) @@ -252,36 +275,61 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) case kpidNumImages: prop = (UInt32)_db.Images.Size(); break; case kpidBootImage: if (_bootIndex != 0) prop = (UInt32)_bootIndex; break; + case kpidMethod: { - bool lzx = false, xpress = false, copy = false; - FOR_VECTOR (i, _xmls) + UInt32 methodUnknown = 0; + UInt32 methodMask = 0; + unsigned chunkSizeBits = 0; + { - const CHeader &header = _volumes[_xmls[i].VolIndex].Header; - if (header.IsCompressed()) - if (header.IsLzxMode()) - lzx = true; + FOR_VECTOR (i, _xmls) + { + const CHeader &header = _volumes[_xmls[i].VolIndex].Header; + unsigned method = header.GetMethod(); + if (method < ARRAY_SIZE(k_Methods)) + methodMask |= ((UInt32)1 << method); else - xpress = true; - else - copy = true; + methodUnknown = method; + if (chunkSizeBits < header.ChunkSizeBits) + chunkSizeBits = header.ChunkSizeBits; + } } + AString res; - if (lzx) - res = kMethodLZX; - if (xpress) + + bool numMethods = 0; + for (unsigned i = 0; i < ARRAY_SIZE(k_Methods); i++) { - res.Add_Space_if_NotEmpty(); - res += kMethodXpress; + if (methodMask & ((UInt32)1 << i)) + { + res.Add_Space_if_NotEmpty(); + res += k_Methods[i]; + numMethods++; + } } - if (copy) + + if (methodUnknown != 0) { + char temp[32]; + ConvertUInt32ToString(methodUnknown, temp); res.Add_Space_if_NotEmpty(); - res += kMethodCopy; + res += temp; + numMethods++; + } + + if (numMethods == 1 && chunkSizeBits != 0) + { + char temp[32]; + temp[0] = ':'; + ConvertUInt32ToString((UInt32)chunkSizeBits, temp + 1); + res += temp; } + prop = res; break; } + case kpidIsTree: prop = true; break; case kpidIsAltStream: prop = _db.ThereAreAltStreams; break; case kpidIsAux: prop = true; break; @@ -293,8 +341,8 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { UInt32 flags = 0; if (!_isArc) flags |= kpv_ErrorFlags_IsNotArc; - // if (HeadersError) flags |= kpv_ErrorFlags_HeadersError; - // if (UnexpectedEnd) flags |= kpv_ErrorFlags_UnexpectedEndOfArc; + if (_db.HeadersError) flags |= kpv_ErrorFlags_HeadersError; + if (_unsupported) flags |= kpv_ErrorFlags_UnsupportedMethod; prop = flags; break; } @@ -313,23 +361,13 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) case kpidReadOnly: { - bool readOnly = false; - if (ThereIsError()) - readOnly = true; - else if (_volumes.Size() != 0) - { - if (_version != kWimVersion - || _volumes.Size() != 2 - || _volumes[0].Stream - // || _db.Images.Size() > kNumImagesMax - ) - readOnly = true; - } + bool readOnly = !IsUpdateSupported(); if (readOnly) prop = readOnly; break; } } + prop.Detach(value); return S_OK; COM_TRY_END @@ -342,7 +380,29 @@ void GetFileTime(const Byte *p, NCOM::CPropVariant &prop) prop.filetime.dwHighDateTime = Get32(p + 4); } -#define FILES_DIR_NAME "[Files]" + +static void MethodToProp(int method, int chunksSizeBits, NCOM::CPropVariant &prop) +{ + if (method >= 0) + { + char temp[32]; + + if ((unsigned)method < ARRAY_SIZE(k_Methods)) + strcpy(temp, k_Methods[method]); + else + ConvertUInt32ToString((unsigned)method, temp); + + if (chunksSizeBits >= 0) + { + size_t pos = strlen(temp); + temp[pos++] = ':'; + ConvertUInt32ToString((unsigned)chunksSizeBits, temp + pos); + } + + prop = temp; + } +} + STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) { @@ -413,8 +473,59 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val _db.GetShortName(realIndex, prop); break; - case kpidPackSize: prop = (UInt64)(si ? si->Resource.PackSize : 0); break; - case kpidSize: prop = (UInt64)(si ? si->Resource.UnpackSize : 0); break; + case kpidPackSize: + { + UInt64 size = 0; + if (si) + { + if (!si->Resource.IsSolidSmall()) + { + size = si->Resource.PackSize; + prop = size; + } + else + { + if (si->Resource.SolidIndex >= 0) + { + const CSolid &ss = _db.Solids[(unsigned)si->Resource.SolidIndex]; + if (ss.FirstSmallStream == item.StreamIndex) + prop = _db.DataStreams[ss.StreamIndex].Resource.PackSize; + } + } + } + break; + } + + case kpidSize: + { + UInt64 size = 0; + if (si) + { + if (si->Resource.IsSolid()) + { + if (si->Resource.IsSolidBig()) + { + if (si->Resource.SolidIndex >= 0) + { + CSolid &ss = _db.Solids[(unsigned)si->Resource.SolidIndex]; + prop = ss.UnpackSize; + } + } + else + { + size = si->Resource.PackSize; + prop = size; + } + } + else + { + size = si->Resource.UnpackSize; + prop = size; + } + } + break; + } + case kpidIsDir: prop = item.IsDir; break; case kpidIsAltStream: prop = item.IsAltStream; break; case kpidNumAltStreams: @@ -467,8 +578,33 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val prop = (UInt32)item.StreamIndex; break; - case kpidMethod: if (si) prop = si->Resource.IsCompressed() ? - (vol->Header.IsLzxMode() ? kMethodLZX : kMethodXpress) : kMethodCopy; break; + case kpidMethod: + if (si) + { + const CResource &r = si->Resource; + if (r.IsSolid()) + { + if (r.SolidIndex >= 0) + { + CSolid &ss = _db.Solids[r.SolidIndex]; + MethodToProp(ss.Method, ss.ChunkSizeBits, prop); + } + } + else + { + int method = 0; + int chunkSizeBits = -1; + if (r.IsCompressed()) + { + method = vol->Header.GetMethod(); + chunkSizeBits = vol->Header.ChunkSizeBits; + } + MethodToProp(method, chunkSizeBits, prop); + } + } + break; + + case kpidSolid: if (si) prop = si->Resource.IsSolid(); break; case kpidLinks: if (si) prop = (UInt32)si->RefCount; break; #ifdef WIM_DETAILS case kpidVolume: if (si) prop = (UInt32)si->PartNumber; break; @@ -488,7 +624,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val case kpidIsDir: prop = false; break; case kpidPackSize: case kpidSize: prop = (UInt64)_xmls[index].Data.Size(); break; - case kpidMethod: prop = kMethodCopy; break; + case kpidMethod: /* prop = k_Method_Copy; */ break; } } else @@ -629,14 +765,6 @@ STDMETHODIMP CHandler::GetParent(UInt32 index, UInt32 *parent, UInt32 *parentTyp return S_OK; } -static bool IsEmptySha(const Byte *data) -{ - for (int i = 0; i < kHashSize; i++) - if (data[i] != 0) - return false; - return true; -} - STDMETHODIMP CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType) { *data = NULL; @@ -773,6 +901,7 @@ STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCal for (UInt32 i = 1; i <= numVolumes; i++) { CMyComPtr curStream; + if (i == 1) curStream = inStream; else @@ -786,14 +915,17 @@ STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCal if (!curStream) break; } + CHeader header; HRESULT res = NWim::ReadHeader(curStream, header, _phySize); + if (res != S_OK) { if (i != 1 && res == S_FALSE) continue; return res; } + _isArc = true; _bootIndex = header.BootIndex; _version = header.Version; @@ -806,17 +938,25 @@ STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCal CWimXml xml; xml.VolIndex = header.PartNumber; res = _db.OpenXml(curStream, header, xml.Data); + if (res == S_OK) { if (!xml.Parse()) _xmlError = true; + if (xml.IsEncrypted) + { + _unsupported = true; + return S_FALSE; + } + UInt64 totalFiles = xml.GetTotalFilesAndDirs() + xml.Images.Size(); totalFiles += 16 + xml.Images.Size() * 4; // we reserve some additional items if (totalFiles >= ((UInt32)1 << 30)) totalFiles = 0; res = _db.Open(curStream, header, (unsigned)totalFiles, callback); } + if (res != S_OK) { if (i != 1 && res == S_FALSE) @@ -859,7 +999,7 @@ STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCal } } - RINOK(_db.FillAndCheck()); + RINOK(_db.FillAndCheck(_volumes)); int defaultImageIndex = (int)_defaultImageNumber - 1; bool showImageNumber = (_db.Images.Size() != 1 && defaultImageIndex < 0); @@ -901,9 +1041,11 @@ STDMETHODIMP CHandler::Close() _numIgnoreItems = 0; _xmlError = false; _isArc = false; + _unsupported = false; return S_OK; } + STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) { @@ -917,6 +1059,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, UInt32 i; UInt64 totalSize = 0; + for (i = 0; i < numItems; i++) { UInt32 index = allFilesMode ? i : indices[i]; @@ -926,7 +1069,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, if (streamIndex >= 0) { const CStreamInfo &si = _db.DataStreams[streamIndex]; - totalSize += si.Resource.UnpackSize; + totalSize += _db.Get_UnpackSize_of_Resource(si.Resource); } } else @@ -939,9 +1082,8 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, RINOK(extractCallback->SetTotal(totalSize)); - UInt64 currentTotalPacked = 0; UInt64 currentTotalUnPacked = 0; - UInt64 currentItemUnPacked, currentItemPacked; + UInt64 currentItemUnPacked; int prevSuccessStreamIndex = -1; @@ -951,13 +1093,12 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, CMyComPtr progress = lps; lps->Init(extractCallback, false); - for (i = 0; i < numItems; currentTotalUnPacked += currentItemUnPacked, - currentTotalPacked += currentItemPacked) + for (i = 0; i < numItems; + currentTotalUnPacked += currentItemUnPacked) { currentItemUnPacked = 0; - currentItemPacked = 0; - lps->InSize = currentTotalPacked; + lps->InSize = unpacker.TotalPacked; lps->OutSize = currentTotalUnPacked; RINOK(lps->SetCur()); @@ -1005,8 +1146,8 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, } const CStreamInfo &si = _db.DataStreams[streamIndex]; - currentItemUnPacked = si.Resource.UnpackSize; - currentItemPacked = si.Resource.PackSize; + currentItemUnPacked = _db.Get_UnpackSize_of_Resource(si.Resource); + // currentItemPacked = _db.Get_PackSize_of_Resource(streamIndex); if (!testMode && !realOutStream) continue; @@ -1016,17 +1157,20 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, { Byte digest[kHashSize]; const CVolume &vol = _volumes[si.PartNumber]; - HRESULT res = unpacker.Unpack(vol.Stream, si.Resource, vol.Header.IsLzxMode(), - realOutStream, progress, digest); + bool needDigest = !si.IsEmptyHash(); + HRESULT res = unpacker.Unpack(vol.Stream, si.Resource, vol.Header, &_db, + realOutStream, progress, needDigest ? digest : NULL); if (res == S_OK) { - if (memcmp(digest, si.Hash, kHashSize) == 0) + if (!needDigest || memcmp(digest, si.Hash, kHashSize) == 0) prevSuccessStreamIndex = streamIndex; else opRes = NExtract::NOperationResult::kCRCError; } else if (res == S_FALSE) opRes = NExtract::NOperationResult::kDataError; + else if (res == E_NOTIMPL) + opRes = NExtract::NOperationResult::kUnsupportedMethod; else return res; } diff --git a/CPP/7zip/Archive/Wim/WimHandler.h b/CPP/7zip/Archive/Wim/WimHandler.h index 00de1b87..3ba88d2b 100644 --- a/CPP/7zip/Archive/Wim/WimHandler.h +++ b/CPP/7zip/Archive/Wim/WimHandler.h @@ -10,6 +10,8 @@ namespace NArchive { namespace NWim { +static const Int32 kNumImagesMaxUpdate = (1 << 10); + class CHandler: public IInArchive, public IArchiveGetRawProps, @@ -34,6 +36,7 @@ class CHandler: bool _xmlError; bool _isArc; + bool _unsupported; bool _set_use_ShowImageNumber; bool _set_showImageNumber; @@ -53,6 +56,26 @@ class CHandler: _defaultImageNumber = -1; } + bool IsUpdateSupported() const + { + if (ThereIsError()) return false; + if (_db.Images.Size() > kNumImagesMaxUpdate) return false; + + // Solid format is complicated. So we disable updating now. + if (!_db.Solids.IsEmpty()) return false; + + if (_volumes.Size() == 0) + return true; + + if (_volumes.Size() != 2) return false; + if (_volumes[0].Stream) return false; + if (_version != k_Version_NonSolid + // && _version != k_Version_Solid + ) return false; + + return true; + } + bool ThereIsError() const { return _xmlError || _db.ThereIsError(); } HRESULT GetSecurity(UInt32 realIndex, const void **data, UInt32 *dataSize, UInt32 *propType); diff --git a/CPP/7zip/Archive/Wim/WimHandlerOut.cpp b/CPP/7zip/Archive/Wim/WimHandlerOut.cpp index 145ede42..2eb6c94b 100644 --- a/CPP/7zip/Archive/Wim/WimHandlerOut.cpp +++ b/CPP/7zip/Archive/Wim/WimHandlerOut.cpp @@ -2,10 +2,6 @@ #include "StdAfx.h" -// #include - -#include "../../../../C/CpuArch.h" - #include "../../../Common/ComTry.h" #include "../../../Common/IntToString.h" #include "../../../Common/StringToInt.h" @@ -30,49 +26,36 @@ using namespace NWindows; namespace NArchive { namespace NWim { -static const Int32 kNumImagesMax = (1 << 10); - -struct CSha1Hash +static int AddUniqHash(const CStreamInfo *streams, CUIntVector &sorted, const Byte *h, int streamIndexForInsert) { - Byte Hash[kHashSize]; -}; - -class CHashList -{ - CUIntVector Sorted; -public: - CRecordVector Digests; - - int AddUniq(const Byte *h); -}; - -// returns -1 : if it's new HASH - -int CHashList::AddUniq(const Byte *h) -{ - unsigned left = 0, right = Sorted.Size(); + unsigned left = 0, right = sorted.Size(); while (left != right) { unsigned mid = (left + right) / 2; - unsigned index = Sorted[mid]; - const Byte *hash2 = Digests[index].Hash; + unsigned index = sorted[mid]; + const Byte *hash2 = streams[index].Hash; + unsigned i; for (i = 0; i < kHashSize; i++) if (h[i] != hash2[i]) break; + if (i == kHashSize) return index; + if (h[i] < hash2[i]) right = mid; else left = mid + 1; } - CSha1Hash h2; - memcpy(h2.Hash, h, kHashSize); - Sorted.Insert(left, Digests.Add(h2)); + + if (streamIndexForInsert >= 0) + sorted.Insert(left, streamIndexForInsert); + return -1; } + struct CAltStream { int UpdateIndex; @@ -84,6 +67,7 @@ struct CAltStream CAltStream(): UpdateIndex(-1), HashIndex(-1), Skip(false) {} }; + struct CMetaItem { int UpdateIndex; @@ -114,6 +98,7 @@ struct CMetaItem Skip(false), NumSkipAltStreams(0) {} }; + static int Compare_HardLink_MetaItems(const CMetaItem &a1, const CMetaItem &a2) { if (a1.VolID < a2.VolID) return -1; @@ -125,6 +110,7 @@ static int Compare_HardLink_MetaItems(const CMetaItem &a1, const CMetaItem &a2) return ::CompareFileTime(&a1.MTime, &a2.MTime); } + static int AddToHardLinkList(const CObjectVector &metaItems, unsigned indexOfItem, CUIntVector &indexes) { const CMetaItem &mi = metaItems[indexOfItem]; @@ -145,6 +131,7 @@ static int AddToHardLinkList(const CObjectVector &metaItems, unsigned return -1; } + struct CUpdateItem { unsigned CallbackIndex; // index in callback @@ -160,6 +147,7 @@ struct CUpdateItem CUpdateItem(): MetaIndex(-1), AltStreamIndex(-1), InArcIndex(-1) {} }; + struct CDir { int MetaIndex; @@ -224,12 +212,14 @@ bool CDir::FindDir(const CObjectVector &items, const UString &name, u return false; } + STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type) { *type = NFileTimeType::kWindows; return S_OK; } + HRESULT CHandler::GetOutProperty(IArchiveUpdateCallback *callback, UInt32 callbackIndex, Int32 arcIndex, PROPID propID, PROPVARIANT *value) { if (arcIndex >= 0) @@ -237,6 +227,7 @@ HRESULT CHandler::GetOutProperty(IArchiveUpdateCallback *callback, UInt32 callba return callback->GetProperty(callbackIndex, propID, value); } + HRESULT CHandler::GetTime(IArchiveUpdateCallback *callback, UInt32 callbackIndex, Int32 arcIndex, PROPID propID, FILETIME &ft) { ft.dwLowDateTime = ft.dwHighDateTime = 0; @@ -249,6 +240,7 @@ HRESULT CHandler::GetTime(IArchiveUpdateCallback *callback, UInt32 callbackIndex return S_OK; } + static HRESULT GetRootTime( IArchiveGetRootProps *callback, IArchiveGetRootProps *arcRoot, @@ -292,6 +284,7 @@ void CResource::WriteTo(Byte *p) const Set64(p + 16, UnpackSize); } + void CHeader::WriteTo(Byte *p) const { memcpy(p, kSignature, kSignatureSize); @@ -311,6 +304,7 @@ void CHeader::WriteTo(Byte *p) const memset(p + 0x94, 0, 60); } + void CStreamInfo::WriteTo(Byte *p) const { Resource.WriteTo(p); @@ -319,6 +313,7 @@ void CStreamInfo::WriteTo(Byte *p) const memcpy(p + 0x1E, Hash, kHashSize); } + class CInStreamWithSha1: public ISequentialInStream, public CMyUnknownImp @@ -352,6 +347,7 @@ STDMETHODIMP CInStreamWithSha1::Read(void *data, UInt32 size, UInt32 *processedS return result; } + static void SetFileTimeToMem(Byte *p, const FILETIME &ft) { Set32(p, ft.dwLowDateTime); @@ -391,7 +387,8 @@ static size_t WriteItem_Dummy(const CMetaItem &item) return totalLen; } -static size_t WriteItem(const CRecordVector &digests, const CMetaItem &item, Byte *p) + +static size_t WriteItem(const CStreamInfo *streams, const CMetaItem &item, Byte *p) { if (item.Skip) return 0; @@ -437,7 +434,7 @@ static size_t WriteItem(const CRecordVector &digests, const CMetaItem if (item.GetNumAltStreams() == 0) { if (item.HashIndex >= 0) - memcpy(p + 0x40, digests[item.HashIndex].Hash, kHashSize); + memcpy(p + 0x40, streams[item.HashIndex].Hash, kHashSize); } else { @@ -450,7 +447,7 @@ static size_t WriteItem(const CRecordVector &digests, const CMetaItem memset(p, 0, curLen); Set64(p, curLen); if (item.HashIndex >= 0) - memcpy(p + 0x10, digests[item.HashIndex].Hash, kHashSize); + memcpy(p + 0x10, streams[item.HashIndex].Hash, kHashSize); totalLen += curLen; p += curLen; } @@ -468,7 +465,7 @@ static size_t WriteItem(const CRecordVector &digests, const CMetaItem Set64(p, curLen); if (ss.HashIndex >= 0) - memcpy(p + 0x10, digests[ss.HashIndex].Hash, kHashSize); + memcpy(p + 0x10, streams[ss.HashIndex].Hash, kHashSize); Set16(p + 0x24, (UInt16)fileNameLen); for (i = 0; i * 2 < fileNameLen; i++) Set16(p + 0x26 + i * 2, ss.Name[i]); @@ -480,10 +477,11 @@ static size_t WriteItem(const CRecordVector &digests, const CMetaItem return totalLen; } + struct CDb { CMetaItem DefaultDirItem; - const CRecordVector *Hashes; + const CStreamInfo *Hashes; CObjectVector MetaItems; CRecordVector UpdateItems; CUIntVector UpdateIndexes; /* indexes in UpdateItems in order of writing data streams @@ -494,6 +492,7 @@ struct CDb void WriteOrderList(const CDir &tree); }; + size_t CDb::WriteTree_Dummy(const CDir &tree) const { unsigned i; @@ -509,11 +508,12 @@ size_t CDb::WriteTree_Dummy(const CDir &tree) const return pos + 8; } + void CDb::WriteTree(const CDir &tree, Byte *dest, size_t &pos) const { unsigned i; for (i = 0; i < tree.Files.Size(); i++) - pos += WriteItem(*Hashes, MetaItems[tree.Files[i]], dest + pos); + pos += WriteItem(Hashes, MetaItems[tree.Files[i]], dest + pos); size_t posStart = pos; for (i = 0; i < tree.Dirs.Size(); i++) @@ -530,7 +530,7 @@ void CDb::WriteTree(const CDir &tree, Byte *dest, size_t &pos) const bool needCreateTree = (metaItem.Reparse.Size() == 0) || !subDir.Files.IsEmpty() || !subDir.Dirs.IsEmpty(); - size_t len = WriteItem(*Hashes, metaItem, dest + posStart); + size_t len = WriteItem(Hashes, metaItem, dest + posStart); posStart += len; if (needCreateTree) { @@ -540,6 +540,7 @@ void CDb::WriteTree(const CDir &tree, Byte *dest, size_t &pos) const } } + void CDb::WriteOrderList(const CDir &tree) { if (tree.MetaIndex >= 0) @@ -564,6 +565,7 @@ void CDb::WriteOrderList(const CDir &tree) WriteOrderList(tree.Dirs[i]); } + static void AddTag_ToString(AString &s, const char *name, const char *value) { s += '<'; @@ -576,6 +578,7 @@ static void AddTag_ToString(AString &s, const char *name, const char *value) s += '>'; } + static void AddTagUInt64_ToString(AString &s, const char *name, UInt64 value) { char temp[32]; @@ -583,6 +586,7 @@ static void AddTagUInt64_ToString(AString &s, const char *name, UInt64 value) AddTag_ToString(s, name, temp); } + static CXmlItem &AddUniqueTag(CXmlItem &parentItem, const char *name) { int index = parentItem.FindSubTag(name); @@ -598,6 +602,7 @@ static CXmlItem &AddUniqueTag(CXmlItem &parentItem, const char *name) return subItem; } + static void AddTag_UInt64_2(CXmlItem &item, UInt64 value) { CXmlItem &subItem = item.SubItems.AddNew(); @@ -607,11 +612,13 @@ static void AddTag_UInt64_2(CXmlItem &item, UInt64 value) subItem.Name = temp; } + static void AddTag_UInt64(CXmlItem &parentItem, const char *name, UInt64 value) { AddTag_UInt64_2(AddUniqueTag(parentItem, name), value); } + static void AddTag_Hex(CXmlItem &item, const char *name, UInt32 value) { item.IsTag = true; @@ -625,17 +632,20 @@ static void AddTag_Hex(CXmlItem &item, const char *name, UInt32 value) subItem.Name = temp; } + static void AddTag_Time_2(CXmlItem &item, const FILETIME &ft) { AddTag_Hex(item.SubItems.AddNew(), "HIGHPART", ft.dwHighDateTime); AddTag_Hex(item.SubItems.AddNew(), "LOWPART", ft.dwLowDateTime); } + static void AddTag_Time(CXmlItem &parentItem, const char *name, const FILETIME &ft) { AddTag_Time_2(AddUniqueTag(parentItem, name), ft); } + static void AddTag_String_IfEmpty(CXmlItem &parentItem, const char *name, const char *value) { int index = parentItem.FindSubTag(name); @@ -649,15 +659,17 @@ static void AddTag_String_IfEmpty(CXmlItem &parentItem, const char *name, const subItem.Name = value; } + void CHeader::SetDefaultFields(bool useLZX) { - Version = kWimVersion; + Version = k_Version_NonSolid; Flags = NHeaderFlags::kReparsePointFixup; ChunkSize = 0; if (useLZX) { Flags |= NHeaderFlags::kCompression | NHeaderFlags::kLZX; ChunkSize = kChunkSize; + ChunkSizeBits = kChunkSizeBits; } g_RandomGenerator.Generate(Guid, 16); PartNumber = 1; @@ -670,19 +682,23 @@ void CHeader::SetDefaultFields(bool useLZX) IntegrityResource.Clear(); } + static void AddTrees(CObjectVector &trees, CObjectVector &metaItems, const CMetaItem &ri, int curTreeIndex) { while (curTreeIndex >= (int)trees.Size()) trees.AddNew().Dirs.AddNew().MetaIndex = metaItems.Add(ri); } + #define IS_LETTER_CHAR(c) ((c) >= 'a' && (c) <= 'z' || (c) >= 'A' && (c) <= 'Z') + + STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 numItems, IArchiveUpdateCallback *callback) { COM_TRY_BEGIN - if (ThereIsError()) + if (!IsUpdateSupported()) return E_NOTIMPL; bool isUpdate = (_volumes.Size() != 0); @@ -692,14 +708,8 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu if (isUpdate) { showImageNumber = _showImageNumber; - if (_version != kWimVersion) - return E_NOTIMPL; - if (_volumes.Size() != 2 || _volumes[0].Stream) - return E_NOTIMPL; if (!showImageNumber) defaultImageIndex = _db.IndexOfUserImage; - if (_db.Images.Size() > kNumImagesMax) - return E_NOTIMPL; } else { @@ -708,7 +718,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu defaultImageIndex = 0; } - if (defaultImageIndex >= kNumImagesMax) + if (defaultImageIndex >= kNumImagesMaxUpdate) return E_NOTIMPL; CMyComPtr outStream; @@ -783,7 +793,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu UInt64 val = ConvertStringToUInt64(path, &end); if (end == path) return E_INVALIDARG; - if (val == 0 || val > kNumImagesMax) + if (val == 0 || val > kNumImagesMaxUpdate) return E_INVALIDARG; wchar_t c = *end; if (c != 0 && c != ':' && c != L'/' && c != WCHAR_PATH_SEPARATOR) @@ -889,6 +899,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu UInt32 indexInArchive; Int32 newData, newProps; RINOK(callback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArchive)); + if (newData == 0 || newProps == 0) { if (indexInArchive >= _db.SortedItems.Size()) @@ -910,7 +921,14 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu // if deleted item was not renamed, we just skip it if (newProps == 0) continue; + if (item.StreamIndex >= 0) + { + // we don't support property change for SolidBig streams + if (_db.DataStreams[item.StreamIndex].Resource.IsSolidBig()) + return E_NOTIMPL; + } } + if (newData == 0) ui.InArcIndex = indexInArchive; } @@ -955,6 +973,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu } NCOM::CPropVariant prop; + if (newData) { RINOK(callback->GetProperty(i, kpidSize, &prop)); @@ -963,6 +982,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu { RINOK(GetProperty(indexInArchive, kpidSize, &prop)); } + if (prop.vt == VT_UI8) size = prop.uhVal.QuadPart; else if (prop.vt != VT_EMPTY) @@ -999,7 +1019,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu UInt64 val = ConvertStringToUInt64(path, &end); if (end == path) return E_INVALIDARG; - if (val == 0 || val > kNumImagesMax) + if (val == 0 || val > kNumImagesMaxUpdate) return E_INVALIDARG; imageIndex = (int)val - 1; @@ -1111,6 +1131,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu ui.MetaIndex = db.MetaItems.Size(); db.MetaItems.AddNew(); } + CMetaItem &mi = db.MetaItems[ui.MetaIndex]; mi.Size = size; mi.IsDir = isDir; @@ -1163,6 +1184,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu { getRawProps->GetRawProp(i, kpidNtSecure, &data, &dataSize, &propType); } + if (dataSize != 0) { if (propType != NPropDataType::kRaw) @@ -1173,6 +1195,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu data = NULL; dataSize = 0; propType = 0; + if (arcIndex >= 0) { GetRawProp(arcIndex, kpidNtReparse, &data, &dataSize, &propType); @@ -1181,6 +1204,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu { getRawProps->GetRawProp(i, kpidNtReparse, &data, &dataSize, &propType); } + if (dataSize != 0) { if (propType != NPropDataType::kRaw) @@ -1228,7 +1252,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu UInt64 complexity = 0; unsigned numDataStreams = _db.DataStreams.Size(); - CIntArr streamsRefs(numDataStreams); + CUIntArr streamsRefs(numDataStreams); for (i = 0; i < numDataStreams; i++) streamsRefs[i] = 0; @@ -1249,11 +1273,13 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu } } + // ---------- Update Streams Refs Counts in changed images for (i = 0; i < db.UpdateIndexes.Size(); i++) { const CUpdateItem &ui = db.UpdateItems[db.UpdateIndexes[i]]; + if (ui.InArcIndex >= 0) { if ((unsigned)ui.InArcIndex >= _db.SortedItems.Size()) @@ -1274,12 +1300,32 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu } } + // Clear ref counts for SolidBig streams + for (i = 0; i < _db.DataStreams.Size(); i++) - if (streamsRefs[i] != 0) - complexity += _db.DataStreams[i].Resource.PackSize; + if (_db.DataStreams[i].Resource.IsSolidBig()) + streamsRefs[i] = 0; + + // Set ref counts for SolidBig streams - RINOK(callback->SetTotal(complexity)); + for (i = 0; i < _db.DataStreams.Size(); i++) + if (streamsRefs[i] != 0) + { + const CResource &rs = _db.DataStreams[i].Resource; + if (rs.IsSolidSmall()) + streamsRefs[_db.Solids[rs.SolidIndex].StreamIndex] = 1; + } + for (i = 0; i < _db.DataStreams.Size(); i++) + if (streamsRefs[i] != 0) + { + const CResource &rs = _db.DataStreams[i].Resource; + if (!rs.IsSolidSmall()) + complexity += rs.PackSize; + } + + RINOK(callback->SetTotal(complexity)); + UInt64 totalComplexity = complexity; NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder; CMyComPtr copyCoder = copyCoderSpec; @@ -1300,7 +1346,9 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu { const CHeader &srcHeader = _volumes[1].Header; header.Flags = srcHeader.Flags; + header.Version = srcHeader.Version; header.ChunkSize = srcHeader.ChunkSize; + header.ChunkSizeBits = srcHeader.ChunkSizeBits; } Byte buf[kHeaderSizeMax]; @@ -1322,40 +1370,84 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu } - // these two lists have same sizes and same hashes in same order. - CHashList hashes; - CObjectVector streams; - + CRecordVector streams; + CUIntVector sortedHashes; // indexes to streams, sorted by SHA1 // ---------- Copy unchanged data streams ---------- + UInt64 solidRunOffset = 0; + UInt64 curSolidSize = 0; + for (i = 0; i < _db.DataStreams.Size(); i++) { - if (streamsRefs[i] == 0) - continue; + const CStreamInfo &siOld = _db.DataStreams[i]; + const CResource &rs = siOld.Resource; + + unsigned numRefs = streamsRefs[i]; + + if (numRefs == 0) + { + if (!rs.IsSolidSmall()) + continue; + if (streamsRefs[_db.Solids[rs.SolidIndex].StreamIndex] == 0) + continue; + } lps->InSize = lps->OutSize = complexity; RINOK(lps->SetCur()); - const CStreamInfo &siOld = _db.DataStreams[i]; - if (hashes.AddUniq(siOld.Hash) >= 0) - return E_FAIL; // two streams with same SHA-1 - - RINOK(_volumes[siOld.PartNumber].Stream->Seek(siOld.Resource.Offset, STREAM_SEEK_SET, NULL)); - inStreamLimitedSpec->Init(siOld.Resource.PackSize); - RINOK(copyCoder->Code(inStreamLimited, outStream, NULL, NULL, progress)); - if (copyCoderSpec->TotalSize != siOld.Resource.PackSize) - return E_FAIL; - - CStreamInfo &s = streams.AddNew(); - s.Resource = siOld.Resource; - s.Resource.Offset = curPos; + int streamIndex = streams.Size(); + CStreamInfo s; + s.Resource = rs; s.PartNumber = 1; - s.RefCount = streamsRefs[i]; + s.RefCount = numRefs; + memcpy(s.Hash, siOld.Hash, kHashSize); - curPos += s.Resource.PackSize; - lps->ProgressOffset += s.Resource.PackSize; + if (rs.IsSolid()) + { + CSolid &ss = _db.Solids[rs.SolidIndex]; + if (rs.IsSolidSmall()) + { + UInt64 oldOffset = ss.SolidOffset; + if (rs.Offset < oldOffset) + return E_FAIL; + UInt64 relatOffset = rs.Offset - oldOffset; + s.Resource.Offset = solidRunOffset + relatOffset; + } + else + { + // IsSolidBig + solidRunOffset += curSolidSize; + curSolidSize = ss.UnpackSize; + } + } + else + { + solidRunOffset = 0; + curSolidSize = 0; + } + + if (!rs.IsSolid() || rs.IsSolidSmall()) + { + int find = AddUniqHash(&streams.Front(), sortedHashes, siOld.Hash, streamIndex); + if (find >= 0) + return E_FAIL; // two streams with same SHA-1 + } + + if (!rs.IsSolid() || rs.IsSolidBig()) + { + RINOK(_volumes[siOld.PartNumber].Stream->Seek(rs.Offset, STREAM_SEEK_SET, NULL)); + inStreamLimitedSpec->Init(rs.PackSize); + RINOK(copyCoder->Code(inStreamLimited, outStream, NULL, NULL, progress)); + if (copyCoderSpec->TotalSize != rs.PackSize) + return E_FAIL; + s.Resource.Offset = curPos; + curPos += rs.PackSize; + lps->ProgressOffset += rs.PackSize; + } + + streams.Add(s); } @@ -1367,7 +1459,6 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu { lps->InSize = lps->OutSize = complexity; RINOK(lps->SetCur()); - const CUpdateItem &ui = db.UpdateItems[db.UpdateIndexes[i]]; CMetaItem &mi = db.MetaItems[ui.MetaIndex]; UInt64 size = 0; @@ -1396,7 +1487,9 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu if ((unsigned)ui.InArcIndex >= _db.SortedItems.Size()) return E_FAIL; + const CItem &item = _db.Items[_db.SortedItems[ui.InArcIndex]]; + if (item.StreamIndex < 0) { if (size == 0) @@ -1408,19 +1501,23 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu // We support empty file (size = 0, but with stream and SHA-1) from old archive const CStreamInfo &siOld = _db.DataStreams[item.StreamIndex]; + + int index = AddUniqHash(&streams.Front(), sortedHashes, siOld.Hash, -1); // we must have written that stream already - int index = hashes.AddUniq(siOld.Hash); if (index < 0) return E_FAIL; + if (ui.AltStreamIndex < 0) mi.HashIndex = index; else mi.AltStreams[ui.AltStreamIndex].HashIndex = index; + continue; } CMyComPtr fileInStream; HRESULT res = callback->GetStream(ui.CallbackIndex, &fileInStream); + if (res == S_FALSE) { if (ui.AltStreamIndex >= 0) @@ -1452,8 +1549,6 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu if (getProps2->GetProps2(&props) == S_OK) { mi.Attrib = props.Attrib; - mi.Size = props.Size; - size = props.Size; mi.CTime = props.CTime; mi.ATime = props.ATime; mi.MTime = props.MTime; @@ -1463,6 +1558,19 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu mi.VolID = props.VolID; if (mi.FileID != 0) miIndex = AddToHardLinkList(db.MetaItems, ui.MetaIndex, hlIndexes); + + if (props.Size != size && props.Size != (UInt64)(Int64)-1) + { + Int64 delta = (Int64)props.Size - (Int64)size; + Int64 newComplexity = totalComplexity + delta; + if (newComplexity > 0) + { + totalComplexity = newComplexity; + callback->SetTotal(totalComplexity); + } + mi.Size = props.Size; + size = props.Size; + } } } } @@ -1484,14 +1592,16 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu sha1.Update((const Byte *)mi.Reparse + 8, packSize); Byte hash[kHashSize]; sha1.Final(hash); - int index = hashes.AddUniq(hash); + + int index = AddUniqHash(&streams.Front(), sortedHashes, hash, streams.Size()); + if (index >= 0) streams[index].RefCount++; else { - RINOK(WriteStream(outStream, (const Byte *)mi.Reparse + 8, packSize)); index = streams.Size(); - CStreamInfo &s = streams.AddNew(); + RINOK(WriteStream(outStream, (const Byte *)mi.Reparse + 8, packSize)); + CStreamInfo s; s.Resource.PackSize = packSize; s.Resource.Offset = curPos; s.Resource.UnpackSize = packSize; @@ -1504,7 +1614,10 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu s.RefCount = 1; memcpy(s.Hash, hash, kHashSize); curPos += packSize; + + streams.Add(s); } + mi.HashIndex = index; } else @@ -1534,8 +1647,9 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu Byte hash[kHashSize]; UInt64 packSize = offsetBlockSize + size; inShaStreamSpec->Final(hash); - int index = hashes.AddUniq(hash); - + + int index = AddUniqHash(&streams.Front(), sortedHashes, hash, streams.Size()); + if (index >= 0) { streams[index].RefCount++; @@ -1545,7 +1659,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu else { index = streams.Size(); - CStreamInfo &s = streams.AddNew(); + CStreamInfo s; s.Resource.PackSize = packSize; s.Resource.Offset = curPos; s.Resource.UnpackSize = size; @@ -1558,6 +1672,8 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu s.RefCount = 1; memcpy(s.Hash, hash, kHashSize); curPos += packSize; + + streams.Add(s); } if (ui.AltStreamIndex < 0) @@ -1658,15 +1774,16 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu Set32((Byte *)meta, (UInt32)pos); // size of security data } - db.Hashes = &hashes.Digests; + db.Hashes = &streams.Front(); db.WriteTree(tree, (Byte *)meta, pos); { NCrypto::NSha1::CContext sha; sha.Init(); sha.Update((const Byte *)meta, pos); - CSha1Hash digest; - sha.Final(digest.Hash); + + Byte digest[kHashSize]; + sha.Final(digest); CStreamInfo s; s.Resource.PackSize = pos; @@ -1675,7 +1792,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu s.Resource.Flags = NResourceFlags::kMetadata; s.PartNumber = 1; s.RefCount = 1; - memcpy(s.Hash, digest.Hash, kHashSize); + memcpy(s.Hash, digest, kHashSize); streams.Add(s); if (_bootIndex != 0 && _bootIndex == (UInt32)i + 1) diff --git a/CPP/7zip/Archive/Wim/WimIn.cpp b/CPP/7zip/Archive/Wim/WimIn.cpp index 12b8525c..2c1ec5de 100644 --- a/CPP/7zip/Archive/Wim/WimIn.cpp +++ b/CPP/7zip/Archive/Wim/WimIn.cpp @@ -2,7 +2,14 @@ #include "StdAfx.h" -// #include +// #define SHOW_DEBUG_INFO + +#ifdef SHOW_DEBUG_INFO +#include +#define PRF(x) x +#else +#define PRF(x) +#endif #include "../../../../C/CpuArch.h" @@ -14,6 +21,8 @@ #include "../../Common/StreamObjects.h" #include "../../Common/StreamUtils.h" +#include "../../Compress/XPressDecoder.h" + #include "../Common/OutStreamWithSha1.h" #include "WimIn.h" @@ -25,245 +34,397 @@ namespace NArchive { namespace NWim { -namespace NXpress { +static int inline GetLog(UInt32 num) +{ + for (int i = 0; i < 32; i++) + if (((UInt32)1 << i) == num) + return i; + return -1; +} + -class CDecoderFlusher +CUnpacker::~CUnpacker() { - CDecoder *m_Decoder; -public: - bool NeedFlush; - CDecoderFlusher(CDecoder *decoder): m_Decoder(decoder), NeedFlush(true) {} - ~CDecoderFlusher() - { - if (NeedFlush) - m_Decoder->Flush(); - } -}; + if (lzmsDecoder) + delete lzmsDecoder; +} + -HRESULT CDecoder::CodeSpec(UInt32 outSize) +HRESULT CUnpacker::UnpackChunk( + ISequentialInStream *inStream, + unsigned method, unsigned chunkSizeBits, + size_t inSize, size_t outSize, + ISequentialOutStream *outStream) { + if (inSize == outSize) + { + } + else if (method == NMethod::kXPRESS) + { + } + else if (method == NMethod::kLZX) { - Byte levels[kMainTableSize]; - for (unsigned i = 0; i < kMainTableSize; i += 2) + if (!lzxDecoder) { - Byte b = m_InBitStream.DirectReadByte(); - levels[i] = (Byte)(b & 0xF); - levels[i + 1] = (Byte)(b >> 4); + lzxDecoderSpec = new NCompress::NLzx::CDecoder(true); + lzxDecoder = lzxDecoderSpec; } - if (!m_MainDecoder.SetCodeLengths(levels)) - return S_FALSE; } + else if (method == NMethod::kLZMS) + { + if (!lzmsDecoder) + lzmsDecoder = new NCompress::NLzms::CDecoder(); + } + else + return E_NOTIMPL; - while (outSize > 0) + const size_t chunkSize = (size_t)1 << chunkSizeBits; + + unpackBuf.EnsureCapacity(chunkSize); + if (!unpackBuf.Data) + return E_OUTOFMEMORY; + + HRESULT res = S_FALSE; + size_t unpackedSize = 0; + + if (inSize == outSize) + { + unpackedSize = outSize; + res = ReadStream(inStream, unpackBuf.Data, &unpackedSize); + TotalPacked += unpackedSize; + } + else if (inSize < chunkSize) { - UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream); - if (number < 256) + packBuf.EnsureCapacity(chunkSize); + if (!packBuf.Data) + return E_OUTOFMEMORY; + + RINOK(ReadStream_FALSE(inStream, packBuf.Data, inSize)); + + TotalPacked += inSize; + + if (method == NMethod::kXPRESS) + { + res = NCompress::NXpress::Decode(packBuf.Data, inSize, unpackBuf.Data, outSize); + if (res == S_OK) + unpackedSize = outSize; + } + else if (method == NMethod::kLZX) { - m_OutWindowStream.PutByte((Byte)number); - outSize--; + lzxDecoderSpec->SetExternalWindow(unpackBuf.Data, chunkSizeBits); + lzxDecoderSpec->KeepHistoryForNext = false; + lzxDecoderSpec->SetKeepHistory(false); + res = lzxDecoderSpec->Code(packBuf.Data, inSize, (UInt32)outSize); + unpackedSize = lzxDecoderSpec->GetUnpackSize(); + if (res == S_OK && !lzxDecoderSpec->WasBlockFinished()) + res = S_FALSE; } else { - if (number >= kMainTableSize) - return S_FALSE; - UInt32 posLenSlot = number - 256; - UInt32 posSlot = posLenSlot / kNumLenSlots; - UInt32 len = posLenSlot % kNumLenSlots; - UInt32 distance = (1 << posSlot) - 1 + m_InBitStream.ReadBits(posSlot); - - if (len == kNumLenSlots - 1) - { - len = m_InBitStream.DirectReadByte(); - if (len == 0xFF) - { - len = m_InBitStream.DirectReadByte(); - len |= (UInt32)m_InBitStream.DirectReadByte() << 8; - } - else - len += kNumLenSlots - 1; - } - - len += kMatchMinLen; - UInt32 locLen = (len <= outSize ? len : outSize); - - if (!m_OutWindowStream.CopyBlock(distance, locLen)) - return S_FALSE; - - len -= locLen; - outSize -= locLen; - if (len != 0) - return S_FALSE; + res = lzmsDecoder->Code(packBuf.Data, inSize, unpackBuf.Data, outSize); + unpackedSize = lzmsDecoder->GetUnpackSize();; } } - return S_OK; + + if (unpackedSize != outSize) + { + if (res == S_OK) + res = S_FALSE; + + if (unpackedSize > outSize) + res = S_FALSE; + else + memset(unpackBuf.Data + unpackedSize, 0, outSize - unpackedSize); + } + + if (outStream) + { + RINOK(WriteStream(outStream, unpackBuf.Data, outSize)); + } + + return res; } -const UInt32 kDictSize = (1 << kNumPosSlots); -HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, UInt32 outSize) +HRESULT CUnpacker::Unpack2( + IInStream *inStream, + const CResource &resource, + const CHeader &header, + const CDatabase *db, + ISequentialOutStream *outStream, + ICompressProgressInfo *progress) { - if (!m_OutWindowStream.Create(kDictSize) || !m_InBitStream.Create(1 << 16)) - return E_OUTOFMEMORY; + if (!resource.IsCompressed() && !resource.IsSolid()) + { + if (!copyCoder) + { + copyCoderSpec = new NCompress::CCopyCoder; + copyCoder = copyCoderSpec; + } - CDecoderFlusher flusher(this); + CLimitedSequentialInStream *limitedStreamSpec = new CLimitedSequentialInStream(); + CMyComPtr limitedStream = limitedStreamSpec; + limitedStreamSpec->SetStream(inStream); + + RINOK(inStream->Seek(resource.Offset, STREAM_SEEK_SET, NULL)); + if (resource.PackSize != resource.UnpackSize) + return S_FALSE; - m_InBitStream.SetStream(inStream); - m_OutWindowStream.SetStream(outStream); - m_InBitStream.Init(); - m_OutWindowStream.Init(false); + limitedStreamSpec->Init(resource.PackSize); + TotalPacked += resource.PackSize; + + HRESULT res = copyCoder->Code(limitedStream, outStream, NULL, NULL, progress); + + if (res == S_OK && copyCoderSpec->TotalSize != resource.UnpackSize) + res = S_FALSE; + return res; + } + + if (resource.IsSolid()) + { + if (!db || resource.SolidIndex < 0) + return E_NOTIMPL; + if (resource.IsCompressed()) + return E_NOTIMPL; - RINOK(CodeSpec(outSize)); + const CSolid &ss = db->Solids[resource.SolidIndex]; + + const unsigned chunkSizeBits = ss.ChunkSizeBits; + const size_t chunkSize = (size_t)1 << chunkSizeBits; + + size_t chunkIndex = 0; + UInt64 rem = ss.UnpackSize; + size_t offsetInChunk = 0; + + if (resource.IsSolidSmall()) + { + UInt64 offs = resource.Offset; + if (offs < ss.SolidOffset) + return E_NOTIMPL; + offs -= ss.SolidOffset; + if (offs > ss.UnpackSize) + return E_NOTIMPL; + rem = resource.PackSize; + if (rem > ss.UnpackSize - offs) + return E_NOTIMPL; + chunkIndex = (size_t)(offs >> chunkSizeBits); + offsetInChunk = (size_t)offs & (chunkSize - 1); + } + + UInt64 packProcessed = 0; + UInt64 outProcessed = 0; + + if (_solidIndex == resource.SolidIndex && _unpackedChunkIndex == chunkIndex) + { + size_t cur = chunkSize - offsetInChunk; + if (cur > rem) + cur = (size_t)rem; + RINOK(WriteStream(outStream, unpackBuf.Data + offsetInChunk, cur)); + outProcessed += cur; + rem -= cur; + offsetInChunk = 0; + chunkIndex++; + } + + for (;;) + { + if (rem == 0) + return S_OK; + + UInt64 offset = ss.Chunks[chunkIndex]; + UInt64 packSize = ss.GetChunkPackSize(chunkIndex); + const CResource &rs = db->DataStreams[ss.StreamIndex].Resource; + RINOK(inStream->Seek(rs.Offset + ss.HeadersSize + offset, STREAM_SEEK_SET, NULL)); + + size_t cur = chunkSize; + UInt64 unpackRem = ss.UnpackSize - ((UInt64)chunkIndex << chunkSizeBits); + if (cur > unpackRem) + cur = (size_t)unpackRem; + + _solidIndex = -1; + _unpackedChunkIndex = 0; + + HRESULT res = UnpackChunk(inStream, ss.Method, chunkSizeBits, (size_t)packSize, cur, NULL); + + if (res != S_OK) + { + // We ignore data errors in solid stream. SHA will show what files are bad. + if (res != S_FALSE) + return res; + } + + _solidIndex = resource.SolidIndex; + _unpackedChunkIndex = chunkIndex; + + if (cur > rem) + cur = (size_t)rem; + + RINOK(WriteStream(outStream, unpackBuf.Data + offsetInChunk, cur)); + + if (progress) + { + RINOK(progress->SetRatioInfo(&packProcessed, &outProcessed)); + packProcessed += packSize; + outProcessed += cur; + } + + rem -= cur; + offsetInChunk = 0; + chunkIndex++; + } + } - flusher.NeedFlush = false; - return Flush(); -} -HRESULT CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, UInt32 outSize) -{ - try { return CodeReal(inStream, outStream, outSize); } - catch(const CInBufferException &e) { return e.ErrorCode; } \ - catch(const CLzOutWindowException &e) { return e.ErrorCode; } - catch(...) { return S_FALSE; } -} + // ---------- NON Solid ---------- -} + const UInt64 unpackSize = resource.UnpackSize; + if (unpackSize == 0) + { + if (resource.PackSize == 0) + return S_OK; + return S_FALSE; + } -HRESULT CUnpacker::Unpack(IInStream *inStream, const CResource &resource, bool lzxMode, - ISequentialOutStream *outStream, ICompressProgressInfo *progress) -{ - RINOK(inStream->Seek(resource.Offset, STREAM_SEEK_SET, NULL)); + if (unpackSize > ((UInt64)1 << 63)) + return E_NOTIMPL; - CLimitedSequentialInStream *limitedStreamSpec = new CLimitedSequentialInStream(); - CMyComPtr limitedStream = limitedStreamSpec; - limitedStreamSpec->SetStream(inStream); + const unsigned chunkSizeBits = header.ChunkSizeBits; + const unsigned entrySizeShifts = (resource.UnpackSize < ((UInt64)1 << 32) ? 2 : 3); - if (!copyCoder) - { - copyCoderSpec = new NCompress::CCopyCoder; - copyCoder = copyCoderSpec; - } - if (!resource.IsCompressed()) + UInt64 baseOffset = resource.Offset; + UInt64 packDataSize; + size_t numChunks; { - if (resource.PackSize != resource.UnpackSize) + UInt64 numChunks64 = (unpackSize + (((UInt32)1 << chunkSizeBits) - 1)) >> chunkSizeBits; + UInt64 sizesBufSize64 = (numChunks64 - 1) << entrySizeShifts; + if (sizesBufSize64 > resource.PackSize) return S_FALSE; - limitedStreamSpec->Init(resource.PackSize); - return copyCoder->Code(limitedStreamSpec, outStream, NULL, NULL, progress); - } - if (resource.UnpackSize == 0) - return S_OK; - UInt64 numChunks = (resource.UnpackSize + kChunkSize - 1) >> kChunkSizeBits; - unsigned entrySize = ((resource.UnpackSize > (UInt64)1 << 32) ? 8 : 4); - UInt64 sizesBufSize64 = entrySize * (numChunks - 1); - size_t sizesBufSize = (size_t)sizesBufSize64; - if (sizesBufSize != sizesBufSize64) - return E_OUTOFMEMORY; - sizesBuf.AllocAtLeast(sizesBufSize); - RINOK(ReadStream_FALSE(inStream, (Byte *)sizesBuf, sizesBufSize)); - const Byte *p = (const Byte *)sizesBuf; - - if (lzxMode && !lzxDecoder) - { - lzxDecoderSpec = new NCompress::NLzx::CDecoder(true); - lzxDecoder = lzxDecoderSpec; - RINOK(lzxDecoderSpec->SetParams(kChunkSizeBits)); + packDataSize = resource.PackSize - sizesBufSize64; + size_t sizesBufSize = (size_t)sizesBufSize64; + if (sizesBufSize != sizesBufSize64) + return E_OUTOFMEMORY; + sizesBuf.AllocAtLeast(sizesBufSize); + RINOK(inStream->Seek(baseOffset, STREAM_SEEK_SET, NULL)); + RINOK(ReadStream_FALSE(inStream, sizesBuf, sizesBufSize)); + baseOffset += sizesBufSize64; + numChunks = (size_t)numChunks64; } - - UInt64 baseOffset = resource.Offset + sizesBufSize64; + + _solidIndex = -1; + _unpackedChunkIndex = 0; + UInt64 outProcessed = 0; - for (UInt32 i = 0; i < (UInt32)numChunks; i++) + UInt64 offset = 0; + + for (size_t i = 0; i < numChunks; i++) { - UInt64 offset = 0; - if (i > 0) + UInt64 nextOffset = packDataSize; + + if (i + 1 < numChunks) { - offset = (entrySize == 4) ? Get32(p): Get64(p); - p += entrySize; + const Byte *p = (const Byte *)sizesBuf + (i << entrySizeShifts); + nextOffset = (entrySizeShifts == 2) ? Get32(p): Get64(p); } - UInt64 nextOffset = resource.PackSize - sizesBufSize64; - if (i + 1 < (UInt32)numChunks) - nextOffset = (entrySize == 4) ? Get32(p): Get64(p); + if (nextOffset < offset) return S_FALSE; + UInt64 inSize64 = nextOffset - offset; + size_t inSize = (size_t)inSize64; + if (inSize != inSize64) + return S_FALSE; + RINOK(inStream->Seek(baseOffset + offset, STREAM_SEEK_SET, NULL)); - UInt64 inSize = nextOffset - offset; - limitedStreamSpec->Init(inSize); if (progress) { RINOK(progress->SetRatioInfo(&offset, &outProcessed)); } - UInt32 outSize = kChunkSize; - if (outProcessed + outSize > resource.UnpackSize) - outSize = (UInt32)(resource.UnpackSize - outProcessed); - UInt64 outSize64 = outSize; - if (inSize == outSize) - { - RINOK(copyCoder->Code(limitedStreamSpec, outStream, NULL, &outSize64, NULL)); - } - else - { - if (lzxMode) - { - lzxDecoderSpec->SetKeepHistory(false); - RINOK(lzxDecoder->Code(limitedStreamSpec, outStream, NULL, &outSize64, NULL)); - } - else - { - RINOK(xpressDecoder.Code(limitedStreamSpec, outStream, outSize)); - } - } + size_t outSize = (size_t)1 << chunkSizeBits; + const UInt64 rem = unpackSize - outProcessed; + if (outSize > rem) + outSize = (size_t)rem; + + RINOK(UnpackChunk(inStream, header.GetMethod(), chunkSizeBits, inSize, outSize, outStream)); + outProcessed += outSize; + offset = nextOffset; } + return S_OK; } -HRESULT CUnpacker::Unpack(IInStream *inStream, const CResource &resource, bool lzxMode, + +HRESULT CUnpacker::Unpack(IInStream *inStream, const CResource &resource, const CHeader &header, const CDatabase *db, ISequentialOutStream *outStream, ICompressProgressInfo *progress, Byte *digest) { - COutStreamWithSha1 *shaStreamSpec = new COutStreamWithSha1(); - CMyComPtr shaStream = shaStreamSpec; - shaStreamSpec->SetStream(outStream); - shaStreamSpec->Init(digest != NULL); - HRESULT result = Unpack(inStream, resource, lzxMode, shaStream, progress); + COutStreamWithSha1 *shaStreamSpec = NULL; + CMyComPtr shaStream; + + // outStream can be NULL, so we use COutStreamWithSha1 even if sha1 is not required + // if (digest) + { + shaStreamSpec = new COutStreamWithSha1(); + shaStream = shaStreamSpec; + shaStreamSpec->SetStream(outStream); + shaStreamSpec->Init(digest != NULL); + outStream = shaStream; + } + + HRESULT res = Unpack2(inStream, resource, header, db, outStream, progress); + if (digest) shaStreamSpec->Final(digest); - return result; + + return res; } -static HRESULT UnpackData(IInStream *inStream, const CResource &resource, bool lzxMode, CByteBuffer &buf, Byte *digest) + +HRESULT CUnpacker::UnpackData(IInStream *inStream, + const CResource &resource, const CHeader &header, + const CDatabase *db, + CByteBuffer &buf, Byte *digest) { - size_t size = (size_t)resource.UnpackSize; - if (size != resource.UnpackSize) + // if (resource.IsSolid()) return E_NOTIMPL; + + UInt64 unpackSize64 = resource.UnpackSize; + if (db) + unpackSize64 = db->Get_UnpackSize_of_Resource(resource); + + size_t size = (size_t)unpackSize64; + if (size != unpackSize64) return E_OUTOFMEMORY; + buf.Alloc(size); CBufPtrSeqOutStream *outStreamSpec = new CBufPtrSeqOutStream(); CMyComPtr outStream = outStreamSpec; outStreamSpec->Init((Byte *)buf, size); - CUnpacker unpacker; - return unpacker.Unpack(inStream, resource, lzxMode, outStream, NULL, digest); + return Unpack(inStream, resource, header, db, outStream, NULL, digest); } + void CResource::Parse(const Byte *p) { Flags = p[7]; PackSize = Get64(p) & (((UInt64)1 << 56) - 1); Offset = Get64(p + 8); UnpackSize = Get64(p + 16); + KeepSolid = false; + SolidIndex = -1; } #define GET_RESOURCE(_p_, res) res.ParseAndUpdatePhySize(_p_, phySize) -static void GetStream(bool oldVersion, const Byte *p, CStreamInfo &s) +static inline void ParseStream(bool oldVersion, const Byte *p, CStreamInfo &s) { s.Resource.Parse(p); if (oldVersion) { s.PartNumber = 1; s.Id = Get32(p + 24); - // printf("\n%d", s.Id); p += 28; } else @@ -300,6 +461,7 @@ void CDatabase::GetShortName(unsigned index, NWindows::NCOM::CPropVariant &name) // empty shortName has no ZERO at the end ? } + void CDatabase::GetItemName(unsigned index, NWindows::NCOM::CPropVariant &name) const { const CItem &item = Items[index]; @@ -321,6 +483,7 @@ void CDatabase::GetItemName(unsigned index, NWindows::NCOM::CPropVariant &name) s[i] = Get16(meta + i * 2); } + void CDatabase::GetItemPath(unsigned index1, bool showImageNumber, NWindows::NCOM::CPropVariant &path) const { unsigned size = 0; @@ -403,22 +566,16 @@ void CDatabase::GetItemPath(unsigned index1, bool showImageNumber, NWindows::NCO } } -static bool IsEmptySha(const Byte *data) -{ - for (unsigned i = 0; i < kHashSize; i++) - if (data[i] != 0) - return false; - return true; -} -// Root folders in OLD archives (ver = 1.10) conatin real items. -// Root folders in NEW archives (ver > 1.11) contain only one folder with empty name. +// if (ver <= 1.10), root folder contains real items. +// if (ver >= 1.12), root folder contains only one folder with empty name. HRESULT CDatabase::ParseDirItem(size_t pos, int parent) { - if ((pos & 7) != 0) + const unsigned align = GetDirAlignMask(); + if ((pos & align) != 0) return S_FALSE; - + for (unsigned numItems = 0;; numItems++) { if (OpenCallback && (Items.Size() & 0xFFFF) == 0) @@ -426,25 +583,28 @@ HRESULT CDatabase::ParseDirItem(size_t pos, int parent) UInt64 numFiles = Items.Size(); RINOK(OpenCallback->SetCompleted(&numFiles, NULL)); } + size_t rem = DirSize - pos; if (pos < DirStartOffset || pos > DirSize || rem < 8) return S_FALSE; + const Byte *p = DirData + pos; + UInt64 len = Get64(p); if (len == 0) { - if (parent < 0 && numItems != 1) - Images.Back().NumEmptyRootItems = 0; DirProcessed += 8; return S_OK; } - if ((len & 7) != 0 || rem < len) + + if ((len & align) != 0 || rem < len) return S_FALSE; + DirProcessed += (size_t)len; if (DirProcessed > DirSize) return S_FALSE; - UInt32 dirRecordSize = IsOldVersion ? kDirRecordSizeOld : kDirRecordSize; + const unsigned dirRecordSize = IsOldVersion ? kDirRecordSizeOld : kDirRecordSize; if (len < dirRecordSize) return S_FALSE; @@ -452,14 +612,15 @@ HRESULT CDatabase::ParseDirItem(size_t pos, int parent) UInt32 attrib = Get32(p + 8); item.IsDir = ((attrib & 0x10) != 0); UInt64 subdirOffset = Get64(p + 0x10); - UInt32 numAltStreams = Get16(p + dirRecordSize - 6); - UInt32 shortNameLen = Get16(p + dirRecordSize - 4); - UInt32 fileNameLen = Get16(p + dirRecordSize - 2); + + const UInt32 numAltStreams = Get16(p + dirRecordSize - 6); + const UInt32 shortNameLen = Get16(p + dirRecordSize - 4); + const UInt32 fileNameLen = Get16(p + dirRecordSize - 2); 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 (((dirRecordSize + fileNameLen2 + shortNameLen2 + 6) & ~7) > len) + const UInt32 shortNameLen2 = (shortNameLen == 0 ? shortNameLen : shortNameLen + 2); + const UInt32 fileNameLen2 = (fileNameLen == 0 ? fileNameLen : fileNameLen + 2); + if (((dirRecordSize + fileNameLen2 + shortNameLen2 + align) & ~align) > len) return S_FALSE; p += dirRecordSize; @@ -471,6 +632,9 @@ HRESULT CDatabase::ParseDirItem(size_t pos, int parent) if (*(const UInt16 *)(p + j) == 0) return S_FALSE; } + + // PRF(printf("\n%S", p)); + if (shortNameLen != 0) { // empty shortName has no ZERO at the end ? @@ -485,36 +649,27 @@ HRESULT CDatabase::ParseDirItem(size_t pos, int parent) item.Offset = pos; item.Parent = parent; item.ImageIndex = Images.Size() - 1; - unsigned prevIndex = Items.Add(item); + + const unsigned prevIndex = Items.Add(item); pos += (size_t)len; - unsigned numItems2 = Items.Size(); - for (UInt32 i = 0; i < numAltStreams; i++) { - size_t rem = DirSize - pos; + const size_t rem = DirSize - pos; if (pos < DirStartOffset || pos > DirSize || rem < 8) return S_FALSE; const Byte *p = DirData + pos; - UInt64 len = Get64(p); - if (len == 0) + const UInt64 len = Get64(p); + if ((len & align) != 0 || rem < len || len < (IsOldVersion ? 0x18 : 0x28)) return S_FALSE; - if ((len & 7) != 0 || rem < len) - return S_FALSE; - if (IsOldVersion) - { - if (len < 0x18) - return S_FALSE; - } - else - if (len < 0x28) - return S_FALSE; + DirProcessed += (size_t)len; if (DirProcessed > DirSize) return S_FALSE; unsigned extraOffset = 0; + if (IsOldVersion) extraOffset = 0x10; else @@ -523,13 +678,14 @@ HRESULT CDatabase::ParseDirItem(size_t pos, int parent) return S_FALSE; extraOffset = 0x24; } + UInt32 fileNameLen = Get16(p + extraOffset); if ((fileNameLen & 1) != 0) return S_FALSE; /* Probably different versions of ImageX can use different number of additional ZEROs. So we don't use exact check. */ UInt32 fileNameLen2 = (fileNameLen == 0 ? fileNameLen : fileNameLen + 2); - if (((extraOffset + 2 + fileNameLen2 + 6) & ~7) > len) + if (((extraOffset + 2 + fileNameLen2 + align) & ~align) > len) return S_FALSE; { @@ -539,21 +695,30 @@ HRESULT CDatabase::ParseDirItem(size_t pos, int parent) for (UInt32 j = 0; j < fileNameLen; j += 2) if (*(const UInt16 *)(p2 + j) == 0) return S_FALSE; + + // PRF(printf("\n %S", p2)); } /* wim uses alt sreams list, if there is at least one alt stream. - And alt stream without name is main stream. */ + And alt stream without name is main stream. */ + + // Why wimlib writes two alt streams for REPARSE_POINT, with empty second alt stream? + Byte *prevMeta = DirData + item.Offset; + if (fileNameLen == 0 && - (attrib & FILE_ATTRIBUTE_REPARSE_POINT - || !item.IsDir /* && (IsOldVersion || IsEmptySha(prevMeta + 0x40)) */ )) + ((attrib & FILE_ATTRIBUTE_REPARSE_POINT) || !item.IsDir) + && (IsOldVersion || IsEmptySha(prevMeta + 0x40))) { - Byte *prevMeta = DirData + item.Offset; if (IsOldVersion) memcpy(prevMeta + 0x10, p + 8, 4); // It's 32-bit Id - else - memcpy(prevMeta + 0x40, p + 0x10, kHashSize); + else if (!IsEmptySha(p + 0x10)) + { + // if (IsEmptySha(prevMeta + 0x40)) + memcpy(prevMeta + 0x40, p + 0x10, kHashSize); + // else HeadersError = true; + } } else { @@ -565,13 +730,31 @@ HRESULT CDatabase::ParseDirItem(size_t pos, int parent) item2.ImageIndex = Images.Size() - 1; Items.Add(item2); } + pos += (size_t)len; } if (parent < 0 && numItems == 0 && shortNameLen == 0 && fileNameLen == 0 && item.IsDir) { - CImage &image = Images.Back(); - image.NumEmptyRootItems = numItems2 - image.StartItem; // Items.Size() + const Byte *p2 = DirData + pos; + if (DirSize - pos >= 8 && Get64(p2) == 0) + { + CImage &image = Images.Back(); + image.NumEmptyRootItems = 1; + + if (subdirOffset != 0 + && DirSize - pos >= 16 + && Get64(p2 + 8) != 0 + && pos + 8 < subdirOffset) + { + // Longhorn.4093 contains hidden files after empty root folder and before items of next folder. Why? + // That code shows them. If we want to ignore them, we need to update DirProcessed. + // DirProcessed += (size_t)(subdirOffset - (pos + 8)); + // printf("\ndirOffset = %5d hiddenOffset = %5d\n", (int)subdirOffset, (int)pos + 8); + subdirOffset = pos + 8; + // return S_FALSE; + } + } } if (item.IsDir && subdirOffset != 0) @@ -581,6 +764,7 @@ HRESULT CDatabase::ParseDirItem(size_t pos, int parent) } } + HRESULT CDatabase::ParseImageDirs(CByteBuffer &buf, int parent) { DirData = buf; @@ -593,29 +777,37 @@ HRESULT CDatabase::ParseImageDirs(CByteBuffer &buf, int parent) if (IsOldVersion) { - // there is no specification about that code - UInt32 sum = 0; - image.SecurOffsets.Add(0); - for (;;) + UInt32 numEntries = Get32(p + 4); + + if (numEntries > (1 << 28) || + numEntries > (DirSize >> 3)) + return S_FALSE; + + UInt32 sum = 8; + if (numEntries != 0) + sum = numEntries * 8; + + image.SecurOffsets.ClearAndReserve(numEntries + 1); + image.SecurOffsets.AddInReserved(sum); + + for (UInt32 i = 0; i < numEntries; i++) { - if (pos + 8 > DirSize) + const Byte *pp = p + (size_t)i * 8; + UInt32 len = Get32(pp); + if (i != 0 && Get32(pp + 4) != 0) return S_FALSE; - UInt32 len = Get32(p + pos); if (len > DirSize - sum) return S_FALSE; sum += len; - image.SecurOffsets.Add(sum); - UInt32 n = Get32(p + pos + 4); // what does this field mean? - pos += 8; - if (n == 0) - break; + if (sum < len) + return S_FALSE; + image.SecurOffsets.AddInReserved(sum); } - if (sum > DirSize - pos) - return S_FALSE; - FOR_VECTOR (i, image.SecurOffsets) - image.SecurOffsets[i] += (UInt32)pos; - pos += sum; - pos = (pos + 7) & ~(size_t)7; + + pos = sum; + + const size_t align = GetDirAlignMask(); + pos = (pos + align) & ~(size_t)align; } else { @@ -633,6 +825,7 @@ HRESULT CDatabase::ParseImageDirs(CByteBuffer &buf, int parent) UInt32 sum = (UInt32)pos + numEntries * 8; image.SecurOffsets.ClearAndReserve(numEntries + 1); image.SecurOffsets.AddInReserved(sum); + for (UInt32 i = 0; i < numEntries; i++, pos += 8) { UInt64 len = Get64(p + pos); @@ -641,6 +834,7 @@ HRESULT CDatabase::ParseImageDirs(CByteBuffer &buf, int parent) sum += (UInt32)len; image.SecurOffsets.AddInReserved(sum); } + pos = sum; pos = (pos + 7) & ~(size_t)7; if (pos != (((size_t)totalLen + 7) & ~(size_t)7)) @@ -650,21 +844,27 @@ HRESULT CDatabase::ParseImageDirs(CByteBuffer &buf, int parent) if (pos > DirSize) return S_FALSE; + DirStartOffset = DirProcessed = pos; image.StartItem = Items.Size(); + RINOK(ParseDirItem(pos, parent)); + image.NumItems = Items.Size() - image.StartItem; if (DirProcessed == DirSize) return S_OK; + /* Original program writes additional 8 bytes (END_OF_ROOT_FOLDER), but the reference to that folder is empty */ // we can't use DirProcessed - DirStartOffset == 112 check if there is alt stream in root - if (DirProcessed == DirSize - 8 && Get64(p + DirSize - 8) == 0) + if (DirProcessed == DirSize - 8 && Get64(p + DirSize - 8) != 0) return S_OK; + return S_FALSE; } + HRESULT CHeader::Parse(const Byte *p, UInt64 &phySize) { UInt32 headerSize = Get32(p + 8); @@ -673,10 +873,37 @@ HRESULT CHeader::Parse(const Byte *p, UInt64 &phySize) Flags = Get32(p + 0x10); if (!IsSupported()) return S_FALSE; - ChunkSize = Get32(p + 0x14); - if (ChunkSize != kChunkSize && ChunkSize != 0) - return S_FALSE; + + { + ChunkSize = Get32(p + 0x14); + ChunkSizeBits = kChunkSizeBits; + if (ChunkSize != 0) + { + int log = GetLog(ChunkSize); + if (log < 12) + return S_FALSE; + ChunkSizeBits = log; + } + } + + _IsOldVersion = false; + _IsNewVersion = false; + + if (IsSolidVersion()) + _IsNewVersion = true; + else + { + if (Version < 0x010900) + return S_FALSE; + _IsOldVersion = (Version <= 0x010A00); + // We don't know details about 1.11 version. So we use headerSize to guess exact features. + if (Version == 0x010B00 && headerSize == 0x60) + _IsOldVersion = true; + _IsNewVersion = (Version >= 0x010D00); + } + unsigned offset; + if (IsOldVersion()) { if (headerSize != 0x60) @@ -693,21 +920,26 @@ HRESULT CHeader::Parse(const Byte *p, UInt64 &phySize) memcpy(Guid, p + 0x18, 16); PartNumber = Get16(p + 0x28); NumParts = Get16(p + 0x2A); + if (PartNumber == 0 || PartNumber > NumParts) + return S_FALSE; offset = 0x2C; if (IsNewVersion()) { + // if (headerSize < 0xD0) + if (headerSize != 0xD0) + return S_FALSE; NumImages = Get32(p + offset); offset += 4; } } + GET_RESOURCE(p + offset , OffsetResource); GET_RESOURCE(p + offset + 0x18, XmlResource); GET_RESOURCE(p + offset + 0x30, MetadataResource); BootIndex = 0; + if (IsNewVersion()) { - if (headerSize < 0xD0) - return S_FALSE; BootIndex = Get32(p + offset + 0x48); GET_RESOURCE(p + offset + 0x4C, IntegrityResource); } @@ -715,6 +947,7 @@ HRESULT CHeader::Parse(const Byte *p, UInt64 &phySize) return S_OK; } + const Byte kSignature[kSignatureSize] = { 'M', 'S', 'W', 'I', 'M', 0, 0, 0 }; HRESULT ReadHeader(IInStream *inStream, CHeader &h, UInt64 &phySize) @@ -726,40 +959,85 @@ HRESULT ReadHeader(IInStream *inStream, CHeader &h, UInt64 &phySize) return h.Parse(p, phySize); } + static HRESULT ReadStreams(IInStream *inStream, const CHeader &h, CDatabase &db) { CByteBuffer offsetBuf; - RINOK(UnpackData(inStream, h.OffsetResource, h.IsLzxMode(), offsetBuf, NULL)); - size_t i; - size_t streamInfoSize = h.IsOldVersion() ? kStreamInfoSize + 2 : kStreamInfoSize; - for (i = 0; offsetBuf.Size() - i >= streamInfoSize; i += streamInfoSize) + + CUnpacker unpacker; + RINOK(unpacker.UnpackData(inStream, h.OffsetResource, h, NULL, offsetBuf, NULL)); + + const size_t streamInfoSize = h.IsOldVersion() ? kStreamInfoSize + 2 : kStreamInfoSize; + unsigned numItems = (unsigned)(offsetBuf.Size() / streamInfoSize); + if ((size_t)numItems * streamInfoSize != offsetBuf.Size()) + return S_FALSE; + db.DataStreams.Reserve(numItems); + + bool keepSolid = false; + + for (size_t i = 0; i < offsetBuf.Size(); i += streamInfoSize) { CStreamInfo s; - GetStream(h.IsOldVersion(), (const Byte *)offsetBuf + i, s); - if (s.PartNumber == h.PartNumber) + ParseStream(h.IsOldVersion(), (const Byte *)offsetBuf + i, s); + + PRF(printf("\n")); + PRF(printf(s.Resource.IsMetadata() ? "### META" : " DATA")); + PRF(printf(" %2X", s.Resource.Flags)); + PRF(printf(" %9I64X", s.Resource.Offset)); + PRF(printf(" %9I64X", s.Resource.PackSize)); + PRF(printf(" %9I64X", s.Resource.UnpackSize)); + PRF(printf(" %d", s.RefCount)); + + if (s.PartNumber != h.PartNumber) + continue; + + if (s.Resource.IsSolid()) { - if (s.Resource.IsMetadata()) + s.Resource.KeepSolid = keepSolid; + keepSolid = true; + } + else + { + s.Resource.KeepSolid = false; + keepSolid = false; + } + + if (!s.Resource.IsMetadata()) + db.DataStreams.AddInReserved(s); + else + { + if (s.Resource.IsSolid()) + return E_NOTIMPL; + if (s.RefCount == 0) { - if (s.RefCount == 0) - return S_FALSE; - if (s.RefCount > 1) - { - s.RefCount--; - db.DataStreams.Add(s); - } - s.RefCount = 1; - db.MetaStreams.Add(s); + // some wims have such (deleted?) metadata stream. + // examples: boot.wim in VistaBeta2, WinPE.wim from WAIK. + // db.DataStreams.Add(s); + // we can show these delete images, if we comment "continue" command; + continue; } - else - db.DataStreams.Add(s); + + if (s.RefCount > 1) + { + return S_FALSE; + // s.RefCount--; + // db.DataStreams.Add(s); + } + + db.MetaStreams.Add(s); } } - return (i == offsetBuf.Size()) ? S_OK : S_FALSE; + + PRF(printf("\n")); + + return S_OK; } + HRESULT CDatabase::OpenXml(IInStream *inStream, const CHeader &h, CByteBuffer &xml) { - return UnpackData(inStream, h.XmlResource, h.IsLzxMode(), xml, NULL); + CUnpacker unpacker; + return unpacker.UnpackData(inStream, h.XmlResource, h, this, xml, NULL); } static void SetRootNames(CImage &image, unsigned value) @@ -777,66 +1055,63 @@ static void SetRootNames(CImage &image, unsigned value) } } + HRESULT CDatabase::Open(IInStream *inStream, const CHeader &h, unsigned numItemsReserve, IArchiveOpenCallback *openCallback) { OpenCallback = openCallback; IsOldVersion = h.IsOldVersion(); + IsOldVersion9 = (h.Version == 0x10900); + RINOK(ReadStreams(inStream, h, *this)); - // printf("\nh.PartNumber = %02d", (unsigned)h.PartNumber); bool needBootMetadata = !h.MetadataResource.IsEmpty(); + unsigned numNonDeletedImages = 0; + + CUnpacker unpacker; FOR_VECTOR (i, MetaStreams) { const CStreamInfo &si = MetaStreams[i]; - /* - printf("\ni = %5d" - " Refs = %3d" - " Part = %1d" - " Offs = %7X" - " PackSize = %7X" - " Size = %7X" - " Flags = %d " - , - i, - si.RefCount, - (unsigned)si.PartNumber, - (unsigned)si.Resource.Offset, - (unsigned)si.Resource.PackSize, - (unsigned)si.Resource.UnpackSize, - (unsigned)si.Resource.Flags - ); - for (unsigned y = 0; y < 2; y++) - printf("%02X", (unsigned)si.Hash[y]); - */ if (h.PartNumber != 1 || si.PartNumber != h.PartNumber) continue; - Byte hash[kHashSize]; + const int userImage = Images.Size() + GetStartImageIndex(); CImage &image = Images.AddNew(); - SetRootNames(image, Images.Size()); + SetRootNames(image, userImage); + CByteBuffer &metadata = image.Meta; - RINOK(UnpackData(inStream, si.Resource, h.IsLzxMode(), metadata, hash)); + Byte hash[kHashSize]; + + RINOK(unpacker.UnpackData(inStream, si.Resource, h, this, metadata, hash)); + if (memcmp(hash, si.Hash, kHashSize) != 0 && !(h.IsOldVersion() && IsEmptySha(si.Hash))) return S_FALSE; + image.NumEmptyRootItems = 0; + if (Items.IsEmpty()) Items.ClearAndReserve(numItemsReserve); + RINOK(ParseImageDirs(metadata, -1)); + if (needBootMetadata) { bool sameRes = (h.MetadataResource.Offset == si.Resource.Offset); if (sameRes) needBootMetadata = false; - bool isBootIndex = (h.BootIndex == (UInt32)Images.Size()); if (h.IsNewVersion()) { - if (sameRes && !isBootIndex) - return S_FALSE; - if (isBootIndex && !sameRes) - return S_FALSE; + if (si.RefCount == 1) + { + numNonDeletedImages++; + bool isBootIndex = (h.BootIndex == numNonDeletedImages); + if (sameRes && !isBootIndex) + return S_FALSE; + if (isBootIndex && !sameRes) + return S_FALSE; + } } } } @@ -847,6 +1122,25 @@ HRESULT CDatabase::Open(IInStream *inStream, const CHeader &h, unsigned numItems } +bool CDatabase::ItemHasStream(const CItem &item) const +{ + if (item.ImageIndex < 0) + return true; + const Byte *meta = Images[item.ImageIndex].Meta + item.Offset; + if (IsOldVersion) + { + // old wim use same field for file_id and dir_offset; + if (item.IsDir) + return false; + meta += (item.IsAltStream ? 0x8 : 0x10); + UInt32 id = GetUi32(meta); + return id != 0; + } + meta += (item.IsAltStream ? 0x10 : 0x40); + return !IsEmptySha(meta); +} + + #define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; } static int CompareStreamsByPos(const CStreamInfo *p1, const CStreamInfo *p2, void * /* param */) @@ -858,24 +1152,23 @@ static int CompareStreamsByPos(const CStreamInfo *p1, const CStreamInfo *p2, voi static int CompareIDs(const unsigned *p1, const unsigned *p2, void *param) { - const CRecordVector &streams = *(const CRecordVector *)param; + const CStreamInfo *streams = (const CStreamInfo *)param; return MyCompare(streams[*p1].Id, streams[*p2].Id); } static int CompareHashRefs(const unsigned *p1, const unsigned *p2, void *param) { - const CRecordVector &streams = *(const CRecordVector *)param; + const CStreamInfo *streams = (const CStreamInfo *)param; return memcmp(streams[*p1].Hash, streams[*p2].Hash, kHashSize); } -static int FindId(const CRecordVector &streams, - const CUIntVector &sortedByHash, UInt32 id) +static int FindId(const CStreamInfo *streams, const CUIntVector &sorted, UInt32 id) { - unsigned left = 0, right = streams.Size(); + unsigned left = 0, right = sorted.Size(); while (left != right) { unsigned mid = (left + right) / 2; - unsigned streamIndex = sortedByHash[mid]; + unsigned streamIndex = sorted[mid]; UInt32 id2 = streams[streamIndex].Id; if (id == id2) return streamIndex; @@ -887,14 +1180,13 @@ static int FindId(const CRecordVector &streams, return -1; } -static int FindHash(const CRecordVector &streams, - const CUIntVector &sortedByHash, const Byte *hash) +static int FindHash(const CStreamInfo *streams, const CUIntVector &sorted, const Byte *hash) { - unsigned left = 0, right = streams.Size(); + unsigned left = 0, right = sorted.Size(); while (left != right) { unsigned mid = (left + right) / 2; - unsigned streamIndex = sortedByHash[mid]; + unsigned streamIndex = sorted[mid]; const Byte *hash2 = streams[streamIndex].Hash; unsigned i; for (i = 0; i < kHashSize; i++) @@ -910,27 +1202,6 @@ static int FindHash(const CRecordVector &streams, return -1; } -bool CDatabase::ItemHasStream(const CItem &item) const -{ - if (item.ImageIndex < 0) - return true; - const Byte *meta = Images[item.ImageIndex].Meta + item.Offset; - if (IsOldVersion) - { - // old wim use same field for file_id and dir_offset; - if (item.IsDir) - return false; - meta += (item.IsAltStream ? 0x8 : 0x10); - UInt32 id = GetUi32(meta); - return id != 0; - } - meta += (item.IsAltStream ? 0x10 : 0x40); - for (unsigned i = 0; i < kHashSize; i++) - if (meta[i] != 0) - return true; - return false; -} - static int CompareItems(const unsigned *a1, const unsigned *a2, void *param) { const CRecordVector &items = ((CDatabase *)param)->Items; @@ -946,10 +1217,190 @@ static int CompareItems(const unsigned *a1, const unsigned *a2, void *param) return MyCompare(i1.Offset, i2.Offset); } -HRESULT CDatabase::FillAndCheck() + +HRESULT CDatabase::FillAndCheck(const CObjectVector &volumes) { + CUIntVector sortedByHash; + sortedByHash.Reserve(DataStreams.Size()); { - DataStreams.Sort(CompareStreamsByPos, NULL); + CByteBuffer sizesBuf; + + for (unsigned iii = 0; iii < DataStreams.Size();) + { + { + const CResource &r = DataStreams[iii].Resource; + if (!r.IsSolid()) + { + sortedByHash.AddInReserved(iii++); + continue; + } + } + + UInt64 solidRunOffset = 0; + unsigned k; + unsigned numSolidsStart = Solids.Size(); + + for (k = iii; k < DataStreams.Size(); k++) + { + CStreamInfo &si = DataStreams[k]; + CResource &r = si.Resource; + + if (!r.IsSolid()) + break; + if (!r.KeepSolid && k != iii) + break; + + if (r.Flags != NResourceFlags::kSolid) + return S_FALSE; + + if (!r.IsSolidBig()) + continue; + + if (!si.IsEmptyHash()) + return S_FALSE; + if (si.RefCount != 1) + return S_FALSE; + + r.SolidIndex = Solids.Size(); + + CSolid &ss = Solids.AddNew(); + ss.StreamIndex = k; + ss.SolidOffset = solidRunOffset; + { + const size_t kSolidHeaderSize = 8 + 4 + 4; + Byte header[kSolidHeaderSize]; + + if (si.PartNumber >= volumes.Size()) + return S_FALSE; + + const CVolume &vol = volumes[si.PartNumber]; + IInStream *inStream = vol.Stream; + RINOK(inStream->Seek(r.Offset, STREAM_SEEK_SET, NULL)); + RINOK(ReadStream_FALSE(inStream, (Byte *)header, kSolidHeaderSize)); + + ss.UnpackSize = GetUi64(header); + + if (ss.UnpackSize > ((UInt64)1 << 63)) + return S_FALSE; + + solidRunOffset += ss.UnpackSize; + if (solidRunOffset < ss.UnpackSize) + return S_FALSE; + + const UInt32 solidChunkSize = GetUi32(header + 8); + int log = GetLog(solidChunkSize); + if (log < 8 || log > 31) + return S_FALSE; + ss.ChunkSizeBits = log; + ss.Method = GetUi32(header + 12); + + UInt64 numChunks64 = (ss.UnpackSize + (((UInt32)1 << ss.ChunkSizeBits) - 1)) >> ss.ChunkSizeBits; + UInt64 sizesBufSize64 = 4 * numChunks64; + ss.HeadersSize = kSolidHeaderSize + sizesBufSize64; + size_t sizesBufSize = (size_t)sizesBufSize64; + if (sizesBufSize != sizesBufSize64) + return E_OUTOFMEMORY; + sizesBuf.AllocAtLeast(sizesBufSize); + + RINOK(ReadStream_FALSE(inStream, sizesBuf, sizesBufSize)); + + size_t numChunks = (size_t)numChunks64; + ss.Chunks.Alloc(numChunks + 1); + + UInt64 offset = 0; + + size_t c; + for (c = 0; c < numChunks; c++) + { + ss.Chunks[c] = offset; + UInt32 packSize = GetUi32((const Byte *)sizesBuf + c * 4); + offset += packSize; + if (offset < packSize) + return S_FALSE; + } + ss.Chunks[c] = offset; + + if (ss.Chunks[0] != 0) + return S_FALSE; + if (ss.HeadersSize + offset != r.PackSize) + return S_FALSE; + } + } + + unsigned solidLim = k; + + for (k = iii; k < solidLim; k++) + { + CStreamInfo &si = DataStreams[k]; + CResource &r = si.Resource; + + if (!r.IsSolidSmall()) + continue; + + if (si.IsEmptyHash()) + return S_FALSE; + + unsigned solidIndex; + { + UInt64 offset = r.Offset; + for (solidIndex = numSolidsStart;; solidIndex++) + { + if (solidIndex == Solids.Size()) + return S_FALSE; + UInt64 unpackSize = Solids[solidIndex].UnpackSize; + if (offset < unpackSize) + break; + offset -= unpackSize; + } + } + CSolid &ss = Solids[solidIndex]; + if (r.Offset < ss.SolidOffset) + return S_FALSE; + UInt64 relat = r.Offset - ss.SolidOffset; + if (relat > ss.UnpackSize) + return S_FALSE; + if (r.PackSize > ss.UnpackSize - relat) + return S_FALSE; + r.SolidIndex = solidIndex; + if (ss.FirstSmallStream < 0) + ss.FirstSmallStream = k; + + sortedByHash.AddInReserved(k); + // ss.NumRefs++; + } + + iii = solidLim; + } + } + + if (Solids.IsEmpty()) + { + /* We want to check that streams layout is OK. + So we need resources sorted by offset. + Another code can work with non-sorted streams. + NOTE: all WIM programs probably create wim archives with + sorted data streams. So it doesn't call Sort() here. */ + + { + unsigned i; + for (i = 1; i < DataStreams.Size(); i++) + { + const CStreamInfo &s0 = DataStreams[i - 1]; + const CStreamInfo &s1 = DataStreams[i]; + if (s0.PartNumber < s1.PartNumber) continue; + if (s0.PartNumber > s1.PartNumber) break; + if (s0.Resource.Offset < s1.Resource.Offset) continue; + if (s0.Resource.Offset > s1.Resource.Offset) break; + if (s0.Resource.PackSize > s1.Resource.PackSize) break; + } + + if (i < DataStreams.Size()) + { + // return E_FAIL; + DataStreams.Sort(CompareStreamsByPos, NULL); + } + } + for (unsigned i = 1; i < DataStreams.Size(); i++) { const CStreamInfo &s0 = DataStreams[i - 1]; @@ -961,17 +1412,35 @@ HRESULT CDatabase::FillAndCheck() } { - CUIntVector sortedByHash; { - unsigned num = DataStreams.Size(); - sortedByHash.ClearAndSetSize(num); - unsigned *vals = &sortedByHash[0]; - for (unsigned i = 0; i < num; i++) - vals[i] = i; + const CStreamInfo *streams = &DataStreams.Front(); + if (IsOldVersion) - sortedByHash.Sort(CompareIDs, &DataStreams); + { + sortedByHash.Sort(CompareIDs, (void *)streams); + + for (unsigned i = 1; i < sortedByHash.Size(); i++) + if (streams[sortedByHash[i - 1]].Id >= + streams[sortedByHash[i]].Id) + return S_FALSE; + } else - sortedByHash.Sort(CompareHashRefs, &DataStreams); + { + sortedByHash.Sort(CompareHashRefs, (void *)streams); + + if (!sortedByHash.IsEmpty()) + { + if (IsEmptySha(streams[sortedByHash[0]].Hash)) + HeadersError = true; + + for (unsigned i = 1; i < sortedByHash.Size(); i++) + if (memcmp( + streams[sortedByHash[i - 1]].Hash, + streams[sortedByHash[i]].Hash, + kHashSize) >= 0) + return S_FALSE; + } + } } FOR_VECTOR (i, Items) @@ -986,7 +1455,7 @@ HRESULT CDatabase::FillAndCheck() hash += (item.IsAltStream ? 0x8 : 0x10); UInt32 id = GetUi32(hash); if (id != 0) - item.StreamIndex = FindId(DataStreams, sortedByHash, id); + item.StreamIndex = FindId(&DataStreams.Front(), sortedByHash, id); } } /* @@ -998,13 +1467,9 @@ HRESULT CDatabase::FillAndCheck() else { hash += (item.IsAltStream ? 0x10 : 0x40); - unsigned hi; - for (hi = 0; hi < kHashSize; hi++) - if (hash[hi] != 0) - break; - if (hi != kHashSize) + if (!IsEmptySha(hash)) { - item.StreamIndex = FindHash(DataStreams, sortedByHash, hash); + item.StreamIndex = FindHash(&DataStreams.Front(), sortedByHash, hash); } } } @@ -1035,29 +1500,36 @@ HRESULT CDatabase::FillAndCheck() for (i = 0; i < DataStreams.Size(); i++) { const CStreamInfo &s = DataStreams[i]; - if (s.RefCount != refCounts[i]) + if (s.RefCount != refCounts[i] + && !s.Resource.IsSolidBig()) { /* - printf("\ni = %5d si.Refcount = %d realRefs = %d size = %6d offset = %6x id = %4d ", + printf("\ni=%5d si.Ref=%2d realRefs=%2d size=%8d offset=%8x id=%4d ", i, s.RefCount, refCounts[i], (unsigned)s.Resource.UnpackSize, (unsigned)s.Resource.Offset, s.Id); */ - // return S_FALSE; RefCountError = true; } + if (refCounts[i] == 0) { - CItem item; - item.Offset = 0; - item.StreamIndex = i; - item.ImageIndex = -1; - ThereAreDeletedStreams = true; - Items.Add(item); + const CResource &r = DataStreams[i].Resource; + if (!r.IsSolidBig() || Solids[r.SolidIndex].FirstSmallStream < 0) + { + CItem item; + item.Offset = 0; + item.StreamIndex = i; + item.ImageIndex = -1; + Items.Add(item); + ThereAreDeletedStreams = true; + } } } } + return S_OK; } + HRESULT CDatabase::GenerateSortedItems(int imageIndex, bool showImageNumber) { SortedItems.Clear(); @@ -1117,9 +1589,11 @@ HRESULT CDatabase::GenerateSortedItems(int imageIndex, bool showImageNumber) image.VirtualRootIndex = VirtualRoots.Size(); VirtualRoots.Add(i); } + return S_OK; } + static void IntVector_SetMinusOne_IfNeed(CIntVector &v, unsigned size) { if (v.Size() == size) @@ -1130,6 +1604,7 @@ static void IntVector_SetMinusOne_IfNeed(CIntVector &v, unsigned size) vals[i] = -1; } + HRESULT CDatabase::ExtractReparseStreams(const CObjectVector &volumes, IArchiveOpenCallback *openCallback) { ItemToReparse.Clear(); @@ -1140,11 +1615,14 @@ HRESULT CDatabase::ExtractReparseStreams(const CObjectVector &volumes, return S_OK; CIntVector streamToReparse; + CUnpacker unpacker; + UInt64 totalPackedPrev = 0; - FOR_VECTOR(i, Items) + FOR_VECTOR(indexInSorted, SortedItems) { - // maybe it's better to use sorted items for faster access? - const CItem &item = Items[i]; + // we use sorted items for faster access + unsigned itemIndex = SortedItems[indexInSorted]; + const CItem &item = Items[itemIndex]; if (!item.HasMetadata() || item.IsAltStream) continue; @@ -1173,10 +1651,14 @@ HRESULT CDatabase::ExtractReparseStreams(const CObjectVector &volumes, int reparseIndex = streamToReparse[item.StreamIndex]; CByteBuffer buf; - if (openCallback && (i & 0xFFFF) == 0) + if (openCallback) { - UInt64 numFiles = Items.Size(); - RINOK(openCallback->SetCompleted(&numFiles, NULL)); + if ((unpacker.TotalPacked - totalPackedPrev) >= ((UInt32)1 << 16)) + { + UInt64 numFiles = Items.Size(); + RINOK(openCallback->SetCompleted(&numFiles, &unpacker.TotalPacked)); + totalPackedPrev = unpacker.TotalPacked; + } } if (reparseIndex >= 0) @@ -1184,7 +1666,7 @@ HRESULT CDatabase::ExtractReparseStreams(const CObjectVector &volumes, const CByteBuffer &reparse = ReparseItems[reparseIndex]; if (tag == Get32(reparse)) { - ItemToReparse[i] = reparseIndex; + ItemToReparse[itemIndex] = reparseIndex; continue; } buf = reparse; @@ -1203,7 +1685,7 @@ HRESULT CDatabase::ExtractReparseStreams(const CObjectVector &volumes, */ Byte digest[kHashSize]; - HRESULT res = UnpackData(vol.Stream, si.Resource, vol.Header.IsLzxMode(), buf, digest); + HRESULT res = unpacker.UnpackData(vol.Stream, si.Resource, vol.Header, this, buf, digest); if (res == S_FALSE) continue; @@ -1226,7 +1708,7 @@ HRESULT CDatabase::ExtractReparseStreams(const CObjectVector &volumes, SetUi32(dest + 4, (UInt32)buf.Size()); if (buf.Size() != 0) memcpy(dest + 8, buf, buf.Size()); - ItemToReparse[i] = ReparseItems.Size() - 1; + ItemToReparse[itemIndex] = ReparseItems.Size() - 1; } return S_OK; @@ -1252,6 +1734,7 @@ static bool ParseNumber64(const AString &s, UInt64 &res) return *end == 0; } + static bool ParseNumber32(const AString &s, UInt32 &res) { UInt64 res64; @@ -1261,6 +1744,7 @@ static bool ParseNumber32(const AString &s, UInt32 &res) return true; } + static bool ParseTime(const CXmlItem &item, FILETIME &ft, const char *tag) { int index = item.FindSubTag(tag); @@ -1279,6 +1763,7 @@ static bool ParseTime(const CXmlItem &item, FILETIME &ft, const char *tag) return false; } + void CImageInfo::Parse(const CXmlItem &item) { CTimeDefined = ParseTime(item, CTime, "CREATIONTIME"); @@ -1310,8 +1795,10 @@ void CWimXml::ToUnicode(UString &s) s.ReleaseBuf_SetLen((unsigned)(chars - (const wchar_t *)s)); } + bool CWimXml::Parse() { + IsEncrypted = false; AString utf; { UString s; @@ -1328,16 +1815,36 @@ bool CWimXml::Parse() FOR_VECTOR (i, Xml.Root.SubItems) { const CXmlItem &item = Xml.Root.SubItems[i]; + if (item.IsTagged("IMAGE")) { CImageInfo imageInfo; imageInfo.Parse(item); - if (!imageInfo.IndexDefined || imageInfo.Index != (UInt32)Images.Size() + 1) + if (!imageInfo.IndexDefined) return false; + + if (imageInfo.Index != (UInt32)Images.Size() + 1) + { + // old wim (1.09) uses zero based image index + if (imageInfo.Index != (UInt32)Images.Size()) + return false; + } + imageInfo.ItemIndexInXml = i; Images.Add(imageInfo); } + + if (item.IsTagged("ESD")) + { + FOR_VECTOR (k, item.SubItems) + { + const CXmlItem &item2 = item.SubItems[k]; + if (item2.IsTagged("ENCRYPTED")) + IsEncrypted = true; + } + } } + return true; } diff --git a/CPP/7zip/Archive/Wim/WimIn.h b/CPP/7zip/Archive/Wim/WimIn.h index c3b93a8d..ac4a2bd8 100644 --- a/CPP/7zip/Archive/Wim/WimIn.h +++ b/CPP/7zip/Archive/Wim/WimIn.h @@ -3,12 +3,15 @@ #ifndef __ARCHIVE_WIM_IN_H #define __ARCHIVE_WIM_IN_H +#include "../../../../C/Alloc.h" + #include "../../../Common/MyBuffer.h" #include "../../../Common/MyXml.h" #include "../../../Windows/PropVariant.h" #include "../../Compress/CopyCoder.h" +#include "../../Compress/LzmsDecoder.h" #include "../../Compress/LzxDecoder.h" #include "../IArchive.h" @@ -16,8 +19,20 @@ namespace NArchive { namespace NWim { -const UInt32 kDirRecordSizeOld = 62; -const UInt32 kDirRecordSize = 102; +/* +WIM versions: +hexVer : headerSize : ver + : 1.07.01 - 1.08.01 : Longhorn.4001-4015 - another header, no signature, CAB compression +10900 : 60 : 1.09 : Longhorn.4029-4039 (2003) +10A00 : 60 : 1.10 : Longhorn.4083 (2004) image starting from 1 +10B00 : ?? : 1.11 : ?? +10C00 : 74 : 1.12 : Longhorn.4093 - VistaBeta1.5112 (2005) - (Multi-Part, SHA1) +10D00 : D0 : 1.13 : VistaBeta2 - Win10, (NumImages, BootIndex, IntegrityResource) +00E00 : D0 : 0.14 : LZMS, solid, esd, dism +*/ + +const unsigned kDirRecordSizeOld = 62; +const unsigned kDirRecordSize = 102; /* There is error in WIM specification about dwReparseTag, dwReparseReserved and liHardLink fields. @@ -114,85 +129,26 @@ const UInt32 kDirRecordSize = 102; */ -namespace NXpress { - -class CBitStream -{ - CInBuffer m_Stream; - UInt32 m_Value; - unsigned m_BitPos; -public: - bool Create(UInt32 bufferSize) { return m_Stream.Create(bufferSize); } - void SetStream(ISequentialInStream *s) { m_Stream.SetStream(s); } - - void Init() { m_Stream.Init(); m_BitPos = 0; } - // UInt64 GetProcessedSize() const { return m_Stream.GetProcessedSize() - m_BitPos / 8; } - Byte DirectReadByte() { return m_Stream.ReadByte(); } - - void Normalize() - { - if (m_BitPos < 16) - { - Byte b0 = m_Stream.ReadByte(); - Byte b1 = m_Stream.ReadByte(); - m_Value = (m_Value << 8) | b1; - m_Value = (m_Value << 8) | b0; - m_BitPos += 16; - } - } - - UInt32 GetValue(unsigned numBits) - { - Normalize(); - return (m_Value >> (m_BitPos - numBits)) & ((1 << numBits) - 1); - } - - void MovePos(unsigned numBits) { m_BitPos -= numBits; } - - UInt32 ReadBits(unsigned numBits) - { - UInt32 res = GetValue(numBits); - m_BitPos -= numBits; - return res; - } -}; - -const unsigned kNumHuffmanBits = 16; -const UInt32 kMatchMinLen = 3; -const UInt32 kNumLenSlots = 16; -const UInt32 kNumPosSlots = 16; -const UInt32 kNumPosLenSlots = kNumPosSlots * kNumLenSlots; -const UInt32 kMainTableSize = 256 + kNumPosLenSlots; - -class CDecoder -{ - CBitStream m_InBitStream; - CLzOutWindow m_OutWindowStream; - NCompress::NHuffman::CDecoder m_MainDecoder; - - HRESULT CodeSpec(UInt32 size); - HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, UInt32 outSize); -public: - HRESULT Flush() { return m_OutWindowStream.Flush(); } - HRESULT Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, UInt32 outSize); -}; - -} namespace NResourceFlags { - const Byte kFree = 1; - const Byte kMetadata = 2; - const Byte Compressed = 4; - // const Byte Spanned = 4; + // const Byte kFree = 1 << 0; + const Byte kMetadata = 1 << 1; + const Byte kCompressed = 1 << 2; + // const Byte kSpanned = 1 << 3; + const Byte kSolid = 1 << 4; } +const UInt64 k_SolidBig_Resource_Marker = (UInt64)1 << 32; + struct CResource { UInt64 PackSize; UInt64 Offset; UInt64 UnpackSize; Byte Flags; + bool KeepSolid; + int SolidIndex; void Clear() { @@ -200,7 +156,10 @@ struct CResource Offset = 0; UnpackSize = 0; Flags = 0; + KeepSolid = false; + SolidIndex = -1; } + UInt64 GetEndLimit() const { return Offset + PackSize; } void Parse(const Byte *p); void ParseAndUpdatePhySize(const Byte *p, UInt64 &phySize) @@ -212,59 +171,130 @@ struct CResource } 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 IsCompressed() const { return (Flags & NResourceFlags::kCompressed) != 0; } + bool IsSolid() const { return (Flags & NResourceFlags::kSolid) != 0; } + bool IsSolidBig() const { return IsSolid() && UnpackSize == k_SolidBig_Resource_Marker; } + bool IsSolidSmall() const { return IsSolid() && UnpackSize == 0; } + bool IsEmpty() const { return (UnpackSize == 0); } }; + +struct CSolid +{ + unsigned StreamIndex; + // unsigned NumRefs; + int FirstSmallStream; + + UInt64 SolidOffset; + + UInt64 UnpackSize; + int Method; + int ChunkSizeBits; + + UInt64 HeadersSize; + // size_t NumChunks; + CObjArray Chunks; // [NumChunks + 1] (start offset) + + UInt64 GetChunkPackSize(size_t chunkIndex) const { return Chunks[chunkIndex + 1] - Chunks[chunkIndex]; } + + CSolid(): + FirstSmallStream(-1), + // NumRefs(0), + Method(-1) + {} +}; + + namespace NHeaderFlags { - const UInt32 kCompression = 2; - const UInt32 kReadOnly = 4; - const UInt32 kSpanned = 8; - const UInt32 kResourceOnly = 0x10; - const UInt32 kMetadataOnly = 0x20; - const UInt32 kWriteInProgress = 0x40; - const UInt32 kReparsePointFixup = 0x80; - const UInt32 kXPRESS = 0x20000; - const UInt32 kLZX = 0x40000; + const UInt32 kCompression = 1 << 1; + const UInt32 kReadOnly = 1 << 2; + const UInt32 kSpanned = 1 << 3; + const UInt32 kResourceOnly = 1 << 4; + const UInt32 kMetadataOnly = 1 << 5; + const UInt32 kWriteInProgress = 1 << 6; + const UInt32 kReparsePointFixup = 1 << 7; + + const UInt32 kXPRESS = (UInt32)1 << 17; + const UInt32 kLZX = (UInt32)1 << 18; + const UInt32 kLZMS = (UInt32)1 << 19; + + const UInt32 kMethodMask = 0xFFFE0000; } -const UInt32 kWimVersion = 0x010D00; + +namespace NMethod +{ + const UInt32 kXPRESS = 1; + const UInt32 kLZX = 2; + const UInt32 kLZMS = 3; +} + + +const UInt32 k_Version_NonSolid = 0x10D00; +const UInt32 k_Version_Solid = 0xE00; const unsigned kHeaderSizeMax = 0xD0; const unsigned kSignatureSize = 8; extern const Byte kSignature[kSignatureSize]; + const unsigned kChunkSizeBits = 15; -const UInt32 kChunkSize = (1 << kChunkSizeBits); +const UInt32 kChunkSize = (UInt32)1 << kChunkSizeBits; + struct CHeader { UInt32 Version; UInt32 Flags; UInt32 ChunkSize; + unsigned ChunkSizeBits; Byte Guid[16]; UInt16 PartNumber; UInt16 NumParts; UInt32 NumImages; - + UInt32 BootIndex; + + bool _IsOldVersion; // 1.10- + bool _IsNewVersion; // 1.13+ or 0.14 + CResource OffsetResource; CResource XmlResource; CResource MetadataResource; CResource IntegrityResource; - UInt32 BootIndex; void SetDefaultFields(bool useLZX); void WriteTo(Byte *p) const; HRESULT Parse(const Byte *p, UInt64 &phySize); + 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 IsOldVersion() const { return (Version <= 0x010A00); } - bool IsNewVersion() const { return (Version > 0x010C00); } + + bool IsSupported() const + { + return (!IsCompressed() + || (Flags & NHeaderFlags::kLZX) != 0 + || (Flags & NHeaderFlags::kXPRESS) != 0 + || (Flags & NHeaderFlags::kLZMS) != 0); + } + + unsigned GetMethod() const + { + if (!IsCompressed()) + return 0; + UInt32 mask = (Flags & NHeaderFlags::kMethodMask); + if (mask == 0) return 0; + if (mask == NHeaderFlags::kXPRESS) return NMethod::kXPRESS; + if (mask == NHeaderFlags::kLZX) return NMethod::kLZX; + if (mask == NHeaderFlags::kLZMS) return NMethod::kLZMS; + return mask; + } + + bool IsOldVersion() const { return _IsOldVersion; } + bool IsNewVersion() const { return _IsNewVersion; } + bool IsSolidVersion() const { return (Version == k_Version_Solid); } bool AreFromOnArchive(const CHeader &h) { @@ -272,7 +302,17 @@ struct CHeader } }; + const unsigned kHashSize = 20; + +inline bool IsEmptySha(const Byte *data) +{ + for (unsigned i = 0; i < kHashSize; i++) + if (data[i] != 0) + return false; + return true; +} + const unsigned kStreamInfoSize = 24 + 2 + 4 + kHashSize; struct CStreamInfo @@ -283,9 +323,12 @@ struct CStreamInfo UInt32 Id; // for OLD WIM format Byte Hash[kHashSize]; + bool IsEmptyHash() const { return IsEmptySha(Hash); } + void WriteTo(Byte *p) const; }; + struct CItem { size_t Offset; @@ -321,6 +364,7 @@ struct CImage CImage(): VirtualRootIndex(-1) {} }; + struct CImageInfo { bool CTimeDefined; @@ -345,6 +389,7 @@ struct CImageInfo void Parse(const CXmlItem &item); }; + struct CWimXml { CByteBuffer Data; @@ -354,6 +399,7 @@ struct CWimXml CObjectVector Images; UString FileName; + bool IsEncrypted; UInt64 GetTotalFilesAndDirs() const { @@ -365,14 +411,18 @@ struct CWimXml void ToUnicode(UString &s); bool Parse(); + + CWimXml(): IsEncrypted(false) {} }; + struct CVolume { CHeader Header; CMyComPtr Stream; }; + class CDatabase { Byte *DirData; @@ -386,9 +436,9 @@ class CDatabase public: CRecordVector DataStreams; - - CRecordVector MetaStreams; + + CObjectVector Solids; CRecordVector Items; CObjectVector ReparseItems; @@ -397,10 +447,15 @@ public: CObjectVector Images; + bool IsOldVersion9; bool IsOldVersion; bool ThereAreDeletedStreams; bool ThereAreAltStreams; bool RefCountError; + bool HeadersError; + + bool GetStartImageIndex() const { return IsOldVersion9 ? 0 : 1; } + unsigned GetDirAlignMask() const { return IsOldVersion9 ? 3 : 7; } // User Items can contain all images or just one image from all. CUIntVector SortedItems; @@ -423,6 +478,31 @@ public: bool ItemHasStream(const CItem &item) const; + UInt64 Get_UnpackSize_of_Resource(const CResource &r) const + { + if (!r.IsSolid()) + return r.UnpackSize; + if (r.IsSolidSmall()) + return r.PackSize; + if (r.IsSolidBig() && r.SolidIndex >= 0) + return Solids[(unsigned)r.SolidIndex].UnpackSize; + return 0; + } + + UInt64 Get_PackSize_of_Resource(unsigned streamIndex) const + { + const CResource &r = DataStreams[streamIndex].Resource; + if (!r.IsSolidSmall()) + return r.PackSize; + if (r.SolidIndex >= 0) + { + const CSolid &ss = Solids[(unsigned)r.SolidIndex]; + if (ss.FirstSmallStream == (int)streamIndex) + return DataStreams[ss.StreamIndex].Resource.PackSize; + } + return 0; + } + UInt64 GetUnpackSize() const { UInt64 res = 0; @@ -442,8 +522,8 @@ public: void Clear() { DataStreams.Clear(); - MetaStreams.Clear(); + Solids.Clear(); Items.Clear(); ReparseItems.Clear(); @@ -458,6 +538,7 @@ public: ThereAreDeletedStreams = false; ThereAreAltStreams = false; RefCountError = false; + HeadersError = false; } CDatabase(): RefCountError(false) {} @@ -468,7 +549,7 @@ public: HRESULT OpenXml(IInStream *inStream, const CHeader &h, CByteBuffer &xml); HRESULT Open(IInStream *inStream, const CHeader &h, unsigned numItemsReserve, IArchiveOpenCallback *openCallback); - HRESULT FillAndCheck(); + HRESULT FillAndCheck(const CObjectVector &volumes); /* imageIndex showImageNumber NumImages @@ -484,23 +565,87 @@ public: HRESULT ReadHeader(IInStream *inStream, CHeader &header, UInt64 &phySize); + +struct CMidBuf +{ + Byte *Data; + size_t _size; + + CMidBuf(): Data(NULL), _size(0) {} + + void EnsureCapacity(size_t size) + { + if (size > _size) + { + ::MidFree(Data); + _size = 0; + Data = (Byte *)::MidAlloc(size); + if (Data) + _size = size; + } + } + + ~CMidBuf() { ::MidFree(Data); } +}; + + class CUnpacker { NCompress::CCopyCoder *copyCoderSpec; CMyComPtr copyCoder; NCompress::NLzx::CDecoder *lzxDecoderSpec; - CMyComPtr lzxDecoder; + CMyComPtr lzxDecoder; - NXpress::CDecoder xpressDecoder; + NCompress::NLzms::CDecoder *lzmsDecoder; CByteBuffer sizesBuf; - HRESULT Unpack(IInStream *inStream, const CResource &res, bool lzxMode, - ISequentialOutStream *outStream, ICompressProgressInfo *progress); + CMidBuf packBuf; + CMidBuf unpackBuf; + + // solid resource + int _solidIndex; + size_t _unpackedChunkIndex; + + HRESULT UnpackChunk( + ISequentialInStream *inStream, + unsigned method, unsigned chunkSizeBits, + size_t inSize, size_t outSize, + ISequentialOutStream *outStream); + + HRESULT Unpack2( + IInStream *inStream, + const CResource &res, + const CHeader &header, + const CDatabase *db, + ISequentialOutStream *outStream, + ICompressProgressInfo *progress); + public: - HRESULT Unpack(IInStream *inStream, const CResource &res, bool lzxMode, - ISequentialOutStream *outStream, ICompressProgressInfo *progress, Byte *digest); + UInt64 TotalPacked; + + CUnpacker(): + lzmsDecoder(NULL), + _solidIndex(-1), + _unpackedChunkIndex(0), + TotalPacked(0) + {} + ~CUnpacker(); + + HRESULT Unpack( + IInStream *inStream, + const CResource &res, + const CHeader &header, + const CDatabase *db, + ISequentialOutStream *outStream, + ICompressProgressInfo *progress, + Byte *digest); + + HRESULT UnpackData(IInStream *inStream, + const CResource &resource, const CHeader &header, + const CDatabase *db, + CByteBuffer &buf, Byte *digest); }; }} diff --git a/CPP/7zip/Archive/Wim/WimRegister.cpp b/CPP/7zip/Archive/Wim/WimRegister.cpp index 3063dec4..6ad28acc 100644 --- a/CPP/7zip/Archive/Wim/WimRegister.cpp +++ b/CPP/7zip/Archive/Wim/WimRegister.cpp @@ -10,7 +10,7 @@ namespace NArchive { namespace NWim { REGISTER_ARC_IO( - "wim", "wim swm", 0, 0xE6, + "wim", "wim swm esd", 0, 0xE6, kSignature, 0, NArcInfoFlags::kAltStreams | diff --git a/CPP/7zip/Archive/XzHandler.cpp b/CPP/7zip/Archive/XzHandler.cpp index ada14fbf..11f4b444 100644 --- a/CPP/7zip/Archive/XzHandler.cpp +++ b/CPP/7zip/Archive/XzHandler.cpp @@ -351,7 +351,8 @@ struct COpenCallbackWrap static SRes OpenCallbackProgress(void *pp, UInt64 inSize, UInt64 /* outSize */) { COpenCallbackWrap *p = (COpenCallbackWrap *)pp; - p->Res = p->OpenCallback->SetCompleted(NULL, &inSize); + if (p->OpenCallback) + p->Res = p->OpenCallback->SetCompleted(NULL, &inSize); return (SRes)p->Res; } @@ -414,7 +415,10 @@ HRESULT CHandler::Open2(IInStream *inStream, /* UInt32 flags, */ IArchiveOpenCal } RINOK(inStream->Seek(0, STREAM_SEEK_END, &_stat.PhySize)); - RINOK(callback->SetTotal(NULL, &_stat.PhySize)); + if (callback) + { + RINOK(callback->SetTotal(NULL, &_stat.PhySize)); + } CSeekInStreamWrap inStreamImp(inStream); @@ -466,7 +470,7 @@ STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCal COM_TRY_BEGIN { Close(); - return Open2(inStream, /* 0, */ callback); + return Open2(inStream, callback); } COM_TRY_END } diff --git a/CPP/7zip/Archive/Zip/ZipUpdate.cpp b/CPP/7zip/Archive/Zip/ZipUpdate.cpp index 7d03056c..d4b321dc 100644 --- a/CPP/7zip/Archive/Zip/ZipUpdate.cpp +++ b/CPP/7zip/Archive/Zip/ZipUpdate.cpp @@ -8,7 +8,7 @@ #include "../../../Common/Defs.h" #include "../../../Common/StringConvert.h" -#include "../../../Windows/Defs.h" +#include "../../../Windows/TimeUtils.h" #include "../../../Windows/Thread.h" #include "../../Common/CreateCoder.h" @@ -61,6 +61,7 @@ static HRESULT WriteRange(IInStream *inStream, COutArchive &outArchive, return progress->SetRatioInfo(&range.Size, &range.Size); } + static void SetFileHeader( COutArchive &archive, const CCompressionMethodMode &options, @@ -108,6 +109,7 @@ static void SetFileHeader( } } + static void SetItemInfoFromCompressingResult(const CCompressingResult &compressingResult, bool isAesMode, Byte aesKeyMode, CItem &item) { @@ -134,6 +136,7 @@ static void SetItemInfoFromCompressingResult(const CCompressingResult &compressi } } + #ifndef _7ZIP_ST static THREAD_FUNC_DECL CoderThread(void *threadCoderInfo); @@ -188,7 +191,6 @@ struct CThreadInfo Thread.Wait(); Thread.Close(); } - }; void CThreadInfo::WaitAndCode() @@ -390,9 +392,11 @@ static HRESULT UpdateItemOldData( complexity += range.Size; archive.MoveCurPos(range.Size); } + return S_OK; } + static void WriteDirHeader(COutArchive &archive, const CCompressionMethodMode *options, const CUpdateItem &ui, CItemOut &item) { @@ -404,15 +408,65 @@ static void WriteDirHeader(COutArchive &archive, const CCompressionMethodMode *o archive.WriteLocalHeader_And_SeekToNextFile(item); } + +static inline bool IsZero_FILETIME(const FILETIME &ft) +{ + return (ft.dwHighDateTime == 0 && ft.dwLowDateTime == 0); +} + +static void UpdatePropsFromStream(CUpdateItem &item, ISequentialInStream *fileInStream, + IArchiveUpdateCallback *updateCallback, UInt64 &totalComplexity) +{ + CMyComPtr getProps; + fileInStream->QueryInterface(IID_IStreamGetProps, (void **)&getProps); + if (!getProps) + return; + + FILETIME cTime, aTime, mTime; + UInt64 size; + // UInt32 attrib; + if (getProps->GetProps(&size, &cTime, &aTime, &mTime, NULL) != S_OK) + return; + + if (size != item.Size && size != (UInt64)(Int64)-1) + { + Int64 newComplexity = totalComplexity + ((Int64)size - (Int64)item.Size); + if (newComplexity > 0) + { + totalComplexity = newComplexity; + updateCallback->SetTotal(totalComplexity); + } + item.Size = size; + } + + if (!IsZero_FILETIME(mTime)) + { + item.Ntfs_MTime = mTime; + FILETIME loc = { 0, 0 }; + if (FileTimeToLocalFileTime(&mTime, &loc)) + { + item.Time = 0; + NTime::FileTimeToDosTime(loc, item.Time); + } + } + + if (!IsZero_FILETIME(cTime)) item.Ntfs_CTime = cTime; + if (!IsZero_FILETIME(aTime)) item.Ntfs_ATime = aTime; + + // item.Attrib = attrib; +} + + static HRESULT Update2St( DECL_EXTERNAL_CODECS_LOC_VARS COutArchive &archive, CInArchive *inArchive, const CObjectVector &inputItems, - const CObjectVector &updateItems, + CObjectVector &updateItems, const CCompressionMethodMode *options, const CByteBuffer *comment, IArchiveUpdateCallback *updateCallback, + UInt64 &totalComplexity, IArchiveUpdateCallbackFile *opCallback) { CLocalProgress *lps = new CLocalProgress; @@ -429,7 +483,7 @@ static HRESULT Update2St( lps->InSize = unpackSizeTotal; lps->OutSize = packSizeTotal; RINOK(lps->SetCur()); - const CUpdateItem &ui = updateItems[itemIndex]; + CUpdateItem &ui = updateItems[itemIndex]; CItemEx itemEx; CItemOut item; @@ -471,8 +525,10 @@ static HRESULT Update2St( } */ - // file Size can be 64-bit !!! + UpdatePropsFromStream(ui, fileInStream, updateCallback, totalComplexity); SetFileHeader(archive, *options, ui, item); + + // file Size can be 64-bit !!! archive.PrepareWriteCompressedData(item.Name.Len(), ui.Size, options->IsRealAesMode()); CCompressingResult compressingResult; CMyComPtr outStream; @@ -508,6 +564,7 @@ static HRESULT Update2St( lps->SendRatio = true; lps->ProgressOffset += complexity; } + items.Add(item); lps->ProgressOffset += kLocalHeaderSize; } @@ -519,12 +576,13 @@ static HRESULT Update2St( return S_OK; } + static HRESULT Update2( DECL_EXTERNAL_CODECS_LOC_VARS COutArchive &archive, CInArchive *inArchive, const CObjectVector &inputItems, - const CObjectVector &updateItems, + CObjectVector &updateItems, const CCompressionMethodMode *options, const CByteBuffer *comment, IArchiveUpdateCallback *updateCallback) @@ -567,6 +625,8 @@ static HRESULT Update2( complexity++; // end of central updateCallback->SetTotal(complexity); + UInt64 totalComplexity = complexity; + CAddCommon compressor(*options); complexity = 0; @@ -596,6 +656,7 @@ static HRESULT Update2( mtMode = false; Byte method = options->MethodSequence.Front(); + if (!mtMode) { if (options2.MethodInfo.FindProp(NCoderPropID::kNumThreads) < 0) @@ -643,7 +704,7 @@ static HRESULT Update2( return Update2St( EXTERNAL_CODECS_LOC_VARS archive, inArchive, - inputItems, updateItems, &options2, comment, updateCallback, opCallback); + inputItems, updateItems, &options2, comment, updateCallback, totalComplexity, opCallback); #ifndef _7ZIP_ST @@ -691,8 +752,8 @@ static HRESULT Update2( RINOK(threadInfo.CreateThread()); } } - unsigned mtItemIndex = 0; + unsigned mtItemIndex = 0; unsigned itemIndex = 0; int lastRealStreamItemIndex = -1; @@ -700,11 +761,12 @@ static HRESULT Update2( { if ((UInt32)threadIndices.Size() < numThreads && mtItemIndex < updateItems.Size()) { - const CUpdateItem &ui = updateItems[mtItemIndex++]; + CUpdateItem &ui = updateItems[mtItemIndex++]; if (!ui.NewData) continue; CItemEx itemEx; CItemOut item; + if (ui.NewProps) { if (ui.IsDir) @@ -719,7 +781,9 @@ static HRESULT Update2( if (item.IsDir()) continue; } + CMyComPtr fileInStream; + { NWindows::NSynchronization::CCriticalSectionLock lock(mtProgressMixerSpec->Mixer2->CriticalSection); HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream); @@ -735,6 +799,7 @@ static HRESULT Update2( RINOK(res); if (!fileInStream) return E_INVALIDARG; + UpdatePropsFromStream(ui, fileInStream, updateCallback, totalComplexity); RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); } @@ -760,6 +825,7 @@ static HRESULT Update2( break; } } + continue; } @@ -773,6 +839,7 @@ static HRESULT Update2( CItemEx itemEx; CItemOut item; + if (!ui.NewProps || !ui.NewData) { itemEx = inputItems[ui.IndexInArc]; @@ -784,6 +851,7 @@ static HRESULT Update2( if (ui.NewData) { bool isDir = ((ui.NewProps) ? ui.IsDir : item.IsDir()); + if (isDir) { WriteDirHeader(archive, options, ui, item); @@ -799,6 +867,7 @@ static HRESULT Update2( } CMemBlocks2 &memRef = refs.Refs[itemIndex]; + if (memRef.Defined) { CMyComPtr outStream; @@ -834,6 +903,7 @@ static HRESULT Update2( DWORD lastError = GetLastError(); return lastError != 0 ? lastError : E_FAIL; } + unsigned t = (unsigned)(result - WAIT_OBJECT_0); if (t >= compressingCompletedEvents.Size()) return E_FAIL; @@ -844,6 +914,7 @@ static HRESULT Update2( RINOK(threadInfo.Result); threadIndices.Delete(t); compressingCompletedEvents.Delete(t); + if (t == 0) { RINOK(threadInfo.OutStreamSpec->WriteToRealStream()); @@ -868,17 +939,20 @@ static HRESULT Update2( { RINOK(UpdateItemOldData(archive, inArchive, itemEx, ui, item, progress, opCallback, complexity)); } + items.Add(item); complexity += kLocalHeaderSize; mtProgressMixerSpec->Mixer2->SetProgressOffset(complexity); itemIndex++; } + RINOK(mtCompressProgressMixer.SetRatioInfo(0, NULL, NULL)); archive.WriteCentralDir(items, comment); return S_OK; #endif } + static const size_t kCacheBlockSize = (1 << 20); static const size_t kCacheSize = (kCacheBlockSize << 2); static const size_t kCacheMask = (kCacheSize - 1); @@ -1095,7 +1169,7 @@ STDMETHODIMP CCacheOutStream::SetSize(UInt64 newSize) HRESULT Update( DECL_EXTERNAL_CODECS_LOC_VARS const CObjectVector &inputItems, - const CObjectVector &updateItems, + CObjectVector &updateItems, ISequentialOutStream *seqOutStream, CInArchive *inArchive, bool removeSfx, CCompressionMethodMode *compressionMethodMode, diff --git a/CPP/7zip/Archive/Zip/ZipUpdate.h b/CPP/7zip/Archive/Zip/ZipUpdate.h index 747c07bc..054db668 100644 --- a/CPP/7zip/Archive/Zip/ZipUpdate.h +++ b/CPP/7zip/Archive/Zip/ZipUpdate.h @@ -48,7 +48,7 @@ struct CUpdateItem HRESULT Update( DECL_EXTERNAL_CODECS_LOC_VARS const CObjectVector &inputItems, - const CObjectVector &updateItems, + CObjectVector &updateItems, ISequentialOutStream *seqOutStream, CInArchive *inArchive, bool removeSfx, CCompressionMethodMode *compressionMethodMode, diff --git a/CPP/7zip/Bundles/Alone/Alone.dsp b/CPP/7zip/Bundles/Alone/Alone.dsp index cd7341c1..db2d54cd 100644 --- a/CPP/7zip/Bundles/Alone/Alone.dsp +++ b/CPP/7zip/Bundles/Alone/Alone.dsp @@ -1145,14 +1145,6 @@ SOURCE=..\..\Compress\Lzx.h # End Source File # Begin Source File -SOURCE=..\..\Compress\Lzx86Converter.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\Lzx86Converter.h -# End Source File -# Begin Source File - SOURCE=..\..\Compress\LzxDecoder.cpp # End Source File # Begin Source File diff --git a/CPP/7zip/Bundles/Alone/makefile b/CPP/7zip/Bundles/Alone/makefile index 02a51398..766bf96a 100644 --- a/CPP/7zip/Bundles/Alone/makefile +++ b/CPP/7zip/Bundles/Alone/makefile @@ -161,7 +161,6 @@ COMPRESS_OBJS = \ $O\LzmaEncoder.obj \ $O\LzmaRegister.obj \ $O\LzOutWindow.obj \ - $O\Lzx86Converter.obj \ $O\LzxDecoder.obj \ $O\PpmdDecoder.obj \ $O\PpmdEncoder.obj \ diff --git a/CPP/7zip/Bundles/Format7zF/Arc.mak b/CPP/7zip/Bundles/Format7zF/Arc.mak index a1221c61..3ea45b5d 100644 --- a/CPP/7zip/Bundles/Format7zF/Arc.mak +++ b/CPP/7zip/Bundles/Format7zF/Arc.mak @@ -64,6 +64,8 @@ AR_OBJS = \ $O\FatHandler.obj \ $O\FlvHandler.obj \ $O\GzHandler.obj \ + $O\GptHandler.obj \ + $O\HandlerCont.obj \ $O\HfsHandler.obj \ $O\IhexHandler.obj \ $O\LzhHandler.obj \ @@ -75,12 +77,15 @@ AR_OBJS = \ $O\NtfsHandler.obj \ $O\PeHandler.obj \ $O\PpmdHandler.obj \ + $O\QcowHandler.obj \ $O\RpmHandler.obj \ $O\SplitHandler.obj \ $O\SquashfsHandler.obj \ $O\SwfHandler.obj \ $O\UefiHandler.obj \ + $O\VdiHandler.obj \ $O\VhdHandler.obj \ + $O\VmdkHandler.obj \ $O\XarHandler.obj \ $O\XzHandler.obj \ $O\ZHandler.obj \ @@ -201,8 +206,8 @@ COMPRESS_OBJS = \ $O\LzmaDecoder.obj \ $O\LzmaEncoder.obj \ $O\LzmaRegister.obj \ + $O\LzmsDecoder.obj \ $O\LzOutWindow.obj \ - $O\Lzx86Converter.obj \ $O\LzxDecoder.obj \ $O\PpmdDecoder.obj \ $O\PpmdEncoder.obj \ @@ -219,6 +224,7 @@ COMPRESS_OBJS = \ $O\ZlibDecoder.obj \ $O\ZlibEncoder.obj \ $O\ZDecoder.obj \ + $O\XPressDecoder.obj \ CRYPTO_OBJS = \ $O\7zAes.obj \ diff --git a/CPP/7zip/Bundles/Format7zF/Format7z.dsp b/CPP/7zip/Bundles/Format7zF/Format7z.dsp index 169d9f0e..f22d746e 100644 --- a/CPP/7zip/Bundles/Format7zF/Format7z.dsp +++ b/CPP/7zip/Bundles/Format7zF/Format7z.dsp @@ -756,15 +756,17 @@ SOURCE=..\..\Compress\Lzx.h # End Source File # Begin Source File -SOURCE=..\..\Compress\Lzx86Converter.cpp -# End Source File -# Begin Source File +SOURCE=..\..\Compress\LzxDecoder.cpp -SOURCE=..\..\Compress\Lzx86Converter.h -# End Source File -# Begin Source File +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +!ENDIF -SOURCE=..\..\Compress\LzxDecoder.cpp # End Source File # Begin Source File @@ -793,6 +795,24 @@ SOURCE=..\..\Compress\LzhDecoder.h # End Source File # Begin Source File +SOURCE=..\..\Compress\LzmsDecoder.cpp + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\LzmsDecoder.h +# End Source File +# Begin Source File + SOURCE=..\..\Compress\LzOutWindow.cpp # End Source File # Begin Source File @@ -801,6 +821,24 @@ SOURCE=..\..\Compress\LzOutWindow.h # End Source File # Begin Source File +SOURCE=..\..\Compress\XpressDecoder.cpp + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\XpressDecoder.h +# End Source File +# Begin Source File + SOURCE=..\..\Compress\ZDecoder.cpp # End Source File # Begin Source File @@ -2401,10 +2439,22 @@ SOURCE=..\..\Archive\FlvHandler.cpp # End Source File # Begin Source File +SOURCE=..\..\Archive\GptHandler.cpp +# End Source File +# Begin Source File + SOURCE=..\..\Archive\GzHandler.cpp # End Source File # Begin Source File +SOURCE=..\..\Archive\HandlerCont.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\HandlerCont.h +# End Source File +# Begin Source File + SOURCE=..\..\Archive\HfsHandler.cpp # End Source File # Begin Source File @@ -2463,6 +2513,10 @@ SOURCE=..\..\Archive\PpmdHandler.cpp # End Source File # Begin Source File +SOURCE=..\..\Archive\QcowHandler.cpp +# End Source File +# Begin Source File + SOURCE=..\..\Archive\RpmHandler.cpp # End Source File # Begin Source File @@ -2483,10 +2537,18 @@ SOURCE=..\..\Archive\UefiHandler.cpp # End Source File # Begin Source File +SOURCE=..\..\Archive\VdiHandler.cpp +# End Source File +# Begin Source File + SOURCE=..\..\Archive\VhdHandler.cpp # End Source File # Begin Source File +SOURCE=..\..\Archive\VmdkHandler.cpp +# End Source File +# Begin Source File + SOURCE=..\..\Archive\XarHandler.cpp # End Source File # Begin Source File diff --git a/CPP/7zip/Compress/BZip2Decoder.cpp b/CPP/7zip/Compress/BZip2Decoder.cpp index db4d0933..04222e49 100644 --- a/CPP/7zip/Compress/BZip2Decoder.cpp +++ b/CPP/7zip/Compress/BZip2Decoder.cpp @@ -173,7 +173,7 @@ HRESULT CBase::ReadBlock(UInt32 *charCounters, UInt32 blockSizeMax, CBlockProps } for (; i < kMaxAlphaSize; i++) lens[i] = 0; - if (!m_HuffmanDecoders[t].SetCodeLengths(lens)) + if (!m_HuffmanDecoders[t].Build(lens)) return S_FALSE; } while (++t < numTables); @@ -205,7 +205,7 @@ HRESULT CBase::ReadBlock(UInt32 *charCounters, UInt32 blockSizeMax, CBlockProps if (BitDecoder.ExtraBitsWereRead_Fast()) break; - UInt32 nextSym = huffmanDecoder->DecodeSymbol(&BitDecoder); + UInt32 nextSym = huffmanDecoder->Decode(&BitDecoder); if (nextSym < 2) { diff --git a/CPP/7zip/Compress/DeflateDecoder.cpp b/CPP/7zip/Compress/DeflateDecoder.cpp index 5e2d5d3e..5c097f13 100644 --- a/CPP/7zip/Compress/DeflateDecoder.cpp +++ b/CPP/7zip/Compress/DeflateDecoder.cpp @@ -26,39 +26,51 @@ Byte CCoder::ReadAlignedByte() return m_InBitStream.ReadAlignedByte(); } -bool CCoder::DeCodeLevelTable(Byte *values, unsigned numSymbols) +bool CCoder::DecodeLevels(Byte *levels, unsigned numSymbols) { unsigned i = 0; + do { - UInt32 number = m_LevelDecoder.DecodeSymbol(&m_InBitStream); - if (number < kTableDirectLevels) - values[i++] = (Byte)number; - else if (number < kLevelTableSize) + UInt32 sym = m_LevelDecoder.Decode(&m_InBitStream); + if (sym < kTableDirectLevels) + levels[i++] = (Byte)sym; + else { - if (number == kTableLevelRepNumber) + if (sym >= kLevelTableSize) + return false; + + unsigned num; + unsigned numBits; + Byte symbol; + + if (sym == kTableLevelRepNumber) { if (i == 0) return false; - unsigned num = ReadBits(2) + 3; - for (; num > 0 && i < numSymbols; num--, i++) - values[i] = values[i - 1]; + numBits = 2; + num = 0; + symbol = levels[i - 1]; } else { - unsigned num; - if (number == kTableLevel0Number) - num = ReadBits(3) + 3; - else - num = ReadBits(7) + 11; - for (; num > 0 && i < numSymbols; num--) - values[i++] = 0; + sym -= kTableLevel0Number; + sym <<= 2; + numBits = 3 + (unsigned)sym; + num = ((unsigned)sym << 1); + symbol = 0; } + + num += i + 3 + ReadBits(numBits); + if (num > numSymbols) + return false; + do + levels[i++] = symbol; + while (i < num); } - else - return false; } while (i < numSymbols); + return true; } @@ -116,10 +128,10 @@ bool CCoder::ReadTables(void) if (m_InBitStream.ExtraBitsWereRead()) return false; - RIF(m_LevelDecoder.SetCodeLengths(levelLevels)); + RIF(m_LevelDecoder.Build(levelLevels)); Byte tmpLevels[kFixedMainTableSize + kFixedDistTableSize]; - if (!DeCodeLevelTable(tmpLevels, numLitLenLevels + _numDistLevels)) + if (!DecodeLevels(tmpLevels, numLitLenLevels + _numDistLevels)) return false; if (m_InBitStream.ExtraBitsWereRead()) @@ -129,8 +141,8 @@ bool CCoder::ReadTables(void) memcpy(levels.litLenLevels, tmpLevels, numLitLenLevels); memcpy(levels.distLevels, tmpLevels + numLitLenLevels, _numDistLevels); } - RIF(m_MainDecoder.SetCodeLengths(levels.litLenLevels)); - return m_DistDecoder.SetCodeLengths(levels.distLevels); + RIF(m_MainDecoder.Build(levels.litLenLevels)); + return m_DistDecoder.Build(levels.distLevels); } HRESULT CCoder::CodeSpec(UInt32 curSize, bool finishInputStream) @@ -161,6 +173,7 @@ HRESULT CCoder::CodeSpec(UInt32 curSize, bool finishInputStream) { if (m_InBitStream.ExtraBitsWereRead()) return S_FALSE; + if (_needReadTable) { if (m_FinalBlock) @@ -194,43 +207,44 @@ HRESULT CCoder::CodeSpec(UInt32 curSize, bool finishInputStream) if (m_InBitStream.ExtraBitsWereRead_Fast()) return S_FALSE; - UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream); - if (number < 0x100) + UInt32 sym = m_MainDecoder.Decode(&m_InBitStream); + + if (sym < 0x100) { - m_OutWindowStream.PutByte((Byte)number); + m_OutWindowStream.PutByte((Byte)sym); curSize--; continue; } - else if (number == kSymbolEndOfBlock) + else if (sym == kSymbolEndOfBlock) { _needReadTable = true; break; } - else if (number < kMainTableSize) + else if (sym < kMainTableSize) { - number -= kSymbolMatch; + sym -= kSymbolMatch; UInt32 len; { unsigned numBits; if (_deflate64Mode) { - len = kLenStart64[number]; - numBits = kLenDirectBits64[number]; + len = kLenStart64[sym]; + numBits = kLenDirectBits64[sym]; } else { - len = kLenStart32[number]; - numBits = kLenDirectBits32[number]; + len = kLenStart32[sym]; + numBits = kLenDirectBits32[sym]; } len += kMatchMinLen + m_InBitStream.ReadBits(numBits); } UInt32 locLen = len; if (locLen > curSize) locLen = (UInt32)curSize; - number = m_DistDecoder.DecodeSymbol(&m_InBitStream); - if (number >= _numDistLevels) + sym = m_DistDecoder.Decode(&m_InBitStream); + if (sym >= _numDistLevels) return S_FALSE; - UInt32 distance = kDistStart[number] + m_InBitStream.ReadBits(kDistDirectBits[number]); + UInt32 distance = kDistStart[sym] + m_InBitStream.ReadBits(kDistDirectBits[sym]); if (!m_OutWindowStream.CopyBlock(distance, locLen)) return S_FALSE; curSize -= locLen; @@ -248,7 +262,7 @@ HRESULT CCoder::CodeSpec(UInt32 curSize, bool finishInputStream) if (finishInputStream && curSize == 0) { - if (m_MainDecoder.DecodeSymbol(&m_InBitStream) != kSymbolEndOfBlock) + if (m_MainDecoder.Decode(&m_InBitStream) != kSymbolEndOfBlock) return S_FALSE; _needReadTable = true; } @@ -260,6 +274,7 @@ HRESULT CCoder::CodeSpec(UInt32 curSize, bool finishInputStream) return S_OK; } + #ifdef _NO_EXCEPTIONS #define DEFLATE_TRY_BEGIN @@ -275,6 +290,7 @@ HRESULT CCoder::CodeSpec(UInt32 curSize, bool finishInputStream) #endif + HRESULT CCoder::CodeReal(ISequentialOutStream *outStream, const UInt64 *outSize, ICompressProgressInfo *progress) { @@ -285,6 +301,7 @@ HRESULT CCoder::CodeReal(ISequentialOutStream *outStream, const UInt64 inStart = _needInitInStream ? 0 : m_InBitStream.GetProcessedSize(); const UInt64 start = m_OutWindowStream.GetProcessedSize(); + for (;;) { UInt32 curSize = 1 << 18; @@ -311,12 +328,14 @@ HRESULT CCoder::CodeReal(ISequentialOutStream *outStream, RINOK(progress->SetRatioInfo(&inSize, &nowPos64)); } } + if (_remainLen == kLenIdFinished && ZlibMode) { m_InBitStream.AlignToByte(); for (unsigned i = 0; i < 4; i++) ZlibFooter[i] = ReadAlignedByte(); } + flusher.NeedFlush = false; res = Flush(); if (res == S_OK && _remainLen != kLenIdNeedInit && InputEofError()) @@ -337,7 +356,7 @@ HRESULT CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStr STDMETHODIMP CCoder::GetInStreamProcessedSize(UInt64 *value) { - if (value == NULL) + if (!value) return E_INVALIDARG; *value = m_InBitStream.GetProcessedSize(); return S_OK; diff --git a/CPP/7zip/Compress/DeflateDecoder.h b/CPP/7zip/Compress/DeflateDecoder.h index 856a5771..0b29737f 100644 --- a/CPP/7zip/Compress/DeflateDecoder.h +++ b/CPP/7zip/Compress/DeflateDecoder.h @@ -36,7 +36,7 @@ class CCoder: NBitl::CDecoder m_InBitStream; NCompress::NHuffman::CDecoder m_MainDecoder; NCompress::NHuffman::CDecoder m_DistDecoder; - NCompress::NHuffman::CDecoder m_LevelDecoder; + NCompress::NHuffman::CDecoder7b m_LevelDecoder; UInt32 m_StoredBlockSize; @@ -56,7 +56,7 @@ class CCoder: UInt32 ReadBits(unsigned numBits); - bool DeCodeLevelTable(Byte *values, unsigned numSymbols); + bool DecodeLevels(Byte *levels, unsigned numSymbols); bool ReadTables(); HRESULT Flush() { return m_OutWindowStream.Flush(); } diff --git a/CPP/7zip/Compress/HuffmanDecoder.h b/CPP/7zip/Compress/HuffmanDecoder.h index 65e0f93c..04364c14 100644 --- a/CPP/7zip/Compress/HuffmanDecoder.h +++ b/CPP/7zip/Compress/HuffmanDecoder.h @@ -8,42 +8,89 @@ namespace NCompress { namespace NHuffman { -const unsigned kNumTableBits = 9; - -template +template class CDecoder { - UInt32 m_Limits[kNumBitsMax + 1]; // m_Limits[i] = value limit for symbols with length = i - UInt32 m_Positions[kNumBitsMax + 1]; // m_Positions[i] = index in m_Symbols[] of first symbol with length = i - UInt32 m_Symbols[m_NumSymbols]; - Byte m_Lengths[1 << kNumTableBits]; // Table of length for short codes - + UInt32 _limits[kNumBitsMax + 2]; + UInt32 _poses[kNumBitsMax + 1]; + UInt16 _lens[1 << kNumTableBits]; + UInt16 _symbols[m_NumSymbols]; public: - bool SetCodeLengths(const Byte *lens) + bool Build(const Byte *lens) throw() { UInt32 lenCounts[kNumBitsMax + 1]; - UInt32 tmpPositions[kNumBitsMax + 1]; + UInt32 tmpPoses[kNumBitsMax + 1]; unsigned i; - for (i = 1; i <= kNumBitsMax; i++) + for (i = 0; i <= kNumBitsMax; i++) lenCounts[i] = 0; - UInt32 symbol; + UInt32 sym; + + for (sym = 0; sym < m_NumSymbols; sym++) + lenCounts[lens[sym]]++; + + lenCounts[0] = 0; + _poses[0] = 0; + _limits[0] = 0; + UInt32 startPos = 0; + const UInt32 kMaxValue = (UInt32)1 << kNumBitsMax; - for (symbol = 0; symbol < m_NumSymbols; symbol++) + for (i = 1; i <= kNumBitsMax; i++) { - unsigned len = lens[symbol]; - if (len > kNumBitsMax) + startPos += lenCounts[i] << (kNumBitsMax - i); + if (startPos > kMaxValue) return false; - lenCounts[len]++; - m_Symbols[symbol] = 0xFFFFFFFF; + _limits[i] = startPos; + _poses[i] = _poses[i - 1] + lenCounts[i - 1]; + tmpPoses[i] = _poses[i]; + } + + _limits[kNumBitsMax + 1] = kMaxValue; + + for (sym = 0; sym < m_NumSymbols; sym++) + { + unsigned len = lens[sym]; + if (len == 0) + continue; + + unsigned offset = tmpPoses[len]; + _symbols[offset] = (UInt16)sym; + tmpPoses[len] = offset + 1; + + if (len <= kNumTableBits) + { + offset -= _poses[len]; + UInt32 num = (UInt32)1 << (kNumTableBits - len); + UInt16 val = (UInt16)((sym << 4) | len); + UInt16 *dest = _lens + (_limits[len - 1] >> (kNumBitsMax - kNumTableBits)) + (offset << (kNumTableBits - len)); + for (UInt32 k = 0; k < num; k++) + dest[k] = val; + } } + return true; + } + + bool BuildFull(const Byte *lens, UInt32 numSymbols = m_NumSymbols) throw() + { + UInt32 lenCounts[kNumBitsMax + 1]; + UInt32 tmpPoses[kNumBitsMax + 1]; + + unsigned i; + for (i = 0; i <= kNumBitsMax; i++) + lenCounts[i] = 0; + + UInt32 sym; + + for (sym = 0; sym < numSymbols; sym++) + lenCounts[lens[sym]]++; + lenCounts[0] = 0; - m_Positions[0] = m_Limits[0] = 0; + _poses[0] = 0; + _limits[0] = 0; UInt32 startPos = 0; - UInt32 index = 0; const UInt32 kMaxValue = (UInt32)1 << kNumBitsMax; for (i = 1; i <= kNumBitsMax; i++) @@ -51,44 +98,160 @@ public: startPos += lenCounts[i] << (kNumBitsMax - i); if (startPos > kMaxValue) return false; - m_Limits[i] = (i == kNumBitsMax) ? kMaxValue : startPos; - m_Positions[i] = m_Positions[i - 1] + lenCounts[i - 1]; - tmpPositions[i] = m_Positions[i]; - if (i <= kNumTableBits) + _limits[i] = startPos; + _poses[i] = _poses[i - 1] + lenCounts[i - 1]; + tmpPoses[i] = _poses[i]; + } + + _limits[kNumBitsMax + 1] = kMaxValue; + + for (sym = 0; sym < numSymbols; sym++) + { + unsigned len = lens[sym]; + if (len == 0) + continue; + + unsigned offset = tmpPoses[len]; + _symbols[offset] = (UInt16)sym; + tmpPoses[len] = offset + 1; + + if (len <= kNumTableBits) { - UInt32 limit = (m_Limits[i] >> (kNumBitsMax - kNumTableBits)); - for (; index < limit; index++) - m_Lengths[index] = (Byte)i; + offset -= _poses[len]; + UInt32 num = (UInt32)1 << (kNumTableBits - len); + UInt16 val = (UInt16)((sym << 4) | len); + UInt16 *dest = _lens + (_limits[len - 1] >> (kNumBitsMax - kNumTableBits)) + (offset << (kNumTableBits - len)); + for (UInt32 k = 0; k < num; k++) + dest[k] = val; } } - for (symbol = 0; symbol < m_NumSymbols; symbol++) + return startPos == kMaxValue; + } + + template + UInt32 Decode(TBitDecoder *bitStream) const throw() + { + UInt32 val = bitStream->GetValue(kNumBitsMax); + + if (val < _limits[kNumTableBits]) { - unsigned len = lens[symbol]; - if (len != 0) - m_Symbols[tmpPositions[len]++] = symbol; + UInt32 pair = _lens[val >> (kNumBitsMax - kNumTableBits)]; + bitStream->MovePos((unsigned)(pair & 0xF)); + return pair >> 4; } + + unsigned numBits; + for (numBits = kNumTableBits + 1; val >= _limits[numBits]; numBits++); - return true; + if (numBits > kNumBitsMax) + return 0xFFFFFFFF; + + bitStream->MovePos(numBits); + UInt32 index = _poses[numBits] + ((val - _limits[numBits - 1]) >> (kNumBitsMax - numBits)); + return _symbols[index]; } template - UInt32 DecodeSymbol(TBitDecoder *bitStream) + UInt32 DecodeFull(TBitDecoder *bitStream) const throw() { - unsigned numBits; UInt32 val = bitStream->GetValue(kNumBitsMax); - if (val < m_Limits[kNumTableBits]) - numBits = m_Lengths[val >> (kNumBitsMax - kNumTableBits)]; - else - for (numBits = kNumTableBits + 1; val >= m_Limits[numBits]; numBits++); + if (val < _limits[kNumTableBits]) + { + UInt32 pair = _lens[val >> (kNumBitsMax - kNumTableBits)]; + bitStream->MovePos((unsigned)(pair & 0xF)); + return pair >> 4; + } + + unsigned numBits; + for (numBits = kNumTableBits + 1; val >= _limits[numBits]; numBits++); bitStream->MovePos(numBits); - UInt32 index = m_Positions[numBits] + ((val - m_Limits[numBits - 1]) >> (kNumBitsMax - numBits)); - if (index >= m_NumSymbols) - // throw CDecoderException(); // test it - return 0xFFFFFFFF; - return m_Symbols[index]; + UInt32 index = _poses[numBits] + ((val - _limits[numBits - 1]) >> (kNumBitsMax - numBits)); + return _symbols[index]; + } +}; + + + +template +class CDecoder7b +{ + Byte _lens[1 << 7]; +public: + + bool Build(const Byte *lens) throw() + { + const unsigned kNumBitsMax = 7; + + UInt32 lenCounts[kNumBitsMax + 1]; + UInt32 tmpPoses[kNumBitsMax + 1]; + UInt32 _poses[kNumBitsMax + 1]; + UInt32 _limits[kNumBitsMax + 1]; + + unsigned i; + for (i = 0; i <= kNumBitsMax; i++) + lenCounts[i] = 0; + + UInt32 sym; + + for (sym = 0; sym < m_NumSymbols; sym++) + lenCounts[lens[sym]]++; + + lenCounts[0] = 0; + _poses[0] = 0; + _limits[0] = 0; + UInt32 startPos = 0; + const UInt32 kMaxValue = (UInt32)1 << kNumBitsMax; + + for (i = 1; i <= kNumBitsMax; i++) + { + startPos += lenCounts[i] << (kNumBitsMax - i); + if (startPos > kMaxValue) + return false; + _limits[i] = startPos; + _poses[i] = _poses[i - 1] + lenCounts[i - 1]; + tmpPoses[i] = _poses[i]; + } + + for (sym = 0; sym < m_NumSymbols; sym++) + { + unsigned len = lens[sym]; + if (len == 0) + continue; + + unsigned offset = tmpPoses[len]; + tmpPoses[len] = offset + 1; + + { + offset -= _poses[len]; + UInt32 num = (UInt32)1 << (kNumBitsMax - len); + Byte val = (Byte)((sym << 3) | len); + Byte *dest = _lens + (_limits[len - 1]) + (offset << (kNumBitsMax - len)); + for (UInt32 k = 0; k < num; k++) + dest[k] = val; + } + } + + { + UInt32 limit = _limits[kNumBitsMax]; + UInt32 num = ((UInt32)1 << kNumBitsMax) - limit; + Byte *dest = _lens + limit; + for (UInt32 k = 0; k < num; k++) + dest[k] = (Byte)(0x1F << 3); + } + + return true; + } + + template + UInt32 Decode(TBitDecoder *bitStream) const throw() + { + UInt32 val = bitStream->GetValue(7); + UInt32 pair = _lens[val]; + bitStream->MovePos((unsigned)(pair & 0x7)); + return pair >> 3; } }; diff --git a/CPP/7zip/Compress/LzhDecoder.cpp b/CPP/7zip/Compress/LzhDecoder.cpp index bf4a0b68..b0aa7536 100644 --- a/CPP/7zip/Compress/LzhDecoder.cpp +++ b/CPP/7zip/Compress/LzhDecoder.cpp @@ -71,7 +71,7 @@ bool CCoder::ReadTP(unsigned num, unsigned numBits, int spec) if (!CheckCodeLens(lens, NPT)) return false; - return _decoderT.SetCodeLengths(lens); + return _decoderT.Build(lens); } } @@ -101,7 +101,7 @@ bool CCoder::ReadC() { UInt32 c = (unsigned)_symbolT; if (_symbolT < 0) - c = _decoderT.DecodeSymbol(&_inBitStream); + c = _decoderT.Decode(&_inBitStream); if (c <= 2) { @@ -129,7 +129,7 @@ bool CCoder::ReadC() if (!CheckCodeLens(lens, NC)) return false; - return _decoderC.SetCodeLengths(lens); + return _decoderC.Build(lens); } } @@ -169,7 +169,7 @@ HRESULT CCoder::CodeReal(UInt64 rem, ICompressProgressInfo *progress) UInt32 number = (unsigned)_symbolC; if (_symbolC < 0) - number = _decoderC.DecodeSymbol(&_inBitStream); + number = _decoderC.Decode(&_inBitStream); if (number < 256) { @@ -182,7 +182,7 @@ HRESULT CCoder::CodeReal(UInt64 rem, ICompressProgressInfo *progress) UInt32 dist = (unsigned)_symbolT; if (_symbolT < 0) - dist = _decoderT.DecodeSymbol(&_inBitStream); + dist = _decoderT.Decode(&_inBitStream); if (dist > 1) { diff --git a/CPP/7zip/Compress/LzmsDecoder.cpp b/CPP/7zip/Compress/LzmsDecoder.cpp new file mode 100644 index 00000000..1f83b63d --- /dev/null +++ b/CPP/7zip/Compress/LzmsDecoder.cpp @@ -0,0 +1,573 @@ +// LzmsDecoder.cpp +// The code is based on LZMS description from wimlib code + +#include "StdAfx.h" + +#include "../../../C/Alloc.h" + +#include "LzmsDecoder.h" + +namespace NCompress { +namespace NLzms { + +static UInt32 g_PosBases[k_NumPosSyms /* + 1 */]; + +static Byte g_PosDirectBits[k_NumPosSyms]; + +static const Byte k_PosRuns[31] = +{ + 8, 0, 9, 7, 10, 15, 15, 20, 20, 30, 33, 40, 42, 45, 60, 73, + 80, 85, 95, 105, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 +}; + +static UInt32 g_LenBases[k_NumLenSyms]; + +static const Byte k_LenDirectBits[k_NumLenSyms] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, + 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 6, + 7, 8, 9, 10, 16, 30, +}; + +static struct CInit +{ + CInit() + { + { + unsigned sum = 0; + for (unsigned i = 0; i < sizeof(k_PosRuns); i++) + { + unsigned t = k_PosRuns[i]; + for (unsigned y = 0; y < t; y++) + g_PosDirectBits[sum + y] = (Byte)i; + sum += t; + } + } + { + UInt32 sum = 1; + for (unsigned i = 0; i < k_NumPosSyms; i++) + { + g_PosBases[i] = sum; + sum += (UInt32)1 << g_PosDirectBits[i]; + } + // g_PosBases[k_NumPosSyms] = sum; + } + { + UInt32 sum = 1; + for (unsigned i = 0; i < k_NumLenSyms; i++) + { + g_LenBases[i] = sum; + sum += (UInt32)1 << k_LenDirectBits[i]; + } + } + } +} g_Init; + +static unsigned GetNumPosSlots(size_t size) +{ + if (size < 2) + return 0; + + size--; + + if (size >= g_PosBases[k_NumPosSyms - 1]) + return k_NumPosSyms; + unsigned left = 0; + unsigned right = k_NumPosSyms; + for (;;) + { + unsigned m = (left + right) / 2; + if (left == m) + return m + 1; + if (size >= g_PosBases[m]) + left = m; + else + right = m; + } +} + + +static const Int32 k_x86_WindowSize = 65535; +static const Int32 k_x86_TransOffset = 1023; + +static const size_t k_x86_HistorySize = (1 << 16); + +static void x86_Filter(Byte *data, UInt32 size, Int32 *history) +{ + if (size <= 17) + return; + + Byte isCode[256]; + memset(isCode, 0, 256); + isCode[0x48] = 1; + isCode[0x4C] = 1; + isCode[0xE8] = 1; + isCode[0xE9] = 1; + isCode[0xF0] = 1; + isCode[0xFF] = 1; + + { + for (size_t i = 0; i < k_x86_HistorySize; i++) + history[i] = -(Int32)k_x86_WindowSize - 1; + } + + size -= 16; + const unsigned kSave = 6; + const Byte savedByte = data[size + kSave]; + data[size + kSave] = 0xE8; + Int32 last_x86_pos = -k_x86_TransOffset - 1; + + // first byte is ignored + Int32 i = 0; + + for (;;) + { + const Byte *p = data + (UInt32)i; + + for (;;) + { + if (isCode[*(++p)]) break; + if (isCode[*(++p)]) break; + } + + i = (Int32)(p - data); + if ((UInt32)i >= size) + break; + + UInt32 codeLen; + + Int32 maxTransOffset = k_x86_TransOffset; + + Byte b = p[0]; + + if (b == 0x48) + { + if (p[1] == 0x8B) + { + if ((p[2] & 0xF7) != 0x5) + continue; + // MOV RAX / RCX, [RIP + disp32] + } + else if (p[1] == 0x8D) // LEA + { + if ((p[2] & 0x7) != 0x5) + continue; + // LEA R**, [] + } + else + continue; + codeLen = 3; + } + else if (b == 0x4C) + { + if (p[1] != 0x8D || (p[2] & 0x7) != 0x5) + continue; + // LEA R*, [] + codeLen = 3; + } + else if (b == 0xE8) + { + // CALL + codeLen = 1; + maxTransOffset /= 2; + } + else if (b == 0xE9) + { + // JUMP + i += 4; + continue; + } + else if (b == 0xF0) + { + if (p[1] != 0x83 || p[2] != 0x05) + continue; + // LOCK ADD [RIP + disp32], imm8 + // LOCK ADD [disp32], imm8 + codeLen = 3; + } + else + // if (b == 0xFF) + { + if (p[1] != 0x15) + continue; + // CALL [RIP + disp32]; + // CALL [disp32]; + codeLen = 2; + } + + Int32 *target; + { + const Byte *p2 = p + codeLen; + UInt32 n = GetUi32(p2); + if (i - last_x86_pos <= maxTransOffset) + { + n -= i; + SetUi32(p2, n); + } + target = history + (((UInt32)i + n) & 0xFFFF); + } + + i += codeLen + sizeof(UInt32) - 1; + + if (i - *target <= k_x86_WindowSize) + last_x86_pos = i; + *target = i; + } + + data[size + kSave] = savedByte; +} + + + +static const int kLenIdNeedInit = -2; + +CDecoder::CDecoder(): + _x86_history(NULL) +{ +} + +CDecoder::~CDecoder() +{ + ::MidFree(_x86_history); +} + +#define RIF(x) { if (!(x)) return false; } + +#define LIMIT_CHECK if (_bs._buf < _rc.cur) return S_FALSE; +// #define LIMIT_CHECK + +#define READ_BITS_CHECK(numDirectBits) \ + if (_bs._buf < _rc.cur) return S_FALSE; \ + if ((size_t)(_bs._buf - _rc.cur) < (numDirectBits >> 3)) return S_FALSE; + + +#define HUFF_DEC(sym, pp) \ + sym = pp.DecodeFull(&_bs); \ + pp.Freqs[sym]++; \ + if (--pp.RebuildRem == 0) pp.Rebuild(); + + +HRESULT CDecoder::CodeReal(const Byte *in, size_t inSize, Byte *_win, size_t outSize) +{ + // size_t inSizeT = (size_t)(inSize); + // Byte *_win; + // size_t _pos; + _pos = 0; + + CBitDecoder _bs; + CRangeDecoder _rc; + + if (inSize < 8 || (inSize & 1) != 0) + return S_FALSE; + _rc.Init(in, inSize); + if (_rc.code >= _rc.range) + return S_FALSE; + _bs.Init(in, inSize); + + { + { + unsigned i; + for (i = 0 ; i < k_NumReps + 1; i++) + _reps[i] = i + 1; + + for (i = 0 ; i < k_NumReps + 1; i++) + _deltaReps[i] = i + 1; + + mainState = 0; + matchState = 0; + + { for (size_t i = 0; i < k_NumMainProbs; i++) mainProbs[i].Init(); } + { for (size_t i = 0; i < k_NumMatchProbs; i++) matchProbs[i].Init(); } + + { + for (size_t k = 0; k < k_NumReps; k++) + { + lzRepStates[k] = 0; + for (size_t i = 0; i < k_NumRepProbs; i++) + lzRepProbs[k][i].Init(); + } + } + { + for (size_t k = 0; k < k_NumReps; k++) + { + deltaRepStates[k] = 0; + for (size_t i = 0; i < k_NumRepProbs; i++) + deltaRepProbs[k][i].Init(); + } + } + + m_LitDecoder.Init(); + m_LenDecoder.Init(); + m_PowerDecoder.Init(); + unsigned numPosSyms = GetNumPosSlots(outSize); + if (numPosSyms < 2) + numPosSyms = 2; + m_PosDecoder.Init(numPosSyms); + m_DeltaDecoder.Init(numPosSyms); + } + } + + { + unsigned prevType = 0; + + while (_pos < outSize) + { + if (_rc.Decode(&mainState, k_NumMainProbs, mainProbs) == 0) + { + UInt32 number; + HUFF_DEC(number, m_LitDecoder); + LIMIT_CHECK + _win[_pos++] = (Byte)number; + prevType = 0; + } + else if (_rc.Decode(&matchState, k_NumMatchProbs, matchProbs) == 0) + { + UInt32 distance; + + if (_rc.Decode(&lzRepStates[0], k_NumRepProbs, lzRepProbs[0]) == 0) + { + UInt32 number; + HUFF_DEC(number, m_PosDecoder); + LIMIT_CHECK + + unsigned numDirectBits = g_PosDirectBits[number]; + distance = g_PosBases[number]; + READ_BITS_CHECK(numDirectBits); + distance += _bs.ReadBits32(numDirectBits); + // LIMIT_CHECK + _reps[3] = _reps[2]; + _reps[2] = _reps[1]; + _reps[1] = _reps[0]; + _reps[0] = distance; + } + else + { + if (_rc.Decode(&lzRepStates[1], k_NumRepProbs, lzRepProbs[1]) == 0) + { + if (prevType != 1) + distance = _reps[0]; + else + { + distance = _reps[1]; + _reps[1] = _reps[0]; + _reps[0] = distance; + } + } + else if (_rc.Decode(&lzRepStates[2], k_NumRepProbs, lzRepProbs[2]) == 0) + { + if (prevType != 1) + { + distance = _reps[1]; + _reps[1] = _reps[0]; + _reps[0] = distance; + } + else + { + distance = _reps[2]; + _reps[2] = _reps[1]; + _reps[1] = _reps[0]; + _reps[0] = distance; + } + } + else + { + if (prevType != 1) + { + distance = _reps[2]; + _reps[2] = _reps[1]; + _reps[1] = _reps[0]; + _reps[0] = distance; + } + else + { + distance = _reps[3]; + _reps[3] = _reps[2]; + _reps[2] = _reps[1]; + _reps[1] = _reps[0]; + _reps[0] = distance; + } + } + } + + UInt32 lenSlot; + HUFF_DEC(lenSlot, m_LenDecoder); + LIMIT_CHECK + + UInt32 len = g_LenBases[lenSlot]; + { + unsigned numDirectBits = k_LenDirectBits[lenSlot]; + READ_BITS_CHECK(numDirectBits); + len += _bs.ReadBits32(numDirectBits); + } + // LIMIT_CHECK + + if (len > outSize - _pos) + return S_FALSE; + + if (distance > _pos) + return S_FALSE; + + Byte *dest = _win + _pos; + const Byte *src = dest - distance; + _pos += len; + do + *dest++ = *src++; + while (--len); + + prevType = 1; + } + else + { + UInt64 distance; + + UInt32 power; + UInt32 distance32; + + if (_rc.Decode(&deltaRepStates[0], k_NumRepProbs, deltaRepProbs[0]) == 0) + { + HUFF_DEC(power, m_PowerDecoder); + LIMIT_CHECK + + UInt32 number; + HUFF_DEC(number, m_DeltaDecoder); + LIMIT_CHECK + + unsigned numDirectBits = g_PosDirectBits[number]; + distance32 = g_PosBases[number]; + READ_BITS_CHECK(numDirectBits); + distance32 += _bs.ReadBits32(numDirectBits); + // LIMIT_CHECK + + distance = ((UInt64)power << 32) | distance32; + + _deltaReps[3] = _deltaReps[2]; + _deltaReps[2] = _deltaReps[1]; + _deltaReps[1] = _deltaReps[0]; + _deltaReps[0] = distance; + } + else + { + if (_rc.Decode(&deltaRepStates[1], k_NumRepProbs, deltaRepProbs[1]) == 0) + { + if (prevType != 2) + distance = _deltaReps[0]; + else + { + distance = _deltaReps[1]; + _deltaReps[1] = _deltaReps[0]; + _deltaReps[0] = distance; + } + } + else if (_rc.Decode(&deltaRepStates[2], k_NumRepProbs, deltaRepProbs[2]) == 0) + { + if (prevType != 2) + { + distance = _deltaReps[1]; + _deltaReps[1] = _deltaReps[0]; + _deltaReps[0] = distance; + } + else + { + distance = _deltaReps[2]; + _deltaReps[2] = _deltaReps[1]; + _deltaReps[1] = _deltaReps[0]; + _deltaReps[0] = distance; + } + } + else + { + if (prevType != 2) + { + distance = _deltaReps[2]; + _deltaReps[2] = _deltaReps[1]; + _deltaReps[1] = _deltaReps[0]; + _deltaReps[0] = distance; + } + else + { + distance = _deltaReps[3]; + _deltaReps[3] = _deltaReps[2]; + _deltaReps[2] = _deltaReps[1]; + _deltaReps[1] = _deltaReps[0]; + _deltaReps[0] = distance; + } + } + distance32 = (UInt32)_deltaReps[0] & 0xFFFFFFFF; + power = (UInt32)(_deltaReps[0] >> 32); + } + + UInt32 dist = (distance32 << power); + + UInt32 lenSlot; + HUFF_DEC(lenSlot, m_LenDecoder); + LIMIT_CHECK + + UInt32 len = g_LenBases[lenSlot]; + { + unsigned numDirectBits = k_LenDirectBits[lenSlot]; + READ_BITS_CHECK(numDirectBits); + len += _bs.ReadBits32(numDirectBits); + } + // LIMIT_CHECK + + if (len > outSize - _pos) + return S_FALSE; + + if (dist > _pos) + return S_FALSE; + size_t span = (size_t)1 << power; + Byte *dest = _win + _pos - span; + const Byte *src = dest - dist; + _pos += len; + do + { + *(dest + span) = (Byte)(*(dest) + *(src + span) - *(src)); + src++; + dest++; + } + while (--len); + + prevType = 2; + } + } + } + + _rc.Normalize(); + if (_rc.code != 0) + return S_FALSE; + if (_rc.cur > _bs._buf || + _rc.cur == _bs._buf && _bs._bitPos != 0) + return S_FALSE; + + /* + int delta = (int)(_bs._buf - _rc.cur); + if (_bs._bitPos != 0) + delta--; + if ((delta & 1)) + delta--; + printf("%d ", delta); + */ + + return S_OK; +} + +HRESULT CDecoder::Code(const Byte *in, size_t inSize, Byte *out, size_t outSize) +{ + if (!_x86_history) + { + _x86_history = (Int32 *)::MidAlloc(sizeof(Int32) * k_x86_HistorySize); + if (!_x86_history) + return E_OUTOFMEMORY; + } + HRESULT res; + // try + { + res = CodeReal(in, inSize, out, outSize); + } + // catch (...) { res = S_FALSE; } + x86_Filter(out, (UInt32)_pos, _x86_history); + return res; +} + +}} diff --git a/CPP/7zip/Compress/LzmsDecoder.h b/CPP/7zip/Compress/LzmsDecoder.h new file mode 100644 index 00000000..510d3389 --- /dev/null +++ b/CPP/7zip/Compress/LzmsDecoder.h @@ -0,0 +1,271 @@ +// LzmsDecoder.h +// The code is based on LZMS description from wimlib code + +#ifndef __LZMS_DECODER_H +#define __LZMS_DECODER_H + +// #define SHOW_DEBUG_INFO + +#ifdef SHOW_DEBUG_INFO +#include +#define PRF(x) x +#else +// #define PRF(x) +#endif + +#include "../../../C/CpuArch.h" +#include "../../../C/HuffEnc.h" + +#include "../../Common/MyBuffer.h" +#include "../../Common/MyCom.h" + +#include "../ICoder.h" + +#include "HuffmanDecoder.h" + +namespace NCompress { +namespace NLzms { + +class CBitDecoder +{ +public: + const Byte *_buf; + unsigned _bitPos; + + void Init(const Byte *buf, size_t size) throw() + { + _buf = buf + size; + _bitPos = 0; + } + + UInt32 GetValue(unsigned numBits) const + { + UInt32 v = ((UInt32)_buf[-1] << 16) | ((UInt32)_buf[-2] << 8) | (UInt32)_buf[-3]; + v >>= (24 - numBits - _bitPos); + return v & ((1 << numBits) - 1); + } + + void MovePos(unsigned numBits) + { + _bitPos += numBits; + _buf -= (_bitPos >> 3); + _bitPos &= 7; + } + + UInt32 ReadBits32(unsigned numBits) + { + UInt32 mask = (((UInt32)1 << numBits) - 1); + numBits += _bitPos; + const Byte *buf = _buf; + UInt32 v = GetUi32(buf - 4); + if (numBits > 32) + { + v <<= (numBits - 32); + v |= (UInt32)buf[-5] >> (40 - numBits); + } + else + v >>= (32 - numBits); + _buf = buf - (numBits >> 3); + _bitPos = numBits & 7; + return v & mask; + } +}; + + +const unsigned k_NumLitSyms = 256; +const unsigned k_NumLenSyms = 54; +const unsigned k_NumPosSyms = 799; +const unsigned k_NumPowerSyms = 8; + +const unsigned k_NumProbBits = 6; +const unsigned k_ProbLimit = 1 << k_NumProbBits; +const unsigned k_InitialProb = 48; +const UInt32 k_InitialHist = 0x55555555; + +const unsigned k_NumReps = 3; + +const unsigned k_NumMainProbs = 16; +const unsigned k_NumMatchProbs = 32; +const unsigned k_NumRepProbs = 64; + +const unsigned k_NumHuffmanBits = 15; + +template +class CHuffDecoder: public NCompress::NHuffman::CDecoder +{ +public: + UInt32 RebuildRem; + UInt32 NumSyms; + UInt32 Freqs[m_NumSyms]; + + void Generate() throw() + { + UInt32 vals[m_NumSyms]; + Byte levels[m_NumSyms]; + + // We need to check that our algorithm is OK, when optimal Huffman tree uses more than 15 levels !!! + Huffman_Generate(Freqs, vals, levels, NumSyms, k_NumHuffmanBits); + + /* + for (UInt32 i = NumSyms; i < m_NumSyms; i++) + levels[i] = 0; + */ + this->BuildFull(levels, NumSyms); + } + + void Rebuild() throw() + { + Generate(); + RebuildRem = m_RebuildFreq; + UInt32 num = NumSyms; + for (UInt32 i = 0; i < num; i++) + Freqs[i] = (Freqs[i] >> 1) + 1; + } + +public: + void Init(UInt32 numSyms = m_NumSyms) throw() + { + RebuildRem = m_RebuildFreq; + NumSyms = numSyms; + for (UInt32 i = 0; i < numSyms; i++) + Freqs[i] = 1; + // for (; i < m_NumSyms; i++) Freqs[i] = 0; + Generate(); + } +}; + + +struct CProbEntry +{ + UInt32 Prob; + UInt64 Hist; + + void Init() + { + Prob = k_InitialProb; + Hist = k_InitialHist; + } + + UInt32 GetProb() const throw() + { + UInt32 prob = Prob; + if (prob == 0) + prob = 1; + else if (prob == k_ProbLimit) + prob = k_ProbLimit - 1; + return prob; + } + + void Update(unsigned bit) throw() + { + Prob += (Int32)(Hist >> (k_ProbLimit - 1)) - (Int32)bit; + Hist = (Hist << 1) | bit; + } +}; + + +struct CRangeDecoder +{ + UInt32 range; + UInt32 code; + const Byte *cur; + // const Byte *end; + + void Init(const Byte *data, size_t /* size */) throw() + { + range = 0xFFFFFFFF; + code = (((UInt32)GetUi16(data)) << 16) | GetUi16(data + 2); + cur = data + 4; + // end = data + size; + } + + void Normalize() + { + if (range <= 0xFFFF) + { + range <<= 16; + code <<= 16; + // if (cur >= end) throw 1; + code |= GetUi16(cur); + cur += 2; + } + } + + unsigned Decode(UInt32 *state, UInt32 numStates, struct CProbEntry *probs) + { + UInt32 st = *state; + CProbEntry *entry = &probs[st]; + st = (st << 1) & (numStates - 1); + + UInt32 prob = entry->GetProb(); + + if (range <= 0xFFFF) + { + range <<= 16; + code <<= 16; + // if (cur >= end) throw 1; + code |= GetUi16(cur); + cur += 2; + } + + UInt32 bound = (range >> k_NumProbBits) * prob; + + if (code < bound) + { + range = bound; + *state = st; + entry->Update(0); + return 0; + } + else + { + range -= bound; + code -= bound; + *state = st | 1; + entry->Update(1); + return 1; + } + } +}; + + +class CDecoder +{ + // CRangeDecoder _rc; + // CBitDecoder _bs; + size_t _pos; + + UInt32 _reps[k_NumReps + 1]; + UInt64 _deltaReps[k_NumReps + 1]; + + UInt32 mainState; + UInt32 matchState; + UInt32 lzRepStates[k_NumReps]; + UInt32 deltaRepStates[k_NumReps]; + + struct CProbEntry mainProbs[k_NumMainProbs]; + struct CProbEntry matchProbs[k_NumMatchProbs]; + + struct CProbEntry lzRepProbs[k_NumReps][k_NumRepProbs]; + struct CProbEntry deltaRepProbs[k_NumReps][k_NumRepProbs]; + + CHuffDecoder m_LitDecoder; + CHuffDecoder m_PosDecoder; + CHuffDecoder m_LenDecoder; + CHuffDecoder m_PowerDecoder; + CHuffDecoder m_DeltaDecoder; + + Int32 *_x86_history; + + HRESULT CodeReal(const Byte *in, size_t inSize, Byte *out, size_t outSize); +public: + CDecoder(); + ~CDecoder(); + + HRESULT Code(const Byte *in, size_t inSize, Byte *out, size_t outSize); + const size_t GetUnpackSize() const { return _pos; } +}; + +}} + +#endif diff --git a/CPP/7zip/Compress/Lzx.h b/CPP/7zip/Compress/Lzx.h index 09ab7f07..29ca4cac 100644 --- a/CPP/7zip/Compress/Lzx.h +++ b/CPP/7zip/Compress/Lzx.h @@ -6,55 +6,51 @@ namespace NCompress { namespace NLzx { +const unsigned kBlockType_NumBits = 3; +const unsigned kBlockType_Verbatim = 1; +const unsigned kBlockType_Aligned = 2; +const unsigned kBlockType_Uncompressed = 3; + const unsigned kNumHuffmanBits = 16; -const UInt32 kNumRepDistances = 3; +const unsigned kNumReps = 3; -const UInt32 kNumLenSlots = 8; -const UInt32 kMatchMinLen = 2; -const UInt32 kNumLenSymbols = 249; -const UInt32 kMatchMaxLen = kMatchMinLen + (kNumLenSlots - 1) + kNumLenSymbols - 1; +const unsigned kNumLenSlots = 8; +const unsigned kMatchMinLen = 2; +const unsigned kNumLenSymbols = 249; +const unsigned kMatchMaxLen = kMatchMinLen + (kNumLenSlots - 1) + kNumLenSymbols - 1; +const unsigned kNumAlignLevelBits = 3; const unsigned kNumAlignBits = 3; -const UInt32 kAlignTableSize = 1 << kNumAlignBits; - -const UInt32 kNumPosSlots = 50; -const UInt32 kNumPosLenSlots = kNumPosSlots * kNumLenSlots; - -const UInt32 kMainTableSize = 256 + kNumPosLenSlots; -const UInt32 kLevelTableSize = 20; -const UInt32 kMaxTableSize = kMainTableSize; - -const unsigned kNumBlockTypeBits = 3; -const unsigned kBlockTypeVerbatim = 1; -const unsigned kBlockTypeAligned = 2; -const unsigned kBlockTypeUncompressed = 3; +const unsigned kAlignTableSize = 1 << kNumAlignBits; -const unsigned kUncompressedBlockSizeNumBits = 24; +const unsigned kNumPosSlots = 50; +const unsigned kNumPosLenSlots = kNumPosSlots * kNumLenSlots; -const unsigned kNumBitsForPreTreeLevel = 4; +const unsigned kMainTableSize = 256 + kNumPosLenSlots; +const unsigned kLevelTableSize = 20; +const unsigned kMaxTableSize = kMainTableSize; -const unsigned kLevelSymbolZeros = 17; -const unsigned kLevelSymbolZerosBig = 18; -const unsigned kLevelSymbolSame = 19; +const unsigned kNumLevelBits = 4; -const unsigned kLevelSymbolZerosStartValue = 4; -const unsigned kLevelSymbolZerosNumBits = 4; +const unsigned kLevelSym_Zero1 = 17; +const unsigned kLevelSym_Zero2 = 18; +const unsigned kLevelSym_Same = 19; -const unsigned kLevelSymbolZerosBigStartValue = kLevelSymbolZerosStartValue + - (1 << kLevelSymbolZerosNumBits); -const unsigned kLevelSymbolZerosBigNumBits = 5; +const unsigned kLevelSym_Zero1_Start = 4; +const unsigned kLevelSym_Zero1_NumBits = 4; -const unsigned kLevelSymbolSameNumBits = 1; -const unsigned kLevelSymbolSameStartValue = 4; +const unsigned kLevelSym_Zero2_Start = kLevelSym_Zero1_Start + (1 << kLevelSym_Zero1_NumBits); +const unsigned kLevelSym_Zero2_NumBits = 5; -const unsigned kNumBitsForAlignLevel = 3; - -const unsigned kNumDictionaryBitsMin = 15; -const unsigned kNumDictionaryBitsMax = 21; -const UInt32 kDictionarySizeMax = (1 << kNumDictionaryBitsMax); +const unsigned kLevelSym_Same_NumBits = 1; +const unsigned kLevelSym_Same_Start = 4; + +const unsigned kNumDictBits_Min = 15; +const unsigned kNumDictBits_Max = 21; +const UInt32 kDictSize_Max = (UInt32)1 << kNumDictBits_Max; const unsigned kNumLinearPosSlotBits = 17; -const UInt32 kNumPowerPosSlots = 0x26; +const unsigned kNumPowerPosSlots = 38; }} diff --git a/CPP/7zip/Compress/Lzx86Converter.cpp b/CPP/7zip/Compress/Lzx86Converter.cpp deleted file mode 100644 index 3a63057a..00000000 --- a/CPP/7zip/Compress/Lzx86Converter.cpp +++ /dev/null @@ -1,90 +0,0 @@ -// Lzx86Converter.cpp - -#include "StdAfx.h" - -#include "../../Common/Defs.h" - -#include "Lzx86Converter.h" - -namespace NCompress { -namespace NLzx { - -static const UInt32 kResidue = 6 + 4; - -void Cx86ConvertOutStream::MakeTranslation() -{ - if (_pos <= kResidue) - return; - UInt32 numBytes = _pos - kResidue; - Byte *buf = _buf; - for (UInt32 i = 0; i < numBytes;) - { - if (buf[i++] == 0xE8) - { - Int32 absValue = 0; - unsigned j; - for (j = 0; j < 4; j++) - absValue += (UInt32)buf[i + j] << (j * 8); - Int32 pos = (Int32)(_processedSize + i - 1); - if (absValue >= -pos && absValue < (Int32)_translationSize) - { - UInt32 offset = (absValue >= 0) ? - absValue - pos : - absValue + _translationSize; - for (j = 0; j < 4; j++) - { - buf[i + j] = (Byte)(offset & 0xFF); - offset >>= 8; - } - } - i += 4; - } - } -} - -STDMETHODIMP Cx86ConvertOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize) -{ - if (processedSize) - *processedSize = 0; - if (!_translationMode) - return _stream->Write(data, size, processedSize); - UInt32 realProcessedSize = 0; - while (realProcessedSize < size) - { - UInt32 writeSize = MyMin(size - realProcessedSize, kUncompressedBlockSize - _pos); - memcpy(_buf + _pos, (const Byte *)data + realProcessedSize, writeSize); - _pos += writeSize; - realProcessedSize += writeSize; - if (_pos == kUncompressedBlockSize) - { - RINOK(Flush()); - } - } - if (processedSize) - *processedSize = realProcessedSize; - return S_OK; -} - -HRESULT Cx86ConvertOutStream::Flush() -{ - if (_pos == 0) - return S_OK; - if (_translationMode) - MakeTranslation(); - UInt32 pos = 0; - do - { - UInt32 processed; - RINOK(_stream->Write(_buf + pos, _pos - pos, &processed)); - if (processed == 0) - return E_FAIL; - pos += processed; - } - while (pos < _pos); - _processedSize += _pos; - _pos = 0; - _translationMode = (_translationMode && (_processedSize < ((UInt32)1 << 30))); - return S_OK; -} - -}} diff --git a/CPP/7zip/Compress/Lzx86Converter.h b/CPP/7zip/Compress/Lzx86Converter.h deleted file mode 100644 index 1e531d1a..00000000 --- a/CPP/7zip/Compress/Lzx86Converter.h +++ /dev/null @@ -1,45 +0,0 @@ -// Lzx86Converter.h - -#ifndef __LZX_86_CONVERTER_H -#define __LZX_86_CONVERTER_H - -#include "../../Common/MyCom.h" - -#include "../IStream.h" - -namespace NCompress { -namespace NLzx { - -const unsigned kUncompressedBlockSize = (unsigned)1 << 15; - -class Cx86ConvertOutStream: - public ISequentialOutStream, - public CMyUnknownImp -{ - ISequentialOutStream *_stream; - UInt32 _processedSize; - UInt32 _pos; - UInt32 _translationSize; - bool _translationMode; - Byte _buf[kUncompressedBlockSize]; - - void MakeTranslation(); -public: - void SetStream(ISequentialOutStream *outStream) { _stream = outStream; } - void Init(bool translationMode, UInt32 translationSize) - { - _translationMode = translationMode; - _translationSize = translationSize; - _processedSize = 0; - _pos = 0; - } - HRESULT Flush(); - - MY_UNKNOWN_IMP - - STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); -}; - -}} - -#endif diff --git a/CPP/7zip/Compress/LzxDecoder.cpp b/CPP/7zip/Compress/LzxDecoder.cpp index acf3b037..8bdcc307 100644 --- a/CPP/7zip/Compress/LzxDecoder.cpp +++ b/CPP/7zip/Compress/LzxDecoder.cpp @@ -2,394 +2,528 @@ #include "StdAfx.h" -#include "../../Common/Defs.h" +#include + +// #define SHOW_DEBUG_INFO + +#ifdef SHOW_DEBUG_INFO +#include +#define PRF(x) x +#else +#define PRF(x) +#endif + +#include "../../../C/Alloc.h" #include "LzxDecoder.h" namespace NCompress { namespace NLzx { -const int kLenIdNeedInit = -2; +static void x86_Filter(Byte *data, UInt32 size, UInt32 processedSize, UInt32 translationSize) +{ + const UInt32 kResidue = 10; + if (size <= kResidue) + return; + size -= kResidue; + + Byte save = data[size + 4]; + data[size + 4] = 0xE8; + + for (UInt32 i = 0;;) + { + const Byte *p = data + i; + for (;;) + { + if (*p++ == 0xE8) break; + if (*p++ == 0xE8) break; + if (*p++ == 0xE8) break; + if (*p++ == 0xE8) break; + } + + i = (UInt32)(p - data); + + if (i > size) + break; + { + Int32 v = GetUi32(p); + Int32 pos = (Int32)((Int32)1 - (Int32)(processedSize + i)); + i += 4; + if (v >= pos && v < (Int32)translationSize) + { + v += (v >= 0 ? pos : translationSize); + SetUi32(p, v); + } + } + } + + data[size + 4] = save; +} + CDecoder::CDecoder(bool wimMode): - _keepHistory(false), - _skipByte(false), - _wimMode(wimMode) + _win(NULL), + _keepHistory(false), + _skipByte(false), + _wimMode(wimMode), + _numDictBits(15), + _unpackBlockSize(0), + _x86_buf(NULL), + _x86_translationSize(0), + KeepHistoryForNext(true), + NeedAlloc(true), + _unpackedData(NULL) { - m_x86ConvertOutStreamSpec = new Cx86ConvertOutStream; - m_x86ConvertOutStream = m_x86ConvertOutStreamSpec; } -/* -void CDecoder::ReleaseStreams() +CDecoder::~CDecoder() { - m_OutWindowStream.ReleaseStream(); - m_InBitStream.ReleaseStream(); - m_x86ConvertOutStreamSpec->ReleaseStream(); + if (NeedAlloc) + ::MidFree(_win); + ::MidFree(_x86_buf); } -*/ -STDMETHODIMP CDecoder::Flush() +HRESULT CDecoder::Flush() { - RINOK(m_OutWindowStream.Flush()); - return m_x86ConvertOutStreamSpec->Flush(); + if (_x86_translationSize != 0) + { + Byte *destData = _win + _writePos; + UInt32 curSize = _pos - _writePos; + if (KeepHistoryForNext) + { + if (!_x86_buf) + { + // we must change it to support another chunk sizes + const size_t kChunkSize = (size_t)1 << 15; + if (curSize > kChunkSize) + return E_NOTIMPL; + _x86_buf = (Byte *)::MidAlloc(kChunkSize); + if (!_x86_buf) + return E_OUTOFMEMORY; + } + memcpy(_x86_buf, destData, curSize); + _unpackedData = _x86_buf; + destData = _x86_buf; + } + x86_Filter(destData, (UInt32)curSize, _x86_processedSize, _x86_translationSize); + _x86_processedSize += (UInt32)curSize; + if (_x86_processedSize >= ((UInt32)1 << 30)) + _x86_translationSize = 0; + } + + return S_OK; } -UInt32 CDecoder::ReadBits(unsigned numBits) { return m_InBitStream.ReadBits(numBits); } + +UInt32 CDecoder::ReadBits(unsigned numBits) { return _bitStream.ReadBitsSmall(numBits); } #define RIF(x) { if (!(x)) return false; } -bool CDecoder::ReadTable(Byte *lastLevels, Byte *newLevels, UInt32 numSymbols) +bool CDecoder::ReadTable(Byte *levels, unsigned numSymbols) { - Byte levelLevels[kLevelTableSize]; - UInt32 i; - for (i = 0; i < kLevelTableSize; i++) - levelLevels[i] = (Byte)ReadBits(kNumBitsForPreTreeLevel); - RIF(m_LevelDecoder.SetCodeLengths(levelLevels)); - unsigned num = 0; - Byte symbol = 0; - for (i = 0; i < numSymbols;) { - if (num != 0) + Byte levels2[kLevelTableSize]; + for (unsigned i = 0; i < kLevelTableSize; i++) + levels2[i] = (Byte)ReadBits(kNumLevelBits); + RIF(_levelDecoder.Build(levels2)); + } + + unsigned i = 0; + do + { + UInt32 sym = _levelDecoder.Decode(&_bitStream); + if (sym <= kNumHuffmanBits) { - lastLevels[i] = newLevels[i] = symbol; - i++; - num--; + int delta = (int)levels[i] - (int)sym; + delta += (delta < 0) ? (kNumHuffmanBits + 1) : 0; + levels[i++] = (Byte)delta; continue; } - UInt32 number = m_LevelDecoder.DecodeSymbol(&m_InBitStream); - if (number == kLevelSymbolZeros) - { - num = kLevelSymbolZerosStartValue + (unsigned)ReadBits(kLevelSymbolZerosNumBits); - symbol = 0; - } - else if (number == kLevelSymbolZerosBig) + + unsigned num; + Byte symbol; + + if (sym < kLevelSym_Same) { - num = kLevelSymbolZerosBigStartValue + (unsigned)ReadBits(kLevelSymbolZerosBigNumBits); + sym -= kLevelSym_Zero1; + num = kLevelSym_Zero1_Start + ((unsigned)sym << kLevelSym_Zero1_NumBits) + + (unsigned)ReadBits(kLevelSym_Zero1_NumBits + sym); symbol = 0; } - else if (number == kLevelSymbolSame || number <= kNumHuffmanBits) + else if (sym == kLevelSym_Same) { - if (number <= kNumHuffmanBits) - num = 1; - else - { - num = kLevelSymbolSameStartValue + (unsigned)ReadBits(kLevelSymbolSameNumBits); - number = m_LevelDecoder.DecodeSymbol(&m_InBitStream); - if (number > kNumHuffmanBits) - return false; - } - symbol = Byte((17 + lastLevels[i] - number) % (kNumHuffmanBits + 1)); + num = kLevelSym_Same_Start + (unsigned)ReadBits(kLevelSym_Same_NumBits); + sym = _levelDecoder.Decode(&_bitStream); + if (sym > kNumHuffmanBits) + return false; + int delta = (int)levels[i] - (int)sym; + delta += (delta < 0) ? (kNumHuffmanBits + 1) : 0; + symbol = (Byte)delta; } else return false; + + unsigned limit = i + num; + if (limit > numSymbols) + return false; + + do + levels[i++] = symbol; + while (i < limit); } + while (i < numSymbols); + return true; } + bool CDecoder::ReadTables(void) { - Byte newLevels[kMaxTableSize]; { if (_skipByte) - m_InBitStream.DirectReadByte(); - m_InBitStream.Normalize(); + { + if (_bitStream.DirectReadByte() != 0) + return false; + } + + _bitStream.NormalizeBig(); - unsigned blockType = (unsigned)ReadBits(kNumBlockTypeBits); - if (blockType > kBlockTypeUncompressed) + unsigned blockType = (unsigned)ReadBits(kBlockType_NumBits); + if (blockType > kBlockType_Uncompressed) return false; - if (_wimMode) - if (ReadBits(1) == 1) - m_UnCompressedBlockSize = (1 << 15); - else - m_UnCompressedBlockSize = ReadBits(16); - else - m_UnCompressedBlockSize = m_InBitStream.ReadBitsBig(kUncompressedBlockSizeNumBits); + + _unpackBlockSize = (1 << 15); + if (!_wimMode || ReadBits(1) == 0) + { + _unpackBlockSize = ReadBits(16); + // wimlib supports chunks larger than 32KB (unsupported my MS wim). + if (!_wimMode || _numDictBits >= 16) + { + _unpackBlockSize <<= 8; + _unpackBlockSize |= ReadBits(8); + } + } + + PRF(printf("\nBlockSize = %6d %s ", _unpackBlockSize, (_pos & 1) ? "@@@" : " ")); - m_IsUncompressedBlock = (blockType == kBlockTypeUncompressed); + _isUncompressedBlock = (blockType == kBlockType_Uncompressed); - _skipByte = (m_IsUncompressedBlock && ((m_UnCompressedBlockSize & 1) != 0)); + _skipByte = false; - if (m_IsUncompressedBlock) + if (_isUncompressedBlock) { - ReadBits(16 - m_InBitStream.GetBitPosition()); - if (!m_InBitStream.ReadUInt32(m_RepDistances[0])) + _skipByte = ((_unpackBlockSize & 1) != 0); + + PRF(printf(" UncompressedBlock ")); + if (_unpackBlockSize & 1) + { + PRF(printf(" ######### ")); + } + + if (!_bitStream.PrepareUncompressed()) return false; - m_RepDistances[0]--; - for (unsigned i = 1; i < kNumRepDistances; i++) + if (_bitStream.GetRem() < kNumReps * 4) + return false; + + for (unsigned i = 0; i < kNumReps; i++) { - UInt32 rep = 0; - for (unsigned j = 0; j < 4; j++) - rep |= (UInt32)m_InBitStream.DirectReadByte() << (8 * j); - m_RepDistances[i] = rep - 1; + UInt32 rep = _bitStream.ReadUInt32(); + if (rep > _winSize) + return false; + _reps[i] = rep; } + return true; } - m_AlignIsUsed = (blockType == kBlockTypeAligned); - if (m_AlignIsUsed) + + _numAlignBits = 64; + + if (blockType == kBlockType_Aligned) { + Byte levels[kAlignTableSize]; + _numAlignBits = kNumAlignBits; for (unsigned i = 0; i < kAlignTableSize; i++) - newLevels[i] = (Byte)ReadBits(kNumBitsForAlignLevel); - RIF(m_AlignDecoder.SetCodeLengths(newLevels)); + levels[i] = (Byte)ReadBits(kNumAlignLevelBits); + RIF(_alignDecoder.Build(levels)); } } - RIF(ReadTable(m_LastMainLevels, newLevels, 256)); - RIF(ReadTable(m_LastMainLevels + 256, newLevels + 256, m_NumPosLenSlots)); - for (UInt32 i = 256 + m_NumPosLenSlots; i < kMainTableSize; i++) - newLevels[i] = 0; - RIF(m_MainDecoder.SetCodeLengths(newLevels)); - - RIF(ReadTable(m_LastLenLevels, newLevels, kNumLenSymbols)); - return m_LenDecoder.SetCodeLengths(newLevels); -} - -class CDecoderFlusher -{ - CDecoder *m_Decoder; -public: - bool NeedFlush; - CDecoderFlusher(CDecoder *decoder): m_Decoder(decoder), NeedFlush(true) {} - ~CDecoderFlusher() - { - if (NeedFlush) - m_Decoder->Flush(); - // m_Decoder->ReleaseStreams(); - } -}; - - -void CDecoder::ClearPrevLevels() -{ - unsigned i; - for (i = 0; i < kMainTableSize; i++) - m_LastMainLevels[i] = 0; - for (i = 0; i < kNumLenSymbols; i++) - m_LastLenLevels[i] = 0; + RIF(ReadTable(_mainLevels, 256)); + RIF(ReadTable(_mainLevels + 256, _numPosLenSlots)); + unsigned end = 256 + _numPosLenSlots; + memset(_mainLevels + end, 0, kMainTableSize - end); + RIF(_mainDecoder.Build(_mainLevels)); + RIF(ReadTable(_lenLevels, kNumLenSymbols)); + return _lenDecoder.Build(_lenLevels); } HRESULT CDecoder::CodeSpec(UInt32 curSize) { - if (_remainLen == kLenIdNeedInit) + if (!_keepHistory || !_isUncompressedBlock) + _bitStream.NormalizeBig(); + + if (!_keepHistory) { - _remainLen = 0; - m_InBitStream.Init(); - if (!_keepHistory || !m_IsUncompressedBlock) - m_InBitStream.Normalize(); - if (!_keepHistory) + _skipByte = false; + _unpackBlockSize = 0; + + memset(_mainLevels, 0, kMainTableSize); + memset(_lenLevels, 0, kNumLenSymbols); + { - _skipByte = false; - m_UnCompressedBlockSize = 0; - ClearPrevLevels(); - UInt32 i86TranslationSize = 12000000; - bool translationMode = true; + _x86_translationSize = 12000000; if (!_wimMode) { - translationMode = (ReadBits(1) != 0); - if (translationMode) + _x86_translationSize = 0; + if (ReadBits(1) != 0) { - i86TranslationSize = ReadBits(16) << 16; - i86TranslationSize |= ReadBits(16); + UInt32 v = ReadBits(16) << 16; + v |= ReadBits(16); + _x86_translationSize = v; } } - m_x86ConvertOutStreamSpec->Init(translationMode, i86TranslationSize); - for (unsigned i = 0 ; i < kNumRepDistances; i++) - m_RepDistances[i] = 0; + _x86_processedSize = 0; } - } - while (_remainLen > 0 && curSize > 0) - { - m_OutWindowStream.PutByte(m_OutWindowStream.GetByte(m_RepDistances[0])); - _remainLen--; - curSize--; + _reps[0] = 1; + _reps[1] = 1; + _reps[2] = 1; } while (curSize > 0) { - if (m_UnCompressedBlockSize == 0) + if (_bitStream.WasExtraReadError_Fast()) + return S_FALSE; + + if (_unpackBlockSize == 0) + { if (!ReadTables()) return S_FALSE; - UInt32 next = (Int32)MyMin(m_UnCompressedBlockSize, curSize); - curSize -= next; - m_UnCompressedBlockSize -= next; - if (m_IsUncompressedBlock) + continue; + } + + UInt32 next = _unpackBlockSize; + if (next > curSize) + next = curSize; + + if (_isUncompressedBlock) { - while (next > 0) + size_t rem = _bitStream.GetRem(); + if (rem == 0) + return S_FALSE; + if (next > rem) + next = (UInt32)rem; + _bitStream.CopyTo(_win + _pos, next); + _pos += next; + curSize -= next; + _unpackBlockSize -= next; + + /* we don't know where skipByte can be placed, if it's end of chunk: + 1) in current chunk - there are such cab archives, if chunk is last + 2) in next chunk - are there such archives ? */ + + if (_skipByte + && _unpackBlockSize == 0 + && curSize == 0 + && _bitStream.IsOneDirectByteLeft()) { - m_OutWindowStream.PutByte(m_InBitStream.DirectReadByte()); - next--; + _skipByte = false; + if (_bitStream.DirectReadByte() != 0) + return S_FALSE; } + + continue; } - else while (next > 0) + + curSize -= next; + _unpackBlockSize -= next; + + Byte *win = _win; + + while (next > 0) { - UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream); - if (number < 256) + if (_bitStream.WasExtraReadError_Fast()) + return S_FALSE; + + UInt32 sym = _mainDecoder.Decode(&_bitStream); + + if (sym < 256) { - m_OutWindowStream.PutByte((Byte)number); + win[_pos++] = (Byte)sym; next--; + continue; } - else { - UInt32 posLenSlot = number - 256; - if (posLenSlot >= m_NumPosLenSlots) + sym -= 256; + if (sym >= _numPosLenSlots) return S_FALSE; - UInt32 posSlot = posLenSlot / kNumLenSlots; - UInt32 lenSlot = posLenSlot % kNumLenSlots; + UInt32 posSlot = sym / kNumLenSlots; + UInt32 lenSlot = sym % kNumLenSlots; UInt32 len = kMatchMinLen + lenSlot; + if (lenSlot == kNumLenSlots - 1) { - UInt32 lenTemp = m_LenDecoder.DecodeSymbol(&m_InBitStream); + UInt32 lenTemp = _lenDecoder.Decode(&_bitStream); if (lenTemp >= kNumLenSymbols) return S_FALSE; - len += lenTemp; + len = kMatchMinLen + kNumLenSlots - 1 + lenTemp; } - if (posSlot < kNumRepDistances) + UInt32 dist; + + if (posSlot < kNumReps) { - UInt32 distance = m_RepDistances[posSlot]; - m_RepDistances[posSlot] = m_RepDistances[0]; - m_RepDistances[0] = distance; + dist = _reps[posSlot]; + _reps[posSlot] = _reps[0]; + _reps[0] = dist; } else { - UInt32 distance; unsigned numDirectBits; + if (posSlot < kNumPowerPosSlots) { numDirectBits = (unsigned)(posSlot >> 1) - 1; - distance = ((2 | (posSlot & 1)) << numDirectBits); + dist = ((2 | (posSlot & 1)) << numDirectBits); } else { numDirectBits = kNumLinearPosSlotBits; - distance = ((posSlot - 0x22) << kNumLinearPosSlotBits); + dist = ((posSlot - 0x22) << kNumLinearPosSlotBits); } - if (m_AlignIsUsed && numDirectBits >= kNumAlignBits) + if (numDirectBits >= _numAlignBits) { - distance += (m_InBitStream.ReadBits(numDirectBits - kNumAlignBits) << kNumAlignBits); - UInt32 alignTemp = m_AlignDecoder.DecodeSymbol(&m_InBitStream); + dist += (_bitStream.ReadBitsSmall(numDirectBits - kNumAlignBits) << kNumAlignBits); + UInt32 alignTemp = _alignDecoder.Decode(&_bitStream); if (alignTemp >= kAlignTableSize) return S_FALSE; - distance += alignTemp; + dist += alignTemp; } else - distance += m_InBitStream.ReadBits(numDirectBits); - m_RepDistances[2] = m_RepDistances[1]; - m_RepDistances[1] = m_RepDistances[0]; - m_RepDistances[0] = distance - kNumRepDistances; + dist += _bitStream.ReadBitsBig(numDirectBits); + + dist -= kNumReps - 1; + _reps[2] = _reps[1]; + _reps[1] = _reps[0]; + _reps[0] = dist; } - UInt32 locLen = len; - if (locLen > next) - locLen = next; + if (len > next) + return S_FALSE; - if (!m_OutWindowStream.CopyBlock(m_RepDistances[0], locLen)) + if (dist > _pos && !_overDict) return S_FALSE; - len -= locLen; - next -= locLen; - if (len != 0) + Byte *dest = win + _pos; + const UInt32 mask = (_winSize - 1); + UInt32 srcPos = (_pos - dist) & mask; + + next -= len; + + if (len > _winSize - srcPos) + { + _pos += len; + do + { + *dest++ = win[srcPos++]; + srcPos &= mask; + } + while (--len); + } + else { - _remainLen = (int)len; - return S_OK; + ptrdiff_t src = (ptrdiff_t)srcPos - (ptrdiff_t)_pos; + _pos += len; + const Byte *lim = dest + len; + *(dest) = *(dest + src); + dest++; + do + *(dest) = *(dest + src); + while (++dest != lim); } } } } + + if (!_bitStream.WasFinishedOK()) + return S_FALSE; + return S_OK; } -HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *, const UInt64 *outSize, ICompressProgressInfo *progress) + +HRESULT CDecoder::Code(const Byte *inData, size_t inSize, UInt32 outSize) { - if (outSize == NULL) - return E_INVALIDARG; - UInt64 size = *outSize; + if (_pos == _winSize) + { + _pos = 0; + _overDict = true; + } - // RINOK(SetInStream(inStream)); - m_InBitStream.SetStream(inStream); - m_x86ConvertOutStreamSpec->SetStream(outStream); - m_OutWindowStream.SetStream(m_x86ConvertOutStream); - RINOK(SetOutStreamSize(outSize)); + if (!_keepHistory) + { + _pos = 0; + _overDict = false; + } - CDecoderFlusher flusher(this); + _writePos = _pos; + _unpackedData = _win + _pos; + + if (outSize > _winSize - _pos) + return S_FALSE; - const UInt64 start = m_OutWindowStream.GetProcessedSize(); - for (;;) + PRF(printf("\ninSize = %d", inSize)); + if ((inSize & 1) != 0) { - UInt32 curSize = 1 << 18; - UInt64 rem = size - (m_OutWindowStream.GetProcessedSize() - start); - if (curSize > rem) - curSize = (UInt32)rem; - if (curSize == 0) - break; - RINOK(CodeSpec(curSize)); - if (progress != NULL) - { - UInt64 inSize = m_InBitStream.GetProcessedSize(); - UInt64 nowPos64 = m_OutWindowStream.GetProcessedSize() - start; - RINOK(progress->SetRatioInfo(&inSize, &nowPos64)); - } + PRF(printf(" ---------")); } - flusher.NeedFlush = false; - return Flush(); -} -HRESULT CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) -{ - try { return CodeReal(inStream, outStream, inSize, outSize, progress); } - catch(const CLzOutWindowException &e) { return e.ErrorCode; } - catch(...) { return S_FALSE; } -} + if (inSize < 1) + return S_FALSE; -/* -STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream) -{ - m_InStreamRef = inStream; - m_InBitStream.SetStream(inStream); - return S_OK; -} + _bitStream.Init(inData, inSize); -STDMETHODIMP CDecoder::ReleaseInStream() -{ - m_InStreamRef.Release(); - return S_OK; + HRESULT res = CodeSpec(outSize); + HRESULT res2 = Flush(); + return (res == S_OK ? res2 : res); } -*/ -STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize) + +HRESULT CDecoder::SetParams2(unsigned numDictBits) { - if (outSize == NULL) - return E_FAIL; - // flush calls m_x86ConvertOutStreamSpec->flush, so we must init x86Convert. - if (!_keepHistory) - m_x86ConvertOutStreamSpec->Init(false, 0); - _remainLen = kLenIdNeedInit; - m_OutWindowStream.Init(_keepHistory); + _numDictBits = numDictBits; + if (numDictBits < kNumDictBits_Min || numDictBits > kNumDictBits_Max) + return E_INVALIDARG; + unsigned numPosSlots = (numDictBits < 20) ? + numDictBits * 2 : + 34 + ((unsigned)1 << (numDictBits - 17)); + _numPosLenSlots = numPosSlots * kNumLenSlots; return S_OK; } + -HRESULT CDecoder::SetParams(unsigned numDictBits) +HRESULT CDecoder::SetParams_and_Alloc(unsigned numDictBits) { - if (numDictBits < kNumDictionaryBitsMin || numDictBits > kNumDictionaryBitsMax) - return E_INVALIDARG; - UInt32 numPosSlots; - if (numDictBits < 20) - numPosSlots = 30 + (numDictBits - 15) * 2; - else if (numDictBits == 20) - numPosSlots = 42; - else - numPosSlots = 50; - m_NumPosLenSlots = numPosSlots * kNumLenSlots; - if (!m_OutWindowStream.Create(kDictionarySizeMax)) - return E_OUTOFMEMORY; - if (!m_InBitStream.Create(1 << 16)) - return E_OUTOFMEMORY; + RINOK(SetParams2(numDictBits)); + + UInt32 newWinSize = (UInt32)1 << numDictBits; + + if (NeedAlloc) + { + if (!_win || newWinSize != _winSize) + { + ::MidFree(_win); + _winSize = 0; + _win = (Byte *)::MidAlloc(newWinSize); + if (!_win) + return E_OUTOFMEMORY; + } + } + + _winSize = (UInt32)newWinSize; return S_OK; } diff --git a/CPP/7zip/Compress/LzxDecoder.h b/CPP/7zip/Compress/LzxDecoder.h index 62d5b488..b06d5948 100644 --- a/CPP/7zip/Compress/LzxDecoder.h +++ b/CPP/7zip/Compress/LzxDecoder.h @@ -3,155 +3,240 @@ #ifndef __LZX_DECODER_H #define __LZX_DECODER_H -#include "../ICoder.h" +#include "../../../C/CpuArch.h" -#include "../Common/InBuffer.h" +#include "../../Common/MyCom.h" #include "HuffmanDecoder.h" -#include "LzOutWindow.h" #include "Lzx.h" -#include "Lzx86Converter.h" namespace NCompress { namespace NLzx { -namespace NBitStream { - -const unsigned kNumBigValueBits = 8 * 4; -const unsigned kNumValueBits = 17; -const UInt32 kBitDecoderValueMask = (1 << kNumValueBits) - 1; - -class CDecoder +class CBitDecoder { - CInBuffer _stream; - UInt32 _value; unsigned _bitPos; + UInt32 _value; + const Byte *_buf; + const Byte *_bufLim; + UInt32 _extraSize; public: - CDecoder() {} - bool Create(UInt32 bufSize) { return _stream.Create(bufSize); } - - void SetStream(ISequentialInStream *s) { _stream.SetStream(s); } - void Init() + void Init(const Byte *data, size_t size) { - _stream.Init(); - _bitPos = kNumBigValueBits; + _buf = data; + _bufLim = data + size - 1; + _bitPos = 0; + _extraSize = 0; } - UInt64 GetProcessedSize() const { return _stream.GetProcessedSize() - ((kNumBigValueBits - _bitPos) >> 3); } + size_t GetRem() const { return _bufLim + 1 - _buf; } + bool WasExtraReadError_Fast() const { return _extraSize > 4; } + + bool WasFinishedOK() const + { + if (_buf != _bufLim + 1) + return false; + if ((_bitPos >> 4) * 2 != _extraSize) + return false; + unsigned numBits = _bitPos & 15; + return (((_value >> (_bitPos - numBits)) & (((UInt32)1 << numBits) - 1)) == 0); + } - unsigned GetBitPosition() const { return _bitPos & 0xF; } + void NormalizeSmall() + { + if (_bitPos <= 16) + { + UInt32 val; + if (_buf >= _bufLim) + { + val = 0xFFFF; + _extraSize += 2; + } + else + { + val = GetUi16(_buf); + _buf += 2; + } + _value = (_value << 16) | val; + _bitPos += 16; + } + } - void Normalize() + void NormalizeBig() { - for (; _bitPos >= 16; _bitPos -= 16) + if (_bitPos <= 16) { - Byte b0 = _stream.ReadByte(); - Byte b1 = _stream.ReadByte(); - _value = (_value << 8) | b1; - _value = (_value << 8) | b0; + UInt32 val; + if (_buf >= _bufLim) + { + val = 0xFFFF; + _extraSize += 2; + } + else + { + val = GetUi16(_buf); + _buf += 2; + } + _value = (_value << 16) | val; + _bitPos += 16; + if (_bitPos <= 16) + { + UInt32 val; + if (_buf >= _bufLim) + { + val = 0xFFFF; + _extraSize += 2; + } + else + { + val = GetUi16(_buf); + _buf += 2; + } + _value = (_value << 16) | val; + _bitPos += 16; + } } } UInt32 GetValue(unsigned numBits) const { - return ((_value >> ((32 - kNumValueBits) - _bitPos)) & kBitDecoderValueMask) >> (kNumValueBits - numBits); + return (_value >> (_bitPos - numBits)) & (((UInt32)1 << numBits) - 1); } void MovePos(unsigned numBits) { - _bitPos += numBits; - Normalize(); + _bitPos -= numBits; + NormalizeSmall(); } - UInt32 ReadBits(unsigned numBits) + UInt32 ReadBitsSmall(unsigned numBits) { - UInt32 res = GetValue(numBits); - MovePos(numBits); - return res; + _bitPos -= numBits; + UInt32 val = (_value >> _bitPos) & (((UInt32)1 << numBits) - 1); + NormalizeSmall(); + return val; } UInt32 ReadBitsBig(unsigned numBits) { - unsigned numBits0 = numBits / 2; - unsigned numBits1 = numBits - numBits0; - UInt32 res = ReadBits(numBits0) << numBits1; - return res + ReadBits(numBits1); + _bitPos -= numBits; + UInt32 val = (_value >> _bitPos) & (((UInt32)1 << numBits) - 1); + NormalizeBig(); + return val; } - bool ReadUInt32(UInt32 &v) + bool PrepareUncompressed() { - if (_bitPos != 0) + if (_extraSize != 0) + return false; + unsigned numBits = _bitPos - 16; + if (((_value >> 16) & (((UInt32)1 << numBits) - 1)) != 0) return false; - v = ((_value >> 16) & 0xFFFF) | ((_value << 16) & 0xFFFF0000); - _bitPos = kNumBigValueBits; + _buf -= 2; + _bitPos = 0; return true; } - Byte DirectReadByte() { return _stream.ReadByte(); } + UInt32 ReadUInt32() + { + UInt32 v = GetUi32(_buf); + _buf += 4; + return v; + } + + void CopyTo(Byte *dest, size_t size) + { + memcpy(dest, _buf, size); + _buf += size; + } + bool IsOneDirectByteLeft() const { return _buf == _bufLim && _extraSize == 0; } + + Byte DirectReadByte() + { + if (_buf > _bufLim) + { + _extraSize++; + return 0xFF; + } + return *_buf++; + } }; -} -class CDecoder : - public ICompressCoder, + +class CDecoder: + public IUnknown, public CMyUnknownImp { - // CMyComPtr m_InStreamRef; - NBitStream::CDecoder m_InBitStream; - CLzOutWindow m_OutWindowStream; - - UInt32 m_RepDistances[kNumRepDistances]; - UInt32 m_NumPosLenSlots; + CBitDecoder _bitStream; + Byte *_win; + UInt32 _pos; + UInt32 _winSize; - bool m_IsUncompressedBlock; - bool m_AlignIsUsed; + bool _overDict; + bool _isUncompressedBlock; + bool _skipByte; + unsigned _numAlignBits; - NCompress::NHuffman::CDecoder m_MainDecoder; - NCompress::NHuffman::CDecoder m_LenDecoder; - NCompress::NHuffman::CDecoder m_AlignDecoder; - NCompress::NHuffman::CDecoder m_LevelDecoder; + UInt32 _reps[kNumReps]; + UInt32 _numPosLenSlots; + UInt32 _unpackBlockSize; - Byte m_LastMainLevels[kMainTableSize]; - Byte m_LastLenLevels[kNumLenSymbols]; +public: + bool KeepHistoryForNext; + bool NeedAlloc; +private: + bool _keepHistory; + bool _wimMode; + unsigned _numDictBits; + UInt32 _writePos; - Cx86ConvertOutStream *m_x86ConvertOutStreamSpec; - CMyComPtr m_x86ConvertOutStream; + Byte *_x86_buf; + UInt32 _x86_translationSize; + UInt32 _x86_processedSize; - UInt32 m_UnCompressedBlockSize; + Byte *_unpackedData; + + NHuffman::CDecoder _mainDecoder; + NHuffman::CDecoder _lenDecoder; + NHuffman::CDecoder7b _alignDecoder; + NHuffman::CDecoder _levelDecoder; - bool _keepHistory; - int _remainLen; - bool _skipByte; + Byte _mainLevels[kMainTableSize]; + Byte _lenLevels[kNumLenSymbols]; - bool _wimMode; + HRESULT Flush(); UInt32 ReadBits(unsigned numBits); - bool ReadTable(Byte *lastLevels, Byte *newLevels, UInt32 numSymbols); + bool ReadTable(Byte *levels, unsigned numSymbols); bool ReadTables(); - void ClearPrevLevels(); HRESULT CodeSpec(UInt32 size); - - HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); + HRESULT SetParams2(unsigned numDictBits); public: CDecoder(bool wimMode = false); + ~CDecoder(); MY_UNKNOWN_IMP - // void ReleaseStreams(); - STDMETHOD(Flush)(); + HRESULT SetExternalWindow(Byte *win, unsigned numDictBits) + { + NeedAlloc = false; + _win = win; + _winSize = (UInt32)1 << numDictBits; + return SetParams2(numDictBits); + } - STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); + void SetKeepHistory(bool keepHistory) { _keepHistory = keepHistory; } - // STDMETHOD(SetInStream)(ISequentialInStream *inStream); - // STDMETHOD(ReleaseInStream)(); - STDMETHOD(SetOutStreamSize)(const UInt64 *outSize); + HRESULT SetParams_and_Alloc(unsigned numDictBits); - HRESULT SetParams(unsigned numDictBits); - void SetKeepHistory(bool keepHistory) { _keepHistory = keepHistory; } + HRESULT Code(const Byte *inData, size_t inSize, UInt32 outSize); + + bool WasBlockFinished() const { return _unpackBlockSize == 0; } + const Byte *GetUnpackData() const { return _unpackedData; } + const UInt32 GetUnpackSize() const { return _pos - _writePos; } }; }} diff --git a/CPP/7zip/Compress/QuantumDecoder.cpp b/CPP/7zip/Compress/QuantumDecoder.cpp index b184dfb6..2adb9053 100644 --- a/CPP/7zip/Compress/QuantumDecoder.cpp +++ b/CPP/7zip/Compress/QuantumDecoder.cpp @@ -9,13 +9,81 @@ namespace NCompress { namespace NQuantum { -static const int kLenIdNeedInit = -2; - static const unsigned kNumLenSymbols = 27; static const unsigned kMatchMinLen = 3; static const unsigned kNumSimplePosSlots = 4; static const unsigned kNumSimpleLenSlots = 6; +static const UInt16 kUpdateStep = 8; +static const UInt16 kFreqSumMax = 3800; +static const unsigned kReorderCountStart = 4; +static const unsigned kReorderCount = 50; + +void CModelDecoder::Init(unsigned numItems) +{ + NumItems = numItems; + ReorderCount = kReorderCountStart; + for (unsigned i = 0; i < numItems; i++) + { + Freqs[i] = (UInt16)(numItems - i); + Vals[i] = (Byte)i; + } + Freqs[numItems] = 0; +} + +unsigned CModelDecoder::Decode(CRangeDecoder *rc) +{ + UInt32 threshold = rc->GetThreshold(Freqs[0]); + unsigned i; + for (i = 1; Freqs[i] > threshold; i++); + + rc->Decode(Freqs[i], Freqs[i - 1], Freqs[0]); + unsigned res = Vals[--i]; + + do + Freqs[i] += kUpdateStep; + while (i--); + + if (Freqs[0] > kFreqSumMax) + { + if (--ReorderCount == 0) + { + ReorderCount = kReorderCount; + for (i = 0; i < NumItems; i++) + Freqs[i] = (UInt16)(((Freqs[i] - Freqs[i + 1]) + 1) >> 1); + for (i = 0; i < NumItems - 1; i++) + for (unsigned j = i + 1; j < NumItems; j++) + if (Freqs[i] < Freqs[j]) + { + UInt16 tmpFreq = Freqs[i]; + Byte tmpVal = Vals[i]; + Freqs[i] = Freqs[j]; + Vals[i] = Vals[j]; + Freqs[j] = tmpFreq; + Vals[j] = tmpVal; + } + + do + Freqs[i] = (UInt16)(Freqs[i] + Freqs[i + 1]); + while (i--); + } + else + { + i = NumItems - 1; + do + { + Freqs[i] >>= 1; + if (Freqs[i] <= Freqs[i + 1]) + Freqs[i] = (UInt16)(Freqs[i + 1] + 1); + } + while (i--); + } + } + + return res; +} + + void CDecoder::Init() { m_Selector.Init(kNumSelectors); @@ -29,156 +97,97 @@ void CDecoder::Init() m_LenSlot.Init(kNumLenSymbols); } -HRESULT CDecoder::CodeSpec(UInt32 curSize) + +HRESULT CDecoder::CodeSpec(const Byte *inData, size_t inSize, UInt32 outSize) { - if (_remainLen == kLenIdNeedInit) - { - _rangeDecoder.Init(); - _remainLen = 0; - } - if (curSize == 0) - return S_OK; + if (inSize < 2) + return S_FALSE; - while (_remainLen > 0 && curSize > 0) - { - _remainLen--; - Byte b = _outWindowStream.GetByte(_rep0); - _outWindowStream.PutByte(b); - curSize--; - } + CRangeDecoder rc; + rc.Stream.SetStreamAndInit(inData, inSize); + rc.Init(); - while (curSize > 0) + while (outSize != 0) { - if (_rangeDecoder.Stream.WasFinished()) + if (rc.Stream.WasExtraRead()) return S_FALSE; - unsigned selector = m_Selector.Decode(&_rangeDecoder); + unsigned selector = m_Selector.Decode(&rc); + if (selector < kNumLitSelectors) { - Byte b = (Byte)((selector << (8 - kNumLitSelectorBits)) + m_Literals[selector].Decode(&_rangeDecoder)); - _outWindowStream.PutByte(b); - curSize--; + Byte b = (Byte)((selector << (8 - kNumLitSelectorBits)) + m_Literals[selector].Decode(&rc)); + _outWindow.PutByte(b); + outSize--; } else { selector -= kNumLitSelectors; unsigned len = selector + kMatchMinLen; + if (selector == 2) { - unsigned lenSlot = m_LenSlot.Decode(&_rangeDecoder); + unsigned lenSlot = m_LenSlot.Decode(&rc); if (lenSlot >= kNumSimpleLenSlots) { lenSlot -= 2; - int numDirectBits = (int)(lenSlot >> 2); + unsigned numDirectBits = (unsigned)(lenSlot >> 2); len += ((4 | (lenSlot & 3)) << numDirectBits) - 2; if (numDirectBits < 6) - len += _rangeDecoder.Stream.ReadBits(numDirectBits); + len += rc.Stream.ReadBits(numDirectBits); } else len += lenSlot; } - UInt32 rep0 = m_PosSlot[selector].Decode(&_rangeDecoder); - if (rep0 >= kNumSimplePosSlots) + + UInt32 dist = m_PosSlot[selector].Decode(&rc); + + if (dist >= kNumSimplePosSlots) { - int numDirectBits = (int)((rep0 >> 1) - 1); - rep0 = ((2 | (rep0 & 1)) << numDirectBits) + _rangeDecoder.Stream.ReadBits(numDirectBits); + unsigned numDirectBits = (unsigned)((dist >> 1) - 1); + dist = ((2 | (dist & 1)) << numDirectBits) + rc.Stream.ReadBits(numDirectBits); } + unsigned locLen = len; - if (len > curSize) - locLen = (unsigned)curSize; - if (!_outWindowStream.CopyBlock(rep0, locLen)) + if (len > outSize) + locLen = (unsigned)outSize; + if (!_outWindow.CopyBlock(dist, locLen)) return S_FALSE; - curSize -= locLen; + outSize -= locLen; len -= locLen; if (len != 0) - { - _remainLen = (int)len; - _rep0 = rep0; - break; - } + return S_FALSE; } } - return _rangeDecoder.Stream.WasFinished() ? S_FALSE : S_OK; + + return rc.Finish() ? S_OK : S_FALSE; } -HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *, const UInt64 *outSize, ICompressProgressInfo *progress) +HRESULT CDecoder::Code(const Byte *inData, size_t inSize, + ISequentialOutStream *outStream, UInt32 outSize, + bool keepHistory) { - if (outSize == NULL) - return E_INVALIDARG; - UInt64 size = *outSize; - - // SetInStream(inStream); - _rangeDecoder.SetStream(inStream); - - _outWindowStream.SetStream(outStream); - SetOutStreamSize(outSize); - CDecoderFlusher flusher(this); - - const UInt64 start = _outWindowStream.GetProcessedSize(); - for (;;) + try { - UInt32 curSize = 1 << 18; - UInt64 rem = size - (_outWindowStream.GetProcessedSize() - start); - if (curSize > rem) - curSize = (UInt32)rem; - if (curSize == 0) - break; - RINOK(CodeSpec(curSize)); - if (progress != NULL) - { - UInt64 inSize = _rangeDecoder.GetProcessedSize(); - UInt64 nowPos64 = _outWindowStream.GetProcessedSize() - start; - RINOK(progress->SetRatioInfo(&inSize, &nowPos64)); - } + _outWindow.SetStream(outStream); + _outWindow.Init(keepHistory); + if (!keepHistory) + Init(); + + HRESULT res = CodeSpec(inData, inSize, outSize); + HRESULT res2 = _outWindow.Flush(); + return res != S_OK ? res : res2; } - flusher.NeedFlush = false; - return Flush(); -} - -STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) -{ - try { return CodeReal(inStream, outStream, inSize, outSize, progress); } - catch(const CInBufferException &e) { return e.ErrorCode; } - catch(const CLzOutWindowException &e) { return e.ErrorCode; } + catch(const CLzOutWindowException &e) { return e.ErrorCode; } catch(...) { return S_FALSE; } } -/* -STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream) -{ - m_InStreamRef = inStream; - _rangeDecoder.SetStream(inStream); - return S_OK; -} - -STDMETHODIMP CDecoder::ReleaseInStream() -{ - m_InStreamRef.Release(); - return S_OK; -} -*/ - -STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize) -{ - if (outSize == NULL) - return E_FAIL; - _remainLen = kLenIdNeedInit; - _outWindowStream.Init(_keepHistory); - if (!_keepHistory) - Init(); - return S_OK; -} - -HRESULT CDecoder::SetParams(int numDictBits) +HRESULT CDecoder::SetParams(unsigned numDictBits) { if (numDictBits > 21) return E_INVALIDARG; _numDictBits = numDictBits; - if (!_outWindowStream.Create((UInt32)1 << _numDictBits)) - return E_OUTOFMEMORY; - if (!_rangeDecoder.Create(1 << 20)) + if (!_outWindow.Create((UInt32)1 << _numDictBits)) return E_OUTOFMEMORY; return S_OK; } diff --git a/CPP/7zip/Compress/QuantumDecoder.h b/CPP/7zip/Compress/QuantumDecoder.h index c18ea2aa..afeba708 100644 --- a/CPP/7zip/Compress/QuantumDecoder.h +++ b/CPP/7zip/Compress/QuantumDecoder.h @@ -5,92 +5,94 @@ #include "../../Common/MyCom.h" -#include "../ICoder.h" - -#include "../Common/InBuffer.h" - #include "LzOutWindow.h" namespace NCompress { namespace NQuantum { -class CStreamBitDecoder +class CBitDecoder { UInt32 Value; - CInBuffer Stream; + bool _extra; + const Byte *_buf; + const Byte *_bufLim; public: - bool Create(UInt32 bufferSize) { return Stream.Create(bufferSize); } - void SetStream(ISequentialInStream *stream) { Stream.SetStream(stream); } - // void ReleaseStream() { Stream.ReleaseStream(); } - - void Finish() { Value = 0x10000; } - - void Init() + void SetStreamAndInit(const Byte *inData, size_t inSize) { - Stream.Init(); + _buf = inData; + _bufLim = inData + inSize; Value = 0x10000; + _extra = false; } - UInt64 GetProcessedSize() const { return Stream.GetProcessedSize(); } - bool WasFinished() const { return Stream.WasFinished(); } + bool WasExtraRead() const { return _extra; } + + bool WasFinishedOK() const + { + return !_extra && _buf == _bufLim; + } UInt32 ReadBit() { if (Value >= 0x10000) - Value = 0x100 | Stream.ReadByte(); + { + Byte b; + if (_buf >= _bufLim) + { + b = 0xFF; + _extra = true; + } + else + b = *_buf++; + Value = 0x100 | b; + } UInt32 res = (Value >> 7) & 1; Value <<= 1; return res; } - UInt32 ReadBits(int numBits) // numBits > 0 + UInt32 ReadStart16Bits() + { + // we use check for extra read in another code. + UInt32 val = ((UInt32)*_buf << 8) | _buf[1]; + _buf += 2; + return val; + } + + UInt32 ReadBits(unsigned numBits) // numBits > 0 { UInt32 res = 0; do res = (res << 1) | ReadBit(); - while (--numBits != 0); + while (--numBits); return res; } }; -const unsigned kNumLitSelectorBits = 2; -const unsigned kNumLitSelectors = (1 << kNumLitSelectorBits); -const unsigned kNumLitSymbols = 1 << (8 - kNumLitSelectorBits); -const unsigned kNumMatchSelectors = 3; -const unsigned kNumSelectors = kNumLitSelectors + kNumMatchSelectors; -const unsigned kNumSymbolsMax = kNumLitSymbols; // 64 - -namespace NRangeCoder { -class CDecoder +class CRangeDecoder { UInt32 Low; UInt32 Range; UInt32 Code; public: - CStreamBitDecoder Stream; - bool Create(UInt32 bufferSize) { return Stream.Create(bufferSize); } - void SetStream(ISequentialInStream *stream) { Stream.SetStream(stream); } - // void ReleaseStream() { Stream.ReleaseStream(); } + CBitDecoder Stream; void Init() { - Stream.Init(); Low = 0; Range = 0x10000; - Code = Stream.ReadBits(16); + Code = Stream.ReadStart16Bits(); } - void Finish() + bool Finish() { - // we need these extra two Bit_reads - Stream.ReadBit(); - Stream.ReadBit(); - Stream.Finish(); + // do all streams use these two bits at end? + if (Stream.ReadBit() != 0) return false; + if (Stream.ReadBit() != 0) return false; + return Stream.WasFinishedOK(); } - UInt64 GetProcessedSize() const { return Stream.GetProcessedSize(); } - UInt32 GetThreshold(UInt32 total) const { return ((Code + 1) * total - 1) / Range; // & 0xFFFF is not required; @@ -119,148 +121,52 @@ public: } }; -const UInt16 kUpdateStep = 8; -const UInt16 kFreqSumMax = 3800; -const UInt16 kReorderCountStart = 4; -const UInt16 kReorderCount = 50; + +const unsigned kNumLitSelectorBits = 2; +const unsigned kNumLitSelectors = (1 << kNumLitSelectorBits); +const unsigned kNumLitSymbols = 1 << (8 - kNumLitSelectorBits); +const unsigned kNumMatchSelectors = 3; +const unsigned kNumSelectors = kNumLitSelectors + kNumMatchSelectors; +const unsigned kNumSymbolsMax = kNumLitSymbols; // 64 + class CModelDecoder { unsigned NumItems; unsigned ReorderCount; UInt16 Freqs[kNumSymbolsMax + 1]; - Byte Values[kNumSymbolsMax]; + Byte Vals[kNumSymbolsMax]; public: - void Init(unsigned numItems) - { - NumItems = numItems; - ReorderCount = kReorderCountStart; - for (unsigned i = 0; i < numItems; i++) - { - Freqs[i] = (UInt16)(numItems - i); - Values[i] = (Byte)i; - } - Freqs[numItems] = 0; - } - - unsigned Decode(CDecoder *rangeDecoder) - { - UInt32 threshold = rangeDecoder->GetThreshold(Freqs[0]); - unsigned i; - for (i = 1; Freqs[i] > threshold; i++); - rangeDecoder->Decode(Freqs[i], Freqs[i - 1], Freqs[0]); - unsigned res = Values[--i]; - do - Freqs[i] += kUpdateStep; - while (i-- != 0); - - if (Freqs[0] > kFreqSumMax) - { - if (--ReorderCount == 0) - { - ReorderCount = kReorderCount; - for (i = 0; i < NumItems; i++) - Freqs[i] = (UInt16)(((Freqs[i] - Freqs[i + 1]) + 1) >> 1); - for (i = 0; i < NumItems - 1; i++) - for (unsigned j = i + 1; j < NumItems; j++) - if (Freqs[i] < Freqs[j]) - { - UInt16 tmpFreq = Freqs[i]; - Byte tmpVal = Values[i]; - Freqs[i] = Freqs[j]; - Values[i] = Values[j]; - Freqs[j] = tmpFreq; - Values[j] = tmpVal; - } - do - Freqs[i] = (UInt16)(Freqs[i] + Freqs[i + 1]); - while (i-- != 0); - } - else - { - i = NumItems - 1; - do - { - Freqs[i] >>= 1; - if (Freqs[i] <= Freqs[i + 1]) - Freqs[i] = (UInt16)(Freqs[i + 1] + 1); - } - while (i-- != 0); - } - } - return res; - } + void Init(unsigned numItems); + unsigned Decode(CRangeDecoder *rc); }; -} class CDecoder: - public ICompressCoder, - // public ICompressSetInStream, - // public ICompressSetOutStreamSize, + public IUnknown, public CMyUnknownImp { - CLzOutWindow _outWindowStream; - // CMyComPtr m_InStreamRef; - NRangeCoder::CDecoder _rangeDecoder; + CLzOutWindow _outWindow; + unsigned _numDictBits; - UInt64 _outSize; - int _remainLen; // -1 means end of stream. // -2 means need Init - UInt32 _rep0; + CModelDecoder m_Selector; + CModelDecoder m_Literals[kNumLitSelectors]; + CModelDecoder m_PosSlot[kNumMatchSelectors]; + CModelDecoder m_LenSlot; - int _numDictBits; - bool _keepHistory; - - NRangeCoder::CModelDecoder m_Selector; - NRangeCoder::CModelDecoder m_Literals[kNumLitSelectors]; - NRangeCoder::CModelDecoder m_PosSlot[kNumMatchSelectors]; - NRangeCoder::CModelDecoder m_LenSlot; void Init(); - HRESULT CodeSpec(UInt32 size); + HRESULT CodeSpec(const Byte *inData, size_t inSize, UInt32 outSize); public: MY_UNKNOWN_IMP - /* - MY_UNKNOWN_IMP2( - ICompressSetInStream, - ICompressSetOutStreamSize) - void ReleaseStreams() - { - _outWindowStream.ReleaseStream(); - ReleaseInStream(); - } - */ - - class CDecoderFlusher - { - CDecoder *_decoder; - public: - bool NeedFlush; - CDecoderFlusher(CDecoder *decoder): _decoder(decoder), NeedFlush(true) {} - ~CDecoderFlusher() - { - if (NeedFlush) - _decoder->Flush(); - // _decoder->ReleaseStreams(); - } - }; + HRESULT Code(const Byte *inData, size_t inSize, + ISequentialOutStream *outStream, UInt32 outSize, + bool keepHistory); - HRESULT Flush() { return _outWindowStream.Flush(); } - - HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); + HRESULT SetParams(unsigned numDictBits); - STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); - - // STDMETHOD(SetInStream)(ISequentialInStream *inStream); - // STDMETHOD(ReleaseInStream)(); - STDMETHOD(SetOutStreamSize)(const UInt64 *outSize); - - HRESULT SetParams(int numDictBits); - void SetKeepHistory(bool keepHistory) { _keepHistory = keepHistory; } - CDecoder(): _keepHistory(false) {} + CDecoder(): _numDictBits(0) {} virtual ~CDecoder() {} }; diff --git a/CPP/7zip/Compress/Rar2Decoder.cpp b/CPP/7zip/Compress/Rar2Decoder.cpp index 5082ded3..4d1bd6b2 100644 --- a/CPP/7zip/Compress/Rar2Decoder.cpp +++ b/CPP/7zip/Compress/Rar2Decoder.cpp @@ -122,21 +122,21 @@ bool CDecoder::ReadTables(void) unsigned i; for (i = 0; i < kLevelTableSize; i++) levelLevels[i] = (Byte)ReadBits(4); - RIF(m_LevelDecoder.SetCodeLengths(levelLevels)); + RIF(m_LevelDecoder.Build(levelLevels)); i = 0; while (i < numLevels) { - UInt32 number = m_LevelDecoder.DecodeSymbol(&m_InBitStream); - if (number < kTableDirectLevels) + UInt32 sym = m_LevelDecoder.Decode(&m_InBitStream); + if (sym < kTableDirectLevels) { - newLevels[i] = (Byte)((number + m_LastLevels[i]) & kLevelMask); + newLevels[i] = (Byte)((sym + m_LastLevels[i]) & kLevelMask); i++; } else { - if (number == kTableLevelRepNumber) + if (sym == kTableLevelRepNumber) { unsigned t = ReadBits(2) + 3; for (unsigned reps = t; reps > 0 && i < numLevels; reps--, i++) @@ -145,9 +145,9 @@ bool CDecoder::ReadTables(void) else { unsigned num; - if (number == kTableLevel0Number) + if (sym == kTableLevel0Number) num = ReadBits(3) + 3; - else if (number == kTableLevel0Number2) + else if (sym == kTableLevel0Number2) num = ReadBits(7) + 11; else return false; @@ -160,13 +160,13 @@ bool CDecoder::ReadTables(void) if (m_AudioMode) for (i = 0; i < m_NumChannels; i++) { - RIF(m_MMDecoders[i].SetCodeLengths(&newLevels[i * kMMTableSize])); + RIF(m_MMDecoders[i].Build(&newLevels[i * kMMTableSize])); } else { - RIF(m_MainDecoder.SetCodeLengths(&newLevels[0])); - RIF(m_DistDecoder.SetCodeLengths(&newLevels[kMainTableSize])); - RIF(m_LenDecoder.SetCodeLengths(&newLevels[kMainTableSize + kDistTableSize])); + RIF(m_MainDecoder.Build(&newLevels[0])); + RIF(m_DistDecoder.Build(&newLevels[kMainTableSize])); + RIF(m_LenDecoder.Build(&newLevels[kMainTableSize + kDistTableSize])); } memcpy(m_LastLevels, newLevels, kMaxTableSize); @@ -182,7 +182,7 @@ bool CDecoder::ReadLastTables() // if (m_InBitStream.GetProcessedSize() + 2 <= m_PackSize) // test it: probably incorrect; if (m_AudioMode) { - UInt32 symbol = m_MMDecoders[m_MmFilter.CurrentChannel].DecodeSymbol(&m_InBitStream); + UInt32 symbol = m_MMDecoders[m_MmFilter.CurrentChannel].Decode(&m_InBitStream); if (symbol == 256) return ReadTables(); if (symbol >= kMMTableSize) @@ -190,10 +190,10 @@ bool CDecoder::ReadLastTables() } else { - UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream); - if (number == kReadTableNumber) + UInt32 sym = m_MainDecoder.Decode(&m_InBitStream); + if (sym == kReadTableNumber) return ReadTables(); - if (number >= kMainTableSize) + if (sym >= kMainTableSize) return false; } return true; @@ -216,7 +216,7 @@ bool CDecoder::DecodeMm(UInt32 pos) { while (pos-- > 0) { - UInt32 symbol = m_MMDecoders[m_MmFilter.CurrentChannel].DecodeSymbol(&m_InBitStream); + UInt32 symbol = m_MMDecoders[m_MmFilter.CurrentChannel].Decode(&m_InBitStream); if (symbol == 256) return true; if (symbol >= kMMTableSize) @@ -238,23 +238,23 @@ bool CDecoder::DecodeLz(Int32 pos) { while (pos > 0) { - UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream); + UInt32 sym = m_MainDecoder.Decode(&m_InBitStream); UInt32 length, distance; - if (number < 256) + if (sym < 256) { - m_OutWindowStream.PutByte(Byte(number)); + m_OutWindowStream.PutByte(Byte(sym)); pos--; continue; } - else if (number >= kMatchNumber) + else if (sym >= kMatchNumber) { - number -= kMatchNumber; - length = kNormalMatchMinLen + UInt32(kLenStart[number]) + - m_InBitStream.ReadBits(kLenDirectBits[number]); - number = m_DistDecoder.DecodeSymbol(&m_InBitStream); - if (number >= kDistTableSize) + sym -= kMatchNumber; + length = kNormalMatchMinLen + UInt32(kLenStart[sym]) + + m_InBitStream.ReadBits(kLenDirectBits[sym]); + sym = m_DistDecoder.Decode(&m_InBitStream); + if (sym >= kDistTableSize) return false; - distance = kDistStart[number] + m_InBitStream.ReadBits(kDistDirectBits[number]); + distance = kDistStart[sym] + m_InBitStream.ReadBits(kDistDirectBits[sym]); if (distance >= kDistLimit3) { length += 2 - ((distance - kDistLimit4) >> 31); @@ -263,20 +263,20 @@ bool CDecoder::DecodeLz(Int32 pos) // length++; } } - else if (number == kRepBothNumber) + else if (sym == kRepBothNumber) { length = m_LastLength; if (length == 0) return false; distance = m_RepDists[(m_RepDistPtr + 4 - 1) & 3]; } - else if (number < kLen2Number) + else if (sym < kLen2Number) { - distance = m_RepDists[(m_RepDistPtr - (number - kRepNumber + 1)) & 3]; - number = m_LenDecoder.DecodeSymbol(&m_InBitStream); - if (number >= kLenTableSize) + distance = m_RepDists[(m_RepDistPtr - (sym - kRepNumber + 1)) & 3]; + sym = m_LenDecoder.Decode(&m_InBitStream); + if (sym >= kLenTableSize) return false; - length = 2 + kLenStart[number] + m_InBitStream.ReadBits(kLenDirectBits[number]); + length = 2 + kLenStart[sym] + m_InBitStream.ReadBits(kLenDirectBits[sym]); if (distance >= kDistLimit2) { length++; @@ -289,14 +289,14 @@ bool CDecoder::DecodeLz(Int32 pos) } } } - else if (number < kReadTableNumber) + else if (sym < kReadTableNumber) { - number -= kLen2Number; - distance = kLen2DistStarts[number] + - m_InBitStream.ReadBits(kLen2DistDirectBits[number]); + sym -= kLen2Number; + distance = kLen2DistStarts[sym] + + m_InBitStream.ReadBits(kLen2DistDirectBits[sym]); length = 2; } - else if (number == kReadTableNumber) + else if (sym == kReadTableNumber) return true; else return false; diff --git a/CPP/7zip/Compress/Rar3Decoder.cpp b/CPP/7zip/Compress/Rar3Decoder.cpp index 81eb8285..496400a4 100644 --- a/CPP/7zip/Compress/Rar3Decoder.cpp +++ b/CPP/7zip/Compress/Rar3Decoder.cpp @@ -568,26 +568,26 @@ HRESULT CDecoder::ReadTables(bool &keepDecompressing) } levelLevels[i] = (Byte)length; } - RIF(m_LevelDecoder.SetCodeLengths(levelLevels)); + RIF(m_LevelDecoder.Build(levelLevels)); i = 0; while (i < kTablesSizesSum) { - UInt32 number = m_LevelDecoder.DecodeSymbol(&m_InBitStream.BitDecoder); - if (number < 16) + UInt32 sym = m_LevelDecoder.Decode(&m_InBitStream.BitDecoder); + if (sym < 16) { - newLevels[i] = Byte((number + m_LastLevels[i]) & 15); + newLevels[i] = Byte((sym + m_LastLevels[i]) & 15); i++; } - else if (number > kLevelTableSize) + else if (sym > kLevelTableSize) return S_FALSE; else { int num; - if (((number - 16) & 1) == 0) + if (((sym - 16) & 1) == 0) num = ReadBits(3) + 3; else num = ReadBits(7) + 11; - if (number < 18) + if (sym < 18) { if (i == 0) return S_FALSE; @@ -612,10 +612,10 @@ HRESULT CDecoder::ReadTables(bool &keepDecompressing) } */ - RIF(m_MainDecoder.SetCodeLengths(&newLevels[0])); - RIF(m_DistDecoder.SetCodeLengths(&newLevels[kMainTableSize])); - RIF(m_AlignDecoder.SetCodeLengths(&newLevels[kMainTableSize + kDistTableSize])); - RIF(m_LenDecoder.SetCodeLengths(&newLevels[kMainTableSize + kDistTableSize + kAlignTableSize])); + RIF(m_MainDecoder.Build(&newLevels[0])); + RIF(m_DistDecoder.Build(&newLevels[kMainTableSize])); + RIF(m_AlignDecoder.Build(&newLevels[kMainTableSize + kDistTableSize])); + RIF(m_LenDecoder.Build(&newLevels[kMainTableSize + kDistTableSize + kAlignTableSize])); memcpy(m_LastLevels, newLevels, kTablesSizesSum); return S_OK; @@ -687,38 +687,38 @@ HRESULT CDecoder::DecodeLZ(bool &keepDecompressing) if (InputEofError_Fast()) return S_FALSE; - UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream.BitDecoder); - if (number < 256) + UInt32 sym = m_MainDecoder.Decode(&m_InBitStream.BitDecoder); + if (sym < 256) { - PutByte((Byte)number); + PutByte((Byte)sym); continue; } - else if (number == kSymbolReadTable) + else if (sym == kSymbolReadTable) { RINOK(ReadEndOfBlock(keepDecompressing)); break; } - else if (number == 257) + else if (sym == 257) { if (!ReadVmCodeLZ()) return S_FALSE; continue; } - else if (number == 258) + else if (sym == 258) { if (length == 0) return S_FALSE; } - else if (number < kSymbolRep + 4) + else if (sym < kSymbolRep + 4) { - if (number != kSymbolRep) + if (sym != kSymbolRep) { UInt32 distance; - if (number == kSymbolRep + 1) + if (sym == kSymbolRep + 1) distance = rep1; else { - if (number == kSymbolRep + 2) + if (sym == kSymbolRep + 2) distance = rep2; else { @@ -731,32 +731,32 @@ HRESULT CDecoder::DecodeLZ(bool &keepDecompressing) rep0 = distance; } - UInt32 number = m_LenDecoder.DecodeSymbol(&m_InBitStream.BitDecoder); - if (number >= kLenTableSize) + UInt32 sym = m_LenDecoder.Decode(&m_InBitStream.BitDecoder); + if (sym >= kLenTableSize) return S_FALSE; - length = 2 + kLenStart[number] + m_InBitStream.BitDecoder.ReadBits(kLenDirectBits[number]); + length = 2 + kLenStart[sym] + m_InBitStream.BitDecoder.ReadBits(kLenDirectBits[sym]); } else { rep3 = rep2; rep2 = rep1; rep1 = rep0; - if (number < 271) + if (sym < 271) { - number -= 263; - rep0 = kLen2DistStarts[number] + m_InBitStream.BitDecoder.ReadBits(kLen2DistDirectBits[number]); + sym -= 263; + rep0 = kLen2DistStarts[sym] + m_InBitStream.BitDecoder.ReadBits(kLen2DistDirectBits[sym]); length = 2; } - else if (number < 299) + else if (sym < 299) { - number -= 271; - length = kNormalMatchMinLen + (UInt32)kLenStart[number] + m_InBitStream.BitDecoder.ReadBits(kLenDirectBits[number]); - UInt32 number = m_DistDecoder.DecodeSymbol(&m_InBitStream.BitDecoder); - if (number >= kDistTableSize) + sym -= 271; + length = kNormalMatchMinLen + (UInt32)kLenStart[sym] + m_InBitStream.BitDecoder.ReadBits(kLenDirectBits[sym]); + UInt32 sym = m_DistDecoder.Decode(&m_InBitStream.BitDecoder); + if (sym >= kDistTableSize) return S_FALSE; - rep0 = kDistStart[number]; - int numBits = kDistDirectBits[number]; - if (number >= (kNumAlignBits * 2) + 2) + rep0 = kDistStart[sym]; + int numBits = kDistDirectBits[sym]; + if (sym >= (kNumAlignBits * 2) + 2) { if (numBits > kNumAlignBits) rep0 += (m_InBitStream.BitDecoder.ReadBits(numBits - kNumAlignBits) << kNumAlignBits); @@ -767,13 +767,13 @@ HRESULT CDecoder::DecodeLZ(bool &keepDecompressing) } else { - UInt32 number = m_AlignDecoder.DecodeSymbol(&m_InBitStream.BitDecoder); - if (number < (1 << kNumAlignBits)) + UInt32 sym = m_AlignDecoder.Decode(&m_InBitStream.BitDecoder); + if (sym < (1 << kNumAlignBits)) { - rep0 += number; - PrevAlignBits = number; + rep0 += sym; + PrevAlignBits = sym; } - else if (number == (1 << kNumAlignBits)) + else if (sym == (1 << kNumAlignBits)) { PrevAlignCount = kNumAlignReps; rep0 += PrevAlignBits; diff --git a/CPP/7zip/Compress/Rar5Decoder.cpp b/CPP/7zip/Compress/Rar5Decoder.cpp index 9e3ff3e4..19b40f39 100644 --- a/CPP/7zip/Compress/Rar5Decoder.cpp +++ b/CPP/7zip/Compress/Rar5Decoder.cpp @@ -304,6 +304,7 @@ HRESULT CDecoder::AddFilter(CBitDecoder &_bitStream) // if (f.Size > ((UInt32)1 << 16)) _unsupportedFilter = true; f.Type = (Byte)_bitStream.ReadBits9fix(3); + f.Channels = 0; if (f.Type == FILTER_DELTA) f.Channels = (Byte)(_bitStream.ReadBits9fix(5) + 1); f.Start = _lzSize + blockStart; @@ -408,7 +409,7 @@ HRESULT CDecoder::ReadTables(CBitDecoder &_bitStream) if (_bitStream.IsBlockOverRead()) return S_FALSE; - RIF(m_LevelDecoder.SetCodeLengths(lens2)); + RIF(m_LevelDecoder.Build(lens2)); } Byte lens[kTablesSizesSum]; @@ -424,7 +425,7 @@ HRESULT CDecoder::ReadTables(CBitDecoder &_bitStream) return S_FALSE; } - UInt32 sym = m_LevelDecoder.DecodeSymbol(&_bitStream); + UInt32 sym = m_LevelDecoder.Decode(&_bitStream); if (sym < 16) lens[i++] = (Byte)sym; @@ -466,10 +467,10 @@ HRESULT CDecoder::ReadTables(CBitDecoder &_bitStream) if (_bitStream.InputEofError()) return S_FALSE; - RIF(m_MainDecoder.SetCodeLengths(&lens[0])); - RIF(m_DistDecoder.SetCodeLengths(&lens[kMainTableSize])); - RIF(m_AlignDecoder.SetCodeLengths(&lens[kMainTableSize + kDistTableSize])); - RIF(m_LenDecoder.SetCodeLengths(&lens[kMainTableSize + kDistTableSize + kAlignTableSize])); + RIF(m_MainDecoder.Build(&lens[0])); + RIF(m_DistDecoder.Build(&lens[kMainTableSize])); + RIF(m_AlignDecoder.Build(&lens[kMainTableSize + kDistTableSize])); + RIF(m_LenDecoder.Build(&lens[kMainTableSize + kDistTableSize + kAlignTableSize])); _useAlignBits = false; // _useAlignBits = true; @@ -601,7 +602,7 @@ HRESULT CDecoder::DecodeLZ() } } - UInt32 sym = m_MainDecoder.DecodeSymbol(&_bitStream); + UInt32 sym = m_MainDecoder.Decode(&_bitStream); if (sym < 256) { @@ -638,7 +639,7 @@ HRESULT CDecoder::DecodeLZ() rep0 = dist; } - UInt32 sym = m_LenDecoder.DecodeSymbol(&_bitStream); + UInt32 sym = m_LenDecoder.Decode(&_bitStream); if (sym >= kLenTableSize) break; // return S_FALSE; len = SlotToLen(_bitStream, sym); @@ -669,7 +670,7 @@ HRESULT CDecoder::DecodeLZ() _reps[1] = rep0; len = SlotToLen(_bitStream, sym - (kSymbolRep + kNumReps)); - rep0 = m_DistDecoder.DecodeSymbol(&_bitStream); + rep0 = m_DistDecoder.Decode(&_bitStream); if (rep0 >= 4) { @@ -690,7 +691,7 @@ HRESULT CDecoder::DecodeLZ() { // if (numBits > kNumAlignBits) rep0 += (_bitStream.ReadBits32(numBits - kNumAlignBits) << kNumAlignBits); - UInt32 a = m_AlignDecoder.DecodeSymbol(&_bitStream); + UInt32 a = m_AlignDecoder.Decode(&_bitStream); if (a >= kAlignTableSize) break; // return S_FALSE; rep0 += a; diff --git a/CPP/7zip/Compress/XpressDecoder.cpp b/CPP/7zip/Compress/XpressDecoder.cpp new file mode 100644 index 00000000..a4d45335 --- /dev/null +++ b/CPP/7zip/Compress/XpressDecoder.cpp @@ -0,0 +1,129 @@ +// XpressDecoder.cpp + +#include "StdAfx.h" + +// #include + +#include "../../../C/CpuArch.h" + +#include "HuffmanDecoder.h" + +namespace NCompress { +namespace NXpress { + +struct CBitStream +{ + UInt32 Value; + unsigned BitPos; + + UInt32 GetValue(unsigned numBits) const + { + return (Value >> (BitPos - numBits)) & ((1 << numBits) - 1); + } + + void MovePos(unsigned numBits) + { + BitPos -= numBits; + } +}; + +#define BIT_STREAM_NORMALIZE \ + if (bs.BitPos < 16) { \ + if (in >= lim) return S_FALSE; \ + bs.Value = (bs.Value << 16) | GetUi16(in); \ + in += 2; bs.BitPos += 16; } + +const unsigned kNumHuffBits = 15; +const unsigned kNumLenSlots = 16; +const unsigned kNumPosSlots = 16; +const unsigned kNumSyms = 256 + kNumPosSlots * kNumLenSlots; + +HRESULT Decode(const Byte *in, size_t inSize, Byte *out, size_t outSize) +{ + NCompress::NHuffman::CDecoder huff; + + if (inSize < kNumSyms / 2 + 4) + return S_FALSE; + { + Byte levels[kNumSyms]; + for (unsigned i = 0; i < kNumSyms / 2; i++) + { + Byte b = in[i]; + levels[i * 2] = (Byte)(b & 0xF); + levels[i * 2 + 1] = (Byte)(b >> 4); + } + if (!huff.BuildFull(levels)) + return S_FALSE; + } + + + CBitStream bs; + + const Byte *lim = in + inSize - 1; + + in += kNumSyms / 2; + bs.Value = (GetUi16(in) << 16) | GetUi16(in + 2); + in += 4; + bs.BitPos = 32; + + size_t pos = 0; + + for (;;) + { + // printf("\n%d", pos); + UInt32 sym = huff.DecodeFull(&bs); + // printf(" sym = %d", sym); + BIT_STREAM_NORMALIZE + + if (pos >= outSize) + return (sym == 256 && in == lim + 1) ? S_OK : S_FALSE; + + if (sym < 256) + out[pos++] = (Byte)sym; + else + { + sym -= 256; + UInt32 dist = sym / kNumLenSlots; + UInt32 len = sym & (kNumLenSlots - 1); + + if (len == kNumLenSlots - 1) + { + if (in > lim) + return S_FALSE; + len = *in++; + if (len == 0xFF) + { + if (in >= lim) + return S_FALSE; + len = GetUi16(in); + in += 2; + } + else + len += kNumLenSlots - 1; + } + + bs.BitPos -= dist; + dist = (UInt32)1 << dist; + dist += ((bs.Value >> bs.BitPos) & (dist - 1)); + + BIT_STREAM_NORMALIZE + + if (len > outSize - pos) + return S_FALSE; + if (dist > pos) + return S_FALSE; + + Byte *dest = out + pos; + const Byte *src = dest - dist; + pos += len + 3; + len += 1; + *dest++ = *src++; + *dest++ = *src++; + do + *dest++ = *src++; + while (--len); + } + } +} + +}} diff --git a/CPP/7zip/Compress/XpressDecoder.h b/CPP/7zip/Compress/XpressDecoder.h new file mode 100644 index 00000000..cada85bf --- /dev/null +++ b/CPP/7zip/Compress/XpressDecoder.h @@ -0,0 +1,13 @@ +// XpressDecoder.h + +#ifndef __XPRESS_DECODER_H +#define __XPRESS_DECODER_H + +namespace NCompress { +namespace NXpress { + +HRESULT Decode(const Byte *in, size_t inSize, Byte *out, size_t outSize); + +}} + +#endif diff --git a/CPP/7zip/Guid.txt b/CPP/7zip/Guid.txt index 1ab1b7a2..02bcdea3 100644 --- a/CPP/7zip/Guid.txt +++ b/CPP/7zip/Guid.txt @@ -163,6 +163,10 @@ Handler GUIDs: 0C xz 0D ppmd + C8 VMDK + C9 VDI + CA Qcow + CB GPT CC Rar5 CD IHex CE Hxs diff --git a/CPP/7zip/UI/Agent/Agent.cpp b/CPP/7zip/UI/Agent/Agent.cpp index 557282eb..201e82c1 100644 --- a/CPP/7zip/UI/Agent/Agent.cpp +++ b/CPP/7zip/UI/Agent/Agent.cpp @@ -1465,6 +1465,9 @@ STDMETHODIMP CAgentFolder::Extract(const UInt32 *indices, extractCallbackSpec->InitForMulti(false, pathMode, overwriteMode); + if (extractCallback2) + extractCallback2->SetTotal(_agentSpec->GetArc().GetEstmatedPhySize()); + FString pathU; if (path) { diff --git a/CPP/7zip/UI/Agent/Agent.h b/CPP/7zip/UI/Agent/Agent.h index 2c505b84..9d70c7a1 100644 --- a/CPP/7zip/UI/Agent/Agent.h +++ b/CPP/7zip/UI/Agent/Agent.h @@ -251,7 +251,9 @@ public: FOR_VECTOR (i, _archiveLink.Arcs) { const CArc &arc = _archiveLink.Arcs[i]; - if (!g_CodecsObj->Formats[arc.FormatIndex].UpdateEnabled || arc.IsReadOnly) + if (arc.FormatIndex < 0 + || arc.IsReadOnly + || !g_CodecsObj->Formats[arc.FormatIndex].UpdateEnabled) return true; } return false; @@ -274,9 +276,14 @@ public: UString s2; if (arc.ErrorInfo.ErrorFormatIndex >= 0) { - s2.AddAscii("Can not open the file as ["); - s2 += g_CodecsObj->Formats[arc.ErrorInfo.ErrorFormatIndex].Name; - s2.AddAscii("] archive"); + if (arc.ErrorInfo.ErrorFormatIndex == arc.FormatIndex) + s2.AddAscii("Warning: The archive is open with offset"); + else + { + s2.AddAscii("Can not open the file as ["); + s2 += g_CodecsObj->GetFormatNamePtr(arc.ErrorInfo.ErrorFormatIndex); + s2.AddAscii("] archive"); + } } if (!arc.ErrorInfo.ErrorMessage.IsEmpty()) @@ -288,6 +295,7 @@ public: s2.AddAscii("]: "); s2 += arc.ErrorInfo.ErrorMessage; } + if (!s2.IsEmpty()) { if (!s.IsEmpty()) diff --git a/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp b/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp index 8e4936a9..040f9b41 100644 --- a/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp +++ b/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp @@ -216,10 +216,9 @@ void CArchiveExtractCallback::Init( // _progressTotal = 0; // _progressTotal_Defined = false; - _progressTotal = _packTotal; - _progressTotal_Defined = true; - _packTotal = packSize; + _progressTotal = packSize; + _progressTotal_Defined = true; _extractCallback2 = extractCallback2; _compressProgress.Release(); @@ -962,7 +961,12 @@ if (askExtractMode == NArchive::NExtract::NAskMode::kExtract && !_testMode) bool isAnti = false; RINOK(_arc->IsItemAnti(index, isAnti)); - Correct_FsPath(_pathMode == NExtract::NPathMode::kAbsPaths, pathParts, _item.MainIsDir); + #ifdef SUPPORT_ALT_STREAMS + if (!_item.IsAltStream + || !pathParts.IsEmpty() + || !(_removePartsForAltStreams || _pathMode == NExtract::NPathMode::kNoPathsAlt)) + #endif + Correct_FsPath(_pathMode == NExtract::NPathMode::kAbsPaths, pathParts, _item.MainIsDir); #ifdef SUPPORT_ALT_STREAMS @@ -970,12 +974,18 @@ if (askExtractMode == NArchive::NExtract::NAskMode::kExtract && !_testMode) { UString s = _item.AltStreamName; Correct_AltStream_Name(s); - bool needColon = ((!_removePartsForAltStreams && _pathMode != NExtract::NPathMode::kNoPathsAlt) || !pathParts.IsEmpty()); + bool needColon = true; + if (pathParts.IsEmpty()) + { pathParts.AddNew(); - if (_pathMode == NExtract::NPathMode::kAbsPaths && + if (_removePartsForAltStreams || _pathMode == NExtract::NPathMode::kNoPathsAlt) + needColon = false; + } + else if (_pathMode == NExtract::NPathMode::kAbsPaths && NWildcard::GetNumPrefixParts_if_DrivePath(pathParts) == pathParts.Size()) pathParts.AddNew(); + UString &name = pathParts.Back(); if (needColon) name += (wchar_t)(_ntOptions.ReplaceColonForAltStream ? L'_' : L':'); diff --git a/CPP/7zip/UI/Common/ExtractingFilePath.cpp b/CPP/7zip/UI/Common/ExtractingFilePath.cpp index 5ba14045..7e088cfe 100644 --- a/CPP/7zip/UI/Common/ExtractingFilePath.cpp +++ b/CPP/7zip/UI/Common/ExtractingFilePath.cpp @@ -17,7 +17,9 @@ static void ReplaceIncorrectChars(UString &s) if ( #ifdef _WIN32 c == ':' || c == '*' || c == '?' || c < 0x20 || c == '<' || c == '>' || c == '|' || c == '"' - || c == '/' || + || c == '/' + || c == 0x202E // RLO + || #endif c == WCHAR_PATH_SEPARATOR) s.ReplaceOneCharAtPos(i, '_'); @@ -53,7 +55,9 @@ void Correct_AltStream_Name(UString &s) for (unsigned i = 0; i < len; i++) { wchar_t c = s[i]; - if (c == ':' || c == '\\' || c == '/') + if (c == ':' || c == '\\' || c == '/' + || c == 0x202E // RLO + ) s.ReplaceOneCharAtPos(i, '_'); } if (s.IsEmpty()) diff --git a/CPP/7zip/UI/Common/OpenArchive.h b/CPP/7zip/UI/Common/OpenArchive.h index c62bf826..10514ec4 100644 --- a/CPP/7zip/UI/Common/OpenArchive.h +++ b/CPP/7zip/UI/Common/OpenArchive.h @@ -299,6 +299,8 @@ public: UInt64 AvailPhySize; // PhySize, but it's reduced if exceed end of file // bool offsetDefined; + UInt64 GetEstmatedPhySize() const { return PhySizeDefined ? PhySize : FileSize; } + UInt64 ArcStreamOffset; // offset of stream that is open by Archive Handler Int64 GetGlobalOffset() const { return ArcStreamOffset + Offset; } // it's global offset of archive diff --git a/CPP/7zip/UI/Console/Main.cpp b/CPP/7zip/UI/Console/Main.cpp index b9cb4eb9..b07b1dc6 100644 --- a/CPP/7zip/UI/Console/Main.cpp +++ b/CPP/7zip/UI/Console/Main.cpp @@ -847,7 +847,7 @@ int Main2( #endif ecs->Init(g_StdStream, g_ErrStream, percentsStream); - ecs->MutiArcMode = (ArchivePathsSorted.Size() > 1); + ecs->MultiArcMode = (ArchivePathsSorted.Size() > 1); ecs->LogLevel = options.LogLevel; ecs->PercentsNameLevel = percentsNameLevel; diff --git a/CPP/7zip/UI/Console/OpenCallbackConsole.cpp b/CPP/7zip/UI/Console/OpenCallbackConsole.cpp index 5b2377be..9d25a729 100644 --- a/CPP/7zip/UI/Console/OpenCallbackConsole.cpp +++ b/CPP/7zip/UI/Console/OpenCallbackConsole.cpp @@ -19,7 +19,7 @@ HRESULT COpenCallbackConsole::Open_CheckBreak() HRESULT COpenCallbackConsole::Open_SetTotal(const UInt64 *files, const UInt64 *bytes) { - if (!MutiArcMode && NeedPercents()) + if (!MultiArcMode && NeedPercents()) { if (files) { @@ -46,7 +46,7 @@ HRESULT COpenCallbackConsole::Open_SetTotal(const UInt64 *files, const UInt64 *b HRESULT COpenCallbackConsole::Open_SetCompleted(const UInt64 *files, const UInt64 *bytes) { - if (!MutiArcMode && NeedPercents()) + if (!MultiArcMode && NeedPercents()) { if (files) { diff --git a/CPP/7zip/UI/Console/OpenCallbackConsole.h b/CPP/7zip/UI/Console/OpenCallbackConsole.h index 66d1fafa..0dd4e1d1 100644 --- a/CPP/7zip/UI/Console/OpenCallbackConsole.h +++ b/CPP/7zip/UI/Console/OpenCallbackConsole.h @@ -26,7 +26,7 @@ protected: public: - bool MutiArcMode; + bool MultiArcMode; void ClosePercents() { @@ -37,7 +37,7 @@ public: COpenCallbackConsole(): _totalFilesDefined(false), _totalBytesDefined(false), - MutiArcMode(false) + MultiArcMode(false) #ifndef _NO_CRYPTO , PasswordIsDefined(false) diff --git a/CPP/7zip/UI/Far/Far.cpp b/CPP/7zip/UI/Far/Far.cpp index d5656e29..0cd53cc5 100644 --- a/CPP/7zip/UI/Far/Far.cpp +++ b/CPP/7zip/UI/Far/Far.cpp @@ -373,18 +373,21 @@ static HANDLE MyOpenFilePluginW(const wchar_t *name) HRESULT result = ::OpenArchive(fullName, &archiveHandler, archiverInfoResult, defaultName, openArchiveCallback); */ + if (result == E_ABORT) + return (HANDLE)-2; + + UString errorMessage = agent->GetErrorMessage(); + if (!errorMessage.IsEmpty()) + g_StartupInfo.ShowErrorMessage(UnicodeStringToMultiByte(errorMessage, CP_OEMCP)); + if (result != S_OK) { - if (result == E_ABORT) - return (HANDLE)-2; + if (result == S_FALSE) + return INVALID_HANDLE_VALUE; ShowSysErrorMessage(result); return INVALID_HANDLE_VALUE; } - UString errorMessage = agent->GetErrorMessage(); - if (!errorMessage.IsEmpty()) - g_StartupInfo.ShowErrorMessage(UnicodeStringToMultiByte(errorMessage, CP_OEMCP)); - // ::OutputDebugStringA("after OpenArchive\n"); CPlugin *plugin = new CPlugin( diff --git a/CPP/7zip/UI/Far/FarUtils.cpp b/CPP/7zip/UI/Far/FarUtils.cpp index 28a4ada9..1875a189 100644 --- a/CPP/7zip/UI/Far/FarUtils.cpp +++ b/CPP/7zip/UI/Far/FarUtils.cpp @@ -68,6 +68,7 @@ void CStartupInfo::SetErrorTitle(AString &s) s += GetMsgString(NMessageID::kError); } +/* int CStartupInfo::ShowErrorMessage(const char *message) { AString s; @@ -75,6 +76,7 @@ int CStartupInfo::ShowErrorMessage(const char *message) const char *items[]= { s, message }; return ShowWarningWithOk(items, ARRAY_SIZE(items)); } +*/ int CStartupInfo::ShowErrorMessage2(const char *m1, const char *m2) { @@ -84,48 +86,45 @@ int CStartupInfo::ShowErrorMessage2(const char *m1, const char *m2) return ShowWarningWithOk(items, ARRAY_SIZE(items)); } -/* -static void SplitString(const AString &srcString, AStringVector &destStrings) +static void SplitString(const AString &src, AStringVector &destStrings) { destStrings.Clear(); - AString string; - unsigned len = srcString.Len(); + AString s; + unsigned len = src.Len(); if (len == 0) return; for (unsigned i = 0; i < len; i++) { - char c = srcString[i]; + char c = src[i]; if (c == '\n') { - if (!string.IsEmpty()) + if (!s.IsEmpty()) { - destStrings.Add(string); - string.Empty(); + destStrings.Add(s); + s.Empty(); } } else - string += c; + s += c; } - if (!string.IsEmpty()) - destStrings.Add(string); + if (!s.IsEmpty()) + destStrings.Add(s); } -*/ -/* -int CStartupInfo::ShowMessageLines(const char *message) +int CStartupInfo::ShowErrorMessage(const char *message) { AStringVector strings; SplitString(message, strings); const unsigned kNumStringsMax = 20; - const char *items[kNumStringsMax + 1] = { GetMsgString(NMessageID::kError) }; - unsigned pos = 1; + const char *items[kNumStringsMax + 1]; + unsigned pos = 0; + items[pos++] = GetMsgString(NMessageID::kError); for (unsigned i = 0; i < strings.Size() && pos < kNumStringsMax; i++) items[pos++] = strings[i]; items[pos++] = GetMsgString(NMessageID::kOk); return ShowMessage(FMSG_WARNING, NULL, items, pos, 1); } -*/ /* int CStartupInfo::ShowMessageLines(const char *message) diff --git a/CPP/7zip/UI/FileManager/App.h b/CPP/7zip/UI/FileManager/App.h index 5fe95e0b..190864cb 100644 --- a/CPP/7zip/UI/FileManager/App.h +++ b/CPP/7zip/UI/FileManager/App.h @@ -188,7 +188,7 @@ public: // File Menu void OpenItem() { GetFocusedPanel().OpenSelectedItems(true); } - void OpenItemInside() { GetFocusedPanel().OpenFocusedItemAsInternal(); } + void OpenItemInside(const wchar_t *type) { GetFocusedPanel().OpenFocusedItemAsInternal(type); } void OpenItemOutside() { GetFocusedPanel().OpenSelectedItems(false); } void EditItem(bool useEditor) { GetFocusedPanel().EditItem(useEditor); } void Rename() { GetFocusedPanel().RenameFile(); } diff --git a/CPP/7zip/UI/FileManager/ExtractCallback.cpp b/CPP/7zip/UI/FileManager/ExtractCallback.cpp index 50c43163..7d61d14d 100644 --- a/CPP/7zip/UI/FileManager/ExtractCallback.cpp +++ b/CPP/7zip/UI/FileManager/ExtractCallback.cpp @@ -91,15 +91,45 @@ HRESULT CExtractCallbackImp::Open_CheckBreak() return ProgressDialog->Sync.CheckStop(); } -HRESULT CExtractCallbackImp::Open_SetTotal(const UInt64 * /* numFiles */, const UInt64 * /* numBytes */) +HRESULT CExtractCallbackImp::Open_SetTotal(const UInt64 *files, const UInt64 *bytes) { - // if (numFiles != NULL) ProgressDialog->Sync.SetNumFilesTotal(*numFiles); - return S_OK; + HRESULT res = S_OK; + if (!MultiArcMode) + { + if (files) + { + _totalFilesDefined = true; + // res = ProgressDialog->Sync.Set_NumFilesTotal(*files); + } + else + _totalFilesDefined = false; + + if (bytes) + { + _totalBytesDefined = true; + ProgressDialog->Sync.Set_NumBytesTotal(*bytes); + } + else + _totalBytesDefined = false; + } + + return res; } -HRESULT CExtractCallbackImp::Open_SetCompleted(const UInt64 * /* numFiles */, const UInt64 * /* numBytes */) +HRESULT CExtractCallbackImp::Open_SetCompleted(const UInt64 *files, const UInt64 *bytes) { - // if (numFiles != NULL) ProgressDialog->Sync.SetNumFilesCur(*numFiles); + if (!MultiArcMode) + { + if (files) + { + ProgressDialog->Sync.Set_NumFilesCur(*files); + } + + if (bytes) + { + } + } + return ProgressDialog->Sync.CheckStop(); } diff --git a/CPP/7zip/UI/FileManager/ExtractCallback.h b/CPP/7zip/UI/FileManager/ExtractCallback.h index 1654bcd6..6cd8d0aa 100644 --- a/CPP/7zip/UI/FileManager/ExtractCallback.h +++ b/CPP/7zip/UI/FileManager/ExtractCallback.h @@ -284,6 +284,10 @@ public: UString _lang_Skipping; UString _lang_Empty; + bool _totalFilesDefined; + bool _totalBytesDefined; + bool MultiArcMode; + CExtractCallbackImp(): #ifndef _NO_CRYPTO PasswordIsDefined(false), @@ -291,7 +295,12 @@ public: #endif OverwriteMode(NExtract::NOverwriteMode::kAsk), StreamMode(false), - ProcessAltStreams(true) + ProcessAltStreams(true), + + _totalFilesDefined(false), + _totalBytesDefined(false), + MultiArcMode(false) + #ifndef _SFX , _hashCalc(NULL) #endif diff --git a/CPP/7zip/UI/FileManager/LinkDialogRes.h b/CPP/7zip/UI/FileManager/LinkDialogRes.h index 6b2dc2cf..47b89192 100644 --- a/CPP/7zip/UI/FileManager/LinkDialogRes.h +++ b/CPP/7zip/UI/FileManager/LinkDialogRes.h @@ -2,13 +2,13 @@ #define IDB_LINK_LINK 7701 -#define IDT_LINK_PATH_FROM 7702 -#define IDT_LINK_PATH_TO 7703 +#define IDT_LINK_PATH_FROM 7702 +#define IDT_LINK_PATH_TO 7703 #define IDG_LINK_TYPE 7710 #define IDR_LINK_TYPE_HARD 7711 -#define IDR_LINK_TYPE_SYM_FILE 7712 -#define IDR_LINK_TYPE_SYM_DIR 7713 +#define IDR_LINK_TYPE_SYM_FILE 7712 +#define IDR_LINK_TYPE_SYM_DIR 7713 #define IDR_LINK_TYPE_JUNCTION 7714 diff --git a/CPP/7zip/UI/FileManager/MyLoadMenu.cpp b/CPP/7zip/UI/FileManager/MyLoadMenu.cpp index b0f6615e..4b299b5c 100644 --- a/CPP/7zip/UI/FileManager/MyLoadMenu.cpp +++ b/CPP/7zip/UI/FileManager/MyLoadMenu.cpp @@ -143,7 +143,9 @@ static void MyChangeMenu(HMENU menuLoc, int level, int menuIndex) else continue; } + LangString_OnlyFromLangFile(langID, newString); + if (newString.IsEmpty()) continue; } @@ -154,7 +156,21 @@ static void MyChangeMenu(HMENU menuLoc, int level, int menuIndex) int langPos = FindLangItem(item.wID); // we don't need lang change for CRC items!!! - LangString_OnlyFromLangFile(langPos >= 0 ? kIDLangPairs[langPos].LangID : item.wID, newString); + + UInt32 langID = langPos >= 0 ? kIDLangPairs[langPos].LangID : item.wID; + + if (langID == IDM_OPEN_INSIDE_ONE || langID == IDM_OPEN_INSIDE_PARSER) + { + LangString_OnlyFromLangFile(IDM_OPEN_INSIDE, newString); + newString.Replace(L"&", L""); + int tabPos = newString.Find(L"\t"); + if (tabPos >= 0) + newString.DeleteFrom(tabPos); + newString += (langID == IDM_OPEN_INSIDE_ONE ? L" *" : L" #"); + } + else + LangString_OnlyFromLangFile(langID, newString); + if (newString.IsEmpty()) continue; @@ -162,6 +178,7 @@ static void MyChangeMenu(HMENU menuLoc, int level, int menuIndex) if (tabPos >= 0) newString += item.StringValue.Ptr(tabPos); } + { item.StringValue = newString; item.fMask = Get_fMask_for_String(); @@ -358,6 +375,7 @@ void CFileMenu::Load(HMENU hMenu, unsigned startPos) ReadRegDiff(diffPath); unsigned numRealItems = startPos; + for (unsigned i = 0;; i++) { CMenuItem item; @@ -375,6 +393,13 @@ void CFileMenu::Load(HMENU hMenu, unsigned startPos) if (item.wID == IDM_DIFF && diffPath.IsEmpty()) continue; + if (item.wID == IDM_OPEN_INSIDE_ONE || item.wID == IDM_OPEN_INSIDE_PARSER) + { + // We use diff as "super mode" marker for additional commands. + if (diffPath.IsEmpty()) + continue; + } + bool isOneFsFile = (isFsFolder && numItems == 1 && allAreFiles); bool disable = (!isOneFsFile && (item.wID == IDM_SPLIT || item.wID == IDM_COMBINE)); @@ -415,6 +440,7 @@ void CFileMenu::Load(HMENU hMenu, unsigned startPos) numRealItems = startPos; } } + destMenu.RemoveAllItemsFrom(numRealItems); } @@ -432,7 +458,11 @@ bool ExecuteFileCommand(int id) { // File case IDM_OPEN: g_App.OpenItem(); break; - case IDM_OPEN_INSIDE: g_App.OpenItemInside(); break; + + case IDM_OPEN_INSIDE: g_App.OpenItemInside(NULL); break; + case IDM_OPEN_INSIDE_ONE: g_App.OpenItemInside(L"*"); break; + case IDM_OPEN_INSIDE_PARSER: g_App.OpenItemInside(L"#"); break; + case IDM_OPEN_OUTSIDE: g_App.OpenItemOutside(); break; case IDM_FILE_VIEW: g_App.EditItem(false); break; case IDM_FILE_EDIT: g_App.EditItem(true); break; diff --git a/CPP/7zip/UI/FileManager/Panel.h b/CPP/7zip/UI/FileManager/Panel.h index 5d03f6da..63b97a25 100644 --- a/CPP/7zip/UI/FileManager/Panel.h +++ b/CPP/7zip/UI/FileManager/Panel.h @@ -285,7 +285,7 @@ private: HRESULT InitColumns(); // void InitColumns2(PROPID sortID); - void InsertColumn(int index); + void InsertColumn(unsigned index); void SetFocusedSelectedItem(int index, bool select); HRESULT RefreshListCtrl(const UString &focusedName, int focusedPos, bool selectFocused, @@ -351,6 +351,7 @@ public: */ return (UInt32)item.lParam; } + int GetRealItemIndex(int indexInListView) const { /* @@ -690,7 +691,7 @@ public: void OpenAltStreams(); - void OpenFocusedItemAsInternal(); + void OpenFocusedItemAsInternal(const wchar_t *type = NULL); void OpenSelectedItems(bool internal); void OpenFolderExternal(int index); @@ -703,13 +704,14 @@ public: const UString &arcFormat, bool &encrypted); HRESULT OpenItemAsArchive(const UString &relPath, const UString &arcFormat, bool &encrypted); - HRESULT OpenItemAsArchive(int index); + HRESULT OpenItemAsArchive(int index, const wchar_t *type = NULL); void OpenItemInArchive(int index, bool tryInternal, bool tryExternal, - bool editMode, bool useEditor); + bool editMode, bool useEditor, const wchar_t *type = NULL); HRESULT OnOpenItemChanged(UInt32 index, const wchar_t *fullFilePath, bool usePassword, const UString &password); LRESULT OnOpenItemChanged(LPARAM lParam); - void OpenItem(int index, bool tryInternal, bool tryExternal); + bool IsVirus_Message(const UString &name); + void OpenItem(int index, bool tryInternal, bool tryExternal, const wchar_t *type = NULL); void EditItem(bool useEditor); void EditItem(int index, bool useEditor); diff --git a/CPP/7zip/UI/FileManager/PanelItemOpen.cpp b/CPP/7zip/UI/FileManager/PanelItemOpen.cpp index b47a30a3..5ff605f4 100644 --- a/CPP/7zip/UI/FileManager/PanelItemOpen.cpp +++ b/CPP/7zip/UI/FileManager/PanelItemOpen.cpp @@ -157,12 +157,6 @@ public: } }; -static bool IsNameVirus(const UString &name) -{ - // return (name.Find(L" ") >= 0); - return (wcsstr(name, L" ") != NULL); -} - struct CTmpProcessInfo: public CTempFileInfo { CChildProcesses Processes; @@ -320,12 +314,12 @@ HRESULT CPanel::OpenItemAsArchive(const UString &relPath, const UString &arcForm return OpenItemAsArchive(NULL, tfi, fullPath, arcFormat, encrypted); } -HRESULT CPanel::OpenItemAsArchive(int index) +HRESULT CPanel::OpenItemAsArchive(int index, const wchar_t *type) { CDisableTimerProcessing disableTimerProcessing1(*this); CDisableNotify disableNotify(*this); bool encrypted; - HRESULT res = OpenItemAsArchive(GetItemRelPath2(index), UString(), encrypted); + HRESULT res = OpenItemAsArchive(GetItemRelPath2(index), type ? type : L"", encrypted); if (res != S_OK) { RefreshTitle(true); // in case of error we must refresh changed title of 7zFM @@ -600,19 +594,77 @@ void CPanel::OpenFolderExternal(int index) StartApplicationDontWait(fsPrefix, name, (HWND)*this); } -void CPanel::OpenItem(int index, bool tryInternal, bool tryExternal) +bool CPanel::IsVirus_Message(const UString &name) +{ + UString name2; + + const wchar_t cRLO = (wchar_t)0x202E; + bool isVirus = false; + bool isSpaceError = false; + name2 = name; + + if (name2.Find(cRLO) >= 0) + { + UString badString = cRLO; + name2.Replace(badString, L"[RLO]"); + isVirus = true; + } + { + const wchar_t *kVirusSpaces = L" "; + // const unsigned kNumSpaces = strlen(kVirusSpaces); + for (;;) + { + int pos = name2.Find(kVirusSpaces); + if (pos < 0) + break; + isVirus = true; + isSpaceError = true; + name2.Replace(kVirusSpaces, L" "); + } + } + + if (!isVirus) + return false; + + UString s = LangString(IDS_VIRUS); + + if (!isSpaceError) + { + int pos1 = s.Find(L'('); + if (pos1 >= 0) + { + int pos2 = s.Find(L')', pos1 + 1); + if (pos2 >= 0) + { + s.Delete(pos1, pos2 + 1 - pos1); + if (pos1 > 0 && s[pos1 - 1] == ' ' && s[pos1] == '.') + s.Delete(pos1 - 1); + } + } + } + + UString name3 = name; + name3.Replace(L'\n', L'_'); + name2.Replace(L'\n', L'_'); + + s.Add_LF(); s += name2; + s.Add_LF(); s += name3; + + MessageBoxMyError(s); + return true; +} + +void CPanel::OpenItem(int index, bool tryInternal, bool tryExternal, const wchar_t *type) { CDisableTimerProcessing disableTimerProcessing(*this); UString name = GetItemRelPath2(index); - if (IsNameVirus(name)) - { - MessageBoxErrorLang(IDS_VIRUS); + + if (IsVirus_Message(name)) return; - } if (!_parentFolders.IsEmpty()) { - OpenItemInArchive(index, tryInternal, tryExternal, false, false); + OpenItemInArchive(index, tryInternal, tryExternal, false, false, type); return; } @@ -623,7 +675,7 @@ void CPanel::OpenItem(int index, bool tryInternal, bool tryExternal) if (tryInternal) if (!tryExternal || !DoItemAlwaysStart(name)) { - HRESULT res = OpenItemAsArchive(index); + HRESULT res = OpenItemAsArchive(index, type); disableNotify.Restore(); // we must restore to allow text notification update InvalidateList(); if (res == S_OK || res == E_ABORT) @@ -634,6 +686,7 @@ void CPanel::OpenItem(int index, bool tryInternal, bool tryExternal) return; } } + if (tryExternal) { // SetCurrentDirectory opens HANDLE to folder!!! @@ -939,16 +992,13 @@ static HRESULT GetTime(IFolderFolder *folder, UInt32 index, PROPID propID, FILET } */ -void CPanel::OpenItemInArchive(int index, bool tryInternal, bool tryExternal, bool editMode, bool useEditor) +void CPanel::OpenItemInArchive(int index, bool tryInternal, bool tryExternal, bool editMode, bool useEditor, const wchar_t *type) { const UString name = GetItemName(index); const UString relPath = GetItemRelPath(index); - if (IsNameVirus(name)) - { - MessageBoxErrorLang(IDS_VIRUS); + if (IsVirus_Message(name)) return; - } if (!_folderOperations) { @@ -966,6 +1016,7 @@ void CPanel::OpenItemInArchive(int index, bool tryInternal, bool tryExternal, bo MessageBoxLastError(); return; } + FString tempDir = tempDirectory.GetPath(); FString tempDirNorm = tempDir; NName::NormalizeDirPathPrefix(tempDirNorm); @@ -993,7 +1044,7 @@ void CPanel::OpenItemInArchive(int index, bool tryInternal, bool tryExternal, bo if (subStream) { bool encrypted; - HRESULT res = OpenItemAsArchive(subStream, tempFileInfo, fullVirtPath, UString(), encrypted); + HRESULT res = OpenItemAsArchive(subStream, tempFileInfo, fullVirtPath, type ? type : L"", encrypted); if (res == S_OK) { tempDirectory.DisableDeleting(); @@ -1104,7 +1155,7 @@ void CPanel::OpenItemInArchive(int index, bool tryInternal, bool tryExternal, bo CMyComPtr bufInStream = bufInStreamSpec; bufInStreamSpec->Init(file.Data, streamSize, virtFileSystem); bool encrypted; - if (OpenItemAsArchive(bufInStream, tempFileInfo, fullVirtPath, UString(), encrypted) == S_OK) + if (OpenItemAsArchive(bufInStream, tempFileInfo, fullVirtPath, type ? type : L"", encrypted) == S_OK) { tempDirectory.DisableDeleting(); RefreshListCtrl(); @@ -1130,7 +1181,7 @@ void CPanel::OpenItemInArchive(int index, bool tryInternal, bool tryExternal, bo if (tryAsArchive) { bool encrypted; - if (OpenItemAsArchive(NULL, tempFileInfo, fullVirtPath, UString(), encrypted) == S_OK) + if (OpenItemAsArchive(NULL, tempFileInfo, fullVirtPath, type ? type : L"", encrypted) == S_OK) { tempDirectory.DisableDeleting(); RefreshListCtrl(); diff --git a/CPP/7zip/UI/FileManager/PanelItems.cpp b/CPP/7zip/UI/FileManager/PanelItems.cpp index 491a36ad..e6b89cbe 100644 --- a/CPP/7zip/UI/FileManager/PanelItems.cpp +++ b/CPP/7zip/UI/FileManager/PanelItems.cpp @@ -210,14 +210,15 @@ HRESULT CPanel::InitColumns() */ _sortID = _listViewInfo.SortID; + _visibleProperties.Sort(); + for (i = 0; i < _visibleProperties.Size(); i++) - { InsertColumn(i); - } + return S_OK; } -void CPanel::InsertColumn(int index) +void CPanel::InsertColumn(unsigned index) { const CItemProperty &prop = _visibleProperties[index]; LV_COLUMNW column; @@ -225,6 +226,7 @@ void CPanel::InsertColumn(int index) column.cx = prop.Width; column.fmt = GetColumnAlign(prop.ID, prop.Type); column.iOrder = prop.Order; + // iOrder must be <= _listView.ItemCount column.iSubItem = index; column.pszText = const_cast((const wchar_t *)prop.Name); _listView.InsertColumn(index, &column); @@ -775,7 +777,7 @@ void CPanel::EditItem(bool useEditor) EditItem(realIndex, useEditor); } -void CPanel::OpenFocusedItemAsInternal() +void CPanel::OpenFocusedItemAsInternal(const wchar_t *type) { int focusedItem = _listView.GetFocusedItem(); if (focusedItem < 0) @@ -784,7 +786,7 @@ void CPanel::OpenFocusedItemAsInternal() if (IsItem_Folder(realIndex)) OpenFolder(realIndex); else - OpenItem(realIndex, true, false); + OpenItem(realIndex, true, false, type); } void CPanel::OpenSelectedItems(bool tryInternal) @@ -1059,10 +1061,10 @@ void CPanel::ShowColumnsContextMenu(int x, int y) if (prop.IsVisible) { - int prevVisibleSize = _visibleProperties.Size(); - prop.Order = prevVisibleSize; + unsigned num = _visibleProperties.Size(); + prop.Order = num; _visibleProperties.Add(prop); - InsertColumn(prevVisibleSize); + InsertColumn(num); } else { diff --git a/CPP/7zip/UI/FileManager/PanelListNotify.cpp b/CPP/7zip/UI/FileManager/PanelListNotify.cpp index 2f37db14..74a75d02 100644 --- a/CPP/7zip/UI/FileManager/PanelListNotify.cpp +++ b/CPP/7zip/UI/FileManager/PanelListNotify.cpp @@ -320,23 +320,33 @@ LRESULT CPanel::SetItemText(LVITEMW &item) const wchar_t *name = NULL; unsigned nameLen = 0; _folderGetItemName->GetItemName(realIndex, &name, &nameLen); + if (name) { unsigned dest = 0; unsigned limit = item.cchTextMax - 1; + for (unsigned i = 0; dest < limit;) { wchar_t c = name[i++]; if (c == 0) break; text[dest++] = c; + if (c != ' ') + { + if (c != 0x202E) // RLO + continue; + text[dest - 1] = '_'; continue; + } + if (name[i + 1] != ' ') continue; unsigned t = 2; for (; name[i + t] == ' '; t++); + if (t >= 4 && dest + 4 <= limit) { text[dest++] = '.'; @@ -346,6 +356,7 @@ LRESULT CPanel::SetItemText(LVITEMW &item) i += t; } } + text[dest] = 0; return 0; } diff --git a/CPP/7zip/UI/FileManager/resource.h b/CPP/7zip/UI/FileManager/resource.h index 23e64edc..b7ca17f1 100644 --- a/CPP/7zip/UI/FileManager/resource.h +++ b/CPP/7zip/UI/FileManager/resource.h @@ -47,6 +47,9 @@ #define IDM_LINK 558 #define IDM_ALT_STREAMS 559 +#define IDM_OPEN_INSIDE_ONE 590 +#define IDM_OPEN_INSIDE_PARSER 591 + #define IDM_SELECT_ALL 600 #define IDM_DESELECT_ALL 601 #define IDM_INVERT_SELECTION 602 diff --git a/CPP/7zip/UI/FileManager/resource.rc b/CPP/7zip/UI/FileManager/resource.rc index fb57e4f0..7db5d3a1 100644 --- a/CPP/7zip/UI/FileManager/resource.rc +++ b/CPP/7zip/UI/FileManager/resource.rc @@ -19,6 +19,8 @@ BEGIN BEGIN MENUITEM "&Open\tEnter", IDM_OPEN MENUITEM "Open &Inside\tCtrl+PgDn", IDM_OPEN_INSIDE + MENUITEM "Open Inside *", IDM_OPEN_INSIDE_ONE + MENUITEM "Open Inside #", IDM_OPEN_INSIDE_PARSER MENUITEM "Open O&utside\tShift+Enter", IDM_OPEN_OUTSIDE MENUITEM "&View\tF3", IDM_FILE_VIEW MENUITEM "&Edit\tF4", IDM_FILE_EDIT diff --git a/CPP/7zip/UI/GUI/ExtractDialogRes.h b/CPP/7zip/UI/GUI/ExtractDialogRes.h index 403a6546..ed12bfb3 100644 --- a/CPP/7zip/UI/GUI/ExtractDialogRes.h +++ b/CPP/7zip/UI/GUI/ExtractDialogRes.h @@ -18,7 +18,7 @@ #define IDX_EXTRACT_ELIM_DUP 3430 #define IDX_EXTRACT_NT_SECUR 3431 -// #define IDX_EXTRACT_ALT_STREAMS 3432 +// #define IDX_EXTRACT_ALT_STREAMS 3432 #define IDX_PASSWORD_SHOW 3803 #define IDG_PASSWORD 3807 diff --git a/CPP/7zip/UI/GUI/GUI.cpp b/CPP/7zip/UI/GUI/GUI.cpp index 0f3cde94..489fc721 100644 --- a/CPP/7zip/UI/GUI/GUI.cpp +++ b/CPP/7zip/UI/GUI/GUI.cpp @@ -254,6 +254,8 @@ static int Main2() } } + ecs->MultiArcMode = (ArchivePathsSorted.Size() > 1); + HRESULT result = ExtractGUI(codecs, formatIndices, excludedFormatIndices, ArchivePathsSorted, diff --git a/CPP/7zip/UI/GUI/resource3.h b/CPP/7zip/UI/GUI/resource3.h index 1758d525..c25737fa 100644 --- a/CPP/7zip/UI/GUI/resource3.h +++ b/CPP/7zip/UI/GUI/resource3.h @@ -1,10 +1,10 @@ #define IDS_PROGRESS_REMOVE 3305 -#define IDS_PROGRESS_ADD 3320 -#define IDS_PROGRESS_UPDATE 3321 -#define IDS_PROGRESS_ANALYZE 3322 -#define IDS_PROGRESS_REPLICATE 3323 -#define IDS_PROGRESS_REPACK 3324 +#define IDS_PROGRESS_ADD 3320 +#define IDS_PROGRESS_UPDATE 3321 +#define IDS_PROGRESS_ANALYZE 3322 +#define IDS_PROGRESS_REPLICATE 3323 +#define IDS_PROGRESS_REPACK 3324 -#define IDS_PROGRESS_DELETE 3326 -#define IDS_PROGRESS_HEADER 3327 +#define IDS_PROGRESS_DELETE 3326 +#define IDS_PROGRESS_HEADER 3327 -- cgit v1.2.3