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