diff options
author | Igor Pavlov <ipavlov@users.sourceforge.net> | 2010-10-04 04:00:00 +0400 |
---|---|---|
committer | Kornel LesiĆski <kornel@geekhood.net> | 2016-05-28 02:16:04 +0300 |
commit | 2eb60a059819da595efb8e1de49f04c241f5b981 (patch) | |
tree | fe5423b6679c605b545b726cb875883ea9299b31 /CPP/7zip/Archive/Zip | |
parent | 044e4bb7413beb329edfa3ad27b492d819cdc811 (diff) |
9.179.17
Diffstat (limited to 'CPP/7zip/Archive/Zip')
-rwxr-xr-x | CPP/7zip/Archive/Zip/ZipAddCommon.cpp | 5 | ||||
-rwxr-xr-x | CPP/7zip/Archive/Zip/ZipIn.cpp | 12 | ||||
-rwxr-xr-x | CPP/7zip/Archive/Zip/ZipUpdate.cpp | 227 |
3 files changed, 238 insertions, 6 deletions
diff --git a/CPP/7zip/Archive/Zip/ZipAddCommon.cpp b/CPP/7zip/Archive/Zip/ZipAddCommon.cpp index 3451e3f1..ae75a1a2 100755 --- a/CPP/7zip/Archive/Zip/ZipAddCommon.cpp +++ b/CPP/7zip/Archive/Zip/ZipAddCommon.cpp @@ -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; } }} diff --git a/CPP/7zip/Archive/Zip/ZipIn.cpp b/CPP/7zip/Archive/Zip/ZipIn.cpp index 1048b57d..b36b61be 100755 --- a/CPP/7zip/Archive/Zip/ZipIn.cpp +++ b/CPP/7zip/Archive/Zip/ZipIn.cpp @@ -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; } } diff --git a/CPP/7zip/Archive/Zip/ZipUpdate.cpp b/CPP/7zip/Archive/Zip/ZipUpdate.cpp index 6dd20f94..d4fdee3d 100755 --- a/CPP/7zip/Archive/Zip/ZipUpdate.cpp +++ b/CPP/7zip/Archive/Zip/ZipUpdate.cpp @@ -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) { |