mirror of
https://github.com/Xevion/easy7zip.git
synced 2025-12-06 13:14:59 -06:00
544 lines
13 KiB
C++
Executable File
544 lines
13 KiB
C++
Executable File
// ElfHandler.cpp
|
|
|
|
#include "StdAfx.h"
|
|
|
|
#include "../../../C/CpuArch.h"
|
|
|
|
#include "Common/Buffer.h"
|
|
#include "Common/ComTry.h"
|
|
#include "Common/IntToString.h"
|
|
|
|
#include "Windows/PropVariantUtils.h"
|
|
|
|
#include "../Common/LimitedStreams.h"
|
|
#include "../Common/ProgressUtils.h"
|
|
#include "../Common/RegisterArc.h"
|
|
#include "../Common/StreamUtils.h"
|
|
|
|
#include "../Compress/CopyCoder.h"
|
|
|
|
#include "Common/DummyOutStream.h"
|
|
|
|
static UInt16 Get16(const Byte *p, int be) { if (be) return GetBe16(p); return GetUi16(p); }
|
|
static UInt32 Get32(const Byte *p, int be) { if (be) return GetBe32(p); return GetUi32(p); }
|
|
static UInt64 Get64(const Byte *p, int be) { if (be) return GetBe64(p); return GetUi64(p); }
|
|
|
|
using namespace NWindows;
|
|
|
|
namespace NArchive {
|
|
namespace NElf {
|
|
|
|
#define ELF_CLASS_32 1
|
|
#define ELF_CLASS_64 2
|
|
|
|
#define ELF_DATA_2LSB 1
|
|
#define ELF_DATA_2MSB 2
|
|
|
|
#define NUM_SCAN_SECTIONS_MAX (1 << 6)
|
|
|
|
struct CHeader
|
|
{
|
|
bool Mode64;
|
|
bool Be;
|
|
Byte Os;
|
|
Byte AbiVer;
|
|
|
|
UInt16 Type;
|
|
UInt16 Machine;
|
|
// UInt32 Version;
|
|
|
|
// UInt64 EntryVa;
|
|
UInt64 ProgOffset;
|
|
UInt64 SectOffset;
|
|
UInt32 Flags;
|
|
UInt16 ElfHeaderSize;
|
|
UInt16 SegmentEntrySize;
|
|
UInt16 NumSegments;
|
|
UInt16 SectEntrySize;
|
|
UInt16 NumSections;
|
|
// UInt16 SectNameStringTableIndex;
|
|
|
|
bool Parse(const Byte *buf);
|
|
|
|
bool CheckSegmentEntrySize() const
|
|
{
|
|
return (Mode64 && SegmentEntrySize == 0x38) || (!Mode64 && SegmentEntrySize == 0x20);
|
|
};
|
|
|
|
UInt64 GetHeadersSize() const
|
|
{ return ElfHeaderSize +
|
|
(UInt64)SegmentEntrySize * NumSegments +
|
|
(UInt64)SectEntrySize * NumSections; }
|
|
|
|
};
|
|
|
|
bool CHeader::Parse(const Byte *p)
|
|
{
|
|
switch(p[4])
|
|
{
|
|
case ELF_CLASS_32: Mode64 = false; break;
|
|
case ELF_CLASS_64: Mode64 = true; break;
|
|
default: return false;
|
|
}
|
|
bool be;
|
|
switch(p[5])
|
|
{
|
|
case ELF_DATA_2LSB: be = false; break;
|
|
case ELF_DATA_2MSB: be = true; break;
|
|
default: return false;
|
|
}
|
|
Be = be;
|
|
if (p[6] != 1) // Version
|
|
return false;
|
|
Os = p[7];
|
|
AbiVer = p[8];
|
|
for (int i = 9; i < 16; i++)
|
|
if (p[i] != 0)
|
|
return false;
|
|
|
|
Type = Get16(p + 0x10, be);
|
|
Machine = Get16(p + 0x12, be);
|
|
if (Get32(p + 0x14, be) != 1) // Version
|
|
return false;
|
|
|
|
if (Mode64)
|
|
{
|
|
// EntryVa = Get64(p + 0x18, be);
|
|
ProgOffset = Get64(p + 0x20, be);
|
|
SectOffset = Get64(p + 0x28, be);
|
|
p += 0x30;
|
|
}
|
|
else
|
|
{
|
|
// EntryVa = Get32(p + 0x18, be);
|
|
ProgOffset = Get32(p + 0x1C, be);
|
|
SectOffset = Get32(p + 0x20, be);
|
|
p += 0x24;
|
|
}
|
|
|
|
Flags = Get32(p + 0, be);
|
|
ElfHeaderSize = Get16(p + 4, be);
|
|
SegmentEntrySize = Get16(p + 6, be);
|
|
NumSegments = Get16(p + 8, be);
|
|
SectEntrySize = Get16(p + 10, be);
|
|
NumSections = Get16(p + 12, be);
|
|
// SectNameStringTableIndex = Get16(p + 14, be);
|
|
return CheckSegmentEntrySize();
|
|
}
|
|
|
|
struct CSegment
|
|
{
|
|
UInt32 Type;
|
|
UInt32 Flags;
|
|
UInt64 Offset;
|
|
UInt64 Va;
|
|
// UInt64 Pa;
|
|
UInt64 PSize;
|
|
UInt64 VSize;
|
|
// UInt64 Align;
|
|
|
|
void UpdateTotalSize(UInt64 &totalSize)
|
|
{
|
|
UInt64 t = Offset + PSize;
|
|
if (t > totalSize)
|
|
totalSize = t;
|
|
}
|
|
void Parse(const Byte *p, bool mode64, bool be);
|
|
};
|
|
|
|
void CSegment::Parse(const Byte *p, bool mode64, bool be)
|
|
{
|
|
Type = Get32(p, be);
|
|
if (mode64)
|
|
{
|
|
Flags = Get32(p + 4, be);
|
|
Offset = Get64(p + 8, be);
|
|
Va = Get64(p + 0x10, be);
|
|
// Pa = Get64(p + 0x18, be);
|
|
PSize = Get64(p + 0x20, be);
|
|
VSize = Get64(p + 0x28, be);
|
|
// Align = Get64(p + 0x30, be);
|
|
}
|
|
else
|
|
{
|
|
Offset = Get32(p + 4, be);
|
|
Va = Get32(p + 8, be);
|
|
// Pa = Get32(p + 12, be);
|
|
PSize = Get32(p + 16, be);
|
|
VSize = Get32(p + 20, be);
|
|
Flags = Get32(p + 24, be);
|
|
// Align = Get32(p + 28, be);
|
|
}
|
|
}
|
|
|
|
static const CUInt32PCharPair g_MachinePairs[] =
|
|
{
|
|
{ 0, "None" },
|
|
{ 1, "AT&T WE 32100" },
|
|
{ 2, "SPARC" },
|
|
{ 3, "Intel 386" },
|
|
{ 4, "Motorola 68000" },
|
|
{ 5, "Motorola 88000" },
|
|
{ 6, "Intel 486" },
|
|
{ 7, "Intel i860" },
|
|
{ 8, "MIPS" },
|
|
{ 9, "IBM S/370" },
|
|
{ 10, "MIPS RS3000 LE" },
|
|
{ 11, "RS6000" },
|
|
|
|
{ 15, "PA-RISC" },
|
|
{ 16, "nCUBE" },
|
|
{ 17, "Fujitsu VPP500" },
|
|
{ 18, "SPARC 32+" },
|
|
{ 19, "Intel i960" },
|
|
{ 20, "PowerPC" },
|
|
{ 21, "PowerPC 64-bit" },
|
|
{ 22, "IBM S/390" },
|
|
|
|
{ 36, "NEX v800" },
|
|
{ 37, "Fujitsu FR20" },
|
|
{ 38, "TRW RH-32" },
|
|
{ 39, "Motorola RCE" },
|
|
{ 40, "ARM" },
|
|
{ 41, "Alpha" },
|
|
{ 42, "Hitachi SH" },
|
|
{ 43, "SPARC-V9" },
|
|
{ 44, "Siemens Tricore" },
|
|
{ 45, "ARC" },
|
|
{ 46, "H8/300" },
|
|
{ 47, "H8/300H" },
|
|
{ 48, "H8S" },
|
|
{ 49, "H8/500" },
|
|
{ 50, "IA-64" },
|
|
{ 51, "Stanford MIPS-X" },
|
|
{ 52, "Motorola ColdFire" },
|
|
{ 53, "M68HC12" },
|
|
{ 54, "Fujitsu MMA" },
|
|
{ 55, "Siemens PCP" },
|
|
{ 56, "Sony nCPU" },
|
|
{ 57, "Denso NDR1" },
|
|
{ 58, "Motorola StarCore" },
|
|
{ 59, "Toyota ME16" },
|
|
{ 60, "ST100" },
|
|
{ 61, "Advanced Logic TinyJ" },
|
|
{ 62, "AMD64" },
|
|
{ 63, "Sony DSP" },
|
|
|
|
{ 66, "Siemens FX66" },
|
|
{ 67, "ST9+" },
|
|
{ 68, "ST7" },
|
|
{ 69, "MC68HC16" },
|
|
{ 70, "MC68HC11" },
|
|
{ 71, "MC68HC08" },
|
|
{ 72, "MC68HC05" },
|
|
{ 73, "Silicon Graphics SVx" },
|
|
{ 74, "ST19" },
|
|
{ 75, "Digital VAX" },
|
|
{ 76, "Axis CRIS" },
|
|
{ 77, "Infineon JAVELIN" },
|
|
{ 78, "Element 14 FirePath" },
|
|
{ 79, "LSI ZSP" },
|
|
{ 80, "MMIX" },
|
|
{ 81, "HUANY" },
|
|
{ 82, "SiTera Prism" },
|
|
{ 83, "Atmel AVR" },
|
|
{ 84, "Fujitsu FR30" },
|
|
{ 85, "Mitsubishi D10V" },
|
|
{ 86, "Mitsubishi D30V" },
|
|
{ 87, "NEC v850" },
|
|
{ 88, "Mitsubishi M32R" },
|
|
{ 89, "Matsushita MN10300" },
|
|
{ 90, "Matsushita MN10200" },
|
|
{ 91, "picoJava" },
|
|
{ 92, "OpenRISC" },
|
|
{ 93, "ARC Tangent-A5" },
|
|
{ 94, "Tensilica Xtensa" },
|
|
{ 0x9026, "Alpha" }
|
|
};
|
|
|
|
static const CUInt32PCharPair g_AbiOS[] =
|
|
{
|
|
{ 0, "None" },
|
|
{ 1, "HP-UX" },
|
|
{ 2, "NetBSD" },
|
|
{ 3, "Linux" },
|
|
|
|
{ 6, "Solaris" },
|
|
{ 7, "AIX" },
|
|
{ 8, "IRIX" },
|
|
{ 9, "FreeBSD" },
|
|
{ 10, "TRU64" },
|
|
{ 11, "Novell Modesto" },
|
|
{ 12, "OpenBSD" },
|
|
{ 13, "OpenVMS" },
|
|
{ 14, "HP NSK" },
|
|
{ 15, "AROS" },
|
|
{ 97, "ARM" },
|
|
{ 255, "Standalone" }
|
|
};
|
|
|
|
static const CUInt32PCharPair g_SegmentFlags[] =
|
|
{
|
|
{ 1 << 0, "Execute" },
|
|
{ 1 << 1, "Write" },
|
|
{ 1 << 2, "Read" }
|
|
};
|
|
|
|
static const char *g_Types[] =
|
|
{
|
|
"None",
|
|
"Relocatable file",
|
|
"Executable file",
|
|
"Shared object file",
|
|
"Core file"
|
|
};
|
|
|
|
static const char *g_SegnmentTypes[] =
|
|
{
|
|
"Unused",
|
|
"Loadable segment",
|
|
"Dynamic linking tables",
|
|
"Program interpreter path name",
|
|
"Note section",
|
|
"SHLIB",
|
|
"Program header table",
|
|
"TLS"
|
|
};
|
|
|
|
class CHandler:
|
|
public IInArchive,
|
|
public CMyUnknownImp
|
|
{
|
|
CMyComPtr<IInStream> _inStream;
|
|
CObjectVector<CSegment> _sections;
|
|
UInt32 _peOffset;
|
|
CHeader _header;
|
|
UInt64 _totalSize;
|
|
HRESULT Open2(IInStream *stream);
|
|
bool Parse(const Byte *buf, UInt32 size);
|
|
public:
|
|
MY_UNKNOWN_IMP1(IInArchive)
|
|
INTERFACE_IInArchive(;)
|
|
};
|
|
|
|
#define ELF_PT_PHDR 6
|
|
|
|
bool CHandler::Parse(const Byte *buf, UInt32 size)
|
|
{
|
|
if (size < 64)
|
|
return false;
|
|
if (!_header.Parse(buf))
|
|
return false;
|
|
if (_header.ProgOffset > size ||
|
|
_header.ProgOffset + (UInt64)_header.SegmentEntrySize * _header.NumSegments > size ||
|
|
_header.NumSegments > NUM_SCAN_SECTIONS_MAX)
|
|
return false;
|
|
const Byte *p = buf + _header.ProgOffset;
|
|
_totalSize = _header.ProgOffset;
|
|
|
|
for (int i = 0; i < _header.NumSegments; i++, p += _header.SegmentEntrySize)
|
|
{
|
|
CSegment sect;
|
|
sect.Parse(p, _header.Mode64, _header.Be);
|
|
sect.UpdateTotalSize(_totalSize);
|
|
if (sect.Type != ELF_PT_PHDR)
|
|
_sections.Add(sect);
|
|
}
|
|
UInt64 total2 = _header.SectOffset + (UInt64)_header.SectEntrySize * _header.NumSections;
|
|
if (total2 > _totalSize)
|
|
_totalSize = total2;
|
|
return true;
|
|
}
|
|
|
|
STATPROPSTG kArcProps[] =
|
|
{
|
|
{ NULL, kpidCpu, VT_BSTR},
|
|
{ NULL, kpidBit64, VT_BOOL},
|
|
{ NULL, kpidBigEndian, VT_BOOL},
|
|
{ NULL, kpidHostOS, VT_BSTR},
|
|
{ NULL, kpidCharacts, VT_BSTR},
|
|
{ NULL, kpidPhySize, VT_UI8},
|
|
{ NULL, kpidHeadersSize, VT_UI8}
|
|
};
|
|
|
|
STATPROPSTG kProps[] =
|
|
{
|
|
{ NULL, kpidPath, VT_BSTR},
|
|
{ NULL, kpidSize, VT_UI8},
|
|
{ NULL, kpidPackSize, VT_UI8},
|
|
{ NULL, kpidType, VT_BSTR},
|
|
{ NULL, kpidCharacts, VT_BSTR},
|
|
{ NULL, kpidOffset, VT_UI8},
|
|
{ NULL, kpidVa, VT_UI8}
|
|
};
|
|
|
|
IMP_IInArchive_Props
|
|
IMP_IInArchive_ArcProps
|
|
|
|
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
|
|
{
|
|
COM_TRY_BEGIN
|
|
NCOM::CPropVariant prop;
|
|
switch(propID)
|
|
{
|
|
case kpidPhySize: prop = _totalSize; break;
|
|
case kpidHeadersSize: prop = _header.GetHeadersSize(); break;
|
|
case kpidBit64: if (_header.Mode64) prop = _header.Mode64; break;
|
|
case kpidBigEndian: if (_header.Be) prop = _header.Be; break;
|
|
case kpidCpu: PAIR_TO_PROP(g_MachinePairs, _header.Machine, prop); break;
|
|
case kpidHostOS: PAIR_TO_PROP(g_AbiOS, _header.Os, prop); break;
|
|
case kpidCharacts: TYPE_TO_PROP(g_Types, _header.Type, prop); break;
|
|
}
|
|
prop.Detach(value);
|
|
return S_OK;
|
|
COM_TRY_END
|
|
}
|
|
|
|
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
|
|
{
|
|
COM_TRY_BEGIN
|
|
NCOM::CPropVariant prop;
|
|
const CSegment &item = _sections[index];
|
|
switch(propID)
|
|
{
|
|
case kpidPath:
|
|
{
|
|
wchar_t sz[32];
|
|
ConvertUInt64ToString(index, sz);
|
|
prop = sz;
|
|
break;
|
|
}
|
|
case kpidSize: prop = (UInt64)item.VSize; break;
|
|
case kpidPackSize: prop = (UInt64)item.PSize; break;
|
|
case kpidOffset: prop = item.Offset; break;
|
|
case kpidVa: prop = item.Va; break;
|
|
case kpidType: TYPE_TO_PROP(g_SegnmentTypes, item.Type, prop); break;
|
|
case kpidCharacts: FLAGS_TO_PROP(g_SegmentFlags, item.Flags, prop); break;
|
|
}
|
|
prop.Detach(value);
|
|
return S_OK;
|
|
COM_TRY_END
|
|
}
|
|
|
|
HRESULT CHandler::Open2(IInStream *stream)
|
|
{
|
|
const UInt32 kBufSize = 1 << 18;
|
|
const UInt32 kSigSize = 4;
|
|
|
|
CByteBuffer buffer;
|
|
buffer.SetCapacity(kBufSize);
|
|
Byte *buf = buffer;
|
|
|
|
size_t processed = kSigSize;
|
|
RINOK(ReadStream_FALSE(stream, buf, processed));
|
|
if (buf[0] != 0x7F || buf[1] != 'E' || buf[2] != 'L' || buf[3] != 'F')
|
|
return S_FALSE;
|
|
processed = kBufSize - kSigSize;
|
|
RINOK(ReadStream(stream, buf + kSigSize, &processed));
|
|
processed += kSigSize;
|
|
if (!Parse(buf, (UInt32)processed))
|
|
return S_FALSE;
|
|
UInt64 fileSize;
|
|
RINOK(stream->Seek(0, STREAM_SEEK_END, &fileSize));
|
|
return (fileSize == _totalSize) ? S_OK : S_FALSE;
|
|
}
|
|
|
|
STDMETHODIMP CHandler::Open(IInStream *inStream,
|
|
const UInt64 * /* maxCheckStartPosition */,
|
|
IArchiveOpenCallback * /* openArchiveCallback */)
|
|
{
|
|
COM_TRY_BEGIN
|
|
Close();
|
|
RINOK(Open2(inStream));
|
|
_inStream = inStream;
|
|
return S_OK;
|
|
COM_TRY_END
|
|
}
|
|
|
|
STDMETHODIMP CHandler::Close()
|
|
{
|
|
_inStream.Release();
|
|
_sections.Clear();
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
|
|
{
|
|
*numItems = _sections.Size();
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
|
|
Int32 _aTestMode, IArchiveExtractCallback *extractCallback)
|
|
{
|
|
COM_TRY_BEGIN
|
|
bool testMode = (_aTestMode != 0);
|
|
bool allFilesMode = (numItems == UInt32(-1));
|
|
if (allFilesMode)
|
|
numItems = _sections.Size();
|
|
if (numItems == 0)
|
|
return S_OK;
|
|
UInt64 totalSize = 0;
|
|
UInt32 i;
|
|
for (i = 0; i < numItems; i++)
|
|
totalSize += _sections[allFilesMode ? i : indices[i]].PSize;
|
|
extractCallback->SetTotal(totalSize);
|
|
|
|
UInt64 currentTotalSize = 0;
|
|
UInt64 currentItemSize;
|
|
|
|
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(_inStream);
|
|
|
|
CDummyOutStream *outStreamSpec = new CDummyOutStream;
|
|
CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
|
|
|
|
for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
|
|
{
|
|
lps->InSize = lps->OutSize = currentTotalSize;
|
|
RINOK(lps->SetCur());
|
|
Int32 askMode = testMode ?
|
|
NArchive::NExtract::NAskMode::kTest :
|
|
NArchive::NExtract::NAskMode::kExtract;
|
|
UInt32 index = allFilesMode ? i : indices[i];
|
|
const CSegment &item = _sections[index];
|
|
currentItemSize = item.PSize;
|
|
{
|
|
CMyComPtr<ISequentialOutStream> realOutStream;
|
|
RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
|
|
if (!testMode && (!realOutStream))
|
|
continue;
|
|
outStreamSpec->SetStream(realOutStream);
|
|
outStreamSpec->Init();
|
|
}
|
|
|
|
RINOK(extractCallback->PrepareOperation(askMode));
|
|
RINOK(_inStream->Seek(item.Offset, STREAM_SEEK_SET, NULL));
|
|
streamSpec->Init(currentItemSize);
|
|
RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
|
|
outStreamSpec->ReleaseStream();
|
|
RINOK(extractCallback->SetOperationResult(copyCoderSpec->TotalSize == currentItemSize ?
|
|
NArchive::NExtract::NOperationResult::kOK:
|
|
NArchive::NExtract::NOperationResult::kDataError));
|
|
}
|
|
return S_OK;
|
|
COM_TRY_END
|
|
}
|
|
|
|
static IInArchive *CreateArc() { return new CHandler; }
|
|
|
|
static CArcInfo g_ArcInfo =
|
|
{ L"ELF", L"", 0, 0xDE, { 0 }, 0, false, CreateArc, 0 };
|
|
|
|
REGISTER_ARC(Elf)
|
|
|
|
}}
|