Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/kornelski/7z.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Pavlov <ipavlov@users.sourceforge.net>2015-09-22 03:00:00 +0300
committerKornel LesiƄski <kornel@geekhood.net>2016-05-28 02:16:55 +0300
commitf6444c32568553e0261ca0105083658f12be6284 (patch)
tree8f4eb80f6accd2a9d0759e2564fd6a2b00836e02 /CPP/7zip/Archive/Cab
parentcba375916fb18db8b9101aedf4fa079e019311b3 (diff)
15.0715.07
Diffstat (limited to 'CPP/7zip/Archive/Cab')
-rw-r--r--CPP/7zip/Archive/Cab/CabBlockInStream.cpp11
-rw-r--r--CPP/7zip/Archive/Cab/CabBlockInStream.h6
-rw-r--r--CPP/7zip/Archive/Cab/CabHandler.cpp125
3 files changed, 119 insertions, 23 deletions
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<bool> *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<IArchiveExtractCallbackMessage> 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<ICompressCoder> deflateDecoder;
NCompress::NLzx::CDecoder *lzxDecoderSpec = NULL;
- CMyComPtr<ICompressCoder> lzxDecoder;
+ CMyComPtr<IUnknown> lzxDecoder;
NCompress::NQuantum::CDecoder *quantumDecoderSpec = NULL;
- CMyComPtr<ICompressCoder> quantumDecoder;
+ CMyComPtr<IUnknown> quantumDecoder;
CCabBlockInStream *cabBlockInStreamSpec = new CCabBlockInStream();
CMyComPtr<ISequentialInStream> cabBlockInStream = cabBlockInStreamSpec;
@@ -968,7 +1010,8 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
CFolderOutStream *cabFolderOutStream = new CFolderOutStream;
CMyComPtr<ISequentialOutStream> 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();