mirror of
https://github.com/Xevion/easy7zip.git
synced 2025-12-13 14:11:34 -06:00
4.59 beta
This commit is contained in:
committed by
Kornel Lesiński
parent
3901bf0ab8
commit
173c07e166
586
CPP/7zip/Archive/XarHandler.cpp
Executable file
586
CPP/7zip/Archive/XarHandler.cpp
Executable file
@@ -0,0 +1,586 @@
|
||||
// XarHandler.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../C/CpuArch.h"
|
||||
|
||||
#include "Common/ComTry.h"
|
||||
#include "Common/MyXml.h"
|
||||
#include "Common/StringToInt.h"
|
||||
#include "Common/UTFConvert.h"
|
||||
|
||||
#include "Windows/PropVariant.h"
|
||||
#include "Windows/Time.h"
|
||||
|
||||
#include "../Common/LimitedStreams.h"
|
||||
#include "../Common/ProgressUtils.h"
|
||||
#include "../Common/RegisterArc.h"
|
||||
#include "../Common/StreamObjects.h"
|
||||
#include "../Common/StreamUtils.h"
|
||||
|
||||
#include "../Compress/BZip2/BZip2Decoder.h"
|
||||
#include "../Compress/Copy/CopyCoder.h"
|
||||
#include "../Compress/Deflate/ZlibDecoder.h"
|
||||
|
||||
#include "Common/OutStreamWithSha1.h"
|
||||
|
||||
#define XAR_SHOW_RAW
|
||||
|
||||
#define Get16(p) GetBe16(p)
|
||||
#define Get32(p) GetBe32(p)
|
||||
#define Get64(p) GetBe64(p)
|
||||
|
||||
namespace NArchive {
|
||||
namespace NXar {
|
||||
|
||||
struct CFile
|
||||
{
|
||||
AString Name;
|
||||
AString Method;
|
||||
UInt64 Size;
|
||||
UInt64 PackSize;
|
||||
UInt64 Offset;
|
||||
|
||||
// UInt32 mode;
|
||||
UInt64 CTime;
|
||||
UInt64 MTime;
|
||||
UInt64 ATime;
|
||||
|
||||
bool IsDir;
|
||||
bool HasData;
|
||||
|
||||
bool Sha1IsDefined;
|
||||
Byte Sha1[20];
|
||||
// bool packSha1IsDefined;
|
||||
// Byte packSha1[20];
|
||||
|
||||
int Parent;
|
||||
|
||||
CFile(): IsDir(false), HasData(false), Sha1IsDefined(false),
|
||||
/* packSha1IsDefined(false), */
|
||||
Parent(-1), Size(0), PackSize(0), CTime(0), MTime(0), ATime(0) {}
|
||||
};
|
||||
|
||||
class CHandler:
|
||||
public IInArchive,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
UInt64 _dataStartPos;
|
||||
CMyComPtr<IInStream> _inStream;
|
||||
AString _xml;
|
||||
CObjectVector<CFile> _files;
|
||||
|
||||
HRESULT Open2(IInStream *stream);
|
||||
HRESULT Extract(IInStream *stream);
|
||||
public:
|
||||
MY_UNKNOWN_IMP1(IInArchive)
|
||||
INTERFACE_IInArchive(;)
|
||||
};
|
||||
|
||||
const UInt32 kXmlSizeMax = ((UInt32)1 << 30) - (1 << 14);
|
||||
|
||||
STATPROPSTG kProps[] =
|
||||
{
|
||||
{ NULL, kpidPath, VT_BSTR},
|
||||
{ NULL, kpidSize, VT_UI8},
|
||||
{ NULL, kpidPackSize, VT_UI8},
|
||||
{ NULL, kpidMTime, VT_FILETIME},
|
||||
{ NULL, kpidCTime, VT_FILETIME},
|
||||
{ NULL, kpidATime, VT_FILETIME},
|
||||
{ NULL, kpidMethod, VT_BSTR}
|
||||
};
|
||||
|
||||
IMP_IInArchive_Props
|
||||
IMP_IInArchive_ArcProps_NO
|
||||
|
||||
static bool ParseNumber(const char *s, int size, UInt32 &res)
|
||||
{
|
||||
const char *end;
|
||||
res = (UInt32)ConvertStringToUInt64(s, &end);
|
||||
return (end - s == size);
|
||||
}
|
||||
|
||||
static bool ParseUInt64(const CXmlItem &item, const char *name, UInt64 &res)
|
||||
{
|
||||
AString s = item.GetSubStringForTag(name);
|
||||
const char *end;
|
||||
res = ConvertStringToUInt64(s, &end);
|
||||
return (end - (const char *)s == s.Length());
|
||||
}
|
||||
|
||||
static UInt64 ParseTime(const CXmlItem &item, const char *name)
|
||||
{
|
||||
AString s = item.GetSubStringForTag(name);
|
||||
if (s.Length() < 20)
|
||||
return 0;
|
||||
const char *p = s;
|
||||
if (p[ 4] != '-' || p[ 7] != '-' || p[10] != 'T' ||
|
||||
p[13] != ':' || p[16] != ':' || p[19] != 'Z')
|
||||
return 0;
|
||||
UInt32 year, month, day, hour, min, sec;
|
||||
if (!ParseNumber(p, 4, year )) return 0;
|
||||
if (!ParseNumber(p + 5, 2, month)) return 0;
|
||||
if (!ParseNumber(p + 8, 2, day )) return 0;
|
||||
if (!ParseNumber(p + 11, 2, hour )) return 0;
|
||||
if (!ParseNumber(p + 14, 2, min )) return 0;
|
||||
if (!ParseNumber(p + 17, 2, sec )) return 0;
|
||||
|
||||
UInt64 numSecs;
|
||||
if (!NWindows::NTime::GetSecondsSince1601(year, month, day, hour, min, sec, numSecs))
|
||||
return 0;
|
||||
return numSecs * 10000000;
|
||||
}
|
||||
|
||||
static bool HexToByte(char c, Byte &res)
|
||||
{
|
||||
if (c >= '0' && c <= '9') res = c - '0';
|
||||
else if (c >= 'A' && c <= 'F') res = c - 'A' + 10;
|
||||
else if (c >= 'a' && c <= 'f') res = c - 'a' + 10;
|
||||
else return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
#define METHOD_NAME_ZLIB "zlib"
|
||||
|
||||
static bool ParseSha1(const CXmlItem &item, const char *name, Byte *digest)
|
||||
{
|
||||
int index = item.FindSubTag(name);
|
||||
if (index < 0)
|
||||
return false;
|
||||
const CXmlItem &checkItem = item.SubItems[index];
|
||||
AString style = checkItem.GetPropertyValue("style");
|
||||
if (style == "SHA1")
|
||||
{
|
||||
AString s = checkItem.GetSubString();
|
||||
if (s.Length() != 40)
|
||||
return false;
|
||||
for (int i = 0; i < s.Length(); i += 2)
|
||||
{
|
||||
Byte b0, b1;
|
||||
if (!HexToByte(s[i], b0) || !HexToByte(s[i + 1], b1))
|
||||
return false;
|
||||
digest[i / 2] = (b0 << 4) | b1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool AddItem(const CXmlItem &item, CObjectVector<CFile> &files, int parent)
|
||||
{
|
||||
if (!item.IsTag)
|
||||
return true;
|
||||
if (item.Name == "file")
|
||||
{
|
||||
CFile file;
|
||||
file.Parent = parent;
|
||||
parent = files.Size();
|
||||
file.Name = item.GetSubStringForTag("name");
|
||||
AString type = item.GetSubStringForTag("type");
|
||||
if (type == "directory")
|
||||
file.IsDir = true;
|
||||
else if (type == "file")
|
||||
file.IsDir = false;
|
||||
else
|
||||
return false;
|
||||
|
||||
int dataIndex = item.FindSubTag("data");
|
||||
if (dataIndex >= 0 && !file.IsDir)
|
||||
{
|
||||
file.HasData = true;
|
||||
const CXmlItem &dataItem = item.SubItems[dataIndex];
|
||||
if (!ParseUInt64(dataItem, "size", file.Size))
|
||||
return false;
|
||||
if (!ParseUInt64(dataItem, "length", file.PackSize))
|
||||
return false;
|
||||
if (!ParseUInt64(dataItem, "offset", file.Offset))
|
||||
return false;
|
||||
file.Sha1IsDefined = ParseSha1(dataItem, "extracted-checksum", file.Sha1);
|
||||
// file.packSha1IsDefined = ParseSha1(dataItem, "archived-checksum", file.packSha1);
|
||||
int encodingIndex = dataItem.FindSubTag("encoding");
|
||||
const CXmlItem &encodingItem = dataItem.SubItems[encodingIndex];
|
||||
if (encodingItem.IsTag)
|
||||
{
|
||||
AString s = encodingItem.GetPropertyValue("style");
|
||||
if (s.Length() >= 0)
|
||||
{
|
||||
AString appl = "application/";
|
||||
if (s.Left(appl.Length()) == appl)
|
||||
{
|
||||
s = s.Mid(appl.Length());
|
||||
AString xx = "x-";
|
||||
if (s.Left(xx.Length()) == xx)
|
||||
{
|
||||
s = s.Mid(xx.Length());
|
||||
if (s == "gzip")
|
||||
s = METHOD_NAME_ZLIB;
|
||||
}
|
||||
}
|
||||
file.Method = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
file.CTime = ParseTime(item, "ctime");
|
||||
file.MTime = ParseTime(item, "mtime");
|
||||
file.ATime = ParseTime(item, "atime");
|
||||
files.Add(file);
|
||||
}
|
||||
for (int i = 0; i < item.SubItems.Size(); i++)
|
||||
if (!AddItem(item.SubItems[i], files, parent))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
HRESULT CHandler::Open2(IInStream *stream)
|
||||
{
|
||||
UInt64 archiveStartPos;
|
||||
RINOK(stream->Seek(0, STREAM_SEEK_SET, &archiveStartPos));
|
||||
|
||||
const UInt32 kHeaderSize = 0x1C;
|
||||
Byte buf[kHeaderSize];
|
||||
RINOK(ReadStream_FALSE(stream, buf, kHeaderSize));
|
||||
|
||||
UInt32 size = Get16(buf + 4);
|
||||
// UInt32 ver = Get16(buf + 6); // == 0
|
||||
if (Get32(buf) != 0x78617221 || size != kHeaderSize)
|
||||
return S_FALSE;
|
||||
|
||||
UInt64 packSize = Get64(buf + 8);
|
||||
UInt64 unpackSize = Get64(buf + 0x10);
|
||||
// UInt32 checkSumAlogo = Get32(buf + 0x18);
|
||||
|
||||
if (unpackSize >= kXmlSizeMax)
|
||||
return S_FALSE;
|
||||
|
||||
_dataStartPos = archiveStartPos + kHeaderSize + packSize;
|
||||
|
||||
char *ss = _xml.GetBuffer((int)unpackSize + 1);
|
||||
|
||||
NCompress::NZlib::CDecoder *zlibCoderSpec = new NCompress::NZlib::CDecoder();
|
||||
CMyComPtr<ICompressCoder> zlibCoder = zlibCoderSpec;
|
||||
|
||||
CLimitedSequentialInStream *inStreamLimSpec = new CLimitedSequentialInStream;
|
||||
CMyComPtr<ISequentialInStream> inStreamLim(inStreamLimSpec);
|
||||
inStreamLimSpec->SetStream(stream);
|
||||
inStreamLimSpec->Init(packSize);
|
||||
|
||||
CSequentialOutStreamImp2 *outStreamLimSpec = new CSequentialOutStreamImp2;
|
||||
CMyComPtr<ISequentialOutStream> outStreamLim(outStreamLimSpec);
|
||||
outStreamLimSpec->Init((Byte *)ss, (size_t)unpackSize);
|
||||
|
||||
RINOK(zlibCoder->Code(inStreamLim, outStreamLim, NULL, NULL, NULL));
|
||||
|
||||
if (outStreamLimSpec->GetPos() != (size_t)unpackSize)
|
||||
return S_FALSE;
|
||||
|
||||
ss[(size_t)unpackSize] = 0;
|
||||
_xml.ReleaseBuffer();
|
||||
|
||||
CXml xml;
|
||||
if (!xml.Parse(_xml))
|
||||
return S_FALSE;
|
||||
|
||||
if (!xml.Root.IsTagged("xar") || xml.Root.SubItems.Size() != 1)
|
||||
return S_FALSE;
|
||||
const CXmlItem &toc = xml.Root.SubItems[0];
|
||||
if (!toc.IsTagged("toc"))
|
||||
return S_FALSE;
|
||||
if (!AddItem(toc, _files, -1))
|
||||
return S_FALSE;
|
||||
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();
|
||||
_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)
|
||||
|
||||
}}
|
||||
Reference in New Issue
Block a user