xref: /aosp_15_r20/external/lzma/CPP/7zip/Archive/XarHandler.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1*f6dc9357SAndroid Build Coastguard Worker // XarHandler.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 "../../../C/Sha256.h"
6*f6dc9357SAndroid Build Coastguard Worker #include "../../../C/Sha512.h"
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/MyLinux.h"
11*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/MyXml.h"
12*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/StringToInt.h"
13*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/UTFConvert.h"
14*f6dc9357SAndroid Build Coastguard Worker 
15*f6dc9357SAndroid Build Coastguard Worker #include "../../Windows/PropVariant.h"
16*f6dc9357SAndroid Build Coastguard Worker #include "../../Windows/TimeUtils.h"
17*f6dc9357SAndroid Build Coastguard Worker 
18*f6dc9357SAndroid Build Coastguard Worker #include "../Common/LimitedStreams.h"
19*f6dc9357SAndroid Build Coastguard Worker #include "../Common/ProgressUtils.h"
20*f6dc9357SAndroid Build Coastguard Worker #include "../Common/RegisterArc.h"
21*f6dc9357SAndroid Build Coastguard Worker #include "../Common/StreamObjects.h"
22*f6dc9357SAndroid Build Coastguard Worker #include "../Common/StreamUtils.h"
23*f6dc9357SAndroid Build Coastguard Worker 
24*f6dc9357SAndroid Build Coastguard Worker #include "../Compress/BZip2Decoder.h"
25*f6dc9357SAndroid Build Coastguard Worker #include "../Compress/CopyCoder.h"
26*f6dc9357SAndroid Build Coastguard Worker #include "../Compress/ZlibDecoder.h"
27*f6dc9357SAndroid Build Coastguard Worker 
28*f6dc9357SAndroid Build Coastguard Worker #include "Common/OutStreamWithSha1.h"
29*f6dc9357SAndroid Build Coastguard Worker 
30*f6dc9357SAndroid Build Coastguard Worker using namespace NWindows;
31*f6dc9357SAndroid Build Coastguard Worker 
32*f6dc9357SAndroid Build Coastguard Worker #define XAR_SHOW_RAW
33*f6dc9357SAndroid Build Coastguard Worker 
34*f6dc9357SAndroid Build Coastguard Worker #define Get16(p) GetBe16(p)
35*f6dc9357SAndroid Build Coastguard Worker #define Get32(p) GetBe32(p)
36*f6dc9357SAndroid Build Coastguard Worker #define Get64(p) GetBe64(p)
37*f6dc9357SAndroid Build Coastguard Worker 
38*f6dc9357SAndroid Build Coastguard Worker namespace NArchive {
39*f6dc9357SAndroid Build Coastguard Worker namespace NXar {
40*f6dc9357SAndroid Build Coastguard Worker 
41*f6dc9357SAndroid Build Coastguard Worker Z7_CLASS_IMP_NOQIB_1(
42*f6dc9357SAndroid Build Coastguard Worker   CInStreamWithSha256
43*f6dc9357SAndroid Build Coastguard Worker   , ISequentialInStream
44*f6dc9357SAndroid Build Coastguard Worker )
45*f6dc9357SAndroid Build Coastguard Worker   bool _sha512Mode;
46*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<ISequentialInStream> _stream;
47*f6dc9357SAndroid Build Coastguard Worker   CAlignedBuffer1 _sha256;
48*f6dc9357SAndroid Build Coastguard Worker   CAlignedBuffer1 _sha512;
49*f6dc9357SAndroid Build Coastguard Worker   UInt64 _size;
50*f6dc9357SAndroid Build Coastguard Worker 
Sha256()51*f6dc9357SAndroid Build Coastguard Worker   CSha256 *Sha256() { return (CSha256 *)(void *)(Byte *)_sha256; }
Sha512()52*f6dc9357SAndroid Build Coastguard Worker   CSha512 *Sha512() { return (CSha512 *)(void *)(Byte *)_sha512; }
53*f6dc9357SAndroid Build Coastguard Worker public:
54*f6dc9357SAndroid Build Coastguard Worker   CInStreamWithSha256():
55*f6dc9357SAndroid Build Coastguard Worker       _sha256(sizeof(CSha256)),
56*f6dc9357SAndroid Build Coastguard Worker       _sha512(sizeof(CSha512))
57*f6dc9357SAndroid Build Coastguard Worker       {}
58*f6dc9357SAndroid Build Coastguard Worker   void SetStream(ISequentialInStream *stream) { _stream = stream;  }
59*f6dc9357SAndroid Build Coastguard Worker   void Init(bool sha512Mode)
60*f6dc9357SAndroid Build Coastguard Worker   {
61*f6dc9357SAndroid Build Coastguard Worker     _sha512Mode = sha512Mode;
62*f6dc9357SAndroid Build Coastguard Worker     _size = 0;
63*f6dc9357SAndroid Build Coastguard Worker     if (sha512Mode)
64*f6dc9357SAndroid Build Coastguard Worker       Sha512_Init(Sha512(), SHA512_DIGEST_SIZE);
65*f6dc9357SAndroid Build Coastguard Worker     else
66*f6dc9357SAndroid Build Coastguard Worker       Sha256_Init(Sha256());
67*f6dc9357SAndroid Build Coastguard Worker   }
68*f6dc9357SAndroid Build Coastguard Worker   void ReleaseStream() { _stream.Release(); }
69*f6dc9357SAndroid Build Coastguard Worker   UInt64 GetSize() const { return _size; }
70*f6dc9357SAndroid Build Coastguard Worker   void Final256(Byte *digest) { Sha256_Final(Sha256(), digest); }
71*f6dc9357SAndroid Build Coastguard Worker   void Final512(Byte *digest) { Sha512_Final(Sha512(), digest, SHA512_DIGEST_SIZE); }
72*f6dc9357SAndroid Build Coastguard Worker };
73*f6dc9357SAndroid Build Coastguard Worker 
74*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CInStreamWithSha256::Read(void *data, UInt32 size, UInt32 *processedSize))
75*f6dc9357SAndroid Build Coastguard Worker {
76*f6dc9357SAndroid Build Coastguard Worker   UInt32 realProcessedSize;
77*f6dc9357SAndroid Build Coastguard Worker   const HRESULT result = _stream->Read(data, size, &realProcessedSize);
78*f6dc9357SAndroid Build Coastguard Worker   _size += realProcessedSize;
79*f6dc9357SAndroid Build Coastguard Worker   if (_sha512Mode)
80*f6dc9357SAndroid Build Coastguard Worker     Sha512_Update(Sha512(), (const Byte *)data, realProcessedSize);
81*f6dc9357SAndroid Build Coastguard Worker   else
82*f6dc9357SAndroid Build Coastguard Worker     Sha256_Update(Sha256(), (const Byte *)data, realProcessedSize);
83*f6dc9357SAndroid Build Coastguard Worker   if (processedSize)
84*f6dc9357SAndroid Build Coastguard Worker     *processedSize = realProcessedSize;
85*f6dc9357SAndroid Build Coastguard Worker   return result;
86*f6dc9357SAndroid Build Coastguard Worker }
87*f6dc9357SAndroid Build Coastguard Worker 
88*f6dc9357SAndroid Build Coastguard Worker 
89*f6dc9357SAndroid Build Coastguard Worker Z7_CLASS_IMP_NOQIB_1(
90*f6dc9357SAndroid Build Coastguard Worker   COutStreamWithSha256
91*f6dc9357SAndroid Build Coastguard Worker   , ISequentialOutStream
92*f6dc9357SAndroid Build Coastguard Worker )
93*f6dc9357SAndroid Build Coastguard Worker   bool _sha512Mode;
94*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<ISequentialOutStream> _stream;
95*f6dc9357SAndroid Build Coastguard Worker   CAlignedBuffer1 _sha256;
96*f6dc9357SAndroid Build Coastguard Worker   CAlignedBuffer1 _sha512;
97*f6dc9357SAndroid Build Coastguard Worker   UInt64 _size;
98*f6dc9357SAndroid Build Coastguard Worker 
99*f6dc9357SAndroid Build Coastguard Worker   CSha256 *Sha256() { return (CSha256 *)(void *)(Byte *)_sha256; }
100*f6dc9357SAndroid Build Coastguard Worker   CSha512 *Sha512() { return (CSha512 *)(void *)(Byte *)_sha512; }
101*f6dc9357SAndroid Build Coastguard Worker public:
102*f6dc9357SAndroid Build Coastguard Worker   COutStreamWithSha256():
103*f6dc9357SAndroid Build Coastguard Worker       _sha256(sizeof(CSha256)),
104*f6dc9357SAndroid Build Coastguard Worker       _sha512(sizeof(CSha512))
105*f6dc9357SAndroid Build Coastguard Worker       {}
106*f6dc9357SAndroid Build Coastguard Worker   void SetStream(ISequentialOutStream *stream) { _stream = stream; }
107*f6dc9357SAndroid Build Coastguard Worker   void ReleaseStream() { _stream.Release(); }
108*f6dc9357SAndroid Build Coastguard Worker   void Init(bool sha512Mode)
109*f6dc9357SAndroid Build Coastguard Worker   {
110*f6dc9357SAndroid Build Coastguard Worker     _sha512Mode = sha512Mode;
111*f6dc9357SAndroid Build Coastguard Worker     _size = 0;
112*f6dc9357SAndroid Build Coastguard Worker     if (sha512Mode)
113*f6dc9357SAndroid Build Coastguard Worker       Sha512_Init(Sha512(), SHA512_DIGEST_SIZE);
114*f6dc9357SAndroid Build Coastguard Worker     else
115*f6dc9357SAndroid Build Coastguard Worker       Sha256_Init(Sha256());
116*f6dc9357SAndroid Build Coastguard Worker   }
117*f6dc9357SAndroid Build Coastguard Worker   UInt64 GetSize() const { return _size; }
118*f6dc9357SAndroid Build Coastguard Worker   void Final256(Byte *digest) { Sha256_Final(Sha256(), digest); }
119*f6dc9357SAndroid Build Coastguard Worker   void Final512(Byte *digest) { Sha512_Final(Sha512(), digest, SHA512_DIGEST_SIZE); }
120*f6dc9357SAndroid Build Coastguard Worker };
121*f6dc9357SAndroid Build Coastguard Worker 
122*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(COutStreamWithSha256::Write(const void *data, UInt32 size, UInt32 *processedSize))
123*f6dc9357SAndroid Build Coastguard Worker {
124*f6dc9357SAndroid Build Coastguard Worker   HRESULT result = S_OK;
125*f6dc9357SAndroid Build Coastguard Worker   if (_stream)
126*f6dc9357SAndroid Build Coastguard Worker     result = _stream->Write(data, size, &size);
127*f6dc9357SAndroid Build Coastguard Worker   // if (_calculate)
128*f6dc9357SAndroid Build Coastguard Worker   if (_sha512Mode)
129*f6dc9357SAndroid Build Coastguard Worker     Sha512_Update(Sha512(), (const Byte *)data, size);
130*f6dc9357SAndroid Build Coastguard Worker   else
131*f6dc9357SAndroid Build Coastguard Worker     Sha256_Update(Sha256(), (const Byte *)data, size);
132*f6dc9357SAndroid Build Coastguard Worker   _size += size;
133*f6dc9357SAndroid Build Coastguard Worker   if (processedSize)
134*f6dc9357SAndroid Build Coastguard Worker     *processedSize = size;
135*f6dc9357SAndroid Build Coastguard Worker   return result;
136*f6dc9357SAndroid Build Coastguard Worker }
137*f6dc9357SAndroid Build Coastguard Worker 
138*f6dc9357SAndroid Build Coastguard Worker // we limit supported xml sizes:
139*f6dc9357SAndroid Build Coastguard Worker // ((size_t)1 << (sizeof(size_t) / 2 + 28)) - (1u << 14);
140*f6dc9357SAndroid Build Coastguard Worker static const size_t kXmlSizeMax = ((size_t)1 << 30) - (1u << 14);
141*f6dc9357SAndroid Build Coastguard Worker static const size_t kXmlPackSizeMax = kXmlSizeMax;
142*f6dc9357SAndroid Build Coastguard Worker 
143*f6dc9357SAndroid Build Coastguard Worker #define XAR_CKSUM_NONE    0
144*f6dc9357SAndroid Build Coastguard Worker #define XAR_CKSUM_SHA1    1
145*f6dc9357SAndroid Build Coastguard Worker #define XAR_CKSUM_MD5     2
146*f6dc9357SAndroid Build Coastguard Worker #define XAR_CKSUM_SHA256  3
147*f6dc9357SAndroid Build Coastguard Worker #define XAR_CKSUM_SHA512  4
148*f6dc9357SAndroid Build Coastguard Worker // #define XAR_CKSUM_OTHER   3
149*f6dc9357SAndroid Build Coastguard Worker // fork version of xar can use (3) as special case,
150*f6dc9357SAndroid Build Coastguard Worker // where name of hash is stored as string at the end of header
151*f6dc9357SAndroid Build Coastguard Worker // we do not support such hash still.
152*f6dc9357SAndroid Build Coastguard Worker 
153*f6dc9357SAndroid Build Coastguard Worker static const char * const k_ChecksumNames[] =
154*f6dc9357SAndroid Build Coastguard Worker {
155*f6dc9357SAndroid Build Coastguard Worker     "NONE"
156*f6dc9357SAndroid Build Coastguard Worker   , "SHA1"
157*f6dc9357SAndroid Build Coastguard Worker   , "MD5"
158*f6dc9357SAndroid Build Coastguard Worker   , "SHA256"
159*f6dc9357SAndroid Build Coastguard Worker   , "SHA512"
160*f6dc9357SAndroid Build Coastguard Worker };
161*f6dc9357SAndroid Build Coastguard Worker 
162*f6dc9357SAndroid Build Coastguard Worker static unsigned GetHashSize(int algo)
163*f6dc9357SAndroid Build Coastguard Worker {
164*f6dc9357SAndroid Build Coastguard Worker   if (algo <= XAR_CKSUM_NONE || algo > XAR_CKSUM_SHA512)
165*f6dc9357SAndroid Build Coastguard Worker     return 0;
166*f6dc9357SAndroid Build Coastguard Worker   if (algo == XAR_CKSUM_SHA1)
167*f6dc9357SAndroid Build Coastguard Worker     return SHA1_DIGEST_SIZE;
168*f6dc9357SAndroid Build Coastguard Worker   return (16u >> XAR_CKSUM_MD5) << algo;
169*f6dc9357SAndroid Build Coastguard Worker }
170*f6dc9357SAndroid Build Coastguard Worker 
171*f6dc9357SAndroid Build Coastguard Worker #define METHOD_NAME_ZLIB  "zlib"
172*f6dc9357SAndroid Build Coastguard Worker 
173*f6dc9357SAndroid Build Coastguard Worker static int Find_ChecksumId_for_Name(const AString &style)
174*f6dc9357SAndroid Build Coastguard Worker {
175*f6dc9357SAndroid Build Coastguard Worker   for (unsigned i = 0; i < Z7_ARRAY_SIZE(k_ChecksumNames); i++)
176*f6dc9357SAndroid Build Coastguard Worker   {
177*f6dc9357SAndroid Build Coastguard Worker     // old xars used upper case in "style"
178*f6dc9357SAndroid Build Coastguard Worker     // new xars use  lower case in "style"
179*f6dc9357SAndroid Build Coastguard Worker     if (style.IsEqualTo_Ascii_NoCase(k_ChecksumNames[i]))
180*f6dc9357SAndroid Build Coastguard Worker       return (int)i;
181*f6dc9357SAndroid Build Coastguard Worker   }
182*f6dc9357SAndroid Build Coastguard Worker   return -1;
183*f6dc9357SAndroid Build Coastguard Worker }
184*f6dc9357SAndroid Build Coastguard Worker 
185*f6dc9357SAndroid Build Coastguard Worker 
186*f6dc9357SAndroid Build Coastguard Worker struct CCheckSum
187*f6dc9357SAndroid Build Coastguard Worker {
188*f6dc9357SAndroid Build Coastguard Worker   int AlgoNumber;
189*f6dc9357SAndroid Build Coastguard Worker   bool Error;
190*f6dc9357SAndroid Build Coastguard Worker   CByteBuffer Data;
191*f6dc9357SAndroid Build Coastguard Worker   AString Style;
192*f6dc9357SAndroid Build Coastguard Worker 
193*f6dc9357SAndroid Build Coastguard Worker   CCheckSum(): AlgoNumber(-1), Error(false) {}
194*f6dc9357SAndroid Build Coastguard Worker   void AddNameToString(AString &s) const;
195*f6dc9357SAndroid Build Coastguard Worker };
196*f6dc9357SAndroid Build Coastguard Worker 
197*f6dc9357SAndroid Build Coastguard Worker void CCheckSum::AddNameToString(AString &s) const
198*f6dc9357SAndroid Build Coastguard Worker {
199*f6dc9357SAndroid Build Coastguard Worker   if (Style.IsEmpty())
200*f6dc9357SAndroid Build Coastguard Worker     s.Add_OptSpaced("NO-CHECKSUM");
201*f6dc9357SAndroid Build Coastguard Worker   else
202*f6dc9357SAndroid Build Coastguard Worker   {
203*f6dc9357SAndroid Build Coastguard Worker     s.Add_OptSpaced(Style);
204*f6dc9357SAndroid Build Coastguard Worker     if (Error)
205*f6dc9357SAndroid Build Coastguard Worker       s += "-ERROR";
206*f6dc9357SAndroid Build Coastguard Worker   }
207*f6dc9357SAndroid Build Coastguard Worker }
208*f6dc9357SAndroid Build Coastguard Worker 
209*f6dc9357SAndroid Build Coastguard Worker 
210*f6dc9357SAndroid Build Coastguard Worker struct CFile
211*f6dc9357SAndroid Build Coastguard Worker {
212*f6dc9357SAndroid Build Coastguard Worker   bool IsDir;
213*f6dc9357SAndroid Build Coastguard Worker   bool Is_SymLink;
214*f6dc9357SAndroid Build Coastguard Worker   bool HasData;
215*f6dc9357SAndroid Build Coastguard Worker   bool Mode_Defined;
216*f6dc9357SAndroid Build Coastguard Worker   bool INode_Defined;
217*f6dc9357SAndroid Build Coastguard Worker   bool UserId_Defined;
218*f6dc9357SAndroid Build Coastguard Worker   bool GroupId_Defined;
219*f6dc9357SAndroid Build Coastguard Worker   // bool Device_Defined;
220*f6dc9357SAndroid Build Coastguard Worker   bool Id_Defined;
221*f6dc9357SAndroid Build Coastguard Worker 
222*f6dc9357SAndroid Build Coastguard Worker   int Parent;
223*f6dc9357SAndroid Build Coastguard Worker   UInt32 Mode;
224*f6dc9357SAndroid Build Coastguard Worker 
225*f6dc9357SAndroid Build Coastguard Worker   UInt64 Size;
226*f6dc9357SAndroid Build Coastguard Worker   UInt64 PackSize;
227*f6dc9357SAndroid Build Coastguard Worker   UInt64 Offset;
228*f6dc9357SAndroid Build Coastguard Worker   UInt64 MTime;
229*f6dc9357SAndroid Build Coastguard Worker   UInt64 CTime;
230*f6dc9357SAndroid Build Coastguard Worker   UInt64 ATime;
231*f6dc9357SAndroid Build Coastguard Worker   UInt64 INode;
232*f6dc9357SAndroid Build Coastguard Worker   UInt64 UserId;
233*f6dc9357SAndroid Build Coastguard Worker   UInt64 GroupId;
234*f6dc9357SAndroid Build Coastguard Worker   // UInt64 Device;
235*f6dc9357SAndroid Build Coastguard Worker 
236*f6dc9357SAndroid Build Coastguard Worker   AString Name;
237*f6dc9357SAndroid Build Coastguard Worker   AString Method;
238*f6dc9357SAndroid Build Coastguard Worker   AString User;
239*f6dc9357SAndroid Build Coastguard Worker   AString Group;
240*f6dc9357SAndroid Build Coastguard Worker   // AString Id;
241*f6dc9357SAndroid Build Coastguard Worker   AString Type;
242*f6dc9357SAndroid Build Coastguard Worker   AString Link;
243*f6dc9357SAndroid Build Coastguard Worker   // AString LinkType;
244*f6dc9357SAndroid Build Coastguard Worker   // AString LinkFrom;
245*f6dc9357SAndroid Build Coastguard Worker 
246*f6dc9357SAndroid Build Coastguard Worker   UInt64 Id;
247*f6dc9357SAndroid Build Coastguard Worker   CCheckSum extracted_checksum;
248*f6dc9357SAndroid Build Coastguard Worker   CCheckSum archived_checksum;
249*f6dc9357SAndroid Build Coastguard Worker 
250*f6dc9357SAndroid Build Coastguard Worker   CFile(int parent):
251*f6dc9357SAndroid Build Coastguard Worker       IsDir(false),
252*f6dc9357SAndroid Build Coastguard Worker       Is_SymLink(false),
253*f6dc9357SAndroid Build Coastguard Worker       HasData(false),
254*f6dc9357SAndroid Build Coastguard Worker       Mode_Defined(false),
255*f6dc9357SAndroid Build Coastguard Worker       INode_Defined(false),
256*f6dc9357SAndroid Build Coastguard Worker       UserId_Defined(false),
257*f6dc9357SAndroid Build Coastguard Worker       GroupId_Defined(false),
258*f6dc9357SAndroid Build Coastguard Worker       // Device_Defined(false),
259*f6dc9357SAndroid Build Coastguard Worker       Id_Defined(false),
260*f6dc9357SAndroid Build Coastguard Worker       Parent(parent),
261*f6dc9357SAndroid Build Coastguard Worker       Mode(0),
262*f6dc9357SAndroid Build Coastguard Worker       Size(0), PackSize(0), Offset(0),
263*f6dc9357SAndroid Build Coastguard Worker       MTime(0), CTime(0), ATime(0),
264*f6dc9357SAndroid Build Coastguard Worker       INode(0)
265*f6dc9357SAndroid Build Coastguard Worker       {}
266*f6dc9357SAndroid Build Coastguard Worker 
267*f6dc9357SAndroid Build Coastguard Worker   bool IsCopyMethod() const
268*f6dc9357SAndroid Build Coastguard Worker   {
269*f6dc9357SAndroid Build Coastguard Worker     return Method.IsEmpty() || Method == "octet-stream";
270*f6dc9357SAndroid Build Coastguard Worker   }
271*f6dc9357SAndroid Build Coastguard Worker 
272*f6dc9357SAndroid Build Coastguard Worker   void UpdateTotalPackSize(UInt64 &totalSize) const
273*f6dc9357SAndroid Build Coastguard Worker   {
274*f6dc9357SAndroid Build Coastguard Worker     const UInt64 t = Offset + PackSize;
275*f6dc9357SAndroid Build Coastguard Worker     if (t >= Offset)
276*f6dc9357SAndroid Build Coastguard Worker     if (totalSize < t)
277*f6dc9357SAndroid Build Coastguard Worker         totalSize = t;
278*f6dc9357SAndroid Build Coastguard Worker   }
279*f6dc9357SAndroid Build Coastguard Worker };
280*f6dc9357SAndroid Build Coastguard Worker 
281*f6dc9357SAndroid Build Coastguard Worker 
282*f6dc9357SAndroid Build Coastguard Worker Z7_CLASS_IMP_CHandler_IInArchive_2(
283*f6dc9357SAndroid Build Coastguard Worker     IArchiveGetRawProps,
284*f6dc9357SAndroid Build Coastguard Worker     IInArchiveGetStream
285*f6dc9357SAndroid Build Coastguard Worker )
286*f6dc9357SAndroid Build Coastguard Worker   bool _is_pkg;
287*f6dc9357SAndroid Build Coastguard Worker   bool _toc_CrcError;
288*f6dc9357SAndroid Build Coastguard Worker   CObjectVector<CFile> _files;
289*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<IInStream> _inStream;
290*f6dc9357SAndroid Build Coastguard Worker   UInt64 _dataStartPos;
291*f6dc9357SAndroid Build Coastguard Worker   UInt64 _phySize;
292*f6dc9357SAndroid Build Coastguard Worker   CAlignedBuffer _xmlBuf;
293*f6dc9357SAndroid Build Coastguard Worker   size_t _xmlLen;
294*f6dc9357SAndroid Build Coastguard Worker   // UInt64 CreationTime;
295*f6dc9357SAndroid Build Coastguard Worker   AString CreationTime_String;
296*f6dc9357SAndroid Build Coastguard Worker   UInt32 _checkSumAlgo;
297*f6dc9357SAndroid Build Coastguard Worker   Int32 _mainSubfile;
298*f6dc9357SAndroid Build Coastguard Worker 
299*f6dc9357SAndroid Build Coastguard Worker   HRESULT Open2(IInStream *stream);
300*f6dc9357SAndroid Build Coastguard Worker };
301*f6dc9357SAndroid Build Coastguard Worker 
302*f6dc9357SAndroid Build Coastguard Worker 
303*f6dc9357SAndroid Build Coastguard Worker static const Byte kArcProps[] =
304*f6dc9357SAndroid Build Coastguard Worker {
305*f6dc9357SAndroid Build Coastguard Worker   kpidSubType,
306*f6dc9357SAndroid Build Coastguard Worker   // kpidHeadersSize,
307*f6dc9357SAndroid Build Coastguard Worker   kpidMethod,
308*f6dc9357SAndroid Build Coastguard Worker   kpidCTime
309*f6dc9357SAndroid Build Coastguard Worker };
310*f6dc9357SAndroid Build Coastguard Worker 
311*f6dc9357SAndroid Build Coastguard Worker // #define kpidLinkType 250
312*f6dc9357SAndroid Build Coastguard Worker // #define kpidLinkFrom 251
313*f6dc9357SAndroid Build Coastguard Worker 
314*f6dc9357SAndroid Build Coastguard Worker static const Byte kProps[] =
315*f6dc9357SAndroid Build Coastguard Worker {
316*f6dc9357SAndroid Build Coastguard Worker   kpidPath,
317*f6dc9357SAndroid Build Coastguard Worker   kpidSize,
318*f6dc9357SAndroid Build Coastguard Worker   kpidPackSize,
319*f6dc9357SAndroid Build Coastguard Worker   kpidMTime,
320*f6dc9357SAndroid Build Coastguard Worker   kpidCTime,
321*f6dc9357SAndroid Build Coastguard Worker   kpidATime,
322*f6dc9357SAndroid Build Coastguard Worker   kpidPosixAttrib,
323*f6dc9357SAndroid Build Coastguard Worker   kpidType,
324*f6dc9357SAndroid Build Coastguard Worker   kpidUser,
325*f6dc9357SAndroid Build Coastguard Worker   kpidGroup,
326*f6dc9357SAndroid Build Coastguard Worker   kpidUserId,
327*f6dc9357SAndroid Build Coastguard Worker   kpidGroupId,
328*f6dc9357SAndroid Build Coastguard Worker   kpidINode,
329*f6dc9357SAndroid Build Coastguard Worker   // kpidDeviceMajor,
330*f6dc9357SAndroid Build Coastguard Worker   // kpidDeviceMinor,
331*f6dc9357SAndroid Build Coastguard Worker   kpidSymLink,
332*f6dc9357SAndroid Build Coastguard Worker   // kpidLinkType,
333*f6dc9357SAndroid Build Coastguard Worker   // kpidLinkFrom,
334*f6dc9357SAndroid Build Coastguard Worker   kpidMethod,
335*f6dc9357SAndroid Build Coastguard Worker   kpidId,
336*f6dc9357SAndroid Build Coastguard Worker   kpidOffset
337*f6dc9357SAndroid Build Coastguard Worker };
338*f6dc9357SAndroid Build Coastguard Worker 
339*f6dc9357SAndroid Build Coastguard Worker IMP_IInArchive_Props
340*f6dc9357SAndroid Build Coastguard Worker IMP_IInArchive_ArcProps
341*f6dc9357SAndroid Build Coastguard Worker 
342*f6dc9357SAndroid Build Coastguard Worker static bool ParseUInt64(const CXmlItem &item, const char *name, UInt64 &res)
343*f6dc9357SAndroid Build Coastguard Worker {
344*f6dc9357SAndroid Build Coastguard Worker   const AString s (item.GetSubStringForTag(name));
345*f6dc9357SAndroid Build Coastguard Worker   if (s.IsEmpty())
346*f6dc9357SAndroid Build Coastguard Worker     return false;
347*f6dc9357SAndroid Build Coastguard Worker   const char *end;
348*f6dc9357SAndroid Build Coastguard Worker   res = ConvertStringToUInt64(s, &end);
349*f6dc9357SAndroid Build Coastguard Worker   return *end == 0;
350*f6dc9357SAndroid Build Coastguard Worker }
351*f6dc9357SAndroid Build Coastguard Worker 
352*f6dc9357SAndroid Build Coastguard Worker 
353*f6dc9357SAndroid Build Coastguard Worker #define PARSE_NUM(_num_, _dest_) \
354*f6dc9357SAndroid Build Coastguard Worker     { const char *end; _dest_ = ConvertStringToUInt32(p, &end); \
355*f6dc9357SAndroid Build Coastguard Worker     if ((unsigned)(end - p) != _num_) return 0; \
356*f6dc9357SAndroid Build Coastguard Worker     p += _num_ + 1; }
357*f6dc9357SAndroid Build Coastguard Worker 
358*f6dc9357SAndroid Build Coastguard Worker static UInt64 ParseTime(const CXmlItem &item, const char *name /* , bool z_isRequired */ )
359*f6dc9357SAndroid Build Coastguard Worker {
360*f6dc9357SAndroid Build Coastguard Worker   const AString s (item.GetSubStringForTag(name));
361*f6dc9357SAndroid Build Coastguard Worker   if (s.Len() < 20 /* (z_isRequired ? 20u : 19u) */)
362*f6dc9357SAndroid Build Coastguard Worker     return 0;
363*f6dc9357SAndroid Build Coastguard Worker   const char *p = s;
364*f6dc9357SAndroid Build Coastguard Worker   if (p[ 4] != '-' ||
365*f6dc9357SAndroid Build Coastguard Worker       p[ 7] != '-' ||
366*f6dc9357SAndroid Build Coastguard Worker       p[10] != 'T' ||
367*f6dc9357SAndroid Build Coastguard Worker       p[13] != ':' ||
368*f6dc9357SAndroid Build Coastguard Worker       p[16] != ':')
369*f6dc9357SAndroid Build Coastguard Worker     return 0;
370*f6dc9357SAndroid Build Coastguard Worker   // if (z_isRequired)
371*f6dc9357SAndroid Build Coastguard Worker   if (p[19] != 'Z')
372*f6dc9357SAndroid Build Coastguard Worker     return 0;
373*f6dc9357SAndroid Build Coastguard Worker   UInt32 year, month, day, hour, min, sec;
374*f6dc9357SAndroid Build Coastguard Worker   PARSE_NUM(4, year)
375*f6dc9357SAndroid Build Coastguard Worker   PARSE_NUM(2, month)
376*f6dc9357SAndroid Build Coastguard Worker   PARSE_NUM(2, day)
377*f6dc9357SAndroid Build Coastguard Worker   PARSE_NUM(2, hour)
378*f6dc9357SAndroid Build Coastguard Worker   PARSE_NUM(2, min)
379*f6dc9357SAndroid Build Coastguard Worker   PARSE_NUM(2, sec)
380*f6dc9357SAndroid Build Coastguard Worker   UInt64 numSecs;
381*f6dc9357SAndroid Build Coastguard Worker   if (!NTime::GetSecondsSince1601(year, month, day, hour, min, sec, numSecs))
382*f6dc9357SAndroid Build Coastguard Worker     return 0;
383*f6dc9357SAndroid Build Coastguard Worker   return numSecs * 10000000;
384*f6dc9357SAndroid Build Coastguard Worker }
385*f6dc9357SAndroid Build Coastguard Worker 
386*f6dc9357SAndroid Build Coastguard Worker 
387*f6dc9357SAndroid Build Coastguard Worker static void ParseChecksum(const CXmlItem &item, const char *name, CCheckSum &checksum)
388*f6dc9357SAndroid Build Coastguard Worker {
389*f6dc9357SAndroid Build Coastguard Worker   const CXmlItem *checkItem = item.FindSubTag_GetPtr(name);
390*f6dc9357SAndroid Build Coastguard Worker   if (!checkItem)
391*f6dc9357SAndroid Build Coastguard Worker     return; // false;
392*f6dc9357SAndroid Build Coastguard Worker   checksum.Style = checkItem->GetPropVal("style");
393*f6dc9357SAndroid Build Coastguard Worker   const AString s (checkItem->GetSubString());
394*f6dc9357SAndroid Build Coastguard Worker   if ((s.Len() & 1) == 0 && s.Len() <= (2u << 7)) // 1024-bit max
395*f6dc9357SAndroid Build Coastguard Worker   {
396*f6dc9357SAndroid Build Coastguard Worker     const size_t size = s.Len() / 2;
397*f6dc9357SAndroid Build Coastguard Worker     CByteBuffer temp(size);
398*f6dc9357SAndroid Build Coastguard Worker     if ((size_t)(ParseHexString(s, temp) - temp) == size)
399*f6dc9357SAndroid Build Coastguard Worker     {
400*f6dc9357SAndroid Build Coastguard Worker       checksum.Data = temp;
401*f6dc9357SAndroid Build Coastguard Worker       const int index = Find_ChecksumId_for_Name(checksum.Style);
402*f6dc9357SAndroid Build Coastguard Worker       if (index >= 0 && checksum.Data.Size() == GetHashSize(index))
403*f6dc9357SAndroid Build Coastguard Worker       {
404*f6dc9357SAndroid Build Coastguard Worker         checksum.AlgoNumber = index;
405*f6dc9357SAndroid Build Coastguard Worker         return;
406*f6dc9357SAndroid Build Coastguard Worker       }
407*f6dc9357SAndroid Build Coastguard Worker     }
408*f6dc9357SAndroid Build Coastguard Worker   }
409*f6dc9357SAndroid Build Coastguard Worker   checksum.Error = true;
410*f6dc9357SAndroid Build Coastguard Worker }
411*f6dc9357SAndroid Build Coastguard Worker 
412*f6dc9357SAndroid Build Coastguard Worker 
413*f6dc9357SAndroid Build Coastguard Worker static bool AddItem(const CXmlItem &item, CObjectVector<CFile> &files, int parent, int level)
414*f6dc9357SAndroid Build Coastguard Worker {
415*f6dc9357SAndroid Build Coastguard Worker   if (!item.IsTag)
416*f6dc9357SAndroid Build Coastguard Worker     return true;
417*f6dc9357SAndroid Build Coastguard Worker   if (level >= 1024)
418*f6dc9357SAndroid Build Coastguard Worker     return false;
419*f6dc9357SAndroid Build Coastguard Worker   if (item.Name == "file")
420*f6dc9357SAndroid Build Coastguard Worker   {
421*f6dc9357SAndroid Build Coastguard Worker     CFile file(parent);
422*f6dc9357SAndroid Build Coastguard Worker     parent = (int)files.Size();
423*f6dc9357SAndroid Build Coastguard Worker     {
424*f6dc9357SAndroid Build Coastguard Worker       const AString id = item.GetPropVal("id");
425*f6dc9357SAndroid Build Coastguard Worker       const char *end;
426*f6dc9357SAndroid Build Coastguard Worker       file.Id = ConvertStringToUInt64(id, &end);
427*f6dc9357SAndroid Build Coastguard Worker       if (*end == 0)
428*f6dc9357SAndroid Build Coastguard Worker         file.Id_Defined = true;
429*f6dc9357SAndroid Build Coastguard Worker     }
430*f6dc9357SAndroid Build Coastguard Worker     file.Name = item.GetSubStringForTag("name");
431*f6dc9357SAndroid Build Coastguard Worker     z7_xml_DecodeString(file.Name);
432*f6dc9357SAndroid Build Coastguard Worker     {
433*f6dc9357SAndroid Build Coastguard Worker       const CXmlItem *typeItem = item.FindSubTag_GetPtr("type");
434*f6dc9357SAndroid Build Coastguard Worker       if (typeItem)
435*f6dc9357SAndroid Build Coastguard Worker       {
436*f6dc9357SAndroid Build Coastguard Worker         file.Type = typeItem->GetSubString();
437*f6dc9357SAndroid Build Coastguard Worker         // file.LinkFrom = typeItem->GetPropVal("link");
438*f6dc9357SAndroid Build Coastguard Worker         if (file.Type == "directory")
439*f6dc9357SAndroid Build Coastguard Worker           file.IsDir = true;
440*f6dc9357SAndroid Build Coastguard Worker         else
441*f6dc9357SAndroid Build Coastguard Worker         {
442*f6dc9357SAndroid Build Coastguard Worker           // file.IsDir = false;
443*f6dc9357SAndroid Build Coastguard Worker           /*
444*f6dc9357SAndroid Build Coastguard Worker           else if (file.Type == "file")
445*f6dc9357SAndroid Build Coastguard Worker           {}
446*f6dc9357SAndroid Build Coastguard Worker           else if (file.Type == "hardlink")
447*f6dc9357SAndroid Build Coastguard Worker           {}
448*f6dc9357SAndroid Build Coastguard Worker           else
449*f6dc9357SAndroid Build Coastguard Worker           */
450*f6dc9357SAndroid Build Coastguard Worker           if (file.Type == "symlink")
451*f6dc9357SAndroid Build Coastguard Worker             file.Is_SymLink = true;
452*f6dc9357SAndroid Build Coastguard Worker           // file.IsDir = false;
453*f6dc9357SAndroid Build Coastguard Worker         }
454*f6dc9357SAndroid Build Coastguard Worker       }
455*f6dc9357SAndroid Build Coastguard Worker     }
456*f6dc9357SAndroid Build Coastguard Worker     {
457*f6dc9357SAndroid Build Coastguard Worker       const CXmlItem *linkItem = item.FindSubTag_GetPtr("link");
458*f6dc9357SAndroid Build Coastguard Worker       if (linkItem)
459*f6dc9357SAndroid Build Coastguard Worker       {
460*f6dc9357SAndroid Build Coastguard Worker         // file.LinkType = linkItem->GetPropVal("type");
461*f6dc9357SAndroid Build Coastguard Worker         file.Link = linkItem->GetSubString();
462*f6dc9357SAndroid Build Coastguard Worker         z7_xml_DecodeString(file.Link);
463*f6dc9357SAndroid Build Coastguard Worker       }
464*f6dc9357SAndroid Build Coastguard Worker     }
465*f6dc9357SAndroid Build Coastguard Worker 
466*f6dc9357SAndroid Build Coastguard Worker     const CXmlItem *dataItem = item.FindSubTag_GetPtr("data");
467*f6dc9357SAndroid Build Coastguard Worker     if (dataItem && !file.IsDir)
468*f6dc9357SAndroid Build Coastguard Worker     {
469*f6dc9357SAndroid Build Coastguard Worker       file.HasData = true;
470*f6dc9357SAndroid Build Coastguard Worker       if (!ParseUInt64(*dataItem, "size", file.Size))
471*f6dc9357SAndroid Build Coastguard Worker         return false;
472*f6dc9357SAndroid Build Coastguard Worker       if (!ParseUInt64(*dataItem, "length", file.PackSize))
473*f6dc9357SAndroid Build Coastguard Worker         return false;
474*f6dc9357SAndroid Build Coastguard Worker       if (!ParseUInt64(*dataItem, "offset", file.Offset))
475*f6dc9357SAndroid Build Coastguard Worker         return false;
476*f6dc9357SAndroid Build Coastguard Worker       ParseChecksum(*dataItem, "extracted-checksum", file.extracted_checksum);
477*f6dc9357SAndroid Build Coastguard Worker       ParseChecksum(*dataItem, "archived-checksum",  file.archived_checksum);
478*f6dc9357SAndroid Build Coastguard Worker       const CXmlItem *encodingItem = dataItem->FindSubTag_GetPtr("encoding");
479*f6dc9357SAndroid Build Coastguard Worker       if (encodingItem)
480*f6dc9357SAndroid Build Coastguard Worker       {
481*f6dc9357SAndroid Build Coastguard Worker         AString s (encodingItem->GetPropVal("style"));
482*f6dc9357SAndroid Build Coastguard Worker         if (!s.IsEmpty())
483*f6dc9357SAndroid Build Coastguard Worker         {
484*f6dc9357SAndroid Build Coastguard Worker           const AString appl ("application/");
485*f6dc9357SAndroid Build Coastguard Worker           if (s.IsPrefixedBy(appl))
486*f6dc9357SAndroid Build Coastguard Worker           {
487*f6dc9357SAndroid Build Coastguard Worker             s.DeleteFrontal(appl.Len());
488*f6dc9357SAndroid Build Coastguard Worker             const AString xx ("x-");
489*f6dc9357SAndroid Build Coastguard Worker             if (s.IsPrefixedBy(xx))
490*f6dc9357SAndroid Build Coastguard Worker             {
491*f6dc9357SAndroid Build Coastguard Worker               s.DeleteFrontal(xx.Len());
492*f6dc9357SAndroid Build Coastguard Worker               if (s == "gzip")
493*f6dc9357SAndroid Build Coastguard Worker                 s = METHOD_NAME_ZLIB;
494*f6dc9357SAndroid Build Coastguard Worker             }
495*f6dc9357SAndroid Build Coastguard Worker           }
496*f6dc9357SAndroid Build Coastguard Worker           file.Method = s;
497*f6dc9357SAndroid Build Coastguard Worker         }
498*f6dc9357SAndroid Build Coastguard Worker       }
499*f6dc9357SAndroid Build Coastguard Worker     }
500*f6dc9357SAndroid Build Coastguard Worker 
501*f6dc9357SAndroid Build Coastguard Worker     file.INode_Defined = ParseUInt64(item, "inode", file.INode);
502*f6dc9357SAndroid Build Coastguard Worker     file.UserId_Defined = ParseUInt64(item, "uid", file.UserId);
503*f6dc9357SAndroid Build Coastguard Worker     file.GroupId_Defined = ParseUInt64(item, "gid", file.GroupId);
504*f6dc9357SAndroid Build Coastguard Worker     // file.Device_Defined = ParseUInt64(item, "deviceno", file.Device);
505*f6dc9357SAndroid Build Coastguard Worker     file.MTime = ParseTime(item, "mtime"); // z_IsRequied = true
506*f6dc9357SAndroid Build Coastguard Worker     file.CTime = ParseTime(item, "ctime");
507*f6dc9357SAndroid Build Coastguard Worker     file.ATime = ParseTime(item, "atime");
508*f6dc9357SAndroid Build Coastguard Worker     {
509*f6dc9357SAndroid Build Coastguard Worker       const AString s (item.GetSubStringForTag("mode"));
510*f6dc9357SAndroid Build Coastguard Worker       if (s[0] == '0')
511*f6dc9357SAndroid Build Coastguard Worker       {
512*f6dc9357SAndroid Build Coastguard Worker         const char *end;
513*f6dc9357SAndroid Build Coastguard Worker         file.Mode = ConvertOctStringToUInt32(s, &end);
514*f6dc9357SAndroid Build Coastguard Worker         file.Mode_Defined = (*end == 0);
515*f6dc9357SAndroid Build Coastguard Worker       }
516*f6dc9357SAndroid Build Coastguard Worker     }
517*f6dc9357SAndroid Build Coastguard Worker     file.User = item.GetSubStringForTag("user");
518*f6dc9357SAndroid Build Coastguard Worker     file.Group = item.GetSubStringForTag("group");
519*f6dc9357SAndroid Build Coastguard Worker 
520*f6dc9357SAndroid Build Coastguard Worker     files.Add(file);
521*f6dc9357SAndroid Build Coastguard Worker   }
522*f6dc9357SAndroid Build Coastguard Worker 
523*f6dc9357SAndroid Build Coastguard Worker   FOR_VECTOR (i, item.SubItems)
524*f6dc9357SAndroid Build Coastguard Worker     if (!AddItem(item.SubItems[i], files, parent, level + 1))
525*f6dc9357SAndroid Build Coastguard Worker       return false;
526*f6dc9357SAndroid Build Coastguard Worker   return true;
527*f6dc9357SAndroid Build Coastguard Worker }
528*f6dc9357SAndroid Build Coastguard Worker 
529*f6dc9357SAndroid Build Coastguard Worker 
530*f6dc9357SAndroid Build Coastguard Worker 
531*f6dc9357SAndroid Build Coastguard Worker struct CInStreamWithHash
532*f6dc9357SAndroid Build Coastguard Worker {
533*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ISequentialInStream, CInStreamWithSha1> inStreamSha1;
534*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ISequentialInStream, CInStreamWithSha256> inStreamSha256;
535*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ISequentialInStream, CLimitedSequentialInStream> inStreamLim;
536*f6dc9357SAndroid Build Coastguard Worker 
537*f6dc9357SAndroid Build Coastguard Worker   void SetStreamAndInit(ISequentialInStream *stream, int algo);
538*f6dc9357SAndroid Build Coastguard Worker   bool CheckHash(int algo, const Byte *digest_from_arc) const;
539*f6dc9357SAndroid Build Coastguard Worker };
540*f6dc9357SAndroid Build Coastguard Worker 
541*f6dc9357SAndroid Build Coastguard Worker 
542*f6dc9357SAndroid Build Coastguard Worker void CInStreamWithHash::SetStreamAndInit(ISequentialInStream *stream, int algo)
543*f6dc9357SAndroid Build Coastguard Worker {
544*f6dc9357SAndroid Build Coastguard Worker   if (algo == XAR_CKSUM_SHA1)
545*f6dc9357SAndroid Build Coastguard Worker   {
546*f6dc9357SAndroid Build Coastguard Worker     inStreamSha1->SetStream(stream);
547*f6dc9357SAndroid Build Coastguard Worker     inStreamSha1->Init();
548*f6dc9357SAndroid Build Coastguard Worker     stream = inStreamSha1;
549*f6dc9357SAndroid Build Coastguard Worker   }
550*f6dc9357SAndroid Build Coastguard Worker   else if (algo == XAR_CKSUM_SHA256
551*f6dc9357SAndroid Build Coastguard Worker         || algo == XAR_CKSUM_SHA512)
552*f6dc9357SAndroid Build Coastguard Worker   {
553*f6dc9357SAndroid Build Coastguard Worker     inStreamSha256->SetStream(stream);
554*f6dc9357SAndroid Build Coastguard Worker     inStreamSha256->Init(algo == XAR_CKSUM_SHA512);
555*f6dc9357SAndroid Build Coastguard Worker     stream = inStreamSha256;
556*f6dc9357SAndroid Build Coastguard Worker   }
557*f6dc9357SAndroid Build Coastguard Worker   inStreamLim->SetStream(stream);
558*f6dc9357SAndroid Build Coastguard Worker }
559*f6dc9357SAndroid Build Coastguard Worker 
560*f6dc9357SAndroid Build Coastguard Worker bool CInStreamWithHash::CheckHash(int algo, const Byte *digest_from_arc) const
561*f6dc9357SAndroid Build Coastguard Worker {
562*f6dc9357SAndroid Build Coastguard Worker   if (algo == XAR_CKSUM_SHA1)
563*f6dc9357SAndroid Build Coastguard Worker   {
564*f6dc9357SAndroid Build Coastguard Worker     Byte digest[SHA1_DIGEST_SIZE];
565*f6dc9357SAndroid Build Coastguard Worker     inStreamSha1->Final(digest);
566*f6dc9357SAndroid Build Coastguard Worker     if (memcmp(digest, digest_from_arc, sizeof(digest)) != 0)
567*f6dc9357SAndroid Build Coastguard Worker       return false;
568*f6dc9357SAndroid Build Coastguard Worker   }
569*f6dc9357SAndroid Build Coastguard Worker   else if (algo == XAR_CKSUM_SHA256)
570*f6dc9357SAndroid Build Coastguard Worker   {
571*f6dc9357SAndroid Build Coastguard Worker     Byte digest[SHA256_DIGEST_SIZE];
572*f6dc9357SAndroid Build Coastguard Worker     inStreamSha256->Final256(digest);
573*f6dc9357SAndroid Build Coastguard Worker     if (memcmp(digest, digest_from_arc, sizeof(digest)) != 0)
574*f6dc9357SAndroid Build Coastguard Worker       return false;
575*f6dc9357SAndroid Build Coastguard Worker   }
576*f6dc9357SAndroid Build Coastguard Worker   else if (algo == XAR_CKSUM_SHA512)
577*f6dc9357SAndroid Build Coastguard Worker   {
578*f6dc9357SAndroid Build Coastguard Worker     Byte digest[SHA512_DIGEST_SIZE];
579*f6dc9357SAndroid Build Coastguard Worker     inStreamSha256->Final512(digest);
580*f6dc9357SAndroid Build Coastguard Worker     if (memcmp(digest, digest_from_arc, sizeof(digest)) != 0)
581*f6dc9357SAndroid Build Coastguard Worker       return false;
582*f6dc9357SAndroid Build Coastguard Worker   }
583*f6dc9357SAndroid Build Coastguard Worker   return true;
584*f6dc9357SAndroid Build Coastguard Worker }
585*f6dc9357SAndroid Build Coastguard Worker 
586*f6dc9357SAndroid Build Coastguard Worker 
587*f6dc9357SAndroid Build Coastguard Worker HRESULT CHandler::Open2(IInStream *stream)
588*f6dc9357SAndroid Build Coastguard Worker {
589*f6dc9357SAndroid Build Coastguard Worker   const unsigned kHeaderSize = 28;
590*f6dc9357SAndroid Build Coastguard Worker   UInt32 buf32[kHeaderSize / sizeof(UInt32)];
591*f6dc9357SAndroid Build Coastguard Worker   RINOK(ReadStream_FALSE(stream, buf32, kHeaderSize))
592*f6dc9357SAndroid Build Coastguard Worker   const unsigned headerSize = Get16((const Byte *)(const void *)buf32 + 4);
593*f6dc9357SAndroid Build Coastguard Worker   // xar library now writes 1 to version field.
594*f6dc9357SAndroid Build Coastguard Worker   // some old xars could have version == 0 ?
595*f6dc9357SAndroid Build Coastguard Worker   // specification allows (headerSize != 28),
596*f6dc9357SAndroid Build Coastguard Worker   // but we don't expect big value in (headerSize).
597*f6dc9357SAndroid Build Coastguard Worker   // so we restrict (headerSize) with 64 bytes to reduce false open.
598*f6dc9357SAndroid Build Coastguard Worker   const unsigned kHeaderSize_MAX = 64;
599*f6dc9357SAndroid Build Coastguard Worker   if (Get32(buf32) != 0x78617221  // signature: "xar!"
600*f6dc9357SAndroid Build Coastguard Worker       || headerSize < kHeaderSize
601*f6dc9357SAndroid Build Coastguard Worker       || headerSize > kHeaderSize_MAX
602*f6dc9357SAndroid Build Coastguard Worker       || Get16((const Byte *)(const void *)buf32 + 6) > 1 // version
603*f6dc9357SAndroid Build Coastguard Worker       )
604*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
605*f6dc9357SAndroid Build Coastguard Worker   _checkSumAlgo = Get32(buf32 + 6);
606*f6dc9357SAndroid Build Coastguard Worker   const UInt64 packSize = Get64(buf32 + 2);
607*f6dc9357SAndroid Build Coastguard Worker   const UInt64 unpackSize = Get64(buf32 + 4);
608*f6dc9357SAndroid Build Coastguard Worker   if (packSize >= kXmlPackSizeMax ||
609*f6dc9357SAndroid Build Coastguard Worker       unpackSize >= kXmlSizeMax)
610*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
611*f6dc9357SAndroid Build Coastguard Worker   /* some xar archives can have padding bytes at offset 28,
612*f6dc9357SAndroid Build Coastguard Worker      or checksum algorithm name at offset 28 (in xar fork, if cksum_alg==3)
613*f6dc9357SAndroid Build Coastguard Worker      But we didn't see such xar archives.
614*f6dc9357SAndroid Build Coastguard Worker   */
615*f6dc9357SAndroid Build Coastguard Worker   if (headerSize != kHeaderSize)
616*f6dc9357SAndroid Build Coastguard Worker   {
617*f6dc9357SAndroid Build Coastguard Worker     RINOK(InStream_SeekSet(stream, headerSize))
618*f6dc9357SAndroid Build Coastguard Worker   }
619*f6dc9357SAndroid Build Coastguard Worker   _dataStartPos = headerSize + packSize;
620*f6dc9357SAndroid Build Coastguard Worker   _phySize = _dataStartPos;
621*f6dc9357SAndroid Build Coastguard Worker 
622*f6dc9357SAndroid Build Coastguard Worker   _xmlBuf.Alloc((size_t)unpackSize + 1);
623*f6dc9357SAndroid Build Coastguard Worker   if (!_xmlBuf.IsAllocated())
624*f6dc9357SAndroid Build Coastguard Worker     return E_OUTOFMEMORY;
625*f6dc9357SAndroid Build Coastguard Worker   _xmlLen = (size_t)unpackSize;
626*f6dc9357SAndroid Build Coastguard Worker 
627*f6dc9357SAndroid Build Coastguard Worker   CInStreamWithHash hashStream;
628*f6dc9357SAndroid Build Coastguard Worker   {
629*f6dc9357SAndroid Build Coastguard Worker     CMyComPtr2_Create<ICompressCoder, NCompress::NZlib::CDecoder> zlibCoder;
630*f6dc9357SAndroid Build Coastguard Worker     hashStream.SetStreamAndInit(stream, (int)(unsigned)_checkSumAlgo);
631*f6dc9357SAndroid Build Coastguard Worker     hashStream.inStreamLim->Init(packSize);
632*f6dc9357SAndroid Build Coastguard Worker     CMyComPtr2_Create<ISequentialOutStream, CBufPtrSeqOutStream> outStreamLim;
633*f6dc9357SAndroid Build Coastguard Worker     outStreamLim->Init(_xmlBuf, (size_t)unpackSize);
634*f6dc9357SAndroid Build Coastguard Worker     RINOK(zlibCoder.Interface()->Code(hashStream.inStreamLim, outStreamLim, NULL, &unpackSize, NULL))
635*f6dc9357SAndroid Build Coastguard Worker     if (outStreamLim->GetPos() != (size_t)unpackSize)
636*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
637*f6dc9357SAndroid Build Coastguard Worker   }
638*f6dc9357SAndroid Build Coastguard Worker   _xmlBuf[(size_t)unpackSize] = 0;
639*f6dc9357SAndroid Build Coastguard Worker   if (strlen((const char *)(const Byte *)_xmlBuf) != (size_t)unpackSize)
640*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
641*f6dc9357SAndroid Build Coastguard Worker   CXml xml;
642*f6dc9357SAndroid Build Coastguard Worker   if (!xml.Parse((const char *)(const Byte *)_xmlBuf))
643*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
644*f6dc9357SAndroid Build Coastguard Worker 
645*f6dc9357SAndroid Build Coastguard Worker   if (!xml.Root.IsTagged("xar") || xml.Root.SubItems.Size() != 1)
646*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
647*f6dc9357SAndroid Build Coastguard Worker   const CXmlItem &toc = xml.Root.SubItems[0];
648*f6dc9357SAndroid Build Coastguard Worker   if (!toc.IsTagged("toc"))
649*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
650*f6dc9357SAndroid Build Coastguard Worker 
651*f6dc9357SAndroid Build Coastguard Worker   // CreationTime = ParseTime(toc, "creation-time", false); // z_IsRequied
652*f6dc9357SAndroid Build Coastguard Worker   CreationTime_String = toc.GetSubStringForTag("creation-time");
653*f6dc9357SAndroid Build Coastguard Worker   {
654*f6dc9357SAndroid Build Coastguard Worker     // we suppose that offset of checksum is always 0;
655*f6dc9357SAndroid Build Coastguard Worker     // but [TOC].xml contains exact offset value in <checksum> block.
656*f6dc9357SAndroid Build Coastguard Worker     const UInt64 offset = 0;
657*f6dc9357SAndroid Build Coastguard Worker     const unsigned hashSize = GetHashSize((int)(unsigned)_checkSumAlgo);
658*f6dc9357SAndroid Build Coastguard Worker     if (hashSize)
659*f6dc9357SAndroid Build Coastguard Worker     {
660*f6dc9357SAndroid Build Coastguard Worker       /*
661*f6dc9357SAndroid Build Coastguard Worker       const CXmlItem *csItem = toc.FindSubTag_GetPtr("checksum");
662*f6dc9357SAndroid Build Coastguard Worker       if (csItem)
663*f6dc9357SAndroid Build Coastguard Worker       {
664*f6dc9357SAndroid Build Coastguard Worker         const int checkSumAlgo2 = Find_ChecksumId_for_Name(csItem->GetPropVal("style"));
665*f6dc9357SAndroid Build Coastguard Worker         UInt64 csSize, csOffset;
666*f6dc9357SAndroid Build Coastguard Worker         if (ParseUInt64(*csItem, "size", csSize) &&
667*f6dc9357SAndroid Build Coastguard Worker             ParseUInt64(*csItem, "offset", csOffset)  &&
668*f6dc9357SAndroid Build Coastguard Worker             csSize == hashSize &&
669*f6dc9357SAndroid Build Coastguard Worker             (unsigned)checkSumAlgo2 == _checkSumAlgo)
670*f6dc9357SAndroid Build Coastguard Worker           offset = csOffset;
671*f6dc9357SAndroid Build Coastguard Worker       }
672*f6dc9357SAndroid Build Coastguard Worker       */
673*f6dc9357SAndroid Build Coastguard Worker       CByteBuffer digest_from_arc(hashSize);
674*f6dc9357SAndroid Build Coastguard Worker       RINOK(InStream_SeekSet(stream, _dataStartPos + offset))
675*f6dc9357SAndroid Build Coastguard Worker       RINOK(ReadStream_FALSE(stream, digest_from_arc, hashSize))
676*f6dc9357SAndroid Build Coastguard Worker       if (!hashStream.CheckHash((int)(unsigned)_checkSumAlgo, digest_from_arc))
677*f6dc9357SAndroid Build Coastguard Worker         _toc_CrcError = true;
678*f6dc9357SAndroid Build Coastguard Worker     }
679*f6dc9357SAndroid Build Coastguard Worker   }
680*f6dc9357SAndroid Build Coastguard Worker 
681*f6dc9357SAndroid Build Coastguard Worker   if (!AddItem(toc, _files,
682*f6dc9357SAndroid Build Coastguard Worker       -1, // parent
683*f6dc9357SAndroid Build Coastguard Worker       0)) // level
684*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
685*f6dc9357SAndroid Build Coastguard Worker 
686*f6dc9357SAndroid Build Coastguard Worker   UInt64 totalPackSize = 0;
687*f6dc9357SAndroid Build Coastguard Worker   unsigned numMainFiles = 0;
688*f6dc9357SAndroid Build Coastguard Worker 
689*f6dc9357SAndroid Build Coastguard Worker   FOR_VECTOR (i, _files)
690*f6dc9357SAndroid Build Coastguard Worker   {
691*f6dc9357SAndroid Build Coastguard Worker     const CFile &file = _files[i];
692*f6dc9357SAndroid Build Coastguard Worker     file.UpdateTotalPackSize(totalPackSize);
693*f6dc9357SAndroid Build Coastguard Worker     if (file.Parent == -1)
694*f6dc9357SAndroid Build Coastguard Worker     {
695*f6dc9357SAndroid Build Coastguard Worker       if (file.Name == "Payload" || file.Name == "Content")
696*f6dc9357SAndroid Build Coastguard Worker       {
697*f6dc9357SAndroid Build Coastguard Worker         _mainSubfile = (Int32)(int)i;
698*f6dc9357SAndroid Build Coastguard Worker         numMainFiles++;
699*f6dc9357SAndroid Build Coastguard Worker       }
700*f6dc9357SAndroid Build Coastguard Worker       else if (file.Name == "PackageInfo")
701*f6dc9357SAndroid Build Coastguard Worker         _is_pkg = true;
702*f6dc9357SAndroid Build Coastguard Worker     }
703*f6dc9357SAndroid Build Coastguard Worker   }
704*f6dc9357SAndroid Build Coastguard Worker 
705*f6dc9357SAndroid Build Coastguard Worker   if (numMainFiles > 1)
706*f6dc9357SAndroid Build Coastguard Worker     _mainSubfile = -1;
707*f6dc9357SAndroid Build Coastguard Worker 
708*f6dc9357SAndroid Build Coastguard Worker   const UInt64 k_PhySizeLim = (UInt64)1 << 62;
709*f6dc9357SAndroid Build Coastguard Worker   _phySize = (totalPackSize > k_PhySizeLim - _dataStartPos) ?
710*f6dc9357SAndroid Build Coastguard Worker       k_PhySizeLim :
711*f6dc9357SAndroid Build Coastguard Worker       _dataStartPos + totalPackSize;
712*f6dc9357SAndroid Build Coastguard Worker 
713*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
714*f6dc9357SAndroid Build Coastguard Worker }
715*f6dc9357SAndroid Build Coastguard Worker 
716*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Open(IInStream *stream,
717*f6dc9357SAndroid Build Coastguard Worker     const UInt64 * /* maxCheckStartPosition */,
718*f6dc9357SAndroid Build Coastguard Worker     IArchiveOpenCallback * /* openArchiveCallback */))
719*f6dc9357SAndroid Build Coastguard Worker {
720*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
721*f6dc9357SAndroid Build Coastguard Worker   {
722*f6dc9357SAndroid Build Coastguard Worker     Close();
723*f6dc9357SAndroid Build Coastguard Worker     RINOK(Open2(stream))
724*f6dc9357SAndroid Build Coastguard Worker     _inStream = stream;
725*f6dc9357SAndroid Build Coastguard Worker   }
726*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
727*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
728*f6dc9357SAndroid Build Coastguard Worker }
729*f6dc9357SAndroid Build Coastguard Worker 
730*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Close())
731*f6dc9357SAndroid Build Coastguard Worker {
732*f6dc9357SAndroid Build Coastguard Worker   _phySize = 0;
733*f6dc9357SAndroid Build Coastguard Worker   _dataStartPos = 0;
734*f6dc9357SAndroid Build Coastguard Worker   _inStream.Release();
735*f6dc9357SAndroid Build Coastguard Worker   _files.Clear();
736*f6dc9357SAndroid Build Coastguard Worker   _xmlLen = 0;
737*f6dc9357SAndroid Build Coastguard Worker   _xmlBuf.Free();
738*f6dc9357SAndroid Build Coastguard Worker   _mainSubfile = -1;
739*f6dc9357SAndroid Build Coastguard Worker   _is_pkg = false;
740*f6dc9357SAndroid Build Coastguard Worker   _toc_CrcError = false;
741*f6dc9357SAndroid Build Coastguard Worker   _checkSumAlgo = 0;
742*f6dc9357SAndroid Build Coastguard Worker   // CreationTime = 0;
743*f6dc9357SAndroid Build Coastguard Worker   CreationTime_String.Empty();
744*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
745*f6dc9357SAndroid Build Coastguard Worker }
746*f6dc9357SAndroid Build Coastguard Worker 
747*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
748*f6dc9357SAndroid Build Coastguard Worker {
749*f6dc9357SAndroid Build Coastguard Worker   *numItems = _files.Size()
750*f6dc9357SAndroid Build Coastguard Worker #ifdef XAR_SHOW_RAW
751*f6dc9357SAndroid Build Coastguard Worker     + 1
752*f6dc9357SAndroid Build Coastguard Worker #endif
753*f6dc9357SAndroid Build Coastguard Worker   ;
754*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
755*f6dc9357SAndroid Build Coastguard Worker }
756*f6dc9357SAndroid Build Coastguard Worker 
757*f6dc9357SAndroid Build Coastguard Worker static void TimeToProp(UInt64 t, NCOM::CPropVariant &prop)
758*f6dc9357SAndroid Build Coastguard Worker {
759*f6dc9357SAndroid Build Coastguard Worker   if (t != 0)
760*f6dc9357SAndroid Build Coastguard Worker   {
761*f6dc9357SAndroid Build Coastguard Worker     FILETIME ft;
762*f6dc9357SAndroid Build Coastguard Worker     ft.dwLowDateTime = (UInt32)(t);
763*f6dc9357SAndroid Build Coastguard Worker     ft.dwHighDateTime = (UInt32)(t >> 32);
764*f6dc9357SAndroid Build Coastguard Worker     prop = ft;
765*f6dc9357SAndroid Build Coastguard Worker   }
766*f6dc9357SAndroid Build Coastguard Worker }
767*f6dc9357SAndroid Build Coastguard Worker 
768*f6dc9357SAndroid Build Coastguard Worker static void Utf8StringToProp(const AString &s, NCOM::CPropVariant &prop)
769*f6dc9357SAndroid Build Coastguard Worker {
770*f6dc9357SAndroid Build Coastguard Worker   if (!s.IsEmpty())
771*f6dc9357SAndroid Build Coastguard Worker   {
772*f6dc9357SAndroid Build Coastguard Worker     UString us;
773*f6dc9357SAndroid Build Coastguard Worker     ConvertUTF8ToUnicode(s, us);
774*f6dc9357SAndroid Build Coastguard Worker     prop = us;
775*f6dc9357SAndroid Build Coastguard Worker   }
776*f6dc9357SAndroid Build Coastguard Worker }
777*f6dc9357SAndroid Build Coastguard Worker 
778*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
779*f6dc9357SAndroid Build Coastguard Worker {
780*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
781*f6dc9357SAndroid Build Coastguard Worker   NCOM::CPropVariant prop;
782*f6dc9357SAndroid Build Coastguard Worker   switch (propID)
783*f6dc9357SAndroid Build Coastguard Worker   {
784*f6dc9357SAndroid Build Coastguard Worker     // case kpidHeadersSize: prop = _dataStartPos; break;
785*f6dc9357SAndroid Build Coastguard Worker     case kpidPhySize: prop = _phySize; break;
786*f6dc9357SAndroid Build Coastguard Worker     case kpidMainSubfile: if (_mainSubfile >= 0) prop = (UInt32)_mainSubfile; break;
787*f6dc9357SAndroid Build Coastguard Worker     case kpidSubType: if (_is_pkg) prop = "pkg"; break;
788*f6dc9357SAndroid Build Coastguard Worker     case kpidExtension: prop = _is_pkg ? "pkg" : "xar"; break;
789*f6dc9357SAndroid Build Coastguard Worker     case kpidCTime:
790*f6dc9357SAndroid Build Coastguard Worker     {
791*f6dc9357SAndroid Build Coastguard Worker       // it's local time. We can transfer it to UTC time, if we use FILETIME.
792*f6dc9357SAndroid Build Coastguard Worker       // TimeToProp(CreationTime, prop); break;
793*f6dc9357SAndroid Build Coastguard Worker       if (!CreationTime_String.IsEmpty())
794*f6dc9357SAndroid Build Coastguard Worker         prop = CreationTime_String;
795*f6dc9357SAndroid Build Coastguard Worker       break;
796*f6dc9357SAndroid Build Coastguard Worker     }
797*f6dc9357SAndroid Build Coastguard Worker     case kpidMethod:
798*f6dc9357SAndroid Build Coastguard Worker     {
799*f6dc9357SAndroid Build Coastguard Worker       AString s;
800*f6dc9357SAndroid Build Coastguard Worker       if (_checkSumAlgo < Z7_ARRAY_SIZE(k_ChecksumNames))
801*f6dc9357SAndroid Build Coastguard Worker         s = k_ChecksumNames[_checkSumAlgo];
802*f6dc9357SAndroid Build Coastguard Worker       else
803*f6dc9357SAndroid Build Coastguard Worker       {
804*f6dc9357SAndroid Build Coastguard Worker         s += "Checksum";
805*f6dc9357SAndroid Build Coastguard Worker         s.Add_UInt32(_checkSumAlgo);
806*f6dc9357SAndroid Build Coastguard Worker       }
807*f6dc9357SAndroid Build Coastguard Worker       prop = s;
808*f6dc9357SAndroid Build Coastguard Worker       break;
809*f6dc9357SAndroid Build Coastguard Worker     }
810*f6dc9357SAndroid Build Coastguard Worker     case kpidWarningFlags:
811*f6dc9357SAndroid Build Coastguard Worker     {
812*f6dc9357SAndroid Build Coastguard Worker       UInt32 v = 0;
813*f6dc9357SAndroid Build Coastguard Worker       if (_toc_CrcError) v |= kpv_ErrorFlags_CrcError;
814*f6dc9357SAndroid Build Coastguard Worker       prop = v;
815*f6dc9357SAndroid Build Coastguard Worker       break;
816*f6dc9357SAndroid Build Coastguard Worker     }
817*f6dc9357SAndroid Build Coastguard Worker     case kpidINode: prop = true; break;
818*f6dc9357SAndroid Build Coastguard Worker     case kpidIsTree: prop = true; break;
819*f6dc9357SAndroid Build Coastguard Worker   }
820*f6dc9357SAndroid Build Coastguard Worker   prop.Detach(value);
821*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
822*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
823*f6dc9357SAndroid Build Coastguard Worker }
824*f6dc9357SAndroid Build Coastguard Worker 
825*f6dc9357SAndroid Build Coastguard Worker 
826*f6dc9357SAndroid Build Coastguard Worker /*
827*f6dc9357SAndroid Build Coastguard Worker inline UInt32 MY_dev_major(UInt64 dev)
828*f6dc9357SAndroid Build Coastguard Worker {
829*f6dc9357SAndroid Build Coastguard Worker   return ((UInt32)(dev >> 8) & (UInt32)0xfff) | ((UInt32)(dev >> 32) & ~(UInt32)0xfff);
830*f6dc9357SAndroid Build Coastguard Worker }
831*f6dc9357SAndroid Build Coastguard Worker inline UInt32 MY_dev_minor(UInt64 dev)
832*f6dc9357SAndroid Build Coastguard Worker {
833*f6dc9357SAndroid Build Coastguard Worker   return ((UInt32)(dev) & 0xff) | ((UInt32)(dev >> 12) & ~(UInt32)0xff);
834*f6dc9357SAndroid Build Coastguard Worker }
835*f6dc9357SAndroid Build Coastguard Worker */
836*f6dc9357SAndroid Build Coastguard Worker 
837*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
838*f6dc9357SAndroid Build Coastguard Worker {
839*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
840*f6dc9357SAndroid Build Coastguard Worker   NCOM::CPropVariant prop;
841*f6dc9357SAndroid Build Coastguard Worker 
842*f6dc9357SAndroid Build Coastguard Worker #ifdef XAR_SHOW_RAW
843*f6dc9357SAndroid Build Coastguard Worker   if (index >= _files.Size())
844*f6dc9357SAndroid Build Coastguard Worker   {
845*f6dc9357SAndroid Build Coastguard Worker     switch (propID)
846*f6dc9357SAndroid Build Coastguard Worker     {
847*f6dc9357SAndroid Build Coastguard Worker       case kpidName:
848*f6dc9357SAndroid Build Coastguard Worker       case kpidPath:
849*f6dc9357SAndroid Build Coastguard Worker         prop = "[TOC].xml"; break;
850*f6dc9357SAndroid Build Coastguard Worker       case kpidSize:
851*f6dc9357SAndroid Build Coastguard Worker       case kpidPackSize: prop = (UInt64)_xmlLen; break;
852*f6dc9357SAndroid Build Coastguard Worker     }
853*f6dc9357SAndroid Build Coastguard Worker   }
854*f6dc9357SAndroid Build Coastguard Worker   else
855*f6dc9357SAndroid Build Coastguard Worker #endif
856*f6dc9357SAndroid Build Coastguard Worker   {
857*f6dc9357SAndroid Build Coastguard Worker     const CFile &item = _files[index];
858*f6dc9357SAndroid Build Coastguard Worker     switch (propID)
859*f6dc9357SAndroid Build Coastguard Worker     {
860*f6dc9357SAndroid Build Coastguard Worker       case kpidPath:
861*f6dc9357SAndroid Build Coastguard Worker       {
862*f6dc9357SAndroid Build Coastguard Worker         AString path;
863*f6dc9357SAndroid Build Coastguard Worker         unsigned cur = index;
864*f6dc9357SAndroid Build Coastguard Worker         for (;;)
865*f6dc9357SAndroid Build Coastguard Worker         {
866*f6dc9357SAndroid Build Coastguard Worker           const CFile &item2 = _files[cur];
867*f6dc9357SAndroid Build Coastguard Worker           if (!path.IsEmpty())
868*f6dc9357SAndroid Build Coastguard Worker             path.InsertAtFront(CHAR_PATH_SEPARATOR);
869*f6dc9357SAndroid Build Coastguard Worker // #define XAR_EMPTY_NAME_REPLACEMENT "[]"
870*f6dc9357SAndroid Build Coastguard Worker           if (item2.Name.IsEmpty())
871*f6dc9357SAndroid Build Coastguard Worker           {
872*f6dc9357SAndroid Build Coastguard Worker             AString s('[');
873*f6dc9357SAndroid Build Coastguard Worker             s.Add_UInt32(cur);
874*f6dc9357SAndroid Build Coastguard Worker             s.Add_Char(']');
875*f6dc9357SAndroid Build Coastguard Worker             path.Insert(0, s);
876*f6dc9357SAndroid Build Coastguard Worker           }
877*f6dc9357SAndroid Build Coastguard Worker           else
878*f6dc9357SAndroid Build Coastguard Worker             path.Insert(0, item2.Name);
879*f6dc9357SAndroid Build Coastguard Worker           if (item2.Parent < 0)
880*f6dc9357SAndroid Build Coastguard Worker             break;
881*f6dc9357SAndroid Build Coastguard Worker           cur = (unsigned)item2.Parent;
882*f6dc9357SAndroid Build Coastguard Worker         }
883*f6dc9357SAndroid Build Coastguard Worker         Utf8StringToProp(path, prop);
884*f6dc9357SAndroid Build Coastguard Worker         break;
885*f6dc9357SAndroid Build Coastguard Worker       }
886*f6dc9357SAndroid Build Coastguard Worker 
887*f6dc9357SAndroid Build Coastguard Worker       case kpidName:
888*f6dc9357SAndroid Build Coastguard Worker       {
889*f6dc9357SAndroid Build Coastguard Worker         if (item.Name.IsEmpty())
890*f6dc9357SAndroid Build Coastguard Worker         {
891*f6dc9357SAndroid Build Coastguard Worker           AString s('[');
892*f6dc9357SAndroid Build Coastguard Worker           s.Add_UInt32(index);
893*f6dc9357SAndroid Build Coastguard Worker           s.Add_Char(']');
894*f6dc9357SAndroid Build Coastguard Worker           prop = s;
895*f6dc9357SAndroid Build Coastguard Worker         }
896*f6dc9357SAndroid Build Coastguard Worker         else
897*f6dc9357SAndroid Build Coastguard Worker           Utf8StringToProp(item.Name, prop);
898*f6dc9357SAndroid Build Coastguard Worker         break;
899*f6dc9357SAndroid Build Coastguard Worker       }
900*f6dc9357SAndroid Build Coastguard Worker 
901*f6dc9357SAndroid Build Coastguard Worker       case kpidIsDir: prop = item.IsDir; break;
902*f6dc9357SAndroid Build Coastguard Worker 
903*f6dc9357SAndroid Build Coastguard Worker       case kpidSize:     if (item.HasData && !item.IsDir) prop = item.Size; break;
904*f6dc9357SAndroid Build Coastguard Worker       case kpidPackSize: if (item.HasData && !item.IsDir) prop = item.PackSize; break;
905*f6dc9357SAndroid Build Coastguard Worker 
906*f6dc9357SAndroid Build Coastguard Worker       case kpidMethod:
907*f6dc9357SAndroid Build Coastguard Worker       {
908*f6dc9357SAndroid Build Coastguard Worker         if (item.HasData)
909*f6dc9357SAndroid Build Coastguard Worker         {
910*f6dc9357SAndroid Build Coastguard Worker           AString s = item.Method;
911*f6dc9357SAndroid Build Coastguard Worker           item.extracted_checksum.AddNameToString(s);
912*f6dc9357SAndroid Build Coastguard Worker           item.archived_checksum.AddNameToString(s);
913*f6dc9357SAndroid Build Coastguard Worker           Utf8StringToProp(s, prop);
914*f6dc9357SAndroid Build Coastguard Worker         }
915*f6dc9357SAndroid Build Coastguard Worker         break;
916*f6dc9357SAndroid Build Coastguard Worker       }
917*f6dc9357SAndroid Build Coastguard Worker 
918*f6dc9357SAndroid Build Coastguard Worker       case kpidMTime: TimeToProp(item.MTime, prop); break;
919*f6dc9357SAndroid Build Coastguard Worker       case kpidCTime: TimeToProp(item.CTime, prop); break;
920*f6dc9357SAndroid Build Coastguard Worker       case kpidATime: TimeToProp(item.ATime, prop); break;
921*f6dc9357SAndroid Build Coastguard Worker 
922*f6dc9357SAndroid Build Coastguard Worker       case kpidPosixAttrib:
923*f6dc9357SAndroid Build Coastguard Worker         if (item.Mode_Defined)
924*f6dc9357SAndroid Build Coastguard Worker         {
925*f6dc9357SAndroid Build Coastguard Worker           UInt32 mode = item.Mode;
926*f6dc9357SAndroid Build Coastguard Worker           if ((mode & MY_LIN_S_IFMT) == 0)
927*f6dc9357SAndroid Build Coastguard Worker             mode |= (
928*f6dc9357SAndroid Build Coastguard Worker                 item.Is_SymLink ? MY_LIN_S_IFLNK :
929*f6dc9357SAndroid Build Coastguard Worker                 item.IsDir      ? MY_LIN_S_IFDIR :
930*f6dc9357SAndroid Build Coastguard Worker                                   MY_LIN_S_IFREG);
931*f6dc9357SAndroid Build Coastguard Worker           prop = mode;
932*f6dc9357SAndroid Build Coastguard Worker         }
933*f6dc9357SAndroid Build Coastguard Worker         break;
934*f6dc9357SAndroid Build Coastguard Worker 
935*f6dc9357SAndroid Build Coastguard Worker       case kpidType:  Utf8StringToProp(item.Type, prop); break;
936*f6dc9357SAndroid Build Coastguard Worker       case kpidUser:  Utf8StringToProp(item.User, prop); break;
937*f6dc9357SAndroid Build Coastguard Worker       case kpidGroup: Utf8StringToProp(item.Group, prop); break;
938*f6dc9357SAndroid Build Coastguard Worker       case kpidSymLink: if (item.Is_SymLink) Utf8StringToProp(item.Link, prop); break;
939*f6dc9357SAndroid Build Coastguard Worker 
940*f6dc9357SAndroid Build Coastguard Worker       case kpidUserId:  if (item.UserId_Defined)  prop = item.UserId;   break;
941*f6dc9357SAndroid Build Coastguard Worker       case kpidGroupId: if (item.GroupId_Defined) prop = item.GroupId;  break;
942*f6dc9357SAndroid Build Coastguard Worker       case kpidINode:   if (item.INode_Defined)   prop = item.INode;    break;
943*f6dc9357SAndroid Build Coastguard Worker       case kpidId:      if (item.Id_Defined)      prop = item.Id;       break;
944*f6dc9357SAndroid Build Coastguard Worker       // Utf8StringToProp(item.Id, prop);
945*f6dc9357SAndroid Build Coastguard Worker       /*
946*f6dc9357SAndroid Build Coastguard Worker       case kpidDeviceMajor: if (item.Device_Defined) prop = (UInt32)MY_dev_major(item.Device);  break;
947*f6dc9357SAndroid Build Coastguard Worker       case kpidDeviceMinor: if (item.Device_Defined) prop = (UInt32)MY_dev_minor(item.Device);  break;
948*f6dc9357SAndroid Build Coastguard Worker       case kpidLinkType:
949*f6dc9357SAndroid Build Coastguard Worker         if (!item.LinkType.IsEmpty())
950*f6dc9357SAndroid Build Coastguard Worker           Utf8StringToProp(item.LinkType, prop);
951*f6dc9357SAndroid Build Coastguard Worker         break;
952*f6dc9357SAndroid Build Coastguard Worker       case kpidLinkFrom:
953*f6dc9357SAndroid Build Coastguard Worker         if (!item.LinkFrom.IsEmpty())
954*f6dc9357SAndroid Build Coastguard Worker           Utf8StringToProp(item.LinkFrom, prop);
955*f6dc9357SAndroid Build Coastguard Worker         break;
956*f6dc9357SAndroid Build Coastguard Worker       */
957*f6dc9357SAndroid Build Coastguard Worker       case kpidOffset:
958*f6dc9357SAndroid Build Coastguard Worker         if (item.HasData)
959*f6dc9357SAndroid Build Coastguard Worker           prop = _dataStartPos + item.Offset;
960*f6dc9357SAndroid Build Coastguard Worker         break;
961*f6dc9357SAndroid Build Coastguard Worker     }
962*f6dc9357SAndroid Build Coastguard Worker   }
963*f6dc9357SAndroid Build Coastguard Worker   prop.Detach(value);
964*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
965*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
966*f6dc9357SAndroid Build Coastguard Worker }
967*f6dc9357SAndroid Build Coastguard Worker 
968*f6dc9357SAndroid Build Coastguard Worker 
969*f6dc9357SAndroid Build Coastguard Worker // for debug:
970*f6dc9357SAndroid Build Coastguard Worker // #define Z7_XAR_SHOW_CHECKSUM_PACK
971*f6dc9357SAndroid Build Coastguard Worker 
972*f6dc9357SAndroid Build Coastguard Worker #ifdef Z7_XAR_SHOW_CHECKSUM_PACK
973*f6dc9357SAndroid Build Coastguard Worker enum
974*f6dc9357SAndroid Build Coastguard Worker {
975*f6dc9357SAndroid Build Coastguard Worker   kpidChecksumPack = kpidUserDefined
976*f6dc9357SAndroid Build Coastguard Worker };
977*f6dc9357SAndroid Build Coastguard Worker #endif
978*f6dc9357SAndroid Build Coastguard Worker 
979*f6dc9357SAndroid Build Coastguard Worker static const Byte kRawProps[] =
980*f6dc9357SAndroid Build Coastguard Worker {
981*f6dc9357SAndroid Build Coastguard Worker   kpidChecksum
982*f6dc9357SAndroid Build Coastguard Worker #ifdef Z7_XAR_SHOW_CHECKSUM_PACK
983*f6dc9357SAndroid Build Coastguard Worker   , kpidCRC // instead of kpidUserDefined / kpidCRC
984*f6dc9357SAndroid Build Coastguard Worker #endif
985*f6dc9357SAndroid Build Coastguard Worker };
986*f6dc9357SAndroid Build Coastguard Worker 
987*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetNumRawProps(UInt32 *numProps))
988*f6dc9357SAndroid Build Coastguard Worker {
989*f6dc9357SAndroid Build Coastguard Worker   *numProps = Z7_ARRAY_SIZE(kRawProps);
990*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
991*f6dc9357SAndroid Build Coastguard Worker }
992*f6dc9357SAndroid Build Coastguard Worker 
993*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetRawPropInfo(UInt32 index, BSTR *name, PROPID *propID))
994*f6dc9357SAndroid Build Coastguard Worker {
995*f6dc9357SAndroid Build Coastguard Worker   *propID = kRawProps[index];
996*f6dc9357SAndroid Build Coastguard Worker   *name = NULL;
997*f6dc9357SAndroid Build Coastguard Worker 
998*f6dc9357SAndroid Build Coastguard Worker #ifdef Z7_XAR_SHOW_CHECKSUM_PACK
999*f6dc9357SAndroid Build Coastguard Worker   if (index != 0)
1000*f6dc9357SAndroid Build Coastguard Worker   {
1001*f6dc9357SAndroid Build Coastguard Worker     *propID = kpidChecksumPack;
1002*f6dc9357SAndroid Build Coastguard Worker     *name = NWindows::NCOM::AllocBstrFromAscii("archived-checksum");
1003*f6dc9357SAndroid Build Coastguard Worker   }
1004*f6dc9357SAndroid Build Coastguard Worker #endif
1005*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1006*f6dc9357SAndroid Build Coastguard Worker }
1007*f6dc9357SAndroid Build Coastguard Worker 
1008*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetParent(UInt32 index, UInt32 *parent, UInt32 *parentType))
1009*f6dc9357SAndroid Build Coastguard Worker {
1010*f6dc9357SAndroid Build Coastguard Worker   *parentType = NParentType::kDir;
1011*f6dc9357SAndroid Build Coastguard Worker   *parent = (UInt32)(Int32)-1;
1012*f6dc9357SAndroid Build Coastguard Worker #ifdef XAR_SHOW_RAW
1013*f6dc9357SAndroid Build Coastguard Worker   if (index >= _files.Size())
1014*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
1015*f6dc9357SAndroid Build Coastguard Worker #endif
1016*f6dc9357SAndroid Build Coastguard Worker   {
1017*f6dc9357SAndroid Build Coastguard Worker     const CFile &item = _files[index];
1018*f6dc9357SAndroid Build Coastguard Worker     *parent = (UInt32)(Int32)item.Parent;
1019*f6dc9357SAndroid Build Coastguard Worker   }
1020*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1021*f6dc9357SAndroid Build Coastguard Worker }
1022*f6dc9357SAndroid Build Coastguard Worker 
1023*f6dc9357SAndroid Build Coastguard Worker 
1024*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType))
1025*f6dc9357SAndroid Build Coastguard Worker {
1026*f6dc9357SAndroid Build Coastguard Worker   *data = NULL;
1027*f6dc9357SAndroid Build Coastguard Worker   *dataSize = 0;
1028*f6dc9357SAndroid Build Coastguard Worker   *propType = 0;
1029*f6dc9357SAndroid Build Coastguard Worker 
1030*f6dc9357SAndroid Build Coastguard Worker   // COM_TRY_BEGIN
1031*f6dc9357SAndroid Build Coastguard Worker   NCOM::CPropVariant prop;
1032*f6dc9357SAndroid Build Coastguard Worker 
1033*f6dc9357SAndroid Build Coastguard Worker   if (propID == kpidChecksum)
1034*f6dc9357SAndroid Build Coastguard Worker   {
1035*f6dc9357SAndroid Build Coastguard Worker #ifdef XAR_SHOW_RAW
1036*f6dc9357SAndroid Build Coastguard Worker     if (index >= _files.Size())
1037*f6dc9357SAndroid Build Coastguard Worker     {
1038*f6dc9357SAndroid Build Coastguard Worker       // case kpidPath: prop = "[TOC].xml"; break;
1039*f6dc9357SAndroid Build Coastguard Worker     }
1040*f6dc9357SAndroid Build Coastguard Worker     else
1041*f6dc9357SAndroid Build Coastguard Worker #endif
1042*f6dc9357SAndroid Build Coastguard Worker     {
1043*f6dc9357SAndroid Build Coastguard Worker       const CFile &item = _files[index];
1044*f6dc9357SAndroid Build Coastguard Worker       const size_t size = item.extracted_checksum.Data.Size();
1045*f6dc9357SAndroid Build Coastguard Worker       if (size != 0)
1046*f6dc9357SAndroid Build Coastguard Worker       {
1047*f6dc9357SAndroid Build Coastguard Worker         *dataSize = (UInt32)size;
1048*f6dc9357SAndroid Build Coastguard Worker         *propType = NPropDataType::kRaw;
1049*f6dc9357SAndroid Build Coastguard Worker         *data = item.extracted_checksum.Data;
1050*f6dc9357SAndroid Build Coastguard Worker       }
1051*f6dc9357SAndroid Build Coastguard Worker     }
1052*f6dc9357SAndroid Build Coastguard Worker   }
1053*f6dc9357SAndroid Build Coastguard Worker 
1054*f6dc9357SAndroid Build Coastguard Worker #ifdef Z7_XAR_SHOW_CHECKSUM_PACK
1055*f6dc9357SAndroid Build Coastguard Worker   if (propID == kpidChecksumPack)
1056*f6dc9357SAndroid Build Coastguard Worker   {
1057*f6dc9357SAndroid Build Coastguard Worker #ifdef XAR_SHOW_RAW
1058*f6dc9357SAndroid Build Coastguard Worker     if (index >= _files.Size())
1059*f6dc9357SAndroid Build Coastguard Worker     {
1060*f6dc9357SAndroid Build Coastguard Worker       // we can show digest check sum here
1061*f6dc9357SAndroid Build Coastguard Worker     }
1062*f6dc9357SAndroid Build Coastguard Worker     else
1063*f6dc9357SAndroid Build Coastguard Worker #endif
1064*f6dc9357SAndroid Build Coastguard Worker     {
1065*f6dc9357SAndroid Build Coastguard Worker       const CFile &item = _files[index];
1066*f6dc9357SAndroid Build Coastguard Worker       const size_t size = (UInt32)item.archived_checksum.Data.Size();
1067*f6dc9357SAndroid Build Coastguard Worker       if (size != 0)
1068*f6dc9357SAndroid Build Coastguard Worker       {
1069*f6dc9357SAndroid Build Coastguard Worker         *dataSize = (UInt32)size;
1070*f6dc9357SAndroid Build Coastguard Worker         *propType = NPropDataType::kRaw;
1071*f6dc9357SAndroid Build Coastguard Worker         *data = item.archived_checksum.Data;
1072*f6dc9357SAndroid Build Coastguard Worker       }
1073*f6dc9357SAndroid Build Coastguard Worker     }
1074*f6dc9357SAndroid Build Coastguard Worker   }
1075*f6dc9357SAndroid Build Coastguard Worker #endif
1076*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1077*f6dc9357SAndroid Build Coastguard Worker }
1078*f6dc9357SAndroid Build Coastguard Worker 
1079*f6dc9357SAndroid Build Coastguard Worker 
1080*f6dc9357SAndroid Build Coastguard Worker 
1081*f6dc9357SAndroid Build Coastguard Worker 
1082*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
1083*f6dc9357SAndroid Build Coastguard Worker     Int32 testMode, IArchiveExtractCallback *extractCallback))
1084*f6dc9357SAndroid Build Coastguard Worker {
1085*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
1086*f6dc9357SAndroid Build Coastguard Worker   const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
1087*f6dc9357SAndroid Build Coastguard Worker   if (allFilesMode)
1088*f6dc9357SAndroid Build Coastguard Worker     numItems = _files.Size()
1089*f6dc9357SAndroid Build Coastguard Worker #ifdef XAR_SHOW_RAW
1090*f6dc9357SAndroid Build Coastguard Worker     + 1
1091*f6dc9357SAndroid Build Coastguard Worker #endif
1092*f6dc9357SAndroid Build Coastguard Worker     ;
1093*f6dc9357SAndroid Build Coastguard Worker   if (numItems == 0)
1094*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
1095*f6dc9357SAndroid Build Coastguard Worker   UInt64 totalSize = 0;
1096*f6dc9357SAndroid Build Coastguard Worker   UInt32 i;
1097*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < numItems; i++)
1098*f6dc9357SAndroid Build Coastguard Worker   {
1099*f6dc9357SAndroid Build Coastguard Worker     const UInt32 index = allFilesMode ? i : indices[i];
1100*f6dc9357SAndroid Build Coastguard Worker #ifdef XAR_SHOW_RAW
1101*f6dc9357SAndroid Build Coastguard Worker     if (index >= _files.Size())
1102*f6dc9357SAndroid Build Coastguard Worker       totalSize += _xmlLen;
1103*f6dc9357SAndroid Build Coastguard Worker     else
1104*f6dc9357SAndroid Build Coastguard Worker #endif
1105*f6dc9357SAndroid Build Coastguard Worker       totalSize += _files[index].Size;
1106*f6dc9357SAndroid Build Coastguard Worker   }
1107*f6dc9357SAndroid Build Coastguard Worker   RINOK(extractCallback->SetTotal(totalSize))
1108*f6dc9357SAndroid Build Coastguard Worker 
1109*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ICompressProgressInfo, CLocalProgress> lps;
1110*f6dc9357SAndroid Build Coastguard Worker   lps->Init(extractCallback, false);
1111*f6dc9357SAndroid Build Coastguard Worker   CInStreamWithHash inHashStream;
1112*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ISequentialOutStream, COutStreamWithSha1> outStreamSha1;
1113*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ISequentialOutStream, COutStreamWithSha256> outStreamSha256;
1114*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ISequentialOutStream, CLimitedSequentialOutStream> outStreamLim;
1115*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ICompressCoder, NCompress::CCopyCoder> copyCoder;
1116*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ICompressCoder, NCompress::NZlib::CDecoder> zlibCoder;
1117*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ICompressCoder, NCompress::NBZip2::CDecoder> bzip2Coder;
1118*f6dc9357SAndroid Build Coastguard Worker   bzip2Coder->FinishMode = true;
1119*f6dc9357SAndroid Build Coastguard Worker 
1120*f6dc9357SAndroid Build Coastguard Worker   UInt64 cur_PackSize, cur_UnpSize;
1121*f6dc9357SAndroid Build Coastguard Worker 
1122*f6dc9357SAndroid Build Coastguard Worker   for (i = 0;; i++,
1123*f6dc9357SAndroid Build Coastguard Worker       lps->InSize += cur_PackSize,
1124*f6dc9357SAndroid Build Coastguard Worker       lps->OutSize += cur_UnpSize)
1125*f6dc9357SAndroid Build Coastguard Worker   {
1126*f6dc9357SAndroid Build Coastguard Worker     cur_PackSize = 0;
1127*f6dc9357SAndroid Build Coastguard Worker     cur_UnpSize = 0;
1128*f6dc9357SAndroid Build Coastguard Worker     RINOK(lps->SetCur())
1129*f6dc9357SAndroid Build Coastguard Worker     if (i >= numItems)
1130*f6dc9357SAndroid Build Coastguard Worker       break;
1131*f6dc9357SAndroid Build Coastguard Worker 
1132*f6dc9357SAndroid Build Coastguard Worker     CMyComPtr<ISequentialOutStream> realOutStream;
1133*f6dc9357SAndroid Build Coastguard Worker     const Int32 askMode = testMode ?
1134*f6dc9357SAndroid Build Coastguard Worker         NExtract::NAskMode::kTest :
1135*f6dc9357SAndroid Build Coastguard Worker         NExtract::NAskMode::kExtract;
1136*f6dc9357SAndroid Build Coastguard Worker     const UInt32 index = allFilesMode ? i : indices[i];
1137*f6dc9357SAndroid Build Coastguard Worker     RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
1138*f6dc9357SAndroid Build Coastguard Worker 
1139*f6dc9357SAndroid Build Coastguard Worker     if (index < _files.Size())
1140*f6dc9357SAndroid Build Coastguard Worker     {
1141*f6dc9357SAndroid Build Coastguard Worker       const CFile &item = _files[index];
1142*f6dc9357SAndroid Build Coastguard Worker       if (item.IsDir)
1143*f6dc9357SAndroid Build Coastguard Worker       {
1144*f6dc9357SAndroid Build Coastguard Worker         RINOK(extractCallback->PrepareOperation(askMode))
1145*f6dc9357SAndroid Build Coastguard Worker         realOutStream.Release();
1146*f6dc9357SAndroid Build Coastguard Worker         RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
1147*f6dc9357SAndroid Build Coastguard Worker         continue;
1148*f6dc9357SAndroid Build Coastguard Worker       }
1149*f6dc9357SAndroid Build Coastguard Worker     }
1150*f6dc9357SAndroid Build Coastguard Worker 
1151*f6dc9357SAndroid Build Coastguard Worker     if (!testMode && !realOutStream)
1152*f6dc9357SAndroid Build Coastguard Worker       continue;
1153*f6dc9357SAndroid Build Coastguard Worker     RINOK(extractCallback->PrepareOperation(askMode))
1154*f6dc9357SAndroid Build Coastguard Worker 
1155*f6dc9357SAndroid Build Coastguard Worker     Int32 opRes = NExtract::NOperationResult::kOK;
1156*f6dc9357SAndroid Build Coastguard Worker 
1157*f6dc9357SAndroid Build Coastguard Worker #ifdef XAR_SHOW_RAW
1158*f6dc9357SAndroid Build Coastguard Worker     if (index >= _files.Size())
1159*f6dc9357SAndroid Build Coastguard Worker     {
1160*f6dc9357SAndroid Build Coastguard Worker       cur_PackSize = cur_UnpSize = _xmlLen;
1161*f6dc9357SAndroid Build Coastguard Worker       if (realOutStream)
1162*f6dc9357SAndroid Build Coastguard Worker         RINOK(WriteStream(realOutStream, _xmlBuf, _xmlLen))
1163*f6dc9357SAndroid Build Coastguard Worker       realOutStream.Release();
1164*f6dc9357SAndroid Build Coastguard Worker     }
1165*f6dc9357SAndroid Build Coastguard Worker     else
1166*f6dc9357SAndroid Build Coastguard Worker #endif
1167*f6dc9357SAndroid Build Coastguard Worker     {
1168*f6dc9357SAndroid Build Coastguard Worker       const CFile &item = _files[index];
1169*f6dc9357SAndroid Build Coastguard Worker       if (!item.HasData)
1170*f6dc9357SAndroid Build Coastguard Worker         realOutStream.Release();
1171*f6dc9357SAndroid Build Coastguard Worker       else
1172*f6dc9357SAndroid Build Coastguard Worker       {
1173*f6dc9357SAndroid Build Coastguard Worker         cur_PackSize = item.PackSize;
1174*f6dc9357SAndroid Build Coastguard Worker         cur_UnpSize = item.Size;
1175*f6dc9357SAndroid Build Coastguard Worker 
1176*f6dc9357SAndroid Build Coastguard Worker         RINOK(InStream_SeekSet(_inStream, _dataStartPos + item.Offset))
1177*f6dc9357SAndroid Build Coastguard Worker 
1178*f6dc9357SAndroid Build Coastguard Worker         inHashStream.SetStreamAndInit(_inStream, item.archived_checksum.AlgoNumber);
1179*f6dc9357SAndroid Build Coastguard Worker         inHashStream.inStreamLim->Init(item.PackSize);
1180*f6dc9357SAndroid Build Coastguard Worker 
1181*f6dc9357SAndroid Build Coastguard Worker         const int checksum_method = item.extracted_checksum.AlgoNumber;
1182*f6dc9357SAndroid Build Coastguard Worker         if (checksum_method == XAR_CKSUM_SHA1)
1183*f6dc9357SAndroid Build Coastguard Worker         {
1184*f6dc9357SAndroid Build Coastguard Worker           outStreamLim->SetStream(outStreamSha1);
1185*f6dc9357SAndroid Build Coastguard Worker           outStreamSha1->SetStream(realOutStream);
1186*f6dc9357SAndroid Build Coastguard Worker           outStreamSha1->Init();
1187*f6dc9357SAndroid Build Coastguard Worker         }
1188*f6dc9357SAndroid Build Coastguard Worker         else if (checksum_method == XAR_CKSUM_SHA256
1189*f6dc9357SAndroid Build Coastguard Worker               || checksum_method == XAR_CKSUM_SHA512)
1190*f6dc9357SAndroid Build Coastguard Worker         {
1191*f6dc9357SAndroid Build Coastguard Worker           outStreamLim->SetStream(outStreamSha256);
1192*f6dc9357SAndroid Build Coastguard Worker           outStreamSha256->SetStream(realOutStream);
1193*f6dc9357SAndroid Build Coastguard Worker           outStreamSha256->Init(checksum_method == XAR_CKSUM_SHA512);
1194*f6dc9357SAndroid Build Coastguard Worker         }
1195*f6dc9357SAndroid Build Coastguard Worker         else
1196*f6dc9357SAndroid Build Coastguard Worker           outStreamLim->SetStream(realOutStream);
1197*f6dc9357SAndroid Build Coastguard Worker 
1198*f6dc9357SAndroid Build Coastguard Worker         realOutStream.Release();
1199*f6dc9357SAndroid Build Coastguard Worker 
1200*f6dc9357SAndroid Build Coastguard Worker         // outStreamSha1->Init(item.Sha1IsDefined);
1201*f6dc9357SAndroid Build Coastguard Worker 
1202*f6dc9357SAndroid Build Coastguard Worker         outStreamLim->Init(item.Size);
1203*f6dc9357SAndroid Build Coastguard Worker         HRESULT res = S_OK;
1204*f6dc9357SAndroid Build Coastguard Worker 
1205*f6dc9357SAndroid Build Coastguard Worker         ICompressCoder *coder = NULL;
1206*f6dc9357SAndroid Build Coastguard Worker         if (item.IsCopyMethod())
1207*f6dc9357SAndroid Build Coastguard Worker         {
1208*f6dc9357SAndroid Build Coastguard Worker           if (item.PackSize == item.Size)
1209*f6dc9357SAndroid Build Coastguard Worker             coder = copyCoder;
1210*f6dc9357SAndroid Build Coastguard Worker           else
1211*f6dc9357SAndroid Build Coastguard Worker             opRes = NExtract::NOperationResult::kUnsupportedMethod;
1212*f6dc9357SAndroid Build Coastguard Worker         }
1213*f6dc9357SAndroid Build Coastguard Worker         else if (item.Method == METHOD_NAME_ZLIB)
1214*f6dc9357SAndroid Build Coastguard Worker           coder = zlibCoder;
1215*f6dc9357SAndroid Build Coastguard Worker         else if (item.Method == "bzip2")
1216*f6dc9357SAndroid Build Coastguard Worker           coder = bzip2Coder;
1217*f6dc9357SAndroid Build Coastguard Worker         else
1218*f6dc9357SAndroid Build Coastguard Worker           opRes = NExtract::NOperationResult::kUnsupportedMethod;
1219*f6dc9357SAndroid Build Coastguard Worker 
1220*f6dc9357SAndroid Build Coastguard Worker         if (coder)
1221*f6dc9357SAndroid Build Coastguard Worker           res = coder->Code(inHashStream.inStreamLim, outStreamLim, NULL, &item.Size, lps);
1222*f6dc9357SAndroid Build Coastguard Worker 
1223*f6dc9357SAndroid Build Coastguard Worker         if (res != S_OK)
1224*f6dc9357SAndroid Build Coastguard Worker         {
1225*f6dc9357SAndroid Build Coastguard Worker           if (!outStreamLim->IsFinishedOK())
1226*f6dc9357SAndroid Build Coastguard Worker             opRes = NExtract::NOperationResult::kDataError;
1227*f6dc9357SAndroid Build Coastguard Worker           else if (res != S_FALSE)
1228*f6dc9357SAndroid Build Coastguard Worker             return res;
1229*f6dc9357SAndroid Build Coastguard Worker           if (opRes == NExtract::NOperationResult::kOK)
1230*f6dc9357SAndroid Build Coastguard Worker             opRes = NExtract::NOperationResult::kDataError;
1231*f6dc9357SAndroid Build Coastguard Worker         }
1232*f6dc9357SAndroid Build Coastguard Worker 
1233*f6dc9357SAndroid Build Coastguard Worker         if (opRes == NExtract::NOperationResult::kOK)
1234*f6dc9357SAndroid Build Coastguard Worker         {
1235*f6dc9357SAndroid Build Coastguard Worker           if (outStreamLim->IsFinishedOK())
1236*f6dc9357SAndroid Build Coastguard Worker           {
1237*f6dc9357SAndroid Build Coastguard Worker             if (checksum_method == XAR_CKSUM_SHA1)
1238*f6dc9357SAndroid Build Coastguard Worker             {
1239*f6dc9357SAndroid Build Coastguard Worker               Byte digest[SHA1_DIGEST_SIZE];
1240*f6dc9357SAndroid Build Coastguard Worker               outStreamSha1->Final(digest);
1241*f6dc9357SAndroid Build Coastguard Worker               if (memcmp(digest, item.extracted_checksum.Data, SHA1_DIGEST_SIZE) != 0)
1242*f6dc9357SAndroid Build Coastguard Worker                 opRes = NExtract::NOperationResult::kCRCError;
1243*f6dc9357SAndroid Build Coastguard Worker             }
1244*f6dc9357SAndroid Build Coastguard Worker             else if (checksum_method == XAR_CKSUM_SHA256)
1245*f6dc9357SAndroid Build Coastguard Worker             {
1246*f6dc9357SAndroid Build Coastguard Worker               Byte digest[SHA256_DIGEST_SIZE];
1247*f6dc9357SAndroid Build Coastguard Worker               outStreamSha256->Final256(digest);
1248*f6dc9357SAndroid Build Coastguard Worker               if (memcmp(digest, item.extracted_checksum.Data, sizeof(digest)) != 0)
1249*f6dc9357SAndroid Build Coastguard Worker                 opRes = NExtract::NOperationResult::kCRCError;
1250*f6dc9357SAndroid Build Coastguard Worker             }
1251*f6dc9357SAndroid Build Coastguard Worker             else if (checksum_method == XAR_CKSUM_SHA512)
1252*f6dc9357SAndroid Build Coastguard Worker             {
1253*f6dc9357SAndroid Build Coastguard Worker               Byte digest[SHA512_DIGEST_SIZE];
1254*f6dc9357SAndroid Build Coastguard Worker               outStreamSha256->Final512(digest);
1255*f6dc9357SAndroid Build Coastguard Worker               if (memcmp(digest, item.extracted_checksum.Data, sizeof(digest)) != 0)
1256*f6dc9357SAndroid Build Coastguard Worker                 opRes = NExtract::NOperationResult::kCRCError;
1257*f6dc9357SAndroid Build Coastguard Worker             }
1258*f6dc9357SAndroid Build Coastguard Worker             if (opRes == NExtract::NOperationResult::kOK)
1259*f6dc9357SAndroid Build Coastguard Worker               if (!inHashStream.CheckHash(
1260*f6dc9357SAndroid Build Coastguard Worker                     item.archived_checksum.AlgoNumber,
1261*f6dc9357SAndroid Build Coastguard Worker                     item.archived_checksum.Data))
1262*f6dc9357SAndroid Build Coastguard Worker                 opRes = NExtract::NOperationResult::kCRCError;
1263*f6dc9357SAndroid Build Coastguard Worker           }
1264*f6dc9357SAndroid Build Coastguard Worker           else
1265*f6dc9357SAndroid Build Coastguard Worker             opRes = NExtract::NOperationResult::kDataError;
1266*f6dc9357SAndroid Build Coastguard Worker         }
1267*f6dc9357SAndroid Build Coastguard Worker         if (checksum_method == XAR_CKSUM_SHA1)
1268*f6dc9357SAndroid Build Coastguard Worker           outStreamSha1->ReleaseStream();
1269*f6dc9357SAndroid Build Coastguard Worker         else if (checksum_method == XAR_CKSUM_SHA256)
1270*f6dc9357SAndroid Build Coastguard Worker           outStreamSha256->ReleaseStream();
1271*f6dc9357SAndroid Build Coastguard Worker       }
1272*f6dc9357SAndroid Build Coastguard Worker       outStreamLim->ReleaseStream();
1273*f6dc9357SAndroid Build Coastguard Worker     }
1274*f6dc9357SAndroid Build Coastguard Worker     RINOK(extractCallback->SetOperationResult(opRes))
1275*f6dc9357SAndroid Build Coastguard Worker   }
1276*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1277*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
1278*f6dc9357SAndroid Build Coastguard Worker }
1279*f6dc9357SAndroid Build Coastguard Worker 
1280*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
1281*f6dc9357SAndroid Build Coastguard Worker {
1282*f6dc9357SAndroid Build Coastguard Worker   *stream = NULL;
1283*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
1284*f6dc9357SAndroid Build Coastguard Worker #ifdef XAR_SHOW_RAW
1285*f6dc9357SAndroid Build Coastguard Worker   if (index >= _files.Size())
1286*f6dc9357SAndroid Build Coastguard Worker   {
1287*f6dc9357SAndroid Build Coastguard Worker     Create_BufInStream_WithNewBuffer(_xmlBuf, _xmlLen, stream);
1288*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
1289*f6dc9357SAndroid Build Coastguard Worker   }
1290*f6dc9357SAndroid Build Coastguard Worker   else
1291*f6dc9357SAndroid Build Coastguard Worker #endif
1292*f6dc9357SAndroid Build Coastguard Worker   {
1293*f6dc9357SAndroid Build Coastguard Worker     const CFile &item = _files[index];
1294*f6dc9357SAndroid Build Coastguard Worker     if (item.HasData && item.IsCopyMethod() && item.PackSize == item.Size)
1295*f6dc9357SAndroid Build Coastguard Worker       return CreateLimitedInStream(_inStream, _dataStartPos + item.Offset, item.Size, stream);
1296*f6dc9357SAndroid Build Coastguard Worker   }
1297*f6dc9357SAndroid Build Coastguard Worker   return S_FALSE;
1298*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
1299*f6dc9357SAndroid Build Coastguard Worker }
1300*f6dc9357SAndroid Build Coastguard Worker 
1301*f6dc9357SAndroid Build Coastguard Worker // 0x1c == 28 is expected header size value for most archives.
1302*f6dc9357SAndroid Build Coastguard Worker // but we want to support another (rare case) headers sizes.
1303*f6dc9357SAndroid Build Coastguard Worker // so we must reduce signature to 4 or 5 bytes.
1304*f6dc9357SAndroid Build Coastguard Worker static const Byte k_Signature[] =
1305*f6dc9357SAndroid Build Coastguard Worker //  { 'x', 'a', 'r', '!', 0, 0x1C, 0 };
1306*f6dc9357SAndroid Build Coastguard Worker     { 'x', 'a', 'r', '!', 0 };
1307*f6dc9357SAndroid Build Coastguard Worker 
1308*f6dc9357SAndroid Build Coastguard Worker REGISTER_ARC_I(
1309*f6dc9357SAndroid Build Coastguard Worker   "Xar", "xar pkg xip", NULL, 0xE1,
1310*f6dc9357SAndroid Build Coastguard Worker   k_Signature,
1311*f6dc9357SAndroid Build Coastguard Worker   0,
1312*f6dc9357SAndroid Build Coastguard Worker   0,
1313*f6dc9357SAndroid Build Coastguard Worker   NULL)
1314*f6dc9357SAndroid Build Coastguard Worker 
1315*f6dc9357SAndroid Build Coastguard Worker }}
1316