This commit is contained in:
Igor Pavlov
2016-05-10 00:00:00 +00:00
committed by Kornel Lesiński
parent c20d013055
commit 66ac98bb02
92 changed files with 2462 additions and 925 deletions

View File

@@ -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();