feat: add support for .lz and .lz4 compression algorithms

This commit is contained in:
yh-sb 2025-12-24 13:05:20 +02:00
parent 5e96a82794
commit 85e04af223
7 changed files with 1052 additions and 0 deletions

140
C/Lz4Dec.c Normal file
View file

@ -0,0 +1,140 @@
/* Lz4Dec.c -- LZ4 Decoder
2025 : Igor Pavlov : Public domain */
#include "Precomp.h"
#include <string.h>
#include "Lz4Dec.h"
/*
LZ4 block format:
A block is composed of sequences.
Each sequence: [token][literals][match]
Token (1 byte):
- High 4 bits: literal length (0-15, 15 means more bytes follow)
- Low 4 bits: match length - 4 (0-15, 15 means more bytes follow)
If literal length == 15, read additional bytes until byte < 255
Literals: raw bytes
Match:
- Offset: 2 bytes little-endian (must be > 0)
- If match length field == 15, read additional bytes until byte < 255
- Actual match length = field value + 4
Last sequence has no match (ends after literals)
*/
SRes Lz4Dec_DecodeBlock(
const Byte *src, SizeT srcLen,
Byte *dest, SizeT *destLen,
SizeT *srcConsumed)
{
const Byte *srcEnd = src + srcLen;
const Byte *srcStart = src;
Byte *destStart = dest;
Byte *destEnd = dest + *destLen;
*srcConsumed = 0;
*destLen = 0;
while (src < srcEnd)
{
unsigned token;
SizeT litLen;
SizeT matchLen;
// Read token
token = *src++;
litLen = token >> 4;
matchLen = token & 0x0F;
// Extended literal length
if (litLen == 15)
{
for (;;)
{
unsigned b;
if (src >= srcEnd)
return SZ_ERROR_INPUT_EOF;
b = *src++;
litLen += b;
if (b != 255)
break;
}
}
// Copy literals (non-overlapping)
if (litLen > 0)
{
if (src + litLen > srcEnd)
return SZ_ERROR_INPUT_EOF;
if (dest + litLen > destEnd)
return SZ_ERROR_OUTPUT_EOF;
memcpy(dest, src, litLen);
src += litLen;
dest += litLen;
}
// Is last sequence ? (no match)
if (src >= srcEnd)
break;
// Read match offset (2 bytes, little-endian)
{
SizeT offset;
const Byte *matchSrc;
if (src + 2 > srcEnd)
return SZ_ERROR_INPUT_EOF;
offset = (SizeT)src[0] | ((SizeT)src[1] << 8);
src += 2;
if (offset == 0)
return SZ_ERROR_DATA; // Offset 0 is invalid
// Extended match length
matchLen += 4; // Minimum match length is 4
if ((token & 0x0F) == 15)
{
for (;;)
{
unsigned b;
if (src >= srcEnd)
return SZ_ERROR_INPUT_EOF;
b = *src++;
matchLen += b;
if (b != 255)
break;
}
}
// Validate offset
if (offset > (SizeT)(dest - destStart))
return SZ_ERROR_DATA; // Offset too large
// Copy match
if (dest + matchLen > destEnd)
return SZ_ERROR_OUTPUT_EOF;
matchSrc = dest - offset;
// Handle overlapping copies
{
SizeT i;
for (i = 0; i < matchLen; i++)
dest[i] = matchSrc[i];
}
dest += matchLen;
}
}
*srcConsumed = (SizeT)(src - srcStart);
*destLen = (SizeT)(dest - destStart);
return SZ_OK;
}

27
C/Lz4Dec.h Normal file
View file

@ -0,0 +1,27 @@
/* Lz4Dec.h -- LZ4 Decoder
2025 : Igor Pavlov : Public domain */
#ifndef Z7_LZ4_DEC_H
#define Z7_LZ4_DEC_H
#include "7zTypes.h"
EXTERN_C_BEGIN
/*
LZ4 block decoder
Returns:
SZ_OK - success
SZ_ERROR_DATA - data error
SZ_ERROR_INPUT_EOF - need more input
SZ_ERROR_OUTPUT_EOF - need more output space
*/
SRes Lz4Dec_DecodeBlock(
const Byte *src, SizeT srcLen,
Byte *dest, SizeT *destLen,
SizeT *srcConsumed);
EXTERN_C_END
#endif

View file

@ -544,6 +544,10 @@ $O/LvmHandler.o: ../../Archive/LvmHandler.cpp
$(CXX) $(CXXFLAGS) $<
$O/LzhHandler.o: ../../Archive/LzhHandler.cpp
$(CXX) $(CXXFLAGS) $<
$O/Lz4Handler.o: ../../Archive/Lz4Handler.cpp
$(CXX) $(CXXFLAGS) $<
$O/LzipHandler.o: ../../Archive/LzipHandler.cpp
$(CXX) $(CXXFLAGS) $<
$O/LzmaHandler.o: ../../Archive/LzmaHandler.cpp
$(CXX) $(CXXFLAGS) $<
$O/MachoHandler.o: ../../Archive/MachoHandler.cpp
@ -1192,6 +1196,8 @@ $O/HuffEnc.o: ../../../../C/HuffEnc.c
$(CC) $(CFLAGS) $<
$O/LzFind.o: ../../../../C/LzFind.c
$(CC) $(CFLAGS) $<
$O/Lz4Dec.o: ../../../../C/Lz4Dec.c
$(CC) $(CFLAGS) $<
# ifdef MT_FILES
$O/LzFindMt.o: ../../../../C/LzFindMt.c

View file

@ -0,0 +1,546 @@
// Lz4Handler.cpp
#include "StdAfx.h"
#include "../../Common/ComTry.h"
#include "../../Windows/PropVariant.h"
#include "../Common/ProgressUtils.h"
#include "../Common/RegisterArc.h"
#include "../Common/StreamUtils.h"
#include "../Compress/CopyCoder.h"
#include "Common/DummyOutStream.h"
#include "../../../C/CpuArch.h"
#include "../../../C/Alloc.h"
#include "../../../C/Lz4Dec.h"
using namespace NWindows;
namespace NArchive {
namespace NLz4 {
/*
LZ4 Frame format:
Magic: 4 bytes (0x184D2204 little-endian)
Frame Descriptor:
FLG byte:
bits 7-6: Version (must be 01)
bit 5: Block Independence
bit 4: Block Checksum flag
bit 3: Content Size flag
bit 2: Content Checksum flag
bit 1: Reserved (0)
bit 0: DictID flag
BD byte:
bit 7: Reserved (0)
bits 6-4: Block Max Size (4=64KB, 5=256KB, 6=1MB, 7=4MB)
bits 3-0: Reserved (0)
[Content Size: 8 bytes if Content Size flag set]
[DictID: 4 bytes if DictID flag set]
Header Checksum: 1 byte (XXH32 >> 8)
Data Blocks:
Block Size: 4 bytes (bit 31: 1=uncompressed, bits 30-0: size)
Block Data: size bytes
[Block Checksum: 4 bytes if Block Checksum flag set]
... repeat until Block Size == 0
End Mark: 4 bytes (0x00000000)
[Content Checksum: 4 bytes if Content Checksum flag set]
*/
static const UInt32 kMagic = 0x184D2204;
static const unsigned kMagicSize = 4;
static const unsigned kMinHeaderSize = 7; // magic + FLG + BD + HC
static const unsigned kMaxHeaderSize = 19; // magic + FLG + BD + content_size(8) + dictid(4) + HC
static const unsigned kBlockSizes[] = {
0, // 0: reserved
0, // 1: reserved
0, // 2: reserved
0, // 3: reserved
64 << 10, // 4: 64 KB
256 << 10, // 5: 256 KB
1 << 20, // 6: 1 MB
4 << 20 // 7: 4 MB
};
struct CFrameInfo
{
bool BlockIndependence;
bool BlockChecksum;
bool ContentSizePresent;
bool ContentChecksum;
bool DictIdPresent;
UInt32 BlockMaxSize;
UInt64 ContentSize;
UInt32 DictId;
unsigned GetHeaderSize() const
{
return kMagicSize + 2 + (ContentSizePresent ? 8 : 0) + (DictIdPresent ? 4 : 0) + 1;
}
bool Parse(const Byte *p, size_t size)
{
if (size < kMinHeaderSize)
return false;
// Check magic
if (GetUi32(p) != kMagic)
return false;
p += 4;
Byte flg = p[0];
Byte bd = p[1];
p += 2;
// Version must be 01
if ((flg >> 6) != 1)
return false;
// Reserved bit in FLG must be 0
if (flg & 2)
return false;
// Reserved bits in BD must be 0
if (bd & 0x8F)
return false;
BlockIndependence = (flg & 0x20) != 0;
BlockChecksum = (flg & 0x10) != 0;
ContentSizePresent = (flg & 0x08) != 0;
ContentChecksum = (flg & 0x04) != 0;
DictIdPresent = (flg & 0x01) != 0;
unsigned blockMaxSizeCode = (bd >> 4) & 7;
if (blockMaxSizeCode < 4)
return false; // Reserved values
BlockMaxSize = kBlockSizes[blockMaxSizeCode];
ContentSize = 0;
DictId = 0;
unsigned headerSize = kMagicSize + 2;
if (ContentSizePresent)
{
headerSize += 8;
if (size < headerSize + 1)
return false;
ContentSize = GetUi64(p);
p += 8;
}
if (DictIdPresent)
{
headerSize += 4;
if (size < headerSize + 1)
return false;
DictId = GetUi32(p);
p += 4;
}
// Header checksum (we don't verify it, just skip)
headerSize += 1;
return true;
}
};
API_FUNC_static_IsArc IsArc_Lz4(const Byte *p, size_t size)
{
if (size < kMinHeaderSize)
return k_IsArc_Res_NEED_MORE;
// Check magic
if (GetUi32(p) != kMagic)
return k_IsArc_Res_NO;
Byte flg = p[4];
Byte bd = p[5];
// Version must be 01
if ((flg >> 6) != 1)
return k_IsArc_Res_NO;
// Reserved bit in FLG must be 0
if (flg & 2)
return k_IsArc_Res_NO;
// Reserved bits in BD must be 0
if (bd & 0x8F)
return k_IsArc_Res_NO;
// Block max size must be valid
unsigned blockMaxSizeCode = (bd >> 4) & 7;
if (blockMaxSizeCode < 4)
return k_IsArc_Res_NO;
return k_IsArc_Res_YES;
}
}
Z7_CLASS_IMP_CHandler_IInArchive_1(
IArchiveOpenSeq
)
CMyComPtr<IInStream> _stream;
CMyComPtr<ISequentialInStream> _seqStream;
bool _isArc;
bool _needSeekToStart;
bool _dataAfterEnd;
bool _needMoreInput;
bool _dataError;
bool _packSize_Defined;
bool _unpackSize_Defined;
UInt64 _packSize;
UInt64 _unpackSize;
CFrameInfo _frameInfo;
};
static const Byte kProps[] =
{
kpidSize,
kpidPackSize
};
static const Byte kArcProps[] =
{
kpidPhySize
};
IMP_IInArchive_Props
IMP_IInArchive_ArcProps
Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
{
NCOM::CPropVariant prop;
switch (propID)
{
case kpidPhySize: if (_packSize_Defined) prop = _packSize; break;
case kpidUnpackSize: if (_unpackSize_Defined) prop = _unpackSize; break;
case kpidErrorFlags:
{
UInt32 v = 0;
if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;
if (_needMoreInput) v |= kpv_ErrorFlags_UnexpectedEnd;
if (_dataAfterEnd) v |= kpv_ErrorFlags_DataAfterEnd;
if (_dataError) v |= kpv_ErrorFlags_DataError;
prop = v;
break;
}
default: break;
}
prop.Detach(value);
return S_OK;
}
Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
{
*numItems = 1;
return S_OK;
}
Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value))
{
NCOM::CPropVariant prop;
switch (propID)
{
case kpidPackSize: if (_packSize_Defined) prop = _packSize; break;
case kpidSize: if (_unpackSize_Defined) prop = _unpackSize; break;
default: break;
}
prop.Detach(value);
return S_OK;
}
Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *))
{
COM_TRY_BEGIN
Close();
{
Byte buf[kMaxHeaderSize];
RINOK(ReadStream_FALSE(stream, buf, kMinHeaderSize))
if (IsArc_Lz4(buf, kMinHeaderSize) == k_IsArc_Res_NO)
return S_FALSE;
if (!_frameInfo.Parse(buf, kMinHeaderSize))
return S_FALSE;
// Read additional header bytes if needed
unsigned headerSize = _frameInfo.GetHeaderSize();
if (headerSize > kMinHeaderSize)
{
RINOK(ReadStream_FALSE(stream, buf + kMinHeaderSize, headerSize - kMinHeaderSize))
if (!_frameInfo.Parse(buf, headerSize))
return S_FALSE;
}
if (_frameInfo.ContentSizePresent)
{
_unpackSize = _frameInfo.ContentSize;
_unpackSize_Defined = true;
}
_isArc = true;
_stream = stream;
_seqStream = stream;
_needSeekToStart = true;
}
return S_OK;
COM_TRY_END
}
Z7_COM7F_IMF(CHandler::OpenSeq(ISequentialInStream *stream))
{
Close();
_isArc = true;
_seqStream = stream;
return S_OK;
}
Z7_COM7F_IMF(CHandler::Close())
{
_isArc = false;
_needSeekToStart = false;
_dataAfterEnd = false;
_needMoreInput = false;
_dataError = false;
_packSize_Defined = false;
_unpackSize_Defined = false;
_packSize = 0;
_unpackSize = 0;
_seqStream.Release();
_stream.Release();
return S_OK;
}
Z7_COM7F_IMF(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;
if (_packSize_Defined)
{
RINOK(extractCallback->SetTotal(_packSize))
}
Int32 opRes;
{
CMyComPtr<ISequentialOutStream> realOutStream;
const Int32 askMode = testMode ?
NExtract::NAskMode::kTest :
NExtract::NAskMode::kExtract;
RINOK(extractCallback->GetStream(0, &realOutStream, askMode))
if (!testMode && !realOutStream)
return S_OK;
RINOK(extractCallback->PrepareOperation(askMode))
if (_needSeekToStart)
{
if (!_stream)
return E_FAIL;
RINOK(InStream_SeekToBegin(_stream))
}
else
_needSeekToStart = true;
// Read and parse header
Byte header[kMaxHeaderSize];
RINOK(ReadStream_FALSE(_seqStream, header, kMinHeaderSize))
CFrameInfo frameInfo;
if (!frameInfo.Parse(header, kMinHeaderSize))
{
_isArc = false;
opRes = NExtract::NOperationResult::kIsNotArc;
}
else
{
unsigned headerSize = frameInfo.GetHeaderSize();
if (headerSize > kMinHeaderSize)
{
RINOK(ReadStream_FALSE(_seqStream, header + kMinHeaderSize, headerSize - kMinHeaderSize))
}
CMyComPtr2_Create<ISequentialOutStream, CDummyOutStream> outStream;
outStream->SetStream(realOutStream);
outStream->Init();
CMyComPtr2_Create<ICompressProgressInfo, CLocalProgress> lps;
lps->Init(extractCallback, true);
_dataAfterEnd = false;
_needMoreInput = false;
_dataError = false;
UInt64 inProcessed = headerSize;
UInt64 outProcessed = 0;
bool finished = false;
// Allocate buffers
Byte *compBuf = NULL;
Byte *decompBuf = NULL;
UInt32 blockMaxSize = frameInfo.BlockMaxSize;
compBuf = (Byte *)MyAlloc(blockMaxSize);
decompBuf = (Byte *)MyAlloc(blockMaxSize);
if (!compBuf || !decompBuf)
{
MyFree(compBuf);
MyFree(decompBuf);
return E_OUTOFMEMORY;
}
opRes = NExtract::NOperationResult::kOK;
// Process blocks
while (!finished)
{
// Read block size
Byte blockHeader[4];
HRESULT res = ReadStream_FALSE(_seqStream, blockHeader, 4);
if (res != S_OK)
{
_needMoreInput = true;
opRes = NExtract::NOperationResult::kUnexpectedEnd;
break;
}
inProcessed += 4;
UInt32 blockSize = GetUi32(blockHeader);
// End mark
if (blockSize == 0)
{
finished = true;
// Skip content checksum if present
if (frameInfo.ContentChecksum)
{
Byte checksum[4];
res = ReadStream_FALSE(_seqStream, checksum, 4);
if (res == S_OK)
inProcessed += 4;
}
break;
}
bool uncompressed = (blockSize & 0x80000000) != 0;
blockSize &= 0x7FFFFFFF;
if (blockSize > blockMaxSize)
{
_dataError = true;
opRes = NExtract::NOperationResult::kDataError;
break;
}
// Read block data
res = ReadStream_FALSE(_seqStream, compBuf, blockSize);
if (res != S_OK)
{
_needMoreInput = true;
opRes = NExtract::NOperationResult::kUnexpectedEnd;
break;
}
inProcessed += blockSize;
// Skip block checksum if present
if (frameInfo.BlockChecksum)
{
Byte checksum[4];
res = ReadStream_FALSE(_seqStream, checksum, 4);
if (res != S_OK)
{
_needMoreInput = true;
opRes = NExtract::NOperationResult::kUnexpectedEnd;
break;
}
inProcessed += 4;
}
// Decompress or copy
const Byte *outData;
SizeT outLen;
if (uncompressed)
{
// Uncompressed block - write directly from compBuf
outData = compBuf;
outLen = blockSize;
}
else
{
// Decompress
outLen = blockMaxSize;
SizeT srcConsumed;
SRes sres = Lz4Dec_DecodeBlock(compBuf, blockSize, decompBuf, &outLen, &srcConsumed);
if (sres != SZ_OK)
{
_dataError = true;
opRes = NExtract::NOperationResult::kDataError;
break;
}
outData = decompBuf;
}
// Write output
if (outLen > 0)
{
const HRESULT writeRes = WriteStream(outStream, outData, outLen);
if (writeRes != S_OK)
{
MyFree(compBuf);
MyFree(decompBuf);
return writeRes;
}
outProcessed += outLen;
}
// Progress
lps.Interface()->SetRatioInfo(&inProcessed, &outProcessed);
}
MyFree(compBuf);
MyFree(decompBuf);
_packSize = inProcessed;
_unpackSize = outProcessed;
_packSize_Defined = true;
_unpackSize_Defined = true;
}
}
return extractCallback->SetOperationResult(opRes);
COM_TRY_END
}
static const Byte k_Signature[] = { 0x04, 0x22, 0x4D, 0x18 };
REGISTER_ARC_I(
"lz4", "lz4 tlz4", "* .tar", 0x11,
k_Signature,
0,
NArcInfoFlags::kKeepName
, IsArc_Lz4)
}}

View file

@ -0,0 +1,329 @@
// LzipHandler.cpp
#include "StdAfx.h"
#include "../../Common/ComTry.h"
#include "../../Windows/PropVariant.h"
#include "../Common/ProgressUtils.h"
#include "../Common/RegisterArc.h"
#include "../Common/StreamUtils.h"
#include "../Compress/CopyCoder.h"
#include "../Compress/LzmaDecoder.h"
#include "Common/DummyOutStream.h"
#include "../../../C/CpuArch.h"
using namespace NWindows;
namespace NArchive {
namespace NLzip {
// Lzip member structure:
// Header (6 bytes): "LZIP" + version (1 byte) + dictionary_size (1 byte)
// LZMA stream
// Trailer (20 bytes): CRC32 (4 bytes) + data_size (8 bytes) + member_size (8 bytes)
static const UInt32 kHeaderSize = 6;
static const UInt32 kTrailerSize = 20;
// Lzip always uses these LZMA parameters: lc=3, lp=0, pb=2
// Encoded as: lc + lp*9 + pb*9*5 = 3 + 0 + 90 = 93 = 0x5D
static const Byte kLzmaLiteralProps = 0x5D;
static const Byte kSignature[] = { 'L', 'Z', 'I', 'P' };
static const Byte kSignatureSize = 4;
static inline UInt32 GetDictSize(Byte ds)
{
// Dictionary size formula from lzip specification:
// bits 4-0 (0x1F) contain the exponent (dictionary size = 2^exponent)
// bits 7-5 contain the numerator of the fraction to subtract
// dictionary_size = base_size - fraction * (base_size >> 4)
const unsigned exp = ds & 0x1F;
const UInt32 base = (UInt32)1 << exp;
const unsigned frac = ds >> 5;
return base - (frac * (base >> 4));
}
API_FUNC_static_IsArc IsArc_Lzip(const Byte *p, size_t size)
{
if (size < kHeaderSize)
return k_IsArc_Res_NEED_MORE;
if (memcmp(p, kSignature, kSignatureSize) != 0)
return k_IsArc_Res_NO;
const Byte version = p[4];
if (version != 1)
return k_IsArc_Res_NO; // Only version 1 is supported
const Byte ds = p[5];
// Valid dictionary size: 4 KiB to 512 MiB
// ds byte value encodes: exponent in bits 4-0, fraction in bits 7-5
// Minimum valid exponent is 12 (2^12 = 4 KiB)
// Maximum valid exponent is 29 (2^29 = 512 MiB)
const unsigned exp = ds & 0x1F;
if (exp < 12 || exp > 29)
return k_IsArc_Res_NO;
return k_IsArc_Res_YES;
}
}
Z7_CLASS_IMP_CHandler_IInArchive_1(
IArchiveOpenSeq
)
CMyComPtr<IInStream> _stream;
CMyComPtr<ISequentialInStream> _seqStream;
bool _isArc;
bool _needSeekToStart;
bool _dataAfterEnd;
bool _needMoreInput;
bool _packSize_Defined;
bool _unpackSize_Defined;
bool _numMembers_Defined;
UInt64 _packSize;
UInt64 _unpackSize;
UInt64 _numMembers;
Byte _version;
UInt32 _dictSize;
};
static const Byte kProps[] =
{
kpidSize,
kpidPackSize
};
static const Byte kArcProps[] =
{
kpidNumStreams
};
IMP_IInArchive_Props
IMP_IInArchive_ArcProps
Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
{
NCOM::CPropVariant prop;
switch (propID)
{
case kpidPhySize: if (_packSize_Defined) prop = _packSize; break;
case kpidUnpackSize: if (_unpackSize_Defined) prop = _unpackSize; break;
case kpidNumStreams: if (_numMembers_Defined) prop = _numMembers; break;
case kpidErrorFlags:
{
UInt32 v = 0;
if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;
if (_needMoreInput) v |= kpv_ErrorFlags_UnexpectedEnd;
if (_dataAfterEnd) v |= kpv_ErrorFlags_DataAfterEnd;
prop = v;
break;
}
default: break;
}
prop.Detach(value);
return S_OK;
}
Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
{
*numItems = 1;
return S_OK;
}
Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value))
{
NCOM::CPropVariant prop;
switch (propID)
{
case kpidPackSize: if (_packSize_Defined) prop = _packSize; break;
case kpidSize: if (_unpackSize_Defined) prop = _unpackSize; break;
default: break;
}
prop.Detach(value);
return S_OK;
}
Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *))
{
COM_TRY_BEGIN
Close();
{
Byte buf[kHeaderSize];
RINOK(ReadStream_FALSE(stream, buf, kHeaderSize))
if (IsArc_Lzip(buf, kHeaderSize) == k_IsArc_Res_NO)
return S_FALSE;
_version = buf[4];
_dictSize = GetDictSize(buf[5]);
_isArc = true;
_stream = stream;
_seqStream = stream;
_needSeekToStart = true;
}
return S_OK;
COM_TRY_END
}
Z7_COM7F_IMF(CHandler::OpenSeq(ISequentialInStream *stream))
{
Close();
_isArc = true;
_seqStream = stream;
return S_OK;
}
Z7_COM7F_IMF(CHandler::Close())
{
_isArc = false;
_needSeekToStart = false;
_dataAfterEnd = false;
_needMoreInput = false;
_packSize_Defined = false;
_unpackSize_Defined = false;
_numMembers_Defined = false;
_packSize = 0;
_version = 0;
_dictSize = 0;
_seqStream.Release();
_stream.Release();
return S_OK;
}
Z7_COM7F_IMF(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;
if (_packSize_Defined)
{
RINOK(extractCallback->SetTotal(_packSize))
}
Int32 opRes;
{
CMyComPtr<ISequentialOutStream> realOutStream;
const Int32 askMode = testMode ?
NExtract::NAskMode::kTest :
NExtract::NAskMode::kExtract;
RINOK(extractCallback->GetStream(0, &realOutStream, askMode))
if (!testMode && !realOutStream)
return S_OK;
RINOK(extractCallback->PrepareOperation(askMode))
if (_needSeekToStart)
{
if (!_stream)
return E_FAIL;
RINOK(InStream_SeekToBegin(_stream))
}
else
_needSeekToStart = true;
// Read header
Byte header[kHeaderSize];
RINOK(ReadStream_FALSE(_seqStream, header, kHeaderSize))
if (IsArc_Lzip(header, kHeaderSize) == k_IsArc_Res_NO)
{
_isArc = false;
opRes = NExtract::NOperationResult::kIsNotArc;
}
else
{
_version = header[4];
_dictSize = GetDictSize(header[5]);
// Construct LZMA properties (5 bytes): props_byte + dictionary_size (4 bytes LE)
Byte lzmaProps[5];
lzmaProps[0] = kLzmaLiteralProps; // lc=3, lp=0, pb=2
SetUi32(lzmaProps + 1, _dictSize);
CMyComPtr2_Create<ICompressCoder, NCompress::NLzma::CDecoder> decoder;
RINOK(decoder->SetDecoderProperties2(lzmaProps, 5))
decoder->FinishStream = true;
CMyComPtr2_Create<ISequentialOutStream, CDummyOutStream> outStream;
outStream->SetStream(realOutStream);
outStream->Init();
CMyComPtr2_Create<ICompressProgressInfo, CLocalProgress> lps;
lps->Init(extractCallback, true);
_dataAfterEnd = false;
_needMoreInput = false;
HRESULT result = decoder.Interface()->Code(_seqStream, outStream, NULL, NULL, lps);
if (result != S_FALSE && result != S_OK)
return result;
const UInt64 inProcessedSize = decoder->GetInputProcessedSize();
const UInt64 outProcessedSize = decoder->GetOutputProcessedSize();
_packSize = kHeaderSize + inProcessedSize + kTrailerSize;
_unpackSize = outProcessedSize;
_numMembers = 1;
_packSize_Defined = true;
_unpackSize_Defined = true;
_numMembers_Defined = true;
lps.Interface()->SetRatioInfo(&_packSize, &_unpackSize);
if (decoder->NeedsMoreInput())
{
_needMoreInput = true;
opRes = NExtract::NOperationResult::kUnexpectedEnd;
}
else if (result == S_FALSE)
{
opRes = NExtract::NOperationResult::kDataError;
}
else if (!decoder->CheckFinishStatus(true)) // Expect end marker
{
opRes = NExtract::NOperationResult::kDataError;
}
else
{
opRes = NExtract::NOperationResult::kOK;
}
}
}
return extractCallback->SetOperationResult(opRes);
COM_TRY_END
}
static const Byte k_Signature[] = { 'L', 'Z', 'I', 'P', 1 };
REGISTER_ARC_I(
"lzip", "lz tlz", "* .tar", 0x10,
k_Signature,
0,
NArcInfoFlags::kKeepName
, IsArc_Lzip)
}}

View file

@ -81,6 +81,7 @@ AR_OBJS = \
$O\IhexHandler.obj \
$O\LpHandler.obj \
$O\LzhHandler.obj \
$O\LzipHandler.obj \
$O\LzmaHandler.obj \
$O\MachoHandler.obj \
$O\MbrHandler.obj \

View file

@ -118,6 +118,8 @@ AR_OBJS = \
$O/IhexHandler.o \
$O/LpHandler.o \
$O/LzhHandler.o \
$O/Lz4Handler.o \
$O/LzipHandler.o \
$O/LzmaHandler.o \
$O/MachoHandler.o \
$O/MbrHandler.o \
@ -336,6 +338,7 @@ C_OBJS = \
$O/Delta.o \
$O/HuffEnc.o \
$O/LzFind.o \
$O/Lz4Dec.o \
$O/Lzma2Dec.o \
$O/Lzma2DecMt.o \
$O/Lzma2Enc.o \