1*f6dc9357SAndroid Build Coastguard Worker // Archive/CabIn.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 "../../../../C/CpuArch.h"
8*f6dc9357SAndroid Build Coastguard Worker
9*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/LimitedStreams.h"
10*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/StreamUtils.h"
11*f6dc9357SAndroid Build Coastguard Worker
12*f6dc9357SAndroid Build Coastguard Worker #include "CabIn.h"
13*f6dc9357SAndroid Build Coastguard Worker
14*f6dc9357SAndroid Build Coastguard Worker #define Get16(p) GetUi16(p)
15*f6dc9357SAndroid Build Coastguard Worker #define Get32(p) GetUi32(p)
16*f6dc9357SAndroid Build Coastguard Worker
17*f6dc9357SAndroid Build Coastguard Worker namespace NArchive {
18*f6dc9357SAndroid Build Coastguard Worker namespace NCab {
19*f6dc9357SAndroid Build Coastguard Worker
20*f6dc9357SAndroid Build Coastguard Worker struct CUnexpectedEndException {};
21*f6dc9357SAndroid Build Coastguard Worker
Skip(unsigned size)22*f6dc9357SAndroid Build Coastguard Worker void CInArchive::Skip(unsigned size)
23*f6dc9357SAndroid Build Coastguard Worker {
24*f6dc9357SAndroid Build Coastguard Worker if (_inBuffer.Skip(size) != size)
25*f6dc9357SAndroid Build Coastguard Worker throw CUnexpectedEndException();
26*f6dc9357SAndroid Build Coastguard Worker }
27*f6dc9357SAndroid Build Coastguard Worker
Read(Byte * data,unsigned size)28*f6dc9357SAndroid Build Coastguard Worker void CInArchive::Read(Byte *data, unsigned size)
29*f6dc9357SAndroid Build Coastguard Worker {
30*f6dc9357SAndroid Build Coastguard Worker if (_inBuffer.ReadBytes(data, size) != size)
31*f6dc9357SAndroid Build Coastguard Worker throw CUnexpectedEndException();
32*f6dc9357SAndroid Build Coastguard Worker }
33*f6dc9357SAndroid Build Coastguard Worker
ReadName(AString & s)34*f6dc9357SAndroid Build Coastguard Worker void CInArchive::ReadName(AString &s)
35*f6dc9357SAndroid Build Coastguard Worker {
36*f6dc9357SAndroid Build Coastguard Worker for (size_t i = 0; i < ((size_t)1 << 13); i++)
37*f6dc9357SAndroid Build Coastguard Worker {
38*f6dc9357SAndroid Build Coastguard Worker Byte b;
39*f6dc9357SAndroid Build Coastguard Worker if (!_inBuffer.ReadByte(b))
40*f6dc9357SAndroid Build Coastguard Worker throw CUnexpectedEndException();
41*f6dc9357SAndroid Build Coastguard Worker if (b == 0)
42*f6dc9357SAndroid Build Coastguard Worker {
43*f6dc9357SAndroid Build Coastguard Worker s.SetFrom((const char *)(const Byte *)_tempBuf, (unsigned)i);
44*f6dc9357SAndroid Build Coastguard Worker return;
45*f6dc9357SAndroid Build Coastguard Worker }
46*f6dc9357SAndroid Build Coastguard Worker if (_tempBuf.Size() == i)
47*f6dc9357SAndroid Build Coastguard Worker _tempBuf.ChangeSize_KeepData(i * 2, i);
48*f6dc9357SAndroid Build Coastguard Worker _tempBuf[i] = b;
49*f6dc9357SAndroid Build Coastguard Worker }
50*f6dc9357SAndroid Build Coastguard Worker
51*f6dc9357SAndroid Build Coastguard Worker for (;;)
52*f6dc9357SAndroid Build Coastguard Worker {
53*f6dc9357SAndroid Build Coastguard Worker Byte b;
54*f6dc9357SAndroid Build Coastguard Worker if (!_inBuffer.ReadByte(b))
55*f6dc9357SAndroid Build Coastguard Worker throw CUnexpectedEndException();
56*f6dc9357SAndroid Build Coastguard Worker if (b == 0)
57*f6dc9357SAndroid Build Coastguard Worker break;
58*f6dc9357SAndroid Build Coastguard Worker }
59*f6dc9357SAndroid Build Coastguard Worker
60*f6dc9357SAndroid Build Coastguard Worker ErrorInNames = true;
61*f6dc9357SAndroid Build Coastguard Worker s = "[ERROR-LONG-PATH]";
62*f6dc9357SAndroid Build Coastguard Worker }
63*f6dc9357SAndroid Build Coastguard Worker
ReadOtherArc(COtherArc & oa)64*f6dc9357SAndroid Build Coastguard Worker void CInArchive::ReadOtherArc(COtherArc &oa)
65*f6dc9357SAndroid Build Coastguard Worker {
66*f6dc9357SAndroid Build Coastguard Worker ReadName(oa.FileName);
67*f6dc9357SAndroid Build Coastguard Worker ReadName(oa.DiskName);
68*f6dc9357SAndroid Build Coastguard Worker }
69*f6dc9357SAndroid Build Coastguard Worker
70*f6dc9357SAndroid Build Coastguard Worker
71*f6dc9357SAndroid Build Coastguard Worker struct CSignatureFinder
72*f6dc9357SAndroid Build Coastguard Worker {
73*f6dc9357SAndroid Build Coastguard Worker Byte *Buf;
74*f6dc9357SAndroid Build Coastguard Worker UInt32 Pos;
75*f6dc9357SAndroid Build Coastguard Worker UInt32 End;
76*f6dc9357SAndroid Build Coastguard Worker const Byte *Signature;
77*f6dc9357SAndroid Build Coastguard Worker UInt32 SignatureSize;
78*f6dc9357SAndroid Build Coastguard Worker
79*f6dc9357SAndroid Build Coastguard Worker UInt32 _headerSize;
80*f6dc9357SAndroid Build Coastguard Worker UInt32 _alignSize;
81*f6dc9357SAndroid Build Coastguard Worker UInt32 _bufUseCapacity;
82*f6dc9357SAndroid Build Coastguard Worker
83*f6dc9357SAndroid Build Coastguard Worker const UInt64 *SearchLimit;
84*f6dc9357SAndroid Build Coastguard Worker ISequentialInStream *Stream;
85*f6dc9357SAndroid Build Coastguard Worker UInt64 Processed; // Global offset of start of Buf
86*f6dc9357SAndroid Build Coastguard Worker
GetTotalCapacityNArchive::NCab::CSignatureFinder87*f6dc9357SAndroid Build Coastguard Worker UInt32 GetTotalCapacity(UInt32 basicSize, UInt32 headerSize)
88*f6dc9357SAndroid Build Coastguard Worker {
89*f6dc9357SAndroid Build Coastguard Worker _headerSize = headerSize;
90*f6dc9357SAndroid Build Coastguard Worker for (_alignSize = (1 << 5); _alignSize < _headerSize; _alignSize <<= 1);
91*f6dc9357SAndroid Build Coastguard Worker _bufUseCapacity = basicSize + _alignSize;
92*f6dc9357SAndroid Build Coastguard Worker return _bufUseCapacity + 16;
93*f6dc9357SAndroid Build Coastguard Worker }
94*f6dc9357SAndroid Build Coastguard Worker
95*f6dc9357SAndroid Build Coastguard Worker /*
96*f6dc9357SAndroid Build Coastguard Worker returns:
97*f6dc9357SAndroid Build Coastguard Worker S_OK - signature found (at Pos)
98*f6dc9357SAndroid Build Coastguard Worker S_FALSE - signature not found
99*f6dc9357SAndroid Build Coastguard Worker */
100*f6dc9357SAndroid Build Coastguard Worker HRESULT Find();
101*f6dc9357SAndroid Build Coastguard Worker };
102*f6dc9357SAndroid Build Coastguard Worker
103*f6dc9357SAndroid Build Coastguard Worker
Find()104*f6dc9357SAndroid Build Coastguard Worker HRESULT CSignatureFinder::Find()
105*f6dc9357SAndroid Build Coastguard Worker {
106*f6dc9357SAndroid Build Coastguard Worker for (;;)
107*f6dc9357SAndroid Build Coastguard Worker {
108*f6dc9357SAndroid Build Coastguard Worker Buf[End] = Signature[0]; // it's for fast search;
109*f6dc9357SAndroid Build Coastguard Worker
110*f6dc9357SAndroid Build Coastguard Worker while (End - Pos >= _headerSize)
111*f6dc9357SAndroid Build Coastguard Worker {
112*f6dc9357SAndroid Build Coastguard Worker const Byte *p = Buf + Pos;
113*f6dc9357SAndroid Build Coastguard Worker const Byte b = Signature[0];
114*f6dc9357SAndroid Build Coastguard Worker for (;;)
115*f6dc9357SAndroid Build Coastguard Worker {
116*f6dc9357SAndroid Build Coastguard Worker if (*p == b) { break; } p++;
117*f6dc9357SAndroid Build Coastguard Worker if (*p == b) { break; } p++;
118*f6dc9357SAndroid Build Coastguard Worker }
119*f6dc9357SAndroid Build Coastguard Worker Pos = (UInt32)(p - Buf);
120*f6dc9357SAndroid Build Coastguard Worker if (End - Pos < _headerSize)
121*f6dc9357SAndroid Build Coastguard Worker {
122*f6dc9357SAndroid Build Coastguard Worker Pos = End - _headerSize + 1;
123*f6dc9357SAndroid Build Coastguard Worker break;
124*f6dc9357SAndroid Build Coastguard Worker }
125*f6dc9357SAndroid Build Coastguard Worker UInt32 i;
126*f6dc9357SAndroid Build Coastguard Worker for (i = 1; i < SignatureSize && p[i] == Signature[i]; i++);
127*f6dc9357SAndroid Build Coastguard Worker if (i == SignatureSize)
128*f6dc9357SAndroid Build Coastguard Worker return S_OK;
129*f6dc9357SAndroid Build Coastguard Worker Pos++;
130*f6dc9357SAndroid Build Coastguard Worker }
131*f6dc9357SAndroid Build Coastguard Worker
132*f6dc9357SAndroid Build Coastguard Worker if (Pos >= _alignSize)
133*f6dc9357SAndroid Build Coastguard Worker {
134*f6dc9357SAndroid Build Coastguard Worker const UInt32 num = (Pos & ~(_alignSize - 1));
135*f6dc9357SAndroid Build Coastguard Worker Processed += num;
136*f6dc9357SAndroid Build Coastguard Worker Pos -= num;
137*f6dc9357SAndroid Build Coastguard Worker End -= num;
138*f6dc9357SAndroid Build Coastguard Worker memmove(Buf, Buf + num, End);
139*f6dc9357SAndroid Build Coastguard Worker }
140*f6dc9357SAndroid Build Coastguard Worker UInt32 rem = _bufUseCapacity - End;
141*f6dc9357SAndroid Build Coastguard Worker if (SearchLimit)
142*f6dc9357SAndroid Build Coastguard Worker {
143*f6dc9357SAndroid Build Coastguard Worker if (Processed + Pos > *SearchLimit)
144*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
145*f6dc9357SAndroid Build Coastguard Worker const UInt64 rem2 = *SearchLimit - (Processed + End) + _headerSize;
146*f6dc9357SAndroid Build Coastguard Worker if (rem > rem2)
147*f6dc9357SAndroid Build Coastguard Worker rem = (UInt32)rem2;
148*f6dc9357SAndroid Build Coastguard Worker }
149*f6dc9357SAndroid Build Coastguard Worker
150*f6dc9357SAndroid Build Coastguard Worker UInt32 processedSize;
151*f6dc9357SAndroid Build Coastguard Worker if (Processed == 0 && rem == _bufUseCapacity - _headerSize)
152*f6dc9357SAndroid Build Coastguard Worker rem -= _alignSize; // to make reads more aligned.
153*f6dc9357SAndroid Build Coastguard Worker RINOK(Stream->Read(Buf + End, rem, &processedSize))
154*f6dc9357SAndroid Build Coastguard Worker if (processedSize == 0)
155*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
156*f6dc9357SAndroid Build Coastguard Worker End += processedSize;
157*f6dc9357SAndroid Build Coastguard Worker }
158*f6dc9357SAndroid Build Coastguard Worker }
159*f6dc9357SAndroid Build Coastguard Worker
160*f6dc9357SAndroid Build Coastguard Worker
Parse(const Byte * p)161*f6dc9357SAndroid Build Coastguard Worker bool CInArcInfo::Parse(const Byte *p)
162*f6dc9357SAndroid Build Coastguard Worker {
163*f6dc9357SAndroid Build Coastguard Worker if (Get32(p + 0x0C) != 0 ||
164*f6dc9357SAndroid Build Coastguard Worker Get32(p + 0x14) != 0)
165*f6dc9357SAndroid Build Coastguard Worker return false;
166*f6dc9357SAndroid Build Coastguard Worker Size = Get32(p + 8);
167*f6dc9357SAndroid Build Coastguard Worker if (Size < 36)
168*f6dc9357SAndroid Build Coastguard Worker return false;
169*f6dc9357SAndroid Build Coastguard Worker Flags = Get16(p + 0x1E);
170*f6dc9357SAndroid Build Coastguard Worker if (Flags > 7)
171*f6dc9357SAndroid Build Coastguard Worker return false;
172*f6dc9357SAndroid Build Coastguard Worker FileHeadersOffset = Get32(p + 0x10);
173*f6dc9357SAndroid Build Coastguard Worker if (FileHeadersOffset != 0 && FileHeadersOffset > Size)
174*f6dc9357SAndroid Build Coastguard Worker return false;
175*f6dc9357SAndroid Build Coastguard Worker VersionMinor = p[0x18];
176*f6dc9357SAndroid Build Coastguard Worker VersionMajor = p[0x19];
177*f6dc9357SAndroid Build Coastguard Worker NumFolders = Get16(p + 0x1A);
178*f6dc9357SAndroid Build Coastguard Worker NumFiles = Get16(p + 0x1C);
179*f6dc9357SAndroid Build Coastguard Worker return true;
180*f6dc9357SAndroid Build Coastguard Worker }
181*f6dc9357SAndroid Build Coastguard Worker
182*f6dc9357SAndroid Build Coastguard Worker
Open2(CDatabaseEx & db,const UInt64 * searchHeaderSizeLimit)183*f6dc9357SAndroid Build Coastguard Worker HRESULT CInArchive::Open2(CDatabaseEx &db, const UInt64 *searchHeaderSizeLimit)
184*f6dc9357SAndroid Build Coastguard Worker {
185*f6dc9357SAndroid Build Coastguard Worker IsArc = false;
186*f6dc9357SAndroid Build Coastguard Worker ErrorInNames = false;
187*f6dc9357SAndroid Build Coastguard Worker UnexpectedEnd = false;
188*f6dc9357SAndroid Build Coastguard Worker HeaderError = false;
189*f6dc9357SAndroid Build Coastguard Worker
190*f6dc9357SAndroid Build Coastguard Worker db.Clear();
191*f6dc9357SAndroid Build Coastguard Worker RINOK(InStream_GetPos(db.Stream, db.StartPosition))
192*f6dc9357SAndroid Build Coastguard Worker // UInt64 temp = db.StartPosition;
193*f6dc9357SAndroid Build Coastguard Worker
194*f6dc9357SAndroid Build Coastguard Worker CByteBuffer buffer;
195*f6dc9357SAndroid Build Coastguard Worker CInArcInfo &ai = db.ArcInfo;
196*f6dc9357SAndroid Build Coastguard Worker UInt64 startInBuf = 0;
197*f6dc9357SAndroid Build Coastguard Worker
198*f6dc9357SAndroid Build Coastguard Worker CLimitedSequentialInStream *limitedStreamSpec = NULL;
199*f6dc9357SAndroid Build Coastguard Worker CMyComPtr<ISequentialInStream> limitedStream;
200*f6dc9357SAndroid Build Coastguard Worker
201*f6dc9357SAndroid Build Coastguard Worker // for (int iii = 0; iii < 10000; iii++)
202*f6dc9357SAndroid Build Coastguard Worker {
203*f6dc9357SAndroid Build Coastguard Worker // db.StartPosition = temp; RINOK(InStream_SeekSet(db.Stream, db.StartPosition))
204*f6dc9357SAndroid Build Coastguard Worker
205*f6dc9357SAndroid Build Coastguard Worker const UInt32 kMainHeaderSize = 32;
206*f6dc9357SAndroid Build Coastguard Worker Byte header[kMainHeaderSize];
207*f6dc9357SAndroid Build Coastguard Worker const UInt32 kBufSize = 1 << 15;
208*f6dc9357SAndroid Build Coastguard Worker RINOK(ReadStream_FALSE(db.Stream, header, kMainHeaderSize))
209*f6dc9357SAndroid Build Coastguard Worker if (memcmp(header, NHeader::kMarker, NHeader::kMarkerSize) == 0 && ai.Parse(header))
210*f6dc9357SAndroid Build Coastguard Worker {
211*f6dc9357SAndroid Build Coastguard Worker limitedStreamSpec = new CLimitedSequentialInStream;
212*f6dc9357SAndroid Build Coastguard Worker limitedStream = limitedStreamSpec;
213*f6dc9357SAndroid Build Coastguard Worker limitedStreamSpec->SetStream(db.Stream);
214*f6dc9357SAndroid Build Coastguard Worker limitedStreamSpec->Init(ai.Size - NHeader::kMarkerSize);
215*f6dc9357SAndroid Build Coastguard Worker buffer.Alloc(kBufSize);
216*f6dc9357SAndroid Build Coastguard Worker memcpy(buffer, header, kMainHeaderSize);
217*f6dc9357SAndroid Build Coastguard Worker UInt32 numProcessedBytes;
218*f6dc9357SAndroid Build Coastguard Worker RINOK(limitedStream->Read(buffer + kMainHeaderSize, kBufSize - kMainHeaderSize, &numProcessedBytes))
219*f6dc9357SAndroid Build Coastguard Worker _inBuffer.SetBuf(buffer, (UInt32)kBufSize, kMainHeaderSize + numProcessedBytes, kMainHeaderSize);
220*f6dc9357SAndroid Build Coastguard Worker }
221*f6dc9357SAndroid Build Coastguard Worker else
222*f6dc9357SAndroid Build Coastguard Worker {
223*f6dc9357SAndroid Build Coastguard Worker if (searchHeaderSizeLimit && *searchHeaderSizeLimit == 0)
224*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
225*f6dc9357SAndroid Build Coastguard Worker
226*f6dc9357SAndroid Build Coastguard Worker CSignatureFinder finder;
227*f6dc9357SAndroid Build Coastguard Worker
228*f6dc9357SAndroid Build Coastguard Worker finder.Stream = db.Stream;
229*f6dc9357SAndroid Build Coastguard Worker finder.Signature = NHeader::kMarker;
230*f6dc9357SAndroid Build Coastguard Worker finder.SignatureSize = NHeader::kMarkerSize;
231*f6dc9357SAndroid Build Coastguard Worker finder.SearchLimit = searchHeaderSizeLimit;
232*f6dc9357SAndroid Build Coastguard Worker
233*f6dc9357SAndroid Build Coastguard Worker buffer.Alloc(finder.GetTotalCapacity(kBufSize, kMainHeaderSize));
234*f6dc9357SAndroid Build Coastguard Worker finder.Buf = buffer;
235*f6dc9357SAndroid Build Coastguard Worker
236*f6dc9357SAndroid Build Coastguard Worker memcpy(buffer, header, kMainHeaderSize);
237*f6dc9357SAndroid Build Coastguard Worker finder.Processed = db.StartPosition;
238*f6dc9357SAndroid Build Coastguard Worker finder.End = kMainHeaderSize;
239*f6dc9357SAndroid Build Coastguard Worker finder.Pos = 1;
240*f6dc9357SAndroid Build Coastguard Worker
241*f6dc9357SAndroid Build Coastguard Worker for (;;)
242*f6dc9357SAndroid Build Coastguard Worker {
243*f6dc9357SAndroid Build Coastguard Worker RINOK(finder.Find())
244*f6dc9357SAndroid Build Coastguard Worker if (ai.Parse(finder.Buf + finder.Pos))
245*f6dc9357SAndroid Build Coastguard Worker {
246*f6dc9357SAndroid Build Coastguard Worker db.StartPosition = finder.Processed + finder.Pos;
247*f6dc9357SAndroid Build Coastguard Worker limitedStreamSpec = new CLimitedSequentialInStream;
248*f6dc9357SAndroid Build Coastguard Worker limitedStreamSpec->SetStream(db.Stream);
249*f6dc9357SAndroid Build Coastguard Worker limitedStream = limitedStreamSpec;
250*f6dc9357SAndroid Build Coastguard Worker const UInt32 remInFinder = finder.End - finder.Pos;
251*f6dc9357SAndroid Build Coastguard Worker if (ai.Size <= remInFinder)
252*f6dc9357SAndroid Build Coastguard Worker {
253*f6dc9357SAndroid Build Coastguard Worker limitedStreamSpec->Init(0);
254*f6dc9357SAndroid Build Coastguard Worker finder.End = finder.Pos + ai.Size;
255*f6dc9357SAndroid Build Coastguard Worker }
256*f6dc9357SAndroid Build Coastguard Worker else
257*f6dc9357SAndroid Build Coastguard Worker limitedStreamSpec->Init(ai.Size - remInFinder);
258*f6dc9357SAndroid Build Coastguard Worker
259*f6dc9357SAndroid Build Coastguard Worker startInBuf = finder.Pos;
260*f6dc9357SAndroid Build Coastguard Worker _inBuffer.SetBuf(buffer, (UInt32)kBufSize, finder.End, finder.Pos + kMainHeaderSize);
261*f6dc9357SAndroid Build Coastguard Worker break;
262*f6dc9357SAndroid Build Coastguard Worker }
263*f6dc9357SAndroid Build Coastguard Worker finder.Pos++;
264*f6dc9357SAndroid Build Coastguard Worker }
265*f6dc9357SAndroid Build Coastguard Worker }
266*f6dc9357SAndroid Build Coastguard Worker }
267*f6dc9357SAndroid Build Coastguard Worker
268*f6dc9357SAndroid Build Coastguard Worker IsArc = true;
269*f6dc9357SAndroid Build Coastguard Worker
270*f6dc9357SAndroid Build Coastguard Worker _inBuffer.SetStream(limitedStream);
271*f6dc9357SAndroid Build Coastguard Worker if (_tempBuf.Size() == 0)
272*f6dc9357SAndroid Build Coastguard Worker _tempBuf.Alloc(1 << 12);
273*f6dc9357SAndroid Build Coastguard Worker
274*f6dc9357SAndroid Build Coastguard Worker Byte p[16];
275*f6dc9357SAndroid Build Coastguard Worker const unsigned nextSize = 4 + (ai.ReserveBlockPresent() ? 4 : 0);
276*f6dc9357SAndroid Build Coastguard Worker Read(p, nextSize);
277*f6dc9357SAndroid Build Coastguard Worker ai.SetID = Get16(p);
278*f6dc9357SAndroid Build Coastguard Worker ai.CabinetNumber = Get16(p + 2);
279*f6dc9357SAndroid Build Coastguard Worker
280*f6dc9357SAndroid Build Coastguard Worker if (ai.ReserveBlockPresent())
281*f6dc9357SAndroid Build Coastguard Worker {
282*f6dc9357SAndroid Build Coastguard Worker ai.PerCabinet_AreaSize = Get16(p + 4);
283*f6dc9357SAndroid Build Coastguard Worker ai.PerFolder_AreaSize = p[6];
284*f6dc9357SAndroid Build Coastguard Worker ai.PerDataBlock_AreaSize = p[7];
285*f6dc9357SAndroid Build Coastguard Worker Skip(ai.PerCabinet_AreaSize);
286*f6dc9357SAndroid Build Coastguard Worker }
287*f6dc9357SAndroid Build Coastguard Worker
288*f6dc9357SAndroid Build Coastguard Worker if (ai.IsTherePrev()) ReadOtherArc(ai.PrevArc);
289*f6dc9357SAndroid Build Coastguard Worker if (ai.IsThereNext()) ReadOtherArc(ai.NextArc);
290*f6dc9357SAndroid Build Coastguard Worker
291*f6dc9357SAndroid Build Coastguard Worker UInt32 i;
292*f6dc9357SAndroid Build Coastguard Worker
293*f6dc9357SAndroid Build Coastguard Worker db.Folders.ClearAndReserve(ai.NumFolders);
294*f6dc9357SAndroid Build Coastguard Worker
295*f6dc9357SAndroid Build Coastguard Worker for (i = 0; i < ai.NumFolders; i++)
296*f6dc9357SAndroid Build Coastguard Worker {
297*f6dc9357SAndroid Build Coastguard Worker Read(p, 8);
298*f6dc9357SAndroid Build Coastguard Worker CFolder folder;
299*f6dc9357SAndroid Build Coastguard Worker folder.DataStart = Get32(p);
300*f6dc9357SAndroid Build Coastguard Worker folder.NumDataBlocks = Get16(p + 4);
301*f6dc9357SAndroid Build Coastguard Worker folder.MethodMajor = p[6];
302*f6dc9357SAndroid Build Coastguard Worker folder.MethodMinor = p[7];
303*f6dc9357SAndroid Build Coastguard Worker Skip(ai.PerFolder_AreaSize);
304*f6dc9357SAndroid Build Coastguard Worker db.Folders.AddInReserved(folder);
305*f6dc9357SAndroid Build Coastguard Worker }
306*f6dc9357SAndroid Build Coastguard Worker
307*f6dc9357SAndroid Build Coastguard Worker // for (int iii = 0; iii < 10000; iii++) {
308*f6dc9357SAndroid Build Coastguard Worker
309*f6dc9357SAndroid Build Coastguard Worker if (_inBuffer.GetProcessedSize() - startInBuf != ai.FileHeadersOffset)
310*f6dc9357SAndroid Build Coastguard Worker {
311*f6dc9357SAndroid Build Coastguard Worker // printf("\n!!! Seek Error !!!!\n");
312*f6dc9357SAndroid Build Coastguard Worker // fflush(stdout);
313*f6dc9357SAndroid Build Coastguard Worker RINOK(InStream_SeekSet(db.Stream, db.StartPosition + ai.FileHeadersOffset))
314*f6dc9357SAndroid Build Coastguard Worker limitedStreamSpec->Init(ai.Size - ai.FileHeadersOffset);
315*f6dc9357SAndroid Build Coastguard Worker _inBuffer.Init();
316*f6dc9357SAndroid Build Coastguard Worker }
317*f6dc9357SAndroid Build Coastguard Worker
318*f6dc9357SAndroid Build Coastguard Worker db.Items.ClearAndReserve(ai.NumFiles);
319*f6dc9357SAndroid Build Coastguard Worker
320*f6dc9357SAndroid Build Coastguard Worker for (i = 0; i < ai.NumFiles; i++)
321*f6dc9357SAndroid Build Coastguard Worker {
322*f6dc9357SAndroid Build Coastguard Worker Read(p, 16);
323*f6dc9357SAndroid Build Coastguard Worker CItem &item = db.Items.AddNewInReserved();
324*f6dc9357SAndroid Build Coastguard Worker item.Size = Get32(p);
325*f6dc9357SAndroid Build Coastguard Worker item.Offset = Get32(p + 4);
326*f6dc9357SAndroid Build Coastguard Worker item.FolderIndex = Get16(p + 8);
327*f6dc9357SAndroid Build Coastguard Worker const UInt16 pureDate = Get16(p + 10);
328*f6dc9357SAndroid Build Coastguard Worker const UInt16 pureTime = Get16(p + 12);
329*f6dc9357SAndroid Build Coastguard Worker item.Time = (((UInt32)pureDate << 16)) | pureTime;
330*f6dc9357SAndroid Build Coastguard Worker item.Attributes = Get16(p + 14);
331*f6dc9357SAndroid Build Coastguard Worker
332*f6dc9357SAndroid Build Coastguard Worker ReadName(item.Name);
333*f6dc9357SAndroid Build Coastguard Worker
334*f6dc9357SAndroid Build Coastguard Worker if (item.GetFolderIndex(db.Folders.Size()) >= (int)db.Folders.Size())
335*f6dc9357SAndroid Build Coastguard Worker {
336*f6dc9357SAndroid Build Coastguard Worker HeaderError = true;
337*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
338*f6dc9357SAndroid Build Coastguard Worker }
339*f6dc9357SAndroid Build Coastguard Worker }
340*f6dc9357SAndroid Build Coastguard Worker
341*f6dc9357SAndroid Build Coastguard Worker // }
342*f6dc9357SAndroid Build Coastguard Worker
343*f6dc9357SAndroid Build Coastguard Worker return S_OK;
344*f6dc9357SAndroid Build Coastguard Worker }
345*f6dc9357SAndroid Build Coastguard Worker
346*f6dc9357SAndroid Build Coastguard Worker
Open(CDatabaseEx & db,const UInt64 * searchHeaderSizeLimit)347*f6dc9357SAndroid Build Coastguard Worker HRESULT CInArchive::Open(CDatabaseEx &db, const UInt64 *searchHeaderSizeLimit)
348*f6dc9357SAndroid Build Coastguard Worker {
349*f6dc9357SAndroid Build Coastguard Worker try
350*f6dc9357SAndroid Build Coastguard Worker {
351*f6dc9357SAndroid Build Coastguard Worker return Open2(db, searchHeaderSizeLimit);
352*f6dc9357SAndroid Build Coastguard Worker }
353*f6dc9357SAndroid Build Coastguard Worker catch(const CInBufferException &e) { return e.ErrorCode; }
354*f6dc9357SAndroid Build Coastguard Worker catch(CUnexpectedEndException &) { UnexpectedEnd = true; return S_FALSE; }
355*f6dc9357SAndroid Build Coastguard Worker }
356*f6dc9357SAndroid Build Coastguard Worker
357*f6dc9357SAndroid Build Coastguard Worker
358*f6dc9357SAndroid Build Coastguard Worker
359*f6dc9357SAndroid Build Coastguard Worker #define RINOZ(x) { int _tt_ = (x); if (_tt_ != 0) return _tt_; }
360*f6dc9357SAndroid Build Coastguard Worker
CompareMvItems(const CMvItem * p1,const CMvItem * p2,void * param)361*f6dc9357SAndroid Build Coastguard Worker static int CompareMvItems(const CMvItem *p1, const CMvItem *p2, void *param)
362*f6dc9357SAndroid Build Coastguard Worker {
363*f6dc9357SAndroid Build Coastguard Worker const CMvDatabaseEx &mvDb = *(const CMvDatabaseEx *)param;
364*f6dc9357SAndroid Build Coastguard Worker const CDatabaseEx &db1 = mvDb.Volumes[p1->VolumeIndex];
365*f6dc9357SAndroid Build Coastguard Worker const CDatabaseEx &db2 = mvDb.Volumes[p2->VolumeIndex];
366*f6dc9357SAndroid Build Coastguard Worker const CItem &item1 = db1.Items[p1->ItemIndex];
367*f6dc9357SAndroid Build Coastguard Worker const CItem &item2 = db2.Items[p2->ItemIndex];
368*f6dc9357SAndroid Build Coastguard Worker const bool isDir1 = item1.IsDir();
369*f6dc9357SAndroid Build Coastguard Worker const bool isDir2 = item2.IsDir();
370*f6dc9357SAndroid Build Coastguard Worker if (isDir1 && !isDir2) return -1;
371*f6dc9357SAndroid Build Coastguard Worker if (isDir2 && !isDir1) return 1;
372*f6dc9357SAndroid Build Coastguard Worker const int f1 = mvDb.GetFolderIndex(p1);
373*f6dc9357SAndroid Build Coastguard Worker const int f2 = mvDb.GetFolderIndex(p2);
374*f6dc9357SAndroid Build Coastguard Worker RINOZ(MyCompare(f1, f2))
375*f6dc9357SAndroid Build Coastguard Worker RINOZ(MyCompare(item1.Offset, item2.Offset))
376*f6dc9357SAndroid Build Coastguard Worker RINOZ(MyCompare(item1.Size, item2.Size))
377*f6dc9357SAndroid Build Coastguard Worker RINOZ(MyCompare(p1->VolumeIndex, p2->VolumeIndex))
378*f6dc9357SAndroid Build Coastguard Worker return MyCompare(p1->ItemIndex, p2->ItemIndex);
379*f6dc9357SAndroid Build Coastguard Worker }
380*f6dc9357SAndroid Build Coastguard Worker
381*f6dc9357SAndroid Build Coastguard Worker
AreItemsEqual(unsigned i1,unsigned i2)382*f6dc9357SAndroid Build Coastguard Worker bool CMvDatabaseEx::AreItemsEqual(unsigned i1, unsigned i2)
383*f6dc9357SAndroid Build Coastguard Worker {
384*f6dc9357SAndroid Build Coastguard Worker const CMvItem *p1 = &Items[i1];
385*f6dc9357SAndroid Build Coastguard Worker const CMvItem *p2 = &Items[i2];
386*f6dc9357SAndroid Build Coastguard Worker const CDatabaseEx &db1 = Volumes[p1->VolumeIndex];
387*f6dc9357SAndroid Build Coastguard Worker const CDatabaseEx &db2 = Volumes[p2->VolumeIndex];
388*f6dc9357SAndroid Build Coastguard Worker const CItem &item1 = db1.Items[p1->ItemIndex];
389*f6dc9357SAndroid Build Coastguard Worker const CItem &item2 = db2.Items[p2->ItemIndex];
390*f6dc9357SAndroid Build Coastguard Worker return GetFolderIndex(p1) == GetFolderIndex(p2)
391*f6dc9357SAndroid Build Coastguard Worker && item1.Offset == item2.Offset
392*f6dc9357SAndroid Build Coastguard Worker && item1.Size == item2.Size
393*f6dc9357SAndroid Build Coastguard Worker && item1.Name == item2.Name;
394*f6dc9357SAndroid Build Coastguard Worker }
395*f6dc9357SAndroid Build Coastguard Worker
396*f6dc9357SAndroid Build Coastguard Worker
FillSortAndShrink()397*f6dc9357SAndroid Build Coastguard Worker void CMvDatabaseEx::FillSortAndShrink()
398*f6dc9357SAndroid Build Coastguard Worker {
399*f6dc9357SAndroid Build Coastguard Worker Items.Clear();
400*f6dc9357SAndroid Build Coastguard Worker StartFolderOfVol.Clear();
401*f6dc9357SAndroid Build Coastguard Worker FolderStartFileIndex.Clear();
402*f6dc9357SAndroid Build Coastguard Worker
403*f6dc9357SAndroid Build Coastguard Worker int offset = 0;
404*f6dc9357SAndroid Build Coastguard Worker
405*f6dc9357SAndroid Build Coastguard Worker FOR_VECTOR (v, Volumes)
406*f6dc9357SAndroid Build Coastguard Worker {
407*f6dc9357SAndroid Build Coastguard Worker const CDatabaseEx &db = Volumes[v];
408*f6dc9357SAndroid Build Coastguard Worker int curOffset = offset;
409*f6dc9357SAndroid Build Coastguard Worker if (db.IsTherePrevFolder())
410*f6dc9357SAndroid Build Coastguard Worker curOffset--;
411*f6dc9357SAndroid Build Coastguard Worker StartFolderOfVol.Add(curOffset);
412*f6dc9357SAndroid Build Coastguard Worker offset += db.GetNumberOfNewFolders();
413*f6dc9357SAndroid Build Coastguard Worker
414*f6dc9357SAndroid Build Coastguard Worker CMvItem mvItem;
415*f6dc9357SAndroid Build Coastguard Worker mvItem.VolumeIndex = v;
416*f6dc9357SAndroid Build Coastguard Worker FOR_VECTOR (i, db.Items)
417*f6dc9357SAndroid Build Coastguard Worker {
418*f6dc9357SAndroid Build Coastguard Worker mvItem.ItemIndex = i;
419*f6dc9357SAndroid Build Coastguard Worker Items.Add(mvItem);
420*f6dc9357SAndroid Build Coastguard Worker }
421*f6dc9357SAndroid Build Coastguard Worker }
422*f6dc9357SAndroid Build Coastguard Worker
423*f6dc9357SAndroid Build Coastguard Worker if (Items.Size() > 1)
424*f6dc9357SAndroid Build Coastguard Worker {
425*f6dc9357SAndroid Build Coastguard Worker Items.Sort(CompareMvItems, (void *)this);
426*f6dc9357SAndroid Build Coastguard Worker unsigned j = 1;
427*f6dc9357SAndroid Build Coastguard Worker unsigned i = 1;
428*f6dc9357SAndroid Build Coastguard Worker for (; i < Items.Size(); i++)
429*f6dc9357SAndroid Build Coastguard Worker if (!AreItemsEqual(i, i - 1))
430*f6dc9357SAndroid Build Coastguard Worker Items[j++] = Items[i];
431*f6dc9357SAndroid Build Coastguard Worker Items.DeleteFrom(j);
432*f6dc9357SAndroid Build Coastguard Worker }
433*f6dc9357SAndroid Build Coastguard Worker
434*f6dc9357SAndroid Build Coastguard Worker FOR_VECTOR (i, Items)
435*f6dc9357SAndroid Build Coastguard Worker {
436*f6dc9357SAndroid Build Coastguard Worker const int folderIndex = GetFolderIndex(&Items[i]);
437*f6dc9357SAndroid Build Coastguard Worker while (folderIndex >= (int)FolderStartFileIndex.Size())
438*f6dc9357SAndroid Build Coastguard Worker FolderStartFileIndex.Add(i);
439*f6dc9357SAndroid Build Coastguard Worker }
440*f6dc9357SAndroid Build Coastguard Worker }
441*f6dc9357SAndroid Build Coastguard Worker
442*f6dc9357SAndroid Build Coastguard Worker
Check()443*f6dc9357SAndroid Build Coastguard Worker bool CMvDatabaseEx::Check()
444*f6dc9357SAndroid Build Coastguard Worker {
445*f6dc9357SAndroid Build Coastguard Worker for (unsigned v = 1; v < Volumes.Size(); v++)
446*f6dc9357SAndroid Build Coastguard Worker {
447*f6dc9357SAndroid Build Coastguard Worker const CDatabaseEx &db1 = Volumes[v];
448*f6dc9357SAndroid Build Coastguard Worker if (db1.IsTherePrevFolder())
449*f6dc9357SAndroid Build Coastguard Worker {
450*f6dc9357SAndroid Build Coastguard Worker const CDatabaseEx &db0 = Volumes[v - 1];
451*f6dc9357SAndroid Build Coastguard Worker if (db0.Folders.IsEmpty() || db1.Folders.IsEmpty())
452*f6dc9357SAndroid Build Coastguard Worker return false;
453*f6dc9357SAndroid Build Coastguard Worker const CFolder &f0 = db0.Folders.Back();
454*f6dc9357SAndroid Build Coastguard Worker const CFolder &f1 = db1.Folders.FrontItem();
455*f6dc9357SAndroid Build Coastguard Worker if (f0.MethodMajor != f1.MethodMajor ||
456*f6dc9357SAndroid Build Coastguard Worker f0.MethodMinor != f1.MethodMinor)
457*f6dc9357SAndroid Build Coastguard Worker return false;
458*f6dc9357SAndroid Build Coastguard Worker }
459*f6dc9357SAndroid Build Coastguard Worker }
460*f6dc9357SAndroid Build Coastguard Worker
461*f6dc9357SAndroid Build Coastguard Worker UInt32 beginPos = 0;
462*f6dc9357SAndroid Build Coastguard Worker UInt64 endPos = 0;
463*f6dc9357SAndroid Build Coastguard Worker int prevFolder = -2;
464*f6dc9357SAndroid Build Coastguard Worker
465*f6dc9357SAndroid Build Coastguard Worker FOR_VECTOR (i, Items)
466*f6dc9357SAndroid Build Coastguard Worker {
467*f6dc9357SAndroid Build Coastguard Worker const CMvItem &mvItem = Items[i];
468*f6dc9357SAndroid Build Coastguard Worker const int fIndex = GetFolderIndex(&mvItem);
469*f6dc9357SAndroid Build Coastguard Worker if (fIndex >= (int)FolderStartFileIndex.Size())
470*f6dc9357SAndroid Build Coastguard Worker return false;
471*f6dc9357SAndroid Build Coastguard Worker const CItem &item = Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex];
472*f6dc9357SAndroid Build Coastguard Worker if (item.IsDir())
473*f6dc9357SAndroid Build Coastguard Worker continue;
474*f6dc9357SAndroid Build Coastguard Worker
475*f6dc9357SAndroid Build Coastguard Worker const int folderIndex = GetFolderIndex(&mvItem);
476*f6dc9357SAndroid Build Coastguard Worker
477*f6dc9357SAndroid Build Coastguard Worker if (folderIndex != prevFolder)
478*f6dc9357SAndroid Build Coastguard Worker prevFolder = folderIndex;
479*f6dc9357SAndroid Build Coastguard Worker else if (item.Offset < endPos &&
480*f6dc9357SAndroid Build Coastguard Worker (item.Offset != beginPos || item.GetEndOffset() != endPos))
481*f6dc9357SAndroid Build Coastguard Worker return false;
482*f6dc9357SAndroid Build Coastguard Worker
483*f6dc9357SAndroid Build Coastguard Worker beginPos = item.Offset;
484*f6dc9357SAndroid Build Coastguard Worker endPos = item.GetEndOffset();
485*f6dc9357SAndroid Build Coastguard Worker }
486*f6dc9357SAndroid Build Coastguard Worker
487*f6dc9357SAndroid Build Coastguard Worker return true;
488*f6dc9357SAndroid Build Coastguard Worker }
489*f6dc9357SAndroid Build Coastguard Worker
490*f6dc9357SAndroid Build Coastguard Worker }}
491