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 §ion = 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