mirror of
https://github.com/Xevion/easy7zip.git
synced 2025-12-06 13:14:59 -06:00
- Minor speed optimization for LZMA2 (xz and 7z) multi-threading compression.
7-Zip now uses additional memory buffers for multi-block LZMA2 compression.
CPU utilization was slightly improved.
- 7-zip now creates multi-block xz archives by default. Block size can be
specified with -ms[Size]{m|g} switch.
- xz decoder now can unpack random block from multi-block xz archives. 7-Zip
File Manager now can open nested multi-block xz archives (for example,
image.iso.xz) without full unpacking of xz archive.
- 7-Zip now can create zip archives from stdin to stdout.
- 7-Zip command line: @listfile now doesn't work after -- switch. Use
-i@listfile before -- switch instead.
fixed bugs:
- 7-Zip could add unrequired alternate file streams to WIM archives, for
commands that contain filename wildcards and -sns switch.
- 7-Zip 17.00 beta crashed for commands that write anti-item to 7z archive.
- 7-Zip 17.00 beta ignored "Use large memory pages" option.
264 lines
6.0 KiB
C++
264 lines
6.0 KiB
C++
// XzDecoder.cpp
|
|
|
|
#include "StdAfx.h"
|
|
|
|
#include "../../../C/Alloc.h"
|
|
|
|
#include "../Common/StreamUtils.h"
|
|
|
|
#include "../Archive/IArchive.h"
|
|
|
|
#include "XzDecoder.h"
|
|
|
|
using namespace NArchive;
|
|
|
|
namespace NCompress {
|
|
namespace NXz {
|
|
|
|
|
|
CXzUnpackerCPP::CXzUnpackerCPP(): InBuf(NULL), OutBuf(NULL)
|
|
{
|
|
XzUnpacker_Construct(&p, &g_Alloc);
|
|
}
|
|
|
|
CXzUnpackerCPP::~CXzUnpackerCPP()
|
|
{
|
|
XzUnpacker_Free(&p);
|
|
MidFree(InBuf);
|
|
MidFree(OutBuf);
|
|
}
|
|
|
|
|
|
void CStatInfo::Clear()
|
|
{
|
|
InSize = 0;
|
|
OutSize = 0;
|
|
PhySize = 0;
|
|
|
|
NumStreams = 0;
|
|
NumBlocks = 0;
|
|
|
|
UnpackSize_Defined = false;
|
|
|
|
NumStreams_Defined = false;
|
|
NumBlocks_Defined = false;
|
|
|
|
IsArc = false;
|
|
UnexpectedEnd = false;
|
|
DataAfterEnd = false;
|
|
Unsupported = false;
|
|
HeadersError = false;
|
|
DataError = false;
|
|
CrcError = false;
|
|
}
|
|
|
|
|
|
HRESULT CDecoder::Decode(ISequentialInStream *seqInStream, ISequentialOutStream *outStream,
|
|
const UInt64 *outSizeLimit, bool finishStream, ICompressProgressInfo *progress)
|
|
{
|
|
const size_t kInBufSize = (size_t)1 << 20;
|
|
const size_t kOutBufSize = (size_t)1 << 21;
|
|
|
|
Clear();
|
|
DecodeRes = SZ_OK;
|
|
|
|
XzUnpacker_Init(&xzu.p);
|
|
|
|
if (!xzu.InBuf)
|
|
{
|
|
xzu.InBuf = (Byte *)MidAlloc(kInBufSize);
|
|
if (!xzu.InBuf)
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
if (!xzu.OutBuf)
|
|
{
|
|
xzu.OutBuf = (Byte *)MidAlloc(kOutBufSize);
|
|
if (!xzu.OutBuf)
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
UInt32 inSize = 0;
|
|
UInt32 inPos = 0;
|
|
SizeT outPos = 0;
|
|
|
|
HRESULT readRes = S_OK;
|
|
|
|
for (;;)
|
|
{
|
|
if (inPos == inSize && readRes == S_OK)
|
|
{
|
|
inPos = inSize = 0;
|
|
readRes = seqInStream->Read(xzu.InBuf, kInBufSize, &inSize);
|
|
}
|
|
|
|
SizeT inLen = inSize - inPos;
|
|
SizeT outLen = kOutBufSize - outPos;
|
|
ECoderFinishMode finishMode = CODER_FINISH_ANY;
|
|
|
|
/*
|
|
// 17.01 : the code was disabled:
|
|
if (inSize == 0)
|
|
finishMode = CODER_FINISH_END;
|
|
*/
|
|
|
|
if (outSizeLimit)
|
|
{
|
|
const UInt64 rem = *outSizeLimit - OutSize;
|
|
if (outLen >= rem)
|
|
{
|
|
outLen = (SizeT)rem;
|
|
if (finishStream)
|
|
finishMode = CODER_FINISH_END;
|
|
}
|
|
}
|
|
|
|
ECoderStatus status;
|
|
|
|
const SizeT outLenRequested = outLen;
|
|
|
|
SRes res = XzUnpacker_Code(&xzu.p,
|
|
xzu.OutBuf + outPos, &outLen,
|
|
xzu.InBuf + inPos, &inLen,
|
|
finishMode, &status);
|
|
|
|
DecodeRes = res;
|
|
|
|
inPos += (UInt32)inLen;
|
|
outPos += outLen;
|
|
|
|
InSize += inLen;
|
|
OutSize += outLen;
|
|
|
|
bool finished = ((inLen == 0 && outLen == 0) || res != SZ_OK);
|
|
|
|
if (outLen >= outLenRequested || finished)
|
|
{
|
|
if (outStream && outPos != 0)
|
|
{
|
|
RINOK(WriteStream(outStream, xzu.OutBuf, outPos));
|
|
}
|
|
outPos = 0;
|
|
}
|
|
|
|
if (progress)
|
|
{
|
|
RINOK(progress->SetRatioInfo(&InSize, &OutSize));
|
|
}
|
|
|
|
if (!finished)
|
|
continue;
|
|
|
|
{
|
|
PhySize = InSize;
|
|
NumStreams = xzu.p.numStartedStreams;
|
|
if (NumStreams > 0)
|
|
IsArc = true;
|
|
NumBlocks = xzu.p.numTotalBlocks;
|
|
|
|
UnpackSize_Defined = true;
|
|
NumStreams_Defined = true;
|
|
NumBlocks_Defined = true;
|
|
|
|
UInt64 extraSize = XzUnpacker_GetExtraSize(&xzu.p);
|
|
|
|
if (res == SZ_OK)
|
|
{
|
|
if (status == CODER_STATUS_NEEDS_MORE_INPUT)
|
|
{
|
|
extraSize = 0;
|
|
if (!XzUnpacker_IsStreamWasFinished(&xzu.p))
|
|
{
|
|
// finished at padding bytes, but padding is not aligned for 4
|
|
UnexpectedEnd = true;
|
|
res = SZ_ERROR_DATA;
|
|
}
|
|
}
|
|
else // status == CODER_STATUS_NOT_FINISHED
|
|
res = SZ_ERROR_DATA;
|
|
}
|
|
else if (res == SZ_ERROR_NO_ARCHIVE)
|
|
{
|
|
if (InSize == extraSize)
|
|
IsArc = false;
|
|
else
|
|
{
|
|
if (extraSize != 0 || inPos != inSize)
|
|
{
|
|
DataAfterEnd = true;
|
|
res = SZ_OK;
|
|
}
|
|
}
|
|
}
|
|
|
|
DecodeRes = res;
|
|
PhySize -= extraSize;
|
|
|
|
switch (res)
|
|
{
|
|
case SZ_OK: break;
|
|
case SZ_ERROR_NO_ARCHIVE: IsArc = false; break;
|
|
case SZ_ERROR_ARCHIVE: HeadersError = true; break;
|
|
case SZ_ERROR_UNSUPPORTED: Unsupported = true; break;
|
|
case SZ_ERROR_CRC: CrcError = true; break;
|
|
case SZ_ERROR_DATA: DataError = true; break;
|
|
default: DataError = true; break;
|
|
}
|
|
|
|
return readRes;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
Int32 CDecoder::Get_Extract_OperationResult() const
|
|
{
|
|
Int32 opRes;
|
|
if (!IsArc)
|
|
opRes = NExtract::NOperationResult::kIsNotArc;
|
|
else if (UnexpectedEnd)
|
|
opRes = NExtract::NOperationResult::kUnexpectedEnd;
|
|
else if (DataAfterEnd)
|
|
opRes = NExtract::NOperationResult::kDataAfterEnd;
|
|
else if (CrcError)
|
|
opRes = NExtract::NOperationResult::kCRCError;
|
|
else if (Unsupported)
|
|
opRes = NExtract::NOperationResult::kUnsupportedMethod;
|
|
else if (HeadersError)
|
|
opRes = NExtract::NOperationResult::kDataError;
|
|
else if (DataError)
|
|
opRes = NExtract::NOperationResult::kDataError;
|
|
else if (DecodeRes != SZ_OK)
|
|
opRes = NExtract::NOperationResult::kDataError;
|
|
else
|
|
opRes = NExtract::NOperationResult::kOK;
|
|
return opRes;
|
|
}
|
|
|
|
|
|
|
|
HRESULT CComDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
|
const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
|
|
{
|
|
RINOK(_decoder.Decode(inStream, outStream, outSize, _finishStream, progress));
|
|
Int32 opRes = _decoder.Get_Extract_OperationResult();
|
|
if (opRes == NArchive::NExtract::NOperationResult::kUnsupportedMethod)
|
|
return E_NOTIMPL;
|
|
if (opRes != NArchive::NExtract::NOperationResult::kOK)
|
|
return S_FALSE;
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CComDecoder::SetFinishMode(UInt32 finishMode)
|
|
{
|
|
_finishStream = (finishMode != 0);
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CComDecoder::GetInStreamProcessedSize(UInt64 *value)
|
|
{
|
|
*value = _decoder.InSize;
|
|
return S_OK;
|
|
}
|
|
|
|
}}
|