1296 lines
30 KiB
C++
1296 lines
30 KiB
C++
// 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 *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 const char *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
|
|
{
|
|
char s[16];
|
|
ConvertUInt32ToString(propID, s);
|
|
nameA = s;
|
|
}
|
|
}
|
|
|
|
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.AddAscii(" = ");
|
|
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 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.PrintUString(FilePath, 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
|
|
}
|
|
#ifdef _WIN32
|
|
else if (f.PropID == kpidNtReparse)
|
|
{
|
|
UString s;
|
|
if (ConvertNtReparseToString((const Byte *)data, dataSize, s))
|
|
{
|
|
needPrint = false;
|
|
g_StdOut.PrintUString(s, TempAString);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
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);
|
|
if (techMode)
|
|
{
|
|
// replace CR/LF here.
|
|
g_StdOut.PrintUString(TempWString, TempAString);
|
|
}
|
|
else
|
|
PrintUString(f.TextAdjustment, width, TempWString, TempAString);
|
|
}
|
|
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, 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 PrintPropPair(CStdOutStream &so, const char *name, const wchar_t *val)
|
|
{
|
|
so << name << " = " << val << endl;
|
|
}
|
|
|
|
|
|
static void PrintPropertyPair2(CStdOutStream &so, 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(so, nameA, s);
|
|
else
|
|
so << nameU << " = " << s << endl;
|
|
}
|
|
}
|
|
|
|
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);
|
|
|
|
PrintErrorFlags(so, "WARNINGS:", er.GetWarningFlags());
|
|
if (!er.WarningMessage.IsEmpty())
|
|
PrintPropPair(so, "WARNING", er.WarningMessage);
|
|
}
|
|
|
|
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);
|
|
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));
|
|
|
|
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 << arcLink.NonOpen_ArcPath << 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();
|
|
/* FIXME
|
|
if (errorCode == 0)
|
|
errorCode = ERROR_FILE_NOT_FOUND;
|
|
*/
|
|
lastError = HRESULT_FROM_WIN32(lastError);;
|
|
g_StdOut.Flush();
|
|
*g_ErrStream << endl << kError << NError::MyFormatMessage(errorCode) <<
|
|
endl << arcPath << endl << endl;
|
|
numErrors++;
|
|
continue;
|
|
}
|
|
if (fi.IsDir())
|
|
{
|
|
g_StdOut.Flush();
|
|
*g_ErrStream << endl << kError << arcPath << " 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 << arcPath << endl << endl;
|
|
}
|
|
|
|
HRESULT result = arcLink.Open3(options, &openCallback);
|
|
|
|
if (result != S_OK)
|
|
{
|
|
if (result == E_ABORT)
|
|
return result;
|
|
g_StdOut.Flush();
|
|
*g_ErrStream << endl << kError << arcPath << " : ";
|
|
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;
|
|
}
|
|
|
|
{
|
|
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[(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);
|
|
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;
|
|
}
|