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} 26 DEFINE_GUID(CLSID_CFormat7z, 27 0x23170F69, 0x40C1, 0x278A, 0x10, 0x00, 0x00, 0x01, 0x10, 0x07, 0x00, 0x00); 28 29 using namespace NWindows; 30 31 #define kDllName "7z.dll" 32 33 static const char *kCopyrightString = MY_7ZIP_VERSION 34 " (" kDllName " client) " 35 MY_COPYRIGHT " " MY_DATE; 36 37 static 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 45 typedef UINT32 (WINAPI * CreateObjectFunc)( 46 const GUID *clsID, 47 const GUID *interfaceID, 48 void **outObject); 49 50 51 void PrintString(const UString &s) 52 { 53 printf("%s", (LPCSTR)GetOemString(s)); 54 } 55 56 void PrintString(const AString &s) 57 { 58 printf("%s", (LPCSTR)s); 59 } 60 61 void PrintNewLine() 62 { 63 PrintString("\n"); 64 } 65 66 void PrintStringLn(const AString &s) 67 { 68 PrintString(s); 69 PrintNewLine(); 70 } 71 72 void PrintError(const AString &s) 73 { 74 PrintNewLine(); 75 PrintString(s); 76 PrintNewLine(); 77 } 78 79 static 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 92 static HRESULT IsArchiveItemFolder(IInArchive *archive, UInt32 index, bool &result) 93 { 94 return IsArchiveItemProp(archive, index, kpidIsDir, result); 95 } 96 97 98 static const wchar_t *kEmptyFileAlias = L"[Content]"; 99 100 101 ////////////////////////////////////////////////////////////// 102 // Archive Open callback class 103 104 105 class CArchiveOpenCallback: 106 public IArchiveOpenCallback, 107 public ICryptoGetTextPassword, 108 public CMyUnknownImp 109 { 110 public: 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 124 STDMETHODIMP CArchiveOpenCallback::SetTotal(const UInt64 * /* files */, const UInt64 * /* bytes */) 125 { 126 return S_OK; 127 } 128 129 STDMETHODIMP CArchiveOpenCallback::SetCompleted(const UInt64 * /* files */, const UInt64 * /* bytes */) 130 { 131 return S_OK; 132 } 133 134 STDMETHODIMP 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 151 static const wchar_t *kCantDeleteOutputFile = L"ERROR: Can not delete output file "; 152 153 static const char *kTestingString = "Testing "; 154 static const char *kExtractingString = "Extracting "; 155 static const char *kSkippingString = "Skipping "; 156 157 static const char *kUnsupportedMethod = "Unsupported Method"; 158 static const char *kCRCFailed = "CRC Failed"; 159 static const char *kDataError = "Data Error"; 160 static const char *kUnknownError = "Unknown Error"; 161 162 class CArchiveExtractCallback: 163 public IArchiveExtractCallback, 164 public ICryptoGetTextPassword, 165 public CMyUnknownImp 166 { 167 public: 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 182 private: 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 200 public: 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 210 void CArchiveExtractCallback::Init(IInArchive *archiveHandler, const UString &directoryPath) 211 { 212 NumErrors = 0; 213 _archiveHandler = archiveHandler; 214 _directoryPath = directoryPath; 215 NFile::NName::NormalizeDirPathPrefix(_directoryPath); 216 } 217 218 STDMETHODIMP CArchiveExtractCallback::SetTotal(UInt64 /* size */) 219 { 220 return S_OK; 221 } 222 223 STDMETHODIMP CArchiveExtractCallback::SetCompleted(const UInt64 * /* completeValue */) 224 { 225 return S_OK; 226 } 227 228 STDMETHODIMP 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 343 STDMETHODIMP 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 360 STDMETHODIMP 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 401 STDMETHODIMP 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 419 struct 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 432 class CArchiveUpdateCallback: 433 public IArchiveUpdateCallback2, 434 public ICryptoGetTextPassword2, 435 public CMyUnknownImp 436 { 437 public: 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 456 public: 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 487 STDMETHODIMP CArchiveUpdateCallback::SetTotal(UInt64 /* size */) 488 { 489 return S_OK; 490 } 491 492 STDMETHODIMP CArchiveUpdateCallback::SetCompleted(const UInt64 * /* completeValue */) 493 { 494 return S_OK; 495 } 496 497 498 STDMETHODIMP CArchiveUpdateCallback::EnumProperties(IEnumSTATPROPSTG ** /* enumerator */) 499 { 500 return E_NOTIMPL; 501 } 502 503 STDMETHODIMP 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 515 STDMETHODIMP 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 543 HRESULT CArchiveUpdateCallback::Finilize() 544 { 545 if (m_NeedBeClosed) 546 { 547 PrintNewLine(); 548 m_NeedBeClosed = false; 549 } 550 return S_OK; 551 } 552 553 static void GetStream2(const wchar_t *name) 554 { 555 PrintString("Compressing "); 556 if (name[0] == 0) 557 name = kEmptyFileAlias; 558 PrintString(name); 559 } 560 561 STDMETHODIMP 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 594 STDMETHODIMP CArchiveUpdateCallback::SetOperationResult(Int32 /* operationResult */) 595 { 596 m_NeedBeClosed = true; 597 return S_OK; 598 } 599 600 STDMETHODIMP 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 610 STDMETHODIMP 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 629 STDMETHODIMP 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 653 int 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