xref: /aosp_15_r20/external/lzma/CPP/7zip/Archive/Zip/ZipUpdate.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1*f6dc9357SAndroid Build Coastguard Worker // ZipUpdate.cpp
2*f6dc9357SAndroid Build Coastguard Worker 
3*f6dc9357SAndroid Build Coastguard Worker #include "StdAfx.h"
4*f6dc9357SAndroid Build Coastguard Worker 
5*f6dc9357SAndroid Build Coastguard Worker // #define DEBUG_CACHE
6*f6dc9357SAndroid Build Coastguard Worker 
7*f6dc9357SAndroid Build Coastguard Worker #ifdef DEBUG_CACHE
8*f6dc9357SAndroid Build Coastguard Worker #include <stdio.h>
9*f6dc9357SAndroid Build Coastguard Worker   #define PRF(x) x
10*f6dc9357SAndroid Build Coastguard Worker #else
11*f6dc9357SAndroid Build Coastguard Worker   #define PRF(x)
12*f6dc9357SAndroid Build Coastguard Worker #endif
13*f6dc9357SAndroid Build Coastguard Worker 
14*f6dc9357SAndroid Build Coastguard Worker #include "../../../../C/Alloc.h"
15*f6dc9357SAndroid Build Coastguard Worker 
16*f6dc9357SAndroid Build Coastguard Worker #include "../../../Common/AutoPtr.h"
17*f6dc9357SAndroid Build Coastguard Worker #include "../../../Common/Defs.h"
18*f6dc9357SAndroid Build Coastguard Worker #include "../../../Common/StringConvert.h"
19*f6dc9357SAndroid Build Coastguard Worker 
20*f6dc9357SAndroid Build Coastguard Worker #include "../../../Windows/TimeUtils.h"
21*f6dc9357SAndroid Build Coastguard Worker #include "../../../Windows/Thread.h"
22*f6dc9357SAndroid Build Coastguard Worker 
23*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/CreateCoder.h"
24*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/LimitedStreams.h"
25*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/OutMemStream.h"
26*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/ProgressUtils.h"
27*f6dc9357SAndroid Build Coastguard Worker #ifndef Z7_ST
28*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/ProgressMt.h"
29*f6dc9357SAndroid Build Coastguard Worker #endif
30*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/StreamUtils.h"
31*f6dc9357SAndroid Build Coastguard Worker 
32*f6dc9357SAndroid Build Coastguard Worker #include "../../Compress/CopyCoder.h"
33*f6dc9357SAndroid Build Coastguard Worker // #include "../../Compress/ZstdEncoderProps.h"
34*f6dc9357SAndroid Build Coastguard Worker 
35*f6dc9357SAndroid Build Coastguard Worker #include "ZipAddCommon.h"
36*f6dc9357SAndroid Build Coastguard Worker #include "ZipOut.h"
37*f6dc9357SAndroid Build Coastguard Worker #include "ZipUpdate.h"
38*f6dc9357SAndroid Build Coastguard Worker 
39*f6dc9357SAndroid Build Coastguard Worker using namespace NWindows;
40*f6dc9357SAndroid Build Coastguard Worker using namespace NSynchronization;
41*f6dc9357SAndroid Build Coastguard Worker 
42*f6dc9357SAndroid Build Coastguard Worker namespace NArchive {
43*f6dc9357SAndroid Build Coastguard Worker namespace NZip {
44*f6dc9357SAndroid Build Coastguard Worker 
45*f6dc9357SAndroid Build Coastguard Worker static const Byte kHostOS =
46*f6dc9357SAndroid Build Coastguard Worker   #ifdef _WIN32
47*f6dc9357SAndroid Build Coastguard Worker   NFileHeader::NHostOS::kFAT;
48*f6dc9357SAndroid Build Coastguard Worker   #else
49*f6dc9357SAndroid Build Coastguard Worker   NFileHeader::NHostOS::kUnix;
50*f6dc9357SAndroid Build Coastguard Worker   #endif
51*f6dc9357SAndroid Build Coastguard Worker 
52*f6dc9357SAndroid Build Coastguard Worker static const Byte kMadeByHostOS = kHostOS;
53*f6dc9357SAndroid Build Coastguard Worker 
54*f6dc9357SAndroid Build Coastguard Worker // 18.06: now we always write zero to high byte of ExtractVersion field.
55*f6dc9357SAndroid Build Coastguard Worker // Previous versions of p7zip wrote (NFileHeader::NHostOS::kUnix) there, that is not correct
56*f6dc9357SAndroid Build Coastguard Worker static const Byte kExtractHostOS = 0;
57*f6dc9357SAndroid Build Coastguard Worker 
58*f6dc9357SAndroid Build Coastguard Worker static const Byte kMethodForDirectory = NFileHeader::NCompressionMethod::kStore;
59*f6dc9357SAndroid Build Coastguard Worker 
60*f6dc9357SAndroid Build Coastguard Worker 
AddAesExtra(CItem & item,Byte aesKeyMode,UInt16 method)61*f6dc9357SAndroid Build Coastguard Worker static void AddAesExtra(CItem &item, Byte aesKeyMode, UInt16 method)
62*f6dc9357SAndroid Build Coastguard Worker {
63*f6dc9357SAndroid Build Coastguard Worker   CWzAesExtra wzAesField;
64*f6dc9357SAndroid Build Coastguard Worker   wzAesField.Strength = aesKeyMode;
65*f6dc9357SAndroid Build Coastguard Worker   wzAesField.Method = method;
66*f6dc9357SAndroid Build Coastguard Worker   item.Method = NFileHeader::NCompressionMethod::kWzAES;
67*f6dc9357SAndroid Build Coastguard Worker   item.Crc = 0;
68*f6dc9357SAndroid Build Coastguard Worker   CExtraSubBlock sb;
69*f6dc9357SAndroid Build Coastguard Worker   wzAesField.SetSubBlock(sb);
70*f6dc9357SAndroid Build Coastguard Worker   item.LocalExtra.SubBlocks.Add(sb);
71*f6dc9357SAndroid Build Coastguard Worker   item.CentralExtra.SubBlocks.Add(sb);
72*f6dc9357SAndroid Build Coastguard Worker }
73*f6dc9357SAndroid Build Coastguard Worker 
74*f6dc9357SAndroid Build Coastguard Worker 
Copy_From_UpdateItem_To_ItemOut(const CUpdateItem & ui,CItemOut & item)75*f6dc9357SAndroid Build Coastguard Worker static void Copy_From_UpdateItem_To_ItemOut(const CUpdateItem &ui, CItemOut &item)
76*f6dc9357SAndroid Build Coastguard Worker {
77*f6dc9357SAndroid Build Coastguard Worker   item.Name = ui.Name;
78*f6dc9357SAndroid Build Coastguard Worker   item.Name_Utf = ui.Name_Utf;
79*f6dc9357SAndroid Build Coastguard Worker   item.Comment = ui.Comment;
80*f6dc9357SAndroid Build Coastguard Worker   item.SetUtf8(ui.IsUtf8);
81*f6dc9357SAndroid Build Coastguard Worker   // item.SetFlag_AltStream(ui.IsAltStream);
82*f6dc9357SAndroid Build Coastguard Worker   // item.ExternalAttrib = ui.Attrib;
83*f6dc9357SAndroid Build Coastguard Worker   item.Time = ui.Time;
84*f6dc9357SAndroid Build Coastguard Worker   item.Ntfs_MTime = ui.Ntfs_MTime;
85*f6dc9357SAndroid Build Coastguard Worker   item.Ntfs_ATime = ui.Ntfs_ATime;
86*f6dc9357SAndroid Build Coastguard Worker   item.Ntfs_CTime = ui.Ntfs_CTime;
87*f6dc9357SAndroid Build Coastguard Worker 
88*f6dc9357SAndroid Build Coastguard Worker   item.Write_UnixTime = ui.Write_UnixTime;
89*f6dc9357SAndroid Build Coastguard Worker   item.Write_NtfsTime = ui.Write_NtfsTime;
90*f6dc9357SAndroid Build Coastguard Worker }
91*f6dc9357SAndroid Build Coastguard Worker 
SetFileHeader(const CCompressionMethodMode & options,const CUpdateItem & ui,bool useDescriptor,CItemOut & item)92*f6dc9357SAndroid Build Coastguard Worker static void SetFileHeader(
93*f6dc9357SAndroid Build Coastguard Worker     const CCompressionMethodMode &options,
94*f6dc9357SAndroid Build Coastguard Worker     const CUpdateItem &ui,
95*f6dc9357SAndroid Build Coastguard Worker     bool useDescriptor,
96*f6dc9357SAndroid Build Coastguard Worker     CItemOut &item)
97*f6dc9357SAndroid Build Coastguard Worker {
98*f6dc9357SAndroid Build Coastguard Worker   item.Size = ui.Size;
99*f6dc9357SAndroid Build Coastguard Worker   const bool isDir = ui.IsDir;
100*f6dc9357SAndroid Build Coastguard Worker 
101*f6dc9357SAndroid Build Coastguard Worker   item.ClearFlags();
102*f6dc9357SAndroid Build Coastguard Worker 
103*f6dc9357SAndroid Build Coastguard Worker   if (ui.NewProps)
104*f6dc9357SAndroid Build Coastguard Worker   {
105*f6dc9357SAndroid Build Coastguard Worker     Copy_From_UpdateItem_To_ItemOut(ui, item);
106*f6dc9357SAndroid Build Coastguard Worker     // item.SetFlag_AltStream(ui.IsAltStream);
107*f6dc9357SAndroid Build Coastguard Worker     item.ExternalAttrib = ui.Attrib;
108*f6dc9357SAndroid Build Coastguard Worker   }
109*f6dc9357SAndroid Build Coastguard Worker   /*
110*f6dc9357SAndroid Build Coastguard Worker   else
111*f6dc9357SAndroid Build Coastguard Worker     isDir = item.IsDir();
112*f6dc9357SAndroid Build Coastguard Worker   */
113*f6dc9357SAndroid Build Coastguard Worker 
114*f6dc9357SAndroid Build Coastguard Worker   item.MadeByVersion.HostOS = kMadeByHostOS;
115*f6dc9357SAndroid Build Coastguard Worker   item.MadeByVersion.Version = NFileHeader::NCompressionMethod::kMadeByProgramVersion;
116*f6dc9357SAndroid Build Coastguard Worker 
117*f6dc9357SAndroid Build Coastguard Worker   item.ExtractVersion.HostOS = kExtractHostOS;
118*f6dc9357SAndroid Build Coastguard Worker 
119*f6dc9357SAndroid Build Coastguard Worker   item.InternalAttrib = 0; // test it
120*f6dc9357SAndroid Build Coastguard Worker   item.SetEncrypted(!isDir && options.Password_Defined);
121*f6dc9357SAndroid Build Coastguard Worker   item.SetDescriptorMode(useDescriptor);
122*f6dc9357SAndroid Build Coastguard Worker 
123*f6dc9357SAndroid Build Coastguard Worker   if (isDir)
124*f6dc9357SAndroid Build Coastguard Worker   {
125*f6dc9357SAndroid Build Coastguard Worker     item.ExtractVersion.Version = NFileHeader::NCompressionMethod::kExtractVersion_Dir;
126*f6dc9357SAndroid Build Coastguard Worker     item.Method = kMethodForDirectory;
127*f6dc9357SAndroid Build Coastguard Worker     item.PackSize = 0;
128*f6dc9357SAndroid Build Coastguard Worker     item.Size = 0;
129*f6dc9357SAndroid Build Coastguard Worker     item.Crc = 0;
130*f6dc9357SAndroid Build Coastguard Worker   }
131*f6dc9357SAndroid Build Coastguard Worker 
132*f6dc9357SAndroid Build Coastguard Worker   item.LocalExtra.Clear();
133*f6dc9357SAndroid Build Coastguard Worker   item.CentralExtra.Clear();
134*f6dc9357SAndroid Build Coastguard Worker 
135*f6dc9357SAndroid Build Coastguard Worker   if (isDir)
136*f6dc9357SAndroid Build Coastguard Worker   {
137*f6dc9357SAndroid Build Coastguard Worker     item.ExtractVersion.Version = NFileHeader::NCompressionMethod::kExtractVersion_Dir;
138*f6dc9357SAndroid Build Coastguard Worker     item.Method = kMethodForDirectory;
139*f6dc9357SAndroid Build Coastguard Worker     item.PackSize = 0;
140*f6dc9357SAndroid Build Coastguard Worker     item.Size = 0;
141*f6dc9357SAndroid Build Coastguard Worker     item.Crc = 0;
142*f6dc9357SAndroid Build Coastguard Worker   }
143*f6dc9357SAndroid Build Coastguard Worker   else if (options.IsRealAesMode())
144*f6dc9357SAndroid Build Coastguard Worker     AddAesExtra(item, options.AesKeyMode, (Byte)(options.MethodSequence.IsEmpty() ? 8 : options.MethodSequence[0]));
145*f6dc9357SAndroid Build Coastguard Worker }
146*f6dc9357SAndroid Build Coastguard Worker 
147*f6dc9357SAndroid Build Coastguard Worker 
148*f6dc9357SAndroid Build Coastguard Worker // we call SetItemInfoFromCompressingResult() after SetFileHeader()
149*f6dc9357SAndroid Build Coastguard Worker 
SetItemInfoFromCompressingResult(const CCompressingResult & compressingResult,bool isAesMode,Byte aesKeyMode,CItem & item)150*f6dc9357SAndroid Build Coastguard Worker static void SetItemInfoFromCompressingResult(const CCompressingResult &compressingResult,
151*f6dc9357SAndroid Build Coastguard Worker     bool isAesMode, Byte aesKeyMode, CItem &item)
152*f6dc9357SAndroid Build Coastguard Worker {
153*f6dc9357SAndroid Build Coastguard Worker   item.ExtractVersion.Version = compressingResult.ExtractVersion;
154*f6dc9357SAndroid Build Coastguard Worker   item.Method = compressingResult.Method;
155*f6dc9357SAndroid Build Coastguard Worker   if (compressingResult.Method == NFileHeader::NCompressionMethod::kLZMA && compressingResult.LzmaEos)
156*f6dc9357SAndroid Build Coastguard Worker     item.Flags |= NFileHeader::NFlags::kLzmaEOS;
157*f6dc9357SAndroid Build Coastguard Worker   item.Crc = compressingResult.CRC;
158*f6dc9357SAndroid Build Coastguard Worker   item.Size = compressingResult.UnpackSize;
159*f6dc9357SAndroid Build Coastguard Worker   item.PackSize = compressingResult.PackSize;
160*f6dc9357SAndroid Build Coastguard Worker 
161*f6dc9357SAndroid Build Coastguard Worker   item.LocalExtra.Clear();
162*f6dc9357SAndroid Build Coastguard Worker   item.CentralExtra.Clear();
163*f6dc9357SAndroid Build Coastguard Worker 
164*f6dc9357SAndroid Build Coastguard Worker   if (isAesMode)
165*f6dc9357SAndroid Build Coastguard Worker     AddAesExtra(item, aesKeyMode, compressingResult.Method);
166*f6dc9357SAndroid Build Coastguard Worker }
167*f6dc9357SAndroid Build Coastguard Worker 
168*f6dc9357SAndroid Build Coastguard Worker 
169*f6dc9357SAndroid Build Coastguard Worker #ifndef Z7_ST
170*f6dc9357SAndroid Build Coastguard Worker 
171*f6dc9357SAndroid Build Coastguard Worker struct CMtSem
172*f6dc9357SAndroid Build Coastguard Worker {
173*f6dc9357SAndroid Build Coastguard Worker   NWindows::NSynchronization::CSemaphore Semaphore;
174*f6dc9357SAndroid Build Coastguard Worker   NWindows::NSynchronization::CCriticalSection CS;
175*f6dc9357SAndroid Build Coastguard Worker   CIntVector Indexes;
176*f6dc9357SAndroid Build Coastguard Worker   int Head;
177*f6dc9357SAndroid Build Coastguard Worker 
ReleaseItemNArchive::NZip::CMtSem178*f6dc9357SAndroid Build Coastguard Worker   void ReleaseItem(unsigned index)
179*f6dc9357SAndroid Build Coastguard Worker   {
180*f6dc9357SAndroid Build Coastguard Worker     {
181*f6dc9357SAndroid Build Coastguard Worker       CCriticalSectionLock lock(CS);
182*f6dc9357SAndroid Build Coastguard Worker       Indexes[index] = Head;
183*f6dc9357SAndroid Build Coastguard Worker       Head = (int)index;
184*f6dc9357SAndroid Build Coastguard Worker     }
185*f6dc9357SAndroid Build Coastguard Worker     Semaphore.Release();
186*f6dc9357SAndroid Build Coastguard Worker   }
187*f6dc9357SAndroid Build Coastguard Worker 
GetFreeItemNArchive::NZip::CMtSem188*f6dc9357SAndroid Build Coastguard Worker   int GetFreeItem()
189*f6dc9357SAndroid Build Coastguard Worker   {
190*f6dc9357SAndroid Build Coastguard Worker     int i;
191*f6dc9357SAndroid Build Coastguard Worker     {
192*f6dc9357SAndroid Build Coastguard Worker       CCriticalSectionLock lock(CS);
193*f6dc9357SAndroid Build Coastguard Worker       i = Head;
194*f6dc9357SAndroid Build Coastguard Worker       Head = Indexes[(unsigned)i];
195*f6dc9357SAndroid Build Coastguard Worker     }
196*f6dc9357SAndroid Build Coastguard Worker     return i;
197*f6dc9357SAndroid Build Coastguard Worker   }
198*f6dc9357SAndroid Build Coastguard Worker };
199*f6dc9357SAndroid Build Coastguard Worker 
200*f6dc9357SAndroid Build Coastguard Worker static THREAD_FUNC_DECL CoderThread(void *threadCoderInfo);
201*f6dc9357SAndroid Build Coastguard Worker 
202*f6dc9357SAndroid Build Coastguard Worker struct CThreadInfo
203*f6dc9357SAndroid Build Coastguard Worker {
204*f6dc9357SAndroid Build Coastguard Worker   DECL_EXTERNAL_CODECS_LOC_VARS_DECL
205*f6dc9357SAndroid Build Coastguard Worker 
206*f6dc9357SAndroid Build Coastguard Worker   NWindows::CThread Thread;
207*f6dc9357SAndroid Build Coastguard Worker   NWindows::NSynchronization::CAutoResetEvent CompressEvent;
208*f6dc9357SAndroid Build Coastguard Worker   CMtSem *MtSem;
209*f6dc9357SAndroid Build Coastguard Worker   unsigned ThreadIndex;
210*f6dc9357SAndroid Build Coastguard Worker 
211*f6dc9357SAndroid Build Coastguard Worker   bool ExitThread;
212*f6dc9357SAndroid Build Coastguard Worker 
213*f6dc9357SAndroid Build Coastguard Worker   CMtCompressProgress *ProgressSpec;
214*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<ICompressProgressInfo> Progress;
215*f6dc9357SAndroid Build Coastguard Worker 
216*f6dc9357SAndroid Build Coastguard Worker   COutMemStream *OutStreamSpec;
217*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<IOutStream> OutStream;
218*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<ISequentialInStream> InStream;
219*f6dc9357SAndroid Build Coastguard Worker 
220*f6dc9357SAndroid Build Coastguard Worker   CAddCommon Coder;
221*f6dc9357SAndroid Build Coastguard Worker   HRESULT Result;
222*f6dc9357SAndroid Build Coastguard Worker   CCompressingResult CompressingResult;
223*f6dc9357SAndroid Build Coastguard Worker 
224*f6dc9357SAndroid Build Coastguard Worker   bool IsFree;
225*f6dc9357SAndroid Build Coastguard Worker   bool InSeqMode;
226*f6dc9357SAndroid Build Coastguard Worker   bool OutSeqMode;
227*f6dc9357SAndroid Build Coastguard Worker   bool ExpectedDataSize_IsConfirmed;
228*f6dc9357SAndroid Build Coastguard Worker 
229*f6dc9357SAndroid Build Coastguard Worker   UInt32 UpdateIndex;
230*f6dc9357SAndroid Build Coastguard Worker   UInt32 FileTime;
231*f6dc9357SAndroid Build Coastguard Worker   UInt64 ExpectedDataSize;
232*f6dc9357SAndroid Build Coastguard Worker 
CThreadInfoNArchive::NZip::CThreadInfo233*f6dc9357SAndroid Build Coastguard Worker   CThreadInfo():
234*f6dc9357SAndroid Build Coastguard Worker       MtSem(NULL),
235*f6dc9357SAndroid Build Coastguard Worker       ExitThread(false),
236*f6dc9357SAndroid Build Coastguard Worker       ProgressSpec(NULL),
237*f6dc9357SAndroid Build Coastguard Worker       OutStreamSpec(NULL),
238*f6dc9357SAndroid Build Coastguard Worker       IsFree(true),
239*f6dc9357SAndroid Build Coastguard Worker       InSeqMode(false),
240*f6dc9357SAndroid Build Coastguard Worker       OutSeqMode(false),
241*f6dc9357SAndroid Build Coastguard Worker       ExpectedDataSize_IsConfirmed(false),
242*f6dc9357SAndroid Build Coastguard Worker       FileTime(0),
243*f6dc9357SAndroid Build Coastguard Worker       ExpectedDataSize((UInt64)(Int64)-1)
244*f6dc9357SAndroid Build Coastguard Worker   {}
245*f6dc9357SAndroid Build Coastguard Worker 
SetOptionsNArchive::NZip::CThreadInfo246*f6dc9357SAndroid Build Coastguard Worker   void SetOptions(const CCompressionMethodMode &options)
247*f6dc9357SAndroid Build Coastguard Worker   {
248*f6dc9357SAndroid Build Coastguard Worker     Coder.SetOptions(options);
249*f6dc9357SAndroid Build Coastguard Worker   }
250*f6dc9357SAndroid Build Coastguard Worker 
CreateEventsNArchive::NZip::CThreadInfo251*f6dc9357SAndroid Build Coastguard Worker   HRESULT CreateEvents()
252*f6dc9357SAndroid Build Coastguard Worker   {
253*f6dc9357SAndroid Build Coastguard Worker     WRes wres = CompressEvent.CreateIfNotCreated_Reset();
254*f6dc9357SAndroid Build Coastguard Worker     return HRESULT_FROM_WIN32(wres);
255*f6dc9357SAndroid Build Coastguard Worker   }
256*f6dc9357SAndroid Build Coastguard Worker 
CreateThreadNArchive::NZip::CThreadInfo257*f6dc9357SAndroid Build Coastguard Worker   HRESULT CreateThread()
258*f6dc9357SAndroid Build Coastguard Worker   {
259*f6dc9357SAndroid Build Coastguard Worker     WRes wres = Thread.Create(CoderThread, this);
260*f6dc9357SAndroid Build Coastguard Worker     return HRESULT_FROM_WIN32(wres);
261*f6dc9357SAndroid Build Coastguard Worker   }
262*f6dc9357SAndroid Build Coastguard Worker 
263*f6dc9357SAndroid Build Coastguard Worker   void WaitAndCode();
264*f6dc9357SAndroid Build Coastguard Worker 
StopWait_CloseNArchive::NZip::CThreadInfo265*f6dc9357SAndroid Build Coastguard Worker   void StopWait_Close()
266*f6dc9357SAndroid Build Coastguard Worker   {
267*f6dc9357SAndroid Build Coastguard Worker     ExitThread = true;
268*f6dc9357SAndroid Build Coastguard Worker     if (OutStreamSpec)
269*f6dc9357SAndroid Build Coastguard Worker       OutStreamSpec->StopWriting(E_ABORT);
270*f6dc9357SAndroid Build Coastguard Worker     if (CompressEvent.IsCreated())
271*f6dc9357SAndroid Build Coastguard Worker       CompressEvent.Set();
272*f6dc9357SAndroid Build Coastguard Worker     Thread.Wait_Close();
273*f6dc9357SAndroid Build Coastguard Worker   }
274*f6dc9357SAndroid Build Coastguard Worker };
275*f6dc9357SAndroid Build Coastguard Worker 
WaitAndCode()276*f6dc9357SAndroid Build Coastguard Worker void CThreadInfo::WaitAndCode()
277*f6dc9357SAndroid Build Coastguard Worker {
278*f6dc9357SAndroid Build Coastguard Worker   for (;;)
279*f6dc9357SAndroid Build Coastguard Worker   {
280*f6dc9357SAndroid Build Coastguard Worker     CompressEvent.Lock();
281*f6dc9357SAndroid Build Coastguard Worker     if (ExitThread)
282*f6dc9357SAndroid Build Coastguard Worker       return;
283*f6dc9357SAndroid Build Coastguard Worker 
284*f6dc9357SAndroid Build Coastguard Worker     Result = Coder.Compress(
285*f6dc9357SAndroid Build Coastguard Worker         EXTERNAL_CODECS_LOC_VARS
286*f6dc9357SAndroid Build Coastguard Worker         InStream, OutStream,
287*f6dc9357SAndroid Build Coastguard Worker         InSeqMode, OutSeqMode, FileTime, ExpectedDataSize,
288*f6dc9357SAndroid Build Coastguard Worker         ExpectedDataSize_IsConfirmed,
289*f6dc9357SAndroid Build Coastguard Worker         Progress, CompressingResult);
290*f6dc9357SAndroid Build Coastguard Worker 
291*f6dc9357SAndroid Build Coastguard Worker     if (Result == S_OK && Progress)
292*f6dc9357SAndroid Build Coastguard Worker       Result = Progress->SetRatioInfo(&CompressingResult.UnpackSize, &CompressingResult.PackSize);
293*f6dc9357SAndroid Build Coastguard Worker 
294*f6dc9357SAndroid Build Coastguard Worker     MtSem->ReleaseItem(ThreadIndex);
295*f6dc9357SAndroid Build Coastguard Worker   }
296*f6dc9357SAndroid Build Coastguard Worker }
297*f6dc9357SAndroid Build Coastguard Worker 
CoderThread(void * threadCoderInfo)298*f6dc9357SAndroid Build Coastguard Worker static THREAD_FUNC_DECL CoderThread(void *threadCoderInfo)
299*f6dc9357SAndroid Build Coastguard Worker {
300*f6dc9357SAndroid Build Coastguard Worker   ((CThreadInfo *)threadCoderInfo)->WaitAndCode();
301*f6dc9357SAndroid Build Coastguard Worker   return 0;
302*f6dc9357SAndroid Build Coastguard Worker }
303*f6dc9357SAndroid Build Coastguard Worker 
304*f6dc9357SAndroid Build Coastguard Worker class CThreads
305*f6dc9357SAndroid Build Coastguard Worker {
306*f6dc9357SAndroid Build Coastguard Worker public:
307*f6dc9357SAndroid Build Coastguard Worker   CObjectVector<CThreadInfo> Threads;
~CThreads()308*f6dc9357SAndroid Build Coastguard Worker   ~CThreads()
309*f6dc9357SAndroid Build Coastguard Worker   {
310*f6dc9357SAndroid Build Coastguard Worker     FOR_VECTOR (i, Threads)
311*f6dc9357SAndroid Build Coastguard Worker       Threads[i].StopWait_Close();
312*f6dc9357SAndroid Build Coastguard Worker   }
313*f6dc9357SAndroid Build Coastguard Worker };
314*f6dc9357SAndroid Build Coastguard Worker 
315*f6dc9357SAndroid Build Coastguard Worker struct CMemBlocks2: public CMemLockBlocks
316*f6dc9357SAndroid Build Coastguard Worker {
317*f6dc9357SAndroid Build Coastguard Worker   bool Skip;
318*f6dc9357SAndroid Build Coastguard Worker   bool InSeqMode;
319*f6dc9357SAndroid Build Coastguard Worker   bool PreDescriptorMode;
320*f6dc9357SAndroid Build Coastguard Worker   bool Finished;
321*f6dc9357SAndroid Build Coastguard Worker   CCompressingResult CompressingResult;
322*f6dc9357SAndroid Build Coastguard Worker 
CMemBlocks2NArchive::NZip::CMemBlocks2323*f6dc9357SAndroid Build Coastguard Worker   CMemBlocks2(): Skip(false), InSeqMode(false), PreDescriptorMode(false), Finished(false),
324*f6dc9357SAndroid Build Coastguard Worker     CompressingResult() {}
325*f6dc9357SAndroid Build Coastguard Worker };
326*f6dc9357SAndroid Build Coastguard Worker 
327*f6dc9357SAndroid Build Coastguard Worker class CMemRefs
328*f6dc9357SAndroid Build Coastguard Worker {
329*f6dc9357SAndroid Build Coastguard Worker public:
330*f6dc9357SAndroid Build Coastguard Worker   CMemBlockManagerMt *Manager;
331*f6dc9357SAndroid Build Coastguard Worker   CObjectVector<CMemBlocks2> Refs;
CMemRefs(CMemBlockManagerMt * manager)332*f6dc9357SAndroid Build Coastguard Worker   CMemRefs(CMemBlockManagerMt *manager): Manager(manager) {}
~CMemRefs()333*f6dc9357SAndroid Build Coastguard Worker   ~CMemRefs()
334*f6dc9357SAndroid Build Coastguard Worker   {
335*f6dc9357SAndroid Build Coastguard Worker     FOR_VECTOR (i, Refs)
336*f6dc9357SAndroid Build Coastguard Worker       Refs[i].FreeOpt(Manager);
337*f6dc9357SAndroid Build Coastguard Worker   }
338*f6dc9357SAndroid Build Coastguard Worker };
339*f6dc9357SAndroid Build Coastguard Worker 
340*f6dc9357SAndroid Build Coastguard Worker 
341*f6dc9357SAndroid Build Coastguard Worker Z7_CLASS_IMP_NOQIB_1(
342*f6dc9357SAndroid Build Coastguard Worker   CMtProgressMixer2
343*f6dc9357SAndroid Build Coastguard Worker   , ICompressProgressInfo
344*f6dc9357SAndroid Build Coastguard Worker )
345*f6dc9357SAndroid Build Coastguard Worker   UInt64 ProgressOffset;
346*f6dc9357SAndroid Build Coastguard Worker   UInt64 InSizes[2];
347*f6dc9357SAndroid Build Coastguard Worker   UInt64 OutSizes[2];
348*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<IProgress> Progress;
349*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<ICompressProgressInfo> RatioProgress;
350*f6dc9357SAndroid Build Coastguard Worker   bool _inSizeIsMain;
351*f6dc9357SAndroid Build Coastguard Worker public:
352*f6dc9357SAndroid Build Coastguard Worker   NWindows::NSynchronization::CCriticalSection CriticalSection;
353*f6dc9357SAndroid Build Coastguard Worker   void Create(IProgress *progress, bool inSizeIsMain);
354*f6dc9357SAndroid Build Coastguard Worker   void SetProgressOffset(UInt64 progressOffset);
355*f6dc9357SAndroid Build Coastguard Worker   void SetProgressOffset_NoLock(UInt64 progressOffset);
356*f6dc9357SAndroid Build Coastguard Worker   HRESULT SetRatioInfo(unsigned index, const UInt64 *inSize, const UInt64 *outSize);
357*f6dc9357SAndroid Build Coastguard Worker };
358*f6dc9357SAndroid Build Coastguard Worker 
359*f6dc9357SAndroid Build Coastguard Worker void CMtProgressMixer2::Create(IProgress *progress, bool inSizeIsMain)
360*f6dc9357SAndroid Build Coastguard Worker {
361*f6dc9357SAndroid Build Coastguard Worker   Progress = progress;
362*f6dc9357SAndroid Build Coastguard Worker   Progress.QueryInterface(IID_ICompressProgressInfo, &RatioProgress);
363*f6dc9357SAndroid Build Coastguard Worker   _inSizeIsMain = inSizeIsMain;
364*f6dc9357SAndroid Build Coastguard Worker   ProgressOffset = InSizes[0] = InSizes[1] = OutSizes[0] = OutSizes[1] = 0;
365*f6dc9357SAndroid Build Coastguard Worker }
366*f6dc9357SAndroid Build Coastguard Worker 
367*f6dc9357SAndroid Build Coastguard Worker void CMtProgressMixer2::SetProgressOffset_NoLock(UInt64 progressOffset)
368*f6dc9357SAndroid Build Coastguard Worker {
369*f6dc9357SAndroid Build Coastguard Worker   InSizes[1] = OutSizes[1] = 0;
370*f6dc9357SAndroid Build Coastguard Worker   ProgressOffset = progressOffset;
371*f6dc9357SAndroid Build Coastguard Worker }
372*f6dc9357SAndroid Build Coastguard Worker 
373*f6dc9357SAndroid Build Coastguard Worker void CMtProgressMixer2::SetProgressOffset(UInt64 progressOffset)
374*f6dc9357SAndroid Build Coastguard Worker {
375*f6dc9357SAndroid Build Coastguard Worker   CriticalSection.Enter();
376*f6dc9357SAndroid Build Coastguard Worker   SetProgressOffset_NoLock(progressOffset);
377*f6dc9357SAndroid Build Coastguard Worker   CriticalSection.Leave();
378*f6dc9357SAndroid Build Coastguard Worker }
379*f6dc9357SAndroid Build Coastguard Worker 
380*f6dc9357SAndroid Build Coastguard Worker HRESULT CMtProgressMixer2::SetRatioInfo(unsigned index, const UInt64 *inSize, const UInt64 *outSize)
381*f6dc9357SAndroid Build Coastguard Worker {
382*f6dc9357SAndroid Build Coastguard Worker   NWindows::NSynchronization::CCriticalSectionLock lock(CriticalSection);
383*f6dc9357SAndroid Build Coastguard Worker   if (index == 0 && RatioProgress)
384*f6dc9357SAndroid Build Coastguard Worker   {
385*f6dc9357SAndroid Build Coastguard Worker     RINOK(RatioProgress->SetRatioInfo(inSize, outSize))
386*f6dc9357SAndroid Build Coastguard Worker   }
387*f6dc9357SAndroid Build Coastguard Worker   if (inSize)
388*f6dc9357SAndroid Build Coastguard Worker     InSizes[index] = *inSize;
389*f6dc9357SAndroid Build Coastguard Worker   if (outSize)
390*f6dc9357SAndroid Build Coastguard Worker     OutSizes[index] = *outSize;
391*f6dc9357SAndroid Build Coastguard Worker   UInt64 v = ProgressOffset + (_inSizeIsMain  ?
392*f6dc9357SAndroid Build Coastguard Worker       (InSizes[0] + InSizes[1]) :
393*f6dc9357SAndroid Build Coastguard Worker       (OutSizes[0] + OutSizes[1]));
394*f6dc9357SAndroid Build Coastguard Worker   return Progress->SetCompleted(&v);
395*f6dc9357SAndroid Build Coastguard Worker }
396*f6dc9357SAndroid Build Coastguard Worker 
397*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CMtProgressMixer2::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize))
398*f6dc9357SAndroid Build Coastguard Worker {
399*f6dc9357SAndroid Build Coastguard Worker   return SetRatioInfo(0, inSize, outSize);
400*f6dc9357SAndroid Build Coastguard Worker }
401*f6dc9357SAndroid Build Coastguard Worker 
402*f6dc9357SAndroid Build Coastguard Worker 
403*f6dc9357SAndroid Build Coastguard Worker Z7_CLASS_IMP_NOQIB_1(
404*f6dc9357SAndroid Build Coastguard Worker   CMtProgressMixer
405*f6dc9357SAndroid Build Coastguard Worker   , ICompressProgressInfo
406*f6dc9357SAndroid Build Coastguard Worker )
407*f6dc9357SAndroid Build Coastguard Worker public:
408*f6dc9357SAndroid Build Coastguard Worker   CMtProgressMixer2 *Mixer2;
409*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<ICompressProgressInfo> RatioProgress;
410*f6dc9357SAndroid Build Coastguard Worker   void Create(IProgress *progress, bool inSizeIsMain);
411*f6dc9357SAndroid Build Coastguard Worker };
412*f6dc9357SAndroid Build Coastguard Worker 
413*f6dc9357SAndroid Build Coastguard Worker void CMtProgressMixer::Create(IProgress *progress, bool inSizeIsMain)
414*f6dc9357SAndroid Build Coastguard Worker {
415*f6dc9357SAndroid Build Coastguard Worker   Mixer2 = new CMtProgressMixer2;
416*f6dc9357SAndroid Build Coastguard Worker   RatioProgress = Mixer2;
417*f6dc9357SAndroid Build Coastguard Worker   Mixer2->Create(progress, inSizeIsMain);
418*f6dc9357SAndroid Build Coastguard Worker }
419*f6dc9357SAndroid Build Coastguard Worker 
420*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CMtProgressMixer::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize))
421*f6dc9357SAndroid Build Coastguard Worker {
422*f6dc9357SAndroid Build Coastguard Worker   return Mixer2->SetRatioInfo(1, inSize, outSize);
423*f6dc9357SAndroid Build Coastguard Worker }
424*f6dc9357SAndroid Build Coastguard Worker 
425*f6dc9357SAndroid Build Coastguard Worker 
426*f6dc9357SAndroid Build Coastguard Worker #endif
427*f6dc9357SAndroid Build Coastguard Worker 
428*f6dc9357SAndroid Build Coastguard Worker static HRESULT UpdateItemOldData(
429*f6dc9357SAndroid Build Coastguard Worker     COutArchive &archive,
430*f6dc9357SAndroid Build Coastguard Worker     CInArchive *inArchive,
431*f6dc9357SAndroid Build Coastguard Worker     const CItemEx &itemEx,
432*f6dc9357SAndroid Build Coastguard Worker     const CUpdateItem &ui,
433*f6dc9357SAndroid Build Coastguard Worker     CItemOut &item,
434*f6dc9357SAndroid Build Coastguard Worker     /* bool izZip64, */
435*f6dc9357SAndroid Build Coastguard Worker     ICompressProgressInfo *progress,
436*f6dc9357SAndroid Build Coastguard Worker     IArchiveUpdateCallbackFile *opCallback,
437*f6dc9357SAndroid Build Coastguard Worker     UInt64 &complexity)
438*f6dc9357SAndroid Build Coastguard Worker {
439*f6dc9357SAndroid Build Coastguard Worker   if (opCallback)
440*f6dc9357SAndroid Build Coastguard Worker   {
441*f6dc9357SAndroid Build Coastguard Worker     RINOK(opCallback->ReportOperation(
442*f6dc9357SAndroid Build Coastguard Worker         NEventIndexType::kInArcIndex, (UInt32)ui.IndexInArc,
443*f6dc9357SAndroid Build Coastguard Worker         NUpdateNotifyOp::kReplicate))
444*f6dc9357SAndroid Build Coastguard Worker   }
445*f6dc9357SAndroid Build Coastguard Worker 
446*f6dc9357SAndroid Build Coastguard Worker   UInt64 rangeSize;
447*f6dc9357SAndroid Build Coastguard Worker 
448*f6dc9357SAndroid Build Coastguard Worker   RINOK(archive.ClearRestriction())
449*f6dc9357SAndroid Build Coastguard Worker 
450*f6dc9357SAndroid Build Coastguard Worker   if (ui.NewProps)
451*f6dc9357SAndroid Build Coastguard Worker   {
452*f6dc9357SAndroid Build Coastguard Worker     if (item.HasDescriptor())
453*f6dc9357SAndroid Build Coastguard Worker       return E_NOTIMPL;
454*f6dc9357SAndroid Build Coastguard Worker 
455*f6dc9357SAndroid Build Coastguard Worker     // we keep ExternalAttrib and some another properties from old archive
456*f6dc9357SAndroid Build Coastguard Worker     // item.ExternalAttrib = ui.Attrib;
457*f6dc9357SAndroid Build Coastguard Worker     // if we don't change Comment, we keep Comment from OldProperties
458*f6dc9357SAndroid Build Coastguard Worker     Copy_From_UpdateItem_To_ItemOut(ui, item);
459*f6dc9357SAndroid Build Coastguard Worker     // item.SetFlag_AltStream(ui.IsAltStream);
460*f6dc9357SAndroid Build Coastguard Worker 
461*f6dc9357SAndroid Build Coastguard Worker     item.CentralExtra.RemoveUnknownSubBlocks();
462*f6dc9357SAndroid Build Coastguard Worker     item.LocalExtra.RemoveUnknownSubBlocks();
463*f6dc9357SAndroid Build Coastguard Worker 
464*f6dc9357SAndroid Build Coastguard Worker     archive.WriteLocalHeader(item);
465*f6dc9357SAndroid Build Coastguard Worker     rangeSize = item.GetPackSizeWithDescriptor();
466*f6dc9357SAndroid Build Coastguard Worker   }
467*f6dc9357SAndroid Build Coastguard Worker   else
468*f6dc9357SAndroid Build Coastguard Worker   {
469*f6dc9357SAndroid Build Coastguard Worker     item.LocalHeaderPos = archive.GetCurPos();
470*f6dc9357SAndroid Build Coastguard Worker     rangeSize = itemEx.GetLocalFullSize();
471*f6dc9357SAndroid Build Coastguard Worker   }
472*f6dc9357SAndroid Build Coastguard Worker 
473*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<ISequentialInStream> packStream;
474*f6dc9357SAndroid Build Coastguard Worker 
475*f6dc9357SAndroid Build Coastguard Worker   RINOK(inArchive->GetItemStream(itemEx, ui.NewProps, packStream))
476*f6dc9357SAndroid Build Coastguard Worker   if (!packStream)
477*f6dc9357SAndroid Build Coastguard Worker     return E_NOTIMPL;
478*f6dc9357SAndroid Build Coastguard Worker 
479*f6dc9357SAndroid Build Coastguard Worker   complexity += rangeSize;
480*f6dc9357SAndroid Build Coastguard Worker 
481*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<ISequentialOutStream> outStream;
482*f6dc9357SAndroid Build Coastguard Worker   archive.CreateStreamForCopying(outStream);
483*f6dc9357SAndroid Build Coastguard Worker   HRESULT res = NCompress::CopyStream_ExactSize(packStream, outStream, rangeSize, progress);
484*f6dc9357SAndroid Build Coastguard Worker   archive.MoveCurPos(rangeSize);
485*f6dc9357SAndroid Build Coastguard Worker   return res;
486*f6dc9357SAndroid Build Coastguard Worker }
487*f6dc9357SAndroid Build Coastguard Worker 
488*f6dc9357SAndroid Build Coastguard Worker 
489*f6dc9357SAndroid Build Coastguard Worker static HRESULT WriteDirHeader(COutArchive &archive, const CCompressionMethodMode *options,
490*f6dc9357SAndroid Build Coastguard Worker     const CUpdateItem &ui, CItemOut &item)
491*f6dc9357SAndroid Build Coastguard Worker {
492*f6dc9357SAndroid Build Coastguard Worker   SetFileHeader(*options, ui, false, item);
493*f6dc9357SAndroid Build Coastguard Worker   RINOK(archive.ClearRestriction())
494*f6dc9357SAndroid Build Coastguard Worker   archive.WriteLocalHeader(item);
495*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
496*f6dc9357SAndroid Build Coastguard Worker }
497*f6dc9357SAndroid Build Coastguard Worker 
498*f6dc9357SAndroid Build Coastguard Worker 
499*f6dc9357SAndroid Build Coastguard Worker static void UpdatePropsFromStream(
500*f6dc9357SAndroid Build Coastguard Worker     const CUpdateOptions &options,
501*f6dc9357SAndroid Build Coastguard Worker     CUpdateItem &item, ISequentialInStream *fileInStream,
502*f6dc9357SAndroid Build Coastguard Worker     IArchiveUpdateCallback *updateCallback, UInt64 &totalComplexity)
503*f6dc9357SAndroid Build Coastguard Worker {
504*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<IStreamGetProps> getProps;
505*f6dc9357SAndroid Build Coastguard Worker   fileInStream->QueryInterface(IID_IStreamGetProps, (void **)&getProps);
506*f6dc9357SAndroid Build Coastguard Worker   UInt64 size = (UInt64)(Int64)-1;
507*f6dc9357SAndroid Build Coastguard Worker   bool size_WasSet = false;
508*f6dc9357SAndroid Build Coastguard Worker 
509*f6dc9357SAndroid Build Coastguard Worker   if (getProps)
510*f6dc9357SAndroid Build Coastguard Worker   {
511*f6dc9357SAndroid Build Coastguard Worker     FILETIME cTime, aTime, mTime;
512*f6dc9357SAndroid Build Coastguard Worker     UInt32 attrib;
513*f6dc9357SAndroid Build Coastguard Worker     if (getProps->GetProps(&size, &cTime, &aTime, &mTime, &attrib) == S_OK)
514*f6dc9357SAndroid Build Coastguard Worker     {
515*f6dc9357SAndroid Build Coastguard Worker       if (options.Write_MTime)
516*f6dc9357SAndroid Build Coastguard Worker         if (!FILETIME_IsZero(mTime))
517*f6dc9357SAndroid Build Coastguard Worker         {
518*f6dc9357SAndroid Build Coastguard Worker           item.Ntfs_MTime = mTime;
519*f6dc9357SAndroid Build Coastguard Worker           NTime::UtcFileTime_To_LocalDosTime(mTime, item.Time);
520*f6dc9357SAndroid Build Coastguard Worker         }
521*f6dc9357SAndroid Build Coastguard Worker 
522*f6dc9357SAndroid Build Coastguard Worker       if (options.Write_CTime) if (!FILETIME_IsZero(cTime)) item.Ntfs_CTime = cTime;
523*f6dc9357SAndroid Build Coastguard Worker       if (options.Write_ATime) if (!FILETIME_IsZero(aTime)) item.Ntfs_ATime = aTime;
524*f6dc9357SAndroid Build Coastguard Worker 
525*f6dc9357SAndroid Build Coastguard Worker       item.Attrib = attrib;
526*f6dc9357SAndroid Build Coastguard Worker       size_WasSet = true;
527*f6dc9357SAndroid Build Coastguard Worker     }
528*f6dc9357SAndroid Build Coastguard Worker   }
529*f6dc9357SAndroid Build Coastguard Worker 
530*f6dc9357SAndroid Build Coastguard Worker   if (!size_WasSet)
531*f6dc9357SAndroid Build Coastguard Worker   {
532*f6dc9357SAndroid Build Coastguard Worker     CMyComPtr<IStreamGetSize> streamGetSize;
533*f6dc9357SAndroid Build Coastguard Worker     fileInStream->QueryInterface(IID_IStreamGetSize, (void **)&streamGetSize);
534*f6dc9357SAndroid Build Coastguard Worker     if (streamGetSize)
535*f6dc9357SAndroid Build Coastguard Worker     {
536*f6dc9357SAndroid Build Coastguard Worker       if (streamGetSize->GetSize(&size) == S_OK)
537*f6dc9357SAndroid Build Coastguard Worker         size_WasSet = true;
538*f6dc9357SAndroid Build Coastguard Worker     }
539*f6dc9357SAndroid Build Coastguard Worker   }
540*f6dc9357SAndroid Build Coastguard Worker 
541*f6dc9357SAndroid Build Coastguard Worker   if (size_WasSet && size != (UInt64)(Int64)-1)
542*f6dc9357SAndroid Build Coastguard Worker   {
543*f6dc9357SAndroid Build Coastguard Worker     item.Size_WasSetFromStream = true;
544*f6dc9357SAndroid Build Coastguard Worker     if (size != item.Size)
545*f6dc9357SAndroid Build Coastguard Worker     {
546*f6dc9357SAndroid Build Coastguard Worker       const Int64 newComplexity = (Int64)totalComplexity + ((Int64)size - (Int64)item.Size);
547*f6dc9357SAndroid Build Coastguard Worker       if (newComplexity > 0)
548*f6dc9357SAndroid Build Coastguard Worker       {
549*f6dc9357SAndroid Build Coastguard Worker         totalComplexity = (UInt64)newComplexity;
550*f6dc9357SAndroid Build Coastguard Worker         updateCallback->SetTotal(totalComplexity);
551*f6dc9357SAndroid Build Coastguard Worker       }
552*f6dc9357SAndroid Build Coastguard Worker       item.Size = size;
553*f6dc9357SAndroid Build Coastguard Worker     }
554*f6dc9357SAndroid Build Coastguard Worker   }
555*f6dc9357SAndroid Build Coastguard Worker }
556*f6dc9357SAndroid Build Coastguard Worker 
557*f6dc9357SAndroid Build Coastguard Worker 
558*f6dc9357SAndroid Build Coastguard Worker /*
559*f6dc9357SAndroid Build Coastguard Worker static HRESULT ReportProps(
560*f6dc9357SAndroid Build Coastguard Worker     IArchiveUpdateCallbackArcProp *reportArcProp,
561*f6dc9357SAndroid Build Coastguard Worker     UInt32 index,
562*f6dc9357SAndroid Build Coastguard Worker     const CItemOut &item,
563*f6dc9357SAndroid Build Coastguard Worker     bool isAesMode)
564*f6dc9357SAndroid Build Coastguard Worker {
565*f6dc9357SAndroid Build Coastguard Worker   PROPVARIANT prop;
566*f6dc9357SAndroid Build Coastguard Worker   prop.vt = VT_EMPTY;
567*f6dc9357SAndroid Build Coastguard Worker   prop.wReserved1 = 0;
568*f6dc9357SAndroid Build Coastguard Worker 
569*f6dc9357SAndroid Build Coastguard Worker   NCOM::PropVarEm_Set_UInt64(&prop, item.Size);
570*f6dc9357SAndroid Build Coastguard Worker   RINOK(reportArcProp->ReportProp(NEventIndexType::kOutArcIndex, index, kpidSize, &prop));
571*f6dc9357SAndroid Build Coastguard Worker 
572*f6dc9357SAndroid Build Coastguard Worker   NCOM::PropVarEm_Set_UInt64(&prop, item.PackSize);
573*f6dc9357SAndroid Build Coastguard Worker   RINOK(reportArcProp->ReportProp(NEventIndexType::kOutArcIndex, index, kpidPackSize, &prop));
574*f6dc9357SAndroid Build Coastguard Worker 
575*f6dc9357SAndroid Build Coastguard Worker   if (!isAesMode)
576*f6dc9357SAndroid Build Coastguard Worker   {
577*f6dc9357SAndroid Build Coastguard Worker     NCOM::PropVarEm_Set_UInt32(&prop, item.Crc);
578*f6dc9357SAndroid Build Coastguard Worker     RINOK(reportArcProp->ReportProp(NEventIndexType::kOutArcIndex, index, kpidCRC, &prop));
579*f6dc9357SAndroid Build Coastguard Worker   }
580*f6dc9357SAndroid Build Coastguard Worker 
581*f6dc9357SAndroid Build Coastguard Worker   RINOK(reportArcProp->ReportFinished(NEventIndexType::kOutArcIndex, index, NUpdate::NOperationResult::kOK));
582*f6dc9357SAndroid Build Coastguard Worker 
583*f6dc9357SAndroid Build Coastguard Worker   // if (opCallback) RINOK(opCallback->ReportOperation(NEventIndexType::kOutArcIndex, index, NUpdateNotifyOp::kOpFinished))
584*f6dc9357SAndroid Build Coastguard Worker 
585*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
586*f6dc9357SAndroid Build Coastguard Worker }
587*f6dc9357SAndroid Build Coastguard Worker */
588*f6dc9357SAndroid Build Coastguard Worker 
589*f6dc9357SAndroid Build Coastguard Worker /*
590*f6dc9357SAndroid Build Coastguard Worker struct CTotalStats
591*f6dc9357SAndroid Build Coastguard Worker {
592*f6dc9357SAndroid Build Coastguard Worker   UInt64 Size;
593*f6dc9357SAndroid Build Coastguard Worker   UInt64 PackSize;
594*f6dc9357SAndroid Build Coastguard Worker 
595*f6dc9357SAndroid Build Coastguard Worker   void UpdateWithItem(const CItemOut &item)
596*f6dc9357SAndroid Build Coastguard Worker   {
597*f6dc9357SAndroid Build Coastguard Worker     Size += item.Size;
598*f6dc9357SAndroid Build Coastguard Worker     PackSize += item.PackSize;
599*f6dc9357SAndroid Build Coastguard Worker   }
600*f6dc9357SAndroid Build Coastguard Worker };
601*f6dc9357SAndroid Build Coastguard Worker 
602*f6dc9357SAndroid Build Coastguard Worker static HRESULT ReportArcProps(IArchiveUpdateCallbackArcProp *reportArcProp,
603*f6dc9357SAndroid Build Coastguard Worker     CTotalStats &st)
604*f6dc9357SAndroid Build Coastguard Worker {
605*f6dc9357SAndroid Build Coastguard Worker   PROPVARIANT prop;
606*f6dc9357SAndroid Build Coastguard Worker   prop.vt = VT_EMPTY;
607*f6dc9357SAndroid Build Coastguard Worker   prop.wReserved1 = 0;
608*f6dc9357SAndroid Build Coastguard Worker   {
609*f6dc9357SAndroid Build Coastguard Worker     NWindows::NCOM::PropVarEm_Set_UInt64(&prop, st.Size);
610*f6dc9357SAndroid Build Coastguard Worker     RINOK(reportArcProp->ReportProp(
611*f6dc9357SAndroid Build Coastguard Worker       NEventIndexType::kArcProp, 0, kpidSize, &prop));
612*f6dc9357SAndroid Build Coastguard Worker   }
613*f6dc9357SAndroid Build Coastguard Worker   {
614*f6dc9357SAndroid Build Coastguard Worker     NWindows::NCOM::PropVarEm_Set_UInt64(&prop, st.PackSize);
615*f6dc9357SAndroid Build Coastguard Worker     RINOK(reportArcProp->ReportProp(
616*f6dc9357SAndroid Build Coastguard Worker       NEventIndexType::kArcProp, 0, kpidPackSize, &prop));
617*f6dc9357SAndroid Build Coastguard Worker   }
618*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
619*f6dc9357SAndroid Build Coastguard Worker }
620*f6dc9357SAndroid Build Coastguard Worker */
621*f6dc9357SAndroid Build Coastguard Worker 
622*f6dc9357SAndroid Build Coastguard Worker 
623*f6dc9357SAndroid Build Coastguard Worker static HRESULT Update2St(
624*f6dc9357SAndroid Build Coastguard Worker     DECL_EXTERNAL_CODECS_LOC_VARS
625*f6dc9357SAndroid Build Coastguard Worker     COutArchive &archive,
626*f6dc9357SAndroid Build Coastguard Worker     CInArchive *inArchive,
627*f6dc9357SAndroid Build Coastguard Worker     const CObjectVector<CItemEx> &inputItems,
628*f6dc9357SAndroid Build Coastguard Worker     CObjectVector<CUpdateItem> &updateItems,
629*f6dc9357SAndroid Build Coastguard Worker     const CUpdateOptions &updateOptions,
630*f6dc9357SAndroid Build Coastguard Worker     const CCompressionMethodMode *options, bool outSeqMode,
631*f6dc9357SAndroid Build Coastguard Worker     const CByteBuffer *comment,
632*f6dc9357SAndroid Build Coastguard Worker     IArchiveUpdateCallback *updateCallback,
633*f6dc9357SAndroid Build Coastguard Worker     UInt64 &totalComplexity,
634*f6dc9357SAndroid Build Coastguard Worker     IArchiveUpdateCallbackFile *opCallback
635*f6dc9357SAndroid Build Coastguard Worker     // , IArchiveUpdateCallbackArcProp *reportArcProp
636*f6dc9357SAndroid Build Coastguard Worker     )
637*f6dc9357SAndroid Build Coastguard Worker {
638*f6dc9357SAndroid Build Coastguard Worker   CLocalProgress *lps = new CLocalProgress;
639*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<ICompressProgressInfo> progress = lps;
640*f6dc9357SAndroid Build Coastguard Worker   lps->Init(updateCallback, true);
641*f6dc9357SAndroid Build Coastguard Worker 
642*f6dc9357SAndroid Build Coastguard Worker   CAddCommon compressor;
643*f6dc9357SAndroid Build Coastguard Worker   compressor.SetOptions(*options);
644*f6dc9357SAndroid Build Coastguard Worker 
645*f6dc9357SAndroid Build Coastguard Worker   CObjectVector<CItemOut> items;
646*f6dc9357SAndroid Build Coastguard Worker   UInt64 unpackSizeTotal = 0, packSizeTotal = 0;
647*f6dc9357SAndroid Build Coastguard Worker 
648*f6dc9357SAndroid Build Coastguard Worker   FOR_VECTOR (itemIndex, updateItems)
649*f6dc9357SAndroid Build Coastguard Worker   {
650*f6dc9357SAndroid Build Coastguard Worker     lps->InSize = unpackSizeTotal;
651*f6dc9357SAndroid Build Coastguard Worker     lps->OutSize = packSizeTotal;
652*f6dc9357SAndroid Build Coastguard Worker     RINOK(lps->SetCur())
653*f6dc9357SAndroid Build Coastguard Worker     CUpdateItem &ui = updateItems[itemIndex];
654*f6dc9357SAndroid Build Coastguard Worker     CItemEx itemEx;
655*f6dc9357SAndroid Build Coastguard Worker     CItemOut item;
656*f6dc9357SAndroid Build Coastguard Worker 
657*f6dc9357SAndroid Build Coastguard Worker     if (!ui.NewProps || !ui.NewData)
658*f6dc9357SAndroid Build Coastguard Worker     {
659*f6dc9357SAndroid Build Coastguard Worker       // Note: for (ui.NewProps && !ui.NewData) it copies Props from old archive,
660*f6dc9357SAndroid Build Coastguard Worker       // But we will rewrite all important properties later. But we can keep some properties like Comment
661*f6dc9357SAndroid Build Coastguard Worker       itemEx = inputItems[(unsigned)ui.IndexInArc];
662*f6dc9357SAndroid Build Coastguard Worker       if (inArchive->Read_LocalItem_After_CdItem_Full(itemEx) != S_OK)
663*f6dc9357SAndroid Build Coastguard Worker         return E_NOTIMPL;
664*f6dc9357SAndroid Build Coastguard Worker       (CItem &)item = itemEx;
665*f6dc9357SAndroid Build Coastguard Worker     }
666*f6dc9357SAndroid Build Coastguard Worker 
667*f6dc9357SAndroid Build Coastguard Worker     if (ui.NewData)
668*f6dc9357SAndroid Build Coastguard Worker     {
669*f6dc9357SAndroid Build Coastguard Worker       // bool isDir = ((ui.NewProps) ? ui.IsDir : item.IsDir());
670*f6dc9357SAndroid Build Coastguard Worker       bool isDir = ui.IsDir;
671*f6dc9357SAndroid Build Coastguard Worker       if (isDir)
672*f6dc9357SAndroid Build Coastguard Worker       {
673*f6dc9357SAndroid Build Coastguard Worker         RINOK(WriteDirHeader(archive, options, ui, item))
674*f6dc9357SAndroid Build Coastguard Worker       }
675*f6dc9357SAndroid Build Coastguard Worker       else
676*f6dc9357SAndroid Build Coastguard Worker       {
677*f6dc9357SAndroid Build Coastguard Worker        CMyComPtr<ISequentialInStream> fileInStream;
678*f6dc9357SAndroid Build Coastguard Worker        {
679*f6dc9357SAndroid Build Coastguard Worker         HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream);
680*f6dc9357SAndroid Build Coastguard Worker         if (res == S_FALSE)
681*f6dc9357SAndroid Build Coastguard Worker         {
682*f6dc9357SAndroid Build Coastguard Worker           lps->ProgressOffset += ui.Size;
683*f6dc9357SAndroid Build Coastguard Worker           RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK))
684*f6dc9357SAndroid Build Coastguard Worker           continue;
685*f6dc9357SAndroid Build Coastguard Worker         }
686*f6dc9357SAndroid Build Coastguard Worker         RINOK(res)
687*f6dc9357SAndroid Build Coastguard Worker         if (!fileInStream)
688*f6dc9357SAndroid Build Coastguard Worker           return E_INVALIDARG;
689*f6dc9357SAndroid Build Coastguard Worker 
690*f6dc9357SAndroid Build Coastguard Worker         bool inSeqMode = false;
691*f6dc9357SAndroid Build Coastguard Worker         if (!inSeqMode)
692*f6dc9357SAndroid Build Coastguard Worker         {
693*f6dc9357SAndroid Build Coastguard Worker           CMyComPtr<IInStream> inStream2;
694*f6dc9357SAndroid Build Coastguard Worker           fileInStream->QueryInterface(IID_IInStream, (void **)&inStream2);
695*f6dc9357SAndroid Build Coastguard Worker           inSeqMode = (inStream2 == NULL);
696*f6dc9357SAndroid Build Coastguard Worker         }
697*f6dc9357SAndroid Build Coastguard Worker         // seqMode = true; // to test seqMode
698*f6dc9357SAndroid Build Coastguard Worker 
699*f6dc9357SAndroid Build Coastguard Worker         UpdatePropsFromStream(updateOptions, ui, fileInStream, updateCallback, totalComplexity);
700*f6dc9357SAndroid Build Coastguard Worker 
701*f6dc9357SAndroid Build Coastguard Worker         CCompressingResult compressingResult;
702*f6dc9357SAndroid Build Coastguard Worker 
703*f6dc9357SAndroid Build Coastguard Worker         RINOK(compressor.Set_Pre_CompressionResult(
704*f6dc9357SAndroid Build Coastguard Worker             inSeqMode, outSeqMode,
705*f6dc9357SAndroid Build Coastguard Worker             ui.Size,
706*f6dc9357SAndroid Build Coastguard Worker             compressingResult))
707*f6dc9357SAndroid Build Coastguard Worker 
708*f6dc9357SAndroid Build Coastguard Worker         SetFileHeader(*options, ui, compressingResult.DescriptorMode, item);
709*f6dc9357SAndroid Build Coastguard Worker 
710*f6dc9357SAndroid Build Coastguard Worker         // file Size can be 64-bit !!!
711*f6dc9357SAndroid Build Coastguard Worker 
712*f6dc9357SAndroid Build Coastguard Worker         SetItemInfoFromCompressingResult(compressingResult, options->IsRealAesMode(), options->AesKeyMode, item);
713*f6dc9357SAndroid Build Coastguard Worker 
714*f6dc9357SAndroid Build Coastguard Worker         RINOK(archive.SetRestrictionFromCurrent())
715*f6dc9357SAndroid Build Coastguard Worker         archive.WriteLocalHeader(item);
716*f6dc9357SAndroid Build Coastguard Worker 
717*f6dc9357SAndroid Build Coastguard Worker         CMyComPtr<IOutStream> outStream;
718*f6dc9357SAndroid Build Coastguard Worker         archive.CreateStreamForCompressing(outStream);
719*f6dc9357SAndroid Build Coastguard Worker 
720*f6dc9357SAndroid Build Coastguard Worker         RINOK(compressor.Compress(
721*f6dc9357SAndroid Build Coastguard Worker             EXTERNAL_CODECS_LOC_VARS
722*f6dc9357SAndroid Build Coastguard Worker             fileInStream, outStream,
723*f6dc9357SAndroid Build Coastguard Worker             inSeqMode, outSeqMode,
724*f6dc9357SAndroid Build Coastguard Worker             ui.Time,
725*f6dc9357SAndroid Build Coastguard Worker             ui.Size, ui.Size_WasSetFromStream,
726*f6dc9357SAndroid Build Coastguard Worker             progress, compressingResult))
727*f6dc9357SAndroid Build Coastguard Worker 
728*f6dc9357SAndroid Build Coastguard Worker         if (item.HasDescriptor() != compressingResult.DescriptorMode)
729*f6dc9357SAndroid Build Coastguard Worker           return E_FAIL;
730*f6dc9357SAndroid Build Coastguard Worker 
731*f6dc9357SAndroid Build Coastguard Worker         SetItemInfoFromCompressingResult(compressingResult, options->IsRealAesMode(), options->AesKeyMode, item);
732*f6dc9357SAndroid Build Coastguard Worker 
733*f6dc9357SAndroid Build Coastguard Worker         archive.WriteLocalHeader_Replace(item);
734*f6dc9357SAndroid Build Coastguard Worker        }
735*f6dc9357SAndroid Build Coastguard Worker        // if (reportArcProp) RINOK(ReportProps(reportArcProp, ui.IndexInClient, item, options->IsRealAesMode()))
736*f6dc9357SAndroid Build Coastguard Worker        RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK))
737*f6dc9357SAndroid Build Coastguard Worker        unpackSizeTotal += item.Size;
738*f6dc9357SAndroid Build Coastguard Worker        packSizeTotal += item.PackSize;
739*f6dc9357SAndroid Build Coastguard Worker       }
740*f6dc9357SAndroid Build Coastguard Worker     }
741*f6dc9357SAndroid Build Coastguard Worker     else
742*f6dc9357SAndroid Build Coastguard Worker     {
743*f6dc9357SAndroid Build Coastguard Worker       UInt64 complexity = 0;
744*f6dc9357SAndroid Build Coastguard Worker       lps->SendRatio = false;
745*f6dc9357SAndroid Build Coastguard Worker 
746*f6dc9357SAndroid Build Coastguard Worker       RINOK(UpdateItemOldData(archive, inArchive, itemEx, ui, item, progress, opCallback, complexity))
747*f6dc9357SAndroid Build Coastguard Worker 
748*f6dc9357SAndroid Build Coastguard Worker       lps->SendRatio = true;
749*f6dc9357SAndroid Build Coastguard Worker       lps->ProgressOffset += complexity;
750*f6dc9357SAndroid Build Coastguard Worker     }
751*f6dc9357SAndroid Build Coastguard Worker 
752*f6dc9357SAndroid Build Coastguard Worker     items.Add(item);
753*f6dc9357SAndroid Build Coastguard Worker     lps->ProgressOffset += kLocalHeaderSize;
754*f6dc9357SAndroid Build Coastguard Worker   }
755*f6dc9357SAndroid Build Coastguard Worker 
756*f6dc9357SAndroid Build Coastguard Worker   lps->InSize = unpackSizeTotal;
757*f6dc9357SAndroid Build Coastguard Worker   lps->OutSize = packSizeTotal;
758*f6dc9357SAndroid Build Coastguard Worker   RINOK(lps->SetCur())
759*f6dc9357SAndroid Build Coastguard Worker 
760*f6dc9357SAndroid Build Coastguard Worker   RINOK(archive.WriteCentralDir(items, comment))
761*f6dc9357SAndroid Build Coastguard Worker 
762*f6dc9357SAndroid Build Coastguard Worker   /*
763*f6dc9357SAndroid Build Coastguard Worker   CTotalStats stat;
764*f6dc9357SAndroid Build Coastguard Worker   stat.Size = unpackSizeTotal;
765*f6dc9357SAndroid Build Coastguard Worker   stat.PackSize = packSizeTotal;
766*f6dc9357SAndroid Build Coastguard Worker   if (reportArcProp)
767*f6dc9357SAndroid Build Coastguard Worker     RINOK(ReportArcProps(reportArcProp, stat))
768*f6dc9357SAndroid Build Coastguard Worker   */
769*f6dc9357SAndroid Build Coastguard Worker 
770*f6dc9357SAndroid Build Coastguard Worker   lps->ProgressOffset += kCentralHeaderSize * updateItems.Size() + 1;
771*f6dc9357SAndroid Build Coastguard Worker   return lps->SetCur();
772*f6dc9357SAndroid Build Coastguard Worker }
773*f6dc9357SAndroid Build Coastguard Worker 
774*f6dc9357SAndroid Build Coastguard Worker #ifndef Z7_ST
775*f6dc9357SAndroid Build Coastguard Worker 
776*f6dc9357SAndroid Build Coastguard Worker 
777*f6dc9357SAndroid Build Coastguard Worker static const size_t kBlockSize = 1 << 16;
778*f6dc9357SAndroid Build Coastguard Worker // kMemPerThread must be >= kBlockSize
779*f6dc9357SAndroid Build Coastguard Worker //
780*f6dc9357SAndroid Build Coastguard Worker static const size_t kMemPerThread = (size_t)sizeof(size_t) << 23;
781*f6dc9357SAndroid Build Coastguard Worker // static const size_t kMemPerThread = (size_t)sizeof(size_t) << 16; // for debug
782*f6dc9357SAndroid Build Coastguard Worker // static const size_t kMemPerThread = (size_t)1 << 16; // for debug
783*f6dc9357SAndroid Build Coastguard Worker 
784*f6dc9357SAndroid Build Coastguard Worker /*
785*f6dc9357SAndroid Build Coastguard Worker in:
786*f6dc9357SAndroid Build Coastguard Worker    nt_Zip >= 1:  the starting maximum number of ZIP threads for search
787*f6dc9357SAndroid Build Coastguard Worker out:
788*f6dc9357SAndroid Build Coastguard Worker    nt_Zip:  calculated number of ZIP threads
789*f6dc9357SAndroid Build Coastguard Worker    returns: calculated number of ZSTD threads
790*f6dc9357SAndroid Build Coastguard Worker */
791*f6dc9357SAndroid Build Coastguard Worker /*
792*f6dc9357SAndroid Build Coastguard Worker static UInt32 CalcThreads_for_ZipZstd(CZstdEncProps *zstdProps,
793*f6dc9357SAndroid Build Coastguard Worker     UInt64 memLimit, UInt32 totalThreads,
794*f6dc9357SAndroid Build Coastguard Worker     UInt32 &nt_Zip)
795*f6dc9357SAndroid Build Coastguard Worker {
796*f6dc9357SAndroid Build Coastguard Worker   for (; nt_Zip > 1; nt_Zip--)
797*f6dc9357SAndroid Build Coastguard Worker   {
798*f6dc9357SAndroid Build Coastguard Worker     UInt64 mem1 = memLimit / nt_Zip;
799*f6dc9357SAndroid Build Coastguard Worker     if (mem1 <= kMemPerThread)
800*f6dc9357SAndroid Build Coastguard Worker       continue;
801*f6dc9357SAndroid Build Coastguard Worker     mem1 -= kMemPerThread;
802*f6dc9357SAndroid Build Coastguard Worker     UInt32 n_ZSTD = ZstdEncProps_GetNumThreads_for_MemUsageLimit(
803*f6dc9357SAndroid Build Coastguard Worker         zstdProps, mem1, totalThreads / nt_Zip);
804*f6dc9357SAndroid Build Coastguard Worker     // we don't allow (nbWorkers == 1) here
805*f6dc9357SAndroid Build Coastguard Worker     if (n_ZSTD <= 1)
806*f6dc9357SAndroid Build Coastguard Worker       n_ZSTD = 0;
807*f6dc9357SAndroid Build Coastguard Worker     zstdProps->nbWorkers = n_ZSTD;
808*f6dc9357SAndroid Build Coastguard Worker     mem1 = ZstdEncProps_GetMemUsage(zstdProps);
809*f6dc9357SAndroid Build Coastguard Worker     if ((mem1 + kMemPerThread) * nt_Zip <= memLimit)
810*f6dc9357SAndroid Build Coastguard Worker       return n_ZSTD;
811*f6dc9357SAndroid Build Coastguard Worker   }
812*f6dc9357SAndroid Build Coastguard Worker   return ZstdEncProps_GetNumThreads_for_MemUsageLimit(
813*f6dc9357SAndroid Build Coastguard Worker       zstdProps, memLimit, totalThreads);
814*f6dc9357SAndroid Build Coastguard Worker }
815*f6dc9357SAndroid Build Coastguard Worker 
816*f6dc9357SAndroid Build Coastguard Worker 
817*f6dc9357SAndroid Build Coastguard Worker static UInt32 SetZstdThreads(
818*f6dc9357SAndroid Build Coastguard Worker     const CCompressionMethodMode &options,
819*f6dc9357SAndroid Build Coastguard Worker     COneMethodInfo *oneMethodMain,
820*f6dc9357SAndroid Build Coastguard Worker     UInt32 numThreads,
821*f6dc9357SAndroid Build Coastguard Worker     UInt32 numZipThreads_limit,
822*f6dc9357SAndroid Build Coastguard Worker     UInt64 numFilesToCompress,
823*f6dc9357SAndroid Build Coastguard Worker     UInt64 numBytesToCompress)
824*f6dc9357SAndroid Build Coastguard Worker {
825*f6dc9357SAndroid Build Coastguard Worker   NCompress::NZstd::CEncoderProps encoderProps;
826*f6dc9357SAndroid Build Coastguard Worker   RINOK(encoderProps.SetFromMethodProps(*oneMethodMain));
827*f6dc9357SAndroid Build Coastguard Worker   CZstdEncProps &zstdProps = encoderProps.EncProps;
828*f6dc9357SAndroid Build Coastguard Worker   ZstdEncProps_NormalizeFull(&zstdProps);
829*f6dc9357SAndroid Build Coastguard Worker   if (oneMethodMain->FindProp(NCoderPropID::kNumThreads) >= 0)
830*f6dc9357SAndroid Build Coastguard Worker   {
831*f6dc9357SAndroid Build Coastguard Worker     // threads for ZSTD are fixed
832*f6dc9357SAndroid Build Coastguard Worker     if (zstdProps.nbWorkers > 1)
833*f6dc9357SAndroid Build Coastguard Worker       numThreads /= zstdProps.nbWorkers;
834*f6dc9357SAndroid Build Coastguard Worker     if (numThreads > numZipThreads_limit)
835*f6dc9357SAndroid Build Coastguard Worker       numThreads = numZipThreads_limit;
836*f6dc9357SAndroid Build Coastguard Worker     if (options._memUsage_WasSet
837*f6dc9357SAndroid Build Coastguard Worker         && !options._numThreads_WasForced)
838*f6dc9357SAndroid Build Coastguard Worker     {
839*f6dc9357SAndroid Build Coastguard Worker       const UInt64 mem1 = ZstdEncProps_GetMemUsage(&zstdProps);
840*f6dc9357SAndroid Build Coastguard Worker       const UInt64 numZipThreads = options._memUsage_Compress / (mem1 + kMemPerThread);
841*f6dc9357SAndroid Build Coastguard Worker       if (numThreads > numZipThreads)
842*f6dc9357SAndroid Build Coastguard Worker         numThreads = (UInt32)numZipThreads;
843*f6dc9357SAndroid Build Coastguard Worker     }
844*f6dc9357SAndroid Build Coastguard Worker     return numThreads;
845*f6dc9357SAndroid Build Coastguard Worker   }
846*f6dc9357SAndroid Build Coastguard Worker   {
847*f6dc9357SAndroid Build Coastguard Worker     // threads for ZSTD are not fixed
848*f6dc9357SAndroid Build Coastguard Worker 
849*f6dc9357SAndroid Build Coastguard Worker     // calculate estimated required number of ZST threads per file size statistics
850*f6dc9357SAndroid Build Coastguard Worker     UInt32 t = MY_ZSTDMT_NBWORKERS_MAX;
851*f6dc9357SAndroid Build Coastguard Worker     {
852*f6dc9357SAndroid Build Coastguard Worker       UInt64 averageNumberOfBlocks = 0;
853*f6dc9357SAndroid Build Coastguard Worker       const UInt64 averageSize = numBytesToCompress / numFilesToCompress;
854*f6dc9357SAndroid Build Coastguard Worker       const UInt64 jobSize = zstdProps.jobSize;
855*f6dc9357SAndroid Build Coastguard Worker       if (jobSize != 0)
856*f6dc9357SAndroid Build Coastguard Worker         averageNumberOfBlocks = averageSize / jobSize + 0;
857*f6dc9357SAndroid Build Coastguard Worker       if (t > averageNumberOfBlocks)
858*f6dc9357SAndroid Build Coastguard Worker         t = (UInt32)averageNumberOfBlocks;
859*f6dc9357SAndroid Build Coastguard Worker     }
860*f6dc9357SAndroid Build Coastguard Worker     if (t > numThreads)
861*f6dc9357SAndroid Build Coastguard Worker       t = numThreads;
862*f6dc9357SAndroid Build Coastguard Worker 
863*f6dc9357SAndroid Build Coastguard Worker     // calculate the nuber of zip threads
864*f6dc9357SAndroid Build Coastguard Worker     UInt32 numZipThreads = numThreads;
865*f6dc9357SAndroid Build Coastguard Worker     if (t > 1)
866*f6dc9357SAndroid Build Coastguard Worker       numZipThreads = numThreads / t;
867*f6dc9357SAndroid Build Coastguard Worker     if (numZipThreads > numZipThreads_limit)
868*f6dc9357SAndroid Build Coastguard Worker       numZipThreads = numZipThreads_limit;
869*f6dc9357SAndroid Build Coastguard Worker     if (numZipThreads < 1)
870*f6dc9357SAndroid Build Coastguard Worker       numZipThreads = 1;
871*f6dc9357SAndroid Build Coastguard Worker     {
872*f6dc9357SAndroid Build Coastguard Worker       // recalculate the number of ZSTD threads via the number of ZIP threads
873*f6dc9357SAndroid Build Coastguard Worker       const UInt32 t2 = numThreads / numZipThreads;
874*f6dc9357SAndroid Build Coastguard Worker       if (t < t2)
875*f6dc9357SAndroid Build Coastguard Worker         t = t2;
876*f6dc9357SAndroid Build Coastguard Worker     }
877*f6dc9357SAndroid Build Coastguard Worker 
878*f6dc9357SAndroid Build Coastguard Worker     if (options._memUsage_WasSet
879*f6dc9357SAndroid Build Coastguard Worker         && !options._numThreads_WasForced)
880*f6dc9357SAndroid Build Coastguard Worker     {
881*f6dc9357SAndroid Build Coastguard Worker       t = CalcThreads_for_ZipZstd(&zstdProps,
882*f6dc9357SAndroid Build Coastguard Worker           options._memUsage_Compress, numThreads, numZipThreads);
883*f6dc9357SAndroid Build Coastguard Worker       numThreads = numZipThreads;
884*f6dc9357SAndroid Build Coastguard Worker     }
885*f6dc9357SAndroid Build Coastguard Worker     // we don't use (nbWorkers = 1) here
886*f6dc9357SAndroid Build Coastguard Worker     if (t <= 1)
887*f6dc9357SAndroid Build Coastguard Worker       t = 0;
888*f6dc9357SAndroid Build Coastguard Worker     oneMethodMain->AddProp_NumThreads(t);
889*f6dc9357SAndroid Build Coastguard Worker     return numThreads;
890*f6dc9357SAndroid Build Coastguard Worker   }
891*f6dc9357SAndroid Build Coastguard Worker }
892*f6dc9357SAndroid Build Coastguard Worker */
893*f6dc9357SAndroid Build Coastguard Worker 
894*f6dc9357SAndroid Build Coastguard Worker #endif
895*f6dc9357SAndroid Build Coastguard Worker 
896*f6dc9357SAndroid Build Coastguard Worker 
897*f6dc9357SAndroid Build Coastguard Worker 
898*f6dc9357SAndroid Build Coastguard Worker 
899*f6dc9357SAndroid Build Coastguard Worker static HRESULT Update2(
900*f6dc9357SAndroid Build Coastguard Worker     DECL_EXTERNAL_CODECS_LOC_VARS
901*f6dc9357SAndroid Build Coastguard Worker     COutArchive &archive,
902*f6dc9357SAndroid Build Coastguard Worker     CInArchive *inArchive,
903*f6dc9357SAndroid Build Coastguard Worker     const CObjectVector<CItemEx> &inputItems,
904*f6dc9357SAndroid Build Coastguard Worker     CObjectVector<CUpdateItem> &updateItems,
905*f6dc9357SAndroid Build Coastguard Worker     const CUpdateOptions &updateOptions,
906*f6dc9357SAndroid Build Coastguard Worker     const CCompressionMethodMode &options, bool outSeqMode,
907*f6dc9357SAndroid Build Coastguard Worker     const CByteBuffer *comment,
908*f6dc9357SAndroid Build Coastguard Worker     IArchiveUpdateCallback *updateCallback)
909*f6dc9357SAndroid Build Coastguard Worker {
910*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<IArchiveUpdateCallbackFile> opCallback;
911*f6dc9357SAndroid Build Coastguard Worker   updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback);
912*f6dc9357SAndroid Build Coastguard Worker 
913*f6dc9357SAndroid Build Coastguard Worker   /*
914*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<IArchiveUpdateCallbackArcProp> reportArcProp;
915*f6dc9357SAndroid Build Coastguard Worker   updateCallback->QueryInterface(IID_IArchiveUpdateCallbackArcProp, (void **)&reportArcProp);
916*f6dc9357SAndroid Build Coastguard Worker   */
917*f6dc9357SAndroid Build Coastguard Worker 
918*f6dc9357SAndroid Build Coastguard Worker   bool unknownComplexity = false;
919*f6dc9357SAndroid Build Coastguard Worker   UInt64 complexity = 0;
920*f6dc9357SAndroid Build Coastguard Worker  #ifndef Z7_ST
921*f6dc9357SAndroid Build Coastguard Worker   UInt64 numFilesToCompress = 0;
922*f6dc9357SAndroid Build Coastguard Worker   UInt64 numBytesToCompress = 0;
923*f6dc9357SAndroid Build Coastguard Worker  #endif
924*f6dc9357SAndroid Build Coastguard Worker 
925*f6dc9357SAndroid Build Coastguard Worker   unsigned i;
926*f6dc9357SAndroid Build Coastguard Worker 
927*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < updateItems.Size(); i++)
928*f6dc9357SAndroid Build Coastguard Worker   {
929*f6dc9357SAndroid Build Coastguard Worker     const CUpdateItem &ui = updateItems[i];
930*f6dc9357SAndroid Build Coastguard Worker     if (ui.NewData)
931*f6dc9357SAndroid Build Coastguard Worker     {
932*f6dc9357SAndroid Build Coastguard Worker       if (ui.Size == (UInt64)(Int64)-1)
933*f6dc9357SAndroid Build Coastguard Worker         unknownComplexity = true;
934*f6dc9357SAndroid Build Coastguard Worker       else
935*f6dc9357SAndroid Build Coastguard Worker         complexity += ui.Size;
936*f6dc9357SAndroid Build Coastguard Worker      #ifndef Z7_ST
937*f6dc9357SAndroid Build Coastguard Worker       numBytesToCompress += ui.Size;
938*f6dc9357SAndroid Build Coastguard Worker       numFilesToCompress++;
939*f6dc9357SAndroid Build Coastguard Worker      #endif
940*f6dc9357SAndroid Build Coastguard Worker       /*
941*f6dc9357SAndroid Build Coastguard Worker       if (ui.Commented)
942*f6dc9357SAndroid Build Coastguard Worker         complexity += ui.CommentRange.Size;
943*f6dc9357SAndroid Build Coastguard Worker       */
944*f6dc9357SAndroid Build Coastguard Worker     }
945*f6dc9357SAndroid Build Coastguard Worker     else
946*f6dc9357SAndroid Build Coastguard Worker     {
947*f6dc9357SAndroid Build Coastguard Worker       CItemEx inputItem = inputItems[(unsigned)ui.IndexInArc];
948*f6dc9357SAndroid Build Coastguard Worker       if (inArchive->Read_LocalItem_After_CdItem_Full(inputItem) != S_OK)
949*f6dc9357SAndroid Build Coastguard Worker         return E_NOTIMPL;
950*f6dc9357SAndroid Build Coastguard Worker       complexity += inputItem.GetLocalFullSize();
951*f6dc9357SAndroid Build Coastguard Worker       // complexity += inputItem.GetCentralExtraPlusCommentSize();
952*f6dc9357SAndroid Build Coastguard Worker     }
953*f6dc9357SAndroid Build Coastguard Worker     complexity += kLocalHeaderSize;
954*f6dc9357SAndroid Build Coastguard Worker     complexity += kCentralHeaderSize;
955*f6dc9357SAndroid Build Coastguard Worker   }
956*f6dc9357SAndroid Build Coastguard Worker 
957*f6dc9357SAndroid Build Coastguard Worker   if (comment)
958*f6dc9357SAndroid Build Coastguard Worker     complexity += comment->Size();
959*f6dc9357SAndroid Build Coastguard Worker   complexity++; // end of central
960*f6dc9357SAndroid Build Coastguard Worker 
961*f6dc9357SAndroid Build Coastguard Worker   if (!unknownComplexity)
962*f6dc9357SAndroid Build Coastguard Worker     updateCallback->SetTotal(complexity);
963*f6dc9357SAndroid Build Coastguard Worker 
964*f6dc9357SAndroid Build Coastguard Worker   UInt64 totalComplexity = complexity;
965*f6dc9357SAndroid Build Coastguard Worker 
966*f6dc9357SAndroid Build Coastguard Worker   CCompressionMethodMode options2 = options;
967*f6dc9357SAndroid Build Coastguard Worker 
968*f6dc9357SAndroid Build Coastguard Worker   if (options2._methods.IsEmpty())
969*f6dc9357SAndroid Build Coastguard Worker   {
970*f6dc9357SAndroid Build Coastguard Worker     // we need method item, if default method was used
971*f6dc9357SAndroid Build Coastguard Worker     options2._methods.AddNew();
972*f6dc9357SAndroid Build Coastguard Worker   }
973*f6dc9357SAndroid Build Coastguard Worker 
974*f6dc9357SAndroid Build Coastguard Worker   CAddCommon compressor;
975*f6dc9357SAndroid Build Coastguard Worker   compressor.SetOptions(options2);
976*f6dc9357SAndroid Build Coastguard Worker 
977*f6dc9357SAndroid Build Coastguard Worker   complexity = 0;
978*f6dc9357SAndroid Build Coastguard Worker 
979*f6dc9357SAndroid Build Coastguard Worker   const Byte method = options.MethodSequence.FrontItem();
980*f6dc9357SAndroid Build Coastguard Worker 
981*f6dc9357SAndroid Build Coastguard Worker   COneMethodInfo *oneMethodMain = NULL;
982*f6dc9357SAndroid Build Coastguard Worker   if (!options2._methods.IsEmpty())
983*f6dc9357SAndroid Build Coastguard Worker     oneMethodMain = &options2._methods[0];
984*f6dc9357SAndroid Build Coastguard Worker 
985*f6dc9357SAndroid Build Coastguard Worker   {
986*f6dc9357SAndroid Build Coastguard Worker     FOR_VECTOR (mi, options2._methods)
987*f6dc9357SAndroid Build Coastguard Worker     {
988*f6dc9357SAndroid Build Coastguard Worker       options2.SetGlobalLevelTo(options2._methods[mi]);
989*f6dc9357SAndroid Build Coastguard Worker     }
990*f6dc9357SAndroid Build Coastguard Worker   }
991*f6dc9357SAndroid Build Coastguard Worker 
992*f6dc9357SAndroid Build Coastguard Worker   if (oneMethodMain)
993*f6dc9357SAndroid Build Coastguard Worker   {
994*f6dc9357SAndroid Build Coastguard Worker     // appnote recommends to use EOS marker for LZMA.
995*f6dc9357SAndroid Build Coastguard Worker     if (method == NFileHeader::NCompressionMethod::kLZMA)
996*f6dc9357SAndroid Build Coastguard Worker       oneMethodMain->AddProp_EndMarker_if_NotFound(true);
997*f6dc9357SAndroid Build Coastguard Worker   }
998*f6dc9357SAndroid Build Coastguard Worker 
999*f6dc9357SAndroid Build Coastguard Worker 
1000*f6dc9357SAndroid Build Coastguard Worker   #ifndef Z7_ST
1001*f6dc9357SAndroid Build Coastguard Worker 
1002*f6dc9357SAndroid Build Coastguard Worker   UInt32 numThreads = options._numThreads;
1003*f6dc9357SAndroid Build Coastguard Worker 
1004*f6dc9357SAndroid Build Coastguard Worker   UInt32 numZipThreads_limit = numThreads;
1005*f6dc9357SAndroid Build Coastguard Worker   if (numZipThreads_limit > numFilesToCompress)
1006*f6dc9357SAndroid Build Coastguard Worker     numZipThreads_limit = (UInt32)numFilesToCompress;
1007*f6dc9357SAndroid Build Coastguard Worker 
1008*f6dc9357SAndroid Build Coastguard Worker   if (numZipThreads_limit > 1)
1009*f6dc9357SAndroid Build Coastguard Worker   {
1010*f6dc9357SAndroid Build Coastguard Worker     const unsigned numFiles_OPEN_MAX = NSystem::Get_File_OPEN_MAX_Reduced_for_3_tasks();
1011*f6dc9357SAndroid Build Coastguard Worker     // printf("\nzip:numFiles_OPEN_MAX =%d\n", (unsigned)numFiles_OPEN_MAX);
1012*f6dc9357SAndroid Build Coastguard Worker     if (numZipThreads_limit > numFiles_OPEN_MAX)
1013*f6dc9357SAndroid Build Coastguard Worker       numZipThreads_limit = (UInt32)numFiles_OPEN_MAX;
1014*f6dc9357SAndroid Build Coastguard Worker   }
1015*f6dc9357SAndroid Build Coastguard Worker 
1016*f6dc9357SAndroid Build Coastguard Worker   {
1017*f6dc9357SAndroid Build Coastguard Worker     const UInt32 kNumMaxThreads =
1018*f6dc9357SAndroid Build Coastguard Worker       #ifdef _WIN32
1019*f6dc9357SAndroid Build Coastguard Worker         64; // _WIN32 supports only 64 threads in one group. So no need for more threads here
1020*f6dc9357SAndroid Build Coastguard Worker       #else
1021*f6dc9357SAndroid Build Coastguard Worker         128;
1022*f6dc9357SAndroid Build Coastguard Worker       #endif
1023*f6dc9357SAndroid Build Coastguard Worker     if (numThreads > kNumMaxThreads)
1024*f6dc9357SAndroid Build Coastguard Worker       numThreads = kNumMaxThreads;
1025*f6dc9357SAndroid Build Coastguard Worker   }
1026*f6dc9357SAndroid Build Coastguard Worker   /*
1027*f6dc9357SAndroid Build Coastguard Worker   if (numThreads > MAXIMUM_WAIT_OBJECTS) // is 64 in Windows
1028*f6dc9357SAndroid Build Coastguard Worker     numThreads = MAXIMUM_WAIT_OBJECTS;
1029*f6dc9357SAndroid Build Coastguard Worker   */
1030*f6dc9357SAndroid Build Coastguard Worker 
1031*f6dc9357SAndroid Build Coastguard Worker 
1032*f6dc9357SAndroid Build Coastguard Worker   /*
1033*f6dc9357SAndroid Build Coastguard Worker   // zstd supports (numThreads == 0);
1034*f6dc9357SAndroid Build Coastguard Worker   if (numThreads < 1)
1035*f6dc9357SAndroid Build Coastguard Worker     numThreads = 1;
1036*f6dc9357SAndroid Build Coastguard Worker   */
1037*f6dc9357SAndroid Build Coastguard Worker 
1038*f6dc9357SAndroid Build Coastguard Worker   bool mtMode = (numThreads > 1);
1039*f6dc9357SAndroid Build Coastguard Worker 
1040*f6dc9357SAndroid Build Coastguard Worker   if (numFilesToCompress <= 1)
1041*f6dc9357SAndroid Build Coastguard Worker     mtMode = false;
1042*f6dc9357SAndroid Build Coastguard Worker 
1043*f6dc9357SAndroid Build Coastguard Worker   // mtMode = true; // debug: to test mtMode
1044*f6dc9357SAndroid Build Coastguard Worker 
1045*f6dc9357SAndroid Build Coastguard Worker   if (!mtMode)
1046*f6dc9357SAndroid Build Coastguard Worker   {
1047*f6dc9357SAndroid Build Coastguard Worker     // if (oneMethodMain) {
1048*f6dc9357SAndroid Build Coastguard Worker     /*
1049*f6dc9357SAndroid Build Coastguard Worker     if (method == NFileHeader::NCompressionMethod::kZstdWz)
1050*f6dc9357SAndroid Build Coastguard Worker     {
1051*f6dc9357SAndroid Build Coastguard Worker       if (oneMethodMain->FindProp(NCoderPropID::kNumThreads) < 0)
1052*f6dc9357SAndroid Build Coastguard Worker       {
1053*f6dc9357SAndroid Build Coastguard Worker         // numZstdThreads was not forced in oneMethodMain
1054*f6dc9357SAndroid Build Coastguard Worker         if (numThreads >= 1
1055*f6dc9357SAndroid Build Coastguard Worker             && options._memUsage_WasSet
1056*f6dc9357SAndroid Build Coastguard Worker             && !options._numThreads_WasForced)
1057*f6dc9357SAndroid Build Coastguard Worker         {
1058*f6dc9357SAndroid Build Coastguard Worker           NCompress::NZstd::CEncoderProps encoderProps;
1059*f6dc9357SAndroid Build Coastguard Worker           RINOK(encoderProps.SetFromMethodProps(*oneMethodMain))
1060*f6dc9357SAndroid Build Coastguard Worker           CZstdEncProps &zstdProps = encoderProps.EncProps;
1061*f6dc9357SAndroid Build Coastguard Worker           ZstdEncProps_NormalizeFull(&zstdProps);
1062*f6dc9357SAndroid Build Coastguard Worker           numThreads = ZstdEncProps_GetNumThreads_for_MemUsageLimit(
1063*f6dc9357SAndroid Build Coastguard Worker               &zstdProps, options._memUsage_Compress, numThreads);
1064*f6dc9357SAndroid Build Coastguard Worker           // we allow (nbWorkers = 1) here.
1065*f6dc9357SAndroid Build Coastguard Worker         }
1066*f6dc9357SAndroid Build Coastguard Worker         oneMethodMain->AddProp_NumThreads(numThreads);
1067*f6dc9357SAndroid Build Coastguard Worker       }
1068*f6dc9357SAndroid Build Coastguard Worker     } // kZstdWz
1069*f6dc9357SAndroid Build Coastguard Worker     */
1070*f6dc9357SAndroid Build Coastguard Worker     // } // oneMethodMain
1071*f6dc9357SAndroid Build Coastguard Worker 
1072*f6dc9357SAndroid Build Coastguard Worker     FOR_VECTOR (mi, options2._methods)
1073*f6dc9357SAndroid Build Coastguard Worker     {
1074*f6dc9357SAndroid Build Coastguard Worker       COneMethodInfo &onem = options2._methods[mi];
1075*f6dc9357SAndroid Build Coastguard Worker 
1076*f6dc9357SAndroid Build Coastguard Worker       if (onem.FindProp(NCoderPropID::kNumThreads) < 0)
1077*f6dc9357SAndroid Build Coastguard Worker       {
1078*f6dc9357SAndroid Build Coastguard Worker         // fixme: we should check the number of threads for xz method also
1079*f6dc9357SAndroid Build Coastguard Worker         // fixed for 9.31. bzip2 default is just one thread.
1080*f6dc9357SAndroid Build Coastguard Worker         onem.AddProp_NumThreads(numThreads);
1081*f6dc9357SAndroid Build Coastguard Worker       }
1082*f6dc9357SAndroid Build Coastguard Worker     }
1083*f6dc9357SAndroid Build Coastguard Worker   }
1084*f6dc9357SAndroid Build Coastguard Worker   else // mtMode
1085*f6dc9357SAndroid Build Coastguard Worker   {
1086*f6dc9357SAndroid Build Coastguard Worker     if (method == NFileHeader::NCompressionMethod::kStore && !options.Password_Defined)
1087*f6dc9357SAndroid Build Coastguard Worker       numThreads = 1;
1088*f6dc9357SAndroid Build Coastguard Worker 
1089*f6dc9357SAndroid Build Coastguard Worker    if (oneMethodMain)
1090*f6dc9357SAndroid Build Coastguard Worker    {
1091*f6dc9357SAndroid Build Coastguard Worker 
1092*f6dc9357SAndroid Build Coastguard Worker     if (method == NFileHeader::NCompressionMethod::kBZip2)
1093*f6dc9357SAndroid Build Coastguard Worker     {
1094*f6dc9357SAndroid Build Coastguard Worker       bool fixedNumber;
1095*f6dc9357SAndroid Build Coastguard Worker       UInt32 numBZip2Threads = oneMethodMain->Get_BZip2_NumThreads(fixedNumber);
1096*f6dc9357SAndroid Build Coastguard Worker       if (!fixedNumber)
1097*f6dc9357SAndroid Build Coastguard Worker       {
1098*f6dc9357SAndroid Build Coastguard Worker         const UInt64 averageSize = numBytesToCompress / numFilesToCompress;
1099*f6dc9357SAndroid Build Coastguard Worker         const UInt32 blockSize = oneMethodMain->Get_BZip2_BlockSize();
1100*f6dc9357SAndroid Build Coastguard Worker         const UInt64 averageNumberOfBlocks = averageSize / blockSize + 1;
1101*f6dc9357SAndroid Build Coastguard Worker         numBZip2Threads = 64;
1102*f6dc9357SAndroid Build Coastguard Worker         if (numBZip2Threads > averageNumberOfBlocks)
1103*f6dc9357SAndroid Build Coastguard Worker           numBZip2Threads = (UInt32)averageNumberOfBlocks;
1104*f6dc9357SAndroid Build Coastguard Worker         if (numBZip2Threads > numThreads)
1105*f6dc9357SAndroid Build Coastguard Worker           numBZip2Threads = numThreads;
1106*f6dc9357SAndroid Build Coastguard Worker         oneMethodMain->AddProp_NumThreads(numBZip2Threads);
1107*f6dc9357SAndroid Build Coastguard Worker       }
1108*f6dc9357SAndroid Build Coastguard Worker       numThreads /= numBZip2Threads;
1109*f6dc9357SAndroid Build Coastguard Worker     }
1110*f6dc9357SAndroid Build Coastguard Worker     else if (method == NFileHeader::NCompressionMethod::kXz)
1111*f6dc9357SAndroid Build Coastguard Worker     {
1112*f6dc9357SAndroid Build Coastguard Worker       UInt32 numLzmaThreads = 1;
1113*f6dc9357SAndroid Build Coastguard Worker       int numXzThreads = oneMethodMain->Get_Xz_NumThreads(numLzmaThreads);
1114*f6dc9357SAndroid Build Coastguard Worker       if (numXzThreads < 0)
1115*f6dc9357SAndroid Build Coastguard Worker       {
1116*f6dc9357SAndroid Build Coastguard Worker         // numXzThreads is unknown
1117*f6dc9357SAndroid Build Coastguard Worker         const UInt64 averageSize = numBytesToCompress / numFilesToCompress;
1118*f6dc9357SAndroid Build Coastguard Worker         const UInt64 blockSize = oneMethodMain->Get_Xz_BlockSize();
1119*f6dc9357SAndroid Build Coastguard Worker         UInt64 averageNumberOfBlocks = 1;
1120*f6dc9357SAndroid Build Coastguard Worker         if (blockSize != (UInt64)(Int64)-1)
1121*f6dc9357SAndroid Build Coastguard Worker           averageNumberOfBlocks = averageSize / blockSize + 1;
1122*f6dc9357SAndroid Build Coastguard Worker         UInt32 t = 256;
1123*f6dc9357SAndroid Build Coastguard Worker         if (t > averageNumberOfBlocks)
1124*f6dc9357SAndroid Build Coastguard Worker           t = (UInt32)averageNumberOfBlocks;
1125*f6dc9357SAndroid Build Coastguard Worker         t *= numLzmaThreads;
1126*f6dc9357SAndroid Build Coastguard Worker         if (t > numThreads)
1127*f6dc9357SAndroid Build Coastguard Worker           t = numThreads;
1128*f6dc9357SAndroid Build Coastguard Worker         oneMethodMain->AddProp_NumThreads(t);
1129*f6dc9357SAndroid Build Coastguard Worker         numXzThreads = (int)t;
1130*f6dc9357SAndroid Build Coastguard Worker       }
1131*f6dc9357SAndroid Build Coastguard Worker       numThreads /= (unsigned)numXzThreads;
1132*f6dc9357SAndroid Build Coastguard Worker     }
1133*f6dc9357SAndroid Build Coastguard Worker     /*
1134*f6dc9357SAndroid Build Coastguard Worker     else if (method == NFileHeader::NCompressionMethod::kZstdWz)
1135*f6dc9357SAndroid Build Coastguard Worker     {
1136*f6dc9357SAndroid Build Coastguard Worker       numThreads = SetZstdThreads(options,
1137*f6dc9357SAndroid Build Coastguard Worker           oneMethodMain, numThreads,
1138*f6dc9357SAndroid Build Coastguard Worker           numZipThreads_limit,
1139*f6dc9357SAndroid Build Coastguard Worker           numFilesToCompress, numBytesToCompress);
1140*f6dc9357SAndroid Build Coastguard Worker     }
1141*f6dc9357SAndroid Build Coastguard Worker     */
1142*f6dc9357SAndroid Build Coastguard Worker     else if (
1143*f6dc9357SAndroid Build Coastguard Worker            method == NFileHeader::NCompressionMethod::kDeflate
1144*f6dc9357SAndroid Build Coastguard Worker         || method == NFileHeader::NCompressionMethod::kDeflate64
1145*f6dc9357SAndroid Build Coastguard Worker         || method == NFileHeader::NCompressionMethod::kPPMd)
1146*f6dc9357SAndroid Build Coastguard Worker     {
1147*f6dc9357SAndroid Build Coastguard Worker       if (numThreads > 1
1148*f6dc9357SAndroid Build Coastguard Worker           && options._memUsage_WasSet
1149*f6dc9357SAndroid Build Coastguard Worker           && !options._numThreads_WasForced)
1150*f6dc9357SAndroid Build Coastguard Worker       {
1151*f6dc9357SAndroid Build Coastguard Worker         UInt64 methodMemUsage;
1152*f6dc9357SAndroid Build Coastguard Worker         if (method == NFileHeader::NCompressionMethod::kPPMd)
1153*f6dc9357SAndroid Build Coastguard Worker           methodMemUsage = oneMethodMain->Get_Ppmd_MemSize();
1154*f6dc9357SAndroid Build Coastguard Worker         else
1155*f6dc9357SAndroid Build Coastguard Worker           methodMemUsage = (4 << 20); // for deflate
1156*f6dc9357SAndroid Build Coastguard Worker         const UInt64 threadMemUsage = kMemPerThread + methodMemUsage;
1157*f6dc9357SAndroid Build Coastguard Worker         const UInt64 numThreads64 = options._memUsage_Compress / threadMemUsage;
1158*f6dc9357SAndroid Build Coastguard Worker         if (numThreads64 < numThreads)
1159*f6dc9357SAndroid Build Coastguard Worker           numThreads = (UInt32)numThreads64;
1160*f6dc9357SAndroid Build Coastguard Worker       }
1161*f6dc9357SAndroid Build Coastguard Worker     }
1162*f6dc9357SAndroid Build Coastguard Worker     else if (method == NFileHeader::NCompressionMethod::kLZMA)
1163*f6dc9357SAndroid Build Coastguard Worker     {
1164*f6dc9357SAndroid Build Coastguard Worker       // we suppose that default LZMA is 2 thread. So we don't change it
1165*f6dc9357SAndroid Build Coastguard Worker       const UInt32 numLZMAThreads = oneMethodMain->Get_Lzma_NumThreads();
1166*f6dc9357SAndroid Build Coastguard Worker       numThreads /= numLZMAThreads;
1167*f6dc9357SAndroid Build Coastguard Worker 
1168*f6dc9357SAndroid Build Coastguard Worker       if (numThreads > 1
1169*f6dc9357SAndroid Build Coastguard Worker           && options._memUsage_WasSet
1170*f6dc9357SAndroid Build Coastguard Worker           && !options._numThreads_WasForced)
1171*f6dc9357SAndroid Build Coastguard Worker       {
1172*f6dc9357SAndroid Build Coastguard Worker         const UInt64 methodMemUsage = oneMethodMain->Get_Lzma_MemUsage(true);
1173*f6dc9357SAndroid Build Coastguard Worker         const UInt64 threadMemUsage = kMemPerThread + methodMemUsage;
1174*f6dc9357SAndroid Build Coastguard Worker         const UInt64 numThreads64 = options._memUsage_Compress / threadMemUsage;
1175*f6dc9357SAndroid Build Coastguard Worker         if (numThreads64 < numThreads)
1176*f6dc9357SAndroid Build Coastguard Worker           numThreads = (UInt32)numThreads64;
1177*f6dc9357SAndroid Build Coastguard Worker       }
1178*f6dc9357SAndroid Build Coastguard Worker     }
1179*f6dc9357SAndroid Build Coastguard Worker    } // (oneMethodMain)
1180*f6dc9357SAndroid Build Coastguard Worker 
1181*f6dc9357SAndroid Build Coastguard Worker     if (numThreads > numZipThreads_limit)
1182*f6dc9357SAndroid Build Coastguard Worker       numThreads = numZipThreads_limit;
1183*f6dc9357SAndroid Build Coastguard Worker     if (numThreads <= 1)
1184*f6dc9357SAndroid Build Coastguard Worker     {
1185*f6dc9357SAndroid Build Coastguard Worker       mtMode = false;
1186*f6dc9357SAndroid Build Coastguard Worker       numThreads = 1;
1187*f6dc9357SAndroid Build Coastguard Worker     }
1188*f6dc9357SAndroid Build Coastguard Worker   }
1189*f6dc9357SAndroid Build Coastguard Worker 
1190*f6dc9357SAndroid Build Coastguard Worker   // mtMode = true; // to test mtMode for seqMode
1191*f6dc9357SAndroid Build Coastguard Worker 
1192*f6dc9357SAndroid Build Coastguard Worker   if (!mtMode)
1193*f6dc9357SAndroid Build Coastguard Worker   #endif
1194*f6dc9357SAndroid Build Coastguard Worker     return Update2St(
1195*f6dc9357SAndroid Build Coastguard Worker         EXTERNAL_CODECS_LOC_VARS
1196*f6dc9357SAndroid Build Coastguard Worker         archive, inArchive,
1197*f6dc9357SAndroid Build Coastguard Worker         inputItems, updateItems,
1198*f6dc9357SAndroid Build Coastguard Worker         updateOptions,
1199*f6dc9357SAndroid Build Coastguard Worker         &options2, outSeqMode,
1200*f6dc9357SAndroid Build Coastguard Worker         comment, updateCallback, totalComplexity,
1201*f6dc9357SAndroid Build Coastguard Worker         opCallback
1202*f6dc9357SAndroid Build Coastguard Worker         // , reportArcProp
1203*f6dc9357SAndroid Build Coastguard Worker         );
1204*f6dc9357SAndroid Build Coastguard Worker 
1205*f6dc9357SAndroid Build Coastguard Worker 
1206*f6dc9357SAndroid Build Coastguard Worker   #ifndef Z7_ST
1207*f6dc9357SAndroid Build Coastguard Worker 
1208*f6dc9357SAndroid Build Coastguard Worker   /*
1209*f6dc9357SAndroid Build Coastguard Worker   CTotalStats stat;
1210*f6dc9357SAndroid Build Coastguard Worker   stat.Size = 0;
1211*f6dc9357SAndroid Build Coastguard Worker   stat.PackSize = 0;
1212*f6dc9357SAndroid Build Coastguard Worker   */
1213*f6dc9357SAndroid Build Coastguard Worker   if (numThreads < 1)
1214*f6dc9357SAndroid Build Coastguard Worker     numThreads = 1;
1215*f6dc9357SAndroid Build Coastguard Worker 
1216*f6dc9357SAndroid Build Coastguard Worker   CObjectVector<CItemOut> items;
1217*f6dc9357SAndroid Build Coastguard Worker 
1218*f6dc9357SAndroid Build Coastguard Worker   CMtProgressMixer *mtProgressMixerSpec = new CMtProgressMixer;
1219*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<ICompressProgressInfo> progress = mtProgressMixerSpec;
1220*f6dc9357SAndroid Build Coastguard Worker   mtProgressMixerSpec->Create(updateCallback, true);
1221*f6dc9357SAndroid Build Coastguard Worker 
1222*f6dc9357SAndroid Build Coastguard Worker   CMtCompressProgressMixer mtCompressProgressMixer;
1223*f6dc9357SAndroid Build Coastguard Worker   mtCompressProgressMixer.Init(numThreads, mtProgressMixerSpec->RatioProgress);
1224*f6dc9357SAndroid Build Coastguard Worker 
1225*f6dc9357SAndroid Build Coastguard Worker   CMemBlockManagerMt memManager(kBlockSize);
1226*f6dc9357SAndroid Build Coastguard Worker   CMemRefs refs(&memManager);
1227*f6dc9357SAndroid Build Coastguard Worker 
1228*f6dc9357SAndroid Build Coastguard Worker   CMtSem mtSem;
1229*f6dc9357SAndroid Build Coastguard Worker   CThreads threads;
1230*f6dc9357SAndroid Build Coastguard Worker   mtSem.Head = -1;
1231*f6dc9357SAndroid Build Coastguard Worker   mtSem.Indexes.ClearAndSetSize(numThreads);
1232*f6dc9357SAndroid Build Coastguard Worker   {
1233*f6dc9357SAndroid Build Coastguard Worker     WRes wres = mtSem.Semaphore.Create(0, numThreads);
1234*f6dc9357SAndroid Build Coastguard Worker     if (wres != 0)
1235*f6dc9357SAndroid Build Coastguard Worker       return HRESULT_FROM_WIN32(wres);
1236*f6dc9357SAndroid Build Coastguard Worker   }
1237*f6dc9357SAndroid Build Coastguard Worker 
1238*f6dc9357SAndroid Build Coastguard Worker   CUIntVector threadIndices;  // list threads in order of updateItems
1239*f6dc9357SAndroid Build Coastguard Worker 
1240*f6dc9357SAndroid Build Coastguard Worker   {
1241*f6dc9357SAndroid Build Coastguard Worker     RINOK(memManager.AllocateSpaceAlways((size_t)numThreads * (kMemPerThread / kBlockSize)))
1242*f6dc9357SAndroid Build Coastguard Worker     for (i = 0; i < updateItems.Size(); i++)
1243*f6dc9357SAndroid Build Coastguard Worker       refs.Refs.Add(CMemBlocks2());
1244*f6dc9357SAndroid Build Coastguard Worker 
1245*f6dc9357SAndroid Build Coastguard Worker     for (i = 0; i < numThreads; i++)
1246*f6dc9357SAndroid Build Coastguard Worker     {
1247*f6dc9357SAndroid Build Coastguard Worker       threads.Threads.AddNew();
1248*f6dc9357SAndroid Build Coastguard Worker       // mtSem.Indexes[i] = -1; // actually we don't use these values
1249*f6dc9357SAndroid Build Coastguard Worker     }
1250*f6dc9357SAndroid Build Coastguard Worker 
1251*f6dc9357SAndroid Build Coastguard Worker     for (i = 0; i < numThreads; i++)
1252*f6dc9357SAndroid Build Coastguard Worker     {
1253*f6dc9357SAndroid Build Coastguard Worker       CThreadInfo &threadInfo = threads.Threads[i];
1254*f6dc9357SAndroid Build Coastguard Worker       threadInfo.ThreadIndex = i;
1255*f6dc9357SAndroid Build Coastguard Worker       threadInfo.SetOptions(options2);
1256*f6dc9357SAndroid Build Coastguard Worker       #ifdef Z7_EXTERNAL_CODECS
1257*f6dc9357SAndroid Build Coastguard Worker       threadInfo._externalCodecs = _externalCodecs;
1258*f6dc9357SAndroid Build Coastguard Worker       #endif
1259*f6dc9357SAndroid Build Coastguard Worker       RINOK(threadInfo.CreateEvents())
1260*f6dc9357SAndroid Build Coastguard Worker       threadInfo.OutStreamSpec = new COutMemStream(&memManager);
1261*f6dc9357SAndroid Build Coastguard Worker       RINOK(threadInfo.OutStreamSpec->CreateEvents(SYNC_WFMO(&memManager.Synchro)))
1262*f6dc9357SAndroid Build Coastguard Worker       threadInfo.OutStream = threadInfo.OutStreamSpec;
1263*f6dc9357SAndroid Build Coastguard Worker       threadInfo.ProgressSpec = new CMtCompressProgress();
1264*f6dc9357SAndroid Build Coastguard Worker       threadInfo.Progress = threadInfo.ProgressSpec;
1265*f6dc9357SAndroid Build Coastguard Worker       threadInfo.ProgressSpec->Init(&mtCompressProgressMixer, i);
1266*f6dc9357SAndroid Build Coastguard Worker       threadInfo.MtSem = &mtSem;
1267*f6dc9357SAndroid Build Coastguard Worker       RINOK(threadInfo.CreateThread())
1268*f6dc9357SAndroid Build Coastguard Worker     }
1269*f6dc9357SAndroid Build Coastguard Worker   }
1270*f6dc9357SAndroid Build Coastguard Worker 
1271*f6dc9357SAndroid Build Coastguard Worker   unsigned mtItemIndex = 0;
1272*f6dc9357SAndroid Build Coastguard Worker   unsigned itemIndex = 0;
1273*f6dc9357SAndroid Build Coastguard Worker   int lastRealStreamItemIndex = -1;
1274*f6dc9357SAndroid Build Coastguard Worker 
1275*f6dc9357SAndroid Build Coastguard Worker 
1276*f6dc9357SAndroid Build Coastguard Worker   while (itemIndex < updateItems.Size())
1277*f6dc9357SAndroid Build Coastguard Worker   {
1278*f6dc9357SAndroid Build Coastguard Worker     if (threadIndices.Size() < numThreads && mtItemIndex < updateItems.Size())
1279*f6dc9357SAndroid Build Coastguard Worker     {
1280*f6dc9357SAndroid Build Coastguard Worker       // we start ahead the threads for compressing
1281*f6dc9357SAndroid Build Coastguard Worker       // also we set refs.Refs[itemIndex].SeqMode that is used later
1282*f6dc9357SAndroid Build Coastguard Worker       // don't move that code block
1283*f6dc9357SAndroid Build Coastguard Worker 
1284*f6dc9357SAndroid Build Coastguard Worker       CUpdateItem &ui = updateItems[mtItemIndex++];
1285*f6dc9357SAndroid Build Coastguard Worker       if (!ui.NewData)
1286*f6dc9357SAndroid Build Coastguard Worker         continue;
1287*f6dc9357SAndroid Build Coastguard Worker       CItemEx itemEx;
1288*f6dc9357SAndroid Build Coastguard Worker       CItemOut item;
1289*f6dc9357SAndroid Build Coastguard Worker 
1290*f6dc9357SAndroid Build Coastguard Worker       if (ui.NewProps)
1291*f6dc9357SAndroid Build Coastguard Worker       {
1292*f6dc9357SAndroid Build Coastguard Worker         if (ui.IsDir)
1293*f6dc9357SAndroid Build Coastguard Worker           continue;
1294*f6dc9357SAndroid Build Coastguard Worker       }
1295*f6dc9357SAndroid Build Coastguard Worker       else
1296*f6dc9357SAndroid Build Coastguard Worker       {
1297*f6dc9357SAndroid Build Coastguard Worker         itemEx = inputItems[(unsigned)ui.IndexInArc];
1298*f6dc9357SAndroid Build Coastguard Worker         if (inArchive->Read_LocalItem_After_CdItem_Full(itemEx) != S_OK)
1299*f6dc9357SAndroid Build Coastguard Worker           return E_NOTIMPL;
1300*f6dc9357SAndroid Build Coastguard Worker         (CItem &)item = itemEx;
1301*f6dc9357SAndroid Build Coastguard Worker         if (item.IsDir() != ui.IsDir)
1302*f6dc9357SAndroid Build Coastguard Worker           return E_NOTIMPL;
1303*f6dc9357SAndroid Build Coastguard Worker         if (ui.IsDir)
1304*f6dc9357SAndroid Build Coastguard Worker           continue;
1305*f6dc9357SAndroid Build Coastguard Worker       }
1306*f6dc9357SAndroid Build Coastguard Worker 
1307*f6dc9357SAndroid Build Coastguard Worker       CMyComPtr<ISequentialInStream> fileInStream;
1308*f6dc9357SAndroid Build Coastguard Worker 
1309*f6dc9357SAndroid Build Coastguard Worker       CMemBlocks2 &memRef2 = refs.Refs[mtItemIndex - 1];
1310*f6dc9357SAndroid Build Coastguard Worker 
1311*f6dc9357SAndroid Build Coastguard Worker       {
1312*f6dc9357SAndroid Build Coastguard Worker         NWindows::NSynchronization::CCriticalSectionLock lock(mtProgressMixerSpec->Mixer2->CriticalSection);
1313*f6dc9357SAndroid Build Coastguard Worker         const HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream);
1314*f6dc9357SAndroid Build Coastguard Worker         if (res == S_FALSE)
1315*f6dc9357SAndroid Build Coastguard Worker         {
1316*f6dc9357SAndroid Build Coastguard Worker           complexity += ui.Size;
1317*f6dc9357SAndroid Build Coastguard Worker           complexity += kLocalHeaderSize;
1318*f6dc9357SAndroid Build Coastguard Worker           mtProgressMixerSpec->Mixer2->SetProgressOffset_NoLock(complexity);
1319*f6dc9357SAndroid Build Coastguard Worker           RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK))
1320*f6dc9357SAndroid Build Coastguard Worker           memRef2.Skip = true;
1321*f6dc9357SAndroid Build Coastguard Worker           continue;
1322*f6dc9357SAndroid Build Coastguard Worker         }
1323*f6dc9357SAndroid Build Coastguard Worker         RINOK(res)
1324*f6dc9357SAndroid Build Coastguard Worker         if (!fileInStream)
1325*f6dc9357SAndroid Build Coastguard Worker           return E_INVALIDARG;
1326*f6dc9357SAndroid Build Coastguard Worker         UpdatePropsFromStream(updateOptions, ui, fileInStream, updateCallback, totalComplexity);
1327*f6dc9357SAndroid Build Coastguard Worker         RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK))
1328*f6dc9357SAndroid Build Coastguard Worker       }
1329*f6dc9357SAndroid Build Coastguard Worker 
1330*f6dc9357SAndroid Build Coastguard Worker       UInt32 k;
1331*f6dc9357SAndroid Build Coastguard Worker       for (k = 0; k < numThreads; k++)
1332*f6dc9357SAndroid Build Coastguard Worker         if (threads.Threads[k].IsFree)
1333*f6dc9357SAndroid Build Coastguard Worker           break;
1334*f6dc9357SAndroid Build Coastguard Worker 
1335*f6dc9357SAndroid Build Coastguard Worker       if (k == numThreads)
1336*f6dc9357SAndroid Build Coastguard Worker         return E_FAIL;
1337*f6dc9357SAndroid Build Coastguard Worker       {
1338*f6dc9357SAndroid Build Coastguard Worker         {
1339*f6dc9357SAndroid Build Coastguard Worker           CThreadInfo &threadInfo = threads.Threads[k];
1340*f6dc9357SAndroid Build Coastguard Worker           threadInfo.IsFree = false;
1341*f6dc9357SAndroid Build Coastguard Worker           threadInfo.InStream = fileInStream;
1342*f6dc9357SAndroid Build Coastguard Worker 
1343*f6dc9357SAndroid Build Coastguard Worker           bool inSeqMode = false;
1344*f6dc9357SAndroid Build Coastguard Worker 
1345*f6dc9357SAndroid Build Coastguard Worker           if (!inSeqMode)
1346*f6dc9357SAndroid Build Coastguard Worker           {
1347*f6dc9357SAndroid Build Coastguard Worker             CMyComPtr<IInStream> inStream2;
1348*f6dc9357SAndroid Build Coastguard Worker             fileInStream->QueryInterface(IID_IInStream, (void **)&inStream2);
1349*f6dc9357SAndroid Build Coastguard Worker             inSeqMode = (inStream2 == NULL);
1350*f6dc9357SAndroid Build Coastguard Worker           }
1351*f6dc9357SAndroid Build Coastguard Worker           memRef2.InSeqMode = inSeqMode;
1352*f6dc9357SAndroid Build Coastguard Worker 
1353*f6dc9357SAndroid Build Coastguard Worker           // !!!!! we must release ref before sending event
1354*f6dc9357SAndroid Build Coastguard Worker           // BUG was here in v4.43 and v4.44. It could change ref counter in two threads in same time
1355*f6dc9357SAndroid Build Coastguard Worker           fileInStream.Release();
1356*f6dc9357SAndroid Build Coastguard Worker 
1357*f6dc9357SAndroid Build Coastguard Worker           threadInfo.OutStreamSpec->Init();
1358*f6dc9357SAndroid Build Coastguard Worker           threadInfo.ProgressSpec->Reinit();
1359*f6dc9357SAndroid Build Coastguard Worker 
1360*f6dc9357SAndroid Build Coastguard Worker           threadInfo.UpdateIndex = mtItemIndex - 1;
1361*f6dc9357SAndroid Build Coastguard Worker           threadInfo.InSeqMode = inSeqMode;
1362*f6dc9357SAndroid Build Coastguard Worker           threadInfo.OutSeqMode = outSeqMode;
1363*f6dc9357SAndroid Build Coastguard Worker           threadInfo.FileTime = ui.Time; // FileTime is used for ZipCrypto only in seqMode
1364*f6dc9357SAndroid Build Coastguard Worker           threadInfo.ExpectedDataSize = ui.Size;
1365*f6dc9357SAndroid Build Coastguard Worker           threadInfo.ExpectedDataSize_IsConfirmed = ui.Size_WasSetFromStream;
1366*f6dc9357SAndroid Build Coastguard Worker 
1367*f6dc9357SAndroid Build Coastguard Worker           threadInfo.CompressEvent.Set();
1368*f6dc9357SAndroid Build Coastguard Worker 
1369*f6dc9357SAndroid Build Coastguard Worker           threadIndices.Add(k);
1370*f6dc9357SAndroid Build Coastguard Worker         }
1371*f6dc9357SAndroid Build Coastguard Worker       }
1372*f6dc9357SAndroid Build Coastguard Worker 
1373*f6dc9357SAndroid Build Coastguard Worker       continue;
1374*f6dc9357SAndroid Build Coastguard Worker     }
1375*f6dc9357SAndroid Build Coastguard Worker 
1376*f6dc9357SAndroid Build Coastguard Worker     if (refs.Refs[itemIndex].Skip)
1377*f6dc9357SAndroid Build Coastguard Worker     {
1378*f6dc9357SAndroid Build Coastguard Worker       itemIndex++;
1379*f6dc9357SAndroid Build Coastguard Worker       continue;
1380*f6dc9357SAndroid Build Coastguard Worker     }
1381*f6dc9357SAndroid Build Coastguard Worker 
1382*f6dc9357SAndroid Build Coastguard Worker     const CUpdateItem &ui = updateItems[itemIndex];
1383*f6dc9357SAndroid Build Coastguard Worker 
1384*f6dc9357SAndroid Build Coastguard Worker     CItemEx itemEx;
1385*f6dc9357SAndroid Build Coastguard Worker     CItemOut item;
1386*f6dc9357SAndroid Build Coastguard Worker 
1387*f6dc9357SAndroid Build Coastguard Worker     if (!ui.NewProps || !ui.NewData)
1388*f6dc9357SAndroid Build Coastguard Worker     {
1389*f6dc9357SAndroid Build Coastguard Worker       itemEx = inputItems[(unsigned)ui.IndexInArc];
1390*f6dc9357SAndroid Build Coastguard Worker       if (inArchive->Read_LocalItem_After_CdItem_Full(itemEx) != S_OK)
1391*f6dc9357SAndroid Build Coastguard Worker         return E_NOTIMPL;
1392*f6dc9357SAndroid Build Coastguard Worker       (CItem &)item = itemEx;
1393*f6dc9357SAndroid Build Coastguard Worker     }
1394*f6dc9357SAndroid Build Coastguard Worker 
1395*f6dc9357SAndroid Build Coastguard Worker     if (ui.NewData)
1396*f6dc9357SAndroid Build Coastguard Worker     {
1397*f6dc9357SAndroid Build Coastguard Worker       // bool isDir = ((ui.NewProps) ? ui.IsDir : item.IsDir());
1398*f6dc9357SAndroid Build Coastguard Worker       const bool isDir = ui.IsDir;
1399*f6dc9357SAndroid Build Coastguard Worker 
1400*f6dc9357SAndroid Build Coastguard Worker       if (isDir)
1401*f6dc9357SAndroid Build Coastguard Worker       {
1402*f6dc9357SAndroid Build Coastguard Worker         RINOK(WriteDirHeader(archive, &options, ui, item))
1403*f6dc9357SAndroid Build Coastguard Worker       }
1404*f6dc9357SAndroid Build Coastguard Worker       else
1405*f6dc9357SAndroid Build Coastguard Worker       {
1406*f6dc9357SAndroid Build Coastguard Worker         CMemBlocks2 &memRef = refs.Refs[itemIndex];
1407*f6dc9357SAndroid Build Coastguard Worker 
1408*f6dc9357SAndroid Build Coastguard Worker         if (memRef.Finished)
1409*f6dc9357SAndroid Build Coastguard Worker         {
1410*f6dc9357SAndroid Build Coastguard Worker           if (lastRealStreamItemIndex < (int)itemIndex)
1411*f6dc9357SAndroid Build Coastguard Worker             lastRealStreamItemIndex = (int)itemIndex;
1412*f6dc9357SAndroid Build Coastguard Worker 
1413*f6dc9357SAndroid Build Coastguard Worker           SetFileHeader(options, ui, memRef.CompressingResult.DescriptorMode, item);
1414*f6dc9357SAndroid Build Coastguard Worker 
1415*f6dc9357SAndroid Build Coastguard Worker           // the BUG was fixed in 9.26:
1416*f6dc9357SAndroid Build Coastguard Worker           // SetItemInfoFromCompressingResult must be after SetFileHeader
1417*f6dc9357SAndroid Build Coastguard Worker           // to write correct Size.
1418*f6dc9357SAndroid Build Coastguard Worker 
1419*f6dc9357SAndroid Build Coastguard Worker           SetItemInfoFromCompressingResult(memRef.CompressingResult,
1420*f6dc9357SAndroid Build Coastguard Worker               options.IsRealAesMode(), options.AesKeyMode, item);
1421*f6dc9357SAndroid Build Coastguard Worker           RINOK(archive.ClearRestriction())
1422*f6dc9357SAndroid Build Coastguard Worker           archive.WriteLocalHeader(item);
1423*f6dc9357SAndroid Build Coastguard Worker           // RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
1424*f6dc9357SAndroid Build Coastguard Worker           CMyComPtr<ISequentialOutStream> outStream;
1425*f6dc9357SAndroid Build Coastguard Worker           archive.CreateStreamForCopying(outStream);
1426*f6dc9357SAndroid Build Coastguard Worker           memRef.WriteToStream(memManager.GetBlockSize(), outStream);
1427*f6dc9357SAndroid Build Coastguard Worker           // v23: we fixed the bug: we need to write descriptor also
1428*f6dc9357SAndroid Build Coastguard Worker           if (item.HasDescriptor())
1429*f6dc9357SAndroid Build Coastguard Worker           {
1430*f6dc9357SAndroid Build Coastguard Worker             /* that function doesn't rewrite local header, if item.HasDescriptor().
1431*f6dc9357SAndroid Build Coastguard Worker                it just writes descriptor */
1432*f6dc9357SAndroid Build Coastguard Worker             archive.WriteLocalHeader_Replace(item);
1433*f6dc9357SAndroid Build Coastguard Worker           }
1434*f6dc9357SAndroid Build Coastguard Worker           else
1435*f6dc9357SAndroid Build Coastguard Worker             archive.MoveCurPos(item.PackSize);
1436*f6dc9357SAndroid Build Coastguard Worker           memRef.FreeOpt(&memManager);
1437*f6dc9357SAndroid Build Coastguard Worker           /*
1438*f6dc9357SAndroid Build Coastguard Worker           if (reportArcProp)
1439*f6dc9357SAndroid Build Coastguard Worker           {
1440*f6dc9357SAndroid Build Coastguard Worker             stat.UpdateWithItem(item);
1441*f6dc9357SAndroid Build Coastguard Worker             RINOK(ReportProps(reportArcProp, ui.IndexInClient, item, options.IsRealAesMode()));
1442*f6dc9357SAndroid Build Coastguard Worker           }
1443*f6dc9357SAndroid Build Coastguard Worker           */
1444*f6dc9357SAndroid Build Coastguard Worker         }
1445*f6dc9357SAndroid Build Coastguard Worker         else
1446*f6dc9357SAndroid Build Coastguard Worker         {
1447*f6dc9357SAndroid Build Coastguard Worker           // current file was not finished
1448*f6dc9357SAndroid Build Coastguard Worker 
1449*f6dc9357SAndroid Build Coastguard Worker           if (lastRealStreamItemIndex < (int)itemIndex)
1450*f6dc9357SAndroid Build Coastguard Worker           {
1451*f6dc9357SAndroid Build Coastguard Worker             // LocalHeader was not written for current itemIndex still
1452*f6dc9357SAndroid Build Coastguard Worker 
1453*f6dc9357SAndroid Build Coastguard Worker             lastRealStreamItemIndex = (int)itemIndex;
1454*f6dc9357SAndroid Build Coastguard Worker 
1455*f6dc9357SAndroid Build Coastguard Worker             // thread was started before for that item already, and memRef.SeqMode was set
1456*f6dc9357SAndroid Build Coastguard Worker 
1457*f6dc9357SAndroid Build Coastguard Worker             CCompressingResult compressingResult;
1458*f6dc9357SAndroid Build Coastguard Worker             RINOK(compressor.Set_Pre_CompressionResult(
1459*f6dc9357SAndroid Build Coastguard Worker                 memRef.InSeqMode, outSeqMode,
1460*f6dc9357SAndroid Build Coastguard Worker                 ui.Size,
1461*f6dc9357SAndroid Build Coastguard Worker                 compressingResult))
1462*f6dc9357SAndroid Build Coastguard Worker 
1463*f6dc9357SAndroid Build Coastguard Worker             memRef.PreDescriptorMode = compressingResult.DescriptorMode;
1464*f6dc9357SAndroid Build Coastguard Worker             SetFileHeader(options, ui, compressingResult.DescriptorMode, item);
1465*f6dc9357SAndroid Build Coastguard Worker 
1466*f6dc9357SAndroid Build Coastguard Worker             SetItemInfoFromCompressingResult(compressingResult, options.IsRealAesMode(), options.AesKeyMode, item);
1467*f6dc9357SAndroid Build Coastguard Worker 
1468*f6dc9357SAndroid Build Coastguard Worker             // file Size can be 64-bit !!!
1469*f6dc9357SAndroid Build Coastguard Worker             RINOK(archive.SetRestrictionFromCurrent())
1470*f6dc9357SAndroid Build Coastguard Worker             archive.WriteLocalHeader(item);
1471*f6dc9357SAndroid Build Coastguard Worker           }
1472*f6dc9357SAndroid Build Coastguard Worker 
1473*f6dc9357SAndroid Build Coastguard Worker           {
1474*f6dc9357SAndroid Build Coastguard Worker             CThreadInfo &thread = threads.Threads[threadIndices.FrontItem()];
1475*f6dc9357SAndroid Build Coastguard Worker             if (!thread.OutStreamSpec->WasUnlockEventSent())
1476*f6dc9357SAndroid Build Coastguard Worker             {
1477*f6dc9357SAndroid Build Coastguard Worker               CMyComPtr<IOutStream> outStream;
1478*f6dc9357SAndroid Build Coastguard Worker               archive.CreateStreamForCompressing(outStream);
1479*f6dc9357SAndroid Build Coastguard Worker               thread.OutStreamSpec->SetOutStream(outStream);
1480*f6dc9357SAndroid Build Coastguard Worker               thread.OutStreamSpec->SetRealStreamMode();
1481*f6dc9357SAndroid Build Coastguard Worker             }
1482*f6dc9357SAndroid Build Coastguard Worker           }
1483*f6dc9357SAndroid Build Coastguard Worker 
1484*f6dc9357SAndroid Build Coastguard Worker           const WRes wres = mtSem.Semaphore.Lock();
1485*f6dc9357SAndroid Build Coastguard Worker           if (wres != 0)
1486*f6dc9357SAndroid Build Coastguard Worker             return HRESULT_FROM_WIN32(wres);
1487*f6dc9357SAndroid Build Coastguard Worker 
1488*f6dc9357SAndroid Build Coastguard Worker           const int ti = mtSem.GetFreeItem();
1489*f6dc9357SAndroid Build Coastguard Worker           if (ti < 0)
1490*f6dc9357SAndroid Build Coastguard Worker             return E_FAIL;
1491*f6dc9357SAndroid Build Coastguard Worker 
1492*f6dc9357SAndroid Build Coastguard Worker           CThreadInfo &threadInfo = threads.Threads[(unsigned)ti];
1493*f6dc9357SAndroid Build Coastguard Worker           threadInfo.InStream.Release();
1494*f6dc9357SAndroid Build Coastguard Worker           threadInfo.IsFree = true;
1495*f6dc9357SAndroid Build Coastguard Worker           RINOK(threadInfo.Result)
1496*f6dc9357SAndroid Build Coastguard Worker 
1497*f6dc9357SAndroid Build Coastguard Worker           unsigned t = 0;
1498*f6dc9357SAndroid Build Coastguard Worker 
1499*f6dc9357SAndroid Build Coastguard Worker           for (;;)
1500*f6dc9357SAndroid Build Coastguard Worker           {
1501*f6dc9357SAndroid Build Coastguard Worker             if (t == threadIndices.Size())
1502*f6dc9357SAndroid Build Coastguard Worker               return E_FAIL;
1503*f6dc9357SAndroid Build Coastguard Worker             if (threadIndices[t] == (unsigned)ti)
1504*f6dc9357SAndroid Build Coastguard Worker               break;
1505*f6dc9357SAndroid Build Coastguard Worker             t++;
1506*f6dc9357SAndroid Build Coastguard Worker           }
1507*f6dc9357SAndroid Build Coastguard Worker           threadIndices.Delete(t);
1508*f6dc9357SAndroid Build Coastguard Worker 
1509*f6dc9357SAndroid Build Coastguard Worker           if (t == 0)
1510*f6dc9357SAndroid Build Coastguard Worker           {
1511*f6dc9357SAndroid Build Coastguard Worker             // if thread for current file was finished.
1512*f6dc9357SAndroid Build Coastguard Worker             if (threadInfo.UpdateIndex != itemIndex)
1513*f6dc9357SAndroid Build Coastguard Worker               return E_FAIL;
1514*f6dc9357SAndroid Build Coastguard Worker 
1515*f6dc9357SAndroid Build Coastguard Worker             if (memRef.PreDescriptorMode != threadInfo.CompressingResult.DescriptorMode)
1516*f6dc9357SAndroid Build Coastguard Worker               return E_FAIL;
1517*f6dc9357SAndroid Build Coastguard Worker 
1518*f6dc9357SAndroid Build Coastguard Worker             RINOK(threadInfo.OutStreamSpec->WriteToRealStream())
1519*f6dc9357SAndroid Build Coastguard Worker             threadInfo.OutStreamSpec->ReleaseOutStream();
1520*f6dc9357SAndroid Build Coastguard Worker             SetFileHeader(options, ui, threadInfo.CompressingResult.DescriptorMode, item);
1521*f6dc9357SAndroid Build Coastguard Worker             SetItemInfoFromCompressingResult(threadInfo.CompressingResult,
1522*f6dc9357SAndroid Build Coastguard Worker                 options.IsRealAesMode(), options.AesKeyMode, item);
1523*f6dc9357SAndroid Build Coastguard Worker 
1524*f6dc9357SAndroid Build Coastguard Worker             archive.WriteLocalHeader_Replace(item);
1525*f6dc9357SAndroid Build Coastguard Worker 
1526*f6dc9357SAndroid Build Coastguard Worker             /*
1527*f6dc9357SAndroid Build Coastguard Worker             if (reportArcProp)
1528*f6dc9357SAndroid Build Coastguard Worker             {
1529*f6dc9357SAndroid Build Coastguard Worker               stat.UpdateWithItem(item);
1530*f6dc9357SAndroid Build Coastguard Worker               RINOK(ReportProps(reportArcProp, ui.IndexInClient, item, options.IsRealAesMode()));
1531*f6dc9357SAndroid Build Coastguard Worker             }
1532*f6dc9357SAndroid Build Coastguard Worker             */
1533*f6dc9357SAndroid Build Coastguard Worker           }
1534*f6dc9357SAndroid Build Coastguard Worker           else
1535*f6dc9357SAndroid Build Coastguard Worker           {
1536*f6dc9357SAndroid Build Coastguard Worker             // it's not current file. So we must store information in array
1537*f6dc9357SAndroid Build Coastguard Worker             CMemBlocks2 &memRef2 = refs.Refs[threadInfo.UpdateIndex];
1538*f6dc9357SAndroid Build Coastguard Worker             threadInfo.OutStreamSpec->DetachData(memRef2);
1539*f6dc9357SAndroid Build Coastguard Worker             memRef2.CompressingResult = threadInfo.CompressingResult;
1540*f6dc9357SAndroid Build Coastguard Worker             // memRef2.SeqMode = threadInfo.SeqMode; // it was set before
1541*f6dc9357SAndroid Build Coastguard Worker             memRef2.Finished = true;
1542*f6dc9357SAndroid Build Coastguard Worker             continue;
1543*f6dc9357SAndroid Build Coastguard Worker           }
1544*f6dc9357SAndroid Build Coastguard Worker         }
1545*f6dc9357SAndroid Build Coastguard Worker       }
1546*f6dc9357SAndroid Build Coastguard Worker     }
1547*f6dc9357SAndroid Build Coastguard Worker     else
1548*f6dc9357SAndroid Build Coastguard Worker     {
1549*f6dc9357SAndroid Build Coastguard Worker       RINOK(UpdateItemOldData(archive, inArchive, itemEx, ui, item, progress, opCallback, complexity))
1550*f6dc9357SAndroid Build Coastguard Worker     }
1551*f6dc9357SAndroid Build Coastguard Worker 
1552*f6dc9357SAndroid Build Coastguard Worker     items.Add(item);
1553*f6dc9357SAndroid Build Coastguard Worker     complexity += kLocalHeaderSize;
1554*f6dc9357SAndroid Build Coastguard Worker     mtProgressMixerSpec->Mixer2->SetProgressOffset(complexity);
1555*f6dc9357SAndroid Build Coastguard Worker     itemIndex++;
1556*f6dc9357SAndroid Build Coastguard Worker   }
1557*f6dc9357SAndroid Build Coastguard Worker 
1558*f6dc9357SAndroid Build Coastguard Worker   RINOK(mtCompressProgressMixer.SetRatioInfo(0, NULL, NULL))
1559*f6dc9357SAndroid Build Coastguard Worker 
1560*f6dc9357SAndroid Build Coastguard Worker   RINOK(archive.WriteCentralDir(items, comment))
1561*f6dc9357SAndroid Build Coastguard Worker 
1562*f6dc9357SAndroid Build Coastguard Worker   /*
1563*f6dc9357SAndroid Build Coastguard Worker   if (reportArcProp)
1564*f6dc9357SAndroid Build Coastguard Worker   {
1565*f6dc9357SAndroid Build Coastguard Worker     RINOK(ReportArcProps(reportArcProp, stat));
1566*f6dc9357SAndroid Build Coastguard Worker   }
1567*f6dc9357SAndroid Build Coastguard Worker   */
1568*f6dc9357SAndroid Build Coastguard Worker 
1569*f6dc9357SAndroid Build Coastguard Worker   complexity += kCentralHeaderSize * updateItems.Size() + 1;
1570*f6dc9357SAndroid Build Coastguard Worker   mtProgressMixerSpec->Mixer2->SetProgressOffset(complexity);
1571*f6dc9357SAndroid Build Coastguard Worker   return mtCompressProgressMixer.SetRatioInfo(0, NULL, NULL);
1572*f6dc9357SAndroid Build Coastguard Worker 
1573*f6dc9357SAndroid Build Coastguard Worker   #endif
1574*f6dc9357SAndroid Build Coastguard Worker }
1575*f6dc9357SAndroid Build Coastguard Worker 
1576*f6dc9357SAndroid Build Coastguard Worker /*
1577*f6dc9357SAndroid Build Coastguard Worker // we need CSeekOutStream, if we need Seek(0, STREAM_SEEK_CUR) for seqential stream
1578*f6dc9357SAndroid Build Coastguard Worker Z7_CLASS_IMP_COM_1(
1579*f6dc9357SAndroid Build Coastguard Worker   CSeekOutStream
1580*f6dc9357SAndroid Build Coastguard Worker   , IOutStream
1581*f6dc9357SAndroid Build Coastguard Worker )
1582*f6dc9357SAndroid Build Coastguard Worker   Z7_IFACE_COM7_IMP(ISequentialOutStream)
1583*f6dc9357SAndroid Build Coastguard Worker 
1584*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<ISequentialOutStream> _seqStream;
1585*f6dc9357SAndroid Build Coastguard Worker   UInt64 _size;
1586*f6dc9357SAndroid Build Coastguard Worker public:
1587*f6dc9357SAndroid Build Coastguard Worker   void Init(ISequentialOutStream *seqStream)
1588*f6dc9357SAndroid Build Coastguard Worker   {
1589*f6dc9357SAndroid Build Coastguard Worker     _size = 0;
1590*f6dc9357SAndroid Build Coastguard Worker     _seqStream = seqStream;
1591*f6dc9357SAndroid Build Coastguard Worker   }
1592*f6dc9357SAndroid Build Coastguard Worker };
1593*f6dc9357SAndroid Build Coastguard Worker 
1594*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CSeekOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize))
1595*f6dc9357SAndroid Build Coastguard Worker {
1596*f6dc9357SAndroid Build Coastguard Worker   UInt32 realProcessedSize;
1597*f6dc9357SAndroid Build Coastguard Worker   const HRESULT result = _seqStream->Write(data, size, &realProcessedSize);
1598*f6dc9357SAndroid Build Coastguard Worker   _size += realProcessedSize;
1599*f6dc9357SAndroid Build Coastguard Worker   if (processedSize)
1600*f6dc9357SAndroid Build Coastguard Worker     *processedSize = realProcessedSize;
1601*f6dc9357SAndroid Build Coastguard Worker   return result;
1602*f6dc9357SAndroid Build Coastguard Worker }
1603*f6dc9357SAndroid Build Coastguard Worker 
1604*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CSeekOutStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
1605*f6dc9357SAndroid Build Coastguard Worker {
1606*f6dc9357SAndroid Build Coastguard Worker   if (seekOrigin != STREAM_SEEK_CUR || offset != 0)
1607*f6dc9357SAndroid Build Coastguard Worker     return E_NOTIMPL;
1608*f6dc9357SAndroid Build Coastguard Worker   if (newPosition)
1609*f6dc9357SAndroid Build Coastguard Worker     *newPosition = (UInt64)_size;
1610*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1611*f6dc9357SAndroid Build Coastguard Worker }
1612*f6dc9357SAndroid Build Coastguard Worker 
1613*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CSeekOutStream::SetSize(UInt64 newSize))
1614*f6dc9357SAndroid Build Coastguard Worker {
1615*f6dc9357SAndroid Build Coastguard Worker   UNUSED_VAR(newSize)
1616*f6dc9357SAndroid Build Coastguard Worker   return E_NOTIMPL;
1617*f6dc9357SAndroid Build Coastguard Worker }
1618*f6dc9357SAndroid Build Coastguard Worker */
1619*f6dc9357SAndroid Build Coastguard Worker 
1620*f6dc9357SAndroid Build Coastguard Worker static const size_t kCacheBlockSize = 1 << 20;
1621*f6dc9357SAndroid Build Coastguard Worker static const size_t kCacheSize = kCacheBlockSize << 2;
1622*f6dc9357SAndroid Build Coastguard Worker static const size_t kCacheMask = kCacheSize - 1;
1623*f6dc9357SAndroid Build Coastguard Worker 
1624*f6dc9357SAndroid Build Coastguard Worker Z7_CLASS_IMP_NOQIB_2(
1625*f6dc9357SAndroid Build Coastguard Worker   CCacheOutStream
1626*f6dc9357SAndroid Build Coastguard Worker   , IOutStream
1627*f6dc9357SAndroid Build Coastguard Worker   , IStreamSetRestriction
1628*f6dc9357SAndroid Build Coastguard Worker )
1629*f6dc9357SAndroid Build Coastguard Worker   Z7_IFACE_COM7_IMP(ISequentialOutStream)
1630*f6dc9357SAndroid Build Coastguard Worker 
1631*f6dc9357SAndroid Build Coastguard Worker   HRESULT _hres;
1632*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<ISequentialOutStream> _seqStream;
1633*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<IOutStream> _stream;
1634*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<IStreamSetRestriction> _setRestriction;
1635*f6dc9357SAndroid Build Coastguard Worker   Byte *_cache;
1636*f6dc9357SAndroid Build Coastguard Worker   size_t _cachedSize;
1637*f6dc9357SAndroid Build Coastguard Worker   UInt64 _cachedPos;
1638*f6dc9357SAndroid Build Coastguard Worker   UInt64 _virtPos;
1639*f6dc9357SAndroid Build Coastguard Worker   UInt64 _virtSize;
1640*f6dc9357SAndroid Build Coastguard Worker   UInt64 _phyPos;
1641*f6dc9357SAndroid Build Coastguard Worker   UInt64 _phySize;
1642*f6dc9357SAndroid Build Coastguard Worker   UInt64 _restrict_begin;
1643*f6dc9357SAndroid Build Coastguard Worker   UInt64 _restrict_end;
1644*f6dc9357SAndroid Build Coastguard Worker 
1645*f6dc9357SAndroid Build Coastguard Worker   HRESULT FlushFromCache(size_t size);
1646*f6dc9357SAndroid Build Coastguard Worker   HRESULT FlushNonRestrictedBlocks();
1647*f6dc9357SAndroid Build Coastguard Worker   HRESULT FlushCache();
1648*f6dc9357SAndroid Build Coastguard Worker   HRESULT SetRestriction_ForWrite(size_t writeSize) const;
1649*f6dc9357SAndroid Build Coastguard Worker 
1650*f6dc9357SAndroid Build Coastguard Worker   HRESULT SeekPhy(UInt64 pos)
1651*f6dc9357SAndroid Build Coastguard Worker   {
1652*f6dc9357SAndroid Build Coastguard Worker     if (pos == _phyPos)
1653*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
1654*f6dc9357SAndroid Build Coastguard Worker     if (!_stream)
1655*f6dc9357SAndroid Build Coastguard Worker       return E_NOTIMPL;
1656*f6dc9357SAndroid Build Coastguard Worker     _hres = _stream->Seek((Int64)pos, STREAM_SEEK_SET, &_phyPos);
1657*f6dc9357SAndroid Build Coastguard Worker     if (_hres == S_OK && _phyPos != pos)
1658*f6dc9357SAndroid Build Coastguard Worker       _hres = E_FAIL;
1659*f6dc9357SAndroid Build Coastguard Worker     return _hres;
1660*f6dc9357SAndroid Build Coastguard Worker   }
1661*f6dc9357SAndroid Build Coastguard Worker 
1662*f6dc9357SAndroid Build Coastguard Worker public:
1663*f6dc9357SAndroid Build Coastguard Worker   CCacheOutStream(): _cache(NULL) {}
1664*f6dc9357SAndroid Build Coastguard Worker   ~CCacheOutStream();
1665*f6dc9357SAndroid Build Coastguard Worker   bool Allocate()
1666*f6dc9357SAndroid Build Coastguard Worker   {
1667*f6dc9357SAndroid Build Coastguard Worker     if (!_cache)
1668*f6dc9357SAndroid Build Coastguard Worker       _cache = (Byte *)::MidAlloc(kCacheSize);
1669*f6dc9357SAndroid Build Coastguard Worker     return _cache != NULL;
1670*f6dc9357SAndroid Build Coastguard Worker   }
1671*f6dc9357SAndroid Build Coastguard Worker   HRESULT Init(ISequentialOutStream *seqStream, IOutStream *stream, IStreamSetRestriction *setRestriction);
1672*f6dc9357SAndroid Build Coastguard Worker   HRESULT FinalFlush();
1673*f6dc9357SAndroid Build Coastguard Worker };
1674*f6dc9357SAndroid Build Coastguard Worker 
1675*f6dc9357SAndroid Build Coastguard Worker CCacheOutStream::~CCacheOutStream()
1676*f6dc9357SAndroid Build Coastguard Worker {
1677*f6dc9357SAndroid Build Coastguard Worker   ::MidFree(_cache);
1678*f6dc9357SAndroid Build Coastguard Worker }
1679*f6dc9357SAndroid Build Coastguard Worker 
1680*f6dc9357SAndroid Build Coastguard Worker 
1681*f6dc9357SAndroid Build Coastguard Worker HRESULT CCacheOutStream::Init(ISequentialOutStream *seqStream, IOutStream *stream, IStreamSetRestriction *setRestriction)
1682*f6dc9357SAndroid Build Coastguard Worker {
1683*f6dc9357SAndroid Build Coastguard Worker   _hres = S_OK;
1684*f6dc9357SAndroid Build Coastguard Worker   _cachedSize = 0;
1685*f6dc9357SAndroid Build Coastguard Worker   _cachedPos = 0;
1686*f6dc9357SAndroid Build Coastguard Worker   _virtPos = 0;
1687*f6dc9357SAndroid Build Coastguard Worker   _virtSize = 0;
1688*f6dc9357SAndroid Build Coastguard Worker   // by default we have no restriction
1689*f6dc9357SAndroid Build Coastguard Worker   _restrict_begin = 0;
1690*f6dc9357SAndroid Build Coastguard Worker   _restrict_end = 0;
1691*f6dc9357SAndroid Build Coastguard Worker   _seqStream = seqStream;
1692*f6dc9357SAndroid Build Coastguard Worker   _stream = stream;
1693*f6dc9357SAndroid Build Coastguard Worker   _setRestriction = setRestriction;
1694*f6dc9357SAndroid Build Coastguard Worker   if (_stream)
1695*f6dc9357SAndroid Build Coastguard Worker   {
1696*f6dc9357SAndroid Build Coastguard Worker     RINOK(_stream->Seek(0, STREAM_SEEK_CUR, &_virtPos))
1697*f6dc9357SAndroid Build Coastguard Worker     RINOK(_stream->Seek(0, STREAM_SEEK_END, &_virtSize))
1698*f6dc9357SAndroid Build Coastguard Worker     RINOK(_stream->Seek((Int64)_virtPos, STREAM_SEEK_SET, &_virtPos))
1699*f6dc9357SAndroid Build Coastguard Worker   }
1700*f6dc9357SAndroid Build Coastguard Worker   _phyPos = _virtPos;
1701*f6dc9357SAndroid Build Coastguard Worker   _phySize = _virtSize;
1702*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1703*f6dc9357SAndroid Build Coastguard Worker }
1704*f6dc9357SAndroid Build Coastguard Worker 
1705*f6dc9357SAndroid Build Coastguard Worker 
1706*f6dc9357SAndroid Build Coastguard Worker /* we call SetRestriction_ForWrite() just before Write() from cache.
1707*f6dc9357SAndroid Build Coastguard Worker    (_phyPos == _cachedPos)
1708*f6dc9357SAndroid Build Coastguard Worker    (writeSize != 0)
1709*f6dc9357SAndroid Build Coastguard Worker */
1710*f6dc9357SAndroid Build Coastguard Worker HRESULT CCacheOutStream::SetRestriction_ForWrite(size_t writeSize) const
1711*f6dc9357SAndroid Build Coastguard Worker {
1712*f6dc9357SAndroid Build Coastguard Worker   if (!_setRestriction)
1713*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
1714*f6dc9357SAndroid Build Coastguard Worker   PRF(printf("\n-- CCacheOutStream::SetRestriction_ForWrite _cachedPos = 0x%x, writeSize = %d\n", (unsigned)_cachedPos, (unsigned)writeSize));
1715*f6dc9357SAndroid Build Coastguard Worker   UInt64 begin = _restrict_begin;
1716*f6dc9357SAndroid Build Coastguard Worker   UInt64 end = _restrict_end;
1717*f6dc9357SAndroid Build Coastguard Worker   const UInt64 phyPos = _phyPos;
1718*f6dc9357SAndroid Build Coastguard Worker   if (phyPos != _cachedPos) return E_FAIL;
1719*f6dc9357SAndroid Build Coastguard Worker   if (phyPos == _phySize)
1720*f6dc9357SAndroid Build Coastguard Worker   {
1721*f6dc9357SAndroid Build Coastguard Worker     // The writing will be to the end of phy stream.
1722*f6dc9357SAndroid Build Coastguard Worker     // So we will try to use non-restricted write, if possible.
1723*f6dc9357SAndroid Build Coastguard Worker     if (begin == end)
1724*f6dc9357SAndroid Build Coastguard Worker       begin = _virtPos; // _virtSize; // it's supposed that (_virtSize == _virtPos)
1725*f6dc9357SAndroid Build Coastguard Worker     if (phyPos + writeSize <= begin)
1726*f6dc9357SAndroid Build Coastguard Worker     {
1727*f6dc9357SAndroid Build Coastguard Worker       // the write is not restricted
1728*f6dc9357SAndroid Build Coastguard Worker       PRF(printf("\n+++ write is not restricted \n"));
1729*f6dc9357SAndroid Build Coastguard Worker       begin = 0;
1730*f6dc9357SAndroid Build Coastguard Worker       end = 0;
1731*f6dc9357SAndroid Build Coastguard Worker     }
1732*f6dc9357SAndroid Build Coastguard Worker     else
1733*f6dc9357SAndroid Build Coastguard Worker     {
1734*f6dc9357SAndroid Build Coastguard Worker       if (begin > phyPos)
1735*f6dc9357SAndroid Build Coastguard Worker         begin = phyPos;
1736*f6dc9357SAndroid Build Coastguard Worker       end = (UInt64)(Int64)-1;
1737*f6dc9357SAndroid Build Coastguard Worker     }
1738*f6dc9357SAndroid Build Coastguard Worker   }
1739*f6dc9357SAndroid Build Coastguard Worker   else
1740*f6dc9357SAndroid Build Coastguard Worker   {
1741*f6dc9357SAndroid Build Coastguard Worker     // (phyPos != _phySize)
1742*f6dc9357SAndroid Build Coastguard Worker     if (begin == end || begin > phyPos)
1743*f6dc9357SAndroid Build Coastguard Worker       begin = phyPos;
1744*f6dc9357SAndroid Build Coastguard Worker     end = (UInt64)(Int64)-1;
1745*f6dc9357SAndroid Build Coastguard Worker   }
1746*f6dc9357SAndroid Build Coastguard Worker   return _setRestriction->SetRestriction(begin, end);
1747*f6dc9357SAndroid Build Coastguard Worker }
1748*f6dc9357SAndroid Build Coastguard Worker 
1749*f6dc9357SAndroid Build Coastguard Worker 
1750*f6dc9357SAndroid Build Coastguard Worker /* it writes up to (size) bytes from cache.
1751*f6dc9357SAndroid Build Coastguard Worker    (size > _cachedSize) is allowed
1752*f6dc9357SAndroid Build Coastguard Worker */
1753*f6dc9357SAndroid Build Coastguard Worker HRESULT CCacheOutStream::FlushFromCache(size_t size)
1754*f6dc9357SAndroid Build Coastguard Worker {
1755*f6dc9357SAndroid Build Coastguard Worker   PRF(printf("\n-- CCacheOutStream::FlushFromCache %u\n", (unsigned)size));
1756*f6dc9357SAndroid Build Coastguard Worker   if (_hres != S_OK)
1757*f6dc9357SAndroid Build Coastguard Worker     return _hres;
1758*f6dc9357SAndroid Build Coastguard Worker   if (size > _cachedSize)
1759*f6dc9357SAndroid Build Coastguard Worker       size = _cachedSize;
1760*f6dc9357SAndroid Build Coastguard Worker   // (size <= _cachedSize)
1761*f6dc9357SAndroid Build Coastguard Worker   if (size == 0)
1762*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
1763*f6dc9357SAndroid Build Coastguard Worker   RINOK(SeekPhy(_cachedPos))
1764*f6dc9357SAndroid Build Coastguard Worker   for (;;)
1765*f6dc9357SAndroid Build Coastguard Worker   {
1766*f6dc9357SAndroid Build Coastguard Worker     // (_phyPos == _cachedPos)
1767*f6dc9357SAndroid Build Coastguard Worker     const size_t pos = (size_t)_cachedPos & kCacheMask;
1768*f6dc9357SAndroid Build Coastguard Worker     const size_t cur = MyMin(kCacheSize - pos, size);
1769*f6dc9357SAndroid Build Coastguard Worker     _hres = SetRestriction_ForWrite(cur);
1770*f6dc9357SAndroid Build Coastguard Worker     RINOK(_hres)
1771*f6dc9357SAndroid Build Coastguard Worker     PRF(printf("\n-- CCacheOutStream::WriteFromCache _phyPos = 0x%x, size = %d\n", (unsigned)_phyPos, (unsigned)cur));
1772*f6dc9357SAndroid Build Coastguard Worker     _hres = WriteStream(_seqStream, _cache + pos, cur);
1773*f6dc9357SAndroid Build Coastguard Worker     RINOK(_hres)
1774*f6dc9357SAndroid Build Coastguard Worker     _phyPos += cur;
1775*f6dc9357SAndroid Build Coastguard Worker     if (_phySize < _phyPos)
1776*f6dc9357SAndroid Build Coastguard Worker       _phySize = _phyPos;
1777*f6dc9357SAndroid Build Coastguard Worker     _cachedPos += cur;
1778*f6dc9357SAndroid Build Coastguard Worker     _cachedSize -= cur;
1779*f6dc9357SAndroid Build Coastguard Worker     size -= cur;
1780*f6dc9357SAndroid Build Coastguard Worker     if (size == 0)
1781*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
1782*f6dc9357SAndroid Build Coastguard Worker   }
1783*f6dc9357SAndroid Build Coastguard Worker }
1784*f6dc9357SAndroid Build Coastguard Worker 
1785*f6dc9357SAndroid Build Coastguard Worker 
1786*f6dc9357SAndroid Build Coastguard Worker HRESULT CCacheOutStream::FlushNonRestrictedBlocks()
1787*f6dc9357SAndroid Build Coastguard Worker {
1788*f6dc9357SAndroid Build Coastguard Worker   for (;;)
1789*f6dc9357SAndroid Build Coastguard Worker   {
1790*f6dc9357SAndroid Build Coastguard Worker     const size_t size = kCacheBlockSize - ((size_t)_cachedPos & (kCacheBlockSize - 1));
1791*f6dc9357SAndroid Build Coastguard Worker     if (_cachedSize < size)
1792*f6dc9357SAndroid Build Coastguard Worker       break;
1793*f6dc9357SAndroid Build Coastguard Worker     UInt64 begin = _restrict_begin;
1794*f6dc9357SAndroid Build Coastguard Worker     if (begin == _restrict_end)
1795*f6dc9357SAndroid Build Coastguard Worker       begin = _virtPos;
1796*f6dc9357SAndroid Build Coastguard Worker     // we don't flush the data to restricted area
1797*f6dc9357SAndroid Build Coastguard Worker     if (_cachedPos + size > begin)
1798*f6dc9357SAndroid Build Coastguard Worker       break;
1799*f6dc9357SAndroid Build Coastguard Worker     RINOK(FlushFromCache(size))
1800*f6dc9357SAndroid Build Coastguard Worker   }
1801*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1802*f6dc9357SAndroid Build Coastguard Worker }
1803*f6dc9357SAndroid Build Coastguard Worker 
1804*f6dc9357SAndroid Build Coastguard Worker 
1805*f6dc9357SAndroid Build Coastguard Worker HRESULT CCacheOutStream::FlushCache()
1806*f6dc9357SAndroid Build Coastguard Worker {
1807*f6dc9357SAndroid Build Coastguard Worker   return FlushFromCache(_cachedSize);
1808*f6dc9357SAndroid Build Coastguard Worker }
1809*f6dc9357SAndroid Build Coastguard Worker 
1810*f6dc9357SAndroid Build Coastguard Worker HRESULT CCacheOutStream::FinalFlush()
1811*f6dc9357SAndroid Build Coastguard Worker {
1812*f6dc9357SAndroid Build Coastguard Worker   _restrict_begin = 0;
1813*f6dc9357SAndroid Build Coastguard Worker   _restrict_end = 0;
1814*f6dc9357SAndroid Build Coastguard Worker   RINOK(FlushCache())
1815*f6dc9357SAndroid Build Coastguard Worker   if (_stream && _hres == S_OK)
1816*f6dc9357SAndroid Build Coastguard Worker   {
1817*f6dc9357SAndroid Build Coastguard Worker     if (_virtSize != _phySize)
1818*f6dc9357SAndroid Build Coastguard Worker     {
1819*f6dc9357SAndroid Build Coastguard Worker       // it's unexpected
1820*f6dc9357SAndroid Build Coastguard Worker       RINOK(_stream->SetSize(_virtSize))
1821*f6dc9357SAndroid Build Coastguard Worker       _phySize = _virtSize;
1822*f6dc9357SAndroid Build Coastguard Worker     }
1823*f6dc9357SAndroid Build Coastguard Worker     _hres = SeekPhy(_virtPos);
1824*f6dc9357SAndroid Build Coastguard Worker   }
1825*f6dc9357SAndroid Build Coastguard Worker   return _hres;
1826*f6dc9357SAndroid Build Coastguard Worker }
1827*f6dc9357SAndroid Build Coastguard Worker 
1828*f6dc9357SAndroid Build Coastguard Worker 
1829*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CCacheOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize))
1830*f6dc9357SAndroid Build Coastguard Worker {
1831*f6dc9357SAndroid Build Coastguard Worker   PRF(printf("\n==== CCacheOutStream::Write virtPos=0x%x, %u\n", (unsigned)_virtPos, (unsigned)size));
1832*f6dc9357SAndroid Build Coastguard Worker 
1833*f6dc9357SAndroid Build Coastguard Worker   if (processedSize)
1834*f6dc9357SAndroid Build Coastguard Worker     *processedSize = 0;
1835*f6dc9357SAndroid Build Coastguard Worker   if (size == 0)
1836*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
1837*f6dc9357SAndroid Build Coastguard Worker   if (_hres != S_OK)
1838*f6dc9357SAndroid Build Coastguard Worker     return _hres;
1839*f6dc9357SAndroid Build Coastguard Worker 
1840*f6dc9357SAndroid Build Coastguard Worker   if (_cachedSize != 0)
1841*f6dc9357SAndroid Build Coastguard Worker   if (_virtPos < _cachedPos ||
1842*f6dc9357SAndroid Build Coastguard Worker       _virtPos > _cachedPos + _cachedSize)
1843*f6dc9357SAndroid Build Coastguard Worker   {
1844*f6dc9357SAndroid Build Coastguard Worker     RINOK(FlushCache())
1845*f6dc9357SAndroid Build Coastguard Worker   }
1846*f6dc9357SAndroid Build Coastguard Worker 
1847*f6dc9357SAndroid Build Coastguard Worker   if (_cachedSize == 0)
1848*f6dc9357SAndroid Build Coastguard Worker     _cachedPos = _virtPos;
1849*f6dc9357SAndroid Build Coastguard Worker 
1850*f6dc9357SAndroid Build Coastguard Worker   const size_t pos = (size_t)_virtPos & kCacheMask;
1851*f6dc9357SAndroid Build Coastguard Worker   {
1852*f6dc9357SAndroid Build Coastguard Worker     const size_t blockRem = kCacheBlockSize - ((size_t)_virtPos & (kCacheBlockSize - 1));
1853*f6dc9357SAndroid Build Coastguard Worker     if (size > blockRem)
1854*f6dc9357SAndroid Build Coastguard Worker       size = (UInt32)blockRem;
1855*f6dc9357SAndroid Build Coastguard Worker   }
1856*f6dc9357SAndroid Build Coastguard Worker   // _cachedPos <= _virtPos <= _cachedPos + _cachedSize
1857*f6dc9357SAndroid Build Coastguard Worker   const UInt64 cachedRem = _cachedPos + _cachedSize - _virtPos;
1858*f6dc9357SAndroid Build Coastguard Worker   if (cachedRem)
1859*f6dc9357SAndroid Build Coastguard Worker   {
1860*f6dc9357SAndroid Build Coastguard Worker     // _virtPos < _cachedPos + _cachedSize
1861*f6dc9357SAndroid Build Coastguard Worker     // we rewrite only existing data in cache. So _cachedSize will be not changed
1862*f6dc9357SAndroid Build Coastguard Worker     if (size > cachedRem)
1863*f6dc9357SAndroid Build Coastguard Worker       size = (UInt32)cachedRem;
1864*f6dc9357SAndroid Build Coastguard Worker   }
1865*f6dc9357SAndroid Build Coastguard Worker   else
1866*f6dc9357SAndroid Build Coastguard Worker   {
1867*f6dc9357SAndroid Build Coastguard Worker     // _virtPos == _cachedPos + _cachedSize
1868*f6dc9357SAndroid Build Coastguard Worker     // so we need to add new data to the end of cache
1869*f6dc9357SAndroid Build Coastguard Worker     if (_cachedSize == kCacheSize)
1870*f6dc9357SAndroid Build Coastguard Worker     {
1871*f6dc9357SAndroid Build Coastguard Worker       // cache is full. So we need to flush some part of cache.
1872*f6dc9357SAndroid Build Coastguard Worker       // we flush only one block, but we are allowed to flush any size here
1873*f6dc9357SAndroid Build Coastguard Worker       RINOK(FlushFromCache(kCacheBlockSize - ((size_t)_cachedPos & (kCacheBlockSize - 1))))
1874*f6dc9357SAndroid Build Coastguard Worker     }
1875*f6dc9357SAndroid Build Coastguard Worker     // _cachedSize != kCacheSize
1876*f6dc9357SAndroid Build Coastguard Worker     // so we have some space for new data in cache
1877*f6dc9357SAndroid Build Coastguard Worker     if (_cachedSize == 0)
1878*f6dc9357SAndroid Build Coastguard Worker     {
1879*f6dc9357SAndroid Build Coastguard Worker       /* this code is optional (for optimization):
1880*f6dc9357SAndroid Build Coastguard Worker          we write data directly without cache,
1881*f6dc9357SAndroid Build Coastguard Worker          if there is no restriction and we have full block. */
1882*f6dc9357SAndroid Build Coastguard Worker       if (_restrict_begin == _restrict_end
1883*f6dc9357SAndroid Build Coastguard Worker           && size == kCacheBlockSize)
1884*f6dc9357SAndroid Build Coastguard Worker       {
1885*f6dc9357SAndroid Build Coastguard Worker         RINOK(SeekPhy(_virtPos))
1886*f6dc9357SAndroid Build Coastguard Worker         if (_setRestriction)
1887*f6dc9357SAndroid Build Coastguard Worker         {
1888*f6dc9357SAndroid Build Coastguard Worker           _hres = _setRestriction->SetRestriction(_restrict_begin, _restrict_end);
1889*f6dc9357SAndroid Build Coastguard Worker           RINOK(_hres)
1890*f6dc9357SAndroid Build Coastguard Worker         }
1891*f6dc9357SAndroid Build Coastguard Worker         PRF(printf("\n-- CCacheOutStream::WriteDirectly _phyPos = 0x%x, size = %d\n", (unsigned)_phyPos, (unsigned)size));
1892*f6dc9357SAndroid Build Coastguard Worker         _hres = WriteStream(_seqStream, data, size);
1893*f6dc9357SAndroid Build Coastguard Worker         RINOK(_hres)
1894*f6dc9357SAndroid Build Coastguard Worker         if (processedSize)
1895*f6dc9357SAndroid Build Coastguard Worker           *processedSize = size;
1896*f6dc9357SAndroid Build Coastguard Worker         _virtPos += size;
1897*f6dc9357SAndroid Build Coastguard Worker         if (_virtSize < _virtPos)
1898*f6dc9357SAndroid Build Coastguard Worker           _virtSize = _virtPos;
1899*f6dc9357SAndroid Build Coastguard Worker         _phyPos += size;
1900*f6dc9357SAndroid Build Coastguard Worker         if (_phySize < _phyPos)
1901*f6dc9357SAndroid Build Coastguard Worker           _phySize = _phyPos;
1902*f6dc9357SAndroid Build Coastguard Worker         return S_OK;
1903*f6dc9357SAndroid Build Coastguard Worker       }
1904*f6dc9357SAndroid Build Coastguard Worker     }
1905*f6dc9357SAndroid Build Coastguard Worker     else // (_cachedSize != 0)
1906*f6dc9357SAndroid Build Coastguard Worker     {
1907*f6dc9357SAndroid Build Coastguard Worker       const size_t startPos = (size_t)_cachedPos & kCacheMask;
1908*f6dc9357SAndroid Build Coastguard Worker       // we don't allow new data to overwrite old start data in cache.
1909*f6dc9357SAndroid Build Coastguard Worker       // (startPos == pos) here means that cache is empty.
1910*f6dc9357SAndroid Build Coastguard Worker       // (startPos == pos) is not possible here.
1911*f6dc9357SAndroid Build Coastguard Worker       if (startPos > pos)
1912*f6dc9357SAndroid Build Coastguard Worker         size = (UInt32)MyMin((size_t)size, (size_t)(startPos - pos));
1913*f6dc9357SAndroid Build Coastguard Worker     }
1914*f6dc9357SAndroid Build Coastguard Worker     // _virtPos == (_cachedPos + _cachedSize) still
1915*f6dc9357SAndroid Build Coastguard Worker     _cachedSize += size;
1916*f6dc9357SAndroid Build Coastguard Worker   }
1917*f6dc9357SAndroid Build Coastguard Worker 
1918*f6dc9357SAndroid Build Coastguard Worker   memcpy(_cache + pos, data, size);
1919*f6dc9357SAndroid Build Coastguard Worker   if (processedSize)
1920*f6dc9357SAndroid Build Coastguard Worker     *processedSize = size;
1921*f6dc9357SAndroid Build Coastguard Worker   _virtPos += size;
1922*f6dc9357SAndroid Build Coastguard Worker   if (_virtSize < _virtPos)
1923*f6dc9357SAndroid Build Coastguard Worker     _virtSize = _virtPos;
1924*f6dc9357SAndroid Build Coastguard Worker   return FlushNonRestrictedBlocks();
1925*f6dc9357SAndroid Build Coastguard Worker }
1926*f6dc9357SAndroid Build Coastguard Worker 
1927*f6dc9357SAndroid Build Coastguard Worker 
1928*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CCacheOutStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
1929*f6dc9357SAndroid Build Coastguard Worker {
1930*f6dc9357SAndroid Build Coastguard Worker   PRF(printf("\n==== CCacheOutStream::Seek seekOrigin=%d Seek =%u\n", seekOrigin, (unsigned)offset));
1931*f6dc9357SAndroid Build Coastguard Worker   switch (seekOrigin)
1932*f6dc9357SAndroid Build Coastguard Worker   {
1933*f6dc9357SAndroid Build Coastguard Worker     case STREAM_SEEK_SET: break;
1934*f6dc9357SAndroid Build Coastguard Worker     case STREAM_SEEK_CUR: offset += _virtPos; break;
1935*f6dc9357SAndroid Build Coastguard Worker     case STREAM_SEEK_END: offset += _virtSize; break;
1936*f6dc9357SAndroid Build Coastguard Worker     default: return STG_E_INVALIDFUNCTION;
1937*f6dc9357SAndroid Build Coastguard Worker   }
1938*f6dc9357SAndroid Build Coastguard Worker   if (offset < 0)
1939*f6dc9357SAndroid Build Coastguard Worker     return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
1940*f6dc9357SAndroid Build Coastguard Worker   _virtPos = (UInt64)offset;
1941*f6dc9357SAndroid Build Coastguard Worker   if (newPosition)
1942*f6dc9357SAndroid Build Coastguard Worker     *newPosition = (UInt64)offset;
1943*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1944*f6dc9357SAndroid Build Coastguard Worker }
1945*f6dc9357SAndroid Build Coastguard Worker 
1946*f6dc9357SAndroid Build Coastguard Worker 
1947*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CCacheOutStream::SetSize(UInt64 newSize))
1948*f6dc9357SAndroid Build Coastguard Worker {
1949*f6dc9357SAndroid Build Coastguard Worker   if (_hres != S_OK)
1950*f6dc9357SAndroid Build Coastguard Worker     return _hres;
1951*f6dc9357SAndroid Build Coastguard Worker 
1952*f6dc9357SAndroid Build Coastguard Worker   if (newSize <= _cachedPos || _cachedSize == 0)
1953*f6dc9357SAndroid Build Coastguard Worker   {
1954*f6dc9357SAndroid Build Coastguard Worker     _cachedSize = 0;
1955*f6dc9357SAndroid Build Coastguard Worker     _cachedPos = newSize;
1956*f6dc9357SAndroid Build Coastguard Worker   }
1957*f6dc9357SAndroid Build Coastguard Worker   else
1958*f6dc9357SAndroid Build Coastguard Worker   {
1959*f6dc9357SAndroid Build Coastguard Worker     // _cachedSize != 0
1960*f6dc9357SAndroid Build Coastguard Worker     // newSize > _cachedPos
1961*f6dc9357SAndroid Build Coastguard Worker     const UInt64 offset = newSize - _cachedPos;
1962*f6dc9357SAndroid Build Coastguard Worker     if (offset <= _cachedSize)
1963*f6dc9357SAndroid Build Coastguard Worker     {
1964*f6dc9357SAndroid Build Coastguard Worker       // newSize is inside cached block or is touching cached block.
1965*f6dc9357SAndroid Build Coastguard Worker       // so we reduce cache
1966*f6dc9357SAndroid Build Coastguard Worker       _cachedSize = (size_t)offset;
1967*f6dc9357SAndroid Build Coastguard Worker       if (_phySize <= newSize)
1968*f6dc9357SAndroid Build Coastguard Worker       {
1969*f6dc9357SAndroid Build Coastguard Worker         // _phySize will be restored later after cache flush
1970*f6dc9357SAndroid Build Coastguard Worker         _virtSize = newSize;
1971*f6dc9357SAndroid Build Coastguard Worker         return S_OK;
1972*f6dc9357SAndroid Build Coastguard Worker       }
1973*f6dc9357SAndroid Build Coastguard Worker       // (_phySize > newSize)
1974*f6dc9357SAndroid Build Coastguard Worker       // so we must reduce phyStream size to (newSize) or to (_cachedPos)
1975*f6dc9357SAndroid Build Coastguard Worker       // newPhySize = _cachedPos; // optional reduce to _cachedPos
1976*f6dc9357SAndroid Build Coastguard Worker     }
1977*f6dc9357SAndroid Build Coastguard Worker     else
1978*f6dc9357SAndroid Build Coastguard Worker     {
1979*f6dc9357SAndroid Build Coastguard Worker       // newSize > _cachedPos + _cachedSize
1980*f6dc9357SAndroid Build Coastguard Worker       /* It's possible that we need to write zeros,
1981*f6dc9357SAndroid Build Coastguard Worker          if new size is larger than old size.
1982*f6dc9357SAndroid Build Coastguard Worker          We don't optimize for possible cases here.
1983*f6dc9357SAndroid Build Coastguard Worker          So we just flush the cache. */
1984*f6dc9357SAndroid Build Coastguard Worker       _hres = FlushCache();
1985*f6dc9357SAndroid Build Coastguard Worker     }
1986*f6dc9357SAndroid Build Coastguard Worker   }
1987*f6dc9357SAndroid Build Coastguard Worker 
1988*f6dc9357SAndroid Build Coastguard Worker   _virtSize = newSize;
1989*f6dc9357SAndroid Build Coastguard Worker 
1990*f6dc9357SAndroid Build Coastguard Worker   if (_hres != S_OK)
1991*f6dc9357SAndroid Build Coastguard Worker     return _hres;
1992*f6dc9357SAndroid Build Coastguard Worker 
1993*f6dc9357SAndroid Build Coastguard Worker   if (newSize != _phySize)
1994*f6dc9357SAndroid Build Coastguard Worker   {
1995*f6dc9357SAndroid Build Coastguard Worker     if (!_stream)
1996*f6dc9357SAndroid Build Coastguard Worker       return E_NOTIMPL;
1997*f6dc9357SAndroid Build Coastguard Worker     // if (_phyPos > newSize)
1998*f6dc9357SAndroid Build Coastguard Worker     RINOK(SeekPhy(newSize))
1999*f6dc9357SAndroid Build Coastguard Worker     if (_setRestriction)
2000*f6dc9357SAndroid Build Coastguard Worker     {
2001*f6dc9357SAndroid Build Coastguard Worker       UInt64 begin = _restrict_begin;
2002*f6dc9357SAndroid Build Coastguard Worker       UInt64 end = _restrict_end;
2003*f6dc9357SAndroid Build Coastguard Worker       if (_cachedSize != 0)
2004*f6dc9357SAndroid Build Coastguard Worker       {
2005*f6dc9357SAndroid Build Coastguard Worker         if (begin > _cachedPos)
2006*f6dc9357SAndroid Build Coastguard Worker           begin = _cachedPos;
2007*f6dc9357SAndroid Build Coastguard Worker         end = (UInt64)(Int64)-1;
2008*f6dc9357SAndroid Build Coastguard Worker       }
2009*f6dc9357SAndroid Build Coastguard Worker       _hres = _setRestriction->SetRestriction(begin, end);
2010*f6dc9357SAndroid Build Coastguard Worker       RINOK(_hres)
2011*f6dc9357SAndroid Build Coastguard Worker     }
2012*f6dc9357SAndroid Build Coastguard Worker     _hres = _stream->SetSize(newSize);
2013*f6dc9357SAndroid Build Coastguard Worker     RINOK(_hres)
2014*f6dc9357SAndroid Build Coastguard Worker     _phySize = newSize;
2015*f6dc9357SAndroid Build Coastguard Worker   }
2016*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
2017*f6dc9357SAndroid Build Coastguard Worker }
2018*f6dc9357SAndroid Build Coastguard Worker 
2019*f6dc9357SAndroid Build Coastguard Worker 
2020*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CCacheOutStream::SetRestriction(UInt64 begin, UInt64 end))
2021*f6dc9357SAndroid Build Coastguard Worker {
2022*f6dc9357SAndroid Build Coastguard Worker   PRF(printf("\n============ CCacheOutStream::SetRestriction 0x%x, %u\n", (unsigned)begin, (unsigned)end));
2023*f6dc9357SAndroid Build Coastguard Worker   _restrict_begin = begin;
2024*f6dc9357SAndroid Build Coastguard Worker   _restrict_end = end;
2025*f6dc9357SAndroid Build Coastguard Worker   return FlushNonRestrictedBlocks();
2026*f6dc9357SAndroid Build Coastguard Worker }
2027*f6dc9357SAndroid Build Coastguard Worker 
2028*f6dc9357SAndroid Build Coastguard Worker 
2029*f6dc9357SAndroid Build Coastguard Worker 
2030*f6dc9357SAndroid Build Coastguard Worker HRESULT Update(
2031*f6dc9357SAndroid Build Coastguard Worker     DECL_EXTERNAL_CODECS_LOC_VARS
2032*f6dc9357SAndroid Build Coastguard Worker     const CObjectVector<CItemEx> &inputItems,
2033*f6dc9357SAndroid Build Coastguard Worker     CObjectVector<CUpdateItem> &updateItems,
2034*f6dc9357SAndroid Build Coastguard Worker     ISequentialOutStream *seqOutStream,
2035*f6dc9357SAndroid Build Coastguard Worker     CInArchive *inArchive, bool removeSfx,
2036*f6dc9357SAndroid Build Coastguard Worker     const CUpdateOptions &updateOptions,
2037*f6dc9357SAndroid Build Coastguard Worker     const CCompressionMethodMode &compressionMethodMode,
2038*f6dc9357SAndroid Build Coastguard Worker     IArchiveUpdateCallback *updateCallback)
2039*f6dc9357SAndroid Build Coastguard Worker {
2040*f6dc9357SAndroid Build Coastguard Worker   /*
2041*f6dc9357SAndroid Build Coastguard Worker   // it was tested before
2042*f6dc9357SAndroid Build Coastguard Worker   if (inArchive)
2043*f6dc9357SAndroid Build Coastguard Worker   {
2044*f6dc9357SAndroid Build Coastguard Worker     if (!inArchive->CanUpdate())
2045*f6dc9357SAndroid Build Coastguard Worker       return E_NOTIMPL;
2046*f6dc9357SAndroid Build Coastguard Worker   }
2047*f6dc9357SAndroid Build Coastguard Worker   */
2048*f6dc9357SAndroid Build Coastguard Worker 
2049*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<IStreamSetRestriction> setRestriction;
2050*f6dc9357SAndroid Build Coastguard Worker   seqOutStream->QueryInterface(IID_IStreamSetRestriction, (void **)&setRestriction);
2051*f6dc9357SAndroid Build Coastguard Worker   if (setRestriction)
2052*f6dc9357SAndroid Build Coastguard Worker   {
2053*f6dc9357SAndroid Build Coastguard Worker     RINOK(setRestriction->SetRestriction(0, 0))
2054*f6dc9357SAndroid Build Coastguard Worker   }
2055*f6dc9357SAndroid Build Coastguard Worker 
2056*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<IOutStream> outStream;
2057*f6dc9357SAndroid Build Coastguard Worker   CCacheOutStream *cacheStream;
2058*f6dc9357SAndroid Build Coastguard Worker   bool outSeqMode;
2059*f6dc9357SAndroid Build Coastguard Worker 
2060*f6dc9357SAndroid Build Coastguard Worker   {
2061*f6dc9357SAndroid Build Coastguard Worker     CMyComPtr<IOutStream> outStreamReal;
2062*f6dc9357SAndroid Build Coastguard Worker 
2063*f6dc9357SAndroid Build Coastguard Worker     if (!compressionMethodMode.Force_SeqOutMode)
2064*f6dc9357SAndroid Build Coastguard Worker     {
2065*f6dc9357SAndroid Build Coastguard Worker       seqOutStream->QueryInterface(IID_IOutStream, (void **)&outStreamReal);
2066*f6dc9357SAndroid Build Coastguard Worker       /*
2067*f6dc9357SAndroid Build Coastguard Worker       if (!outStreamReal)
2068*f6dc9357SAndroid Build Coastguard Worker         return E_NOTIMPL;
2069*f6dc9357SAndroid Build Coastguard Worker       */
2070*f6dc9357SAndroid Build Coastguard Worker     }
2071*f6dc9357SAndroid Build Coastguard Worker 
2072*f6dc9357SAndroid Build Coastguard Worker     if (inArchive)
2073*f6dc9357SAndroid Build Coastguard Worker     {
2074*f6dc9357SAndroid Build Coastguard Worker       if (!inArchive->IsMultiVol && inArchive->ArcInfo.Base > 0 && !removeSfx)
2075*f6dc9357SAndroid Build Coastguard Worker       {
2076*f6dc9357SAndroid Build Coastguard Worker         IInStream *baseStream = inArchive->GetBaseStream();
2077*f6dc9357SAndroid Build Coastguard Worker         RINOK(InStream_SeekToBegin(baseStream))
2078*f6dc9357SAndroid Build Coastguard Worker         RINOK(NCompress::CopyStream_ExactSize(baseStream, seqOutStream, (UInt64)inArchive->ArcInfo.Base, NULL))
2079*f6dc9357SAndroid Build Coastguard Worker       }
2080*f6dc9357SAndroid Build Coastguard Worker     }
2081*f6dc9357SAndroid Build Coastguard Worker 
2082*f6dc9357SAndroid Build Coastguard Worker     outSeqMode = (outStreamReal == NULL);
2083*f6dc9357SAndroid Build Coastguard Worker     if (outSeqMode)
2084*f6dc9357SAndroid Build Coastguard Worker       setRestriction.Release();
2085*f6dc9357SAndroid Build Coastguard Worker     /* CCacheOutStream works as non-restricted by default.
2086*f6dc9357SAndroid Build Coastguard Worker        So we use (setRestriction == NULL) for outSeqMode */
2087*f6dc9357SAndroid Build Coastguard Worker     // bool use_cacheStream = true;
2088*f6dc9357SAndroid Build Coastguard Worker     // if (use_cacheStream)
2089*f6dc9357SAndroid Build Coastguard Worker     {
2090*f6dc9357SAndroid Build Coastguard Worker       cacheStream = new CCacheOutStream();
2091*f6dc9357SAndroid Build Coastguard Worker       outStream = cacheStream;
2092*f6dc9357SAndroid Build Coastguard Worker       if (!cacheStream->Allocate())
2093*f6dc9357SAndroid Build Coastguard Worker         return E_OUTOFMEMORY;
2094*f6dc9357SAndroid Build Coastguard Worker       RINOK(cacheStream->Init(seqOutStream, outStreamReal, setRestriction))
2095*f6dc9357SAndroid Build Coastguard Worker       setRestriction.Release();
2096*f6dc9357SAndroid Build Coastguard Worker       if (!outSeqMode)
2097*f6dc9357SAndroid Build Coastguard Worker         setRestriction = cacheStream;
2098*f6dc9357SAndroid Build Coastguard Worker     }
2099*f6dc9357SAndroid Build Coastguard Worker     /*
2100*f6dc9357SAndroid Build Coastguard Worker     else if (!outStreamReal)
2101*f6dc9357SAndroid Build Coastguard Worker     {
2102*f6dc9357SAndroid Build Coastguard Worker       CSeekOutStream *seekOutStream = new CSeekOutStream();
2103*f6dc9357SAndroid Build Coastguard Worker       outStream = seekOutStream;
2104*f6dc9357SAndroid Build Coastguard Worker       seekOutStream->Init(seqOutStream);
2105*f6dc9357SAndroid Build Coastguard Worker     }
2106*f6dc9357SAndroid Build Coastguard Worker     else
2107*f6dc9357SAndroid Build Coastguard Worker       outStream = outStreamReal;
2108*f6dc9357SAndroid Build Coastguard Worker     */
2109*f6dc9357SAndroid Build Coastguard Worker   }
2110*f6dc9357SAndroid Build Coastguard Worker 
2111*f6dc9357SAndroid Build Coastguard Worker   COutArchive outArchive;
2112*f6dc9357SAndroid Build Coastguard Worker   outArchive.SetRestriction = setRestriction;
2113*f6dc9357SAndroid Build Coastguard Worker 
2114*f6dc9357SAndroid Build Coastguard Worker   RINOK(outArchive.Create(outStream))
2115*f6dc9357SAndroid Build Coastguard Worker 
2116*f6dc9357SAndroid Build Coastguard Worker   if (inArchive)
2117*f6dc9357SAndroid Build Coastguard Worker   {
2118*f6dc9357SAndroid Build Coastguard Worker     if (!inArchive->IsMultiVol && (Int64)inArchive->ArcInfo.MarkerPos2 > inArchive->ArcInfo.Base)
2119*f6dc9357SAndroid Build Coastguard Worker     {
2120*f6dc9357SAndroid Build Coastguard Worker       IInStream *baseStream = inArchive->GetBaseStream();
2121*f6dc9357SAndroid Build Coastguard Worker       RINOK(InStream_SeekSet(baseStream, (UInt64)inArchive->ArcInfo.Base))
2122*f6dc9357SAndroid Build Coastguard Worker       const UInt64 embStubSize = (UInt64)((Int64)inArchive->ArcInfo.MarkerPos2 - inArchive->ArcInfo.Base);
2123*f6dc9357SAndroid Build Coastguard Worker       RINOK(NCompress::CopyStream_ExactSize(baseStream, outStream, embStubSize, NULL))
2124*f6dc9357SAndroid Build Coastguard Worker       outArchive.MoveCurPos(embStubSize);
2125*f6dc9357SAndroid Build Coastguard Worker     }
2126*f6dc9357SAndroid Build Coastguard Worker   }
2127*f6dc9357SAndroid Build Coastguard Worker 
2128*f6dc9357SAndroid Build Coastguard Worker   RINOK (Update2(
2129*f6dc9357SAndroid Build Coastguard Worker       EXTERNAL_CODECS_LOC_VARS
2130*f6dc9357SAndroid Build Coastguard Worker       outArchive, inArchive,
2131*f6dc9357SAndroid Build Coastguard Worker       inputItems, updateItems,
2132*f6dc9357SAndroid Build Coastguard Worker       updateOptions,
2133*f6dc9357SAndroid Build Coastguard Worker       compressionMethodMode, outSeqMode,
2134*f6dc9357SAndroid Build Coastguard Worker       inArchive ? &inArchive->ArcInfo.Comment : NULL,
2135*f6dc9357SAndroid Build Coastguard Worker       updateCallback))
2136*f6dc9357SAndroid Build Coastguard Worker 
2137*f6dc9357SAndroid Build Coastguard Worker   return cacheStream->FinalFlush();
2138*f6dc9357SAndroid Build Coastguard Worker }
2139*f6dc9357SAndroid Build Coastguard Worker 
2140*f6dc9357SAndroid Build Coastguard Worker }}
2141