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