xref: /aosp_15_r20/external/lzma/CPP/7zip/Archive/Zip/ZipIn.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1*f6dc9357SAndroid Build Coastguard Worker // Archive/ZipIn.cpp
2*f6dc9357SAndroid Build Coastguard Worker 
3*f6dc9357SAndroid Build Coastguard Worker #include "StdAfx.h"
4*f6dc9357SAndroid Build Coastguard Worker 
5*f6dc9357SAndroid Build Coastguard Worker // #include <stdio.h>
6*f6dc9357SAndroid Build Coastguard Worker 
7*f6dc9357SAndroid Build Coastguard Worker #include "../../../Common/DynamicBuffer.h"
8*f6dc9357SAndroid Build Coastguard Worker #include "../../../Common/IntToString.h"
9*f6dc9357SAndroid Build Coastguard Worker #include "../../../Common/MyException.h"
10*f6dc9357SAndroid Build Coastguard Worker #include "../../../Common/StringToInt.h"
11*f6dc9357SAndroid Build Coastguard Worker 
12*f6dc9357SAndroid Build Coastguard Worker #include "../../../Windows/PropVariant.h"
13*f6dc9357SAndroid Build Coastguard Worker 
14*f6dc9357SAndroid Build Coastguard Worker #include "../IArchive.h"
15*f6dc9357SAndroid Build Coastguard Worker 
16*f6dc9357SAndroid Build Coastguard Worker #include "ZipIn.h"
17*f6dc9357SAndroid Build Coastguard Worker 
18*f6dc9357SAndroid Build Coastguard Worker #define Get16(p) GetUi16(p)
19*f6dc9357SAndroid Build Coastguard Worker #define Get32(p) GetUi32(p)
20*f6dc9357SAndroid Build Coastguard Worker #define Get64(p) GetUi64(p)
21*f6dc9357SAndroid Build Coastguard Worker 
22*f6dc9357SAndroid Build Coastguard Worker #define G16(offs, v) v = Get16(p + (offs))
23*f6dc9357SAndroid Build Coastguard Worker #define G32(offs, v) v = Get32(p + (offs))
24*f6dc9357SAndroid Build Coastguard Worker #define G64(offs, v) v = Get64(p + (offs))
25*f6dc9357SAndroid Build Coastguard Worker 
26*f6dc9357SAndroid Build Coastguard Worker namespace NArchive {
27*f6dc9357SAndroid Build Coastguard Worker namespace NZip {
28*f6dc9357SAndroid Build Coastguard Worker 
29*f6dc9357SAndroid Build Coastguard Worker /* we try to use same size of Buffer (1 << 17) for all tasks.
30*f6dc9357SAndroid Build Coastguard Worker    it allow to avoid reallocations and cache clearing. */
31*f6dc9357SAndroid Build Coastguard Worker 
32*f6dc9357SAndroid Build Coastguard Worker static const size_t kSeqBufferSize = (size_t)1 << 17;
33*f6dc9357SAndroid Build Coastguard Worker 
34*f6dc9357SAndroid Build Coastguard Worker /*
35*f6dc9357SAndroid Build Coastguard Worker Open()
36*f6dc9357SAndroid Build Coastguard Worker {
37*f6dc9357SAndroid Build Coastguard Worker   _inBufMode = false;
38*f6dc9357SAndroid Build Coastguard Worker   ReadVols()
39*f6dc9357SAndroid Build Coastguard Worker     FindCd();
40*f6dc9357SAndroid Build Coastguard Worker       TryEcd64()
41*f6dc9357SAndroid Build Coastguard Worker   SeekToVol()
42*f6dc9357SAndroid Build Coastguard Worker   FindMarker()
43*f6dc9357SAndroid Build Coastguard Worker     _inBufMode = true;
44*f6dc9357SAndroid Build Coastguard Worker   ReadHeaders()
45*f6dc9357SAndroid Build Coastguard Worker     _inBufMode = false;
46*f6dc9357SAndroid Build Coastguard Worker     ReadCd()
47*f6dc9357SAndroid Build Coastguard Worker       FindCd()
48*f6dc9357SAndroid Build Coastguard Worker         TryEcd64()
49*f6dc9357SAndroid Build Coastguard Worker       TryReadCd()
50*f6dc9357SAndroid Build Coastguard Worker       {
51*f6dc9357SAndroid Build Coastguard Worker         SeekToVol();
52*f6dc9357SAndroid Build Coastguard Worker         _inBufMode = true;
53*f6dc9357SAndroid Build Coastguard Worker       }
54*f6dc9357SAndroid Build Coastguard Worker     _inBufMode = true;
55*f6dc9357SAndroid Build Coastguard Worker     ReadLocals()
56*f6dc9357SAndroid Build Coastguard Worker     ReadCdItem()
57*f6dc9357SAndroid Build Coastguard Worker     ....
58*f6dc9357SAndroid Build Coastguard Worker }
59*f6dc9357SAndroid Build Coastguard Worker FindCd() writes to Buffer without touching (_inBufMode)
60*f6dc9357SAndroid Build Coastguard Worker */
61*f6dc9357SAndroid Build Coastguard Worker 
62*f6dc9357SAndroid Build Coastguard Worker /*
63*f6dc9357SAndroid Build Coastguard Worker   if (not defined ZIP_SELF_CHECK) : it reads CD and if error in first pass CD reading, it reads LOCALS-CD-MODE
64*f6dc9357SAndroid Build Coastguard Worker   if (    defined ZIP_SELF_CHECK) : it always reads CD and LOCALS-CD-MODE
65*f6dc9357SAndroid Build Coastguard Worker   use ZIP_SELF_CHECK to check LOCALS-CD-MODE for any zip archive
66*f6dc9357SAndroid Build Coastguard Worker */
67*f6dc9357SAndroid Build Coastguard Worker 
68*f6dc9357SAndroid Build Coastguard Worker // #define ZIP_SELF_CHECK
69*f6dc9357SAndroid Build Coastguard Worker 
70*f6dc9357SAndroid Build Coastguard Worker 
71*f6dc9357SAndroid Build Coastguard Worker struct CEcd
72*f6dc9357SAndroid Build Coastguard Worker {
73*f6dc9357SAndroid Build Coastguard Worker   UInt16 ThisDisk;
74*f6dc9357SAndroid Build Coastguard Worker   UInt16 CdDisk;
75*f6dc9357SAndroid Build Coastguard Worker   UInt16 NumEntries_in_ThisDisk;
76*f6dc9357SAndroid Build Coastguard Worker   UInt16 NumEntries;
77*f6dc9357SAndroid Build Coastguard Worker   UInt32 Size;
78*f6dc9357SAndroid Build Coastguard Worker   UInt32 Offset;
79*f6dc9357SAndroid Build Coastguard Worker   UInt16 CommentSize;
80*f6dc9357SAndroid Build Coastguard Worker 
IsEmptyArcNArchive::NZip::CEcd81*f6dc9357SAndroid Build Coastguard Worker   bool IsEmptyArc() const
82*f6dc9357SAndroid Build Coastguard Worker   {
83*f6dc9357SAndroid Build Coastguard Worker     return ThisDisk == 0
84*f6dc9357SAndroid Build Coastguard Worker         && CdDisk == 0
85*f6dc9357SAndroid Build Coastguard Worker         && NumEntries_in_ThisDisk == 0
86*f6dc9357SAndroid Build Coastguard Worker         && NumEntries == 0
87*f6dc9357SAndroid Build Coastguard Worker         && Size == 0
88*f6dc9357SAndroid Build Coastguard Worker         && Offset == 0 // test it
89*f6dc9357SAndroid Build Coastguard Worker     ;
90*f6dc9357SAndroid Build Coastguard Worker   }
91*f6dc9357SAndroid Build Coastguard Worker 
92*f6dc9357SAndroid Build Coastguard Worker   void Parse(const Byte *p); // (p) doesn't include signature
93*f6dc9357SAndroid Build Coastguard Worker };
94*f6dc9357SAndroid Build Coastguard Worker 
Parse(const Byte * p)95*f6dc9357SAndroid Build Coastguard Worker void CEcd::Parse(const Byte *p)
96*f6dc9357SAndroid Build Coastguard Worker {
97*f6dc9357SAndroid Build Coastguard Worker   // (p) doesn't include signature
98*f6dc9357SAndroid Build Coastguard Worker   G16(0, ThisDisk);
99*f6dc9357SAndroid Build Coastguard Worker   G16(2, CdDisk);
100*f6dc9357SAndroid Build Coastguard Worker   G16(4, NumEntries_in_ThisDisk);
101*f6dc9357SAndroid Build Coastguard Worker   G16(6, NumEntries);
102*f6dc9357SAndroid Build Coastguard Worker   G32(8, Size);
103*f6dc9357SAndroid Build Coastguard Worker   G32(12, Offset);
104*f6dc9357SAndroid Build Coastguard Worker   G16(16, CommentSize);
105*f6dc9357SAndroid Build Coastguard Worker }
106*f6dc9357SAndroid Build Coastguard Worker 
107*f6dc9357SAndroid Build Coastguard Worker 
ParseEcd32(const Byte * p)108*f6dc9357SAndroid Build Coastguard Worker void CCdInfo::ParseEcd32(const Byte *p)
109*f6dc9357SAndroid Build Coastguard Worker {
110*f6dc9357SAndroid Build Coastguard Worker   IsFromEcd64 = false;
111*f6dc9357SAndroid Build Coastguard Worker   // (p) includes signature
112*f6dc9357SAndroid Build Coastguard Worker   p += 4;
113*f6dc9357SAndroid Build Coastguard Worker   G16(0, ThisDisk);
114*f6dc9357SAndroid Build Coastguard Worker   G16(2, CdDisk);
115*f6dc9357SAndroid Build Coastguard Worker   G16(4, NumEntries_in_ThisDisk);
116*f6dc9357SAndroid Build Coastguard Worker   G16(6, NumEntries);
117*f6dc9357SAndroid Build Coastguard Worker   G32(8, Size);
118*f6dc9357SAndroid Build Coastguard Worker   G32(12, Offset);
119*f6dc9357SAndroid Build Coastguard Worker   G16(16, CommentSize);
120*f6dc9357SAndroid Build Coastguard Worker }
121*f6dc9357SAndroid Build Coastguard Worker 
ParseEcd64e(const Byte * p)122*f6dc9357SAndroid Build Coastguard Worker void CCdInfo::ParseEcd64e(const Byte *p)
123*f6dc9357SAndroid Build Coastguard Worker {
124*f6dc9357SAndroid Build Coastguard Worker   IsFromEcd64 = true;
125*f6dc9357SAndroid Build Coastguard Worker   // (p) exclude signature
126*f6dc9357SAndroid Build Coastguard Worker   G16(0, VersionMade);
127*f6dc9357SAndroid Build Coastguard Worker   G16(2, VersionNeedExtract);
128*f6dc9357SAndroid Build Coastguard Worker   G32(4, ThisDisk);
129*f6dc9357SAndroid Build Coastguard Worker   G32(8, CdDisk);
130*f6dc9357SAndroid Build Coastguard Worker 
131*f6dc9357SAndroid Build Coastguard Worker   G64(12, NumEntries_in_ThisDisk);
132*f6dc9357SAndroid Build Coastguard Worker   G64(20, NumEntries);
133*f6dc9357SAndroid Build Coastguard Worker   G64(28, Size);
134*f6dc9357SAndroid Build Coastguard Worker   G64(36, Offset);
135*f6dc9357SAndroid Build Coastguard Worker }
136*f6dc9357SAndroid Build Coastguard Worker 
137*f6dc9357SAndroid Build Coastguard Worker 
138*f6dc9357SAndroid Build Coastguard Worker struct CLocator
139*f6dc9357SAndroid Build Coastguard Worker {
140*f6dc9357SAndroid Build Coastguard Worker   UInt32 Ecd64Disk;
141*f6dc9357SAndroid Build Coastguard Worker   UInt32 NumDisks;
142*f6dc9357SAndroid Build Coastguard Worker   UInt64 Ecd64Offset;
143*f6dc9357SAndroid Build Coastguard Worker 
CLocatorNArchive::NZip::CLocator144*f6dc9357SAndroid Build Coastguard Worker   CLocator(): Ecd64Disk(0), NumDisks(0), Ecd64Offset(0) {}
145*f6dc9357SAndroid Build Coastguard Worker 
ParseNArchive::NZip::CLocator146*f6dc9357SAndroid Build Coastguard Worker   void Parse(const Byte *p)
147*f6dc9357SAndroid Build Coastguard Worker   {
148*f6dc9357SAndroid Build Coastguard Worker     G32(0, Ecd64Disk);
149*f6dc9357SAndroid Build Coastguard Worker     G64(4, Ecd64Offset);
150*f6dc9357SAndroid Build Coastguard Worker     G32(12, NumDisks);
151*f6dc9357SAndroid Build Coastguard Worker   }
152*f6dc9357SAndroid Build Coastguard Worker 
IsEmptyArcNArchive::NZip::CLocator153*f6dc9357SAndroid Build Coastguard Worker   bool IsEmptyArc() const
154*f6dc9357SAndroid Build Coastguard Worker   {
155*f6dc9357SAndroid Build Coastguard Worker     return Ecd64Disk == 0 && NumDisks == 0 && Ecd64Offset == 0;
156*f6dc9357SAndroid Build Coastguard Worker   }
157*f6dc9357SAndroid Build Coastguard Worker };
158*f6dc9357SAndroid Build Coastguard Worker 
159*f6dc9357SAndroid Build Coastguard Worker 
160*f6dc9357SAndroid Build Coastguard Worker 
161*f6dc9357SAndroid Build Coastguard Worker 
ClearRefs()162*f6dc9357SAndroid Build Coastguard Worker void CInArchive::ClearRefs()
163*f6dc9357SAndroid Build Coastguard Worker {
164*f6dc9357SAndroid Build Coastguard Worker   StreamRef.Release();
165*f6dc9357SAndroid Build Coastguard Worker   Stream = NULL;
166*f6dc9357SAndroid Build Coastguard Worker   StartStream = NULL;
167*f6dc9357SAndroid Build Coastguard Worker   Callback = NULL;
168*f6dc9357SAndroid Build Coastguard Worker 
169*f6dc9357SAndroid Build Coastguard Worker   Vols.Clear();
170*f6dc9357SAndroid Build Coastguard Worker }
171*f6dc9357SAndroid Build Coastguard Worker 
Close()172*f6dc9357SAndroid Build Coastguard Worker void CInArchive::Close()
173*f6dc9357SAndroid Build Coastguard Worker {
174*f6dc9357SAndroid Build Coastguard Worker   _cnt = 0;
175*f6dc9357SAndroid Build Coastguard Worker   DisableBufMode();
176*f6dc9357SAndroid Build Coastguard Worker 
177*f6dc9357SAndroid Build Coastguard Worker   IsArcOpen = false;
178*f6dc9357SAndroid Build Coastguard Worker 
179*f6dc9357SAndroid Build Coastguard Worker   IsArc = false;
180*f6dc9357SAndroid Build Coastguard Worker   IsZip64 = false;
181*f6dc9357SAndroid Build Coastguard Worker 
182*f6dc9357SAndroid Build Coastguard Worker   IsApk = false;
183*f6dc9357SAndroid Build Coastguard Worker   IsCdUnsorted = false;
184*f6dc9357SAndroid Build Coastguard Worker 
185*f6dc9357SAndroid Build Coastguard Worker   HeadersError = false;
186*f6dc9357SAndroid Build Coastguard Worker   HeadersWarning = false;
187*f6dc9357SAndroid Build Coastguard Worker   ExtraMinorError = false;
188*f6dc9357SAndroid Build Coastguard Worker 
189*f6dc9357SAndroid Build Coastguard Worker   UnexpectedEnd = false;
190*f6dc9357SAndroid Build Coastguard Worker   LocalsWereRead = false;
191*f6dc9357SAndroid Build Coastguard Worker   LocalsCenterMerged = false;
192*f6dc9357SAndroid Build Coastguard Worker   NoCentralDir = false;
193*f6dc9357SAndroid Build Coastguard Worker   Overflow32bit = false;
194*f6dc9357SAndroid Build Coastguard Worker   Cd_NumEntries_Overflow_16bit = false;
195*f6dc9357SAndroid Build Coastguard Worker 
196*f6dc9357SAndroid Build Coastguard Worker   MarkerIsFound = false;
197*f6dc9357SAndroid Build Coastguard Worker   MarkerIsSafe = false;
198*f6dc9357SAndroid Build Coastguard Worker 
199*f6dc9357SAndroid Build Coastguard Worker   IsMultiVol = false;
200*f6dc9357SAndroid Build Coastguard Worker   UseDisk_in_SingleVol = false;
201*f6dc9357SAndroid Build Coastguard Worker   EcdVolIndex = 0;
202*f6dc9357SAndroid Build Coastguard Worker 
203*f6dc9357SAndroid Build Coastguard Worker   ArcInfo.Clear();
204*f6dc9357SAndroid Build Coastguard Worker 
205*f6dc9357SAndroid Build Coastguard Worker   ClearRefs();
206*f6dc9357SAndroid Build Coastguard Worker }
207*f6dc9357SAndroid Build Coastguard Worker 
208*f6dc9357SAndroid Build Coastguard Worker 
209*f6dc9357SAndroid Build Coastguard Worker 
Seek_SavePos(UInt64 offset)210*f6dc9357SAndroid Build Coastguard Worker HRESULT CInArchive::Seek_SavePos(UInt64 offset)
211*f6dc9357SAndroid Build Coastguard Worker {
212*f6dc9357SAndroid Build Coastguard Worker   // InitBuf();
213*f6dc9357SAndroid Build Coastguard Worker   // if (!Stream) return S_FALSE;
214*f6dc9357SAndroid Build Coastguard Worker   return Stream->Seek((Int64)offset, STREAM_SEEK_SET, &_streamPos);
215*f6dc9357SAndroid Build Coastguard Worker }
216*f6dc9357SAndroid Build Coastguard Worker 
217*f6dc9357SAndroid Build Coastguard Worker 
218*f6dc9357SAndroid Build Coastguard Worker /* SeekToVol() will keep the cached mode, if new volIndex is
219*f6dc9357SAndroid Build Coastguard Worker    same Vols.StreamIndex volume, and offset doesn't go out of cached region */
220*f6dc9357SAndroid Build Coastguard Worker 
SeekToVol(int volIndex,UInt64 offset)221*f6dc9357SAndroid Build Coastguard Worker HRESULT CInArchive::SeekToVol(int volIndex, UInt64 offset)
222*f6dc9357SAndroid Build Coastguard Worker {
223*f6dc9357SAndroid Build Coastguard Worker   if (volIndex != Vols.StreamIndex)
224*f6dc9357SAndroid Build Coastguard Worker   {
225*f6dc9357SAndroid Build Coastguard Worker     if (IsMultiVol && volIndex >= 0)
226*f6dc9357SAndroid Build Coastguard Worker     {
227*f6dc9357SAndroid Build Coastguard Worker       if ((unsigned)volIndex >= Vols.Streams.Size())
228*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
229*f6dc9357SAndroid Build Coastguard Worker       if (!Vols.Streams[(unsigned)volIndex].Stream)
230*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
231*f6dc9357SAndroid Build Coastguard Worker       Stream = Vols.Streams[(unsigned)volIndex].Stream;
232*f6dc9357SAndroid Build Coastguard Worker     }
233*f6dc9357SAndroid Build Coastguard Worker     else if (volIndex == -2)
234*f6dc9357SAndroid Build Coastguard Worker     {
235*f6dc9357SAndroid Build Coastguard Worker       if (!Vols.ZipStream)
236*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
237*f6dc9357SAndroid Build Coastguard Worker       Stream = Vols.ZipStream;
238*f6dc9357SAndroid Build Coastguard Worker     }
239*f6dc9357SAndroid Build Coastguard Worker     else
240*f6dc9357SAndroid Build Coastguard Worker       Stream = StartStream;
241*f6dc9357SAndroid Build Coastguard Worker     Vols.StreamIndex = volIndex;
242*f6dc9357SAndroid Build Coastguard Worker   }
243*f6dc9357SAndroid Build Coastguard Worker   else
244*f6dc9357SAndroid Build Coastguard Worker   {
245*f6dc9357SAndroid Build Coastguard Worker     if (offset <= _streamPos)
246*f6dc9357SAndroid Build Coastguard Worker     {
247*f6dc9357SAndroid Build Coastguard Worker       const UInt64 back = _streamPos - offset;
248*f6dc9357SAndroid Build Coastguard Worker       if (back <= _bufCached)
249*f6dc9357SAndroid Build Coastguard Worker       {
250*f6dc9357SAndroid Build Coastguard Worker         _bufPos = _bufCached - (size_t)back;
251*f6dc9357SAndroid Build Coastguard Worker         return S_OK;
252*f6dc9357SAndroid Build Coastguard Worker       }
253*f6dc9357SAndroid Build Coastguard Worker     }
254*f6dc9357SAndroid Build Coastguard Worker   }
255*f6dc9357SAndroid Build Coastguard Worker   InitBuf();
256*f6dc9357SAndroid Build Coastguard Worker   return Seek_SavePos(offset);
257*f6dc9357SAndroid Build Coastguard Worker }
258*f6dc9357SAndroid Build Coastguard Worker 
259*f6dc9357SAndroid Build Coastguard Worker 
AllocateBuffer(size_t size)260*f6dc9357SAndroid Build Coastguard Worker HRESULT CInArchive::AllocateBuffer(size_t size)
261*f6dc9357SAndroid Build Coastguard Worker {
262*f6dc9357SAndroid Build Coastguard Worker   if (size <= Buffer.Size())
263*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
264*f6dc9357SAndroid Build Coastguard Worker   /* in cached mode virtual_pos is not equal to phy_pos (_streamPos)
265*f6dc9357SAndroid Build Coastguard Worker      so we change _streamPos and do Seek() to virtual_pos before cache clearing */
266*f6dc9357SAndroid Build Coastguard Worker   if (_bufPos != _bufCached)
267*f6dc9357SAndroid Build Coastguard Worker   {
268*f6dc9357SAndroid Build Coastguard Worker     RINOK(Seek_SavePos(GetVirtStreamPos()))
269*f6dc9357SAndroid Build Coastguard Worker   }
270*f6dc9357SAndroid Build Coastguard Worker   InitBuf();
271*f6dc9357SAndroid Build Coastguard Worker   Buffer.AllocAtLeast(size);
272*f6dc9357SAndroid Build Coastguard Worker   if (!Buffer.IsAllocated())
273*f6dc9357SAndroid Build Coastguard Worker     return E_OUTOFMEMORY;
274*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
275*f6dc9357SAndroid Build Coastguard Worker }
276*f6dc9357SAndroid Build Coastguard Worker 
277*f6dc9357SAndroid Build Coastguard Worker // ---------- ReadFromCache ----------
278*f6dc9357SAndroid Build Coastguard Worker // reads from cache and from Stream
279*f6dc9357SAndroid Build Coastguard Worker // move to next volume can be allowed if (CanStartNewVol) and only before first byte reading
280*f6dc9357SAndroid Build Coastguard Worker 
ReadFromCache(Byte * data,unsigned size,unsigned & processed)281*f6dc9357SAndroid Build Coastguard Worker HRESULT CInArchive::ReadFromCache(Byte *data, unsigned size, unsigned &processed)
282*f6dc9357SAndroid Build Coastguard Worker {
283*f6dc9357SAndroid Build Coastguard Worker   HRESULT result = S_OK;
284*f6dc9357SAndroid Build Coastguard Worker   processed = 0;
285*f6dc9357SAndroid Build Coastguard Worker 
286*f6dc9357SAndroid Build Coastguard Worker   for (;;)
287*f6dc9357SAndroid Build Coastguard Worker   {
288*f6dc9357SAndroid Build Coastguard Worker     if (size == 0)
289*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
290*f6dc9357SAndroid Build Coastguard Worker 
291*f6dc9357SAndroid Build Coastguard Worker     const size_t avail = GetAvail();
292*f6dc9357SAndroid Build Coastguard Worker 
293*f6dc9357SAndroid Build Coastguard Worker     if (avail != 0)
294*f6dc9357SAndroid Build Coastguard Worker     {
295*f6dc9357SAndroid Build Coastguard Worker       unsigned cur = size;
296*f6dc9357SAndroid Build Coastguard Worker       if (cur > avail)
297*f6dc9357SAndroid Build Coastguard Worker         cur = (unsigned)avail;
298*f6dc9357SAndroid Build Coastguard Worker       memcpy(data, (const Byte *)Buffer + _bufPos, cur);
299*f6dc9357SAndroid Build Coastguard Worker 
300*f6dc9357SAndroid Build Coastguard Worker       data += cur;
301*f6dc9357SAndroid Build Coastguard Worker       size -= cur;
302*f6dc9357SAndroid Build Coastguard Worker       processed += cur;
303*f6dc9357SAndroid Build Coastguard Worker 
304*f6dc9357SAndroid Build Coastguard Worker       _bufPos += cur;
305*f6dc9357SAndroid Build Coastguard Worker       _cnt += cur;
306*f6dc9357SAndroid Build Coastguard Worker 
307*f6dc9357SAndroid Build Coastguard Worker       CanStartNewVol = false;
308*f6dc9357SAndroid Build Coastguard Worker 
309*f6dc9357SAndroid Build Coastguard Worker       continue;
310*f6dc9357SAndroid Build Coastguard Worker     }
311*f6dc9357SAndroid Build Coastguard Worker 
312*f6dc9357SAndroid Build Coastguard Worker     InitBuf();
313*f6dc9357SAndroid Build Coastguard Worker 
314*f6dc9357SAndroid Build Coastguard Worker     if (_inBufMode)
315*f6dc9357SAndroid Build Coastguard Worker     {
316*f6dc9357SAndroid Build Coastguard Worker       UInt32 cur = 0;
317*f6dc9357SAndroid Build Coastguard Worker       result = Stream->Read(Buffer, (UInt32)Buffer.Size(), &cur);
318*f6dc9357SAndroid Build Coastguard Worker       _bufPos = 0;
319*f6dc9357SAndroid Build Coastguard Worker       _bufCached = cur;
320*f6dc9357SAndroid Build Coastguard Worker       _streamPos += cur;
321*f6dc9357SAndroid Build Coastguard Worker       if (cur != 0)
322*f6dc9357SAndroid Build Coastguard Worker         CanStartNewVol = false;
323*f6dc9357SAndroid Build Coastguard Worker       if (result != S_OK)
324*f6dc9357SAndroid Build Coastguard Worker         break;
325*f6dc9357SAndroid Build Coastguard Worker       if (cur != 0)
326*f6dc9357SAndroid Build Coastguard Worker         continue;
327*f6dc9357SAndroid Build Coastguard Worker     }
328*f6dc9357SAndroid Build Coastguard Worker     else
329*f6dc9357SAndroid Build Coastguard Worker     {
330*f6dc9357SAndroid Build Coastguard Worker       size_t cur = size;
331*f6dc9357SAndroid Build Coastguard Worker       result = ReadStream(Stream, data, &cur);
332*f6dc9357SAndroid Build Coastguard Worker       data += cur;
333*f6dc9357SAndroid Build Coastguard Worker       size -= (unsigned)cur;
334*f6dc9357SAndroid Build Coastguard Worker       processed += (unsigned)cur;
335*f6dc9357SAndroid Build Coastguard Worker       _streamPos += cur;
336*f6dc9357SAndroid Build Coastguard Worker       _cnt += cur;
337*f6dc9357SAndroid Build Coastguard Worker       if (cur != 0)
338*f6dc9357SAndroid Build Coastguard Worker       {
339*f6dc9357SAndroid Build Coastguard Worker         CanStartNewVol = false;
340*f6dc9357SAndroid Build Coastguard Worker         break;
341*f6dc9357SAndroid Build Coastguard Worker       }
342*f6dc9357SAndroid Build Coastguard Worker       if (result != S_OK)
343*f6dc9357SAndroid Build Coastguard Worker         break;
344*f6dc9357SAndroid Build Coastguard Worker     }
345*f6dc9357SAndroid Build Coastguard Worker 
346*f6dc9357SAndroid Build Coastguard Worker     if (   !IsMultiVol
347*f6dc9357SAndroid Build Coastguard Worker         || !CanStartNewVol
348*f6dc9357SAndroid Build Coastguard Worker         || Vols.StreamIndex < 0
349*f6dc9357SAndroid Build Coastguard Worker         || (unsigned)Vols.StreamIndex + 1 >= Vols.Streams.Size())
350*f6dc9357SAndroid Build Coastguard Worker       break;
351*f6dc9357SAndroid Build Coastguard Worker 
352*f6dc9357SAndroid Build Coastguard Worker     const CVols::CSubStreamInfo &s = Vols.Streams[(unsigned)Vols.StreamIndex + 1];
353*f6dc9357SAndroid Build Coastguard Worker     if (!s.Stream)
354*f6dc9357SAndroid Build Coastguard Worker       break;
355*f6dc9357SAndroid Build Coastguard Worker     result = s.SeekToStart();
356*f6dc9357SAndroid Build Coastguard Worker     if (result != S_OK)
357*f6dc9357SAndroid Build Coastguard Worker       break;
358*f6dc9357SAndroid Build Coastguard Worker     Vols.StreamIndex++;
359*f6dc9357SAndroid Build Coastguard Worker     _streamPos = 0;
360*f6dc9357SAndroid Build Coastguard Worker     // Vols.NeedSeek = false;
361*f6dc9357SAndroid Build Coastguard Worker 
362*f6dc9357SAndroid Build Coastguard Worker     Stream = s.Stream;
363*f6dc9357SAndroid Build Coastguard Worker   }
364*f6dc9357SAndroid Build Coastguard Worker 
365*f6dc9357SAndroid Build Coastguard Worker   return result;
366*f6dc9357SAndroid Build Coastguard Worker }
367*f6dc9357SAndroid Build Coastguard Worker 
368*f6dc9357SAndroid Build Coastguard Worker 
ReadFromCache_FALSE(Byte * data,unsigned size)369*f6dc9357SAndroid Build Coastguard Worker HRESULT CInArchive::ReadFromCache_FALSE(Byte *data, unsigned size)
370*f6dc9357SAndroid Build Coastguard Worker {
371*f6dc9357SAndroid Build Coastguard Worker   unsigned processed;
372*f6dc9357SAndroid Build Coastguard Worker   HRESULT res = ReadFromCache(data, size, processed);
373*f6dc9357SAndroid Build Coastguard Worker   if (res == S_OK && size != processed)
374*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
375*f6dc9357SAndroid Build Coastguard Worker   return res;
376*f6dc9357SAndroid Build Coastguard Worker }
377*f6dc9357SAndroid Build Coastguard Worker 
378*f6dc9357SAndroid Build Coastguard Worker 
CheckDosTime(UInt32 dosTime)379*f6dc9357SAndroid Build Coastguard Worker static bool CheckDosTime(UInt32 dosTime)
380*f6dc9357SAndroid Build Coastguard Worker {
381*f6dc9357SAndroid Build Coastguard Worker   if (dosTime == 0)
382*f6dc9357SAndroid Build Coastguard Worker     return true;
383*f6dc9357SAndroid Build Coastguard Worker   unsigned month = (dosTime >> 21) & 0xF;
384*f6dc9357SAndroid Build Coastguard Worker   unsigned day = (dosTime >> 16) & 0x1F;
385*f6dc9357SAndroid Build Coastguard Worker   unsigned hour = (dosTime >> 11) & 0x1F;
386*f6dc9357SAndroid Build Coastguard Worker   unsigned min = (dosTime >> 5) & 0x3F;
387*f6dc9357SAndroid Build Coastguard Worker   unsigned sec = (dosTime & 0x1F) * 2;
388*f6dc9357SAndroid Build Coastguard Worker   if (month < 1 || month > 12 || day < 1 || day > 31 || hour > 23 || min > 59 || sec > 59)
389*f6dc9357SAndroid Build Coastguard Worker     return false;
390*f6dc9357SAndroid Build Coastguard Worker   return true;
391*f6dc9357SAndroid Build Coastguard Worker }
392*f6dc9357SAndroid Build Coastguard Worker 
IsArc_Zip(const Byte * p,size_t size)393*f6dc9357SAndroid Build Coastguard Worker API_FUNC_IsArc IsArc_Zip(const Byte *p, size_t size)
394*f6dc9357SAndroid Build Coastguard Worker {
395*f6dc9357SAndroid Build Coastguard Worker   if (size < 8)
396*f6dc9357SAndroid Build Coastguard Worker     return k_IsArc_Res_NEED_MORE;
397*f6dc9357SAndroid Build Coastguard Worker   if (p[0] != 'P')
398*f6dc9357SAndroid Build Coastguard Worker     return k_IsArc_Res_NO;
399*f6dc9357SAndroid Build Coastguard Worker 
400*f6dc9357SAndroid Build Coastguard Worker   UInt32 sig = Get32(p);
401*f6dc9357SAndroid Build Coastguard Worker 
402*f6dc9357SAndroid Build Coastguard Worker   if (sig == NSignature::kNoSpan || sig == NSignature::kSpan)
403*f6dc9357SAndroid Build Coastguard Worker   {
404*f6dc9357SAndroid Build Coastguard Worker     p += 4;
405*f6dc9357SAndroid Build Coastguard Worker     size -= 4;
406*f6dc9357SAndroid Build Coastguard Worker   }
407*f6dc9357SAndroid Build Coastguard Worker 
408*f6dc9357SAndroid Build Coastguard Worker   sig = Get32(p);
409*f6dc9357SAndroid Build Coastguard Worker 
410*f6dc9357SAndroid Build Coastguard Worker   if (sig == NSignature::kEcd64)
411*f6dc9357SAndroid Build Coastguard Worker   {
412*f6dc9357SAndroid Build Coastguard Worker     if (size < kEcd64_FullSize)
413*f6dc9357SAndroid Build Coastguard Worker       return k_IsArc_Res_NEED_MORE;
414*f6dc9357SAndroid Build Coastguard Worker 
415*f6dc9357SAndroid Build Coastguard Worker     const UInt64 recordSize = Get64(p + 4);
416*f6dc9357SAndroid Build Coastguard Worker     if (   recordSize < kEcd64_MainSize
417*f6dc9357SAndroid Build Coastguard Worker         || recordSize > kEcd64_MainSize + (1 << 20))
418*f6dc9357SAndroid Build Coastguard Worker       return k_IsArc_Res_NO;
419*f6dc9357SAndroid Build Coastguard Worker     CCdInfo cdInfo;
420*f6dc9357SAndroid Build Coastguard Worker     cdInfo.ParseEcd64e(p + 12);
421*f6dc9357SAndroid Build Coastguard Worker     if (!cdInfo.IsEmptyArc())
422*f6dc9357SAndroid Build Coastguard Worker       return k_IsArc_Res_NO;
423*f6dc9357SAndroid Build Coastguard Worker     return k_IsArc_Res_YES; // k_IsArc_Res_YES_2;
424*f6dc9357SAndroid Build Coastguard Worker   }
425*f6dc9357SAndroid Build Coastguard Worker 
426*f6dc9357SAndroid Build Coastguard Worker   if (sig == NSignature::kEcd)
427*f6dc9357SAndroid Build Coastguard Worker   {
428*f6dc9357SAndroid Build Coastguard Worker     if (size < kEcdSize)
429*f6dc9357SAndroid Build Coastguard Worker       return k_IsArc_Res_NEED_MORE;
430*f6dc9357SAndroid Build Coastguard Worker     CEcd ecd;
431*f6dc9357SAndroid Build Coastguard Worker     ecd.Parse(p + 4);
432*f6dc9357SAndroid Build Coastguard Worker     // if (ecd.cdSize != 0)
433*f6dc9357SAndroid Build Coastguard Worker     if (!ecd.IsEmptyArc())
434*f6dc9357SAndroid Build Coastguard Worker       return k_IsArc_Res_NO;
435*f6dc9357SAndroid Build Coastguard Worker     return k_IsArc_Res_YES; // k_IsArc_Res_YES_2;
436*f6dc9357SAndroid Build Coastguard Worker   }
437*f6dc9357SAndroid Build Coastguard Worker 
438*f6dc9357SAndroid Build Coastguard Worker   if (sig != NSignature::kLocalFileHeader)
439*f6dc9357SAndroid Build Coastguard Worker     return k_IsArc_Res_NO;
440*f6dc9357SAndroid Build Coastguard Worker 
441*f6dc9357SAndroid Build Coastguard Worker   if (size < kLocalHeaderSize)
442*f6dc9357SAndroid Build Coastguard Worker     return k_IsArc_Res_NEED_MORE;
443*f6dc9357SAndroid Build Coastguard Worker 
444*f6dc9357SAndroid Build Coastguard Worker   p += 4;
445*f6dc9357SAndroid Build Coastguard Worker 
446*f6dc9357SAndroid Build Coastguard Worker   {
447*f6dc9357SAndroid Build Coastguard Worker     const unsigned kPureHeaderSize = kLocalHeaderSize - 4;
448*f6dc9357SAndroid Build Coastguard Worker     unsigned i;
449*f6dc9357SAndroid Build Coastguard Worker     for (i = 0; i < kPureHeaderSize && p[i] == 0; i++);
450*f6dc9357SAndroid Build Coastguard Worker     if (i == kPureHeaderSize)
451*f6dc9357SAndroid Build Coastguard Worker       return k_IsArc_Res_NEED_MORE;
452*f6dc9357SAndroid Build Coastguard Worker   }
453*f6dc9357SAndroid Build Coastguard Worker 
454*f6dc9357SAndroid Build Coastguard Worker   /*
455*f6dc9357SAndroid Build Coastguard Worker   if (p[0] >= 128) // ExtractVersion.Version;
456*f6dc9357SAndroid Build Coastguard Worker     return k_IsArc_Res_NO;
457*f6dc9357SAndroid Build Coastguard Worker   */
458*f6dc9357SAndroid Build Coastguard Worker 
459*f6dc9357SAndroid Build Coastguard Worker   // ExtractVersion.Version = p[0];
460*f6dc9357SAndroid Build Coastguard Worker   // ExtractVersion.HostOS = p[1];
461*f6dc9357SAndroid Build Coastguard Worker   // Flags = Get16(p + 2);
462*f6dc9357SAndroid Build Coastguard Worker   // Method = Get16(p + 4);
463*f6dc9357SAndroid Build Coastguard Worker   /*
464*f6dc9357SAndroid Build Coastguard Worker   // 9.33: some zip archives contain incorrect value in timestamp. So we don't check it now
465*f6dc9357SAndroid Build Coastguard Worker   UInt32 dosTime = Get32(p + 6);
466*f6dc9357SAndroid Build Coastguard Worker   if (!CheckDosTime(dosTime))
467*f6dc9357SAndroid Build Coastguard Worker     return k_IsArc_Res_NO;
468*f6dc9357SAndroid Build Coastguard Worker   */
469*f6dc9357SAndroid Build Coastguard Worker   // Crc = Get32(p + 10);
470*f6dc9357SAndroid Build Coastguard Worker   // PackSize = Get32(p + 14);
471*f6dc9357SAndroid Build Coastguard Worker   // Size = Get32(p + 18);
472*f6dc9357SAndroid Build Coastguard Worker   const unsigned nameSize = Get16(p + 22);
473*f6dc9357SAndroid Build Coastguard Worker   unsigned extraSize = Get16(p + 24);
474*f6dc9357SAndroid Build Coastguard Worker   const UInt32 extraOffset = kLocalHeaderSize + (UInt32)nameSize;
475*f6dc9357SAndroid Build Coastguard Worker 
476*f6dc9357SAndroid Build Coastguard Worker   /*
477*f6dc9357SAndroid Build Coastguard Worker   // 21.02: fixed. we don't use the following check
478*f6dc9357SAndroid Build Coastguard Worker   if (extraOffset + extraSize > (1 << 16))
479*f6dc9357SAndroid Build Coastguard Worker     return k_IsArc_Res_NO;
480*f6dc9357SAndroid Build Coastguard Worker   */
481*f6dc9357SAndroid Build Coastguard Worker 
482*f6dc9357SAndroid Build Coastguard Worker   p -= 4;
483*f6dc9357SAndroid Build Coastguard Worker 
484*f6dc9357SAndroid Build Coastguard Worker   {
485*f6dc9357SAndroid Build Coastguard Worker     size_t rem = size - kLocalHeaderSize;
486*f6dc9357SAndroid Build Coastguard Worker     if (rem > nameSize)
487*f6dc9357SAndroid Build Coastguard Worker       rem = nameSize;
488*f6dc9357SAndroid Build Coastguard Worker     const Byte *p2 = p + kLocalHeaderSize;
489*f6dc9357SAndroid Build Coastguard Worker     for (size_t i = 0; i < rem; i++)
490*f6dc9357SAndroid Build Coastguard Worker       if (p2[i] == 0)
491*f6dc9357SAndroid Build Coastguard Worker       {
492*f6dc9357SAndroid Build Coastguard Worker         // we support some "bad" zip archives that contain zeros after name
493*f6dc9357SAndroid Build Coastguard Worker         for (size_t k = i + 1; k < rem; k++)
494*f6dc9357SAndroid Build Coastguard Worker           if (p2[k] != 0)
495*f6dc9357SAndroid Build Coastguard Worker             return k_IsArc_Res_NO;
496*f6dc9357SAndroid Build Coastguard Worker         break;
497*f6dc9357SAndroid Build Coastguard Worker         /*
498*f6dc9357SAndroid Build Coastguard Worker         if (i != nameSize - 1)
499*f6dc9357SAndroid Build Coastguard Worker           return k_IsArc_Res_NO;
500*f6dc9357SAndroid Build Coastguard Worker         */
501*f6dc9357SAndroid Build Coastguard Worker       }
502*f6dc9357SAndroid Build Coastguard Worker   }
503*f6dc9357SAndroid Build Coastguard Worker 
504*f6dc9357SAndroid Build Coastguard Worker   if (size < extraOffset)
505*f6dc9357SAndroid Build Coastguard Worker     return k_IsArc_Res_NEED_MORE;
506*f6dc9357SAndroid Build Coastguard Worker 
507*f6dc9357SAndroid Build Coastguard Worker   if (extraSize > 0)
508*f6dc9357SAndroid Build Coastguard Worker   {
509*f6dc9357SAndroid Build Coastguard Worker     p += extraOffset;
510*f6dc9357SAndroid Build Coastguard Worker     size -= extraOffset;
511*f6dc9357SAndroid Build Coastguard Worker     while (extraSize != 0)
512*f6dc9357SAndroid Build Coastguard Worker     {
513*f6dc9357SAndroid Build Coastguard Worker       if (extraSize < 4)
514*f6dc9357SAndroid Build Coastguard Worker       {
515*f6dc9357SAndroid Build Coastguard Worker         // 7-Zip before 9.31 created incorrect WzAES Extra in folder's local headers.
516*f6dc9357SAndroid Build Coastguard Worker         // so we return k_IsArc_Res_YES to support such archives.
517*f6dc9357SAndroid Build Coastguard Worker         // return k_IsArc_Res_NO; // do we need to support such extra ?
518*f6dc9357SAndroid Build Coastguard Worker         return k_IsArc_Res_YES;
519*f6dc9357SAndroid Build Coastguard Worker       }
520*f6dc9357SAndroid Build Coastguard Worker       if (size < 4)
521*f6dc9357SAndroid Build Coastguard Worker         return k_IsArc_Res_NEED_MORE;
522*f6dc9357SAndroid Build Coastguard Worker       unsigned dataSize = Get16(p + 2);
523*f6dc9357SAndroid Build Coastguard Worker       size -= 4;
524*f6dc9357SAndroid Build Coastguard Worker       extraSize -= 4;
525*f6dc9357SAndroid Build Coastguard Worker       p += 4;
526*f6dc9357SAndroid Build Coastguard Worker       if (dataSize > extraSize)
527*f6dc9357SAndroid Build Coastguard Worker       {
528*f6dc9357SAndroid Build Coastguard Worker         // It can be error on header.
529*f6dc9357SAndroid Build Coastguard Worker         // We want to support such rare case bad archives.
530*f6dc9357SAndroid Build Coastguard Worker         // We use additional checks to reduce false-positive probability.
531*f6dc9357SAndroid Build Coastguard Worker         if (nameSize == 0
532*f6dc9357SAndroid Build Coastguard Worker             || nameSize > (1 << 9)
533*f6dc9357SAndroid Build Coastguard Worker             || extraSize > (1 << 9))
534*f6dc9357SAndroid Build Coastguard Worker           return k_IsArc_Res_NO;
535*f6dc9357SAndroid Build Coastguard Worker         return k_IsArc_Res_YES;
536*f6dc9357SAndroid Build Coastguard Worker       }
537*f6dc9357SAndroid Build Coastguard Worker       if (dataSize > size)
538*f6dc9357SAndroid Build Coastguard Worker         return k_IsArc_Res_NEED_MORE;
539*f6dc9357SAndroid Build Coastguard Worker       size -= dataSize;
540*f6dc9357SAndroid Build Coastguard Worker       extraSize -= dataSize;
541*f6dc9357SAndroid Build Coastguard Worker       p += dataSize;
542*f6dc9357SAndroid Build Coastguard Worker     }
543*f6dc9357SAndroid Build Coastguard Worker   }
544*f6dc9357SAndroid Build Coastguard Worker 
545*f6dc9357SAndroid Build Coastguard Worker   return k_IsArc_Res_YES;
546*f6dc9357SAndroid Build Coastguard Worker }
547*f6dc9357SAndroid Build Coastguard Worker 
IsArc_Zip_2(const Byte * p,size_t size,bool isFinal)548*f6dc9357SAndroid Build Coastguard Worker static UInt32 IsArc_Zip_2(const Byte *p, size_t size, bool isFinal)
549*f6dc9357SAndroid Build Coastguard Worker {
550*f6dc9357SAndroid Build Coastguard Worker   UInt32 res = IsArc_Zip(p, size);
551*f6dc9357SAndroid Build Coastguard Worker   if (res == k_IsArc_Res_NEED_MORE && isFinal)
552*f6dc9357SAndroid Build Coastguard Worker     return k_IsArc_Res_NO;
553*f6dc9357SAndroid Build Coastguard Worker   return res;
554*f6dc9357SAndroid Build Coastguard Worker }
555*f6dc9357SAndroid Build Coastguard Worker 
556*f6dc9357SAndroid Build Coastguard Worker 
557*f6dc9357SAndroid Build Coastguard Worker 
558*f6dc9357SAndroid Build Coastguard Worker /* FindPK_4() is allowed to access data up to and including &limit[3].
559*f6dc9357SAndroid Build Coastguard Worker    limit[4] access is not allowed.
560*f6dc9357SAndroid Build Coastguard Worker   return:
561*f6dc9357SAndroid Build Coastguard Worker     (return_ptr <  limit) : "PK" was found at (return_ptr)
562*f6dc9357SAndroid Build Coastguard Worker     (return_ptr >= limit) : limit was reached or crossed. So no "PK" found before limit
563*f6dc9357SAndroid Build Coastguard Worker */
564*f6dc9357SAndroid Build Coastguard Worker Z7_NO_INLINE
FindPK_4(const Byte * p,const Byte * limit)565*f6dc9357SAndroid Build Coastguard Worker static const Byte *FindPK_4(const Byte *p, const Byte *limit)
566*f6dc9357SAndroid Build Coastguard Worker {
567*f6dc9357SAndroid Build Coastguard Worker   for (;;)
568*f6dc9357SAndroid Build Coastguard Worker   {
569*f6dc9357SAndroid Build Coastguard Worker     for (;;)
570*f6dc9357SAndroid Build Coastguard Worker     {
571*f6dc9357SAndroid Build Coastguard Worker       if (p >= limit)
572*f6dc9357SAndroid Build Coastguard Worker         return limit;
573*f6dc9357SAndroid Build Coastguard Worker       Byte b = p[1];
574*f6dc9357SAndroid Build Coastguard Worker       if (b == 0x4B) { if (p[0] == 0x50) { return p;     } p += 1; break; }
575*f6dc9357SAndroid Build Coastguard Worker       if (b == 0x50) { if (p[2] == 0x4B) { return p + 1; } p += 2; break; }
576*f6dc9357SAndroid Build Coastguard Worker       b = p[3];
577*f6dc9357SAndroid Build Coastguard Worker       p += 4;
578*f6dc9357SAndroid Build Coastguard Worker       if (b == 0x4B) { if (p[-2]== 0x50) { return p - 2; } p -= 1; break; }
579*f6dc9357SAndroid Build Coastguard Worker       if (b == 0x50) { if (p[0] == 0x4B) { return p - 1; }         break; }
580*f6dc9357SAndroid Build Coastguard Worker     }
581*f6dc9357SAndroid Build Coastguard Worker   }
582*f6dc9357SAndroid Build Coastguard Worker   /*
583*f6dc9357SAndroid Build Coastguard Worker   for (;;)
584*f6dc9357SAndroid Build Coastguard Worker   {
585*f6dc9357SAndroid Build Coastguard Worker     for (;;)
586*f6dc9357SAndroid Build Coastguard Worker     {
587*f6dc9357SAndroid Build Coastguard Worker       if (p >= limit)
588*f6dc9357SAndroid Build Coastguard Worker         return limit;
589*f6dc9357SAndroid Build Coastguard Worker       if (*p++ == 0x50) break;
590*f6dc9357SAndroid Build Coastguard Worker       if (*p++ == 0x50) break;
591*f6dc9357SAndroid Build Coastguard Worker       if (*p++ == 0x50) break;
592*f6dc9357SAndroid Build Coastguard Worker       if (*p++ == 0x50) break;
593*f6dc9357SAndroid Build Coastguard Worker     }
594*f6dc9357SAndroid Build Coastguard Worker     if (*p == 0x4B)
595*f6dc9357SAndroid Build Coastguard Worker       return p - 1;
596*f6dc9357SAndroid Build Coastguard Worker   }
597*f6dc9357SAndroid Build Coastguard Worker   */
598*f6dc9357SAndroid Build Coastguard Worker }
599*f6dc9357SAndroid Build Coastguard Worker 
600*f6dc9357SAndroid Build Coastguard Worker 
601*f6dc9357SAndroid Build Coastguard Worker /*
602*f6dc9357SAndroid Build Coastguard Worker ---------- FindMarker ----------
603*f6dc9357SAndroid Build Coastguard Worker returns:
604*f6dc9357SAndroid Build Coastguard Worker   S_OK:
605*f6dc9357SAndroid Build Coastguard Worker     ArcInfo.MarkerVolIndex : volume of marker
606*f6dc9357SAndroid Build Coastguard Worker     ArcInfo.MarkerPos   : Pos of first signature
607*f6dc9357SAndroid Build Coastguard Worker     ArcInfo.MarkerPos2  : Pos of main signature (local item signature in most cases)
608*f6dc9357SAndroid Build Coastguard Worker     _streamPos          : stream pos
609*f6dc9357SAndroid Build Coastguard Worker     _cnt                : The number of virtal Bytes after start of search to offset after signature
610*f6dc9357SAndroid Build Coastguard Worker     _signature          : main signature
611*f6dc9357SAndroid Build Coastguard Worker 
612*f6dc9357SAndroid Build Coastguard Worker   S_FALSE: can't find marker, or there is some non-zip data after marker
613*f6dc9357SAndroid Build Coastguard Worker 
614*f6dc9357SAndroid Build Coastguard Worker   Error code: stream reading error.
615*f6dc9357SAndroid Build Coastguard Worker */
616*f6dc9357SAndroid Build Coastguard Worker 
FindMarker(const UInt64 * searchLimit)617*f6dc9357SAndroid Build Coastguard Worker HRESULT CInArchive::FindMarker(const UInt64 *searchLimit)
618*f6dc9357SAndroid Build Coastguard Worker {
619*f6dc9357SAndroid Build Coastguard Worker   ArcInfo.MarkerPos = GetVirtStreamPos();
620*f6dc9357SAndroid Build Coastguard Worker   ArcInfo.MarkerPos2 = ArcInfo.MarkerPos;
621*f6dc9357SAndroid Build Coastguard Worker   ArcInfo.MarkerVolIndex = Vols.StreamIndex;
622*f6dc9357SAndroid Build Coastguard Worker 
623*f6dc9357SAndroid Build Coastguard Worker   _cnt = 0;
624*f6dc9357SAndroid Build Coastguard Worker 
625*f6dc9357SAndroid Build Coastguard Worker   CanStartNewVol = false;
626*f6dc9357SAndroid Build Coastguard Worker 
627*f6dc9357SAndroid Build Coastguard Worker   if (searchLimit && *searchLimit == 0)
628*f6dc9357SAndroid Build Coastguard Worker   {
629*f6dc9357SAndroid Build Coastguard Worker     Byte startBuf[kMarkerSize];
630*f6dc9357SAndroid Build Coastguard Worker     RINOK(ReadFromCache_FALSE(startBuf, kMarkerSize))
631*f6dc9357SAndroid Build Coastguard Worker 
632*f6dc9357SAndroid Build Coastguard Worker     UInt32 marker = Get32(startBuf);
633*f6dc9357SAndroid Build Coastguard Worker     _signature = marker;
634*f6dc9357SAndroid Build Coastguard Worker 
635*f6dc9357SAndroid Build Coastguard Worker     if (   marker == NSignature::kNoSpan
636*f6dc9357SAndroid Build Coastguard Worker         || marker == NSignature::kSpan)
637*f6dc9357SAndroid Build Coastguard Worker     {
638*f6dc9357SAndroid Build Coastguard Worker       RINOK(ReadFromCache_FALSE(startBuf, kMarkerSize))
639*f6dc9357SAndroid Build Coastguard Worker       _signature = Get32(startBuf);
640*f6dc9357SAndroid Build Coastguard Worker     }
641*f6dc9357SAndroid Build Coastguard Worker 
642*f6dc9357SAndroid Build Coastguard Worker     if (   _signature != NSignature::kEcd
643*f6dc9357SAndroid Build Coastguard Worker         && _signature != NSignature::kEcd64
644*f6dc9357SAndroid Build Coastguard Worker         && _signature != NSignature::kLocalFileHeader)
645*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
646*f6dc9357SAndroid Build Coastguard Worker 
647*f6dc9357SAndroid Build Coastguard Worker     ArcInfo.MarkerPos2 = GetVirtStreamPos() - 4;
648*f6dc9357SAndroid Build Coastguard Worker     ArcInfo.IsSpanMode = (marker == NSignature::kSpan);
649*f6dc9357SAndroid Build Coastguard Worker 
650*f6dc9357SAndroid Build Coastguard Worker     // we use weak test in case of (*searchLimit == 0)
651*f6dc9357SAndroid Build Coastguard Worker     // since error will be detected later in Open function
652*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
653*f6dc9357SAndroid Build Coastguard Worker   }
654*f6dc9357SAndroid Build Coastguard Worker 
655*f6dc9357SAndroid Build Coastguard Worker   // zip specification: (_zip_header_size < (1 << 16))
656*f6dc9357SAndroid Build Coastguard Worker   // so we need such size to check header
657*f6dc9357SAndroid Build Coastguard Worker   const size_t kCheckSize = (size_t)1 << 16;
658*f6dc9357SAndroid Build Coastguard Worker   const size_t kBufSize   = (size_t)1 << 17; // (kBufSize must be > kCheckSize)
659*f6dc9357SAndroid Build Coastguard Worker 
660*f6dc9357SAndroid Build Coastguard Worker   RINOK(AllocateBuffer(kBufSize))
661*f6dc9357SAndroid Build Coastguard Worker 
662*f6dc9357SAndroid Build Coastguard Worker   _inBufMode = true;
663*f6dc9357SAndroid Build Coastguard Worker 
664*f6dc9357SAndroid Build Coastguard Worker   UInt64 progressPrev = 0;
665*f6dc9357SAndroid Build Coastguard Worker 
666*f6dc9357SAndroid Build Coastguard Worker   for (;;)
667*f6dc9357SAndroid Build Coastguard Worker   {
668*f6dc9357SAndroid Build Coastguard Worker     RINOK(LookAhead(kBufSize))
669*f6dc9357SAndroid Build Coastguard Worker 
670*f6dc9357SAndroid Build Coastguard Worker     const size_t avail = GetAvail();
671*f6dc9357SAndroid Build Coastguard Worker 
672*f6dc9357SAndroid Build Coastguard Worker     size_t limitPos;
673*f6dc9357SAndroid Build Coastguard Worker     // (avail > kBufSize) is possible, if (Buffer.Size() > kBufSize)
674*f6dc9357SAndroid Build Coastguard Worker     const bool isFinished = (avail < kBufSize);
675*f6dc9357SAndroid Build Coastguard Worker     if (isFinished)
676*f6dc9357SAndroid Build Coastguard Worker     {
677*f6dc9357SAndroid Build Coastguard Worker       const unsigned kMinAllowed = 4;
678*f6dc9357SAndroid Build Coastguard Worker       if (avail <= kMinAllowed)
679*f6dc9357SAndroid Build Coastguard Worker       {
680*f6dc9357SAndroid Build Coastguard Worker         if (   !IsMultiVol
681*f6dc9357SAndroid Build Coastguard Worker             || Vols.StreamIndex < 0
682*f6dc9357SAndroid Build Coastguard Worker             || (unsigned)Vols.StreamIndex + 1 >= Vols.Streams.Size())
683*f6dc9357SAndroid Build Coastguard Worker           break;
684*f6dc9357SAndroid Build Coastguard Worker 
685*f6dc9357SAndroid Build Coastguard Worker         SkipLookahed(avail);
686*f6dc9357SAndroid Build Coastguard Worker 
687*f6dc9357SAndroid Build Coastguard Worker         const CVols::CSubStreamInfo &s = Vols.Streams[(unsigned)Vols.StreamIndex + 1];
688*f6dc9357SAndroid Build Coastguard Worker         if (!s.Stream)
689*f6dc9357SAndroid Build Coastguard Worker           break;
690*f6dc9357SAndroid Build Coastguard Worker 
691*f6dc9357SAndroid Build Coastguard Worker         RINOK(s.SeekToStart())
692*f6dc9357SAndroid Build Coastguard Worker 
693*f6dc9357SAndroid Build Coastguard Worker         InitBuf();
694*f6dc9357SAndroid Build Coastguard Worker         Vols.StreamIndex++;
695*f6dc9357SAndroid Build Coastguard Worker         _streamPos = 0;
696*f6dc9357SAndroid Build Coastguard Worker         Stream = s.Stream;
697*f6dc9357SAndroid Build Coastguard Worker         continue;
698*f6dc9357SAndroid Build Coastguard Worker       }
699*f6dc9357SAndroid Build Coastguard Worker       limitPos = avail - kMinAllowed;
700*f6dc9357SAndroid Build Coastguard Worker     }
701*f6dc9357SAndroid Build Coastguard Worker     else
702*f6dc9357SAndroid Build Coastguard Worker       limitPos = (avail - kCheckSize);
703*f6dc9357SAndroid Build Coastguard Worker 
704*f6dc9357SAndroid Build Coastguard Worker     // we don't check at (limitPos) for good fast aligned operations
705*f6dc9357SAndroid Build Coastguard Worker 
706*f6dc9357SAndroid Build Coastguard Worker     if (searchLimit)
707*f6dc9357SAndroid Build Coastguard Worker     {
708*f6dc9357SAndroid Build Coastguard Worker       if (_cnt > *searchLimit)
709*f6dc9357SAndroid Build Coastguard Worker         break;
710*f6dc9357SAndroid Build Coastguard Worker       UInt64 rem = *searchLimit - _cnt;
711*f6dc9357SAndroid Build Coastguard Worker       if (limitPos > rem)
712*f6dc9357SAndroid Build Coastguard Worker         limitPos = (size_t)rem + 1;
713*f6dc9357SAndroid Build Coastguard Worker     }
714*f6dc9357SAndroid Build Coastguard Worker 
715*f6dc9357SAndroid Build Coastguard Worker     if (limitPos == 0)
716*f6dc9357SAndroid Build Coastguard Worker       break;
717*f6dc9357SAndroid Build Coastguard Worker 
718*f6dc9357SAndroid Build Coastguard Worker     const Byte * const pStart = Buffer + _bufPos;
719*f6dc9357SAndroid Build Coastguard Worker     const Byte * p = pStart;
720*f6dc9357SAndroid Build Coastguard Worker     const Byte * const limit = pStart + limitPos;
721*f6dc9357SAndroid Build Coastguard Worker 
722*f6dc9357SAndroid Build Coastguard Worker     for (;; p++)
723*f6dc9357SAndroid Build Coastguard Worker     {
724*f6dc9357SAndroid Build Coastguard Worker       p = FindPK_4(p, limit);
725*f6dc9357SAndroid Build Coastguard Worker       if (p >= limit)
726*f6dc9357SAndroid Build Coastguard Worker         break;
727*f6dc9357SAndroid Build Coastguard Worker       size_t rem = (size_t)(pStart + avail - p);
728*f6dc9357SAndroid Build Coastguard Worker       /* 22.02 : we limit check size with kCheckSize to be consistent for
729*f6dc9357SAndroid Build Coastguard Worker          any different combination of _bufPos in Buffer and size of Buffer. */
730*f6dc9357SAndroid Build Coastguard Worker       if (rem > kCheckSize)
731*f6dc9357SAndroid Build Coastguard Worker         rem = kCheckSize;
732*f6dc9357SAndroid Build Coastguard Worker       const UInt32 res = IsArc_Zip_2(p, rem, isFinished);
733*f6dc9357SAndroid Build Coastguard Worker       if (res != k_IsArc_Res_NO)
734*f6dc9357SAndroid Build Coastguard Worker       {
735*f6dc9357SAndroid Build Coastguard Worker         if (rem < kMarkerSize)
736*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
737*f6dc9357SAndroid Build Coastguard Worker         _signature = Get32(p);
738*f6dc9357SAndroid Build Coastguard Worker         SkipLookahed((size_t)(p - pStart));
739*f6dc9357SAndroid Build Coastguard Worker         ArcInfo.MarkerVolIndex = Vols.StreamIndex;
740*f6dc9357SAndroid Build Coastguard Worker         ArcInfo.MarkerPos = GetVirtStreamPos();
741*f6dc9357SAndroid Build Coastguard Worker         ArcInfo.MarkerPos2 = ArcInfo.MarkerPos;
742*f6dc9357SAndroid Build Coastguard Worker         SkipLookahed(4);
743*f6dc9357SAndroid Build Coastguard Worker         if (   _signature == NSignature::kNoSpan
744*f6dc9357SAndroid Build Coastguard Worker             || _signature == NSignature::kSpan)
745*f6dc9357SAndroid Build Coastguard Worker         {
746*f6dc9357SAndroid Build Coastguard Worker           if (rem < kMarkerSize * 2)
747*f6dc9357SAndroid Build Coastguard Worker             return S_FALSE;
748*f6dc9357SAndroid Build Coastguard Worker           ArcInfo.IsSpanMode = (_signature == NSignature::kSpan);
749*f6dc9357SAndroid Build Coastguard Worker           _signature = Get32(p + 4);
750*f6dc9357SAndroid Build Coastguard Worker           ArcInfo.MarkerPos2 += 4;
751*f6dc9357SAndroid Build Coastguard Worker           SkipLookahed(4);
752*f6dc9357SAndroid Build Coastguard Worker         }
753*f6dc9357SAndroid Build Coastguard Worker         return S_OK;
754*f6dc9357SAndroid Build Coastguard Worker       }
755*f6dc9357SAndroid Build Coastguard Worker     }
756*f6dc9357SAndroid Build Coastguard Worker 
757*f6dc9357SAndroid Build Coastguard Worker     if (!IsMultiVol && isFinished)
758*f6dc9357SAndroid Build Coastguard Worker       break;
759*f6dc9357SAndroid Build Coastguard Worker 
760*f6dc9357SAndroid Build Coastguard Worker     SkipLookahed((size_t)(p - pStart));
761*f6dc9357SAndroid Build Coastguard Worker 
762*f6dc9357SAndroid Build Coastguard Worker     if (Callback && (_cnt - progressPrev) >= ((UInt32)1 << 23))
763*f6dc9357SAndroid Build Coastguard Worker     {
764*f6dc9357SAndroid Build Coastguard Worker       progressPrev = _cnt;
765*f6dc9357SAndroid Build Coastguard Worker       // const UInt64 numFiles64 = 0;
766*f6dc9357SAndroid Build Coastguard Worker       RINOK(Callback->SetCompleted(NULL, &_cnt))
767*f6dc9357SAndroid Build Coastguard Worker     }
768*f6dc9357SAndroid Build Coastguard Worker   }
769*f6dc9357SAndroid Build Coastguard Worker 
770*f6dc9357SAndroid Build Coastguard Worker   return S_FALSE;
771*f6dc9357SAndroid Build Coastguard Worker }
772*f6dc9357SAndroid Build Coastguard Worker 
773*f6dc9357SAndroid Build Coastguard Worker 
774*f6dc9357SAndroid Build Coastguard Worker /*
775*f6dc9357SAndroid Build Coastguard Worker ---------- IncreaseRealPosition ----------
776*f6dc9357SAndroid Build Coastguard Worker moves virtual offset in virtual stream.
777*f6dc9357SAndroid Build Coastguard Worker changing to new volumes is allowed
778*f6dc9357SAndroid Build Coastguard Worker */
779*f6dc9357SAndroid Build Coastguard Worker 
IncreaseRealPosition(UInt64 offset,bool & isFinished)780*f6dc9357SAndroid Build Coastguard Worker HRESULT CInArchive::IncreaseRealPosition(UInt64 offset, bool &isFinished)
781*f6dc9357SAndroid Build Coastguard Worker {
782*f6dc9357SAndroid Build Coastguard Worker   isFinished = false;
783*f6dc9357SAndroid Build Coastguard Worker 
784*f6dc9357SAndroid Build Coastguard Worker   for (;;)
785*f6dc9357SAndroid Build Coastguard Worker   {
786*f6dc9357SAndroid Build Coastguard Worker     const size_t avail = GetAvail();
787*f6dc9357SAndroid Build Coastguard Worker 
788*f6dc9357SAndroid Build Coastguard Worker     if (offset <= avail)
789*f6dc9357SAndroid Build Coastguard Worker     {
790*f6dc9357SAndroid Build Coastguard Worker       _bufPos += (size_t)offset;
791*f6dc9357SAndroid Build Coastguard Worker       _cnt += offset;
792*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
793*f6dc9357SAndroid Build Coastguard Worker     }
794*f6dc9357SAndroid Build Coastguard Worker 
795*f6dc9357SAndroid Build Coastguard Worker     _cnt += avail;
796*f6dc9357SAndroid Build Coastguard Worker     offset -= avail;
797*f6dc9357SAndroid Build Coastguard Worker 
798*f6dc9357SAndroid Build Coastguard Worker     _bufCached = 0;
799*f6dc9357SAndroid Build Coastguard Worker     _bufPos = 0;
800*f6dc9357SAndroid Build Coastguard Worker 
801*f6dc9357SAndroid Build Coastguard Worker     if (!_inBufMode)
802*f6dc9357SAndroid Build Coastguard Worker       break;
803*f6dc9357SAndroid Build Coastguard Worker 
804*f6dc9357SAndroid Build Coastguard Worker     CanStartNewVol = true;
805*f6dc9357SAndroid Build Coastguard Worker     LookAhead(1);
806*f6dc9357SAndroid Build Coastguard Worker 
807*f6dc9357SAndroid Build Coastguard Worker     if (GetAvail() == 0)
808*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
809*f6dc9357SAndroid Build Coastguard Worker   }
810*f6dc9357SAndroid Build Coastguard Worker 
811*f6dc9357SAndroid Build Coastguard Worker   // cache is empty
812*f6dc9357SAndroid Build Coastguard Worker 
813*f6dc9357SAndroid Build Coastguard Worker   if (!IsMultiVol)
814*f6dc9357SAndroid Build Coastguard Worker   {
815*f6dc9357SAndroid Build Coastguard Worker     _cnt += offset;
816*f6dc9357SAndroid Build Coastguard Worker     return Stream->Seek((Int64)offset, STREAM_SEEK_CUR, &_streamPos);
817*f6dc9357SAndroid Build Coastguard Worker   }
818*f6dc9357SAndroid Build Coastguard Worker 
819*f6dc9357SAndroid Build Coastguard Worker   for (;;)
820*f6dc9357SAndroid Build Coastguard Worker   {
821*f6dc9357SAndroid Build Coastguard Worker     if (offset == 0)
822*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
823*f6dc9357SAndroid Build Coastguard Worker 
824*f6dc9357SAndroid Build Coastguard Worker     if (Vols.StreamIndex < 0)
825*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
826*f6dc9357SAndroid Build Coastguard Worker     if ((unsigned)Vols.StreamIndex >= Vols.Streams.Size())
827*f6dc9357SAndroid Build Coastguard Worker     {
828*f6dc9357SAndroid Build Coastguard Worker       isFinished = true;
829*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
830*f6dc9357SAndroid Build Coastguard Worker     }
831*f6dc9357SAndroid Build Coastguard Worker     {
832*f6dc9357SAndroid Build Coastguard Worker       const CVols::CSubStreamInfo &s = Vols.Streams[(unsigned)Vols.StreamIndex];
833*f6dc9357SAndroid Build Coastguard Worker       if (!s.Stream)
834*f6dc9357SAndroid Build Coastguard Worker       {
835*f6dc9357SAndroid Build Coastguard Worker         isFinished = true;
836*f6dc9357SAndroid Build Coastguard Worker         return S_OK;
837*f6dc9357SAndroid Build Coastguard Worker       }
838*f6dc9357SAndroid Build Coastguard Worker       if (_streamPos > s.Size)
839*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
840*f6dc9357SAndroid Build Coastguard Worker       const UInt64 rem = s.Size - _streamPos;
841*f6dc9357SAndroid Build Coastguard Worker       if ((UInt64)offset <= rem)
842*f6dc9357SAndroid Build Coastguard Worker       {
843*f6dc9357SAndroid Build Coastguard Worker         _cnt += offset;
844*f6dc9357SAndroid Build Coastguard Worker         return Stream->Seek((Int64)offset, STREAM_SEEK_CUR, &_streamPos);
845*f6dc9357SAndroid Build Coastguard Worker       }
846*f6dc9357SAndroid Build Coastguard Worker       RINOK(Seek_SavePos(s.Size))
847*f6dc9357SAndroid Build Coastguard Worker       offset -= rem;
848*f6dc9357SAndroid Build Coastguard Worker       _cnt += rem;
849*f6dc9357SAndroid Build Coastguard Worker     }
850*f6dc9357SAndroid Build Coastguard Worker 
851*f6dc9357SAndroid Build Coastguard Worker     Stream = NULL;
852*f6dc9357SAndroid Build Coastguard Worker     _streamPos = 0;
853*f6dc9357SAndroid Build Coastguard Worker     Vols.StreamIndex++;
854*f6dc9357SAndroid Build Coastguard Worker     if ((unsigned)Vols.StreamIndex >= Vols.Streams.Size())
855*f6dc9357SAndroid Build Coastguard Worker     {
856*f6dc9357SAndroid Build Coastguard Worker       isFinished = true;
857*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
858*f6dc9357SAndroid Build Coastguard Worker     }
859*f6dc9357SAndroid Build Coastguard Worker     const CVols::CSubStreamInfo &s2 = Vols.Streams[(unsigned)Vols.StreamIndex];
860*f6dc9357SAndroid Build Coastguard Worker     if (!s2.Stream)
861*f6dc9357SAndroid Build Coastguard Worker     {
862*f6dc9357SAndroid Build Coastguard Worker       isFinished = true;
863*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
864*f6dc9357SAndroid Build Coastguard Worker     }
865*f6dc9357SAndroid Build Coastguard Worker     Stream = s2.Stream;
866*f6dc9357SAndroid Build Coastguard Worker     RINOK(Seek_SavePos(0))
867*f6dc9357SAndroid Build Coastguard Worker   }
868*f6dc9357SAndroid Build Coastguard Worker }
869*f6dc9357SAndroid Build Coastguard Worker 
870*f6dc9357SAndroid Build Coastguard Worker 
871*f6dc9357SAndroid Build Coastguard Worker 
872*f6dc9357SAndroid Build Coastguard Worker /*
873*f6dc9357SAndroid Build Coastguard Worker ---------- LookAhead ----------
874*f6dc9357SAndroid Build Coastguard Worker Reads data to buffer, if required.
875*f6dc9357SAndroid Build Coastguard Worker 
876*f6dc9357SAndroid Build Coastguard Worker It can read from volumes as long as Buffer.Size().
877*f6dc9357SAndroid Build Coastguard Worker But it moves to new volume, only if it's required to provide minRequired bytes in buffer.
878*f6dc9357SAndroid Build Coastguard Worker 
879*f6dc9357SAndroid Build Coastguard Worker in:
880*f6dc9357SAndroid Build Coastguard Worker   (minRequired <= Buffer.Size())
881*f6dc9357SAndroid Build Coastguard Worker 
882*f6dc9357SAndroid Build Coastguard Worker return:
883*f6dc9357SAndroid Build Coastguard Worker   S_OK : if (GetAvail() < minRequired) after function return, it's end of stream(s) data, or no new volume stream.
884*f6dc9357SAndroid Build Coastguard Worker   Error codes: IInStream::Read() error or IInStream::Seek() error for multivol
885*f6dc9357SAndroid Build Coastguard Worker */
886*f6dc9357SAndroid Build Coastguard Worker 
LookAhead(size_t minRequired)887*f6dc9357SAndroid Build Coastguard Worker HRESULT CInArchive::LookAhead(size_t minRequired)
888*f6dc9357SAndroid Build Coastguard Worker {
889*f6dc9357SAndroid Build Coastguard Worker   for (;;)
890*f6dc9357SAndroid Build Coastguard Worker   {
891*f6dc9357SAndroid Build Coastguard Worker     const size_t avail = GetAvail();
892*f6dc9357SAndroid Build Coastguard Worker 
893*f6dc9357SAndroid Build Coastguard Worker     if (minRequired <= avail)
894*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
895*f6dc9357SAndroid Build Coastguard Worker 
896*f6dc9357SAndroid Build Coastguard Worker     if (_bufPos != 0)
897*f6dc9357SAndroid Build Coastguard Worker     {
898*f6dc9357SAndroid Build Coastguard Worker       if (avail != 0)
899*f6dc9357SAndroid Build Coastguard Worker         memmove(Buffer, Buffer + _bufPos, avail);
900*f6dc9357SAndroid Build Coastguard Worker       _bufPos = 0;
901*f6dc9357SAndroid Build Coastguard Worker       _bufCached = avail;
902*f6dc9357SAndroid Build Coastguard Worker     }
903*f6dc9357SAndroid Build Coastguard Worker 
904*f6dc9357SAndroid Build Coastguard Worker     const size_t pos = _bufCached;
905*f6dc9357SAndroid Build Coastguard Worker     UInt32 processed = 0;
906*f6dc9357SAndroid Build Coastguard Worker     HRESULT res = Stream->Read(Buffer + pos, (UInt32)(Buffer.Size() - pos), &processed);
907*f6dc9357SAndroid Build Coastguard Worker     _streamPos += processed;
908*f6dc9357SAndroid Build Coastguard Worker     _bufCached += processed;
909*f6dc9357SAndroid Build Coastguard Worker 
910*f6dc9357SAndroid Build Coastguard Worker     if (res != S_OK)
911*f6dc9357SAndroid Build Coastguard Worker       return res;
912*f6dc9357SAndroid Build Coastguard Worker 
913*f6dc9357SAndroid Build Coastguard Worker     if (processed != 0)
914*f6dc9357SAndroid Build Coastguard Worker       continue;
915*f6dc9357SAndroid Build Coastguard Worker 
916*f6dc9357SAndroid Build Coastguard Worker     if (   !IsMultiVol
917*f6dc9357SAndroid Build Coastguard Worker         || !CanStartNewVol
918*f6dc9357SAndroid Build Coastguard Worker         || Vols.StreamIndex < 0
919*f6dc9357SAndroid Build Coastguard Worker         || (unsigned)Vols.StreamIndex + 1 >= Vols.Streams.Size())
920*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
921*f6dc9357SAndroid Build Coastguard Worker 
922*f6dc9357SAndroid Build Coastguard Worker     const CVols::CSubStreamInfo &s = Vols.Streams[(unsigned)Vols.StreamIndex + 1];
923*f6dc9357SAndroid Build Coastguard Worker     if (!s.Stream)
924*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
925*f6dc9357SAndroid Build Coastguard Worker 
926*f6dc9357SAndroid Build Coastguard Worker     RINOK(s.SeekToStart())
927*f6dc9357SAndroid Build Coastguard Worker 
928*f6dc9357SAndroid Build Coastguard Worker     Vols.StreamIndex++;
929*f6dc9357SAndroid Build Coastguard Worker     _streamPos = 0;
930*f6dc9357SAndroid Build Coastguard Worker     Stream = s.Stream;
931*f6dc9357SAndroid Build Coastguard Worker     // Vols.NeedSeek = false;
932*f6dc9357SAndroid Build Coastguard Worker   }
933*f6dc9357SAndroid Build Coastguard Worker }
934*f6dc9357SAndroid Build Coastguard Worker 
935*f6dc9357SAndroid Build Coastguard Worker 
936*f6dc9357SAndroid Build Coastguard Worker class CUnexpectEnd {};
937*f6dc9357SAndroid Build Coastguard Worker 
938*f6dc9357SAndroid Build Coastguard Worker 
939*f6dc9357SAndroid Build Coastguard Worker /*
940*f6dc9357SAndroid Build Coastguard Worker ---------- SafeRead ----------
941*f6dc9357SAndroid Build Coastguard Worker 
942*f6dc9357SAndroid Build Coastguard Worker reads data of exact size from stream(s)
943*f6dc9357SAndroid Build Coastguard Worker 
944*f6dc9357SAndroid Build Coastguard Worker in:
945*f6dc9357SAndroid Build Coastguard Worker   _inBufMode
946*f6dc9357SAndroid Build Coastguard Worker   if (CanStartNewVol) it can go to next volume before first byte reading, if there is end of volume data.
947*f6dc9357SAndroid Build Coastguard Worker 
948*f6dc9357SAndroid Build Coastguard Worker in, out:
949*f6dc9357SAndroid Build Coastguard Worker   _streamPos  :  position in Stream
950*f6dc9357SAndroid Build Coastguard Worker   Stream
951*f6dc9357SAndroid Build Coastguard Worker   Vols  :  if (IsMultiVol)
952*f6dc9357SAndroid Build Coastguard Worker   _cnt
953*f6dc9357SAndroid Build Coastguard Worker 
954*f6dc9357SAndroid Build Coastguard Worker out:
955*f6dc9357SAndroid Build Coastguard Worker   (CanStartNewVol == false), if some data was read
956*f6dc9357SAndroid Build Coastguard Worker 
957*f6dc9357SAndroid Build Coastguard Worker return:
958*f6dc9357SAndroid Build Coastguard Worker   S_OK : success reading of requested data
959*f6dc9357SAndroid Build Coastguard Worker 
960*f6dc9357SAndroid Build Coastguard Worker exceptions:
961*f6dc9357SAndroid Build Coastguard Worker   CSystemException() - stream reading error
962*f6dc9357SAndroid Build Coastguard Worker   CUnexpectEnd()  :  could not read data of requested size
963*f6dc9357SAndroid Build Coastguard Worker */
964*f6dc9357SAndroid Build Coastguard Worker 
SafeRead(Byte * data,unsigned size)965*f6dc9357SAndroid Build Coastguard Worker void CInArchive::SafeRead(Byte *data, unsigned size)
966*f6dc9357SAndroid Build Coastguard Worker {
967*f6dc9357SAndroid Build Coastguard Worker   unsigned processed;
968*f6dc9357SAndroid Build Coastguard Worker   HRESULT result = ReadFromCache(data, size, processed);
969*f6dc9357SAndroid Build Coastguard Worker   if (result != S_OK)
970*f6dc9357SAndroid Build Coastguard Worker     throw CSystemException(result);
971*f6dc9357SAndroid Build Coastguard Worker   if (size != processed)
972*f6dc9357SAndroid Build Coastguard Worker     throw CUnexpectEnd();
973*f6dc9357SAndroid Build Coastguard Worker }
974*f6dc9357SAndroid Build Coastguard Worker 
ReadBuffer(CByteBuffer & buffer,unsigned size)975*f6dc9357SAndroid Build Coastguard Worker void CInArchive::ReadBuffer(CByteBuffer &buffer, unsigned size)
976*f6dc9357SAndroid Build Coastguard Worker {
977*f6dc9357SAndroid Build Coastguard Worker   buffer.Alloc(size);
978*f6dc9357SAndroid Build Coastguard Worker   if (size != 0)
979*f6dc9357SAndroid Build Coastguard Worker     SafeRead(buffer, size);
980*f6dc9357SAndroid Build Coastguard Worker }
981*f6dc9357SAndroid Build Coastguard Worker 
982*f6dc9357SAndroid Build Coastguard Worker // Byte CInArchive::ReadByte  () { Byte b;      SafeRead(&b, 1); return b; }
983*f6dc9357SAndroid Build Coastguard Worker // UInt16 CInArchive::ReadUInt16() { Byte buf[2]; SafeRead(buf, 2); return Get16(buf); }
ReadUInt32()984*f6dc9357SAndroid Build Coastguard Worker UInt32 CInArchive::ReadUInt32() { Byte buf[4]; SafeRead(buf, 4); return Get32(buf); }
ReadUInt64()985*f6dc9357SAndroid Build Coastguard Worker UInt64 CInArchive::ReadUInt64() { Byte buf[8]; SafeRead(buf, 8); return Get64(buf); }
986*f6dc9357SAndroid Build Coastguard Worker 
ReadSignature()987*f6dc9357SAndroid Build Coastguard Worker void CInArchive::ReadSignature()
988*f6dc9357SAndroid Build Coastguard Worker {
989*f6dc9357SAndroid Build Coastguard Worker   CanStartNewVol = true;
990*f6dc9357SAndroid Build Coastguard Worker   _signature = ReadUInt32();
991*f6dc9357SAndroid Build Coastguard Worker   // CanStartNewVol = false; // it's already changed in SafeRead
992*f6dc9357SAndroid Build Coastguard Worker }
993*f6dc9357SAndroid Build Coastguard Worker 
994*f6dc9357SAndroid Build Coastguard Worker 
995*f6dc9357SAndroid Build Coastguard Worker // we Skip() inside headers only, so no need for stream change in multivol.
996*f6dc9357SAndroid Build Coastguard Worker 
Skip(size_t num)997*f6dc9357SAndroid Build Coastguard Worker void CInArchive::Skip(size_t num)
998*f6dc9357SAndroid Build Coastguard Worker {
999*f6dc9357SAndroid Build Coastguard Worker   while (num != 0)
1000*f6dc9357SAndroid Build Coastguard Worker   {
1001*f6dc9357SAndroid Build Coastguard Worker     const unsigned kBufSize = (size_t)1 << 10;
1002*f6dc9357SAndroid Build Coastguard Worker     Byte buf[kBufSize];
1003*f6dc9357SAndroid Build Coastguard Worker     unsigned step = kBufSize;
1004*f6dc9357SAndroid Build Coastguard Worker     if (step > num)
1005*f6dc9357SAndroid Build Coastguard Worker       step = (unsigned)num;
1006*f6dc9357SAndroid Build Coastguard Worker     SafeRead(buf, step);
1007*f6dc9357SAndroid Build Coastguard Worker     num -= step;
1008*f6dc9357SAndroid Build Coastguard Worker   }
1009*f6dc9357SAndroid Build Coastguard Worker }
1010*f6dc9357SAndroid Build Coastguard Worker 
1011*f6dc9357SAndroid Build Coastguard Worker /*
1012*f6dc9357SAndroid Build Coastguard Worker HRESULT CInArchive::Callback_Completed(unsigned numFiles)
1013*f6dc9357SAndroid Build Coastguard Worker {
1014*f6dc9357SAndroid Build Coastguard Worker   const UInt64 numFiles64 = numFiles;
1015*f6dc9357SAndroid Build Coastguard Worker   return Callback->SetCompleted(&numFiles64, &_cnt);
1016*f6dc9357SAndroid Build Coastguard Worker }
1017*f6dc9357SAndroid Build Coastguard Worker */
1018*f6dc9357SAndroid Build Coastguard Worker 
Skip64(UInt64 num,unsigned numFiles)1019*f6dc9357SAndroid Build Coastguard Worker HRESULT CInArchive::Skip64(UInt64 num, unsigned numFiles)
1020*f6dc9357SAndroid Build Coastguard Worker {
1021*f6dc9357SAndroid Build Coastguard Worker   if (num == 0)
1022*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
1023*f6dc9357SAndroid Build Coastguard Worker 
1024*f6dc9357SAndroid Build Coastguard Worker   for (;;)
1025*f6dc9357SAndroid Build Coastguard Worker   {
1026*f6dc9357SAndroid Build Coastguard Worker     size_t step = (size_t)1 << 24;
1027*f6dc9357SAndroid Build Coastguard Worker     if (step > num)
1028*f6dc9357SAndroid Build Coastguard Worker       step = (size_t)num;
1029*f6dc9357SAndroid Build Coastguard Worker     Skip(step);
1030*f6dc9357SAndroid Build Coastguard Worker     num -= step;
1031*f6dc9357SAndroid Build Coastguard Worker     if (num == 0)
1032*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
1033*f6dc9357SAndroid Build Coastguard Worker     if (Callback)
1034*f6dc9357SAndroid Build Coastguard Worker     {
1035*f6dc9357SAndroid Build Coastguard Worker       const UInt64 numFiles64 = numFiles;
1036*f6dc9357SAndroid Build Coastguard Worker       RINOK(Callback->SetCompleted(&numFiles64, &_cnt))
1037*f6dc9357SAndroid Build Coastguard Worker     }
1038*f6dc9357SAndroid Build Coastguard Worker   }
1039*f6dc9357SAndroid Build Coastguard Worker }
1040*f6dc9357SAndroid Build Coastguard Worker 
1041*f6dc9357SAndroid Build Coastguard Worker 
ReadFileName(unsigned size,AString & s)1042*f6dc9357SAndroid Build Coastguard Worker bool CInArchive::ReadFileName(unsigned size, AString &s)
1043*f6dc9357SAndroid Build Coastguard Worker {
1044*f6dc9357SAndroid Build Coastguard Worker   if (size == 0)
1045*f6dc9357SAndroid Build Coastguard Worker   {
1046*f6dc9357SAndroid Build Coastguard Worker     s.Empty();
1047*f6dc9357SAndroid Build Coastguard Worker     return true;
1048*f6dc9357SAndroid Build Coastguard Worker   }
1049*f6dc9357SAndroid Build Coastguard Worker   char *p = s.GetBuf(size);
1050*f6dc9357SAndroid Build Coastguard Worker   SafeRead((Byte *)p, size);
1051*f6dc9357SAndroid Build Coastguard Worker   unsigned i = size;
1052*f6dc9357SAndroid Build Coastguard Worker   do
1053*f6dc9357SAndroid Build Coastguard Worker   {
1054*f6dc9357SAndroid Build Coastguard Worker     if (p[i - 1] != 0)
1055*f6dc9357SAndroid Build Coastguard Worker       break;
1056*f6dc9357SAndroid Build Coastguard Worker   }
1057*f6dc9357SAndroid Build Coastguard Worker   while (--i);
1058*f6dc9357SAndroid Build Coastguard Worker   s.ReleaseBuf_CalcLen(size);
1059*f6dc9357SAndroid Build Coastguard Worker   return s.Len() == i;
1060*f6dc9357SAndroid Build Coastguard Worker }
1061*f6dc9357SAndroid Build Coastguard Worker 
1062*f6dc9357SAndroid Build Coastguard Worker 
1063*f6dc9357SAndroid Build Coastguard Worker #define ZIP64_IS_32_MAX(n) ((n) == 0xFFFFFFFF)
1064*f6dc9357SAndroid Build Coastguard Worker #define ZIP64_IS_16_MAX(n) ((n) == 0xFFFF)
1065*f6dc9357SAndroid Build Coastguard Worker 
1066*f6dc9357SAndroid Build Coastguard Worker 
ReadExtra(const CLocalItem & item,unsigned extraSize,CExtraBlock & extra,UInt64 & unpackSize,UInt64 & packSize,CItem * cdItem)1067*f6dc9357SAndroid Build Coastguard Worker bool CInArchive::ReadExtra(const CLocalItem &item, unsigned extraSize, CExtraBlock &extra,
1068*f6dc9357SAndroid Build Coastguard Worker     UInt64 &unpackSize, UInt64 &packSize,
1069*f6dc9357SAndroid Build Coastguard Worker     CItem *cdItem)
1070*f6dc9357SAndroid Build Coastguard Worker {
1071*f6dc9357SAndroid Build Coastguard Worker   extra.Clear();
1072*f6dc9357SAndroid Build Coastguard Worker 
1073*f6dc9357SAndroid Build Coastguard Worker   while (extraSize >= 4)
1074*f6dc9357SAndroid Build Coastguard Worker   {
1075*f6dc9357SAndroid Build Coastguard Worker     CExtraSubBlock subBlock;
1076*f6dc9357SAndroid Build Coastguard Worker     const UInt32 pair = ReadUInt32();
1077*f6dc9357SAndroid Build Coastguard Worker     subBlock.ID = (pair & 0xFFFF);
1078*f6dc9357SAndroid Build Coastguard Worker     unsigned size = (unsigned)(pair >> 16);
1079*f6dc9357SAndroid Build Coastguard Worker     // const unsigned origSize = size;
1080*f6dc9357SAndroid Build Coastguard Worker 
1081*f6dc9357SAndroid Build Coastguard Worker     extraSize -= 4;
1082*f6dc9357SAndroid Build Coastguard Worker 
1083*f6dc9357SAndroid Build Coastguard Worker     if (size > extraSize)
1084*f6dc9357SAndroid Build Coastguard Worker     {
1085*f6dc9357SAndroid Build Coastguard Worker       // it's error in extra
1086*f6dc9357SAndroid Build Coastguard Worker       HeadersWarning = true;
1087*f6dc9357SAndroid Build Coastguard Worker       extra.Error = true;
1088*f6dc9357SAndroid Build Coastguard Worker       Skip(extraSize);
1089*f6dc9357SAndroid Build Coastguard Worker       return false;
1090*f6dc9357SAndroid Build Coastguard Worker     }
1091*f6dc9357SAndroid Build Coastguard Worker 
1092*f6dc9357SAndroid Build Coastguard Worker     extraSize -= size;
1093*f6dc9357SAndroid Build Coastguard Worker 
1094*f6dc9357SAndroid Build Coastguard Worker     if (subBlock.ID == NFileHeader::NExtraID::kZip64)
1095*f6dc9357SAndroid Build Coastguard Worker     {
1096*f6dc9357SAndroid Build Coastguard Worker       extra.IsZip64 = true;
1097*f6dc9357SAndroid Build Coastguard Worker       bool isOK = true;
1098*f6dc9357SAndroid Build Coastguard Worker 
1099*f6dc9357SAndroid Build Coastguard Worker       if (!cdItem
1100*f6dc9357SAndroid Build Coastguard Worker           && size == 16
1101*f6dc9357SAndroid Build Coastguard Worker           && !ZIP64_IS_32_MAX(unpackSize)
1102*f6dc9357SAndroid Build Coastguard Worker           && !ZIP64_IS_32_MAX(packSize))
1103*f6dc9357SAndroid Build Coastguard Worker       {
1104*f6dc9357SAndroid Build Coastguard Worker         /* Win10 Explorer's "Send to Zip" for big (3500 MiB) files
1105*f6dc9357SAndroid Build Coastguard Worker            creates Zip64 Extra in local file header.
1106*f6dc9357SAndroid Build Coastguard Worker            But if both uncompressed and compressed sizes are smaller than 4 GiB,
1107*f6dc9357SAndroid Build Coastguard Worker            Win10 doesn't store 0xFFFFFFFF in 32-bit fields as expected by zip specification.
1108*f6dc9357SAndroid Build Coastguard Worker            21.04: we ignore these minor errors in Win10 zip archives. */
1109*f6dc9357SAndroid Build Coastguard Worker         if (ReadUInt64() != unpackSize)
1110*f6dc9357SAndroid Build Coastguard Worker           isOK = false;
1111*f6dc9357SAndroid Build Coastguard Worker         if (ReadUInt64() != packSize)
1112*f6dc9357SAndroid Build Coastguard Worker           isOK = false;
1113*f6dc9357SAndroid Build Coastguard Worker         size = 0;
1114*f6dc9357SAndroid Build Coastguard Worker       }
1115*f6dc9357SAndroid Build Coastguard Worker       else
1116*f6dc9357SAndroid Build Coastguard Worker       {
1117*f6dc9357SAndroid Build Coastguard Worker         if (ZIP64_IS_32_MAX(unpackSize))
1118*f6dc9357SAndroid Build Coastguard Worker           { if (size < 8) isOK = false; else { size -= 8; unpackSize = ReadUInt64(); }}
1119*f6dc9357SAndroid Build Coastguard Worker 
1120*f6dc9357SAndroid Build Coastguard Worker         if (isOK && ZIP64_IS_32_MAX(packSize))
1121*f6dc9357SAndroid Build Coastguard Worker           { if (size < 8) isOK = false; else { size -= 8; packSize = ReadUInt64(); }}
1122*f6dc9357SAndroid Build Coastguard Worker 
1123*f6dc9357SAndroid Build Coastguard Worker         if (cdItem)
1124*f6dc9357SAndroid Build Coastguard Worker         {
1125*f6dc9357SAndroid Build Coastguard Worker           if (isOK)
1126*f6dc9357SAndroid Build Coastguard Worker           {
1127*f6dc9357SAndroid Build Coastguard Worker             if (ZIP64_IS_32_MAX(cdItem->LocalHeaderPos))
1128*f6dc9357SAndroid Build Coastguard Worker               { if (size < 8) isOK = false; else { size -= 8; cdItem->LocalHeaderPos = ReadUInt64(); }}
1129*f6dc9357SAndroid Build Coastguard Worker             /*
1130*f6dc9357SAndroid Build Coastguard Worker             else if (size == 8)
1131*f6dc9357SAndroid Build Coastguard Worker             {
1132*f6dc9357SAndroid Build Coastguard Worker               size -= 8;
1133*f6dc9357SAndroid Build Coastguard Worker               const UInt64 v = ReadUInt64();
1134*f6dc9357SAndroid Build Coastguard Worker               // soong_zip, an AOSP tool (written in the Go) writes incorrect value.
1135*f6dc9357SAndroid Build Coastguard Worker               // we can ignore that minor error here
1136*f6dc9357SAndroid Build Coastguard Worker               if (v != cdItem->LocalHeaderPos)
1137*f6dc9357SAndroid Build Coastguard Worker                 isOK = false; // ignore error
1138*f6dc9357SAndroid Build Coastguard Worker               // isOK = false; // force error
1139*f6dc9357SAndroid Build Coastguard Worker             }
1140*f6dc9357SAndroid Build Coastguard Worker             */
1141*f6dc9357SAndroid Build Coastguard Worker           }
1142*f6dc9357SAndroid Build Coastguard Worker 
1143*f6dc9357SAndroid Build Coastguard Worker           if (isOK && ZIP64_IS_16_MAX(cdItem->Disk))
1144*f6dc9357SAndroid Build Coastguard Worker             { if (size < 4) isOK = false; else { size -= 4; cdItem->Disk = ReadUInt32(); }}
1145*f6dc9357SAndroid Build Coastguard Worker         }
1146*f6dc9357SAndroid Build Coastguard Worker       }
1147*f6dc9357SAndroid Build Coastguard Worker 
1148*f6dc9357SAndroid Build Coastguard Worker       // we can ignore errors, when some zip archiver still write all fields to zip64 extra in local header
1149*f6dc9357SAndroid Build Coastguard Worker       // if (&& (cdItem || !isOK || origSize != 8 * 3 + 4 || size != 8 * 1 + 4))
1150*f6dc9357SAndroid Build Coastguard Worker       if (!isOK || size != 0)
1151*f6dc9357SAndroid Build Coastguard Worker       {
1152*f6dc9357SAndroid Build Coastguard Worker         HeadersWarning = true;
1153*f6dc9357SAndroid Build Coastguard Worker         extra.Error = true;
1154*f6dc9357SAndroid Build Coastguard Worker         extra.IsZip64_Error = true;
1155*f6dc9357SAndroid Build Coastguard Worker       }
1156*f6dc9357SAndroid Build Coastguard Worker       Skip(size);
1157*f6dc9357SAndroid Build Coastguard Worker     }
1158*f6dc9357SAndroid Build Coastguard Worker     else
1159*f6dc9357SAndroid Build Coastguard Worker     {
1160*f6dc9357SAndroid Build Coastguard Worker       ReadBuffer(subBlock.Data, size);
1161*f6dc9357SAndroid Build Coastguard Worker       extra.SubBlocks.Add(subBlock);
1162*f6dc9357SAndroid Build Coastguard Worker       if (subBlock.ID == NFileHeader::NExtraID::kIzUnicodeName)
1163*f6dc9357SAndroid Build Coastguard Worker       {
1164*f6dc9357SAndroid Build Coastguard Worker         if (!subBlock.CheckIzUnicode(item.Name))
1165*f6dc9357SAndroid Build Coastguard Worker           extra.Error = true;
1166*f6dc9357SAndroid Build Coastguard Worker       }
1167*f6dc9357SAndroid Build Coastguard Worker     }
1168*f6dc9357SAndroid Build Coastguard Worker   }
1169*f6dc9357SAndroid Build Coastguard Worker 
1170*f6dc9357SAndroid Build Coastguard Worker   if (extraSize != 0)
1171*f6dc9357SAndroid Build Coastguard Worker   {
1172*f6dc9357SAndroid Build Coastguard Worker     ExtraMinorError = true;
1173*f6dc9357SAndroid Build Coastguard Worker     extra.MinorError = true;
1174*f6dc9357SAndroid Build Coastguard Worker     // 7-Zip before 9.31 created incorrect WzAES Extra in folder's local headers.
1175*f6dc9357SAndroid Build Coastguard Worker     // so we don't return false, but just set warning flag
1176*f6dc9357SAndroid Build Coastguard Worker     // return false;
1177*f6dc9357SAndroid Build Coastguard Worker     Skip(extraSize);
1178*f6dc9357SAndroid Build Coastguard Worker   }
1179*f6dc9357SAndroid Build Coastguard Worker 
1180*f6dc9357SAndroid Build Coastguard Worker   return true;
1181*f6dc9357SAndroid Build Coastguard Worker }
1182*f6dc9357SAndroid Build Coastguard Worker 
1183*f6dc9357SAndroid Build Coastguard Worker 
ReadLocalItem(CItemEx & item)1184*f6dc9357SAndroid Build Coastguard Worker bool CInArchive::ReadLocalItem(CItemEx &item)
1185*f6dc9357SAndroid Build Coastguard Worker {
1186*f6dc9357SAndroid Build Coastguard Worker   item.Disk = 0;
1187*f6dc9357SAndroid Build Coastguard Worker   if (IsMultiVol && Vols.StreamIndex >= 0)
1188*f6dc9357SAndroid Build Coastguard Worker     item.Disk = (UInt32)Vols.StreamIndex;
1189*f6dc9357SAndroid Build Coastguard Worker   const unsigned kPureHeaderSize = kLocalHeaderSize - 4;
1190*f6dc9357SAndroid Build Coastguard Worker   Byte p[kPureHeaderSize];
1191*f6dc9357SAndroid Build Coastguard Worker   SafeRead(p, kPureHeaderSize);
1192*f6dc9357SAndroid Build Coastguard Worker   {
1193*f6dc9357SAndroid Build Coastguard Worker     unsigned i;
1194*f6dc9357SAndroid Build Coastguard Worker     for (i = 0; i < kPureHeaderSize && p[i] == 0; i++);
1195*f6dc9357SAndroid Build Coastguard Worker     if (i == kPureHeaderSize)
1196*f6dc9357SAndroid Build Coastguard Worker       return false;
1197*f6dc9357SAndroid Build Coastguard Worker   }
1198*f6dc9357SAndroid Build Coastguard Worker 
1199*f6dc9357SAndroid Build Coastguard Worker   item.ExtractVersion.Version = p[0];
1200*f6dc9357SAndroid Build Coastguard Worker   item.ExtractVersion.HostOS = p[1];
1201*f6dc9357SAndroid Build Coastguard Worker   G16(2, item.Flags);
1202*f6dc9357SAndroid Build Coastguard Worker   G16(4, item.Method);
1203*f6dc9357SAndroid Build Coastguard Worker   G32(6, item.Time);
1204*f6dc9357SAndroid Build Coastguard Worker   G32(10, item.Crc);
1205*f6dc9357SAndroid Build Coastguard Worker   G32(14, item.PackSize);
1206*f6dc9357SAndroid Build Coastguard Worker   G32(18, item.Size);
1207*f6dc9357SAndroid Build Coastguard Worker   const unsigned nameSize = Get16(p + 22);
1208*f6dc9357SAndroid Build Coastguard Worker   const unsigned extraSize = Get16(p + 24);
1209*f6dc9357SAndroid Build Coastguard Worker   bool isOkName = ReadFileName(nameSize, item.Name);
1210*f6dc9357SAndroid Build Coastguard Worker   item.LocalFullHeaderSize = kLocalHeaderSize + (UInt32)nameSize + extraSize;
1211*f6dc9357SAndroid Build Coastguard Worker   item.DescriptorWasRead = false;
1212*f6dc9357SAndroid Build Coastguard Worker 
1213*f6dc9357SAndroid Build Coastguard Worker   /*
1214*f6dc9357SAndroid Build Coastguard Worker   if (item.IsDir())
1215*f6dc9357SAndroid Build Coastguard Worker     item.Size = 0; // check It
1216*f6dc9357SAndroid Build Coastguard Worker   */
1217*f6dc9357SAndroid Build Coastguard Worker 
1218*f6dc9357SAndroid Build Coastguard Worker   if (extraSize > 0)
1219*f6dc9357SAndroid Build Coastguard Worker   {
1220*f6dc9357SAndroid Build Coastguard Worker     if (!ReadExtra(item, extraSize, item.LocalExtra, item.Size, item.PackSize, NULL))
1221*f6dc9357SAndroid Build Coastguard Worker     {
1222*f6dc9357SAndroid Build Coastguard Worker       /* Most of archives are OK for Extra. But there are some rare cases
1223*f6dc9357SAndroid Build Coastguard Worker          that have error. And if error in first item, it can't open archive.
1224*f6dc9357SAndroid Build Coastguard Worker          So we ignore that error */
1225*f6dc9357SAndroid Build Coastguard Worker       // return false;
1226*f6dc9357SAndroid Build Coastguard Worker     }
1227*f6dc9357SAndroid Build Coastguard Worker   }
1228*f6dc9357SAndroid Build Coastguard Worker 
1229*f6dc9357SAndroid Build Coastguard Worker   if (!CheckDosTime(item.Time))
1230*f6dc9357SAndroid Build Coastguard Worker   {
1231*f6dc9357SAndroid Build Coastguard Worker     HeadersWarning = true;
1232*f6dc9357SAndroid Build Coastguard Worker     // return false;
1233*f6dc9357SAndroid Build Coastguard Worker   }
1234*f6dc9357SAndroid Build Coastguard Worker 
1235*f6dc9357SAndroid Build Coastguard Worker   if (item.Name.Len() != nameSize)
1236*f6dc9357SAndroid Build Coastguard Worker   {
1237*f6dc9357SAndroid Build Coastguard Worker     // we support some "bad" zip archives that contain zeros after name
1238*f6dc9357SAndroid Build Coastguard Worker     if (!isOkName)
1239*f6dc9357SAndroid Build Coastguard Worker       return false;
1240*f6dc9357SAndroid Build Coastguard Worker     HeadersWarning = true;
1241*f6dc9357SAndroid Build Coastguard Worker   }
1242*f6dc9357SAndroid Build Coastguard Worker 
1243*f6dc9357SAndroid Build Coastguard Worker   // return item.LocalFullHeaderSize <= ((UInt32)1 << 16);
1244*f6dc9357SAndroid Build Coastguard Worker   return true;
1245*f6dc9357SAndroid Build Coastguard Worker }
1246*f6dc9357SAndroid Build Coastguard Worker 
1247*f6dc9357SAndroid Build Coastguard Worker 
FlagsAreSame(const CItem & i1,const CItem & i2_cd)1248*f6dc9357SAndroid Build Coastguard Worker static bool FlagsAreSame(const CItem &i1, const CItem &i2_cd)
1249*f6dc9357SAndroid Build Coastguard Worker {
1250*f6dc9357SAndroid Build Coastguard Worker   if (i1.Method != i2_cd.Method)
1251*f6dc9357SAndroid Build Coastguard Worker     return false;
1252*f6dc9357SAndroid Build Coastguard Worker 
1253*f6dc9357SAndroid Build Coastguard Worker   UInt32 mask = i1.Flags ^ i2_cd.Flags;
1254*f6dc9357SAndroid Build Coastguard Worker   if (mask == 0)
1255*f6dc9357SAndroid Build Coastguard Worker     return true;
1256*f6dc9357SAndroid Build Coastguard Worker   switch (i1.Method)
1257*f6dc9357SAndroid Build Coastguard Worker   {
1258*f6dc9357SAndroid Build Coastguard Worker     case NFileHeader::NCompressionMethod::kDeflate:
1259*f6dc9357SAndroid Build Coastguard Worker       mask &= 0x7FF9;
1260*f6dc9357SAndroid Build Coastguard Worker       break;
1261*f6dc9357SAndroid Build Coastguard Worker     default:
1262*f6dc9357SAndroid Build Coastguard Worker       if (i1.Method <= NFileHeader::NCompressionMethod::kImplode)
1263*f6dc9357SAndroid Build Coastguard Worker         mask &= 0x7FFF;
1264*f6dc9357SAndroid Build Coastguard Worker   }
1265*f6dc9357SAndroid Build Coastguard Worker 
1266*f6dc9357SAndroid Build Coastguard Worker   // we can ignore utf8 flag, if name is ascii, or if only cdItem has utf8 flag
1267*f6dc9357SAndroid Build Coastguard Worker   if (mask & NFileHeader::NFlags::kUtf8)
1268*f6dc9357SAndroid Build Coastguard Worker     if ((i1.Name.IsAscii() && i2_cd.Name.IsAscii())
1269*f6dc9357SAndroid Build Coastguard Worker         || (i2_cd.Flags & NFileHeader::NFlags::kUtf8))
1270*f6dc9357SAndroid Build Coastguard Worker       mask &= ~NFileHeader::NFlags::kUtf8;
1271*f6dc9357SAndroid Build Coastguard Worker 
1272*f6dc9357SAndroid Build Coastguard Worker   // some bad archive in rare case can use descriptor without descriptor flag in Central Dir
1273*f6dc9357SAndroid Build Coastguard Worker   // if (i1.HasDescriptor())
1274*f6dc9357SAndroid Build Coastguard Worker   mask &= ~NFileHeader::NFlags::kDescriptorUsedMask;
1275*f6dc9357SAndroid Build Coastguard Worker 
1276*f6dc9357SAndroid Build Coastguard Worker   return (mask == 0);
1277*f6dc9357SAndroid Build Coastguard Worker }
1278*f6dc9357SAndroid Build Coastguard Worker 
1279*f6dc9357SAndroid Build Coastguard Worker 
1280*f6dc9357SAndroid Build Coastguard Worker // #ifdef _WIN32
AreEqualPaths_IgnoreSlashes(const char * s1,const char * s2)1281*f6dc9357SAndroid Build Coastguard Worker static bool AreEqualPaths_IgnoreSlashes(const char *s1, const char *s2)
1282*f6dc9357SAndroid Build Coastguard Worker {
1283*f6dc9357SAndroid Build Coastguard Worker   for (;;)
1284*f6dc9357SAndroid Build Coastguard Worker   {
1285*f6dc9357SAndroid Build Coastguard Worker     char c1 = *s1++;
1286*f6dc9357SAndroid Build Coastguard Worker     char c2 = *s2++;
1287*f6dc9357SAndroid Build Coastguard Worker     if (c1 == c2)
1288*f6dc9357SAndroid Build Coastguard Worker     {
1289*f6dc9357SAndroid Build Coastguard Worker       if (c1 == 0)
1290*f6dc9357SAndroid Build Coastguard Worker         return true;
1291*f6dc9357SAndroid Build Coastguard Worker     }
1292*f6dc9357SAndroid Build Coastguard Worker     else
1293*f6dc9357SAndroid Build Coastguard Worker     {
1294*f6dc9357SAndroid Build Coastguard Worker       if (c1 == '\\') c1 = '/';
1295*f6dc9357SAndroid Build Coastguard Worker       if (c2 == '\\') c2 = '/';
1296*f6dc9357SAndroid Build Coastguard Worker       if (c1 != c2)
1297*f6dc9357SAndroid Build Coastguard Worker         return false;
1298*f6dc9357SAndroid Build Coastguard Worker     }
1299*f6dc9357SAndroid Build Coastguard Worker   }
1300*f6dc9357SAndroid Build Coastguard Worker }
1301*f6dc9357SAndroid Build Coastguard Worker // #endif
1302*f6dc9357SAndroid Build Coastguard Worker 
1303*f6dc9357SAndroid Build Coastguard Worker 
AreItemsEqual(const CItemEx & localItem,const CItemEx & cdItem)1304*f6dc9357SAndroid Build Coastguard Worker static bool AreItemsEqual(const CItemEx &localItem, const CItemEx &cdItem)
1305*f6dc9357SAndroid Build Coastguard Worker {
1306*f6dc9357SAndroid Build Coastguard Worker   if (!FlagsAreSame(localItem, cdItem))
1307*f6dc9357SAndroid Build Coastguard Worker     return false;
1308*f6dc9357SAndroid Build Coastguard Worker   if (!localItem.HasDescriptor())
1309*f6dc9357SAndroid Build Coastguard Worker   {
1310*f6dc9357SAndroid Build Coastguard Worker     if (cdItem.PackSize != localItem.PackSize
1311*f6dc9357SAndroid Build Coastguard Worker         || cdItem.Size != localItem.Size
1312*f6dc9357SAndroid Build Coastguard Worker         || (cdItem.Crc != localItem.Crc && cdItem.Crc != 0)) // some program writes 0 to crc field in central directory
1313*f6dc9357SAndroid Build Coastguard Worker       return false;
1314*f6dc9357SAndroid Build Coastguard Worker   }
1315*f6dc9357SAndroid Build Coastguard Worker   /* pkzip 2.50 creates incorrect archives. It uses
1316*f6dc9357SAndroid Build Coastguard Worker        - WIN encoding for name in local header
1317*f6dc9357SAndroid Build Coastguard Worker        - OEM encoding for name in central header
1318*f6dc9357SAndroid Build Coastguard Worker      We don't support these strange items. */
1319*f6dc9357SAndroid Build Coastguard Worker 
1320*f6dc9357SAndroid Build Coastguard Worker   /* if (cdItem.Name.Len() != localItem.Name.Len())
1321*f6dc9357SAndroid Build Coastguard Worker     return false;
1322*f6dc9357SAndroid Build Coastguard Worker   */
1323*f6dc9357SAndroid Build Coastguard Worker   if (cdItem.Name != localItem.Name)
1324*f6dc9357SAndroid Build Coastguard Worker   {
1325*f6dc9357SAndroid Build Coastguard Worker     // #ifdef _WIN32
1326*f6dc9357SAndroid Build Coastguard Worker     // some xap files use backslash in central dir items.
1327*f6dc9357SAndroid Build Coastguard Worker     // we can ignore such errors in windows, where all slashes are converted to backslashes
1328*f6dc9357SAndroid Build Coastguard Worker     unsigned hostOs = cdItem.GetHostOS();
1329*f6dc9357SAndroid Build Coastguard Worker 
1330*f6dc9357SAndroid Build Coastguard Worker     if (hostOs == NFileHeader::NHostOS::kFAT ||
1331*f6dc9357SAndroid Build Coastguard Worker         hostOs == NFileHeader::NHostOS::kNTFS)
1332*f6dc9357SAndroid Build Coastguard Worker     {
1333*f6dc9357SAndroid Build Coastguard Worker       if (!AreEqualPaths_IgnoreSlashes(cdItem.Name, localItem.Name))
1334*f6dc9357SAndroid Build Coastguard Worker       {
1335*f6dc9357SAndroid Build Coastguard Worker         // pkzip 2.50 uses DOS encoding in central dir and WIN encoding in local header.
1336*f6dc9357SAndroid Build Coastguard Worker         // so we ignore that error
1337*f6dc9357SAndroid Build Coastguard Worker         if (hostOs != NFileHeader::NHostOS::kFAT
1338*f6dc9357SAndroid Build Coastguard Worker             || cdItem.MadeByVersion.Version < 25
1339*f6dc9357SAndroid Build Coastguard Worker             || cdItem.MadeByVersion.Version > 40)
1340*f6dc9357SAndroid Build Coastguard Worker           return false;
1341*f6dc9357SAndroid Build Coastguard Worker       }
1342*f6dc9357SAndroid Build Coastguard Worker     }
1343*f6dc9357SAndroid Build Coastguard Worker     /*
1344*f6dc9357SAndroid Build Coastguard Worker     else
1345*f6dc9357SAndroid Build Coastguard Worker     #endif
1346*f6dc9357SAndroid Build Coastguard Worker       return false;
1347*f6dc9357SAndroid Build Coastguard Worker     */
1348*f6dc9357SAndroid Build Coastguard Worker   }
1349*f6dc9357SAndroid Build Coastguard Worker   return true;
1350*f6dc9357SAndroid Build Coastguard Worker }
1351*f6dc9357SAndroid Build Coastguard Worker 
1352*f6dc9357SAndroid Build Coastguard Worker 
Read_LocalItem_After_CdItem(CItemEx & item,bool & isAvail,bool & headersError)1353*f6dc9357SAndroid Build Coastguard Worker HRESULT CInArchive::Read_LocalItem_After_CdItem(CItemEx &item, bool &isAvail, bool &headersError)
1354*f6dc9357SAndroid Build Coastguard Worker {
1355*f6dc9357SAndroid Build Coastguard Worker   isAvail = true;
1356*f6dc9357SAndroid Build Coastguard Worker   headersError = false;
1357*f6dc9357SAndroid Build Coastguard Worker   if (item.FromLocal)
1358*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
1359*f6dc9357SAndroid Build Coastguard Worker   try
1360*f6dc9357SAndroid Build Coastguard Worker   {
1361*f6dc9357SAndroid Build Coastguard Worker     UInt64 offset = item.LocalHeaderPos;
1362*f6dc9357SAndroid Build Coastguard Worker 
1363*f6dc9357SAndroid Build Coastguard Worker     if (IsMultiVol)
1364*f6dc9357SAndroid Build Coastguard Worker     {
1365*f6dc9357SAndroid Build Coastguard Worker       if (item.Disk >= Vols.Streams.Size())
1366*f6dc9357SAndroid Build Coastguard Worker       {
1367*f6dc9357SAndroid Build Coastguard Worker         isAvail = false;
1368*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
1369*f6dc9357SAndroid Build Coastguard Worker       }
1370*f6dc9357SAndroid Build Coastguard Worker       Stream = Vols.Streams[item.Disk].Stream;
1371*f6dc9357SAndroid Build Coastguard Worker       Vols.StreamIndex = (int)item.Disk;
1372*f6dc9357SAndroid Build Coastguard Worker       if (!Stream)
1373*f6dc9357SAndroid Build Coastguard Worker       {
1374*f6dc9357SAndroid Build Coastguard Worker         isAvail = false;
1375*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
1376*f6dc9357SAndroid Build Coastguard Worker       }
1377*f6dc9357SAndroid Build Coastguard Worker     }
1378*f6dc9357SAndroid Build Coastguard Worker     else
1379*f6dc9357SAndroid Build Coastguard Worker     {
1380*f6dc9357SAndroid Build Coastguard Worker       if (UseDisk_in_SingleVol && item.Disk != EcdVolIndex)
1381*f6dc9357SAndroid Build Coastguard Worker       {
1382*f6dc9357SAndroid Build Coastguard Worker         isAvail = false;
1383*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
1384*f6dc9357SAndroid Build Coastguard Worker       }
1385*f6dc9357SAndroid Build Coastguard Worker       Stream = StreamRef;
1386*f6dc9357SAndroid Build Coastguard Worker 
1387*f6dc9357SAndroid Build Coastguard Worker       offset = (UInt64)((Int64)offset + ArcInfo.Base);
1388*f6dc9357SAndroid Build Coastguard Worker       if (ArcInfo.Base < 0 && (Int64)offset < 0)
1389*f6dc9357SAndroid Build Coastguard Worker       {
1390*f6dc9357SAndroid Build Coastguard Worker         isAvail = false;
1391*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
1392*f6dc9357SAndroid Build Coastguard Worker       }
1393*f6dc9357SAndroid Build Coastguard Worker     }
1394*f6dc9357SAndroid Build Coastguard Worker 
1395*f6dc9357SAndroid Build Coastguard Worker     _inBufMode = false;
1396*f6dc9357SAndroid Build Coastguard Worker     RINOK(Seek_SavePos(offset))
1397*f6dc9357SAndroid Build Coastguard Worker     InitBuf();
1398*f6dc9357SAndroid Build Coastguard Worker     /*
1399*f6dc9357SAndroid Build Coastguard Worker     // we can use buf mode with small buffer to reduce
1400*f6dc9357SAndroid Build Coastguard Worker     // the number of Read() calls in ReadLocalItem()
1401*f6dc9357SAndroid Build Coastguard Worker     _inBufMode = true;
1402*f6dc9357SAndroid Build Coastguard Worker     Buffer.Alloc(1 << 10);
1403*f6dc9357SAndroid Build Coastguard Worker     if (!Buffer.IsAllocated())
1404*f6dc9357SAndroid Build Coastguard Worker       return E_OUTOFMEMORY;
1405*f6dc9357SAndroid Build Coastguard Worker     */
1406*f6dc9357SAndroid Build Coastguard Worker 
1407*f6dc9357SAndroid Build Coastguard Worker     CItemEx localItem;
1408*f6dc9357SAndroid Build Coastguard Worker     if (ReadUInt32() != NSignature::kLocalFileHeader)
1409*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1410*f6dc9357SAndroid Build Coastguard Worker     ReadLocalItem(localItem);
1411*f6dc9357SAndroid Build Coastguard Worker     if (!AreItemsEqual(localItem, item))
1412*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1413*f6dc9357SAndroid Build Coastguard Worker     item.LocalFullHeaderSize = localItem.LocalFullHeaderSize;
1414*f6dc9357SAndroid Build Coastguard Worker     item.LocalExtra = localItem.LocalExtra;
1415*f6dc9357SAndroid Build Coastguard Worker     if (item.Crc != localItem.Crc && !localItem.HasDescriptor())
1416*f6dc9357SAndroid Build Coastguard Worker     {
1417*f6dc9357SAndroid Build Coastguard Worker       item.Crc = localItem.Crc;
1418*f6dc9357SAndroid Build Coastguard Worker       headersError = true;
1419*f6dc9357SAndroid Build Coastguard Worker     }
1420*f6dc9357SAndroid Build Coastguard Worker     if ((item.Flags ^ localItem.Flags) & NFileHeader::NFlags::kDescriptorUsedMask)
1421*f6dc9357SAndroid Build Coastguard Worker     {
1422*f6dc9357SAndroid Build Coastguard Worker       item.Flags = (UInt16)(item.Flags ^ NFileHeader::NFlags::kDescriptorUsedMask);
1423*f6dc9357SAndroid Build Coastguard Worker       headersError = true;
1424*f6dc9357SAndroid Build Coastguard Worker     }
1425*f6dc9357SAndroid Build Coastguard Worker     item.FromLocal = true;
1426*f6dc9357SAndroid Build Coastguard Worker   }
1427*f6dc9357SAndroid Build Coastguard Worker   catch(...) { return S_FALSE; }
1428*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1429*f6dc9357SAndroid Build Coastguard Worker }
1430*f6dc9357SAndroid Build Coastguard Worker 
1431*f6dc9357SAndroid Build Coastguard Worker 
1432*f6dc9357SAndroid Build Coastguard Worker /*
1433*f6dc9357SAndroid Build Coastguard Worker ---------- FindDescriptor ----------
1434*f6dc9357SAndroid Build Coastguard Worker 
1435*f6dc9357SAndroid Build Coastguard Worker in:
1436*f6dc9357SAndroid Build Coastguard Worker   _streamPos : position in Stream
1437*f6dc9357SAndroid Build Coastguard Worker   Stream :
1438*f6dc9357SAndroid Build Coastguard Worker   Vols : if (IsMultiVol)
1439*f6dc9357SAndroid Build Coastguard Worker 
1440*f6dc9357SAndroid Build Coastguard Worker action:
1441*f6dc9357SAndroid Build Coastguard Worker   searches descriptor in input stream(s).
1442*f6dc9357SAndroid Build Coastguard Worker   sets
1443*f6dc9357SAndroid Build Coastguard Worker     item.DescriptorWasRead = true;
1444*f6dc9357SAndroid Build Coastguard Worker     item.Size
1445*f6dc9357SAndroid Build Coastguard Worker     item.PackSize
1446*f6dc9357SAndroid Build Coastguard Worker     item.Crc
1447*f6dc9357SAndroid Build Coastguard Worker   if descriptor was found
1448*f6dc9357SAndroid Build Coastguard Worker 
1449*f6dc9357SAndroid Build Coastguard Worker out:
1450*f6dc9357SAndroid Build Coastguard Worker   S_OK:
1451*f6dc9357SAndroid Build Coastguard Worker       if ( item.DescriptorWasRead) : if descriptor was found
1452*f6dc9357SAndroid Build Coastguard Worker       if (!item.DescriptorWasRead) : if descriptor was not found : unexpected end of stream(s)
1453*f6dc9357SAndroid Build Coastguard Worker 
1454*f6dc9357SAndroid Build Coastguard Worker   S_FALSE: if no items or there is just one item with strange properies that doesn't look like real archive.
1455*f6dc9357SAndroid Build Coastguard Worker 
1456*f6dc9357SAndroid Build Coastguard Worker   another error code: Callback error.
1457*f6dc9357SAndroid Build Coastguard Worker 
1458*f6dc9357SAndroid Build Coastguard Worker exceptions :
1459*f6dc9357SAndroid Build Coastguard Worker   CSystemException() : stream reading error
1460*f6dc9357SAndroid Build Coastguard Worker */
1461*f6dc9357SAndroid Build Coastguard Worker 
FindDescriptor(CItemEx & item,unsigned numFiles)1462*f6dc9357SAndroid Build Coastguard Worker HRESULT CInArchive::FindDescriptor(CItemEx &item, unsigned numFiles)
1463*f6dc9357SAndroid Build Coastguard Worker {
1464*f6dc9357SAndroid Build Coastguard Worker   // const size_t kBufSize = (size_t)1 << 5; // don't increase it too much. It reads data look ahead.
1465*f6dc9357SAndroid Build Coastguard Worker 
1466*f6dc9357SAndroid Build Coastguard Worker   // Buffer.Alloc(kBufSize);
1467*f6dc9357SAndroid Build Coastguard Worker   // Byte *buf = Buffer;
1468*f6dc9357SAndroid Build Coastguard Worker 
1469*f6dc9357SAndroid Build Coastguard Worker   UInt64 packedSize = 0;
1470*f6dc9357SAndroid Build Coastguard Worker 
1471*f6dc9357SAndroid Build Coastguard Worker   UInt64 progressPrev = _cnt;
1472*f6dc9357SAndroid Build Coastguard Worker 
1473*f6dc9357SAndroid Build Coastguard Worker   for (;;)
1474*f6dc9357SAndroid Build Coastguard Worker   {
1475*f6dc9357SAndroid Build Coastguard Worker     /* appnote specification claims that we must use 64-bit descriptor, if there is zip64 extra.
1476*f6dc9357SAndroid Build Coastguard Worker        But some old third-party xps archives used 64-bit descriptor without zip64 extra. */
1477*f6dc9357SAndroid Build Coastguard Worker     // unsigned descriptorSize = kDataDescriptorSize64 + kNextSignatureSize;
1478*f6dc9357SAndroid Build Coastguard Worker 
1479*f6dc9357SAndroid Build Coastguard Worker     // const unsigned kNextSignatureSize = 0;  // we can disable check for next signatuire
1480*f6dc9357SAndroid Build Coastguard Worker     const unsigned kNextSignatureSize = 4;  // we check also for signature for next File headear
1481*f6dc9357SAndroid Build Coastguard Worker 
1482*f6dc9357SAndroid Build Coastguard Worker     const unsigned descriptorSize4 = item.GetDescriptorSize() + kNextSignatureSize;
1483*f6dc9357SAndroid Build Coastguard Worker 
1484*f6dc9357SAndroid Build Coastguard Worker     if (descriptorSize4 > Buffer.Size()) return E_FAIL;
1485*f6dc9357SAndroid Build Coastguard Worker 
1486*f6dc9357SAndroid Build Coastguard Worker     // size_t processedSize;
1487*f6dc9357SAndroid Build Coastguard Worker     CanStartNewVol = true;
1488*f6dc9357SAndroid Build Coastguard Worker     RINOK(LookAhead(descriptorSize4))
1489*f6dc9357SAndroid Build Coastguard Worker     const size_t avail = GetAvail();
1490*f6dc9357SAndroid Build Coastguard Worker 
1491*f6dc9357SAndroid Build Coastguard Worker     if (avail < descriptorSize4)
1492*f6dc9357SAndroid Build Coastguard Worker     {
1493*f6dc9357SAndroid Build Coastguard Worker       // we write to packSize all these available bytes.
1494*f6dc9357SAndroid Build Coastguard Worker       // later it's simpler to work with such value than with 0
1495*f6dc9357SAndroid Build Coastguard Worker       // if (item.PackSize == 0)
1496*f6dc9357SAndroid Build Coastguard Worker         item.PackSize = packedSize + avail;
1497*f6dc9357SAndroid Build Coastguard Worker       if (item.Method == 0)
1498*f6dc9357SAndroid Build Coastguard Worker         item.Size = item.PackSize;
1499*f6dc9357SAndroid Build Coastguard Worker       SkipLookahed(avail);
1500*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
1501*f6dc9357SAndroid Build Coastguard Worker     }
1502*f6dc9357SAndroid Build Coastguard Worker 
1503*f6dc9357SAndroid Build Coastguard Worker     const Byte * const pStart = Buffer + _bufPos;
1504*f6dc9357SAndroid Build Coastguard Worker     const Byte * p = pStart;
1505*f6dc9357SAndroid Build Coastguard Worker     const Byte * const limit = pStart + (avail - descriptorSize4);
1506*f6dc9357SAndroid Build Coastguard Worker 
1507*f6dc9357SAndroid Build Coastguard Worker     for (; p <= limit; p++)
1508*f6dc9357SAndroid Build Coastguard Worker     {
1509*f6dc9357SAndroid Build Coastguard Worker       // descriptor signature field is Info-ZIP's extension to pkware Zip specification.
1510*f6dc9357SAndroid Build Coastguard Worker       // New ZIP specification also allows descriptorSignature.
1511*f6dc9357SAndroid Build Coastguard Worker 
1512*f6dc9357SAndroid Build Coastguard Worker       p = FindPK_4(p, limit + 1);
1513*f6dc9357SAndroid Build Coastguard Worker       if (p > limit)
1514*f6dc9357SAndroid Build Coastguard Worker         break;
1515*f6dc9357SAndroid Build Coastguard Worker 
1516*f6dc9357SAndroid Build Coastguard Worker       /*
1517*f6dc9357SAndroid Build Coastguard Worker       if (*p != 0x50)
1518*f6dc9357SAndroid Build Coastguard Worker         continue;
1519*f6dc9357SAndroid Build Coastguard Worker       */
1520*f6dc9357SAndroid Build Coastguard Worker 
1521*f6dc9357SAndroid Build Coastguard Worker       if (Get32(p) != NSignature::kDataDescriptor)
1522*f6dc9357SAndroid Build Coastguard Worker         continue;
1523*f6dc9357SAndroid Build Coastguard Worker 
1524*f6dc9357SAndroid Build Coastguard Worker       // we check next signatuire after descriptor
1525*f6dc9357SAndroid Build Coastguard Worker       // maybe we need check only 2 bytes "PK" instead of 4 bytes, if some another type of header is possible after descriptor
1526*f6dc9357SAndroid Build Coastguard Worker       const UInt32 sig = Get32(p + descriptorSize4 - kNextSignatureSize);
1527*f6dc9357SAndroid Build Coastguard Worker       if (   sig != NSignature::kLocalFileHeader
1528*f6dc9357SAndroid Build Coastguard Worker           && sig != NSignature::kCentralFileHeader)
1529*f6dc9357SAndroid Build Coastguard Worker         continue;
1530*f6dc9357SAndroid Build Coastguard Worker 
1531*f6dc9357SAndroid Build Coastguard Worker       const UInt64 packSizeCur = packedSize + (size_t)(p - pStart);
1532*f6dc9357SAndroid Build Coastguard Worker       if (descriptorSize4 == kDataDescriptorSize64 + kNextSignatureSize) // if (item.LocalExtra.IsZip64)
1533*f6dc9357SAndroid Build Coastguard Worker       {
1534*f6dc9357SAndroid Build Coastguard Worker         const UInt64 descriptorPackSize = Get64(p + 8);
1535*f6dc9357SAndroid Build Coastguard Worker         if (descriptorPackSize != packSizeCur)
1536*f6dc9357SAndroid Build Coastguard Worker           continue;
1537*f6dc9357SAndroid Build Coastguard Worker         item.Size = Get64(p + 16);
1538*f6dc9357SAndroid Build Coastguard Worker       }
1539*f6dc9357SAndroid Build Coastguard Worker       else
1540*f6dc9357SAndroid Build Coastguard Worker       {
1541*f6dc9357SAndroid Build Coastguard Worker         const UInt32 descriptorPackSize = Get32(p + 8);
1542*f6dc9357SAndroid Build Coastguard Worker         if (descriptorPackSize != (UInt32)packSizeCur)
1543*f6dc9357SAndroid Build Coastguard Worker           continue;
1544*f6dc9357SAndroid Build Coastguard Worker         item.Size = Get32(p + 12);
1545*f6dc9357SAndroid Build Coastguard Worker         // that item.Size can be truncated to 32-bit value here
1546*f6dc9357SAndroid Build Coastguard Worker       }
1547*f6dc9357SAndroid Build Coastguard Worker       // We write calculated 64-bit packSize, even if descriptor64 was not used
1548*f6dc9357SAndroid Build Coastguard Worker       item.PackSize = packSizeCur;
1549*f6dc9357SAndroid Build Coastguard Worker 
1550*f6dc9357SAndroid Build Coastguard Worker       item.DescriptorWasRead = true;
1551*f6dc9357SAndroid Build Coastguard Worker       item.Crc = Get32(p + 4);
1552*f6dc9357SAndroid Build Coastguard Worker 
1553*f6dc9357SAndroid Build Coastguard Worker       const size_t skip = (size_t)(p - pStart) + descriptorSize4 - kNextSignatureSize;
1554*f6dc9357SAndroid Build Coastguard Worker 
1555*f6dc9357SAndroid Build Coastguard Worker       SkipLookahed(skip);
1556*f6dc9357SAndroid Build Coastguard Worker 
1557*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
1558*f6dc9357SAndroid Build Coastguard Worker     }
1559*f6dc9357SAndroid Build Coastguard Worker 
1560*f6dc9357SAndroid Build Coastguard Worker     const size_t skip = (size_t)(p - pStart);
1561*f6dc9357SAndroid Build Coastguard Worker     SkipLookahed(skip);
1562*f6dc9357SAndroid Build Coastguard Worker 
1563*f6dc9357SAndroid Build Coastguard Worker     packedSize += skip;
1564*f6dc9357SAndroid Build Coastguard Worker 
1565*f6dc9357SAndroid Build Coastguard Worker     if (Callback)
1566*f6dc9357SAndroid Build Coastguard Worker     if (_cnt - progressPrev >= ((UInt32)1 << 22))
1567*f6dc9357SAndroid Build Coastguard Worker     {
1568*f6dc9357SAndroid Build Coastguard Worker       progressPrev = _cnt;
1569*f6dc9357SAndroid Build Coastguard Worker       const UInt64 numFiles64 = numFiles;
1570*f6dc9357SAndroid Build Coastguard Worker       RINOK(Callback->SetCompleted(&numFiles64, &_cnt))
1571*f6dc9357SAndroid Build Coastguard Worker     }
1572*f6dc9357SAndroid Build Coastguard Worker   }
1573*f6dc9357SAndroid Build Coastguard Worker }
1574*f6dc9357SAndroid Build Coastguard Worker 
1575*f6dc9357SAndroid Build Coastguard Worker 
CheckDescriptor(const CItemEx & item)1576*f6dc9357SAndroid Build Coastguard Worker HRESULT CInArchive::CheckDescriptor(const CItemEx &item)
1577*f6dc9357SAndroid Build Coastguard Worker {
1578*f6dc9357SAndroid Build Coastguard Worker   if (!item.HasDescriptor())
1579*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
1580*f6dc9357SAndroid Build Coastguard Worker 
1581*f6dc9357SAndroid Build Coastguard Worker   // pkzip's version without descriptor signature is not supported
1582*f6dc9357SAndroid Build Coastguard Worker 
1583*f6dc9357SAndroid Build Coastguard Worker   bool isFinished = false;
1584*f6dc9357SAndroid Build Coastguard Worker   RINOK(IncreaseRealPosition(item.PackSize, isFinished))
1585*f6dc9357SAndroid Build Coastguard Worker   if (isFinished)
1586*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
1587*f6dc9357SAndroid Build Coastguard Worker 
1588*f6dc9357SAndroid Build Coastguard Worker   /*
1589*f6dc9357SAndroid Build Coastguard Worker   if (!IsMultiVol)
1590*f6dc9357SAndroid Build Coastguard Worker   {
1591*f6dc9357SAndroid Build Coastguard Worker     RINOK(Seek_SavePos(ArcInfo.Base + item.GetDataPosition() + item.PackSize));
1592*f6dc9357SAndroid Build Coastguard Worker   }
1593*f6dc9357SAndroid Build Coastguard Worker   */
1594*f6dc9357SAndroid Build Coastguard Worker 
1595*f6dc9357SAndroid Build Coastguard Worker   Byte buf[kDataDescriptorSize64];
1596*f6dc9357SAndroid Build Coastguard Worker   try
1597*f6dc9357SAndroid Build Coastguard Worker   {
1598*f6dc9357SAndroid Build Coastguard Worker     CanStartNewVol = true;
1599*f6dc9357SAndroid Build Coastguard Worker     SafeRead(buf, item.GetDescriptorSize());
1600*f6dc9357SAndroid Build Coastguard Worker   }
1601*f6dc9357SAndroid Build Coastguard Worker   catch (const CSystemException &e) { return e.ErrorCode; }
1602*f6dc9357SAndroid Build Coastguard Worker   // catch (const CUnexpectEnd &)
1603*f6dc9357SAndroid Build Coastguard Worker   catch(...)
1604*f6dc9357SAndroid Build Coastguard Worker   {
1605*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
1606*f6dc9357SAndroid Build Coastguard Worker   }
1607*f6dc9357SAndroid Build Coastguard Worker   // RINOK(ReadStream_FALSE(Stream, buf, item.GetDescriptorSize()));
1608*f6dc9357SAndroid Build Coastguard Worker 
1609*f6dc9357SAndroid Build Coastguard Worker   if (Get32(buf) != NSignature::kDataDescriptor)
1610*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
1611*f6dc9357SAndroid Build Coastguard Worker   UInt32 crc = Get32(buf + 4);
1612*f6dc9357SAndroid Build Coastguard Worker   UInt64 packSize, unpackSize;
1613*f6dc9357SAndroid Build Coastguard Worker 
1614*f6dc9357SAndroid Build Coastguard Worker   if (item.LocalExtra.IsZip64)
1615*f6dc9357SAndroid Build Coastguard Worker   {
1616*f6dc9357SAndroid Build Coastguard Worker     packSize = Get64(buf + 8);
1617*f6dc9357SAndroid Build Coastguard Worker     unpackSize = Get64(buf + 16);
1618*f6dc9357SAndroid Build Coastguard Worker   }
1619*f6dc9357SAndroid Build Coastguard Worker   else
1620*f6dc9357SAndroid Build Coastguard Worker   {
1621*f6dc9357SAndroid Build Coastguard Worker     packSize = Get32(buf + 8);
1622*f6dc9357SAndroid Build Coastguard Worker     unpackSize = Get32(buf + 12);
1623*f6dc9357SAndroid Build Coastguard Worker   }
1624*f6dc9357SAndroid Build Coastguard Worker 
1625*f6dc9357SAndroid Build Coastguard Worker   if (crc != item.Crc || item.PackSize != packSize || item.Size != unpackSize)
1626*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
1627*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1628*f6dc9357SAndroid Build Coastguard Worker }
1629*f6dc9357SAndroid Build Coastguard Worker 
1630*f6dc9357SAndroid Build Coastguard Worker 
Read_LocalItem_After_CdItem_Full(CItemEx & item)1631*f6dc9357SAndroid Build Coastguard Worker HRESULT CInArchive::Read_LocalItem_After_CdItem_Full(CItemEx &item)
1632*f6dc9357SAndroid Build Coastguard Worker {
1633*f6dc9357SAndroid Build Coastguard Worker   if (item.FromLocal)
1634*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
1635*f6dc9357SAndroid Build Coastguard Worker   try
1636*f6dc9357SAndroid Build Coastguard Worker   {
1637*f6dc9357SAndroid Build Coastguard Worker     bool isAvail = true;
1638*f6dc9357SAndroid Build Coastguard Worker     bool headersError = false;
1639*f6dc9357SAndroid Build Coastguard Worker     RINOK(Read_LocalItem_After_CdItem(item, isAvail, headersError))
1640*f6dc9357SAndroid Build Coastguard Worker     if (headersError)
1641*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1642*f6dc9357SAndroid Build Coastguard Worker     if (item.HasDescriptor())
1643*f6dc9357SAndroid Build Coastguard Worker       return CheckDescriptor(item);
1644*f6dc9357SAndroid Build Coastguard Worker   }
1645*f6dc9357SAndroid Build Coastguard Worker   catch(...) { return S_FALSE; }
1646*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1647*f6dc9357SAndroid Build Coastguard Worker }
1648*f6dc9357SAndroid Build Coastguard Worker 
1649*f6dc9357SAndroid Build Coastguard Worker 
ReadCdItem(CItemEx & item)1650*f6dc9357SAndroid Build Coastguard Worker HRESULT CInArchive::ReadCdItem(CItemEx &item)
1651*f6dc9357SAndroid Build Coastguard Worker {
1652*f6dc9357SAndroid Build Coastguard Worker   item.FromCentral = true;
1653*f6dc9357SAndroid Build Coastguard Worker   Byte p[kCentralHeaderSize - 4];
1654*f6dc9357SAndroid Build Coastguard Worker   SafeRead(p, kCentralHeaderSize - 4);
1655*f6dc9357SAndroid Build Coastguard Worker 
1656*f6dc9357SAndroid Build Coastguard Worker   item.MadeByVersion.Version = p[0];
1657*f6dc9357SAndroid Build Coastguard Worker   item.MadeByVersion.HostOS = p[1];
1658*f6dc9357SAndroid Build Coastguard Worker   item.ExtractVersion.Version = p[2];
1659*f6dc9357SAndroid Build Coastguard Worker   item.ExtractVersion.HostOS = p[3];
1660*f6dc9357SAndroid Build Coastguard Worker   G16(4, item.Flags);
1661*f6dc9357SAndroid Build Coastguard Worker   G16(6, item.Method);
1662*f6dc9357SAndroid Build Coastguard Worker   G32(8, item.Time);
1663*f6dc9357SAndroid Build Coastguard Worker   G32(12, item.Crc);
1664*f6dc9357SAndroid Build Coastguard Worker   G32(16, item.PackSize);
1665*f6dc9357SAndroid Build Coastguard Worker   G32(20, item.Size);
1666*f6dc9357SAndroid Build Coastguard Worker   const unsigned nameSize = Get16(p + 24);
1667*f6dc9357SAndroid Build Coastguard Worker   const unsigned extraSize = Get16(p + 26);
1668*f6dc9357SAndroid Build Coastguard Worker   const unsigned commentSize = Get16(p + 28);
1669*f6dc9357SAndroid Build Coastguard Worker   G16(30, item.Disk);
1670*f6dc9357SAndroid Build Coastguard Worker   G16(32, item.InternalAttrib);
1671*f6dc9357SAndroid Build Coastguard Worker   G32(34, item.ExternalAttrib);
1672*f6dc9357SAndroid Build Coastguard Worker   G32(38, item.LocalHeaderPos);
1673*f6dc9357SAndroid Build Coastguard Worker   ReadFileName(nameSize, item.Name);
1674*f6dc9357SAndroid Build Coastguard Worker 
1675*f6dc9357SAndroid Build Coastguard Worker   if (extraSize > 0)
1676*f6dc9357SAndroid Build Coastguard Worker     ReadExtra(item, extraSize, item.CentralExtra, item.Size, item.PackSize, &item);
1677*f6dc9357SAndroid Build Coastguard Worker 
1678*f6dc9357SAndroid Build Coastguard Worker   // May be these strings must be deleted
1679*f6dc9357SAndroid Build Coastguard Worker   /*
1680*f6dc9357SAndroid Build Coastguard Worker   if (item.IsDir())
1681*f6dc9357SAndroid Build Coastguard Worker     item.Size = 0;
1682*f6dc9357SAndroid Build Coastguard Worker   */
1683*f6dc9357SAndroid Build Coastguard Worker 
1684*f6dc9357SAndroid Build Coastguard Worker   ReadBuffer(item.Comment, commentSize);
1685*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1686*f6dc9357SAndroid Build Coastguard Worker }
1687*f6dc9357SAndroid Build Coastguard Worker 
1688*f6dc9357SAndroid Build Coastguard Worker 
1689*f6dc9357SAndroid Build Coastguard Worker /*
1690*f6dc9357SAndroid Build Coastguard Worker TryEcd64()
1691*f6dc9357SAndroid Build Coastguard Worker   (_inBufMode == false) is expected here
1692*f6dc9357SAndroid Build Coastguard Worker   so TryEcd64() can't change the Buffer.
1693*f6dc9357SAndroid Build Coastguard Worker   if (Ecd64 is not covered by cached region),
1694*f6dc9357SAndroid Build Coastguard Worker     TryEcd64() can change cached region ranges (_bufCached, _bufPos) and _streamPos.
1695*f6dc9357SAndroid Build Coastguard Worker */
1696*f6dc9357SAndroid Build Coastguard Worker 
TryEcd64(UInt64 offset,CCdInfo & cdInfo)1697*f6dc9357SAndroid Build Coastguard Worker HRESULT CInArchive::TryEcd64(UInt64 offset, CCdInfo &cdInfo)
1698*f6dc9357SAndroid Build Coastguard Worker {
1699*f6dc9357SAndroid Build Coastguard Worker   if (offset >= ((UInt64)1 << 63))
1700*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
1701*f6dc9357SAndroid Build Coastguard Worker   Byte buf[kEcd64_FullSize];
1702*f6dc9357SAndroid Build Coastguard Worker 
1703*f6dc9357SAndroid Build Coastguard Worker   RINOK(SeekToVol(Vols.StreamIndex, offset))
1704*f6dc9357SAndroid Build Coastguard Worker   RINOK(ReadFromCache_FALSE(buf, kEcd64_FullSize))
1705*f6dc9357SAndroid Build Coastguard Worker 
1706*f6dc9357SAndroid Build Coastguard Worker   if (Get32(buf) != NSignature::kEcd64)
1707*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
1708*f6dc9357SAndroid Build Coastguard Worker   UInt64 mainSize = Get64(buf + 4);
1709*f6dc9357SAndroid Build Coastguard Worker   if (mainSize < kEcd64_MainSize || mainSize > ((UInt64)1 << 40))
1710*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
1711*f6dc9357SAndroid Build Coastguard Worker   cdInfo.ParseEcd64e(buf + 12);
1712*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1713*f6dc9357SAndroid Build Coastguard Worker }
1714*f6dc9357SAndroid Build Coastguard Worker 
1715*f6dc9357SAndroid Build Coastguard Worker 
1716*f6dc9357SAndroid Build Coastguard Worker /* FindCd() doesn't use previous cached region,
1717*f6dc9357SAndroid Build Coastguard Worker    but it uses Buffer. So it sets new cached region */
1718*f6dc9357SAndroid Build Coastguard Worker 
FindCd(bool checkOffsetMode)1719*f6dc9357SAndroid Build Coastguard Worker HRESULT CInArchive::FindCd(bool checkOffsetMode)
1720*f6dc9357SAndroid Build Coastguard Worker {
1721*f6dc9357SAndroid Build Coastguard Worker   CCdInfo &cdInfo = Vols.ecd;
1722*f6dc9357SAndroid Build Coastguard Worker 
1723*f6dc9357SAndroid Build Coastguard Worker   UInt64 endPos;
1724*f6dc9357SAndroid Build Coastguard Worker 
1725*f6dc9357SAndroid Build Coastguard Worker   // There are no useful data in cache in most cases here.
1726*f6dc9357SAndroid Build Coastguard Worker   // So here we don't use cache data from previous operations .
1727*f6dc9357SAndroid Build Coastguard Worker 
1728*f6dc9357SAndroid Build Coastguard Worker   InitBuf();
1729*f6dc9357SAndroid Build Coastguard Worker   RINOK(InStream_GetSize_SeekToEnd(Stream, endPos))
1730*f6dc9357SAndroid Build Coastguard Worker   _streamPos = endPos;
1731*f6dc9357SAndroid Build Coastguard Worker 
1732*f6dc9357SAndroid Build Coastguard Worker   // const UInt32 kBufSizeMax2 = ((UInt32)1 << 16) + kEcdSize + kEcd64Locator_Size + kEcd64_FullSize;
1733*f6dc9357SAndroid Build Coastguard Worker   const size_t kBufSizeMax = ((size_t)1 << 17); // must be larger than kBufSizeMax2
1734*f6dc9357SAndroid Build Coastguard Worker 
1735*f6dc9357SAndroid Build Coastguard Worker   const size_t bufSize = (endPos < kBufSizeMax) ? (size_t)endPos : kBufSizeMax;
1736*f6dc9357SAndroid Build Coastguard Worker   if (bufSize < kEcdSize)
1737*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
1738*f6dc9357SAndroid Build Coastguard Worker   // CByteArr byteBuffer(bufSize);
1739*f6dc9357SAndroid Build Coastguard Worker 
1740*f6dc9357SAndroid Build Coastguard Worker   RINOK(AllocateBuffer(kBufSizeMax))
1741*f6dc9357SAndroid Build Coastguard Worker 
1742*f6dc9357SAndroid Build Coastguard Worker   RINOK(Seek_SavePos(endPos - bufSize))
1743*f6dc9357SAndroid Build Coastguard Worker 
1744*f6dc9357SAndroid Build Coastguard Worker   size_t processed = bufSize;
1745*f6dc9357SAndroid Build Coastguard Worker   HRESULT res = ReadStream(Stream, Buffer, &processed);
1746*f6dc9357SAndroid Build Coastguard Worker   _streamPos += processed;
1747*f6dc9357SAndroid Build Coastguard Worker   _bufCached = processed;
1748*f6dc9357SAndroid Build Coastguard Worker   _bufPos = 0;
1749*f6dc9357SAndroid Build Coastguard Worker   _cnt += processed;
1750*f6dc9357SAndroid Build Coastguard Worker   if (res != S_OK)
1751*f6dc9357SAndroid Build Coastguard Worker     return res;
1752*f6dc9357SAndroid Build Coastguard Worker   if (processed != bufSize)
1753*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
1754*f6dc9357SAndroid Build Coastguard Worker 
1755*f6dc9357SAndroid Build Coastguard Worker 
1756*f6dc9357SAndroid Build Coastguard Worker   for (size_t i = bufSize - kEcdSize + 1;;)
1757*f6dc9357SAndroid Build Coastguard Worker   {
1758*f6dc9357SAndroid Build Coastguard Worker     if (i == 0)
1759*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1760*f6dc9357SAndroid Build Coastguard Worker 
1761*f6dc9357SAndroid Build Coastguard Worker     const Byte *buf = Buffer;
1762*f6dc9357SAndroid Build Coastguard Worker 
1763*f6dc9357SAndroid Build Coastguard Worker     for (;;)
1764*f6dc9357SAndroid Build Coastguard Worker     {
1765*f6dc9357SAndroid Build Coastguard Worker       i--;
1766*f6dc9357SAndroid Build Coastguard Worker       if (buf[i] == 0x50)
1767*f6dc9357SAndroid Build Coastguard Worker         break;
1768*f6dc9357SAndroid Build Coastguard Worker       if (i == 0)
1769*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
1770*f6dc9357SAndroid Build Coastguard Worker     }
1771*f6dc9357SAndroid Build Coastguard Worker 
1772*f6dc9357SAndroid Build Coastguard Worker     if (Get32(buf + i) != NSignature::kEcd)
1773*f6dc9357SAndroid Build Coastguard Worker       continue;
1774*f6dc9357SAndroid Build Coastguard Worker 
1775*f6dc9357SAndroid Build Coastguard Worker     cdInfo.ParseEcd32(buf + i);
1776*f6dc9357SAndroid Build Coastguard Worker 
1777*f6dc9357SAndroid Build Coastguard Worker     if (i >= kEcd64Locator_Size)
1778*f6dc9357SAndroid Build Coastguard Worker     {
1779*f6dc9357SAndroid Build Coastguard Worker       const size_t locatorIndex = i - kEcd64Locator_Size;
1780*f6dc9357SAndroid Build Coastguard Worker       if (Get32(buf + locatorIndex) == NSignature::kEcd64Locator)
1781*f6dc9357SAndroid Build Coastguard Worker       {
1782*f6dc9357SAndroid Build Coastguard Worker         CLocator locator;
1783*f6dc9357SAndroid Build Coastguard Worker         locator.Parse(buf + locatorIndex + 4);
1784*f6dc9357SAndroid Build Coastguard Worker         UInt32 numDisks = locator.NumDisks;
1785*f6dc9357SAndroid Build Coastguard Worker         // we ignore the error, where some zip creators use (NumDisks == 0)
1786*f6dc9357SAndroid Build Coastguard Worker         if (numDisks == 0)
1787*f6dc9357SAndroid Build Coastguard Worker           numDisks = 1;
1788*f6dc9357SAndroid Build Coastguard Worker         if ((cdInfo.ThisDisk == numDisks - 1 || ZIP64_IS_16_MAX(cdInfo.ThisDisk))
1789*f6dc9357SAndroid Build Coastguard Worker             && locator.Ecd64Disk < numDisks)
1790*f6dc9357SAndroid Build Coastguard Worker         {
1791*f6dc9357SAndroid Build Coastguard Worker           if (locator.Ecd64Disk != cdInfo.ThisDisk && !ZIP64_IS_16_MAX(cdInfo.ThisDisk))
1792*f6dc9357SAndroid Build Coastguard Worker             return E_NOTIMPL;
1793*f6dc9357SAndroid Build Coastguard Worker 
1794*f6dc9357SAndroid Build Coastguard Worker           // Most of the zip64 use fixed size Zip64 ECD
1795*f6dc9357SAndroid Build Coastguard Worker           // we try relative backward reading.
1796*f6dc9357SAndroid Build Coastguard Worker 
1797*f6dc9357SAndroid Build Coastguard Worker           UInt64 absEcd64 = endPos - bufSize + i - (kEcd64Locator_Size + kEcd64_FullSize);
1798*f6dc9357SAndroid Build Coastguard Worker 
1799*f6dc9357SAndroid Build Coastguard Worker           if (locatorIndex >= kEcd64_FullSize)
1800*f6dc9357SAndroid Build Coastguard Worker           if (checkOffsetMode || absEcd64 == locator.Ecd64Offset)
1801*f6dc9357SAndroid Build Coastguard Worker           {
1802*f6dc9357SAndroid Build Coastguard Worker             const Byte *ecd64 = buf + locatorIndex - kEcd64_FullSize;
1803*f6dc9357SAndroid Build Coastguard Worker             if (Get32(ecd64) == NSignature::kEcd64)
1804*f6dc9357SAndroid Build Coastguard Worker             {
1805*f6dc9357SAndroid Build Coastguard Worker               UInt64 mainEcd64Size = Get64(ecd64 + 4);
1806*f6dc9357SAndroid Build Coastguard Worker               if (mainEcd64Size == kEcd64_MainSize)
1807*f6dc9357SAndroid Build Coastguard Worker               {
1808*f6dc9357SAndroid Build Coastguard Worker                 cdInfo.ParseEcd64e(ecd64 + 12);
1809*f6dc9357SAndroid Build Coastguard Worker                 ArcInfo.Base = (Int64)(absEcd64 - locator.Ecd64Offset);
1810*f6dc9357SAndroid Build Coastguard Worker                 // ArcInfo.BaseVolIndex = cdInfo.ThisDisk;
1811*f6dc9357SAndroid Build Coastguard Worker                 return S_OK;
1812*f6dc9357SAndroid Build Coastguard Worker               }
1813*f6dc9357SAndroid Build Coastguard Worker             }
1814*f6dc9357SAndroid Build Coastguard Worker           }
1815*f6dc9357SAndroid Build Coastguard Worker 
1816*f6dc9357SAndroid Build Coastguard Worker           // some zip64 use variable size Zip64 ECD.
1817*f6dc9357SAndroid Build Coastguard Worker           // we try to use absolute offset from locator.
1818*f6dc9357SAndroid Build Coastguard Worker 
1819*f6dc9357SAndroid Build Coastguard Worker           if (absEcd64 != locator.Ecd64Offset)
1820*f6dc9357SAndroid Build Coastguard Worker           {
1821*f6dc9357SAndroid Build Coastguard Worker             if (TryEcd64(locator.Ecd64Offset, cdInfo) == S_OK)
1822*f6dc9357SAndroid Build Coastguard Worker             {
1823*f6dc9357SAndroid Build Coastguard Worker               ArcInfo.Base = 0;
1824*f6dc9357SAndroid Build Coastguard Worker               // ArcInfo.BaseVolIndex = cdInfo.ThisDisk;
1825*f6dc9357SAndroid Build Coastguard Worker               return S_OK;
1826*f6dc9357SAndroid Build Coastguard Worker             }
1827*f6dc9357SAndroid Build Coastguard Worker           }
1828*f6dc9357SAndroid Build Coastguard Worker 
1829*f6dc9357SAndroid Build Coastguard Worker           // for variable Zip64 ECD with for archives with offset != 0.
1830*f6dc9357SAndroid Build Coastguard Worker 
1831*f6dc9357SAndroid Build Coastguard Worker           if (checkOffsetMode
1832*f6dc9357SAndroid Build Coastguard Worker               && ArcInfo.MarkerPos != 0
1833*f6dc9357SAndroid Build Coastguard Worker               && ArcInfo.MarkerPos + locator.Ecd64Offset != absEcd64)
1834*f6dc9357SAndroid Build Coastguard Worker           {
1835*f6dc9357SAndroid Build Coastguard Worker             if (TryEcd64(ArcInfo.MarkerPos + locator.Ecd64Offset, cdInfo) == S_OK)
1836*f6dc9357SAndroid Build Coastguard Worker             {
1837*f6dc9357SAndroid Build Coastguard Worker               ArcInfo.Base = (Int64)ArcInfo.MarkerPos;
1838*f6dc9357SAndroid Build Coastguard Worker               // ArcInfo.BaseVolIndex = cdInfo.ThisDisk;
1839*f6dc9357SAndroid Build Coastguard Worker               return S_OK;
1840*f6dc9357SAndroid Build Coastguard Worker             }
1841*f6dc9357SAndroid Build Coastguard Worker           }
1842*f6dc9357SAndroid Build Coastguard Worker         }
1843*f6dc9357SAndroid Build Coastguard Worker       }
1844*f6dc9357SAndroid Build Coastguard Worker     }
1845*f6dc9357SAndroid Build Coastguard Worker 
1846*f6dc9357SAndroid Build Coastguard Worker     // bool isVolMode = (Vols.EndVolIndex != -1);
1847*f6dc9357SAndroid Build Coastguard Worker     // UInt32 searchDisk = (isVolMode ? Vols.EndVolIndex : 0);
1848*f6dc9357SAndroid Build Coastguard Worker 
1849*f6dc9357SAndroid Build Coastguard Worker     if (/* searchDisk == thisDisk && */ cdInfo.CdDisk <= cdInfo.ThisDisk)
1850*f6dc9357SAndroid Build Coastguard Worker     {
1851*f6dc9357SAndroid Build Coastguard Worker       // if (isVolMode)
1852*f6dc9357SAndroid Build Coastguard Worker       {
1853*f6dc9357SAndroid Build Coastguard Worker         if (cdInfo.CdDisk != cdInfo.ThisDisk)
1854*f6dc9357SAndroid Build Coastguard Worker           return S_OK;
1855*f6dc9357SAndroid Build Coastguard Worker       }
1856*f6dc9357SAndroid Build Coastguard Worker 
1857*f6dc9357SAndroid Build Coastguard Worker       UInt64 absEcdPos = endPos - bufSize + i;
1858*f6dc9357SAndroid Build Coastguard Worker       UInt64 cdEnd = cdInfo.Size + cdInfo.Offset;
1859*f6dc9357SAndroid Build Coastguard Worker       ArcInfo.Base = 0;
1860*f6dc9357SAndroid Build Coastguard Worker       // ArcInfo.BaseVolIndex = cdInfo.ThisDisk;
1861*f6dc9357SAndroid Build Coastguard Worker       if (absEcdPos != cdEnd)
1862*f6dc9357SAndroid Build Coastguard Worker       {
1863*f6dc9357SAndroid Build Coastguard Worker         /*
1864*f6dc9357SAndroid Build Coastguard Worker         if (cdInfo.Offset <= 16 && cdInfo.Size != 0)
1865*f6dc9357SAndroid Build Coastguard Worker         {
1866*f6dc9357SAndroid Build Coastguard Worker           // here we support some rare ZIP files with Central directory at the start
1867*f6dc9357SAndroid Build Coastguard Worker           ArcInfo.Base = 0;
1868*f6dc9357SAndroid Build Coastguard Worker         }
1869*f6dc9357SAndroid Build Coastguard Worker         else
1870*f6dc9357SAndroid Build Coastguard Worker         */
1871*f6dc9357SAndroid Build Coastguard Worker         ArcInfo.Base = (Int64)(absEcdPos - cdEnd);
1872*f6dc9357SAndroid Build Coastguard Worker       }
1873*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
1874*f6dc9357SAndroid Build Coastguard Worker     }
1875*f6dc9357SAndroid Build Coastguard Worker   }
1876*f6dc9357SAndroid Build Coastguard Worker }
1877*f6dc9357SAndroid Build Coastguard Worker 
1878*f6dc9357SAndroid Build Coastguard Worker 
TryReadCd(CObjectVector<CItemEx> & items,const CCdInfo & cdInfo,UInt64 cdOffset,UInt64 cdSize)1879*f6dc9357SAndroid Build Coastguard Worker HRESULT CInArchive::TryReadCd(CObjectVector<CItemEx> &items, const CCdInfo &cdInfo, UInt64 cdOffset, UInt64 cdSize)
1880*f6dc9357SAndroid Build Coastguard Worker {
1881*f6dc9357SAndroid Build Coastguard Worker   items.Clear();
1882*f6dc9357SAndroid Build Coastguard Worker   IsCdUnsorted = false;
1883*f6dc9357SAndroid Build Coastguard Worker 
1884*f6dc9357SAndroid Build Coastguard Worker   // _startLocalFromCd_Disk = (UInt32)(Int32)-1;
1885*f6dc9357SAndroid Build Coastguard Worker   // _startLocalFromCd_Offset = (UInt64)(Int64)-1;
1886*f6dc9357SAndroid Build Coastguard Worker 
1887*f6dc9357SAndroid Build Coastguard Worker   RINOK(SeekToVol(IsMultiVol ? (int)cdInfo.CdDisk : -1, cdOffset))
1888*f6dc9357SAndroid Build Coastguard Worker 
1889*f6dc9357SAndroid Build Coastguard Worker   _inBufMode = true;
1890*f6dc9357SAndroid Build Coastguard Worker   _cnt = 0;
1891*f6dc9357SAndroid Build Coastguard Worker 
1892*f6dc9357SAndroid Build Coastguard Worker   if (Callback)
1893*f6dc9357SAndroid Build Coastguard Worker   {
1894*f6dc9357SAndroid Build Coastguard Worker     RINOK(Callback->SetTotal(&cdInfo.NumEntries, IsMultiVol ? &Vols.TotalBytesSize : NULL))
1895*f6dc9357SAndroid Build Coastguard Worker   }
1896*f6dc9357SAndroid Build Coastguard Worker   UInt64 numFileExpected = cdInfo.NumEntries;
1897*f6dc9357SAndroid Build Coastguard Worker   const UInt64 *totalFilesPtr = &numFileExpected;
1898*f6dc9357SAndroid Build Coastguard Worker   bool isCorrect_NumEntries = (cdInfo.IsFromEcd64 || numFileExpected >= ((UInt32)1 << 16));
1899*f6dc9357SAndroid Build Coastguard Worker 
1900*f6dc9357SAndroid Build Coastguard Worker   while (_cnt < cdSize)
1901*f6dc9357SAndroid Build Coastguard Worker   {
1902*f6dc9357SAndroid Build Coastguard Worker     CanStartNewVol = true;
1903*f6dc9357SAndroid Build Coastguard Worker     if (ReadUInt32() != NSignature::kCentralFileHeader)
1904*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1905*f6dc9357SAndroid Build Coastguard Worker     CanStartNewVol = false;
1906*f6dc9357SAndroid Build Coastguard Worker     {
1907*f6dc9357SAndroid Build Coastguard Worker       CItemEx cdItem;
1908*f6dc9357SAndroid Build Coastguard Worker       RINOK(ReadCdItem(cdItem))
1909*f6dc9357SAndroid Build Coastguard Worker 
1910*f6dc9357SAndroid Build Coastguard Worker       /*
1911*f6dc9357SAndroid Build Coastguard Worker       if (cdItem.Disk < _startLocalFromCd_Disk ||
1912*f6dc9357SAndroid Build Coastguard Worker           cdItem.Disk == _startLocalFromCd_Disk &&
1913*f6dc9357SAndroid Build Coastguard Worker           cdItem.LocalHeaderPos < _startLocalFromCd_Offset)
1914*f6dc9357SAndroid Build Coastguard Worker       {
1915*f6dc9357SAndroid Build Coastguard Worker         _startLocalFromCd_Disk = cdItem.Disk;
1916*f6dc9357SAndroid Build Coastguard Worker         _startLocalFromCd_Offset = cdItem.LocalHeaderPos;
1917*f6dc9357SAndroid Build Coastguard Worker       }
1918*f6dc9357SAndroid Build Coastguard Worker       */
1919*f6dc9357SAndroid Build Coastguard Worker 
1920*f6dc9357SAndroid Build Coastguard Worker       if (items.Size() > 0 && !IsCdUnsorted)
1921*f6dc9357SAndroid Build Coastguard Worker       {
1922*f6dc9357SAndroid Build Coastguard Worker         const CItemEx &prev = items.Back();
1923*f6dc9357SAndroid Build Coastguard Worker         if (cdItem.Disk < prev.Disk
1924*f6dc9357SAndroid Build Coastguard Worker             || (cdItem.Disk == prev.Disk &&
1925*f6dc9357SAndroid Build Coastguard Worker             cdItem.LocalHeaderPos < prev.LocalHeaderPos))
1926*f6dc9357SAndroid Build Coastguard Worker           IsCdUnsorted = true;
1927*f6dc9357SAndroid Build Coastguard Worker       }
1928*f6dc9357SAndroid Build Coastguard Worker 
1929*f6dc9357SAndroid Build Coastguard Worker       items.Add(cdItem);
1930*f6dc9357SAndroid Build Coastguard Worker     }
1931*f6dc9357SAndroid Build Coastguard Worker     if (Callback && (items.Size() & 0xFFF) == 0)
1932*f6dc9357SAndroid Build Coastguard Worker     {
1933*f6dc9357SAndroid Build Coastguard Worker       const UInt64 numFiles = items.Size();
1934*f6dc9357SAndroid Build Coastguard Worker 
1935*f6dc9357SAndroid Build Coastguard Worker       if (numFiles > numFileExpected && totalFilesPtr)
1936*f6dc9357SAndroid Build Coastguard Worker       {
1937*f6dc9357SAndroid Build Coastguard Worker         if (isCorrect_NumEntries)
1938*f6dc9357SAndroid Build Coastguard Worker           totalFilesPtr = NULL;
1939*f6dc9357SAndroid Build Coastguard Worker         else
1940*f6dc9357SAndroid Build Coastguard Worker           while (numFiles > numFileExpected)
1941*f6dc9357SAndroid Build Coastguard Worker             numFileExpected += (UInt32)1 << 16;
1942*f6dc9357SAndroid Build Coastguard Worker         RINOK(Callback->SetTotal(totalFilesPtr, NULL))
1943*f6dc9357SAndroid Build Coastguard Worker       }
1944*f6dc9357SAndroid Build Coastguard Worker 
1945*f6dc9357SAndroid Build Coastguard Worker       RINOK(Callback->SetCompleted(&numFiles, &_cnt))
1946*f6dc9357SAndroid Build Coastguard Worker     }
1947*f6dc9357SAndroid Build Coastguard Worker   }
1948*f6dc9357SAndroid Build Coastguard Worker 
1949*f6dc9357SAndroid Build Coastguard Worker   CanStartNewVol = true;
1950*f6dc9357SAndroid Build Coastguard Worker 
1951*f6dc9357SAndroid Build Coastguard Worker   return (_cnt == cdSize) ? S_OK : S_FALSE;
1952*f6dc9357SAndroid Build Coastguard Worker }
1953*f6dc9357SAndroid Build Coastguard Worker 
1954*f6dc9357SAndroid Build Coastguard Worker 
1955*f6dc9357SAndroid Build Coastguard Worker /*
1956*f6dc9357SAndroid Build Coastguard Worker static int CompareCdItems(void *const *elem1, void *const *elem2, void *)
1957*f6dc9357SAndroid Build Coastguard Worker {
1958*f6dc9357SAndroid Build Coastguard Worker   const CItemEx *i1 = *(const CItemEx **)elem1;
1959*f6dc9357SAndroid Build Coastguard Worker   const CItemEx *i2 = *(const CItemEx **)elem2;
1960*f6dc9357SAndroid Build Coastguard Worker 
1961*f6dc9357SAndroid Build Coastguard Worker   if (i1->Disk < i2->Disk) return -1;
1962*f6dc9357SAndroid Build Coastguard Worker   if (i1->Disk > i2->Disk) return 1;
1963*f6dc9357SAndroid Build Coastguard Worker   if (i1->LocalHeaderPos < i2->LocalHeaderPos) return -1;
1964*f6dc9357SAndroid Build Coastguard Worker   if (i1->LocalHeaderPos > i2->LocalHeaderPos) return 1;
1965*f6dc9357SAndroid Build Coastguard Worker   if (i1 < i2) return -1;
1966*f6dc9357SAndroid Build Coastguard Worker   if (i1 > i2) return 1;
1967*f6dc9357SAndroid Build Coastguard Worker   return 0;
1968*f6dc9357SAndroid Build Coastguard Worker }
1969*f6dc9357SAndroid Build Coastguard Worker */
1970*f6dc9357SAndroid Build Coastguard Worker 
ReadCd(CObjectVector<CItemEx> & items,UInt32 & cdDisk,UInt64 & cdOffset,UInt64 & cdSize)1971*f6dc9357SAndroid Build Coastguard Worker HRESULT CInArchive::ReadCd(CObjectVector<CItemEx> &items, UInt32 &cdDisk, UInt64 &cdOffset, UInt64 &cdSize)
1972*f6dc9357SAndroid Build Coastguard Worker {
1973*f6dc9357SAndroid Build Coastguard Worker   bool checkOffsetMode = true;
1974*f6dc9357SAndroid Build Coastguard Worker 
1975*f6dc9357SAndroid Build Coastguard Worker   if (IsMultiVol)
1976*f6dc9357SAndroid Build Coastguard Worker   {
1977*f6dc9357SAndroid Build Coastguard Worker     if (Vols.EndVolIndex == -1)
1978*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1979*f6dc9357SAndroid Build Coastguard Worker     Stream = Vols.Streams[(unsigned)Vols.EndVolIndex].Stream;
1980*f6dc9357SAndroid Build Coastguard Worker     if (!Vols.StartIsZip)
1981*f6dc9357SAndroid Build Coastguard Worker       checkOffsetMode = false;
1982*f6dc9357SAndroid Build Coastguard Worker   }
1983*f6dc9357SAndroid Build Coastguard Worker   else
1984*f6dc9357SAndroid Build Coastguard Worker     Stream = StartStream;
1985*f6dc9357SAndroid Build Coastguard Worker 
1986*f6dc9357SAndroid Build Coastguard Worker   if (!Vols.ecd_wasRead)
1987*f6dc9357SAndroid Build Coastguard Worker   {
1988*f6dc9357SAndroid Build Coastguard Worker     RINOK(FindCd(checkOffsetMode))
1989*f6dc9357SAndroid Build Coastguard Worker   }
1990*f6dc9357SAndroid Build Coastguard Worker 
1991*f6dc9357SAndroid Build Coastguard Worker   CCdInfo &cdInfo = Vols.ecd;
1992*f6dc9357SAndroid Build Coastguard Worker 
1993*f6dc9357SAndroid Build Coastguard Worker   HRESULT res = S_FALSE;
1994*f6dc9357SAndroid Build Coastguard Worker 
1995*f6dc9357SAndroid Build Coastguard Worker   cdSize = cdInfo.Size;
1996*f6dc9357SAndroid Build Coastguard Worker   cdOffset = cdInfo.Offset;
1997*f6dc9357SAndroid Build Coastguard Worker   cdDisk = cdInfo.CdDisk;
1998*f6dc9357SAndroid Build Coastguard Worker 
1999*f6dc9357SAndroid Build Coastguard Worker   if (!IsMultiVol)
2000*f6dc9357SAndroid Build Coastguard Worker   {
2001*f6dc9357SAndroid Build Coastguard Worker     if (cdInfo.ThisDisk != cdInfo.CdDisk)
2002*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
2003*f6dc9357SAndroid Build Coastguard Worker   }
2004*f6dc9357SAndroid Build Coastguard Worker 
2005*f6dc9357SAndroid Build Coastguard Worker   const UInt64 base = (IsMultiVol ? 0 : (UInt64)ArcInfo.Base);
2006*f6dc9357SAndroid Build Coastguard Worker   res = TryReadCd(items, cdInfo, base + cdOffset, cdSize);
2007*f6dc9357SAndroid Build Coastguard Worker 
2008*f6dc9357SAndroid Build Coastguard Worker   if (res == S_FALSE && !IsMultiVol && base != ArcInfo.MarkerPos)
2009*f6dc9357SAndroid Build Coastguard Worker   {
2010*f6dc9357SAndroid Build Coastguard Worker     // do we need that additional attempt to read cd?
2011*f6dc9357SAndroid Build Coastguard Worker     res = TryReadCd(items, cdInfo, ArcInfo.MarkerPos + cdOffset, cdSize);
2012*f6dc9357SAndroid Build Coastguard Worker     if (res == S_OK)
2013*f6dc9357SAndroid Build Coastguard Worker       ArcInfo.Base = (Int64)ArcInfo.MarkerPos;
2014*f6dc9357SAndroid Build Coastguard Worker   }
2015*f6dc9357SAndroid Build Coastguard Worker 
2016*f6dc9357SAndroid Build Coastguard Worker   // Some rare case files are unsorted
2017*f6dc9357SAndroid Build Coastguard Worker   // items.Sort(CompareCdItems, NULL);
2018*f6dc9357SAndroid Build Coastguard Worker   return res;
2019*f6dc9357SAndroid Build Coastguard Worker }
2020*f6dc9357SAndroid Build Coastguard Worker 
2021*f6dc9357SAndroid Build Coastguard Worker 
FindItem(const CObjectVector<CItemEx> & items,const CItemEx & item)2022*f6dc9357SAndroid Build Coastguard Worker static int FindItem(const CObjectVector<CItemEx> &items, const CItemEx &item)
2023*f6dc9357SAndroid Build Coastguard Worker {
2024*f6dc9357SAndroid Build Coastguard Worker   unsigned left = 0, right = items.Size();
2025*f6dc9357SAndroid Build Coastguard Worker   for (;;)
2026*f6dc9357SAndroid Build Coastguard Worker   {
2027*f6dc9357SAndroid Build Coastguard Worker     if (left >= right)
2028*f6dc9357SAndroid Build Coastguard Worker       return -1;
2029*f6dc9357SAndroid Build Coastguard Worker     const unsigned index = (unsigned)(((size_t)left + (size_t)right) / 2);
2030*f6dc9357SAndroid Build Coastguard Worker     const CItemEx &item2 = items[index];
2031*f6dc9357SAndroid Build Coastguard Worker     if (item.Disk < item2.Disk)
2032*f6dc9357SAndroid Build Coastguard Worker       right = index;
2033*f6dc9357SAndroid Build Coastguard Worker     else if (item.Disk > item2.Disk)
2034*f6dc9357SAndroid Build Coastguard Worker       left = index + 1;
2035*f6dc9357SAndroid Build Coastguard Worker     else if (item.LocalHeaderPos == item2.LocalHeaderPos)
2036*f6dc9357SAndroid Build Coastguard Worker       return (int)index;
2037*f6dc9357SAndroid Build Coastguard Worker     else if (item.LocalHeaderPos < item2.LocalHeaderPos)
2038*f6dc9357SAndroid Build Coastguard Worker       right = index;
2039*f6dc9357SAndroid Build Coastguard Worker     else
2040*f6dc9357SAndroid Build Coastguard Worker       left = index + 1;
2041*f6dc9357SAndroid Build Coastguard Worker   }
2042*f6dc9357SAndroid Build Coastguard Worker }
2043*f6dc9357SAndroid Build Coastguard Worker 
IsStrangeItem(const CItem & item)2044*f6dc9357SAndroid Build Coastguard Worker static bool IsStrangeItem(const CItem &item)
2045*f6dc9357SAndroid Build Coastguard Worker {
2046*f6dc9357SAndroid Build Coastguard Worker   return item.Name.Len() > (1 << 14) || item.Method > (1 << 8);
2047*f6dc9357SAndroid Build Coastguard Worker }
2048*f6dc9357SAndroid Build Coastguard Worker 
2049*f6dc9357SAndroid Build Coastguard Worker 
2050*f6dc9357SAndroid Build Coastguard Worker 
2051*f6dc9357SAndroid Build Coastguard Worker /*
2052*f6dc9357SAndroid Build Coastguard Worker   ---------- ReadLocals ----------
2053*f6dc9357SAndroid Build Coastguard Worker 
2054*f6dc9357SAndroid Build Coastguard Worker in:
2055*f6dc9357SAndroid Build Coastguard Worker   (_signature == NSignature::kLocalFileHeader)
2056*f6dc9357SAndroid Build Coastguard Worker   VirtStreamPos : after _signature : position in Stream
2057*f6dc9357SAndroid Build Coastguard Worker   Stream :
2058*f6dc9357SAndroid Build Coastguard Worker   Vols : if (IsMultiVol)
2059*f6dc9357SAndroid Build Coastguard Worker   (_inBufMode == false)
2060*f6dc9357SAndroid Build Coastguard Worker 
2061*f6dc9357SAndroid Build Coastguard Worker action:
2062*f6dc9357SAndroid Build Coastguard Worker   it parses local items.
2063*f6dc9357SAndroid Build Coastguard Worker 
2064*f6dc9357SAndroid Build Coastguard Worker   if ( IsMultiVol) it writes absolute offsets to CItemEx::LocalHeaderPos
2065*f6dc9357SAndroid Build Coastguard Worker   if (!IsMultiVol) it writes relative (from ArcInfo.Base) offsets to CItemEx::LocalHeaderPos
2066*f6dc9357SAndroid Build Coastguard Worker                later we can correct CItemEx::LocalHeaderPos values, if
2067*f6dc9357SAndroid Build Coastguard Worker                some new value for ArcInfo.Base will be detected
2068*f6dc9357SAndroid Build Coastguard Worker out:
2069*f6dc9357SAndroid Build Coastguard Worker   S_OK:
2070*f6dc9357SAndroid Build Coastguard Worker     (_signature != NSignature::kLocalFileHeade)
2071*f6dc9357SAndroid Build Coastguard Worker     _streamPos : after _signature
2072*f6dc9357SAndroid Build Coastguard Worker 
2073*f6dc9357SAndroid Build Coastguard Worker   S_FALSE: if no items or there is just one item with strange properies that doesn't look like real archive.
2074*f6dc9357SAndroid Build Coastguard Worker 
2075*f6dc9357SAndroid Build Coastguard Worker   another error code: stream reading error or Callback error.
2076*f6dc9357SAndroid Build Coastguard Worker 
2077*f6dc9357SAndroid Build Coastguard Worker   CUnexpectEnd() exception : it's not fatal exception here.
2078*f6dc9357SAndroid Build Coastguard Worker       It means that reading was interrupted by unexpected end of input stream,
2079*f6dc9357SAndroid Build Coastguard Worker       but some CItemEx items were parsed OK.
2080*f6dc9357SAndroid Build Coastguard Worker       We can stop further archive parsing.
2081*f6dc9357SAndroid Build Coastguard Worker       But we can use all filled CItemEx items.
2082*f6dc9357SAndroid Build Coastguard Worker */
2083*f6dc9357SAndroid Build Coastguard Worker 
ReadLocals(CObjectVector<CItemEx> & items)2084*f6dc9357SAndroid Build Coastguard Worker HRESULT CInArchive::ReadLocals(CObjectVector<CItemEx> &items)
2085*f6dc9357SAndroid Build Coastguard Worker {
2086*f6dc9357SAndroid Build Coastguard Worker   items.Clear();
2087*f6dc9357SAndroid Build Coastguard Worker 
2088*f6dc9357SAndroid Build Coastguard Worker   UInt64 progressPrev = _cnt;
2089*f6dc9357SAndroid Build Coastguard Worker 
2090*f6dc9357SAndroid Build Coastguard Worker   if (Callback)
2091*f6dc9357SAndroid Build Coastguard Worker   {
2092*f6dc9357SAndroid Build Coastguard Worker     RINOK(Callback->SetTotal(NULL, IsMultiVol ? &Vols.TotalBytesSize : NULL))
2093*f6dc9357SAndroid Build Coastguard Worker   }
2094*f6dc9357SAndroid Build Coastguard Worker 
2095*f6dc9357SAndroid Build Coastguard Worker   while (_signature == NSignature::kLocalFileHeader)
2096*f6dc9357SAndroid Build Coastguard Worker   {
2097*f6dc9357SAndroid Build Coastguard Worker     CItemEx item;
2098*f6dc9357SAndroid Build Coastguard Worker 
2099*f6dc9357SAndroid Build Coastguard Worker     item.LocalHeaderPos = GetVirtStreamPos() - 4;
2100*f6dc9357SAndroid Build Coastguard Worker     if (!IsMultiVol)
2101*f6dc9357SAndroid Build Coastguard Worker       item.LocalHeaderPos = (UInt64)((Int64)item.LocalHeaderPos - ArcInfo.Base);
2102*f6dc9357SAndroid Build Coastguard Worker 
2103*f6dc9357SAndroid Build Coastguard Worker     try
2104*f6dc9357SAndroid Build Coastguard Worker     {
2105*f6dc9357SAndroid Build Coastguard Worker       ReadLocalItem(item);
2106*f6dc9357SAndroid Build Coastguard Worker       item.FromLocal = true;
2107*f6dc9357SAndroid Build Coastguard Worker       bool isFinished = false;
2108*f6dc9357SAndroid Build Coastguard Worker 
2109*f6dc9357SAndroid Build Coastguard Worker       if (item.HasDescriptor())
2110*f6dc9357SAndroid Build Coastguard Worker       {
2111*f6dc9357SAndroid Build Coastguard Worker         RINOK(FindDescriptor(item, items.Size()))
2112*f6dc9357SAndroid Build Coastguard Worker         isFinished = !item.DescriptorWasRead;
2113*f6dc9357SAndroid Build Coastguard Worker       }
2114*f6dc9357SAndroid Build Coastguard Worker       else
2115*f6dc9357SAndroid Build Coastguard Worker       {
2116*f6dc9357SAndroid Build Coastguard Worker         if (item.PackSize >= ((UInt64)1 << 62))
2117*f6dc9357SAndroid Build Coastguard Worker           throw CUnexpectEnd();
2118*f6dc9357SAndroid Build Coastguard Worker         RINOK(IncreaseRealPosition(item.PackSize, isFinished))
2119*f6dc9357SAndroid Build Coastguard Worker       }
2120*f6dc9357SAndroid Build Coastguard Worker 
2121*f6dc9357SAndroid Build Coastguard Worker       items.Add(item);
2122*f6dc9357SAndroid Build Coastguard Worker 
2123*f6dc9357SAndroid Build Coastguard Worker       if (isFinished)
2124*f6dc9357SAndroid Build Coastguard Worker         throw CUnexpectEnd();
2125*f6dc9357SAndroid Build Coastguard Worker 
2126*f6dc9357SAndroid Build Coastguard Worker       ReadSignature();
2127*f6dc9357SAndroid Build Coastguard Worker     }
2128*f6dc9357SAndroid Build Coastguard Worker     catch (CUnexpectEnd &)
2129*f6dc9357SAndroid Build Coastguard Worker     {
2130*f6dc9357SAndroid Build Coastguard Worker       if (items.IsEmpty() || (items.Size() == 1 && IsStrangeItem(items[0])))
2131*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
2132*f6dc9357SAndroid Build Coastguard Worker       throw;
2133*f6dc9357SAndroid Build Coastguard Worker     }
2134*f6dc9357SAndroid Build Coastguard Worker 
2135*f6dc9357SAndroid Build Coastguard Worker 
2136*f6dc9357SAndroid Build Coastguard Worker     if (Callback)
2137*f6dc9357SAndroid Build Coastguard Worker     if ((items.Size() & 0xFF) == 0
2138*f6dc9357SAndroid Build Coastguard Worker         || _cnt - progressPrev >= ((UInt32)1 << 22))
2139*f6dc9357SAndroid Build Coastguard Worker     {
2140*f6dc9357SAndroid Build Coastguard Worker       progressPrev = _cnt;
2141*f6dc9357SAndroid Build Coastguard Worker       const UInt64 numFiles = items.Size();
2142*f6dc9357SAndroid Build Coastguard Worker       RINOK(Callback->SetCompleted(&numFiles, &_cnt))
2143*f6dc9357SAndroid Build Coastguard Worker     }
2144*f6dc9357SAndroid Build Coastguard Worker   }
2145*f6dc9357SAndroid Build Coastguard Worker 
2146*f6dc9357SAndroid Build Coastguard Worker   if (items.Size() == 1 && _signature != NSignature::kCentralFileHeader)
2147*f6dc9357SAndroid Build Coastguard Worker     if (IsStrangeItem(items[0]))
2148*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
2149*f6dc9357SAndroid Build Coastguard Worker 
2150*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
2151*f6dc9357SAndroid Build Coastguard Worker }
2152*f6dc9357SAndroid Build Coastguard Worker 
2153*f6dc9357SAndroid Build Coastguard Worker 
2154*f6dc9357SAndroid Build Coastguard Worker 
ParseArcName(IArchiveOpenVolumeCallback * volCallback)2155*f6dc9357SAndroid Build Coastguard Worker HRESULT CVols::ParseArcName(IArchiveOpenVolumeCallback *volCallback)
2156*f6dc9357SAndroid Build Coastguard Worker {
2157*f6dc9357SAndroid Build Coastguard Worker   UString name;
2158*f6dc9357SAndroid Build Coastguard Worker   {
2159*f6dc9357SAndroid Build Coastguard Worker     NWindows::NCOM::CPropVariant prop;
2160*f6dc9357SAndroid Build Coastguard Worker     RINOK(volCallback->GetProperty(kpidName, &prop))
2161*f6dc9357SAndroid Build Coastguard Worker     if (prop.vt != VT_BSTR)
2162*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
2163*f6dc9357SAndroid Build Coastguard Worker     name = prop.bstrVal;
2164*f6dc9357SAndroid Build Coastguard Worker   }
2165*f6dc9357SAndroid Build Coastguard Worker 
2166*f6dc9357SAndroid Build Coastguard Worker   const int dotPos = name.ReverseFind_Dot();
2167*f6dc9357SAndroid Build Coastguard Worker   if (dotPos < 0)
2168*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
2169*f6dc9357SAndroid Build Coastguard Worker   const UString ext = name.Ptr((unsigned)(dotPos + 1));
2170*f6dc9357SAndroid Build Coastguard Worker   name.DeleteFrom((unsigned)(dotPos + 1));
2171*f6dc9357SAndroid Build Coastguard Worker 
2172*f6dc9357SAndroid Build Coastguard Worker   StartVolIndex = (Int32)(-1);
2173*f6dc9357SAndroid Build Coastguard Worker 
2174*f6dc9357SAndroid Build Coastguard Worker   if (ext.IsEmpty())
2175*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
2176*f6dc9357SAndroid Build Coastguard Worker   {
2177*f6dc9357SAndroid Build Coastguard Worker     wchar_t c = ext[0];
2178*f6dc9357SAndroid Build Coastguard Worker     IsUpperCase = (c >= 'A' && c <= 'Z');
2179*f6dc9357SAndroid Build Coastguard Worker     if (ext.IsEqualTo_Ascii_NoCase("zip"))
2180*f6dc9357SAndroid Build Coastguard Worker     {
2181*f6dc9357SAndroid Build Coastguard Worker       BaseName = name;
2182*f6dc9357SAndroid Build Coastguard Worker       StartIsZ = true;
2183*f6dc9357SAndroid Build Coastguard Worker       StartIsZip = true;
2184*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
2185*f6dc9357SAndroid Build Coastguard Worker     }
2186*f6dc9357SAndroid Build Coastguard Worker     else if (ext.IsEqualTo_Ascii_NoCase("exe"))
2187*f6dc9357SAndroid Build Coastguard Worker     {
2188*f6dc9357SAndroid Build Coastguard Worker       /* possible cases:
2189*f6dc9357SAndroid Build Coastguard Worker          - exe with zip inside
2190*f6dc9357SAndroid Build Coastguard Worker          - sfx: a.exe, a.z02, a.z03,... , a.zip
2191*f6dc9357SAndroid Build Coastguard Worker                 a.exe is start volume.
2192*f6dc9357SAndroid Build Coastguard Worker          - zip renamed to exe
2193*f6dc9357SAndroid Build Coastguard Worker       */
2194*f6dc9357SAndroid Build Coastguard Worker 
2195*f6dc9357SAndroid Build Coastguard Worker       StartIsExe = true;
2196*f6dc9357SAndroid Build Coastguard Worker       BaseName = name;
2197*f6dc9357SAndroid Build Coastguard Worker       StartVolIndex = 0;
2198*f6dc9357SAndroid Build Coastguard Worker       /* sfx-zip can use both arc.exe and arc.zip
2199*f6dc9357SAndroid Build Coastguard Worker          We can open arc.zip, if it was requesed to open arc.exe.
2200*f6dc9357SAndroid Build Coastguard Worker          But it's possible that arc.exe and arc.zip are not parts of same archive.
2201*f6dc9357SAndroid Build Coastguard Worker          So we can disable such operation */
2202*f6dc9357SAndroid Build Coastguard Worker 
2203*f6dc9357SAndroid Build Coastguard Worker       // 18.04: we still want to open zip renamed to exe.
2204*f6dc9357SAndroid Build Coastguard Worker       /*
2205*f6dc9357SAndroid Build Coastguard Worker       {
2206*f6dc9357SAndroid Build Coastguard Worker         UString volName = name;
2207*f6dc9357SAndroid Build Coastguard Worker         volName += IsUpperCase ? "Z01" : "z01";
2208*f6dc9357SAndroid Build Coastguard Worker         {
2209*f6dc9357SAndroid Build Coastguard Worker           CMyComPtr<IInStream> stream;
2210*f6dc9357SAndroid Build Coastguard Worker           HRESULT res2 = volCallback->GetStream(volName, &stream);
2211*f6dc9357SAndroid Build Coastguard Worker           if (res2 == S_OK)
2212*f6dc9357SAndroid Build Coastguard Worker             DisableVolsSearch = true;
2213*f6dc9357SAndroid Build Coastguard Worker         }
2214*f6dc9357SAndroid Build Coastguard Worker       }
2215*f6dc9357SAndroid Build Coastguard Worker       */
2216*f6dc9357SAndroid Build Coastguard Worker       DisableVolsSearch = true;
2217*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
2218*f6dc9357SAndroid Build Coastguard Worker     }
2219*f6dc9357SAndroid Build Coastguard Worker     else if (ext[0] == 'z' || ext[0] == 'Z')
2220*f6dc9357SAndroid Build Coastguard Worker     {
2221*f6dc9357SAndroid Build Coastguard Worker       if (ext.Len() < 3)
2222*f6dc9357SAndroid Build Coastguard Worker         return S_OK;
2223*f6dc9357SAndroid Build Coastguard Worker       const wchar_t *end = NULL;
2224*f6dc9357SAndroid Build Coastguard Worker       UInt32 volNum = ConvertStringToUInt32(ext.Ptr(1), &end);
2225*f6dc9357SAndroid Build Coastguard Worker       if (*end != 0 || volNum < 1 || volNum > ((UInt32)1 << 30))
2226*f6dc9357SAndroid Build Coastguard Worker         return S_OK;
2227*f6dc9357SAndroid Build Coastguard Worker       StartVolIndex = (Int32)(volNum - 1);
2228*f6dc9357SAndroid Build Coastguard Worker       BaseName = name;
2229*f6dc9357SAndroid Build Coastguard Worker       StartIsZ = true;
2230*f6dc9357SAndroid Build Coastguard Worker     }
2231*f6dc9357SAndroid Build Coastguard Worker     else
2232*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
2233*f6dc9357SAndroid Build Coastguard Worker   }
2234*f6dc9357SAndroid Build Coastguard Worker 
2235*f6dc9357SAndroid Build Coastguard Worker   UString volName = BaseName;
2236*f6dc9357SAndroid Build Coastguard Worker   volName += (IsUpperCase ? "ZIP" : "zip");
2237*f6dc9357SAndroid Build Coastguard Worker 
2238*f6dc9357SAndroid Build Coastguard Worker   HRESULT res = volCallback->GetStream(volName, &ZipStream);
2239*f6dc9357SAndroid Build Coastguard Worker 
2240*f6dc9357SAndroid Build Coastguard Worker   if (res == S_FALSE || !ZipStream)
2241*f6dc9357SAndroid Build Coastguard Worker   {
2242*f6dc9357SAndroid Build Coastguard Worker     if (MissingName.IsEmpty())
2243*f6dc9357SAndroid Build Coastguard Worker     {
2244*f6dc9357SAndroid Build Coastguard Worker       MissingZip = true;
2245*f6dc9357SAndroid Build Coastguard Worker       MissingName = volName;
2246*f6dc9357SAndroid Build Coastguard Worker     }
2247*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
2248*f6dc9357SAndroid Build Coastguard Worker   }
2249*f6dc9357SAndroid Build Coastguard Worker 
2250*f6dc9357SAndroid Build Coastguard Worker   return res;
2251*f6dc9357SAndroid Build Coastguard Worker }
2252*f6dc9357SAndroid Build Coastguard Worker 
2253*f6dc9357SAndroid Build Coastguard Worker 
ReadVols2(IArchiveOpenVolumeCallback * volCallback,unsigned start,int lastDisk,int zipDisk,unsigned numMissingVolsMax,unsigned & numMissingVols)2254*f6dc9357SAndroid Build Coastguard Worker HRESULT CInArchive::ReadVols2(IArchiveOpenVolumeCallback *volCallback,
2255*f6dc9357SAndroid Build Coastguard Worker     unsigned start, int lastDisk, int zipDisk, unsigned numMissingVolsMax, unsigned &numMissingVols)
2256*f6dc9357SAndroid Build Coastguard Worker {
2257*f6dc9357SAndroid Build Coastguard Worker   if (Vols.DisableVolsSearch)
2258*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
2259*f6dc9357SAndroid Build Coastguard Worker 
2260*f6dc9357SAndroid Build Coastguard Worker   numMissingVols = 0;
2261*f6dc9357SAndroid Build Coastguard Worker 
2262*f6dc9357SAndroid Build Coastguard Worker   for (unsigned i = start;; i++)
2263*f6dc9357SAndroid Build Coastguard Worker   {
2264*f6dc9357SAndroid Build Coastguard Worker     if (lastDisk >= 0 && i >= (unsigned)lastDisk)
2265*f6dc9357SAndroid Build Coastguard Worker       break;
2266*f6dc9357SAndroid Build Coastguard Worker 
2267*f6dc9357SAndroid Build Coastguard Worker     if (i < Vols.Streams.Size())
2268*f6dc9357SAndroid Build Coastguard Worker       if (Vols.Streams[i].Stream)
2269*f6dc9357SAndroid Build Coastguard Worker         continue;
2270*f6dc9357SAndroid Build Coastguard Worker 
2271*f6dc9357SAndroid Build Coastguard Worker     CMyComPtr<IInStream> stream;
2272*f6dc9357SAndroid Build Coastguard Worker 
2273*f6dc9357SAndroid Build Coastguard Worker     if ((int)i == zipDisk)
2274*f6dc9357SAndroid Build Coastguard Worker     {
2275*f6dc9357SAndroid Build Coastguard Worker       stream = Vols.ZipStream;
2276*f6dc9357SAndroid Build Coastguard Worker     }
2277*f6dc9357SAndroid Build Coastguard Worker     else if ((int)i == Vols.StartVolIndex)
2278*f6dc9357SAndroid Build Coastguard Worker     {
2279*f6dc9357SAndroid Build Coastguard Worker       stream = StartStream;
2280*f6dc9357SAndroid Build Coastguard Worker     }
2281*f6dc9357SAndroid Build Coastguard Worker     else
2282*f6dc9357SAndroid Build Coastguard Worker     {
2283*f6dc9357SAndroid Build Coastguard Worker       UString volName = Vols.BaseName;
2284*f6dc9357SAndroid Build Coastguard Worker       {
2285*f6dc9357SAndroid Build Coastguard Worker         volName.Add_Char(Vols.IsUpperCase ? 'Z' : 'z');
2286*f6dc9357SAndroid Build Coastguard Worker         const unsigned v = i + 1;
2287*f6dc9357SAndroid Build Coastguard Worker         if (v < 10)
2288*f6dc9357SAndroid Build Coastguard Worker           volName.Add_Char('0');
2289*f6dc9357SAndroid Build Coastguard Worker         volName.Add_UInt32(v);
2290*f6dc9357SAndroid Build Coastguard Worker       }
2291*f6dc9357SAndroid Build Coastguard Worker 
2292*f6dc9357SAndroid Build Coastguard Worker       HRESULT res = volCallback->GetStream(volName, &stream);
2293*f6dc9357SAndroid Build Coastguard Worker       if (res != S_OK && res != S_FALSE)
2294*f6dc9357SAndroid Build Coastguard Worker         return res;
2295*f6dc9357SAndroid Build Coastguard Worker       if (res == S_FALSE || !stream)
2296*f6dc9357SAndroid Build Coastguard Worker       {
2297*f6dc9357SAndroid Build Coastguard Worker         if (i == 0)
2298*f6dc9357SAndroid Build Coastguard Worker         {
2299*f6dc9357SAndroid Build Coastguard Worker           UString volName_exe = Vols.BaseName;
2300*f6dc9357SAndroid Build Coastguard Worker           volName_exe += (Vols.IsUpperCase ? "EXE" : "exe");
2301*f6dc9357SAndroid Build Coastguard Worker 
2302*f6dc9357SAndroid Build Coastguard Worker           HRESULT res2 = volCallback->GetStream(volName_exe, &stream);
2303*f6dc9357SAndroid Build Coastguard Worker           if (res2 != S_OK && res2 != S_FALSE)
2304*f6dc9357SAndroid Build Coastguard Worker             return res2;
2305*f6dc9357SAndroid Build Coastguard Worker           res = res2;
2306*f6dc9357SAndroid Build Coastguard Worker         }
2307*f6dc9357SAndroid Build Coastguard Worker       }
2308*f6dc9357SAndroid Build Coastguard Worker       if (res == S_FALSE || !stream)
2309*f6dc9357SAndroid Build Coastguard Worker       {
2310*f6dc9357SAndroid Build Coastguard Worker         if (i == 1 && Vols.StartIsExe)
2311*f6dc9357SAndroid Build Coastguard Worker           return S_OK;
2312*f6dc9357SAndroid Build Coastguard Worker         if (Vols.MissingName.IsEmpty())
2313*f6dc9357SAndroid Build Coastguard Worker           Vols.MissingName = volName;
2314*f6dc9357SAndroid Build Coastguard Worker         numMissingVols++;
2315*f6dc9357SAndroid Build Coastguard Worker         if (numMissingVols > numMissingVolsMax)
2316*f6dc9357SAndroid Build Coastguard Worker           return S_OK;
2317*f6dc9357SAndroid Build Coastguard Worker         if (lastDisk == -1 && numMissingVols != 0)
2318*f6dc9357SAndroid Build Coastguard Worker           return S_OK;
2319*f6dc9357SAndroid Build Coastguard Worker         continue;
2320*f6dc9357SAndroid Build Coastguard Worker       }
2321*f6dc9357SAndroid Build Coastguard Worker     }
2322*f6dc9357SAndroid Build Coastguard Worker 
2323*f6dc9357SAndroid Build Coastguard Worker     UInt64 pos, size;
2324*f6dc9357SAndroid Build Coastguard Worker     RINOK(InStream_GetPos_GetSize(stream, pos, size))
2325*f6dc9357SAndroid Build Coastguard Worker 
2326*f6dc9357SAndroid Build Coastguard Worker     while (i >= Vols.Streams.Size())
2327*f6dc9357SAndroid Build Coastguard Worker       Vols.Streams.AddNew();
2328*f6dc9357SAndroid Build Coastguard Worker 
2329*f6dc9357SAndroid Build Coastguard Worker     CVols::CSubStreamInfo &ss = Vols.Streams[i];
2330*f6dc9357SAndroid Build Coastguard Worker     Vols.NumVols++;
2331*f6dc9357SAndroid Build Coastguard Worker     Vols.TotalBytesSize += size;
2332*f6dc9357SAndroid Build Coastguard Worker 
2333*f6dc9357SAndroid Build Coastguard Worker     ss.Stream = stream;
2334*f6dc9357SAndroid Build Coastguard Worker     ss.Size = size;
2335*f6dc9357SAndroid Build Coastguard Worker 
2336*f6dc9357SAndroid Build Coastguard Worker     if ((int)i == zipDisk)
2337*f6dc9357SAndroid Build Coastguard Worker     {
2338*f6dc9357SAndroid Build Coastguard Worker       Vols.EndVolIndex = (int)(Vols.Streams.Size() - 1);
2339*f6dc9357SAndroid Build Coastguard Worker       break;
2340*f6dc9357SAndroid Build Coastguard Worker     }
2341*f6dc9357SAndroid Build Coastguard Worker   }
2342*f6dc9357SAndroid Build Coastguard Worker 
2343*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
2344*f6dc9357SAndroid Build Coastguard Worker }
2345*f6dc9357SAndroid Build Coastguard Worker 
2346*f6dc9357SAndroid Build Coastguard Worker 
ReadVols()2347*f6dc9357SAndroid Build Coastguard Worker HRESULT CInArchive::ReadVols()
2348*f6dc9357SAndroid Build Coastguard Worker {
2349*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<IArchiveOpenVolumeCallback> volCallback;
2350*f6dc9357SAndroid Build Coastguard Worker 
2351*f6dc9357SAndroid Build Coastguard Worker   Callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&volCallback);
2352*f6dc9357SAndroid Build Coastguard Worker   if (!volCallback)
2353*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
2354*f6dc9357SAndroid Build Coastguard Worker 
2355*f6dc9357SAndroid Build Coastguard Worker   RINOK(Vols.ParseArcName(volCallback))
2356*f6dc9357SAndroid Build Coastguard Worker 
2357*f6dc9357SAndroid Build Coastguard Worker   // const int startZIndex = Vols.StartVolIndex;
2358*f6dc9357SAndroid Build Coastguard Worker 
2359*f6dc9357SAndroid Build Coastguard Worker   if (!Vols.StartIsZ)
2360*f6dc9357SAndroid Build Coastguard Worker   {
2361*f6dc9357SAndroid Build Coastguard Worker     if (!Vols.StartIsExe)
2362*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
2363*f6dc9357SAndroid Build Coastguard Worker   }
2364*f6dc9357SAndroid Build Coastguard Worker 
2365*f6dc9357SAndroid Build Coastguard Worker   int zipDisk = -1;
2366*f6dc9357SAndroid Build Coastguard Worker   int cdDisk = -1;
2367*f6dc9357SAndroid Build Coastguard Worker 
2368*f6dc9357SAndroid Build Coastguard Worker   if (Vols.StartIsZip)
2369*f6dc9357SAndroid Build Coastguard Worker     Vols.ZipStream = StartStream;
2370*f6dc9357SAndroid Build Coastguard Worker 
2371*f6dc9357SAndroid Build Coastguard Worker   if (Vols.ZipStream)
2372*f6dc9357SAndroid Build Coastguard Worker   {
2373*f6dc9357SAndroid Build Coastguard Worker     Stream = Vols.ZipStream;
2374*f6dc9357SAndroid Build Coastguard Worker 
2375*f6dc9357SAndroid Build Coastguard Worker     if (Vols.StartIsZip)
2376*f6dc9357SAndroid Build Coastguard Worker       Vols.StreamIndex = -1;
2377*f6dc9357SAndroid Build Coastguard Worker     else
2378*f6dc9357SAndroid Build Coastguard Worker     {
2379*f6dc9357SAndroid Build Coastguard Worker       Vols.StreamIndex = -2;
2380*f6dc9357SAndroid Build Coastguard Worker       InitBuf();
2381*f6dc9357SAndroid Build Coastguard Worker     }
2382*f6dc9357SAndroid Build Coastguard Worker 
2383*f6dc9357SAndroid Build Coastguard Worker     HRESULT res = FindCd(true);
2384*f6dc9357SAndroid Build Coastguard Worker 
2385*f6dc9357SAndroid Build Coastguard Worker     CCdInfo &ecd = Vols.ecd;
2386*f6dc9357SAndroid Build Coastguard Worker     if (res == S_OK)
2387*f6dc9357SAndroid Build Coastguard Worker     {
2388*f6dc9357SAndroid Build Coastguard Worker       zipDisk = (int)ecd.ThisDisk;
2389*f6dc9357SAndroid Build Coastguard Worker       Vols.ecd_wasRead = true;
2390*f6dc9357SAndroid Build Coastguard Worker 
2391*f6dc9357SAndroid Build Coastguard Worker       // if is not multivol or bad multivol, we return to main single stream code
2392*f6dc9357SAndroid Build Coastguard Worker       if (ecd.ThisDisk == 0
2393*f6dc9357SAndroid Build Coastguard Worker           || ecd.ThisDisk >= ((UInt32)1 << 30)
2394*f6dc9357SAndroid Build Coastguard Worker           || ecd.ThisDisk < ecd.CdDisk)
2395*f6dc9357SAndroid Build Coastguard Worker         return S_OK;
2396*f6dc9357SAndroid Build Coastguard Worker 
2397*f6dc9357SAndroid Build Coastguard Worker       cdDisk = (int)ecd.CdDisk;
2398*f6dc9357SAndroid Build Coastguard Worker       if (Vols.StartVolIndex < 0)
2399*f6dc9357SAndroid Build Coastguard Worker         Vols.StartVolIndex = (Int32)ecd.ThisDisk;
2400*f6dc9357SAndroid Build Coastguard Worker       else if ((UInt32)Vols.StartVolIndex >= ecd.ThisDisk)
2401*f6dc9357SAndroid Build Coastguard Worker         return S_OK;
2402*f6dc9357SAndroid Build Coastguard Worker 
2403*f6dc9357SAndroid Build Coastguard Worker       // Vols.StartVolIndex = ecd.ThisDisk;
2404*f6dc9357SAndroid Build Coastguard Worker       // Vols.EndVolIndex = ecd.ThisDisk;
2405*f6dc9357SAndroid Build Coastguard Worker       unsigned numMissingVols;
2406*f6dc9357SAndroid Build Coastguard Worker       if (cdDisk != zipDisk)
2407*f6dc9357SAndroid Build Coastguard Worker       {
2408*f6dc9357SAndroid Build Coastguard Worker         // get volumes required for cd.
2409*f6dc9357SAndroid Build Coastguard Worker         RINOK(ReadVols2(volCallback, (unsigned)cdDisk, zipDisk, zipDisk, 0, numMissingVols))
2410*f6dc9357SAndroid Build Coastguard Worker         if (numMissingVols != 0)
2411*f6dc9357SAndroid Build Coastguard Worker         {
2412*f6dc9357SAndroid Build Coastguard Worker           // cdOK = false;
2413*f6dc9357SAndroid Build Coastguard Worker         }
2414*f6dc9357SAndroid Build Coastguard Worker       }
2415*f6dc9357SAndroid Build Coastguard Worker     }
2416*f6dc9357SAndroid Build Coastguard Worker     else if (res != S_FALSE)
2417*f6dc9357SAndroid Build Coastguard Worker       return res;
2418*f6dc9357SAndroid Build Coastguard Worker   }
2419*f6dc9357SAndroid Build Coastguard Worker 
2420*f6dc9357SAndroid Build Coastguard Worker   if (Vols.StartVolIndex < 0)
2421*f6dc9357SAndroid Build Coastguard Worker   {
2422*f6dc9357SAndroid Build Coastguard Worker     // is not mutivol;
2423*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
2424*f6dc9357SAndroid Build Coastguard Worker   }
2425*f6dc9357SAndroid Build Coastguard Worker 
2426*f6dc9357SAndroid Build Coastguard Worker   /*
2427*f6dc9357SAndroid Build Coastguard Worker   if (!Vols.Streams.IsEmpty())
2428*f6dc9357SAndroid Build Coastguard Worker     IsMultiVol = true;
2429*f6dc9357SAndroid Build Coastguard Worker   */
2430*f6dc9357SAndroid Build Coastguard Worker 
2431*f6dc9357SAndroid Build Coastguard Worker   unsigned numMissingVols;
2432*f6dc9357SAndroid Build Coastguard Worker 
2433*f6dc9357SAndroid Build Coastguard Worker   if (cdDisk != 0)
2434*f6dc9357SAndroid Build Coastguard Worker   {
2435*f6dc9357SAndroid Build Coastguard Worker     // get volumes that were no requested still
2436*f6dc9357SAndroid Build Coastguard Worker     const unsigned kNumMissingVolsMax = 1 << 12;
2437*f6dc9357SAndroid Build Coastguard Worker     RINOK(ReadVols2(volCallback, 0, cdDisk < 0 ? -1 : cdDisk, zipDisk, kNumMissingVolsMax, numMissingVols))
2438*f6dc9357SAndroid Build Coastguard Worker   }
2439*f6dc9357SAndroid Build Coastguard Worker 
2440*f6dc9357SAndroid Build Coastguard Worker   // if (Vols.StartVolIndex >= 0)
2441*f6dc9357SAndroid Build Coastguard Worker   {
2442*f6dc9357SAndroid Build Coastguard Worker     if (Vols.Streams.IsEmpty())
2443*f6dc9357SAndroid Build Coastguard Worker       if (Vols.StartVolIndex > (1 << 20))
2444*f6dc9357SAndroid Build Coastguard Worker         return S_OK;
2445*f6dc9357SAndroid Build Coastguard Worker     if ((unsigned)Vols.StartVolIndex >= Vols.Streams.Size()
2446*f6dc9357SAndroid Build Coastguard Worker         || !Vols.Streams[(unsigned)Vols.StartVolIndex].Stream)
2447*f6dc9357SAndroid Build Coastguard Worker     {
2448*f6dc9357SAndroid Build Coastguard Worker       // we get volumes starting from StartVolIndex, if they we not requested before know the volume index (if FindCd() was ok)
2449*f6dc9357SAndroid Build Coastguard Worker       RINOK(ReadVols2(volCallback, (unsigned)Vols.StartVolIndex, zipDisk, zipDisk, 0, numMissingVols))
2450*f6dc9357SAndroid Build Coastguard Worker     }
2451*f6dc9357SAndroid Build Coastguard Worker   }
2452*f6dc9357SAndroid Build Coastguard Worker 
2453*f6dc9357SAndroid Build Coastguard Worker   if (Vols.ZipStream)
2454*f6dc9357SAndroid Build Coastguard Worker   {
2455*f6dc9357SAndroid Build Coastguard Worker     // if there is no another volumes and volumeIndex is too big, we don't use multivol mode
2456*f6dc9357SAndroid Build Coastguard Worker     if (Vols.Streams.IsEmpty())
2457*f6dc9357SAndroid Build Coastguard Worker       if (zipDisk > (1 << 10))
2458*f6dc9357SAndroid Build Coastguard Worker         return S_OK;
2459*f6dc9357SAndroid Build Coastguard Worker     if (zipDisk >= 0)
2460*f6dc9357SAndroid Build Coastguard Worker     {
2461*f6dc9357SAndroid Build Coastguard Worker       // we create item in Streams for ZipStream, if we know the volume index (if FindCd() was ok)
2462*f6dc9357SAndroid Build Coastguard Worker       RINOK(ReadVols2(volCallback, (unsigned)zipDisk, zipDisk + 1, zipDisk, 0, numMissingVols))
2463*f6dc9357SAndroid Build Coastguard Worker     }
2464*f6dc9357SAndroid Build Coastguard Worker   }
2465*f6dc9357SAndroid Build Coastguard Worker 
2466*f6dc9357SAndroid Build Coastguard Worker   if (!Vols.Streams.IsEmpty())
2467*f6dc9357SAndroid Build Coastguard Worker   {
2468*f6dc9357SAndroid Build Coastguard Worker     IsMultiVol = true;
2469*f6dc9357SAndroid Build Coastguard Worker     /*
2470*f6dc9357SAndroid Build Coastguard Worker     if (cdDisk)
2471*f6dc9357SAndroid Build Coastguard Worker       IsMultiVol = true;
2472*f6dc9357SAndroid Build Coastguard Worker     */
2473*f6dc9357SAndroid Build Coastguard Worker     const int startZIndex = Vols.StartVolIndex;
2474*f6dc9357SAndroid Build Coastguard Worker     if (startZIndex >= 0)
2475*f6dc9357SAndroid Build Coastguard Worker     {
2476*f6dc9357SAndroid Build Coastguard Worker       // if all volumes before start volume are OK, we can start parsing from 0
2477*f6dc9357SAndroid Build Coastguard Worker       // if there are missing volumes before startZIndex, we start parsing in current startZIndex
2478*f6dc9357SAndroid Build Coastguard Worker       if ((unsigned)startZIndex < Vols.Streams.Size())
2479*f6dc9357SAndroid Build Coastguard Worker       {
2480*f6dc9357SAndroid Build Coastguard Worker         for (unsigned i = 0; i <= (unsigned)startZIndex; i++)
2481*f6dc9357SAndroid Build Coastguard Worker           if (!Vols.Streams[i].Stream)
2482*f6dc9357SAndroid Build Coastguard Worker           {
2483*f6dc9357SAndroid Build Coastguard Worker             Vols.StartParsingVol = startZIndex;
2484*f6dc9357SAndroid Build Coastguard Worker             break;
2485*f6dc9357SAndroid Build Coastguard Worker           }
2486*f6dc9357SAndroid Build Coastguard Worker       }
2487*f6dc9357SAndroid Build Coastguard Worker     }
2488*f6dc9357SAndroid Build Coastguard Worker   }
2489*f6dc9357SAndroid Build Coastguard Worker 
2490*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
2491*f6dc9357SAndroid Build Coastguard Worker }
2492*f6dc9357SAndroid Build Coastguard Worker 
2493*f6dc9357SAndroid Build Coastguard Worker 
2494*f6dc9357SAndroid Build Coastguard Worker 
Read(void * data,UInt32 size,UInt32 * processedSize)2495*f6dc9357SAndroid Build Coastguard Worker HRESULT CVols::Read(void *data, UInt32 size, UInt32 *processedSize)
2496*f6dc9357SAndroid Build Coastguard Worker {
2497*f6dc9357SAndroid Build Coastguard Worker   if (processedSize)
2498*f6dc9357SAndroid Build Coastguard Worker     *processedSize = 0;
2499*f6dc9357SAndroid Build Coastguard Worker   if (size == 0)
2500*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
2501*f6dc9357SAndroid Build Coastguard Worker 
2502*f6dc9357SAndroid Build Coastguard Worker   for (;;)
2503*f6dc9357SAndroid Build Coastguard Worker   {
2504*f6dc9357SAndroid Build Coastguard Worker     if (StreamIndex < 0)
2505*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
2506*f6dc9357SAndroid Build Coastguard Worker     if ((unsigned)StreamIndex >= Streams.Size())
2507*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
2508*f6dc9357SAndroid Build Coastguard Worker     const CVols::CSubStreamInfo &s = Streams[(unsigned)StreamIndex];
2509*f6dc9357SAndroid Build Coastguard Worker     if (!s.Stream)
2510*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
2511*f6dc9357SAndroid Build Coastguard Worker     if (NeedSeek)
2512*f6dc9357SAndroid Build Coastguard Worker     {
2513*f6dc9357SAndroid Build Coastguard Worker       RINOK(s.SeekToStart())
2514*f6dc9357SAndroid Build Coastguard Worker       NeedSeek = false;
2515*f6dc9357SAndroid Build Coastguard Worker     }
2516*f6dc9357SAndroid Build Coastguard Worker     UInt32 realProcessedSize = 0;
2517*f6dc9357SAndroid Build Coastguard Worker     HRESULT res = s.Stream->Read(data, size, &realProcessedSize);
2518*f6dc9357SAndroid Build Coastguard Worker     if (processedSize)
2519*f6dc9357SAndroid Build Coastguard Worker       *processedSize = realProcessedSize;
2520*f6dc9357SAndroid Build Coastguard Worker     if (res != S_OK)
2521*f6dc9357SAndroid Build Coastguard Worker       return res;
2522*f6dc9357SAndroid Build Coastguard Worker     if (realProcessedSize != 0)
2523*f6dc9357SAndroid Build Coastguard Worker       return res;
2524*f6dc9357SAndroid Build Coastguard Worker     StreamIndex++;
2525*f6dc9357SAndroid Build Coastguard Worker     NeedSeek = true;
2526*f6dc9357SAndroid Build Coastguard Worker   }
2527*f6dc9357SAndroid Build Coastguard Worker }
2528*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CVolStream::Read (void * data,UInt32 size,UInt32 * processedSize))2529*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CVolStream::Read(void *data, UInt32 size, UInt32 *processedSize))
2530*f6dc9357SAndroid Build Coastguard Worker {
2531*f6dc9357SAndroid Build Coastguard Worker   return Vols->Read(data, size, processedSize);
2532*f6dc9357SAndroid Build Coastguard Worker }
2533*f6dc9357SAndroid Build Coastguard Worker 
2534*f6dc9357SAndroid Build Coastguard Worker 
2535*f6dc9357SAndroid Build Coastguard Worker 
2536*f6dc9357SAndroid Build Coastguard Worker 
2537*f6dc9357SAndroid Build Coastguard Worker #define COPY_ECD_ITEM_16(n) if (!isZip64 || !ZIP64_IS_16_MAX(ecd. n))     cdInfo. n = ecd. n;
2538*f6dc9357SAndroid Build Coastguard Worker #define COPY_ECD_ITEM_32(n) if (!isZip64 || !ZIP64_IS_32_MAX(ecd. n)) cdInfo. n = ecd. n;
2539*f6dc9357SAndroid Build Coastguard Worker 
2540*f6dc9357SAndroid Build Coastguard Worker 
ReadHeaders(CObjectVector<CItemEx> & items)2541*f6dc9357SAndroid Build Coastguard Worker HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items)
2542*f6dc9357SAndroid Build Coastguard Worker {
2543*f6dc9357SAndroid Build Coastguard Worker   // buffer that can be used for cd reading
2544*f6dc9357SAndroid Build Coastguard Worker   RINOK(AllocateBuffer(kSeqBufferSize))
2545*f6dc9357SAndroid Build Coastguard Worker 
2546*f6dc9357SAndroid Build Coastguard Worker   // here we can read small records. So we switch off _inBufMode.
2547*f6dc9357SAndroid Build Coastguard Worker   _inBufMode = false;
2548*f6dc9357SAndroid Build Coastguard Worker 
2549*f6dc9357SAndroid Build Coastguard Worker   HRESULT res = S_OK;
2550*f6dc9357SAndroid Build Coastguard Worker 
2551*f6dc9357SAndroid Build Coastguard Worker   bool localsWereRead = false;
2552*f6dc9357SAndroid Build Coastguard Worker 
2553*f6dc9357SAndroid Build Coastguard Worker   /* we try to open archive with the following modes:
2554*f6dc9357SAndroid Build Coastguard Worker      1) CD-MODE        : fast mode : we read backward ECD and CD, compare CD items with first Local item.
2555*f6dc9357SAndroid Build Coastguard Worker      2) LOCALS-CD-MODE : slow mode, if CD-MODE fails : we sequentially read all Locals and then CD.
2556*f6dc9357SAndroid Build Coastguard Worker      Then we read sequentially ECD64, Locator, ECD again at the end.
2557*f6dc9357SAndroid Build Coastguard Worker 
2558*f6dc9357SAndroid Build Coastguard Worker      - in LOCALS-CD-MODE we use use the following
2559*f6dc9357SAndroid Build Coastguard Worker          variables (with real cd properties) to set Base archive offset
2560*f6dc9357SAndroid Build Coastguard Worker          and check real cd properties with values from ECD/ECD64.
2561*f6dc9357SAndroid Build Coastguard Worker   */
2562*f6dc9357SAndroid Build Coastguard Worker 
2563*f6dc9357SAndroid Build Coastguard Worker   UInt64 cdSize = 0;
2564*f6dc9357SAndroid Build Coastguard Worker   UInt64 cdRelatOffset = 0;
2565*f6dc9357SAndroid Build Coastguard Worker   UInt32 cdDisk = 0;
2566*f6dc9357SAndroid Build Coastguard Worker 
2567*f6dc9357SAndroid Build Coastguard Worker   UInt64 cdAbsOffset = 0;   // absolute cd offset, for LOCALS-CD-MODE only.
2568*f6dc9357SAndroid Build Coastguard Worker 
2569*f6dc9357SAndroid Build Coastguard Worker if (Force_ReadLocals_Mode)
2570*f6dc9357SAndroid Build Coastguard Worker {
2571*f6dc9357SAndroid Build Coastguard Worker   IsArc = true;
2572*f6dc9357SAndroid Build Coastguard Worker   res = S_FALSE; // we will use LOCALS-CD-MODE mode
2573*f6dc9357SAndroid Build Coastguard Worker }
2574*f6dc9357SAndroid Build Coastguard Worker else
2575*f6dc9357SAndroid Build Coastguard Worker {
2576*f6dc9357SAndroid Build Coastguard Worker   if (!MarkerIsFound || !MarkerIsSafe)
2577*f6dc9357SAndroid Build Coastguard Worker   {
2578*f6dc9357SAndroid Build Coastguard Worker     IsArc = true;
2579*f6dc9357SAndroid Build Coastguard Worker     res = ReadCd(items, cdDisk, cdRelatOffset, cdSize);
2580*f6dc9357SAndroid Build Coastguard Worker     if (res == S_OK)
2581*f6dc9357SAndroid Build Coastguard Worker       ReadSignature();
2582*f6dc9357SAndroid Build Coastguard Worker     else if (res != S_FALSE)
2583*f6dc9357SAndroid Build Coastguard Worker       return res;
2584*f6dc9357SAndroid Build Coastguard Worker   }
2585*f6dc9357SAndroid Build Coastguard Worker   else  // (MarkerIsFound && MarkerIsSafe)
2586*f6dc9357SAndroid Build Coastguard Worker   {
2587*f6dc9357SAndroid Build Coastguard Worker 
2588*f6dc9357SAndroid Build Coastguard Worker   // _signature must be kLocalFileHeader or kEcd or kEcd64
2589*f6dc9357SAndroid Build Coastguard Worker 
2590*f6dc9357SAndroid Build Coastguard Worker   SeekToVol(ArcInfo.MarkerVolIndex, ArcInfo.MarkerPos2 + 4);
2591*f6dc9357SAndroid Build Coastguard Worker 
2592*f6dc9357SAndroid Build Coastguard Worker   CanStartNewVol = false;
2593*f6dc9357SAndroid Build Coastguard Worker 
2594*f6dc9357SAndroid Build Coastguard Worker   if (_signature == NSignature::kEcd64)
2595*f6dc9357SAndroid Build Coastguard Worker   {
2596*f6dc9357SAndroid Build Coastguard Worker     // UInt64 ecd64Offset = GetVirtStreamPos() - 4;
2597*f6dc9357SAndroid Build Coastguard Worker     IsZip64 = true;
2598*f6dc9357SAndroid Build Coastguard Worker 
2599*f6dc9357SAndroid Build Coastguard Worker     {
2600*f6dc9357SAndroid Build Coastguard Worker       const UInt64 recordSize = ReadUInt64();
2601*f6dc9357SAndroid Build Coastguard Worker       if (recordSize < kEcd64_MainSize)
2602*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
2603*f6dc9357SAndroid Build Coastguard Worker       if (recordSize >= ((UInt64)1 << 62))
2604*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
2605*f6dc9357SAndroid Build Coastguard Worker 
2606*f6dc9357SAndroid Build Coastguard Worker       {
2607*f6dc9357SAndroid Build Coastguard Worker         const unsigned kBufSize = kEcd64_MainSize;
2608*f6dc9357SAndroid Build Coastguard Worker         Byte buf[kBufSize];
2609*f6dc9357SAndroid Build Coastguard Worker         SafeRead(buf, kBufSize);
2610*f6dc9357SAndroid Build Coastguard Worker         CCdInfo cdInfo;
2611*f6dc9357SAndroid Build Coastguard Worker         cdInfo.ParseEcd64e(buf);
2612*f6dc9357SAndroid Build Coastguard Worker         if (!cdInfo.IsEmptyArc())
2613*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
2614*f6dc9357SAndroid Build Coastguard Worker       }
2615*f6dc9357SAndroid Build Coastguard Worker 
2616*f6dc9357SAndroid Build Coastguard Worker       RINOK(Skip64(recordSize - kEcd64_MainSize, 0))
2617*f6dc9357SAndroid Build Coastguard Worker     }
2618*f6dc9357SAndroid Build Coastguard Worker 
2619*f6dc9357SAndroid Build Coastguard Worker     ReadSignature();
2620*f6dc9357SAndroid Build Coastguard Worker     if (_signature != NSignature::kEcd64Locator)
2621*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
2622*f6dc9357SAndroid Build Coastguard Worker 
2623*f6dc9357SAndroid Build Coastguard Worker     {
2624*f6dc9357SAndroid Build Coastguard Worker       const unsigned kBufSize = 16;
2625*f6dc9357SAndroid Build Coastguard Worker       Byte buf[kBufSize];
2626*f6dc9357SAndroid Build Coastguard Worker       SafeRead(buf, kBufSize);
2627*f6dc9357SAndroid Build Coastguard Worker       CLocator locator;
2628*f6dc9357SAndroid Build Coastguard Worker       locator.Parse(buf);
2629*f6dc9357SAndroid Build Coastguard Worker       if (!locator.IsEmptyArc())
2630*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
2631*f6dc9357SAndroid Build Coastguard Worker     }
2632*f6dc9357SAndroid Build Coastguard Worker 
2633*f6dc9357SAndroid Build Coastguard Worker     ReadSignature();
2634*f6dc9357SAndroid Build Coastguard Worker     if (_signature != NSignature::kEcd)
2635*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
2636*f6dc9357SAndroid Build Coastguard Worker   }
2637*f6dc9357SAndroid Build Coastguard Worker 
2638*f6dc9357SAndroid Build Coastguard Worker   if (_signature == NSignature::kEcd)
2639*f6dc9357SAndroid Build Coastguard Worker   {
2640*f6dc9357SAndroid Build Coastguard Worker     // It must be empty archive or backware archive
2641*f6dc9357SAndroid Build Coastguard Worker     // we don't support backware archive still
2642*f6dc9357SAndroid Build Coastguard Worker 
2643*f6dc9357SAndroid Build Coastguard Worker     const unsigned kBufSize = kEcdSize - 4;
2644*f6dc9357SAndroid Build Coastguard Worker     Byte buf[kBufSize];
2645*f6dc9357SAndroid Build Coastguard Worker     SafeRead(buf, kBufSize);
2646*f6dc9357SAndroid Build Coastguard Worker     CEcd ecd;
2647*f6dc9357SAndroid Build Coastguard Worker     ecd.Parse(buf);
2648*f6dc9357SAndroid Build Coastguard Worker     // if (ecd.cdSize != 0)
2649*f6dc9357SAndroid Build Coastguard Worker     // Do we need also to support the case where empty zip archive with PK00 uses cdOffset = 4 ??
2650*f6dc9357SAndroid Build Coastguard Worker     if (!ecd.IsEmptyArc())
2651*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
2652*f6dc9357SAndroid Build Coastguard Worker 
2653*f6dc9357SAndroid Build Coastguard Worker     ArcInfo.Base = (Int64)ArcInfo.MarkerPos;
2654*f6dc9357SAndroid Build Coastguard Worker     IsArc = true; // check it: we need more tests?
2655*f6dc9357SAndroid Build Coastguard Worker 
2656*f6dc9357SAndroid Build Coastguard Worker     RINOK(SeekToVol(ArcInfo.MarkerVolIndex, ArcInfo.MarkerPos2))
2657*f6dc9357SAndroid Build Coastguard Worker     ReadSignature();
2658*f6dc9357SAndroid Build Coastguard Worker   }
2659*f6dc9357SAndroid Build Coastguard Worker   else
2660*f6dc9357SAndroid Build Coastguard Worker   {
2661*f6dc9357SAndroid Build Coastguard Worker     CItemEx firstItem;
2662*f6dc9357SAndroid Build Coastguard Worker     try
2663*f6dc9357SAndroid Build Coastguard Worker     {
2664*f6dc9357SAndroid Build Coastguard Worker       try
2665*f6dc9357SAndroid Build Coastguard Worker       {
2666*f6dc9357SAndroid Build Coastguard Worker         if (!ReadLocalItem(firstItem))
2667*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
2668*f6dc9357SAndroid Build Coastguard Worker       }
2669*f6dc9357SAndroid Build Coastguard Worker       catch(CUnexpectEnd &)
2670*f6dc9357SAndroid Build Coastguard Worker       {
2671*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
2672*f6dc9357SAndroid Build Coastguard Worker       }
2673*f6dc9357SAndroid Build Coastguard Worker 
2674*f6dc9357SAndroid Build Coastguard Worker       IsArc = true;
2675*f6dc9357SAndroid Build Coastguard Worker       res = ReadCd(items, cdDisk, cdRelatOffset, cdSize);
2676*f6dc9357SAndroid Build Coastguard Worker       if (res == S_OK)
2677*f6dc9357SAndroid Build Coastguard Worker         ReadSignature();
2678*f6dc9357SAndroid Build Coastguard Worker     }
2679*f6dc9357SAndroid Build Coastguard Worker     catch(CUnexpectEnd &) { res = S_FALSE; }
2680*f6dc9357SAndroid Build Coastguard Worker 
2681*f6dc9357SAndroid Build Coastguard Worker     if (res != S_FALSE && res != S_OK)
2682*f6dc9357SAndroid Build Coastguard Worker       return res;
2683*f6dc9357SAndroid Build Coastguard Worker 
2684*f6dc9357SAndroid Build Coastguard Worker     if (res == S_OK && items.Size() == 0)
2685*f6dc9357SAndroid Build Coastguard Worker       res = S_FALSE;
2686*f6dc9357SAndroid Build Coastguard Worker 
2687*f6dc9357SAndroid Build Coastguard Worker     if (res == S_OK)
2688*f6dc9357SAndroid Build Coastguard Worker     {
2689*f6dc9357SAndroid Build Coastguard Worker       // we can't read local items here to keep _inBufMode state
2690*f6dc9357SAndroid Build Coastguard Worker       if ((Int64)ArcInfo.MarkerPos2 < ArcInfo.Base)
2691*f6dc9357SAndroid Build Coastguard Worker         res = S_FALSE;
2692*f6dc9357SAndroid Build Coastguard Worker       else
2693*f6dc9357SAndroid Build Coastguard Worker       {
2694*f6dc9357SAndroid Build Coastguard Worker         firstItem.LocalHeaderPos = (UInt64)((Int64)ArcInfo.MarkerPos2 - ArcInfo.Base);
2695*f6dc9357SAndroid Build Coastguard Worker         int index = -1;
2696*f6dc9357SAndroid Build Coastguard Worker 
2697*f6dc9357SAndroid Build Coastguard Worker         UInt32 min_Disk = (UInt32)(Int32)-1;
2698*f6dc9357SAndroid Build Coastguard Worker         UInt64 min_LocalHeaderPos = (UInt64)(Int64)-1;
2699*f6dc9357SAndroid Build Coastguard Worker 
2700*f6dc9357SAndroid Build Coastguard Worker         if (!IsCdUnsorted)
2701*f6dc9357SAndroid Build Coastguard Worker           index = FindItem(items, firstItem);
2702*f6dc9357SAndroid Build Coastguard Worker         else
2703*f6dc9357SAndroid Build Coastguard Worker         {
2704*f6dc9357SAndroid Build Coastguard Worker           FOR_VECTOR (i, items)
2705*f6dc9357SAndroid Build Coastguard Worker           {
2706*f6dc9357SAndroid Build Coastguard Worker             const CItemEx &cdItem = items[i];
2707*f6dc9357SAndroid Build Coastguard Worker             if (cdItem.Disk == firstItem.Disk
2708*f6dc9357SAndroid Build Coastguard Worker                 && (cdItem.LocalHeaderPos == firstItem.LocalHeaderPos))
2709*f6dc9357SAndroid Build Coastguard Worker               index = (int)i;
2710*f6dc9357SAndroid Build Coastguard Worker 
2711*f6dc9357SAndroid Build Coastguard Worker             if (i == 0
2712*f6dc9357SAndroid Build Coastguard Worker                 || cdItem.Disk < min_Disk
2713*f6dc9357SAndroid Build Coastguard Worker                 || (cdItem.Disk == min_Disk && cdItem.LocalHeaderPos < min_LocalHeaderPos))
2714*f6dc9357SAndroid Build Coastguard Worker             {
2715*f6dc9357SAndroid Build Coastguard Worker               min_Disk = cdItem.Disk;
2716*f6dc9357SAndroid Build Coastguard Worker               min_LocalHeaderPos = cdItem.LocalHeaderPos;
2717*f6dc9357SAndroid Build Coastguard Worker             }
2718*f6dc9357SAndroid Build Coastguard Worker           }
2719*f6dc9357SAndroid Build Coastguard Worker         }
2720*f6dc9357SAndroid Build Coastguard Worker 
2721*f6dc9357SAndroid Build Coastguard Worker         if (index == -1)
2722*f6dc9357SAndroid Build Coastguard Worker           res = S_FALSE;
2723*f6dc9357SAndroid Build Coastguard Worker         else if (!AreItemsEqual(firstItem, items[(unsigned)index]))
2724*f6dc9357SAndroid Build Coastguard Worker           res = S_FALSE;
2725*f6dc9357SAndroid Build Coastguard Worker         else
2726*f6dc9357SAndroid Build Coastguard Worker         {
2727*f6dc9357SAndroid Build Coastguard Worker           ArcInfo.CdWasRead = true;
2728*f6dc9357SAndroid Build Coastguard Worker           if (IsCdUnsorted)
2729*f6dc9357SAndroid Build Coastguard Worker             ArcInfo.FirstItemRelatOffset = min_LocalHeaderPos;
2730*f6dc9357SAndroid Build Coastguard Worker           else
2731*f6dc9357SAndroid Build Coastguard Worker             ArcInfo.FirstItemRelatOffset = items[0].LocalHeaderPos;
2732*f6dc9357SAndroid Build Coastguard Worker 
2733*f6dc9357SAndroid Build Coastguard Worker           // ArcInfo.FirstItemRelatOffset = _startLocalFromCd_Offset;
2734*f6dc9357SAndroid Build Coastguard Worker         }
2735*f6dc9357SAndroid Build Coastguard Worker       }
2736*f6dc9357SAndroid Build Coastguard Worker     }
2737*f6dc9357SAndroid Build Coastguard Worker   }
2738*f6dc9357SAndroid Build Coastguard Worker   } // (MarkerIsFound && MarkerIsSafe)
2739*f6dc9357SAndroid Build Coastguard Worker 
2740*f6dc9357SAndroid Build Coastguard Worker } // (!onlyLocalsMode)
2741*f6dc9357SAndroid Build Coastguard Worker 
2742*f6dc9357SAndroid Build Coastguard Worker 
2743*f6dc9357SAndroid Build Coastguard Worker   CObjectVector<CItemEx> cdItems;
2744*f6dc9357SAndroid Build Coastguard Worker 
2745*f6dc9357SAndroid Build Coastguard Worker   bool needSetBase = false; // we set needSetBase only for LOCALS_CD_MODE
2746*f6dc9357SAndroid Build Coastguard Worker   unsigned numCdItems = items.Size();
2747*f6dc9357SAndroid Build Coastguard Worker 
2748*f6dc9357SAndroid Build Coastguard Worker   #ifdef ZIP_SELF_CHECK
2749*f6dc9357SAndroid Build Coastguard Worker   res = S_FALSE; // if uncommented, it uses additional LOCALS-CD-MODE mode to check the code
2750*f6dc9357SAndroid Build Coastguard Worker   #endif
2751*f6dc9357SAndroid Build Coastguard Worker 
2752*f6dc9357SAndroid Build Coastguard Worker   if (res != S_OK)
2753*f6dc9357SAndroid Build Coastguard Worker   {
2754*f6dc9357SAndroid Build Coastguard Worker     // ---------- LOCALS-CD-MODE ----------
2755*f6dc9357SAndroid Build Coastguard Worker     // CD doesn't match firstItem,
2756*f6dc9357SAndroid Build Coastguard Worker     // so we clear items and read Locals and CD.
2757*f6dc9357SAndroid Build Coastguard Worker 
2758*f6dc9357SAndroid Build Coastguard Worker     items.Clear();
2759*f6dc9357SAndroid Build Coastguard Worker     localsWereRead = true;
2760*f6dc9357SAndroid Build Coastguard Worker 
2761*f6dc9357SAndroid Build Coastguard Worker     HeadersError = false;
2762*f6dc9357SAndroid Build Coastguard Worker     HeadersWarning = false;
2763*f6dc9357SAndroid Build Coastguard Worker     ExtraMinorError = false;
2764*f6dc9357SAndroid Build Coastguard Worker 
2765*f6dc9357SAndroid Build Coastguard Worker     /* we can use any mode: with buffer and without buffer
2766*f6dc9357SAndroid Build Coastguard Worker          without buffer : skips packed data : fast for big files : slow for small files
2767*f6dc9357SAndroid Build Coastguard Worker          with    buffer : reads packed data : slow for big files : fast for small files
2768*f6dc9357SAndroid Build Coastguard Worker        Buffer mode is more effective. */
2769*f6dc9357SAndroid Build Coastguard Worker     // _inBufMode = false;
2770*f6dc9357SAndroid Build Coastguard Worker     _inBufMode = true;
2771*f6dc9357SAndroid Build Coastguard Worker     // we could change the buffer size here, if we want smaller Buffer.
2772*f6dc9357SAndroid Build Coastguard Worker     // RINOK(ReAllocateBuffer(kSeqBufferSize));
2773*f6dc9357SAndroid Build Coastguard Worker     // InitBuf()
2774*f6dc9357SAndroid Build Coastguard Worker 
2775*f6dc9357SAndroid Build Coastguard Worker     ArcInfo.Base = 0;
2776*f6dc9357SAndroid Build Coastguard Worker 
2777*f6dc9357SAndroid Build Coastguard Worker    if (!Disable_FindMarker)
2778*f6dc9357SAndroid Build Coastguard Worker    {
2779*f6dc9357SAndroid Build Coastguard Worker     if (!MarkerIsFound)
2780*f6dc9357SAndroid Build Coastguard Worker     {
2781*f6dc9357SAndroid Build Coastguard Worker       if (!IsMultiVol)
2782*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
2783*f6dc9357SAndroid Build Coastguard Worker       if (Vols.StartParsingVol != 0)
2784*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
2785*f6dc9357SAndroid Build Coastguard Worker       // if (StartParsingVol == 0) and we didn't find marker, we use default zero marker.
2786*f6dc9357SAndroid Build Coastguard Worker       // so we suppose that there is no sfx stub
2787*f6dc9357SAndroid Build Coastguard Worker       RINOK(SeekToVol(0, ArcInfo.MarkerPos2))
2788*f6dc9357SAndroid Build Coastguard Worker     }
2789*f6dc9357SAndroid Build Coastguard Worker     else
2790*f6dc9357SAndroid Build Coastguard Worker     {
2791*f6dc9357SAndroid Build Coastguard Worker       if (ArcInfo.MarkerPos != 0)
2792*f6dc9357SAndroid Build Coastguard Worker       {
2793*f6dc9357SAndroid Build Coastguard Worker         /*
2794*f6dc9357SAndroid Build Coastguard Worker         If multi-vol or there is (No)Span-marker at start of stream, we set (Base) as 0.
2795*f6dc9357SAndroid Build Coastguard Worker         In another caes:
2796*f6dc9357SAndroid Build Coastguard Worker           (No)Span-marker is supposed as false positive. So we set (Base) as main marker (MarkerPos2).
2797*f6dc9357SAndroid Build Coastguard Worker           The (Base) can be corrected later after ECD reading.
2798*f6dc9357SAndroid Build Coastguard Worker           But sfx volume with stub and (No)Span-marker in (!IsMultiVol) mode will have incorrect (Base) here.
2799*f6dc9357SAndroid Build Coastguard Worker         */
2800*f6dc9357SAndroid Build Coastguard Worker         ArcInfo.Base = (Int64)ArcInfo.MarkerPos2;
2801*f6dc9357SAndroid Build Coastguard Worker       }
2802*f6dc9357SAndroid Build Coastguard Worker       RINOK(SeekToVol(ArcInfo.MarkerVolIndex, ArcInfo.MarkerPos2))
2803*f6dc9357SAndroid Build Coastguard Worker     }
2804*f6dc9357SAndroid Build Coastguard Worker    }
2805*f6dc9357SAndroid Build Coastguard Worker     _cnt = 0;
2806*f6dc9357SAndroid Build Coastguard Worker 
2807*f6dc9357SAndroid Build Coastguard Worker     ReadSignature();
2808*f6dc9357SAndroid Build Coastguard Worker 
2809*f6dc9357SAndroid Build Coastguard Worker     LocalsWereRead = true;
2810*f6dc9357SAndroid Build Coastguard Worker 
2811*f6dc9357SAndroid Build Coastguard Worker     RINOK(ReadLocals(items))
2812*f6dc9357SAndroid Build Coastguard Worker 
2813*f6dc9357SAndroid Build Coastguard Worker     if (_signature != NSignature::kCentralFileHeader)
2814*f6dc9357SAndroid Build Coastguard Worker     {
2815*f6dc9357SAndroid Build Coastguard Worker       // GetVirtStreamPos() - 4
2816*f6dc9357SAndroid Build Coastguard Worker       if (items.IsEmpty())
2817*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
2818*f6dc9357SAndroid Build Coastguard Worker 
2819*f6dc9357SAndroid Build Coastguard Worker       bool isError = true;
2820*f6dc9357SAndroid Build Coastguard Worker 
2821*f6dc9357SAndroid Build Coastguard Worker       const UInt32 apkSize = _signature;
2822*f6dc9357SAndroid Build Coastguard Worker       const unsigned kApkFooterSize = 16 + 8;
2823*f6dc9357SAndroid Build Coastguard Worker       if (apkSize >= kApkFooterSize && apkSize <= (1 << 20))
2824*f6dc9357SAndroid Build Coastguard Worker       {
2825*f6dc9357SAndroid Build Coastguard Worker         if (ReadUInt32() == 0)
2826*f6dc9357SAndroid Build Coastguard Worker         {
2827*f6dc9357SAndroid Build Coastguard Worker           CByteBuffer apk;
2828*f6dc9357SAndroid Build Coastguard Worker           apk.Alloc(apkSize);
2829*f6dc9357SAndroid Build Coastguard Worker           SafeRead(apk, apkSize);
2830*f6dc9357SAndroid Build Coastguard Worker           ReadSignature();
2831*f6dc9357SAndroid Build Coastguard Worker           const Byte *footer = apk + apkSize - kApkFooterSize;
2832*f6dc9357SAndroid Build Coastguard Worker           if (_signature == NSignature::kCentralFileHeader)
2833*f6dc9357SAndroid Build Coastguard Worker           if (GetUi64(footer) == apkSize)
2834*f6dc9357SAndroid Build Coastguard Worker           if (memcmp(footer + 8, "APK Sig Block 42", 16) == 0)
2835*f6dc9357SAndroid Build Coastguard Worker           {
2836*f6dc9357SAndroid Build Coastguard Worker             isError = false;
2837*f6dc9357SAndroid Build Coastguard Worker             IsApk = true;
2838*f6dc9357SAndroid Build Coastguard Worker           }
2839*f6dc9357SAndroid Build Coastguard Worker         }
2840*f6dc9357SAndroid Build Coastguard Worker       }
2841*f6dc9357SAndroid Build Coastguard Worker 
2842*f6dc9357SAndroid Build Coastguard Worker       if (isError)
2843*f6dc9357SAndroid Build Coastguard Worker       {
2844*f6dc9357SAndroid Build Coastguard Worker         NoCentralDir = true;
2845*f6dc9357SAndroid Build Coastguard Worker         HeadersError = true;
2846*f6dc9357SAndroid Build Coastguard Worker         return S_OK;
2847*f6dc9357SAndroid Build Coastguard Worker       }
2848*f6dc9357SAndroid Build Coastguard Worker     }
2849*f6dc9357SAndroid Build Coastguard Worker 
2850*f6dc9357SAndroid Build Coastguard Worker     _inBufMode = true;
2851*f6dc9357SAndroid Build Coastguard Worker 
2852*f6dc9357SAndroid Build Coastguard Worker     cdAbsOffset = GetVirtStreamPos() - 4;
2853*f6dc9357SAndroid Build Coastguard Worker     cdDisk = (UInt32)Vols.StreamIndex;
2854*f6dc9357SAndroid Build Coastguard Worker 
2855*f6dc9357SAndroid Build Coastguard Worker     #ifdef ZIP_SELF_CHECK
2856*f6dc9357SAndroid Build Coastguard Worker     if (!IsMultiVol && _cnt != GetVirtStreamPos() - ArcInfo.MarkerPos2)
2857*f6dc9357SAndroid Build Coastguard Worker       return E_FAIL;
2858*f6dc9357SAndroid Build Coastguard Worker     #endif
2859*f6dc9357SAndroid Build Coastguard Worker 
2860*f6dc9357SAndroid Build Coastguard Worker     const UInt64 processedCnt_start = _cnt;
2861*f6dc9357SAndroid Build Coastguard Worker 
2862*f6dc9357SAndroid Build Coastguard Worker     for (;;)
2863*f6dc9357SAndroid Build Coastguard Worker     {
2864*f6dc9357SAndroid Build Coastguard Worker       CItemEx cdItem;
2865*f6dc9357SAndroid Build Coastguard Worker 
2866*f6dc9357SAndroid Build Coastguard Worker       RINOK(ReadCdItem(cdItem))
2867*f6dc9357SAndroid Build Coastguard Worker 
2868*f6dc9357SAndroid Build Coastguard Worker       cdItems.Add(cdItem);
2869*f6dc9357SAndroid Build Coastguard Worker       if (Callback && (cdItems.Size() & 0xFFF) == 0)
2870*f6dc9357SAndroid Build Coastguard Worker       {
2871*f6dc9357SAndroid Build Coastguard Worker         const UInt64 numFiles = items.Size();
2872*f6dc9357SAndroid Build Coastguard Worker         const UInt64 numBytes = _cnt;
2873*f6dc9357SAndroid Build Coastguard Worker         RINOK(Callback->SetCompleted(&numFiles, &numBytes))
2874*f6dc9357SAndroid Build Coastguard Worker       }
2875*f6dc9357SAndroid Build Coastguard Worker       ReadSignature();
2876*f6dc9357SAndroid Build Coastguard Worker       if (_signature != NSignature::kCentralFileHeader)
2877*f6dc9357SAndroid Build Coastguard Worker         break;
2878*f6dc9357SAndroid Build Coastguard Worker     }
2879*f6dc9357SAndroid Build Coastguard Worker 
2880*f6dc9357SAndroid Build Coastguard Worker     cdSize = _cnt - processedCnt_start;
2881*f6dc9357SAndroid Build Coastguard Worker 
2882*f6dc9357SAndroid Build Coastguard Worker     #ifdef ZIP_SELF_CHECK
2883*f6dc9357SAndroid Build Coastguard Worker     if (!IsMultiVol)
2884*f6dc9357SAndroid Build Coastguard Worker     {
2885*f6dc9357SAndroid Build Coastguard Worker       if (_cnt != GetVirtStreamPos() - ArcInfo.MarkerPos2)
2886*f6dc9357SAndroid Build Coastguard Worker         return E_FAIL;
2887*f6dc9357SAndroid Build Coastguard Worker       if (cdSize != (GetVirtStreamPos() - 4) - cdAbsOffset)
2888*f6dc9357SAndroid Build Coastguard Worker         return E_FAIL;
2889*f6dc9357SAndroid Build Coastguard Worker     }
2890*f6dc9357SAndroid Build Coastguard Worker     #endif
2891*f6dc9357SAndroid Build Coastguard Worker 
2892*f6dc9357SAndroid Build Coastguard Worker     needSetBase = true;
2893*f6dc9357SAndroid Build Coastguard Worker     numCdItems = cdItems.Size();
2894*f6dc9357SAndroid Build Coastguard Worker     cdRelatOffset = (UInt64)((Int64)cdAbsOffset - ArcInfo.Base);
2895*f6dc9357SAndroid Build Coastguard Worker 
2896*f6dc9357SAndroid Build Coastguard Worker     if (!cdItems.IsEmpty())
2897*f6dc9357SAndroid Build Coastguard Worker     {
2898*f6dc9357SAndroid Build Coastguard Worker       ArcInfo.CdWasRead = true;
2899*f6dc9357SAndroid Build Coastguard Worker       ArcInfo.FirstItemRelatOffset = cdItems[0].LocalHeaderPos;
2900*f6dc9357SAndroid Build Coastguard Worker     }
2901*f6dc9357SAndroid Build Coastguard Worker   }
2902*f6dc9357SAndroid Build Coastguard Worker 
2903*f6dc9357SAndroid Build Coastguard Worker 
2904*f6dc9357SAndroid Build Coastguard Worker 
2905*f6dc9357SAndroid Build Coastguard Worker   CCdInfo cdInfo;
2906*f6dc9357SAndroid Build Coastguard Worker   CLocator locator;
2907*f6dc9357SAndroid Build Coastguard Worker   bool isZip64 = false;
2908*f6dc9357SAndroid Build Coastguard Worker   const UInt64 ecd64AbsOffset = GetVirtStreamPos() - 4;
2909*f6dc9357SAndroid Build Coastguard Worker   int ecd64Disk = -1;
2910*f6dc9357SAndroid Build Coastguard Worker 
2911*f6dc9357SAndroid Build Coastguard Worker   if (_signature == NSignature::kEcd64)
2912*f6dc9357SAndroid Build Coastguard Worker   {
2913*f6dc9357SAndroid Build Coastguard Worker     ecd64Disk = Vols.StreamIndex;
2914*f6dc9357SAndroid Build Coastguard Worker 
2915*f6dc9357SAndroid Build Coastguard Worker     IsZip64 = isZip64 = true;
2916*f6dc9357SAndroid Build Coastguard Worker 
2917*f6dc9357SAndroid Build Coastguard Worker     {
2918*f6dc9357SAndroid Build Coastguard Worker       const UInt64 recordSize = ReadUInt64();
2919*f6dc9357SAndroid Build Coastguard Worker       if (recordSize < kEcd64_MainSize
2920*f6dc9357SAndroid Build Coastguard Worker           || recordSize >= ((UInt64)1 << 62))
2921*f6dc9357SAndroid Build Coastguard Worker       {
2922*f6dc9357SAndroid Build Coastguard Worker         HeadersError = true;
2923*f6dc9357SAndroid Build Coastguard Worker         return S_OK;
2924*f6dc9357SAndroid Build Coastguard Worker       }
2925*f6dc9357SAndroid Build Coastguard Worker 
2926*f6dc9357SAndroid Build Coastguard Worker       {
2927*f6dc9357SAndroid Build Coastguard Worker         const unsigned kBufSize = kEcd64_MainSize;
2928*f6dc9357SAndroid Build Coastguard Worker         Byte buf[kBufSize];
2929*f6dc9357SAndroid Build Coastguard Worker         SafeRead(buf, kBufSize);
2930*f6dc9357SAndroid Build Coastguard Worker         cdInfo.ParseEcd64e(buf);
2931*f6dc9357SAndroid Build Coastguard Worker       }
2932*f6dc9357SAndroid Build Coastguard Worker 
2933*f6dc9357SAndroid Build Coastguard Worker       RINOK(Skip64(recordSize - kEcd64_MainSize, items.Size()))
2934*f6dc9357SAndroid Build Coastguard Worker     }
2935*f6dc9357SAndroid Build Coastguard Worker 
2936*f6dc9357SAndroid Build Coastguard Worker 
2937*f6dc9357SAndroid Build Coastguard Worker     ReadSignature();
2938*f6dc9357SAndroid Build Coastguard Worker 
2939*f6dc9357SAndroid Build Coastguard Worker     if (_signature != NSignature::kEcd64Locator)
2940*f6dc9357SAndroid Build Coastguard Worker     {
2941*f6dc9357SAndroid Build Coastguard Worker       HeadersError = true;
2942*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
2943*f6dc9357SAndroid Build Coastguard Worker     }
2944*f6dc9357SAndroid Build Coastguard Worker 
2945*f6dc9357SAndroid Build Coastguard Worker     {
2946*f6dc9357SAndroid Build Coastguard Worker       const unsigned kBufSize = 16;
2947*f6dc9357SAndroid Build Coastguard Worker       Byte buf[kBufSize];
2948*f6dc9357SAndroid Build Coastguard Worker       SafeRead(buf, kBufSize);
2949*f6dc9357SAndroid Build Coastguard Worker       locator.Parse(buf);
2950*f6dc9357SAndroid Build Coastguard Worker       // we ignore the error, where some zip creators use (NumDisks == 0)
2951*f6dc9357SAndroid Build Coastguard Worker       // if (locator.NumDisks == 0) HeadersWarning = true;
2952*f6dc9357SAndroid Build Coastguard Worker     }
2953*f6dc9357SAndroid Build Coastguard Worker 
2954*f6dc9357SAndroid Build Coastguard Worker     ReadSignature();
2955*f6dc9357SAndroid Build Coastguard Worker   }
2956*f6dc9357SAndroid Build Coastguard Worker 
2957*f6dc9357SAndroid Build Coastguard Worker 
2958*f6dc9357SAndroid Build Coastguard Worker   if (_signature != NSignature::kEcd)
2959*f6dc9357SAndroid Build Coastguard Worker   {
2960*f6dc9357SAndroid Build Coastguard Worker     HeadersError = true;
2961*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
2962*f6dc9357SAndroid Build Coastguard Worker   }
2963*f6dc9357SAndroid Build Coastguard Worker 
2964*f6dc9357SAndroid Build Coastguard Worker 
2965*f6dc9357SAndroid Build Coastguard Worker   CanStartNewVol = false;
2966*f6dc9357SAndroid Build Coastguard Worker 
2967*f6dc9357SAndroid Build Coastguard Worker   // ---------- ECD ----------
2968*f6dc9357SAndroid Build Coastguard Worker 
2969*f6dc9357SAndroid Build Coastguard Worker   CEcd ecd;
2970*f6dc9357SAndroid Build Coastguard Worker   {
2971*f6dc9357SAndroid Build Coastguard Worker     const unsigned kBufSize = kEcdSize - 4;
2972*f6dc9357SAndroid Build Coastguard Worker     Byte buf[kBufSize];
2973*f6dc9357SAndroid Build Coastguard Worker     SafeRead(buf, kBufSize);
2974*f6dc9357SAndroid Build Coastguard Worker     ecd.Parse(buf);
2975*f6dc9357SAndroid Build Coastguard Worker   }
2976*f6dc9357SAndroid Build Coastguard Worker 
2977*f6dc9357SAndroid Build Coastguard Worker   COPY_ECD_ITEM_16(ThisDisk)
2978*f6dc9357SAndroid Build Coastguard Worker   COPY_ECD_ITEM_16(CdDisk)
2979*f6dc9357SAndroid Build Coastguard Worker   COPY_ECD_ITEM_16(NumEntries_in_ThisDisk)
2980*f6dc9357SAndroid Build Coastguard Worker   COPY_ECD_ITEM_16(NumEntries)
2981*f6dc9357SAndroid Build Coastguard Worker   COPY_ECD_ITEM_32(Size)
2982*f6dc9357SAndroid Build Coastguard Worker   COPY_ECD_ITEM_32(Offset)
2983*f6dc9357SAndroid Build Coastguard Worker 
2984*f6dc9357SAndroid Build Coastguard Worker   bool cdOK = true;
2985*f6dc9357SAndroid Build Coastguard Worker 
2986*f6dc9357SAndroid Build Coastguard Worker   if ((UInt32)cdInfo.Size != (UInt32)cdSize)
2987*f6dc9357SAndroid Build Coastguard Worker   {
2988*f6dc9357SAndroid Build Coastguard Worker     // return S_FALSE;
2989*f6dc9357SAndroid Build Coastguard Worker     cdOK = false;
2990*f6dc9357SAndroid Build Coastguard Worker   }
2991*f6dc9357SAndroid Build Coastguard Worker 
2992*f6dc9357SAndroid Build Coastguard Worker   if (isZip64)
2993*f6dc9357SAndroid Build Coastguard Worker   {
2994*f6dc9357SAndroid Build Coastguard Worker     if (cdInfo.NumEntries != numCdItems
2995*f6dc9357SAndroid Build Coastguard Worker         || cdInfo.Size != cdSize)
2996*f6dc9357SAndroid Build Coastguard Worker     {
2997*f6dc9357SAndroid Build Coastguard Worker       cdOK = false;
2998*f6dc9357SAndroid Build Coastguard Worker     }
2999*f6dc9357SAndroid Build Coastguard Worker   }
3000*f6dc9357SAndroid Build Coastguard Worker 
3001*f6dc9357SAndroid Build Coastguard Worker 
3002*f6dc9357SAndroid Build Coastguard Worker   if (IsMultiVol)
3003*f6dc9357SAndroid Build Coastguard Worker   {
3004*f6dc9357SAndroid Build Coastguard Worker     if (cdDisk != cdInfo.CdDisk)
3005*f6dc9357SAndroid Build Coastguard Worker       HeadersError = true;
3006*f6dc9357SAndroid Build Coastguard Worker   }
3007*f6dc9357SAndroid Build Coastguard Worker   else if (needSetBase && cdOK)
3008*f6dc9357SAndroid Build Coastguard Worker   {
3009*f6dc9357SAndroid Build Coastguard Worker     const UInt64 oldBase = (UInt64)ArcInfo.Base;
3010*f6dc9357SAndroid Build Coastguard Worker     // localsWereRead == true
3011*f6dc9357SAndroid Build Coastguard Worker     // ArcInfo.Base == ArcInfo.MarkerPos2
3012*f6dc9357SAndroid Build Coastguard Worker     // cdRelatOffset == (cdAbsOffset - ArcInfo.Base)
3013*f6dc9357SAndroid Build Coastguard Worker 
3014*f6dc9357SAndroid Build Coastguard Worker     if (isZip64)
3015*f6dc9357SAndroid Build Coastguard Worker     {
3016*f6dc9357SAndroid Build Coastguard Worker       if (ecd64Disk == Vols.StartVolIndex)
3017*f6dc9357SAndroid Build Coastguard Worker       {
3018*f6dc9357SAndroid Build Coastguard Worker         const Int64 newBase = (Int64)ecd64AbsOffset - (Int64)locator.Ecd64Offset;
3019*f6dc9357SAndroid Build Coastguard Worker         if (newBase <= (Int64)ecd64AbsOffset)
3020*f6dc9357SAndroid Build Coastguard Worker         {
3021*f6dc9357SAndroid Build Coastguard Worker           if (!localsWereRead || newBase <= (Int64)ArcInfo.MarkerPos2)
3022*f6dc9357SAndroid Build Coastguard Worker           {
3023*f6dc9357SAndroid Build Coastguard Worker             ArcInfo.Base = newBase;
3024*f6dc9357SAndroid Build Coastguard Worker             cdRelatOffset = (UInt64)((Int64)cdAbsOffset - newBase);
3025*f6dc9357SAndroid Build Coastguard Worker           }
3026*f6dc9357SAndroid Build Coastguard Worker           else
3027*f6dc9357SAndroid Build Coastguard Worker             cdOK = false;
3028*f6dc9357SAndroid Build Coastguard Worker         }
3029*f6dc9357SAndroid Build Coastguard Worker       }
3030*f6dc9357SAndroid Build Coastguard Worker     }
3031*f6dc9357SAndroid Build Coastguard Worker     else if (numCdItems != 0) // we can't use ecd.Offset in empty archive?
3032*f6dc9357SAndroid Build Coastguard Worker     {
3033*f6dc9357SAndroid Build Coastguard Worker       if ((int)cdDisk == Vols.StartVolIndex)
3034*f6dc9357SAndroid Build Coastguard Worker       {
3035*f6dc9357SAndroid Build Coastguard Worker         const Int64 newBase = (Int64)cdAbsOffset - (Int64)cdInfo.Offset;
3036*f6dc9357SAndroid Build Coastguard Worker         if (newBase <= (Int64)cdAbsOffset)
3037*f6dc9357SAndroid Build Coastguard Worker         {
3038*f6dc9357SAndroid Build Coastguard Worker           if (!localsWereRead || newBase <= (Int64)ArcInfo.MarkerPos2)
3039*f6dc9357SAndroid Build Coastguard Worker           {
3040*f6dc9357SAndroid Build Coastguard Worker             // cd can be more accurate, when it points before Locals
3041*f6dc9357SAndroid Build Coastguard Worker             // so we change Base and cdRelatOffset
3042*f6dc9357SAndroid Build Coastguard Worker             ArcInfo.Base = newBase;
3043*f6dc9357SAndroid Build Coastguard Worker             cdRelatOffset = cdInfo.Offset;
3044*f6dc9357SAndroid Build Coastguard Worker           }
3045*f6dc9357SAndroid Build Coastguard Worker           else
3046*f6dc9357SAndroid Build Coastguard Worker           {
3047*f6dc9357SAndroid Build Coastguard Worker             // const UInt64 delta = ((UInt64)cdRelatOffset - cdInfo.Offset);
3048*f6dc9357SAndroid Build Coastguard Worker             const UInt64 delta = ((UInt64)(newBase - ArcInfo.Base));
3049*f6dc9357SAndroid Build Coastguard Worker             if ((UInt32)delta == 0)
3050*f6dc9357SAndroid Build Coastguard Worker             {
3051*f6dc9357SAndroid Build Coastguard Worker               // we set Overflow32bit mode, only if there is (x<<32) offset
3052*f6dc9357SAndroid Build Coastguard Worker               // between real_CD_offset_from_MarkerPos and CD_Offset_in_ECD.
3053*f6dc9357SAndroid Build Coastguard Worker               // Base and cdRelatOffset unchanged
3054*f6dc9357SAndroid Build Coastguard Worker               Overflow32bit = true;
3055*f6dc9357SAndroid Build Coastguard Worker             }
3056*f6dc9357SAndroid Build Coastguard Worker             else
3057*f6dc9357SAndroid Build Coastguard Worker               cdOK = false;
3058*f6dc9357SAndroid Build Coastguard Worker           }
3059*f6dc9357SAndroid Build Coastguard Worker         }
3060*f6dc9357SAndroid Build Coastguard Worker         else
3061*f6dc9357SAndroid Build Coastguard Worker           cdOK = false;
3062*f6dc9357SAndroid Build Coastguard Worker       }
3063*f6dc9357SAndroid Build Coastguard Worker     }
3064*f6dc9357SAndroid Build Coastguard Worker     // cdRelatOffset = cdAbsOffset - ArcInfo.Base;
3065*f6dc9357SAndroid Build Coastguard Worker 
3066*f6dc9357SAndroid Build Coastguard Worker     if (localsWereRead)
3067*f6dc9357SAndroid Build Coastguard Worker     {
3068*f6dc9357SAndroid Build Coastguard Worker       const UInt64 delta = (UInt64)((Int64)oldBase - ArcInfo.Base);
3069*f6dc9357SAndroid Build Coastguard Worker       if (delta != 0)
3070*f6dc9357SAndroid Build Coastguard Worker       {
3071*f6dc9357SAndroid Build Coastguard Worker         FOR_VECTOR (i, items)
3072*f6dc9357SAndroid Build Coastguard Worker           items[i].LocalHeaderPos += delta;
3073*f6dc9357SAndroid Build Coastguard Worker       }
3074*f6dc9357SAndroid Build Coastguard Worker     }
3075*f6dc9357SAndroid Build Coastguard Worker   }
3076*f6dc9357SAndroid Build Coastguard Worker 
3077*f6dc9357SAndroid Build Coastguard Worker   if (!cdOK)
3078*f6dc9357SAndroid Build Coastguard Worker     HeadersError = true;
3079*f6dc9357SAndroid Build Coastguard Worker 
3080*f6dc9357SAndroid Build Coastguard Worker   EcdVolIndex = cdInfo.ThisDisk;
3081*f6dc9357SAndroid Build Coastguard Worker 
3082*f6dc9357SAndroid Build Coastguard Worker   if (!IsMultiVol)
3083*f6dc9357SAndroid Build Coastguard Worker   {
3084*f6dc9357SAndroid Build Coastguard Worker     if (EcdVolIndex == 0 && Vols.MissingZip && Vols.StartIsExe)
3085*f6dc9357SAndroid Build Coastguard Worker     {
3086*f6dc9357SAndroid Build Coastguard Worker       Vols.MissingName.Empty();
3087*f6dc9357SAndroid Build Coastguard Worker       Vols.MissingZip = false;
3088*f6dc9357SAndroid Build Coastguard Worker     }
3089*f6dc9357SAndroid Build Coastguard Worker 
3090*f6dc9357SAndroid Build Coastguard Worker     if (localsWereRead)
3091*f6dc9357SAndroid Build Coastguard Worker     {
3092*f6dc9357SAndroid Build Coastguard Worker       if (EcdVolIndex != 0)
3093*f6dc9357SAndroid Build Coastguard Worker       {
3094*f6dc9357SAndroid Build Coastguard Worker         FOR_VECTOR (i, items)
3095*f6dc9357SAndroid Build Coastguard Worker           items[i].Disk = EcdVolIndex;
3096*f6dc9357SAndroid Build Coastguard Worker       }
3097*f6dc9357SAndroid Build Coastguard Worker     }
3098*f6dc9357SAndroid Build Coastguard Worker 
3099*f6dc9357SAndroid Build Coastguard Worker     UseDisk_in_SingleVol = true;
3100*f6dc9357SAndroid Build Coastguard Worker   }
3101*f6dc9357SAndroid Build Coastguard Worker 
3102*f6dc9357SAndroid Build Coastguard Worker   if (isZip64)
3103*f6dc9357SAndroid Build Coastguard Worker   {
3104*f6dc9357SAndroid Build Coastguard Worker     if ((cdInfo.ThisDisk == 0 && ecd64AbsOffset != (UInt64)(ArcInfo.Base + (Int64)locator.Ecd64Offset))
3105*f6dc9357SAndroid Build Coastguard Worker         // || cdInfo.NumEntries_in_ThisDisk != numCdItems
3106*f6dc9357SAndroid Build Coastguard Worker         || cdInfo.NumEntries != numCdItems
3107*f6dc9357SAndroid Build Coastguard Worker         || cdInfo.Size != cdSize
3108*f6dc9357SAndroid Build Coastguard Worker         || (cdInfo.Offset != cdRelatOffset && !items.IsEmpty()))
3109*f6dc9357SAndroid Build Coastguard Worker     {
3110*f6dc9357SAndroid Build Coastguard Worker       HeadersError = true;
3111*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
3112*f6dc9357SAndroid Build Coastguard Worker     }
3113*f6dc9357SAndroid Build Coastguard Worker   }
3114*f6dc9357SAndroid Build Coastguard Worker 
3115*f6dc9357SAndroid Build Coastguard Worker   if (cdOK && !cdItems.IsEmpty())
3116*f6dc9357SAndroid Build Coastguard Worker   {
3117*f6dc9357SAndroid Build Coastguard Worker     // ---------- merge Central Directory Items ----------
3118*f6dc9357SAndroid Build Coastguard Worker 
3119*f6dc9357SAndroid Build Coastguard Worker     CRecordVector<unsigned> items2;
3120*f6dc9357SAndroid Build Coastguard Worker 
3121*f6dc9357SAndroid Build Coastguard Worker     int nextLocalIndex = 0;
3122*f6dc9357SAndroid Build Coastguard Worker 
3123*f6dc9357SAndroid Build Coastguard Worker     LocalsCenterMerged = true;
3124*f6dc9357SAndroid Build Coastguard Worker 
3125*f6dc9357SAndroid Build Coastguard Worker     FOR_VECTOR (i, cdItems)
3126*f6dc9357SAndroid Build Coastguard Worker     {
3127*f6dc9357SAndroid Build Coastguard Worker       if (Callback)
3128*f6dc9357SAndroid Build Coastguard Worker       if ((i & 0x3FFF) == 0)
3129*f6dc9357SAndroid Build Coastguard Worker       {
3130*f6dc9357SAndroid Build Coastguard Worker         const UInt64 numFiles64 = items.Size() + items2.Size();
3131*f6dc9357SAndroid Build Coastguard Worker         RINOK(Callback->SetCompleted(&numFiles64, &_cnt))
3132*f6dc9357SAndroid Build Coastguard Worker       }
3133*f6dc9357SAndroid Build Coastguard Worker 
3134*f6dc9357SAndroid Build Coastguard Worker       const CItemEx &cdItem = cdItems[i];
3135*f6dc9357SAndroid Build Coastguard Worker 
3136*f6dc9357SAndroid Build Coastguard Worker       int index = -1;
3137*f6dc9357SAndroid Build Coastguard Worker 
3138*f6dc9357SAndroid Build Coastguard Worker       if (nextLocalIndex != -1)
3139*f6dc9357SAndroid Build Coastguard Worker       {
3140*f6dc9357SAndroid Build Coastguard Worker         if ((unsigned)nextLocalIndex < items.Size())
3141*f6dc9357SAndroid Build Coastguard Worker         {
3142*f6dc9357SAndroid Build Coastguard Worker           CItemEx &item = items[(unsigned)nextLocalIndex];
3143*f6dc9357SAndroid Build Coastguard Worker           if (item.Disk == cdItem.Disk &&
3144*f6dc9357SAndroid Build Coastguard Worker               (item.LocalHeaderPos == cdItem.LocalHeaderPos
3145*f6dc9357SAndroid Build Coastguard Worker               || (Overflow32bit && (UInt32)item.LocalHeaderPos == cdItem.LocalHeaderPos)))
3146*f6dc9357SAndroid Build Coastguard Worker             index = nextLocalIndex++;
3147*f6dc9357SAndroid Build Coastguard Worker           else
3148*f6dc9357SAndroid Build Coastguard Worker             nextLocalIndex = -1;
3149*f6dc9357SAndroid Build Coastguard Worker         }
3150*f6dc9357SAndroid Build Coastguard Worker       }
3151*f6dc9357SAndroid Build Coastguard Worker 
3152*f6dc9357SAndroid Build Coastguard Worker       if (index == -1)
3153*f6dc9357SAndroid Build Coastguard Worker         index = FindItem(items, cdItem);
3154*f6dc9357SAndroid Build Coastguard Worker 
3155*f6dc9357SAndroid Build Coastguard Worker       // index = -1;
3156*f6dc9357SAndroid Build Coastguard Worker 
3157*f6dc9357SAndroid Build Coastguard Worker       if (index == -1)
3158*f6dc9357SAndroid Build Coastguard Worker       {
3159*f6dc9357SAndroid Build Coastguard Worker         items2.Add(i);
3160*f6dc9357SAndroid Build Coastguard Worker         HeadersError = true;
3161*f6dc9357SAndroid Build Coastguard Worker         continue;
3162*f6dc9357SAndroid Build Coastguard Worker       }
3163*f6dc9357SAndroid Build Coastguard Worker 
3164*f6dc9357SAndroid Build Coastguard Worker       CItemEx &item = items[(unsigned)index];
3165*f6dc9357SAndroid Build Coastguard Worker       if (item.Name != cdItem.Name
3166*f6dc9357SAndroid Build Coastguard Worker           // || item.Name.Len() != cdItem.Name.Len()
3167*f6dc9357SAndroid Build Coastguard Worker           || item.PackSize != cdItem.PackSize
3168*f6dc9357SAndroid Build Coastguard Worker           || item.Size != cdItem.Size
3169*f6dc9357SAndroid Build Coastguard Worker           // item.ExtractVersion != cdItem.ExtractVersion
3170*f6dc9357SAndroid Build Coastguard Worker           || !FlagsAreSame(item, cdItem)
3171*f6dc9357SAndroid Build Coastguard Worker           || item.Crc != cdItem.Crc)
3172*f6dc9357SAndroid Build Coastguard Worker       {
3173*f6dc9357SAndroid Build Coastguard Worker         HeadersError = true;
3174*f6dc9357SAndroid Build Coastguard Worker         continue;
3175*f6dc9357SAndroid Build Coastguard Worker       }
3176*f6dc9357SAndroid Build Coastguard Worker 
3177*f6dc9357SAndroid Build Coastguard Worker       // item.Name = cdItem.Name;
3178*f6dc9357SAndroid Build Coastguard Worker       item.MadeByVersion = cdItem.MadeByVersion;
3179*f6dc9357SAndroid Build Coastguard Worker       item.CentralExtra = cdItem.CentralExtra;
3180*f6dc9357SAndroid Build Coastguard Worker       item.InternalAttrib = cdItem.InternalAttrib;
3181*f6dc9357SAndroid Build Coastguard Worker       item.ExternalAttrib = cdItem.ExternalAttrib;
3182*f6dc9357SAndroid Build Coastguard Worker       item.Comment = cdItem.Comment;
3183*f6dc9357SAndroid Build Coastguard Worker       item.FromCentral = cdItem.FromCentral;
3184*f6dc9357SAndroid Build Coastguard Worker       // 22.02: we force utf8 flag, if central header has utf8 flag
3185*f6dc9357SAndroid Build Coastguard Worker       if (cdItem.Flags & NFileHeader::NFlags::kUtf8)
3186*f6dc9357SAndroid Build Coastguard Worker         item.Flags |= NFileHeader::NFlags::kUtf8;
3187*f6dc9357SAndroid Build Coastguard Worker     }
3188*f6dc9357SAndroid Build Coastguard Worker 
3189*f6dc9357SAndroid Build Coastguard Worker     FOR_VECTOR (k, items2)
3190*f6dc9357SAndroid Build Coastguard Worker       items.Add(cdItems[items2[k]]);
3191*f6dc9357SAndroid Build Coastguard Worker   }
3192*f6dc9357SAndroid Build Coastguard Worker 
3193*f6dc9357SAndroid Build Coastguard Worker   if (ecd.NumEntries < ecd.NumEntries_in_ThisDisk)
3194*f6dc9357SAndroid Build Coastguard Worker     HeadersError = true;
3195*f6dc9357SAndroid Build Coastguard Worker 
3196*f6dc9357SAndroid Build Coastguard Worker   if (ecd.ThisDisk == 0)
3197*f6dc9357SAndroid Build Coastguard Worker   {
3198*f6dc9357SAndroid Build Coastguard Worker     // if (isZip64)
3199*f6dc9357SAndroid Build Coastguard Worker     {
3200*f6dc9357SAndroid Build Coastguard Worker       if (ecd.NumEntries != ecd.NumEntries_in_ThisDisk)
3201*f6dc9357SAndroid Build Coastguard Worker         HeadersError = true;
3202*f6dc9357SAndroid Build Coastguard Worker     }
3203*f6dc9357SAndroid Build Coastguard Worker   }
3204*f6dc9357SAndroid Build Coastguard Worker 
3205*f6dc9357SAndroid Build Coastguard Worker   if (isZip64)
3206*f6dc9357SAndroid Build Coastguard Worker   {
3207*f6dc9357SAndroid Build Coastguard Worker     if (cdInfo.NumEntries != items.Size()
3208*f6dc9357SAndroid Build Coastguard Worker         || (ecd.NumEntries != items.Size() && ecd.NumEntries != 0xFFFF))
3209*f6dc9357SAndroid Build Coastguard Worker       HeadersError = true;
3210*f6dc9357SAndroid Build Coastguard Worker   }
3211*f6dc9357SAndroid Build Coastguard Worker   else
3212*f6dc9357SAndroid Build Coastguard Worker   {
3213*f6dc9357SAndroid Build Coastguard Worker     // old 7-zip could store 32-bit number of CD items to 16-bit field.
3214*f6dc9357SAndroid Build Coastguard Worker     // if (ecd.NumEntries != items.Size())
3215*f6dc9357SAndroid Build Coastguard Worker     if (ecd.NumEntries > items.Size())
3216*f6dc9357SAndroid Build Coastguard Worker       HeadersError = true;
3217*f6dc9357SAndroid Build Coastguard Worker 
3218*f6dc9357SAndroid Build Coastguard Worker     if (cdInfo.NumEntries != numCdItems)
3219*f6dc9357SAndroid Build Coastguard Worker     {
3220*f6dc9357SAndroid Build Coastguard Worker       if ((UInt16)cdInfo.NumEntries != (UInt16)numCdItems)
3221*f6dc9357SAndroid Build Coastguard Worker         HeadersError = true;
3222*f6dc9357SAndroid Build Coastguard Worker       else
3223*f6dc9357SAndroid Build Coastguard Worker         Cd_NumEntries_Overflow_16bit = true;
3224*f6dc9357SAndroid Build Coastguard Worker     }
3225*f6dc9357SAndroid Build Coastguard Worker   }
3226*f6dc9357SAndroid Build Coastguard Worker 
3227*f6dc9357SAndroid Build Coastguard Worker   ReadBuffer(ArcInfo.Comment, ecd.CommentSize);
3228*f6dc9357SAndroid Build Coastguard Worker 
3229*f6dc9357SAndroid Build Coastguard Worker   _inBufMode = false;
3230*f6dc9357SAndroid Build Coastguard Worker 
3231*f6dc9357SAndroid Build Coastguard Worker   // DisableBufMode();
3232*f6dc9357SAndroid Build Coastguard Worker   // Buffer.Free();
3233*f6dc9357SAndroid Build Coastguard Worker   /* we can't clear buf varibles. we need them to calculate PhySize of archive */
3234*f6dc9357SAndroid Build Coastguard Worker 
3235*f6dc9357SAndroid Build Coastguard Worker   if ((UInt16)cdInfo.NumEntries != (UInt16)numCdItems
3236*f6dc9357SAndroid Build Coastguard Worker       || (UInt32)cdInfo.Size != (UInt32)cdSize
3237*f6dc9357SAndroid Build Coastguard Worker       || ((UInt32)cdInfo.Offset != (UInt32)cdRelatOffset && !items.IsEmpty()))
3238*f6dc9357SAndroid Build Coastguard Worker   {
3239*f6dc9357SAndroid Build Coastguard Worker     // return S_FALSE;
3240*f6dc9357SAndroid Build Coastguard Worker     HeadersError = true;
3241*f6dc9357SAndroid Build Coastguard Worker   }
3242*f6dc9357SAndroid Build Coastguard Worker 
3243*f6dc9357SAndroid Build Coastguard Worker   #ifdef ZIP_SELF_CHECK
3244*f6dc9357SAndroid Build Coastguard Worker   if (localsWereRead)
3245*f6dc9357SAndroid Build Coastguard Worker   {
3246*f6dc9357SAndroid Build Coastguard Worker     const UInt64 endPos = ArcInfo.MarkerPos2 + _cnt;
3247*f6dc9357SAndroid Build Coastguard Worker     if (endPos != (IsMultiVol ? Vols.TotalBytesSize : ArcInfo.FileEndPos))
3248*f6dc9357SAndroid Build Coastguard Worker     {
3249*f6dc9357SAndroid Build Coastguard Worker       // there are some data after the end of archive or error in code;
3250*f6dc9357SAndroid Build Coastguard Worker       return E_FAIL;
3251*f6dc9357SAndroid Build Coastguard Worker     }
3252*f6dc9357SAndroid Build Coastguard Worker   }
3253*f6dc9357SAndroid Build Coastguard Worker   #endif
3254*f6dc9357SAndroid Build Coastguard Worker 
3255*f6dc9357SAndroid Build Coastguard Worker   // printf("\nOpen OK");
3256*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
3257*f6dc9357SAndroid Build Coastguard Worker }
3258*f6dc9357SAndroid Build Coastguard Worker 
3259*f6dc9357SAndroid Build Coastguard Worker 
3260*f6dc9357SAndroid Build Coastguard Worker 
Open(IInStream * stream,const UInt64 * searchLimit,IArchiveOpenCallback * callback,CObjectVector<CItemEx> & items)3261*f6dc9357SAndroid Build Coastguard Worker HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchLimit,
3262*f6dc9357SAndroid Build Coastguard Worker     IArchiveOpenCallback *callback, CObjectVector<CItemEx> &items)
3263*f6dc9357SAndroid Build Coastguard Worker {
3264*f6dc9357SAndroid Build Coastguard Worker   items.Clear();
3265*f6dc9357SAndroid Build Coastguard Worker 
3266*f6dc9357SAndroid Build Coastguard Worker   Close();
3267*f6dc9357SAndroid Build Coastguard Worker 
3268*f6dc9357SAndroid Build Coastguard Worker   UInt64 startPos;
3269*f6dc9357SAndroid Build Coastguard Worker   RINOK(InStream_GetPos(stream, startPos))
3270*f6dc9357SAndroid Build Coastguard Worker   RINOK(InStream_GetSize_SeekToEnd(stream, ArcInfo.FileEndPos))
3271*f6dc9357SAndroid Build Coastguard Worker   _streamPos = ArcInfo.FileEndPos;
3272*f6dc9357SAndroid Build Coastguard Worker 
3273*f6dc9357SAndroid Build Coastguard Worker   StartStream = stream;
3274*f6dc9357SAndroid Build Coastguard Worker   Stream = stream;
3275*f6dc9357SAndroid Build Coastguard Worker   Callback = callback;
3276*f6dc9357SAndroid Build Coastguard Worker 
3277*f6dc9357SAndroid Build Coastguard Worker   DisableBufMode();
3278*f6dc9357SAndroid Build Coastguard Worker 
3279*f6dc9357SAndroid Build Coastguard Worker   bool volWasRequested = false;
3280*f6dc9357SAndroid Build Coastguard Worker 
3281*f6dc9357SAndroid Build Coastguard Worker   if (!Disable_VolsRead)
3282*f6dc9357SAndroid Build Coastguard Worker   if (callback
3283*f6dc9357SAndroid Build Coastguard Worker       && (startPos == 0 || !searchLimit || *searchLimit != 0))
3284*f6dc9357SAndroid Build Coastguard Worker   {
3285*f6dc9357SAndroid Build Coastguard Worker     // we try to read volumes only if it's first call (offset == 0) or scan is allowed.
3286*f6dc9357SAndroid Build Coastguard Worker     volWasRequested = true;
3287*f6dc9357SAndroid Build Coastguard Worker     RINOK(ReadVols())
3288*f6dc9357SAndroid Build Coastguard Worker   }
3289*f6dc9357SAndroid Build Coastguard Worker 
3290*f6dc9357SAndroid Build Coastguard Worker   if (Disable_FindMarker)
3291*f6dc9357SAndroid Build Coastguard Worker   {
3292*f6dc9357SAndroid Build Coastguard Worker     RINOK(SeekToVol(-1, startPos))
3293*f6dc9357SAndroid Build Coastguard Worker     StreamRef = stream;
3294*f6dc9357SAndroid Build Coastguard Worker     Stream = stream;
3295*f6dc9357SAndroid Build Coastguard Worker     MarkerIsFound = true;
3296*f6dc9357SAndroid Build Coastguard Worker     MarkerIsSafe = true;
3297*f6dc9357SAndroid Build Coastguard Worker     ArcInfo.MarkerPos = startPos;
3298*f6dc9357SAndroid Build Coastguard Worker     ArcInfo.MarkerPos2 = startPos;
3299*f6dc9357SAndroid Build Coastguard Worker   }
3300*f6dc9357SAndroid Build Coastguard Worker   else
3301*f6dc9357SAndroid Build Coastguard Worker   if (IsMultiVol && Vols.StartParsingVol == 0 && (unsigned)Vols.StartParsingVol < Vols.Streams.Size())
3302*f6dc9357SAndroid Build Coastguard Worker   {
3303*f6dc9357SAndroid Build Coastguard Worker     // only StartParsingVol = 0 is safe search.
3304*f6dc9357SAndroid Build Coastguard Worker     RINOK(SeekToVol(0, 0))
3305*f6dc9357SAndroid Build Coastguard Worker     // if (Stream)
3306*f6dc9357SAndroid Build Coastguard Worker     {
3307*f6dc9357SAndroid Build Coastguard Worker       // UInt64 limit = 1 << 22; // for sfx
3308*f6dc9357SAndroid Build Coastguard Worker       UInt64 limit = 0; // without sfx
3309*f6dc9357SAndroid Build Coastguard Worker 
3310*f6dc9357SAndroid Build Coastguard Worker       HRESULT res = FindMarker(&limit);
3311*f6dc9357SAndroid Build Coastguard Worker 
3312*f6dc9357SAndroid Build Coastguard Worker       if (res == S_OK)
3313*f6dc9357SAndroid Build Coastguard Worker       {
3314*f6dc9357SAndroid Build Coastguard Worker         MarkerIsFound = true;
3315*f6dc9357SAndroid Build Coastguard Worker         MarkerIsSafe = true;
3316*f6dc9357SAndroid Build Coastguard Worker       }
3317*f6dc9357SAndroid Build Coastguard Worker       else if (res != S_FALSE)
3318*f6dc9357SAndroid Build Coastguard Worker         return res;
3319*f6dc9357SAndroid Build Coastguard Worker     }
3320*f6dc9357SAndroid Build Coastguard Worker   }
3321*f6dc9357SAndroid Build Coastguard Worker   else
3322*f6dc9357SAndroid Build Coastguard Worker   {
3323*f6dc9357SAndroid Build Coastguard Worker     // printf("\nOpen offset = %u\n", (unsigned)startPos);
3324*f6dc9357SAndroid Build Coastguard Worker     if (IsMultiVol
3325*f6dc9357SAndroid Build Coastguard Worker         && (unsigned)Vols.StartParsingVol < Vols.Streams.Size()
3326*f6dc9357SAndroid Build Coastguard Worker         && Vols.Streams[(unsigned)Vols.StartParsingVol].Stream)
3327*f6dc9357SAndroid Build Coastguard Worker     {
3328*f6dc9357SAndroid Build Coastguard Worker       RINOK(SeekToVol(Vols.StartParsingVol, Vols.StreamIndex == Vols.StartVolIndex ? startPos : 0))
3329*f6dc9357SAndroid Build Coastguard Worker     }
3330*f6dc9357SAndroid Build Coastguard Worker     else
3331*f6dc9357SAndroid Build Coastguard Worker     {
3332*f6dc9357SAndroid Build Coastguard Worker       RINOK(SeekToVol(-1, startPos))
3333*f6dc9357SAndroid Build Coastguard Worker     }
3334*f6dc9357SAndroid Build Coastguard Worker 
3335*f6dc9357SAndroid Build Coastguard Worker     // UInt64 limit = 1 << 22;
3336*f6dc9357SAndroid Build Coastguard Worker     // HRESULT res = FindMarker(&limit);
3337*f6dc9357SAndroid Build Coastguard Worker 
3338*f6dc9357SAndroid Build Coastguard Worker     HRESULT res = FindMarker(searchLimit);
3339*f6dc9357SAndroid Build Coastguard Worker 
3340*f6dc9357SAndroid Build Coastguard Worker     // const UInt64 curPos = GetVirtStreamPos();
3341*f6dc9357SAndroid Build Coastguard Worker     const UInt64 curPos = ArcInfo.MarkerPos2 + 4;
3342*f6dc9357SAndroid Build Coastguard Worker 
3343*f6dc9357SAndroid Build Coastguard Worker     if (res == S_OK)
3344*f6dc9357SAndroid Build Coastguard Worker       MarkerIsFound = true;
3345*f6dc9357SAndroid Build Coastguard Worker     else if (!IsMultiVol)
3346*f6dc9357SAndroid Build Coastguard Worker     {
3347*f6dc9357SAndroid Build Coastguard Worker       /*
3348*f6dc9357SAndroid Build Coastguard Worker       // if (startPos != 0), probably CD could be already tested with another call with (startPos == 0).
3349*f6dc9357SAndroid Build Coastguard Worker       // so we don't want to try to open CD again in that case.
3350*f6dc9357SAndroid Build Coastguard Worker       if (startPos != 0)
3351*f6dc9357SAndroid Build Coastguard Worker         return res;
3352*f6dc9357SAndroid Build Coastguard Worker       // we can try to open CD, if there is no Marker and (startPos == 0).
3353*f6dc9357SAndroid Build Coastguard Worker       // is it OK to open such files as ZIP, or big number of false positive, when CD can be find in end of file ?
3354*f6dc9357SAndroid Build Coastguard Worker       */
3355*f6dc9357SAndroid Build Coastguard Worker       return res;
3356*f6dc9357SAndroid Build Coastguard Worker     }
3357*f6dc9357SAndroid Build Coastguard Worker 
3358*f6dc9357SAndroid Build Coastguard Worker     if (ArcInfo.IsSpanMode && !volWasRequested)
3359*f6dc9357SAndroid Build Coastguard Worker     {
3360*f6dc9357SAndroid Build Coastguard Worker       RINOK(ReadVols())
3361*f6dc9357SAndroid Build Coastguard Worker       if (IsMultiVol && MarkerIsFound && ArcInfo.MarkerVolIndex < 0)
3362*f6dc9357SAndroid Build Coastguard Worker         ArcInfo.MarkerVolIndex = Vols.StartVolIndex;
3363*f6dc9357SAndroid Build Coastguard Worker     }
3364*f6dc9357SAndroid Build Coastguard Worker 
3365*f6dc9357SAndroid Build Coastguard Worker     MarkerIsSafe = !IsMultiVol
3366*f6dc9357SAndroid Build Coastguard Worker         || (ArcInfo.MarkerVolIndex == 0 && ArcInfo.MarkerPos == 0)
3367*f6dc9357SAndroid Build Coastguard Worker         ;
3368*f6dc9357SAndroid Build Coastguard Worker 
3369*f6dc9357SAndroid Build Coastguard Worker 
3370*f6dc9357SAndroid Build Coastguard Worker     if (IsMultiVol)
3371*f6dc9357SAndroid Build Coastguard Worker     {
3372*f6dc9357SAndroid Build Coastguard Worker       if ((unsigned)Vols.StartVolIndex < Vols.Streams.Size())
3373*f6dc9357SAndroid Build Coastguard Worker       {
3374*f6dc9357SAndroid Build Coastguard Worker         Stream = Vols.Streams[(unsigned)Vols.StartVolIndex].Stream;
3375*f6dc9357SAndroid Build Coastguard Worker         if (Stream)
3376*f6dc9357SAndroid Build Coastguard Worker         {
3377*f6dc9357SAndroid Build Coastguard Worker           RINOK(Seek_SavePos(curPos))
3378*f6dc9357SAndroid Build Coastguard Worker         }
3379*f6dc9357SAndroid Build Coastguard Worker         else
3380*f6dc9357SAndroid Build Coastguard Worker           IsMultiVol = false;
3381*f6dc9357SAndroid Build Coastguard Worker       }
3382*f6dc9357SAndroid Build Coastguard Worker       else
3383*f6dc9357SAndroid Build Coastguard Worker         IsMultiVol = false;
3384*f6dc9357SAndroid Build Coastguard Worker     }
3385*f6dc9357SAndroid Build Coastguard Worker 
3386*f6dc9357SAndroid Build Coastguard Worker     if (!IsMultiVol)
3387*f6dc9357SAndroid Build Coastguard Worker     {
3388*f6dc9357SAndroid Build Coastguard Worker       if (Vols.StreamIndex != -1)
3389*f6dc9357SAndroid Build Coastguard Worker       {
3390*f6dc9357SAndroid Build Coastguard Worker         Stream = StartStream;
3391*f6dc9357SAndroid Build Coastguard Worker         Vols.StreamIndex = -1;
3392*f6dc9357SAndroid Build Coastguard Worker         InitBuf();
3393*f6dc9357SAndroid Build Coastguard Worker         RINOK(Seek_SavePos(curPos))
3394*f6dc9357SAndroid Build Coastguard Worker       }
3395*f6dc9357SAndroid Build Coastguard Worker 
3396*f6dc9357SAndroid Build Coastguard Worker       ArcInfo.MarkerVolIndex = -1;
3397*f6dc9357SAndroid Build Coastguard Worker       StreamRef = stream;
3398*f6dc9357SAndroid Build Coastguard Worker       Stream = stream;
3399*f6dc9357SAndroid Build Coastguard Worker     }
3400*f6dc9357SAndroid Build Coastguard Worker   }
3401*f6dc9357SAndroid Build Coastguard Worker 
3402*f6dc9357SAndroid Build Coastguard Worker 
3403*f6dc9357SAndroid Build Coastguard Worker   if (!IsMultiVol)
3404*f6dc9357SAndroid Build Coastguard Worker     Vols.ClearRefs();
3405*f6dc9357SAndroid Build Coastguard Worker 
3406*f6dc9357SAndroid Build Coastguard Worker   {
3407*f6dc9357SAndroid Build Coastguard Worker     HRESULT res;
3408*f6dc9357SAndroid Build Coastguard Worker     try
3409*f6dc9357SAndroid Build Coastguard Worker     {
3410*f6dc9357SAndroid Build Coastguard Worker       res = ReadHeaders(items);
3411*f6dc9357SAndroid Build Coastguard Worker     }
3412*f6dc9357SAndroid Build Coastguard Worker     catch (const CSystemException &e) { res = e.ErrorCode; }
3413*f6dc9357SAndroid Build Coastguard Worker     catch (const CUnexpectEnd &)
3414*f6dc9357SAndroid Build Coastguard Worker     {
3415*f6dc9357SAndroid Build Coastguard Worker       if (items.IsEmpty())
3416*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
3417*f6dc9357SAndroid Build Coastguard Worker       UnexpectedEnd = true;
3418*f6dc9357SAndroid Build Coastguard Worker       res = S_OK;
3419*f6dc9357SAndroid Build Coastguard Worker     }
3420*f6dc9357SAndroid Build Coastguard Worker     catch (...)
3421*f6dc9357SAndroid Build Coastguard Worker     {
3422*f6dc9357SAndroid Build Coastguard Worker       DisableBufMode();
3423*f6dc9357SAndroid Build Coastguard Worker       throw;
3424*f6dc9357SAndroid Build Coastguard Worker     }
3425*f6dc9357SAndroid Build Coastguard Worker 
3426*f6dc9357SAndroid Build Coastguard Worker     if (IsMultiVol)
3427*f6dc9357SAndroid Build Coastguard Worker     {
3428*f6dc9357SAndroid Build Coastguard Worker       ArcInfo.FinishPos = ArcInfo.FileEndPos;
3429*f6dc9357SAndroid Build Coastguard Worker       if ((unsigned)Vols.StreamIndex < Vols.Streams.Size())
3430*f6dc9357SAndroid Build Coastguard Worker         if (GetVirtStreamPos() < Vols.Streams[(unsigned)Vols.StreamIndex].Size)
3431*f6dc9357SAndroid Build Coastguard Worker           ArcInfo.ThereIsTail = true;
3432*f6dc9357SAndroid Build Coastguard Worker     }
3433*f6dc9357SAndroid Build Coastguard Worker     else
3434*f6dc9357SAndroid Build Coastguard Worker     {
3435*f6dc9357SAndroid Build Coastguard Worker       ArcInfo.FinishPos = GetVirtStreamPos();
3436*f6dc9357SAndroid Build Coastguard Worker       ArcInfo.ThereIsTail = (ArcInfo.FileEndPos > ArcInfo.FinishPos);
3437*f6dc9357SAndroid Build Coastguard Worker     }
3438*f6dc9357SAndroid Build Coastguard Worker 
3439*f6dc9357SAndroid Build Coastguard Worker     DisableBufMode();
3440*f6dc9357SAndroid Build Coastguard Worker 
3441*f6dc9357SAndroid Build Coastguard Worker     IsArcOpen = true;
3442*f6dc9357SAndroid Build Coastguard Worker     if (!IsMultiVol)
3443*f6dc9357SAndroid Build Coastguard Worker       Vols.Streams.Clear();
3444*f6dc9357SAndroid Build Coastguard Worker     return res;
3445*f6dc9357SAndroid Build Coastguard Worker   }
3446*f6dc9357SAndroid Build Coastguard Worker }
3447*f6dc9357SAndroid Build Coastguard Worker 
3448*f6dc9357SAndroid Build Coastguard Worker 
GetItemStream(const CItemEx & item,bool seekPackData,CMyComPtr<ISequentialInStream> & stream)3449*f6dc9357SAndroid Build Coastguard Worker HRESULT CInArchive::GetItemStream(const CItemEx &item, bool seekPackData, CMyComPtr<ISequentialInStream> &stream)
3450*f6dc9357SAndroid Build Coastguard Worker {
3451*f6dc9357SAndroid Build Coastguard Worker   stream.Release();
3452*f6dc9357SAndroid Build Coastguard Worker 
3453*f6dc9357SAndroid Build Coastguard Worker   UInt64 pos = item.LocalHeaderPos;
3454*f6dc9357SAndroid Build Coastguard Worker   if (seekPackData)
3455*f6dc9357SAndroid Build Coastguard Worker     pos += item.LocalFullHeaderSize;
3456*f6dc9357SAndroid Build Coastguard Worker 
3457*f6dc9357SAndroid Build Coastguard Worker   if (!IsMultiVol)
3458*f6dc9357SAndroid Build Coastguard Worker   {
3459*f6dc9357SAndroid Build Coastguard Worker     if (UseDisk_in_SingleVol && item.Disk != EcdVolIndex)
3460*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
3461*f6dc9357SAndroid Build Coastguard Worker     pos = (UInt64)((Int64)pos + ArcInfo.Base);
3462*f6dc9357SAndroid Build Coastguard Worker     RINOK(InStream_SeekSet(StreamRef, pos))
3463*f6dc9357SAndroid Build Coastguard Worker     stream = StreamRef;
3464*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
3465*f6dc9357SAndroid Build Coastguard Worker   }
3466*f6dc9357SAndroid Build Coastguard Worker 
3467*f6dc9357SAndroid Build Coastguard Worker   if (item.Disk >= Vols.Streams.Size())
3468*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
3469*f6dc9357SAndroid Build Coastguard Worker 
3470*f6dc9357SAndroid Build Coastguard Worker   IInStream *str2 = Vols.Streams[item.Disk].Stream;
3471*f6dc9357SAndroid Build Coastguard Worker   if (!str2)
3472*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
3473*f6dc9357SAndroid Build Coastguard Worker   RINOK(InStream_SeekSet(str2, pos))
3474*f6dc9357SAndroid Build Coastguard Worker 
3475*f6dc9357SAndroid Build Coastguard Worker   Vols.NeedSeek = false;
3476*f6dc9357SAndroid Build Coastguard Worker   Vols.StreamIndex = (int)item.Disk;
3477*f6dc9357SAndroid Build Coastguard Worker 
3478*f6dc9357SAndroid Build Coastguard Worker   CVolStream *volsStreamSpec = new CVolStream;
3479*f6dc9357SAndroid Build Coastguard Worker   volsStreamSpec->Vols = &Vols;
3480*f6dc9357SAndroid Build Coastguard Worker   stream = volsStreamSpec;
3481*f6dc9357SAndroid Build Coastguard Worker 
3482*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
3483*f6dc9357SAndroid Build Coastguard Worker }
3484*f6dc9357SAndroid Build Coastguard Worker 
3485*f6dc9357SAndroid Build Coastguard Worker }}
3486