mirror of
https://github.com/Xevion/easy7zip.git
synced 2025-12-06 15:14:59 -06:00
267 lines
6.6 KiB
C++
Executable File
267 lines
6.6 KiB
C++
Executable File
// MubHandler.cpp
|
|
|
|
#include "StdAfx.h"
|
|
|
|
#include "../../../C/CpuArch.h"
|
|
|
|
#include "Common/ComTry.h"
|
|
|
|
#include "Windows/PropVariant.h"
|
|
|
|
#include "../Common/LimitedStreams.h"
|
|
#include "../Common/ProgressUtils.h"
|
|
#include "../Common/RegisterArc.h"
|
|
#include "../Common/StreamUtils.h"
|
|
|
|
#include "../Compress/CopyCoder.h"
|
|
|
|
#define Get32(p) GetBe32(p)
|
|
|
|
namespace NArchive {
|
|
namespace NMub {
|
|
|
|
struct CItem
|
|
{
|
|
UInt32 Type;
|
|
UInt32 SubType;
|
|
UInt64 Offset;
|
|
UInt64 Size;
|
|
UInt32 Align;
|
|
bool IsTail;
|
|
};
|
|
|
|
const UInt32 kNumFilesMax = 10;
|
|
|
|
class CHandler:
|
|
public IInArchive,
|
|
public IInArchiveGetStream,
|
|
public CMyUnknownImp
|
|
{
|
|
UInt64 _startPos;
|
|
CMyComPtr<IInStream> _stream;
|
|
UInt32 _numItems;
|
|
CItem _items[kNumFilesMax + 1];
|
|
HRESULT Open2(IInStream *stream);
|
|
public:
|
|
MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
|
|
INTERFACE_IInArchive(;)
|
|
STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
|
|
};
|
|
|
|
STATPROPSTG kProps[] =
|
|
{
|
|
{ NULL, kpidSize, VT_UI8}
|
|
};
|
|
|
|
IMP_IInArchive_Props
|
|
IMP_IInArchive_ArcProps_NO
|
|
|
|
#define MACH_ARCH_ABI64 0x1000000
|
|
#define MACH_MACHINE_386 7
|
|
#define MACH_MACHINE_ARM 12
|
|
#define MACH_MACHINE_SPARC 14
|
|
#define MACH_MACHINE_PPC 18
|
|
|
|
#define MACH_MACHINE_PPC64 (MACH_MACHINE_PPC | MACH_ARCH_ABI64)
|
|
#define MACH_MACHINE_AMD64 (MACH_MACHINE_386 | MACH_ARCH_ABI64)
|
|
|
|
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
|
|
{
|
|
NWindows::NCOM::CPropVariant prop;
|
|
const CItem &item = _items[index];
|
|
switch(propID)
|
|
{
|
|
case kpidExtension:
|
|
{
|
|
const wchar_t *ext;
|
|
if (item.IsTail)
|
|
ext = L"tail";
|
|
else
|
|
{
|
|
switch(item.Type)
|
|
{
|
|
case MACH_MACHINE_386: ext = L"86"; break;
|
|
case MACH_MACHINE_ARM: ext = L"arm"; break;
|
|
case MACH_MACHINE_SPARC: ext = L"sparc"; break;
|
|
case MACH_MACHINE_PPC: ext = L"ppc"; break;
|
|
case MACH_MACHINE_PPC64: ext = L"ppc64"; break;
|
|
case MACH_MACHINE_AMD64: ext = L"x64"; break;
|
|
default: ext = L"unknown"; break;
|
|
}
|
|
}
|
|
prop = ext;
|
|
break;
|
|
}
|
|
case kpidSize:
|
|
case kpidPackSize:
|
|
prop = (UInt64)item.Size;
|
|
break;
|
|
}
|
|
prop.Detach(value);
|
|
return S_OK;
|
|
}
|
|
|
|
#define MACH_TYPE_ABI64 (1 << 24)
|
|
#define MACH_SUBTYPE_ABI64 (1 << 31)
|
|
|
|
HRESULT CHandler::Open2(IInStream *stream)
|
|
{
|
|
RINOK(stream->Seek(0, STREAM_SEEK_SET, &_startPos));
|
|
|
|
const UInt32 kHeaderSize = 8;
|
|
const UInt32 kRecordSize = 5 * 4;
|
|
const UInt32 kBufSize = kHeaderSize + kNumFilesMax * kRecordSize;
|
|
Byte buf[kBufSize];
|
|
size_t processed = kBufSize;
|
|
RINOK(ReadStream(stream, buf, &processed));
|
|
if (processed < kHeaderSize)
|
|
return S_FALSE;
|
|
UInt32 num = Get32(buf + 4);
|
|
if (Get32(buf) != 0xCAFEBABE || num > kNumFilesMax || processed < kHeaderSize + num * kRecordSize)
|
|
return S_FALSE;
|
|
UInt64 endPosMax = kHeaderSize;
|
|
for (UInt32 i = 0; i < num; i++)
|
|
{
|
|
const Byte *p = buf + kHeaderSize + i * kRecordSize;
|
|
CItem &sb = _items[i];
|
|
sb.IsTail = false;
|
|
sb.Type = Get32(p);
|
|
sb.SubType = Get32(p + 4);
|
|
sb.Offset = Get32(p + 8);
|
|
sb.Size = Get32(p + 12);
|
|
sb.Align = Get32(p + 16);
|
|
|
|
if ((sb.Type & ~MACH_TYPE_ABI64) >= 0x100 ||
|
|
(sb.SubType & ~MACH_SUBTYPE_ABI64) >= 0x100 ||
|
|
sb.Align > 31)
|
|
return S_FALSE;
|
|
|
|
UInt64 endPos = (UInt64)sb.Offset + sb.Size;
|
|
if (endPos > endPosMax)
|
|
endPosMax = endPos;
|
|
}
|
|
UInt64 fileSize;
|
|
RINOK(stream->Seek(0, STREAM_SEEK_END, &fileSize));
|
|
fileSize -= _startPos;
|
|
_numItems = num;
|
|
if (fileSize > endPosMax)
|
|
{
|
|
CItem &sb = _items[_numItems++];
|
|
sb.IsTail = true;
|
|
sb.Type = 0;
|
|
sb.SubType = 0;
|
|
sb.Offset = endPosMax;
|
|
sb.Size = fileSize - endPosMax;
|
|
sb.Align = 0;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CHandler::Open(IInStream *inStream,
|
|
const UInt64 * /* maxCheckStartPosition */,
|
|
IArchiveOpenCallback * /* openArchiveCallback */)
|
|
{
|
|
COM_TRY_BEGIN
|
|
Close();
|
|
try
|
|
{
|
|
if (Open2(inStream) != S_OK)
|
|
return S_FALSE;
|
|
_stream = inStream;
|
|
}
|
|
catch(...) { return S_FALSE; }
|
|
return S_OK;
|
|
COM_TRY_END
|
|
}
|
|
|
|
STDMETHODIMP CHandler::Close()
|
|
{
|
|
_stream.Release();
|
|
_numItems = 0;
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
|
|
{
|
|
*numItems = _numItems;
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
|
Int32 testMode, IArchiveExtractCallback *extractCallback)
|
|
{
|
|
COM_TRY_BEGIN
|
|
bool allFilesMode = (numItems == (UInt32)-1);
|
|
if (allFilesMode)
|
|
numItems = _numItems;
|
|
if (numItems == 0)
|
|
return S_OK;
|
|
UInt64 totalSize = 0;
|
|
UInt32 i;
|
|
for (i = 0; i < numItems; i++)
|
|
totalSize += _items[allFilesMode ? i : indices[i]].Size;
|
|
extractCallback->SetTotal(totalSize);
|
|
|
|
UInt64 currentTotalSize = 0;
|
|
|
|
NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
|
|
CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
|
|
|
|
CLocalProgress *lps = new CLocalProgress;
|
|
CMyComPtr<ICompressProgressInfo> progress = lps;
|
|
lps->Init(extractCallback, false);
|
|
|
|
CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
|
|
CMyComPtr<ISequentialInStream> inStream(streamSpec);
|
|
streamSpec->SetStream(_stream);
|
|
|
|
for (i = 0; i < numItems; i++)
|
|
{
|
|
lps->InSize = lps->OutSize = currentTotalSize;
|
|
RINOK(lps->SetCur());
|
|
CMyComPtr<ISequentialOutStream> realOutStream;
|
|
Int32 askMode = testMode ?
|
|
NExtract::NAskMode::kTest :
|
|
NExtract::NAskMode::kExtract;
|
|
UInt32 index = allFilesMode ? i : indices[i];
|
|
const CItem &item = _items[index];
|
|
RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
|
|
currentTotalSize += item.Size;
|
|
|
|
if (!testMode && !realOutStream)
|
|
continue;
|
|
RINOK(extractCallback->PrepareOperation(askMode));
|
|
if (testMode)
|
|
{
|
|
RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
|
|
continue;
|
|
}
|
|
RINOK(_stream->Seek(_startPos + item.Offset, STREAM_SEEK_SET, NULL));
|
|
streamSpec->Init(item.Size);
|
|
RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress));
|
|
realOutStream.Release();
|
|
RINOK(extractCallback->SetOperationResult((copyCoderSpec->TotalSize == item.Size) ?
|
|
NExtract::NOperationResult::kOK:
|
|
NExtract::NOperationResult::kDataError));
|
|
}
|
|
return S_OK;
|
|
COM_TRY_END
|
|
}
|
|
|
|
STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
|
|
{
|
|
COM_TRY_BEGIN
|
|
const CItem &item = _items[index];
|
|
return CreateLimitedInStream(_stream, _startPos + item.Offset, item.Size, stream);
|
|
COM_TRY_END
|
|
}
|
|
|
|
static IInArchive *CreateArc() { return new CHandler; }
|
|
|
|
static CArcInfo g_ArcInfo =
|
|
{ L"Mub", L"", 0, 0xE2, { 0xCA, 0xFE, 0xBA, 0xBE, 0, 0, 0 }, 7, false, CreateArc, 0 };
|
|
|
|
REGISTER_ARC(Mub)
|
|
|
|
}}
|