1*f6dc9357SAndroid Build Coastguard Worker // HfsHandler.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/CpuArch.h"
6*f6dc9357SAndroid Build Coastguard Worker
7*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/ComTry.h"
8*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/MyString.h"
9*f6dc9357SAndroid Build Coastguard Worker
10*f6dc9357SAndroid Build Coastguard Worker #include "../../Windows/PropVariantUtils.h"
11*f6dc9357SAndroid Build Coastguard Worker
12*f6dc9357SAndroid Build Coastguard Worker #include "../Common/LimitedStreams.h"
13*f6dc9357SAndroid Build Coastguard Worker #include "../Common/RegisterArc.h"
14*f6dc9357SAndroid Build Coastguard Worker #include "../Common/StreamObjects.h"
15*f6dc9357SAndroid Build Coastguard Worker #include "../Common/StreamUtils.h"
16*f6dc9357SAndroid Build Coastguard Worker
17*f6dc9357SAndroid Build Coastguard Worker #include "HfsHandler.h"
18*f6dc9357SAndroid Build Coastguard Worker
19*f6dc9357SAndroid Build Coastguard Worker /* if HFS_SHOW_ALT_STREAMS is defined, the handler will show attribute files
20*f6dc9357SAndroid Build Coastguard Worker and resource forks. In most cases it looks useless. So we disable it. */
21*f6dc9357SAndroid Build Coastguard Worker
22*f6dc9357SAndroid Build Coastguard Worker #define HFS_SHOW_ALT_STREAMS
23*f6dc9357SAndroid Build Coastguard Worker
24*f6dc9357SAndroid Build Coastguard Worker #define Get16(p) GetBe16(p)
25*f6dc9357SAndroid Build Coastguard Worker #define Get32(p) GetBe32(p)
26*f6dc9357SAndroid Build Coastguard Worker #define Get64(p) GetBe64(p)
27*f6dc9357SAndroid Build Coastguard Worker
28*f6dc9357SAndroid Build Coastguard Worker #define Get16a(p) GetBe16a(p)
29*f6dc9357SAndroid Build Coastguard Worker #define Get32a(p) GetBe32a(p)
30*f6dc9357SAndroid Build Coastguard Worker
31*f6dc9357SAndroid Build Coastguard Worker namespace NArchive {
32*f6dc9357SAndroid Build Coastguard Worker namespace NHfs {
33*f6dc9357SAndroid Build Coastguard Worker
34*f6dc9357SAndroid Build Coastguard Worker static const char * const kResFileName = "rsrc"; // "com.apple.ResourceFork";
35*f6dc9357SAndroid Build Coastguard Worker
36*f6dc9357SAndroid Build Coastguard Worker struct CExtent
37*f6dc9357SAndroid Build Coastguard Worker {
38*f6dc9357SAndroid Build Coastguard Worker UInt32 Pos;
39*f6dc9357SAndroid Build Coastguard Worker UInt32 NumBlocks;
40*f6dc9357SAndroid Build Coastguard Worker };
41*f6dc9357SAndroid Build Coastguard Worker
42*f6dc9357SAndroid Build Coastguard Worker struct CIdExtents
43*f6dc9357SAndroid Build Coastguard Worker {
44*f6dc9357SAndroid Build Coastguard Worker UInt32 ID;
45*f6dc9357SAndroid Build Coastguard Worker UInt32 StartBlock;
46*f6dc9357SAndroid Build Coastguard Worker CRecordVector<CExtent> Extents;
47*f6dc9357SAndroid Build Coastguard Worker };
48*f6dc9357SAndroid Build Coastguard Worker
49*f6dc9357SAndroid Build Coastguard Worker struct CFork
50*f6dc9357SAndroid Build Coastguard Worker {
51*f6dc9357SAndroid Build Coastguard Worker UInt64 Size;
52*f6dc9357SAndroid Build Coastguard Worker UInt32 NumBlocks;
53*f6dc9357SAndroid Build Coastguard Worker // UInt32 ClumpSize;
54*f6dc9357SAndroid Build Coastguard Worker CRecordVector<CExtent> Extents;
55*f6dc9357SAndroid Build Coastguard Worker
CForkNArchive::NHfs::CFork56*f6dc9357SAndroid Build Coastguard Worker CFork(): Size(0), NumBlocks(0) {}
57*f6dc9357SAndroid Build Coastguard Worker
58*f6dc9357SAndroid Build Coastguard Worker void Parse(const Byte *p);
59*f6dc9357SAndroid Build Coastguard Worker
IsEmptyNArchive::NHfs::CFork60*f6dc9357SAndroid Build Coastguard Worker bool IsEmpty() const { return Size == 0 && NumBlocks == 0 && Extents.Size() == 0; }
61*f6dc9357SAndroid Build Coastguard Worker
62*f6dc9357SAndroid Build Coastguard Worker UInt32 Calc_NumBlocks_from_Extents() const;
63*f6dc9357SAndroid Build Coastguard Worker bool Check_NumBlocks() const;
64*f6dc9357SAndroid Build Coastguard Worker
Check_Size_with_NumBlocksNArchive::NHfs::CFork65*f6dc9357SAndroid Build Coastguard Worker bool Check_Size_with_NumBlocks(unsigned blockSizeLog) const
66*f6dc9357SAndroid Build Coastguard Worker {
67*f6dc9357SAndroid Build Coastguard Worker return Size <= ((UInt64)NumBlocks << blockSizeLog);
68*f6dc9357SAndroid Build Coastguard Worker }
69*f6dc9357SAndroid Build Coastguard Worker
IsOkNArchive::NHfs::CFork70*f6dc9357SAndroid Build Coastguard Worker bool IsOk(unsigned blockSizeLog) const
71*f6dc9357SAndroid Build Coastguard Worker {
72*f6dc9357SAndroid Build Coastguard Worker // we don't check cases with extra (empty) blocks in last extent
73*f6dc9357SAndroid Build Coastguard Worker return Check_NumBlocks() && Check_Size_with_NumBlocks(blockSizeLog);
74*f6dc9357SAndroid Build Coastguard Worker }
75*f6dc9357SAndroid Build Coastguard Worker
76*f6dc9357SAndroid Build Coastguard Worker bool Upgrade(const CObjectVector<CIdExtents> &items, UInt32 id);
UpgradeAndTestNArchive::NHfs::CFork77*f6dc9357SAndroid Build Coastguard Worker bool UpgradeAndTest(const CObjectVector<CIdExtents> &items, UInt32 id, unsigned blockSizeLog)
78*f6dc9357SAndroid Build Coastguard Worker {
79*f6dc9357SAndroid Build Coastguard Worker if (!Upgrade(items, id))
80*f6dc9357SAndroid Build Coastguard Worker return false;
81*f6dc9357SAndroid Build Coastguard Worker return IsOk(blockSizeLog);
82*f6dc9357SAndroid Build Coastguard Worker }
83*f6dc9357SAndroid Build Coastguard Worker };
84*f6dc9357SAndroid Build Coastguard Worker
85*f6dc9357SAndroid Build Coastguard Worker static const unsigned kNumFixedExtents = 8;
86*f6dc9357SAndroid Build Coastguard Worker static const unsigned kForkRecSize = 16 + kNumFixedExtents * 8;
87*f6dc9357SAndroid Build Coastguard Worker
88*f6dc9357SAndroid Build Coastguard Worker
Parse(const Byte * p)89*f6dc9357SAndroid Build Coastguard Worker void CFork::Parse(const Byte *p)
90*f6dc9357SAndroid Build Coastguard Worker {
91*f6dc9357SAndroid Build Coastguard Worker Extents.Clear();
92*f6dc9357SAndroid Build Coastguard Worker Size = Get64(p);
93*f6dc9357SAndroid Build Coastguard Worker // ClumpSize = Get32(p + 8);
94*f6dc9357SAndroid Build Coastguard Worker NumBlocks = Get32(p + 12);
95*f6dc9357SAndroid Build Coastguard Worker p += 16;
96*f6dc9357SAndroid Build Coastguard Worker for (unsigned i = 0; i < kNumFixedExtents; i++, p += 8)
97*f6dc9357SAndroid Build Coastguard Worker {
98*f6dc9357SAndroid Build Coastguard Worker CExtent e;
99*f6dc9357SAndroid Build Coastguard Worker e.Pos = Get32(p);
100*f6dc9357SAndroid Build Coastguard Worker e.NumBlocks = Get32(p + 4);
101*f6dc9357SAndroid Build Coastguard Worker if (e.NumBlocks != 0)
102*f6dc9357SAndroid Build Coastguard Worker Extents.Add(e);
103*f6dc9357SAndroid Build Coastguard Worker }
104*f6dc9357SAndroid Build Coastguard Worker }
105*f6dc9357SAndroid Build Coastguard Worker
Calc_NumBlocks_from_Extents() const106*f6dc9357SAndroid Build Coastguard Worker UInt32 CFork::Calc_NumBlocks_from_Extents() const
107*f6dc9357SAndroid Build Coastguard Worker {
108*f6dc9357SAndroid Build Coastguard Worker UInt32 num = 0;
109*f6dc9357SAndroid Build Coastguard Worker FOR_VECTOR (i, Extents)
110*f6dc9357SAndroid Build Coastguard Worker num += Extents[i].NumBlocks;
111*f6dc9357SAndroid Build Coastguard Worker return num;
112*f6dc9357SAndroid Build Coastguard Worker }
113*f6dc9357SAndroid Build Coastguard Worker
Check_NumBlocks() const114*f6dc9357SAndroid Build Coastguard Worker bool CFork::Check_NumBlocks() const
115*f6dc9357SAndroid Build Coastguard Worker {
116*f6dc9357SAndroid Build Coastguard Worker UInt32 num = NumBlocks;
117*f6dc9357SAndroid Build Coastguard Worker FOR_VECTOR (i, Extents)
118*f6dc9357SAndroid Build Coastguard Worker {
119*f6dc9357SAndroid Build Coastguard Worker const UInt32 cur = Extents[i].NumBlocks;
120*f6dc9357SAndroid Build Coastguard Worker if (num < cur)
121*f6dc9357SAndroid Build Coastguard Worker return false;
122*f6dc9357SAndroid Build Coastguard Worker num -= cur;
123*f6dc9357SAndroid Build Coastguard Worker }
124*f6dc9357SAndroid Build Coastguard Worker return num == 0;
125*f6dc9357SAndroid Build Coastguard Worker }
126*f6dc9357SAndroid Build Coastguard Worker
127*f6dc9357SAndroid Build Coastguard Worker struct CIdIndexPair
128*f6dc9357SAndroid Build Coastguard Worker {
129*f6dc9357SAndroid Build Coastguard Worker UInt32 ID;
130*f6dc9357SAndroid Build Coastguard Worker unsigned Index;
131*f6dc9357SAndroid Build Coastguard Worker
132*f6dc9357SAndroid Build Coastguard Worker int Compare(const CIdIndexPair &a) const;
133*f6dc9357SAndroid Build Coastguard Worker };
134*f6dc9357SAndroid Build Coastguard Worker
135*f6dc9357SAndroid Build Coastguard Worker #define RINOZ(x) { const int _t_ = (x); if (_t_ != 0) return _t_; }
136*f6dc9357SAndroid Build Coastguard Worker
Compare(const CIdIndexPair & a) const137*f6dc9357SAndroid Build Coastguard Worker int CIdIndexPair::Compare(const CIdIndexPair &a) const
138*f6dc9357SAndroid Build Coastguard Worker {
139*f6dc9357SAndroid Build Coastguard Worker RINOZ(MyCompare(ID, a.ID))
140*f6dc9357SAndroid Build Coastguard Worker return MyCompare(Index, a.Index);
141*f6dc9357SAndroid Build Coastguard Worker }
142*f6dc9357SAndroid Build Coastguard Worker
FindItemIndex(const CRecordVector<CIdIndexPair> & items,UInt32 id)143*f6dc9357SAndroid Build Coastguard Worker static int FindItemIndex(const CRecordVector<CIdIndexPair> &items, UInt32 id)
144*f6dc9357SAndroid Build Coastguard Worker {
145*f6dc9357SAndroid Build Coastguard Worker unsigned left = 0, right = items.Size();
146*f6dc9357SAndroid Build Coastguard Worker while (left != right)
147*f6dc9357SAndroid Build Coastguard Worker {
148*f6dc9357SAndroid Build Coastguard Worker const unsigned mid = (left + right) / 2;
149*f6dc9357SAndroid Build Coastguard Worker const UInt32 midVal = items[mid].ID;
150*f6dc9357SAndroid Build Coastguard Worker if (id == midVal)
151*f6dc9357SAndroid Build Coastguard Worker return (int)items[mid].Index;
152*f6dc9357SAndroid Build Coastguard Worker if (id < midVal)
153*f6dc9357SAndroid Build Coastguard Worker right = mid;
154*f6dc9357SAndroid Build Coastguard Worker else
155*f6dc9357SAndroid Build Coastguard Worker left = mid + 1;
156*f6dc9357SAndroid Build Coastguard Worker }
157*f6dc9357SAndroid Build Coastguard Worker return -1;
158*f6dc9357SAndroid Build Coastguard Worker }
159*f6dc9357SAndroid Build Coastguard Worker
Find_in_IdExtents(const CObjectVector<CIdExtents> & items,UInt32 id)160*f6dc9357SAndroid Build Coastguard Worker static int Find_in_IdExtents(const CObjectVector<CIdExtents> &items, UInt32 id)
161*f6dc9357SAndroid Build Coastguard Worker {
162*f6dc9357SAndroid Build Coastguard Worker unsigned left = 0, right = items.Size();
163*f6dc9357SAndroid Build Coastguard Worker while (left != right)
164*f6dc9357SAndroid Build Coastguard Worker {
165*f6dc9357SAndroid Build Coastguard Worker const unsigned mid = (left + right) / 2;
166*f6dc9357SAndroid Build Coastguard Worker const UInt32 midVal = items[mid].ID;
167*f6dc9357SAndroid Build Coastguard Worker if (id == midVal)
168*f6dc9357SAndroid Build Coastguard Worker return (int)mid;
169*f6dc9357SAndroid Build Coastguard Worker if (id < midVal)
170*f6dc9357SAndroid Build Coastguard Worker right = mid;
171*f6dc9357SAndroid Build Coastguard Worker else
172*f6dc9357SAndroid Build Coastguard Worker left = mid + 1;
173*f6dc9357SAndroid Build Coastguard Worker }
174*f6dc9357SAndroid Build Coastguard Worker return -1;
175*f6dc9357SAndroid Build Coastguard Worker }
176*f6dc9357SAndroid Build Coastguard Worker
Upgrade(const CObjectVector<CIdExtents> & items,UInt32 id)177*f6dc9357SAndroid Build Coastguard Worker bool CFork::Upgrade(const CObjectVector<CIdExtents> &items, UInt32 id)
178*f6dc9357SAndroid Build Coastguard Worker {
179*f6dc9357SAndroid Build Coastguard Worker const int index = Find_in_IdExtents(items, id);
180*f6dc9357SAndroid Build Coastguard Worker if (index < 0)
181*f6dc9357SAndroid Build Coastguard Worker return true;
182*f6dc9357SAndroid Build Coastguard Worker const CIdExtents &item = items[index];
183*f6dc9357SAndroid Build Coastguard Worker if (Calc_NumBlocks_from_Extents() != item.StartBlock)
184*f6dc9357SAndroid Build Coastguard Worker return false;
185*f6dc9357SAndroid Build Coastguard Worker Extents += item.Extents;
186*f6dc9357SAndroid Build Coastguard Worker return true;
187*f6dc9357SAndroid Build Coastguard Worker }
188*f6dc9357SAndroid Build Coastguard Worker
189*f6dc9357SAndroid Build Coastguard Worker
190*f6dc9357SAndroid Build Coastguard Worker struct CVolHeader
191*f6dc9357SAndroid Build Coastguard Worker {
192*f6dc9357SAndroid Build Coastguard Worker unsigned BlockSizeLog;
193*f6dc9357SAndroid Build Coastguard Worker UInt32 NumFiles;
194*f6dc9357SAndroid Build Coastguard Worker UInt32 NumFolders;
195*f6dc9357SAndroid Build Coastguard Worker UInt32 NumBlocks;
196*f6dc9357SAndroid Build Coastguard Worker UInt32 NumFreeBlocks;
197*f6dc9357SAndroid Build Coastguard Worker
198*f6dc9357SAndroid Build Coastguard Worker bool Is_Hsfx_ver5;
199*f6dc9357SAndroid Build Coastguard Worker // UInt32 Attr;
200*f6dc9357SAndroid Build Coastguard Worker // UInt32 LastMountedVersion;
201*f6dc9357SAndroid Build Coastguard Worker // UInt32 JournalInfoBlock;
202*f6dc9357SAndroid Build Coastguard Worker
203*f6dc9357SAndroid Build Coastguard Worker UInt32 CTime;
204*f6dc9357SAndroid Build Coastguard Worker UInt32 MTime;
205*f6dc9357SAndroid Build Coastguard Worker // UInt32 BackupTime;
206*f6dc9357SAndroid Build Coastguard Worker // UInt32 CheckedTime;
207*f6dc9357SAndroid Build Coastguard Worker
208*f6dc9357SAndroid Build Coastguard Worker // UInt32 WriteCount;
209*f6dc9357SAndroid Build Coastguard Worker // UInt32 FinderInfo[8];
210*f6dc9357SAndroid Build Coastguard Worker // UInt64 VolID;
211*f6dc9357SAndroid Build Coastguard Worker
GetPhySizeNArchive::NHfs::CVolHeader212*f6dc9357SAndroid Build Coastguard Worker UInt64 GetPhySize() const { return (UInt64)NumBlocks << BlockSizeLog; }
GetFreeSizeNArchive::NHfs::CVolHeader213*f6dc9357SAndroid Build Coastguard Worker UInt64 GetFreeSize() const { return (UInt64)NumFreeBlocks << BlockSizeLog; }
IsHfsXNArchive::NHfs::CVolHeader214*f6dc9357SAndroid Build Coastguard Worker bool IsHfsX() const { return Is_Hsfx_ver5; }
215*f6dc9357SAndroid Build Coastguard Worker };
216*f6dc9357SAndroid Build Coastguard Worker
HfsTimeToFileTime(UInt32 hfsTime,FILETIME & ft)217*f6dc9357SAndroid Build Coastguard Worker inline void HfsTimeToFileTime(UInt32 hfsTime, FILETIME &ft)
218*f6dc9357SAndroid Build Coastguard Worker {
219*f6dc9357SAndroid Build Coastguard Worker UInt64 v = ((UInt64)3600 * 24 * (365 * 303 + 24 * 3) + hfsTime) * 10000000;
220*f6dc9357SAndroid Build Coastguard Worker ft.dwLowDateTime = (DWORD)v;
221*f6dc9357SAndroid Build Coastguard Worker ft.dwHighDateTime = (DWORD)(v >> 32);
222*f6dc9357SAndroid Build Coastguard Worker }
223*f6dc9357SAndroid Build Coastguard Worker
224*f6dc9357SAndroid Build Coastguard Worker enum ERecordType
225*f6dc9357SAndroid Build Coastguard Worker {
226*f6dc9357SAndroid Build Coastguard Worker RECORD_TYPE_FOLDER = 1,
227*f6dc9357SAndroid Build Coastguard Worker RECORD_TYPE_FILE,
228*f6dc9357SAndroid Build Coastguard Worker RECORD_TYPE_FOLDER_THREAD,
229*f6dc9357SAndroid Build Coastguard Worker RECORD_TYPE_FILE_THREAD
230*f6dc9357SAndroid Build Coastguard Worker };
231*f6dc9357SAndroid Build Coastguard Worker
232*f6dc9357SAndroid Build Coastguard Worker
233*f6dc9357SAndroid Build Coastguard Worker
234*f6dc9357SAndroid Build Coastguard Worker // static const UInt32 kMethod_1_NO_COMPRESSION = 1; // in xattr
235*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kMethod_ZLIB_ATTR = 3;
236*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kMethod_ZLIB_RSRC = 4;
237*f6dc9357SAndroid Build Coastguard Worker // static const UInt32 kMethod_DEDUP = 5; // de-dup within the generation store
238*f6dc9357SAndroid Build Coastguard Worker // macos 10.10
239*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kMethod_LZVN_ATTR = 7;
240*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kMethod_LZVN_RSRC = 8;
241*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kMethod_COPY_ATTR = 9;
242*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kMethod_COPY_RSRC = 10;
243*f6dc9357SAndroid Build Coastguard Worker // macos 10.11
244*f6dc9357SAndroid Build Coastguard Worker // static const UInt32 kMethod_LZFSE_ATTR = 11;
245*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kMethod_LZFSE_RSRC = 12;
246*f6dc9357SAndroid Build Coastguard Worker
247*f6dc9357SAndroid Build Coastguard Worker // static const UInt32 kMethod_ZBM_RSRC = 14;
248*f6dc9357SAndroid Build Coastguard Worker
249*f6dc9357SAndroid Build Coastguard Worker static const char * const g_Methods[] =
250*f6dc9357SAndroid Build Coastguard Worker {
251*f6dc9357SAndroid Build Coastguard Worker NULL
252*f6dc9357SAndroid Build Coastguard Worker , NULL
253*f6dc9357SAndroid Build Coastguard Worker , NULL
254*f6dc9357SAndroid Build Coastguard Worker , "ZLIB-attr"
255*f6dc9357SAndroid Build Coastguard Worker , "ZLIB-rsrc"
256*f6dc9357SAndroid Build Coastguard Worker , NULL
257*f6dc9357SAndroid Build Coastguard Worker , NULL
258*f6dc9357SAndroid Build Coastguard Worker , "LZVN-attr"
259*f6dc9357SAndroid Build Coastguard Worker , "LZVN-rsrc"
260*f6dc9357SAndroid Build Coastguard Worker , "COPY-attr"
261*f6dc9357SAndroid Build Coastguard Worker , "COPY-rsrc"
262*f6dc9357SAndroid Build Coastguard Worker , "LZFSE-attr"
263*f6dc9357SAndroid Build Coastguard Worker , "LZFSE-rsrc"
264*f6dc9357SAndroid Build Coastguard Worker , NULL
265*f6dc9357SAndroid Build Coastguard Worker , "ZBM-rsrc"
266*f6dc9357SAndroid Build Coastguard Worker };
267*f6dc9357SAndroid Build Coastguard Worker
268*f6dc9357SAndroid Build Coastguard Worker
269*f6dc9357SAndroid Build Coastguard Worker static const Byte k_COPY_Uncompressed_Marker = 0xcc;
270*f6dc9357SAndroid Build Coastguard Worker static const Byte k_LZVN_Uncompressed_Marker = 6;
271*f6dc9357SAndroid Build Coastguard Worker
Parse(const Byte * p,size_t dataSize)272*f6dc9357SAndroid Build Coastguard Worker void CCompressHeader::Parse(const Byte *p, size_t dataSize)
273*f6dc9357SAndroid Build Coastguard Worker {
274*f6dc9357SAndroid Build Coastguard Worker Clear();
275*f6dc9357SAndroid Build Coastguard Worker
276*f6dc9357SAndroid Build Coastguard Worker if (dataSize < k_decmpfs_HeaderSize)
277*f6dc9357SAndroid Build Coastguard Worker return;
278*f6dc9357SAndroid Build Coastguard Worker if (GetUi32(p) != 0x636D7066) // magic == "fpmc"
279*f6dc9357SAndroid Build Coastguard Worker return;
280*f6dc9357SAndroid Build Coastguard Worker Method = GetUi32(p + 4);
281*f6dc9357SAndroid Build Coastguard Worker UnpackSize = GetUi64(p + 8);
282*f6dc9357SAndroid Build Coastguard Worker dataSize -= k_decmpfs_HeaderSize;
283*f6dc9357SAndroid Build Coastguard Worker IsCorrect = true;
284*f6dc9357SAndroid Build Coastguard Worker
285*f6dc9357SAndroid Build Coastguard Worker if ( Method == kMethod_ZLIB_RSRC
286*f6dc9357SAndroid Build Coastguard Worker || Method == kMethod_COPY_RSRC
287*f6dc9357SAndroid Build Coastguard Worker || Method == kMethod_LZVN_RSRC
288*f6dc9357SAndroid Build Coastguard Worker || Method == kMethod_LZFSE_RSRC
289*f6dc9357SAndroid Build Coastguard Worker // || Method == kMethod_ZBM_RSRC // for debug
290*f6dc9357SAndroid Build Coastguard Worker )
291*f6dc9357SAndroid Build Coastguard Worker {
292*f6dc9357SAndroid Build Coastguard Worker IsResource = true;
293*f6dc9357SAndroid Build Coastguard Worker if (dataSize == 0)
294*f6dc9357SAndroid Build Coastguard Worker IsSupported = (
295*f6dc9357SAndroid Build Coastguard Worker Method != kMethod_LZFSE_RSRC &&
296*f6dc9357SAndroid Build Coastguard Worker Method != kMethod_COPY_RSRC);
297*f6dc9357SAndroid Build Coastguard Worker return;
298*f6dc9357SAndroid Build Coastguard Worker }
299*f6dc9357SAndroid Build Coastguard Worker
300*f6dc9357SAndroid Build Coastguard Worker if ( Method == kMethod_ZLIB_ATTR
301*f6dc9357SAndroid Build Coastguard Worker || Method == kMethod_COPY_ATTR
302*f6dc9357SAndroid Build Coastguard Worker || Method == kMethod_LZVN_ATTR
303*f6dc9357SAndroid Build Coastguard Worker // || Method == kMethod_LZFSE_ATTR
304*f6dc9357SAndroid Build Coastguard Worker )
305*f6dc9357SAndroid Build Coastguard Worker {
306*f6dc9357SAndroid Build Coastguard Worker if (dataSize == 0)
307*f6dc9357SAndroid Build Coastguard Worker return;
308*f6dc9357SAndroid Build Coastguard Worker const Byte b = p[k_decmpfs_HeaderSize];
309*f6dc9357SAndroid Build Coastguard Worker if ( (Method == kMethod_ZLIB_ATTR && (b & 0xf) == 0xf)
310*f6dc9357SAndroid Build Coastguard Worker || (Method == kMethod_COPY_ATTR && b == k_COPY_Uncompressed_Marker)
311*f6dc9357SAndroid Build Coastguard Worker || (Method == kMethod_LZVN_ATTR && b == k_LZVN_Uncompressed_Marker))
312*f6dc9357SAndroid Build Coastguard Worker {
313*f6dc9357SAndroid Build Coastguard Worker dataSize--;
314*f6dc9357SAndroid Build Coastguard Worker // if (UnpackSize > dataSize)
315*f6dc9357SAndroid Build Coastguard Worker if (UnpackSize != dataSize)
316*f6dc9357SAndroid Build Coastguard Worker return;
317*f6dc9357SAndroid Build Coastguard Worker DataPos = k_decmpfs_HeaderSize + 1;
318*f6dc9357SAndroid Build Coastguard Worker IsSupported = true;
319*f6dc9357SAndroid Build Coastguard Worker }
320*f6dc9357SAndroid Build Coastguard Worker else
321*f6dc9357SAndroid Build Coastguard Worker {
322*f6dc9357SAndroid Build Coastguard Worker if (Method != kMethod_COPY_ATTR)
323*f6dc9357SAndroid Build Coastguard Worker IsSupported = true;
324*f6dc9357SAndroid Build Coastguard Worker DataPos = k_decmpfs_HeaderSize;
325*f6dc9357SAndroid Build Coastguard Worker }
326*f6dc9357SAndroid Build Coastguard Worker }
327*f6dc9357SAndroid Build Coastguard Worker }
328*f6dc9357SAndroid Build Coastguard Worker
329*f6dc9357SAndroid Build Coastguard Worker
MethodToProp(NWindows::NCOM::CPropVariant & prop) const330*f6dc9357SAndroid Build Coastguard Worker void CCompressHeader::MethodToProp(NWindows::NCOM::CPropVariant &prop) const
331*f6dc9357SAndroid Build Coastguard Worker {
332*f6dc9357SAndroid Build Coastguard Worker if (!IsCorrect)
333*f6dc9357SAndroid Build Coastguard Worker return;
334*f6dc9357SAndroid Build Coastguard Worker const UInt32 method = Method;
335*f6dc9357SAndroid Build Coastguard Worker const char *p = NULL;
336*f6dc9357SAndroid Build Coastguard Worker if (method < Z7_ARRAY_SIZE(g_Methods))
337*f6dc9357SAndroid Build Coastguard Worker p = g_Methods[method];
338*f6dc9357SAndroid Build Coastguard Worker AString s;
339*f6dc9357SAndroid Build Coastguard Worker if (p)
340*f6dc9357SAndroid Build Coastguard Worker s = p;
341*f6dc9357SAndroid Build Coastguard Worker else
342*f6dc9357SAndroid Build Coastguard Worker s.Add_UInt32(method);
343*f6dc9357SAndroid Build Coastguard Worker // if (!IsSupported) s += "-unsuported";
344*f6dc9357SAndroid Build Coastguard Worker prop = s;
345*f6dc9357SAndroid Build Coastguard Worker }
346*f6dc9357SAndroid Build Coastguard Worker
MethodsMaskToProp(UInt32 methodsMask,NWindows::NCOM::CPropVariant & prop)347*f6dc9357SAndroid Build Coastguard Worker void MethodsMaskToProp(UInt32 methodsMask, NWindows::NCOM::CPropVariant &prop)
348*f6dc9357SAndroid Build Coastguard Worker {
349*f6dc9357SAndroid Build Coastguard Worker FLAGS_TO_PROP(g_Methods, methodsMask, prop);
350*f6dc9357SAndroid Build Coastguard Worker }
351*f6dc9357SAndroid Build Coastguard Worker
352*f6dc9357SAndroid Build Coastguard Worker
353*f6dc9357SAndroid Build Coastguard Worker struct CItem
354*f6dc9357SAndroid Build Coastguard Worker {
355*f6dc9357SAndroid Build Coastguard Worker UString Name;
356*f6dc9357SAndroid Build Coastguard Worker
357*f6dc9357SAndroid Build Coastguard Worker UInt32 ParentID;
358*f6dc9357SAndroid Build Coastguard Worker
359*f6dc9357SAndroid Build Coastguard Worker UInt16 Type;
360*f6dc9357SAndroid Build Coastguard Worker UInt16 FileMode;
361*f6dc9357SAndroid Build Coastguard Worker // UInt16 Flags;
362*f6dc9357SAndroid Build Coastguard Worker // UInt32 Valence;
363*f6dc9357SAndroid Build Coastguard Worker UInt32 ID;
364*f6dc9357SAndroid Build Coastguard Worker UInt32 CTime;
365*f6dc9357SAndroid Build Coastguard Worker UInt32 MTime;
366*f6dc9357SAndroid Build Coastguard Worker UInt32 AttrMTime;
367*f6dc9357SAndroid Build Coastguard Worker UInt32 ATime;
368*f6dc9357SAndroid Build Coastguard Worker // UInt32 BackupDate;
369*f6dc9357SAndroid Build Coastguard Worker
370*f6dc9357SAndroid Build Coastguard Worker /*
371*f6dc9357SAndroid Build Coastguard Worker UInt32 OwnerID;
372*f6dc9357SAndroid Build Coastguard Worker UInt32 GroupID;
373*f6dc9357SAndroid Build Coastguard Worker Byte AdminFlags;
374*f6dc9357SAndroid Build Coastguard Worker Byte OwnerFlags;
375*f6dc9357SAndroid Build Coastguard Worker union
376*f6dc9357SAndroid Build Coastguard Worker {
377*f6dc9357SAndroid Build Coastguard Worker UInt32 iNodeNum;
378*f6dc9357SAndroid Build Coastguard Worker UInt32 LinkCount;
379*f6dc9357SAndroid Build Coastguard Worker UInt32 RawDevice;
380*f6dc9357SAndroid Build Coastguard Worker } special;
381*f6dc9357SAndroid Build Coastguard Worker
382*f6dc9357SAndroid Build Coastguard Worker UInt32 FileType;
383*f6dc9357SAndroid Build Coastguard Worker UInt32 FileCreator;
384*f6dc9357SAndroid Build Coastguard Worker UInt16 FinderFlags;
385*f6dc9357SAndroid Build Coastguard Worker UInt16 Point[2];
386*f6dc9357SAndroid Build Coastguard Worker */
387*f6dc9357SAndroid Build Coastguard Worker
388*f6dc9357SAndroid Build Coastguard Worker CFork DataFork;
389*f6dc9357SAndroid Build Coastguard Worker CFork ResourceFork;
390*f6dc9357SAndroid Build Coastguard Worker
391*f6dc9357SAndroid Build Coastguard Worker // for compressed attribute (decmpfs)
392*f6dc9357SAndroid Build Coastguard Worker int decmpfs_AttrIndex;
393*f6dc9357SAndroid Build Coastguard Worker CCompressHeader CompressHeader;
394*f6dc9357SAndroid Build Coastguard Worker
CItemNArchive::NHfs::CItem395*f6dc9357SAndroid Build Coastguard Worker CItem():
396*f6dc9357SAndroid Build Coastguard Worker decmpfs_AttrIndex(-1)
397*f6dc9357SAndroid Build Coastguard Worker {}
IsDirNArchive::NHfs::CItem398*f6dc9357SAndroid Build Coastguard Worker bool IsDir() const { return Type == RECORD_TYPE_FOLDER; }
399*f6dc9357SAndroid Build Coastguard Worker // const CFork *GetFork(bool isResource) const { return (isResource ? &ResourceFork: &DataFork); }
400*f6dc9357SAndroid Build Coastguard Worker };
401*f6dc9357SAndroid Build Coastguard Worker
402*f6dc9357SAndroid Build Coastguard Worker
403*f6dc9357SAndroid Build Coastguard Worker struct CAttr
404*f6dc9357SAndroid Build Coastguard Worker {
405*f6dc9357SAndroid Build Coastguard Worker UInt32 ID;
406*f6dc9357SAndroid Build Coastguard Worker bool Fork_defined;
407*f6dc9357SAndroid Build Coastguard Worker
408*f6dc9357SAndroid Build Coastguard Worker // UInt32 Size; // for (Fork_defined == false) case
409*f6dc9357SAndroid Build Coastguard Worker // size_t DataPos; // for (Fork_defined == false) case
410*f6dc9357SAndroid Build Coastguard Worker CByteBuffer Data;
411*f6dc9357SAndroid Build Coastguard Worker
412*f6dc9357SAndroid Build Coastguard Worker CFork Fork;
413*f6dc9357SAndroid Build Coastguard Worker
414*f6dc9357SAndroid Build Coastguard Worker UString Name;
415*f6dc9357SAndroid Build Coastguard Worker
GetSizeNArchive::NHfs::CAttr416*f6dc9357SAndroid Build Coastguard Worker UInt64 GetSize() const
417*f6dc9357SAndroid Build Coastguard Worker {
418*f6dc9357SAndroid Build Coastguard Worker if (Fork_defined)
419*f6dc9357SAndroid Build Coastguard Worker return Fork.Size;
420*f6dc9357SAndroid Build Coastguard Worker return Data.Size();
421*f6dc9357SAndroid Build Coastguard Worker }
422*f6dc9357SAndroid Build Coastguard Worker
CAttrNArchive::NHfs::CAttr423*f6dc9357SAndroid Build Coastguard Worker CAttr():
424*f6dc9357SAndroid Build Coastguard Worker Fork_defined(false)
425*f6dc9357SAndroid Build Coastguard Worker // Size(0),
426*f6dc9357SAndroid Build Coastguard Worker // DataPos(0),
427*f6dc9357SAndroid Build Coastguard Worker {}
428*f6dc9357SAndroid Build Coastguard Worker };
429*f6dc9357SAndroid Build Coastguard Worker
430*f6dc9357SAndroid Build Coastguard Worker
431*f6dc9357SAndroid Build Coastguard Worker static const int kAttrIndex_Item = -1;
432*f6dc9357SAndroid Build Coastguard Worker static const int kAttrIndex_Resource = -2;
433*f6dc9357SAndroid Build Coastguard Worker
434*f6dc9357SAndroid Build Coastguard Worker struct CRef
435*f6dc9357SAndroid Build Coastguard Worker {
436*f6dc9357SAndroid Build Coastguard Worker unsigned ItemIndex;
437*f6dc9357SAndroid Build Coastguard Worker int AttrIndex;
438*f6dc9357SAndroid Build Coastguard Worker int Parent;
439*f6dc9357SAndroid Build Coastguard Worker
CRefNArchive::NHfs::CRef440*f6dc9357SAndroid Build Coastguard Worker CRef(): AttrIndex(kAttrIndex_Item), Parent(-1) {}
IsResourceNArchive::NHfs::CRef441*f6dc9357SAndroid Build Coastguard Worker bool IsResource() const { return AttrIndex == kAttrIndex_Resource; }
IsAltStreamNArchive::NHfs::CRef442*f6dc9357SAndroid Build Coastguard Worker bool IsAltStream() const { return AttrIndex != kAttrIndex_Item; }
IsItemNArchive::NHfs::CRef443*f6dc9357SAndroid Build Coastguard Worker bool IsItem() const { return AttrIndex == kAttrIndex_Item; }
444*f6dc9357SAndroid Build Coastguard Worker };
445*f6dc9357SAndroid Build Coastguard Worker
446*f6dc9357SAndroid Build Coastguard Worker
447*f6dc9357SAndroid Build Coastguard Worker class CDatabase
448*f6dc9357SAndroid Build Coastguard Worker {
449*f6dc9357SAndroid Build Coastguard Worker HRESULT ReadFile(const CFork &fork, CByteBuffer &buf, IInStream *inStream);
450*f6dc9357SAndroid Build Coastguard Worker HRESULT LoadExtentFile(const CFork &fork, IInStream *inStream, CObjectVector<CIdExtents> *overflowExtentsArray);
451*f6dc9357SAndroid Build Coastguard Worker HRESULT LoadAttrs(const CFork &fork, IInStream *inStream, IArchiveOpenCallback *progress);
452*f6dc9357SAndroid Build Coastguard Worker HRESULT LoadCatalog(const CFork &fork, const CObjectVector<CIdExtents> *overflowExtentsArray, IInStream *inStream, IArchiveOpenCallback *progress);
453*f6dc9357SAndroid Build Coastguard Worker bool Parse_decmpgfs(unsigned attrIndex, CItem &item, bool &skip);
454*f6dc9357SAndroid Build Coastguard Worker public:
455*f6dc9357SAndroid Build Coastguard Worker CRecordVector<CRef> Refs;
456*f6dc9357SAndroid Build Coastguard Worker CObjectVector<CItem> Items;
457*f6dc9357SAndroid Build Coastguard Worker CObjectVector<CAttr> Attrs;
458*f6dc9357SAndroid Build Coastguard Worker
459*f6dc9357SAndroid Build Coastguard Worker // CByteBuffer AttrBuf;
460*f6dc9357SAndroid Build Coastguard Worker
461*f6dc9357SAndroid Build Coastguard Worker CVolHeader Header;
462*f6dc9357SAndroid Build Coastguard Worker bool HeadersError;
463*f6dc9357SAndroid Build Coastguard Worker bool UnsupportedFeature;
464*f6dc9357SAndroid Build Coastguard Worker bool ThereAreAltStreams;
465*f6dc9357SAndroid Build Coastguard Worker // bool CaseSensetive;
466*f6dc9357SAndroid Build Coastguard Worker UInt32 MethodsMask;
467*f6dc9357SAndroid Build Coastguard Worker UString ResFileName;
468*f6dc9357SAndroid Build Coastguard Worker
469*f6dc9357SAndroid Build Coastguard Worker UInt64 SpecOffset;
470*f6dc9357SAndroid Build Coastguard Worker // UInt64 PhySize;
471*f6dc9357SAndroid Build Coastguard Worker UInt64 PhySize2;
472*f6dc9357SAndroid Build Coastguard Worker UInt64 ArcFileSize;
473*f6dc9357SAndroid Build Coastguard Worker
Clear()474*f6dc9357SAndroid Build Coastguard Worker void Clear()
475*f6dc9357SAndroid Build Coastguard Worker {
476*f6dc9357SAndroid Build Coastguard Worker SpecOffset = 0;
477*f6dc9357SAndroid Build Coastguard Worker // PhySize = 0;
478*f6dc9357SAndroid Build Coastguard Worker PhySize2 = 0;
479*f6dc9357SAndroid Build Coastguard Worker ArcFileSize = 0;
480*f6dc9357SAndroid Build Coastguard Worker MethodsMask = 0;
481*f6dc9357SAndroid Build Coastguard Worker HeadersError = false;
482*f6dc9357SAndroid Build Coastguard Worker UnsupportedFeature = false;
483*f6dc9357SAndroid Build Coastguard Worker ThereAreAltStreams = false;
484*f6dc9357SAndroid Build Coastguard Worker // CaseSensetive = false;
485*f6dc9357SAndroid Build Coastguard Worker
486*f6dc9357SAndroid Build Coastguard Worker Refs.Clear();
487*f6dc9357SAndroid Build Coastguard Worker Items.Clear();
488*f6dc9357SAndroid Build Coastguard Worker Attrs.Clear();
489*f6dc9357SAndroid Build Coastguard Worker // AttrBuf.Free();
490*f6dc9357SAndroid Build Coastguard Worker }
491*f6dc9357SAndroid Build Coastguard Worker
Get_UnpackSize_of_Ref(const CRef & ref) const492*f6dc9357SAndroid Build Coastguard Worker UInt64 Get_UnpackSize_of_Ref(const CRef &ref) const
493*f6dc9357SAndroid Build Coastguard Worker {
494*f6dc9357SAndroid Build Coastguard Worker if (ref.AttrIndex >= 0)
495*f6dc9357SAndroid Build Coastguard Worker return Attrs[ref.AttrIndex].GetSize();
496*f6dc9357SAndroid Build Coastguard Worker const CItem &item = Items[ref.ItemIndex];
497*f6dc9357SAndroid Build Coastguard Worker if (ref.IsResource())
498*f6dc9357SAndroid Build Coastguard Worker return item.ResourceFork.Size;
499*f6dc9357SAndroid Build Coastguard Worker if (item.IsDir())
500*f6dc9357SAndroid Build Coastguard Worker return 0;
501*f6dc9357SAndroid Build Coastguard Worker else if (item.CompressHeader.IsCorrect)
502*f6dc9357SAndroid Build Coastguard Worker return item.CompressHeader.UnpackSize;
503*f6dc9357SAndroid Build Coastguard Worker return item.DataFork.Size;
504*f6dc9357SAndroid Build Coastguard Worker }
505*f6dc9357SAndroid Build Coastguard Worker
506*f6dc9357SAndroid Build Coastguard Worker void GetItemPath(unsigned index, NWindows::NCOM::CPropVariant &path) const;
507*f6dc9357SAndroid Build Coastguard Worker HRESULT Open2(IInStream *inStream, IArchiveOpenCallback *progress);
508*f6dc9357SAndroid Build Coastguard Worker };
509*f6dc9357SAndroid Build Coastguard Worker
510*f6dc9357SAndroid Build Coastguard Worker enum
511*f6dc9357SAndroid Build Coastguard Worker {
512*f6dc9357SAndroid Build Coastguard Worker kHfsID_Root = 1,
513*f6dc9357SAndroid Build Coastguard Worker kHfsID_RootFolder = 2,
514*f6dc9357SAndroid Build Coastguard Worker kHfsID_ExtentsFile = 3,
515*f6dc9357SAndroid Build Coastguard Worker kHfsID_CatalogFile = 4,
516*f6dc9357SAndroid Build Coastguard Worker kHfsID_BadBlockFile = 5,
517*f6dc9357SAndroid Build Coastguard Worker kHfsID_AllocationFile = 6,
518*f6dc9357SAndroid Build Coastguard Worker kHfsID_StartupFile = 7,
519*f6dc9357SAndroid Build Coastguard Worker kHfsID_AttributesFile = 8,
520*f6dc9357SAndroid Build Coastguard Worker kHfsID_RepairCatalogFile = 14,
521*f6dc9357SAndroid Build Coastguard Worker kHfsID_BogusExtentFile = 15,
522*f6dc9357SAndroid Build Coastguard Worker kHfsID_FirstUserCatalogNode = 16
523*f6dc9357SAndroid Build Coastguard Worker };
524*f6dc9357SAndroid Build Coastguard Worker
GetItemPath(unsigned index,NWindows::NCOM::CPropVariant & path) const525*f6dc9357SAndroid Build Coastguard Worker void CDatabase::GetItemPath(unsigned index, NWindows::NCOM::CPropVariant &path) const
526*f6dc9357SAndroid Build Coastguard Worker {
527*f6dc9357SAndroid Build Coastguard Worker unsigned len = 0;
528*f6dc9357SAndroid Build Coastguard Worker const unsigned kNumLevelsMax = (1 << 10);
529*f6dc9357SAndroid Build Coastguard Worker unsigned cur = index;
530*f6dc9357SAndroid Build Coastguard Worker unsigned i;
531*f6dc9357SAndroid Build Coastguard Worker
532*f6dc9357SAndroid Build Coastguard Worker for (i = 0; i < kNumLevelsMax; i++)
533*f6dc9357SAndroid Build Coastguard Worker {
534*f6dc9357SAndroid Build Coastguard Worker const CRef &ref = Refs[cur];
535*f6dc9357SAndroid Build Coastguard Worker const UString *s;
536*f6dc9357SAndroid Build Coastguard Worker
537*f6dc9357SAndroid Build Coastguard Worker if (ref.IsResource())
538*f6dc9357SAndroid Build Coastguard Worker s = &ResFileName;
539*f6dc9357SAndroid Build Coastguard Worker else if (ref.AttrIndex >= 0)
540*f6dc9357SAndroid Build Coastguard Worker s = &Attrs[ref.AttrIndex].Name;
541*f6dc9357SAndroid Build Coastguard Worker else
542*f6dc9357SAndroid Build Coastguard Worker s = &Items[ref.ItemIndex].Name;
543*f6dc9357SAndroid Build Coastguard Worker
544*f6dc9357SAndroid Build Coastguard Worker len += s->Len();
545*f6dc9357SAndroid Build Coastguard Worker len++;
546*f6dc9357SAndroid Build Coastguard Worker cur = (unsigned)ref.Parent;
547*f6dc9357SAndroid Build Coastguard Worker if (ref.Parent < 0)
548*f6dc9357SAndroid Build Coastguard Worker break;
549*f6dc9357SAndroid Build Coastguard Worker }
550*f6dc9357SAndroid Build Coastguard Worker
551*f6dc9357SAndroid Build Coastguard Worker len--;
552*f6dc9357SAndroid Build Coastguard Worker wchar_t *p = path.AllocBstr(len);
553*f6dc9357SAndroid Build Coastguard Worker p[len] = 0;
554*f6dc9357SAndroid Build Coastguard Worker cur = index;
555*f6dc9357SAndroid Build Coastguard Worker
556*f6dc9357SAndroid Build Coastguard Worker for (;;)
557*f6dc9357SAndroid Build Coastguard Worker {
558*f6dc9357SAndroid Build Coastguard Worker const CRef &ref = Refs[cur];
559*f6dc9357SAndroid Build Coastguard Worker const UString *s;
560*f6dc9357SAndroid Build Coastguard Worker wchar_t delimChar = L':';
561*f6dc9357SAndroid Build Coastguard Worker
562*f6dc9357SAndroid Build Coastguard Worker if (ref.IsResource())
563*f6dc9357SAndroid Build Coastguard Worker s = &ResFileName;
564*f6dc9357SAndroid Build Coastguard Worker else if (ref.AttrIndex >= 0)
565*f6dc9357SAndroid Build Coastguard Worker s = &Attrs[ref.AttrIndex].Name;
566*f6dc9357SAndroid Build Coastguard Worker else
567*f6dc9357SAndroid Build Coastguard Worker {
568*f6dc9357SAndroid Build Coastguard Worker delimChar = WCHAR_PATH_SEPARATOR;
569*f6dc9357SAndroid Build Coastguard Worker s = &Items[ref.ItemIndex].Name;
570*f6dc9357SAndroid Build Coastguard Worker }
571*f6dc9357SAndroid Build Coastguard Worker
572*f6dc9357SAndroid Build Coastguard Worker unsigned curLen = s->Len();
573*f6dc9357SAndroid Build Coastguard Worker len -= curLen;
574*f6dc9357SAndroid Build Coastguard Worker
575*f6dc9357SAndroid Build Coastguard Worker const wchar_t *src = (const wchar_t *)*s;
576*f6dc9357SAndroid Build Coastguard Worker wchar_t *dest = p + len;
577*f6dc9357SAndroid Build Coastguard Worker for (unsigned j = 0; j < curLen; j++)
578*f6dc9357SAndroid Build Coastguard Worker {
579*f6dc9357SAndroid Build Coastguard Worker wchar_t c = src[j];
580*f6dc9357SAndroid Build Coastguard Worker // 18.06
581*f6dc9357SAndroid Build Coastguard Worker if (c == CHAR_PATH_SEPARATOR || c == '/')
582*f6dc9357SAndroid Build Coastguard Worker c = '_';
583*f6dc9357SAndroid Build Coastguard Worker dest[j] = c;
584*f6dc9357SAndroid Build Coastguard Worker }
585*f6dc9357SAndroid Build Coastguard Worker
586*f6dc9357SAndroid Build Coastguard Worker if (len == 0)
587*f6dc9357SAndroid Build Coastguard Worker break;
588*f6dc9357SAndroid Build Coastguard Worker p[--len] = delimChar;
589*f6dc9357SAndroid Build Coastguard Worker cur = (unsigned)ref.Parent;
590*f6dc9357SAndroid Build Coastguard Worker }
591*f6dc9357SAndroid Build Coastguard Worker }
592*f6dc9357SAndroid Build Coastguard Worker
593*f6dc9357SAndroid Build Coastguard Worker // Actually we read all blocks. It can be larger than fork.Size
594*f6dc9357SAndroid Build Coastguard Worker
ReadFile(const CFork & fork,CByteBuffer & buf,IInStream * inStream)595*f6dc9357SAndroid Build Coastguard Worker HRESULT CDatabase::ReadFile(const CFork &fork, CByteBuffer &buf, IInStream *inStream)
596*f6dc9357SAndroid Build Coastguard Worker {
597*f6dc9357SAndroid Build Coastguard Worker if (fork.NumBlocks >= Header.NumBlocks)
598*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
599*f6dc9357SAndroid Build Coastguard Worker if (((ArcFileSize - SpecOffset) >> Header.BlockSizeLog) + 1 < fork.NumBlocks)
600*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
601*f6dc9357SAndroid Build Coastguard Worker
602*f6dc9357SAndroid Build Coastguard Worker const size_t totalSize = (size_t)fork.NumBlocks << Header.BlockSizeLog;
603*f6dc9357SAndroid Build Coastguard Worker if ((totalSize >> Header.BlockSizeLog) != fork.NumBlocks)
604*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
605*f6dc9357SAndroid Build Coastguard Worker buf.Alloc(totalSize);
606*f6dc9357SAndroid Build Coastguard Worker UInt32 curBlock = 0;
607*f6dc9357SAndroid Build Coastguard Worker FOR_VECTOR (i, fork.Extents)
608*f6dc9357SAndroid Build Coastguard Worker {
609*f6dc9357SAndroid Build Coastguard Worker if (curBlock >= fork.NumBlocks)
610*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
611*f6dc9357SAndroid Build Coastguard Worker const CExtent &e = fork.Extents[i];
612*f6dc9357SAndroid Build Coastguard Worker if (e.Pos > Header.NumBlocks ||
613*f6dc9357SAndroid Build Coastguard Worker e.NumBlocks > fork.NumBlocks - curBlock ||
614*f6dc9357SAndroid Build Coastguard Worker e.NumBlocks > Header.NumBlocks - e.Pos)
615*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
616*f6dc9357SAndroid Build Coastguard Worker RINOK(InStream_SeekSet(inStream, SpecOffset + ((UInt64)e.Pos << Header.BlockSizeLog)))
617*f6dc9357SAndroid Build Coastguard Worker RINOK(ReadStream_FALSE(inStream,
618*f6dc9357SAndroid Build Coastguard Worker (Byte *)buf + ((size_t)curBlock << Header.BlockSizeLog),
619*f6dc9357SAndroid Build Coastguard Worker (size_t)e.NumBlocks << Header.BlockSizeLog))
620*f6dc9357SAndroid Build Coastguard Worker curBlock += e.NumBlocks;
621*f6dc9357SAndroid Build Coastguard Worker }
622*f6dc9357SAndroid Build Coastguard Worker return S_OK;
623*f6dc9357SAndroid Build Coastguard Worker }
624*f6dc9357SAndroid Build Coastguard Worker
625*f6dc9357SAndroid Build Coastguard Worker static const unsigned kNodeDescriptor_Size = 14;
626*f6dc9357SAndroid Build Coastguard Worker
627*f6dc9357SAndroid Build Coastguard Worker struct CNodeDescriptor
628*f6dc9357SAndroid Build Coastguard Worker {
629*f6dc9357SAndroid Build Coastguard Worker UInt32 fLink;
630*f6dc9357SAndroid Build Coastguard Worker // UInt32 bLink;
631*f6dc9357SAndroid Build Coastguard Worker Byte Kind;
632*f6dc9357SAndroid Build Coastguard Worker // Byte Height;
633*f6dc9357SAndroid Build Coastguard Worker unsigned NumRecords;
634*f6dc9357SAndroid Build Coastguard Worker
635*f6dc9357SAndroid Build Coastguard Worker bool Parse(const Byte *p, unsigned nodeSizeLog);
636*f6dc9357SAndroid Build Coastguard Worker };
637*f6dc9357SAndroid Build Coastguard Worker
638*f6dc9357SAndroid Build Coastguard Worker
Parse(const Byte * p,unsigned nodeSizeLog)639*f6dc9357SAndroid Build Coastguard Worker bool CNodeDescriptor::Parse(const Byte *p, unsigned nodeSizeLog)
640*f6dc9357SAndroid Build Coastguard Worker {
641*f6dc9357SAndroid Build Coastguard Worker fLink = Get32(p);
642*f6dc9357SAndroid Build Coastguard Worker // bLink = Get32(p + 4);
643*f6dc9357SAndroid Build Coastguard Worker Kind = p[8];
644*f6dc9357SAndroid Build Coastguard Worker // Height = p[9];
645*f6dc9357SAndroid Build Coastguard Worker NumRecords = Get16(p + 10);
646*f6dc9357SAndroid Build Coastguard Worker
647*f6dc9357SAndroid Build Coastguard Worker const size_t nodeSize = (size_t)1 << nodeSizeLog;
648*f6dc9357SAndroid Build Coastguard Worker if (kNodeDescriptor_Size + ((UInt32)NumRecords + 1) * 2 > nodeSize)
649*f6dc9357SAndroid Build Coastguard Worker return false;
650*f6dc9357SAndroid Build Coastguard Worker const size_t limit = nodeSize - ((UInt32)NumRecords + 1) * 2;
651*f6dc9357SAndroid Build Coastguard Worker
652*f6dc9357SAndroid Build Coastguard Worker p += nodeSize - 2;
653*f6dc9357SAndroid Build Coastguard Worker
654*f6dc9357SAndroid Build Coastguard Worker for (unsigned i = 0; i < NumRecords; i++)
655*f6dc9357SAndroid Build Coastguard Worker {
656*f6dc9357SAndroid Build Coastguard Worker const UInt32 offs = Get16(p);
657*f6dc9357SAndroid Build Coastguard Worker p -= 2;
658*f6dc9357SAndroid Build Coastguard Worker const UInt32 offsNext = Get16(p);
659*f6dc9357SAndroid Build Coastguard Worker if (offs < kNodeDescriptor_Size
660*f6dc9357SAndroid Build Coastguard Worker || offs >= offsNext
661*f6dc9357SAndroid Build Coastguard Worker || offsNext > limit)
662*f6dc9357SAndroid Build Coastguard Worker return false;
663*f6dc9357SAndroid Build Coastguard Worker }
664*f6dc9357SAndroid Build Coastguard Worker return true;
665*f6dc9357SAndroid Build Coastguard Worker }
666*f6dc9357SAndroid Build Coastguard Worker
667*f6dc9357SAndroid Build Coastguard Worker struct CHeaderRec
668*f6dc9357SAndroid Build Coastguard Worker {
669*f6dc9357SAndroid Build Coastguard Worker // UInt16 TreeDepth;
670*f6dc9357SAndroid Build Coastguard Worker // UInt32 RootNode;
671*f6dc9357SAndroid Build Coastguard Worker // UInt32 LeafRecords;
672*f6dc9357SAndroid Build Coastguard Worker UInt32 FirstLeafNode;
673*f6dc9357SAndroid Build Coastguard Worker // UInt32 LastLeafNode;
674*f6dc9357SAndroid Build Coastguard Worker unsigned NodeSizeLog;
675*f6dc9357SAndroid Build Coastguard Worker // UInt16 MaxKeyLength;
676*f6dc9357SAndroid Build Coastguard Worker UInt32 TotalNodes;
677*f6dc9357SAndroid Build Coastguard Worker // UInt32 FreeNodes;
678*f6dc9357SAndroid Build Coastguard Worker // UInt16 Reserved1;
679*f6dc9357SAndroid Build Coastguard Worker // UInt32 ClumpSize;
680*f6dc9357SAndroid Build Coastguard Worker // Byte BtreeType;
681*f6dc9357SAndroid Build Coastguard Worker // Byte KeyCompareType;
682*f6dc9357SAndroid Build Coastguard Worker // UInt32 Attributes;
683*f6dc9357SAndroid Build Coastguard Worker // UInt32 Reserved3[16];
684*f6dc9357SAndroid Build Coastguard Worker
685*f6dc9357SAndroid Build Coastguard Worker HRESULT Parse2(const CByteBuffer &buf);
686*f6dc9357SAndroid Build Coastguard Worker };
687*f6dc9357SAndroid Build Coastguard Worker
Parse2(const CByteBuffer & buf)688*f6dc9357SAndroid Build Coastguard Worker HRESULT CHeaderRec::Parse2(const CByteBuffer &buf)
689*f6dc9357SAndroid Build Coastguard Worker {
690*f6dc9357SAndroid Build Coastguard Worker if (buf.Size() < kNodeDescriptor_Size + 0x2A + 16 * 4)
691*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
692*f6dc9357SAndroid Build Coastguard Worker const Byte * p = (const Byte *)buf + kNodeDescriptor_Size;
693*f6dc9357SAndroid Build Coastguard Worker // TreeDepth = Get16(p);
694*f6dc9357SAndroid Build Coastguard Worker // RootNode = Get32(p + 2);
695*f6dc9357SAndroid Build Coastguard Worker // LeafRecords = Get32(p + 6);
696*f6dc9357SAndroid Build Coastguard Worker FirstLeafNode = Get32(p + 0xA);
697*f6dc9357SAndroid Build Coastguard Worker // LastLeafNode = Get32(p + 0xE);
698*f6dc9357SAndroid Build Coastguard Worker const UInt32 nodeSize = Get16(p + 0x12);
699*f6dc9357SAndroid Build Coastguard Worker
700*f6dc9357SAndroid Build Coastguard Worker unsigned i;
701*f6dc9357SAndroid Build Coastguard Worker for (i = 9; ((UInt32)1 << i) != nodeSize; i++)
702*f6dc9357SAndroid Build Coastguard Worker if (i == 16)
703*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
704*f6dc9357SAndroid Build Coastguard Worker NodeSizeLog = i;
705*f6dc9357SAndroid Build Coastguard Worker
706*f6dc9357SAndroid Build Coastguard Worker // MaxKeyLength = Get16(p + 0x14);
707*f6dc9357SAndroid Build Coastguard Worker TotalNodes = Get32(p + 0x16);
708*f6dc9357SAndroid Build Coastguard Worker // FreeNodes = Get32(p + 0x1A);
709*f6dc9357SAndroid Build Coastguard Worker // Reserved1 = Get16(p + 0x1E);
710*f6dc9357SAndroid Build Coastguard Worker // ClumpSize = Get32(p + 0x20);
711*f6dc9357SAndroid Build Coastguard Worker // BtreeType = p[0x24];
712*f6dc9357SAndroid Build Coastguard Worker // KeyCompareType = p[0x25];
713*f6dc9357SAndroid Build Coastguard Worker // Attributes = Get32(p + 0x26);
714*f6dc9357SAndroid Build Coastguard Worker /*
715*f6dc9357SAndroid Build Coastguard Worker for (int i = 0; i < 16; i++)
716*f6dc9357SAndroid Build Coastguard Worker Reserved3[i] = Get32(p + 0x2A + i * 4);
717*f6dc9357SAndroid Build Coastguard Worker */
718*f6dc9357SAndroid Build Coastguard Worker
719*f6dc9357SAndroid Build Coastguard Worker if ((buf.Size() >> NodeSizeLog) < TotalNodes)
720*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
721*f6dc9357SAndroid Build Coastguard Worker
722*f6dc9357SAndroid Build Coastguard Worker return S_OK;
723*f6dc9357SAndroid Build Coastguard Worker }
724*f6dc9357SAndroid Build Coastguard Worker
725*f6dc9357SAndroid Build Coastguard Worker
726*f6dc9357SAndroid Build Coastguard Worker static const Byte kNodeType_Leaf = 0xFF;
727*f6dc9357SAndroid Build Coastguard Worker // static const Byte kNodeType_Index = 0;
728*f6dc9357SAndroid Build Coastguard Worker // static const Byte kNodeType_Header = 1;
729*f6dc9357SAndroid Build Coastguard Worker // static const Byte kNodeType_Mode = 2;
730*f6dc9357SAndroid Build Coastguard Worker
731*f6dc9357SAndroid Build Coastguard Worker static const Byte kExtentForkType_Data = 0;
732*f6dc9357SAndroid Build Coastguard Worker static const Byte kExtentForkType_Resource = 0xFF;
733*f6dc9357SAndroid Build Coastguard Worker
734*f6dc9357SAndroid Build Coastguard Worker /* It loads data extents from Extents Overflow File
735*f6dc9357SAndroid Build Coastguard Worker Most dmg installers are not fragmented. So there are no extents in Overflow File. */
736*f6dc9357SAndroid Build Coastguard Worker
LoadExtentFile(const CFork & fork,IInStream * inStream,CObjectVector<CIdExtents> * overflowExtentsArray)737*f6dc9357SAndroid Build Coastguard Worker HRESULT CDatabase::LoadExtentFile(const CFork &fork, IInStream *inStream, CObjectVector<CIdExtents> *overflowExtentsArray)
738*f6dc9357SAndroid Build Coastguard Worker {
739*f6dc9357SAndroid Build Coastguard Worker if (fork.NumBlocks == 0)
740*f6dc9357SAndroid Build Coastguard Worker return S_OK;
741*f6dc9357SAndroid Build Coastguard Worker CByteBuffer buf;
742*f6dc9357SAndroid Build Coastguard Worker RINOK(ReadFile(fork, buf, inStream))
743*f6dc9357SAndroid Build Coastguard Worker const Byte *p = (const Byte *)buf;
744*f6dc9357SAndroid Build Coastguard Worker
745*f6dc9357SAndroid Build Coastguard Worker // CNodeDescriptor nodeDesc;
746*f6dc9357SAndroid Build Coastguard Worker // nodeDesc.Parse(p);
747*f6dc9357SAndroid Build Coastguard Worker CHeaderRec hr;
748*f6dc9357SAndroid Build Coastguard Worker RINOK(hr.Parse2(buf))
749*f6dc9357SAndroid Build Coastguard Worker
750*f6dc9357SAndroid Build Coastguard Worker UInt32 node = hr.FirstLeafNode;
751*f6dc9357SAndroid Build Coastguard Worker if (node == 0)
752*f6dc9357SAndroid Build Coastguard Worker return S_OK;
753*f6dc9357SAndroid Build Coastguard Worker if (hr.TotalNodes == 0)
754*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
755*f6dc9357SAndroid Build Coastguard Worker
756*f6dc9357SAndroid Build Coastguard Worker CByteArr usedBuf(hr.TotalNodes);
757*f6dc9357SAndroid Build Coastguard Worker memset(usedBuf, 0, hr.TotalNodes);
758*f6dc9357SAndroid Build Coastguard Worker
759*f6dc9357SAndroid Build Coastguard Worker while (node != 0)
760*f6dc9357SAndroid Build Coastguard Worker {
761*f6dc9357SAndroid Build Coastguard Worker if (node >= hr.TotalNodes || usedBuf[node] != 0)
762*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
763*f6dc9357SAndroid Build Coastguard Worker usedBuf[node] = 1;
764*f6dc9357SAndroid Build Coastguard Worker
765*f6dc9357SAndroid Build Coastguard Worker const size_t nodeOffset = (size_t)node << hr.NodeSizeLog;
766*f6dc9357SAndroid Build Coastguard Worker CNodeDescriptor desc;
767*f6dc9357SAndroid Build Coastguard Worker if (!desc.Parse(p + nodeOffset, hr.NodeSizeLog))
768*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
769*f6dc9357SAndroid Build Coastguard Worker if (desc.Kind != kNodeType_Leaf)
770*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
771*f6dc9357SAndroid Build Coastguard Worker
772*f6dc9357SAndroid Build Coastguard Worker UInt32 endBlock = 0;
773*f6dc9357SAndroid Build Coastguard Worker
774*f6dc9357SAndroid Build Coastguard Worker for (unsigned i = 0; i < desc.NumRecords; i++)
775*f6dc9357SAndroid Build Coastguard Worker {
776*f6dc9357SAndroid Build Coastguard Worker const UInt32 nodeSize = ((UInt32)1 << hr.NodeSizeLog);
777*f6dc9357SAndroid Build Coastguard Worker const Byte *r = p + nodeOffset + nodeSize - i * 2;
778*f6dc9357SAndroid Build Coastguard Worker const UInt32 offs = Get16(r - 2);
779*f6dc9357SAndroid Build Coastguard Worker UInt32 recSize = Get16(r - 4) - offs;
780*f6dc9357SAndroid Build Coastguard Worker const unsigned kKeyLen = 10;
781*f6dc9357SAndroid Build Coastguard Worker
782*f6dc9357SAndroid Build Coastguard Worker if (recSize != 2 + kKeyLen + kNumFixedExtents * 8)
783*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
784*f6dc9357SAndroid Build Coastguard Worker
785*f6dc9357SAndroid Build Coastguard Worker r = p + nodeOffset + offs;
786*f6dc9357SAndroid Build Coastguard Worker if (Get16(r) != kKeyLen)
787*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
788*f6dc9357SAndroid Build Coastguard Worker
789*f6dc9357SAndroid Build Coastguard Worker const Byte forkType = r[2];
790*f6dc9357SAndroid Build Coastguard Worker unsigned forkTypeIndex;
791*f6dc9357SAndroid Build Coastguard Worker if (forkType == kExtentForkType_Data)
792*f6dc9357SAndroid Build Coastguard Worker forkTypeIndex = 0;
793*f6dc9357SAndroid Build Coastguard Worker else if (forkType == kExtentForkType_Resource)
794*f6dc9357SAndroid Build Coastguard Worker forkTypeIndex = 1;
795*f6dc9357SAndroid Build Coastguard Worker else
796*f6dc9357SAndroid Build Coastguard Worker continue;
797*f6dc9357SAndroid Build Coastguard Worker CObjectVector<CIdExtents> &overflowExtents = overflowExtentsArray[forkTypeIndex];
798*f6dc9357SAndroid Build Coastguard Worker
799*f6dc9357SAndroid Build Coastguard Worker const UInt32 id = Get32(r + 4);
800*f6dc9357SAndroid Build Coastguard Worker const UInt32 startBlock = Get32(r + 8);
801*f6dc9357SAndroid Build Coastguard Worker r += 2 + kKeyLen;
802*f6dc9357SAndroid Build Coastguard Worker
803*f6dc9357SAndroid Build Coastguard Worker bool needNew = true;
804*f6dc9357SAndroid Build Coastguard Worker
805*f6dc9357SAndroid Build Coastguard Worker if (overflowExtents.Size() != 0)
806*f6dc9357SAndroid Build Coastguard Worker {
807*f6dc9357SAndroid Build Coastguard Worker CIdExtents &e = overflowExtents.Back();
808*f6dc9357SAndroid Build Coastguard Worker if (e.ID == id)
809*f6dc9357SAndroid Build Coastguard Worker {
810*f6dc9357SAndroid Build Coastguard Worker if (endBlock != startBlock)
811*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
812*f6dc9357SAndroid Build Coastguard Worker needNew = false;
813*f6dc9357SAndroid Build Coastguard Worker }
814*f6dc9357SAndroid Build Coastguard Worker }
815*f6dc9357SAndroid Build Coastguard Worker
816*f6dc9357SAndroid Build Coastguard Worker if (needNew)
817*f6dc9357SAndroid Build Coastguard Worker {
818*f6dc9357SAndroid Build Coastguard Worker CIdExtents &e = overflowExtents.AddNew();
819*f6dc9357SAndroid Build Coastguard Worker e.ID = id;
820*f6dc9357SAndroid Build Coastguard Worker e.StartBlock = startBlock;
821*f6dc9357SAndroid Build Coastguard Worker endBlock = startBlock;
822*f6dc9357SAndroid Build Coastguard Worker }
823*f6dc9357SAndroid Build Coastguard Worker
824*f6dc9357SAndroid Build Coastguard Worker CIdExtents &e = overflowExtents.Back();
825*f6dc9357SAndroid Build Coastguard Worker
826*f6dc9357SAndroid Build Coastguard Worker for (unsigned k = 0; k < kNumFixedExtents; k++, r += 8)
827*f6dc9357SAndroid Build Coastguard Worker {
828*f6dc9357SAndroid Build Coastguard Worker CExtent ee;
829*f6dc9357SAndroid Build Coastguard Worker ee.Pos = Get32(r);
830*f6dc9357SAndroid Build Coastguard Worker ee.NumBlocks = Get32(r + 4);
831*f6dc9357SAndroid Build Coastguard Worker if (ee.NumBlocks != 0)
832*f6dc9357SAndroid Build Coastguard Worker {
833*f6dc9357SAndroid Build Coastguard Worker e.Extents.Add(ee);
834*f6dc9357SAndroid Build Coastguard Worker endBlock += ee.NumBlocks;
835*f6dc9357SAndroid Build Coastguard Worker }
836*f6dc9357SAndroid Build Coastguard Worker }
837*f6dc9357SAndroid Build Coastguard Worker }
838*f6dc9357SAndroid Build Coastguard Worker
839*f6dc9357SAndroid Build Coastguard Worker node = desc.fLink;
840*f6dc9357SAndroid Build Coastguard Worker }
841*f6dc9357SAndroid Build Coastguard Worker return S_OK;
842*f6dc9357SAndroid Build Coastguard Worker }
843*f6dc9357SAndroid Build Coastguard Worker
LoadName(const Byte * data,unsigned len,UString & dest)844*f6dc9357SAndroid Build Coastguard Worker static void LoadName(const Byte *data, unsigned len, UString &dest)
845*f6dc9357SAndroid Build Coastguard Worker {
846*f6dc9357SAndroid Build Coastguard Worker wchar_t *p = dest.GetBuf(len);
847*f6dc9357SAndroid Build Coastguard Worker unsigned i;
848*f6dc9357SAndroid Build Coastguard Worker for (i = 0; i < len; i++)
849*f6dc9357SAndroid Build Coastguard Worker {
850*f6dc9357SAndroid Build Coastguard Worker const wchar_t c = Get16(data + i * 2);
851*f6dc9357SAndroid Build Coastguard Worker if (c == 0)
852*f6dc9357SAndroid Build Coastguard Worker break;
853*f6dc9357SAndroid Build Coastguard Worker p[i] = c;
854*f6dc9357SAndroid Build Coastguard Worker }
855*f6dc9357SAndroid Build Coastguard Worker p[i] = 0;
856*f6dc9357SAndroid Build Coastguard Worker dest.ReleaseBuf_SetLen(i);
857*f6dc9357SAndroid Build Coastguard Worker }
858*f6dc9357SAndroid Build Coastguard Worker
IsNameEqualTo(const Byte * data,const char * name)859*f6dc9357SAndroid Build Coastguard Worker static bool IsNameEqualTo(const Byte *data, const char *name)
860*f6dc9357SAndroid Build Coastguard Worker {
861*f6dc9357SAndroid Build Coastguard Worker for (unsigned i = 0;; i++)
862*f6dc9357SAndroid Build Coastguard Worker {
863*f6dc9357SAndroid Build Coastguard Worker const char c = name[i];
864*f6dc9357SAndroid Build Coastguard Worker if (c == 0)
865*f6dc9357SAndroid Build Coastguard Worker return true;
866*f6dc9357SAndroid Build Coastguard Worker if (Get16(data + i * 2) != (Byte)c)
867*f6dc9357SAndroid Build Coastguard Worker return false;
868*f6dc9357SAndroid Build Coastguard Worker }
869*f6dc9357SAndroid Build Coastguard Worker }
870*f6dc9357SAndroid Build Coastguard Worker
871*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kAttrRecordType_Inline = 0x10;
872*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kAttrRecordType_Fork = 0x20;
873*f6dc9357SAndroid Build Coastguard Worker // static const UInt32 kAttrRecordType_Extents = 0x30;
874*f6dc9357SAndroid Build Coastguard Worker
LoadAttrs(const CFork & fork,IInStream * inStream,IArchiveOpenCallback * progress)875*f6dc9357SAndroid Build Coastguard Worker HRESULT CDatabase::LoadAttrs(const CFork &fork, IInStream *inStream, IArchiveOpenCallback *progress)
876*f6dc9357SAndroid Build Coastguard Worker {
877*f6dc9357SAndroid Build Coastguard Worker if (fork.NumBlocks == 0)
878*f6dc9357SAndroid Build Coastguard Worker return S_OK;
879*f6dc9357SAndroid Build Coastguard Worker
880*f6dc9357SAndroid Build Coastguard Worker CByteBuffer AttrBuf;
881*f6dc9357SAndroid Build Coastguard Worker RINOK(ReadFile(fork, AttrBuf, inStream))
882*f6dc9357SAndroid Build Coastguard Worker const Byte *p = (const Byte *)AttrBuf;
883*f6dc9357SAndroid Build Coastguard Worker
884*f6dc9357SAndroid Build Coastguard Worker // CNodeDescriptor nodeDesc;
885*f6dc9357SAndroid Build Coastguard Worker // nodeDesc.Parse(p);
886*f6dc9357SAndroid Build Coastguard Worker CHeaderRec hr;
887*f6dc9357SAndroid Build Coastguard Worker RINOK(hr.Parse2(AttrBuf))
888*f6dc9357SAndroid Build Coastguard Worker
889*f6dc9357SAndroid Build Coastguard Worker // CaseSensetive = (Header.IsHfsX() && hr.KeyCompareType == 0xBC);
890*f6dc9357SAndroid Build Coastguard Worker
891*f6dc9357SAndroid Build Coastguard Worker UInt32 node = hr.FirstLeafNode;
892*f6dc9357SAndroid Build Coastguard Worker if (node == 0)
893*f6dc9357SAndroid Build Coastguard Worker return S_OK;
894*f6dc9357SAndroid Build Coastguard Worker if (hr.TotalNodes == 0)
895*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
896*f6dc9357SAndroid Build Coastguard Worker
897*f6dc9357SAndroid Build Coastguard Worker CByteArr usedBuf(hr.TotalNodes);
898*f6dc9357SAndroid Build Coastguard Worker memset(usedBuf, 0, hr.TotalNodes);
899*f6dc9357SAndroid Build Coastguard Worker
900*f6dc9357SAndroid Build Coastguard Worker CFork resFork;
901*f6dc9357SAndroid Build Coastguard Worker
902*f6dc9357SAndroid Build Coastguard Worker while (node != 0)
903*f6dc9357SAndroid Build Coastguard Worker {
904*f6dc9357SAndroid Build Coastguard Worker if (node >= hr.TotalNodes || usedBuf[node] != 0)
905*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
906*f6dc9357SAndroid Build Coastguard Worker usedBuf[node] = 1;
907*f6dc9357SAndroid Build Coastguard Worker
908*f6dc9357SAndroid Build Coastguard Worker const size_t nodeOffset = (size_t)node << hr.NodeSizeLog;
909*f6dc9357SAndroid Build Coastguard Worker CNodeDescriptor desc;
910*f6dc9357SAndroid Build Coastguard Worker if (!desc.Parse(p + nodeOffset, hr.NodeSizeLog))
911*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
912*f6dc9357SAndroid Build Coastguard Worker if (desc.Kind != kNodeType_Leaf)
913*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
914*f6dc9357SAndroid Build Coastguard Worker
915*f6dc9357SAndroid Build Coastguard Worker for (unsigned i = 0; i < desc.NumRecords; i++)
916*f6dc9357SAndroid Build Coastguard Worker {
917*f6dc9357SAndroid Build Coastguard Worker const UInt32 nodeSize = ((UInt32)1 << hr.NodeSizeLog);
918*f6dc9357SAndroid Build Coastguard Worker const Byte *r = p + nodeOffset + nodeSize - i * 2;
919*f6dc9357SAndroid Build Coastguard Worker const UInt32 offs = Get16(r - 2);
920*f6dc9357SAndroid Build Coastguard Worker UInt32 recSize = Get16(r - 4) - offs;
921*f6dc9357SAndroid Build Coastguard Worker const unsigned kHeadSize = 14;
922*f6dc9357SAndroid Build Coastguard Worker if (recSize < kHeadSize)
923*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
924*f6dc9357SAndroid Build Coastguard Worker
925*f6dc9357SAndroid Build Coastguard Worker r = p + nodeOffset + offs;
926*f6dc9357SAndroid Build Coastguard Worker const UInt32 keyLen = Get16(r);
927*f6dc9357SAndroid Build Coastguard Worker
928*f6dc9357SAndroid Build Coastguard Worker // UInt16 pad = Get16(r + 2);
929*f6dc9357SAndroid Build Coastguard Worker const UInt32 fileID = Get32(r + 4);
930*f6dc9357SAndroid Build Coastguard Worker const unsigned startBlock = Get32(r + 8);
931*f6dc9357SAndroid Build Coastguard Worker if (startBlock != 0)
932*f6dc9357SAndroid Build Coastguard Worker {
933*f6dc9357SAndroid Build Coastguard Worker // that case is still unsupported
934*f6dc9357SAndroid Build Coastguard Worker UnsupportedFeature = true;
935*f6dc9357SAndroid Build Coastguard Worker continue;
936*f6dc9357SAndroid Build Coastguard Worker }
937*f6dc9357SAndroid Build Coastguard Worker const unsigned nameLen = Get16(r + 12);
938*f6dc9357SAndroid Build Coastguard Worker
939*f6dc9357SAndroid Build Coastguard Worker if (keyLen + 2 > recSize ||
940*f6dc9357SAndroid Build Coastguard Worker keyLen != kHeadSize - 2 + nameLen * 2)
941*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
942*f6dc9357SAndroid Build Coastguard Worker r += kHeadSize;
943*f6dc9357SAndroid Build Coastguard Worker recSize -= kHeadSize;
944*f6dc9357SAndroid Build Coastguard Worker
945*f6dc9357SAndroid Build Coastguard Worker const Byte *name = r;
946*f6dc9357SAndroid Build Coastguard Worker r += nameLen * 2;
947*f6dc9357SAndroid Build Coastguard Worker recSize -= nameLen * 2;
948*f6dc9357SAndroid Build Coastguard Worker
949*f6dc9357SAndroid Build Coastguard Worker if (recSize < 4)
950*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
951*f6dc9357SAndroid Build Coastguard Worker
952*f6dc9357SAndroid Build Coastguard Worker const UInt32 recordType = Get32(r);
953*f6dc9357SAndroid Build Coastguard Worker
954*f6dc9357SAndroid Build Coastguard Worker if (progress && (Attrs.Size() & 0xFFF) == 0)
955*f6dc9357SAndroid Build Coastguard Worker {
956*f6dc9357SAndroid Build Coastguard Worker const UInt64 numFiles = 0;
957*f6dc9357SAndroid Build Coastguard Worker RINOK(progress->SetCompleted(&numFiles, NULL))
958*f6dc9357SAndroid Build Coastguard Worker }
959*f6dc9357SAndroid Build Coastguard Worker
960*f6dc9357SAndroid Build Coastguard Worker if (Attrs.Size() >= ((UInt32)1 << 31))
961*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
962*f6dc9357SAndroid Build Coastguard Worker
963*f6dc9357SAndroid Build Coastguard Worker CAttr &attr = Attrs.AddNew();
964*f6dc9357SAndroid Build Coastguard Worker attr.ID = fileID;
965*f6dc9357SAndroid Build Coastguard Worker LoadName(name, nameLen, attr.Name);
966*f6dc9357SAndroid Build Coastguard Worker
967*f6dc9357SAndroid Build Coastguard Worker if (recordType == kAttrRecordType_Fork)
968*f6dc9357SAndroid Build Coastguard Worker {
969*f6dc9357SAndroid Build Coastguard Worker // 22.00 : some hfs files contain it;
970*f6dc9357SAndroid Build Coastguard Worker /* spec: If the attribute has more than 8 extents, there will be additional
971*f6dc9357SAndroid Build Coastguard Worker records (of type kAttrRecordType_Extents) for this attribute. */
972*f6dc9357SAndroid Build Coastguard Worker if (recSize != 8 + kForkRecSize)
973*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
974*f6dc9357SAndroid Build Coastguard Worker if (Get32(r + 4) != 0) // reserved
975*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
976*f6dc9357SAndroid Build Coastguard Worker attr.Fork.Parse(r + 8);
977*f6dc9357SAndroid Build Coastguard Worker attr.Fork_defined = true;
978*f6dc9357SAndroid Build Coastguard Worker continue;
979*f6dc9357SAndroid Build Coastguard Worker }
980*f6dc9357SAndroid Build Coastguard Worker else if (recordType != kAttrRecordType_Inline)
981*f6dc9357SAndroid Build Coastguard Worker {
982*f6dc9357SAndroid Build Coastguard Worker UnsupportedFeature = true;
983*f6dc9357SAndroid Build Coastguard Worker continue;
984*f6dc9357SAndroid Build Coastguard Worker }
985*f6dc9357SAndroid Build Coastguard Worker
986*f6dc9357SAndroid Build Coastguard Worker const unsigned kRecordHeaderSize = 16;
987*f6dc9357SAndroid Build Coastguard Worker if (recSize < kRecordHeaderSize)
988*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
989*f6dc9357SAndroid Build Coastguard Worker if (Get32(r + 4) != 0 || Get32(r + 8) != 0) // reserved
990*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
991*f6dc9357SAndroid Build Coastguard Worker const UInt32 dataSize = Get32(r + 12);
992*f6dc9357SAndroid Build Coastguard Worker
993*f6dc9357SAndroid Build Coastguard Worker r += kRecordHeaderSize;
994*f6dc9357SAndroid Build Coastguard Worker recSize -= kRecordHeaderSize;
995*f6dc9357SAndroid Build Coastguard Worker
996*f6dc9357SAndroid Build Coastguard Worker if (recSize < dataSize)
997*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
998*f6dc9357SAndroid Build Coastguard Worker
999*f6dc9357SAndroid Build Coastguard Worker attr.Data.CopyFrom(r, dataSize);
1000*f6dc9357SAndroid Build Coastguard Worker // attr.DataPos = nodeOffset + offs + 2 + keyLen + kRecordHeaderSize;
1001*f6dc9357SAndroid Build Coastguard Worker // attr.Size = dataSize;
1002*f6dc9357SAndroid Build Coastguard Worker }
1003*f6dc9357SAndroid Build Coastguard Worker
1004*f6dc9357SAndroid Build Coastguard Worker node = desc.fLink;
1005*f6dc9357SAndroid Build Coastguard Worker }
1006*f6dc9357SAndroid Build Coastguard Worker return S_OK;
1007*f6dc9357SAndroid Build Coastguard Worker }
1008*f6dc9357SAndroid Build Coastguard Worker
1009*f6dc9357SAndroid Build Coastguard Worker
Parse_decmpgfs(unsigned attrIndex,CItem & item,bool & skip)1010*f6dc9357SAndroid Build Coastguard Worker bool CDatabase::Parse_decmpgfs(unsigned attrIndex, CItem &item, bool &skip)
1011*f6dc9357SAndroid Build Coastguard Worker {
1012*f6dc9357SAndroid Build Coastguard Worker const CAttr &attr = Attrs[attrIndex];
1013*f6dc9357SAndroid Build Coastguard Worker skip = false;
1014*f6dc9357SAndroid Build Coastguard Worker if (item.CompressHeader.IsCorrect || !item.DataFork.IsEmpty())
1015*f6dc9357SAndroid Build Coastguard Worker return false;
1016*f6dc9357SAndroid Build Coastguard Worker
1017*f6dc9357SAndroid Build Coastguard Worker item.CompressHeader.Parse(attr.Data, attr.Data.Size());
1018*f6dc9357SAndroid Build Coastguard Worker
1019*f6dc9357SAndroid Build Coastguard Worker if (item.CompressHeader.IsCorrect)
1020*f6dc9357SAndroid Build Coastguard Worker {
1021*f6dc9357SAndroid Build Coastguard Worker item.decmpfs_AttrIndex = (int)attrIndex;
1022*f6dc9357SAndroid Build Coastguard Worker skip = true;
1023*f6dc9357SAndroid Build Coastguard Worker if (item.CompressHeader.Method < sizeof(MethodsMask) * 8)
1024*f6dc9357SAndroid Build Coastguard Worker MethodsMask |= ((UInt32)1 << item.CompressHeader.Method);
1025*f6dc9357SAndroid Build Coastguard Worker }
1026*f6dc9357SAndroid Build Coastguard Worker
1027*f6dc9357SAndroid Build Coastguard Worker return true;
1028*f6dc9357SAndroid Build Coastguard Worker }
1029*f6dc9357SAndroid Build Coastguard Worker
1030*f6dc9357SAndroid Build Coastguard Worker
LoadCatalog(const CFork & fork,const CObjectVector<CIdExtents> * overflowExtentsArray,IInStream * inStream,IArchiveOpenCallback * progress)1031*f6dc9357SAndroid Build Coastguard Worker HRESULT CDatabase::LoadCatalog(const CFork &fork, const CObjectVector<CIdExtents> *overflowExtentsArray, IInStream *inStream, IArchiveOpenCallback *progress)
1032*f6dc9357SAndroid Build Coastguard Worker {
1033*f6dc9357SAndroid Build Coastguard Worker CByteBuffer buf;
1034*f6dc9357SAndroid Build Coastguard Worker RINOK(ReadFile(fork, buf, inStream))
1035*f6dc9357SAndroid Build Coastguard Worker const Byte *p = (const Byte *)buf;
1036*f6dc9357SAndroid Build Coastguard Worker
1037*f6dc9357SAndroid Build Coastguard Worker // CNodeDescriptor nodeDesc;
1038*f6dc9357SAndroid Build Coastguard Worker // nodeDesc.Parse(p);
1039*f6dc9357SAndroid Build Coastguard Worker CHeaderRec hr;
1040*f6dc9357SAndroid Build Coastguard Worker RINOK(hr.Parse2(buf))
1041*f6dc9357SAndroid Build Coastguard Worker
1042*f6dc9357SAndroid Build Coastguard Worker CRecordVector<CIdIndexPair> IdToIndexMap;
1043*f6dc9357SAndroid Build Coastguard Worker
1044*f6dc9357SAndroid Build Coastguard Worker const unsigned reserveSize = (unsigned)(Header.NumFolders + 1 + Header.NumFiles);
1045*f6dc9357SAndroid Build Coastguard Worker
1046*f6dc9357SAndroid Build Coastguard Worker const unsigned kBasicRecSize = 0x58;
1047*f6dc9357SAndroid Build Coastguard Worker const unsigned kMinRecSize = kBasicRecSize + 10;
1048*f6dc9357SAndroid Build Coastguard Worker
1049*f6dc9357SAndroid Build Coastguard Worker if ((UInt64)reserveSize * kMinRecSize < buf.Size())
1050*f6dc9357SAndroid Build Coastguard Worker {
1051*f6dc9357SAndroid Build Coastguard Worker Items.ClearAndReserve(reserveSize);
1052*f6dc9357SAndroid Build Coastguard Worker Refs.ClearAndReserve(reserveSize);
1053*f6dc9357SAndroid Build Coastguard Worker IdToIndexMap.ClearAndReserve(reserveSize);
1054*f6dc9357SAndroid Build Coastguard Worker }
1055*f6dc9357SAndroid Build Coastguard Worker
1056*f6dc9357SAndroid Build Coastguard Worker // CaseSensetive = (Header.IsHfsX() && hr.KeyCompareType == 0xBC);
1057*f6dc9357SAndroid Build Coastguard Worker
1058*f6dc9357SAndroid Build Coastguard Worker CByteArr usedBuf(hr.TotalNodes);
1059*f6dc9357SAndroid Build Coastguard Worker if (hr.TotalNodes != 0)
1060*f6dc9357SAndroid Build Coastguard Worker memset(usedBuf, 0, hr.TotalNodes);
1061*f6dc9357SAndroid Build Coastguard Worker
1062*f6dc9357SAndroid Build Coastguard Worker CFork resFork;
1063*f6dc9357SAndroid Build Coastguard Worker
1064*f6dc9357SAndroid Build Coastguard Worker UInt32 node = hr.FirstLeafNode;
1065*f6dc9357SAndroid Build Coastguard Worker UInt32 numFiles = 0;
1066*f6dc9357SAndroid Build Coastguard Worker UInt32 numFolders = 0;
1067*f6dc9357SAndroid Build Coastguard Worker
1068*f6dc9357SAndroid Build Coastguard Worker while (node != 0)
1069*f6dc9357SAndroid Build Coastguard Worker {
1070*f6dc9357SAndroid Build Coastguard Worker if (node >= hr.TotalNodes || usedBuf[node] != 0)
1071*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1072*f6dc9357SAndroid Build Coastguard Worker usedBuf[node] = 1;
1073*f6dc9357SAndroid Build Coastguard Worker
1074*f6dc9357SAndroid Build Coastguard Worker const size_t nodeOffset = (size_t)node << hr.NodeSizeLog;
1075*f6dc9357SAndroid Build Coastguard Worker CNodeDescriptor desc;
1076*f6dc9357SAndroid Build Coastguard Worker if (!desc.Parse(p + nodeOffset, hr.NodeSizeLog))
1077*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1078*f6dc9357SAndroid Build Coastguard Worker if (desc.Kind != kNodeType_Leaf)
1079*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1080*f6dc9357SAndroid Build Coastguard Worker
1081*f6dc9357SAndroid Build Coastguard Worker for (unsigned i = 0; i < desc.NumRecords; i++)
1082*f6dc9357SAndroid Build Coastguard Worker {
1083*f6dc9357SAndroid Build Coastguard Worker const UInt32 nodeSize = (1 << hr.NodeSizeLog);
1084*f6dc9357SAndroid Build Coastguard Worker const Byte *r = p + nodeOffset + nodeSize - i * 2;
1085*f6dc9357SAndroid Build Coastguard Worker const UInt32 offs = Get16(r - 2);
1086*f6dc9357SAndroid Build Coastguard Worker UInt32 recSize = Get16(r - 4) - offs;
1087*f6dc9357SAndroid Build Coastguard Worker if (recSize < 6)
1088*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1089*f6dc9357SAndroid Build Coastguard Worker
1090*f6dc9357SAndroid Build Coastguard Worker r = p + nodeOffset + offs;
1091*f6dc9357SAndroid Build Coastguard Worker UInt32 keyLen = Get16(r);
1092*f6dc9357SAndroid Build Coastguard Worker UInt32 parentID = Get32(r + 2);
1093*f6dc9357SAndroid Build Coastguard Worker if (keyLen < 6 || (keyLen & 1) != 0 || keyLen + 2 > recSize)
1094*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1095*f6dc9357SAndroid Build Coastguard Worker r += 6;
1096*f6dc9357SAndroid Build Coastguard Worker recSize -= 6;
1097*f6dc9357SAndroid Build Coastguard Worker keyLen -= 6;
1098*f6dc9357SAndroid Build Coastguard Worker
1099*f6dc9357SAndroid Build Coastguard Worker unsigned nameLen = Get16(r);
1100*f6dc9357SAndroid Build Coastguard Worker if (nameLen * 2 != (unsigned)keyLen)
1101*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1102*f6dc9357SAndroid Build Coastguard Worker r += 2;
1103*f6dc9357SAndroid Build Coastguard Worker recSize -= 2;
1104*f6dc9357SAndroid Build Coastguard Worker
1105*f6dc9357SAndroid Build Coastguard Worker r += nameLen * 2;
1106*f6dc9357SAndroid Build Coastguard Worker recSize -= nameLen * 2;
1107*f6dc9357SAndroid Build Coastguard Worker
1108*f6dc9357SAndroid Build Coastguard Worker if (recSize < 2)
1109*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1110*f6dc9357SAndroid Build Coastguard Worker UInt16 type = Get16(r);
1111*f6dc9357SAndroid Build Coastguard Worker
1112*f6dc9357SAndroid Build Coastguard Worker if (type != RECORD_TYPE_FOLDER &&
1113*f6dc9357SAndroid Build Coastguard Worker type != RECORD_TYPE_FILE)
1114*f6dc9357SAndroid Build Coastguard Worker continue;
1115*f6dc9357SAndroid Build Coastguard Worker
1116*f6dc9357SAndroid Build Coastguard Worker if (recSize < kBasicRecSize)
1117*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1118*f6dc9357SAndroid Build Coastguard Worker
1119*f6dc9357SAndroid Build Coastguard Worker CItem &item = Items.AddNew();
1120*f6dc9357SAndroid Build Coastguard Worker item.ParentID = parentID;
1121*f6dc9357SAndroid Build Coastguard Worker item.Type = type;
1122*f6dc9357SAndroid Build Coastguard Worker // item.Flags = Get16(r + 2);
1123*f6dc9357SAndroid Build Coastguard Worker // item.Valence = Get32(r + 4);
1124*f6dc9357SAndroid Build Coastguard Worker item.ID = Get32(r + 8);
1125*f6dc9357SAndroid Build Coastguard Worker {
1126*f6dc9357SAndroid Build Coastguard Worker const Byte *name = r - (nameLen * 2);
1127*f6dc9357SAndroid Build Coastguard Worker LoadName(name, nameLen, item.Name);
1128*f6dc9357SAndroid Build Coastguard Worker if (item.Name.Len() <= 1)
1129*f6dc9357SAndroid Build Coastguard Worker {
1130*f6dc9357SAndroid Build Coastguard Worker if (item.Name.IsEmpty() && nameLen == 21)
1131*f6dc9357SAndroid Build Coastguard Worker {
1132*f6dc9357SAndroid Build Coastguard Worker if (GetUi32(name) == 0 &&
1133*f6dc9357SAndroid Build Coastguard Worker GetUi32(name + 4) == 0 &&
1134*f6dc9357SAndroid Build Coastguard Worker IsNameEqualTo(name + 8, "HFS+ Private Data"))
1135*f6dc9357SAndroid Build Coastguard Worker {
1136*f6dc9357SAndroid Build Coastguard Worker // it's folder for "Hard Links" files
1137*f6dc9357SAndroid Build Coastguard Worker item.Name = "[HFS+ Private Data]";
1138*f6dc9357SAndroid Build Coastguard Worker }
1139*f6dc9357SAndroid Build Coastguard Worker }
1140*f6dc9357SAndroid Build Coastguard Worker
1141*f6dc9357SAndroid Build Coastguard Worker // Some dmg files have ' ' folder item.
1142*f6dc9357SAndroid Build Coastguard Worker if (item.Name.IsEmpty() || item.Name[0] == L' ')
1143*f6dc9357SAndroid Build Coastguard Worker item.Name = "[]";
1144*f6dc9357SAndroid Build Coastguard Worker }
1145*f6dc9357SAndroid Build Coastguard Worker }
1146*f6dc9357SAndroid Build Coastguard Worker
1147*f6dc9357SAndroid Build Coastguard Worker item.CTime = Get32(r + 0xC);
1148*f6dc9357SAndroid Build Coastguard Worker item.MTime = Get32(r + 0x10);
1149*f6dc9357SAndroid Build Coastguard Worker item.AttrMTime = Get32(r + 0x14);
1150*f6dc9357SAndroid Build Coastguard Worker item.ATime = Get32(r + 0x18);
1151*f6dc9357SAndroid Build Coastguard Worker // item.BackupDate = Get32(r + 0x1C);
1152*f6dc9357SAndroid Build Coastguard Worker
1153*f6dc9357SAndroid Build Coastguard Worker /*
1154*f6dc9357SAndroid Build Coastguard Worker item.OwnerID = Get32(r + 0x20);
1155*f6dc9357SAndroid Build Coastguard Worker item.GroupID = Get32(r + 0x24);
1156*f6dc9357SAndroid Build Coastguard Worker item.AdminFlags = r[0x28];
1157*f6dc9357SAndroid Build Coastguard Worker item.OwnerFlags = r[0x29];
1158*f6dc9357SAndroid Build Coastguard Worker */
1159*f6dc9357SAndroid Build Coastguard Worker item.FileMode = Get16(r + 0x2A);
1160*f6dc9357SAndroid Build Coastguard Worker /*
1161*f6dc9357SAndroid Build Coastguard Worker item.special.iNodeNum = Get16(r + 0x2C); // or .linkCount
1162*f6dc9357SAndroid Build Coastguard Worker item.FileType = Get32(r + 0x30);
1163*f6dc9357SAndroid Build Coastguard Worker item.FileCreator = Get32(r + 0x34);
1164*f6dc9357SAndroid Build Coastguard Worker item.FinderFlags = Get16(r + 0x38);
1165*f6dc9357SAndroid Build Coastguard Worker item.Point[0] = Get16(r + 0x3A); // v
1166*f6dc9357SAndroid Build Coastguard Worker item.Point[1] = Get16(r + 0x3C); // h
1167*f6dc9357SAndroid Build Coastguard Worker */
1168*f6dc9357SAndroid Build Coastguard Worker
1169*f6dc9357SAndroid Build Coastguard Worker // const refIndex = Refs.Size();
1170*f6dc9357SAndroid Build Coastguard Worker CIdIndexPair pair;
1171*f6dc9357SAndroid Build Coastguard Worker pair.ID = item.ID;
1172*f6dc9357SAndroid Build Coastguard Worker pair.Index = Items.Size() - 1;
1173*f6dc9357SAndroid Build Coastguard Worker IdToIndexMap.Add(pair);
1174*f6dc9357SAndroid Build Coastguard Worker
1175*f6dc9357SAndroid Build Coastguard Worker recSize -= kBasicRecSize;
1176*f6dc9357SAndroid Build Coastguard Worker r += kBasicRecSize;
1177*f6dc9357SAndroid Build Coastguard Worker if (item.IsDir())
1178*f6dc9357SAndroid Build Coastguard Worker {
1179*f6dc9357SAndroid Build Coastguard Worker numFolders++;
1180*f6dc9357SAndroid Build Coastguard Worker if (recSize != 0)
1181*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1182*f6dc9357SAndroid Build Coastguard Worker }
1183*f6dc9357SAndroid Build Coastguard Worker else
1184*f6dc9357SAndroid Build Coastguard Worker {
1185*f6dc9357SAndroid Build Coastguard Worker numFiles++;
1186*f6dc9357SAndroid Build Coastguard Worker if (recSize != kForkRecSize * 2)
1187*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1188*f6dc9357SAndroid Build Coastguard Worker
1189*f6dc9357SAndroid Build Coastguard Worker item.DataFork.Parse(r);
1190*f6dc9357SAndroid Build Coastguard Worker
1191*f6dc9357SAndroid Build Coastguard Worker if (!item.DataFork.UpgradeAndTest(overflowExtentsArray[0], item.ID, Header.BlockSizeLog))
1192*f6dc9357SAndroid Build Coastguard Worker HeadersError = true;
1193*f6dc9357SAndroid Build Coastguard Worker
1194*f6dc9357SAndroid Build Coastguard Worker item.ResourceFork.Parse(r + kForkRecSize);
1195*f6dc9357SAndroid Build Coastguard Worker if (!item.ResourceFork.IsEmpty())
1196*f6dc9357SAndroid Build Coastguard Worker {
1197*f6dc9357SAndroid Build Coastguard Worker if (!item.ResourceFork.UpgradeAndTest(overflowExtentsArray[1], item.ID, Header.BlockSizeLog))
1198*f6dc9357SAndroid Build Coastguard Worker HeadersError = true;
1199*f6dc9357SAndroid Build Coastguard Worker // ThereAreAltStreams = true;
1200*f6dc9357SAndroid Build Coastguard Worker }
1201*f6dc9357SAndroid Build Coastguard Worker }
1202*f6dc9357SAndroid Build Coastguard Worker if (progress && (Items.Size() & 0xFFF) == 0)
1203*f6dc9357SAndroid Build Coastguard Worker {
1204*f6dc9357SAndroid Build Coastguard Worker const UInt64 numItems = Items.Size();
1205*f6dc9357SAndroid Build Coastguard Worker RINOK(progress->SetCompleted(&numItems, NULL))
1206*f6dc9357SAndroid Build Coastguard Worker }
1207*f6dc9357SAndroid Build Coastguard Worker }
1208*f6dc9357SAndroid Build Coastguard Worker node = desc.fLink;
1209*f6dc9357SAndroid Build Coastguard Worker }
1210*f6dc9357SAndroid Build Coastguard Worker
1211*f6dc9357SAndroid Build Coastguard Worker if (Header.NumFiles != numFiles ||
1212*f6dc9357SAndroid Build Coastguard Worker Header.NumFolders + 1 != numFolders)
1213*f6dc9357SAndroid Build Coastguard Worker HeadersError = true;
1214*f6dc9357SAndroid Build Coastguard Worker
1215*f6dc9357SAndroid Build Coastguard Worker IdToIndexMap.Sort2();
1216*f6dc9357SAndroid Build Coastguard Worker {
1217*f6dc9357SAndroid Build Coastguard Worker for (unsigned i = 1; i < IdToIndexMap.Size(); i++)
1218*f6dc9357SAndroid Build Coastguard Worker if (IdToIndexMap[i - 1].ID == IdToIndexMap[i].ID)
1219*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1220*f6dc9357SAndroid Build Coastguard Worker }
1221*f6dc9357SAndroid Build Coastguard Worker
1222*f6dc9357SAndroid Build Coastguard Worker
1223*f6dc9357SAndroid Build Coastguard Worker CBoolArr skipAttr(Attrs.Size());
1224*f6dc9357SAndroid Build Coastguard Worker {
1225*f6dc9357SAndroid Build Coastguard Worker for (unsigned i = 0; i < Attrs.Size(); i++)
1226*f6dc9357SAndroid Build Coastguard Worker skipAttr[i] = false;
1227*f6dc9357SAndroid Build Coastguard Worker }
1228*f6dc9357SAndroid Build Coastguard Worker
1229*f6dc9357SAndroid Build Coastguard Worker {
1230*f6dc9357SAndroid Build Coastguard Worker FOR_VECTOR (i, Attrs)
1231*f6dc9357SAndroid Build Coastguard Worker {
1232*f6dc9357SAndroid Build Coastguard Worker const CAttr &attr = Attrs[i];
1233*f6dc9357SAndroid Build Coastguard Worker
1234*f6dc9357SAndroid Build Coastguard Worker const int itemIndex = FindItemIndex(IdToIndexMap, attr.ID);
1235*f6dc9357SAndroid Build Coastguard Worker if (itemIndex < 0)
1236*f6dc9357SAndroid Build Coastguard Worker {
1237*f6dc9357SAndroid Build Coastguard Worker HeadersError = true;
1238*f6dc9357SAndroid Build Coastguard Worker continue;
1239*f6dc9357SAndroid Build Coastguard Worker }
1240*f6dc9357SAndroid Build Coastguard Worker
1241*f6dc9357SAndroid Build Coastguard Worker if (attr.Name.IsEqualTo("com.apple.decmpfs"))
1242*f6dc9357SAndroid Build Coastguard Worker {
1243*f6dc9357SAndroid Build Coastguard Worker if (!Parse_decmpgfs(i, Items[itemIndex], skipAttr[i]))
1244*f6dc9357SAndroid Build Coastguard Worker HeadersError = true;
1245*f6dc9357SAndroid Build Coastguard Worker }
1246*f6dc9357SAndroid Build Coastguard Worker }
1247*f6dc9357SAndroid Build Coastguard Worker }
1248*f6dc9357SAndroid Build Coastguard Worker
1249*f6dc9357SAndroid Build Coastguard Worker IdToIndexMap.ClearAndReserve(Items.Size());
1250*f6dc9357SAndroid Build Coastguard Worker
1251*f6dc9357SAndroid Build Coastguard Worker {
1252*f6dc9357SAndroid Build Coastguard Worker FOR_VECTOR (i, Items)
1253*f6dc9357SAndroid Build Coastguard Worker {
1254*f6dc9357SAndroid Build Coastguard Worker const CItem &item = Items[i];
1255*f6dc9357SAndroid Build Coastguard Worker
1256*f6dc9357SAndroid Build Coastguard Worker CIdIndexPair pair;
1257*f6dc9357SAndroid Build Coastguard Worker pair.ID = item.ID;
1258*f6dc9357SAndroid Build Coastguard Worker pair.Index = Refs.Size();
1259*f6dc9357SAndroid Build Coastguard Worker IdToIndexMap.Add(pair);
1260*f6dc9357SAndroid Build Coastguard Worker
1261*f6dc9357SAndroid Build Coastguard Worker CRef ref;
1262*f6dc9357SAndroid Build Coastguard Worker ref.ItemIndex = i;
1263*f6dc9357SAndroid Build Coastguard Worker Refs.Add(ref);
1264*f6dc9357SAndroid Build Coastguard Worker
1265*f6dc9357SAndroid Build Coastguard Worker #ifdef HFS_SHOW_ALT_STREAMS
1266*f6dc9357SAndroid Build Coastguard Worker
1267*f6dc9357SAndroid Build Coastguard Worker if (item.ResourceFork.IsEmpty())
1268*f6dc9357SAndroid Build Coastguard Worker continue;
1269*f6dc9357SAndroid Build Coastguard Worker if (item.CompressHeader.IsSupported && item.CompressHeader.IsMethod_Resource())
1270*f6dc9357SAndroid Build Coastguard Worker continue;
1271*f6dc9357SAndroid Build Coastguard Worker
1272*f6dc9357SAndroid Build Coastguard Worker ThereAreAltStreams = true;
1273*f6dc9357SAndroid Build Coastguard Worker ref.AttrIndex = kAttrIndex_Resource;
1274*f6dc9357SAndroid Build Coastguard Worker ref.Parent = (int)(Refs.Size() - 1);
1275*f6dc9357SAndroid Build Coastguard Worker Refs.Add(ref);
1276*f6dc9357SAndroid Build Coastguard Worker
1277*f6dc9357SAndroid Build Coastguard Worker #endif
1278*f6dc9357SAndroid Build Coastguard Worker }
1279*f6dc9357SAndroid Build Coastguard Worker }
1280*f6dc9357SAndroid Build Coastguard Worker
1281*f6dc9357SAndroid Build Coastguard Worker IdToIndexMap.Sort2();
1282*f6dc9357SAndroid Build Coastguard Worker
1283*f6dc9357SAndroid Build Coastguard Worker {
1284*f6dc9357SAndroid Build Coastguard Worker FOR_VECTOR (i, Refs)
1285*f6dc9357SAndroid Build Coastguard Worker {
1286*f6dc9357SAndroid Build Coastguard Worker CRef &ref = Refs[i];
1287*f6dc9357SAndroid Build Coastguard Worker if (ref.IsResource())
1288*f6dc9357SAndroid Build Coastguard Worker continue;
1289*f6dc9357SAndroid Build Coastguard Worker const CItem &item = Items[ref.ItemIndex];
1290*f6dc9357SAndroid Build Coastguard Worker ref.Parent = FindItemIndex(IdToIndexMap, item.ParentID);
1291*f6dc9357SAndroid Build Coastguard Worker if (ref.Parent >= 0)
1292*f6dc9357SAndroid Build Coastguard Worker {
1293*f6dc9357SAndroid Build Coastguard Worker if (!Items[Refs[ref.Parent].ItemIndex].IsDir())
1294*f6dc9357SAndroid Build Coastguard Worker {
1295*f6dc9357SAndroid Build Coastguard Worker ref.Parent = -1;
1296*f6dc9357SAndroid Build Coastguard Worker HeadersError = true;
1297*f6dc9357SAndroid Build Coastguard Worker }
1298*f6dc9357SAndroid Build Coastguard Worker }
1299*f6dc9357SAndroid Build Coastguard Worker }
1300*f6dc9357SAndroid Build Coastguard Worker }
1301*f6dc9357SAndroid Build Coastguard Worker
1302*f6dc9357SAndroid Build Coastguard Worker #ifdef HFS_SHOW_ALT_STREAMS
1303*f6dc9357SAndroid Build Coastguard Worker {
1304*f6dc9357SAndroid Build Coastguard Worker FOR_VECTOR (i, Attrs)
1305*f6dc9357SAndroid Build Coastguard Worker {
1306*f6dc9357SAndroid Build Coastguard Worker if (skipAttr[i])
1307*f6dc9357SAndroid Build Coastguard Worker continue;
1308*f6dc9357SAndroid Build Coastguard Worker const CAttr &attr = Attrs[i];
1309*f6dc9357SAndroid Build Coastguard Worker
1310*f6dc9357SAndroid Build Coastguard Worker const int refIndex = FindItemIndex(IdToIndexMap, attr.ID);
1311*f6dc9357SAndroid Build Coastguard Worker if (refIndex < 0)
1312*f6dc9357SAndroid Build Coastguard Worker {
1313*f6dc9357SAndroid Build Coastguard Worker HeadersError = true;
1314*f6dc9357SAndroid Build Coastguard Worker continue;
1315*f6dc9357SAndroid Build Coastguard Worker }
1316*f6dc9357SAndroid Build Coastguard Worker
1317*f6dc9357SAndroid Build Coastguard Worker ThereAreAltStreams = true;
1318*f6dc9357SAndroid Build Coastguard Worker
1319*f6dc9357SAndroid Build Coastguard Worker CRef ref;
1320*f6dc9357SAndroid Build Coastguard Worker ref.AttrIndex = (int)i;
1321*f6dc9357SAndroid Build Coastguard Worker ref.Parent = refIndex;
1322*f6dc9357SAndroid Build Coastguard Worker ref.ItemIndex = Refs[refIndex].ItemIndex;
1323*f6dc9357SAndroid Build Coastguard Worker Refs.Add(ref);
1324*f6dc9357SAndroid Build Coastguard Worker }
1325*f6dc9357SAndroid Build Coastguard Worker }
1326*f6dc9357SAndroid Build Coastguard Worker #endif
1327*f6dc9357SAndroid Build Coastguard Worker
1328*f6dc9357SAndroid Build Coastguard Worker return S_OK;
1329*f6dc9357SAndroid Build Coastguard Worker }
1330*f6dc9357SAndroid Build Coastguard Worker
1331*f6dc9357SAndroid Build Coastguard Worker static const unsigned kHeaderPadSize = 1 << 10;
1332*f6dc9357SAndroid Build Coastguard Worker static const unsigned kMainHeaderSize = 512;
1333*f6dc9357SAndroid Build Coastguard Worker static const unsigned kHfsHeaderSize = kHeaderPadSize + kMainHeaderSize;
1334*f6dc9357SAndroid Build Coastguard Worker
1335*f6dc9357SAndroid Build Coastguard Worker static const unsigned k_Signature_LE16_HFS_BD = 'B' + ((unsigned)'D' << 8);
1336*f6dc9357SAndroid Build Coastguard Worker static const unsigned k_Signature_LE16_HPLUS = 'H' + ((unsigned)'+' << 8);
1337*f6dc9357SAndroid Build Coastguard Worker static const UInt32 k_Signature_LE32_HFSP_VER4 = 'H' + ((UInt32)'+' << 8) + ((UInt32)4 << 24);
1338*f6dc9357SAndroid Build Coastguard Worker static const UInt32 k_Signature_LE32_HFSX_VER5 = 'H' + ((UInt32)'X' << 8) + ((UInt32)5 << 24);
1339*f6dc9357SAndroid Build Coastguard Worker
IsArc_HFS(const Byte * p,size_t size)1340*f6dc9357SAndroid Build Coastguard Worker API_FUNC_static_IsArc IsArc_HFS(const Byte *p, size_t size)
1341*f6dc9357SAndroid Build Coastguard Worker {
1342*f6dc9357SAndroid Build Coastguard Worker if (size < kHfsHeaderSize)
1343*f6dc9357SAndroid Build Coastguard Worker return k_IsArc_Res_NEED_MORE;
1344*f6dc9357SAndroid Build Coastguard Worker p += kHeaderPadSize;
1345*f6dc9357SAndroid Build Coastguard Worker const UInt32 sig = GetUi32(p);
1346*f6dc9357SAndroid Build Coastguard Worker if (sig != k_Signature_LE32_HFSP_VER4)
1347*f6dc9357SAndroid Build Coastguard Worker if (sig != k_Signature_LE32_HFSX_VER5)
1348*f6dc9357SAndroid Build Coastguard Worker if ((UInt16)sig != k_Signature_LE16_HFS_BD
1349*f6dc9357SAndroid Build Coastguard Worker || GetUi16(p + 0x7c) != k_Signature_LE16_HPLUS)
1350*f6dc9357SAndroid Build Coastguard Worker return k_IsArc_Res_NO;
1351*f6dc9357SAndroid Build Coastguard Worker return k_IsArc_Res_YES;
1352*f6dc9357SAndroid Build Coastguard Worker }
1353*f6dc9357SAndroid Build Coastguard Worker }
1354*f6dc9357SAndroid Build Coastguard Worker
Open2(IInStream * inStream,IArchiveOpenCallback * progress)1355*f6dc9357SAndroid Build Coastguard Worker HRESULT CDatabase::Open2(IInStream *inStream, IArchiveOpenCallback *progress)
1356*f6dc9357SAndroid Build Coastguard Worker {
1357*f6dc9357SAndroid Build Coastguard Worker Clear();
1358*f6dc9357SAndroid Build Coastguard Worker UInt32 buf32[kHfsHeaderSize / 4];
1359*f6dc9357SAndroid Build Coastguard Worker RINOK(ReadStream_FALSE(inStream, buf32, kHfsHeaderSize))
1360*f6dc9357SAndroid Build Coastguard Worker const Byte *p = (const Byte *)buf32 + kHeaderPadSize;
1361*f6dc9357SAndroid Build Coastguard Worker CVolHeader &h = Header;
1362*f6dc9357SAndroid Build Coastguard Worker
1363*f6dc9357SAndroid Build Coastguard Worker if (GetUi16a(p) == k_Signature_LE16_HFS_BD)
1364*f6dc9357SAndroid Build Coastguard Worker {
1365*f6dc9357SAndroid Build Coastguard Worker /*
1366*f6dc9357SAndroid Build Coastguard Worker It's header for old HFS format.
1367*f6dc9357SAndroid Build Coastguard Worker We don't support old HFS format, but we support
1368*f6dc9357SAndroid Build Coastguard Worker special HFS volume that contains embedded HFS+ volume.
1369*f6dc9357SAndroid Build Coastguard Worker HFS MDB : Master directory block
1370*f6dc9357SAndroid Build Coastguard Worker HFS VIB : Volume information block
1371*f6dc9357SAndroid Build Coastguard Worker some old images contain boot data with "LK" signature at start of buf32.
1372*f6dc9357SAndroid Build Coastguard Worker */
1373*f6dc9357SAndroid Build Coastguard Worker #if 1
1374*f6dc9357SAndroid Build Coastguard Worker // here we check first bytes of archive,
1375*f6dc9357SAndroid Build Coastguard Worker // because start data can contain signature of some another
1376*f6dc9357SAndroid Build Coastguard Worker // archive type that could have priority over HFS.
1377*f6dc9357SAndroid Build Coastguard Worker const void *buf_ptr = (const void *)buf32;
1378*f6dc9357SAndroid Build Coastguard Worker const unsigned sig = GetUi16a(buf_ptr);
1379*f6dc9357SAndroid Build Coastguard Worker if (sig != 'L' + ((unsigned)'K' << 8))
1380*f6dc9357SAndroid Build Coastguard Worker {
1381*f6dc9357SAndroid Build Coastguard Worker // some old HFS (non HFS+) files have no "LK" signature,
1382*f6dc9357SAndroid Build Coastguard Worker // but have non-zero data after 2 first bytes in start 1 KiB.
1383*f6dc9357SAndroid Build Coastguard Worker if (sig != 0)
1384*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1385*f6dc9357SAndroid Build Coastguard Worker /*
1386*f6dc9357SAndroid Build Coastguard Worker for (unsigned i = 0; i < kHeaderPadSize / 4; i++)
1387*f6dc9357SAndroid Build Coastguard Worker if (buf32[i] != 0)
1388*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1389*f6dc9357SAndroid Build Coastguard Worker */
1390*f6dc9357SAndroid Build Coastguard Worker }
1391*f6dc9357SAndroid Build Coastguard Worker #endif
1392*f6dc9357SAndroid Build Coastguard Worker if (GetUi16a(p + 0x7c) != k_Signature_LE16_HPLUS) // signature of embedded HFS+ volume
1393*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1394*f6dc9357SAndroid Build Coastguard Worker /*
1395*f6dc9357SAndroid Build Coastguard Worker h.CTime = Get32(p + 0x2);
1396*f6dc9357SAndroid Build Coastguard Worker h.MTime = Get32(p + 0x6);
1397*f6dc9357SAndroid Build Coastguard Worker
1398*f6dc9357SAndroid Build Coastguard Worker h.NumFiles = Get32(p + 0x54);
1399*f6dc9357SAndroid Build Coastguard Worker h.NumFolders = Get32(p + 0x58);
1400*f6dc9357SAndroid Build Coastguard Worker
1401*f6dc9357SAndroid Build Coastguard Worker if (h.NumFolders > ((UInt32)1 << 29) ||
1402*f6dc9357SAndroid Build Coastguard Worker h.NumFiles > ((UInt32)1 << 30))
1403*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1404*f6dc9357SAndroid Build Coastguard Worker if (progress)
1405*f6dc9357SAndroid Build Coastguard Worker {
1406*f6dc9357SAndroid Build Coastguard Worker UInt64 numFiles = (UInt64)h.NumFiles + h.NumFolders + 1;
1407*f6dc9357SAndroid Build Coastguard Worker RINOK(progress->SetTotal(&numFiles, NULL))
1408*f6dc9357SAndroid Build Coastguard Worker }
1409*f6dc9357SAndroid Build Coastguard Worker h.NumFreeBlocks = Get16(p + 0x22);
1410*f6dc9357SAndroid Build Coastguard Worker */
1411*f6dc9357SAndroid Build Coastguard Worker
1412*f6dc9357SAndroid Build Coastguard Worker // v24.09: blockSize in old HFS image can be non-power of 2.
1413*f6dc9357SAndroid Build Coastguard Worker const UInt32 blockSize = Get32a(p + 0x14); // drAlBlkSiz
1414*f6dc9357SAndroid Build Coastguard Worker if (blockSize == 0 || (blockSize & 0x1ff))
1415*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1416*f6dc9357SAndroid Build Coastguard Worker const unsigned numBlocks = Get16a(p + 0x12); // drNmAlBlks
1417*f6dc9357SAndroid Build Coastguard Worker // UInt16 drFreeBks = Get16a(p + 0x22); // number of unused allocation blocks
1418*f6dc9357SAndroid Build Coastguard Worker /*
1419*f6dc9357SAndroid Build Coastguard Worker we suppose that it has the following layout:
1420*f6dc9357SAndroid Build Coastguard Worker {
1421*f6dc9357SAndroid Build Coastguard Worker start data with header
1422*f6dc9357SAndroid Build Coastguard Worker blocks[h.NumBlocks]
1423*f6dc9357SAndroid Build Coastguard Worker end data with header (probably size_of_footer <= blockSize).
1424*f6dc9357SAndroid Build Coastguard Worker }
1425*f6dc9357SAndroid Build Coastguard Worker */
1426*f6dc9357SAndroid Build Coastguard Worker // PhySize2 = ((UInt64)numBlocks + 2) * blockSize;
1427*f6dc9357SAndroid Build Coastguard Worker const unsigned sector_of_FirstBlock = Get16a(p + 0x1c); // drAlBlSt : first allocation block in volume
1428*f6dc9357SAndroid Build Coastguard Worker const UInt32 startBlock = Get16a(p + 0x7c + 2);
1429*f6dc9357SAndroid Build Coastguard Worker const UInt32 blockCount = Get16a(p + 0x7c + 4);
1430*f6dc9357SAndroid Build Coastguard Worker SpecOffset = (UInt32)sector_of_FirstBlock << 9; // it's 32-bit here
1431*f6dc9357SAndroid Build Coastguard Worker PhySize2 = SpecOffset + (UInt64)numBlocks * blockSize;
1432*f6dc9357SAndroid Build Coastguard Worker SpecOffset += (UInt64)startBlock * blockSize;
1433*f6dc9357SAndroid Build Coastguard Worker // before v24.09: // SpecOffset = (UInt64)(1 + startBlock) * blockSize;
1434*f6dc9357SAndroid Build Coastguard Worker const UInt64 phy = SpecOffset + (UInt64)blockCount * blockSize;
1435*f6dc9357SAndroid Build Coastguard Worker if (PhySize2 < phy)
1436*f6dc9357SAndroid Build Coastguard Worker PhySize2 = phy;
1437*f6dc9357SAndroid Build Coastguard Worker UInt32 tail = 1 << 10; // at least 1 KiB tail (for footer MDB) is expected.
1438*f6dc9357SAndroid Build Coastguard Worker if (tail < blockSize)
1439*f6dc9357SAndroid Build Coastguard Worker tail = blockSize;
1440*f6dc9357SAndroid Build Coastguard Worker RINOK(InStream_GetSize_SeekToEnd(inStream, ArcFileSize))
1441*f6dc9357SAndroid Build Coastguard Worker if (ArcFileSize > PhySize2 &&
1442*f6dc9357SAndroid Build Coastguard Worker ArcFileSize - PhySize2 <= tail)
1443*f6dc9357SAndroid Build Coastguard Worker {
1444*f6dc9357SAndroid Build Coastguard Worker // data after blocks[h.NumBlocks] must contain another copy of MDB.
1445*f6dc9357SAndroid Build Coastguard Worker // In example where blockSize is not power of 2, we have
1446*f6dc9357SAndroid Build Coastguard Worker // (ArcFileSize - PhySize2) < blockSize.
1447*f6dc9357SAndroid Build Coastguard Worker // We suppose that data after blocks[h.NumBlocks] is part of HFS archive.
1448*f6dc9357SAndroid Build Coastguard Worker // Maybe we should scan for footer MDB data (in last 1 KiB)?
1449*f6dc9357SAndroid Build Coastguard Worker PhySize2 = ArcFileSize;
1450*f6dc9357SAndroid Build Coastguard Worker }
1451*f6dc9357SAndroid Build Coastguard Worker RINOK(InStream_SeekSet(inStream, SpecOffset))
1452*f6dc9357SAndroid Build Coastguard Worker RINOK(ReadStream_FALSE(inStream, buf32, kHfsHeaderSize))
1453*f6dc9357SAndroid Build Coastguard Worker }
1454*f6dc9357SAndroid Build Coastguard Worker
1455*f6dc9357SAndroid Build Coastguard Worker // HFS+ / HFSX volume header (starting from offset==1024):
1456*f6dc9357SAndroid Build Coastguard Worker {
1457*f6dc9357SAndroid Build Coastguard Worker // v24.09: we use strict condition test for pair signature(Version):
1458*f6dc9357SAndroid Build Coastguard Worker // H+(4), HX(5):
1459*f6dc9357SAndroid Build Coastguard Worker const UInt32 sig = GetUi32a(p);
1460*f6dc9357SAndroid Build Coastguard Worker // h.Version = Get16(p + 2);
1461*f6dc9357SAndroid Build Coastguard Worker h.Is_Hsfx_ver5 = false;
1462*f6dc9357SAndroid Build Coastguard Worker if (sig != k_Signature_LE32_HFSP_VER4)
1463*f6dc9357SAndroid Build Coastguard Worker {
1464*f6dc9357SAndroid Build Coastguard Worker if (sig != k_Signature_LE32_HFSX_VER5)
1465*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1466*f6dc9357SAndroid Build Coastguard Worker h.Is_Hsfx_ver5 = true;
1467*f6dc9357SAndroid Build Coastguard Worker }
1468*f6dc9357SAndroid Build Coastguard Worker }
1469*f6dc9357SAndroid Build Coastguard Worker {
1470*f6dc9357SAndroid Build Coastguard Worker const UInt32 blockSize = Get32a(p + 0x28);
1471*f6dc9357SAndroid Build Coastguard Worker unsigned i;
1472*f6dc9357SAndroid Build Coastguard Worker for (i = 9; ((UInt32)1 << i) != blockSize; i++)
1473*f6dc9357SAndroid Build Coastguard Worker if (i == 31)
1474*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1475*f6dc9357SAndroid Build Coastguard Worker h.BlockSizeLog = i;
1476*f6dc9357SAndroid Build Coastguard Worker }
1477*f6dc9357SAndroid Build Coastguard Worker #if 1
1478*f6dc9357SAndroid Build Coastguard Worker // HFS Plus DOCs: The first 1024 bytes are reserved for use as boot blocks
1479*f6dc9357SAndroid Build Coastguard Worker // v24.09: we don't check starting 1 KiB before old (HFS MDB) block ("BD" signture) .
1480*f6dc9357SAndroid Build Coastguard Worker // but we still check starting 1 KiB before HFS+ / HFSX volume header.
1481*f6dc9357SAndroid Build Coastguard Worker // are there HFS+ / HFSX images with non-zero data in this reserved area?
1482*f6dc9357SAndroid Build Coastguard Worker {
1483*f6dc9357SAndroid Build Coastguard Worker for (unsigned i = 0; i < kHeaderPadSize / 4; i++)
1484*f6dc9357SAndroid Build Coastguard Worker if (buf32[i] != 0)
1485*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1486*f6dc9357SAndroid Build Coastguard Worker }
1487*f6dc9357SAndroid Build Coastguard Worker #endif
1488*f6dc9357SAndroid Build Coastguard Worker // h.Attr = Get32a(p + 4);
1489*f6dc9357SAndroid Build Coastguard Worker // h.LastMountedVersion = Get32a(p + 8);
1490*f6dc9357SAndroid Build Coastguard Worker // h.JournalInfoBlock = Get32a(p + 0xC);
1491*f6dc9357SAndroid Build Coastguard Worker h.CTime = Get32a(p + 0x10);
1492*f6dc9357SAndroid Build Coastguard Worker h.MTime = Get32a(p + 0x14);
1493*f6dc9357SAndroid Build Coastguard Worker // h.BackupTime = Get32a(p + 0x18);
1494*f6dc9357SAndroid Build Coastguard Worker // h.CheckedTime = Get32a(p + 0x1C);
1495*f6dc9357SAndroid Build Coastguard Worker h.NumFiles = Get32a(p + 0x20);
1496*f6dc9357SAndroid Build Coastguard Worker h.NumFolders = Get32a(p + 0x24);
1497*f6dc9357SAndroid Build Coastguard Worker if (h.NumFolders > ((UInt32)1 << 29) ||
1498*f6dc9357SAndroid Build Coastguard Worker h.NumFiles > ((UInt32)1 << 30))
1499*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1500*f6dc9357SAndroid Build Coastguard Worker
1501*f6dc9357SAndroid Build Coastguard Worker RINOK(InStream_GetSize_SeekToEnd(inStream, ArcFileSize))
1502*f6dc9357SAndroid Build Coastguard Worker if (progress)
1503*f6dc9357SAndroid Build Coastguard Worker {
1504*f6dc9357SAndroid Build Coastguard Worker const UInt64 numFiles = (UInt64)h.NumFiles + h.NumFolders + 1;
1505*f6dc9357SAndroid Build Coastguard Worker RINOK(progress->SetTotal(&numFiles, NULL))
1506*f6dc9357SAndroid Build Coastguard Worker }
1507*f6dc9357SAndroid Build Coastguard Worker
1508*f6dc9357SAndroid Build Coastguard Worker h.NumBlocks = Get32a(p + 0x2C);
1509*f6dc9357SAndroid Build Coastguard Worker h.NumFreeBlocks = Get32a(p + 0x30);
1510*f6dc9357SAndroid Build Coastguard Worker /*
1511*f6dc9357SAndroid Build Coastguard Worker h.NextCalatlogNodeID = Get32(p + 0x40);
1512*f6dc9357SAndroid Build Coastguard Worker h.WriteCount = Get32(p + 0x44);
1513*f6dc9357SAndroid Build Coastguard Worker for (i = 0; i < 6; i++)
1514*f6dc9357SAndroid Build Coastguard Worker h.FinderInfo[i] = Get32(p + 0x50 + i * 4);
1515*f6dc9357SAndroid Build Coastguard Worker h.VolID = Get64(p + 0x68);
1516*f6dc9357SAndroid Build Coastguard Worker */
1517*f6dc9357SAndroid Build Coastguard Worker
1518*f6dc9357SAndroid Build Coastguard Worker ResFileName = kResFileName;
1519*f6dc9357SAndroid Build Coastguard Worker
1520*f6dc9357SAndroid Build Coastguard Worker CFork extentsFork, catalogFork, attrFork;
1521*f6dc9357SAndroid Build Coastguard Worker // allocationFork.Parse(p + 0x70 + 0x50 * 0);
1522*f6dc9357SAndroid Build Coastguard Worker extentsFork.Parse(p + 0x70 + 0x50 * 1);
1523*f6dc9357SAndroid Build Coastguard Worker catalogFork.Parse(p + 0x70 + 0x50 * 2);
1524*f6dc9357SAndroid Build Coastguard Worker attrFork.Parse (p + 0x70 + 0x50 * 3);
1525*f6dc9357SAndroid Build Coastguard Worker // startupFork.Parse(p + 0x70 + 0x50 * 4);
1526*f6dc9357SAndroid Build Coastguard Worker
1527*f6dc9357SAndroid Build Coastguard Worker CObjectVector<CIdExtents> overflowExtents[2];
1528*f6dc9357SAndroid Build Coastguard Worker if (!extentsFork.IsOk(Header.BlockSizeLog))
1529*f6dc9357SAndroid Build Coastguard Worker HeadersError = true;
1530*f6dc9357SAndroid Build Coastguard Worker else
1531*f6dc9357SAndroid Build Coastguard Worker {
1532*f6dc9357SAndroid Build Coastguard Worker const HRESULT res = LoadExtentFile(extentsFork, inStream, overflowExtents);
1533*f6dc9357SAndroid Build Coastguard Worker if (res == S_FALSE)
1534*f6dc9357SAndroid Build Coastguard Worker HeadersError = true;
1535*f6dc9357SAndroid Build Coastguard Worker else if (res != S_OK)
1536*f6dc9357SAndroid Build Coastguard Worker return res;
1537*f6dc9357SAndroid Build Coastguard Worker }
1538*f6dc9357SAndroid Build Coastguard Worker
1539*f6dc9357SAndroid Build Coastguard Worker if (!catalogFork.UpgradeAndTest(overflowExtents[0], kHfsID_CatalogFile, Header.BlockSizeLog))
1540*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1541*f6dc9357SAndroid Build Coastguard Worker
1542*f6dc9357SAndroid Build Coastguard Worker if (!attrFork.UpgradeAndTest(overflowExtents[0], kHfsID_AttributesFile, Header.BlockSizeLog))
1543*f6dc9357SAndroid Build Coastguard Worker HeadersError = true;
1544*f6dc9357SAndroid Build Coastguard Worker else
1545*f6dc9357SAndroid Build Coastguard Worker {
1546*f6dc9357SAndroid Build Coastguard Worker if (attrFork.Size != 0)
1547*f6dc9357SAndroid Build Coastguard Worker RINOK(LoadAttrs(attrFork, inStream, progress))
1548*f6dc9357SAndroid Build Coastguard Worker }
1549*f6dc9357SAndroid Build Coastguard Worker
1550*f6dc9357SAndroid Build Coastguard Worker RINOK(LoadCatalog(catalogFork, overflowExtents, inStream, progress))
1551*f6dc9357SAndroid Build Coastguard Worker
1552*f6dc9357SAndroid Build Coastguard Worker // PhySize = Header.GetPhySize();
1553*f6dc9357SAndroid Build Coastguard Worker return S_OK;
1554*f6dc9357SAndroid Build Coastguard Worker }
1555*f6dc9357SAndroid Build Coastguard Worker
1556*f6dc9357SAndroid Build Coastguard Worker
1557*f6dc9357SAndroid Build Coastguard Worker
1558*f6dc9357SAndroid Build Coastguard Worker Z7_class_CHandler_final:
1559*f6dc9357SAndroid Build Coastguard Worker public IInArchive,
1560*f6dc9357SAndroid Build Coastguard Worker public IArchiveGetRawProps,
1561*f6dc9357SAndroid Build Coastguard Worker public IInArchiveGetStream,
1562*f6dc9357SAndroid Build Coastguard Worker public CMyUnknownImp,
1563*f6dc9357SAndroid Build Coastguard Worker public CDatabase
1564*f6dc9357SAndroid Build Coastguard Worker {
1565*f6dc9357SAndroid Build Coastguard Worker Z7_IFACES_IMP_UNK_3(
1566*f6dc9357SAndroid Build Coastguard Worker IInArchive,
1567*f6dc9357SAndroid Build Coastguard Worker IArchiveGetRawProps,
1568*f6dc9357SAndroid Build Coastguard Worker IInArchiveGetStream)
1569*f6dc9357SAndroid Build Coastguard Worker
1570*f6dc9357SAndroid Build Coastguard Worker CMyComPtr<IInStream> _stream;
1571*f6dc9357SAndroid Build Coastguard Worker HRESULT GetForkStream(const CFork &fork, ISequentialInStream **stream);
1572*f6dc9357SAndroid Build Coastguard Worker };
1573*f6dc9357SAndroid Build Coastguard Worker
1574*f6dc9357SAndroid Build Coastguard Worker static const Byte kProps[] =
1575*f6dc9357SAndroid Build Coastguard Worker {
1576*f6dc9357SAndroid Build Coastguard Worker kpidPath,
1577*f6dc9357SAndroid Build Coastguard Worker kpidIsDir,
1578*f6dc9357SAndroid Build Coastguard Worker kpidSize,
1579*f6dc9357SAndroid Build Coastguard Worker kpidPackSize,
1580*f6dc9357SAndroid Build Coastguard Worker kpidCTime,
1581*f6dc9357SAndroid Build Coastguard Worker kpidMTime,
1582*f6dc9357SAndroid Build Coastguard Worker kpidATime,
1583*f6dc9357SAndroid Build Coastguard Worker kpidChangeTime,
1584*f6dc9357SAndroid Build Coastguard Worker kpidPosixAttrib,
1585*f6dc9357SAndroid Build Coastguard Worker /*
1586*f6dc9357SAndroid Build Coastguard Worker kpidUserId,
1587*f6dc9357SAndroid Build Coastguard Worker kpidGroupId,
1588*f6dc9357SAndroid Build Coastguard Worker */
1589*f6dc9357SAndroid Build Coastguard Worker #ifdef HFS_SHOW_ALT_STREAMS
1590*f6dc9357SAndroid Build Coastguard Worker kpidIsAltStream,
1591*f6dc9357SAndroid Build Coastguard Worker #endif
1592*f6dc9357SAndroid Build Coastguard Worker kpidMethod
1593*f6dc9357SAndroid Build Coastguard Worker };
1594*f6dc9357SAndroid Build Coastguard Worker
1595*f6dc9357SAndroid Build Coastguard Worker static const Byte kArcProps[] =
1596*f6dc9357SAndroid Build Coastguard Worker {
1597*f6dc9357SAndroid Build Coastguard Worker kpidMethod,
1598*f6dc9357SAndroid Build Coastguard Worker kpidCharacts,
1599*f6dc9357SAndroid Build Coastguard Worker kpidClusterSize,
1600*f6dc9357SAndroid Build Coastguard Worker kpidFreeSpace,
1601*f6dc9357SAndroid Build Coastguard Worker kpidCTime,
1602*f6dc9357SAndroid Build Coastguard Worker kpidMTime
1603*f6dc9357SAndroid Build Coastguard Worker };
1604*f6dc9357SAndroid Build Coastguard Worker
1605*f6dc9357SAndroid Build Coastguard Worker IMP_IInArchive_Props
1606*f6dc9357SAndroid Build Coastguard Worker IMP_IInArchive_ArcProps
1607*f6dc9357SAndroid Build Coastguard Worker
1608*f6dc9357SAndroid Build Coastguard Worker static void HfsTimeToProp(UInt32 hfsTime, NWindows::NCOM::CPropVariant &prop)
1609*f6dc9357SAndroid Build Coastguard Worker {
1610*f6dc9357SAndroid Build Coastguard Worker if (hfsTime == 0)
1611*f6dc9357SAndroid Build Coastguard Worker return;
1612*f6dc9357SAndroid Build Coastguard Worker FILETIME ft;
1613*f6dc9357SAndroid Build Coastguard Worker HfsTimeToFileTime(hfsTime, ft);
1614*f6dc9357SAndroid Build Coastguard Worker prop.SetAsTimeFrom_FT_Prec(ft, k_PropVar_TimePrec_Base);
1615*f6dc9357SAndroid Build Coastguard Worker }
1616*f6dc9357SAndroid Build Coastguard Worker
1617*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
1618*f6dc9357SAndroid Build Coastguard Worker {
1619*f6dc9357SAndroid Build Coastguard Worker COM_TRY_BEGIN
1620*f6dc9357SAndroid Build Coastguard Worker NWindows::NCOM::CPropVariant prop;
1621*f6dc9357SAndroid Build Coastguard Worker switch (propID)
1622*f6dc9357SAndroid Build Coastguard Worker {
1623*f6dc9357SAndroid Build Coastguard Worker case kpidExtension: prop = Header.IsHfsX() ? "hfsx" : "hfs"; break;
1624*f6dc9357SAndroid Build Coastguard Worker case kpidMethod: prop = Header.IsHfsX() ? "HFSX" : "HFS+"; break;
1625*f6dc9357SAndroid Build Coastguard Worker case kpidCharacts: MethodsMaskToProp(MethodsMask, prop); break;
1626*f6dc9357SAndroid Build Coastguard Worker case kpidPhySize:
1627*f6dc9357SAndroid Build Coastguard Worker {
1628*f6dc9357SAndroid Build Coastguard Worker UInt64 v = SpecOffset + Header.GetPhySize(); // PhySize;
1629*f6dc9357SAndroid Build Coastguard Worker if (v < PhySize2)
1630*f6dc9357SAndroid Build Coastguard Worker v = PhySize2;
1631*f6dc9357SAndroid Build Coastguard Worker prop = v;
1632*f6dc9357SAndroid Build Coastguard Worker break;
1633*f6dc9357SAndroid Build Coastguard Worker }
1634*f6dc9357SAndroid Build Coastguard Worker case kpidClusterSize: prop = (UInt32)1 << Header.BlockSizeLog; break;
1635*f6dc9357SAndroid Build Coastguard Worker case kpidFreeSpace: prop = (UInt64)Header.GetFreeSize(); break;
1636*f6dc9357SAndroid Build Coastguard Worker case kpidMTime: HfsTimeToProp(Header.MTime, prop); break;
1637*f6dc9357SAndroid Build Coastguard Worker case kpidCTime:
1638*f6dc9357SAndroid Build Coastguard Worker {
1639*f6dc9357SAndroid Build Coastguard Worker if (Header.CTime != 0)
1640*f6dc9357SAndroid Build Coastguard Worker {
1641*f6dc9357SAndroid Build Coastguard Worker FILETIME localFt, ft;
1642*f6dc9357SAndroid Build Coastguard Worker HfsTimeToFileTime(Header.CTime, localFt);
1643*f6dc9357SAndroid Build Coastguard Worker if (LocalFileTimeToFileTime(&localFt, &ft))
1644*f6dc9357SAndroid Build Coastguard Worker prop.SetAsTimeFrom_FT_Prec(ft, k_PropVar_TimePrec_Base);
1645*f6dc9357SAndroid Build Coastguard Worker }
1646*f6dc9357SAndroid Build Coastguard Worker break;
1647*f6dc9357SAndroid Build Coastguard Worker }
1648*f6dc9357SAndroid Build Coastguard Worker case kpidIsTree: prop = true; break;
1649*f6dc9357SAndroid Build Coastguard Worker case kpidErrorFlags:
1650*f6dc9357SAndroid Build Coastguard Worker {
1651*f6dc9357SAndroid Build Coastguard Worker UInt32 flags = 0;
1652*f6dc9357SAndroid Build Coastguard Worker if (HeadersError) flags |= kpv_ErrorFlags_HeadersError;
1653*f6dc9357SAndroid Build Coastguard Worker if (UnsupportedFeature) flags |= kpv_ErrorFlags_UnsupportedFeature;
1654*f6dc9357SAndroid Build Coastguard Worker if (flags != 0)
1655*f6dc9357SAndroid Build Coastguard Worker prop = flags;
1656*f6dc9357SAndroid Build Coastguard Worker break;
1657*f6dc9357SAndroid Build Coastguard Worker }
1658*f6dc9357SAndroid Build Coastguard Worker case kpidIsAltStream: prop = ThereAreAltStreams; break;
1659*f6dc9357SAndroid Build Coastguard Worker }
1660*f6dc9357SAndroid Build Coastguard Worker prop.Detach(value);
1661*f6dc9357SAndroid Build Coastguard Worker return S_OK;
1662*f6dc9357SAndroid Build Coastguard Worker COM_TRY_END
1663*f6dc9357SAndroid Build Coastguard Worker }
1664*f6dc9357SAndroid Build Coastguard Worker
1665*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetNumRawProps(UInt32 *numProps))
1666*f6dc9357SAndroid Build Coastguard Worker {
1667*f6dc9357SAndroid Build Coastguard Worker *numProps = 0;
1668*f6dc9357SAndroid Build Coastguard Worker return S_OK;
1669*f6dc9357SAndroid Build Coastguard Worker }
1670*f6dc9357SAndroid Build Coastguard Worker
1671*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID))
1672*f6dc9357SAndroid Build Coastguard Worker {
1673*f6dc9357SAndroid Build Coastguard Worker *name = NULL;
1674*f6dc9357SAndroid Build Coastguard Worker *propID = 0;
1675*f6dc9357SAndroid Build Coastguard Worker return S_OK;
1676*f6dc9357SAndroid Build Coastguard Worker }
1677*f6dc9357SAndroid Build Coastguard Worker
1678*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetParent(UInt32 index, UInt32 *parent, UInt32 *parentType))
1679*f6dc9357SAndroid Build Coastguard Worker {
1680*f6dc9357SAndroid Build Coastguard Worker const CRef &ref = Refs[index];
1681*f6dc9357SAndroid Build Coastguard Worker *parentType = ref.IsAltStream() ?
1682*f6dc9357SAndroid Build Coastguard Worker NParentType::kAltStream :
1683*f6dc9357SAndroid Build Coastguard Worker NParentType::kDir;
1684*f6dc9357SAndroid Build Coastguard Worker *parent = (UInt32)(Int32)ref.Parent;
1685*f6dc9357SAndroid Build Coastguard Worker return S_OK;
1686*f6dc9357SAndroid Build Coastguard Worker }
1687*f6dc9357SAndroid Build Coastguard Worker
1688*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType))
1689*f6dc9357SAndroid Build Coastguard Worker {
1690*f6dc9357SAndroid Build Coastguard Worker *data = NULL;
1691*f6dc9357SAndroid Build Coastguard Worker *dataSize = 0;
1692*f6dc9357SAndroid Build Coastguard Worker *propType = 0;
1693*f6dc9357SAndroid Build Coastguard Worker #ifdef MY_CPU_LE
1694*f6dc9357SAndroid Build Coastguard Worker if (propID == kpidName)
1695*f6dc9357SAndroid Build Coastguard Worker {
1696*f6dc9357SAndroid Build Coastguard Worker const CRef &ref = Refs[index];
1697*f6dc9357SAndroid Build Coastguard Worker const UString *s;
1698*f6dc9357SAndroid Build Coastguard Worker if (ref.IsResource())
1699*f6dc9357SAndroid Build Coastguard Worker s = &ResFileName;
1700*f6dc9357SAndroid Build Coastguard Worker else if (ref.AttrIndex >= 0)
1701*f6dc9357SAndroid Build Coastguard Worker s = &Attrs[ref.AttrIndex].Name;
1702*f6dc9357SAndroid Build Coastguard Worker else
1703*f6dc9357SAndroid Build Coastguard Worker s = &Items[ref.ItemIndex].Name;
1704*f6dc9357SAndroid Build Coastguard Worker *data = (const wchar_t *)(*s);
1705*f6dc9357SAndroid Build Coastguard Worker *dataSize = (s->Len() + 1) * (UInt32)sizeof(wchar_t);
1706*f6dc9357SAndroid Build Coastguard Worker *propType = PROP_DATA_TYPE_wchar_t_PTR_Z_LE;
1707*f6dc9357SAndroid Build Coastguard Worker return S_OK;
1708*f6dc9357SAndroid Build Coastguard Worker }
1709*f6dc9357SAndroid Build Coastguard Worker #else
1710*f6dc9357SAndroid Build Coastguard Worker UNUSED_VAR(index)
1711*f6dc9357SAndroid Build Coastguard Worker UNUSED_VAR(propID)
1712*f6dc9357SAndroid Build Coastguard Worker #endif
1713*f6dc9357SAndroid Build Coastguard Worker return S_OK;
1714*f6dc9357SAndroid Build Coastguard Worker }
1715*f6dc9357SAndroid Build Coastguard Worker
1716*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
1717*f6dc9357SAndroid Build Coastguard Worker {
1718*f6dc9357SAndroid Build Coastguard Worker COM_TRY_BEGIN
1719*f6dc9357SAndroid Build Coastguard Worker NWindows::NCOM::CPropVariant prop;
1720*f6dc9357SAndroid Build Coastguard Worker const CRef &ref = Refs[index];
1721*f6dc9357SAndroid Build Coastguard Worker const CItem &item = Items[ref.ItemIndex];
1722*f6dc9357SAndroid Build Coastguard Worker switch (propID)
1723*f6dc9357SAndroid Build Coastguard Worker {
1724*f6dc9357SAndroid Build Coastguard Worker case kpidPath: GetItemPath(index, prop); break;
1725*f6dc9357SAndroid Build Coastguard Worker case kpidName:
1726*f6dc9357SAndroid Build Coastguard Worker {
1727*f6dc9357SAndroid Build Coastguard Worker const UString *s;
1728*f6dc9357SAndroid Build Coastguard Worker if (ref.IsResource())
1729*f6dc9357SAndroid Build Coastguard Worker s = &ResFileName;
1730*f6dc9357SAndroid Build Coastguard Worker else if (ref.AttrIndex >= 0)
1731*f6dc9357SAndroid Build Coastguard Worker s = &Attrs[ref.AttrIndex].Name;
1732*f6dc9357SAndroid Build Coastguard Worker else
1733*f6dc9357SAndroid Build Coastguard Worker s = &item.Name;
1734*f6dc9357SAndroid Build Coastguard Worker prop = *s;
1735*f6dc9357SAndroid Build Coastguard Worker break;
1736*f6dc9357SAndroid Build Coastguard Worker }
1737*f6dc9357SAndroid Build Coastguard Worker case kpidPackSize:
1738*f6dc9357SAndroid Build Coastguard Worker {
1739*f6dc9357SAndroid Build Coastguard Worker UInt64 size;
1740*f6dc9357SAndroid Build Coastguard Worker if (ref.AttrIndex >= 0)
1741*f6dc9357SAndroid Build Coastguard Worker size = Attrs[ref.AttrIndex].GetSize();
1742*f6dc9357SAndroid Build Coastguard Worker else if (ref.IsResource())
1743*f6dc9357SAndroid Build Coastguard Worker size = (UInt64)item.ResourceFork.NumBlocks << Header.BlockSizeLog;
1744*f6dc9357SAndroid Build Coastguard Worker else if (item.IsDir())
1745*f6dc9357SAndroid Build Coastguard Worker break;
1746*f6dc9357SAndroid Build Coastguard Worker else if (item.CompressHeader.IsCorrect)
1747*f6dc9357SAndroid Build Coastguard Worker {
1748*f6dc9357SAndroid Build Coastguard Worker if (item.CompressHeader.IsMethod_Resource())
1749*f6dc9357SAndroid Build Coastguard Worker size = (UInt64)item.ResourceFork.NumBlocks << Header.BlockSizeLog;
1750*f6dc9357SAndroid Build Coastguard Worker else if (item.decmpfs_AttrIndex >= 0)
1751*f6dc9357SAndroid Build Coastguard Worker {
1752*f6dc9357SAndroid Build Coastguard Worker // size = item.PackSize;
1753*f6dc9357SAndroid Build Coastguard Worker const CAttr &attr = Attrs[item.decmpfs_AttrIndex];
1754*f6dc9357SAndroid Build Coastguard Worker size = attr.Data.Size() - item.CompressHeader.DataPos;
1755*f6dc9357SAndroid Build Coastguard Worker }
1756*f6dc9357SAndroid Build Coastguard Worker else
1757*f6dc9357SAndroid Build Coastguard Worker size = 0;
1758*f6dc9357SAndroid Build Coastguard Worker }
1759*f6dc9357SAndroid Build Coastguard Worker else
1760*f6dc9357SAndroid Build Coastguard Worker size = (UInt64)item.DataFork.NumBlocks << Header.BlockSizeLog;
1761*f6dc9357SAndroid Build Coastguard Worker prop = size;
1762*f6dc9357SAndroid Build Coastguard Worker break;
1763*f6dc9357SAndroid Build Coastguard Worker }
1764*f6dc9357SAndroid Build Coastguard Worker case kpidSize:
1765*f6dc9357SAndroid Build Coastguard Worker {
1766*f6dc9357SAndroid Build Coastguard Worker UInt64 size;
1767*f6dc9357SAndroid Build Coastguard Worker if (ref.AttrIndex >= 0)
1768*f6dc9357SAndroid Build Coastguard Worker size = Attrs[ref.AttrIndex].GetSize();
1769*f6dc9357SAndroid Build Coastguard Worker else if (ref.IsResource())
1770*f6dc9357SAndroid Build Coastguard Worker size = item.ResourceFork.Size;
1771*f6dc9357SAndroid Build Coastguard Worker else if (item.IsDir())
1772*f6dc9357SAndroid Build Coastguard Worker break;
1773*f6dc9357SAndroid Build Coastguard Worker else if (item.CompressHeader.IsCorrect)
1774*f6dc9357SAndroid Build Coastguard Worker size = item.CompressHeader.UnpackSize;
1775*f6dc9357SAndroid Build Coastguard Worker else
1776*f6dc9357SAndroid Build Coastguard Worker size = item.DataFork.Size;
1777*f6dc9357SAndroid Build Coastguard Worker prop = size;
1778*f6dc9357SAndroid Build Coastguard Worker break;
1779*f6dc9357SAndroid Build Coastguard Worker }
1780*f6dc9357SAndroid Build Coastguard Worker case kpidIsDir: prop = (ref.IsItem() && item.IsDir()); break;
1781*f6dc9357SAndroid Build Coastguard Worker case kpidIsAltStream: prop = ref.IsAltStream(); break;
1782*f6dc9357SAndroid Build Coastguard Worker case kpidCTime: HfsTimeToProp(item.CTime, prop); break;
1783*f6dc9357SAndroid Build Coastguard Worker case kpidMTime: HfsTimeToProp(item.MTime, prop); break;
1784*f6dc9357SAndroid Build Coastguard Worker case kpidATime: HfsTimeToProp(item.ATime, prop); break;
1785*f6dc9357SAndroid Build Coastguard Worker case kpidChangeTime: HfsTimeToProp(item.AttrMTime, prop); break;
1786*f6dc9357SAndroid Build Coastguard Worker case kpidPosixAttrib: if (ref.IsItem()) prop = (UInt32)item.FileMode; break;
1787*f6dc9357SAndroid Build Coastguard Worker /*
1788*f6dc9357SAndroid Build Coastguard Worker case kpidUserId: prop = (UInt32)item.OwnerID; break;
1789*f6dc9357SAndroid Build Coastguard Worker case kpidGroupId: prop = (UInt32)item.GroupID; break;
1790*f6dc9357SAndroid Build Coastguard Worker */
1791*f6dc9357SAndroid Build Coastguard Worker
1792*f6dc9357SAndroid Build Coastguard Worker case kpidMethod:
1793*f6dc9357SAndroid Build Coastguard Worker if (ref.IsItem())
1794*f6dc9357SAndroid Build Coastguard Worker item.CompressHeader.MethodToProp(prop);
1795*f6dc9357SAndroid Build Coastguard Worker break;
1796*f6dc9357SAndroid Build Coastguard Worker }
1797*f6dc9357SAndroid Build Coastguard Worker prop.Detach(value);
1798*f6dc9357SAndroid Build Coastguard Worker return S_OK;
1799*f6dc9357SAndroid Build Coastguard Worker COM_TRY_END
1800*f6dc9357SAndroid Build Coastguard Worker }
1801*f6dc9357SAndroid Build Coastguard Worker
1802*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Open(IInStream *inStream,
1803*f6dc9357SAndroid Build Coastguard Worker const UInt64 * /* maxCheckStartPosition */,
1804*f6dc9357SAndroid Build Coastguard Worker IArchiveOpenCallback *callback))
1805*f6dc9357SAndroid Build Coastguard Worker {
1806*f6dc9357SAndroid Build Coastguard Worker COM_TRY_BEGIN
1807*f6dc9357SAndroid Build Coastguard Worker Close();
1808*f6dc9357SAndroid Build Coastguard Worker RINOK(Open2(inStream, callback))
1809*f6dc9357SAndroid Build Coastguard Worker _stream = inStream;
1810*f6dc9357SAndroid Build Coastguard Worker return S_OK;
1811*f6dc9357SAndroid Build Coastguard Worker COM_TRY_END
1812*f6dc9357SAndroid Build Coastguard Worker }
1813*f6dc9357SAndroid Build Coastguard Worker
1814*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Close())
1815*f6dc9357SAndroid Build Coastguard Worker {
1816*f6dc9357SAndroid Build Coastguard Worker _stream.Release();
1817*f6dc9357SAndroid Build Coastguard Worker Clear();
1818*f6dc9357SAndroid Build Coastguard Worker return S_OK;
1819*f6dc9357SAndroid Build Coastguard Worker }
1820*f6dc9357SAndroid Build Coastguard Worker
1821*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kCompressionBlockSize = 1 << 16;
1822*f6dc9357SAndroid Build Coastguard Worker
1823*f6dc9357SAndroid Build Coastguard Worker CDecoder::CDecoder(bool IsAdlerOptional)
1824*f6dc9357SAndroid Build Coastguard Worker {
1825*f6dc9357SAndroid Build Coastguard Worker /* Some new hfs files contain zlib resource fork without Adler checksum.
1826*f6dc9357SAndroid Build Coastguard Worker We do not know how we must detect case where there is Adler
1827*f6dc9357SAndroid Build Coastguard Worker checksum or there is no Adler checksum.
1828*f6dc9357SAndroid Build Coastguard Worker */
1829*f6dc9357SAndroid Build Coastguard Worker _zlibDecoder->IsAdlerOptional = IsAdlerOptional;
1830*f6dc9357SAndroid Build Coastguard Worker _lzfseDecoder->LzvnMode = true;
1831*f6dc9357SAndroid Build Coastguard Worker }
1832*f6dc9357SAndroid Build Coastguard Worker
1833*f6dc9357SAndroid Build Coastguard Worker HRESULT CDecoder::ExtractResourceFork_ZLIB(
1834*f6dc9357SAndroid Build Coastguard Worker ISequentialInStream *inStream, ISequentialOutStream *outStream,
1835*f6dc9357SAndroid Build Coastguard Worker UInt64 forkSize, UInt64 unpackSize,
1836*f6dc9357SAndroid Build Coastguard Worker UInt64 progressStart, IArchiveExtractCallback *extractCallback)
1837*f6dc9357SAndroid Build Coastguard Worker {
1838*f6dc9357SAndroid Build Coastguard Worker const unsigned kHeaderSize = 0x100 + 8;
1839*f6dc9357SAndroid Build Coastguard Worker
1840*f6dc9357SAndroid Build Coastguard Worker const size_t kBufSize = kCompressionBlockSize;
1841*f6dc9357SAndroid Build Coastguard Worker _buf.Alloc(kBufSize + 0x10); // we need 1 additional bytes for uncompressed chunk header
1842*f6dc9357SAndroid Build Coastguard Worker
1843*f6dc9357SAndroid Build Coastguard Worker RINOK(ReadStream_FALSE(inStream, _buf, kHeaderSize))
1844*f6dc9357SAndroid Build Coastguard Worker Byte *buf = _buf;
1845*f6dc9357SAndroid Build Coastguard Worker const UInt32 dataPos = Get32(buf);
1846*f6dc9357SAndroid Build Coastguard Worker const UInt32 mapPos = Get32(buf + 4);
1847*f6dc9357SAndroid Build Coastguard Worker const UInt32 dataSize = Get32(buf + 8);
1848*f6dc9357SAndroid Build Coastguard Worker const UInt32 mapSize = Get32(buf + 12);
1849*f6dc9357SAndroid Build Coastguard Worker
1850*f6dc9357SAndroid Build Coastguard Worker const UInt32 kResMapSize = 50;
1851*f6dc9357SAndroid Build Coastguard Worker
1852*f6dc9357SAndroid Build Coastguard Worker if (mapSize != kResMapSize
1853*f6dc9357SAndroid Build Coastguard Worker || dataPos > mapPos
1854*f6dc9357SAndroid Build Coastguard Worker || dataSize != mapPos - dataPos
1855*f6dc9357SAndroid Build Coastguard Worker || mapSize > forkSize
1856*f6dc9357SAndroid Build Coastguard Worker || mapPos != forkSize - mapSize)
1857*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1858*f6dc9357SAndroid Build Coastguard Worker
1859*f6dc9357SAndroid Build Coastguard Worker const UInt32 dataSize2 = Get32(buf + 0x100);
1860*f6dc9357SAndroid Build Coastguard Worker if (4 + dataSize2 != dataSize
1861*f6dc9357SAndroid Build Coastguard Worker || dataSize2 < 8
1862*f6dc9357SAndroid Build Coastguard Worker || dataSize2 > dataSize)
1863*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1864*f6dc9357SAndroid Build Coastguard Worker
1865*f6dc9357SAndroid Build Coastguard Worker const UInt32 numBlocks = GetUi32(buf + 0x100 + 4);
1866*f6dc9357SAndroid Build Coastguard Worker if (((dataSize2 - 4) >> 3) < numBlocks)
1867*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1868*f6dc9357SAndroid Build Coastguard Worker {
1869*f6dc9357SAndroid Build Coastguard Worker const UInt64 up = unpackSize + kCompressionBlockSize - 1;
1870*f6dc9357SAndroid Build Coastguard Worker if (up < unpackSize || up / kCompressionBlockSize != numBlocks)
1871*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1872*f6dc9357SAndroid Build Coastguard Worker }
1873*f6dc9357SAndroid Build Coastguard Worker
1874*f6dc9357SAndroid Build Coastguard Worker const UInt32 tableSize = (numBlocks << 3);
1875*f6dc9357SAndroid Build Coastguard Worker
1876*f6dc9357SAndroid Build Coastguard Worker _tableBuf.AllocAtLeast(tableSize);
1877*f6dc9357SAndroid Build Coastguard Worker
1878*f6dc9357SAndroid Build Coastguard Worker RINOK(ReadStream_FALSE(inStream, _tableBuf, tableSize))
1879*f6dc9357SAndroid Build Coastguard Worker const Byte *tableBuf = _tableBuf;
1880*f6dc9357SAndroid Build Coastguard Worker
1881*f6dc9357SAndroid Build Coastguard Worker UInt32 prev = 4 + tableSize;
1882*f6dc9357SAndroid Build Coastguard Worker
1883*f6dc9357SAndroid Build Coastguard Worker UInt32 i;
1884*f6dc9357SAndroid Build Coastguard Worker for (i = 0; i < numBlocks; i++)
1885*f6dc9357SAndroid Build Coastguard Worker {
1886*f6dc9357SAndroid Build Coastguard Worker const UInt32 offs = GetUi32(tableBuf + i * 8);
1887*f6dc9357SAndroid Build Coastguard Worker const UInt32 size = GetUi32(tableBuf + i * 8 + 4);
1888*f6dc9357SAndroid Build Coastguard Worker if (size == 0
1889*f6dc9357SAndroid Build Coastguard Worker || prev != offs
1890*f6dc9357SAndroid Build Coastguard Worker || offs > dataSize2
1891*f6dc9357SAndroid Build Coastguard Worker || size > dataSize2 - offs)
1892*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1893*f6dc9357SAndroid Build Coastguard Worker prev = offs + size;
1894*f6dc9357SAndroid Build Coastguard Worker }
1895*f6dc9357SAndroid Build Coastguard Worker
1896*f6dc9357SAndroid Build Coastguard Worker if (prev != dataSize2)
1897*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1898*f6dc9357SAndroid Build Coastguard Worker
1899*f6dc9357SAndroid Build Coastguard Worker CMyComPtr2_Create<ISequentialInStream, CBufInStream> bufInStream;
1900*f6dc9357SAndroid Build Coastguard Worker
1901*f6dc9357SAndroid Build Coastguard Worker // bool padError = false;
1902*f6dc9357SAndroid Build Coastguard Worker UInt64 outPos = 0;
1903*f6dc9357SAndroid Build Coastguard Worker
1904*f6dc9357SAndroid Build Coastguard Worker for (i = 0; i < numBlocks; i++)
1905*f6dc9357SAndroid Build Coastguard Worker {
1906*f6dc9357SAndroid Build Coastguard Worker const UInt64 rem = unpackSize - outPos;
1907*f6dc9357SAndroid Build Coastguard Worker if (rem == 0)
1908*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1909*f6dc9357SAndroid Build Coastguard Worker UInt32 blockSize = kCompressionBlockSize;
1910*f6dc9357SAndroid Build Coastguard Worker if (rem < kCompressionBlockSize)
1911*f6dc9357SAndroid Build Coastguard Worker blockSize = (UInt32)rem;
1912*f6dc9357SAndroid Build Coastguard Worker
1913*f6dc9357SAndroid Build Coastguard Worker const UInt32 size = GetUi32(tableBuf + i * 8 + 4);
1914*f6dc9357SAndroid Build Coastguard Worker
1915*f6dc9357SAndroid Build Coastguard Worker if (size > kCompressionBlockSize + 1)
1916*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1917*f6dc9357SAndroid Build Coastguard Worker
1918*f6dc9357SAndroid Build Coastguard Worker RINOK(ReadStream_FALSE(inStream, buf, size))
1919*f6dc9357SAndroid Build Coastguard Worker
1920*f6dc9357SAndroid Build Coastguard Worker if ((buf[0] & 0xF) == 0xF)
1921*f6dc9357SAndroid Build Coastguard Worker {
1922*f6dc9357SAndroid Build Coastguard Worker // (buf[0] = 0xff) is marker of uncompressed block in APFS
1923*f6dc9357SAndroid Build Coastguard Worker // that code was not tested in HFS
1924*f6dc9357SAndroid Build Coastguard Worker if (size - 1 != blockSize)
1925*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1926*f6dc9357SAndroid Build Coastguard Worker
1927*f6dc9357SAndroid Build Coastguard Worker if (outStream)
1928*f6dc9357SAndroid Build Coastguard Worker {
1929*f6dc9357SAndroid Build Coastguard Worker RINOK(WriteStream(outStream, buf + 1, blockSize))
1930*f6dc9357SAndroid Build Coastguard Worker }
1931*f6dc9357SAndroid Build Coastguard Worker }
1932*f6dc9357SAndroid Build Coastguard Worker else
1933*f6dc9357SAndroid Build Coastguard Worker {
1934*f6dc9357SAndroid Build Coastguard Worker const UInt64 blockSize64 = blockSize;
1935*f6dc9357SAndroid Build Coastguard Worker bufInStream->Init(buf, size);
1936*f6dc9357SAndroid Build Coastguard Worker RINOK(_zlibDecoder.Interface()->Code(bufInStream, outStream, NULL, &blockSize64, NULL))
1937*f6dc9357SAndroid Build Coastguard Worker if (_zlibDecoder->GetOutputProcessedSize() != blockSize)
1938*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1939*f6dc9357SAndroid Build Coastguard Worker const UInt64 inSize = _zlibDecoder->GetInputProcessedSize();
1940*f6dc9357SAndroid Build Coastguard Worker if (inSize != size)
1941*f6dc9357SAndroid Build Coastguard Worker {
1942*f6dc9357SAndroid Build Coastguard Worker if (inSize > size)
1943*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1944*f6dc9357SAndroid Build Coastguard Worker // apfs file can contain junk (non-zeros) after data block.
1945*f6dc9357SAndroid Build Coastguard Worker /*
1946*f6dc9357SAndroid Build Coastguard Worker if (!padError)
1947*f6dc9357SAndroid Build Coastguard Worker {
1948*f6dc9357SAndroid Build Coastguard Worker const Byte *p = buf + (UInt32)inSize;
1949*f6dc9357SAndroid Build Coastguard Worker const Byte *e = p + (size - (UInt32)inSize);
1950*f6dc9357SAndroid Build Coastguard Worker do
1951*f6dc9357SAndroid Build Coastguard Worker {
1952*f6dc9357SAndroid Build Coastguard Worker if (*p != 0)
1953*f6dc9357SAndroid Build Coastguard Worker {
1954*f6dc9357SAndroid Build Coastguard Worker padError = true;
1955*f6dc9357SAndroid Build Coastguard Worker break;
1956*f6dc9357SAndroid Build Coastguard Worker }
1957*f6dc9357SAndroid Build Coastguard Worker }
1958*f6dc9357SAndroid Build Coastguard Worker while (++p != e);
1959*f6dc9357SAndroid Build Coastguard Worker }
1960*f6dc9357SAndroid Build Coastguard Worker */
1961*f6dc9357SAndroid Build Coastguard Worker }
1962*f6dc9357SAndroid Build Coastguard Worker }
1963*f6dc9357SAndroid Build Coastguard Worker
1964*f6dc9357SAndroid Build Coastguard Worker outPos += blockSize;
1965*f6dc9357SAndroid Build Coastguard Worker if ((i & 0xFF) == 0)
1966*f6dc9357SAndroid Build Coastguard Worker {
1967*f6dc9357SAndroid Build Coastguard Worker const UInt64 progressPos = progressStart + outPos;
1968*f6dc9357SAndroid Build Coastguard Worker RINOK(extractCallback->SetCompleted(&progressPos))
1969*f6dc9357SAndroid Build Coastguard Worker }
1970*f6dc9357SAndroid Build Coastguard Worker }
1971*f6dc9357SAndroid Build Coastguard Worker
1972*f6dc9357SAndroid Build Coastguard Worker if (outPos != unpackSize)
1973*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1974*f6dc9357SAndroid Build Coastguard Worker
1975*f6dc9357SAndroid Build Coastguard Worker // if (padError) return S_FALSE;
1976*f6dc9357SAndroid Build Coastguard Worker
1977*f6dc9357SAndroid Build Coastguard Worker /* We check Resource Map
1978*f6dc9357SAndroid Build Coastguard Worker Are there HFS files with another values in Resource Map ??? */
1979*f6dc9357SAndroid Build Coastguard Worker
1980*f6dc9357SAndroid Build Coastguard Worker RINOK(ReadStream_FALSE(inStream, buf, mapSize))
1981*f6dc9357SAndroid Build Coastguard Worker const UInt32 types = Get16(buf + 24);
1982*f6dc9357SAndroid Build Coastguard Worker const UInt32 names = Get16(buf + 26);
1983*f6dc9357SAndroid Build Coastguard Worker const UInt32 numTypes = Get16(buf + 28);
1984*f6dc9357SAndroid Build Coastguard Worker if (numTypes != 0 || types != 28 || names != kResMapSize)
1985*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1986*f6dc9357SAndroid Build Coastguard Worker const UInt32 resType = Get32(buf + 30);
1987*f6dc9357SAndroid Build Coastguard Worker const UInt32 numResources = Get16(buf + 34);
1988*f6dc9357SAndroid Build Coastguard Worker const UInt32 resListOffset = Get16(buf + 36);
1989*f6dc9357SAndroid Build Coastguard Worker if (resType != 0x636D7066) // cmpf
1990*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1991*f6dc9357SAndroid Build Coastguard Worker if (numResources != 0 || resListOffset != 10)
1992*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
1993*f6dc9357SAndroid Build Coastguard Worker
1994*f6dc9357SAndroid Build Coastguard Worker const UInt32 entryId = Get16(buf + 38);
1995*f6dc9357SAndroid Build Coastguard Worker const UInt32 nameOffset = Get16(buf + 40);
1996*f6dc9357SAndroid Build Coastguard Worker // Byte attrib = buf[42];
1997*f6dc9357SAndroid Build Coastguard Worker const UInt32 resourceOffset = Get32(buf + 42) & 0xFFFFFF;
1998*f6dc9357SAndroid Build Coastguard Worker if (entryId != 1 || nameOffset != 0xFFFF || resourceOffset != 0)
1999*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
2000*f6dc9357SAndroid Build Coastguard Worker
2001*f6dc9357SAndroid Build Coastguard Worker return S_OK;
2002*f6dc9357SAndroid Build Coastguard Worker }
2003*f6dc9357SAndroid Build Coastguard Worker
2004*f6dc9357SAndroid Build Coastguard Worker
2005*f6dc9357SAndroid Build Coastguard Worker
2006*f6dc9357SAndroid Build Coastguard Worker HRESULT CDecoder::ExtractResourceFork_LZFSE(
2007*f6dc9357SAndroid Build Coastguard Worker ISequentialInStream *inStream, ISequentialOutStream *outStream,
2008*f6dc9357SAndroid Build Coastguard Worker UInt64 forkSize, UInt64 unpackSize,
2009*f6dc9357SAndroid Build Coastguard Worker UInt64 progressStart, IArchiveExtractCallback *extractCallback)
2010*f6dc9357SAndroid Build Coastguard Worker {
2011*f6dc9357SAndroid Build Coastguard Worker const UInt32 kNumBlocksMax = (UInt32)1 << 29;
2012*f6dc9357SAndroid Build Coastguard Worker if (unpackSize >= (UInt64)kNumBlocksMax * kCompressionBlockSize)
2013*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
2014*f6dc9357SAndroid Build Coastguard Worker const UInt32 numBlocks = (UInt32)((unpackSize + kCompressionBlockSize - 1) / kCompressionBlockSize);
2015*f6dc9357SAndroid Build Coastguard Worker const UInt32 numBlocks2 = numBlocks + 1;
2016*f6dc9357SAndroid Build Coastguard Worker const UInt32 tableSize = (numBlocks2 << 2);
2017*f6dc9357SAndroid Build Coastguard Worker if (tableSize > forkSize)
2018*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
2019*f6dc9357SAndroid Build Coastguard Worker _tableBuf.AllocAtLeast(tableSize);
2020*f6dc9357SAndroid Build Coastguard Worker RINOK(ReadStream_FALSE(inStream, _tableBuf, tableSize))
2021*f6dc9357SAndroid Build Coastguard Worker const Byte *tableBuf = _tableBuf;
2022*f6dc9357SAndroid Build Coastguard Worker
2023*f6dc9357SAndroid Build Coastguard Worker {
2024*f6dc9357SAndroid Build Coastguard Worker UInt32 prev = GetUi32(tableBuf);
2025*f6dc9357SAndroid Build Coastguard Worker if (prev != tableSize)
2026*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
2027*f6dc9357SAndroid Build Coastguard Worker for (UInt32 i = 1; i < numBlocks2; i++)
2028*f6dc9357SAndroid Build Coastguard Worker {
2029*f6dc9357SAndroid Build Coastguard Worker const UInt32 offs = GetUi32(tableBuf + i * 4);
2030*f6dc9357SAndroid Build Coastguard Worker if (offs <= prev)
2031*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
2032*f6dc9357SAndroid Build Coastguard Worker prev = offs;
2033*f6dc9357SAndroid Build Coastguard Worker }
2034*f6dc9357SAndroid Build Coastguard Worker if (prev != forkSize)
2035*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
2036*f6dc9357SAndroid Build Coastguard Worker }
2037*f6dc9357SAndroid Build Coastguard Worker
2038*f6dc9357SAndroid Build Coastguard Worker const size_t kBufSize = kCompressionBlockSize;
2039*f6dc9357SAndroid Build Coastguard Worker _buf.Alloc(kBufSize + 0x10); // we need 1 additional bytes for uncompressed chunk header
2040*f6dc9357SAndroid Build Coastguard Worker
2041*f6dc9357SAndroid Build Coastguard Worker CMyComPtr2_Create<ISequentialInStream, CBufInStream> bufInStream;
2042*f6dc9357SAndroid Build Coastguard Worker
2043*f6dc9357SAndroid Build Coastguard Worker UInt64 outPos = 0;
2044*f6dc9357SAndroid Build Coastguard Worker
2045*f6dc9357SAndroid Build Coastguard Worker for (UInt32 i = 0; i < numBlocks; i++)
2046*f6dc9357SAndroid Build Coastguard Worker {
2047*f6dc9357SAndroid Build Coastguard Worker const UInt64 rem = unpackSize - outPos;
2048*f6dc9357SAndroid Build Coastguard Worker if (rem == 0)
2049*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
2050*f6dc9357SAndroid Build Coastguard Worker UInt32 blockSize = kCompressionBlockSize;
2051*f6dc9357SAndroid Build Coastguard Worker if (rem < kCompressionBlockSize)
2052*f6dc9357SAndroid Build Coastguard Worker blockSize = (UInt32)rem;
2053*f6dc9357SAndroid Build Coastguard Worker
2054*f6dc9357SAndroid Build Coastguard Worker const UInt32 size =
2055*f6dc9357SAndroid Build Coastguard Worker GetUi32(tableBuf + i * 4 + 4) -
2056*f6dc9357SAndroid Build Coastguard Worker GetUi32(tableBuf + i * 4);
2057*f6dc9357SAndroid Build Coastguard Worker
2058*f6dc9357SAndroid Build Coastguard Worker if (size > kCompressionBlockSize + 1)
2059*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
2060*f6dc9357SAndroid Build Coastguard Worker
2061*f6dc9357SAndroid Build Coastguard Worker RINOK(ReadStream_FALSE(inStream, _buf, size))
2062*f6dc9357SAndroid Build Coastguard Worker const Byte *buf = _buf;
2063*f6dc9357SAndroid Build Coastguard Worker
2064*f6dc9357SAndroid Build Coastguard Worker if (buf[0] == k_LZVN_Uncompressed_Marker)
2065*f6dc9357SAndroid Build Coastguard Worker {
2066*f6dc9357SAndroid Build Coastguard Worker if (size - 1 != blockSize)
2067*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
2068*f6dc9357SAndroid Build Coastguard Worker if (outStream)
2069*f6dc9357SAndroid Build Coastguard Worker {
2070*f6dc9357SAndroid Build Coastguard Worker RINOK(WriteStream(outStream, buf + 1, blockSize))
2071*f6dc9357SAndroid Build Coastguard Worker }
2072*f6dc9357SAndroid Build Coastguard Worker }
2073*f6dc9357SAndroid Build Coastguard Worker else
2074*f6dc9357SAndroid Build Coastguard Worker {
2075*f6dc9357SAndroid Build Coastguard Worker const UInt64 blockSize64 = blockSize;
2076*f6dc9357SAndroid Build Coastguard Worker const UInt64 packSize64 = size;
2077*f6dc9357SAndroid Build Coastguard Worker bufInStream->Init(buf, size);
2078*f6dc9357SAndroid Build Coastguard Worker RINOK(_lzfseDecoder.Interface()->Code(bufInStream, outStream, &packSize64, &blockSize64, NULL))
2079*f6dc9357SAndroid Build Coastguard Worker // in/out sizes were checked in Code()
2080*f6dc9357SAndroid Build Coastguard Worker }
2081*f6dc9357SAndroid Build Coastguard Worker
2082*f6dc9357SAndroid Build Coastguard Worker outPos += blockSize;
2083*f6dc9357SAndroid Build Coastguard Worker if ((i & 0xFF) == 0)
2084*f6dc9357SAndroid Build Coastguard Worker {
2085*f6dc9357SAndroid Build Coastguard Worker const UInt64 progressPos = progressStart + outPos;
2086*f6dc9357SAndroid Build Coastguard Worker RINOK(extractCallback->SetCompleted(&progressPos))
2087*f6dc9357SAndroid Build Coastguard Worker }
2088*f6dc9357SAndroid Build Coastguard Worker }
2089*f6dc9357SAndroid Build Coastguard Worker
2090*f6dc9357SAndroid Build Coastguard Worker return S_OK;
2091*f6dc9357SAndroid Build Coastguard Worker }
2092*f6dc9357SAndroid Build Coastguard Worker
2093*f6dc9357SAndroid Build Coastguard Worker
2094*f6dc9357SAndroid Build Coastguard Worker /*
2095*f6dc9357SAndroid Build Coastguard Worker static UInt32 GetUi24(const Byte *p)
2096*f6dc9357SAndroid Build Coastguard Worker {
2097*f6dc9357SAndroid Build Coastguard Worker return p[0] + ((UInt32)p[1] << 8) + ((UInt32)p[2] << 24);
2098*f6dc9357SAndroid Build Coastguard Worker }
2099*f6dc9357SAndroid Build Coastguard Worker
2100*f6dc9357SAndroid Build Coastguard Worker HRESULT CDecoder::ExtractResourceFork_ZBM(
2101*f6dc9357SAndroid Build Coastguard Worker ISequentialInStream *inStream, ISequentialOutStream *outStream,
2102*f6dc9357SAndroid Build Coastguard Worker UInt64 forkSize, UInt64 unpackSize,
2103*f6dc9357SAndroid Build Coastguard Worker UInt64 progressStart, IArchiveExtractCallback *extractCallback)
2104*f6dc9357SAndroid Build Coastguard Worker {
2105*f6dc9357SAndroid Build Coastguard Worker const UInt32 kNumBlocksMax = (UInt32)1 << 29;
2106*f6dc9357SAndroid Build Coastguard Worker if (unpackSize >= (UInt64)kNumBlocksMax * kCompressionBlockSize)
2107*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
2108*f6dc9357SAndroid Build Coastguard Worker const UInt32 numBlocks = (UInt32)((unpackSize + kCompressionBlockSize - 1) / kCompressionBlockSize);
2109*f6dc9357SAndroid Build Coastguard Worker const UInt32 numBlocks2 = numBlocks + 1;
2110*f6dc9357SAndroid Build Coastguard Worker const UInt32 tableSize = (numBlocks2 << 2);
2111*f6dc9357SAndroid Build Coastguard Worker if (tableSize > forkSize)
2112*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
2113*f6dc9357SAndroid Build Coastguard Worker _tableBuf.AllocAtLeast(tableSize);
2114*f6dc9357SAndroid Build Coastguard Worker RINOK(ReadStream_FALSE(inStream, _tableBuf, tableSize));
2115*f6dc9357SAndroid Build Coastguard Worker const Byte *tableBuf = _tableBuf;
2116*f6dc9357SAndroid Build Coastguard Worker
2117*f6dc9357SAndroid Build Coastguard Worker {
2118*f6dc9357SAndroid Build Coastguard Worker UInt32 prev = GetUi32(tableBuf);
2119*f6dc9357SAndroid Build Coastguard Worker if (prev != tableSize)
2120*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
2121*f6dc9357SAndroid Build Coastguard Worker for (UInt32 i = 1; i < numBlocks2; i++)
2122*f6dc9357SAndroid Build Coastguard Worker {
2123*f6dc9357SAndroid Build Coastguard Worker const UInt32 offs = GetUi32(tableBuf + i * 4);
2124*f6dc9357SAndroid Build Coastguard Worker if (offs <= prev)
2125*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
2126*f6dc9357SAndroid Build Coastguard Worker prev = offs;
2127*f6dc9357SAndroid Build Coastguard Worker }
2128*f6dc9357SAndroid Build Coastguard Worker if (prev != forkSize)
2129*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
2130*f6dc9357SAndroid Build Coastguard Worker }
2131*f6dc9357SAndroid Build Coastguard Worker
2132*f6dc9357SAndroid Build Coastguard Worker const size_t kBufSize = kCompressionBlockSize;
2133*f6dc9357SAndroid Build Coastguard Worker _buf.Alloc(kBufSize + 0x10); // we need 1 additional bytes for uncompressed chunk header
2134*f6dc9357SAndroid Build Coastguard Worker
2135*f6dc9357SAndroid Build Coastguard Worker CBufInStream *bufInStream = new CBufInStream;
2136*f6dc9357SAndroid Build Coastguard Worker CMyComPtr<ISequentialInStream> bufInStream = bufInStream;
2137*f6dc9357SAndroid Build Coastguard Worker
2138*f6dc9357SAndroid Build Coastguard Worker UInt64 outPos = 0;
2139*f6dc9357SAndroid Build Coastguard Worker
2140*f6dc9357SAndroid Build Coastguard Worker for (UInt32 i = 0; i < numBlocks; i++)
2141*f6dc9357SAndroid Build Coastguard Worker {
2142*f6dc9357SAndroid Build Coastguard Worker const UInt64 rem = unpackSize - outPos;
2143*f6dc9357SAndroid Build Coastguard Worker if (rem == 0)
2144*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
2145*f6dc9357SAndroid Build Coastguard Worker UInt32 blockSize = kCompressionBlockSize;
2146*f6dc9357SAndroid Build Coastguard Worker if (rem < kCompressionBlockSize)
2147*f6dc9357SAndroid Build Coastguard Worker blockSize = (UInt32)rem;
2148*f6dc9357SAndroid Build Coastguard Worker
2149*f6dc9357SAndroid Build Coastguard Worker const UInt32 size =
2150*f6dc9357SAndroid Build Coastguard Worker GetUi32(tableBuf + i * 4 + 4) -
2151*f6dc9357SAndroid Build Coastguard Worker GetUi32(tableBuf + i * 4);
2152*f6dc9357SAndroid Build Coastguard Worker
2153*f6dc9357SAndroid Build Coastguard Worker // if (size > kCompressionBlockSize + 1)
2154*f6dc9357SAndroid Build Coastguard Worker if (size > blockSize + 1)
2155*f6dc9357SAndroid Build Coastguard Worker return S_FALSE; // we don't expect it, because encode will use uncompressed chunk
2156*f6dc9357SAndroid Build Coastguard Worker
2157*f6dc9357SAndroid Build Coastguard Worker RINOK(ReadStream_FALSE(inStream, _buf, size));
2158*f6dc9357SAndroid Build Coastguard Worker const Byte *buf = _buf;
2159*f6dc9357SAndroid Build Coastguard Worker
2160*f6dc9357SAndroid Build Coastguard Worker // (size != 0)
2161*f6dc9357SAndroid Build Coastguard Worker // if (size == 0) return S_FALSE;
2162*f6dc9357SAndroid Build Coastguard Worker
2163*f6dc9357SAndroid Build Coastguard Worker if (buf[0] == 0xFF) // uncompressed marker
2164*f6dc9357SAndroid Build Coastguard Worker {
2165*f6dc9357SAndroid Build Coastguard Worker if (size != blockSize + 1)
2166*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
2167*f6dc9357SAndroid Build Coastguard Worker if (outStream)
2168*f6dc9357SAndroid Build Coastguard Worker {
2169*f6dc9357SAndroid Build Coastguard Worker RINOK(WriteStream(outStream, buf + 1, blockSize));
2170*f6dc9357SAndroid Build Coastguard Worker }
2171*f6dc9357SAndroid Build Coastguard Worker }
2172*f6dc9357SAndroid Build Coastguard Worker else
2173*f6dc9357SAndroid Build Coastguard Worker {
2174*f6dc9357SAndroid Build Coastguard Worker if (size < 4)
2175*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
2176*f6dc9357SAndroid Build Coastguard Worker if (buf[0] != 'Z' ||
2177*f6dc9357SAndroid Build Coastguard Worker buf[1] != 'B' ||
2178*f6dc9357SAndroid Build Coastguard Worker buf[2] != 'M' ||
2179*f6dc9357SAndroid Build Coastguard Worker buf[3] != 9)
2180*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
2181*f6dc9357SAndroid Build Coastguard Worker // for debug:
2182*f6dc9357SAndroid Build Coastguard Worker unsigned packPos = 4;
2183*f6dc9357SAndroid Build Coastguard Worker unsigned unpackPos = 0;
2184*f6dc9357SAndroid Build Coastguard Worker unsigned packRem = size - packPos;
2185*f6dc9357SAndroid Build Coastguard Worker for (;;)
2186*f6dc9357SAndroid Build Coastguard Worker {
2187*f6dc9357SAndroid Build Coastguard Worker if (packRem < 6)
2188*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
2189*f6dc9357SAndroid Build Coastguard Worker const UInt32 packSize = GetUi24(buf + packPos);
2190*f6dc9357SAndroid Build Coastguard Worker const UInt32 chunkUnpackSize = GetUi24(buf + packPos + 3);
2191*f6dc9357SAndroid Build Coastguard Worker if (packSize < 6)
2192*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
2193*f6dc9357SAndroid Build Coastguard Worker if (packSize > packRem)
2194*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
2195*f6dc9357SAndroid Build Coastguard Worker if (chunkUnpackSize > blockSize - unpackPos)
2196*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
2197*f6dc9357SAndroid Build Coastguard Worker packPos += packSize;
2198*f6dc9357SAndroid Build Coastguard Worker packRem -= packSize;
2199*f6dc9357SAndroid Build Coastguard Worker unpackPos += chunkUnpackSize;
2200*f6dc9357SAndroid Build Coastguard Worker if (packSize == 6)
2201*f6dc9357SAndroid Build Coastguard Worker {
2202*f6dc9357SAndroid Build Coastguard Worker if (chunkUnpackSize != 0)
2203*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
2204*f6dc9357SAndroid Build Coastguard Worker break;
2205*f6dc9357SAndroid Build Coastguard Worker }
2206*f6dc9357SAndroid Build Coastguard Worker if (packSize >= chunkUnpackSize + 6)
2207*f6dc9357SAndroid Build Coastguard Worker {
2208*f6dc9357SAndroid Build Coastguard Worker if (packSize > chunkUnpackSize + 6)
2209*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
2210*f6dc9357SAndroid Build Coastguard Worker // uncompressed chunk;
2211*f6dc9357SAndroid Build Coastguard Worker }
2212*f6dc9357SAndroid Build Coastguard Worker else
2213*f6dc9357SAndroid Build Coastguard Worker {
2214*f6dc9357SAndroid Build Coastguard Worker // compressed chunk
2215*f6dc9357SAndroid Build Coastguard Worker const Byte *t = buf + packPos - packSize + 6;
2216*f6dc9357SAndroid Build Coastguard Worker UInt32 r = packSize - 6;
2217*f6dc9357SAndroid Build Coastguard Worker if (r < 9)
2218*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
2219*f6dc9357SAndroid Build Coastguard Worker const UInt32 v0 = GetUi24(t);
2220*f6dc9357SAndroid Build Coastguard Worker const UInt32 v1 = GetUi24(t + 3);
2221*f6dc9357SAndroid Build Coastguard Worker const UInt32 v2 = GetUi24(t + 6);
2222*f6dc9357SAndroid Build Coastguard Worker if (v0 > v1 || v1 > v2 || v2 > packSize)
2223*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
2224*f6dc9357SAndroid Build Coastguard Worker // here we need the code that will decompress ZBM chunk
2225*f6dc9357SAndroid Build Coastguard Worker }
2226*f6dc9357SAndroid Build Coastguard Worker }
2227*f6dc9357SAndroid Build Coastguard Worker
2228*f6dc9357SAndroid Build Coastguard Worker if (unpackPos != blockSize)
2229*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
2230*f6dc9357SAndroid Build Coastguard Worker
2231*f6dc9357SAndroid Build Coastguard Worker UInt32 size1 = size;
2232*f6dc9357SAndroid Build Coastguard Worker if (size1 > kCompressionBlockSize)
2233*f6dc9357SAndroid Build Coastguard Worker {
2234*f6dc9357SAndroid Build Coastguard Worker size1 = kCompressionBlockSize;
2235*f6dc9357SAndroid Build Coastguard Worker // return S_FALSE;
2236*f6dc9357SAndroid Build Coastguard Worker }
2237*f6dc9357SAndroid Build Coastguard Worker if (outStream)
2238*f6dc9357SAndroid Build Coastguard Worker {
2239*f6dc9357SAndroid Build Coastguard Worker RINOK(WriteStream(outStream, buf, size1))
2240*f6dc9357SAndroid Build Coastguard Worker
2241*f6dc9357SAndroid Build Coastguard Worker const UInt32 kTempSize = 1 << 16;
2242*f6dc9357SAndroid Build Coastguard Worker Byte temp[kTempSize];
2243*f6dc9357SAndroid Build Coastguard Worker memset(temp, 0, kTempSize);
2244*f6dc9357SAndroid Build Coastguard Worker
2245*f6dc9357SAndroid Build Coastguard Worker for (UInt32 k = size1; k < kCompressionBlockSize; k++)
2246*f6dc9357SAndroid Build Coastguard Worker {
2247*f6dc9357SAndroid Build Coastguard Worker UInt32 cur = kCompressionBlockSize - k;
2248*f6dc9357SAndroid Build Coastguard Worker if (cur > kTempSize)
2249*f6dc9357SAndroid Build Coastguard Worker cur = kTempSize;
2250*f6dc9357SAndroid Build Coastguard Worker RINOK(WriteStream(outStream, temp, cur))
2251*f6dc9357SAndroid Build Coastguard Worker k += cur;
2252*f6dc9357SAndroid Build Coastguard Worker }
2253*f6dc9357SAndroid Build Coastguard Worker }
2254*f6dc9357SAndroid Build Coastguard Worker
2255*f6dc9357SAndroid Build Coastguard Worker // const UInt64 blockSize64 = blockSize;
2256*f6dc9357SAndroid Build Coastguard Worker // const UInt64 packSize64 = size;
2257*f6dc9357SAndroid Build Coastguard Worker // bufInStream->Init(buf, size);
2258*f6dc9357SAndroid Build Coastguard Worker // RINOK(_zbmDecoderSpec->Code(bufInStream, outStream, &packSize64, &blockSize64, NULL));
2259*f6dc9357SAndroid Build Coastguard Worker // in/out sizes were checked in Code()
2260*f6dc9357SAndroid Build Coastguard Worker }
2261*f6dc9357SAndroid Build Coastguard Worker
2262*f6dc9357SAndroid Build Coastguard Worker outPos += blockSize;
2263*f6dc9357SAndroid Build Coastguard Worker if ((i & 0xFF) == 0)
2264*f6dc9357SAndroid Build Coastguard Worker {
2265*f6dc9357SAndroid Build Coastguard Worker const UInt64 progressPos = progressStart + outPos;
2266*f6dc9357SAndroid Build Coastguard Worker RINOK(extractCallback->SetCompleted(&progressPos));
2267*f6dc9357SAndroid Build Coastguard Worker }
2268*f6dc9357SAndroid Build Coastguard Worker }
2269*f6dc9357SAndroid Build Coastguard Worker
2270*f6dc9357SAndroid Build Coastguard Worker return S_OK;
2271*f6dc9357SAndroid Build Coastguard Worker }
2272*f6dc9357SAndroid Build Coastguard Worker */
2273*f6dc9357SAndroid Build Coastguard Worker
2274*f6dc9357SAndroid Build Coastguard Worker HRESULT CDecoder::Extract(
2275*f6dc9357SAndroid Build Coastguard Worker ISequentialInStream *inStreamFork, ISequentialOutStream *realOutStream,
2276*f6dc9357SAndroid Build Coastguard Worker UInt64 forkSize,
2277*f6dc9357SAndroid Build Coastguard Worker const CCompressHeader &compressHeader,
2278*f6dc9357SAndroid Build Coastguard Worker const CByteBuffer *data,
2279*f6dc9357SAndroid Build Coastguard Worker UInt64 progressStart, IArchiveExtractCallback *extractCallback,
2280*f6dc9357SAndroid Build Coastguard Worker int &opRes)
2281*f6dc9357SAndroid Build Coastguard Worker {
2282*f6dc9357SAndroid Build Coastguard Worker opRes = NExtract::NOperationResult::kDataError;
2283*f6dc9357SAndroid Build Coastguard Worker
2284*f6dc9357SAndroid Build Coastguard Worker if (compressHeader.IsMethod_Uncompressed_Inline())
2285*f6dc9357SAndroid Build Coastguard Worker {
2286*f6dc9357SAndroid Build Coastguard Worker const size_t packSize = data->Size() - compressHeader.DataPos;
2287*f6dc9357SAndroid Build Coastguard Worker if (realOutStream)
2288*f6dc9357SAndroid Build Coastguard Worker {
2289*f6dc9357SAndroid Build Coastguard Worker RINOK(WriteStream(realOutStream, *data + compressHeader.DataPos, packSize))
2290*f6dc9357SAndroid Build Coastguard Worker }
2291*f6dc9357SAndroid Build Coastguard Worker opRes = NExtract::NOperationResult::kOK;
2292*f6dc9357SAndroid Build Coastguard Worker return S_OK;
2293*f6dc9357SAndroid Build Coastguard Worker }
2294*f6dc9357SAndroid Build Coastguard Worker
2295*f6dc9357SAndroid Build Coastguard Worker if (compressHeader.Method == kMethod_ZLIB_ATTR ||
2296*f6dc9357SAndroid Build Coastguard Worker compressHeader.Method == kMethod_LZVN_ATTR)
2297*f6dc9357SAndroid Build Coastguard Worker {
2298*f6dc9357SAndroid Build Coastguard Worker CMyComPtr2_Create<ISequentialInStream, CBufInStream> bufInStream;
2299*f6dc9357SAndroid Build Coastguard Worker const size_t packSize = data->Size() - compressHeader.DataPos;
2300*f6dc9357SAndroid Build Coastguard Worker bufInStream->Init(*data + compressHeader.DataPos, packSize);
2301*f6dc9357SAndroid Build Coastguard Worker
2302*f6dc9357SAndroid Build Coastguard Worker if (compressHeader.Method == kMethod_ZLIB_ATTR)
2303*f6dc9357SAndroid Build Coastguard Worker {
2304*f6dc9357SAndroid Build Coastguard Worker const HRESULT hres = _zlibDecoder.Interface()->Code(bufInStream, realOutStream,
2305*f6dc9357SAndroid Build Coastguard Worker NULL, &compressHeader.UnpackSize, NULL);
2306*f6dc9357SAndroid Build Coastguard Worker if (hres == S_OK)
2307*f6dc9357SAndroid Build Coastguard Worker if (_zlibDecoder->GetOutputProcessedSize() == compressHeader.UnpackSize
2308*f6dc9357SAndroid Build Coastguard Worker && _zlibDecoder->GetInputProcessedSize() == packSize)
2309*f6dc9357SAndroid Build Coastguard Worker opRes = NExtract::NOperationResult::kOK;
2310*f6dc9357SAndroid Build Coastguard Worker return hres;
2311*f6dc9357SAndroid Build Coastguard Worker }
2312*f6dc9357SAndroid Build Coastguard Worker {
2313*f6dc9357SAndroid Build Coastguard Worker const UInt64 packSize64 = packSize;
2314*f6dc9357SAndroid Build Coastguard Worker const HRESULT hres = _lzfseDecoder.Interface()->Code(bufInStream, realOutStream,
2315*f6dc9357SAndroid Build Coastguard Worker &packSize64, &compressHeader.UnpackSize, NULL);
2316*f6dc9357SAndroid Build Coastguard Worker if (hres == S_OK)
2317*f6dc9357SAndroid Build Coastguard Worker {
2318*f6dc9357SAndroid Build Coastguard Worker // in/out sizes were checked in Code()
2319*f6dc9357SAndroid Build Coastguard Worker opRes = NExtract::NOperationResult::kOK;
2320*f6dc9357SAndroid Build Coastguard Worker }
2321*f6dc9357SAndroid Build Coastguard Worker return hres;
2322*f6dc9357SAndroid Build Coastguard Worker }
2323*f6dc9357SAndroid Build Coastguard Worker }
2324*f6dc9357SAndroid Build Coastguard Worker
2325*f6dc9357SAndroid Build Coastguard Worker HRESULT hres;
2326*f6dc9357SAndroid Build Coastguard Worker if (compressHeader.Method == NHfs::kMethod_ZLIB_RSRC)
2327*f6dc9357SAndroid Build Coastguard Worker {
2328*f6dc9357SAndroid Build Coastguard Worker hres = ExtractResourceFork_ZLIB(
2329*f6dc9357SAndroid Build Coastguard Worker inStreamFork, realOutStream,
2330*f6dc9357SAndroid Build Coastguard Worker forkSize, compressHeader.UnpackSize,
2331*f6dc9357SAndroid Build Coastguard Worker progressStart, extractCallback);
2332*f6dc9357SAndroid Build Coastguard Worker // for debug:
2333*f6dc9357SAndroid Build Coastguard Worker // hres = NCompress::CopyStream(inStreamFork, realOutStream, NULL);
2334*f6dc9357SAndroid Build Coastguard Worker }
2335*f6dc9357SAndroid Build Coastguard Worker else if (compressHeader.Method == NHfs::kMethod_LZVN_RSRC)
2336*f6dc9357SAndroid Build Coastguard Worker {
2337*f6dc9357SAndroid Build Coastguard Worker hres = ExtractResourceFork_LZFSE(
2338*f6dc9357SAndroid Build Coastguard Worker inStreamFork, realOutStream,
2339*f6dc9357SAndroid Build Coastguard Worker forkSize, compressHeader.UnpackSize,
2340*f6dc9357SAndroid Build Coastguard Worker progressStart, extractCallback);
2341*f6dc9357SAndroid Build Coastguard Worker }
2342*f6dc9357SAndroid Build Coastguard Worker /*
2343*f6dc9357SAndroid Build Coastguard Worker else if (compressHeader.Method == NHfs::kMethod_ZBM_RSRC)
2344*f6dc9357SAndroid Build Coastguard Worker {
2345*f6dc9357SAndroid Build Coastguard Worker hres = ExtractResourceFork_ZBM(
2346*f6dc9357SAndroid Build Coastguard Worker inStreamFork, realOutStream,
2347*f6dc9357SAndroid Build Coastguard Worker forkSize, compressHeader.UnpackSize,
2348*f6dc9357SAndroid Build Coastguard Worker progressStart, extractCallback);
2349*f6dc9357SAndroid Build Coastguard Worker }
2350*f6dc9357SAndroid Build Coastguard Worker */
2351*f6dc9357SAndroid Build Coastguard Worker else
2352*f6dc9357SAndroid Build Coastguard Worker {
2353*f6dc9357SAndroid Build Coastguard Worker opRes = NExtract::NOperationResult::kUnsupportedMethod;
2354*f6dc9357SAndroid Build Coastguard Worker hres = S_FALSE;
2355*f6dc9357SAndroid Build Coastguard Worker }
2356*f6dc9357SAndroid Build Coastguard Worker
2357*f6dc9357SAndroid Build Coastguard Worker if (hres == S_OK)
2358*f6dc9357SAndroid Build Coastguard Worker opRes = NExtract::NOperationResult::kOK;
2359*f6dc9357SAndroid Build Coastguard Worker return hres;
2360*f6dc9357SAndroid Build Coastguard Worker }
2361*f6dc9357SAndroid Build Coastguard Worker
2362*f6dc9357SAndroid Build Coastguard Worker
2363*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
2364*f6dc9357SAndroid Build Coastguard Worker Int32 testMode, IArchiveExtractCallback *extractCallback))
2365*f6dc9357SAndroid Build Coastguard Worker {
2366*f6dc9357SAndroid Build Coastguard Worker COM_TRY_BEGIN
2367*f6dc9357SAndroid Build Coastguard Worker const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
2368*f6dc9357SAndroid Build Coastguard Worker if (allFilesMode)
2369*f6dc9357SAndroid Build Coastguard Worker numItems = Refs.Size();
2370*f6dc9357SAndroid Build Coastguard Worker if (numItems == 0)
2371*f6dc9357SAndroid Build Coastguard Worker return S_OK;
2372*f6dc9357SAndroid Build Coastguard Worker UInt32 i;
2373*f6dc9357SAndroid Build Coastguard Worker UInt64 totalSize = 0;
2374*f6dc9357SAndroid Build Coastguard Worker for (i = 0; i < numItems; i++)
2375*f6dc9357SAndroid Build Coastguard Worker {
2376*f6dc9357SAndroid Build Coastguard Worker const CRef &ref = Refs[allFilesMode ? i : indices[i]];
2377*f6dc9357SAndroid Build Coastguard Worker totalSize += Get_UnpackSize_of_Ref(ref);
2378*f6dc9357SAndroid Build Coastguard Worker }
2379*f6dc9357SAndroid Build Coastguard Worker RINOK(extractCallback->SetTotal(totalSize))
2380*f6dc9357SAndroid Build Coastguard Worker
2381*f6dc9357SAndroid Build Coastguard Worker UInt64 currentTotalSize = 0, currentItemSize = 0;
2382*f6dc9357SAndroid Build Coastguard Worker
2383*f6dc9357SAndroid Build Coastguard Worker const size_t kBufSize = kCompressionBlockSize;
2384*f6dc9357SAndroid Build Coastguard Worker CByteBuffer buf(kBufSize + 0x10); // we need 1 additional bytes for uncompressed chunk header
2385*f6dc9357SAndroid Build Coastguard Worker
2386*f6dc9357SAndroid Build Coastguard Worker // there are hfs without adler in zlib.
2387*f6dc9357SAndroid Build Coastguard Worker CDecoder decoder(true); // IsAdlerOptional
2388*f6dc9357SAndroid Build Coastguard Worker
2389*f6dc9357SAndroid Build Coastguard Worker for (i = 0;; i++, currentTotalSize += currentItemSize)
2390*f6dc9357SAndroid Build Coastguard Worker {
2391*f6dc9357SAndroid Build Coastguard Worker RINOK(extractCallback->SetCompleted(¤tTotalSize))
2392*f6dc9357SAndroid Build Coastguard Worker if (i >= numItems)
2393*f6dc9357SAndroid Build Coastguard Worker break;
2394*f6dc9357SAndroid Build Coastguard Worker const UInt32 index = allFilesMode ? i : indices[i];
2395*f6dc9357SAndroid Build Coastguard Worker const CRef &ref = Refs[index];
2396*f6dc9357SAndroid Build Coastguard Worker const CItem &item = Items[ref.ItemIndex];
2397*f6dc9357SAndroid Build Coastguard Worker currentItemSize = Get_UnpackSize_of_Ref(ref);
2398*f6dc9357SAndroid Build Coastguard Worker
2399*f6dc9357SAndroid Build Coastguard Worker int opRes;
2400*f6dc9357SAndroid Build Coastguard Worker {
2401*f6dc9357SAndroid Build Coastguard Worker CMyComPtr<ISequentialOutStream> realOutStream;
2402*f6dc9357SAndroid Build Coastguard Worker const Int32 askMode = testMode ?
2403*f6dc9357SAndroid Build Coastguard Worker NExtract::NAskMode::kTest :
2404*f6dc9357SAndroid Build Coastguard Worker NExtract::NAskMode::kExtract;
2405*f6dc9357SAndroid Build Coastguard Worker RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
2406*f6dc9357SAndroid Build Coastguard Worker
2407*f6dc9357SAndroid Build Coastguard Worker if (ref.IsItem() && item.IsDir())
2408*f6dc9357SAndroid Build Coastguard Worker {
2409*f6dc9357SAndroid Build Coastguard Worker RINOK(extractCallback->PrepareOperation(askMode))
2410*f6dc9357SAndroid Build Coastguard Worker RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
2411*f6dc9357SAndroid Build Coastguard Worker continue;
2412*f6dc9357SAndroid Build Coastguard Worker }
2413*f6dc9357SAndroid Build Coastguard Worker if (!testMode && !realOutStream)
2414*f6dc9357SAndroid Build Coastguard Worker continue;
2415*f6dc9357SAndroid Build Coastguard Worker
2416*f6dc9357SAndroid Build Coastguard Worker RINOK(extractCallback->PrepareOperation(askMode))
2417*f6dc9357SAndroid Build Coastguard Worker
2418*f6dc9357SAndroid Build Coastguard Worker UInt64 pos = 0;
2419*f6dc9357SAndroid Build Coastguard Worker opRes = NExtract::NOperationResult::kDataError;
2420*f6dc9357SAndroid Build Coastguard Worker const CFork *fork = NULL;
2421*f6dc9357SAndroid Build Coastguard Worker
2422*f6dc9357SAndroid Build Coastguard Worker if (ref.AttrIndex >= 0)
2423*f6dc9357SAndroid Build Coastguard Worker {
2424*f6dc9357SAndroid Build Coastguard Worker const CAttr &attr = Attrs[ref.AttrIndex];
2425*f6dc9357SAndroid Build Coastguard Worker if (attr.Fork_defined && attr.Data.Size() == 0)
2426*f6dc9357SAndroid Build Coastguard Worker fork = &attr.Fork;
2427*f6dc9357SAndroid Build Coastguard Worker else
2428*f6dc9357SAndroid Build Coastguard Worker {
2429*f6dc9357SAndroid Build Coastguard Worker opRes = NExtract::NOperationResult::kOK;
2430*f6dc9357SAndroid Build Coastguard Worker if (realOutStream)
2431*f6dc9357SAndroid Build Coastguard Worker {
2432*f6dc9357SAndroid Build Coastguard Worker RINOK(WriteStream(realOutStream,
2433*f6dc9357SAndroid Build Coastguard Worker // AttrBuf + attr.Pos, attr.Size
2434*f6dc9357SAndroid Build Coastguard Worker attr.Data, attr.Data.Size()
2435*f6dc9357SAndroid Build Coastguard Worker ))
2436*f6dc9357SAndroid Build Coastguard Worker }
2437*f6dc9357SAndroid Build Coastguard Worker }
2438*f6dc9357SAndroid Build Coastguard Worker }
2439*f6dc9357SAndroid Build Coastguard Worker else if (ref.IsResource())
2440*f6dc9357SAndroid Build Coastguard Worker fork = &item.ResourceFork;
2441*f6dc9357SAndroid Build Coastguard Worker else if (item.CompressHeader.IsSupported)
2442*f6dc9357SAndroid Build Coastguard Worker {
2443*f6dc9357SAndroid Build Coastguard Worker CMyComPtr<ISequentialInStream> inStreamFork;
2444*f6dc9357SAndroid Build Coastguard Worker UInt64 forkSize = 0;
2445*f6dc9357SAndroid Build Coastguard Worker const CByteBuffer *decmpfs_Data = NULL;
2446*f6dc9357SAndroid Build Coastguard Worker
2447*f6dc9357SAndroid Build Coastguard Worker if (item.CompressHeader.IsMethod_Resource())
2448*f6dc9357SAndroid Build Coastguard Worker {
2449*f6dc9357SAndroid Build Coastguard Worker const CFork &resourceFork = item.ResourceFork;
2450*f6dc9357SAndroid Build Coastguard Worker forkSize = resourceFork.Size;
2451*f6dc9357SAndroid Build Coastguard Worker GetForkStream(resourceFork, &inStreamFork);
2452*f6dc9357SAndroid Build Coastguard Worker }
2453*f6dc9357SAndroid Build Coastguard Worker else
2454*f6dc9357SAndroid Build Coastguard Worker {
2455*f6dc9357SAndroid Build Coastguard Worker const CAttr &attr = Attrs[item.decmpfs_AttrIndex];
2456*f6dc9357SAndroid Build Coastguard Worker decmpfs_Data = &attr.Data;
2457*f6dc9357SAndroid Build Coastguard Worker }
2458*f6dc9357SAndroid Build Coastguard Worker
2459*f6dc9357SAndroid Build Coastguard Worker if (inStreamFork || decmpfs_Data)
2460*f6dc9357SAndroid Build Coastguard Worker {
2461*f6dc9357SAndroid Build Coastguard Worker const HRESULT hres = decoder.Extract(
2462*f6dc9357SAndroid Build Coastguard Worker inStreamFork, realOutStream,
2463*f6dc9357SAndroid Build Coastguard Worker forkSize,
2464*f6dc9357SAndroid Build Coastguard Worker item.CompressHeader,
2465*f6dc9357SAndroid Build Coastguard Worker decmpfs_Data,
2466*f6dc9357SAndroid Build Coastguard Worker currentTotalSize, extractCallback,
2467*f6dc9357SAndroid Build Coastguard Worker opRes);
2468*f6dc9357SAndroid Build Coastguard Worker if (hres != S_FALSE && hres != S_OK)
2469*f6dc9357SAndroid Build Coastguard Worker return hres;
2470*f6dc9357SAndroid Build Coastguard Worker }
2471*f6dc9357SAndroid Build Coastguard Worker }
2472*f6dc9357SAndroid Build Coastguard Worker else if (item.CompressHeader.IsCorrect)
2473*f6dc9357SAndroid Build Coastguard Worker opRes = NExtract::NOperationResult::kUnsupportedMethod;
2474*f6dc9357SAndroid Build Coastguard Worker else
2475*f6dc9357SAndroid Build Coastguard Worker fork = &item.DataFork;
2476*f6dc9357SAndroid Build Coastguard Worker
2477*f6dc9357SAndroid Build Coastguard Worker if (fork)
2478*f6dc9357SAndroid Build Coastguard Worker {
2479*f6dc9357SAndroid Build Coastguard Worker if (fork->IsOk(Header.BlockSizeLog))
2480*f6dc9357SAndroid Build Coastguard Worker {
2481*f6dc9357SAndroid Build Coastguard Worker opRes = NExtract::NOperationResult::kOK;
2482*f6dc9357SAndroid Build Coastguard Worker unsigned extentIndex;
2483*f6dc9357SAndroid Build Coastguard Worker for (extentIndex = 0; extentIndex < fork->Extents.Size(); extentIndex++)
2484*f6dc9357SAndroid Build Coastguard Worker {
2485*f6dc9357SAndroid Build Coastguard Worker if (opRes != NExtract::NOperationResult::kOK)
2486*f6dc9357SAndroid Build Coastguard Worker break;
2487*f6dc9357SAndroid Build Coastguard Worker if (fork->Size == pos)
2488*f6dc9357SAndroid Build Coastguard Worker break;
2489*f6dc9357SAndroid Build Coastguard Worker const CExtent &e = fork->Extents[extentIndex];
2490*f6dc9357SAndroid Build Coastguard Worker RINOK(InStream_SeekSet(_stream, SpecOffset + ((UInt64)e.Pos << Header.BlockSizeLog)))
2491*f6dc9357SAndroid Build Coastguard Worker UInt64 extentRem = (UInt64)e.NumBlocks << Header.BlockSizeLog;
2492*f6dc9357SAndroid Build Coastguard Worker while (extentRem != 0)
2493*f6dc9357SAndroid Build Coastguard Worker {
2494*f6dc9357SAndroid Build Coastguard Worker const UInt64 rem = fork->Size - pos;
2495*f6dc9357SAndroid Build Coastguard Worker if (rem == 0)
2496*f6dc9357SAndroid Build Coastguard Worker {
2497*f6dc9357SAndroid Build Coastguard Worker // Here we check that there are no extra (empty) blocks in last extent.
2498*f6dc9357SAndroid Build Coastguard Worker if (extentRem >= ((UInt64)1 << Header.BlockSizeLog))
2499*f6dc9357SAndroid Build Coastguard Worker opRes = NExtract::NOperationResult::kDataError;
2500*f6dc9357SAndroid Build Coastguard Worker break;
2501*f6dc9357SAndroid Build Coastguard Worker }
2502*f6dc9357SAndroid Build Coastguard Worker size_t cur = kBufSize;
2503*f6dc9357SAndroid Build Coastguard Worker if (cur > rem)
2504*f6dc9357SAndroid Build Coastguard Worker cur = (size_t)rem;
2505*f6dc9357SAndroid Build Coastguard Worker if (cur > extentRem)
2506*f6dc9357SAndroid Build Coastguard Worker cur = (size_t)extentRem;
2507*f6dc9357SAndroid Build Coastguard Worker RINOK(ReadStream(_stream, buf, &cur))
2508*f6dc9357SAndroid Build Coastguard Worker if (cur == 0)
2509*f6dc9357SAndroid Build Coastguard Worker {
2510*f6dc9357SAndroid Build Coastguard Worker opRes = NExtract::NOperationResult::kDataError;
2511*f6dc9357SAndroid Build Coastguard Worker break;
2512*f6dc9357SAndroid Build Coastguard Worker }
2513*f6dc9357SAndroid Build Coastguard Worker if (realOutStream)
2514*f6dc9357SAndroid Build Coastguard Worker {
2515*f6dc9357SAndroid Build Coastguard Worker RINOK(WriteStream(realOutStream, buf, cur))
2516*f6dc9357SAndroid Build Coastguard Worker }
2517*f6dc9357SAndroid Build Coastguard Worker pos += cur;
2518*f6dc9357SAndroid Build Coastguard Worker extentRem -= cur;
2519*f6dc9357SAndroid Build Coastguard Worker const UInt64 processed = currentTotalSize + pos;
2520*f6dc9357SAndroid Build Coastguard Worker RINOK(extractCallback->SetCompleted(&processed))
2521*f6dc9357SAndroid Build Coastguard Worker }
2522*f6dc9357SAndroid Build Coastguard Worker }
2523*f6dc9357SAndroid Build Coastguard Worker if (extentIndex != fork->Extents.Size() || fork->Size != pos)
2524*f6dc9357SAndroid Build Coastguard Worker opRes = NExtract::NOperationResult::kDataError;
2525*f6dc9357SAndroid Build Coastguard Worker }
2526*f6dc9357SAndroid Build Coastguard Worker }
2527*f6dc9357SAndroid Build Coastguard Worker }
2528*f6dc9357SAndroid Build Coastguard Worker RINOK(extractCallback->SetOperationResult(opRes))
2529*f6dc9357SAndroid Build Coastguard Worker }
2530*f6dc9357SAndroid Build Coastguard Worker return S_OK;
2531*f6dc9357SAndroid Build Coastguard Worker COM_TRY_END
2532*f6dc9357SAndroid Build Coastguard Worker }
2533*f6dc9357SAndroid Build Coastguard Worker
2534*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
2535*f6dc9357SAndroid Build Coastguard Worker {
2536*f6dc9357SAndroid Build Coastguard Worker *numItems = Refs.Size();
2537*f6dc9357SAndroid Build Coastguard Worker return S_OK;
2538*f6dc9357SAndroid Build Coastguard Worker }
2539*f6dc9357SAndroid Build Coastguard Worker
2540*f6dc9357SAndroid Build Coastguard Worker HRESULT CHandler::GetForkStream(const CFork &fork, ISequentialInStream **stream)
2541*f6dc9357SAndroid Build Coastguard Worker {
2542*f6dc9357SAndroid Build Coastguard Worker *stream = NULL;
2543*f6dc9357SAndroid Build Coastguard Worker
2544*f6dc9357SAndroid Build Coastguard Worker if (!fork.IsOk(Header.BlockSizeLog))
2545*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
2546*f6dc9357SAndroid Build Coastguard Worker
2547*f6dc9357SAndroid Build Coastguard Worker CMyComPtr2<ISequentialInStream, CExtentsStream> extentStream;
2548*f6dc9357SAndroid Build Coastguard Worker extentStream.Create_if_Empty();
2549*f6dc9357SAndroid Build Coastguard Worker
2550*f6dc9357SAndroid Build Coastguard Worker UInt64 rem = fork.Size;
2551*f6dc9357SAndroid Build Coastguard Worker UInt64 virt = 0;
2552*f6dc9357SAndroid Build Coastguard Worker
2553*f6dc9357SAndroid Build Coastguard Worker FOR_VECTOR (i, fork.Extents)
2554*f6dc9357SAndroid Build Coastguard Worker {
2555*f6dc9357SAndroid Build Coastguard Worker const CExtent &e = fork.Extents[i];
2556*f6dc9357SAndroid Build Coastguard Worker if (e.NumBlocks == 0)
2557*f6dc9357SAndroid Build Coastguard Worker continue;
2558*f6dc9357SAndroid Build Coastguard Worker UInt64 cur = ((UInt64)e.NumBlocks << Header.BlockSizeLog);
2559*f6dc9357SAndroid Build Coastguard Worker if (cur > rem)
2560*f6dc9357SAndroid Build Coastguard Worker {
2561*f6dc9357SAndroid Build Coastguard Worker cur = rem;
2562*f6dc9357SAndroid Build Coastguard Worker if (i != fork.Extents.Size() - 1)
2563*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
2564*f6dc9357SAndroid Build Coastguard Worker }
2565*f6dc9357SAndroid Build Coastguard Worker CSeekExtent se;
2566*f6dc9357SAndroid Build Coastguard Worker se.Phy = SpecOffset + ((UInt64)e.Pos << Header.BlockSizeLog);
2567*f6dc9357SAndroid Build Coastguard Worker se.Virt = virt;
2568*f6dc9357SAndroid Build Coastguard Worker virt += cur;
2569*f6dc9357SAndroid Build Coastguard Worker rem -= cur;
2570*f6dc9357SAndroid Build Coastguard Worker extentStream->Extents.Add(se);
2571*f6dc9357SAndroid Build Coastguard Worker }
2572*f6dc9357SAndroid Build Coastguard Worker
2573*f6dc9357SAndroid Build Coastguard Worker if (rem != 0)
2574*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
2575*f6dc9357SAndroid Build Coastguard Worker
2576*f6dc9357SAndroid Build Coastguard Worker CSeekExtent se;
2577*f6dc9357SAndroid Build Coastguard Worker se.Phy = 0; // = SpecOffset ?
2578*f6dc9357SAndroid Build Coastguard Worker se.Virt = virt;
2579*f6dc9357SAndroid Build Coastguard Worker extentStream->Extents.Add(se);
2580*f6dc9357SAndroid Build Coastguard Worker extentStream->Stream = _stream;
2581*f6dc9357SAndroid Build Coastguard Worker extentStream->Init();
2582*f6dc9357SAndroid Build Coastguard Worker *stream = extentStream.Detach();
2583*f6dc9357SAndroid Build Coastguard Worker return S_OK;
2584*f6dc9357SAndroid Build Coastguard Worker }
2585*f6dc9357SAndroid Build Coastguard Worker
2586*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
2587*f6dc9357SAndroid Build Coastguard Worker {
2588*f6dc9357SAndroid Build Coastguard Worker *stream = NULL;
2589*f6dc9357SAndroid Build Coastguard Worker
2590*f6dc9357SAndroid Build Coastguard Worker const CRef &ref = Refs[index];
2591*f6dc9357SAndroid Build Coastguard Worker const CFork *fork = NULL;
2592*f6dc9357SAndroid Build Coastguard Worker if (ref.AttrIndex >= 0)
2593*f6dc9357SAndroid Build Coastguard Worker {
2594*f6dc9357SAndroid Build Coastguard Worker const CAttr &attr = Attrs[ref.AttrIndex];
2595*f6dc9357SAndroid Build Coastguard Worker if (!attr.Fork_defined || attr.Data.Size() != 0)
2596*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
2597*f6dc9357SAndroid Build Coastguard Worker fork = &attr.Fork;
2598*f6dc9357SAndroid Build Coastguard Worker }
2599*f6dc9357SAndroid Build Coastguard Worker else
2600*f6dc9357SAndroid Build Coastguard Worker {
2601*f6dc9357SAndroid Build Coastguard Worker const CItem &item = Items[ref.ItemIndex];
2602*f6dc9357SAndroid Build Coastguard Worker if (ref.IsResource())
2603*f6dc9357SAndroid Build Coastguard Worker fork = &item.ResourceFork;
2604*f6dc9357SAndroid Build Coastguard Worker else if (item.IsDir())
2605*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
2606*f6dc9357SAndroid Build Coastguard Worker else if (item.CompressHeader.IsCorrect)
2607*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
2608*f6dc9357SAndroid Build Coastguard Worker else
2609*f6dc9357SAndroid Build Coastguard Worker fork = &item.DataFork;
2610*f6dc9357SAndroid Build Coastguard Worker }
2611*f6dc9357SAndroid Build Coastguard Worker return GetForkStream(*fork, stream);
2612*f6dc9357SAndroid Build Coastguard Worker }
2613*f6dc9357SAndroid Build Coastguard Worker
2614*f6dc9357SAndroid Build Coastguard Worker static const Byte k_Signature[] = {
2615*f6dc9357SAndroid Build Coastguard Worker 2, 'B', 'D',
2616*f6dc9357SAndroid Build Coastguard Worker 4, 'H', '+', 0, 4,
2617*f6dc9357SAndroid Build Coastguard Worker 4, 'H', 'X', 0, 5 };
2618*f6dc9357SAndroid Build Coastguard Worker
2619*f6dc9357SAndroid Build Coastguard Worker REGISTER_ARC_I(
2620*f6dc9357SAndroid Build Coastguard Worker "HFS", "hfs hfsx", NULL, 0xE3,
2621*f6dc9357SAndroid Build Coastguard Worker k_Signature,
2622*f6dc9357SAndroid Build Coastguard Worker kHeaderPadSize,
2623*f6dc9357SAndroid Build Coastguard Worker NArcInfoFlags::kMultiSignature,
2624*f6dc9357SAndroid Build Coastguard Worker IsArc_HFS)
2625*f6dc9357SAndroid Build Coastguard Worker
2626*f6dc9357SAndroid Build Coastguard Worker }}
2627