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