1 // 7zHandlerOut.cpp
2
3 #include "StdAfx.h"
4
5 #include "../../../Common/ComTry.h"
6 #include "../../../Common/StringToInt.h"
7 #include "../../../Common/Wildcard.h"
8
9 #include "../Common/ItemNameUtils.h"
10 #include "../Common/ParseProperties.h"
11
12 #include "7zHandler.h"
13 #include "7zOut.h"
14 #include "7zUpdate.h"
15
16 #ifndef Z7_EXTRACT_ONLY
17
18 using namespace NWindows;
19
20 namespace NArchive {
21 namespace N7z {
22
23 #define k_LZMA_Name "LZMA"
24 #define kDefaultMethodName "LZMA2"
25 #define k_Copy_Name "Copy"
26
27 #define k_MatchFinder_ForHeaders "BT2"
28
29 static const UInt32 k_NumFastBytes_ForHeaders = 273;
30 static const UInt32 k_Level_ForHeaders = 5;
31 static const UInt32 k_Dictionary_ForHeaders =
32 #ifdef UNDER_CE
33 1 << 18;
34 #else
35 1 << 20;
36 #endif
37
Z7_COM7F_IMF(CHandler::GetFileTimeType (UInt32 * type))38 Z7_COM7F_IMF(CHandler::GetFileTimeType(UInt32 *type))
39 {
40 *type = NFileTimeType::kWindows;
41 return S_OK;
42 }
43
PropsMethod_To_FullMethod(CMethodFull & dest,const COneMethodInfo & m)44 HRESULT CHandler::PropsMethod_To_FullMethod(CMethodFull &dest, const COneMethodInfo &m)
45 {
46 bool isFilter;
47 dest.CodecIndex = FindMethod_Index(
48 EXTERNAL_CODECS_VARS
49 m.MethodName, true,
50 dest.Id, dest.NumStreams, isFilter);
51 if (dest.CodecIndex < 0)
52 return E_INVALIDARG;
53 (CProps &)dest = (CProps &)m;
54 return S_OK;
55 }
56
SetHeaderMethod(CCompressionMethodMode & headerMethod)57 HRESULT CHandler::SetHeaderMethod(CCompressionMethodMode &headerMethod)
58 {
59 if (!_compressHeaders)
60 return S_OK;
61 COneMethodInfo m;
62 m.MethodName = k_LZMA_Name;
63 m.AddProp_Ascii(NCoderPropID::kMatchFinder, k_MatchFinder_ForHeaders);
64 m.AddProp_Level(k_Level_ForHeaders);
65 m.AddProp32(NCoderPropID::kNumFastBytes, k_NumFastBytes_ForHeaders);
66 m.AddProp32(NCoderPropID::kDictionarySize, k_Dictionary_ForHeaders);
67 m.AddProp_NumThreads(1);
68
69 CMethodFull &methodFull = headerMethod.Methods.AddNew();
70 return PropsMethod_To_FullMethod(methodFull, m);
71 }
72
73
SetMainMethod(CCompressionMethodMode & methodMode)74 HRESULT CHandler::SetMainMethod(CCompressionMethodMode &methodMode)
75 {
76 methodMode.Bonds = _bonds;
77
78 // we create local copy of _methods. So we can modify it.
79 CObjectVector<COneMethodInfo> methods = _methods;
80
81 {
82 FOR_VECTOR (i, methods)
83 {
84 AString &methodName = methods[i].MethodName;
85 if (methodName.IsEmpty())
86 methodName = kDefaultMethodName;
87 }
88 if (methods.IsEmpty())
89 {
90 COneMethodInfo &m = methods.AddNew();
91 m.MethodName = (GetLevel() == 0 ? k_Copy_Name : kDefaultMethodName);
92 methodMode.DefaultMethod_was_Inserted = true;
93 }
94 }
95
96 if (!_filterMethod.MethodName.IsEmpty())
97 {
98 // if (methodMode.Bonds.IsEmpty())
99 {
100 FOR_VECTOR (k, methodMode.Bonds)
101 {
102 CBond2 &bond = methodMode.Bonds[k];
103 bond.InCoder++;
104 bond.OutCoder++;
105 }
106 methods.Insert(0, _filterMethod);
107 methodMode.Filter_was_Inserted = true;
108 }
109 }
110
111 const UInt64 kSolidBytes_Min = (1 << 24);
112 const UInt64 kSolidBytes_Max = ((UInt64)1 << 32);
113
114 bool needSolid = false;
115
116 FOR_VECTOR (i, methods)
117 {
118 COneMethodInfo &oneMethodInfo = methods[i];
119
120 SetGlobalLevelTo(oneMethodInfo);
121
122 #ifndef Z7_ST
123 const bool numThreads_WasSpecifiedInMethod = (oneMethodInfo.Get_NumThreads() >= 0);
124 if (!numThreads_WasSpecifiedInMethod)
125 {
126 // here we set the (NCoderPropID::kNumThreads) property in each method, only if there is no such property already
127 CMultiMethodProps::SetMethodThreadsTo_IfNotFinded(oneMethodInfo, methodMode.NumThreads);
128 }
129 #endif
130
131 CMethodFull &methodFull = methodMode.Methods.AddNew();
132 RINOK(PropsMethod_To_FullMethod(methodFull, oneMethodInfo))
133
134 #ifndef Z7_ST
135 methodFull.Set_NumThreads = true;
136 methodFull.NumThreads = methodMode.NumThreads;
137 #endif
138
139 if (methodFull.Id != k_Copy)
140 needSolid = true;
141
142 UInt64 dicSize;
143 switch (methodFull.Id)
144 {
145 case k_LZMA:
146 case k_LZMA2: dicSize = oneMethodInfo.Get_Lzma_DicSize(); break;
147 case k_PPMD: dicSize = oneMethodInfo.Get_Ppmd_MemSize(); break;
148 case k_Deflate: dicSize = (UInt32)1 << 15; break;
149 case k_Deflate64: dicSize = (UInt32)1 << 16; break;
150 case k_BZip2: dicSize = oneMethodInfo.Get_BZip2_BlockSize(); break;
151 // case k_ZSTD: dicSize = 1 << 23; break;
152 default: continue;
153 }
154
155 UInt64 numSolidBytes;
156
157 /*
158 if (methodFull.Id == k_ZSTD)
159 {
160 // continue;
161 NCompress::NZstd::CEncoderProps encoderProps;
162 RINOK(oneMethodInfo.Set_PropsTo_zstd(encoderProps));
163 CZstdEncProps &zstdProps = encoderProps.EncProps;
164 ZstdEncProps_NormalizeFull(&zstdProps);
165 UInt64 cs = (UInt64)(zstdProps.jobSize);
166 UInt32 winSize = (UInt32)(1 << zstdProps.windowLog);
167 if (cs < winSize)
168 cs = winSize;
169 numSolidBytes = cs << 6;
170 const UInt64 kSolidBytes_Zstd_Max = ((UInt64)1 << 34);
171 if (numSolidBytes > kSolidBytes_Zstd_Max)
172 numSolidBytes = kSolidBytes_Zstd_Max;
173
174 methodFull.Set_NumThreads = false; // we don't use ICompressSetCoderMt::SetNumberOfThreads() for LZMA2 encoder
175
176 #ifndef Z7_ST
177 if (!numThreads_WasSpecifiedInMethod
178 && !methodMode.NumThreads_WasForced
179 && methodMode.MemoryUsageLimit_WasSet
180 )
181 {
182 const UInt32 numThreads_Original = methodMode.NumThreads;
183 const UInt32 numThreads_New = ZstdEncProps_GetNumThreads_for_MemUsageLimit(
184 &zstdProps,
185 methodMode.MemoryUsageLimit,
186 numThreads_Original);
187 if (numThreads_Original != numThreads_New)
188 {
189 CMultiMethodProps::SetMethodThreadsTo_Replace(methodFull, numThreads_New);
190 }
191 }
192 #endif
193 }
194 else
195 */
196 if (methodFull.Id == k_LZMA2)
197 {
198 // he we calculate default chunk Size for LZMA2 as defined in LZMA2 encoder code
199 /* lzma2 code use dictionary up to fake 4 GiB to calculate ChunkSize.
200 So we do same */
201 UInt64 cs = (UInt64)dicSize << 2;
202 const UInt32 kMinSize = (UInt32)1 << 20;
203 const UInt32 kMaxSize = (UInt32)1 << 28;
204 if (cs < kMinSize) cs = kMinSize;
205 if (cs > kMaxSize) cs = kMaxSize;
206 if (cs < dicSize) cs = dicSize;
207 cs += (kMinSize - 1);
208 cs &= ~(UInt64)(kMinSize - 1);
209 // we want to use at least 64 chunks (threads) per one solid block.
210
211 // here we don't use chunkSize property
212 numSolidBytes = cs << 6;
213
214 // here we get real chunkSize
215 cs = oneMethodInfo.Get_Xz_BlockSize();
216 if (dicSize > cs)
217 dicSize = cs;
218
219 const UInt64 kSolidBytes_Lzma2_Max = ((UInt64)1 << 34);
220 if (numSolidBytes > kSolidBytes_Lzma2_Max)
221 numSolidBytes = kSolidBytes_Lzma2_Max;
222
223 methodFull.Set_NumThreads = false; // we don't use ICompressSetCoderMt::SetNumberOfThreads() for LZMA2 encoder
224
225 #ifndef Z7_ST
226 if (!numThreads_WasSpecifiedInMethod
227 && !methodMode.NumThreads_WasForced
228 && methodMode.MemoryUsageLimit_WasSet
229 )
230 {
231 const UInt32 lzmaThreads = oneMethodInfo.Get_Lzma_NumThreads();
232 const UInt32 numBlockThreads_Original = methodMode.NumThreads / lzmaThreads;
233
234 if (numBlockThreads_Original > 1)
235 {
236 /*
237 const UInt32 kNumThreads_Max = 1024;
238 if (numBlockThreads > kNumMaxThreads)
239 numBlockThreads = kNumMaxThreads;
240 */
241
242 UInt32 numBlockThreads = numBlockThreads_Original;
243 const UInt64 lzmaMemUsage = oneMethodInfo.Get_Lzma_MemUsage(false); // solid
244
245 for (; numBlockThreads > 1; numBlockThreads--)
246 {
247 UInt64 size = numBlockThreads * (lzmaMemUsage + cs);
248 UInt32 numPackChunks = numBlockThreads + (numBlockThreads / 8) + 1;
249 if (cs < ((UInt32)1 << 26)) numPackChunks++;
250 if (cs < ((UInt32)1 << 24)) numPackChunks++;
251 if (cs < ((UInt32)1 << 22)) numPackChunks++;
252 size += numPackChunks * cs;
253 // printf("\nnumBlockThreads = %d, size = %d\n", (unsigned)(numBlockThreads), (unsigned)(size >> 20));
254 if (size <= methodMode.MemoryUsageLimit)
255 break;
256 }
257
258 if (numBlockThreads == 0)
259 numBlockThreads = 1;
260 if (numBlockThreads != numBlockThreads_Original)
261 {
262 const UInt32 numThreads_New = numBlockThreads * lzmaThreads;
263 CMultiMethodProps::SetMethodThreadsTo_Replace(methodFull, numThreads_New);
264 }
265 }
266 }
267 #endif
268 }
269 else
270 {
271 numSolidBytes = (UInt64)dicSize << 7;
272 if (numSolidBytes > kSolidBytes_Max)
273 numSolidBytes = kSolidBytes_Max;
274 }
275
276 if (_numSolidBytesDefined)
277 continue;
278
279 if (numSolidBytes < kSolidBytes_Min)
280 numSolidBytes = kSolidBytes_Min;
281 _numSolidBytes = numSolidBytes;
282 _numSolidBytesDefined = true;
283 }
284
285 if (!_numSolidBytesDefined)
286 {
287 if (needSolid)
288 _numSolidBytes = kSolidBytes_Max;
289 else
290 _numSolidBytes = 0;
291 }
292 _numSolidBytesDefined = true;
293
294
295 return S_OK;
296 }
297
298
299
GetTime(IArchiveUpdateCallback * updateCallback,unsigned index,PROPID propID,UInt64 & ft,bool & ftDefined)300 static HRESULT GetTime(IArchiveUpdateCallback *updateCallback, unsigned index, PROPID propID, UInt64 &ft, bool &ftDefined)
301 {
302 // ft = 0;
303 // ftDefined = false;
304 NCOM::CPropVariant prop;
305 RINOK(updateCallback->GetProperty(index, propID, &prop))
306 if (prop.vt == VT_FILETIME)
307 {
308 ft = prop.filetime.dwLowDateTime | ((UInt64)prop.filetime.dwHighDateTime << 32);
309 ftDefined = true;
310 }
311 else if (prop.vt != VT_EMPTY)
312 return E_INVALIDARG;
313 else
314 {
315 ft = 0;
316 ftDefined = false;
317 }
318 return S_OK;
319 }
320
321 /*
322
323 #ifdef _WIN32
324 static const wchar_t kDirDelimiter1 = L'\\';
325 #endif
326 static const wchar_t kDirDelimiter2 = L'/';
327
328 static inline bool IsCharDirLimiter(wchar_t c)
329 {
330 return (
331 #ifdef _WIN32
332 c == kDirDelimiter1 ||
333 #endif
334 c == kDirDelimiter2);
335 }
336
337 static int FillSortIndex(CObjectVector<CTreeFolder> &treeFolders, int cur, int curSortIndex)
338 {
339 CTreeFolder &tf = treeFolders[cur];
340 tf.SortIndex = curSortIndex++;
341 for (int i = 0; i < tf.SubFolders.Size(); i++)
342 curSortIndex = FillSortIndex(treeFolders, tf.SubFolders[i], curSortIndex);
343 tf.SortIndexEnd = curSortIndex;
344 return curSortIndex;
345 }
346
347 static int FindSubFolder(const CObjectVector<CTreeFolder> &treeFolders, int cur, const UString &name, int &insertPos)
348 {
349 const CIntVector &subFolders = treeFolders[cur].SubFolders;
350 int left = 0, right = subFolders.Size();
351 insertPos = -1;
352 for (;;)
353 {
354 if (left == right)
355 {
356 insertPos = left;
357 return -1;
358 }
359 int mid = (left + right) / 2;
360 int midFolder = subFolders[mid];
361 int compare = CompareFileNames(name, treeFolders[midFolder].Name);
362 if (compare == 0)
363 return midFolder;
364 if (compare < 0)
365 right = mid;
366 else
367 left = mid + 1;
368 }
369 }
370
371 static int AddFolder(CObjectVector<CTreeFolder> &treeFolders, int cur, const UString &name)
372 {
373 int insertPos;
374 int folderIndex = FindSubFolder(treeFolders, cur, name, insertPos);
375 if (folderIndex < 0)
376 {
377 folderIndex = treeFolders.Size();
378 CTreeFolder &newFolder = treeFolders.AddNew();
379 newFolder.Parent = cur;
380 newFolder.Name = name;
381 treeFolders[cur].SubFolders.Insert(insertPos, folderIndex);
382 }
383 // else if (treeFolders[folderIndex].IsAltStreamFolder != isAltStreamFolder) throw 1123234234;
384 return folderIndex;
385 }
386 */
387
Z7_COM7F_IMF(CHandler::UpdateItems (ISequentialOutStream * outStream,UInt32 numItems,IArchiveUpdateCallback * updateCallback))388 Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
389 IArchiveUpdateCallback *updateCallback))
390 {
391 COM_TRY_BEGIN
392
393 const CDbEx *db = NULL;
394 #ifdef Z7_7Z_VOL
395 if (_volumes.Size() > 1)
396 return E_FAIL;
397 const CVolume *volume = 0;
398 if (_volumes.Size() == 1)
399 {
400 volume = &_volumes.Front();
401 db = &volume->Database;
402 }
403 #else
404 if (_inStream)
405 db = &_db;
406 #endif
407
408 if (db && !db->CanUpdate())
409 return E_NOTIMPL;
410
411 /*
412 Z7_DECL_CMyComPtr_QI_FROM(
413 IArchiveGetRawProps,
414 getRawProps, updateCallback)
415
416 CUniqBlocks secureBlocks;
417 secureBlocks.AddUniq(NULL, 0);
418
419 CObjectVector<CTreeFolder> treeFolders;
420 {
421 CTreeFolder folder;
422 folder.Parent = -1;
423 treeFolders.Add(folder);
424 }
425 */
426
427 CObjectVector<CUpdateItem> updateItems;
428
429 bool need_CTime = (TimeOptions.Write_CTime.Def && TimeOptions.Write_CTime.Val);
430 bool need_ATime = (TimeOptions.Write_ATime.Def && TimeOptions.Write_ATime.Val);
431 bool need_MTime = (TimeOptions.Write_MTime.Def ? TimeOptions.Write_MTime.Val : true);
432 bool need_Attrib = (Write_Attrib.Def ? Write_Attrib.Val : true);
433
434 if (db && !db->Files.IsEmpty())
435 {
436 if (!TimeOptions.Write_CTime.Def) need_CTime = !db->CTime.Defs.IsEmpty();
437 if (!TimeOptions.Write_ATime.Def) need_ATime = !db->ATime.Defs.IsEmpty();
438 if (!TimeOptions.Write_MTime.Def) need_MTime = !db->MTime.Defs.IsEmpty();
439 if (!Write_Attrib.Def) need_Attrib = !db->Attrib.Defs.IsEmpty();
440 }
441
442 // UString s;
443 UString name;
444
445 for (UInt32 i = 0; i < numItems; i++)
446 {
447 Int32 newData, newProps;
448 UInt32 indexInArchive;
449 if (!updateCallback)
450 return E_FAIL;
451 RINOK(updateCallback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArchive))
452 CUpdateItem ui;
453 ui.NewProps = IntToBool(newProps);
454 ui.NewData = IntToBool(newData);
455 ui.IndexInArchive = (int)indexInArchive;
456 ui.IndexInClient = i;
457 ui.IsAnti = false;
458 ui.Size = 0;
459
460 name.Empty();
461 // bool isAltStream = false;
462 if (ui.IndexInArchive != -1)
463 {
464 if (!db || (unsigned)ui.IndexInArchive >= db->Files.Size())
465 return E_INVALIDARG;
466 const CFileItem &fi = db->Files[(unsigned)ui.IndexInArchive];
467 if (!ui.NewProps)
468 {
469 _db.GetPath((unsigned)ui.IndexInArchive, name);
470 }
471 ui.IsDir = fi.IsDir;
472 ui.Size = fi.Size;
473 // isAltStream = fi.IsAltStream;
474 ui.IsAnti = db->IsItemAnti((unsigned)ui.IndexInArchive);
475
476 if (!ui.NewProps)
477 {
478 ui.CTimeDefined = db->CTime.GetItem((unsigned)ui.IndexInArchive, ui.CTime);
479 ui.ATimeDefined = db->ATime.GetItem((unsigned)ui.IndexInArchive, ui.ATime);
480 ui.MTimeDefined = db->MTime.GetItem((unsigned)ui.IndexInArchive, ui.MTime);
481 }
482 }
483
484 if (ui.NewProps)
485 {
486 bool folderStatusIsDefined;
487 if (need_Attrib)
488 {
489 NCOM::CPropVariant prop;
490 RINOK(updateCallback->GetProperty(i, kpidAttrib, &prop))
491 if (prop.vt == VT_EMPTY)
492 ui.AttribDefined = false;
493 else if (prop.vt != VT_UI4)
494 return E_INVALIDARG;
495 else
496 {
497 ui.Attrib = prop.ulVal;
498 ui.AttribDefined = true;
499 }
500 }
501
502 // we need MTime to sort files.
503 if (need_CTime) RINOK(GetTime(updateCallback, i, kpidCTime, ui.CTime, ui.CTimeDefined))
504 if (need_ATime) RINOK(GetTime(updateCallback, i, kpidATime, ui.ATime, ui.ATimeDefined))
505 if (need_MTime) RINOK(GetTime(updateCallback, i, kpidMTime, ui.MTime, ui.MTimeDefined))
506
507 /*
508 if (getRawProps)
509 {
510 const void *data;
511 UInt32 dataSize;
512 UInt32 propType;
513
514 getRawProps->GetRawProp(i, kpidNtSecure, &data, &dataSize, &propType);
515 if (dataSize != 0 && propType != NPropDataType::kRaw)
516 return E_FAIL;
517 ui.SecureIndex = secureBlocks.AddUniq((const Byte *)data, dataSize);
518 }
519 */
520
521 {
522 NCOM::CPropVariant prop;
523 RINOK(updateCallback->GetProperty(i, kpidPath, &prop))
524 if (prop.vt == VT_EMPTY)
525 {
526 }
527 else if (prop.vt != VT_BSTR)
528 return E_INVALIDARG;
529 else
530 {
531 name = prop.bstrVal;
532 NItemName::ReplaceSlashes_OsToUnix(name);
533 }
534 }
535 {
536 NCOM::CPropVariant prop;
537 RINOK(updateCallback->GetProperty(i, kpidIsDir, &prop))
538 if (prop.vt == VT_EMPTY)
539 folderStatusIsDefined = false;
540 else if (prop.vt != VT_BOOL)
541 return E_INVALIDARG;
542 else
543 {
544 ui.IsDir = (prop.boolVal != VARIANT_FALSE);
545 folderStatusIsDefined = true;
546 }
547 }
548
549 {
550 NCOM::CPropVariant prop;
551 RINOK(updateCallback->GetProperty(i, kpidIsAnti, &prop))
552 if (prop.vt == VT_EMPTY)
553 ui.IsAnti = false;
554 else if (prop.vt != VT_BOOL)
555 return E_INVALIDARG;
556 else
557 ui.IsAnti = (prop.boolVal != VARIANT_FALSE);
558 }
559
560 /*
561 {
562 NCOM::CPropVariant prop;
563 RINOK(updateCallback->GetProperty(i, kpidIsAltStream, &prop));
564 if (prop.vt == VT_EMPTY)
565 isAltStream = false;
566 else if (prop.vt != VT_BOOL)
567 return E_INVALIDARG;
568 else
569 isAltStream = (prop.boolVal != VARIANT_FALSE);
570 }
571 */
572
573 if (ui.IsAnti)
574 {
575 ui.AttribDefined = false;
576
577 ui.CTimeDefined = false;
578 ui.ATimeDefined = false;
579 ui.MTimeDefined = false;
580
581 ui.Size = 0;
582 }
583
584 if (!folderStatusIsDefined && ui.AttribDefined)
585 ui.SetDirStatusFromAttrib();
586 }
587 else
588 {
589 /*
590 if (_db.SecureIDs.IsEmpty())
591 ui.SecureIndex = secureBlocks.AddUniq(NULL, 0);
592 else
593 {
594 int id = _db.SecureIDs[ui.IndexInArchive];
595 size_t offs = _db.SecureOffsets[id];
596 size_t size = _db.SecureOffsets[id + 1] - offs;
597 ui.SecureIndex = secureBlocks.AddUniq(_db.SecureBuf + offs, size);
598 }
599 */
600 }
601
602 /*
603 {
604 int folderIndex = 0;
605 if (_useParents)
606 {
607 int j;
608 s.Empty();
609 for (j = 0; j < name.Len(); j++)
610 {
611 wchar_t c = name[j];
612 if (IsCharDirLimiter(c))
613 {
614 folderIndex = AddFolder(treeFolders, folderIndex, s);
615 s.Empty();
616 continue;
617 }
618 s += c;
619 }
620 if (isAltStream)
621 {
622 int colonPos = s.Find(':');
623 if (colonPos < 0)
624 {
625 // isAltStream = false;
626 return E_INVALIDARG;
627 }
628 UString mainName = s.Left(colonPos);
629 int newFolderIndex = AddFolder(treeFolders, folderIndex, mainName);
630 if (treeFolders[newFolderIndex].UpdateItemIndex < 0)
631 {
632 for (int j = updateItems.Size() - 1; j >= 0; j--)
633 {
634 CUpdateItem &ui2 = updateItems[j];
635 if (ui2.ParentFolderIndex == folderIndex
636 && ui2.Name == mainName)
637 {
638 ui2.TreeFolderIndex = newFolderIndex;
639 treeFolders[newFolderIndex].UpdateItemIndex = j;
640 }
641 }
642 }
643 folderIndex = newFolderIndex;
644 s.Delete(0, colonPos + 1);
645 }
646 ui.Name = s;
647 }
648 else
649 ui.Name = name;
650 ui.IsAltStream = isAltStream;
651 ui.ParentFolderIndex = folderIndex;
652 ui.TreeFolderIndex = -1;
653 if (ui.IsDir && !s.IsEmpty())
654 {
655 ui.TreeFolderIndex = AddFolder(treeFolders, folderIndex, s);
656 treeFolders[ui.TreeFolderIndex].UpdateItemIndex = updateItems.Size();
657 }
658 }
659 */
660 ui.Name = name;
661
662 if (ui.NewData)
663 {
664 ui.Size = 0;
665 if (!ui.IsDir)
666 {
667 NCOM::CPropVariant prop;
668 RINOK(updateCallback->GetProperty(i, kpidSize, &prop))
669 if (prop.vt != VT_UI8)
670 return E_INVALIDARG;
671 ui.Size = (UInt64)prop.uhVal.QuadPart;
672 if (ui.Size != 0 && ui.IsAnti)
673 return E_INVALIDARG;
674 }
675 }
676
677 updateItems.Add(ui);
678 }
679
680 /*
681 FillSortIndex(treeFolders, 0, 0);
682 for (i = 0; i < (UInt32)updateItems.Size(); i++)
683 {
684 CUpdateItem &ui = updateItems[i];
685 ui.ParentSortIndex = treeFolders[ui.ParentFolderIndex].SortIndex;
686 ui.ParentSortIndexEnd = treeFolders[ui.ParentFolderIndex].SortIndexEnd;
687 }
688 */
689
690 CCompressionMethodMode methodMode, headerMethod;
691
692 methodMode.MemoryUsageLimit = _memUsage_Compress;
693 methodMode.MemoryUsageLimit_WasSet = _memUsage_WasSet;
694
695 #ifndef Z7_ST
696 {
697 UInt32 numThreads = _numThreads;
698 const UInt32 kNumThreads_Max = 1024;
699 if (numThreads > kNumThreads_Max)
700 numThreads = kNumThreads_Max;
701 methodMode.NumThreads = numThreads;
702 methodMode.NumThreads_WasForced = _numThreads_WasForced;
703 methodMode.MultiThreadMixer = _useMultiThreadMixer;
704 // headerMethod.NumThreads = 1;
705 headerMethod.MultiThreadMixer = _useMultiThreadMixer;
706 }
707 #endif
708
709 const HRESULT res = SetMainMethod(methodMode);
710 RINOK(res)
711
712 RINOK(SetHeaderMethod(headerMethod))
713
714 Z7_DECL_CMyComPtr_QI_FROM(
715 ICryptoGetTextPassword2,
716 getPassword2, updateCallback)
717
718 methodMode.PasswordIsDefined = false;
719 methodMode.Password.Wipe_and_Empty();
720 if (getPassword2)
721 {
722 CMyComBSTR_Wipe password;
723 Int32 passwordIsDefined;
724 RINOK(getPassword2->CryptoGetTextPassword2(&passwordIsDefined, &password))
725 methodMode.PasswordIsDefined = IntToBool(passwordIsDefined);
726 if (methodMode.PasswordIsDefined && password)
727 methodMode.Password = password;
728 }
729
730 bool compressMainHeader = _compressHeaders; // check it
731
732 bool encryptHeaders = false;
733
734 #ifndef Z7_NO_CRYPTO
735 if (!methodMode.PasswordIsDefined && _passwordIsDefined)
736 {
737 // if header is compressed, we use that password for updated archive
738 methodMode.PasswordIsDefined = true;
739 methodMode.Password = _password;
740 }
741 #endif
742
743 if (methodMode.PasswordIsDefined)
744 {
745 if (_encryptHeadersSpecified)
746 encryptHeaders = _encryptHeaders;
747 #ifndef Z7_NO_CRYPTO
748 else
749 encryptHeaders = _passwordIsDefined;
750 #endif
751 compressMainHeader = true;
752 if (encryptHeaders)
753 {
754 headerMethod.PasswordIsDefined = methodMode.PasswordIsDefined;
755 headerMethod.Password = methodMode.Password;
756 }
757 }
758
759 if (numItems < 2)
760 compressMainHeader = false;
761
762 const int level = GetLevel();
763
764 CUpdateOptions options;
765 options.Need_CTime = need_CTime;
766 options.Need_ATime = need_ATime;
767 options.Need_MTime = need_MTime;
768 options.Need_Attrib = need_Attrib;
769 // options.Need_Crc = (_crcSize != 0); // for debug
770
771 options.Method = &methodMode;
772 options.HeaderMethod = (_compressHeaders || encryptHeaders) ? &headerMethod : NULL;
773 options.UseFilters = (level != 0 && _autoFilter && !methodMode.Filter_was_Inserted);
774 options.MaxFilter = (level >= 8);
775 options.AnalysisLevel = GetAnalysisLevel();
776
777 options.HeaderOptions.CompressMainHeader = compressMainHeader;
778 /*
779 options.HeaderOptions.WriteCTime = Write_CTime;
780 options.HeaderOptions.WriteATime = Write_ATime;
781 options.HeaderOptions.WriteMTime = Write_MTime;
782 options.HeaderOptions.WriteAttrib = Write_Attrib;
783 */
784
785 options.NumSolidFiles = _numSolidFiles;
786 options.NumSolidBytes = _numSolidBytes;
787 options.SolidExtension = _solidExtension;
788 options.UseTypeSorting = _useTypeSorting;
789
790 options.RemoveSfxBlock = _removeSfxBlock;
791 // options.VolumeMode = _volumeMode;
792
793 options.MultiThreadMixer = _useMultiThreadMixer;
794
795 /*
796 if (secureBlocks.Sorted.Size() > 1)
797 {
798 secureBlocks.GetReverseMap();
799 for (int i = 0; i < updateItems.Size(); i++)
800 {
801 int &secureIndex = updateItems[i].SecureIndex;
802 secureIndex = secureBlocks.BufIndexToSortedIndex[secureIndex];
803 }
804 }
805 */
806
807 return Update(
808 EXTERNAL_CODECS_VARS
809 #ifdef Z7_7Z_VOL
810 volume ? volume->Stream: 0,
811 volume ? db : 0,
812 #else
813 _inStream,
814 db,
815 #endif
816 updateItems,
817 // treeFolders,
818 // secureBlocks,
819 outStream, updateCallback, options);
820
821 COM_TRY_END
822 }
823
ParseBond(UString & srcString,UInt32 & coder,UInt32 & stream)824 static HRESULT ParseBond(UString &srcString, UInt32 &coder, UInt32 &stream)
825 {
826 stream = 0;
827 {
828 const unsigned index = ParseStringToUInt32(srcString, coder);
829 if (index == 0)
830 return E_INVALIDARG;
831 srcString.DeleteFrontal(index);
832 }
833 if (srcString[0] == 's')
834 {
835 srcString.Delete(0);
836 const unsigned index = ParseStringToUInt32(srcString, stream);
837 if (index == 0)
838 return E_INVALIDARG;
839 srcString.DeleteFrontal(index);
840 }
841 return S_OK;
842 }
843
InitProps7z()844 void COutHandler::InitProps7z()
845 {
846 _removeSfxBlock = false;
847 _compressHeaders = true;
848 _encryptHeadersSpecified = false;
849 _encryptHeaders = false;
850 // _useParents = false;
851
852 TimeOptions.Init();
853 Write_Attrib.Init();
854
855 _useMultiThreadMixer = true;
856
857 // _volumeMode = false;
858
859 InitSolid();
860 _useTypeSorting = false;
861 }
862
InitProps()863 void COutHandler::InitProps()
864 {
865 CMultiMethodProps::Init();
866 InitProps7z();
867 }
868
869
870
SetSolidFromString(const UString & s)871 HRESULT COutHandler::SetSolidFromString(const UString &s)
872 {
873 UString s2 = s;
874 s2.MakeLower_Ascii();
875 for (unsigned i = 0; i < s2.Len();)
876 {
877 const wchar_t *start = ((const wchar_t *)s2) + i;
878 const wchar_t *end;
879 UInt64 v = ConvertStringToUInt64(start, &end);
880 if (start == end)
881 {
882 if (s2[i++] != 'e')
883 return E_INVALIDARG;
884 _solidExtension = true;
885 continue;
886 }
887 i += (unsigned)(end - start);
888 if (i == s2.Len())
889 return E_INVALIDARG;
890 const wchar_t c = s2[i++];
891 if (c == 'f')
892 {
893 if (v < 1)
894 v = 1;
895 _numSolidFiles = v;
896 }
897 else
898 {
899 unsigned numBits;
900 switch (c)
901 {
902 case 'b': numBits = 0; break;
903 case 'k': numBits = 10; break;
904 case 'm': numBits = 20; break;
905 case 'g': numBits = 30; break;
906 case 't': numBits = 40; break;
907 default: return E_INVALIDARG;
908 }
909 _numSolidBytes = (v << numBits);
910 _numSolidBytesDefined = true;
911 /*
912 if (_numSolidBytes == 0)
913 _numSolidFiles = 1;
914 */
915 }
916 }
917 return S_OK;
918 }
919
SetSolidFromPROPVARIANT(const PROPVARIANT & value)920 HRESULT COutHandler::SetSolidFromPROPVARIANT(const PROPVARIANT &value)
921 {
922 bool isSolid;
923 switch (value.vt)
924 {
925 case VT_EMPTY: isSolid = true; break;
926 case VT_BOOL: isSolid = (value.boolVal != VARIANT_FALSE); break;
927 case VT_BSTR:
928 if (StringToBool(value.bstrVal, isSolid))
929 break;
930 return SetSolidFromString(value.bstrVal);
931 default: return E_INVALIDARG;
932 }
933 if (isSolid)
934 InitSolid();
935 else
936 _numSolidFiles = 1;
937 return S_OK;
938 }
939
PROPVARIANT_to_BoolPair(const PROPVARIANT & prop,CBoolPair & dest)940 static HRESULT PROPVARIANT_to_BoolPair(const PROPVARIANT &prop, CBoolPair &dest)
941 {
942 RINOK(PROPVARIANT_to_bool(prop, dest.Val))
943 dest.Def = true;
944 return S_OK;
945 }
946
SetProperty(const wchar_t * nameSpec,const PROPVARIANT & value)947 HRESULT COutHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value)
948 {
949 UString name = nameSpec;
950 name.MakeLower_Ascii();
951 if (name.IsEmpty())
952 return E_INVALIDARG;
953
954 if (name[0] == L's')
955 {
956 name.Delete(0);
957 if (name.IsEmpty())
958 return SetSolidFromPROPVARIANT(value);
959 if (value.vt != VT_EMPTY)
960 return E_INVALIDARG;
961 return SetSolidFromString(name);
962 }
963
964 UInt32 number;
965 const unsigned index = ParseStringToUInt32(name, number);
966 // UString realName = name.Ptr(index);
967 if (index == 0)
968 {
969 if (name.IsEqualTo("rsfx")) return PROPVARIANT_to_bool(value, _removeSfxBlock);
970 if (name.IsEqualTo("hc")) return PROPVARIANT_to_bool(value, _compressHeaders);
971 // if (name.IsEqualToNoCase(L"HS")) return PROPVARIANT_to_bool(value, _useParents);
972
973 if (name.IsEqualTo("hcf"))
974 {
975 bool compressHeadersFull = true;
976 RINOK(PROPVARIANT_to_bool(value, compressHeadersFull))
977 return compressHeadersFull ? S_OK: E_INVALIDARG;
978 }
979
980 if (name.IsEqualTo("he"))
981 {
982 RINOK(PROPVARIANT_to_bool(value, _encryptHeaders))
983 _encryptHeadersSpecified = true;
984 return S_OK;
985 }
986
987 {
988 bool processed;
989 RINOK(TimeOptions.Parse(name, value, processed))
990 if (processed)
991 {
992 if ( TimeOptions.Prec != (UInt32)(Int32)-1
993 && TimeOptions.Prec != k_PropVar_TimePrec_0
994 && TimeOptions.Prec != k_PropVar_TimePrec_HighPrec
995 && TimeOptions.Prec != k_PropVar_TimePrec_100ns)
996 return E_INVALIDARG;
997 return S_OK;
998 }
999 }
1000
1001 if (name.IsEqualTo("tr")) return PROPVARIANT_to_BoolPair(value, Write_Attrib);
1002
1003 if (name.IsEqualTo("mtf")) return PROPVARIANT_to_bool(value, _useMultiThreadMixer);
1004
1005 if (name.IsEqualTo("qs")) return PROPVARIANT_to_bool(value, _useTypeSorting);
1006
1007 // if (name.IsEqualTo("v")) return PROPVARIANT_to_bool(value, _volumeMode);
1008 }
1009 return CMultiMethodProps::SetProperty(name, value);
1010 }
1011
Z7_COM7F_IMF(CHandler::SetProperties (const wchar_t * const * names,const PROPVARIANT * values,UInt32 numProps))1012 Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps))
1013 {
1014 COM_TRY_BEGIN
1015 _bonds.Clear();
1016 InitProps();
1017
1018 for (UInt32 i = 0; i < numProps; i++)
1019 {
1020 UString name = names[i];
1021 name.MakeLower_Ascii();
1022 if (name.IsEmpty())
1023 return E_INVALIDARG;
1024
1025 const PROPVARIANT &value = values[i];
1026
1027 if (name.Find(L':') >= 0) // 'b' was used as NCoderPropID::kBlockSize2 before v23
1028 if (name[0] == 'b')
1029 {
1030 if (value.vt != VT_EMPTY)
1031 return E_INVALIDARG;
1032 name.Delete(0);
1033
1034 CBond2 bond;
1035 RINOK(ParseBond(name, bond.OutCoder, bond.OutStream))
1036 if (name[0] != ':')
1037 return E_INVALIDARG;
1038 name.Delete(0);
1039 UInt32 inStream = 0;
1040 RINOK(ParseBond(name, bond.InCoder, inStream))
1041 if (inStream != 0)
1042 return E_INVALIDARG;
1043 if (!name.IsEmpty())
1044 return E_INVALIDARG;
1045 _bonds.Add(bond);
1046 continue;
1047 }
1048
1049 RINOK(SetProperty(name, value))
1050 }
1051
1052 unsigned numEmptyMethods = GetNumEmptyMethods();
1053 if (numEmptyMethods > 0)
1054 {
1055 unsigned k;
1056 for (k = 0; k < _bonds.Size(); k++)
1057 {
1058 const CBond2 &bond = _bonds[k];
1059 if (bond.InCoder < (UInt32)numEmptyMethods ||
1060 bond.OutCoder < (UInt32)numEmptyMethods)
1061 return E_INVALIDARG;
1062 }
1063 for (k = 0; k < _bonds.Size(); k++)
1064 {
1065 CBond2 &bond = _bonds[k];
1066 bond.InCoder -= (UInt32)numEmptyMethods;
1067 bond.OutCoder -= (UInt32)numEmptyMethods;
1068 }
1069 _methods.DeleteFrontal(numEmptyMethods);
1070 }
1071
1072 FOR_VECTOR (k, _bonds)
1073 {
1074 const CBond2 &bond = _bonds[k];
1075 if (bond.InCoder >= (UInt32)_methods.Size() ||
1076 bond.OutCoder >= (UInt32)_methods.Size())
1077 return E_INVALIDARG;
1078 }
1079
1080 return S_OK;
1081 COM_TRY_END
1082 }
1083
1084 }}
1085
1086 #endif
1087