xref: /aosp_15_r20/external/lzma/CPP/7zip/Archive/Cab/CabIn.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
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