OLD | NEW |
| (Empty) |
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/PropVariant.h" | |
14 #include "Windows/PropVariantConversions.h" | |
15 | |
16 #include "../../Common/FileStreams.h" | |
17 | |
18 #include "../../Archive/IArchive.h" | |
19 | |
20 #include "../../IPassword.h" | |
21 #include "../../MyVersion.h" | |
22 | |
23 // use another CLSIDs, if you want to support other formats (zip, rar, ...). | |
24 // {23170F69-40C1-278A-1000-000110070000} | |
25 DEFINE_GUID(CLSID_CFormat7z, | |
26 0x23170F69, 0x40C1, 0x278A, 0x10, 0x00, 0x00, 0x01, 0x10, 0x07, 0x00, 0x00); | |
27 | |
28 using namespace NWindows; | |
29 | |
30 #define kDllName "7z.dll" | |
31 | |
32 static const char *kCopyrightString = MY_7ZIP_VERSION | |
33 " (" kDllName " client) " | |
34 MY_COPYRIGHT " " MY_DATE; | |
35 | |
36 static const char *kHelpString = | |
37 "Usage: Client7z.exe [a | l | x ] archive.7z [fileName ...]\n" | |
38 "Examples:\n" | |
39 " Client7z.exe a archive.7z f1.txt f2.txt : compress two files to archive.7z\n
" | |
40 " Client7z.exe l archive.7z : List contents of archive.7z\n" | |
41 " Client7z.exe x archive.7z : eXtract files from archive.7z\n"; | |
42 | |
43 | |
44 typedef UINT32 (WINAPI * CreateObjectFunc)( | |
45 const GUID *clsID, | |
46 const GUID *interfaceID, | |
47 void **outObject); | |
48 | |
49 #ifdef _WIN32 | |
50 #ifndef _UNICODE | |
51 bool g_IsNT = false; | |
52 static inline bool IsItWindowsNT() | |
53 { | |
54 OSVERSIONINFO versionInfo; | |
55 versionInfo.dwOSVersionInfoSize = sizeof(versionInfo); | |
56 if (!::GetVersionEx(&versionInfo)) | |
57 return false; | |
58 return (versionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT); | |
59 } | |
60 #endif | |
61 #endif | |
62 | |
63 void PrintString(const UString &s) | |
64 { | |
65 printf("%s", (LPCSTR)GetOemString(s)); | |
66 } | |
67 | |
68 void PrintString(const AString &s) | |
69 { | |
70 printf("%s", (LPCSTR)s); | |
71 } | |
72 | |
73 void PrintNewLine() | |
74 { | |
75 PrintString("\n"); | |
76 } | |
77 | |
78 void PrintStringLn(const AString &s) | |
79 { | |
80 PrintString(s); | |
81 PrintNewLine(); | |
82 } | |
83 | |
84 void PrintError(const AString &s) | |
85 { | |
86 PrintNewLine(); | |
87 PrintString(s); | |
88 PrintNewLine(); | |
89 } | |
90 | |
91 static HRESULT IsArchiveItemProp(IInArchive *archive, UInt32 index, PROPID propI
D, bool &result) | |
92 { | |
93 NCOM::CPropVariant prop; | |
94 RINOK(archive->GetProperty(index, propID, &prop)); | |
95 if (prop.vt == VT_BOOL) | |
96 result = VARIANT_BOOLToBool(prop.boolVal); | |
97 else if (prop.vt == VT_EMPTY) | |
98 result = false; | |
99 else | |
100 return E_FAIL; | |
101 return S_OK; | |
102 } | |
103 | |
104 static HRESULT IsArchiveItemFolder(IInArchive *archive, UInt32 index, bool &resu
lt) | |
105 { | |
106 return IsArchiveItemProp(archive, index, kpidIsDir, result); | |
107 } | |
108 | |
109 | |
110 static const wchar_t *kEmptyFileAlias = L"[Content]"; | |
111 | |
112 | |
113 ////////////////////////////////////////////////////////////// | |
114 // Archive Open callback class | |
115 | |
116 | |
117 class CArchiveOpenCallback: | |
118 public IArchiveOpenCallback, | |
119 public ICryptoGetTextPassword, | |
120 public CMyUnknownImp | |
121 { | |
122 public: | |
123 MY_UNKNOWN_IMP1(ICryptoGetTextPassword) | |
124 | |
125 STDMETHOD(SetTotal)(const UInt64 *files, const UInt64 *bytes); | |
126 STDMETHOD(SetCompleted)(const UInt64 *files, const UInt64 *bytes); | |
127 | |
128 STDMETHOD(CryptoGetTextPassword)(BSTR *password); | |
129 | |
130 bool PasswordIsDefined; | |
131 UString Password; | |
132 | |
133 CArchiveOpenCallback() : PasswordIsDefined(false) {} | |
134 }; | |
135 | |
136 STDMETHODIMP CArchiveOpenCallback::SetTotal(const UInt64 * /* files */, const UI
nt64 * /* bytes */) | |
137 { | |
138 return S_OK; | |
139 } | |
140 | |
141 STDMETHODIMP CArchiveOpenCallback::SetCompleted(const UInt64 * /* files */, cons
t UInt64 * /* bytes */) | |
142 { | |
143 return S_OK; | |
144 } | |
145 | |
146 STDMETHODIMP CArchiveOpenCallback::CryptoGetTextPassword(BSTR *password) | |
147 { | |
148 if (!PasswordIsDefined) | |
149 { | |
150 // You can ask real password here from user | |
151 // Password = GetPassword(OutStream); | |
152 // PasswordIsDefined = true; | |
153 PrintError("Password is not defined"); | |
154 return E_ABORT; | |
155 } | |
156 return StringToBstr(Password, password); | |
157 } | |
158 | |
159 | |
160 ////////////////////////////////////////////////////////////// | |
161 // Archive Extracting callback class | |
162 | |
163 static const wchar_t *kCantDeleteOutputFile = L"ERROR: Can not delete output fil
e "; | |
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 ask
ExtractMode); | |
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 MTime; | |
203 UInt32 Attrib; | |
204 bool isDir; | |
205 bool AttribDefined; | |
206 bool MTimeDefined; | |
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 &di
rectoryPath) | |
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 * /* completeVal
ue */) | |
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 prop; | |
249 RINOK(_archiveHandler->GetProperty(index, kpidPath, &prop)); | |
250 | |
251 UString fullPath; | |
252 if (prop.vt == VT_EMPTY) | |
253 fullPath = kEmptyFileAlias; | |
254 else | |
255 { | |
256 if (prop.vt != VT_BSTR) | |
257 return E_FAIL; | |
258 fullPath = prop.bstrVal; | |
259 } | |
260 _filePath = fullPath; | |
261 } | |
262 | |
263 if (askExtractMode != NArchive::NExtract::NAskMode::kExtract) | |
264 return S_OK; | |
265 | |
266 { | |
267 // Get Attrib | |
268 NCOM::CPropVariant prop; | |
269 RINOK(_archiveHandler->GetProperty(index, kpidAttrib, &prop)); | |
270 if (prop.vt == VT_EMPTY) | |
271 { | |
272 _processedFileInfo.Attrib = 0; | |
273 _processedFileInfo.AttribDefined = false; | |
274 } | |
275 else | |
276 { | |
277 if (prop.vt != VT_UI4) | |
278 return E_FAIL; | |
279 _processedFileInfo.Attrib = prop.ulVal; | |
280 _processedFileInfo.AttribDefined = true; | |
281 } | |
282 } | |
283 | |
284 RINOK(IsArchiveItemFolder(_archiveHandler, index, _processedFileInfo.isDir)); | |
285 | |
286 { | |
287 // Get Modified Time | |
288 NCOM::CPropVariant prop; | |
289 RINOK(_archiveHandler->GetProperty(index, kpidMTime, &prop)); | |
290 _processedFileInfo.MTimeDefined = false; | |
291 switch(prop.vt) | |
292 { | |
293 case VT_EMPTY: | |
294 // _processedFileInfo.MTime = _utcMTimeDefault; | |
295 break; | |
296 case VT_FILETIME: | |
297 _processedFileInfo.MTime = prop.filetime; | |
298 _processedFileInfo.MTimeDefined = true; | |
299 break; | |
300 default: | |
301 return E_FAIL; | |
302 } | |
303 | |
304 } | |
305 { | |
306 // Get Size | |
307 NCOM::CPropVariant prop; | |
308 RINOK(_archiveHandler->GetProperty(index, kpidSize, &prop)); | |
309 bool newFileSizeDefined = (prop.vt != VT_EMPTY); | |
310 UInt64 newFileSize; | |
311 if (newFileSizeDefined) | |
312 newFileSize = ConvertPropVariantToUInt64(prop); | |
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.isDir) | |
327 { | |
328 NFile::NDirectory::CreateComplexDirectory(fullProcessedPath); | |
329 } | |
330 else | |
331 { | |
332 NFile::NFind::CFileInfoW fi; | |
333 if (NFile::NFind::FindFile(fullProcessedPath, fi)) | |
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: _extractMode = true; break; | |
361 }; | |
362 switch (askExtractMode) | |
363 { | |
364 case NArchive::NExtract::NAskMode::kExtract: PrintString(kExtractingString)
; break; | |
365 case NArchive::NExtract::NAskMode::kTest: PrintString(kTestingString); brea
k; | |
366 case NArchive::NExtract::NAskMode::kSkip: PrintString(kSkippingString); bre
ak; | |
367 }; | |
368 PrintString(_filePath); | |
369 return S_OK; | |
370 } | |
371 | |
372 STDMETHODIMP CArchiveExtractCallback::SetOperationResult(Int32 operationResult) | |
373 { | |
374 switch(operationResult) | |
375 { | |
376 case NArchive::NExtract::NOperationResult::kOK: | |
377 break; | |
378 default: | |
379 { | |
380 NumErrors++; | |
381 PrintString(" "); | |
382 switch(operationResult) | |
383 { | |
384 case NArchive::NExtract::NOperationResult::kUnSupportedMethod: | |
385 PrintString(kUnsupportedMethod); | |
386 break; | |
387 case NArchive::NExtract::NOperationResult::kCRCError: | |
388 PrintString(kCRCFailed); | |
389 break; | |
390 case NArchive::NExtract::NOperationResult::kDataError: | |
391 PrintString(kDataError); | |
392 break; | |
393 default: | |
394 PrintString(kUnknownError); | |
395 } | |
396 } | |
397 } | |
398 | |
399 if (_outFileStream != NULL) | |
400 { | |
401 if (_processedFileInfo.MTimeDefined) | |
402 _outFileStreamSpec->SetMTime(&_processedFileInfo.MTime); | |
403 RINOK(_outFileStreamSpec->Close()); | |
404 } | |
405 _outFileStream.Release(); | |
406 if (_extractMode && _processedFileInfo.AttribDefined) | |
407 NFile::NDirectory::MySetFileAttributes(_diskFilePath, _processedFileInfo.Att
rib); | |
408 PrintNewLine(); | |
409 return S_OK; | |
410 } | |
411 | |
412 | |
413 STDMETHODIMP CArchiveExtractCallback::CryptoGetTextPassword(BSTR *password) | |
414 { | |
415 if (!PasswordIsDefined) | |
416 { | |
417 // You can ask real password here from user | |
418 // Password = GetPassword(OutStream); | |
419 // PasswordIsDefined = true; | |
420 PrintError("Password is not defined"); | |
421 return E_ABORT; | |
422 } | |
423 return StringToBstr(Password, password); | |
424 } | |
425 | |
426 | |
427 | |
428 ////////////////////////////////////////////////////////////// | |
429 // Archive Creating callback class | |
430 | |
431 struct CDirItem | |
432 { | |
433 UInt64 Size; | |
434 FILETIME CTime; | |
435 FILETIME ATime; | |
436 FILETIME MTime; | |
437 UString Name; | |
438 UString FullPath; | |
439 UInt32 Attrib; | |
440 | |
441 bool isDir() const { return (Attrib & FILE_ATTRIBUTE_DIRECTORY) != 0 ; } | |
442 }; | |
443 | |
444 class CArchiveUpdateCallback: | |
445 public IArchiveUpdateCallback2, | |
446 public ICryptoGetTextPassword2, | |
447 public CMyUnknownImp | |
448 { | |
449 public: | |
450 MY_UNKNOWN_IMP2(IArchiveUpdateCallback2, ICryptoGetTextPassword2) | |
451 | |
452 // IProgress | |
453 STDMETHOD(SetTotal)(UInt64 size); | |
454 STDMETHOD(SetCompleted)(const UInt64 *completeValue); | |
455 | |
456 // IUpdateCallback2 | |
457 STDMETHOD(EnumProperties)(IEnumSTATPROPSTG **enumerator); | |
458 STDMETHOD(GetUpdateItemInfo)(UInt32 index, | |
459 Int32 *newData, Int32 *newProperties, UInt32 *indexInArchive); | |
460 STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value); | |
461 STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **inStream); | |
462 STDMETHOD(SetOperationResult)(Int32 operationResult); | |
463 STDMETHOD(GetVolumeSize)(UInt32 index, UInt64 *size); | |
464 STDMETHOD(GetVolumeStream)(UInt32 index, ISequentialOutStream **volumeStream); | |
465 | |
466 STDMETHOD(CryptoGetTextPassword2)(Int32 *passwordIsDefined, BSTR *password); | |
467 | |
468 public: | |
469 CRecordVector<UInt64> VolumesSizes; | |
470 UString VolName; | |
471 UString VolExt; | |
472 | |
473 UString DirPrefix; | |
474 const CObjectVector<CDirItem> *DirItems; | |
475 | |
476 bool PasswordIsDefined; | |
477 UString Password; | |
478 bool AskPassword; | |
479 | |
480 bool m_NeedBeClosed; | |
481 | |
482 UStringVector FailedFiles; | |
483 CRecordVector<HRESULT> FailedCodes; | |
484 | |
485 CArchiveUpdateCallback(): PasswordIsDefined(false), AskPassword(false), DirIte
ms(0) {}; | |
486 | |
487 ~CArchiveUpdateCallback() { Finilize(); } | |
488 HRESULT Finilize(); | |
489 | |
490 void Init(const CObjectVector<CDirItem> *dirItems) | |
491 { | |
492 DirItems = dirItems; | |
493 m_NeedBeClosed = false; | |
494 FailedFiles.Clear(); | |
495 FailedCodes.Clear(); | |
496 } | |
497 }; | |
498 | |
499 STDMETHODIMP CArchiveUpdateCallback::SetTotal(UInt64 /* size */) | |
500 { | |
501 return S_OK; | |
502 } | |
503 | |
504 STDMETHODIMP CArchiveUpdateCallback::SetCompleted(const UInt64 * /* completeValu
e */) | |
505 { | |
506 return S_OK; | |
507 } | |
508 | |
509 | |
510 STDMETHODIMP CArchiveUpdateCallback::EnumProperties(IEnumSTATPROPSTG ** /* enume
rator */) | |
511 { | |
512 return E_NOTIMPL; | |
513 } | |
514 | |
515 STDMETHODIMP CArchiveUpdateCallback::GetUpdateItemInfo(UInt32 /* index */, | |
516 Int32 *newData, Int32 *newProperties, UInt32 *indexInArchive) | |
517 { | |
518 if (newData != NULL) | |
519 *newData = BoolToInt(true); | |
520 if (newProperties != NULL) | |
521 *newProperties = BoolToInt(true); | |
522 if (indexInArchive != NULL) | |
523 *indexInArchive = (UInt32)-1; | |
524 return S_OK; | |
525 } | |
526 | |
527 STDMETHODIMP CArchiveUpdateCallback::GetProperty(UInt32 index, PROPID propID, PR
OPVARIANT *value) | |
528 { | |
529 NWindows::NCOM::CPropVariant prop; | |
530 | |
531 if (propID == kpidIsAnti) | |
532 { | |
533 prop = false; | |
534 prop.Detach(value); | |
535 return S_OK; | |
536 } | |
537 | |
538 { | |
539 const CDirItem &dirItem = (*DirItems)[index]; | |
540 switch(propID) | |
541 { | |
542 case kpidPath: prop = dirItem.Name; break; | |
543 case kpidIsDir: prop = dirItem.isDir(); break; | |
544 case kpidSize: prop = dirItem.Size; break; | |
545 case kpidAttrib: prop = dirItem.Attrib; break; | |
546 case kpidCTime: prop = dirItem.CTime; break; | |
547 case kpidATime: prop = dirItem.ATime; break; | |
548 case kpidMTime: prop = dirItem.MTime; break; | |
549 } | |
550 } | |
551 prop.Detach(value); | |
552 return S_OK; | |
553 } | |
554 | |
555 HRESULT CArchiveUpdateCallback::Finilize() | |
556 { | |
557 if (m_NeedBeClosed) | |
558 { | |
559 PrintNewLine(); | |
560 m_NeedBeClosed = false; | |
561 } | |
562 return S_OK; | |
563 } | |
564 | |
565 static void GetStream2(const wchar_t *name) | |
566 { | |
567 PrintString("Compressing "); | |
568 if (name[0] == 0) | |
569 name = kEmptyFileAlias; | |
570 PrintString(name); | |
571 } | |
572 | |
573 STDMETHODIMP CArchiveUpdateCallback::GetStream(UInt32 index, ISequentialInStream
**inStream) | |
574 { | |
575 RINOK(Finilize()); | |
576 | |
577 const CDirItem &dirItem = (*DirItems)[index]; | |
578 GetStream2(dirItem.Name); | |
579 | |
580 if (dirItem.isDir()) | |
581 return S_OK; | |
582 | |
583 { | |
584 CInFileStream *inStreamSpec = new CInFileStream; | |
585 CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec); | |
586 UString path = DirPrefix + dirItem.FullPath; | |
587 if (!inStreamSpec->Open(path)) | |
588 { | |
589 DWORD sysError = ::GetLastError(); | |
590 FailedCodes.Add(sysError); | |
591 FailedFiles.Add(path); | |
592 // if (systemError == ERROR_SHARING_VIOLATION) | |
593 { | |
594 PrintNewLine(); | |
595 PrintError("WARNING: can't open file"); | |
596 // PrintString(NError::MyFormatMessageW(systemError)); | |
597 return S_FALSE; | |
598 } | |
599 // return sysError; | |
600 } | |
601 *inStream = inStreamLoc.Detach(); | |
602 } | |
603 return S_OK; | |
604 } | |
605 | |
606 STDMETHODIMP CArchiveUpdateCallback::SetOperationResult(Int32 /* operationResult
*/) | |
607 { | |
608 m_NeedBeClosed = true; | |
609 return S_OK; | |
610 } | |
611 | |
612 STDMETHODIMP CArchiveUpdateCallback::GetVolumeSize(UInt32 index, UInt64 *size) | |
613 { | |
614 if (VolumesSizes.Size() == 0) | |
615 return S_FALSE; | |
616 if (index >= (UInt32)VolumesSizes.Size()) | |
617 index = VolumesSizes.Size() - 1; | |
618 *size = VolumesSizes[index]; | |
619 return S_OK; | |
620 } | |
621 | |
622 STDMETHODIMP CArchiveUpdateCallback::GetVolumeStream(UInt32 index, ISequentialOu
tStream **volumeStream) | |
623 { | |
624 wchar_t temp[32]; | |
625 ConvertUInt64ToString(index + 1, temp); | |
626 UString res = temp; | |
627 while (res.Length() < 2) | |
628 res = UString(L'0') + res; | |
629 UString fileName = VolName; | |
630 fileName += L'.'; | |
631 fileName += res; | |
632 fileName += VolExt; | |
633 COutFileStream *streamSpec = new COutFileStream; | |
634 CMyComPtr<ISequentialOutStream> streamLoc(streamSpec); | |
635 if (!streamSpec->Create(fileName, false)) | |
636 return ::GetLastError(); | |
637 *volumeStream = streamLoc.Detach(); | |
638 return S_OK; | |
639 } | |
640 | |
641 STDMETHODIMP CArchiveUpdateCallback::CryptoGetTextPassword2(Int32 *passwordIsDef
ined, BSTR *password) | |
642 { | |
643 if (!PasswordIsDefined) | |
644 { | |
645 if (AskPassword) | |
646 { | |
647 // You can ask real password here from user | |
648 // Password = GetPassword(OutStream); | |
649 // PasswordIsDefined = true; | |
650 PrintError("Password is not defined"); | |
651 return E_ABORT; | |
652 } | |
653 } | |
654 *passwordIsDefined = BoolToInt(PasswordIsDefined); | |
655 return StringToBstr(Password, password); | |
656 } | |
657 | |
658 | |
659 | |
660 ////////////////////////////////////////////////////////////////////////// | |
661 // Main function | |
662 | |
663 int MY_CDECL main(int argc, char* argv[]) | |
664 { | |
665 #ifdef _WIN32 | |
666 #ifndef _UNICODE | |
667 g_IsNT = IsItWindowsNT(); | |
668 #endif | |
669 #endif | |
670 | |
671 PrintStringLn(kCopyrightString); | |
672 | |
673 if (argc < 3) | |
674 { | |
675 PrintStringLn(kHelpString); | |
676 return 1; | |
677 } | |
678 NWindows::NDLL::CLibrary library; | |
679 if (!library.Load(TEXT(kDllName))) | |
680 { | |
681 PrintError("Can not load library"); | |
682 return 1; | |
683 } | |
684 CreateObjectFunc createObjectFunc = (CreateObjectFunc)library.GetProcAddress("
CreateObject"); | |
685 if (createObjectFunc == 0) | |
686 { | |
687 PrintError("Can not get CreateObject"); | |
688 return 1; | |
689 } | |
690 | |
691 AString command = argv[1]; | |
692 command.MakeLower(); | |
693 UString archiveName = GetUnicodeString(argv[2], CP_OEMCP); | |
694 if (command.Compare("a") == 0) | |
695 { | |
696 // create archive command | |
697 if (argc < 4) | |
698 { | |
699 PrintStringLn(kHelpString); | |
700 return 1; | |
701 } | |
702 CObjectVector<CDirItem> dirItems; | |
703 int i; | |
704 for (i = 3; i < argc; i++) | |
705 { | |
706 CDirItem di; | |
707 UString name = GetUnicodeString(argv[i], CP_OEMCP); | |
708 | |
709 NFile::NFind::CFileInfoW fi; | |
710 if (!NFile::NFind::FindFile(name, fi)) | |
711 { | |
712 PrintString(UString(L"Can't find file") + name); | |
713 return 1; | |
714 } | |
715 | |
716 di.Attrib = fi.Attrib; | |
717 di.Size = fi.Size; | |
718 di.CTime = fi.CTime; | |
719 di.ATime = fi.ATime; | |
720 di.MTime = fi.MTime; | |
721 di.Name = name; | |
722 di.FullPath = name; | |
723 dirItems.Add(di); | |
724 } | |
725 COutFileStream *outFileStreamSpec = new COutFileStream; | |
726 CMyComPtr<IOutStream> outFileStream = outFileStreamSpec; | |
727 if (!outFileStreamSpec->Create(archiveName, false)) | |
728 { | |
729 PrintError("can't create archive file"); | |
730 return 1; | |
731 } | |
732 | |
733 CMyComPtr<IOutArchive> outArchive; | |
734 if (createObjectFunc(&CLSID_CFormat7z, &IID_IOutArchive, (void **)&outArchiv
e) != S_OK) | |
735 { | |
736 PrintError("Can not get class object"); | |
737 return 1; | |
738 } | |
739 | |
740 CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback; | |
741 CMyComPtr<IArchiveUpdateCallback2> updateCallback(updateCallbackSpec); | |
742 updateCallbackSpec->Init(&dirItems); | |
743 // updateCallbackSpec->PasswordIsDefined = true; | |
744 // updateCallbackSpec->Password = L"1"; | |
745 | |
746 HRESULT result = outArchive->UpdateItems(outFileStream, dirItems.Size(), upd
ateCallback); | |
747 updateCallbackSpec->Finilize(); | |
748 if (result != S_OK) | |
749 { | |
750 PrintError("Update Error"); | |
751 return 1; | |
752 } | |
753 for (i = 0; i < updateCallbackSpec->FailedFiles.Size(); i++) | |
754 { | |
755 PrintNewLine(); | |
756 PrintString((UString)L"Error for file: " + updateCallbackSpec->FailedFiles
[i]); | |
757 } | |
758 if (updateCallbackSpec->FailedFiles.Size() != 0) | |
759 return 1; | |
760 } | |
761 else | |
762 { | |
763 if (argc != 3) | |
764 { | |
765 PrintStringLn(kHelpString); | |
766 return 1; | |
767 } | |
768 | |
769 bool listCommand; | |
770 if (command.Compare("l") == 0) | |
771 listCommand = true; | |
772 else if (command.Compare("x") == 0) | |
773 listCommand = false; | |
774 else | |
775 { | |
776 PrintError("incorrect command"); | |
777 return 1; | |
778 } | |
779 | |
780 CMyComPtr<IInArchive> archive; | |
781 if (createObjectFunc(&CLSID_CFormat7z, &IID_IInArchive, (void **)&archive) !
= S_OK) | |
782 { | |
783 PrintError("Can not get class object"); | |
784 return 1; | |
785 } | |
786 | |
787 CInFileStream *fileSpec = new CInFileStream; | |
788 CMyComPtr<IInStream> file = fileSpec; | |
789 | |
790 if (!fileSpec->Open(archiveName)) | |
791 { | |
792 PrintError("Can not open archive file"); | |
793 return 1; | |
794 } | |
795 | |
796 { | |
797 CArchiveOpenCallback *openCallbackSpec = new CArchiveOpenCallback; | |
798 CMyComPtr<IArchiveOpenCallback> openCallback(openCallbackSpec); | |
799 openCallbackSpec->PasswordIsDefined = false; | |
800 // openCallbackSpec->PasswordIsDefined = true; | |
801 // openCallbackSpec->Password = L"1"; | |
802 | |
803 if (archive->Open(file, 0, openCallback) != S_OK) | |
804 { | |
805 PrintError("Can not open archive"); | |
806 return 1; | |
807 } | |
808 } | |
809 | |
810 if (listCommand) | |
811 { | |
812 // List command | |
813 UInt32 numItems = 0; | |
814 archive->GetNumberOfItems(&numItems); | |
815 for (UInt32 i = 0; i < numItems; i++) | |
816 { | |
817 { | |
818 // Get uncompressed size of file | |
819 NWindows::NCOM::CPropVariant prop; | |
820 archive->GetProperty(i, kpidSize, &prop); | |
821 UString s = ConvertPropVariantToString(prop); | |
822 PrintString(s); | |
823 PrintString(" "); | |
824 } | |
825 { | |
826 // Get name of file | |
827 NWindows::NCOM::CPropVariant prop; | |
828 archive->GetProperty(i, kpidPath, &prop); | |
829 UString s = ConvertPropVariantToString(prop); | |
830 PrintString(s); | |
831 } | |
832 PrintString("\n"); | |
833 } | |
834 } | |
835 else | |
836 { | |
837 // Extract command | |
838 CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback
; | |
839 CMyComPtr<IArchiveExtractCallback> extractCallback(extractCallbackSpec); | |
840 extractCallbackSpec->Init(archive, L""); // second parameter is output fol
der path | |
841 extractCallbackSpec->PasswordIsDefined = false; | |
842 // extractCallbackSpec->PasswordIsDefined = true; | |
843 // extractCallbackSpec->Password = L"1"; | |
844 HRESULT result = archive->Extract(NULL, (UInt32)(Int32)(-1), false, extrac
tCallback); | |
845 if (result != S_OK) | |
846 { | |
847 PrintError("Extract Error"); | |
848 return 1; | |
849 } | |
850 } | |
851 } | |
852 return 0; | |
853 } | |
OLD | NEW |