"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "CPP/7zip/Archive/Zip/ZipIn.cpp" between
p7zip_15.14.1_src_all.tar.gz and p7zip_16.02_src_all.tar.gz

About: p7zip is a command-line file archiver with a high compression ratio (a port of the Windows program 7za.exe).

ZipIn.cpp  (p7zip_15.14.1_src_all):ZipIn.cpp  (p7zip_16.02_src_all)
// Archive/ZipIn.cpp // Archive/ZipIn.cpp
#include "StdAfx.h" #include "StdAfx.h"
// #include <stdio.h> // #include <stdio.h>
#include "../../../Common/DynamicBuffer.h" #include "../../../Common/DynamicBuffer.h"
#include "../../../Common/IntToString.h"
#include "../../../Common/StringToInt.h"
#include "../../../Windows/PropVariant.h"
#include "../../Common/LimitedStreams.h"
#include "../../Common/StreamUtils.h" #include "../../Common/StreamUtils.h"
#include "../IArchive.h" #include "../IArchive.h"
#include "ZipIn.h" #include "ZipIn.h"
#define Get16(p) GetUi16(p) #define Get16(p) GetUi16(p)
#define Get32(p) GetUi32(p) #define Get32(p) GetUi32(p)
#define Get64(p) GetUi64(p) #define Get64(p) GetUi64(p)
#define G16(offs, v) v = Get16(p + (offs))
#define G32(offs, v) v = Get32(p + (offs))
#define G64(offs, v) v = Get64(p + (offs))
namespace NArchive { namespace NArchive {
namespace NZip { namespace NZip {
struct CEcd struct CEcd
{ {
UInt16 thisDiskNumber; UInt16 ThisDisk;
UInt16 startCDDiskNumber; UInt16 CdDisk;
UInt16 numEntriesInCDOnThisDisk; UInt16 NumEntries_in_ThisDisk;
UInt16 numEntriesInCD; UInt16 NumEntries;
UInt32 cdSize; UInt32 Size;
UInt32 cdStartOffset; UInt32 Offset;
UInt16 commentSize; UInt16 CommentSize;
void Parse(const Byte *p); bool IsEmptyArc() const
{
bool IsEmptyArc() return ThisDisk == 0
{ && CdDisk == 0
return thisDiskNumber == 0 && startCDDiskNumber == 0 && && NumEntries_in_ThisDisk == 0
numEntriesInCDOnThisDisk == 0 && numEntriesInCD == 0 && cdSize == 0 && NumEntries == 0
&& cdStartOffset == 0 // test it && Size == 0
&& Offset == 0 // test it
; ;
} }
void Parse(const Byte *p); // (p) doesn't include signature
}; };
void CEcd::Parse(const Byte *p) void CEcd::Parse(const Byte *p)
{ {
thisDiskNumber = Get16(p); // (p) doesn't include signature
startCDDiskNumber = Get16(p + 2); G16(0, ThisDisk);
numEntriesInCDOnThisDisk = Get16(p + 4); G16(2, CdDisk);
numEntriesInCD = Get16(p + 6); G16(4, NumEntries_in_ThisDisk);
cdSize = Get32(p + 8); G16(6, NumEntries);
cdStartOffset = Get32(p + 12); G32(8, Size);
commentSize = Get16(p + 16); G32(12, Offset);
} G16(16, CommentSize);
}
struct CEcd64
{
UInt16 versionMade;
UInt16 versionNeedExtract;
UInt32 thisDiskNumber;
UInt32 startCDDiskNumber;
UInt64 numEntriesInCDOnThisDisk;
UInt64 numEntriesInCD;
UInt64 cdSize;
UInt64 cdStartOffset;
void Parse(const Byte *p); void CCdInfo::ParseEcd32(const Byte *p)
CEcd64() { memset(this, 0, sizeof(*this)); } {
}; // (p) includes signature
p += 4;
G16(0, ThisDisk);
G16(2, CdDisk);
G16(4, NumEntries_in_ThisDisk);
G16(6, NumEntries);
G32(8, Size);
G32(12, Offset);
G16(16, CommentSize);
}
void CEcd64::Parse(const Byte *p) void CCdInfo::ParseEcd64e(const Byte *p)
{ {
versionMade = Get16(p); // (p) exclude signature
versionNeedExtract = Get16(p + 2); G16(0, VersionMade);
thisDiskNumber = Get32(p + 4); G16(2, VersionNeedExtract);
startCDDiskNumber = Get32(p + 8); G32(4, ThisDisk);
numEntriesInCDOnThisDisk = Get64(p + 12); G32(8, CdDisk);
numEntriesInCD = Get64(p + 20);
cdSize = Get64(p + 28); G64(12, NumEntries_in_ThisDisk);
cdStartOffset = Get64(p + 36); G64(20, NumEntries);
G64(28, Size);
G64(36, Offset);
} }
HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit) struct CLocator
{ {
_inBufMode = false; UInt32 Ecd64Disk;
Close(); UInt32 NumDisks;
RINOK(stream->Seek(0, STREAM_SEEK_CUR, &m_Position)); UInt64 Ecd64Offset;
RINOK(stream->Seek(0, STREAM_SEEK_END, &ArcInfo.FileEndPos));
RINOK(stream->Seek(m_Position, STREAM_SEEK_SET, NULL));
// printf("\nOpen offset = %d", (int)m_Position); CLocator(): Ecd64Disk(0), NumDisks(0), Ecd64Offset(0) {}
RINOK(FindAndReadMarker(stream, searchHeaderSizeLimit));
RINOK(stream->Seek(m_Position, STREAM_SEEK_SET, NULL)); void Parse(const Byte *p)
Stream = stream; {
return S_OK; G32(0, Ecd64Disk);
G64(4, Ecd64Offset);
G32(12, NumDisks);
}
};
void CInArchive::ClearRefs()
{
StreamRef.Release();
Stream = NULL;
StartStream = NULL;
Callback = NULL;
Vols.Clear();
} }
void CInArchive::Close() void CInArchive::Close()
{ {
_processedCnt = 0;
IsArc = false; IsArc = false;
IsArcOpen = false;
IsMultiVol = false;
UseDisk_in_SingleVol = false;
EcdVolIndex = 0;
HeadersError = false; HeadersError = false;
HeadersWarning = false; HeadersWarning = false;
ExtraMinorError = false; ExtraMinorError = false;
UnexpectedEnd = false; UnexpectedEnd = false;
NoCentralDir = false; NoCentralDir = false;
IsZip64 = false; IsZip64 = false;
Stream.Release(); MarkerIsFound = false;
ClearRefs();
} }
HRESULT CInArchive::Seek(UInt64 offset) HRESULT CInArchive::Seek(UInt64 offset)
{ {
return Stream->Seek(offset, STREAM_SEEK_SET, NULL); return Stream->Seek(offset, STREAM_SEEK_SET, NULL);
} }
static bool CheckDosTime(UInt32 dosTime) static bool CheckDosTime(UInt32 dosTime)
{ {
if (dosTime == 0) if (dosTime == 0)
skipping to change at line 137 skipping to change at line 166
API_FUNC_IsArc IsArc_Zip(const Byte *p, size_t size) API_FUNC_IsArc IsArc_Zip(const Byte *p, size_t size)
{ {
if (size < 8) if (size < 8)
return k_IsArc_Res_NEED_MORE; return k_IsArc_Res_NEED_MORE;
if (p[0] != 'P') if (p[0] != 'P')
return k_IsArc_Res_NO; return k_IsArc_Res_NO;
UInt32 value = Get32(p); UInt32 value = Get32(p);
if (value == NSignature::kNoSpan) if (value == NSignature::kNoSpan
|| value == NSignature::kSpan)
{ {
p += 4; p += 4;
size -= 4; size -= 4;
} }
value = Get32(p); value = Get32(p);
if (value == NSignature::kEcd) if (value == NSignature::kEcd)
{ {
if (size < kEcdSize) if (size < kEcdSize)
skipping to change at line 253 skipping to change at line 283
} }
static UInt32 IsArc_Zip_2(const Byte *p, size_t size, bool isFinal) static UInt32 IsArc_Zip_2(const Byte *p, size_t size, bool isFinal)
{ {
UInt32 res = IsArc_Zip(p, size); UInt32 res = IsArc_Zip(p, size);
if (res == k_IsArc_Res_NEED_MORE && isFinal) if (res == k_IsArc_Res_NEED_MORE && isFinal)
return k_IsArc_Res_NO; return k_IsArc_Res_NO;
return res; return res;
} }
HRESULT CInArchive::FindAndReadMarker(IInStream *stream, const UInt64 *searchLim it) HRESULT CInArchive::FindMarker(IInStream *stream, const UInt64 *searchLimit)
{ {
ArcInfo.Clear();
ArcInfo.MarkerPos = m_Position; ArcInfo.MarkerPos = m_Position;
ArcInfo.MarkerPos2 = m_Position; ArcInfo.MarkerPos2 = m_Position;
if (searchLimit && *searchLimit == 0) if (searchLimit && *searchLimit == 0)
{ {
const unsigned kStartBufSize = kMarkerSize; Byte startBuf[kMarkerSize];
Byte startBuf[kStartBufSize]; {
size_t processed = kStartBufSize; size_t processed = kMarkerSize;
RINOK(ReadStream(stream, startBuf, &processed)); RINOK(ReadStream(stream, startBuf, &processed));
m_Position += processed; m_Position += processed;
if (processed < kMarkerSize) if (processed != kMarkerSize)
return S_FALSE; return S_FALSE;
}
m_Signature = Get32(startBuf); m_Signature = Get32(startBuf);
if (m_Signature != NSignature::kEcd && if (m_Signature != NSignature::kEcd &&
m_Signature != NSignature::kLocalFileHeader) m_Signature != NSignature::kLocalFileHeader)
{ {
if (m_Signature != NSignature::kNoSpan) if (m_Signature != NSignature::kNoSpan)
return S_FALSE; {
size_t processed = kStartBufSize; if (m_Signature != NSignature::kSpan)
return S_FALSE;
if (m_Position != 4) // we don't support multivol archives with sfx stub
return S_FALSE;
ArcInfo.IsSpanMode = true;
}
size_t processed = kMarkerSize;
RINOK(ReadStream(stream, startBuf, &processed)); RINOK(ReadStream(stream, startBuf, &processed));
m_Position += processed; m_Position += processed;
if (processed < kMarkerSize) if (processed != kMarkerSize)
return S_FALSE; return S_FALSE;
m_Signature = Get32(startBuf); m_Signature = Get32(startBuf);
if (m_Signature != NSignature::kEcd && if (m_Signature != NSignature::kEcd &&
m_Signature != NSignature::kLocalFileHeader) m_Signature != NSignature::kLocalFileHeader)
return S_FALSE; return S_FALSE;
ArcInfo.MarkerPos2 += 4; ArcInfo.MarkerPos2 += 4;
} }
// we use weak test in case of *searchLimit == 0) // we use weak test in case of (*searchLimit == 0)
// since error will be detected later in Open function // since error will be detected later in Open function
// m_Position = ArcInfo.MarkerPos2 + 4;
return S_OK; // maybe we need to search backward. return S_OK; // maybe we need to search backward.
} }
const size_t kBufSize = (size_t)1 << 18; // must be larger than kCheckSize const size_t kBufSize = (size_t)1 << 18; // must be larger than kCheckSize
const size_t kCheckSize = (size_t)1 << 16; // must be smaller than kBufSize const size_t kCheckSize = (size_t)1 << 16; // must be smaller than kBufSize
CByteArr buffer(kBufSize); CByteArr buffer(kBufSize);
size_t numBytesInBuffer = 0; size_t numBytesInBuffer = 0;
UInt64 curScanPos = 0; UInt64 curScanPos = 0;
for (;;) for (;;)
{ {
size_t numReadBytes = kBufSize - numBytesInBuffer; size_t numReadBytes = kBufSize - numBytesInBuffer;
RINOK(ReadStream(stream, buffer + numBytesInBuffer, &numReadBytes)); RINOK(ReadStream(stream, buffer + numBytesInBuffer, &numReadBytes));
m_Position += numReadBytes; m_Position += numReadBytes;
numBytesInBuffer += numReadBytes; numBytesInBuffer += numReadBytes;
bool isFinished = (numBytesInBuffer != kBufSize); const bool isFinished = (numBytesInBuffer != kBufSize);
size_t limit = (isFinished ? numBytesInBuffer : numBytesInBuffer - kCheckSiz size_t limit = numBytesInBuffer;;
e); if (isFinished)
{
if (limit == 0)
break;
limit--;
}
else
limit -= kCheckSize;
if (searchLimit && curScanPos + limit > *searchLimit) if (searchLimit && curScanPos + limit > *searchLimit)
limit = (size_t)(*searchLimit - curScanPos + 1); limit = (size_t)(*searchLimit - curScanPos + 1);
if (limit < 1) if (limit < 1)
break; break;
const Byte *buf = buffer; const Byte *buf = buffer;
for (size_t pos = 0; pos < limit; pos++) for (size_t pos = 0; pos < limit; pos++)
{ {
skipping to change at line 331 skipping to change at line 376
continue; continue;
size_t rem = numBytesInBuffer - pos; size_t rem = numBytesInBuffer - pos;
UInt32 res = IsArc_Zip_2(buf + pos, rem, isFinished); UInt32 res = IsArc_Zip_2(buf + pos, rem, isFinished);
if (res != k_IsArc_Res_NO) if (res != k_IsArc_Res_NO)
{ {
if (rem < kMarkerSize) if (rem < kMarkerSize)
return S_FALSE; return S_FALSE;
m_Signature = Get32(buf + pos); m_Signature = Get32(buf + pos);
ArcInfo.MarkerPos += curScanPos + pos; ArcInfo.MarkerPos += curScanPos + pos;
ArcInfo.MarkerPos2 = ArcInfo.MarkerPos; ArcInfo.MarkerPos2 = ArcInfo.MarkerPos;
if (m_Signature == NSignature::kNoSpan) if (m_Signature == NSignature::kNoSpan
|| m_Signature == NSignature::kSpan)
{ {
m_Signature = Get32(buf + pos + 4); m_Signature = Get32(buf + pos + 4);
ArcInfo.MarkerPos2 += 4; ArcInfo.MarkerPos2 += 4;
} }
m_Position = ArcInfo.MarkerPos2 + kMarkerSize; m_Position = ArcInfo.MarkerPos2 + kMarkerSize;
return S_OK; return S_OK;
} }
} }
if (isFinished) if (isFinished)
break; break;
curScanPos += limit; curScanPos += limit;
numBytesInBuffer -= limit; numBytesInBuffer -= limit;
memmove(buffer, buffer + limit, numBytesInBuffer); memmove(buffer, buffer + limit, numBytesInBuffer);
} }
return S_FALSE; return S_FALSE;
} }
HRESULT CInArchive::IncreaseRealPosition(Int64 addValue) HRESULT CInArchive::IncreaseRealPosition(Int64 addValue, bool &isFinished)
{ {
return Stream->Seek(addValue, STREAM_SEEK_CUR, &m_Position); isFinished = false;
if (!IsMultiVol)
return Stream->Seek(addValue, STREAM_SEEK_CUR, &m_Position);
for (;;)
{
if (addValue == 0)
return S_OK;
if (addValue > 0)
{
if (Vols.StreamIndex < 0)
return S_FALSE;
if ((unsigned)Vols.StreamIndex >= Vols.Streams.Size())
{
isFinished = true;
return S_OK;
}
{
const CVols::CSubStreamInfo &s = Vols.Streams[Vols.StreamIndex];
if (!s.Stream)
{
isFinished = true;
return S_OK;
}
if (m_Position > s.Size)
return S_FALSE;
UInt64 rem = s.Size - m_Position;
if ((UInt64)addValue <= rem)
return Stream->Seek(addValue, STREAM_SEEK_CUR, &m_Position);
RINOK(Stream->Seek(s.Size, STREAM_SEEK_SET, &m_Position));
addValue -= rem;
Stream = NULL;
Vols.StreamIndex++;
if ((unsigned)Vols.StreamIndex >= Vols.Streams.Size())
{
isFinished = true;
return S_OK;
}
}
const CVols::CSubStreamInfo &s2 = Vols.Streams[Vols.StreamIndex];
if (!s2.Stream)
{
isFinished = true;
return S_OK;
}
Stream = s2.Stream;
m_Position = 0;
RINOK(Stream->Seek(0, STREAM_SEEK_SET, &m_Position));
}
else
{
if (!Stream)
return S_FALSE;
{
if (m_Position >= (UInt64)(-addValue))
return Stream->Seek(addValue, STREAM_SEEK_CUR, &m_Position);
addValue += m_Position;
RINOK(Stream->Seek(0, STREAM_SEEK_SET, &m_Position));
m_Position = 0;
Stream = NULL;
if (--Vols.StreamIndex < 0)
return S_FALSE;
}
const CVols::CSubStreamInfo &s2 = Vols.Streams[Vols.StreamIndex];
if (!s2.Stream)
return S_FALSE;
Stream = s2.Stream;
m_Position = s2.Size;
RINOK(Stream->Seek(s2.Size, STREAM_SEEK_SET, &m_Position));
}
}
} }
class CUnexpectEnd {}; class CUnexpectEnd {};
HRESULT CInArchive::ReadBytes(void *data, UInt32 size, UInt32 *processedSize) HRESULT CInArchive::ReadBytes(void *data, UInt32 size, UInt32 *processedSize)
{ {
size_t realProcessedSize = size; size_t realProcessedSize = size;
HRESULT result = S_OK; HRESULT result = S_OK;
if (_inBufMode) if (_inBufMode)
{ {
skipping to change at line 379 skipping to change at line 495
result = ReadStream(Stream, data, &realProcessedSize); result = ReadStream(Stream, data, &realProcessedSize);
if (processedSize) if (processedSize)
*processedSize = (UInt32)realProcessedSize; *processedSize = (UInt32)realProcessedSize;
m_Position += realProcessedSize; m_Position += realProcessedSize;
return result; return result;
} }
void CInArchive::SafeReadBytes(void *data, unsigned size) void CInArchive::SafeReadBytes(void *data, unsigned size)
{ {
size_t processed = size; size_t processed = size;
if (_inBufMode)
{ HRESULT result = S_OK;
processed = _inBuffer.ReadBytes((Byte *)data, size);
m_Position += processed; if (!_inBufMode)
} result = ReadStream(Stream, data, &processed);
else else
{ {
HRESULT result = ReadStream(Stream, data, &processed); for (;;)
m_Position += processed; {
if (result != S_OK) processed = _inBuffer.ReadBytes((Byte *)data, size);
throw CSystemException(result); if (processed != 0
|| IsMultiVol
|| !CanStartNewVol
|| Vols.StreamIndex < 0
|| (unsigned)Vols.StreamIndex >= Vols.Streams.Size())
break;
Vols.StreamIndex++;
const CVols::CSubStreamInfo &s = Vols.Streams[Vols.StreamIndex];
if (!s.Stream)
break;
// if (Vols.NeedSeek)
{
result = s.Stream->Seek(0, STREAM_SEEK_SET, NULL);
m_Position = 0;
if (result != S_OK)
break;
Vols.NeedSeek = false;
}
_inBuffer.SetStream(s.Stream);
_inBuffer.Init();
}
CanStartNewVol = false;
} }
m_Position += processed;
_processedCnt += processed;
if (result != S_OK)
throw CSystemException(result);
if (processed != size) if (processed != size)
throw CUnexpectEnd(); throw CUnexpectEnd();
} }
void CInArchive::ReadBuffer(CByteBuffer &buffer, unsigned size) void CInArchive::ReadBuffer(CByteBuffer &buffer, unsigned size)
{ {
buffer.Alloc(size); buffer.Alloc(size);
if (size > 0) if (size > 0)
SafeReadBytes(buffer, size); SafeReadBytes(buffer, size);
} }
skipping to change at line 413 skipping to change at line 557
{ {
Byte b; Byte b;
SafeReadBytes(&b, 1); SafeReadBytes(&b, 1);
return b; return b;
} }
UInt16 CInArchive::ReadUInt16() { Byte buf[2]; SafeReadBytes(buf, 2); return Get 16(buf); } UInt16 CInArchive::ReadUInt16() { Byte buf[2]; SafeReadBytes(buf, 2); return Get 16(buf); }
UInt32 CInArchive::ReadUInt32() { Byte buf[4]; SafeReadBytes(buf, 4); return Get 32(buf); } UInt32 CInArchive::ReadUInt32() { Byte buf[4]; SafeReadBytes(buf, 4); return Get 32(buf); }
UInt64 CInArchive::ReadUInt64() { Byte buf[8]; SafeReadBytes(buf, 8); return Get 64(buf); } UInt64 CInArchive::ReadUInt64() { Byte buf[8]; SafeReadBytes(buf, 8); return Get 64(buf); }
// we use Skip() inside headers only, so no need for stream change in multivol.
void CInArchive::Skip(unsigned num) void CInArchive::Skip(unsigned num)
{ {
if (_inBufMode) if (_inBufMode)
{ {
size_t skip = _inBuffer.Skip(num); size_t skip = _inBuffer.Skip(num);
m_Position += skip; m_Position += skip;
_processedCnt += skip;
if (skip != num) if (skip != num)
throw CUnexpectEnd(); throw CUnexpectEnd();
} }
else else
{ {
for (unsigned i = 0; i < num; i++) for (unsigned i = 0; i < num; i++)
ReadByte(); ReadByte();
} }
} }
skipping to change at line 442 skipping to change at line 589
ReadByte(); ReadByte();
} }
void CInArchive::ReadFileName(unsigned size, AString &s) void CInArchive::ReadFileName(unsigned size, AString &s)
{ {
if (size == 0) if (size == 0)
{ {
s.Empty(); s.Empty();
return; return;
} }
char *p = s.GetBuf(size); SafeReadBytes(s.GetBuf(size), size);
SafeReadBytes(p, size);
s.ReleaseBuf_CalcLen(size); s.ReleaseBuf_CalcLen(size);
} }
bool CInArchive::ReadExtra(unsigned extraSize, CExtraBlock &extraBlock, bool CInArchive::ReadExtra(unsigned extraSize, CExtraBlock &extraBlock,
UInt64 &unpackSize, UInt64 &packSize, UInt64 &localHeaderOffset, UInt32 &dis kStartNumber) UInt64 &unpackSize, UInt64 &packSize, UInt64 &localHeaderOffset, UInt32 &dis kStartNumber)
{ {
extraBlock.Clear(); extraBlock.Clear();
UInt32 remain = extraSize; UInt32 remain = extraSize;
while (remain >= 4) while (remain >= 4)
{ {
CExtraSubBlock subBlock; CExtraSubBlock subBlock;
subBlock.ID = ReadUInt16(); subBlock.ID = ReadUInt16();
unsigned dataSize = ReadUInt16(); unsigned dataSize = ReadUInt16();
remain -= 4; remain -= 4;
if (dataSize > remain) // it's bug if (dataSize > remain) // it's bug
{ {
HeadersWarning = true; HeadersWarning = true;
Skip(remain); Skip(remain);
skipping to change at line 511 skipping to change at line 659
} }
Skip(dataSize); Skip(dataSize);
} }
else else
{ {
ReadBuffer(subBlock.Data, dataSize); ReadBuffer(subBlock.Data, dataSize);
extraBlock.SubBlocks.Add(subBlock); extraBlock.SubBlocks.Add(subBlock);
} }
remain -= dataSize; remain -= dataSize;
} }
if (remain != 0) if (remain != 0)
{ {
ExtraMinorError = true; ExtraMinorError = true;
// 7-Zip before 9.31 created incorrect WsAES Extra in folder's local headers . // 7-Zip before 9.31 created incorrect WsAES Extra in folder's local headers .
// so we don't return false, but just set warning flag // so we don't return false, but just set warning flag
// return false; // return false;
} }
Skip(remain); Skip(remain);
return true; return true;
} }
bool CInArchive::ReadLocalItem(CItemEx &item) bool CInArchive::ReadLocalItem(CItemEx &item)
{ {
item.Disk = 0;
if (IsMultiVol && Vols.StreamIndex >= 0)
item.Disk = Vols.StreamIndex;
const unsigned kPureHeaderSize = kLocalHeaderSize - 4; const unsigned kPureHeaderSize = kLocalHeaderSize - 4;
Byte p[kPureHeaderSize]; Byte p[kPureHeaderSize];
SafeReadBytes(p, kPureHeaderSize); SafeReadBytes(p, kPureHeaderSize);
{ {
unsigned i; unsigned i;
for (i = 0; i < kPureHeaderSize && p[i] == 0; i++); for (i = 0; i < kPureHeaderSize && p[i] == 0; i++);
if (i == kPureHeaderSize) if (i == kPureHeaderSize)
return false; return false;
} }
item.ExtractVersion.Version = p[0]; item.ExtractVersion.Version = p[0];
item.ExtractVersion.HostOS = p[1]; item.ExtractVersion.HostOS = p[1];
item.Flags = Get16(p + 2); G16(2, item.Flags);
item.Method = Get16(p + 4); G16(4, item.Method);
item.Time = Get32(p + 6); G32(6, item.Time);
item.Crc = Get32(p + 10); G32(10, item.Crc);
item.PackSize = Get32(p + 14); G32(14, item.PackSize);
item.Size = Get32(p + 18); G32(18, item.Size);
unsigned nameSize = Get16(p + 22); const unsigned nameSize = Get16(p + 22);
unsigned extraSize = Get16(p + 24); const unsigned extraSize = Get16(p + 24);
ReadFileName(nameSize, item.Name); ReadFileName(nameSize, item.Name);
item.LocalFullHeaderSize = kLocalHeaderSize + (UInt32)nameSize + extraSize; item.LocalFullHeaderSize = kLocalHeaderSize + (UInt32)nameSize + extraSize;
/* /*
if (item.IsDir()) if (item.IsDir())
item.Size = 0; // check It item.Size = 0; // check It
*/ */
if (extraSize > 0) if (extraSize > 0)
{ {
skipping to change at line 599 skipping to change at line 752
UInt32 mask = 0xFFFF; UInt32 mask = 0xFFFF;
switch (i1.Method) switch (i1.Method)
{ {
case NFileHeader::NCompressionMethod::kDeflated: case NFileHeader::NCompressionMethod::kDeflated:
mask = 0x7FF9; mask = 0x7FF9;
break; break;
default: default:
if (i1.Method <= NFileHeader::NCompressionMethod::kImploded) if (i1.Method <= NFileHeader::NCompressionMethod::kImploded)
mask = 0x7FFF; mask = 0x7FFF;
} }
// we can ignore utf8 flag, if name is ascii
if ((i1.Flags ^ i2.Flags) & NFileHeader::NFlags::kUtf8)
if (i1.Name.IsAscii() && i2.Name.IsAscii())
mask &= ~NFileHeader::NFlags::kUtf8;
return ((i1.Flags & mask) == (i2.Flags & mask)); return ((i1.Flags & mask) == (i2.Flags & mask));
} }
// #ifdef _WIN32 // #ifdef _WIN32
static bool AreEqualPaths_IgnoreSlashes(const char *s1, const char *s2) static bool AreEqualPaths_IgnoreSlashes(const char *s1, const char *s2)
{ {
for (;;) for (;;)
{ {
char c1 = *s1++; char c1 = *s1++;
char c2 = *s2++; char c2 = *s2++;
skipping to change at line 672 skipping to change at line 831
} }
/* /*
else else
#endif #endif
return false; return false;
*/ */
} }
return true; return true;
} }
HRESULT CInArchive::ReadLocalItemAfterCdItem(CItemEx &item) HRESULT CInArchive::ReadLocalItemAfterCdItem(CItemEx &item, bool &isAvail)
{ {
isAvail = true;
if (item.FromLocal) if (item.FromLocal)
return S_OK; return S_OK;
try try
{ {
UInt64 offset = ArcInfo.Base + item.LocalHeaderPos; UInt64 offset = item.LocalHeaderPos;
if (ArcInfo.Base < 0 && (Int64)offset < 0)
return S_FALSE; if (IsMultiVol)
RINOK(Seek(offset)); {
if (item.Disk >= Vols.Streams.Size())
{
isAvail = false;
return S_FALSE;
}
IInStream *str2 = Vols.Streams[item.Disk].Stream;
if (!str2)
{
isAvail = false;
return S_FALSE;
}
RINOK(str2->Seek(offset, STREAM_SEEK_SET, NULL));
Stream = str2;
Vols.StreamIndex = item.Disk;
}
else
{
if (UseDisk_in_SingleVol && item.Disk != EcdVolIndex)
{
isAvail = false;
return S_FALSE;
}
Stream = StreamRef;
offset += ArcInfo.Base;
if (ArcInfo.Base < 0 && (Int64)offset < 0)
{
isAvail = false;
return S_FALSE;
}
RINOK(Seek(offset));
}
CItemEx localItem; CItemEx localItem;
if (ReadUInt32() != NSignature::kLocalFileHeader) if (ReadUInt32() != NSignature::kLocalFileHeader)
return S_FALSE; return S_FALSE;
ReadLocalItem(localItem); ReadLocalItem(localItem);
if (!AreItemsEqual(localItem, item)) if (!AreItemsEqual(localItem, item))
return S_FALSE; return S_FALSE;
item.LocalFullHeaderSize = localItem.LocalFullHeaderSize; item.LocalFullHeaderSize = localItem.LocalFullHeaderSize;
item.LocalExtra = localItem.LocalExtra; item.LocalExtra = localItem.LocalExtra;
item.FromLocal = true; item.FromLocal = true;
} }
skipping to change at line 728 skipping to change at line 921
continue; continue;
// !!!! It must be fixed for Zip64 archives // !!!! It must be fixed for Zip64 archives
if (Get32(buf + i) == NSignature::kDataDescriptor) if (Get32(buf + i) == NSignature::kDataDescriptor)
{ {
UInt32 descriptorPackSize = Get32(buf + i + 8); UInt32 descriptorPackSize = Get32(buf + i + 8);
if (descriptorPackSize == packedSize + i) if (descriptorPackSize == packedSize + i)
{ {
item.Crc = Get32(buf + i + 4); item.Crc = Get32(buf + i + 4);
item.PackSize = descriptorPackSize; item.PackSize = descriptorPackSize;
item.Size = Get32(buf + i + 12); item.Size = Get32(buf + i + 12);
return IncreaseRealPosition((Int64)(Int32)(0 - (numBytesInBuffer - i - bool isFinished;
kDataDescriptorSize))); return IncreaseRealPosition((Int64)(Int32)(0 - (numBytesInBuffer - i -
kDataDescriptorSize)), isFinished);
} }
} }
} }
packedSize += i; packedSize += i;
unsigned j; unsigned j;
for (j = 0; i < numBytesInBuffer; i++, j++) for (j = 0; i < numBytesInBuffer; i++, j++)
buf[j] = buf[i]; buf[j] = buf[i];
numBytesInBuffer = j; numBytesInBuffer = j;
} }
} }
HRESULT CInArchive::ReadLocalItemAfterCdItemFull(CItemEx &item) HRESULT CInArchive::ReadLocalItemAfterCdItemFull(CItemEx &item)
{ {
if (item.FromLocal) if (item.FromLocal)
return S_OK; return S_OK;
try try
{ {
RINOK(ReadLocalItemAfterCdItem(item)); bool isAvail = true;
RINOK(ReadLocalItemAfterCdItem(item, isAvail));
if (item.HasDescriptor()) if (item.HasDescriptor())
{ {
// pkzip's version without descriptor is not supported
RINOK(Seek(ArcInfo.Base + item.GetDataPosition() + item.PackSize)); RINOK(Seek(ArcInfo.Base + item.GetDataPosition() + item.PackSize));
if (ReadUInt32() != NSignature::kDataDescriptor) if (ReadUInt32() != NSignature::kDataDescriptor)
return S_FALSE; return S_FALSE;
UInt32 crc = ReadUInt32(); UInt32 crc = ReadUInt32();
UInt64 packSize, unpackSize; UInt64 packSize, unpackSize;
/* /*
if (IsZip64) if (IsZip64)
{ {
packSize = ReadUInt64(); packSize = ReadUInt64();
skipping to change at line 787 skipping to change at line 983
HRESULT CInArchive::ReadCdItem(CItemEx &item) HRESULT CInArchive::ReadCdItem(CItemEx &item)
{ {
item.FromCentral = true; item.FromCentral = true;
Byte p[kCentralHeaderSize - 4]; Byte p[kCentralHeaderSize - 4];
SafeReadBytes(p, kCentralHeaderSize - 4); SafeReadBytes(p, kCentralHeaderSize - 4);
item.MadeByVersion.Version = p[0]; item.MadeByVersion.Version = p[0];
item.MadeByVersion.HostOS = p[1]; item.MadeByVersion.HostOS = p[1];
item.ExtractVersion.Version = p[2]; item.ExtractVersion.Version = p[2];
item.ExtractVersion.HostOS = p[3]; item.ExtractVersion.HostOS = p[3];
item.Flags = Get16(p + 4); G16(4, item.Flags);
item.Method = Get16(p + 6); G16(6, item.Method);
item.Time = Get32(p + 8); G32(8, item.Time);
item.Crc = Get32(p + 12); G32(12, item.Crc);
item.PackSize = Get32(p + 16); G32(16, item.PackSize);
item.Size = Get32(p + 20); G32(20, item.Size);
const unsigned nameSize = Get16(p + 24); const unsigned nameSize = Get16(p + 24);
const unsigned extraSize = Get16(p + 26); const unsigned extraSize = Get16(p + 26);
const unsigned commentSize = Get16(p + 28); const unsigned commentSize = Get16(p + 28);
UInt32 diskNumberStart = Get16(p + 30); G16(30, item.Disk);
item.InternalAttrib = Get16(p + 32); G16(32, item.InternalAttrib);
item.ExternalAttrib = Get32(p + 34); G32(34, item.ExternalAttrib);
item.LocalHeaderPos = Get32(p + 38); G32(38, item.LocalHeaderPos);
ReadFileName(nameSize, item.Name); ReadFileName(nameSize, item.Name);
if (extraSize > 0) if (extraSize > 0)
{ ReadExtra(extraSize, item.CentralExtra, item.Size, item.PackSize, item.Local
ReadExtra(extraSize, item.CentralExtra, item.Size, item.PackSize, HeaderPos, item.Disk);
item.LocalHeaderPos, diskNumberStart);
}
if (diskNumberStart != 0)
return E_NOTIMPL;
// May be these strings must be deleted // May be these strings must be deleted
/* /*
if (item.IsDir()) if (item.IsDir())
item.Size = 0; item.Size = 0;
*/ */
ReadBuffer(item.Comment, commentSize); ReadBuffer(item.Comment, commentSize);
return S_OK; return S_OK;
} }
void CCdInfo::ParseEcd(const Byte *p)
{
NumEntries = Get16(p + 10);
Size = Get32(p + 12);
Offset = Get32(p + 16);
}
void CCdInfo::ParseEcd64(const Byte *p)
{
NumEntries = Get64(p + 24);
Size = Get64(p + 40);
Offset = Get64(p + 48);
}
HRESULT CInArchive::TryEcd64(UInt64 offset, CCdInfo &cdInfo) HRESULT CInArchive::TryEcd64(UInt64 offset, CCdInfo &cdInfo)
{ {
if (offset >= ((UInt64)1 << 63)) if (offset >= ((UInt64)1 << 63))
return S_FALSE; return S_FALSE;
RINOK(Seek(offset)); RINOK(Seek(offset));
Byte buf[kEcd64_FullSize]; Byte buf[kEcd64_FullSize];
RINOK(ReadStream_FALSE(Stream, buf, kEcd64_FullSize)); RINOK(ReadStream_FALSE(Stream, buf, kEcd64_FullSize));
if (Get32(buf) != NSignature::kEcd64) if (Get32(buf) != NSignature::kEcd64)
return S_FALSE; return S_FALSE;
UInt64 mainSize = Get64(buf + 4); UInt64 mainSize = Get64(buf + 4);
if (mainSize < kEcd64_MainSize || mainSize > ((UInt64)1 << 32)) if (mainSize < kEcd64_MainSize || mainSize > ((UInt64)1 << 32))
return S_FALSE; return S_FALSE;
cdInfo.ParseEcd64(buf); cdInfo.ParseEcd64e(buf + 12);
return S_OK; return S_OK;
} }
HRESULT CInArchive::FindCd(CCdInfo &cdInfo) HRESULT CInArchive::FindCd(bool checkOffsetMode)
{ {
UInt64 endPosition; CCdInfo &cdInfo = Vols.ecd;
RINOK(Stream->Seek(0, STREAM_SEEK_END, &endPosition));
UInt64 endPos;
RINOK(Stream->Seek(0, STREAM_SEEK_END, &endPos));
const UInt32 kBufSizeMax = ((UInt32)1 << 16) + kEcdSize + kEcd64Locator_Size + kEcd64_FullSize; const UInt32 kBufSizeMax = ((UInt32)1 << 16) + kEcdSize + kEcd64Locator_Size + kEcd64_FullSize;
UInt32 bufSize = (endPosition < kBufSizeMax) ? (UInt32)endPosition : kBufSizeM ax; const UInt32 bufSize = (endPos < kBufSizeMax) ? (UInt32)endPos : kBufSizeMax;
if (bufSize < kEcdSize) if (bufSize < kEcdSize)
return S_FALSE; return S_FALSE;
CByteArr byteBuffer(bufSize); CByteArr byteBuffer(bufSize);
UInt64 startPosition = endPosition - bufSize; const UInt64 startPos = endPos - bufSize;
RINOK(Stream->Seek(startPosition, STREAM_SEEK_SET, &m_Position)); RINOK(Stream->Seek(startPos, STREAM_SEEK_SET, &m_Position));
if (m_Position != startPosition) if (m_Position != startPos)
return S_FALSE; return S_FALSE;
RINOK(ReadStream_FALSE(Stream, byteBuffer, bufSize)); RINOK(ReadStream_FALSE(Stream, byteBuffer, bufSize));
const Byte *buf = byteBuffer; for (UInt32 i = bufSize - kEcdSize + 1;;)
for (UInt32 i = bufSize - kEcdSize;; i--)
{ {
if (buf[i] != 0x50) if (i == 0)
return S_FALSE;
const Byte *buf = byteBuffer;
for (;;)
{ {
if (i == 0) return S_FALSE;
i--; i--;
if (buf[i] != 0x50) if (buf[i] == 0x50)
{ break;
if (i == 0) return S_FALSE; if (i == 0)
continue; return S_FALSE;
}
} }
if (Get32(buf + i) == NSignature::kEcd)
if (Get32(buf + i) != NSignature::kEcd)
continue;
cdInfo.ParseEcd32(buf + i);
if (i >= kEcd64Locator_Size)
{ {
if (i >= kEcd64_FullSize + kEcd64Locator_Size) const Byte *locatorPtr = buf + i - kEcd64Locator_Size;
if (Get32(locatorPtr) == NSignature::kEcd64Locator)
{ {
const Byte *locator = buf + i - kEcd64Locator_Size; CLocator locator;
if (Get32(locator) == NSignature::kEcd64Locator && locator.Parse(locatorPtr + 4);
Get32(locator + 4) == 0) // number of the disk with the start of the if ((cdInfo.ThisDisk == locator.NumDisks - 1 || cdInfo.ThisDisk == 0xFFF
zip64 ECD F)
&& locator.Ecd64Disk < locator.NumDisks)
{ {
if (locator.Ecd64Disk != cdInfo.ThisDisk && cdInfo.ThisDisk != 0xFFFF)
return E_NOTIMPL;
// Most of the zip64 use fixed size Zip64 ECD // Most of the zip64 use fixed size Zip64 ECD
// we try relative backward reading.
UInt64 ecd64Offset = Get64(locator + 8); UInt64 absEcd64 = endPos - bufSize + i - (kEcd64Locator_Size + kEcd64_
UInt64 absEcd64 = endPosition - bufSize + i - (kEcd64Locator_Size + kE FullSize);
cd64_FullSize); if (checkOffsetMode || absEcd64 == locator.Ecd64Offset)
{ {
const Byte *ecd64 = locator - kEcd64_FullSize; const Byte *ecd64 = locatorPtr - kEcd64_FullSize;
if (Get32(ecd64) == NSignature::kEcd64 && if (Get32(ecd64) == NSignature::kEcd64)
Get64(ecd64 + 4) == kEcd64_MainSize)
{ {
cdInfo.ParseEcd64(ecd64); UInt64 mainEcd64Size = Get64(ecd64 + 4);
ArcInfo.Base = absEcd64 - ecd64Offset; if (mainEcd64Size == kEcd64_MainSize)
return S_OK; {
cdInfo.ParseEcd64e(ecd64 + 12);
ArcInfo.Base = absEcd64 - locator.Ecd64Offset;
// ArcInfo.BaseVolIndex = cdInfo.ThisDisk;
return S_OK;
}
} }
} }
// some zip64 use variable size Zip64 ECD. // some zip64 use variable size Zip64 ECD.
// we try to find it // we try to use absolute offset from locator.
if (absEcd64 != ecd64Offset)
if (absEcd64 != locator.Ecd64Offset)
{ {
if (TryEcd64(ecd64Offset, cdInfo) == S_OK) if (TryEcd64(locator.Ecd64Offset, cdInfo) == S_OK)
{ {
ArcInfo.Base = 0; ArcInfo.Base = 0;
// ArcInfo.BaseVolIndex = cdInfo.ThisDisk;
return S_OK; return S_OK;
} }
} }
if (ArcInfo.MarkerPos != 0 &&
ArcInfo.MarkerPos + ecd64Offset != absEcd64) // for variable Zip64 ECD with for archives with offset != 0.
if (checkOffsetMode
&& ArcInfo.MarkerPos != 0
&& ArcInfo.MarkerPos + locator.Ecd64Offset != absEcd64)
{ {
if (TryEcd64(ArcInfo.MarkerPos + ecd64Offset, cdInfo) == S_OK) if (TryEcd64(ArcInfo.MarkerPos + locator.Ecd64Offset, cdInfo) == S_O K)
{ {
ArcInfo.Base = ArcInfo.MarkerPos; ArcInfo.Base = ArcInfo.MarkerPos;
// ArcInfo.BaseVolIndex = cdInfo.ThisDisk;
return S_OK; return S_OK;
} }
} }
} }
} }
if (Get32(buf + i + 4) == 0) // ThisDiskNumber, StartCentralDirectoryDiskN }
umber;
// bool isVolMode = (Vols.EndVolIndex != -1);
// UInt32 searchDisk = (isVolMode ? Vols.EndVolIndex : 0);
if (/* searchDisk == thisDisk && */ cdInfo.CdDisk <= cdInfo.ThisDisk)
{
// if (isVolMode)
{
if (cdInfo.CdDisk != cdInfo.ThisDisk)
return S_OK;
}
UInt64 absEcdPos = endPos - bufSize + i;
UInt64 cdEnd = cdInfo.Size + cdInfo.Offset;
ArcInfo.Base = 0;
// ArcInfo.BaseVolIndex = cdInfo.ThisDisk;
if (absEcdPos != cdEnd)
{ {
cdInfo.ParseEcd(buf + i); /*
UInt64 absEcdPos = endPosition - bufSize + i; if (cdInfo.Offset <= 16 && cdInfo.Size != 0)
UInt64 cdEnd = cdInfo.Size + cdInfo.Offset;
ArcInfo.Base = 0;
if (absEcdPos != cdEnd)
{ {
/* // here we support some rare ZIP files with Central directory at the s
if (cdInfo.Offset <= 16 && cdInfo.Size != 0) tart
{ ArcInfo.Base = 0;
// here we support some rare ZIP files with Central directory at the
start
ArcInfo.Base = 0;
}
else
*/
ArcInfo.Base = absEcdPos - cdEnd;
} }
return S_OK; else
*/
ArcInfo.Base = absEcdPos - cdEnd;
} }
return S_OK;
} }
if (i == 0)
return S_FALSE;
} }
} }
HRESULT CInArchive::TryReadCd(CObjectVector<CItemEx> &items, UInt64 cdOffset, UI nt64 cdSize, CProgressVirt *progress) HRESULT CInArchive::TryReadCd(CObjectVector<CItemEx> &items, const CCdInfo &cdIn fo, UInt64 cdOffset, UInt64 cdSize)
{ {
items.Clear(); items.Clear();
RINOK(Stream->Seek(cdOffset, STREAM_SEEK_SET, &m_Position));
if (m_Position != cdOffset) ISequentialInStream *stream;
return S_FALSE;
if (!IsMultiVol)
{
stream = this->StartStream;
Vols.StreamIndex = -1;
RINOK(this->StartStream->Seek(cdOffset, STREAM_SEEK_SET, &m_Position));
if (m_Position != cdOffset)
return S_FALSE;
}
else
{
if (cdInfo.CdDisk >= Vols.Streams.Size())
return S_FALSE;
IInStream *str2 = Vols.Streams[cdInfo.CdDisk].Stream;
if (!str2)
return S_FALSE;
RINOK(str2->Seek(cdOffset, STREAM_SEEK_SET, NULL));
stream = str2;
Vols.NeedSeek = false;
Vols.StreamIndex = cdInfo.CdDisk;
m_Position = cdOffset;
}
_inBuffer.SetStream(stream);
_inBuffer.Init(); _inBuffer.Init();
_inBufMode = true; _inBufMode = true;
while (m_Position - cdOffset < cdSize) _processedCnt = 0;
while (_processedCnt < cdSize)
{ {
CanStartNewVol = true;
if (ReadUInt32() != NSignature::kCentralFileHeader) if (ReadUInt32() != NSignature::kCentralFileHeader)
return S_FALSE; return S_FALSE;
CItemEx cdItem; {
RINOK(ReadCdItem(cdItem)); CItemEx cdItem;
items.Add(cdItem); RINOK(ReadCdItem(cdItem));
if (progress && (items.Size() & 0xFFF) == 0) items.Add(cdItem);
RINOK(progress->SetCompletedCD(items.Size())); }
if (Callback && (items.Size() & 0xFFF) == 0)
{
const UInt64 numFiles = items.Size();
RINOK(Callback->SetCompleted(&numFiles, NULL));
}
} }
return (m_Position - cdOffset == cdSize) ? S_OK : S_FALSE;
CanStartNewVol = true;
return (_processedCnt == cdSize) ? S_OK : S_FALSE;
} }
HRESULT CInArchive::ReadCd(CObjectVector<CItemEx> &items, UInt64 &cdOffset, UInt 64 &cdSize, CProgressVirt *progress) HRESULT CInArchive::ReadCd(CObjectVector<CItemEx> &items, UInt32 &cdDisk, UInt64 &cdOffset, UInt64 &cdSize)
{ {
CCdInfo cdInfo; bool checkOffsetMode = true;
RINOK(FindCd(cdInfo));
if (IsMultiVol)
{
if (Vols.EndVolIndex == -1)
return S_FALSE;
Stream = Vols.Streams[Vols.EndVolIndex].Stream;
if (!Vols.StartIsZip)
checkOffsetMode = false;
}
else
Stream = StartStream;
if (!Vols.ecd_wasRead)
{
RINOK(FindCd(checkOffsetMode));
}
CCdInfo &cdInfo = Vols.ecd;
HRESULT res = S_FALSE; HRESULT res = S_FALSE;
cdSize = cdInfo.Size; cdSize = cdInfo.Size;
cdOffset = cdInfo.Offset; cdOffset = cdInfo.Offset;
if (progress) cdDisk = cdInfo.CdDisk;
progress->SetTotalCD(cdInfo.NumEntries);
res = TryReadCd(items, ArcInfo.Base + cdOffset, cdSize, progress); if (Callback)
if (res == S_FALSE && ArcInfo.Base == 0)
{ {
res = TryReadCd(items, ArcInfo.MarkerPos + cdOffset, cdSize, progress); RINOK(Callback->SetTotal(&cdInfo.NumEntries, NULL));
}
const UInt64 base = (IsMultiVol ? 0 : ArcInfo.Base);
res = TryReadCd(items, cdInfo, base + cdOffset, cdSize);
if (res == S_FALSE && !IsMultiVol && base != ArcInfo.MarkerPos)
{
// do we need that additional attempt to read cd?
res = TryReadCd(items, cdInfo, ArcInfo.MarkerPos + cdOffset, cdSize);
if (res == S_OK) if (res == S_OK)
ArcInfo.Base = ArcInfo.MarkerPos; ArcInfo.Base = ArcInfo.MarkerPos;
} }
return res; return res;
} }
static HRESULT FindItem(const CObjectVector<CItemEx> &items, UInt64 offset) static int FindItem(const CObjectVector<CItemEx> &items, const CItemEx &item)
{ {
unsigned left = 0, right = items.Size(); unsigned left = 0, right = items.Size();
for (;;) for (;;)
{ {
if (left >= right) if (left >= right)
return -1; return -1;
unsigned index = (left + right) / 2; unsigned index = (left + right) / 2;
UInt64 position = items[index].LocalHeaderPos; const CItemEx &item2 = items[index];
if (offset == position) if (item.Disk < item2.Disk)
right = index;
else if (item.Disk > item2.Disk)
left = index + 1;
else if (item.LocalHeaderPos == item2.LocalHeaderPos)
return index; return index;
if (offset < position) else if (item.LocalHeaderPos < item2.LocalHeaderPos)
right = index; right = index;
else else
left = index + 1; left = index + 1;
} }
} }
bool IsStrangeItem(const CItem &item) static bool IsStrangeItem(const CItem &item)
{ {
return item.Name.Len() > (1 << 14) || item.Method > (1 << 8); return item.Name.Len() > (1 << 14) || item.Method > (1 << 8);
} }
HRESULT CInArchive::ReadLocals( HRESULT CInArchive::ReadLocals(CObjectVector<CItemEx> &items)
CObjectVector<CItemEx> &items, CProgressVirt *progress)
{ {
items.Clear(); items.Clear();
while (m_Signature == NSignature::kLocalFileHeader) while (m_Signature == NSignature::kLocalFileHeader)
{ {
CItemEx item; CItemEx item;
item.LocalHeaderPos = m_Position - 4 - ArcInfo.MarkerPos; item.LocalHeaderPos = m_Position - 4;
if (!IsMultiVol)
item.LocalHeaderPos -= ArcInfo.MarkerPos;
// we write ralative LocalHeaderPos here. Later we can correct it to real Ba se. // we write ralative LocalHeaderPos here. Later we can correct it to real Ba se.
try try
{ {
ReadLocalItem(item); ReadLocalItem(item);
item.FromLocal = true; item.FromLocal = true;
bool isFinished = false;
if (item.HasDescriptor()) if (item.HasDescriptor())
ReadLocalItemDescriptor(item); ReadLocalItemDescriptor(item);
else else
{ {
RINOK(IncreaseRealPosition(item.PackSize)); /*
if (IsMultiVol)
{
const int kStep = 10000;
RINOK(IncreaseRealPosition(-kStep, isFinished));
RINOK(IncreaseRealPosition(item.PackSize + kStep, isFinished));
}
else
*/
RINOK(IncreaseRealPosition(item.PackSize, isFinished));
} }
items.Add(item); items.Add(item);
if (isFinished)
throw CUnexpectEnd();
m_Signature = ReadUInt32(); m_Signature = ReadUInt32();
} }
catch (CUnexpectEnd &) catch (CUnexpectEnd &)
{ {
if (items.IsEmpty() || items.Size() == 1 && IsStrangeItem(items[0])) if (items.IsEmpty() || items.Size() == 1 && IsStrangeItem(items[0]))
return S_FALSE; return S_FALSE;
throw; throw;
} }
if (progress && (items.Size() & 0xFF) == 0) if (Callback && (items.Size() & 0xFF) == 0)
RINOK(progress->SetCompletedLocal(items.Size(), item.LocalHeaderPos)); {
const UInt64 numFiles = items.Size();
UInt64 numBytes = 0;
// if (!sMultiVol)
numBytes = item.LocalHeaderPos;
RINOK(Callback->SetCompleted(&numFiles, &numBytes));
}
} }
if (items.Size() == 1 && m_Signature != NSignature::kCentralFileHeader) if (items.Size() == 1 && m_Signature != NSignature::kCentralFileHeader)
if (IsStrangeItem(items[0])) if (IsStrangeItem(items[0]))
return S_FALSE; return S_FALSE;
return S_OK; return S_OK;
} }
#define COPY_ECD_ITEM_16(n) if (!isZip64 || ecd. n != 0xFFFF) ecd64. n = ecd HRESULT CVols::ParseArcName(IArchiveOpenVolumeCallback *volCallback)
. n;
#define COPY_ECD_ITEM_32(n) if (!isZip64 || ecd. n != 0xFFFFFFFF) ecd64. n = ecd
. n;
HRESULT CInArchive::ReadHeaders2(CObjectVector<CItemEx> &items, CProgressVirt *p
rogress)
{ {
items.Clear(); UString name;
// m_Signature must be kLocalFileHeader or kEcd
// m_Position points to next byte after signature
RINOK(Stream->Seek(m_Position, STREAM_SEEK_SET, NULL));
if (!_inBuffer.Create(1 << 15))
return E_OUTOFMEMORY;
_inBuffer.SetStream(Stream);
bool needReadCd = true;
bool localsWereRead = false;
if (m_Signature == NSignature::kEcd)
{ {
// It must be empty archive or backware archive NWindows::NCOM::CPropVariant prop;
// we don't support backware archive still RINOK(volCallback->GetProperty(kpidName, &prop));
if (prop.vt != VT_BSTR)
return S_OK;
name = prop.bstrVal;
}
const unsigned kBufSize = kEcdSize - 4; UString base = name;
Byte buf[kBufSize]; int dotPos = name.ReverseFind_Dot();
SafeReadBytes(buf, kBufSize);
CEcd ecd;
ecd.Parse(buf);
// if (ecd.cdSize != 0)
// Do we need also to support the case where empty zip archive with PK00 use
s cdOffset = 4 ??
if (!ecd.IsEmptyArc())
return S_FALSE;
ArcInfo.Base = ArcInfo.MarkerPos; if (dotPos < 0)
needReadCd = false; return S_OK;
IsArc = true; // check it: we need more tests?
RINOK(Stream->Seek(ArcInfo.MarkerPos2 + 4, STREAM_SEEK_SET, &m_Position));
}
UInt64 cdSize = 0, cdRelatOffset = 0, cdAbsOffset = 0; base.DeleteFrom(dotPos + 1);
HRESULT res = S_OK;
if (needReadCd) const UString ext = name.Ptr(dotPos + 1);
StartVolIndex = (Int32)(-1);
if (ext.IsEmpty())
return S_OK;
else
{ {
CItemEx firstItem; wchar_t c = ext[0];
// try IsUpperCase = (c >= 'A' && c <= 'Z');
if (ext.IsEqualTo_Ascii_NoCase("zip"))
{
BaseName = base;
StartIsZ = true;
StartIsZip = true;
return S_OK;
}
else if (ext.IsEqualTo_Ascii_NoCase("exe"))
{
StartIsExe = true;
BaseName = base;
StartVolIndex = 0;
}
else if (ext[0] == 'z' || ext[0] == 'Z')
{
if (ext.Len() < 3)
return S_OK;
const wchar_t *end = NULL;
UInt32 volNum = ConvertStringToUInt32(ext.Ptr(1), &end);
if (*end != 0 || volNum < 1 || volNum > ((UInt32)1 << 30))
return S_OK;
StartVolIndex = volNum - 1;
BaseName = base;
StartIsZ = true;
}
else
return S_OK;
}
UString volName = BaseName;
volName.AddAscii(IsUpperCase ? "ZIP" : "zip");
HRESULT result = volCallback->GetStream(volName, &ZipStream);
if (result == S_FALSE || !ZipStream)
{
if (MissingName.IsEmpty())
MissingName = volName;
return S_OK;
}
return result;
}
HRESULT CInArchive::ReadVols2(IArchiveOpenVolumeCallback *volCallback,
unsigned start, int lastDisk, int zipDisk, unsigned numMissingVolsMax, unsig
ned &numMissingVols)
{
numMissingVols = 0;
for (unsigned i = start;; i++)
{
if (lastDisk >= 0 && i >= (unsigned)lastDisk)
break;
if (i < Vols.Streams.Size())
if (Vols.Streams[i].Stream)
continue;
CMyComPtr<IInStream> stream;
if ((int)i == zipDisk)
{
stream = Vols.ZipStream;
}
else if ((int)i == Vols.StartVolIndex)
{
stream = StartStream;
}
else
{
UString volName = Vols.BaseName;
{
volName += (wchar_t)(Vols.IsUpperCase ? 'Z' : 'z');
{
char s[32];
ConvertUInt32ToString(i + 1, s);
unsigned len = (unsigned)strlen(s);
while (len < 2)
{
volName += (wchar_t)'0';
len++;
}
volName.AddAscii(s);
}
}
HRESULT result = volCallback->GetStream(volName, &stream);
if (result != S_OK && result != S_FALSE)
return result;
if (result == S_FALSE || !stream)
{
if (Vols.MissingName.IsEmpty())
Vols.MissingName = volName;
numMissingVols++;
if (numMissingVols > numMissingVolsMax)
return S_OK;
if (lastDisk == -1 && numMissingVols != 0)
return S_OK;
continue;
}
}
UInt64 size;
UInt64 pos;
RINOK(stream->Seek(0, STREAM_SEEK_CUR, &pos));
RINOK(stream->Seek(0, STREAM_SEEK_END, &size));
RINOK(stream->Seek(pos, STREAM_SEEK_SET, NULL));
while (i >= Vols.Streams.Size())
Vols.Streams.AddNew();
CVols::CSubStreamInfo &ss = Vols.Streams[i];
Vols.NumVols++;
ss.Stream = stream;
ss.Size = size;
if ((int)i == zipDisk)
{
Vols.EndVolIndex = Vols.Streams.Size() - 1;
break;
}
}
return S_OK;
}
HRESULT CInArchive::ReadVols()
{
CMyComPtr<IArchiveOpenVolumeCallback> volCallback;
Callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&volCallback
);
if (!volCallback)
return S_OK;
RINOK(Vols.ParseArcName(volCallback));
int startZIndex = Vols.StartVolIndex;
if (!Vols.StartIsZ)
{
// if (!Vols.StartIsExe)
return S_OK;
}
int zipDisk = -1;
int cdDisk = -1;
if (Vols.StartIsZip)
Vols.ZipStream = StartStream;
// bool cdOK = false;
if (Vols.ZipStream)
{
Stream = Vols.ZipStream;
HRESULT res = FindCd(true);
CCdInfo &ecd = Vols.ecd;
if (res == S_OK)
{
zipDisk = ecd.ThisDisk;
Vols.ecd_wasRead = true;
if (ecd.ThisDisk == 0
|| ecd.ThisDisk >= ((UInt32)1 << 30)
|| ecd.ThisDisk < ecd.CdDisk)
return S_OK;
cdDisk = ecd.CdDisk;
if (Vols.StartVolIndex < 0)
Vols.StartVolIndex = ecd.ThisDisk;
// Vols.StartVolIndex = ecd.ThisDisk;
// Vols.EndVolIndex = ecd.ThisDisk;
unsigned numMissingVols;
if (cdDisk == zipDisk)
{
// cdOK = true;
}
else
{
RINOK(ReadVols2(volCallback, cdDisk, zipDisk, zipDisk, 0, numMissingVols
));
if (numMissingVols == 0)
{
// cdOK = false;
}
}
}
else if (res != S_FALSE)
return res;
}
if (Vols.Streams.Size() > 0)
IsMultiVol = true;
if (Vols.StartVolIndex < 0)
return S_OK;
unsigned numMissingVols;
if (cdDisk != 0)
{
RINOK(ReadVols2(volCallback, 0, cdDisk < 0 ? -1 : cdDisk, zipDisk, 1 << 10,
numMissingVols));
}
if (Vols.ZipStream)
{
if (Vols.Streams.IsEmpty())
if (zipDisk > (1 << 10))
return S_OK;
RINOK(ReadVols2(volCallback, zipDisk, zipDisk + 1, zipDisk, 0, numMissingVol
s));
}
if (!Vols.Streams.IsEmpty())
{
IsMultiVol = true;
/*
if (cdDisk)
IsMultiVol = true;
*/
if (startZIndex >= 0)
{
if (Vols.Streams.Size() >= (unsigned)startZIndex)
{
for (unsigned i = 0; i < (unsigned)startZIndex; i++)
if (!Vols.Streams[i].Stream)
{
Vols.StartParsingVol = startZIndex;
break;
}
}
}
}
return S_OK;
}
HRESULT CVols::Read(void *data, UInt32 size, UInt32 *processedSize)
{
if (processedSize)
*processedSize = 0;
if (size == 0)
return S_OK;
for (;;)
{
if (StreamIndex < 0)
return S_OK;
if ((unsigned)StreamIndex >= Streams.Size())
return S_OK;
const CVols::CSubStreamInfo &s = Streams[StreamIndex];
if (!s.Stream)
return S_FALSE;
if (NeedSeek)
{
RINOK(s.Stream->Seek(0, STREAM_SEEK_SET, NULL));
NeedSeek = false;
}
UInt32 realProcessedSize = 0;
HRESULT res = s.Stream->Read(data, size, &realProcessedSize);
if (processedSize)
*processedSize = realProcessedSize;
if (res != S_OK)
return res;
if (realProcessedSize != 0)
return res;
StreamIndex++;
NeedSeek = true;
}
}
STDMETHODIMP CVolStream::Read(void *data, UInt32 size, UInt32 *processedSize)
{
return Vols->Read(data, size, processedSize);
}
#define COPY_ECD_ITEM_16(n) if (!isZip64 || ecd. n != 0xFFFF) ecd64. n = ecd
. n;
#define COPY_ECD_ITEM_32(n) if (!isZip64 || ecd. n != 0xFFFFFFFF) ecd64. n = ecd
. n;
HRESULT CInArchive::ReadHeaders2(CObjectVector<CItemEx> &items)
{
HRESULT res = S_OK;
bool localsWereRead = false;
UInt64 cdSize = 0, cdRelatOffset = 0, cdAbsOffset = 0;
UInt32 cdDisk = 0;
if (!_inBuffer.Create(1 << 15))
return E_OUTOFMEMORY;
if (!MarkerIsFound)
{
IsArc = true;
res = ReadCd(items, cdDisk, cdRelatOffset, cdSize);
if (res == S_OK)
m_Signature = ReadUInt32();
}
else
{
// m_Signature must be kLocalFileHeader or kEcd
// m_Position points to next byte after signature
RINOK(Stream->Seek(m_Position, STREAM_SEEK_SET, NULL));
_inBuffer.SetStream(Stream);
bool needReadCd = true;
if (m_Signature == NSignature::kEcd)
{
// It must be empty archive or backware archive
// we don't support backware archive still
const unsigned kBufSize = kEcdSize - 4;
Byte buf[kBufSize];
SafeReadBytes(buf, kBufSize);
CEcd ecd;
ecd.Parse(buf);
// if (ecd.cdSize != 0)
// Do we need also to support the case where empty zip archive with PK00 use
s cdOffset = 4 ??
if (!ecd.IsEmptyArc())
return S_FALSE;
ArcInfo.Base = ArcInfo.MarkerPos;
needReadCd = false;
IsArc = true; // check it: we need more tests?
RINOK(Stream->Seek(ArcInfo.MarkerPos2 + 4, STREAM_SEEK_SET, &m_Position));
}
if (needReadCd)
{
CItemEx firstItem;
// try
{ {
try try
{ {
if (!ReadLocalItem(firstItem)) if (!ReadLocalItem(firstItem))
return S_FALSE; return S_FALSE;
} }
catch(CUnexpectEnd &) catch(CUnexpectEnd &)
{ {
return S_FALSE; return S_FALSE;
} }
IsArc = true; IsArc = true;
res = ReadCd(items, cdRelatOffset, cdSize, progress); res = ReadCd(items, cdDisk, cdRelatOffset, cdSize);
if (res == S_OK) if (res == S_OK)
m_Signature = ReadUInt32(); m_Signature = ReadUInt32();
} }
// catch() { res = S_FALSE; } // catch() { res = S_FALSE; }
if (res != S_FALSE && res != S_OK) if (res != S_FALSE && res != S_OK)
return res; return res;
if (res == S_OK && items.Size() == 0) if (res == S_OK && items.Size() == 0)
res = S_FALSE; res = S_FALSE;
if (res == S_OK) if (res == S_OK)
{ {
// we can't read local items here to keep _inBufMode state // we can't read local items here to keep _inBufMode state
firstItem.LocalHeaderPos = ArcInfo.MarkerPos2 - ArcInfo.Base; if ((Int64)ArcInfo.MarkerPos2 < ArcInfo.Base)
int index = FindItem(items, firstItem.LocalHeaderPos);
if (index == -1)
res = S_FALSE;
else if (!AreItemsEqual(firstItem, items[index]))
res = S_FALSE; res = S_FALSE;
ArcInfo.CdWasRead = true; else
ArcInfo.FirstItemRelatOffset = items[0].LocalHeaderPos; {
firstItem.LocalHeaderPos = ArcInfo.MarkerPos2 - ArcInfo.Base;
int index = FindItem(items, firstItem);
if (index == -1)
res = S_FALSE;
else if (!AreItemsEqual(firstItem, items[index]))
res = S_FALSE;
else
{
ArcInfo.CdWasRead = true;
ArcInfo.FirstItemRelatOffset = items[0].LocalHeaderPos;
}
}
} }
} }
}
CObjectVector<CItemEx> cdItems; CObjectVector<CItemEx> cdItems;
bool needSetBase = false; bool needSetBase = false;
unsigned numCdItems = items.Size(); unsigned numCdItems = items.Size();
if (res == S_FALSE) if (res == S_FALSE)
{ {
// CD doesn't match firstItem so we clear items and read Locals. // CD doesn't match firstItem,
// so we clear items and read Locals.
items.Clear(); items.Clear();
localsWereRead = true; localsWereRead = true;
_inBufMode = false; _inBufMode = false;
ArcInfo.Base = ArcInfo.MarkerPos; ArcInfo.Base = ArcInfo.MarkerPos;
if (IsMultiVol)
{
Vols.StreamIndex = Vols.StartParsingVol;
if (Vols.StartParsingVol >= (int)Vols.Streams.Size())
return S_FALSE;
Stream = Vols.Streams[Vols.StartParsingVol].Stream;
if (!Stream)
return S_FALSE;
}
RINOK(Stream->Seek(ArcInfo.MarkerPos2, STREAM_SEEK_SET, &m_Position)); RINOK(Stream->Seek(ArcInfo.MarkerPos2, STREAM_SEEK_SET, &m_Position));
m_Signature = ReadUInt32(); m_Signature = ReadUInt32();
RINOK(ReadLocals(items, progress)); RINOK(ReadLocals(items));
if (m_Signature != NSignature::kCentralFileHeader) if (m_Signature != NSignature::kCentralFileHeader)
{ {
m_Position -= 4; // if (!UnexpectedEnd)
m_Position -= 4;
NoCentralDir = true; NoCentralDir = true;
HeadersError = true; HeadersError = true;
return S_OK; return S_OK;
} }
_inBufMode = true; _inBufMode = true;
_inBuffer.Init(); _inBuffer.Init();
cdAbsOffset = m_Position - 4; cdAbsOffset = m_Position - 4;
cdDisk = Vols.StreamIndex;
for (;;) for (;;)
{ {
CItemEx cdItem; CItemEx cdItem;
CanStartNewVol = true;
RINOK(ReadCdItem(cdItem)); RINOK(ReadCdItem(cdItem));
cdItems.Add(cdItem); cdItems.Add(cdItem);
if (progress && (cdItems.Size() & 0xFFF) == 0) if (Callback && (cdItems.Size() & 0xFFF) == 0)
RINOK(progress->SetCompletedCD(items.Size())); {
const UInt64 numFiles = items.Size();
RINOK(Callback->SetCompleted(&numFiles, NULL));
}
CanStartNewVol = true;
m_Signature = ReadUInt32(); m_Signature = ReadUInt32();
if (m_Signature != NSignature::kCentralFileHeader) if (m_Signature != NSignature::kCentralFileHeader)
break; break;
} }
cdSize = (m_Position - 4) - cdAbsOffset; cdSize = (m_Position - 4) - cdAbsOffset;
needSetBase = true; needSetBase = true;
numCdItems = cdItems.Size(); numCdItems = cdItems.Size();
if (!cdItems.IsEmpty()) if (!cdItems.IsEmpty())
{ {
ArcInfo.CdWasRead = true; ArcInfo.CdWasRead = true;
ArcInfo.FirstItemRelatOffset = cdItems[0].LocalHeaderPos; ArcInfo.FirstItemRelatOffset = cdItems[0].LocalHeaderPos;
} }
} }
CEcd64 ecd64; CCdInfo ecd64;
CLocator locator;
bool isZip64 = false; bool isZip64 = false;
UInt64 ecd64AbsOffset = m_Position - 4; const UInt64 ecd64AbsOffset = m_Position - 4;
int ecd64Disk = -1;
if (m_Signature == NSignature::kEcd64) if (m_Signature == NSignature::kEcd64)
{ {
ecd64Disk = Vols.StreamIndex;
IsZip64 = isZip64 = true; IsZip64 = isZip64 = true;
UInt64 recordSize = ReadUInt64();
const unsigned kBufSize = kEcd64_MainSize; {
Byte buf[kBufSize]; const UInt64 recordSize = ReadUInt64();
SafeReadBytes(buf, kBufSize); if (recordSize < kEcd64_MainSize)
ecd64.Parse(buf); {
HeadersError = true;
return S_OK;
}
{
const unsigned kBufSize = kEcd64_MainSize;
Byte buf[kBufSize];
SafeReadBytes(buf, kBufSize);
ecd64.ParseEcd64e(buf);
}
Skip64(recordSize - kEcd64_MainSize);
}
Skip64(recordSize - kEcd64_MainSize);
m_Signature = ReadUInt32(); m_Signature = ReadUInt32();
if (ecd64.thisDiskNumber != 0 || ecd64.startCDDiskNumber != 0) if (m_Signature != NSignature::kEcd64Locator)
return E_NOTIMPL; {
HeadersError = true;
return S_OK;
}
if (needSetBase)
{ {
ArcInfo.Base = cdAbsOffset - ecd64.cdStartOffset; const unsigned kBufSize = 16;
cdRelatOffset = ecd64.cdStartOffset; Byte buf[kBufSize];
needSetBase = false; SafeReadBytes(buf, kBufSize);
locator.Parse(buf);
} }
if (ecd64.numEntriesInCDOnThisDisk != numCdItems || m_Signature = ReadUInt32();
ecd64.numEntriesInCD != numCdItems ||
ecd64.cdSize != cdSize ||
(ecd64.cdStartOffset != cdRelatOffset &&
(!items.IsEmpty())))
return S_FALSE;
} }
if (m_Signature == NSignature::kEcd64Locator) if (m_Signature != NSignature::kEcd)
{ {
if (!isZip64) HeadersError = true;
return S_FALSE; return S_OK;
/* UInt32 startEndCDDiskNumber = */ ReadUInt32();
UInt64 ecd64RelatOffset = ReadUInt64();
/* UInt32 numberOfDisks = */ ReadUInt32();
if (ecd64AbsOffset != ArcInfo.Base + ecd64RelatOffset)
return S_FALSE;
m_Signature = ReadUInt32();
} }
if (m_Signature != NSignature::kEcd) // ---------- ECD ----------
return S_FALSE;
const unsigned kBufSize = kEcdSize - 4;
Byte buf[kBufSize];
SafeReadBytes(buf, kBufSize);
CEcd ecd; CEcd ecd;
ecd.Parse(buf); {
const unsigned kBufSize = kEcdSize - 4;
Byte buf[kBufSize];
SafeReadBytes(buf, kBufSize);
ecd.Parse(buf);
}
COPY_ECD_ITEM_16(thisDiskNumber); COPY_ECD_ITEM_16(ThisDisk);
COPY_ECD_ITEM_16(startCDDiskNumber); COPY_ECD_ITEM_16(CdDisk);
COPY_ECD_ITEM_16(numEntriesInCDOnThisDisk); COPY_ECD_ITEM_16(NumEntries_in_ThisDisk);
COPY_ECD_ITEM_16(numEntriesInCD); COPY_ECD_ITEM_16(NumEntries);
COPY_ECD_ITEM_32(cdSize); COPY_ECD_ITEM_32(Size);
COPY_ECD_ITEM_32(cdStartOffset); COPY_ECD_ITEM_32(Offset);
if (needSetBase) if (IsMultiVol)
{ {
ArcInfo.Base = cdAbsOffset - ecd64.cdStartOffset; if (cdDisk != (int)ecd64.CdDisk)
cdRelatOffset = ecd64.cdStartOffset; HeadersError = true;
needSetBase = false;
} }
else if (needSetBase)
{
if (isZip64)
{
if (ecd64Disk == Vols.StartVolIndex)
{
ArcInfo.Base = ecd64AbsOffset - locator.Ecd64Offset;
// cdRelatOffset = ecd64.Offset;
needSetBase = false;
}
}
else
{
if ((int)cdDisk == Vols.StartVolIndex)
{
ArcInfo.Base = cdAbsOffset - ecd64.Offset;
cdRelatOffset = ecd64.Offset;
needSetBase = false;
}
}
}
EcdVolIndex = ecd64.ThisDisk;
if (localsWereRead && (UInt64)ArcInfo.Base != ArcInfo.MarkerPos) if (!IsMultiVol)
{ {
UInt64 delta = ArcInfo.MarkerPos - ArcInfo.Base; UseDisk_in_SingleVol = true;
for (unsigned i = 0; i < items.Size(); i++)
items[i].LocalHeaderPos += delta; if (localsWereRead)
{
if ((UInt64)ArcInfo.Base != ArcInfo.MarkerPos)
{
const UInt64 delta = ArcInfo.MarkerPos - ArcInfo.Base;
FOR_VECTOR (i, items)
items[i].LocalHeaderPos += delta;
}
if (EcdVolIndex != 0)
{
FOR_VECTOR (i, items)
items[i].Disk = EcdVolIndex;
}
}
}
if (isZip64)
{
if (ecd64.ThisDisk == 0 && ecd64AbsOffset != ArcInfo.Base + locator.Ecd64Off
set
// || ecd64.NumEntries_in_ThisDisk != numCdItems
|| ecd64.NumEntries != numCdItems
|| ecd64.Size != cdSize
|| (ecd64.Offset != cdRelatOffset && !items.IsEmpty()))
{
HeadersError = true;
return S_OK;
}
} }
// ---------- merge Central Directory Items ---------- // ---------- merge Central Directory Items ----------
if (!cdItems.IsEmpty()) if (!cdItems.IsEmpty())
{ {
for (unsigned i = 0; i < cdItems.Size(); i++) CObjectVector<CItemEx> items2;
FOR_VECTOR (i, cdItems)
{ {
const CItemEx &cdItem = cdItems[i]; const CItemEx &cdItem = cdItems[i];
int index = FindItem(items, cdItem.LocalHeaderPos); int index = FindItem(items, cdItem);
if (index == -1) if (index == -1)
{ {
items.Add(cdItem); items2.Add(cdItem);
HeadersError = true;
continue; continue;
} }
CItemEx &item = items[index]; CItemEx &item = items[index];
if (item.Name != cdItem.Name if (item.Name != cdItem.Name
// || item.Name.Len() != cdItem.Name.Len() // || item.Name.Len() != cdItem.Name.Len()
|| item.PackSize != cdItem.PackSize || item.PackSize != cdItem.PackSize
|| item.Size != cdItem.Size || item.Size != cdItem.Size
// item.ExtractVersion != cdItem.ExtractVersion // item.ExtractVersion != cdItem.ExtractVersion
|| !FlagsAreSame(item, cdItem) || !FlagsAreSame(item, cdItem)
|| item.Crc != cdItem.Crc) || item.Crc != cdItem.Crc)
{
HeadersError = true;
continue; continue;
}
// item.LocalHeaderPos = cdItem.LocalHeaderPos;
// item.Name = cdItem.Name; // item.Name = cdItem.Name;
item.MadeByVersion = cdItem.MadeByVersion; item.MadeByVersion = cdItem.MadeByVersion;
item.CentralExtra = cdItem.CentralExtra; item.CentralExtra = cdItem.CentralExtra;
item.InternalAttrib = cdItem.InternalAttrib; item.InternalAttrib = cdItem.InternalAttrib;
item.ExternalAttrib = cdItem.ExternalAttrib; item.ExternalAttrib = cdItem.ExternalAttrib;
item.Comment = cdItem.Comment; item.Comment = cdItem.Comment;
item.FromCentral = cdItem.FromCentral; item.FromCentral = cdItem.FromCentral;
} }
items += items2;
}
if (ecd.NumEntries < ecd.NumEntries_in_ThisDisk)
HeadersError = true;
if (ecd.ThisDisk == 0)
{
// if (isZip64)
{
if (ecd.NumEntries != ecd.NumEntries_in_ThisDisk)
HeadersError = true;
}
} }
if (ecd64.thisDiskNumber != 0 || ecd64.startCDDiskNumber != 0) if (ecd.NumEntries > items.Size())
return E_NOTIMPL; HeadersError = true;
if (isZip64) if (isZip64)
{ {
if (ecd64.numEntriesInCDOnThisDisk != items.Size()) if (ecd64.NumEntries != items.Size())
HeadersError = true; HeadersError = true;
} }
else else
{ {
// old 7-zip could store 32-bit number of CD items to 16-bit field. // old 7-zip could store 32-bit number of CD items to 16-bit field.
if ((UInt16)ecd64.numEntriesInCDOnThisDisk != (UInt16)numCdItems || /*
(UInt16)ecd64.numEntriesInCDOnThisDisk != (UInt16)items.Size()) if ((UInt16)ecd64.NumEntries == (UInt16)items.Size())
HeadersError = true; HeadersError = true;
*/
} }
ReadBuffer(ArcInfo.Comment, ecd.commentSize); ReadBuffer(ArcInfo.Comment, ecd.CommentSize);
_inBufMode = false; _inBufMode = false;
_inBuffer.Free(); _inBuffer.Free();
if ( if ((UInt16)ecd64.NumEntries != (UInt16)numCdItems
(UInt16)ecd64.numEntriesInCD != ((UInt16)numCdItems) || || (UInt32)ecd64.Size != (UInt32)cdSize
(UInt32)ecd64.cdSize != (UInt32)cdSize || || ((UInt32)ecd64.Offset != (UInt32)cdRelatOffset && !items.IsEmpty()))
((UInt32)(ecd64.cdStartOffset) != (UInt32)cdRelatOffset &&
(!items.IsEmpty())))
{ {
// return S_FALSE; // return S_FALSE;
HeadersError = true; HeadersError = true;
} }
// printf("\nOpen OK"); // printf("\nOpen OK");
return S_OK; return S_OK;
} }
HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items, CProgressVirt *pr HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchLimit,
ogress) IArchiveOpenCallback *callback, CObjectVector<CItemEx> &items)
{ {
HRESULT res; _inBufMode = false;
try items.Clear();
Close();
ArcInfo.Clear();
UInt64 startPos;
RINOK(stream->Seek(0, STREAM_SEEK_CUR, &startPos));
RINOK(stream->Seek(0, STREAM_SEEK_END, &ArcInfo.FileEndPos));
m_Position = ArcInfo.FileEndPos;
StartStream = stream;
Callback = callback;
bool volWasRequested = false;
if (callback
&& (startPos == 0 || !searchLimit || *searchLimit != 0))
{ {
res = ReadHeaders2(items, progress); volWasRequested = true;
RINOK(ReadVols());
} }
catch (const CInBufferException &e) { res = e.ErrorCode; }
catch (const CUnexpectEnd &) if (IsMultiVol && Vols.StartVolIndex != 0)
{ {
if (items.IsEmpty()) Stream = Vols.Streams[0].Stream;
return S_FALSE; if (Stream)
UnexpectedEnd = true; {
res = S_OK; m_Position = 0;
RINOK(Stream->Seek(0, STREAM_SEEK_SET, NULL));
UInt64 limit = 0;
HRESULT res = FindMarker(Stream, &limit);
if (res == S_OK)
MarkerIsFound = true;
else if (res != S_FALSE)
return res;
}
}
else
{
// printf("\nOpen offset = %u\n", (unsigned)startPos);
RINOK(stream->Seek(startPos, STREAM_SEEK_SET, NULL));
m_Position = startPos;
HRESULT res = FindMarker(stream, searchLimit);
UInt64 curPos = m_Position;
if (res == S_OK)
MarkerIsFound = true;
else
{
// if (res != S_FALSE)
return res;
}
MarkerIsFound = true;
if (ArcInfo.IsSpanMode && !volWasRequested)
{
RINOK(ReadVols());
}
if (IsMultiVol && (unsigned)Vols.StartVolIndex < Vols.Streams.Size())
{
Stream = Vols.Streams[Vols.StartVolIndex].Stream;
if (!Stream)
IsMultiVol = false;
else
{
RINOK(Stream->Seek(curPos, STREAM_SEEK_SET, NULL));
m_Position = curPos;
}
}
else
IsMultiVol = false;
if (!IsMultiVol)
{
RINOK(stream->Seek(curPos, STREAM_SEEK_SET, NULL));
m_Position = curPos;
StreamRef = stream;
Stream = stream;
}
} }
catch (...)
{ {
HRESULT res;
try
{
res = ReadHeaders2(items);
}
catch (const CInBufferException &e) { res = e.ErrorCode; }
catch (const CUnexpectEnd &)
{
if (items.IsEmpty())
return S_FALSE;
UnexpectedEnd = true;
res = S_OK;
}
catch (...)
{
_inBufMode = false;
throw;
}
if (IsMultiVol)
{
ArcInfo.FinishPos = ArcInfo.FileEndPos;
if ((unsigned)Vols.StreamIndex < Vols.Streams.Size())
if (m_Position < Vols.Streams[Vols.StreamIndex].Size)
ArcInfo.ThereIsTail = true;
}
else
{
ArcInfo.FinishPos = m_Position;
ArcInfo.ThereIsTail = (ArcInfo.FileEndPos > m_Position);
}
_inBufMode = false; _inBufMode = false;
throw; IsArcOpen = true;
if (!IsMultiVol)
Vols.Streams.Clear();
return res;
} }
ArcInfo.FinishPos = m_Position;
_inBufMode = false;
return res;
} }
ISequentialInStream* CInArchive::CreateLimitedStream(UInt64 position, UInt64 siz e) HRESULT CInArchive::GetItemStream(const CItemEx &item, bool seekPackData, CMyCom Ptr<ISequentialInStream> &stream)
{ {
CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; stream.Release();
CMyComPtr<ISequentialInStream> stream(streamSpec);
Stream->Seek(ArcInfo.Base + position, STREAM_SEEK_SET, NULL); UInt64 pos = item.LocalHeaderPos;
streamSpec->SetStream(Stream); if (seekPackData)
streamSpec->Init(size); pos += item.LocalFullHeaderSize;
return stream.Detach();
if (!IsMultiVol)
{
if (UseDisk_in_SingleVol && item.Disk != EcdVolIndex)
return S_OK;
pos += ArcInfo.Base;
RINOK(StreamRef->Seek(pos, STREAM_SEEK_SET, NULL));
stream = StreamRef;
return S_OK;
}
if (item.Disk >= Vols.Streams.Size())
return S_OK;
IInStream *str2 = Vols.Streams[item.Disk].Stream;
if (!str2)
return S_OK;
RINOK(str2->Seek(pos, STREAM_SEEK_SET, NULL));
Vols.NeedSeek = false;
Vols.StreamIndex = item.Disk;
CVolStream *volsStreamSpec = new CVolStream;
volsStreamSpec->Vols = &Vols;
stream = volsStreamSpec;
return S_OK;
} }
}} }}
 End of changes. 173 change blocks. 
368 lines changed or deleted 1221 lines changed or added

Home  |  About  |  All  |  Newest  |  Fossies Dox  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTPS