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