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 *kListing = "Listing archive: "; 132 133 static const char *kString_Files = "files"; 134 static const char *kString_Dirs = "folders"; 135 static const char *kString_AltStreams = "alternate streams"; 136 static const char *kString_Streams = "streams"; 137 138 static const char *kError = "ERROR: "; 139 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 199 static void PrintSpaces(unsigned numSpaces) 200 { 201 if (numSpaces > 0 && numSpaces <= kNumSpacesMax) 202 g_StdOut << g_Spaces + (kNumSpacesMax - numSpaces); 203 } 204 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 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 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 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 301 CListUInt64Def(): Val(0), Def(false) {} 302 void Add(UInt64 v) { Val += v; Def = true; } 303 void Add(const CListUInt64Def &v) { if (v.Def) Add(v.Val); } 304 }; 305 306 struct CListFileTimeDef 307 { 308 FILETIME Val; 309 bool Def; 310 311 CListFileTimeDef(): Def(false) { Val.dwLowDateTime = 0; Val.dwHighDateTime = 0; } 312 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 329 CListStat(): NumFiles(0) {} 330 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 } 337 void SetSizeDefIfNoFiles() { if (NumFiles == 0) Size.Def = true; } 338 }; 339 340 struct CListStat2 341 { 342 CListStat MainFiles; 343 CListStat AltStreams; 344 UInt64 NumDirs; 345 346 CListStat2(): NumDirs(0) {} 347 348 void Update(const CListStat2 &st) 349 { 350 MainFiles.Update(st.MainFiles); 351 AltStreams.Update(st.AltStreams); 352 NumDirs += st.NumDirs; 353 } 354 const UInt64 GetNumStreams() const { return MainFiles.NumFiles + AltStreams.NumFiles; } 355 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 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 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 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 char s[16]; 421 ConvertUInt32ToString(propID, s); 422 nameA = s; 423 } 424 } 425 426 void CFieldPrinter::AddProp(const wchar_t *name, PROPID propID, bool isRawProp) 427 { 428 CFieldInfo f; 429 f.PropID = propID; 430 f.IsRawProp = isRawProp; 431 GetPropName(propID, name, f.NameA, f.NameU); 432 f.NameU.AddAscii(" = "); 433 if (!f.NameA.IsEmpty()) 434 f.NameA += " = "; 435 else 436 { 437 const UString &s = f.NameU; 438 AString sA; 439 unsigned i; 440 for (i = 0; i < s.Len(); i++) 441 { 442 wchar_t c = s[i]; 443 if (c >= 0x80) 444 break; 445 sA += (char)c; 446 } 447 if (i == s.Len()) 448 f.NameA = sA; 449 } 450 _fields.Add(f); 451 } 452 453 HRESULT CFieldPrinter::AddMainProps(IInArchive *archive) 454 { 455 UInt32 numProps; 456 RINOK(archive->GetNumberOfProperties(&numProps)); 457 for (UInt32 i = 0; i < numProps; i++) 458 { 459 CMyComBSTR name; 460 PROPID propID; 461 VARTYPE vt; 462 RINOK(archive->GetPropertyInfo(i, &name, &propID, &vt)); 463 AddProp(name, propID, false); 464 } 465 return S_OK; 466 } 467 468 HRESULT CFieldPrinter::AddRawProps(IArchiveGetRawProps *getRawProps) 469 { 470 UInt32 numProps; 471 RINOK(getRawProps->GetNumRawProps(&numProps)); 472 for (UInt32 i = 0; i < numProps; i++) 473 { 474 CMyComBSTR name; 475 PROPID propID; 476 RINOK(getRawProps->GetRawPropInfo(i, &name, &propID)); 477 AddProp(name, propID, true); 478 } 479 return S_OK; 480 } 481 482 void CFieldPrinter::PrintTitle() 483 { 484 FOR_VECTOR (i, _fields) 485 { 486 const CFieldInfo &f = _fields[i]; 487 PrintSpaces(f.PrefixSpacesWidth); 488 PrintString(f.TitleAdjustment, ((f.PropID == kpidPath) ? 0: f.Width), f.NameA); 489 } 490 } 491 492 void CFieldPrinter::PrintTitleLines() 493 { 494 g_StdOut << LinesString; 495 } 496 497 static void PrintTime(char *dest, const FILETIME *ft) 498 { 499 *dest = 0; 500 if (ft->dwLowDateTime == 0 && ft->dwHighDateTime == 0) 501 return; 502 FILETIME locTime; 503 if (!FileTimeToLocalFileTime(ft, &locTime)) 504 throw 20121211; 505 ConvertFileTimeToString(locTime, dest, true, true); 506 } 507 508 #ifndef _SFX 509 510 static inline char GetHex(Byte value) 511 { 512 return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10))); 513 } 514 515 static void HexToString(char *dest, const Byte *data, UInt32 size) 516 { 517 for (UInt32 i = 0; i < size; i++) 518 { 519 Byte b = data[i]; 520 dest[0] = GetHex((Byte)((b >> 4) & 0xF)); 521 dest[1] = GetHex((Byte)(b & 0xF)); 522 dest += 2; 523 } 524 *dest = 0; 525 } 526 527 #endif 528 529 #define MY_ENDL endl 530 531 HRESULT CFieldPrinter::PrintItemInfo(UInt32 index, const CListStat &st) 532 { 533 char temp[128]; 534 size_t tempPos = 0; 535 536 bool techMode = this->TechMode; 537 /* 538 if (techMode) 539 { 540 g_StdOut << "Index = "; 541 g_StdOut << (UInt64)index; 542 g_StdOut << endl; 543 } 544 */ 545 FOR_VECTOR (i, _fields) 546 { 547 const CFieldInfo &f = _fields[i]; 548 549 if (!techMode) 550 { 551 PrintSpacesToString(temp + tempPos, f.PrefixSpacesWidth); 552 tempPos += f.PrefixSpacesWidth; 553 } 554 555 if (techMode) 556 { 557 if (!f.NameA.IsEmpty()) 558 g_StdOut << f.NameA; 559 else 560 g_StdOut << f.NameU; 561 } 562 563 if (f.PropID == kpidPath) 564 { 565 if (!techMode) 566 g_StdOut << temp; 567 g_StdOut.PrintUString(FilePath, TempAString); 568 if (techMode) 569 g_StdOut << MY_ENDL; 570 continue; 571 } 572 573 const unsigned width = f.Width; 574 575 if (f.IsRawProp) 576 { 577 #ifndef _SFX 578 579 const void *data; 580 UInt32 dataSize; 581 UInt32 propType; 582 RINOK(Arc->GetRawProps->GetRawProp(index, f.PropID, &data, &dataSize, &propType)); 583 584 if (dataSize != 0) 585 { 586 bool needPrint = true; 587 588 if (f.PropID == kpidNtSecure) 589 { 590 if (propType != NPropDataType::kRaw) 591 return E_FAIL; 592 #ifndef _SFX 593 ConvertNtSecureToString((const Byte *)data, dataSize, TempAString); 594 g_StdOut << TempAString; 595 needPrint = false; 596 #endif 597 } 598 else if (f.PropID == kpidNtReparse) 599 { 600 UString s; 601 if (ConvertNtReparseToString((const Byte *)data, dataSize, s)) 602 { 603 needPrint = false; 604 g_StdOut.PrintUString(s, TempAString); 605 } 606 } 607 608 if (needPrint) 609 { 610 if (propType != NPropDataType::kRaw) 611 return E_FAIL; 612 613 const UInt32 kMaxDataSize = 64; 614 615 if (dataSize > kMaxDataSize) 616 { 617 g_StdOut << "data:"; 618 g_StdOut << dataSize; 619 } 620 else 621 { 622 char hexStr[kMaxDataSize * 2 + 4]; 623 HexToString(hexStr, (const Byte *)data, dataSize); 624 g_StdOut << hexStr; 625 } 626 } 627 } 628 629 #endif 630 } 631 else 632 { 633 CPropVariant prop; 634 switch (f.PropID) 635 { 636 case kpidSize: if (st.Size.Def) prop = st.Size.Val; break; 637 case kpidPackSize: if (st.PackSize.Def) prop = st.PackSize.Val; break; 638 case kpidMTime: if (st.MTime.Def) prop = st.MTime.Val; break; 639 default: 640 RINOK(Arc->Archive->GetProperty(index, f.PropID, &prop)); 641 } 642 if (f.PropID == kpidAttrib && (prop.vt == VT_EMPTY || prop.vt == VT_UI4)) 643 { 644 GetAttribString((prop.vt == VT_EMPTY) ? 0 : prop.ulVal, IsDir, techMode, temp + tempPos); 645 if (techMode) 646 g_StdOut << temp + tempPos; 647 else 648 tempPos += strlen(temp + tempPos); 649 } 650 else if (prop.vt == VT_EMPTY) 651 { 652 if (!techMode) 653 { 654 PrintSpacesToString(temp + tempPos, width); 655 tempPos += width; 656 } 657 } 658 else if (prop.vt == VT_FILETIME) 659 { 660 PrintTime(temp + tempPos, &prop.filetime); 661 if (techMode) 662 g_StdOut << temp + tempPos; 663 else 664 { 665 size_t len = strlen(temp + tempPos); 666 tempPos += len; 667 if (len < (unsigned)f.Width) 668 { 669 len = f.Width - len; 670 PrintSpacesToString(temp + tempPos, (unsigned)len); 671 tempPos += len; 672 } 673 } 674 } 675 else if (prop.vt == VT_BSTR) 676 { 677 TempWString.SetFromBstr(prop.bstrVal); 678 if (techMode) 679 { 680 // replace CR/LF here. 681 g_StdOut.PrintUString(TempWString, TempAString); 682 } 683 else 684 PrintUString(f.TextAdjustment, width, TempWString, TempAString); 685 } 686 else 687 { 688 char s[64]; 689 ConvertPropertyToShortString(s, prop, f.PropID); 690 if (techMode) 691 g_StdOut << s; 692 else 693 { 694 PrintStringToString(temp + tempPos, f.TextAdjustment, width, s); 695 tempPos += strlen(temp + tempPos); 696 } 697 } 698 } 699 if (techMode) 700 g_StdOut << MY_ENDL; 701 } 702 g_StdOut << MY_ENDL; 703 return S_OK; 704 } 705 706 static void PrintNumber(EAdjustment adj, unsigned width, const CListUInt64Def &value) 707 { 708 char s[32]; 709 s[0] = 0; 710 if (value.Def) 711 ConvertUInt64ToString(value.Val, s); 712 PrintString(adj, width, s); 713 } 714 715 void Print_UInt64_and_String(AString &s, UInt64 val, const char *name); 716 717 void CFieldPrinter::PrintSum(const CListStat &st, UInt64 numDirs, const char *str) 718 { 719 FOR_VECTOR (i, _fields) 720 { 721 const CFieldInfo &f = _fields[i]; 722 PrintSpaces(f.PrefixSpacesWidth); 723 if (f.PropID == kpidSize) 724 PrintNumber(f.TextAdjustment, f.Width, st.Size); 725 else if (f.PropID == kpidPackSize) 726 PrintNumber(f.TextAdjustment, f.Width, st.PackSize); 727 else if (f.PropID == kpidMTime) 728 { 729 char s[64]; 730 s[0] = 0; 731 if (st.MTime.Def) 732 PrintTime(s, &st.MTime.Val); 733 PrintString(f.TextAdjustment, f.Width, s); 734 } 735 else if (f.PropID == kpidPath) 736 { 737 AString s; 738 Print_UInt64_and_String(s, st.NumFiles, str); 739 if (numDirs != 0) 740 { 741 s += ", "; 742 Print_UInt64_and_String(s, numDirs, kString_Dirs); 743 } 744 PrintString(f.TextAdjustment, 0, s); 745 } 746 else 747 PrintString(f.TextAdjustment, f.Width, ""); 748 } 749 g_StdOut << endl; 750 } 751 752 void CFieldPrinter::PrintSum(const CListStat2 &stat2) 753 { 754 PrintSum(stat2.MainFiles, stat2.NumDirs, kString_Files); 755 if (stat2.AltStreams.NumFiles != 0) 756 { 757 PrintSum(stat2.AltStreams, 0, kString_AltStreams);; 758 CListStat st = stat2.MainFiles; 759 st.Update(stat2.AltStreams); 760 PrintSum(st, 0, kString_Streams); 761 } 762 } 763 764 static HRESULT GetUInt64Value(IInArchive *archive, UInt32 index, PROPID propID, CListUInt64Def &value) 765 { 766 value.Val = 0; 767 value.Def = false; 768 CPropVariant prop; 769 RINOK(archive->GetProperty(index, propID, &prop)); 770 value.Def = ConvertPropVariantToUInt64(prop, value.Val); 771 return S_OK; 772 } 773 774 static HRESULT GetItemMTime(IInArchive *archive, UInt32 index, CListFileTimeDef &t) 775 { 776 t.Val.dwLowDateTime = 0; 777 t.Val.dwHighDateTime = 0; 778 t.Def = false; 779 CPropVariant prop; 780 RINOK(archive->GetProperty(index, kpidMTime, &prop)); 781 if (prop.vt == VT_FILETIME) 782 { 783 t.Val = prop.filetime; 784 t.Def = true; 785 } 786 else if (prop.vt != VT_EMPTY) 787 return E_FAIL; 788 return S_OK; 789 } 790 791 static void PrintPropNameAndNumber(CStdOutStream &so, const char *name, UInt64 val) 792 { 793 so << name << ": " << val << endl; 794 } 795 796 static void PrintPropName_and_Eq(CStdOutStream &so, PROPID propID) 797 { 798 const char *s; 799 char temp[16]; 800 if (propID < ARRAY_SIZE(kPropIdToName)) 801 s = kPropIdToName[propID]; 802 else 803 { 804 ConvertUInt32ToString(propID, temp); 805 s = temp; 806 } 807 so << s << " = "; 808 } 809 810 static void PrintPropNameAndNumber(CStdOutStream &so, PROPID propID, UInt64 val) 811 { 812 PrintPropName_and_Eq(so, propID); 813 so << val << endl; 814 } 815 816 static void PrintPropNameAndNumber_Signed(CStdOutStream &so, PROPID propID, Int64 val) 817 { 818 PrintPropName_and_Eq(so, propID); 819 so << val << endl; 820 } 821 822 static void PrintPropPair(CStdOutStream &so, const char *name, const wchar_t *val) 823 { 824 so << name << " = " << val << endl; 825 } 826 827 828 static void PrintPropertyPair2(CStdOutStream &so, PROPID propID, const wchar_t *name, const CPropVariant &prop) 829 { 830 UString s; 831 ConvertPropertyToString(s, prop, propID); 832 if (!s.IsEmpty()) 833 { 834 AString nameA; 835 UString nameU; 836 GetPropName(propID, name, nameA, nameU); 837 if (!nameA.IsEmpty()) 838 PrintPropPair(so, nameA, s); 839 else 840 so << nameU << " = " << s << endl; 841 } 842 } 843 844 static HRESULT PrintArcProp(CStdOutStream &so, IInArchive *archive, PROPID propID, const wchar_t *name) 845 { 846 CPropVariant prop; 847 RINOK(archive->GetArchiveProperty(propID, &prop)); 848 PrintPropertyPair2(so, propID, name, prop); 849 return S_OK; 850 } 851 852 static void PrintArcTypeError(CStdOutStream &so, const UString &type, bool isWarning) 853 { 854 so << "Open " << (isWarning ? "WARNING" : "ERROR") 855 << ": Can not open the file as [" 856 << type 857 << "] archive" 858 << endl; 859 } 860 861 int Find_FileName_InSortedVector(const UStringVector &fileName, const UString& name); 862 863 void PrintErrorFlags(CStdOutStream &so, const char *s, UInt32 errorFlags); 864 865 static void ErrorInfo_Print(CStdOutStream &so, const CArcErrorInfo &er) 866 { 867 PrintErrorFlags(so, "ERRORS:", er.GetErrorFlags()); 868 if (!er.ErrorMessage.IsEmpty()) 869 PrintPropPair(so, "ERROR", er.ErrorMessage); 870 871 PrintErrorFlags(so, "WARNINGS:", er.GetWarningFlags()); 872 if (!er.WarningMessage.IsEmpty()) 873 PrintPropPair(so, "WARNING", er.WarningMessage); 874 } 875 876 HRESULT Print_OpenArchive_Props(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink) 877 { 878 FOR_VECTOR (r, arcLink.Arcs) 879 { 880 const CArc &arc = arcLink.Arcs[r]; 881 const CArcErrorInfo &er = arc.ErrorInfo; 882 883 so << "--\n"; 884 PrintPropPair(so, "Path", arc.Path); 885 if (er.ErrorFormatIndex >= 0) 886 { 887 if (er.ErrorFormatIndex == arc.FormatIndex) 888 so << "Warning: The archive is open with offset" << endl; 889 else 890 PrintArcTypeError(so, codecs->GetFormatNamePtr(er.ErrorFormatIndex), true); 891 } 892 PrintPropPair(so, "Type", codecs->GetFormatNamePtr(arc.FormatIndex)); 893 894 ErrorInfo_Print(so, er); 895 896 Int64 offset = arc.GetGlobalOffset(); 897 if (offset != 0) 898 PrintPropNameAndNumber_Signed(so, kpidOffset, offset); 899 IInArchive *archive = arc.Archive; 900 RINOK(PrintArcProp(so, archive, kpidPhySize, NULL)); 901 if (er.TailSize != 0) 902 PrintPropNameAndNumber(so, kpidTailSize, er.TailSize); 903 { 904 UInt32 numProps; 905 RINOK(archive->GetNumberOfArchiveProperties(&numProps)); 906 907 for (UInt32 j = 0; j < numProps; j++) 908 { 909 CMyComBSTR name; 910 PROPID propID; 911 VARTYPE vt; 912 RINOK(archive->GetArchivePropertyInfo(j, &name, &propID, &vt)); 913 RINOK(PrintArcProp(so, archive, propID, name)); 914 } 915 } 916 917 if (r != arcLink.Arcs.Size() - 1) 918 { 919 UInt32 numProps; 920 so << "----\n"; 921 if (archive->GetNumberOfProperties(&numProps) == S_OK) 922 { 923 UInt32 mainIndex = arcLink.Arcs[r + 1].SubfileIndex; 924 for (UInt32 j = 0; j < numProps; j++) 925 { 926 CMyComBSTR name; 927 PROPID propID; 928 VARTYPE vt; 929 RINOK(archive->GetPropertyInfo(j, &name, &propID, &vt)); 930 CPropVariant prop; 931 RINOK(archive->GetProperty(mainIndex, propID, &prop)); 932 PrintPropertyPair2(so, propID, name, prop); 933 } 934 } 935 } 936 } 937 return S_OK; 938 } 939 940 HRESULT Print_OpenArchive_Error(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink) 941 { 942 #ifndef _NO_CRYPTO 943 if (arcLink.PasswordWasAsked) 944 so << "Can not open encrypted archive. Wrong password?"; 945 else 946 #endif 947 { 948 if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0) 949 { 950 so << arcLink.NonOpen_ArcPath << endl; 951 PrintArcTypeError(so, codecs->Formats[arcLink.NonOpen_ErrorInfo.ErrorFormatIndex].Name, false); 952 } 953 else 954 so << "Can not open the file as archive"; 955 } 956 957 so << endl; 958 so << endl; 959 ErrorInfo_Print(so, arcLink.NonOpen_ErrorInfo); 960 961 return S_OK; 962 } 963 964 bool CensorNode_CheckPath(const NWildcard::CCensorNode &node, const CReadArcItem &item); 965 966 HRESULT ListArchives(CCodecs *codecs, 967 const CObjectVector<COpenType> &types, 968 const CIntVector &excludedFormats, 969 bool stdInMode, 970 UStringVector &arcPaths, UStringVector &arcPathsFull, 971 bool processAltStreams, bool showAltStreams, 972 const NWildcard::CCensorNode &wildcardCensor, 973 bool enableHeaders, bool techMode, 974 #ifndef _NO_CRYPTO 975 bool &passwordEnabled, UString &password, 976 #endif 977 #ifndef _SFX 978 const CObjectVector<CProperty> *props, 979 #endif 980 UInt64 &numErrors, 981 UInt64 &numWarnings) 982 { 983 bool allFilesAreAllowed = wildcardCensor.AreAllAllowed(); 984 985 numErrors = 0; 986 numWarnings = 0; 987 988 CFieldPrinter fp; 989 if (!techMode) 990 fp.Init(kStandardFieldTable, ARRAY_SIZE(kStandardFieldTable)); 991 992 CListStat2 stat2total; 993 994 CBoolArr skipArcs(arcPaths.Size()); 995 unsigned arcIndex; 996 for (arcIndex = 0; arcIndex < arcPaths.Size(); arcIndex++) 997 skipArcs[arcIndex] = false; 998 UInt64 numVolumes = 0; 999 UInt64 numArcs = 0; 1000 UInt64 totalArcSizes = 0; 1001 1002 HRESULT lastError = 0; 1003 1004 for (arcIndex = 0; arcIndex < arcPaths.Size(); arcIndex++) 1005 { 1006 if (skipArcs[arcIndex]) 1007 continue; 1008 const UString &arcPath = arcPaths[arcIndex]; 1009 UInt64 arcPackSize = 0; 1010 1011 if (!stdInMode) 1012 { 1013 NFile::NFind::CFileInfo fi; 1014 if (!fi.Find(us2fs(arcPath))) 1015 { 1016 DWORD errorCode = GetLastError(); 1017 if (errorCode == 0) 1018 errorCode = ERROR_FILE_NOT_FOUND; 1019 lastError = HRESULT_FROM_WIN32(lastError);; 1020 g_StdOut.Flush(); 1021 *g_ErrStream << endl << kError << NError::MyFormatMessage(errorCode) << 1022 endl << arcPath << endl << endl; 1023 numErrors++; 1024 continue; 1025 } 1026 if (fi.IsDir()) 1027 { 1028 g_StdOut.Flush(); 1029 *g_ErrStream << endl << kError << arcPath << " is not a file" << endl << endl; 1030 numErrors++; 1031 continue; 1032 } 1033 arcPackSize = fi.Size; 1034 totalArcSizes += arcPackSize; 1035 } 1036 1037 CArchiveLink arcLink; 1038 1039 COpenCallbackConsole openCallback; 1040 openCallback.Init(&g_StdOut, g_ErrStream, NULL); 1041 1042 #ifndef _NO_CRYPTO 1043 1044 openCallback.PasswordIsDefined = passwordEnabled; 1045 openCallback.Password = password; 1046 1047 #endif 1048 1049 /* 1050 CObjectVector<COptionalOpenProperties> optPropsVector; 1051 COptionalOpenProperties &optProps = optPropsVector.AddNew(); 1052 optProps.Props = *props; 1053 */ 1054 1055 COpenOptions options; 1056 #ifndef _SFX 1057 options.props = props; 1058 #endif 1059 options.codecs = codecs; 1060 options.types = &types; 1061 options.excludedFormats = &excludedFormats; 1062 options.stdInMode = stdInMode; 1063 options.stream = NULL; 1064 options.filePath = arcPath; 1065 1066 if (enableHeaders) 1067 { 1068 g_StdOut << endl << kListing << arcPath << endl << endl; 1069 } 1070 1071 HRESULT result = arcLink.Open_Strict(options, &openCallback); 1072 1073 if (result != S_OK) 1074 { 1075 if (result == E_ABORT) 1076 return result; 1077 g_StdOut.Flush(); 1078 *g_ErrStream << endl << kError << arcPath << " : "; 1079 if (result == S_FALSE) 1080 { 1081 Print_OpenArchive_Error(*g_ErrStream, codecs, arcLink); 1082 } 1083 else 1084 { 1085 lastError = result; 1086 *g_ErrStream << "opening : "; 1087 if (result == E_OUTOFMEMORY) 1088 *g_ErrStream << "Can't allocate required memory"; 1089 else 1090 *g_ErrStream << NError::MyFormatMessage(result); 1091 } 1092 *g_ErrStream << endl; 1093 numErrors++; 1094 continue; 1095 } 1096 1097 { 1098 FOR_VECTOR (r, arcLink.Arcs) 1099 { 1100 const CArcErrorInfo &arc = arcLink.Arcs[r].ErrorInfo; 1101 if (!arc.WarningMessage.IsEmpty()) 1102 numWarnings++; 1103 if (arc.AreThereWarnings()) 1104 numWarnings++; 1105 if (arc.ErrorFormatIndex >= 0) 1106 numWarnings++; 1107 if (arc.AreThereErrors()) 1108 { 1109 numErrors++; 1110 // break; 1111 } 1112 if (!arc.ErrorMessage.IsEmpty()) 1113 numErrors++; 1114 } 1115 } 1116 1117 numArcs++; 1118 numVolumes++; 1119 1120 if (!stdInMode) 1121 { 1122 numVolumes += arcLink.VolumePaths.Size(); 1123 totalArcSizes += arcLink.VolumesSize; 1124 FOR_VECTOR (v, arcLink.VolumePaths) 1125 { 1126 int index = Find_FileName_InSortedVector(arcPathsFull, arcLink.VolumePaths[v]); 1127 if (index >= 0 && (unsigned)index > arcIndex) 1128 skipArcs[(unsigned)index] = true; 1129 } 1130 } 1131 1132 1133 if (enableHeaders) 1134 { 1135 RINOK(Print_OpenArchive_Props(g_StdOut, codecs, arcLink)); 1136 1137 g_StdOut << endl; 1138 if (techMode) 1139 g_StdOut << "----------\n"; 1140 } 1141 1142 if (enableHeaders && !techMode) 1143 { 1144 fp.PrintTitle(); 1145 g_StdOut << endl; 1146 fp.PrintTitleLines(); 1147 g_StdOut << endl; 1148 } 1149 1150 const CArc &arc = arcLink.Arcs.Back(); 1151 fp.Arc = &arc; 1152 fp.TechMode = techMode; 1153 IInArchive *archive = arc.Archive; 1154 if (techMode) 1155 { 1156 fp.Clear(); 1157 RINOK(fp.AddMainProps(archive)); 1158 if (arc.GetRawProps) 1159 { 1160 RINOK(fp.AddRawProps(arc.GetRawProps)); 1161 } 1162 } 1163 1164 CListStat2 stat2; 1165 1166 UInt32 numItems; 1167 RINOK(archive->GetNumberOfItems(&numItems)); 1168 1169 CReadArcItem item; 1170 UStringVector pathParts; 1171 1172 for (UInt32 i = 0; i < numItems; i++) 1173 { 1174 if (NConsoleClose::TestBreakSignal()) 1175 return E_ABORT; 1176 1177 HRESULT res = arc.GetItemPath2(i, fp.FilePath); 1178 1179 if (stdInMode && res == E_INVALIDARG) 1180 break; 1181 RINOK(res); 1182 1183 if (arc.Ask_Aux) 1184 { 1185 bool isAux; 1186 RINOK(Archive_IsItem_Aux(archive, i, isAux)); 1187 if (isAux) 1188 continue; 1189 } 1190 1191 bool isAltStream = false; 1192 if (arc.Ask_AltStream) 1193 { 1194 RINOK(Archive_IsItem_AltStream(archive, i, isAltStream)); 1195 if (isAltStream && !processAltStreams) 1196 continue; 1197 } 1198 1199 RINOK(Archive_IsItem_Dir(archive, i, fp.IsDir)); 1200 1201 if (!allFilesAreAllowed) 1202 { 1203 if (isAltStream) 1204 { 1205 RINOK(arc.GetItem(i, item)); 1206 if (!CensorNode_CheckPath(wildcardCensor, item)) 1207 continue; 1208 } 1209 else 1210 { 1211 SplitPathToParts(fp.FilePath, pathParts);; 1212 bool include; 1213 if (!wildcardCensor.CheckPathVect(pathParts, !fp.IsDir, include)) 1214 continue; 1215 if (!include) 1216 continue; 1217 } 1218 } 1219 1220 CListStat st; 1221 1222 RINOK(GetUInt64Value(archive, i, kpidSize, st.Size)); 1223 RINOK(GetUInt64Value(archive, i, kpidPackSize, st.PackSize)); 1224 RINOK(GetItemMTime(archive, i, st.MTime)); 1225 1226 if (fp.IsDir) 1227 stat2.NumDirs++; 1228 else 1229 st.NumFiles = 1; 1230 stat2.GetStat(isAltStream).Update(st); 1231 1232 if (isAltStream && !showAltStreams) 1233 continue; 1234 RINOK(fp.PrintItemInfo(i, st)); 1235 } 1236 1237 UInt64 numStreams = stat2.GetNumStreams(); 1238 if (!stdInMode 1239 && !stat2.MainFiles.PackSize.Def 1240 && !stat2.AltStreams.PackSize.Def) 1241 { 1242 if (arcLink.VolumePaths.Size() != 0) 1243 arcPackSize += arcLink.VolumesSize; 1244 stat2.MainFiles.PackSize.Add((numStreams == 0) ? 0 : arcPackSize); 1245 } 1246 1247 stat2.MainFiles.SetSizeDefIfNoFiles(); 1248 stat2.AltStreams.SetSizeDefIfNoFiles(); 1249 1250 if (enableHeaders && !techMode) 1251 { 1252 fp.PrintTitleLines(); 1253 g_StdOut << endl; 1254 fp.PrintSum(stat2); 1255 } 1256 1257 if (enableHeaders) 1258 { 1259 if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0) 1260 { 1261 g_StdOut << "----------\n"; 1262 PrintPropPair(g_StdOut, "Path", arcLink.NonOpen_ArcPath); 1263 PrintArcTypeError(g_StdOut, codecs->Formats[arcLink.NonOpen_ErrorInfo.ErrorFormatIndex].Name, false); 1264 } 1265 } 1266 1267 stat2total.Update(stat2); 1268 1269 g_StdOut.Flush(); 1270 } 1271 1272 if (enableHeaders && !techMode && (arcPaths.Size() > 1 || numVolumes > 1)) 1273 { 1274 g_StdOut << endl; 1275 fp.PrintTitleLines(); 1276 g_StdOut << endl; 1277 fp.PrintSum(stat2total); 1278 g_StdOut << endl; 1279 PrintPropNameAndNumber(g_StdOut, "Archives", numArcs); 1280 PrintPropNameAndNumber(g_StdOut, "Volumes", numVolumes); 1281 PrintPropNameAndNumber(g_StdOut, "Total archives size", totalArcSizes); 1282 } 1283 1284 if (numErrors == 1 && lastError != 0) 1285 return lastError; 1286 1287 return S_OK; 1288 } 1289