📄 dmghandler.cpp
字号:
startPos = b.PackPos;
}
startPos += b.PackSize;
*/
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);
}
}
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 kpidPackedSize:
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 kpidPackedSize:
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
}
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 = _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<ICompressCoder> copyCoder = copyCoderSpec;
NCompress::NBZip2::CDecoder *bzip2CoderSpec = new NCompress::NBZip2::CDecoder();
CMyComPtr<ICompressCoder> bzip2Coder = bzip2CoderSpec;
NCompress::NZlib::CDecoder *zlibCoderSpec = new NCompress::NZlib::CDecoder();
CMyComPtr<ICompressCoder> zlibCoder = zlibCoderSpec;
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++, currentPackTotal += currentPackSize, currentUnpTotal += currentUnpSize)
{
lps->InSize = currentPackTotal;
lps->OutSize = currentUnpTotal;
currentPackSize = 0;
currentUnpSize = 0;
RINOK(lps->SetCur());
CMyComPtr<ISequentialOutStream> realOutStream;
Int32 askMode = testMode ?
NArchive::NExtract::NAskMode::kTest :
NArchive::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<ISequentialOutStream> outStream(outStreamSpec);
outStreamSpec->SetStream(realOutStream);
realOutStream.Release();
Int32 opRes = NArchive::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 = NArchive::NExtract::NOperationResult::kDataError;
break;
}
RINOK(_inStream->Seek(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 = NArchive::NExtract::NOperationResult::kUnSupportedMethod;
break;
case METHOD_COPY:
if (block.UnpSize != block.PackSize)
{
opRes = NArchive::NExtract::NOperationResult::kUnSupportedMethod;
break;
}
res = copyCoder->Code(inStream, outStream, NULL, NULL, progress);
break;
case METHOD_ZLIB:
{
res = zlibCoder->Code(inStream, outStream, NULL, NULL, progress);
if (res != S_OK)
break;
break;
}
case METHOD_BZIP2:
{
res = bzip2Coder->Code(inStream, outStream, NULL, NULL, progress);
if (res == S_OK)
if (streamSpec->GetSize() != block.PackSize)
opRes = NArchive::NExtract::NOperationResult::kDataError;
break;
}
default:
opRes = NArchive::NExtract::NOperationResult::kUnSupportedMethod;
break;
}
if (res != S_OK)
{
if (res != S_FALSE)
return res;
if (opRes == NArchive::NExtract::NOperationResult::kOK)
opRes = NArchive::NExtract::NOperationResult::kDataError;
}
unpPos += block.UnpSize;
if (!outStreamSpec->IsFinishedOK())
{
if (realMethod && opRes == NArchive::NExtract::NOperationResult::kOK)
opRes = NArchive::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)
}}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -