?? ziphandler.cpp
字號(hào):
{
NCrypto::NZip::CDecoder *_zipCryptoDecoderSpec;
NCrypto::NZipStrong::CDecoder *_pkAesDecoderSpec;
NCrypto::NWzAes::CDecoder *_wzAesDecoderSpec;
CMyComPtr<ICompressFilter> _zipCryptoDecoder;
CMyComPtr<ICompressFilter> _pkAesDecoder;
CMyComPtr<ICompressFilter> _wzAesDecoder;
CFilterCoder *filterStreamSpec;
CMyComPtr<ISequentialInStream> filterStream;
CMyComPtr<ICryptoGetTextPassword> getTextPassword;
CObjectVector<CMethodItem> methodItems;
public:
CZipDecoder():
_zipCryptoDecoderSpec(0),
_pkAesDecoderSpec(0),
_wzAesDecoderSpec(0),
filterStreamSpec(0) {}
HRESULT Decode(
DECL_EXTERNAL_CODECS_LOC_VARS
CInArchive &archive, const CItemEx &item,
ISequentialOutStream *realOutStream,
IArchiveExtractCallback *extractCallback,
ICompressProgressInfo *compressProgress,
UInt32 numThreads, Int32 &res);
};
HRESULT CZipDecoder::Decode(
DECL_EXTERNAL_CODECS_LOC_VARS
CInArchive &archive, const CItemEx &item,
ISequentialOutStream *realOutStream,
IArchiveExtractCallback *extractCallback,
ICompressProgressInfo *compressProgress,
UInt32 numThreads, Int32 &res)
{
res = NArchive::NExtract::NOperationResult::kDataError;
CInStreamReleaser inStreamReleaser;
bool needCRC = true;
bool wzAesMode = false;
bool pkAesMode = false;
UInt16 methodId = item.CompressionMethod;
if (item.IsEncrypted())
{
if (item.IsStrongEncrypted())
{
CStrongCryptoField f;
if (item.CentralExtra.GetStrongCryptoField(f))
{
pkAesMode = true;
}
if (!pkAesMode)
{
res = NArchive::NExtract::NOperationResult::kUnSupportedMethod;
return S_OK;
}
}
if (methodId == NFileHeader::NCompressionMethod::kWzAES)
{
CWzAesExtraField aesField;
if (item.CentralExtra.GetWzAesField(aesField))
{
wzAesMode = true;
needCRC = aesField.NeedCrc();
}
}
}
COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC;
CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;
outStreamSpec->SetStream(realOutStream);
outStreamSpec->Init(needCRC);
UInt64 authenticationPos;
CMyComPtr<ISequentialInStream> inStream;
{
UInt64 packSize = item.PackSize;
if (wzAesMode)
{
if (packSize < NCrypto::NWzAes::kMacSize)
return S_OK;
packSize -= NCrypto::NWzAes::kMacSize;
}
UInt64 dataPos = item.GetDataPosition();
inStream.Attach(archive.CreateLimitedStream(dataPos, packSize));
authenticationPos = dataPos + packSize;
}
CMyComPtr<ICompressFilter> cryptoFilter;
if (item.IsEncrypted())
{
if (wzAesMode)
{
CWzAesExtraField aesField;
if (!item.CentralExtra.GetWzAesField(aesField))
return S_OK;
methodId = aesField.Method;
if (!_wzAesDecoder)
{
_wzAesDecoderSpec = new NCrypto::NWzAes::CDecoder;
_wzAesDecoder = _wzAesDecoderSpec;
}
cryptoFilter = _wzAesDecoder;
Byte properties = aesField.Strength;
RINOK(_wzAesDecoderSpec->SetDecoderProperties2(&properties, 1));
}
else if (pkAesMode)
{
if (!_pkAesDecoder)
{
_pkAesDecoderSpec = new NCrypto::NZipStrong::CDecoder;
_pkAesDecoder = _pkAesDecoderSpec;
}
cryptoFilter = _pkAesDecoder;
}
else
{
if (!_zipCryptoDecoder)
{
_zipCryptoDecoderSpec = new NCrypto::NZip::CDecoder;
_zipCryptoDecoder = _zipCryptoDecoderSpec;
}
cryptoFilter = _zipCryptoDecoder;
}
CMyComPtr<ICryptoSetPassword> cryptoSetPassword;
RINOK(cryptoFilter.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword));
if (!getTextPassword)
extractCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getTextPassword);
if (getTextPassword)
{
CMyComBSTR password;
RINOK(getTextPassword->CryptoGetTextPassword(&password));
AString charPassword;
if (wzAesMode || pkAesMode)
{
charPassword = UnicodeStringToMultiByte((const wchar_t *)password, CP_ACP);
/*
for (int i = 0;; i++)
{
wchar_t c = password[i];
if (c == 0)
break;
if (c >= 0x80)
{
res = NArchive::NExtract::NOperationResult::kDataError;
return S_OK;
}
charPassword += (char)c;
}
*/
}
else
{
// we use OEM. WinZip/Windows probably use ANSI for some files
charPassword = UnicodeStringToMultiByte((const wchar_t *)password, CP_OEMCP);
}
HRESULT result = cryptoSetPassword->CryptoSetPassword(
(const Byte *)(const char *)charPassword, charPassword.Length());
if (result != S_OK)
return S_OK;
}
else
{
RINOK(cryptoSetPassword->CryptoSetPassword(0, 0));
}
}
int m;
for (m = 0; m < methodItems.Size(); m++)
if (methodItems[m].ZipMethod == methodId)
break;
if (m == methodItems.Size())
{
CMethodItem mi;
mi.ZipMethod = methodId;
if (methodId == NFileHeader::NCompressionMethod::kStored)
mi.Coder = new NCompress::CCopyCoder;
else if (methodId == NFileHeader::NCompressionMethod::kShrunk)
mi.Coder = new NCompress::NShrink::CDecoder;
else if (methodId == NFileHeader::NCompressionMethod::kImploded)
mi.Coder = new NCompress::NImplode::NDecoder::CCoder;
else if (methodId == NFileHeader::NCompressionMethod::kLZMA)
mi.Coder = new CLzmaDecoder;
else
{
CMethodId szMethodID;
if (methodId == NFileHeader::NCompressionMethod::kBZip2)
szMethodID = kMethodId_BZip2;
else
{
if (methodId > 0xFF)
{
res = NArchive::NExtract::NOperationResult::kUnSupportedMethod;
return S_OK;
}
szMethodID = kMethodId_ZipBase + (Byte)methodId;
}
RINOK(CreateCoder(EXTERNAL_CODECS_LOC_VARS szMethodID, mi.Coder, false));
if (mi.Coder == 0)
{
res = NArchive::NExtract::NOperationResult::kUnSupportedMethod;
return S_OK;
}
}
m = methodItems.Add(mi);
}
ICompressCoder *coder = methodItems[m].Coder;
{
CMyComPtr<ICompressSetDecoderProperties2> setDecoderProperties;
coder->QueryInterface(IID_ICompressSetDecoderProperties2, (void **)&setDecoderProperties);
if (setDecoderProperties)
{
Byte properties = (Byte)item.Flags;
RINOK(setDecoderProperties->SetDecoderProperties2(&properties, 1));
}
}
#ifdef COMPRESS_MT
{
CMyComPtr<ICompressSetCoderMt> setCoderMt;
coder->QueryInterface(IID_ICompressSetCoderMt, (void **)&setCoderMt);
if (setCoderMt)
{
RINOK(setCoderMt->SetNumberOfThreads(numThreads));
}
}
#endif
{
HRESULT result = S_OK;
CMyComPtr<ISequentialInStream> inStreamNew;
if (item.IsEncrypted())
{
if (!filterStream)
{
filterStreamSpec = new CFilterCoder;
filterStream = filterStreamSpec;
}
filterStreamSpec->Filter = cryptoFilter;
if (wzAesMode)
{
result = _wzAesDecoderSpec->ReadHeader(inStream);
}
else if (pkAesMode)
{
result =_pkAesDecoderSpec->ReadHeader(inStream, item.FileCRC, item.UnPackSize);
if (result == S_OK)
{
bool passwOK;
result = _pkAesDecoderSpec->CheckPassword(passwOK);
if (result == S_OK && !passwOK)
result = S_FALSE;
}
}
else
{
result = _zipCryptoDecoderSpec->ReadHeader(inStream);
}
if (result == S_OK)
{
RINOK(filterStreamSpec->SetInStream(inStream));
inStreamReleaser.FilterCoder = filterStreamSpec;
inStreamNew = filterStream;
if (wzAesMode)
{
if (!_wzAesDecoderSpec->CheckPasswordVerifyCode())
result = S_FALSE;
}
}
}
else
inStreamNew = inStream;
if (result == S_OK)
result = coder->Code(inStreamNew, outStream, NULL, &item.UnPackSize, compressProgress);
if (result == S_FALSE)
return S_OK;
if (result == E_NOTIMPL)
{
res = NArchive::NExtract::NOperationResult::kUnSupportedMethod;
return S_OK;
}
RINOK(result);
}
bool crcOK = true;
bool authOk = true;
if (needCRC)
crcOK = (outStreamSpec->GetCRC() == item.FileCRC);
if (wzAesMode)
{
inStream.Attach(archive.CreateLimitedStream(authenticationPos, NCrypto::NWzAes::kMacSize));
if (_wzAesDecoderSpec->CheckMac(inStream, authOk) != S_OK)
authOk = false;
}
res = ((crcOK && authOk) ?
NArchive::NExtract::NOperationResult::kOK :
NArchive::NExtract::NOperationResult::kCRCError);
return S_OK;
}
STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
Int32 _aTestMode, IArchiveExtractCallback *extractCallback)
{
COM_TRY_BEGIN
CZipDecoder myDecoder;
bool testMode = (_aTestMode != 0);
UInt64 totalUnPacked = 0, totalPacked = 0;
bool allFilesMode = (numItems == UInt32(-1));
if (allFilesMode)
numItems = m_Items.Size();
if(numItems == 0)
return S_OK;
UInt32 i;
for(i = 0; i < numItems; i++)
{
const CItemEx &item = m_Items[allFilesMode ? i : indices[i]];
totalUnPacked += item.UnPackSize;
totalPacked += item.PackSize;
}
RINOK(extractCallback->SetTotal(totalUnPacked));
UInt64 currentTotalUnPacked = 0, currentTotalPacked = 0;
UInt64 currentItemUnPacked, currentItemPacked;
CLocalProgress *lps = new CLocalProgress;
CMyComPtr<ICompressProgressInfo> progress = lps;
lps->Init(extractCallback, false);
for (i = 0; i < numItems; i++, currentTotalUnPacked += currentItemUnPacked,
currentTotalPacked += currentItemPacked)
{
currentItemUnPacked = 0;
currentItemPacked = 0;
lps->InSize = currentTotalPacked;
lps->OutSize = currentTotalUnPacked;
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));
CItemEx item = m_Items[index];
if (!item.FromLocal)
{
HRESULT res = m_Archive.ReadLocalItemAfterCdItem(item);
if (res == S_FALSE)
{
if (item.IsDir() || realOutStream || testMode)
{
RINOK(extractCallback->PrepareOperation(askMode));
realOutStream.Release();
RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kUnSupportedMethod));
}
continue;
}
RINOK(res);
}
if (item.IsDir() || item.IgnoreItem())
{
// if (!testMode)
{
RINOK(extractCallback->PrepareOperation(askMode));
realOutStream.Release();
RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK));
}
continue;
}
currentItemUnPacked = item.UnPackSize;
currentItemPacked = item.PackSize;
if (!testMode && (!realOutStream))
continue;
RINOK(extractCallback->PrepareOperation(askMode));
Int32 res;
RINOK(myDecoder.Decode(
EXTERNAL_CODECS_VARS
m_Archive, item, realOutStream, extractCallback,
progress, _numThreads, res));
realOutStream.Release();
RINOK(extractCallback->SetOperationResult(res))
}
return S_OK;
COM_TRY_END
}
IMPL_ISetCompressCodecsInfo
}}
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -