1*f6dc9357SAndroid Build Coastguard Worker // ComHandler.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 "../../../C/Alloc.h"
6*f6dc9357SAndroid Build Coastguard Worker #include "../../../C/CpuArch.h"
7*f6dc9357SAndroid Build Coastguard Worker
8*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/IntToString.h"
9*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/ComTry.h"
10*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/MyCom.h"
11*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/MyBuffer.h"
12*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/MyString.h"
13*f6dc9357SAndroid Build Coastguard Worker
14*f6dc9357SAndroid Build Coastguard Worker #include "../../Windows/PropVariant.h"
15*f6dc9357SAndroid Build Coastguard Worker
16*f6dc9357SAndroid Build Coastguard Worker #include "../Common/LimitedStreams.h"
17*f6dc9357SAndroid Build Coastguard Worker #include "../Common/ProgressUtils.h"
18*f6dc9357SAndroid Build Coastguard Worker #include "../Common/RegisterArc.h"
19*f6dc9357SAndroid Build Coastguard Worker #include "../Common/StreamUtils.h"
20*f6dc9357SAndroid Build Coastguard Worker
21*f6dc9357SAndroid Build Coastguard Worker #include "../Compress/CopyCoder.h"
22*f6dc9357SAndroid Build Coastguard Worker
23*f6dc9357SAndroid Build Coastguard Worker #define Get16(p) GetUi16(p)
24*f6dc9357SAndroid Build Coastguard Worker #define Get32(p) GetUi32(p)
25*f6dc9357SAndroid Build Coastguard Worker
26*f6dc9357SAndroid Build Coastguard Worker namespace NArchive {
27*f6dc9357SAndroid Build Coastguard Worker namespace NCom {
28*f6dc9357SAndroid Build Coastguard Worker
29*f6dc9357SAndroid Build Coastguard Worker static const Byte kSignature[] =
30*f6dc9357SAndroid Build Coastguard Worker { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 };
31*f6dc9357SAndroid Build Coastguard Worker
32*f6dc9357SAndroid Build Coastguard Worker enum EType
33*f6dc9357SAndroid Build Coastguard Worker {
34*f6dc9357SAndroid Build Coastguard Worker k_Type_Common,
35*f6dc9357SAndroid Build Coastguard Worker k_Type_Msi,
36*f6dc9357SAndroid Build Coastguard Worker k_Type_Msp,
37*f6dc9357SAndroid Build Coastguard Worker k_Type_Doc,
38*f6dc9357SAndroid Build Coastguard Worker k_Type_Ppt,
39*f6dc9357SAndroid Build Coastguard Worker k_Type_Xls
40*f6dc9357SAndroid Build Coastguard Worker };
41*f6dc9357SAndroid Build Coastguard Worker
42*f6dc9357SAndroid Build Coastguard Worker static const char * const kExtensions[] =
43*f6dc9357SAndroid Build Coastguard Worker {
44*f6dc9357SAndroid Build Coastguard Worker "compound"
45*f6dc9357SAndroid Build Coastguard Worker , "msi"
46*f6dc9357SAndroid Build Coastguard Worker , "msp"
47*f6dc9357SAndroid Build Coastguard Worker , "doc"
48*f6dc9357SAndroid Build Coastguard Worker , "ppt"
49*f6dc9357SAndroid Build Coastguard Worker , "xls"
50*f6dc9357SAndroid Build Coastguard Worker };
51*f6dc9357SAndroid Build Coastguard Worker
52*f6dc9357SAndroid Build Coastguard Worker namespace NFatID
53*f6dc9357SAndroid Build Coastguard Worker {
54*f6dc9357SAndroid Build Coastguard Worker // static const UInt32 kFree = 0xFFFFFFFF;
55*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kEndOfChain = 0xFFFFFFFE;
56*f6dc9357SAndroid Build Coastguard Worker // static const UInt32 kFatSector = 0xFFFFFFFD;
57*f6dc9357SAndroid Build Coastguard Worker // static const UInt32 kMatSector = 0xFFFFFFFC;
58*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kMaxValue = 0xFFFFFFFA;
59*f6dc9357SAndroid Build Coastguard Worker }
60*f6dc9357SAndroid Build Coastguard Worker
61*f6dc9357SAndroid Build Coastguard Worker namespace NItemType
62*f6dc9357SAndroid Build Coastguard Worker {
63*f6dc9357SAndroid Build Coastguard Worker static const Byte kEmpty = 0;
64*f6dc9357SAndroid Build Coastguard Worker static const Byte kStorage = 1;
65*f6dc9357SAndroid Build Coastguard Worker // static const Byte kStream = 2;
66*f6dc9357SAndroid Build Coastguard Worker // static const Byte kLockBytes = 3;
67*f6dc9357SAndroid Build Coastguard Worker // static const Byte kProperty = 4;
68*f6dc9357SAndroid Build Coastguard Worker static const Byte kRootStorage = 5;
69*f6dc9357SAndroid Build Coastguard Worker }
70*f6dc9357SAndroid Build Coastguard Worker
71*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kNameSizeMax = 64;
72*f6dc9357SAndroid Build Coastguard Worker
73*f6dc9357SAndroid Build Coastguard Worker struct CItem
74*f6dc9357SAndroid Build Coastguard Worker {
75*f6dc9357SAndroid Build Coastguard Worker Byte Name[kNameSizeMax];
76*f6dc9357SAndroid Build Coastguard Worker // UInt16 NameSize;
77*f6dc9357SAndroid Build Coastguard Worker // UInt32 Flags;
78*f6dc9357SAndroid Build Coastguard Worker FILETIME CTime;
79*f6dc9357SAndroid Build Coastguard Worker FILETIME MTime;
80*f6dc9357SAndroid Build Coastguard Worker UInt64 Size;
81*f6dc9357SAndroid Build Coastguard Worker UInt32 LeftDid;
82*f6dc9357SAndroid Build Coastguard Worker UInt32 RightDid;
83*f6dc9357SAndroid Build Coastguard Worker UInt32 SonDid;
84*f6dc9357SAndroid Build Coastguard Worker UInt32 Sid;
85*f6dc9357SAndroid Build Coastguard Worker Byte Type;
86*f6dc9357SAndroid Build Coastguard Worker
IsEmptyNArchive::NCom::CItem87*f6dc9357SAndroid Build Coastguard Worker bool IsEmpty() const { return Type == NItemType::kEmpty; }
IsDirNArchive::NCom::CItem88*f6dc9357SAndroid Build Coastguard Worker bool IsDir() const { return Type == NItemType::kStorage || Type == NItemType::kRootStorage; }
89*f6dc9357SAndroid Build Coastguard Worker
90*f6dc9357SAndroid Build Coastguard Worker void Parse(const Byte *p, bool mode64bit);
91*f6dc9357SAndroid Build Coastguard Worker };
92*f6dc9357SAndroid Build Coastguard Worker
93*f6dc9357SAndroid Build Coastguard Worker struct CRef
94*f6dc9357SAndroid Build Coastguard Worker {
95*f6dc9357SAndroid Build Coastguard Worker int Parent;
96*f6dc9357SAndroid Build Coastguard Worker UInt32 Did;
97*f6dc9357SAndroid Build Coastguard Worker };
98*f6dc9357SAndroid Build Coastguard Worker
99*f6dc9357SAndroid Build Coastguard Worker class CDatabase
100*f6dc9357SAndroid Build Coastguard Worker {
101*f6dc9357SAndroid Build Coastguard Worker UInt32 NumSectorsInMiniStream;
102*f6dc9357SAndroid Build Coastguard Worker CObjArray<UInt32> MiniSids;
103*f6dc9357SAndroid Build Coastguard Worker
104*f6dc9357SAndroid Build Coastguard Worker HRESULT AddNode(int parent, UInt32 did);
105*f6dc9357SAndroid Build Coastguard Worker public:
106*f6dc9357SAndroid Build Coastguard Worker
107*f6dc9357SAndroid Build Coastguard Worker CObjArray<UInt32> Fat;
108*f6dc9357SAndroid Build Coastguard Worker UInt32 FatSize;
109*f6dc9357SAndroid Build Coastguard Worker
110*f6dc9357SAndroid Build Coastguard Worker CObjArray<UInt32> Mat;
111*f6dc9357SAndroid Build Coastguard Worker UInt32 MatSize;
112*f6dc9357SAndroid Build Coastguard Worker
113*f6dc9357SAndroid Build Coastguard Worker CObjectVector<CItem> Items;
114*f6dc9357SAndroid Build Coastguard Worker CRecordVector<CRef> Refs;
115*f6dc9357SAndroid Build Coastguard Worker
116*f6dc9357SAndroid Build Coastguard Worker UInt32 LongStreamMinSize;
117*f6dc9357SAndroid Build Coastguard Worker unsigned SectorSizeBits;
118*f6dc9357SAndroid Build Coastguard Worker unsigned MiniSectorSizeBits;
119*f6dc9357SAndroid Build Coastguard Worker
120*f6dc9357SAndroid Build Coastguard Worker Int32 MainSubfile;
121*f6dc9357SAndroid Build Coastguard Worker
122*f6dc9357SAndroid Build Coastguard Worker UInt64 PhySize;
123*f6dc9357SAndroid Build Coastguard Worker UInt64 PhySize_Aligned;
124*f6dc9357SAndroid Build Coastguard Worker EType Type;
125*f6dc9357SAndroid Build Coastguard Worker
IsNotArcType() const126*f6dc9357SAndroid Build Coastguard Worker bool IsNotArcType() const
127*f6dc9357SAndroid Build Coastguard Worker {
128*f6dc9357SAndroid Build Coastguard Worker return
129*f6dc9357SAndroid Build Coastguard Worker Type != k_Type_Msi &&
130*f6dc9357SAndroid Build Coastguard Worker Type != k_Type_Msp;
131*f6dc9357SAndroid Build Coastguard Worker }
132*f6dc9357SAndroid Build Coastguard Worker
UpdatePhySize(UInt64 val,UInt64 val_Aligned)133*f6dc9357SAndroid Build Coastguard Worker void UpdatePhySize(UInt64 val, UInt64 val_Aligned)
134*f6dc9357SAndroid Build Coastguard Worker {
135*f6dc9357SAndroid Build Coastguard Worker if (PhySize < val)
136*f6dc9357SAndroid Build Coastguard Worker PhySize = val;
137*f6dc9357SAndroid Build Coastguard Worker if (PhySize_Aligned < val_Aligned)
138*f6dc9357SAndroid Build Coastguard Worker PhySize_Aligned = val_Aligned;
139*f6dc9357SAndroid Build Coastguard Worker }
140*f6dc9357SAndroid Build Coastguard Worker HRESULT ReadSector(IInStream *inStream, Byte *buf, unsigned sectorSizeBits, UInt32 sid);
141*f6dc9357SAndroid Build Coastguard Worker HRESULT ReadIDs(IInStream *inStream, Byte *buf, unsigned sectorSizeBits, UInt32 sid, UInt32 *dest);
142*f6dc9357SAndroid Build Coastguard Worker
143*f6dc9357SAndroid Build Coastguard Worker HRESULT Update_PhySize_WithItem(unsigned index);
144*f6dc9357SAndroid Build Coastguard Worker
145*f6dc9357SAndroid Build Coastguard Worker void Clear();
IsLargeStream(UInt64 size) const146*f6dc9357SAndroid Build Coastguard Worker bool IsLargeStream(UInt64 size) const { return size >= LongStreamMinSize; }
147*f6dc9357SAndroid Build Coastguard Worker UString GetItemPath(UInt32 index) const;
148*f6dc9357SAndroid Build Coastguard Worker
GetItemPackSize(UInt64 size) const149*f6dc9357SAndroid Build Coastguard Worker UInt64 GetItemPackSize(UInt64 size) const
150*f6dc9357SAndroid Build Coastguard Worker {
151*f6dc9357SAndroid Build Coastguard Worker UInt64 mask = ((UInt64)1 << (IsLargeStream(size) ? SectorSizeBits : MiniSectorSizeBits)) - 1;
152*f6dc9357SAndroid Build Coastguard Worker return (size + mask) & ~mask;
153*f6dc9357SAndroid Build Coastguard Worker }
154*f6dc9357SAndroid Build Coastguard Worker
GetMiniCluster(UInt32 sid,UInt64 & res) const155*f6dc9357SAndroid Build Coastguard Worker bool GetMiniCluster(UInt32 sid, UInt64 &res) const
156*f6dc9357SAndroid Build Coastguard Worker {
157*f6dc9357SAndroid Build Coastguard Worker unsigned subBits = SectorSizeBits - MiniSectorSizeBits;
158*f6dc9357SAndroid Build Coastguard Worker UInt32 fid = sid >> subBits;
159*f6dc9357SAndroid Build Coastguard Worker if (fid >= NumSectorsInMiniStream)
160*f6dc9357SAndroid Build Coastguard Worker return false;
161*f6dc9357SAndroid Build Coastguard Worker res = (((UInt64)MiniSids[fid] + 1) << subBits) + (sid & ((1 << subBits) - 1));
162*f6dc9357SAndroid Build Coastguard Worker return true;
163*f6dc9357SAndroid Build Coastguard Worker }
164*f6dc9357SAndroid Build Coastguard Worker
165*f6dc9357SAndroid Build Coastguard Worker HRESULT Open(IInStream *inStream);
166*f6dc9357SAndroid Build Coastguard Worker };
167*f6dc9357SAndroid Build Coastguard Worker
168*f6dc9357SAndroid Build Coastguard Worker
ReadSector(IInStream * inStream,Byte * buf,unsigned sectorSizeBits,UInt32 sid)169*f6dc9357SAndroid Build Coastguard Worker HRESULT CDatabase::ReadSector(IInStream *inStream, Byte *buf, unsigned sectorSizeBits, UInt32 sid)
170*f6dc9357SAndroid Build Coastguard Worker {
171*f6dc9357SAndroid Build Coastguard Worker const UInt64 end = ((UInt64)sid + 2) << sectorSizeBits;
172*f6dc9357SAndroid Build Coastguard Worker UpdatePhySize(end, end);
173*f6dc9357SAndroid Build Coastguard Worker RINOK(InStream_SeekSet(inStream, (((UInt64)sid + 1) << sectorSizeBits)))
174*f6dc9357SAndroid Build Coastguard Worker return ReadStream_FALSE(inStream, buf, (size_t)1 << sectorSizeBits);
175*f6dc9357SAndroid Build Coastguard Worker }
176*f6dc9357SAndroid Build Coastguard Worker
ReadIDs(IInStream * inStream,Byte * buf,unsigned sectorSizeBits,UInt32 sid,UInt32 * dest)177*f6dc9357SAndroid Build Coastguard Worker HRESULT CDatabase::ReadIDs(IInStream *inStream, Byte *buf, unsigned sectorSizeBits, UInt32 sid, UInt32 *dest)
178*f6dc9357SAndroid Build Coastguard Worker {
179*f6dc9357SAndroid Build Coastguard Worker RINOK(ReadSector(inStream, buf, sectorSizeBits, sid))
180*f6dc9357SAndroid Build Coastguard Worker UInt32 sectorSize = (UInt32)1 << sectorSizeBits;
181*f6dc9357SAndroid Build Coastguard Worker for (UInt32 t = 0; t < sectorSize; t += 4)
182*f6dc9357SAndroid Build Coastguard Worker *dest++ = Get32(buf + t);
183*f6dc9357SAndroid Build Coastguard Worker return S_OK;
184*f6dc9357SAndroid Build Coastguard Worker }
185*f6dc9357SAndroid Build Coastguard Worker
GetFileTimeFromMem(const Byte * p,FILETIME * ft)186*f6dc9357SAndroid Build Coastguard Worker static void GetFileTimeFromMem(const Byte *p, FILETIME *ft)
187*f6dc9357SAndroid Build Coastguard Worker {
188*f6dc9357SAndroid Build Coastguard Worker ft->dwLowDateTime = Get32(p);
189*f6dc9357SAndroid Build Coastguard Worker ft->dwHighDateTime = Get32(p + 4);
190*f6dc9357SAndroid Build Coastguard Worker }
191*f6dc9357SAndroid Build Coastguard Worker
Parse(const Byte * p,bool mode64bit)192*f6dc9357SAndroid Build Coastguard Worker void CItem::Parse(const Byte *p, bool mode64bit)
193*f6dc9357SAndroid Build Coastguard Worker {
194*f6dc9357SAndroid Build Coastguard Worker memcpy(Name, p, kNameSizeMax);
195*f6dc9357SAndroid Build Coastguard Worker // NameSize = Get16(p + 64);
196*f6dc9357SAndroid Build Coastguard Worker Type = p[66];
197*f6dc9357SAndroid Build Coastguard Worker LeftDid = Get32(p + 68);
198*f6dc9357SAndroid Build Coastguard Worker RightDid = Get32(p + 72);
199*f6dc9357SAndroid Build Coastguard Worker SonDid = Get32(p + 76);
200*f6dc9357SAndroid Build Coastguard Worker // Flags = Get32(p + 96);
201*f6dc9357SAndroid Build Coastguard Worker GetFileTimeFromMem(p + 100, &CTime);
202*f6dc9357SAndroid Build Coastguard Worker GetFileTimeFromMem(p + 108, &MTime);
203*f6dc9357SAndroid Build Coastguard Worker Sid = Get32(p + 116);
204*f6dc9357SAndroid Build Coastguard Worker Size = Get32(p + 120);
205*f6dc9357SAndroid Build Coastguard Worker if (mode64bit)
206*f6dc9357SAndroid Build Coastguard Worker Size |= ((UInt64)Get32(p + 124) << 32);
207*f6dc9357SAndroid Build Coastguard Worker }
208*f6dc9357SAndroid Build Coastguard Worker
Clear()209*f6dc9357SAndroid Build Coastguard Worker void CDatabase::Clear()
210*f6dc9357SAndroid Build Coastguard Worker {
211*f6dc9357SAndroid Build Coastguard Worker PhySize = 0;
212*f6dc9357SAndroid Build Coastguard Worker PhySize_Aligned = 0;
213*f6dc9357SAndroid Build Coastguard Worker
214*f6dc9357SAndroid Build Coastguard Worker Fat.Free();
215*f6dc9357SAndroid Build Coastguard Worker MiniSids.Free();
216*f6dc9357SAndroid Build Coastguard Worker Mat.Free();
217*f6dc9357SAndroid Build Coastguard Worker Items.Clear();
218*f6dc9357SAndroid Build Coastguard Worker Refs.Clear();
219*f6dc9357SAndroid Build Coastguard Worker }
220*f6dc9357SAndroid Build Coastguard Worker
221*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kNoDid = 0xFFFFFFFF;
222*f6dc9357SAndroid Build Coastguard Worker
AddNode(int parent,UInt32 did)223*f6dc9357SAndroid Build Coastguard Worker HRESULT CDatabase::AddNode(int parent, UInt32 did)
224*f6dc9357SAndroid Build Coastguard Worker {
225*f6dc9357SAndroid Build Coastguard Worker if (did == kNoDid)
226*f6dc9357SAndroid Build Coastguard Worker return S_OK;
227*f6dc9357SAndroid Build Coastguard Worker if (did >= (UInt32)Items.Size())
228*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
229*f6dc9357SAndroid Build Coastguard Worker const CItem &item = Items[did];
230*f6dc9357SAndroid Build Coastguard Worker if (item.IsEmpty())
231*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
232*f6dc9357SAndroid Build Coastguard Worker CRef ref;
233*f6dc9357SAndroid Build Coastguard Worker ref.Parent = parent;
234*f6dc9357SAndroid Build Coastguard Worker ref.Did = did;
235*f6dc9357SAndroid Build Coastguard Worker const unsigned index = Refs.Add(ref);
236*f6dc9357SAndroid Build Coastguard Worker if (Refs.Size() > Items.Size())
237*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
238*f6dc9357SAndroid Build Coastguard Worker RINOK(AddNode(parent, item.LeftDid))
239*f6dc9357SAndroid Build Coastguard Worker RINOK(AddNode(parent, item.RightDid))
240*f6dc9357SAndroid Build Coastguard Worker if (item.IsDir())
241*f6dc9357SAndroid Build Coastguard Worker {
242*f6dc9357SAndroid Build Coastguard Worker RINOK(AddNode((int)index, item.SonDid))
243*f6dc9357SAndroid Build Coastguard Worker }
244*f6dc9357SAndroid Build Coastguard Worker return S_OK;
245*f6dc9357SAndroid Build Coastguard Worker }
246*f6dc9357SAndroid Build Coastguard Worker
CompoundNameToFileName(const UString & s)247*f6dc9357SAndroid Build Coastguard Worker static UString CompoundNameToFileName(const UString &s)
248*f6dc9357SAndroid Build Coastguard Worker {
249*f6dc9357SAndroid Build Coastguard Worker UString res;
250*f6dc9357SAndroid Build Coastguard Worker for (unsigned i = 0; i < s.Len(); i++)
251*f6dc9357SAndroid Build Coastguard Worker {
252*f6dc9357SAndroid Build Coastguard Worker const wchar_t c = s[i];
253*f6dc9357SAndroid Build Coastguard Worker if ((unsigned)(int)c < 0x20)
254*f6dc9357SAndroid Build Coastguard Worker {
255*f6dc9357SAndroid Build Coastguard Worker res.Add_Char('[');
256*f6dc9357SAndroid Build Coastguard Worker res.Add_UInt32((UInt32)(unsigned)(int)c);
257*f6dc9357SAndroid Build Coastguard Worker res.Add_Char(']');
258*f6dc9357SAndroid Build Coastguard Worker }
259*f6dc9357SAndroid Build Coastguard Worker else
260*f6dc9357SAndroid Build Coastguard Worker res += c;
261*f6dc9357SAndroid Build Coastguard Worker }
262*f6dc9357SAndroid Build Coastguard Worker return res;
263*f6dc9357SAndroid Build Coastguard Worker }
264*f6dc9357SAndroid Build Coastguard Worker
265*f6dc9357SAndroid Build Coastguard Worker static const char k_Msi_Chars[] =
266*f6dc9357SAndroid Build Coastguard Worker "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz._";
267*f6dc9357SAndroid Build Coastguard Worker
268*f6dc9357SAndroid Build Coastguard Worker // static const char * const k_Msi_ID = ""; // "{msi}";
269*f6dc9357SAndroid Build Coastguard Worker static const char k_Msi_SpecChar = '!';
270*f6dc9357SAndroid Build Coastguard Worker
271*f6dc9357SAndroid Build Coastguard Worker static const unsigned k_Msi_NumBits = 6;
272*f6dc9357SAndroid Build Coastguard Worker static const unsigned k_Msi_NumChars = 1 << k_Msi_NumBits;
273*f6dc9357SAndroid Build Coastguard Worker static const unsigned k_Msi_CharMask = k_Msi_NumChars - 1;
274*f6dc9357SAndroid Build Coastguard Worker static const unsigned k_Msi_StartUnicodeChar = 0x3800;
275*f6dc9357SAndroid Build Coastguard Worker static const unsigned k_Msi_UnicodeRange = k_Msi_NumChars * (k_Msi_NumChars + 1);
276*f6dc9357SAndroid Build Coastguard Worker
277*f6dc9357SAndroid Build Coastguard Worker
IsMsiName(const Byte * p)278*f6dc9357SAndroid Build Coastguard Worker static bool IsMsiName(const Byte *p)
279*f6dc9357SAndroid Build Coastguard Worker {
280*f6dc9357SAndroid Build Coastguard Worker UInt32 c = Get16(p);
281*f6dc9357SAndroid Build Coastguard Worker return
282*f6dc9357SAndroid Build Coastguard Worker c >= k_Msi_StartUnicodeChar &&
283*f6dc9357SAndroid Build Coastguard Worker c <= k_Msi_StartUnicodeChar + k_Msi_UnicodeRange;
284*f6dc9357SAndroid Build Coastguard Worker }
285*f6dc9357SAndroid Build Coastguard Worker
AreEqualNames(const Byte * rawName,const char * asciiName)286*f6dc9357SAndroid Build Coastguard Worker static bool AreEqualNames(const Byte *rawName, const char *asciiName)
287*f6dc9357SAndroid Build Coastguard Worker {
288*f6dc9357SAndroid Build Coastguard Worker for (unsigned i = 0; i < kNameSizeMax / 2; i++)
289*f6dc9357SAndroid Build Coastguard Worker {
290*f6dc9357SAndroid Build Coastguard Worker wchar_t c = Get16(rawName + i * 2);
291*f6dc9357SAndroid Build Coastguard Worker wchar_t c2 = (Byte)asciiName[i];
292*f6dc9357SAndroid Build Coastguard Worker if (c != c2)
293*f6dc9357SAndroid Build Coastguard Worker return false;
294*f6dc9357SAndroid Build Coastguard Worker if (c == 0)
295*f6dc9357SAndroid Build Coastguard Worker return true;
296*f6dc9357SAndroid Build Coastguard Worker }
297*f6dc9357SAndroid Build Coastguard Worker return false;
298*f6dc9357SAndroid Build Coastguard Worker }
299*f6dc9357SAndroid Build Coastguard Worker
CompoundMsiNameToFileName(const UString & name,UString & res)300*f6dc9357SAndroid Build Coastguard Worker static bool CompoundMsiNameToFileName(const UString &name, UString &res)
301*f6dc9357SAndroid Build Coastguard Worker {
302*f6dc9357SAndroid Build Coastguard Worker res.Empty();
303*f6dc9357SAndroid Build Coastguard Worker for (unsigned i = 0; i < name.Len(); i++)
304*f6dc9357SAndroid Build Coastguard Worker {
305*f6dc9357SAndroid Build Coastguard Worker wchar_t c = name[i];
306*f6dc9357SAndroid Build Coastguard Worker if (c < (wchar_t)k_Msi_StartUnicodeChar || c > (wchar_t)(k_Msi_StartUnicodeChar + k_Msi_UnicodeRange))
307*f6dc9357SAndroid Build Coastguard Worker return false;
308*f6dc9357SAndroid Build Coastguard Worker /*
309*f6dc9357SAndroid Build Coastguard Worker if (i == 0)
310*f6dc9357SAndroid Build Coastguard Worker res += k_Msi_ID;
311*f6dc9357SAndroid Build Coastguard Worker */
312*f6dc9357SAndroid Build Coastguard Worker c -= (wchar_t)k_Msi_StartUnicodeChar;
313*f6dc9357SAndroid Build Coastguard Worker
314*f6dc9357SAndroid Build Coastguard Worker const unsigned c0 = (unsigned)c & k_Msi_CharMask;
315*f6dc9357SAndroid Build Coastguard Worker const unsigned c1 = (unsigned)c >> k_Msi_NumBits;
316*f6dc9357SAndroid Build Coastguard Worker
317*f6dc9357SAndroid Build Coastguard Worker if (c1 <= k_Msi_NumChars)
318*f6dc9357SAndroid Build Coastguard Worker {
319*f6dc9357SAndroid Build Coastguard Worker res.Add_Char(k_Msi_Chars[c0]);
320*f6dc9357SAndroid Build Coastguard Worker if (c1 == k_Msi_NumChars)
321*f6dc9357SAndroid Build Coastguard Worker break;
322*f6dc9357SAndroid Build Coastguard Worker res.Add_Char(k_Msi_Chars[c1]);
323*f6dc9357SAndroid Build Coastguard Worker }
324*f6dc9357SAndroid Build Coastguard Worker else
325*f6dc9357SAndroid Build Coastguard Worker res.Add_Char(k_Msi_SpecChar);
326*f6dc9357SAndroid Build Coastguard Worker }
327*f6dc9357SAndroid Build Coastguard Worker return true;
328*f6dc9357SAndroid Build Coastguard Worker }
329*f6dc9357SAndroid Build Coastguard Worker
ConvertName(const Byte * p,bool & isMsi)330*f6dc9357SAndroid Build Coastguard Worker static UString ConvertName(const Byte *p, bool &isMsi)
331*f6dc9357SAndroid Build Coastguard Worker {
332*f6dc9357SAndroid Build Coastguard Worker isMsi = false;
333*f6dc9357SAndroid Build Coastguard Worker UString s;
334*f6dc9357SAndroid Build Coastguard Worker
335*f6dc9357SAndroid Build Coastguard Worker for (unsigned i = 0; i < kNameSizeMax; i += 2)
336*f6dc9357SAndroid Build Coastguard Worker {
337*f6dc9357SAndroid Build Coastguard Worker wchar_t c = Get16(p + i);
338*f6dc9357SAndroid Build Coastguard Worker if (c == 0)
339*f6dc9357SAndroid Build Coastguard Worker break;
340*f6dc9357SAndroid Build Coastguard Worker s += c;
341*f6dc9357SAndroid Build Coastguard Worker }
342*f6dc9357SAndroid Build Coastguard Worker
343*f6dc9357SAndroid Build Coastguard Worker UString msiName;
344*f6dc9357SAndroid Build Coastguard Worker if (CompoundMsiNameToFileName(s, msiName))
345*f6dc9357SAndroid Build Coastguard Worker {
346*f6dc9357SAndroid Build Coastguard Worker isMsi = true;
347*f6dc9357SAndroid Build Coastguard Worker return msiName;
348*f6dc9357SAndroid Build Coastguard Worker }
349*f6dc9357SAndroid Build Coastguard Worker return CompoundNameToFileName(s);
350*f6dc9357SAndroid Build Coastguard Worker }
351*f6dc9357SAndroid Build Coastguard Worker
ConvertName(const Byte * p)352*f6dc9357SAndroid Build Coastguard Worker static UString ConvertName(const Byte *p)
353*f6dc9357SAndroid Build Coastguard Worker {
354*f6dc9357SAndroid Build Coastguard Worker bool isMsi;
355*f6dc9357SAndroid Build Coastguard Worker return ConvertName(p, isMsi);
356*f6dc9357SAndroid Build Coastguard Worker }
357*f6dc9357SAndroid Build Coastguard Worker
GetItemPath(UInt32 index) const358*f6dc9357SAndroid Build Coastguard Worker UString CDatabase::GetItemPath(UInt32 index) const
359*f6dc9357SAndroid Build Coastguard Worker {
360*f6dc9357SAndroid Build Coastguard Worker UString s;
361*f6dc9357SAndroid Build Coastguard Worker while (index != kNoDid)
362*f6dc9357SAndroid Build Coastguard Worker {
363*f6dc9357SAndroid Build Coastguard Worker const CRef &ref = Refs[index];
364*f6dc9357SAndroid Build Coastguard Worker const CItem &item = Items[ref.Did];
365*f6dc9357SAndroid Build Coastguard Worker if (!s.IsEmpty())
366*f6dc9357SAndroid Build Coastguard Worker s.InsertAtFront(WCHAR_PATH_SEPARATOR);
367*f6dc9357SAndroid Build Coastguard Worker s.Insert(0, ConvertName(item.Name));
368*f6dc9357SAndroid Build Coastguard Worker index = (unsigned)ref.Parent;
369*f6dc9357SAndroid Build Coastguard Worker }
370*f6dc9357SAndroid Build Coastguard Worker return s;
371*f6dc9357SAndroid Build Coastguard Worker }
372*f6dc9357SAndroid Build Coastguard Worker
Update_PhySize_WithItem(unsigned index)373*f6dc9357SAndroid Build Coastguard Worker HRESULT CDatabase::Update_PhySize_WithItem(unsigned index)
374*f6dc9357SAndroid Build Coastguard Worker {
375*f6dc9357SAndroid Build Coastguard Worker const CItem &item = Items[index];
376*f6dc9357SAndroid Build Coastguard Worker bool isLargeStream = (index == 0 || IsLargeStream(item.Size));
377*f6dc9357SAndroid Build Coastguard Worker if (!isLargeStream)
378*f6dc9357SAndroid Build Coastguard Worker return S_OK;
379*f6dc9357SAndroid Build Coastguard Worker const unsigned bsLog = isLargeStream ? SectorSizeBits : MiniSectorSizeBits;
380*f6dc9357SAndroid Build Coastguard Worker // streamSpec->Size = item.Size;
381*f6dc9357SAndroid Build Coastguard Worker
382*f6dc9357SAndroid Build Coastguard Worker const UInt32 clusterSize = (UInt32)1 << bsLog;
383*f6dc9357SAndroid Build Coastguard Worker const UInt64 numClusters64 = (item.Size + clusterSize - 1) >> bsLog;
384*f6dc9357SAndroid Build Coastguard Worker if (numClusters64 >= ((UInt32)1 << 31))
385*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
386*f6dc9357SAndroid Build Coastguard Worker UInt32 sid = item.Sid;
387*f6dc9357SAndroid Build Coastguard Worker UInt64 size = item.Size;
388*f6dc9357SAndroid Build Coastguard Worker
389*f6dc9357SAndroid Build Coastguard Worker if (size != 0)
390*f6dc9357SAndroid Build Coastguard Worker {
391*f6dc9357SAndroid Build Coastguard Worker for (;; size -= clusterSize)
392*f6dc9357SAndroid Build Coastguard Worker {
393*f6dc9357SAndroid Build Coastguard Worker // if (isLargeStream)
394*f6dc9357SAndroid Build Coastguard Worker {
395*f6dc9357SAndroid Build Coastguard Worker if (sid >= FatSize)
396*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
397*f6dc9357SAndroid Build Coastguard Worker UInt64 end = ((UInt64)sid + 1) << bsLog;
398*f6dc9357SAndroid Build Coastguard Worker const UInt64 end_Aligned = end + clusterSize;
399*f6dc9357SAndroid Build Coastguard Worker if (size < clusterSize)
400*f6dc9357SAndroid Build Coastguard Worker end += size;
401*f6dc9357SAndroid Build Coastguard Worker else
402*f6dc9357SAndroid Build Coastguard Worker end = end_Aligned;
403*f6dc9357SAndroid Build Coastguard Worker UpdatePhySize(end, end_Aligned);
404*f6dc9357SAndroid Build Coastguard Worker sid = Fat[sid];
405*f6dc9357SAndroid Build Coastguard Worker }
406*f6dc9357SAndroid Build Coastguard Worker if (size <= clusterSize)
407*f6dc9357SAndroid Build Coastguard Worker break;
408*f6dc9357SAndroid Build Coastguard Worker }
409*f6dc9357SAndroid Build Coastguard Worker }
410*f6dc9357SAndroid Build Coastguard Worker if (sid != NFatID::kEndOfChain)
411*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
412*f6dc9357SAndroid Build Coastguard Worker return S_OK;
413*f6dc9357SAndroid Build Coastguard Worker }
414*f6dc9357SAndroid Build Coastguard Worker
415*f6dc9357SAndroid Build Coastguard Worker // There is name "[!]MsiPatchSequence" in msp files
416*f6dc9357SAndroid Build Coastguard Worker static const unsigned kMspSequence_Size = 18;
417*f6dc9357SAndroid Build Coastguard Worker static const Byte kMspSequence[kMspSequence_Size] =
418*f6dc9357SAndroid Build Coastguard Worker { 0x40, 0x48, 0x96, 0x45, 0x6C, 0x3E, 0xE4, 0x45,
419*f6dc9357SAndroid Build Coastguard Worker 0xE6, 0x42, 0x16, 0x42, 0x37, 0x41, 0x27, 0x41,
420*f6dc9357SAndroid Build Coastguard Worker 0x37, 0x41 };
421*f6dc9357SAndroid Build Coastguard Worker
Open(IInStream * inStream)422*f6dc9357SAndroid Build Coastguard Worker HRESULT CDatabase::Open(IInStream *inStream)
423*f6dc9357SAndroid Build Coastguard Worker {
424*f6dc9357SAndroid Build Coastguard Worker MainSubfile = -1;
425*f6dc9357SAndroid Build Coastguard Worker Type = k_Type_Common;
426*f6dc9357SAndroid Build Coastguard Worker const UInt32 kHeaderSize = 512;
427*f6dc9357SAndroid Build Coastguard Worker Byte p[kHeaderSize];
428*f6dc9357SAndroid Build Coastguard Worker PhySize = kHeaderSize;
429*f6dc9357SAndroid Build Coastguard Worker RINOK(ReadStream_FALSE(inStream, p, kHeaderSize))
430*f6dc9357SAndroid Build Coastguard Worker if (memcmp(p, kSignature, Z7_ARRAY_SIZE(kSignature)) != 0)
431*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
432*f6dc9357SAndroid Build Coastguard Worker if (Get16(p + 0x1A) > 4) // majorVer
433*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
434*f6dc9357SAndroid Build Coastguard Worker if (Get16(p + 0x1C) != 0xFFFE) // Little-endian
435*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
436*f6dc9357SAndroid Build Coastguard Worker unsigned sectorSizeBits = Get16(p + 0x1E);
437*f6dc9357SAndroid Build Coastguard Worker bool mode64bit = (sectorSizeBits >= 12);
438*f6dc9357SAndroid Build Coastguard Worker unsigned miniSectorSizeBits = Get16(p + 0x20);
439*f6dc9357SAndroid Build Coastguard Worker SectorSizeBits = sectorSizeBits;
440*f6dc9357SAndroid Build Coastguard Worker MiniSectorSizeBits = miniSectorSizeBits;
441*f6dc9357SAndroid Build Coastguard Worker
442*f6dc9357SAndroid Build Coastguard Worker if (sectorSizeBits > 24 ||
443*f6dc9357SAndroid Build Coastguard Worker sectorSizeBits < 7 ||
444*f6dc9357SAndroid Build Coastguard Worker miniSectorSizeBits > 24 ||
445*f6dc9357SAndroid Build Coastguard Worker miniSectorSizeBits < 2 ||
446*f6dc9357SAndroid Build Coastguard Worker miniSectorSizeBits > sectorSizeBits)
447*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
448*f6dc9357SAndroid Build Coastguard Worker UInt32 numSectorsForFAT = Get32(p + 0x2C); // SAT
449*f6dc9357SAndroid Build Coastguard Worker LongStreamMinSize = Get32(p + 0x38);
450*f6dc9357SAndroid Build Coastguard Worker
451*f6dc9357SAndroid Build Coastguard Worker UInt32 sectSize = (UInt32)1 << sectorSizeBits;
452*f6dc9357SAndroid Build Coastguard Worker
453*f6dc9357SAndroid Build Coastguard Worker CByteBuffer sect(sectSize);
454*f6dc9357SAndroid Build Coastguard Worker
455*f6dc9357SAndroid Build Coastguard Worker unsigned ssb2 = sectorSizeBits - 2;
456*f6dc9357SAndroid Build Coastguard Worker UInt32 numSidsInSec = (UInt32)1 << ssb2;
457*f6dc9357SAndroid Build Coastguard Worker UInt32 numFatItems = numSectorsForFAT << ssb2;
458*f6dc9357SAndroid Build Coastguard Worker if ((numFatItems >> ssb2) != numSectorsForFAT)
459*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
460*f6dc9357SAndroid Build Coastguard Worker FatSize = numFatItems;
461*f6dc9357SAndroid Build Coastguard Worker
462*f6dc9357SAndroid Build Coastguard Worker {
463*f6dc9357SAndroid Build Coastguard Worker UInt32 numSectorsForBat = Get32(p + 0x48); // master sector allocation table
464*f6dc9357SAndroid Build Coastguard Worker const UInt32 kNumHeaderBatItems = 109;
465*f6dc9357SAndroid Build Coastguard Worker UInt32 numBatItems = kNumHeaderBatItems + (numSectorsForBat << ssb2);
466*f6dc9357SAndroid Build Coastguard Worker if (numBatItems < kNumHeaderBatItems || ((numBatItems - kNumHeaderBatItems) >> ssb2) != numSectorsForBat)
467*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
468*f6dc9357SAndroid Build Coastguard Worker CObjArray<UInt32> bat(numBatItems);
469*f6dc9357SAndroid Build Coastguard Worker UInt32 i;
470*f6dc9357SAndroid Build Coastguard Worker for (i = 0; i < kNumHeaderBatItems; i++)
471*f6dc9357SAndroid Build Coastguard Worker bat[i] = Get32(p + 0x4c + i * 4);
472*f6dc9357SAndroid Build Coastguard Worker UInt32 sid = Get32(p + 0x44);
473*f6dc9357SAndroid Build Coastguard Worker for (UInt32 s = 0; s < numSectorsForBat; s++)
474*f6dc9357SAndroid Build Coastguard Worker {
475*f6dc9357SAndroid Build Coastguard Worker RINOK(ReadIDs(inStream, sect, sectorSizeBits, sid, bat + i))
476*f6dc9357SAndroid Build Coastguard Worker i += numSidsInSec - 1;
477*f6dc9357SAndroid Build Coastguard Worker sid = bat[i];
478*f6dc9357SAndroid Build Coastguard Worker }
479*f6dc9357SAndroid Build Coastguard Worker numBatItems = i;
480*f6dc9357SAndroid Build Coastguard Worker
481*f6dc9357SAndroid Build Coastguard Worker Fat.Alloc(numFatItems);
482*f6dc9357SAndroid Build Coastguard Worker UInt32 j = 0;
483*f6dc9357SAndroid Build Coastguard Worker
484*f6dc9357SAndroid Build Coastguard Worker for (i = 0; i < numFatItems; j++, i += numSidsInSec)
485*f6dc9357SAndroid Build Coastguard Worker {
486*f6dc9357SAndroid Build Coastguard Worker if (j >= numBatItems)
487*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
488*f6dc9357SAndroid Build Coastguard Worker RINOK(ReadIDs(inStream, sect, sectorSizeBits, bat[j], Fat + i))
489*f6dc9357SAndroid Build Coastguard Worker }
490*f6dc9357SAndroid Build Coastguard Worker FatSize = numFatItems = i;
491*f6dc9357SAndroid Build Coastguard Worker }
492*f6dc9357SAndroid Build Coastguard Worker
493*f6dc9357SAndroid Build Coastguard Worker UInt32 numMatItems;
494*f6dc9357SAndroid Build Coastguard Worker {
495*f6dc9357SAndroid Build Coastguard Worker UInt32 numSectorsForMat = Get32(p + 0x40);
496*f6dc9357SAndroid Build Coastguard Worker numMatItems = (UInt32)numSectorsForMat << ssb2;
497*f6dc9357SAndroid Build Coastguard Worker if ((numMatItems >> ssb2) != numSectorsForMat)
498*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
499*f6dc9357SAndroid Build Coastguard Worker Mat.Alloc(numMatItems);
500*f6dc9357SAndroid Build Coastguard Worker UInt32 i;
501*f6dc9357SAndroid Build Coastguard Worker UInt32 sid = Get32(p + 0x3C); // short-sector table SID
502*f6dc9357SAndroid Build Coastguard Worker for (i = 0; i < numMatItems; i += numSidsInSec)
503*f6dc9357SAndroid Build Coastguard Worker {
504*f6dc9357SAndroid Build Coastguard Worker RINOK(ReadIDs(inStream, sect, sectorSizeBits, sid, Mat + i))
505*f6dc9357SAndroid Build Coastguard Worker if (sid >= numFatItems)
506*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
507*f6dc9357SAndroid Build Coastguard Worker sid = Fat[sid];
508*f6dc9357SAndroid Build Coastguard Worker }
509*f6dc9357SAndroid Build Coastguard Worker if (sid != NFatID::kEndOfChain)
510*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
511*f6dc9357SAndroid Build Coastguard Worker }
512*f6dc9357SAndroid Build Coastguard Worker
513*f6dc9357SAndroid Build Coastguard Worker {
514*f6dc9357SAndroid Build Coastguard Worker CByteBuffer used(numFatItems);
515*f6dc9357SAndroid Build Coastguard Worker for (UInt32 i = 0; i < numFatItems; i++)
516*f6dc9357SAndroid Build Coastguard Worker used[i] = 0;
517*f6dc9357SAndroid Build Coastguard Worker UInt32 sid = Get32(p + 0x30); // directory stream SID
518*f6dc9357SAndroid Build Coastguard Worker for (;;)
519*f6dc9357SAndroid Build Coastguard Worker {
520*f6dc9357SAndroid Build Coastguard Worker if (sid >= numFatItems)
521*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
522*f6dc9357SAndroid Build Coastguard Worker if (used[sid])
523*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
524*f6dc9357SAndroid Build Coastguard Worker used[sid] = 1;
525*f6dc9357SAndroid Build Coastguard Worker RINOK(ReadSector(inStream, sect, sectorSizeBits, sid))
526*f6dc9357SAndroid Build Coastguard Worker for (UInt32 i = 0; i < sectSize; i += 128)
527*f6dc9357SAndroid Build Coastguard Worker {
528*f6dc9357SAndroid Build Coastguard Worker CItem item;
529*f6dc9357SAndroid Build Coastguard Worker item.Parse(sect + i, mode64bit);
530*f6dc9357SAndroid Build Coastguard Worker Items.Add(item);
531*f6dc9357SAndroid Build Coastguard Worker }
532*f6dc9357SAndroid Build Coastguard Worker sid = Fat[sid];
533*f6dc9357SAndroid Build Coastguard Worker if (sid == NFatID::kEndOfChain)
534*f6dc9357SAndroid Build Coastguard Worker break;
535*f6dc9357SAndroid Build Coastguard Worker }
536*f6dc9357SAndroid Build Coastguard Worker }
537*f6dc9357SAndroid Build Coastguard Worker
538*f6dc9357SAndroid Build Coastguard Worker const CItem &root = Items[0];
539*f6dc9357SAndroid Build Coastguard Worker
540*f6dc9357SAndroid Build Coastguard Worker {
541*f6dc9357SAndroid Build Coastguard Worker UInt32 numSectorsInMiniStream;
542*f6dc9357SAndroid Build Coastguard Worker {
543*f6dc9357SAndroid Build Coastguard Worker UInt64 numSatSects64 = (root.Size + sectSize - 1) >> sectorSizeBits;
544*f6dc9357SAndroid Build Coastguard Worker if (numSatSects64 > NFatID::kMaxValue)
545*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
546*f6dc9357SAndroid Build Coastguard Worker numSectorsInMiniStream = (UInt32)numSatSects64;
547*f6dc9357SAndroid Build Coastguard Worker }
548*f6dc9357SAndroid Build Coastguard Worker NumSectorsInMiniStream = numSectorsInMiniStream;
549*f6dc9357SAndroid Build Coastguard Worker MiniSids.Alloc(numSectorsInMiniStream);
550*f6dc9357SAndroid Build Coastguard Worker {
551*f6dc9357SAndroid Build Coastguard Worker UInt64 matSize64 = (root.Size + ((UInt64)1 << miniSectorSizeBits) - 1) >> miniSectorSizeBits;
552*f6dc9357SAndroid Build Coastguard Worker if (matSize64 > NFatID::kMaxValue)
553*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
554*f6dc9357SAndroid Build Coastguard Worker MatSize = (UInt32)matSize64;
555*f6dc9357SAndroid Build Coastguard Worker if (numMatItems < MatSize)
556*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
557*f6dc9357SAndroid Build Coastguard Worker }
558*f6dc9357SAndroid Build Coastguard Worker
559*f6dc9357SAndroid Build Coastguard Worker UInt32 sid = root.Sid;
560*f6dc9357SAndroid Build Coastguard Worker for (UInt32 i = 0; ; i++)
561*f6dc9357SAndroid Build Coastguard Worker {
562*f6dc9357SAndroid Build Coastguard Worker if (sid == NFatID::kEndOfChain)
563*f6dc9357SAndroid Build Coastguard Worker {
564*f6dc9357SAndroid Build Coastguard Worker if (i != numSectorsInMiniStream)
565*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
566*f6dc9357SAndroid Build Coastguard Worker break;
567*f6dc9357SAndroid Build Coastguard Worker }
568*f6dc9357SAndroid Build Coastguard Worker if (i >= numSectorsInMiniStream)
569*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
570*f6dc9357SAndroid Build Coastguard Worker MiniSids[i] = sid;
571*f6dc9357SAndroid Build Coastguard Worker if (sid >= numFatItems)
572*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
573*f6dc9357SAndroid Build Coastguard Worker sid = Fat[sid];
574*f6dc9357SAndroid Build Coastguard Worker }
575*f6dc9357SAndroid Build Coastguard Worker }
576*f6dc9357SAndroid Build Coastguard Worker
577*f6dc9357SAndroid Build Coastguard Worker RINOK(AddNode(-1, root.SonDid))
578*f6dc9357SAndroid Build Coastguard Worker
579*f6dc9357SAndroid Build Coastguard Worker unsigned numCabs = 0;
580*f6dc9357SAndroid Build Coastguard Worker
581*f6dc9357SAndroid Build Coastguard Worker FOR_VECTOR (i, Refs)
582*f6dc9357SAndroid Build Coastguard Worker {
583*f6dc9357SAndroid Build Coastguard Worker const CItem &item = Items[Refs[i].Did];
584*f6dc9357SAndroid Build Coastguard Worker if (item.IsDir() || numCabs > 1)
585*f6dc9357SAndroid Build Coastguard Worker continue;
586*f6dc9357SAndroid Build Coastguard Worker bool isMsiName;
587*f6dc9357SAndroid Build Coastguard Worker const UString msiName = ConvertName(item.Name, isMsiName);
588*f6dc9357SAndroid Build Coastguard Worker if (isMsiName && !msiName.IsEmpty())
589*f6dc9357SAndroid Build Coastguard Worker {
590*f6dc9357SAndroid Build Coastguard Worker // bool isThereExt = (msiName.Find(L'.') >= 0);
591*f6dc9357SAndroid Build Coastguard Worker bool isMsiSpec = (msiName[0] == k_Msi_SpecChar);
592*f6dc9357SAndroid Build Coastguard Worker if ((msiName.Len() >= 4 && StringsAreEqualNoCase_Ascii(msiName.RightPtr(4), ".cab"))
593*f6dc9357SAndroid Build Coastguard Worker || (!isMsiSpec && msiName.Len() >= 3 && StringsAreEqualNoCase_Ascii(msiName.RightPtr(3), "exe"))
594*f6dc9357SAndroid Build Coastguard Worker // || (!isMsiSpec && !isThereExt)
595*f6dc9357SAndroid Build Coastguard Worker )
596*f6dc9357SAndroid Build Coastguard Worker {
597*f6dc9357SAndroid Build Coastguard Worker numCabs++;
598*f6dc9357SAndroid Build Coastguard Worker MainSubfile = (int)i;
599*f6dc9357SAndroid Build Coastguard Worker }
600*f6dc9357SAndroid Build Coastguard Worker }
601*f6dc9357SAndroid Build Coastguard Worker }
602*f6dc9357SAndroid Build Coastguard Worker
603*f6dc9357SAndroid Build Coastguard Worker if (numCabs > 1)
604*f6dc9357SAndroid Build Coastguard Worker MainSubfile = -1;
605*f6dc9357SAndroid Build Coastguard Worker
606*f6dc9357SAndroid Build Coastguard Worker {
607*f6dc9357SAndroid Build Coastguard Worker FOR_VECTOR (t, Items)
608*f6dc9357SAndroid Build Coastguard Worker {
609*f6dc9357SAndroid Build Coastguard Worker Update_PhySize_WithItem(t);
610*f6dc9357SAndroid Build Coastguard Worker }
611*f6dc9357SAndroid Build Coastguard Worker }
612*f6dc9357SAndroid Build Coastguard Worker {
613*f6dc9357SAndroid Build Coastguard Worker if (PhySize != PhySize_Aligned)
614*f6dc9357SAndroid Build Coastguard Worker {
615*f6dc9357SAndroid Build Coastguard Worker /* some msi (in rare cases) have unaligned size of archive,
616*f6dc9357SAndroid Build Coastguard Worker where there is no padding data after payload data in last cluster of archive */
617*f6dc9357SAndroid Build Coastguard Worker UInt64 fileSize;
618*f6dc9357SAndroid Build Coastguard Worker RINOK(InStream_GetSize_SeekToEnd(inStream, fileSize))
619*f6dc9357SAndroid Build Coastguard Worker if (PhySize != fileSize)
620*f6dc9357SAndroid Build Coastguard Worker PhySize = PhySize_Aligned;
621*f6dc9357SAndroid Build Coastguard Worker }
622*f6dc9357SAndroid Build Coastguard Worker }
623*f6dc9357SAndroid Build Coastguard Worker {
624*f6dc9357SAndroid Build Coastguard Worker FOR_VECTOR (t, Items)
625*f6dc9357SAndroid Build Coastguard Worker {
626*f6dc9357SAndroid Build Coastguard Worker const CItem &item = Items[t];
627*f6dc9357SAndroid Build Coastguard Worker
628*f6dc9357SAndroid Build Coastguard Worker if (IsMsiName(item.Name))
629*f6dc9357SAndroid Build Coastguard Worker {
630*f6dc9357SAndroid Build Coastguard Worker Type = k_Type_Msi;
631*f6dc9357SAndroid Build Coastguard Worker if (memcmp(item.Name, kMspSequence, kMspSequence_Size) == 0)
632*f6dc9357SAndroid Build Coastguard Worker {
633*f6dc9357SAndroid Build Coastguard Worker Type = k_Type_Msp;
634*f6dc9357SAndroid Build Coastguard Worker break;
635*f6dc9357SAndroid Build Coastguard Worker }
636*f6dc9357SAndroid Build Coastguard Worker continue;
637*f6dc9357SAndroid Build Coastguard Worker }
638*f6dc9357SAndroid Build Coastguard Worker if (AreEqualNames(item.Name, "WordDocument"))
639*f6dc9357SAndroid Build Coastguard Worker {
640*f6dc9357SAndroid Build Coastguard Worker Type = k_Type_Doc;
641*f6dc9357SAndroid Build Coastguard Worker break;
642*f6dc9357SAndroid Build Coastguard Worker }
643*f6dc9357SAndroid Build Coastguard Worker if (AreEqualNames(item.Name, "PowerPoint Document"))
644*f6dc9357SAndroid Build Coastguard Worker {
645*f6dc9357SAndroid Build Coastguard Worker Type = k_Type_Ppt;
646*f6dc9357SAndroid Build Coastguard Worker break;
647*f6dc9357SAndroid Build Coastguard Worker }
648*f6dc9357SAndroid Build Coastguard Worker if (AreEqualNames(item.Name, "Workbook"))
649*f6dc9357SAndroid Build Coastguard Worker {
650*f6dc9357SAndroid Build Coastguard Worker Type = k_Type_Xls;
651*f6dc9357SAndroid Build Coastguard Worker break;
652*f6dc9357SAndroid Build Coastguard Worker }
653*f6dc9357SAndroid Build Coastguard Worker }
654*f6dc9357SAndroid Build Coastguard Worker }
655*f6dc9357SAndroid Build Coastguard Worker
656*f6dc9357SAndroid Build Coastguard Worker return S_OK;
657*f6dc9357SAndroid Build Coastguard Worker }
658*f6dc9357SAndroid Build Coastguard Worker
659*f6dc9357SAndroid Build Coastguard Worker Z7_CLASS_IMP_CHandler_IInArchive_1(
660*f6dc9357SAndroid Build Coastguard Worker IInArchiveGetStream
661*f6dc9357SAndroid Build Coastguard Worker )
662*f6dc9357SAndroid Build Coastguard Worker CMyComPtr<IInStream> _stream;
663*f6dc9357SAndroid Build Coastguard Worker CDatabase _db;
664*f6dc9357SAndroid Build Coastguard Worker };
665*f6dc9357SAndroid Build Coastguard Worker
666*f6dc9357SAndroid Build Coastguard Worker static const Byte kProps[] =
667*f6dc9357SAndroid Build Coastguard Worker {
668*f6dc9357SAndroid Build Coastguard Worker kpidPath,
669*f6dc9357SAndroid Build Coastguard Worker kpidSize,
670*f6dc9357SAndroid Build Coastguard Worker kpidPackSize,
671*f6dc9357SAndroid Build Coastguard Worker kpidCTime,
672*f6dc9357SAndroid Build Coastguard Worker kpidMTime
673*f6dc9357SAndroid Build Coastguard Worker };
674*f6dc9357SAndroid Build Coastguard Worker
675*f6dc9357SAndroid Build Coastguard Worker static const Byte kArcProps[] =
676*f6dc9357SAndroid Build Coastguard Worker {
677*f6dc9357SAndroid Build Coastguard Worker kpidExtension,
678*f6dc9357SAndroid Build Coastguard Worker kpidClusterSize,
679*f6dc9357SAndroid Build Coastguard Worker kpidSectorSize
680*f6dc9357SAndroid Build Coastguard Worker };
681*f6dc9357SAndroid Build Coastguard Worker
682*f6dc9357SAndroid Build Coastguard Worker IMP_IInArchive_Props
683*f6dc9357SAndroid Build Coastguard Worker IMP_IInArchive_ArcProps
684*f6dc9357SAndroid Build Coastguard Worker
Z7_COM7F_IMF(CHandler::GetArchiveProperty (PROPID propID,PROPVARIANT * value))685*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
686*f6dc9357SAndroid Build Coastguard Worker {
687*f6dc9357SAndroid Build Coastguard Worker COM_TRY_BEGIN
688*f6dc9357SAndroid Build Coastguard Worker NWindows::NCOM::CPropVariant prop;
689*f6dc9357SAndroid Build Coastguard Worker switch (propID)
690*f6dc9357SAndroid Build Coastguard Worker {
691*f6dc9357SAndroid Build Coastguard Worker case kpidExtension: prop = kExtensions[(unsigned)_db.Type]; break;
692*f6dc9357SAndroid Build Coastguard Worker case kpidPhySize: prop = _db.PhySize; break;
693*f6dc9357SAndroid Build Coastguard Worker case kpidClusterSize: prop = (UInt32)1 << _db.SectorSizeBits; break;
694*f6dc9357SAndroid Build Coastguard Worker case kpidSectorSize: prop = (UInt32)1 << _db.MiniSectorSizeBits; break;
695*f6dc9357SAndroid Build Coastguard Worker case kpidMainSubfile: if (_db.MainSubfile >= 0) prop = (UInt32)_db.MainSubfile; break;
696*f6dc9357SAndroid Build Coastguard Worker case kpidIsNotArcType: if (_db.IsNotArcType()) prop = true; break;
697*f6dc9357SAndroid Build Coastguard Worker }
698*f6dc9357SAndroid Build Coastguard Worker prop.Detach(value);
699*f6dc9357SAndroid Build Coastguard Worker return S_OK;
700*f6dc9357SAndroid Build Coastguard Worker COM_TRY_END
701*f6dc9357SAndroid Build Coastguard Worker }
702*f6dc9357SAndroid Build Coastguard Worker
Z7_COM7F_IMF(CHandler::GetProperty (UInt32 index,PROPID propID,PROPVARIANT * value))703*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
704*f6dc9357SAndroid Build Coastguard Worker {
705*f6dc9357SAndroid Build Coastguard Worker COM_TRY_BEGIN
706*f6dc9357SAndroid Build Coastguard Worker NWindows::NCOM::CPropVariant prop;
707*f6dc9357SAndroid Build Coastguard Worker const CRef &ref = _db.Refs[index];
708*f6dc9357SAndroid Build Coastguard Worker const CItem &item = _db.Items[ref.Did];
709*f6dc9357SAndroid Build Coastguard Worker
710*f6dc9357SAndroid Build Coastguard Worker switch (propID)
711*f6dc9357SAndroid Build Coastguard Worker {
712*f6dc9357SAndroid Build Coastguard Worker case kpidPath: prop = _db.GetItemPath(index); break;
713*f6dc9357SAndroid Build Coastguard Worker case kpidIsDir: prop = item.IsDir(); break;
714*f6dc9357SAndroid Build Coastguard Worker case kpidCTime: prop = item.CTime; break;
715*f6dc9357SAndroid Build Coastguard Worker case kpidMTime: prop = item.MTime; break;
716*f6dc9357SAndroid Build Coastguard Worker case kpidPackSize: if (!item.IsDir()) prop = _db.GetItemPackSize(item.Size); break;
717*f6dc9357SAndroid Build Coastguard Worker case kpidSize: if (!item.IsDir()) prop = item.Size; break;
718*f6dc9357SAndroid Build Coastguard Worker }
719*f6dc9357SAndroid Build Coastguard Worker prop.Detach(value);
720*f6dc9357SAndroid Build Coastguard Worker return S_OK;
721*f6dc9357SAndroid Build Coastguard Worker COM_TRY_END
722*f6dc9357SAndroid Build Coastguard Worker }
723*f6dc9357SAndroid Build Coastguard Worker
Z7_COM7F_IMF(CHandler::Open (IInStream * inStream,const UInt64 *,IArchiveOpenCallback *))724*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Open(IInStream *inStream,
725*f6dc9357SAndroid Build Coastguard Worker const UInt64 * /* maxCheckStartPosition */,
726*f6dc9357SAndroid Build Coastguard Worker IArchiveOpenCallback * /* openArchiveCallback */))
727*f6dc9357SAndroid Build Coastguard Worker {
728*f6dc9357SAndroid Build Coastguard Worker COM_TRY_BEGIN
729*f6dc9357SAndroid Build Coastguard Worker Close();
730*f6dc9357SAndroid Build Coastguard Worker try
731*f6dc9357SAndroid Build Coastguard Worker {
732*f6dc9357SAndroid Build Coastguard Worker if (_db.Open(inStream) != S_OK)
733*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
734*f6dc9357SAndroid Build Coastguard Worker _stream = inStream;
735*f6dc9357SAndroid Build Coastguard Worker }
736*f6dc9357SAndroid Build Coastguard Worker catch(...) { return S_FALSE; }
737*f6dc9357SAndroid Build Coastguard Worker return S_OK;
738*f6dc9357SAndroid Build Coastguard Worker COM_TRY_END
739*f6dc9357SAndroid Build Coastguard Worker }
740*f6dc9357SAndroid Build Coastguard Worker
Z7_COM7F_IMF(CHandler::Close ())741*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Close())
742*f6dc9357SAndroid Build Coastguard Worker {
743*f6dc9357SAndroid Build Coastguard Worker _db.Clear();
744*f6dc9357SAndroid Build Coastguard Worker _stream.Release();
745*f6dc9357SAndroid Build Coastguard Worker return S_OK;
746*f6dc9357SAndroid Build Coastguard Worker }
747*f6dc9357SAndroid Build Coastguard Worker
Z7_COM7F_IMF(CHandler::Extract (const UInt32 * indices,UInt32 numItems,Int32 testMode,IArchiveExtractCallback * extractCallback))748*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
749*f6dc9357SAndroid Build Coastguard Worker Int32 testMode, IArchiveExtractCallback *extractCallback))
750*f6dc9357SAndroid Build Coastguard Worker {
751*f6dc9357SAndroid Build Coastguard Worker COM_TRY_BEGIN
752*f6dc9357SAndroid Build Coastguard Worker const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
753*f6dc9357SAndroid Build Coastguard Worker if (allFilesMode)
754*f6dc9357SAndroid Build Coastguard Worker numItems = _db.Refs.Size();
755*f6dc9357SAndroid Build Coastguard Worker if (numItems == 0)
756*f6dc9357SAndroid Build Coastguard Worker return S_OK;
757*f6dc9357SAndroid Build Coastguard Worker UInt32 i;
758*f6dc9357SAndroid Build Coastguard Worker UInt64 totalSize = 0;
759*f6dc9357SAndroid Build Coastguard Worker for (i = 0; i < numItems; i++)
760*f6dc9357SAndroid Build Coastguard Worker {
761*f6dc9357SAndroid Build Coastguard Worker const CItem &item = _db.Items[_db.Refs[allFilesMode ? i : indices[i]].Did];
762*f6dc9357SAndroid Build Coastguard Worker if (!item.IsDir())
763*f6dc9357SAndroid Build Coastguard Worker totalSize += item.Size;
764*f6dc9357SAndroid Build Coastguard Worker }
765*f6dc9357SAndroid Build Coastguard Worker RINOK(extractCallback->SetTotal(totalSize))
766*f6dc9357SAndroid Build Coastguard Worker
767*f6dc9357SAndroid Build Coastguard Worker UInt64 totalPackSize;
768*f6dc9357SAndroid Build Coastguard Worker totalSize = totalPackSize = 0;
769*f6dc9357SAndroid Build Coastguard Worker
770*f6dc9357SAndroid Build Coastguard Worker NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
771*f6dc9357SAndroid Build Coastguard Worker CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
772*f6dc9357SAndroid Build Coastguard Worker
773*f6dc9357SAndroid Build Coastguard Worker CLocalProgress *lps = new CLocalProgress;
774*f6dc9357SAndroid Build Coastguard Worker CMyComPtr<ICompressProgressInfo> progress = lps;
775*f6dc9357SAndroid Build Coastguard Worker lps->Init(extractCallback, false);
776*f6dc9357SAndroid Build Coastguard Worker
777*f6dc9357SAndroid Build Coastguard Worker for (i = 0; i < numItems; i++)
778*f6dc9357SAndroid Build Coastguard Worker {
779*f6dc9357SAndroid Build Coastguard Worker lps->InSize = totalPackSize;
780*f6dc9357SAndroid Build Coastguard Worker lps->OutSize = totalSize;
781*f6dc9357SAndroid Build Coastguard Worker RINOK(lps->SetCur())
782*f6dc9357SAndroid Build Coastguard Worker const UInt32 index = allFilesMode ? i : indices[i];
783*f6dc9357SAndroid Build Coastguard Worker const CItem &item = _db.Items[_db.Refs[index].Did];
784*f6dc9357SAndroid Build Coastguard Worker
785*f6dc9357SAndroid Build Coastguard Worker CMyComPtr<ISequentialOutStream> outStream;
786*f6dc9357SAndroid Build Coastguard Worker const Int32 askMode = testMode ?
787*f6dc9357SAndroid Build Coastguard Worker NExtract::NAskMode::kTest :
788*f6dc9357SAndroid Build Coastguard Worker NExtract::NAskMode::kExtract;
789*f6dc9357SAndroid Build Coastguard Worker RINOK(extractCallback->GetStream(index, &outStream, askMode))
790*f6dc9357SAndroid Build Coastguard Worker
791*f6dc9357SAndroid Build Coastguard Worker if (item.IsDir())
792*f6dc9357SAndroid Build Coastguard Worker {
793*f6dc9357SAndroid Build Coastguard Worker RINOK(extractCallback->PrepareOperation(askMode))
794*f6dc9357SAndroid Build Coastguard Worker RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
795*f6dc9357SAndroid Build Coastguard Worker continue;
796*f6dc9357SAndroid Build Coastguard Worker }
797*f6dc9357SAndroid Build Coastguard Worker
798*f6dc9357SAndroid Build Coastguard Worker totalPackSize += _db.GetItemPackSize(item.Size);
799*f6dc9357SAndroid Build Coastguard Worker totalSize += item.Size;
800*f6dc9357SAndroid Build Coastguard Worker
801*f6dc9357SAndroid Build Coastguard Worker if (!testMode && !outStream)
802*f6dc9357SAndroid Build Coastguard Worker continue;
803*f6dc9357SAndroid Build Coastguard Worker RINOK(extractCallback->PrepareOperation(askMode))
804*f6dc9357SAndroid Build Coastguard Worker Int32 res = NExtract::NOperationResult::kDataError;
805*f6dc9357SAndroid Build Coastguard Worker CMyComPtr<ISequentialInStream> inStream;
806*f6dc9357SAndroid Build Coastguard Worker HRESULT hres = GetStream(index, &inStream);
807*f6dc9357SAndroid Build Coastguard Worker if (hres == S_FALSE)
808*f6dc9357SAndroid Build Coastguard Worker res = NExtract::NOperationResult::kDataError;
809*f6dc9357SAndroid Build Coastguard Worker else if (hres == E_NOTIMPL)
810*f6dc9357SAndroid Build Coastguard Worker res = NExtract::NOperationResult::kUnsupportedMethod;
811*f6dc9357SAndroid Build Coastguard Worker else
812*f6dc9357SAndroid Build Coastguard Worker {
813*f6dc9357SAndroid Build Coastguard Worker RINOK(hres)
814*f6dc9357SAndroid Build Coastguard Worker if (inStream)
815*f6dc9357SAndroid Build Coastguard Worker {
816*f6dc9357SAndroid Build Coastguard Worker RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress))
817*f6dc9357SAndroid Build Coastguard Worker if (copyCoderSpec->TotalSize == item.Size)
818*f6dc9357SAndroid Build Coastguard Worker res = NExtract::NOperationResult::kOK;
819*f6dc9357SAndroid Build Coastguard Worker }
820*f6dc9357SAndroid Build Coastguard Worker }
821*f6dc9357SAndroid Build Coastguard Worker outStream.Release();
822*f6dc9357SAndroid Build Coastguard Worker RINOK(extractCallback->SetOperationResult(res))
823*f6dc9357SAndroid Build Coastguard Worker }
824*f6dc9357SAndroid Build Coastguard Worker return S_OK;
825*f6dc9357SAndroid Build Coastguard Worker COM_TRY_END
826*f6dc9357SAndroid Build Coastguard Worker }
827*f6dc9357SAndroid Build Coastguard Worker
Z7_COM7F_IMF(CHandler::GetNumberOfItems (UInt32 * numItems))828*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
829*f6dc9357SAndroid Build Coastguard Worker {
830*f6dc9357SAndroid Build Coastguard Worker *numItems = _db.Refs.Size();
831*f6dc9357SAndroid Build Coastguard Worker return S_OK;
832*f6dc9357SAndroid Build Coastguard Worker }
833*f6dc9357SAndroid Build Coastguard Worker
Z7_COM7F_IMF(CHandler::GetStream (UInt32 index,ISequentialInStream ** stream))834*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
835*f6dc9357SAndroid Build Coastguard Worker {
836*f6dc9357SAndroid Build Coastguard Worker COM_TRY_BEGIN
837*f6dc9357SAndroid Build Coastguard Worker *stream = NULL;
838*f6dc9357SAndroid Build Coastguard Worker const UInt32 itemIndex = _db.Refs[index].Did;
839*f6dc9357SAndroid Build Coastguard Worker const CItem &item = _db.Items[itemIndex];
840*f6dc9357SAndroid Build Coastguard Worker CClusterInStream *streamSpec = new CClusterInStream;
841*f6dc9357SAndroid Build Coastguard Worker CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
842*f6dc9357SAndroid Build Coastguard Worker streamSpec->Stream = _stream;
843*f6dc9357SAndroid Build Coastguard Worker streamSpec->StartOffset = 0;
844*f6dc9357SAndroid Build Coastguard Worker
845*f6dc9357SAndroid Build Coastguard Worker const bool isLargeStream = (itemIndex == 0 || _db.IsLargeStream(item.Size));
846*f6dc9357SAndroid Build Coastguard Worker const unsigned bsLog = isLargeStream ? _db.SectorSizeBits : _db.MiniSectorSizeBits;
847*f6dc9357SAndroid Build Coastguard Worker streamSpec->BlockSizeLog = bsLog;
848*f6dc9357SAndroid Build Coastguard Worker streamSpec->Size = item.Size;
849*f6dc9357SAndroid Build Coastguard Worker
850*f6dc9357SAndroid Build Coastguard Worker const UInt32 clusterSize = (UInt32)1 << bsLog;
851*f6dc9357SAndroid Build Coastguard Worker const UInt64 numClusters64 = (item.Size + clusterSize - 1) >> bsLog;
852*f6dc9357SAndroid Build Coastguard Worker if (numClusters64 >= ((UInt32)1 << 31))
853*f6dc9357SAndroid Build Coastguard Worker return E_NOTIMPL;
854*f6dc9357SAndroid Build Coastguard Worker streamSpec->Vector.ClearAndReserve((unsigned)numClusters64);
855*f6dc9357SAndroid Build Coastguard Worker UInt32 sid = item.Sid;
856*f6dc9357SAndroid Build Coastguard Worker UInt64 size = item.Size;
857*f6dc9357SAndroid Build Coastguard Worker
858*f6dc9357SAndroid Build Coastguard Worker if (size != 0)
859*f6dc9357SAndroid Build Coastguard Worker {
860*f6dc9357SAndroid Build Coastguard Worker for (;; size -= clusterSize)
861*f6dc9357SAndroid Build Coastguard Worker {
862*f6dc9357SAndroid Build Coastguard Worker if (isLargeStream)
863*f6dc9357SAndroid Build Coastguard Worker {
864*f6dc9357SAndroid Build Coastguard Worker if (sid >= _db.FatSize)
865*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
866*f6dc9357SAndroid Build Coastguard Worker streamSpec->Vector.AddInReserved(sid + 1);
867*f6dc9357SAndroid Build Coastguard Worker sid = _db.Fat[sid];
868*f6dc9357SAndroid Build Coastguard Worker }
869*f6dc9357SAndroid Build Coastguard Worker else
870*f6dc9357SAndroid Build Coastguard Worker {
871*f6dc9357SAndroid Build Coastguard Worker UInt64 val = 0;
872*f6dc9357SAndroid Build Coastguard Worker if (sid >= _db.MatSize || !_db.GetMiniCluster(sid, val) || val >= (UInt64)1 << 32)
873*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
874*f6dc9357SAndroid Build Coastguard Worker streamSpec->Vector.AddInReserved((UInt32)val);
875*f6dc9357SAndroid Build Coastguard Worker sid = _db.Mat[sid];
876*f6dc9357SAndroid Build Coastguard Worker }
877*f6dc9357SAndroid Build Coastguard Worker if (size <= clusterSize)
878*f6dc9357SAndroid Build Coastguard Worker break;
879*f6dc9357SAndroid Build Coastguard Worker }
880*f6dc9357SAndroid Build Coastguard Worker }
881*f6dc9357SAndroid Build Coastguard Worker if (sid != NFatID::kEndOfChain)
882*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
883*f6dc9357SAndroid Build Coastguard Worker RINOK(streamSpec->InitAndSeek())
884*f6dc9357SAndroid Build Coastguard Worker *stream = streamTemp.Detach();
885*f6dc9357SAndroid Build Coastguard Worker return S_OK;
886*f6dc9357SAndroid Build Coastguard Worker COM_TRY_END
887*f6dc9357SAndroid Build Coastguard Worker }
888*f6dc9357SAndroid Build Coastguard Worker
889*f6dc9357SAndroid Build Coastguard Worker REGISTER_ARC_I(
890*f6dc9357SAndroid Build Coastguard Worker "Compound", "msi msp doc xls ppt", NULL, 0xE5,
891*f6dc9357SAndroid Build Coastguard Worker kSignature,
892*f6dc9357SAndroid Build Coastguard Worker 0,
893*f6dc9357SAndroid Build Coastguard Worker 0,
894*f6dc9357SAndroid Build Coastguard Worker NULL)
895*f6dc9357SAndroid Build Coastguard Worker
896*f6dc9357SAndroid Build Coastguard Worker }}
897