xref: /aosp_15_r20/external/lzma/CPP/7zip/Archive/Rar/Rar5Handler.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1*f6dc9357SAndroid Build Coastguard Worker // Rar5Handler.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/7zCrc.h"
6*f6dc9357SAndroid Build Coastguard Worker #include "../../../../C/CpuArch.h"
7*f6dc9357SAndroid Build Coastguard Worker 
8*f6dc9357SAndroid Build Coastguard Worker #include "../../../Common/ComTry.h"
9*f6dc9357SAndroid Build Coastguard Worker #include "../../../Common/IntToString.h"
10*f6dc9357SAndroid Build Coastguard Worker #include "../../../Common/MyBuffer2.h"
11*f6dc9357SAndroid Build Coastguard Worker #include "../../../Common/UTFConvert.h"
12*f6dc9357SAndroid Build Coastguard Worker 
13*f6dc9357SAndroid Build Coastguard Worker #include "../../../Windows/PropVariantUtils.h"
14*f6dc9357SAndroid Build Coastguard Worker #include "../../../Windows/TimeUtils.h"
15*f6dc9357SAndroid Build Coastguard Worker 
16*f6dc9357SAndroid Build Coastguard Worker #include "../../IPassword.h"
17*f6dc9357SAndroid Build Coastguard Worker 
18*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/FilterCoder.h"
19*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/LimitedStreams.h"
20*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/MethodProps.h"
21*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/ProgressUtils.h"
22*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/RegisterArc.h"
23*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/StreamObjects.h"
24*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/StreamUtils.h"
25*f6dc9357SAndroid Build Coastguard Worker 
26*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/RegisterCodec.h"
27*f6dc9357SAndroid Build Coastguard Worker 
28*f6dc9357SAndroid Build Coastguard Worker #include "../../Compress/CopyCoder.h"
29*f6dc9357SAndroid Build Coastguard Worker 
30*f6dc9357SAndroid Build Coastguard Worker #include "../../Crypto/Rar5Aes.h"
31*f6dc9357SAndroid Build Coastguard Worker 
32*f6dc9357SAndroid Build Coastguard Worker #include "../../Archive/Common/FindSignature.h"
33*f6dc9357SAndroid Build Coastguard Worker #include "../../Archive/Common/ItemNameUtils.h"
34*f6dc9357SAndroid Build Coastguard Worker #include "../../Archive/Common/HandlerOut.h"
35*f6dc9357SAndroid Build Coastguard Worker 
36*f6dc9357SAndroid Build Coastguard Worker #include "../../Archive/HandlerCont.h"
37*f6dc9357SAndroid Build Coastguard Worker 
38*f6dc9357SAndroid Build Coastguard Worker #include "../../Archive/Rar/RarVol.h"
39*f6dc9357SAndroid Build Coastguard Worker #include "Rar5Handler.h"
40*f6dc9357SAndroid Build Coastguard Worker 
41*f6dc9357SAndroid Build Coastguard Worker using namespace NWindows;
42*f6dc9357SAndroid Build Coastguard Worker 
43*f6dc9357SAndroid Build Coastguard Worker #define Get32(p) GetUi32(p)
44*f6dc9357SAndroid Build Coastguard Worker 
45*f6dc9357SAndroid Build Coastguard Worker namespace NArchive {
46*f6dc9357SAndroid Build Coastguard Worker namespace NRar5 {
47*f6dc9357SAndroid Build Coastguard Worker 
48*f6dc9357SAndroid Build Coastguard Worker static const unsigned kMarkerSize = 8;
49*f6dc9357SAndroid Build Coastguard Worker 
50*f6dc9357SAndroid Build Coastguard Worker static const Byte kMarker[kMarkerSize] =
51*f6dc9357SAndroid Build Coastguard Worker   { 0x52, 0x61, 0x72, 0x21, 0x1a, 0x07, 0x01, 0 };
52*f6dc9357SAndroid Build Coastguard Worker 
53*f6dc9357SAndroid Build Coastguard Worker // Comment length is limited to 256 KB in rar-encoder.
54*f6dc9357SAndroid Build Coastguard Worker // So we use same limitation
55*f6dc9357SAndroid Build Coastguard Worker static const size_t kCommentSize_Max = (size_t)1 << 18;
56*f6dc9357SAndroid Build Coastguard Worker 
57*f6dc9357SAndroid Build Coastguard Worker 
58*f6dc9357SAndroid Build Coastguard Worker static const char * const kHostOS[] =
59*f6dc9357SAndroid Build Coastguard Worker {
60*f6dc9357SAndroid Build Coastguard Worker     "Windows"
61*f6dc9357SAndroid Build Coastguard Worker   , "Unix"
62*f6dc9357SAndroid Build Coastguard Worker };
63*f6dc9357SAndroid Build Coastguard Worker 
64*f6dc9357SAndroid Build Coastguard Worker 
65*f6dc9357SAndroid Build Coastguard Worker static const char * const k_ArcFlags[] =
66*f6dc9357SAndroid Build Coastguard Worker {
67*f6dc9357SAndroid Build Coastguard Worker     "Volume"
68*f6dc9357SAndroid Build Coastguard Worker   , "VolumeField"
69*f6dc9357SAndroid Build Coastguard Worker   , "Solid"
70*f6dc9357SAndroid Build Coastguard Worker   , "Recovery"
71*f6dc9357SAndroid Build Coastguard Worker   , "Lock" // 4
72*f6dc9357SAndroid Build Coastguard Worker };
73*f6dc9357SAndroid Build Coastguard Worker 
74*f6dc9357SAndroid Build Coastguard Worker 
75*f6dc9357SAndroid Build Coastguard Worker static const char * const k_FileFlags[] =
76*f6dc9357SAndroid Build Coastguard Worker {
77*f6dc9357SAndroid Build Coastguard Worker     "Dir"
78*f6dc9357SAndroid Build Coastguard Worker   , "UnixTime"
79*f6dc9357SAndroid Build Coastguard Worker   , "CRC"
80*f6dc9357SAndroid Build Coastguard Worker   , "UnknownSize"
81*f6dc9357SAndroid Build Coastguard Worker };
82*f6dc9357SAndroid Build Coastguard Worker 
83*f6dc9357SAndroid Build Coastguard Worker 
84*f6dc9357SAndroid Build Coastguard Worker static const char * const g_ExtraTypes[] =
85*f6dc9357SAndroid Build Coastguard Worker {
86*f6dc9357SAndroid Build Coastguard Worker     "0"
87*f6dc9357SAndroid Build Coastguard Worker   , "Crypto"
88*f6dc9357SAndroid Build Coastguard Worker   , "Hash"
89*f6dc9357SAndroid Build Coastguard Worker   , "Time"
90*f6dc9357SAndroid Build Coastguard Worker   , "Version"
91*f6dc9357SAndroid Build Coastguard Worker   , "Link"
92*f6dc9357SAndroid Build Coastguard Worker   , "UnixOwner"
93*f6dc9357SAndroid Build Coastguard Worker   , "Subdata"
94*f6dc9357SAndroid Build Coastguard Worker };
95*f6dc9357SAndroid Build Coastguard Worker 
96*f6dc9357SAndroid Build Coastguard Worker 
97*f6dc9357SAndroid Build Coastguard Worker static const char * const g_LinkTypes[] =
98*f6dc9357SAndroid Build Coastguard Worker {
99*f6dc9357SAndroid Build Coastguard Worker     "0"
100*f6dc9357SAndroid Build Coastguard Worker   , "UnixSymLink"
101*f6dc9357SAndroid Build Coastguard Worker   , "WinSymLink"
102*f6dc9357SAndroid Build Coastguard Worker   , "WinJunction"
103*f6dc9357SAndroid Build Coastguard Worker   , "HardLink"
104*f6dc9357SAndroid Build Coastguard Worker   , "FileCopy"
105*f6dc9357SAndroid Build Coastguard Worker };
106*f6dc9357SAndroid Build Coastguard Worker 
107*f6dc9357SAndroid Build Coastguard Worker 
108*f6dc9357SAndroid Build Coastguard Worker static const char g_ExtraTimeFlags[] = { 'u', 'M', 'C', 'A', 'n' };
109*f6dc9357SAndroid Build Coastguard Worker 
110*f6dc9357SAndroid Build Coastguard Worker 
111*f6dc9357SAndroid Build Coastguard Worker static
112*f6dc9357SAndroid Build Coastguard Worker Z7_NO_INLINE
ReadVarInt(const Byte * p,size_t maxSize,UInt64 * val_ptr)113*f6dc9357SAndroid Build Coastguard Worker unsigned ReadVarInt(const Byte *p, size_t maxSize, UInt64 *val_ptr)
114*f6dc9357SAndroid Build Coastguard Worker {
115*f6dc9357SAndroid Build Coastguard Worker   if (maxSize > 10)
116*f6dc9357SAndroid Build Coastguard Worker       maxSize = 10;
117*f6dc9357SAndroid Build Coastguard Worker   UInt64 val = 0;
118*f6dc9357SAndroid Build Coastguard Worker   unsigned i;
119*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < maxSize;)
120*f6dc9357SAndroid Build Coastguard Worker   {
121*f6dc9357SAndroid Build Coastguard Worker     const unsigned b = p[i];
122*f6dc9357SAndroid Build Coastguard Worker     val |= (UInt64)(b & 0x7F) << (7 * i);
123*f6dc9357SAndroid Build Coastguard Worker     i++;
124*f6dc9357SAndroid Build Coastguard Worker     if ((b & 0x80) == 0)
125*f6dc9357SAndroid Build Coastguard Worker     {
126*f6dc9357SAndroid Build Coastguard Worker       *val_ptr = val;
127*f6dc9357SAndroid Build Coastguard Worker       return i;
128*f6dc9357SAndroid Build Coastguard Worker     }
129*f6dc9357SAndroid Build Coastguard Worker   }
130*f6dc9357SAndroid Build Coastguard Worker   *val_ptr = 0;
131*f6dc9357SAndroid Build Coastguard Worker #if 1
132*f6dc9357SAndroid Build Coastguard Worker   return 0; // 7zip-unrar : strict check of error
133*f6dc9357SAndroid Build Coastguard Worker #else
134*f6dc9357SAndroid Build Coastguard Worker   return i; // original-unrar : ignore error
135*f6dc9357SAndroid Build Coastguard Worker #endif
136*f6dc9357SAndroid Build Coastguard Worker }
137*f6dc9357SAndroid Build Coastguard Worker 
138*f6dc9357SAndroid Build Coastguard Worker 
139*f6dc9357SAndroid Build Coastguard Worker #define PARSE_VAR_INT(p, size, dest) \
140*f6dc9357SAndroid Build Coastguard Worker { const unsigned num_ = ReadVarInt(p, size, &dest);  \
141*f6dc9357SAndroid Build Coastguard Worker   if (num_ == 0) return false; \
142*f6dc9357SAndroid Build Coastguard Worker   p += num_; \
143*f6dc9357SAndroid Build Coastguard Worker   size -= num_; \
144*f6dc9357SAndroid Build Coastguard Worker }
145*f6dc9357SAndroid Build Coastguard Worker 
146*f6dc9357SAndroid Build Coastguard Worker 
Parse(const Byte * p,unsigned size)147*f6dc9357SAndroid Build Coastguard Worker bool CLinkInfo::Parse(const Byte *p, unsigned size)
148*f6dc9357SAndroid Build Coastguard Worker {
149*f6dc9357SAndroid Build Coastguard Worker   const Byte *pStart = p;
150*f6dc9357SAndroid Build Coastguard Worker   UInt64 len;
151*f6dc9357SAndroid Build Coastguard Worker   PARSE_VAR_INT(p, size, Type)
152*f6dc9357SAndroid Build Coastguard Worker   PARSE_VAR_INT(p, size, Flags)
153*f6dc9357SAndroid Build Coastguard Worker   PARSE_VAR_INT(p, size, len)
154*f6dc9357SAndroid Build Coastguard Worker   if (size != len)
155*f6dc9357SAndroid Build Coastguard Worker     return false;
156*f6dc9357SAndroid Build Coastguard Worker   NameLen = (unsigned)len;
157*f6dc9357SAndroid Build Coastguard Worker   NameOffset = (unsigned)(size_t)(p - pStart);
158*f6dc9357SAndroid Build Coastguard Worker   return true;
159*f6dc9357SAndroid Build Coastguard Worker }
160*f6dc9357SAndroid Build Coastguard Worker 
161*f6dc9357SAndroid Build Coastguard Worker 
AddHex64(AString & s,UInt64 v)162*f6dc9357SAndroid Build Coastguard Worker static void AddHex64(AString &s, UInt64 v)
163*f6dc9357SAndroid Build Coastguard Worker {
164*f6dc9357SAndroid Build Coastguard Worker   char sz[32];
165*f6dc9357SAndroid Build Coastguard Worker   sz[0] = '0';
166*f6dc9357SAndroid Build Coastguard Worker   sz[1] = 'x';
167*f6dc9357SAndroid Build Coastguard Worker   ConvertUInt64ToHex(v, sz + 2);
168*f6dc9357SAndroid Build Coastguard Worker   s += sz;
169*f6dc9357SAndroid Build Coastguard Worker }
170*f6dc9357SAndroid Build Coastguard Worker 
171*f6dc9357SAndroid Build Coastguard Worker 
PrintType(AString & s,const char * const table[],unsigned num,UInt64 val)172*f6dc9357SAndroid Build Coastguard Worker static void PrintType(AString &s, const char * const table[], unsigned num, UInt64 val)
173*f6dc9357SAndroid Build Coastguard Worker {
174*f6dc9357SAndroid Build Coastguard Worker   char sz[32];
175*f6dc9357SAndroid Build Coastguard Worker   const char *p = NULL;
176*f6dc9357SAndroid Build Coastguard Worker   if (val < num)
177*f6dc9357SAndroid Build Coastguard Worker     p = table[(unsigned)val];
178*f6dc9357SAndroid Build Coastguard Worker   if (!p)
179*f6dc9357SAndroid Build Coastguard Worker   {
180*f6dc9357SAndroid Build Coastguard Worker     ConvertUInt64ToString(val, sz);
181*f6dc9357SAndroid Build Coastguard Worker     p = sz;
182*f6dc9357SAndroid Build Coastguard Worker   }
183*f6dc9357SAndroid Build Coastguard Worker   s += p;
184*f6dc9357SAndroid Build Coastguard Worker }
185*f6dc9357SAndroid Build Coastguard Worker 
186*f6dc9357SAndroid Build Coastguard Worker 
FindExtra(unsigned extraID,unsigned & recordDataSize) const187*f6dc9357SAndroid Build Coastguard Worker int CItem::FindExtra(unsigned extraID, unsigned &recordDataSize) const
188*f6dc9357SAndroid Build Coastguard Worker {
189*f6dc9357SAndroid Build Coastguard Worker   recordDataSize = 0;
190*f6dc9357SAndroid Build Coastguard Worker   size_t offset = 0;
191*f6dc9357SAndroid Build Coastguard Worker 
192*f6dc9357SAndroid Build Coastguard Worker   for (;;)
193*f6dc9357SAndroid Build Coastguard Worker   {
194*f6dc9357SAndroid Build Coastguard Worker     size_t rem = Extra.Size() - offset;
195*f6dc9357SAndroid Build Coastguard Worker     if (rem == 0)
196*f6dc9357SAndroid Build Coastguard Worker       return -1;
197*f6dc9357SAndroid Build Coastguard Worker 
198*f6dc9357SAndroid Build Coastguard Worker     {
199*f6dc9357SAndroid Build Coastguard Worker       UInt64 size;
200*f6dc9357SAndroid Build Coastguard Worker       const unsigned num = ReadVarInt(Extra + offset, rem, &size);
201*f6dc9357SAndroid Build Coastguard Worker       if (num == 0)
202*f6dc9357SAndroid Build Coastguard Worker         return -1;
203*f6dc9357SAndroid Build Coastguard Worker       offset += num;
204*f6dc9357SAndroid Build Coastguard Worker       rem -= num;
205*f6dc9357SAndroid Build Coastguard Worker       if (size > rem)
206*f6dc9357SAndroid Build Coastguard Worker         return -1;
207*f6dc9357SAndroid Build Coastguard Worker       rem = (size_t)size;
208*f6dc9357SAndroid Build Coastguard Worker     }
209*f6dc9357SAndroid Build Coastguard Worker     {
210*f6dc9357SAndroid Build Coastguard Worker       UInt64 id;
211*f6dc9357SAndroid Build Coastguard Worker       const unsigned num = ReadVarInt(Extra + offset, rem, &id);
212*f6dc9357SAndroid Build Coastguard Worker       if (num == 0)
213*f6dc9357SAndroid Build Coastguard Worker         return -1;
214*f6dc9357SAndroid Build Coastguard Worker       offset += num;
215*f6dc9357SAndroid Build Coastguard Worker       rem -= num;
216*f6dc9357SAndroid Build Coastguard Worker 
217*f6dc9357SAndroid Build Coastguard Worker       // There was BUG in RAR 5.21- : it stored (size-1) instead of (size)
218*f6dc9357SAndroid Build Coastguard Worker       // for Subdata record in Service header.
219*f6dc9357SAndroid Build Coastguard Worker       // That record always was last in bad archives, so we can fix that case.
220*f6dc9357SAndroid Build Coastguard Worker       if (id == NExtraID::kSubdata
221*f6dc9357SAndroid Build Coastguard Worker           && RecordType == NHeaderType::kService
222*f6dc9357SAndroid Build Coastguard Worker           && rem + 1 == Extra.Size() - offset)
223*f6dc9357SAndroid Build Coastguard Worker         rem++;
224*f6dc9357SAndroid Build Coastguard Worker 
225*f6dc9357SAndroid Build Coastguard Worker       if (id == extraID)
226*f6dc9357SAndroid Build Coastguard Worker       {
227*f6dc9357SAndroid Build Coastguard Worker         recordDataSize = (unsigned)rem;
228*f6dc9357SAndroid Build Coastguard Worker         return (int)offset;
229*f6dc9357SAndroid Build Coastguard Worker       }
230*f6dc9357SAndroid Build Coastguard Worker 
231*f6dc9357SAndroid Build Coastguard Worker       offset += rem;
232*f6dc9357SAndroid Build Coastguard Worker     }
233*f6dc9357SAndroid Build Coastguard Worker   }
234*f6dc9357SAndroid Build Coastguard Worker }
235*f6dc9357SAndroid Build Coastguard Worker 
236*f6dc9357SAndroid Build Coastguard Worker 
PrintInfo(AString & s) const237*f6dc9357SAndroid Build Coastguard Worker void CItem::PrintInfo(AString &s) const
238*f6dc9357SAndroid Build Coastguard Worker {
239*f6dc9357SAndroid Build Coastguard Worker   size_t offset = 0;
240*f6dc9357SAndroid Build Coastguard Worker 
241*f6dc9357SAndroid Build Coastguard Worker   for (;;)
242*f6dc9357SAndroid Build Coastguard Worker   {
243*f6dc9357SAndroid Build Coastguard Worker     size_t rem = Extra.Size() - offset;
244*f6dc9357SAndroid Build Coastguard Worker     if (rem == 0)
245*f6dc9357SAndroid Build Coastguard Worker       return;
246*f6dc9357SAndroid Build Coastguard Worker 
247*f6dc9357SAndroid Build Coastguard Worker     {
248*f6dc9357SAndroid Build Coastguard Worker       UInt64 size;
249*f6dc9357SAndroid Build Coastguard Worker       unsigned num = ReadVarInt(Extra + offset, rem, &size);
250*f6dc9357SAndroid Build Coastguard Worker       if (num == 0)
251*f6dc9357SAndroid Build Coastguard Worker         return;
252*f6dc9357SAndroid Build Coastguard Worker       offset += num;
253*f6dc9357SAndroid Build Coastguard Worker       rem -= num;
254*f6dc9357SAndroid Build Coastguard Worker       if (size > rem)
255*f6dc9357SAndroid Build Coastguard Worker         break;
256*f6dc9357SAndroid Build Coastguard Worker       rem = (size_t)size;
257*f6dc9357SAndroid Build Coastguard Worker     }
258*f6dc9357SAndroid Build Coastguard Worker     {
259*f6dc9357SAndroid Build Coastguard Worker       UInt64 id;
260*f6dc9357SAndroid Build Coastguard Worker       {
261*f6dc9357SAndroid Build Coastguard Worker         unsigned num = ReadVarInt(Extra + offset, rem, &id);
262*f6dc9357SAndroid Build Coastguard Worker         if (num == 0)
263*f6dc9357SAndroid Build Coastguard Worker           break;
264*f6dc9357SAndroid Build Coastguard Worker         offset += num;
265*f6dc9357SAndroid Build Coastguard Worker         rem -= num;
266*f6dc9357SAndroid Build Coastguard Worker       }
267*f6dc9357SAndroid Build Coastguard Worker 
268*f6dc9357SAndroid Build Coastguard Worker       // There was BUG in RAR 5.21- : it stored (size-1) instead of (size)
269*f6dc9357SAndroid Build Coastguard Worker       // for Subdata record in Service header.
270*f6dc9357SAndroid Build Coastguard Worker       // That record always was last in bad archives, so we can fix that case.
271*f6dc9357SAndroid Build Coastguard Worker       if (id == NExtraID::kSubdata
272*f6dc9357SAndroid Build Coastguard Worker           && RecordType == NHeaderType::kService
273*f6dc9357SAndroid Build Coastguard Worker           && rem + 1 == Extra.Size() - offset)
274*f6dc9357SAndroid Build Coastguard Worker         rem++;
275*f6dc9357SAndroid Build Coastguard Worker 
276*f6dc9357SAndroid Build Coastguard Worker       s.Add_Space_if_NotEmpty();
277*f6dc9357SAndroid Build Coastguard Worker       PrintType(s, g_ExtraTypes, Z7_ARRAY_SIZE(g_ExtraTypes), id);
278*f6dc9357SAndroid Build Coastguard Worker 
279*f6dc9357SAndroid Build Coastguard Worker       if (id == NExtraID::kTime)
280*f6dc9357SAndroid Build Coastguard Worker       {
281*f6dc9357SAndroid Build Coastguard Worker         const Byte *p = Extra + offset;
282*f6dc9357SAndroid Build Coastguard Worker         UInt64 flags;
283*f6dc9357SAndroid Build Coastguard Worker         const unsigned num = ReadVarInt(p, rem, &flags);
284*f6dc9357SAndroid Build Coastguard Worker         if (num != 0)
285*f6dc9357SAndroid Build Coastguard Worker         {
286*f6dc9357SAndroid Build Coastguard Worker           s.Add_Colon();
287*f6dc9357SAndroid Build Coastguard Worker           for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_ExtraTimeFlags); i++)
288*f6dc9357SAndroid Build Coastguard Worker             if ((flags & ((UInt64)1 << i)) != 0)
289*f6dc9357SAndroid Build Coastguard Worker               s.Add_Char(g_ExtraTimeFlags[i]);
290*f6dc9357SAndroid Build Coastguard Worker           flags &= ~(((UInt64)1 << Z7_ARRAY_SIZE(g_ExtraTimeFlags)) - 1);
291*f6dc9357SAndroid Build Coastguard Worker           if (flags != 0)
292*f6dc9357SAndroid Build Coastguard Worker           {
293*f6dc9357SAndroid Build Coastguard Worker             s.Add_Char('_');
294*f6dc9357SAndroid Build Coastguard Worker             AddHex64(s, flags);
295*f6dc9357SAndroid Build Coastguard Worker           }
296*f6dc9357SAndroid Build Coastguard Worker         }
297*f6dc9357SAndroid Build Coastguard Worker       }
298*f6dc9357SAndroid Build Coastguard Worker       else if (id == NExtraID::kLink)
299*f6dc9357SAndroid Build Coastguard Worker       {
300*f6dc9357SAndroid Build Coastguard Worker         CLinkInfo linkInfo;
301*f6dc9357SAndroid Build Coastguard Worker         if (linkInfo.Parse(Extra + offset, (unsigned)rem))
302*f6dc9357SAndroid Build Coastguard Worker         {
303*f6dc9357SAndroid Build Coastguard Worker           s.Add_Colon();
304*f6dc9357SAndroid Build Coastguard Worker           PrintType(s, g_LinkTypes, Z7_ARRAY_SIZE(g_LinkTypes), linkInfo.Type);
305*f6dc9357SAndroid Build Coastguard Worker           UInt64 flags = linkInfo.Flags;
306*f6dc9357SAndroid Build Coastguard Worker           if (flags != 0)
307*f6dc9357SAndroid Build Coastguard Worker           {
308*f6dc9357SAndroid Build Coastguard Worker             s.Add_Colon();
309*f6dc9357SAndroid Build Coastguard Worker             if (flags & NLinkFlags::kTargetIsDir)
310*f6dc9357SAndroid Build Coastguard Worker             {
311*f6dc9357SAndroid Build Coastguard Worker               s.Add_Char('D');
312*f6dc9357SAndroid Build Coastguard Worker               flags &= ~((UInt64)NLinkFlags::kTargetIsDir);
313*f6dc9357SAndroid Build Coastguard Worker             }
314*f6dc9357SAndroid Build Coastguard Worker             if (flags != 0)
315*f6dc9357SAndroid Build Coastguard Worker             {
316*f6dc9357SAndroid Build Coastguard Worker               s.Add_Char('_');
317*f6dc9357SAndroid Build Coastguard Worker               AddHex64(s, flags);
318*f6dc9357SAndroid Build Coastguard Worker             }
319*f6dc9357SAndroid Build Coastguard Worker           }
320*f6dc9357SAndroid Build Coastguard Worker         }
321*f6dc9357SAndroid Build Coastguard Worker       }
322*f6dc9357SAndroid Build Coastguard Worker 
323*f6dc9357SAndroid Build Coastguard Worker       offset += rem;
324*f6dc9357SAndroid Build Coastguard Worker     }
325*f6dc9357SAndroid Build Coastguard Worker   }
326*f6dc9357SAndroid Build Coastguard Worker 
327*f6dc9357SAndroid Build Coastguard Worker   s.Add_OptSpaced("ERROR");
328*f6dc9357SAndroid Build Coastguard Worker }
329*f6dc9357SAndroid Build Coastguard Worker 
330*f6dc9357SAndroid Build Coastguard Worker 
Parse(const Byte * p,size_t size)331*f6dc9357SAndroid Build Coastguard Worker bool CCryptoInfo::Parse(const Byte *p, size_t size)
332*f6dc9357SAndroid Build Coastguard Worker {
333*f6dc9357SAndroid Build Coastguard Worker   Algo = 0;
334*f6dc9357SAndroid Build Coastguard Worker   Flags = 0;
335*f6dc9357SAndroid Build Coastguard Worker   Cnt = 0;
336*f6dc9357SAndroid Build Coastguard Worker   PARSE_VAR_INT(p, size, Algo)
337*f6dc9357SAndroid Build Coastguard Worker   PARSE_VAR_INT(p, size, Flags)
338*f6dc9357SAndroid Build Coastguard Worker   if (size > 0)
339*f6dc9357SAndroid Build Coastguard Worker     Cnt = p[0];
340*f6dc9357SAndroid Build Coastguard Worker   if (size != 1 + 16 + 16 + (unsigned)(IsThereCheck() ? 12 : 0))
341*f6dc9357SAndroid Build Coastguard Worker     return false;
342*f6dc9357SAndroid Build Coastguard Worker   return true;
343*f6dc9357SAndroid Build Coastguard Worker }
344*f6dc9357SAndroid Build Coastguard Worker 
345*f6dc9357SAndroid Build Coastguard Worker 
FindExtra_Version(UInt64 & version) const346*f6dc9357SAndroid Build Coastguard Worker bool CItem::FindExtra_Version(UInt64 &version) const
347*f6dc9357SAndroid Build Coastguard Worker {
348*f6dc9357SAndroid Build Coastguard Worker   unsigned size;
349*f6dc9357SAndroid Build Coastguard Worker   const int offset = FindExtra(NExtraID::kVersion, size);
350*f6dc9357SAndroid Build Coastguard Worker   if (offset < 0)
351*f6dc9357SAndroid Build Coastguard Worker     return false;
352*f6dc9357SAndroid Build Coastguard Worker   const Byte *p = Extra + (unsigned)offset;
353*f6dc9357SAndroid Build Coastguard Worker 
354*f6dc9357SAndroid Build Coastguard Worker   UInt64 flags;
355*f6dc9357SAndroid Build Coastguard Worker   PARSE_VAR_INT(p, size, flags)
356*f6dc9357SAndroid Build Coastguard Worker   PARSE_VAR_INT(p, size, version)
357*f6dc9357SAndroid Build Coastguard Worker   return size == 0;
358*f6dc9357SAndroid Build Coastguard Worker }
359*f6dc9357SAndroid Build Coastguard Worker 
FindExtra_Link(CLinkInfo & link) const360*f6dc9357SAndroid Build Coastguard Worker bool CItem::FindExtra_Link(CLinkInfo &link) const
361*f6dc9357SAndroid Build Coastguard Worker {
362*f6dc9357SAndroid Build Coastguard Worker   unsigned size;
363*f6dc9357SAndroid Build Coastguard Worker   const int offset = FindExtra(NExtraID::kLink, size);
364*f6dc9357SAndroid Build Coastguard Worker   if (offset < 0)
365*f6dc9357SAndroid Build Coastguard Worker     return false;
366*f6dc9357SAndroid Build Coastguard Worker   if (!link.Parse(Extra + (unsigned)offset, size))
367*f6dc9357SAndroid Build Coastguard Worker     return false;
368*f6dc9357SAndroid Build Coastguard Worker   link.NameOffset += (unsigned)offset;
369*f6dc9357SAndroid Build Coastguard Worker   return true;
370*f6dc9357SAndroid Build Coastguard Worker }
371*f6dc9357SAndroid Build Coastguard Worker 
Is_CopyLink() const372*f6dc9357SAndroid Build Coastguard Worker bool CItem::Is_CopyLink() const
373*f6dc9357SAndroid Build Coastguard Worker {
374*f6dc9357SAndroid Build Coastguard Worker   CLinkInfo link;
375*f6dc9357SAndroid Build Coastguard Worker   return FindExtra_Link(link) && link.Type == NLinkType::kFileCopy;
376*f6dc9357SAndroid Build Coastguard Worker }
377*f6dc9357SAndroid Build Coastguard Worker 
Is_HardLink() const378*f6dc9357SAndroid Build Coastguard Worker bool CItem::Is_HardLink() const
379*f6dc9357SAndroid Build Coastguard Worker {
380*f6dc9357SAndroid Build Coastguard Worker   CLinkInfo link;
381*f6dc9357SAndroid Build Coastguard Worker   return FindExtra_Link(link) && link.Type == NLinkType::kHardLink;
382*f6dc9357SAndroid Build Coastguard Worker }
383*f6dc9357SAndroid Build Coastguard Worker 
Is_CopyLink_or_HardLink() const384*f6dc9357SAndroid Build Coastguard Worker bool CItem::Is_CopyLink_or_HardLink() const
385*f6dc9357SAndroid Build Coastguard Worker {
386*f6dc9357SAndroid Build Coastguard Worker   CLinkInfo link;
387*f6dc9357SAndroid Build Coastguard Worker   return FindExtra_Link(link) && (link.Type == NLinkType::kFileCopy || link.Type == NLinkType::kHardLink);
388*f6dc9357SAndroid Build Coastguard Worker }
389*f6dc9357SAndroid Build Coastguard Worker 
Link_to_Prop(unsigned linkType,NWindows::NCOM::CPropVariant & prop) const390*f6dc9357SAndroid Build Coastguard Worker void CItem::Link_to_Prop(unsigned linkType, NWindows::NCOM::CPropVariant &prop) const
391*f6dc9357SAndroid Build Coastguard Worker {
392*f6dc9357SAndroid Build Coastguard Worker   CLinkInfo link;
393*f6dc9357SAndroid Build Coastguard Worker   if (!FindExtra_Link(link))
394*f6dc9357SAndroid Build Coastguard Worker     return;
395*f6dc9357SAndroid Build Coastguard Worker 
396*f6dc9357SAndroid Build Coastguard Worker   if (link.Type != linkType)
397*f6dc9357SAndroid Build Coastguard Worker   {
398*f6dc9357SAndroid Build Coastguard Worker     if (linkType != NLinkType::kUnixSymLink)
399*f6dc9357SAndroid Build Coastguard Worker       return;
400*f6dc9357SAndroid Build Coastguard Worker     switch ((unsigned)link.Type)
401*f6dc9357SAndroid Build Coastguard Worker     {
402*f6dc9357SAndroid Build Coastguard Worker       case NLinkType::kUnixSymLink:
403*f6dc9357SAndroid Build Coastguard Worker       case NLinkType::kWinSymLink:
404*f6dc9357SAndroid Build Coastguard Worker       case NLinkType::kWinJunction:
405*f6dc9357SAndroid Build Coastguard Worker         break;
406*f6dc9357SAndroid Build Coastguard Worker       default: return;
407*f6dc9357SAndroid Build Coastguard Worker     }
408*f6dc9357SAndroid Build Coastguard Worker   }
409*f6dc9357SAndroid Build Coastguard Worker 
410*f6dc9357SAndroid Build Coastguard Worker   AString s;
411*f6dc9357SAndroid Build Coastguard Worker   s.SetFrom_CalcLen((const char *)(Extra + link.NameOffset), link.NameLen);
412*f6dc9357SAndroid Build Coastguard Worker 
413*f6dc9357SAndroid Build Coastguard Worker   UString unicode;
414*f6dc9357SAndroid Build Coastguard Worker   ConvertUTF8ToUnicode(s, unicode);
415*f6dc9357SAndroid Build Coastguard Worker   prop = NItemName::GetOsPath(unicode);
416*f6dc9357SAndroid Build Coastguard Worker }
417*f6dc9357SAndroid Build Coastguard Worker 
GetAltStreamName(AString & name) const418*f6dc9357SAndroid Build Coastguard Worker bool CItem::GetAltStreamName(AString &name) const
419*f6dc9357SAndroid Build Coastguard Worker {
420*f6dc9357SAndroid Build Coastguard Worker   name.Empty();
421*f6dc9357SAndroid Build Coastguard Worker   unsigned size;
422*f6dc9357SAndroid Build Coastguard Worker   const int offset = FindExtra(NExtraID::kSubdata, size);
423*f6dc9357SAndroid Build Coastguard Worker   if (offset < 0)
424*f6dc9357SAndroid Build Coastguard Worker     return false;
425*f6dc9357SAndroid Build Coastguard Worker   name.SetFrom_CalcLen((const char *)(Extra + (unsigned)offset), size);
426*f6dc9357SAndroid Build Coastguard Worker   return true;
427*f6dc9357SAndroid Build Coastguard Worker }
428*f6dc9357SAndroid Build Coastguard Worker 
429*f6dc9357SAndroid Build Coastguard Worker 
430*f6dc9357SAndroid Build Coastguard Worker class CHash
431*f6dc9357SAndroid Build Coastguard Worker {
432*f6dc9357SAndroid Build Coastguard Worker   bool _calcCRC;
433*f6dc9357SAndroid Build Coastguard Worker   UInt32 _crc;
434*f6dc9357SAndroid Build Coastguard Worker   int _blakeOffset;
435*f6dc9357SAndroid Build Coastguard Worker   CAlignedBuffer1 _buf;
436*f6dc9357SAndroid Build Coastguard Worker   // CBlake2sp _blake;
BlakeObj()437*f6dc9357SAndroid Build Coastguard Worker   CBlake2sp *BlakeObj() { return (CBlake2sp *)(void *)(Byte *)_buf; }
438*f6dc9357SAndroid Build Coastguard Worker public:
CHash()439*f6dc9357SAndroid Build Coastguard Worker   CHash():
440*f6dc9357SAndroid Build Coastguard Worker     _buf(sizeof(CBlake2sp))
441*f6dc9357SAndroid Build Coastguard Worker     {}
442*f6dc9357SAndroid Build Coastguard Worker 
Init_NoCalc()443*f6dc9357SAndroid Build Coastguard Worker   void Init_NoCalc()
444*f6dc9357SAndroid Build Coastguard Worker   {
445*f6dc9357SAndroid Build Coastguard Worker     _calcCRC = false;
446*f6dc9357SAndroid Build Coastguard Worker     _crc = CRC_INIT_VAL;
447*f6dc9357SAndroid Build Coastguard Worker     _blakeOffset = -1;
448*f6dc9357SAndroid Build Coastguard Worker   }
449*f6dc9357SAndroid Build Coastguard Worker 
450*f6dc9357SAndroid Build Coastguard Worker   void Init(const CItem &item);
451*f6dc9357SAndroid Build Coastguard Worker   void Update(const void *data, size_t size);
GetCRC() const452*f6dc9357SAndroid Build Coastguard Worker   UInt32 GetCRC() const { return CRC_GET_DIGEST(_crc); }
453*f6dc9357SAndroid Build Coastguard Worker 
454*f6dc9357SAndroid Build Coastguard Worker   bool Check(const CItem &item, NCrypto::NRar5::CDecoder *cryptoDecoder);
455*f6dc9357SAndroid Build Coastguard Worker };
456*f6dc9357SAndroid Build Coastguard Worker 
Init(const CItem & item)457*f6dc9357SAndroid Build Coastguard Worker void CHash::Init(const CItem &item)
458*f6dc9357SAndroid Build Coastguard Worker {
459*f6dc9357SAndroid Build Coastguard Worker   _crc = CRC_INIT_VAL;
460*f6dc9357SAndroid Build Coastguard Worker   _calcCRC = item.Has_CRC();
461*f6dc9357SAndroid Build Coastguard Worker   _blakeOffset = item.FindExtra_Blake();
462*f6dc9357SAndroid Build Coastguard Worker   if (_blakeOffset >= 0)
463*f6dc9357SAndroid Build Coastguard Worker     Blake2sp_Init(BlakeObj());
464*f6dc9357SAndroid Build Coastguard Worker }
465*f6dc9357SAndroid Build Coastguard Worker 
Update(const void * data,size_t size)466*f6dc9357SAndroid Build Coastguard Worker void CHash::Update(const void *data, size_t size)
467*f6dc9357SAndroid Build Coastguard Worker {
468*f6dc9357SAndroid Build Coastguard Worker   if (_calcCRC)
469*f6dc9357SAndroid Build Coastguard Worker     _crc = CrcUpdate(_crc, data, size);
470*f6dc9357SAndroid Build Coastguard Worker   if (_blakeOffset >= 0)
471*f6dc9357SAndroid Build Coastguard Worker     Blake2sp_Update(BlakeObj(), (const Byte *)data, size);
472*f6dc9357SAndroid Build Coastguard Worker }
473*f6dc9357SAndroid Build Coastguard Worker 
Check(const CItem & item,NCrypto::NRar5::CDecoder * cryptoDecoder)474*f6dc9357SAndroid Build Coastguard Worker bool CHash::Check(const CItem &item, NCrypto::NRar5::CDecoder *cryptoDecoder)
475*f6dc9357SAndroid Build Coastguard Worker {
476*f6dc9357SAndroid Build Coastguard Worker   if (_calcCRC)
477*f6dc9357SAndroid Build Coastguard Worker   {
478*f6dc9357SAndroid Build Coastguard Worker     UInt32 crc = GetCRC();
479*f6dc9357SAndroid Build Coastguard Worker     if (cryptoDecoder)
480*f6dc9357SAndroid Build Coastguard Worker       crc = cryptoDecoder->Hmac_Convert_Crc32(crc);
481*f6dc9357SAndroid Build Coastguard Worker     if (crc != item.CRC)
482*f6dc9357SAndroid Build Coastguard Worker       return false;
483*f6dc9357SAndroid Build Coastguard Worker   }
484*f6dc9357SAndroid Build Coastguard Worker   if (_blakeOffset >= 0)
485*f6dc9357SAndroid Build Coastguard Worker   {
486*f6dc9357SAndroid Build Coastguard Worker     UInt32 digest[Z7_BLAKE2S_DIGEST_SIZE / sizeof(UInt32)];
487*f6dc9357SAndroid Build Coastguard Worker     Blake2sp_Final(BlakeObj(), (Byte *)(void *)digest);
488*f6dc9357SAndroid Build Coastguard Worker     if (cryptoDecoder)
489*f6dc9357SAndroid Build Coastguard Worker       cryptoDecoder->Hmac_Convert_32Bytes((Byte *)(void *)digest);
490*f6dc9357SAndroid Build Coastguard Worker     if (memcmp(digest, item.Extra + (unsigned)_blakeOffset, Z7_BLAKE2S_DIGEST_SIZE) != 0)
491*f6dc9357SAndroid Build Coastguard Worker       return false;
492*f6dc9357SAndroid Build Coastguard Worker   }
493*f6dc9357SAndroid Build Coastguard Worker   return true;
494*f6dc9357SAndroid Build Coastguard Worker }
495*f6dc9357SAndroid Build Coastguard Worker 
496*f6dc9357SAndroid Build Coastguard Worker 
497*f6dc9357SAndroid Build Coastguard Worker Z7_CLASS_IMP_NOQIB_1(
498*f6dc9357SAndroid Build Coastguard Worker   COutStreamWithHash
499*f6dc9357SAndroid Build Coastguard Worker   , ISequentialOutStream
500*f6dc9357SAndroid Build Coastguard Worker )
501*f6dc9357SAndroid Build Coastguard Worker   bool _size_Defined;
502*f6dc9357SAndroid Build Coastguard Worker   ISequentialOutStream *_stream;
503*f6dc9357SAndroid Build Coastguard Worker   UInt64 _pos;
504*f6dc9357SAndroid Build Coastguard Worker   UInt64 _size;
505*f6dc9357SAndroid Build Coastguard Worker   Byte *_destBuf;
506*f6dc9357SAndroid Build Coastguard Worker public:
507*f6dc9357SAndroid Build Coastguard Worker   CHash _hash;
508*f6dc9357SAndroid Build Coastguard Worker 
509*f6dc9357SAndroid Build Coastguard Worker   COutStreamWithHash(): _destBuf(NULL) {}
510*f6dc9357SAndroid Build Coastguard Worker 
511*f6dc9357SAndroid Build Coastguard Worker   void SetStream(ISequentialOutStream *stream) { _stream = stream; }
512*f6dc9357SAndroid Build Coastguard Worker   void Init(const CItem &item, Byte *destBuf, bool needChecksumCheck)
513*f6dc9357SAndroid Build Coastguard Worker   {
514*f6dc9357SAndroid Build Coastguard Worker     _size_Defined = false;
515*f6dc9357SAndroid Build Coastguard Worker     _size = 0;
516*f6dc9357SAndroid Build Coastguard Worker     _destBuf = NULL;
517*f6dc9357SAndroid Build Coastguard Worker     if (!item.Is_UnknownSize())
518*f6dc9357SAndroid Build Coastguard Worker     {
519*f6dc9357SAndroid Build Coastguard Worker       _size_Defined = true;
520*f6dc9357SAndroid Build Coastguard Worker       _size = item.Size;
521*f6dc9357SAndroid Build Coastguard Worker       _destBuf = destBuf;
522*f6dc9357SAndroid Build Coastguard Worker     }
523*f6dc9357SAndroid Build Coastguard Worker     _pos = 0;
524*f6dc9357SAndroid Build Coastguard Worker     if (needChecksumCheck)
525*f6dc9357SAndroid Build Coastguard Worker       _hash.Init(item);
526*f6dc9357SAndroid Build Coastguard Worker     else
527*f6dc9357SAndroid Build Coastguard Worker       _hash.Init_NoCalc();
528*f6dc9357SAndroid Build Coastguard Worker   }
529*f6dc9357SAndroid Build Coastguard Worker   UInt64 GetPos() const { return _pos; }
530*f6dc9357SAndroid Build Coastguard Worker };
531*f6dc9357SAndroid Build Coastguard Worker 
532*f6dc9357SAndroid Build Coastguard Worker 
533*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(COutStreamWithHash::Write(const void *data, UInt32 size, UInt32 *processedSize))
534*f6dc9357SAndroid Build Coastguard Worker {
535*f6dc9357SAndroid Build Coastguard Worker   HRESULT result = S_OK;
536*f6dc9357SAndroid Build Coastguard Worker   if (_size_Defined)
537*f6dc9357SAndroid Build Coastguard Worker   {
538*f6dc9357SAndroid Build Coastguard Worker     const UInt64 rem = _size - _pos;
539*f6dc9357SAndroid Build Coastguard Worker     if (size > rem)
540*f6dc9357SAndroid Build Coastguard Worker       size = (UInt32)rem;
541*f6dc9357SAndroid Build Coastguard Worker   }
542*f6dc9357SAndroid Build Coastguard Worker   if (_stream)
543*f6dc9357SAndroid Build Coastguard Worker     result = _stream->Write(data, size, &size);
544*f6dc9357SAndroid Build Coastguard Worker   if (_destBuf)
545*f6dc9357SAndroid Build Coastguard Worker     memcpy(_destBuf + (size_t)_pos, data, size);
546*f6dc9357SAndroid Build Coastguard Worker   _hash.Update(data, size);
547*f6dc9357SAndroid Build Coastguard Worker   _pos += size;
548*f6dc9357SAndroid Build Coastguard Worker   if (processedSize)
549*f6dc9357SAndroid Build Coastguard Worker     *processedSize = size;
550*f6dc9357SAndroid Build Coastguard Worker   return result;
551*f6dc9357SAndroid Build Coastguard Worker }
552*f6dc9357SAndroid Build Coastguard Worker 
553*f6dc9357SAndroid Build Coastguard Worker 
554*f6dc9357SAndroid Build Coastguard Worker 
555*f6dc9357SAndroid Build Coastguard Worker 
556*f6dc9357SAndroid Build Coastguard Worker 
557*f6dc9357SAndroid Build Coastguard Worker class CInArchive
558*f6dc9357SAndroid Build Coastguard Worker {
559*f6dc9357SAndroid Build Coastguard Worker   CAlignedBuffer _buf;
560*f6dc9357SAndroid Build Coastguard Worker   size_t _bufSize;
561*f6dc9357SAndroid Build Coastguard Worker   size_t _bufPos;
562*f6dc9357SAndroid Build Coastguard Worker   ISequentialInStream *_stream;
563*f6dc9357SAndroid Build Coastguard Worker 
564*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2<ICompressFilter, NCrypto::NRar5::CDecoder> m_CryptoDecoder;
565*f6dc9357SAndroid Build Coastguard Worker 
566*f6dc9357SAndroid Build Coastguard Worker   Z7_CLASS_NO_COPY(CInArchive)
567*f6dc9357SAndroid Build Coastguard Worker 
568*f6dc9357SAndroid Build Coastguard Worker   HRESULT ReadStream_Check(void *data, size_t size);
569*f6dc9357SAndroid Build Coastguard Worker 
570*f6dc9357SAndroid Build Coastguard Worker public:
571*f6dc9357SAndroid Build Coastguard Worker   bool m_CryptoMode;
572*f6dc9357SAndroid Build Coastguard Worker 
573*f6dc9357SAndroid Build Coastguard Worker   bool WrongPassword;
574*f6dc9357SAndroid Build Coastguard Worker   bool IsArc;
575*f6dc9357SAndroid Build Coastguard Worker   bool UnexpectedEnd;
576*f6dc9357SAndroid Build Coastguard Worker 
577*f6dc9357SAndroid Build Coastguard Worker   UInt64 StreamStartPosition;
578*f6dc9357SAndroid Build Coastguard Worker   UInt64 Position;
579*f6dc9357SAndroid Build Coastguard Worker 
580*f6dc9357SAndroid Build Coastguard Worker   size_t Get_Buf_RemainSize() const { return _bufSize - _bufPos; }
581*f6dc9357SAndroid Build Coastguard Worker   bool Is_Buf_Finished() const { return _bufPos == _bufSize; }
582*f6dc9357SAndroid Build Coastguard Worker   const Byte *Get_Buf_Data() const { return _buf + _bufPos; }
583*f6dc9357SAndroid Build Coastguard Worker   void Move_BufPos(size_t num) { _bufPos += num; }
584*f6dc9357SAndroid Build Coastguard Worker   bool ReadVar(UInt64 &val);
585*f6dc9357SAndroid Build Coastguard Worker 
586*f6dc9357SAndroid Build Coastguard Worker   struct CHeader
587*f6dc9357SAndroid Build Coastguard Worker   {
588*f6dc9357SAndroid Build Coastguard Worker     UInt64 Type;
589*f6dc9357SAndroid Build Coastguard Worker     UInt64 Flags;
590*f6dc9357SAndroid Build Coastguard Worker     size_t ExtraSize;
591*f6dc9357SAndroid Build Coastguard Worker     UInt64 DataSize;
592*f6dc9357SAndroid Build Coastguard Worker   };
593*f6dc9357SAndroid Build Coastguard Worker 
594*f6dc9357SAndroid Build Coastguard Worker   CInArchive() {}
595*f6dc9357SAndroid Build Coastguard Worker 
596*f6dc9357SAndroid Build Coastguard Worker   HRESULT ReadBlockHeader(CHeader &h);
597*f6dc9357SAndroid Build Coastguard Worker   bool ReadFileHeader(const CHeader &header, CItem &item);
598*f6dc9357SAndroid Build Coastguard Worker   void AddToSeekValue(UInt64 addValue)
599*f6dc9357SAndroid Build Coastguard Worker   {
600*f6dc9357SAndroid Build Coastguard Worker     Position += addValue;
601*f6dc9357SAndroid Build Coastguard Worker   }
602*f6dc9357SAndroid Build Coastguard Worker 
603*f6dc9357SAndroid Build Coastguard Worker   HRESULT Open(IInStream *inStream, const UInt64 *searchHeaderSizeLimit, ICryptoGetTextPassword *getTextPassword,
604*f6dc9357SAndroid Build Coastguard Worker       CInArcInfo &info);
605*f6dc9357SAndroid Build Coastguard Worker };
606*f6dc9357SAndroid Build Coastguard Worker 
607*f6dc9357SAndroid Build Coastguard Worker 
608*f6dc9357SAndroid Build Coastguard Worker static HRESULT MySetPassword(ICryptoGetTextPassword *getTextPassword, NCrypto::NRar5::CDecoder *cryptoDecoder)
609*f6dc9357SAndroid Build Coastguard Worker {
610*f6dc9357SAndroid Build Coastguard Worker   CMyComBSTR_Wipe password;
611*f6dc9357SAndroid Build Coastguard Worker   RINOK(getTextPassword->CryptoGetTextPassword(&password))
612*f6dc9357SAndroid Build Coastguard Worker   AString_Wipe utf8;
613*f6dc9357SAndroid Build Coastguard Worker   const unsigned kPasswordLen_MAX = 127;
614*f6dc9357SAndroid Build Coastguard Worker   UString_Wipe unicode;
615*f6dc9357SAndroid Build Coastguard Worker   unicode.SetFromBstr(password);
616*f6dc9357SAndroid Build Coastguard Worker   if (unicode.Len() > kPasswordLen_MAX)
617*f6dc9357SAndroid Build Coastguard Worker     unicode.DeleteFrom(kPasswordLen_MAX);
618*f6dc9357SAndroid Build Coastguard Worker   ConvertUnicodeToUTF8(unicode, utf8);
619*f6dc9357SAndroid Build Coastguard Worker   cryptoDecoder->SetPassword((const Byte *)(const char *)utf8, utf8.Len());
620*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
621*f6dc9357SAndroid Build Coastguard Worker }
622*f6dc9357SAndroid Build Coastguard Worker 
623*f6dc9357SAndroid Build Coastguard Worker 
624*f6dc9357SAndroid Build Coastguard Worker bool CInArchive::ReadVar(UInt64 &val)
625*f6dc9357SAndroid Build Coastguard Worker {
626*f6dc9357SAndroid Build Coastguard Worker   const unsigned offset = ReadVarInt(Get_Buf_Data(), Get_Buf_RemainSize(), &val);
627*f6dc9357SAndroid Build Coastguard Worker   Move_BufPos(offset);
628*f6dc9357SAndroid Build Coastguard Worker   return (offset != 0);
629*f6dc9357SAndroid Build Coastguard Worker }
630*f6dc9357SAndroid Build Coastguard Worker 
631*f6dc9357SAndroid Build Coastguard Worker 
632*f6dc9357SAndroid Build Coastguard Worker HRESULT CInArchive::ReadStream_Check(void *data, size_t size)
633*f6dc9357SAndroid Build Coastguard Worker {
634*f6dc9357SAndroid Build Coastguard Worker   size_t size2 = size;
635*f6dc9357SAndroid Build Coastguard Worker   RINOK(ReadStream(_stream, data, &size2))
636*f6dc9357SAndroid Build Coastguard Worker   if (size2 == size)
637*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
638*f6dc9357SAndroid Build Coastguard Worker   UnexpectedEnd = true;
639*f6dc9357SAndroid Build Coastguard Worker   return S_FALSE;
640*f6dc9357SAndroid Build Coastguard Worker }
641*f6dc9357SAndroid Build Coastguard Worker 
642*f6dc9357SAndroid Build Coastguard Worker 
643*f6dc9357SAndroid Build Coastguard Worker HRESULT CInArchive::ReadBlockHeader(CHeader &h)
644*f6dc9357SAndroid Build Coastguard Worker {
645*f6dc9357SAndroid Build Coastguard Worker   h.Type = 0;
646*f6dc9357SAndroid Build Coastguard Worker   h.Flags = 0;
647*f6dc9357SAndroid Build Coastguard Worker   h.ExtraSize = 0;
648*f6dc9357SAndroid Build Coastguard Worker   h.DataSize = 0;
649*f6dc9357SAndroid Build Coastguard Worker 
650*f6dc9357SAndroid Build Coastguard Worker   Byte buf[AES_BLOCK_SIZE];
651*f6dc9357SAndroid Build Coastguard Worker   unsigned filled;
652*f6dc9357SAndroid Build Coastguard Worker 
653*f6dc9357SAndroid Build Coastguard Worker   if (m_CryptoMode)
654*f6dc9357SAndroid Build Coastguard Worker   {
655*f6dc9357SAndroid Build Coastguard Worker     _buf.AllocAtLeast(1 << 12); // at least (AES_BLOCK_SIZE * 2)
656*f6dc9357SAndroid Build Coastguard Worker     if (!(Byte *)_buf)
657*f6dc9357SAndroid Build Coastguard Worker       return E_OUTOFMEMORY;
658*f6dc9357SAndroid Build Coastguard Worker     RINOK(ReadStream_Check(_buf, AES_BLOCK_SIZE * 2))
659*f6dc9357SAndroid Build Coastguard Worker     memcpy(m_CryptoDecoder->_iv, _buf, AES_BLOCK_SIZE);
660*f6dc9357SAndroid Build Coastguard Worker     RINOK(m_CryptoDecoder->Init())
661*f6dc9357SAndroid Build Coastguard Worker     // we call RAR5_AES_Filter with:
662*f6dc9357SAndroid Build Coastguard Worker     //   data_ptr  == aligned_ptr + 16
663*f6dc9357SAndroid Build Coastguard Worker     //   data_size == 16
664*f6dc9357SAndroid Build Coastguard Worker     if (m_CryptoDecoder->Filter(_buf + AES_BLOCK_SIZE, AES_BLOCK_SIZE) != AES_BLOCK_SIZE)
665*f6dc9357SAndroid Build Coastguard Worker       return E_FAIL;
666*f6dc9357SAndroid Build Coastguard Worker     memcpy(buf, _buf + AES_BLOCK_SIZE, AES_BLOCK_SIZE);
667*f6dc9357SAndroid Build Coastguard Worker     filled = AES_BLOCK_SIZE;
668*f6dc9357SAndroid Build Coastguard Worker   }
669*f6dc9357SAndroid Build Coastguard Worker   else
670*f6dc9357SAndroid Build Coastguard Worker   {
671*f6dc9357SAndroid Build Coastguard Worker     const unsigned kStartSize = 4 + 3;
672*f6dc9357SAndroid Build Coastguard Worker     RINOK(ReadStream_Check(buf, kStartSize))
673*f6dc9357SAndroid Build Coastguard Worker     filled = kStartSize;
674*f6dc9357SAndroid Build Coastguard Worker   }
675*f6dc9357SAndroid Build Coastguard Worker 
676*f6dc9357SAndroid Build Coastguard Worker   {
677*f6dc9357SAndroid Build Coastguard Worker     UInt64 val;
678*f6dc9357SAndroid Build Coastguard Worker     unsigned offset = ReadVarInt(buf + 4, 3, &val);
679*f6dc9357SAndroid Build Coastguard Worker     if (offset == 0)
680*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
681*f6dc9357SAndroid Build Coastguard Worker     size_t size = (size_t)val;
682*f6dc9357SAndroid Build Coastguard Worker     if (size < 2)
683*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
684*f6dc9357SAndroid Build Coastguard Worker     offset += 4;
685*f6dc9357SAndroid Build Coastguard Worker     _bufPos = offset;
686*f6dc9357SAndroid Build Coastguard Worker     size += offset;
687*f6dc9357SAndroid Build Coastguard Worker     _bufSize = size;
688*f6dc9357SAndroid Build Coastguard Worker     if (m_CryptoMode)
689*f6dc9357SAndroid Build Coastguard Worker       size = (size + AES_BLOCK_SIZE - 1) & ~(size_t)(AES_BLOCK_SIZE - 1);
690*f6dc9357SAndroid Build Coastguard Worker     _buf.AllocAtLeast(size);
691*f6dc9357SAndroid Build Coastguard Worker     if (!(Byte *)_buf)
692*f6dc9357SAndroid Build Coastguard Worker       return E_OUTOFMEMORY;
693*f6dc9357SAndroid Build Coastguard Worker     memcpy(_buf, buf, filled);
694*f6dc9357SAndroid Build Coastguard Worker     const size_t rem = size - filled;
695*f6dc9357SAndroid Build Coastguard Worker     // if (m_CryptoMode), we add AES_BLOCK_SIZE here, because _iv is not included to size.
696*f6dc9357SAndroid Build Coastguard Worker     AddToSeekValue(size + (m_CryptoMode ? AES_BLOCK_SIZE : 0));
697*f6dc9357SAndroid Build Coastguard Worker     RINOK(ReadStream_Check(_buf + filled, rem))
698*f6dc9357SAndroid Build Coastguard Worker     if (m_CryptoMode)
699*f6dc9357SAndroid Build Coastguard Worker     {
700*f6dc9357SAndroid Build Coastguard Worker       // we call RAR5_AES_Filter with:
701*f6dc9357SAndroid Build Coastguard Worker       //   data_ptr  == aligned_ptr + 16
702*f6dc9357SAndroid Build Coastguard Worker       //   (rem) can be big
703*f6dc9357SAndroid Build Coastguard Worker       if (m_CryptoDecoder->Filter(_buf + filled, (UInt32)rem) != rem)
704*f6dc9357SAndroid Build Coastguard Worker         return E_FAIL;
705*f6dc9357SAndroid Build Coastguard Worker #if 1
706*f6dc9357SAndroid Build Coastguard Worker       // optional 7zip-unrar check : remainder must contain zeros.
707*f6dc9357SAndroid Build Coastguard Worker       const size_t pad = size - _bufSize;
708*f6dc9357SAndroid Build Coastguard Worker       const Byte *p = _buf + _bufSize;
709*f6dc9357SAndroid Build Coastguard Worker       for (size_t i = 0; i < pad; i++)
710*f6dc9357SAndroid Build Coastguard Worker         if (p[i])
711*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
712*f6dc9357SAndroid Build Coastguard Worker #endif
713*f6dc9357SAndroid Build Coastguard Worker     }
714*f6dc9357SAndroid Build Coastguard Worker   }
715*f6dc9357SAndroid Build Coastguard Worker 
716*f6dc9357SAndroid Build Coastguard Worker   if (CrcCalc(_buf + 4, _bufSize - 4) != Get32(buf))
717*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
718*f6dc9357SAndroid Build Coastguard Worker 
719*f6dc9357SAndroid Build Coastguard Worker   if (!ReadVar(h.Type)) return S_FALSE;
720*f6dc9357SAndroid Build Coastguard Worker   if (!ReadVar(h.Flags)) return S_FALSE;
721*f6dc9357SAndroid Build Coastguard Worker 
722*f6dc9357SAndroid Build Coastguard Worker   if (h.Flags & NHeaderFlags::kExtra)
723*f6dc9357SAndroid Build Coastguard Worker   {
724*f6dc9357SAndroid Build Coastguard Worker     UInt64 extraSize;
725*f6dc9357SAndroid Build Coastguard Worker     if (!ReadVar(extraSize))
726*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
727*f6dc9357SAndroid Build Coastguard Worker     if (extraSize >= (1u << 21))
728*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
729*f6dc9357SAndroid Build Coastguard Worker     h.ExtraSize = (size_t)extraSize;
730*f6dc9357SAndroid Build Coastguard Worker   }
731*f6dc9357SAndroid Build Coastguard Worker 
732*f6dc9357SAndroid Build Coastguard Worker   if (h.Flags & NHeaderFlags::kData)
733*f6dc9357SAndroid Build Coastguard Worker   {
734*f6dc9357SAndroid Build Coastguard Worker     if (!ReadVar(h.DataSize))
735*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
736*f6dc9357SAndroid Build Coastguard Worker   }
737*f6dc9357SAndroid Build Coastguard Worker 
738*f6dc9357SAndroid Build Coastguard Worker   if (h.ExtraSize > Get_Buf_RemainSize())
739*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
740*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
741*f6dc9357SAndroid Build Coastguard Worker }
742*f6dc9357SAndroid Build Coastguard Worker 
743*f6dc9357SAndroid Build Coastguard Worker 
744*f6dc9357SAndroid Build Coastguard Worker bool CInArcInfo::CLocator::Parse(const Byte *p, size_t size)
745*f6dc9357SAndroid Build Coastguard Worker {
746*f6dc9357SAndroid Build Coastguard Worker   Flags = 0;
747*f6dc9357SAndroid Build Coastguard Worker   QuickOpen = 0;
748*f6dc9357SAndroid Build Coastguard Worker   Recovery = 0;
749*f6dc9357SAndroid Build Coastguard Worker 
750*f6dc9357SAndroid Build Coastguard Worker   PARSE_VAR_INT(p, size, Flags)
751*f6dc9357SAndroid Build Coastguard Worker 
752*f6dc9357SAndroid Build Coastguard Worker   if (Is_QuickOpen())
753*f6dc9357SAndroid Build Coastguard Worker   {
754*f6dc9357SAndroid Build Coastguard Worker     PARSE_VAR_INT(p, size, QuickOpen)
755*f6dc9357SAndroid Build Coastguard Worker   }
756*f6dc9357SAndroid Build Coastguard Worker   if (Is_Recovery())
757*f6dc9357SAndroid Build Coastguard Worker   {
758*f6dc9357SAndroid Build Coastguard Worker     PARSE_VAR_INT(p, size, Recovery)
759*f6dc9357SAndroid Build Coastguard Worker   }
760*f6dc9357SAndroid Build Coastguard Worker #if 0
761*f6dc9357SAndroid Build Coastguard Worker   // another records are possible in future rar formats.
762*f6dc9357SAndroid Build Coastguard Worker   if (size != 0)
763*f6dc9357SAndroid Build Coastguard Worker     return false;
764*f6dc9357SAndroid Build Coastguard Worker #endif
765*f6dc9357SAndroid Build Coastguard Worker   return true;
766*f6dc9357SAndroid Build Coastguard Worker }
767*f6dc9357SAndroid Build Coastguard Worker 
768*f6dc9357SAndroid Build Coastguard Worker 
769*f6dc9357SAndroid Build Coastguard Worker bool CInArcInfo::CMetadata::Parse(const Byte *p, size_t size)
770*f6dc9357SAndroid Build Coastguard Worker {
771*f6dc9357SAndroid Build Coastguard Worker   PARSE_VAR_INT(p, size, Flags)
772*f6dc9357SAndroid Build Coastguard Worker   if (Flags & NMetadataFlags::kArcName)
773*f6dc9357SAndroid Build Coastguard Worker   {
774*f6dc9357SAndroid Build Coastguard Worker     UInt64 nameLen;
775*f6dc9357SAndroid Build Coastguard Worker     PARSE_VAR_INT(p, size, nameLen)
776*f6dc9357SAndroid Build Coastguard Worker     if (nameLen > size)
777*f6dc9357SAndroid Build Coastguard Worker       return false;
778*f6dc9357SAndroid Build Coastguard Worker     ArcName.SetFrom_CalcLen((const char *)(const void *)p, (unsigned)nameLen);
779*f6dc9357SAndroid Build Coastguard Worker     p += (size_t)nameLen;
780*f6dc9357SAndroid Build Coastguard Worker     size -= (size_t)nameLen;
781*f6dc9357SAndroid Build Coastguard Worker   }
782*f6dc9357SAndroid Build Coastguard Worker   if (Flags & NMetadataFlags::kCTime)
783*f6dc9357SAndroid Build Coastguard Worker   {
784*f6dc9357SAndroid Build Coastguard Worker     if ((Flags & NMetadataFlags::kUnixTime) &&
785*f6dc9357SAndroid Build Coastguard Worker         (Flags & NMetadataFlags::kNanoSec) == 0)
786*f6dc9357SAndroid Build Coastguard Worker     {
787*f6dc9357SAndroid Build Coastguard Worker       if (size < 4)
788*f6dc9357SAndroid Build Coastguard Worker         return false;
789*f6dc9357SAndroid Build Coastguard Worker       CTime = GetUi32(p);
790*f6dc9357SAndroid Build Coastguard Worker       p += 4;
791*f6dc9357SAndroid Build Coastguard Worker       size -= 4;
792*f6dc9357SAndroid Build Coastguard Worker     }
793*f6dc9357SAndroid Build Coastguard Worker     else
794*f6dc9357SAndroid Build Coastguard Worker     {
795*f6dc9357SAndroid Build Coastguard Worker       if (size < 8)
796*f6dc9357SAndroid Build Coastguard Worker         return false;
797*f6dc9357SAndroid Build Coastguard Worker       CTime = GetUi64(p);
798*f6dc9357SAndroid Build Coastguard Worker       p += 8;
799*f6dc9357SAndroid Build Coastguard Worker       size -= 8;
800*f6dc9357SAndroid Build Coastguard Worker     }
801*f6dc9357SAndroid Build Coastguard Worker   }
802*f6dc9357SAndroid Build Coastguard Worker #if 0
803*f6dc9357SAndroid Build Coastguard Worker   // another records are possible in future rar formats.
804*f6dc9357SAndroid Build Coastguard Worker   if (size != 0)
805*f6dc9357SAndroid Build Coastguard Worker     return false;
806*f6dc9357SAndroid Build Coastguard Worker #endif
807*f6dc9357SAndroid Build Coastguard Worker   return true;
808*f6dc9357SAndroid Build Coastguard Worker }
809*f6dc9357SAndroid Build Coastguard Worker 
810*f6dc9357SAndroid Build Coastguard Worker 
811*f6dc9357SAndroid Build Coastguard Worker bool CInArcInfo::ParseExtra(const Byte *p, size_t size)
812*f6dc9357SAndroid Build Coastguard Worker {
813*f6dc9357SAndroid Build Coastguard Worker   for (;;)
814*f6dc9357SAndroid Build Coastguard Worker   {
815*f6dc9357SAndroid Build Coastguard Worker     if (size == 0)
816*f6dc9357SAndroid Build Coastguard Worker       return true;
817*f6dc9357SAndroid Build Coastguard Worker     UInt64 recSize64, id;
818*f6dc9357SAndroid Build Coastguard Worker     PARSE_VAR_INT(p, size, recSize64)
819*f6dc9357SAndroid Build Coastguard Worker     if (recSize64 > size)
820*f6dc9357SAndroid Build Coastguard Worker       return false;
821*f6dc9357SAndroid Build Coastguard Worker     size_t recSize = (size_t)recSize64;
822*f6dc9357SAndroid Build Coastguard Worker     size -= recSize;
823*f6dc9357SAndroid Build Coastguard Worker     // READ_VAR_INT(p, recSize, recSize)
824*f6dc9357SAndroid Build Coastguard Worker     {
825*f6dc9357SAndroid Build Coastguard Worker       const unsigned num = ReadVarInt(p, recSize, &id);
826*f6dc9357SAndroid Build Coastguard Worker       if (num == 0)
827*f6dc9357SAndroid Build Coastguard Worker         return false;
828*f6dc9357SAndroid Build Coastguard Worker       p += num;
829*f6dc9357SAndroid Build Coastguard Worker       recSize -= num;
830*f6dc9357SAndroid Build Coastguard Worker     }
831*f6dc9357SAndroid Build Coastguard Worker     if (id == kArcExtraRecordType_Metadata)
832*f6dc9357SAndroid Build Coastguard Worker     {
833*f6dc9357SAndroid Build Coastguard Worker       Metadata_Defined = true;
834*f6dc9357SAndroid Build Coastguard Worker       if (!Metadata.Parse(p, recSize))
835*f6dc9357SAndroid Build Coastguard Worker         Metadata_Error = true;
836*f6dc9357SAndroid Build Coastguard Worker     }
837*f6dc9357SAndroid Build Coastguard Worker     else if (id == kArcExtraRecordType_Locator)
838*f6dc9357SAndroid Build Coastguard Worker     {
839*f6dc9357SAndroid Build Coastguard Worker       Locator_Defined = true;
840*f6dc9357SAndroid Build Coastguard Worker       if (!Locator.Parse(p, recSize))
841*f6dc9357SAndroid Build Coastguard Worker         Locator_Error = true;
842*f6dc9357SAndroid Build Coastguard Worker     }
843*f6dc9357SAndroid Build Coastguard Worker     else
844*f6dc9357SAndroid Build Coastguard Worker       UnknownExtraRecord = true;
845*f6dc9357SAndroid Build Coastguard Worker     p += recSize;
846*f6dc9357SAndroid Build Coastguard Worker   }
847*f6dc9357SAndroid Build Coastguard Worker }
848*f6dc9357SAndroid Build Coastguard Worker 
849*f6dc9357SAndroid Build Coastguard Worker 
850*f6dc9357SAndroid Build Coastguard Worker 
851*f6dc9357SAndroid Build Coastguard Worker HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit, ICryptoGetTextPassword *getTextPassword,
852*f6dc9357SAndroid Build Coastguard Worker     CInArcInfo &info)
853*f6dc9357SAndroid Build Coastguard Worker {
854*f6dc9357SAndroid Build Coastguard Worker   m_CryptoMode = false;
855*f6dc9357SAndroid Build Coastguard Worker 
856*f6dc9357SAndroid Build Coastguard Worker   WrongPassword = false;
857*f6dc9357SAndroid Build Coastguard Worker   IsArc = false;
858*f6dc9357SAndroid Build Coastguard Worker   UnexpectedEnd = false;
859*f6dc9357SAndroid Build Coastguard Worker 
860*f6dc9357SAndroid Build Coastguard Worker   Position = StreamStartPosition;
861*f6dc9357SAndroid Build Coastguard Worker 
862*f6dc9357SAndroid Build Coastguard Worker   UInt64 arcStartPos = StreamStartPosition;
863*f6dc9357SAndroid Build Coastguard Worker   {
864*f6dc9357SAndroid Build Coastguard Worker     Byte marker[kMarkerSize];
865*f6dc9357SAndroid Build Coastguard Worker     RINOK(ReadStream_FALSE(stream, marker, kMarkerSize))
866*f6dc9357SAndroid Build Coastguard Worker     if (memcmp(marker, kMarker, kMarkerSize) == 0)
867*f6dc9357SAndroid Build Coastguard Worker       Position += kMarkerSize;
868*f6dc9357SAndroid Build Coastguard Worker     else
869*f6dc9357SAndroid Build Coastguard Worker     {
870*f6dc9357SAndroid Build Coastguard Worker       if (searchHeaderSizeLimit && *searchHeaderSizeLimit == 0)
871*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
872*f6dc9357SAndroid Build Coastguard Worker       RINOK(InStream_SeekSet(stream, StreamStartPosition))
873*f6dc9357SAndroid Build Coastguard Worker       RINOK(FindSignatureInStream(stream, kMarker, kMarkerSize,
874*f6dc9357SAndroid Build Coastguard Worker           searchHeaderSizeLimit, arcStartPos))
875*f6dc9357SAndroid Build Coastguard Worker       arcStartPos += StreamStartPosition;
876*f6dc9357SAndroid Build Coastguard Worker       Position = arcStartPos + kMarkerSize;
877*f6dc9357SAndroid Build Coastguard Worker       RINOK(InStream_SeekSet(stream, Position))
878*f6dc9357SAndroid Build Coastguard Worker     }
879*f6dc9357SAndroid Build Coastguard Worker   }
880*f6dc9357SAndroid Build Coastguard Worker 
881*f6dc9357SAndroid Build Coastguard Worker   info.StartPos = arcStartPos;
882*f6dc9357SAndroid Build Coastguard Worker   _stream = stream;
883*f6dc9357SAndroid Build Coastguard Worker 
884*f6dc9357SAndroid Build Coastguard Worker   CHeader h;
885*f6dc9357SAndroid Build Coastguard Worker   RINOK(ReadBlockHeader(h))
886*f6dc9357SAndroid Build Coastguard Worker   info.IsEncrypted = false;
887*f6dc9357SAndroid Build Coastguard Worker 
888*f6dc9357SAndroid Build Coastguard Worker   if (h.Type == NHeaderType::kArcEncrypt)
889*f6dc9357SAndroid Build Coastguard Worker   {
890*f6dc9357SAndroid Build Coastguard Worker     info.IsEncrypted = true;
891*f6dc9357SAndroid Build Coastguard Worker     IsArc = true;
892*f6dc9357SAndroid Build Coastguard Worker     if (!getTextPassword)
893*f6dc9357SAndroid Build Coastguard Worker       return E_NOTIMPL;
894*f6dc9357SAndroid Build Coastguard Worker     m_CryptoMode = true;
895*f6dc9357SAndroid Build Coastguard Worker     m_CryptoDecoder.Create_if_Empty();
896*f6dc9357SAndroid Build Coastguard Worker     RINOK(m_CryptoDecoder->SetDecoderProps(
897*f6dc9357SAndroid Build Coastguard Worker         Get_Buf_Data(), (unsigned)Get_Buf_RemainSize(), false, false))
898*f6dc9357SAndroid Build Coastguard Worker     RINOK(MySetPassword(getTextPassword, m_CryptoDecoder.ClsPtr()))
899*f6dc9357SAndroid Build Coastguard Worker     if (!m_CryptoDecoder->CalcKey_and_CheckPassword())
900*f6dc9357SAndroid Build Coastguard Worker     {
901*f6dc9357SAndroid Build Coastguard Worker       WrongPassword = True;
902*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
903*f6dc9357SAndroid Build Coastguard Worker     }
904*f6dc9357SAndroid Build Coastguard Worker     RINOK(ReadBlockHeader(h))
905*f6dc9357SAndroid Build Coastguard Worker   }
906*f6dc9357SAndroid Build Coastguard Worker 
907*f6dc9357SAndroid Build Coastguard Worker   if (h.Type != NHeaderType::kArc)
908*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
909*f6dc9357SAndroid Build Coastguard Worker 
910*f6dc9357SAndroid Build Coastguard Worker   IsArc = true;
911*f6dc9357SAndroid Build Coastguard Worker   info.VolNumber = 0;
912*f6dc9357SAndroid Build Coastguard Worker 
913*f6dc9357SAndroid Build Coastguard Worker   if (!ReadVar(info.Flags))
914*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
915*f6dc9357SAndroid Build Coastguard Worker 
916*f6dc9357SAndroid Build Coastguard Worker   if (info.Flags & NArcFlags::kVolNumber)
917*f6dc9357SAndroid Build Coastguard Worker     if (!ReadVar(info.VolNumber))
918*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
919*f6dc9357SAndroid Build Coastguard Worker 
920*f6dc9357SAndroid Build Coastguard Worker   if (h.ExtraSize != Get_Buf_RemainSize())
921*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
922*f6dc9357SAndroid Build Coastguard Worker   if (h.ExtraSize)
923*f6dc9357SAndroid Build Coastguard Worker   {
924*f6dc9357SAndroid Build Coastguard Worker     if (!info.ParseExtra(Get_Buf_Data(), h.ExtraSize))
925*f6dc9357SAndroid Build Coastguard Worker       info.Extra_Error = true;
926*f6dc9357SAndroid Build Coastguard Worker   }
927*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
928*f6dc9357SAndroid Build Coastguard Worker }
929*f6dc9357SAndroid Build Coastguard Worker 
930*f6dc9357SAndroid Build Coastguard Worker 
931*f6dc9357SAndroid Build Coastguard Worker bool CInArchive::ReadFileHeader(const CHeader &header, CItem &item)
932*f6dc9357SAndroid Build Coastguard Worker {
933*f6dc9357SAndroid Build Coastguard Worker   item.CommonFlags = (UInt32)header.Flags;
934*f6dc9357SAndroid Build Coastguard Worker   item.PackSize = header.DataSize;
935*f6dc9357SAndroid Build Coastguard Worker   item.UnixMTime = 0;
936*f6dc9357SAndroid Build Coastguard Worker   item.CRC = 0;
937*f6dc9357SAndroid Build Coastguard Worker 
938*f6dc9357SAndroid Build Coastguard Worker   {
939*f6dc9357SAndroid Build Coastguard Worker     UInt64 flags64;
940*f6dc9357SAndroid Build Coastguard Worker     if (!ReadVar(flags64)) return false;
941*f6dc9357SAndroid Build Coastguard Worker     item.Flags = (UInt32)flags64;
942*f6dc9357SAndroid Build Coastguard Worker   }
943*f6dc9357SAndroid Build Coastguard Worker 
944*f6dc9357SAndroid Build Coastguard Worker   if (!ReadVar(item.Size)) return false;
945*f6dc9357SAndroid Build Coastguard Worker 
946*f6dc9357SAndroid Build Coastguard Worker   {
947*f6dc9357SAndroid Build Coastguard Worker     UInt64 attrib;
948*f6dc9357SAndroid Build Coastguard Worker     if (!ReadVar(attrib)) return false;
949*f6dc9357SAndroid Build Coastguard Worker     item.Attrib = (UInt32)attrib;
950*f6dc9357SAndroid Build Coastguard Worker   }
951*f6dc9357SAndroid Build Coastguard Worker   if (item.Has_UnixMTime())
952*f6dc9357SAndroid Build Coastguard Worker   {
953*f6dc9357SAndroid Build Coastguard Worker     if (Get_Buf_RemainSize() < 4)
954*f6dc9357SAndroid Build Coastguard Worker       return false;
955*f6dc9357SAndroid Build Coastguard Worker     item.UnixMTime = Get32(Get_Buf_Data());
956*f6dc9357SAndroid Build Coastguard Worker     Move_BufPos(4);
957*f6dc9357SAndroid Build Coastguard Worker   }
958*f6dc9357SAndroid Build Coastguard Worker   if (item.Has_CRC())
959*f6dc9357SAndroid Build Coastguard Worker   {
960*f6dc9357SAndroid Build Coastguard Worker     if (Get_Buf_RemainSize() < 4)
961*f6dc9357SAndroid Build Coastguard Worker       return false;
962*f6dc9357SAndroid Build Coastguard Worker     item.CRC = Get32(Get_Buf_Data());
963*f6dc9357SAndroid Build Coastguard Worker     Move_BufPos(4);
964*f6dc9357SAndroid Build Coastguard Worker   }
965*f6dc9357SAndroid Build Coastguard Worker   {
966*f6dc9357SAndroid Build Coastguard Worker     UInt64 method;
967*f6dc9357SAndroid Build Coastguard Worker     if (!ReadVar(method)) return false;
968*f6dc9357SAndroid Build Coastguard Worker     item.Method = (UInt32)method;
969*f6dc9357SAndroid Build Coastguard Worker   }
970*f6dc9357SAndroid Build Coastguard Worker 
971*f6dc9357SAndroid Build Coastguard Worker   if (!ReadVar(item.HostOS)) return false;
972*f6dc9357SAndroid Build Coastguard Worker 
973*f6dc9357SAndroid Build Coastguard Worker   {
974*f6dc9357SAndroid Build Coastguard Worker     UInt64 len;
975*f6dc9357SAndroid Build Coastguard Worker     if (!ReadVar(len)) return false;
976*f6dc9357SAndroid Build Coastguard Worker     if (len > Get_Buf_RemainSize())
977*f6dc9357SAndroid Build Coastguard Worker       return false;
978*f6dc9357SAndroid Build Coastguard Worker     item.Name.SetFrom_CalcLen((const char *)Get_Buf_Data(), (unsigned)len);
979*f6dc9357SAndroid Build Coastguard Worker     Move_BufPos((size_t)len);
980*f6dc9357SAndroid Build Coastguard Worker   }
981*f6dc9357SAndroid Build Coastguard Worker 
982*f6dc9357SAndroid Build Coastguard Worker   item.Extra.Free();
983*f6dc9357SAndroid Build Coastguard Worker   const size_t extraSize = header.ExtraSize;
984*f6dc9357SAndroid Build Coastguard Worker   if (extraSize != 0)
985*f6dc9357SAndroid Build Coastguard Worker   {
986*f6dc9357SAndroid Build Coastguard Worker     if (Get_Buf_RemainSize() < extraSize)
987*f6dc9357SAndroid Build Coastguard Worker       return false;
988*f6dc9357SAndroid Build Coastguard Worker     item.Extra.Alloc(extraSize);
989*f6dc9357SAndroid Build Coastguard Worker     memcpy(item.Extra, Get_Buf_Data(), extraSize);
990*f6dc9357SAndroid Build Coastguard Worker     Move_BufPos(extraSize);
991*f6dc9357SAndroid Build Coastguard Worker   }
992*f6dc9357SAndroid Build Coastguard Worker 
993*f6dc9357SAndroid Build Coastguard Worker   return Is_Buf_Finished();
994*f6dc9357SAndroid Build Coastguard Worker }
995*f6dc9357SAndroid Build Coastguard Worker 
996*f6dc9357SAndroid Build Coastguard Worker 
997*f6dc9357SAndroid Build Coastguard Worker 
998*f6dc9357SAndroid Build Coastguard Worker struct CLinkFile
999*f6dc9357SAndroid Build Coastguard Worker {
1000*f6dc9357SAndroid Build Coastguard Worker   unsigned Index;
1001*f6dc9357SAndroid Build Coastguard Worker   unsigned NumLinks; // the number of links to Data
1002*f6dc9357SAndroid Build Coastguard Worker   CByteBuffer Data;
1003*f6dc9357SAndroid Build Coastguard Worker   HRESULT Res;
1004*f6dc9357SAndroid Build Coastguard Worker   bool crcOK;
1005*f6dc9357SAndroid Build Coastguard Worker 
1006*f6dc9357SAndroid Build Coastguard Worker   CLinkFile(): Index(0), NumLinks(0), Res(S_OK), crcOK(true) {}
1007*f6dc9357SAndroid Build Coastguard Worker };
1008*f6dc9357SAndroid Build Coastguard Worker 
1009*f6dc9357SAndroid Build Coastguard Worker 
1010*f6dc9357SAndroid Build Coastguard Worker struct CUnpacker
1011*f6dc9357SAndroid Build Coastguard Worker {
1012*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2<ICompressCoder, NCompress::CCopyCoder> copyCoder;
1013*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<ICompressCoder> LzCoders[2];
1014*f6dc9357SAndroid Build Coastguard Worker   bool SolidAllowed;
1015*f6dc9357SAndroid Build Coastguard Worker   bool NeedCrc;
1016*f6dc9357SAndroid Build Coastguard Worker   CFilterCoder *filterStreamSpec;
1017*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<ISequentialInStream> filterStream;
1018*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2<ICompressFilter, NCrypto::NRar5::CDecoder> cryptoDecoder;
1019*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<ICryptoGetTextPassword> getTextPassword;
1020*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2<ISequentialOutStream, COutStreamWithHash> outStream;
1021*f6dc9357SAndroid Build Coastguard Worker 
1022*f6dc9357SAndroid Build Coastguard Worker   CByteBuffer _tempBuf;
1023*f6dc9357SAndroid Build Coastguard Worker   CLinkFile *linkFile;
1024*f6dc9357SAndroid Build Coastguard Worker 
1025*f6dc9357SAndroid Build Coastguard Worker   CUnpacker(): linkFile(NULL) { SolidAllowed = false; NeedCrc = true; }
1026*f6dc9357SAndroid Build Coastguard Worker 
1027*f6dc9357SAndroid Build Coastguard Worker   HRESULT Create(DECL_EXTERNAL_CODECS_LOC_VARS
1028*f6dc9357SAndroid Build Coastguard Worker       const CItem &item, bool isSolid, bool &wrongPassword);
1029*f6dc9357SAndroid Build Coastguard Worker 
1030*f6dc9357SAndroid Build Coastguard Worker   HRESULT Code(const CItem &item, const CItem &lastItem, UInt64 packSize,
1031*f6dc9357SAndroid Build Coastguard Worker       ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress,
1032*f6dc9357SAndroid Build Coastguard Worker       bool &isCrcOK);
1033*f6dc9357SAndroid Build Coastguard Worker 
1034*f6dc9357SAndroid Build Coastguard Worker   HRESULT DecodeToBuf(DECL_EXTERNAL_CODECS_LOC_VARS
1035*f6dc9357SAndroid Build Coastguard Worker       const CItem &item, UInt64 packSize, ISequentialInStream *inStream, CByteBuffer &buffer);
1036*f6dc9357SAndroid Build Coastguard Worker };
1037*f6dc9357SAndroid Build Coastguard Worker 
1038*f6dc9357SAndroid Build Coastguard Worker 
1039*f6dc9357SAndroid Build Coastguard Worker static const unsigned kLzMethodMax = 5;
1040*f6dc9357SAndroid Build Coastguard Worker 
1041*f6dc9357SAndroid Build Coastguard Worker HRESULT CUnpacker::Create(DECL_EXTERNAL_CODECS_LOC_VARS
1042*f6dc9357SAndroid Build Coastguard Worker     const CItem &item, bool isSolid, bool &wrongPassword)
1043*f6dc9357SAndroid Build Coastguard Worker {
1044*f6dc9357SAndroid Build Coastguard Worker   wrongPassword = false;
1045*f6dc9357SAndroid Build Coastguard Worker 
1046*f6dc9357SAndroid Build Coastguard Worker   if (item.Get_AlgoVersion_RawBits() > 1)
1047*f6dc9357SAndroid Build Coastguard Worker     return E_NOTIMPL;
1048*f6dc9357SAndroid Build Coastguard Worker 
1049*f6dc9357SAndroid Build Coastguard Worker   outStream.Create_if_Empty();
1050*f6dc9357SAndroid Build Coastguard Worker 
1051*f6dc9357SAndroid Build Coastguard Worker   const unsigned method = item.Get_Method();
1052*f6dc9357SAndroid Build Coastguard Worker 
1053*f6dc9357SAndroid Build Coastguard Worker   if (method == 0)
1054*f6dc9357SAndroid Build Coastguard Worker     copyCoder.Create_if_Empty();
1055*f6dc9357SAndroid Build Coastguard Worker   else
1056*f6dc9357SAndroid Build Coastguard Worker   {
1057*f6dc9357SAndroid Build Coastguard Worker     if (method > kLzMethodMax)
1058*f6dc9357SAndroid Build Coastguard Worker       return E_NOTIMPL;
1059*f6dc9357SAndroid Build Coastguard Worker     /*
1060*f6dc9357SAndroid Build Coastguard Worker     if (item.IsSplitBefore())
1061*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1062*f6dc9357SAndroid Build Coastguard Worker     */
1063*f6dc9357SAndroid Build Coastguard Worker     const unsigned lzIndex = item.IsService() ? 1 : 0;
1064*f6dc9357SAndroid Build Coastguard Worker     CMyComPtr<ICompressCoder> &lzCoder = LzCoders[lzIndex];
1065*f6dc9357SAndroid Build Coastguard Worker     if (!lzCoder)
1066*f6dc9357SAndroid Build Coastguard Worker     {
1067*f6dc9357SAndroid Build Coastguard Worker       const UInt32 methodID = 0x40305;
1068*f6dc9357SAndroid Build Coastguard Worker       RINOK(CreateCoder_Id(EXTERNAL_CODECS_LOC_VARS methodID, false, lzCoder))
1069*f6dc9357SAndroid Build Coastguard Worker       if (!lzCoder)
1070*f6dc9357SAndroid Build Coastguard Worker         return E_NOTIMPL;
1071*f6dc9357SAndroid Build Coastguard Worker     }
1072*f6dc9357SAndroid Build Coastguard Worker 
1073*f6dc9357SAndroid Build Coastguard Worker     CMyComPtr<ICompressSetDecoderProperties2> csdp;
1074*f6dc9357SAndroid Build Coastguard Worker     RINOK(lzCoder.QueryInterface(IID_ICompressSetDecoderProperties2, &csdp))
1075*f6dc9357SAndroid Build Coastguard Worker     if (!csdp)
1076*f6dc9357SAndroid Build Coastguard Worker       return E_NOTIMPL;
1077*f6dc9357SAndroid Build Coastguard Worker     const unsigned ver = item.Get_AlgoVersion_HuffRev();
1078*f6dc9357SAndroid Build Coastguard Worker     if (ver > 1)
1079*f6dc9357SAndroid Build Coastguard Worker       return E_NOTIMPL;
1080*f6dc9357SAndroid Build Coastguard Worker     const Byte props[2] =
1081*f6dc9357SAndroid Build Coastguard Worker     {
1082*f6dc9357SAndroid Build Coastguard Worker       (Byte)item.Get_DictSize_Main(),
1083*f6dc9357SAndroid Build Coastguard Worker       (Byte)((item.Get_DictSize_Frac() << 3) + (ver << 1) + (isSolid ? 1 : 0))
1084*f6dc9357SAndroid Build Coastguard Worker     };
1085*f6dc9357SAndroid Build Coastguard Worker     RINOK(csdp->SetDecoderProperties2(props, 2))
1086*f6dc9357SAndroid Build Coastguard Worker   }
1087*f6dc9357SAndroid Build Coastguard Worker 
1088*f6dc9357SAndroid Build Coastguard Worker   unsigned cryptoSize = 0;
1089*f6dc9357SAndroid Build Coastguard Worker   const int cryptoOffset = item.FindExtra(NExtraID::kCrypto, cryptoSize);
1090*f6dc9357SAndroid Build Coastguard Worker 
1091*f6dc9357SAndroid Build Coastguard Worker   if (cryptoOffset >= 0)
1092*f6dc9357SAndroid Build Coastguard Worker   {
1093*f6dc9357SAndroid Build Coastguard Worker     if (!filterStream)
1094*f6dc9357SAndroid Build Coastguard Worker     {
1095*f6dc9357SAndroid Build Coastguard Worker       filterStreamSpec = new CFilterCoder(false);
1096*f6dc9357SAndroid Build Coastguard Worker       filterStream = filterStreamSpec;
1097*f6dc9357SAndroid Build Coastguard Worker     }
1098*f6dc9357SAndroid Build Coastguard Worker 
1099*f6dc9357SAndroid Build Coastguard Worker     cryptoDecoder.Create_if_Empty();
1100*f6dc9357SAndroid Build Coastguard Worker 
1101*f6dc9357SAndroid Build Coastguard Worker     RINOK(cryptoDecoder->SetDecoderProps(item.Extra + (unsigned)cryptoOffset, cryptoSize, true, item.IsService()))
1102*f6dc9357SAndroid Build Coastguard Worker 
1103*f6dc9357SAndroid Build Coastguard Worker     if (!getTextPassword)
1104*f6dc9357SAndroid Build Coastguard Worker     {
1105*f6dc9357SAndroid Build Coastguard Worker       wrongPassword = True;
1106*f6dc9357SAndroid Build Coastguard Worker       return E_NOTIMPL;
1107*f6dc9357SAndroid Build Coastguard Worker     }
1108*f6dc9357SAndroid Build Coastguard Worker 
1109*f6dc9357SAndroid Build Coastguard Worker     RINOK(MySetPassword(getTextPassword, cryptoDecoder.ClsPtr()))
1110*f6dc9357SAndroid Build Coastguard Worker 
1111*f6dc9357SAndroid Build Coastguard Worker     if (!cryptoDecoder->CalcKey_and_CheckPassword())
1112*f6dc9357SAndroid Build Coastguard Worker       wrongPassword = True;
1113*f6dc9357SAndroid Build Coastguard Worker   }
1114*f6dc9357SAndroid Build Coastguard Worker 
1115*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1116*f6dc9357SAndroid Build Coastguard Worker }
1117*f6dc9357SAndroid Build Coastguard Worker 
1118*f6dc9357SAndroid Build Coastguard Worker 
1119*f6dc9357SAndroid Build Coastguard Worker HRESULT CUnpacker::Code(const CItem &item, const CItem &lastItem, UInt64 packSize,
1120*f6dc9357SAndroid Build Coastguard Worker     ISequentialInStream *volsInStream, ISequentialOutStream *realOutStream, ICompressProgressInfo *progress,
1121*f6dc9357SAndroid Build Coastguard Worker     bool &isCrcOK)
1122*f6dc9357SAndroid Build Coastguard Worker {
1123*f6dc9357SAndroid Build Coastguard Worker   isCrcOK = true;
1124*f6dc9357SAndroid Build Coastguard Worker 
1125*f6dc9357SAndroid Build Coastguard Worker   const unsigned method = item.Get_Method();
1126*f6dc9357SAndroid Build Coastguard Worker   if (method > kLzMethodMax)
1127*f6dc9357SAndroid Build Coastguard Worker     return E_NOTIMPL;
1128*f6dc9357SAndroid Build Coastguard Worker 
1129*f6dc9357SAndroid Build Coastguard Worker   const bool needBuf = (linkFile && linkFile->NumLinks != 0);
1130*f6dc9357SAndroid Build Coastguard Worker 
1131*f6dc9357SAndroid Build Coastguard Worker   if (needBuf && !lastItem.Is_UnknownSize())
1132*f6dc9357SAndroid Build Coastguard Worker   {
1133*f6dc9357SAndroid Build Coastguard Worker     const size_t dataSize = (size_t)lastItem.Size;
1134*f6dc9357SAndroid Build Coastguard Worker     if (dataSize != lastItem.Size)
1135*f6dc9357SAndroid Build Coastguard Worker       return E_NOTIMPL;
1136*f6dc9357SAndroid Build Coastguard Worker     linkFile->Data.Alloc(dataSize);
1137*f6dc9357SAndroid Build Coastguard Worker   }
1138*f6dc9357SAndroid Build Coastguard Worker 
1139*f6dc9357SAndroid Build Coastguard Worker   bool isCryptoMode = false;
1140*f6dc9357SAndroid Build Coastguard Worker   ISequentialInStream *inStream;
1141*f6dc9357SAndroid Build Coastguard Worker 
1142*f6dc9357SAndroid Build Coastguard Worker   if (item.IsEncrypted())
1143*f6dc9357SAndroid Build Coastguard Worker   {
1144*f6dc9357SAndroid Build Coastguard Worker     filterStreamSpec->Filter = cryptoDecoder;
1145*f6dc9357SAndroid Build Coastguard Worker     filterStreamSpec->SetInStream(volsInStream);
1146*f6dc9357SAndroid Build Coastguard Worker     filterStreamSpec->SetOutStreamSize(NULL);
1147*f6dc9357SAndroid Build Coastguard Worker     inStream = filterStream;
1148*f6dc9357SAndroid Build Coastguard Worker     isCryptoMode = true;
1149*f6dc9357SAndroid Build Coastguard Worker   }
1150*f6dc9357SAndroid Build Coastguard Worker   else
1151*f6dc9357SAndroid Build Coastguard Worker     inStream = volsInStream;
1152*f6dc9357SAndroid Build Coastguard Worker 
1153*f6dc9357SAndroid Build Coastguard Worker   ICompressCoder *commonCoder = (method == 0) ?
1154*f6dc9357SAndroid Build Coastguard Worker       copyCoder.Interface() :
1155*f6dc9357SAndroid Build Coastguard Worker       LzCoders[item.IsService() ? 1 : 0].Interface();
1156*f6dc9357SAndroid Build Coastguard Worker 
1157*f6dc9357SAndroid Build Coastguard Worker   outStream->SetStream(realOutStream);
1158*f6dc9357SAndroid Build Coastguard Worker   outStream->Init(lastItem, (needBuf ? (Byte *)linkFile->Data : NULL), NeedCrc);
1159*f6dc9357SAndroid Build Coastguard Worker 
1160*f6dc9357SAndroid Build Coastguard Worker   HRESULT res = S_OK;
1161*f6dc9357SAndroid Build Coastguard Worker   if (packSize != 0 || lastItem.Is_UnknownSize() || lastItem.Size != 0)
1162*f6dc9357SAndroid Build Coastguard Worker   {
1163*f6dc9357SAndroid Build Coastguard Worker     res = commonCoder->Code(inStream, outStream, &packSize,
1164*f6dc9357SAndroid Build Coastguard Worker       lastItem.Is_UnknownSize() ? NULL : &lastItem.Size, progress);
1165*f6dc9357SAndroid Build Coastguard Worker     if (!item.IsService())
1166*f6dc9357SAndroid Build Coastguard Worker       SolidAllowed = true;
1167*f6dc9357SAndroid Build Coastguard Worker   }
1168*f6dc9357SAndroid Build Coastguard Worker   else
1169*f6dc9357SAndroid Build Coastguard Worker   {
1170*f6dc9357SAndroid Build Coastguard Worker     // res = res;
1171*f6dc9357SAndroid Build Coastguard Worker   }
1172*f6dc9357SAndroid Build Coastguard Worker 
1173*f6dc9357SAndroid Build Coastguard Worker   if (isCryptoMode)
1174*f6dc9357SAndroid Build Coastguard Worker     filterStreamSpec->ReleaseInStream();
1175*f6dc9357SAndroid Build Coastguard Worker 
1176*f6dc9357SAndroid Build Coastguard Worker   const UInt64 processedSize = outStream->GetPos();
1177*f6dc9357SAndroid Build Coastguard Worker   if (res == S_OK && !lastItem.Is_UnknownSize() && processedSize != lastItem.Size)
1178*f6dc9357SAndroid Build Coastguard Worker     res = S_FALSE;
1179*f6dc9357SAndroid Build Coastguard Worker 
1180*f6dc9357SAndroid Build Coastguard Worker   // if (res == S_OK)
1181*f6dc9357SAndroid Build Coastguard Worker   {
1182*f6dc9357SAndroid Build Coastguard Worker     unsigned cryptoSize = 0;
1183*f6dc9357SAndroid Build Coastguard Worker     const int cryptoOffset = lastItem.FindExtra(NExtraID::kCrypto, cryptoSize);
1184*f6dc9357SAndroid Build Coastguard Worker     NCrypto::NRar5::CDecoder *crypto = NULL;
1185*f6dc9357SAndroid Build Coastguard Worker     if (cryptoOffset >= 0)
1186*f6dc9357SAndroid Build Coastguard Worker     {
1187*f6dc9357SAndroid Build Coastguard Worker       CCryptoInfo cryptoInfo;
1188*f6dc9357SAndroid Build Coastguard Worker       if (cryptoInfo.Parse(lastItem.Extra + (unsigned)cryptoOffset, cryptoSize))
1189*f6dc9357SAndroid Build Coastguard Worker         if (cryptoInfo.UseMAC())
1190*f6dc9357SAndroid Build Coastguard Worker           crypto = cryptoDecoder.ClsPtr();
1191*f6dc9357SAndroid Build Coastguard Worker     }
1192*f6dc9357SAndroid Build Coastguard Worker     if (NeedCrc)
1193*f6dc9357SAndroid Build Coastguard Worker       isCrcOK =  outStream->_hash.Check(lastItem, crypto);
1194*f6dc9357SAndroid Build Coastguard Worker   }
1195*f6dc9357SAndroid Build Coastguard Worker 
1196*f6dc9357SAndroid Build Coastguard Worker   if (linkFile)
1197*f6dc9357SAndroid Build Coastguard Worker   {
1198*f6dc9357SAndroid Build Coastguard Worker     linkFile->Res = res;
1199*f6dc9357SAndroid Build Coastguard Worker     linkFile->crcOK = isCrcOK;
1200*f6dc9357SAndroid Build Coastguard Worker     if (needBuf
1201*f6dc9357SAndroid Build Coastguard Worker         && !lastItem.Is_UnknownSize()
1202*f6dc9357SAndroid Build Coastguard Worker         && processedSize != lastItem.Size)
1203*f6dc9357SAndroid Build Coastguard Worker       linkFile->Data.ChangeSize_KeepData((size_t)processedSize, (size_t)processedSize);
1204*f6dc9357SAndroid Build Coastguard Worker   }
1205*f6dc9357SAndroid Build Coastguard Worker 
1206*f6dc9357SAndroid Build Coastguard Worker   return res;
1207*f6dc9357SAndroid Build Coastguard Worker }
1208*f6dc9357SAndroid Build Coastguard Worker 
1209*f6dc9357SAndroid Build Coastguard Worker 
1210*f6dc9357SAndroid Build Coastguard Worker HRESULT CUnpacker::DecodeToBuf(DECL_EXTERNAL_CODECS_LOC_VARS
1211*f6dc9357SAndroid Build Coastguard Worker     const CItem &item, UInt64 packSize,
1212*f6dc9357SAndroid Build Coastguard Worker     ISequentialInStream *inStream,
1213*f6dc9357SAndroid Build Coastguard Worker     CByteBuffer &buffer)
1214*f6dc9357SAndroid Build Coastguard Worker {
1215*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ISequentialOutStream, CBufPtrSeqOutStream> out;
1216*f6dc9357SAndroid Build Coastguard Worker   _tempBuf.AllocAtLeast((size_t)item.Size);
1217*f6dc9357SAndroid Build Coastguard Worker   out->Init(_tempBuf, (size_t)item.Size);
1218*f6dc9357SAndroid Build Coastguard Worker 
1219*f6dc9357SAndroid Build Coastguard Worker   bool wrongPassword;
1220*f6dc9357SAndroid Build Coastguard Worker 
1221*f6dc9357SAndroid Build Coastguard Worker   if (item.IsSolid())
1222*f6dc9357SAndroid Build Coastguard Worker     return E_NOTIMPL;
1223*f6dc9357SAndroid Build Coastguard Worker 
1224*f6dc9357SAndroid Build Coastguard Worker   HRESULT res = Create(EXTERNAL_CODECS_LOC_VARS item, item.IsSolid(), wrongPassword);
1225*f6dc9357SAndroid Build Coastguard Worker 
1226*f6dc9357SAndroid Build Coastguard Worker   if (res == S_OK)
1227*f6dc9357SAndroid Build Coastguard Worker   {
1228*f6dc9357SAndroid Build Coastguard Worker     if (wrongPassword)
1229*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1230*f6dc9357SAndroid Build Coastguard Worker 
1231*f6dc9357SAndroid Build Coastguard Worker     CMyComPtr2_Create<ISequentialInStream, CLimitedSequentialInStream> limitedStream;
1232*f6dc9357SAndroid Build Coastguard Worker     limitedStream->SetStream(inStream);
1233*f6dc9357SAndroid Build Coastguard Worker     limitedStream->Init(packSize);
1234*f6dc9357SAndroid Build Coastguard Worker 
1235*f6dc9357SAndroid Build Coastguard Worker     bool crcOK = true;
1236*f6dc9357SAndroid Build Coastguard Worker     res = Code(item, item, packSize, limitedStream, out, NULL, crcOK);
1237*f6dc9357SAndroid Build Coastguard Worker     if (res == S_OK)
1238*f6dc9357SAndroid Build Coastguard Worker     {
1239*f6dc9357SAndroid Build Coastguard Worker       if (!crcOK || out->GetPos() != item.Size)
1240*f6dc9357SAndroid Build Coastguard Worker         res = S_FALSE;
1241*f6dc9357SAndroid Build Coastguard Worker       else
1242*f6dc9357SAndroid Build Coastguard Worker         buffer.CopyFrom(_tempBuf, (size_t)item.Size);
1243*f6dc9357SAndroid Build Coastguard Worker     }
1244*f6dc9357SAndroid Build Coastguard Worker   }
1245*f6dc9357SAndroid Build Coastguard Worker 
1246*f6dc9357SAndroid Build Coastguard Worker   return res;
1247*f6dc9357SAndroid Build Coastguard Worker }
1248*f6dc9357SAndroid Build Coastguard Worker 
1249*f6dc9357SAndroid Build Coastguard Worker 
1250*f6dc9357SAndroid Build Coastguard Worker struct CTempBuf
1251*f6dc9357SAndroid Build Coastguard Worker {
1252*f6dc9357SAndroid Build Coastguard Worker   CByteBuffer _buf;
1253*f6dc9357SAndroid Build Coastguard Worker   size_t _offset;
1254*f6dc9357SAndroid Build Coastguard Worker   bool _isOK;
1255*f6dc9357SAndroid Build Coastguard Worker 
1256*f6dc9357SAndroid Build Coastguard Worker   void Clear()
1257*f6dc9357SAndroid Build Coastguard Worker   {
1258*f6dc9357SAndroid Build Coastguard Worker     _offset = 0;
1259*f6dc9357SAndroid Build Coastguard Worker     _isOK = true;
1260*f6dc9357SAndroid Build Coastguard Worker   }
1261*f6dc9357SAndroid Build Coastguard Worker 
1262*f6dc9357SAndroid Build Coastguard Worker   CTempBuf() { Clear(); }
1263*f6dc9357SAndroid Build Coastguard Worker 
1264*f6dc9357SAndroid Build Coastguard Worker   HRESULT Decode(DECL_EXTERNAL_CODECS_LOC_VARS
1265*f6dc9357SAndroid Build Coastguard Worker       const CItem &item,
1266*f6dc9357SAndroid Build Coastguard Worker       ISequentialInStream *inStream,
1267*f6dc9357SAndroid Build Coastguard Worker       CUnpacker &unpacker,
1268*f6dc9357SAndroid Build Coastguard Worker       CByteBuffer &destBuf);
1269*f6dc9357SAndroid Build Coastguard Worker };
1270*f6dc9357SAndroid Build Coastguard Worker 
1271*f6dc9357SAndroid Build Coastguard Worker 
1272*f6dc9357SAndroid Build Coastguard Worker HRESULT CTempBuf::Decode(DECL_EXTERNAL_CODECS_LOC_VARS
1273*f6dc9357SAndroid Build Coastguard Worker     const CItem &item,
1274*f6dc9357SAndroid Build Coastguard Worker     ISequentialInStream *inStream,
1275*f6dc9357SAndroid Build Coastguard Worker     CUnpacker &unpacker,
1276*f6dc9357SAndroid Build Coastguard Worker     CByteBuffer &destBuf)
1277*f6dc9357SAndroid Build Coastguard Worker {
1278*f6dc9357SAndroid Build Coastguard Worker   const size_t kPackSize_Max = (1 << 24);
1279*f6dc9357SAndroid Build Coastguard Worker   if (item.Size > (1 << 24)
1280*f6dc9357SAndroid Build Coastguard Worker       || item.Size == 0
1281*f6dc9357SAndroid Build Coastguard Worker       || item.PackSize >= kPackSize_Max)
1282*f6dc9357SAndroid Build Coastguard Worker   {
1283*f6dc9357SAndroid Build Coastguard Worker     Clear();
1284*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
1285*f6dc9357SAndroid Build Coastguard Worker   }
1286*f6dc9357SAndroid Build Coastguard Worker 
1287*f6dc9357SAndroid Build Coastguard Worker   if (item.IsSplit() /* && _isOK */)
1288*f6dc9357SAndroid Build Coastguard Worker   {
1289*f6dc9357SAndroid Build Coastguard Worker     size_t packSize = (size_t)item.PackSize;
1290*f6dc9357SAndroid Build Coastguard Worker     if (packSize > kPackSize_Max - _offset)
1291*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
1292*f6dc9357SAndroid Build Coastguard Worker     size_t newSize = _offset + packSize;
1293*f6dc9357SAndroid Build Coastguard Worker     if (newSize > _buf.Size())
1294*f6dc9357SAndroid Build Coastguard Worker       _buf.ChangeSize_KeepData(newSize, _offset);
1295*f6dc9357SAndroid Build Coastguard Worker 
1296*f6dc9357SAndroid Build Coastguard Worker     Byte *data = (Byte *)_buf + _offset;
1297*f6dc9357SAndroid Build Coastguard Worker     RINOK(ReadStream_FALSE(inStream, data, packSize))
1298*f6dc9357SAndroid Build Coastguard Worker 
1299*f6dc9357SAndroid Build Coastguard Worker     _offset += packSize;
1300*f6dc9357SAndroid Build Coastguard Worker 
1301*f6dc9357SAndroid Build Coastguard Worker     if (item.IsSplitAfter())
1302*f6dc9357SAndroid Build Coastguard Worker     {
1303*f6dc9357SAndroid Build Coastguard Worker       CHash hash;
1304*f6dc9357SAndroid Build Coastguard Worker       hash.Init(item);
1305*f6dc9357SAndroid Build Coastguard Worker       hash.Update(data, packSize);
1306*f6dc9357SAndroid Build Coastguard Worker       _isOK = hash.Check(item, NULL); // RAR5 doesn't use HMAC for packed part
1307*f6dc9357SAndroid Build Coastguard Worker     }
1308*f6dc9357SAndroid Build Coastguard Worker   }
1309*f6dc9357SAndroid Build Coastguard Worker 
1310*f6dc9357SAndroid Build Coastguard Worker   if (_isOK)
1311*f6dc9357SAndroid Build Coastguard Worker   {
1312*f6dc9357SAndroid Build Coastguard Worker     if (!item.IsSplitAfter())
1313*f6dc9357SAndroid Build Coastguard Worker     {
1314*f6dc9357SAndroid Build Coastguard Worker       if (_offset == 0)
1315*f6dc9357SAndroid Build Coastguard Worker       {
1316*f6dc9357SAndroid Build Coastguard Worker         RINOK(unpacker.DecodeToBuf(EXTERNAL_CODECS_LOC_VARS
1317*f6dc9357SAndroid Build Coastguard Worker             item, item.PackSize, inStream, destBuf))
1318*f6dc9357SAndroid Build Coastguard Worker       }
1319*f6dc9357SAndroid Build Coastguard Worker       else
1320*f6dc9357SAndroid Build Coastguard Worker       {
1321*f6dc9357SAndroid Build Coastguard Worker         CMyComPtr2_Create<ISequentialInStream, CBufInStream> bufInStream;
1322*f6dc9357SAndroid Build Coastguard Worker         bufInStream->Init(_buf, _offset);
1323*f6dc9357SAndroid Build Coastguard Worker         RINOK(unpacker.DecodeToBuf(EXTERNAL_CODECS_LOC_VARS
1324*f6dc9357SAndroid Build Coastguard Worker             item, _offset, bufInStream, destBuf))
1325*f6dc9357SAndroid Build Coastguard Worker       }
1326*f6dc9357SAndroid Build Coastguard Worker     }
1327*f6dc9357SAndroid Build Coastguard Worker   }
1328*f6dc9357SAndroid Build Coastguard Worker 
1329*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1330*f6dc9357SAndroid Build Coastguard Worker }
1331*f6dc9357SAndroid Build Coastguard Worker 
1332*f6dc9357SAndroid Build Coastguard Worker 
1333*f6dc9357SAndroid Build Coastguard Worker 
1334*f6dc9357SAndroid Build Coastguard Worker static const Byte kProps[] =
1335*f6dc9357SAndroid Build Coastguard Worker {
1336*f6dc9357SAndroid Build Coastguard Worker   kpidPath,
1337*f6dc9357SAndroid Build Coastguard Worker   kpidIsDir,
1338*f6dc9357SAndroid Build Coastguard Worker   kpidSize,
1339*f6dc9357SAndroid Build Coastguard Worker   kpidPackSize,
1340*f6dc9357SAndroid Build Coastguard Worker   kpidMTime,
1341*f6dc9357SAndroid Build Coastguard Worker   kpidCTime,
1342*f6dc9357SAndroid Build Coastguard Worker   kpidATime,
1343*f6dc9357SAndroid Build Coastguard Worker   kpidAttrib,
1344*f6dc9357SAndroid Build Coastguard Worker   // kpidPosixAttrib, // for debug
1345*f6dc9357SAndroid Build Coastguard Worker 
1346*f6dc9357SAndroid Build Coastguard Worker   kpidIsAltStream,
1347*f6dc9357SAndroid Build Coastguard Worker   kpidEncrypted,
1348*f6dc9357SAndroid Build Coastguard Worker   kpidSolid,
1349*f6dc9357SAndroid Build Coastguard Worker   kpidSplitBefore,
1350*f6dc9357SAndroid Build Coastguard Worker   kpidSplitAfter,
1351*f6dc9357SAndroid Build Coastguard Worker   kpidCRC,
1352*f6dc9357SAndroid Build Coastguard Worker   kpidHostOS,
1353*f6dc9357SAndroid Build Coastguard Worker   kpidMethod,
1354*f6dc9357SAndroid Build Coastguard Worker   kpidCharacts,
1355*f6dc9357SAndroid Build Coastguard Worker   kpidSymLink,
1356*f6dc9357SAndroid Build Coastguard Worker   kpidHardLink,
1357*f6dc9357SAndroid Build Coastguard Worker   kpidCopyLink,
1358*f6dc9357SAndroid Build Coastguard Worker 
1359*f6dc9357SAndroid Build Coastguard Worker   kpidVolumeIndex
1360*f6dc9357SAndroid Build Coastguard Worker };
1361*f6dc9357SAndroid Build Coastguard Worker 
1362*f6dc9357SAndroid Build Coastguard Worker 
1363*f6dc9357SAndroid Build Coastguard Worker static const Byte kArcProps[] =
1364*f6dc9357SAndroid Build Coastguard Worker {
1365*f6dc9357SAndroid Build Coastguard Worker   kpidTotalPhySize,
1366*f6dc9357SAndroid Build Coastguard Worker   kpidCharacts,
1367*f6dc9357SAndroid Build Coastguard Worker   kpidEncrypted,
1368*f6dc9357SAndroid Build Coastguard Worker   kpidSolid,
1369*f6dc9357SAndroid Build Coastguard Worker   kpidNumBlocks,
1370*f6dc9357SAndroid Build Coastguard Worker   kpidMethod,
1371*f6dc9357SAndroid Build Coastguard Worker   kpidIsVolume,
1372*f6dc9357SAndroid Build Coastguard Worker   kpidVolumeIndex,
1373*f6dc9357SAndroid Build Coastguard Worker   kpidNumVolumes,
1374*f6dc9357SAndroid Build Coastguard Worker   kpidName,
1375*f6dc9357SAndroid Build Coastguard Worker   kpidCTime,
1376*f6dc9357SAndroid Build Coastguard Worker   kpidComment
1377*f6dc9357SAndroid Build Coastguard Worker };
1378*f6dc9357SAndroid Build Coastguard Worker 
1379*f6dc9357SAndroid Build Coastguard Worker 
1380*f6dc9357SAndroid Build Coastguard Worker IMP_IInArchive_Props
1381*f6dc9357SAndroid Build Coastguard Worker IMP_IInArchive_ArcProps
1382*f6dc9357SAndroid Build Coastguard Worker 
1383*f6dc9357SAndroid Build Coastguard Worker 
1384*f6dc9357SAndroid Build Coastguard Worker UInt64 CHandler::GetPackSize(unsigned refIndex) const
1385*f6dc9357SAndroid Build Coastguard Worker {
1386*f6dc9357SAndroid Build Coastguard Worker   UInt64 size = 0;
1387*f6dc9357SAndroid Build Coastguard Worker   unsigned index = _refs[refIndex].Item;
1388*f6dc9357SAndroid Build Coastguard Worker   for (;;)
1389*f6dc9357SAndroid Build Coastguard Worker   {
1390*f6dc9357SAndroid Build Coastguard Worker     const CItem &item = _items[index];
1391*f6dc9357SAndroid Build Coastguard Worker     size += item.PackSize;
1392*f6dc9357SAndroid Build Coastguard Worker     if (item.NextItem < 0)
1393*f6dc9357SAndroid Build Coastguard Worker       return size;
1394*f6dc9357SAndroid Build Coastguard Worker     index = (unsigned)item.NextItem;
1395*f6dc9357SAndroid Build Coastguard Worker   }
1396*f6dc9357SAndroid Build Coastguard Worker }
1397*f6dc9357SAndroid Build Coastguard Worker 
1398*f6dc9357SAndroid Build Coastguard Worker static char *PrintDictSize(char *s, UInt64 w)
1399*f6dc9357SAndroid Build Coastguard Worker {
1400*f6dc9357SAndroid Build Coastguard Worker   char                               c = 'K'; w >>= 10;
1401*f6dc9357SAndroid Build Coastguard Worker   if ((w & ((1 << 10) - 1)) == 0)  { c = 'M'; w >>= 10;
1402*f6dc9357SAndroid Build Coastguard Worker   if ((w & ((1 << 10) - 1)) == 0)  { c = 'G'; w >>= 10; }}
1403*f6dc9357SAndroid Build Coastguard Worker   s = ConvertUInt64ToString(w, s);
1404*f6dc9357SAndroid Build Coastguard Worker   *s++ = c;
1405*f6dc9357SAndroid Build Coastguard Worker   *s = 0;
1406*f6dc9357SAndroid Build Coastguard Worker   return s;
1407*f6dc9357SAndroid Build Coastguard Worker }
1408*f6dc9357SAndroid Build Coastguard Worker 
1409*f6dc9357SAndroid Build Coastguard Worker 
1410*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
1411*f6dc9357SAndroid Build Coastguard Worker {
1412*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
1413*f6dc9357SAndroid Build Coastguard Worker 
1414*f6dc9357SAndroid Build Coastguard Worker   NCOM::CPropVariant prop;
1415*f6dc9357SAndroid Build Coastguard Worker 
1416*f6dc9357SAndroid Build Coastguard Worker   const CInArcInfo *arcInfo = NULL;
1417*f6dc9357SAndroid Build Coastguard Worker   if (!_arcs.IsEmpty())
1418*f6dc9357SAndroid Build Coastguard Worker     arcInfo = &_arcs[0].Info;
1419*f6dc9357SAndroid Build Coastguard Worker 
1420*f6dc9357SAndroid Build Coastguard Worker   switch (propID)
1421*f6dc9357SAndroid Build Coastguard Worker   {
1422*f6dc9357SAndroid Build Coastguard Worker     case kpidVolumeIndex: if (arcInfo && arcInfo->IsVolume()) prop = arcInfo->GetVolIndex(); break;
1423*f6dc9357SAndroid Build Coastguard Worker     case kpidSolid: if (arcInfo) prop = arcInfo->IsSolid(); break;
1424*f6dc9357SAndroid Build Coastguard Worker     case kpidCharacts:
1425*f6dc9357SAndroid Build Coastguard Worker     {
1426*f6dc9357SAndroid Build Coastguard Worker       AString s;
1427*f6dc9357SAndroid Build Coastguard Worker       if (arcInfo)
1428*f6dc9357SAndroid Build Coastguard Worker       {
1429*f6dc9357SAndroid Build Coastguard Worker         s = FlagsToString(k_ArcFlags, Z7_ARRAY_SIZE(k_ArcFlags), (UInt32)arcInfo->Flags);
1430*f6dc9357SAndroid Build Coastguard Worker         if (arcInfo->Extra_Error)
1431*f6dc9357SAndroid Build Coastguard Worker           s.Add_OptSpaced("Extra-ERROR");
1432*f6dc9357SAndroid Build Coastguard Worker         if (arcInfo->UnsupportedFeature)
1433*f6dc9357SAndroid Build Coastguard Worker           s.Add_OptSpaced("unsupported-feature");
1434*f6dc9357SAndroid Build Coastguard Worker         if (arcInfo->Metadata_Defined)
1435*f6dc9357SAndroid Build Coastguard Worker         {
1436*f6dc9357SAndroid Build Coastguard Worker           s.Add_OptSpaced("Metadata");
1437*f6dc9357SAndroid Build Coastguard Worker           if (arcInfo->Metadata_Error)
1438*f6dc9357SAndroid Build Coastguard Worker             s += "-ERROR";
1439*f6dc9357SAndroid Build Coastguard Worker           else
1440*f6dc9357SAndroid Build Coastguard Worker           {
1441*f6dc9357SAndroid Build Coastguard Worker             if (arcInfo->Metadata.Flags & NMetadataFlags::kArcName)
1442*f6dc9357SAndroid Build Coastguard Worker               s.Add_OptSpaced("arc-name");
1443*f6dc9357SAndroid Build Coastguard Worker             if (arcInfo->Metadata.Flags & NMetadataFlags::kCTime)
1444*f6dc9357SAndroid Build Coastguard Worker             {
1445*f6dc9357SAndroid Build Coastguard Worker               s.Add_OptSpaced("ctime-");
1446*f6dc9357SAndroid Build Coastguard Worker               s +=
1447*f6dc9357SAndroid Build Coastguard Worker                 (arcInfo->Metadata.Flags & NMetadataFlags::kUnixTime) ?
1448*f6dc9357SAndroid Build Coastguard Worker                 (arcInfo->Metadata.Flags & NMetadataFlags::kNanoSec) ?
1449*f6dc9357SAndroid Build Coastguard Worker                     "1ns" : "1s" : "win";
1450*f6dc9357SAndroid Build Coastguard Worker             }
1451*f6dc9357SAndroid Build Coastguard Worker           }
1452*f6dc9357SAndroid Build Coastguard Worker         }
1453*f6dc9357SAndroid Build Coastguard Worker         if (arcInfo->Locator_Defined)
1454*f6dc9357SAndroid Build Coastguard Worker         {
1455*f6dc9357SAndroid Build Coastguard Worker           s.Add_OptSpaced("Locator");
1456*f6dc9357SAndroid Build Coastguard Worker           if (arcInfo->Locator_Error)
1457*f6dc9357SAndroid Build Coastguard Worker             s += "-ERROR";
1458*f6dc9357SAndroid Build Coastguard Worker           else
1459*f6dc9357SAndroid Build Coastguard Worker           {
1460*f6dc9357SAndroid Build Coastguard Worker             if (arcInfo->Locator.Is_QuickOpen())
1461*f6dc9357SAndroid Build Coastguard Worker             {
1462*f6dc9357SAndroid Build Coastguard Worker               s.Add_OptSpaced("QuickOpen:");
1463*f6dc9357SAndroid Build Coastguard Worker               s.Add_UInt64(arcInfo->Locator.QuickOpen);
1464*f6dc9357SAndroid Build Coastguard Worker             }
1465*f6dc9357SAndroid Build Coastguard Worker             if (arcInfo->Locator.Is_Recovery())
1466*f6dc9357SAndroid Build Coastguard Worker             {
1467*f6dc9357SAndroid Build Coastguard Worker               s.Add_OptSpaced("Recovery:");
1468*f6dc9357SAndroid Build Coastguard Worker               s.Add_UInt64(arcInfo->Locator.Recovery);
1469*f6dc9357SAndroid Build Coastguard Worker             }
1470*f6dc9357SAndroid Build Coastguard Worker           }
1471*f6dc9357SAndroid Build Coastguard Worker         }
1472*f6dc9357SAndroid Build Coastguard Worker         if (arcInfo->UnknownExtraRecord)
1473*f6dc9357SAndroid Build Coastguard Worker           s.Add_OptSpaced("Unknown-Extra-Record");
1474*f6dc9357SAndroid Build Coastguard Worker 
1475*f6dc9357SAndroid Build Coastguard Worker       }
1476*f6dc9357SAndroid Build Coastguard Worker       if (_comment_WasUsedInArc)
1477*f6dc9357SAndroid Build Coastguard Worker       {
1478*f6dc9357SAndroid Build Coastguard Worker         s.Add_OptSpaced("Comment");
1479*f6dc9357SAndroid Build Coastguard Worker         // s.Add_UInt32((UInt32)_comment.Size());
1480*f6dc9357SAndroid Build Coastguard Worker       }
1481*f6dc9357SAndroid Build Coastguard Worker       //
1482*f6dc9357SAndroid Build Coastguard Worker       if (_acls.Size() != 0)
1483*f6dc9357SAndroid Build Coastguard Worker       {
1484*f6dc9357SAndroid Build Coastguard Worker         s.Add_OptSpaced("ACL");
1485*f6dc9357SAndroid Build Coastguard Worker         // s.Add_UInt32(_acls.Size());
1486*f6dc9357SAndroid Build Coastguard Worker       }
1487*f6dc9357SAndroid Build Coastguard Worker       if (!s.IsEmpty())
1488*f6dc9357SAndroid Build Coastguard Worker         prop = s;
1489*f6dc9357SAndroid Build Coastguard Worker       break;
1490*f6dc9357SAndroid Build Coastguard Worker     }
1491*f6dc9357SAndroid Build Coastguard Worker     case kpidEncrypted: if (arcInfo) prop = arcInfo->IsEncrypted; break; // it's for encrypted names.
1492*f6dc9357SAndroid Build Coastguard Worker     case kpidIsVolume: if (arcInfo) prop = arcInfo->IsVolume(); break;
1493*f6dc9357SAndroid Build Coastguard Worker     case kpidNumVolumes: prop = (UInt32)_arcs.Size(); break;
1494*f6dc9357SAndroid Build Coastguard Worker     case kpidOffset: if (arcInfo && arcInfo->StartPos != 0) prop = arcInfo->StartPos; break;
1495*f6dc9357SAndroid Build Coastguard Worker 
1496*f6dc9357SAndroid Build Coastguard Worker     case kpidTotalPhySize:
1497*f6dc9357SAndroid Build Coastguard Worker     {
1498*f6dc9357SAndroid Build Coastguard Worker       if (_arcs.Size() > 1)
1499*f6dc9357SAndroid Build Coastguard Worker       {
1500*f6dc9357SAndroid Build Coastguard Worker         UInt64 sum = 0;
1501*f6dc9357SAndroid Build Coastguard Worker         FOR_VECTOR (v, _arcs)
1502*f6dc9357SAndroid Build Coastguard Worker           sum += _arcs[v].Info.GetPhySize();
1503*f6dc9357SAndroid Build Coastguard Worker         prop = sum;
1504*f6dc9357SAndroid Build Coastguard Worker       }
1505*f6dc9357SAndroid Build Coastguard Worker       break;
1506*f6dc9357SAndroid Build Coastguard Worker     }
1507*f6dc9357SAndroid Build Coastguard Worker 
1508*f6dc9357SAndroid Build Coastguard Worker     case kpidPhySize:
1509*f6dc9357SAndroid Build Coastguard Worker     {
1510*f6dc9357SAndroid Build Coastguard Worker       if (arcInfo)
1511*f6dc9357SAndroid Build Coastguard Worker         prop = arcInfo->GetPhySize();
1512*f6dc9357SAndroid Build Coastguard Worker       break;
1513*f6dc9357SAndroid Build Coastguard Worker     }
1514*f6dc9357SAndroid Build Coastguard Worker 
1515*f6dc9357SAndroid Build Coastguard Worker     case kpidName:
1516*f6dc9357SAndroid Build Coastguard Worker       if (arcInfo)
1517*f6dc9357SAndroid Build Coastguard Worker       if (!arcInfo->Metadata_Error
1518*f6dc9357SAndroid Build Coastguard Worker           && !arcInfo->Metadata.ArcName.IsEmpty())
1519*f6dc9357SAndroid Build Coastguard Worker       {
1520*f6dc9357SAndroid Build Coastguard Worker         UString s;
1521*f6dc9357SAndroid Build Coastguard Worker         if (ConvertUTF8ToUnicode(arcInfo->Metadata.ArcName, s))
1522*f6dc9357SAndroid Build Coastguard Worker           prop = s;
1523*f6dc9357SAndroid Build Coastguard Worker       }
1524*f6dc9357SAndroid Build Coastguard Worker       break;
1525*f6dc9357SAndroid Build Coastguard Worker 
1526*f6dc9357SAndroid Build Coastguard Worker     case kpidCTime:
1527*f6dc9357SAndroid Build Coastguard Worker       if (arcInfo)
1528*f6dc9357SAndroid Build Coastguard Worker       if (!arcInfo->Metadata_Error
1529*f6dc9357SAndroid Build Coastguard Worker           && (arcInfo->Metadata.Flags & NMetadataFlags::kCTime))
1530*f6dc9357SAndroid Build Coastguard Worker       {
1531*f6dc9357SAndroid Build Coastguard Worker         const UInt64 ct = arcInfo->Metadata.CTime;
1532*f6dc9357SAndroid Build Coastguard Worker         if (arcInfo->Metadata.Flags & NMetadataFlags::kUnixTime)
1533*f6dc9357SAndroid Build Coastguard Worker         {
1534*f6dc9357SAndroid Build Coastguard Worker           if (arcInfo->Metadata.Flags & NMetadataFlags::kNanoSec)
1535*f6dc9357SAndroid Build Coastguard Worker           {
1536*f6dc9357SAndroid Build Coastguard Worker             const UInt64 sec = ct / 1000000000;
1537*f6dc9357SAndroid Build Coastguard Worker             const UInt64 ns  = ct % 1000000000;
1538*f6dc9357SAndroid Build Coastguard Worker             UInt64 wt = NTime::UnixTime64_To_FileTime64((Int64)sec);
1539*f6dc9357SAndroid Build Coastguard Worker             wt += ns / 100;
1540*f6dc9357SAndroid Build Coastguard Worker             const unsigned ns100 = (unsigned)(ns % 100);
1541*f6dc9357SAndroid Build Coastguard Worker             FILETIME ft;
1542*f6dc9357SAndroid Build Coastguard Worker             ft.dwLowDateTime = (DWORD)(UInt32)wt;
1543*f6dc9357SAndroid Build Coastguard Worker             ft.dwHighDateTime = (DWORD)(UInt32)(wt >> 32);
1544*f6dc9357SAndroid Build Coastguard Worker             prop.SetAsTimeFrom_FT_Prec_Ns100(ft, k_PropVar_TimePrec_1ns, ns100);
1545*f6dc9357SAndroid Build Coastguard Worker           }
1546*f6dc9357SAndroid Build Coastguard Worker           else
1547*f6dc9357SAndroid Build Coastguard Worker           {
1548*f6dc9357SAndroid Build Coastguard Worker             const UInt64 wt = NTime::UnixTime64_To_FileTime64((Int64)ct);
1549*f6dc9357SAndroid Build Coastguard Worker             prop.SetAsTimeFrom_Ft64_Prec(wt, k_PropVar_TimePrec_Unix);
1550*f6dc9357SAndroid Build Coastguard Worker           }
1551*f6dc9357SAndroid Build Coastguard Worker         }
1552*f6dc9357SAndroid Build Coastguard Worker         else
1553*f6dc9357SAndroid Build Coastguard Worker           prop.SetAsTimeFrom_Ft64_Prec(ct, k_PropVar_TimePrec_100ns);
1554*f6dc9357SAndroid Build Coastguard Worker       }
1555*f6dc9357SAndroid Build Coastguard Worker       break;
1556*f6dc9357SAndroid Build Coastguard Worker 
1557*f6dc9357SAndroid Build Coastguard Worker     case kpidComment:
1558*f6dc9357SAndroid Build Coastguard Worker     {
1559*f6dc9357SAndroid Build Coastguard Worker       // if (!_arcs.IsEmpty())
1560*f6dc9357SAndroid Build Coastguard Worker       {
1561*f6dc9357SAndroid Build Coastguard Worker         // const CArc &arc = _arcs[0];
1562*f6dc9357SAndroid Build Coastguard Worker         const CByteBuffer &cmt = _comment;
1563*f6dc9357SAndroid Build Coastguard Worker         if (cmt.Size() != 0 /* && cmt.Size() < (1 << 16) */)
1564*f6dc9357SAndroid Build Coastguard Worker         {
1565*f6dc9357SAndroid Build Coastguard Worker           AString s;
1566*f6dc9357SAndroid Build Coastguard Worker           s.SetFrom_CalcLen((const char *)(const Byte *)cmt, (unsigned)cmt.Size());
1567*f6dc9357SAndroid Build Coastguard Worker           UString unicode;
1568*f6dc9357SAndroid Build Coastguard Worker           ConvertUTF8ToUnicode(s, unicode);
1569*f6dc9357SAndroid Build Coastguard Worker           prop = unicode;
1570*f6dc9357SAndroid Build Coastguard Worker         }
1571*f6dc9357SAndroid Build Coastguard Worker       }
1572*f6dc9357SAndroid Build Coastguard Worker       break;
1573*f6dc9357SAndroid Build Coastguard Worker     }
1574*f6dc9357SAndroid Build Coastguard Worker 
1575*f6dc9357SAndroid Build Coastguard Worker     case kpidNumBlocks:
1576*f6dc9357SAndroid Build Coastguard Worker     {
1577*f6dc9357SAndroid Build Coastguard Worker       prop = (UInt32)_numBlocks;
1578*f6dc9357SAndroid Build Coastguard Worker       break;
1579*f6dc9357SAndroid Build Coastguard Worker     }
1580*f6dc9357SAndroid Build Coastguard Worker 
1581*f6dc9357SAndroid Build Coastguard Worker     case kpidMethod:
1582*f6dc9357SAndroid Build Coastguard Worker     {
1583*f6dc9357SAndroid Build Coastguard Worker       AString s;
1584*f6dc9357SAndroid Build Coastguard Worker 
1585*f6dc9357SAndroid Build Coastguard Worker       UInt64 algo = _algo_Mask;
1586*f6dc9357SAndroid Build Coastguard Worker       for (unsigned v = 0; algo != 0; v++, algo >>= 1)
1587*f6dc9357SAndroid Build Coastguard Worker       {
1588*f6dc9357SAndroid Build Coastguard Worker         if ((algo & 1) == 0)
1589*f6dc9357SAndroid Build Coastguard Worker           continue;
1590*f6dc9357SAndroid Build Coastguard Worker         s.Add_OptSpaced("v");
1591*f6dc9357SAndroid Build Coastguard Worker         s.Add_UInt32(v + 6);
1592*f6dc9357SAndroid Build Coastguard Worker         if (v < Z7_ARRAY_SIZE(_methodMasks))
1593*f6dc9357SAndroid Build Coastguard Worker         {
1594*f6dc9357SAndroid Build Coastguard Worker           const UInt64 dict = _dictMaxSizes[v];
1595*f6dc9357SAndroid Build Coastguard Worker           if (dict)
1596*f6dc9357SAndroid Build Coastguard Worker           {
1597*f6dc9357SAndroid Build Coastguard Worker             char temp[24];
1598*f6dc9357SAndroid Build Coastguard Worker             temp[0] = ':';
1599*f6dc9357SAndroid Build Coastguard Worker             PrintDictSize(temp + 1, dict);
1600*f6dc9357SAndroid Build Coastguard Worker             s += temp;
1601*f6dc9357SAndroid Build Coastguard Worker           }
1602*f6dc9357SAndroid Build Coastguard Worker           unsigned method = _methodMasks[v];
1603*f6dc9357SAndroid Build Coastguard Worker           for (unsigned m = 0; method; m++, method >>= 1)
1604*f6dc9357SAndroid Build Coastguard Worker           {
1605*f6dc9357SAndroid Build Coastguard Worker             if ((method & 1) == 0)
1606*f6dc9357SAndroid Build Coastguard Worker               continue;
1607*f6dc9357SAndroid Build Coastguard Worker             s += ":m";
1608*f6dc9357SAndroid Build Coastguard Worker             s.Add_UInt32(m);
1609*f6dc9357SAndroid Build Coastguard Worker           }
1610*f6dc9357SAndroid Build Coastguard Worker         }
1611*f6dc9357SAndroid Build Coastguard Worker       }
1612*f6dc9357SAndroid Build Coastguard Worker       if (_rar5comapt_mask & 2)
1613*f6dc9357SAndroid Build Coastguard Worker       {
1614*f6dc9357SAndroid Build Coastguard Worker         s += ":c";
1615*f6dc9357SAndroid Build Coastguard Worker         if (_rar5comapt_mask & 1)
1616*f6dc9357SAndroid Build Coastguard Worker           s.Add_Char('n');
1617*f6dc9357SAndroid Build Coastguard Worker       }
1618*f6dc9357SAndroid Build Coastguard Worker       prop = s;
1619*f6dc9357SAndroid Build Coastguard Worker       break;
1620*f6dc9357SAndroid Build Coastguard Worker     }
1621*f6dc9357SAndroid Build Coastguard Worker 
1622*f6dc9357SAndroid Build Coastguard Worker     case kpidError:
1623*f6dc9357SAndroid Build Coastguard Worker     {
1624*f6dc9357SAndroid Build Coastguard Worker       if (/* &_missingVol || */ !_missingVolName.IsEmpty())
1625*f6dc9357SAndroid Build Coastguard Worker       {
1626*f6dc9357SAndroid Build Coastguard Worker         UString s ("Missing volume : ");
1627*f6dc9357SAndroid Build Coastguard Worker         s += _missingVolName;
1628*f6dc9357SAndroid Build Coastguard Worker         prop = s;
1629*f6dc9357SAndroid Build Coastguard Worker       }
1630*f6dc9357SAndroid Build Coastguard Worker       break;
1631*f6dc9357SAndroid Build Coastguard Worker     }
1632*f6dc9357SAndroid Build Coastguard Worker 
1633*f6dc9357SAndroid Build Coastguard Worker     case kpidErrorFlags:
1634*f6dc9357SAndroid Build Coastguard Worker     {
1635*f6dc9357SAndroid Build Coastguard Worker       UInt32 v = _errorFlags;
1636*f6dc9357SAndroid Build Coastguard Worker       if (!_isArc)
1637*f6dc9357SAndroid Build Coastguard Worker         v |= kpv_ErrorFlags_IsNotArc;
1638*f6dc9357SAndroid Build Coastguard Worker       if (_error_in_ACL)
1639*f6dc9357SAndroid Build Coastguard Worker         v |= kpv_ErrorFlags_HeadersError;
1640*f6dc9357SAndroid Build Coastguard Worker       if (_split_Error)
1641*f6dc9357SAndroid Build Coastguard Worker         v |= kpv_ErrorFlags_HeadersError;
1642*f6dc9357SAndroid Build Coastguard Worker       prop = v;
1643*f6dc9357SAndroid Build Coastguard Worker       break;
1644*f6dc9357SAndroid Build Coastguard Worker     }
1645*f6dc9357SAndroid Build Coastguard Worker 
1646*f6dc9357SAndroid Build Coastguard Worker     /*
1647*f6dc9357SAndroid Build Coastguard Worker     case kpidWarningFlags:
1648*f6dc9357SAndroid Build Coastguard Worker     {
1649*f6dc9357SAndroid Build Coastguard Worker       if (_warningFlags != 0)
1650*f6dc9357SAndroid Build Coastguard Worker         prop = _warningFlags;
1651*f6dc9357SAndroid Build Coastguard Worker       break;
1652*f6dc9357SAndroid Build Coastguard Worker     }
1653*f6dc9357SAndroid Build Coastguard Worker     */
1654*f6dc9357SAndroid Build Coastguard Worker 
1655*f6dc9357SAndroid Build Coastguard Worker     case kpidExtension:
1656*f6dc9357SAndroid Build Coastguard Worker       if (_arcs.Size() == 1)
1657*f6dc9357SAndroid Build Coastguard Worker       {
1658*f6dc9357SAndroid Build Coastguard Worker         if (arcInfo->IsVolume())
1659*f6dc9357SAndroid Build Coastguard Worker         {
1660*f6dc9357SAndroid Build Coastguard Worker           AString s ("part");
1661*f6dc9357SAndroid Build Coastguard Worker           UInt32 v = (UInt32)arcInfo->GetVolIndex() + 1;
1662*f6dc9357SAndroid Build Coastguard Worker           if (v < 10)
1663*f6dc9357SAndroid Build Coastguard Worker             s.Add_Char('0');
1664*f6dc9357SAndroid Build Coastguard Worker           s.Add_UInt32(v);
1665*f6dc9357SAndroid Build Coastguard Worker           s += ".rar";
1666*f6dc9357SAndroid Build Coastguard Worker           prop = s;
1667*f6dc9357SAndroid Build Coastguard Worker         }
1668*f6dc9357SAndroid Build Coastguard Worker       }
1669*f6dc9357SAndroid Build Coastguard Worker       break;
1670*f6dc9357SAndroid Build Coastguard Worker 
1671*f6dc9357SAndroid Build Coastguard Worker     case kpidIsAltStream: prop = true; break;
1672*f6dc9357SAndroid Build Coastguard Worker   }
1673*f6dc9357SAndroid Build Coastguard Worker 
1674*f6dc9357SAndroid Build Coastguard Worker   prop.Detach(value);
1675*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1676*f6dc9357SAndroid Build Coastguard Worker 
1677*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
1678*f6dc9357SAndroid Build Coastguard Worker }
1679*f6dc9357SAndroid Build Coastguard Worker 
1680*f6dc9357SAndroid Build Coastguard Worker 
1681*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
1682*f6dc9357SAndroid Build Coastguard Worker {
1683*f6dc9357SAndroid Build Coastguard Worker   *numItems = (UInt32)_refs.Size();
1684*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1685*f6dc9357SAndroid Build Coastguard Worker }
1686*f6dc9357SAndroid Build Coastguard Worker 
1687*f6dc9357SAndroid Build Coastguard Worker 
1688*f6dc9357SAndroid Build Coastguard Worker static const Byte kRawProps[] =
1689*f6dc9357SAndroid Build Coastguard Worker {
1690*f6dc9357SAndroid Build Coastguard Worker   kpidChecksum,
1691*f6dc9357SAndroid Build Coastguard Worker   kpidNtSecure
1692*f6dc9357SAndroid Build Coastguard Worker };
1693*f6dc9357SAndroid Build Coastguard Worker 
1694*f6dc9357SAndroid Build Coastguard Worker 
1695*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetNumRawProps(UInt32 *numProps))
1696*f6dc9357SAndroid Build Coastguard Worker {
1697*f6dc9357SAndroid Build Coastguard Worker   *numProps = Z7_ARRAY_SIZE(kRawProps);
1698*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1699*f6dc9357SAndroid Build Coastguard Worker }
1700*f6dc9357SAndroid Build Coastguard Worker 
1701*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetRawPropInfo(UInt32 index, BSTR *name, PROPID *propID))
1702*f6dc9357SAndroid Build Coastguard Worker {
1703*f6dc9357SAndroid Build Coastguard Worker   *propID = kRawProps[index];
1704*f6dc9357SAndroid Build Coastguard Worker   *name = NULL;
1705*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1706*f6dc9357SAndroid Build Coastguard Worker }
1707*f6dc9357SAndroid Build Coastguard Worker 
1708*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetParent(UInt32 index, UInt32 *parent, UInt32 *parentType))
1709*f6dc9357SAndroid Build Coastguard Worker {
1710*f6dc9357SAndroid Build Coastguard Worker   *parentType = NParentType::kDir;
1711*f6dc9357SAndroid Build Coastguard Worker   *parent = (UInt32)(Int32)-1;
1712*f6dc9357SAndroid Build Coastguard Worker 
1713*f6dc9357SAndroid Build Coastguard Worker   if (index >= _refs.Size())
1714*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
1715*f6dc9357SAndroid Build Coastguard Worker 
1716*f6dc9357SAndroid Build Coastguard Worker   const CRefItem &ref = _refs[index];
1717*f6dc9357SAndroid Build Coastguard Worker   const CItem &item = _items[ref.Item];
1718*f6dc9357SAndroid Build Coastguard Worker 
1719*f6dc9357SAndroid Build Coastguard Worker   if (item.Is_STM() && ref.Parent >= 0)
1720*f6dc9357SAndroid Build Coastguard Worker   {
1721*f6dc9357SAndroid Build Coastguard Worker     *parent = (UInt32)ref.Parent;
1722*f6dc9357SAndroid Build Coastguard Worker     *parentType = NParentType::kAltStream;
1723*f6dc9357SAndroid Build Coastguard Worker   }
1724*f6dc9357SAndroid Build Coastguard Worker 
1725*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1726*f6dc9357SAndroid Build Coastguard Worker }
1727*f6dc9357SAndroid Build Coastguard Worker 
1728*f6dc9357SAndroid Build Coastguard Worker 
1729*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType))
1730*f6dc9357SAndroid Build Coastguard Worker {
1731*f6dc9357SAndroid Build Coastguard Worker   *data = NULL;
1732*f6dc9357SAndroid Build Coastguard Worker   *dataSize = 0;
1733*f6dc9357SAndroid Build Coastguard Worker   *propType = 0;
1734*f6dc9357SAndroid Build Coastguard Worker 
1735*f6dc9357SAndroid Build Coastguard Worker   if (index >= _refs.Size())
1736*f6dc9357SAndroid Build Coastguard Worker     return E_INVALIDARG;
1737*f6dc9357SAndroid Build Coastguard Worker 
1738*f6dc9357SAndroid Build Coastguard Worker   const CItem &item = _items[_refs[index].Item];
1739*f6dc9357SAndroid Build Coastguard Worker 
1740*f6dc9357SAndroid Build Coastguard Worker   if (propID == kpidNtSecure)
1741*f6dc9357SAndroid Build Coastguard Worker   {
1742*f6dc9357SAndroid Build Coastguard Worker     if (item.ACL >= 0)
1743*f6dc9357SAndroid Build Coastguard Worker     {
1744*f6dc9357SAndroid Build Coastguard Worker       const CByteBuffer &buf = _acls[item.ACL];
1745*f6dc9357SAndroid Build Coastguard Worker       *dataSize = (UInt32)buf.Size();
1746*f6dc9357SAndroid Build Coastguard Worker       *propType = NPropDataType::kRaw;
1747*f6dc9357SAndroid Build Coastguard Worker       *data = (const Byte *)buf;
1748*f6dc9357SAndroid Build Coastguard Worker     }
1749*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
1750*f6dc9357SAndroid Build Coastguard Worker   }
1751*f6dc9357SAndroid Build Coastguard Worker 
1752*f6dc9357SAndroid Build Coastguard Worker   if (propID == kpidChecksum)
1753*f6dc9357SAndroid Build Coastguard Worker   {
1754*f6dc9357SAndroid Build Coastguard Worker     const int hashRecOffset = item.FindExtra_Blake();
1755*f6dc9357SAndroid Build Coastguard Worker     if (hashRecOffset >= 0)
1756*f6dc9357SAndroid Build Coastguard Worker     {
1757*f6dc9357SAndroid Build Coastguard Worker       *dataSize = Z7_BLAKE2S_DIGEST_SIZE;
1758*f6dc9357SAndroid Build Coastguard Worker       *propType = NPropDataType::kRaw;
1759*f6dc9357SAndroid Build Coastguard Worker       *data = item.Extra + (unsigned)hashRecOffset;
1760*f6dc9357SAndroid Build Coastguard Worker     }
1761*f6dc9357SAndroid Build Coastguard Worker     /*
1762*f6dc9357SAndroid Build Coastguard Worker     else if (item.Has_CRC() && item.IsEncrypted())
1763*f6dc9357SAndroid Build Coastguard Worker     {
1764*f6dc9357SAndroid Build Coastguard Worker       *dataSize = 4;
1765*f6dc9357SAndroid Build Coastguard Worker       *propType = NPropDataType::kRaw;
1766*f6dc9357SAndroid Build Coastguard Worker       *data = &item->CRC; // we must show same value for big/little endian here
1767*f6dc9357SAndroid Build Coastguard Worker     }
1768*f6dc9357SAndroid Build Coastguard Worker     */
1769*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
1770*f6dc9357SAndroid Build Coastguard Worker   }
1771*f6dc9357SAndroid Build Coastguard Worker 
1772*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1773*f6dc9357SAndroid Build Coastguard Worker }
1774*f6dc9357SAndroid Build Coastguard Worker 
1775*f6dc9357SAndroid Build Coastguard Worker 
1776*f6dc9357SAndroid Build Coastguard Worker static void TimeRecordToProp(const CItem &item, unsigned stampIndex, NCOM::CPropVariant &prop)
1777*f6dc9357SAndroid Build Coastguard Worker {
1778*f6dc9357SAndroid Build Coastguard Worker   unsigned size;
1779*f6dc9357SAndroid Build Coastguard Worker   const int offset = item.FindExtra(NExtraID::kTime, size);
1780*f6dc9357SAndroid Build Coastguard Worker   if (offset < 0)
1781*f6dc9357SAndroid Build Coastguard Worker     return;
1782*f6dc9357SAndroid Build Coastguard Worker 
1783*f6dc9357SAndroid Build Coastguard Worker   const Byte *p = item.Extra + (unsigned)offset;
1784*f6dc9357SAndroid Build Coastguard Worker   UInt64 flags;
1785*f6dc9357SAndroid Build Coastguard Worker   // PARSE_VAR_INT(p, size, flags)
1786*f6dc9357SAndroid Build Coastguard Worker   {
1787*f6dc9357SAndroid Build Coastguard Worker     const unsigned num = ReadVarInt(p, size, &flags);
1788*f6dc9357SAndroid Build Coastguard Worker     if (num == 0)
1789*f6dc9357SAndroid Build Coastguard Worker       return;
1790*f6dc9357SAndroid Build Coastguard Worker     p += num;
1791*f6dc9357SAndroid Build Coastguard Worker     size -= num;
1792*f6dc9357SAndroid Build Coastguard Worker   }
1793*f6dc9357SAndroid Build Coastguard Worker 
1794*f6dc9357SAndroid Build Coastguard Worker   if ((flags & (NTimeRecord::NFlags::kMTime << stampIndex)) == 0)
1795*f6dc9357SAndroid Build Coastguard Worker     return;
1796*f6dc9357SAndroid Build Coastguard Worker 
1797*f6dc9357SAndroid Build Coastguard Worker   unsigned numStamps = 0;
1798*f6dc9357SAndroid Build Coastguard Worker   unsigned curStamp = 0;
1799*f6dc9357SAndroid Build Coastguard Worker 
1800*f6dc9357SAndroid Build Coastguard Worker   for (unsigned i = 0; i < 3; i++)
1801*f6dc9357SAndroid Build Coastguard Worker     if ((flags & (NTimeRecord::NFlags::kMTime << i)) != 0)
1802*f6dc9357SAndroid Build Coastguard Worker     {
1803*f6dc9357SAndroid Build Coastguard Worker       if (i == stampIndex)
1804*f6dc9357SAndroid Build Coastguard Worker         curStamp = numStamps;
1805*f6dc9357SAndroid Build Coastguard Worker       numStamps++;
1806*f6dc9357SAndroid Build Coastguard Worker     }
1807*f6dc9357SAndroid Build Coastguard Worker 
1808*f6dc9357SAndroid Build Coastguard Worker   FILETIME ft;
1809*f6dc9357SAndroid Build Coastguard Worker 
1810*f6dc9357SAndroid Build Coastguard Worker   unsigned timePrec = 0;
1811*f6dc9357SAndroid Build Coastguard Worker   unsigned ns100 = 0;
1812*f6dc9357SAndroid Build Coastguard Worker 
1813*f6dc9357SAndroid Build Coastguard Worker   if ((flags & NTimeRecord::NFlags::kUnixTime) != 0)
1814*f6dc9357SAndroid Build Coastguard Worker   {
1815*f6dc9357SAndroid Build Coastguard Worker     curStamp *= 4;
1816*f6dc9357SAndroid Build Coastguard Worker     if (curStamp + 4 > size)
1817*f6dc9357SAndroid Build Coastguard Worker       return;
1818*f6dc9357SAndroid Build Coastguard Worker     p += curStamp;
1819*f6dc9357SAndroid Build Coastguard Worker     UInt64 val = NTime::UnixTime_To_FileTime64(Get32(p));
1820*f6dc9357SAndroid Build Coastguard Worker     numStamps *= 4;
1821*f6dc9357SAndroid Build Coastguard Worker     timePrec = k_PropVar_TimePrec_Unix;
1822*f6dc9357SAndroid Build Coastguard Worker     if ((flags & NTimeRecord::NFlags::kUnixNs) != 0 && numStamps * 2 <= size)
1823*f6dc9357SAndroid Build Coastguard Worker     {
1824*f6dc9357SAndroid Build Coastguard Worker       const UInt32 ns = Get32(p + numStamps) & 0x3FFFFFFF;
1825*f6dc9357SAndroid Build Coastguard Worker       if (ns < 1000000000)
1826*f6dc9357SAndroid Build Coastguard Worker       {
1827*f6dc9357SAndroid Build Coastguard Worker         val += ns / 100;
1828*f6dc9357SAndroid Build Coastguard Worker         ns100 = (unsigned)(ns % 100);
1829*f6dc9357SAndroid Build Coastguard Worker         timePrec = k_PropVar_TimePrec_1ns;
1830*f6dc9357SAndroid Build Coastguard Worker       }
1831*f6dc9357SAndroid Build Coastguard Worker     }
1832*f6dc9357SAndroid Build Coastguard Worker     ft.dwLowDateTime = (DWORD)val;
1833*f6dc9357SAndroid Build Coastguard Worker     ft.dwHighDateTime = (DWORD)(val >> 32);
1834*f6dc9357SAndroid Build Coastguard Worker   }
1835*f6dc9357SAndroid Build Coastguard Worker   else
1836*f6dc9357SAndroid Build Coastguard Worker   {
1837*f6dc9357SAndroid Build Coastguard Worker     curStamp *= 8;
1838*f6dc9357SAndroid Build Coastguard Worker     if (curStamp + 8 > size)
1839*f6dc9357SAndroid Build Coastguard Worker       return;
1840*f6dc9357SAndroid Build Coastguard Worker     p += curStamp;
1841*f6dc9357SAndroid Build Coastguard Worker     ft.dwLowDateTime = Get32(p);
1842*f6dc9357SAndroid Build Coastguard Worker     ft.dwHighDateTime = Get32(p + 4);
1843*f6dc9357SAndroid Build Coastguard Worker   }
1844*f6dc9357SAndroid Build Coastguard Worker 
1845*f6dc9357SAndroid Build Coastguard Worker   prop.SetAsTimeFrom_FT_Prec_Ns100(ft, timePrec, ns100);
1846*f6dc9357SAndroid Build Coastguard Worker }
1847*f6dc9357SAndroid Build Coastguard Worker 
1848*f6dc9357SAndroid Build Coastguard Worker 
1849*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
1850*f6dc9357SAndroid Build Coastguard Worker {
1851*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
1852*f6dc9357SAndroid Build Coastguard Worker 
1853*f6dc9357SAndroid Build Coastguard Worker   NCOM::CPropVariant prop;
1854*f6dc9357SAndroid Build Coastguard Worker   const CRefItem &ref = _refs[index];
1855*f6dc9357SAndroid Build Coastguard Worker   const CItem &item = _items[ref.Item];
1856*f6dc9357SAndroid Build Coastguard Worker   const CItem &lastItem = _items[ref.Last];
1857*f6dc9357SAndroid Build Coastguard Worker 
1858*f6dc9357SAndroid Build Coastguard Worker   switch (propID)
1859*f6dc9357SAndroid Build Coastguard Worker   {
1860*f6dc9357SAndroid Build Coastguard Worker     case kpidPath:
1861*f6dc9357SAndroid Build Coastguard Worker     {
1862*f6dc9357SAndroid Build Coastguard Worker       UString unicodeName;
1863*f6dc9357SAndroid Build Coastguard Worker 
1864*f6dc9357SAndroid Build Coastguard Worker       if (item.Is_STM())
1865*f6dc9357SAndroid Build Coastguard Worker       {
1866*f6dc9357SAndroid Build Coastguard Worker         AString s;
1867*f6dc9357SAndroid Build Coastguard Worker         if (ref.Parent >= 0)
1868*f6dc9357SAndroid Build Coastguard Worker         {
1869*f6dc9357SAndroid Build Coastguard Worker           const CItem &mainItem = _items[_refs[ref.Parent].Item];
1870*f6dc9357SAndroid Build Coastguard Worker           s = mainItem.Name;
1871*f6dc9357SAndroid Build Coastguard Worker         }
1872*f6dc9357SAndroid Build Coastguard Worker 
1873*f6dc9357SAndroid Build Coastguard Worker         AString name;
1874*f6dc9357SAndroid Build Coastguard Worker         item.GetAltStreamName(name);
1875*f6dc9357SAndroid Build Coastguard Worker         if (name[0] != ':')
1876*f6dc9357SAndroid Build Coastguard Worker           s.Add_Colon();
1877*f6dc9357SAndroid Build Coastguard Worker         s += name;
1878*f6dc9357SAndroid Build Coastguard Worker         ConvertUTF8ToUnicode(s, unicodeName);
1879*f6dc9357SAndroid Build Coastguard Worker       }
1880*f6dc9357SAndroid Build Coastguard Worker       else
1881*f6dc9357SAndroid Build Coastguard Worker       {
1882*f6dc9357SAndroid Build Coastguard Worker         ConvertUTF8ToUnicode(item.Name, unicodeName);
1883*f6dc9357SAndroid Build Coastguard Worker 
1884*f6dc9357SAndroid Build Coastguard Worker         if (item.Version_Defined)
1885*f6dc9357SAndroid Build Coastguard Worker         {
1886*f6dc9357SAndroid Build Coastguard Worker           char temp[32];
1887*f6dc9357SAndroid Build Coastguard Worker           // temp[0] = ';';
1888*f6dc9357SAndroid Build Coastguard Worker           // ConvertUInt64ToString(item.Version, temp + 1);
1889*f6dc9357SAndroid Build Coastguard Worker           // unicodeName += temp;
1890*f6dc9357SAndroid Build Coastguard Worker           ConvertUInt64ToString(item.Version, temp);
1891*f6dc9357SAndroid Build Coastguard Worker           UString s2 ("[VER]" STRING_PATH_SEPARATOR);
1892*f6dc9357SAndroid Build Coastguard Worker           s2 += temp;
1893*f6dc9357SAndroid Build Coastguard Worker           s2.Add_PathSepar();
1894*f6dc9357SAndroid Build Coastguard Worker           unicodeName.Insert(0, s2);
1895*f6dc9357SAndroid Build Coastguard Worker         }
1896*f6dc9357SAndroid Build Coastguard Worker       }
1897*f6dc9357SAndroid Build Coastguard Worker 
1898*f6dc9357SAndroid Build Coastguard Worker       NItemName::ReplaceToOsSlashes_Remove_TailSlash(unicodeName);
1899*f6dc9357SAndroid Build Coastguard Worker       prop = unicodeName;
1900*f6dc9357SAndroid Build Coastguard Worker 
1901*f6dc9357SAndroid Build Coastguard Worker       break;
1902*f6dc9357SAndroid Build Coastguard Worker     }
1903*f6dc9357SAndroid Build Coastguard Worker 
1904*f6dc9357SAndroid Build Coastguard Worker     case kpidIsDir: prop = item.IsDir(); break;
1905*f6dc9357SAndroid Build Coastguard Worker     case kpidSize: if (!lastItem.Is_UnknownSize()) prop = lastItem.Size; break;
1906*f6dc9357SAndroid Build Coastguard Worker     case kpidPackSize: prop = GetPackSize((unsigned)index); break;
1907*f6dc9357SAndroid Build Coastguard Worker 
1908*f6dc9357SAndroid Build Coastguard Worker     case kpidMTime:
1909*f6dc9357SAndroid Build Coastguard Worker     {
1910*f6dc9357SAndroid Build Coastguard Worker       TimeRecordToProp(item, NTimeRecord::k_Index_MTime, prop);
1911*f6dc9357SAndroid Build Coastguard Worker       if (prop.vt == VT_EMPTY && item.Has_UnixMTime())
1912*f6dc9357SAndroid Build Coastguard Worker         PropVariant_SetFrom_UnixTime(prop, item.UnixMTime);
1913*f6dc9357SAndroid Build Coastguard Worker       if (prop.vt == VT_EMPTY && ref.Parent >= 0)
1914*f6dc9357SAndroid Build Coastguard Worker       {
1915*f6dc9357SAndroid Build Coastguard Worker         const CItem &baseItem = _items[_refs[ref.Parent].Item];
1916*f6dc9357SAndroid Build Coastguard Worker         TimeRecordToProp(baseItem, NTimeRecord::k_Index_MTime, prop);
1917*f6dc9357SAndroid Build Coastguard Worker         if (prop.vt == VT_EMPTY && baseItem.Has_UnixMTime())
1918*f6dc9357SAndroid Build Coastguard Worker           PropVariant_SetFrom_UnixTime(prop, baseItem.UnixMTime);
1919*f6dc9357SAndroid Build Coastguard Worker       }
1920*f6dc9357SAndroid Build Coastguard Worker       break;
1921*f6dc9357SAndroid Build Coastguard Worker     }
1922*f6dc9357SAndroid Build Coastguard Worker     case kpidCTime: TimeRecordToProp(item, NTimeRecord::k_Index_CTime, prop); break;
1923*f6dc9357SAndroid Build Coastguard Worker     case kpidATime: TimeRecordToProp(item, NTimeRecord::k_Index_ATime, prop); break;
1924*f6dc9357SAndroid Build Coastguard Worker 
1925*f6dc9357SAndroid Build Coastguard Worker     case kpidName:
1926*f6dc9357SAndroid Build Coastguard Worker     {
1927*f6dc9357SAndroid Build Coastguard Worker       if (item.Is_STM())
1928*f6dc9357SAndroid Build Coastguard Worker       {
1929*f6dc9357SAndroid Build Coastguard Worker         AString name;
1930*f6dc9357SAndroid Build Coastguard Worker         item.GetAltStreamName(name);
1931*f6dc9357SAndroid Build Coastguard Worker         if (name[0] == ':')
1932*f6dc9357SAndroid Build Coastguard Worker         {
1933*f6dc9357SAndroid Build Coastguard Worker           name.DeleteFrontal(1);
1934*f6dc9357SAndroid Build Coastguard Worker           UString unicodeName;
1935*f6dc9357SAndroid Build Coastguard Worker           ConvertUTF8ToUnicode(name, unicodeName);
1936*f6dc9357SAndroid Build Coastguard Worker           prop = unicodeName;
1937*f6dc9357SAndroid Build Coastguard Worker         }
1938*f6dc9357SAndroid Build Coastguard Worker       }
1939*f6dc9357SAndroid Build Coastguard Worker       break;
1940*f6dc9357SAndroid Build Coastguard Worker     }
1941*f6dc9357SAndroid Build Coastguard Worker 
1942*f6dc9357SAndroid Build Coastguard Worker     case kpidIsAltStream: prop = item.Is_STM(); break;
1943*f6dc9357SAndroid Build Coastguard Worker 
1944*f6dc9357SAndroid Build Coastguard Worker     case kpidSymLink: item.Link_to_Prop(NLinkType::kUnixSymLink, prop); break;
1945*f6dc9357SAndroid Build Coastguard Worker     case kpidHardLink: item.Link_to_Prop(NLinkType::kHardLink, prop); break;
1946*f6dc9357SAndroid Build Coastguard Worker     case kpidCopyLink: item.Link_to_Prop(NLinkType::kFileCopy, prop); break;
1947*f6dc9357SAndroid Build Coastguard Worker 
1948*f6dc9357SAndroid Build Coastguard Worker     case kpidAttrib: prop = item.GetWinAttrib(); break;
1949*f6dc9357SAndroid Build Coastguard Worker     case kpidPosixAttrib:
1950*f6dc9357SAndroid Build Coastguard Worker       if (item.HostOS == kHost_Unix)
1951*f6dc9357SAndroid Build Coastguard Worker         prop = (UInt32)item.Attrib;
1952*f6dc9357SAndroid Build Coastguard Worker       break;
1953*f6dc9357SAndroid Build Coastguard Worker 
1954*f6dc9357SAndroid Build Coastguard Worker     case kpidEncrypted: prop = item.IsEncrypted(); break;
1955*f6dc9357SAndroid Build Coastguard Worker     case kpidSolid: prop = item.IsSolid(); break;
1956*f6dc9357SAndroid Build Coastguard Worker 
1957*f6dc9357SAndroid Build Coastguard Worker     case kpidSplitBefore: prop = item.IsSplitBefore(); break;
1958*f6dc9357SAndroid Build Coastguard Worker     case kpidSplitAfter: prop = lastItem.IsSplitAfter(); break;
1959*f6dc9357SAndroid Build Coastguard Worker 
1960*f6dc9357SAndroid Build Coastguard Worker     case kpidVolumeIndex:
1961*f6dc9357SAndroid Build Coastguard Worker     {
1962*f6dc9357SAndroid Build Coastguard Worker       if (item.VolIndex < _arcs.Size())
1963*f6dc9357SAndroid Build Coastguard Worker       {
1964*f6dc9357SAndroid Build Coastguard Worker         const CInArcInfo &arcInfo = _arcs[item.VolIndex].Info;
1965*f6dc9357SAndroid Build Coastguard Worker         if (arcInfo.IsVolume())
1966*f6dc9357SAndroid Build Coastguard Worker           prop = (UInt64)arcInfo.GetVolIndex();
1967*f6dc9357SAndroid Build Coastguard Worker       }
1968*f6dc9357SAndroid Build Coastguard Worker       break;
1969*f6dc9357SAndroid Build Coastguard Worker     }
1970*f6dc9357SAndroid Build Coastguard Worker 
1971*f6dc9357SAndroid Build Coastguard Worker     case kpidCRC:
1972*f6dc9357SAndroid Build Coastguard Worker     {
1973*f6dc9357SAndroid Build Coastguard Worker       const CItem *item2 = (lastItem.IsSplitAfter() ? &item : &lastItem);
1974*f6dc9357SAndroid Build Coastguard Worker       // we don't want to show crc for encrypted file here,
1975*f6dc9357SAndroid Build Coastguard Worker       // because crc is also encrrypted.
1976*f6dc9357SAndroid Build Coastguard Worker       if (item2->Has_CRC() && !item2->IsEncrypted())
1977*f6dc9357SAndroid Build Coastguard Worker         prop = item2->CRC;
1978*f6dc9357SAndroid Build Coastguard Worker       break;
1979*f6dc9357SAndroid Build Coastguard Worker     }
1980*f6dc9357SAndroid Build Coastguard Worker 
1981*f6dc9357SAndroid Build Coastguard Worker     case kpidMethod:
1982*f6dc9357SAndroid Build Coastguard Worker     {
1983*f6dc9357SAndroid Build Coastguard Worker       char temp[128];
1984*f6dc9357SAndroid Build Coastguard Worker       const unsigned algo = item.Get_AlgoVersion_RawBits();
1985*f6dc9357SAndroid Build Coastguard Worker       char *s = temp;
1986*f6dc9357SAndroid Build Coastguard Worker       // if (algo != 0)
1987*f6dc9357SAndroid Build Coastguard Worker       {
1988*f6dc9357SAndroid Build Coastguard Worker         *s++ = 'v';
1989*f6dc9357SAndroid Build Coastguard Worker         s = ConvertUInt32ToString((UInt32)algo + 6, s);
1990*f6dc9357SAndroid Build Coastguard Worker         if (item.Is_Rar5_Compat())
1991*f6dc9357SAndroid Build Coastguard Worker           *s++ = 'c';
1992*f6dc9357SAndroid Build Coastguard Worker         *s++ = ':';
1993*f6dc9357SAndroid Build Coastguard Worker       }
1994*f6dc9357SAndroid Build Coastguard Worker       {
1995*f6dc9357SAndroid Build Coastguard Worker         const unsigned m = item.Get_Method();
1996*f6dc9357SAndroid Build Coastguard Worker         *s++ = 'm';
1997*f6dc9357SAndroid Build Coastguard Worker         *s++ = (char)(m + '0');
1998*f6dc9357SAndroid Build Coastguard Worker         if (!item.IsDir())
1999*f6dc9357SAndroid Build Coastguard Worker         {
2000*f6dc9357SAndroid Build Coastguard Worker           *s++ = ':';
2001*f6dc9357SAndroid Build Coastguard Worker           const unsigned dictMain = item.Get_DictSize_Main();
2002*f6dc9357SAndroid Build Coastguard Worker           const unsigned frac = item.Get_DictSize_Frac();
2003*f6dc9357SAndroid Build Coastguard Worker           /*
2004*f6dc9357SAndroid Build Coastguard Worker           if (frac == 0 && algo == 0)
2005*f6dc9357SAndroid Build Coastguard Worker             s = ConvertUInt32ToString(dictMain + 17, s);
2006*f6dc9357SAndroid Build Coastguard Worker           else
2007*f6dc9357SAndroid Build Coastguard Worker           */
2008*f6dc9357SAndroid Build Coastguard Worker           s = PrintDictSize(s, (UInt64)(32 + frac) << (12 + dictMain));
2009*f6dc9357SAndroid Build Coastguard Worker           if (item.Is_Rar5_Compat())
2010*f6dc9357SAndroid Build Coastguard Worker           {
2011*f6dc9357SAndroid Build Coastguard Worker             *s++ = ':';
2012*f6dc9357SAndroid Build Coastguard Worker             *s++ = 'c';
2013*f6dc9357SAndroid Build Coastguard Worker           }
2014*f6dc9357SAndroid Build Coastguard Worker         }
2015*f6dc9357SAndroid Build Coastguard Worker       }
2016*f6dc9357SAndroid Build Coastguard Worker       unsigned cryptoSize = 0;
2017*f6dc9357SAndroid Build Coastguard Worker       const int cryptoOffset = item.FindExtra(NExtraID::kCrypto, cryptoSize);
2018*f6dc9357SAndroid Build Coastguard Worker       if (cryptoOffset >= 0)
2019*f6dc9357SAndroid Build Coastguard Worker       {
2020*f6dc9357SAndroid Build Coastguard Worker         *s++ = ' ';
2021*f6dc9357SAndroid Build Coastguard Worker         CCryptoInfo cryptoInfo;
2022*f6dc9357SAndroid Build Coastguard Worker         const bool isOK = cryptoInfo.Parse(item.Extra + (unsigned)cryptoOffset, cryptoSize);
2023*f6dc9357SAndroid Build Coastguard Worker         if (cryptoInfo.Algo == 0)
2024*f6dc9357SAndroid Build Coastguard Worker           s = MyStpCpy(s, "AES");
2025*f6dc9357SAndroid Build Coastguard Worker         else
2026*f6dc9357SAndroid Build Coastguard Worker         {
2027*f6dc9357SAndroid Build Coastguard Worker           s = MyStpCpy(s, "Crypto_");
2028*f6dc9357SAndroid Build Coastguard Worker           s = ConvertUInt64ToString(cryptoInfo.Algo, s);
2029*f6dc9357SAndroid Build Coastguard Worker         }
2030*f6dc9357SAndroid Build Coastguard Worker         if (isOK)
2031*f6dc9357SAndroid Build Coastguard Worker         {
2032*f6dc9357SAndroid Build Coastguard Worker           *s++ = ':';
2033*f6dc9357SAndroid Build Coastguard Worker           s = ConvertUInt32ToString(cryptoInfo.Cnt, s);
2034*f6dc9357SAndroid Build Coastguard Worker           *s++ = ':';
2035*f6dc9357SAndroid Build Coastguard Worker           s = ConvertUInt64ToString(cryptoInfo.Flags, s);
2036*f6dc9357SAndroid Build Coastguard Worker         }
2037*f6dc9357SAndroid Build Coastguard Worker       }
2038*f6dc9357SAndroid Build Coastguard Worker       *s = 0;
2039*f6dc9357SAndroid Build Coastguard Worker       prop = temp;
2040*f6dc9357SAndroid Build Coastguard Worker       break;
2041*f6dc9357SAndroid Build Coastguard Worker     }
2042*f6dc9357SAndroid Build Coastguard Worker 
2043*f6dc9357SAndroid Build Coastguard Worker     case kpidCharacts:
2044*f6dc9357SAndroid Build Coastguard Worker     {
2045*f6dc9357SAndroid Build Coastguard Worker       AString s;
2046*f6dc9357SAndroid Build Coastguard Worker 
2047*f6dc9357SAndroid Build Coastguard Worker       if (item.ACL >= 0)
2048*f6dc9357SAndroid Build Coastguard Worker         s.Add_OptSpaced("ACL");
2049*f6dc9357SAndroid Build Coastguard Worker 
2050*f6dc9357SAndroid Build Coastguard Worker       const UInt32 flags = item.Flags;
2051*f6dc9357SAndroid Build Coastguard Worker       if (flags != 0)
2052*f6dc9357SAndroid Build Coastguard Worker       {
2053*f6dc9357SAndroid Build Coastguard Worker         const AString s2 = FlagsToString(k_FileFlags, Z7_ARRAY_SIZE(k_FileFlags), flags);
2054*f6dc9357SAndroid Build Coastguard Worker         if (!s2.IsEmpty())
2055*f6dc9357SAndroid Build Coastguard Worker           s.Add_OptSpaced(s2);
2056*f6dc9357SAndroid Build Coastguard Worker       }
2057*f6dc9357SAndroid Build Coastguard Worker 
2058*f6dc9357SAndroid Build Coastguard Worker       item.PrintInfo(s);
2059*f6dc9357SAndroid Build Coastguard Worker 
2060*f6dc9357SAndroid Build Coastguard Worker       if (!s.IsEmpty())
2061*f6dc9357SAndroid Build Coastguard Worker         prop = s;
2062*f6dc9357SAndroid Build Coastguard Worker       break;
2063*f6dc9357SAndroid Build Coastguard Worker     }
2064*f6dc9357SAndroid Build Coastguard Worker 
2065*f6dc9357SAndroid Build Coastguard Worker 
2066*f6dc9357SAndroid Build Coastguard Worker     case kpidHostOS:
2067*f6dc9357SAndroid Build Coastguard Worker       if (item.HostOS < Z7_ARRAY_SIZE(kHostOS))
2068*f6dc9357SAndroid Build Coastguard Worker         prop = kHostOS[(size_t)item.HostOS];
2069*f6dc9357SAndroid Build Coastguard Worker       else
2070*f6dc9357SAndroid Build Coastguard Worker         prop = (UInt64)item.HostOS;
2071*f6dc9357SAndroid Build Coastguard Worker       break;
2072*f6dc9357SAndroid Build Coastguard Worker   }
2073*f6dc9357SAndroid Build Coastguard Worker 
2074*f6dc9357SAndroid Build Coastguard Worker   prop.Detach(value);
2075*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
2076*f6dc9357SAndroid Build Coastguard Worker 
2077*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
2078*f6dc9357SAndroid Build Coastguard Worker }
2079*f6dc9357SAndroid Build Coastguard Worker 
2080*f6dc9357SAndroid Build Coastguard Worker 
2081*f6dc9357SAndroid Build Coastguard Worker 
2082*f6dc9357SAndroid Build Coastguard Worker // ---------- Copy Links ----------
2083*f6dc9357SAndroid Build Coastguard Worker 
2084*f6dc9357SAndroid Build Coastguard Worker static int CompareItemsPaths(const CHandler &handler, unsigned p1, unsigned p2, const AString *name1)
2085*f6dc9357SAndroid Build Coastguard Worker {
2086*f6dc9357SAndroid Build Coastguard Worker   const CItem &item1 = handler._items[handler._refs[p1].Item];
2087*f6dc9357SAndroid Build Coastguard Worker   const CItem &item2 = handler._items[handler._refs[p2].Item];
2088*f6dc9357SAndroid Build Coastguard Worker 
2089*f6dc9357SAndroid Build Coastguard Worker   if (item1.Version_Defined)
2090*f6dc9357SAndroid Build Coastguard Worker   {
2091*f6dc9357SAndroid Build Coastguard Worker     if (!item2.Version_Defined)
2092*f6dc9357SAndroid Build Coastguard Worker       return -1;
2093*f6dc9357SAndroid Build Coastguard Worker     const int res = MyCompare(item1.Version, item2.Version);
2094*f6dc9357SAndroid Build Coastguard Worker     if (res != 0)
2095*f6dc9357SAndroid Build Coastguard Worker       return res;
2096*f6dc9357SAndroid Build Coastguard Worker   }
2097*f6dc9357SAndroid Build Coastguard Worker   else if (item2.Version_Defined)
2098*f6dc9357SAndroid Build Coastguard Worker     return 1;
2099*f6dc9357SAndroid Build Coastguard Worker 
2100*f6dc9357SAndroid Build Coastguard Worker   if (!name1)
2101*f6dc9357SAndroid Build Coastguard Worker     name1 = &item1.Name;
2102*f6dc9357SAndroid Build Coastguard Worker   return strcmp(*name1, item2.Name);
2103*f6dc9357SAndroid Build Coastguard Worker }
2104*f6dc9357SAndroid Build Coastguard Worker 
2105*f6dc9357SAndroid Build Coastguard Worker static int CompareItemsPaths2(const CHandler &handler, unsigned p1, unsigned p2, const AString *name1)
2106*f6dc9357SAndroid Build Coastguard Worker {
2107*f6dc9357SAndroid Build Coastguard Worker   const int res = CompareItemsPaths(handler, p1, p2, name1);
2108*f6dc9357SAndroid Build Coastguard Worker   if (res != 0)
2109*f6dc9357SAndroid Build Coastguard Worker     return res;
2110*f6dc9357SAndroid Build Coastguard Worker   return MyCompare(p1, p2);
2111*f6dc9357SAndroid Build Coastguard Worker }
2112*f6dc9357SAndroid Build Coastguard Worker 
2113*f6dc9357SAndroid Build Coastguard Worker static int CompareItemsPaths_Sort(const unsigned *p1, const unsigned *p2, void *param)
2114*f6dc9357SAndroid Build Coastguard Worker {
2115*f6dc9357SAndroid Build Coastguard Worker   return CompareItemsPaths2(*(const CHandler *)param, *p1, *p2, NULL);
2116*f6dc9357SAndroid Build Coastguard Worker }
2117*f6dc9357SAndroid Build Coastguard Worker 
2118*f6dc9357SAndroid Build Coastguard Worker static int FindLink(const CHandler &handler, const CUIntVector &sorted,
2119*f6dc9357SAndroid Build Coastguard Worker     const AString &s, unsigned index)
2120*f6dc9357SAndroid Build Coastguard Worker {
2121*f6dc9357SAndroid Build Coastguard Worker   unsigned left = 0, right = sorted.Size();
2122*f6dc9357SAndroid Build Coastguard Worker   for (;;)
2123*f6dc9357SAndroid Build Coastguard Worker   {
2124*f6dc9357SAndroid Build Coastguard Worker     if (left == right)
2125*f6dc9357SAndroid Build Coastguard Worker     {
2126*f6dc9357SAndroid Build Coastguard Worker       if (left > 0)
2127*f6dc9357SAndroid Build Coastguard Worker       {
2128*f6dc9357SAndroid Build Coastguard Worker         const unsigned refIndex = sorted[left - 1];
2129*f6dc9357SAndroid Build Coastguard Worker         if (CompareItemsPaths(handler, index, refIndex, &s) == 0)
2130*f6dc9357SAndroid Build Coastguard Worker           return (int)refIndex;
2131*f6dc9357SAndroid Build Coastguard Worker       }
2132*f6dc9357SAndroid Build Coastguard Worker       if (right < sorted.Size())
2133*f6dc9357SAndroid Build Coastguard Worker       {
2134*f6dc9357SAndroid Build Coastguard Worker         const unsigned refIndex = sorted[right];
2135*f6dc9357SAndroid Build Coastguard Worker         if (CompareItemsPaths(handler, index, refIndex, &s) == 0)
2136*f6dc9357SAndroid Build Coastguard Worker           return (int)refIndex;
2137*f6dc9357SAndroid Build Coastguard Worker       }
2138*f6dc9357SAndroid Build Coastguard Worker       return -1;
2139*f6dc9357SAndroid Build Coastguard Worker     }
2140*f6dc9357SAndroid Build Coastguard Worker 
2141*f6dc9357SAndroid Build Coastguard Worker     const unsigned mid = (left + right) / 2;
2142*f6dc9357SAndroid Build Coastguard Worker     const unsigned refIndex = sorted[mid];
2143*f6dc9357SAndroid Build Coastguard Worker     const int compare = CompareItemsPaths2(handler, index, refIndex, &s);
2144*f6dc9357SAndroid Build Coastguard Worker     if (compare == 0)
2145*f6dc9357SAndroid Build Coastguard Worker       return (int)refIndex;
2146*f6dc9357SAndroid Build Coastguard Worker     if (compare < 0)
2147*f6dc9357SAndroid Build Coastguard Worker       right = mid;
2148*f6dc9357SAndroid Build Coastguard Worker     else
2149*f6dc9357SAndroid Build Coastguard Worker       left = mid + 1;
2150*f6dc9357SAndroid Build Coastguard Worker   }
2151*f6dc9357SAndroid Build Coastguard Worker }
2152*f6dc9357SAndroid Build Coastguard Worker 
2153*f6dc9357SAndroid Build Coastguard Worker void CHandler::FillLinks()
2154*f6dc9357SAndroid Build Coastguard Worker {
2155*f6dc9357SAndroid Build Coastguard Worker   unsigned i;
2156*f6dc9357SAndroid Build Coastguard Worker 
2157*f6dc9357SAndroid Build Coastguard Worker   bool need_FillLinks = false;
2158*f6dc9357SAndroid Build Coastguard Worker 
2159*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < _refs.Size(); i++)
2160*f6dc9357SAndroid Build Coastguard Worker   {
2161*f6dc9357SAndroid Build Coastguard Worker     const CItem &item = _items[_refs[i].Item];
2162*f6dc9357SAndroid Build Coastguard Worker     if (!item.IsDir()
2163*f6dc9357SAndroid Build Coastguard Worker         && !item.IsService()
2164*f6dc9357SAndroid Build Coastguard Worker         && item.NeedUse_as_CopyLink())
2165*f6dc9357SAndroid Build Coastguard Worker       need_FillLinks = true;
2166*f6dc9357SAndroid Build Coastguard Worker 
2167*f6dc9357SAndroid Build Coastguard Worker     if (!item.IsSolid())
2168*f6dc9357SAndroid Build Coastguard Worker       _numBlocks++;
2169*f6dc9357SAndroid Build Coastguard Worker 
2170*f6dc9357SAndroid Build Coastguard Worker     const unsigned algo = item.Get_AlgoVersion_RawBits();
2171*f6dc9357SAndroid Build Coastguard Worker     _algo_Mask |= (UInt64)1 << algo;
2172*f6dc9357SAndroid Build Coastguard Worker     _rar5comapt_mask |= 1u << item.Get_Rar5_CompatBit();
2173*f6dc9357SAndroid Build Coastguard Worker     if (!item.IsDir() && algo < Z7_ARRAY_SIZE(_methodMasks))
2174*f6dc9357SAndroid Build Coastguard Worker     {
2175*f6dc9357SAndroid Build Coastguard Worker       _methodMasks[algo] |= 1u << (item.Get_Method());
2176*f6dc9357SAndroid Build Coastguard Worker       UInt64 d = 32 + item.Get_DictSize_Frac();
2177*f6dc9357SAndroid Build Coastguard Worker       d <<= (12 + item.Get_DictSize_Main());
2178*f6dc9357SAndroid Build Coastguard Worker       if (_dictMaxSizes[algo] < d)
2179*f6dc9357SAndroid Build Coastguard Worker           _dictMaxSizes[algo] = d;
2180*f6dc9357SAndroid Build Coastguard Worker     }
2181*f6dc9357SAndroid Build Coastguard Worker   }
2182*f6dc9357SAndroid Build Coastguard Worker 
2183*f6dc9357SAndroid Build Coastguard Worker   if (!need_FillLinks)
2184*f6dc9357SAndroid Build Coastguard Worker     return;
2185*f6dc9357SAndroid Build Coastguard Worker 
2186*f6dc9357SAndroid Build Coastguard Worker   CUIntVector sorted;
2187*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < _refs.Size(); i++)
2188*f6dc9357SAndroid Build Coastguard Worker   {
2189*f6dc9357SAndroid Build Coastguard Worker     const CItem &item = _items[_refs[i].Item];
2190*f6dc9357SAndroid Build Coastguard Worker     if (!item.IsDir() && !item.IsService())
2191*f6dc9357SAndroid Build Coastguard Worker       sorted.Add(i);
2192*f6dc9357SAndroid Build Coastguard Worker   }
2193*f6dc9357SAndroid Build Coastguard Worker 
2194*f6dc9357SAndroid Build Coastguard Worker   if (sorted.IsEmpty())
2195*f6dc9357SAndroid Build Coastguard Worker     return;
2196*f6dc9357SAndroid Build Coastguard Worker 
2197*f6dc9357SAndroid Build Coastguard Worker   sorted.Sort(CompareItemsPaths_Sort, (void *)this);
2198*f6dc9357SAndroid Build Coastguard Worker 
2199*f6dc9357SAndroid Build Coastguard Worker   AString link;
2200*f6dc9357SAndroid Build Coastguard Worker 
2201*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < _refs.Size(); i++)
2202*f6dc9357SAndroid Build Coastguard Worker   {
2203*f6dc9357SAndroid Build Coastguard Worker     CRefItem &ref = _refs[i];
2204*f6dc9357SAndroid Build Coastguard Worker     const CItem &item = _items[ref.Item];
2205*f6dc9357SAndroid Build Coastguard Worker     if (item.IsDir() || item.IsService() || item.PackSize != 0)
2206*f6dc9357SAndroid Build Coastguard Worker       continue;
2207*f6dc9357SAndroid Build Coastguard Worker     CLinkInfo linkInfo;
2208*f6dc9357SAndroid Build Coastguard Worker     if (!item.FindExtra_Link(linkInfo) || linkInfo.Type != NLinkType::kFileCopy)
2209*f6dc9357SAndroid Build Coastguard Worker       continue;
2210*f6dc9357SAndroid Build Coastguard Worker     link.SetFrom_CalcLen((const char *)(item.Extra + linkInfo.NameOffset), linkInfo.NameLen);
2211*f6dc9357SAndroid Build Coastguard Worker     const int linkIndex = FindLink(*this, sorted, link, i);
2212*f6dc9357SAndroid Build Coastguard Worker     if (linkIndex < 0)
2213*f6dc9357SAndroid Build Coastguard Worker       continue;
2214*f6dc9357SAndroid Build Coastguard Worker     if ((unsigned)linkIndex >= i)
2215*f6dc9357SAndroid Build Coastguard Worker       continue; // we don't support forward links that can lead to loops
2216*f6dc9357SAndroid Build Coastguard Worker     const CRefItem &linkRef = _refs[linkIndex];
2217*f6dc9357SAndroid Build Coastguard Worker     const CItem &linkItem = _items[linkRef.Item];
2218*f6dc9357SAndroid Build Coastguard Worker     if (linkItem.Size == item.Size)
2219*f6dc9357SAndroid Build Coastguard Worker     {
2220*f6dc9357SAndroid Build Coastguard Worker       if (linkRef.Link >= 0)
2221*f6dc9357SAndroid Build Coastguard Worker         ref.Link = linkRef.Link;
2222*f6dc9357SAndroid Build Coastguard Worker       else if (!linkItem.NeedUse_as_CopyLink())
2223*f6dc9357SAndroid Build Coastguard Worker         ref.Link = linkIndex;
2224*f6dc9357SAndroid Build Coastguard Worker     }
2225*f6dc9357SAndroid Build Coastguard Worker   }
2226*f6dc9357SAndroid Build Coastguard Worker }
2227*f6dc9357SAndroid Build Coastguard Worker 
2228*f6dc9357SAndroid Build Coastguard Worker 
2229*f6dc9357SAndroid Build Coastguard Worker 
2230*f6dc9357SAndroid Build Coastguard Worker HRESULT CHandler::Open2(IInStream *stream,
2231*f6dc9357SAndroid Build Coastguard Worker     const UInt64 *maxCheckStartPosition,
2232*f6dc9357SAndroid Build Coastguard Worker     IArchiveOpenCallback *openCallback)
2233*f6dc9357SAndroid Build Coastguard Worker {
2234*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
2235*f6dc9357SAndroid Build Coastguard Worker   // CMyComPtr<ICryptoGetTextPassword> getTextPassword;
2236*f6dc9357SAndroid Build Coastguard Worker   NRar::CVolumeName seqName;
2237*f6dc9357SAndroid Build Coastguard Worker   CTempBuf tempBuf;
2238*f6dc9357SAndroid Build Coastguard Worker   CUnpacker unpacker;
2239*f6dc9357SAndroid Build Coastguard Worker 
2240*f6dc9357SAndroid Build Coastguard Worker   if (openCallback)
2241*f6dc9357SAndroid Build Coastguard Worker   {
2242*f6dc9357SAndroid Build Coastguard Worker     openCallback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback);
2243*f6dc9357SAndroid Build Coastguard Worker     openCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&unpacker.getTextPassword);
2244*f6dc9357SAndroid Build Coastguard Worker   }
2245*f6dc9357SAndroid Build Coastguard Worker   // unpacker.getTextPassword = getTextPassword;
2246*f6dc9357SAndroid Build Coastguard Worker 
2247*f6dc9357SAndroid Build Coastguard Worker   CInArchive arch;
2248*f6dc9357SAndroid Build Coastguard Worker   int prevSplitFile = -1;
2249*f6dc9357SAndroid Build Coastguard Worker   int prevMainFile = -1;
2250*f6dc9357SAndroid Build Coastguard Worker   UInt64 totalBytes = 0;
2251*f6dc9357SAndroid Build Coastguard Worker   UInt64 curBytes = 0;
2252*f6dc9357SAndroid Build Coastguard Worker   bool nextVol_is_Required = false;
2253*f6dc9357SAndroid Build Coastguard Worker 
2254*f6dc9357SAndroid Build Coastguard Worker   for (;;)
2255*f6dc9357SAndroid Build Coastguard Worker   {
2256*f6dc9357SAndroid Build Coastguard Worker     CMyComPtr<IInStream> inStream;
2257*f6dc9357SAndroid Build Coastguard Worker 
2258*f6dc9357SAndroid Build Coastguard Worker     if (_arcs.IsEmpty())
2259*f6dc9357SAndroid Build Coastguard Worker       inStream = stream;
2260*f6dc9357SAndroid Build Coastguard Worker     else
2261*f6dc9357SAndroid Build Coastguard Worker     {
2262*f6dc9357SAndroid Build Coastguard Worker       if (!openVolumeCallback)
2263*f6dc9357SAndroid Build Coastguard Worker         break;
2264*f6dc9357SAndroid Build Coastguard Worker       if (_arcs.Size() == 1)
2265*f6dc9357SAndroid Build Coastguard Worker       {
2266*f6dc9357SAndroid Build Coastguard Worker         UString baseName;
2267*f6dc9357SAndroid Build Coastguard Worker         {
2268*f6dc9357SAndroid Build Coastguard Worker           NCOM::CPropVariant prop;
2269*f6dc9357SAndroid Build Coastguard Worker           RINOK(openVolumeCallback->GetProperty(kpidName, &prop))
2270*f6dc9357SAndroid Build Coastguard Worker           if (prop.vt != VT_BSTR)
2271*f6dc9357SAndroid Build Coastguard Worker             break;
2272*f6dc9357SAndroid Build Coastguard Worker           baseName = prop.bstrVal;
2273*f6dc9357SAndroid Build Coastguard Worker         }
2274*f6dc9357SAndroid Build Coastguard Worker         if (!seqName.InitName(baseName))
2275*f6dc9357SAndroid Build Coastguard Worker           break;
2276*f6dc9357SAndroid Build Coastguard Worker       }
2277*f6dc9357SAndroid Build Coastguard Worker       const UString volName = seqName.GetNextName();
2278*f6dc9357SAndroid Build Coastguard Worker       const HRESULT result = openVolumeCallback->GetStream(volName, &inStream);
2279*f6dc9357SAndroid Build Coastguard Worker       if (result != S_OK && result != S_FALSE)
2280*f6dc9357SAndroid Build Coastguard Worker         return result;
2281*f6dc9357SAndroid Build Coastguard Worker       if (!inStream || result != S_OK)
2282*f6dc9357SAndroid Build Coastguard Worker       {
2283*f6dc9357SAndroid Build Coastguard Worker         if (nextVol_is_Required)
2284*f6dc9357SAndroid Build Coastguard Worker           _missingVolName = volName;
2285*f6dc9357SAndroid Build Coastguard Worker         break;
2286*f6dc9357SAndroid Build Coastguard Worker       }
2287*f6dc9357SAndroid Build Coastguard Worker     }
2288*f6dc9357SAndroid Build Coastguard Worker 
2289*f6dc9357SAndroid Build Coastguard Worker     UInt64 endPos = 0;
2290*f6dc9357SAndroid Build Coastguard Worker     RINOK(InStream_GetPos_GetSize(inStream, arch.StreamStartPosition, endPos))
2291*f6dc9357SAndroid Build Coastguard Worker 
2292*f6dc9357SAndroid Build Coastguard Worker     if (openCallback)
2293*f6dc9357SAndroid Build Coastguard Worker     {
2294*f6dc9357SAndroid Build Coastguard Worker       totalBytes += endPos;
2295*f6dc9357SAndroid Build Coastguard Worker       RINOK(openCallback->SetTotal(NULL, &totalBytes))
2296*f6dc9357SAndroid Build Coastguard Worker     }
2297*f6dc9357SAndroid Build Coastguard Worker 
2298*f6dc9357SAndroid Build Coastguard Worker     CInArcInfo arcInfo_Open;
2299*f6dc9357SAndroid Build Coastguard Worker     {
2300*f6dc9357SAndroid Build Coastguard Worker       const HRESULT res = arch.Open(inStream, maxCheckStartPosition, unpacker.getTextPassword, arcInfo_Open);
2301*f6dc9357SAndroid Build Coastguard Worker       if (arch.IsArc && arch.UnexpectedEnd)
2302*f6dc9357SAndroid Build Coastguard Worker         _errorFlags |= kpv_ErrorFlags_UnexpectedEnd;
2303*f6dc9357SAndroid Build Coastguard Worker       if (_arcs.IsEmpty())
2304*f6dc9357SAndroid Build Coastguard Worker         _isArc = arch.IsArc;
2305*f6dc9357SAndroid Build Coastguard Worker       if (res != S_OK)
2306*f6dc9357SAndroid Build Coastguard Worker       {
2307*f6dc9357SAndroid Build Coastguard Worker         if (res != S_FALSE)
2308*f6dc9357SAndroid Build Coastguard Worker           return res;
2309*f6dc9357SAndroid Build Coastguard Worker         if (_arcs.IsEmpty())
2310*f6dc9357SAndroid Build Coastguard Worker           return res;
2311*f6dc9357SAndroid Build Coastguard Worker         break;
2312*f6dc9357SAndroid Build Coastguard Worker       }
2313*f6dc9357SAndroid Build Coastguard Worker     }
2314*f6dc9357SAndroid Build Coastguard Worker 
2315*f6dc9357SAndroid Build Coastguard Worker     CArc &arc = _arcs.AddNew();
2316*f6dc9357SAndroid Build Coastguard Worker     CInArcInfo &arcInfo = arc.Info;
2317*f6dc9357SAndroid Build Coastguard Worker     arcInfo = arcInfo_Open;
2318*f6dc9357SAndroid Build Coastguard Worker     arc.Stream = inStream;
2319*f6dc9357SAndroid Build Coastguard Worker 
2320*f6dc9357SAndroid Build Coastguard Worker     CItem item;
2321*f6dc9357SAndroid Build Coastguard Worker 
2322*f6dc9357SAndroid Build Coastguard Worker     for (;;)
2323*f6dc9357SAndroid Build Coastguard Worker     {
2324*f6dc9357SAndroid Build Coastguard Worker       item.Clear();
2325*f6dc9357SAndroid Build Coastguard Worker 
2326*f6dc9357SAndroid Build Coastguard Worker       arcInfo.EndPos = arch.Position;
2327*f6dc9357SAndroid Build Coastguard Worker       if (arch.Position > endPos)
2328*f6dc9357SAndroid Build Coastguard Worker       {
2329*f6dc9357SAndroid Build Coastguard Worker         _errorFlags |= kpv_ErrorFlags_UnexpectedEnd;
2330*f6dc9357SAndroid Build Coastguard Worker         break;
2331*f6dc9357SAndroid Build Coastguard Worker       }
2332*f6dc9357SAndroid Build Coastguard Worker       RINOK(InStream_SeekSet(inStream, arch.Position))
2333*f6dc9357SAndroid Build Coastguard Worker 
2334*f6dc9357SAndroid Build Coastguard Worker       {
2335*f6dc9357SAndroid Build Coastguard Worker         CInArchive::CHeader h;
2336*f6dc9357SAndroid Build Coastguard Worker         const HRESULT res = arch.ReadBlockHeader(h);
2337*f6dc9357SAndroid Build Coastguard Worker         if (res != S_OK)
2338*f6dc9357SAndroid Build Coastguard Worker         {
2339*f6dc9357SAndroid Build Coastguard Worker           if (res != S_FALSE)
2340*f6dc9357SAndroid Build Coastguard Worker             return res;
2341*f6dc9357SAndroid Build Coastguard Worker           if (arch.UnexpectedEnd)
2342*f6dc9357SAndroid Build Coastguard Worker           {
2343*f6dc9357SAndroid Build Coastguard Worker             _errorFlags |= kpv_ErrorFlags_UnexpectedEnd;
2344*f6dc9357SAndroid Build Coastguard Worker             if (arcInfo.EndPos < arch.Position)
2345*f6dc9357SAndroid Build Coastguard Worker                 arcInfo.EndPos = arch.Position;
2346*f6dc9357SAndroid Build Coastguard Worker             if (arcInfo.EndPos < endPos)
2347*f6dc9357SAndroid Build Coastguard Worker                 arcInfo.EndPos = endPos;
2348*f6dc9357SAndroid Build Coastguard Worker           }
2349*f6dc9357SAndroid Build Coastguard Worker           else
2350*f6dc9357SAndroid Build Coastguard Worker             _errorFlags |= kpv_ErrorFlags_HeadersError;
2351*f6dc9357SAndroid Build Coastguard Worker           break;
2352*f6dc9357SAndroid Build Coastguard Worker         }
2353*f6dc9357SAndroid Build Coastguard Worker 
2354*f6dc9357SAndroid Build Coastguard Worker         if (h.Type == NHeaderType::kEndOfArc)
2355*f6dc9357SAndroid Build Coastguard Worker         {
2356*f6dc9357SAndroid Build Coastguard Worker           arcInfo.EndPos = arch.Position;
2357*f6dc9357SAndroid Build Coastguard Worker           arcInfo.EndOfArchive_was_Read = true;
2358*f6dc9357SAndroid Build Coastguard Worker           if (!arch.ReadVar(arcInfo.EndFlags))
2359*f6dc9357SAndroid Build Coastguard Worker             _errorFlags |= kpv_ErrorFlags_HeadersError;
2360*f6dc9357SAndroid Build Coastguard Worker           if (!arch.Is_Buf_Finished() || h.ExtraSize || h.DataSize)
2361*f6dc9357SAndroid Build Coastguard Worker             arcInfo.UnsupportedFeature = true;
2362*f6dc9357SAndroid Build Coastguard Worker           if (arcInfo.IsVolume())
2363*f6dc9357SAndroid Build Coastguard Worker           {
2364*f6dc9357SAndroid Build Coastguard Worker             // for multivolume archives RAR can add ZERO bytes at the end for alignment.
2365*f6dc9357SAndroid Build Coastguard Worker             // We must skip these bytes to prevent phySize warning.
2366*f6dc9357SAndroid Build Coastguard Worker             RINOK(InStream_SeekSet(inStream, arcInfo.EndPos))
2367*f6dc9357SAndroid Build Coastguard Worker             bool areThereNonZeros;
2368*f6dc9357SAndroid Build Coastguard Worker             UInt64 numZeros;
2369*f6dc9357SAndroid Build Coastguard Worker             const UInt64 maxSize = 1 << 12;
2370*f6dc9357SAndroid Build Coastguard Worker             RINOK(ReadZeroTail(inStream, areThereNonZeros, numZeros, maxSize))
2371*f6dc9357SAndroid Build Coastguard Worker             if (!areThereNonZeros && numZeros != 0 && numZeros <= maxSize)
2372*f6dc9357SAndroid Build Coastguard Worker               arcInfo.EndPos += numZeros;
2373*f6dc9357SAndroid Build Coastguard Worker           }
2374*f6dc9357SAndroid Build Coastguard Worker           break;
2375*f6dc9357SAndroid Build Coastguard Worker         }
2376*f6dc9357SAndroid Build Coastguard Worker 
2377*f6dc9357SAndroid Build Coastguard Worker         if (h.Type != NHeaderType::kFile &&
2378*f6dc9357SAndroid Build Coastguard Worker             h.Type != NHeaderType::kService)
2379*f6dc9357SAndroid Build Coastguard Worker         {
2380*f6dc9357SAndroid Build Coastguard Worker           _errorFlags |= kpv_ErrorFlags_UnsupportedFeature;
2381*f6dc9357SAndroid Build Coastguard Worker           break;
2382*f6dc9357SAndroid Build Coastguard Worker         }
2383*f6dc9357SAndroid Build Coastguard Worker 
2384*f6dc9357SAndroid Build Coastguard Worker         item.RecordType = (Byte)h.Type;
2385*f6dc9357SAndroid Build Coastguard Worker         if (!arch.ReadFileHeader(h, item))
2386*f6dc9357SAndroid Build Coastguard Worker         {
2387*f6dc9357SAndroid Build Coastguard Worker           _errorFlags |= kpv_ErrorFlags_HeadersError;
2388*f6dc9357SAndroid Build Coastguard Worker           break;
2389*f6dc9357SAndroid Build Coastguard Worker         }
2390*f6dc9357SAndroid Build Coastguard Worker         item.DataPos = arch.Position;
2391*f6dc9357SAndroid Build Coastguard Worker       }
2392*f6dc9357SAndroid Build Coastguard Worker 
2393*f6dc9357SAndroid Build Coastguard Worker       bool isOk_packSize = true;
2394*f6dc9357SAndroid Build Coastguard Worker       {
2395*f6dc9357SAndroid Build Coastguard Worker         arcInfo.EndPos = arch.Position;
2396*f6dc9357SAndroid Build Coastguard Worker         if (arch.Position + item.PackSize < arch.Position)
2397*f6dc9357SAndroid Build Coastguard Worker         {
2398*f6dc9357SAndroid Build Coastguard Worker           isOk_packSize = false;
2399*f6dc9357SAndroid Build Coastguard Worker           _errorFlags |= kpv_ErrorFlags_HeadersError;
2400*f6dc9357SAndroid Build Coastguard Worker           if (arcInfo.EndPos < endPos)
2401*f6dc9357SAndroid Build Coastguard Worker               arcInfo.EndPos = endPos;
2402*f6dc9357SAndroid Build Coastguard Worker         }
2403*f6dc9357SAndroid Build Coastguard Worker         else
2404*f6dc9357SAndroid Build Coastguard Worker         {
2405*f6dc9357SAndroid Build Coastguard Worker           arch.AddToSeekValue(item.PackSize); // Position points to next header;
2406*f6dc9357SAndroid Build Coastguard Worker           arcInfo.EndPos = arch.Position;
2407*f6dc9357SAndroid Build Coastguard Worker         }
2408*f6dc9357SAndroid Build Coastguard Worker       }
2409*f6dc9357SAndroid Build Coastguard Worker 
2410*f6dc9357SAndroid Build Coastguard Worker       bool needAdd = true;
2411*f6dc9357SAndroid Build Coastguard Worker 
2412*f6dc9357SAndroid Build Coastguard Worker       if (!_comment_WasUsedInArc
2413*f6dc9357SAndroid Build Coastguard Worker           && _comment.Size() == 0
2414*f6dc9357SAndroid Build Coastguard Worker           && item.Is_CMT())
2415*f6dc9357SAndroid Build Coastguard Worker       {
2416*f6dc9357SAndroid Build Coastguard Worker         _comment_WasUsedInArc = true;
2417*f6dc9357SAndroid Build Coastguard Worker         if (   item.PackSize <= kCommentSize_Max
2418*f6dc9357SAndroid Build Coastguard Worker             && item.PackSize == item.Size
2419*f6dc9357SAndroid Build Coastguard Worker             && item.PackSize != 0
2420*f6dc9357SAndroid Build Coastguard Worker             && item.Get_Method() == 0
2421*f6dc9357SAndroid Build Coastguard Worker             && !item.IsSplit())
2422*f6dc9357SAndroid Build Coastguard Worker         {
2423*f6dc9357SAndroid Build Coastguard Worker           RINOK(unpacker.DecodeToBuf(EXTERNAL_CODECS_VARS item, item.PackSize, inStream, _comment))
2424*f6dc9357SAndroid Build Coastguard Worker           needAdd = false;
2425*f6dc9357SAndroid Build Coastguard Worker           // item.RecordType = (Byte)NHeaderType::kFile; // for debug
2426*f6dc9357SAndroid Build Coastguard Worker         }
2427*f6dc9357SAndroid Build Coastguard Worker       }
2428*f6dc9357SAndroid Build Coastguard Worker 
2429*f6dc9357SAndroid Build Coastguard Worker       CRefItem ref;
2430*f6dc9357SAndroid Build Coastguard Worker       ref.Item = _items.Size();
2431*f6dc9357SAndroid Build Coastguard Worker       ref.Last = ref.Item;
2432*f6dc9357SAndroid Build Coastguard Worker       ref.Parent = -1;
2433*f6dc9357SAndroid Build Coastguard Worker       ref.Link = -1;
2434*f6dc9357SAndroid Build Coastguard Worker 
2435*f6dc9357SAndroid Build Coastguard Worker       if (needAdd)
2436*f6dc9357SAndroid Build Coastguard Worker       {
2437*f6dc9357SAndroid Build Coastguard Worker         if (item.IsService())
2438*f6dc9357SAndroid Build Coastguard Worker         {
2439*f6dc9357SAndroid Build Coastguard Worker           if (item.Is_STM())
2440*f6dc9357SAndroid Build Coastguard Worker           {
2441*f6dc9357SAndroid Build Coastguard Worker             if (prevMainFile >= 0)
2442*f6dc9357SAndroid Build Coastguard Worker               ref.Parent = prevMainFile;
2443*f6dc9357SAndroid Build Coastguard Worker           }
2444*f6dc9357SAndroid Build Coastguard Worker           else
2445*f6dc9357SAndroid Build Coastguard Worker           {
2446*f6dc9357SAndroid Build Coastguard Worker             needAdd = false;
2447*f6dc9357SAndroid Build Coastguard Worker             if (item.Is_ACL())
2448*f6dc9357SAndroid Build Coastguard Worker             {
2449*f6dc9357SAndroid Build Coastguard Worker               _acl_Used = true;
2450*f6dc9357SAndroid Build Coastguard Worker               if (item.IsEncrypted() && !arch.m_CryptoMode)
2451*f6dc9357SAndroid Build Coastguard Worker                 _error_in_ACL = true;
2452*f6dc9357SAndroid Build Coastguard Worker               else if (item.IsSolid()
2453*f6dc9357SAndroid Build Coastguard Worker                   || prevMainFile < 0
2454*f6dc9357SAndroid Build Coastguard Worker                   || item.Size >= (1 << 24)
2455*f6dc9357SAndroid Build Coastguard Worker                   || item.Size == 0)
2456*f6dc9357SAndroid Build Coastguard Worker                 _error_in_ACL = true;
2457*f6dc9357SAndroid Build Coastguard Worker               if (prevMainFile >= 0 && item.Size < (1 << 24) && item.Size != 0)
2458*f6dc9357SAndroid Build Coastguard Worker               {
2459*f6dc9357SAndroid Build Coastguard Worker                 CItem &mainItem = _items[_refs[prevMainFile].Item];
2460*f6dc9357SAndroid Build Coastguard Worker 
2461*f6dc9357SAndroid Build Coastguard Worker                 if (mainItem.ACL < 0)
2462*f6dc9357SAndroid Build Coastguard Worker                 {
2463*f6dc9357SAndroid Build Coastguard Worker                   CByteBuffer acl;
2464*f6dc9357SAndroid Build Coastguard Worker                   const HRESULT res = tempBuf.Decode(EXTERNAL_CODECS_VARS item, inStream, unpacker, acl);
2465*f6dc9357SAndroid Build Coastguard Worker                   if (!item.IsSplitAfter())
2466*f6dc9357SAndroid Build Coastguard Worker                     tempBuf.Clear();
2467*f6dc9357SAndroid Build Coastguard Worker                   if (res != S_OK)
2468*f6dc9357SAndroid Build Coastguard Worker                   {
2469*f6dc9357SAndroid Build Coastguard Worker                     tempBuf.Clear();
2470*f6dc9357SAndroid Build Coastguard Worker                     if (res != S_FALSE && res != E_NOTIMPL)
2471*f6dc9357SAndroid Build Coastguard Worker                       return res;
2472*f6dc9357SAndroid Build Coastguard Worker                     _error_in_ACL = true;
2473*f6dc9357SAndroid Build Coastguard Worker                   }
2474*f6dc9357SAndroid Build Coastguard Worker                   else if (acl.Size() != 0)
2475*f6dc9357SAndroid Build Coastguard Worker                   {
2476*f6dc9357SAndroid Build Coastguard Worker                     if (_acls.IsEmpty() || acl != _acls.Back())
2477*f6dc9357SAndroid Build Coastguard Worker                       _acls.Add(acl);
2478*f6dc9357SAndroid Build Coastguard Worker                     mainItem.ACL = (int)_acls.Size() - 1;
2479*f6dc9357SAndroid Build Coastguard Worker                   }
2480*f6dc9357SAndroid Build Coastguard Worker                 }
2481*f6dc9357SAndroid Build Coastguard Worker               }
2482*f6dc9357SAndroid Build Coastguard Worker             }
2483*f6dc9357SAndroid Build Coastguard Worker           }
2484*f6dc9357SAndroid Build Coastguard Worker         } // item.IsService()
2485*f6dc9357SAndroid Build Coastguard Worker 
2486*f6dc9357SAndroid Build Coastguard Worker         if (needAdd)
2487*f6dc9357SAndroid Build Coastguard Worker         {
2488*f6dc9357SAndroid Build Coastguard Worker           if (item.IsSplitBefore())
2489*f6dc9357SAndroid Build Coastguard Worker           {
2490*f6dc9357SAndroid Build Coastguard Worker             if (prevSplitFile >= 0)
2491*f6dc9357SAndroid Build Coastguard Worker             {
2492*f6dc9357SAndroid Build Coastguard Worker               CRefItem &ref2 = _refs[prevSplitFile];
2493*f6dc9357SAndroid Build Coastguard Worker               CItem &prevItem = _items[ref2.Last];
2494*f6dc9357SAndroid Build Coastguard Worker               if (item.IsNextForItem(prevItem))
2495*f6dc9357SAndroid Build Coastguard Worker               {
2496*f6dc9357SAndroid Build Coastguard Worker                 ref2.Last = _items.Size();
2497*f6dc9357SAndroid Build Coastguard Worker                 prevItem.NextItem = (int)ref2.Last;
2498*f6dc9357SAndroid Build Coastguard Worker                 needAdd = false;
2499*f6dc9357SAndroid Build Coastguard Worker               }
2500*f6dc9357SAndroid Build Coastguard Worker             }
2501*f6dc9357SAndroid Build Coastguard Worker             else
2502*f6dc9357SAndroid Build Coastguard Worker               _split_Error = true;
2503*f6dc9357SAndroid Build Coastguard Worker           }
2504*f6dc9357SAndroid Build Coastguard Worker         }
2505*f6dc9357SAndroid Build Coastguard Worker 
2506*f6dc9357SAndroid Build Coastguard Worker         if (needAdd)
2507*f6dc9357SAndroid Build Coastguard Worker         {
2508*f6dc9357SAndroid Build Coastguard Worker           if (item.IsSplitAfter())
2509*f6dc9357SAndroid Build Coastguard Worker             prevSplitFile = (int)_refs.Size();
2510*f6dc9357SAndroid Build Coastguard Worker           if (!item.IsService())
2511*f6dc9357SAndroid Build Coastguard Worker             prevMainFile = (int)_refs.Size();
2512*f6dc9357SAndroid Build Coastguard Worker         }
2513*f6dc9357SAndroid Build Coastguard Worker       }
2514*f6dc9357SAndroid Build Coastguard Worker 
2515*f6dc9357SAndroid Build Coastguard Worker       {
2516*f6dc9357SAndroid Build Coastguard Worker         UInt64 version;
2517*f6dc9357SAndroid Build Coastguard Worker         if (item.FindExtra_Version(version))
2518*f6dc9357SAndroid Build Coastguard Worker         {
2519*f6dc9357SAndroid Build Coastguard Worker           item.Version_Defined = true;
2520*f6dc9357SAndroid Build Coastguard Worker           item.Version = version;
2521*f6dc9357SAndroid Build Coastguard Worker         }
2522*f6dc9357SAndroid Build Coastguard Worker       }
2523*f6dc9357SAndroid Build Coastguard Worker 
2524*f6dc9357SAndroid Build Coastguard Worker       item.VolIndex = _arcs.Size() - 1;
2525*f6dc9357SAndroid Build Coastguard Worker       _items.Add(item);
2526*f6dc9357SAndroid Build Coastguard Worker       if (needAdd)
2527*f6dc9357SAndroid Build Coastguard Worker         _refs.Add(ref);
2528*f6dc9357SAndroid Build Coastguard Worker 
2529*f6dc9357SAndroid Build Coastguard Worker       if (openCallback && (_items.Size() & 0xFF) == 0)
2530*f6dc9357SAndroid Build Coastguard Worker       {
2531*f6dc9357SAndroid Build Coastguard Worker         const UInt64 numFiles = _refs.Size(); // _items.Size()
2532*f6dc9357SAndroid Build Coastguard Worker         const UInt64 numBytes = curBytes + item.DataPos;
2533*f6dc9357SAndroid Build Coastguard Worker         RINOK(openCallback->SetCompleted(&numFiles, &numBytes))
2534*f6dc9357SAndroid Build Coastguard Worker       }
2535*f6dc9357SAndroid Build Coastguard Worker 
2536*f6dc9357SAndroid Build Coastguard Worker       if (!isOk_packSize)
2537*f6dc9357SAndroid Build Coastguard Worker         break;
2538*f6dc9357SAndroid Build Coastguard Worker     }
2539*f6dc9357SAndroid Build Coastguard Worker 
2540*f6dc9357SAndroid Build Coastguard Worker     curBytes += endPos;
2541*f6dc9357SAndroid Build Coastguard Worker 
2542*f6dc9357SAndroid Build Coastguard Worker     nextVol_is_Required = false;
2543*f6dc9357SAndroid Build Coastguard Worker 
2544*f6dc9357SAndroid Build Coastguard Worker     if (!arcInfo.IsVolume())
2545*f6dc9357SAndroid Build Coastguard Worker       break;
2546*f6dc9357SAndroid Build Coastguard Worker 
2547*f6dc9357SAndroid Build Coastguard Worker     if (arcInfo.EndOfArchive_was_Read)
2548*f6dc9357SAndroid Build Coastguard Worker     {
2549*f6dc9357SAndroid Build Coastguard Worker       if (!arcInfo.AreMoreVolumes())
2550*f6dc9357SAndroid Build Coastguard Worker         break;
2551*f6dc9357SAndroid Build Coastguard Worker       nextVol_is_Required = true;
2552*f6dc9357SAndroid Build Coastguard Worker     }
2553*f6dc9357SAndroid Build Coastguard Worker   }
2554*f6dc9357SAndroid Build Coastguard Worker 
2555*f6dc9357SAndroid Build Coastguard Worker   FillLinks();
2556*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
2557*f6dc9357SAndroid Build Coastguard Worker }
2558*f6dc9357SAndroid Build Coastguard Worker 
2559*f6dc9357SAndroid Build Coastguard Worker 
2560*f6dc9357SAndroid Build Coastguard Worker 
2561*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Open(IInStream *stream,
2562*f6dc9357SAndroid Build Coastguard Worker     const UInt64 *maxCheckStartPosition,
2563*f6dc9357SAndroid Build Coastguard Worker     IArchiveOpenCallback *openCallback))
2564*f6dc9357SAndroid Build Coastguard Worker {
2565*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
2566*f6dc9357SAndroid Build Coastguard Worker   Close();
2567*f6dc9357SAndroid Build Coastguard Worker   return Open2(stream, maxCheckStartPosition, openCallback);
2568*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
2569*f6dc9357SAndroid Build Coastguard Worker }
2570*f6dc9357SAndroid Build Coastguard Worker 
2571*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Close())
2572*f6dc9357SAndroid Build Coastguard Worker {
2573*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
2574*f6dc9357SAndroid Build Coastguard Worker   _missingVolName.Empty();
2575*f6dc9357SAndroid Build Coastguard Worker   _errorFlags = 0;
2576*f6dc9357SAndroid Build Coastguard Worker   // _warningFlags = 0;
2577*f6dc9357SAndroid Build Coastguard Worker   _isArc = false;
2578*f6dc9357SAndroid Build Coastguard Worker   _comment_WasUsedInArc = false;
2579*f6dc9357SAndroid Build Coastguard Worker   _acl_Used = false;
2580*f6dc9357SAndroid Build Coastguard Worker   _error_in_ACL = false;
2581*f6dc9357SAndroid Build Coastguard Worker   _split_Error = false;
2582*f6dc9357SAndroid Build Coastguard Worker   _numBlocks = 0;
2583*f6dc9357SAndroid Build Coastguard Worker   _rar5comapt_mask = 0;
2584*f6dc9357SAndroid Build Coastguard Worker   _algo_Mask = 0; // (UInt64)0u - 1;
2585*f6dc9357SAndroid Build Coastguard Worker   for (unsigned i = 0; i < Z7_ARRAY_SIZE(_methodMasks); i++)
2586*f6dc9357SAndroid Build Coastguard Worker   {
2587*f6dc9357SAndroid Build Coastguard Worker     _methodMasks[i] = 0;
2588*f6dc9357SAndroid Build Coastguard Worker     _dictMaxSizes[i] = 0;
2589*f6dc9357SAndroid Build Coastguard Worker   }
2590*f6dc9357SAndroid Build Coastguard Worker 
2591*f6dc9357SAndroid Build Coastguard Worker   _refs.Clear();
2592*f6dc9357SAndroid Build Coastguard Worker   _items.Clear();
2593*f6dc9357SAndroid Build Coastguard Worker   _arcs.Clear();
2594*f6dc9357SAndroid Build Coastguard Worker   _acls.Clear();
2595*f6dc9357SAndroid Build Coastguard Worker   _comment.Free();
2596*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
2597*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
2598*f6dc9357SAndroid Build Coastguard Worker }
2599*f6dc9357SAndroid Build Coastguard Worker 
2600*f6dc9357SAndroid Build Coastguard Worker 
2601*f6dc9357SAndroid Build Coastguard Worker Z7_CLASS_IMP_NOQIB_1(
2602*f6dc9357SAndroid Build Coastguard Worker   CVolsInStream
2603*f6dc9357SAndroid Build Coastguard Worker   , ISequentialInStream
2604*f6dc9357SAndroid Build Coastguard Worker )
2605*f6dc9357SAndroid Build Coastguard Worker   UInt64 _rem;
2606*f6dc9357SAndroid Build Coastguard Worker   ISequentialInStream *_stream;
2607*f6dc9357SAndroid Build Coastguard Worker   const CObjectVector<CArc> *_arcs;
2608*f6dc9357SAndroid Build Coastguard Worker   const CObjectVector<CItem> *_items;
2609*f6dc9357SAndroid Build Coastguard Worker   int _itemIndex;
2610*f6dc9357SAndroid Build Coastguard Worker public:
2611*f6dc9357SAndroid Build Coastguard Worker   bool CrcIsOK;
2612*f6dc9357SAndroid Build Coastguard Worker private:
2613*f6dc9357SAndroid Build Coastguard Worker   CHash _hash;
2614*f6dc9357SAndroid Build Coastguard Worker public:
2615*f6dc9357SAndroid Build Coastguard Worker   void Init(const CObjectVector<CArc> *arcs,
2616*f6dc9357SAndroid Build Coastguard Worker       const CObjectVector<CItem> *items,
2617*f6dc9357SAndroid Build Coastguard Worker       unsigned itemIndex)
2618*f6dc9357SAndroid Build Coastguard Worker   {
2619*f6dc9357SAndroid Build Coastguard Worker     _arcs = arcs;
2620*f6dc9357SAndroid Build Coastguard Worker     _items = items;
2621*f6dc9357SAndroid Build Coastguard Worker     _itemIndex = (int)itemIndex;
2622*f6dc9357SAndroid Build Coastguard Worker     _stream = NULL;
2623*f6dc9357SAndroid Build Coastguard Worker     CrcIsOK = true;
2624*f6dc9357SAndroid Build Coastguard Worker   }
2625*f6dc9357SAndroid Build Coastguard Worker };
2626*f6dc9357SAndroid Build Coastguard Worker 
2627*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CVolsInStream::Read(void *data, UInt32 size, UInt32 *processedSize))
2628*f6dc9357SAndroid Build Coastguard Worker {
2629*f6dc9357SAndroid Build Coastguard Worker   if (processedSize)
2630*f6dc9357SAndroid Build Coastguard Worker     *processedSize = 0;
2631*f6dc9357SAndroid Build Coastguard Worker   UInt32 realProcessedSize = 0;
2632*f6dc9357SAndroid Build Coastguard Worker 
2633*f6dc9357SAndroid Build Coastguard Worker   while (size != 0)
2634*f6dc9357SAndroid Build Coastguard Worker   {
2635*f6dc9357SAndroid Build Coastguard Worker     if (!_stream)
2636*f6dc9357SAndroid Build Coastguard Worker     {
2637*f6dc9357SAndroid Build Coastguard Worker       if (_itemIndex < 0)
2638*f6dc9357SAndroid Build Coastguard Worker         break;
2639*f6dc9357SAndroid Build Coastguard Worker       const CItem &item = (*_items)[_itemIndex];
2640*f6dc9357SAndroid Build Coastguard Worker       IInStream *s = (*_arcs)[item.VolIndex].Stream;
2641*f6dc9357SAndroid Build Coastguard Worker       RINOK(InStream_SeekSet(s, item.GetDataPosition()))
2642*f6dc9357SAndroid Build Coastguard Worker       _stream = s;
2643*f6dc9357SAndroid Build Coastguard Worker       if (CrcIsOK && item.IsSplitAfter())
2644*f6dc9357SAndroid Build Coastguard Worker         _hash.Init(item);
2645*f6dc9357SAndroid Build Coastguard Worker       else
2646*f6dc9357SAndroid Build Coastguard Worker         _hash.Init_NoCalc();
2647*f6dc9357SAndroid Build Coastguard Worker       _rem = item.PackSize;
2648*f6dc9357SAndroid Build Coastguard Worker     }
2649*f6dc9357SAndroid Build Coastguard Worker     {
2650*f6dc9357SAndroid Build Coastguard Worker       UInt32 cur = size;
2651*f6dc9357SAndroid Build Coastguard Worker       if (cur > _rem)
2652*f6dc9357SAndroid Build Coastguard Worker         cur = (UInt32)_rem;
2653*f6dc9357SAndroid Build Coastguard Worker       const UInt32 num = cur;
2654*f6dc9357SAndroid Build Coastguard Worker       HRESULT res = _stream->Read(data, cur, &cur);
2655*f6dc9357SAndroid Build Coastguard Worker       _hash.Update(data, cur);
2656*f6dc9357SAndroid Build Coastguard Worker       realProcessedSize += cur;
2657*f6dc9357SAndroid Build Coastguard Worker       if (processedSize)
2658*f6dc9357SAndroid Build Coastguard Worker         *processedSize = realProcessedSize;
2659*f6dc9357SAndroid Build Coastguard Worker       data = (Byte *)data + cur;
2660*f6dc9357SAndroid Build Coastguard Worker       size -= cur;
2661*f6dc9357SAndroid Build Coastguard Worker       _rem -= cur;
2662*f6dc9357SAndroid Build Coastguard Worker       if (_rem == 0)
2663*f6dc9357SAndroid Build Coastguard Worker       {
2664*f6dc9357SAndroid Build Coastguard Worker         const CItem &item = (*_items)[_itemIndex];
2665*f6dc9357SAndroid Build Coastguard Worker         _itemIndex = item.NextItem;
2666*f6dc9357SAndroid Build Coastguard Worker         if (!_hash.Check(item, NULL)) // RAR doesn't use MAC here
2667*f6dc9357SAndroid Build Coastguard Worker           CrcIsOK = false;
2668*f6dc9357SAndroid Build Coastguard Worker         _stream = NULL;
2669*f6dc9357SAndroid Build Coastguard Worker       }
2670*f6dc9357SAndroid Build Coastguard Worker       if (res != S_OK)
2671*f6dc9357SAndroid Build Coastguard Worker         return res;
2672*f6dc9357SAndroid Build Coastguard Worker       if (realProcessedSize != 0)
2673*f6dc9357SAndroid Build Coastguard Worker         return S_OK;
2674*f6dc9357SAndroid Build Coastguard Worker       if (cur == 0 && num != 0)
2675*f6dc9357SAndroid Build Coastguard Worker         return S_OK;
2676*f6dc9357SAndroid Build Coastguard Worker     }
2677*f6dc9357SAndroid Build Coastguard Worker   }
2678*f6dc9357SAndroid Build Coastguard Worker 
2679*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
2680*f6dc9357SAndroid Build Coastguard Worker }
2681*f6dc9357SAndroid Build Coastguard Worker 
2682*f6dc9357SAndroid Build Coastguard Worker 
2683*f6dc9357SAndroid Build Coastguard Worker static int FindLinkBuf(CObjectVector<CLinkFile> &linkFiles, unsigned index)
2684*f6dc9357SAndroid Build Coastguard Worker {
2685*f6dc9357SAndroid Build Coastguard Worker   unsigned left = 0, right = linkFiles.Size();
2686*f6dc9357SAndroid Build Coastguard Worker   for (;;)
2687*f6dc9357SAndroid Build Coastguard Worker   {
2688*f6dc9357SAndroid Build Coastguard Worker     if (left == right)
2689*f6dc9357SAndroid Build Coastguard Worker       return -1;
2690*f6dc9357SAndroid Build Coastguard Worker     const unsigned mid = (left + right) / 2;
2691*f6dc9357SAndroid Build Coastguard Worker     const unsigned linkIndex = linkFiles[mid].Index;
2692*f6dc9357SAndroid Build Coastguard Worker     if (index == linkIndex)
2693*f6dc9357SAndroid Build Coastguard Worker       return (int)mid;
2694*f6dc9357SAndroid Build Coastguard Worker     if (index < linkIndex)
2695*f6dc9357SAndroid Build Coastguard Worker       right = mid;
2696*f6dc9357SAndroid Build Coastguard Worker     else
2697*f6dc9357SAndroid Build Coastguard Worker       left = mid + 1;
2698*f6dc9357SAndroid Build Coastguard Worker   }
2699*f6dc9357SAndroid Build Coastguard Worker }
2700*f6dc9357SAndroid Build Coastguard Worker 
2701*f6dc9357SAndroid Build Coastguard Worker 
2702*f6dc9357SAndroid Build Coastguard Worker static inline int DecoderRes_to_OpRes(HRESULT res, bool crcOK)
2703*f6dc9357SAndroid Build Coastguard Worker {
2704*f6dc9357SAndroid Build Coastguard Worker   if (res == E_NOTIMPL)
2705*f6dc9357SAndroid Build Coastguard Worker     return NExtract::NOperationResult::kUnsupportedMethod;
2706*f6dc9357SAndroid Build Coastguard Worker   // if (res == S_FALSE)
2707*f6dc9357SAndroid Build Coastguard Worker   if (res != S_OK)
2708*f6dc9357SAndroid Build Coastguard Worker     return NExtract::NOperationResult::kDataError;
2709*f6dc9357SAndroid Build Coastguard Worker   return crcOK ?
2710*f6dc9357SAndroid Build Coastguard Worker     NExtract::NOperationResult::kOK :
2711*f6dc9357SAndroid Build Coastguard Worker     NExtract::NOperationResult::kCRCError;
2712*f6dc9357SAndroid Build Coastguard Worker }
2713*f6dc9357SAndroid Build Coastguard Worker 
2714*f6dc9357SAndroid Build Coastguard Worker 
2715*f6dc9357SAndroid Build Coastguard Worker static HRESULT CopyData_with_Progress(const Byte *data, size_t size,
2716*f6dc9357SAndroid Build Coastguard Worker     ISequentialOutStream *outStream, ICompressProgressInfo *progress)
2717*f6dc9357SAndroid Build Coastguard Worker {
2718*f6dc9357SAndroid Build Coastguard Worker   UInt64 pos64 = 0;
2719*f6dc9357SAndroid Build Coastguard Worker   while (size)
2720*f6dc9357SAndroid Build Coastguard Worker   {
2721*f6dc9357SAndroid Build Coastguard Worker     const UInt32 kStepSize = (UInt32)1 << 24;
2722*f6dc9357SAndroid Build Coastguard Worker     UInt32 cur = kStepSize;
2723*f6dc9357SAndroid Build Coastguard Worker     if (cur > size)
2724*f6dc9357SAndroid Build Coastguard Worker       cur = (UInt32)size;
2725*f6dc9357SAndroid Build Coastguard Worker     RINOK(outStream->Write(data, cur, &cur))
2726*f6dc9357SAndroid Build Coastguard Worker     if (cur == 0)
2727*f6dc9357SAndroid Build Coastguard Worker       return E_FAIL;
2728*f6dc9357SAndroid Build Coastguard Worker     size -= cur;
2729*f6dc9357SAndroid Build Coastguard Worker     data += cur;
2730*f6dc9357SAndroid Build Coastguard Worker     pos64 += cur;
2731*f6dc9357SAndroid Build Coastguard Worker     if (progress)
2732*f6dc9357SAndroid Build Coastguard Worker     {
2733*f6dc9357SAndroid Build Coastguard Worker       RINOK(progress->SetRatioInfo(&pos64, &pos64))
2734*f6dc9357SAndroid Build Coastguard Worker     }
2735*f6dc9357SAndroid Build Coastguard Worker   }
2736*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
2737*f6dc9357SAndroid Build Coastguard Worker }
2738*f6dc9357SAndroid Build Coastguard Worker 
2739*f6dc9357SAndroid Build Coastguard Worker 
2740*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
2741*f6dc9357SAndroid Build Coastguard Worker     Int32 testMode, IArchiveExtractCallback *extractCallback))
2742*f6dc9357SAndroid Build Coastguard Worker {
2743*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
2744*f6dc9357SAndroid Build Coastguard Worker   const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
2745*f6dc9357SAndroid Build Coastguard Worker   if (allFilesMode)
2746*f6dc9357SAndroid Build Coastguard Worker     numItems = (UInt32)_refs.Size();
2747*f6dc9357SAndroid Build Coastguard Worker   if (numItems == 0)
2748*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
2749*f6dc9357SAndroid Build Coastguard Worker 
2750*f6dc9357SAndroid Build Coastguard Worker   CByteArr extractStatuses(_refs.Size());
2751*f6dc9357SAndroid Build Coastguard Worker   memset(extractStatuses, 0, _refs.Size());
2752*f6dc9357SAndroid Build Coastguard Worker 
2753*f6dc9357SAndroid Build Coastguard Worker   // we don't want to use temp buffer for big link files.
2754*f6dc9357SAndroid Build Coastguard Worker   const size_t k_CopyLinkFile_MaxSize = (size_t)1 << (28 + sizeof(size_t) / 2);
2755*f6dc9357SAndroid Build Coastguard Worker 
2756*f6dc9357SAndroid Build Coastguard Worker   const Byte kStatus_Extract = 1 << 0;
2757*f6dc9357SAndroid Build Coastguard Worker   const Byte kStatus_Skip = 1 << 1;
2758*f6dc9357SAndroid Build Coastguard Worker   const Byte kStatus_Link = 1 << 2;
2759*f6dc9357SAndroid Build Coastguard Worker 
2760*f6dc9357SAndroid Build Coastguard Worker   /*
2761*f6dc9357SAndroid Build Coastguard Worker     In original RAR:
2762*f6dc9357SAndroid Build Coastguard Worker     1) service streams are not allowed to be solid,
2763*f6dc9357SAndroid Build Coastguard Worker         and solid flag must be ignored for service streams.
2764*f6dc9357SAndroid Build Coastguard Worker     2) If RAR creates new solid block and first file in solid block is Link file,
2765*f6dc9357SAndroid Build Coastguard Worker          then it can clear solid flag for Link file and
2766*f6dc9357SAndroid Build Coastguard Worker          clear solid flag for first non-Link file after Link file.
2767*f6dc9357SAndroid Build Coastguard Worker   */
2768*f6dc9357SAndroid Build Coastguard Worker 
2769*f6dc9357SAndroid Build Coastguard Worker   CObjectVector<CLinkFile> linkFiles;
2770*f6dc9357SAndroid Build Coastguard Worker 
2771*f6dc9357SAndroid Build Coastguard Worker   {
2772*f6dc9357SAndroid Build Coastguard Worker     UInt64 total = 0;
2773*f6dc9357SAndroid Build Coastguard Worker     bool isThereUndefinedSize = false;
2774*f6dc9357SAndroid Build Coastguard Worker     bool thereAreLinks = false;
2775*f6dc9357SAndroid Build Coastguard Worker     {
2776*f6dc9357SAndroid Build Coastguard Worker       unsigned solidLimit = 0;
2777*f6dc9357SAndroid Build Coastguard Worker       for (UInt32 t = 0; t < numItems; t++)
2778*f6dc9357SAndroid Build Coastguard Worker       {
2779*f6dc9357SAndroid Build Coastguard Worker         const unsigned index = (unsigned)(allFilesMode ? t : indices[t]);
2780*f6dc9357SAndroid Build Coastguard Worker         const CRefItem &ref = _refs[index];
2781*f6dc9357SAndroid Build Coastguard Worker         const CItem &item = _items[ref.Item];
2782*f6dc9357SAndroid Build Coastguard Worker         const CItem &lastItem = _items[ref.Last];
2783*f6dc9357SAndroid Build Coastguard Worker 
2784*f6dc9357SAndroid Build Coastguard Worker         extractStatuses[index] |= kStatus_Extract;
2785*f6dc9357SAndroid Build Coastguard Worker 
2786*f6dc9357SAndroid Build Coastguard Worker         if (!lastItem.Is_UnknownSize())
2787*f6dc9357SAndroid Build Coastguard Worker           total += lastItem.Size;
2788*f6dc9357SAndroid Build Coastguard Worker         else
2789*f6dc9357SAndroid Build Coastguard Worker           isThereUndefinedSize = true;
2790*f6dc9357SAndroid Build Coastguard Worker 
2791*f6dc9357SAndroid Build Coastguard Worker         if (ref.Link >= 0)
2792*f6dc9357SAndroid Build Coastguard Worker         {
2793*f6dc9357SAndroid Build Coastguard Worker           // 18.06 fixed: we use links for Test mode too
2794*f6dc9357SAndroid Build Coastguard Worker           // if (!testMode)
2795*f6dc9357SAndroid Build Coastguard Worker           {
2796*f6dc9357SAndroid Build Coastguard Worker             if ((unsigned)ref.Link < index)
2797*f6dc9357SAndroid Build Coastguard Worker             {
2798*f6dc9357SAndroid Build Coastguard Worker               const CRefItem &linkRef = _refs[(unsigned)ref.Link];
2799*f6dc9357SAndroid Build Coastguard Worker               const CItem &linkItem = _items[linkRef.Item];
2800*f6dc9357SAndroid Build Coastguard Worker               if (linkItem.IsSolid())
2801*f6dc9357SAndroid Build Coastguard Worker               if (testMode || linkItem.Size <= k_CopyLinkFile_MaxSize)
2802*f6dc9357SAndroid Build Coastguard Worker               {
2803*f6dc9357SAndroid Build Coastguard Worker                 if (extractStatuses[(unsigned)ref.Link] == 0)
2804*f6dc9357SAndroid Build Coastguard Worker                 {
2805*f6dc9357SAndroid Build Coastguard Worker                   const CItem &lastLinkItem = _items[linkRef.Last];
2806*f6dc9357SAndroid Build Coastguard Worker                   if (!lastLinkItem.Is_UnknownSize())
2807*f6dc9357SAndroid Build Coastguard Worker                     total += lastLinkItem.Size;
2808*f6dc9357SAndroid Build Coastguard Worker                   else
2809*f6dc9357SAndroid Build Coastguard Worker                     isThereUndefinedSize = true;
2810*f6dc9357SAndroid Build Coastguard Worker                 }
2811*f6dc9357SAndroid Build Coastguard Worker                 extractStatuses[(unsigned)ref.Link] |= kStatus_Link;
2812*f6dc9357SAndroid Build Coastguard Worker                 thereAreLinks = true;
2813*f6dc9357SAndroid Build Coastguard Worker               }
2814*f6dc9357SAndroid Build Coastguard Worker             }
2815*f6dc9357SAndroid Build Coastguard Worker           }
2816*f6dc9357SAndroid Build Coastguard Worker           continue;
2817*f6dc9357SAndroid Build Coastguard Worker         }
2818*f6dc9357SAndroid Build Coastguard Worker 
2819*f6dc9357SAndroid Build Coastguard Worker         if (item.IsService())
2820*f6dc9357SAndroid Build Coastguard Worker           continue;
2821*f6dc9357SAndroid Build Coastguard Worker 
2822*f6dc9357SAndroid Build Coastguard Worker         if (item.IsSolid())
2823*f6dc9357SAndroid Build Coastguard Worker         {
2824*f6dc9357SAndroid Build Coastguard Worker           unsigned j = index;
2825*f6dc9357SAndroid Build Coastguard Worker 
2826*f6dc9357SAndroid Build Coastguard Worker           while (j > solidLimit)
2827*f6dc9357SAndroid Build Coastguard Worker           {
2828*f6dc9357SAndroid Build Coastguard Worker             j--;
2829*f6dc9357SAndroid Build Coastguard Worker             const CRefItem &ref2 = _refs[j];
2830*f6dc9357SAndroid Build Coastguard Worker             const CItem &item2 = _items[ref2.Item];
2831*f6dc9357SAndroid Build Coastguard Worker             if (!item2.IsService())
2832*f6dc9357SAndroid Build Coastguard Worker             {
2833*f6dc9357SAndroid Build Coastguard Worker               if (extractStatuses[j] == 0)
2834*f6dc9357SAndroid Build Coastguard Worker               {
2835*f6dc9357SAndroid Build Coastguard Worker                 const CItem &lastItem2 = _items[ref2.Last];
2836*f6dc9357SAndroid Build Coastguard Worker                 if (!lastItem2.Is_UnknownSize())
2837*f6dc9357SAndroid Build Coastguard Worker                   total += lastItem2.Size;
2838*f6dc9357SAndroid Build Coastguard Worker                 else
2839*f6dc9357SAndroid Build Coastguard Worker                   isThereUndefinedSize = true;
2840*f6dc9357SAndroid Build Coastguard Worker               }
2841*f6dc9357SAndroid Build Coastguard Worker               extractStatuses[j] |= kStatus_Skip;
2842*f6dc9357SAndroid Build Coastguard Worker               if (!item2.IsSolid())
2843*f6dc9357SAndroid Build Coastguard Worker                 break;
2844*f6dc9357SAndroid Build Coastguard Worker             }
2845*f6dc9357SAndroid Build Coastguard Worker           }
2846*f6dc9357SAndroid Build Coastguard Worker         }
2847*f6dc9357SAndroid Build Coastguard Worker 
2848*f6dc9357SAndroid Build Coastguard Worker         solidLimit = index + 1;
2849*f6dc9357SAndroid Build Coastguard Worker       }
2850*f6dc9357SAndroid Build Coastguard Worker     }
2851*f6dc9357SAndroid Build Coastguard Worker 
2852*f6dc9357SAndroid Build Coastguard Worker     if (thereAreLinks)
2853*f6dc9357SAndroid Build Coastguard Worker     {
2854*f6dc9357SAndroid Build Coastguard Worker       unsigned solidLimit = 0;
2855*f6dc9357SAndroid Build Coastguard Worker 
2856*f6dc9357SAndroid Build Coastguard Worker       FOR_VECTOR (i, _refs)
2857*f6dc9357SAndroid Build Coastguard Worker       {
2858*f6dc9357SAndroid Build Coastguard Worker         if ((extractStatuses[i] & kStatus_Link) == 0)
2859*f6dc9357SAndroid Build Coastguard Worker           continue;
2860*f6dc9357SAndroid Build Coastguard Worker 
2861*f6dc9357SAndroid Build Coastguard Worker         // We use CLinkFile for testMode too.
2862*f6dc9357SAndroid Build Coastguard Worker         // So we can show errors for copy files.
2863*f6dc9357SAndroid Build Coastguard Worker         // if (!testMode)
2864*f6dc9357SAndroid Build Coastguard Worker         {
2865*f6dc9357SAndroid Build Coastguard Worker           CLinkFile &linkFile = linkFiles.AddNew();
2866*f6dc9357SAndroid Build Coastguard Worker           linkFile.Index = i;
2867*f6dc9357SAndroid Build Coastguard Worker         }
2868*f6dc9357SAndroid Build Coastguard Worker 
2869*f6dc9357SAndroid Build Coastguard Worker         const CItem &item = _items[_refs[i].Item];
2870*f6dc9357SAndroid Build Coastguard Worker         /*
2871*f6dc9357SAndroid Build Coastguard Worker         if (item.IsService())
2872*f6dc9357SAndroid Build Coastguard Worker           continue;
2873*f6dc9357SAndroid Build Coastguard Worker         */
2874*f6dc9357SAndroid Build Coastguard Worker 
2875*f6dc9357SAndroid Build Coastguard Worker         if (item.IsSolid())
2876*f6dc9357SAndroid Build Coastguard Worker         {
2877*f6dc9357SAndroid Build Coastguard Worker           unsigned j = i;
2878*f6dc9357SAndroid Build Coastguard Worker 
2879*f6dc9357SAndroid Build Coastguard Worker           while (j > solidLimit)
2880*f6dc9357SAndroid Build Coastguard Worker           {
2881*f6dc9357SAndroid Build Coastguard Worker             j--;
2882*f6dc9357SAndroid Build Coastguard Worker             const CRefItem &ref2 = _refs[j];
2883*f6dc9357SAndroid Build Coastguard Worker             const CItem &item2 = _items[ref2.Item];
2884*f6dc9357SAndroid Build Coastguard Worker             if (!item2.IsService())
2885*f6dc9357SAndroid Build Coastguard Worker             {
2886*f6dc9357SAndroid Build Coastguard Worker               if (extractStatuses[j] != 0)
2887*f6dc9357SAndroid Build Coastguard Worker                 break;
2888*f6dc9357SAndroid Build Coastguard Worker               extractStatuses[j] = kStatus_Skip;
2889*f6dc9357SAndroid Build Coastguard Worker               {
2890*f6dc9357SAndroid Build Coastguard Worker                 const CItem &lastItem2 = _items[ref2.Last];
2891*f6dc9357SAndroid Build Coastguard Worker                 if (!lastItem2.Is_UnknownSize())
2892*f6dc9357SAndroid Build Coastguard Worker                   total += lastItem2.Size;
2893*f6dc9357SAndroid Build Coastguard Worker                 else
2894*f6dc9357SAndroid Build Coastguard Worker                   isThereUndefinedSize = true;
2895*f6dc9357SAndroid Build Coastguard Worker               }
2896*f6dc9357SAndroid Build Coastguard Worker               if (!item2.IsSolid())
2897*f6dc9357SAndroid Build Coastguard Worker                 break;
2898*f6dc9357SAndroid Build Coastguard Worker             }
2899*f6dc9357SAndroid Build Coastguard Worker           }
2900*f6dc9357SAndroid Build Coastguard Worker         }
2901*f6dc9357SAndroid Build Coastguard Worker 
2902*f6dc9357SAndroid Build Coastguard Worker         solidLimit = i + 1;
2903*f6dc9357SAndroid Build Coastguard Worker       }
2904*f6dc9357SAndroid Build Coastguard Worker 
2905*f6dc9357SAndroid Build Coastguard Worker       if (!testMode)
2906*f6dc9357SAndroid Build Coastguard Worker       for (UInt32 t = 0; t < numItems; t++)
2907*f6dc9357SAndroid Build Coastguard Worker       {
2908*f6dc9357SAndroid Build Coastguard Worker         const unsigned index = (unsigned)(allFilesMode ? t : indices[t]);
2909*f6dc9357SAndroid Build Coastguard Worker         const CRefItem &ref = _refs[index];
2910*f6dc9357SAndroid Build Coastguard Worker 
2911*f6dc9357SAndroid Build Coastguard Worker         const int linkIndex = ref.Link;
2912*f6dc9357SAndroid Build Coastguard Worker         if (linkIndex < 0 || (unsigned)linkIndex >= index)
2913*f6dc9357SAndroid Build Coastguard Worker           continue;
2914*f6dc9357SAndroid Build Coastguard Worker         const CItem &linkItem = _items[_refs[(unsigned)linkIndex].Item];
2915*f6dc9357SAndroid Build Coastguard Worker         if (!linkItem.IsSolid() || linkItem.Size > k_CopyLinkFile_MaxSize)
2916*f6dc9357SAndroid Build Coastguard Worker           continue;
2917*f6dc9357SAndroid Build Coastguard Worker         const int bufIndex = FindLinkBuf(linkFiles, (unsigned)linkIndex);
2918*f6dc9357SAndroid Build Coastguard Worker         if (bufIndex < 0)
2919*f6dc9357SAndroid Build Coastguard Worker           return E_FAIL;
2920*f6dc9357SAndroid Build Coastguard Worker         linkFiles[bufIndex].NumLinks++;
2921*f6dc9357SAndroid Build Coastguard Worker       }
2922*f6dc9357SAndroid Build Coastguard Worker     }
2923*f6dc9357SAndroid Build Coastguard Worker 
2924*f6dc9357SAndroid Build Coastguard Worker     if (total != 0 || !isThereUndefinedSize)
2925*f6dc9357SAndroid Build Coastguard Worker     {
2926*f6dc9357SAndroid Build Coastguard Worker       RINOK(extractCallback->SetTotal(total))
2927*f6dc9357SAndroid Build Coastguard Worker     }
2928*f6dc9357SAndroid Build Coastguard Worker   }
2929*f6dc9357SAndroid Build Coastguard Worker 
2930*f6dc9357SAndroid Build Coastguard Worker 
2931*f6dc9357SAndroid Build Coastguard Worker 
2932*f6dc9357SAndroid Build Coastguard Worker   // ---------- MEMORY REQUEST ----------
2933*f6dc9357SAndroid Build Coastguard Worker   {
2934*f6dc9357SAndroid Build Coastguard Worker     UInt64 dictMaxSize = 0;
2935*f6dc9357SAndroid Build Coastguard Worker     for (UInt32 i = 0; i < _refs.Size(); i++)
2936*f6dc9357SAndroid Build Coastguard Worker     {
2937*f6dc9357SAndroid Build Coastguard Worker       if (extractStatuses[i] == 0)
2938*f6dc9357SAndroid Build Coastguard Worker         continue;
2939*f6dc9357SAndroid Build Coastguard Worker       const CRefItem &ref = _refs[i];
2940*f6dc9357SAndroid Build Coastguard Worker       const CItem &item = _items[ref.Item];
2941*f6dc9357SAndroid Build Coastguard Worker /*
2942*f6dc9357SAndroid Build Coastguard Worker       if (!item.IsDir() && !item.IsService() && item.NeedUse_as_CopyLink())
2943*f6dc9357SAndroid Build Coastguard Worker       {
2944*f6dc9357SAndroid Build Coastguard Worker       }
2945*f6dc9357SAndroid Build Coastguard Worker */
2946*f6dc9357SAndroid Build Coastguard Worker       const unsigned algo = item.Get_AlgoVersion_RawBits();
2947*f6dc9357SAndroid Build Coastguard Worker       if (!item.IsDir() && algo < Z7_ARRAY_SIZE(_methodMasks))
2948*f6dc9357SAndroid Build Coastguard Worker       {
2949*f6dc9357SAndroid Build Coastguard Worker         const UInt64 d = item.Get_DictSize64();
2950*f6dc9357SAndroid Build Coastguard Worker         if (dictMaxSize < d)
2951*f6dc9357SAndroid Build Coastguard Worker             dictMaxSize = d;
2952*f6dc9357SAndroid Build Coastguard Worker       }
2953*f6dc9357SAndroid Build Coastguard Worker     }
2954*f6dc9357SAndroid Build Coastguard Worker     // we use callback, if dict exceeds (1 GB), because
2955*f6dc9357SAndroid Build Coastguard Worker     // client code can set low limit (1 GB) for allowed memory usage.
2956*f6dc9357SAndroid Build Coastguard Worker     const UInt64 k_MemLimit_for_Callback = (UInt64)1 << 30;
2957*f6dc9357SAndroid Build Coastguard Worker     if (dictMaxSize > (_memUsage_WasSet ?
2958*f6dc9357SAndroid Build Coastguard Worker         _memUsage_Decompress : k_MemLimit_for_Callback))
2959*f6dc9357SAndroid Build Coastguard Worker     {
2960*f6dc9357SAndroid Build Coastguard Worker       {
2961*f6dc9357SAndroid Build Coastguard Worker         CMyComPtr<IArchiveRequestMemoryUseCallback> requestMem;
2962*f6dc9357SAndroid Build Coastguard Worker         extractCallback->QueryInterface(IID_IArchiveRequestMemoryUseCallback, (void **)&requestMem);
2963*f6dc9357SAndroid Build Coastguard Worker         if (!requestMem)
2964*f6dc9357SAndroid Build Coastguard Worker         {
2965*f6dc9357SAndroid Build Coastguard Worker           if (_memUsage_WasSet)
2966*f6dc9357SAndroid Build Coastguard Worker             return E_OUTOFMEMORY;
2967*f6dc9357SAndroid Build Coastguard Worker         }
2968*f6dc9357SAndroid Build Coastguard Worker         else
2969*f6dc9357SAndroid Build Coastguard Worker         {
2970*f6dc9357SAndroid Build Coastguard Worker           UInt64 allowedSize = _memUsage_WasSet ?
2971*f6dc9357SAndroid Build Coastguard Worker               _memUsage_Decompress :
2972*f6dc9357SAndroid Build Coastguard Worker               (UInt64)1 << 32; // 4 GB is default allowed limit for RAR7
2973*f6dc9357SAndroid Build Coastguard Worker 
2974*f6dc9357SAndroid Build Coastguard Worker           const UInt32 flags = (_memUsage_WasSet ?
2975*f6dc9357SAndroid Build Coastguard Worker                 NRequestMemoryUseFlags::k_AllowedSize_WasForced |
2976*f6dc9357SAndroid Build Coastguard Worker                 NRequestMemoryUseFlags::k_MLimit_Exceeded :
2977*f6dc9357SAndroid Build Coastguard Worker             (dictMaxSize > allowedSize) ?
2978*f6dc9357SAndroid Build Coastguard Worker                 NRequestMemoryUseFlags::k_DefaultLimit_Exceeded:
2979*f6dc9357SAndroid Build Coastguard Worker                 0)
2980*f6dc9357SAndroid Build Coastguard Worker              |  NRequestMemoryUseFlags::k_SkipArc_IsExpected
2981*f6dc9357SAndroid Build Coastguard Worker              // |  NRequestMemoryUseFlags::k_NoErrorMessage // for debug
2982*f6dc9357SAndroid Build Coastguard Worker              ;
2983*f6dc9357SAndroid Build Coastguard Worker 
2984*f6dc9357SAndroid Build Coastguard Worker           // we set "Allow" for default case, if requestMem doesn't process anything.
2985*f6dc9357SAndroid Build Coastguard Worker           UInt32 answerFlags =
2986*f6dc9357SAndroid Build Coastguard Worker               (_memUsage_WasSet && dictMaxSize > allowedSize) ?
2987*f6dc9357SAndroid Build Coastguard Worker                 NRequestMemoryAnswerFlags::k_Limit_Exceeded
2988*f6dc9357SAndroid Build Coastguard Worker               | NRequestMemoryAnswerFlags::k_SkipArc
2989*f6dc9357SAndroid Build Coastguard Worker               : NRequestMemoryAnswerFlags::k_Allow;
2990*f6dc9357SAndroid Build Coastguard Worker 
2991*f6dc9357SAndroid Build Coastguard Worker           RINOK(requestMem->RequestMemoryUse(
2992*f6dc9357SAndroid Build Coastguard Worker               flags,
2993*f6dc9357SAndroid Build Coastguard Worker               NEventIndexType::kNoIndex,
2994*f6dc9357SAndroid Build Coastguard Worker               // NEventIndexType::kInArcIndex, // for debug
2995*f6dc9357SAndroid Build Coastguard Worker               0,    // index
2996*f6dc9357SAndroid Build Coastguard Worker               NULL, // path
2997*f6dc9357SAndroid Build Coastguard Worker               dictMaxSize, &allowedSize, &answerFlags))
2998*f6dc9357SAndroid Build Coastguard Worker           if ( (answerFlags & NRequestMemoryAnswerFlags::k_Allow) == 0
2999*f6dc9357SAndroid Build Coastguard Worker             || (answerFlags & NRequestMemoryAnswerFlags::k_Stop)
3000*f6dc9357SAndroid Build Coastguard Worker             || (answerFlags & NRequestMemoryAnswerFlags::k_SkipArc)
3001*f6dc9357SAndroid Build Coastguard Worker             )
3002*f6dc9357SAndroid Build Coastguard Worker           {
3003*f6dc9357SAndroid Build Coastguard Worker             return E_OUTOFMEMORY;
3004*f6dc9357SAndroid Build Coastguard Worker           }
3005*f6dc9357SAndroid Build Coastguard Worker /*
3006*f6dc9357SAndroid Build Coastguard Worker           if ((answerFlags & NRequestMemoryAnswerFlags::k_AskForBigFile) == 0 &&
3007*f6dc9357SAndroid Build Coastguard Worker               (answerFlags & NRequestMemoryAnswerFlags::k_ReportForBigFile) == 0)
3008*f6dc9357SAndroid Build Coastguard Worker           {
3009*f6dc9357SAndroid Build Coastguard Worker             // requestMem.Release();
3010*f6dc9357SAndroid Build Coastguard Worker           }
3011*f6dc9357SAndroid Build Coastguard Worker */
3012*f6dc9357SAndroid Build Coastguard Worker         }
3013*f6dc9357SAndroid Build Coastguard Worker       }
3014*f6dc9357SAndroid Build Coastguard Worker     }
3015*f6dc9357SAndroid Build Coastguard Worker   }
3016*f6dc9357SAndroid Build Coastguard Worker 
3017*f6dc9357SAndroid Build Coastguard Worker 
3018*f6dc9357SAndroid Build Coastguard Worker 
3019*f6dc9357SAndroid Build Coastguard Worker   // ---------- UNPACK ----------
3020*f6dc9357SAndroid Build Coastguard Worker 
3021*f6dc9357SAndroid Build Coastguard Worker   UInt64 totalUnpacked = 0;
3022*f6dc9357SAndroid Build Coastguard Worker   UInt64 totalPacked = 0;
3023*f6dc9357SAndroid Build Coastguard Worker   UInt64 curUnpackSize;
3024*f6dc9357SAndroid Build Coastguard Worker   UInt64 curPackSize;
3025*f6dc9357SAndroid Build Coastguard Worker 
3026*f6dc9357SAndroid Build Coastguard Worker   CUnpacker unpacker;
3027*f6dc9357SAndroid Build Coastguard Worker   unpacker.NeedCrc = _needChecksumCheck;
3028*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ISequentialInStream, CVolsInStream> volsInStream;
3029*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ICompressProgressInfo, CLocalProgress> lps;
3030*f6dc9357SAndroid Build Coastguard Worker   lps->Init(extractCallback, false);
3031*f6dc9357SAndroid Build Coastguard Worker 
3032*f6dc9357SAndroid Build Coastguard Worker /*
3033*f6dc9357SAndroid Build Coastguard Worker   bool prevSolidWasSkipped = false;
3034*f6dc9357SAndroid Build Coastguard Worker   UInt64 solidDictSize_Skip = 0;
3035*f6dc9357SAndroid Build Coastguard Worker */
3036*f6dc9357SAndroid Build Coastguard Worker 
3037*f6dc9357SAndroid Build Coastguard Worker   for (unsigned i = 0;; i++,
3038*f6dc9357SAndroid Build Coastguard Worker       totalUnpacked += curUnpackSize,
3039*f6dc9357SAndroid Build Coastguard Worker       totalPacked += curPackSize)
3040*f6dc9357SAndroid Build Coastguard Worker   {
3041*f6dc9357SAndroid Build Coastguard Worker     lps->InSize = totalPacked;
3042*f6dc9357SAndroid Build Coastguard Worker     lps->OutSize = totalUnpacked;
3043*f6dc9357SAndroid Build Coastguard Worker     RINOK(lps->SetCur())
3044*f6dc9357SAndroid Build Coastguard Worker     {
3045*f6dc9357SAndroid Build Coastguard Worker       const unsigned num = _refs.Size();
3046*f6dc9357SAndroid Build Coastguard Worker       if (i >= num)
3047*f6dc9357SAndroid Build Coastguard Worker         break;
3048*f6dc9357SAndroid Build Coastguard Worker       for (;;)
3049*f6dc9357SAndroid Build Coastguard Worker       {
3050*f6dc9357SAndroid Build Coastguard Worker         if (extractStatuses[i] != 0)
3051*f6dc9357SAndroid Build Coastguard Worker           break;
3052*f6dc9357SAndroid Build Coastguard Worker         i++;
3053*f6dc9357SAndroid Build Coastguard Worker         if (i >= num)
3054*f6dc9357SAndroid Build Coastguard Worker           break;
3055*f6dc9357SAndroid Build Coastguard Worker       }
3056*f6dc9357SAndroid Build Coastguard Worker       if (i >= num)
3057*f6dc9357SAndroid Build Coastguard Worker         break;
3058*f6dc9357SAndroid Build Coastguard Worker     }
3059*f6dc9357SAndroid Build Coastguard Worker     curUnpackSize = 0;
3060*f6dc9357SAndroid Build Coastguard Worker     curPackSize = 0;
3061*f6dc9357SAndroid Build Coastguard Worker 
3062*f6dc9357SAndroid Build Coastguard Worker     // isExtract means that we don't skip that item. So we need read data.
3063*f6dc9357SAndroid Build Coastguard Worker     const bool isExtract = ((extractStatuses[i] & kStatus_Extract) != 0);
3064*f6dc9357SAndroid Build Coastguard Worker     Int32 askMode =
3065*f6dc9357SAndroid Build Coastguard Worker         isExtract ? (testMode ?
3066*f6dc9357SAndroid Build Coastguard Worker           NExtract::NAskMode::kTest :
3067*f6dc9357SAndroid Build Coastguard Worker           NExtract::NAskMode::kExtract) :
3068*f6dc9357SAndroid Build Coastguard Worker           NExtract::NAskMode::kSkip;
3069*f6dc9357SAndroid Build Coastguard Worker 
3070*f6dc9357SAndroid Build Coastguard Worker     unpacker.linkFile = NULL;
3071*f6dc9357SAndroid Build Coastguard Worker 
3072*f6dc9357SAndroid Build Coastguard Worker     // if (!testMode)
3073*f6dc9357SAndroid Build Coastguard Worker     if ((extractStatuses[i] & kStatus_Link) != 0)
3074*f6dc9357SAndroid Build Coastguard Worker     {
3075*f6dc9357SAndroid Build Coastguard Worker       const int bufIndex = FindLinkBuf(linkFiles, i);
3076*f6dc9357SAndroid Build Coastguard Worker       if (bufIndex < 0)
3077*f6dc9357SAndroid Build Coastguard Worker         return E_FAIL;
3078*f6dc9357SAndroid Build Coastguard Worker       unpacker.linkFile = &linkFiles[bufIndex];
3079*f6dc9357SAndroid Build Coastguard Worker     }
3080*f6dc9357SAndroid Build Coastguard Worker 
3081*f6dc9357SAndroid Build Coastguard Worker     const unsigned index = i;
3082*f6dc9357SAndroid Build Coastguard Worker     const CRefItem *ref = &_refs[index];
3083*f6dc9357SAndroid Build Coastguard Worker     const CItem *item = &_items[ref->Item];
3084*f6dc9357SAndroid Build Coastguard Worker     const CItem &lastItem = _items[ref->Last];
3085*f6dc9357SAndroid Build Coastguard Worker 
3086*f6dc9357SAndroid Build Coastguard Worker     curUnpackSize = 0;
3087*f6dc9357SAndroid Build Coastguard Worker     if (!lastItem.Is_UnknownSize())
3088*f6dc9357SAndroid Build Coastguard Worker       curUnpackSize = lastItem.Size;
3089*f6dc9357SAndroid Build Coastguard Worker 
3090*f6dc9357SAndroid Build Coastguard Worker     curPackSize = GetPackSize(index);
3091*f6dc9357SAndroid Build Coastguard Worker 
3092*f6dc9357SAndroid Build Coastguard Worker     bool isSolid = false;
3093*f6dc9357SAndroid Build Coastguard Worker     if (!item->IsService())
3094*f6dc9357SAndroid Build Coastguard Worker     {
3095*f6dc9357SAndroid Build Coastguard Worker       if (item->IsSolid())
3096*f6dc9357SAndroid Build Coastguard Worker         isSolid = unpacker.SolidAllowed;
3097*f6dc9357SAndroid Build Coastguard Worker       unpacker.SolidAllowed = isSolid;
3098*f6dc9357SAndroid Build Coastguard Worker     }
3099*f6dc9357SAndroid Build Coastguard Worker 
3100*f6dc9357SAndroid Build Coastguard Worker 
3101*f6dc9357SAndroid Build Coastguard Worker     // ----- request mem -----
3102*f6dc9357SAndroid Build Coastguard Worker /*
3103*f6dc9357SAndroid Build Coastguard Worker     // link files are complicated cases. (ref->Link >= 0)
3104*f6dc9357SAndroid Build Coastguard Worker     // link file can refer to non-solid file that can have big dictionary
3105*f6dc9357SAndroid Build Coastguard Worker     // link file can refer to solid files that requres buffer
3106*f6dc9357SAndroid Build Coastguard Worker     if (!item->IsDir() && requestMem && ref->Link < 0)
3107*f6dc9357SAndroid Build Coastguard Worker     {
3108*f6dc9357SAndroid Build Coastguard Worker       bool needSkip = false;
3109*f6dc9357SAndroid Build Coastguard Worker       if (isSolid)
3110*f6dc9357SAndroid Build Coastguard Worker         needSkip = prevSolidWasSkipped;
3111*f6dc9357SAndroid Build Coastguard Worker       else
3112*f6dc9357SAndroid Build Coastguard Worker       {
3113*f6dc9357SAndroid Build Coastguard Worker         // isSolid == false
3114*f6dc9357SAndroid Build Coastguard Worker         const unsigned algo = item->Get_AlgoVersion_RawBits();
3115*f6dc9357SAndroid Build Coastguard Worker         // const unsigned m = item.Get_Method();
3116*f6dc9357SAndroid Build Coastguard Worker         if (algo < Z7_ARRAY_SIZE(_methodMasks))
3117*f6dc9357SAndroid Build Coastguard Worker         {
3118*f6dc9357SAndroid Build Coastguard Worker           solidDictSize_Skip = item->Get_DictSize64();
3119*f6dc9357SAndroid Build Coastguard Worker           if (solidDictSize_Skip > allowedSize)
3120*f6dc9357SAndroid Build Coastguard Worker             needSkip = true;
3121*f6dc9357SAndroid Build Coastguard Worker         }
3122*f6dc9357SAndroid Build Coastguard Worker       }
3123*f6dc9357SAndroid Build Coastguard Worker       if (needSkip)
3124*f6dc9357SAndroid Build Coastguard Worker       {
3125*f6dc9357SAndroid Build Coastguard Worker         UInt32 answerFlags = 0;
3126*f6dc9357SAndroid Build Coastguard Worker         UInt64 allowedSize_File = allowedSize;
3127*f6dc9357SAndroid Build Coastguard Worker         RINOK(requestMem->RequestMemoryUse(
3128*f6dc9357SAndroid Build Coastguard Worker                   NRequestMemoryUseFlags::k_Limit_Exceeded |
3129*f6dc9357SAndroid Build Coastguard Worker                   NRequestMemoryUseFlags::k_IsReport,
3130*f6dc9357SAndroid Build Coastguard Worker               NEventIndexType::kInArcIndex,
3131*f6dc9357SAndroid Build Coastguard Worker               index,
3132*f6dc9357SAndroid Build Coastguard Worker               NULL, // path
3133*f6dc9357SAndroid Build Coastguard Worker               solidDictSize_Skip, &allowedSize_File, &answerFlags))
3134*f6dc9357SAndroid Build Coastguard Worker         if (!item->IsService())
3135*f6dc9357SAndroid Build Coastguard Worker           prevSolidWasSkipped = true;
3136*f6dc9357SAndroid Build Coastguard Worker         continue;
3137*f6dc9357SAndroid Build Coastguard Worker       }
3138*f6dc9357SAndroid Build Coastguard Worker     }
3139*f6dc9357SAndroid Build Coastguard Worker     if (!item->IsService() && item->IsDir())
3140*f6dc9357SAndroid Build Coastguard Worker       prevSolidWasSkipped = false;
3141*f6dc9357SAndroid Build Coastguard Worker */
3142*f6dc9357SAndroid Build Coastguard Worker 
3143*f6dc9357SAndroid Build Coastguard Worker     CMyComPtr<ISequentialOutStream> realOutStream;
3144*f6dc9357SAndroid Build Coastguard Worker     RINOK(extractCallback->GetStream((UInt32)index, &realOutStream, askMode))
3145*f6dc9357SAndroid Build Coastguard Worker 
3146*f6dc9357SAndroid Build Coastguard Worker     if (item->IsDir())
3147*f6dc9357SAndroid Build Coastguard Worker     {
3148*f6dc9357SAndroid Build Coastguard Worker       RINOK(extractCallback->PrepareOperation(askMode))
3149*f6dc9357SAndroid Build Coastguard Worker       RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
3150*f6dc9357SAndroid Build Coastguard Worker       continue;
3151*f6dc9357SAndroid Build Coastguard Worker     }
3152*f6dc9357SAndroid Build Coastguard Worker 
3153*f6dc9357SAndroid Build Coastguard Worker     const int index2 = ref->Link;
3154*f6dc9357SAndroid Build Coastguard Worker 
3155*f6dc9357SAndroid Build Coastguard Worker     int bufIndex = -1;
3156*f6dc9357SAndroid Build Coastguard Worker 
3157*f6dc9357SAndroid Build Coastguard Worker     if (index2 >= 0)
3158*f6dc9357SAndroid Build Coastguard Worker     {
3159*f6dc9357SAndroid Build Coastguard Worker       const CRefItem &ref2 = _refs[index2];
3160*f6dc9357SAndroid Build Coastguard Worker       const CItem &item2 = _items[ref2.Item];
3161*f6dc9357SAndroid Build Coastguard Worker       const CItem &lastItem2 = _items[ref2.Last];
3162*f6dc9357SAndroid Build Coastguard Worker       if (!item2.IsSolid())
3163*f6dc9357SAndroid Build Coastguard Worker       {
3164*f6dc9357SAndroid Build Coastguard Worker         item = &item2;
3165*f6dc9357SAndroid Build Coastguard Worker         ref = &ref2;
3166*f6dc9357SAndroid Build Coastguard Worker         if (!lastItem2.Is_UnknownSize())
3167*f6dc9357SAndroid Build Coastguard Worker           curUnpackSize = lastItem2.Size;
3168*f6dc9357SAndroid Build Coastguard Worker         else
3169*f6dc9357SAndroid Build Coastguard Worker           curUnpackSize = 0;
3170*f6dc9357SAndroid Build Coastguard Worker         curPackSize = GetPackSize((unsigned)index2);
3171*f6dc9357SAndroid Build Coastguard Worker       }
3172*f6dc9357SAndroid Build Coastguard Worker       else
3173*f6dc9357SAndroid Build Coastguard Worker       {
3174*f6dc9357SAndroid Build Coastguard Worker         if ((unsigned)index2 < index)
3175*f6dc9357SAndroid Build Coastguard Worker           bufIndex = FindLinkBuf(linkFiles, (unsigned)index2);
3176*f6dc9357SAndroid Build Coastguard Worker       }
3177*f6dc9357SAndroid Build Coastguard Worker     }
3178*f6dc9357SAndroid Build Coastguard Worker 
3179*f6dc9357SAndroid Build Coastguard Worker     bool needCallback = true;
3180*f6dc9357SAndroid Build Coastguard Worker 
3181*f6dc9357SAndroid Build Coastguard Worker     if (!realOutStream)
3182*f6dc9357SAndroid Build Coastguard Worker     {
3183*f6dc9357SAndroid Build Coastguard Worker       if (testMode)
3184*f6dc9357SAndroid Build Coastguard Worker       {
3185*f6dc9357SAndroid Build Coastguard Worker         if (item->NeedUse_as_CopyLink_or_HardLink())
3186*f6dc9357SAndroid Build Coastguard Worker         {
3187*f6dc9357SAndroid Build Coastguard Worker           Int32 opRes = NExtract::NOperationResult::kOK;
3188*f6dc9357SAndroid Build Coastguard Worker           if (bufIndex >= 0)
3189*f6dc9357SAndroid Build Coastguard Worker           {
3190*f6dc9357SAndroid Build Coastguard Worker             const CLinkFile &linkFile = linkFiles[bufIndex];
3191*f6dc9357SAndroid Build Coastguard Worker             opRes = DecoderRes_to_OpRes(linkFile.Res, linkFile.crcOK);
3192*f6dc9357SAndroid Build Coastguard Worker           }
3193*f6dc9357SAndroid Build Coastguard Worker 
3194*f6dc9357SAndroid Build Coastguard Worker           RINOK(extractCallback->PrepareOperation(askMode))
3195*f6dc9357SAndroid Build Coastguard Worker           RINOK(extractCallback->SetOperationResult(opRes))
3196*f6dc9357SAndroid Build Coastguard Worker           continue;
3197*f6dc9357SAndroid Build Coastguard Worker         }
3198*f6dc9357SAndroid Build Coastguard Worker       }
3199*f6dc9357SAndroid Build Coastguard Worker       else
3200*f6dc9357SAndroid Build Coastguard Worker       {
3201*f6dc9357SAndroid Build Coastguard Worker         if (item->IsService())
3202*f6dc9357SAndroid Build Coastguard Worker           continue;
3203*f6dc9357SAndroid Build Coastguard Worker 
3204*f6dc9357SAndroid Build Coastguard Worker         needCallback = false;
3205*f6dc9357SAndroid Build Coastguard Worker 
3206*f6dc9357SAndroid Build Coastguard Worker         if (!item->NeedUse_as_HardLink())
3207*f6dc9357SAndroid Build Coastguard Worker         if (index2 < 0)
3208*f6dc9357SAndroid Build Coastguard Worker 
3209*f6dc9357SAndroid Build Coastguard Worker         for (unsigned n = i + 1; n < _refs.Size(); n++)
3210*f6dc9357SAndroid Build Coastguard Worker         {
3211*f6dc9357SAndroid Build Coastguard Worker           const CItem &nextItem = _items[_refs[n].Item];
3212*f6dc9357SAndroid Build Coastguard Worker           if (nextItem.IsService())
3213*f6dc9357SAndroid Build Coastguard Worker             continue;
3214*f6dc9357SAndroid Build Coastguard Worker           if (!nextItem.IsSolid())
3215*f6dc9357SAndroid Build Coastguard Worker             break;
3216*f6dc9357SAndroid Build Coastguard Worker           if (extractStatuses[i] != 0)
3217*f6dc9357SAndroid Build Coastguard Worker           {
3218*f6dc9357SAndroid Build Coastguard Worker             needCallback = true;
3219*f6dc9357SAndroid Build Coastguard Worker             break;
3220*f6dc9357SAndroid Build Coastguard Worker           }
3221*f6dc9357SAndroid Build Coastguard Worker         }
3222*f6dc9357SAndroid Build Coastguard Worker 
3223*f6dc9357SAndroid Build Coastguard Worker         askMode = NExtract::NAskMode::kSkip;
3224*f6dc9357SAndroid Build Coastguard Worker       }
3225*f6dc9357SAndroid Build Coastguard Worker     }
3226*f6dc9357SAndroid Build Coastguard Worker 
3227*f6dc9357SAndroid Build Coastguard Worker     if (needCallback)
3228*f6dc9357SAndroid Build Coastguard Worker     {
3229*f6dc9357SAndroid Build Coastguard Worker       RINOK(extractCallback->PrepareOperation(askMode))
3230*f6dc9357SAndroid Build Coastguard Worker     }
3231*f6dc9357SAndroid Build Coastguard Worker 
3232*f6dc9357SAndroid Build Coastguard Worker     if (bufIndex >= 0)
3233*f6dc9357SAndroid Build Coastguard Worker     {
3234*f6dc9357SAndroid Build Coastguard Worker       CLinkFile &linkFile = linkFiles[bufIndex];
3235*f6dc9357SAndroid Build Coastguard Worker 
3236*f6dc9357SAndroid Build Coastguard Worker       if (isExtract)
3237*f6dc9357SAndroid Build Coastguard Worker       {
3238*f6dc9357SAndroid Build Coastguard Worker         if (linkFile.NumLinks == 0)
3239*f6dc9357SAndroid Build Coastguard Worker           return E_FAIL;
3240*f6dc9357SAndroid Build Coastguard Worker 
3241*f6dc9357SAndroid Build Coastguard Worker         if (needCallback)
3242*f6dc9357SAndroid Build Coastguard Worker         if (realOutStream)
3243*f6dc9357SAndroid Build Coastguard Worker         {
3244*f6dc9357SAndroid Build Coastguard Worker           RINOK(CopyData_with_Progress(linkFile.Data, linkFile.Data.Size(), realOutStream, lps))
3245*f6dc9357SAndroid Build Coastguard Worker         }
3246*f6dc9357SAndroid Build Coastguard Worker 
3247*f6dc9357SAndroid Build Coastguard Worker         if (--linkFile.NumLinks == 0)
3248*f6dc9357SAndroid Build Coastguard Worker           linkFile.Data.Free();
3249*f6dc9357SAndroid Build Coastguard Worker       }
3250*f6dc9357SAndroid Build Coastguard Worker 
3251*f6dc9357SAndroid Build Coastguard Worker       if (needCallback)
3252*f6dc9357SAndroid Build Coastguard Worker       {
3253*f6dc9357SAndroid Build Coastguard Worker         RINOK(extractCallback->SetOperationResult(DecoderRes_to_OpRes(linkFile.Res, linkFile.crcOK)))
3254*f6dc9357SAndroid Build Coastguard Worker       }
3255*f6dc9357SAndroid Build Coastguard Worker       continue;
3256*f6dc9357SAndroid Build Coastguard Worker     }
3257*f6dc9357SAndroid Build Coastguard Worker 
3258*f6dc9357SAndroid Build Coastguard Worker     if (!needCallback)
3259*f6dc9357SAndroid Build Coastguard Worker       continue;
3260*f6dc9357SAndroid Build Coastguard Worker 
3261*f6dc9357SAndroid Build Coastguard Worker     if (item->NeedUse_as_CopyLink())
3262*f6dc9357SAndroid Build Coastguard Worker     {
3263*f6dc9357SAndroid Build Coastguard Worker       const int opRes = realOutStream ?
3264*f6dc9357SAndroid Build Coastguard Worker           NExtract::NOperationResult::kUnsupportedMethod:
3265*f6dc9357SAndroid Build Coastguard Worker           NExtract::NOperationResult::kOK;
3266*f6dc9357SAndroid Build Coastguard Worker       realOutStream.Release();
3267*f6dc9357SAndroid Build Coastguard Worker       RINOK(extractCallback->SetOperationResult(opRes))
3268*f6dc9357SAndroid Build Coastguard Worker       continue;
3269*f6dc9357SAndroid Build Coastguard Worker     }
3270*f6dc9357SAndroid Build Coastguard Worker 
3271*f6dc9357SAndroid Build Coastguard Worker     volsInStream->Init(&_arcs, &_items, ref->Item);
3272*f6dc9357SAndroid Build Coastguard Worker 
3273*f6dc9357SAndroid Build Coastguard Worker     const UInt64 packSize = curPackSize;
3274*f6dc9357SAndroid Build Coastguard Worker 
3275*f6dc9357SAndroid Build Coastguard Worker     if (item->IsEncrypted())
3276*f6dc9357SAndroid Build Coastguard Worker       if (!unpacker.getTextPassword)
3277*f6dc9357SAndroid Build Coastguard Worker         extractCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&unpacker.getTextPassword);
3278*f6dc9357SAndroid Build Coastguard Worker 
3279*f6dc9357SAndroid Build Coastguard Worker     bool wrongPassword;
3280*f6dc9357SAndroid Build Coastguard Worker     HRESULT result = unpacker.Create(EXTERNAL_CODECS_VARS *item, isSolid, wrongPassword);
3281*f6dc9357SAndroid Build Coastguard Worker 
3282*f6dc9357SAndroid Build Coastguard Worker     if (wrongPassword)
3283*f6dc9357SAndroid Build Coastguard Worker     {
3284*f6dc9357SAndroid Build Coastguard Worker       realOutStream.Release();
3285*f6dc9357SAndroid Build Coastguard Worker       RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kWrongPassword))
3286*f6dc9357SAndroid Build Coastguard Worker       continue;
3287*f6dc9357SAndroid Build Coastguard Worker     }
3288*f6dc9357SAndroid Build Coastguard Worker 
3289*f6dc9357SAndroid Build Coastguard Worker     bool crcOK = true;
3290*f6dc9357SAndroid Build Coastguard Worker     if (result == S_OK)
3291*f6dc9357SAndroid Build Coastguard Worker       result = unpacker.Code(*item, _items[ref->Last], packSize, volsInStream, realOutStream, lps, crcOK);
3292*f6dc9357SAndroid Build Coastguard Worker     realOutStream.Release();
3293*f6dc9357SAndroid Build Coastguard Worker     if (!volsInStream->CrcIsOK)
3294*f6dc9357SAndroid Build Coastguard Worker       crcOK = false;
3295*f6dc9357SAndroid Build Coastguard Worker 
3296*f6dc9357SAndroid Build Coastguard Worker     int opRes = crcOK ?
3297*f6dc9357SAndroid Build Coastguard Worker         NExtract::NOperationResult::kOK:
3298*f6dc9357SAndroid Build Coastguard Worker         NExtract::NOperationResult::kCRCError;
3299*f6dc9357SAndroid Build Coastguard Worker 
3300*f6dc9357SAndroid Build Coastguard Worker     if (result != S_OK)
3301*f6dc9357SAndroid Build Coastguard Worker     {
3302*f6dc9357SAndroid Build Coastguard Worker       if (result == S_FALSE)
3303*f6dc9357SAndroid Build Coastguard Worker         opRes = NExtract::NOperationResult::kDataError;
3304*f6dc9357SAndroid Build Coastguard Worker       else if (result == E_NOTIMPL)
3305*f6dc9357SAndroid Build Coastguard Worker         opRes = NExtract::NOperationResult::kUnsupportedMethod;
3306*f6dc9357SAndroid Build Coastguard Worker       else
3307*f6dc9357SAndroid Build Coastguard Worker         return result;
3308*f6dc9357SAndroid Build Coastguard Worker     }
3309*f6dc9357SAndroid Build Coastguard Worker 
3310*f6dc9357SAndroid Build Coastguard Worker     RINOK(extractCallback->SetOperationResult(opRes))
3311*f6dc9357SAndroid Build Coastguard Worker   }
3312*f6dc9357SAndroid Build Coastguard Worker 
3313*f6dc9357SAndroid Build Coastguard Worker   {
3314*f6dc9357SAndroid Build Coastguard Worker     FOR_VECTOR (k, linkFiles)
3315*f6dc9357SAndroid Build Coastguard Worker       if (linkFiles[k].NumLinks != 0)
3316*f6dc9357SAndroid Build Coastguard Worker         return E_FAIL;
3317*f6dc9357SAndroid Build Coastguard Worker   }
3318*f6dc9357SAndroid Build Coastguard Worker 
3319*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
3320*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
3321*f6dc9357SAndroid Build Coastguard Worker }
3322*f6dc9357SAndroid Build Coastguard Worker 
3323*f6dc9357SAndroid Build Coastguard Worker 
3324*f6dc9357SAndroid Build Coastguard Worker CHandler::CHandler()
3325*f6dc9357SAndroid Build Coastguard Worker {
3326*f6dc9357SAndroid Build Coastguard Worker   InitDefaults();
3327*f6dc9357SAndroid Build Coastguard Worker }
3328*f6dc9357SAndroid Build Coastguard Worker 
3329*f6dc9357SAndroid Build Coastguard Worker void CHandler::InitDefaults()
3330*f6dc9357SAndroid Build Coastguard Worker {
3331*f6dc9357SAndroid Build Coastguard Worker   _needChecksumCheck = true;
3332*f6dc9357SAndroid Build Coastguard Worker   _memUsage_WasSet = false;
3333*f6dc9357SAndroid Build Coastguard Worker   _memUsage_Decompress = (UInt64)1 << 32;
3334*f6dc9357SAndroid Build Coastguard Worker }
3335*f6dc9357SAndroid Build Coastguard Worker 
3336*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps))
3337*f6dc9357SAndroid Build Coastguard Worker {
3338*f6dc9357SAndroid Build Coastguard Worker   InitDefaults();
3339*f6dc9357SAndroid Build Coastguard Worker 
3340*f6dc9357SAndroid Build Coastguard Worker   for (UInt32 i = 0; i < numProps; i++)
3341*f6dc9357SAndroid Build Coastguard Worker   {
3342*f6dc9357SAndroid Build Coastguard Worker     UString name = names[i];
3343*f6dc9357SAndroid Build Coastguard Worker     name.MakeLower_Ascii();
3344*f6dc9357SAndroid Build Coastguard Worker     if (name.IsEmpty())
3345*f6dc9357SAndroid Build Coastguard Worker       return E_INVALIDARG;
3346*f6dc9357SAndroid Build Coastguard Worker 
3347*f6dc9357SAndroid Build Coastguard Worker     const PROPVARIANT &prop = values[i];
3348*f6dc9357SAndroid Build Coastguard Worker 
3349*f6dc9357SAndroid Build Coastguard Worker     if (name.IsPrefixedBy_Ascii_NoCase("mt"))
3350*f6dc9357SAndroid Build Coastguard Worker     {
3351*f6dc9357SAndroid Build Coastguard Worker     }
3352*f6dc9357SAndroid Build Coastguard Worker     else if (name.IsPrefixedBy_Ascii_NoCase("memx"))
3353*f6dc9357SAndroid Build Coastguard Worker     {
3354*f6dc9357SAndroid Build Coastguard Worker       size_t memAvail;
3355*f6dc9357SAndroid Build Coastguard Worker       if (!NWindows::NSystem::GetRamSize(memAvail))
3356*f6dc9357SAndroid Build Coastguard Worker         memAvail = (size_t)sizeof(size_t) << 28;
3357*f6dc9357SAndroid Build Coastguard Worker       UInt64 v;
3358*f6dc9357SAndroid Build Coastguard Worker       if (!ParseSizeString(name.Ptr(4), prop, memAvail, v))
3359*f6dc9357SAndroid Build Coastguard Worker         return E_INVALIDARG;
3360*f6dc9357SAndroid Build Coastguard Worker       _memUsage_Decompress = v;
3361*f6dc9357SAndroid Build Coastguard Worker       _memUsage_WasSet = true;
3362*f6dc9357SAndroid Build Coastguard Worker     }
3363*f6dc9357SAndroid Build Coastguard Worker     else if (name.IsPrefixedBy_Ascii_NoCase("crc"))
3364*f6dc9357SAndroid Build Coastguard Worker     {
3365*f6dc9357SAndroid Build Coastguard Worker       name.Delete(0, 3);
3366*f6dc9357SAndroid Build Coastguard Worker       UInt32 crcSize = 1;
3367*f6dc9357SAndroid Build Coastguard Worker       RINOK(ParsePropToUInt32(name, prop, crcSize))
3368*f6dc9357SAndroid Build Coastguard Worker       _needChecksumCheck = (crcSize != 0);
3369*f6dc9357SAndroid Build Coastguard Worker     }
3370*f6dc9357SAndroid Build Coastguard Worker     else
3371*f6dc9357SAndroid Build Coastguard Worker     {
3372*f6dc9357SAndroid Build Coastguard Worker       return E_INVALIDARG;
3373*f6dc9357SAndroid Build Coastguard Worker     }
3374*f6dc9357SAndroid Build Coastguard Worker   }
3375*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
3376*f6dc9357SAndroid Build Coastguard Worker }
3377*f6dc9357SAndroid Build Coastguard Worker 
3378*f6dc9357SAndroid Build Coastguard Worker 
3379*f6dc9357SAndroid Build Coastguard Worker IMPL_ISetCompressCodecsInfo
3380*f6dc9357SAndroid Build Coastguard Worker 
3381*f6dc9357SAndroid Build Coastguard Worker REGISTER_ARC_I(
3382*f6dc9357SAndroid Build Coastguard Worker   "Rar5", "rar r00", NULL, 0xCC,
3383*f6dc9357SAndroid Build Coastguard Worker   kMarker,
3384*f6dc9357SAndroid Build Coastguard Worker   0,
3385*f6dc9357SAndroid Build Coastguard Worker   NArcInfoFlags::kFindSignature,
3386*f6dc9357SAndroid Build Coastguard Worker   NULL)
3387*f6dc9357SAndroid Build Coastguard Worker 
3388*f6dc9357SAndroid Build Coastguard Worker }}
3389*f6dc9357SAndroid Build Coastguard Worker 
3390*f6dc9357SAndroid Build Coastguard Worker 
3391*f6dc9357SAndroid Build Coastguard Worker Z7_CLASS_IMP_COM_2(
3392*f6dc9357SAndroid Build Coastguard Worker   CBlake2spHasher
3393*f6dc9357SAndroid Build Coastguard Worker   , IHasher
3394*f6dc9357SAndroid Build Coastguard Worker   , ICompressSetCoderProperties
3395*f6dc9357SAndroid Build Coastguard Worker )
3396*f6dc9357SAndroid Build Coastguard Worker   CAlignedBuffer1 _buf;
3397*f6dc9357SAndroid Build Coastguard Worker   // CBlake2sp _blake;
3398*f6dc9357SAndroid Build Coastguard Worker   #define Z7_BLACK2S_ALIGN_OBJECT_OFFSET 0
3399*f6dc9357SAndroid Build Coastguard Worker   CBlake2sp *Obj() { return (CBlake2sp *)(void *)((Byte *)_buf + Z7_BLACK2S_ALIGN_OBJECT_OFFSET); }
3400*f6dc9357SAndroid Build Coastguard Worker public:
3401*f6dc9357SAndroid Build Coastguard Worker   Byte _mtDummy[1 << 7];  // it's public to eliminate clang warning: unused private field
3402*f6dc9357SAndroid Build Coastguard Worker   CBlake2spHasher():
3403*f6dc9357SAndroid Build Coastguard Worker     _buf(sizeof(CBlake2sp) + Z7_BLACK2S_ALIGN_OBJECT_OFFSET)
3404*f6dc9357SAndroid Build Coastguard Worker   {
3405*f6dc9357SAndroid Build Coastguard Worker     Blake2sp_SetFunction(Obj(), 0);
3406*f6dc9357SAndroid Build Coastguard Worker     Blake2sp_InitState(Obj());
3407*f6dc9357SAndroid Build Coastguard Worker   }
3408*f6dc9357SAndroid Build Coastguard Worker };
3409*f6dc9357SAndroid Build Coastguard Worker 
3410*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF2(void, CBlake2spHasher::Init())
3411*f6dc9357SAndroid Build Coastguard Worker {
3412*f6dc9357SAndroid Build Coastguard Worker   Blake2sp_InitState(Obj());
3413*f6dc9357SAndroid Build Coastguard Worker }
3414*f6dc9357SAndroid Build Coastguard Worker 
3415*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF2(void, CBlake2spHasher::Update(const void *data, UInt32 size))
3416*f6dc9357SAndroid Build Coastguard Worker {
3417*f6dc9357SAndroid Build Coastguard Worker #if 1
3418*f6dc9357SAndroid Build Coastguard Worker   Blake2sp_Update(Obj(), (const Byte *)data, (size_t)size);
3419*f6dc9357SAndroid Build Coastguard Worker #else
3420*f6dc9357SAndroid Build Coastguard Worker   // for debug:
3421*f6dc9357SAndroid Build Coastguard Worker   for (;;)
3422*f6dc9357SAndroid Build Coastguard Worker   {
3423*f6dc9357SAndroid Build Coastguard Worker     if (size == 0)
3424*f6dc9357SAndroid Build Coastguard Worker       return;
3425*f6dc9357SAndroid Build Coastguard Worker     UInt32 size2 = (size * 0x85EBCA87) % size / 800;
3426*f6dc9357SAndroid Build Coastguard Worker     // UInt32 size2 = size / 2;
3427*f6dc9357SAndroid Build Coastguard Worker     if (size2 == 0)
3428*f6dc9357SAndroid Build Coastguard Worker       size2 = 1;
3429*f6dc9357SAndroid Build Coastguard Worker     Blake2sp_Update(Obj(), (const Byte *)data, size2);
3430*f6dc9357SAndroid Build Coastguard Worker     data = (const void *)((const Byte *)data + size2);
3431*f6dc9357SAndroid Build Coastguard Worker     size -= size2;
3432*f6dc9357SAndroid Build Coastguard Worker   }
3433*f6dc9357SAndroid Build Coastguard Worker #endif
3434*f6dc9357SAndroid Build Coastguard Worker }
3435*f6dc9357SAndroid Build Coastguard Worker 
3436*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF2(void, CBlake2spHasher::Final(Byte *digest))
3437*f6dc9357SAndroid Build Coastguard Worker {
3438*f6dc9357SAndroid Build Coastguard Worker   Blake2sp_Final(Obj(), digest);
3439*f6dc9357SAndroid Build Coastguard Worker }
3440*f6dc9357SAndroid Build Coastguard Worker 
3441*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CBlake2spHasher::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps))
3442*f6dc9357SAndroid Build Coastguard Worker {
3443*f6dc9357SAndroid Build Coastguard Worker   unsigned algo = 0;
3444*f6dc9357SAndroid Build Coastguard Worker   for (UInt32 i = 0; i < numProps; i++)
3445*f6dc9357SAndroid Build Coastguard Worker   {
3446*f6dc9357SAndroid Build Coastguard Worker     if (propIDs[i] == NCoderPropID::kDefaultProp)
3447*f6dc9357SAndroid Build Coastguard Worker     {
3448*f6dc9357SAndroid Build Coastguard Worker       const PROPVARIANT &prop = coderProps[i];
3449*f6dc9357SAndroid Build Coastguard Worker       if (prop.vt != VT_UI4)
3450*f6dc9357SAndroid Build Coastguard Worker         return E_INVALIDARG;
3451*f6dc9357SAndroid Build Coastguard Worker       /*
3452*f6dc9357SAndroid Build Coastguard Worker       if (prop.ulVal > Z7_BLAKE2S_ALGO_MAX)
3453*f6dc9357SAndroid Build Coastguard Worker         return E_NOTIMPL;
3454*f6dc9357SAndroid Build Coastguard Worker       */
3455*f6dc9357SAndroid Build Coastguard Worker       algo = (unsigned)prop.ulVal;
3456*f6dc9357SAndroid Build Coastguard Worker     }
3457*f6dc9357SAndroid Build Coastguard Worker   }
3458*f6dc9357SAndroid Build Coastguard Worker   if (!Blake2sp_SetFunction(Obj(), algo))
3459*f6dc9357SAndroid Build Coastguard Worker     return E_NOTIMPL;
3460*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
3461*f6dc9357SAndroid Build Coastguard Worker }
3462*f6dc9357SAndroid Build Coastguard Worker 
3463*f6dc9357SAndroid Build Coastguard Worker REGISTER_HASHER(CBlake2spHasher, 0x202, "BLAKE2sp", Z7_BLAKE2S_DIGEST_SIZE)
3464*f6dc9357SAndroid Build Coastguard Worker 
3465*f6dc9357SAndroid Build Coastguard Worker static struct CBlake2sp_Prepare { CBlake2sp_Prepare() { z7_Black2sp_Prepare(); } } g_Blake2sp_Prepare;
3466