//HRESULT wipeOutArchive(CInArchive *archive, CFileEnumeratorCallback *fileEnumeratorCallback) { HRESULT wipeOutArchive(Client7zHandler *handler, fileItemInfo &v, CFileEnumeratorCallback *fileEnumeratorCallback) { CInArchive *archive; RINOK(handler->openArchive(v, &archive)) boost::scoped_ptr<CInArchive> archiveGuard(archive); CMyComPtr<CArchiveExtractCallback> archiveExtractCallback = new CArchiveExtractCallback(NULL); //CInArchiveImpl *archive_ = dynamic_cast<CInArchiveImpl*>(archive); //CMyComPtr<IInArchive> archiveHandler; //RINOK(archive_->getArchiveHandler(&archiveHandler)) std::wstring rootPath(v.path); rootPath += L"\\"; archiveExtractCallback->Init(archive, fileEnumeratorCallback, rootPath); //RINOK(archiveHandler->Extract(NULL, (UInt32)(Int32)(-1), 0, archiveExtractCallback)) RINOK(archive->Extract(NULL, (UInt32)(Int32)(-1), 0, archiveExtractCallback)) return S_OK; }
HRESULT CZipDecoder::Decode( CInArchive &archive, const CItemEx &item, ISequentialOutStream *realOutStream, IArchiveExtractCallback *_extractCallback, quint32 numThreads, qint32 &res) { RefPtr<IArchiveExtractCallback> extractCallback(_extractCallback); res = NArchive::NExtract::NOperationResult::kDataError; CInStreamReleaser inStreamReleaser; bool needCRC = true; bool aesMode = false; #ifdef ZIP_STRONG_SUPORT bool pkAesMode = false; #endif quint16 methodId = item.CompressionMethod; if (item.IsEncrypted()) { if (item.IsStrongEncrypted()) { #ifdef ZIP_STRONG_SUPORT CStrongCryptoField f; if (item.CentralExtra.GetStrongCryptoField(f)) { pkAesMode = true; } if (!pkAesMode) #endif { res = NArchive::NExtract::NOperationResult::kUnSupportedMethod; return S_OK; } } if (methodId == NFileHeader::NCompressionMethod::kWzAES) { CWzAesExtraField aesField; if (item.CentralExtra.GetWzAesField(aesField)) { aesMode = true; needCRC = aesField.NeedCrc(); } } } COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC; RefPtr<ISequentialOutStream> outStream = outStreamSpec; outStreamSpec->SetStream(realOutStream); outStreamSpec->Init(needCRC); quint64 authenticationPos; RefPtr<ISequentialInStream> inStream; { quint64 packSize = item.PackSize; if (aesMode) { if (packSize < NCrypto::NWzAES::kMacSize) return S_OK; packSize -= NCrypto::NWzAES::kMacSize; } quint64 dataPos = item.GetDataPosition(); inStream = archive.CreateLimitedStream(dataPos, packSize); authenticationPos = dataPos + packSize; } RefPtr<ICompressFilter> cryptoFilter; if (item.IsEncrypted()) { if (aesMode) { CWzAesExtraField aesField; if (!item.CentralExtra.GetWzAesField(aesField)) return S_OK; methodId = aesField.Method; if (!_aesDecoder) { _aesDecoderSpec = new NCrypto::NWzAES::CDecoder; _aesDecoder = _aesDecoderSpec; } cryptoFilter = _aesDecoder; quint8 properties = aesField.Strength; RINOK(_aesDecoderSpec->SetDecoderProperties2(&properties, 1)); } #ifdef ZIP_STRONG_SUPORT else if (pkAesMode) { if (!_zsDecoder) { _zsDecoderSpec = new NCrypto::NZipStrong::CDecoder; _zsDecoder = _zsDecoderSpec; } cryptoFilter = _zsDecoder; } #endif else { if (!_zipCryptoDecoder) { _zipCryptoDecoderSpec = new NCrypto::NZip::CDecoder; _zipCryptoDecoder = _zipCryptoDecoderSpec; } cryptoFilter = _zipCryptoDecoder; } RefPtr<ICryptoSetPassword> cryptoSetPassword; RINOK(cryptoFilter.QueryInterface(&cryptoSetPassword)); if (!getTextPassword) extractCallback.QueryInterface(&getTextPassword); if (getTextPassword) { QString password; RINOK(getTextPassword->CryptoGetTextPassword(&password)); QByteArray charPassword; if (aesMode #ifdef ZIP_STRONG_SUPORT || pkAesMode #endif ) { charPassword = password.toUtf8(); /* 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 = password.toLocal8Bit(); } HRESULT res = cryptoSetPassword->CryptoSetPassword( (const quint8 *)charPassword.constData(), charPassword.length()); if (res != 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 { 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 + (quint8)methodId; } QObject *dec = CreateDecoderForId(szMethodID); if (dec) mi.Coder = qobject_cast<ICompressCoder *>(dec); if (mi.Coder == 0) { delete dec; res = NArchive::NExtract::NOperationResult::kUnSupportedMethod; return S_OK; } } methodItems.append(new CMethodItem(mi)); m = methodItems.size() - 1; } RefPtr<ICompressCoder> coder(methodItems[m]->Coder); { RefPtr<ICompressSetDecoderProperties2> setDecoderProperties; coder.QueryInterface(&setDecoderProperties); if (setDecoderProperties) { quint8 properties = (quint8)item.Flags; RINOK(setDecoderProperties->SetDecoderProperties2(&properties, 1)); } } #ifdef THREADED { RefPtr<ICompressSetCoderMt> setCoderMt; coder.QueryInterface(&setCoderMt); if (setCoderMt) { RINOK(setCoderMt->SetNumberOfThreads(numThreads)); } } #endif { HRESULT result; RefPtr<ISequentialInStream> inStreamNew; if (item.IsEncrypted()) { if (!filterStream) { filterStreamSpec = new CFilterCoder; filterStream = filterStreamSpec; } filterStreamSpec->setFilter(cryptoFilter); if (aesMode) { RINOK(_aesDecoderSpec->ReadHeader(inStream)); } #ifdef ZIP_STRONG_SUPORT else if (pkAesMode) { RINOK(_zsDecoderSpec->ReadHeader(inStream)); } #endif else { RINOK(_zipCryptoDecoderSpec->ReadHeader(inStream)); } RINOK(filterStreamSpec->SetInStream(inStream)); inStreamReleaser.FilterCoder = filterStreamSpec; inStreamNew = filterStream; if (aesMode) { if (!_aesDecoderSpec->CheckPasswordVerifyCode()) return S_OK; } } else inStreamNew = inStream; result = coder->Code(inStreamNew, outStream, NULL, &item.UnPackSize); if (result == S_FALSE) return S_OK; RINOK(result); } bool crcOK = true; bool authOk = true; if (needCRC) crcOK = (outStreamSpec->GetCRC() == item.FileCRC); if (aesMode) { inStream = archive.CreateLimitedStream(authenticationPos, NCrypto::NWzAES::kMacSize); if (_aesDecoderSpec->CheckMac(inStream, authOk) != S_OK) authOk = false; } res = ((crcOK && authOk) ? NArchive::NExtract::NOperationResult::kOK : NArchive::NExtract::NOperationResult::kCRCError); return S_OK; }
STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *callback) { COM_TRY_BEGIN Close(); HRESULT res = S_FALSE; CInArchive archive; CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback; callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback); CMyComPtr<IInStream> nextStream = inStream; bool prevChecked = false; UInt64 numItems = 0; try { while (nextStream != 0) { CDatabaseEx db; db.Stream = nextStream; res = archive.Open(maxCheckStartPosition, db); if (res == S_OK) { if (!m_Database.Volumes.IsEmpty()) { const CDatabaseEx &dbPrev = m_Database.Volumes[prevChecked ? m_Database.Volumes.Size() - 1 : 0]; if (dbPrev.ArchiveInfo.SetID != db.ArchiveInfo.SetID || dbPrev.ArchiveInfo.CabinetNumber + (prevChecked ? 1: - 1) != db.ArchiveInfo.CabinetNumber) res = S_FALSE; } } if (res == S_OK) m_Database.Volumes.Insert(prevChecked ? m_Database.Volumes.Size() : 0, db); else if (res != S_FALSE) return res; else { if (m_Database.Volumes.IsEmpty()) return S_FALSE; if (prevChecked) break; prevChecked = true; } numItems += db.Items.Size(); RINOK(callback->SetCompleted(&numItems, NULL)); nextStream = 0; for (;;) { const COtherArchive *otherArchive = 0; if (!prevChecked) { const CInArchiveInfo &ai = m_Database.Volumes.Front().ArchiveInfo; if (ai.IsTherePrev()) otherArchive = &ai.PrevArc; else prevChecked = true; } if (otherArchive == 0) { const CInArchiveInfo &ai = m_Database.Volumes.Back().ArchiveInfo; if (ai.IsThereNext()) otherArchive = &ai.NextArc; } if (!otherArchive) break; const UString fullName = MultiByteToUnicodeString(otherArchive->FileName, CP_ACP); if (!openVolumeCallback) break; HRESULT result = openVolumeCallback->GetStream(fullName, &nextStream); if (result == S_OK) break; if (result != S_FALSE) return result; if (prevChecked) break; prevChecked = true; } } if (res == S_OK) { m_Database.FillSortAndShrink(); if (!m_Database.Check()) res = S_FALSE; } } catch(...) { res = S_FALSE; } if (res != S_OK) { Close(); return res; } COM_TRY_END return S_OK; }
STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *callback) { COM_TRY_BEGIN Close(); CInArchive archive; CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback; callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback); CMyComPtr<IInStream> nextStream = inStream; bool prevChecked = false; UInt64 numItems = 0; unsigned numTempVolumes = 0; // try { while (nextStream != NULL) { CDatabaseEx db; db.Stream = nextStream; HRESULT res = archive.Open(db, maxCheckStartPosition); _errorInHeaders |= archive.HeaderError; _errorInHeaders |= archive.ErrorInNames; _unexpectedEnd |= archive.UnexpectedEnd; if (res == S_OK && !m_Database.Volumes.IsEmpty()) { const CArchInfo &lastArc = m_Database.Volumes.Back().ArcInfo; unsigned cabNumber = db.ArcInfo.CabinetNumber; if (lastArc.SetID != db.ArcInfo.SetID) res = S_FALSE; else if (prevChecked) { if (cabNumber != lastArc.CabinetNumber + 1) res = S_FALSE; } else if (cabNumber >= lastArc.CabinetNumber) res = S_FALSE; else if (numTempVolumes != 0) { const CArchInfo &prevArc = m_Database.Volumes[numTempVolumes - 1].ArcInfo; if (cabNumber != prevArc.CabinetNumber + 1) res = S_FALSE; } } if (archive.IsArc || res == S_OK) { _isArc = true; if (m_Database.Volumes.IsEmpty()) { _offset = db.StartPosition; _phySize = db.ArcInfo.Size; } } if (res == S_OK) { numItems += db.Items.Size(); m_Database.Volumes.Insert(prevChecked ? m_Database.Volumes.Size() : numTempVolumes, db); if (!prevChecked && m_Database.Volumes.Size() > 1) { numTempVolumes++; if (db.ArcInfo.CabinetNumber + 1 == m_Database.Volumes[numTempVolumes].ArcInfo.CabinetNumber) numTempVolumes = 0; } } else { if (res != S_FALSE) return res; if (m_Database.Volumes.IsEmpty()) return S_FALSE; if (prevChecked) break; prevChecked = true; if (numTempVolumes != 0) { m_Database.Volumes.DeleteFrontal(numTempVolumes); numTempVolumes = 0; } } RINOK(callback->SetCompleted(&numItems, NULL)); nextStream = NULL; for (;;) { const COtherArc *otherArc = NULL; if (!prevChecked) { if (numTempVolumes == 0) { const CInArcInfo &ai = m_Database.Volumes[0].ArcInfo; if (ai.IsTherePrev()) otherArc = &ai.PrevArc; else prevChecked = true; } else { const CInArcInfo &ai = m_Database.Volumes[numTempVolumes - 1].ArcInfo; if (ai.IsThereNext()) otherArc = &ai.NextArc; else { prevChecked = true; m_Database.Volumes.DeleteFrontal(numTempVolumes); numTempVolumes = 0; } } } if (!otherArc) { const CInArcInfo &ai = m_Database.Volumes.Back().ArcInfo; if (ai.IsThereNext()) otherArc = &ai.NextArc; } if (!otherArc) break; if (!openVolumeCallback) break; // printf("\n%s", otherArc->FileName); const UString fullName = MultiByteToUnicodeString(otherArc->FileName, CP_ACP); HRESULT result = openVolumeCallback->GetStream(fullName, &nextStream); if (result == S_OK) break; if (result != S_FALSE) return result; if (!_errorMessage.IsEmpty()) _errorMessage.Add_LF(); _errorMessage.AddAscii("Can't open volume: "); _errorMessage += fullName; if (prevChecked) break; prevChecked = true; if (numTempVolumes != 0) { m_Database.Volumes.DeleteFrontal(numTempVolumes); numTempVolumes = 0; } } } // read nextStream iteration if (numTempVolumes != 0) { m_Database.Volumes.DeleteFrontal(numTempVolumes); numTempVolumes = 0; } if (m_Database.Volumes.IsEmpty()) return S_FALSE; else { m_Database.FillSortAndShrink(); if (!m_Database.Check()) return S_FALSE; } } COM_TRY_END return S_OK; }