1370b324cSopenharmony_ci// 7zHandlerOut.cpp
2370b324cSopenharmony_ci
3370b324cSopenharmony_ci#include "StdAfx.h"
4370b324cSopenharmony_ci
5370b324cSopenharmony_ci#include "../../../Common/ComTry.h"
6370b324cSopenharmony_ci#include "../../../Common/StringToInt.h"
7370b324cSopenharmony_ci#include "../../../Common/Wildcard.h"
8370b324cSopenharmony_ci
9370b324cSopenharmony_ci#include "../Common/ItemNameUtils.h"
10370b324cSopenharmony_ci#include "../Common/ParseProperties.h"
11370b324cSopenharmony_ci
12370b324cSopenharmony_ci#include "7zHandler.h"
13370b324cSopenharmony_ci#include "7zOut.h"
14370b324cSopenharmony_ci#include "7zUpdate.h"
15370b324cSopenharmony_ci
16370b324cSopenharmony_ci#ifndef Z7_EXTRACT_ONLY
17370b324cSopenharmony_ci
18370b324cSopenharmony_ciusing namespace NWindows;
19370b324cSopenharmony_ci
20370b324cSopenharmony_cinamespace NArchive {
21370b324cSopenharmony_cinamespace N7z {
22370b324cSopenharmony_ci
23370b324cSopenharmony_ci#define k_LZMA_Name "LZMA"
24370b324cSopenharmony_ci#define kDefaultMethodName "LZMA2"
25370b324cSopenharmony_ci#define k_Copy_Name "Copy"
26370b324cSopenharmony_ci
27370b324cSopenharmony_ci#define k_MatchFinder_ForHeaders "BT2"
28370b324cSopenharmony_ci
29370b324cSopenharmony_cistatic const UInt32 k_NumFastBytes_ForHeaders = 273;
30370b324cSopenharmony_cistatic const UInt32 k_Level_ForHeaders = 5;
31370b324cSopenharmony_cistatic const UInt32 k_Dictionary_ForHeaders =
32370b324cSopenharmony_ci  #ifdef UNDER_CE
33370b324cSopenharmony_ci  1 << 18;
34370b324cSopenharmony_ci  #else
35370b324cSopenharmony_ci  1 << 20;
36370b324cSopenharmony_ci  #endif
37370b324cSopenharmony_ci
38370b324cSopenharmony_ciZ7_COM7F_IMF(CHandler::GetFileTimeType(UInt32 *type))
39370b324cSopenharmony_ci{
40370b324cSopenharmony_ci  *type = NFileTimeType::kWindows;
41370b324cSopenharmony_ci  return S_OK;
42370b324cSopenharmony_ci}
43370b324cSopenharmony_ci
44370b324cSopenharmony_ciHRESULT CHandler::PropsMethod_To_FullMethod(CMethodFull &dest, const COneMethodInfo &m)
45370b324cSopenharmony_ci{
46370b324cSopenharmony_ci  bool isFilter;
47370b324cSopenharmony_ci  dest.CodecIndex = FindMethod_Index(
48370b324cSopenharmony_ci      EXTERNAL_CODECS_VARS
49370b324cSopenharmony_ci      m.MethodName, true,
50370b324cSopenharmony_ci      dest.Id, dest.NumStreams, isFilter);
51370b324cSopenharmony_ci  if (dest.CodecIndex < 0)
52370b324cSopenharmony_ci    return E_INVALIDARG;
53370b324cSopenharmony_ci  (CProps &)dest = (CProps &)m;
54370b324cSopenharmony_ci  return S_OK;
55370b324cSopenharmony_ci}
56370b324cSopenharmony_ci
57370b324cSopenharmony_ciHRESULT CHandler::SetHeaderMethod(CCompressionMethodMode &headerMethod)
58370b324cSopenharmony_ci{
59370b324cSopenharmony_ci  if (!_compressHeaders)
60370b324cSopenharmony_ci    return S_OK;
61370b324cSopenharmony_ci  COneMethodInfo m;
62370b324cSopenharmony_ci  m.MethodName = k_LZMA_Name;
63370b324cSopenharmony_ci  m.AddProp_Ascii(NCoderPropID::kMatchFinder, k_MatchFinder_ForHeaders);
64370b324cSopenharmony_ci  m.AddProp_Level(k_Level_ForHeaders);
65370b324cSopenharmony_ci  m.AddProp32(NCoderPropID::kNumFastBytes, k_NumFastBytes_ForHeaders);
66370b324cSopenharmony_ci  m.AddProp32(NCoderPropID::kDictionarySize, k_Dictionary_ForHeaders);
67370b324cSopenharmony_ci  m.AddProp_NumThreads(1);
68370b324cSopenharmony_ci
69370b324cSopenharmony_ci  CMethodFull &methodFull = headerMethod.Methods.AddNew();
70370b324cSopenharmony_ci  return PropsMethod_To_FullMethod(methodFull, m);
71370b324cSopenharmony_ci}
72370b324cSopenharmony_ci
73370b324cSopenharmony_ci
74370b324cSopenharmony_ciHRESULT CHandler::SetMainMethod(CCompressionMethodMode &methodMode)
75370b324cSopenharmony_ci{
76370b324cSopenharmony_ci  methodMode.Bonds = _bonds;
77370b324cSopenharmony_ci
78370b324cSopenharmony_ci  // we create local copy of _methods. So we can modify it.
79370b324cSopenharmony_ci  CObjectVector<COneMethodInfo> methods = _methods;
80370b324cSopenharmony_ci
81370b324cSopenharmony_ci  {
82370b324cSopenharmony_ci    FOR_VECTOR (i, methods)
83370b324cSopenharmony_ci    {
84370b324cSopenharmony_ci      AString &methodName = methods[i].MethodName;
85370b324cSopenharmony_ci      if (methodName.IsEmpty())
86370b324cSopenharmony_ci        methodName = kDefaultMethodName;
87370b324cSopenharmony_ci    }
88370b324cSopenharmony_ci    if (methods.IsEmpty())
89370b324cSopenharmony_ci    {
90370b324cSopenharmony_ci      COneMethodInfo &m = methods.AddNew();
91370b324cSopenharmony_ci      m.MethodName = (GetLevel() == 0 ? k_Copy_Name : kDefaultMethodName);
92370b324cSopenharmony_ci      methodMode.DefaultMethod_was_Inserted = true;
93370b324cSopenharmony_ci    }
94370b324cSopenharmony_ci  }
95370b324cSopenharmony_ci
96370b324cSopenharmony_ci  if (!_filterMethod.MethodName.IsEmpty())
97370b324cSopenharmony_ci  {
98370b324cSopenharmony_ci    // if (methodMode.Bonds.IsEmpty())
99370b324cSopenharmony_ci    {
100370b324cSopenharmony_ci      FOR_VECTOR (k, methodMode.Bonds)
101370b324cSopenharmony_ci      {
102370b324cSopenharmony_ci        CBond2 &bond = methodMode.Bonds[k];
103370b324cSopenharmony_ci        bond.InCoder++;
104370b324cSopenharmony_ci        bond.OutCoder++;
105370b324cSopenharmony_ci      }
106370b324cSopenharmony_ci      methods.Insert(0, _filterMethod);
107370b324cSopenharmony_ci      methodMode.Filter_was_Inserted = true;
108370b324cSopenharmony_ci    }
109370b324cSopenharmony_ci  }
110370b324cSopenharmony_ci
111370b324cSopenharmony_ci  const UInt64 kSolidBytes_Min = (1 << 24);
112370b324cSopenharmony_ci  const UInt64 kSolidBytes_Max = ((UInt64)1 << 32);
113370b324cSopenharmony_ci
114370b324cSopenharmony_ci  bool needSolid = false;
115370b324cSopenharmony_ci
116370b324cSopenharmony_ci  FOR_VECTOR (i, methods)
117370b324cSopenharmony_ci  {
118370b324cSopenharmony_ci    COneMethodInfo &oneMethodInfo = methods[i];
119370b324cSopenharmony_ci
120370b324cSopenharmony_ci    SetGlobalLevelTo(oneMethodInfo);
121370b324cSopenharmony_ci
122370b324cSopenharmony_ci    #ifndef Z7_ST
123370b324cSopenharmony_ci    const bool numThreads_WasSpecifiedInMethod = (oneMethodInfo.Get_NumThreads() >= 0);
124370b324cSopenharmony_ci    if (!numThreads_WasSpecifiedInMethod)
125370b324cSopenharmony_ci    {
126370b324cSopenharmony_ci      // here we set the (NCoderPropID::kNumThreads) property in each method, only if there is no such property already
127370b324cSopenharmony_ci      CMultiMethodProps::SetMethodThreadsTo_IfNotFinded(oneMethodInfo, methodMode.NumThreads);
128370b324cSopenharmony_ci    }
129370b324cSopenharmony_ci    #endif
130370b324cSopenharmony_ci
131370b324cSopenharmony_ci    CMethodFull &methodFull = methodMode.Methods.AddNew();
132370b324cSopenharmony_ci    RINOK(PropsMethod_To_FullMethod(methodFull, oneMethodInfo))
133370b324cSopenharmony_ci
134370b324cSopenharmony_ci    #ifndef Z7_ST
135370b324cSopenharmony_ci    methodFull.Set_NumThreads = true;
136370b324cSopenharmony_ci    methodFull.NumThreads = methodMode.NumThreads;
137370b324cSopenharmony_ci    #endif
138370b324cSopenharmony_ci
139370b324cSopenharmony_ci    if (methodFull.Id != k_Copy)
140370b324cSopenharmony_ci      needSolid = true;
141370b324cSopenharmony_ci
142370b324cSopenharmony_ci    UInt64 dicSize;
143370b324cSopenharmony_ci    switch (methodFull.Id)
144370b324cSopenharmony_ci    {
145370b324cSopenharmony_ci      case k_LZMA:
146370b324cSopenharmony_ci      case k_LZMA2: dicSize = oneMethodInfo.Get_Lzma_DicSize(); break;
147370b324cSopenharmony_ci      case k_PPMD: dicSize = oneMethodInfo.Get_Ppmd_MemSize(); break;
148370b324cSopenharmony_ci      case k_Deflate: dicSize = (UInt32)1 << 15; break;
149370b324cSopenharmony_ci      case k_Deflate64: dicSize = (UInt32)1 << 16; break;
150370b324cSopenharmony_ci      case k_BZip2: dicSize = oneMethodInfo.Get_BZip2_BlockSize(); break;
151370b324cSopenharmony_ci      // case k_ZSTD: dicSize = 1 << 23; break;
152370b324cSopenharmony_ci      default: continue;
153370b324cSopenharmony_ci    }
154370b324cSopenharmony_ci
155370b324cSopenharmony_ci    UInt64 numSolidBytes;
156370b324cSopenharmony_ci
157370b324cSopenharmony_ci    /*
158370b324cSopenharmony_ci    if (methodFull.Id == k_ZSTD)
159370b324cSopenharmony_ci    {
160370b324cSopenharmony_ci      // continue;
161370b324cSopenharmony_ci      NCompress::NZstd::CEncoderProps encoderProps;
162370b324cSopenharmony_ci      RINOK(oneMethodInfo.Set_PropsTo_zstd(encoderProps));
163370b324cSopenharmony_ci      CZstdEncProps &zstdProps = encoderProps.EncProps;
164370b324cSopenharmony_ci      ZstdEncProps_NormalizeFull(&zstdProps);
165370b324cSopenharmony_ci      UInt64 cs = (UInt64)(zstdProps.jobSize);
166370b324cSopenharmony_ci      UInt32 winSize = (UInt32)(1 << zstdProps.windowLog);
167370b324cSopenharmony_ci      if (cs < winSize)
168370b324cSopenharmony_ci        cs = winSize;
169370b324cSopenharmony_ci      numSolidBytes = cs << 6;
170370b324cSopenharmony_ci      const UInt64 kSolidBytes_Zstd_Max = ((UInt64)1 << 34);
171370b324cSopenharmony_ci      if (numSolidBytes > kSolidBytes_Zstd_Max)
172370b324cSopenharmony_ci        numSolidBytes = kSolidBytes_Zstd_Max;
173370b324cSopenharmony_ci
174370b324cSopenharmony_ci      methodFull.Set_NumThreads = false; // we don't use ICompressSetCoderMt::SetNumberOfThreads() for LZMA2 encoder
175370b324cSopenharmony_ci
176370b324cSopenharmony_ci      #ifndef Z7_ST
177370b324cSopenharmony_ci      if (!numThreads_WasSpecifiedInMethod
178370b324cSopenharmony_ci          && !methodMode.NumThreads_WasForced
179370b324cSopenharmony_ci          && methodMode.MemoryUsageLimit_WasSet
180370b324cSopenharmony_ci          )
181370b324cSopenharmony_ci      {
182370b324cSopenharmony_ci        const UInt32 numThreads_Original = methodMode.NumThreads;
183370b324cSopenharmony_ci        const UInt32 numThreads_New = ZstdEncProps_GetNumThreads_for_MemUsageLimit(
184370b324cSopenharmony_ci            &zstdProps,
185370b324cSopenharmony_ci            methodMode.MemoryUsageLimit,
186370b324cSopenharmony_ci            numThreads_Original);
187370b324cSopenharmony_ci        if (numThreads_Original != numThreads_New)
188370b324cSopenharmony_ci        {
189370b324cSopenharmony_ci          CMultiMethodProps::SetMethodThreadsTo_Replace(methodFull, numThreads_New);
190370b324cSopenharmony_ci        }
191370b324cSopenharmony_ci      }
192370b324cSopenharmony_ci      #endif
193370b324cSopenharmony_ci    }
194370b324cSopenharmony_ci    else
195370b324cSopenharmony_ci    */
196370b324cSopenharmony_ci    if (methodFull.Id == k_LZMA2)
197370b324cSopenharmony_ci    {
198370b324cSopenharmony_ci      // he we calculate default chunk Size for LZMA2 as defined in LZMA2 encoder code
199370b324cSopenharmony_ci      /* lzma2 code use dictionary up to fake 4 GiB to calculate ChunkSize.
200370b324cSopenharmony_ci         So we do same */
201370b324cSopenharmony_ci      UInt64 cs = (UInt64)dicSize << 2;
202370b324cSopenharmony_ci      const UInt32 kMinSize = (UInt32)1 << 20;
203370b324cSopenharmony_ci      const UInt32 kMaxSize = (UInt32)1 << 28;
204370b324cSopenharmony_ci      if (cs < kMinSize) cs = kMinSize;
205370b324cSopenharmony_ci      if (cs > kMaxSize) cs = kMaxSize;
206370b324cSopenharmony_ci      if (cs < dicSize) cs = dicSize;
207370b324cSopenharmony_ci      cs += (kMinSize - 1);
208370b324cSopenharmony_ci      cs &= ~(UInt64)(kMinSize - 1);
209370b324cSopenharmony_ci      // we want to use at least 64 chunks (threads) per one solid block.
210370b324cSopenharmony_ci
211370b324cSopenharmony_ci      // here we don't use chunkSize property
212370b324cSopenharmony_ci      numSolidBytes = cs << 6;
213370b324cSopenharmony_ci
214370b324cSopenharmony_ci      // here we get real chunkSize
215370b324cSopenharmony_ci      cs = oneMethodInfo.Get_Xz_BlockSize();
216370b324cSopenharmony_ci      if (dicSize > cs)
217370b324cSopenharmony_ci        dicSize = cs;
218370b324cSopenharmony_ci
219370b324cSopenharmony_ci      const UInt64 kSolidBytes_Lzma2_Max = ((UInt64)1 << 34);
220370b324cSopenharmony_ci      if (numSolidBytes > kSolidBytes_Lzma2_Max)
221370b324cSopenharmony_ci        numSolidBytes = kSolidBytes_Lzma2_Max;
222370b324cSopenharmony_ci
223370b324cSopenharmony_ci      methodFull.Set_NumThreads = false; // we don't use ICompressSetCoderMt::SetNumberOfThreads() for LZMA2 encoder
224370b324cSopenharmony_ci
225370b324cSopenharmony_ci      #ifndef Z7_ST
226370b324cSopenharmony_ci      if (!numThreads_WasSpecifiedInMethod
227370b324cSopenharmony_ci          && !methodMode.NumThreads_WasForced
228370b324cSopenharmony_ci          && methodMode.MemoryUsageLimit_WasSet
229370b324cSopenharmony_ci          )
230370b324cSopenharmony_ci      {
231370b324cSopenharmony_ci        const UInt32 lzmaThreads = oneMethodInfo.Get_Lzma_NumThreads();
232370b324cSopenharmony_ci        const UInt32 numBlockThreads_Original = methodMode.NumThreads / lzmaThreads;
233370b324cSopenharmony_ci
234370b324cSopenharmony_ci        if (numBlockThreads_Original > 1)
235370b324cSopenharmony_ci        {
236370b324cSopenharmony_ci          /*
237370b324cSopenharmony_ci            const UInt32 kNumThreads_Max = 1024;
238370b324cSopenharmony_ci            if (numBlockThreads > kNumMaxThreads)
239370b324cSopenharmony_ci            numBlockThreads = kNumMaxThreads;
240370b324cSopenharmony_ci          */
241370b324cSopenharmony_ci
242370b324cSopenharmony_ci          UInt32 numBlockThreads = numBlockThreads_Original;
243370b324cSopenharmony_ci          const UInt64 lzmaMemUsage = oneMethodInfo.Get_Lzma_MemUsage(false); // solid
244370b324cSopenharmony_ci
245370b324cSopenharmony_ci          for (; numBlockThreads > 1; numBlockThreads--)
246370b324cSopenharmony_ci          {
247370b324cSopenharmony_ci            UInt64 size = numBlockThreads * (lzmaMemUsage + cs);
248370b324cSopenharmony_ci            UInt32 numPackChunks = numBlockThreads + (numBlockThreads / 8) + 1;
249370b324cSopenharmony_ci            if (cs < ((UInt32)1 << 26)) numPackChunks++;
250370b324cSopenharmony_ci            if (cs < ((UInt32)1 << 24)) numPackChunks++;
251370b324cSopenharmony_ci            if (cs < ((UInt32)1 << 22)) numPackChunks++;
252370b324cSopenharmony_ci            size += numPackChunks * cs;
253370b324cSopenharmony_ci            // printf("\nnumBlockThreads = %d, size = %d\n", (unsigned)(numBlockThreads), (unsigned)(size >> 20));
254370b324cSopenharmony_ci            if (size <= methodMode.MemoryUsageLimit)
255370b324cSopenharmony_ci              break;
256370b324cSopenharmony_ci          }
257370b324cSopenharmony_ci
258370b324cSopenharmony_ci          if (numBlockThreads == 0)
259370b324cSopenharmony_ci            numBlockThreads = 1;
260370b324cSopenharmony_ci          if (numBlockThreads != numBlockThreads_Original)
261370b324cSopenharmony_ci          {
262370b324cSopenharmony_ci            const UInt32 numThreads_New = numBlockThreads * lzmaThreads;
263370b324cSopenharmony_ci            CMultiMethodProps::SetMethodThreadsTo_Replace(methodFull, numThreads_New);
264370b324cSopenharmony_ci          }
265370b324cSopenharmony_ci        }
266370b324cSopenharmony_ci      }
267370b324cSopenharmony_ci      #endif
268370b324cSopenharmony_ci    }
269370b324cSopenharmony_ci    else
270370b324cSopenharmony_ci    {
271370b324cSopenharmony_ci      numSolidBytes = (UInt64)dicSize << 7;
272370b324cSopenharmony_ci      if (numSolidBytes > kSolidBytes_Max)
273370b324cSopenharmony_ci        numSolidBytes = kSolidBytes_Max;
274370b324cSopenharmony_ci    }
275370b324cSopenharmony_ci
276370b324cSopenharmony_ci    if (_numSolidBytesDefined)
277370b324cSopenharmony_ci      continue;
278370b324cSopenharmony_ci
279370b324cSopenharmony_ci    if (numSolidBytes < kSolidBytes_Min)
280370b324cSopenharmony_ci      numSolidBytes = kSolidBytes_Min;
281370b324cSopenharmony_ci    _numSolidBytes = numSolidBytes;
282370b324cSopenharmony_ci    _numSolidBytesDefined = true;
283370b324cSopenharmony_ci  }
284370b324cSopenharmony_ci
285370b324cSopenharmony_ci  if (!_numSolidBytesDefined)
286370b324cSopenharmony_ci  {
287370b324cSopenharmony_ci    if (needSolid)
288370b324cSopenharmony_ci      _numSolidBytes = kSolidBytes_Max;
289370b324cSopenharmony_ci    else
290370b324cSopenharmony_ci      _numSolidBytes = 0;
291370b324cSopenharmony_ci  }
292370b324cSopenharmony_ci  _numSolidBytesDefined = true;
293370b324cSopenharmony_ci
294370b324cSopenharmony_ci
295370b324cSopenharmony_ci  return S_OK;
296370b324cSopenharmony_ci}
297370b324cSopenharmony_ci
298370b324cSopenharmony_ci
299370b324cSopenharmony_ci
300370b324cSopenharmony_cistatic HRESULT GetTime(IArchiveUpdateCallback *updateCallback, unsigned index, PROPID propID, UInt64 &ft, bool &ftDefined)
301370b324cSopenharmony_ci{
302370b324cSopenharmony_ci  // ft = 0;
303370b324cSopenharmony_ci  // ftDefined = false;
304370b324cSopenharmony_ci  NCOM::CPropVariant prop;
305370b324cSopenharmony_ci  RINOK(updateCallback->GetProperty(index, propID, &prop))
306370b324cSopenharmony_ci  if (prop.vt == VT_FILETIME)
307370b324cSopenharmony_ci  {
308370b324cSopenharmony_ci    ft = prop.filetime.dwLowDateTime | ((UInt64)prop.filetime.dwHighDateTime << 32);
309370b324cSopenharmony_ci    ftDefined = true;
310370b324cSopenharmony_ci  }
311370b324cSopenharmony_ci  else if (prop.vt != VT_EMPTY)
312370b324cSopenharmony_ci    return E_INVALIDARG;
313370b324cSopenharmony_ci  else
314370b324cSopenharmony_ci  {
315370b324cSopenharmony_ci    ft = 0;
316370b324cSopenharmony_ci    ftDefined = false;
317370b324cSopenharmony_ci  }
318370b324cSopenharmony_ci  return S_OK;
319370b324cSopenharmony_ci}
320370b324cSopenharmony_ci
321370b324cSopenharmony_ci/*
322370b324cSopenharmony_ci
323370b324cSopenharmony_ci#ifdef _WIN32
324370b324cSopenharmony_cistatic const wchar_t kDirDelimiter1 = L'\\';
325370b324cSopenharmony_ci#endif
326370b324cSopenharmony_cistatic const wchar_t kDirDelimiter2 = L'/';
327370b324cSopenharmony_ci
328370b324cSopenharmony_cistatic inline bool IsCharDirLimiter(wchar_t c)
329370b324cSopenharmony_ci{
330370b324cSopenharmony_ci  return (
331370b324cSopenharmony_ci    #ifdef _WIN32
332370b324cSopenharmony_ci    c == kDirDelimiter1 ||
333370b324cSopenharmony_ci    #endif
334370b324cSopenharmony_ci    c == kDirDelimiter2);
335370b324cSopenharmony_ci}
336370b324cSopenharmony_ci
337370b324cSopenharmony_cistatic int FillSortIndex(CObjectVector<CTreeFolder> &treeFolders, int cur, int curSortIndex)
338370b324cSopenharmony_ci{
339370b324cSopenharmony_ci  CTreeFolder &tf = treeFolders[cur];
340370b324cSopenharmony_ci  tf.SortIndex = curSortIndex++;
341370b324cSopenharmony_ci  for (int i = 0; i < tf.SubFolders.Size(); i++)
342370b324cSopenharmony_ci    curSortIndex = FillSortIndex(treeFolders, tf.SubFolders[i], curSortIndex);
343370b324cSopenharmony_ci  tf.SortIndexEnd = curSortIndex;
344370b324cSopenharmony_ci  return curSortIndex;
345370b324cSopenharmony_ci}
346370b324cSopenharmony_ci
347370b324cSopenharmony_cistatic int FindSubFolder(const CObjectVector<CTreeFolder> &treeFolders, int cur, const UString &name, int &insertPos)
348370b324cSopenharmony_ci{
349370b324cSopenharmony_ci  const CIntVector &subFolders = treeFolders[cur].SubFolders;
350370b324cSopenharmony_ci  int left = 0, right = subFolders.Size();
351370b324cSopenharmony_ci  insertPos = -1;
352370b324cSopenharmony_ci  for (;;)
353370b324cSopenharmony_ci  {
354370b324cSopenharmony_ci    if (left == right)
355370b324cSopenharmony_ci    {
356370b324cSopenharmony_ci      insertPos = left;
357370b324cSopenharmony_ci      return -1;
358370b324cSopenharmony_ci    }
359370b324cSopenharmony_ci    int mid = (left + right) / 2;
360370b324cSopenharmony_ci    int midFolder = subFolders[mid];
361370b324cSopenharmony_ci    int compare = CompareFileNames(name, treeFolders[midFolder].Name);
362370b324cSopenharmony_ci    if (compare == 0)
363370b324cSopenharmony_ci      return midFolder;
364370b324cSopenharmony_ci    if (compare < 0)
365370b324cSopenharmony_ci      right = mid;
366370b324cSopenharmony_ci    else
367370b324cSopenharmony_ci      left = mid + 1;
368370b324cSopenharmony_ci  }
369370b324cSopenharmony_ci}
370370b324cSopenharmony_ci
371370b324cSopenharmony_cistatic int AddFolder(CObjectVector<CTreeFolder> &treeFolders, int cur, const UString &name)
372370b324cSopenharmony_ci{
373370b324cSopenharmony_ci  int insertPos;
374370b324cSopenharmony_ci  int folderIndex = FindSubFolder(treeFolders, cur, name, insertPos);
375370b324cSopenharmony_ci  if (folderIndex < 0)
376370b324cSopenharmony_ci  {
377370b324cSopenharmony_ci    folderIndex = treeFolders.Size();
378370b324cSopenharmony_ci    CTreeFolder &newFolder = treeFolders.AddNew();
379370b324cSopenharmony_ci    newFolder.Parent = cur;
380370b324cSopenharmony_ci    newFolder.Name = name;
381370b324cSopenharmony_ci    treeFolders[cur].SubFolders.Insert(insertPos, folderIndex);
382370b324cSopenharmony_ci  }
383370b324cSopenharmony_ci  // else if (treeFolders[folderIndex].IsAltStreamFolder != isAltStreamFolder) throw 1123234234;
384370b324cSopenharmony_ci  return folderIndex;
385370b324cSopenharmony_ci}
386370b324cSopenharmony_ci*/
387370b324cSopenharmony_ci
388370b324cSopenharmony_ciZ7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
389370b324cSopenharmony_ci    IArchiveUpdateCallback *updateCallback))
390370b324cSopenharmony_ci{
391370b324cSopenharmony_ci  COM_TRY_BEGIN
392370b324cSopenharmony_ci
393370b324cSopenharmony_ci  const CDbEx *db = NULL;
394370b324cSopenharmony_ci  #ifdef Z7_7Z_VOL
395370b324cSopenharmony_ci  if (_volumes.Size() > 1)
396370b324cSopenharmony_ci    return E_FAIL;
397370b324cSopenharmony_ci  const CVolume *volume = 0;
398370b324cSopenharmony_ci  if (_volumes.Size() == 1)
399370b324cSopenharmony_ci  {
400370b324cSopenharmony_ci    volume = &_volumes.Front();
401370b324cSopenharmony_ci    db = &volume->Database;
402370b324cSopenharmony_ci  }
403370b324cSopenharmony_ci  #else
404370b324cSopenharmony_ci  if (_inStream)
405370b324cSopenharmony_ci    db = &_db;
406370b324cSopenharmony_ci  #endif
407370b324cSopenharmony_ci
408370b324cSopenharmony_ci  if (db && !db->CanUpdate())
409370b324cSopenharmony_ci    return E_NOTIMPL;
410370b324cSopenharmony_ci
411370b324cSopenharmony_ci  /*
412370b324cSopenharmony_ci  Z7_DECL_CMyComPtr_QI_FROM(
413370b324cSopenharmony_ci      IArchiveGetRawProps,
414370b324cSopenharmony_ci      getRawProps, updateCallback)
415370b324cSopenharmony_ci
416370b324cSopenharmony_ci  CUniqBlocks secureBlocks;
417370b324cSopenharmony_ci  secureBlocks.AddUniq(NULL, 0);
418370b324cSopenharmony_ci
419370b324cSopenharmony_ci  CObjectVector<CTreeFolder> treeFolders;
420370b324cSopenharmony_ci  {
421370b324cSopenharmony_ci    CTreeFolder folder;
422370b324cSopenharmony_ci    folder.Parent = -1;
423370b324cSopenharmony_ci    treeFolders.Add(folder);
424370b324cSopenharmony_ci  }
425370b324cSopenharmony_ci  */
426370b324cSopenharmony_ci
427370b324cSopenharmony_ci  CObjectVector<CUpdateItem> updateItems;
428370b324cSopenharmony_ci
429370b324cSopenharmony_ci  bool need_CTime = (TimeOptions.Write_CTime.Def && TimeOptions.Write_CTime.Val);
430370b324cSopenharmony_ci  bool need_ATime = (TimeOptions.Write_ATime.Def && TimeOptions.Write_ATime.Val);
431370b324cSopenharmony_ci  bool need_MTime = (TimeOptions.Write_MTime.Def ? TimeOptions.Write_MTime.Val : true);
432370b324cSopenharmony_ci  bool need_Attrib = (Write_Attrib.Def ? Write_Attrib.Val : true);
433370b324cSopenharmony_ci
434370b324cSopenharmony_ci  if (db && !db->Files.IsEmpty())
435370b324cSopenharmony_ci  {
436370b324cSopenharmony_ci    if (!TimeOptions.Write_CTime.Def) need_CTime = !db->CTime.Defs.IsEmpty();
437370b324cSopenharmony_ci    if (!TimeOptions.Write_ATime.Def) need_ATime = !db->ATime.Defs.IsEmpty();
438370b324cSopenharmony_ci    if (!TimeOptions.Write_MTime.Def) need_MTime = !db->MTime.Defs.IsEmpty();
439370b324cSopenharmony_ci    if (!Write_Attrib.Def) need_Attrib = !db->Attrib.Defs.IsEmpty();
440370b324cSopenharmony_ci  }
441370b324cSopenharmony_ci
442370b324cSopenharmony_ci  // UString s;
443370b324cSopenharmony_ci  UString name;
444370b324cSopenharmony_ci
445370b324cSopenharmony_ci  for (UInt32 i = 0; i < numItems; i++)
446370b324cSopenharmony_ci  {
447370b324cSopenharmony_ci    Int32 newData, newProps;
448370b324cSopenharmony_ci    UInt32 indexInArchive;
449370b324cSopenharmony_ci    if (!updateCallback)
450370b324cSopenharmony_ci      return E_FAIL;
451370b324cSopenharmony_ci    RINOK(updateCallback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArchive))
452370b324cSopenharmony_ci    CUpdateItem ui;
453370b324cSopenharmony_ci    ui.NewProps = IntToBool(newProps);
454370b324cSopenharmony_ci    ui.NewData = IntToBool(newData);
455370b324cSopenharmony_ci    ui.IndexInArchive = (int)indexInArchive;
456370b324cSopenharmony_ci    ui.IndexInClient = i;
457370b324cSopenharmony_ci    ui.IsAnti = false;
458370b324cSopenharmony_ci    ui.Size = 0;
459370b324cSopenharmony_ci
460370b324cSopenharmony_ci    name.Empty();
461370b324cSopenharmony_ci    // bool isAltStream = false;
462370b324cSopenharmony_ci    if (ui.IndexInArchive != -1)
463370b324cSopenharmony_ci    {
464370b324cSopenharmony_ci      if (!db || (unsigned)ui.IndexInArchive >= db->Files.Size())
465370b324cSopenharmony_ci        return E_INVALIDARG;
466370b324cSopenharmony_ci      const CFileItem &fi = db->Files[(unsigned)ui.IndexInArchive];
467370b324cSopenharmony_ci      if (!ui.NewProps)
468370b324cSopenharmony_ci      {
469370b324cSopenharmony_ci        _db.GetPath((unsigned)ui.IndexInArchive, name);
470370b324cSopenharmony_ci      }
471370b324cSopenharmony_ci      ui.IsDir = fi.IsDir;
472370b324cSopenharmony_ci      ui.Size = fi.Size;
473370b324cSopenharmony_ci      // isAltStream = fi.IsAltStream;
474370b324cSopenharmony_ci      ui.IsAnti = db->IsItemAnti((unsigned)ui.IndexInArchive);
475370b324cSopenharmony_ci
476370b324cSopenharmony_ci      if (!ui.NewProps)
477370b324cSopenharmony_ci      {
478370b324cSopenharmony_ci        ui.CTimeDefined = db->CTime.GetItem((unsigned)ui.IndexInArchive, ui.CTime);
479370b324cSopenharmony_ci        ui.ATimeDefined = db->ATime.GetItem((unsigned)ui.IndexInArchive, ui.ATime);
480370b324cSopenharmony_ci        ui.MTimeDefined = db->MTime.GetItem((unsigned)ui.IndexInArchive, ui.MTime);
481370b324cSopenharmony_ci      }
482370b324cSopenharmony_ci    }
483370b324cSopenharmony_ci
484370b324cSopenharmony_ci    if (ui.NewProps)
485370b324cSopenharmony_ci    {
486370b324cSopenharmony_ci      bool folderStatusIsDefined;
487370b324cSopenharmony_ci      if (need_Attrib)
488370b324cSopenharmony_ci      {
489370b324cSopenharmony_ci        NCOM::CPropVariant prop;
490370b324cSopenharmony_ci        RINOK(updateCallback->GetProperty(i, kpidAttrib, &prop))
491370b324cSopenharmony_ci        if (prop.vt == VT_EMPTY)
492370b324cSopenharmony_ci          ui.AttribDefined = false;
493370b324cSopenharmony_ci        else if (prop.vt != VT_UI4)
494370b324cSopenharmony_ci          return E_INVALIDARG;
495370b324cSopenharmony_ci        else
496370b324cSopenharmony_ci        {
497370b324cSopenharmony_ci          ui.Attrib = prop.ulVal;
498370b324cSopenharmony_ci          ui.AttribDefined = true;
499370b324cSopenharmony_ci        }
500370b324cSopenharmony_ci      }
501370b324cSopenharmony_ci
502370b324cSopenharmony_ci      // we need MTime to sort files.
503370b324cSopenharmony_ci      if (need_CTime) RINOK(GetTime(updateCallback, i, kpidCTime, ui.CTime, ui.CTimeDefined))
504370b324cSopenharmony_ci      if (need_ATime) RINOK(GetTime(updateCallback, i, kpidATime, ui.ATime, ui.ATimeDefined))
505370b324cSopenharmony_ci      if (need_MTime) RINOK(GetTime(updateCallback, i, kpidMTime, ui.MTime, ui.MTimeDefined))
506370b324cSopenharmony_ci
507370b324cSopenharmony_ci      /*
508370b324cSopenharmony_ci      if (getRawProps)
509370b324cSopenharmony_ci      {
510370b324cSopenharmony_ci        const void *data;
511370b324cSopenharmony_ci        UInt32 dataSize;
512370b324cSopenharmony_ci        UInt32 propType;
513370b324cSopenharmony_ci
514370b324cSopenharmony_ci        getRawProps->GetRawProp(i, kpidNtSecure, &data, &dataSize, &propType);
515370b324cSopenharmony_ci        if (dataSize != 0 && propType != NPropDataType::kRaw)
516370b324cSopenharmony_ci          return E_FAIL;
517370b324cSopenharmony_ci        ui.SecureIndex = secureBlocks.AddUniq((const Byte *)data, dataSize);
518370b324cSopenharmony_ci      }
519370b324cSopenharmony_ci      */
520370b324cSopenharmony_ci
521370b324cSopenharmony_ci      {
522370b324cSopenharmony_ci        NCOM::CPropVariant prop;
523370b324cSopenharmony_ci        RINOK(updateCallback->GetProperty(i, kpidPath, &prop))
524370b324cSopenharmony_ci        if (prop.vt == VT_EMPTY)
525370b324cSopenharmony_ci        {
526370b324cSopenharmony_ci        }
527370b324cSopenharmony_ci        else if (prop.vt != VT_BSTR)
528370b324cSopenharmony_ci          return E_INVALIDARG;
529370b324cSopenharmony_ci        else
530370b324cSopenharmony_ci        {
531370b324cSopenharmony_ci          name = prop.bstrVal;
532370b324cSopenharmony_ci          NItemName::ReplaceSlashes_OsToUnix(name);
533370b324cSopenharmony_ci        }
534370b324cSopenharmony_ci      }
535370b324cSopenharmony_ci      {
536370b324cSopenharmony_ci        NCOM::CPropVariant prop;
537370b324cSopenharmony_ci        RINOK(updateCallback->GetProperty(i, kpidIsDir, &prop))
538370b324cSopenharmony_ci        if (prop.vt == VT_EMPTY)
539370b324cSopenharmony_ci          folderStatusIsDefined = false;
540370b324cSopenharmony_ci        else if (prop.vt != VT_BOOL)
541370b324cSopenharmony_ci          return E_INVALIDARG;
542370b324cSopenharmony_ci        else
543370b324cSopenharmony_ci        {
544370b324cSopenharmony_ci          ui.IsDir = (prop.boolVal != VARIANT_FALSE);
545370b324cSopenharmony_ci          folderStatusIsDefined = true;
546370b324cSopenharmony_ci        }
547370b324cSopenharmony_ci      }
548370b324cSopenharmony_ci
549370b324cSopenharmony_ci      {
550370b324cSopenharmony_ci        NCOM::CPropVariant prop;
551370b324cSopenharmony_ci        RINOK(updateCallback->GetProperty(i, kpidIsAnti, &prop))
552370b324cSopenharmony_ci        if (prop.vt == VT_EMPTY)
553370b324cSopenharmony_ci          ui.IsAnti = false;
554370b324cSopenharmony_ci        else if (prop.vt != VT_BOOL)
555370b324cSopenharmony_ci          return E_INVALIDARG;
556370b324cSopenharmony_ci        else
557370b324cSopenharmony_ci          ui.IsAnti = (prop.boolVal != VARIANT_FALSE);
558370b324cSopenharmony_ci      }
559370b324cSopenharmony_ci
560370b324cSopenharmony_ci      /*
561370b324cSopenharmony_ci      {
562370b324cSopenharmony_ci        NCOM::CPropVariant prop;
563370b324cSopenharmony_ci        RINOK(updateCallback->GetProperty(i, kpidIsAltStream, &prop));
564370b324cSopenharmony_ci        if (prop.vt == VT_EMPTY)
565370b324cSopenharmony_ci          isAltStream = false;
566370b324cSopenharmony_ci        else if (prop.vt != VT_BOOL)
567370b324cSopenharmony_ci          return E_INVALIDARG;
568370b324cSopenharmony_ci        else
569370b324cSopenharmony_ci          isAltStream = (prop.boolVal != VARIANT_FALSE);
570370b324cSopenharmony_ci      }
571370b324cSopenharmony_ci      */
572370b324cSopenharmony_ci
573370b324cSopenharmony_ci      if (ui.IsAnti)
574370b324cSopenharmony_ci      {
575370b324cSopenharmony_ci        ui.AttribDefined = false;
576370b324cSopenharmony_ci
577370b324cSopenharmony_ci        ui.CTimeDefined = false;
578370b324cSopenharmony_ci        ui.ATimeDefined = false;
579370b324cSopenharmony_ci        ui.MTimeDefined = false;
580370b324cSopenharmony_ci
581370b324cSopenharmony_ci        ui.Size = 0;
582370b324cSopenharmony_ci      }
583370b324cSopenharmony_ci
584370b324cSopenharmony_ci      if (!folderStatusIsDefined && ui.AttribDefined)
585370b324cSopenharmony_ci        ui.SetDirStatusFromAttrib();
586370b324cSopenharmony_ci    }
587370b324cSopenharmony_ci    else
588370b324cSopenharmony_ci    {
589370b324cSopenharmony_ci      /*
590370b324cSopenharmony_ci      if (_db.SecureIDs.IsEmpty())
591370b324cSopenharmony_ci        ui.SecureIndex = secureBlocks.AddUniq(NULL, 0);
592370b324cSopenharmony_ci      else
593370b324cSopenharmony_ci      {
594370b324cSopenharmony_ci        int id = _db.SecureIDs[ui.IndexInArchive];
595370b324cSopenharmony_ci        size_t offs = _db.SecureOffsets[id];
596370b324cSopenharmony_ci        size_t size = _db.SecureOffsets[id + 1] - offs;
597370b324cSopenharmony_ci        ui.SecureIndex = secureBlocks.AddUniq(_db.SecureBuf + offs, size);
598370b324cSopenharmony_ci      }
599370b324cSopenharmony_ci      */
600370b324cSopenharmony_ci    }
601370b324cSopenharmony_ci
602370b324cSopenharmony_ci    /*
603370b324cSopenharmony_ci    {
604370b324cSopenharmony_ci      int folderIndex = 0;
605370b324cSopenharmony_ci      if (_useParents)
606370b324cSopenharmony_ci      {
607370b324cSopenharmony_ci        int j;
608370b324cSopenharmony_ci        s.Empty();
609370b324cSopenharmony_ci        for (j = 0; j < name.Len(); j++)
610370b324cSopenharmony_ci        {
611370b324cSopenharmony_ci          wchar_t c = name[j];
612370b324cSopenharmony_ci          if (IsCharDirLimiter(c))
613370b324cSopenharmony_ci          {
614370b324cSopenharmony_ci            folderIndex = AddFolder(treeFolders, folderIndex, s);
615370b324cSopenharmony_ci            s.Empty();
616370b324cSopenharmony_ci            continue;
617370b324cSopenharmony_ci          }
618370b324cSopenharmony_ci          s += c;
619370b324cSopenharmony_ci        }
620370b324cSopenharmony_ci        if (isAltStream)
621370b324cSopenharmony_ci        {
622370b324cSopenharmony_ci          int colonPos = s.Find(':');
623370b324cSopenharmony_ci          if (colonPos < 0)
624370b324cSopenharmony_ci          {
625370b324cSopenharmony_ci            // isAltStream = false;
626370b324cSopenharmony_ci            return E_INVALIDARG;
627370b324cSopenharmony_ci          }
628370b324cSopenharmony_ci          UString mainName = s.Left(colonPos);
629370b324cSopenharmony_ci          int newFolderIndex = AddFolder(treeFolders, folderIndex, mainName);
630370b324cSopenharmony_ci          if (treeFolders[newFolderIndex].UpdateItemIndex < 0)
631370b324cSopenharmony_ci          {
632370b324cSopenharmony_ci            for (int j = updateItems.Size() - 1; j >= 0; j--)
633370b324cSopenharmony_ci            {
634370b324cSopenharmony_ci              CUpdateItem &ui2 = updateItems[j];
635370b324cSopenharmony_ci              if (ui2.ParentFolderIndex == folderIndex
636370b324cSopenharmony_ci                  && ui2.Name == mainName)
637370b324cSopenharmony_ci              {
638370b324cSopenharmony_ci                ui2.TreeFolderIndex = newFolderIndex;
639370b324cSopenharmony_ci                treeFolders[newFolderIndex].UpdateItemIndex = j;
640370b324cSopenharmony_ci              }
641370b324cSopenharmony_ci            }
642370b324cSopenharmony_ci          }
643370b324cSopenharmony_ci          folderIndex = newFolderIndex;
644370b324cSopenharmony_ci          s.Delete(0, colonPos + 1);
645370b324cSopenharmony_ci        }
646370b324cSopenharmony_ci        ui.Name = s;
647370b324cSopenharmony_ci      }
648370b324cSopenharmony_ci      else
649370b324cSopenharmony_ci        ui.Name = name;
650370b324cSopenharmony_ci      ui.IsAltStream = isAltStream;
651370b324cSopenharmony_ci      ui.ParentFolderIndex = folderIndex;
652370b324cSopenharmony_ci      ui.TreeFolderIndex = -1;
653370b324cSopenharmony_ci      if (ui.IsDir && !s.IsEmpty())
654370b324cSopenharmony_ci      {
655370b324cSopenharmony_ci        ui.TreeFolderIndex = AddFolder(treeFolders, folderIndex, s);
656370b324cSopenharmony_ci        treeFolders[ui.TreeFolderIndex].UpdateItemIndex = updateItems.Size();
657370b324cSopenharmony_ci      }
658370b324cSopenharmony_ci    }
659370b324cSopenharmony_ci    */
660370b324cSopenharmony_ci    ui.Name = name;
661370b324cSopenharmony_ci
662370b324cSopenharmony_ci    if (ui.NewData)
663370b324cSopenharmony_ci    {
664370b324cSopenharmony_ci      ui.Size = 0;
665370b324cSopenharmony_ci      if (!ui.IsDir)
666370b324cSopenharmony_ci      {
667370b324cSopenharmony_ci        NCOM::CPropVariant prop;
668370b324cSopenharmony_ci        RINOK(updateCallback->GetProperty(i, kpidSize, &prop))
669370b324cSopenharmony_ci        if (prop.vt != VT_UI8)
670370b324cSopenharmony_ci          return E_INVALIDARG;
671370b324cSopenharmony_ci        ui.Size = (UInt64)prop.uhVal.QuadPart;
672370b324cSopenharmony_ci        if (ui.Size != 0 && ui.IsAnti)
673370b324cSopenharmony_ci          return E_INVALIDARG;
674370b324cSopenharmony_ci      }
675370b324cSopenharmony_ci    }
676370b324cSopenharmony_ci
677370b324cSopenharmony_ci    updateItems.Add(ui);
678370b324cSopenharmony_ci  }
679370b324cSopenharmony_ci
680370b324cSopenharmony_ci  /*
681370b324cSopenharmony_ci  FillSortIndex(treeFolders, 0, 0);
682370b324cSopenharmony_ci  for (i = 0; i < (UInt32)updateItems.Size(); i++)
683370b324cSopenharmony_ci  {
684370b324cSopenharmony_ci    CUpdateItem &ui = updateItems[i];
685370b324cSopenharmony_ci    ui.ParentSortIndex = treeFolders[ui.ParentFolderIndex].SortIndex;
686370b324cSopenharmony_ci    ui.ParentSortIndexEnd = treeFolders[ui.ParentFolderIndex].SortIndexEnd;
687370b324cSopenharmony_ci  }
688370b324cSopenharmony_ci  */
689370b324cSopenharmony_ci
690370b324cSopenharmony_ci  CCompressionMethodMode methodMode, headerMethod;
691370b324cSopenharmony_ci
692370b324cSopenharmony_ci  methodMode.MemoryUsageLimit = _memUsage_Compress;
693370b324cSopenharmony_ci  methodMode.MemoryUsageLimit_WasSet = _memUsage_WasSet;
694370b324cSopenharmony_ci
695370b324cSopenharmony_ci  #ifndef Z7_ST
696370b324cSopenharmony_ci  {
697370b324cSopenharmony_ci    UInt32 numThreads = _numThreads;
698370b324cSopenharmony_ci    const UInt32 kNumThreads_Max = 1024;
699370b324cSopenharmony_ci    if (numThreads > kNumThreads_Max)
700370b324cSopenharmony_ci      numThreads = kNumThreads_Max;
701370b324cSopenharmony_ci    methodMode.NumThreads = numThreads;
702370b324cSopenharmony_ci    methodMode.NumThreads_WasForced = _numThreads_WasForced;
703370b324cSopenharmony_ci    methodMode.MultiThreadMixer = _useMultiThreadMixer;
704370b324cSopenharmony_ci    // headerMethod.NumThreads = 1;
705370b324cSopenharmony_ci    headerMethod.MultiThreadMixer = _useMultiThreadMixer;
706370b324cSopenharmony_ci  }
707370b324cSopenharmony_ci  #endif
708370b324cSopenharmony_ci
709370b324cSopenharmony_ci  const HRESULT res = SetMainMethod(methodMode);
710370b324cSopenharmony_ci  RINOK(res)
711370b324cSopenharmony_ci
712370b324cSopenharmony_ci  RINOK(SetHeaderMethod(headerMethod))
713370b324cSopenharmony_ci
714370b324cSopenharmony_ci  Z7_DECL_CMyComPtr_QI_FROM(
715370b324cSopenharmony_ci    ICryptoGetTextPassword2,
716370b324cSopenharmony_ci    getPassword2, updateCallback)
717370b324cSopenharmony_ci
718370b324cSopenharmony_ci  methodMode.PasswordIsDefined = false;
719370b324cSopenharmony_ci  methodMode.Password.Wipe_and_Empty();
720370b324cSopenharmony_ci  if (getPassword2)
721370b324cSopenharmony_ci  {
722370b324cSopenharmony_ci    CMyComBSTR_Wipe password;
723370b324cSopenharmony_ci    Int32 passwordIsDefined;
724370b324cSopenharmony_ci    RINOK(getPassword2->CryptoGetTextPassword2(&passwordIsDefined, &password))
725370b324cSopenharmony_ci    methodMode.PasswordIsDefined = IntToBool(passwordIsDefined);
726370b324cSopenharmony_ci    if (methodMode.PasswordIsDefined && password)
727370b324cSopenharmony_ci      methodMode.Password = password;
728370b324cSopenharmony_ci  }
729370b324cSopenharmony_ci
730370b324cSopenharmony_ci  bool compressMainHeader = _compressHeaders;  // check it
731370b324cSopenharmony_ci
732370b324cSopenharmony_ci  bool encryptHeaders = false;
733370b324cSopenharmony_ci
734370b324cSopenharmony_ci  #ifndef Z7_NO_CRYPTO
735370b324cSopenharmony_ci  if (!methodMode.PasswordIsDefined && _passwordIsDefined)
736370b324cSopenharmony_ci  {
737370b324cSopenharmony_ci    // if header is compressed, we use that password for updated archive
738370b324cSopenharmony_ci    methodMode.PasswordIsDefined = true;
739370b324cSopenharmony_ci    methodMode.Password = _password;
740370b324cSopenharmony_ci  }
741370b324cSopenharmony_ci  #endif
742370b324cSopenharmony_ci
743370b324cSopenharmony_ci  if (methodMode.PasswordIsDefined)
744370b324cSopenharmony_ci  {
745370b324cSopenharmony_ci    if (_encryptHeadersSpecified)
746370b324cSopenharmony_ci      encryptHeaders = _encryptHeaders;
747370b324cSopenharmony_ci    #ifndef Z7_NO_CRYPTO
748370b324cSopenharmony_ci    else
749370b324cSopenharmony_ci      encryptHeaders = _passwordIsDefined;
750370b324cSopenharmony_ci    #endif
751370b324cSopenharmony_ci    compressMainHeader = true;
752370b324cSopenharmony_ci    if (encryptHeaders)
753370b324cSopenharmony_ci    {
754370b324cSopenharmony_ci      headerMethod.PasswordIsDefined = methodMode.PasswordIsDefined;
755370b324cSopenharmony_ci      headerMethod.Password = methodMode.Password;
756370b324cSopenharmony_ci    }
757370b324cSopenharmony_ci  }
758370b324cSopenharmony_ci
759370b324cSopenharmony_ci  if (numItems < 2)
760370b324cSopenharmony_ci    compressMainHeader = false;
761370b324cSopenharmony_ci
762370b324cSopenharmony_ci  const int level = GetLevel();
763370b324cSopenharmony_ci
764370b324cSopenharmony_ci  CUpdateOptions options;
765370b324cSopenharmony_ci  options.Need_CTime = need_CTime;
766370b324cSopenharmony_ci  options.Need_ATime = need_ATime;
767370b324cSopenharmony_ci  options.Need_MTime = need_MTime;
768370b324cSopenharmony_ci  options.Need_Attrib = need_Attrib;
769370b324cSopenharmony_ci  // options.Need_Crc = (_crcSize != 0); // for debug
770370b324cSopenharmony_ci
771370b324cSopenharmony_ci  options.Method = &methodMode;
772370b324cSopenharmony_ci  options.HeaderMethod = (_compressHeaders || encryptHeaders) ? &headerMethod : NULL;
773370b324cSopenharmony_ci  options.UseFilters = (level != 0 && _autoFilter && !methodMode.Filter_was_Inserted);
774370b324cSopenharmony_ci  options.MaxFilter = (level >= 8);
775370b324cSopenharmony_ci  options.AnalysisLevel = GetAnalysisLevel();
776370b324cSopenharmony_ci
777370b324cSopenharmony_ci  options.HeaderOptions.CompressMainHeader = compressMainHeader;
778370b324cSopenharmony_ci  /*
779370b324cSopenharmony_ci  options.HeaderOptions.WriteCTime = Write_CTime;
780370b324cSopenharmony_ci  options.HeaderOptions.WriteATime = Write_ATime;
781370b324cSopenharmony_ci  options.HeaderOptions.WriteMTime = Write_MTime;
782370b324cSopenharmony_ci  options.HeaderOptions.WriteAttrib = Write_Attrib;
783370b324cSopenharmony_ci  */
784370b324cSopenharmony_ci
785370b324cSopenharmony_ci  options.NumSolidFiles = _numSolidFiles;
786370b324cSopenharmony_ci  options.NumSolidBytes = _numSolidBytes;
787370b324cSopenharmony_ci  options.SolidExtension = _solidExtension;
788370b324cSopenharmony_ci  options.UseTypeSorting = _useTypeSorting;
789370b324cSopenharmony_ci
790370b324cSopenharmony_ci  options.RemoveSfxBlock = _removeSfxBlock;
791370b324cSopenharmony_ci  // options.VolumeMode = _volumeMode;
792370b324cSopenharmony_ci
793370b324cSopenharmony_ci  options.MultiThreadMixer = _useMultiThreadMixer;
794370b324cSopenharmony_ci
795370b324cSopenharmony_ci  /*
796370b324cSopenharmony_ci  if (secureBlocks.Sorted.Size() > 1)
797370b324cSopenharmony_ci  {
798370b324cSopenharmony_ci    secureBlocks.GetReverseMap();
799370b324cSopenharmony_ci    for (int i = 0; i < updateItems.Size(); i++)
800370b324cSopenharmony_ci    {
801370b324cSopenharmony_ci      int &secureIndex = updateItems[i].SecureIndex;
802370b324cSopenharmony_ci      secureIndex = secureBlocks.BufIndexToSortedIndex[secureIndex];
803370b324cSopenharmony_ci    }
804370b324cSopenharmony_ci  }
805370b324cSopenharmony_ci  */
806370b324cSopenharmony_ci
807370b324cSopenharmony_ci  return Update(
808370b324cSopenharmony_ci      EXTERNAL_CODECS_VARS
809370b324cSopenharmony_ci      #ifdef Z7_7Z_VOL
810370b324cSopenharmony_ci      volume ? volume->Stream: 0,
811370b324cSopenharmony_ci      volume ? db : 0,
812370b324cSopenharmony_ci      #else
813370b324cSopenharmony_ci      _inStream,
814370b324cSopenharmony_ci      db,
815370b324cSopenharmony_ci      #endif
816370b324cSopenharmony_ci      updateItems,
817370b324cSopenharmony_ci      // treeFolders,
818370b324cSopenharmony_ci      // secureBlocks,
819370b324cSopenharmony_ci      outStream, updateCallback, options);
820370b324cSopenharmony_ci
821370b324cSopenharmony_ci  COM_TRY_END
822370b324cSopenharmony_ci}
823370b324cSopenharmony_ci
824370b324cSopenharmony_cistatic HRESULT ParseBond(UString &srcString, UInt32 &coder, UInt32 &stream)
825370b324cSopenharmony_ci{
826370b324cSopenharmony_ci  stream = 0;
827370b324cSopenharmony_ci  {
828370b324cSopenharmony_ci    const unsigned index = ParseStringToUInt32(srcString, coder);
829370b324cSopenharmony_ci    if (index == 0)
830370b324cSopenharmony_ci      return E_INVALIDARG;
831370b324cSopenharmony_ci    srcString.DeleteFrontal(index);
832370b324cSopenharmony_ci  }
833370b324cSopenharmony_ci  if (srcString[0] == 's')
834370b324cSopenharmony_ci  {
835370b324cSopenharmony_ci    srcString.Delete(0);
836370b324cSopenharmony_ci    const unsigned index = ParseStringToUInt32(srcString, stream);
837370b324cSopenharmony_ci    if (index == 0)
838370b324cSopenharmony_ci      return E_INVALIDARG;
839370b324cSopenharmony_ci    srcString.DeleteFrontal(index);
840370b324cSopenharmony_ci  }
841370b324cSopenharmony_ci  return S_OK;
842370b324cSopenharmony_ci}
843370b324cSopenharmony_ci
844370b324cSopenharmony_civoid COutHandler::InitProps7z()
845370b324cSopenharmony_ci{
846370b324cSopenharmony_ci  _removeSfxBlock = false;
847370b324cSopenharmony_ci  _compressHeaders = true;
848370b324cSopenharmony_ci  _encryptHeadersSpecified = false;
849370b324cSopenharmony_ci  _encryptHeaders = false;
850370b324cSopenharmony_ci  // _useParents = false;
851370b324cSopenharmony_ci
852370b324cSopenharmony_ci  TimeOptions.Init();
853370b324cSopenharmony_ci  Write_Attrib.Init();
854370b324cSopenharmony_ci
855370b324cSopenharmony_ci  _useMultiThreadMixer = true;
856370b324cSopenharmony_ci
857370b324cSopenharmony_ci  // _volumeMode = false;
858370b324cSopenharmony_ci
859370b324cSopenharmony_ci  InitSolid();
860370b324cSopenharmony_ci  _useTypeSorting = false;
861370b324cSopenharmony_ci}
862370b324cSopenharmony_ci
863370b324cSopenharmony_civoid COutHandler::InitProps()
864370b324cSopenharmony_ci{
865370b324cSopenharmony_ci  CMultiMethodProps::Init();
866370b324cSopenharmony_ci  InitProps7z();
867370b324cSopenharmony_ci}
868370b324cSopenharmony_ci
869370b324cSopenharmony_ci
870370b324cSopenharmony_ci
871370b324cSopenharmony_ciHRESULT COutHandler::SetSolidFromString(const UString &s)
872370b324cSopenharmony_ci{
873370b324cSopenharmony_ci  UString s2 = s;
874370b324cSopenharmony_ci  s2.MakeLower_Ascii();
875370b324cSopenharmony_ci  for (unsigned i = 0; i < s2.Len();)
876370b324cSopenharmony_ci  {
877370b324cSopenharmony_ci    const wchar_t *start = ((const wchar_t *)s2) + i;
878370b324cSopenharmony_ci    const wchar_t *end;
879370b324cSopenharmony_ci    UInt64 v = ConvertStringToUInt64(start, &end);
880370b324cSopenharmony_ci    if (start == end)
881370b324cSopenharmony_ci    {
882370b324cSopenharmony_ci      if (s2[i++] != 'e')
883370b324cSopenharmony_ci        return E_INVALIDARG;
884370b324cSopenharmony_ci      _solidExtension = true;
885370b324cSopenharmony_ci      continue;
886370b324cSopenharmony_ci    }
887370b324cSopenharmony_ci    i += (unsigned)(end - start);
888370b324cSopenharmony_ci    if (i == s2.Len())
889370b324cSopenharmony_ci      return E_INVALIDARG;
890370b324cSopenharmony_ci    const wchar_t c = s2[i++];
891370b324cSopenharmony_ci    if (c == 'f')
892370b324cSopenharmony_ci    {
893370b324cSopenharmony_ci      if (v < 1)
894370b324cSopenharmony_ci        v = 1;
895370b324cSopenharmony_ci      _numSolidFiles = v;
896370b324cSopenharmony_ci    }
897370b324cSopenharmony_ci    else
898370b324cSopenharmony_ci    {
899370b324cSopenharmony_ci      unsigned numBits;
900370b324cSopenharmony_ci      switch (c)
901370b324cSopenharmony_ci      {
902370b324cSopenharmony_ci        case 'b': numBits =  0; break;
903370b324cSopenharmony_ci        case 'k': numBits = 10; break;
904370b324cSopenharmony_ci        case 'm': numBits = 20; break;
905370b324cSopenharmony_ci        case 'g': numBits = 30; break;
906370b324cSopenharmony_ci        case 't': numBits = 40; break;
907370b324cSopenharmony_ci        default: return E_INVALIDARG;
908370b324cSopenharmony_ci      }
909370b324cSopenharmony_ci      _numSolidBytes = (v << numBits);
910370b324cSopenharmony_ci      _numSolidBytesDefined = true;
911370b324cSopenharmony_ci      /*
912370b324cSopenharmony_ci      if (_numSolidBytes == 0)
913370b324cSopenharmony_ci        _numSolidFiles = 1;
914370b324cSopenharmony_ci      */
915370b324cSopenharmony_ci    }
916370b324cSopenharmony_ci  }
917370b324cSopenharmony_ci  return S_OK;
918370b324cSopenharmony_ci}
919370b324cSopenharmony_ci
920370b324cSopenharmony_ciHRESULT COutHandler::SetSolidFromPROPVARIANT(const PROPVARIANT &value)
921370b324cSopenharmony_ci{
922370b324cSopenharmony_ci  bool isSolid;
923370b324cSopenharmony_ci  switch (value.vt)
924370b324cSopenharmony_ci  {
925370b324cSopenharmony_ci    case VT_EMPTY: isSolid = true; break;
926370b324cSopenharmony_ci    case VT_BOOL: isSolid = (value.boolVal != VARIANT_FALSE); break;
927370b324cSopenharmony_ci    case VT_BSTR:
928370b324cSopenharmony_ci      if (StringToBool(value.bstrVal, isSolid))
929370b324cSopenharmony_ci        break;
930370b324cSopenharmony_ci      return SetSolidFromString(value.bstrVal);
931370b324cSopenharmony_ci    default: return E_INVALIDARG;
932370b324cSopenharmony_ci  }
933370b324cSopenharmony_ci  if (isSolid)
934370b324cSopenharmony_ci    InitSolid();
935370b324cSopenharmony_ci  else
936370b324cSopenharmony_ci    _numSolidFiles = 1;
937370b324cSopenharmony_ci  return S_OK;
938370b324cSopenharmony_ci}
939370b324cSopenharmony_ci
940370b324cSopenharmony_cistatic HRESULT PROPVARIANT_to_BoolPair(const PROPVARIANT &prop, CBoolPair &dest)
941370b324cSopenharmony_ci{
942370b324cSopenharmony_ci  RINOK(PROPVARIANT_to_bool(prop, dest.Val))
943370b324cSopenharmony_ci  dest.Def = true;
944370b324cSopenharmony_ci  return S_OK;
945370b324cSopenharmony_ci}
946370b324cSopenharmony_ci
947370b324cSopenharmony_ciHRESULT COutHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value)
948370b324cSopenharmony_ci{
949370b324cSopenharmony_ci  UString name = nameSpec;
950370b324cSopenharmony_ci  name.MakeLower_Ascii();
951370b324cSopenharmony_ci  if (name.IsEmpty())
952370b324cSopenharmony_ci    return E_INVALIDARG;
953370b324cSopenharmony_ci
954370b324cSopenharmony_ci  if (name[0] == L's')
955370b324cSopenharmony_ci  {
956370b324cSopenharmony_ci    name.Delete(0);
957370b324cSopenharmony_ci    if (name.IsEmpty())
958370b324cSopenharmony_ci      return SetSolidFromPROPVARIANT(value);
959370b324cSopenharmony_ci    if (value.vt != VT_EMPTY)
960370b324cSopenharmony_ci      return E_INVALIDARG;
961370b324cSopenharmony_ci    return SetSolidFromString(name);
962370b324cSopenharmony_ci  }
963370b324cSopenharmony_ci
964370b324cSopenharmony_ci  UInt32 number;
965370b324cSopenharmony_ci  const unsigned index = ParseStringToUInt32(name, number);
966370b324cSopenharmony_ci  // UString realName = name.Ptr(index);
967370b324cSopenharmony_ci  if (index == 0)
968370b324cSopenharmony_ci  {
969370b324cSopenharmony_ci    if (name.IsEqualTo("rsfx")) return PROPVARIANT_to_bool(value, _removeSfxBlock);
970370b324cSopenharmony_ci    if (name.IsEqualTo("hc")) return PROPVARIANT_to_bool(value, _compressHeaders);
971370b324cSopenharmony_ci    // if (name.IsEqualToNoCase(L"HS")) return PROPVARIANT_to_bool(value, _useParents);
972370b324cSopenharmony_ci
973370b324cSopenharmony_ci    if (name.IsEqualTo("hcf"))
974370b324cSopenharmony_ci    {
975370b324cSopenharmony_ci      bool compressHeadersFull = true;
976370b324cSopenharmony_ci      RINOK(PROPVARIANT_to_bool(value, compressHeadersFull))
977370b324cSopenharmony_ci      return compressHeadersFull ? S_OK: E_INVALIDARG;
978370b324cSopenharmony_ci    }
979370b324cSopenharmony_ci
980370b324cSopenharmony_ci    if (name.IsEqualTo("he"))
981370b324cSopenharmony_ci    {
982370b324cSopenharmony_ci      RINOK(PROPVARIANT_to_bool(value, _encryptHeaders))
983370b324cSopenharmony_ci      _encryptHeadersSpecified = true;
984370b324cSopenharmony_ci      return S_OK;
985370b324cSopenharmony_ci    }
986370b324cSopenharmony_ci
987370b324cSopenharmony_ci    {
988370b324cSopenharmony_ci      bool processed;
989370b324cSopenharmony_ci      RINOK(TimeOptions.Parse(name, value, processed))
990370b324cSopenharmony_ci      if (processed)
991370b324cSopenharmony_ci      {
992370b324cSopenharmony_ci        if (   TimeOptions.Prec != (UInt32)(Int32)-1
993370b324cSopenharmony_ci            && TimeOptions.Prec != k_PropVar_TimePrec_0
994370b324cSopenharmony_ci            && TimeOptions.Prec != k_PropVar_TimePrec_HighPrec
995370b324cSopenharmony_ci            && TimeOptions.Prec != k_PropVar_TimePrec_100ns)
996370b324cSopenharmony_ci          return E_INVALIDARG;
997370b324cSopenharmony_ci        return S_OK;
998370b324cSopenharmony_ci      }
999370b324cSopenharmony_ci    }
1000370b324cSopenharmony_ci
1001370b324cSopenharmony_ci    if (name.IsEqualTo("tr")) return PROPVARIANT_to_BoolPair(value, Write_Attrib);
1002370b324cSopenharmony_ci
1003370b324cSopenharmony_ci    if (name.IsEqualTo("mtf")) return PROPVARIANT_to_bool(value, _useMultiThreadMixer);
1004370b324cSopenharmony_ci
1005370b324cSopenharmony_ci    if (name.IsEqualTo("qs")) return PROPVARIANT_to_bool(value, _useTypeSorting);
1006370b324cSopenharmony_ci
1007370b324cSopenharmony_ci    // if (name.IsEqualTo("v"))  return PROPVARIANT_to_bool(value, _volumeMode);
1008370b324cSopenharmony_ci  }
1009370b324cSopenharmony_ci  return CMultiMethodProps::SetProperty(name, value);
1010370b324cSopenharmony_ci}
1011370b324cSopenharmony_ci
1012370b324cSopenharmony_ciZ7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps))
1013370b324cSopenharmony_ci{
1014370b324cSopenharmony_ci  COM_TRY_BEGIN
1015370b324cSopenharmony_ci  _bonds.Clear();
1016370b324cSopenharmony_ci  InitProps();
1017370b324cSopenharmony_ci
1018370b324cSopenharmony_ci  for (UInt32 i = 0; i < numProps; i++)
1019370b324cSopenharmony_ci  {
1020370b324cSopenharmony_ci    UString name = names[i];
1021370b324cSopenharmony_ci    name.MakeLower_Ascii();
1022370b324cSopenharmony_ci    if (name.IsEmpty())
1023370b324cSopenharmony_ci      return E_INVALIDARG;
1024370b324cSopenharmony_ci
1025370b324cSopenharmony_ci    const PROPVARIANT &value = values[i];
1026370b324cSopenharmony_ci
1027370b324cSopenharmony_ci    if (name.Find(L':') >= 0) // 'b' was used as NCoderPropID::kBlockSize2 before v23
1028370b324cSopenharmony_ci    if (name[0] == 'b')
1029370b324cSopenharmony_ci    {
1030370b324cSopenharmony_ci      if (value.vt != VT_EMPTY)
1031370b324cSopenharmony_ci        return E_INVALIDARG;
1032370b324cSopenharmony_ci      name.Delete(0);
1033370b324cSopenharmony_ci
1034370b324cSopenharmony_ci      CBond2 bond;
1035370b324cSopenharmony_ci      RINOK(ParseBond(name, bond.OutCoder, bond.OutStream))
1036370b324cSopenharmony_ci      if (name[0] != ':')
1037370b324cSopenharmony_ci        return E_INVALIDARG;
1038370b324cSopenharmony_ci      name.Delete(0);
1039370b324cSopenharmony_ci      UInt32 inStream = 0;
1040370b324cSopenharmony_ci      RINOK(ParseBond(name, bond.InCoder, inStream))
1041370b324cSopenharmony_ci      if (inStream != 0)
1042370b324cSopenharmony_ci        return E_INVALIDARG;
1043370b324cSopenharmony_ci      if (!name.IsEmpty())
1044370b324cSopenharmony_ci        return E_INVALIDARG;
1045370b324cSopenharmony_ci      _bonds.Add(bond);
1046370b324cSopenharmony_ci      continue;
1047370b324cSopenharmony_ci    }
1048370b324cSopenharmony_ci
1049370b324cSopenharmony_ci    RINOK(SetProperty(name, value))
1050370b324cSopenharmony_ci  }
1051370b324cSopenharmony_ci
1052370b324cSopenharmony_ci  unsigned numEmptyMethods = GetNumEmptyMethods();
1053370b324cSopenharmony_ci  if (numEmptyMethods > 0)
1054370b324cSopenharmony_ci  {
1055370b324cSopenharmony_ci    unsigned k;
1056370b324cSopenharmony_ci    for (k = 0; k < _bonds.Size(); k++)
1057370b324cSopenharmony_ci    {
1058370b324cSopenharmony_ci      const CBond2 &bond = _bonds[k];
1059370b324cSopenharmony_ci      if (bond.InCoder < (UInt32)numEmptyMethods ||
1060370b324cSopenharmony_ci          bond.OutCoder < (UInt32)numEmptyMethods)
1061370b324cSopenharmony_ci        return E_INVALIDARG;
1062370b324cSopenharmony_ci    }
1063370b324cSopenharmony_ci    for (k = 0; k < _bonds.Size(); k++)
1064370b324cSopenharmony_ci    {
1065370b324cSopenharmony_ci      CBond2 &bond = _bonds[k];
1066370b324cSopenharmony_ci      bond.InCoder -= (UInt32)numEmptyMethods;
1067370b324cSopenharmony_ci      bond.OutCoder -= (UInt32)numEmptyMethods;
1068370b324cSopenharmony_ci    }
1069370b324cSopenharmony_ci    _methods.DeleteFrontal(numEmptyMethods);
1070370b324cSopenharmony_ci  }
1071370b324cSopenharmony_ci
1072370b324cSopenharmony_ci  FOR_VECTOR (k, _bonds)
1073370b324cSopenharmony_ci  {
1074370b324cSopenharmony_ci    const CBond2 &bond = _bonds[k];
1075370b324cSopenharmony_ci    if (bond.InCoder >= (UInt32)_methods.Size() ||
1076370b324cSopenharmony_ci        bond.OutCoder >= (UInt32)_methods.Size())
1077370b324cSopenharmony_ci      return E_INVALIDARG;
1078370b324cSopenharmony_ci  }
1079370b324cSopenharmony_ci
1080370b324cSopenharmony_ci  return S_OK;
1081370b324cSopenharmony_ci  COM_TRY_END
1082370b324cSopenharmony_ci}
1083370b324cSopenharmony_ci
1084370b324cSopenharmony_ci}}
1085370b324cSopenharmony_ci
1086370b324cSopenharmony_ci#endif
1087