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