diff options
Diffstat (limited to 'CPP/7zip/Archive/MubHandler.cpp')
-rwxr-xr-x | CPP/7zip/Archive/MubHandler.cpp | 264 |
1 files changed, 264 insertions, 0 deletions
diff --git a/CPP/7zip/Archive/MubHandler.cpp b/CPP/7zip/Archive/MubHandler.cpp new file mode 100755 index 00000000..edf00f93 --- /dev/null +++ b/CPP/7zip/Archive/MubHandler.cpp @@ -0,0 +1,264 @@ +// MubHandler.cpp + +#include "StdAfx.h" + +#include "../../../C/CpuArch.h" + +#include "Common/ComTry.h" + +#include "Windows/PropVariant.h" + +#include "../Common/LimitedStreams.h" +#include "../Common/ProgressUtils.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/Copy/CopyCoder.h" + +#define Get32(p) GetBe32(p) + +namespace NArchive { +namespace NMub { + +struct CItem +{ + UInt32 Type; + UInt32 SubType; + UInt64 Offset; + UInt64 Size; + UInt32 Align; + bool IsTail; +}; + +const UInt32 kNumFilesMax = 10; + +class CHandler: + public IInArchive, + public CMyUnknownImp +{ + UInt64 _startPos; + CMyComPtr<IInStream> _inStream; + UInt32 _numItems; + CItem _items[kNumFilesMax + 1]; + HRESULT Open2(IInStream *stream); +public: + MY_UNKNOWN_IMP1(IInArchive) + INTERFACE_IInArchive(;) +}; + +STATPROPSTG kProps[] = +{ + { NULL, kpidSize, VT_UI8}, + { NULL, kpidPackSize, VT_UI8} +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps_NO + +#define MACH_ARCH_ABI64 0x1000000 +#define MACH_MACHINE_386 7 +#define MACH_MACHINE_ARM 12 +#define MACH_MACHINE_SPARC 14 +#define MACH_MACHINE_PPC 18 + +#define MACH_MACHINE_PPC64 (MACH_MACHINE_PPC | MACH_ARCH_ABI64) +#define MACH_MACHINE_AMD64 (MACH_MACHINE_386 | MACH_ARCH_ABI64) + +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +{ + NWindows::NCOM::CPropVariant prop; + const CItem &item = _items[index]; + switch(propID) + { + case kpidExtension: + { + const wchar_t *ext; + if (item.IsTail) + ext = L"tail"; + else + { + switch(item.Type) + { + case MACH_MACHINE_386: ext = L"86"; break; + case MACH_MACHINE_ARM: ext = L"arm"; break; + case MACH_MACHINE_SPARC: ext = L"sparc"; break; + case MACH_MACHINE_PPC: ext = L"ppc"; break; + case MACH_MACHINE_PPC64: ext = L"ppc64"; break; + case MACH_MACHINE_AMD64: ext = L"x64"; break; + default: ext = L"unknown"; break; + } + } + prop = ext; + break; + } + case kpidSize: + case kpidPackSize: + prop = (UInt64)item.Size; + break; + } + prop.Detach(value); + return S_OK; +} + +#define MACH_TYPE_ABI64 (1 << 24) +#define MACH_SUBTYPE_ABI64 (1 << 31) + +HRESULT CHandler::Open2(IInStream *stream) +{ + RINOK(stream->Seek(0, STREAM_SEEK_SET, &_startPos)); + + const UInt32 kHeaderSize = 8; + const UInt32 kRecordSize = 5 * 4; + const UInt32 kBufSize = kHeaderSize + kNumFilesMax * kRecordSize; + Byte buf[kBufSize]; + size_t processed = kBufSize; + RINOK(ReadStream(stream, buf, &processed)); + if (processed < kHeaderSize) + return S_FALSE; + UInt32 num = Get32(buf + 4); + if (Get32(buf) != 0xCAFEBABE || num > kNumFilesMax || processed < kHeaderSize + num * kRecordSize) + return S_FALSE; + UInt64 endPosMax = kHeaderSize; + for (UInt32 i = 0; i < num; i++) + { + const Byte *p = buf + kHeaderSize + i * kRecordSize; + CItem &sb = _items[i]; + sb.IsTail = false; + sb.Type = Get32(p); + sb.SubType = Get32(p + 4); + sb.Offset = Get32(p + 8); + sb.Size = Get32(p + 12); + sb.Align = Get32(p + 16); + + if ((sb.Type & ~MACH_TYPE_ABI64) >= 0x100 || + (sb.SubType & ~MACH_SUBTYPE_ABI64) >= 0x100 || + sb.Align > 31) + return S_FALSE; + + UInt64 endPos = (UInt64)sb.Offset + sb.Size; + if (endPos > endPosMax) + endPosMax = endPos; + } + UInt64 fileSize; + RINOK(stream->Seek(0, STREAM_SEEK_END, &fileSize)); + fileSize -= _startPos; + _numItems = num; + if (fileSize > endPosMax) + { + CItem &sb = _items[_numItems++]; + sb.IsTail = true; + sb.Type = 0; + sb.SubType = 0; + sb.Offset = endPosMax; + sb.Size = fileSize - endPosMax; + sb.Align = 0; + } + return S_OK; +} + +STDMETHODIMP CHandler::Open(IInStream *inStream, + const UInt64 * /* maxCheckStartPosition */, + IArchiveOpenCallback * /* openArchiveCallback */) +{ + COM_TRY_BEGIN + Close(); + try + { + if (Open2(inStream) != S_OK) + return S_FALSE; + _inStream = inStream; + } + catch(...) { return S_FALSE; } + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::Close() +{ + _inStream.Release(); + _numItems = 0; + return S_OK; +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = _numItems; + return S_OK; +} + +STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems, + Int32 _aTestMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + bool testMode = (_aTestMode != 0); + bool allFilesMode = (numItems == UInt32(-1)); + if (allFilesMode) + numItems = _numItems; + if (numItems == 0) + return S_OK; + UInt64 totalSize = 0; + UInt32 i; + for (i = 0; i < numItems; i++) + totalSize += _items[allFilesMode ? i : indices[i]].Size; + 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()); + CMyComPtr<ISequentialOutStream> realOutStream; + Int32 askMode = testMode ? + NArchive::NExtract::NAskMode::kTest : + NArchive::NExtract::NAskMode::kExtract; + UInt32 index = allFilesMode ? i : indices[i]; + const CItem &item = _items[index]; + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); + currentItemSize = item.Size; + + + + + + + if (!testMode && (!realOutStream)) + continue; + RINOK(extractCallback->PrepareOperation(askMode)); + if (testMode) + { + RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK)); + continue; + } + RINOK(_inStream->Seek(_startPos + item.Offset, STREAM_SEEK_SET, NULL)); + streamSpec->Init(item.Size); + RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress)); + realOutStream.Release(); + RINOK(extractCallback->SetOperationResult((copyCoderSpec->TotalSize == item.Size) ? + NArchive::NExtract::NOperationResult::kOK: + NArchive::NExtract::NOperationResult::kDataError)); + } + return S_OK; + COM_TRY_END +} + +static IInArchive *CreateArc() { return new CHandler; } + +static CArcInfo g_ArcInfo = + { L"Mub", L"", 0, 0xE2, { 0xCA, 0xFE, 0xBA, 0xBE, 0, 0, 0 }, 7, false, CreateArc, 0 }; + +REGISTER_ARC(Mub) + +}} |