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