diff options
author | Igor Pavlov <ipavlov@users.sourceforge.net> | 2014-11-23 03:00:00 +0300 |
---|---|---|
committer | Kornel LesiĆski <kornel@geekhood.net> | 2016-05-28 02:16:51 +0300 |
commit | f08f4dcc3c02464c17753b3feafcfe5243b9e236 (patch) | |
tree | b0e1b15bc5368d92dff422e8ec0818564a2b00b8 /CPP/7zip/Archive/MachoHandler.cpp | |
parent | 83f8ddcc5b2161e1e3c49666265257fca8aeb12c (diff) |
9.349.34
Diffstat (limited to 'CPP/7zip/Archive/MachoHandler.cpp')
-rw-r--r--[-rwxr-xr-x] | CPP/7zip/Archive/MachoHandler.cpp | 640 |
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 § = _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 § = _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) |