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
10 #include "Windows/Error.h"
11 #include "Windows/FileDir.h"
12 #include "Windows/PropVariant.h"
13 #include "Windows/PropVariantConversions.h"
14
15 #include "../../Archive/IArchive.h"
16
17 #include "../Common/OpenArchive.h"
18 #include "../Common/PropIDUtils.h"
19
20 #include "ConsoleClose.h"
21 #include "List.h"
22 #include "OpenCallbackConsole.h"
23
24 using namespace NWindows;
25
26 struct CPropIdToName
27 {
28 PROPID PropID;
29 const wchar_t *Name;
30 };
31
32 static const CPropIdToName kPropIdToName[] =
33 {
34 { kpidPath, L"Path" },
35 { kpidName, L"Name" },
36 { kpidIsDir, L"Folder" },
37 { kpidSize, L"Size" },
38 { kpidPackSize, L"Packed Size" },
39 { kpidAttrib, L"Attributes" },
40 { kpidCTime, L"Created" },
41 { kpidATime, L"Accessed" },
42 { kpidMTime, L"Modified" },
43 { kpidSolid, L"Solid" },
44 { kpidCommented, L"Commented" },
45 { kpidEncrypted, L"Encrypted" },
46 { kpidSplitBefore, L"Split Before" },
47 { kpidSplitAfter, L"Split After" },
48 { kpidDictionarySize, L"Dictionary Size" },
49 { kpidCRC, L"CRC" },
50 { kpidType, L"Type" },
51 { kpidIsAnti, L"Anti" },
52 { kpidMethod, L"Method" },
53 { kpidHostOS, L"Host OS" },
54 { kpidFileSystem, L"File System" },
55 { kpidUser, L"User" },
56 { kpidGroup, L"Group" },
57 { kpidBlock, L"Block" },
58 { kpidComment, L"Comment" },
59 { kpidPosition, L"Position" },
60 { kpidPrefix, L"Prefix" },
61 { kpidNumSubDirs, L"Folders" },
62 { kpidNumSubFiles, L"Files" },
63 { kpidUnpackVer, L"Version" },
64 { kpidVolume, L"Volume" },
65 { kpidIsVolume, L"Multivolume" },
66 { kpidOffset, L"Offset" },
67 { kpidLinks, L"Links" },
68 { kpidNumBlocks, L"Blocks" },
69 { kpidNumVolumes, L"Volumes" },
70
71 { kpidBit64, L"64-bit" },
72 { kpidBigEndian, L"Big-endian" },
73 { kpidCpu, L"CPU" },
74 { kpidPhySize, L"Physical Size" },
75 { kpidHeadersSize, L"Headers Size" },
76 { kpidChecksum, L"Checksum" },
77 { kpidCharacts, L"Characteristics" },
78 { kpidVa, L"Virtual Address" },
79 { kpidId, L"ID" },
80 { kpidShortName, L"Short Name" },
81 { kpidCreatorApp, L"Creator Application"},
82 { kpidSectorSize, L"Sector Size" },
83 { kpidPosixAttrib, L"Mode" },
84 { kpidLink, L"Link" },
85 { kpidError, L"Error" },
86
87 { kpidTotalSize, L"Total Size" },
88 { kpidFreeSpace, L"Free Space" },
89 { kpidClusterSize, L"Cluster Size" },
90 { kpidVolumeName, L"Label" }
91 };
92
93 static const char kEmptyAttribChar = '.';
94
95 static const char *kListing = "Listing archive: ";
96 static const wchar_t *kFilesMessage = L"files";
97 static const wchar_t *kDirsMessage = L"folders";
98
GetAttribString(DWORD wa,bool isDir,char * s)99 static void GetAttribString(DWORD wa, bool isDir, char *s)
100 {
101 s[0] = ((wa & FILE_ATTRIBUTE_DIRECTORY) != 0 || isDir) ? 'D' : kEmptyAttribChar;
102 s[1] = ((wa & FILE_ATTRIBUTE_READONLY) != 0) ? 'R': kEmptyAttribChar;
103 s[2] = ((wa & FILE_ATTRIBUTE_HIDDEN) != 0) ? 'H': kEmptyAttribChar;
104 s[3] = ((wa & FILE_ATTRIBUTE_SYSTEM) != 0) ? 'S': kEmptyAttribChar;
105 s[4] = ((wa & FILE_ATTRIBUTE_ARCHIVE) != 0) ? 'A': kEmptyAttribChar;
106 s[5] = '\0';
107 }
108
109 enum EAdjustment
110 {
111 kLeft,
112 kCenter,
113 kRight
114 };
115
116 struct CFieldInfo
117 {
118 PROPID PropID;
119 UString Name;
120 EAdjustment TitleAdjustment;
121 EAdjustment TextAdjustment;
122 int PrefixSpacesWidth;
123 int Width;
124 };
125
126 struct CFieldInfoInit
127 {
128 PROPID PropID;
129 const wchar_t *Name;
130 EAdjustment TitleAdjustment;
131 EAdjustment TextAdjustment;
132 int PrefixSpacesWidth;
133 int Width;
134 };
135
136 static CFieldInfoInit kStandardFieldTable[] =
137 {
138 { kpidMTime, L" Date Time", kLeft, kLeft, 0, 19 },
139 { kpidAttrib, L"Attr", kRight, kCenter, 1, 5 },
140 { kpidSize, L"Size", kRight, kRight, 1, 12 },
141 { kpidPackSize, L"Compressed", kRight, kRight, 1, 12 },
142 { kpidPath, L"Name", kLeft, kLeft, 2, 24 }
143 };
144
PrintSpaces(int numSpaces)145 static void PrintSpaces(int numSpaces)
146 {
147 for (int i = 0; i < numSpaces; i++)
148 g_StdOut << ' ';
149 }
150
PrintString(EAdjustment adjustment,int width,const UString & textString)151 static void PrintString(EAdjustment adjustment, int width, const UString &textString)
152 {
153 const int numSpaces = width - textString.Length();
154 int numLeftSpaces = 0;
155 switch (adjustment)
156 {
157 case kLeft:
158 numLeftSpaces = 0;
159 break;
160 case kCenter:
161 numLeftSpaces = numSpaces / 2;
162 break;
163 case kRight:
164 numLeftSpaces = numSpaces;
165 break;
166 }
167 PrintSpaces(numLeftSpaces);
168 g_StdOut << textString;
169 PrintSpaces(numSpaces - numLeftSpaces);
170 }
171
172 class CFieldPrinter
173 {
174 CObjectVector<CFieldInfo> _fields;
175 public:
Clear()176 void Clear() { _fields.Clear(); }
177 void Init(const CFieldInfoInit *standardFieldTable, int numItems);
178 HRESULT Init(IInArchive *archive);
179 void PrintTitle();
180 void PrintTitleLines();
181 HRESULT PrintItemInfo(const CArc &arc, UInt32 index, bool techMode);
182 HRESULT PrintSummaryInfo(UInt64 numFiles, UInt64 numDirs,
183 const UInt64 *size, const UInt64 *compressedSize);
184 };
185
Init(const CFieldInfoInit * standardFieldTable,int numItems)186 void CFieldPrinter::Init(const CFieldInfoInit *standardFieldTable, int numItems)
187 {
188 Clear();
189 for (int i = 0; i < numItems; i++)
190 {
191 CFieldInfo fieldInfo;
192 const CFieldInfoInit &fieldInfoInit = standardFieldTable[i];
193 fieldInfo.PropID = fieldInfoInit.PropID;
194 fieldInfo.Name = fieldInfoInit.Name;
195 fieldInfo.TitleAdjustment = fieldInfoInit.TitleAdjustment;
196 fieldInfo.TextAdjustment = fieldInfoInit.TextAdjustment;
197 fieldInfo.PrefixSpacesWidth = fieldInfoInit.PrefixSpacesWidth;
198 fieldInfo.Width = fieldInfoInit.Width;
199 _fields.Add(fieldInfo);
200 }
201 }
202
GetPropName(PROPID propID,BSTR name)203 static UString GetPropName(PROPID propID, BSTR name)
204 {
205 for (int i = 0; i < sizeof(kPropIdToName) / sizeof(kPropIdToName[0]); i++)
206 {
207 const CPropIdToName &propIdToName = kPropIdToName[i];
208 if (propIdToName.PropID == propID)
209 return propIdToName.Name;
210 }
211 if (name)
212 return name;
213 wchar_t s[16];
214 ConvertUInt32ToString(propID, s);
215 return s;
216 }
217
Init(IInArchive * archive)218 HRESULT CFieldPrinter::Init(IInArchive *archive)
219 {
220 Clear();
221 UInt32 numProps;
222 RINOK(archive->GetNumberOfProperties(&numProps));
223 for (UInt32 i = 0; i < numProps; i++)
224 {
225 CMyComBSTR name;
226 PROPID propID;
227 VARTYPE vt;
228 RINOK(archive->GetPropertyInfo(i, &name, &propID, &vt));
229 CFieldInfo fieldInfo;
230 fieldInfo.PropID = propID;
231 fieldInfo.Name = GetPropName(propID, name);
232 _fields.Add(fieldInfo);
233 }
234 return S_OK;
235 }
236
PrintTitle()237 void CFieldPrinter::PrintTitle()
238 {
239 for (int i = 0; i < _fields.Size(); i++)
240 {
241 const CFieldInfo &fieldInfo = _fields[i];
242 PrintSpaces(fieldInfo.PrefixSpacesWidth);
243 PrintString(fieldInfo.TitleAdjustment,
244 ((fieldInfo.PropID == kpidPath) ? 0: fieldInfo.Width), fieldInfo.Name);
245 }
246 }
247
PrintTitleLines()248 void CFieldPrinter::PrintTitleLines()
249 {
250 for (int i = 0; i < _fields.Size(); i++)
251 {
252 const CFieldInfo &fieldInfo = _fields[i];
253 PrintSpaces(fieldInfo.PrefixSpacesWidth);
254 for (int i = 0; i < fieldInfo.Width; i++)
255 g_StdOut << '-';
256 }
257 }
258
259
IsFileTimeZero(CONST FILETIME * lpFileTime)260 static BOOL IsFileTimeZero(CONST FILETIME *lpFileTime)
261 {
262 return (lpFileTime->dwLowDateTime == 0) && (lpFileTime->dwHighDateTime == 0);
263 }
264
265 static const char *kEmptyTimeString = " ";
PrintTime(const NCOM::CPropVariant & prop)266 static void PrintTime(const NCOM::CPropVariant &prop)
267 {
268 if (prop.vt != VT_FILETIME)
269 throw "incorrect item";
270 if (IsFileTimeZero(&prop.filetime))
271 g_StdOut << kEmptyTimeString;
272 else
273 {
274 FILETIME localFileTime;
275 if (!FileTimeToLocalFileTime(&prop.filetime, &localFileTime))
276 throw "FileTimeToLocalFileTime error";
277 char s[32];
278 if (ConvertFileTimeToString(localFileTime, s, true, true))
279 g_StdOut << s;
280 else
281 g_StdOut << kEmptyTimeString;
282 }
283 }
284
PrintItemInfo(const CArc & arc,UInt32 index,bool techMode)285 HRESULT CFieldPrinter::PrintItemInfo(const CArc &arc, UInt32 index, bool techMode)
286 {
287 /*
288 if (techMode)
289 {
290 g_StdOut << "Index = ";
291 g_StdOut << (UInt64)index;
292 g_StdOut << endl;
293 }
294 */
295 for (int i = 0; i < _fields.Size(); i++)
296 {
297 const CFieldInfo &fieldInfo = _fields[i];
298 if (!techMode)
299 PrintSpaces(fieldInfo.PrefixSpacesWidth);
300
301 NCOM::CPropVariant prop;
302 if (fieldInfo.PropID == kpidPath)
303 {
304 UString s;
305 RINOK(arc.GetItemPath(index, s));
306 prop = s;
307 }
308 else
309 {
310 RINOK(arc.Archive->GetProperty(index, fieldInfo.PropID, &prop));
311 }
312 if (techMode)
313 {
314 g_StdOut << fieldInfo.Name << " = ";
315 }
316 int width = (fieldInfo.PropID == kpidPath) ? 0: fieldInfo.Width;
317 if (fieldInfo.PropID == kpidAttrib && (prop.vt == VT_EMPTY || prop.vt == VT_UI4))
318 {
319 UInt32 attrib = (prop.vt == VT_EMPTY) ? 0 : prop.ulVal;
320 bool isFolder;
321 RINOK(IsArchiveItemFolder(arc.Archive, index, isFolder));
322 char s[8];
323 GetAttribString(attrib, isFolder, s);
324 g_StdOut << s;
325 }
326 else if (prop.vt == VT_EMPTY)
327 {
328 if (!techMode)
329 PrintSpaces(width);
330 }
331 else if (fieldInfo.PropID == kpidMTime)
332 {
333 PrintTime(prop);
334 }
335 else if (prop.vt == VT_BSTR)
336 {
337 if (techMode)
338 g_StdOut << prop.bstrVal;
339 else
340 PrintString(fieldInfo.TextAdjustment, width, prop.bstrVal);
341 }
342 else
343 {
344 UString s = ConvertPropertyToString(prop, fieldInfo.PropID);
345 s.Replace(wchar_t(0xA), L' ');
346 s.Replace(wchar_t(0xD), L' ');
347
348 if (techMode)
349 g_StdOut << s;
350 else
351 PrintString(fieldInfo.TextAdjustment, width, s);
352 }
353 if (techMode)
354 g_StdOut << endl;
355 }
356 return S_OK;
357 }
358
PrintNumberString(EAdjustment adjustment,int width,const UInt64 * value)359 static void PrintNumberString(EAdjustment adjustment, int width, const UInt64 *value)
360 {
361 wchar_t textString[32] = { 0 };
362 if (value != NULL)
363 ConvertUInt64ToString(*value, textString);
364 PrintString(adjustment, width, textString);
365 }
366
367
PrintSummaryInfo(UInt64 numFiles,UInt64 numDirs,const UInt64 * size,const UInt64 * compressedSize)368 HRESULT CFieldPrinter::PrintSummaryInfo(UInt64 numFiles, UInt64 numDirs,
369 const UInt64 *size, const UInt64 *compressedSize)
370 {
371 for (int i = 0; i < _fields.Size(); i++)
372 {
373 const CFieldInfo &fieldInfo = _fields[i];
374 PrintSpaces(fieldInfo.PrefixSpacesWidth);
375 NCOM::CPropVariant prop;
376 if (fieldInfo.PropID == kpidSize)
377 PrintNumberString(fieldInfo.TextAdjustment, fieldInfo.Width, size);
378 else if (fieldInfo.PropID == kpidPackSize)
379 PrintNumberString(fieldInfo.TextAdjustment, fieldInfo.Width, compressedSize);
380 else if (fieldInfo.PropID == kpidPath)
381 {
382 wchar_t textString[32];
383 ConvertUInt64ToString(numFiles, textString);
384 UString temp = textString;
385 temp += L" ";
386 temp += kFilesMessage;
387 temp += L", ";
388 ConvertUInt64ToString(numDirs, textString);
389 temp += textString;
390 temp += L" ";
391 temp += kDirsMessage;
392 PrintString(fieldInfo.TextAdjustment, 0, temp);
393 }
394 else
395 PrintString(fieldInfo.TextAdjustment, fieldInfo.Width, L"");
396 }
397 return S_OK;
398 }
399
GetUInt64Value(IInArchive * archive,UInt32 index,PROPID propID,UInt64 & value)400 bool GetUInt64Value(IInArchive *archive, UInt32 index, PROPID propID, UInt64 &value)
401 {
402 NCOM::CPropVariant prop;
403 if (archive->GetProperty(index, propID, &prop) != S_OK)
404 throw "GetPropertyValue error";
405 if (prop.vt == VT_EMPTY)
406 return false;
407 value = ConvertPropVariantToUInt64(prop);
408 return true;
409 }
410
PrintPropPair(const wchar_t * name,const wchar_t * value)411 static void PrintPropPair(const wchar_t *name, const wchar_t *value)
412 {
413 g_StdOut << name << " = " << value << endl;
414 }
415
ListArchives(CCodecs * codecs,const CIntVector & formatIndices,bool stdInMode,UStringVector & arcPaths,UStringVector & arcPathsFull,const NWildcard::CCensorNode & wildcardCensor,bool enableHeaders,bool techMode,bool & passwordEnabled,UString & password,UInt64 & numErrors)416 HRESULT ListArchives(CCodecs *codecs, const CIntVector &formatIndices,
417 bool stdInMode,
418 UStringVector &arcPaths, UStringVector &arcPathsFull,
419 const NWildcard::CCensorNode &wildcardCensor,
420 bool enableHeaders, bool techMode,
421 #ifndef _NO_CRYPTO
422 bool &passwordEnabled, UString &password,
423 #endif
424 UInt64 &numErrors)
425 {
426 numErrors = 0;
427 CFieldPrinter fieldPrinter;
428 if (!techMode)
429 fieldPrinter.Init(kStandardFieldTable, sizeof(kStandardFieldTable) / sizeof(kStandardFieldTable[0]));
430
431 UInt64 numFiles2 = 0, numDirs2 = 0, totalPackSize2 = 0, totalUnPackSize2 = 0;
432 UInt64 *totalPackSizePointer2 = 0, *totalUnPackSizePointer2 = 0;
433 int numArcs = /* stdInMode ? 1 : */ arcPaths.Size();
434 for (int i = 0; i < numArcs; i++)
435 {
436 const UString &archiveName = arcPaths[i];
437 UInt64 arcPackSize = 0;
438 if (!stdInMode)
439 {
440 NFile::NFind::CFileInfo fi;
441 if (!fi.Find(us2fs(archiveName)) || fi.IsDir())
442 {
443 g_StdOut << endl << "Error: " << archiveName << " is not file" << endl;
444 numErrors++;
445 continue;
446 }
447 arcPackSize = fi.Size;
448 }
449
450 CArchiveLink archiveLink;
451
452 COpenCallbackConsole openCallback;
453 openCallback.OutStream = &g_StdOut;
454
455 #ifndef _NO_CRYPTO
456
457 openCallback.PasswordIsDefined = passwordEnabled;
458 openCallback.Password = password;
459
460 #endif
461
462 HRESULT result = archiveLink.Open2(codecs, formatIndices, stdInMode, NULL, archiveName, &openCallback);
463 if (result != S_OK)
464 {
465 if (result == E_ABORT)
466 return result;
467 g_StdOut << endl << "Error: " << archiveName << ": ";
468 if (result == S_FALSE)
469 {
470 #ifndef _NO_CRYPTO
471 if (openCallback.Open_WasPasswordAsked())
472 g_StdOut << "Can not open encrypted archive. Wrong password?";
473 else
474 #endif
475 g_StdOut << "Can not open file as archive";
476 }
477 else if (result == E_OUTOFMEMORY)
478 g_StdOut << "Can't allocate required memory";
479 else
480 g_StdOut << NError::MyFormatMessageW(result);
481 g_StdOut << endl;
482 numErrors++;
483 continue;
484 }
485
486 if (!stdInMode)
487 for (int v = 0; v < archiveLink.VolumePaths.Size(); v++)
488 {
489 int index = arcPathsFull.FindInSorted(archiveLink.VolumePaths[v]);
490 if (index >= 0 && index > i)
491 {
492 arcPaths.Delete(index);
493 arcPathsFull.Delete(index);
494 numArcs = arcPaths.Size();
495 }
496 }
497
498 if (enableHeaders)
499 {
500 g_StdOut << endl << kListing << archiveName << endl << endl;
501
502 for (int i = 0; i < archiveLink.Arcs.Size(); i++)
503 {
504 const CArc &arc = archiveLink.Arcs[i];
505
506 g_StdOut << "--\n";
507 PrintPropPair(L"Path", arc.Path);
508 PrintPropPair(L"Type", codecs->Formats[arc.FormatIndex].Name);
509 if (!arc.ErrorMessage.IsEmpty())
510 PrintPropPair(L"Error", arc.ErrorMessage);
511 UInt32 numProps;
512 IInArchive *archive = arc.Archive;
513 if (archive->GetNumberOfArchiveProperties(&numProps) == S_OK)
514 {
515 for (UInt32 j = 0; j < numProps; j++)
516 {
517 CMyComBSTR name;
518 PROPID propID;
519 VARTYPE vt;
520 RINOK(archive->GetArchivePropertyInfo(j, &name, &propID, &vt));
521 NCOM::CPropVariant prop;
522 RINOK(archive->GetArchiveProperty(propID, &prop));
523 UString s = ConvertPropertyToString(prop, propID);
524 if (!s.IsEmpty())
525 PrintPropPair(GetPropName(propID, name), s);
526 }
527 }
528 if (i != archiveLink.Arcs.Size() - 1)
529 {
530 UInt32 numProps;
531 g_StdOut << "----\n";
532 if (archive->GetNumberOfProperties(&numProps) == S_OK)
533 {
534 UInt32 mainIndex = archiveLink.Arcs[i + 1].SubfileIndex;
535 for (UInt32 j = 0; j < numProps; j++)
536 {
537 CMyComBSTR name;
538 PROPID propID;
539 VARTYPE vt;
540 RINOK(archive->GetPropertyInfo(j, &name, &propID, &vt));
541 NCOM::CPropVariant prop;
542 RINOK(archive->GetProperty(mainIndex, propID, &prop));
543 UString s = ConvertPropertyToString(prop, propID);
544 if (!s.IsEmpty())
545 PrintPropPair(GetPropName(propID, name), s);
546 }
547 }
548 }
549
550 }
551 g_StdOut << endl;
552 if (techMode)
553 g_StdOut << "----------\n";
554 }
555
556 if (enableHeaders && !techMode)
557 {
558 fieldPrinter.PrintTitle();
559 g_StdOut << endl;
560 fieldPrinter.PrintTitleLines();
561 g_StdOut << endl;
562 }
563
564 const CArc &arc = archiveLink.Arcs.Back();
565 IInArchive *archive = arc.Archive;
566 if (techMode)
567 {
568 RINOK(fieldPrinter.Init(archive));
569 }
570 UInt64 numFiles = 0, numDirs = 0, totalPackSize = 0, totalUnPackSize = 0;
571 UInt64 *totalPackSizePointer = 0, *totalUnPackSizePointer = 0;
572 UInt32 numItems;
573 RINOK(archive->GetNumberOfItems(&numItems));
574 for (UInt32 i = 0; i < numItems; i++)
575 {
576 if (NConsoleClose::TestBreakSignal())
577 return E_ABORT;
578
579 UString filePath;
580 HRESULT res = arc.GetItemPath(i, filePath);
581 if (stdInMode && res == E_INVALIDARG)
582 break;
583 RINOK(res);
584
585 bool isFolder;
586 RINOK(IsArchiveItemFolder(archive, i, isFolder));
587 if (!wildcardCensor.CheckPath(filePath, !isFolder))
588 continue;
589
590 fieldPrinter.PrintItemInfo(arc, i, techMode);
591
592 UInt64 packSize, unpackSize;
593 if (!GetUInt64Value(archive, i, kpidSize, unpackSize))
594 unpackSize = 0;
595 else
596 totalUnPackSizePointer = &totalUnPackSize;
597 if (!GetUInt64Value(archive, i, kpidPackSize, packSize))
598 packSize = 0;
599 else
600 totalPackSizePointer = &totalPackSize;
601
602 g_StdOut << endl;
603
604 if (isFolder)
605 numDirs++;
606 else
607 numFiles++;
608 totalPackSize += packSize;
609 totalUnPackSize += unpackSize;
610 }
611
612 if (!stdInMode && totalPackSizePointer == 0)
613 {
614 if (archiveLink.VolumePaths.Size() != 0)
615 arcPackSize += archiveLink.VolumesSize;
616 totalPackSize = (numFiles == 0) ? 0 : arcPackSize;
617 totalPackSizePointer = &totalPackSize;
618 }
619 if (totalUnPackSizePointer == 0 && numFiles == 0)
620 {
621 totalUnPackSize = 0;
622 totalUnPackSizePointer = &totalUnPackSize;
623 }
624 if (enableHeaders && !techMode)
625 {
626 fieldPrinter.PrintTitleLines();
627 g_StdOut << endl;
628 fieldPrinter.PrintSummaryInfo(numFiles, numDirs, totalUnPackSizePointer, totalPackSizePointer);
629 g_StdOut << endl;
630 }
631 if (totalPackSizePointer != 0)
632 {
633 totalPackSizePointer2 = &totalPackSize2;
634 totalPackSize2 += totalPackSize;
635 }
636 if (totalUnPackSizePointer != 0)
637 {
638 totalUnPackSizePointer2 = &totalUnPackSize2;
639 totalUnPackSize2 += totalUnPackSize;
640 }
641 numFiles2 += numFiles;
642 numDirs2 += numDirs;
643 }
644 if (enableHeaders && !techMode && numArcs > 1)
645 {
646 g_StdOut << endl;
647 fieldPrinter.PrintTitleLines();
648 g_StdOut << endl;
649 fieldPrinter.PrintSummaryInfo(numFiles2, numDirs2, totalUnPackSizePointer2, totalPackSizePointer2);
650 g_StdOut << endl;
651 g_StdOut << "Archives: " << numArcs << endl;
652 }
653 return S_OK;
654 }
655