Imported Upstream version 9.20
[platform/upstream/7zip.git] / CPP / 7zip / Archive / XzHandler.cpp
1 // XzHandler.cpp\r
2 \r
3 #include "StdAfx.h"\r
4 \r
5 #include "../../../C/Alloc.h"\r
6 #include "../../../C/XzCrc64.h"\r
7 #include "../../../C/XzEnc.h"\r
8 \r
9 #include "../../Common/ComTry.h"\r
10 #include "../../Common/IntToString.h"\r
11 \r
12 #include "../ICoder.h"\r
13 \r
14 #include "../Common/CWrappers.h"\r
15 #include "../Common/ProgressUtils.h"\r
16 #include "../Common/RegisterArc.h"\r
17 #include "../Common/StreamUtils.h"\r
18 \r
19 #include "../Compress/CopyCoder.h"\r
20 \r
21 #include "IArchive.h"\r
22 \r
23 #include "Common/HandlerOut.h"\r
24 \r
25 using namespace NWindows;\r
26 \r
27 namespace NCompress {\r
28 namespace NLzma2 {\r
29 \r
30 HRESULT SetLzma2Prop(PROPID propID, const PROPVARIANT &prop, CLzma2EncProps &lzma2Props);\r
31 \r
32 }}\r
33 \r
34 static void *SzAlloc(void *, size_t size) { return MyAlloc(size); }\r
35 static void SzFree(void *, void *address) { MyFree(address); }\r
36 static ISzAlloc g_Alloc = { SzAlloc, SzFree };\r
37 \r
38 namespace NArchive {\r
39 namespace NXz {\r
40 \r
41 struct CCrc64Gen { CCrc64Gen() { Crc64GenerateTable(); } } g_Crc64TableInit;\r
42 \r
43 class CHandler:\r
44   public IInArchive,\r
45   public IArchiveOpenSeq,\r
46   #ifndef EXTRACT_ONLY\r
47   public IOutArchive,\r
48   public ISetProperties,\r
49   public COutHandler,\r
50   #endif\r
51   public CMyUnknownImp\r
52 {\r
53   Int64 _startPosition;\r
54   UInt64 _packSize;\r
55   UInt64 _unpackSize;\r
56   UInt64 _numBlocks;\r
57   AString _methodsString;\r
58   bool _useSeq;\r
59   UInt64 _unpackSizeDefined;\r
60   UInt64 _packSizeDefined;\r
61   \r
62   CMyComPtr<IInStream> _stream;\r
63   CMyComPtr<ISequentialInStream> _seqStream;\r
64 \r
65   UInt32 _crcSize;\r
66 \r
67   void Init()\r
68   {\r
69     _crcSize = 4;\r
70     COutHandler::Init();\r
71   }\r
72 \r
73   HRESULT Open2(IInStream *inStream, IArchiveOpenCallback *callback);\r
74 \r
75 public:\r
76   MY_QUERYINTERFACE_BEGIN2(IInArchive)\r
77   MY_QUERYINTERFACE_ENTRY(IArchiveOpenSeq)\r
78   #ifndef EXTRACT_ONLY\r
79   MY_QUERYINTERFACE_ENTRY(IOutArchive)\r
80   MY_QUERYINTERFACE_ENTRY(ISetProperties)\r
81   #endif\r
82   MY_QUERYINTERFACE_END\r
83   MY_ADDREF_RELEASE\r
84 \r
85   INTERFACE_IInArchive(;)\r
86   STDMETHOD(OpenSeq)(ISequentialInStream *stream);\r
87 \r
88   #ifndef EXTRACT_ONLY\r
89   INTERFACE_IOutArchive(;)\r
90   STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, Int32 numProps);\r
91   #endif\r
92 \r
93   CHandler();\r
94 };\r
95 \r
96 CHandler::CHandler()\r
97 {\r
98   Init();\r
99 }\r
100 \r
101 STATPROPSTG kProps[] =\r
102 {\r
103   { NULL, kpidSize, VT_UI8},\r
104   { NULL, kpidPackSize, VT_UI8},\r
105   { NULL, kpidMethod, VT_BSTR}\r
106 };\r
107 \r
108 STATPROPSTG kArcProps[] =\r
109 {\r
110   { NULL, kpidMethod, VT_BSTR},\r
111   { NULL, kpidNumBlocks, VT_UI4}\r
112 };\r
113 \r
114 IMP_IInArchive_Props\r
115 IMP_IInArchive_ArcProps\r
116 \r
117 static char GetHex(Byte value)\r
118 {\r
119   return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10)));\r
120 }\r
121 \r
122 static inline void AddHexToString(AString &res, Byte value)\r
123 {\r
124   res += GetHex((Byte)(value >> 4));\r
125   res += GetHex((Byte)(value & 0xF));\r
126 }\r
127 \r
128 static AString ConvertUInt32ToString(UInt32 value)\r
129 {\r
130   char temp[32];\r
131   ::ConvertUInt32ToString(value, temp);\r
132   return temp;\r
133 }\r
134 \r
135 static AString Lzma2PropToString(int prop)\r
136 {\r
137   if ((prop & 1) == 0)\r
138     return ConvertUInt32ToString(prop / 2 + 12);\r
139   AString res;\r
140   char c;\r
141 \r
142   UInt32 size = (2 | ((prop) & 1)) << ((prop) / 2 + 1);\r
143 \r
144   if (prop > 17)\r
145   {\r
146     res = ConvertUInt32ToString(size >> 10);\r
147     c = 'm';\r
148   }\r
149   else\r
150   {\r
151     res = ConvertUInt32ToString(size);\r
152     c = 'k';\r
153   }\r
154   return res + c;\r
155 }\r
156 \r
157 struct CMethodNamePair\r
158 {\r
159   UInt32 Id;\r
160   const char *Name;\r
161 };\r
162 \r
163 static CMethodNamePair g_NamePairs[] =\r
164 {\r
165   { XZ_ID_Subblock, "SB" },\r
166   { XZ_ID_Delta, "Delta" },\r
167   { XZ_ID_X86, "x86" },\r
168   { XZ_ID_PPC, "PPC" },\r
169   { XZ_ID_IA64, "IA64" },\r
170   { XZ_ID_ARM, "ARM" },\r
171   { XZ_ID_ARMT, "ARMT" },\r
172   { XZ_ID_SPARC, "SPARC" },\r
173   { XZ_ID_LZMA2, "LZMA2" }\r
174 };\r
175 \r
176 static AString GetMethodString(const CXzFilter &f)\r
177 {\r
178   AString s;\r
179 \r
180   for (int i = 0; i < sizeof(g_NamePairs) / sizeof(g_NamePairs[i]); i++)\r
181     if (g_NamePairs[i].Id == f.id)\r
182       s = g_NamePairs[i].Name;\r
183   if (s.IsEmpty())\r
184   {\r
185     char temp[32];\r
186     ::ConvertUInt64ToString(f.id, temp);\r
187     s = temp;\r
188   }\r
189 \r
190   if (f.propsSize > 0)\r
191   {\r
192     s += ':';\r
193     if (f.id == XZ_ID_LZMA2 && f.propsSize == 1)\r
194       s += Lzma2PropToString(f.props[0]);\r
195     else if (f.id == XZ_ID_Delta && f.propsSize == 1)\r
196       s += ConvertUInt32ToString((UInt32)f.props[0] + 1);\r
197     else\r
198     {\r
199       s += '[';\r
200       for (UInt32 bi = 0; bi < f.propsSize; bi++)\r
201         AddHexToString(s, f.props[bi]);\r
202       s += ']';\r
203     }\r
204   }\r
205   return s;\r
206 }\r
207 \r
208 static void AddString(AString &dest, const AString &src)\r
209 {\r
210   if (!dest.IsEmpty())\r
211     dest += ' ';\r
212   dest += src;\r
213 }\r
214 \r
215 static const char *kChecks[] =\r
216 {\r
217   "NoCheck",\r
218   "CRC32",\r
219   NULL,\r
220   NULL,\r
221   "CRC64",\r
222   NULL,\r
223   NULL,\r
224   NULL,\r
225   NULL,\r
226   NULL,\r
227   "SHA256",\r
228   NULL,\r
229   NULL,\r
230   NULL,\r
231   NULL,\r
232   NULL\r
233 };\r
234 \r
235 static AString GetCheckString(const CXzs &xzs)\r
236 {\r
237   size_t i;\r
238   UInt32 mask = 0;\r
239   for (i = 0; i < xzs.num; i++)\r
240     mask |= ((UInt32)1 << XzFlags_GetCheckType(xzs.streams[i].flags));\r
241   AString s;\r
242   for (i = 0; i <= XZ_CHECK_MASK; i++)\r
243     if (((mask >> i) & 1) != 0)\r
244     {\r
245       AString s2;\r
246       if (kChecks[i])\r
247         s2 = kChecks[i];\r
248       else\r
249         s2 = "Check-" + ConvertUInt32ToString((UInt32)i);\r
250       AddString(s, s2);\r
251     }\r
252   return s;\r
253 }\r
254 \r
255 STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)\r
256 {\r
257   COM_TRY_BEGIN\r
258   NWindows::NCOM::CPropVariant prop;\r
259   switch(propID)\r
260   {\r
261     case kpidNumBlocks: if (!_useSeq) prop = _numBlocks; break;\r
262     case kpidPhySize: if (_packSizeDefined) prop = _packSize; break;\r
263     case kpidMethod: if (!_methodsString.IsEmpty()) prop = _methodsString; break;\r
264   }\r
265   prop.Detach(value);\r
266   return S_OK;\r
267   COM_TRY_END\r
268 }\r
269 \r
270 STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)\r
271 {\r
272   *numItems = 1;\r
273   return S_OK;\r
274 }\r
275 \r
276 STDMETHODIMP CHandler::GetProperty(UInt32, PROPID propID,  PROPVARIANT *value)\r
277 {\r
278   COM_TRY_BEGIN\r
279   NWindows::NCOM::CPropVariant prop;\r
280   switch(propID)\r
281   {\r
282     case kpidSize: if (_unpackSizeDefined) prop = _unpackSize; break;\r
283     case kpidPackSize: if (_packSizeDefined) prop = _packSize; break;\r
284     case kpidMethod: if (!_methodsString.IsEmpty()) prop = _methodsString; break;\r
285   }\r
286   prop.Detach(value);\r
287   return S_OK;\r
288   COM_TRY_END\r
289 }\r
290 \r
291 \r
292 struct COpenCallbackWrap\r
293 {\r
294   ICompressProgress p;\r
295   IArchiveOpenCallback *OpenCallback;\r
296   HRESULT Res;\r
297   COpenCallbackWrap(IArchiveOpenCallback *progress);\r
298 };\r
299 \r
300 static SRes OpenCallbackProgress(void *pp, UInt64 inSize, UInt64 /* outSize */)\r
301 {\r
302   COpenCallbackWrap *p = (COpenCallbackWrap *)pp;\r
303   p->Res = p->OpenCallback->SetCompleted(NULL, &inSize);\r
304   return (SRes)p->Res;\r
305 }\r
306 \r
307 COpenCallbackWrap::COpenCallbackWrap(IArchiveOpenCallback *callback)\r
308 {\r
309   p.Progress = OpenCallbackProgress;\r
310   OpenCallback = callback;\r
311   Res = SZ_OK;\r
312 }\r
313 \r
314 struct CXzsCPP\r
315 {\r
316   CXzs p;\r
317   CXzsCPP() { Xzs_Construct(&p); }\r
318   ~CXzsCPP() { Xzs_Free(&p, &g_Alloc); }\r
319 };\r
320 \r
321 HRESULT CHandler::Open2(IInStream *inStream, IArchiveOpenCallback *callback)\r
322 {\r
323   CSeekInStreamWrap inStreamImp(inStream);\r
324 \r
325   CLookToRead lookStream;\r
326   LookToRead_CreateVTable(&lookStream, True);\r
327   lookStream.realStream = &inStreamImp.p;\r
328   LookToRead_Init(&lookStream);\r
329 \r
330   COpenCallbackWrap openWrap(callback);\r
331   RINOK(inStream->Seek(0, STREAM_SEEK_END, &_packSize));\r
332   RINOK(callback->SetTotal(NULL, &_packSize));\r
333 \r
334   CXzsCPP xzs;\r
335   SRes res = Xzs_ReadBackward(&xzs.p, &lookStream.s, &_startPosition, &openWrap.p, &g_Alloc);\r
336   if (res == SZ_ERROR_NO_ARCHIVE && xzs.p.num > 0)\r
337     res = SZ_OK;\r
338   if (res == SZ_OK)\r
339   {\r
340     _packSize -= _startPosition;\r
341     _unpackSize = Xzs_GetUnpackSize(&xzs.p);\r
342     _unpackSizeDefined = _packSizeDefined = true;\r
343     _numBlocks = (UInt64)Xzs_GetNumBlocks(&xzs.p);\r
344 \r
345     RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL));\r
346     CXzStreamFlags st;\r
347     CSeqInStreamWrap inStreamWrap(inStream);\r
348     SRes res2 = Xz_ReadHeader(&st, &inStreamWrap.p);\r
349 \r
350     if (res2 == SZ_OK)\r
351     {\r
352       CXzBlock block;\r
353       Bool isIndex;\r
354       UInt32 headerSizeRes;\r
355       res2 = XzBlock_ReadHeader(&block, &inStreamWrap.p, &isIndex, &headerSizeRes);\r
356       if (res2 == SZ_OK && !isIndex)\r
357       {\r
358         int numFilters = XzBlock_GetNumFilters(&block);\r
359         for (int i = 0; i < numFilters; i++)\r
360           AddString(_methodsString, GetMethodString(block.filters[i]));\r
361       }\r
362     }\r
363     AddString(_methodsString, GetCheckString(xzs.p));\r
364   }\r
365 \r
366   if (res != SZ_OK || _startPosition != 0)\r
367   {\r
368     RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL));\r
369     CXzStreamFlags st;\r
370     CSeqInStreamWrap inStreamWrap(inStream);\r
371     SRes res2 = Xz_ReadHeader(&st, &inStreamWrap.p);\r
372     if (res2 == SZ_OK)\r
373     {\r
374       res = res2;\r
375       _startPosition = 0;\r
376       _useSeq = True;\r
377       _unpackSizeDefined = _packSizeDefined = false;\r
378     }\r
379   }\r
380   if (res == SZ_ERROR_NO_ARCHIVE)\r
381     return S_FALSE;\r
382   RINOK(SResToHRESULT(res));\r
383   _stream = inStream;\r
384   _seqStream = inStream;\r
385   return S_OK;\r
386 }\r
387 \r
388 STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *callback)\r
389 {\r
390   COM_TRY_BEGIN\r
391   try\r
392   {\r
393     Close();\r
394     return Open2(inStream, callback);\r
395   }\r
396   catch(...) { return S_FALSE; }\r
397   COM_TRY_END\r
398 }\r
399 \r
400 STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream)\r
401 {\r
402   Close();\r
403   _seqStream = stream;\r
404   return S_OK;\r
405 }\r
406 \r
407 STDMETHODIMP CHandler::Close()\r
408 {\r
409   _numBlocks = 0;\r
410   _useSeq = true;\r
411   _unpackSizeDefined = _packSizeDefined = false;\r
412   _methodsString.Empty();\r
413   _stream.Release();\r
414   _seqStream.Release();\r
415   return S_OK;\r
416 }\r
417 \r
418 class CSeekToSeqStream:\r
419   public IInStream,\r
420   public CMyUnknownImp\r
421 {\r
422 public:\r
423   CMyComPtr<ISequentialInStream> Stream;\r
424   MY_UNKNOWN_IMP1(IInStream)\r
425 \r
426   STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);\r
427   STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);\r
428 };\r
429 \r
430 STDMETHODIMP CSeekToSeqStream::Read(void *data, UInt32 size, UInt32 *processedSize)\r
431 {\r
432   return Stream->Read(data, size, processedSize);\r
433 }\r
434 \r
435 STDMETHODIMP CSeekToSeqStream::Seek(Int64, UInt32, UInt64 *) { return E_NOTIMPL; }\r
436 \r
437 struct CXzUnpackerCPP\r
438 {\r
439   Byte *InBuf;\r
440   Byte *OutBuf;\r
441   CXzUnpacker p;\r
442   CXzUnpackerCPP(): InBuf(0), OutBuf(0) {}\r
443   ~CXzUnpackerCPP()\r
444   {\r
445     XzUnpacker_Free(&p);\r
446     MyFree(InBuf);\r
447     MyFree(OutBuf);\r
448   }\r
449 };\r
450 \r
451 STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,\r
452     Int32 testMode, IArchiveExtractCallback *extractCallback)\r
453 {\r
454   COM_TRY_BEGIN\r
455   if (numItems == 0)\r
456     return S_OK;\r
457   if (numItems != (UInt32)-1 && (numItems != 1 || indices[0] != 0))\r
458     return E_INVALIDARG;\r
459 \r
460   extractCallback->SetTotal(_packSize);\r
461   UInt64 currentTotalPacked = 0;\r
462   RINOK(extractCallback->SetCompleted(&currentTotalPacked));\r
463   CMyComPtr<ISequentialOutStream> realOutStream;\r
464   Int32 askMode = testMode ?\r
465       NExtract::NAskMode::kTest :\r
466       NExtract::NAskMode::kExtract;\r
467   \r
468   RINOK(extractCallback->GetStream(0, &realOutStream, askMode));\r
469   \r
470   if (!testMode && !realOutStream)\r
471     return S_OK;\r
472 \r
473   extractCallback->PrepareOperation(askMode);\r
474 \r
475   if (_stream)\r
476   {\r
477     RINOK(_stream->Seek(_startPosition, STREAM_SEEK_SET, NULL));\r
478   }\r
479 \r
480   CLocalProgress *lps = new CLocalProgress;\r
481   CMyComPtr<ICompressProgressInfo> progress = lps;\r
482   lps->Init(extractCallback, true);\r
483 \r
484   CCompressProgressWrap progressWrap(progress);\r
485 \r
486   SRes res;\r
487 \r
488   const UInt32 kInBufSize = 1 << 15;\r
489   const UInt32 kOutBufSize = 1 << 21;\r
490 \r
491   UInt32 inPos = 0;\r
492   UInt32 inSize = 0;\r
493   UInt32 outPos = 0;\r
494   CXzUnpackerCPP xzu;\r
495   res = XzUnpacker_Create(&xzu.p, &g_Alloc);\r
496   if (res == SZ_OK)\r
497   {\r
498     xzu.InBuf = (Byte *)MyAlloc(kInBufSize);\r
499     xzu.OutBuf = (Byte *)MyAlloc(kOutBufSize);\r
500     if (xzu.InBuf == 0 || xzu.OutBuf == 0)\r
501       res = SZ_ERROR_MEM;\r
502   }\r
503   if (res == SZ_OK)\r
504   for (;;)\r
505   {\r
506     if (inPos == inSize)\r
507     {\r
508       inPos = inSize = 0;\r
509       RINOK(_seqStream->Read(xzu.InBuf, kInBufSize, &inSize));\r
510     }\r
511 \r
512     SizeT inLen = inSize - inPos;\r
513     SizeT outLen = kOutBufSize - outPos;\r
514     ECoderStatus status;\r
515     res = XzUnpacker_Code(&xzu.p,\r
516         xzu.OutBuf + outPos, &outLen,\r
517         xzu.InBuf + inPos, &inLen,\r
518         (inSize == 0 ? CODER_FINISH_END : CODER_FINISH_ANY), &status);\r
519 \r
520     // printf("\n_inPos = %6d  inLen = %5d, outLen = %5d", inPos, inLen, outLen);\r
521 \r
522     inPos += (UInt32)inLen;\r
523     outPos += (UInt32)outLen;\r
524     lps->InSize += inLen;\r
525     lps->OutSize += outLen;\r
526 \r
527     bool finished = (((inLen == 0) && (outLen == 0)) || res != SZ_OK);\r
528 \r
529     if (outPos == kOutBufSize || finished)\r
530     {\r
531       if (realOutStream && outPos > 0)\r
532       {\r
533         RINOK(WriteStream(realOutStream, xzu.OutBuf, outPos));\r
534       }\r
535       outPos = 0;\r
536     }\r
537     if (finished)\r
538     {\r
539       _packSize = lps->InSize;\r
540       _unpackSize = lps->OutSize;\r
541       _packSizeDefined = _unpackSizeDefined = true;\r
542       if (res == SZ_OK)\r
543       {\r
544         if (status == CODER_STATUS_NEEDS_MORE_INPUT)\r
545         {\r
546           if (XzUnpacker_IsStreamWasFinished(&xzu.p))\r
547             _packSize -= xzu.p.padSize;\r
548           else\r
549             res = SZ_ERROR_DATA;\r
550         }\r
551         else\r
552           res = SZ_ERROR_DATA;\r
553       }\r
554       break;\r
555     }\r
556     RINOK(lps->SetCur());\r
557   }\r
558 \r
559   Int32 opRes;\r
560   switch(res)\r
561   {\r
562     case SZ_OK:\r
563       opRes = NExtract::NOperationResult::kOK; break;\r
564     case SZ_ERROR_UNSUPPORTED:\r
565       opRes = NExtract::NOperationResult::kUnSupportedMethod; break;\r
566     case SZ_ERROR_CRC:\r
567       opRes = NExtract::NOperationResult::kCRCError; break;\r
568     case SZ_ERROR_DATA:\r
569     case SZ_ERROR_ARCHIVE:\r
570     case SZ_ERROR_NO_ARCHIVE:\r
571       opRes = NExtract::NOperationResult::kDataError; break;\r
572     default:\r
573       return SResToHRESULT(res);\r
574   }\r
575   realOutStream.Release();\r
576   RINOK(extractCallback->SetOperationResult(opRes));\r
577   return S_OK;\r
578   COM_TRY_END\r
579 }\r
580 \r
581 #ifndef EXTRACT_ONLY\r
582 \r
583 STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType)\r
584 {\r
585   *timeType = NFileTimeType::kUnix;\r
586   return S_OK;\r
587 }\r
588 \r
589 STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,\r
590     IArchiveUpdateCallback *updateCallback)\r
591 {\r
592   CSeqOutStreamWrap seqOutStream(outStream);\r
593   \r
594   if (numItems == 0)\r
595   {\r
596     SRes res = Xz_EncodeEmpty(&seqOutStream.p);\r
597     return SResToHRESULT(res);\r
598   }\r
599   \r
600   if (numItems != 1)\r
601     return E_INVALIDARG;\r
602 \r
603   Int32 newData, newProps;\r
604   UInt32 indexInArchive;\r
605   if (!updateCallback)\r
606     return E_FAIL;\r
607   RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive));\r
608 \r
609   if (IntToBool(newProps))\r
610   {\r
611     {\r
612       NCOM::CPropVariant prop;\r
613       RINOK(updateCallback->GetProperty(0, kpidIsDir, &prop));\r
614       if (prop.vt != VT_EMPTY)\r
615         if (prop.vt != VT_BOOL || prop.boolVal != VARIANT_FALSE)\r
616           return E_INVALIDARG;\r
617     }\r
618   }\r
619 \r
620   if (IntToBool(newData))\r
621   {\r
622     {\r
623       UInt64 size;\r
624       NCOM::CPropVariant prop;\r
625       RINOK(updateCallback->GetProperty(0, kpidSize, &prop));\r
626       if (prop.vt != VT_UI8)\r
627         return E_INVALIDARG;\r
628       size = prop.uhVal.QuadPart;\r
629       RINOK(updateCallback->SetTotal(size));\r
630     }\r
631 \r
632     CLzma2EncProps lzma2Props;\r
633     Lzma2EncProps_Init(&lzma2Props);\r
634 \r
635     lzma2Props.lzmaProps.level = _level;\r
636 \r
637     CMyComPtr<ISequentialInStream> fileInStream;\r
638     RINOK(updateCallback->GetStream(0, &fileInStream));\r
639 \r
640     CSeqInStreamWrap seqInStream(fileInStream);\r
641 \r
642     for (int i = 0; i < _methods.Size(); i++)\r
643     {\r
644       COneMethodInfo &m = _methods[i];\r
645       SetCompressionMethod2(m\r
646       #ifndef _7ZIP_ST\r
647       , _numThreads\r
648       #endif\r
649       );\r
650       if (m.IsLzma())\r
651       {\r
652         for (int j = 0; j < m.Props.Size(); j++)\r
653         {\r
654           const CProp &prop = m.Props[j];\r
655           RINOK(NCompress::NLzma2::SetLzma2Prop(prop.Id, prop.Value, lzma2Props));\r
656         }\r
657       }\r
658     }\r
659 \r
660     #ifndef _7ZIP_ST\r
661     lzma2Props.numTotalThreads = _numThreads;\r
662     #endif\r
663 \r
664     CLocalProgress *lps = new CLocalProgress;\r
665     CMyComPtr<ICompressProgressInfo> progress = lps;\r
666     lps->Init(updateCallback, true);\r
667 \r
668     CCompressProgressWrap progressWrap(progress);\r
669     SRes res = Xz_Encode(&seqOutStream.p, &seqInStream.p, &lzma2Props, False, &progressWrap.p);\r
670     if (res == SZ_OK)\r
671       return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK);\r
672     return SResToHRESULT(res);\r
673   }\r
674   if (indexInArchive != 0)\r
675     return E_INVALIDARG;\r
676   if (_stream)\r
677     RINOK(_stream->Seek(_startPosition, STREAM_SEEK_SET, NULL));\r
678   return NCompress::CopyStream(_stream, outStream, 0);\r
679 }\r
680 \r
681 STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProps)\r
682 {\r
683   COM_TRY_BEGIN\r
684   BeforeSetProperty();\r
685   for (int i = 0; i < numProps; i++)\r
686   {\r
687     RINOK(SetProperty(names[i], values[i]));\r
688   }\r
689   return S_OK;\r
690   COM_TRY_END\r
691 }\r
692 \r
693 #endif\r
694 \r
695 static IInArchive *CreateArc() { return new NArchive::NXz::CHandler; }\r
696 #ifndef EXTRACT_ONLY\r
697 static IOutArchive *CreateArcOut() { return new NArchive::NXz::CHandler; }\r
698 #else\r
699 #define CreateArcOut 0\r
700 #endif\r
701 \r
702 static CArcInfo g_ArcInfo =\r
703   { L"xz", L"xz txz", L"* .tar", 0xC, {0xFD, '7' , 'z', 'X', 'Z', '\0'}, 6, true, CreateArc, CreateArcOut };\r
704 \r
705 REGISTER_ARC(xz)\r
706 \r
707 }}\r