// 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; | |
} |