This commit is contained in:
Igor Pavlov
2017-08-29 20:49:43 +01:00
committed by Kornel
parent 2efa10565a
commit b5dc853b24
110 changed files with 4714 additions and 1700 deletions

View File

@@ -370,6 +370,17 @@ HRESULT CEncoder::Encode(
resetInitVector->ResetInitVector();
}
{
CMyComPtr<ICompressSetCoderPropertiesOpt> optProps;
coder->QueryInterface(IID_ICompressSetCoderPropertiesOpt, (void **)&optProps);
if (optProps)
{
PROPID propID = NCoderPropID::kExpectedDataSize;
NWindows::NCOM::CPropVariant prop = (UInt64)unpackSize;
RINOK(optProps->SetCoderPropertiesOpt(&propID, &prop, 1));
}
}
CMyComPtr<ICompressWriteCoderProperties> writeCoderProperties;
coder->QueryInterface(IID_ICompressWriteCoderProperties, (void **)&writeCoderProperties);
@@ -380,7 +391,7 @@ HRESULT CEncoder::Encode(
CDynBufSeqOutStream *outStreamSpec = new CDynBufSeqOutStream;
CMyComPtr<ISequentialOutStream> dynOutStream(outStreamSpec);
outStreamSpec->Init();
writeCoderProperties->WriteCoderProperties(dynOutStream);
RINOK(writeCoderProperties->WriteCoderProperties(dynOutStream));
outStreamSpec->CopyToBuffer(props);
}
else

View File

@@ -80,14 +80,17 @@ STDMETHODIMP CFolderInStream::Read(void *data, UInt32 size, UInt32 *processedSiz
{
if (_stream)
{
UInt32 processed2;
RINOK(_stream->Read(data, size, &processed2));
if (processed2 != 0)
UInt32 cur = size;
const UInt32 kMax = (UInt32)1 << 20;
if (cur > kMax)
cur = kMax;
RINOK(_stream->Read(data, cur, &cur));
if (cur != 0)
{
_crc = CrcUpdate(_crc, data, processed2);
_pos += processed2;
_crc = CrcUpdate(_crc, data, cur);
_pos += cur;
if (processedSize)
*processedSize = processed2;
*processedSize = cur;
return S_OK;
}

View File

@@ -515,7 +515,7 @@ HRESULT COutArchive::EncodeStream(
outFolders.FolderUnpackCRCs.Vals.Add(CrcCalc(data, data.Size()));
// outFolders.NumUnpackStreamsVector.Add(1);
UInt64 dataSize64 = data.Size();
UInt64 unpackSize;
UInt64 unpackSize = data.Size();
RINOK(encoder.Encode(
EXTERNAL_CODECS_LOC_VARS
stream,

View File

@@ -2171,6 +2171,7 @@ HRESULT Update(
#endif
}
curUnpackSize = sizeToEncode;
HRESULT encodeRes = encoder.Encode(
EXTERNAL_CODECS_LOC_VARS
@@ -2358,7 +2359,9 @@ HRESULT Update(
inStreamSpec->Init(updateCallback, &indices[i], numSubFiles);
unsigned startPackIndex = newDatabase.PackSizes.Size();
UInt64 curFolderUnpackSize;
UInt64 curFolderUnpackSize = totalSize;
// curFolderUnpackSize = (UInt64)(Int64)-1;
RINOK(encoder.Encode(
EXTERNAL_CODECS_LOC_VARS
solidInStream,

View File

@@ -461,8 +461,8 @@ bool CHeader::Parse(const Byte *p)
if (Is64Bit())
{
HI_32(150, NumBlocks);
// HI_32(154, NumBlocksSuper);
HI_32(0x150, NumBlocks);
// HI_32(0x154, NumBlocksSuper);
HI_32(0x158, NumFreeBlocks);
}

View File

@@ -2489,7 +2489,7 @@ void CInArchive::DetectNsisType(const CBlockHeader &bh, const Byte *p)
if (c2 == NS_3_CODE_VAR)
// if (c2 <= NS_3_CODE_SKIP && c2 != NS_3_CODE_SHELL && c2 != 1)
{
if ((strData[i+ 2] & 0x80) != 0)
if ((strData[i + 2] & 0x80) != 0)
{
// const char *p2 = (const char *)(strData + i + 1);
// p2 = p2;
@@ -5048,6 +5048,12 @@ HRESULT CInArchive::Parse()
DetectNsisType(bhEntries, _data + bhEntries.Offset);
Decoder.IsNsisDeflate = (NsisType != k_NsisType_Nsis3);
// some NSIS files (that are not detected as k_NsisType_Nsis3)
// use original (non-NSIS) Deflate
// How to detect these cases?
// Decoder.IsNsisDeflate = false;
#ifdef NSIS_SCRIPT

View File

@@ -341,15 +341,19 @@ bool CVolInfo::Parse(const Byte *p, unsigned size)
struct CAttr
{
UInt32 Type;
Byte NonResident;
// Non-Resident
Byte CompressionUnit;
// UInt32 Len;
UString2 Name;
// UInt16 Flags;
// UInt16 Instance;
CByteBuffer Data;
Byte NonResident;
// Non-Resident
Byte CompressionUnit;
UInt64 LowVcn;
UInt64 HighVcn;
UInt64 AllocatedSize;
@@ -408,15 +412,16 @@ UInt32 CAttr::Parse(const Byte *p, unsigned size)
return 8; // required size is 4, but attributes are 8 bytes aligned. So we return 8
if (size < 0x18)
return 0;
PRF(printf(" T=%2X", Type));
UInt32 len = Get32(p + 0x04);
UInt32 len = Get32(p + 4);
PRF(printf(" L=%3d", len));
if (len > size)
return 0;
if ((len & 7) != 0)
return 0;
NonResident = p[0x08];
NonResident = p[8];
{
unsigned nameLen = p[9];
UInt32 nameOffset = Get16(p + 0x0A);
@@ -437,6 +442,7 @@ UInt32 CAttr::Parse(const Byte *p, unsigned size)
UInt32 dataSize;
UInt32 offs;
if (NonResident)
{
if (len < 0x40)
@@ -472,16 +478,19 @@ UInt32 CAttr::Parse(const Byte *p, unsigned size)
{
if (len < 0x18)
return 0;
PRF(printf(" RES"));
dataSize = Get32(p + 0x10);
PRF(printf(" dataSize=%3d", dataSize));
offs = Get16(p + 0x14);
G32(p + 0x10, dataSize);
G16(p + 0x14, offs);
// G16(p + 0x16, ResidentFlags);
PRF(printf(" RES"));
PRF(printf(" dataSize=%3d", dataSize));
// PRF(printf(" ResFlags=%4X", ResidentFlags));
}
if (offs > len || dataSize > len || len - dataSize < offs)
return 0;
Data.CopyFrom(p + offs, dataSize);
#ifdef SHOW_DEBUG_INFO
PRF(printf(" : "));
for (unsigned i = 0; i < Data.Size(); i++)
@@ -489,16 +498,19 @@ UInt32 CAttr::Parse(const Byte *p, unsigned size)
PRF(printf(" %02X", (unsigned)Data[i]));
}
#endif
return len;
}
bool CAttr::ParseExtents(CRecordVector<CExtent> &extents, UInt64 numClustersMax, unsigned compressionUnit) const
{
const Byte *p = Data;
unsigned size = (unsigned)Data.Size();
UInt64 vcn = LowVcn;
UInt64 lcn = 0;
UInt64 highVcn1 = HighVcn + 1;
const UInt64 highVcn1 = HighVcn + 1;
if (LowVcn != extents.Back().Virt || highVcn1 > (UInt64)1 << 63)
return false;
@@ -528,15 +540,30 @@ bool CAttr::ParseExtents(CRecordVector<CExtent> &extents, UInt64 numClustersMax,
if ((highVcn1 - vcn) < vSize)
return false;
CExtent e;
e.Virt = vcn;
vcn += vSize;
num = (b >> 4) & 0xF;
if (num > 8 || num > size)
return false;
CExtent e;
e.Virt = vcn;
if (num == 0)
{
// Sparse
/* if Unit is compressed, it can have many Elements for each compressed Unit:
and last Element for unit MUST be without LCN.
Element 0: numCompressedClusters2, LCN_0
Element 1: numCompressedClusters2, LCN_1
...
Last Element : (16 - total_clusters_in_previous_elements), no LCN
*/
// sparse is not allowed for (compressionUnit == 0) ? Why ?
if (compressionUnit == 0)
return false;
e.Phy = kEmptyExtent;
}
else
@@ -553,9 +580,10 @@ bool CAttr::ParseExtents(CRecordVector<CExtent> &extents, UInt64 numClustersMax,
return false;
e.Phy = lcn;
}
extents.Add(e);
vcn += vSize;
}
CExtent e;
e.Phy = kEmptyExtent;
e.Virt = vcn;
@@ -563,10 +591,11 @@ bool CAttr::ParseExtents(CRecordVector<CExtent> &extents, UInt64 numClustersMax,
return (highVcn1 == vcn);
}
static const UInt64 kEmptyTag = (UInt64)(Int64)-1;
static const unsigned kNumCacheChunksLog = 1;
static const size_t kNumCacheChunks = (1 << kNumCacheChunksLog);
static const size_t kNumCacheChunks = (size_t)1 << kNumCacheChunksLog;
class CInStream:
public IInStream,
@@ -734,24 +763,27 @@ STDMETHODIMP CInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
while (_curRem == 0)
{
UInt64 cacheTag = _virtPos >> _chunkSizeLog;
UInt32 cacheIndex = (UInt32)cacheTag & (kNumCacheChunks - 1);
const UInt64 cacheTag = _virtPos >> _chunkSizeLog;
const size_t cacheIndex = (size_t)cacheTag & (kNumCacheChunks - 1);
if (_tags[cacheIndex] == cacheTag)
{
UInt32 chunkSize = (UInt32)1 << _chunkSizeLog;
UInt32 offset = (UInt32)_virtPos & (chunkSize - 1);
UInt32 cur = MyMin(chunkSize - offset, size);
const size_t chunkSize = (size_t)1 << _chunkSizeLog;
const size_t offset = (size_t)_virtPos & (chunkSize - 1);
size_t cur = chunkSize - offset;
if (cur > size)
cur = size;
memcpy(data, _outBuf + (cacheIndex << _chunkSizeLog) + offset, cur);
*processedSize = cur;
*processedSize = (UInt32)cur;
_virtPos += cur;
return S_OK;
}
PRF2(printf("\nVirtPos = %6d", _virtPos));
UInt32 comprUnitSize = (UInt32)1 << CompressionUnit;
UInt64 virtBlock = _virtPos >> BlockSizeLog;
UInt64 virtBlock2 = virtBlock & ~((UInt64)comprUnitSize - 1);
const UInt32 comprUnitSize = (UInt32)1 << CompressionUnit;
const UInt64 virtBlock = _virtPos >> BlockSizeLog;
const UInt64 virtBlock2 = virtBlock & ~((UInt64)comprUnitSize - 1);
unsigned left = 0, right = Extents.Size();
for (;;)
@@ -766,7 +798,7 @@ STDMETHODIMP CInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
}
bool isCompressed = false;
UInt64 virtBlock2End = virtBlock2 + comprUnitSize;
const UInt64 virtBlock2End = virtBlock2 + comprUnitSize;
if (CompressionUnit != 0)
for (unsigned i = left; i < Extents.Size(); i++)
{
@@ -802,7 +834,9 @@ STDMETHODIMP CInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
_curRem = next - _virtPos;
break;
}
bool thereArePhy = false;
for (unsigned i2 = left; i2 < Extents.Size(); i2++)
{
const CExtent &e = Extents[i2];
@@ -814,6 +848,7 @@ STDMETHODIMP CInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
break;
}
}
if (!thereArePhy)
{
_curRem = (Extents[i + 1].Virt << BlockSizeLog) - _virtPos;
@@ -823,6 +858,7 @@ STDMETHODIMP CInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
size_t offs = 0;
UInt64 curVirt = virtBlock2;
for (i = left; i < Extents.Size(); i++)
{
const CExtent &e = Extents[i];
@@ -845,6 +881,7 @@ STDMETHODIMP CInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
_physPos += compressed;
offs += compressed;
}
size_t destLenMax = GetCuSize();
size_t destLen = destLenMax;
const UInt64 rem = Size - (virtBlock2 << BlockSizeLog);
@@ -863,6 +900,7 @@ STDMETHODIMP CInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
return S_FALSE;
}
}
if (size > _curRem)
size = (UInt32)_curRem;
HRESULT res = S_OK;
@@ -913,6 +951,12 @@ static HRESULT DataParseExtents(unsigned clusterSizeLog, const CObjectVector<CAt
const CAttr &attr0 = attrs[attrIndex];
/*
if (attrs[attrIndexLim - 1].HighVcn + 1 != (attr0.AllocatedSize >> clusterSizeLog))
{
}
*/
if (attr0.AllocatedSize < attr0.Size ||
(attrs[attrIndexLim - 1].HighVcn + 1) != (attr0.AllocatedSize >> clusterSizeLog) ||
(attr0.AllocatedSize & ((1 << clusterSizeLog) - 1)) != 0)

View File

@@ -1363,7 +1363,7 @@ static const Byte kProps[] =
kpidCharacts,
kpidSymLink,
kpidHardLink,
kpidCopyLink,
kpidCopyLink
};

View File

@@ -60,6 +60,7 @@ UInt64 Get64b(const Byte *p, bool be) { return be ? GetBe64(p) : GetUi64(p); }
static const UInt32 kSignature32_LE = 0x73717368;
static const UInt32 kSignature32_BE = 0x68737173;
static const UInt32 kSignature32_LZ = 0x71736873;
static const UInt32 kSignature32_B2 = 0x73687371;
#define kMethod_ZLIB 1
#define kMethod_LZMA 2
@@ -225,6 +226,7 @@ struct CHeader
case kSignature32_LE: break;
case kSignature32_BE: be = true; break;
case kSignature32_LZ: SeveralMethods = true; break;
case kSignature32_B2: SeveralMethods = true; be = true; break;
default: return false;
}
GET_32 (4, NumInodes);
@@ -2258,7 +2260,8 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
static const Byte k_Signature[] = {
4, 'h', 's', 'q', 's',
4, 's', 'q', 's', 'h',
4, 's', 'h', 's', 'q' };
4, 's', 'h', 's', 'q',
4, 'q', 's', 'h', 's' };
REGISTER_ARC_I(
"SquashFS", "squashfs", 0, 0xD2,

View File

@@ -26,24 +26,25 @@ static void MyStrNCpy(char *dest, const char *src, unsigned size)
}
}
static bool OctalToNumber(const char *srcString, unsigned size, UInt64 &res)
static bool OctalToNumber(const char *srcString, unsigned size, UInt64 &res, bool allowEmpty = false)
{
res = 0;
char sz[32];
MyStrNCpy(sz, srcString, size);
sz[size] = 0;
const char *end;
unsigned i;
for (i = 0; sz[i] == ' '; i++);
if (sz[i] == 0)
return allowEmpty;
res = ConvertOctStringToUInt64(sz + i, &end);
if (end == sz + i)
return false;
return (*end == ' ' || *end == 0);
}
static bool OctalToNumber32(const char *srcString, unsigned size, UInt32 &res)
static bool OctalToNumber32(const char *srcString, unsigned size, UInt32 &res, bool allowEmpty = false)
{
UInt64 res64;
if (!OctalToNumber(srcString, size, res64))
if (!OctalToNumber(srcString, size, res64, allowEmpty))
return false;
res = (UInt32)res64;
return (res64 <= 0xFFFFFFFF);
@@ -123,7 +124,8 @@ API_FUNC_IsArc IsArc_Tar(const Byte *p2, size_t size)
p += NFileHeader::kNameSize;
UInt32 mode;
CHECK(OctalToNumber32(p, 8, mode)); p += 8;
// we allow empty Mode value for LongName prefix items
CHECK(OctalToNumber32(p, 8, mode, true)); p += 8;
// if (!OctalToNumber32(p, 8, item.UID)) item.UID = 0;
p += 8;
@@ -194,7 +196,8 @@ static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemE
(item.Name.Len() == NFileHeader::kNameSize ||
item.Name.Len() == NFileHeader::kNameSize - 1);
RIF(OctalToNumber32(p, 8, item.Mode)); p += 8;
// we allow empty Mode value for LongName prefix items
RIF(OctalToNumber32(p, 8, item.Mode, true)); p += 8;
if (!OctalToNumber32(p, 8, item.UID)) item.UID = 0; p += 8;
if (!OctalToNumber32(p, 8, item.GID)) item.GID = 0; p += 8;

View File

@@ -7,8 +7,11 @@
#include "../../Common/ComTry.h"
#include "../../Common/Defs.h"
#include "../../Common/IntToString.h"
#include "../../Common/MyBuffer.h"
#include "../../Common/StringToInt.h"
#include "../../Windows/PropVariant.h"
#include "../../Windows/System.h"
#include "../Common/CWrappers.h"
#include "../Common/ProgressUtils.h"
@@ -33,9 +36,19 @@ namespace NXz {
#define k_LZMA2_Name "LZMA2"
struct CBlockInfo
{
unsigned StreamFlags;
UInt64 PackPos;
UInt64 PackSize; // pure value from Index record, it doesn't include pad zeros
UInt64 UnpackPos;
};
class CHandler:
public IInArchive,
public IArchiveOpenSeq,
public IInArchiveGetStream,
#ifndef EXTRACT_ONLY
public IOutArchive,
public ISetProperties,
@@ -48,9 +61,7 @@ class CHandler:
bool _isArc;
bool _needSeekToStart;
bool _phySize_Defined;
CMyComPtr<IInStream> _stream;
CMyComPtr<ISequentialInStream> _seqStream;
bool _firstBlockWasRead;
AString _methodsString;
@@ -58,8 +69,20 @@ class CHandler:
UInt32 _filterId;
UInt64 _numSolidBytes;
HRESULT SetSolidFromString(const UString &s);
HRESULT SetSolidFromPROPVARIANT(const PROPVARIANT &value);
HRESULT SetProperty(const wchar_t *name, const PROPVARIANT &value);
void InitSolid()
{
_numSolidBytes = XZ_PROPS__BLOCK_SIZE__AUTO;
}
void Init()
{
InitSolid();
_filterId = 0;
CMultiMethodProps::Init();
}
@@ -83,6 +106,7 @@ class CHandler:
public:
MY_QUERYINTERFACE_BEGIN2(IInArchive)
MY_QUERYINTERFACE_ENTRY(IArchiveOpenSeq)
MY_QUERYINTERFACE_ENTRY(IInArchiveGetStream)
#ifndef EXTRACT_ONLY
MY_QUERYINTERFACE_ENTRY(IOutArchive)
MY_QUERYINTERFACE_ENTRY(ISetProperties)
@@ -92,22 +116,45 @@ public:
INTERFACE_IInArchive(;)
STDMETHOD(OpenSeq)(ISequentialInStream *stream);
STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
#ifndef EXTRACT_ONLY
INTERFACE_IOutArchive(;)
STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps);
#endif
size_t _blocksArraySize;
CBlockInfo *_blocks;
UInt64 _maxBlocksSize;
CMyComPtr<IInStream> _stream;
CMyComPtr<ISequentialInStream> _seqStream;
CXzBlock _firstBlock;
CHandler();
~CHandler();
HRESULT SeekToPackPos(UInt64 pos)
{
return _stream->Seek(pos, STREAM_SEEK_SET, NULL);
}
};
CHandler::CHandler()
CHandler::CHandler():
_blocks(NULL),
_blocksArraySize(0)
{
#ifndef EXTRACT_ONLY
Init();
#endif
}
CHandler::~CHandler()
{
MyFree(_blocks);
}
static const Byte kProps[] =
{
@@ -120,7 +167,9 @@ static const Byte kArcProps[] =
{
kpidMethod,
kpidNumStreams,
kpidNumBlocks
kpidNumBlocks,
kpidClusterSize,
kpidCharacts
};
IMP_IInArchive_Props
@@ -177,7 +226,7 @@ static const CMethodNamePair g_NamePairs[] =
{ XZ_ID_LZMA2, "LZMA2" }
};
static AString GetMethodString(const CXzFilter &f)
static void AddMethodString(AString &s, const CXzFilter &f)
{
const char *p = NULL;
for (unsigned i = 0; i < ARRAY_SIZE(g_NamePairs); i++)
@@ -193,7 +242,7 @@ static AString GetMethodString(const CXzFilter &f)
p = temp;
}
AString s (p);
s += p;
if (f.propsSize > 0)
{
@@ -210,13 +259,6 @@ static AString GetMethodString(const CXzFilter &f)
s += ']';
}
}
return s;
}
static void AddString(AString &dest, const AString &src)
{
dest.Add_Space_if_NotEmpty();
dest += src;
}
static const char * const kChecks[] =
@@ -239,27 +281,24 @@ static const char * const kChecks[] =
, NULL
};
static AString GetCheckString(const CXzs &xzs)
static void AddCheckString(AString &s, const CXzs &xzs)
{
size_t i;
UInt32 mask = 0;
for (i = 0; i < xzs.num; i++)
mask |= ((UInt32)1 << XzFlags_GetCheckType(xzs.streams[i].flags));
AString s;
for (i = 0; i <= XZ_CHECK_MASK; i++)
if (((mask >> i) & 1) != 0)
{
AString s2;
s.Add_Space_if_NotEmpty();
if (kChecks[i])
s2 = kChecks[i];
s += kChecks[i];
else
{
s2 = "Check-";
s2.Add_UInt32((UInt32)i);
s += "Check-";
s.Add_UInt32((UInt32)i);
}
AddString(s, s2);
}
return s;
}
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
@@ -272,11 +311,26 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
case kpidNumStreams: if (_stat.NumStreams_Defined) prop = _stat.NumStreams; break;
case kpidNumBlocks: if (_stat.NumBlocks_Defined) prop = _stat.NumBlocks; break;
case kpidUnpackSize: if (_stat.UnpackSize_Defined) prop = _stat.OutSize; break;
case kpidClusterSize: if (_stat.NumBlocks_Defined && _stat.NumBlocks > 1) prop = _maxBlocksSize; break;
case kpidCharacts:
if (_firstBlockWasRead)
{
AString s;
if (XzBlock_HasPackSize(&_firstBlock))
s.Add_OptSpaced("BlockPackSize");
if (XzBlock_HasUnpackSize(&_firstBlock))
s.Add_OptSpaced("BlockUnpackSize");
if (!s.IsEmpty())
prop = s;
}
break;
case kpidMethod: if (!_methodsString.IsEmpty()) prop = _methodsString; break;
case kpidErrorFlags:
{
UInt32 v = 0;
if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;;
if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;
if (_stat.UnexpectedEnd) v |= kpv_ErrorFlags_UnexpectedEnd;
if (_stat.DataAfterEnd) v |= kpv_ErrorFlags_DataAfterEnd;
if (_stat.HeadersError) v |= kpv_ErrorFlags_HeadersError;
@@ -284,6 +338,13 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
if (_stat.DataError) v |= kpv_ErrorFlags_DataError;
if (_stat.CrcError) v |= kpv_ErrorFlags_CrcError;
prop = v;
break;
}
case kpidMainSubfile:
{
// if (_blocks) prop = (UInt32)0;
break;
}
}
prop.Detach(value);
@@ -409,9 +470,15 @@ HRESULT CHandler::Open2(IInStream *inStream, /* UInt32 flags, */ IArchiveOpenCal
SRes res2 = XzBlock_ReadHeader(&block, &inStreamWrap.vt, &isIndex, &headerSizeRes);
if (res2 == SZ_OK && !isIndex)
{
_firstBlockWasRead = true;
_firstBlock = block;
unsigned numFilters = XzBlock_GetNumFilters(&block);
for (unsigned i = 0; i < numFilters; i++)
AddString(_methodsString, GetMethodString(block.filters[i]));
{
_methodsString.Add_Space_if_NotEmpty();
AddMethodString(_methodsString, block.filters[i]);
}
}
}
}
@@ -422,7 +489,7 @@ HRESULT CHandler::Open2(IInStream *inStream, /* UInt32 flags, */ IArchiveOpenCal
RINOK(callback->SetTotal(NULL, &_stat.PhySize));
}
CSeekInStreamWrap inStreamImp;;
CSeekInStreamWrap inStreamImp;
inStreamImp.Init(inStream);
@@ -460,7 +527,64 @@ HRESULT CHandler::Open2(IInStream *inStream, /* UInt32 flags, */ IArchiveOpenCal
_stat.NumBlocks = Xzs_GetNumBlocks(&xzs.p);
_stat.NumBlocks_Defined = true;
AddString(_methodsString, GetCheckString(xzs.p));
AddCheckString(_methodsString, xzs.p);
const size_t numBlocks = (size_t)_stat.NumBlocks + 1;
const size_t bytesAlloc = numBlocks * sizeof(CBlockInfo);
if (bytesAlloc / sizeof(CBlockInfo) == _stat.NumBlocks + 1)
{
_blocks = (CBlockInfo *)MyAlloc(bytesAlloc);
if (_blocks)
{
unsigned blockIndex = 0;
UInt64 unpackPos = 0;
for (size_t si = xzs.p.num; si != 0;)
{
si--;
const CXzStream &str = xzs.p.streams[si];
UInt64 packPos = str.startOffset + XZ_STREAM_HEADER_SIZE;
for (size_t bi = 0; bi < str.numBlocks; bi++)
{
const CXzBlockSizes &bs = str.blocks[bi];
const UInt64 packSizeAligned = bs.totalSize + ((0 - (unsigned)bs.totalSize) & 3);
if (bs.unpackSize != 0)
{
if (blockIndex >= _stat.NumBlocks)
return E_FAIL;
CBlockInfo &block = _blocks[blockIndex++];
block.StreamFlags = str.flags;
block.PackSize = bs.totalSize; // packSizeAligned;
block.PackPos = packPos;
block.UnpackPos = unpackPos;
}
packPos += packSizeAligned;
unpackPos += bs.unpackSize;
if (_maxBlocksSize < bs.unpackSize)
_maxBlocksSize = bs.unpackSize;
}
}
/*
if (blockIndex != _stat.NumBlocks)
{
// there are Empty blocks;
}
*/
if (_stat.OutSize != unpackPos)
return E_FAIL;
CBlockInfo &block = _blocks[blockIndex++];
block.StreamFlags = 0;
block.PackSize = 0;
block.PackPos = 0;
block.UnpackPos = unpackPos;
_blocksArraySize = blockIndex;
}
}
}
else
{
@@ -474,6 +598,8 @@ HRESULT CHandler::Open2(IInStream *inStream, /* UInt32 flags, */ IArchiveOpenCal
return S_OK;
}
STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *callback)
{
COM_TRY_BEGIN
@@ -499,39 +625,297 @@ STDMETHODIMP CHandler::Close()
_isArc = false;
_needSeekToStart = false;
_phySize_Defined = false;
_firstBlockWasRead = false;
_methodsString.Empty();
_stream.Release();
_seqStream.Release();
MyFree(_blocks);
_blocks = NULL;
_blocksArraySize = 0;
_maxBlocksSize = 0;
return S_OK;
}
struct CXzUnpackerCPP2
{
Byte *InBuf;
// Byte *OutBuf;
CXzUnpacker p;
CXzUnpackerCPP2();
~CXzUnpackerCPP2();
};
CXzUnpackerCPP2::CXzUnpackerCPP2(): InBuf(NULL)
// , OutBuf(NULL)
{
XzUnpacker_Construct(&p, &g_Alloc);
}
CXzUnpackerCPP2::~CXzUnpackerCPP2()
{
XzUnpacker_Free(&p);
MidFree(InBuf);
// MidFree(OutBuf);
}
class CInStream:
public IInStream,
public CMyUnknownImp
{
public:
UInt64 _virtPos;
UInt64 Size;
UInt64 _cacheStartPos;
size_t _cacheSize;
CByteBuffer _cache;
// UInt64 _startPos;
CXzUnpackerCPP2 xz;
void InitAndSeek()
{
_virtPos = 0;
_cacheStartPos = 0;
_cacheSize = 0;
// _startPos = startPos;
}
CHandler *_handlerSpec;
CMyComPtr<IUnknown> _handler;
MY_UNKNOWN_IMP1(IInStream)
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
~CInStream();
};
CInStream::~CInStream()
{
// _cache.Free();
}
size_t FindBlock(const CBlockInfo *blocks, size_t numBlocks, UInt64 pos)
{
size_t left = 0, right = numBlocks;
for (;;)
{
size_t mid = (left + right) / 2;
if (mid == left)
return left;
if (pos < blocks[mid].UnpackPos)
right = mid;
else
left = mid;
}
}
static HRESULT DecodeBlock(CXzUnpackerCPP2 &xzu,
ISequentialInStream *seqInStream,
unsigned streamFlags,
UInt64 packSize, // pure size from Index record, it doesn't include pad zeros
size_t unpackSize, Byte *dest
// , ICompressProgressInfo *progress
)
{
const size_t kInBufSize = (size_t)1 << 16;
XzUnpacker_Init(&xzu.p);
if (!xzu.InBuf)
{
xzu.InBuf = (Byte *)MidAlloc(kInBufSize);
if (!xzu.InBuf)
return E_OUTOFMEMORY;
}
xzu.p.streamFlags = (UInt16)streamFlags;
XzUnpacker_PrepareToRandomBlockDecoding(&xzu.p);
const UInt64 packSizeAligned = packSize + ((0 - (unsigned)packSize) & 3);
UInt64 packRem = packSizeAligned;
UInt32 inSize = 0;
SizeT inPos = 0;
SizeT outPos = 0;
HRESULT readRes = S_OK;
for (;;)
{
if (inPos == inSize && readRes == S_OK)
{
inPos = 0;
inSize = 0;
UInt32 rem = kInBufSize;
if (rem > packRem)
rem = (UInt32)packRem;
if (rem != 0)
readRes = seqInStream->Read(xzu.InBuf, rem, &inSize);
}
SizeT inLen = inSize - inPos;
SizeT outLen = unpackSize - outPos;
ECoderStatus status;
SRes res = XzUnpacker_Code(&xzu.p,
dest + outPos, &outLen,
xzu.InBuf + inPos, &inLen,
CODER_FINISH_END, &status);
// return E_OUTOFMEMORY;
// res = SZ_ERROR_CRC;
if (res != SZ_OK)
{
if (res == SZ_ERROR_CRC)
return S_FALSE;
return SResToHRESULT(res);
}
inPos += inLen;
outPos += outLen;
packRem -= inLen;
Bool blockFinished = XzUnpacker_IsBlockFinished(&xzu.p);
if ((inLen == 0 && outLen == 0) || blockFinished)
{
if (packRem != 0 || !blockFinished || unpackSize != outPos)
return S_FALSE;
if (XzUnpacker_GetPackSizeForIndex(&xzu.p) != packSize)
return S_FALSE;
return S_OK;
}
}
}
STDMETHODIMP CInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
{
COM_TRY_BEGIN
if (processedSize)
*processedSize = 0;
if (size == 0)
return S_OK;
{
if (_virtPos >= Size)
return S_OK; // (Size == _virtPos) ? S_OK: E_FAIL;
{
UInt64 rem = Size - _virtPos;
if (size > rem)
size = (UInt32)rem;
}
}
if (size == 0)
return S_OK;
if (_virtPos < _cacheStartPos || _virtPos >= _cacheStartPos + _cacheSize)
{
size_t bi = FindBlock(_handlerSpec->_blocks, _handlerSpec->_blocksArraySize, _virtPos);
const CBlockInfo &block = _handlerSpec->_blocks[bi];
const UInt64 unpackSize = _handlerSpec->_blocks[bi + 1].UnpackPos - block.UnpackPos;
if (_cache.Size() < unpackSize)
return E_FAIL;
_cacheSize = 0;
RINOK(_handlerSpec->SeekToPackPos(block.PackPos));
RINOK(DecodeBlock(xz, _handlerSpec->_seqStream, block.StreamFlags, block.PackSize,
(size_t)unpackSize, _cache));
_cacheStartPos = block.UnpackPos;
_cacheSize = (size_t)unpackSize;
}
{
size_t offset = (size_t)(_virtPos - _cacheStartPos);
size_t rem = _cacheSize - offset;
if (size > rem)
size = (UInt32)rem;
memcpy(data, _cache + offset, size);
_virtPos += size;
if (processedSize)
*processedSize = size;
return S_OK;
}
COM_TRY_END
}
STDMETHODIMP CInStream::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;
}
class CSeekToSeqStream:
public IInStream,
public CMyUnknownImp
{
public:
CMyComPtr<ISequentialInStream> Stream;
MY_UNKNOWN_IMP1(IInStream)
static const UInt64 kMaxBlockSize_for_GetStream = (UInt64)1 << 40;
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
};
STDMETHODIMP CSeekToSeqStream::Read(void *data, UInt32 size, UInt32 *processedSize)
STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
{
return Stream->Read(data, size, processedSize);
COM_TRY_BEGIN
*stream = NULL;
if (index != 0)
return E_INVALIDARG;
if (!_stat.UnpackSize_Defined
|| _maxBlocksSize > kMaxBlockSize_for_GetStream
|| _maxBlocksSize != (size_t)_maxBlocksSize)
return S_FALSE;
UInt64 physSize = (UInt64)(sizeof(size_t)) << 29;
bool ramSize_Defined = NSystem::GetRamSize(physSize);
if (ramSize_Defined)
{
if (_maxBlocksSize > physSize / 4)
return S_FALSE;
}
CInStream *spec = new CInStream;
CMyComPtr<ISequentialInStream> specStream = spec;
spec->_cache.Alloc((size_t)_maxBlocksSize);
spec->_handlerSpec = this;
spec->_handler = (IInArchive *)this;
spec->Size = _stat.OutSize;
spec->InitAndSeek();
*stream = specStream.Detach();
return S_OK;
COM_TRY_END
}
STDMETHODIMP CSeekToSeqStream::Seek(Int64, UInt32, UInt64 *) { return E_NOTIMPL; }
@@ -584,6 +968,8 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
COM_TRY_END
}
#ifndef EXTRACT_ONLY
STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType)
@@ -592,16 +978,15 @@ STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType)
return S_OK;
}
STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
IArchiveUpdateCallback *updateCallback)
{
COM_TRY_BEGIN
if (numItems == 0)
{
CSeqOutStreamWrap seqOutStream;
seqOutStream.Init(outStream);
SRes res = Xz_EncodeEmpty(&seqOutStream.vt);
return SResToHRESULT(res);
@@ -641,82 +1026,76 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
NCompress::NXz::CEncoder *encoderSpec = new NCompress::NXz::CEncoder;
CMyComPtr<ICompressCoder> encoder = encoderSpec;
CLzma2EncProps &lzma2Props = encoderSpec->_lzma2Props;
CXzProps &xzProps = encoderSpec->xzProps;
CLzma2EncProps &lzma2Props = xzProps.lzma2Props;
lzma2Props.lzmaProps.level = GetLevel();
CMyComPtr<ISequentialInStream> fileInStream;
RINOK(updateCallback->GetStream(0, &fileInStream));
xzProps.reduceSize = size;
/*
{
NCOM::CPropVariant prop = (UInt64)size;
RINOK(encoderSpec->SetCoderProp(NCoderPropID::kReduceSize, prop));
}
*/
#ifndef _7ZIP_ST
xzProps.numTotalThreads = _numThreads;
#endif
xzProps.blockSize = _numSolidBytes;
if (_numSolidBytes == XZ_PROPS__BLOCK_SIZE__SOLID)
{
xzProps.lzma2Props.blockSize = LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID;
}
RINOK(encoderSpec->SetCheckSize(_crcSize));
{
CXzFilterProps &filter = xzProps.filterProps;
if (_filterId == XZ_ID_Delta)
{
bool deltaDefined = false;
FOR_VECTOR (j, _filterMethod.Props)
{
const CProp &prop = _filterMethod.Props[j];
if (prop.Id == NCoderPropID::kDefaultProp && prop.Value.vt == VT_UI4)
{
UInt32 delta = (UInt32)prop.Value.ulVal;
if (delta < 1 || delta > 256)
return E_INVALIDARG;
filter.delta = delta;
deltaDefined = true;
}
else
return E_INVALIDARG;
}
if (!deltaDefined)
return E_INVALIDARG;
}
filter.id = _filterId;
}
FOR_VECTOR (i, _methods)
{
COneMethodInfo &m = _methods[i];
/*
SetGlobalLevelTo(m);
#ifndef _7ZIP_ST
CMultiMethodProps::SetMethodThreads(m, _numThreads);
#endif
*/
FOR_VECTOR (j, m.Props)
{
FOR_VECTOR (j, m.Props)
{
const CProp &prop = m.Props[j];
RINOK(encoderSpec->SetCoderProp(prop.Id, prop.Value));
}
const CProp &prop = m.Props[j];
RINOK(encoderSpec->SetCoderProp(prop.Id, prop.Value));
}
}
#ifndef _7ZIP_ST
lzma2Props.numTotalThreads = _numThreads;
#endif
CMyComPtr<ISequentialInStream> fileInStream;
RINOK(updateCallback->GetStream(0, &fileInStream));
CLocalProgress *lps = new CLocalProgress;
CMyComPtr<ICompressProgressInfo> progress = lps;
lps->Init(updateCallback, true);
CXzProps &xzProps = encoderSpec->xzProps;
CXzFilterProps &filter = encoderSpec->filter;
XzProps_Init(&xzProps);
XzFilterProps_Init(&filter);
xzProps.lzma2Props = &lzma2Props;
xzProps.filterProps = (_filterId != 0 ? &filter : NULL);
switch (_crcSize)
{
case 0: xzProps.checkId = XZ_CHECK_NO; break;
case 4: xzProps.checkId = XZ_CHECK_CRC32; break;
case 8: xzProps.checkId = XZ_CHECK_CRC64; break;
case 32: xzProps.checkId = XZ_CHECK_SHA256; break;
default: return E_INVALIDARG;
}
filter.id = _filterId;
if (_filterId == XZ_ID_Delta)
{
bool deltaDefined = false;
FOR_VECTOR (j, _filterMethod.Props)
{
const CProp &prop = _filterMethod.Props[j];
if (prop.Id == NCoderPropID::kDefaultProp && prop.Value.vt == VT_UI4)
{
UInt32 delta = (UInt32)prop.Value.ulVal;
if (delta < 1 || delta > 256)
return E_INVALIDARG;
filter.delta = delta;
deltaDefined = true;
}
}
if (!deltaDefined)
return E_INVALIDARG;
}
return encoderSpec->Code(fileInStream, outStream, NULL, NULL, progress);
}
@@ -747,11 +1126,83 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
}
HRESULT CHandler::SetSolidFromString(const UString &s)
{
UString s2 = s;
s2.MakeLower_Ascii();
{
const wchar_t *start = ((const wchar_t *)s2);
const wchar_t *end;
UInt64 v = ConvertStringToUInt64(start, &end);
if (start == end)
return E_INVALIDARG;
if ((unsigned)(end - start) + 1 != s2.Len())
return E_INVALIDARG;
wchar_t c = *end;
{
unsigned numBits;
switch (c)
{
case 'b': numBits = 0; break;
case 'k': numBits = 10; break;
case 'm': numBits = 20; break;
case 'g': numBits = 30; break;
case 't': numBits = 40; break;
default: return E_INVALIDARG;
}
_numSolidBytes = (v << numBits);
}
}
return S_OK;
}
HRESULT CHandler::SetSolidFromPROPVARIANT(const PROPVARIANT &value)
{
bool isSolid;
switch (value.vt)
{
case VT_EMPTY: isSolid = true; break;
case VT_BOOL: isSolid = (value.boolVal != VARIANT_FALSE); break;
case VT_BSTR:
if (StringToBool(value.bstrVal, isSolid))
break;
return SetSolidFromString(value.bstrVal);
default: return E_INVALIDARG;
}
_numSolidBytes = (isSolid ? XZ_PROPS__BLOCK_SIZE__SOLID : XZ_PROPS__BLOCK_SIZE__AUTO);
return S_OK;
}
HRESULT CHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value)
{
UString name = nameSpec;
name.MakeLower_Ascii();
if (name.IsEmpty())
return E_INVALIDARG;
if (name[0] == L's')
{
name.Delete(0);
if (name.IsEmpty())
return SetSolidFromPROPVARIANT(value);
if (value.vt != VT_EMPTY)
return E_INVALIDARG;
return SetSolidFromString(name);
}
return CMultiMethodProps::SetProperty(name, value);
}
STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)
{
COM_TRY_BEGIN
Init();
for (UInt32 i = 0; i < numProps; i++)
{
RINOK(SetProperty(names[i], values[i]));
@@ -781,7 +1232,9 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVAR
AString &methodName = _methods[0].MethodName;
if (methodName.IsEmpty())
methodName = k_LZMA2_Name;
else if (!methodName.IsEqualTo_Ascii_NoCase(k_LZMA2_Name))
else if (
!methodName.IsEqualTo_Ascii_NoCase(k_LZMA2_Name)
&& !methodName.IsEqualTo_Ascii_NoCase("xz"))
return E_INVALIDARG;
}

View File

@@ -36,6 +36,7 @@ static const UInt32 kLzmaHeaderSize = 4 + kLzmaPropsSize;
class CLzmaEncoder:
public ICompressCoder,
public ICompressSetCoderProperties,
public ICompressSetCoderPropertiesOpt,
public CMyUnknownImp
{
public:
@@ -46,8 +47,11 @@ public:
STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
STDMETHOD(SetCoderPropertiesOpt)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
MY_UNKNOWN_IMP1(ICompressSetCoderProperties)
MY_UNKNOWN_IMP2(
ICompressSetCoderProperties,
ICompressSetCoderPropertiesOpt)
};
STDMETHODIMP CLzmaEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)
@@ -71,6 +75,11 @@ STDMETHODIMP CLzmaEncoder::SetCoderProperties(const PROPID *propIDs, const PROPV
return S_OK;
}
STDMETHODIMP CLzmaEncoder::SetCoderPropertiesOpt(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)
{
return EncoderSpec->SetCoderPropertiesOpt(propIDs, props, numProps);
}
STDMETHODIMP CLzmaEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
{
@@ -118,7 +127,8 @@ HRESULT CAddCommon::CalcStreamCRC(ISequentialInStream *inStream, UInt32 &resultC
}
HRESULT CAddCommon::Set_Pre_CompressionResult(bool seqMode, UInt64 unpackSize, CCompressingResult &opRes) const
HRESULT CAddCommon::Set_Pre_CompressionResult(bool inSeqMode, bool outSeqMode, UInt64 unpackSize,
CCompressingResult &opRes) const
{
// We use Zip64, if unPackSize size is larger than 0xF8000000 to support
// cases when compressed size can be about 3% larger than uncompressed size
@@ -144,7 +154,7 @@ HRESULT CAddCommon::Set_Pre_CompressionResult(bool seqMode, UInt64 unpackSize, C
opRes.LzmaEos = false;
opRes.ExtractVersion = NCompressionMethod::kExtractVersion_Default;
opRes.FileTimeWasUsed = false;
opRes.DescriptorMode = outSeqMode;
if (_options.PasswordIsDefined)
{
@@ -153,8 +163,8 @@ HRESULT CAddCommon::Set_Pre_CompressionResult(bool seqMode, UInt64 unpackSize, C
opRes.ExtractVersion = NCompressionMethod::kExtractVersion_Aes;
else
{
if (seqMode)
opRes.FileTimeWasUsed = true;
if (inSeqMode)
opRes.DescriptorMode = true;
}
}
@@ -187,7 +197,8 @@ HRESULT CAddCommon::Set_Pre_CompressionResult(bool seqMode, UInt64 unpackSize, C
HRESULT CAddCommon::Compress(
DECL_EXTERNAL_CODECS_LOC_VARS
ISequentialInStream *inStream, IOutStream *outStream,
bool seqMode, UInt32 fileTime,
bool inSeqMode, bool outSeqMode,
UInt32 fileTime, UInt64 expectedDataSize,
ICompressProgressInfo *progress, CCompressingResult &opRes)
{
opRes.LzmaEos = false;
@@ -202,16 +213,31 @@ HRESULT CAddCommon::Compress(
CMyComPtr<ISequentialInStream> inCrcStream = inSecCrcStreamSpec;
CMyComPtr<IInStream> inStream2;
if (!seqMode)
if (!inSeqMode)
{
inStream->QueryInterface(IID_IInStream, (void **)&inStream2);
if (!inStream2)
{
// inSeqMode = true;
// inSeqMode must be correct before
return E_FAIL;
}
}
inSecCrcStreamSpec->SetStream(inStream);
inSecCrcStreamSpec->Init();
unsigned numTestMethods = _options.MethodSequence.Size();
if (seqMode || (numTestMethods > 1 && !inStream2))
numTestMethods = 1;
bool descriptorMode = outSeqMode;
if (!outSeqMode)
if (inSeqMode && _options.PasswordIsDefined && !_options.IsAesMode)
descriptorMode = true;
opRes.DescriptorMode = descriptorMode;
if (numTestMethods > 1)
if (inSeqMode || outSeqMode || !inStream2)
numTestMethods = 1;
UInt32 crc = 0;
bool crc_IsCalculated = false;
@@ -219,19 +245,23 @@ HRESULT CAddCommon::Compress(
Byte method = 0;
CFilterCoder::C_OutStream_Releaser outStreamReleaser;
opRes.ExtractVersion = NCompressionMethod::kExtractVersion_Default;
opRes.FileTimeWasUsed = false;
for (unsigned i = 0; i < numTestMethods; i++)
{
opRes.LzmaEos = false;
opRes.ExtractVersion = NCompressionMethod::kExtractVersion_Default;
if (inStream2 && i != 0)
if (i != 0)
{
inSecCrcStreamSpec->Init();
RINOK(inStream2->Seek(0, STREAM_SEEK_SET, NULL));
if (inStream2)
{
inSecCrcStreamSpec->Init();
RINOK(inStream2->Seek(0, STREAM_SEEK_SET, NULL));
}
RINOK(outStream->SetSize(0));
RINOK(outStream->Seek(0, STREAM_SEEK_SET, NULL));
}
RINOK(outStream->SetSize(0));
RINOK(outStream->Seek(0, STREAM_SEEK_SET, NULL));
if (_options.PasswordIsDefined)
{
@@ -264,7 +294,12 @@ HRESULT CAddCommon::Compress(
UInt32 check;
if (inStream2)
if (descriptorMode)
{
// it's Info-ZIP modification for stream_mode descriptor_mode (bit 3 of the general purpose bit flag is set)
check = (fileTime & 0xFFFF);
}
else
{
if (!crc_IsCalculated)
{
@@ -275,11 +310,6 @@ HRESULT CAddCommon::Compress(
}
check = (crc >> 16);
}
else
{
opRes.FileTimeWasUsed = true;
check = (fileTime & 0xFFFF);
}
RINOK(_filterSpec->WriteHeader_Check16(outStream, (UInt16)check));
}
@@ -295,7 +325,13 @@ HRESULT CAddCommon::Compress(
{
case NCompressionMethod::kStore:
{
if (_copyCoderSpec == NULL)
if (descriptorMode)
{
// we still can create descriptor_mode archives with "Store" method, but they are not good for 100%
return E_NOTIMPL;
}
if (!_copyCoderSpec)
{
_copyCoderSpec = new NCompress::CCopyCoder;
_copyCoder = _copyCoderSpec;
@@ -390,6 +426,18 @@ HRESULT CAddCommon::Compress(
outStreamNew = outStream;
if (_compressExtractVersion > opRes.ExtractVersion)
opRes.ExtractVersion = _compressExtractVersion;
{
CMyComPtr<ICompressSetCoderPropertiesOpt> optProps;
_compressEncoder->QueryInterface(IID_ICompressSetCoderPropertiesOpt, (void **)&optProps);
if (optProps)
{
PROPID propID = NCoderPropID::kExpectedDataSize;
NWindows::NCOM::CPropVariant prop = (UInt64)expectedDataSize;
RINOK(optProps->SetCoderPropertiesOpt(&propID, &prop, 1));
}
}
RINOK(_compressEncoder->Code(inCrcStream, outStreamNew, NULL, NULL, progress));
break;
}

View File

@@ -26,7 +26,7 @@ struct CCompressingResult
UInt32 CRC;
UInt16 Method;
Byte ExtractVersion;
bool FileTimeWasUsed;
bool DescriptorMode;
bool LzmaEos;
};
@@ -53,12 +53,14 @@ public:
CAddCommon(const CCompressionMethodMode &options);
~CAddCommon();
HRESULT Set_Pre_CompressionResult(bool seqMode, UInt64 unpackSize, CCompressingResult &opRes) const;
HRESULT Set_Pre_CompressionResult(bool inSeqMode, bool outSeqMode, UInt64 unpackSize,
CCompressingResult &opRes) const;
HRESULT Compress(
DECL_EXTERNAL_CODECS_LOC_VARS
ISequentialInStream *inStream, IOutStream *outStream,
bool seqMode, UInt32 fileTime,
bool inSeqMode, bool outSeqMode,
UInt32 fileTime, UInt64 expectedDataSize,
ICompressProgressInfo *progress, CCompressingResult &opRes);
};

View File

@@ -564,7 +564,8 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
AString s2 = FlagsToString(g_HeaderCharacts, ARRAY_SIZE(g_HeaderCharacts), flags);
if (!s2.IsEmpty())
{
s.Add_OptSpaced(":");
if (!s.IsEmpty())
s.Add_OptSpaced(":");
s.Add_OptSpaced(s2);
}
}

View File

@@ -459,7 +459,16 @@ API_FUNC_IsArc IsArc_Zip(const Byte *p, size_t size)
extraSize -= 4;
p += 4;
if (dataSize > extraSize)
return k_IsArc_Res_NO;
{
// It can be error on header.
// We want to support such rare case bad archives.
// We use additional checks to reduce false-positive probability.
if (nameSize == 0
|| nameSize > (1 << 9)
|| extraSize > (1 << 9))
return k_IsArc_Res_NO;
return k_IsArc_Res_YES;
}
if (dataSize > size)
return k_IsArc_Res_NEED_MORE;
size -= dataSize;

View File

@@ -269,7 +269,25 @@ UInt32 CItem::GetWinAttrib() const
case NHostOS::kUnix:
// do we need to clear 16 low bits in this case?
if (FromCentral)
{
/*
Some programs write posix attributes in high 16 bits of ExternalAttrib
Also some programs can write additional marker flag:
0x8000 - p7zip
0x4000 - Zip in MacOS
no marker - Info-Zip
Client code has two options to detect posix field:
1) check 0x8000 marker. In that case we must add 0x8000 marker here.
2) check that high 4 bits (file type bits in posix field) of attributes are not zero.
*/
winAttrib = ExternalAttrib & 0xFFFF0000;
// #ifndef _WIN32
winAttrib |= 0x8000; // add posix mode marker
// #endif
}
break;
}
if (IsDir()) // test it;

View File

@@ -174,6 +174,9 @@ void COutArchive::WriteLocalHeader_Replace(CItemOut &item)
{
WriteDescriptor(item);
m_OutBuffer.FlushWithCheck();
return;
// we don't replace local header, if we write Descriptor.
// so local header with Descriptor flag must be written to local header before.
}
const UInt64 nextPos = m_CurPos;

View File

@@ -62,7 +62,7 @@ static void AddAesExtra(CItem &item, Byte aesKeyMode, UInt16 method)
static void SetFileHeader(
const CCompressionMethodMode &options,
const CUpdateItem &ui,
// bool isSeqMode,
bool useDescriptor,
CItemOut &item)
{
item.Size = ui.Size;
@@ -94,7 +94,7 @@ static void SetFileHeader(
item.InternalAttrib = 0; // test it
item.SetEncrypted(!isDir && options.PasswordIsDefined);
// item.SetDescriptorMode(isSeqMode);
item.SetDescriptorMode(useDescriptor);
if (isDir)
{
@@ -166,18 +166,22 @@ struct CThreadInfo
HRESULT Result;
CCompressingResult CompressingResult;
bool SeqMode;
bool InSeqMode;
bool OutSeqMode;
bool IsFree;
UInt32 UpdateIndex;
UInt32 FileTime;
UInt64 ExpectedDataSize;
CThreadInfo(const CCompressionMethodMode &options):
ExitThread(false),
ProgressSpec(0),
OutStreamSpec(0),
Coder(options),
SeqMode(false),
FileTime(0)
InSeqMode(false),
OutSeqMode(false),
FileTime(0),
ExpectedDataSize((UInt64)(Int64)-1)
{}
HRESULT CreateEvents()
@@ -210,7 +214,9 @@ void CThreadInfo::WaitAndCode()
Result = Coder.Compress(
EXTERNAL_CODECS_LOC_VARS
InStream, OutStream, SeqMode, FileTime, Progress, CompressingResult);
InStream, OutStream,
InSeqMode, OutSeqMode, FileTime, ExpectedDataSize,
Progress, CompressingResult);
if (Result == S_OK && Progress)
Result = Progress->SetRatioInfo(&CompressingResult.UnpackSize, &CompressingResult.PackSize);
@@ -237,10 +243,13 @@ public:
struct CMemBlocks2: public CMemLockBlocks
{
CCompressingResult CompressingResult;
bool Defined;
bool Skip;
CMemBlocks2(): Defined(false), Skip(false) {}
bool InSeqMode;
bool PreDescriptorMode;
bool Finished;
CCompressingResult CompressingResult;
CMemBlocks2(): Skip(false), InSeqMode(false), PreDescriptorMode(false), Finished(false) {}
};
class CMemRefs
@@ -412,7 +421,7 @@ static HRESULT UpdateItemOldData(
static void WriteDirHeader(COutArchive &archive, const CCompressionMethodMode *options,
const CUpdateItem &ui, CItemOut &item)
{
SetFileHeader(*options, ui, item);
SetFileHeader(*options, ui, false, item);
archive.WriteLocalHeader(item);
}
@@ -471,7 +480,7 @@ static HRESULT Update2St(
CInArchive *inArchive,
const CObjectVector<CItemEx> &inputItems,
CObjectVector<CUpdateItem> &updateItems,
const CCompressionMethodMode *options,
const CCompressionMethodMode *options, bool outSeqMode,
const CByteBuffer *comment,
IArchiveUpdateCallback *updateCallback,
UInt64 &totalComplexity,
@@ -527,28 +536,28 @@ static HRESULT Update2St(
if (!fileInStream)
return E_INVALIDARG;
bool seqMode;
bool inSeqMode = false;
if (!inSeqMode)
{
CMyComPtr<IInStream> inStream2;
fileInStream->QueryInterface(IID_IInStream, (void **)&inStream2);
seqMode = (inStream2 == NULL);
inSeqMode = (inStream2 == NULL);
}
// seqMode = true; // to test seqMode
UpdatePropsFromStream(ui, fileInStream, updateCallback, totalComplexity);
SetFileHeader(*options, ui, item);
item.SetDescriptorMode(seqMode);
// file Size can be 64-bit !!!
CCompressingResult compressingResult;
RINOK(compressor.Set_Pre_CompressionResult(
seqMode,
inSeqMode, outSeqMode,
ui.Size,
compressingResult));
SetFileHeader(*options, ui, compressingResult.DescriptorMode, item);
// file Size can be 64-bit !!!
SetItemInfoFromCompressingResult(compressingResult, options->IsRealAesMode(), options->AesKeyMode, item);
archive.WriteLocalHeader(item);
@@ -559,17 +568,12 @@ static HRESULT Update2St(
RINOK(compressor.Compress(
EXTERNAL_CODECS_LOC_VARS
fileInStream, outStream,
seqMode, ui.Time,
inSeqMode, outSeqMode,
ui.Time, ui.Size,
progress, compressingResult));
if (compressingResult.FileTimeWasUsed)
{
/*
if (!item.HasDescriptor())
return E_FAIL;
*/
item.SetDescriptorMode(true);
}
if (item.HasDescriptor() != compressingResult.DescriptorMode)
return E_FAIL;
SetItemInfoFromCompressingResult(compressingResult, options->IsRealAesMode(), options->AesKeyMode, item);
@@ -609,7 +613,7 @@ static HRESULT Update2(
CInArchive *inArchive,
const CObjectVector<CItemEx> &inputItems,
CObjectVector<CUpdateItem> &updateItems,
const CCompressionMethodMode &options,
const CCompressionMethodMode &options, bool outSeqMode,
const CByteBuffer *comment,
IArchiveUpdateCallback *updateCallback)
{
@@ -743,32 +747,38 @@ static HRESULT Update2(
const UInt64 averageSize = numBytesToCompress / numFilesToCompress;
const UInt32 blockSize = oneMethodMain->Get_BZip2_BlockSize();
const UInt64 averageNumberOfBlocks = averageSize / blockSize + 1;
numBZip2Threads = 32;
numBZip2Threads = 64;
if (numBZip2Threads > averageNumberOfBlocks)
numBZip2Threads = (UInt32)averageNumberOfBlocks;
if (numBZip2Threads > numThreads)
numBZip2Threads = numThreads;
oneMethodMain->AddProp_NumThreads(numBZip2Threads);
}
numThreads /= numBZip2Threads;
}
if (method == NFileHeader::NCompressionMethod::kXz)
else if (method == NFileHeader::NCompressionMethod::kXz)
{
bool fixedNumber;
UInt32 numLzma2Threads = oneMethodMain->Get_Lzma2_NumThreads(fixedNumber);
if (!fixedNumber)
UInt32 numLzmaThreads = 1;
int numXzThreads = oneMethodMain->Get_Xz_NumThreads(numLzmaThreads);
if (numXzThreads < 0)
{
const UInt64 averageSize = numBytesToCompress / numFilesToCompress;
const UInt64 blockSize = oneMethodMain->Get_Lzma2_BlockSize();
const UInt64 averageNumberOfBlocks = averageSize / blockSize + 1;
numLzma2Threads = 2;
if (numLzma2Threads > averageNumberOfBlocks)
numLzma2Threads = (UInt32)averageNumberOfBlocks;
oneMethodMain->AddProp_NumThreads(numLzma2Threads);
const UInt64 blockSize = oneMethodMain->Get_Xz_BlockSize();
UInt64 averageNumberOfBlocks = 1;
if (blockSize != (UInt64)(Int64)-1)
averageNumberOfBlocks = averageSize / blockSize + 1;
UInt32 t = 256;
if (t > averageNumberOfBlocks)
t = (UInt32)averageNumberOfBlocks;
t *= numLzmaThreads;
if (t > numThreads)
t = numThreads;
oneMethodMain->AddProp_NumThreads(t);
numXzThreads = t;
}
numThreads /= numLzma2Threads;
numThreads /= (unsigned)numXzThreads;
}
if (method == NFileHeader::NCompressionMethod::kLZMA)
else if (method == NFileHeader::NCompressionMethod::kLZMA)
{
// we suppose that default LZMA is 2 thread. So we don't change it
UInt32 numLZMAThreads = oneMethodMain->Get_Lzma_NumThreads();
@@ -782,12 +792,14 @@ static HRESULT Update2(
mtMode = false;
}
// mtMode = true; // to test mtMode for seqMode
if (!mtMode)
#endif
return Update2St(
EXTERNAL_CODECS_LOC_VARS
archive, inArchive,
inputItems, updateItems, &options2, comment, updateCallback, totalComplexity, opCallback);
inputItems, updateItems, &options2, outSeqMode, comment, updateCallback, totalComplexity, opCallback);
#ifndef _7ZIP_ST
@@ -830,8 +842,10 @@ static HRESULT Update2(
threadInfo.ProgressSpec = new CMtCompressProgress();
threadInfo.Progress = threadInfo.ProgressSpec;
threadInfo.ProgressSpec->Init(&mtCompressProgressMixer, (int)i);
threadInfo.SeqMode = false; // fix it !
threadInfo.FileTime = 0; // fix it !
threadInfo.InSeqMode = false;
threadInfo.OutSeqMode = false;
threadInfo.FileTime = 0;
threadInfo.ExpectedDataSize = (UInt64)(Int64)-1;
RINOK(threadInfo.CreateThread());
}
}
@@ -840,10 +854,15 @@ static HRESULT Update2(
unsigned itemIndex = 0;
int lastRealStreamItemIndex = -1;
while (itemIndex < updateItems.Size())
{
if (threadIndices.Size() < numThreads && mtItemIndex < updateItems.Size())
{
// we start ahead the threads for compressing
// also we set refs.Refs[itemIndex].SeqMode that is used later
// don't move that code block
CUpdateItem &ui = updateItems[mtItemIndex++];
if (!ui.NewData)
continue;
@@ -869,6 +888,8 @@ static HRESULT Update2(
CMyComPtr<ISequentialInStream> fileInStream;
CMemBlocks2 &memRef2 = refs.Refs[mtItemIndex - 1];
{
NWindows::NSynchronization::CCriticalSectionLock lock(mtProgressMixerSpec->Mixer2->CriticalSection);
HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream);
@@ -878,7 +899,7 @@ static HRESULT Update2(
complexity += kLocalHeaderSize;
mtProgressMixerSpec->Mixer2->SetProgressOffset(complexity);
RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
refs.Refs[mtItemIndex - 1].Skip = true;
memRef2.Skip = true;
continue;
}
RINOK(res);
@@ -888,26 +909,46 @@ static HRESULT Update2(
RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
}
for (UInt32 k = 0; k < numThreads; k++)
UInt32 k;
for (k = 0; k < numThreads; k++)
if (threads.Threads[k].IsFree)
break;
if (k == numThreads)
return E_FAIL;
{
CThreadInfo &threadInfo = threads.Threads[k];
if (threadInfo.IsFree)
{
CThreadInfo &threadInfo = threads.Threads[k];
threadInfo.IsFree = false;
threadInfo.InStream = fileInStream;
bool inSeqMode = false;
if (!inSeqMode)
{
CMyComPtr<IInStream> inStream2;
fileInStream->QueryInterface(IID_IInStream, (void **)&inStream2);
inSeqMode = (inStream2 == NULL);
}
memRef2.InSeqMode = inSeqMode;
// !!!!! we must release ref before sending event
// BUG was here in v4.43 and v4.44. It could change ref counter in two threads in same time
fileInStream.Release();
threadInfo.OutStreamSpec->Init();
threadInfo.ProgressSpec->Reinit();
threadInfo.CompressEvent.Set();
threadInfo.UpdateIndex = mtItemIndex - 1;
threadInfo.InSeqMode = inSeqMode;
threadInfo.OutSeqMode = outSeqMode;
threadInfo.FileTime = ui.Time; // FileTime is used for ZipCrypto only in seqMode
threadInfo.ExpectedDataSize = ui.Size;
threadInfo.CompressEvent.Set();
compressingCompletedEvents.Add(threadInfo.CompressionCompletedEvent);
threadIndices.Add(k);
break;
}
}
@@ -946,15 +987,17 @@ static HRESULT Update2(
{
CMemBlocks2 &memRef = refs.Refs[itemIndex];
if (memRef.Defined)
if (memRef.Finished)
{
if (lastRealStreamItemIndex < (int)itemIndex)
lastRealStreamItemIndex = itemIndex;
SetFileHeader(options, ui, item);
SetFileHeader(options, ui, memRef.CompressingResult.DescriptorMode, item);
// the BUG was fixed in 9.26:
// SetItemInfoFromCompressingResult must be after SetFileHeader
// to write correct Size.
SetItemInfoFromCompressingResult(memRef.CompressingResult,
options.IsRealAesMode(), options.AesKeyMode, item);
archive.WriteLocalHeader(item);
@@ -967,16 +1010,25 @@ static HRESULT Update2(
}
else
{
// current file was not finished
if (lastRealStreamItemIndex < (int)itemIndex)
{
// LocalHeader was not written for current itemIndex still
lastRealStreamItemIndex = itemIndex;
SetFileHeader(options, ui, item);
// thread was started before for that item already, and memRef.SeqMode was set
CCompressingResult compressingResult;
RINOK(compressor.Set_Pre_CompressionResult(
false, // seqMode
memRef.InSeqMode, outSeqMode,
ui.Size,
compressingResult));
memRef.PreDescriptorMode = compressingResult.DescriptorMode;
SetFileHeader(options, ui, compressingResult.DescriptorMode, item);
SetItemInfoFromCompressingResult(compressingResult, options.IsRealAesMode(), options.AesKeyMode, item);
// file Size can be 64-bit !!!
@@ -1015,19 +1067,29 @@ static HRESULT Update2(
if (t == 0)
{
// if thread for current file was finished.
if (threadInfo.UpdateIndex != itemIndex)
return E_FAIL;
if (memRef.PreDescriptorMode != threadInfo.CompressingResult.DescriptorMode)
return E_FAIL;
RINOK(threadInfo.OutStreamSpec->WriteToRealStream());
threadInfo.OutStreamSpec->ReleaseOutStream();
SetFileHeader(options, ui, item);
SetFileHeader(options, ui, threadInfo.CompressingResult.DescriptorMode, item);
SetItemInfoFromCompressingResult(threadInfo.CompressingResult,
options.IsRealAesMode(), options.AesKeyMode, item);
archive.WriteLocalHeader_Replace(item);
}
else
{
// it's not current file. So we must store information in array
CMemBlocks2 &memRef2 = refs.Refs[threadInfo.UpdateIndex];
threadInfo.OutStreamSpec->DetachData(memRef2);
memRef2.CompressingResult = threadInfo.CompressingResult;
memRef2.Defined = true;
// memRef2.SeqMode = threadInfo.SeqMode; // it was set before
memRef2.Finished = true;
continue;
}
}
@@ -1060,6 +1122,7 @@ class CCacheOutStream:
public CMyUnknownImp
{
CMyComPtr<IOutStream> _stream;
CMyComPtr<ISequentialOutStream> _seqStream;
Byte *_cache;
UInt64 _virtPos;
UInt64 _virtSize;
@@ -1075,10 +1138,10 @@ class CCacheOutStream:
}
HRESULT FlushCache();
public:
CCacheOutStream(): _cache(0) {}
CCacheOutStream(): _cache(NULL) {}
~CCacheOutStream();
bool Allocate();
HRESULT Init(IOutStream *stream);
HRESULT Init(ISequentialOutStream *seqStream, IOutStream *stream);
MY_UNKNOWN_IMP
@@ -1094,13 +1157,19 @@ bool CCacheOutStream::Allocate()
return (_cache != NULL);
}
HRESULT CCacheOutStream::Init(IOutStream *stream)
HRESULT CCacheOutStream::Init(ISequentialOutStream *seqStream, IOutStream *stream)
{
_virtPos = _phyPos = 0;
_virtPos = 0;
_phyPos = 0;
_virtSize = 0;
_seqStream = seqStream;
_stream = stream;
RINOK(_stream->Seek(0, STREAM_SEEK_CUR, &_virtPos));
RINOK(_stream->Seek(0, STREAM_SEEK_END, &_virtSize));
RINOK(_stream->Seek(_virtPos, STREAM_SEEK_SET, &_virtPos));
if (_stream)
{
RINOK(_stream->Seek(0, STREAM_SEEK_CUR, &_virtPos));
RINOK(_stream->Seek(0, STREAM_SEEK_END, &_virtSize));
RINOK(_stream->Seek(_virtPos, STREAM_SEEK_SET, &_virtPos));
}
_phyPos = _virtPos;
_phySize = _virtSize;
_cachedPos = 0;
@@ -1114,12 +1183,14 @@ HRESULT CCacheOutStream::MyWrite(size_t size)
{
if (_phyPos != _cachedPos)
{
if (!_stream)
return E_FAIL;
RINOK(_stream->Seek(_cachedPos, STREAM_SEEK_SET, &_phyPos));
}
size_t pos = (size_t)_cachedPos & kCacheMask;
size_t curSize = MyMin(kCacheSize - pos, _cachedSize);
curSize = MyMin(curSize, size);
RINOK(WriteStream(_stream, _cache + pos, curSize));
RINOK(WriteStream(_seqStream, _cache + pos, curSize));
_phyPos += curSize;
if (_phySize < _phyPos)
_phySize = _phyPos;
@@ -1138,10 +1209,13 @@ HRESULT CCacheOutStream::FlushCache()
CCacheOutStream::~CCacheOutStream()
{
FlushCache();
if (_virtSize != _phySize)
_stream->SetSize(_virtSize);
if (_virtPos != _phyPos)
_stream->Seek(_virtPos, STREAM_SEEK_SET, NULL);
if (_stream)
{
if (_virtSize != _phySize)
_stream->SetSize(_virtSize);
if (_virtPos != _phyPos)
_stream->Seek(_virtPos, STREAM_SEEK_SET, NULL);
}
::MidFree(_cache);
}
@@ -1250,6 +1324,8 @@ STDMETHODIMP CCacheOutStream::SetSize(UInt64 newSize)
_virtSize = newSize;
if (newSize < _phySize)
{
if (!_stream)
return E_NOTIMPL;
RINOK(_stream->SetSize(newSize));
_phySize = newSize;
}
@@ -1281,11 +1357,14 @@ HRESULT Update(
CMyComPtr<IOutStream> outStream;
bool outSeqMode;
{
CMyComPtr<IOutStream> outStreamReal;
seqOutStream->QueryInterface(IID_IOutStream, (void **)&outStreamReal);
if (!outStreamReal)
return E_NOTIMPL;
{
// return E_NOTIMPL;
}
if (inArchive)
{
@@ -1293,7 +1372,7 @@ HRESULT Update(
{
IInStream *baseStream = inArchive->GetBaseStream();
RINOK(baseStream->Seek(0, STREAM_SEEK_SET, NULL));
RINOK(NCompress::CopyStream_ExactSize(baseStream, outStreamReal, inArchive->ArcInfo.Base, NULL));
RINOK(NCompress::CopyStream_ExactSize(baseStream, seqOutStream, inArchive->ArcInfo.Base, NULL));
}
}
@@ -1301,7 +1380,8 @@ HRESULT Update(
outStream = cacheStream;
if (!cacheStream->Allocate())
return E_OUTOFMEMORY;
RINOK(cacheStream->Init(outStreamReal));
RINOK(cacheStream->Init(seqOutStream, outStreamReal));
outSeqMode = (outStreamReal == NULL);
}
COutArchive outArchive;
@@ -1323,7 +1403,7 @@ HRESULT Update(
EXTERNAL_CODECS_LOC_VARS
outArchive, inArchive,
inputItems, updateItems,
compressionMethodMode,
compressionMethodMode, outSeqMode,
inArchive ? &inArchive->ArcInfo.Comment : NULL,
updateCallback);
}