summaryrefslogtreecommitdiffstats
path: root/other-licenses/7zstub/src/CPP/7zip/UI/Console/List.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--other-licenses/7zstub/src/CPP/7zip/UI/Console/List.cpp1349
1 files changed, 1349 insertions, 0 deletions
diff --git a/other-licenses/7zstub/src/CPP/7zip/UI/Console/List.cpp b/other-licenses/7zstub/src/CPP/7zip/UI/Console/List.cpp
new file mode 100644
index 0000000000..ebcabb6853
--- /dev/null
+++ b/other-licenses/7zstub/src/CPP/7zip/UI/Console/List.cpp
@@ -0,0 +1,1349 @@
+// 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;
+
+extern CStdOutStream *g_StdStream;
+extern CStdOutStream *g_ErrStream;
+
+static const char * const 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"
+ , "Read-only"
+ , "Out Name"
+ , "Copy Link"
+};
+
+static const char kEmptyAttribChar = '.';
+
+static const char * const kListing = "Listing archive: ";
+
+static const char * const kString_Files = "files";
+static const char * const kString_Dirs = "folders";
+static const char * const kString_AltStreams = "alternate streams";
+static const char * const kString_Streams = "streams";
+
+static const char * const kError = "ERROR: ";
+
+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;
+ unsigned PrefixSpacesWidth;
+ unsigned Width;
+};
+
+struct CFieldInfoInit
+{
+ PROPID PropID;
+ const char *Name;
+ EAdjustment TitleAdjustment;
+ EAdjustment TextAdjustment;
+ unsigned PrefixSpacesWidth;
+ unsigned 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 unsigned kNumSpacesMax = 32; // it must be larger than max CFieldInfoInit.Width
+static const char *g_Spaces =
+" " ;
+
+static void PrintSpaces(unsigned numSpaces)
+{
+ if (numSpaces > 0 && numSpaces <= kNumSpacesMax)
+ g_StdOut << g_Spaces + (kNumSpacesMax - numSpaces);
+}
+
+static void PrintSpacesToString(char *dest, unsigned numSpaces)
+{
+ unsigned i;
+ for (i = 0; i < numSpaces; i++)
+ dest[i] = ' ';
+ dest[i] = 0;
+}
+
+// extern int g_CodePage;
+
+static void PrintUString(EAdjustment adj, unsigned width, const UString &s, AString &temp)
+{
+ /*
+ // we don't need multibyte align.
+ int codePage = g_CodePage;
+ if (codePage == -1)
+ codePage = CP_OEMCP;
+ if (codePage == CP_UTF8)
+ ConvertUnicodeToUTF8(s, temp);
+ else
+ UnicodeStringToMultiByte2(temp, s, (UINT)codePage);
+ */
+
+ unsigned numSpaces = 0;
+
+ if (width > s.Len())
+ {
+ numSpaces = width - s.Len();
+ unsigned numLeftSpaces = 0;
+ switch (adj)
+ {
+ case kLeft: numLeftSpaces = 0; break;
+ case kCenter: numLeftSpaces = numSpaces / 2; break;
+ case kRight: numLeftSpaces = numSpaces; break;
+ }
+ PrintSpaces(numLeftSpaces);
+ numSpaces -= numLeftSpaces;
+ }
+
+ g_StdOut.PrintUString(s, temp);
+ PrintSpaces(numSpaces);
+}
+
+static void PrintString(EAdjustment adj, unsigned width, const char *s)
+{
+ unsigned numSpaces = 0;
+ unsigned len = (unsigned)strlen(s);
+
+ if (width > len)
+ {
+ numSpaces = width - len;
+ unsigned numLeftSpaces = 0;
+ switch (adj)
+ {
+ case kLeft: numLeftSpaces = 0; break;
+ case kCenter: numLeftSpaces = numSpaces / 2; break;
+ case kRight: numLeftSpaces = numSpaces; break;
+ }
+ PrintSpaces(numLeftSpaces);
+ numSpaces -= numLeftSpaces;
+ }
+
+ g_StdOut << s;
+ PrintSpaces(numSpaces);
+}
+
+static void PrintStringToString(char *dest, EAdjustment adj, unsigned width, const char *textString)
+{
+ unsigned numSpaces = 0;
+ unsigned len = (unsigned)strlen(textString);
+
+ if (width > len)
+ {
+ numSpaces = width - len;
+ unsigned numLeftSpaces = 0;
+ switch (adj)
+ {
+ case kLeft: numLeftSpaces = 0; break;
+ case kCenter: numLeftSpaces = numSpaces / 2; break;
+ case kRight: numLeftSpaces = numSpaces; break;
+ }
+ PrintSpacesToString(dest, numLeftSpaces);
+ dest += numLeftSpaces;
+ numSpaces -= numLeftSpaces;
+ }
+
+ memcpy(dest, textString, len);
+ dest += len;
+ PrintSpacesToString(dest, numSpaces);
+}
+
+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 &st)
+ {
+ Size.Add(st.Size);
+ PackSize.Add(st.PackSize);
+ MTime.Update(st.MTime);
+ NumFiles += st.NumFiles;
+ }
+ void SetSizeDefIfNoFiles() { if (NumFiles == 0) Size.Def = true; }
+};
+
+struct CListStat2
+{
+ CListStat MainFiles;
+ CListStat AltStreams;
+ UInt64 NumDirs;
+
+ CListStat2(): NumDirs(0) {}
+
+ void Update(const CListStat2 &st)
+ {
+ MainFiles.Update(st.MainFiles);
+ AltStreams.Update(st.AltStreams);
+ NumDirs += st.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(const wchar_t *name, PROPID propID, bool isRawProp);
+public:
+ const CArc *Arc;
+ bool TechMode;
+ UString FilePath;
+ AString TempAString;
+ UString TempWString;
+ bool IsDir;
+
+ AString LinesString;
+
+ void Clear() { _fields.Clear(); LinesString.Empty(); }
+ void Init(const CFieldInfoInit *standardFieldTable, unsigned numItems);
+
+ HRESULT AddMainProps(IInArchive *archive);
+ HRESULT AddRawProps(IArchiveGetRawProps *getRawProps);
+
+ void PrintTitle();
+ void PrintTitleLines();
+ HRESULT PrintItemInfo(UInt32 index, const CListStat &st);
+ void PrintSum(const CListStat &st, UInt64 numDirs, const char *str);
+ void PrintSum(const CListStat2 &stat2);
+};
+
+void CFieldPrinter::Init(const CFieldInfoInit *standardFieldTable, unsigned numItems)
+{
+ Clear();
+ for (unsigned 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;
+
+ unsigned k;
+ for (k = 0; k < fii.PrefixSpacesWidth; k++)
+ LinesString.Add_Space();
+ 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
+ {
+ nameA.Empty();
+ nameA.Add_UInt32(propID);
+ }
+}
+
+void CFieldPrinter::AddProp(const wchar_t *name, PROPID propID, bool isRawProp)
+{
+ CFieldInfo f;
+ f.PropID = propID;
+ f.IsRawProp = isRawProp;
+ GetPropName(propID, name, f.NameA, f.NameU);
+ f.NameU += " = ";
+ 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;
+ ConvertUtcFileTimeToString(*ft, dest, kTimestampPrintLevel_SEC);
+}
+
+#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 endl
+
+HRESULT CFieldPrinter::PrintItemInfo(UInt32 index, const CListStat &st)
+{
+ 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.NormalizePrint_UString(FilePath, TempWString, TempAString);
+ if (techMode)
+ g_StdOut << MY_ENDL;
+ continue;
+ }
+
+ const unsigned 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.PrintUString(s, TempAString);
+ }
+ }
+
+ 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 (st.Size.Def) prop = st.Size.Val; break;
+ case kpidPackSize: if (st.PackSize.Def) prop = st.PackSize.Val; break;
+ case kpidMTime: if (st.MTime.Def) prop = st.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, IsDir, 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 = f.Width - len;
+ PrintSpacesToString(temp + tempPos, (unsigned)len);
+ tempPos += len;
+ }
+ }
+ }
+ else if (prop.vt == VT_BSTR)
+ {
+ TempWString.SetFromBstr(prop.bstrVal);
+ // do we need multi-line support here ?
+ g_StdOut.Normalize_UString(TempWString);
+ if (techMode)
+ {
+ g_StdOut.PrintUString(TempWString, TempAString);
+ }
+ else
+ PrintUString(f.TextAdjustment, width, TempWString, TempAString);
+ }
+ else
+ {
+ char s[64];
+ ConvertPropertyToShortString2(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, unsigned width, const CListUInt64Def &value)
+{
+ char s[32];
+ s[0] = 0;
+ if (value.Def)
+ ConvertUInt64ToString(value.Val, s);
+ PrintString(adj, width, s);
+}
+
+void Print_UInt64_and_String(AString &s, UInt64 val, const char *name);
+
+void CFieldPrinter::PrintSum(const CListStat &st, 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, st.Size);
+ else if (f.PropID == kpidPackSize)
+ PrintNumber(f.TextAdjustment, f.Width, st.PackSize);
+ else if (f.PropID == kpidMTime)
+ {
+ char s[64];
+ s[0] = 0;
+ if (st.MTime.Def)
+ PrintTime(s, &st.MTime.Val);
+ PrintString(f.TextAdjustment, f.Width, s);
+ }
+ else if (f.PropID == kpidPath)
+ {
+ AString s;
+ Print_UInt64_and_String(s, st.NumFiles, str);
+ if (numDirs != 0)
+ {
+ s += ", ";
+ Print_UInt64_and_String(s, numDirs, kString_Dirs);
+ }
+ PrintString(f.TextAdjustment, 0, s);
+ }
+ else
+ PrintString(f.TextAdjustment, f.Width, "");
+ }
+ 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 st = stat2.MainFiles;
+ st.Update(stat2.AltStreams);
+ PrintSum(st, 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(CStdOutStream &so, const char *name, UInt64 val)
+{
+ so << name << ": " << val << endl;
+}
+
+static void PrintPropName_and_Eq(CStdOutStream &so, PROPID propID)
+{
+ const char *s;
+ char temp[16];
+ if (propID < ARRAY_SIZE(kPropIdToName))
+ s = kPropIdToName[propID];
+ else
+ {
+ ConvertUInt32ToString(propID, temp);
+ s = temp;
+ }
+ so << s << " = ";
+}
+
+static void PrintPropNameAndNumber(CStdOutStream &so, PROPID propID, UInt64 val)
+{
+ PrintPropName_and_Eq(so, propID);
+ so << val << endl;
+}
+
+static void PrintPropNameAndNumber_Signed(CStdOutStream &so, PROPID propID, Int64 val)
+{
+ PrintPropName_and_Eq(so, propID);
+ so << val << endl;
+}
+
+
+static void UString_Replace_CRLF_to_LF(UString &s)
+{
+ // s.Replace(L"\r\n", L"\n");
+ wchar_t *src = s.GetBuf();
+ wchar_t *dest = src;
+ for (;;)
+ {
+ wchar_t c = *src++;
+ if (c == 0)
+ break;
+ if (c == '\r' && *src == '\n')
+ {
+ src++;
+ c = '\n';
+ }
+ *dest++ = c;
+ }
+ s.ReleaseBuf_SetEnd((unsigned)(dest - s.GetBuf()));
+}
+
+
+static void PrintPropVal_MultiLine(CStdOutStream &so, const wchar_t *val)
+{
+ UString s = val;
+ if (s.Find(L'\n') >= 0)
+ {
+ so << endl;
+ so << "{";
+ so << endl;
+ UString_Replace_CRLF_to_LF(s);
+ so.Normalize_UString__LF_Allowed(s);
+ so << s;
+ so << endl;
+ so << "}";
+ }
+ else
+ {
+ so.Normalize_UString(s);
+ so << s;
+ }
+ so << endl;
+}
+
+
+static void PrintPropPair(CStdOutStream &so, const char *name, const wchar_t *val, bool multiLine)
+{
+ so << name << " = ";
+ if (multiLine)
+ {
+ PrintPropVal_MultiLine(so, val);
+ return;
+ }
+ UString s = val;
+ so.Normalize_UString(s);
+ so << s;
+ so << endl;
+}
+
+
+static void PrintPropertyPair2(CStdOutStream &so, PROPID propID, const wchar_t *name, const CPropVariant &prop)
+{
+ UString s;
+ ConvertPropertyToString2(s, prop, propID);
+ if (!s.IsEmpty())
+ {
+ AString nameA;
+ UString nameU;
+ GetPropName(propID, name, nameA, nameU);
+ if (!nameA.IsEmpty())
+ so << nameA;
+ else
+ so << nameU;
+ so << " = ";
+ PrintPropVal_MultiLine(so, s);
+ }
+}
+
+static HRESULT PrintArcProp(CStdOutStream &so, IInArchive *archive, PROPID propID, const wchar_t *name)
+{
+ CPropVariant prop;
+ RINOK(archive->GetArchiveProperty(propID, &prop));
+ PrintPropertyPair2(so, propID, name, prop);
+ return S_OK;
+}
+
+static void PrintArcTypeError(CStdOutStream &so, const UString &type, bool isWarning)
+{
+ so << "Open " << (isWarning ? "WARNING" : "ERROR")
+ << ": Can not open the file as ["
+ << type
+ << "] archive"
+ << endl;
+}
+
+int Find_FileName_InSortedVector(const UStringVector &fileName, const UString& name);
+
+void PrintErrorFlags(CStdOutStream &so, const char *s, UInt32 errorFlags);
+
+static void ErrorInfo_Print(CStdOutStream &so, const CArcErrorInfo &er)
+{
+ PrintErrorFlags(so, "ERRORS:", er.GetErrorFlags());
+ if (!er.ErrorMessage.IsEmpty())
+ PrintPropPair(so, "ERROR", er.ErrorMessage, true);
+
+ PrintErrorFlags(so, "WARNINGS:", er.GetWarningFlags());
+ if (!er.WarningMessage.IsEmpty())
+ PrintPropPair(so, "WARNING", er.WarningMessage, true);
+}
+
+HRESULT Print_OpenArchive_Props(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink)
+{
+ FOR_VECTOR (r, arcLink.Arcs)
+ {
+ const CArc &arc = arcLink.Arcs[r];
+ const CArcErrorInfo &er = arc.ErrorInfo;
+
+ so << "--\n";
+ PrintPropPair(so, "Path", arc.Path, false);
+ if (er.ErrorFormatIndex >= 0)
+ {
+ if (er.ErrorFormatIndex == arc.FormatIndex)
+ so << "Warning: The archive is open with offset" << endl;
+ else
+ PrintArcTypeError(so, codecs->GetFormatNamePtr(er.ErrorFormatIndex), true);
+ }
+ PrintPropPair(so, "Type", codecs->GetFormatNamePtr(arc.FormatIndex), false);
+
+ ErrorInfo_Print(so, er);
+
+ Int64 offset = arc.GetGlobalOffset();
+ if (offset != 0)
+ PrintPropNameAndNumber_Signed(so, kpidOffset, offset);
+ IInArchive *archive = arc.Archive;
+ RINOK(PrintArcProp(so, archive, kpidPhySize, NULL));
+ if (er.TailSize != 0)
+ PrintPropNameAndNumber(so, 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(so, archive, propID, name));
+ }
+ }
+
+ if (r != arcLink.Arcs.Size() - 1)
+ {
+ UInt32 numProps;
+ so << "----\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(so, propID, name, prop);
+ }
+ }
+ }
+ }
+ return S_OK;
+}
+
+HRESULT Print_OpenArchive_Error(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink)
+{
+ #ifndef _NO_CRYPTO
+ if (arcLink.PasswordWasAsked)
+ so << "Can not open encrypted archive. Wrong password?";
+ else
+ #endif
+ {
+ if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0)
+ {
+ so.NormalizePrint_UString(arcLink.NonOpen_ArcPath);
+ so << endl;
+ PrintArcTypeError(so, codecs->Formats[arcLink.NonOpen_ErrorInfo.ErrorFormatIndex].Name, false);
+ }
+ else
+ so << "Can not open the file as archive";
+ }
+
+ so << endl;
+ so << endl;
+ ErrorInfo_Print(so, arcLink.NonOpen_ErrorInfo);
+
+ return S_OK;
+}
+
+bool CensorNode_CheckPath(const NWildcard::CCensorNode &node, const CReadArcItem &item);
+
+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 stat2total;
+
+ 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;
+
+ HRESULT lastError = 0;
+
+ for (arcIndex = 0; arcIndex < arcPaths.Size(); arcIndex++)
+ {
+ if (skipArcs[arcIndex])
+ continue;
+ const UString &arcPath = arcPaths[arcIndex];
+ UInt64 arcPackSize = 0;
+
+ if (!stdInMode)
+ {
+ NFile::NFind::CFileInfo fi;
+ if (!fi.Find(us2fs(arcPath)))
+ {
+ DWORD errorCode = GetLastError();
+ if (errorCode == 0)
+ errorCode = ERROR_FILE_NOT_FOUND;
+ lastError = HRESULT_FROM_WIN32(lastError);;
+ g_StdOut.Flush();
+ *g_ErrStream << endl << kError << NError::MyFormatMessage(errorCode) << endl;
+ g_ErrStream->NormalizePrint_UString(arcPath);
+ *g_ErrStream << endl << endl;
+ numErrors++;
+ continue;
+ }
+ if (fi.IsDir())
+ {
+ g_StdOut.Flush();
+ *g_ErrStream << endl << kError;
+ g_ErrStream->NormalizePrint_UString(arcPath);
+ *g_ErrStream << " is not a file" << endl << endl;
+ numErrors++;
+ continue;
+ }
+ arcPackSize = fi.Size;
+ totalArcSizes += arcPackSize;
+ }
+
+ CArchiveLink arcLink;
+
+ COpenCallbackConsole openCallback;
+ openCallback.Init(&g_StdOut, g_ErrStream, NULL);
+
+ #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 = arcPath;
+
+ if (enableHeaders)
+ {
+ g_StdOut << endl << kListing;
+ g_StdOut.NormalizePrint_UString(arcPath);
+ g_StdOut << endl << endl;
+ }
+
+ HRESULT result = arcLink.Open_Strict(options, &openCallback);
+
+ if (result != S_OK)
+ {
+ if (result == E_ABORT)
+ return result;
+ g_StdOut.Flush();
+ *g_ErrStream << endl << kError;
+ g_ErrStream->NormalizePrint_UString(arcPath);
+ *g_ErrStream << " : ";
+ if (result == S_FALSE)
+ {
+ Print_OpenArchive_Error(*g_ErrStream, codecs, arcLink);
+ }
+ else
+ {
+ lastError = result;
+ *g_ErrStream << "opening : ";
+ if (result == E_OUTOFMEMORY)
+ *g_ErrStream << "Can't allocate required memory";
+ else
+ *g_ErrStream << NError::MyFormatMessage(result);
+ }
+ *g_ErrStream << endl;
+ numErrors++;
+ continue;
+ }
+
+ {
+ 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[(unsigned)index] = true;
+ }
+ }
+
+
+ if (enableHeaders)
+ {
+ RINOK(Print_OpenArchive_Props(g_StdOut, codecs, arcLink));
+
+ 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 stat2;
+
+ UInt32 numItems;
+ RINOK(archive->GetNumberOfItems(&numItems));
+
+ CReadArcItem item;
+ UStringVector pathParts;
+
+ 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_Dir(archive, i, fp.IsDir));
+
+ if (!allFilesAreAllowed)
+ {
+ if (isAltStream)
+ {
+ RINOK(arc.GetItem(i, item));
+ if (!CensorNode_CheckPath(wildcardCensor, item))
+ continue;
+ }
+ else
+ {
+ SplitPathToParts(fp.FilePath, pathParts);;
+ bool include;
+ if (!wildcardCensor.CheckPathVect(pathParts, !fp.IsDir, include))
+ continue;
+ if (!include)
+ 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.IsDir)
+ stat2.NumDirs++;
+ else
+ st.NumFiles = 1;
+ stat2.GetStat(isAltStream).Update(st);
+
+ if (isAltStream && !showAltStreams)
+ continue;
+ RINOK(fp.PrintItemInfo(i, st));
+ }
+
+ UInt64 numStreams = stat2.GetNumStreams();
+ if (!stdInMode
+ && !stat2.MainFiles.PackSize.Def
+ && !stat2.AltStreams.PackSize.Def)
+ {
+ if (arcLink.VolumePaths.Size() != 0)
+ arcPackSize += arcLink.VolumesSize;
+ stat2.MainFiles.PackSize.Add((numStreams == 0) ? 0 : arcPackSize);
+ }
+
+ stat2.MainFiles.SetSizeDefIfNoFiles();
+ stat2.AltStreams.SetSizeDefIfNoFiles();
+
+ if (enableHeaders && !techMode)
+ {
+ fp.PrintTitleLines();
+ g_StdOut << endl;
+ fp.PrintSum(stat2);
+ }
+
+ if (enableHeaders)
+ {
+ if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0)
+ {
+ g_StdOut << "----------\n";
+ PrintPropPair(g_StdOut, "Path", arcLink.NonOpen_ArcPath, false);
+ PrintArcTypeError(g_StdOut, codecs->Formats[arcLink.NonOpen_ErrorInfo.ErrorFormatIndex].Name, false);
+ }
+ }
+
+ stat2total.Update(stat2);
+
+ g_StdOut.Flush();
+ }
+
+ if (enableHeaders && !techMode && (arcPaths.Size() > 1 || numVolumes > 1))
+ {
+ g_StdOut << endl;
+ fp.PrintTitleLines();
+ g_StdOut << endl;
+ fp.PrintSum(stat2total);
+ g_StdOut << endl;
+ PrintPropNameAndNumber(g_StdOut, "Archives", numArcs);
+ PrintPropNameAndNumber(g_StdOut, "Volumes", numVolumes);
+ PrintPropNameAndNumber(g_StdOut, "Total archives size", totalArcSizes);
+ }
+
+ if (numErrors == 1 && lastError != 0)
+ return lastError;
+
+ return S_OK;
+}