static HRESULT EnumerateAltStreams( const NFind::CFileInfo &fi, const NWildcard::CCensorNode &curNode, int phyParent, int logParent, const FString &fullPath, const UStringVector &addArchivePrefix, // prefix from curNode CDirItems &dirItems) { NFind::CStreamEnumerator enumerator(fullPath); for (;;) { NFind::CStreamInfo si; bool found; if (!enumerator.Next(si, found)) { return dirItems.AddError(fullPath + FTEXT(":*")); // , (DWORD)E_FAIL } if (!found) return S_OK; if (si.IsMainStream()) continue; UStringVector addArchivePrefixNew = addArchivePrefix; UString reducedName = si.GetReducedName(); addArchivePrefixNew.Back() += reducedName; if (curNode.CheckPathToRoot(false, addArchivePrefixNew, true)) continue; NFind::CFileInfo fi2 = fi; fi2.Name += us2fs(reducedName); fi2.Size = si.Size; fi2.Attrib &= ~FILE_ATTRIBUTE_DIRECTORY; fi2.IsAltStream = true; dirItems.AddDirFileInfo(phyParent, logParent, -1, fi2); } }
HRESULT DecompressArchive( IInArchive *archive, const UString &defaultName, const NWildcard::CCensorNode &wildcardCensor, const CExtractOptions &options, IExtractCallbackUI *callback) { CRecordVector<UInt32> realIndices; UInt32 numItems; RINOK(archive->GetNumberOfItems(&numItems)); for(UInt32 i = 0; i < numItems; i++) { UString filePath; RINOK(GetArchiveItemPath(archive, i, options.DefaultItemName, filePath)); bool isFolder; RINOK(IsArchiveItemFolder(archive, i, isFolder)); if (!wildcardCensor.CheckPath(filePath, !isFolder)) continue; realIndices.Add(i); } if (realIndices.Size() == 0) { callback->ThereAreNoFiles(); return S_OK; } CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback; CMyComPtr<IArchiveExtractCallback> extractCallback(extractCallbackSpec); UStringVector removePathParts; UString outDir = options.OutputDir; outDir.Replace(L"*", defaultName); if(!outDir.IsEmpty()) if(!NFile::NDirectory::CreateComplexDirectory(outDir)) { throw UString(L"Can not create output directory ") + outDir; } extractCallbackSpec->Init( archive, callback, options.StdOutMode, outDir, options.PathMode, options.OverwriteMode, removePathParts, options.DefaultItemName, options.ArchiveFileInfo.LastWriteTime, options.ArchiveFileInfo.Attributes); HRESULT result = archive->Extract(&realIndices.Front(), realIndices.Size(), options.TestMode? 1: 0, extractCallback); return callback->ExtractResult(result); }
static HRESULT EnumerateForItem( NFind::CFileInfo &fi, const NWildcard::CCensorNode &curNode, int phyParent, int logParent, const FString &phyPrefix, const UStringVector &addArchivePrefix, // prefix from curNode CDirItems &dirItems, bool enterToSubFolders) { const UString name = fs2us(fi.Name); bool enterToSubFolders2 = enterToSubFolders; UStringVector addArchivePrefixNew = addArchivePrefix; addArchivePrefixNew.Add(name); { UStringVector addArchivePrefixNewTemp(addArchivePrefixNew); if (curNode.CheckPathToRoot(false, addArchivePrefixNewTemp, !fi.IsDir())) return S_OK; } int dirItemIndex = -1; bool addAllSubStreams = false; if (curNode.CheckPathToRoot(true, addArchivePrefixNew, !fi.IsDir())) { int secureIndex = -1; #ifdef _USE_SECURITY_CODE if (dirItems.ReadSecure) { RINOK(dirItems.AddSecurityItem(phyPrefix + fi.Name, secureIndex)); } #endif dirItemIndex = dirItems.Items.Size(); dirItems.AddDirFileInfo(phyParent, logParent, secureIndex, fi); if (fi.IsDir()) enterToSubFolders2 = true; addAllSubStreams = true; } #ifndef UNDER_CE if (dirItems.ScanAltStreams) { RINOK(EnumerateAltStreams(fi, curNode, phyParent, logParent, phyPrefix + fi.Name, addArchivePrefixNew, addAllSubStreams, dirItems)); } if (dirItemIndex >= 0) { CDirItem &dirItem = dirItems.Items[dirItemIndex]; RINOK(dirItems.SetLinkInfo(dirItem, fi, phyPrefix)); if (dirItem.ReparseData.Size() != 0) return S_OK; } #endif if (!fi.IsDir()) return S_OK; const NWildcard::CCensorNode *nextNode = 0; if (addArchivePrefix.IsEmpty()) { int index = curNode.FindSubNode(name); if (index >= 0) nextNode = &curNode.SubNodes[index]; } if (!enterToSubFolders2 && nextNode == 0) return S_OK; addArchivePrefixNew = addArchivePrefix; if (nextNode == 0) { nextNode = &curNode; addArchivePrefixNew.Add(name); } return EnumerateDirItems_Spec( *nextNode, phyParent, logParent, fi.Name, phyPrefix, addArchivePrefixNew, dirItems, enterToSubFolders2); }
static HRESULT DecompressArchive( IInArchive *archive, UInt64 packSize, const NWildcard::CCensorNode &wildcardCensor, const CExtractOptions &options, IExtractCallbackUI *callback, CArchiveExtractCallback *extractCallbackSpec, UString &errorMessage) { CRecordVector<UInt32> realIndices; UInt32 numItems; RINOK(archive->GetNumberOfItems(&numItems)); for(UInt32 i = 0; i < numItems; i++) { UString filePath; RINOK(GetArchiveItemPath(archive, i, options.DefaultItemName, filePath)); bool isFolder; RINOK(IsArchiveItemFolder(archive, i, isFolder)); if (!wildcardCensor.CheckPath(filePath, !isFolder)) continue; realIndices.Add(i); } if (realIndices.Size() == 0) { callback->ThereAreNoFiles(); return S_OK; } UStringVector removePathParts; UString outDir = options.OutputDir; outDir.Replace(L"*", options.DefaultItemName); #ifdef _WIN32 outDir.TrimRight(); #endif if(!outDir.IsEmpty()) if(!NFile::NDirectory::CreateComplexDirectory(outDir)) { HRESULT res = ::GetLastError(); if (res == S_OK) res = E_FAIL; errorMessage = ((UString)L"Can not create output directory ") + outDir; return res; } extractCallbackSpec->Init( archive, callback, options.StdOutMode, outDir, removePathParts, options.DefaultItemName, options.ArchiveFileInfo.MTime, options.ArchiveFileInfo.Attrib, packSize); #ifdef COMPRESS_MT RINOK(SetProperties(archive, options.Properties)); #endif HRESULT result = archive->Extract(&realIndices.Front(), realIndices.Size(), options.TestMode? 1: 0, extractCallbackSpec); return callback->ExtractResult(result); }
HRESULT ListArchives(CCodecs *codecs, const CIntVector &formatIndices, bool stdInMode, UStringVector &arcPaths, UStringVector &arcPathsFull, const NWildcard::CCensorNode &wildcardCensor, bool enableHeaders, bool techMode, #ifndef _NO_CRYPTO bool &passwordEnabled, UString &password, #endif UInt64 &numErrors) { numErrors = 0; CFieldPrinter fieldPrinter; if (!techMode) fieldPrinter.Init(kStandardFieldTable, sizeof(kStandardFieldTable) / sizeof(kStandardFieldTable[0])); UInt64 numFiles2 = 0, numDirs2 = 0, totalPackSize2 = 0, totalUnPackSize2 = 0; UInt64 *totalPackSizePointer2 = 0, *totalUnPackSizePointer2 = 0; int numArcs = /* stdInMode ? 1 : */ arcPaths.Size(); for (int i = 0; i < numArcs; i++) { const UString &archiveName = arcPaths[i]; UInt64 arcPackSize = 0; if (!stdInMode) { NFile::NFind::CFileInfoW fi; if (!fi.Find(archiveName) || fi.IsDir()) { g_StdOut << endl << "Error: " << archiveName << " is not file" << endl; numErrors++; continue; } arcPackSize = fi.Size; } CArchiveLink archiveLink; COpenCallbackConsole openCallback; openCallback.OutStream = &g_StdOut; #ifndef _NO_CRYPTO openCallback.PasswordIsDefined = passwordEnabled; openCallback.Password = password; #endif HRESULT result = archiveLink.Open2(codecs, formatIndices, stdInMode, NULL, archiveName, &openCallback); if (result != S_OK) { if (result == E_ABORT) return result; g_StdOut << endl << "Error: " << archiveName << ": "; if (result == S_FALSE) { #ifndef _NO_CRYPTO if (openCallback.Open_WasPasswordAsked()) g_StdOut << "Can not open encrypted archive. Wrong password?"; else #endif g_StdOut << "Can not open file as archive"; } else if (result == E_OUTOFMEMORY) g_StdOut << "Can't allocate required memory"; else g_StdOut << NError::MyFormatMessage(result); g_StdOut << endl; numErrors++; continue; } if (!stdInMode) for (int v = 0; v < archiveLink.VolumePaths.Size(); v++) { int index = arcPathsFull.FindInSorted(archiveLink.VolumePaths[v]); if (index >= 0 && index > i) { arcPaths.Delete(index); arcPathsFull.Delete(index); numArcs = arcPaths.Size(); } } if (enableHeaders) { g_StdOut << endl << kListing << archiveName << endl << endl; for (int i = 0; i < archiveLink.Arcs.Size(); i++) { const CArc &arc = archiveLink.Arcs[i]; g_StdOut << "--\n"; PrintPropPair(L"Path", arc.Path); PrintPropPair(L"Type", codecs->Formats[arc.FormatIndex].Name); if (!arc.ErrorMessage.IsEmpty()) PrintPropPair(L"Error", arc.ErrorMessage); UInt32 numProps; IInArchive *archive = arc.Archive; if (archive->GetNumberOfArchiveProperties(&numProps) == S_OK) { for (UInt32 j = 0; j < numProps; j++) { CMyComBSTR name; PROPID propID; VARTYPE vt; RINOK(archive->GetArchivePropertyInfo(j, &name, &propID, &vt)); NCOM::CPropVariant prop; RINOK(archive->GetArchiveProperty(propID, &prop)); UString s = ConvertPropertyToString(prop, propID); if (!s.IsEmpty()) PrintPropPair(GetPropName(propID, name), s); } } if (i != archiveLink.Arcs.Size() - 1) { UInt32 numProps; g_StdOut << "----\n"; if (archive->GetNumberOfProperties(&numProps) == S_OK) { UInt32 mainIndex = archiveLink.Arcs[i + 1].SubfileIndex; for (UInt32 j = 0; j < numProps; j++) { CMyComBSTR name; PROPID propID; VARTYPE vt; RINOK(archive->GetPropertyInfo(j, &name, &propID, &vt)); NCOM::CPropVariant prop; RINOK(archive->GetProperty(mainIndex, propID, &prop)); UString s = ConvertPropertyToString(prop, propID); if (!s.IsEmpty()) PrintPropPair(GetPropName(propID, name), s); } } } } g_StdOut << endl; if (techMode) g_StdOut << "----------\n"; } if (enableHeaders && !techMode) { fieldPrinter.PrintTitle(); g_StdOut << endl; fieldPrinter.PrintTitleLines(); g_StdOut << endl; } const CArc &arc = archiveLink.Arcs.Back(); IInArchive *archive = arc.Archive; if (techMode) { RINOK(fieldPrinter.Init(archive)); } UInt64 numFiles = 0, numDirs = 0, totalPackSize = 0, totalUnPackSize = 0; UInt64 *totalPackSizePointer = 0, *totalUnPackSizePointer = 0; UInt32 numItems; RINOK(archive->GetNumberOfItems(&numItems)); for (UInt32 i = 0; i < numItems; i++) { if (NConsoleClose::TestBreakSignal()) return E_ABORT; UString filePath; HRESULT res = arc.GetItemPath(i, filePath); if (stdInMode && res == E_INVALIDARG) break; RINOK(res); bool isFolder; RINOK(IsArchiveItemFolder(archive, i, isFolder)); if (!wildcardCensor.CheckPath(filePath, !isFolder)) continue; fieldPrinter.PrintItemInfo(arc, i, techMode); UInt64 packSize, unpackSize; if (!GetUInt64Value(archive, i, kpidSize, unpackSize)) unpackSize = 0; else totalUnPackSizePointer = &totalUnPackSize; if (!GetUInt64Value(archive, i, kpidPackSize, packSize)) packSize = 0; else totalPackSizePointer = &totalPackSize; g_StdOut << endl; if (isFolder) numDirs++; else numFiles++; totalPackSize += packSize; totalUnPackSize += unpackSize; } if (!stdInMode && totalPackSizePointer == 0) { if (archiveLink.VolumePaths.Size() != 0) arcPackSize += archiveLink.VolumesSize; totalPackSize = (numFiles == 0) ? 0 : arcPackSize; totalPackSizePointer = &totalPackSize; } if (totalUnPackSizePointer == 0 && numFiles == 0) { totalUnPackSize = 0; totalUnPackSizePointer = &totalUnPackSize; } if (enableHeaders && !techMode) { fieldPrinter.PrintTitleLines(); g_StdOut << endl; fieldPrinter.PrintSummaryInfo(numFiles, numDirs, totalUnPackSizePointer, totalPackSizePointer); g_StdOut << endl; } if (totalPackSizePointer != 0) { totalPackSizePointer2 = &totalPackSize2; totalPackSize2 += totalPackSize; } if (totalUnPackSizePointer != 0) { totalUnPackSizePointer2 = &totalUnPackSize2; totalUnPackSize2 += totalUnPackSize; } numFiles2 += numFiles; numDirs2 += numDirs; } if (enableHeaders && !techMode && numArcs > 1) { g_StdOut << endl; fieldPrinter.PrintTitleLines(); g_StdOut << endl; fieldPrinter.PrintSummaryInfo(numFiles2, numDirs2, totalUnPackSizePointer2, totalPackSizePointer2); g_StdOut << endl; g_StdOut << "Archives: " << numArcs << endl; } return S_OK; }
static HRESULT EnumerateDirItems( const NWildcard::CCensorNode &curNode, const UString &diskPrefix, // full disk path prefix const UString &archivePrefix, // prefix from root const UStringVector &addArchivePrefix, // prefix from curNode CObjectVector<CDirItem> &dirItems, bool enterToSubFolders, IEnumDirItemCallback *callback, UStringVector &errorPaths, CRecordVector<DWORD> &errorCodes) { if (!enterToSubFolders) if (curNode.NeedCheckSubDirs()) enterToSubFolders = true; if (callback) RINOK(callback->CheckBreak()); // try direct_names case at first if (addArchivePrefix.IsEmpty() && !enterToSubFolders) { // check that all names are direct int i; for (i = 0; i < curNode.IncludeItems.Size(); i++) { const NWildcard::CItem &item = curNode.IncludeItems[i]; if (item.Recursive || item.PathParts.Size() != 1) break; const UString &name = item.PathParts.Front(); if (name.IsEmpty() || DoesNameContainWildCard(name)) break; } if (i == curNode.IncludeItems.Size()) { // all names are direct (no wildcards) // so we don't need file_system's dir enumerator CRecordVector<bool> needEnterVector; for (i = 0; i < curNode.IncludeItems.Size(); i++) { const NWildcard::CItem &item = curNode.IncludeItems[i]; const UString &name = item.PathParts.Front(); const UString fullPath = diskPrefix + name; NFind::CFileInfoW fileInfo; if (!NFind::FindFile(fullPath, fileInfo)) { errorCodes.Add(::GetLastError()); errorPaths.Add(fullPath); continue; } bool isDir = fileInfo.IsDirectory(); if (isDir && !item.ForDir || !isDir && !item.ForFile) { errorCodes.Add((DWORD)E_FAIL); errorPaths.Add(fullPath); continue; } const UString realName = fileInfo.getFileName(); const UString realDiskPath = diskPrefix + realName; { UStringVector pathParts; pathParts.Add(fileInfo.getFileName()); if (curNode.CheckPathToRoot(false, pathParts, !isDir)) continue; } AddDirFileInfo(archivePrefix, realDiskPath, fileInfo, dirItems); if (!isDir) continue; UStringVector addArchivePrefixNew; const NWildcard::CCensorNode *nextNode = 0; int index = curNode.FindSubNode(name); if (index >= 0) { for (int t = needEnterVector.Size(); t <= index; t++) needEnterVector.Add(true); needEnterVector[index] = false; nextNode = &curNode.SubNodes[index]; } else { nextNode = &curNode; addArchivePrefixNew.Add(name); // don't change it to realName. It's for shortnames support } RINOK(EnumerateDirItems(*nextNode, realDiskPath + wchar_t(kDirDelimiter), archivePrefix + realName + wchar_t(kDirDelimiter), addArchivePrefixNew, dirItems, true, callback, errorPaths, errorCodes)); } for (i = 0; i < curNode.SubNodes.Size(); i++) { if (i < needEnterVector.Size()) if (!needEnterVector[i]) continue; const NWildcard::CCensorNode &nextNode = curNode.SubNodes[i]; const UString fullPath = diskPrefix + nextNode.Name; NFind::CFileInfoW fileInfo; if (!NFind::FindFile(fullPath, fileInfo)) { if (!nextNode.AreThereIncludeItems()) continue; errorCodes.Add(::GetLastError()); errorPaths.Add(fullPath); continue; } if (!fileInfo.IsDirectory()) { errorCodes.Add((DWORD)E_FAIL); errorPaths.Add(fullPath); continue; } RINOK(EnumerateDirItems(nextNode, diskPrefix + fileInfo.getFileName() + wchar_t(kDirDelimiter), archivePrefix + fileInfo.getFileName() + wchar_t(kDirDelimiter), UStringVector(), dirItems, false, callback, errorPaths, errorCodes)); } return S_OK; } } NFind::CEnumeratorW enumerator(diskPrefix + wchar_t(kAnyStringWildcard)); for (;;) { NFind::CFileInfoW fileInfo; bool found; if (!enumerator.Next(fileInfo, found)) { errorCodes.Add(::GetLastError()); errorPaths.Add(diskPrefix); break; } if (!found) break; if (callback) RINOK(callback->CheckBreak()); const UString &name = fileInfo.getFileName(); bool enterToSubFolders2 = enterToSubFolders; UStringVector addArchivePrefixNew = addArchivePrefix; addArchivePrefixNew.Add(name); { UStringVector addArchivePrefixNewTemp(addArchivePrefixNew); if (curNode.CheckPathToRoot(false, addArchivePrefixNewTemp, !fileInfo.IsDirectory())) continue; } if (curNode.CheckPathToRoot(true, addArchivePrefixNew, !fileInfo.IsDirectory())) { AddDirFileInfo(archivePrefix, diskPrefix + name, fileInfo, dirItems); if (fileInfo.IsDirectory()) enterToSubFolders2 = true; } if (!fileInfo.IsDirectory()) continue; const NWildcard::CCensorNode *nextNode = 0; if (addArchivePrefix.IsEmpty()) { int index = curNode.FindSubNode(name); if (index >= 0) nextNode = &curNode.SubNodes[index]; } if (!enterToSubFolders2 && nextNode == 0) continue; addArchivePrefixNew = addArchivePrefix; if (nextNode == 0) { nextNode = &curNode; addArchivePrefixNew.Add(name); } RINOK(EnumerateDirItems(*nextNode, diskPrefix + name + wchar_t(kDirDelimiter), archivePrefix + name + wchar_t(kDirDelimiter), addArchivePrefixNew, dirItems, enterToSubFolders2, callback, errorPaths, errorCodes)); } return S_OK; }
int APIENTRY WinMain2() { UString password; bool assumeYes = false; bool outputFolderDefined = false; UString outputFolder; UStringVector subStrings; NCommandLineParser::SplitCommandLine(GetCommandLineW(), subStrings); for (int i = 1; i < subStrings.Size(); i++) { const UString &s = subStrings[i]; if (s.CompareNoCase(L"-y") == 0) assumeYes = true; else if (s.Left(2).CompareNoCase(L"-o") == 0) { outputFolder = s.Mid(2); NWindows::NFile::NName::NormalizeDirPathPrefix(outputFolder); outputFolderDefined = !outputFolder.IsEmpty(); } else if (s.Left(2).CompareNoCase(L"-p") == 0) { password = s.Mid(2); } } UString path; NWindows::NDLL::MyGetModuleFileName(g_hInstance, path); UString fullPath; int fileNamePartStartIndex; if (!NWindows::NFile::NDirectory::MyGetFullPathName(path, fullPath, fileNamePartStartIndex)) { ShowErrorMessage(L"Error 1329484"); return 1; } CCodecs *codecs = new CCodecs; CMyComPtr<IUnknown> compressCodecsInfo = codecs; HRESULT result = codecs->Load(); if (result != S_OK) { ErrorMessageForHRESULT(result); return 1; } // COpenCallbackGUI openCallback; // openCallback.PasswordIsDefined = !password.IsEmpty(); // openCallback.Password = password; CExtractCallbackImp *ecs = new CExtractCallbackImp; CMyComPtr<IFolderArchiveExtractCallback> extractCallback = ecs; ecs->Init(); ecs->PasswordIsDefined = !password.IsEmpty(); ecs->Password = password; CExtractOptions eo; eo.OutputDir = outputFolderDefined ? outputFolder : fullPath.Left(fileNamePartStartIndex); eo.YesToAll = assumeYes; eo.OverwriteMode = assumeYes ? NExtract::NOverwriteMode::kWithoutPrompt : NExtract::NOverwriteMode::kAskBefore; eo.PathMode = NExtract::NPathMode::kFullPathnames; eo.TestMode = false; UStringVector v1, v2; v1.Add(fullPath); v2.Add(fullPath); NWildcard::CCensorNode wildcardCensor; wildcardCensor.AddItem(true, L"*", true, true, true); result = ExtractGUI(codecs, CIntVector(), v1, v2, wildcardCensor, eo, (assumeYes ? false: true), ecs); if (result == S_OK) { if (ecs->Messages.Size() > 0 || ecs->NumArchiveErrors != 0) return NExitCode::kFatalError; return 0; } if (result == E_ABORT) return NExitCode::kUserBreak; if (result == S_FALSE) ShowErrorMessage(L"Error in archive"); else ErrorMessageForHRESULT(result); if (result == E_OUTOFMEMORY) return NExitCode::kMemoryError; return NExitCode::kFatalError; }
static HRESULT EnumerateDirItems(const NWildcard::CCensorNode &curNode, int phyParent, int logParent, const FString &phyPrefix, const UStringVector &addArchivePrefix, // prefix from curNode CDirItems &dirItems, bool enterToSubFolders, IEnumDirItemCallback *callback, FStringVector &errorPaths, CRecordVector<DWORD> &errorCodes) { if (!enterToSubFolders) if (curNode.NeedCheckSubDirs()) enterToSubFolders = true; if (callback) RINOK(callback->ScanProgress(dirItems.GetNumFolders(), dirItems.Items.Size(), fs2us(phyPrefix))); // try direct_names case at first if (addArchivePrefix.IsEmpty() && !enterToSubFolders) { // check that all names are direct int i; for (i = 0; i < curNode.IncludeItems.Size(); i++) { const NWildcard::CItem &item = curNode.IncludeItems[i]; if (item.Recursive || item.PathParts.Size() != 1) break; const UString &name = item.PathParts.Front(); if (name.IsEmpty() || DoesNameContainWildCard(name)) break; } if (i == curNode.IncludeItems.Size()) { // all names are direct (no wildcards) // so we don't need file_system's dir enumerator CRecordVector<bool> needEnterVector; for (i = 0; i < curNode.IncludeItems.Size(); i++) { const NWildcard::CItem &item = curNode.IncludeItems[i]; const UString &name = item.PathParts.Front(); const FString fullPath = phyPrefix + us2fs(name); NFind::CFileInfo fi; if (!fi.Find(fullPath)) { errorCodes.Add(::GetLastError()); errorPaths.Add(fullPath); continue; } bool isDir = fi.IsDir(); if (isDir && !item.ForDir || !isDir && !item.ForFile) { errorCodes.Add((DWORD)E_FAIL); errorPaths.Add(fullPath); continue; } { UStringVector pathParts; pathParts.Add(fs2us(fi.Name)); if (curNode.CheckPathToRoot(false, pathParts, !isDir)) continue; } AddDirFileInfo(phyParent, logParent, fi, dirItems.Items); if (!isDir) continue; UStringVector addArchivePrefixNew; const NWildcard::CCensorNode *nextNode = 0; int index = curNode.FindSubNode(name); if (index >= 0) { for (int t = needEnterVector.Size(); t <= index; t++) needEnterVector.Add(true); needEnterVector[index] = false; nextNode = &curNode.SubNodes[index]; } else { nextNode = &curNode; addArchivePrefixNew.Add(name); // don't change it to fi.Name. It's for shortnames support } RINOK(EnumerateDirItems_Spec(*nextNode, phyParent, logParent, fi.Name, phyPrefix, addArchivePrefixNew, dirItems, true, callback, errorPaths, errorCodes)); } for (i = 0; i < curNode.SubNodes.Size(); i++) { if (i < needEnterVector.Size()) if (!needEnterVector[i]) continue; const NWildcard::CCensorNode &nextNode = curNode.SubNodes[i]; const FString fullPath = phyPrefix + us2fs(nextNode.Name); NFind::CFileInfo fi; if (!fi.Find(fullPath)) { if (!nextNode.AreThereIncludeItems()) continue; errorCodes.Add(::GetLastError()); errorPaths.Add(fullPath); continue; } if (!fi.IsDir()) { errorCodes.Add((DWORD)E_FAIL); errorPaths.Add(fullPath); continue; } RINOK(EnumerateDirItems_Spec(nextNode, phyParent, logParent, fi.Name, phyPrefix, UStringVector(), dirItems, false, callback, errorPaths, errorCodes)); } return S_OK; } } NFind::CEnumerator enumerator(phyPrefix + FCHAR_ANY_MASK); for (int ttt = 0; ; ttt++) { NFind::CFileInfo fi; bool found; if (!enumerator.Next(fi, found)) { errorCodes.Add(::GetLastError()); errorPaths.Add(phyPrefix); break; } if (!found) break; if (callback && (ttt & 0xFF) == 0xFF) RINOK(callback->ScanProgress(dirItems.GetNumFolders(), dirItems.Items.Size(), fs2us(phyPrefix))); const UString &name = fs2us(fi.Name); bool enterToSubFolders2 = enterToSubFolders; UStringVector addArchivePrefixNew = addArchivePrefix; addArchivePrefixNew.Add(name); { UStringVector addArchivePrefixNewTemp(addArchivePrefixNew); if (curNode.CheckPathToRoot(false, addArchivePrefixNewTemp, !fi.IsDir())) continue; } if (curNode.CheckPathToRoot(true, addArchivePrefixNew, !fi.IsDir())) { AddDirFileInfo(phyParent, logParent, fi, dirItems.Items); if (fi.IsDir()) enterToSubFolders2 = true; } if (!fi.IsDir()) continue; const NWildcard::CCensorNode *nextNode = 0; if (addArchivePrefix.IsEmpty()) { int index = curNode.FindSubNode(name); if (index >= 0) nextNode = &curNode.SubNodes[index]; } if (!enterToSubFolders2 && nextNode == 0) continue; addArchivePrefixNew = addArchivePrefix; if (nextNode == 0) { nextNode = &curNode; addArchivePrefixNew.Add(name); } RINOK(EnumerateDirItems_Spec(*nextNode, phyParent, logParent, fi.Name, phyPrefix, addArchivePrefixNew, dirItems, enterToSubFolders2, callback, errorPaths, errorCodes)); } return S_OK; }
int APIENTRY WinMain2() { // OleInitialize is required for ProgressBar in TaskBar. #ifndef UNDER_CE OleInitialize(NULL); #endif #ifndef UNDER_CE g_ComCtl32Version = ::GetDllVersion(TEXT("comctl32.dll")); g_LVN_ITEMACTIVATE_Support = (g_ComCtl32Version >= MAKELONG(71, 4)); #endif UString password; bool assumeYes = false; bool outputFolderDefined = false; FString outputFolder; UStringVector commandStrings; NCommandLineParser::SplitCommandLine(GetCommandLineW(), commandStrings); #ifndef UNDER_CE if (commandStrings.Size() > 0) commandStrings.Delete(0); #endif FOR_VECTOR (i, commandStrings) { const UString &s = commandStrings[i]; if (s.Len() > 1 && s[0] == '-') { wchar_t c = MyCharLower_Ascii(s[1]); if (c == 'y') { assumeYes = true; if (s.Len() != 2) { ShowErrorMessage(L"Bad command"); return 1; } } else if (c == 'o') { outputFolder = us2fs(s.Ptr(2)); NName::NormalizeDirPathPrefix(outputFolder); outputFolderDefined = !outputFolder.IsEmpty(); } else if (c == 'p') { password = s.Ptr(2); } } } FString path; NDLL::MyGetModuleFileName(path); FString fullPath; if (!MyGetFullPathName(path, fullPath)) { ShowErrorMessage(L"Error 1329484"); return 1; } CCodecs *codecs = new CCodecs; CMyComPtr<IUnknown> compressCodecsInfo = codecs; HRESULT result = codecs->Load(); if (result != S_OK) { ErrorMessageForHRESULT(result); return 1; } // COpenCallbackGUI openCallback; // openCallback.PasswordIsDefined = !password.IsEmpty(); // openCallback.Password = password; CExtractCallbackImp *ecs = new CExtractCallbackImp; CMyComPtr<IFolderArchiveExtractCallback> extractCallback = ecs; ecs->Init(); #ifndef _NO_CRYPTO ecs->PasswordIsDefined = !password.IsEmpty(); ecs->Password = password; #endif CExtractOptions eo; FString dirPrefix; if (!GetOnlyDirPrefix(path, dirPrefix)) { ShowErrorMessage(L"Error 1329485"); return 1; } eo.OutputDir = outputFolderDefined ? outputFolder : dirPrefix; eo.YesToAll = assumeYes; eo.OverwriteMode = assumeYes ? NExtract::NOverwriteMode::kOverwrite : NExtract::NOverwriteMode::kAsk; eo.PathMode = NExtract::NPathMode::kFullPaths; eo.TestMode = false; UStringVector v1, v2; v1.Add(fs2us(fullPath)); v2.Add(fs2us(fullPath)); NWildcard::CCensorNode wildcardCensor; wildcardCensor.AddItem(true, L"*", true, true, true, true); bool messageWasDisplayed = false; result = ExtractGUI(codecs, CObjectVector<COpenType>(), CIntVector(), v1, v2, wildcardCensor, eo, (assumeYes ? false: true), messageWasDisplayed, ecs); if (result == S_OK) { if (!ecs->IsOK()) return NExitCode::kFatalError; return 0; } if (result == E_ABORT) return NExitCode::kUserBreak; if (!messageWasDisplayed) { if (result == S_FALSE) ShowErrorMessage(L"Error in archive"); else ErrorMessageForHRESULT(result); } if (result == E_OUTOFMEMORY) return NExitCode::kMemoryError; return NExitCode::kFatalError; }
HRESULT ListArchives( CCodecs *codecs, UStringVector &archivePaths, UStringVector &archivePathsFull, const NWildcard::CCensorNode &wildcardCensor, bool enableHeaders, bool techMode, bool &passwordEnabled, UString &password, UInt64 &numErrors) { numErrors = 0; CFieldPrinter fieldPrinter; if (!techMode) fieldPrinter.Init(kStandardFieldTable, sizeof(kStandardFieldTable) / sizeof(kStandardFieldTable[0])); UInt64 numFiles2 = 0, numDirs2 = 0, totalPackSize2 = 0, totalUnPackSize2 = 0; UInt64 *totalPackSizePointer2 = 0, *totalUnPackSizePointer2 = 0; for (int i = 0; i < archivePaths.Size(); i++) { const UString &archiveName = archivePaths[i]; NFile::NFind::CFileInfoW archiveFileInfo; if (!NFile::NFind::FindFile(archiveName, archiveFileInfo) || archiveFileInfo.IsDirectory()) { g_StdOut << endl << "Error: " << archiveName << " is not archive" << endl; numErrors++; continue; } if (archiveFileInfo.IsDirectory()) { g_StdOut << endl << "Error: " << archiveName << " is not file" << endl; numErrors++; continue; } CArchiveLink archiveLink; COpenCallbackConsole openCallback; openCallback.OutStream = &g_StdOut; openCallback.PasswordIsDefined = passwordEnabled; openCallback.Password = password; HRESULT result = MyOpenArchive(codecs, archiveName, archiveLink, &openCallback); if (result != S_OK) { g_StdOut << endl << "Error: " << archiveName << " is not supported archive" << endl; numErrors++; continue; } for (int v = 0; v < archiveLink.VolumePaths.Size(); v++) { int index = archivePathsFull.FindInSorted(archiveLink.VolumePaths[v]); if (index >= 0 && index > i) { archivePaths.Delete(index); archivePathsFull.Delete(index); } } IInArchive *archive = archiveLink.GetArchive(); const UString defaultItemName = archiveLink.GetDefaultItemName(); if (enableHeaders) { g_StdOut << endl << kListing << archiveName << endl << endl; UInt32 numProps; if (archive->GetNumberOfArchiveProperties(&numProps) == S_OK) { for (UInt32 i = 0; i < numProps; i++) { CMyComBSTR name; PROPID propID; VARTYPE vt; if (archive->GetArchivePropertyInfo(i, &name, &propID, &vt) != S_OK) continue; NCOM::CPropVariant prop; if (archive->GetArchiveProperty(propID, &prop) != S_OK) continue; UString s = ConvertPropertyToString(prop, propID); if (!s.IsEmpty()) g_StdOut << GetPropName(propID, name) << " = " << s << endl; } } if (techMode) g_StdOut << "----------\n"; if (numProps > 0) g_StdOut << endl; } if (enableHeaders && !techMode) { fieldPrinter.PrintTitle(); g_StdOut << endl; fieldPrinter.PrintTitleLines(); g_StdOut << endl; } if (techMode) { RINOK(fieldPrinter.Init(archive)); } UInt64 numFiles = 0, numDirs = 0, totalPackSize = 0, totalUnPackSize = 0; UInt64 *totalPackSizePointer = 0, *totalUnPackSizePointer = 0; UInt32 numItems; RINOK(archive->GetNumberOfItems(&numItems)); for(UInt32 i = 0; i < numItems; i++) { if (NConsoleClose::TestBreakSignal()) return E_ABORT; UString filePath; RINOK(GetArchiveItemPath(archive, i, defaultItemName, filePath)); bool isFolder; RINOK(IsArchiveItemFolder(archive, i, isFolder)); if (!wildcardCensor.CheckPath(filePath, !isFolder)) continue; fieldPrinter.PrintItemInfo(archive, defaultItemName, archiveFileInfo, i, techMode); UInt64 packSize, unpackSize; if (!GetUInt64Value(archive, i, kpidSize, unpackSize)) unpackSize = 0; else totalUnPackSizePointer = &totalUnPackSize; if (!GetUInt64Value(archive, i, kpidPackedSize, packSize)) packSize = 0; else totalPackSizePointer = &totalPackSize; g_StdOut << endl; if (isFolder) numDirs++; else numFiles++; totalPackSize += packSize; totalUnPackSize += unpackSize; } if (enableHeaders && !techMode) { fieldPrinter.PrintTitleLines(); g_StdOut << endl; fieldPrinter.PrintSummaryInfo(numFiles, numDirs, totalUnPackSizePointer, totalPackSizePointer); g_StdOut << endl; } if (totalPackSizePointer != 0) { totalPackSizePointer2 = &totalPackSize2; totalPackSize2 += totalPackSize; } if (totalUnPackSizePointer != 0) { totalUnPackSizePointer2 = &totalUnPackSize2; totalUnPackSize2 += totalUnPackSize; } numFiles2 += numFiles; numDirs2 += numDirs; } if (enableHeaders && !techMode && archivePaths.Size() > 1) { g_StdOut << endl; fieldPrinter.PrintTitleLines(); g_StdOut << endl; fieldPrinter.PrintSummaryInfo(numFiles2, numDirs2, totalUnPackSizePointer2, totalPackSizePointer2); g_StdOut << endl; g_StdOut << "Archives: " << archivePaths.Size() << endl; } return S_OK; }
static HRESULT DecompressArchive( const CArc &arc, UInt64 packSize, const NWildcard::CCensorNode &wildcardCensor, const CExtractOptions &options, IExtractCallbackUI *callback, CArchiveExtractCallback *extractCallbackSpec, UString &errorMessage, UInt64 &stdInProcessed) { stdInProcessed = 0; IInArchive *archive = arc.Archive; CRecordVector<UInt32> realIndices; if (!options.StdInMode) { UInt32 numItems; RINOK(archive->GetNumberOfItems(&numItems)); for (UInt32 i = 0; i < numItems; i++) { UString filePath; RINOK(arc.GetItemPath(i, filePath)); bool isFolder; RINOK(IsArchiveItemFolder(archive, i, isFolder)); if (!wildcardCensor.CheckPath(filePath, !isFolder)) continue; realIndices.Add(i); } if (realIndices.Size() == 0) { callback->ThereAreNoFiles(); return S_OK; } } UStringVector removePathParts; UString outDir = options.OutputDir; outDir.Replace(L"*", GetCorrectFsPath(arc.DefaultName)); #ifdef _WIN32 // GetCorrectFullFsPath doesn't like "..". // outDir.TrimRight(); // outDir = GetCorrectFullFsPath(outDir); #endif if (!outDir.IsEmpty()) if (!NFile::NDirectory::CreateComplexDirectory(outDir)) { HRESULT res = ::GetLastError(); if (res == S_OK) res = E_FAIL; errorMessage = ((UString)L"Can not create output directory ") + outDir; return res; } extractCallbackSpec->Init( options.StdInMode ? &wildcardCensor : NULL, &arc, callback, options.StdOutMode, options.TestMode, options.CalcCrc, outDir, removePathParts, packSize); #if !defined(_7ZIP_ST) && !defined(_SFX) RINOK(SetProperties(archive, options.Properties)); #endif HRESULT result; Int32 testMode = (options.TestMode && !options.CalcCrc) ? 1: 0; if (options.StdInMode) { result = archive->Extract(NULL, (UInt32)(Int32)-1, testMode, extractCallbackSpec); NCOM::CPropVariant prop; if (archive->GetArchiveProperty(kpidPhySize, &prop) == S_OK) if (prop.vt == VT_UI8 || prop.vt == VT_UI4) stdInProcessed = ConvertPropVariantToUInt64(prop); } else result = archive->Extract(&realIndices.Front(), realIndices.Size(), testMode, extractCallbackSpec); return callback->ExtractResult(result); }