mirror of
https://github.com/Xevion/easy7zip.git
synced 2026-02-01 06:24:12 -06:00
4.59 beta
This commit is contained in:
committed by
Kornel Lesiński
parent
3901bf0ab8
commit
173c07e166
Executable
+543
@@ -0,0 +1,543 @@
|
||||
4// 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/Copy/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)
|
||||
|
||||
}}
|
||||
Reference in New Issue
Block a user