// List.cpp #include "StdAfx.h" #include "../../../Common/IntToString.h" #include "../../../Common/MyCom.h" #include "../../../Common/StdOutStream.h" #include "../../../Common/StringConvert.h" #include "../../../Common/UTFConvert.h" #include "../../../Windows/ErrorMsg.h" #include "../../../Windows/FileDir.h" #include "../../../Windows/PropVariant.h" #include "../../../Windows/PropVariantConv.h" #include "../Common/OpenArchive.h" #include "../Common/PropIDUtils.h" #include "ConsoleClose.h" #include "List.h" #include "OpenCallbackConsole.h" using namespace NWindows; using namespace NCOM; static const char *kPropIdToName[] = { "0" , "1" , "2" , "Path" , "Name" , "Extension" , "Folder" , "Size" , "Packed Size" , "Attributes" , "Created" , "Accessed" , "Modified" , "Solid" , "Commented" , "Encrypted" , "Split Before" , "Split After" , "Dictionary Size" , "CRC" , "Type" , "Anti" , "Method" , "Host OS" , "File System" , "User" , "Group" , "Block" , "Comment" , "Position" , "Path Prefix" , "Folders" , "Files" , "Version" , "Volume" , "Multivolume" , "Offset" , "Links" , "Blocks" , "Volumes" , "Time Type" , "64-bit" , "Big-endian" , "CPU" , "Physical Size" , "Headers Size" , "Checksum" , "Characteristics" , "Virtual Address" , "ID" , "Short Name" , "Creator Application" , "Sector Size" , "Mode" , "Symbolic Link" , "Error" , "Total Size" , "Free Space" , "Cluster Size" , "Label" , "Local Name" , "Provider" , "NT Security" , "Alternate Stream" , "Aux" , "Deleted" , "Tree" , "SHA-1" , "SHA-256" , "Error Type" , "Errors" , "Errors" , "Warnings" , "Warning" , "Streams" , "Alternate Streams" , "Alternate Streams Size" , "Virtual Size" , "Unpack Size" , "Total Physical Size" , "Volume Index" , "SubType" , "Short Comment" , "Code Page" , "Is not archive type" , "Physical Size can't be detected" , "Zeros Tail Is Allowed" , "Tail Size" , "Embedded Stub Size" , "Link" , "Hard Link" , "iNode" , "Stream ID" }; static const char kEmptyAttribChar = '.'; static const char *kListing = "Listing archive: "; static const char *kString_Files = "files"; static const char *kString_Dirs = "folders"; static const char *kString_AltStreams = "alternate streams"; static const char *kString_Streams = "streams"; static void GetAttribString(UInt32 wa, bool isDir, bool allAttribs, char *s) { if (isDir) wa |= FILE_ATTRIBUTE_DIRECTORY; if (allAttribs) { ConvertWinAttribToString(s, wa); return; } s[0] = ((wa & FILE_ATTRIBUTE_DIRECTORY) != 0) ? 'D': kEmptyAttribChar; s[1] = ((wa & FILE_ATTRIBUTE_READONLY) != 0) ? 'R': kEmptyAttribChar; s[2] = ((wa & FILE_ATTRIBUTE_HIDDEN) != 0) ? 'H': kEmptyAttribChar; s[3] = ((wa & FILE_ATTRIBUTE_SYSTEM) != 0) ? 'S': kEmptyAttribChar; s[4] = ((wa & FILE_ATTRIBUTE_ARCHIVE) != 0) ? 'A': kEmptyAttribChar; s[5] = 0; } enum EAdjustment { kLeft, kCenter, kRight }; struct CFieldInfo { PROPID PropID; bool IsRawProp; UString NameU; AString NameA; EAdjustment TitleAdjustment; EAdjustment TextAdjustment; int PrefixSpacesWidth; int Width; }; struct CFieldInfoInit { PROPID PropID; const char *Name; EAdjustment TitleAdjustment; EAdjustment TextAdjustment; int PrefixSpacesWidth; int Width; }; static const CFieldInfoInit kStandardFieldTable[] = { { kpidMTime, " Date Time", kLeft, kLeft, 0, 19 }, { kpidAttrib, "Attr", kRight, kCenter, 1, 5 }, { kpidSize, "Size", kRight, kRight, 1, 12 }, { kpidPackSize, "Compressed", kRight, kRight, 1, 12 }, { kpidPath, "Name", kLeft, kLeft, 2, 24 } }; const int kNumSpacesMax = 32; // it must be larger than max CFieldInfoInit.Width static const char *g_Spaces = " " ; static void PrintSpaces(int numSpaces) { if (numSpaces > 0 && numSpaces <= kNumSpacesMax) g_StdOut << g_Spaces + (kNumSpacesMax - numSpaces); } static void PrintSpacesToString(char *dest, int numSpaces) { int i; for (i = 0; i < numSpaces; i++) dest[i] = ' '; dest[i] = 0; } static void PrintString(EAdjustment adj, int width, const UString &textString) { const int numSpaces = width - textString.Len(); int numLeftSpaces = 0; switch (adj) { case kLeft: numLeftSpaces = 0; break; case kCenter: numLeftSpaces = numSpaces / 2; break; case kRight: numLeftSpaces = numSpaces; break; } PrintSpaces(numLeftSpaces); g_StdOut << textString; PrintSpaces(numSpaces - numLeftSpaces); } static void PrintString(EAdjustment adj, int width, const char *textString) { const int numSpaces = width - (int)strlen(textString); int numLeftSpaces = 0; switch (adj) { case kLeft: numLeftSpaces = 0; break; case kCenter: numLeftSpaces = numSpaces / 2; break; case kRight: numLeftSpaces = numSpaces; break; } PrintSpaces(numLeftSpaces); g_StdOut << textString; PrintSpaces(numSpaces - numLeftSpaces); } static void PrintStringToString(char *dest, EAdjustment adj, int width, const char *textString) { int len = (int)strlen(textString); const int numSpaces = width - len; int numLeftSpaces = 0; switch (adj) { case kLeft: numLeftSpaces = 0; break; case kCenter: numLeftSpaces = numSpaces / 2; break; case kRight: numLeftSpaces = numSpaces; break; } PrintSpacesToString(dest, numLeftSpaces); if (numLeftSpaces > 0) dest += numLeftSpaces; memcpy(dest, textString, len); dest += len; PrintSpacesToString(dest, numSpaces - numLeftSpaces); } struct CListUInt64Def { UInt64 Val; bool Def; CListUInt64Def(): Val(0), Def(false) {} void Add(UInt64 v) { Val += v; Def = true; } void Add(const CListUInt64Def &v) { if (v.Def) Add(v.Val); } }; struct CListFileTimeDef { FILETIME Val; bool Def; CListFileTimeDef(): Def(false) { Val.dwLowDateTime = 0; Val.dwHighDateTime = 0; } void Update(const CListFileTimeDef &t) { if (t.Def && (!Def || CompareFileTime(&Val, &t.Val) < 0)) { Val = t.Val; Def = true; } } }; struct CListStat { CListUInt64Def Size; CListUInt64Def PackSize; CListFileTimeDef MTime; UInt64 NumFiles; CListStat(): NumFiles(0) {} void Update(const CListStat &stat) { Size.Add(stat.Size); PackSize.Add(stat.PackSize); MTime.Update(stat.MTime); NumFiles += stat.NumFiles; } void SetSizeDefIfNoFiles() { if (NumFiles == 0) Size.Def = true; } }; struct CListStat2 { CListStat MainFiles; CListStat AltStreams; UInt64 NumDirs; CListStat2(): NumDirs(0) {} void Update(const CListStat2 &stat) { MainFiles.Update(stat.MainFiles); AltStreams.Update(stat.AltStreams); NumDirs += stat.NumDirs; } const UInt64 GetNumStreams() const { return MainFiles.NumFiles + AltStreams.NumFiles; } CListStat &GetStat(bool altStreamsMode) { return altStreamsMode ? AltStreams : MainFiles; } }; class CFieldPrinter { CObjectVector<CFieldInfo> _fields; void AddProp(BSTR name, PROPID propID, bool isRawProp); public: const CArc *Arc; bool TechMode; UString FilePath; AString TempAString; UString TempWString; bool IsFolder; AString LinesString; void Clear() { _fields.Clear(); LinesString.Empty(); } void Init(const CFieldInfoInit *standardFieldTable, int numItems); HRESULT AddMainProps(IInArchive *archive); HRESULT AddRawProps(IArchiveGetRawProps *getRawProps); void PrintTitle(); void PrintTitleLines(); HRESULT PrintItemInfo(UInt32 index, const CListStat &stat); void PrintSum(const CListStat &stat, UInt64 numDirs, const char *str); void PrintSum(const CListStat2 &stat); }; void CFieldPrinter::Init(const CFieldInfoInit *standardFieldTable, int numItems) { Clear(); for (int i = 0; i < numItems; i++) { CFieldInfo &f = _fields.AddNew(); const CFieldInfoInit &fii = standardFieldTable[i]; f.PropID = fii.PropID; f.IsRawProp = false; f.NameA = fii.Name; f.TitleAdjustment = fii.TitleAdjustment; f.TextAdjustment = fii.TextAdjustment; f.PrefixSpacesWidth = fii.PrefixSpacesWidth; f.Width = fii.Width; int k; for (k = 0; k < fii.PrefixSpacesWidth; k++) LinesString += ' '; for (k = 0; k < fii.Width; k++) LinesString += '-'; } } static void GetPropName(PROPID propID, const wchar_t *name, AString &nameA, UString &nameU) { if (propID < ARRAY_SIZE(kPropIdToName)) { nameA = kPropIdToName[propID]; return; } if (name) nameU = name; else { char s[16]; ConvertUInt32ToString(propID, s); nameA = s; } } void CFieldPrinter::AddProp(BSTR name, PROPID propID, bool isRawProp) { CFieldInfo f; f.PropID = propID; f.IsRawProp = isRawProp; GetPropName(propID, name, f.NameA, f.NameU); f.NameU += L" = "; if (!f.NameA.IsEmpty()) f.NameA += " = "; else { const UString &s = f.NameU; AString sA; unsigned i; for (i = 0; i < s.Len(); i++) { wchar_t c = s[i]; if (c >= 0x80) break; sA += (char)c; } if (i == s.Len()) f.NameA = sA; } _fields.Add(f); } HRESULT CFieldPrinter::AddMainProps(IInArchive *archive) { UInt32 numProps; RINOK(archive->GetNumberOfProperties(&numProps)); for (UInt32 i = 0; i < numProps; i++) { CMyComBSTR name; PROPID propID; VARTYPE vt; RINOK(archive->GetPropertyInfo(i, &name, &propID, &vt)); AddProp(name, propID, false); } return S_OK; } HRESULT CFieldPrinter::AddRawProps(IArchiveGetRawProps *getRawProps) { UInt32 numProps; RINOK(getRawProps->GetNumRawProps(&numProps)); for (UInt32 i = 0; i < numProps; i++) { CMyComBSTR name; PROPID propID; RINOK(getRawProps->GetRawPropInfo(i, &name, &propID)); AddProp(name, propID, true); } return S_OK; } void CFieldPrinter::PrintTitle() { FOR_VECTOR (i, _fields) { const CFieldInfo &f = _fields[i]; PrintSpaces(f.PrefixSpacesWidth); PrintString(f.TitleAdjustment, ((f.PropID == kpidPath) ? 0: f.Width), f.NameA); } } void CFieldPrinter::PrintTitleLines() { g_StdOut << LinesString; } static void PrintTime(char *dest, const FILETIME *ft) { *dest = 0; if (ft->dwLowDateTime == 0 && ft->dwHighDateTime == 0) return; FILETIME locTime; if (!FileTimeToLocalFileTime(ft, &locTime)) throw 20121211; ConvertFileTimeToString(locTime, dest, true, true); } #ifndef _SFX static inline char GetHex(Byte value) { return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10))); } static void HexToString(char *dest, const Byte *data, UInt32 size) { for (UInt32 i = 0; i < size; i++) { Byte b = data[i]; dest[0] = GetHex((Byte)((b >> 4) & 0xF)); dest[1] = GetHex((Byte)(b & 0xF)); dest += 2; } *dest = 0; } #endif #define MY_ENDL '\n' HRESULT CFieldPrinter::PrintItemInfo(UInt32 index, const CListStat &stat) { char temp[128]; size_t tempPos = 0; bool techMode = this->TechMode; /* if (techMode) { g_StdOut << "Index = "; g_StdOut << (UInt64)index; g_StdOut << endl; } */ FOR_VECTOR (i, _fields) { const CFieldInfo &f = _fields[i]; if (!techMode) { PrintSpacesToString(temp + tempPos, f.PrefixSpacesWidth); tempPos += f.PrefixSpacesWidth; } if (techMode) { if (!f.NameA.IsEmpty()) g_StdOut << f.NameA; else g_StdOut << f.NameU; } if (f.PropID == kpidPath) { if (!techMode) g_StdOut << temp; g_StdOut.PrintUString(FilePath, TempAString); if (techMode) g_StdOut << MY_ENDL; continue; } int width = f.Width; if (f.IsRawProp) { #ifndef _SFX const void *data; UInt32 dataSize; UInt32 propType; RINOK(Arc->GetRawProps->GetRawProp(index, f.PropID, &data, &dataSize, &propType)); if (dataSize != 0) { bool needPrint = true; if (f.PropID == kpidNtSecure) { if (propType != NPropDataType::kRaw) return E_FAIL; #ifndef _SFX ConvertNtSecureToString((const Byte *)data, dataSize, TempAString); g_StdOut << TempAString; needPrint = false; #endif } else if (f.PropID == kpidNtReparse) { UString s; if (ConvertNtReparseToString((const Byte *)data, dataSize, s)) { needPrint = false; g_StdOut << s; } } if (needPrint) { if (propType != NPropDataType::kRaw) return E_FAIL; const UInt32 kMaxDataSize = 64; if (dataSize > kMaxDataSize) { g_StdOut << "data:"; g_StdOut << dataSize; } else { char hexStr[kMaxDataSize * 2 + 4]; HexToString(hexStr, (const Byte *)data, dataSize); g_StdOut << hexStr; } } } #endif } else { CPropVariant prop; switch (f.PropID) { case kpidSize: if (stat.Size.Def) prop = stat.Size.Val; break; case kpidPackSize: if (stat.PackSize.Def) prop = stat.PackSize.Val; break; case kpidMTime: if (stat.MTime.Def) prop = stat.MTime.Val; break; default: RINOK(Arc->Archive->GetProperty(index, f.PropID, &prop)); } if (f.PropID == kpidAttrib && (prop.vt == VT_EMPTY || prop.vt == VT_UI4)) { GetAttribString((prop.vt == VT_EMPTY) ? 0 : prop.ulVal, IsFolder, techMode, temp + tempPos); if (techMode) g_StdOut << temp + tempPos; else tempPos += strlen(temp + tempPos); } else if (prop.vt == VT_EMPTY) { if (!techMode) { PrintSpacesToString(temp + tempPos, width); tempPos += width; } } else if (prop.vt == VT_FILETIME) { PrintTime(temp + tempPos, &prop.filetime); if (techMode) g_StdOut << temp + tempPos; else { size_t len = strlen(temp + tempPos); tempPos += len; if (len < (unsigned)f.Width) { len = (size_t)f.Width - len; PrintSpacesToString(temp + tempPos, (int)len); tempPos += len; } } } else if (prop.vt == VT_BSTR) { if (techMode) { int len = (int)wcslen(prop.bstrVal); MyStringCopy(TempWString.GetBuffer(len), prop.bstrVal); // replace CR/LF here. TempWString.ReleaseBuffer(len); g_StdOut.PrintUString(TempWString, TempAString); } else PrintString(f.TextAdjustment, width, prop.bstrVal); } else { char s[64]; ConvertPropertyToShortString(s, prop, f.PropID); if (techMode) g_StdOut << s; else { PrintStringToString(temp + tempPos, f.TextAdjustment, width, s); tempPos += strlen(temp + tempPos); } } } if (techMode) g_StdOut << MY_ENDL; } g_StdOut << MY_ENDL; return S_OK; } static void PrintNumber(EAdjustment adj, int width, const CListUInt64Def &value) { wchar_t s[32]; s[0] = 0; if (value.Def) ConvertUInt64ToString(value.Val, s); PrintString(adj, width, s); } static void PrintNumberAndString(AString &s, UInt64 value, const char *text) { char t[32]; ConvertUInt64ToString(value, t); s += t; s += ' '; s += text; } void CFieldPrinter::PrintSum(const CListStat &stat, UInt64 numDirs, const char *str) { FOR_VECTOR (i, _fields) { const CFieldInfo &f = _fields[i]; PrintSpaces(f.PrefixSpacesWidth); if (f.PropID == kpidSize) PrintNumber(f.TextAdjustment, f.Width, stat.Size); else if (f.PropID == kpidPackSize) PrintNumber(f.TextAdjustment, f.Width, stat.PackSize); else if (f.PropID == kpidMTime) { char s[64]; s[0] = 0; if (stat.MTime.Def) PrintTime(s, &stat.MTime.Val); PrintString(f.TextAdjustment, f.Width, s); } else if (f.PropID == kpidPath) { AString s; PrintNumberAndString(s, stat.NumFiles, str); if (numDirs != 0) { s += ", "; PrintNumberAndString(s, numDirs, kString_Dirs); } PrintString(f.TextAdjustment, 0, s); } else PrintString(f.TextAdjustment, f.Width, L""); } g_StdOut << endl; } void CFieldPrinter::PrintSum(const CListStat2 &stat2) { PrintSum(stat2.MainFiles, stat2.NumDirs, kString_Files); if (stat2.AltStreams.NumFiles != 0) { PrintSum(stat2.AltStreams, 0, kString_AltStreams);; CListStat stat = stat2.MainFiles; stat.Update(stat2.AltStreams); PrintSum(stat, 0, kString_Streams); } } static HRESULT GetUInt64Value(IInArchive *archive, UInt32 index, PROPID propID, CListUInt64Def &value) { value.Val = 0; value.Def = false; CPropVariant prop; RINOK(archive->GetProperty(index, propID, &prop)); value.Def = ConvertPropVariantToUInt64(prop, value.Val); return S_OK; } static HRESULT GetItemMTime(IInArchive *archive, UInt32 index, CListFileTimeDef &t) { t.Val.dwLowDateTime = 0; t.Val.dwHighDateTime = 0; t.Def = false; CPropVariant prop; RINOK(archive->GetProperty(index, kpidMTime, &prop)); if (prop.vt == VT_FILETIME) { t.Val = prop.filetime; t.Def = true; } else if (prop.vt != VT_EMPTY) return E_FAIL; return S_OK; } static void PrintPropNameAndNumber(const char *name, UInt64 val) { g_StdOut << name << ": " << val << endl; } static void PrintPropName_and_Eq(PROPID propID) { const char *s; char temp[16]; if (propID < ARRAY_SIZE(kPropIdToName)) s = kPropIdToName[propID]; else { ConvertUInt32ToString(propID, temp); s = temp; } g_StdOut << s << " = "; } static void PrintPropNameAndNumber(PROPID propID, UInt64 val) { PrintPropName_and_Eq(propID); g_StdOut << val << endl; } static void PrintPropNameAndNumber_Signed(PROPID propID, Int64 val) { PrintPropName_and_Eq(propID); g_StdOut << val << endl; } static void PrintPropPair(const char *name, const wchar_t *val) { g_StdOut << name << " = " << val << endl; } static void PrintPropertyPair2(PROPID propID, const wchar_t *name, const CPropVariant &prop) { UString s; ConvertPropertyToString(s, prop, propID); if (!s.IsEmpty()) { AString nameA; UString nameU; GetPropName(propID, name, nameA, nameU); if (!nameA.IsEmpty()) PrintPropPair(nameA, s); else g_StdOut << nameU << " = " << s << endl; } } static HRESULT PrintArcProp(IInArchive *archive, PROPID propID, const wchar_t *name) { CPropVariant prop; RINOK(archive->GetArchiveProperty(propID, &prop)); PrintPropertyPair2(propID, name, prop); return S_OK; } static void PrintArcTypeError(const UString &type, bool isWarning) { g_StdOut << "Open " << (isWarning ? "Warning" : "Error") << ": Can not open the file as [" << type << "] archive" << endl; } int Find_FileName_InSortedVector(const UStringVector &fileName, const UString& name); AString GetOpenArcErrorMessage(UInt32 errorFlags); static void PrintErrorFlags(const char *s, UInt32 errorFlags) { g_StdOut << s << endl << GetOpenArcErrorMessage(errorFlags) << endl; } static void ErrorInfo_Print(const CArcErrorInfo &er) { if (er.AreThereErrors()) PrintErrorFlags("Errors:", er.GetErrorFlags()); if (!er.ErrorMessage.IsEmpty()) PrintPropPair("Error", er.ErrorMessage); if (er.AreThereWarnings()) PrintErrorFlags("Warnings:", er.GetWarningFlags()); if (!er.WarningMessage.IsEmpty()) PrintPropPair("Warning", er.WarningMessage); } HRESULT ListArchives(CCodecs *codecs, const CObjectVector<COpenType> &types, const CIntVector &excludedFormats, bool stdInMode, UStringVector &arcPaths, UStringVector &arcPathsFull, bool processAltStreams, bool showAltStreams, const NWildcard::CCensorNode &wildcardCensor, bool enableHeaders, bool techMode, #ifndef _NO_CRYPTO bool &passwordEnabled, UString &password, #endif #ifndef _SFX const CObjectVector<CProperty> *props, #endif UInt64 &numErrors, UInt64 &numWarnings) { bool AllFilesAreAllowed = wildcardCensor.AreAllAllowed(); numErrors = 0; numWarnings = 0; CFieldPrinter fp; if (!techMode) fp.Init(kStandardFieldTable, ARRAY_SIZE(kStandardFieldTable)); CListStat2 stat2; CBoolArr skipArcs(arcPaths.Size()); unsigned arcIndex; for (arcIndex = 0; arcIndex < arcPaths.Size(); arcIndex++) skipArcs[arcIndex] = false; UInt64 numVolumes = 0; UInt64 numArcs = 0; UInt64 totalArcSizes = 0; for (arcIndex = 0; arcIndex < arcPaths.Size(); arcIndex++) { if (skipArcs[arcIndex]) continue; const UString &archiveName = arcPaths[arcIndex]; UInt64 arcPackSize = 0; if (!stdInMode) { NFile::NFind::CFileInfo fi; if (!fi.Find(us2fs(archiveName)) || fi.IsDir()) { g_StdOut << endl << "Error: " << archiveName << " is not file" << endl; numErrors++; continue; } arcPackSize = fi.Size; totalArcSizes += arcPackSize; } CArchiveLink arcLink; COpenCallbackConsole openCallback; openCallback.OutStream = &g_StdOut; #ifndef _NO_CRYPTO openCallback.PasswordIsDefined = passwordEnabled; openCallback.Password = password; #endif /* CObjectVector<COptionalOpenProperties> optPropsVector; COptionalOpenProperties &optProps = optPropsVector.AddNew(); optProps.Props = *props; */ COpenOptions options; #ifndef _SFX options.props = props; #endif options.codecs = codecs; options.types = &types; options.excludedFormats = &excludedFormats; options.stdInMode = stdInMode; options.stream = NULL; options.filePath = archiveName; HRESULT result = arcLink.Open2(options, &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 { if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0) { PrintArcTypeError(codecs->Formats[arcLink.NonOpen_ErrorInfo.ErrorFormatIndex].Name, false); } else g_StdOut << "Can not open the file as archive"; } g_StdOut << endl; ErrorInfo_Print(arcLink.NonOpen_ErrorInfo); } else if (result == E_OUTOFMEMORY) g_StdOut << "Can't allocate required memory"; else g_StdOut << NError::MyFormatMessage(result); g_StdOut << endl; numErrors++; continue; } { if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0) numErrors++; FOR_VECTOR (r, arcLink.Arcs) { const CArcErrorInfo &arc = arcLink.Arcs[r].ErrorInfo; if (!arc.WarningMessage.IsEmpty()) numWarnings++; if (arc.AreThereWarnings()) numWarnings++; if (arc.ErrorFormatIndex >= 0) numWarnings++; if (arc.AreThereErrors()) { numErrors++; // break; } if (!arc.ErrorMessage.IsEmpty()) numErrors++; } } numArcs++; numVolumes++; if (!stdInMode) { numVolumes += arcLink.VolumePaths.Size(); totalArcSizes += arcLink.VolumesSize; FOR_VECTOR (v, arcLink.VolumePaths) { int index = Find_FileName_InSortedVector(arcPathsFull, arcLink.VolumePaths[v]); if (index >= 0 && (unsigned)index > arcIndex) skipArcs[index] = true; } } if (enableHeaders) { g_StdOut << endl << kListing << archiveName << endl << endl; FOR_VECTOR (r, arcLink.Arcs) { const CArc &arc = arcLink.Arcs[r]; const CArcErrorInfo &er = arc.ErrorInfo; g_StdOut << "--\n"; PrintPropPair("Path", arc.Path); if (er.ErrorFormatIndex >= 0) { if (er.ErrorFormatIndex == arc.FormatIndex) g_StdOut << "Warning: The archive is open with offset" << endl; else PrintArcTypeError(codecs->GetFormatNamePtr(er.ErrorFormatIndex), true); } PrintPropPair("Type", codecs->GetFormatNamePtr(arc.FormatIndex)); ErrorInfo_Print(er); Int64 offset = arc.GetGlobalOffset(); if (offset != 0) PrintPropNameAndNumber_Signed(kpidOffset, offset); IInArchive *archive = arc.Archive; RINOK(PrintArcProp(archive, kpidPhySize, NULL)); if (er.TailSize != 0) PrintPropNameAndNumber(kpidTailSize, er.TailSize); UInt32 numProps; RINOK(archive->GetNumberOfArchiveProperties(&numProps)); { for (UInt32 j = 0; j < numProps; j++) { CMyComBSTR name; PROPID propID; VARTYPE vt; RINOK(archive->GetArchivePropertyInfo(j, &name, &propID, &vt)); RINOK(PrintArcProp(archive, propID, name)); } } if (r != arcLink.Arcs.Size() - 1) { UInt32 numProps; g_StdOut << "----\n"; if (archive->GetNumberOfProperties(&numProps) == S_OK) { UInt32 mainIndex = arcLink.Arcs[r + 1].SubfileIndex; for (UInt32 j = 0; j < numProps; j++) { CMyComBSTR name; PROPID propID; VARTYPE vt; RINOK(archive->GetPropertyInfo(j, &name, &propID, &vt)); CPropVariant prop; RINOK(archive->GetProperty(mainIndex, propID, &prop)); PrintPropertyPair2(propID, name, prop); } } } } g_StdOut << endl; if (techMode) g_StdOut << "----------\n"; } if (enableHeaders && !techMode) { fp.PrintTitle(); g_StdOut << endl; fp.PrintTitleLines(); g_StdOut << endl; } const CArc &arc = arcLink.Arcs.Back(); fp.Arc = &arc; fp.TechMode = techMode; IInArchive *archive = arc.Archive; if (techMode) { fp.Clear(); RINOK(fp.AddMainProps(archive)); if (arc.GetRawProps) { RINOK(fp.AddRawProps(arc.GetRawProps)); } } CListStat2 stat; UInt32 numItems; RINOK(archive->GetNumberOfItems(&numItems)); for (UInt32 i = 0; i < numItems; i++) { if (NConsoleClose::TestBreakSignal()) return E_ABORT; HRESULT res = arc.GetItemPath2(i, fp.FilePath); if (stdInMode && res == E_INVALIDARG) break; RINOK(res); if (arc.Ask_Aux) { bool isAux; RINOK(Archive_IsItem_Aux(archive, i, isAux)); if (isAux) continue; } bool isAltStream = false; if (arc.Ask_AltStream) { RINOK(Archive_IsItem_AltStream(archive, i, isAltStream)); if (isAltStream && !processAltStreams) continue; } RINOK(Archive_IsItem_Folder(archive, i, fp.IsFolder)); if (!AllFilesAreAllowed) { if (!wildcardCensor.CheckPath(isAltStream, fp.FilePath, !fp.IsFolder)) continue; } CListStat st; RINOK(GetUInt64Value(archive, i, kpidSize, st.Size)); RINOK(GetUInt64Value(archive, i, kpidPackSize, st.PackSize)); RINOK(GetItemMTime(archive, i, st.MTime)); if (fp.IsFolder) stat.NumDirs++; else st.NumFiles = 1; stat.GetStat(isAltStream).Update(st); if (isAltStream && !showAltStreams) continue; RINOK(fp.PrintItemInfo(i, st)); } UInt64 numStreams = stat.GetNumStreams(); if (!stdInMode && !stat.MainFiles.PackSize.Def && !stat.AltStreams.PackSize.Def) { if (arcLink.VolumePaths.Size() != 0) arcPackSize += arcLink.VolumesSize; stat.MainFiles.PackSize.Add((numStreams == 0) ? 0 : arcPackSize); } stat.MainFiles.SetSizeDefIfNoFiles(); stat.AltStreams.SetSizeDefIfNoFiles(); if (enableHeaders && !techMode) { fp.PrintTitleLines(); g_StdOut << endl; fp.PrintSum(stat); } if (enableHeaders) { if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0) { g_StdOut << "----------\n"; PrintPropPair("Path", arcLink.NonOpen_ArcPath); PrintArcTypeError(codecs->Formats[arcLink.NonOpen_ErrorInfo.ErrorFormatIndex].Name, false); } } stat2.Update(stat); fflush(stdout); } if (enableHeaders && !techMode && (arcPaths.Size() > 1 || numVolumes > 1)) { g_StdOut << endl; fp.PrintTitleLines(); g_StdOut << endl; fp.PrintSum(stat2); g_StdOut << endl; PrintPropNameAndNumber("Archives", numArcs); PrintPropNameAndNumber("Volumes", numVolumes); PrintPropNameAndNumber("Total archives size", totalArcSizes); } return S_OK; }