Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/kornelski/7z.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'CPP/7zip/Archive/Zip/ZipHandler.cpp')
-rw-r--r--CPP/7zip/Archive/Zip/ZipHandler.cpp134
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();