Client7z.cpp revision baa3858d3f5d128a5c8466b700098109edcad5f2
1// Client7z.cpp 2 3#include "StdAfx.h" 4 5#include "Common/IntToString.h" 6#include "Common/MyInitGuid.h" 7#include "Common/StringConvert.h" 8 9#include "Windows/DLL.h" 10#include "Windows/FileDir.h" 11#include "Windows/FileFind.h" 12#include "Windows/FileName.h" 13#include "Windows/NtCheck.h" 14#include "Windows/PropVariant.h" 15#include "Windows/PropVariantConversions.h" 16 17#include "../../Common/FileStreams.h" 18 19#include "../../Archive/IArchive.h" 20 21#include "../../IPassword.h" 22#include "../../MyVersion.h" 23 24// use another CLSIDs, if you want to support other formats (zip, rar, ...). 25// {23170F69-40C1-278A-1000-000110070000} 26DEFINE_GUID(CLSID_CFormat7z, 27 0x23170F69, 0x40C1, 0x278A, 0x10, 0x00, 0x00, 0x01, 0x10, 0x07, 0x00, 0x00); 28 29using namespace NWindows; 30 31#define kDllName "7z.dll" 32 33static const char *kCopyrightString = MY_7ZIP_VERSION 34" (" kDllName " client) " 35MY_COPYRIGHT " " MY_DATE; 36 37static const char *kHelpString = 38"Usage: Client7z.exe [a | l | x ] archive.7z [fileName ...]\n" 39"Examples:\n" 40" Client7z.exe a archive.7z f1.txt f2.txt : compress two files to archive.7z\n" 41" Client7z.exe l archive.7z : List contents of archive.7z\n" 42" Client7z.exe x archive.7z : eXtract files from archive.7z\n"; 43 44 45typedef UINT32 (WINAPI * CreateObjectFunc)( 46 const GUID *clsID, 47 const GUID *interfaceID, 48 void **outObject); 49 50 51void PrintString(const UString &s) 52{ 53 printf("%s", (LPCSTR)GetOemString(s)); 54} 55 56void PrintString(const AString &s) 57{ 58 printf("%s", (LPCSTR)s); 59} 60 61void PrintNewLine() 62{ 63 PrintString("\n"); 64} 65 66void PrintStringLn(const AString &s) 67{ 68 PrintString(s); 69 PrintNewLine(); 70} 71 72void PrintError(const AString &s) 73{ 74 PrintNewLine(); 75 PrintString(s); 76 PrintNewLine(); 77} 78 79static HRESULT IsArchiveItemProp(IInArchive *archive, UInt32 index, PROPID propID, bool &result) 80{ 81 NCOM::CPropVariant prop; 82 RINOK(archive->GetProperty(index, propID, &prop)); 83 if (prop.vt == VT_BOOL) 84 result = VARIANT_BOOLToBool(prop.boolVal); 85 else if (prop.vt == VT_EMPTY) 86 result = false; 87 else 88 return E_FAIL; 89 return S_OK; 90} 91 92static HRESULT IsArchiveItemFolder(IInArchive *archive, UInt32 index, bool &result) 93{ 94 return IsArchiveItemProp(archive, index, kpidIsDir, result); 95} 96 97 98static const wchar_t *kEmptyFileAlias = L"[Content]"; 99 100 101////////////////////////////////////////////////////////////// 102// Archive Open callback class 103 104 105class CArchiveOpenCallback: 106 public IArchiveOpenCallback, 107 public ICryptoGetTextPassword, 108 public CMyUnknownImp 109{ 110public: 111 MY_UNKNOWN_IMP1(ICryptoGetTextPassword) 112 113 STDMETHOD(SetTotal)(const UInt64 *files, const UInt64 *bytes); 114 STDMETHOD(SetCompleted)(const UInt64 *files, const UInt64 *bytes); 115 116 STDMETHOD(CryptoGetTextPassword)(BSTR *password); 117 118 bool PasswordIsDefined; 119 UString Password; 120 121 CArchiveOpenCallback() : PasswordIsDefined(false) {} 122}; 123 124STDMETHODIMP CArchiveOpenCallback::SetTotal(const UInt64 * /* files */, const UInt64 * /* bytes */) 125{ 126 return S_OK; 127} 128 129STDMETHODIMP CArchiveOpenCallback::SetCompleted(const UInt64 * /* files */, const UInt64 * /* bytes */) 130{ 131 return S_OK; 132} 133 134STDMETHODIMP CArchiveOpenCallback::CryptoGetTextPassword(BSTR *password) 135{ 136 if (!PasswordIsDefined) 137 { 138 // You can ask real password here from user 139 // Password = GetPassword(OutStream); 140 // PasswordIsDefined = true; 141 PrintError("Password is not defined"); 142 return E_ABORT; 143 } 144 return StringToBstr(Password, password); 145} 146 147 148////////////////////////////////////////////////////////////// 149// Archive Extracting callback class 150 151static const wchar_t *kCantDeleteOutputFile = L"ERROR: Can not delete output file "; 152 153static const char *kTestingString = "Testing "; 154static const char *kExtractingString = "Extracting "; 155static const char *kSkippingString = "Skipping "; 156 157static const char *kUnsupportedMethod = "Unsupported Method"; 158static const char *kCRCFailed = "CRC Failed"; 159static const char *kDataError = "Data Error"; 160static const char *kUnknownError = "Unknown Error"; 161 162class CArchiveExtractCallback: 163 public IArchiveExtractCallback, 164 public ICryptoGetTextPassword, 165 public CMyUnknownImp 166{ 167public: 168 MY_UNKNOWN_IMP1(ICryptoGetTextPassword) 169 170 // IProgress 171 STDMETHOD(SetTotal)(UInt64 size); 172 STDMETHOD(SetCompleted)(const UInt64 *completeValue); 173 174 // IArchiveExtractCallback 175 STDMETHOD(GetStream)(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode); 176 STDMETHOD(PrepareOperation)(Int32 askExtractMode); 177 STDMETHOD(SetOperationResult)(Int32 resultEOperationResult); 178 179 // ICryptoGetTextPassword 180 STDMETHOD(CryptoGetTextPassword)(BSTR *aPassword); 181 182private: 183 CMyComPtr<IInArchive> _archiveHandler; 184 UString _directoryPath; // Output directory 185 UString _filePath; // name inside arcvhive 186 UString _diskFilePath; // full path to file on disk 187 bool _extractMode; 188 struct CProcessedFileInfo 189 { 190 FILETIME MTime; 191 UInt32 Attrib; 192 bool isDir; 193 bool AttribDefined; 194 bool MTimeDefined; 195 } _processedFileInfo; 196 197 COutFileStream *_outFileStreamSpec; 198 CMyComPtr<ISequentialOutStream> _outFileStream; 199 200public: 201 void Init(IInArchive *archiveHandler, const UString &directoryPath); 202 203 UInt64 NumErrors; 204 bool PasswordIsDefined; 205 UString Password; 206 207 CArchiveExtractCallback() : PasswordIsDefined(false) {} 208}; 209 210void CArchiveExtractCallback::Init(IInArchive *archiveHandler, const UString &directoryPath) 211{ 212 NumErrors = 0; 213 _archiveHandler = archiveHandler; 214 _directoryPath = directoryPath; 215 NFile::NName::NormalizeDirPathPrefix(_directoryPath); 216} 217 218STDMETHODIMP CArchiveExtractCallback::SetTotal(UInt64 /* size */) 219{ 220 return S_OK; 221} 222 223STDMETHODIMP CArchiveExtractCallback::SetCompleted(const UInt64 * /* completeValue */) 224{ 225 return S_OK; 226} 227 228STDMETHODIMP CArchiveExtractCallback::GetStream(UInt32 index, 229 ISequentialOutStream **outStream, Int32 askExtractMode) 230{ 231 *outStream = 0; 232 _outFileStream.Release(); 233 234 { 235 // Get Name 236 NCOM::CPropVariant prop; 237 RINOK(_archiveHandler->GetProperty(index, kpidPath, &prop)); 238 239 UString fullPath; 240 if (prop.vt == VT_EMPTY) 241 fullPath = kEmptyFileAlias; 242 else 243 { 244 if (prop.vt != VT_BSTR) 245 return E_FAIL; 246 fullPath = prop.bstrVal; 247 } 248 _filePath = fullPath; 249 } 250 251 if (askExtractMode != NArchive::NExtract::NAskMode::kExtract) 252 return S_OK; 253 254 { 255 // Get Attrib 256 NCOM::CPropVariant prop; 257 RINOK(_archiveHandler->GetProperty(index, kpidAttrib, &prop)); 258 if (prop.vt == VT_EMPTY) 259 { 260 _processedFileInfo.Attrib = 0; 261 _processedFileInfo.AttribDefined = false; 262 } 263 else 264 { 265 if (prop.vt != VT_UI4) 266 return E_FAIL; 267 _processedFileInfo.Attrib = prop.ulVal; 268 _processedFileInfo.AttribDefined = true; 269 } 270 } 271 272 RINOK(IsArchiveItemFolder(_archiveHandler, index, _processedFileInfo.isDir)); 273 274 { 275 // Get Modified Time 276 NCOM::CPropVariant prop; 277 RINOK(_archiveHandler->GetProperty(index, kpidMTime, &prop)); 278 _processedFileInfo.MTimeDefined = false; 279 switch(prop.vt) 280 { 281 case VT_EMPTY: 282 // _processedFileInfo.MTime = _utcMTimeDefault; 283 break; 284 case VT_FILETIME: 285 _processedFileInfo.MTime = prop.filetime; 286 _processedFileInfo.MTimeDefined = true; 287 break; 288 default: 289 return E_FAIL; 290 } 291 292 } 293 { 294 // Get Size 295 NCOM::CPropVariant prop; 296 RINOK(_archiveHandler->GetProperty(index, kpidSize, &prop)); 297 bool newFileSizeDefined = (prop.vt != VT_EMPTY); 298 UInt64 newFileSize; 299 if (newFileSizeDefined) 300 newFileSize = ConvertPropVariantToUInt64(prop); 301 } 302 303 304 { 305 // Create folders for file 306 int slashPos = _filePath.ReverseFind(WCHAR_PATH_SEPARATOR); 307 if (slashPos >= 0) 308 NFile::NDirectory::CreateComplexDirectory(_directoryPath + _filePath.Left(slashPos)); 309 } 310 311 UString fullProcessedPath = _directoryPath + _filePath; 312 _diskFilePath = fullProcessedPath; 313 314 if (_processedFileInfo.isDir) 315 { 316 NFile::NDirectory::CreateComplexDirectory(fullProcessedPath); 317 } 318 else 319 { 320 NFile::NFind::CFileInfoW fi; 321 if (fi.Find(fullProcessedPath)) 322 { 323 if (!NFile::NDirectory::DeleteFileAlways(fullProcessedPath)) 324 { 325 PrintString(UString(kCantDeleteOutputFile) + fullProcessedPath); 326 return E_ABORT; 327 } 328 } 329 330 _outFileStreamSpec = new COutFileStream; 331 CMyComPtr<ISequentialOutStream> outStreamLoc(_outFileStreamSpec); 332 if (!_outFileStreamSpec->Open(fullProcessedPath, CREATE_ALWAYS)) 333 { 334 PrintString((UString)L"can not open output file " + fullProcessedPath); 335 return E_ABORT; 336 } 337 _outFileStream = outStreamLoc; 338 *outStream = outStreamLoc.Detach(); 339 } 340 return S_OK; 341} 342 343STDMETHODIMP CArchiveExtractCallback::PrepareOperation(Int32 askExtractMode) 344{ 345 _extractMode = false; 346 switch (askExtractMode) 347 { 348 case NArchive::NExtract::NAskMode::kExtract: _extractMode = true; break; 349 }; 350 switch (askExtractMode) 351 { 352 case NArchive::NExtract::NAskMode::kExtract: PrintString(kExtractingString); break; 353 case NArchive::NExtract::NAskMode::kTest: PrintString(kTestingString); break; 354 case NArchive::NExtract::NAskMode::kSkip: PrintString(kSkippingString); break; 355 }; 356 PrintString(_filePath); 357 return S_OK; 358} 359 360STDMETHODIMP CArchiveExtractCallback::SetOperationResult(Int32 operationResult) 361{ 362 switch(operationResult) 363 { 364 case NArchive::NExtract::NOperationResult::kOK: 365 break; 366 default: 367 { 368 NumErrors++; 369 PrintString(" "); 370 switch(operationResult) 371 { 372 case NArchive::NExtract::NOperationResult::kUnSupportedMethod: 373 PrintString(kUnsupportedMethod); 374 break; 375 case NArchive::NExtract::NOperationResult::kCRCError: 376 PrintString(kCRCFailed); 377 break; 378 case NArchive::NExtract::NOperationResult::kDataError: 379 PrintString(kDataError); 380 break; 381 default: 382 PrintString(kUnknownError); 383 } 384 } 385 } 386 387 if (_outFileStream != NULL) 388 { 389 if (_processedFileInfo.MTimeDefined) 390 _outFileStreamSpec->SetMTime(&_processedFileInfo.MTime); 391 RINOK(_outFileStreamSpec->Close()); 392 } 393 _outFileStream.Release(); 394 if (_extractMode && _processedFileInfo.AttribDefined) 395 NFile::NDirectory::MySetFileAttributes(_diskFilePath, _processedFileInfo.Attrib); 396 PrintNewLine(); 397 return S_OK; 398} 399 400 401STDMETHODIMP CArchiveExtractCallback::CryptoGetTextPassword(BSTR *password) 402{ 403 if (!PasswordIsDefined) 404 { 405 // You can ask real password here from user 406 // Password = GetPassword(OutStream); 407 // PasswordIsDefined = true; 408 PrintError("Password is not defined"); 409 return E_ABORT; 410 } 411 return StringToBstr(Password, password); 412} 413 414 415 416////////////////////////////////////////////////////////////// 417// Archive Creating callback class 418 419struct CDirItem 420{ 421 UInt64 Size; 422 FILETIME CTime; 423 FILETIME ATime; 424 FILETIME MTime; 425 UString Name; 426 UString FullPath; 427 UInt32 Attrib; 428 429 bool isDir() const { return (Attrib & FILE_ATTRIBUTE_DIRECTORY) != 0 ; } 430}; 431 432class CArchiveUpdateCallback: 433 public IArchiveUpdateCallback2, 434 public ICryptoGetTextPassword2, 435 public CMyUnknownImp 436{ 437public: 438 MY_UNKNOWN_IMP2(IArchiveUpdateCallback2, ICryptoGetTextPassword2) 439 440 // IProgress 441 STDMETHOD(SetTotal)(UInt64 size); 442 STDMETHOD(SetCompleted)(const UInt64 *completeValue); 443 444 // IUpdateCallback2 445 STDMETHOD(EnumProperties)(IEnumSTATPROPSTG **enumerator); 446 STDMETHOD(GetUpdateItemInfo)(UInt32 index, 447 Int32 *newData, Int32 *newProperties, UInt32 *indexInArchive); 448 STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value); 449 STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **inStream); 450 STDMETHOD(SetOperationResult)(Int32 operationResult); 451 STDMETHOD(GetVolumeSize)(UInt32 index, UInt64 *size); 452 STDMETHOD(GetVolumeStream)(UInt32 index, ISequentialOutStream **volumeStream); 453 454 STDMETHOD(CryptoGetTextPassword2)(Int32 *passwordIsDefined, BSTR *password); 455 456public: 457 CRecordVector<UInt64> VolumesSizes; 458 UString VolName; 459 UString VolExt; 460 461 UString DirPrefix; 462 const CObjectVector<CDirItem> *DirItems; 463 464 bool PasswordIsDefined; 465 UString Password; 466 bool AskPassword; 467 468 bool m_NeedBeClosed; 469 470 UStringVector FailedFiles; 471 CRecordVector<HRESULT> FailedCodes; 472 473 CArchiveUpdateCallback(): PasswordIsDefined(false), AskPassword(false), DirItems(0) {}; 474 475 ~CArchiveUpdateCallback() { Finilize(); } 476 HRESULT Finilize(); 477 478 void Init(const CObjectVector<CDirItem> *dirItems) 479 { 480 DirItems = dirItems; 481 m_NeedBeClosed = false; 482 FailedFiles.Clear(); 483 FailedCodes.Clear(); 484 } 485}; 486 487STDMETHODIMP CArchiveUpdateCallback::SetTotal(UInt64 /* size */) 488{ 489 return S_OK; 490} 491 492STDMETHODIMP CArchiveUpdateCallback::SetCompleted(const UInt64 * /* completeValue */) 493{ 494 return S_OK; 495} 496 497 498STDMETHODIMP CArchiveUpdateCallback::EnumProperties(IEnumSTATPROPSTG ** /* enumerator */) 499{ 500 return E_NOTIMPL; 501} 502 503STDMETHODIMP CArchiveUpdateCallback::GetUpdateItemInfo(UInt32 /* index */, 504 Int32 *newData, Int32 *newProperties, UInt32 *indexInArchive) 505{ 506 if (newData != NULL) 507 *newData = BoolToInt(true); 508 if (newProperties != NULL) 509 *newProperties = BoolToInt(true); 510 if (indexInArchive != NULL) 511 *indexInArchive = (UInt32)-1; 512 return S_OK; 513} 514 515STDMETHODIMP CArchiveUpdateCallback::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) 516{ 517 NWindows::NCOM::CPropVariant prop; 518 519 if (propID == kpidIsAnti) 520 { 521 prop = false; 522 prop.Detach(value); 523 return S_OK; 524 } 525 526 { 527 const CDirItem &dirItem = (*DirItems)[index]; 528 switch(propID) 529 { 530 case kpidPath: prop = dirItem.Name; break; 531 case kpidIsDir: prop = dirItem.isDir(); break; 532 case kpidSize: prop = dirItem.Size; break; 533 case kpidAttrib: prop = dirItem.Attrib; break; 534 case kpidCTime: prop = dirItem.CTime; break; 535 case kpidATime: prop = dirItem.ATime; break; 536 case kpidMTime: prop = dirItem.MTime; break; 537 } 538 } 539 prop.Detach(value); 540 return S_OK; 541} 542 543HRESULT CArchiveUpdateCallback::Finilize() 544{ 545 if (m_NeedBeClosed) 546 { 547 PrintNewLine(); 548 m_NeedBeClosed = false; 549 } 550 return S_OK; 551} 552 553static void GetStream2(const wchar_t *name) 554{ 555 PrintString("Compressing "); 556 if (name[0] == 0) 557 name = kEmptyFileAlias; 558 PrintString(name); 559} 560 561STDMETHODIMP CArchiveUpdateCallback::GetStream(UInt32 index, ISequentialInStream **inStream) 562{ 563 RINOK(Finilize()); 564 565 const CDirItem &dirItem = (*DirItems)[index]; 566 GetStream2(dirItem.Name); 567 568 if (dirItem.isDir()) 569 return S_OK; 570 571 { 572 CInFileStream *inStreamSpec = new CInFileStream; 573 CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec); 574 UString path = DirPrefix + dirItem.FullPath; 575 if (!inStreamSpec->Open(path)) 576 { 577 DWORD sysError = ::GetLastError(); 578 FailedCodes.Add(sysError); 579 FailedFiles.Add(path); 580 // if (systemError == ERROR_SHARING_VIOLATION) 581 { 582 PrintNewLine(); 583 PrintError("WARNING: can't open file"); 584 // PrintString(NError::MyFormatMessageW(systemError)); 585 return S_FALSE; 586 } 587 // return sysError; 588 } 589 *inStream = inStreamLoc.Detach(); 590 } 591 return S_OK; 592} 593 594STDMETHODIMP CArchiveUpdateCallback::SetOperationResult(Int32 /* operationResult */) 595{ 596 m_NeedBeClosed = true; 597 return S_OK; 598} 599 600STDMETHODIMP CArchiveUpdateCallback::GetVolumeSize(UInt32 index, UInt64 *size) 601{ 602 if (VolumesSizes.Size() == 0) 603 return S_FALSE; 604 if (index >= (UInt32)VolumesSizes.Size()) 605 index = VolumesSizes.Size() - 1; 606 *size = VolumesSizes[index]; 607 return S_OK; 608} 609 610STDMETHODIMP CArchiveUpdateCallback::GetVolumeStream(UInt32 index, ISequentialOutStream **volumeStream) 611{ 612 wchar_t temp[16]; 613 ConvertUInt32ToString(index + 1, temp); 614 UString res = temp; 615 while (res.Length() < 2) 616 res = UString(L'0') + res; 617 UString fileName = VolName; 618 fileName += L'.'; 619 fileName += res; 620 fileName += VolExt; 621 COutFileStream *streamSpec = new COutFileStream; 622 CMyComPtr<ISequentialOutStream> streamLoc(streamSpec); 623 if (!streamSpec->Create(fileName, false)) 624 return ::GetLastError(); 625 *volumeStream = streamLoc.Detach(); 626 return S_OK; 627} 628 629STDMETHODIMP CArchiveUpdateCallback::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password) 630{ 631 if (!PasswordIsDefined) 632 { 633 if (AskPassword) 634 { 635 // You can ask real password here from user 636 // Password = GetPassword(OutStream); 637 // PasswordIsDefined = true; 638 PrintError("Password is not defined"); 639 return E_ABORT; 640 } 641 } 642 *passwordIsDefined = BoolToInt(PasswordIsDefined); 643 return StringToBstr(Password, password); 644} 645 646 647 648////////////////////////////////////////////////////////////////////////// 649// Main function 650 651#define NT_CHECK_FAIL_ACTION PrintError("Unsupported Windows version"); return 1; 652 653int MY_CDECL main(int numArgs, const char *args[]) 654{ 655 NT_CHECK 656 657 PrintStringLn(kCopyrightString); 658 659 if (numArgs < 3) 660 { 661 PrintStringLn(kHelpString); 662 return 1; 663 } 664 NWindows::NDLL::CLibrary lib; 665 if (!lib.Load(TEXT(kDllName))) 666 { 667 PrintError("Can not load 7-zip library"); 668 return 1; 669 } 670 CreateObjectFunc createObjectFunc = (CreateObjectFunc)lib.GetProc("CreateObject"); 671 if (createObjectFunc == 0) 672 { 673 PrintError("Can not get CreateObject"); 674 return 1; 675 } 676 677 char c; 678 { 679 AString command = args[1]; 680 if (command.Length() != 1) 681 { 682 PrintError("incorrect command"); 683 return 1; 684 } 685 c = MyCharLower(command[0]); 686 } 687 UString archiveName = GetUnicodeString(args[2]); 688 if (c == 'a') 689 { 690 // create archive command 691 if (numArgs < 4) 692 { 693 PrintStringLn(kHelpString); 694 return 1; 695 } 696 CObjectVector<CDirItem> dirItems; 697 int i; 698 for (i = 3; i < numArgs; i++) 699 { 700 CDirItem di; 701 UString name = GetUnicodeString(args[i]); 702 703 NFile::NFind::CFileInfoW fi; 704 if (!fi.Find(name)) 705 { 706 PrintString(UString(L"Can't find file") + name); 707 return 1; 708 } 709 710 di.Attrib = fi.Attrib; 711 di.Size = fi.Size; 712 di.CTime = fi.CTime; 713 di.ATime = fi.ATime; 714 di.MTime = fi.MTime; 715 di.Name = name; 716 di.FullPath = name; 717 dirItems.Add(di); 718 } 719 COutFileStream *outFileStreamSpec = new COutFileStream; 720 CMyComPtr<IOutStream> outFileStream = outFileStreamSpec; 721 if (!outFileStreamSpec->Create(archiveName, false)) 722 { 723 PrintError("can't create archive file"); 724 return 1; 725 } 726 727 CMyComPtr<IOutArchive> outArchive; 728 if (createObjectFunc(&CLSID_CFormat7z, &IID_IOutArchive, (void **)&outArchive) != S_OK) 729 { 730 PrintError("Can not get class object"); 731 return 1; 732 } 733 734 CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback; 735 CMyComPtr<IArchiveUpdateCallback2> updateCallback(updateCallbackSpec); 736 updateCallbackSpec->Init(&dirItems); 737 // updateCallbackSpec->PasswordIsDefined = true; 738 // updateCallbackSpec->Password = L"1"; 739 740 /* 741 { 742 const wchar_t *names[] = 743 { 744 L"s", 745 L"x" 746 }; 747 const int kNumProps = sizeof(names) / sizeof(names[0]); 748 NWindows::NCOM::CPropVariant values[kNumProps] = 749 { 750 false, // solid mode OFF 751 (UInt32)9 // compression level = 9 - ultra 752 }; 753 CMyComPtr<ISetProperties> setProperties; 754 outArchive->QueryInterface(IID_ISetProperties, (void **)&setProperties); 755 if (!setProperties) 756 { 757 PrintError("ISetProperties unsupported"); 758 return 1; 759 } 760 RINOK(setProperties->SetProperties(names, values, kNumProps)); 761 } 762 */ 763 764 HRESULT result = outArchive->UpdateItems(outFileStream, dirItems.Size(), updateCallback); 765 updateCallbackSpec->Finilize(); 766 if (result != S_OK) 767 { 768 PrintError("Update Error"); 769 return 1; 770 } 771 for (i = 0; i < updateCallbackSpec->FailedFiles.Size(); i++) 772 { 773 PrintNewLine(); 774 PrintString((UString)L"Error for file: " + updateCallbackSpec->FailedFiles[i]); 775 } 776 if (updateCallbackSpec->FailedFiles.Size() != 0) 777 return 1; 778 } 779 else 780 { 781 if (numArgs != 3) 782 { 783 PrintStringLn(kHelpString); 784 return 1; 785 } 786 787 bool listCommand; 788 if (c == 'l') 789 listCommand = true; 790 else if (c == 'x') 791 listCommand = false; 792 else 793 { 794 PrintError("incorrect command"); 795 return 1; 796 } 797 798 CMyComPtr<IInArchive> archive; 799 if (createObjectFunc(&CLSID_CFormat7z, &IID_IInArchive, (void **)&archive) != S_OK) 800 { 801 PrintError("Can not get class object"); 802 return 1; 803 } 804 805 CInFileStream *fileSpec = new CInFileStream; 806 CMyComPtr<IInStream> file = fileSpec; 807 808 if (!fileSpec->Open(archiveName)) 809 { 810 PrintError("Can not open archive file"); 811 return 1; 812 } 813 814 { 815 CArchiveOpenCallback *openCallbackSpec = new CArchiveOpenCallback; 816 CMyComPtr<IArchiveOpenCallback> openCallback(openCallbackSpec); 817 openCallbackSpec->PasswordIsDefined = false; 818 // openCallbackSpec->PasswordIsDefined = true; 819 // openCallbackSpec->Password = L"1"; 820 821 if (archive->Open(file, 0, openCallback) != S_OK) 822 { 823 PrintError("Can not open archive"); 824 return 1; 825 } 826 } 827 828 if (listCommand) 829 { 830 // List command 831 UInt32 numItems = 0; 832 archive->GetNumberOfItems(&numItems); 833 for (UInt32 i = 0; i < numItems; i++) 834 { 835 { 836 // Get uncompressed size of file 837 NWindows::NCOM::CPropVariant prop; 838 archive->GetProperty(i, kpidSize, &prop); 839 UString s = ConvertPropVariantToString(prop); 840 PrintString(s); 841 PrintString(" "); 842 } 843 { 844 // Get name of file 845 NWindows::NCOM::CPropVariant prop; 846 archive->GetProperty(i, kpidPath, &prop); 847 UString s = ConvertPropVariantToString(prop); 848 PrintString(s); 849 } 850 PrintString("\n"); 851 } 852 } 853 else 854 { 855 // Extract command 856 CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback; 857 CMyComPtr<IArchiveExtractCallback> extractCallback(extractCallbackSpec); 858 extractCallbackSpec->Init(archive, L""); // second parameter is output folder path 859 extractCallbackSpec->PasswordIsDefined = false; 860 // extractCallbackSpec->PasswordIsDefined = true; 861 // extractCallbackSpec->Password = L"1"; 862 HRESULT result = archive->Extract(NULL, (UInt32)(Int32)(-1), false, extractCallback); 863 if (result != S_OK) 864 { 865 PrintError("Extract Error"); 866 return 1; 867 } 868 } 869 } 870 return 0; 871} 872