xref: /aosp_15_r20/external/lzma/CPP/7zip/Archive/LzhHandler.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1*f6dc9357SAndroid Build Coastguard Worker // LzhHandler.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/CpuArch.h"
6*f6dc9357SAndroid Build Coastguard Worker 
7*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/AutoPtr.h"
8*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/ComTry.h"
9*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/MyBuffer.h"
10*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/StringConvert.h"
11*f6dc9357SAndroid Build Coastguard Worker 
12*f6dc9357SAndroid Build Coastguard Worker #include "../../Windows/PropVariant.h"
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 "../ICoder.h"
17*f6dc9357SAndroid Build Coastguard Worker 
18*f6dc9357SAndroid Build Coastguard Worker #include "../Common/LimitedStreams.h"
19*f6dc9357SAndroid Build Coastguard Worker #include "../Common/ProgressUtils.h"
20*f6dc9357SAndroid Build Coastguard Worker #include "../Common/RegisterArc.h"
21*f6dc9357SAndroid Build Coastguard Worker #include "../Common/StreamUtils.h"
22*f6dc9357SAndroid Build Coastguard Worker 
23*f6dc9357SAndroid Build Coastguard Worker #include "../Compress/CopyCoder.h"
24*f6dc9357SAndroid Build Coastguard Worker #include "../Compress/LzhDecoder.h"
25*f6dc9357SAndroid Build Coastguard Worker 
26*f6dc9357SAndroid Build Coastguard Worker #include "IArchive.h"
27*f6dc9357SAndroid Build Coastguard Worker 
28*f6dc9357SAndroid Build Coastguard Worker #include "Common/ItemNameUtils.h"
29*f6dc9357SAndroid Build Coastguard Worker 
30*f6dc9357SAndroid Build Coastguard Worker using namespace NWindows;
31*f6dc9357SAndroid Build Coastguard Worker using namespace NTime;
32*f6dc9357SAndroid Build Coastguard Worker 
33*f6dc9357SAndroid Build Coastguard Worker #define Get16(p) GetUi16(p)
34*f6dc9357SAndroid Build Coastguard Worker #define Get32(p) GetUi32(p)
35*f6dc9357SAndroid Build Coastguard Worker 
36*f6dc9357SAndroid Build Coastguard Worker 
37*f6dc9357SAndroid Build Coastguard Worker // CRC-16 (-IBM, -ANSI). The poly is 0x8005 (x^16 + x^15 + x^2 + 1)
38*f6dc9357SAndroid Build Coastguard Worker 
39*f6dc9357SAndroid Build Coastguard Worker static const UInt16 kCrc16Poly = 0xA001;
40*f6dc9357SAndroid Build Coastguard Worker 
41*f6dc9357SAndroid Build Coastguard Worker MY_ALIGN(64)
42*f6dc9357SAndroid Build Coastguard Worker static UInt16 g_LzhCrc16Table[256];
43*f6dc9357SAndroid Build Coastguard Worker 
44*f6dc9357SAndroid Build Coastguard Worker #define CRC16_UPDATE_BYTE(crc, b) (g_LzhCrc16Table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
45*f6dc9357SAndroid Build Coastguard Worker 
46*f6dc9357SAndroid Build Coastguard Worker UInt32 LzhCrc16Update(UInt32 crc, const void *data, size_t size);
LzhCrc16Update(UInt32 crc,const void * data,size_t size)47*f6dc9357SAndroid Build Coastguard Worker UInt32 LzhCrc16Update(UInt32 crc, const void *data, size_t size)
48*f6dc9357SAndroid Build Coastguard Worker {
49*f6dc9357SAndroid Build Coastguard Worker   const Byte *p = (const Byte *)data;
50*f6dc9357SAndroid Build Coastguard Worker   const Byte *pEnd = p + size;
51*f6dc9357SAndroid Build Coastguard Worker   for (; p != pEnd; p++)
52*f6dc9357SAndroid Build Coastguard Worker     crc = CRC16_UPDATE_BYTE(crc, *p);
53*f6dc9357SAndroid Build Coastguard Worker   return crc;
54*f6dc9357SAndroid Build Coastguard Worker }
55*f6dc9357SAndroid Build Coastguard Worker 
56*f6dc9357SAndroid Build Coastguard Worker static struct CLzhCrc16TableInit
57*f6dc9357SAndroid Build Coastguard Worker {
CLzhCrc16TableInitCLzhCrc16TableInit58*f6dc9357SAndroid Build Coastguard Worker   CLzhCrc16TableInit()
59*f6dc9357SAndroid Build Coastguard Worker   {
60*f6dc9357SAndroid Build Coastguard Worker     for (UInt32 i = 0; i < 256; i++)
61*f6dc9357SAndroid Build Coastguard Worker     {
62*f6dc9357SAndroid Build Coastguard Worker       UInt32 r = i;
63*f6dc9357SAndroid Build Coastguard Worker       for (unsigned j = 0; j < 8; j++)
64*f6dc9357SAndroid Build Coastguard Worker         r = (r >> 1) ^ (kCrc16Poly & ((UInt32)0 - (r & 1)));
65*f6dc9357SAndroid Build Coastguard Worker       g_LzhCrc16Table[i] = (UInt16)r;
66*f6dc9357SAndroid Build Coastguard Worker     }
67*f6dc9357SAndroid Build Coastguard Worker   }
68*f6dc9357SAndroid Build Coastguard Worker } g_LzhCrc16TableInit;
69*f6dc9357SAndroid Build Coastguard Worker 
70*f6dc9357SAndroid Build Coastguard Worker 
71*f6dc9357SAndroid Build Coastguard Worker namespace NArchive {
72*f6dc9357SAndroid Build Coastguard Worker namespace NLzh{
73*f6dc9357SAndroid Build Coastguard Worker 
74*f6dc9357SAndroid Build Coastguard Worker const unsigned kMethodIdSize = 5;
75*f6dc9357SAndroid Build Coastguard Worker 
76*f6dc9357SAndroid Build Coastguard Worker const Byte kExtIdFileName = 0x01;
77*f6dc9357SAndroid Build Coastguard Worker const Byte kExtIdDirName  = 0x02;
78*f6dc9357SAndroid Build Coastguard Worker const Byte kExtIdUnixTime = 0x54;
79*f6dc9357SAndroid Build Coastguard Worker 
80*f6dc9357SAndroid Build Coastguard Worker struct CExtension
81*f6dc9357SAndroid Build Coastguard Worker {
82*f6dc9357SAndroid Build Coastguard Worker   Byte Type;
83*f6dc9357SAndroid Build Coastguard Worker   CByteBuffer Data;
84*f6dc9357SAndroid Build Coastguard Worker 
GetStringNArchive::NLzh::CExtension85*f6dc9357SAndroid Build Coastguard Worker   AString GetString() const
86*f6dc9357SAndroid Build Coastguard Worker   {
87*f6dc9357SAndroid Build Coastguard Worker     AString s;
88*f6dc9357SAndroid Build Coastguard Worker     s.SetFrom_CalcLen((const char *)(const Byte *)Data, (unsigned)Data.Size());
89*f6dc9357SAndroid Build Coastguard Worker     return s;
90*f6dc9357SAndroid Build Coastguard Worker   }
91*f6dc9357SAndroid Build Coastguard Worker };
92*f6dc9357SAndroid Build Coastguard Worker 
93*f6dc9357SAndroid Build Coastguard Worker const UInt32 kBasicPartSize = 22;
94*f6dc9357SAndroid Build Coastguard Worker 
IsArc_Lzh(const Byte * p,size_t size)95*f6dc9357SAndroid Build Coastguard Worker API_FUNC_static_IsArc IsArc_Lzh(const Byte *p, size_t size)
96*f6dc9357SAndroid Build Coastguard Worker {
97*f6dc9357SAndroid Build Coastguard Worker   if (size < 2 + kBasicPartSize)
98*f6dc9357SAndroid Build Coastguard Worker     return k_IsArc_Res_NEED_MORE;
99*f6dc9357SAndroid Build Coastguard Worker   if (p[2] != '-' || p[3] != 'l'  || p[4] != 'h' || p[6] != '-')
100*f6dc9357SAndroid Build Coastguard Worker     return k_IsArc_Res_NO;
101*f6dc9357SAndroid Build Coastguard Worker   Byte n = p[5];
102*f6dc9357SAndroid Build Coastguard Worker   if (n != 'd')
103*f6dc9357SAndroid Build Coastguard Worker     if (n < '0' || n > '7')
104*f6dc9357SAndroid Build Coastguard Worker       return k_IsArc_Res_NO;
105*f6dc9357SAndroid Build Coastguard Worker   return k_IsArc_Res_YES;
106*f6dc9357SAndroid Build Coastguard Worker }
107*f6dc9357SAndroid Build Coastguard Worker }
108*f6dc9357SAndroid Build Coastguard Worker 
109*f6dc9357SAndroid Build Coastguard Worker struct CItem
110*f6dc9357SAndroid Build Coastguard Worker {
111*f6dc9357SAndroid Build Coastguard Worker   AString Name;
112*f6dc9357SAndroid Build Coastguard Worker   Byte Method[kMethodIdSize];
113*f6dc9357SAndroid Build Coastguard Worker   Byte Attributes;
114*f6dc9357SAndroid Build Coastguard Worker   Byte Level;
115*f6dc9357SAndroid Build Coastguard Worker   Byte OsId;
116*f6dc9357SAndroid Build Coastguard Worker   UInt32 PackSize;
117*f6dc9357SAndroid Build Coastguard Worker   UInt32 Size;
118*f6dc9357SAndroid Build Coastguard Worker   UInt32 ModifiedTime;
119*f6dc9357SAndroid Build Coastguard Worker   UInt16 CRC;
120*f6dc9357SAndroid Build Coastguard Worker   CObjectVector<CExtension> Extensions;
121*f6dc9357SAndroid Build Coastguard Worker 
IsValidMethodNArchive::CItem122*f6dc9357SAndroid Build Coastguard Worker   bool IsValidMethod() const  { return (Method[0] == '-' && Method[1] == 'l' && Method[4] == '-'); }
IsLhMethodNArchive::CItem123*f6dc9357SAndroid Build Coastguard Worker   bool IsLhMethod() const  {return (IsValidMethod() && Method[2] == 'h'); }
IsDirNArchive::CItem124*f6dc9357SAndroid Build Coastguard Worker   bool IsDir() const {return (IsLhMethod() && Method[3] == 'd'); }
125*f6dc9357SAndroid Build Coastguard Worker 
IsCopyMethodNArchive::CItem126*f6dc9357SAndroid Build Coastguard Worker   bool IsCopyMethod() const
127*f6dc9357SAndroid Build Coastguard Worker   {
128*f6dc9357SAndroid Build Coastguard Worker     return (IsLhMethod() && Method[3] == '0') ||
129*f6dc9357SAndroid Build Coastguard Worker       (IsValidMethod() && Method[2] == 'z' && Method[3] == '4');
130*f6dc9357SAndroid Build Coastguard Worker   }
131*f6dc9357SAndroid Build Coastguard Worker 
IsLh1GroupMethodNArchive::CItem132*f6dc9357SAndroid Build Coastguard Worker   bool IsLh1GroupMethod() const
133*f6dc9357SAndroid Build Coastguard Worker   {
134*f6dc9357SAndroid Build Coastguard Worker     if (!IsLhMethod())
135*f6dc9357SAndroid Build Coastguard Worker       return false;
136*f6dc9357SAndroid Build Coastguard Worker     switch (Method[3])
137*f6dc9357SAndroid Build Coastguard Worker     {
138*f6dc9357SAndroid Build Coastguard Worker       case '1':
139*f6dc9357SAndroid Build Coastguard Worker         return true;
140*f6dc9357SAndroid Build Coastguard Worker     }
141*f6dc9357SAndroid Build Coastguard Worker     return false;
142*f6dc9357SAndroid Build Coastguard Worker   }
143*f6dc9357SAndroid Build Coastguard Worker 
IsLh4GroupMethodNArchive::CItem144*f6dc9357SAndroid Build Coastguard Worker   bool IsLh4GroupMethod() const
145*f6dc9357SAndroid Build Coastguard Worker   {
146*f6dc9357SAndroid Build Coastguard Worker     if (!IsLhMethod())
147*f6dc9357SAndroid Build Coastguard Worker       return false;
148*f6dc9357SAndroid Build Coastguard Worker     switch (Method[3])
149*f6dc9357SAndroid Build Coastguard Worker     {
150*f6dc9357SAndroid Build Coastguard Worker       case '4':
151*f6dc9357SAndroid Build Coastguard Worker       case '5':
152*f6dc9357SAndroid Build Coastguard Worker       case '6':
153*f6dc9357SAndroid Build Coastguard Worker       case '7':
154*f6dc9357SAndroid Build Coastguard Worker         return true;
155*f6dc9357SAndroid Build Coastguard Worker     }
156*f6dc9357SAndroid Build Coastguard Worker     return false;
157*f6dc9357SAndroid Build Coastguard Worker   }
158*f6dc9357SAndroid Build Coastguard Worker 
GetNumDictBitsNArchive::CItem159*f6dc9357SAndroid Build Coastguard Worker   unsigned GetNumDictBits() const
160*f6dc9357SAndroid Build Coastguard Worker   {
161*f6dc9357SAndroid Build Coastguard Worker     if (!IsLhMethod())
162*f6dc9357SAndroid Build Coastguard Worker       return 0;
163*f6dc9357SAndroid Build Coastguard Worker     switch (Method[3])
164*f6dc9357SAndroid Build Coastguard Worker     {
165*f6dc9357SAndroid Build Coastguard Worker       case '1': return 12;
166*f6dc9357SAndroid Build Coastguard Worker       case '2': return 13;
167*f6dc9357SAndroid Build Coastguard Worker       case '3': return 13;
168*f6dc9357SAndroid Build Coastguard Worker       case '4': return 12;
169*f6dc9357SAndroid Build Coastguard Worker       case '5': return 13;
170*f6dc9357SAndroid Build Coastguard Worker       case '6': return 15;
171*f6dc9357SAndroid Build Coastguard Worker       case '7': return 16;
172*f6dc9357SAndroid Build Coastguard Worker     }
173*f6dc9357SAndroid Build Coastguard Worker     return 0;
174*f6dc9357SAndroid Build Coastguard Worker   }
175*f6dc9357SAndroid Build Coastguard Worker 
FindExtNArchive::CItem176*f6dc9357SAndroid Build Coastguard Worker   int FindExt(Byte type) const
177*f6dc9357SAndroid Build Coastguard Worker   {
178*f6dc9357SAndroid Build Coastguard Worker     FOR_VECTOR (i, Extensions)
179*f6dc9357SAndroid Build Coastguard Worker       if (Extensions[i].Type == type)
180*f6dc9357SAndroid Build Coastguard Worker         return (int)i;
181*f6dc9357SAndroid Build Coastguard Worker     return -1;
182*f6dc9357SAndroid Build Coastguard Worker   }
183*f6dc9357SAndroid Build Coastguard Worker 
GetUnixTimeNArchive::CItem184*f6dc9357SAndroid Build Coastguard Worker   bool GetUnixTime(UInt32 &value) const
185*f6dc9357SAndroid Build Coastguard Worker   {
186*f6dc9357SAndroid Build Coastguard Worker     value = 0;
187*f6dc9357SAndroid Build Coastguard Worker     int index = FindExt(kExtIdUnixTime);
188*f6dc9357SAndroid Build Coastguard Worker     if (index < 0
189*f6dc9357SAndroid Build Coastguard Worker         || Extensions[index].Data.Size() < 4)
190*f6dc9357SAndroid Build Coastguard Worker     {
191*f6dc9357SAndroid Build Coastguard Worker       if (Level == 2)
192*f6dc9357SAndroid Build Coastguard Worker       {
193*f6dc9357SAndroid Build Coastguard Worker         value = ModifiedTime;
194*f6dc9357SAndroid Build Coastguard Worker         return true;
195*f6dc9357SAndroid Build Coastguard Worker       }
196*f6dc9357SAndroid Build Coastguard Worker       return false;
197*f6dc9357SAndroid Build Coastguard Worker     }
198*f6dc9357SAndroid Build Coastguard Worker     const Byte *data = (const Byte *)(Extensions[index].Data);
199*f6dc9357SAndroid Build Coastguard Worker     value = GetUi32(data);
200*f6dc9357SAndroid Build Coastguard Worker     return true;
201*f6dc9357SAndroid Build Coastguard Worker   }
202*f6dc9357SAndroid Build Coastguard Worker 
GetDirNameNArchive::CItem203*f6dc9357SAndroid Build Coastguard Worker   AString GetDirName() const
204*f6dc9357SAndroid Build Coastguard Worker   {
205*f6dc9357SAndroid Build Coastguard Worker     int index = FindExt(kExtIdDirName);
206*f6dc9357SAndroid Build Coastguard Worker     if (index < 0)
207*f6dc9357SAndroid Build Coastguard Worker       return AString();
208*f6dc9357SAndroid Build Coastguard Worker     return Extensions[index].GetString();
209*f6dc9357SAndroid Build Coastguard Worker   }
210*f6dc9357SAndroid Build Coastguard Worker 
GetFileNameNArchive::CItem211*f6dc9357SAndroid Build Coastguard Worker   AString GetFileName() const
212*f6dc9357SAndroid Build Coastguard Worker   {
213*f6dc9357SAndroid Build Coastguard Worker     int index = FindExt(kExtIdFileName);
214*f6dc9357SAndroid Build Coastguard Worker     if (index < 0)
215*f6dc9357SAndroid Build Coastguard Worker       return Name;
216*f6dc9357SAndroid Build Coastguard Worker     return Extensions[index].GetString();
217*f6dc9357SAndroid Build Coastguard Worker   }
218*f6dc9357SAndroid Build Coastguard Worker 
GetNameNArchive::CItem219*f6dc9357SAndroid Build Coastguard Worker   AString GetName() const
220*f6dc9357SAndroid Build Coastguard Worker   {
221*f6dc9357SAndroid Build Coastguard Worker     AString s (GetDirName());
222*f6dc9357SAndroid Build Coastguard Worker     const char kDirSeparator = '\\';
223*f6dc9357SAndroid Build Coastguard Worker     // check kDirSeparator in Linux
224*f6dc9357SAndroid Build Coastguard Worker     s.Replace((char)(Byte)0xFF, kDirSeparator);
225*f6dc9357SAndroid Build Coastguard Worker     if (!s.IsEmpty() && s.Back() != kDirSeparator)
226*f6dc9357SAndroid Build Coastguard Worker       s += kDirSeparator;
227*f6dc9357SAndroid Build Coastguard Worker     s += GetFileName();
228*f6dc9357SAndroid Build Coastguard Worker     return s;
229*f6dc9357SAndroid Build Coastguard Worker   }
230*f6dc9357SAndroid Build Coastguard Worker };
231*f6dc9357SAndroid Build Coastguard Worker 
ReadUInt16(const Byte * p,UInt16 & v)232*f6dc9357SAndroid Build Coastguard Worker static const Byte *ReadUInt16(const Byte *p, UInt16 &v)
233*f6dc9357SAndroid Build Coastguard Worker {
234*f6dc9357SAndroid Build Coastguard Worker   v = Get16(p);
235*f6dc9357SAndroid Build Coastguard Worker   return p + 2;
236*f6dc9357SAndroid Build Coastguard Worker }
237*f6dc9357SAndroid Build Coastguard Worker 
ReadString(const Byte * p,size_t size,AString & s)238*f6dc9357SAndroid Build Coastguard Worker static const Byte *ReadString(const Byte *p, size_t size, AString &s)
239*f6dc9357SAndroid Build Coastguard Worker {
240*f6dc9357SAndroid Build Coastguard Worker   s.Empty();
241*f6dc9357SAndroid Build Coastguard Worker   for (size_t i = 0; i < size; i++)
242*f6dc9357SAndroid Build Coastguard Worker   {
243*f6dc9357SAndroid Build Coastguard Worker     const Byte c = p[i];
244*f6dc9357SAndroid Build Coastguard Worker     if (c == 0)
245*f6dc9357SAndroid Build Coastguard Worker       break;
246*f6dc9357SAndroid Build Coastguard Worker     s += (char)c;
247*f6dc9357SAndroid Build Coastguard Worker   }
248*f6dc9357SAndroid Build Coastguard Worker   return p + size;
249*f6dc9357SAndroid Build Coastguard Worker }
250*f6dc9357SAndroid Build Coastguard Worker 
CalcSum(const Byte * data,size_t size)251*f6dc9357SAndroid Build Coastguard Worker static Byte CalcSum(const Byte *data, size_t size)
252*f6dc9357SAndroid Build Coastguard Worker {
253*f6dc9357SAndroid Build Coastguard Worker   Byte sum = 0;
254*f6dc9357SAndroid Build Coastguard Worker   for (size_t i = 0; i < size; i++)
255*f6dc9357SAndroid Build Coastguard Worker     sum = (Byte)(sum + data[i]);
256*f6dc9357SAndroid Build Coastguard Worker   return sum;
257*f6dc9357SAndroid Build Coastguard Worker }
258*f6dc9357SAndroid Build Coastguard Worker 
GetNextItem(ISequentialInStream * stream,bool & filled,CItem & item)259*f6dc9357SAndroid Build Coastguard Worker static HRESULT GetNextItem(ISequentialInStream *stream, bool &filled, CItem &item)
260*f6dc9357SAndroid Build Coastguard Worker {
261*f6dc9357SAndroid Build Coastguard Worker   filled = false;
262*f6dc9357SAndroid Build Coastguard Worker 
263*f6dc9357SAndroid Build Coastguard Worker   size_t processedSize = 2;
264*f6dc9357SAndroid Build Coastguard Worker   Byte startHeader[2];
265*f6dc9357SAndroid Build Coastguard Worker   RINOK(ReadStream(stream, startHeader, &processedSize))
266*f6dc9357SAndroid Build Coastguard Worker   if (processedSize == 0)
267*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
268*f6dc9357SAndroid Build Coastguard Worker   if (processedSize == 1)
269*f6dc9357SAndroid Build Coastguard Worker     return (startHeader[0] == 0) ? S_OK: S_FALSE;
270*f6dc9357SAndroid Build Coastguard Worker   if (startHeader[0] == 0 && startHeader[1] == 0)
271*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
272*f6dc9357SAndroid Build Coastguard Worker 
273*f6dc9357SAndroid Build Coastguard Worker   Byte header[256];
274*f6dc9357SAndroid Build Coastguard Worker   processedSize = kBasicPartSize;
275*f6dc9357SAndroid Build Coastguard Worker   RINOK(ReadStream(stream, header, &processedSize))
276*f6dc9357SAndroid Build Coastguard Worker   if (processedSize != kBasicPartSize)
277*f6dc9357SAndroid Build Coastguard Worker     return (startHeader[0] == 0) ? S_OK: S_FALSE;
278*f6dc9357SAndroid Build Coastguard Worker 
279*f6dc9357SAndroid Build Coastguard Worker   const Byte *p = header;
280*f6dc9357SAndroid Build Coastguard Worker   memcpy(item.Method, p, kMethodIdSize);
281*f6dc9357SAndroid Build Coastguard Worker   if (!item.IsValidMethod())
282*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
283*f6dc9357SAndroid Build Coastguard Worker   p += kMethodIdSize;
284*f6dc9357SAndroid Build Coastguard Worker   item.PackSize = Get32(p);
285*f6dc9357SAndroid Build Coastguard Worker   item.Size = Get32(p + 4);
286*f6dc9357SAndroid Build Coastguard Worker   item.ModifiedTime = Get32(p + 8);
287*f6dc9357SAndroid Build Coastguard Worker   item.Attributes = p[12];
288*f6dc9357SAndroid Build Coastguard Worker   item.Level = p[13];
289*f6dc9357SAndroid Build Coastguard Worker   p += 14;
290*f6dc9357SAndroid Build Coastguard Worker   if (item.Level > 2)
291*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
292*f6dc9357SAndroid Build Coastguard Worker   UInt32 headerSize;
293*f6dc9357SAndroid Build Coastguard Worker   if (item.Level < 2)
294*f6dc9357SAndroid Build Coastguard Worker   {
295*f6dc9357SAndroid Build Coastguard Worker     headerSize = startHeader[0];
296*f6dc9357SAndroid Build Coastguard Worker     if (headerSize < kBasicPartSize)
297*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
298*f6dc9357SAndroid Build Coastguard Worker     RINOK(ReadStream_FALSE(stream, header + kBasicPartSize, headerSize - kBasicPartSize))
299*f6dc9357SAndroid Build Coastguard Worker     if (startHeader[1] != CalcSum(header, headerSize))
300*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
301*f6dc9357SAndroid Build Coastguard Worker     const size_t nameLength = *p++;
302*f6dc9357SAndroid Build Coastguard Worker     if ((size_t)(p - header) + nameLength + 2 > headerSize)
303*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
304*f6dc9357SAndroid Build Coastguard Worker     p = ReadString(p, nameLength, item.Name);
305*f6dc9357SAndroid Build Coastguard Worker   }
306*f6dc9357SAndroid Build Coastguard Worker   else
307*f6dc9357SAndroid Build Coastguard Worker     headerSize = startHeader[0] | ((UInt32)startHeader[1] << 8);
308*f6dc9357SAndroid Build Coastguard Worker   p = ReadUInt16(p, item.CRC);
309*f6dc9357SAndroid Build Coastguard Worker   if (item.Level != 0)
310*f6dc9357SAndroid Build Coastguard Worker   {
311*f6dc9357SAndroid Build Coastguard Worker     if (item.Level == 2)
312*f6dc9357SAndroid Build Coastguard Worker     {
313*f6dc9357SAndroid Build Coastguard Worker       RINOK(ReadStream_FALSE(stream, header + kBasicPartSize, 2))
314*f6dc9357SAndroid Build Coastguard Worker     }
315*f6dc9357SAndroid Build Coastguard Worker     if ((size_t)(p - header) + 3 > headerSize)
316*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
317*f6dc9357SAndroid Build Coastguard Worker     item.OsId = *p++;
318*f6dc9357SAndroid Build Coastguard Worker     UInt16 nextSize;
319*f6dc9357SAndroid Build Coastguard Worker     p = ReadUInt16(p, nextSize);
320*f6dc9357SAndroid Build Coastguard Worker     while (nextSize != 0)
321*f6dc9357SAndroid Build Coastguard Worker     {
322*f6dc9357SAndroid Build Coastguard Worker       if (nextSize < 3)
323*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
324*f6dc9357SAndroid Build Coastguard Worker       if (item.Level == 1)
325*f6dc9357SAndroid Build Coastguard Worker       {
326*f6dc9357SAndroid Build Coastguard Worker         if (item.PackSize < nextSize)
327*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
328*f6dc9357SAndroid Build Coastguard Worker         item.PackSize -= nextSize;
329*f6dc9357SAndroid Build Coastguard Worker       }
330*f6dc9357SAndroid Build Coastguard Worker       if (item.Extensions.Size() >= (1 << 8))
331*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
332*f6dc9357SAndroid Build Coastguard Worker       CExtension ext;
333*f6dc9357SAndroid Build Coastguard Worker       RINOK(ReadStream_FALSE(stream, &ext.Type, 1))
334*f6dc9357SAndroid Build Coastguard Worker       nextSize = (UInt16)(nextSize - 3);
335*f6dc9357SAndroid Build Coastguard Worker       ext.Data.Alloc(nextSize);
336*f6dc9357SAndroid Build Coastguard Worker       RINOK(ReadStream_FALSE(stream, (Byte *)ext.Data, nextSize))
337*f6dc9357SAndroid Build Coastguard Worker       item.Extensions.Add(ext);
338*f6dc9357SAndroid Build Coastguard Worker       Byte hdr2[2];
339*f6dc9357SAndroid Build Coastguard Worker       RINOK(ReadStream_FALSE(stream, hdr2, 2))
340*f6dc9357SAndroid Build Coastguard Worker       ReadUInt16(hdr2, nextSize);
341*f6dc9357SAndroid Build Coastguard Worker     }
342*f6dc9357SAndroid Build Coastguard Worker   }
343*f6dc9357SAndroid Build Coastguard Worker   filled = true;
344*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
345*f6dc9357SAndroid Build Coastguard Worker }
346*f6dc9357SAndroid Build Coastguard Worker 
347*f6dc9357SAndroid Build Coastguard Worker 
348*f6dc9357SAndroid Build Coastguard Worker static const CUInt32PCharPair g_OsPairs[] =
349*f6dc9357SAndroid Build Coastguard Worker {
350*f6dc9357SAndroid Build Coastguard Worker   {   0, "MS-DOS" },
351*f6dc9357SAndroid Build Coastguard Worker   { 'M', "MS-DOS" },
352*f6dc9357SAndroid Build Coastguard Worker   { '2', "OS/2" },
353*f6dc9357SAndroid Build Coastguard Worker   { '9', "OS9" },
354*f6dc9357SAndroid Build Coastguard Worker   { 'K', "OS/68K" },
355*f6dc9357SAndroid Build Coastguard Worker   { '3', "OS/386" },
356*f6dc9357SAndroid Build Coastguard Worker   { 'H', "HUMAN" },
357*f6dc9357SAndroid Build Coastguard Worker   { 'U', "UNIX" },
358*f6dc9357SAndroid Build Coastguard Worker   { 'C', "CP/M" },
359*f6dc9357SAndroid Build Coastguard Worker   { 'F', "FLEX" },
360*f6dc9357SAndroid Build Coastguard Worker   { 'm', "Mac" },
361*f6dc9357SAndroid Build Coastguard Worker   { 'R', "Runser" },
362*f6dc9357SAndroid Build Coastguard Worker   { 'T', "TownsOS" },
363*f6dc9357SAndroid Build Coastguard Worker   { 'X', "XOSK" },
364*f6dc9357SAndroid Build Coastguard Worker   { 'w', "Windows 95" },
365*f6dc9357SAndroid Build Coastguard Worker   { 'W', "Windows NT" },
366*f6dc9357SAndroid Build Coastguard Worker   { 'J', "Java VM" }
367*f6dc9357SAndroid Build Coastguard Worker };
368*f6dc9357SAndroid Build Coastguard Worker 
369*f6dc9357SAndroid Build Coastguard Worker 
370*f6dc9357SAndroid Build Coastguard Worker static const Byte kProps[] =
371*f6dc9357SAndroid Build Coastguard Worker {
372*f6dc9357SAndroid Build Coastguard Worker   kpidPath,
373*f6dc9357SAndroid Build Coastguard Worker   kpidIsDir,
374*f6dc9357SAndroid Build Coastguard Worker   kpidSize,
375*f6dc9357SAndroid Build Coastguard Worker   kpidPackSize,
376*f6dc9357SAndroid Build Coastguard Worker   kpidMTime,
377*f6dc9357SAndroid Build Coastguard Worker   // kpidAttrib,
378*f6dc9357SAndroid Build Coastguard Worker   kpidCRC,
379*f6dc9357SAndroid Build Coastguard Worker   kpidMethod,
380*f6dc9357SAndroid Build Coastguard Worker   kpidHostOS
381*f6dc9357SAndroid Build Coastguard Worker };
382*f6dc9357SAndroid Build Coastguard Worker 
383*f6dc9357SAndroid Build Coastguard Worker 
384*f6dc9357SAndroid Build Coastguard Worker Z7_CLASS_IMP_NOQIB_1(
385*f6dc9357SAndroid Build Coastguard Worker   COutStreamWithCRC
386*f6dc9357SAndroid Build Coastguard Worker   , ISequentialOutStream
387*f6dc9357SAndroid Build Coastguard Worker )
388*f6dc9357SAndroid Build Coastguard Worker   UInt32 _crc;
389*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<ISequentialOutStream> _stream;
390*f6dc9357SAndroid Build Coastguard Worker public:
391*f6dc9357SAndroid Build Coastguard Worker   void Init(ISequentialOutStream *stream)
392*f6dc9357SAndroid Build Coastguard Worker   {
393*f6dc9357SAndroid Build Coastguard Worker     _stream = stream;
394*f6dc9357SAndroid Build Coastguard Worker     _crc = 0;
395*f6dc9357SAndroid Build Coastguard Worker   }
396*f6dc9357SAndroid Build Coastguard Worker   void ReleaseStream() { _stream.Release(); }
397*f6dc9357SAndroid Build Coastguard Worker   UInt32 GetCRC() const { return _crc; }
398*f6dc9357SAndroid Build Coastguard Worker };
399*f6dc9357SAndroid Build Coastguard Worker 
400*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(COutStreamWithCRC::Write(const void *data, UInt32 size, UInt32 *processedSize))
401*f6dc9357SAndroid Build Coastguard Worker {
402*f6dc9357SAndroid Build Coastguard Worker   HRESULT res = S_OK;
403*f6dc9357SAndroid Build Coastguard Worker   if (_stream)
404*f6dc9357SAndroid Build Coastguard Worker     res = _stream->Write(data, size, &size);
405*f6dc9357SAndroid Build Coastguard Worker   _crc = LzhCrc16Update(_crc, data, size);
406*f6dc9357SAndroid Build Coastguard Worker   if (processedSize)
407*f6dc9357SAndroid Build Coastguard Worker     *processedSize = size;
408*f6dc9357SAndroid Build Coastguard Worker   return res;
409*f6dc9357SAndroid Build Coastguard Worker }
410*f6dc9357SAndroid Build Coastguard Worker 
411*f6dc9357SAndroid Build Coastguard Worker 
412*f6dc9357SAndroid Build Coastguard Worker struct CItemEx: public CItem
413*f6dc9357SAndroid Build Coastguard Worker {
414*f6dc9357SAndroid Build Coastguard Worker   UInt64 DataPosition;
415*f6dc9357SAndroid Build Coastguard Worker };
416*f6dc9357SAndroid Build Coastguard Worker 
417*f6dc9357SAndroid Build Coastguard Worker 
418*f6dc9357SAndroid Build Coastguard Worker Z7_CLASS_IMP_CHandler_IInArchive_0
419*f6dc9357SAndroid Build Coastguard Worker 
420*f6dc9357SAndroid Build Coastguard Worker   CObjectVector<CItemEx> _items;
421*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<IInStream> _stream;
422*f6dc9357SAndroid Build Coastguard Worker   UInt64 _phySize;
423*f6dc9357SAndroid Build Coastguard Worker   UInt32 _errorFlags;
424*f6dc9357SAndroid Build Coastguard Worker   bool _isArc;
425*f6dc9357SAndroid Build Coastguard Worker public:
426*f6dc9357SAndroid Build Coastguard Worker   CHandler();
427*f6dc9357SAndroid Build Coastguard Worker };
428*f6dc9357SAndroid Build Coastguard Worker 
429*f6dc9357SAndroid Build Coastguard Worker IMP_IInArchive_Props
430*f6dc9357SAndroid Build Coastguard Worker IMP_IInArchive_ArcProps_NO_Table
431*f6dc9357SAndroid Build Coastguard Worker 
432*f6dc9357SAndroid Build Coastguard Worker CHandler::CHandler() {}
433*f6dc9357SAndroid Build Coastguard Worker 
434*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
435*f6dc9357SAndroid Build Coastguard Worker {
436*f6dc9357SAndroid Build Coastguard Worker   *numItems = _items.Size();
437*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
438*f6dc9357SAndroid Build Coastguard Worker }
439*f6dc9357SAndroid Build Coastguard Worker 
440*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
441*f6dc9357SAndroid Build Coastguard Worker {
442*f6dc9357SAndroid Build Coastguard Worker   NCOM::CPropVariant prop;
443*f6dc9357SAndroid Build Coastguard Worker   switch (propID)
444*f6dc9357SAndroid Build Coastguard Worker   {
445*f6dc9357SAndroid Build Coastguard Worker     case kpidPhySize: prop = _phySize; break;
446*f6dc9357SAndroid Build Coastguard Worker 
447*f6dc9357SAndroid Build Coastguard Worker     case kpidErrorFlags:
448*f6dc9357SAndroid Build Coastguard Worker       UInt32 v = _errorFlags;
449*f6dc9357SAndroid Build Coastguard Worker       if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;
450*f6dc9357SAndroid Build Coastguard Worker       prop = v;
451*f6dc9357SAndroid Build Coastguard Worker       break;
452*f6dc9357SAndroid Build Coastguard Worker   }
453*f6dc9357SAndroid Build Coastguard Worker   prop.Detach(value);
454*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
455*f6dc9357SAndroid Build Coastguard Worker }
456*f6dc9357SAndroid Build Coastguard Worker 
457*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
458*f6dc9357SAndroid Build Coastguard Worker {
459*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
460*f6dc9357SAndroid Build Coastguard Worker   NCOM::CPropVariant prop;
461*f6dc9357SAndroid Build Coastguard Worker   const CItemEx &item = _items[index];
462*f6dc9357SAndroid Build Coastguard Worker   switch (propID)
463*f6dc9357SAndroid Build Coastguard Worker   {
464*f6dc9357SAndroid Build Coastguard Worker     case kpidPath:
465*f6dc9357SAndroid Build Coastguard Worker     {
466*f6dc9357SAndroid Build Coastguard Worker       UString s = NItemName::WinPathToOsPath(MultiByteToUnicodeString(item.GetName(), CP_OEMCP));
467*f6dc9357SAndroid Build Coastguard Worker       if (!s.IsEmpty())
468*f6dc9357SAndroid Build Coastguard Worker       {
469*f6dc9357SAndroid Build Coastguard Worker         if (s.Back() == WCHAR_PATH_SEPARATOR)
470*f6dc9357SAndroid Build Coastguard Worker           s.DeleteBack();
471*f6dc9357SAndroid Build Coastguard Worker         prop = s;
472*f6dc9357SAndroid Build Coastguard Worker       }
473*f6dc9357SAndroid Build Coastguard Worker       break;
474*f6dc9357SAndroid Build Coastguard Worker     }
475*f6dc9357SAndroid Build Coastguard Worker     case kpidIsDir:  prop = item.IsDir(); break;
476*f6dc9357SAndroid Build Coastguard Worker     case kpidSize:   prop = (UInt64)item.Size; break;
477*f6dc9357SAndroid Build Coastguard Worker     case kpidPackSize:  prop = (UInt64)item.PackSize; break;
478*f6dc9357SAndroid Build Coastguard Worker     case kpidCRC:  prop = (UInt32)item.CRC; break;
479*f6dc9357SAndroid Build Coastguard Worker     case kpidHostOS:  PAIR_TO_PROP(g_OsPairs, item.OsId, prop); break;
480*f6dc9357SAndroid Build Coastguard Worker     case kpidMTime:
481*f6dc9357SAndroid Build Coastguard Worker     {
482*f6dc9357SAndroid Build Coastguard Worker       UInt32 unixTime;
483*f6dc9357SAndroid Build Coastguard Worker       if (item.GetUnixTime(unixTime))
484*f6dc9357SAndroid Build Coastguard Worker         PropVariant_SetFrom_UnixTime(prop, unixTime);
485*f6dc9357SAndroid Build Coastguard Worker       else
486*f6dc9357SAndroid Build Coastguard Worker         PropVariant_SetFrom_DosTime(prop, item.ModifiedTime);
487*f6dc9357SAndroid Build Coastguard Worker       break;
488*f6dc9357SAndroid Build Coastguard Worker     }
489*f6dc9357SAndroid Build Coastguard Worker     // case kpidAttrib:  prop = (UInt32)item.Attributes; break;
490*f6dc9357SAndroid Build Coastguard Worker     case kpidMethod:
491*f6dc9357SAndroid Build Coastguard Worker     {
492*f6dc9357SAndroid Build Coastguard Worker       char method2[kMethodIdSize + 1];
493*f6dc9357SAndroid Build Coastguard Worker       method2[kMethodIdSize] = 0;
494*f6dc9357SAndroid Build Coastguard Worker       memcpy(method2, item.Method, kMethodIdSize);
495*f6dc9357SAndroid Build Coastguard Worker       prop = method2;
496*f6dc9357SAndroid Build Coastguard Worker       break;
497*f6dc9357SAndroid Build Coastguard Worker     }
498*f6dc9357SAndroid Build Coastguard Worker   }
499*f6dc9357SAndroid Build Coastguard Worker   prop.Detach(value);
500*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
501*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
502*f6dc9357SAndroid Build Coastguard Worker }
503*f6dc9357SAndroid Build Coastguard Worker 
504*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Open(IInStream *stream,
505*f6dc9357SAndroid Build Coastguard Worker     const UInt64 * /* maxCheckStartPosition */, IArchiveOpenCallback *callback))
506*f6dc9357SAndroid Build Coastguard Worker {
507*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
508*f6dc9357SAndroid Build Coastguard Worker   Close();
509*f6dc9357SAndroid Build Coastguard Worker   try
510*f6dc9357SAndroid Build Coastguard Worker   {
511*f6dc9357SAndroid Build Coastguard Worker     _items.Clear();
512*f6dc9357SAndroid Build Coastguard Worker 
513*f6dc9357SAndroid Build Coastguard Worker     UInt64 endPos;
514*f6dc9357SAndroid Build Coastguard Worker     bool needSetTotal = true;
515*f6dc9357SAndroid Build Coastguard Worker 
516*f6dc9357SAndroid Build Coastguard Worker     RINOK(InStream_AtBegin_GetSize(stream, endPos))
517*f6dc9357SAndroid Build Coastguard Worker 
518*f6dc9357SAndroid Build Coastguard Worker     for (;;)
519*f6dc9357SAndroid Build Coastguard Worker     {
520*f6dc9357SAndroid Build Coastguard Worker       CItemEx item;
521*f6dc9357SAndroid Build Coastguard Worker       bool filled;
522*f6dc9357SAndroid Build Coastguard Worker       const HRESULT res = GetNextItem(stream, filled, item);
523*f6dc9357SAndroid Build Coastguard Worker       RINOK(InStream_GetPos(stream, item.DataPosition))
524*f6dc9357SAndroid Build Coastguard Worker       if (res == S_FALSE)
525*f6dc9357SAndroid Build Coastguard Worker       {
526*f6dc9357SAndroid Build Coastguard Worker         _errorFlags = kpv_ErrorFlags_HeadersError;
527*f6dc9357SAndroid Build Coastguard Worker         break;
528*f6dc9357SAndroid Build Coastguard Worker       }
529*f6dc9357SAndroid Build Coastguard Worker 
530*f6dc9357SAndroid Build Coastguard Worker       if (res != S_OK)
531*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
532*f6dc9357SAndroid Build Coastguard Worker       _phySize = item.DataPosition;
533*f6dc9357SAndroid Build Coastguard Worker       if (!filled)
534*f6dc9357SAndroid Build Coastguard Worker         break;
535*f6dc9357SAndroid Build Coastguard Worker       _items.Add(item);
536*f6dc9357SAndroid Build Coastguard Worker 
537*f6dc9357SAndroid Build Coastguard Worker       _isArc = true;
538*f6dc9357SAndroid Build Coastguard Worker 
539*f6dc9357SAndroid Build Coastguard Worker       UInt64 newPostion;
540*f6dc9357SAndroid Build Coastguard Worker       RINOK(stream->Seek(item.PackSize, STREAM_SEEK_CUR, &newPostion))
541*f6dc9357SAndroid Build Coastguard Worker       if (newPostion > endPos)
542*f6dc9357SAndroid Build Coastguard Worker       {
543*f6dc9357SAndroid Build Coastguard Worker         _phySize = endPos;
544*f6dc9357SAndroid Build Coastguard Worker         _errorFlags = kpv_ErrorFlags_UnexpectedEnd;
545*f6dc9357SAndroid Build Coastguard Worker         break;
546*f6dc9357SAndroid Build Coastguard Worker       }
547*f6dc9357SAndroid Build Coastguard Worker       _phySize = newPostion;
548*f6dc9357SAndroid Build Coastguard Worker       if (callback)
549*f6dc9357SAndroid Build Coastguard Worker       {
550*f6dc9357SAndroid Build Coastguard Worker         if (needSetTotal)
551*f6dc9357SAndroid Build Coastguard Worker         {
552*f6dc9357SAndroid Build Coastguard Worker           RINOK(callback->SetTotal(NULL, &endPos))
553*f6dc9357SAndroid Build Coastguard Worker           needSetTotal = false;
554*f6dc9357SAndroid Build Coastguard Worker         }
555*f6dc9357SAndroid Build Coastguard Worker         if (_items.Size() % 100 == 0)
556*f6dc9357SAndroid Build Coastguard Worker         {
557*f6dc9357SAndroid Build Coastguard Worker           const UInt64 numFiles = _items.Size();
558*f6dc9357SAndroid Build Coastguard Worker           const UInt64 numBytes = item.DataPosition;
559*f6dc9357SAndroid Build Coastguard Worker           RINOK(callback->SetCompleted(&numFiles, &numBytes))
560*f6dc9357SAndroid Build Coastguard Worker         }
561*f6dc9357SAndroid Build Coastguard Worker       }
562*f6dc9357SAndroid Build Coastguard Worker     }
563*f6dc9357SAndroid Build Coastguard Worker     if (_items.IsEmpty())
564*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
565*f6dc9357SAndroid Build Coastguard Worker 
566*f6dc9357SAndroid Build Coastguard Worker     _stream = stream;
567*f6dc9357SAndroid Build Coastguard Worker   }
568*f6dc9357SAndroid Build Coastguard Worker   catch(...)
569*f6dc9357SAndroid Build Coastguard Worker   {
570*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
571*f6dc9357SAndroid Build Coastguard Worker   }
572*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
573*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
574*f6dc9357SAndroid Build Coastguard Worker }
575*f6dc9357SAndroid Build Coastguard Worker 
576*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Close())
577*f6dc9357SAndroid Build Coastguard Worker {
578*f6dc9357SAndroid Build Coastguard Worker   _isArc = false;
579*f6dc9357SAndroid Build Coastguard Worker   _phySize = 0;
580*f6dc9357SAndroid Build Coastguard Worker   _errorFlags = 0;
581*f6dc9357SAndroid Build Coastguard Worker   _items.Clear();
582*f6dc9357SAndroid Build Coastguard Worker   _stream.Release();
583*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
584*f6dc9357SAndroid Build Coastguard Worker }
585*f6dc9357SAndroid Build Coastguard Worker 
586*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
587*f6dc9357SAndroid Build Coastguard Worker     Int32 testMode, IArchiveExtractCallback *extractCallback))
588*f6dc9357SAndroid Build Coastguard Worker {
589*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
590*f6dc9357SAndroid Build Coastguard Worker   const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
591*f6dc9357SAndroid Build Coastguard Worker   if (allFilesMode)
592*f6dc9357SAndroid Build Coastguard Worker     numItems = _items.Size();
593*f6dc9357SAndroid Build Coastguard Worker   if (numItems == 0)
594*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
595*f6dc9357SAndroid Build Coastguard Worker   UInt64 totalUnPacked = 0 /* , totalPacked = 0 */;
596*f6dc9357SAndroid Build Coastguard Worker   UInt32 i;
597*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < numItems; i++)
598*f6dc9357SAndroid Build Coastguard Worker   {
599*f6dc9357SAndroid Build Coastguard Worker     const CItemEx &item = _items[allFilesMode ? i : indices[i]];
600*f6dc9357SAndroid Build Coastguard Worker     totalUnPacked += item.Size;
601*f6dc9357SAndroid Build Coastguard Worker     // totalPacked += item.PackSize;
602*f6dc9357SAndroid Build Coastguard Worker   }
603*f6dc9357SAndroid Build Coastguard Worker   RINOK(extractCallback->SetTotal(totalUnPacked))
604*f6dc9357SAndroid Build Coastguard Worker 
605*f6dc9357SAndroid Build Coastguard Worker   UInt32 cur_Unpacked, cur_Packed;
606*f6dc9357SAndroid Build Coastguard Worker 
607*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ICompressProgressInfo, CLocalProgress> lps;
608*f6dc9357SAndroid Build Coastguard Worker   lps->Init(extractCallback, false);
609*f6dc9357SAndroid Build Coastguard Worker   CMyUniquePtr<NCompress::NLzh::NDecoder::CCoder> lzhDecoder;
610*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ICompressCoder, NCompress::CCopyCoder> copyCoder;
611*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ISequentialInStream, CLimitedSequentialInStream> inStream;
612*f6dc9357SAndroid Build Coastguard Worker   inStream->SetStream(_stream);
613*f6dc9357SAndroid Build Coastguard Worker 
614*f6dc9357SAndroid Build Coastguard Worker   for (i = 0;; i++,
615*f6dc9357SAndroid Build Coastguard Worker       lps->OutSize += cur_Unpacked,
616*f6dc9357SAndroid Build Coastguard Worker       lps->InSize += cur_Packed)
617*f6dc9357SAndroid Build Coastguard Worker   {
618*f6dc9357SAndroid Build Coastguard Worker     cur_Unpacked = 0;
619*f6dc9357SAndroid Build Coastguard Worker     cur_Packed = 0;
620*f6dc9357SAndroid Build Coastguard Worker     RINOK(lps->SetCur())
621*f6dc9357SAndroid Build Coastguard Worker     if (i >= numItems)
622*f6dc9357SAndroid Build Coastguard Worker       break;
623*f6dc9357SAndroid Build Coastguard Worker 
624*f6dc9357SAndroid Build Coastguard Worker     Int32 opRes;
625*f6dc9357SAndroid Build Coastguard Worker     {
626*f6dc9357SAndroid Build Coastguard Worker       CMyComPtr<ISequentialOutStream> realOutStream;
627*f6dc9357SAndroid Build Coastguard Worker       const Int32 askMode = testMode ?
628*f6dc9357SAndroid Build Coastguard Worker           NExtract::NAskMode::kTest :
629*f6dc9357SAndroid Build Coastguard Worker           NExtract::NAskMode::kExtract;
630*f6dc9357SAndroid Build Coastguard Worker       const UInt32 index = allFilesMode ? i : indices[i];
631*f6dc9357SAndroid Build Coastguard Worker       const CItemEx &item = _items[index];
632*f6dc9357SAndroid Build Coastguard Worker       RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
633*f6dc9357SAndroid Build Coastguard Worker 
634*f6dc9357SAndroid Build Coastguard Worker       if (item.IsDir())
635*f6dc9357SAndroid Build Coastguard Worker       {
636*f6dc9357SAndroid Build Coastguard Worker         // if (!testMode)
637*f6dc9357SAndroid Build Coastguard Worker         {
638*f6dc9357SAndroid Build Coastguard Worker           RINOK(extractCallback->PrepareOperation(askMode))
639*f6dc9357SAndroid Build Coastguard Worker           RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
640*f6dc9357SAndroid Build Coastguard Worker         }
641*f6dc9357SAndroid Build Coastguard Worker         continue;
642*f6dc9357SAndroid Build Coastguard Worker       }
643*f6dc9357SAndroid Build Coastguard Worker 
644*f6dc9357SAndroid Build Coastguard Worker       if (!testMode && !realOutStream)
645*f6dc9357SAndroid Build Coastguard Worker         continue;
646*f6dc9357SAndroid Build Coastguard Worker 
647*f6dc9357SAndroid Build Coastguard Worker       RINOK(extractCallback->PrepareOperation(askMode))
648*f6dc9357SAndroid Build Coastguard Worker       cur_Unpacked = item.Size;
649*f6dc9357SAndroid Build Coastguard Worker       cur_Packed = item.PackSize;
650*f6dc9357SAndroid Build Coastguard Worker 
651*f6dc9357SAndroid Build Coastguard Worker       CMyComPtr2_Create<ISequentialOutStream, COutStreamWithCRC> outStream;
652*f6dc9357SAndroid Build Coastguard Worker       outStream->Init(realOutStream);
653*f6dc9357SAndroid Build Coastguard Worker       realOutStream.Release();
654*f6dc9357SAndroid Build Coastguard Worker 
655*f6dc9357SAndroid Build Coastguard Worker       RINOK(InStream_SeekSet(_stream, item.DataPosition))
656*f6dc9357SAndroid Build Coastguard Worker 
657*f6dc9357SAndroid Build Coastguard Worker       inStream->Init(item.PackSize);
658*f6dc9357SAndroid Build Coastguard Worker 
659*f6dc9357SAndroid Build Coastguard Worker       HRESULT res = S_OK;
660*f6dc9357SAndroid Build Coastguard Worker       opRes = NExtract::NOperationResult::kOK;
661*f6dc9357SAndroid Build Coastguard Worker 
662*f6dc9357SAndroid Build Coastguard Worker       if (item.IsCopyMethod())
663*f6dc9357SAndroid Build Coastguard Worker       {
664*f6dc9357SAndroid Build Coastguard Worker         res = copyCoder.Interface()->Code(inStream, outStream, NULL, NULL, lps);
665*f6dc9357SAndroid Build Coastguard Worker         if (res == S_OK && copyCoder->TotalSize != item.PackSize)
666*f6dc9357SAndroid Build Coastguard Worker           res = S_FALSE;
667*f6dc9357SAndroid Build Coastguard Worker       }
668*f6dc9357SAndroid Build Coastguard Worker       else if (item.IsLh4GroupMethod())
669*f6dc9357SAndroid Build Coastguard Worker       {
670*f6dc9357SAndroid Build Coastguard Worker         lzhDecoder.Create_if_Empty();
671*f6dc9357SAndroid Build Coastguard Worker         // lzhDecoder->FinishMode = true;
672*f6dc9357SAndroid Build Coastguard Worker         lzhDecoder->SetDictSize((UInt32)1 << item.GetNumDictBits());
673*f6dc9357SAndroid Build Coastguard Worker         res = lzhDecoder->Code(inStream, outStream, cur_Unpacked, lps);
674*f6dc9357SAndroid Build Coastguard Worker         if (res == S_OK && lzhDecoder->GetInputProcessedSize() != item.PackSize)
675*f6dc9357SAndroid Build Coastguard Worker           res = S_FALSE;
676*f6dc9357SAndroid Build Coastguard Worker       }
677*f6dc9357SAndroid Build Coastguard Worker       /*
678*f6dc9357SAndroid Build Coastguard Worker       else if (item.IsLh1GroupMethod())
679*f6dc9357SAndroid Build Coastguard Worker       {
680*f6dc9357SAndroid Build Coastguard Worker         if (!lzh1Decoder)
681*f6dc9357SAndroid Build Coastguard Worker         {
682*f6dc9357SAndroid Build Coastguard Worker           lzh1DecoderSpec = new NCompress::NLzh1::NDecoder::CCoder;
683*f6dc9357SAndroid Build Coastguard Worker           lzh1Decoder = lzh1DecoderSpec;
684*f6dc9357SAndroid Build Coastguard Worker         }
685*f6dc9357SAndroid Build Coastguard Worker         lzh1DecoderSpec->SetDictionary(item.GetNumDictBits());
686*f6dc9357SAndroid Build Coastguard Worker         res = lzh1Decoder->Code(inStream, outStream, NULL, &cur_Unpacked, progress);
687*f6dc9357SAndroid Build Coastguard Worker       }
688*f6dc9357SAndroid Build Coastguard Worker       */
689*f6dc9357SAndroid Build Coastguard Worker       else
690*f6dc9357SAndroid Build Coastguard Worker         opRes = NExtract::NOperationResult::kUnsupportedMethod;
691*f6dc9357SAndroid Build Coastguard Worker 
692*f6dc9357SAndroid Build Coastguard Worker       if (opRes == NExtract::NOperationResult::kOK)
693*f6dc9357SAndroid Build Coastguard Worker       {
694*f6dc9357SAndroid Build Coastguard Worker         if (res == S_FALSE)
695*f6dc9357SAndroid Build Coastguard Worker           opRes = NExtract::NOperationResult::kDataError;
696*f6dc9357SAndroid Build Coastguard Worker         else
697*f6dc9357SAndroid Build Coastguard Worker         {
698*f6dc9357SAndroid Build Coastguard Worker           RINOK(res)
699*f6dc9357SAndroid Build Coastguard Worker           if (outStream->GetCRC() != item.CRC)
700*f6dc9357SAndroid Build Coastguard Worker             opRes = NExtract::NOperationResult::kCRCError;
701*f6dc9357SAndroid Build Coastguard Worker         }
702*f6dc9357SAndroid Build Coastguard Worker       }
703*f6dc9357SAndroid Build Coastguard Worker     }
704*f6dc9357SAndroid Build Coastguard Worker     RINOK(extractCallback->SetOperationResult(opRes))
705*f6dc9357SAndroid Build Coastguard Worker   }
706*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
707*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
708*f6dc9357SAndroid Build Coastguard Worker }
709*f6dc9357SAndroid Build Coastguard Worker 
710*f6dc9357SAndroid Build Coastguard Worker static const Byte k_Signature[] = { '-', 'l', 'h' };
711*f6dc9357SAndroid Build Coastguard Worker 
712*f6dc9357SAndroid Build Coastguard Worker REGISTER_ARC_I(
713*f6dc9357SAndroid Build Coastguard Worker   "Lzh", "lzh lha", NULL, 6,
714*f6dc9357SAndroid Build Coastguard Worker   k_Signature,
715*f6dc9357SAndroid Build Coastguard Worker   2,
716*f6dc9357SAndroid Build Coastguard Worker   0,
717*f6dc9357SAndroid Build Coastguard Worker   IsArc_Lzh)
718*f6dc9357SAndroid Build Coastguard Worker 
719*f6dc9357SAndroid Build Coastguard Worker }}
720