5 #include "../../../C/CpuArch.h"
\r
7 #include "Common/ComTry.h"
\r
9 #include "Windows/PropVariant.h"
\r
11 #include "../Common/LimitedStreams.h"
\r
12 #include "../Common/ProgressUtils.h"
\r
13 #include "../Common/RegisterArc.h"
\r
14 #include "../Common/StreamUtils.h"
\r
16 #include "../Compress/CopyCoder.h"
\r
18 #define Get32(p) GetBe32(p)
\r
20 namespace NArchive {
\r
33 const UInt32 kNumFilesMax = 10;
\r
37 public IInArchiveGetStream,
\r
38 public CMyUnknownImp
\r
41 CMyComPtr<IInStream> _stream;
\r
43 CItem _items[kNumFilesMax + 1];
\r
44 HRESULT Open2(IInStream *stream);
\r
46 MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
\r
47 INTERFACE_IInArchive(;)
\r
48 STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
\r
51 STATPROPSTG kProps[] =
\r
53 { NULL, kpidSize, VT_UI8}
\r
56 IMP_IInArchive_Props
\r
57 IMP_IInArchive_ArcProps_NO
\r
59 #define MACH_ARCH_ABI64 0x1000000
\r
60 #define MACH_MACHINE_386 7
\r
61 #define MACH_MACHINE_ARM 12
\r
62 #define MACH_MACHINE_SPARC 14
\r
63 #define MACH_MACHINE_PPC 18
\r
65 #define MACH_MACHINE_PPC64 (MACH_MACHINE_PPC | MACH_ARCH_ABI64)
\r
66 #define MACH_MACHINE_AMD64 (MACH_MACHINE_386 | MACH_ARCH_ABI64)
\r
68 STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
\r
70 NWindows::NCOM::CPropVariant prop;
\r
71 const CItem &item = _items[index];
\r
83 case MACH_MACHINE_386: ext = L"86"; break;
\r
84 case MACH_MACHINE_ARM: ext = L"arm"; break;
\r
85 case MACH_MACHINE_SPARC: ext = L"sparc"; break;
\r
86 case MACH_MACHINE_PPC: ext = L"ppc"; break;
\r
87 case MACH_MACHINE_PPC64: ext = L"ppc64"; break;
\r
88 case MACH_MACHINE_AMD64: ext = L"x64"; break;
\r
89 default: ext = L"unknown"; break;
\r
97 prop = (UInt64)item.Size;
\r
100 prop.Detach(value);
\r
104 #define MACH_TYPE_ABI64 (1 << 24)
\r
105 #define MACH_SUBTYPE_ABI64 (1 << 31)
\r
107 HRESULT CHandler::Open2(IInStream *stream)
\r
109 RINOK(stream->Seek(0, STREAM_SEEK_SET, &_startPos));
\r
111 const UInt32 kHeaderSize = 8;
\r
112 const UInt32 kRecordSize = 5 * 4;
\r
113 const UInt32 kBufSize = kHeaderSize + kNumFilesMax * kRecordSize;
\r
114 Byte buf[kBufSize];
\r
115 size_t processed = kBufSize;
\r
116 RINOK(ReadStream(stream, buf, &processed));
\r
117 if (processed < kHeaderSize)
\r
119 UInt32 num = Get32(buf + 4);
\r
120 if (Get32(buf) != 0xCAFEBABE || num > kNumFilesMax || processed < kHeaderSize + num * kRecordSize)
\r
122 UInt64 endPosMax = kHeaderSize;
\r
123 for (UInt32 i = 0; i < num; i++)
\r
125 const Byte *p = buf + kHeaderSize + i * kRecordSize;
\r
126 CItem &sb = _items[i];
\r
128 sb.Type = Get32(p);
\r
129 sb.SubType = Get32(p + 4);
\r
130 sb.Offset = Get32(p + 8);
\r
131 sb.Size = Get32(p + 12);
\r
132 sb.Align = Get32(p + 16);
\r
134 if ((sb.Type & ~MACH_TYPE_ABI64) >= 0x100 ||
\r
135 (sb.SubType & ~MACH_SUBTYPE_ABI64) >= 0x100 ||
\r
139 UInt64 endPos = (UInt64)sb.Offset + sb.Size;
\r
140 if (endPos > endPosMax)
\r
141 endPosMax = endPos;
\r
144 RINOK(stream->Seek(0, STREAM_SEEK_END, &fileSize));
\r
145 fileSize -= _startPos;
\r
147 if (fileSize > endPosMax)
\r
149 CItem &sb = _items[_numItems++];
\r
153 sb.Offset = endPosMax;
\r
154 sb.Size = fileSize - endPosMax;
\r
160 STDMETHODIMP CHandler::Open(IInStream *inStream,
\r
161 const UInt64 * /* maxCheckStartPosition */,
\r
162 IArchiveOpenCallback * /* openArchiveCallback */)
\r
168 if (Open2(inStream) != S_OK)
\r
170 _stream = inStream;
\r
172 catch(...) { return S_FALSE; }
\r
177 STDMETHODIMP CHandler::Close()
\r
184 STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
\r
186 *numItems = _numItems;
\r
190 STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
\r
191 Int32 testMode, IArchiveExtractCallback *extractCallback)
\r
194 bool allFilesMode = (numItems == (UInt32)-1);
\r
196 numItems = _numItems;
\r
199 UInt64 totalSize = 0;
\r
201 for (i = 0; i < numItems; i++)
\r
202 totalSize += _items[allFilesMode ? i : indices[i]].Size;
\r
203 extractCallback->SetTotal(totalSize);
\r
205 UInt64 currentTotalSize = 0;
\r
207 NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
\r
208 CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
\r
210 CLocalProgress *lps = new CLocalProgress;
\r
211 CMyComPtr<ICompressProgressInfo> progress = lps;
\r
212 lps->Init(extractCallback, false);
\r
214 CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
\r
215 CMyComPtr<ISequentialInStream> inStream(streamSpec);
\r
216 streamSpec->SetStream(_stream);
\r
218 for (i = 0; i < numItems; i++)
\r
220 lps->InSize = lps->OutSize = currentTotalSize;
\r
221 RINOK(lps->SetCur());
\r
222 CMyComPtr<ISequentialOutStream> realOutStream;
\r
223 Int32 askMode = testMode ?
\r
224 NExtract::NAskMode::kTest :
\r
225 NExtract::NAskMode::kExtract;
\r
226 UInt32 index = allFilesMode ? i : indices[i];
\r
227 const CItem &item = _items[index];
\r
228 RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
\r
229 currentTotalSize += item.Size;
\r
231 if (!testMode && !realOutStream)
\r
233 RINOK(extractCallback->PrepareOperation(askMode));
\r
236 RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
\r
239 RINOK(_stream->Seek(_startPos + item.Offset, STREAM_SEEK_SET, NULL));
\r
240 streamSpec->Init(item.Size);
\r
241 RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress));
\r
242 realOutStream.Release();
\r
243 RINOK(extractCallback->SetOperationResult((copyCoderSpec->TotalSize == item.Size) ?
\r
244 NExtract::NOperationResult::kOK:
\r
245 NExtract::NOperationResult::kDataError));
\r
251 STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
\r
254 const CItem &item = _items[index];
\r
255 return CreateLimitedInStream(_stream, _startPos + item.Offset, item.Size, stream);
\r
259 static IInArchive *CreateArc() { return new CHandler; }
\r
261 static CArcInfo g_ArcInfo =
\r
262 { L"Mub", L"", 0, 0xE2, { 0xCA, 0xFE, 0xBA, 0xBE, 0, 0, 0 }, 7, false, CreateArc, 0 };
\r