1 // Client7z.cpp
2
3 #include "StdAfx.h"
4
5 #include <stdio.h>
6
7 #include "../../../Common/MyWindows.h"
8 #include "../../../Common/MyInitGuid.h"
9
10 #include "../../../Common/Defs.h"
11 #include "../../../Common/IntToString.h"
12 #include "../../../Common/StringConvert.h"
13
14 #include "../../../Windows/DLL.h"
15 #include "../../../Windows/FileDir.h"
16 #include "../../../Windows/FileFind.h"
17 #include "../../../Windows/FileName.h"
18 #include "../../../Windows/NtCheck.h"
19 #include "../../../Windows/PropVariant.h"
20 #include "../../../Windows/PropVariantConv.h"
21
22 #include "../../Common/FileStreams.h"
23
24 #include "../../Archive/IArchive.h"
25
26 #include "../../IPassword.h"
27 #include "../../../../C/7zVersion.h"
28
29 #ifdef _WIN32
30 extern
31 HINSTANCE g_hInstance;
32 HINSTANCE g_hInstance = NULL;
33 #endif
34
35 // You can find full list of all GUIDs supported by 7-Zip in Guid.txt file.
36 // 7z format GUID: {23170F69-40C1-278A-1000-000110070000}
37
38 #define DEFINE_GUID_ARC(name, id) Z7_DEFINE_GUID(name, \
39 0x23170F69, 0x40C1, 0x278A, 0x10, 0x00, 0x00, 0x01, 0x10, id, 0x00, 0x00);
40
41 enum
42 {
43 kId_Zip = 1,
44 kId_BZip2 = 2,
45 kId_7z = 7,
46 kId_Xz = 0xC,
47 kId_Tar = 0xEE,
48 kId_GZip = 0xEF
49 };
50
51 // use another id, if you want to support other formats (zip, Xz, ...).
52 // DEFINE_GUID_ARC (CLSID_Format, kId_Zip)
53 // DEFINE_GUID_ARC (CLSID_Format, kId_BZip2)
54 // DEFINE_GUID_ARC (CLSID_Format, kId_Xz)
55 // DEFINE_GUID_ARC (CLSID_Format, kId_Tar)
56 // DEFINE_GUID_ARC (CLSID_Format, kId_GZip)
57 DEFINE_GUID_ARC (CLSID_Format, kId_7z)
58
59 using namespace NWindows;
60 using namespace NFile;
61 using namespace NDir;
62
63 #ifdef _WIN32
64 #define kDllName "7z.dll"
65 #else
66 #define kDllName "7z.so"
67 #endif
68
69 static const char * const kCopyrightString =
70 "\n"
71 "7-Zip"
72 " (" kDllName " client)"
73 " " MY_VERSION
74 " : " MY_COPYRIGHT_DATE
75 "\n";
76
77 static const char * const kHelpString =
78 "Usage: 7zcl.exe [a | l | x] archive.7z [fileName ...]\n"
79 "Examples:\n"
80 " 7zcl.exe a archive.7z f1.txt f2.txt : compress two files to archive.7z\n"
81 " 7zcl.exe l archive.7z : List contents of archive.7z\n"
82 " 7zcl.exe x archive.7z : eXtract files from archive.7z\n";
83
84
Convert_UString_to_AString(const UString & s,AString & temp)85 static void Convert_UString_to_AString(const UString &s, AString &temp)
86 {
87 int codePage = CP_OEMCP;
88 /*
89 int g_CodePage = -1;
90 int codePage = g_CodePage;
91 if (codePage == -1)
92 codePage = CP_OEMCP;
93 if (codePage == CP_UTF8)
94 ConvertUnicodeToUTF8(s, temp);
95 else
96 */
97 UnicodeStringToMultiByte2(temp, s, (UINT)codePage);
98 }
99
CmdStringToFString(const char * s)100 static FString CmdStringToFString(const char *s)
101 {
102 return us2fs(GetUnicodeString(s));
103 }
104
Print(const char * s)105 static void Print(const char *s)
106 {
107 fputs(s, stdout);
108 }
109
Print(const AString & s)110 static void Print(const AString &s)
111 {
112 Print(s.Ptr());
113 }
114
Print(const UString & s)115 static void Print(const UString &s)
116 {
117 AString as;
118 Convert_UString_to_AString(s, as);
119 Print(as);
120 }
121
Print(const wchar_t * s)122 static void Print(const wchar_t *s)
123 {
124 Print(UString(s));
125 }
126
PrintNewLine()127 static void PrintNewLine()
128 {
129 Print("\n");
130 }
131
PrintStringLn(const char * s)132 static void PrintStringLn(const char *s)
133 {
134 Print(s);
135 PrintNewLine();
136 }
137
PrintError(const char * message)138 static void PrintError(const char *message)
139 {
140 Print("Error: ");
141 PrintNewLine();
142 Print(message);
143 PrintNewLine();
144 }
145
PrintError(const char * message,const FString & name)146 static void PrintError(const char *message, const FString &name)
147 {
148 PrintError(message);
149 Print(name);
150 }
151
152
IsArchiveItemProp(IInArchive * archive,UInt32 index,PROPID propID,bool & result)153 static HRESULT IsArchiveItemProp(IInArchive *archive, UInt32 index, PROPID propID, bool &result)
154 {
155 NCOM::CPropVariant prop;
156 RINOK(archive->GetProperty(index, propID, &prop))
157 if (prop.vt == VT_BOOL)
158 result = VARIANT_BOOLToBool(prop.boolVal);
159 else if (prop.vt == VT_EMPTY)
160 result = false;
161 else
162 return E_FAIL;
163 return S_OK;
164 }
165
IsArchiveItemFolder(IInArchive * archive,UInt32 index,bool & result)166 static HRESULT IsArchiveItemFolder(IInArchive *archive, UInt32 index, bool &result)
167 {
168 return IsArchiveItemProp(archive, index, kpidIsDir, result);
169 }
170
171
172 static const wchar_t * const kEmptyFileAlias = L"[Content]";
173
174
175 //////////////////////////////////////////////////////////////
176 // Archive Open callback class
177
178
179 class CArchiveOpenCallback Z7_final:
180 public IArchiveOpenCallback,
181 public ICryptoGetTextPassword,
182 public CMyUnknownImp
183 {
184 Z7_IFACES_IMP_UNK_2(IArchiveOpenCallback, ICryptoGetTextPassword)
185 public:
186
187 bool PasswordIsDefined;
188 UString Password;
189
CArchiveOpenCallback()190 CArchiveOpenCallback() : PasswordIsDefined(false) {}
191 };
192
Z7_COM7F_IMF(CArchiveOpenCallback::SetTotal (const UInt64 *,const UInt64 *))193 Z7_COM7F_IMF(CArchiveOpenCallback::SetTotal(const UInt64 * /* files */, const UInt64 * /* bytes */))
194 {
195 return S_OK;
196 }
197
Z7_COM7F_IMF(CArchiveOpenCallback::SetCompleted (const UInt64 *,const UInt64 *))198 Z7_COM7F_IMF(CArchiveOpenCallback::SetCompleted(const UInt64 * /* files */, const UInt64 * /* bytes */))
199 {
200 return S_OK;
201 }
202
Z7_COM7F_IMF(CArchiveOpenCallback::CryptoGetTextPassword (BSTR * password))203 Z7_COM7F_IMF(CArchiveOpenCallback::CryptoGetTextPassword(BSTR *password))
204 {
205 if (!PasswordIsDefined)
206 {
207 // You can ask real password here from user
208 // Password = GetPassword(OutStream);
209 // PasswordIsDefined = true;
210 PrintError("Password is not defined");
211 return E_ABORT;
212 }
213 return StringToBstr(Password, password);
214 }
215
216
217
218 static const char * const kIncorrectCommand = "incorrect command";
219
220 //////////////////////////////////////////////////////////////
221 // Archive Extracting callback class
222
223 static const char * const kTestingString = "Testing ";
224 static const char * const kExtractingString = "Extracting ";
225 static const char * const kSkippingString = "Skipping ";
226 static const char * const kReadingString = "Reading ";
227
228 static const char * const kUnsupportedMethod = "Unsupported Method";
229 static const char * const kCRCFailed = "CRC Failed";
230 static const char * const kDataError = "Data Error";
231 static const char * const kUnavailableData = "Unavailable data";
232 static const char * const kUnexpectedEnd = "Unexpected end of data";
233 static const char * const kDataAfterEnd = "There are some data after the end of the payload data";
234 static const char * const kIsNotArc = "Is not archive";
235 static const char * const kHeadersError = "Headers Error";
236
237
238 struct CArcTime
239 {
240 FILETIME FT;
241 UInt16 Prec;
242 Byte Ns100;
243 bool Def;
244
CArcTimeCArcTime245 CArcTime()
246 {
247 Clear();
248 }
249
ClearCArcTime250 void Clear()
251 {
252 FT.dwHighDateTime = FT.dwLowDateTime = 0;
253 Prec = 0;
254 Ns100 = 0;
255 Def = false;
256 }
257
IsZeroCArcTime258 bool IsZero() const
259 {
260 return FT.dwLowDateTime == 0 && FT.dwHighDateTime == 0 && Ns100 == 0;
261 }
262
GetNumDigitsCArcTime263 int GetNumDigits() const
264 {
265 if (Prec == k_PropVar_TimePrec_Unix ||
266 Prec == k_PropVar_TimePrec_DOS)
267 return 0;
268 if (Prec == k_PropVar_TimePrec_HighPrec)
269 return 9;
270 if (Prec == k_PropVar_TimePrec_0)
271 return 7;
272 int digits = (int)Prec - (int)k_PropVar_TimePrec_Base;
273 if (digits < 0)
274 digits = 0;
275 return digits;
276 }
277
Write_To_FiTimeCArcTime278 void Write_To_FiTime(CFiTime &dest) const
279 {
280 #ifdef _WIN32
281 dest = FT;
282 #else
283 if (FILETIME_To_timespec(FT, dest))
284 if ((Prec == k_PropVar_TimePrec_Base + 8 ||
285 Prec == k_PropVar_TimePrec_Base + 9)
286 && Ns100 != 0)
287 {
288 dest.tv_nsec += Ns100;
289 }
290 #endif
291 }
292
Set_From_PropCArcTime293 void Set_From_Prop(const PROPVARIANT &prop)
294 {
295 FT = prop.filetime;
296 unsigned prec = 0;
297 unsigned ns100 = 0;
298 const unsigned prec_Temp = prop.wReserved1;
299 if (prec_Temp != 0
300 && prec_Temp <= k_PropVar_TimePrec_1ns
301 && prop.wReserved3 == 0)
302 {
303 const unsigned ns100_Temp = prop.wReserved2;
304 if (ns100_Temp < 100)
305 {
306 ns100 = ns100_Temp;
307 prec = prec_Temp;
308 }
309 }
310 Prec = (UInt16)prec;
311 Ns100 = (Byte)ns100;
312 Def = true;
313 }
314 };
315
316
317
318 class CArchiveExtractCallback Z7_final:
319 public IArchiveExtractCallback,
320 public ICryptoGetTextPassword,
321 public CMyUnknownImp
322 {
323 Z7_IFACES_IMP_UNK_2(IArchiveExtractCallback, ICryptoGetTextPassword)
324 Z7_IFACE_COM7_IMP(IProgress)
325
326 CMyComPtr<IInArchive> _archiveHandler;
327 FString _directoryPath; // Output directory
328 UString _filePath; // name inside arcvhive
329 FString _diskFilePath; // full path to file on disk
330 bool _extractMode;
331 struct CProcessedFileInfo
332 {
333 CArcTime MTime;
334 UInt32 Attrib;
335 bool isDir;
336 bool Attrib_Defined;
337 } _processedFileInfo;
338
339 COutFileStream *_outFileStreamSpec;
340 CMyComPtr<ISequentialOutStream> _outFileStream;
341
342 public:
343 void Init(IInArchive *archiveHandler, const FString &directoryPath);
344
345 UInt64 NumErrors;
346 bool PasswordIsDefined;
347 UString Password;
348
CArchiveExtractCallback()349 CArchiveExtractCallback() : PasswordIsDefined(false) {}
350 };
351
Init(IInArchive * archiveHandler,const FString & directoryPath)352 void CArchiveExtractCallback::Init(IInArchive *archiveHandler, const FString &directoryPath)
353 {
354 NumErrors = 0;
355 _archiveHandler = archiveHandler;
356 _directoryPath = directoryPath;
357 NName::NormalizeDirPathPrefix(_directoryPath);
358 }
359
Z7_COM7F_IMF(CArchiveExtractCallback::SetTotal (UInt64))360 Z7_COM7F_IMF(CArchiveExtractCallback::SetTotal(UInt64 /* size */))
361 {
362 return S_OK;
363 }
364
Z7_COM7F_IMF(CArchiveExtractCallback::SetCompleted (const UInt64 *))365 Z7_COM7F_IMF(CArchiveExtractCallback::SetCompleted(const UInt64 * /* completeValue */))
366 {
367 return S_OK;
368 }
369
Z7_COM7F_IMF(CArchiveExtractCallback::GetStream (UInt32 index,ISequentialOutStream ** outStream,Int32 askExtractMode))370 Z7_COM7F_IMF(CArchiveExtractCallback::GetStream(UInt32 index,
371 ISequentialOutStream **outStream, Int32 askExtractMode))
372 {
373 *outStream = NULL;
374 _outFileStream.Release();
375
376 {
377 // Get Name
378 NCOM::CPropVariant prop;
379 RINOK(_archiveHandler->GetProperty(index, kpidPath, &prop))
380
381 UString fullPath;
382 if (prop.vt == VT_EMPTY)
383 fullPath = kEmptyFileAlias;
384 else
385 {
386 if (prop.vt != VT_BSTR)
387 return E_FAIL;
388 fullPath = prop.bstrVal;
389 }
390 _filePath = fullPath;
391 }
392
393 if (askExtractMode != NArchive::NExtract::NAskMode::kExtract)
394 return S_OK;
395
396 {
397 // Get Attrib
398 NCOM::CPropVariant prop;
399 RINOK(_archiveHandler->GetProperty(index, kpidAttrib, &prop))
400 if (prop.vt == VT_EMPTY)
401 {
402 _processedFileInfo.Attrib = 0;
403 _processedFileInfo.Attrib_Defined = false;
404 }
405 else
406 {
407 if (prop.vt != VT_UI4)
408 return E_FAIL;
409 _processedFileInfo.Attrib = prop.ulVal;
410 _processedFileInfo.Attrib_Defined = true;
411 }
412 }
413
414 RINOK(IsArchiveItemFolder(_archiveHandler, index, _processedFileInfo.isDir))
415
416 {
417 _processedFileInfo.MTime.Clear();
418 // Get Modified Time
419 NCOM::CPropVariant prop;
420 RINOK(_archiveHandler->GetProperty(index, kpidMTime, &prop))
421 switch (prop.vt)
422 {
423 case VT_EMPTY:
424 // _processedFileInfo.MTime = _utcMTimeDefault;
425 break;
426 case VT_FILETIME:
427 _processedFileInfo.MTime.Set_From_Prop(prop);
428 break;
429 default:
430 return E_FAIL;
431 }
432
433 }
434 {
435 // Get Size
436 NCOM::CPropVariant prop;
437 RINOK(_archiveHandler->GetProperty(index, kpidSize, &prop))
438 UInt64 newFileSize;
439 /* bool newFileSizeDefined = */ ConvertPropVariantToUInt64(prop, newFileSize);
440 }
441
442
443 {
444 // Create folders for file
445 int slashPos = _filePath.ReverseFind_PathSepar();
446 if (slashPos >= 0)
447 CreateComplexDir(_directoryPath + us2fs(_filePath.Left(slashPos)));
448 }
449
450 FString fullProcessedPath = _directoryPath + us2fs(_filePath);
451 _diskFilePath = fullProcessedPath;
452
453 if (_processedFileInfo.isDir)
454 {
455 CreateComplexDir(fullProcessedPath);
456 }
457 else
458 {
459 NFind::CFileInfo fi;
460 if (fi.Find(fullProcessedPath))
461 {
462 if (!DeleteFileAlways(fullProcessedPath))
463 {
464 PrintError("Cannot delete output file", fullProcessedPath);
465 return E_ABORT;
466 }
467 }
468
469 _outFileStreamSpec = new COutFileStream;
470 CMyComPtr<ISequentialOutStream> outStreamLoc(_outFileStreamSpec);
471 if (!_outFileStreamSpec->Open(fullProcessedPath, CREATE_ALWAYS))
472 {
473 PrintError("Cannot open output file", fullProcessedPath);
474 return E_ABORT;
475 }
476 _outFileStream = outStreamLoc;
477 *outStream = outStreamLoc.Detach();
478 }
479 return S_OK;
480 }
481
Z7_COM7F_IMF(CArchiveExtractCallback::PrepareOperation (Int32 askExtractMode))482 Z7_COM7F_IMF(CArchiveExtractCallback::PrepareOperation(Int32 askExtractMode))
483 {
484 _extractMode = false;
485 switch (askExtractMode)
486 {
487 case NArchive::NExtract::NAskMode::kExtract: _extractMode = true; break;
488 }
489 switch (askExtractMode)
490 {
491 case NArchive::NExtract::NAskMode::kExtract: Print(kExtractingString); break;
492 case NArchive::NExtract::NAskMode::kTest: Print(kTestingString); break;
493 case NArchive::NExtract::NAskMode::kSkip: Print(kSkippingString); break;
494 case NArchive::NExtract::NAskMode::kReadExternal: Print(kReadingString); break;
495 default:
496 Print("??? "); break;
497 }
498 Print(_filePath);
499 return S_OK;
500 }
501
Z7_COM7F_IMF(CArchiveExtractCallback::SetOperationResult (Int32 operationResult))502 Z7_COM7F_IMF(CArchiveExtractCallback::SetOperationResult(Int32 operationResult))
503 {
504 switch (operationResult)
505 {
506 case NArchive::NExtract::NOperationResult::kOK:
507 break;
508 default:
509 {
510 NumErrors++;
511 Print(" : ");
512 const char *s = NULL;
513 switch (operationResult)
514 {
515 case NArchive::NExtract::NOperationResult::kUnsupportedMethod:
516 s = kUnsupportedMethod;
517 break;
518 case NArchive::NExtract::NOperationResult::kCRCError:
519 s = kCRCFailed;
520 break;
521 case NArchive::NExtract::NOperationResult::kDataError:
522 s = kDataError;
523 break;
524 case NArchive::NExtract::NOperationResult::kUnavailable:
525 s = kUnavailableData;
526 break;
527 case NArchive::NExtract::NOperationResult::kUnexpectedEnd:
528 s = kUnexpectedEnd;
529 break;
530 case NArchive::NExtract::NOperationResult::kDataAfterEnd:
531 s = kDataAfterEnd;
532 break;
533 case NArchive::NExtract::NOperationResult::kIsNotArc:
534 s = kIsNotArc;
535 break;
536 case NArchive::NExtract::NOperationResult::kHeadersError:
537 s = kHeadersError;
538 break;
539 }
540 if (s)
541 {
542 Print("Error : ");
543 Print(s);
544 }
545 else
546 {
547 char temp[16];
548 ConvertUInt32ToString((UInt32)operationResult, temp);
549 Print("Error #");
550 Print(temp);
551 }
552 }
553 }
554
555 if (_outFileStream)
556 {
557 if (_processedFileInfo.MTime.Def)
558 {
559 CFiTime ft;
560 _processedFileInfo.MTime.Write_To_FiTime(ft);
561 _outFileStreamSpec->SetMTime(&ft);
562 }
563 RINOK(_outFileStreamSpec->Close())
564 }
565 _outFileStream.Release();
566 if (_extractMode && _processedFileInfo.Attrib_Defined)
567 SetFileAttrib_PosixHighDetect(_diskFilePath, _processedFileInfo.Attrib);
568 PrintNewLine();
569 return S_OK;
570 }
571
572
Z7_COM7F_IMF(CArchiveExtractCallback::CryptoGetTextPassword (BSTR * password))573 Z7_COM7F_IMF(CArchiveExtractCallback::CryptoGetTextPassword(BSTR *password))
574 {
575 if (!PasswordIsDefined)
576 {
577 // You can ask real password here from user
578 // Password = GetPassword(OutStream);
579 // PasswordIsDefined = true;
580 PrintError("Password is not defined");
581 return E_ABORT;
582 }
583 return StringToBstr(Password, password);
584 }
585
586
587
588 //////////////////////////////////////////////////////////////
589 // Archive Creating callback class
590
591 struct CDirItem: public NWindows::NFile::NFind::CFileInfoBase
592 {
593 UString Path_For_Handler;
594 FString FullPath; // for filesystem
595
CDirItemCDirItem596 CDirItem(const NWindows::NFile::NFind::CFileInfo &fi):
597 CFileInfoBase(fi)
598 {}
599 };
600
601 class CArchiveUpdateCallback Z7_final:
602 public IArchiveUpdateCallback2,
603 public ICryptoGetTextPassword2,
604 public CMyUnknownImp
605 {
606 Z7_IFACES_IMP_UNK_2(IArchiveUpdateCallback2, ICryptoGetTextPassword2)
607 Z7_IFACE_COM7_IMP(IProgress)
608 Z7_IFACE_COM7_IMP(IArchiveUpdateCallback)
609
610 public:
611 CRecordVector<UInt64> VolumesSizes;
612 UString VolName;
613 UString VolExt;
614
615 FString DirPrefix;
616 const CObjectVector<CDirItem> *DirItems;
617
618 bool PasswordIsDefined;
619 UString Password;
620 bool AskPassword;
621
622 bool m_NeedBeClosed;
623
624 FStringVector FailedFiles;
625 CRecordVector<HRESULT> FailedCodes;
626
CArchiveUpdateCallback()627 CArchiveUpdateCallback():
628 DirItems(NULL),
629 PasswordIsDefined(false),
630 AskPassword(false)
631 {}
632
~CArchiveUpdateCallback()633 ~CArchiveUpdateCallback() { Finilize(); }
634 HRESULT Finilize();
635
Init(const CObjectVector<CDirItem> * dirItems)636 void Init(const CObjectVector<CDirItem> *dirItems)
637 {
638 DirItems = dirItems;
639 m_NeedBeClosed = false;
640 FailedFiles.Clear();
641 FailedCodes.Clear();
642 }
643 };
644
Z7_COM7F_IMF(CArchiveUpdateCallback::SetTotal (UInt64))645 Z7_COM7F_IMF(CArchiveUpdateCallback::SetTotal(UInt64 /* size */))
646 {
647 return S_OK;
648 }
649
Z7_COM7F_IMF(CArchiveUpdateCallback::SetCompleted (const UInt64 *))650 Z7_COM7F_IMF(CArchiveUpdateCallback::SetCompleted(const UInt64 * /* completeValue */))
651 {
652 return S_OK;
653 }
654
Z7_COM7F_IMF(CArchiveUpdateCallback::GetUpdateItemInfo (UInt32,Int32 * newData,Int32 * newProperties,UInt32 * indexInArchive))655 Z7_COM7F_IMF(CArchiveUpdateCallback::GetUpdateItemInfo(UInt32 /* index */,
656 Int32 *newData, Int32 *newProperties, UInt32 *indexInArchive))
657 {
658 if (newData)
659 *newData = BoolToInt(true);
660 if (newProperties)
661 *newProperties = BoolToInt(true);
662 if (indexInArchive)
663 *indexInArchive = (UInt32)(Int32)-1;
664 return S_OK;
665 }
666
Z7_COM7F_IMF(CArchiveUpdateCallback::GetProperty (UInt32 index,PROPID propID,PROPVARIANT * value))667 Z7_COM7F_IMF(CArchiveUpdateCallback::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
668 {
669 NCOM::CPropVariant prop;
670
671 if (propID == kpidIsAnti)
672 {
673 prop = false;
674 prop.Detach(value);
675 return S_OK;
676 }
677
678 {
679 const CDirItem &di = (*DirItems)[index];
680 switch (propID)
681 {
682 case kpidPath: prop = di.Path_For_Handler; break;
683 case kpidIsDir: prop = di.IsDir(); break;
684 case kpidSize: prop = di.Size; break;
685 case kpidCTime: PropVariant_SetFrom_FiTime(prop, di.CTime); break;
686 case kpidATime: PropVariant_SetFrom_FiTime(prop, di.ATime); break;
687 case kpidMTime: PropVariant_SetFrom_FiTime(prop, di.MTime); break;
688 case kpidAttrib: prop = (UInt32)di.GetWinAttrib(); break;
689 case kpidPosixAttrib: prop = (UInt32)di.GetPosixAttrib(); break;
690 }
691 }
692 prop.Detach(value);
693 return S_OK;
694 }
695
Finilize()696 HRESULT CArchiveUpdateCallback::Finilize()
697 {
698 if (m_NeedBeClosed)
699 {
700 PrintNewLine();
701 m_NeedBeClosed = false;
702 }
703 return S_OK;
704 }
705
GetStream2(const wchar_t * name)706 static void GetStream2(const wchar_t *name)
707 {
708 Print("Compressing ");
709 if (name[0] == 0)
710 name = kEmptyFileAlias;
711 Print(name);
712 }
713
Z7_COM7F_IMF(CArchiveUpdateCallback::GetStream (UInt32 index,ISequentialInStream ** inStream))714 Z7_COM7F_IMF(CArchiveUpdateCallback::GetStream(UInt32 index, ISequentialInStream **inStream))
715 {
716 RINOK(Finilize())
717
718 const CDirItem &dirItem = (*DirItems)[index];
719 GetStream2(dirItem.Path_For_Handler);
720
721 if (dirItem.IsDir())
722 return S_OK;
723
724 {
725 CInFileStream *inStreamSpec = new CInFileStream;
726 CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec);
727 FString path = DirPrefix + dirItem.FullPath;
728 if (!inStreamSpec->Open(path))
729 {
730 const DWORD sysError = ::GetLastError();
731 FailedCodes.Add(HRESULT_FROM_WIN32(sysError));
732 FailedFiles.Add(path);
733 // if (systemError == ERROR_SHARING_VIOLATION)
734 {
735 PrintNewLine();
736 PrintError("WARNING: can't open file");
737 // Print(NError::MyFormatMessageW(systemError));
738 return S_FALSE;
739 }
740 // return sysError;
741 }
742 *inStream = inStreamLoc.Detach();
743 }
744 return S_OK;
745 }
746
Z7_COM7F_IMF(CArchiveUpdateCallback::SetOperationResult (Int32))747 Z7_COM7F_IMF(CArchiveUpdateCallback::SetOperationResult(Int32 /* operationResult */))
748 {
749 m_NeedBeClosed = true;
750 return S_OK;
751 }
752
Z7_COM7F_IMF(CArchiveUpdateCallback::GetVolumeSize (UInt32 index,UInt64 * size))753 Z7_COM7F_IMF(CArchiveUpdateCallback::GetVolumeSize(UInt32 index, UInt64 *size))
754 {
755 if (VolumesSizes.Size() == 0)
756 return S_FALSE;
757 if (index >= (UInt32)VolumesSizes.Size())
758 index = VolumesSizes.Size() - 1;
759 *size = VolumesSizes[index];
760 return S_OK;
761 }
762
Z7_COM7F_IMF(CArchiveUpdateCallback::GetVolumeStream (UInt32 index,ISequentialOutStream ** volumeStream))763 Z7_COM7F_IMF(CArchiveUpdateCallback::GetVolumeStream(UInt32 index, ISequentialOutStream **volumeStream))
764 {
765 wchar_t temp[16];
766 ConvertUInt32ToString(index + 1, temp);
767 UString res = temp;
768 while (res.Len() < 2)
769 res.InsertAtFront(L'0');
770 UString fileName = VolName;
771 fileName.Add_Dot();
772 fileName += res;
773 fileName += VolExt;
774 COutFileStream *streamSpec = new COutFileStream;
775 CMyComPtr<ISequentialOutStream> streamLoc(streamSpec);
776 if (!streamSpec->Create(us2fs(fileName), false))
777 return GetLastError_noZero_HRESULT();
778 *volumeStream = streamLoc.Detach();
779 return S_OK;
780 }
781
Z7_COM7F_IMF(CArchiveUpdateCallback::CryptoGetTextPassword2 (Int32 * passwordIsDefined,BSTR * password))782 Z7_COM7F_IMF(CArchiveUpdateCallback::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password))
783 {
784 if (!PasswordIsDefined)
785 {
786 if (AskPassword)
787 {
788 // You can ask real password here from user
789 // Password = GetPassword(OutStream);
790 // PasswordIsDefined = true;
791 PrintError("Password is not defined");
792 return E_ABORT;
793 }
794 }
795 *passwordIsDefined = BoolToInt(PasswordIsDefined);
796 return StringToBstr(Password, password);
797 }
798
799
800 // Main function
801
802 #if defined(_UNICODE) && !defined(_WIN64) && !defined(UNDER_CE)
803 #define NT_CHECK_FAIL_ACTION PrintError("Unsupported Windows version"); return 1;
804 #endif
805
main(int numArgs,const char * args[])806 int Z7_CDECL main(int numArgs, const char *args[])
807 {
808 NT_CHECK
809
810 #ifdef ENV_HAVE_LOCALE
811 MY_SetLocale();
812 #endif
813
814 PrintStringLn(kCopyrightString);
815
816 if (numArgs < 2)
817 {
818 PrintStringLn(kHelpString);
819 return 0;
820 }
821
822 FString dllPrefix;
823
824 #ifdef _WIN32
825 dllPrefix = NDLL::GetModuleDirPrefix();
826 #else
827 {
828 AString s (args[0]);
829 int sep = s.ReverseFind_PathSepar();
830 s.DeleteFrom(sep + 1);
831 dllPrefix = s;
832 }
833 #endif
834
835 NDLL::CLibrary lib;
836 if (!lib.Load(dllPrefix + FTEXT(kDllName)))
837 {
838 PrintError("Cannot load 7-zip library");
839 return 1;
840 }
841
842 Func_CreateObject
843 f_CreateObject = Z7_GET_PROC_ADDRESS(
844 Func_CreateObject, lib.Get_HMODULE(),
845 "CreateObject");
846 if (!f_CreateObject)
847 {
848 PrintError("Cannot get CreateObject");
849 return 1;
850 }
851
852 char c = 0;
853 UString password;
854 bool passwordIsDefined = false;
855 CObjectVector<FString> params;
856
857 for (int curCmd = 1; curCmd < numArgs; curCmd++)
858 {
859 AString a(args[curCmd]);
860
861 if (!a.IsEmpty())
862 {
863 if (a[0] == '-')
864 {
865 if (!passwordIsDefined && a[1] == 'p')
866 {
867 password = GetUnicodeString(a.Ptr(2));
868 passwordIsDefined = true;
869 continue;
870 }
871 }
872 else
873 {
874 if (c)
875 {
876 params.Add(CmdStringToFString(a));
877 continue;
878 }
879 if (a.Len() == 1)
880 {
881 c = (char)MyCharLower_Ascii(a[0]);
882 continue;
883 }
884 }
885 }
886 {
887 PrintError(kIncorrectCommand);
888 return 1;
889 }
890 }
891
892 if (!c || params.Size() < 1)
893 {
894 PrintError(kIncorrectCommand);
895 return 1;
896 }
897
898 const FString &archiveName = params[0];
899
900 if (c == 'a')
901 {
902 // create archive command
903 if (params.Size() < 2)
904 {
905 PrintError(kIncorrectCommand);
906 return 1;
907 }
908 CObjectVector<CDirItem> dirItems;
909 {
910 unsigned i;
911 for (i = 1; i < params.Size(); i++)
912 {
913 const FString &name = params[i];
914
915 NFind::CFileInfo fi;
916 if (!fi.Find(name))
917 {
918 PrintError("Can't find file", name);
919 return 1;
920 }
921
922 CDirItem di(fi);
923
924 di.Path_For_Handler = fs2us(name);
925 di.FullPath = name;
926 dirItems.Add(di);
927 }
928 }
929
930 COutFileStream *outFileStreamSpec = new COutFileStream;
931 CMyComPtr<IOutStream> outFileStream = outFileStreamSpec;
932 if (!outFileStreamSpec->Create(archiveName, false))
933 {
934 PrintError("can't create archive file");
935 return 1;
936 }
937
938 CMyComPtr<IOutArchive> outArchive;
939 if (f_CreateObject(&CLSID_Format, &IID_IOutArchive, (void **)&outArchive) != S_OK)
940 {
941 PrintError("Cannot get class object");
942 return 1;
943 }
944
945 CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback;
946 CMyComPtr<IArchiveUpdateCallback2> updateCallback(updateCallbackSpec);
947 updateCallbackSpec->Init(&dirItems);
948 updateCallbackSpec->PasswordIsDefined = passwordIsDefined;
949 updateCallbackSpec->Password = password;
950
951 /*
952 {
953 const wchar_t *names[] =
954 {
955 L"m",
956 L"s",
957 L"x"
958 };
959 const unsigned kNumProps = Z7_ARRAY_SIZE(names);
960 NCOM::CPropVariant values[kNumProps] =
961 {
962 L"lzma",
963 false, // solid mode OFF
964 (UInt32)9 // compression level = 9 - ultra
965 };
966 CMyComPtr<ISetProperties> setProperties;
967 outArchive->QueryInterface(IID_ISetProperties, (void **)&setProperties);
968 if (!setProperties)
969 {
970 PrintError("ISetProperties unsupported");
971 return 1;
972 }
973 if (setProperties->SetProperties(names, values, kNumProps) != S_OK)
974 {
975 PrintError("SetProperties() error");
976 return 1;
977 }
978 }
979 */
980
981 HRESULT result = outArchive->UpdateItems(outFileStream, dirItems.Size(), updateCallback);
982
983 updateCallbackSpec->Finilize();
984
985 if (result != S_OK)
986 {
987 PrintError("Update Error");
988 return 1;
989 }
990
991 FOR_VECTOR (i, updateCallbackSpec->FailedFiles)
992 {
993 PrintNewLine();
994 PrintError("Error for file", updateCallbackSpec->FailedFiles[i]);
995 }
996
997 if (updateCallbackSpec->FailedFiles.Size() != 0)
998 return 1;
999 }
1000 else
1001 {
1002 if (params.Size() != 1)
1003 {
1004 PrintError(kIncorrectCommand);
1005 return 1;
1006 }
1007
1008 bool listCommand;
1009
1010 if (c == 'l')
1011 listCommand = true;
1012 else if (c == 'x')
1013 listCommand = false;
1014 else
1015 {
1016 PrintError(kIncorrectCommand);
1017 return 1;
1018 }
1019
1020 CMyComPtr<IInArchive> archive;
1021 if (f_CreateObject(&CLSID_Format, &IID_IInArchive, (void **)&archive) != S_OK)
1022 {
1023 PrintError("Cannot get class object");
1024 return 1;
1025 }
1026
1027 CInFileStream *fileSpec = new CInFileStream;
1028 CMyComPtr<IInStream> file = fileSpec;
1029
1030 if (!fileSpec->Open(archiveName))
1031 {
1032 PrintError("Cannot open archive file", archiveName);
1033 return 1;
1034 }
1035
1036 {
1037 CArchiveOpenCallback *openCallbackSpec = new CArchiveOpenCallback;
1038 CMyComPtr<IArchiveOpenCallback> openCallback(openCallbackSpec);
1039 openCallbackSpec->PasswordIsDefined = passwordIsDefined;
1040 openCallbackSpec->Password = password;
1041
1042 const UInt64 scanSize = 1 << 23;
1043 if (archive->Open(file, &scanSize, openCallback) != S_OK)
1044 {
1045 PrintError("Cannot open file as archive", archiveName);
1046 return 1;
1047 }
1048 }
1049
1050 if (listCommand)
1051 {
1052 // List command
1053 UInt32 numItems = 0;
1054 archive->GetNumberOfItems(&numItems);
1055 for (UInt32 i = 0; i < numItems; i++)
1056 {
1057 {
1058 // Get uncompressed size of file
1059 NCOM::CPropVariant prop;
1060 archive->GetProperty(i, kpidSize, &prop);
1061 char s[32];
1062 ConvertPropVariantToShortString(prop, s);
1063 Print(s);
1064 Print(" ");
1065 }
1066 {
1067 // Get name of file
1068 NCOM::CPropVariant prop;
1069 archive->GetProperty(i, kpidPath, &prop);
1070 if (prop.vt == VT_BSTR)
1071 Print(prop.bstrVal);
1072 else if (prop.vt != VT_EMPTY)
1073 Print("ERROR!");
1074 }
1075 PrintNewLine();
1076 }
1077 }
1078 else
1079 {
1080 // Extract command
1081 CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback;
1082 CMyComPtr<IArchiveExtractCallback> extractCallback(extractCallbackSpec);
1083 extractCallbackSpec->Init(archive, FString()); // second parameter is output folder path
1084 extractCallbackSpec->PasswordIsDefined = passwordIsDefined;
1085 extractCallbackSpec->Password = password;
1086
1087 /*
1088 const wchar_t *names[] =
1089 {
1090 L"mt",
1091 L"mtf"
1092 };
1093 const unsigned kNumProps = sizeof(names) / sizeof(names[0]);
1094 NCOM::CPropVariant values[kNumProps] =
1095 {
1096 (UInt32)1,
1097 false
1098 };
1099 CMyComPtr<ISetProperties> setProperties;
1100 archive->QueryInterface(IID_ISetProperties, (void **)&setProperties);
1101 if (setProperties)
1102 {
1103 if (setProperties->SetProperties(names, values, kNumProps) != S_OK)
1104 {
1105 PrintError("SetProperties() error");
1106 return 1;
1107 }
1108 }
1109 */
1110
1111 HRESULT result = archive->Extract(NULL, (UInt32)(Int32)(-1), false, extractCallback);
1112
1113 if (result != S_OK)
1114 {
1115 PrintError("Extract Error");
1116 return 1;
1117 }
1118 }
1119 }
1120
1121 return 0;
1122 }
1123