mirror of
https://github.com/Xevion/easy7zip.git
synced 2025-12-06 07:14:55 -06:00
745 lines
18 KiB
C++
Executable File
745 lines
18 KiB
C++
Executable File
// MachoHandler.cpp
|
|
|
|
#include "StdAfx.h"
|
|
|
|
#include "../../../C/CpuArch.h"
|
|
|
|
#include "../../Common/ComTry.h"
|
|
#include "../../Common/MyBuffer.h"
|
|
#include "../../Common/StringConvert.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"
|
|
|
|
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 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 CPU_SUBTYPE_I386_ALL 3
|
|
|
|
// #define CPU_TYPE_PPC64 (CPU_ARCH_ABI64 | CPU_TYPE_PPC)
|
|
#define CPU_TYPE_AMD64 (CPU_ARCH_ABI64 | CPU_TYPE_386)
|
|
#define CPU_TYPE_ARM64 (CPU_ARCH_ABI64 | CPU_TYPE_ARM)
|
|
|
|
#define CPU_SUBTYPE_LIB64 ((UInt32)1 << 31)
|
|
|
|
#define CPU_SUBTYPE_POWERPC_970 100
|
|
|
|
static const char * const k_PowerPc_SubTypes[] =
|
|
{
|
|
NULL
|
|
, "601"
|
|
, "602"
|
|
, "603"
|
|
, "603e"
|
|
, "603ev"
|
|
, "604"
|
|
, "604e"
|
|
, "620"
|
|
, "750"
|
|
, "7400"
|
|
, "7450"
|
|
};
|
|
|
|
static const CUInt32PCharPair g_CpuPairs[] =
|
|
{
|
|
{ CPU_TYPE_AMD64, "x64" },
|
|
{ CPU_TYPE_ARM64, "ARM64" },
|
|
{ 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 * const 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"
|
|
, "DTRACE_DOF"
|
|
, "LAZY_DYLIB_SYMBOL_POINTERS"
|
|
, "THREAD_LOCAL_REGULAR"
|
|
, "THREAD_LOCAL_ZEROFILL"
|
|
, "THREAD_LOCAL_VARIABLES"
|
|
, "THREAD_LOCAL_VARIABLE_POINTERS"
|
|
, "THREAD_LOCAL_INIT_FUNCTION_POINTERS"
|
|
};
|
|
|
|
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 * const g_FileTypes[] =
|
|
{
|
|
"0"
|
|
, "OBJECT"
|
|
, "EXECUTE"
|
|
, "FVMLIB"
|
|
, "CORE"
|
|
, "PRELOAD"
|
|
, "DYLIB"
|
|
, "DYLINKER"
|
|
, "BUNDLE"
|
|
, "DYLIB_STUB"
|
|
, "DSYM"
|
|
};
|
|
|
|
|
|
static const char * const 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_SectFlags[] =
|
|
{
|
|
{ 31, "PURE_INSTRUCTIONS" },
|
|
{ 30, "NO_TOC" },
|
|
{ 29, "STRIP_STATIC_SYMS" },
|
|
{ 28, "NO_DEAD_STRIP" },
|
|
{ 27, "LIVE_SUPPORT" },
|
|
{ 26, "SELF_MODIFYING_CODE" },
|
|
{ 25, "DEBUG" },
|
|
{ 10, "SOME_INSTRUCTIONS" },
|
|
{ 9, "EXT_RELOC" },
|
|
{ 8, "LOC_RELOC" }
|
|
};
|
|
|
|
|
|
// VM_PROT_*
|
|
static const char * const g_SegmentProt[] =
|
|
{
|
|
"READ"
|
|
, "WRITE"
|
|
, "EXECUTE"
|
|
/*
|
|
, "NO_CHANGE"
|
|
, "COPY"
|
|
, "TRUSTED"
|
|
, "IS_MASK"
|
|
*/
|
|
};
|
|
|
|
// SG_*
|
|
|
|
static const char * const g_SegmentFlags[] =
|
|
{
|
|
"SG_HIGHVM"
|
|
, "SG_FVMLIB"
|
|
, "SG_NORELOC"
|
|
, "SG_PROTECTED_VERSION_1"
|
|
, "SG_READ_ONLY"
|
|
};
|
|
|
|
static const unsigned kNameSize = 16;
|
|
|
|
struct CSegment
|
|
{
|
|
char Name[kNameSize];
|
|
UInt32 MaxProt;
|
|
UInt32 InitProt;
|
|
UInt32 Flags;
|
|
};
|
|
|
|
struct CSection
|
|
{
|
|
char Name[kNameSize];
|
|
// char SegName[kNameSize];
|
|
UInt64 Va;
|
|
UInt64 Pa;
|
|
UInt64 VSize;
|
|
UInt64 PSize;
|
|
|
|
UInt32 Align;
|
|
UInt32 Flags;
|
|
unsigned SegmentIndex;
|
|
bool IsDummy;
|
|
|
|
CSection(): IsDummy(false) {}
|
|
// UInt64 GetPackSize() const { return Flags == SECT_ATTR_ZEROFILL ? 0 : Size; }
|
|
UInt64 GetPackSize() const { return PSize; }
|
|
};
|
|
|
|
|
|
Z7_CLASS_IMP_CHandler_IInArchive_1(
|
|
IArchiveAllowTail
|
|
)
|
|
CMyComPtr<IInStream> _inStream;
|
|
CObjectVector<CSegment> _segments;
|
|
CObjectVector<CSection> _sections;
|
|
bool _allowTail;
|
|
bool _mode64;
|
|
bool _be;
|
|
UInt32 _cpuType;
|
|
UInt32 _cpuSubType;
|
|
UInt32 _type;
|
|
UInt32 _flags;
|
|
UInt32 _headersSize;
|
|
UInt64 _totalSize;
|
|
|
|
HRESULT Open2(ISequentialInStream *stream);
|
|
public:
|
|
CHandler(): _allowTail(false) {}
|
|
};
|
|
|
|
static const Byte kArcProps[] =
|
|
{
|
|
kpidCpu,
|
|
kpidBit64,
|
|
kpidBigEndian,
|
|
kpidCharacts,
|
|
kpidHeadersSize
|
|
};
|
|
|
|
static const Byte kProps[] =
|
|
{
|
|
kpidPath,
|
|
kpidSize,
|
|
kpidPackSize,
|
|
kpidCharacts,
|
|
kpidOffset,
|
|
kpidVa,
|
|
kpidClusterSize // Align
|
|
};
|
|
|
|
IMP_IInArchive_Props
|
|
IMP_IInArchive_ArcProps
|
|
|
|
Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
|
|
{
|
|
COM_TRY_BEGIN
|
|
CPropVariant prop;
|
|
switch (propID)
|
|
{
|
|
case kpidShortComment:
|
|
case kpidCpu:
|
|
{
|
|
AString s;
|
|
const UInt32 cpu = _cpuType & ~(UInt32)CPU_ARCH_ABI64;
|
|
UInt32 flag64 = _cpuType & (UInt32)CPU_ARCH_ABI64;
|
|
{
|
|
s.Add_UInt32(cpu);
|
|
for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_CpuPairs); i++)
|
|
{
|
|
const CUInt32PCharPair &pair = g_CpuPairs[i];
|
|
if (pair.Value == cpu || pair.Value == _cpuType)
|
|
{
|
|
if (pair.Value == _cpuType)
|
|
flag64 = 0;
|
|
s = pair.Name;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (flag64 != 0)
|
|
s.Add_OptSpaced("64-bit");
|
|
else if ((_cpuSubType & CPU_SUBTYPE_LIB64) && _cpuType != CPU_TYPE_AMD64)
|
|
s.Add_OptSpaced("64-bit-lib");
|
|
}
|
|
const UInt32 t = _cpuSubType & ~(UInt32)CPU_SUBTYPE_LIB64;
|
|
if (t != 0 && (t != CPU_SUBTYPE_I386_ALL || cpu != CPU_TYPE_386))
|
|
{
|
|
const char *n = NULL;
|
|
if (cpu == CPU_TYPE_PPC)
|
|
{
|
|
if (t == CPU_SUBTYPE_POWERPC_970)
|
|
n = "970";
|
|
else if (t < Z7_ARRAY_SIZE(k_PowerPc_SubTypes))
|
|
n = k_PowerPc_SubTypes[t];
|
|
}
|
|
s.Add_Space();
|
|
if (n)
|
|
s += n;
|
|
else
|
|
s.Add_UInt32(t);
|
|
}
|
|
prop = s;
|
|
break;
|
|
}
|
|
case kpidCharacts:
|
|
{
|
|
// TYPE_TO_PROP(g_FileTypes, _type, prop); break;
|
|
AString res (TypeToString(g_FileTypes, Z7_ARRAY_SIZE(g_FileTypes), _type));
|
|
const AString s (FlagsToString(g_ArcFlags, Z7_ARRAY_SIZE(g_ArcFlags), _flags));
|
|
if (!s.IsEmpty())
|
|
{
|
|
res.Add_Space();
|
|
res += s;
|
|
}
|
|
prop = res;
|
|
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;
|
|
COM_TRY_END
|
|
}
|
|
|
|
static void AddName(AString &s, const char *name)
|
|
{
|
|
char temp[kNameSize + 1];
|
|
memcpy(temp, name, kNameSize);
|
|
temp[kNameSize] = 0;
|
|
s += temp;
|
|
}
|
|
|
|
|
|
Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
|
|
{
|
|
COM_TRY_BEGIN
|
|
CPropVariant prop;
|
|
const CSection &item = _sections[index];
|
|
switch (propID)
|
|
{
|
|
case kpidPath:
|
|
{
|
|
AString s;
|
|
AddName(s, _segments[item.SegmentIndex].Name);
|
|
if (!item.IsDummy)
|
|
{
|
|
// CSection::SegName and CSegment::Name are same in real cases.
|
|
// AddName(s, item.SegName);
|
|
AddName(s, item.Name);
|
|
}
|
|
prop = MultiByteToUnicodeString(s);
|
|
break;
|
|
}
|
|
case kpidSize: /* prop = (UInt64)item.VSize; break; */
|
|
case kpidPackSize: prop = (UInt64)item.GetPackSize(); break;
|
|
case kpidCharacts:
|
|
{
|
|
AString res;
|
|
{
|
|
if (!item.IsDummy)
|
|
{
|
|
{
|
|
const AString s (TypeToString(g_SectTypes, Z7_ARRAY_SIZE(g_SectTypes), item.Flags & SECT_TYPE_MASK));
|
|
if (!s.IsEmpty())
|
|
{
|
|
res.Add_OptSpaced("sect_type:");
|
|
res.Add_OptSpaced(s);
|
|
}
|
|
}
|
|
{
|
|
const AString s (FlagsToString(g_SectFlags, Z7_ARRAY_SIZE(g_SectFlags), item.Flags & SECT_ATTR_MASK));
|
|
if (!s.IsEmpty())
|
|
{
|
|
res.Add_OptSpaced("sect_flags:");
|
|
res.Add_OptSpaced(s);
|
|
}
|
|
}
|
|
}
|
|
const CSegment &seg = _segments[item.SegmentIndex];
|
|
{
|
|
const AString s (FlagsToString(g_SegmentFlags, Z7_ARRAY_SIZE(g_SegmentFlags), seg.Flags));
|
|
if (!s.IsEmpty())
|
|
{
|
|
res.Add_OptSpaced("seg_flags:");
|
|
res.Add_OptSpaced(s);
|
|
}
|
|
}
|
|
{
|
|
const AString s (FlagsToString(g_SegmentProt, Z7_ARRAY_SIZE(g_SegmentProt), seg.MaxProt));
|
|
if (!s.IsEmpty())
|
|
{
|
|
res.Add_OptSpaced("max_prot:");
|
|
res.Add_OptSpaced(s);
|
|
}
|
|
}
|
|
{
|
|
const AString s (FlagsToString(g_SegmentProt, Z7_ARRAY_SIZE(g_SegmentProt), seg.InitProt));
|
|
if (!s.IsEmpty())
|
|
{
|
|
res.Add_OptSpaced("init_prot:");
|
|
res.Add_OptSpaced(s);
|
|
}
|
|
}
|
|
}
|
|
if (!res.IsEmpty())
|
|
prop = res;
|
|
break;
|
|
}
|
|
case kpidOffset: prop = item.Pa; break;
|
|
case kpidVa: prop = item.Va; break;
|
|
case kpidClusterSize: prop = (UInt32)1 << item.Align; break;
|
|
}
|
|
prop.Detach(value);
|
|
return S_OK;
|
|
COM_TRY_END
|
|
}
|
|
|
|
|
|
HRESULT CHandler::Open2(ISequentialInStream *stream)
|
|
{
|
|
const UInt32 kStartHeaderSize = 7 * 4;
|
|
|
|
Byte header[kStartHeaderSize];
|
|
RINOK(ReadStream_FALSE(stream, header, kStartHeaderSize))
|
|
bool be, mode64;
|
|
switch (GetUi32(header))
|
|
{
|
|
case 0xCEFAEDFE: be = true; mode64 = false; break;
|
|
case 0xCFFAEDFE: be = true; mode64 = true; break;
|
|
case 0xFEEDFACE: be = false; mode64 = false; break;
|
|
case 0xFEEDFACF: be = false; mode64 = true; break;
|
|
default: return S_FALSE;
|
|
}
|
|
|
|
_mode64 = mode64;
|
|
_be = be;
|
|
|
|
const UInt32 numCommands = Get32(header + 0x10, be);
|
|
const 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;
|
|
seg.MaxProt = Get32(buf + offs - 16, be);
|
|
seg.InitProt = Get32(buf + offs - 12, be);
|
|
seg.Flags = Get32(buf + offs - 4, be);
|
|
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.Align = 0;
|
|
sect.Flags = 0;
|
|
}
|
|
else do
|
|
{
|
|
const 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.Align = Get32(p + f32Offset + 4, be);
|
|
// sect.reloff = Get32(p + f32Offset + 8, be);
|
|
// sect.nreloc = Get32(p + f32Offset + 12, be);
|
|
sect.Flags = Get32(p + f32Offset + 16, be);
|
|
if ((sect.Flags & SECT_TYPE_MASK) == 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;
|
|
}
|
|
|
|
Z7_COM7F_IMF(CHandler::Open(IInStream *inStream,
|
|
const UInt64 * /* maxCheckStartPosition */,
|
|
IArchiveOpenCallback * /* openArchiveCallback */))
|
|
{
|
|
COM_TRY_BEGIN
|
|
Close();
|
|
RINOK(Open2(inStream))
|
|
if (!_allowTail)
|
|
{
|
|
UInt64 fileSize;
|
|
RINOK(InStream_GetSize_SeekToEnd(inStream, fileSize))
|
|
if (fileSize > _totalSize)
|
|
return S_FALSE;
|
|
}
|
|
_inStream = inStream;
|
|
return S_OK;
|
|
COM_TRY_END
|
|
}
|
|
|
|
Z7_COM7F_IMF(CHandler::Close())
|
|
{
|
|
_totalSize = 0;
|
|
_inStream.Release();
|
|
_sections.Clear();
|
|
_segments.Clear();
|
|
return S_OK;
|
|
}
|
|
|
|
Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
|
|
{
|
|
*numItems = _sections.Size();
|
|
return S_OK;
|
|
}
|
|
|
|
Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
|
Int32 testMode, IArchiveExtractCallback *extractCallback))
|
|
{
|
|
COM_TRY_BEGIN
|
|
const bool allFilesMode = (numItems == (UInt32)(Int32)-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]].GetPackSize();
|
|
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);
|
|
|
|
for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
|
|
{
|
|
lps->InSize = lps->OutSize = currentTotalSize;
|
|
RINOK(lps->SetCur())
|
|
const Int32 askMode = testMode ?
|
|
NExtract::NAskMode::kTest :
|
|
NExtract::NAskMode::kExtract;
|
|
const UInt32 index = allFilesMode ? i : indices[i];
|
|
const CSection &item = _sections[index];
|
|
currentItemSize = item.GetPackSize();
|
|
|
|
CMyComPtr<ISequentialOutStream> outStream;
|
|
RINOK(extractCallback->GetStream(index, &outStream, askMode))
|
|
if (!testMode && !outStream)
|
|
continue;
|
|
|
|
RINOK(extractCallback->PrepareOperation(askMode))
|
|
RINOK(InStream_SeekSet(_inStream, item.Pa))
|
|
streamSpec->Init(currentItemSize);
|
|
RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress))
|
|
outStream.Release();
|
|
RINOK(extractCallback->SetOperationResult(copyCoderSpec->TotalSize == currentItemSize ?
|
|
NExtract::NOperationResult::kOK:
|
|
NExtract::NOperationResult::kDataError))
|
|
}
|
|
return S_OK;
|
|
COM_TRY_END
|
|
}
|
|
|
|
Z7_COM7F_IMF(CHandler::AllowTail(Int32 allowTail))
|
|
{
|
|
_allowTail = IntToBool(allowTail);
|
|
return S_OK;
|
|
}
|
|
|
|
static const Byte k_Signature[] = {
|
|
4, 0xCE, 0xFA, 0xED, 0xFE,
|
|
4, 0xCF, 0xFA, 0xED, 0xFE,
|
|
4, 0xFE, 0xED, 0xFA, 0xCE,
|
|
4, 0xFE, 0xED, 0xFA, 0xCF };
|
|
|
|
REGISTER_ARC_I(
|
|
"MachO", "macho", NULL, 0xDF,
|
|
k_Signature,
|
|
0,
|
|
NArcInfoFlags::kMultiSignature |
|
|
NArcInfoFlags::kPreArc,
|
|
NULL)
|
|
|
|
}}
|