mirror of
https://github.com/Xevion/easy7zip.git
synced 2025-12-08 18:07:15 -06:00
9.18
This commit is contained in:
committed by
Kornel Lesiński
parent
2eb60a0598
commit
c65230d858
@@ -10,6 +10,8 @@
|
||||
|
||||
#include "../../Common/LimitedStreams.h"
|
||||
#include "../../Common/ProgressUtils.h"
|
||||
#include "../../Common/StreamObjects.h"
|
||||
#include "../../Common/StreamUtils.h"
|
||||
|
||||
#include "../Common/ItemNameUtils.h"
|
||||
|
||||
@@ -21,7 +23,9 @@ using namespace NWindows;
|
||||
namespace NArchive {
|
||||
namespace NTar {
|
||||
|
||||
static STATPROPSTG kProps[] =
|
||||
static const char *kUnexpectedEnd = "Unexpected end of archive";
|
||||
|
||||
static const STATPROPSTG kProps[] =
|
||||
{
|
||||
{ NULL, kpidPath, VT_BSTR},
|
||||
{ NULL, kpidIsDir, VT_BOOL},
|
||||
@@ -34,8 +38,14 @@ static STATPROPSTG kProps[] =
|
||||
{ NULL, kpidLink, VT_BSTR}
|
||||
};
|
||||
|
||||
static const STATPROPSTG kArcProps[] =
|
||||
{
|
||||
{ NULL, kpidPhySize, VT_UI8},
|
||||
{ NULL, kpidHeadersSize, VT_UI8}
|
||||
};
|
||||
|
||||
IMP_IInArchive_Props
|
||||
IMP_IInArchive_ArcProps_NO_Table
|
||||
IMP_IInArchive_ArcProps
|
||||
|
||||
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
@@ -43,11 +53,22 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
|
||||
switch(propID)
|
||||
{
|
||||
case kpidPhySize: if (_phySizeDefined) prop = _phySize; break;
|
||||
case kpidHeadersSize: if (_phySizeDefined) prop = _headersSize; break;
|
||||
case kpidError: if (!_errorMessage.IsEmpty()) prop = _errorMessage; break;
|
||||
}
|
||||
prop.Detach(value);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CHandler::ReadItem2(ISequentialInStream *stream, bool &filled, CItemEx &item)
|
||||
{
|
||||
item.HeaderPos = _phySize;
|
||||
RINOK(ReadItem(stream, filled, item, _errorMessage));
|
||||
_phySize += item.HeaderSize;
|
||||
_headersSize += item.HeaderSize;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
|
||||
{
|
||||
UInt64 endPos = 0;
|
||||
@@ -56,26 +77,29 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
|
||||
RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
|
||||
}
|
||||
|
||||
_isGood = true;
|
||||
UInt64 pos = 0;
|
||||
_phySizeDefined = true;
|
||||
for (;;)
|
||||
{
|
||||
CItemEx item;
|
||||
bool filled;
|
||||
item.HeaderPosition = pos;
|
||||
RINOK(ReadItem(stream, filled, item));
|
||||
RINOK(ReadItem2(stream, filled, item));
|
||||
if (!filled)
|
||||
break;
|
||||
_items.Add(item);
|
||||
|
||||
RINOK(stream->Seek(item.GetPackSize(), STREAM_SEEK_CUR, &pos));
|
||||
if (pos > endPos)
|
||||
return S_FALSE;
|
||||
if (pos == endPos)
|
||||
RINOK(stream->Seek(item.GetPackSize(), STREAM_SEEK_CUR, &_phySize));
|
||||
if (_phySize > endPos)
|
||||
{
|
||||
_isGood = false;
|
||||
_errorMessage = kUnexpectedEnd;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
if (_phySize == endPos)
|
||||
{
|
||||
_errorMessage = "There are no trailing zero-filled records";
|
||||
break;
|
||||
}
|
||||
*/
|
||||
if (callback != NULL)
|
||||
{
|
||||
if (_items.Size() == 1)
|
||||
@@ -85,7 +109,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
|
||||
if (_items.Size() % 100 == 0)
|
||||
{
|
||||
UInt64 numFiles = _items.Size();
|
||||
RINOK(callback->SetCompleted(&numFiles, &pos));
|
||||
RINOK(callback->SetCompleted(&numFiles, &_phySize));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -132,7 +156,10 @@ STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream)
|
||||
|
||||
STDMETHODIMP CHandler::Close()
|
||||
{
|
||||
_errorMessage.Empty();
|
||||
_phySizeDefined = false;
|
||||
_phySize = 0;
|
||||
_headersSize = 0;
|
||||
_curIndex = 0;
|
||||
_latestIsRead = false;
|
||||
_items.Clear();
|
||||
@@ -161,16 +188,24 @@ HRESULT CHandler::SkipTo(UInt32 index)
|
||||
{
|
||||
UInt64 packSize = _latestItem.GetPackSize();
|
||||
RINOK(copyCoderSpec->Code(_seqStream, NULL, &packSize, &packSize, NULL));
|
||||
_phySize += copyCoderSpec->TotalSize;
|
||||
if (copyCoderSpec->TotalSize != packSize)
|
||||
{
|
||||
_errorMessage = kUnexpectedEnd;
|
||||
return S_FALSE;
|
||||
}
|
||||
_latestIsRead = false;
|
||||
_curIndex++;
|
||||
}
|
||||
else
|
||||
{
|
||||
bool filled;
|
||||
// item.HeaderPosition = pos;
|
||||
RINOK(ReadItem(_seqStream, filled, _latestItem));
|
||||
RINOK(ReadItem2(_seqStream, filled, _latestItem));
|
||||
if (!filled)
|
||||
{
|
||||
_phySizeDefined = true;
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
_latestIsRead = true;
|
||||
}
|
||||
}
|
||||
@@ -203,10 +238,10 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
|
||||
|
||||
switch(propID)
|
||||
{
|
||||
case kpidPath: prop = NItemName::GetOSName2(TarStringToUnicode(item->Name)); break;
|
||||
case kpidIsDir: prop = item->IsDir(); break;
|
||||
case kpidSize: prop = item->Size; break;
|
||||
case kpidPackSize: prop = item->GetPackSize(); break;
|
||||
case kpidPath: prop = NItemName::GetOSName2(TarStringToUnicode(item->Name)); break;
|
||||
case kpidIsDir: prop = item->IsDir(); break;
|
||||
case kpidSize: prop = item->GetUnpackSize(); break;
|
||||
case kpidPackSize: prop = item->GetPackSize(); break;
|
||||
case kpidMTime:
|
||||
if (item->MTime != 0)
|
||||
{
|
||||
@@ -216,9 +251,9 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
|
||||
}
|
||||
break;
|
||||
case kpidPosixAttrib: prop = item->Mode; break;
|
||||
case kpidUser: prop = TarStringToUnicode(item->User); break;
|
||||
case kpidGroup: prop = TarStringToUnicode(item->Group); break;
|
||||
case kpidLink: prop = TarStringToUnicode(item->LinkName); break;
|
||||
case kpidUser: prop = TarStringToUnicode(item->User); break;
|
||||
case kpidGroup: prop = TarStringToUnicode(item->Group); break;
|
||||
case kpidLink: prop = TarStringToUnicode(item->LinkName); break;
|
||||
}
|
||||
prop.Detach(value);
|
||||
return S_OK;
|
||||
@@ -242,7 +277,7 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
UInt64 totalSize = 0;
|
||||
UInt32 i;
|
||||
for (i = 0; i < numItems; i++)
|
||||
totalSize += _items[allFilesMode ? i : indices[i]].Size;
|
||||
totalSize += _items[allFilesMode ? i : indices[i]].GetUnpackSize();
|
||||
extractCallback->SetTotal(totalSize);
|
||||
|
||||
UInt64 totalPackSize;
|
||||
@@ -282,7 +317,8 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
item = &_items[index];
|
||||
|
||||
RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
|
||||
totalSize += item->Size;
|
||||
UInt64 unpackSize = item->GetUnpackSize();
|
||||
totalSize += unpackSize;
|
||||
totalPackSize += item->GetPackSize();
|
||||
if (item->IsDir())
|
||||
{
|
||||
@@ -302,14 +338,21 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
|
||||
outStreamSpec->SetStream(realOutStream);
|
||||
realOutStream.Release();
|
||||
outStreamSpec->Init(skipMode ? 0 : item->Size, true);
|
||||
outStreamSpec->Init(skipMode ? 0 : unpackSize, true);
|
||||
|
||||
if (!seqMode)
|
||||
if (item->IsLink())
|
||||
{
|
||||
RINOK(_stream->Seek(item->GetDataPosition(), STREAM_SEEK_SET, NULL));
|
||||
RINOK(WriteStream(outStreamSpec, (const char *)item->LinkName, item->LinkName.Length()));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!seqMode)
|
||||
{
|
||||
RINOK(_stream->Seek(item->GetDataPosition(), STREAM_SEEK_SET, NULL));
|
||||
}
|
||||
streamSpec->Init(item->GetPackSize());
|
||||
RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
|
||||
}
|
||||
streamSpec->Init(item->GetPackSize());
|
||||
RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
|
||||
if (seqMode)
|
||||
{
|
||||
_latestIsRead = false;
|
||||
@@ -328,6 +371,14 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
const CItemEx &item = _items[index];
|
||||
if (item.IsLink())
|
||||
{
|
||||
CBufInStream *streamSpec = new CBufInStream;
|
||||
CMyComPtr<IInStream> streamTemp = streamSpec;
|
||||
streamSpec->Init((const Byte *)(const char *)item.LinkName, item.LinkName.Length(), (IInArchive *)this);
|
||||
*stream = streamTemp.Detach();
|
||||
return S_OK;
|
||||
}
|
||||
return CreateLimitedInStream(_stream, item.GetDataPosition(), item.Size, stream);
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
@@ -23,18 +23,20 @@ class CHandler:
|
||||
CObjectVector<CItemEx> _items;
|
||||
CMyComPtr<IInStream> _stream;
|
||||
CMyComPtr<ISequentialInStream> _seqStream;
|
||||
bool _isGood;
|
||||
|
||||
UInt32 _curIndex;
|
||||
bool _latestIsRead;
|
||||
CItemEx _latestItem;
|
||||
|
||||
UInt64 _phySize;
|
||||
UInt64 _headersSize;
|
||||
bool _phySizeDefined;
|
||||
AString _errorMessage;
|
||||
|
||||
NCompress::CCopyCoder *copyCoderSpec;
|
||||
CMyComPtr<ICompressCoder> copyCoder;
|
||||
|
||||
HRESULT ReadItem2(ISequentialInStream *stream, bool &filled, CItemEx &itemInfo);
|
||||
HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback);
|
||||
HRESULT SkipTo(UInt32 index);
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
|
||||
IArchiveUpdateCallback *callback)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
if ((_stream && !_isGood) || _seqStream)
|
||||
if ((_stream && !_errorMessage.IsEmpty()) || _seqStream)
|
||||
return E_NOTIMPL;
|
||||
CObjectVector<CUpdateItem> updateItems;
|
||||
for (UInt32 i = 0; i < numItems; i++)
|
||||
|
||||
@@ -63,29 +63,40 @@ static void ReadString(const char *s, int size, AString &result)
|
||||
result = temp;
|
||||
}
|
||||
|
||||
static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemEx &item, size_t &processedSize)
|
||||
static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemEx &item, AString &error)
|
||||
{
|
||||
item.LongLinkSize = 0;
|
||||
char buf[NFileHeader::kRecordSize];
|
||||
char *p = buf;
|
||||
|
||||
error.Empty();
|
||||
filled = false;
|
||||
|
||||
bool thereAreEmptyRecords = false;
|
||||
for (;;)
|
||||
{
|
||||
processedSize = NFileHeader::kRecordSize;
|
||||
size_t processedSize = NFileHeader::kRecordSize;
|
||||
RINOK(ReadStream(stream, buf, &processedSize));
|
||||
if (processedSize == 0)
|
||||
{
|
||||
if (!thereAreEmptyRecords )
|
||||
error = "There are no trailing zero-filled records";
|
||||
return S_OK;
|
||||
}
|
||||
if (processedSize != NFileHeader::kRecordSize)
|
||||
return S_FALSE;
|
||||
{
|
||||
error = "There is no correct record at the end of archive";
|
||||
return S_OK;
|
||||
}
|
||||
item.HeaderSize += NFileHeader::kRecordSize;
|
||||
if (!IsRecordLast(buf))
|
||||
break;
|
||||
thereAreEmptyRecords = true;
|
||||
}
|
||||
if (thereAreEmptyRecords)
|
||||
return S_FALSE;
|
||||
{
|
||||
error = "There are data after end of archive";
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
ReadString(p, NFileHeader::kNameSize, item.Name); p += NFileHeader::kNameSize;
|
||||
|
||||
@@ -143,59 +154,54 @@ static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemE
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &item)
|
||||
HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &item, AString &error)
|
||||
{
|
||||
size_t processedSize;
|
||||
RINOK(GetNextItemReal(stream, filled, item, processedSize));
|
||||
if (!filled)
|
||||
return S_OK;
|
||||
// GNUtar extension
|
||||
if (item.LinkFlag == 'L' || // NEXT file has a long name
|
||||
item.LinkFlag == 'K') // NEXT file has a long linkname
|
||||
item.HeaderSize = 0;
|
||||
bool flagL = false;
|
||||
bool flagK = false;
|
||||
AString nameL;
|
||||
AString nameK;
|
||||
for (;;)
|
||||
{
|
||||
if (item.Name.Compare(NFileHeader::kLongLink) != 0)
|
||||
if (item.Name.Compare(NFileHeader::kLongLink2) != 0)
|
||||
RINOK(GetNextItemReal(stream, filled, item, error));
|
||||
if (!filled)
|
||||
return S_OK;
|
||||
if (item.LinkFlag == 'L' || // NEXT file has a long name
|
||||
item.LinkFlag == 'K') // NEXT file has a long linkname
|
||||
{
|
||||
AString *name;
|
||||
if (item.LinkFlag == 'L')
|
||||
{ if (flagL) return S_FALSE; flagL = true; name = &nameL; }
|
||||
else
|
||||
{ if (flagK) return S_FALSE; flagK = true; name = &nameK; }
|
||||
|
||||
if (item.Name.Compare(NFileHeader::kLongLink) != 0 &&
|
||||
item.Name.Compare(NFileHeader::kLongLink2) != 0)
|
||||
return S_FALSE;
|
||||
|
||||
AString fullName;
|
||||
if (item.Size > (1 << 15))
|
||||
if (item.Size > (1 << 14))
|
||||
return S_FALSE;
|
||||
int packSize = (int)item.GetPackSize();
|
||||
char *buf = name->GetBuffer(packSize);
|
||||
RINOK(ReadStream_FALSE(stream, buf, packSize));
|
||||
item.HeaderSize += packSize;
|
||||
buf[(size_t)item.Size] = '\0';
|
||||
name->ReleaseBuffer();
|
||||
continue;
|
||||
}
|
||||
if (item.LinkFlag == 'g' || item.LinkFlag == 'x' || item.LinkFlag == 'X')
|
||||
{
|
||||
// pax Extended Header
|
||||
}
|
||||
else if (item.LinkFlag == NFileHeader::NLinkFlag::kDumpDir)
|
||||
{
|
||||
// GNU Extensions to the Archive Format
|
||||
}
|
||||
else if (item.LinkFlag > '7' || (item.LinkFlag < '0' && item.LinkFlag != 0))
|
||||
return S_FALSE;
|
||||
int packSize = (int)item.GetPackSize();
|
||||
char *buffer = fullName.GetBuffer(packSize + 1);
|
||||
|
||||
RINOK(ReadStream_FALSE(stream, buffer, packSize));
|
||||
processedSize += packSize;
|
||||
buffer[item.Size] = '\0';
|
||||
fullName.ReleaseBuffer();
|
||||
|
||||
UInt64 headerPosition = item.HeaderPosition;
|
||||
if (item.LinkFlag == 'L')
|
||||
{
|
||||
size_t processedSize2;
|
||||
RINOK(GetNextItemReal(stream, filled, item, processedSize2));
|
||||
item.LongLinkSize = (unsigned)processedSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
item.LongLinkSize = (unsigned)processedSize - NFileHeader::kRecordSize;
|
||||
item.Size = 0;
|
||||
}
|
||||
item.Name = fullName;
|
||||
item.HeaderPosition = headerPosition;
|
||||
}
|
||||
else if (item.LinkFlag == 'g' || item.LinkFlag == 'x' || item.LinkFlag == 'X')
|
||||
{
|
||||
// pax Extended Header
|
||||
if (flagL) item.Name = nameL;
|
||||
if (flagK) item.LinkName = nameK;
|
||||
return S_OK;
|
||||
}
|
||||
else if (item.LinkFlag == NFileHeader::NLinkFlag::kDumpDir)
|
||||
{
|
||||
// GNU Extensions to the Archive Format
|
||||
return S_OK;
|
||||
}
|
||||
else if (item.LinkFlag > '7' || (item.LinkFlag < '0' && item.LinkFlag != 0))
|
||||
return S_FALSE;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
// Archive/TarIn.h
|
||||
// TarIn.h
|
||||
|
||||
#ifndef __ARCHIVE_TAR_IN_H
|
||||
#define __ARCHIVE_TAR_IN_H
|
||||
|
||||
#include "Common/MyCom.h"
|
||||
#include "../../IStream.h"
|
||||
|
||||
#include "TarItem.h"
|
||||
@@ -11,7 +10,7 @@
|
||||
namespace NArchive {
|
||||
namespace NTar {
|
||||
|
||||
HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &itemInfo);
|
||||
HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &itemInfo, AString &error);
|
||||
|
||||
}}
|
||||
|
||||
|
||||
@@ -31,6 +31,9 @@ struct CItem
|
||||
bool DeviceMajorDefined;
|
||||
bool DeviceMinorDefined;
|
||||
|
||||
bool IsLink() const { return LinkFlag == NFileHeader::NLinkFlag::kSymbolicLink && (Size == 0); }
|
||||
UInt64 GetUnpackSize() const { return IsLink() ? LinkName.Length() : Size; }
|
||||
|
||||
bool IsDir() const
|
||||
{
|
||||
switch(LinkFlag)
|
||||
@@ -58,10 +61,10 @@ struct CItem
|
||||
|
||||
struct CItemEx: public CItem
|
||||
{
|
||||
UInt64 HeaderPosition;
|
||||
unsigned LongLinkSize;
|
||||
UInt64 GetDataPosition() const { return HeaderPosition + LongLinkSize + NFileHeader::kRecordSize; }
|
||||
UInt64 GetFullSize() const { return LongLinkSize + NFileHeader::kRecordSize + Size; }
|
||||
UInt64 HeaderPos;
|
||||
unsigned HeaderSize;
|
||||
UInt64 GetDataPosition() const { return HeaderPos + HeaderSize; }
|
||||
UInt64 GetFullSize() const { return HeaderSize + Size; }
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
@@ -111,25 +111,25 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
|
||||
}
|
||||
else
|
||||
{
|
||||
const CItemEx &existItemInfo = inputItems[ui.IndexInArchive];
|
||||
const CItemEx &existItem = inputItems[ui.IndexInArchive];
|
||||
UInt64 size;
|
||||
if (ui.NewProps)
|
||||
{
|
||||
RINOK(outArchive.WriteHeader(item));
|
||||
RINOK(inStream->Seek(existItemInfo.GetDataPosition(), STREAM_SEEK_SET, NULL));
|
||||
size = existItemInfo.Size;
|
||||
RINOK(inStream->Seek(existItem.GetDataPosition(), STREAM_SEEK_SET, NULL));
|
||||
size = existItem.Size;
|
||||
}
|
||||
else
|
||||
{
|
||||
RINOK(inStream->Seek(existItemInfo.HeaderPosition, STREAM_SEEK_SET, NULL));
|
||||
size = existItemInfo.GetFullSize();
|
||||
RINOK(inStream->Seek(existItem.HeaderPos, STREAM_SEEK_SET, NULL));
|
||||
size = existItem.GetFullSize();
|
||||
}
|
||||
streamSpec->Init(size);
|
||||
|
||||
RINOK(copyCoder->Code(inStreamLimited, outStream, NULL, NULL, progress));
|
||||
if (copyCoderSpec->TotalSize != size)
|
||||
return E_FAIL;
|
||||
RINOK(outArchive.FillDataResidual(existItemInfo.Size));
|
||||
RINOK(outArchive.FillDataResidual(existItem.Size));
|
||||
complexity += size;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user