5
#include "../../../C/CpuArch.h"
7
#include "Common/ComTry.h"
9
#include "Windows/PropVariant.h"
11
#include "../Common/LimitedStreams.h"
12
#include "../Common/ProgressUtils.h"
13
#include "../Common/RegisterArc.h"
14
#include "../Common/StreamUtils.h"
16
#include "../Compress/CopyCoder.h"
18
#define Get32(p) GetBe32(p)
33
const UInt32 kNumFilesMax = 10;
40
CMyComPtr<IInStream> _inStream;
42
CItem _items[kNumFilesMax + 1];
43
HRESULT Open2(IInStream *stream);
45
MY_UNKNOWN_IMP1(IInArchive)
46
INTERFACE_IInArchive(;)
49
STATPROPSTG kProps[] =
51
{ NULL, kpidSize, VT_UI8},
52
{ NULL, kpidPackSize, VT_UI8}
56
IMP_IInArchive_ArcProps_NO
58
#define MACH_ARCH_ABI64 0x1000000
59
#define MACH_MACHINE_386 7
60
#define MACH_MACHINE_ARM 12
61
#define MACH_MACHINE_SPARC 14
62
#define MACH_MACHINE_PPC 18
64
#define MACH_MACHINE_PPC64 (MACH_MACHINE_PPC | MACH_ARCH_ABI64)
65
#define MACH_MACHINE_AMD64 (MACH_MACHINE_386 | MACH_ARCH_ABI64)
67
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
69
NWindows::NCOM::CPropVariant prop;
70
const CItem &item = _items[index];
82
case MACH_MACHINE_386: ext = L"86"; break;
83
case MACH_MACHINE_ARM: ext = L"arm"; break;
84
case MACH_MACHINE_SPARC: ext = L"sparc"; break;
85
case MACH_MACHINE_PPC: ext = L"ppc"; break;
86
case MACH_MACHINE_PPC64: ext = L"ppc64"; break;
87
case MACH_MACHINE_AMD64: ext = L"x64"; break;
88
default: ext = L"unknown"; break;
96
prop = (UInt64)item.Size;
103
#define MACH_TYPE_ABI64 (1 << 24)
104
#define MACH_SUBTYPE_ABI64 (1 << 31)
106
HRESULT CHandler::Open2(IInStream *stream)
108
RINOK(stream->Seek(0, STREAM_SEEK_SET, &_startPos));
110
const UInt32 kHeaderSize = 8;
111
const UInt32 kRecordSize = 5 * 4;
112
const UInt32 kBufSize = kHeaderSize + kNumFilesMax * kRecordSize;
114
size_t processed = kBufSize;
115
RINOK(ReadStream(stream, buf, &processed));
116
if (processed < kHeaderSize)
118
UInt32 num = Get32(buf + 4);
119
if (Get32(buf) != 0xCAFEBABE || num > kNumFilesMax || processed < kHeaderSize + num * kRecordSize)
121
UInt64 endPosMax = kHeaderSize;
122
for (UInt32 i = 0; i < num; i++)
124
const Byte *p = buf + kHeaderSize + i * kRecordSize;
125
CItem &sb = _items[i];
128
sb.SubType = Get32(p + 4);
129
sb.Offset = Get32(p + 8);
130
sb.Size = Get32(p + 12);
131
sb.Align = Get32(p + 16);
133
if ((sb.Type & ~MACH_TYPE_ABI64) >= 0x100 ||
134
(sb.SubType & ~MACH_SUBTYPE_ABI64) >= 0x100 ||
138
UInt64 endPos = (UInt64)sb.Offset + sb.Size;
139
if (endPos > endPosMax)
143
RINOK(stream->Seek(0, STREAM_SEEK_END, &fileSize));
144
fileSize -= _startPos;
146
if (fileSize > endPosMax)
148
CItem &sb = _items[_numItems++];
152
sb.Offset = endPosMax;
153
sb.Size = fileSize - endPosMax;
159
STDMETHODIMP CHandler::Open(IInStream *inStream,
160
const UInt64 * /* maxCheckStartPosition */,
161
IArchiveOpenCallback * /* openArchiveCallback */)
167
if (Open2(inStream) != S_OK)
169
_inStream = inStream;
171
catch(...) { return S_FALSE; }
176
STDMETHODIMP CHandler::Close()
183
STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
185
*numItems = _numItems;
189
STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
190
Int32 _aTestMode, IArchiveExtractCallback *extractCallback)
193
bool testMode = (_aTestMode != 0);
194
bool allFilesMode = (numItems == UInt32(-1));
196
numItems = _numItems;
199
UInt64 totalSize = 0;
201
for (i = 0; i < numItems; i++)
202
totalSize += _items[allFilesMode ? i : indices[i]].Size;
203
extractCallback->SetTotal(totalSize);
205
UInt64 currentTotalSize = 0;
206
UInt64 currentItemSize;
208
NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
209
CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
211
CLocalProgress *lps = new CLocalProgress;
212
CMyComPtr<ICompressProgressInfo> progress = lps;
213
lps->Init(extractCallback, false);
215
CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
216
CMyComPtr<ISequentialInStream> inStream(streamSpec);
217
streamSpec->SetStream(_inStream);
219
for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
221
lps->InSize = lps->OutSize = currentTotalSize;
222
RINOK(lps->SetCur());
223
CMyComPtr<ISequentialOutStream> realOutStream;
224
Int32 askMode = testMode ?
225
NArchive::NExtract::NAskMode::kTest :
226
NArchive::NExtract::NAskMode::kExtract;
227
UInt32 index = allFilesMode ? i : indices[i];
228
const CItem &item = _items[index];
229
RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
230
currentItemSize = item.Size;
237
if (!testMode && (!realOutStream))
239
RINOK(extractCallback->PrepareOperation(askMode));
242
RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK));
245
RINOK(_inStream->Seek(_startPos + item.Offset, STREAM_SEEK_SET, NULL));
246
streamSpec->Init(item.Size);
247
RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress));
248
realOutStream.Release();
249
RINOK(extractCallback->SetOperationResult((copyCoderSpec->TotalSize == item.Size) ?
250
NArchive::NExtract::NOperationResult::kOK:
251
NArchive::NExtract::NOperationResult::kDataError));
257
static IInArchive *CreateArc() { return new CHandler; }
259
static CArcInfo g_ArcInfo =
260
{ L"Mub", L"", 0, 0xE2, { 0xCA, 0xFE, 0xBA, 0xBE, 0, 0, 0 }, 7, false, CreateArc, 0 };