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