xref: /aosp_15_r20/external/lzma/CPP/7zip/Archive/GzHandler.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1*f6dc9357SAndroid Build Coastguard Worker // GzHandler.cpp
2*f6dc9357SAndroid Build Coastguard Worker 
3*f6dc9357SAndroid Build Coastguard Worker #include "StdAfx.h"
4*f6dc9357SAndroid Build Coastguard Worker 
5*f6dc9357SAndroid Build Coastguard Worker // #include  <stdio.h>
6*f6dc9357SAndroid Build Coastguard Worker 
7*f6dc9357SAndroid Build Coastguard Worker #include "../../../C/CpuArch.h"
8*f6dc9357SAndroid Build Coastguard Worker 
9*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/ComTry.h"
10*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/Defs.h"
11*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/StringConvert.h"
12*f6dc9357SAndroid Build Coastguard Worker 
13*f6dc9357SAndroid Build Coastguard Worker #include "../../Windows/PropVariantUtils.h"
14*f6dc9357SAndroid Build Coastguard Worker #include "../../Windows/TimeUtils.h"
15*f6dc9357SAndroid Build Coastguard Worker 
16*f6dc9357SAndroid Build Coastguard Worker #include "../Common/ProgressUtils.h"
17*f6dc9357SAndroid Build Coastguard Worker #include "../Common/RegisterArc.h"
18*f6dc9357SAndroid Build Coastguard Worker #include "../Common/StreamUtils.h"
19*f6dc9357SAndroid Build Coastguard Worker 
20*f6dc9357SAndroid Build Coastguard Worker #include "../Compress/CopyCoder.h"
21*f6dc9357SAndroid Build Coastguard Worker #include "../Compress/DeflateDecoder.h"
22*f6dc9357SAndroid Build Coastguard Worker #include "../Compress/DeflateEncoder.h"
23*f6dc9357SAndroid Build Coastguard Worker 
24*f6dc9357SAndroid Build Coastguard Worker #include "Common/HandlerOut.h"
25*f6dc9357SAndroid Build Coastguard Worker #include "Common/InStreamWithCRC.h"
26*f6dc9357SAndroid Build Coastguard Worker #include "Common/OutStreamWithCRC.h"
27*f6dc9357SAndroid Build Coastguard Worker 
28*f6dc9357SAndroid Build Coastguard Worker #define Get32(p) GetUi32(p)
29*f6dc9357SAndroid Build Coastguard Worker 
30*f6dc9357SAndroid Build Coastguard Worker using namespace NWindows;
31*f6dc9357SAndroid Build Coastguard Worker 
32*f6dc9357SAndroid Build Coastguard Worker using namespace NCompress;
33*f6dc9357SAndroid Build Coastguard Worker using namespace NDeflate;
34*f6dc9357SAndroid Build Coastguard Worker 
35*f6dc9357SAndroid Build Coastguard Worker namespace NArchive {
36*f6dc9357SAndroid Build Coastguard Worker namespace NGz {
37*f6dc9357SAndroid Build Coastguard Worker 
38*f6dc9357SAndroid Build Coastguard Worker   static const Byte kSignature_0 = 0x1F;
39*f6dc9357SAndroid Build Coastguard Worker   static const Byte kSignature_1 = 0x8B;
40*f6dc9357SAndroid Build Coastguard Worker   static const Byte kSignature_2 = 8; //  NCompressionMethod::kDeflate
41*f6dc9357SAndroid Build Coastguard Worker 
42*f6dc9357SAndroid Build Coastguard Worker   // Latest versions of gzip program don't write comment field to gz archive.
43*f6dc9357SAndroid Build Coastguard Worker   // We also don't write comment field to gz archive.
44*f6dc9357SAndroid Build Coastguard Worker 
45*f6dc9357SAndroid Build Coastguard Worker   namespace NFlags
46*f6dc9357SAndroid Build Coastguard Worker   {
47*f6dc9357SAndroid Build Coastguard Worker     // const Byte kIsText  = 1 << 0;
48*f6dc9357SAndroid Build Coastguard Worker     const Byte kCrc     = 1 << 1;
49*f6dc9357SAndroid Build Coastguard Worker     const Byte kExtra   = 1 << 2;
50*f6dc9357SAndroid Build Coastguard Worker     const Byte kName    = 1 << 3;
51*f6dc9357SAndroid Build Coastguard Worker     const Byte kComment = 1 << 4;
52*f6dc9357SAndroid Build Coastguard Worker     const Byte kReserved = 0xE0;
53*f6dc9357SAndroid Build Coastguard Worker   }
54*f6dc9357SAndroid Build Coastguard Worker 
55*f6dc9357SAndroid Build Coastguard Worker   namespace NExtraFlags
56*f6dc9357SAndroid Build Coastguard Worker   {
57*f6dc9357SAndroid Build Coastguard Worker     const Byte kMaximum = 2;
58*f6dc9357SAndroid Build Coastguard Worker     const Byte kFastest = 4;
59*f6dc9357SAndroid Build Coastguard Worker   }
60*f6dc9357SAndroid Build Coastguard Worker 
61*f6dc9357SAndroid Build Coastguard Worker   namespace NHostOS
62*f6dc9357SAndroid Build Coastguard Worker   {
63*f6dc9357SAndroid Build Coastguard Worker     enum EEnum
64*f6dc9357SAndroid Build Coastguard Worker     {
65*f6dc9357SAndroid Build Coastguard Worker       kFAT = 0,
66*f6dc9357SAndroid Build Coastguard Worker       kAMIGA,
67*f6dc9357SAndroid Build Coastguard Worker       kVMS,
68*f6dc9357SAndroid Build Coastguard Worker       kUnix,
69*f6dc9357SAndroid Build Coastguard Worker       kVM_CMS,
70*f6dc9357SAndroid Build Coastguard Worker       kAtari,
71*f6dc9357SAndroid Build Coastguard Worker       kHPFS,
72*f6dc9357SAndroid Build Coastguard Worker       kMac,
73*f6dc9357SAndroid Build Coastguard Worker       kZ_System,
74*f6dc9357SAndroid Build Coastguard Worker       kCPM,
75*f6dc9357SAndroid Build Coastguard Worker       kTOPS20,
76*f6dc9357SAndroid Build Coastguard Worker       kNTFS,
77*f6dc9357SAndroid Build Coastguard Worker       kQDOS,
78*f6dc9357SAndroid Build Coastguard Worker       kAcorn,
79*f6dc9357SAndroid Build Coastguard Worker       kVFAT,
80*f6dc9357SAndroid Build Coastguard Worker       kMVS,
81*f6dc9357SAndroid Build Coastguard Worker       kBeOS,
82*f6dc9357SAndroid Build Coastguard Worker       kTandem,
83*f6dc9357SAndroid Build Coastguard Worker 
84*f6dc9357SAndroid Build Coastguard Worker       kUnknown = 255
85*f6dc9357SAndroid Build Coastguard Worker     };
86*f6dc9357SAndroid Build Coastguard Worker   }
87*f6dc9357SAndroid Build Coastguard Worker 
88*f6dc9357SAndroid Build Coastguard Worker static const char * const kHostOSes[] =
89*f6dc9357SAndroid Build Coastguard Worker {
90*f6dc9357SAndroid Build Coastguard Worker     "FAT"
91*f6dc9357SAndroid Build Coastguard Worker   , "AMIGA"
92*f6dc9357SAndroid Build Coastguard Worker   , "VMS"
93*f6dc9357SAndroid Build Coastguard Worker   , "Unix"
94*f6dc9357SAndroid Build Coastguard Worker   , "VM/CMS"
95*f6dc9357SAndroid Build Coastguard Worker   , "Atari"
96*f6dc9357SAndroid Build Coastguard Worker   , "HPFS"
97*f6dc9357SAndroid Build Coastguard Worker   , "Macintosh"
98*f6dc9357SAndroid Build Coastguard Worker   , "Z-System"
99*f6dc9357SAndroid Build Coastguard Worker   , "CP/M"
100*f6dc9357SAndroid Build Coastguard Worker   , "TOPS-20"
101*f6dc9357SAndroid Build Coastguard Worker   , "NTFS"
102*f6dc9357SAndroid Build Coastguard Worker   , "SMS/QDOS"
103*f6dc9357SAndroid Build Coastguard Worker   , "Acorn"
104*f6dc9357SAndroid Build Coastguard Worker   , "VFAT"
105*f6dc9357SAndroid Build Coastguard Worker   , "MVS"
106*f6dc9357SAndroid Build Coastguard Worker   , "BeOS"
107*f6dc9357SAndroid Build Coastguard Worker   , "Tandem"
108*f6dc9357SAndroid Build Coastguard Worker   , "OS/400"
109*f6dc9357SAndroid Build Coastguard Worker   , "OS/X"
110*f6dc9357SAndroid Build Coastguard Worker };
111*f6dc9357SAndroid Build Coastguard Worker 
112*f6dc9357SAndroid Build Coastguard Worker 
113*f6dc9357SAndroid Build Coastguard Worker class CItem
114*f6dc9357SAndroid Build Coastguard Worker {
TestFlag(Byte flag) const115*f6dc9357SAndroid Build Coastguard Worker   bool TestFlag(Byte flag) const { return (Flags & flag) != 0; }
116*f6dc9357SAndroid Build Coastguard Worker public:
117*f6dc9357SAndroid Build Coastguard Worker   Byte Flags;
118*f6dc9357SAndroid Build Coastguard Worker   Byte ExtraFlags;
119*f6dc9357SAndroid Build Coastguard Worker   Byte HostOS;
120*f6dc9357SAndroid Build Coastguard Worker   UInt32 Time;
121*f6dc9357SAndroid Build Coastguard Worker   UInt32 Crc;
122*f6dc9357SAndroid Build Coastguard Worker   UInt32 Size32;
123*f6dc9357SAndroid Build Coastguard Worker 
124*f6dc9357SAndroid Build Coastguard Worker   AString Name;
125*f6dc9357SAndroid Build Coastguard Worker   AString Comment;
126*f6dc9357SAndroid Build Coastguard Worker   // CByteBuffer Extra;
127*f6dc9357SAndroid Build Coastguard Worker 
CItem()128*f6dc9357SAndroid Build Coastguard Worker   CItem():
129*f6dc9357SAndroid Build Coastguard Worker     Flags(0),
130*f6dc9357SAndroid Build Coastguard Worker     ExtraFlags(0),
131*f6dc9357SAndroid Build Coastguard Worker     HostOS(0),
132*f6dc9357SAndroid Build Coastguard Worker     Time(0),
133*f6dc9357SAndroid Build Coastguard Worker     Crc(0),
134*f6dc9357SAndroid Build Coastguard Worker     Size32(0) {}
135*f6dc9357SAndroid Build Coastguard Worker 
Clear()136*f6dc9357SAndroid Build Coastguard Worker   void Clear()
137*f6dc9357SAndroid Build Coastguard Worker   {
138*f6dc9357SAndroid Build Coastguard Worker     Name.Empty();
139*f6dc9357SAndroid Build Coastguard Worker     Comment.Empty();
140*f6dc9357SAndroid Build Coastguard Worker     // Extra.Free();
141*f6dc9357SAndroid Build Coastguard Worker   }
142*f6dc9357SAndroid Build Coastguard Worker 
CopyMetaPropsFrom(const CItem & a)143*f6dc9357SAndroid Build Coastguard Worker   void CopyMetaPropsFrom(const CItem &a)
144*f6dc9357SAndroid Build Coastguard Worker   {
145*f6dc9357SAndroid Build Coastguard Worker     Flags = a.Flags;
146*f6dc9357SAndroid Build Coastguard Worker     HostOS = a.HostOS;
147*f6dc9357SAndroid Build Coastguard Worker     Time = a.Time;
148*f6dc9357SAndroid Build Coastguard Worker     Name = a.Name;
149*f6dc9357SAndroid Build Coastguard Worker     Comment = a.Comment;
150*f6dc9357SAndroid Build Coastguard Worker     // Extra = a.Extra;
151*f6dc9357SAndroid Build Coastguard Worker   }
152*f6dc9357SAndroid Build Coastguard Worker 
CopyDataPropsFrom(const CItem & a)153*f6dc9357SAndroid Build Coastguard Worker   void CopyDataPropsFrom(const CItem &a)
154*f6dc9357SAndroid Build Coastguard Worker   {
155*f6dc9357SAndroid Build Coastguard Worker     ExtraFlags = a.ExtraFlags;
156*f6dc9357SAndroid Build Coastguard Worker     Crc = a.Crc;
157*f6dc9357SAndroid Build Coastguard Worker     Size32 = a.Size32;
158*f6dc9357SAndroid Build Coastguard Worker   }
159*f6dc9357SAndroid Build Coastguard Worker 
160*f6dc9357SAndroid Build Coastguard Worker   // bool IsText() const { return TestFlag(NFlags::kIsText); }
HeaderCrcIsPresent() const161*f6dc9357SAndroid Build Coastguard Worker   bool HeaderCrcIsPresent() const { return TestFlag(NFlags::kCrc); }
ExtraFieldIsPresent() const162*f6dc9357SAndroid Build Coastguard Worker   bool ExtraFieldIsPresent() const { return TestFlag(NFlags::kExtra); }
NameIsPresent() const163*f6dc9357SAndroid Build Coastguard Worker   bool NameIsPresent() const { return TestFlag(NFlags::kName); }
CommentIsPresent() const164*f6dc9357SAndroid Build Coastguard Worker   bool CommentIsPresent() const { return TestFlag(NFlags::kComment); }
IsSupported() const165*f6dc9357SAndroid Build Coastguard Worker   bool IsSupported() const { return (Flags & NFlags::kReserved) == 0; }
166*f6dc9357SAndroid Build Coastguard Worker 
167*f6dc9357SAndroid Build Coastguard Worker   HRESULT ReadHeader(NDecoder::CCOMCoder *stream);
168*f6dc9357SAndroid Build Coastguard Worker   HRESULT ReadFooter1(NDecoder::CCOMCoder *stream);
169*f6dc9357SAndroid Build Coastguard Worker   HRESULT ReadFooter2(ISequentialInStream *stream);
170*f6dc9357SAndroid Build Coastguard Worker 
171*f6dc9357SAndroid Build Coastguard Worker   HRESULT WriteHeader(ISequentialOutStream *stream);
172*f6dc9357SAndroid Build Coastguard Worker   HRESULT WriteFooter(ISequentialOutStream *stream);
173*f6dc9357SAndroid Build Coastguard Worker };
174*f6dc9357SAndroid Build Coastguard Worker 
ReadBytes(NDecoder::CCOMCoder * stream,Byte * data,UInt32 size)175*f6dc9357SAndroid Build Coastguard Worker static HRESULT ReadBytes(NDecoder::CCOMCoder *stream, Byte *data, UInt32 size)
176*f6dc9357SAndroid Build Coastguard Worker {
177*f6dc9357SAndroid Build Coastguard Worker   for (UInt32 i = 0; i < size; i++)
178*f6dc9357SAndroid Build Coastguard Worker     data[i] = stream->ReadAlignedByte();
179*f6dc9357SAndroid Build Coastguard Worker   return stream->InputEofError() ? S_FALSE : S_OK;
180*f6dc9357SAndroid Build Coastguard Worker }
181*f6dc9357SAndroid Build Coastguard Worker 
SkipBytes(NDecoder::CCOMCoder * stream,UInt32 size)182*f6dc9357SAndroid Build Coastguard Worker static HRESULT SkipBytes(NDecoder::CCOMCoder *stream, UInt32 size)
183*f6dc9357SAndroid Build Coastguard Worker {
184*f6dc9357SAndroid Build Coastguard Worker   for (UInt32 i = 0; i < size; i++)
185*f6dc9357SAndroid Build Coastguard Worker     stream->ReadAlignedByte();
186*f6dc9357SAndroid Build Coastguard Worker   return stream->InputEofError() ? S_FALSE : S_OK;
187*f6dc9357SAndroid Build Coastguard Worker }
188*f6dc9357SAndroid Build Coastguard Worker 
ReadUInt16(NDecoder::CCOMCoder * stream,UInt32 & value)189*f6dc9357SAndroid Build Coastguard Worker static HRESULT ReadUInt16(NDecoder::CCOMCoder *stream, UInt32 &value /* , UInt32 &crc */)
190*f6dc9357SAndroid Build Coastguard Worker {
191*f6dc9357SAndroid Build Coastguard Worker   value = 0;
192*f6dc9357SAndroid Build Coastguard Worker   for (int i = 0; i < 2; i++)
193*f6dc9357SAndroid Build Coastguard Worker   {
194*f6dc9357SAndroid Build Coastguard Worker     Byte b = stream->ReadAlignedByte();
195*f6dc9357SAndroid Build Coastguard Worker     if (stream->InputEofError())
196*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
197*f6dc9357SAndroid Build Coastguard Worker     // crc = CRC_UPDATE_BYTE(crc, b);
198*f6dc9357SAndroid Build Coastguard Worker     value |= ((UInt32)(b) << (8 * i));
199*f6dc9357SAndroid Build Coastguard Worker   }
200*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
201*f6dc9357SAndroid Build Coastguard Worker }
202*f6dc9357SAndroid Build Coastguard Worker 
ReadString(NDecoder::CCOMCoder * stream,AString & s,size_t limit)203*f6dc9357SAndroid Build Coastguard Worker static HRESULT ReadString(NDecoder::CCOMCoder *stream, AString &s, size_t limit /* , UInt32 &crc */)
204*f6dc9357SAndroid Build Coastguard Worker {
205*f6dc9357SAndroid Build Coastguard Worker   s.Empty();
206*f6dc9357SAndroid Build Coastguard Worker   for (size_t i = 0; i < limit; i++)
207*f6dc9357SAndroid Build Coastguard Worker   {
208*f6dc9357SAndroid Build Coastguard Worker     const Byte b = stream->ReadAlignedByte();
209*f6dc9357SAndroid Build Coastguard Worker     if (stream->InputEofError())
210*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
211*f6dc9357SAndroid Build Coastguard Worker     // crc = CRC_UPDATE_BYTE(crc, b);
212*f6dc9357SAndroid Build Coastguard Worker     if (b == 0)
213*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
214*f6dc9357SAndroid Build Coastguard Worker     s.Add_Char((char)b);
215*f6dc9357SAndroid Build Coastguard Worker   }
216*f6dc9357SAndroid Build Coastguard Worker   return S_FALSE;
217*f6dc9357SAndroid Build Coastguard Worker }
218*f6dc9357SAndroid Build Coastguard Worker 
Is_Deflate(const Byte * p,size_t size)219*f6dc9357SAndroid Build Coastguard Worker static UInt32 Is_Deflate(const Byte *p, size_t size)
220*f6dc9357SAndroid Build Coastguard Worker {
221*f6dc9357SAndroid Build Coastguard Worker   if (size < 1)
222*f6dc9357SAndroid Build Coastguard Worker     return k_IsArc_Res_NEED_MORE;
223*f6dc9357SAndroid Build Coastguard Worker   Byte b = *p;
224*f6dc9357SAndroid Build Coastguard Worker   p++;
225*f6dc9357SAndroid Build Coastguard Worker   size--;
226*f6dc9357SAndroid Build Coastguard Worker   unsigned type = ((unsigned)b >> 1) & 3;
227*f6dc9357SAndroid Build Coastguard Worker   if (type == 3)
228*f6dc9357SAndroid Build Coastguard Worker     return k_IsArc_Res_NO;
229*f6dc9357SAndroid Build Coastguard Worker   if (type == 0)
230*f6dc9357SAndroid Build Coastguard Worker   {
231*f6dc9357SAndroid Build Coastguard Worker     // Stored (uncompreessed data)
232*f6dc9357SAndroid Build Coastguard Worker     if ((b >> 3) != 0)
233*f6dc9357SAndroid Build Coastguard Worker       return k_IsArc_Res_NO;
234*f6dc9357SAndroid Build Coastguard Worker     if (size < 4)
235*f6dc9357SAndroid Build Coastguard Worker       return k_IsArc_Res_NEED_MORE;
236*f6dc9357SAndroid Build Coastguard Worker     UInt16 r = (UInt16)~GetUi16(p + 2);
237*f6dc9357SAndroid Build Coastguard Worker     if (GetUi16(p) != r)
238*f6dc9357SAndroid Build Coastguard Worker       return k_IsArc_Res_NO;
239*f6dc9357SAndroid Build Coastguard Worker   }
240*f6dc9357SAndroid Build Coastguard Worker   else if (type == 2)
241*f6dc9357SAndroid Build Coastguard Worker   {
242*f6dc9357SAndroid Build Coastguard Worker     // Dynamic Huffman
243*f6dc9357SAndroid Build Coastguard Worker     if (size < 1)
244*f6dc9357SAndroid Build Coastguard Worker       return k_IsArc_Res_NEED_MORE;
245*f6dc9357SAndroid Build Coastguard Worker     if ((*p & 0x1F) + 1 > 30) // numDistLevels
246*f6dc9357SAndroid Build Coastguard Worker       return k_IsArc_Res_NO;
247*f6dc9357SAndroid Build Coastguard Worker   }
248*f6dc9357SAndroid Build Coastguard Worker   return k_IsArc_Res_YES;
249*f6dc9357SAndroid Build Coastguard Worker }
250*f6dc9357SAndroid Build Coastguard Worker 
251*f6dc9357SAndroid Build Coastguard Worker static const unsigned kNameMaxLen = 1 << 12;
252*f6dc9357SAndroid Build Coastguard Worker static const unsigned kCommentMaxLen = 1 << 16;
253*f6dc9357SAndroid Build Coastguard Worker 
IsArc_Gz(const Byte * p,size_t size)254*f6dc9357SAndroid Build Coastguard Worker API_FUNC_static_IsArc IsArc_Gz(const Byte *p, size_t size)
255*f6dc9357SAndroid Build Coastguard Worker {
256*f6dc9357SAndroid Build Coastguard Worker   if (size < 10)
257*f6dc9357SAndroid Build Coastguard Worker     return k_IsArc_Res_NEED_MORE;
258*f6dc9357SAndroid Build Coastguard Worker   if (p[0] != kSignature_0 ||
259*f6dc9357SAndroid Build Coastguard Worker       p[1] != kSignature_1 ||
260*f6dc9357SAndroid Build Coastguard Worker       p[2] != kSignature_2)
261*f6dc9357SAndroid Build Coastguard Worker     return k_IsArc_Res_NO;
262*f6dc9357SAndroid Build Coastguard Worker 
263*f6dc9357SAndroid Build Coastguard Worker   const Byte flags = p[3];
264*f6dc9357SAndroid Build Coastguard Worker   if ((flags & NFlags::kReserved) != 0)
265*f6dc9357SAndroid Build Coastguard Worker     return k_IsArc_Res_NO;
266*f6dc9357SAndroid Build Coastguard Worker 
267*f6dc9357SAndroid Build Coastguard Worker   const Byte extraFlags = p[8];
268*f6dc9357SAndroid Build Coastguard Worker   // maybe that flag can have another values for some gz archives?
269*f6dc9357SAndroid Build Coastguard Worker   if (extraFlags != 0 &&
270*f6dc9357SAndroid Build Coastguard Worker       extraFlags != NExtraFlags::kMaximum &&
271*f6dc9357SAndroid Build Coastguard Worker       extraFlags != NExtraFlags::kFastest)
272*f6dc9357SAndroid Build Coastguard Worker     return k_IsArc_Res_NO;
273*f6dc9357SAndroid Build Coastguard Worker 
274*f6dc9357SAndroid Build Coastguard Worker   size -= 10;
275*f6dc9357SAndroid Build Coastguard Worker   p += 10;
276*f6dc9357SAndroid Build Coastguard Worker 
277*f6dc9357SAndroid Build Coastguard Worker   if ((flags & NFlags::kExtra) != 0)
278*f6dc9357SAndroid Build Coastguard Worker   {
279*f6dc9357SAndroid Build Coastguard Worker     if (size < 2)
280*f6dc9357SAndroid Build Coastguard Worker       return k_IsArc_Res_NEED_MORE;
281*f6dc9357SAndroid Build Coastguard Worker     unsigned xlen = GetUi16(p);
282*f6dc9357SAndroid Build Coastguard Worker     size -= 2;
283*f6dc9357SAndroid Build Coastguard Worker     p += 2;
284*f6dc9357SAndroid Build Coastguard Worker     while (xlen != 0)
285*f6dc9357SAndroid Build Coastguard Worker     {
286*f6dc9357SAndroid Build Coastguard Worker       if (xlen < 4)
287*f6dc9357SAndroid Build Coastguard Worker         return k_IsArc_Res_NO;
288*f6dc9357SAndroid Build Coastguard Worker       if (size < 4)
289*f6dc9357SAndroid Build Coastguard Worker         return k_IsArc_Res_NEED_MORE;
290*f6dc9357SAndroid Build Coastguard Worker       const unsigned len = GetUi16(p + 2);
291*f6dc9357SAndroid Build Coastguard Worker       size -= 4;
292*f6dc9357SAndroid Build Coastguard Worker       xlen -= 4;
293*f6dc9357SAndroid Build Coastguard Worker       p += 4;
294*f6dc9357SAndroid Build Coastguard Worker       if (len > xlen)
295*f6dc9357SAndroid Build Coastguard Worker         return k_IsArc_Res_NO;
296*f6dc9357SAndroid Build Coastguard Worker       if (len > size)
297*f6dc9357SAndroid Build Coastguard Worker         return k_IsArc_Res_NEED_MORE;
298*f6dc9357SAndroid Build Coastguard Worker       size -= len;
299*f6dc9357SAndroid Build Coastguard Worker       xlen -= len;
300*f6dc9357SAndroid Build Coastguard Worker       p += len;
301*f6dc9357SAndroid Build Coastguard Worker     }
302*f6dc9357SAndroid Build Coastguard Worker   }
303*f6dc9357SAndroid Build Coastguard Worker 
304*f6dc9357SAndroid Build Coastguard Worker   if ((flags & NFlags::kName) != 0)
305*f6dc9357SAndroid Build Coastguard Worker   {
306*f6dc9357SAndroid Build Coastguard Worker     size_t limit = kNameMaxLen;
307*f6dc9357SAndroid Build Coastguard Worker     if (limit > size)
308*f6dc9357SAndroid Build Coastguard Worker       limit = size;
309*f6dc9357SAndroid Build Coastguard Worker     size_t i;
310*f6dc9357SAndroid Build Coastguard Worker     for (i = 0; i < limit && p[i] != 0; i++);
311*f6dc9357SAndroid Build Coastguard Worker     if (i == size)
312*f6dc9357SAndroid Build Coastguard Worker       return k_IsArc_Res_NEED_MORE;
313*f6dc9357SAndroid Build Coastguard Worker     if (i == limit)
314*f6dc9357SAndroid Build Coastguard Worker       return k_IsArc_Res_NO;
315*f6dc9357SAndroid Build Coastguard Worker     i++;
316*f6dc9357SAndroid Build Coastguard Worker     p += i;
317*f6dc9357SAndroid Build Coastguard Worker     size -= i;
318*f6dc9357SAndroid Build Coastguard Worker   }
319*f6dc9357SAndroid Build Coastguard Worker 
320*f6dc9357SAndroid Build Coastguard Worker   if ((flags & NFlags::kComment) != 0)
321*f6dc9357SAndroid Build Coastguard Worker   {
322*f6dc9357SAndroid Build Coastguard Worker     size_t limit = kCommentMaxLen;
323*f6dc9357SAndroid Build Coastguard Worker     if (limit > size)
324*f6dc9357SAndroid Build Coastguard Worker       limit = size;
325*f6dc9357SAndroid Build Coastguard Worker     size_t i;
326*f6dc9357SAndroid Build Coastguard Worker     for (i = 0; i < limit && p[i] != 0; i++);
327*f6dc9357SAndroid Build Coastguard Worker     if (i == size)
328*f6dc9357SAndroid Build Coastguard Worker       return k_IsArc_Res_NEED_MORE;
329*f6dc9357SAndroid Build Coastguard Worker     if (i == limit)
330*f6dc9357SAndroid Build Coastguard Worker       return k_IsArc_Res_NO;
331*f6dc9357SAndroid Build Coastguard Worker     i++;
332*f6dc9357SAndroid Build Coastguard Worker     p += i;
333*f6dc9357SAndroid Build Coastguard Worker     size -= i;
334*f6dc9357SAndroid Build Coastguard Worker   }
335*f6dc9357SAndroid Build Coastguard Worker 
336*f6dc9357SAndroid Build Coastguard Worker   if ((flags & NFlags::kCrc) != 0)
337*f6dc9357SAndroid Build Coastguard Worker   {
338*f6dc9357SAndroid Build Coastguard Worker     if (size < 2)
339*f6dc9357SAndroid Build Coastguard Worker       return k_IsArc_Res_NEED_MORE;
340*f6dc9357SAndroid Build Coastguard Worker     p += 2;
341*f6dc9357SAndroid Build Coastguard Worker     size -= 2;
342*f6dc9357SAndroid Build Coastguard Worker   }
343*f6dc9357SAndroid Build Coastguard Worker 
344*f6dc9357SAndroid Build Coastguard Worker   return Is_Deflate(p, size);
345*f6dc9357SAndroid Build Coastguard Worker }
346*f6dc9357SAndroid Build Coastguard Worker }
347*f6dc9357SAndroid Build Coastguard Worker 
ReadHeader(NDecoder::CCOMCoder * stream)348*f6dc9357SAndroid Build Coastguard Worker HRESULT CItem::ReadHeader(NDecoder::CCOMCoder *stream)
349*f6dc9357SAndroid Build Coastguard Worker {
350*f6dc9357SAndroid Build Coastguard Worker   Clear();
351*f6dc9357SAndroid Build Coastguard Worker 
352*f6dc9357SAndroid Build Coastguard Worker   // Header-CRC field had another meaning in old version of gzip!
353*f6dc9357SAndroid Build Coastguard Worker   // UInt32 crc = CRC_INIT_VAL;
354*f6dc9357SAndroid Build Coastguard Worker   Byte buf[10];
355*f6dc9357SAndroid Build Coastguard Worker 
356*f6dc9357SAndroid Build Coastguard Worker   RINOK(ReadBytes(stream, buf, 10))
357*f6dc9357SAndroid Build Coastguard Worker 
358*f6dc9357SAndroid Build Coastguard Worker   if (buf[0] != kSignature_0 ||
359*f6dc9357SAndroid Build Coastguard Worker       buf[1] != kSignature_1 ||
360*f6dc9357SAndroid Build Coastguard Worker       buf[2] != kSignature_2)
361*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
362*f6dc9357SAndroid Build Coastguard Worker 
363*f6dc9357SAndroid Build Coastguard Worker   Flags = buf[3];
364*f6dc9357SAndroid Build Coastguard Worker   if (!IsSupported())
365*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
366*f6dc9357SAndroid Build Coastguard Worker 
367*f6dc9357SAndroid Build Coastguard Worker   Time = Get32(buf + 4);
368*f6dc9357SAndroid Build Coastguard Worker   ExtraFlags = buf[8];
369*f6dc9357SAndroid Build Coastguard Worker   HostOS = buf[9];
370*f6dc9357SAndroid Build Coastguard Worker 
371*f6dc9357SAndroid Build Coastguard Worker   // crc = CrcUpdate(crc, buf, 10);
372*f6dc9357SAndroid Build Coastguard Worker 
373*f6dc9357SAndroid Build Coastguard Worker   if (ExtraFieldIsPresent())
374*f6dc9357SAndroid Build Coastguard Worker   {
375*f6dc9357SAndroid Build Coastguard Worker     UInt32 xlen;
376*f6dc9357SAndroid Build Coastguard Worker     RINOK(ReadUInt16(stream, xlen /* , crc */))
377*f6dc9357SAndroid Build Coastguard Worker     RINOK(SkipBytes(stream, xlen))
378*f6dc9357SAndroid Build Coastguard Worker     // Extra.SetCapacity(xlen);
379*f6dc9357SAndroid Build Coastguard Worker     // RINOK(ReadStream_FALSE(stream, Extra, xlen));
380*f6dc9357SAndroid Build Coastguard Worker     // crc = CrcUpdate(crc, Extra, xlen);
381*f6dc9357SAndroid Build Coastguard Worker   }
382*f6dc9357SAndroid Build Coastguard Worker   if (NameIsPresent())
383*f6dc9357SAndroid Build Coastguard Worker     RINOK(ReadString(stream, Name, kNameMaxLen /* , crc */))
384*f6dc9357SAndroid Build Coastguard Worker   if (CommentIsPresent())
385*f6dc9357SAndroid Build Coastguard Worker     RINOK(ReadString(stream, Comment, kCommentMaxLen /* , crc */))
386*f6dc9357SAndroid Build Coastguard Worker 
387*f6dc9357SAndroid Build Coastguard Worker   if (HeaderCrcIsPresent())
388*f6dc9357SAndroid Build Coastguard Worker   {
389*f6dc9357SAndroid Build Coastguard Worker     UInt32 headerCRC;
390*f6dc9357SAndroid Build Coastguard Worker     // UInt32 dummy = 0;
391*f6dc9357SAndroid Build Coastguard Worker     RINOK(ReadUInt16(stream, headerCRC /* , dummy */))
392*f6dc9357SAndroid Build Coastguard Worker     /*
393*f6dc9357SAndroid Build Coastguard Worker     if ((UInt16)CRC_GET_DIGEST(crc) != headerCRC)
394*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
395*f6dc9357SAndroid Build Coastguard Worker     */
396*f6dc9357SAndroid Build Coastguard Worker   }
397*f6dc9357SAndroid Build Coastguard Worker   return stream->InputEofError() ? S_FALSE : S_OK;
398*f6dc9357SAndroid Build Coastguard Worker }
399*f6dc9357SAndroid Build Coastguard Worker 
ReadFooter1(NDecoder::CCOMCoder * stream)400*f6dc9357SAndroid Build Coastguard Worker HRESULT CItem::ReadFooter1(NDecoder::CCOMCoder *stream)
401*f6dc9357SAndroid Build Coastguard Worker {
402*f6dc9357SAndroid Build Coastguard Worker   Byte buf[8];
403*f6dc9357SAndroid Build Coastguard Worker   RINOK(ReadBytes(stream, buf, 8))
404*f6dc9357SAndroid Build Coastguard Worker   Crc = Get32(buf);
405*f6dc9357SAndroid Build Coastguard Worker   Size32 = Get32(buf + 4);
406*f6dc9357SAndroid Build Coastguard Worker   return stream->InputEofError() ? S_FALSE : S_OK;
407*f6dc9357SAndroid Build Coastguard Worker }
408*f6dc9357SAndroid Build Coastguard Worker 
ReadFooter2(ISequentialInStream * stream)409*f6dc9357SAndroid Build Coastguard Worker HRESULT CItem::ReadFooter2(ISequentialInStream *stream)
410*f6dc9357SAndroid Build Coastguard Worker {
411*f6dc9357SAndroid Build Coastguard Worker   Byte buf[8];
412*f6dc9357SAndroid Build Coastguard Worker   RINOK(ReadStream_FALSE(stream, buf, 8))
413*f6dc9357SAndroid Build Coastguard Worker   Crc = Get32(buf);
414*f6dc9357SAndroid Build Coastguard Worker   Size32 = Get32(buf + 4);
415*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
416*f6dc9357SAndroid Build Coastguard Worker }
417*f6dc9357SAndroid Build Coastguard Worker 
WriteHeader(ISequentialOutStream * stream)418*f6dc9357SAndroid Build Coastguard Worker HRESULT CItem::WriteHeader(ISequentialOutStream *stream)
419*f6dc9357SAndroid Build Coastguard Worker {
420*f6dc9357SAndroid Build Coastguard Worker   Byte buf[10];
421*f6dc9357SAndroid Build Coastguard Worker   buf[0] = kSignature_0;
422*f6dc9357SAndroid Build Coastguard Worker   buf[1] = kSignature_1;
423*f6dc9357SAndroid Build Coastguard Worker   buf[2] = kSignature_2;
424*f6dc9357SAndroid Build Coastguard Worker   buf[3] = (Byte)(Flags & NFlags::kName);
425*f6dc9357SAndroid Build Coastguard Worker   // buf[3] |= NFlags::kCrc;
426*f6dc9357SAndroid Build Coastguard Worker   SetUi32(buf + 4, Time)
427*f6dc9357SAndroid Build Coastguard Worker   buf[8] = ExtraFlags;
428*f6dc9357SAndroid Build Coastguard Worker   buf[9] = HostOS;
429*f6dc9357SAndroid Build Coastguard Worker   RINOK(WriteStream(stream, buf, 10))
430*f6dc9357SAndroid Build Coastguard Worker   // crc = CrcUpdate(CRC_INIT_VAL, buf, 10);
431*f6dc9357SAndroid Build Coastguard Worker   if (NameIsPresent())
432*f6dc9357SAndroid Build Coastguard Worker   {
433*f6dc9357SAndroid Build Coastguard Worker     // crc = CrcUpdate(crc, (const char *)Name, Name.Len() + 1);
434*f6dc9357SAndroid Build Coastguard Worker     RINOK(WriteStream(stream, (const char *)Name, Name.Len() + 1))
435*f6dc9357SAndroid Build Coastguard Worker   }
436*f6dc9357SAndroid Build Coastguard Worker   // SetUi16(buf, (UInt16)CRC_GET_DIGEST(crc));
437*f6dc9357SAndroid Build Coastguard Worker   // RINOK(WriteStream(stream, buf, 2));
438*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
439*f6dc9357SAndroid Build Coastguard Worker }
440*f6dc9357SAndroid Build Coastguard Worker 
WriteFooter(ISequentialOutStream * stream)441*f6dc9357SAndroid Build Coastguard Worker HRESULT CItem::WriteFooter(ISequentialOutStream *stream)
442*f6dc9357SAndroid Build Coastguard Worker {
443*f6dc9357SAndroid Build Coastguard Worker   Byte buf[8];
444*f6dc9357SAndroid Build Coastguard Worker   SetUi32(buf, Crc)
445*f6dc9357SAndroid Build Coastguard Worker   SetUi32(buf + 4, Size32)
446*f6dc9357SAndroid Build Coastguard Worker   return WriteStream(stream, buf, 8);
447*f6dc9357SAndroid Build Coastguard Worker }
448*f6dc9357SAndroid Build Coastguard Worker 
449*f6dc9357SAndroid Build Coastguard Worker Z7_CLASS_IMP_CHandler_IInArchive_3(
450*f6dc9357SAndroid Build Coastguard Worker   IArchiveOpenSeq,
451*f6dc9357SAndroid Build Coastguard Worker   IOutArchive,
452*f6dc9357SAndroid Build Coastguard Worker   ISetProperties
453*f6dc9357SAndroid Build Coastguard Worker )
454*f6dc9357SAndroid Build Coastguard Worker   CItem _item;
455*f6dc9357SAndroid Build Coastguard Worker 
456*f6dc9357SAndroid Build Coastguard Worker   bool _isArc;
457*f6dc9357SAndroid Build Coastguard Worker   bool _needSeekToStart;
458*f6dc9357SAndroid Build Coastguard Worker   bool _dataAfterEnd;
459*f6dc9357SAndroid Build Coastguard Worker   bool _needMoreInput;
460*f6dc9357SAndroid Build Coastguard Worker 
461*f6dc9357SAndroid Build Coastguard Worker   bool _packSize_Defined;
462*f6dc9357SAndroid Build Coastguard Worker   bool _unpackSize_Defined;
463*f6dc9357SAndroid Build Coastguard Worker   bool _numStreams_Defined;
464*f6dc9357SAndroid Build Coastguard Worker 
465*f6dc9357SAndroid Build Coastguard Worker   UInt64 _packSize;
466*f6dc9357SAndroid Build Coastguard Worker   UInt64 _unpackSize; // real unpack size (NOT from footer)
467*f6dc9357SAndroid Build Coastguard Worker   UInt64 _numStreams;
468*f6dc9357SAndroid Build Coastguard Worker   UInt64 _headerSize; // only start header (without footer)
469*f6dc9357SAndroid Build Coastguard Worker 
470*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<IInStream> _stream;
471*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2<ICompressCoder, NDecoder::CCOMCoder> _decoder;
472*f6dc9357SAndroid Build Coastguard Worker 
473*f6dc9357SAndroid Build Coastguard Worker   CSingleMethodProps _props;
474*f6dc9357SAndroid Build Coastguard Worker   CHandlerTimeOptions _timeOptions;
475*f6dc9357SAndroid Build Coastguard Worker 
476*f6dc9357SAndroid Build Coastguard Worker public:
477*f6dc9357SAndroid Build Coastguard Worker   CHandler():
478*f6dc9357SAndroid Build Coastguard Worker       _isArc(false)
479*f6dc9357SAndroid Build Coastguard Worker       {}
480*f6dc9357SAndroid Build Coastguard Worker 
481*f6dc9357SAndroid Build Coastguard Worker   void CreateDecoder()
482*f6dc9357SAndroid Build Coastguard Worker   {
483*f6dc9357SAndroid Build Coastguard Worker     _decoder.Create_if_Empty();
484*f6dc9357SAndroid Build Coastguard Worker   }
485*f6dc9357SAndroid Build Coastguard Worker };
486*f6dc9357SAndroid Build Coastguard Worker 
487*f6dc9357SAndroid Build Coastguard Worker static const Byte kProps[] =
488*f6dc9357SAndroid Build Coastguard Worker {
489*f6dc9357SAndroid Build Coastguard Worker   kpidPath,
490*f6dc9357SAndroid Build Coastguard Worker   kpidSize,
491*f6dc9357SAndroid Build Coastguard Worker   kpidPackSize,
492*f6dc9357SAndroid Build Coastguard Worker   kpidMTime,
493*f6dc9357SAndroid Build Coastguard Worker   kpidHostOS,
494*f6dc9357SAndroid Build Coastguard Worker   kpidCRC
495*f6dc9357SAndroid Build Coastguard Worker   // kpidComment
496*f6dc9357SAndroid Build Coastguard Worker };
497*f6dc9357SAndroid Build Coastguard Worker 
498*f6dc9357SAndroid Build Coastguard Worker static const Byte kArcProps[] =
499*f6dc9357SAndroid Build Coastguard Worker {
500*f6dc9357SAndroid Build Coastguard Worker   kpidHeadersSize,
501*f6dc9357SAndroid Build Coastguard Worker   kpidNumStreams
502*f6dc9357SAndroid Build Coastguard Worker };
503*f6dc9357SAndroid Build Coastguard Worker 
504*f6dc9357SAndroid Build Coastguard Worker 
505*f6dc9357SAndroid Build Coastguard Worker IMP_IInArchive_Props
506*f6dc9357SAndroid Build Coastguard Worker IMP_IInArchive_ArcProps
507*f6dc9357SAndroid Build Coastguard Worker 
508*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
509*f6dc9357SAndroid Build Coastguard Worker {
510*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
511*f6dc9357SAndroid Build Coastguard Worker   NCOM::CPropVariant prop;
512*f6dc9357SAndroid Build Coastguard Worker   switch (propID)
513*f6dc9357SAndroid Build Coastguard Worker   {
514*f6dc9357SAndroid Build Coastguard Worker     case kpidPhySize: if (_packSize_Defined) prop = _packSize; break;
515*f6dc9357SAndroid Build Coastguard Worker     case kpidUnpackSize: if (_unpackSize_Defined) prop = _unpackSize; break;
516*f6dc9357SAndroid Build Coastguard Worker     case kpidNumStreams: if (_numStreams_Defined) prop = _numStreams; break;
517*f6dc9357SAndroid Build Coastguard Worker     case kpidHeadersSize: if (_headerSize != 0) prop = _headerSize; break;
518*f6dc9357SAndroid Build Coastguard Worker     case kpidErrorFlags:
519*f6dc9357SAndroid Build Coastguard Worker     {
520*f6dc9357SAndroid Build Coastguard Worker       UInt32 v = 0;
521*f6dc9357SAndroid Build Coastguard Worker       if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;
522*f6dc9357SAndroid Build Coastguard Worker       if (_needMoreInput) v |= kpv_ErrorFlags_UnexpectedEnd;
523*f6dc9357SAndroid Build Coastguard Worker       if (_dataAfterEnd) v |= kpv_ErrorFlags_DataAfterEnd;
524*f6dc9357SAndroid Build Coastguard Worker       prop = v;
525*f6dc9357SAndroid Build Coastguard Worker       break;
526*f6dc9357SAndroid Build Coastguard Worker     }
527*f6dc9357SAndroid Build Coastguard Worker     case kpidName:
528*f6dc9357SAndroid Build Coastguard Worker       if (_item.NameIsPresent())
529*f6dc9357SAndroid Build Coastguard Worker       {
530*f6dc9357SAndroid Build Coastguard Worker         UString s = MultiByteToUnicodeString(_item.Name, CP_ACP);
531*f6dc9357SAndroid Build Coastguard Worker         s += ".gz";
532*f6dc9357SAndroid Build Coastguard Worker         prop = s;
533*f6dc9357SAndroid Build Coastguard Worker       }
534*f6dc9357SAndroid Build Coastguard Worker       break;
535*f6dc9357SAndroid Build Coastguard Worker     default: break;
536*f6dc9357SAndroid Build Coastguard Worker   }
537*f6dc9357SAndroid Build Coastguard Worker   prop.Detach(value);
538*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
539*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
540*f6dc9357SAndroid Build Coastguard Worker }
541*f6dc9357SAndroid Build Coastguard Worker 
542*f6dc9357SAndroid Build Coastguard Worker 
543*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
544*f6dc9357SAndroid Build Coastguard Worker {
545*f6dc9357SAndroid Build Coastguard Worker   *numItems = 1;
546*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
547*f6dc9357SAndroid Build Coastguard Worker }
548*f6dc9357SAndroid Build Coastguard Worker 
549*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value))
550*f6dc9357SAndroid Build Coastguard Worker {
551*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
552*f6dc9357SAndroid Build Coastguard Worker   NCOM::CPropVariant prop;
553*f6dc9357SAndroid Build Coastguard Worker   switch (propID)
554*f6dc9357SAndroid Build Coastguard Worker   {
555*f6dc9357SAndroid Build Coastguard Worker     case kpidPath:
556*f6dc9357SAndroid Build Coastguard Worker       if (_item.NameIsPresent())
557*f6dc9357SAndroid Build Coastguard Worker         prop = MultiByteToUnicodeString(_item.Name, CP_ACP);
558*f6dc9357SAndroid Build Coastguard Worker       break;
559*f6dc9357SAndroid Build Coastguard Worker     // case kpidComment: if (_item.CommentIsPresent()) prop = MultiByteToUnicodeString(_item.Comment, CP_ACP); break;
560*f6dc9357SAndroid Build Coastguard Worker     case kpidMTime:
561*f6dc9357SAndroid Build Coastguard Worker       // gzip specification: MTIME = 0 means no time stamp is available.
562*f6dc9357SAndroid Build Coastguard Worker       if (_item.Time != 0)
563*f6dc9357SAndroid Build Coastguard Worker         PropVariant_SetFrom_UnixTime(prop, _item.Time);
564*f6dc9357SAndroid Build Coastguard Worker       break;
565*f6dc9357SAndroid Build Coastguard Worker     case kpidTimeType:
566*f6dc9357SAndroid Build Coastguard Worker       if (_item.Time != 0)
567*f6dc9357SAndroid Build Coastguard Worker         prop = (UInt32)NFileTimeType::kUnix;
568*f6dc9357SAndroid Build Coastguard Worker       break;
569*f6dc9357SAndroid Build Coastguard Worker     case kpidSize:
570*f6dc9357SAndroid Build Coastguard Worker     {
571*f6dc9357SAndroid Build Coastguard Worker       if (_unpackSize_Defined)
572*f6dc9357SAndroid Build Coastguard Worker         prop = _unpackSize;
573*f6dc9357SAndroid Build Coastguard Worker       else if (_stream)
574*f6dc9357SAndroid Build Coastguard Worker         prop = (UInt64)_item.Size32;
575*f6dc9357SAndroid Build Coastguard Worker       break;
576*f6dc9357SAndroid Build Coastguard Worker     }
577*f6dc9357SAndroid Build Coastguard Worker     case kpidPackSize:
578*f6dc9357SAndroid Build Coastguard Worker     {
579*f6dc9357SAndroid Build Coastguard Worker       if (_packSize_Defined || _stream)
580*f6dc9357SAndroid Build Coastguard Worker         prop = _packSize;
581*f6dc9357SAndroid Build Coastguard Worker       break;
582*f6dc9357SAndroid Build Coastguard Worker     }
583*f6dc9357SAndroid Build Coastguard Worker     case kpidHostOS: TYPE_TO_PROP(kHostOSes, _item.HostOS, prop); break;
584*f6dc9357SAndroid Build Coastguard Worker     case kpidCRC: if (_stream) prop = _item.Crc; break;
585*f6dc9357SAndroid Build Coastguard Worker     default: break;
586*f6dc9357SAndroid Build Coastguard Worker   }
587*f6dc9357SAndroid Build Coastguard Worker   prop.Detach(value);
588*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
589*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
590*f6dc9357SAndroid Build Coastguard Worker }
591*f6dc9357SAndroid Build Coastguard Worker 
592*f6dc9357SAndroid Build Coastguard Worker Z7_CLASS_IMP_COM_1(
593*f6dc9357SAndroid Build Coastguard Worker   CCompressProgressInfoImp,
594*f6dc9357SAndroid Build Coastguard Worker   ICompressProgressInfo
595*f6dc9357SAndroid Build Coastguard Worker )
596*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<IArchiveOpenCallback> Callback;
597*f6dc9357SAndroid Build Coastguard Worker public:
598*f6dc9357SAndroid Build Coastguard Worker   UInt64 Offset;
599*f6dc9357SAndroid Build Coastguard Worker   void Init(IArchiveOpenCallback *callback) { Callback = callback; }
600*f6dc9357SAndroid Build Coastguard Worker };
601*f6dc9357SAndroid Build Coastguard Worker 
602*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CCompressProgressInfoImp::SetRatioInfo(const UInt64 *inSize, const UInt64 * /* outSize */))
603*f6dc9357SAndroid Build Coastguard Worker {
604*f6dc9357SAndroid Build Coastguard Worker   if (Callback)
605*f6dc9357SAndroid Build Coastguard Worker   {
606*f6dc9357SAndroid Build Coastguard Worker     UInt64 files = 0;
607*f6dc9357SAndroid Build Coastguard Worker     UInt64 value = Offset + *inSize;
608*f6dc9357SAndroid Build Coastguard Worker     return Callback->SetCompleted(&files, &value);
609*f6dc9357SAndroid Build Coastguard Worker   }
610*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
611*f6dc9357SAndroid Build Coastguard Worker }
612*f6dc9357SAndroid Build Coastguard Worker 
613*f6dc9357SAndroid Build Coastguard Worker /*
614*f6dc9357SAndroid Build Coastguard Worker */
615*f6dc9357SAndroid Build Coastguard Worker 
616*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *))
617*f6dc9357SAndroid Build Coastguard Worker {
618*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
619*f6dc9357SAndroid Build Coastguard Worker   RINOK(OpenSeq(stream))
620*f6dc9357SAndroid Build Coastguard Worker   _isArc = false;
621*f6dc9357SAndroid Build Coastguard Worker   UInt64 endPos;
622*f6dc9357SAndroid Build Coastguard Worker   RINOK(stream->Seek(-8, STREAM_SEEK_END, &endPos))
623*f6dc9357SAndroid Build Coastguard Worker   _packSize = endPos + 8;
624*f6dc9357SAndroid Build Coastguard Worker   RINOK(_item.ReadFooter2(stream))
625*f6dc9357SAndroid Build Coastguard Worker   _stream = stream;
626*f6dc9357SAndroid Build Coastguard Worker   _isArc = true;
627*f6dc9357SAndroid Build Coastguard Worker   _needSeekToStart = true;
628*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
629*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
630*f6dc9357SAndroid Build Coastguard Worker }
631*f6dc9357SAndroid Build Coastguard Worker 
632*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::OpenSeq(ISequentialInStream *stream))
633*f6dc9357SAndroid Build Coastguard Worker {
634*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
635*f6dc9357SAndroid Build Coastguard Worker   try
636*f6dc9357SAndroid Build Coastguard Worker   {
637*f6dc9357SAndroid Build Coastguard Worker     Close();
638*f6dc9357SAndroid Build Coastguard Worker     CreateDecoder();
639*f6dc9357SAndroid Build Coastguard Worker     _decoder->SetInStream(stream);
640*f6dc9357SAndroid Build Coastguard Worker     _decoder->InitInStream(true);
641*f6dc9357SAndroid Build Coastguard Worker     RINOK(_item.ReadHeader(_decoder.ClsPtr()))
642*f6dc9357SAndroid Build Coastguard Worker     if (_decoder->InputEofError())
643*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
644*f6dc9357SAndroid Build Coastguard Worker     _headerSize = _decoder->GetInputProcessedSize();
645*f6dc9357SAndroid Build Coastguard Worker     _isArc = true;
646*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
647*f6dc9357SAndroid Build Coastguard Worker   }
648*f6dc9357SAndroid Build Coastguard Worker   catch(const CInBufferException &e) { return e.ErrorCode; }
649*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
650*f6dc9357SAndroid Build Coastguard Worker }
651*f6dc9357SAndroid Build Coastguard Worker 
652*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Close())
653*f6dc9357SAndroid Build Coastguard Worker {
654*f6dc9357SAndroid Build Coastguard Worker   _isArc = false;
655*f6dc9357SAndroid Build Coastguard Worker   _needSeekToStart = false;
656*f6dc9357SAndroid Build Coastguard Worker   _dataAfterEnd = false;
657*f6dc9357SAndroid Build Coastguard Worker   _needMoreInput = false;
658*f6dc9357SAndroid Build Coastguard Worker 
659*f6dc9357SAndroid Build Coastguard Worker   _packSize_Defined = false;
660*f6dc9357SAndroid Build Coastguard Worker   _unpackSize_Defined = false;
661*f6dc9357SAndroid Build Coastguard Worker   _numStreams_Defined = false;
662*f6dc9357SAndroid Build Coastguard Worker 
663*f6dc9357SAndroid Build Coastguard Worker   _packSize = 0;
664*f6dc9357SAndroid Build Coastguard Worker   _headerSize = 0;
665*f6dc9357SAndroid Build Coastguard Worker 
666*f6dc9357SAndroid Build Coastguard Worker   _stream.Release();
667*f6dc9357SAndroid Build Coastguard Worker   if (_decoder)
668*f6dc9357SAndroid Build Coastguard Worker     _decoder->ReleaseInStream();
669*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
670*f6dc9357SAndroid Build Coastguard Worker }
671*f6dc9357SAndroid Build Coastguard Worker 
672*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
673*f6dc9357SAndroid Build Coastguard Worker     Int32 testMode, IArchiveExtractCallback *extractCallback))
674*f6dc9357SAndroid Build Coastguard Worker {
675*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
676*f6dc9357SAndroid Build Coastguard Worker   if (numItems == 0)
677*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
678*f6dc9357SAndroid Build Coastguard Worker   if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0))
679*f6dc9357SAndroid Build Coastguard Worker     return E_INVALIDARG;
680*f6dc9357SAndroid Build Coastguard Worker 
681*f6dc9357SAndroid Build Coastguard Worker   if (_packSize_Defined)
682*f6dc9357SAndroid Build Coastguard Worker     RINOK(extractCallback->SetTotal(_packSize))
683*f6dc9357SAndroid Build Coastguard Worker   // UInt64 currentTotalPacked = 0;
684*f6dc9357SAndroid Build Coastguard Worker   // RINOK(extractCallback->SetCompleted(&currentTotalPacked));
685*f6dc9357SAndroid Build Coastguard Worker   Int32 retResult;
686*f6dc9357SAndroid Build Coastguard Worker  {
687*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<ISequentialOutStream> realOutStream;
688*f6dc9357SAndroid Build Coastguard Worker   const Int32 askMode = testMode ?
689*f6dc9357SAndroid Build Coastguard Worker       NExtract::NAskMode::kTest :
690*f6dc9357SAndroid Build Coastguard Worker       NExtract::NAskMode::kExtract;
691*f6dc9357SAndroid Build Coastguard Worker   RINOK(extractCallback->GetStream(0, &realOutStream, askMode))
692*f6dc9357SAndroid Build Coastguard Worker   if (!testMode && !realOutStream)
693*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
694*f6dc9357SAndroid Build Coastguard Worker 
695*f6dc9357SAndroid Build Coastguard Worker   RINOK(extractCallback->PrepareOperation(askMode))
696*f6dc9357SAndroid Build Coastguard Worker 
697*f6dc9357SAndroid Build Coastguard Worker   CreateDecoder();
698*f6dc9357SAndroid Build Coastguard Worker 
699*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ISequentialOutStream, COutStreamWithCRC> outStream;
700*f6dc9357SAndroid Build Coastguard Worker   outStream->SetStream(realOutStream);
701*f6dc9357SAndroid Build Coastguard Worker   outStream->Init();
702*f6dc9357SAndroid Build Coastguard Worker   // realOutStream.Release();
703*f6dc9357SAndroid Build Coastguard Worker 
704*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ICompressProgressInfo, CLocalProgress> lps;
705*f6dc9357SAndroid Build Coastguard Worker   lps->Init(extractCallback, true);
706*f6dc9357SAndroid Build Coastguard Worker 
707*f6dc9357SAndroid Build Coastguard Worker   bool needReadFirstItem = _needSeekToStart;
708*f6dc9357SAndroid Build Coastguard Worker 
709*f6dc9357SAndroid Build Coastguard Worker   if (_needSeekToStart)
710*f6dc9357SAndroid Build Coastguard Worker   {
711*f6dc9357SAndroid Build Coastguard Worker     if (!_stream)
712*f6dc9357SAndroid Build Coastguard Worker       return E_FAIL;
713*f6dc9357SAndroid Build Coastguard Worker     RINOK(InStream_SeekToBegin(_stream))
714*f6dc9357SAndroid Build Coastguard Worker     _decoder->InitInStream(true);
715*f6dc9357SAndroid Build Coastguard Worker     // printf("\nSeek");
716*f6dc9357SAndroid Build Coastguard Worker   }
717*f6dc9357SAndroid Build Coastguard Worker   else
718*f6dc9357SAndroid Build Coastguard Worker     _needSeekToStart = true;
719*f6dc9357SAndroid Build Coastguard Worker 
720*f6dc9357SAndroid Build Coastguard Worker   bool firstItem = true;
721*f6dc9357SAndroid Build Coastguard Worker 
722*f6dc9357SAndroid Build Coastguard Worker   UInt64 packSize = _decoder->GetInputProcessedSize();
723*f6dc9357SAndroid Build Coastguard Worker   // printf("\npackSize = %d", (unsigned)packSize);
724*f6dc9357SAndroid Build Coastguard Worker 
725*f6dc9357SAndroid Build Coastguard Worker   UInt64 unpackedSize = 0;
726*f6dc9357SAndroid Build Coastguard Worker   UInt64 numStreams = 0;
727*f6dc9357SAndroid Build Coastguard Worker 
728*f6dc9357SAndroid Build Coastguard Worker   bool crcError = false;
729*f6dc9357SAndroid Build Coastguard Worker 
730*f6dc9357SAndroid Build Coastguard Worker   HRESULT result = S_OK;
731*f6dc9357SAndroid Build Coastguard Worker 
732*f6dc9357SAndroid Build Coastguard Worker   try {
733*f6dc9357SAndroid Build Coastguard Worker 
734*f6dc9357SAndroid Build Coastguard Worker   for (;;)
735*f6dc9357SAndroid Build Coastguard Worker   {
736*f6dc9357SAndroid Build Coastguard Worker     lps->InSize = packSize;
737*f6dc9357SAndroid Build Coastguard Worker     lps->OutSize = unpackedSize;
738*f6dc9357SAndroid Build Coastguard Worker 
739*f6dc9357SAndroid Build Coastguard Worker     RINOK(lps->SetCur())
740*f6dc9357SAndroid Build Coastguard Worker 
741*f6dc9357SAndroid Build Coastguard Worker     CItem item;
742*f6dc9357SAndroid Build Coastguard Worker 
743*f6dc9357SAndroid Build Coastguard Worker     if (!firstItem || needReadFirstItem)
744*f6dc9357SAndroid Build Coastguard Worker     {
745*f6dc9357SAndroid Build Coastguard Worker       result = item.ReadHeader(_decoder.ClsPtr());
746*f6dc9357SAndroid Build Coastguard Worker 
747*f6dc9357SAndroid Build Coastguard Worker       if (result != S_OK && result != S_FALSE)
748*f6dc9357SAndroid Build Coastguard Worker         return result;
749*f6dc9357SAndroid Build Coastguard Worker 
750*f6dc9357SAndroid Build Coastguard Worker       if (_decoder->InputEofError())
751*f6dc9357SAndroid Build Coastguard Worker         result = S_FALSE;
752*f6dc9357SAndroid Build Coastguard Worker 
753*f6dc9357SAndroid Build Coastguard Worker       if (result != S_OK && firstItem)
754*f6dc9357SAndroid Build Coastguard Worker       {
755*f6dc9357SAndroid Build Coastguard Worker         _isArc = false;
756*f6dc9357SAndroid Build Coastguard Worker         break;
757*f6dc9357SAndroid Build Coastguard Worker       }
758*f6dc9357SAndroid Build Coastguard Worker 
759*f6dc9357SAndroid Build Coastguard Worker       if (packSize == _decoder->GetStreamSize())
760*f6dc9357SAndroid Build Coastguard Worker       {
761*f6dc9357SAndroid Build Coastguard Worker         result = S_OK;
762*f6dc9357SAndroid Build Coastguard Worker         break;
763*f6dc9357SAndroid Build Coastguard Worker       }
764*f6dc9357SAndroid Build Coastguard Worker 
765*f6dc9357SAndroid Build Coastguard Worker       if (result != S_OK)
766*f6dc9357SAndroid Build Coastguard Worker       {
767*f6dc9357SAndroid Build Coastguard Worker         _dataAfterEnd = true;
768*f6dc9357SAndroid Build Coastguard Worker         break;
769*f6dc9357SAndroid Build Coastguard Worker       }
770*f6dc9357SAndroid Build Coastguard Worker     }
771*f6dc9357SAndroid Build Coastguard Worker 
772*f6dc9357SAndroid Build Coastguard Worker     numStreams++;
773*f6dc9357SAndroid Build Coastguard Worker     firstItem = false;
774*f6dc9357SAndroid Build Coastguard Worker 
775*f6dc9357SAndroid Build Coastguard Worker     const UInt64 startOffset = outStream->GetSize();
776*f6dc9357SAndroid Build Coastguard Worker     outStream->InitCRC();
777*f6dc9357SAndroid Build Coastguard Worker 
778*f6dc9357SAndroid Build Coastguard Worker     result = _decoder->CodeResume(outStream, NULL, lps);
779*f6dc9357SAndroid Build Coastguard Worker 
780*f6dc9357SAndroid Build Coastguard Worker     packSize = _decoder->GetInputProcessedSize();
781*f6dc9357SAndroid Build Coastguard Worker     unpackedSize = outStream->GetSize();
782*f6dc9357SAndroid Build Coastguard Worker 
783*f6dc9357SAndroid Build Coastguard Worker     if (result != S_OK && result != S_FALSE)
784*f6dc9357SAndroid Build Coastguard Worker       return result;
785*f6dc9357SAndroid Build Coastguard Worker 
786*f6dc9357SAndroid Build Coastguard Worker     if (_decoder->InputEofError())
787*f6dc9357SAndroid Build Coastguard Worker     {
788*f6dc9357SAndroid Build Coastguard Worker       packSize = _decoder->GetStreamSize();
789*f6dc9357SAndroid Build Coastguard Worker       _needMoreInput = true;
790*f6dc9357SAndroid Build Coastguard Worker       result = S_FALSE;
791*f6dc9357SAndroid Build Coastguard Worker     }
792*f6dc9357SAndroid Build Coastguard Worker 
793*f6dc9357SAndroid Build Coastguard Worker     if (result != S_OK)
794*f6dc9357SAndroid Build Coastguard Worker       break;
795*f6dc9357SAndroid Build Coastguard Worker 
796*f6dc9357SAndroid Build Coastguard Worker     _decoder->AlignToByte();
797*f6dc9357SAndroid Build Coastguard Worker 
798*f6dc9357SAndroid Build Coastguard Worker     result = item.ReadFooter1(_decoder.ClsPtr());
799*f6dc9357SAndroid Build Coastguard Worker 
800*f6dc9357SAndroid Build Coastguard Worker     packSize = _decoder->GetInputProcessedSize();
801*f6dc9357SAndroid Build Coastguard Worker 
802*f6dc9357SAndroid Build Coastguard Worker     if (result != S_OK && result != S_FALSE)
803*f6dc9357SAndroid Build Coastguard Worker       return result;
804*f6dc9357SAndroid Build Coastguard Worker 
805*f6dc9357SAndroid Build Coastguard Worker     if (result != S_OK)
806*f6dc9357SAndroid Build Coastguard Worker     {
807*f6dc9357SAndroid Build Coastguard Worker       if (_decoder->InputEofError())
808*f6dc9357SAndroid Build Coastguard Worker       {
809*f6dc9357SAndroid Build Coastguard Worker         _needMoreInput = true;
810*f6dc9357SAndroid Build Coastguard Worker         result = S_FALSE;
811*f6dc9357SAndroid Build Coastguard Worker       }
812*f6dc9357SAndroid Build Coastguard Worker       break;
813*f6dc9357SAndroid Build Coastguard Worker     }
814*f6dc9357SAndroid Build Coastguard Worker 
815*f6dc9357SAndroid Build Coastguard Worker     if (item.Crc != outStream->GetCRC() ||
816*f6dc9357SAndroid Build Coastguard Worker         item.Size32 != (UInt32)(unpackedSize - startOffset))
817*f6dc9357SAndroid Build Coastguard Worker     {
818*f6dc9357SAndroid Build Coastguard Worker       crcError = true;
819*f6dc9357SAndroid Build Coastguard Worker       result = S_FALSE;
820*f6dc9357SAndroid Build Coastguard Worker       break;
821*f6dc9357SAndroid Build Coastguard Worker     }
822*f6dc9357SAndroid Build Coastguard Worker 
823*f6dc9357SAndroid Build Coastguard Worker     // break; // we can use break, if we need only first stream
824*f6dc9357SAndroid Build Coastguard Worker   }
825*f6dc9357SAndroid Build Coastguard Worker 
826*f6dc9357SAndroid Build Coastguard Worker   } catch(const CInBufferException &e) { return e.ErrorCode; }
827*f6dc9357SAndroid Build Coastguard Worker 
828*f6dc9357SAndroid Build Coastguard Worker   if (!firstItem)
829*f6dc9357SAndroid Build Coastguard Worker   {
830*f6dc9357SAndroid Build Coastguard Worker     _packSize = packSize;
831*f6dc9357SAndroid Build Coastguard Worker     _unpackSize = unpackedSize;
832*f6dc9357SAndroid Build Coastguard Worker     _numStreams = numStreams;
833*f6dc9357SAndroid Build Coastguard Worker 
834*f6dc9357SAndroid Build Coastguard Worker     _packSize_Defined = true;
835*f6dc9357SAndroid Build Coastguard Worker     _unpackSize_Defined = true;
836*f6dc9357SAndroid Build Coastguard Worker     _numStreams_Defined = true;
837*f6dc9357SAndroid Build Coastguard Worker   }
838*f6dc9357SAndroid Build Coastguard Worker 
839*f6dc9357SAndroid Build Coastguard Worker   // outStream.Release();
840*f6dc9357SAndroid Build Coastguard Worker 
841*f6dc9357SAndroid Build Coastguard Worker   retResult = NExtract::NOperationResult::kDataError;
842*f6dc9357SAndroid Build Coastguard Worker 
843*f6dc9357SAndroid Build Coastguard Worker   if (!_isArc)
844*f6dc9357SAndroid Build Coastguard Worker     retResult = NExtract::NOperationResult::kIsNotArc;
845*f6dc9357SAndroid Build Coastguard Worker   else if (_needMoreInput)
846*f6dc9357SAndroid Build Coastguard Worker     retResult = NExtract::NOperationResult::kUnexpectedEnd;
847*f6dc9357SAndroid Build Coastguard Worker   else if (crcError)
848*f6dc9357SAndroid Build Coastguard Worker     retResult = NExtract::NOperationResult::kCRCError;
849*f6dc9357SAndroid Build Coastguard Worker   else if (_dataAfterEnd)
850*f6dc9357SAndroid Build Coastguard Worker     retResult = NExtract::NOperationResult::kDataAfterEnd;
851*f6dc9357SAndroid Build Coastguard Worker   else if (result == S_FALSE)
852*f6dc9357SAndroid Build Coastguard Worker     retResult = NExtract::NOperationResult::kDataError;
853*f6dc9357SAndroid Build Coastguard Worker   else if (result == S_OK)
854*f6dc9357SAndroid Build Coastguard Worker     retResult = NExtract::NOperationResult::kOK;
855*f6dc9357SAndroid Build Coastguard Worker   else
856*f6dc9357SAndroid Build Coastguard Worker     return result;
857*f6dc9357SAndroid Build Coastguard Worker  }
858*f6dc9357SAndroid Build Coastguard Worker 
859*f6dc9357SAndroid Build Coastguard Worker   return extractCallback->SetOperationResult(retResult);
860*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
861*f6dc9357SAndroid Build Coastguard Worker }
862*f6dc9357SAndroid Build Coastguard Worker 
863*f6dc9357SAndroid Build Coastguard Worker static const Byte kHostOS =
864*f6dc9357SAndroid Build Coastguard Worker   #ifdef _WIN32
865*f6dc9357SAndroid Build Coastguard Worker   NHostOS::kFAT;
866*f6dc9357SAndroid Build Coastguard Worker   #else
867*f6dc9357SAndroid Build Coastguard Worker   NHostOS::kUnix;
868*f6dc9357SAndroid Build Coastguard Worker   #endif
869*f6dc9357SAndroid Build Coastguard Worker 
870*f6dc9357SAndroid Build Coastguard Worker 
871*f6dc9357SAndroid Build Coastguard Worker /*
872*f6dc9357SAndroid Build Coastguard Worker static HRESULT ReportItemProp(IArchiveUpdateCallbackArcProp *reportArcProp, PROPID propID, const PROPVARIANT *value)
873*f6dc9357SAndroid Build Coastguard Worker {
874*f6dc9357SAndroid Build Coastguard Worker   return reportArcProp->ReportProp(NEventIndexType::kOutArcIndex, 0, propID, value);
875*f6dc9357SAndroid Build Coastguard Worker }
876*f6dc9357SAndroid Build Coastguard Worker 
877*f6dc9357SAndroid Build Coastguard Worker static HRESULT ReportArcProp(IArchiveUpdateCallbackArcProp *reportArcProp, PROPID propID, const PROPVARIANT *value)
878*f6dc9357SAndroid Build Coastguard Worker {
879*f6dc9357SAndroid Build Coastguard Worker   return reportArcProp->ReportProp(NEventIndexType::kArcProp, 0, propID, value);
880*f6dc9357SAndroid Build Coastguard Worker }
881*f6dc9357SAndroid Build Coastguard Worker 
882*f6dc9357SAndroid Build Coastguard Worker static HRESULT ReportArcProps(IArchiveUpdateCallbackArcProp *reportArcProp,
883*f6dc9357SAndroid Build Coastguard Worker     const CItem &item,
884*f6dc9357SAndroid Build Coastguard Worker     bool needTime,
885*f6dc9357SAndroid Build Coastguard Worker     bool needCrc,
886*f6dc9357SAndroid Build Coastguard Worker     const UInt64 *unpackSize)
887*f6dc9357SAndroid Build Coastguard Worker {
888*f6dc9357SAndroid Build Coastguard Worker   NCOM::CPropVariant timeProp;
889*f6dc9357SAndroid Build Coastguard Worker   NCOM::CPropVariant sizeProp;
890*f6dc9357SAndroid Build Coastguard Worker   if (needTime)
891*f6dc9357SAndroid Build Coastguard Worker   {
892*f6dc9357SAndroid Build Coastguard Worker     FILETIME ft;
893*f6dc9357SAndroid Build Coastguard Worker     NTime::UnixTimeToFileTime(item.Time, ft);
894*f6dc9357SAndroid Build Coastguard Worker     timeProp.SetAsTimeFrom_FT_Prec(ft, k_PropVar_TimePrec_Unix);
895*f6dc9357SAndroid Build Coastguard Worker   }
896*f6dc9357SAndroid Build Coastguard Worker   if (unpackSize)
897*f6dc9357SAndroid Build Coastguard Worker   {
898*f6dc9357SAndroid Build Coastguard Worker     sizeProp = *unpackSize;
899*f6dc9357SAndroid Build Coastguard Worker     RINOK(ReportItemProp(reportArcProp, kpidSize, &sizeProp));
900*f6dc9357SAndroid Build Coastguard Worker   }
901*f6dc9357SAndroid Build Coastguard Worker   if (needCrc)
902*f6dc9357SAndroid Build Coastguard Worker   {
903*f6dc9357SAndroid Build Coastguard Worker     NCOM::CPropVariant prop;
904*f6dc9357SAndroid Build Coastguard Worker     prop = item.Crc;
905*f6dc9357SAndroid Build Coastguard Worker     RINOK(ReportItemProp(reportArcProp, kpidCRC, &prop));
906*f6dc9357SAndroid Build Coastguard Worker   }
907*f6dc9357SAndroid Build Coastguard Worker   {
908*f6dc9357SAndroid Build Coastguard Worker     RINOK(ReportItemProp(reportArcProp, kpidMTime, &timeProp));
909*f6dc9357SAndroid Build Coastguard Worker   }
910*f6dc9357SAndroid Build Coastguard Worker 
911*f6dc9357SAndroid Build Coastguard Worker   RINOK(reportArcProp->ReportFinished(NEventIndexType::kOutArcIndex, 0, NArchive::NUpdate::NOperationResult::kOK));
912*f6dc9357SAndroid Build Coastguard Worker 
913*f6dc9357SAndroid Build Coastguard Worker   if (unpackSize)
914*f6dc9357SAndroid Build Coastguard Worker   {
915*f6dc9357SAndroid Build Coastguard Worker     RINOK(ReportArcProp(reportArcProp, kpidSize, &sizeProp));
916*f6dc9357SAndroid Build Coastguard Worker   }
917*f6dc9357SAndroid Build Coastguard Worker   {
918*f6dc9357SAndroid Build Coastguard Worker     RINOK(ReportArcProp(reportArcProp, kpidComboMTime, &timeProp));
919*f6dc9357SAndroid Build Coastguard Worker   }
920*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
921*f6dc9357SAndroid Build Coastguard Worker }
922*f6dc9357SAndroid Build Coastguard Worker */
923*f6dc9357SAndroid Build Coastguard Worker 
924*f6dc9357SAndroid Build Coastguard Worker static HRESULT UpdateArchive(
925*f6dc9357SAndroid Build Coastguard Worker     ISequentialOutStream *outStream,
926*f6dc9357SAndroid Build Coastguard Worker     UInt64 unpackSize,
927*f6dc9357SAndroid Build Coastguard Worker     CItem &item,
928*f6dc9357SAndroid Build Coastguard Worker     const CSingleMethodProps &props,
929*f6dc9357SAndroid Build Coastguard Worker     const CHandlerTimeOptions &timeOptions,
930*f6dc9357SAndroid Build Coastguard Worker     IArchiveUpdateCallback *updateCallback
931*f6dc9357SAndroid Build Coastguard Worker     // , IArchiveUpdateCallbackArcProp *reportArcProp
932*f6dc9357SAndroid Build Coastguard Worker     )
933*f6dc9357SAndroid Build Coastguard Worker {
934*f6dc9357SAndroid Build Coastguard Worker   UInt64 unpackSizeReal;
935*f6dc9357SAndroid Build Coastguard Worker   {
936*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<ISequentialInStream> fileInStream;
937*f6dc9357SAndroid Build Coastguard Worker 
938*f6dc9357SAndroid Build Coastguard Worker   RINOK(updateCallback->GetStream(0, &fileInStream))
939*f6dc9357SAndroid Build Coastguard Worker 
940*f6dc9357SAndroid Build Coastguard Worker   if (!fileInStream)
941*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
942*f6dc9357SAndroid Build Coastguard Worker 
943*f6dc9357SAndroid Build Coastguard Worker   {
944*f6dc9357SAndroid Build Coastguard Worker     Z7_DECL_CMyComPtr_QI_FROM(
945*f6dc9357SAndroid Build Coastguard Worker         IStreamGetProps,
946*f6dc9357SAndroid Build Coastguard Worker         getProps, fileInStream)
947*f6dc9357SAndroid Build Coastguard Worker     if (getProps)
948*f6dc9357SAndroid Build Coastguard Worker     {
949*f6dc9357SAndroid Build Coastguard Worker       FILETIME mTime;
950*f6dc9357SAndroid Build Coastguard Worker       UInt64 size;
951*f6dc9357SAndroid Build Coastguard Worker       if (getProps->GetProps(&size, NULL, NULL, &mTime, NULL) == S_OK)
952*f6dc9357SAndroid Build Coastguard Worker       {
953*f6dc9357SAndroid Build Coastguard Worker         unpackSize = size;
954*f6dc9357SAndroid Build Coastguard Worker         if (timeOptions.Write_MTime.Val)
955*f6dc9357SAndroid Build Coastguard Worker           NTime::FileTime_To_UnixTime(mTime, item.Time);
956*f6dc9357SAndroid Build Coastguard Worker       }
957*f6dc9357SAndroid Build Coastguard Worker     }
958*f6dc9357SAndroid Build Coastguard Worker   }
959*f6dc9357SAndroid Build Coastguard Worker 
960*f6dc9357SAndroid Build Coastguard Worker   UInt64 complexity = 0;
961*f6dc9357SAndroid Build Coastguard Worker   RINOK(updateCallback->SetTotal(unpackSize))
962*f6dc9357SAndroid Build Coastguard Worker   RINOK(updateCallback->SetCompleted(&complexity))
963*f6dc9357SAndroid Build Coastguard Worker 
964*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ISequentialInStream, CSequentialInStreamWithCRC> crcStream;
965*f6dc9357SAndroid Build Coastguard Worker   crcStream->SetStream(fileInStream);
966*f6dc9357SAndroid Build Coastguard Worker   crcStream->Init();
967*f6dc9357SAndroid Build Coastguard Worker 
968*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ICompressProgressInfo, CLocalProgress> lps;
969*f6dc9357SAndroid Build Coastguard Worker   lps->Init(updateCallback, true);
970*f6dc9357SAndroid Build Coastguard Worker 
971*f6dc9357SAndroid Build Coastguard Worker   item.ExtraFlags = props.GetLevel() >= 7 ?
972*f6dc9357SAndroid Build Coastguard Worker       NExtraFlags::kMaximum :
973*f6dc9357SAndroid Build Coastguard Worker       NExtraFlags::kFastest;
974*f6dc9357SAndroid Build Coastguard Worker 
975*f6dc9357SAndroid Build Coastguard Worker   item.HostOS = kHostOS;
976*f6dc9357SAndroid Build Coastguard Worker 
977*f6dc9357SAndroid Build Coastguard Worker   RINOK(item.WriteHeader(outStream))
978*f6dc9357SAndroid Build Coastguard Worker 
979*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ICompressCoder, NEncoder::CCOMCoder> deflateEncoder;
980*f6dc9357SAndroid Build Coastguard Worker 
981*f6dc9357SAndroid Build Coastguard Worker   RINOK(props.SetCoderProps(deflateEncoder.ClsPtr(), NULL))
982*f6dc9357SAndroid Build Coastguard Worker   RINOK(deflateEncoder.Interface()->Code(crcStream, outStream, NULL, NULL, lps))
983*f6dc9357SAndroid Build Coastguard Worker 
984*f6dc9357SAndroid Build Coastguard Worker   item.Crc = crcStream->GetCRC();
985*f6dc9357SAndroid Build Coastguard Worker   unpackSizeReal = crcStream->GetSize();
986*f6dc9357SAndroid Build Coastguard Worker   item.Size32 = (UInt32)unpackSizeReal;
987*f6dc9357SAndroid Build Coastguard Worker   RINOK(item.WriteFooter(outStream))
988*f6dc9357SAndroid Build Coastguard Worker   }
989*f6dc9357SAndroid Build Coastguard Worker   /*
990*f6dc9357SAndroid Build Coastguard Worker   if (reportArcProp)
991*f6dc9357SAndroid Build Coastguard Worker   {
992*f6dc9357SAndroid Build Coastguard Worker     RINOK(ReportArcProps(reportArcProp,
993*f6dc9357SAndroid Build Coastguard Worker         item,
994*f6dc9357SAndroid Build Coastguard Worker         props._Write_MTime, // item.Time != 0,
995*f6dc9357SAndroid Build Coastguard Worker         true, // writeCrc
996*f6dc9357SAndroid Build Coastguard Worker         &unpackSizeReal));
997*f6dc9357SAndroid Build Coastguard Worker   }
998*f6dc9357SAndroid Build Coastguard Worker   */
999*f6dc9357SAndroid Build Coastguard Worker   return updateCallback->SetOperationResult(NUpdate::NOperationResult::kOK);
1000*f6dc9357SAndroid Build Coastguard Worker }
1001*f6dc9357SAndroid Build Coastguard Worker 
1002*f6dc9357SAndroid Build Coastguard Worker 
1003*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetFileTimeType(UInt32 *timeType))
1004*f6dc9357SAndroid Build Coastguard Worker {
1005*f6dc9357SAndroid Build Coastguard Worker   /*
1006*f6dc9357SAndroid Build Coastguard Worker     if (_item.Time != 0)
1007*f6dc9357SAndroid Build Coastguard Worker     {
1008*f6dc9357SAndroid Build Coastguard Worker       we set NFileTimeType::kUnix in precision,
1009*f6dc9357SAndroid Build Coastguard Worker       and we return NFileTimeType::kUnix in kpidTimeType
1010*f6dc9357SAndroid Build Coastguard Worker       so GetFileTimeType() value is not used in any version of 7-zip.
1011*f6dc9357SAndroid Build Coastguard Worker     }
1012*f6dc9357SAndroid Build Coastguard Worker     else // (_item.Time == 0)
1013*f6dc9357SAndroid Build Coastguard Worker     {
1014*f6dc9357SAndroid Build Coastguard Worker       kpidMTime and kpidTimeType are not defined
1015*f6dc9357SAndroid Build Coastguard Worker       before 22.00 : GetFileTimeType() value is used in GetUpdatePairInfoList();
1016*f6dc9357SAndroid Build Coastguard Worker              22.00 : GetFileTimeType() value is not used
1017*f6dc9357SAndroid Build Coastguard Worker     }
1018*f6dc9357SAndroid Build Coastguard Worker   */
1019*f6dc9357SAndroid Build Coastguard Worker 
1020*f6dc9357SAndroid Build Coastguard Worker   UInt32 t;
1021*f6dc9357SAndroid Build Coastguard Worker   t = NFileTimeType::kUnix;
1022*f6dc9357SAndroid Build Coastguard Worker   if (_isArc ? (_item.Time == 0) : !_timeOptions.Write_MTime.Val)
1023*f6dc9357SAndroid Build Coastguard Worker   {
1024*f6dc9357SAndroid Build Coastguard Worker     t = GET_FileTimeType_NotDefined_for_GetFileTimeType;
1025*f6dc9357SAndroid Build Coastguard Worker     // t = k_PropVar_TimePrec_1ns; // failed in 7-Zip 21
1026*f6dc9357SAndroid Build Coastguard Worker     // t = (UInt32)(Int32)NFileTimeType::kNotDefined; // failed in 7-Zip 21
1027*f6dc9357SAndroid Build Coastguard Worker   }
1028*f6dc9357SAndroid Build Coastguard Worker   *timeType = t;
1029*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1030*f6dc9357SAndroid Build Coastguard Worker }
1031*f6dc9357SAndroid Build Coastguard Worker 
1032*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
1033*f6dc9357SAndroid Build Coastguard Worker     IArchiveUpdateCallback *updateCallback))
1034*f6dc9357SAndroid Build Coastguard Worker {
1035*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
1036*f6dc9357SAndroid Build Coastguard Worker 
1037*f6dc9357SAndroid Build Coastguard Worker   if (numItems != 1)
1038*f6dc9357SAndroid Build Coastguard Worker     return E_INVALIDARG;
1039*f6dc9357SAndroid Build Coastguard Worker 
1040*f6dc9357SAndroid Build Coastguard Worker   {
1041*f6dc9357SAndroid Build Coastguard Worker     Z7_DECL_CMyComPtr_QI_FROM(
1042*f6dc9357SAndroid Build Coastguard Worker         IStreamSetRestriction,
1043*f6dc9357SAndroid Build Coastguard Worker         setRestriction, outStream)
1044*f6dc9357SAndroid Build Coastguard Worker     if (setRestriction)
1045*f6dc9357SAndroid Build Coastguard Worker       RINOK(setRestriction->SetRestriction(0, 0))
1046*f6dc9357SAndroid Build Coastguard Worker   }
1047*f6dc9357SAndroid Build Coastguard Worker 
1048*f6dc9357SAndroid Build Coastguard Worker   Int32 newData, newProps;
1049*f6dc9357SAndroid Build Coastguard Worker   UInt32 indexInArchive;
1050*f6dc9357SAndroid Build Coastguard Worker   if (!updateCallback)
1051*f6dc9357SAndroid Build Coastguard Worker     return E_FAIL;
1052*f6dc9357SAndroid Build Coastguard Worker   RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive))
1053*f6dc9357SAndroid Build Coastguard Worker 
1054*f6dc9357SAndroid Build Coastguard Worker   // Z7_DECL_CMyComPtr_QI_FROM(IArchiveUpdateCallbackArcProp, reportArcProp, updateCallback)
1055*f6dc9357SAndroid Build Coastguard Worker 
1056*f6dc9357SAndroid Build Coastguard Worker   CItem newItem;
1057*f6dc9357SAndroid Build Coastguard Worker 
1058*f6dc9357SAndroid Build Coastguard Worker   if (!IntToBool(newProps))
1059*f6dc9357SAndroid Build Coastguard Worker   {
1060*f6dc9357SAndroid Build Coastguard Worker     newItem.CopyMetaPropsFrom(_item);
1061*f6dc9357SAndroid Build Coastguard Worker   }
1062*f6dc9357SAndroid Build Coastguard Worker   else
1063*f6dc9357SAndroid Build Coastguard Worker   {
1064*f6dc9357SAndroid Build Coastguard Worker     newItem.HostOS = kHostOS;
1065*f6dc9357SAndroid Build Coastguard Worker     if (_timeOptions.Write_MTime.Val)
1066*f6dc9357SAndroid Build Coastguard Worker     {
1067*f6dc9357SAndroid Build Coastguard Worker       NCOM::CPropVariant prop;
1068*f6dc9357SAndroid Build Coastguard Worker       RINOK(updateCallback->GetProperty(0, kpidMTime, &prop))
1069*f6dc9357SAndroid Build Coastguard Worker       if (prop.vt == VT_FILETIME)
1070*f6dc9357SAndroid Build Coastguard Worker         NTime::FileTime_To_UnixTime(prop.filetime, newItem.Time);
1071*f6dc9357SAndroid Build Coastguard Worker       else if (prop.vt == VT_EMPTY)
1072*f6dc9357SAndroid Build Coastguard Worker         newItem.Time = 0;
1073*f6dc9357SAndroid Build Coastguard Worker       else
1074*f6dc9357SAndroid Build Coastguard Worker         return E_INVALIDARG;
1075*f6dc9357SAndroid Build Coastguard Worker     }
1076*f6dc9357SAndroid Build Coastguard Worker     {
1077*f6dc9357SAndroid Build Coastguard Worker       NCOM::CPropVariant prop;
1078*f6dc9357SAndroid Build Coastguard Worker       RINOK(updateCallback->GetProperty(0, kpidPath, &prop))
1079*f6dc9357SAndroid Build Coastguard Worker       if (prop.vt == VT_BSTR)
1080*f6dc9357SAndroid Build Coastguard Worker       {
1081*f6dc9357SAndroid Build Coastguard Worker         UString name = prop.bstrVal;
1082*f6dc9357SAndroid Build Coastguard Worker         int slashPos = name.ReverseFind_PathSepar();
1083*f6dc9357SAndroid Build Coastguard Worker         if (slashPos >= 0)
1084*f6dc9357SAndroid Build Coastguard Worker           name.DeleteFrontal((unsigned)(slashPos + 1));
1085*f6dc9357SAndroid Build Coastguard Worker         newItem.Name = UnicodeStringToMultiByte(name, CP_ACP);
1086*f6dc9357SAndroid Build Coastguard Worker         if (!newItem.Name.IsEmpty())
1087*f6dc9357SAndroid Build Coastguard Worker           newItem.Flags |= NFlags::kName;
1088*f6dc9357SAndroid Build Coastguard Worker       }
1089*f6dc9357SAndroid Build Coastguard Worker       else if (prop.vt != VT_EMPTY)
1090*f6dc9357SAndroid Build Coastguard Worker         return E_INVALIDARG;
1091*f6dc9357SAndroid Build Coastguard Worker     }
1092*f6dc9357SAndroid Build Coastguard Worker     {
1093*f6dc9357SAndroid Build Coastguard Worker       NCOM::CPropVariant prop;
1094*f6dc9357SAndroid Build Coastguard Worker       RINOK(updateCallback->GetProperty(0, kpidIsDir, &prop))
1095*f6dc9357SAndroid Build Coastguard Worker       if (prop.vt != VT_EMPTY)
1096*f6dc9357SAndroid Build Coastguard Worker         if (prop.vt != VT_BOOL || prop.boolVal != VARIANT_FALSE)
1097*f6dc9357SAndroid Build Coastguard Worker           return E_INVALIDARG;
1098*f6dc9357SAndroid Build Coastguard Worker     }
1099*f6dc9357SAndroid Build Coastguard Worker   }
1100*f6dc9357SAndroid Build Coastguard Worker 
1101*f6dc9357SAndroid Build Coastguard Worker   if (IntToBool(newData))
1102*f6dc9357SAndroid Build Coastguard Worker   {
1103*f6dc9357SAndroid Build Coastguard Worker     UInt64 size;
1104*f6dc9357SAndroid Build Coastguard Worker     {
1105*f6dc9357SAndroid Build Coastguard Worker       NCOM::CPropVariant prop;
1106*f6dc9357SAndroid Build Coastguard Worker       RINOK(updateCallback->GetProperty(0, kpidSize, &prop))
1107*f6dc9357SAndroid Build Coastguard Worker       if (prop.vt != VT_UI8)
1108*f6dc9357SAndroid Build Coastguard Worker         return E_INVALIDARG;
1109*f6dc9357SAndroid Build Coastguard Worker       size = prop.uhVal.QuadPart;
1110*f6dc9357SAndroid Build Coastguard Worker     }
1111*f6dc9357SAndroid Build Coastguard Worker     return UpdateArchive(outStream, size, newItem, _props, _timeOptions, updateCallback);
1112*f6dc9357SAndroid Build Coastguard Worker   }
1113*f6dc9357SAndroid Build Coastguard Worker 
1114*f6dc9357SAndroid Build Coastguard Worker   if (indexInArchive != 0)
1115*f6dc9357SAndroid Build Coastguard Worker     return E_INVALIDARG;
1116*f6dc9357SAndroid Build Coastguard Worker 
1117*f6dc9357SAndroid Build Coastguard Worker   if (!_stream)
1118*f6dc9357SAndroid Build Coastguard Worker     return E_NOTIMPL;
1119*f6dc9357SAndroid Build Coastguard Worker 
1120*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ICompressProgressInfo, CLocalProgress> lps;
1121*f6dc9357SAndroid Build Coastguard Worker   lps->Init(updateCallback, true);
1122*f6dc9357SAndroid Build Coastguard Worker 
1123*f6dc9357SAndroid Build Coastguard Worker   Z7_DECL_CMyComPtr_QI_FROM(
1124*f6dc9357SAndroid Build Coastguard Worker       IArchiveUpdateCallbackFile,
1125*f6dc9357SAndroid Build Coastguard Worker       opCallback, updateCallback)
1126*f6dc9357SAndroid Build Coastguard Worker   if (opCallback)
1127*f6dc9357SAndroid Build Coastguard Worker   {
1128*f6dc9357SAndroid Build Coastguard Worker     RINOK(opCallback->ReportOperation(
1129*f6dc9357SAndroid Build Coastguard Worker         NEventIndexType::kInArcIndex, 0,
1130*f6dc9357SAndroid Build Coastguard Worker         NUpdateNotifyOp::kReplicate))
1131*f6dc9357SAndroid Build Coastguard Worker   }
1132*f6dc9357SAndroid Build Coastguard Worker 
1133*f6dc9357SAndroid Build Coastguard Worker   newItem.CopyDataPropsFrom(_item);
1134*f6dc9357SAndroid Build Coastguard Worker 
1135*f6dc9357SAndroid Build Coastguard Worker   UInt64 offset = 0;
1136*f6dc9357SAndroid Build Coastguard Worker   if (IntToBool(newProps))
1137*f6dc9357SAndroid Build Coastguard Worker   {
1138*f6dc9357SAndroid Build Coastguard Worker     newItem.WriteHeader(outStream);
1139*f6dc9357SAndroid Build Coastguard Worker     offset += _headerSize;
1140*f6dc9357SAndroid Build Coastguard Worker   }
1141*f6dc9357SAndroid Build Coastguard Worker   RINOK(InStream_SeekSet(_stream, offset))
1142*f6dc9357SAndroid Build Coastguard Worker 
1143*f6dc9357SAndroid Build Coastguard Worker   /*
1144*f6dc9357SAndroid Build Coastguard Worker   if (reportArcProp)
1145*f6dc9357SAndroid Build Coastguard Worker     ReportArcProps(reportArcProp, newItem,
1146*f6dc9357SAndroid Build Coastguard Worker         _props._Write_MTime,
1147*f6dc9357SAndroid Build Coastguard Worker         false, // writeCrc
1148*f6dc9357SAndroid Build Coastguard Worker         NULL); // unpacksize
1149*f6dc9357SAndroid Build Coastguard Worker   */
1150*f6dc9357SAndroid Build Coastguard Worker 
1151*f6dc9357SAndroid Build Coastguard Worker   return NCompress::CopyStream(_stream, outStream, lps);
1152*f6dc9357SAndroid Build Coastguard Worker 
1153*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
1154*f6dc9357SAndroid Build Coastguard Worker }
1155*f6dc9357SAndroid Build Coastguard Worker 
1156*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps))
1157*f6dc9357SAndroid Build Coastguard Worker {
1158*f6dc9357SAndroid Build Coastguard Worker   _timeOptions.Init();
1159*f6dc9357SAndroid Build Coastguard Worker   _props.Init();
1160*f6dc9357SAndroid Build Coastguard Worker 
1161*f6dc9357SAndroid Build Coastguard Worker   for (UInt32 i = 0; i < numProps; i++)
1162*f6dc9357SAndroid Build Coastguard Worker   {
1163*f6dc9357SAndroid Build Coastguard Worker     UString name = names[i];
1164*f6dc9357SAndroid Build Coastguard Worker     name.MakeLower_Ascii();
1165*f6dc9357SAndroid Build Coastguard Worker     if (name.IsEmpty())
1166*f6dc9357SAndroid Build Coastguard Worker       return E_INVALIDARG;
1167*f6dc9357SAndroid Build Coastguard Worker     const PROPVARIANT &value = values[i];
1168*f6dc9357SAndroid Build Coastguard Worker     {
1169*f6dc9357SAndroid Build Coastguard Worker       bool processed = false;
1170*f6dc9357SAndroid Build Coastguard Worker       RINOK(_timeOptions.Parse(name, value, processed))
1171*f6dc9357SAndroid Build Coastguard Worker       if (processed)
1172*f6dc9357SAndroid Build Coastguard Worker       {
1173*f6dc9357SAndroid Build Coastguard Worker         if (_timeOptions.Write_CTime.Val ||
1174*f6dc9357SAndroid Build Coastguard Worker             _timeOptions.Write_ATime.Val)
1175*f6dc9357SAndroid Build Coastguard Worker           return E_INVALIDARG;
1176*f6dc9357SAndroid Build Coastguard Worker         if (   _timeOptions.Prec != (UInt32)(Int32)-1
1177*f6dc9357SAndroid Build Coastguard Worker             && _timeOptions.Prec != k_PropVar_TimePrec_0
1178*f6dc9357SAndroid Build Coastguard Worker             && _timeOptions.Prec != k_PropVar_TimePrec_Unix
1179*f6dc9357SAndroid Build Coastguard Worker             && _timeOptions.Prec != k_PropVar_TimePrec_HighPrec
1180*f6dc9357SAndroid Build Coastguard Worker             && _timeOptions.Prec != k_PropVar_TimePrec_Base)
1181*f6dc9357SAndroid Build Coastguard Worker           return E_INVALIDARG;
1182*f6dc9357SAndroid Build Coastguard Worker         continue;
1183*f6dc9357SAndroid Build Coastguard Worker       }
1184*f6dc9357SAndroid Build Coastguard Worker     }
1185*f6dc9357SAndroid Build Coastguard Worker     RINOK(_props.SetProperty(name, value))
1186*f6dc9357SAndroid Build Coastguard Worker   }
1187*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1188*f6dc9357SAndroid Build Coastguard Worker }
1189*f6dc9357SAndroid Build Coastguard Worker 
1190*f6dc9357SAndroid Build Coastguard Worker static const Byte k_Signature[] = { kSignature_0, kSignature_1, kSignature_2 };
1191*f6dc9357SAndroid Build Coastguard Worker 
1192*f6dc9357SAndroid Build Coastguard Worker REGISTER_ARC_IO(
1193*f6dc9357SAndroid Build Coastguard Worker   "gzip", "gz gzip tgz tpz apk", "* * .tar .tar .tar", 0xEF,
1194*f6dc9357SAndroid Build Coastguard Worker   k_Signature, 0,
1195*f6dc9357SAndroid Build Coastguard Worker     NArcInfoFlags::kKeepName
1196*f6dc9357SAndroid Build Coastguard Worker   | NArcInfoFlags::kMTime
1197*f6dc9357SAndroid Build Coastguard Worker   | NArcInfoFlags::kMTime_Default
1198*f6dc9357SAndroid Build Coastguard Worker   , TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kUnix)
1199*f6dc9357SAndroid Build Coastguard Worker   | TIME_PREC_TO_ARC_FLAGS_TIME_DEFAULT (NFileTimeType::kUnix)
1200*f6dc9357SAndroid Build Coastguard Worker   , IsArc_Gz)
1201*f6dc9357SAndroid Build Coastguard Worker 
1202*f6dc9357SAndroid Build Coastguard Worker }}
1203