Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/kornelski/7z.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Pavlov <ipavlov@users.sourceforge.net>2014-11-23 03:00:00 +0300
committerKornel LesiƄski <kornel@geekhood.net>2016-05-28 02:16:51 +0300
commitf08f4dcc3c02464c17753b3feafcfe5243b9e236 (patch)
treeb0e1b15bc5368d92dff422e8ec0818564a2b00b8 /CPP/7zip/Archive/MachoHandler.cpp
parent83f8ddcc5b2161e1e3c49666265257fca8aeb12c (diff)
9.349.34
Diffstat (limited to 'CPP/7zip/Archive/MachoHandler.cpp')
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/MachoHandler.cpp640
1 files changed, 402 insertions, 238 deletions
diff --git a/CPP/7zip/Archive/MachoHandler.cpp b/CPP/7zip/Archive/MachoHandler.cpp
index a6261f34..11ff9703 100755..100644
--- a/CPP/7zip/Archive/MachoHandler.cpp
+++ b/CPP/7zip/Archive/MachoHandler.cpp
@@ -4,10 +4,12 @@
#include "../../../C/CpuArch.h"
-#include "Common/Buffer.h"
-#include "Common/ComTry.h"
+#include "../../Common/ComTry.h"
+#include "../../Common/MyBuffer.h"
+#include "../../Common/StringConvert.h"
+#include "../../Common/IntToString.h"
-#include "Windows/PropVariantUtils.h"
+#include "../../Windows/PropVariantUtils.h"
#include "../Common/LimitedStreams.h"
#include "../Common/ProgressUtils.h"
@@ -16,65 +18,142 @@
#include "../Compress/CopyCoder.h"
-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); }
+static UInt32 Get32(const Byte *p, bool be) { if (be) return GetBe32(p); return GetUi32(p); }
+static UInt64 Get64(const Byte *p, bool be) { if (be) return GetBe64(p); return GetUi64(p); }
using namespace NWindows;
+using namespace NCOM;
namespace NArchive {
namespace NMacho {
-#define MACH_ARCH_ABI64 (1 << 24)
-#define MACH_MACHINE_386 7
-#define MACH_MACHINE_ARM 12
-#define MACH_MACHINE_SPARC 14
-#define MACH_MACHINE_PPC 18
+#define CPU_ARCH_ABI64 (1 << 24)
+#define CPU_TYPE_386 7
+#define CPU_TYPE_ARM 12
+#define CPU_TYPE_SPARC 14
+#define CPU_TYPE_PPC 18
-#define MACH_MACHINE_PPC64 (MACH_ARCH_ABI64 | MACH_MACHINE_PPC)
-#define MACH_MACHINE_AMD64 (MACH_ARCH_ABI64 | MACH_MACHINE_386)
+#define CPU_SUBTYPE_I386_ALL 3
-#define MACH_CMD_SEGMENT_32 1
-#define MACH_CMD_SEGMENT_64 0x19
+#define CPU_TYPE_PPC64 (CPU_ARCH_ABI64 | CPU_TYPE_PPC)
+#define CPU_TYPE_AMD64 (CPU_ARCH_ABI64 | CPU_TYPE_386)
-#define MACH_SECT_TYPE_MASK 0x000000FF
-#define MACH_SECT_ATTR_MASK 0xFFFFFF00
+#define CPU_SUBTYPE_LIB64 (1 << 31)
-#define MACH_SECT_ATTR_ZEROFILL 1
+#define CPU_SUBTYPE_POWERPC_970 100
+
+static const char *k_PowerPc_SubTypes[] =
+{
+ NULL
+ , "601"
+ , "602"
+ , "603"
+ , "603e"
+ , "603ev"
+ , "604"
+ , "604e"
+ , "620"
+ , "750"
+ , "7400"
+ , "7450"
+};
+
+static const CUInt32PCharPair g_CpuPairs[] =
+{
+ { CPU_TYPE_386, "x86" },
+ { CPU_TYPE_ARM, "ARM" },
+ { CPU_TYPE_SPARC, "SPARC" },
+ { CPU_TYPE_PPC, "PowerPC" }
+};
+
+
+#define CMD_SEGMENT_32 1
+#define CMD_SEGMENT_64 0x19
+
+#define SECT_TYPE_MASK 0x000000FF
+#define SECT_ATTR_MASK 0xFFFFFF00
+
+#define SECT_ATTR_ZEROFILL 1
static const char *g_SectTypes[] =
{
- "REGULAR",
- "ZEROFILL",
- "CSTRINGS",
- "4BYTE_LITERALS",
- "8BYTE_LITERALS",
- "LITERAL_POINTERS",
- "NON_LAZY_SYMBOL_POINTERS",
- "LAZY_SYMBOL_POINTERS",
- "SYMBOL_STUBS",
- "MOD_INIT_FUNC_POINTERS",
- "MOD_TERM_FUNC_POINTERS",
- "COALESCED",
- "GB_ZEROFILL",
- "INTERPOSING",
- "16BYTE_LITERALS"
+ "REGULAR"
+ , "ZEROFILL"
+ , "CSTRINGS"
+ , "4BYTE_LITERALS"
+ , "8BYTE_LITERALS"
+ , "LITERAL_POINTERS"
+ , "NON_LAZY_SYMBOL_POINTERS"
+ , "LAZY_SYMBOL_POINTERS"
+ , "SYMBOL_STUBS"
+ , "MOD_INIT_FUNC_POINTERS"
+ , "MOD_TERM_FUNC_POINTERS"
+ , "COALESCED"
+ , "GB_ZEROFILL"
+ , "INTERPOSING"
+ , "16BYTE_LITERALS"
+};
+
+enum EFileType
+{
+ kType_OBJECT = 1,
+ kType_EXECUTE,
+ kType_FVMLIB,
+ kType_CORE,
+ kType_PRELOAD,
+ kType_DYLIB,
+ kType_DYLINKER,
+ kType_BUNDLE,
+ kType_DYLIB_STUB,
+ kType_DSYM
};
static const char *g_FileTypes[] =
{
- "0",
- "OBJECT",
- "EXECUTE",
- "FVMLIB",
- "CORE",
- "PRELOAD",
- "DYLIB",
- "DYLINKER",
- "BUNDLE",
- "DYLIB_STUB",
- "DSYM"
+ "0"
+ , "OBJECT"
+ , "EXECUTE"
+ , "FVMLIB"
+ , "CORE"
+ , "PRELOAD"
+ , "DYLIB"
+ , "DYLINKER"
+ , "BUNDLE"
+ , "DYLIB_STUB"
+ , "DSYM"
};
+
+static const char *g_ArcFlags[] =
+{
+ "NOUNDEFS"
+ , "INCRLINK"
+ , "DYLDLINK"
+ , "BINDATLOAD"
+ , "PREBOUND"
+ , "SPLIT_SEGS"
+ , "LAZY_INIT"
+ , "TWOLEVEL"
+ , "FORCE_FLAT"
+ , "NOMULTIDEFS"
+ , "NOFIXPREBINDING"
+ , "PREBINDABLE"
+ , "ALLMODSBOUND"
+ , "SUBSECTIONS_VIA_SYMBOLS"
+ , "CANONICAL"
+ , "WEAK_DEFINES"
+ , "BINDS_TO_WEAK"
+ , "ALLOW_STACK_EXECUTION"
+ , "ROOT_SAFE"
+ , "SETUID_SAFE"
+ , "NO_REEXPORTED_DYLIBS"
+ , "PIE"
+ , "DEAD_STRIPPABLE_DYLIB"
+ , "HAS_TLV_DESCRIPTORS"
+ , "NO_HEAP_EXECUTION"
+};
+
+
static const CUInt32PCharPair g_Flags[] =
{
{ 31, "PURE_INSTRUCTIONS" },
@@ -89,16 +168,6 @@ static const CUInt32PCharPair g_Flags[] =
{ 8, "LOC_RELOC" }
};
-static const CUInt32PCharPair g_MachinePairs[] =
-{
- { MACH_MACHINE_386, "x86" },
- { MACH_MACHINE_ARM, "ARM" },
- { MACH_MACHINE_SPARC, "SPARC" },
- { MACH_MACHINE_PPC, "PowerPC" },
- { MACH_MACHINE_PPC64, "PowerPC 64-bit" },
- { MACH_MACHINE_AMD64, "x64" }
-};
-
static const int kNameSize = 16;
struct CSegment
@@ -121,209 +190,150 @@ struct CSection
bool IsDummy;
CSection(): IsDummy(false) {}
- // UInt64 GetPackSize() const { return Flags == MACH_SECT_ATTR_ZEROFILL ? 0 : Size; }
+ // UInt64 GetPackSize() const { return Flags == SECT_ATTR_ZEROFILL ? 0 : Size; }
UInt64 GetPackSize() const { return PSize; }
};
class CHandler:
public IInArchive,
+ public IArchiveAllowTail,
public CMyUnknownImp
{
CMyComPtr<IInStream> _inStream;
CObjectVector<CSegment> _segments;
CObjectVector<CSection> _sections;
+ bool _allowTail;
bool _mode64;
bool _be;
- UInt32 _machine;
+ UInt32 _cpuType;
+ UInt32 _cpuSubType;
UInt32 _type;
+ UInt32 _flags;
UInt32 _headersSize;
UInt64 _totalSize;
+
HRESULT Open2(ISequentialInStream *stream);
- bool Parse(const Byte *buf, UInt32 size);
public:
- MY_UNKNOWN_IMP1(IInArchive)
+ MY_UNKNOWN_IMP2(IInArchive, IArchiveAllowTail)
INTERFACE_IInArchive(;)
+ STDMETHOD(AllowTail)(Int32 allowTail);
+ CHandler(): _allowTail(false) {}
};
-bool CHandler::Parse(const Byte *buf, UInt32 size)
+static const Byte kArcProps[] =
{
- bool mode64 = _mode64;
- bool be = _be;
-
- const Byte *bufStart = buf;
- bool reduceCommands = false;
- if (size < 512)
- return false;
-
- _machine = Get32(buf + 4, be);
- _type = Get32(buf + 0xC, be);
-
- UInt32 numCommands = Get32(buf + 0x10, be);
- UInt32 commandsSize = Get32(buf + 0x14, be);
- if (commandsSize > size)
- return false;
-
- if (commandsSize > (1 << 24) || numCommands > (1 << 18))
- return false;
-
- if (numCommands > 16)
- {
- reduceCommands = true;
- numCommands = 16;
- }
-
- _headersSize = 0;
-
- buf += 0x1C;
- size -= 0x1C;
+ kpidCpu,
+ kpidBit64,
+ kpidBigEndian,
+ kpidCharacts,
+ kpidHeadersSize
+};
- if (mode64)
- {
- buf += 4;
- size -= 4;
- }
+static const Byte kProps[] =
+{
+ kpidPath,
+ kpidSize,
+ kpidPackSize,
+ kpidCharacts,
+ kpidOffset,
+ kpidVa
+};
- _totalSize = (UInt32)(buf - bufStart);
- if (commandsSize < size)
- size = commandsSize;
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
- for (UInt32 cmdIndex = 0; cmdIndex < numCommands; cmdIndex++)
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ CPropVariant prop;
+ switch (propID)
{
- if (size < 8)
- return false;
- UInt32 cmd = Get32(buf, be);
- UInt32 cmdSize = Get32(buf + 4, be);
- if (size < cmdSize)
- return false;
- if (cmd == MACH_CMD_SEGMENT_32 || cmd == MACH_CMD_SEGMENT_64)
+ case kpidShortComment:
+ case kpidCpu:
{
- UInt32 offs = (cmd == MACH_CMD_SEGMENT_64) ? 0x48 : 0x38;
- if (cmdSize < offs)
- break;
-
- UInt64 vmAddr, vmSize, phAddr, phSize;
-
+ AString s;
+ char temp[16];
+ UInt32 cpu = _cpuType & ~(UInt32)CPU_ARCH_ABI64;
+ if (_cpuType == CPU_TYPE_AMD64)
+ s = "x64";
+ else
{
- if (cmd == MACH_CMD_SEGMENT_64)
- {
- vmAddr = Get64(buf + 0x18, be);
- vmSize = Get64(buf + 0x20, be);
- phAddr = Get64(buf + 0x28, be);
- phSize = Get64(buf + 0x30, be);
- }
- else
+ const char *n = NULL;
+ for (unsigned i = 0; i < ARRAY_SIZE(g_CpuPairs); i++)
{
- vmAddr = Get32(buf + 0x18, be);
- vmSize = Get32(buf + 0x1C, be);
- phAddr = Get32(buf + 0x20, be);
- phSize = Get32(buf + 0x24, be);
+ const CUInt32PCharPair &pair = g_CpuPairs[i];
+ if (pair.Value == cpu)
+ {
+ n = pair.Name;
+ break;
+ }
}
+ if (!n)
{
- UInt64 totalSize = phAddr + phSize;
- if (totalSize > _totalSize)
- _totalSize = totalSize;
+ ConvertUInt32ToString(cpu, temp);
+ n = temp;
}
+ s = n;
+
+ if (_cpuType & CPU_ARCH_ABI64)
+ s += " 64-bit";
+ else if (_cpuSubType & CPU_SUBTYPE_LIB64)
+ s += " 64-bit lib";
}
-
- CSegment seg;
- memcpy(seg.Name, buf + 8, kNameSize);
- _segments.Add(seg);
-
- UInt32 numSections = Get32(buf + offs - 8, be);
- if (numSections > (1 << 8))
- return false;
-
- if (numSections == 0)
- {
- CSection section;
- section.IsDummy = true;
- section.SegmentIndex = _segments.Size() - 1;
- section.Va = vmAddr;
- section.PSize = phSize;
- section.VSize = vmSize;
- section.Pa = phAddr;
- section.Flags = 0;
- _sections.Add(section);
- }
- else do
+ UInt32 t = _cpuSubType & ~(UInt32)CPU_SUBTYPE_LIB64;
+ if (t != 0 && (t != CPU_SUBTYPE_I386_ALL || cpu != CPU_TYPE_386))
{
- CSection section;
- UInt32 headerSize = (cmd == MACH_CMD_SEGMENT_64) ? 0x50 : 0x44;
- const Byte *p = buf + offs;
- if (cmdSize - offs < headerSize)
- break;
- if (cmd == MACH_CMD_SEGMENT_64)
+ const char *n = NULL;
+ if (cpu == CPU_TYPE_PPC)
{
- section.Va = Get64(p + 0x20, be);
- section.VSize = Get64(p + 0x28, be);
- section.Pa = Get32(p + 0x30, be);
- section.Flags = Get32(p + 0x40, be);
+ if (t == CPU_SUBTYPE_POWERPC_970)
+ n = "970";
+ else if (t < ARRAY_SIZE(k_PowerPc_SubTypes))
+ n = k_PowerPc_SubTypes[t];
}
- else
+ if (!n)
{
- section.Va = Get32(p + 0x20, be);
- section.VSize = Get32(p + 0x24, be);
- section.Pa = Get32(p + 0x28, be);
- section.Flags = Get32(p + 0x38, be);
+ ConvertUInt32ToString(t, temp);
+ n = temp;
}
- if (section.Flags == MACH_SECT_ATTR_ZEROFILL)
- section.PSize = 0;
- else
- section.PSize = section.VSize;
- memcpy(section.Name, p, kNameSize);
- memcpy(section.SegName, p + kNameSize, kNameSize);
- section.SegmentIndex = _segments.Size() - 1;
- _sections.Add(section);
- offs += headerSize;
+ s += ' ';
+ s += n;
}
- while (--numSections);
-
- if (offs != cmdSize)
- return false;
+ prop = s;
+ break;
+ }
+ case kpidCharacts:
+ {
+ // TYPE_TO_PROP(g_FileTypes, _type, prop); break;
+ AString res = TypeToString(g_FileTypes, ARRAY_SIZE(g_FileTypes), _type);
+ AString s = FlagsToString(g_ArcFlags, ARRAY_SIZE(g_ArcFlags), _flags);
+ if (!s.IsEmpty())
+ {
+ res += ' ';
+ res += s;
+ }
+ prop = res;
+ break;
}
- buf += cmdSize;
- size -= cmdSize;
- }
- _headersSize = (UInt32)(buf - bufStart);
- return reduceCommands || (size == 0);
-}
-
-static STATPROPSTG kArcProps[] =
-{
- { NULL, kpidCpu, VT_BSTR},
- { NULL, kpidBit64, VT_BOOL},
- { NULL, kpidBigEndian, VT_BOOL},
- { NULL, kpidCharacts, VT_BSTR},
- { NULL, kpidPhySize, VT_UI8},
- { NULL, kpidHeadersSize, VT_UI4}
-};
-
-static STATPROPSTG kProps[] =
-{
- { NULL, kpidPath, VT_BSTR},
- { NULL, kpidSize, VT_UI8},
- { NULL, kpidPackSize, VT_UI8},
- { 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 kpidCpu: PAIR_TO_PROP(g_MachinePairs, _machine, prop); break;
- case kpidCharacts: TYPE_TO_PROP(g_FileTypes, _type, prop); break;
case kpidPhySize: prop = _totalSize; break;
case kpidHeadersSize: prop = _headersSize; break;
case kpidBit64: if (_mode64) prop = _mode64; break;
case kpidBigEndian: if (_be) prop = _be; break;
+ case kpidExtension:
+ {
+ const char *ext = NULL;
+ if (_type == kType_OBJECT)
+ ext = "o";
+ else if (_type == kType_BUNDLE)
+ ext = "bundle";
+ else if (_type == kType_DYLIB)
+ ext = "dylib"; // main shared library usually does not have extension
+ if (ext)
+ prop = ext;
+ break;
+ }
+ // case kpidIsSelfExe: prop = (_type == kType_EXECUTE); break;
}
prop.Detach(value);
return S_OK;
@@ -340,10 +350,8 @@ static AString GetName(const char *name)
static AString SectFlagsToString(UInt32 flags)
{
- AString res = TypeToString(g_SectTypes, sizeof(g_SectTypes) / sizeof(g_SectTypes[0]),
- flags & MACH_SECT_TYPE_MASK);
- AString s = FlagsToString(g_Flags, sizeof(g_Flags) / sizeof(g_Flags[0]),
- flags & MACH_SECT_ATTR_MASK);
+ AString res = TypeToString(g_SectTypes, ARRAY_SIZE(g_SectTypes), flags & SECT_TYPE_MASK);
+ AString s = FlagsToString(g_Flags, ARRAY_SIZE(g_Flags), flags & SECT_ATTR_MASK);
if (!s.IsEmpty())
{
res += ' ';
@@ -355,21 +363,21 @@ static AString SectFlagsToString(UInt32 flags)
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
- NCOM::CPropVariant prop;
+ CPropVariant prop;
const CSection &item = _sections[index];
- switch(propID)
+ switch (propID)
{
case kpidPath:
{
AString s = GetName(_segments[item.SegmentIndex].Name);
if (!item.IsDummy)
s += GetName(item.Name);
- StringToProp(s, prop);
+ prop = MultiByteToUnicodeString(s);
break;
}
case kpidSize: /* prop = (UInt64)item.VSize; break; */
case kpidPackSize: prop = (UInt64)item.GetPackSize(); break;
- case kpidCharacts: if (!item.IsDummy) StringToProp(SectFlagsToString(item.Flags), prop); break;
+ case kpidCharacts: if (!item.IsDummy) prop = SectFlagsToString(item.Flags); break;
case kpidOffset: prop = item.Pa; break;
case kpidVa: prop = item.Va; break;
}
@@ -380,18 +388,12 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
HRESULT CHandler::Open2(ISequentialInStream *stream)
{
- const UInt32 kBufSize = 1 << 18;
- const UInt32 kSigSize = 4;
+ const UInt32 kStartHeaderSize = 7 * 4;
- CByteBuffer buffer;
- buffer.SetCapacity(kBufSize);
- Byte *buf = buffer;
-
- size_t processed = kSigSize;
- RINOK(ReadStream_FALSE(stream, buf, processed));
- UInt32 sig = GetUi32(buf);
+ Byte header[kStartHeaderSize];
+ RINOK(ReadStream_FALSE(stream, header, kStartHeaderSize));
bool be, mode64;
- switch(sig)
+ switch (GetUi32(header))
{
case 0xCEFAEDFE: be = true; mode64 = false; break;
case 0xCFFAEDFE: be = true; mode64 = true; break;
@@ -399,11 +401,148 @@ HRESULT CHandler::Open2(ISequentialInStream *stream)
case 0xFEEDFACF: be = false; mode64 = true; break;
default: return S_FALSE;
}
- processed = kBufSize - kSigSize;
- RINOK(ReadStream(stream, buf + kSigSize, &processed));
- _mode64 = mode64;
- _be = be;
- return Parse(buf, (UInt32)processed + kSigSize) ? S_OK : S_FALSE;
+
+ UInt32 numCommands = Get32(header + 0x10, be);
+ UInt32 commandsSize = Get32(header + 0x14, be);
+
+ if (numCommands == 0)
+ return S_FALSE;
+
+ if (commandsSize > (1 << 24) ||
+ numCommands > (1 << 21) ||
+ numCommands * 8 > commandsSize)
+ return S_FALSE;
+
+ _cpuType = Get32(header + 4, be);
+ _cpuSubType = Get32(header + 8, be);
+ _type = Get32(header + 0xC, be);
+ _flags = Get32(header + 0x18, be);
+
+ /*
+ // Probably the sections are in first commands. So we can reduce the number of commands.
+ bool reduceCommands = false;
+ const UInt32 kNumReduceCommands = 16;
+ if (numCommands > kNumReduceCommands)
+ {
+ reduceCommands = true;
+ numCommands = kNumReduceCommands;
+ }
+ */
+
+ UInt32 startHeaderSize = kStartHeaderSize;
+ if (mode64)
+ startHeaderSize += 4;
+ _headersSize = startHeaderSize + commandsSize;
+ _totalSize = _headersSize;
+ CByteArr buffer(_headersSize);
+ RINOK(ReadStream_FALSE(stream, buffer + kStartHeaderSize, _headersSize - kStartHeaderSize));
+ const Byte *buf = buffer + startHeaderSize;
+ size_t size = _headersSize - startHeaderSize;
+ for (UInt32 cmdIndex = 0; cmdIndex < numCommands; cmdIndex++)
+ {
+ if (size < 8)
+ return S_FALSE;
+ UInt32 cmd = Get32(buf, be);
+ UInt32 cmdSize = Get32(buf + 4, be);
+ if (cmdSize < 8)
+ return S_FALSE;
+ if (size < cmdSize)
+ return S_FALSE;
+ if (cmd == CMD_SEGMENT_32 || cmd == CMD_SEGMENT_64)
+ {
+ UInt32 offs = (cmd == CMD_SEGMENT_64) ? 0x48 : 0x38;
+ if (cmdSize < offs)
+ break;
+
+ UInt64 vmAddr, vmSize, phAddr, phSize;
+
+ {
+ if (cmd == CMD_SEGMENT_64)
+ {
+ vmAddr = Get64(buf + 0x18, be);
+ vmSize = Get64(buf + 0x20, be);
+ phAddr = Get64(buf + 0x28, be);
+ phSize = Get64(buf + 0x30, be);
+ }
+ else
+ {
+ vmAddr = Get32(buf + 0x18, be);
+ vmSize = Get32(buf + 0x1C, be);
+ phAddr = Get32(buf + 0x20, be);
+ phSize = Get32(buf + 0x24, be);
+ }
+ {
+ UInt64 totalSize = phAddr + phSize;
+ if (totalSize < phAddr)
+ return S_FALSE;
+ if (_totalSize < totalSize)
+ _totalSize = totalSize;
+ }
+ }
+
+ CSegment seg;
+ memcpy(seg.Name, buf + 8, kNameSize);
+ _segments.Add(seg);
+
+ UInt32 numSections = Get32(buf + offs - 8, be);
+ if (numSections > (1 << 8))
+ return S_FALSE;
+
+ if (numSections == 0)
+ {
+ CSection &sect = _sections.AddNew();
+ sect.IsDummy = true;
+ sect.SegmentIndex = _segments.Size() - 1;
+ sect.Va = vmAddr;
+ sect.PSize = phSize;
+ sect.VSize = vmSize;
+ sect.Pa = phAddr;
+ sect.Flags = 0;
+ }
+ else do
+ {
+ UInt32 headSize = (cmd == CMD_SEGMENT_64) ? 0x50 : 0x44;
+ const Byte *p = buf + offs;
+ if (cmdSize - offs < headSize)
+ break;
+ CSection &sect = _sections.AddNew();
+ unsigned f32Offset;
+ if (cmd == CMD_SEGMENT_64)
+ {
+ sect.Va = Get64(p + 0x20, be);
+ sect.VSize = Get64(p + 0x28, be);
+ f32Offset = 0x30;
+ }
+ else
+ {
+ sect.Va = Get32(p + 0x20, be);
+ sect.VSize = Get32(p + 0x24, be);
+ f32Offset = 0x28;
+ }
+ sect.Pa = Get32(p + f32Offset, be);
+ sect.Flags = Get32(p + f32Offset + 10, be);
+ if (sect.Flags == SECT_ATTR_ZEROFILL)
+ sect.PSize = 0;
+ else
+ sect.PSize = sect.VSize;
+ memcpy(sect.Name, p, kNameSize);
+ memcpy(sect.SegName, p + kNameSize, kNameSize);
+ sect.SegmentIndex = _segments.Size() - 1;
+ offs += headSize;
+ }
+ while (--numSections);
+
+ if (offs != cmdSize)
+ return S_FALSE;
+ }
+ buf += cmdSize;
+ size -= cmdSize;
+ }
+ // return (reduceCommands || (size == 0)) ? S_OK : S_FALSE;
+ if (size != 0)
+ return S_FALSE;
+
+ return S_OK;
}
STDMETHODIMP CHandler::Open(IInStream *inStream,
@@ -413,6 +552,13 @@ STDMETHODIMP CHandler::Open(IInStream *inStream,
COM_TRY_BEGIN
Close();
RINOK(Open2(inStream));
+ if (!_allowTail)
+ {
+ UInt64 fileSize;
+ RINOK(inStream->Seek(0, STREAM_SEEK_END, &fileSize));
+ if (fileSize > _totalSize)
+ return S_FALSE;
+ }
_inStream = inStream;
return S_OK;
COM_TRY_END
@@ -420,6 +566,7 @@ STDMETHODIMP CHandler::Open(IInStream *inStream,
STDMETHODIMP CHandler::Close()
{
+ _totalSize = 0;
_inStream.Release();
_sections.Clear();
_segments.Clear();
@@ -436,7 +583,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Int32 testMode, IArchiveExtractCallback *extractCallback)
{
COM_TRY_BEGIN
- bool allFilesMode = (numItems == (UInt32)-1);
+ bool allFilesMode = (numItems == (UInt32)(Int32)-1);
if (allFilesMode)
numItems = _sections.Size();
if (numItems == 0)
@@ -490,10 +637,27 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
COM_TRY_END
}
-static IInArchive *CreateArc() { return new CHandler; }
+STDMETHODIMP CHandler::AllowTail(Int32 allowTail)
+{
+ _allowTail = IntToBool(allowTail);
+ return S_OK;
+}
+
+IMP_CreateArcIn
+
+#define k_Signature { \
+ 4, 0xCE, 0xFA, 0xED, 0xFE, \
+ 4, 0xCF, 0xFA, 0xED, 0xFE, \
+ 4, 0xFE, 0xED, 0xFA, 0xCE, \
+ 4, 0xFE, 0xED, 0xFA, 0xCF }
static CArcInfo g_ArcInfo =
- { L"MachO", L"", 0, 0xDF, { 0 }, 0, false, CreateArc, 0 };
+ { "MachO", "macho", 0, 0xDF,
+ 4 * 5, k_Signature,
+ 0,
+ NArcInfoFlags::kMultiSignature |
+ NArcInfoFlags::kPreArc,
+ CreateArc };
REGISTER_ARC(Macho)