xref: /aosp_15_r20/external/lzma/CPP/7zip/Archive/Chm/ChmIn.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1*f6dc9357SAndroid Build Coastguard Worker // Archive/ChmIn.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/IntToString.h"
10*f6dc9357SAndroid Build Coastguard Worker #include "../../../Common/UTFConvert.h"
11*f6dc9357SAndroid Build Coastguard Worker 
12*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/LimitedStreams.h"
13*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/StreamUtils.h"
14*f6dc9357SAndroid Build Coastguard Worker 
15*f6dc9357SAndroid Build Coastguard Worker #include "ChmIn.h"
16*f6dc9357SAndroid Build Coastguard Worker 
17*f6dc9357SAndroid Build Coastguard Worker #define Get32(p) GetUi32(p)
18*f6dc9357SAndroid Build Coastguard Worker #define Get64(p) GetUi64(p)
19*f6dc9357SAndroid Build Coastguard Worker 
20*f6dc9357SAndroid Build Coastguard Worker namespace NArchive {
21*f6dc9357SAndroid Build Coastguard Worker namespace NChm {
22*f6dc9357SAndroid Build Coastguard Worker 
23*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kSignature_ITSP = 0x50535449;
24*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kSignature_PMGL = 0x4C474D50;
25*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kSignature_LZXC = 0x43585A4C;
26*f6dc9357SAndroid Build Coastguard Worker 
27*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kSignature_IFCM = 0x4D434649;
28*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kSignature_AOLL = 0x4C4C4F41;
29*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kSignature_CAOL = 0x4C4F4143;
30*f6dc9357SAndroid Build Coastguard Worker 
31*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kSignature_ITSF = 0x46535449;
32*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kSignature_ITOL = 0x4C4F5449;
33*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kSignature_ITLS = 0x534C5449;
34*f6dc9357SAndroid Build Coastguard Worker 
35*f6dc9357SAndroid Build Coastguard Worker struct CEnexpectedEndException {};
36*f6dc9357SAndroid Build Coastguard Worker struct CHeaderErrorException {};
37*f6dc9357SAndroid Build Coastguard Worker 
38*f6dc9357SAndroid Build Coastguard Worker // define CHM_LOW, if you want to see low level items
39*f6dc9357SAndroid Build Coastguard Worker // #define CHM_LOW
40*f6dc9357SAndroid Build Coastguard Worker 
41*f6dc9357SAndroid Build Coastguard Worker static const Byte kChmLzxGuid[16]   = { 0x40, 0x89, 0xC2, 0x7F, 0x31, 0x9D, 0xD0, 0x11, 0x9B, 0x27, 0x00, 0xA0, 0xC9, 0x1E, 0x9C, 0x7C };
42*f6dc9357SAndroid Build Coastguard Worker static const Byte kHelp2LzxGuid[16] = { 0xC6, 0x07, 0x90, 0x0A, 0x76, 0x40, 0xD3, 0x11, 0x87, 0x89, 0x00, 0x00, 0xF8, 0x10, 0x57, 0x54 };
43*f6dc9357SAndroid Build Coastguard Worker static const Byte kDesGuid[16]      = { 0xA2, 0xE4, 0xF6, 0x67, 0xBF, 0x60, 0xD3, 0x11, 0x85, 0x40, 0x00, 0xC0, 0x4F, 0x58, 0xC3, 0xCF };
44*f6dc9357SAndroid Build Coastguard Worker 
AreGuidsEqual(const Byte * g1,const Byte * g2)45*f6dc9357SAndroid Build Coastguard Worker static bool inline AreGuidsEqual(const Byte *g1, const Byte *g2)
46*f6dc9357SAndroid Build Coastguard Worker {
47*f6dc9357SAndroid Build Coastguard Worker   return memcmp(g1, g2, 16) == 0;
48*f6dc9357SAndroid Build Coastguard Worker }
49*f6dc9357SAndroid Build Coastguard Worker 
PrintByte(unsigned b,AString & s)50*f6dc9357SAndroid Build Coastguard Worker static void PrintByte(unsigned b, AString &s)
51*f6dc9357SAndroid Build Coastguard Worker {
52*f6dc9357SAndroid Build Coastguard Worker   s += (char)GET_HEX_CHAR_UPPER(b >> 4);
53*f6dc9357SAndroid Build Coastguard Worker   s += (char)GET_HEX_CHAR_LOWER(b & 0xF);
54*f6dc9357SAndroid Build Coastguard Worker }
55*f6dc9357SAndroid Build Coastguard Worker 
GetGuidString() const56*f6dc9357SAndroid Build Coastguard Worker AString CMethodInfo::GetGuidString() const
57*f6dc9357SAndroid Build Coastguard Worker {
58*f6dc9357SAndroid Build Coastguard Worker   char s[16 * 2 + 8];
59*f6dc9357SAndroid Build Coastguard Worker   RawLeGuidToString_Braced(Guid, s);
60*f6dc9357SAndroid Build Coastguard Worker   // MyStringUpper_Ascii(s);
61*f6dc9357SAndroid Build Coastguard Worker   return (AString)s;
62*f6dc9357SAndroid Build Coastguard Worker }
63*f6dc9357SAndroid Build Coastguard Worker 
IsLzx() const64*f6dc9357SAndroid Build Coastguard Worker bool CMethodInfo::IsLzx() const
65*f6dc9357SAndroid Build Coastguard Worker {
66*f6dc9357SAndroid Build Coastguard Worker   if (AreGuidsEqual(Guid, kChmLzxGuid))
67*f6dc9357SAndroid Build Coastguard Worker     return true;
68*f6dc9357SAndroid Build Coastguard Worker   return AreGuidsEqual(Guid, kHelp2LzxGuid);
69*f6dc9357SAndroid Build Coastguard Worker }
70*f6dc9357SAndroid Build Coastguard Worker 
IsDes() const71*f6dc9357SAndroid Build Coastguard Worker bool CMethodInfo::IsDes() const
72*f6dc9357SAndroid Build Coastguard Worker {
73*f6dc9357SAndroid Build Coastguard Worker   return AreGuidsEqual(Guid, kDesGuid);
74*f6dc9357SAndroid Build Coastguard Worker }
75*f6dc9357SAndroid Build Coastguard Worker 
GetName() const76*f6dc9357SAndroid Build Coastguard Worker AString CMethodInfo::GetName() const
77*f6dc9357SAndroid Build Coastguard Worker {
78*f6dc9357SAndroid Build Coastguard Worker   AString s;
79*f6dc9357SAndroid Build Coastguard Worker   if (IsLzx())
80*f6dc9357SAndroid Build Coastguard Worker   {
81*f6dc9357SAndroid Build Coastguard Worker     s = "LZX:";
82*f6dc9357SAndroid Build Coastguard Worker     s.Add_UInt32(LzxInfo.GetNumDictBits());
83*f6dc9357SAndroid Build Coastguard Worker   }
84*f6dc9357SAndroid Build Coastguard Worker   else
85*f6dc9357SAndroid Build Coastguard Worker   {
86*f6dc9357SAndroid Build Coastguard Worker     if (IsDes())
87*f6dc9357SAndroid Build Coastguard Worker       s = "DES";
88*f6dc9357SAndroid Build Coastguard Worker     else
89*f6dc9357SAndroid Build Coastguard Worker     {
90*f6dc9357SAndroid Build Coastguard Worker       s = GetGuidString();
91*f6dc9357SAndroid Build Coastguard Worker       /*
92*f6dc9357SAndroid Build Coastguard Worker       if (ControlData.Size() > 0 && ControlData.Size() <= (1 << 6))
93*f6dc9357SAndroid Build Coastguard Worker       {
94*f6dc9357SAndroid Build Coastguard Worker         s.Add_Colon();
95*f6dc9357SAndroid Build Coastguard Worker         for (size_t i = 0; i < ControlData.Size(); i++)
96*f6dc9357SAndroid Build Coastguard Worker           PrintByte(ControlData[i], s);
97*f6dc9357SAndroid Build Coastguard Worker       }
98*f6dc9357SAndroid Build Coastguard Worker       */
99*f6dc9357SAndroid Build Coastguard Worker     }
100*f6dc9357SAndroid Build Coastguard Worker   }
101*f6dc9357SAndroid Build Coastguard Worker   return s;
102*f6dc9357SAndroid Build Coastguard Worker }
103*f6dc9357SAndroid Build Coastguard Worker 
IsLzx() const104*f6dc9357SAndroid Build Coastguard Worker bool CSectionInfo::IsLzx() const
105*f6dc9357SAndroid Build Coastguard Worker {
106*f6dc9357SAndroid Build Coastguard Worker   if (Methods.Size() != 1)
107*f6dc9357SAndroid Build Coastguard Worker     return false;
108*f6dc9357SAndroid Build Coastguard Worker   return Methods[0].IsLzx();
109*f6dc9357SAndroid Build Coastguard Worker }
110*f6dc9357SAndroid Build Coastguard Worker 
GetMethodName() const111*f6dc9357SAndroid Build Coastguard Worker UString CSectionInfo::GetMethodName() const
112*f6dc9357SAndroid Build Coastguard Worker {
113*f6dc9357SAndroid Build Coastguard Worker   UString s;
114*f6dc9357SAndroid Build Coastguard Worker   if (!IsLzx())
115*f6dc9357SAndroid Build Coastguard Worker   {
116*f6dc9357SAndroid Build Coastguard Worker     UString temp;
117*f6dc9357SAndroid Build Coastguard Worker     ConvertUTF8ToUnicode(Name, temp);
118*f6dc9357SAndroid Build Coastguard Worker       s += temp;
119*f6dc9357SAndroid Build Coastguard Worker     s += ": ";
120*f6dc9357SAndroid Build Coastguard Worker   }
121*f6dc9357SAndroid Build Coastguard Worker   FOR_VECTOR (i, Methods)
122*f6dc9357SAndroid Build Coastguard Worker   {
123*f6dc9357SAndroid Build Coastguard Worker     if (i != 0)
124*f6dc9357SAndroid Build Coastguard Worker       s.Add_Space();
125*f6dc9357SAndroid Build Coastguard Worker     s += Methods[i].GetName();
126*f6dc9357SAndroid Build Coastguard Worker   }
127*f6dc9357SAndroid Build Coastguard Worker   return s;
128*f6dc9357SAndroid Build Coastguard Worker }
129*f6dc9357SAndroid Build Coastguard Worker 
ReadByte()130*f6dc9357SAndroid Build Coastguard Worker Byte CInArchive::ReadByte()
131*f6dc9357SAndroid Build Coastguard Worker {
132*f6dc9357SAndroid Build Coastguard Worker   Byte b;
133*f6dc9357SAndroid Build Coastguard Worker   if (!_inBuffer.ReadByte(b))
134*f6dc9357SAndroid Build Coastguard Worker     throw CEnexpectedEndException();
135*f6dc9357SAndroid Build Coastguard Worker   return b;
136*f6dc9357SAndroid Build Coastguard Worker }
137*f6dc9357SAndroid Build Coastguard Worker 
Skip(size_t size)138*f6dc9357SAndroid Build Coastguard Worker void CInArchive::Skip(size_t size)
139*f6dc9357SAndroid Build Coastguard Worker {
140*f6dc9357SAndroid Build Coastguard Worker   if (_inBuffer.Skip(size) != size)
141*f6dc9357SAndroid Build Coastguard Worker     throw CEnexpectedEndException();
142*f6dc9357SAndroid Build Coastguard Worker }
143*f6dc9357SAndroid Build Coastguard Worker 
ReadBytes(Byte * data,UInt32 size)144*f6dc9357SAndroid Build Coastguard Worker void CInArchive::ReadBytes(Byte *data, UInt32 size)
145*f6dc9357SAndroid Build Coastguard Worker {
146*f6dc9357SAndroid Build Coastguard Worker   if (_inBuffer.ReadBytes(data, size) != size)
147*f6dc9357SAndroid Build Coastguard Worker     throw CEnexpectedEndException();
148*f6dc9357SAndroid Build Coastguard Worker }
149*f6dc9357SAndroid Build Coastguard Worker 
ReadUInt16()150*f6dc9357SAndroid Build Coastguard Worker UInt16 CInArchive::ReadUInt16()
151*f6dc9357SAndroid Build Coastguard Worker {
152*f6dc9357SAndroid Build Coastguard Worker   Byte b0, b1;
153*f6dc9357SAndroid Build Coastguard Worker   if (!_inBuffer.ReadByte(b0)) throw CEnexpectedEndException();
154*f6dc9357SAndroid Build Coastguard Worker   if (!_inBuffer.ReadByte(b1)) throw CEnexpectedEndException();
155*f6dc9357SAndroid Build Coastguard Worker   return (UInt16)(((UInt16)b1 << 8) | b0);
156*f6dc9357SAndroid Build Coastguard Worker }
157*f6dc9357SAndroid Build Coastguard Worker 
ReadUInt32()158*f6dc9357SAndroid Build Coastguard Worker UInt32 CInArchive::ReadUInt32()
159*f6dc9357SAndroid Build Coastguard Worker {
160*f6dc9357SAndroid Build Coastguard Worker   Byte p[4];
161*f6dc9357SAndroid Build Coastguard Worker   ReadBytes(p, 4);
162*f6dc9357SAndroid Build Coastguard Worker   return Get32(p);
163*f6dc9357SAndroid Build Coastguard Worker }
164*f6dc9357SAndroid Build Coastguard Worker 
ReadUInt64()165*f6dc9357SAndroid Build Coastguard Worker UInt64 CInArchive::ReadUInt64()
166*f6dc9357SAndroid Build Coastguard Worker {
167*f6dc9357SAndroid Build Coastguard Worker   Byte p[8];
168*f6dc9357SAndroid Build Coastguard Worker   ReadBytes(p, 8);
169*f6dc9357SAndroid Build Coastguard Worker   return Get64(p);
170*f6dc9357SAndroid Build Coastguard Worker }
171*f6dc9357SAndroid Build Coastguard Worker 
ReadEncInt()172*f6dc9357SAndroid Build Coastguard Worker UInt64 CInArchive::ReadEncInt()
173*f6dc9357SAndroid Build Coastguard Worker {
174*f6dc9357SAndroid Build Coastguard Worker   UInt64 val = 0;
175*f6dc9357SAndroid Build Coastguard Worker   for (int i = 0; i < 9; i++)
176*f6dc9357SAndroid Build Coastguard Worker   {
177*f6dc9357SAndroid Build Coastguard Worker     const unsigned b = ReadByte();
178*f6dc9357SAndroid Build Coastguard Worker     val |= (b & 0x7F);
179*f6dc9357SAndroid Build Coastguard Worker     if (b < 0x80)
180*f6dc9357SAndroid Build Coastguard Worker       return val;
181*f6dc9357SAndroid Build Coastguard Worker     val <<= 7;
182*f6dc9357SAndroid Build Coastguard Worker   }
183*f6dc9357SAndroid Build Coastguard Worker   throw CHeaderErrorException();
184*f6dc9357SAndroid Build Coastguard Worker }
185*f6dc9357SAndroid Build Coastguard Worker 
ReadGUID(Byte * g)186*f6dc9357SAndroid Build Coastguard Worker void CInArchive::ReadGUID(Byte *g)
187*f6dc9357SAndroid Build Coastguard Worker {
188*f6dc9357SAndroid Build Coastguard Worker   ReadBytes(g, 16);
189*f6dc9357SAndroid Build Coastguard Worker }
190*f6dc9357SAndroid Build Coastguard Worker 
ReadString(unsigned size,AString & s)191*f6dc9357SAndroid Build Coastguard Worker void CInArchive::ReadString(unsigned size, AString &s)
192*f6dc9357SAndroid Build Coastguard Worker {
193*f6dc9357SAndroid Build Coastguard Worker   s.Empty();
194*f6dc9357SAndroid Build Coastguard Worker   if (size != 0)
195*f6dc9357SAndroid Build Coastguard Worker   {
196*f6dc9357SAndroid Build Coastguard Worker     ReadBytes((Byte *)s.GetBuf(size), size);
197*f6dc9357SAndroid Build Coastguard Worker     s.ReleaseBuf_CalcLen(size);
198*f6dc9357SAndroid Build Coastguard Worker   }
199*f6dc9357SAndroid Build Coastguard Worker }
200*f6dc9357SAndroid Build Coastguard Worker 
ReadUString(unsigned size,UString & s)201*f6dc9357SAndroid Build Coastguard Worker void CInArchive::ReadUString(unsigned size, UString &s)
202*f6dc9357SAndroid Build Coastguard Worker {
203*f6dc9357SAndroid Build Coastguard Worker   s.Empty();
204*f6dc9357SAndroid Build Coastguard Worker   while (size-- != 0)
205*f6dc9357SAndroid Build Coastguard Worker   {
206*f6dc9357SAndroid Build Coastguard Worker     const wchar_t c = ReadUInt16();
207*f6dc9357SAndroid Build Coastguard Worker     if (c == 0)
208*f6dc9357SAndroid Build Coastguard Worker     {
209*f6dc9357SAndroid Build Coastguard Worker       Skip(2 * size);
210*f6dc9357SAndroid Build Coastguard Worker       return;
211*f6dc9357SAndroid Build Coastguard Worker     }
212*f6dc9357SAndroid Build Coastguard Worker     s += c;
213*f6dc9357SAndroid Build Coastguard Worker   }
214*f6dc9357SAndroid Build Coastguard Worker }
215*f6dc9357SAndroid Build Coastguard Worker 
ReadChunk(IInStream * inStream,UInt64 pos,UInt64 size)216*f6dc9357SAndroid Build Coastguard Worker HRESULT CInArchive::ReadChunk(IInStream *inStream, UInt64 pos, UInt64 size)
217*f6dc9357SAndroid Build Coastguard Worker {
218*f6dc9357SAndroid Build Coastguard Worker   RINOK(InStream_SeekSet(inStream, pos))
219*f6dc9357SAndroid Build Coastguard Worker   CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
220*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<ISequentialInStream> limitedStream(streamSpec);
221*f6dc9357SAndroid Build Coastguard Worker   streamSpec->SetStream(inStream);
222*f6dc9357SAndroid Build Coastguard Worker   streamSpec->Init(size);
223*f6dc9357SAndroid Build Coastguard Worker   m_InStreamRef = limitedStream;
224*f6dc9357SAndroid Build Coastguard Worker   _inBuffer.SetStream(limitedStream);
225*f6dc9357SAndroid Build Coastguard Worker   _inBuffer.Init();
226*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
227*f6dc9357SAndroid Build Coastguard Worker }
228*f6dc9357SAndroid Build Coastguard Worker 
ReadDirEntry(CDatabase & database)229*f6dc9357SAndroid Build Coastguard Worker HRESULT CInArchive::ReadDirEntry(CDatabase &database)
230*f6dc9357SAndroid Build Coastguard Worker {
231*f6dc9357SAndroid Build Coastguard Worker   CItem item;
232*f6dc9357SAndroid Build Coastguard Worker   const UInt64 nameLen = ReadEncInt();
233*f6dc9357SAndroid Build Coastguard Worker   if (nameLen == 0 || nameLen > (1 << 13))
234*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
235*f6dc9357SAndroid Build Coastguard Worker   ReadString((unsigned)nameLen, item.Name);
236*f6dc9357SAndroid Build Coastguard Worker   item.Section = ReadEncInt();
237*f6dc9357SAndroid Build Coastguard Worker   item.Offset = ReadEncInt();
238*f6dc9357SAndroid Build Coastguard Worker   item.Size = ReadEncInt();
239*f6dc9357SAndroid Build Coastguard Worker   database.Items.Add(item);
240*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
241*f6dc9357SAndroid Build Coastguard Worker }
242*f6dc9357SAndroid Build Coastguard Worker 
OpenChm(IInStream * inStream,CDatabase & database)243*f6dc9357SAndroid Build Coastguard Worker HRESULT CInArchive::OpenChm(IInStream *inStream, CDatabase &database)
244*f6dc9357SAndroid Build Coastguard Worker {
245*f6dc9357SAndroid Build Coastguard Worker   UInt32 headerSize = ReadUInt32();
246*f6dc9357SAndroid Build Coastguard Worker   if (headerSize != 0x60)
247*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
248*f6dc9357SAndroid Build Coastguard Worker   database.PhySize = headerSize;
249*f6dc9357SAndroid Build Coastguard Worker 
250*f6dc9357SAndroid Build Coastguard Worker   UInt32 unknown1 = ReadUInt32();
251*f6dc9357SAndroid Build Coastguard Worker   if (unknown1 != 0 && unknown1 != 1) // it's 0 in one .sll file
252*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
253*f6dc9357SAndroid Build Coastguard Worker 
254*f6dc9357SAndroid Build Coastguard Worker   IsArc = true;
255*f6dc9357SAndroid Build Coastguard Worker 
256*f6dc9357SAndroid Build Coastguard Worker   /* UInt32 timeStamp = */ ReadUInt32();
257*f6dc9357SAndroid Build Coastguard Worker       // Considered as a big-endian DWORD, it appears to contain seconds (MSB) and
258*f6dc9357SAndroid Build Coastguard Worker       // fractional seconds (second byte).
259*f6dc9357SAndroid Build Coastguard Worker       // The third and fourth bytes may contain even more fractional bits.
260*f6dc9357SAndroid Build Coastguard Worker       // The 4 least significant bits in the last byte are constant.
261*f6dc9357SAndroid Build Coastguard Worker   /* UInt32 lang = */ ReadUInt32();
262*f6dc9357SAndroid Build Coastguard Worker   Byte g[16];
263*f6dc9357SAndroid Build Coastguard Worker   ReadGUID(g); // {7C01FD10-7BAA-11D0-9E0C-00A0-C922-E6EC}
264*f6dc9357SAndroid Build Coastguard Worker   ReadGUID(g); // {7C01FD11-7BAA-11D0-9E0C-00A0-C922-E6EC}
265*f6dc9357SAndroid Build Coastguard Worker   const unsigned kNumSections = 2;
266*f6dc9357SAndroid Build Coastguard Worker   UInt64 sectionOffsets[kNumSections];
267*f6dc9357SAndroid Build Coastguard Worker   UInt64 sectionSizes[kNumSections];
268*f6dc9357SAndroid Build Coastguard Worker   unsigned i;
269*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < kNumSections; i++)
270*f6dc9357SAndroid Build Coastguard Worker   {
271*f6dc9357SAndroid Build Coastguard Worker     sectionOffsets[i] = ReadUInt64();
272*f6dc9357SAndroid Build Coastguard Worker     sectionSizes[i] = ReadUInt64();
273*f6dc9357SAndroid Build Coastguard Worker     UInt64 end = sectionOffsets[i] + sectionSizes[i];
274*f6dc9357SAndroid Build Coastguard Worker     database.UpdatePhySize(end);
275*f6dc9357SAndroid Build Coastguard Worker   }
276*f6dc9357SAndroid Build Coastguard Worker   // if (chmVersion == 3)
277*f6dc9357SAndroid Build Coastguard Worker     database.ContentOffset = ReadUInt64();
278*f6dc9357SAndroid Build Coastguard Worker   /*
279*f6dc9357SAndroid Build Coastguard Worker   else
280*f6dc9357SAndroid Build Coastguard Worker     database.ContentOffset = database.StartPosition + 0x58
281*f6dc9357SAndroid Build Coastguard Worker   */
282*f6dc9357SAndroid Build Coastguard Worker 
283*f6dc9357SAndroid Build Coastguard Worker   // Section 0
284*f6dc9357SAndroid Build Coastguard Worker   ReadChunk(inStream, sectionOffsets[0], sectionSizes[0]);
285*f6dc9357SAndroid Build Coastguard Worker   if (sectionSizes[0] < 0x18)
286*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
287*f6dc9357SAndroid Build Coastguard Worker   if (ReadUInt32() != 0x01FE)
288*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
289*f6dc9357SAndroid Build Coastguard Worker   ReadUInt32(); // unknown:  0
290*f6dc9357SAndroid Build Coastguard Worker   UInt64 fileSize = ReadUInt64();
291*f6dc9357SAndroid Build Coastguard Worker   database.UpdatePhySize(fileSize);
292*f6dc9357SAndroid Build Coastguard Worker   ReadUInt32(); // unknown:  0
293*f6dc9357SAndroid Build Coastguard Worker   ReadUInt32(); // unknown:  0
294*f6dc9357SAndroid Build Coastguard Worker 
295*f6dc9357SAndroid Build Coastguard Worker   // Section 1: The Directory Listing
296*f6dc9357SAndroid Build Coastguard Worker   ReadChunk(inStream, sectionOffsets[1], sectionSizes[1]);
297*f6dc9357SAndroid Build Coastguard Worker   if (ReadUInt32() != kSignature_ITSP)
298*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
299*f6dc9357SAndroid Build Coastguard Worker   if (ReadUInt32() != 1) // version
300*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
301*f6dc9357SAndroid Build Coastguard Worker   /* UInt32 dirHeaderSize = */ ReadUInt32();
302*f6dc9357SAndroid Build Coastguard Worker   ReadUInt32(); // 0x0A (unknown)
303*f6dc9357SAndroid Build Coastguard Worker   UInt32 dirChunkSize = ReadUInt32(); // $1000
304*f6dc9357SAndroid Build Coastguard Worker   if (dirChunkSize < 32)
305*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
306*f6dc9357SAndroid Build Coastguard Worker   /* UInt32 density = */ ReadUInt32(); //  "Density" of quickref section, usually 2.
307*f6dc9357SAndroid Build Coastguard Worker   /* UInt32 depth = */ ReadUInt32(); //  Depth of the index tree: 1 there is no index,
308*f6dc9357SAndroid Build Coastguard Worker                                // 2 if there is one level of PMGI chunks.
309*f6dc9357SAndroid Build Coastguard Worker 
310*f6dc9357SAndroid Build Coastguard Worker   /* UInt32 chunkNumber = */ ReadUInt32(); //  Chunk number of root index chunk, -1 if there is none
311*f6dc9357SAndroid Build Coastguard Worker                                      // (though at least one file has 0 despite there being no
312*f6dc9357SAndroid Build Coastguard Worker                                      // index chunk, probably a bug.)
313*f6dc9357SAndroid Build Coastguard Worker   /* UInt32 firstPmglChunkNumber = */ ReadUInt32(); // Chunk number of first PMGL (listing) chunk
314*f6dc9357SAndroid Build Coastguard Worker   /* UInt32 lastPmglChunkNumber = */ ReadUInt32();  // Chunk number of last PMGL (listing) chunk
315*f6dc9357SAndroid Build Coastguard Worker   ReadUInt32(); // -1 (unknown)
316*f6dc9357SAndroid Build Coastguard Worker   UInt32 numDirChunks = ReadUInt32(); // Number of directory chunks (total)
317*f6dc9357SAndroid Build Coastguard Worker   /* UInt32 windowsLangId = */ ReadUInt32();
318*f6dc9357SAndroid Build Coastguard Worker   ReadGUID(g);  // {5D02926A-212E-11D0-9DF9-00A0C922E6EC}
319*f6dc9357SAndroid Build Coastguard Worker   ReadUInt32(); // 0x54 (This is the length again)
320*f6dc9357SAndroid Build Coastguard Worker   ReadUInt32(); // -1 (unknown)
321*f6dc9357SAndroid Build Coastguard Worker   ReadUInt32(); // -1 (unknown)
322*f6dc9357SAndroid Build Coastguard Worker   ReadUInt32(); // -1 (unknown)
323*f6dc9357SAndroid Build Coastguard Worker 
324*f6dc9357SAndroid Build Coastguard Worker   for (UInt32 ci = 0; ci < numDirChunks; ci++)
325*f6dc9357SAndroid Build Coastguard Worker   {
326*f6dc9357SAndroid Build Coastguard Worker     UInt64 chunkPos = _inBuffer.GetProcessedSize();
327*f6dc9357SAndroid Build Coastguard Worker     if (ReadUInt32() == kSignature_PMGL)
328*f6dc9357SAndroid Build Coastguard Worker     {
329*f6dc9357SAndroid Build Coastguard Worker       // The quickref area is written backwards from the end of the chunk.
330*f6dc9357SAndroid Build Coastguard Worker       // One quickref entry exists for every n entries in the file, where n
331*f6dc9357SAndroid Build Coastguard Worker       // is calculated as 1 + (1 << quickref density). So for density = 2, n = 5.
332*f6dc9357SAndroid Build Coastguard Worker 
333*f6dc9357SAndroid Build Coastguard Worker       const UInt32 quickrefLength = ReadUInt32(); // Len of free space and/or quickref area at end of directory chunk
334*f6dc9357SAndroid Build Coastguard Worker       if (quickrefLength > dirChunkSize || quickrefLength < 2)
335*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
336*f6dc9357SAndroid Build Coastguard Worker       ReadUInt32(); // Always 0
337*f6dc9357SAndroid Build Coastguard Worker       ReadUInt32(); // Chunk number of previous listing chunk when reading
338*f6dc9357SAndroid Build Coastguard Worker                     // directory in sequence (-1 if this is the first listing chunk)
339*f6dc9357SAndroid Build Coastguard Worker       ReadUInt32(); // Chunk number of next  listing chunk when reading
340*f6dc9357SAndroid Build Coastguard Worker                     // directory in sequence (-1 if this is the last listing chunk)
341*f6dc9357SAndroid Build Coastguard Worker       unsigned numItems = 0;
342*f6dc9357SAndroid Build Coastguard Worker 
343*f6dc9357SAndroid Build Coastguard Worker       for (;;)
344*f6dc9357SAndroid Build Coastguard Worker       {
345*f6dc9357SAndroid Build Coastguard Worker         const UInt64 offset = _inBuffer.GetProcessedSize() - chunkPos;
346*f6dc9357SAndroid Build Coastguard Worker         const UInt32 offsetLimit = dirChunkSize - quickrefLength;
347*f6dc9357SAndroid Build Coastguard Worker         if (offset > offsetLimit)
348*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
349*f6dc9357SAndroid Build Coastguard Worker         if (offset == offsetLimit)
350*f6dc9357SAndroid Build Coastguard Worker           break;
351*f6dc9357SAndroid Build Coastguard Worker         RINOK(ReadDirEntry(database))
352*f6dc9357SAndroid Build Coastguard Worker         numItems++;
353*f6dc9357SAndroid Build Coastguard Worker       }
354*f6dc9357SAndroid Build Coastguard Worker 
355*f6dc9357SAndroid Build Coastguard Worker       Skip(quickrefLength - 2);
356*f6dc9357SAndroid Build Coastguard Worker 
357*f6dc9357SAndroid Build Coastguard Worker       const unsigned rrr = ReadUInt16();
358*f6dc9357SAndroid Build Coastguard Worker       if (rrr != numItems)
359*f6dc9357SAndroid Build Coastguard Worker       {
360*f6dc9357SAndroid Build Coastguard Worker         // Lazarus 9-26-2 chm contains 0 here.
361*f6dc9357SAndroid Build Coastguard Worker         if (rrr != 0)
362*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
363*f6dc9357SAndroid Build Coastguard Worker       }
364*f6dc9357SAndroid Build Coastguard Worker     }
365*f6dc9357SAndroid Build Coastguard Worker     else
366*f6dc9357SAndroid Build Coastguard Worker       Skip(dirChunkSize - 4);
367*f6dc9357SAndroid Build Coastguard Worker   }
368*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
369*f6dc9357SAndroid Build Coastguard Worker }
370*f6dc9357SAndroid Build Coastguard Worker 
OpenHelp2(IInStream * inStream,CDatabase & database)371*f6dc9357SAndroid Build Coastguard Worker HRESULT CInArchive::OpenHelp2(IInStream *inStream, CDatabase &database)
372*f6dc9357SAndroid Build Coastguard Worker {
373*f6dc9357SAndroid Build Coastguard Worker   if (ReadUInt32() != 1) // version
374*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
375*f6dc9357SAndroid Build Coastguard Worker   if (ReadUInt32() != 0x28) // Location of header section table
376*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
377*f6dc9357SAndroid Build Coastguard Worker   UInt32 numHeaderSections = ReadUInt32();
378*f6dc9357SAndroid Build Coastguard Worker   const unsigned kNumHeaderSectionsMax = 5;
379*f6dc9357SAndroid Build Coastguard Worker   if (numHeaderSections != kNumHeaderSectionsMax)
380*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
381*f6dc9357SAndroid Build Coastguard Worker 
382*f6dc9357SAndroid Build Coastguard Worker   IsArc = true;
383*f6dc9357SAndroid Build Coastguard Worker 
384*f6dc9357SAndroid Build Coastguard Worker   ReadUInt32(); // Len of post-header table
385*f6dc9357SAndroid Build Coastguard Worker   Byte g[16];
386*f6dc9357SAndroid Build Coastguard Worker   ReadGUID(g);  // {0A9007C1-4076-11D3-8789-0000F8105754}
387*f6dc9357SAndroid Build Coastguard Worker 
388*f6dc9357SAndroid Build Coastguard Worker   // header section table
389*f6dc9357SAndroid Build Coastguard Worker   UInt64 sectionOffsets[kNumHeaderSectionsMax];
390*f6dc9357SAndroid Build Coastguard Worker   UInt64 sectionSizes[kNumHeaderSectionsMax];
391*f6dc9357SAndroid Build Coastguard Worker   UInt32 i;
392*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < numHeaderSections; i++)
393*f6dc9357SAndroid Build Coastguard Worker   {
394*f6dc9357SAndroid Build Coastguard Worker     sectionOffsets[i] = ReadUInt64();
395*f6dc9357SAndroid Build Coastguard Worker     sectionSizes[i] = ReadUInt64();
396*f6dc9357SAndroid Build Coastguard Worker     UInt64 end = sectionOffsets[i] + sectionSizes[i];
397*f6dc9357SAndroid Build Coastguard Worker     database.UpdatePhySize(end);
398*f6dc9357SAndroid Build Coastguard Worker   }
399*f6dc9357SAndroid Build Coastguard Worker 
400*f6dc9357SAndroid Build Coastguard Worker   // Post-Header
401*f6dc9357SAndroid Build Coastguard Worker   ReadUInt32(); // 2
402*f6dc9357SAndroid Build Coastguard Worker   ReadUInt32(); // 0x98: offset to CAOL from beginning of post-header)
403*f6dc9357SAndroid Build Coastguard Worker   // ----- Directory information
404*f6dc9357SAndroid Build Coastguard Worker   ReadUInt64(); // Chunk number of top-level AOLI chunk in directory, or -1
405*f6dc9357SAndroid Build Coastguard Worker   ReadUInt64(); // Chunk number of first AOLL chunk in directory
406*f6dc9357SAndroid Build Coastguard Worker   ReadUInt64(); // Chunk number of last AOLL chunk in directory
407*f6dc9357SAndroid Build Coastguard Worker   ReadUInt64(); // 0 (unknown)
408*f6dc9357SAndroid Build Coastguard Worker   ReadUInt32(); // $2000 (Directory chunk size of directory)
409*f6dc9357SAndroid Build Coastguard Worker   ReadUInt32(); // Quickref density for main directory, usually 2
410*f6dc9357SAndroid Build Coastguard Worker   ReadUInt32(); // 0 (unknown)
411*f6dc9357SAndroid Build Coastguard Worker   ReadUInt32(); // Depth of main directory index tree
412*f6dc9357SAndroid Build Coastguard Worker                 // 1 there is no index, 2 if there is one level of AOLI chunks.
413*f6dc9357SAndroid Build Coastguard Worker   ReadUInt64(); // 0 (unknown)
414*f6dc9357SAndroid Build Coastguard Worker   UInt64 numDirEntries = ReadUInt64(); // Number of directory entries
415*f6dc9357SAndroid Build Coastguard Worker   // ----- Directory Index Information
416*f6dc9357SAndroid Build Coastguard Worker   ReadUInt64(); // -1 (unknown, probably chunk number of top-level AOLI in directory index)
417*f6dc9357SAndroid Build Coastguard Worker   ReadUInt64(); // Chunk number of first AOLL chunk in directory index
418*f6dc9357SAndroid Build Coastguard Worker   ReadUInt64(); // Chunk number of last AOLL chunk in directory index
419*f6dc9357SAndroid Build Coastguard Worker   ReadUInt64(); // 0 (unknown)
420*f6dc9357SAndroid Build Coastguard Worker   ReadUInt32(); // $200 (Directory chunk size of directory index)
421*f6dc9357SAndroid Build Coastguard Worker   ReadUInt32(); // Quickref density for directory index, usually 2
422*f6dc9357SAndroid Build Coastguard Worker   ReadUInt32(); // 0 (unknown)
423*f6dc9357SAndroid Build Coastguard Worker   ReadUInt32(); // Depth of directory index index tree.
424*f6dc9357SAndroid Build Coastguard Worker   ReadUInt64(); // Possibly flags -- sometimes 1, sometimes 0.
425*f6dc9357SAndroid Build Coastguard Worker   ReadUInt64(); // Number of directory index entries (same as number of AOLL
426*f6dc9357SAndroid Build Coastguard Worker                // chunks in main directory)
427*f6dc9357SAndroid Build Coastguard Worker 
428*f6dc9357SAndroid Build Coastguard Worker   // (The obvious guess for the following two fields, which recur in a number
429*f6dc9357SAndroid Build Coastguard Worker   // of places, is they are maximum sizes for the directory and directory index.
430*f6dc9357SAndroid Build Coastguard Worker   // However, I have seen no direct evidence that this is the case.)
431*f6dc9357SAndroid Build Coastguard Worker 
432*f6dc9357SAndroid Build Coastguard Worker   ReadUInt32(); // $100000 (Same as field following chunk size in directory)
433*f6dc9357SAndroid Build Coastguard Worker   ReadUInt32(); // $20000 (Same as field following chunk size in directory index)
434*f6dc9357SAndroid Build Coastguard Worker 
435*f6dc9357SAndroid Build Coastguard Worker   ReadUInt64(); // 0 (unknown)
436*f6dc9357SAndroid Build Coastguard Worker   if (ReadUInt32() != kSignature_CAOL)
437*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
438*f6dc9357SAndroid Build Coastguard Worker   if (ReadUInt32() != 2) // (Most likely a version number)
439*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
440*f6dc9357SAndroid Build Coastguard Worker   UInt32 caolLength = ReadUInt32(); // $50 (Len of the CAOL section, which includes the ITSF section)
441*f6dc9357SAndroid Build Coastguard Worker   if (caolLength >= 0x2C)
442*f6dc9357SAndroid Build Coastguard Worker   {
443*f6dc9357SAndroid Build Coastguard Worker     /* UInt32 c7 = */ ReadUInt16(); // Unknown.  Remains the same when identical files are built.
444*f6dc9357SAndroid Build Coastguard Worker               // Does not appear to be a checksum.  Many files have
445*f6dc9357SAndroid Build Coastguard Worker               // 'HH' (HTML Help?) here, indicating this may be a compiler ID
446*f6dc9357SAndroid Build Coastguard Worker               //  field.  But at least one ITOL/ITLS compiler does not set this
447*f6dc9357SAndroid Build Coastguard Worker               // field to a constant value.
448*f6dc9357SAndroid Build Coastguard Worker     ReadUInt16(); // 0 (Unknown.  Possibly part of 00A4 field)
449*f6dc9357SAndroid Build Coastguard Worker     ReadUInt32(); // Unknown.  Two values have been seen -- $43ED, and 0.
450*f6dc9357SAndroid Build Coastguard Worker     ReadUInt32(); // $2000 (Directory chunk size of directory)
451*f6dc9357SAndroid Build Coastguard Worker     ReadUInt32(); // $200 (Directory chunk size of directory index)
452*f6dc9357SAndroid Build Coastguard Worker     ReadUInt32(); // $100000 (Same as field following chunk size in directory)
453*f6dc9357SAndroid Build Coastguard Worker     ReadUInt32(); // $20000 (Same as field following chunk size in directory index)
454*f6dc9357SAndroid Build Coastguard Worker     ReadUInt32(); // 0 (unknown)
455*f6dc9357SAndroid Build Coastguard Worker     ReadUInt32(); // 0 (Unknown)
456*f6dc9357SAndroid Build Coastguard Worker     if (caolLength == 0x2C)
457*f6dc9357SAndroid Build Coastguard Worker     {
458*f6dc9357SAndroid Build Coastguard Worker       // fprintf(stdout, "\n !!!NewFormat\n");
459*f6dc9357SAndroid Build Coastguard Worker       // fflush(stdout);
460*f6dc9357SAndroid Build Coastguard Worker       database.ContentOffset = 0; // maybe we must add database.StartPosition here?
461*f6dc9357SAndroid Build Coastguard Worker       database.NewFormat = true;
462*f6dc9357SAndroid Build Coastguard Worker     }
463*f6dc9357SAndroid Build Coastguard Worker     else if (caolLength == 0x50)
464*f6dc9357SAndroid Build Coastguard Worker     {
465*f6dc9357SAndroid Build Coastguard Worker       ReadUInt32(); // 0 (Unknown)
466*f6dc9357SAndroid Build Coastguard Worker       if (ReadUInt32() != kSignature_ITSF)
467*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
468*f6dc9357SAndroid Build Coastguard Worker       if (ReadUInt32() != 4) // $4 (Version number -- CHM uses 3)
469*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
470*f6dc9357SAndroid Build Coastguard Worker       if (ReadUInt32() != 0x20) // $20 (length of ITSF)
471*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
472*f6dc9357SAndroid Build Coastguard Worker       UInt32 unknown = ReadUInt32();
473*f6dc9357SAndroid Build Coastguard Worker       if (unknown != 0 && unknown != 1) // = 0 for some HxW files, 1 in other cases;
474*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
475*f6dc9357SAndroid Build Coastguard Worker       database.ContentOffset = database.StartPosition + ReadUInt64();
476*f6dc9357SAndroid Build Coastguard Worker       /* UInt32 timeStamp = */ ReadUInt32();
477*f6dc9357SAndroid Build Coastguard Worker           // A timestamp of some sort.
478*f6dc9357SAndroid Build Coastguard Worker           // Considered as a big-endian DWORD, it appears to contain
479*f6dc9357SAndroid Build Coastguard Worker           // seconds (MSB) and fractional seconds (second byte).
480*f6dc9357SAndroid Build Coastguard Worker           // The third and fourth bytes may contain even more fractional
481*f6dc9357SAndroid Build Coastguard Worker           // bits.  The 4 least significant bits in the last byte are constant.
482*f6dc9357SAndroid Build Coastguard Worker       /* UInt32 lang = */ ReadUInt32(); // BE?
483*f6dc9357SAndroid Build Coastguard Worker     }
484*f6dc9357SAndroid Build Coastguard Worker     else
485*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
486*f6dc9357SAndroid Build Coastguard Worker   }
487*f6dc9357SAndroid Build Coastguard Worker 
488*f6dc9357SAndroid Build Coastguard Worker   // Section 0
489*f6dc9357SAndroid Build Coastguard Worker   ReadChunk(inStream, database.StartPosition + sectionOffsets[0], sectionSizes[0]);
490*f6dc9357SAndroid Build Coastguard Worker   if (sectionSizes[0] < 0x18)
491*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
492*f6dc9357SAndroid Build Coastguard Worker   if (ReadUInt32() != 0x01FE)
493*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
494*f6dc9357SAndroid Build Coastguard Worker   ReadUInt32(); // unknown:  0
495*f6dc9357SAndroid Build Coastguard Worker   UInt64 fileSize = ReadUInt64();
496*f6dc9357SAndroid Build Coastguard Worker   database.UpdatePhySize(fileSize);
497*f6dc9357SAndroid Build Coastguard Worker   ReadUInt32(); // unknown:  0
498*f6dc9357SAndroid Build Coastguard Worker   ReadUInt32(); // unknown:  0
499*f6dc9357SAndroid Build Coastguard Worker 
500*f6dc9357SAndroid Build Coastguard Worker   // Section 1: The Directory Listing
501*f6dc9357SAndroid Build Coastguard Worker   ReadChunk(inStream, database.StartPosition + sectionOffsets[1], sectionSizes[1]);
502*f6dc9357SAndroid Build Coastguard Worker   if (ReadUInt32() != kSignature_IFCM)
503*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
504*f6dc9357SAndroid Build Coastguard Worker   if (ReadUInt32() != 1) // (probably a version number)
505*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
506*f6dc9357SAndroid Build Coastguard Worker   UInt32 dirChunkSize = ReadUInt32(); // $2000
507*f6dc9357SAndroid Build Coastguard Worker   if (dirChunkSize < 64)
508*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
509*f6dc9357SAndroid Build Coastguard Worker   ReadUInt32(); // $100000  (unknown)
510*f6dc9357SAndroid Build Coastguard Worker   ReadUInt32(); // -1 (unknown)
511*f6dc9357SAndroid Build Coastguard Worker   ReadUInt32(); // -1 (unknown)
512*f6dc9357SAndroid Build Coastguard Worker   UInt32 numDirChunks = ReadUInt32();
513*f6dc9357SAndroid Build Coastguard Worker   ReadUInt32(); // 0 (unknown, probably high word of above)
514*f6dc9357SAndroid Build Coastguard Worker 
515*f6dc9357SAndroid Build Coastguard Worker   for (UInt32 ci = 0; ci < numDirChunks; ci++)
516*f6dc9357SAndroid Build Coastguard Worker   {
517*f6dc9357SAndroid Build Coastguard Worker     UInt64 chunkPos = _inBuffer.GetProcessedSize();
518*f6dc9357SAndroid Build Coastguard Worker     if (ReadUInt32() == kSignature_AOLL)
519*f6dc9357SAndroid Build Coastguard Worker     {
520*f6dc9357SAndroid Build Coastguard Worker       UInt32 quickrefLength = ReadUInt32(); // Len of quickref area at end of directory chunk
521*f6dc9357SAndroid Build Coastguard Worker       if (quickrefLength > dirChunkSize || quickrefLength < 2)
522*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
523*f6dc9357SAndroid Build Coastguard Worker       ReadUInt64(); // Directory chunk number
524*f6dc9357SAndroid Build Coastguard Worker             // This must match physical position in file, that is
525*f6dc9357SAndroid Build Coastguard Worker             // the chunk size times the chunk number must be the
526*f6dc9357SAndroid Build Coastguard Worker             // offset from the end of the directory header.
527*f6dc9357SAndroid Build Coastguard Worker       ReadUInt64(); // Chunk number of previous listing chunk when reading
528*f6dc9357SAndroid Build Coastguard Worker                     // directory in sequence (-1 if first listing chunk)
529*f6dc9357SAndroid Build Coastguard Worker       ReadUInt64(); // Chunk number of next listing chunk when reading
530*f6dc9357SAndroid Build Coastguard Worker                     // directory in sequence (-1 if last listing chunk)
531*f6dc9357SAndroid Build Coastguard Worker       ReadUInt64(); // Number of first listing entry in this chunk
532*f6dc9357SAndroid Build Coastguard Worker       ReadUInt32(); // 1 (unknown -- other values have also been seen here)
533*f6dc9357SAndroid Build Coastguard Worker       ReadUInt32(); // 0 (unknown)
534*f6dc9357SAndroid Build Coastguard Worker 
535*f6dc9357SAndroid Build Coastguard Worker       unsigned numItems = 0;
536*f6dc9357SAndroid Build Coastguard Worker       for (;;)
537*f6dc9357SAndroid Build Coastguard Worker       {
538*f6dc9357SAndroid Build Coastguard Worker         const UInt64 offset = _inBuffer.GetProcessedSize() - chunkPos;
539*f6dc9357SAndroid Build Coastguard Worker         const UInt32 offsetLimit = dirChunkSize - quickrefLength;
540*f6dc9357SAndroid Build Coastguard Worker         if (offset > offsetLimit)
541*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
542*f6dc9357SAndroid Build Coastguard Worker         if (offset == offsetLimit)
543*f6dc9357SAndroid Build Coastguard Worker           break;
544*f6dc9357SAndroid Build Coastguard Worker         if (database.NewFormat)
545*f6dc9357SAndroid Build Coastguard Worker         {
546*f6dc9357SAndroid Build Coastguard Worker           const unsigned nameLen = ReadUInt16();
547*f6dc9357SAndroid Build Coastguard Worker           if (nameLen == 0)
548*f6dc9357SAndroid Build Coastguard Worker             return S_FALSE;
549*f6dc9357SAndroid Build Coastguard Worker           UString name;
550*f6dc9357SAndroid Build Coastguard Worker           ReadUString(nameLen, name);
551*f6dc9357SAndroid Build Coastguard Worker           AString s;
552*f6dc9357SAndroid Build Coastguard Worker           ConvertUnicodeToUTF8(name, s);
553*f6dc9357SAndroid Build Coastguard Worker           {
554*f6dc9357SAndroid Build Coastguard Worker             const unsigned b = ReadByte();
555*f6dc9357SAndroid Build Coastguard Worker             s.Add_Space();
556*f6dc9357SAndroid Build Coastguard Worker             PrintByte(b, s);
557*f6dc9357SAndroid Build Coastguard Worker           }
558*f6dc9357SAndroid Build Coastguard Worker           s.Add_Space();
559*f6dc9357SAndroid Build Coastguard Worker           UInt64 len = ReadEncInt();
560*f6dc9357SAndroid Build Coastguard Worker           // then number of items ?
561*f6dc9357SAndroid Build Coastguard Worker           // then length ?
562*f6dc9357SAndroid Build Coastguard Worker           // then some data (binary encoding?)
563*f6dc9357SAndroid Build Coastguard Worker           if (len > 1u << 29) // what limit here we need?
564*f6dc9357SAndroid Build Coastguard Worker             return S_FALSE;
565*f6dc9357SAndroid Build Coastguard Worker           if (len)
566*f6dc9357SAndroid Build Coastguard Worker           do
567*f6dc9357SAndroid Build Coastguard Worker           {
568*f6dc9357SAndroid Build Coastguard Worker             const unsigned b = ReadByte();
569*f6dc9357SAndroid Build Coastguard Worker             PrintByte(b, s);
570*f6dc9357SAndroid Build Coastguard Worker           }
571*f6dc9357SAndroid Build Coastguard Worker           while (--len);
572*f6dc9357SAndroid Build Coastguard Worker           database.NewFormatString += s;
573*f6dc9357SAndroid Build Coastguard Worker           database.NewFormatString += "\r\n";
574*f6dc9357SAndroid Build Coastguard Worker         }
575*f6dc9357SAndroid Build Coastguard Worker         else
576*f6dc9357SAndroid Build Coastguard Worker         {
577*f6dc9357SAndroid Build Coastguard Worker           RINOK(ReadDirEntry(database))
578*f6dc9357SAndroid Build Coastguard Worker         }
579*f6dc9357SAndroid Build Coastguard Worker         numItems++;
580*f6dc9357SAndroid Build Coastguard Worker       }
581*f6dc9357SAndroid Build Coastguard Worker       Skip(quickrefLength - 2);
582*f6dc9357SAndroid Build Coastguard Worker       if (ReadUInt16() != numItems)
583*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
584*f6dc9357SAndroid Build Coastguard Worker       if (numItems > numDirEntries)
585*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
586*f6dc9357SAndroid Build Coastguard Worker       numDirEntries -= numItems;
587*f6dc9357SAndroid Build Coastguard Worker     }
588*f6dc9357SAndroid Build Coastguard Worker     else
589*f6dc9357SAndroid Build Coastguard Worker       Skip(dirChunkSize - 4);
590*f6dc9357SAndroid Build Coastguard Worker   }
591*f6dc9357SAndroid Build Coastguard Worker   return numDirEntries == 0 ? S_OK : S_FALSE;
592*f6dc9357SAndroid Build Coastguard Worker }
593*f6dc9357SAndroid Build Coastguard Worker 
DecompressStream(IInStream * inStream,const CDatabase & database,const AString & name)594*f6dc9357SAndroid Build Coastguard Worker HRESULT CInArchive::DecompressStream(IInStream *inStream, const CDatabase &database, const AString &name)
595*f6dc9357SAndroid Build Coastguard Worker {
596*f6dc9357SAndroid Build Coastguard Worker   int index = database.FindItem(name);
597*f6dc9357SAndroid Build Coastguard Worker   if (index < 0)
598*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
599*f6dc9357SAndroid Build Coastguard Worker   const CItem &item = database.Items[index];
600*f6dc9357SAndroid Build Coastguard Worker   _chunkSize = item.Size;
601*f6dc9357SAndroid Build Coastguard Worker   return ReadChunk(inStream, database.ContentOffset + item.Offset, item.Size);
602*f6dc9357SAndroid Build Coastguard Worker }
603*f6dc9357SAndroid Build Coastguard Worker 
604*f6dc9357SAndroid Build Coastguard Worker 
605*f6dc9357SAndroid Build Coastguard Worker #define DATA_SPACE "::DataSpace/"
606*f6dc9357SAndroid Build Coastguard Worker #define kNameList DATA_SPACE "NameList"
607*f6dc9357SAndroid Build Coastguard Worker #define kStorage DATA_SPACE "Storage/"
608*f6dc9357SAndroid Build Coastguard Worker #define kContent "Content"
609*f6dc9357SAndroid Build Coastguard Worker #define kControlData "ControlData"
610*f6dc9357SAndroid Build Coastguard Worker #define kSpanInfo "SpanInfo"
611*f6dc9357SAndroid Build Coastguard Worker #define kTransform "Transform/"
612*f6dc9357SAndroid Build Coastguard Worker #define kResetTable "/InstanceData/ResetTable"
613*f6dc9357SAndroid Build Coastguard Worker #define kTransformList "List"
614*f6dc9357SAndroid Build Coastguard Worker 
GetSectionPrefix(const AString & name)615*f6dc9357SAndroid Build Coastguard Worker static AString GetSectionPrefix(const AString &name)
616*f6dc9357SAndroid Build Coastguard Worker {
617*f6dc9357SAndroid Build Coastguard Worker   AString s (kStorage);
618*f6dc9357SAndroid Build Coastguard Worker   s += name;
619*f6dc9357SAndroid Build Coastguard Worker   s.Add_Slash();
620*f6dc9357SAndroid Build Coastguard Worker   return s;
621*f6dc9357SAndroid Build Coastguard Worker }
622*f6dc9357SAndroid Build Coastguard Worker 
623*f6dc9357SAndroid Build Coastguard Worker #define RINOZ(x) { int _tt_ = (x); if (_tt_ != 0) return _tt_; }
624*f6dc9357SAndroid Build Coastguard Worker 
CompareFiles(const unsigned * p1,const unsigned * p2,void * param)625*f6dc9357SAndroid Build Coastguard Worker static int CompareFiles(const unsigned *p1, const unsigned *p2, void *param)
626*f6dc9357SAndroid Build Coastguard Worker {
627*f6dc9357SAndroid Build Coastguard Worker   const CObjectVector<CItem> &items = *(const CObjectVector<CItem> *)param;
628*f6dc9357SAndroid Build Coastguard Worker   const CItem &item1 = items[*p1];
629*f6dc9357SAndroid Build Coastguard Worker   const CItem &item2 = items[*p2];
630*f6dc9357SAndroid Build Coastguard Worker   bool isDir1 = item1.IsDir();
631*f6dc9357SAndroid Build Coastguard Worker   bool isDir2 = item2.IsDir();
632*f6dc9357SAndroid Build Coastguard Worker   if (isDir1 && !isDir2)
633*f6dc9357SAndroid Build Coastguard Worker     return -1;
634*f6dc9357SAndroid Build Coastguard Worker   if (isDir2)
635*f6dc9357SAndroid Build Coastguard Worker   {
636*f6dc9357SAndroid Build Coastguard Worker     if (!isDir1)
637*f6dc9357SAndroid Build Coastguard Worker       return 1;
638*f6dc9357SAndroid Build Coastguard Worker   }
639*f6dc9357SAndroid Build Coastguard Worker   else
640*f6dc9357SAndroid Build Coastguard Worker   {
641*f6dc9357SAndroid Build Coastguard Worker     RINOZ(MyCompare(item1.Section, item2.Section))
642*f6dc9357SAndroid Build Coastguard Worker     RINOZ(MyCompare(item1.Offset, item2.Offset))
643*f6dc9357SAndroid Build Coastguard Worker     RINOZ(MyCompare(item1.Size, item2.Size))
644*f6dc9357SAndroid Build Coastguard Worker   }
645*f6dc9357SAndroid Build Coastguard Worker   return MyCompare(*p1, *p2);
646*f6dc9357SAndroid Build Coastguard Worker }
647*f6dc9357SAndroid Build Coastguard Worker 
SetIndices()648*f6dc9357SAndroid Build Coastguard Worker void CFilesDatabase::SetIndices()
649*f6dc9357SAndroid Build Coastguard Worker {
650*f6dc9357SAndroid Build Coastguard Worker   FOR_VECTOR (i, Items)
651*f6dc9357SAndroid Build Coastguard Worker   {
652*f6dc9357SAndroid Build Coastguard Worker     const CItem &item = Items[i];
653*f6dc9357SAndroid Build Coastguard Worker     if (item.IsUserItem() && item.Name.Len() != 1)
654*f6dc9357SAndroid Build Coastguard Worker       Indices.Add(i);
655*f6dc9357SAndroid Build Coastguard Worker   }
656*f6dc9357SAndroid Build Coastguard Worker }
657*f6dc9357SAndroid Build Coastguard Worker 
Sort()658*f6dc9357SAndroid Build Coastguard Worker void CFilesDatabase::Sort()
659*f6dc9357SAndroid Build Coastguard Worker {
660*f6dc9357SAndroid Build Coastguard Worker   Indices.Sort(CompareFiles, (void *)&Items);
661*f6dc9357SAndroid Build Coastguard Worker }
662*f6dc9357SAndroid Build Coastguard Worker 
Check()663*f6dc9357SAndroid Build Coastguard Worker bool CFilesDatabase::Check()
664*f6dc9357SAndroid Build Coastguard Worker {
665*f6dc9357SAndroid Build Coastguard Worker   UInt64 maxPos = 0;
666*f6dc9357SAndroid Build Coastguard Worker   UInt64 prevSection = 0;
667*f6dc9357SAndroid Build Coastguard Worker   FOR_VECTOR (i, Indices)
668*f6dc9357SAndroid Build Coastguard Worker   {
669*f6dc9357SAndroid Build Coastguard Worker     const CItem &item = Items[Indices[i]];
670*f6dc9357SAndroid Build Coastguard Worker     if (item.Section == 0 || item.IsDir())
671*f6dc9357SAndroid Build Coastguard Worker       continue;
672*f6dc9357SAndroid Build Coastguard Worker     if (item.Section != prevSection)
673*f6dc9357SAndroid Build Coastguard Worker     {
674*f6dc9357SAndroid Build Coastguard Worker       prevSection = item.Section;
675*f6dc9357SAndroid Build Coastguard Worker       maxPos = 0;
676*f6dc9357SAndroid Build Coastguard Worker       continue;
677*f6dc9357SAndroid Build Coastguard Worker     }
678*f6dc9357SAndroid Build Coastguard Worker     if (item.Offset < maxPos)
679*f6dc9357SAndroid Build Coastguard Worker       return false;
680*f6dc9357SAndroid Build Coastguard Worker     maxPos = item.Offset + item.Size;
681*f6dc9357SAndroid Build Coastguard Worker     if (maxPos < item.Offset)
682*f6dc9357SAndroid Build Coastguard Worker       return false;
683*f6dc9357SAndroid Build Coastguard Worker   }
684*f6dc9357SAndroid Build Coastguard Worker   return true;
685*f6dc9357SAndroid Build Coastguard Worker }
686*f6dc9357SAndroid Build Coastguard Worker 
CheckSectionRefs()687*f6dc9357SAndroid Build Coastguard Worker bool CFilesDatabase::CheckSectionRefs()
688*f6dc9357SAndroid Build Coastguard Worker {
689*f6dc9357SAndroid Build Coastguard Worker   FOR_VECTOR (i, Indices)
690*f6dc9357SAndroid Build Coastguard Worker   {
691*f6dc9357SAndroid Build Coastguard Worker     const CItem &item = Items[Indices[i]];
692*f6dc9357SAndroid Build Coastguard Worker     if (item.Section == 0 || item.IsDir())
693*f6dc9357SAndroid Build Coastguard Worker       continue;
694*f6dc9357SAndroid Build Coastguard Worker     if (item.Section >= Sections.Size())
695*f6dc9357SAndroid Build Coastguard Worker       return false;
696*f6dc9357SAndroid Build Coastguard Worker   }
697*f6dc9357SAndroid Build Coastguard Worker   return true;
698*f6dc9357SAndroid Build Coastguard Worker }
699*f6dc9357SAndroid Build Coastguard Worker 
GetLog(UInt32 num)700*f6dc9357SAndroid Build Coastguard Worker static int inline GetLog(UInt32 num)
701*f6dc9357SAndroid Build Coastguard Worker {
702*f6dc9357SAndroid Build Coastguard Worker   for (int i = 0; i < 32; i++)
703*f6dc9357SAndroid Build Coastguard Worker     if (((UInt32)1 << i) == num)
704*f6dc9357SAndroid Build Coastguard Worker       return i;
705*f6dc9357SAndroid Build Coastguard Worker   return -1;
706*f6dc9357SAndroid Build Coastguard Worker }
707*f6dc9357SAndroid Build Coastguard Worker 
OpenHighLevel(IInStream * inStream,CFilesDatabase & database)708*f6dc9357SAndroid Build Coastguard Worker HRESULT CInArchive::OpenHighLevel(IInStream *inStream, CFilesDatabase &database)
709*f6dc9357SAndroid Build Coastguard Worker {
710*f6dc9357SAndroid Build Coastguard Worker   {
711*f6dc9357SAndroid Build Coastguard Worker     // The NameList file
712*f6dc9357SAndroid Build Coastguard Worker     RINOK(DecompressStream(inStream, database, (AString)kNameList))
713*f6dc9357SAndroid Build Coastguard Worker     /* UInt16 length = */ ReadUInt16();
714*f6dc9357SAndroid Build Coastguard Worker     UInt16 numSections = ReadUInt16();
715*f6dc9357SAndroid Build Coastguard Worker     for (unsigned i = 0; i < numSections; i++)
716*f6dc9357SAndroid Build Coastguard Worker     {
717*f6dc9357SAndroid Build Coastguard Worker       CSectionInfo section;
718*f6dc9357SAndroid Build Coastguard Worker       const unsigned nameLen = ReadUInt16();
719*f6dc9357SAndroid Build Coastguard Worker       UString name;
720*f6dc9357SAndroid Build Coastguard Worker       ReadUString(nameLen, name);
721*f6dc9357SAndroid Build Coastguard Worker       if (ReadUInt16() != 0)
722*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
723*f6dc9357SAndroid Build Coastguard Worker       ConvertUnicodeToUTF8(name, section.Name);
724*f6dc9357SAndroid Build Coastguard Worker       // if (!ConvertUnicodeToUTF8(name, section.Name)) return S_FALSE;
725*f6dc9357SAndroid Build Coastguard Worker       database.Sections.Add(section);
726*f6dc9357SAndroid Build Coastguard Worker     }
727*f6dc9357SAndroid Build Coastguard Worker   }
728*f6dc9357SAndroid Build Coastguard Worker 
729*f6dc9357SAndroid Build Coastguard Worker   unsigned si;
730*f6dc9357SAndroid Build Coastguard Worker   for (si = 1; si < database.Sections.Size(); si++)
731*f6dc9357SAndroid Build Coastguard Worker   {
732*f6dc9357SAndroid Build Coastguard Worker     CSectionInfo &section = database.Sections[si];
733*f6dc9357SAndroid Build Coastguard Worker     AString sectionPrefix (GetSectionPrefix(section.Name));
734*f6dc9357SAndroid Build Coastguard Worker     {
735*f6dc9357SAndroid Build Coastguard Worker       // Content
736*f6dc9357SAndroid Build Coastguard Worker       int index = database.FindItem(sectionPrefix + kContent);
737*f6dc9357SAndroid Build Coastguard Worker       if (index < 0)
738*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
739*f6dc9357SAndroid Build Coastguard Worker       const CItem &item = database.Items[index];
740*f6dc9357SAndroid Build Coastguard Worker       section.Offset = item.Offset;
741*f6dc9357SAndroid Build Coastguard Worker       section.CompressedSize = item.Size;
742*f6dc9357SAndroid Build Coastguard Worker     }
743*f6dc9357SAndroid Build Coastguard Worker     AString transformPrefix (sectionPrefix + kTransform);
744*f6dc9357SAndroid Build Coastguard Worker     if (database.Help2Format)
745*f6dc9357SAndroid Build Coastguard Worker     {
746*f6dc9357SAndroid Build Coastguard Worker       // Transform List
747*f6dc9357SAndroid Build Coastguard Worker       RINOK(DecompressStream(inStream, database, transformPrefix + kTransformList))
748*f6dc9357SAndroid Build Coastguard Worker       if ((_chunkSize & 0xF) != 0)
749*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
750*f6dc9357SAndroid Build Coastguard Worker       unsigned numGuids = (unsigned)(_chunkSize / 0x10);
751*f6dc9357SAndroid Build Coastguard Worker       if (numGuids < 1)
752*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
753*f6dc9357SAndroid Build Coastguard Worker       for (unsigned i = 0; i < numGuids; i++)
754*f6dc9357SAndroid Build Coastguard Worker       {
755*f6dc9357SAndroid Build Coastguard Worker         CMethodInfo method;
756*f6dc9357SAndroid Build Coastguard Worker         ReadGUID(method.Guid);
757*f6dc9357SAndroid Build Coastguard Worker         section.Methods.Add(method);
758*f6dc9357SAndroid Build Coastguard Worker       }
759*f6dc9357SAndroid Build Coastguard Worker     }
760*f6dc9357SAndroid Build Coastguard Worker     else
761*f6dc9357SAndroid Build Coastguard Worker     {
762*f6dc9357SAndroid Build Coastguard Worker       CMethodInfo method;
763*f6dc9357SAndroid Build Coastguard Worker       memcpy(method.Guid, kChmLzxGuid, 16);
764*f6dc9357SAndroid Build Coastguard Worker       section.Methods.Add(method);
765*f6dc9357SAndroid Build Coastguard Worker     }
766*f6dc9357SAndroid Build Coastguard Worker 
767*f6dc9357SAndroid Build Coastguard Worker     {
768*f6dc9357SAndroid Build Coastguard Worker       // Control Data
769*f6dc9357SAndroid Build Coastguard Worker       RINOK(DecompressStream(inStream, database, sectionPrefix + kControlData))
770*f6dc9357SAndroid Build Coastguard Worker 
771*f6dc9357SAndroid Build Coastguard Worker       FOR_VECTOR (mi, section.Methods)
772*f6dc9357SAndroid Build Coastguard Worker       {
773*f6dc9357SAndroid Build Coastguard Worker         CMethodInfo &method = section.Methods[mi];
774*f6dc9357SAndroid Build Coastguard Worker         UInt32 numDWORDS = ReadUInt32();
775*f6dc9357SAndroid Build Coastguard Worker         if (method.IsLzx())
776*f6dc9357SAndroid Build Coastguard Worker         {
777*f6dc9357SAndroid Build Coastguard Worker           if (numDWORDS < 5)
778*f6dc9357SAndroid Build Coastguard Worker             return S_FALSE;
779*f6dc9357SAndroid Build Coastguard Worker           if (ReadUInt32() != kSignature_LZXC)
780*f6dc9357SAndroid Build Coastguard Worker             return S_FALSE;
781*f6dc9357SAndroid Build Coastguard Worker           CLzxInfo &li = method.LzxInfo;
782*f6dc9357SAndroid Build Coastguard Worker           li.Version = ReadUInt32();
783*f6dc9357SAndroid Build Coastguard Worker           if (li.Version != 2 && li.Version != 3)
784*f6dc9357SAndroid Build Coastguard Worker             return S_FALSE;
785*f6dc9357SAndroid Build Coastguard Worker 
786*f6dc9357SAndroid Build Coastguard Worker           {
787*f6dc9357SAndroid Build Coastguard Worker             // There is bug in VC6, if we use function call as parameter for inline function
788*f6dc9357SAndroid Build Coastguard Worker             const UInt32 val32 = ReadUInt32();
789*f6dc9357SAndroid Build Coastguard Worker             const int n = GetLog(val32);
790*f6dc9357SAndroid Build Coastguard Worker             if (n < 0 || n > 16)
791*f6dc9357SAndroid Build Coastguard Worker               return S_FALSE;
792*f6dc9357SAndroid Build Coastguard Worker             li.ResetIntervalBits = (unsigned)n;
793*f6dc9357SAndroid Build Coastguard Worker           }
794*f6dc9357SAndroid Build Coastguard Worker 
795*f6dc9357SAndroid Build Coastguard Worker           {
796*f6dc9357SAndroid Build Coastguard Worker             const UInt32 val32 = ReadUInt32();
797*f6dc9357SAndroid Build Coastguard Worker             const int n = GetLog(val32);
798*f6dc9357SAndroid Build Coastguard Worker             if (n < 0 || n > 16)
799*f6dc9357SAndroid Build Coastguard Worker               return S_FALSE;
800*f6dc9357SAndroid Build Coastguard Worker             li.WindowSizeBits = (unsigned)n;
801*f6dc9357SAndroid Build Coastguard Worker           }
802*f6dc9357SAndroid Build Coastguard Worker 
803*f6dc9357SAndroid Build Coastguard Worker           li.CacheSize = ReadUInt32();
804*f6dc9357SAndroid Build Coastguard Worker           numDWORDS -= 5;
805*f6dc9357SAndroid Build Coastguard Worker           if (numDWORDS)
806*f6dc9357SAndroid Build Coastguard Worker           do
807*f6dc9357SAndroid Build Coastguard Worker             ReadUInt32();
808*f6dc9357SAndroid Build Coastguard Worker           while (--numDWORDS);
809*f6dc9357SAndroid Build Coastguard Worker         }
810*f6dc9357SAndroid Build Coastguard Worker         else
811*f6dc9357SAndroid Build Coastguard Worker         {
812*f6dc9357SAndroid Build Coastguard Worker           if (numDWORDS > 1u << 27)
813*f6dc9357SAndroid Build Coastguard Worker             return S_FALSE;
814*f6dc9357SAndroid Build Coastguard Worker           const size_t numBytes = (size_t)numDWORDS * 4;
815*f6dc9357SAndroid Build Coastguard Worker           // method.ControlData.Alloc(numBytes);
816*f6dc9357SAndroid Build Coastguard Worker           // ReadBytes(method.ControlData, numBytes);
817*f6dc9357SAndroid Build Coastguard Worker           Skip(numBytes);
818*f6dc9357SAndroid Build Coastguard Worker         }
819*f6dc9357SAndroid Build Coastguard Worker       }
820*f6dc9357SAndroid Build Coastguard Worker     }
821*f6dc9357SAndroid Build Coastguard Worker 
822*f6dc9357SAndroid Build Coastguard Worker     {
823*f6dc9357SAndroid Build Coastguard Worker       // SpanInfo
824*f6dc9357SAndroid Build Coastguard Worker       RINOK(DecompressStream(inStream, database, sectionPrefix + kSpanInfo))
825*f6dc9357SAndroid Build Coastguard Worker       section.UncompressedSize = ReadUInt64();
826*f6dc9357SAndroid Build Coastguard Worker     }
827*f6dc9357SAndroid Build Coastguard Worker 
828*f6dc9357SAndroid Build Coastguard Worker     // read ResetTable for LZX
829*f6dc9357SAndroid Build Coastguard Worker     FOR_VECTOR (mi, section.Methods)
830*f6dc9357SAndroid Build Coastguard Worker     {
831*f6dc9357SAndroid Build Coastguard Worker       CMethodInfo &method = section.Methods[mi];
832*f6dc9357SAndroid Build Coastguard Worker       if (method.IsLzx())
833*f6dc9357SAndroid Build Coastguard Worker       {
834*f6dc9357SAndroid Build Coastguard Worker         // ResetTable;
835*f6dc9357SAndroid Build Coastguard Worker         RINOK(DecompressStream(inStream, database, transformPrefix +
836*f6dc9357SAndroid Build Coastguard Worker             method.GetGuidString() + kResetTable))
837*f6dc9357SAndroid Build Coastguard Worker         CResetTable &rt = method.LzxInfo.ResetTable;
838*f6dc9357SAndroid Build Coastguard Worker 
839*f6dc9357SAndroid Build Coastguard Worker         if (_chunkSize < 4)
840*f6dc9357SAndroid Build Coastguard Worker         {
841*f6dc9357SAndroid Build Coastguard Worker           if (_chunkSize != 0)
842*f6dc9357SAndroid Build Coastguard Worker             return S_FALSE;
843*f6dc9357SAndroid Build Coastguard Worker           // ResetTable is empty in .chw files
844*f6dc9357SAndroid Build Coastguard Worker           if (section.UncompressedSize != 0)
845*f6dc9357SAndroid Build Coastguard Worker             return S_FALSE;
846*f6dc9357SAndroid Build Coastguard Worker           rt.UncompressedSize = 0;
847*f6dc9357SAndroid Build Coastguard Worker           rt.CompressedSize = 0;
848*f6dc9357SAndroid Build Coastguard Worker           // rt.BlockSize = 0;
849*f6dc9357SAndroid Build Coastguard Worker         }
850*f6dc9357SAndroid Build Coastguard Worker         else
851*f6dc9357SAndroid Build Coastguard Worker         {
852*f6dc9357SAndroid Build Coastguard Worker           const UInt32 ver = ReadUInt32(); // 2  unknown (possibly a version number)
853*f6dc9357SAndroid Build Coastguard Worker           if (ver != 2 && ver != 3)
854*f6dc9357SAndroid Build Coastguard Worker             return S_FALSE;
855*f6dc9357SAndroid Build Coastguard Worker           const UInt32 numEntries = ReadUInt32();
856*f6dc9357SAndroid Build Coastguard Worker           const unsigned kEntrySize = 8;
857*f6dc9357SAndroid Build Coastguard Worker           if (ReadUInt32() != kEntrySize)
858*f6dc9357SAndroid Build Coastguard Worker             return S_FALSE;
859*f6dc9357SAndroid Build Coastguard Worker           const unsigned kRtHeaderSize = 4 * 4 + 8 * 3;
860*f6dc9357SAndroid Build Coastguard Worker           if (ReadUInt32() != kRtHeaderSize)
861*f6dc9357SAndroid Build Coastguard Worker             return S_FALSE;
862*f6dc9357SAndroid Build Coastguard Worker           if (kRtHeaderSize + kEntrySize * (UInt64)numEntries != _chunkSize)
863*f6dc9357SAndroid Build Coastguard Worker             return S_FALSE;
864*f6dc9357SAndroid Build Coastguard Worker 
865*f6dc9357SAndroid Build Coastguard Worker           rt.UncompressedSize = ReadUInt64();
866*f6dc9357SAndroid Build Coastguard Worker           rt.CompressedSize = ReadUInt64();
867*f6dc9357SAndroid Build Coastguard Worker           UInt64 blockSize = ReadUInt64();
868*f6dc9357SAndroid Build Coastguard Worker           if (blockSize != kBlockSize)
869*f6dc9357SAndroid Build Coastguard Worker             return S_FALSE;
870*f6dc9357SAndroid Build Coastguard Worker           UInt64 numBlocks = (rt.UncompressedSize + kBlockSize + 1) / kBlockSize;
871*f6dc9357SAndroid Build Coastguard Worker           if (numEntries != numBlocks &&
872*f6dc9357SAndroid Build Coastguard Worker               numEntries != numBlocks + 1)
873*f6dc9357SAndroid Build Coastguard Worker             return S_FALSE;
874*f6dc9357SAndroid Build Coastguard Worker 
875*f6dc9357SAndroid Build Coastguard Worker           rt.ResetOffsets.ClearAndReserve(numEntries);
876*f6dc9357SAndroid Build Coastguard Worker 
877*f6dc9357SAndroid Build Coastguard Worker           for (UInt32 i = 0; i < numEntries; i++)
878*f6dc9357SAndroid Build Coastguard Worker           {
879*f6dc9357SAndroid Build Coastguard Worker             UInt64 v = ReadUInt64();
880*f6dc9357SAndroid Build Coastguard Worker             if (i != 0 && v < rt.ResetOffsets[i - 1])
881*f6dc9357SAndroid Build Coastguard Worker               return S_FALSE;
882*f6dc9357SAndroid Build Coastguard Worker             rt.ResetOffsets.AddInReserved(v);
883*f6dc9357SAndroid Build Coastguard Worker           }
884*f6dc9357SAndroid Build Coastguard Worker 
885*f6dc9357SAndroid Build Coastguard Worker           if (numEntries != 0)
886*f6dc9357SAndroid Build Coastguard Worker             if (rt.ResetOffsets[0] != 0)
887*f6dc9357SAndroid Build Coastguard Worker               return S_FALSE;
888*f6dc9357SAndroid Build Coastguard Worker 
889*f6dc9357SAndroid Build Coastguard Worker           if (numEntries == numBlocks + 1)
890*f6dc9357SAndroid Build Coastguard Worker           {
891*f6dc9357SAndroid Build Coastguard Worker             // Lazarus 9-26-2 chm contains additional entty
892*f6dc9357SAndroid Build Coastguard Worker             if (rt.ResetOffsets.Back() != rt.CompressedSize)
893*f6dc9357SAndroid Build Coastguard Worker               return S_FALSE;
894*f6dc9357SAndroid Build Coastguard Worker           }
895*f6dc9357SAndroid Build Coastguard Worker         }
896*f6dc9357SAndroid Build Coastguard Worker       }
897*f6dc9357SAndroid Build Coastguard Worker     }
898*f6dc9357SAndroid Build Coastguard Worker   }
899*f6dc9357SAndroid Build Coastguard Worker 
900*f6dc9357SAndroid Build Coastguard Worker   database.SetIndices();
901*f6dc9357SAndroid Build Coastguard Worker   database.Sort();
902*f6dc9357SAndroid Build Coastguard Worker   return database.Check() ? S_OK : S_FALSE;
903*f6dc9357SAndroid Build Coastguard Worker }
904*f6dc9357SAndroid Build Coastguard Worker 
Open2(IInStream * inStream,const UInt64 * searchHeaderSizeLimit,CFilesDatabase & database)905*f6dc9357SAndroid Build Coastguard Worker HRESULT CInArchive::Open2(IInStream *inStream,
906*f6dc9357SAndroid Build Coastguard Worker     const UInt64 *searchHeaderSizeLimit,
907*f6dc9357SAndroid Build Coastguard Worker     CFilesDatabase &database)
908*f6dc9357SAndroid Build Coastguard Worker {
909*f6dc9357SAndroid Build Coastguard Worker   IsArc = false;
910*f6dc9357SAndroid Build Coastguard Worker   HeadersError = false;
911*f6dc9357SAndroid Build Coastguard Worker   UnexpectedEnd = false;
912*f6dc9357SAndroid Build Coastguard Worker   UnsupportedFeature = false;
913*f6dc9357SAndroid Build Coastguard Worker 
914*f6dc9357SAndroid Build Coastguard Worker   database.Clear();
915*f6dc9357SAndroid Build Coastguard Worker   database.Help2Format = _help2;
916*f6dc9357SAndroid Build Coastguard Worker   const UInt32 chmVersion = 3;
917*f6dc9357SAndroid Build Coastguard Worker 
918*f6dc9357SAndroid Build Coastguard Worker   RINOK(InStream_GetPos(inStream, database.StartPosition))
919*f6dc9357SAndroid Build Coastguard Worker 
920*f6dc9357SAndroid Build Coastguard Worker   if (!_inBuffer.Create(1 << 14))
921*f6dc9357SAndroid Build Coastguard Worker     return E_OUTOFMEMORY;
922*f6dc9357SAndroid Build Coastguard Worker   _inBuffer.SetStream(inStream);
923*f6dc9357SAndroid Build Coastguard Worker   _inBuffer.Init();
924*f6dc9357SAndroid Build Coastguard Worker 
925*f6dc9357SAndroid Build Coastguard Worker   if (_help2)
926*f6dc9357SAndroid Build Coastguard Worker   {
927*f6dc9357SAndroid Build Coastguard Worker     const unsigned kSignatureSize = 8;
928*f6dc9357SAndroid Build Coastguard Worker     const UInt64 signature = ((UInt64)kSignature_ITLS << 32) | kSignature_ITOL;
929*f6dc9357SAndroid Build Coastguard Worker     UInt64 limit = 1 << 18;
930*f6dc9357SAndroid Build Coastguard Worker 
931*f6dc9357SAndroid Build Coastguard Worker     if (searchHeaderSizeLimit)
932*f6dc9357SAndroid Build Coastguard Worker       if (limit > *searchHeaderSizeLimit)
933*f6dc9357SAndroid Build Coastguard Worker         limit = *searchHeaderSizeLimit;
934*f6dc9357SAndroid Build Coastguard Worker 
935*f6dc9357SAndroid Build Coastguard Worker     UInt64 val = 0;
936*f6dc9357SAndroid Build Coastguard Worker 
937*f6dc9357SAndroid Build Coastguard Worker     for (;;)
938*f6dc9357SAndroid Build Coastguard Worker     {
939*f6dc9357SAndroid Build Coastguard Worker       Byte b;
940*f6dc9357SAndroid Build Coastguard Worker       if (!_inBuffer.ReadByte(b))
941*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
942*f6dc9357SAndroid Build Coastguard Worker       val >>= 8;
943*f6dc9357SAndroid Build Coastguard Worker       val |= ((UInt64)b) << ((kSignatureSize - 1) * 8);
944*f6dc9357SAndroid Build Coastguard Worker       if (_inBuffer.GetProcessedSize() >= kSignatureSize)
945*f6dc9357SAndroid Build Coastguard Worker       {
946*f6dc9357SAndroid Build Coastguard Worker         if (val == signature)
947*f6dc9357SAndroid Build Coastguard Worker           break;
948*f6dc9357SAndroid Build Coastguard Worker         if (_inBuffer.GetProcessedSize() > limit)
949*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
950*f6dc9357SAndroid Build Coastguard Worker       }
951*f6dc9357SAndroid Build Coastguard Worker     }
952*f6dc9357SAndroid Build Coastguard Worker 
953*f6dc9357SAndroid Build Coastguard Worker     database.StartPosition += _inBuffer.GetProcessedSize() - kSignatureSize;
954*f6dc9357SAndroid Build Coastguard Worker     RINOK(OpenHelp2(inStream, database))
955*f6dc9357SAndroid Build Coastguard Worker     if (database.NewFormat)
956*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
957*f6dc9357SAndroid Build Coastguard Worker   }
958*f6dc9357SAndroid Build Coastguard Worker   else
959*f6dc9357SAndroid Build Coastguard Worker   {
960*f6dc9357SAndroid Build Coastguard Worker     if (ReadUInt32() != kSignature_ITSF)
961*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
962*f6dc9357SAndroid Build Coastguard Worker     if (ReadUInt32() != chmVersion)
963*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
964*f6dc9357SAndroid Build Coastguard Worker     RINOK(OpenChm(inStream, database))
965*f6dc9357SAndroid Build Coastguard Worker   }
966*f6dc9357SAndroid Build Coastguard Worker 
967*f6dc9357SAndroid Build Coastguard Worker 
968*f6dc9357SAndroid Build Coastguard Worker   #ifndef CHM_LOW
969*f6dc9357SAndroid Build Coastguard Worker 
970*f6dc9357SAndroid Build Coastguard Worker   try
971*f6dc9357SAndroid Build Coastguard Worker   {
972*f6dc9357SAndroid Build Coastguard Worker     try
973*f6dc9357SAndroid Build Coastguard Worker     {
974*f6dc9357SAndroid Build Coastguard Worker       HRESULT res = OpenHighLevel(inStream, database);
975*f6dc9357SAndroid Build Coastguard Worker       if (res == S_FALSE)
976*f6dc9357SAndroid Build Coastguard Worker       {
977*f6dc9357SAndroid Build Coastguard Worker         UnsupportedFeature = true;
978*f6dc9357SAndroid Build Coastguard Worker         database.HighLevelClear();
979*f6dc9357SAndroid Build Coastguard Worker         return S_OK;
980*f6dc9357SAndroid Build Coastguard Worker       }
981*f6dc9357SAndroid Build Coastguard Worker       RINOK(res)
982*f6dc9357SAndroid Build Coastguard Worker       if (!database.CheckSectionRefs())
983*f6dc9357SAndroid Build Coastguard Worker         HeadersError = true;
984*f6dc9357SAndroid Build Coastguard Worker       database.LowLevel = false;
985*f6dc9357SAndroid Build Coastguard Worker     }
986*f6dc9357SAndroid Build Coastguard Worker     catch(...)
987*f6dc9357SAndroid Build Coastguard Worker     {
988*f6dc9357SAndroid Build Coastguard Worker       database.HighLevelClear();
989*f6dc9357SAndroid Build Coastguard Worker       throw;
990*f6dc9357SAndroid Build Coastguard Worker     }
991*f6dc9357SAndroid Build Coastguard Worker   }
992*f6dc9357SAndroid Build Coastguard Worker   // catch(const CInBufferException &e) { return e.ErrorCode; }
993*f6dc9357SAndroid Build Coastguard Worker   catch(CEnexpectedEndException &) { UnexpectedEnd = true; }
994*f6dc9357SAndroid Build Coastguard Worker   catch(CHeaderErrorException &) { HeadersError = true; }
995*f6dc9357SAndroid Build Coastguard Worker   catch(...) { throw; }
996*f6dc9357SAndroid Build Coastguard Worker 
997*f6dc9357SAndroid Build Coastguard Worker   #endif
998*f6dc9357SAndroid Build Coastguard Worker 
999*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1000*f6dc9357SAndroid Build Coastguard Worker }
1001*f6dc9357SAndroid Build Coastguard Worker 
Open(IInStream * inStream,const UInt64 * searchHeaderSizeLimit,CFilesDatabase & database)1002*f6dc9357SAndroid Build Coastguard Worker HRESULT CInArchive::Open(IInStream *inStream,
1003*f6dc9357SAndroid Build Coastguard Worker     const UInt64 *searchHeaderSizeLimit,
1004*f6dc9357SAndroid Build Coastguard Worker     CFilesDatabase &database)
1005*f6dc9357SAndroid Build Coastguard Worker {
1006*f6dc9357SAndroid Build Coastguard Worker   try
1007*f6dc9357SAndroid Build Coastguard Worker   {
1008*f6dc9357SAndroid Build Coastguard Worker     try
1009*f6dc9357SAndroid Build Coastguard Worker     {
1010*f6dc9357SAndroid Build Coastguard Worker       HRESULT res = Open2(inStream, searchHeaderSizeLimit, database);
1011*f6dc9357SAndroid Build Coastguard Worker       m_InStreamRef.Release();
1012*f6dc9357SAndroid Build Coastguard Worker       return res;
1013*f6dc9357SAndroid Build Coastguard Worker     }
1014*f6dc9357SAndroid Build Coastguard Worker     catch(...)
1015*f6dc9357SAndroid Build Coastguard Worker     {
1016*f6dc9357SAndroid Build Coastguard Worker       m_InStreamRef.Release();
1017*f6dc9357SAndroid Build Coastguard Worker       throw;
1018*f6dc9357SAndroid Build Coastguard Worker     }
1019*f6dc9357SAndroid Build Coastguard Worker   }
1020*f6dc9357SAndroid Build Coastguard Worker   catch(const CInBufferException &e) { return e.ErrorCode; }
1021*f6dc9357SAndroid Build Coastguard Worker   catch(CEnexpectedEndException &) { UnexpectedEnd = true; }
1022*f6dc9357SAndroid Build Coastguard Worker   catch(CHeaderErrorException &) { HeadersError = true; }
1023*f6dc9357SAndroid Build Coastguard Worker   return S_FALSE;
1024*f6dc9357SAndroid Build Coastguard Worker }
1025*f6dc9357SAndroid Build Coastguard Worker 
1026*f6dc9357SAndroid Build Coastguard Worker }}
1027