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