📄 xarhandler.cpp
字号:
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();
_files.Clear();
_xml.Empty();
return S_OK;
}
STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
{
*numItems = _files.Size()
#ifdef XAR_SHOW_RAW
+ 1
#endif
;
return S_OK;
}
static void TimeToProp(UInt64 t, NWindows::NCOM::CPropVariant &prop)
{
if (t != 0)
{
FILETIME ft;
ft.dwLowDateTime = (UInt32)(t);
ft.dwHighDateTime = (UInt32)(t >> 32);
prop = ft;
}
}
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
NWindows::NCOM::CPropVariant prop;
#ifdef XAR_SHOW_RAW
if ((int)index == _files.Size())
{
switch(propID)
{
case kpidPath: prop = L"[TOC].xml"; break;
case kpidSize:
case kpidPackSize: prop = (UInt64)_xml.Length(); break;
}
}
else
#endif
{
const CFile &item = _files[index];
switch(propID)
{
case kpidMethod:
{
UString name;
if (ConvertUTF8ToUnicode(item.Method, name))
prop = name;
break;
}
case kpidPath:
{
AString path;
int cur = index;
do
{
const CFile &item = _files[cur];
AString s = item.Name;
if (s.IsEmpty())
s = "unknown";
if (path.IsEmpty())
path = s;
else
path = s + CHAR_PATH_SEPARATOR + path;
cur = item.Parent;
}
while (cur >= 0);
UString name;
if (ConvertUTF8ToUnicode(path, name))
prop = name;
break;
}
case kpidIsDir: prop = item.IsDir; break;
case kpidSize: if (!item.IsDir) prop = item.Size; break;
case kpidPackSize: if (!item.IsDir) prop = item.PackSize; break;
case kpidMTime: TimeToProp(item.MTime, prop); break;
case kpidCTime: TimeToProp(item.CTime, prop); break;
case kpidATime: TimeToProp(item.ATime, prop); 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 XAR_SHOW_RAW
if (index == _files.Size())
totalSize += _xml.Length();
else
#endif
totalSize += _files[index].Size;
}
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::NZlib::CDecoder *zlibCoderSpec = new NCompress::NZlib::CDecoder();
CMyComPtr<ICompressCoder> zlibCoder = zlibCoderSpec;
NCompress::NBZip2::CDecoder *bzip2CoderSpec = new NCompress::NBZip2::CDecoder();
CMyComPtr<ICompressCoder> bzip2Coder = bzip2CoderSpec;
NCompress::NDeflate::NDecoder::CCOMCoder *deflateCoderSpec = new NCompress::NDeflate::NDecoder::CCOMCoder();
CMyComPtr<ICompressCoder> deflateCoder = deflateCoderSpec;
CLocalProgress *lps = new CLocalProgress;
CMyComPtr<ICompressProgressInfo> progress = lps;
lps->Init(extractCallback, false);
CLimitedSequentialInStream *inStreamSpec = new CLimitedSequentialInStream;
CMyComPtr<ISequentialInStream> inStream(inStreamSpec);
inStreamSpec->SetStream(_inStream);
CLimitedSequentialOutStream *outStreamLimSpec = new CLimitedSequentialOutStream;
CMyComPtr<ISequentialOutStream> outStream(outStreamLimSpec);
COutStreamWithSha1 *outStreamSha1Spec = new COutStreamWithSha1;
{
CMyComPtr<ISequentialOutStream> outStreamSha1(outStreamSha1Spec);
outStreamLimSpec->SetStream(outStreamSha1);
}
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];
RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
if (index < _files.Size())
{
const CFile &item = _files[index];
if (item.IsDir)
{
RINOK(extractCallback->PrepareOperation(askMode));
RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK));
continue;
}
}
if (!testMode && (!realOutStream))
continue;
RINOK(extractCallback->PrepareOperation(askMode));
outStreamSha1Spec->SetStream(realOutStream);
realOutStream.Release();
Int32 opRes = NArchive::NExtract::NOperationResult::kOK;
#ifdef XAR_SHOW_RAW
if (index == _files.Size())
{
outStreamSha1Spec->Init(false);
outStreamLimSpec->Init(_xml.Length());
RINOK(WriteStream(outStream, (const char *)_xml, _xml.Length()));
currentPackSize = currentUnpSize = _xml.Length();
}
else
#endif
{
const CFile &item = _files[index];
if (item.HasData)
{
currentPackSize = item.PackSize;
currentUnpSize = item.Size;
RINOK(_inStream->Seek(_dataStartPos + item.Offset, STREAM_SEEK_SET, NULL));
inStreamSpec->Init(item.PackSize);
outStreamSha1Spec->Init(item.Sha1IsDefined);
outStreamLimSpec->Init(item.Size);
HRESULT res = S_OK;
ICompressCoder *coder = NULL;
if (item.Method == "octet-stream")
if (item.PackSize == item.Size)
coder = copyCoder;
else
opRes = NArchive::NExtract::NOperationResult::kUnSupportedMethod;
else if (item.Method == METHOD_NAME_ZLIB)
coder = zlibCoder;
else if (item.Method == "bzip2")
coder = bzip2Coder;
else
opRes = NArchive::NExtract::NOperationResult::kUnSupportedMethod;
if (coder)
res = coder->Code(inStream, outStream, NULL, NULL, progress);
if (res != S_OK)
{
if (!outStreamLimSpec->IsFinishedOK())
opRes = NArchive::NExtract::NOperationResult::kDataError;
else if (res != S_FALSE)
return res;
if (opRes == NArchive::NExtract::NOperationResult::kOK)
opRes = NArchive::NExtract::NOperationResult::kDataError;
}
if (opRes == NArchive::NExtract::NOperationResult::kOK)
{
if (outStreamLimSpec->IsFinishedOK() &&
outStreamSha1Spec->GetSize() == item.Size)
{
if (!outStreamLimSpec->IsFinishedOK())
{
opRes = NArchive::NExtract::NOperationResult::kDataError;
}
else if (item.Sha1IsDefined)
{
Byte digest[NCrypto::NSha1::kDigestSize];
outStreamSha1Spec->Final(digest);
if (memcmp(digest, item.Sha1, NCrypto::NSha1::kDigestSize) != 0)
opRes = NArchive::NExtract::NOperationResult::kCRCError;
}
}
else
opRes = NArchive::NExtract::NOperationResult::kDataError;
}
}
}
outStreamSha1Spec->ReleaseStream();
RINOK(extractCallback->SetOperationResult(opRes));
}
return S_OK;
COM_TRY_END
}
static IInArchive *CreateArc() { return new NArchive::NXar::CHandler; }
static CArcInfo g_ArcInfo =
{ L"Xar", L"xar", 0, 0xE1, { 'x', 'a', 'r', '!', 0, 0x1C }, 6, false, CreateArc, 0 };
REGISTER_ARC(Xar)
}}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -