mirror of
https://github.com/Xevion/easy7zip.git
synced 2025-12-07 13:15:04 -06:00
16.00
This commit is contained in:
committed by
Kornel Lesiński
parent
c20d013055
commit
66ac98bb02
@@ -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();
|
||||
|
||||
@@ -18,9 +18,8 @@ namespace NSignature
|
||||
const UInt32 kEcd = 0x06054B50;
|
||||
const UInt32 kEcd64 = 0x06064B50;
|
||||
const UInt32 kEcd64Locator = 0x07064B50;
|
||||
|
||||
// const UInt32 kSpan = 0x08074B50;
|
||||
const UInt32 kNoSpan = 0x30304b50; // PK00, replaces kSpan, if there is only 1 segment
|
||||
const UInt32 kSpan = 0x08074B50;
|
||||
const UInt32 kNoSpan = 0x30304B50; // PK00, replaces kSpan, if there is only 1 segment
|
||||
}
|
||||
|
||||
const unsigned kLocalHeaderSize = 4 + 26; // including signature
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -28,6 +28,7 @@ public:
|
||||
{ return LocalHeaderPos + LocalFullHeaderSize; }
|
||||
};
|
||||
|
||||
|
||||
struct CInArchiveInfo
|
||||
{
|
||||
Int64 Base; /* Base offset of start of archive in stream.
|
||||
@@ -40,74 +41,195 @@ struct CInArchiveInfo
|
||||
Base = ArcInfo.MarkerPos; */
|
||||
|
||||
/* The following *Pos variables contain absolute offsets in Stream */
|
||||
UInt64 MarkerPos; /* Pos of first signature, it can point to PK00 signature
|
||||
|
||||
UInt64 MarkerPos; /* Pos of first signature, it can point to kSpan/kNoSpan signature
|
||||
= MarkerPos2 in most archives
|
||||
= MarkerPos2 - 4 if there is PK00 signature */
|
||||
= MarkerPos2 - 4 if there is kSpan/kNoSpan signature */
|
||||
UInt64 MarkerPos2; // Pos of first local item signature in stream
|
||||
UInt64 FinishPos; // Finish pos of archive data
|
||||
UInt64 FinishPos; // Finish pos of archive data in starting volume
|
||||
UInt64 FileEndPos; // Finish pos of stream
|
||||
|
||||
UInt64 FirstItemRelatOffset; /* Relative offset of first local (read from cd) (relative to Base).
|
||||
= 0 in most archives
|
||||
= size of stub for some SFXs */
|
||||
bool CdWasRead;
|
||||
bool IsSpanMode;
|
||||
bool ThereIsTail;
|
||||
|
||||
// UInt32 BaseVolIndex;
|
||||
|
||||
CByteBuffer Comment;
|
||||
|
||||
CInArchiveInfo(): Base(0), MarkerPos(0), MarkerPos2(0), FinishPos(0), FileEndPos(0),
|
||||
FirstItemRelatOffset(0), CdWasRead(false) {}
|
||||
|
||||
UInt64 GetPhySize() const { return FinishPos - Base; }
|
||||
UInt64 GetEmbeddedStubSize() const
|
||||
{
|
||||
if (CdWasRead)
|
||||
return FirstItemRelatOffset;
|
||||
return MarkerPos2 - Base;
|
||||
}
|
||||
bool ThereIsTail() const { return FileEndPos > FinishPos; }
|
||||
|
||||
CInArchiveInfo():
|
||||
Base(0),
|
||||
MarkerPos(0),
|
||||
MarkerPos2(0),
|
||||
FinishPos(0),
|
||||
FileEndPos(0),
|
||||
FirstItemRelatOffset(0),
|
||||
CdWasRead(false),
|
||||
IsSpanMode(false),
|
||||
ThereIsTail(false)
|
||||
// BaseVolIndex(0)
|
||||
{}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
// BaseVolIndex = 0;
|
||||
Base = 0;
|
||||
MarkerPos = 0;
|
||||
MarkerPos2 = 0;
|
||||
FinishPos = 0;
|
||||
FileEndPos = 0;
|
||||
ThereIsTail = false;
|
||||
|
||||
FirstItemRelatOffset = 0;
|
||||
|
||||
CdWasRead = false;
|
||||
IsSpanMode = false;
|
||||
|
||||
Comment.Free();
|
||||
}
|
||||
};
|
||||
|
||||
struct CProgressVirt
|
||||
{
|
||||
virtual HRESULT SetCompletedLocal(UInt64 numFiles, UInt64 numBytes) = 0;
|
||||
virtual HRESULT SetTotalCD(UInt64 numFiles) = 0;
|
||||
virtual HRESULT SetCompletedCD(UInt64 numFiles) = 0;
|
||||
};
|
||||
|
||||
struct CCdInfo
|
||||
{
|
||||
// 64
|
||||
UInt16 VersionMade;
|
||||
UInt16 VersionNeedExtract;
|
||||
|
||||
// old zip
|
||||
UInt32 ThisDisk;
|
||||
UInt32 CdDisk;
|
||||
UInt64 NumEntries_in_ThisDisk;
|
||||
UInt64 NumEntries;
|
||||
UInt64 Size;
|
||||
UInt64 Offset;
|
||||
|
||||
void ParseEcd(const Byte *p);
|
||||
void ParseEcd64(const Byte *p);
|
||||
UInt16 CommentSize;
|
||||
|
||||
CCdInfo() { memset(this, 0, sizeof(*this)); }
|
||||
|
||||
void ParseEcd32(const Byte *p); // (p) includes signature
|
||||
void ParseEcd64e(const Byte *p); // (p) exclude signature
|
||||
};
|
||||
|
||||
|
||||
class CVols
|
||||
{
|
||||
public:
|
||||
|
||||
struct CSubStreamInfo
|
||||
{
|
||||
CMyComPtr<IInStream> Stream;
|
||||
UInt64 Size;
|
||||
|
||||
CSubStreamInfo(): Size(0) {}
|
||||
};
|
||||
|
||||
CObjectVector<CSubStreamInfo> Streams;
|
||||
int StreamIndex;
|
||||
bool NeedSeek;
|
||||
|
||||
CMyComPtr<IInStream> ZipStream;
|
||||
|
||||
bool StartIsExe; // is .exe
|
||||
bool StartIsZ; // is .zip or .zNN
|
||||
bool StartIsZip; // is .zip
|
||||
bool IsUpperCase;
|
||||
Int32 StartVolIndex; // = (NN - 1), if StartStream is .zNN
|
||||
|
||||
Int32 StartParsingVol; // if we need local parsing, we must use that stream
|
||||
unsigned NumVols;
|
||||
|
||||
int EndVolIndex; // index of last volume (ecd volume),
|
||||
// -1, if is not multivol
|
||||
|
||||
UString BaseName; // including '.'
|
||||
|
||||
UString MissingName;
|
||||
|
||||
CCdInfo ecd;
|
||||
bool ecd_wasRead;
|
||||
|
||||
void Clear()
|
||||
{
|
||||
StreamIndex = -1;
|
||||
NeedSeek = false;
|
||||
|
||||
|
||||
StartIsExe = false;
|
||||
StartIsZ = false;
|
||||
StartIsZip = false;
|
||||
IsUpperCase = false;
|
||||
|
||||
StartVolIndex = -1;
|
||||
StartParsingVol = 0;
|
||||
NumVols = 0;
|
||||
EndVolIndex = -1;
|
||||
|
||||
BaseName.Empty();
|
||||
MissingName.Empty();
|
||||
|
||||
ecd_wasRead = false;
|
||||
|
||||
Streams.Clear();
|
||||
ZipStream.Release();
|
||||
}
|
||||
|
||||
HRESULT ParseArcName(IArchiveOpenVolumeCallback *volCallback);
|
||||
|
||||
HRESULT Read(void *data, UInt32 size, UInt32 *processedSize);
|
||||
|
||||
UInt64 GetTotalSize() const
|
||||
{
|
||||
UInt64 total = 0;
|
||||
FOR_VECTOR (i, Streams)
|
||||
total += Streams[i].Size;
|
||||
return total;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class CVolStream:
|
||||
public ISequentialInStream,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
public:
|
||||
CVols *Vols;
|
||||
|
||||
MY_UNKNOWN_IMP1(ISequentialInStream)
|
||||
|
||||
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
|
||||
};
|
||||
|
||||
|
||||
class CInArchive
|
||||
{
|
||||
CInBuffer _inBuffer;
|
||||
bool _inBufMode;
|
||||
UInt32 m_Signature;
|
||||
UInt64 m_Position;
|
||||
|
||||
UInt64 _processedCnt;
|
||||
|
||||
bool CanStartNewVol;
|
||||
|
||||
CMyComPtr<IInStream> StreamRef;
|
||||
IInStream *Stream;
|
||||
IInStream *StartStream;
|
||||
|
||||
bool IsArcOpen;
|
||||
|
||||
HRESULT ReadVols2(IArchiveOpenVolumeCallback *volCallback,
|
||||
unsigned start, int lastDisk, int zipDisk, unsigned numMissingVolsMax, unsigned &numMissingVols);
|
||||
HRESULT ReadVols();
|
||||
|
||||
HRESULT Seek(UInt64 offset);
|
||||
HRESULT FindAndReadMarker(IInStream *stream, const UInt64 *searchHeaderSizeLimit);
|
||||
HRESULT IncreaseRealPosition(Int64 addValue);
|
||||
HRESULT FindMarker(IInStream *stream, const UInt64 *searchLimit);
|
||||
HRESULT IncreaseRealPosition(Int64 addValue, bool &isFinished);
|
||||
|
||||
HRESULT ReadBytes(void *data, UInt32 size, UInt32 *processedSize);
|
||||
void SafeReadBytes(void *data, unsigned size);
|
||||
@@ -126,12 +248,14 @@ class CInArchive
|
||||
HRESULT ReadLocalItemDescriptor(CItemEx &item);
|
||||
HRESULT ReadCdItem(CItemEx &item);
|
||||
HRESULT TryEcd64(UInt64 offset, CCdInfo &cdInfo);
|
||||
HRESULT FindCd(CCdInfo &cdInfo);
|
||||
HRESULT TryReadCd(CObjectVector<CItemEx> &items, UInt64 cdOffset, UInt64 cdSize, CProgressVirt *progress);
|
||||
HRESULT ReadCd(CObjectVector<CItemEx> &items, UInt64 &cdOffset, UInt64 &cdSize, CProgressVirt *progress);
|
||||
HRESULT ReadLocals(CObjectVector<CItemEx> &localItems, CProgressVirt *progress);
|
||||
HRESULT FindCd(bool checkOffsetMode);
|
||||
HRESULT TryReadCd(CObjectVector<CItemEx> &items, const CCdInfo &cdInfo, UInt64 cdOffset, UInt64 cdSize);
|
||||
HRESULT ReadCd(CObjectVector<CItemEx> &items, UInt32 &cdDisk, UInt64 &cdOffset, UInt64 &cdSize);
|
||||
HRESULT ReadLocals(CObjectVector<CItemEx> &localItems);
|
||||
|
||||
HRESULT ReadHeaders2(CObjectVector<CItemEx> &items, CProgressVirt *progress);
|
||||
HRESULT ReadHeaders2(CObjectVector<CItemEx> &items);
|
||||
|
||||
HRESULT GetVolStream(unsigned vol, UInt64 pos, CMyComPtr<ISequentialInStream> &stream);
|
||||
public:
|
||||
CInArchiveInfo ArcInfo;
|
||||
|
||||
@@ -142,46 +266,87 @@ public:
|
||||
bool ExtraMinorError;
|
||||
bool UnexpectedEnd;
|
||||
bool NoCentralDir;
|
||||
|
||||
CMyComPtr<IInStream> Stream;
|
||||
|
||||
void Close();
|
||||
HRESULT Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit);
|
||||
HRESULT ReadHeaders(CObjectVector<CItemEx> &items, CProgressVirt *progress);
|
||||
|
||||
bool IsOpen() const { return Stream != NULL; }
|
||||
bool AreThereErrors() const { return HeadersError || UnexpectedEnd; }
|
||||
bool MarkerIsFound;
|
||||
|
||||
bool IsMultiVol;
|
||||
bool UseDisk_in_SingleVol;
|
||||
UInt32 EcdVolIndex;
|
||||
|
||||
CVols Vols;
|
||||
|
||||
IArchiveOpenCallback *Callback;
|
||||
|
||||
CInArchive(): Stream(NULL), Callback(NULL), IsArcOpen(false) {}
|
||||
|
||||
UInt64 GetPhySize() const
|
||||
{
|
||||
if (IsMultiVol)
|
||||
return ArcInfo.FinishPos;
|
||||
else
|
||||
return ArcInfo.FinishPos - ArcInfo.Base;
|
||||
}
|
||||
|
||||
UInt64 GetOffset() const
|
||||
{
|
||||
if (IsMultiVol)
|
||||
return 0;
|
||||
else
|
||||
return ArcInfo.Base;
|
||||
}
|
||||
|
||||
|
||||
void ClearRefs();
|
||||
void Close();
|
||||
HRESULT Open(IInStream *stream, const UInt64 *searchLimit, IArchiveOpenCallback *callback, CObjectVector<CItemEx> &items);
|
||||
HRESULT ReadHeaders(CObjectVector<CItemEx> &items);
|
||||
|
||||
bool IsOpen() const { return IsArcOpen; }
|
||||
|
||||
bool AreThereErrors() const
|
||||
{
|
||||
return HeadersError
|
||||
|| UnexpectedEnd
|
||||
|| !Vols.MissingName.IsEmpty();
|
||||
}
|
||||
|
||||
bool IsLocalOffsetOK(const CItemEx &item) const
|
||||
{
|
||||
if (item.FromLocal)
|
||||
return true;
|
||||
return /* ArcInfo.Base >= 0 || */ ArcInfo.Base + (Int64)item.LocalHeaderPos >= 0;
|
||||
return (Int64)GetOffset() + (Int64)item.LocalHeaderPos >= 0;
|
||||
}
|
||||
|
||||
HRESULT ReadLocalItemAfterCdItem(CItemEx &item);
|
||||
UInt64 GetEmbeddedStubSize() const
|
||||
{
|
||||
if (ArcInfo.CdWasRead)
|
||||
return ArcInfo.FirstItemRelatOffset;
|
||||
if (IsMultiVol)
|
||||
return 0;
|
||||
return ArcInfo.MarkerPos2 - ArcInfo.Base;
|
||||
}
|
||||
|
||||
|
||||
HRESULT ReadLocalItemAfterCdItem(CItemEx &item, bool &isAvail);
|
||||
HRESULT ReadLocalItemAfterCdItemFull(CItemEx &item);
|
||||
|
||||
ISequentialInStream *CreateLimitedStream(UInt64 position, UInt64 size);
|
||||
HRESULT GetItemStream(const CItemEx &item, bool seekPackData, CMyComPtr<ISequentialInStream> &stream);
|
||||
|
||||
UInt64 GetOffsetInStream(UInt64 offsetFromArc) const { return ArcInfo.Base + offsetFromArc; }
|
||||
IInStream *GetBaseStream() { return StreamRef; }
|
||||
|
||||
bool CanUpdate() const
|
||||
{
|
||||
if (AreThereErrors())
|
||||
return false;
|
||||
if (ArcInfo.Base < 0)
|
||||
return false;
|
||||
if ((Int64)ArcInfo.MarkerPos2 < ArcInfo.Base)
|
||||
if (AreThereErrors()
|
||||
|| IsMultiVol
|
||||
|| ArcInfo.Base < 0
|
||||
|| (Int64)ArcInfo.MarkerPos2 < ArcInfo.Base
|
||||
|| ArcInfo.ThereIsTail
|
||||
|| GetEmbeddedStubSize() != 0)
|
||||
return false;
|
||||
|
||||
// 7-zip probably can update archives with embedded stubs.
|
||||
// we just disable that feature for more safety.
|
||||
if (ArcInfo.GetEmbeddedStubSize() != 0)
|
||||
return false;
|
||||
|
||||
if (ArcInfo.ThereIsTail())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -199,6 +199,8 @@ public:
|
||||
UInt64 PackSize;
|
||||
UInt32 Time;
|
||||
UInt32 Crc;
|
||||
|
||||
UInt32 Disk;
|
||||
|
||||
AString Name;
|
||||
|
||||
|
||||
@@ -12,10 +12,11 @@ namespace NZip {
|
||||
static const Byte k_Signature[] = {
|
||||
4, 0x50, 0x4B, 0x03, 0x04,
|
||||
4, 0x50, 0x4B, 0x05, 0x06,
|
||||
6, 0x50, 0x4B, 0x07, 0x08, 0x50, 0x4B,
|
||||
6, 0x50, 0x4B, 0x30, 0x30, 0x50, 0x4B };
|
||||
|
||||
REGISTER_ARC_IO(
|
||||
"zip", "zip zipx jar xpi odt ods docx xlsx epub", 0, 1,
|
||||
"zip", "zip z01 zipx jar xpi odt ods docx xlsx epub", 0, 1,
|
||||
k_Signature,
|
||||
0,
|
||||
NArcInfoFlags::kFindSignature |
|
||||
|
||||
@@ -52,16 +52,6 @@ static HRESULT CopyBlockToArchive(ISequentialInStream *inStream, UInt64 size,
|
||||
return NCompress::CopyStream_ExactSize(inStream, outStream, size, progress);
|
||||
}
|
||||
|
||||
static HRESULT WriteRange(IInStream *inStream, COutArchive &outArchive,
|
||||
const CUpdateRange &range, ICompressProgressInfo *progress)
|
||||
{
|
||||
UInt64 position;
|
||||
RINOK(inStream->Seek(range.Position, STREAM_SEEK_SET, &position));
|
||||
RINOK(CopyBlockToArchive(inStream, range.Size, outArchive, progress));
|
||||
return progress->SetRatioInfo(&range.Size, &range.Size);
|
||||
}
|
||||
|
||||
|
||||
static void SetFileHeader(
|
||||
COutArchive &archive,
|
||||
const CCompressionMethodMode &options,
|
||||
@@ -358,9 +348,12 @@ static HRESULT UpdateItemOldData(
|
||||
return E_NOTIMPL;
|
||||
|
||||
// use old name size.
|
||||
// CUpdateRange range(item.GetLocalExtraPosition(), item.LocalExtraSize + item.PackSize);
|
||||
CUpdateRange range(inArchive->GetOffsetInStream(itemEx.GetDataPosition()), itemEx.PackSize);
|
||||
|
||||
CMyComPtr<ISequentialInStream> packStream;
|
||||
RINOK(inArchive->GetItemStream(itemEx, true, packStream));
|
||||
if (!packStream)
|
||||
return E_NOTIMPL;
|
||||
|
||||
// we keep ExternalAttrib and some another properties from old archive
|
||||
// item.ExternalAttrib = ui.Attrib;
|
||||
|
||||
@@ -378,19 +371,27 @@ static HRESULT UpdateItemOldData(
|
||||
|
||||
archive.PrepareWriteCompressedData2(item.Name.Len(), item.Size, item.PackSize, item.LocalExtra.HasWzAes());
|
||||
archive.WriteLocalHeader(item);
|
||||
RINOK(WriteRange(inArchive->Stream, archive, range, progress));
|
||||
complexity += range.Size;
|
||||
|
||||
RINOK(CopyBlockToArchive(packStream, itemEx.PackSize, archive, progress));
|
||||
|
||||
complexity += itemEx.PackSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
CUpdateRange range(inArchive->GetOffsetInStream(itemEx.LocalHeaderPos), itemEx.GetLocalFullSize());
|
||||
CMyComPtr<ISequentialInStream> packStream;
|
||||
RINOK(inArchive->GetItemStream(itemEx, false, packStream));
|
||||
if (!packStream)
|
||||
return E_NOTIMPL;
|
||||
|
||||
// set new header position
|
||||
item.LocalHeaderPos = archive.GetCurPos();
|
||||
|
||||
RINOK(WriteRange(inArchive->Stream, archive, range, progress));
|
||||
complexity += range.Size;
|
||||
archive.MoveCurPos(range.Size);
|
||||
const UInt64 rangeSize = itemEx.GetLocalFullSize();
|
||||
|
||||
RINOK(CopyBlockToArchive(packStream, rangeSize, archive, progress));
|
||||
|
||||
complexity += rangeSize;
|
||||
archive.MoveCurPos(rangeSize);
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
@@ -1191,10 +1192,11 @@ HRESULT Update(
|
||||
|
||||
if (inArchive)
|
||||
{
|
||||
if (inArchive->ArcInfo.Base > 0 && !removeSfx)
|
||||
if (!inArchive->IsMultiVol && inArchive->ArcInfo.Base > 0 && !removeSfx)
|
||||
{
|
||||
RINOK(inArchive->Stream->Seek(0, STREAM_SEEK_SET, NULL));
|
||||
RINOK(NCompress::CopyStream_ExactSize(inArchive->Stream, outStreamReal, inArchive->ArcInfo.Base, NULL));
|
||||
IInStream *baseStream = inArchive->GetBaseStream();
|
||||
RINOK(baseStream->Seek(0, STREAM_SEEK_SET, NULL));
|
||||
RINOK(NCompress::CopyStream_ExactSize(baseStream, outStreamReal, inArchive->ArcInfo.Base, NULL));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1210,11 +1212,12 @@ HRESULT Update(
|
||||
|
||||
if (inArchive)
|
||||
{
|
||||
if ((Int64)inArchive->ArcInfo.MarkerPos2 > inArchive->ArcInfo.Base)
|
||||
if (!inArchive->IsMultiVol && (Int64)inArchive->ArcInfo.MarkerPos2 > inArchive->ArcInfo.Base)
|
||||
{
|
||||
RINOK(inArchive->Stream->Seek(inArchive->ArcInfo.Base, STREAM_SEEK_SET, NULL));
|
||||
IInStream *baseStream = inArchive->GetBaseStream();
|
||||
RINOK(baseStream->Seek(inArchive->ArcInfo.Base, STREAM_SEEK_SET, NULL));
|
||||
UInt64 embStubSize = inArchive->ArcInfo.MarkerPos2 - inArchive->ArcInfo.Base;
|
||||
RINOK(NCompress::CopyStream_ExactSize(inArchive->Stream, outStream, embStubSize, NULL));
|
||||
RINOK(NCompress::CopyStream_ExactSize(baseStream, outStream, embStubSize, NULL));
|
||||
outArchive.MoveCurPos(embStubSize);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user