mirror of
https://github.com/Xevion/easy7zip.git
synced 2025-12-07 07:14:56 -06:00
9.17
This commit is contained in:
committed by
Kornel Lesiński
parent
044e4bb741
commit
2eb60a0598
@@ -146,6 +146,7 @@ HRESULT CAddCommon::Compress(
|
||||
opRes.ExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_Default;
|
||||
if (inCrcStreamSpec != 0)
|
||||
RINOK(inCrcStreamSpec->Seek(0, STREAM_SEEK_SET, NULL));
|
||||
RINOK(outStream->SetSize(0));
|
||||
RINOK(outStream->Seek(0, STREAM_SEEK_SET, NULL));
|
||||
if (_options.PasswordIsDefined)
|
||||
{
|
||||
@@ -218,7 +219,7 @@ HRESULT CAddCommon::Compress(
|
||||
_options.Algo,
|
||||
_options.DicSize,
|
||||
_options.NumFastBytes,
|
||||
(BSTR)(const wchar_t *)_options.MatchFinder,
|
||||
const_cast<BSTR>((const wchar_t *)_options.MatchFinder),
|
||||
_options.NumMatchFinderCycles
|
||||
};
|
||||
PROPID propIDs[] =
|
||||
@@ -373,7 +374,7 @@ HRESULT CAddCommon::Compress(
|
||||
RINOK(outStream->Seek(0, STREAM_SEEK_CUR, &opRes.PackSize));
|
||||
}
|
||||
opRes.Method = method;
|
||||
return outStream->SetSize(opRes.PackSize);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
@@ -544,7 +544,17 @@ HRESULT CInArchive::FindCd(CCdInfo &cdInfo)
|
||||
UInt64 curPos = endPosition - bufSize + i;
|
||||
UInt64 cdEnd = cdInfo.Size + cdInfo.Offset;
|
||||
if (curPos != cdEnd)
|
||||
ArcInfo.Base = curPos - cdEnd;
|
||||
{
|
||||
/*
|
||||
if (cdInfo.Offset <= 16 && cdInfo.Size != 0)
|
||||
{
|
||||
// here we support some rare ZIP files with Central directory at the start
|
||||
ArcInfo.Base = 0;
|
||||
}
|
||||
else
|
||||
*/
|
||||
ArcInfo.Base = curPos - cdEnd;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../../C/Alloc.h"
|
||||
|
||||
#include "Common/AutoPtr.h"
|
||||
#include "Common/Defs.h"
|
||||
#include "Common/StringConvert.h"
|
||||
@@ -16,6 +18,7 @@
|
||||
#ifndef _7ZIP_ST
|
||||
#include "../../Common/ProgressMt.h"
|
||||
#endif
|
||||
#include "../../Common/StreamUtils.h"
|
||||
|
||||
#include "../../Compress/CopyCoder.h"
|
||||
|
||||
@@ -798,6 +801,216 @@ static HRESULT Update2(
|
||||
#endif
|
||||
}
|
||||
|
||||
static const size_t kCacheBlockSize = (1 << 20);
|
||||
static const size_t kCacheSize = (kCacheBlockSize << 2);
|
||||
static const size_t kCacheMask = (kCacheSize - 1);
|
||||
|
||||
class CCacheOutStream:
|
||||
public IOutStream,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CMyComPtr<IOutStream> _stream;
|
||||
Byte *_cache;
|
||||
UInt64 _virtPos;
|
||||
UInt64 _virtSize;
|
||||
UInt64 _phyPos;
|
||||
UInt64 _phySize; // <= _virtSize
|
||||
UInt64 _cachedPos; // (_cachedPos + _cachedSize) <= _virtSize
|
||||
size_t _cachedSize;
|
||||
|
||||
HRESULT MyWrite(size_t size);
|
||||
HRESULT MyWriteBlock()
|
||||
{
|
||||
return MyWrite(kCacheBlockSize - ((size_t)_cachedPos & (kCacheBlockSize - 1)));
|
||||
}
|
||||
HRESULT FlushCache();
|
||||
public:
|
||||
CCacheOutStream(): _cache(0) {}
|
||||
~CCacheOutStream();
|
||||
bool Allocate();
|
||||
HRESULT Init(IOutStream *stream);
|
||||
|
||||
MY_UNKNOWN_IMP
|
||||
|
||||
STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
|
||||
STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
|
||||
STDMETHOD(SetSize)(UInt64 newSize);
|
||||
};
|
||||
|
||||
bool CCacheOutStream::Allocate()
|
||||
{
|
||||
if (!_cache)
|
||||
_cache = (Byte *)::MidAlloc(kCacheSize);
|
||||
return (_cache != NULL);
|
||||
}
|
||||
|
||||
HRESULT CCacheOutStream::Init(IOutStream *stream)
|
||||
{
|
||||
_virtPos = _phyPos = 0;
|
||||
_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));
|
||||
_phyPos = _virtPos;
|
||||
_phySize = _virtSize;
|
||||
_cachedPos = 0;
|
||||
_cachedSize = 0;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CCacheOutStream::MyWrite(size_t size)
|
||||
{
|
||||
while (size != 0 && _cachedSize != 0)
|
||||
{
|
||||
if (_phyPos != _cachedPos)
|
||||
{
|
||||
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));
|
||||
_phyPos += curSize;
|
||||
if (_phySize < _phyPos)
|
||||
_phySize = _phyPos;
|
||||
_cachedPos += curSize;
|
||||
_cachedSize -= curSize;
|
||||
size -= curSize;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CCacheOutStream::FlushCache()
|
||||
{
|
||||
return MyWrite(_cachedSize);
|
||||
}
|
||||
|
||||
CCacheOutStream::~CCacheOutStream()
|
||||
{
|
||||
FlushCache();
|
||||
if (_virtSize != _phySize)
|
||||
_stream->SetSize(_virtSize);
|
||||
if (_virtPos != _phyPos)
|
||||
_stream->Seek(_virtPos, STREAM_SEEK_SET, NULL);
|
||||
::MidFree(_cache);
|
||||
}
|
||||
|
||||
STDMETHODIMP CCacheOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
|
||||
{
|
||||
if (processedSize)
|
||||
*processedSize = 0;
|
||||
if (size == 0)
|
||||
return S_OK;
|
||||
|
||||
UInt64 zerosStart = _virtPos;
|
||||
if (_cachedSize != 0)
|
||||
{
|
||||
if (_virtPos < _cachedPos)
|
||||
{
|
||||
RINOK(FlushCache());
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt64 cachedEnd = _cachedPos + _cachedSize;
|
||||
if (cachedEnd < _virtPos)
|
||||
{
|
||||
if (cachedEnd < _phySize)
|
||||
{
|
||||
RINOK(FlushCache());
|
||||
}
|
||||
else
|
||||
zerosStart = cachedEnd;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_cachedSize == 0 && _phySize < _virtPos)
|
||||
_cachedPos = zerosStart = _phySize;
|
||||
|
||||
if (zerosStart != _virtPos)
|
||||
{
|
||||
// write zeros to [cachedEnd ... _virtPos)
|
||||
|
||||
for (;;)
|
||||
{
|
||||
UInt64 cachedEnd = _cachedPos + _cachedSize;
|
||||
size_t endPos = (size_t)cachedEnd & kCacheMask;
|
||||
size_t curSize = kCacheSize - endPos;
|
||||
if (curSize > _virtPos - cachedEnd)
|
||||
curSize = (size_t)(_virtPos - cachedEnd);
|
||||
if (curSize == 0)
|
||||
break;
|
||||
while (curSize > (kCacheSize - _cachedSize))
|
||||
{
|
||||
RINOK(MyWriteBlock());
|
||||
}
|
||||
memset(_cache + endPos, 0, curSize);
|
||||
_cachedSize += curSize;
|
||||
}
|
||||
}
|
||||
|
||||
if (_cachedSize == 0)
|
||||
_cachedPos = _virtPos;
|
||||
|
||||
size_t pos = (size_t)_virtPos & kCacheMask;
|
||||
size = (UInt32)MyMin((size_t)size, kCacheSize - pos);
|
||||
UInt64 cachedEnd = _cachedPos + _cachedSize;
|
||||
if (_virtPos != cachedEnd) // _virtPos < cachedEnd
|
||||
size = (UInt32)MyMin((size_t)size, (size_t)(cachedEnd - _virtPos));
|
||||
else
|
||||
{
|
||||
// _virtPos == cachedEnd
|
||||
if (_cachedSize == kCacheSize)
|
||||
{
|
||||
RINOK(MyWriteBlock());
|
||||
}
|
||||
size_t startPos = (size_t)_cachedPos & kCacheMask;
|
||||
if (startPos > pos)
|
||||
size = (UInt32)MyMin((size_t)size, (size_t)(startPos - pos));
|
||||
_cachedSize += size;
|
||||
}
|
||||
memcpy(_cache + pos, data, size);
|
||||
if (processedSize)
|
||||
*processedSize = size;
|
||||
_virtPos += size;
|
||||
if (_virtSize < _virtPos)
|
||||
_virtSize = _virtPos;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CCacheOutStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
|
||||
{
|
||||
switch(seekOrigin)
|
||||
{
|
||||
case STREAM_SEEK_SET: _virtPos = offset; break;
|
||||
case STREAM_SEEK_CUR: _virtPos += offset; break;
|
||||
case STREAM_SEEK_END: _virtPos = _virtSize + offset; break;
|
||||
default: return STG_E_INVALIDFUNCTION;
|
||||
}
|
||||
if (newPosition)
|
||||
*newPosition = _virtPos;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CCacheOutStream::SetSize(UInt64 newSize)
|
||||
{
|
||||
_virtSize = newSize;
|
||||
if (newSize < _phySize)
|
||||
{
|
||||
RINOK(_stream->SetSize(newSize));
|
||||
_phySize = newSize;
|
||||
}
|
||||
if (newSize <= _cachedPos)
|
||||
{
|
||||
_cachedSize = 0;
|
||||
_cachedPos = newSize;
|
||||
}
|
||||
if (newSize < _cachedPos + _cachedSize)
|
||||
_cachedSize = (size_t)(newSize - _cachedPos);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT Update(
|
||||
DECL_EXTERNAL_CODECS_LOC_VARS
|
||||
const CObjectVector<CItemEx> &inputItems,
|
||||
@@ -808,9 +1021,17 @@ HRESULT Update(
|
||||
IArchiveUpdateCallback *updateCallback)
|
||||
{
|
||||
CMyComPtr<IOutStream> outStream;
|
||||
RINOK(seqOutStream->QueryInterface(IID_IOutStream, (void **)&outStream));
|
||||
if (!outStream)
|
||||
return E_NOTIMPL;
|
||||
{
|
||||
CMyComPtr<IOutStream> outStreamReal;
|
||||
seqOutStream->QueryInterface(IID_IOutStream, (void **)&outStreamReal);
|
||||
if (!outStreamReal)
|
||||
return E_NOTIMPL;
|
||||
CCacheOutStream *cacheStream = new CCacheOutStream();
|
||||
outStream = cacheStream;
|
||||
if (!cacheStream->Allocate())
|
||||
return E_OUTOFMEMORY;
|
||||
RINOK(cacheStream->Init(outStreamReal));
|
||||
}
|
||||
|
||||
if (inArchive)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user