mirror of
https://github.com/Xevion/easy7zip.git
synced 2025-12-08 10:07:02 -06:00
15.07
This commit is contained in:
committed by
Kornel Lesiński
parent
cba375916f
commit
f6444c3256
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user