1 // List.cpp
2
3 #include "StdAfx.h"
4
5 #include "../../../Common/IntToString.h"
6 #include "../../../Common/MyCom.h"
7 #include "../../../Common/StdOutStream.h"
8 #include "../../../Common/StringConvert.h"
9 #include "../../../Common/UTFConvert.h"
10
11 #include "../../../Windows/ErrorMsg.h"
12 #include "../../../Windows/FileDir.h"
13 #include "../../../Windows/PropVariant.h"
14 #include "../../../Windows/PropVariantConv.h"
15
16 #include "../Common/OpenArchive.h"
17 #include "../Common/PropIDUtils.h"
18
19 #include "ConsoleClose.h"
20 #include "List.h"
21 #include "OpenCallbackConsole.h"
22
23 using namespace NWindows;
24 using namespace NCOM;
25
26
27
28 static const char *kPropIdToName[] =
29 {
30 "0"
31 , "1"
32 , "2"
33 , "Path"
34 , "Name"
35 , "Extension"
36 , "Folder"
37 , "Size"
38 , "Packed Size"
39 , "Attributes"
40 , "Created"
41 , "Accessed"
42 , "Modified"
43 , "Solid"
44 , "Commented"
45 , "Encrypted"
46 , "Split Before"
47 , "Split After"
48 , "Dictionary Size"
49 , "CRC"
50 , "Type"
51 , "Anti"
52 , "Method"
53 , "Host OS"
54 , "File System"
55 , "User"
56 , "Group"
57 , "Block"
58 , "Comment"
59 , "Position"
60 , "Path Prefix"
61 , "Folders"
62 , "Files"
63 , "Version"
64 , "Volume"
65 , "Multivolume"
66 , "Offset"
67 , "Links"
68 , "Blocks"
69 , "Volumes"
70 , "Time Type"
71 , "64-bit"
72 , "Big-endian"
73 , "CPU"
74 , "Physical Size"
75 , "Headers Size"
76 , "Checksum"
77 , "Characteristics"
78 , "Virtual Address"
79 , "ID"
80 , "Short Name"
81 , "Creator Application"
82 , "Sector Size"
83 , "Mode"
84 , "Symbolic Link"
85 , "Error"
86 , "Total Size"
87 , "Free Space"
88 , "Cluster Size"
89 , "Label"
90 , "Local Name"
91 , "Provider"
92 , "NT Security"
93 , "Alternate Stream"
94 , "Aux"
95 , "Deleted"
96 , "Tree"
97 , "SHA-1"
98 , "SHA-256"
99 , "Error Type"
100 , "Errors"
101 , "Errors"
102 , "Warnings"
103 , "Warning"
104 , "Streams"
105 , "Alternate Streams"
106 , "Alternate Streams Size"
107 , "Virtual Size"
108 , "Unpack Size"
109 , "Total Physical Size"
110 , "Volume Index"
111 , "SubType"
112 , "Short Comment"
113 , "Code Page"
114 , "Is not archive type"
115 , "Physical Size can't be detected"
116 , "Zeros Tail Is Allowed"
117 , "Tail Size"
118 , "Embedded Stub Size"
119 , "Link"
120 , "Hard Link"
121 , "iNode"
122 , "Stream ID"
123 };
124
125 static const char kEmptyAttribChar = '.';
126
127 static const char *kListing = "Listing archive: ";
128
129 static const char *kString_Files = "files";
130 static const char *kString_Dirs = "folders";
131 static const char *kString_AltStreams = "alternate streams";
132 static const char *kString_Streams = "streams";
133
GetAttribString(UInt32 wa,bool isDir,bool allAttribs,char * s)134 static void GetAttribString(UInt32 wa, bool isDir, bool allAttribs, char *s)
135 {
136 if (isDir)
137 wa |= FILE_ATTRIBUTE_DIRECTORY;
138 if (allAttribs)
139 {
140 ConvertWinAttribToString(s, wa);
141 return;
142 }
143 s[0] = ((wa & FILE_ATTRIBUTE_DIRECTORY) != 0) ? 'D': kEmptyAttribChar;
144 s[1] = ((wa & FILE_ATTRIBUTE_READONLY) != 0) ? 'R': kEmptyAttribChar;
145 s[2] = ((wa & FILE_ATTRIBUTE_HIDDEN) != 0) ? 'H': kEmptyAttribChar;
146 s[3] = ((wa & FILE_ATTRIBUTE_SYSTEM) != 0) ? 'S': kEmptyAttribChar;
147 s[4] = ((wa & FILE_ATTRIBUTE_ARCHIVE) != 0) ? 'A': kEmptyAttribChar;
148 s[5] = 0;
149 }
150
151 enum EAdjustment
152 {
153 kLeft,
154 kCenter,
155 kRight
156 };
157
158 struct CFieldInfo
159 {
160 PROPID PropID;
161 bool IsRawProp;
162 UString NameU;
163 AString NameA;
164 EAdjustment TitleAdjustment;
165 EAdjustment TextAdjustment;
166 int PrefixSpacesWidth;
167 int Width;
168 };
169
170 struct CFieldInfoInit
171 {
172 PROPID PropID;
173 const char *Name;
174 EAdjustment TitleAdjustment;
175 EAdjustment TextAdjustment;
176 int PrefixSpacesWidth;
177 int Width;
178 };
179
180 static const CFieldInfoInit kStandardFieldTable[] =
181 {
182 { kpidMTime, " Date Time", kLeft, kLeft, 0, 19 },
183 { kpidAttrib, "Attr", kRight, kCenter, 1, 5 },
184 { kpidSize, "Size", kRight, kRight, 1, 12 },
185 { kpidPackSize, "Compressed", kRight, kRight, 1, 12 },
186 { kpidPath, "Name", kLeft, kLeft, 2, 24 }
187 };
188
189 const int kNumSpacesMax = 32; // it must be larger than max CFieldInfoInit.Width
190 static const char *g_Spaces =
191 " " ;
192
PrintSpaces(int numSpaces)193 static void PrintSpaces(int numSpaces)
194 {
195 if (numSpaces > 0 && numSpaces <= kNumSpacesMax)
196 g_StdOut << g_Spaces + (kNumSpacesMax - numSpaces);
197 }
198
PrintSpacesToString(char * dest,int numSpaces)199 static void PrintSpacesToString(char *dest, int numSpaces)
200 {
201 int i;
202 for (i = 0; i < numSpaces; i++)
203 dest[i] = ' ';
204 dest[i] = 0;
205 }
206
PrintString(EAdjustment adj,int width,const UString & textString)207 static void PrintString(EAdjustment adj, int width, const UString &textString)
208 {
209 const int numSpaces = width - textString.Len();
210 int numLeftSpaces = 0;
211 switch (adj)
212 {
213 case kLeft: numLeftSpaces = 0; break;
214 case kCenter: numLeftSpaces = numSpaces / 2; break;
215 case kRight: numLeftSpaces = numSpaces; break;
216 }
217 PrintSpaces(numLeftSpaces);
218 g_StdOut << textString;
219 PrintSpaces(numSpaces - numLeftSpaces);
220 }
221
PrintString(EAdjustment adj,int width,const char * textString)222 static void PrintString(EAdjustment adj, int width, const char *textString)
223 {
224 const int numSpaces = width - (int)strlen(textString);
225 int numLeftSpaces = 0;
226 switch (adj)
227 {
228 case kLeft: numLeftSpaces = 0; break;
229 case kCenter: numLeftSpaces = numSpaces / 2; break;
230 case kRight: numLeftSpaces = numSpaces; break;
231 }
232 PrintSpaces(numLeftSpaces);
233 g_StdOut << textString;
234 PrintSpaces(numSpaces - numLeftSpaces);
235 }
236
PrintStringToString(char * dest,EAdjustment adj,int width,const char * textString)237 static void PrintStringToString(char *dest, EAdjustment adj, int width, const char *textString)
238 {
239 int len = (int)strlen(textString);
240 const int numSpaces = width - len;
241 int numLeftSpaces = 0;
242 switch (adj)
243 {
244 case kLeft: numLeftSpaces = 0; break;
245 case kCenter: numLeftSpaces = numSpaces / 2; break;
246 case kRight: numLeftSpaces = numSpaces; break;
247 }
248 PrintSpacesToString(dest, numLeftSpaces);
249 if (numLeftSpaces > 0)
250 dest += numLeftSpaces;
251 memcpy(dest, textString, len);
252 dest += len;
253 PrintSpacesToString(dest, numSpaces - numLeftSpaces);
254 }
255
256 struct CListUInt64Def
257 {
258 UInt64 Val;
259 bool Def;
260
CListUInt64DefCListUInt64Def261 CListUInt64Def(): Val(0), Def(false) {}
AddCListUInt64Def262 void Add(UInt64 v) { Val += v; Def = true; }
AddCListUInt64Def263 void Add(const CListUInt64Def &v) { if (v.Def) Add(v.Val); }
264 };
265
266 struct CListFileTimeDef
267 {
268 FILETIME Val;
269 bool Def;
270
CListFileTimeDefCListFileTimeDef271 CListFileTimeDef(): Def(false) { Val.dwLowDateTime = 0; Val.dwHighDateTime = 0; }
UpdateCListFileTimeDef272 void Update(const CListFileTimeDef &t)
273 {
274 if (t.Def && (!Def || CompareFileTime(&Val, &t.Val) < 0))
275 {
276 Val = t.Val;
277 Def = true;
278 }
279 }
280 };
281
282 struct CListStat
283 {
284 CListUInt64Def Size;
285 CListUInt64Def PackSize;
286 CListFileTimeDef MTime;
287 UInt64 NumFiles;
288
CListStatCListStat289 CListStat(): NumFiles(0) {}
UpdateCListStat290 void Update(const CListStat &stat)
291 {
292 Size.Add(stat.Size);
293 PackSize.Add(stat.PackSize);
294 MTime.Update(stat.MTime);
295 NumFiles += stat.NumFiles;
296 }
SetSizeDefIfNoFilesCListStat297 void SetSizeDefIfNoFiles() { if (NumFiles == 0) Size.Def = true; }
298 };
299
300 struct CListStat2
301 {
302 CListStat MainFiles;
303 CListStat AltStreams;
304 UInt64 NumDirs;
305
CListStat2CListStat2306 CListStat2(): NumDirs(0) {}
307
UpdateCListStat2308 void Update(const CListStat2 &stat)
309 {
310 MainFiles.Update(stat.MainFiles);
311 AltStreams.Update(stat.AltStreams);
312 NumDirs += stat.NumDirs;
313 }
GetNumStreamsCListStat2314 const UInt64 GetNumStreams() const { return MainFiles.NumFiles + AltStreams.NumFiles; }
GetStatCListStat2315 CListStat &GetStat(bool altStreamsMode) { return altStreamsMode ? AltStreams : MainFiles; }
316 };
317
318 class CFieldPrinter
319 {
320 CObjectVector<CFieldInfo> _fields;
321
322 void AddProp(BSTR name, PROPID propID, bool isRawProp);
323 public:
324 const CArc *Arc;
325 bool TechMode;
326 UString FilePath;
327 AString TempAString;
328 UString TempWString;
329 bool IsFolder;
330
331 AString LinesString;
332
Clear()333 void Clear() { _fields.Clear(); LinesString.Empty(); }
334 void Init(const CFieldInfoInit *standardFieldTable, int numItems);
335
336 HRESULT AddMainProps(IInArchive *archive);
337 HRESULT AddRawProps(IArchiveGetRawProps *getRawProps);
338
339 void PrintTitle();
340 void PrintTitleLines();
341 HRESULT PrintItemInfo(UInt32 index, const CListStat &stat);
342 void PrintSum(const CListStat &stat, UInt64 numDirs, const char *str);
343 void PrintSum(const CListStat2 &stat);
344 };
345
Init(const CFieldInfoInit * standardFieldTable,int numItems)346 void CFieldPrinter::Init(const CFieldInfoInit *standardFieldTable, int numItems)
347 {
348 Clear();
349 for (int i = 0; i < numItems; i++)
350 {
351 CFieldInfo &f = _fields.AddNew();
352 const CFieldInfoInit &fii = standardFieldTable[i];
353 f.PropID = fii.PropID;
354 f.IsRawProp = false;
355 f.NameA = fii.Name;
356 f.TitleAdjustment = fii.TitleAdjustment;
357 f.TextAdjustment = fii.TextAdjustment;
358 f.PrefixSpacesWidth = fii.PrefixSpacesWidth;
359 f.Width = fii.Width;
360
361 int k;
362 for (k = 0; k < fii.PrefixSpacesWidth; k++)
363 LinesString += ' ';
364 for (k = 0; k < fii.Width; k++)
365 LinesString += '-';
366 }
367 }
368
GetPropName(PROPID propID,const wchar_t * name,AString & nameA,UString & nameU)369 static void GetPropName(PROPID propID, const wchar_t *name, AString &nameA, UString &nameU)
370 {
371 if (propID < ARRAY_SIZE(kPropIdToName))
372 {
373 nameA = kPropIdToName[propID];
374 return;
375 }
376 if (name)
377 nameU = name;
378 else
379 {
380 char s[16];
381 ConvertUInt32ToString(propID, s);
382 nameA = s;
383 }
384 }
385
AddProp(BSTR name,PROPID propID,bool isRawProp)386 void CFieldPrinter::AddProp(BSTR name, PROPID propID, bool isRawProp)
387 {
388 CFieldInfo f;
389 f.PropID = propID;
390 f.IsRawProp = isRawProp;
391 GetPropName(propID, name, f.NameA, f.NameU);
392 f.NameU += L" = ";
393 if (!f.NameA.IsEmpty())
394 f.NameA += " = ";
395 else
396 {
397 const UString &s = f.NameU;
398 AString sA;
399 unsigned i;
400 for (i = 0; i < s.Len(); i++)
401 {
402 wchar_t c = s[i];
403 if (c >= 0x80)
404 break;
405 sA += (char)c;
406 }
407 if (i == s.Len())
408 f.NameA = sA;
409 }
410 _fields.Add(f);
411 }
412
AddMainProps(IInArchive * archive)413 HRESULT CFieldPrinter::AddMainProps(IInArchive *archive)
414 {
415 UInt32 numProps;
416 RINOK(archive->GetNumberOfProperties(&numProps));
417 for (UInt32 i = 0; i < numProps; i++)
418 {
419 CMyComBSTR name;
420 PROPID propID;
421 VARTYPE vt;
422 RINOK(archive->GetPropertyInfo(i, &name, &propID, &vt));
423 AddProp(name, propID, false);
424 }
425 return S_OK;
426 }
427
AddRawProps(IArchiveGetRawProps * getRawProps)428 HRESULT CFieldPrinter::AddRawProps(IArchiveGetRawProps *getRawProps)
429 {
430 UInt32 numProps;
431 RINOK(getRawProps->GetNumRawProps(&numProps));
432 for (UInt32 i = 0; i < numProps; i++)
433 {
434 CMyComBSTR name;
435 PROPID propID;
436 RINOK(getRawProps->GetRawPropInfo(i, &name, &propID));
437 AddProp(name, propID, true);
438 }
439 return S_OK;
440 }
441
PrintTitle()442 void CFieldPrinter::PrintTitle()
443 {
444 FOR_VECTOR (i, _fields)
445 {
446 const CFieldInfo &f = _fields[i];
447 PrintSpaces(f.PrefixSpacesWidth);
448 PrintString(f.TitleAdjustment, ((f.PropID == kpidPath) ? 0: f.Width), f.NameA);
449 }
450 }
451
PrintTitleLines()452 void CFieldPrinter::PrintTitleLines()
453 {
454 g_StdOut << LinesString;
455 }
456
PrintTime(char * dest,const FILETIME * ft)457 static void PrintTime(char *dest, const FILETIME *ft)
458 {
459 *dest = 0;
460 if (ft->dwLowDateTime == 0 && ft->dwHighDateTime == 0)
461 return;
462 FILETIME locTime;
463 if (!FileTimeToLocalFileTime(ft, &locTime))
464 throw 20121211;
465 ConvertFileTimeToString(locTime, dest, true, true);
466 }
467
468 #ifndef _SFX
469
GetHex(Byte value)470 static inline char GetHex(Byte value)
471 {
472 return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10)));
473 }
474
HexToString(char * dest,const Byte * data,UInt32 size)475 static void HexToString(char *dest, const Byte *data, UInt32 size)
476 {
477 for (UInt32 i = 0; i < size; i++)
478 {
479 Byte b = data[i];
480 dest[0] = GetHex((Byte)((b >> 4) & 0xF));
481 dest[1] = GetHex((Byte)(b & 0xF));
482 dest += 2;
483 }
484 *dest = 0;
485 }
486
487 #endif
488
489 #define MY_ENDL '\n'
490
PrintItemInfo(UInt32 index,const CListStat & stat)491 HRESULT CFieldPrinter::PrintItemInfo(UInt32 index, const CListStat &stat)
492 {
493 char temp[128];
494 size_t tempPos = 0;
495
496 bool techMode = this->TechMode;
497 /*
498 if (techMode)
499 {
500 g_StdOut << "Index = ";
501 g_StdOut << (UInt64)index;
502 g_StdOut << endl;
503 }
504 */
505 FOR_VECTOR (i, _fields)
506 {
507 const CFieldInfo &f = _fields[i];
508
509 if (!techMode)
510 {
511 PrintSpacesToString(temp + tempPos, f.PrefixSpacesWidth);
512 tempPos += f.PrefixSpacesWidth;
513 }
514
515 if (techMode)
516 {
517 if (!f.NameA.IsEmpty())
518 g_StdOut << f.NameA;
519 else
520 g_StdOut << f.NameU;
521 }
522
523 if (f.PropID == kpidPath)
524 {
525 if (!techMode)
526 g_StdOut << temp;
527 g_StdOut.PrintUString(FilePath, TempAString);
528 if (techMode)
529 g_StdOut << MY_ENDL;
530 continue;
531 }
532
533 int width = f.Width;
534
535 if (f.IsRawProp)
536 {
537 #ifndef _SFX
538
539 const void *data;
540 UInt32 dataSize;
541 UInt32 propType;
542 RINOK(Arc->GetRawProps->GetRawProp(index, f.PropID, &data, &dataSize, &propType));
543
544 if (dataSize != 0)
545 {
546 bool needPrint = true;
547
548 if (f.PropID == kpidNtSecure)
549 {
550 if (propType != NPropDataType::kRaw)
551 return E_FAIL;
552 #ifndef _SFX
553 ConvertNtSecureToString((const Byte *)data, dataSize, TempAString);
554 g_StdOut << TempAString;
555 needPrint = false;
556 #endif
557 }
558 else if (f.PropID == kpidNtReparse)
559 {
560 UString s;
561 if (ConvertNtReparseToString((const Byte *)data, dataSize, s))
562 {
563 needPrint = false;
564 g_StdOut << s;
565 }
566 }
567
568 if (needPrint)
569 {
570 if (propType != NPropDataType::kRaw)
571 return E_FAIL;
572
573 const UInt32 kMaxDataSize = 64;
574
575 if (dataSize > kMaxDataSize)
576 {
577 g_StdOut << "data:";
578 g_StdOut << dataSize;
579 }
580 else
581 {
582 char hexStr[kMaxDataSize * 2 + 4];
583 HexToString(hexStr, (const Byte *)data, dataSize);
584 g_StdOut << hexStr;
585 }
586 }
587 }
588
589 #endif
590 }
591 else
592 {
593 CPropVariant prop;
594 switch (f.PropID)
595 {
596 case kpidSize: if (stat.Size.Def) prop = stat.Size.Val; break;
597 case kpidPackSize: if (stat.PackSize.Def) prop = stat.PackSize.Val; break;
598 case kpidMTime: if (stat.MTime.Def) prop = stat.MTime.Val; break;
599 default:
600 RINOK(Arc->Archive->GetProperty(index, f.PropID, &prop));
601 }
602 if (f.PropID == kpidAttrib && (prop.vt == VT_EMPTY || prop.vt == VT_UI4))
603 {
604 GetAttribString((prop.vt == VT_EMPTY) ? 0 : prop.ulVal, IsFolder, techMode, temp + tempPos);
605 if (techMode)
606 g_StdOut << temp + tempPos;
607 else
608 tempPos += strlen(temp + tempPos);
609 }
610 else if (prop.vt == VT_EMPTY)
611 {
612 if (!techMode)
613 {
614 PrintSpacesToString(temp + tempPos, width);
615 tempPos += width;
616 }
617 }
618 else if (prop.vt == VT_FILETIME)
619 {
620 PrintTime(temp + tempPos, &prop.filetime);
621 if (techMode)
622 g_StdOut << temp + tempPos;
623 else
624 {
625 size_t len = strlen(temp + tempPos);
626 tempPos += len;
627 if (len < (unsigned)f.Width)
628 {
629 len = (size_t)f.Width - len;
630 PrintSpacesToString(temp + tempPos, (int)len);
631 tempPos += len;
632 }
633 }
634 }
635 else if (prop.vt == VT_BSTR)
636 {
637 if (techMode)
638 {
639 int len = (int)wcslen(prop.bstrVal);
640 MyStringCopy(TempWString.GetBuffer(len), prop.bstrVal);
641 // replace CR/LF here.
642 TempWString.ReleaseBuffer(len);
643 g_StdOut.PrintUString(TempWString, TempAString);
644 }
645 else
646 PrintString(f.TextAdjustment, width, prop.bstrVal);
647 }
648 else
649 {
650 char s[64];
651 ConvertPropertyToShortString(s, prop, f.PropID);
652 if (techMode)
653 g_StdOut << s;
654 else
655 {
656 PrintStringToString(temp + tempPos, f.TextAdjustment, width, s);
657 tempPos += strlen(temp + tempPos);
658 }
659 }
660 }
661 if (techMode)
662 g_StdOut << MY_ENDL;
663 }
664 g_StdOut << MY_ENDL;
665 return S_OK;
666 }
667
PrintNumber(EAdjustment adj,int width,const CListUInt64Def & value)668 static void PrintNumber(EAdjustment adj, int width, const CListUInt64Def &value)
669 {
670 wchar_t s[32];
671 s[0] = 0;
672 if (value.Def)
673 ConvertUInt64ToString(value.Val, s);
674 PrintString(adj, width, s);
675 }
676
PrintNumberAndString(AString & s,UInt64 value,const char * text)677 static void PrintNumberAndString(AString &s, UInt64 value, const char *text)
678 {
679 char t[32];
680 ConvertUInt64ToString(value, t);
681 s += t;
682 s += ' ';
683 s += text;
684 }
685
PrintSum(const CListStat & stat,UInt64 numDirs,const char * str)686 void CFieldPrinter::PrintSum(const CListStat &stat, UInt64 numDirs, const char *str)
687 {
688 FOR_VECTOR (i, _fields)
689 {
690 const CFieldInfo &f = _fields[i];
691 PrintSpaces(f.PrefixSpacesWidth);
692 if (f.PropID == kpidSize)
693 PrintNumber(f.TextAdjustment, f.Width, stat.Size);
694 else if (f.PropID == kpidPackSize)
695 PrintNumber(f.TextAdjustment, f.Width, stat.PackSize);
696 else if (f.PropID == kpidMTime)
697 {
698 char s[64];
699 s[0] = 0;
700 if (stat.MTime.Def)
701 PrintTime(s, &stat.MTime.Val);
702 PrintString(f.TextAdjustment, f.Width, s);
703 }
704 else if (f.PropID == kpidPath)
705 {
706 AString s;
707 PrintNumberAndString(s, stat.NumFiles, str);
708 if (numDirs != 0)
709 {
710 s += ", ";
711 PrintNumberAndString(s, numDirs, kString_Dirs);
712 }
713 PrintString(f.TextAdjustment, 0, s);
714 }
715 else
716 PrintString(f.TextAdjustment, f.Width, L"");
717 }
718 g_StdOut << endl;
719 }
720
PrintSum(const CListStat2 & stat2)721 void CFieldPrinter::PrintSum(const CListStat2 &stat2)
722 {
723 PrintSum(stat2.MainFiles, stat2.NumDirs, kString_Files);
724 if (stat2.AltStreams.NumFiles != 0)
725 {
726 PrintSum(stat2.AltStreams, 0, kString_AltStreams);;
727 CListStat stat = stat2.MainFiles;
728 stat.Update(stat2.AltStreams);
729 PrintSum(stat, 0, kString_Streams);
730 }
731 }
732
GetUInt64Value(IInArchive * archive,UInt32 index,PROPID propID,CListUInt64Def & value)733 static HRESULT GetUInt64Value(IInArchive *archive, UInt32 index, PROPID propID, CListUInt64Def &value)
734 {
735 value.Val = 0;
736 value.Def = false;
737 CPropVariant prop;
738 RINOK(archive->GetProperty(index, propID, &prop));
739 value.Def = ConvertPropVariantToUInt64(prop, value.Val);
740 return S_OK;
741 }
742
GetItemMTime(IInArchive * archive,UInt32 index,CListFileTimeDef & t)743 static HRESULT GetItemMTime(IInArchive *archive, UInt32 index, CListFileTimeDef &t)
744 {
745 t.Val.dwLowDateTime = 0;
746 t.Val.dwHighDateTime = 0;
747 t.Def = false;
748 CPropVariant prop;
749 RINOK(archive->GetProperty(index, kpidMTime, &prop));
750 if (prop.vt == VT_FILETIME)
751 {
752 t.Val = prop.filetime;
753 t.Def = true;
754 }
755 else if (prop.vt != VT_EMPTY)
756 return E_FAIL;
757 return S_OK;
758 }
759
PrintPropNameAndNumber(const char * name,UInt64 val)760 static void PrintPropNameAndNumber(const char *name, UInt64 val)
761 {
762 g_StdOut << name << ": " << val << endl;
763 }
764
PrintPropName_and_Eq(PROPID propID)765 static void PrintPropName_and_Eq(PROPID propID)
766 {
767 const char *s;
768 char temp[16];
769 if (propID < ARRAY_SIZE(kPropIdToName))
770 s = kPropIdToName[propID];
771 else
772 {
773 ConvertUInt32ToString(propID, temp);
774 s = temp;
775 }
776 g_StdOut << s << " = ";
777 }
778
PrintPropNameAndNumber(PROPID propID,UInt64 val)779 static void PrintPropNameAndNumber(PROPID propID, UInt64 val)
780 {
781 PrintPropName_and_Eq(propID);
782 g_StdOut << val << endl;
783 }
784
PrintPropNameAndNumber_Signed(PROPID propID,Int64 val)785 static void PrintPropNameAndNumber_Signed(PROPID propID, Int64 val)
786 {
787 PrintPropName_and_Eq(propID);
788 g_StdOut << val << endl;
789 }
790
PrintPropPair(const char * name,const wchar_t * val)791 static void PrintPropPair(const char *name, const wchar_t *val)
792 {
793 g_StdOut << name << " = " << val << endl;
794 }
795
796
PrintPropertyPair2(PROPID propID,const wchar_t * name,const CPropVariant & prop)797 static void PrintPropertyPair2(PROPID propID, const wchar_t *name, const CPropVariant &prop)
798 {
799 UString s;
800 ConvertPropertyToString(s, prop, propID);
801 if (!s.IsEmpty())
802 {
803 AString nameA;
804 UString nameU;
805 GetPropName(propID, name, nameA, nameU);
806 if (!nameA.IsEmpty())
807 PrintPropPair(nameA, s);
808 else
809 g_StdOut << nameU << " = " << s << endl;
810 }
811 }
812
PrintArcProp(IInArchive * archive,PROPID propID,const wchar_t * name)813 static HRESULT PrintArcProp(IInArchive *archive, PROPID propID, const wchar_t *name)
814 {
815 CPropVariant prop;
816 RINOK(archive->GetArchiveProperty(propID, &prop));
817 PrintPropertyPair2(propID, name, prop);
818 return S_OK;
819 }
820
PrintArcTypeError(const UString & type,bool isWarning)821 static void PrintArcTypeError(const UString &type, bool isWarning)
822 {
823 g_StdOut << "Open " << (isWarning ? "Warning" : "Error")
824 << ": Can not open the file as ["
825 << type
826 << "] archive"
827 << endl;
828 }
829
830 int Find_FileName_InSortedVector(const UStringVector &fileName, const UString& name);
831
832 AString GetOpenArcErrorMessage(UInt32 errorFlags);
833
PrintErrorFlags(const char * s,UInt32 errorFlags)834 static void PrintErrorFlags(const char *s, UInt32 errorFlags)
835 {
836 g_StdOut << s << endl << GetOpenArcErrorMessage(errorFlags) << endl;
837 }
838
ErrorInfo_Print(const CArcErrorInfo & er)839 static void ErrorInfo_Print(const CArcErrorInfo &er)
840 {
841 if (er.AreThereErrors())
842 PrintErrorFlags("Errors:", er.GetErrorFlags());
843 if (!er.ErrorMessage.IsEmpty())
844 PrintPropPair("Error", er.ErrorMessage);
845 if (er.AreThereWarnings())
846 PrintErrorFlags("Warnings:", er.GetWarningFlags());
847 if (!er.WarningMessage.IsEmpty())
848 PrintPropPair("Warning", er.WarningMessage);
849 }
850
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,bool & passwordEnabled,UString & password,const CObjectVector<CProperty> * props,UInt64 & numErrors,UInt64 & numWarnings)851 HRESULT ListArchives(CCodecs *codecs,
852 const CObjectVector<COpenType> &types,
853 const CIntVector &excludedFormats,
854 bool stdInMode,
855 UStringVector &arcPaths, UStringVector &arcPathsFull,
856 bool processAltStreams, bool showAltStreams,
857 const NWildcard::CCensorNode &wildcardCensor,
858 bool enableHeaders, bool techMode,
859 #ifndef _NO_CRYPTO
860 bool &passwordEnabled, UString &password,
861 #endif
862 #ifndef _SFX
863 const CObjectVector<CProperty> *props,
864 #endif
865 UInt64 &numErrors,
866 UInt64 &numWarnings)
867 {
868 bool AllFilesAreAllowed = wildcardCensor.AreAllAllowed();
869
870 numErrors = 0;
871 numWarnings = 0;
872
873 CFieldPrinter fp;
874 if (!techMode)
875 fp.Init(kStandardFieldTable, ARRAY_SIZE(kStandardFieldTable));
876
877 CListStat2 stat2;
878
879 CBoolArr skipArcs(arcPaths.Size());
880 unsigned arcIndex;
881 for (arcIndex = 0; arcIndex < arcPaths.Size(); arcIndex++)
882 skipArcs[arcIndex] = false;
883 UInt64 numVolumes = 0;
884 UInt64 numArcs = 0;
885 UInt64 totalArcSizes = 0;
886
887 for (arcIndex = 0; arcIndex < arcPaths.Size(); arcIndex++)
888 {
889 if (skipArcs[arcIndex])
890 continue;
891 const UString &archiveName = arcPaths[arcIndex];
892 UInt64 arcPackSize = 0;
893 if (!stdInMode)
894 {
895 NFile::NFind::CFileInfo fi;
896 if (!fi.Find(us2fs(archiveName)) || fi.IsDir())
897 {
898 g_StdOut << endl << "Error: " << archiveName << " is not file" << endl;
899 numErrors++;
900 continue;
901 }
902 arcPackSize = fi.Size;
903 totalArcSizes += arcPackSize;
904 }
905
906 CArchiveLink arcLink;
907
908 COpenCallbackConsole openCallback;
909 openCallback.OutStream = &g_StdOut;
910
911 #ifndef _NO_CRYPTO
912
913 openCallback.PasswordIsDefined = passwordEnabled;
914 openCallback.Password = password;
915
916 #endif
917
918 /*
919 CObjectVector<COptionalOpenProperties> optPropsVector;
920 COptionalOpenProperties &optProps = optPropsVector.AddNew();
921 optProps.Props = *props;
922 */
923
924 COpenOptions options;
925 #ifndef _SFX
926 options.props = props;
927 #endif
928 options.codecs = codecs;
929 options.types = &types;
930 options.excludedFormats = &excludedFormats;
931 options.stdInMode = stdInMode;
932 options.stream = NULL;
933 options.filePath = archiveName;
934 HRESULT result = arcLink.Open2(options, &openCallback);
935
936 if (result != S_OK)
937 {
938 if (result == E_ABORT)
939 return result;
940 g_StdOut << endl << "Error: " << archiveName << ": ";
941 if (result == S_FALSE)
942 {
943 #ifndef _NO_CRYPTO
944 if (openCallback.Open_WasPasswordAsked())
945 g_StdOut << "Can not open encrypted archive. Wrong password?";
946 else
947 #endif
948 {
949 if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0)
950 {
951 PrintArcTypeError(codecs->Formats[arcLink.NonOpen_ErrorInfo.ErrorFormatIndex].Name, false);
952 }
953 else
954 g_StdOut << "Can not open the file as archive";
955 }
956 g_StdOut << endl;
957 ErrorInfo_Print(arcLink.NonOpen_ErrorInfo);
958 }
959 else if (result == E_OUTOFMEMORY)
960 g_StdOut << "Can't allocate required memory";
961 else
962 g_StdOut << NError::MyFormatMessage(result);
963 g_StdOut << endl;
964 numErrors++;
965 continue;
966 }
967 {
968 if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0)
969 numErrors++;
970
971 FOR_VECTOR (r, arcLink.Arcs)
972 {
973 const CArcErrorInfo &arc = arcLink.Arcs[r].ErrorInfo;
974 if (!arc.WarningMessage.IsEmpty())
975 numWarnings++;
976 if (arc.AreThereWarnings())
977 numWarnings++;
978 if (arc.ErrorFormatIndex >= 0)
979 numWarnings++;
980 if (arc.AreThereErrors())
981 {
982 numErrors++;
983 // break;
984 }
985 if (!arc.ErrorMessage.IsEmpty())
986 numErrors++;
987 }
988 }
989
990 numArcs++;
991 numVolumes++;
992
993 if (!stdInMode)
994 {
995 numVolumes += arcLink.VolumePaths.Size();
996 totalArcSizes += arcLink.VolumesSize;
997 FOR_VECTOR (v, arcLink.VolumePaths)
998 {
999 int index = Find_FileName_InSortedVector(arcPathsFull, arcLink.VolumePaths[v]);
1000 if (index >= 0 && (unsigned)index > arcIndex)
1001 skipArcs[index] = true;
1002 }
1003 }
1004
1005
1006 if (enableHeaders)
1007 {
1008 g_StdOut << endl << kListing << archiveName << endl << endl;
1009
1010 FOR_VECTOR (r, arcLink.Arcs)
1011 {
1012 const CArc &arc = arcLink.Arcs[r];
1013 const CArcErrorInfo &er = arc.ErrorInfo;
1014
1015 g_StdOut << "--\n";
1016 PrintPropPair("Path", arc.Path);
1017 if (er.ErrorFormatIndex >= 0)
1018 {
1019 if (er.ErrorFormatIndex == arc.FormatIndex)
1020 g_StdOut << "Warning: The archive is open with offset" << endl;
1021 else
1022 PrintArcTypeError(codecs->GetFormatNamePtr(er.ErrorFormatIndex), true);
1023 }
1024 PrintPropPair("Type", codecs->GetFormatNamePtr(arc.FormatIndex));
1025
1026 ErrorInfo_Print(er);
1027
1028 Int64 offset = arc.GetGlobalOffset();
1029 if (offset != 0)
1030 PrintPropNameAndNumber_Signed(kpidOffset, offset);
1031 IInArchive *archive = arc.Archive;
1032 RINOK(PrintArcProp(archive, kpidPhySize, NULL));
1033 if (er.TailSize != 0)
1034 PrintPropNameAndNumber(kpidTailSize, er.TailSize);
1035 UInt32 numProps;
1036 RINOK(archive->GetNumberOfArchiveProperties(&numProps));
1037 {
1038 for (UInt32 j = 0; j < numProps; j++)
1039 {
1040 CMyComBSTR name;
1041 PROPID propID;
1042 VARTYPE vt;
1043 RINOK(archive->GetArchivePropertyInfo(j, &name, &propID, &vt));
1044 RINOK(PrintArcProp(archive, propID, name));
1045 }
1046 }
1047 if (r != arcLink.Arcs.Size() - 1)
1048 {
1049 UInt32 numProps;
1050 g_StdOut << "----\n";
1051 if (archive->GetNumberOfProperties(&numProps) == S_OK)
1052 {
1053 UInt32 mainIndex = arcLink.Arcs[r + 1].SubfileIndex;
1054 for (UInt32 j = 0; j < numProps; j++)
1055 {
1056 CMyComBSTR name;
1057 PROPID propID;
1058 VARTYPE vt;
1059 RINOK(archive->GetPropertyInfo(j, &name, &propID, &vt));
1060 CPropVariant prop;
1061 RINOK(archive->GetProperty(mainIndex, propID, &prop));
1062 PrintPropertyPair2(propID, name, prop);
1063 }
1064 }
1065 }
1066 }
1067 g_StdOut << endl;
1068 if (techMode)
1069 g_StdOut << "----------\n";
1070 }
1071
1072 if (enableHeaders && !techMode)
1073 {
1074 fp.PrintTitle();
1075 g_StdOut << endl;
1076 fp.PrintTitleLines();
1077 g_StdOut << endl;
1078 }
1079
1080 const CArc &arc = arcLink.Arcs.Back();
1081 fp.Arc = &arc;
1082 fp.TechMode = techMode;
1083 IInArchive *archive = arc.Archive;
1084 if (techMode)
1085 {
1086 fp.Clear();
1087 RINOK(fp.AddMainProps(archive));
1088 if (arc.GetRawProps)
1089 {
1090 RINOK(fp.AddRawProps(arc.GetRawProps));
1091 }
1092 }
1093
1094 CListStat2 stat;
1095
1096 UInt32 numItems;
1097 RINOK(archive->GetNumberOfItems(&numItems));
1098 for (UInt32 i = 0; i < numItems; i++)
1099 {
1100 if (NConsoleClose::TestBreakSignal())
1101 return E_ABORT;
1102
1103 HRESULT res = arc.GetItemPath2(i, fp.FilePath);
1104
1105 if (stdInMode && res == E_INVALIDARG)
1106 break;
1107 RINOK(res);
1108
1109 if (arc.Ask_Aux)
1110 {
1111 bool isAux;
1112 RINOK(Archive_IsItem_Aux(archive, i, isAux));
1113 if (isAux)
1114 continue;
1115 }
1116
1117 bool isAltStream = false;
1118 if (arc.Ask_AltStream)
1119 {
1120 RINOK(Archive_IsItem_AltStream(archive, i, isAltStream));
1121 if (isAltStream && !processAltStreams)
1122 continue;
1123 }
1124
1125 RINOK(Archive_IsItem_Folder(archive, i, fp.IsFolder));
1126
1127 if (!AllFilesAreAllowed)
1128 {
1129 if (!wildcardCensor.CheckPath(isAltStream, fp.FilePath, !fp.IsFolder))
1130 continue;
1131 }
1132
1133 CListStat st;
1134
1135 RINOK(GetUInt64Value(archive, i, kpidSize, st.Size));
1136 RINOK(GetUInt64Value(archive, i, kpidPackSize, st.PackSize));
1137 RINOK(GetItemMTime(archive, i, st.MTime));
1138
1139 if (fp.IsFolder)
1140 stat.NumDirs++;
1141 else
1142 st.NumFiles = 1;
1143 stat.GetStat(isAltStream).Update(st);
1144
1145 if (isAltStream && !showAltStreams)
1146 continue;
1147 RINOK(fp.PrintItemInfo(i, st));
1148 }
1149
1150 UInt64 numStreams = stat.GetNumStreams();
1151 if (!stdInMode
1152 && !stat.MainFiles.PackSize.Def
1153 && !stat.AltStreams.PackSize.Def)
1154 {
1155 if (arcLink.VolumePaths.Size() != 0)
1156 arcPackSize += arcLink.VolumesSize;
1157 stat.MainFiles.PackSize.Add((numStreams == 0) ? 0 : arcPackSize);
1158 }
1159 stat.MainFiles.SetSizeDefIfNoFiles();
1160 stat.AltStreams.SetSizeDefIfNoFiles();
1161 if (enableHeaders && !techMode)
1162 {
1163 fp.PrintTitleLines();
1164 g_StdOut << endl;
1165 fp.PrintSum(stat);
1166 }
1167
1168 if (enableHeaders)
1169 {
1170 if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0)
1171 {
1172 g_StdOut << "----------\n";
1173 PrintPropPair("Path", arcLink.NonOpen_ArcPath);
1174 PrintArcTypeError(codecs->Formats[arcLink.NonOpen_ErrorInfo.ErrorFormatIndex].Name, false);
1175 }
1176 }
1177 stat2.Update(stat);
1178 fflush(stdout);
1179 }
1180 if (enableHeaders && !techMode && (arcPaths.Size() > 1 || numVolumes > 1))
1181 {
1182 g_StdOut << endl;
1183 fp.PrintTitleLines();
1184 g_StdOut << endl;
1185 fp.PrintSum(stat2);
1186 g_StdOut << endl;
1187 PrintPropNameAndNumber("Archives", numArcs);
1188 PrintPropNameAndNumber("Volumes", numVolumes);
1189 PrintPropNameAndNumber("Total archives size", totalArcSizes);
1190 }
1191 return S_OK;
1192 }
1193