diff options
Diffstat (limited to 'CPP/7zip/Archive/Zip/ZipHandler.cpp')
-rw-r--r-- | CPP/7zip/Archive/Zip/ZipHandler.cpp | 134 |
1 files changed, 89 insertions, 45 deletions
diff --git a/CPP/7zip/Archive/Zip/ZipHandler.cpp b/CPP/7zip/Archive/Zip/ZipHandler.cpp index 092dcbc9..75034de0 100644 --- a/CPP/7zip/Archive/Zip/ZipHandler.cpp +++ b/CPP/7zip/Archive/Zip/ZipHandler.cpp @@ -12,6 +12,7 @@ #include "../../IPassword.h" #include "../../Common/FilterCoder.h" +#include "../../Common/LimitedStreams.h" #include "../../Common/ProgressUtils.h" #include "../../Common/StreamObjects.h" #include "../../Common/StreamUtils.h" @@ -142,14 +143,19 @@ static const Byte kProps[] = kpidCRC, kpidMethod, kpidHostOS, - kpidUnpackVer + kpidUnpackVer, + kpidVolumeIndex }; static const Byte kArcProps[] = { kpidEmbeddedStubSize, kpidBit64, - kpidComment + kpidComment, + kpidTotalPhySize, + kpidIsVolume, + kpidVolumeIndex, + kpidNumVolumes }; CHandler::CHandler() @@ -175,18 +181,23 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { case kpidBit64: if (m_Archive.IsZip64) prop = m_Archive.IsZip64; break; case kpidComment: if (m_Archive.ArcInfo.Comment.Size() != 0) prop = MultiByteToUnicodeString(BytesToString(m_Archive.ArcInfo.Comment), CP_ACP); break; - case kpidPhySize: prop = m_Archive.ArcInfo.GetPhySize(); break; - case kpidOffset: /* if (m_Archive.ArcInfo.Base != 0) */ - prop = m_Archive.ArcInfo.Base; break; + + case kpidPhySize: prop = m_Archive.GetPhySize(); break; + case kpidOffset: prop = m_Archive.GetOffset(); break; case kpidEmbeddedStubSize: { - UInt64 stubSize = m_Archive.ArcInfo.GetEmbeddedStubSize(); + UInt64 stubSize = m_Archive.GetEmbeddedStubSize(); if (stubSize != 0) prop = stubSize; break; } + case kpidTotalPhySize: if (m_Archive.IsMultiVol) prop = m_Archive.Vols.GetTotalSize(); break; + case kpidVolumeIndex: if (m_Archive.IsMultiVol) prop = (UInt32)m_Archive.Vols.StartVolIndex; break; + case kpidIsVolume: if (m_Archive.IsMultiVol) prop = true; break; + case kpidNumVolumes: if (m_Archive.IsMultiVol) prop = (UInt32)m_Archive.Vols.Streams.Size(); break; + case kpidWarningFlags: { UInt32 v = 0; @@ -197,6 +208,18 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) break; } + case kpidError: + { + if (!m_Archive.Vols.MissingName.IsEmpty()) + { + UString s; + s.SetFromAscii("Missing volume : "); + s += m_Archive.Vols.MissingName; + prop = s; + } + break; + } + case kpidErrorFlags: { UInt32 v = 0; @@ -209,7 +232,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) but the stream has access only to zip part. In that case we ignore UnavailableStart error. maybe we must show warning in that case. */ - UInt64 stubSize = m_Archive.ArcInfo.GetEmbeddedStubSize(); + UInt64 stubSize = m_Archive.GetEmbeddedStubSize(); if (stubSize < (UInt64)-m_Archive.ArcInfo.Base) v |= kpv_ErrorFlags_UnavailableStart; } @@ -429,6 +452,10 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val case kpidUnpackVer: prop = (UInt32)item.ExtractVersion.Version; break; + + case kpidVolumeIndex: + prop = item.Disk; + break; } prop.Detach(value); @@ -436,30 +463,6 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val COM_TRY_END } -class CProgressImp: public CProgressVirt -{ - CMyComPtr<IArchiveOpenCallback> _callback; -public: - virtual HRESULT SetCompletedLocal(UInt64 numFiles, UInt64 numBytes); - virtual HRESULT SetTotalCD(UInt64 numFiles); - virtual HRESULT SetCompletedCD(UInt64 numFiles); - CProgressImp(IArchiveOpenCallback *callback): _callback(callback) {} -}; - -HRESULT CProgressImp::SetCompletedLocal(UInt64 numFiles, UInt64 numBytes) -{ - return _callback->SetCompleted(&numFiles, &numBytes); -} - -HRESULT CProgressImp::SetTotalCD(UInt64 numFiles) -{ - return _callback->SetTotal(&numFiles, NULL); -} - -HRESULT CProgressImp::SetCompletedCD(UInt64 numFiles) -{ - return _callback->SetCompleted(&numFiles, NULL); -} STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *callback) @@ -468,9 +471,13 @@ STDMETHODIMP CHandler::Open(IInStream *inStream, try { Close(); - RINOK(m_Archive.Open(inStream, maxCheckStartPosition)); - CProgressImp progressImp(callback); - return m_Archive.ReadHeaders(m_Items, callback ? &progressImp : NULL); + HRESULT res = m_Archive.Open(inStream, maxCheckStartPosition, callback, m_Items); + if (res != S_OK) + { + m_Items.Clear(); + m_Archive.ClearRefs(); + } + return res; } catch(...) { Close(); throw; } COM_TRY_END @@ -483,8 +490,6 @@ STDMETHODIMP CHandler::Close() return S_OK; } -////////////////////////////////////// -// CHandler::DecompressItems class CLzmaDecoder: public ICompressCoder, @@ -550,6 +555,8 @@ struct CMethodItem CMyComPtr<ICompressCoder> Coder; }; + + class CZipDecoder { NCrypto::NZip::CDecoder *_zipCryptoDecoderSpec; @@ -584,6 +591,24 @@ public: Int32 &res); }; + +static HRESULT SkipStreamData(ISequentialInStream *stream, UInt64 size) +{ + const size_t kBufSize = 1 << 12; + Byte buf[kBufSize]; + for (;;) + { + if (size == 0) + return S_OK; + size_t curSize = kBufSize; + if (curSize > size) + curSize = (size_t)size; + RINOK(ReadStream_FALSE(stream, buf, curSize)); + size -= curSize; + } +} + + HRESULT CZipDecoder::Decode( DECL_EXTERNAL_CODECS_LOC_VARS CInArchive &archive, const CItemEx &item, @@ -634,9 +659,11 @@ HRESULT CZipDecoder::Decode( outStreamSpec->SetStream(realOutStream); outStreamSpec->Init(needCRC); - UInt64 authenticationPos; - - CMyComPtr<ISequentialInStream> inStream; + CMyComPtr<ISequentialInStream> packStream; + + CLimitedSequentialInStream *limitedStreamSpec = new CLimitedSequentialInStream; + CMyComPtr<ISequentialInStream> inStream(limitedStreamSpec); + { UInt64 packSize = item.PackSize; if (wzAesMode) @@ -645,9 +672,14 @@ HRESULT CZipDecoder::Decode( return S_OK; packSize -= NCrypto::NWzAes::kMacSize; } - UInt64 dataPos = item.GetDataPosition(); - inStream.Attach(archive.CreateLimitedStream(dataPos, packSize)); - authenticationPos = dataPos + packSize; + RINOK(archive.GetItemStream(item, true, packStream)); + if (!packStream) + { + res = NExtract::NOperationResult::kUnavailable; + return S_OK; + } + limitedStreamSpec->SetStream(packStream); + limitedStreamSpec->Init(packSize); } CMyComPtr<ICompressFilter> cryptoFilter; @@ -912,9 +944,15 @@ HRESULT CZipDecoder::Decode( bool authOk = true; if (needCRC) crcOK = (outStreamSpec->GetCRC() == item.Crc); + if (wzAesMode) { - inStream.Attach(archive.CreateLimitedStream(authenticationPos, NCrypto::NWzAes::kMacSize)); + const UInt64 rem = limitedStreamSpec->GetRem(); + if (rem != 0) + if (SkipStreamData(inStream, rem) != S_OK) + authOk = false; + + limitedStreamSpec->Init(NCrypto::NWzAes::kMacSize); if (_wzAesDecoderSpec->CheckMac(inStream, authOk) != S_OK) authOk = false; } @@ -988,16 +1026,21 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnavailable)); continue; } + if (!item.FromLocal) { - HRESULT res = m_Archive.ReadLocalItemAfterCdItem(item); + bool isAvail = true; + HRESULT res = m_Archive.ReadLocalItemAfterCdItem(item, isAvail); if (res == S_FALSE) { if (item.IsDir() || realOutStream || testMode) { RINOK(extractCallback->PrepareOperation(askMode)); realOutStream.Release(); - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kHeadersError)); + RINOK(extractCallback->SetOperationResult( + isAvail ? + NExtract::NOperationResult::kHeadersError : + NExtract::NOperationResult::kUnavailable)); } continue; } @@ -1034,6 +1077,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, RINOK(extractCallback->SetOperationResult(res)) } + lps->InSize = currentTotalPacked; lps->OutSize = currentTotalUnPacked; return lps->SetCur(); |