1370b324cSopenharmony_ci// XzHandler.cpp
2370b324cSopenharmony_ci
3370b324cSopenharmony_ci#include "StdAfx.h"
4370b324cSopenharmony_ci
5370b324cSopenharmony_ci#include "../../../C/Alloc.h"
6370b324cSopenharmony_ci
7370b324cSopenharmony_ci#include "../../Common/ComTry.h"
8370b324cSopenharmony_ci#include "../../Common/Defs.h"
9370b324cSopenharmony_ci#include "../../Common/IntToString.h"
10370b324cSopenharmony_ci#include "../../Common/MyBuffer.h"
11370b324cSopenharmony_ci#include "../../Common/StringToInt.h"
12370b324cSopenharmony_ci
13370b324cSopenharmony_ci#include "../../Windows/PropVariant.h"
14370b324cSopenharmony_ci#include "../../Windows/System.h"
15370b324cSopenharmony_ci
16370b324cSopenharmony_ci#include "../Common/CWrappers.h"
17370b324cSopenharmony_ci#include "../Common/ProgressUtils.h"
18370b324cSopenharmony_ci#include "../Common/RegisterArc.h"
19370b324cSopenharmony_ci#include "../Common/StreamUtils.h"
20370b324cSopenharmony_ci
21370b324cSopenharmony_ci#include "../Compress/CopyCoder.h"
22370b324cSopenharmony_ci#include "../Compress/XzDecoder.h"
23370b324cSopenharmony_ci#include "../Compress/XzEncoder.h"
24370b324cSopenharmony_ci
25370b324cSopenharmony_ci#include "IArchive.h"
26370b324cSopenharmony_ci
27370b324cSopenharmony_ci#include "Common/HandlerOut.h"
28370b324cSopenharmony_ci
29370b324cSopenharmony_ciusing namespace NWindows;
30370b324cSopenharmony_ci
31370b324cSopenharmony_cinamespace NArchive {
32370b324cSopenharmony_cinamespace NXz {
33370b324cSopenharmony_ci
34370b324cSopenharmony_ci#define k_LZMA2_Name "LZMA2"
35370b324cSopenharmony_ci
36370b324cSopenharmony_ci
37370b324cSopenharmony_cistruct CBlockInfo
38370b324cSopenharmony_ci{
39370b324cSopenharmony_ci  unsigned StreamFlags;
40370b324cSopenharmony_ci  UInt64 PackPos;
41370b324cSopenharmony_ci  UInt64 PackSize; // pure value from Index record, it doesn't include pad zeros
42370b324cSopenharmony_ci  UInt64 UnpackPos;
43370b324cSopenharmony_ci};
44370b324cSopenharmony_ci
45370b324cSopenharmony_ci
46370b324cSopenharmony_ciZ7_class_CHandler_final:
47370b324cSopenharmony_ci  public IInArchive,
48370b324cSopenharmony_ci  public IArchiveOpenSeq,
49370b324cSopenharmony_ci  public IInArchiveGetStream,
50370b324cSopenharmony_ci  public ISetProperties,
51370b324cSopenharmony_ci #ifndef Z7_EXTRACT_ONLY
52370b324cSopenharmony_ci  public IOutArchive,
53370b324cSopenharmony_ci #endif
54370b324cSopenharmony_ci  public CMyUnknownImp,
55370b324cSopenharmony_ci #ifndef Z7_EXTRACT_ONLY
56370b324cSopenharmony_ci  public CMultiMethodProps
57370b324cSopenharmony_ci #else
58370b324cSopenharmony_ci  public CCommonMethodProps
59370b324cSopenharmony_ci #endif
60370b324cSopenharmony_ci{
61370b324cSopenharmony_ci  Z7_COM_QI_BEGIN2(IInArchive)
62370b324cSopenharmony_ci  Z7_COM_QI_ENTRY(IArchiveOpenSeq)
63370b324cSopenharmony_ci  Z7_COM_QI_ENTRY(IInArchiveGetStream)
64370b324cSopenharmony_ci  Z7_COM_QI_ENTRY(ISetProperties)
65370b324cSopenharmony_ci #ifndef Z7_EXTRACT_ONLY
66370b324cSopenharmony_ci  Z7_COM_QI_ENTRY(IOutArchive)
67370b324cSopenharmony_ci #endif
68370b324cSopenharmony_ci  Z7_COM_QI_END
69370b324cSopenharmony_ci  Z7_COM_ADDREF_RELEASE
70370b324cSopenharmony_ci
71370b324cSopenharmony_ci  Z7_IFACE_COM7_IMP(IInArchive)
72370b324cSopenharmony_ci  Z7_IFACE_COM7_IMP(IArchiveOpenSeq)
73370b324cSopenharmony_ci  Z7_IFACE_COM7_IMP(IInArchiveGetStream)
74370b324cSopenharmony_ci  Z7_IFACE_COM7_IMP(ISetProperties)
75370b324cSopenharmony_ci #ifndef Z7_EXTRACT_ONLY
76370b324cSopenharmony_ci  Z7_IFACE_COM7_IMP(IOutArchive)
77370b324cSopenharmony_ci #endif
78370b324cSopenharmony_ci
79370b324cSopenharmony_ci  CXzStatInfo _stat;    // it's stat from backward parsing
80370b324cSopenharmony_ci  CXzStatInfo _stat2;   // it's data from forward parsing, if the decoder was called
81370b324cSopenharmony_ci  SRes _stat2_decode_SRes;
82370b324cSopenharmony_ci  bool _stat_defined;
83370b324cSopenharmony_ci  bool _stat2_defined;
84370b324cSopenharmony_ci
85370b324cSopenharmony_ci  const CXzStatInfo *GetStat() const
86370b324cSopenharmony_ci  {
87370b324cSopenharmony_ci    if (_stat_defined) return &_stat;
88370b324cSopenharmony_ci    if (_stat2_defined) return &_stat2;
89370b324cSopenharmony_ci    return NULL;
90370b324cSopenharmony_ci  }
91370b324cSopenharmony_ci
92370b324cSopenharmony_ci  bool _isArc;
93370b324cSopenharmony_ci  bool _needSeekToStart;
94370b324cSopenharmony_ci  bool _firstBlockWasRead;
95370b324cSopenharmony_ci
96370b324cSopenharmony_ci  AString _methodsString;
97370b324cSopenharmony_ci
98370b324cSopenharmony_ci
99370b324cSopenharmony_ci  #ifndef Z7_EXTRACT_ONLY
100370b324cSopenharmony_ci
101370b324cSopenharmony_ci  UInt32 _filterId;
102370b324cSopenharmony_ci  UInt64 _numSolidBytes;
103370b324cSopenharmony_ci
104370b324cSopenharmony_ci  void InitXz()
105370b324cSopenharmony_ci  {
106370b324cSopenharmony_ci    _filterId = 0;
107370b324cSopenharmony_ci    _numSolidBytes = XZ_PROPS_BLOCK_SIZE_AUTO;
108370b324cSopenharmony_ci  }
109370b324cSopenharmony_ci
110370b324cSopenharmony_ci  #endif
111370b324cSopenharmony_ci
112370b324cSopenharmony_ci
113370b324cSopenharmony_ci  void Init()
114370b324cSopenharmony_ci  {
115370b324cSopenharmony_ci    #ifndef Z7_EXTRACT_ONLY
116370b324cSopenharmony_ci      InitXz();
117370b324cSopenharmony_ci      CMultiMethodProps::Init();
118370b324cSopenharmony_ci    #else
119370b324cSopenharmony_ci      CCommonMethodProps::InitCommon();
120370b324cSopenharmony_ci    #endif
121370b324cSopenharmony_ci  }
122370b324cSopenharmony_ci
123370b324cSopenharmony_ci  HRESULT SetProperty(const wchar_t *name, const PROPVARIANT &value);
124370b324cSopenharmony_ci
125370b324cSopenharmony_ci  HRESULT Open2(IInStream *inStream, /* UInt32 flags, */ IArchiveOpenCallback *callback);
126370b324cSopenharmony_ci
127370b324cSopenharmony_ci  HRESULT Decode(NCompress::NXz::CDecoder &decoder,
128370b324cSopenharmony_ci      ISequentialInStream *seqInStream,
129370b324cSopenharmony_ci      ISequentialOutStream *outStream,
130370b324cSopenharmony_ci      ICompressProgressInfo *progress)
131370b324cSopenharmony_ci  {
132370b324cSopenharmony_ci    #ifndef Z7_ST
133370b324cSopenharmony_ci    decoder._numThreads = _numThreads;
134370b324cSopenharmony_ci    #endif
135370b324cSopenharmony_ci    decoder._memUsage = _memUsage_Decompress;
136370b324cSopenharmony_ci
137370b324cSopenharmony_ci    HRESULT hres = decoder.Decode(seqInStream, outStream,
138370b324cSopenharmony_ci        NULL, // *outSizeLimit
139370b324cSopenharmony_ci        true, // finishStream
140370b324cSopenharmony_ci        progress);
141370b324cSopenharmony_ci
142370b324cSopenharmony_ci    if (decoder.MainDecodeSRes_wasUsed
143370b324cSopenharmony_ci        && decoder.MainDecodeSRes != SZ_ERROR_MEM
144370b324cSopenharmony_ci        && decoder.MainDecodeSRes != SZ_ERROR_UNSUPPORTED)
145370b324cSopenharmony_ci    {
146370b324cSopenharmony_ci      // if (!_stat2_defined)
147370b324cSopenharmony_ci      {
148370b324cSopenharmony_ci        _stat2_decode_SRes = decoder.MainDecodeSRes;
149370b324cSopenharmony_ci        _stat2 = decoder.Stat;
150370b324cSopenharmony_ci        _stat2_defined = true;
151370b324cSopenharmony_ci      }
152370b324cSopenharmony_ci    }
153370b324cSopenharmony_ci
154370b324cSopenharmony_ci    return hres;
155370b324cSopenharmony_ci  }
156370b324cSopenharmony_ci
157370b324cSopenharmony_cipublic:
158370b324cSopenharmony_ci  CBlockInfo *_blocks;
159370b324cSopenharmony_ci  size_t _blocksArraySize;
160370b324cSopenharmony_ci  UInt64 _maxBlocksSize;
161370b324cSopenharmony_ci  CMyComPtr<IInStream> _stream;
162370b324cSopenharmony_ci  CMyComPtr<ISequentialInStream> _seqStream;
163370b324cSopenharmony_ci
164370b324cSopenharmony_ci  CXzBlock _firstBlock;
165370b324cSopenharmony_ci
166370b324cSopenharmony_ci  CHandler();
167370b324cSopenharmony_ci  ~CHandler();
168370b324cSopenharmony_ci
169370b324cSopenharmony_ci  HRESULT SeekToPackPos(UInt64 pos)
170370b324cSopenharmony_ci  {
171370b324cSopenharmony_ci    return InStream_SeekSet(_stream, pos);
172370b324cSopenharmony_ci  }
173370b324cSopenharmony_ci};
174370b324cSopenharmony_ci
175370b324cSopenharmony_ci
176370b324cSopenharmony_ciCHandler::CHandler():
177370b324cSopenharmony_ci    _blocks(NULL),
178370b324cSopenharmony_ci    _blocksArraySize(0)
179370b324cSopenharmony_ci{
180370b324cSopenharmony_ci  #ifndef Z7_EXTRACT_ONLY
181370b324cSopenharmony_ci  InitXz();
182370b324cSopenharmony_ci  #endif
183370b324cSopenharmony_ci}
184370b324cSopenharmony_ci
185370b324cSopenharmony_ciCHandler::~CHandler()
186370b324cSopenharmony_ci{
187370b324cSopenharmony_ci  MyFree(_blocks);
188370b324cSopenharmony_ci}
189370b324cSopenharmony_ci
190370b324cSopenharmony_ci
191370b324cSopenharmony_cistatic const Byte kProps[] =
192370b324cSopenharmony_ci{
193370b324cSopenharmony_ci  kpidSize,
194370b324cSopenharmony_ci  kpidPackSize,
195370b324cSopenharmony_ci  kpidMethod
196370b324cSopenharmony_ci};
197370b324cSopenharmony_ci
198370b324cSopenharmony_cistatic const Byte kArcProps[] =
199370b324cSopenharmony_ci{
200370b324cSopenharmony_ci  kpidMethod,
201370b324cSopenharmony_ci  kpidNumStreams,
202370b324cSopenharmony_ci  kpidNumBlocks,
203370b324cSopenharmony_ci  kpidClusterSize,
204370b324cSopenharmony_ci  kpidCharacts
205370b324cSopenharmony_ci};
206370b324cSopenharmony_ci
207370b324cSopenharmony_ciIMP_IInArchive_Props
208370b324cSopenharmony_ciIMP_IInArchive_ArcProps
209370b324cSopenharmony_ci
210370b324cSopenharmony_cistatic inline char GetHex(unsigned value)
211370b324cSopenharmony_ci{
212370b324cSopenharmony_ci  return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10)));
213370b324cSopenharmony_ci}
214370b324cSopenharmony_ci
215370b324cSopenharmony_cistatic inline void AddHexToString(AString &s, Byte value)
216370b324cSopenharmony_ci{
217370b324cSopenharmony_ci  s += GetHex(value >> 4);
218370b324cSopenharmony_ci  s += GetHex(value & 0xF);
219370b324cSopenharmony_ci}
220370b324cSopenharmony_ci
221370b324cSopenharmony_cistatic void Lzma2PropToString(AString &s, unsigned prop)
222370b324cSopenharmony_ci{
223370b324cSopenharmony_ci  char c = 0;
224370b324cSopenharmony_ci  UInt32 size;
225370b324cSopenharmony_ci  if ((prop & 1) == 0)
226370b324cSopenharmony_ci    size = prop / 2 + 12;
227370b324cSopenharmony_ci  else
228370b324cSopenharmony_ci  {
229370b324cSopenharmony_ci    c = 'k';
230370b324cSopenharmony_ci    size = (UInt32)(2 | (prop & 1)) << (prop / 2 + 1);
231370b324cSopenharmony_ci    if (prop > 17)
232370b324cSopenharmony_ci    {
233370b324cSopenharmony_ci      size >>= 10;
234370b324cSopenharmony_ci      c = 'm';
235370b324cSopenharmony_ci    }
236370b324cSopenharmony_ci  }
237370b324cSopenharmony_ci  s.Add_UInt32(size);
238370b324cSopenharmony_ci  if (c != 0)
239370b324cSopenharmony_ci    s += c;
240370b324cSopenharmony_ci}
241370b324cSopenharmony_ci
242370b324cSopenharmony_cistruct CMethodNamePair
243370b324cSopenharmony_ci{
244370b324cSopenharmony_ci  UInt32 Id;
245370b324cSopenharmony_ci  const char *Name;
246370b324cSopenharmony_ci};
247370b324cSopenharmony_ci
248370b324cSopenharmony_cistatic const CMethodNamePair g_NamePairs[] =
249370b324cSopenharmony_ci{
250370b324cSopenharmony_ci  { XZ_ID_Subblock, "SB" },
251370b324cSopenharmony_ci  { XZ_ID_Delta, "Delta" },
252370b324cSopenharmony_ci  { XZ_ID_X86, "BCJ" },
253370b324cSopenharmony_ci  { XZ_ID_PPC, "PPC" },
254370b324cSopenharmony_ci  { XZ_ID_IA64, "IA64" },
255370b324cSopenharmony_ci  { XZ_ID_ARM, "ARM" },
256370b324cSopenharmony_ci  { XZ_ID_ARMT, "ARMT" },
257370b324cSopenharmony_ci  { XZ_ID_SPARC, "SPARC" },
258370b324cSopenharmony_ci  { XZ_ID_ARM64, "ARM64" },
259370b324cSopenharmony_ci  { XZ_ID_LZMA2, "LZMA2" }
260370b324cSopenharmony_ci};
261370b324cSopenharmony_ci
262370b324cSopenharmony_cistatic void AddMethodString(AString &s, const CXzFilter &f)
263370b324cSopenharmony_ci{
264370b324cSopenharmony_ci  const char *p = NULL;
265370b324cSopenharmony_ci  for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_NamePairs); i++)
266370b324cSopenharmony_ci    if (g_NamePairs[i].Id == f.id)
267370b324cSopenharmony_ci    {
268370b324cSopenharmony_ci      p = g_NamePairs[i].Name;
269370b324cSopenharmony_ci      break;
270370b324cSopenharmony_ci    }
271370b324cSopenharmony_ci  char temp[32];
272370b324cSopenharmony_ci  if (!p)
273370b324cSopenharmony_ci  {
274370b324cSopenharmony_ci    ::ConvertUInt64ToString(f.id, temp);
275370b324cSopenharmony_ci    p = temp;
276370b324cSopenharmony_ci  }
277370b324cSopenharmony_ci
278370b324cSopenharmony_ci  s += p;
279370b324cSopenharmony_ci
280370b324cSopenharmony_ci  if (f.propsSize > 0)
281370b324cSopenharmony_ci  {
282370b324cSopenharmony_ci    s += ':';
283370b324cSopenharmony_ci    if (f.id == XZ_ID_LZMA2 && f.propsSize == 1)
284370b324cSopenharmony_ci      Lzma2PropToString(s, f.props[0]);
285370b324cSopenharmony_ci    else if (f.id == XZ_ID_Delta && f.propsSize == 1)
286370b324cSopenharmony_ci      s.Add_UInt32((UInt32)f.props[0] + 1);
287370b324cSopenharmony_ci    else if (f.id == XZ_ID_ARM64 && f.propsSize == 1)
288370b324cSopenharmony_ci      s.Add_UInt32((UInt32)f.props[0] + 16 + 2);
289370b324cSopenharmony_ci    else
290370b324cSopenharmony_ci    {
291370b324cSopenharmony_ci      s += '[';
292370b324cSopenharmony_ci      for (UInt32 bi = 0; bi < f.propsSize; bi++)
293370b324cSopenharmony_ci        AddHexToString(s, f.props[bi]);
294370b324cSopenharmony_ci      s += ']';
295370b324cSopenharmony_ci    }
296370b324cSopenharmony_ci  }
297370b324cSopenharmony_ci}
298370b324cSopenharmony_ci
299370b324cSopenharmony_cistatic const char * const kChecks[] =
300370b324cSopenharmony_ci{
301370b324cSopenharmony_ci    "NoCheck"
302370b324cSopenharmony_ci  , "CRC32"
303370b324cSopenharmony_ci  , NULL
304370b324cSopenharmony_ci  , NULL
305370b324cSopenharmony_ci  , "CRC64"
306370b324cSopenharmony_ci  , NULL
307370b324cSopenharmony_ci  , NULL
308370b324cSopenharmony_ci  , NULL
309370b324cSopenharmony_ci  , NULL
310370b324cSopenharmony_ci  , NULL
311370b324cSopenharmony_ci  , "SHA256"
312370b324cSopenharmony_ci  , NULL
313370b324cSopenharmony_ci  , NULL
314370b324cSopenharmony_ci  , NULL
315370b324cSopenharmony_ci  , NULL
316370b324cSopenharmony_ci  , NULL
317370b324cSopenharmony_ci};
318370b324cSopenharmony_ci
319370b324cSopenharmony_cistatic void AddCheckString(AString &s, const CXzs &xzs)
320370b324cSopenharmony_ci{
321370b324cSopenharmony_ci  size_t i;
322370b324cSopenharmony_ci  UInt32 mask = 0;
323370b324cSopenharmony_ci  for (i = 0; i < xzs.num; i++)
324370b324cSopenharmony_ci    mask |= ((UInt32)1 << XzFlags_GetCheckType(xzs.streams[i].flags));
325370b324cSopenharmony_ci  for (i = 0; i <= XZ_CHECK_MASK; i++)
326370b324cSopenharmony_ci    if (((mask >> i) & 1) != 0)
327370b324cSopenharmony_ci    {
328370b324cSopenharmony_ci      s.Add_Space_if_NotEmpty();
329370b324cSopenharmony_ci      if (kChecks[i])
330370b324cSopenharmony_ci        s += kChecks[i];
331370b324cSopenharmony_ci      else
332370b324cSopenharmony_ci      {
333370b324cSopenharmony_ci        s += "Check-";
334370b324cSopenharmony_ci        s.Add_UInt32((UInt32)i);
335370b324cSopenharmony_ci      }
336370b324cSopenharmony_ci    }
337370b324cSopenharmony_ci}
338370b324cSopenharmony_ci
339370b324cSopenharmony_ciZ7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
340370b324cSopenharmony_ci{
341370b324cSopenharmony_ci  COM_TRY_BEGIN
342370b324cSopenharmony_ci  NCOM::CPropVariant prop;
343370b324cSopenharmony_ci
344370b324cSopenharmony_ci  const CXzStatInfo *stat = GetStat();
345370b324cSopenharmony_ci
346370b324cSopenharmony_ci  switch (propID)
347370b324cSopenharmony_ci  {
348370b324cSopenharmony_ci    case kpidPhySize: if (stat) prop = stat->InSize; break;
349370b324cSopenharmony_ci    case kpidNumStreams: if (stat && stat->NumStreams_Defined) prop = stat->NumStreams; break;
350370b324cSopenharmony_ci    case kpidNumBlocks: if (stat && stat->NumBlocks_Defined) prop = stat->NumBlocks; break;
351370b324cSopenharmony_ci    case kpidUnpackSize: if (stat && stat->UnpackSize_Defined) prop = stat->OutSize; break;
352370b324cSopenharmony_ci    case kpidClusterSize: if (_stat_defined && _stat.NumBlocks_Defined && stat->NumBlocks > 1) prop = _maxBlocksSize; break;
353370b324cSopenharmony_ci    case kpidCharacts:
354370b324cSopenharmony_ci      if (_firstBlockWasRead)
355370b324cSopenharmony_ci      {
356370b324cSopenharmony_ci        AString s;
357370b324cSopenharmony_ci        if (XzBlock_HasPackSize(&_firstBlock))
358370b324cSopenharmony_ci          s.Add_OptSpaced("BlockPackSize");
359370b324cSopenharmony_ci        if (XzBlock_HasUnpackSize(&_firstBlock))
360370b324cSopenharmony_ci          s.Add_OptSpaced("BlockUnpackSize");
361370b324cSopenharmony_ci        if (!s.IsEmpty())
362370b324cSopenharmony_ci          prop = s;
363370b324cSopenharmony_ci      }
364370b324cSopenharmony_ci      break;
365370b324cSopenharmony_ci
366370b324cSopenharmony_ci
367370b324cSopenharmony_ci    case kpidMethod: if (!_methodsString.IsEmpty()) prop = _methodsString; break;
368370b324cSopenharmony_ci    case kpidErrorFlags:
369370b324cSopenharmony_ci    {
370370b324cSopenharmony_ci      UInt32 v = 0;
371370b324cSopenharmony_ci      SRes sres = _stat2_decode_SRes;
372370b324cSopenharmony_ci      if (!_isArc)                      v |= kpv_ErrorFlags_IsNotArc;
373370b324cSopenharmony_ci      if (sres == SZ_ERROR_INPUT_EOF)   v |= kpv_ErrorFlags_UnexpectedEnd;
374370b324cSopenharmony_ci      if (_stat2_defined && _stat2.DataAfterEnd) v |= kpv_ErrorFlags_DataAfterEnd;
375370b324cSopenharmony_ci      if (sres == SZ_ERROR_ARCHIVE)     v |= kpv_ErrorFlags_HeadersError;
376370b324cSopenharmony_ci      if (sres == SZ_ERROR_UNSUPPORTED) v |= kpv_ErrorFlags_UnsupportedMethod;
377370b324cSopenharmony_ci      if (sres == SZ_ERROR_DATA)        v |= kpv_ErrorFlags_DataError;
378370b324cSopenharmony_ci      if (sres == SZ_ERROR_CRC)         v |= kpv_ErrorFlags_CrcError;
379370b324cSopenharmony_ci      if (v != 0)
380370b324cSopenharmony_ci        prop = v;
381370b324cSopenharmony_ci      break;
382370b324cSopenharmony_ci    }
383370b324cSopenharmony_ci
384370b324cSopenharmony_ci    case kpidMainSubfile:
385370b324cSopenharmony_ci    {
386370b324cSopenharmony_ci      // debug only, comment it:
387370b324cSopenharmony_ci      // if (_blocks) prop = (UInt32)0;
388370b324cSopenharmony_ci      break;
389370b324cSopenharmony_ci    }
390370b324cSopenharmony_ci  }
391370b324cSopenharmony_ci  prop.Detach(value);
392370b324cSopenharmony_ci  return S_OK;
393370b324cSopenharmony_ci  COM_TRY_END
394370b324cSopenharmony_ci}
395370b324cSopenharmony_ci
396370b324cSopenharmony_ciZ7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
397370b324cSopenharmony_ci{
398370b324cSopenharmony_ci  *numItems = 1;
399370b324cSopenharmony_ci  return S_OK;
400370b324cSopenharmony_ci}
401370b324cSopenharmony_ci
402370b324cSopenharmony_ciZ7_COM7F_IMF(CHandler::GetProperty(UInt32, PROPID propID, PROPVARIANT *value))
403370b324cSopenharmony_ci{
404370b324cSopenharmony_ci  COM_TRY_BEGIN
405370b324cSopenharmony_ci  const CXzStatInfo *stat = GetStat();
406370b324cSopenharmony_ci  NCOM::CPropVariant prop;
407370b324cSopenharmony_ci  switch (propID)
408370b324cSopenharmony_ci  {
409370b324cSopenharmony_ci    case kpidSize: if (stat && stat->UnpackSize_Defined) prop = stat->OutSize; break;
410370b324cSopenharmony_ci    case kpidPackSize: if (stat) prop = stat->InSize; break;
411370b324cSopenharmony_ci    case kpidMethod: if (!_methodsString.IsEmpty()) prop = _methodsString; break;
412370b324cSopenharmony_ci  }
413370b324cSopenharmony_ci  prop.Detach(value);
414370b324cSopenharmony_ci  return S_OK;
415370b324cSopenharmony_ci  COM_TRY_END
416370b324cSopenharmony_ci}
417370b324cSopenharmony_ci
418370b324cSopenharmony_ci
419370b324cSopenharmony_cistruct COpenCallbackWrap
420370b324cSopenharmony_ci{
421370b324cSopenharmony_ci  ICompressProgress vt;
422370b324cSopenharmony_ci  IArchiveOpenCallback *OpenCallback;
423370b324cSopenharmony_ci  HRESULT Res;
424370b324cSopenharmony_ci
425370b324cSopenharmony_ci  // new clang shows "non-POD" warning for offsetof(), if we use constructor instead of Init()
426370b324cSopenharmony_ci  void Init(IArchiveOpenCallback *progress);
427370b324cSopenharmony_ci};
428370b324cSopenharmony_ci
429370b324cSopenharmony_cistatic SRes OpenCallbackProgress(ICompressProgressPtr pp, UInt64 inSize, UInt64 /* outSize */)
430370b324cSopenharmony_ci{
431370b324cSopenharmony_ci  Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(COpenCallbackWrap)
432370b324cSopenharmony_ci  if (p->OpenCallback)
433370b324cSopenharmony_ci    p->Res = p->OpenCallback->SetCompleted(NULL, &inSize);
434370b324cSopenharmony_ci  return HRESULT_To_SRes(p->Res, SZ_ERROR_PROGRESS);
435370b324cSopenharmony_ci}
436370b324cSopenharmony_ci
437370b324cSopenharmony_civoid COpenCallbackWrap::Init(IArchiveOpenCallback *callback)
438370b324cSopenharmony_ci{
439370b324cSopenharmony_ci  vt.Progress = OpenCallbackProgress;
440370b324cSopenharmony_ci  OpenCallback = callback;
441370b324cSopenharmony_ci  Res = SZ_OK;
442370b324cSopenharmony_ci}
443370b324cSopenharmony_ci
444370b324cSopenharmony_ci
445370b324cSopenharmony_cistruct CXzsCPP
446370b324cSopenharmony_ci{
447370b324cSopenharmony_ci  CXzs p;
448370b324cSopenharmony_ci  CXzsCPP() { Xzs_Construct(&p); }
449370b324cSopenharmony_ci  ~CXzsCPP() { Xzs_Free(&p, &g_Alloc); }
450370b324cSopenharmony_ci};
451370b324cSopenharmony_ci
452370b324cSopenharmony_ci#define kInputBufSize ((size_t)1 << 10)
453370b324cSopenharmony_ci
454370b324cSopenharmony_cistruct CLookToRead2_CPP: public CLookToRead2
455370b324cSopenharmony_ci{
456370b324cSopenharmony_ci  CLookToRead2_CPP()
457370b324cSopenharmony_ci  {
458370b324cSopenharmony_ci    buf = NULL;
459370b324cSopenharmony_ci    LookToRead2_CreateVTable(this,
460370b324cSopenharmony_ci        True // Lookahead ?
461370b324cSopenharmony_ci        );
462370b324cSopenharmony_ci  }
463370b324cSopenharmony_ci  void Alloc(size_t allocSize)
464370b324cSopenharmony_ci  {
465370b324cSopenharmony_ci    buf = (Byte *)MyAlloc(allocSize);
466370b324cSopenharmony_ci    if (buf)
467370b324cSopenharmony_ci      this->bufSize = allocSize;
468370b324cSopenharmony_ci  }
469370b324cSopenharmony_ci  ~CLookToRead2_CPP()
470370b324cSopenharmony_ci  {
471370b324cSopenharmony_ci    MyFree(buf);
472370b324cSopenharmony_ci  }
473370b324cSopenharmony_ci};
474370b324cSopenharmony_ci
475370b324cSopenharmony_ci
476370b324cSopenharmony_cistatic HRESULT SRes_to_Open_HRESULT(SRes res)
477370b324cSopenharmony_ci{
478370b324cSopenharmony_ci  switch (res)
479370b324cSopenharmony_ci  {
480370b324cSopenharmony_ci    case SZ_OK: return S_OK;
481370b324cSopenharmony_ci    case SZ_ERROR_MEM: return E_OUTOFMEMORY;
482370b324cSopenharmony_ci    case SZ_ERROR_PROGRESS: return E_ABORT;
483370b324cSopenharmony_ci    /*
484370b324cSopenharmony_ci    case SZ_ERROR_UNSUPPORTED:
485370b324cSopenharmony_ci    case SZ_ERROR_CRC:
486370b324cSopenharmony_ci    case SZ_ERROR_DATA:
487370b324cSopenharmony_ci    case SZ_ERROR_ARCHIVE:
488370b324cSopenharmony_ci    case SZ_ERROR_NO_ARCHIVE:
489370b324cSopenharmony_ci      return S_FALSE;
490370b324cSopenharmony_ci    */
491370b324cSopenharmony_ci  }
492370b324cSopenharmony_ci  return S_FALSE;
493370b324cSopenharmony_ci}
494370b324cSopenharmony_ci
495370b324cSopenharmony_ci
496370b324cSopenharmony_ci
497370b324cSopenharmony_ciHRESULT CHandler::Open2(IInStream *inStream, /* UInt32 flags, */ IArchiveOpenCallback *callback)
498370b324cSopenharmony_ci{
499370b324cSopenharmony_ci  _needSeekToStart = true;
500370b324cSopenharmony_ci
501370b324cSopenharmony_ci  {
502370b324cSopenharmony_ci    CXzStreamFlags st;
503370b324cSopenharmony_ci    CSeqInStreamWrap inStreamWrap;
504370b324cSopenharmony_ci
505370b324cSopenharmony_ci    inStreamWrap.Init(inStream);
506370b324cSopenharmony_ci
507370b324cSopenharmony_ci    SRes res = Xz_ReadHeader(&st, &inStreamWrap.vt);
508370b324cSopenharmony_ci
509370b324cSopenharmony_ci    if (inStreamWrap.Res != S_OK)
510370b324cSopenharmony_ci      return inStreamWrap.Res;
511370b324cSopenharmony_ci    if (res != SZ_OK)
512370b324cSopenharmony_ci      return SRes_to_Open_HRESULT(res);
513370b324cSopenharmony_ci
514370b324cSopenharmony_ci    {
515370b324cSopenharmony_ci      CXzBlock block;
516370b324cSopenharmony_ci      BoolInt isIndex;
517370b324cSopenharmony_ci      UInt32 headerSizeRes;
518370b324cSopenharmony_ci
519370b324cSopenharmony_ci      SRes res2 = XzBlock_ReadHeader(&block, &inStreamWrap.vt, &isIndex, &headerSizeRes);
520370b324cSopenharmony_ci
521370b324cSopenharmony_ci      if (inStreamWrap.Res != S_OK)
522370b324cSopenharmony_ci        return inStreamWrap.Res;
523370b324cSopenharmony_ci
524370b324cSopenharmony_ci      if (res2 != SZ_OK)
525370b324cSopenharmony_ci      {
526370b324cSopenharmony_ci        if (res2 == SZ_ERROR_INPUT_EOF)
527370b324cSopenharmony_ci        {
528370b324cSopenharmony_ci          _stat2_decode_SRes = res2;
529370b324cSopenharmony_ci          _stream = inStream;
530370b324cSopenharmony_ci          _seqStream = inStream;
531370b324cSopenharmony_ci          _isArc = true;
532370b324cSopenharmony_ci          return S_OK;
533370b324cSopenharmony_ci        }
534370b324cSopenharmony_ci
535370b324cSopenharmony_ci        if (res2 == SZ_ERROR_ARCHIVE)
536370b324cSopenharmony_ci          return S_FALSE;
537370b324cSopenharmony_ci      }
538370b324cSopenharmony_ci      else if (!isIndex)
539370b324cSopenharmony_ci      {
540370b324cSopenharmony_ci        _firstBlockWasRead = true;
541370b324cSopenharmony_ci        _firstBlock = block;
542370b324cSopenharmony_ci
543370b324cSopenharmony_ci        unsigned numFilters = XzBlock_GetNumFilters(&block);
544370b324cSopenharmony_ci        for (unsigned i = 0; i < numFilters; i++)
545370b324cSopenharmony_ci        {
546370b324cSopenharmony_ci          _methodsString.Add_Space_if_NotEmpty();
547370b324cSopenharmony_ci          AddMethodString(_methodsString, block.filters[i]);
548370b324cSopenharmony_ci        }
549370b324cSopenharmony_ci      }
550370b324cSopenharmony_ci    }
551370b324cSopenharmony_ci  }
552370b324cSopenharmony_ci
553370b324cSopenharmony_ci  RINOK(InStream_GetSize_SeekToEnd(inStream, _stat.InSize))
554370b324cSopenharmony_ci  if (callback)
555370b324cSopenharmony_ci  {
556370b324cSopenharmony_ci    RINOK(callback->SetTotal(NULL, &_stat.InSize))
557370b324cSopenharmony_ci  }
558370b324cSopenharmony_ci
559370b324cSopenharmony_ci  CSeekInStreamWrap inStreamImp;
560370b324cSopenharmony_ci
561370b324cSopenharmony_ci  inStreamImp.Init(inStream);
562370b324cSopenharmony_ci
563370b324cSopenharmony_ci  CLookToRead2_CPP lookStream;
564370b324cSopenharmony_ci
565370b324cSopenharmony_ci  lookStream.Alloc(kInputBufSize);
566370b324cSopenharmony_ci
567370b324cSopenharmony_ci  if (!lookStream.buf)
568370b324cSopenharmony_ci    return E_OUTOFMEMORY;
569370b324cSopenharmony_ci
570370b324cSopenharmony_ci  lookStream.realStream = &inStreamImp.vt;
571370b324cSopenharmony_ci  LookToRead2_INIT(&lookStream)
572370b324cSopenharmony_ci
573370b324cSopenharmony_ci  COpenCallbackWrap openWrap;
574370b324cSopenharmony_ci  openWrap.Init(callback);
575370b324cSopenharmony_ci
576370b324cSopenharmony_ci  CXzsCPP xzs;
577370b324cSopenharmony_ci  Int64 startPosition;
578370b324cSopenharmony_ci  SRes res = Xzs_ReadBackward(&xzs.p, &lookStream.vt, &startPosition, &openWrap.vt, &g_Alloc);
579370b324cSopenharmony_ci  if (res == SZ_ERROR_PROGRESS)
580370b324cSopenharmony_ci    return (openWrap.Res == S_OK) ? E_FAIL : openWrap.Res;
581370b324cSopenharmony_ci  /*
582370b324cSopenharmony_ci  if (res == SZ_ERROR_NO_ARCHIVE && xzs.p.num > 0)
583370b324cSopenharmony_ci    res = SZ_OK;
584370b324cSopenharmony_ci  */
585370b324cSopenharmony_ci  if (res == SZ_OK && startPosition == 0)
586370b324cSopenharmony_ci  {
587370b324cSopenharmony_ci    _stat_defined = true;
588370b324cSopenharmony_ci
589370b324cSopenharmony_ci    _stat.OutSize = Xzs_GetUnpackSize(&xzs.p);
590370b324cSopenharmony_ci    _stat.UnpackSize_Defined = true;
591370b324cSopenharmony_ci
592370b324cSopenharmony_ci    _stat.NumStreams = xzs.p.num;
593370b324cSopenharmony_ci    _stat.NumStreams_Defined = true;
594370b324cSopenharmony_ci
595370b324cSopenharmony_ci    _stat.NumBlocks = Xzs_GetNumBlocks(&xzs.p);
596370b324cSopenharmony_ci    _stat.NumBlocks_Defined = true;
597370b324cSopenharmony_ci
598370b324cSopenharmony_ci    AddCheckString(_methodsString, xzs.p);
599370b324cSopenharmony_ci
600370b324cSopenharmony_ci    const size_t numBlocks = (size_t)_stat.NumBlocks + 1;
601370b324cSopenharmony_ci    const size_t bytesAlloc = numBlocks * sizeof(CBlockInfo);
602370b324cSopenharmony_ci
603370b324cSopenharmony_ci    if (bytesAlloc / sizeof(CBlockInfo) == _stat.NumBlocks + 1)
604370b324cSopenharmony_ci    {
605370b324cSopenharmony_ci      _blocks = (CBlockInfo *)MyAlloc(bytesAlloc);
606370b324cSopenharmony_ci      if (_blocks)
607370b324cSopenharmony_ci      {
608370b324cSopenharmony_ci        unsigned blockIndex = 0;
609370b324cSopenharmony_ci        UInt64 unpackPos = 0;
610370b324cSopenharmony_ci
611370b324cSopenharmony_ci        for (size_t si = xzs.p.num; si != 0;)
612370b324cSopenharmony_ci        {
613370b324cSopenharmony_ci          si--;
614370b324cSopenharmony_ci          const CXzStream &str = xzs.p.streams[si];
615370b324cSopenharmony_ci          UInt64 packPos = str.startOffset + XZ_STREAM_HEADER_SIZE;
616370b324cSopenharmony_ci
617370b324cSopenharmony_ci          for (size_t bi = 0; bi < str.numBlocks; bi++)
618370b324cSopenharmony_ci          {
619370b324cSopenharmony_ci            const CXzBlockSizes &bs = str.blocks[bi];
620370b324cSopenharmony_ci            const UInt64 packSizeAligned = bs.totalSize + ((0 - (unsigned)bs.totalSize) & 3);
621370b324cSopenharmony_ci
622370b324cSopenharmony_ci            if (bs.unpackSize != 0)
623370b324cSopenharmony_ci            {
624370b324cSopenharmony_ci              if (blockIndex >= _stat.NumBlocks)
625370b324cSopenharmony_ci                return E_FAIL;
626370b324cSopenharmony_ci
627370b324cSopenharmony_ci              CBlockInfo &block = _blocks[blockIndex++];
628370b324cSopenharmony_ci              block.StreamFlags = str.flags;
629370b324cSopenharmony_ci              block.PackSize = bs.totalSize; // packSizeAligned;
630370b324cSopenharmony_ci              block.PackPos = packPos;
631370b324cSopenharmony_ci              block.UnpackPos = unpackPos;
632370b324cSopenharmony_ci            }
633370b324cSopenharmony_ci            packPos += packSizeAligned;
634370b324cSopenharmony_ci            unpackPos += bs.unpackSize;
635370b324cSopenharmony_ci            if (_maxBlocksSize < bs.unpackSize)
636370b324cSopenharmony_ci              _maxBlocksSize = bs.unpackSize;
637370b324cSopenharmony_ci          }
638370b324cSopenharmony_ci        }
639370b324cSopenharmony_ci
640370b324cSopenharmony_ci        /*
641370b324cSopenharmony_ci        if (blockIndex != _stat.NumBlocks)
642370b324cSopenharmony_ci        {
643370b324cSopenharmony_ci          // there are Empty blocks;
644370b324cSopenharmony_ci        }
645370b324cSopenharmony_ci        */
646370b324cSopenharmony_ci        if (_stat.OutSize != unpackPos)
647370b324cSopenharmony_ci          return E_FAIL;
648370b324cSopenharmony_ci        CBlockInfo &block = _blocks[blockIndex++];
649370b324cSopenharmony_ci        block.StreamFlags = 0;
650370b324cSopenharmony_ci        block.PackSize = 0;
651370b324cSopenharmony_ci        block.PackPos = 0;
652370b324cSopenharmony_ci        block.UnpackPos = unpackPos;
653370b324cSopenharmony_ci        _blocksArraySize = blockIndex;
654370b324cSopenharmony_ci      }
655370b324cSopenharmony_ci    }
656370b324cSopenharmony_ci  }
657370b324cSopenharmony_ci  else
658370b324cSopenharmony_ci  {
659370b324cSopenharmony_ci    res = SZ_OK;
660370b324cSopenharmony_ci  }
661370b324cSopenharmony_ci
662370b324cSopenharmony_ci  RINOK(SRes_to_Open_HRESULT(res))
663370b324cSopenharmony_ci
664370b324cSopenharmony_ci  _stream = inStream;
665370b324cSopenharmony_ci  _seqStream = inStream;
666370b324cSopenharmony_ci  _isArc = true;
667370b324cSopenharmony_ci  return S_OK;
668370b324cSopenharmony_ci}
669370b324cSopenharmony_ci
670370b324cSopenharmony_ci
671370b324cSopenharmony_ci
672370b324cSopenharmony_ciZ7_COM7F_IMF(CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *callback))
673370b324cSopenharmony_ci{
674370b324cSopenharmony_ci  COM_TRY_BEGIN
675370b324cSopenharmony_ci  {
676370b324cSopenharmony_ci    Close();
677370b324cSopenharmony_ci    return Open2(inStream, callback);
678370b324cSopenharmony_ci  }
679370b324cSopenharmony_ci  COM_TRY_END
680370b324cSopenharmony_ci}
681370b324cSopenharmony_ci
682370b324cSopenharmony_ciZ7_COM7F_IMF(CHandler::OpenSeq(ISequentialInStream *stream))
683370b324cSopenharmony_ci{
684370b324cSopenharmony_ci  Close();
685370b324cSopenharmony_ci  _seqStream = stream;
686370b324cSopenharmony_ci  _isArc = true;
687370b324cSopenharmony_ci  _needSeekToStart = false;
688370b324cSopenharmony_ci  return S_OK;
689370b324cSopenharmony_ci}
690370b324cSopenharmony_ci
691370b324cSopenharmony_ciZ7_COM7F_IMF(CHandler::Close())
692370b324cSopenharmony_ci{
693370b324cSopenharmony_ci  XzStatInfo_Clear(&_stat);
694370b324cSopenharmony_ci  XzStatInfo_Clear(&_stat2);
695370b324cSopenharmony_ci  _stat_defined = false;
696370b324cSopenharmony_ci  _stat2_defined = false;
697370b324cSopenharmony_ci  _stat2_decode_SRes = SZ_OK;
698370b324cSopenharmony_ci
699370b324cSopenharmony_ci  _isArc = false;
700370b324cSopenharmony_ci  _needSeekToStart = false;
701370b324cSopenharmony_ci  _firstBlockWasRead = false;
702370b324cSopenharmony_ci
703370b324cSopenharmony_ci   _methodsString.Empty();
704370b324cSopenharmony_ci  _stream.Release();
705370b324cSopenharmony_ci  _seqStream.Release();
706370b324cSopenharmony_ci
707370b324cSopenharmony_ci  MyFree(_blocks);
708370b324cSopenharmony_ci  _blocks = NULL;
709370b324cSopenharmony_ci  _blocksArraySize = 0;
710370b324cSopenharmony_ci  _maxBlocksSize = 0;
711370b324cSopenharmony_ci
712370b324cSopenharmony_ci  return S_OK;
713370b324cSopenharmony_ci}
714370b324cSopenharmony_ci
715370b324cSopenharmony_ci
716370b324cSopenharmony_cistruct CXzUnpackerCPP2
717370b324cSopenharmony_ci{
718370b324cSopenharmony_ci  Byte *InBuf;
719370b324cSopenharmony_ci  // Byte *OutBuf;
720370b324cSopenharmony_ci  CXzUnpacker p;
721370b324cSopenharmony_ci
722370b324cSopenharmony_ci  CXzUnpackerCPP2();
723370b324cSopenharmony_ci  ~CXzUnpackerCPP2();
724370b324cSopenharmony_ci};
725370b324cSopenharmony_ci
726370b324cSopenharmony_ciCXzUnpackerCPP2::CXzUnpackerCPP2(): InBuf(NULL)
727370b324cSopenharmony_ci  // , OutBuf(NULL)
728370b324cSopenharmony_ci{
729370b324cSopenharmony_ci  XzUnpacker_Construct(&p, &g_Alloc);
730370b324cSopenharmony_ci}
731370b324cSopenharmony_ci
732370b324cSopenharmony_ciCXzUnpackerCPP2::~CXzUnpackerCPP2()
733370b324cSopenharmony_ci{
734370b324cSopenharmony_ci  XzUnpacker_Free(&p);
735370b324cSopenharmony_ci  MidFree(InBuf);
736370b324cSopenharmony_ci  // MidFree(OutBuf);
737370b324cSopenharmony_ci}
738370b324cSopenharmony_ci
739370b324cSopenharmony_ci
740370b324cSopenharmony_ciZ7_CLASS_IMP_COM_1(
741370b324cSopenharmony_ci  CInStream
742370b324cSopenharmony_ci  , IInStream
743370b324cSopenharmony_ci)
744370b324cSopenharmony_ci  Z7_IFACE_COM7_IMP(ISequentialInStream)
745370b324cSopenharmony_ci
746370b324cSopenharmony_ci  UInt64 _virtPos;
747370b324cSopenharmony_cipublic:
748370b324cSopenharmony_ci  UInt64 Size;
749370b324cSopenharmony_ci  UInt64 _cacheStartPos;
750370b324cSopenharmony_ci  size_t _cacheSize;
751370b324cSopenharmony_ci  CByteBuffer _cache;
752370b324cSopenharmony_ci  // UInt64 _startPos;
753370b324cSopenharmony_ci  CXzUnpackerCPP2 xz;
754370b324cSopenharmony_ci
755370b324cSopenharmony_ci  void InitAndSeek()
756370b324cSopenharmony_ci  {
757370b324cSopenharmony_ci    _virtPos = 0;
758370b324cSopenharmony_ci    _cacheStartPos = 0;
759370b324cSopenharmony_ci    _cacheSize = 0;
760370b324cSopenharmony_ci    // _startPos = startPos;
761370b324cSopenharmony_ci  }
762370b324cSopenharmony_ci
763370b324cSopenharmony_ci  CHandler *_handlerSpec;
764370b324cSopenharmony_ci  CMyComPtr<IUnknown> _handler;
765370b324cSopenharmony_ci
766370b324cSopenharmony_ci  // ~CInStream();
767370b324cSopenharmony_ci};
768370b324cSopenharmony_ci
769370b324cSopenharmony_ci/*
770370b324cSopenharmony_ciCInStream::~CInStream()
771370b324cSopenharmony_ci{
772370b324cSopenharmony_ci  // _cache.Free();
773370b324cSopenharmony_ci}
774370b324cSopenharmony_ci*/
775370b324cSopenharmony_ci
776370b324cSopenharmony_cistatic size_t FindBlock(const CBlockInfo *blocks, size_t numBlocks, UInt64 pos)
777370b324cSopenharmony_ci{
778370b324cSopenharmony_ci  size_t left = 0, right = numBlocks;
779370b324cSopenharmony_ci  for (;;)
780370b324cSopenharmony_ci  {
781370b324cSopenharmony_ci    size_t mid = (left + right) / 2;
782370b324cSopenharmony_ci    if (mid == left)
783370b324cSopenharmony_ci      return left;
784370b324cSopenharmony_ci    if (pos < blocks[mid].UnpackPos)
785370b324cSopenharmony_ci      right = mid;
786370b324cSopenharmony_ci    else
787370b324cSopenharmony_ci      left = mid;
788370b324cSopenharmony_ci  }
789370b324cSopenharmony_ci}
790370b324cSopenharmony_ci
791370b324cSopenharmony_ci
792370b324cSopenharmony_ci
793370b324cSopenharmony_cistatic HRESULT DecodeBlock(CXzUnpackerCPP2 &xzu,
794370b324cSopenharmony_ci    ISequentialInStream *seqInStream,
795370b324cSopenharmony_ci    unsigned streamFlags,
796370b324cSopenharmony_ci    UInt64 packSize, // pure size from Index record, it doesn't include pad zeros
797370b324cSopenharmony_ci    size_t unpackSize, Byte *dest
798370b324cSopenharmony_ci    // , ICompressProgressInfo *progress
799370b324cSopenharmony_ci    )
800370b324cSopenharmony_ci{
801370b324cSopenharmony_ci  const size_t kInBufSize = (size_t)1 << 16;
802370b324cSopenharmony_ci
803370b324cSopenharmony_ci  XzUnpacker_Init(&xzu.p);
804370b324cSopenharmony_ci
805370b324cSopenharmony_ci  if (!xzu.InBuf)
806370b324cSopenharmony_ci  {
807370b324cSopenharmony_ci    xzu.InBuf = (Byte *)MidAlloc(kInBufSize);
808370b324cSopenharmony_ci    if (!xzu.InBuf)
809370b324cSopenharmony_ci      return E_OUTOFMEMORY;
810370b324cSopenharmony_ci  }
811370b324cSopenharmony_ci
812370b324cSopenharmony_ci  xzu.p.streamFlags = (UInt16)streamFlags;
813370b324cSopenharmony_ci  XzUnpacker_PrepareToRandomBlockDecoding(&xzu.p);
814370b324cSopenharmony_ci
815370b324cSopenharmony_ci  XzUnpacker_SetOutBuf(&xzu.p, dest, unpackSize);
816370b324cSopenharmony_ci
817370b324cSopenharmony_ci  const UInt64 packSizeAligned = packSize + ((0 - (unsigned)packSize) & 3);
818370b324cSopenharmony_ci  UInt64 packRem = packSizeAligned;
819370b324cSopenharmony_ci
820370b324cSopenharmony_ci  UInt32 inSize = 0;
821370b324cSopenharmony_ci  SizeT inPos = 0;
822370b324cSopenharmony_ci  SizeT outPos = 0;
823370b324cSopenharmony_ci
824370b324cSopenharmony_ci  HRESULT readRes = S_OK;
825370b324cSopenharmony_ci
826370b324cSopenharmony_ci  for (;;)
827370b324cSopenharmony_ci  {
828370b324cSopenharmony_ci    if (inPos == inSize && readRes == S_OK)
829370b324cSopenharmony_ci    {
830370b324cSopenharmony_ci      inPos = 0;
831370b324cSopenharmony_ci      inSize = 0;
832370b324cSopenharmony_ci      UInt32 rem = kInBufSize;
833370b324cSopenharmony_ci      if (rem > packRem)
834370b324cSopenharmony_ci        rem = (UInt32)packRem;
835370b324cSopenharmony_ci      if (rem != 0)
836370b324cSopenharmony_ci        readRes = seqInStream->Read(xzu.InBuf, rem, &inSize);
837370b324cSopenharmony_ci    }
838370b324cSopenharmony_ci
839370b324cSopenharmony_ci    SizeT inLen = inSize - inPos;
840370b324cSopenharmony_ci    SizeT outLen = unpackSize - outPos;
841370b324cSopenharmony_ci
842370b324cSopenharmony_ci    ECoderStatus status;
843370b324cSopenharmony_ci
844370b324cSopenharmony_ci    const SRes res = XzUnpacker_Code(&xzu.p,
845370b324cSopenharmony_ci        // dest + outPos,
846370b324cSopenharmony_ci        NULL,
847370b324cSopenharmony_ci        &outLen,
848370b324cSopenharmony_ci        xzu.InBuf + inPos, &inLen,
849370b324cSopenharmony_ci        (inLen == 0), // srcFinished
850370b324cSopenharmony_ci        CODER_FINISH_END, &status);
851370b324cSopenharmony_ci
852370b324cSopenharmony_ci    // return E_OUTOFMEMORY;
853370b324cSopenharmony_ci    // res = SZ_ERROR_CRC;
854370b324cSopenharmony_ci
855370b324cSopenharmony_ci    if (res != SZ_OK)
856370b324cSopenharmony_ci    {
857370b324cSopenharmony_ci      if (res == SZ_ERROR_CRC)
858370b324cSopenharmony_ci        return S_FALSE;
859370b324cSopenharmony_ci      return SResToHRESULT(res);
860370b324cSopenharmony_ci    }
861370b324cSopenharmony_ci
862370b324cSopenharmony_ci    inPos += inLen;
863370b324cSopenharmony_ci    outPos += outLen;
864370b324cSopenharmony_ci
865370b324cSopenharmony_ci    packRem -= inLen;
866370b324cSopenharmony_ci
867370b324cSopenharmony_ci    const BoolInt blockFinished = XzUnpacker_IsBlockFinished(&xzu.p);
868370b324cSopenharmony_ci
869370b324cSopenharmony_ci    if ((inLen == 0 && outLen == 0) || blockFinished)
870370b324cSopenharmony_ci    {
871370b324cSopenharmony_ci      if (packRem != 0 || !blockFinished || unpackSize != outPos)
872370b324cSopenharmony_ci        return S_FALSE;
873370b324cSopenharmony_ci      if (XzUnpacker_GetPackSizeForIndex(&xzu.p) != packSize)
874370b324cSopenharmony_ci        return S_FALSE;
875370b324cSopenharmony_ci      return S_OK;
876370b324cSopenharmony_ci    }
877370b324cSopenharmony_ci  }
878370b324cSopenharmony_ci}
879370b324cSopenharmony_ci
880370b324cSopenharmony_ci
881370b324cSopenharmony_ciZ7_COM7F_IMF(CInStream::Read(void *data, UInt32 size, UInt32 *processedSize))
882370b324cSopenharmony_ci{
883370b324cSopenharmony_ci  COM_TRY_BEGIN
884370b324cSopenharmony_ci
885370b324cSopenharmony_ci  if (processedSize)
886370b324cSopenharmony_ci    *processedSize = 0;
887370b324cSopenharmony_ci  if (size == 0)
888370b324cSopenharmony_ci    return S_OK;
889370b324cSopenharmony_ci
890370b324cSopenharmony_ci  {
891370b324cSopenharmony_ci    if (_virtPos >= Size)
892370b324cSopenharmony_ci      return S_OK; // (Size == _virtPos) ? S_OK: E_FAIL;
893370b324cSopenharmony_ci    {
894370b324cSopenharmony_ci      UInt64 rem = Size - _virtPos;
895370b324cSopenharmony_ci      if (size > rem)
896370b324cSopenharmony_ci        size = (UInt32)rem;
897370b324cSopenharmony_ci    }
898370b324cSopenharmony_ci  }
899370b324cSopenharmony_ci
900370b324cSopenharmony_ci  if (size == 0)
901370b324cSopenharmony_ci    return S_OK;
902370b324cSopenharmony_ci
903370b324cSopenharmony_ci  if (_virtPos < _cacheStartPos || _virtPos >= _cacheStartPos + _cacheSize)
904370b324cSopenharmony_ci  {
905370b324cSopenharmony_ci    const size_t bi = FindBlock(_handlerSpec->_blocks, _handlerSpec->_blocksArraySize, _virtPos);
906370b324cSopenharmony_ci    const CBlockInfo &block = _handlerSpec->_blocks[bi];
907370b324cSopenharmony_ci    const UInt64 unpackSize = _handlerSpec->_blocks[bi + 1].UnpackPos - block.UnpackPos;
908370b324cSopenharmony_ci    if (_cache.Size() < unpackSize)
909370b324cSopenharmony_ci      return E_FAIL;
910370b324cSopenharmony_ci
911370b324cSopenharmony_ci    _cacheSize = 0;
912370b324cSopenharmony_ci
913370b324cSopenharmony_ci    RINOK(_handlerSpec->SeekToPackPos(block.PackPos))
914370b324cSopenharmony_ci    RINOK(DecodeBlock(xz, _handlerSpec->_seqStream, block.StreamFlags, block.PackSize,
915370b324cSopenharmony_ci        (size_t)unpackSize, _cache))
916370b324cSopenharmony_ci    _cacheStartPos = block.UnpackPos;
917370b324cSopenharmony_ci    _cacheSize = (size_t)unpackSize;
918370b324cSopenharmony_ci  }
919370b324cSopenharmony_ci
920370b324cSopenharmony_ci  {
921370b324cSopenharmony_ci    const size_t offset = (size_t)(_virtPos - _cacheStartPos);
922370b324cSopenharmony_ci    const size_t rem = _cacheSize - offset;
923370b324cSopenharmony_ci    if (size > rem)
924370b324cSopenharmony_ci      size = (UInt32)rem;
925370b324cSopenharmony_ci    memcpy(data, _cache + offset, size);
926370b324cSopenharmony_ci    _virtPos += size;
927370b324cSopenharmony_ci    if (processedSize)
928370b324cSopenharmony_ci      *processedSize = size;
929370b324cSopenharmony_ci    return S_OK;
930370b324cSopenharmony_ci  }
931370b324cSopenharmony_ci
932370b324cSopenharmony_ci  COM_TRY_END
933370b324cSopenharmony_ci}
934370b324cSopenharmony_ci
935370b324cSopenharmony_ci
936370b324cSopenharmony_ciZ7_COM7F_IMF(CInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
937370b324cSopenharmony_ci{
938370b324cSopenharmony_ci  switch (seekOrigin)
939370b324cSopenharmony_ci  {
940370b324cSopenharmony_ci    case STREAM_SEEK_SET: break;
941370b324cSopenharmony_ci    case STREAM_SEEK_CUR: offset += _virtPos; break;
942370b324cSopenharmony_ci    case STREAM_SEEK_END: offset += Size; break;
943370b324cSopenharmony_ci    default: return STG_E_INVALIDFUNCTION;
944370b324cSopenharmony_ci  }
945370b324cSopenharmony_ci  if (offset < 0)
946370b324cSopenharmony_ci    return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
947370b324cSopenharmony_ci  _virtPos = (UInt64)offset;
948370b324cSopenharmony_ci  if (newPosition)
949370b324cSopenharmony_ci    *newPosition = (UInt64)offset;
950370b324cSopenharmony_ci  return S_OK;
951370b324cSopenharmony_ci}
952370b324cSopenharmony_ci
953370b324cSopenharmony_ci
954370b324cSopenharmony_ci
955370b324cSopenharmony_cistatic const UInt64 kMaxBlockSize_for_GetStream = (UInt64)1 << 40;
956370b324cSopenharmony_ci
957370b324cSopenharmony_ciZ7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
958370b324cSopenharmony_ci{
959370b324cSopenharmony_ci  COM_TRY_BEGIN
960370b324cSopenharmony_ci
961370b324cSopenharmony_ci  *stream = NULL;
962370b324cSopenharmony_ci
963370b324cSopenharmony_ci  if (index != 0)
964370b324cSopenharmony_ci    return E_INVALIDARG;
965370b324cSopenharmony_ci
966370b324cSopenharmony_ci  if (!_stat.UnpackSize_Defined
967370b324cSopenharmony_ci      || _maxBlocksSize == 0 // 18.02
968370b324cSopenharmony_ci      || _maxBlocksSize > kMaxBlockSize_for_GetStream
969370b324cSopenharmony_ci      || _maxBlocksSize != (size_t)_maxBlocksSize)
970370b324cSopenharmony_ci    return S_FALSE;
971370b324cSopenharmony_ci
972370b324cSopenharmony_ci  UInt64 memSize;
973370b324cSopenharmony_ci  if (!NSystem::GetRamSize(memSize))
974370b324cSopenharmony_ci    memSize = (UInt64)(sizeof(size_t)) << 28;
975370b324cSopenharmony_ci  {
976370b324cSopenharmony_ci    if (_maxBlocksSize > memSize / 4)
977370b324cSopenharmony_ci      return S_FALSE;
978370b324cSopenharmony_ci  }
979370b324cSopenharmony_ci
980370b324cSopenharmony_ci  CInStream *spec = new CInStream;
981370b324cSopenharmony_ci  CMyComPtr<ISequentialInStream> specStream = spec;
982370b324cSopenharmony_ci  spec->_cache.Alloc((size_t)_maxBlocksSize);
983370b324cSopenharmony_ci  spec->_handlerSpec = this;
984370b324cSopenharmony_ci  spec->_handler = (IInArchive *)this;
985370b324cSopenharmony_ci  spec->Size = _stat.OutSize;
986370b324cSopenharmony_ci  spec->InitAndSeek();
987370b324cSopenharmony_ci
988370b324cSopenharmony_ci  *stream = specStream.Detach();
989370b324cSopenharmony_ci  return S_OK;
990370b324cSopenharmony_ci
991370b324cSopenharmony_ci  COM_TRY_END
992370b324cSopenharmony_ci}
993370b324cSopenharmony_ci
994370b324cSopenharmony_ci
995370b324cSopenharmony_cistatic Int32 Get_Extract_OperationResult(const NCompress::NXz::CDecoder &decoder)
996370b324cSopenharmony_ci{
997370b324cSopenharmony_ci  Int32 opRes;
998370b324cSopenharmony_ci  SRes sres = decoder.MainDecodeSRes;
999370b324cSopenharmony_ci  if (sres == SZ_ERROR_NO_ARCHIVE) // (!IsArc)
1000370b324cSopenharmony_ci    opRes = NExtract::NOperationResult::kIsNotArc;
1001370b324cSopenharmony_ci  else if (sres == SZ_ERROR_INPUT_EOF) // (UnexpectedEnd)
1002370b324cSopenharmony_ci    opRes = NExtract::NOperationResult::kUnexpectedEnd;
1003370b324cSopenharmony_ci  else if (decoder.Stat.DataAfterEnd)
1004370b324cSopenharmony_ci    opRes = NExtract::NOperationResult::kDataAfterEnd;
1005370b324cSopenharmony_ci  else if (sres == SZ_ERROR_CRC) // (CrcError)
1006370b324cSopenharmony_ci    opRes = NExtract::NOperationResult::kCRCError;
1007370b324cSopenharmony_ci  else if (sres == SZ_ERROR_UNSUPPORTED) // (Unsupported)
1008370b324cSopenharmony_ci    opRes = NExtract::NOperationResult::kUnsupportedMethod;
1009370b324cSopenharmony_ci  else if (sres == SZ_ERROR_ARCHIVE) //  (HeadersError)
1010370b324cSopenharmony_ci    opRes = NExtract::NOperationResult::kDataError;
1011370b324cSopenharmony_ci  else if (sres == SZ_ERROR_DATA)  // (DataError)
1012370b324cSopenharmony_ci    opRes = NExtract::NOperationResult::kDataError;
1013370b324cSopenharmony_ci  else if (sres != SZ_OK)
1014370b324cSopenharmony_ci    opRes = NExtract::NOperationResult::kDataError;
1015370b324cSopenharmony_ci  else
1016370b324cSopenharmony_ci    opRes = NExtract::NOperationResult::kOK;
1017370b324cSopenharmony_ci  return opRes;
1018370b324cSopenharmony_ci}
1019370b324cSopenharmony_ci
1020370b324cSopenharmony_ci
1021370b324cSopenharmony_ci
1022370b324cSopenharmony_ci
1023370b324cSopenharmony_ciZ7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
1024370b324cSopenharmony_ci    Int32 testMode, IArchiveExtractCallback *extractCallback))
1025370b324cSopenharmony_ci{
1026370b324cSopenharmony_ci  COM_TRY_BEGIN
1027370b324cSopenharmony_ci  if (numItems == 0)
1028370b324cSopenharmony_ci    return S_OK;
1029370b324cSopenharmony_ci  if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0))
1030370b324cSopenharmony_ci    return E_INVALIDARG;
1031370b324cSopenharmony_ci
1032370b324cSopenharmony_ci  const CXzStatInfo *stat = GetStat();
1033370b324cSopenharmony_ci
1034370b324cSopenharmony_ci  if (stat)
1035370b324cSopenharmony_ci    extractCallback->SetTotal(stat->InSize);
1036370b324cSopenharmony_ci
1037370b324cSopenharmony_ci  UInt64 currentTotalPacked = 0;
1038370b324cSopenharmony_ci  RINOK(extractCallback->SetCompleted(&currentTotalPacked))
1039370b324cSopenharmony_ci  CMyComPtr<ISequentialOutStream> realOutStream;
1040370b324cSopenharmony_ci  const Int32 askMode = testMode ?
1041370b324cSopenharmony_ci      NExtract::NAskMode::kTest :
1042370b324cSopenharmony_ci      NExtract::NAskMode::kExtract;
1043370b324cSopenharmony_ci
1044370b324cSopenharmony_ci  RINOK(extractCallback->GetStream(0, &realOutStream, askMode))
1045370b324cSopenharmony_ci
1046370b324cSopenharmony_ci  if (!testMode && !realOutStream)
1047370b324cSopenharmony_ci    return S_OK;
1048370b324cSopenharmony_ci
1049370b324cSopenharmony_ci  extractCallback->PrepareOperation(askMode);
1050370b324cSopenharmony_ci
1051370b324cSopenharmony_ci  CLocalProgress *lps = new CLocalProgress;
1052370b324cSopenharmony_ci  CMyComPtr<ICompressProgressInfo> lpsRef = lps;
1053370b324cSopenharmony_ci  lps->Init(extractCallback, true);
1054370b324cSopenharmony_ci
1055370b324cSopenharmony_ci  if (_needSeekToStart)
1056370b324cSopenharmony_ci  {
1057370b324cSopenharmony_ci    if (!_stream)
1058370b324cSopenharmony_ci      return E_FAIL;
1059370b324cSopenharmony_ci    RINOK(InStream_SeekToBegin(_stream))
1060370b324cSopenharmony_ci  }
1061370b324cSopenharmony_ci  else
1062370b324cSopenharmony_ci    _needSeekToStart = true;
1063370b324cSopenharmony_ci
1064370b324cSopenharmony_ci
1065370b324cSopenharmony_ci  NCompress::NXz::CDecoder decoder;
1066370b324cSopenharmony_ci
1067370b324cSopenharmony_ci  HRESULT hres = Decode(decoder, _seqStream, realOutStream, lpsRef);
1068370b324cSopenharmony_ci
1069370b324cSopenharmony_ci  if (!decoder.MainDecodeSRes_wasUsed)
1070370b324cSopenharmony_ci    return hres == S_OK ? E_FAIL : hres;
1071370b324cSopenharmony_ci
1072370b324cSopenharmony_ci  Int32 opRes = Get_Extract_OperationResult(decoder);
1073370b324cSopenharmony_ci  if (opRes == NExtract::NOperationResult::kOK
1074370b324cSopenharmony_ci      && hres != S_OK)
1075370b324cSopenharmony_ci    opRes = NExtract::NOperationResult::kDataError;
1076370b324cSopenharmony_ci
1077370b324cSopenharmony_ci  realOutStream.Release();
1078370b324cSopenharmony_ci  return extractCallback->SetOperationResult(opRes);
1079370b324cSopenharmony_ci  COM_TRY_END
1080370b324cSopenharmony_ci}
1081370b324cSopenharmony_ci
1082370b324cSopenharmony_ci
1083370b324cSopenharmony_ci
1084370b324cSopenharmony_ci#ifndef Z7_EXTRACT_ONLY
1085370b324cSopenharmony_ci
1086370b324cSopenharmony_ciZ7_COM7F_IMF(CHandler::GetFileTimeType(UInt32 *timeType))
1087370b324cSopenharmony_ci{
1088370b324cSopenharmony_ci  *timeType = GET_FileTimeType_NotDefined_for_GetFileTimeType;
1089370b324cSopenharmony_ci  // *timeType = NFileTimeType::kUnix;
1090370b324cSopenharmony_ci  return S_OK;
1091370b324cSopenharmony_ci}
1092370b324cSopenharmony_ci
1093370b324cSopenharmony_ci
1094370b324cSopenharmony_ciZ7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
1095370b324cSopenharmony_ci    IArchiveUpdateCallback *updateCallback))
1096370b324cSopenharmony_ci{
1097370b324cSopenharmony_ci  COM_TRY_BEGIN
1098370b324cSopenharmony_ci
1099370b324cSopenharmony_ci  if (numItems == 0)
1100370b324cSopenharmony_ci  {
1101370b324cSopenharmony_ci    CSeqOutStreamWrap seqOutStream;
1102370b324cSopenharmony_ci    seqOutStream.Init(outStream);
1103370b324cSopenharmony_ci    SRes res = Xz_EncodeEmpty(&seqOutStream.vt);
1104370b324cSopenharmony_ci    return SResToHRESULT(res);
1105370b324cSopenharmony_ci  }
1106370b324cSopenharmony_ci
1107370b324cSopenharmony_ci  if (numItems != 1)
1108370b324cSopenharmony_ci    return E_INVALIDARG;
1109370b324cSopenharmony_ci
1110370b324cSopenharmony_ci  {
1111370b324cSopenharmony_ci    Z7_DECL_CMyComPtr_QI_FROM(
1112370b324cSopenharmony_ci        IStreamSetRestriction,
1113370b324cSopenharmony_ci        setRestriction, outStream)
1114370b324cSopenharmony_ci    if (setRestriction)
1115370b324cSopenharmony_ci      RINOK(setRestriction->SetRestriction(0, 0))
1116370b324cSopenharmony_ci  }
1117370b324cSopenharmony_ci
1118370b324cSopenharmony_ci  Int32 newData, newProps;
1119370b324cSopenharmony_ci  UInt32 indexInArchive;
1120370b324cSopenharmony_ci  if (!updateCallback)
1121370b324cSopenharmony_ci    return E_FAIL;
1122370b324cSopenharmony_ci  RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive))
1123370b324cSopenharmony_ci
1124370b324cSopenharmony_ci  if (IntToBool(newProps))
1125370b324cSopenharmony_ci  {
1126370b324cSopenharmony_ci    {
1127370b324cSopenharmony_ci      NCOM::CPropVariant prop;
1128370b324cSopenharmony_ci      RINOK(updateCallback->GetProperty(0, kpidIsDir, &prop))
1129370b324cSopenharmony_ci      if (prop.vt != VT_EMPTY)
1130370b324cSopenharmony_ci        if (prop.vt != VT_BOOL || prop.boolVal != VARIANT_FALSE)
1131370b324cSopenharmony_ci          return E_INVALIDARG;
1132370b324cSopenharmony_ci    }
1133370b324cSopenharmony_ci  }
1134370b324cSopenharmony_ci
1135370b324cSopenharmony_ci  if (IntToBool(newData))
1136370b324cSopenharmony_ci  {
1137370b324cSopenharmony_ci    UInt64 dataSize;
1138370b324cSopenharmony_ci    {
1139370b324cSopenharmony_ci      NCOM::CPropVariant prop;
1140370b324cSopenharmony_ci      RINOK(updateCallback->GetProperty(0, kpidSize, &prop))
1141370b324cSopenharmony_ci      if (prop.vt != VT_UI8)
1142370b324cSopenharmony_ci        return E_INVALIDARG;
1143370b324cSopenharmony_ci      dataSize = prop.uhVal.QuadPart;
1144370b324cSopenharmony_ci    }
1145370b324cSopenharmony_ci
1146370b324cSopenharmony_ci    NCompress::NXz::CEncoder *encoderSpec = new NCompress::NXz::CEncoder;
1147370b324cSopenharmony_ci    CMyComPtr<ICompressCoder> encoder = encoderSpec;
1148370b324cSopenharmony_ci
1149370b324cSopenharmony_ci    CXzProps &xzProps = encoderSpec->xzProps;
1150370b324cSopenharmony_ci    CLzma2EncProps &lzma2Props = xzProps.lzma2Props;
1151370b324cSopenharmony_ci
1152370b324cSopenharmony_ci    lzma2Props.lzmaProps.level = GetLevel();
1153370b324cSopenharmony_ci
1154370b324cSopenharmony_ci    xzProps.reduceSize = dataSize;
1155370b324cSopenharmony_ci    /*
1156370b324cSopenharmony_ci    {
1157370b324cSopenharmony_ci      NCOM::CPropVariant prop = (UInt64)dataSize;
1158370b324cSopenharmony_ci      RINOK(encoderSpec->SetCoderProp(NCoderPropID::kReduceSize, prop))
1159370b324cSopenharmony_ci    }
1160370b324cSopenharmony_ci    */
1161370b324cSopenharmony_ci
1162370b324cSopenharmony_ci    #ifndef Z7_ST
1163370b324cSopenharmony_ci
1164370b324cSopenharmony_ci    UInt32 numThreads = _numThreads;
1165370b324cSopenharmony_ci
1166370b324cSopenharmony_ci    const UInt32 kNumThreads_Max = 1024;
1167370b324cSopenharmony_ci    if (numThreads > kNumThreads_Max)
1168370b324cSopenharmony_ci      numThreads = kNumThreads_Max;
1169370b324cSopenharmony_ci
1170370b324cSopenharmony_ci    if (!_numThreads_WasForced
1171370b324cSopenharmony_ci        && _numThreads >= 1
1172370b324cSopenharmony_ci        && _memUsage_WasSet)
1173370b324cSopenharmony_ci    {
1174370b324cSopenharmony_ci      COneMethodInfo oneMethodInfo;
1175370b324cSopenharmony_ci      if (!_methods.IsEmpty())
1176370b324cSopenharmony_ci        oneMethodInfo = _methods[0];
1177370b324cSopenharmony_ci
1178370b324cSopenharmony_ci      SetGlobalLevelTo(oneMethodInfo);
1179370b324cSopenharmony_ci
1180370b324cSopenharmony_ci      const bool numThreads_WasSpecifiedInMethod = (oneMethodInfo.Get_NumThreads() >= 0);
1181370b324cSopenharmony_ci      if (!numThreads_WasSpecifiedInMethod)
1182370b324cSopenharmony_ci      {
1183370b324cSopenharmony_ci        // here we set the (NCoderPropID::kNumThreads) property in each method, only if there is no such property already
1184370b324cSopenharmony_ci        CMultiMethodProps::SetMethodThreadsTo_IfNotFinded(oneMethodInfo, numThreads);
1185370b324cSopenharmony_ci      }
1186370b324cSopenharmony_ci
1187370b324cSopenharmony_ci      UInt64 cs = _numSolidBytes;
1188370b324cSopenharmony_ci      if (cs != XZ_PROPS_BLOCK_SIZE_AUTO)
1189370b324cSopenharmony_ci        oneMethodInfo.AddProp_BlockSize2(cs);
1190370b324cSopenharmony_ci      cs = oneMethodInfo.Get_Xz_BlockSize();
1191370b324cSopenharmony_ci
1192370b324cSopenharmony_ci      if (cs != XZ_PROPS_BLOCK_SIZE_AUTO &&
1193370b324cSopenharmony_ci          cs != XZ_PROPS_BLOCK_SIZE_SOLID)
1194370b324cSopenharmony_ci      {
1195370b324cSopenharmony_ci        const UInt32 lzmaThreads = oneMethodInfo.Get_Lzma_NumThreads();
1196370b324cSopenharmony_ci        const UInt32 numBlockThreads_Original = numThreads / lzmaThreads;
1197370b324cSopenharmony_ci
1198370b324cSopenharmony_ci        if (numBlockThreads_Original > 1)
1199370b324cSopenharmony_ci        {
1200370b324cSopenharmony_ci          UInt32 numBlockThreads = numBlockThreads_Original;
1201370b324cSopenharmony_ci          {
1202370b324cSopenharmony_ci            const UInt64 lzmaMemUsage = oneMethodInfo.Get_Lzma_MemUsage(false);
1203370b324cSopenharmony_ci            for (; numBlockThreads > 1; numBlockThreads--)
1204370b324cSopenharmony_ci            {
1205370b324cSopenharmony_ci              UInt64 size = numBlockThreads * (lzmaMemUsage + cs);
1206370b324cSopenharmony_ci              UInt32 numPackChunks = numBlockThreads + (numBlockThreads / 8) + 1;
1207370b324cSopenharmony_ci              if (cs < ((UInt32)1 << 26)) numPackChunks++;
1208370b324cSopenharmony_ci              if (cs < ((UInt32)1 << 24)) numPackChunks++;
1209370b324cSopenharmony_ci              if (cs < ((UInt32)1 << 22)) numPackChunks++;
1210370b324cSopenharmony_ci              size += numPackChunks * cs;
1211370b324cSopenharmony_ci              // printf("\nnumBlockThreads = %d, size = %d\n", (unsigned)(numBlockThreads), (unsigned)(size >> 20));
1212370b324cSopenharmony_ci              if (size <= _memUsage_Compress)
1213370b324cSopenharmony_ci                break;
1214370b324cSopenharmony_ci            }
1215370b324cSopenharmony_ci          }
1216370b324cSopenharmony_ci          if (numBlockThreads == 0)
1217370b324cSopenharmony_ci            numBlockThreads = 1;
1218370b324cSopenharmony_ci          if (numBlockThreads != numBlockThreads_Original)
1219370b324cSopenharmony_ci            numThreads = numBlockThreads * lzmaThreads;
1220370b324cSopenharmony_ci        }
1221370b324cSopenharmony_ci      }
1222370b324cSopenharmony_ci    }
1223370b324cSopenharmony_ci    xzProps.numTotalThreads = (int)numThreads;
1224370b324cSopenharmony_ci
1225370b324cSopenharmony_ci    #endif // Z7_ST
1226370b324cSopenharmony_ci
1227370b324cSopenharmony_ci
1228370b324cSopenharmony_ci    xzProps.blockSize = _numSolidBytes;
1229370b324cSopenharmony_ci    if (_numSolidBytes == XZ_PROPS_BLOCK_SIZE_SOLID)
1230370b324cSopenharmony_ci    {
1231370b324cSopenharmony_ci      xzProps.lzma2Props.blockSize = LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID;
1232370b324cSopenharmony_ci    }
1233370b324cSopenharmony_ci
1234370b324cSopenharmony_ci    RINOK(encoderSpec->SetCheckSize(_crcSize))
1235370b324cSopenharmony_ci
1236370b324cSopenharmony_ci    {
1237370b324cSopenharmony_ci      CXzFilterProps &filter = xzProps.filterProps;
1238370b324cSopenharmony_ci
1239370b324cSopenharmony_ci      if (_filterId == XZ_ID_Delta)
1240370b324cSopenharmony_ci      {
1241370b324cSopenharmony_ci        bool deltaDefined = false;
1242370b324cSopenharmony_ci        FOR_VECTOR (j, _filterMethod.Props)
1243370b324cSopenharmony_ci        {
1244370b324cSopenharmony_ci          const CProp &prop = _filterMethod.Props[j];
1245370b324cSopenharmony_ci          if (prop.Id == NCoderPropID::kDefaultProp && prop.Value.vt == VT_UI4)
1246370b324cSopenharmony_ci          {
1247370b324cSopenharmony_ci            UInt32 delta = (UInt32)prop.Value.ulVal;
1248370b324cSopenharmony_ci            if (delta < 1 || delta > 256)
1249370b324cSopenharmony_ci              return E_INVALIDARG;
1250370b324cSopenharmony_ci            filter.delta = delta;
1251370b324cSopenharmony_ci            deltaDefined = true;
1252370b324cSopenharmony_ci          }
1253370b324cSopenharmony_ci          else
1254370b324cSopenharmony_ci            return E_INVALIDARG;
1255370b324cSopenharmony_ci        }
1256370b324cSopenharmony_ci        if (!deltaDefined)
1257370b324cSopenharmony_ci          return E_INVALIDARG;
1258370b324cSopenharmony_ci      }
1259370b324cSopenharmony_ci      filter.id = _filterId;
1260370b324cSopenharmony_ci    }
1261370b324cSopenharmony_ci
1262370b324cSopenharmony_ci    FOR_VECTOR (i, _methods)
1263370b324cSopenharmony_ci    {
1264370b324cSopenharmony_ci      COneMethodInfo &m = _methods[i];
1265370b324cSopenharmony_ci
1266370b324cSopenharmony_ci      FOR_VECTOR (j, m.Props)
1267370b324cSopenharmony_ci      {
1268370b324cSopenharmony_ci        const CProp &prop = m.Props[j];
1269370b324cSopenharmony_ci        RINOK(encoderSpec->SetCoderProp(prop.Id, prop.Value))
1270370b324cSopenharmony_ci      }
1271370b324cSopenharmony_ci    }
1272370b324cSopenharmony_ci
1273370b324cSopenharmony_ci    {
1274370b324cSopenharmony_ci      CMyComPtr<ISequentialInStream> fileInStream;
1275370b324cSopenharmony_ci      RINOK(updateCallback->GetStream(0, &fileInStream))
1276370b324cSopenharmony_ci      if (!fileInStream)
1277370b324cSopenharmony_ci        return S_FALSE;
1278370b324cSopenharmony_ci      {
1279370b324cSopenharmony_ci        CMyComPtr<IStreamGetSize> streamGetSize;
1280370b324cSopenharmony_ci        fileInStream.QueryInterface(IID_IStreamGetSize, &streamGetSize);
1281370b324cSopenharmony_ci        if (streamGetSize)
1282370b324cSopenharmony_ci        {
1283370b324cSopenharmony_ci          UInt64 size;
1284370b324cSopenharmony_ci          if (streamGetSize->GetSize(&size) == S_OK)
1285370b324cSopenharmony_ci            dataSize = size;
1286370b324cSopenharmony_ci        }
1287370b324cSopenharmony_ci      }
1288370b324cSopenharmony_ci      RINOK(updateCallback->SetTotal(dataSize))
1289370b324cSopenharmony_ci      CLocalProgress *lps = new CLocalProgress;
1290370b324cSopenharmony_ci      CMyComPtr<ICompressProgressInfo> progress = lps;
1291370b324cSopenharmony_ci      lps->Init(updateCallback, true);
1292370b324cSopenharmony_ci      RINOK(encoder->Code(fileInStream, outStream, NULL, NULL, progress))
1293370b324cSopenharmony_ci    }
1294370b324cSopenharmony_ci
1295370b324cSopenharmony_ci    return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK);
1296370b324cSopenharmony_ci  }
1297370b324cSopenharmony_ci
1298370b324cSopenharmony_ci  if (indexInArchive != 0)
1299370b324cSopenharmony_ci    return E_INVALIDARG;
1300370b324cSopenharmony_ci
1301370b324cSopenharmony_ci  Z7_DECL_CMyComPtr_QI_FROM(
1302370b324cSopenharmony_ci      IArchiveUpdateCallbackFile,
1303370b324cSopenharmony_ci      opCallback, updateCallback)
1304370b324cSopenharmony_ci  if (opCallback)
1305370b324cSopenharmony_ci  {
1306370b324cSopenharmony_ci    RINOK(opCallback->ReportOperation(NEventIndexType::kInArcIndex, 0, NUpdateNotifyOp::kReplicate))
1307370b324cSopenharmony_ci  }
1308370b324cSopenharmony_ci
1309370b324cSopenharmony_ci  if (_stream)
1310370b324cSopenharmony_ci  {
1311370b324cSopenharmony_ci    const CXzStatInfo *stat = GetStat();
1312370b324cSopenharmony_ci    if (stat)
1313370b324cSopenharmony_ci    {
1314370b324cSopenharmony_ci      RINOK(updateCallback->SetTotal(stat->InSize))
1315370b324cSopenharmony_ci    }
1316370b324cSopenharmony_ci    RINOK(InStream_SeekToBegin(_stream))
1317370b324cSopenharmony_ci  }
1318370b324cSopenharmony_ci
1319370b324cSopenharmony_ci  CLocalProgress *lps = new CLocalProgress;
1320370b324cSopenharmony_ci  CMyComPtr<ICompressProgressInfo> progress = lps;
1321370b324cSopenharmony_ci  lps->Init(updateCallback, true);
1322370b324cSopenharmony_ci
1323370b324cSopenharmony_ci  return NCompress::CopyStream(_stream, outStream, progress);
1324370b324cSopenharmony_ci
1325370b324cSopenharmony_ci  COM_TRY_END
1326370b324cSopenharmony_ci}
1327370b324cSopenharmony_ci
1328370b324cSopenharmony_ci#endif
1329370b324cSopenharmony_ci
1330370b324cSopenharmony_ci
1331370b324cSopenharmony_ciHRESULT CHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value)
1332370b324cSopenharmony_ci{
1333370b324cSopenharmony_ci  UString name = nameSpec;
1334370b324cSopenharmony_ci  name.MakeLower_Ascii();
1335370b324cSopenharmony_ci  if (name.IsEmpty())
1336370b324cSopenharmony_ci    return E_INVALIDARG;
1337370b324cSopenharmony_ci
1338370b324cSopenharmony_ci  #ifndef Z7_EXTRACT_ONLY
1339370b324cSopenharmony_ci
1340370b324cSopenharmony_ci  if (name[0] == L's')
1341370b324cSopenharmony_ci  {
1342370b324cSopenharmony_ci    const wchar_t *s = name.Ptr(1);
1343370b324cSopenharmony_ci    if (*s == 0)
1344370b324cSopenharmony_ci    {
1345370b324cSopenharmony_ci      bool useStr = false;
1346370b324cSopenharmony_ci      bool isSolid;
1347370b324cSopenharmony_ci      switch (value.vt)
1348370b324cSopenharmony_ci      {
1349370b324cSopenharmony_ci        case VT_EMPTY: isSolid = true; break;
1350370b324cSopenharmony_ci        case VT_BOOL: isSolid = (value.boolVal != VARIANT_FALSE); break;
1351370b324cSopenharmony_ci        case VT_BSTR:
1352370b324cSopenharmony_ci          if (!StringToBool(value.bstrVal, isSolid))
1353370b324cSopenharmony_ci            useStr = true;
1354370b324cSopenharmony_ci          break;
1355370b324cSopenharmony_ci        default: return E_INVALIDARG;
1356370b324cSopenharmony_ci      }
1357370b324cSopenharmony_ci      if (!useStr)
1358370b324cSopenharmony_ci      {
1359370b324cSopenharmony_ci        _numSolidBytes = (isSolid ? XZ_PROPS_BLOCK_SIZE_SOLID : XZ_PROPS_BLOCK_SIZE_AUTO);
1360370b324cSopenharmony_ci        return S_OK;
1361370b324cSopenharmony_ci      }
1362370b324cSopenharmony_ci    }
1363370b324cSopenharmony_ci    return ParseSizeString(s, value,
1364370b324cSopenharmony_ci        0, // percentsBase
1365370b324cSopenharmony_ci        _numSolidBytes) ? S_OK: E_INVALIDARG;
1366370b324cSopenharmony_ci  }
1367370b324cSopenharmony_ci
1368370b324cSopenharmony_ci  return CMultiMethodProps::SetProperty(name, value);
1369370b324cSopenharmony_ci
1370370b324cSopenharmony_ci  #else
1371370b324cSopenharmony_ci
1372370b324cSopenharmony_ci  {
1373370b324cSopenharmony_ci    HRESULT hres;
1374370b324cSopenharmony_ci    if (SetCommonProperty(name, value, hres))
1375370b324cSopenharmony_ci      return hres;
1376370b324cSopenharmony_ci  }
1377370b324cSopenharmony_ci
1378370b324cSopenharmony_ci  return E_INVALIDARG;
1379370b324cSopenharmony_ci
1380370b324cSopenharmony_ci  #endif
1381370b324cSopenharmony_ci}
1382370b324cSopenharmony_ci
1383370b324cSopenharmony_ci
1384370b324cSopenharmony_ci
1385370b324cSopenharmony_ciZ7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps))
1386370b324cSopenharmony_ci{
1387370b324cSopenharmony_ci  COM_TRY_BEGIN
1388370b324cSopenharmony_ci
1389370b324cSopenharmony_ci  Init();
1390370b324cSopenharmony_ci
1391370b324cSopenharmony_ci  for (UInt32 i = 0; i < numProps; i++)
1392370b324cSopenharmony_ci  {
1393370b324cSopenharmony_ci    RINOK(SetProperty(names[i], values[i]))
1394370b324cSopenharmony_ci  }
1395370b324cSopenharmony_ci
1396370b324cSopenharmony_ci  #ifndef Z7_EXTRACT_ONLY
1397370b324cSopenharmony_ci
1398370b324cSopenharmony_ci  if (!_filterMethod.MethodName.IsEmpty())
1399370b324cSopenharmony_ci  {
1400370b324cSopenharmony_ci    unsigned k;
1401370b324cSopenharmony_ci    for (k = 0; k < Z7_ARRAY_SIZE(g_NamePairs); k++)
1402370b324cSopenharmony_ci    {
1403370b324cSopenharmony_ci      const CMethodNamePair &pair = g_NamePairs[k];
1404370b324cSopenharmony_ci      if (StringsAreEqualNoCase_Ascii(_filterMethod.MethodName, pair.Name))
1405370b324cSopenharmony_ci      {
1406370b324cSopenharmony_ci        _filterId = pair.Id;
1407370b324cSopenharmony_ci        break;
1408370b324cSopenharmony_ci      }
1409370b324cSopenharmony_ci    }
1410370b324cSopenharmony_ci    if (k == Z7_ARRAY_SIZE(g_NamePairs))
1411370b324cSopenharmony_ci      return E_INVALIDARG;
1412370b324cSopenharmony_ci  }
1413370b324cSopenharmony_ci
1414370b324cSopenharmony_ci  _methods.DeleteFrontal(GetNumEmptyMethods());
1415370b324cSopenharmony_ci  if (_methods.Size() > 1)
1416370b324cSopenharmony_ci    return E_INVALIDARG;
1417370b324cSopenharmony_ci  if (_methods.Size() == 1)
1418370b324cSopenharmony_ci  {
1419370b324cSopenharmony_ci    AString &methodName = _methods[0].MethodName;
1420370b324cSopenharmony_ci    if (methodName.IsEmpty())
1421370b324cSopenharmony_ci      methodName = k_LZMA2_Name;
1422370b324cSopenharmony_ci    else if (
1423370b324cSopenharmony_ci        !methodName.IsEqualTo_Ascii_NoCase(k_LZMA2_Name)
1424370b324cSopenharmony_ci        && !methodName.IsEqualTo_Ascii_NoCase("xz"))
1425370b324cSopenharmony_ci      return E_INVALIDARG;
1426370b324cSopenharmony_ci  }
1427370b324cSopenharmony_ci
1428370b324cSopenharmony_ci  #endif
1429370b324cSopenharmony_ci
1430370b324cSopenharmony_ci  return S_OK;
1431370b324cSopenharmony_ci
1432370b324cSopenharmony_ci  COM_TRY_END
1433370b324cSopenharmony_ci}
1434370b324cSopenharmony_ci
1435370b324cSopenharmony_ci
1436370b324cSopenharmony_ciREGISTER_ARC_IO(
1437370b324cSopenharmony_ci  "xz", "xz txz", "* .tar", 0xC,
1438370b324cSopenharmony_ci  XZ_SIG, 0
1439370b324cSopenharmony_ci  , NArcInfoFlags::kKeepName
1440370b324cSopenharmony_ci  , 0
1441370b324cSopenharmony_ci  , NULL)
1442370b324cSopenharmony_ci
1443370b324cSopenharmony_ci}}
1444