rarhandler.cpp
来自「由7-zip提供的压缩、解压缩程序」· C++ 代码 · 共 943 行 · 第 1/2 页
CPP
943 行
if (_archives.IsEmpty()) archive.GetArchiveInfo(_archiveInfo); CItemEx item; while(true) { HRESULT result = archive.GetNextItem(item, getTextPassword); if (result == S_FALSE) break; RINOK(result); if (item.IgnoreItem()) continue; bool needAdd = true; if (item.IsSplitBefore()) { if (!_refItems.IsEmpty()) { CRefItem &refItem = _refItems.Back(); refItem.NumItems++; needAdd = false; } } if (needAdd) { CRefItem refItem; refItem.ItemIndex = _items.Size(); refItem.NumItems = 1; refItem.VolumeIndex = _archives.Size(); _refItems.Add(refItem); } _items.Add(item); if (openArchiveCallback != NULL) { UInt64 numFiles = _items.Size(); RINOK(openArchiveCallback->SetCompleted(&numFiles, NULL)); } } _archives.Add(archive); } } catch(...) { return S_FALSE; } return S_OK; COM_TRY_END}STDMETHODIMP CHandler::Close(){ COM_TRY_BEGIN _refItems.Clear(); _items.Clear(); _archives.Clear(); return S_OK; COM_TRY_END}struct CMethodItem{ Byte RarUnPackVersion; CMyComPtr<ICompressCoder> Coder;};STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems, Int32 _aTestMode, IArchiveExtractCallback *_anExtractCallback){ COM_TRY_BEGIN CMyComPtr<ICryptoGetTextPassword> getTextPassword; bool testMode = (_aTestMode != 0); CMyComPtr<IArchiveExtractCallback> extractCallback = _anExtractCallback; UInt64 censoredTotalUnPacked = 0, // censoredTotalPacked = 0, importantTotalUnPacked = 0; // importantTotalPacked = 0; bool allFilesMode = (numItems == UInt32(-1)); if (allFilesMode) numItems = _refItems.Size(); if(numItems == 0) return S_OK; int lastIndex = 0; CRecordVector<int> importantIndexes; CRecordVector<bool> extractStatuses; for(UInt32 t = 0; t < numItems; t++) { int index = allFilesMode ? t : indices[t]; const CRefItem &refItem = _refItems[index]; const CItemEx &item = _items[refItem.ItemIndex]; censoredTotalUnPacked += item.UnPackSize; // censoredTotalPacked += item.PackSize; int j; for(j = lastIndex; j <= index; j++) // if(!_items[_refItems[j].ItemIndex].IsSolid()) if(!IsSolid(j)) lastIndex = j; for(j = lastIndex; j <= index; j++) { const CRefItem &refItem = _refItems[j]; const CItemEx &item = _items[refItem.ItemIndex]; // const CItemEx &item = _items[j]; importantTotalUnPacked += item.UnPackSize; // importantTotalPacked += item.PackSize; importantIndexes.Add(j); extractStatuses.Add(j == index); } lastIndex = index + 1; } extractCallback->SetTotal(importantTotalUnPacked); UInt64 currentImportantTotalUnPacked = 0; UInt64 currentImportantTotalPacked = 0; UInt64 currentUnPackSize, currentPackSize; /* CSysString path = GetCodecsFolderPrefix() + TEXT("Rar29.dll"); TCHAR compressLibPath[MAX_PATH + 64]; if (!GetCompressFolderPrefix(compressLibPath)) return ::GetLastError(); lstrcat(compressLibPath, TEXT("Rar29.dll")); */ N7z::LoadMethodMap(); CCoderLibraries libraries; CObjectVector<CMethodItem> methodItems; /* CCoderLibrary compressLib; CMyComPtr<ICompressCoder> decoder15; CMyComPtr<ICompressCoder> decoder20; CMyComPtr<ICompressCoder> decoder29; */ NCompress::CCopyCoder *copyCoderSpec = NULL; CMyComPtr<ICompressCoder> copyCoder; // CCoderMixer *mixerCoderSpec; // CMyComPtr<ICompressCoder> mixerCoder; // bool mixerCoderStoreMethod; // int mixerCryptoVersion; CFilterCoder *filterStreamSpec = new CFilterCoder; CMyComPtr<ISequentialInStream> filterStream = filterStreamSpec; NCrypto::NRar20::CDecoder *rar20CryptoDecoderSpec; CMyComPtr<ICompressFilter> rar20CryptoDecoder; NCrypto::NRar29::CDecoder *rar29CryptoDecoderSpec; CMyComPtr<ICompressFilter> rar29CryptoDecoder; CFolderInStream *folderInStreamSpec = NULL; CMyComPtr<ISequentialInStream> folderInStream; for(int i = 0; i < importantIndexes.Size(); i++, currentImportantTotalUnPacked += currentUnPackSize, currentImportantTotalPacked += currentPackSize) { RINOK(extractCallback->SetCompleted( ¤tImportantTotalUnPacked)); CMyComPtr<ISequentialOutStream> realOutStream; Int32 askMode; if(extractStatuses[i]) askMode = testMode ? NArchive::NExtract::NAskMode::kTest : NArchive::NExtract::NAskMode::kExtract; else askMode = NArchive::NExtract::NAskMode::kSkip; UInt32 index = importantIndexes[i]; const CRefItem &refItem = _refItems[index]; const CItemEx &item = _items[refItem.ItemIndex]; currentUnPackSize = item.UnPackSize; currentPackSize = GetPackSize(index); if(item.IgnoreItem()) continue; RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); if(item.IsDirectory()) { RINOK(extractCallback->PrepareOperation(askMode)); RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK)); continue; } bool mustBeProcessedAnywhere = false; if(i < importantIndexes.Size() - 1) { // const CRefItem &nextRefItem = _refItems[importantIndexes[i + 1]]; // const CItemEx &nextItemInfo = _items[nextRefItem.ItemIndex]; // mustBeProcessedAnywhere = nextItemInfo.IsSolid(); mustBeProcessedAnywhere = IsSolid(importantIndexes[i + 1]); } if (!mustBeProcessedAnywhere && !testMode && !realOutStream) continue; if (!realOutStream && !testMode) askMode = NArchive::NExtract::NAskMode::kSkip; RINOK(extractCallback->PrepareOperation(askMode)); COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC; CMyComPtr<ISequentialOutStream> outStream(outStreamSpec); outStreamSpec->Init(realOutStream); realOutStream.Release(); UInt64 packedPos = currentImportantTotalPacked; UInt64 unpackedPos = currentImportantTotalUnPacked; /* for (int partIndex = 0; partIndex < 1; partIndex++) { CMyComPtr<ISequentialInStream> inStream; // item redefinition const CItemEx &item = _items[refItem.ItemIndex + partIndex]; NArchive::NRar::CInArchive &archive = _archives[refItem.VolumeIndex + partIndex]; inStream.Attach(archive.CreateLimitedStream(item.GetDataPosition(), item.PackSize)); */ if (!folderInStream) { folderInStreamSpec = new CFolderInStream; folderInStream = folderInStreamSpec; } folderInStreamSpec->Init(&_archives, &_items, refItem); CLocalProgress *localProgressSpec = new CLocalProgress; CMyComPtr<ICompressProgressInfo> progress = localProgressSpec; localProgressSpec->Init(extractCallback, false); CLocalCompressProgressInfo *localCompressProgressSpec = new CLocalCompressProgressInfo; CMyComPtr<ICompressProgressInfo> compressProgress = localCompressProgressSpec; localCompressProgressSpec->Init(progress, &packedPos, &unpackedPos); UInt64 packSize = currentPackSize; // packedPos += item.PackSize; // unpackedPos += 0; CMyComPtr<ISequentialInStream> inStream; if (item.IsEncrypted()) { CMyComPtr<ICryptoSetPassword> cryptoSetPassword; if (item.UnPackVersion >= 29) { if (!rar29CryptoDecoder) { rar29CryptoDecoderSpec = new NCrypto::NRar29::CDecoder; rar29CryptoDecoder = rar29CryptoDecoderSpec; // RINOK(rar29CryptoDecoder.CoCreateInstance(CLSID_CCryptoRar29Decoder)); } rar29CryptoDecoderSpec->SetRar350Mode(item.UnPackVersion < 36); CMyComPtr<ICompressSetDecoderProperties2> cryptoProperties; RINOK(rar29CryptoDecoder.QueryInterface(IID_ICompressSetDecoderProperties2, &cryptoProperties)); RINOK(cryptoProperties->SetDecoderProperties2(item.Salt, item.HasSalt() ? sizeof(item.Salt) : 0)); filterStreamSpec->Filter = rar29CryptoDecoder; } else if (item.UnPackVersion >= 20) { if (!rar20CryptoDecoder) { rar20CryptoDecoderSpec = new NCrypto::NRar20::CDecoder; rar20CryptoDecoder = rar20CryptoDecoderSpec; // RINOK(rar20CryptoDecoder.CoCreateInstance(CLSID_CCryptoRar20Decoder)); } filterStreamSpec->Filter = rar20CryptoDecoder; } else { outStream.Release(); RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kUnSupportedMethod)); continue; } RINOK(filterStreamSpec->Filter.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword)); if (!getTextPassword) extractCallback.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword); if (getTextPassword) { CMyComBSTR password; RINOK(getTextPassword->CryptoGetTextPassword(&password)); if (item.UnPackVersion >= 29) { CByteBuffer buffer; UString unicodePassword(password); const UInt32 sizeInBytes = unicodePassword.Length() * 2; buffer.SetCapacity(sizeInBytes); for (int i = 0; i < unicodePassword.Length(); i++) { wchar_t c = unicodePassword[i]; ((Byte *)buffer)[i * 2] = (Byte)c; ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8); } RINOK(cryptoSetPassword->CryptoSetPassword( (const Byte *)buffer, sizeInBytes)); } else { AString oemPassword = UnicodeStringToMultiByte( (const wchar_t *)password, CP_OEMCP); RINOK(cryptoSetPassword->CryptoSetPassword( (const Byte *)(const char *)oemPassword, oemPassword.Length())); } } else { RINOK(cryptoSetPassword->CryptoSetPassword(0, 0)); } filterStreamSpec->SetInStream(folderInStream); inStream = filterStream; } else { inStream = folderInStream; } CMyComPtr<ICompressCoder> commonCoder; switch(item.Method) { case '0': { if(copyCoderSpec == NULL) { copyCoderSpec = new NCompress::CCopyCoder; copyCoder = copyCoderSpec; } commonCoder = copyCoder; break; } case '1': case '2': case '3': case '4': case '5': { /* if (item.UnPackVersion >= 29) { outStream.Release(); RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kUnSupportedMethod)); continue; } */ int m; for (m = 0; m < methodItems.Size(); m++) if (methodItems[m].RarUnPackVersion == item.UnPackVersion) break; if (m == methodItems.Size()) { CMethodItem mi; mi.RarUnPackVersion = item.UnPackVersion; N7z::CMethodID methodID = { { 0x04, 0x03 } , 3 }; Byte myID; if (item.UnPackVersion < 20) myID = 1; else if (item.UnPackVersion < 29) myID = 2; else myID = 3; methodID.ID[2] = myID; N7z::CMethodInfo methodInfo; if (!N7z::GetMethodInfo(methodID, methodInfo)) { RINOK(extractCallback->SetOperationResult( NArchive::NExtract::NOperationResult::kUnSupportedMethod)); continue; } RINOK(libraries.CreateCoder(methodInfo.FilePath, methodInfo.Decoder, &mi.Coder)); m = methodItems.Add(mi); } CMyComPtr<ICompressCoder> decoder = methodItems[m].Coder; CMyComPtr<ICompressSetDecoderProperties2> compressSetDecoderProperties; RINOK(decoder.QueryInterface(IID_ICompressSetDecoderProperties2, &compressSetDecoderProperties)); Byte isSolid = (IsSolid(index) || item.IsSplitBefore()) ? 1: 0; RINOK(compressSetDecoderProperties->SetDecoderProperties2(&isSolid, 1)); commonCoder = decoder; break; } default: outStream.Release(); RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kUnSupportedMethod)); continue; } HRESULT result = commonCoder->Code(inStream, outStream, &packSize, &item.UnPackSize, compressProgress); if (item.IsEncrypted()) filterStreamSpec->ReleaseInStream(); if (result == S_FALSE) { outStream.Release(); RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kDataError)); continue; } if (result != S_OK) return result; /* if (refItem.NumItems == 1 && !item.IsSplitBefore() && !item.IsSplitAfter()) */ { const CItemEx &lastItem = _items[refItem.ItemIndex + refItem.NumItems - 1]; bool crcOK = outStreamSpec->GetCRC() == lastItem.FileCRC; outStream.Release(); RINOK(extractCallback->SetOperationResult(crcOK ? NArchive::NExtract::NOperationResult::kOK: NArchive::NExtract::NOperationResult::kCRCError)); } /* else { bool crcOK = true; for (int partIndex = 0; partIndex < refItem.NumItems; partIndex++) { const CItemEx &item = _items[refItem.ItemIndex + partIndex]; if (item.FileCRC != folderInStreamSpec->CRCs[partIndex]) { crcOK = false; break; } } RINOK(extractCallback->SetOperationResult(crcOK ? NArchive::NExtract::NOperationResult::kOK: NArchive::NExtract::NOperationResult::kCRCError)); } */ } return S_OK; COM_TRY_END}/*STDMETHODIMP CHandler::ExtractAllItems(Int32 testMode, IArchiveExtractCallback *extractCallback){ COM_TRY_BEGIN CRecordVector<UInt32> indices; indices.Reserve(_refItems.Size()); for(int i = 0; i < _refItems.Size(); i++) indices.Add(i); return Extract(&indices.Front(), _refItems.Size(), testMode, extractCallback); COM_TRY_END}*/}}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?