void CPanel::CreateFileMenu(HMENU menuSpec, CMyComPtr<IContextMenu> &sevenZipContextMenu, CMyComPtr<IContextMenu> &systemContextMenu, bool programMenu) { sevenZipContextMenu.Release(); systemContextMenu.Release(); CRecordVector<UInt32> operatedIndices; GetOperatedItemIndices(operatedIndices); CMenu menu; menu.Attach(menuSpec); CreateSevenZipMenu(menu, operatedIndices, sevenZipContextMenu); if (g_App.ShowSystemMenu) CreateSystemMenu(menu, operatedIndices, systemContextMenu); /* if (menu.GetItemCount() > 0) menu.AppendItem(MF_SEPARATOR, 0, (LPCTSTR)0); */ int i; for (i = 0; i < operatedIndices.Size(); i++) if (IsItemFolder(operatedIndices[i])) break; bool allAreFiles = (i == operatedIndices.Size()); LoadFileMenu(menu, menu.GetItemCount(), programMenu, IsFSFolder(), operatedIndices.Size(), allAreFiles); }
HRESULT CFolderOutStream::CloseFileWithResOp(Int32 resOp) { m_RealOutStream.Release(); m_FileIsOpen = false; NumIdenticalFiles--; return m_ExtractCallback->SetOperationResult(resOp); }
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 = _sections.Size(); if (numItems == 0) return S_OK; UInt64 totalSize = 0; UInt32 i; for (i = 0; i < numItems; i++) totalSize += _sections[allFilesMode ? i : indices[i]].GetPackSize(); extractCallback->SetTotal(totalSize); UInt64 currentTotalSize = 0; UInt64 currentItemSize; NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; CLocalProgress *lps = new CLocalProgress; CMyComPtr<ICompressProgressInfo> progress = lps; lps->Init(extractCallback, false); CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; CMyComPtr<ISequentialInStream> inStream(streamSpec); streamSpec->SetStream(_inStream); for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize) { lps->InSize = lps->OutSize = currentTotalSize; RINOK(lps->SetCur()); Int32 askMode = testMode ? NArchive::NExtract::NAskMode::kTest : NArchive::NExtract::NAskMode::kExtract; UInt32 index = allFilesMode ? i : indices[i]; const CSection &item = _sections[index]; currentItemSize = item.GetPackSize(); CMyComPtr<ISequentialOutStream> outStream; RINOK(extractCallback->GetStream(index, &outStream, askMode)); if (!testMode && !outStream) continue; RINOK(extractCallback->PrepareOperation(askMode)); RINOK(_inStream->Seek(item.Pa, STREAM_SEEK_SET, NULL)); streamSpec->Init(currentItemSize); RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)); outStream.Release(); RINOK(extractCallback->SetOperationResult(copyCoderSpec->TotalSize == currentItemSize ? NArchive::NExtract::NOperationResult::kOK: NArchive::NExtract::NOperationResult::kDataError)); } return S_OK; COM_TRY_END }
HRESULT CChmFolderOutStream::OpenFile() { Int32 askMode = (*m_ExtractStatuses)[m_CurrentIndex] ? (m_TestMode ? NExtract::NAskMode::kTest : NExtract::NAskMode::kExtract) : NExtract::NAskMode::kSkip; m_RealOutStream.Release(); RINOK(m_ExtractCallback->GetStream(m_StartIndex + m_CurrentIndex, &m_RealOutStream, askMode)); if (!m_RealOutStream && !m_TestMode) askMode = NExtract::NAskMode::kSkip; return m_ExtractCallback->PrepareOperation(askMode); }
HRESULT COutVolumeStream::Flush() { if (_volumeStream) { _file.UnPackSize = _curPos; _file.FileCRC = _crc.GetDigest(); RINOK(WriteVolumeHeader(_archive, _file, _options)); _archive.Close(); _volumeStream.Release(); _file.StartPos += _file.UnPackSize; } return S_OK; }
HRESULT CFolderOutStream::Unsupported() { while(m_CurrentIndex < m_ExtractStatuses->Size()) { HRESULT result = OpenFile(); if (result != S_FALSE && result != S_OK) return result; m_RealOutStream.Release(); RINOK(m_ExtractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod)); m_CurrentIndex++; } return S_OK; }
HRESULT CChmFolderOutStream::WriteEmptyFiles() { if (m_FileIsOpen) return S_OK; for (;m_CurrentIndex < m_NumFiles; m_CurrentIndex++) { UInt64 fileSize = m_Database->GetFileSize(m_StartIndex + m_CurrentIndex); if (fileSize != 0) return S_OK; HRESULT result = OpenFile(); m_RealOutStream.Release(); RINOK(result); RINOK(m_ExtractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); } return S_OK; }
void CPanel::CreateSevenZipMenu(HMENU menuSpec, const CRecordVector<UInt32> &operatedIndices, CMyComPtr<IContextMenu> &sevenZipContextMenu) { sevenZipContextMenu.Release(); CMenu menu; menu.Attach(menuSpec); // CMenuDestroyer menuDestroyer(menu); // menu.CreatePopup(); bool sevenZipMenuCreated = false; CZipContextMenu *contextMenuSpec = new CZipContextMenu; CMyComPtr<IContextMenu> contextMenu = contextMenuSpec; // if (contextMenu.CoCreateInstance(CLSID_CZipContextMenu, IID_IContextMenu) == S_OK) { /* CMyComPtr<IInitContextMenu> initContextMenu; if (contextMenu.QueryInterface(IID_IInitContextMenu, &initContextMenu) != S_OK) return; */ UString currentFolderUnicode = _currentFolderPrefix; UStringVector names; int i; for(i = 0; i < operatedIndices.Size(); i++) names.Add(currentFolderUnicode + GetItemRelPath(operatedIndices[i])); CRecordVector<const wchar_t *> namePointers; for(i = 0; i < operatedIndices.Size(); i++) namePointers.Add(names[i]); // NFile::NDirectory::MySetCurrentDirectory(currentFolderUnicode); if (contextMenuSpec->InitContextMenu(currentFolderUnicode, &namePointers.Front(), operatedIndices.Size()) == S_OK) { HRESULT res = contextMenu->QueryContextMenu(menu, 0, kSevenZipStartMenuID, kSystemStartMenuID - 1, 0); sevenZipMenuCreated = (HRESULT_SEVERITY(res) == SEVERITY_SUCCESS); if (sevenZipMenuCreated) sevenZipContextMenu = contextMenu; // int code = HRESULT_CODE(res); // int nextItemID = code; } } }
HRESULT CFolderOutStream::WriteEmptyFiles() { if (m_FileIsOpen) return S_OK; for (; m_CurrentIndex < m_ExtractStatuses->Size(); m_CurrentIndex++) { const CMvItem &mvItem = m_Database->Items[m_StartIndex + m_CurrentIndex]; const CItem &item = m_Database->Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex]; UInt64 fileSize = item.Size; if (fileSize != 0) return S_OK; HRESULT result = OpenFile(); m_RealOutStream.Release(); RINOK(result); RINOK(m_ExtractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); } return S_OK; }
STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) { COM_TRY_BEGIN bool allFilesMode = (numItems == (UInt32)(Int32)-1); if (allFilesMode) numItems = _archive.Refs.Size(); if (numItems == 0) return S_OK; UInt64 totalSize = 0; UInt32 i; for (i = 0; i < numItems; i++) { UInt32 index = (allFilesMode ? i : indices[i]); if (index < (UInt32)_archive.Refs.Size()) { const CRef &ref = _archive.Refs[index]; const CDir &item = ref.Dir->_subItems[ref.Index]; if (!item.IsDir()) totalSize += ref.TotalSize; } else totalSize += _archive.GetBootItemSize(index - _archive.Refs.Size()); } extractCallback->SetTotal(totalSize); UInt64 currentTotalSize = 0; UInt64 currentItemSize; NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; CLocalProgress *lps = new CLocalProgress; CMyComPtr<ICompressProgressInfo> progress = lps; lps->Init(extractCallback, false); CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; CMyComPtr<ISequentialInStream> inStream(streamSpec); streamSpec->SetStream(_stream); for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize) { lps->InSize = lps->OutSize = currentTotalSize; RINOK(lps->SetCur()); currentItemSize = 0; CMyComPtr<ISequentialOutStream> realOutStream; Int32 askMode = testMode ? NExtract::NAskMode::kTest : NExtract::NAskMode::kExtract; UInt32 index = allFilesMode ? i : indices[i]; RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); UInt64 blockIndex; if (index < (UInt32)_archive.Refs.Size()) { const CRef &ref = _archive.Refs[index]; const CDir &item = ref.Dir->_subItems[ref.Index]; if (item.IsDir()) { RINOK(extractCallback->PrepareOperation(askMode)); RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); continue; } currentItemSize = ref.TotalSize; blockIndex = item.ExtentLocation; } else { unsigned bootIndex = index - _archive.Refs.Size(); const CBootInitialEntry &be = _archive.BootEntries[bootIndex]; currentItemSize = _archive.GetBootItemSize(bootIndex); blockIndex = be.LoadRBA; } if (!testMode && !realOutStream) continue; RINOK(extractCallback->PrepareOperation(askMode)); bool isOK = true; if (index < (UInt32)_archive.Refs.Size()) { const CRef &ref = _archive.Refs[index]; UInt64 offset = 0; for (UInt32 e = 0; e < ref.NumExtents; e++) { lps->InSize = lps->OutSize = currentTotalSize + offset; const CDir &item2 = ref.Dir->_subItems[ref.Index + e]; RINOK(_stream->Seek((UInt64)item2.ExtentLocation * kBlockSize, STREAM_SEEK_SET, NULL)); streamSpec->Init(item2.Size); RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress)); if (copyCoderSpec->TotalSize != item2.Size) { isOK = false; break; } offset += item2.Size; } } else { RINOK(_stream->Seek((UInt64)blockIndex * kBlockSize, STREAM_SEEK_SET, NULL)); streamSpec->Init(currentItemSize); RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress)); if (copyCoderSpec->TotalSize != currentItemSize) isOK = false; } realOutStream.Release(); RINOK(extractCallback->SetOperationResult(isOK ? NExtract::NOperationResult::kOK: NExtract::NOperationResult::kDataError)); } return S_OK; COM_TRY_END }
HRESULT CompressFiles(const CObjectVector<PluginPanelItem> &pluginPanelItems) { if (pluginPanelItems.Size() == 0) return E_FAIL; UStringVector fileNames; int i; for (i = 0; i < pluginPanelItems.Size(); i++) { const PluginPanelItem &panelItem = pluginPanelItems[i]; if (strcmp(panelItem.FindData.cFileName, "..") == 0 && NFind::NAttributes::IsDir(panelItem.FindData.dwFileAttributes)) return E_FAIL; if (strcmp(panelItem.FindData.cFileName, ".") == 0 && NFind::NAttributes::IsDir(panelItem.FindData.dwFileAttributes)) return E_FAIL; FString fullPath; FString fileNameUnicode = us2fs(MultiByteToUnicodeString(panelItem.FindData.cFileName, CP_OEMCP)); if (!MyGetFullPathName(fileNameUnicode, fullPath)) return E_FAIL; fileNames.Add(fs2us(fullPath)); } NCompression::CInfo compressionInfo; compressionInfo.Load(); int archiverIndex = 0; CCodecs *codecs = new CCodecs; CMyComPtr<ICompressCodecsInfo> compressCodecsInfo = codecs; if (codecs->Load() != S_OK) throw "Can't load 7-Zip codecs"; { for (int i = 0; i < codecs->Formats.Size(); i++) { const CArcInfoEx &arcInfo = codecs->Formats[i]; if (arcInfo.UpdateEnabled) { if (archiverIndex == -1) archiverIndex = i; if (arcInfo.Name.CompareNoCase(compressionInfo.ArcType) == 0) archiverIndex = i; } } } UString resultPath; { CParsedPath parsedPath; parsedPath.ParsePath(fileNames.Front()); if (parsedPath.PathParts.Size() == 0) return E_FAIL; if (fileNames.Size() == 1 || parsedPath.PathParts.Size() == 1) { // CSysString pureName, dot, extension; resultPath = parsedPath.PathParts.Back(); } else { parsedPath.PathParts.DeleteBack(); resultPath = parsedPath.PathParts.Back(); } } UString archiveNameSrc = resultPath; UString archiveName = archiveNameSrc; const CArcInfoEx &arcInfo = codecs->Formats[archiverIndex]; int prevFormat = archiverIndex; if (!arcInfo.KeepName) { int dotPos = archiveName.ReverseFind('.'); int slashPos = MyMax(archiveName.ReverseFind('\\'), archiveName.ReverseFind('/')); if (dotPos > slashPos) archiveName = archiveName.Left(dotPos); } archiveName += L'.'; archiveName += arcInfo.GetMainExt(); const CActionSet *actionSet = &kAddActionSet; for (;;) { AString archiveNameA = UnicodeStringToMultiByte(archiveName, CP_OEMCP); const int kYSize = 16; const int kXMid = 38; const int kArchiveNameIndex = 2; const int kMethodRadioIndex = kArchiveNameIndex + 2; const int kModeRadioIndex = kMethodRadioIndex + 7; const CArcInfoEx &arcInfo = codecs->Formats[archiverIndex]; char updateAddToArchiveString[512]; const AString s = UnicodeStringToMultiByte(arcInfo.Name, CP_OEMCP); sprintf(updateAddToArchiveString, g_StartupInfo.GetMsgString(NMessageID::kUpdateAddToArchive), (const char *)s); int methodIndex = 0; int i; for (i = sizeof(g_MethodMap) / sizeof(g_MethodMap[0]) - 1; i >= 0; i--) if (compressionInfo.Level >= g_MethodMap[i]) { methodIndex = i; break; } struct CInitDialogItem initItems[]= { { DI_DOUBLEBOX, 3, 1, 72, kYSize - 2, false, false, 0, false, NMessageID::kUpdateTitle, NULL, NULL }, { DI_TEXT, 5, 2, 0, 0, false, false, 0, false, -1, updateAddToArchiveString, NULL }, { DI_EDIT, 5, 3, 70, 3, true, false, DIF_HISTORY, false, -1, archiveNameA, kArchiveHistoryKeyName}, // { DI_EDIT, 5, 3, 70, 3, true, false, 0, false, -1, archiveName, NULL}, { DI_SINGLEBOX, 4, 4, kXMid - 2, 4 + 7, false, false, 0, false, NMessageID::kUpdateMethod, NULL, NULL }, { DI_RADIOBUTTON, 6, 5, 0, 0, false, methodIndex == 0, DIF_GROUP, false, NMessageID::kUpdateMethodStore, NULL, NULL }, { DI_RADIOBUTTON, 6, 6, 0, 0, false, methodIndex == 1, 0, false, NMessageID::kUpdateMethodFastest, NULL, NULL }, { DI_RADIOBUTTON, 6, 7, 0, 0, false, methodIndex == 2, 0, false, NMessageID::kUpdateMethodFast, NULL, NULL }, { DI_RADIOBUTTON, 6, 8, 0, 0, false, methodIndex == 3, 0, false, NMessageID::kUpdateMethodNormal, NULL, NULL }, { DI_RADIOBUTTON, 6, 9, 0, 0, false, methodIndex == 4, false, 0, NMessageID::kUpdateMethodMaximum, NULL, NULL }, { DI_RADIOBUTTON, 6, 10, 0, 0, false, methodIndex == 5, false, 0, NMessageID::kUpdateMethodUltra, NULL, NULL }, { DI_SINGLEBOX, kXMid, 4, 70, 4 + 5, false, false, 0, false, NMessageID::kUpdateMode, NULL, NULL }, { DI_RADIOBUTTON, kXMid + 2, 5, 0, 0, false, actionSet == &kAddActionSet, DIF_GROUP, false, NMessageID::kUpdateModeAdd, NULL, NULL }, { DI_RADIOBUTTON, kXMid + 2, 6, 0, 0, false, actionSet == &kUpdateActionSet, 0, false, NMessageID::kUpdateModeUpdate, NULL, NULL }, { DI_RADIOBUTTON, kXMid + 2, 7, 0, 0, false, actionSet == &kFreshActionSet, 0, false, NMessageID::kUpdateModeFreshen, NULL, NULL }, { DI_RADIOBUTTON, kXMid + 2, 8, 0, 0, false, actionSet == &kSynchronizeActionSet, 0, false, NMessageID::kUpdateModeSynchronize, NULL, NULL }, { DI_TEXT, 3, kYSize - 4, 0, 0, false, false, DIF_BOXCOLOR|DIF_SEPARATOR, false, -1, "", NULL }, { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, true, NMessageID::kUpdateAdd, NULL, NULL }, { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, false, NMessageID::kUpdateSelectArchiver, NULL, NULL }, { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, false, NMessageID::kCancel, NULL, NULL } }; const int kNumDialogItems = sizeof(initItems) / sizeof(initItems[0]); const int kOkButtonIndex = kNumDialogItems - 3; const int kSelectarchiverButtonIndex = kNumDialogItems - 2; FarDialogItem dialogItems[kNumDialogItems]; g_StartupInfo.InitDialogItems(initItems, dialogItems, kNumDialogItems); int askCode = g_StartupInfo.ShowDialog(76, kYSize, kHelpTopic, dialogItems, kNumDialogItems); archiveNameA = dialogItems[kArchiveNameIndex].Data; archiveNameA.Trim(); archiveName = MultiByteToUnicodeString(archiveNameA, CP_OEMCP); compressionInfo.Level = g_MethodMap[0]; for (i = 0; i < sizeof(g_MethodMap)/ sizeof(g_MethodMap[0]); i++) if (dialogItems[kMethodRadioIndex + i].Selected) compressionInfo.Level = g_MethodMap[i]; if (dialogItems[kModeRadioIndex].Selected) actionSet = &kAddActionSet; else if (dialogItems[kModeRadioIndex + 1].Selected) actionSet = &kUpdateActionSet; else if (dialogItems[kModeRadioIndex + 2].Selected) actionSet = &kFreshActionSet; else if (dialogItems[kModeRadioIndex + 3].Selected) actionSet = &kSynchronizeActionSet; else throw 51751; if (askCode == kSelectarchiverButtonIndex) { CIntVector indices; CSysStringVector archiverNames; for (int i = 0; i < codecs->Formats.Size(); i++) { const CArcInfoEx &arc = codecs->Formats[i]; if (arc.UpdateEnabled) { indices.Add(i); archiverNames.Add(GetSystemString(arc.Name, CP_OEMCP)); } } int index = g_StartupInfo.Menu(FMENU_AUTOHIGHLIGHT, g_StartupInfo.GetMsgString(NMessageID::kUpdateSelectArchiverMenuTitle), NULL, archiverNames, archiverIndex); if (index >= 0) { const CArcInfoEx &prevArchiverInfo = codecs->Formats[prevFormat]; if (prevArchiverInfo.KeepName) { const UString &prevExtension = prevArchiverInfo.GetMainExt(); const int prevExtensionLen = prevExtension.Length(); if (archiveName.Right(prevExtensionLen).CompareNoCase(prevExtension) == 0) { int pos = archiveName.Length() - prevExtensionLen; if (pos > 1) { int dotPos = archiveName.ReverseFind('.'); if (dotPos == pos - 1) archiveName = archiveName.Left(dotPos); } } } archiverIndex = indices[index]; const CArcInfoEx &arcInfo = codecs->Formats[archiverIndex]; prevFormat = archiverIndex; if (arcInfo.KeepName) archiveName = archiveNameSrc; else { int dotPos = archiveName.ReverseFind('.'); int slashPos = MyMax(archiveName.ReverseFind('\\'), archiveName.ReverseFind('/')); if (dotPos > slashPos) archiveName = archiveName.Left(dotPos); } archiveName += L'.'; archiveName += arcInfo.GetMainExt(); } continue; } if (askCode != kOkButtonIndex) return E_ABORT; break; } const CArcInfoEx &archiverInfoFinal = codecs->Formats[archiverIndex]; compressionInfo.ArcType = archiverInfoFinal.Name; compressionInfo.Save(); NWorkDir::CInfo workDirInfo; workDirInfo.Load(); FString fullArchiveName; if (!MyGetFullPathName(us2fs(archiveName), fullArchiveName)) return E_FAIL; CWorkDirTempFile tempFile; RINOK(tempFile.CreateTempFile(fullArchiveName)); CScreenRestorer screenRestorer; CProgressBox progressBox; CProgressBox *progressBoxPointer = NULL; screenRestorer.Save(); progressBoxPointer = &progressBox; progressBox.Init( // g_StartupInfo.GetMsgString(NMessageID::kWaitTitle), g_StartupInfo.GetMsgString(NMessageID::kUpdating), 48); NFind::CFileInfo fileInfo; CMyComPtr<IOutFolderArchive> outArchive; CMyComPtr<IInFolderArchive> archiveHandler; if (fileInfo.Find(fullArchiveName)) { if (fileInfo.IsDir()) throw "There is Directory with such name"; CAgent *agentSpec = new CAgent; archiveHandler = agentSpec; // CLSID realClassID; CMyComBSTR archiveType; RINOK(agentSpec->Open(NULL, GetUnicodeString(fullArchiveName, CP_OEMCP), UString(), // &realClassID, &archiveType, NULL)); if (archiverInfoFinal.Name.CompareNoCase((const wchar_t *)archiveType) != 0) throw "Type of existing archive differs from specified type"; HRESULT result = archiveHandler.QueryInterface( IID_IOutFolderArchive, &outArchive); if (result != S_OK) { g_StartupInfo.ShowMessage(NMessageID::kUpdateNotSupportedForThisArchive); return E_FAIL; } } else { // HRESULT result = outArchive.CoCreateInstance(classID); CAgent *agentSpec = new CAgent; outArchive = agentSpec; /* HRESULT result = outArchive.CoCreateInstance(CLSID_CAgentArchiveHandler); if (result != S_OK) { g_StartupInfo.ShowMessage(NMessageID::kUpdateNotSupportedForThisArchive); return E_FAIL; } */ } CRecordVector<const wchar_t *> fileNamePointers; fileNamePointers.Reserve(fileNames.Size()); for (i = 0; i < fileNames.Size(); i++) fileNamePointers.Add(fileNames[i]); outArchive->SetFolder(NULL); outArchive->SetFiles(L"", &fileNamePointers.Front(), fileNamePointers.Size()); BYTE actionSetByte[NUpdateArchive::NPairState::kNumValues]; for (i = 0; i < NUpdateArchive::NPairState::kNumValues; i++) actionSetByte[i] = (BYTE)actionSet->StateActions[i]; CUpdateCallback100Imp *updateCallbackSpec = new CUpdateCallback100Imp; CMyComPtr<IFolderArchiveUpdateCallback> updateCallback(updateCallbackSpec ); updateCallbackSpec->Init(/* archiveHandler, */ progressBoxPointer); RINOK(SetOutProperties(outArchive, compressionInfo.Level)); HRESULT result = outArchive->DoOperation( codecs, archiverIndex, tempFile.OutStream, actionSetByte, NULL, updateCallback); updateCallback.Release(); outArchive.Release(); if (result != S_OK) { ShowErrorMessage(result); return result; } if (archiveHandler) { archiveHandler->Close(); } if (!tempFile.MoveToOriginal(archiveHandler != NULL)) { ShowLastErrorMessage(); return E_FAIL; } return S_OK; }
STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testModeSpec, IArchiveExtractCallback *extractCallback) { COM_TRY_BEGIN bool allFilesMode = (numItems == (UInt32)(Int32)-1); if (allFilesMode) numItems = m_Database.Items.Size(); if (numItems == 0) return S_OK; bool testMode = (testModeSpec != 0); UInt64 totalUnPacked = 0; UInt32 i; int lastFolder = -2; UInt64 lastFolderSize = 0; for (i = 0; i < numItems; i++) { unsigned index = allFilesMode ? i : indices[i]; const CMvItem &mvItem = m_Database.Items[index]; const CItem &item = m_Database.Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex]; if (item.IsDir()) continue; int folderIndex = m_Database.GetFolderIndex(&mvItem); if (folderIndex != lastFolder) totalUnPacked += lastFolderSize; lastFolder = folderIndex; lastFolderSize = item.GetEndOffset(); } totalUnPacked += lastFolderSize; extractCallback->SetTotal(totalUnPacked); totalUnPacked = 0; UInt64 totalPacked = 0; CLocalProgress *lps = new CLocalProgress; CMyComPtr<ICompressProgressInfo> progress = lps; lps->Init(extractCallback, false); NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder; CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; NCompress::NDeflate::NDecoder::CCOMCoder *deflateDecoderSpec = NULL; CMyComPtr<ICompressCoder> deflateDecoder; NCompress::NLzx::CDecoder *lzxDecoderSpec = NULL; CMyComPtr<ICompressCoder> lzxDecoder; NCompress::NQuantum::CDecoder *quantumDecoderSpec = NULL; CMyComPtr<ICompressCoder> quantumDecoder; CCabBlockInStream *cabBlockInStreamSpec = new CCabBlockInStream(); CMyComPtr<ISequentialInStream> cabBlockInStream = cabBlockInStreamSpec; if (!cabBlockInStreamSpec->Create()) return E_OUTOFMEMORY; CRecordVector<bool> extractStatuses; for (i = 0; i < numItems;) { unsigned index = allFilesMode ? i : indices[i]; const CMvItem &mvItem = m_Database.Items[index]; const CDatabaseEx &db = m_Database.Volumes[mvItem.VolumeIndex]; unsigned itemIndex = mvItem.ItemIndex; const CItem &item = db.Items[itemIndex]; i++; if (item.IsDir()) { Int32 askMode = testMode ? NExtract::NAskMode::kTest : NExtract::NAskMode::kExtract; CMyComPtr<ISequentialOutStream> realOutStream; RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); RINOK(extractCallback->PrepareOperation(askMode)); realOutStream.Release(); RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); continue; } int folderIndex = m_Database.GetFolderIndex(&mvItem); if (folderIndex < 0) { // If we need previous archive Int32 askMode= testMode ? NExtract::NAskMode::kTest : NExtract::NAskMode::kExtract; CMyComPtr<ISequentialOutStream> realOutStream; RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); RINOK(extractCallback->PrepareOperation(askMode)); realOutStream.Release(); RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kDataError)); continue; } unsigned startIndex2 = m_Database.FolderStartFileIndex[folderIndex]; unsigned startIndex = startIndex2; extractStatuses.Clear(); for (; startIndex < index; startIndex++) extractStatuses.Add(false); extractStatuses.Add(true); startIndex++; UInt64 curUnpack = item.GetEndOffset(); for (; i < numItems; i++) { unsigned indexNext = allFilesMode ? i : indices[i]; const CMvItem &mvItem = m_Database.Items[indexNext]; const CItem &item = m_Database.Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex]; if (item.IsDir()) continue; int newFolderIndex = m_Database.GetFolderIndex(&mvItem); if (newFolderIndex != folderIndex) break; for (; startIndex < indexNext; startIndex++) extractStatuses.Add(false); extractStatuses.Add(true); startIndex++; curUnpack = item.GetEndOffset(); } lps->OutSize = totalUnPacked; lps->InSize = totalPacked; RINOK(lps->SetCur()); CFolderOutStream *cabFolderOutStream = new CFolderOutStream; CMyComPtr<ISequentialOutStream> outStream(cabFolderOutStream); const CFolder &folder = db.Folders[item.GetFolderIndex(db.Folders.Size())]; cabFolderOutStream->Init(&m_Database, &extractStatuses, startIndex2, curUnpack, extractCallback, testMode); cabBlockInStreamSpec->MsZip = false; HRESULT res = S_OK; switch (folder.GetMethod()) { case NHeader::NMethod::kNone: break; case NHeader::NMethod::kMSZip: if (!deflateDecoder) { deflateDecoderSpec = new NCompress::NDeflate::NDecoder::CCOMCoder; deflateDecoder = deflateDecoderSpec; } cabBlockInStreamSpec->MsZip = true; break; case NHeader::NMethod::kLZX: if (!lzxDecoder) { lzxDecoderSpec = new NCompress::NLzx::CDecoder; lzxDecoder = lzxDecoderSpec; } res = lzxDecoderSpec->SetParams(folder.MethodMinor); break; case NHeader::NMethod::kQuantum: if (!quantumDecoder) { quantumDecoderSpec = new NCompress::NQuantum::CDecoder; quantumDecoder = quantumDecoderSpec; } res = quantumDecoderSpec->SetParams(folder.MethodMinor); break; default: res = E_INVALIDARG; break; } if (res == E_INVALIDARG) { RINOK(cabFolderOutStream->Unsupported()); totalUnPacked += curUnpack; continue; } RINOK(res); { unsigned volIndex = mvItem.VolumeIndex; int locFolderIndex = item.GetFolderIndex(db.Folders.Size()); bool keepHistory = false; bool keepInputBuffer = false; for (UInt32 bl = 0; cabFolderOutStream->GetRemain() != 0;) { if (volIndex >= m_Database.Volumes.Size()) { res = S_FALSE; break; } const CDatabaseEx &db = m_Database.Volumes[volIndex]; const CFolder &folder = db.Folders[locFolderIndex]; if (bl == 0) { cabBlockInStreamSpec->ReservedSize = db.ArcInfo.GetDataBlockReserveSize(); RINOK(db.Stream->Seek(db.StartPosition + folder.DataStart, STREAM_SEEK_SET, NULL)); } if (bl == folder.NumDataBlocks) { /* CFolder::NumDataBlocks (CFFOLDER::cCFData in CAB specification) is 16-bit. But there are some big CAB archives from MS that contain more than (0xFFFF) CFDATA blocks in folder. Old cab extracting software can show error (or ask next volume) but cab extracting library in new Windows ignores this error. 15.00 : We also try to ignore such error, if archive is not multi-volume. */ if (m_Database.Volumes.Size() > 1) { volIndex++; locFolderIndex = 0; bl = 0; continue; } } bl++; if (!keepInputBuffer) cabBlockInStreamSpec->InitForNewBlock(); UInt32 packSize, unpackSize; res = cabBlockInStreamSpec->PreRead(db.Stream, packSize, unpackSize); if (res == S_FALSE) break; RINOK(res); keepInputBuffer = (unpackSize == 0); if (keepInputBuffer) continue; UInt64 totalUnPacked2 = totalUnPacked + cabFolderOutStream->GetPosInFolder(); totalPacked += packSize; lps->OutSize = totalUnPacked2; lps->InSize = totalPacked; RINOK(lps->SetCur()); UInt64 unpackRemain = cabFolderOutStream->GetRemain(); const UInt32 kBlockSizeMax = (1 << 15); if (unpackRemain > kBlockSizeMax) unpackRemain = kBlockSizeMax; if (unpackRemain > unpackSize) unpackRemain = unpackSize; switch (folder.GetMethod()) { case NHeader::NMethod::kNone: res = copyCoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL); break; case NHeader::NMethod::kMSZip: deflateDecoderSpec->Set_KeepHistory(keepHistory); /* v9.31: now we follow MSZIP specification that requires to finish deflate stream at the end of each block. But PyCabArc can create CAB archives that doesn't have finish marker at the end of block. Cabarc probably ignores such errors in cab archives. Maybe we also should ignore that error? Or we should extract full file and show the warning? */ deflateDecoderSpec->Set_NeedFinishInput(true); res = deflateDecoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL); if (res == S_OK) { if (!deflateDecoderSpec->IsFinished()) res = S_FALSE; if (!deflateDecoderSpec->IsFinalBlock()) res = S_FALSE; } break; case NHeader::NMethod::kLZX: lzxDecoderSpec->SetKeepHistory(keepHistory); res = lzxDecoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL); break; case NHeader::NMethod::kQuantum: quantumDecoderSpec->SetKeepHistory(keepHistory); res = quantumDecoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL); break; } if (res != S_OK) { if (res != S_FALSE) RINOK(res); break; } keepHistory = true; } if (res == S_OK) { RINOK(cabFolderOutStream->WriteEmptyFiles()); } } if (res != S_OK || cabFolderOutStream->GetRemain() != 0) { RINOK(cabFolderOutStream->FlushCorrupted()); } totalUnPacked += curUnpack; } return S_OK; COM_TRY_END }
// This is Write function HRESULT CCabFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *processedSize, bool isOK) { UInt32 realProcessed = 0; if (processedSize != NULL) *processedSize = 0; while(size != 0) { if (m_FileIsOpen) { UInt32 numBytesToWrite = (UInt32)MyMin(m_RemainFileSize, (UInt64)(size)); HRESULT res = S_OK; if (numBytesToWrite > 0) { if (!isOK) m_IsOk = false; if (m_RealOutStream) { UInt32 processedSizeLocal = 0; res = m_RealOutStream->Write((const Byte *)data, numBytesToWrite, &processedSizeLocal); numBytesToWrite = processedSizeLocal; } } realProcessed += numBytesToWrite; if (processedSize != NULL) *processedSize = realProcessed; data = (const void *)((const Byte *)data + numBytesToWrite); size -= numBytesToWrite; m_RemainFileSize -= numBytesToWrite; m_PosInFolder += numBytesToWrite; if (res != S_OK) return res; if (m_RemainFileSize == 0) { m_RealOutStream.Release(); RINOK(m_ExtractCallback->SetOperationResult( m_IsOk ? NArchive::NExtract::NOperationResult::kOK: NArchive::NExtract::NOperationResult::kDataError)); m_FileIsOpen = false; } if (realProcessed > 0) break; // with this break this function works as Write-Part } else { if (m_CurrentIndex >= m_ExtractStatuses->Size()) return E_FAIL; const CMvItem &mvItem = m_Database->Items[m_StartIndex + m_CurrentIndex]; const CItem &item = m_Database->Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex]; m_RemainFileSize = item.Size; UInt32 fileOffset = item.Offset; if (fileOffset < m_PosInFolder) return E_FAIL; if (fileOffset > m_PosInFolder) { UInt32 numBytesToWrite = (UInt32)MyMin((UInt64)fileOffset - m_PosInFolder, UInt64(size)); realProcessed += numBytesToWrite; if (processedSize != NULL) *processedSize = realProcessed; data = (const void *)((const Byte *)data + numBytesToWrite); size -= numBytesToWrite; m_PosInFolder += numBytesToWrite; } if (fileOffset == m_PosInFolder) { RINOK(OpenFile()); m_FileIsOpen = true; m_CurrentIndex++; m_IsOk = true; } } } return WriteEmptyFiles(); }
void CPanel::CreateSystemMenu(HMENU menuSpec, const CRecordVector<UInt32> &operatedIndices, CMyComPtr<IContextMenu> &systemContextMenu) { systemContextMenu.Release(); CreateShellContextMenu(operatedIndices, systemContextMenu); if (systemContextMenu == 0) return; // Set up a CMINVOKECOMMANDINFO structure. CMINVOKECOMMANDINFO ci; ZeroMemory(&ci, sizeof(ci)); ci.cbSize = sizeof(CMINVOKECOMMANDINFO); ci.hwnd = GetParent(); /* if (Sender == GoBtn) { // Verbs that can be used are cut, paste, // properties, delete, and so on. String action; if (CutRb->Checked) action = "cut"; else if (CopyRb->Checked) action = "copy"; else if (DeleteRb->Checked) action = "delete"; else if (PropertiesRb->Checked) action = "properties"; ci.lpVerb = action.c_str(); result = cm->InvokeCommand(&ci); if (result) ShowMessage( "Error copying file to clipboard."); } else */ { // HMENU hMenu = CreatePopupMenu(); CMenu popupMenu; // CMenuDestroyer menuDestroyer(popupMenu); if(!popupMenu.CreatePopup()) throw 210503; HMENU hMenu = popupMenu; DWORD Flags = CMF_EXPLORE; // Optionally the shell will show the extended // context menu on some operating systems when // the shift key is held down at the time the // context menu is invoked. The following is // commented out but you can uncommnent this // line to show the extended context menu. // Flags |= 0x00000080; systemContextMenu->QueryContextMenu(hMenu, 0, kSystemStartMenuID, 0x7FFF, Flags); { CMenu menu; menu.Attach(menuSpec); CMenuItem menuItem; menuItem.fMask = MIIM_SUBMENU | MIIM_TYPE | MIIM_ID; menuItem.fType = MFT_STRING; menuItem.hSubMenu = popupMenu.Detach(); // menuDestroyer.Disable(); menuItem.StringValue = LangString(IDS_SYSTEM, 0x030202A0); menu.InsertItem(0, true, menuItem); } /* if (Cmd < 100 && Cmd != 0) { ci.lpVerb = MAKEINTRESOURCE(Cmd - 1); ci.lpParameters = ""; ci.lpDirectory = ""; ci.nShow = SW_SHOWNORMAL; cm->InvokeCommand(&ci); } // If Cmd is > 100 then it's one of our // inserted menu items. else // Find the menu item. for (int i = 0; i < popupMenu1->Items->Count; i++) { TMenuItem* menu = popupMenu1->Items->Items[i]; // Call its OnClick handler. if (menu->Command == Cmd - 100) menu->OnClick(this); } // Release the memory allocated for the menu. DestroyMenu(hMenu); */ } }
void CFolderOutStream2::ReleaseOutStream() { _outStream.Release(); _crcStreamSpec->ReleaseStream(); }
STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testModeSpec, IArchiveExtractCallback *extractCallback) { COM_TRY_BEGIN bool allFilesMode = (numItems == (UInt32)-1); if (allFilesMode) numItems = m_Database.Items.Size(); if(numItems == 0) return S_OK; bool testMode = (testModeSpec != 0); UInt64 totalUnPacked = 0; UInt32 i; int lastFolder = -2; UInt64 lastFolderSize = 0; for(i = 0; i < numItems; i++) { int index = allFilesMode ? i : indices[i]; const CMvItem &mvItem = m_Database.Items[index]; const CItem &item = m_Database.Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex]; if (item.IsDir()) continue; int folderIndex = m_Database.GetFolderIndex(&mvItem); if (folderIndex != lastFolder) totalUnPacked += lastFolderSize; lastFolder = folderIndex; lastFolderSize = item.GetEndOffset(); } totalUnPacked += lastFolderSize; extractCallback->SetTotal(totalUnPacked); totalUnPacked = 0; UInt64 totalPacked = 0; CLocalProgress *lps = new CLocalProgress; CMyComPtr<ICompressProgressInfo> progress = lps; lps->Init(extractCallback, false); NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder; CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; NCompress::NDeflate::NDecoder::CCOMCoder *deflateDecoderSpec = NULL; CMyComPtr<ICompressCoder> deflateDecoder; NCompress::NLzx::CDecoder *lzxDecoderSpec = NULL; CMyComPtr<ICompressCoder> lzxDecoder; NCompress::NQuantum::CDecoder *quantumDecoderSpec = NULL; CMyComPtr<ICompressCoder> quantumDecoder; CCabBlockInStream *cabBlockInStreamSpec = new CCabBlockInStream(); CMyComPtr<ISequentialInStream> cabBlockInStream = cabBlockInStreamSpec; if (!cabBlockInStreamSpec->Create()) return E_OUTOFMEMORY; CRecordVector<bool> extractStatuses; for(i = 0; i < numItems;) { int index = allFilesMode ? i : indices[i]; const CMvItem &mvItem = m_Database.Items[index]; const CDatabaseEx &db = m_Database.Volumes[mvItem.VolumeIndex]; int itemIndex = mvItem.ItemIndex; const CItem &item = db.Items[itemIndex]; i++; if (item.IsDir()) { Int32 askMode = testMode ? NExtract::NAskMode::kTest : NExtract::NAskMode::kExtract; CMyComPtr<ISequentialOutStream> realOutStream; RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); RINOK(extractCallback->PrepareOperation(askMode)); realOutStream.Release(); RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); continue; } int folderIndex = m_Database.GetFolderIndex(&mvItem); if (folderIndex < 0) { // If we need previous archive Int32 askMode= testMode ? NExtract::NAskMode::kTest : NExtract::NAskMode::kExtract; CMyComPtr<ISequentialOutStream> realOutStream; RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); RINOK(extractCallback->PrepareOperation(askMode)); realOutStream.Release(); RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kDataError)); continue; } int startIndex2 = m_Database.FolderStartFileIndex[folderIndex]; int startIndex = startIndex2; extractStatuses.Clear(); for (; startIndex < index; startIndex++) extractStatuses.Add(false); extractStatuses.Add(true); startIndex++; UInt64 curUnpack = item.GetEndOffset(); for(;i < numItems; i++) { int indexNext = allFilesMode ? i : indices[i]; const CMvItem &mvItem = m_Database.Items[indexNext]; const CItem &item = m_Database.Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex]; if (item.IsDir()) continue; int newFolderIndex = m_Database.GetFolderIndex(&mvItem); if (newFolderIndex != folderIndex) break; for (; startIndex < indexNext; startIndex++) extractStatuses.Add(false); extractStatuses.Add(true); startIndex++; curUnpack = item.GetEndOffset(); } lps->OutSize = totalUnPacked; lps->InSize = totalPacked; RINOK(lps->SetCur()); CFolderOutStream *cabFolderOutStream = new CFolderOutStream; CMyComPtr<ISequentialOutStream> outStream(cabFolderOutStream); const CFolder &folder = db.Folders[item.GetFolderIndex(db.Folders.Size())]; cabFolderOutStream->Init(&m_Database, &extractStatuses, startIndex2, curUnpack, extractCallback, testMode); cabBlockInStreamSpec->MsZip = false; switch(folder.GetCompressionMethod()) { case NHeader::NCompressionMethodMajor::kNone: break; case NHeader::NCompressionMethodMajor::kMSZip: if(deflateDecoderSpec == NULL) { deflateDecoderSpec = new NCompress::NDeflate::NDecoder::CCOMCoder; deflateDecoder = deflateDecoderSpec; } cabBlockInStreamSpec->MsZip = true; break; case NHeader::NCompressionMethodMajor::kLZX: if(lzxDecoderSpec == NULL) { lzxDecoderSpec = new NCompress::NLzx::CDecoder; lzxDecoder = lzxDecoderSpec; } RINOK(lzxDecoderSpec->SetParams(folder.CompressionTypeMinor)); break; case NHeader::NCompressionMethodMajor::kQuantum: if(quantumDecoderSpec == NULL) { quantumDecoderSpec = new NCompress::NQuantum::CDecoder; quantumDecoder = quantumDecoderSpec; } quantumDecoderSpec->SetParams(folder.CompressionTypeMinor); break; default: { RINOK(cabFolderOutStream->Unsupported()); totalUnPacked += curUnpack; continue; } } cabBlockInStreamSpec->InitForNewFolder(); HRESULT res = S_OK; { int volIndex = mvItem.VolumeIndex; int locFolderIndex = item.GetFolderIndex(db.Folders.Size()); bool keepHistory = false; bool keepInputBuffer = false; for (UInt32 f = 0; cabFolderOutStream->GetRemain() != 0;) { if (volIndex >= m_Database.Volumes.Size()) { res = S_FALSE; break; } const CDatabaseEx &db = m_Database.Volumes[volIndex]; const CFolder &folder = db.Folders[locFolderIndex]; if (f == 0) { cabBlockInStreamSpec->SetStream(db.Stream); cabBlockInStreamSpec->ReservedSize = db.ArchiveInfo.GetDataBlockReserveSize(); RINOK(db.Stream->Seek(db.StartPosition + folder.DataStart, STREAM_SEEK_SET, NULL)); } if (f == folder.NumDataBlocks) { volIndex++; locFolderIndex = 0; f = 0; continue; } f++; cabBlockInStreamSpec->DataError = false; if (!keepInputBuffer) cabBlockInStreamSpec->InitForNewBlock(); UInt32 packSize, unpackSize; res = cabBlockInStreamSpec->PreRead(packSize, unpackSize); if (res == S_FALSE) break; RINOK(res); keepInputBuffer = (unpackSize == 0); if (keepInputBuffer) continue; UInt64 totalUnPacked2 = totalUnPacked + cabFolderOutStream->GetPosInFolder(); totalPacked += packSize; lps->OutSize = totalUnPacked2; lps->InSize = totalPacked; RINOK(lps->SetCur()); UInt64 unpackRemain = cabFolderOutStream->GetRemain(); const UInt32 kBlockSizeMax = (1 << 15); if (unpackRemain > kBlockSizeMax) unpackRemain = kBlockSizeMax; if (unpackRemain > unpackSize) unpackRemain = unpackSize; switch(folder.GetCompressionMethod()) { case NHeader::NCompressionMethodMajor::kNone: res = copyCoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL); break; case NHeader::NCompressionMethodMajor::kMSZip: deflateDecoderSpec->SetKeepHistory(keepHistory); res = deflateDecoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL); break; case NHeader::NCompressionMethodMajor::kLZX: lzxDecoderSpec->SetKeepHistory(keepHistory); res = lzxDecoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL); break; case NHeader::NCompressionMethodMajor::kQuantum: quantumDecoderSpec->SetKeepHistory(keepHistory); res = quantumDecoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL); break; } if (res != S_OK) { if (res != S_FALSE) RINOK(res); break; } keepHistory = true; } if (res == S_OK) { RINOK(cabFolderOutStream->WriteEmptyFiles()); } } if (res != S_OK || cabFolderOutStream->GetRemain() != 0) { RINOK(cabFolderOutStream->FlushCorrupted()); } totalUnPacked += curUnpack; } return S_OK; COM_TRY_END }
HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream, const CObjectVector<NArchive::NTar::CItemEx> &inputItems, const CObjectVector<CUpdateItem> &updateItems, UINT codePage, IArchiveUpdateCallback *updateCallback) { COutArchive outArchive; outArchive.Create(outStream); outArchive.Pos = 0; CMyComPtr<IOutStream> outSeekStream; outStream->QueryInterface(IID_IOutStream, (void **)&outSeekStream); UInt64 complexity = 0; unsigned i; for (i = 0; i < updateItems.Size(); i++) { const CUpdateItem &ui = updateItems[i]; if (ui.NewData) complexity += ui.Size; else complexity += inputItems[ui.IndexInArchive].GetFullSize(); } RINOK(updateCallback->SetTotal(complexity)); NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder; CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; CLocalProgress *lps = new CLocalProgress; CMyComPtr<ICompressProgressInfo> progress = lps; lps->Init(updateCallback, true); CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; CMyComPtr<CLimitedSequentialInStream> inStreamLimited(streamSpec); streamSpec->SetStream(inStream); complexity = 0; for (i = 0; i < updateItems.Size(); i++) { lps->InSize = lps->OutSize = complexity; RINOK(lps->SetCur()); const CUpdateItem &ui = updateItems[i]; CItem item; if (ui.NewProps) { item.Mode = ui.Mode; item.Name = ui.Name; item.User = ui.User; item.Group = ui.Group; if (ui.IsDir) { item.LinkFlag = NFileHeader::NLinkFlag::kDirectory; item.PackSize = 0; } else { item.LinkFlag = NFileHeader::NLinkFlag::kNormal; item.PackSize = ui.Size; } item.MTime = ui.MTime; item.DeviceMajorDefined = false; item.DeviceMinorDefined = false; item.UID = 0; item.GID = 0; memcpy(item.Magic, NFileHeader::NMagic::kUsTar_00, 8); } else item = inputItems[ui.IndexInArchive]; AString symLink; if (ui.NewData || ui.NewProps) { RINOK(GetPropString(updateCallback, ui.IndexInClient, kpidSymLink, symLink, codePage, true)); if (!symLink.IsEmpty()) { item.LinkFlag = NFileHeader::NLinkFlag::kSymLink; item.LinkName = symLink; } } if (ui.NewData) { item.SparseBlocks.Clear(); item.PackSize = ui.Size; item.Size = ui.Size; if (ui.Size == (UInt64)(Int64)-1) return E_INVALIDARG; CMyComPtr<ISequentialInStream> fileInStream; bool needWrite = true; if (!symLink.IsEmpty()) { item.PackSize = 0; item.Size = 0; } else { HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream); if (res == S_FALSE) needWrite = false; else { RINOK(res); if (fileInStream) { CMyComPtr<IStreamGetProps> getProps; fileInStream->QueryInterface(IID_IStreamGetProps, (void **)&getProps); if (getProps) { FILETIME mTime; UInt64 size2; if (getProps->GetProps(&size2, NULL, NULL, &mTime, NULL) == S_OK) { item.PackSize = size2; item.MTime = NWindows::NTime::FileTimeToUnixTime64(mTime);; } } } { AString hardLink; RINOK(GetPropString(updateCallback, ui.IndexInClient, kpidHardLink, hardLink, codePage, true)); if (!hardLink.IsEmpty()) { item.LinkFlag = NFileHeader::NLinkFlag::kHardLink; item.LinkName = hardLink; item.PackSize = 0; item.Size = 0; fileInStream.Release(); } } } } if (needWrite) { UInt64 fileHeaderStartPos = outArchive.Pos; RINOK(outArchive.WriteHeader(item)); if (fileInStream) { RINOK(copyCoder->Code(fileInStream, outStream, NULL, NULL, progress)); outArchive.Pos += copyCoderSpec->TotalSize; if (copyCoderSpec->TotalSize != item.PackSize) { if (!outSeekStream) return E_FAIL; UInt64 backOffset = outArchive.Pos - fileHeaderStartPos; RINOK(outSeekStream->Seek(-(Int64)backOffset, STREAM_SEEK_CUR, NULL)); outArchive.Pos = fileHeaderStartPos; item.PackSize = copyCoderSpec->TotalSize; RINOK(outArchive.WriteHeader(item)); RINOK(outSeekStream->Seek(item.PackSize, STREAM_SEEK_CUR, NULL)); outArchive.Pos += item.PackSize; } RINOK(outArchive.FillDataResidual(item.PackSize)); } } complexity += item.PackSize; RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); } else { const CItemEx &existItem = inputItems[ui.IndexInArchive]; UInt64 size; if (ui.NewProps) { // memcpy(item.Magic, NFileHeader::NMagic::kEmpty, 8); if (!symLink.IsEmpty()) { item.PackSize = 0; item.Size = 0; } else { if (ui.IsDir == existItem.IsDir()) item.LinkFlag = existItem.LinkFlag; item.SparseBlocks = existItem.SparseBlocks; item.Size = existItem.Size; item.PackSize = existItem.PackSize; } item.DeviceMajorDefined = existItem.DeviceMajorDefined; item.DeviceMinorDefined = existItem.DeviceMinorDefined; item.DeviceMajor = existItem.DeviceMajor; item.DeviceMinor = existItem.DeviceMinor; item.UID = existItem.UID; item.GID = existItem.GID; RINOK(outArchive.WriteHeader(item)); RINOK(inStream->Seek(existItem.GetDataPosition(), STREAM_SEEK_SET, NULL)); size = existItem.PackSize; } else { RINOK(inStream->Seek(existItem.HeaderPos, STREAM_SEEK_SET, NULL)); size = existItem.GetFullSize(); } streamSpec->Init(size); RINOK(copyCoder->Code(inStreamLimited, outStream, NULL, NULL, progress)); if (copyCoderSpec->TotalSize != size) return E_FAIL; outArchive.Pos += size; RINOK(outArchive.FillDataResidual(existItem.PackSize)); complexity += size; } } lps->InSize = lps->OutSize = complexity; RINOK(lps->SetCur()); return outArchive.WriteFinishHeader(); }
STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) { COM_TRY_BEGIN bool allFilesMode = (numItems == (UInt32)(Int32)-1); if (allFilesMode) numItems = _db.SortedItems.Size() + _numXmlItems + _db.VirtualRoots.Size() + _numIgnoreItems; if (numItems == 0) return S_OK; UInt32 i; UInt64 totalSize = 0; for (i = 0; i < numItems; i++) { UInt32 index = allFilesMode ? i : indices[i]; if (index < _db.SortedItems.Size()) { int streamIndex = _db.Items[_db.SortedItems[index]].StreamIndex; if (streamIndex >= 0) { const CStreamInfo &si = _db.DataStreams[streamIndex]; totalSize += si.Resource.UnpackSize; } } else { index -= _db.SortedItems.Size(); if (index < (UInt32)_numXmlItems) totalSize += _xmls[index].Data.Size(); } } RINOK(extractCallback->SetTotal(totalSize)); UInt64 currentTotalPacked = 0; UInt64 currentTotalUnPacked = 0; UInt64 currentItemUnPacked, currentItemPacked; int prevSuccessStreamIndex = -1; CUnpacker unpacker; CLocalProgress *lps = new CLocalProgress; CMyComPtr<ICompressProgressInfo> progress = lps; lps->Init(extractCallback, false); for (i = 0; i < numItems; currentTotalUnPacked += currentItemUnPacked, currentTotalPacked += currentItemPacked) { currentItemUnPacked = 0; currentItemPacked = 0; lps->InSize = currentTotalPacked; lps->OutSize = currentTotalUnPacked; RINOK(lps->SetCur()); UInt32 index = allFilesMode ? i : indices[i]; i++; Int32 askMode = testMode ? NExtract::NAskMode::kTest : NExtract::NAskMode::kExtract; CMyComPtr<ISequentialOutStream> realOutStream; RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); if (index >= _db.SortedItems.Size()) { if (!testMode && !realOutStream) continue; RINOK(extractCallback->PrepareOperation(askMode)); index -= _db.SortedItems.Size(); if (index < (UInt32)_numXmlItems) { const CByteBuffer &data = _xmls[index].Data; currentItemUnPacked = data.Size(); if (realOutStream) { RINOK(WriteStream(realOutStream, (const Byte *)data, data.Size())); realOutStream.Release(); } } RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); continue; } const CItem &item = _db.Items[_db.SortedItems[index]]; int streamIndex = item.StreamIndex; if (streamIndex < 0) { if (!testMode && !realOutStream) continue; RINOK(extractCallback->PrepareOperation(askMode)); realOutStream.Release(); RINOK(extractCallback->SetOperationResult(_db.ItemHasStream(item) ? NExtract::NOperationResult::kDataError : NExtract::NOperationResult::kOK)); continue; } const CStreamInfo &si = _db.DataStreams[streamIndex]; currentItemUnPacked = si.Resource.UnpackSize; currentItemPacked = si.Resource.PackSize; if (!testMode && !realOutStream) continue; RINOK(extractCallback->PrepareOperation(askMode)); Int32 opRes = NExtract::NOperationResult::kOK; if (streamIndex != prevSuccessStreamIndex || realOutStream) { Byte digest[kHashSize]; const CVolume &vol = _volumes[si.PartNumber]; HRESULT res = unpacker.Unpack(vol.Stream, si.Resource, vol.Header.IsLzxMode(), realOutStream, progress, digest); if (res == S_OK) { if (memcmp(digest, si.Hash, kHashSize) == 0) prevSuccessStreamIndex = streamIndex; else opRes = NExtract::NOperationResult::kCRCError; } else if (res == S_FALSE) opRes = NExtract::NOperationResult::kDataError; else return res; } realOutStream.Release(); RINOK(extractCallback->SetOperationResult(opRes)); } return S_OK; COM_TRY_END }
// This is WritePart function HRESULT CChmFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *processedSize, bool isOK) { UInt32 realProcessed = 0; if (processedSize != NULL) *processedSize = 0; while(size != 0) { if (m_FileIsOpen) { UInt32 numBytesToWrite = (UInt32)MyMin(m_RemainFileSize, (UInt64)(size)); HRESULT res = S_OK; if (numBytesToWrite > 0) { if (!isOK) m_IsOk = false; if (m_RealOutStream) { UInt32 processedSizeLocal = 0; res = m_RealOutStream->Write((const Byte *)data, numBytesToWrite, &processedSizeLocal); numBytesToWrite = processedSizeLocal; } } realProcessed += numBytesToWrite; if (processedSize != NULL) *processedSize = realProcessed; data = (const void *)((const Byte *)data + numBytesToWrite); size -= numBytesToWrite; m_RemainFileSize -= numBytesToWrite; m_PosInSection += numBytesToWrite; m_PosInFolder += numBytesToWrite; if (res != S_OK) return res; if (m_RemainFileSize == 0) { m_RealOutStream.Release(); RINOK(m_ExtractCallback->SetOperationResult( m_IsOk ? NExtract::NOperationResult::kOK: NExtract::NOperationResult::kDataError)); m_FileIsOpen = false; } if (realProcessed > 0) break; // with this break this function works as write part } else { if (m_CurrentIndex >= m_NumFiles) return E_FAIL; int fullIndex = m_StartIndex + m_CurrentIndex; m_RemainFileSize = m_Database->GetFileSize(fullIndex); UInt64 fileOffset = m_Database->GetFileOffset(fullIndex); if (fileOffset < m_PosInSection) return E_FAIL; if (fileOffset > m_PosInSection) { UInt32 numBytesToWrite = (UInt32)MyMin(fileOffset - m_PosInSection, UInt64(size)); realProcessed += numBytesToWrite; if (processedSize != NULL) *processedSize = realProcessed; data = (const void *)((const Byte *)data + numBytesToWrite); size -= numBytesToWrite; m_PosInSection += numBytesToWrite; m_PosInFolder += numBytesToWrite; } if (fileOffset == m_PosInSection) { RINOK(OpenFile()); m_FileIsOpen = true; m_CurrentIndex++; m_IsOk = true; } } } return WriteEmptyFiles(); }
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 = _archive.Refs.Size(); if(numItems == 0) return S_OK; UInt64 totalSize = 0; UInt32 i; for(i = 0; i < numItems; i++) { UInt32 index = (allFilesMode ? i : indices[i]); if (index < (UInt32)_archive.Refs.Size()) { const CRef &ref = _archive.Refs[index]; const CDir &item = ref.Dir->_subItems[ref.Index]; totalSize += item.DataLength; } else { totalSize += _archive.GetBootItemSize(index - _archive.Refs.Size()); } } extractCallback->SetTotal(totalSize); UInt64 currentTotalSize = 0; UInt64 currentItemSize; NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; CLocalProgress *lps = new CLocalProgress; CMyComPtr<ICompressProgressInfo> progress = lps; lps->Init(extractCallback, false); CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; CMyComPtr<ISequentialInStream> inStream(streamSpec); streamSpec->SetStream(_inStream); for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize) { lps->InSize = lps->OutSize = currentTotalSize; RINOK(lps->SetCur()); currentItemSize = 0; CMyComPtr<ISequentialOutStream> realOutStream; Int32 askMode; askMode = testMode ? NArchive::NExtract::NAskMode::kTest : NArchive::NExtract::NAskMode::kExtract; UInt32 index = allFilesMode ? i : indices[i]; RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); UInt64 blockIndex; if (index < (UInt32)_archive.Refs.Size()) { const CRef &ref = _archive.Refs[index]; const CDir &item = ref.Dir->_subItems[ref.Index]; if(item.IsDir()) { RINOK(extractCallback->PrepareOperation(askMode)); RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK)); continue; } currentItemSize = item.DataLength; blockIndex = item.ExtentLocation; } else { int bootIndex = index - _archive.Refs.Size(); const CBootInitialEntry &be = _archive.BootEntries[bootIndex]; currentItemSize = _archive.GetBootItemSize(bootIndex); blockIndex = be.LoadRBA; } if (!testMode && (!realOutStream)) continue; RINOK(extractCallback->PrepareOperation(askMode)); if (testMode) { RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK)); continue; } RINOK(_inStream->Seek(blockIndex * _archive.BlockSize, STREAM_SEEK_SET, NULL)); streamSpec->Init(currentItemSize); RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress)); realOutStream.Release(); RINOK(extractCallback->SetOperationResult((copyCoderSpec->TotalSize == currentItemSize) ? NArchive::NExtract::NOperationResult::kOK: NArchive::NExtract::NOperationResult::kDataError)); } return S_OK; COM_TRY_END }
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 }
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 = _db.Refs.Size(); if (numItems == 0) return S_OK; UInt32 i; UInt64 totalSize = 0; for(i = 0; i < numItems; i++) { const CItem &item = _db.Items[_db.Refs[allFilesMode ? i : indices[i]].Did]; if (!item.IsDir()) totalSize += item.Size; } RINOK(extractCallback->SetTotal(totalSize)); UInt64 totalPackSize; totalSize = totalPackSize = 0; NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; CLocalProgress *lps = new CLocalProgress; CMyComPtr<ICompressProgressInfo> progress = lps; lps->Init(extractCallback, false); for (i = 0; i < numItems; i++) { lps->InSize = totalPackSize; lps->OutSize = totalSize; RINOK(lps->SetCur()); Int32 index = allFilesMode ? i : indices[i]; const CItem &item = _db.Items[_db.Refs[index].Did]; CMyComPtr<ISequentialOutStream> outStream; Int32 askMode = testMode ? NArchive::NExtract::NAskMode::kTest : NArchive::NExtract::NAskMode::kExtract; RINOK(extractCallback->GetStream(index, &outStream, askMode)); if (item.IsDir()) { RINOK(extractCallback->PrepareOperation(askMode)); RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK)); continue; } totalPackSize += _db.GetItemPackSize(item.Size); totalSize += item.Size; if (!testMode && (!outStream)) continue; RINOK(extractCallback->PrepareOperation(askMode)); Int32 res = NArchive::NExtract::NOperationResult::kDataError; CMyComPtr<ISequentialInStream> inStream; HRESULT hres = GetStream(index, &inStream); if (hres == S_FALSE) res = NArchive::NExtract::NOperationResult::kDataError; else if (hres == E_NOTIMPL) res = NArchive::NExtract::NOperationResult::kUnSupportedMethod; else { RINOK(hres); if (inStream) { RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)); if (copyCoderSpec->TotalSize == item.Size) res = NArchive::NExtract::NOperationResult::kOK; } } outStream.Release(); RINOK(extractCallback->SetOperationResult(res)); } return S_OK; COM_TRY_END }
NFileOperationReturnCode::EEnum CPlugin::PutFiles( struct PluginPanelItem *panelItems, int numItems, int moveMode, int opMode) { if (moveMode != 0) { g_StartupInfo.ShowMessage(NMessageID::kMoveIsNotSupported); return NFileOperationReturnCode::kError; } if (numItems == 0) return NFileOperationReturnCode::kError; /* if (!m_ArchiverInfo.UpdateEnabled) { g_StartupInfo.ShowMessage(NMessageID::kUpdateNotSupportedForThisArchive); return NFileOperationReturnCode::kError; } */ const int kYSize = 14; const int kXMid = 38; NCompression::CInfo compressionInfo; compressionInfo.Load(); int methodIndex = 0; int i; for (i = sizeof(g_MethodMap) / sizeof(g_MethodMap[0]) - 1; i >= 0; i--) if (compressionInfo.Level >= g_MethodMap[i]) { methodIndex = i; break; } const int kMethodRadioIndex = 2; const int kModeRadioIndex = kMethodRadioIndex + 7; struct CInitDialogItem initItems[]={ { DI_DOUBLEBOX, 3, 1, 72, kYSize - 2, false, false, 0, false, NMessageID::kUpdateTitle, NULL, NULL }, { DI_SINGLEBOX, 4, 2, kXMid - 2, 2 + 7, false, false, 0, false, NMessageID::kUpdateMethod, NULL, NULL }, { DI_RADIOBUTTON, 6, 3, 0, 0, methodIndex == 0, methodIndex == 0, DIF_GROUP, false, NMessageID::kUpdateMethodStore, NULL, NULL }, { DI_RADIOBUTTON, 6, 4, 0, 0, methodIndex == 1, methodIndex == 1, 0, false, NMessageID::kUpdateMethodFastest, NULL, NULL }, { DI_RADIOBUTTON, 6, 5, 0, 0, methodIndex == 2, methodIndex == 2, 0, false, NMessageID::kUpdateMethodFast, NULL, NULL }, { DI_RADIOBUTTON, 6, 6, 0, 0, methodIndex == 3, methodIndex == 3, 0, false, NMessageID::kUpdateMethodNormal, NULL, NULL }, { DI_RADIOBUTTON, 6, 7, 0, 0, methodIndex == 4, methodIndex == 4, 0, false, NMessageID::kUpdateMethodMaximum, NULL, NULL }, { DI_RADIOBUTTON, 6, 8, 0, 0, methodIndex == 5, methodIndex == 5, 0, false, NMessageID::kUpdateMethodUltra, NULL, NULL }, { DI_SINGLEBOX, kXMid, 2, 70, 2 + 5, false, false, 0, false, NMessageID::kUpdateMode, NULL, NULL }, { DI_RADIOBUTTON, kXMid + 2, 3, 0, 0, false, true, DIF_GROUP, false, NMessageID::kUpdateModeAdd, NULL, NULL }, { DI_RADIOBUTTON, kXMid + 2, 4, 0, 0, false, false, 0, false, NMessageID::kUpdateModeUpdate, NULL, NULL }, { DI_RADIOBUTTON, kXMid + 2, 5, 0, 0, false, false, 0, false, NMessageID::kUpdateModeFreshen, NULL, NULL }, { DI_RADIOBUTTON, kXMid + 2, 6, 0, 0, false, false, 0, false, NMessageID::kUpdateModeSynchronize, NULL, NULL }, { DI_TEXT, 3, kYSize - 4, 0, 0, false, false, DIF_BOXCOLOR|DIF_SEPARATOR, false, -1, "", NULL }, { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, true, NMessageID::kUpdateAdd, NULL, NULL }, { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, false, NMessageID::kCancel, NULL, NULL } }; const int kNumDialogItems = sizeof(initItems) / sizeof(initItems[0]); const int kOkButtonIndex = kNumDialogItems - 2; FarDialogItem dialogItems[kNumDialogItems]; g_StartupInfo.InitDialogItems(initItems, dialogItems, kNumDialogItems); int askCode = g_StartupInfo.ShowDialog(76, kYSize, kHelpTopic, dialogItems, kNumDialogItems); if (askCode != kOkButtonIndex) return NFileOperationReturnCode::kInterruptedByUser; compressionInfo.Level = g_MethodMap[0]; for (i = 0; i < sizeof(g_MethodMap)/ sizeof(g_MethodMap[0]); i++) if (dialogItems[kMethodRadioIndex + i].Selected) compressionInfo.Level = g_MethodMap[i]; const CActionSet *actionSet; if (dialogItems[kModeRadioIndex].Selected) actionSet = &kAddActionSet; else if (dialogItems[kModeRadioIndex + 1].Selected) actionSet = &kUpdateActionSet; else if (dialogItems[kModeRadioIndex + 2].Selected) actionSet = &kFreshActionSet; else if (dialogItems[kModeRadioIndex + 3].Selected) actionSet = &kSynchronizeActionSet; else throw 51751; compressionInfo.Save(); CWorkDirTempFile tempFile;; if (tempFile.CreateTempFile(m_FileName) != S_OK) return NFileOperationReturnCode::kError; /* CSysStringVector fileNames; for (int i = 0; i < numItems; i++) { const PluginPanelItem &panelItem = panelItems[i]; CSysString fullName; if (!MyGetFullPathName(panelItem.FindData.cFileName, fullName)) return NFileOperationReturnCode::kError; fileNames.Add(fullName); } */ CScreenRestorer screenRestorer; CProgressBox progressBox; CProgressBox *progressBoxPointer = NULL; if ((opMode & OPM_SILENT) == 0 && (opMode & OPM_FIND ) == 0) { screenRestorer.Save(); progressBoxPointer = &progressBox; progressBox.Init( // g_StartupInfo.GetMsgString(NMessageID::kWaitTitle), g_StartupInfo.GetMsgString(NMessageID::kUpdating), 48); } UStringVector pathVector; GetPathParts(pathVector); UStringVector fileNames; fileNames.Reserve(numItems); for (i = 0; i < numItems; i++) fileNames.Add(MultiByteToUnicodeString(panelItems[i].FindData.cFileName, CP_OEMCP)); CRecordVector<const wchar_t *> fileNamePointers; fileNamePointers.Reserve(numItems); for (i = 0; i < numItems; i++) fileNamePointers.Add(fileNames[i]); CMyComPtr<IOutFolderArchive> outArchive; HRESULT result = m_ArchiveHandler.QueryInterface(IID_IOutFolderArchive, &outArchive); if (result != S_OK) { g_StartupInfo.ShowMessage(NMessageID::kUpdateNotSupportedForThisArchive); return NFileOperationReturnCode::kError; } outArchive->SetFolder(_folder); outArchive->SetFiles(L"", &fileNamePointers.Front(), fileNamePointers.Size()); BYTE actionSetByte[NUpdateArchive::NPairState::kNumValues]; for (i = 0; i < NUpdateArchive::NPairState::kNumValues; i++) actionSetByte[i] = (BYTE)actionSet->StateActions[i]; CUpdateCallback100Imp *updateCallbackSpec = new CUpdateCallback100Imp; CMyComPtr<IFolderArchiveUpdateCallback> updateCallback(updateCallbackSpec ); updateCallbackSpec->Init(/* m_ArchiveHandler, */ progressBoxPointer); if (SetOutProperties(outArchive, compressionInfo.Level) != S_OK) return NFileOperationReturnCode::kError; result = outArchive->DoOperation2(tempFile.OutStream, actionSetByte, NULL, updateCallback); updateCallback.Release(); outArchive.Release(); if (result == S_OK) { result = AfterUpdate(tempFile, pathVector); } if (result != S_OK) { ShowErrorMessage(result); return NFileOperationReturnCode::kError; } /* if (moveMode != 0) { for (int i = 0; i < numItems; i++) { const PluginPanelItem &pluginPanelItem = panelItems[i]; bool result; if (NFile::NFind::NAttributes::IsDir(pluginPanelItem.FindData.dwFileAttributes)) result = NFile::NDirectory::RemoveDirectoryWithSubItems(pluginPanelItem.FindData.cFileName); else result = NFile::NDirectory::DeleteFileAlways(pluginPanelItem.FindData.cFileName); if (!result) return NFileOperationReturnCode::kError; } } */ return NFileOperationReturnCode::kSuccess; }
HRESULT CPanel::CreateShellContextMenu( const CRecordVector<UInt32> &operatedIndices, CMyComPtr<IContextMenu> &systemContextMenu) { systemContextMenu.Release(); UString folderPath = GetFsPath(); CMyComPtr<IShellFolder> desktopFolder; RINOK(::SHGetDesktopFolder(&desktopFolder)); if (!desktopFolder) { // ShowMessage("Failed to get Desktop folder."); return E_FAIL; } // Separate the file from the folder. // Get a pidl for the folder the file // is located in. LPITEMIDLIST parentPidl; DWORD eaten; RINOK(desktopFolder->ParseDisplayName( GetParent(), 0, (wchar_t *)(const wchar_t *)folderPath, &eaten, &parentPidl, 0)); // Get an IShellFolder for the folder // the file is located in. CMyComPtr<IShellFolder> parentFolder; RINOK(desktopFolder->BindToObject(parentPidl, 0, IID_IShellFolder, (void**)&parentFolder)); if (!parentFolder) { // ShowMessage("Invalid file name."); return E_FAIL; } // Get a pidl for the file itself. CRecordVector<LPITEMIDLIST> pidls; pidls.Reserve(operatedIndices.Size()); for (int i = 0; i < operatedIndices.Size(); i++) { LPITEMIDLIST pidl; UString fileName = GetItemRelPath(operatedIndices[i]); if (IsFSDrivesFolder()) fileName += WCHAR_PATH_SEPARATOR; RINOK(parentFolder->ParseDisplayName(GetParent(), 0, (wchar_t *)(const wchar_t *)fileName, &eaten, &pidl, 0)); pidls.Add(pidl); } ITEMIDLIST temp; if (pidls.Size() == 0) { temp.mkid.cb = 0; /* LPITEMIDLIST pidl; HRESULT result = parentFolder->ParseDisplayName(GetParent(), 0, L"." WSTRING_PATH_SEPARATOR, &eaten, &pidl, 0); if (result != NOERROR) return; */ pidls.Add(&temp); } // Get the IContextMenu for the file. CMyComPtr<IContextMenu> cm; RINOK( parentFolder->GetUIObjectOf(GetParent(), pidls.Size(), (LPCITEMIDLIST *)&pidls.Front(), IID_IContextMenu, 0, (void**)&cm)); if (!cm) { // ShowMessage("Unable to get context menu interface."); return E_FAIL; } systemContextMenu = cm; return S_OK; }
int CPlugin::DeleteFiles(PluginPanelItem *panelItems, int numItems, int opMode) { if (numItems == 0) return FALSE; /* if (!m_ArchiverInfo.UpdateEnabled) { g_StartupInfo.ShowMessage(NMessageID::kUpdateNotSupportedForThisArchive); return FALSE; } */ if ((opMode & OPM_SILENT) == 0) { const char *msgItems[]= { g_StartupInfo.GetMsgString(NMessageID::kDeleteTitle), g_StartupInfo.GetMsgString(NMessageID::kDeleteFiles), g_StartupInfo.GetMsgString(NMessageID::kDeleteDelete), g_StartupInfo.GetMsgString(NMessageID::kDeleteCancel) }; char msg[1024]; if (numItems == 1) { sprintf(msg, g_StartupInfo.GetMsgString(NMessageID::kDeleteFile), panelItems[0].FindData.cFileName); msgItems[1] = msg; } else if (numItems > 1) { sprintf(msg, g_StartupInfo.GetMsgString(NMessageID::kDeleteNumberOfFiles), numItems); msgItems[1] = msg; } if (g_StartupInfo.ShowMessage(FMSG_WARNING, NULL, msgItems, sizeof(msgItems) / sizeof(msgItems[0]), 2) != 0) return (FALSE); } CScreenRestorer screenRestorer; CProgressBox progressBox; CProgressBox *progressBoxPointer = NULL; if ((opMode & OPM_SILENT) == 0 && (opMode & OPM_FIND ) == 0) { screenRestorer.Save(); progressBoxPointer = &progressBox; progressBox.Init( // g_StartupInfo.GetMsgString(NMessageID::kWaitTitle), g_StartupInfo.GetMsgString(NMessageID::kDeleting), 48); } NWorkDir::CInfo workDirInfo; ReadWorkDirInfo(workDirInfo); UString workDir = GetWorkDir(workDirInfo, m_FileName); CreateComplexDirectory(workDir); CTempFileW tempFile; UString tempFileName; if (tempFile.Create(workDir, kTempArchivePrefix, tempFileName) == 0) return FALSE; CRecordVector<UINT32> indices; indices.Reserve(numItems); int i; for(i = 0; i < numItems; i++) indices.Add(panelItems[i].UserData); //////////////////////////// // Save _folder; UStringVector pathVector; GetPathParts(pathVector); CMyComPtr<IOutFolderArchive> outArchive; HRESULT result = m_ArchiveHandler.QueryInterface( IID_IOutFolderArchive, &outArchive); if(result != S_OK) { g_StartupInfo.ShowMessage(NMessageID::kUpdateNotSupportedForThisArchive); return FALSE; } outArchive->SetFolder(_folder); CUpdateCallback100Imp *updateCallbackSpec = new CUpdateCallback100Imp; CMyComPtr<IFolderArchiveUpdateCallback> updateCallback(updateCallbackSpec ); updateCallbackSpec->Init(/* m_ArchiveHandler, */ &progressBox); result = outArchive->DeleteItems( tempFileName, &indices.Front(), indices.Size(), updateCallback); updateCallback.Release(); outArchive.Release(); if (result != S_OK) { ShowErrorMessage(result); return FALSE; } _folder.Release(); m_ArchiveHandler->Close(); if (!DeleteFileAlways(m_FileName)) { ShowLastErrorMessage(); return FALSE; } tempFile.DisableDeleting(); if (!MyMoveFile(tempFileName, m_FileName)) { ShowLastErrorMessage(); return FALSE; } result = m_ArchiveHandler->ReOpen(NULL); if (result != S_OK) { ShowErrorMessage(result); return FALSE; } //////////////////////////// // Restore _folder; m_ArchiveHandler->BindToRootFolder(&_folder); for (i = 0; i < pathVector.Size(); i++) { CMyComPtr<IFolderFolder> newFolder; _folder->BindToFolder(pathVector[i], &newFolder); if(!newFolder ) break; _folder = newFolder; } GetCurrentDir(); return(TRUE); }
STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testModeSpec, IArchiveExtractCallback *extractCallback) { COM_TRY_BEGIN bool allFilesMode = (numItems == (UInt32)-1); if (allFilesMode) numItems = m_Database.NewFormat ? 1: (m_Database.LowLevel ? m_Database.Items.Size(): m_Database.Indices.Size()); if (numItems == 0) return S_OK; bool testMode = (testModeSpec != 0); UInt64 currentTotalSize = 0; NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; UInt32 i; CLocalProgress *lps = new CLocalProgress; CMyComPtr<ICompressProgressInfo> progress = lps; lps->Init(extractCallback, false); CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; CMyComPtr<ISequentialInStream> inStream(streamSpec); streamSpec->SetStream(m_Stream); if (m_Database.LowLevel) { UInt64 currentItemSize = 0; UInt64 totalSize = 0; if (m_Database.NewFormat) totalSize = m_Database.NewFormatString.Length(); else for (i = 0; i < numItems; i++) totalSize += m_Database.Items[allFilesMode ? i : indices[i]].Size; extractCallback->SetTotal(totalSize); for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize) { currentItemSize = 0; lps->InSize = currentTotalSize; // Change it lps->OutSize = currentTotalSize; RINOK(lps->SetCur()); CMyComPtr<ISequentialOutStream> realOutStream; Int32 askMode= testMode ? NExtract::NAskMode::kTest : NExtract::NAskMode::kExtract; Int32 index = allFilesMode ? i : indices[i]; RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); if (m_Database.NewFormat) { if (index != 0) return E_FAIL; if (!testMode && !realOutStream) continue; if (!testMode) { UInt32 size = m_Database.NewFormatString.Length(); RINOK(WriteStream(realOutStream, (const char *)m_Database.NewFormatString, size)); } RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); continue; } const CItem &item = m_Database.Items[index]; currentItemSize = item.Size; if (!testMode && !realOutStream) continue; RINOK(extractCallback->PrepareOperation(askMode)); if (item.Section != 0) { RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod)); continue; } if (testMode) { RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); continue; } RINOK(m_Stream->Seek(m_Database.ContentOffset + item.Offset, STREAM_SEEK_SET, NULL)); streamSpec->Init(item.Size); RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress)); realOutStream.Release(); RINOK(extractCallback->SetOperationResult((copyCoderSpec->TotalSize == item.Size) ? NExtract::NOperationResult::kOK: NExtract::NOperationResult::kDataError)); } return S_OK; } UInt64 lastFolderIndex = ((UInt64)0 - 1); for (i = 0; i < numItems; i++) { UInt32 index = allFilesMode ? i : indices[i]; int entryIndex = m_Database.Indices[index]; const CItem &item = m_Database.Items[entryIndex]; UInt64 sectionIndex = item.Section; if (item.IsDir() || item.Size == 0) continue; if (sectionIndex == 0) { currentTotalSize += item.Size; continue; } const CSectionInfo §ion = m_Database.Sections[(int)item.Section]; if (section.IsLzx()) { const CLzxInfo &lzxInfo = section.Methods[0].LzxInfo; UInt64 folderIndex = m_Database.GetFolder(index); if (lastFolderIndex == folderIndex) folderIndex++; lastFolderIndex = m_Database.GetLastFolder(index); for (; folderIndex <= lastFolderIndex; folderIndex++) currentTotalSize += lzxInfo.GetFolderSize(); } } RINOK(extractCallback->SetTotal(currentTotalSize)); NCompress::NLzx::CDecoder *lzxDecoderSpec = 0; CMyComPtr<ICompressCoder> lzxDecoder; CChmFolderOutStream *chmFolderOutStream = 0; CMyComPtr<ISequentialOutStream> outStream; currentTotalSize = 0; CRecordVector<bool> extractStatuses; for (i = 0; i < numItems;) { RINOK(extractCallback->SetCompleted(¤tTotalSize)); UInt32 index = allFilesMode ? i : indices[i]; i++; int entryIndex = m_Database.Indices[index]; const CItem &item = m_Database.Items[entryIndex]; UInt64 sectionIndex = item.Section; Int32 askMode= testMode ? NExtract::NAskMode::kTest : NExtract::NAskMode::kExtract; if (item.IsDir()) { CMyComPtr<ISequentialOutStream> realOutStream; RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); RINOK(extractCallback->PrepareOperation(askMode)); realOutStream.Release(); RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); continue; } lps->InSize = currentTotalSize; // Change it lps->OutSize = currentTotalSize; if (item.Size == 0 || sectionIndex == 0) { CMyComPtr<ISequentialOutStream> realOutStream; RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); if (!testMode && !realOutStream) continue; RINOK(extractCallback->PrepareOperation(askMode)); Int32 opRes = NExtract::NOperationResult::kOK; if (!testMode && item.Size != 0) { RINOK(m_Stream->Seek(m_Database.ContentOffset + item.Offset, STREAM_SEEK_SET, NULL)); streamSpec->Init(item.Size); RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress)); if (copyCoderSpec->TotalSize != item.Size) opRes = NExtract::NOperationResult::kDataError; } realOutStream.Release(); RINOK(extractCallback->SetOperationResult(opRes)); currentTotalSize += item.Size; continue; } const CSectionInfo §ion = m_Database.Sections[(int)sectionIndex]; if (!section.IsLzx()) { CMyComPtr<ISequentialOutStream> realOutStream; RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); if (!testMode && !realOutStream) continue; RINOK(extractCallback->PrepareOperation(askMode)); RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod)); continue; } const CLzxInfo &lzxInfo = section.Methods[0].LzxInfo; if (chmFolderOutStream == 0) { chmFolderOutStream = new CChmFolderOutStream; outStream = chmFolderOutStream; } chmFolderOutStream->Init(&m_Database, extractCallback, testMode); if (lzxDecoderSpec == NULL) { lzxDecoderSpec = new NCompress::NLzx::CDecoder; lzxDecoder = lzxDecoderSpec; } UInt64 folderIndex = m_Database.GetFolder(index); UInt64 compressedPos = m_Database.ContentOffset + section.Offset; UInt32 numDictBits = lzxInfo.GetNumDictBits(); RINOK(lzxDecoderSpec->SetParams(numDictBits)); const CItem *lastItem = &item; extractStatuses.Clear(); extractStatuses.Add(true); for (;; folderIndex++) { RINOK(extractCallback->SetCompleted(¤tTotalSize)); UInt64 startPos = lzxInfo.GetFolderPos(folderIndex); UInt64 finishPos = lastItem->Offset + lastItem->Size; UInt64 limitFolderIndex = lzxInfo.GetFolder(finishPos); lastFolderIndex = m_Database.GetLastFolder(index); UInt64 folderSize = lzxInfo.GetFolderSize(); UInt64 unPackSize = folderSize; if (extractStatuses.IsEmpty()) chmFolderOutStream->m_StartIndex = index + 1; else chmFolderOutStream->m_StartIndex = index; if (limitFolderIndex == folderIndex) { for (; i < numItems; i++) { UInt32 nextIndex = allFilesMode ? i : indices[i]; int entryIndex = m_Database.Indices[nextIndex]; const CItem &nextItem = m_Database.Items[entryIndex]; if (nextItem.Section != sectionIndex) break; UInt64 nextFolderIndex = m_Database.GetFolder(nextIndex); if (nextFolderIndex != folderIndex) break; for (index++; index < nextIndex; index++) extractStatuses.Add(false); extractStatuses.Add(true); index = nextIndex; lastItem = &nextItem; if (nextItem.Size != 0) finishPos = nextItem.Offset + nextItem.Size; lastFolderIndex = m_Database.GetLastFolder(index); } } unPackSize = MyMin(finishPos - startPos, unPackSize); chmFolderOutStream->m_FolderSize = folderSize; chmFolderOutStream->m_PosInFolder = 0; chmFolderOutStream->m_PosInSection = startPos; chmFolderOutStream->m_ExtractStatuses = &extractStatuses; chmFolderOutStream->m_NumFiles = extractStatuses.Size(); chmFolderOutStream->m_CurrentIndex = 0; try { UInt64 startBlock = lzxInfo.GetBlockIndexFromFolderIndex(folderIndex); const CResetTable &rt = lzxInfo.ResetTable; UInt32 numBlocks = (UInt32)rt.GetNumBlocks(unPackSize); for (UInt32 b = 0; b < numBlocks; b++) { UInt64 completedSize = currentTotalSize + chmFolderOutStream->m_PosInSection - startPos; RINOK(extractCallback->SetCompleted(&completedSize)); UInt64 bCur = startBlock + b; if (bCur >= rt.ResetOffsets.Size()) return E_FAIL; UInt64 offset = rt.ResetOffsets[(int)bCur]; UInt64 compressedSize; rt.GetCompressedSizeOfBlock(bCur, compressedSize); UInt64 rem = finishPos - chmFolderOutStream->m_PosInSection; if (rem > rt.BlockSize) rem = rt.BlockSize; RINOK(m_Stream->Seek(compressedPos + offset, STREAM_SEEK_SET, NULL)); streamSpec->SetStream(m_Stream); streamSpec->Init(compressedSize); lzxDecoderSpec->SetKeepHistory(b > 0); HRESULT res = lzxDecoder->Code(inStream, outStream, NULL, &rem, NULL); if (res != S_OK) { if (res != S_FALSE) return res; throw 1; } } } catch(...) { RINOK(chmFolderOutStream->FlushCorrupted(unPackSize)); } currentTotalSize += folderSize; if (folderIndex == lastFolderIndex) break; extractStatuses.Clear(); } } return S_OK; COM_TRY_END }
int CPlugin::DeleteFiles(PluginPanelItem *panelItems, int numItems, int opMode) { if (numItems == 0) return FALSE; /* if (!m_ArchiverInfo.UpdateEnabled) { g_StartupInfo.ShowMessage(NMessageID::kUpdateNotSupportedForThisArchive); return FALSE; } */ if ((opMode & OPM_SILENT) == 0) { const char *msgItems[]= { g_StartupInfo.GetMsgString(NMessageID::kDeleteTitle), g_StartupInfo.GetMsgString(NMessageID::kDeleteFiles), g_StartupInfo.GetMsgString(NMessageID::kDeleteDelete), g_StartupInfo.GetMsgString(NMessageID::kDeleteCancel) }; char msg[1024]; if (numItems == 1) { sprintf(msg, g_StartupInfo.GetMsgString(NMessageID::kDeleteFile), panelItems[0].FindData.cFileName); msgItems[1] = msg; } else if (numItems > 1) { sprintf(msg, g_StartupInfo.GetMsgString(NMessageID::kDeleteNumberOfFiles), numItems); msgItems[1] = msg; } if (g_StartupInfo.ShowMessage(FMSG_WARNING, NULL, msgItems, sizeof(msgItems) / sizeof(msgItems[0]), 2) != 0) return (FALSE); } CScreenRestorer screenRestorer; CProgressBox progressBox; CProgressBox *progressBoxPointer = NULL; if ((opMode & OPM_SILENT) == 0 && (opMode & OPM_FIND ) == 0) { screenRestorer.Save(); progressBoxPointer = &progressBox; progressBox.Init( // g_StartupInfo.GetMsgString(NMessageID::kWaitTitle), g_StartupInfo.GetMsgString(NMessageID::kDeleting), 48); } CWorkDirTempFile tempFile; if (tempFile.CreateTempFile(m_FileName) != S_OK) return FALSE; CRecordVector<UINT32> indices; indices.Reserve(numItems); int i; for (i = 0; i < numItems; i++) indices.Add((UINT32)panelItems[i].UserData); //////////////////////////// // Save _folder; UStringVector pathVector; GetPathParts(pathVector); CMyComPtr<IOutFolderArchive> outArchive; HRESULT result = m_ArchiveHandler.QueryInterface(IID_IOutFolderArchive, &outArchive); if (result != S_OK) { g_StartupInfo.ShowMessage(NMessageID::kUpdateNotSupportedForThisArchive); return FALSE; } outArchive->SetFolder(_folder); CUpdateCallback100Imp *updateCallbackSpec = new CUpdateCallback100Imp; CMyComPtr<IFolderArchiveUpdateCallback> updateCallback(updateCallbackSpec); updateCallbackSpec->Init(/* m_ArchiveHandler, */ progressBoxPointer); result = outArchive->DeleteItems(tempFile.OutStream, &indices.Front(), indices.Size(), updateCallback); updateCallback.Release(); outArchive.Release(); if (result == S_OK) { result = AfterUpdate(tempFile, pathVector); } if (result != S_OK) { ShowErrorMessage(result); return FALSE; } GetCurrentDir(); return TRUE; }
STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) { COM_TRY_BEGIN CZipDecoder myDecoder; UInt64 totalUnPacked = 0, totalPacked = 0; bool allFilesMode = (numItems == (UInt32)(Int32)-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.Size; 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 ? NExtract::NAskMode::kTest : NExtract::NAskMode::kExtract; UInt32 index = allFilesMode ? i : indices[i]; CItemEx item = m_Items[index]; bool isLocalOffsetOK = m_Archive.IsLocalOffsetOK(item); bool skip = !isLocalOffsetOK && !item.IsDir(); if (skip) askMode = NExtract::NAskMode::kSkip; currentItemUnPacked = item.Size; currentItemPacked = item.PackSize; RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); if (!isLocalOffsetOK) { RINOK(extractCallback->PrepareOperation(askMode)); realOutStream.Release(); RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnavailable)); continue; } 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(NExtract::NOperationResult::kHeadersError)); } continue; } RINOK(res); } if (item.IsDir()) { // if (!testMode) { RINOK(extractCallback->PrepareOperation(askMode)); realOutStream.Release(); RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); } continue; } if (!testMode && !realOutStream) continue; RINOK(extractCallback->PrepareOperation(askMode)); Int32 res; HRESULT hres = myDecoder.Decode( EXTERNAL_CODECS_VARS m_Archive, item, realOutStream, extractCallback, progress, #ifndef _7ZIP_ST _props.NumThreads, #endif res); RINOK(hres); realOutStream.Release(); RINOK(extractCallback->SetOperationResult(res)) } lps->InSize = currentTotalPacked; lps->OutSize = currentTotalUnPacked; return lps->SetCur(); COM_TRY_END }