From be3b47d0d504a3409ce66bd77bb8c0acff87c4f5 Mon Sep 17 00:00:00 2001 From: kh1 Date: Thu, 15 Mar 2012 14:53:47 +0100 Subject: Reorganize the tree, have better ifw.pri. Shadow build support. Change-Id: I01fb12537f863ed0744979973c7e4153889cc5cb Reviewed-by: Tim Jenssen --- src/libs/7zip/win/CPP/7zip/Archive/DmgHandler.cpp | 918 ++++++++++++++++++++++ 1 file changed, 918 insertions(+) create mode 100644 src/libs/7zip/win/CPP/7zip/Archive/DmgHandler.cpp (limited to 'src/libs/7zip/win/CPP/7zip/Archive/DmgHandler.cpp') diff --git a/src/libs/7zip/win/CPP/7zip/Archive/DmgHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/DmgHandler.cpp new file mode 100644 index 000000000..5040d5182 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/DmgHandler.cpp @@ -0,0 +1,918 @@ +// DmgHandler.cpp + +#include "StdAfx.h" + +#include "../../../C/CpuArch.h" + +#include "Common/Buffer.h" +#include "Common/ComTry.h" +#include "Common/IntToString.h" +#include "Common/MyXml.h" +#include "Common/UTFConvert.h" + +#include "Windows/PropVariant.h" + +#include "../Common/LimitedStreams.h" +#include "../Common/ProgressUtils.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/BZip2Decoder.h" +#include "../Compress/CopyCoder.h" +#include "../Compress/ZlibDecoder.h" + +// #define DMG_SHOW_RAW + +// #include +#define PRF(x) // x + +#define Get32(p) GetBe32(p) +#define Get64(p) GetBe64(p) + +static int Base64ToByte(char c) +{ + if (c >= 'A' && c <= 'Z') return c - 'A'; + if (c >= 'a' && c <= 'z') return c - 'a' + 26; + if (c >= '0' && c <= '9') return c - '0' + 52; + if (c == '+') return 62; + if (c == '/') return 63; + if (c == '=') return 0; + return -1; +} + +static int Base64ToBin(Byte *dest, const char *src, int srcLen) +{ + int srcPos = 0; + int destPos = 0; + while (srcPos < srcLen) + { + Byte buf[4]; + int filled = 0; + while (srcPos < srcLen) + { + int n = Base64ToByte(src[srcPos++]); + if (n >= 0) + { + buf[filled++] = (Byte)n; + if (filled == 4) + break; + } + } + if (filled >= 2) { if (dest) dest[destPos] = (buf[0] << 2) | (buf[1] >> 4); destPos++; } + if (filled >= 3) { if (dest) dest[destPos] = (buf[1] << 4) | (buf[2] >> 2); destPos++; } + if (filled >= 4) { if (dest) dest[destPos] = (buf[2] << 6) | (buf[3] ); destPos++; } + } + return destPos; +} + +static UString GetSizeString(UInt64 value) +{ + wchar_t s[32]; + wchar_t c; + if (value < (UInt64)20000) c = 0; + else if (value < ((UInt64)20000 << 10)) { value >>= 10; c = L'K'; } + else if (value < ((UInt64)20000 << 20)) { value >>= 20; c = L'M'; } + else { value >>= 30; c = L'G'; } + ConvertUInt64ToString(value, s); + int p = MyStringLen(s); + s[p++] = c; + s[p++] = L'\0'; + return s; +} + +namespace NArchive { +namespace NDmg { + +struct CBlock +{ + UInt32 Type; + UInt64 UnpPos; + UInt64 UnpSize; + UInt64 PackPos; + UInt64 PackSize; + + UInt64 GetNextPackOffset() const { return PackPos + PackSize; } +}; + +struct CFile +{ + CByteBuffer Raw; + UInt64 StartPos; + CRecordVector Blocks; + UInt64 GetUnpackSize() const + { + UInt64 size = 0; + for (int i = 0; i < Blocks.Size(); i++) + size += Blocks[i].UnpSize; + return size; + }; + UInt64 GetPackSize() const + { + UInt64 size = 0; + for (int i = 0; i < Blocks.Size(); i++) + size += Blocks[i].PackSize; + return size; + }; + + AString Name; +}; + +class CHandler: + public IInArchive, + public CMyUnknownImp +{ + CMyComPtr _inStream; + + AString _xml; + CObjectVector _files; + CRecordVector _fileIndices; + + HRESULT Open2(IInStream *stream); + HRESULT Extract(IInStream *stream); +public: + MY_UNKNOWN_IMP1(IInArchive) + INTERFACE_IInArchive(;) +}; + +const UInt32 kXmlSizeMax = ((UInt32)1 << 31) - (1 << 14); + +enum +{ + METHOD_ZERO_0 = 0, + METHOD_COPY = 1, + METHOD_ZERO_2 = 2, + METHOD_ADC = 0x80000004, + METHOD_ZLIB = 0x80000005, + METHOD_BZIP2 = 0x80000006, + METHOD_DUMMY = 0x7FFFFFFE, + METHOD_END = 0xFFFFFFFF +}; + +struct CMethodStat +{ + UInt32 NumBlocks; + UInt64 PackSize; + UInt64 UnpSize; + CMethodStat(): NumBlocks(0), PackSize(0), UnpSize(0) {} +}; + +struct CMethods +{ + CRecordVector Stats; + CRecordVector Types; + void Update(const CFile &file); + UString GetString() const; +}; + +void CMethods::Update(const CFile &file) +{ + for (int i = 0; i < file.Blocks.Size(); i++) + { + const CBlock &b = file.Blocks[i]; + int index = Types.FindInSorted(b.Type); + if (index < 0) + { + index = Types.AddToUniqueSorted(b.Type); + Stats.Insert(index, CMethodStat()); + } + CMethodStat &m = Stats[index]; + m.PackSize += b.PackSize; + m.UnpSize += b.UnpSize; + m.NumBlocks++; + } +} + +UString CMethods::GetString() const +{ + UString res; + for (int i = 0; i < Types.Size(); i++) + { + if (i != 0) + res += L' '; + wchar_t buf[32]; + const wchar_t *s; + const CMethodStat &m = Stats[i]; + bool showPack = true; + UInt32 type = Types[i]; + switch(type) + { + case METHOD_ZERO_0: s = L"zero0"; showPack = (m.PackSize != 0); break; + case METHOD_ZERO_2: s = L"zero2"; showPack = (m.PackSize != 0); break; + case METHOD_COPY: s = L"copy"; showPack = (m.UnpSize != m.PackSize); break; + case METHOD_ADC: s = L"adc"; break; + case METHOD_ZLIB: s = L"zlib"; break; + case METHOD_BZIP2: s = L"bzip2"; break; + default: ConvertUInt64ToString(type, buf); s = buf; + } + res += s; + if (m.NumBlocks != 1) + { + res += L'['; + ConvertUInt64ToString(m.NumBlocks, buf); + res += buf; + res += L']'; + } + res += L'-'; + res += GetSizeString(m.UnpSize); + if (showPack) + { + res += L'-'; + res += GetSizeString(m.PackSize); + } + } + return res; +} + +STATPROPSTG kProps[] = +{ + { NULL, kpidPath, VT_BSTR}, + { NULL, kpidSize, VT_UI8}, + { NULL, kpidPackSize, VT_UI8}, + { NULL, kpidComment, VT_BSTR}, + { NULL, kpidMethod, VT_BSTR} +}; + +IMP_IInArchive_Props + +STATPROPSTG kArcProps[] = +{ + { NULL, kpidMethod, VT_BSTR}, + { NULL, kpidNumBlocks, VT_UI4} +}; + +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + switch(propID) + { + case kpidMethod: + { + CMethods m; + for (int i = 0; i < _files.Size(); i++) + m.Update(_files[i]); + prop = m.GetString(); + break; + } + case kpidNumBlocks: + { + UInt64 numBlocks = 0; + for (int i = 0; i < _files.Size(); i++) + numBlocks += _files[i].Blocks.Size(); + prop = numBlocks; + break; + } + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +IMP_IInArchive_ArcProps + +static int FindKeyPair(const CXmlItem &item, const AString &key, const AString &nextTag) +{ + for (int i = 0; i + 1 < item.SubItems.Size(); i++) + { + const CXmlItem &si = item.SubItems[i]; + if (si.IsTagged("key") && si.GetSubString() == key && item.SubItems[i + 1].IsTagged(nextTag)) + return i + 1; + } + return -1; +} + +static AString GetStringFromKeyPair(const CXmlItem &item, const AString &key, const AString &nextTag) +{ + int index = FindKeyPair(item, key, nextTag); + if (index >= 0) + return item.SubItems[index].GetSubString(); + return AString(); +} + +HRESULT CHandler::Open2(IInStream *stream) +{ + const int HEADER_SIZE = 0x1E0; + + UInt64 headerPos; + RINOK(stream->Seek(-HEADER_SIZE, STREAM_SEEK_END, &headerPos)); + Byte buf[HEADER_SIZE]; + RINOK(ReadStream_FALSE(stream, buf, HEADER_SIZE)); + UInt64 address1 = Get64(buf + 0); + UInt64 address2 = Get64(buf + 0xB8); + UInt64 size64 = Get64(buf + 0xC0); + if (address1 != address2 || size64 >= kXmlSizeMax || size64 == 0 || + address1 >= headerPos || address1 + size64 > headerPos) + return S_FALSE; + RINOK(stream->Seek(address1, STREAM_SEEK_SET, NULL)); + size_t size = (size_t)size64; + + char *ss = _xml.GetBuffer((int)size + 1); + RINOK(ReadStream_FALSE(stream, ss, size)); + ss[size] = 0; + _xml.ReleaseBuffer(); + + CXml xml; + if (!xml.Parse(_xml)) + return S_FALSE; + if (xml.Root.Name != "plist") + return S_FALSE; + + int dictIndex = xml.Root.FindSubTag("dict"); + if (dictIndex < 0) + return S_FALSE; + + const CXmlItem &dictItem = xml.Root.SubItems[dictIndex]; + int rfDictIndex = FindKeyPair(dictItem, "resource-fork", "dict"); + if (rfDictIndex < 0) + return S_FALSE; + + const CXmlItem &rfDictItem = dictItem.SubItems[rfDictIndex]; + int arrIndex = FindKeyPair(rfDictItem, "blkx", "array"); + if (arrIndex < 0) + return S_FALSE; + + const CXmlItem &arrItem = rfDictItem.SubItems[arrIndex]; + + int i; + for (i = 0; i < arrItem.SubItems.Size(); i++) + { + const CXmlItem &item = arrItem.SubItems[i]; + if (!item.IsTagged("dict")) + continue; + + CFile file; + file.StartPos = 0; + + int destLen; + { + AString dataString; + AString name = GetStringFromKeyPair(item, "Name", "string"); + if (name.IsEmpty()) + name = GetStringFromKeyPair(item, "CFName", "string"); + file.Name = name; + dataString = GetStringFromKeyPair(item, "Data", "data"); + + destLen = Base64ToBin(NULL, dataString, dataString.Length()); + file.Raw.SetCapacity(destLen); + Base64ToBin(file.Raw, dataString, dataString.Length()); + } + + if (destLen > 0xCC && Get32(file.Raw) == 0x6D697368) + { + PRF(printf("\n\n index = %d", _files.Size())); + const int kRecordSize = 40; + for (int offset = 0xCC; offset + kRecordSize <= destLen; offset += kRecordSize) + { + const Byte *p = (const Byte *)file.Raw + offset; + CBlock b; + b.Type = Get32(p); + if (b.Type == METHOD_END) + break; + if (b.Type == METHOD_DUMMY) + continue; + + b.UnpPos = Get64(p + 0x08) << 9; + b.UnpSize = Get64(p + 0x10) << 9; + b.PackPos = Get64(p + 0x18); + b.PackSize = Get64(p + 0x20); + + file.Blocks.Add(b); + + PRF(printf("\nType=%8x m[1]=%8x uPos=%8x uSize=%7x pPos=%8x pSize=%7x", + b.Type, Get32(p + 4), (UInt32)b.UnpPos, (UInt32)b.UnpSize, (UInt32)b.PackPos, (UInt32)b.PackSize)); + } + } + int itemIndex = _files.Add(file); + if (file.Blocks.Size() > 0) + { + // if (file.Name.Find("HFS") >= 0) + _fileIndices.Add(itemIndex); + } + } + + // PackPos for each new file is 0 in some DMG files. So we use additional StartPos + + bool allStartAreZeros = true; + for (i = 0; i < _files.Size(); i++) + { + const CFile &file = _files[i]; + if (!file.Blocks.IsEmpty() && file.Blocks[0].PackPos != 0) + allStartAreZeros = false; + } + UInt64 startPos = 0; + if (allStartAreZeros) + { + for (i = 0; i < _files.Size(); i++) + { + CFile &file = _files[i]; + file.StartPos = startPos; + if (!file.Blocks.IsEmpty()) + startPos += file.Blocks.Back().GetNextPackOffset(); + } + } + + return S_OK; +} + +STDMETHODIMP CHandler::Open(IInStream *stream, + const UInt64 * /* maxCheckStartPosition */, + IArchiveOpenCallback * /* openArchiveCallback */) +{ + COM_TRY_BEGIN + { + Close(); + if (Open2(stream) != S_OK) + return S_FALSE; + _inStream = stream; + } + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::Close() +{ + _inStream.Release(); + _fileIndices.Clear(); + _files.Clear(); + _xml.Empty(); + return S_OK; +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = _fileIndices.Size() + #ifdef DMG_SHOW_RAW + + _files.Size() + 1; + #endif + ; + return S_OK; +} + +#define RAW_PREFIX L"raw" WSTRING_PATH_SEPARATOR + +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + + #ifdef DMG_SHOW_RAW + if ((int)index == _fileIndices.Size()) + { + switch(propID) + { + case kpidPath: + prop = RAW_PREFIX L"a.xml"; + break; + case kpidSize: + case kpidPackSize: + prop = (UInt64)_xml.Length(); + break; + } + } + else if ((int)index > _fileIndices.Size()) + { + int rawIndex = (int)index - (_fileIndices.Size() + 1); + switch(propID) + { + case kpidPath: + { + wchar_t s[32] = RAW_PREFIX; + ConvertUInt64ToString(rawIndex, s + MyStringLen(s)); + prop = s; + break; + } + case kpidSize: + case kpidPackSize: + prop = (UInt64)_files[rawIndex].Raw.GetCapacity(); + break; + } + } + else + #endif + { + int itemIndex = _fileIndices[index]; + const CFile &item = _files[itemIndex]; + switch(propID) + { + case kpidMethod: + { + CMethods m; + m.Update(item); + UString resString = m.GetString(); + if (!resString.IsEmpty()) + prop = resString; + break; + } + + // case kpidExtension: prop = L"hfs"; break; + + case kpidPath: + { + // break; + UString name; + wchar_t s[32]; + ConvertUInt64ToString(index, s); + name = s; + int num = 10; + int numDigits; + for (numDigits = 1; num < _fileIndices.Size(); numDigits++) + num *= 10; + while (name.Length() < numDigits) + name = L'0' + name; + + AString subName; + int pos1 = item.Name.Find('('); + if (pos1 >= 0) + { + pos1++; + int pos2 = item.Name.Find(')', pos1); + if (pos2 >= 0) + { + subName = item.Name.Mid(pos1, pos2 - pos1); + pos1 = subName.Find(':'); + if (pos1 >= 0) + subName = subName.Left(pos1); + } + } + subName.Trim(); + if (!subName.IsEmpty()) + { + if (subName == "Apple_HFS") + subName = "hfs"; + else if (subName == "Apple_HFSX") + subName = "hfsx"; + else if (subName == "Apple_Free") + subName = "free"; + else if (subName == "DDM") + subName = "ddm"; + UString name2; + ConvertUTF8ToUnicode(subName, name2); + name += L'.'; + name += name2; + } + else + { + UString name2; + ConvertUTF8ToUnicode(item.Name, name2); + if (!name2.IsEmpty()) + name += L" - "; + name += name2; + } + prop = name; + break; + } + case kpidComment: + { + UString name; + ConvertUTF8ToUnicode(item.Name, name); + prop = name; + break; + } + + case kpidSize: prop = item.GetUnpackSize(); break; + case kpidPackSize: prop = item.GetPackSize(); break; + } + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +class CAdcDecoder: + public ICompressCoder, + public CMyUnknownImp +{ + CLzOutWindow m_OutWindowStream; + CInBuffer m_InStream; + + void ReleaseStreams() + { + m_OutWindowStream.ReleaseStream(); + m_InStream.ReleaseStream(); + } + + class CCoderReleaser + { + CAdcDecoder *m_Coder; + public: + bool NeedFlush; + CCoderReleaser(CAdcDecoder *coder): m_Coder(coder), NeedFlush(true) {} + ~CCoderReleaser() + { + if (NeedFlush) + m_Coder->m_OutWindowStream.Flush(); + m_Coder->ReleaseStreams(); + } + }; + friend class CCoderReleaser; + +public: + MY_UNKNOWN_IMP + + STDMETHOD(CodeReal)(ISequentialInStream *inStream, + ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, + ICompressProgressInfo *progress); + + STDMETHOD(Code)(ISequentialInStream *inStream, + ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, + ICompressProgressInfo *progress); +}; + +STDMETHODIMP CAdcDecoder::CodeReal(ISequentialInStream *inStream, + ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, + ICompressProgressInfo *progress) +{ + if (!m_OutWindowStream.Create(1 << 18)) + return E_OUTOFMEMORY; + if (!m_InStream.Create(1 << 18)) + return E_OUTOFMEMORY; + + m_OutWindowStream.SetStream(outStream); + m_OutWindowStream.Init(false); + m_InStream.SetStream(inStream); + m_InStream.Init(); + + CCoderReleaser coderReleaser(this); + + const UInt32 kStep = (1 << 20); + UInt64 nextLimit = kStep; + + UInt64 pos = 0; + while (pos < *outSize) + { + if (pos > nextLimit && progress) + { + UInt64 packSize = m_InStream.GetProcessedSize(); + RINOK(progress->SetRatioInfo(&packSize, &pos)); + nextLimit += kStep; + } + Byte b; + if (!m_InStream.ReadByte(b)) + return S_FALSE; + UInt64 rem = *outSize - pos; + if (b & 0x80) + { + unsigned num = (b & 0x7F) + 1; + if (num > rem) + return S_FALSE; + for (unsigned i = 0; i < num; i++) + { + if (!m_InStream.ReadByte(b)) + return S_FALSE; + m_OutWindowStream.PutByte(b); + } + pos += num; + continue; + } + Byte b1; + if (!m_InStream.ReadByte(b1)) + return S_FALSE; + + UInt32 len, distance; + + if (b & 0x40) + { + len = ((UInt32)b & 0x3F) + 4; + Byte b2; + if (!m_InStream.ReadByte(b2)) + return S_FALSE; + distance = ((UInt32)b1 << 8) + b2; + } + else + { + b &= 0x3F; + len = ((UInt32)b >> 2) + 3; + distance = (((UInt32)b & 3) << 8) + b1; + } + + if (distance >= pos || len > rem) + return S_FALSE; + m_OutWindowStream.CopyBlock(distance, len); + pos += len; + } + if (*inSize != m_InStream.GetProcessedSize()) + return S_FALSE; + coderReleaser.NeedFlush = false; + return m_OutWindowStream.Flush(); +} + +STDMETHODIMP CAdcDecoder::Code(ISequentialInStream *inStream, + ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, + ICompressProgressInfo *progress) +{ + try { return CodeReal(inStream, outStream, inSize, outSize, progress);} + catch(const CInBufferException &e) { return e.ErrorCode; } + catch(const CLzOutWindowException &e) { return e.ErrorCode; } + catch(...) { return S_FALSE; } +} + + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + bool allFilesMode = (numItems == (UInt32)-1); + if (allFilesMode) + numItems = _files.Size(); + if (numItems == 0) + return S_OK; + UInt64 totalSize = 0; + UInt32 i; + for (i = 0; i < numItems; i++) + { + int index = (int)(allFilesMode ? i : indices[i]); + #ifdef DMG_SHOW_RAW + if (index == _fileIndices.Size()) + totalSize += _xml.Length(); + else if (index > _fileIndices.Size()) + totalSize += _files[index - (_fileIndices.Size() + 1)].Raw.GetCapacity(); + else + #endif + totalSize += _files[_fileIndices[index]].GetUnpackSize(); + } + extractCallback->SetTotal(totalSize); + + UInt64 currentPackTotal = 0; + UInt64 currentUnpTotal = 0; + UInt64 currentPackSize = 0; + UInt64 currentUnpSize = 0; + + const UInt32 kZeroBufSize = (1 << 14); + CByteBuffer zeroBuf; + zeroBuf.SetCapacity(kZeroBufSize); + memset(zeroBuf, 0, kZeroBufSize); + + NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); + CMyComPtr copyCoder = copyCoderSpec; + + NCompress::NBZip2::CDecoder *bzip2CoderSpec = new NCompress::NBZip2::CDecoder(); + CMyComPtr bzip2Coder = bzip2CoderSpec; + + NCompress::NZlib::CDecoder *zlibCoderSpec = new NCompress::NZlib::CDecoder(); + CMyComPtr zlibCoder = zlibCoderSpec; + + CAdcDecoder *adcCoderSpec = new CAdcDecoder(); + CMyComPtr adcCoder = adcCoderSpec; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(extractCallback, false); + + CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; + CMyComPtr inStream(streamSpec); + streamSpec->SetStream(_inStream); + + for (i = 0; i < numItems; i++, currentPackTotal += currentPackSize, currentUnpTotal += currentUnpSize) + { + lps->InSize = currentPackTotal; + lps->OutSize = currentUnpTotal; + currentPackSize = 0; + currentUnpSize = 0; + RINOK(lps->SetCur()); + CMyComPtr realOutStream; + Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + Int32 index = allFilesMode ? i : indices[i]; + // const CItemEx &item = _files[index]; + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); + + + if (!testMode && !realOutStream) + continue; + RINOK(extractCallback->PrepareOperation(askMode)); + + CLimitedSequentialOutStream *outStreamSpec = new CLimitedSequentialOutStream; + CMyComPtr outStream(outStreamSpec); + outStreamSpec->SetStream(realOutStream); + + realOutStream.Release(); + + Int32 opRes = NExtract::NOperationResult::kOK; + #ifdef DMG_SHOW_RAW + if (index > _fileIndices.Size()) + { + const CByteBuffer &buf = _files[index - (_fileIndices.Size() + 1)].Raw; + outStreamSpec->Init(buf.GetCapacity()); + RINOK(WriteStream(outStream, buf, buf.GetCapacity())); + currentPackSize = currentUnpSize = buf.GetCapacity(); + } + else if (index == _fileIndices.Size()) + { + outStreamSpec->Init(_xml.Length()); + RINOK(WriteStream(outStream, (const char *)_xml, _xml.Length())); + currentPackSize = currentUnpSize = _xml.Length(); + } + else + #endif + { + const CFile &item = _files[_fileIndices[index]]; + currentPackSize = item.GetPackSize(); + currentUnpSize = item.GetUnpackSize(); + + UInt64 unpPos = 0; + UInt64 packPos = 0; + { + for (int j = 0; j < item.Blocks.Size(); j++) + { + lps->InSize = currentPackTotal + packPos; + lps->OutSize = currentUnpTotal + unpPos; + RINOK(lps->SetCur()); + + const CBlock &block = item.Blocks[j]; + + packPos += block.PackSize; + if (block.UnpPos != unpPos) + { + opRes = NExtract::NOperationResult::kDataError; + break; + } + + RINOK(_inStream->Seek(item.StartPos + block.PackPos, STREAM_SEEK_SET, NULL)); + streamSpec->Init(block.PackSize); + // UInt64 startSize = outStreamSpec->GetSize(); + bool realMethod = true; + outStreamSpec->Init(block.UnpSize); + HRESULT res = S_OK; + + switch(block.Type) + { + case METHOD_ZERO_0: + case METHOD_ZERO_2: + realMethod = false; + if (block.PackSize != 0) + opRes = NExtract::NOperationResult::kUnSupportedMethod; + break; + + case METHOD_COPY: + if (block.UnpSize != block.PackSize) + { + opRes = NExtract::NOperationResult::kUnSupportedMethod; + break; + } + res = copyCoder->Code(inStream, outStream, NULL, NULL, progress); + break; + + case METHOD_ADC: + { + res = adcCoder->Code(inStream, outStream, &block.PackSize, &block.UnpSize, progress); + break; + } + + case METHOD_ZLIB: + { + res = zlibCoder->Code(inStream, outStream, NULL, NULL, progress); + break; + } + + case METHOD_BZIP2: + { + res = bzip2Coder->Code(inStream, outStream, NULL, NULL, progress); + if (res == S_OK) + if (streamSpec->GetSize() != block.PackSize) + opRes = NExtract::NOperationResult::kDataError; + break; + } + + default: + opRes = NExtract::NOperationResult::kUnSupportedMethod; + break; + } + if (res != S_OK) + { + if (res != S_FALSE) + return res; + if (opRes == NExtract::NOperationResult::kOK) + opRes = NExtract::NOperationResult::kDataError; + } + unpPos += block.UnpSize; + if (!outStreamSpec->IsFinishedOK()) + { + if (realMethod && opRes == NExtract::NOperationResult::kOK) + opRes = NExtract::NOperationResult::kDataError; + + while (outStreamSpec->GetRem() != 0) + { + UInt64 rem = outStreamSpec->GetRem(); + UInt32 size = (UInt32)MyMin(rem, (UInt64)kZeroBufSize); + RINOK(WriteStream(outStream, zeroBuf, size)); + } + } + } + } + } + outStream.Release(); + RINOK(extractCallback->SetOperationResult(opRes)); + } + return S_OK; + COM_TRY_END +} + +static IInArchive *CreateArc() { return new CHandler; } + +static CArcInfo g_ArcInfo = + { L"Dmg", L"dmg", 0, 0xE4, { 0 }, 0, false, CreateArc, 0 }; + +REGISTER_ARC(Dmg) + +}} -- cgit v1.2.3