xref: /aosp_15_r20/external/lzma/CPP/7zip/Archive/ArjHandler.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1*f6dc9357SAndroid Build Coastguard Worker // ArjHandler.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/StringConvert.h"
10*f6dc9357SAndroid Build Coastguard Worker 
11*f6dc9357SAndroid Build Coastguard Worker #include "../../Windows/PropVariant.h"
12*f6dc9357SAndroid Build Coastguard Worker #include "../../Windows/PropVariantUtils.h"
13*f6dc9357SAndroid Build Coastguard Worker #include "../../Windows/TimeUtils.h"
14*f6dc9357SAndroid Build Coastguard Worker 
15*f6dc9357SAndroid Build Coastguard Worker #include "../Common/LimitedStreams.h"
16*f6dc9357SAndroid Build Coastguard Worker #include "../Common/ProgressUtils.h"
17*f6dc9357SAndroid Build Coastguard Worker #include "../Common/RegisterArc.h"
18*f6dc9357SAndroid Build Coastguard Worker #include "../Common/StreamObjects.h"
19*f6dc9357SAndroid Build Coastguard Worker #include "../Common/StreamUtils.h"
20*f6dc9357SAndroid Build Coastguard Worker 
21*f6dc9357SAndroid Build Coastguard Worker #include "../Compress/CopyCoder.h"
22*f6dc9357SAndroid Build Coastguard Worker #include "../Compress/LzhDecoder.h"
23*f6dc9357SAndroid Build Coastguard Worker 
24*f6dc9357SAndroid Build Coastguard Worker #include "Common/ItemNameUtils.h"
25*f6dc9357SAndroid Build Coastguard Worker #include "Common/OutStreamWithCRC.h"
26*f6dc9357SAndroid Build Coastguard Worker 
27*f6dc9357SAndroid Build Coastguard Worker namespace NCompress {
28*f6dc9357SAndroid Build Coastguard Worker namespace NArj {
29*f6dc9357SAndroid Build Coastguard Worker namespace NDecoder {
30*f6dc9357SAndroid Build Coastguard Worker 
31*f6dc9357SAndroid Build Coastguard Worker static const unsigned kMatchMinLen = 3;
32*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kWindowSize = 1 << 15; // must be >= (1 << 14)
33*f6dc9357SAndroid Build Coastguard Worker 
34*f6dc9357SAndroid Build Coastguard Worker class CCoder
35*f6dc9357SAndroid Build Coastguard Worker {
36*f6dc9357SAndroid Build Coastguard Worker   CLzOutWindow _outWindow;
37*f6dc9357SAndroid Build Coastguard Worker   NBitm::CDecoder<CInBuffer> _inBitStream;
38*f6dc9357SAndroid Build Coastguard Worker   // bool FinishMode;
39*f6dc9357SAndroid Build Coastguard Worker 
40*f6dc9357SAndroid Build Coastguard Worker   class CCoderReleaser
41*f6dc9357SAndroid Build Coastguard Worker   {
42*f6dc9357SAndroid Build Coastguard Worker     CCoder *_coder;
43*f6dc9357SAndroid Build Coastguard Worker   public:
CCoderReleaser(CCoder * coder)44*f6dc9357SAndroid Build Coastguard Worker     CCoderReleaser(CCoder *coder): _coder(coder) {}
Disable()45*f6dc9357SAndroid Build Coastguard Worker     void Disable() { _coder = NULL; }
~CCoderReleaser()46*f6dc9357SAndroid Build Coastguard Worker     ~CCoderReleaser() { if (_coder) _coder->_outWindow.Flush(); }
47*f6dc9357SAndroid Build Coastguard Worker   };
48*f6dc9357SAndroid Build Coastguard Worker   friend class CCoderReleaser;
49*f6dc9357SAndroid Build Coastguard Worker 
50*f6dc9357SAndroid Build Coastguard Worker   HRESULT CodeReal(UInt32 outSize, ICompressProgressInfo *progress);
51*f6dc9357SAndroid Build Coastguard Worker public:
52*f6dc9357SAndroid Build Coastguard Worker 
53*f6dc9357SAndroid Build Coastguard Worker   // CCoder(): FinishMode(true) {}
GetInputProcessedSize() const54*f6dc9357SAndroid Build Coastguard Worker   UInt64 GetInputProcessedSize() const { return _inBitStream.GetProcessedSize(); }
55*f6dc9357SAndroid Build Coastguard Worker   HRESULT Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
56*f6dc9357SAndroid Build Coastguard Worker     UInt32 outSize, ICompressProgressInfo *progress);
57*f6dc9357SAndroid Build Coastguard Worker };
58*f6dc9357SAndroid Build Coastguard Worker 
59*f6dc9357SAndroid Build Coastguard Worker 
CodeReal(UInt32 rem,ICompressProgressInfo * progress)60*f6dc9357SAndroid Build Coastguard Worker HRESULT CCoder::CodeReal(UInt32 rem, ICompressProgressInfo *progress)
61*f6dc9357SAndroid Build Coastguard Worker {
62*f6dc9357SAndroid Build Coastguard Worker   const UInt32 kStep = 1 << 20;
63*f6dc9357SAndroid Build Coastguard Worker   UInt32 next = 0;
64*f6dc9357SAndroid Build Coastguard Worker   if (rem > kStep && progress)
65*f6dc9357SAndroid Build Coastguard Worker     next = rem - kStep;
66*f6dc9357SAndroid Build Coastguard Worker 
67*f6dc9357SAndroid Build Coastguard Worker   while (rem != 0)
68*f6dc9357SAndroid Build Coastguard Worker   {
69*f6dc9357SAndroid Build Coastguard Worker     if (rem <= next)
70*f6dc9357SAndroid Build Coastguard Worker     {
71*f6dc9357SAndroid Build Coastguard Worker       if (_inBitStream.ExtraBitsWereRead())
72*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
73*f6dc9357SAndroid Build Coastguard Worker       const UInt64 packSize = _inBitStream.GetProcessedSize();
74*f6dc9357SAndroid Build Coastguard Worker       const UInt64 pos = _outWindow.GetProcessedSize();
75*f6dc9357SAndroid Build Coastguard Worker       RINOK(progress->SetRatioInfo(&packSize, &pos))
76*f6dc9357SAndroid Build Coastguard Worker       next = 0;
77*f6dc9357SAndroid Build Coastguard Worker       if (rem > kStep)
78*f6dc9357SAndroid Build Coastguard Worker         next = rem - kStep;
79*f6dc9357SAndroid Build Coastguard Worker     }
80*f6dc9357SAndroid Build Coastguard Worker 
81*f6dc9357SAndroid Build Coastguard Worker     UInt32 len;
82*f6dc9357SAndroid Build Coastguard Worker     {
83*f6dc9357SAndroid Build Coastguard Worker       const unsigned kNumBits = 7 + 7;
84*f6dc9357SAndroid Build Coastguard Worker       const UInt32 val = _inBitStream.GetValue(kNumBits);
85*f6dc9357SAndroid Build Coastguard Worker 
86*f6dc9357SAndroid Build Coastguard Worker       if ((val & (1u << (kNumBits - 1))) == 0)
87*f6dc9357SAndroid Build Coastguard Worker       {
88*f6dc9357SAndroid Build Coastguard Worker         _outWindow.PutByte((Byte)(val >> 5));
89*f6dc9357SAndroid Build Coastguard Worker         _inBitStream.MovePos(1 + 8);
90*f6dc9357SAndroid Build Coastguard Worker         rem--;
91*f6dc9357SAndroid Build Coastguard Worker         continue;
92*f6dc9357SAndroid Build Coastguard Worker       }
93*f6dc9357SAndroid Build Coastguard Worker 
94*f6dc9357SAndroid Build Coastguard Worker       unsigned w;
95*f6dc9357SAndroid Build Coastguard Worker       {
96*f6dc9357SAndroid Build Coastguard Worker         UInt32 flag = (UInt32)1 << (kNumBits - 2);
97*f6dc9357SAndroid Build Coastguard Worker         for (w = 1; w < 7; w++, flag >>= 1)
98*f6dc9357SAndroid Build Coastguard Worker           if ((val & flag) == 0)
99*f6dc9357SAndroid Build Coastguard Worker             break;
100*f6dc9357SAndroid Build Coastguard Worker       }
101*f6dc9357SAndroid Build Coastguard Worker       const unsigned readBits = (w != 7 ? 1 : 0) + w * 2;
102*f6dc9357SAndroid Build Coastguard Worker       const UInt32 mask = ((UInt32)1 << w) - 1;
103*f6dc9357SAndroid Build Coastguard Worker       len = mask + kMatchMinLen - 1 +
104*f6dc9357SAndroid Build Coastguard Worker           ((val >> (kNumBits - readBits)) & mask);
105*f6dc9357SAndroid Build Coastguard Worker       _inBitStream.MovePos(readBits);
106*f6dc9357SAndroid Build Coastguard Worker     }
107*f6dc9357SAndroid Build Coastguard Worker     {
108*f6dc9357SAndroid Build Coastguard Worker       const unsigned kNumBits = 4 + 13;
109*f6dc9357SAndroid Build Coastguard Worker       const UInt32 val = _inBitStream.GetValue(kNumBits);
110*f6dc9357SAndroid Build Coastguard Worker       unsigned readBits = 1;
111*f6dc9357SAndroid Build Coastguard Worker       unsigned w;
112*f6dc9357SAndroid Build Coastguard Worker            if ((val & ((UInt32)1 << 16)) == 0) w = 9;
113*f6dc9357SAndroid Build Coastguard Worker       else if ((val & ((UInt32)1 << 15)) == 0) w = 10;
114*f6dc9357SAndroid Build Coastguard Worker       else if ((val & ((UInt32)1 << 14)) == 0) w = 11;
115*f6dc9357SAndroid Build Coastguard Worker       else if ((val & ((UInt32)1 << 13)) == 0) w = 12;
116*f6dc9357SAndroid Build Coastguard Worker       else { w = 13; readBits = 0; }
117*f6dc9357SAndroid Build Coastguard Worker 
118*f6dc9357SAndroid Build Coastguard Worker       readBits += w + w - 9;
119*f6dc9357SAndroid Build Coastguard Worker       const UInt32 dist = ((UInt32)1 << w) - (1 << 9) +
120*f6dc9357SAndroid Build Coastguard Worker           (((val >> (kNumBits - readBits)) & ((1 << w) - 1)));
121*f6dc9357SAndroid Build Coastguard Worker       _inBitStream.MovePos(readBits);
122*f6dc9357SAndroid Build Coastguard Worker       if (len > rem)
123*f6dc9357SAndroid Build Coastguard Worker       {
124*f6dc9357SAndroid Build Coastguard Worker         // if (FinishMode)
125*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
126*f6dc9357SAndroid Build Coastguard Worker         // else len = (UInt32)rem;
127*f6dc9357SAndroid Build Coastguard Worker       }
128*f6dc9357SAndroid Build Coastguard Worker       if (!_outWindow.CopyBlock(dist, len))
129*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
130*f6dc9357SAndroid Build Coastguard Worker       rem -= len;
131*f6dc9357SAndroid Build Coastguard Worker     }
132*f6dc9357SAndroid Build Coastguard Worker   }
133*f6dc9357SAndroid Build Coastguard Worker 
134*f6dc9357SAndroid Build Coastguard Worker   // if (FinishMode)
135*f6dc9357SAndroid Build Coastguard Worker   {
136*f6dc9357SAndroid Build Coastguard Worker     if (_inBitStream.ReadAlignBits() != 0)
137*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
138*f6dc9357SAndroid Build Coastguard Worker   }
139*f6dc9357SAndroid Build Coastguard Worker   if (_inBitStream.ExtraBitsWereRead())
140*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
141*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
142*f6dc9357SAndroid Build Coastguard Worker }
143*f6dc9357SAndroid Build Coastguard Worker 
144*f6dc9357SAndroid Build Coastguard Worker 
Code(ISequentialInStream * inStream,ISequentialOutStream * outStream,UInt32 outSize,ICompressProgressInfo * progress)145*f6dc9357SAndroid Build Coastguard Worker HRESULT CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
146*f6dc9357SAndroid Build Coastguard Worker     UInt32 outSize, ICompressProgressInfo *progress)
147*f6dc9357SAndroid Build Coastguard Worker {
148*f6dc9357SAndroid Build Coastguard Worker   try
149*f6dc9357SAndroid Build Coastguard Worker   {
150*f6dc9357SAndroid Build Coastguard Worker     if (!_outWindow.Create(kWindowSize))
151*f6dc9357SAndroid Build Coastguard Worker       return E_OUTOFMEMORY;
152*f6dc9357SAndroid Build Coastguard Worker     if (!_inBitStream.Create(1 << 17))
153*f6dc9357SAndroid Build Coastguard Worker       return E_OUTOFMEMORY;
154*f6dc9357SAndroid Build Coastguard Worker     _outWindow.SetStream(outStream);
155*f6dc9357SAndroid Build Coastguard Worker     _outWindow.Init(false);
156*f6dc9357SAndroid Build Coastguard Worker     _inBitStream.SetStream(inStream);
157*f6dc9357SAndroid Build Coastguard Worker     _inBitStream.Init();
158*f6dc9357SAndroid Build Coastguard Worker     {
159*f6dc9357SAndroid Build Coastguard Worker       CCoderReleaser coderReleaser(this);
160*f6dc9357SAndroid Build Coastguard Worker       RINOK(CodeReal(outSize, progress))
161*f6dc9357SAndroid Build Coastguard Worker       coderReleaser.Disable();
162*f6dc9357SAndroid Build Coastguard Worker     }
163*f6dc9357SAndroid Build Coastguard Worker     return _outWindow.Flush();
164*f6dc9357SAndroid Build Coastguard Worker   }
165*f6dc9357SAndroid Build Coastguard Worker   catch(const CInBufferException &e) { return e.ErrorCode; }
166*f6dc9357SAndroid Build Coastguard Worker   catch(const CLzOutWindowException &e) { return e.ErrorCode; }
167*f6dc9357SAndroid Build Coastguard Worker   catch(...) { return S_FALSE; }
168*f6dc9357SAndroid Build Coastguard Worker }
169*f6dc9357SAndroid Build Coastguard Worker 
170*f6dc9357SAndroid Build Coastguard Worker }}}
171*f6dc9357SAndroid Build Coastguard Worker 
172*f6dc9357SAndroid Build Coastguard Worker 
173*f6dc9357SAndroid Build Coastguard Worker 
174*f6dc9357SAndroid Build Coastguard Worker 
175*f6dc9357SAndroid Build Coastguard Worker using namespace NWindows;
176*f6dc9357SAndroid Build Coastguard Worker 
177*f6dc9357SAndroid Build Coastguard Worker #define Get16(p) GetUi16(p)
178*f6dc9357SAndroid Build Coastguard Worker #define Get32(p) GetUi32(p)
179*f6dc9357SAndroid Build Coastguard Worker 
180*f6dc9357SAndroid Build Coastguard Worker namespace NArchive {
181*f6dc9357SAndroid Build Coastguard Worker namespace NArj {
182*f6dc9357SAndroid Build Coastguard Worker 
183*f6dc9357SAndroid Build Coastguard Worker static const unsigned kBlockSizeMin = 30;
184*f6dc9357SAndroid Build Coastguard Worker static const unsigned kBlockSizeMax = 2600;
185*f6dc9357SAndroid Build Coastguard Worker 
186*f6dc9357SAndroid Build Coastguard Worker static const Byte kSig0 = 0x60;
187*f6dc9357SAndroid Build Coastguard Worker static const Byte kSig1 = 0xEA;
188*f6dc9357SAndroid Build Coastguard Worker 
189*f6dc9357SAndroid Build Coastguard Worker namespace NCompressionMethod
190*f6dc9357SAndroid Build Coastguard Worker {
191*f6dc9357SAndroid Build Coastguard Worker   enum
192*f6dc9357SAndroid Build Coastguard Worker   {
193*f6dc9357SAndroid Build Coastguard Worker     kStored = 0,
194*f6dc9357SAndroid Build Coastguard Worker     kCompressed1a = 1,
195*f6dc9357SAndroid Build Coastguard Worker     kCompressed1b = 2,
196*f6dc9357SAndroid Build Coastguard Worker     kCompressed1c = 3,
197*f6dc9357SAndroid Build Coastguard Worker     kCompressed2 = 4,
198*f6dc9357SAndroid Build Coastguard Worker     kNoDataNoCRC = 8,
199*f6dc9357SAndroid Build Coastguard Worker     kNoData = 9
200*f6dc9357SAndroid Build Coastguard Worker   };
201*f6dc9357SAndroid Build Coastguard Worker }
202*f6dc9357SAndroid Build Coastguard Worker 
203*f6dc9357SAndroid Build Coastguard Worker namespace NFileType
204*f6dc9357SAndroid Build Coastguard Worker {
205*f6dc9357SAndroid Build Coastguard Worker   enum
206*f6dc9357SAndroid Build Coastguard Worker   {
207*f6dc9357SAndroid Build Coastguard Worker     kBinary = 0,
208*f6dc9357SAndroid Build Coastguard Worker     k7BitText,
209*f6dc9357SAndroid Build Coastguard Worker     kArchiveHeader,
210*f6dc9357SAndroid Build Coastguard Worker     kDirectory,
211*f6dc9357SAndroid Build Coastguard Worker     kVolumeLablel,
212*f6dc9357SAndroid Build Coastguard Worker     kChapterLabel
213*f6dc9357SAndroid Build Coastguard Worker   };
214*f6dc9357SAndroid Build Coastguard Worker }
215*f6dc9357SAndroid Build Coastguard Worker 
216*f6dc9357SAndroid Build Coastguard Worker namespace NFlags
217*f6dc9357SAndroid Build Coastguard Worker {
218*f6dc9357SAndroid Build Coastguard Worker   const Byte kGarbled  = 1 << 0;
219*f6dc9357SAndroid Build Coastguard Worker   // const Byte kAnsiPage = 1 << 1; // or (OLD_SECURED_FLAG) obsolete
220*f6dc9357SAndroid Build Coastguard Worker   const Byte kVolume   = 1 << 2;
221*f6dc9357SAndroid Build Coastguard Worker   const Byte kExtFile  = 1 << 3;
222*f6dc9357SAndroid Build Coastguard Worker   // const Byte kPathSym  = 1 << 4;
223*f6dc9357SAndroid Build Coastguard Worker   // const Byte kBackup   = 1 << 5; // obsolete
224*f6dc9357SAndroid Build Coastguard Worker   // const Byte kSecured  = 1 << 6;
225*f6dc9357SAndroid Build Coastguard Worker   // const Byte kDualName = 1 << 7;
226*f6dc9357SAndroid Build Coastguard Worker }
227*f6dc9357SAndroid Build Coastguard Worker 
228*f6dc9357SAndroid Build Coastguard Worker namespace NHostOS
229*f6dc9357SAndroid Build Coastguard Worker {
230*f6dc9357SAndroid Build Coastguard Worker   enum EEnum
231*f6dc9357SAndroid Build Coastguard Worker   {
232*f6dc9357SAndroid Build Coastguard Worker     kMSDOS = 0,  // MS-DOS, OS/2, Win32, pkarj 2.50 (FAT / VFAT / FAT32)
233*f6dc9357SAndroid Build Coastguard Worker     kPRIMOS,
234*f6dc9357SAndroid Build Coastguard Worker     kUnix,
235*f6dc9357SAndroid Build Coastguard Worker     kAMIGA,
236*f6dc9357SAndroid Build Coastguard Worker     kMac,
237*f6dc9357SAndroid Build Coastguard Worker     kOS_2,
238*f6dc9357SAndroid Build Coastguard Worker     kAPPLE_GS,
239*f6dc9357SAndroid Build Coastguard Worker     kAtari_ST,
240*f6dc9357SAndroid Build Coastguard Worker     kNext,
241*f6dc9357SAndroid Build Coastguard Worker     kVAX_VMS,
242*f6dc9357SAndroid Build Coastguard Worker     kWIN95
243*f6dc9357SAndroid Build Coastguard Worker   };
244*f6dc9357SAndroid Build Coastguard Worker }
245*f6dc9357SAndroid Build Coastguard Worker 
246*f6dc9357SAndroid Build Coastguard Worker static const char * const kHostOS[] =
247*f6dc9357SAndroid Build Coastguard Worker {
248*f6dc9357SAndroid Build Coastguard Worker     "MSDOS"
249*f6dc9357SAndroid Build Coastguard Worker   , "PRIMOS"
250*f6dc9357SAndroid Build Coastguard Worker   , "UNIX"
251*f6dc9357SAndroid Build Coastguard Worker   , "AMIGA"
252*f6dc9357SAndroid Build Coastguard Worker   , "MAC"
253*f6dc9357SAndroid Build Coastguard Worker   , "OS/2"
254*f6dc9357SAndroid Build Coastguard Worker   , "APPLE GS"
255*f6dc9357SAndroid Build Coastguard Worker   , "ATARI ST"
256*f6dc9357SAndroid Build Coastguard Worker   , "NEXT"
257*f6dc9357SAndroid Build Coastguard Worker   , "VAX VMS"
258*f6dc9357SAndroid Build Coastguard Worker   , "WIN95"
259*f6dc9357SAndroid Build Coastguard Worker };
260*f6dc9357SAndroid Build Coastguard Worker 
261*f6dc9357SAndroid Build Coastguard Worker struct CArcHeader
262*f6dc9357SAndroid Build Coastguard Worker {
263*f6dc9357SAndroid Build Coastguard Worker   // Byte ArchiverVersion;
264*f6dc9357SAndroid Build Coastguard Worker   // Byte ExtractVersion;
265*f6dc9357SAndroid Build Coastguard Worker   Byte HostOS;
266*f6dc9357SAndroid Build Coastguard Worker   // Byte Flags;
267*f6dc9357SAndroid Build Coastguard Worker   // Byte SecuryVersion;
268*f6dc9357SAndroid Build Coastguard Worker   // Byte FileType;
269*f6dc9357SAndroid Build Coastguard Worker   // Byte Reserved;
270*f6dc9357SAndroid Build Coastguard Worker   UInt32 CTime;
271*f6dc9357SAndroid Build Coastguard Worker   UInt32 MTime;
272*f6dc9357SAndroid Build Coastguard Worker   UInt32 ArchiveSize;
273*f6dc9357SAndroid Build Coastguard Worker   // UInt32 SecurPos;
274*f6dc9357SAndroid Build Coastguard Worker   // UInt16 FilespecPosInFilename;
275*f6dc9357SAndroid Build Coastguard Worker   UInt16 SecurSize;
276*f6dc9357SAndroid Build Coastguard Worker   // Byte EncryptionVersion;
277*f6dc9357SAndroid Build Coastguard Worker   // Byte LastChapter;
278*f6dc9357SAndroid Build Coastguard Worker   AString Name;
279*f6dc9357SAndroid Build Coastguard Worker   AString Comment;
280*f6dc9357SAndroid Build Coastguard Worker 
281*f6dc9357SAndroid Build Coastguard Worker   HRESULT Parse(const Byte *p, unsigned size);
282*f6dc9357SAndroid Build Coastguard Worker };
283*f6dc9357SAndroid Build Coastguard Worker 
IsArc_Arj(const Byte * p,size_t size)284*f6dc9357SAndroid Build Coastguard Worker API_FUNC_static_IsArc IsArc_Arj(const Byte *p, size_t size)
285*f6dc9357SAndroid Build Coastguard Worker {
286*f6dc9357SAndroid Build Coastguard Worker   if (size < kBlockSizeMin + 4)
287*f6dc9357SAndroid Build Coastguard Worker     return k_IsArc_Res_NEED_MORE;
288*f6dc9357SAndroid Build Coastguard Worker   if (p[0] != kSig0 || p[1] != kSig1)
289*f6dc9357SAndroid Build Coastguard Worker     return k_IsArc_Res_NO;
290*f6dc9357SAndroid Build Coastguard Worker   UInt32 blockSize = Get16(p + 2);
291*f6dc9357SAndroid Build Coastguard Worker   if (blockSize < kBlockSizeMin ||
292*f6dc9357SAndroid Build Coastguard Worker       blockSize > kBlockSizeMax)
293*f6dc9357SAndroid Build Coastguard Worker     return k_IsArc_Res_NO;
294*f6dc9357SAndroid Build Coastguard Worker 
295*f6dc9357SAndroid Build Coastguard Worker   p += 4;
296*f6dc9357SAndroid Build Coastguard Worker   size -= 4;
297*f6dc9357SAndroid Build Coastguard Worker 
298*f6dc9357SAndroid Build Coastguard Worker   Byte headerSize = p[0];
299*f6dc9357SAndroid Build Coastguard Worker   if (headerSize < kBlockSizeMin ||
300*f6dc9357SAndroid Build Coastguard Worker       headerSize > blockSize ||
301*f6dc9357SAndroid Build Coastguard Worker       p[6] != NFileType::kArchiveHeader ||
302*f6dc9357SAndroid Build Coastguard Worker       p[28] > 8) // EncryptionVersion
303*f6dc9357SAndroid Build Coastguard Worker     return k_IsArc_Res_NO;
304*f6dc9357SAndroid Build Coastguard Worker 
305*f6dc9357SAndroid Build Coastguard Worker   if (blockSize + 4 <= size)
306*f6dc9357SAndroid Build Coastguard Worker     if (Get32(p + blockSize) != CrcCalc(p, blockSize))
307*f6dc9357SAndroid Build Coastguard Worker       return k_IsArc_Res_NO;
308*f6dc9357SAndroid Build Coastguard Worker 
309*f6dc9357SAndroid Build Coastguard Worker   return k_IsArc_Res_YES;
310*f6dc9357SAndroid Build Coastguard Worker }
311*f6dc9357SAndroid Build Coastguard Worker }
312*f6dc9357SAndroid Build Coastguard Worker 
ReadString(const Byte * p,unsigned & size,AString & res)313*f6dc9357SAndroid Build Coastguard Worker static HRESULT ReadString(const Byte *p, unsigned &size, AString &res)
314*f6dc9357SAndroid Build Coastguard Worker {
315*f6dc9357SAndroid Build Coastguard Worker   unsigned num = size;
316*f6dc9357SAndroid Build Coastguard Worker   for (unsigned i = 0; i < num;)
317*f6dc9357SAndroid Build Coastguard Worker   {
318*f6dc9357SAndroid Build Coastguard Worker     if (p[i++] == 0)
319*f6dc9357SAndroid Build Coastguard Worker     {
320*f6dc9357SAndroid Build Coastguard Worker       size = i;
321*f6dc9357SAndroid Build Coastguard Worker       res = (const char *)p;
322*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
323*f6dc9357SAndroid Build Coastguard Worker     }
324*f6dc9357SAndroid Build Coastguard Worker   }
325*f6dc9357SAndroid Build Coastguard Worker   return S_FALSE;
326*f6dc9357SAndroid Build Coastguard Worker }
327*f6dc9357SAndroid Build Coastguard Worker 
Parse(const Byte * p,unsigned size)328*f6dc9357SAndroid Build Coastguard Worker HRESULT CArcHeader::Parse(const Byte *p, unsigned size)
329*f6dc9357SAndroid Build Coastguard Worker {
330*f6dc9357SAndroid Build Coastguard Worker   Byte headerSize = p[0];
331*f6dc9357SAndroid Build Coastguard Worker   if (headerSize < kBlockSizeMin || headerSize > size)
332*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
333*f6dc9357SAndroid Build Coastguard Worker   // ArchiverVersion = p[1];
334*f6dc9357SAndroid Build Coastguard Worker   // ExtractVersion = p[2];
335*f6dc9357SAndroid Build Coastguard Worker   HostOS = p[3];
336*f6dc9357SAndroid Build Coastguard Worker   // Flags = p[4];
337*f6dc9357SAndroid Build Coastguard Worker   // SecuryVersion = p[5];
338*f6dc9357SAndroid Build Coastguard Worker   if (p[6] != NFileType::kArchiveHeader)
339*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
340*f6dc9357SAndroid Build Coastguard Worker   // Reserved = p[7];
341*f6dc9357SAndroid Build Coastguard Worker   CTime = Get32(p + 8);
342*f6dc9357SAndroid Build Coastguard Worker   MTime = Get32(p + 12);
343*f6dc9357SAndroid Build Coastguard Worker   ArchiveSize = Get32(p + 16); // it can be zero. (currently used only for secured archives)
344*f6dc9357SAndroid Build Coastguard Worker   // SecurPos = Get32(p + 20);
345*f6dc9357SAndroid Build Coastguard Worker   // UInt16 filespecPositionInFilename = Get16(p + 24);
346*f6dc9357SAndroid Build Coastguard Worker   SecurSize = Get16(p + 26);
347*f6dc9357SAndroid Build Coastguard Worker   // EncryptionVersion = p[28];
348*f6dc9357SAndroid Build Coastguard Worker   // LastChapter = p[29];
349*f6dc9357SAndroid Build Coastguard Worker   unsigned pos = headerSize;
350*f6dc9357SAndroid Build Coastguard Worker   unsigned size1 = size - pos;
351*f6dc9357SAndroid Build Coastguard Worker   RINOK(ReadString(p + pos, size1, Name))
352*f6dc9357SAndroid Build Coastguard Worker   pos += size1;
353*f6dc9357SAndroid Build Coastguard Worker   size1 = size - pos;
354*f6dc9357SAndroid Build Coastguard Worker   RINOK(ReadString(p + pos, size1, Comment))
355*f6dc9357SAndroid Build Coastguard Worker   pos += size1;
356*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
357*f6dc9357SAndroid Build Coastguard Worker }
358*f6dc9357SAndroid Build Coastguard Worker 
359*f6dc9357SAndroid Build Coastguard Worker 
360*f6dc9357SAndroid Build Coastguard Worker struct CExtendedInfo
361*f6dc9357SAndroid Build Coastguard Worker {
362*f6dc9357SAndroid Build Coastguard Worker   UInt64 Size;
363*f6dc9357SAndroid Build Coastguard Worker   bool CrcError;
364*f6dc9357SAndroid Build Coastguard Worker 
ClearNArchive::CExtendedInfo365*f6dc9357SAndroid Build Coastguard Worker   void Clear()
366*f6dc9357SAndroid Build Coastguard Worker   {
367*f6dc9357SAndroid Build Coastguard Worker     Size = 0;
368*f6dc9357SAndroid Build Coastguard Worker     CrcError = false;
369*f6dc9357SAndroid Build Coastguard Worker   }
ParseToPropVarNArchive::CExtendedInfo370*f6dc9357SAndroid Build Coastguard Worker   void ParseToPropVar(NCOM::CPropVariant &prop) const
371*f6dc9357SAndroid Build Coastguard Worker   {
372*f6dc9357SAndroid Build Coastguard Worker     if (Size != 0)
373*f6dc9357SAndroid Build Coastguard Worker     {
374*f6dc9357SAndroid Build Coastguard Worker        AString s;
375*f6dc9357SAndroid Build Coastguard Worker        s += "Extended:";
376*f6dc9357SAndroid Build Coastguard Worker        s.Add_UInt32((UInt32)Size);
377*f6dc9357SAndroid Build Coastguard Worker        if (CrcError)
378*f6dc9357SAndroid Build Coastguard Worker          s += ":CRC_ERROR";
379*f6dc9357SAndroid Build Coastguard Worker        prop = s;
380*f6dc9357SAndroid Build Coastguard Worker     }
381*f6dc9357SAndroid Build Coastguard Worker   }
382*f6dc9357SAndroid Build Coastguard Worker };
383*f6dc9357SAndroid Build Coastguard Worker 
384*f6dc9357SAndroid Build Coastguard Worker 
385*f6dc9357SAndroid Build Coastguard Worker struct CItem
386*f6dc9357SAndroid Build Coastguard Worker {
387*f6dc9357SAndroid Build Coastguard Worker   AString Name;
388*f6dc9357SAndroid Build Coastguard Worker   AString Comment;
389*f6dc9357SAndroid Build Coastguard Worker 
390*f6dc9357SAndroid Build Coastguard Worker   UInt32 MTime;
391*f6dc9357SAndroid Build Coastguard Worker   UInt32 PackSize;
392*f6dc9357SAndroid Build Coastguard Worker   UInt32 Size;
393*f6dc9357SAndroid Build Coastguard Worker   UInt32 FileCRC;
394*f6dc9357SAndroid Build Coastguard Worker   UInt32 SplitPos;
395*f6dc9357SAndroid Build Coastguard Worker 
396*f6dc9357SAndroid Build Coastguard Worker   Byte Version;
397*f6dc9357SAndroid Build Coastguard Worker   Byte ExtractVersion;
398*f6dc9357SAndroid Build Coastguard Worker   Byte HostOS;
399*f6dc9357SAndroid Build Coastguard Worker   Byte Flags;
400*f6dc9357SAndroid Build Coastguard Worker   Byte Method;
401*f6dc9357SAndroid Build Coastguard Worker   Byte FileType;
402*f6dc9357SAndroid Build Coastguard Worker 
403*f6dc9357SAndroid Build Coastguard Worker   // UInt16 FilespecPosInFilename;
404*f6dc9357SAndroid Build Coastguard Worker   UInt16 FileAccessMode;
405*f6dc9357SAndroid Build Coastguard Worker   // Byte FirstChapter;
406*f6dc9357SAndroid Build Coastguard Worker   // Byte LastChapter;
407*f6dc9357SAndroid Build Coastguard Worker 
408*f6dc9357SAndroid Build Coastguard Worker   UInt64 DataPosition;
409*f6dc9357SAndroid Build Coastguard Worker 
410*f6dc9357SAndroid Build Coastguard Worker   CExtendedInfo ExtendedInfo;
411*f6dc9357SAndroid Build Coastguard Worker 
IsEncryptedNArchive::CItem412*f6dc9357SAndroid Build Coastguard Worker   bool IsEncrypted() const { return (Flags & NFlags::kGarbled) != 0; }
IsDirNArchive::CItem413*f6dc9357SAndroid Build Coastguard Worker   bool IsDir() const { return (FileType == NFileType::kDirectory); }
IsSplitAfterNArchive::CItem414*f6dc9357SAndroid Build Coastguard Worker   bool IsSplitAfter() const { return (Flags & NFlags::kVolume) != 0; }
IsSplitBeforeNArchive::CItem415*f6dc9357SAndroid Build Coastguard Worker   bool IsSplitBefore() const { return (Flags & NFlags::kExtFile) != 0; }
GetWinAttribNArchive::CItem416*f6dc9357SAndroid Build Coastguard Worker   UInt32 GetWinAttrib() const
417*f6dc9357SAndroid Build Coastguard Worker   {
418*f6dc9357SAndroid Build Coastguard Worker     UInt32 atrrib = 0;
419*f6dc9357SAndroid Build Coastguard Worker     switch (HostOS)
420*f6dc9357SAndroid Build Coastguard Worker     {
421*f6dc9357SAndroid Build Coastguard Worker       case NHostOS::kMSDOS:
422*f6dc9357SAndroid Build Coastguard Worker       case NHostOS::kWIN95:
423*f6dc9357SAndroid Build Coastguard Worker         atrrib = FileAccessMode;
424*f6dc9357SAndroid Build Coastguard Worker         break;
425*f6dc9357SAndroid Build Coastguard Worker     }
426*f6dc9357SAndroid Build Coastguard Worker     if (IsDir())
427*f6dc9357SAndroid Build Coastguard Worker       atrrib |= FILE_ATTRIBUTE_DIRECTORY;
428*f6dc9357SAndroid Build Coastguard Worker     return atrrib;
429*f6dc9357SAndroid Build Coastguard Worker   }
430*f6dc9357SAndroid Build Coastguard Worker 
431*f6dc9357SAndroid Build Coastguard Worker   HRESULT Parse(const Byte *p, unsigned size);
432*f6dc9357SAndroid Build Coastguard Worker };
433*f6dc9357SAndroid Build Coastguard Worker 
Parse(const Byte * p,unsigned size)434*f6dc9357SAndroid Build Coastguard Worker HRESULT CItem::Parse(const Byte *p, unsigned size)
435*f6dc9357SAndroid Build Coastguard Worker {
436*f6dc9357SAndroid Build Coastguard Worker   Byte headerSize = p[0];
437*f6dc9357SAndroid Build Coastguard Worker   if (headerSize < kBlockSizeMin || headerSize > size)
438*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
439*f6dc9357SAndroid Build Coastguard Worker   Version = p[1];
440*f6dc9357SAndroid Build Coastguard Worker   ExtractVersion = p[2];
441*f6dc9357SAndroid Build Coastguard Worker   HostOS = p[3];
442*f6dc9357SAndroid Build Coastguard Worker   Flags = p[4];
443*f6dc9357SAndroid Build Coastguard Worker   Method = p[5];
444*f6dc9357SAndroid Build Coastguard Worker   FileType = p[6];
445*f6dc9357SAndroid Build Coastguard Worker   // Reserved = p[7];
446*f6dc9357SAndroid Build Coastguard Worker   MTime = Get32(p + 8);
447*f6dc9357SAndroid Build Coastguard Worker   PackSize = Get32(p + 12);
448*f6dc9357SAndroid Build Coastguard Worker   Size = Get32(p + 16);
449*f6dc9357SAndroid Build Coastguard Worker   FileCRC = Get32(p + 20);
450*f6dc9357SAndroid Build Coastguard Worker   // FilespecPosInFilename = Get16(p + 24);
451*f6dc9357SAndroid Build Coastguard Worker   FileAccessMode = Get16(p + 26);
452*f6dc9357SAndroid Build Coastguard Worker   // FirstChapter = p[28];
453*f6dc9357SAndroid Build Coastguard Worker   // FirstChapter = p[29];
454*f6dc9357SAndroid Build Coastguard Worker 
455*f6dc9357SAndroid Build Coastguard Worker   SplitPos = 0;
456*f6dc9357SAndroid Build Coastguard Worker   if (IsSplitBefore() && headerSize >= 34)
457*f6dc9357SAndroid Build Coastguard Worker     SplitPos = Get32(p + 30);
458*f6dc9357SAndroid Build Coastguard Worker 
459*f6dc9357SAndroid Build Coastguard Worker   unsigned pos = headerSize;
460*f6dc9357SAndroid Build Coastguard Worker   unsigned size1 = size - pos;
461*f6dc9357SAndroid Build Coastguard Worker   RINOK(ReadString(p + pos, size1, Name))
462*f6dc9357SAndroid Build Coastguard Worker   pos += size1;
463*f6dc9357SAndroid Build Coastguard Worker   size1 = size - pos;
464*f6dc9357SAndroid Build Coastguard Worker   RINOK(ReadString(p + pos, size1, Comment))
465*f6dc9357SAndroid Build Coastguard Worker   pos += size1;
466*f6dc9357SAndroid Build Coastguard Worker 
467*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
468*f6dc9357SAndroid Build Coastguard Worker }
469*f6dc9357SAndroid Build Coastguard Worker 
470*f6dc9357SAndroid Build Coastguard Worker enum EErrorType
471*f6dc9357SAndroid Build Coastguard Worker {
472*f6dc9357SAndroid Build Coastguard Worker   k_ErrorType_OK,
473*f6dc9357SAndroid Build Coastguard Worker   k_ErrorType_Corrupted,
474*f6dc9357SAndroid Build Coastguard Worker   k_ErrorType_UnexpectedEnd
475*f6dc9357SAndroid Build Coastguard Worker };
476*f6dc9357SAndroid Build Coastguard Worker 
477*f6dc9357SAndroid Build Coastguard Worker class CArc
478*f6dc9357SAndroid Build Coastguard Worker {
479*f6dc9357SAndroid Build Coastguard Worker public:
480*f6dc9357SAndroid Build Coastguard Worker   UInt64 Processed;
481*f6dc9357SAndroid Build Coastguard Worker   EErrorType Error;
482*f6dc9357SAndroid Build Coastguard Worker   bool IsArc;
483*f6dc9357SAndroid Build Coastguard Worker   IInStream *Stream;
484*f6dc9357SAndroid Build Coastguard Worker   IArchiveOpenCallback *Callback;
485*f6dc9357SAndroid Build Coastguard Worker   UInt64 NumFiles;
486*f6dc9357SAndroid Build Coastguard Worker   CArcHeader Header;
487*f6dc9357SAndroid Build Coastguard Worker 
488*f6dc9357SAndroid Build Coastguard Worker   CExtendedInfo ExtendedInfo;
489*f6dc9357SAndroid Build Coastguard Worker 
490*f6dc9357SAndroid Build Coastguard Worker   HRESULT Open();
491*f6dc9357SAndroid Build Coastguard Worker   HRESULT GetNextItem(CItem &item, bool &filled);
Close()492*f6dc9357SAndroid Build Coastguard Worker   void Close()
493*f6dc9357SAndroid Build Coastguard Worker   {
494*f6dc9357SAndroid Build Coastguard Worker     IsArc = false;
495*f6dc9357SAndroid Build Coastguard Worker     Error = k_ErrorType_OK;
496*f6dc9357SAndroid Build Coastguard Worker     ExtendedInfo.Clear();
497*f6dc9357SAndroid Build Coastguard Worker   }
498*f6dc9357SAndroid Build Coastguard Worker private:
499*f6dc9357SAndroid Build Coastguard Worker   unsigned _blockSize;
500*f6dc9357SAndroid Build Coastguard Worker   CByteBuffer _block;
501*f6dc9357SAndroid Build Coastguard Worker 
502*f6dc9357SAndroid Build Coastguard Worker   HRESULT ReadBlock(bool &filled, CExtendedInfo *extendedInfo);
503*f6dc9357SAndroid Build Coastguard Worker   HRESULT SkipExtendedHeaders(CExtendedInfo &extendedInfo);
504*f6dc9357SAndroid Build Coastguard Worker   HRESULT Read(void *data, size_t *size);
505*f6dc9357SAndroid Build Coastguard Worker };
506*f6dc9357SAndroid Build Coastguard Worker 
Read(void * data,size_t * size)507*f6dc9357SAndroid Build Coastguard Worker HRESULT CArc::Read(void *data, size_t *size)
508*f6dc9357SAndroid Build Coastguard Worker {
509*f6dc9357SAndroid Build Coastguard Worker   HRESULT res = ReadStream(Stream, data, size);
510*f6dc9357SAndroid Build Coastguard Worker   Processed += *size;
511*f6dc9357SAndroid Build Coastguard Worker   return res;
512*f6dc9357SAndroid Build Coastguard Worker }
513*f6dc9357SAndroid Build Coastguard Worker 
514*f6dc9357SAndroid Build Coastguard Worker #define READ_STREAM(_dest_, _size_) \
515*f6dc9357SAndroid Build Coastguard Worker   { size_t _processed_ = (_size_); RINOK(Read(_dest_, &_processed_)); \
516*f6dc9357SAndroid Build Coastguard Worker   if (_processed_ != (_size_)) { Error = k_ErrorType_UnexpectedEnd; return S_OK; } }
517*f6dc9357SAndroid Build Coastguard Worker 
ReadBlock(bool & filled,CExtendedInfo * extendedInfo)518*f6dc9357SAndroid Build Coastguard Worker HRESULT CArc::ReadBlock(bool &filled, CExtendedInfo *extendedInfo)
519*f6dc9357SAndroid Build Coastguard Worker {
520*f6dc9357SAndroid Build Coastguard Worker   Error = k_ErrorType_OK;
521*f6dc9357SAndroid Build Coastguard Worker   filled = false;
522*f6dc9357SAndroid Build Coastguard Worker   Byte buf[4];
523*f6dc9357SAndroid Build Coastguard Worker   const unsigned signSize = extendedInfo ? 0 : 2;
524*f6dc9357SAndroid Build Coastguard Worker   READ_STREAM(buf, signSize + 2)
525*f6dc9357SAndroid Build Coastguard Worker   if (!extendedInfo)
526*f6dc9357SAndroid Build Coastguard Worker     if (buf[0] != kSig0 || buf[1] != kSig1)
527*f6dc9357SAndroid Build Coastguard Worker     {
528*f6dc9357SAndroid Build Coastguard Worker       Error = k_ErrorType_Corrupted;
529*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
530*f6dc9357SAndroid Build Coastguard Worker     }
531*f6dc9357SAndroid Build Coastguard Worker   _blockSize = Get16(buf + signSize);
532*f6dc9357SAndroid Build Coastguard Worker   if (_blockSize == 0) // end of archive
533*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
534*f6dc9357SAndroid Build Coastguard Worker 
535*f6dc9357SAndroid Build Coastguard Worker   if (!extendedInfo)
536*f6dc9357SAndroid Build Coastguard Worker     if (_blockSize < kBlockSizeMin || _blockSize > kBlockSizeMax)
537*f6dc9357SAndroid Build Coastguard Worker     {
538*f6dc9357SAndroid Build Coastguard Worker       Error = k_ErrorType_Corrupted;
539*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
540*f6dc9357SAndroid Build Coastguard Worker     }
541*f6dc9357SAndroid Build Coastguard Worker 
542*f6dc9357SAndroid Build Coastguard Worker   const size_t readSize = _blockSize + 4;
543*f6dc9357SAndroid Build Coastguard Worker   if (readSize > _block.Size())
544*f6dc9357SAndroid Build Coastguard Worker   {
545*f6dc9357SAndroid Build Coastguard Worker     // extended data size is limited by (64 KB)
546*f6dc9357SAndroid Build Coastguard Worker     // _blockSize is less than 64 KB
547*f6dc9357SAndroid Build Coastguard Worker     const size_t upSize = (_blockSize > kBlockSizeMax ? (1 << 16) : kBlockSizeMax);
548*f6dc9357SAndroid Build Coastguard Worker     _block.Alloc(upSize + 4);
549*f6dc9357SAndroid Build Coastguard Worker   }
550*f6dc9357SAndroid Build Coastguard Worker 
551*f6dc9357SAndroid Build Coastguard Worker   if (extendedInfo)
552*f6dc9357SAndroid Build Coastguard Worker     extendedInfo->Size += _blockSize;
553*f6dc9357SAndroid Build Coastguard Worker 
554*f6dc9357SAndroid Build Coastguard Worker   READ_STREAM(_block, readSize)
555*f6dc9357SAndroid Build Coastguard Worker   if (Get32(_block + _blockSize) != CrcCalc(_block, _blockSize))
556*f6dc9357SAndroid Build Coastguard Worker   {
557*f6dc9357SAndroid Build Coastguard Worker     if (extendedInfo)
558*f6dc9357SAndroid Build Coastguard Worker       extendedInfo->CrcError = true;
559*f6dc9357SAndroid Build Coastguard Worker     else
560*f6dc9357SAndroid Build Coastguard Worker     {
561*f6dc9357SAndroid Build Coastguard Worker       Error = k_ErrorType_Corrupted;
562*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
563*f6dc9357SAndroid Build Coastguard Worker     }
564*f6dc9357SAndroid Build Coastguard Worker   }
565*f6dc9357SAndroid Build Coastguard Worker   filled = true;
566*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
567*f6dc9357SAndroid Build Coastguard Worker }
568*f6dc9357SAndroid Build Coastguard Worker 
SkipExtendedHeaders(CExtendedInfo & extendedInfo)569*f6dc9357SAndroid Build Coastguard Worker HRESULT CArc::SkipExtendedHeaders(CExtendedInfo &extendedInfo)
570*f6dc9357SAndroid Build Coastguard Worker {
571*f6dc9357SAndroid Build Coastguard Worker   extendedInfo.Clear();
572*f6dc9357SAndroid Build Coastguard Worker   for (UInt32 i = 0;; i++)
573*f6dc9357SAndroid Build Coastguard Worker   {
574*f6dc9357SAndroid Build Coastguard Worker     bool filled;
575*f6dc9357SAndroid Build Coastguard Worker     RINOK(ReadBlock(filled, &extendedInfo))
576*f6dc9357SAndroid Build Coastguard Worker     if (!filled)
577*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
578*f6dc9357SAndroid Build Coastguard Worker     if (Callback && (i & 0xFF) == 0)
579*f6dc9357SAndroid Build Coastguard Worker       RINOK(Callback->SetCompleted(&NumFiles, &Processed))
580*f6dc9357SAndroid Build Coastguard Worker   }
581*f6dc9357SAndroid Build Coastguard Worker }
582*f6dc9357SAndroid Build Coastguard Worker 
Open()583*f6dc9357SAndroid Build Coastguard Worker HRESULT CArc::Open()
584*f6dc9357SAndroid Build Coastguard Worker {
585*f6dc9357SAndroid Build Coastguard Worker   bool filled;
586*f6dc9357SAndroid Build Coastguard Worker   RINOK(ReadBlock(filled, NULL)) // (extendedInfo = NULL)
587*f6dc9357SAndroid Build Coastguard Worker   if (!filled)
588*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
589*f6dc9357SAndroid Build Coastguard Worker   RINOK(Header.Parse(_block, _blockSize))
590*f6dc9357SAndroid Build Coastguard Worker   IsArc = true;
591*f6dc9357SAndroid Build Coastguard Worker   return SkipExtendedHeaders(ExtendedInfo);
592*f6dc9357SAndroid Build Coastguard Worker }
593*f6dc9357SAndroid Build Coastguard Worker 
GetNextItem(CItem & item,bool & filled)594*f6dc9357SAndroid Build Coastguard Worker HRESULT CArc::GetNextItem(CItem &item, bool &filled)
595*f6dc9357SAndroid Build Coastguard Worker {
596*f6dc9357SAndroid Build Coastguard Worker   RINOK(ReadBlock(filled, NULL)) // (extendedInfo = NULL)
597*f6dc9357SAndroid Build Coastguard Worker   if (!filled)
598*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
599*f6dc9357SAndroid Build Coastguard Worker   filled = false;
600*f6dc9357SAndroid Build Coastguard Worker   if (item.Parse(_block, _blockSize) != S_OK)
601*f6dc9357SAndroid Build Coastguard Worker   {
602*f6dc9357SAndroid Build Coastguard Worker     Error = k_ErrorType_Corrupted;
603*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
604*f6dc9357SAndroid Build Coastguard Worker   }
605*f6dc9357SAndroid Build Coastguard Worker   /*
606*f6dc9357SAndroid Build Coastguard Worker   UInt32 extraData;
607*f6dc9357SAndroid Build Coastguard Worker   if ((header.Flags & NFlags::kExtFile) != 0)
608*f6dc9357SAndroid Build Coastguard Worker     extraData = GetUi32(_block + pos);
609*f6dc9357SAndroid Build Coastguard Worker   */
610*f6dc9357SAndroid Build Coastguard Worker 
611*f6dc9357SAndroid Build Coastguard Worker   RINOK(SkipExtendedHeaders(item.ExtendedInfo))
612*f6dc9357SAndroid Build Coastguard Worker   filled = true;
613*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
614*f6dc9357SAndroid Build Coastguard Worker }
615*f6dc9357SAndroid Build Coastguard Worker 
616*f6dc9357SAndroid Build Coastguard Worker 
617*f6dc9357SAndroid Build Coastguard Worker Z7_CLASS_IMP_CHandler_IInArchive_0
618*f6dc9357SAndroid Build Coastguard Worker 
619*f6dc9357SAndroid Build Coastguard Worker   CObjectVector<CItem> _items;
620*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<IInStream> _stream;
621*f6dc9357SAndroid Build Coastguard Worker   UInt64 _phySize;
622*f6dc9357SAndroid Build Coastguard Worker   CArc _arc;
623*f6dc9357SAndroid Build Coastguard Worker 
624*f6dc9357SAndroid Build Coastguard Worker   HRESULT Open2(IInStream *inStream, IArchiveOpenCallback *callback);
625*f6dc9357SAndroid Build Coastguard Worker };
626*f6dc9357SAndroid Build Coastguard Worker 
627*f6dc9357SAndroid Build Coastguard Worker static const Byte kArcProps[] =
628*f6dc9357SAndroid Build Coastguard Worker {
629*f6dc9357SAndroid Build Coastguard Worker   kpidName,
630*f6dc9357SAndroid Build Coastguard Worker   kpidCTime,
631*f6dc9357SAndroid Build Coastguard Worker   kpidMTime,
632*f6dc9357SAndroid Build Coastguard Worker   kpidHostOS,
633*f6dc9357SAndroid Build Coastguard Worker   kpidComment,
634*f6dc9357SAndroid Build Coastguard Worker   kpidCharacts
635*f6dc9357SAndroid Build Coastguard Worker };
636*f6dc9357SAndroid Build Coastguard Worker 
637*f6dc9357SAndroid Build Coastguard Worker static const Byte kProps[] =
638*f6dc9357SAndroid Build Coastguard Worker {
639*f6dc9357SAndroid Build Coastguard Worker   kpidPath,
640*f6dc9357SAndroid Build Coastguard Worker   kpidIsDir,
641*f6dc9357SAndroid Build Coastguard Worker   kpidSize,
642*f6dc9357SAndroid Build Coastguard Worker   kpidPosition,
643*f6dc9357SAndroid Build Coastguard Worker   kpidPackSize,
644*f6dc9357SAndroid Build Coastguard Worker   kpidMTime,
645*f6dc9357SAndroid Build Coastguard Worker   kpidAttrib,
646*f6dc9357SAndroid Build Coastguard Worker   kpidEncrypted,
647*f6dc9357SAndroid Build Coastguard Worker   kpidCRC,
648*f6dc9357SAndroid Build Coastguard Worker   kpidMethod,
649*f6dc9357SAndroid Build Coastguard Worker   kpidHostOS,
650*f6dc9357SAndroid Build Coastguard Worker   kpidComment,
651*f6dc9357SAndroid Build Coastguard Worker   kpidCharacts
652*f6dc9357SAndroid Build Coastguard Worker };
653*f6dc9357SAndroid Build Coastguard Worker 
654*f6dc9357SAndroid Build Coastguard Worker IMP_IInArchive_Props
655*f6dc9357SAndroid Build Coastguard Worker IMP_IInArchive_ArcProps
656*f6dc9357SAndroid Build Coastguard Worker 
SetTime(UInt32 dosTime,NCOM::CPropVariant & prop)657*f6dc9357SAndroid Build Coastguard Worker static void SetTime(UInt32 dosTime, NCOM::CPropVariant &prop)
658*f6dc9357SAndroid Build Coastguard Worker {
659*f6dc9357SAndroid Build Coastguard Worker   if (dosTime == 0)
660*f6dc9357SAndroid Build Coastguard Worker     return;
661*f6dc9357SAndroid Build Coastguard Worker   PropVariant_SetFrom_DosTime(prop, dosTime);
662*f6dc9357SAndroid Build Coastguard Worker }
663*f6dc9357SAndroid Build Coastguard Worker 
SetHostOS(Byte hostOS,NCOM::CPropVariant & prop)664*f6dc9357SAndroid Build Coastguard Worker static void SetHostOS(Byte hostOS, NCOM::CPropVariant &prop)
665*f6dc9357SAndroid Build Coastguard Worker {
666*f6dc9357SAndroid Build Coastguard Worker   TYPE_TO_PROP(kHostOS, hostOS, prop);
667*f6dc9357SAndroid Build Coastguard Worker }
668*f6dc9357SAndroid Build Coastguard Worker 
SetUnicodeString(const AString & s,NCOM::CPropVariant & prop)669*f6dc9357SAndroid Build Coastguard Worker static void SetUnicodeString(const AString &s, NCOM::CPropVariant &prop)
670*f6dc9357SAndroid Build Coastguard Worker {
671*f6dc9357SAndroid Build Coastguard Worker   if (!s.IsEmpty())
672*f6dc9357SAndroid Build Coastguard Worker     prop = MultiByteToUnicodeString(s, CP_OEMCP);
673*f6dc9357SAndroid Build Coastguard Worker }
674*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::GetArchiveProperty (PROPID propID,PROPVARIANT * value))675*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
676*f6dc9357SAndroid Build Coastguard Worker {
677*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
678*f6dc9357SAndroid Build Coastguard Worker   NCOM::CPropVariant prop;
679*f6dc9357SAndroid Build Coastguard Worker   switch (propID)
680*f6dc9357SAndroid Build Coastguard Worker   {
681*f6dc9357SAndroid Build Coastguard Worker     case kpidPhySize: prop = _phySize; break;
682*f6dc9357SAndroid Build Coastguard Worker     case kpidName: SetUnicodeString(_arc.Header.Name, prop); break;
683*f6dc9357SAndroid Build Coastguard Worker     case kpidCTime: SetTime(_arc.Header.CTime, prop); break;
684*f6dc9357SAndroid Build Coastguard Worker     case kpidMTime: SetTime(_arc.Header.MTime, prop); break;
685*f6dc9357SAndroid Build Coastguard Worker     case kpidHostOS: SetHostOS(_arc.Header.HostOS, prop); break;
686*f6dc9357SAndroid Build Coastguard Worker     case kpidComment: SetUnicodeString(_arc.Header.Comment, prop); break;
687*f6dc9357SAndroid Build Coastguard Worker     case kpidErrorFlags:
688*f6dc9357SAndroid Build Coastguard Worker     {
689*f6dc9357SAndroid Build Coastguard Worker       UInt32 v = 0;
690*f6dc9357SAndroid Build Coastguard Worker       if (!_arc.IsArc) v |= kpv_ErrorFlags_IsNotArc;
691*f6dc9357SAndroid Build Coastguard Worker       switch (_arc.Error)
692*f6dc9357SAndroid Build Coastguard Worker       {
693*f6dc9357SAndroid Build Coastguard Worker         case k_ErrorType_UnexpectedEnd: v |= kpv_ErrorFlags_UnexpectedEnd; break;
694*f6dc9357SAndroid Build Coastguard Worker         case k_ErrorType_Corrupted: v |= kpv_ErrorFlags_HeadersError; break;
695*f6dc9357SAndroid Build Coastguard Worker         case k_ErrorType_OK:
696*f6dc9357SAndroid Build Coastguard Worker         // default:
697*f6dc9357SAndroid Build Coastguard Worker           break;
698*f6dc9357SAndroid Build Coastguard Worker       }
699*f6dc9357SAndroid Build Coastguard Worker       prop = v;
700*f6dc9357SAndroid Build Coastguard Worker       break;
701*f6dc9357SAndroid Build Coastguard Worker     }
702*f6dc9357SAndroid Build Coastguard Worker     case kpidCharacts: _arc.ExtendedInfo.ParseToPropVar(prop); break;
703*f6dc9357SAndroid Build Coastguard Worker   }
704*f6dc9357SAndroid Build Coastguard Worker   prop.Detach(value);
705*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
706*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
707*f6dc9357SAndroid Build Coastguard Worker }
708*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::GetNumberOfItems (UInt32 * numItems))709*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
710*f6dc9357SAndroid Build Coastguard Worker {
711*f6dc9357SAndroid Build Coastguard Worker   *numItems = _items.Size();
712*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
713*f6dc9357SAndroid Build Coastguard Worker }
714*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::GetProperty (UInt32 index,PROPID propID,PROPVARIANT * value))715*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
716*f6dc9357SAndroid Build Coastguard Worker {
717*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
718*f6dc9357SAndroid Build Coastguard Worker   NCOM::CPropVariant prop;
719*f6dc9357SAndroid Build Coastguard Worker   const CItem &item = _items[index];
720*f6dc9357SAndroid Build Coastguard Worker   switch (propID)
721*f6dc9357SAndroid Build Coastguard Worker   {
722*f6dc9357SAndroid Build Coastguard Worker     case kpidPath:  prop = NItemName::GetOsPath(MultiByteToUnicodeString(item.Name, CP_OEMCP)); break;
723*f6dc9357SAndroid Build Coastguard Worker     case kpidIsDir:  prop = item.IsDir(); break;
724*f6dc9357SAndroid Build Coastguard Worker     case kpidSize:  prop = item.Size; break;
725*f6dc9357SAndroid Build Coastguard Worker     case kpidPackSize:  prop = item.PackSize; break;
726*f6dc9357SAndroid Build Coastguard Worker     case kpidPosition:  if (item.IsSplitBefore() || item.IsSplitAfter()) prop = (UInt64)item.SplitPos; break;
727*f6dc9357SAndroid Build Coastguard Worker     case kpidAttrib:  prop = item.GetWinAttrib(); break;
728*f6dc9357SAndroid Build Coastguard Worker     case kpidEncrypted:  prop = item.IsEncrypted(); break;
729*f6dc9357SAndroid Build Coastguard Worker     case kpidCRC:  prop = item.FileCRC; break;
730*f6dc9357SAndroid Build Coastguard Worker     case kpidMethod:  prop = item.Method; break;
731*f6dc9357SAndroid Build Coastguard Worker     case kpidHostOS:  SetHostOS(item.HostOS, prop); break;
732*f6dc9357SAndroid Build Coastguard Worker     case kpidMTime:  SetTime(item.MTime, prop); break;
733*f6dc9357SAndroid Build Coastguard Worker     case kpidComment:  SetUnicodeString(item.Comment, prop); break;
734*f6dc9357SAndroid Build Coastguard Worker     case kpidCharacts: item.ExtendedInfo.ParseToPropVar(prop); break;
735*f6dc9357SAndroid Build Coastguard Worker   }
736*f6dc9357SAndroid Build Coastguard Worker   prop.Detach(value);
737*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
738*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
739*f6dc9357SAndroid Build Coastguard Worker }
740*f6dc9357SAndroid Build Coastguard Worker 
Open2(IInStream * inStream,IArchiveOpenCallback * callback)741*f6dc9357SAndroid Build Coastguard Worker HRESULT CHandler::Open2(IInStream *inStream, IArchiveOpenCallback *callback)
742*f6dc9357SAndroid Build Coastguard Worker {
743*f6dc9357SAndroid Build Coastguard Worker   Close();
744*f6dc9357SAndroid Build Coastguard Worker 
745*f6dc9357SAndroid Build Coastguard Worker   UInt64 endPos;
746*f6dc9357SAndroid Build Coastguard Worker   RINOK(InStream_AtBegin_GetSize(inStream, endPos))
747*f6dc9357SAndroid Build Coastguard Worker 
748*f6dc9357SAndroid Build Coastguard Worker   _arc.Stream = inStream;
749*f6dc9357SAndroid Build Coastguard Worker   _arc.Callback = callback;
750*f6dc9357SAndroid Build Coastguard Worker   _arc.NumFiles = 0;
751*f6dc9357SAndroid Build Coastguard Worker   _arc.Processed = 0;
752*f6dc9357SAndroid Build Coastguard Worker 
753*f6dc9357SAndroid Build Coastguard Worker   RINOK(_arc.Open())
754*f6dc9357SAndroid Build Coastguard Worker 
755*f6dc9357SAndroid Build Coastguard Worker   _phySize = _arc.Processed;
756*f6dc9357SAndroid Build Coastguard Worker   if (_arc.Header.ArchiveSize != 0)
757*f6dc9357SAndroid Build Coastguard Worker     _phySize = (UInt64)_arc.Header.ArchiveSize + _arc.Header.SecurSize;
758*f6dc9357SAndroid Build Coastguard Worker 
759*f6dc9357SAndroid Build Coastguard Worker   for (;;)
760*f6dc9357SAndroid Build Coastguard Worker   {
761*f6dc9357SAndroid Build Coastguard Worker     CItem item;
762*f6dc9357SAndroid Build Coastguard Worker     bool filled;
763*f6dc9357SAndroid Build Coastguard Worker 
764*f6dc9357SAndroid Build Coastguard Worker     _arc.Error = k_ErrorType_OK;
765*f6dc9357SAndroid Build Coastguard Worker     RINOK(_arc.GetNextItem(item, filled))
766*f6dc9357SAndroid Build Coastguard Worker 
767*f6dc9357SAndroid Build Coastguard Worker     if (_arc.Error != k_ErrorType_OK)
768*f6dc9357SAndroid Build Coastguard Worker       break;
769*f6dc9357SAndroid Build Coastguard Worker 
770*f6dc9357SAndroid Build Coastguard Worker     if (!filled)
771*f6dc9357SAndroid Build Coastguard Worker     {
772*f6dc9357SAndroid Build Coastguard Worker       if (_arc.Error == k_ErrorType_OK)
773*f6dc9357SAndroid Build Coastguard Worker         if (_arc.Header.ArchiveSize == 0)
774*f6dc9357SAndroid Build Coastguard Worker           _phySize = _arc.Processed;
775*f6dc9357SAndroid Build Coastguard Worker       break;
776*f6dc9357SAndroid Build Coastguard Worker     }
777*f6dc9357SAndroid Build Coastguard Worker     item.DataPosition = _arc.Processed;
778*f6dc9357SAndroid Build Coastguard Worker     _items.Add(item);
779*f6dc9357SAndroid Build Coastguard Worker 
780*f6dc9357SAndroid Build Coastguard Worker     UInt64 pos = item.DataPosition + item.PackSize;
781*f6dc9357SAndroid Build Coastguard Worker     if (_arc.Header.ArchiveSize == 0)
782*f6dc9357SAndroid Build Coastguard Worker       _phySize = pos;
783*f6dc9357SAndroid Build Coastguard Worker     if (pos > endPos)
784*f6dc9357SAndroid Build Coastguard Worker     {
785*f6dc9357SAndroid Build Coastguard Worker       _arc.Error = k_ErrorType_UnexpectedEnd;
786*f6dc9357SAndroid Build Coastguard Worker       break;
787*f6dc9357SAndroid Build Coastguard Worker     }
788*f6dc9357SAndroid Build Coastguard Worker 
789*f6dc9357SAndroid Build Coastguard Worker     RINOK(InStream_SeekSet(inStream, pos))
790*f6dc9357SAndroid Build Coastguard Worker     _arc.NumFiles = _items.Size();
791*f6dc9357SAndroid Build Coastguard Worker     _arc.Processed = pos;
792*f6dc9357SAndroid Build Coastguard Worker 
793*f6dc9357SAndroid Build Coastguard Worker     if (callback && (_items.Size() & 0xFF) == 0)
794*f6dc9357SAndroid Build Coastguard Worker     {
795*f6dc9357SAndroid Build Coastguard Worker       RINOK(callback->SetCompleted(&_arc.NumFiles, &_arc.Processed))
796*f6dc9357SAndroid Build Coastguard Worker     }
797*f6dc9357SAndroid Build Coastguard Worker   }
798*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
799*f6dc9357SAndroid Build Coastguard Worker }
800*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::Open (IInStream * inStream,const UInt64 *,IArchiveOpenCallback * callback))801*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Open(IInStream *inStream,
802*f6dc9357SAndroid Build Coastguard Worker     const UInt64 * /* maxCheckStartPosition */, IArchiveOpenCallback *callback))
803*f6dc9357SAndroid Build Coastguard Worker {
804*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
805*f6dc9357SAndroid Build Coastguard Worker   HRESULT res;
806*f6dc9357SAndroid Build Coastguard Worker   {
807*f6dc9357SAndroid Build Coastguard Worker     res = Open2(inStream, callback);
808*f6dc9357SAndroid Build Coastguard Worker     if (res == S_OK)
809*f6dc9357SAndroid Build Coastguard Worker     {
810*f6dc9357SAndroid Build Coastguard Worker       _stream = inStream;
811*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
812*f6dc9357SAndroid Build Coastguard Worker     }
813*f6dc9357SAndroid Build Coastguard Worker   }
814*f6dc9357SAndroid Build Coastguard Worker   return res;
815*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
816*f6dc9357SAndroid Build Coastguard Worker }
817*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::Close ())818*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Close())
819*f6dc9357SAndroid Build Coastguard Worker {
820*f6dc9357SAndroid Build Coastguard Worker   _arc.Close();
821*f6dc9357SAndroid Build Coastguard Worker   _phySize = 0;
822*f6dc9357SAndroid Build Coastguard Worker   _items.Clear();
823*f6dc9357SAndroid Build Coastguard Worker   _stream.Release();
824*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
825*f6dc9357SAndroid Build Coastguard Worker }
826*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::Extract (const UInt32 * indices,UInt32 numItems,Int32 testMode,IArchiveExtractCallback * extractCallback))827*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
828*f6dc9357SAndroid Build Coastguard Worker     Int32 testMode, IArchiveExtractCallback *extractCallback))
829*f6dc9357SAndroid Build Coastguard Worker {
830*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
831*f6dc9357SAndroid Build Coastguard Worker   UInt64 totalUnpacked = 0, totalPacked = 0;
832*f6dc9357SAndroid Build Coastguard Worker   const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
833*f6dc9357SAndroid Build Coastguard Worker   if (allFilesMode)
834*f6dc9357SAndroid Build Coastguard Worker     numItems = _items.Size();
835*f6dc9357SAndroid Build Coastguard Worker   if (numItems == 0)
836*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
837*f6dc9357SAndroid Build Coastguard Worker   UInt32 i;
838*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < numItems; i++)
839*f6dc9357SAndroid Build Coastguard Worker   {
840*f6dc9357SAndroid Build Coastguard Worker     const CItem &item = _items[allFilesMode ? i : indices[i]];
841*f6dc9357SAndroid Build Coastguard Worker     totalUnpacked += item.Size;
842*f6dc9357SAndroid Build Coastguard Worker     // totalPacked += item.PackSize;
843*f6dc9357SAndroid Build Coastguard Worker   }
844*f6dc9357SAndroid Build Coastguard Worker   RINOK(extractCallback->SetTotal(totalUnpacked))
845*f6dc9357SAndroid Build Coastguard Worker 
846*f6dc9357SAndroid Build Coastguard Worker   totalUnpacked = totalPacked = 0;
847*f6dc9357SAndroid Build Coastguard Worker   UInt32 curUnpacked, curPacked;
848*f6dc9357SAndroid Build Coastguard Worker 
849*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ICompressProgressInfo, CLocalProgress> lps;
850*f6dc9357SAndroid Build Coastguard Worker   lps->Init(extractCallback, false);
851*f6dc9357SAndroid Build Coastguard Worker   CMyUniquePtr<NCompress::NLzh::NDecoder::CCoder> lzhDecoder;
852*f6dc9357SAndroid Build Coastguard Worker   CMyUniquePtr<NCompress::NArj::NDecoder::CCoder> arjDecoder;
853*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ICompressCoder, NCompress::CCopyCoder> copyCoder;
854*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ISequentialInStream, CLimitedSequentialInStream> inStream;
855*f6dc9357SAndroid Build Coastguard Worker   inStream->SetStream(_stream);
856*f6dc9357SAndroid Build Coastguard Worker 
857*f6dc9357SAndroid Build Coastguard Worker   for (i = 0;; i++,
858*f6dc9357SAndroid Build Coastguard Worker       totalUnpacked += curUnpacked,
859*f6dc9357SAndroid Build Coastguard Worker       totalPacked += curPacked)
860*f6dc9357SAndroid Build Coastguard Worker   {
861*f6dc9357SAndroid Build Coastguard Worker     lps->InSize = totalPacked;
862*f6dc9357SAndroid Build Coastguard Worker     lps->OutSize = totalUnpacked;
863*f6dc9357SAndroid Build Coastguard Worker     RINOK(lps->SetCur())
864*f6dc9357SAndroid Build Coastguard Worker     if (i >= numItems)
865*f6dc9357SAndroid Build Coastguard Worker       break;
866*f6dc9357SAndroid Build Coastguard Worker 
867*f6dc9357SAndroid Build Coastguard Worker     curUnpacked = curPacked = 0;
868*f6dc9357SAndroid Build Coastguard Worker 
869*f6dc9357SAndroid Build Coastguard Worker     Int32 opRes;
870*f6dc9357SAndroid Build Coastguard Worker     {
871*f6dc9357SAndroid Build Coastguard Worker       CMyComPtr<ISequentialOutStream> realOutStream;
872*f6dc9357SAndroid Build Coastguard Worker       const Int32 askMode = testMode ?
873*f6dc9357SAndroid Build Coastguard Worker           NExtract::NAskMode::kTest :
874*f6dc9357SAndroid Build Coastguard Worker           NExtract::NAskMode::kExtract;
875*f6dc9357SAndroid Build Coastguard Worker       const UInt32 index = allFilesMode ? i : indices[i];
876*f6dc9357SAndroid Build Coastguard Worker       const CItem &item = _items[index];
877*f6dc9357SAndroid Build Coastguard Worker       RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
878*f6dc9357SAndroid Build Coastguard Worker 
879*f6dc9357SAndroid Build Coastguard Worker       if (item.IsDir())
880*f6dc9357SAndroid Build Coastguard Worker       {
881*f6dc9357SAndroid Build Coastguard Worker         // if (!testMode)
882*f6dc9357SAndroid Build Coastguard Worker         {
883*f6dc9357SAndroid Build Coastguard Worker           RINOK(extractCallback->PrepareOperation(askMode))
884*f6dc9357SAndroid Build Coastguard Worker           // realOutStream.Release();
885*f6dc9357SAndroid Build Coastguard Worker           RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
886*f6dc9357SAndroid Build Coastguard Worker         }
887*f6dc9357SAndroid Build Coastguard Worker         continue;
888*f6dc9357SAndroid Build Coastguard Worker       }
889*f6dc9357SAndroid Build Coastguard Worker 
890*f6dc9357SAndroid Build Coastguard Worker       if (!testMode && !realOutStream)
891*f6dc9357SAndroid Build Coastguard Worker         continue;
892*f6dc9357SAndroid Build Coastguard Worker 
893*f6dc9357SAndroid Build Coastguard Worker       RINOK(extractCallback->PrepareOperation(askMode))
894*f6dc9357SAndroid Build Coastguard Worker       curUnpacked = item.Size;
895*f6dc9357SAndroid Build Coastguard Worker       curPacked = item.PackSize;
896*f6dc9357SAndroid Build Coastguard Worker 
897*f6dc9357SAndroid Build Coastguard Worker       CMyComPtr2_Create<ISequentialOutStream, COutStreamWithCRC> outStream;
898*f6dc9357SAndroid Build Coastguard Worker       outStream->SetStream(realOutStream);
899*f6dc9357SAndroid Build Coastguard Worker       // realOutStream.Release();
900*f6dc9357SAndroid Build Coastguard Worker       outStream->Init();
901*f6dc9357SAndroid Build Coastguard Worker 
902*f6dc9357SAndroid Build Coastguard Worker       inStream->Init(item.PackSize);
903*f6dc9357SAndroid Build Coastguard Worker 
904*f6dc9357SAndroid Build Coastguard Worker       RINOK(InStream_SeekSet(_stream, item.DataPosition))
905*f6dc9357SAndroid Build Coastguard Worker 
906*f6dc9357SAndroid Build Coastguard Worker       HRESULT result = S_OK;
907*f6dc9357SAndroid Build Coastguard Worker       opRes = NExtract::NOperationResult::kOK;
908*f6dc9357SAndroid Build Coastguard Worker 
909*f6dc9357SAndroid Build Coastguard Worker       if (item.IsEncrypted())
910*f6dc9357SAndroid Build Coastguard Worker         opRes = NExtract::NOperationResult::kUnsupportedMethod;
911*f6dc9357SAndroid Build Coastguard Worker       else
912*f6dc9357SAndroid Build Coastguard Worker       {
913*f6dc9357SAndroid Build Coastguard Worker         switch (item.Method)
914*f6dc9357SAndroid Build Coastguard Worker         {
915*f6dc9357SAndroid Build Coastguard Worker           case NCompressionMethod::kStored:
916*f6dc9357SAndroid Build Coastguard Worker           {
917*f6dc9357SAndroid Build Coastguard Worker             result = copyCoder.Interface()->Code(inStream, outStream, NULL, NULL, lps);
918*f6dc9357SAndroid Build Coastguard Worker             if (result == S_OK && copyCoder->TotalSize != item.PackSize)
919*f6dc9357SAndroid Build Coastguard Worker               result = S_FALSE;
920*f6dc9357SAndroid Build Coastguard Worker             break;
921*f6dc9357SAndroid Build Coastguard Worker           }
922*f6dc9357SAndroid Build Coastguard Worker           case NCompressionMethod::kCompressed1a:
923*f6dc9357SAndroid Build Coastguard Worker           case NCompressionMethod::kCompressed1b:
924*f6dc9357SAndroid Build Coastguard Worker           case NCompressionMethod::kCompressed1c:
925*f6dc9357SAndroid Build Coastguard Worker           {
926*f6dc9357SAndroid Build Coastguard Worker             lzhDecoder.Create_if_Empty();
927*f6dc9357SAndroid Build Coastguard Worker             // lzhDecoder->FinishMode = true;
928*f6dc9357SAndroid Build Coastguard Worker             const UInt32 kHistorySize = 26624;
929*f6dc9357SAndroid Build Coastguard Worker             lzhDecoder->SetDictSize(kHistorySize);
930*f6dc9357SAndroid Build Coastguard Worker             result = lzhDecoder->Code(inStream, outStream, curUnpacked, lps);
931*f6dc9357SAndroid Build Coastguard Worker             if (result == S_OK && lzhDecoder->GetInputProcessedSize() != item.PackSize)
932*f6dc9357SAndroid Build Coastguard Worker               result = S_FALSE;
933*f6dc9357SAndroid Build Coastguard Worker             break;
934*f6dc9357SAndroid Build Coastguard Worker           }
935*f6dc9357SAndroid Build Coastguard Worker           case NCompressionMethod::kCompressed2:
936*f6dc9357SAndroid Build Coastguard Worker           {
937*f6dc9357SAndroid Build Coastguard Worker             arjDecoder.Create_if_Empty();
938*f6dc9357SAndroid Build Coastguard Worker             // arjDecoderSpec->FinishMode = true;
939*f6dc9357SAndroid Build Coastguard Worker             result = arjDecoder->Code(inStream, outStream, curUnpacked, lps);
940*f6dc9357SAndroid Build Coastguard Worker             if (result == S_OK && arjDecoder->GetInputProcessedSize() != item.PackSize)
941*f6dc9357SAndroid Build Coastguard Worker               result = S_FALSE;
942*f6dc9357SAndroid Build Coastguard Worker             break;
943*f6dc9357SAndroid Build Coastguard Worker           }
944*f6dc9357SAndroid Build Coastguard Worker           default:
945*f6dc9357SAndroid Build Coastguard Worker             opRes = NExtract::NOperationResult::kUnsupportedMethod;
946*f6dc9357SAndroid Build Coastguard Worker         }
947*f6dc9357SAndroid Build Coastguard Worker       }
948*f6dc9357SAndroid Build Coastguard Worker 
949*f6dc9357SAndroid Build Coastguard Worker       if (opRes == NExtract::NOperationResult::kOK)
950*f6dc9357SAndroid Build Coastguard Worker       {
951*f6dc9357SAndroid Build Coastguard Worker         if (result == S_FALSE)
952*f6dc9357SAndroid Build Coastguard Worker           opRes = NExtract::NOperationResult::kDataError;
953*f6dc9357SAndroid Build Coastguard Worker         else
954*f6dc9357SAndroid Build Coastguard Worker         {
955*f6dc9357SAndroid Build Coastguard Worker           RINOK(result)
956*f6dc9357SAndroid Build Coastguard Worker           opRes = (outStream->GetCRC() == item.FileCRC) ?
957*f6dc9357SAndroid Build Coastguard Worker               NExtract::NOperationResult::kOK:
958*f6dc9357SAndroid Build Coastguard Worker               NExtract::NOperationResult::kCRCError;
959*f6dc9357SAndroid Build Coastguard Worker         }
960*f6dc9357SAndroid Build Coastguard Worker       }
961*f6dc9357SAndroid Build Coastguard Worker     }
962*f6dc9357SAndroid Build Coastguard Worker     RINOK(extractCallback->SetOperationResult(opRes))
963*f6dc9357SAndroid Build Coastguard Worker   }
964*f6dc9357SAndroid Build Coastguard Worker 
965*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
966*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
967*f6dc9357SAndroid Build Coastguard Worker }
968*f6dc9357SAndroid Build Coastguard Worker 
969*f6dc9357SAndroid Build Coastguard Worker static const Byte k_Signature[] = { kSig0, kSig1 };
970*f6dc9357SAndroid Build Coastguard Worker 
971*f6dc9357SAndroid Build Coastguard Worker REGISTER_ARC_I(
972*f6dc9357SAndroid Build Coastguard Worker   "Arj", "arj", NULL, 4,
973*f6dc9357SAndroid Build Coastguard Worker   k_Signature,
974*f6dc9357SAndroid Build Coastguard Worker   0,
975*f6dc9357SAndroid Build Coastguard Worker   0,
976*f6dc9357SAndroid Build Coastguard Worker   IsArc_Arj)
977*f6dc9357SAndroid Build Coastguard Worker 
978*f6dc9357SAndroid Build Coastguard Worker }}
979