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 29HINSTANCE 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} 35DEFINE_GUID(CLSID_CFormat7z, 36 0x23170F69, 0x40C1, 0x278A, 0x10, 0x00, 0x00, 0x01, 0x10, 0x07, 0x00, 0x00); 37 38using namespace NWindows; 39using namespace NFile; 40using namespace NDir; 41 42#define kDllName "7z.dll" 43 44static const char *kCopyrightString = "\n7-Zip " MY_VERSION 45" (" kDllName " client) " 46MY_COPYRIGHT " " MY_DATE "\n"; 47 48static 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 56static AString FStringToConsoleString(const FString &s) 57{ 58 return GetOemString(fs2us(s)); 59} 60 61static FString CmdStringToFString(const char *s) 62{ 63 return us2fs(GetUnicodeString(s)); 64} 65 66static void PrintString(const UString &s) 67{ 68 printf("%s", (LPCSTR)GetOemString(s)); 69} 70 71static void PrintString(const AString &s) 72{ 73 printf("%s", (LPCSTR)s); 74} 75 76static void PrintNewLine() 77{ 78 PrintString("\n"); 79} 80 81static void PrintStringLn(const AString &s) 82{ 83 PrintString(s); 84 PrintNewLine(); 85} 86 87static 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 95static void PrintError(const AString &s) 96{ 97 PrintNewLine(); 98 PrintString(s); 99 PrintNewLine(); 100} 101 102static 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 115static HRESULT IsArchiveItemFolder(IInArchive *archive, UInt32 index, bool &result) 116{ 117 return IsArchiveItemProp(archive, index, kpidIsDir, result); 118} 119 120 121static const wchar_t *kEmptyFileAlias = L"[Content]"; 122 123 124////////////////////////////////////////////////////////////// 125// Archive Open callback class 126 127 128class CArchiveOpenCallback: 129 public IArchiveOpenCallback, 130 public ICryptoGetTextPassword, 131 public CMyUnknownImp 132{ 133public: 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 147STDMETHODIMP CArchiveOpenCallback::SetTotal(const UInt64 * /* files */, const UInt64 * /* bytes */) 148{ 149 return S_OK; 150} 151 152STDMETHODIMP CArchiveOpenCallback::SetCompleted(const UInt64 * /* files */, const UInt64 * /* bytes */) 153{ 154 return S_OK; 155} 156 157STDMETHODIMP 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 174static const char *kTestingString = "Testing "; 175static const char *kExtractingString = "Extracting "; 176static const char *kSkippingString = "Skipping "; 177 178static const char *kUnsupportedMethod = "Unsupported Method"; 179static const char *kCRCFailed = "CRC Failed"; 180static const char *kDataError = "Data Error"; 181static const char *kUnavailableData = "Unavailable data"; 182static const char *kUnexpectedEnd = "Unexpected end of data"; 183static const char *kDataAfterEnd = "There are some data after the end of the payload data"; 184static const char *kIsNotArc = "Is not archive"; 185static const char *kHeadersError = "Headers Error"; 186 187class CArchiveExtractCallback: 188 public IArchiveExtractCallback, 189 public ICryptoGetTextPassword, 190 public CMyUnknownImp 191{ 192public: 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 207private: 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 225public: 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 235void CArchiveExtractCallback::Init(IInArchive *archiveHandler, const FString &directoryPath) 236{ 237 NumErrors = 0; 238 _archiveHandler = archiveHandler; 239 _directoryPath = directoryPath; 240 NName::NormalizeDirPathPrefix(_directoryPath); 241} 242 243STDMETHODIMP CArchiveExtractCallback::SetTotal(UInt64 /* size */) 244{ 245 return S_OK; 246} 247 248STDMETHODIMP CArchiveExtractCallback::SetCompleted(const UInt64 * /* completeValue */) 249{ 250 return S_OK; 251} 252 253STDMETHODIMP 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 366STDMETHODIMP 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 383STDMETHODIMP 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 450STDMETHODIMP 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 468struct 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 481class CArchiveUpdateCallback: 482 public IArchiveUpdateCallback2, 483 public ICryptoGetTextPassword2, 484 public CMyUnknownImp 485{ 486public: 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 505public: 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 536STDMETHODIMP CArchiveUpdateCallback::SetTotal(UInt64 /* size */) 537{ 538 return S_OK; 539} 540 541STDMETHODIMP CArchiveUpdateCallback::SetCompleted(const UInt64 * /* completeValue */) 542{ 543 return S_OK; 544} 545 546 547STDMETHODIMP CArchiveUpdateCallback::EnumProperties(IEnumSTATPROPSTG ** /* enumerator */) 548{ 549 return E_NOTIMPL; 550} 551 552STDMETHODIMP 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 564STDMETHODIMP 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 592HRESULT CArchiveUpdateCallback::Finilize() 593{ 594 if (m_NeedBeClosed) 595 { 596 PrintNewLine(); 597 m_NeedBeClosed = false; 598 } 599 return S_OK; 600} 601 602static void GetStream2(const wchar_t *name) 603{ 604 PrintString("Compressing "); 605 if (name[0] == 0) 606 name = kEmptyFileAlias; 607 PrintString(name); 608} 609 610STDMETHODIMP 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 643STDMETHODIMP CArchiveUpdateCallback::SetOperationResult(Int32 /* operationResult */) 644{ 645 m_NeedBeClosed = true; 646 return S_OK; 647} 648 649STDMETHODIMP 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 659STDMETHODIMP 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 678STDMETHODIMP 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 700int 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