xref: /aosp_15_r20/external/lzma/CPP/7zip/Archive/ExtHandler.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1*f6dc9357SAndroid Build Coastguard Worker // ExtHandler.cpp
2*f6dc9357SAndroid Build Coastguard Worker 
3*f6dc9357SAndroid Build Coastguard Worker #include "StdAfx.h"
4*f6dc9357SAndroid Build Coastguard Worker 
5*f6dc9357SAndroid Build Coastguard Worker // #define SHOW_DEBUG_INFO
6*f6dc9357SAndroid Build Coastguard Worker 
7*f6dc9357SAndroid Build Coastguard Worker // #include <stdio.h>
8*f6dc9357SAndroid Build Coastguard Worker // #define PRF2(x) x
9*f6dc9357SAndroid Build Coastguard Worker 
10*f6dc9357SAndroid Build Coastguard Worker #define PRF2(x)
11*f6dc9357SAndroid Build Coastguard Worker 
12*f6dc9357SAndroid Build Coastguard Worker #ifdef SHOW_DEBUG_INFO
13*f6dc9357SAndroid Build Coastguard Worker #include <stdio.h>
14*f6dc9357SAndroid Build Coastguard Worker #define PRF(x) x
15*f6dc9357SAndroid Build Coastguard Worker #else
16*f6dc9357SAndroid Build Coastguard Worker #define PRF(x)
17*f6dc9357SAndroid Build Coastguard Worker #endif
18*f6dc9357SAndroid Build Coastguard Worker 
19*f6dc9357SAndroid Build Coastguard Worker #include "../../../C/Alloc.h"
20*f6dc9357SAndroid Build Coastguard Worker #include "../../../C/CpuArch.h"
21*f6dc9357SAndroid Build Coastguard Worker 
22*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/ComTry.h"
23*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/IntToString.h"
24*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/MyLinux.h"
25*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/StringConvert.h"
26*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/UTFConvert.h"
27*f6dc9357SAndroid Build Coastguard Worker 
28*f6dc9357SAndroid Build Coastguard Worker #include "../../Windows/PropVariantUtils.h"
29*f6dc9357SAndroid Build Coastguard Worker #include "../../Windows/TimeUtils.h"
30*f6dc9357SAndroid Build Coastguard Worker 
31*f6dc9357SAndroid Build Coastguard Worker #include "../Common/ProgressUtils.h"
32*f6dc9357SAndroid Build Coastguard Worker #include "../Common/RegisterArc.h"
33*f6dc9357SAndroid Build Coastguard Worker #include "../Common/StreamObjects.h"
34*f6dc9357SAndroid Build Coastguard Worker #include "../Common/StreamUtils.h"
35*f6dc9357SAndroid Build Coastguard Worker 
36*f6dc9357SAndroid Build Coastguard Worker #include "../Compress/CopyCoder.h"
37*f6dc9357SAndroid Build Coastguard Worker 
38*f6dc9357SAndroid Build Coastguard Worker using namespace NWindows;
39*f6dc9357SAndroid Build Coastguard Worker 
40*f6dc9357SAndroid Build Coastguard Worker UInt32 LzhCrc16Update(UInt32 crc, const void *data, size_t size);
41*f6dc9357SAndroid Build Coastguard Worker 
42*f6dc9357SAndroid Build Coastguard Worker namespace NArchive {
43*f6dc9357SAndroid Build Coastguard Worker namespace NExt {
44*f6dc9357SAndroid Build Coastguard Worker 
45*f6dc9357SAndroid Build Coastguard Worker #define Get16(p) GetUi16(p)
46*f6dc9357SAndroid Build Coastguard Worker #define Get32(p) GetUi32(p)
47*f6dc9357SAndroid Build Coastguard Worker #define Get64(p) GetUi64(p)
48*f6dc9357SAndroid Build Coastguard Worker 
49*f6dc9357SAndroid Build Coastguard Worker #define LE_16(offs, dest) dest = Get16(p + (offs));
50*f6dc9357SAndroid Build Coastguard Worker #define LE_32(offs, dest) dest = Get32(p + (offs));
51*f6dc9357SAndroid Build Coastguard Worker #define LE_64(offs, dest) dest = Get64(p + (offs));
52*f6dc9357SAndroid Build Coastguard Worker 
53*f6dc9357SAndroid Build Coastguard Worker #define HI_16(offs, dest) dest |= (((UInt32)Get16(p + (offs))) << 16);
54*f6dc9357SAndroid Build Coastguard Worker #define HI_32(offs, dest) dest |= (((UInt64)Get32(p + (offs))) << 32);
55*f6dc9357SAndroid Build Coastguard Worker 
56*f6dc9357SAndroid Build Coastguard Worker /*
57*f6dc9357SAndroid Build Coastguard Worker static UInt32 g_Crc32CTable[256];
58*f6dc9357SAndroid Build Coastguard Worker 
59*f6dc9357SAndroid Build Coastguard Worker static struct CInitCrc32C
60*f6dc9357SAndroid Build Coastguard Worker {
61*f6dc9357SAndroid Build Coastguard Worker   CInitCrc32C()
62*f6dc9357SAndroid Build Coastguard Worker   {
63*f6dc9357SAndroid Build Coastguard Worker     for (unsigned i = 0; i < 256; i++)
64*f6dc9357SAndroid Build Coastguard Worker     {
65*f6dc9357SAndroid Build Coastguard Worker       UInt32 r = i;
66*f6dc9357SAndroid Build Coastguard Worker       unsigned j;
67*f6dc9357SAndroid Build Coastguard Worker       for (j = 0; j < 8; j++)
68*f6dc9357SAndroid Build Coastguard Worker         r = (r >> 1) ^ (0x82F63B78 & ~((r & 1) - 1));
69*f6dc9357SAndroid Build Coastguard Worker       g_Crc32CTable[i] = r;
70*f6dc9357SAndroid Build Coastguard Worker     }
71*f6dc9357SAndroid Build Coastguard Worker   }
72*f6dc9357SAndroid Build Coastguard Worker } g_InitCrc32C;
73*f6dc9357SAndroid Build Coastguard Worker 
74*f6dc9357SAndroid Build Coastguard Worker #define CRC32C_INIT_VAL 0xFFFFFFFF
75*f6dc9357SAndroid Build Coastguard Worker #define CRC32C_GET_DIGEST(crc) ((crc) ^ CRC_INIT_VAL)
76*f6dc9357SAndroid Build Coastguard Worker #define CRC32C_UPDATE_BYTE(crc, b) (g_Crc32CTable[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
77*f6dc9357SAndroid Build Coastguard Worker 
78*f6dc9357SAndroid Build Coastguard Worker static UInt32 Crc32C_Update(UInt32 crc, Byte const *data, size_t size)
79*f6dc9357SAndroid Build Coastguard Worker {
80*f6dc9357SAndroid Build Coastguard Worker   for (size_t i = 0; i < size; i++)
81*f6dc9357SAndroid Build Coastguard Worker     crc = CRC32C_UPDATE_BYTE(crc, data[i]);
82*f6dc9357SAndroid Build Coastguard Worker   return crc;
83*f6dc9357SAndroid Build Coastguard Worker }
84*f6dc9357SAndroid Build Coastguard Worker 
85*f6dc9357SAndroid Build Coastguard Worker static UInt32 Crc32C_Calc(Byte const *data, size_t size)
86*f6dc9357SAndroid Build Coastguard Worker {
87*f6dc9357SAndroid Build Coastguard Worker   return Crc32C_Update(CRC32C_INIT_VAL, data, size);
88*f6dc9357SAndroid Build Coastguard Worker }
89*f6dc9357SAndroid Build Coastguard Worker */
90*f6dc9357SAndroid Build Coastguard Worker 
91*f6dc9357SAndroid Build Coastguard Worker 
92*f6dc9357SAndroid Build Coastguard Worker #define CRC16_INIT_VAL 0xFFFF
93*f6dc9357SAndroid Build Coastguard Worker 
94*f6dc9357SAndroid Build Coastguard Worker #define Crc16Update(crc, data, size)  LzhCrc16Update(crc, data, size)
95*f6dc9357SAndroid Build Coastguard Worker 
Crc16Calc(Byte const * data,size_t size)96*f6dc9357SAndroid Build Coastguard Worker static UInt32 Crc16Calc(Byte const *data, size_t size)
97*f6dc9357SAndroid Build Coastguard Worker {
98*f6dc9357SAndroid Build Coastguard Worker   return Crc16Update(CRC16_INIT_VAL, data, size);
99*f6dc9357SAndroid Build Coastguard Worker }
100*f6dc9357SAndroid Build Coastguard Worker 
101*f6dc9357SAndroid Build Coastguard Worker 
102*f6dc9357SAndroid Build Coastguard Worker #define EXT4_GOOD_OLD_INODE_SIZE 128
103*f6dc9357SAndroid Build Coastguard Worker #define EXT_NODE_SIZE_MIN 128
104*f6dc9357SAndroid Build Coastguard Worker 
105*f6dc9357SAndroid Build Coastguard Worker 
106*f6dc9357SAndroid Build Coastguard Worker // inodes numbers
107*f6dc9357SAndroid Build Coastguard Worker 
108*f6dc9357SAndroid Build Coastguard Worker // #define k_INODE_BAD          1  // Bad blocks
109*f6dc9357SAndroid Build Coastguard Worker #define k_INODE_ROOT         2  // Root dir
110*f6dc9357SAndroid Build Coastguard Worker // #define k_INODE_USR_QUOTA    3  // User quota
111*f6dc9357SAndroid Build Coastguard Worker // #define k_INODE_GRP_QUOTA    4  // Group quota
112*f6dc9357SAndroid Build Coastguard Worker // #define k_INODE_BOOT_LOADER  5  // Boot loader
113*f6dc9357SAndroid Build Coastguard Worker // #define k_INODE_UNDEL_DIR    6  // Undelete dir
114*f6dc9357SAndroid Build Coastguard Worker #define k_INODE_RESIZE       7  // Reserved group descriptors
115*f6dc9357SAndroid Build Coastguard Worker // #define k_INODE_JOURNAL      8  // Journal
116*f6dc9357SAndroid Build Coastguard Worker 
117*f6dc9357SAndroid Build Coastguard Worker // First non-reserved inode for old ext4 filesystems
118*f6dc9357SAndroid Build Coastguard Worker #define k_INODE_GOOD_OLD_FIRST  11
119*f6dc9357SAndroid Build Coastguard Worker 
120*f6dc9357SAndroid Build Coastguard Worker static const char * const k_SysInode_Names[] =
121*f6dc9357SAndroid Build Coastguard Worker {
122*f6dc9357SAndroid Build Coastguard Worker     "0"
123*f6dc9357SAndroid Build Coastguard Worker   , "Bad"
124*f6dc9357SAndroid Build Coastguard Worker   , "Root"
125*f6dc9357SAndroid Build Coastguard Worker   , "UserQuota"
126*f6dc9357SAndroid Build Coastguard Worker   , "GroupQuota"
127*f6dc9357SAndroid Build Coastguard Worker   , "BootLoader"
128*f6dc9357SAndroid Build Coastguard Worker   , "Undelete"
129*f6dc9357SAndroid Build Coastguard Worker   , "Resize"
130*f6dc9357SAndroid Build Coastguard Worker   , "Journal"
131*f6dc9357SAndroid Build Coastguard Worker   , "Exclude"
132*f6dc9357SAndroid Build Coastguard Worker   , "Replica"
133*f6dc9357SAndroid Build Coastguard Worker };
134*f6dc9357SAndroid Build Coastguard Worker 
135*f6dc9357SAndroid Build Coastguard Worker static const char * const kHostOS[] =
136*f6dc9357SAndroid Build Coastguard Worker {
137*f6dc9357SAndroid Build Coastguard Worker     "Linux"
138*f6dc9357SAndroid Build Coastguard Worker   , "Hurd"
139*f6dc9357SAndroid Build Coastguard Worker   , "Masix"
140*f6dc9357SAndroid Build Coastguard Worker   , "FreeBSD"
141*f6dc9357SAndroid Build Coastguard Worker   , "Lites"
142*f6dc9357SAndroid Build Coastguard Worker };
143*f6dc9357SAndroid Build Coastguard Worker 
144*f6dc9357SAndroid Build Coastguard Worker static const char * const g_FeatureCompat_Flags[] =
145*f6dc9357SAndroid Build Coastguard Worker {
146*f6dc9357SAndroid Build Coastguard Worker     "DIR_PREALLOC"
147*f6dc9357SAndroid Build Coastguard Worker   , "IMAGIC_INODES"
148*f6dc9357SAndroid Build Coastguard Worker   , "HAS_JOURNAL"
149*f6dc9357SAndroid Build Coastguard Worker   , "EXT_ATTR"
150*f6dc9357SAndroid Build Coastguard Worker   , "RESIZE_INODE"
151*f6dc9357SAndroid Build Coastguard Worker   , "DIR_INDEX"
152*f6dc9357SAndroid Build Coastguard Worker   , "LAZY_BG" // not in Linux
153*f6dc9357SAndroid Build Coastguard Worker   , NULL // { 7, "EXCLUDE_INODE" // not used
154*f6dc9357SAndroid Build Coastguard Worker   , NULL // { 8, "EXCLUDE_BITMAP" // not in kernel
155*f6dc9357SAndroid Build Coastguard Worker   , "SPARSE_SUPER2"
156*f6dc9357SAndroid Build Coastguard Worker };
157*f6dc9357SAndroid Build Coastguard Worker 
158*f6dc9357SAndroid Build Coastguard Worker 
159*f6dc9357SAndroid Build Coastguard Worker #define EXT4_FEATURE_INCOMPAT_FILETYPE (1 << 1)
160*f6dc9357SAndroid Build Coastguard Worker #define EXT4_FEATURE_INCOMPAT_64BIT (1 << 7)
161*f6dc9357SAndroid Build Coastguard Worker 
162*f6dc9357SAndroid Build Coastguard Worker static const char * const g_FeatureIncompat_Flags[] =
163*f6dc9357SAndroid Build Coastguard Worker {
164*f6dc9357SAndroid Build Coastguard Worker     "COMPRESSION"
165*f6dc9357SAndroid Build Coastguard Worker   , "FILETYPE"
166*f6dc9357SAndroid Build Coastguard Worker   , "RECOVER" /* Needs recovery */
167*f6dc9357SAndroid Build Coastguard Worker   , "JOURNAL_DEV" /* Journal device */
168*f6dc9357SAndroid Build Coastguard Worker   , "META_BG"
169*f6dc9357SAndroid Build Coastguard Worker   , NULL
170*f6dc9357SAndroid Build Coastguard Worker   , "EXTENTS" /* extents support */
171*f6dc9357SAndroid Build Coastguard Worker   , "64BIT"
172*f6dc9357SAndroid Build Coastguard Worker   , "MMP"
173*f6dc9357SAndroid Build Coastguard Worker   , "FLEX_BG"
174*f6dc9357SAndroid Build Coastguard Worker   , "EA_INODE" /* EA in inode */
175*f6dc9357SAndroid Build Coastguard Worker   , NULL
176*f6dc9357SAndroid Build Coastguard Worker   , "DIRDATA" /* data in dirent */
177*f6dc9357SAndroid Build Coastguard Worker   , "BG_USE_META_CSUM" /* use crc32c for bg */
178*f6dc9357SAndroid Build Coastguard Worker   , "LARGEDIR" /* >2GB or 3-lvl htree */
179*f6dc9357SAndroid Build Coastguard Worker   , "INLINE_DATA" /* data in inode */
180*f6dc9357SAndroid Build Coastguard Worker   , "ENCRYPT" // 16
181*f6dc9357SAndroid Build Coastguard Worker };
182*f6dc9357SAndroid Build Coastguard Worker 
183*f6dc9357SAndroid Build Coastguard Worker 
184*f6dc9357SAndroid Build Coastguard Worker static const UInt32 RO_COMPAT_GDT_CSUM = 1 << 4;
185*f6dc9357SAndroid Build Coastguard Worker static const UInt32 RO_COMPAT_METADATA_CSUM = 1 << 10;
186*f6dc9357SAndroid Build Coastguard Worker 
187*f6dc9357SAndroid Build Coastguard Worker static const char * const g_FeatureRoCompat_Flags[] =
188*f6dc9357SAndroid Build Coastguard Worker {
189*f6dc9357SAndroid Build Coastguard Worker     "SPARSE_SUPER"
190*f6dc9357SAndroid Build Coastguard Worker   , "LARGE_FILE"
191*f6dc9357SAndroid Build Coastguard Worker   , "BTREE_DIR"
192*f6dc9357SAndroid Build Coastguard Worker   , "HUGE_FILE"
193*f6dc9357SAndroid Build Coastguard Worker   , "GDT_CSUM"
194*f6dc9357SAndroid Build Coastguard Worker   , "DIR_NLINK"
195*f6dc9357SAndroid Build Coastguard Worker   , "EXTRA_ISIZE"
196*f6dc9357SAndroid Build Coastguard Worker   , "HAS_SNAPSHOT"
197*f6dc9357SAndroid Build Coastguard Worker   , "QUOTA"
198*f6dc9357SAndroid Build Coastguard Worker   , "BIGALLOC"
199*f6dc9357SAndroid Build Coastguard Worker   , "METADATA_CSUM"
200*f6dc9357SAndroid Build Coastguard Worker   , "REPLICA"
201*f6dc9357SAndroid Build Coastguard Worker   , "READONLY" // 12
202*f6dc9357SAndroid Build Coastguard Worker };
203*f6dc9357SAndroid Build Coastguard Worker 
204*f6dc9357SAndroid Build Coastguard Worker 
205*f6dc9357SAndroid Build Coastguard Worker 
206*f6dc9357SAndroid Build Coastguard Worker static const UInt32 k_NodeFlags_HUGE = (UInt32)1 << 18;
207*f6dc9357SAndroid Build Coastguard Worker static const UInt32 k_NodeFlags_EXTENTS = (UInt32)1 << 19;
208*f6dc9357SAndroid Build Coastguard Worker 
209*f6dc9357SAndroid Build Coastguard Worker 
210*f6dc9357SAndroid Build Coastguard Worker static const char * const g_NodeFlags[] =
211*f6dc9357SAndroid Build Coastguard Worker {
212*f6dc9357SAndroid Build Coastguard Worker     "SECRM"
213*f6dc9357SAndroid Build Coastguard Worker   , "UNRM"
214*f6dc9357SAndroid Build Coastguard Worker   , "COMPR"
215*f6dc9357SAndroid Build Coastguard Worker   , "SYNC"
216*f6dc9357SAndroid Build Coastguard Worker   , "IMMUTABLE"
217*f6dc9357SAndroid Build Coastguard Worker   , "APPEND"
218*f6dc9357SAndroid Build Coastguard Worker   , "NODUMP"
219*f6dc9357SAndroid Build Coastguard Worker   , "NOATIME"
220*f6dc9357SAndroid Build Coastguard Worker   , "DIRTY"
221*f6dc9357SAndroid Build Coastguard Worker   , "COMPRBLK"
222*f6dc9357SAndroid Build Coastguard Worker   , "NOCOMPR"
223*f6dc9357SAndroid Build Coastguard Worker   , "ENCRYPT"
224*f6dc9357SAndroid Build Coastguard Worker   , "INDEX"
225*f6dc9357SAndroid Build Coastguard Worker   , "IMAGIC"
226*f6dc9357SAndroid Build Coastguard Worker   , "JOURNAL_DATA"
227*f6dc9357SAndroid Build Coastguard Worker   , "NOTAIL"
228*f6dc9357SAndroid Build Coastguard Worker   , "DIRSYNC"
229*f6dc9357SAndroid Build Coastguard Worker   , "TOPDIR"
230*f6dc9357SAndroid Build Coastguard Worker   , "HUGE_FILE"
231*f6dc9357SAndroid Build Coastguard Worker   , "EXTENTS"
232*f6dc9357SAndroid Build Coastguard Worker   , NULL
233*f6dc9357SAndroid Build Coastguard Worker   , "EA_INODE"
234*f6dc9357SAndroid Build Coastguard Worker   , "EOFBLOCKS"
235*f6dc9357SAndroid Build Coastguard Worker   , NULL
236*f6dc9357SAndroid Build Coastguard Worker   , NULL
237*f6dc9357SAndroid Build Coastguard Worker   , NULL
238*f6dc9357SAndroid Build Coastguard Worker   , NULL
239*f6dc9357SAndroid Build Coastguard Worker   , NULL
240*f6dc9357SAndroid Build Coastguard Worker   , "INLINE_DATA" // 28
241*f6dc9357SAndroid Build Coastguard Worker };
242*f6dc9357SAndroid Build Coastguard Worker 
243*f6dc9357SAndroid Build Coastguard Worker 
244*f6dc9357SAndroid Build Coastguard Worker enum
245*f6dc9357SAndroid Build Coastguard Worker {
246*f6dc9357SAndroid Build Coastguard Worker   k_Type_UNKNOWN,
247*f6dc9357SAndroid Build Coastguard Worker   k_Type_REG_FILE,
248*f6dc9357SAndroid Build Coastguard Worker   k_Type_DIR,
249*f6dc9357SAndroid Build Coastguard Worker   k_Type_CHRDEV,
250*f6dc9357SAndroid Build Coastguard Worker   k_Type_BLKDEV,
251*f6dc9357SAndroid Build Coastguard Worker   k_Type_FIFO,
252*f6dc9357SAndroid Build Coastguard Worker   k_Type_SOCK,
253*f6dc9357SAndroid Build Coastguard Worker   k_Type_SYMLINK
254*f6dc9357SAndroid Build Coastguard Worker };
255*f6dc9357SAndroid Build Coastguard Worker 
256*f6dc9357SAndroid Build Coastguard Worker static const UInt16 k_TypeToMode[] =
257*f6dc9357SAndroid Build Coastguard Worker {
258*f6dc9357SAndroid Build Coastguard Worker   0,
259*f6dc9357SAndroid Build Coastguard Worker   MY_LIN_S_IFREG,
260*f6dc9357SAndroid Build Coastguard Worker   MY_LIN_S_IFDIR,
261*f6dc9357SAndroid Build Coastguard Worker   MY_LIN_S_IFCHR,
262*f6dc9357SAndroid Build Coastguard Worker   MY_LIN_S_IFBLK,
263*f6dc9357SAndroid Build Coastguard Worker   MY_LIN_S_IFIFO,
264*f6dc9357SAndroid Build Coastguard Worker   MY_LIN_S_IFSOCK,
265*f6dc9357SAndroid Build Coastguard Worker   MY_LIN_S_IFLNK
266*f6dc9357SAndroid Build Coastguard Worker };
267*f6dc9357SAndroid Build Coastguard Worker 
268*f6dc9357SAndroid Build Coastguard Worker 
269*f6dc9357SAndroid Build Coastguard Worker #define EXT4_GOOD_OLD_REV 0  // old (original) format
270*f6dc9357SAndroid Build Coastguard Worker // #define EXT4_DYNAMIC_REV 1  // V2 format with dynamic inode sizes
271*f6dc9357SAndroid Build Coastguard Worker 
272*f6dc9357SAndroid Build Coastguard Worker struct CHeader
273*f6dc9357SAndroid Build Coastguard Worker {
274*f6dc9357SAndroid Build Coastguard Worker   unsigned BlockBits;
275*f6dc9357SAndroid Build Coastguard Worker   unsigned ClusterBits;
276*f6dc9357SAndroid Build Coastguard Worker 
277*f6dc9357SAndroid Build Coastguard Worker   UInt32 NumInodes;
278*f6dc9357SAndroid Build Coastguard Worker   UInt64 NumBlocks;
279*f6dc9357SAndroid Build Coastguard Worker   // UInt64 NumBlocksSuper;
280*f6dc9357SAndroid Build Coastguard Worker   UInt64 NumFreeBlocks;
281*f6dc9357SAndroid Build Coastguard Worker   UInt32 NumFreeInodes;
282*f6dc9357SAndroid Build Coastguard Worker   // UInt32 FirstDataBlock;
283*f6dc9357SAndroid Build Coastguard Worker 
284*f6dc9357SAndroid Build Coastguard Worker   UInt32 BlocksPerGroup;
285*f6dc9357SAndroid Build Coastguard Worker   UInt32 ClustersPerGroup;
286*f6dc9357SAndroid Build Coastguard Worker   UInt32 InodesPerGroup;
287*f6dc9357SAndroid Build Coastguard Worker 
288*f6dc9357SAndroid Build Coastguard Worker   UInt32 MountTime;
289*f6dc9357SAndroid Build Coastguard Worker   UInt32 WriteTime;
290*f6dc9357SAndroid Build Coastguard Worker 
291*f6dc9357SAndroid Build Coastguard Worker   // UInt16 NumMounts;
292*f6dc9357SAndroid Build Coastguard Worker   // UInt16 NumMountsMax;
293*f6dc9357SAndroid Build Coastguard Worker 
294*f6dc9357SAndroid Build Coastguard Worker   // UInt16 State;
295*f6dc9357SAndroid Build Coastguard Worker   // UInt16 Errors;
296*f6dc9357SAndroid Build Coastguard Worker   // UInt16 MinorRevLevel;
297*f6dc9357SAndroid Build Coastguard Worker 
298*f6dc9357SAndroid Build Coastguard Worker   UInt32 LastCheckTime;
299*f6dc9357SAndroid Build Coastguard Worker   // UInt32 CheckInterval;
300*f6dc9357SAndroid Build Coastguard Worker   UInt32 CreatorOs;
301*f6dc9357SAndroid Build Coastguard Worker   UInt32 RevLevel;
302*f6dc9357SAndroid Build Coastguard Worker 
303*f6dc9357SAndroid Build Coastguard Worker   // UInt16 DefResUid;
304*f6dc9357SAndroid Build Coastguard Worker   // UInt16 DefResGid;
305*f6dc9357SAndroid Build Coastguard Worker 
306*f6dc9357SAndroid Build Coastguard Worker   UInt32 FirstInode;
307*f6dc9357SAndroid Build Coastguard Worker   UInt16 InodeSize;
308*f6dc9357SAndroid Build Coastguard Worker   UInt16 BlockGroupNr;
309*f6dc9357SAndroid Build Coastguard Worker   UInt32 FeatureCompat;
310*f6dc9357SAndroid Build Coastguard Worker   UInt32 FeatureIncompat;
311*f6dc9357SAndroid Build Coastguard Worker   UInt32 FeatureRoCompat;
312*f6dc9357SAndroid Build Coastguard Worker   Byte Uuid[16];
313*f6dc9357SAndroid Build Coastguard Worker   char VolName[16];
314*f6dc9357SAndroid Build Coastguard Worker   char LastMount[64];
315*f6dc9357SAndroid Build Coastguard Worker   // UInt32 BitmapAlgo;
316*f6dc9357SAndroid Build Coastguard Worker 
317*f6dc9357SAndroid Build Coastguard Worker   UInt32 JournalInode;
318*f6dc9357SAndroid Build Coastguard Worker   UInt16 GdSize; // = 64 if 64-bit();
319*f6dc9357SAndroid Build Coastguard Worker   UInt32 CTime;
320*f6dc9357SAndroid Build Coastguard Worker   UInt16 MinExtraISize;
321*f6dc9357SAndroid Build Coastguard Worker   // UInt16 WantExtraISize;
322*f6dc9357SAndroid Build Coastguard Worker   // UInt32 Flags;
323*f6dc9357SAndroid Build Coastguard Worker   // Byte LogGroupsPerFlex;
324*f6dc9357SAndroid Build Coastguard Worker   // Byte ChecksumType;
325*f6dc9357SAndroid Build Coastguard Worker 
326*f6dc9357SAndroid Build Coastguard Worker   UInt64 WrittenKB;
327*f6dc9357SAndroid Build Coastguard Worker 
IsOldRevNArchive::NExt::CHeader328*f6dc9357SAndroid Build Coastguard Worker   bool IsOldRev() const { return RevLevel == EXT4_GOOD_OLD_REV; }
329*f6dc9357SAndroid Build Coastguard Worker 
GetNumGroupsNArchive::NExt::CHeader330*f6dc9357SAndroid Build Coastguard Worker   UInt64 GetNumGroups() const { return (NumBlocks + BlocksPerGroup - 1) / BlocksPerGroup; }
GetNumGroups2NArchive::NExt::CHeader331*f6dc9357SAndroid Build Coastguard Worker   UInt64 GetNumGroups2() const { return ((UInt64)NumInodes + InodesPerGroup - 1) / InodesPerGroup; }
332*f6dc9357SAndroid Build Coastguard Worker 
IsThereFileTypeNArchive::NExt::CHeader333*f6dc9357SAndroid Build Coastguard Worker   bool IsThereFileType() const { return (FeatureIncompat & EXT4_FEATURE_INCOMPAT_FILETYPE) != 0; }
Is64BitNArchive::NExt::CHeader334*f6dc9357SAndroid Build Coastguard Worker   bool Is64Bit() const { return (FeatureIncompat & EXT4_FEATURE_INCOMPAT_64BIT) != 0; }
UseGdtChecksumNArchive::NExt::CHeader335*f6dc9357SAndroid Build Coastguard Worker   bool UseGdtChecksum() const { return (FeatureRoCompat & RO_COMPAT_GDT_CSUM) != 0; }
UseMetadataChecksumNArchive::NExt::CHeader336*f6dc9357SAndroid Build Coastguard Worker   bool UseMetadataChecksum() const { return (FeatureRoCompat & RO_COMPAT_METADATA_CSUM) != 0; }
337*f6dc9357SAndroid Build Coastguard Worker 
GetPhySizeNArchive::NExt::CHeader338*f6dc9357SAndroid Build Coastguard Worker   UInt64 GetPhySize() const { return NumBlocks << BlockBits; }
339*f6dc9357SAndroid Build Coastguard Worker 
340*f6dc9357SAndroid Build Coastguard Worker   bool Parse(const Byte *p);
341*f6dc9357SAndroid Build Coastguard Worker };
342*f6dc9357SAndroid Build Coastguard Worker 
343*f6dc9357SAndroid Build Coastguard Worker 
GetLog(UInt32 num)344*f6dc9357SAndroid Build Coastguard Worker static int inline GetLog(UInt32 num)
345*f6dc9357SAndroid Build Coastguard Worker {
346*f6dc9357SAndroid Build Coastguard Worker   for (unsigned i = 0; i < 32; i++)
347*f6dc9357SAndroid Build Coastguard Worker     if (((UInt32)1 << i) == num)
348*f6dc9357SAndroid Build Coastguard Worker       return (int)i;
349*f6dc9357SAndroid Build Coastguard Worker   return -1;
350*f6dc9357SAndroid Build Coastguard Worker }
351*f6dc9357SAndroid Build Coastguard Worker 
IsEmptyData(const Byte * data,unsigned size)352*f6dc9357SAndroid Build Coastguard Worker static bool inline IsEmptyData(const Byte *data, unsigned size)
353*f6dc9357SAndroid Build Coastguard Worker {
354*f6dc9357SAndroid Build Coastguard Worker   for (unsigned i = 0; i < size; i++)
355*f6dc9357SAndroid Build Coastguard Worker     if (data[i] != 0)
356*f6dc9357SAndroid Build Coastguard Worker       return false;
357*f6dc9357SAndroid Build Coastguard Worker   return true;
358*f6dc9357SAndroid Build Coastguard Worker }
359*f6dc9357SAndroid Build Coastguard Worker 
360*f6dc9357SAndroid Build Coastguard Worker 
Parse(const Byte * p)361*f6dc9357SAndroid Build Coastguard Worker bool CHeader::Parse(const Byte *p)
362*f6dc9357SAndroid Build Coastguard Worker {
363*f6dc9357SAndroid Build Coastguard Worker   if (GetUi16(p + 0x38) != 0xEF53)
364*f6dc9357SAndroid Build Coastguard Worker     return false;
365*f6dc9357SAndroid Build Coastguard Worker 
366*f6dc9357SAndroid Build Coastguard Worker   LE_32 (0x18, BlockBits)
367*f6dc9357SAndroid Build Coastguard Worker   LE_32 (0x1C, ClusterBits)
368*f6dc9357SAndroid Build Coastguard Worker 
369*f6dc9357SAndroid Build Coastguard Worker   if (ClusterBits != 0 && BlockBits != ClusterBits)
370*f6dc9357SAndroid Build Coastguard Worker     return false;
371*f6dc9357SAndroid Build Coastguard Worker 
372*f6dc9357SAndroid Build Coastguard Worker   if (BlockBits > 16 - 10)
373*f6dc9357SAndroid Build Coastguard Worker     return false;
374*f6dc9357SAndroid Build Coastguard Worker   BlockBits += 10;
375*f6dc9357SAndroid Build Coastguard Worker 
376*f6dc9357SAndroid Build Coastguard Worker   LE_32 (0x00, NumInodes)
377*f6dc9357SAndroid Build Coastguard Worker   LE_32 (0x04, NumBlocks)
378*f6dc9357SAndroid Build Coastguard Worker   // LE_32 (0x08, NumBlocksSuper);
379*f6dc9357SAndroid Build Coastguard Worker   LE_32 (0x0C, NumFreeBlocks)
380*f6dc9357SAndroid Build Coastguard Worker   LE_32 (0x10, NumFreeInodes)
381*f6dc9357SAndroid Build Coastguard Worker 
382*f6dc9357SAndroid Build Coastguard Worker   if (NumInodes < 2 || NumInodes <= NumFreeInodes)
383*f6dc9357SAndroid Build Coastguard Worker     return false;
384*f6dc9357SAndroid Build Coastguard Worker 
385*f6dc9357SAndroid Build Coastguard Worker   UInt32 FirstDataBlock;
386*f6dc9357SAndroid Build Coastguard Worker   LE_32 (0x14, FirstDataBlock)
387*f6dc9357SAndroid Build Coastguard Worker   if (FirstDataBlock != (unsigned)(BlockBits == 10 ? 1 : 0))
388*f6dc9357SAndroid Build Coastguard Worker     return false;
389*f6dc9357SAndroid Build Coastguard Worker 
390*f6dc9357SAndroid Build Coastguard Worker   LE_32 (0x20, BlocksPerGroup)
391*f6dc9357SAndroid Build Coastguard Worker   LE_32 (0x24, ClustersPerGroup)
392*f6dc9357SAndroid Build Coastguard Worker 
393*f6dc9357SAndroid Build Coastguard Worker   if (BlocksPerGroup != ClustersPerGroup)
394*f6dc9357SAndroid Build Coastguard Worker     return false;
395*f6dc9357SAndroid Build Coastguard Worker   if (BlocksPerGroup == 0)
396*f6dc9357SAndroid Build Coastguard Worker     return false;
397*f6dc9357SAndroid Build Coastguard Worker   if (BlocksPerGroup != ((UInt32)1 << (BlockBits + 3)))
398*f6dc9357SAndroid Build Coastguard Worker   {
399*f6dc9357SAndroid Build Coastguard Worker     // it's allowed in ext2
400*f6dc9357SAndroid Build Coastguard Worker     // return false;
401*f6dc9357SAndroid Build Coastguard Worker   }
402*f6dc9357SAndroid Build Coastguard Worker 
403*f6dc9357SAndroid Build Coastguard Worker   LE_32 (0x28, InodesPerGroup)
404*f6dc9357SAndroid Build Coastguard Worker 
405*f6dc9357SAndroid Build Coastguard Worker   if (InodesPerGroup < 1 || InodesPerGroup > NumInodes)
406*f6dc9357SAndroid Build Coastguard Worker     return false;
407*f6dc9357SAndroid Build Coastguard Worker 
408*f6dc9357SAndroid Build Coastguard Worker   LE_32 (0x2C, MountTime)
409*f6dc9357SAndroid Build Coastguard Worker   LE_32 (0x30, WriteTime)
410*f6dc9357SAndroid Build Coastguard Worker 
411*f6dc9357SAndroid Build Coastguard Worker   // LE_16 (0x34, NumMounts);
412*f6dc9357SAndroid Build Coastguard Worker   // LE_16 (0x36, NumMountsMax);
413*f6dc9357SAndroid Build Coastguard Worker 
414*f6dc9357SAndroid Build Coastguard Worker   // LE_16 (0x3A, State);
415*f6dc9357SAndroid Build Coastguard Worker   // LE_16 (0x3C, Errors);
416*f6dc9357SAndroid Build Coastguard Worker   // LE_16 (0x3E, MinorRevLevel);
417*f6dc9357SAndroid Build Coastguard Worker 
418*f6dc9357SAndroid Build Coastguard Worker   LE_32 (0x40, LastCheckTime)
419*f6dc9357SAndroid Build Coastguard Worker   // LE_32 (0x44, CheckInterval);
420*f6dc9357SAndroid Build Coastguard Worker   LE_32 (0x48, CreatorOs)
421*f6dc9357SAndroid Build Coastguard Worker   LE_32 (0x4C, RevLevel)
422*f6dc9357SAndroid Build Coastguard Worker 
423*f6dc9357SAndroid Build Coastguard Worker   // LE_16 (0x50, DefResUid);
424*f6dc9357SAndroid Build Coastguard Worker   // LE_16 (0x52, DefResGid);
425*f6dc9357SAndroid Build Coastguard Worker 
426*f6dc9357SAndroid Build Coastguard Worker   FirstInode = k_INODE_GOOD_OLD_FIRST;
427*f6dc9357SAndroid Build Coastguard Worker   InodeSize = EXT4_GOOD_OLD_INODE_SIZE;
428*f6dc9357SAndroid Build Coastguard Worker 
429*f6dc9357SAndroid Build Coastguard Worker   if (!IsOldRev())
430*f6dc9357SAndroid Build Coastguard Worker   {
431*f6dc9357SAndroid Build Coastguard Worker     LE_32 (0x54, FirstInode)
432*f6dc9357SAndroid Build Coastguard Worker     LE_16 (0x58, InodeSize)
433*f6dc9357SAndroid Build Coastguard Worker     if (FirstInode < k_INODE_GOOD_OLD_FIRST)
434*f6dc9357SAndroid Build Coastguard Worker       return false;
435*f6dc9357SAndroid Build Coastguard Worker     if (InodeSize > ((UInt32)1 << BlockBits)
436*f6dc9357SAndroid Build Coastguard Worker         || InodeSize < EXT_NODE_SIZE_MIN
437*f6dc9357SAndroid Build Coastguard Worker         || GetLog(InodeSize) < 0)
438*f6dc9357SAndroid Build Coastguard Worker       return false;
439*f6dc9357SAndroid Build Coastguard Worker   }
440*f6dc9357SAndroid Build Coastguard Worker 
441*f6dc9357SAndroid Build Coastguard Worker   LE_16 (0x5A, BlockGroupNr)
442*f6dc9357SAndroid Build Coastguard Worker   LE_32 (0x5C, FeatureCompat)
443*f6dc9357SAndroid Build Coastguard Worker   LE_32 (0x60, FeatureIncompat)
444*f6dc9357SAndroid Build Coastguard Worker   LE_32 (0x64, FeatureRoCompat)
445*f6dc9357SAndroid Build Coastguard Worker 
446*f6dc9357SAndroid Build Coastguard Worker   memcpy(Uuid, p + 0x68, sizeof(Uuid));
447*f6dc9357SAndroid Build Coastguard Worker   memcpy(VolName, p + 0x78, sizeof(VolName));
448*f6dc9357SAndroid Build Coastguard Worker   memcpy(LastMount, p + 0x88, sizeof(LastMount));
449*f6dc9357SAndroid Build Coastguard Worker 
450*f6dc9357SAndroid Build Coastguard Worker   // LE_32 (0xC8, BitmapAlgo);
451*f6dc9357SAndroid Build Coastguard Worker 
452*f6dc9357SAndroid Build Coastguard Worker   LE_32 (0xE0, JournalInode)
453*f6dc9357SAndroid Build Coastguard Worker 
454*f6dc9357SAndroid Build Coastguard Worker   LE_16 (0xFE, GdSize)
455*f6dc9357SAndroid Build Coastguard Worker 
456*f6dc9357SAndroid Build Coastguard Worker   LE_32 (0x108, CTime)
457*f6dc9357SAndroid Build Coastguard Worker 
458*f6dc9357SAndroid Build Coastguard Worker   if (Is64Bit())
459*f6dc9357SAndroid Build Coastguard Worker   {
460*f6dc9357SAndroid Build Coastguard Worker     HI_32(0x150, NumBlocks)
461*f6dc9357SAndroid Build Coastguard Worker     // HI_32(0x154, NumBlocksSuper);
462*f6dc9357SAndroid Build Coastguard Worker     HI_32(0x158, NumFreeBlocks)
463*f6dc9357SAndroid Build Coastguard Worker   }
464*f6dc9357SAndroid Build Coastguard Worker 
465*f6dc9357SAndroid Build Coastguard Worker   if (NumBlocks >= (UInt64)1 << (63 - BlockBits))
466*f6dc9357SAndroid Build Coastguard Worker     return false;
467*f6dc9357SAndroid Build Coastguard Worker 
468*f6dc9357SAndroid Build Coastguard Worker 
469*f6dc9357SAndroid Build Coastguard Worker   LE_16(0x15C, MinExtraISize)
470*f6dc9357SAndroid Build Coastguard Worker   // LE_16(0x15E, WantExtraISize);
471*f6dc9357SAndroid Build Coastguard Worker   // LE_32(0x160, Flags);
472*f6dc9357SAndroid Build Coastguard Worker   // LE_16(0x164, RaidStride);
473*f6dc9357SAndroid Build Coastguard Worker   // LE_16(0x166, MmpInterval);
474*f6dc9357SAndroid Build Coastguard Worker   // LE_64(0x168, MmpBlock);
475*f6dc9357SAndroid Build Coastguard Worker 
476*f6dc9357SAndroid Build Coastguard Worker   // LogGroupsPerFlex = p[0x174];
477*f6dc9357SAndroid Build Coastguard Worker   // ChecksumType = p[0x175];
478*f6dc9357SAndroid Build Coastguard Worker 
479*f6dc9357SAndroid Build Coastguard Worker   LE_64 (0x178, WrittenKB)
480*f6dc9357SAndroid Build Coastguard Worker 
481*f6dc9357SAndroid Build Coastguard Worker   // LE_32(0x194, ErrorCount);
482*f6dc9357SAndroid Build Coastguard Worker   // LE_32(0x198, ErrorTime);
483*f6dc9357SAndroid Build Coastguard Worker   // LE_32(0x19C, ErrorINode);
484*f6dc9357SAndroid Build Coastguard Worker   // LE_32(0x1A0, ErrorBlock);
485*f6dc9357SAndroid Build Coastguard Worker 
486*f6dc9357SAndroid Build Coastguard Worker   if (NumBlocks < 1)
487*f6dc9357SAndroid Build Coastguard Worker     return false;
488*f6dc9357SAndroid Build Coastguard Worker   if (NumFreeBlocks > NumBlocks)
489*f6dc9357SAndroid Build Coastguard Worker     return false;
490*f6dc9357SAndroid Build Coastguard Worker 
491*f6dc9357SAndroid Build Coastguard Worker   if (GetNumGroups() != GetNumGroups2())
492*f6dc9357SAndroid Build Coastguard Worker     return false;
493*f6dc9357SAndroid Build Coastguard Worker 
494*f6dc9357SAndroid Build Coastguard Worker   return true;
495*f6dc9357SAndroid Build Coastguard Worker }
496*f6dc9357SAndroid Build Coastguard Worker 
497*f6dc9357SAndroid Build Coastguard Worker 
498*f6dc9357SAndroid Build Coastguard Worker struct CGroupDescriptor
499*f6dc9357SAndroid Build Coastguard Worker {
500*f6dc9357SAndroid Build Coastguard Worker   UInt64 BlockBitmap;
501*f6dc9357SAndroid Build Coastguard Worker   UInt64 InodeBitmap;
502*f6dc9357SAndroid Build Coastguard Worker   UInt64 InodeTable;
503*f6dc9357SAndroid Build Coastguard Worker   UInt32 NumFreeBlocks;
504*f6dc9357SAndroid Build Coastguard Worker   UInt32 NumFreeInodes;
505*f6dc9357SAndroid Build Coastguard Worker   UInt32 DirCount;
506*f6dc9357SAndroid Build Coastguard Worker 
507*f6dc9357SAndroid Build Coastguard Worker   UInt16 Flags;
508*f6dc9357SAndroid Build Coastguard Worker 
509*f6dc9357SAndroid Build Coastguard Worker   UInt64 ExcludeBitmap;
510*f6dc9357SAndroid Build Coastguard Worker   UInt32 BlockBitmap_Checksum;
511*f6dc9357SAndroid Build Coastguard Worker   UInt32 InodeBitmap_Checksum;
512*f6dc9357SAndroid Build Coastguard Worker   UInt32 UnusedCount;
513*f6dc9357SAndroid Build Coastguard Worker   UInt16 Checksum;
514*f6dc9357SAndroid Build Coastguard Worker 
515*f6dc9357SAndroid Build Coastguard Worker   void Parse(const Byte *p, unsigned size);
516*f6dc9357SAndroid Build Coastguard Worker };
517*f6dc9357SAndroid Build Coastguard Worker 
Parse(const Byte * p,unsigned size)518*f6dc9357SAndroid Build Coastguard Worker void CGroupDescriptor::Parse(const Byte *p, unsigned size)
519*f6dc9357SAndroid Build Coastguard Worker {
520*f6dc9357SAndroid Build Coastguard Worker   LE_32 (0x00, BlockBitmap)
521*f6dc9357SAndroid Build Coastguard Worker   LE_32 (0x04, InodeBitmap)
522*f6dc9357SAndroid Build Coastguard Worker   LE_32 (0x08, InodeTable)
523*f6dc9357SAndroid Build Coastguard Worker   LE_16 (0x0C, NumFreeBlocks)
524*f6dc9357SAndroid Build Coastguard Worker   LE_16 (0x0E, NumFreeInodes)
525*f6dc9357SAndroid Build Coastguard Worker   LE_16 (0x10, DirCount)
526*f6dc9357SAndroid Build Coastguard Worker   LE_16 (0x12, Flags)
527*f6dc9357SAndroid Build Coastguard Worker   LE_32 (0x14, ExcludeBitmap)
528*f6dc9357SAndroid Build Coastguard Worker   LE_16 (0x18, BlockBitmap_Checksum)
529*f6dc9357SAndroid Build Coastguard Worker   LE_16 (0x1A, InodeBitmap_Checksum)
530*f6dc9357SAndroid Build Coastguard Worker   LE_16 (0x1C, UnusedCount)
531*f6dc9357SAndroid Build Coastguard Worker   LE_16 (0x1E, Checksum)
532*f6dc9357SAndroid Build Coastguard Worker 
533*f6dc9357SAndroid Build Coastguard Worker   if (size >= 64)
534*f6dc9357SAndroid Build Coastguard Worker   {
535*f6dc9357SAndroid Build Coastguard Worker     p += 0x20;
536*f6dc9357SAndroid Build Coastguard Worker     HI_32 (0x00, BlockBitmap)
537*f6dc9357SAndroid Build Coastguard Worker     HI_32 (0x04, InodeBitmap)
538*f6dc9357SAndroid Build Coastguard Worker     HI_32 (0x08, InodeTable)
539*f6dc9357SAndroid Build Coastguard Worker     HI_16 (0x0C, NumFreeBlocks)
540*f6dc9357SAndroid Build Coastguard Worker     HI_16 (0x0E, NumFreeInodes)
541*f6dc9357SAndroid Build Coastguard Worker     HI_16 (0x10, DirCount)
542*f6dc9357SAndroid Build Coastguard Worker     HI_16 (0x12, UnusedCount) // instead of Flags
543*f6dc9357SAndroid Build Coastguard Worker     HI_32 (0x14, ExcludeBitmap)
544*f6dc9357SAndroid Build Coastguard Worker     HI_16 (0x18, BlockBitmap_Checksum)
545*f6dc9357SAndroid Build Coastguard Worker     HI_16 (0x1A, InodeBitmap_Checksum)
546*f6dc9357SAndroid Build Coastguard Worker     // HI_16 (0x1C, Reserved);
547*f6dc9357SAndroid Build Coastguard Worker   }
548*f6dc9357SAndroid Build Coastguard Worker }
549*f6dc9357SAndroid Build Coastguard Worker 
550*f6dc9357SAndroid Build Coastguard Worker 
551*f6dc9357SAndroid Build Coastguard Worker static const unsigned kNodeBlockFieldSize = 60;
552*f6dc9357SAndroid Build Coastguard Worker 
553*f6dc9357SAndroid Build Coastguard Worker struct CExtentTreeHeader
554*f6dc9357SAndroid Build Coastguard Worker {
555*f6dc9357SAndroid Build Coastguard Worker   UInt16 NumEntries;
556*f6dc9357SAndroid Build Coastguard Worker   UInt16 MaxEntries;
557*f6dc9357SAndroid Build Coastguard Worker   UInt16 Depth;
558*f6dc9357SAndroid Build Coastguard Worker   // UInt32 Generation;
559*f6dc9357SAndroid Build Coastguard Worker 
ParseNArchive::NExt::CExtentTreeHeader560*f6dc9357SAndroid Build Coastguard Worker   bool Parse(const Byte *p)
561*f6dc9357SAndroid Build Coastguard Worker   {
562*f6dc9357SAndroid Build Coastguard Worker     LE_16 (0x02, NumEntries)
563*f6dc9357SAndroid Build Coastguard Worker     LE_16 (0x04, MaxEntries)
564*f6dc9357SAndroid Build Coastguard Worker     LE_16 (0x06, Depth)
565*f6dc9357SAndroid Build Coastguard Worker     // LE_32 (0x08, Generation);
566*f6dc9357SAndroid Build Coastguard Worker     return Get16(p) == 0xF30A; // magic
567*f6dc9357SAndroid Build Coastguard Worker   }
568*f6dc9357SAndroid Build Coastguard Worker };
569*f6dc9357SAndroid Build Coastguard Worker 
570*f6dc9357SAndroid Build Coastguard Worker struct CExtentIndexNode
571*f6dc9357SAndroid Build Coastguard Worker {
572*f6dc9357SAndroid Build Coastguard Worker   UInt32 VirtBlock;
573*f6dc9357SAndroid Build Coastguard Worker   UInt64 PhyLeaf;
574*f6dc9357SAndroid Build Coastguard Worker 
ParseNArchive::NExt::CExtentIndexNode575*f6dc9357SAndroid Build Coastguard Worker   void Parse(const Byte *p)
576*f6dc9357SAndroid Build Coastguard Worker   {
577*f6dc9357SAndroid Build Coastguard Worker     LE_32 (0x00, VirtBlock)
578*f6dc9357SAndroid Build Coastguard Worker     LE_32 (0x04, PhyLeaf)
579*f6dc9357SAndroid Build Coastguard Worker     PhyLeaf |= (((UInt64)Get16(p + 8)) << 32);
580*f6dc9357SAndroid Build Coastguard Worker     // unused 16-bit field (at offset 0x0A) can be not zero in some cases. Why?
581*f6dc9357SAndroid Build Coastguard Worker   }
582*f6dc9357SAndroid Build Coastguard Worker };
583*f6dc9357SAndroid Build Coastguard Worker 
584*f6dc9357SAndroid Build Coastguard Worker struct CExtent
585*f6dc9357SAndroid Build Coastguard Worker {
586*f6dc9357SAndroid Build Coastguard Worker   UInt32 VirtBlock;
587*f6dc9357SAndroid Build Coastguard Worker   UInt16 Len;
588*f6dc9357SAndroid Build Coastguard Worker   bool IsInited;
589*f6dc9357SAndroid Build Coastguard Worker   UInt64 PhyStart;
590*f6dc9357SAndroid Build Coastguard Worker 
GetVirtEndNArchive::NExt::CExtent591*f6dc9357SAndroid Build Coastguard Worker   UInt32 GetVirtEnd() const { return VirtBlock + Len; }
IsLenOKNArchive::NExt::CExtent592*f6dc9357SAndroid Build Coastguard Worker   bool IsLenOK() const { return VirtBlock + Len >= VirtBlock; }
593*f6dc9357SAndroid Build Coastguard Worker 
ParseNArchive::NExt::CExtent594*f6dc9357SAndroid Build Coastguard Worker   void Parse(const Byte *p)
595*f6dc9357SAndroid Build Coastguard Worker   {
596*f6dc9357SAndroid Build Coastguard Worker     LE_32 (0x00, VirtBlock)
597*f6dc9357SAndroid Build Coastguard Worker     LE_16 (0x04, Len)
598*f6dc9357SAndroid Build Coastguard Worker     IsInited = true;
599*f6dc9357SAndroid Build Coastguard Worker     if (Len > (UInt32)0x8000)
600*f6dc9357SAndroid Build Coastguard Worker     {
601*f6dc9357SAndroid Build Coastguard Worker       IsInited = false;
602*f6dc9357SAndroid Build Coastguard Worker       Len = (UInt16)(Len - (UInt32)0x8000);
603*f6dc9357SAndroid Build Coastguard Worker     }
604*f6dc9357SAndroid Build Coastguard Worker     LE_32 (0x08, PhyStart)
605*f6dc9357SAndroid Build Coastguard Worker     UInt16 hi;
606*f6dc9357SAndroid Build Coastguard Worker     LE_16 (0x06, hi)
607*f6dc9357SAndroid Build Coastguard Worker     PhyStart |= ((UInt64)hi << 32);
608*f6dc9357SAndroid Build Coastguard Worker   }
609*f6dc9357SAndroid Build Coastguard Worker };
610*f6dc9357SAndroid Build Coastguard Worker 
611*f6dc9357SAndroid Build Coastguard Worker 
612*f6dc9357SAndroid Build Coastguard Worker 
613*f6dc9357SAndroid Build Coastguard Worker struct CExtTime
614*f6dc9357SAndroid Build Coastguard Worker {
615*f6dc9357SAndroid Build Coastguard Worker   UInt32 Val;
616*f6dc9357SAndroid Build Coastguard Worker   UInt32 Extra;
617*f6dc9357SAndroid Build Coastguard Worker };
618*f6dc9357SAndroid Build Coastguard Worker 
619*f6dc9357SAndroid Build Coastguard Worker struct CNode
620*f6dc9357SAndroid Build Coastguard Worker {
621*f6dc9357SAndroid Build Coastguard Worker   Int32 ParentNode;   // in _refs[], -1 if not dir
622*f6dc9357SAndroid Build Coastguard Worker   int ItemIndex;      // in _items[]   , (set as >=0 only for if (IsDir())
623*f6dc9357SAndroid Build Coastguard Worker   int SymLinkIndex;   // in _symLinks[]
624*f6dc9357SAndroid Build Coastguard Worker   int DirIndex;       // in _dirs[]
625*f6dc9357SAndroid Build Coastguard Worker 
626*f6dc9357SAndroid Build Coastguard Worker   UInt16 Mode;
627*f6dc9357SAndroid Build Coastguard Worker   UInt32 Uid; // fixed 21.02
628*f6dc9357SAndroid Build Coastguard Worker   UInt32 Gid; // fixed 21.02
629*f6dc9357SAndroid Build Coastguard Worker   // UInt16 Checksum;
630*f6dc9357SAndroid Build Coastguard Worker 
631*f6dc9357SAndroid Build Coastguard Worker   UInt64 FileSize;
632*f6dc9357SAndroid Build Coastguard Worker   CExtTime MTime;
633*f6dc9357SAndroid Build Coastguard Worker   CExtTime ATime;
634*f6dc9357SAndroid Build Coastguard Worker   CExtTime CTime;
635*f6dc9357SAndroid Build Coastguard Worker   CExtTime ChangeTime;
636*f6dc9357SAndroid Build Coastguard Worker   // CExtTime DTime;
637*f6dc9357SAndroid Build Coastguard Worker 
638*f6dc9357SAndroid Build Coastguard Worker   UInt64 NumBlocks;
639*f6dc9357SAndroid Build Coastguard Worker   UInt32 NumLinks;
640*f6dc9357SAndroid Build Coastguard Worker   UInt32 Flags;
641*f6dc9357SAndroid Build Coastguard Worker 
642*f6dc9357SAndroid Build Coastguard Worker   UInt32 NumLinksCalced;
643*f6dc9357SAndroid Build Coastguard Worker 
644*f6dc9357SAndroid Build Coastguard Worker   Byte Block[kNodeBlockFieldSize];
645*f6dc9357SAndroid Build Coastguard Worker 
CNodeNArchive::NExt::CNode646*f6dc9357SAndroid Build Coastguard Worker   CNode():
647*f6dc9357SAndroid Build Coastguard Worker       ParentNode(-1),
648*f6dc9357SAndroid Build Coastguard Worker       ItemIndex(-1),
649*f6dc9357SAndroid Build Coastguard Worker       SymLinkIndex(-1),
650*f6dc9357SAndroid Build Coastguard Worker       DirIndex(-1),
651*f6dc9357SAndroid Build Coastguard Worker       NumLinksCalced(0)
652*f6dc9357SAndroid Build Coastguard Worker         {}
653*f6dc9357SAndroid Build Coastguard Worker 
IsFlags_HUGENArchive::NExt::CNode654*f6dc9357SAndroid Build Coastguard Worker   bool IsFlags_HUGE()    const { return (Flags & k_NodeFlags_HUGE) != 0; }
IsFlags_EXTENTSNArchive::NExt::CNode655*f6dc9357SAndroid Build Coastguard Worker   bool IsFlags_EXTENTS() const { return (Flags & k_NodeFlags_EXTENTS) != 0; }
656*f6dc9357SAndroid Build Coastguard Worker 
IsDirNArchive::NExt::CNode657*f6dc9357SAndroid Build Coastguard Worker   bool IsDir()     const { return MY_LIN_S_ISDIR(Mode); }
IsRegularNArchive::NExt::CNode658*f6dc9357SAndroid Build Coastguard Worker   bool IsRegular() const { return MY_LIN_S_ISREG(Mode); }
IsLinkNArchive::NExt::CNode659*f6dc9357SAndroid Build Coastguard Worker   bool IsLink()    const { return MY_LIN_S_ISLNK(Mode); }
660*f6dc9357SAndroid Build Coastguard Worker 
661*f6dc9357SAndroid Build Coastguard Worker   bool Parse(const Byte *p, const CHeader &_h);
662*f6dc9357SAndroid Build Coastguard Worker };
663*f6dc9357SAndroid Build Coastguard Worker 
664*f6dc9357SAndroid Build Coastguard Worker 
Parse(const Byte * p,const CHeader & _h)665*f6dc9357SAndroid Build Coastguard Worker bool CNode::Parse(const Byte *p, const CHeader &_h)
666*f6dc9357SAndroid Build Coastguard Worker {
667*f6dc9357SAndroid Build Coastguard Worker   MTime.Extra = 0;
668*f6dc9357SAndroid Build Coastguard Worker   ATime.Extra = 0;
669*f6dc9357SAndroid Build Coastguard Worker   CTime.Extra = 0;
670*f6dc9357SAndroid Build Coastguard Worker   CTime.Val = 0;
671*f6dc9357SAndroid Build Coastguard Worker   ChangeTime.Extra = 0;
672*f6dc9357SAndroid Build Coastguard Worker   // DTime.Extra = 0;
673*f6dc9357SAndroid Build Coastguard Worker 
674*f6dc9357SAndroid Build Coastguard Worker   LE_16 (0x00, Mode)
675*f6dc9357SAndroid Build Coastguard Worker   LE_16 (0x02, Uid)
676*f6dc9357SAndroid Build Coastguard Worker   LE_32 (0x04, FileSize)
677*f6dc9357SAndroid Build Coastguard Worker   LE_32 (0x08, ATime.Val)
678*f6dc9357SAndroid Build Coastguard Worker   LE_32 (0x0C, ChangeTime.Val)
679*f6dc9357SAndroid Build Coastguard Worker   LE_32 (0x10, MTime.Val)
680*f6dc9357SAndroid Build Coastguard Worker   // LE_32 (0x14, DTime.Val);
681*f6dc9357SAndroid Build Coastguard Worker   LE_16 (0x18, Gid)
682*f6dc9357SAndroid Build Coastguard Worker   LE_16 (0x1A, NumLinks)
683*f6dc9357SAndroid Build Coastguard Worker 
684*f6dc9357SAndroid Build Coastguard Worker   LE_32 (0x1C, NumBlocks)
685*f6dc9357SAndroid Build Coastguard Worker   LE_32 (0x20, Flags)
686*f6dc9357SAndroid Build Coastguard Worker   // LE_32 (0x24, Union osd1);
687*f6dc9357SAndroid Build Coastguard Worker 
688*f6dc9357SAndroid Build Coastguard Worker   memcpy(Block, p + 0x28, kNodeBlockFieldSize);
689*f6dc9357SAndroid Build Coastguard Worker 
690*f6dc9357SAndroid Build Coastguard Worker   // LE_32 (0x64, Generation);  // File version (for NFS)
691*f6dc9357SAndroid Build Coastguard Worker   // LE_32 (0x68, ACL);
692*f6dc9357SAndroid Build Coastguard Worker 
693*f6dc9357SAndroid Build Coastguard Worker   {
694*f6dc9357SAndroid Build Coastguard Worker     UInt32 highSize;
695*f6dc9357SAndroid Build Coastguard Worker     LE_32 (0x6C, highSize) // In ext2/3 this field was named i_dir_acl
696*f6dc9357SAndroid Build Coastguard Worker 
697*f6dc9357SAndroid Build Coastguard Worker     if (IsRegular()) // do we need that check ?
698*f6dc9357SAndroid Build Coastguard Worker       FileSize |= ((UInt64)highSize << 32);
699*f6dc9357SAndroid Build Coastguard Worker   }
700*f6dc9357SAndroid Build Coastguard Worker 
701*f6dc9357SAndroid Build Coastguard Worker   // UInt32 fragmentAddress;
702*f6dc9357SAndroid Build Coastguard Worker   // LE_32 (0x70, fragmentAddress);
703*f6dc9357SAndroid Build Coastguard Worker 
704*f6dc9357SAndroid Build Coastguard Worker   // osd2
705*f6dc9357SAndroid Build Coastguard Worker   {
706*f6dc9357SAndroid Build Coastguard Worker     // Linux;
707*f6dc9357SAndroid Build Coastguard Worker     // ext2:
708*f6dc9357SAndroid Build Coastguard Worker     // Byte FragmentNumber = p[0x74];
709*f6dc9357SAndroid Build Coastguard Worker     // Byte FragmentSize = p[0x74 + 1];
710*f6dc9357SAndroid Build Coastguard Worker 
711*f6dc9357SAndroid Build Coastguard Worker     // ext4:
712*f6dc9357SAndroid Build Coastguard Worker     UInt32 numBlocksHigh;
713*f6dc9357SAndroid Build Coastguard Worker     LE_16 (0x74, numBlocksHigh)
714*f6dc9357SAndroid Build Coastguard Worker     NumBlocks |= (UInt64)numBlocksHigh << 32;
715*f6dc9357SAndroid Build Coastguard Worker 
716*f6dc9357SAndroid Build Coastguard Worker     HI_16 (0x74 + 4, Uid)
717*f6dc9357SAndroid Build Coastguard Worker     HI_16 (0x74 + 6, Gid)
718*f6dc9357SAndroid Build Coastguard Worker     /*
719*f6dc9357SAndroid Build Coastguard Worker     UInt32 checksum;
720*f6dc9357SAndroid Build Coastguard Worker     LE_16 (0x74 + 8, checksum);
721*f6dc9357SAndroid Build Coastguard Worker     checksum = checksum;
722*f6dc9357SAndroid Build Coastguard Worker     */
723*f6dc9357SAndroid Build Coastguard Worker   }
724*f6dc9357SAndroid Build Coastguard Worker 
725*f6dc9357SAndroid Build Coastguard Worker   // 0x74: Byte Union osd2[12];
726*f6dc9357SAndroid Build Coastguard Worker 
727*f6dc9357SAndroid Build Coastguard Worker   if (_h.InodeSize > 128)
728*f6dc9357SAndroid Build Coastguard Worker   {
729*f6dc9357SAndroid Build Coastguard Worker     // InodeSize is power of 2, so the following check is not required:
730*f6dc9357SAndroid Build Coastguard Worker     // if (_h.InodeSize < 128 + 2) return false;
731*f6dc9357SAndroid Build Coastguard Worker     UInt16 extra_isize;
732*f6dc9357SAndroid Build Coastguard Worker     LE_16 (0x80, extra_isize)
733*f6dc9357SAndroid Build Coastguard Worker     if (128 + extra_isize > _h.InodeSize)
734*f6dc9357SAndroid Build Coastguard Worker       return false;
735*f6dc9357SAndroid Build Coastguard Worker     if (extra_isize >= 0x1C)
736*f6dc9357SAndroid Build Coastguard Worker     {
737*f6dc9357SAndroid Build Coastguard Worker       // UInt16 checksumUpper;
738*f6dc9357SAndroid Build Coastguard Worker       // LE_16 (0x82, checksumUpper);
739*f6dc9357SAndroid Build Coastguard Worker       LE_32 (0x84, ChangeTime.Extra)
740*f6dc9357SAndroid Build Coastguard Worker       LE_32 (0x88, MTime.Extra)
741*f6dc9357SAndroid Build Coastguard Worker       LE_32 (0x8C, ATime.Extra)
742*f6dc9357SAndroid Build Coastguard Worker       LE_32 (0x90, CTime.Val)
743*f6dc9357SAndroid Build Coastguard Worker       LE_32 (0x94, CTime.Extra)
744*f6dc9357SAndroid Build Coastguard Worker       // LE_32 (0x98, VersionHi)
745*f6dc9357SAndroid Build Coastguard Worker     }
746*f6dc9357SAndroid Build Coastguard Worker   }
747*f6dc9357SAndroid Build Coastguard Worker 
748*f6dc9357SAndroid Build Coastguard Worker   PRF(printf("size = %5d", (unsigned)FileSize));
749*f6dc9357SAndroid Build Coastguard Worker 
750*f6dc9357SAndroid Build Coastguard Worker   return true;
751*f6dc9357SAndroid Build Coastguard Worker }
752*f6dc9357SAndroid Build Coastguard Worker 
753*f6dc9357SAndroid Build Coastguard Worker 
754*f6dc9357SAndroid Build Coastguard Worker struct CItem
755*f6dc9357SAndroid Build Coastguard Worker {
756*f6dc9357SAndroid Build Coastguard Worker   unsigned Node;        // in _refs[]
757*f6dc9357SAndroid Build Coastguard Worker   int ParentNode;       // in _refs[]
758*f6dc9357SAndroid Build Coastguard Worker   int SymLinkItemIndex; // in _items[], if the Node contains SymLink to existing dir
759*f6dc9357SAndroid Build Coastguard Worker   Byte Type;
760*f6dc9357SAndroid Build Coastguard Worker 
761*f6dc9357SAndroid Build Coastguard Worker   AString Name;
762*f6dc9357SAndroid Build Coastguard Worker 
CItemNArchive::NExt::CItem763*f6dc9357SAndroid Build Coastguard Worker   CItem():
764*f6dc9357SAndroid Build Coastguard Worker       Node(0),
765*f6dc9357SAndroid Build Coastguard Worker       ParentNode(-1),
766*f6dc9357SAndroid Build Coastguard Worker       SymLinkItemIndex(-1),
767*f6dc9357SAndroid Build Coastguard Worker       Type(k_Type_UNKNOWN)
768*f6dc9357SAndroid Build Coastguard Worker         {}
769*f6dc9357SAndroid Build Coastguard Worker 
ClearNArchive::NExt::CItem770*f6dc9357SAndroid Build Coastguard Worker   void Clear()
771*f6dc9357SAndroid Build Coastguard Worker   {
772*f6dc9357SAndroid Build Coastguard Worker     Node = 0;
773*f6dc9357SAndroid Build Coastguard Worker     ParentNode = -1;
774*f6dc9357SAndroid Build Coastguard Worker     SymLinkItemIndex = -1;
775*f6dc9357SAndroid Build Coastguard Worker     Type = k_Type_UNKNOWN;
776*f6dc9357SAndroid Build Coastguard Worker     Name.Empty();
777*f6dc9357SAndroid Build Coastguard Worker   }
778*f6dc9357SAndroid Build Coastguard Worker 
IsDirNArchive::NExt::CItem779*f6dc9357SAndroid Build Coastguard Worker   bool IsDir() const { return Type == k_Type_DIR; }
780*f6dc9357SAndroid Build Coastguard Worker   // bool IsNotDir() const { return Type != k_Type_DIR && Type != k_Type_UNKNOWN; }
781*f6dc9357SAndroid Build Coastguard Worker };
782*f6dc9357SAndroid Build Coastguard Worker 
783*f6dc9357SAndroid Build Coastguard Worker 
784*f6dc9357SAndroid Build Coastguard Worker 
785*f6dc9357SAndroid Build Coastguard Worker static const unsigned kNumTreeLevelsMax = 6; // must be >= 3
786*f6dc9357SAndroid Build Coastguard Worker 
787*f6dc9357SAndroid Build Coastguard Worker 
788*f6dc9357SAndroid Build Coastguard Worker Z7_CLASS_IMP_CHandler_IInArchive_2(
789*f6dc9357SAndroid Build Coastguard Worker   IArchiveGetRawProps,
790*f6dc9357SAndroid Build Coastguard Worker   IInArchiveGetStream
791*f6dc9357SAndroid Build Coastguard Worker )
792*f6dc9357SAndroid Build Coastguard Worker   CObjectVector<CItem> _items;
793*f6dc9357SAndroid Build Coastguard Worker   CIntVector _refs;                 // iNode -> (index in _nodes). if (_refs[iNode] < 0), that node is not filled
794*f6dc9357SAndroid Build Coastguard Worker   CRecordVector<CNode> _nodes;
795*f6dc9357SAndroid Build Coastguard Worker   CObjectVector<CUIntVector> _dirs; // each CUIntVector contains indexes in _items[] only for dir items;
796*f6dc9357SAndroid Build Coastguard Worker   AStringVector _symLinks;
797*f6dc9357SAndroid Build Coastguard Worker   AStringVector _auxItems;
798*f6dc9357SAndroid Build Coastguard Worker   int _auxSysIndex;
799*f6dc9357SAndroid Build Coastguard Worker   int _auxUnknownIndex;
800*f6dc9357SAndroid Build Coastguard Worker 
801*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<IInStream> _stream;
802*f6dc9357SAndroid Build Coastguard Worker   UInt64 _phySize;
803*f6dc9357SAndroid Build Coastguard Worker   bool _isArc;
804*f6dc9357SAndroid Build Coastguard Worker   bool _headersError;
805*f6dc9357SAndroid Build Coastguard Worker   bool _headersWarning;
806*f6dc9357SAndroid Build Coastguard Worker   bool _linksError;
807*f6dc9357SAndroid Build Coastguard Worker 
808*f6dc9357SAndroid Build Coastguard Worker   bool _isUTF;
809*f6dc9357SAndroid Build Coastguard Worker 
810*f6dc9357SAndroid Build Coastguard Worker   CHeader _h;
811*f6dc9357SAndroid Build Coastguard Worker 
812*f6dc9357SAndroid Build Coastguard Worker   IArchiveOpenCallback *_openCallback;
813*f6dc9357SAndroid Build Coastguard Worker   UInt64 _totalRead;
814*f6dc9357SAndroid Build Coastguard Worker   UInt64 _totalReadPrev;
815*f6dc9357SAndroid Build Coastguard Worker 
816*f6dc9357SAndroid Build Coastguard Worker   CByteBuffer _tempBufs[kNumTreeLevelsMax];
817*f6dc9357SAndroid Build Coastguard Worker 
818*f6dc9357SAndroid Build Coastguard Worker 
CheckProgress2()819*f6dc9357SAndroid Build Coastguard Worker   HRESULT CheckProgress2()
820*f6dc9357SAndroid Build Coastguard Worker   {
821*f6dc9357SAndroid Build Coastguard Worker     const UInt64 numFiles = _items.Size();
822*f6dc9357SAndroid Build Coastguard Worker     return _openCallback->SetCompleted(&numFiles, &_totalRead);
823*f6dc9357SAndroid Build Coastguard Worker   }
824*f6dc9357SAndroid Build Coastguard Worker 
CheckProgress()825*f6dc9357SAndroid Build Coastguard Worker   HRESULT CheckProgress()
826*f6dc9357SAndroid Build Coastguard Worker   {
827*f6dc9357SAndroid Build Coastguard Worker     HRESULT res = S_OK;
828*f6dc9357SAndroid Build Coastguard Worker     if (_openCallback)
829*f6dc9357SAndroid Build Coastguard Worker     {
830*f6dc9357SAndroid Build Coastguard Worker       if (_totalRead - _totalReadPrev >= ((UInt32)1 << 20))
831*f6dc9357SAndroid Build Coastguard Worker       {
832*f6dc9357SAndroid Build Coastguard Worker         _totalReadPrev = _totalRead;
833*f6dc9357SAndroid Build Coastguard Worker         res = CheckProgress2();
834*f6dc9357SAndroid Build Coastguard Worker       }
835*f6dc9357SAndroid Build Coastguard Worker     }
836*f6dc9357SAndroid Build Coastguard Worker     return res;
837*f6dc9357SAndroid Build Coastguard Worker   }
838*f6dc9357SAndroid Build Coastguard Worker 
839*f6dc9357SAndroid Build Coastguard Worker 
GetParentAux(const CItem & item) const840*f6dc9357SAndroid Build Coastguard Worker   int GetParentAux(const CItem &item) const
841*f6dc9357SAndroid Build Coastguard Worker   {
842*f6dc9357SAndroid Build Coastguard Worker     if (item.Node < _h.FirstInode && _auxSysIndex >= 0)
843*f6dc9357SAndroid Build Coastguard Worker       return _auxSysIndex;
844*f6dc9357SAndroid Build Coastguard Worker     return _auxUnknownIndex;
845*f6dc9357SAndroid Build Coastguard Worker   }
846*f6dc9357SAndroid Build Coastguard Worker 
847*f6dc9357SAndroid Build Coastguard Worker   HRESULT SeekAndRead(IInStream *inStream, UInt64 block, Byte *data, size_t size);
848*f6dc9357SAndroid Build Coastguard Worker   HRESULT ParseDir(const Byte *data, size_t size, unsigned iNodeDir);
849*f6dc9357SAndroid Build Coastguard Worker   int FindTargetItem_for_SymLink(unsigned dirNode, const AString &path) const;
850*f6dc9357SAndroid Build Coastguard Worker 
851*f6dc9357SAndroid Build Coastguard Worker   HRESULT FillFileBlocks2(UInt32 block, unsigned level, unsigned numBlocks, CRecordVector<UInt32> &blocks);
852*f6dc9357SAndroid Build Coastguard Worker   HRESULT FillFileBlocks(const Byte *p, unsigned numBlocks, CRecordVector<UInt32> &blocks);
853*f6dc9357SAndroid Build Coastguard Worker   HRESULT FillExtents(const Byte *p, size_t size, CRecordVector<CExtent> &extents, int parentDepth);
854*f6dc9357SAndroid Build Coastguard Worker 
855*f6dc9357SAndroid Build Coastguard Worker   HRESULT GetStream_Node(unsigned nodeIndex, ISequentialInStream **stream);
856*f6dc9357SAndroid Build Coastguard Worker   HRESULT ExtractNode(unsigned nodeIndex, CByteBuffer &data);
857*f6dc9357SAndroid Build Coastguard Worker 
858*f6dc9357SAndroid Build Coastguard Worker   void ClearRefs();
859*f6dc9357SAndroid Build Coastguard Worker   HRESULT Open2(IInStream *inStream);
860*f6dc9357SAndroid Build Coastguard Worker 
861*f6dc9357SAndroid Build Coastguard Worker   void GetPath(unsigned index, AString &s) const;
862*f6dc9357SAndroid Build Coastguard Worker   bool GetPackSize(unsigned index, UInt64 &res) const;
863*f6dc9357SAndroid Build Coastguard Worker };
864*f6dc9357SAndroid Build Coastguard Worker 
865*f6dc9357SAndroid Build Coastguard Worker 
866*f6dc9357SAndroid Build Coastguard Worker 
ParseDir(const Byte * p,size_t size,unsigned iNodeDir)867*f6dc9357SAndroid Build Coastguard Worker HRESULT CHandler::ParseDir(const Byte *p, size_t size, unsigned iNodeDir)
868*f6dc9357SAndroid Build Coastguard Worker {
869*f6dc9357SAndroid Build Coastguard Worker   bool isThereSelfLink = false;
870*f6dc9357SAndroid Build Coastguard Worker 
871*f6dc9357SAndroid Build Coastguard Worker   PRF(printf("\n\n========= node = %5d    size = %5d", (unsigned)iNodeDir, (unsigned)size));
872*f6dc9357SAndroid Build Coastguard Worker 
873*f6dc9357SAndroid Build Coastguard Worker   CNode &nodeDir = _nodes[_refs[iNodeDir]];
874*f6dc9357SAndroid Build Coastguard Worker   nodeDir.DirIndex = (int)_dirs.Size();
875*f6dc9357SAndroid Build Coastguard Worker   CUIntVector &dir = _dirs.AddNew();
876*f6dc9357SAndroid Build Coastguard Worker   int parentNode = -1;
877*f6dc9357SAndroid Build Coastguard Worker 
878*f6dc9357SAndroid Build Coastguard Worker   CItem item;
879*f6dc9357SAndroid Build Coastguard Worker 
880*f6dc9357SAndroid Build Coastguard Worker   for (;;)
881*f6dc9357SAndroid Build Coastguard Worker   {
882*f6dc9357SAndroid Build Coastguard Worker     if (size == 0)
883*f6dc9357SAndroid Build Coastguard Worker       break;
884*f6dc9357SAndroid Build Coastguard Worker     if (size < 8)
885*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
886*f6dc9357SAndroid Build Coastguard Worker     UInt32 iNode;
887*f6dc9357SAndroid Build Coastguard Worker     LE_32 (0x00, iNode)
888*f6dc9357SAndroid Build Coastguard Worker     unsigned recLen;
889*f6dc9357SAndroid Build Coastguard Worker     LE_16 (0x04, recLen)
890*f6dc9357SAndroid Build Coastguard Worker     const unsigned nameLen = p[6];
891*f6dc9357SAndroid Build Coastguard Worker     const Byte type = p[7];
892*f6dc9357SAndroid Build Coastguard Worker 
893*f6dc9357SAndroid Build Coastguard Worker     if (recLen > size)
894*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
895*f6dc9357SAndroid Build Coastguard Worker     if (nameLen + 8 > recLen)
896*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
897*f6dc9357SAndroid Build Coastguard Worker 
898*f6dc9357SAndroid Build Coastguard Worker     if (iNode >= _refs.Size())
899*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
900*f6dc9357SAndroid Build Coastguard Worker 
901*f6dc9357SAndroid Build Coastguard Worker     item.Clear();
902*f6dc9357SAndroid Build Coastguard Worker 
903*f6dc9357SAndroid Build Coastguard Worker     if (_h.IsThereFileType())
904*f6dc9357SAndroid Build Coastguard Worker       item.Type = type;
905*f6dc9357SAndroid Build Coastguard Worker     else if (type != 0)
906*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
907*f6dc9357SAndroid Build Coastguard Worker 
908*f6dc9357SAndroid Build Coastguard Worker     item.ParentNode = (int)iNodeDir;
909*f6dc9357SAndroid Build Coastguard Worker     item.Node = iNode;
910*f6dc9357SAndroid Build Coastguard Worker     item.Name.SetFrom_CalcLen((const char *)(p + 8), nameLen);
911*f6dc9357SAndroid Build Coastguard Worker 
912*f6dc9357SAndroid Build Coastguard Worker     p += recLen;
913*f6dc9357SAndroid Build Coastguard Worker     size -= recLen;
914*f6dc9357SAndroid Build Coastguard Worker 
915*f6dc9357SAndroid Build Coastguard Worker     if (item.Name.Len() != nameLen)
916*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
917*f6dc9357SAndroid Build Coastguard Worker 
918*f6dc9357SAndroid Build Coastguard Worker     if (_isUTF)
919*f6dc9357SAndroid Build Coastguard Worker     {
920*f6dc9357SAndroid Build Coastguard Worker       // 21.07 : we force UTF8
921*f6dc9357SAndroid Build Coastguard Worker       // _isUTF = CheckUTF8_AString(item.Name);
922*f6dc9357SAndroid Build Coastguard Worker     }
923*f6dc9357SAndroid Build Coastguard Worker 
924*f6dc9357SAndroid Build Coastguard Worker     if (iNode == 0)
925*f6dc9357SAndroid Build Coastguard Worker     {
926*f6dc9357SAndroid Build Coastguard Worker       /*
927*f6dc9357SAndroid Build Coastguard Worker       ext3 deleted??
928*f6dc9357SAndroid Build Coastguard Worker       if (item.Name.Len() != 0)
929*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
930*f6dc9357SAndroid Build Coastguard Worker       */
931*f6dc9357SAndroid Build Coastguard Worker 
932*f6dc9357SAndroid Build Coastguard Worker       PRF(printf("\n EMPTY %6d %d %s", (unsigned)recLen, (unsigned)type, (const char *)item.Name));
933*f6dc9357SAndroid Build Coastguard Worker       if (type == 0xDE)
934*f6dc9357SAndroid Build Coastguard Worker       {
935*f6dc9357SAndroid Build Coastguard Worker         // checksum
936*f6dc9357SAndroid Build Coastguard Worker       }
937*f6dc9357SAndroid Build Coastguard Worker       continue;
938*f6dc9357SAndroid Build Coastguard Worker     }
939*f6dc9357SAndroid Build Coastguard Worker 
940*f6dc9357SAndroid Build Coastguard Worker     const int nodeIndex = _refs[iNode];
941*f6dc9357SAndroid Build Coastguard Worker     if (nodeIndex < 0)
942*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
943*f6dc9357SAndroid Build Coastguard Worker     CNode &node = _nodes[nodeIndex];
944*f6dc9357SAndroid Build Coastguard Worker 
945*f6dc9357SAndroid Build Coastguard Worker     if (_h.IsThereFileType() && type != 0)
946*f6dc9357SAndroid Build Coastguard Worker     {
947*f6dc9357SAndroid Build Coastguard Worker       if (type >= Z7_ARRAY_SIZE(k_TypeToMode))
948*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
949*f6dc9357SAndroid Build Coastguard Worker       if (k_TypeToMode[type] != (node.Mode & MY_LIN_S_IFMT))
950*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
951*f6dc9357SAndroid Build Coastguard Worker     }
952*f6dc9357SAndroid Build Coastguard Worker 
953*f6dc9357SAndroid Build Coastguard Worker     node.NumLinksCalced++;
954*f6dc9357SAndroid Build Coastguard Worker 
955*f6dc9357SAndroid Build Coastguard Worker     PRF(printf("\n%s %6d %s", item.IsDir() ? "DIR  " : "     ", (unsigned)item.Node, (const char *)item.Name));
956*f6dc9357SAndroid Build Coastguard Worker 
957*f6dc9357SAndroid Build Coastguard Worker     if (item.Name[0] == '.')
958*f6dc9357SAndroid Build Coastguard Worker     {
959*f6dc9357SAndroid Build Coastguard Worker       if (item.Name[1] == 0)
960*f6dc9357SAndroid Build Coastguard Worker       {
961*f6dc9357SAndroid Build Coastguard Worker         if (isThereSelfLink)
962*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
963*f6dc9357SAndroid Build Coastguard Worker         isThereSelfLink = true;
964*f6dc9357SAndroid Build Coastguard Worker         if (iNode != iNodeDir)
965*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
966*f6dc9357SAndroid Build Coastguard Worker         continue;
967*f6dc9357SAndroid Build Coastguard Worker       }
968*f6dc9357SAndroid Build Coastguard Worker 
969*f6dc9357SAndroid Build Coastguard Worker       if (item.Name[1] == '.' && item.Name[2] == 0)
970*f6dc9357SAndroid Build Coastguard Worker       {
971*f6dc9357SAndroid Build Coastguard Worker         if (parentNode >= 0)
972*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
973*f6dc9357SAndroid Build Coastguard Worker         if (!node.IsDir())
974*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
975*f6dc9357SAndroid Build Coastguard Worker         if (iNode == iNodeDir && iNode != k_INODE_ROOT)
976*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
977*f6dc9357SAndroid Build Coastguard Worker 
978*f6dc9357SAndroid Build Coastguard Worker         parentNode = (int)iNode;
979*f6dc9357SAndroid Build Coastguard Worker 
980*f6dc9357SAndroid Build Coastguard Worker         if (nodeDir.ParentNode < 0)
981*f6dc9357SAndroid Build Coastguard Worker           nodeDir.ParentNode = (int)iNode;
982*f6dc9357SAndroid Build Coastguard Worker         else if ((unsigned)nodeDir.ParentNode != iNode)
983*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
984*f6dc9357SAndroid Build Coastguard Worker 
985*f6dc9357SAndroid Build Coastguard Worker         continue;
986*f6dc9357SAndroid Build Coastguard Worker       }
987*f6dc9357SAndroid Build Coastguard Worker     }
988*f6dc9357SAndroid Build Coastguard Worker 
989*f6dc9357SAndroid Build Coastguard Worker     if (iNode == iNodeDir)
990*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
991*f6dc9357SAndroid Build Coastguard Worker 
992*f6dc9357SAndroid Build Coastguard Worker     if (parentNode < 0)
993*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
994*f6dc9357SAndroid Build Coastguard Worker 
995*f6dc9357SAndroid Build Coastguard Worker     if (node.IsDir())
996*f6dc9357SAndroid Build Coastguard Worker     {
997*f6dc9357SAndroid Build Coastguard Worker       if (node.ParentNode < 0)
998*f6dc9357SAndroid Build Coastguard Worker         node.ParentNode = (int)iNodeDir;
999*f6dc9357SAndroid Build Coastguard Worker       else if ((unsigned)node.ParentNode != iNodeDir)
1000*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
1001*f6dc9357SAndroid Build Coastguard Worker       const unsigned itemIndex = _items.Size();
1002*f6dc9357SAndroid Build Coastguard Worker       dir.Add(itemIndex);
1003*f6dc9357SAndroid Build Coastguard Worker       node.ItemIndex = (int)itemIndex;
1004*f6dc9357SAndroid Build Coastguard Worker     }
1005*f6dc9357SAndroid Build Coastguard Worker 
1006*f6dc9357SAndroid Build Coastguard Worker     _items.Add(item);
1007*f6dc9357SAndroid Build Coastguard Worker   }
1008*f6dc9357SAndroid Build Coastguard Worker 
1009*f6dc9357SAndroid Build Coastguard Worker   if (parentNode < 0 || !isThereSelfLink)
1010*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
1011*f6dc9357SAndroid Build Coastguard Worker 
1012*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1013*f6dc9357SAndroid Build Coastguard Worker }
1014*f6dc9357SAndroid Build Coastguard Worker 
1015*f6dc9357SAndroid Build Coastguard Worker 
CompareItemsNames(const unsigned * p1,const unsigned * p2,void * param)1016*f6dc9357SAndroid Build Coastguard Worker static int CompareItemsNames(const unsigned *p1, const unsigned *p2, void *param)
1017*f6dc9357SAndroid Build Coastguard Worker {
1018*f6dc9357SAndroid Build Coastguard Worker   const CObjectVector<CItem> &items = *(const CObjectVector<CItem> *)param;
1019*f6dc9357SAndroid Build Coastguard Worker   return strcmp(items[*p1].Name, items[*p2].Name);
1020*f6dc9357SAndroid Build Coastguard Worker }
1021*f6dc9357SAndroid Build Coastguard Worker 
1022*f6dc9357SAndroid Build Coastguard Worker 
FindTargetItem_for_SymLink(unsigned iNode,const AString & path) const1023*f6dc9357SAndroid Build Coastguard Worker int CHandler::FindTargetItem_for_SymLink(unsigned iNode, const AString &path) const
1024*f6dc9357SAndroid Build Coastguard Worker {
1025*f6dc9357SAndroid Build Coastguard Worker   unsigned pos = 0;
1026*f6dc9357SAndroid Build Coastguard Worker 
1027*f6dc9357SAndroid Build Coastguard Worker   if (path.IsEmpty())
1028*f6dc9357SAndroid Build Coastguard Worker     return -1;
1029*f6dc9357SAndroid Build Coastguard Worker 
1030*f6dc9357SAndroid Build Coastguard Worker   if (path[0] == '/')
1031*f6dc9357SAndroid Build Coastguard Worker   {
1032*f6dc9357SAndroid Build Coastguard Worker     iNode = k_INODE_ROOT;
1033*f6dc9357SAndroid Build Coastguard Worker     if (iNode >= _refs.Size())
1034*f6dc9357SAndroid Build Coastguard Worker       return -1;
1035*f6dc9357SAndroid Build Coastguard Worker     pos = 1;
1036*f6dc9357SAndroid Build Coastguard Worker   }
1037*f6dc9357SAndroid Build Coastguard Worker 
1038*f6dc9357SAndroid Build Coastguard Worker   AString s;
1039*f6dc9357SAndroid Build Coastguard Worker 
1040*f6dc9357SAndroid Build Coastguard Worker   while (pos != path.Len())
1041*f6dc9357SAndroid Build Coastguard Worker   {
1042*f6dc9357SAndroid Build Coastguard Worker     const CNode &node = _nodes[_refs[iNode]];
1043*f6dc9357SAndroid Build Coastguard Worker     const int slash = path.Find('/', pos);
1044*f6dc9357SAndroid Build Coastguard Worker 
1045*f6dc9357SAndroid Build Coastguard Worker     if (slash < 0)
1046*f6dc9357SAndroid Build Coastguard Worker     {
1047*f6dc9357SAndroid Build Coastguard Worker       s = path.Ptr(pos);
1048*f6dc9357SAndroid Build Coastguard Worker       pos = path.Len();
1049*f6dc9357SAndroid Build Coastguard Worker     }
1050*f6dc9357SAndroid Build Coastguard Worker     else
1051*f6dc9357SAndroid Build Coastguard Worker     {
1052*f6dc9357SAndroid Build Coastguard Worker       s.SetFrom(path.Ptr(pos), (unsigned)slash - pos);
1053*f6dc9357SAndroid Build Coastguard Worker       pos = (unsigned)slash + 1;
1054*f6dc9357SAndroid Build Coastguard Worker     }
1055*f6dc9357SAndroid Build Coastguard Worker 
1056*f6dc9357SAndroid Build Coastguard Worker     if (s[0] == '.')
1057*f6dc9357SAndroid Build Coastguard Worker     {
1058*f6dc9357SAndroid Build Coastguard Worker       if (s[1] == 0)
1059*f6dc9357SAndroid Build Coastguard Worker         continue;
1060*f6dc9357SAndroid Build Coastguard Worker       else if (s[1] == '.' && s[2] == 0)
1061*f6dc9357SAndroid Build Coastguard Worker       {
1062*f6dc9357SAndroid Build Coastguard Worker         if (node.ParentNode < 0)
1063*f6dc9357SAndroid Build Coastguard Worker           return -1;
1064*f6dc9357SAndroid Build Coastguard Worker         if (iNode == k_INODE_ROOT)
1065*f6dc9357SAndroid Build Coastguard Worker           return -1;
1066*f6dc9357SAndroid Build Coastguard Worker         iNode = (unsigned)node.ParentNode;
1067*f6dc9357SAndroid Build Coastguard Worker         continue;
1068*f6dc9357SAndroid Build Coastguard Worker       }
1069*f6dc9357SAndroid Build Coastguard Worker     }
1070*f6dc9357SAndroid Build Coastguard Worker 
1071*f6dc9357SAndroid Build Coastguard Worker     if (node.DirIndex < 0)
1072*f6dc9357SAndroid Build Coastguard Worker       return -1;
1073*f6dc9357SAndroid Build Coastguard Worker 
1074*f6dc9357SAndroid Build Coastguard Worker     const CUIntVector &dir = _dirs[node.DirIndex];
1075*f6dc9357SAndroid Build Coastguard Worker 
1076*f6dc9357SAndroid Build Coastguard Worker     /*
1077*f6dc9357SAndroid Build Coastguard Worker     for (unsigned i = 0;; i++)
1078*f6dc9357SAndroid Build Coastguard Worker     {
1079*f6dc9357SAndroid Build Coastguard Worker       if (i >= dir.Size())
1080*f6dc9357SAndroid Build Coastguard Worker         return -1;
1081*f6dc9357SAndroid Build Coastguard Worker       const CItem &item = _items[dir[i]];
1082*f6dc9357SAndroid Build Coastguard Worker       if (item.Name == s)
1083*f6dc9357SAndroid Build Coastguard Worker       {
1084*f6dc9357SAndroid Build Coastguard Worker         iNode = item.Node;
1085*f6dc9357SAndroid Build Coastguard Worker         break;
1086*f6dc9357SAndroid Build Coastguard Worker       }
1087*f6dc9357SAndroid Build Coastguard Worker     }
1088*f6dc9357SAndroid Build Coastguard Worker     */
1089*f6dc9357SAndroid Build Coastguard Worker 
1090*f6dc9357SAndroid Build Coastguard Worker     unsigned left = 0, right = dir.Size();
1091*f6dc9357SAndroid Build Coastguard Worker     for (;;)
1092*f6dc9357SAndroid Build Coastguard Worker     {
1093*f6dc9357SAndroid Build Coastguard Worker       if (left == right)
1094*f6dc9357SAndroid Build Coastguard Worker         return -1;
1095*f6dc9357SAndroid Build Coastguard Worker       const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
1096*f6dc9357SAndroid Build Coastguard Worker       const CItem &item = _items[dir[mid]];
1097*f6dc9357SAndroid Build Coastguard Worker       const int comp = strcmp(s, item.Name);
1098*f6dc9357SAndroid Build Coastguard Worker       if (comp == 0)
1099*f6dc9357SAndroid Build Coastguard Worker       {
1100*f6dc9357SAndroid Build Coastguard Worker         iNode = item.Node;
1101*f6dc9357SAndroid Build Coastguard Worker         break;
1102*f6dc9357SAndroid Build Coastguard Worker       }
1103*f6dc9357SAndroid Build Coastguard Worker       if (comp < 0)
1104*f6dc9357SAndroid Build Coastguard Worker         right = mid;
1105*f6dc9357SAndroid Build Coastguard Worker       else
1106*f6dc9357SAndroid Build Coastguard Worker         left = mid + 1;
1107*f6dc9357SAndroid Build Coastguard Worker     }
1108*f6dc9357SAndroid Build Coastguard Worker   }
1109*f6dc9357SAndroid Build Coastguard Worker 
1110*f6dc9357SAndroid Build Coastguard Worker   return _nodes[_refs[iNode]].ItemIndex;
1111*f6dc9357SAndroid Build Coastguard Worker }
1112*f6dc9357SAndroid Build Coastguard Worker 
1113*f6dc9357SAndroid Build Coastguard Worker 
SeekAndRead(IInStream * inStream,UInt64 block,Byte * data,size_t size)1114*f6dc9357SAndroid Build Coastguard Worker HRESULT CHandler::SeekAndRead(IInStream *inStream, UInt64 block, Byte *data, size_t size)
1115*f6dc9357SAndroid Build Coastguard Worker {
1116*f6dc9357SAndroid Build Coastguard Worker   if (block == 0 || block >= _h.NumBlocks)
1117*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
1118*f6dc9357SAndroid Build Coastguard Worker   if (((size + ((size_t)1 << _h.BlockBits) - 1) >> _h.BlockBits) > _h.NumBlocks - block)
1119*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
1120*f6dc9357SAndroid Build Coastguard Worker   RINOK(InStream_SeekSet(inStream, (UInt64)block << _h.BlockBits))
1121*f6dc9357SAndroid Build Coastguard Worker   _totalRead += size;
1122*f6dc9357SAndroid Build Coastguard Worker   return ReadStream_FALSE(inStream, data, size);
1123*f6dc9357SAndroid Build Coastguard Worker }
1124*f6dc9357SAndroid Build Coastguard Worker 
1125*f6dc9357SAndroid Build Coastguard Worker 
1126*f6dc9357SAndroid Build Coastguard Worker static const unsigned kHeaderSize = 2 * 1024;
1127*f6dc9357SAndroid Build Coastguard Worker static const unsigned kHeaderDataOffset = 1024;
1128*f6dc9357SAndroid Build Coastguard Worker 
Open2(IInStream * inStream)1129*f6dc9357SAndroid Build Coastguard Worker HRESULT CHandler::Open2(IInStream *inStream)
1130*f6dc9357SAndroid Build Coastguard Worker {
1131*f6dc9357SAndroid Build Coastguard Worker   {
1132*f6dc9357SAndroid Build Coastguard Worker     Byte buf[kHeaderSize];
1133*f6dc9357SAndroid Build Coastguard Worker     RINOK(ReadStream_FALSE(inStream, buf, kHeaderSize))
1134*f6dc9357SAndroid Build Coastguard Worker     if (!_h.Parse(buf + kHeaderDataOffset))
1135*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1136*f6dc9357SAndroid Build Coastguard Worker     if (_h.BlockGroupNr != 0)
1137*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE; // it's just copy of super block
1138*f6dc9357SAndroid Build Coastguard Worker   }
1139*f6dc9357SAndroid Build Coastguard Worker 
1140*f6dc9357SAndroid Build Coastguard Worker   {
1141*f6dc9357SAndroid Build Coastguard Worker     // ---------- Read groups and nodes ----------
1142*f6dc9357SAndroid Build Coastguard Worker 
1143*f6dc9357SAndroid Build Coastguard Worker     unsigned numGroups;
1144*f6dc9357SAndroid Build Coastguard Worker     {
1145*f6dc9357SAndroid Build Coastguard Worker       const UInt64 numGroups64 = _h.GetNumGroups();
1146*f6dc9357SAndroid Build Coastguard Worker       if (numGroups64 > (UInt32)1 << 31)
1147*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
1148*f6dc9357SAndroid Build Coastguard Worker       numGroups = (unsigned)numGroups64;
1149*f6dc9357SAndroid Build Coastguard Worker     }
1150*f6dc9357SAndroid Build Coastguard Worker 
1151*f6dc9357SAndroid Build Coastguard Worker     unsigned gdBits = 5;
1152*f6dc9357SAndroid Build Coastguard Worker     if (_h.Is64Bit())
1153*f6dc9357SAndroid Build Coastguard Worker     {
1154*f6dc9357SAndroid Build Coastguard Worker       if (_h.GdSize != 64)
1155*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
1156*f6dc9357SAndroid Build Coastguard Worker       gdBits = 6;
1157*f6dc9357SAndroid Build Coastguard Worker     }
1158*f6dc9357SAndroid Build Coastguard Worker 
1159*f6dc9357SAndroid Build Coastguard Worker     _isArc = true;
1160*f6dc9357SAndroid Build Coastguard Worker     _phySize = _h.GetPhySize();
1161*f6dc9357SAndroid Build Coastguard Worker 
1162*f6dc9357SAndroid Build Coastguard Worker     if (_openCallback)
1163*f6dc9357SAndroid Build Coastguard Worker     {
1164*f6dc9357SAndroid Build Coastguard Worker       RINOK(_openCallback->SetTotal(NULL, &_phySize))
1165*f6dc9357SAndroid Build Coastguard Worker     }
1166*f6dc9357SAndroid Build Coastguard Worker 
1167*f6dc9357SAndroid Build Coastguard Worker     UInt64 fileSize = 0;
1168*f6dc9357SAndroid Build Coastguard Worker     RINOK(InStream_GetSize_SeekToEnd(inStream, fileSize))
1169*f6dc9357SAndroid Build Coastguard Worker 
1170*f6dc9357SAndroid Build Coastguard Worker     CRecordVector<CGroupDescriptor> groups;
1171*f6dc9357SAndroid Build Coastguard Worker 
1172*f6dc9357SAndroid Build Coastguard Worker     {
1173*f6dc9357SAndroid Build Coastguard Worker       // ---------- Read groups ----------
1174*f6dc9357SAndroid Build Coastguard Worker 
1175*f6dc9357SAndroid Build Coastguard Worker       CByteBuffer gdBuf;
1176*f6dc9357SAndroid Build Coastguard Worker       const size_t gdBufSize = (size_t)numGroups << gdBits;
1177*f6dc9357SAndroid Build Coastguard Worker       if ((gdBufSize >> gdBits) != numGroups)
1178*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
1179*f6dc9357SAndroid Build Coastguard Worker       gdBuf.Alloc(gdBufSize);
1180*f6dc9357SAndroid Build Coastguard Worker       RINOK(SeekAndRead(inStream, (_h.BlockBits <= 10 ? 2 : 1), gdBuf, gdBufSize))
1181*f6dc9357SAndroid Build Coastguard Worker 
1182*f6dc9357SAndroid Build Coastguard Worker       for (unsigned i = 0; i < numGroups; i++)
1183*f6dc9357SAndroid Build Coastguard Worker       {
1184*f6dc9357SAndroid Build Coastguard Worker         CGroupDescriptor gd;
1185*f6dc9357SAndroid Build Coastguard Worker 
1186*f6dc9357SAndroid Build Coastguard Worker         const Byte *p = gdBuf + ((size_t)i << gdBits);
1187*f6dc9357SAndroid Build Coastguard Worker         const unsigned gd_Size = (unsigned)1 << gdBits;
1188*f6dc9357SAndroid Build Coastguard Worker         gd.Parse(p, gd_Size);
1189*f6dc9357SAndroid Build Coastguard Worker 
1190*f6dc9357SAndroid Build Coastguard Worker         if (_h.UseMetadataChecksum())
1191*f6dc9357SAndroid Build Coastguard Worker         {
1192*f6dc9357SAndroid Build Coastguard Worker           // use CRC32c
1193*f6dc9357SAndroid Build Coastguard Worker         }
1194*f6dc9357SAndroid Build Coastguard Worker         else if (_h.UseGdtChecksum())
1195*f6dc9357SAndroid Build Coastguard Worker         {
1196*f6dc9357SAndroid Build Coastguard Worker           UInt32 crc = Crc16Calc(_h.Uuid, sizeof(_h.Uuid));
1197*f6dc9357SAndroid Build Coastguard Worker           Byte i_le[4];
1198*f6dc9357SAndroid Build Coastguard Worker           SetUi32(i_le, i)
1199*f6dc9357SAndroid Build Coastguard Worker           crc = Crc16Update(crc, i_le, 4);
1200*f6dc9357SAndroid Build Coastguard Worker           crc = Crc16Update(crc, p, 32 - 2);
1201*f6dc9357SAndroid Build Coastguard Worker           if (gd_Size != 32)
1202*f6dc9357SAndroid Build Coastguard Worker             crc = Crc16Update(crc, p + 32, gd_Size - 32);
1203*f6dc9357SAndroid Build Coastguard Worker           if (crc != gd.Checksum)
1204*f6dc9357SAndroid Build Coastguard Worker             return S_FALSE;
1205*f6dc9357SAndroid Build Coastguard Worker         }
1206*f6dc9357SAndroid Build Coastguard Worker 
1207*f6dc9357SAndroid Build Coastguard Worker         groups.Add(gd);
1208*f6dc9357SAndroid Build Coastguard Worker       }
1209*f6dc9357SAndroid Build Coastguard Worker     }
1210*f6dc9357SAndroid Build Coastguard Worker 
1211*f6dc9357SAndroid Build Coastguard Worker     {
1212*f6dc9357SAndroid Build Coastguard Worker       // ---------- Read nodes ----------
1213*f6dc9357SAndroid Build Coastguard Worker 
1214*f6dc9357SAndroid Build Coastguard Worker       if (_h.NumInodes < _h.NumFreeInodes)
1215*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
1216*f6dc9357SAndroid Build Coastguard Worker 
1217*f6dc9357SAndroid Build Coastguard Worker       UInt32 numNodes = _h.InodesPerGroup;
1218*f6dc9357SAndroid Build Coastguard Worker       if (numNodes > _h.NumInodes)
1219*f6dc9357SAndroid Build Coastguard Worker         numNodes = _h.NumInodes;
1220*f6dc9357SAndroid Build Coastguard Worker       const size_t nodesDataSize = (size_t)numNodes * _h.InodeSize;
1221*f6dc9357SAndroid Build Coastguard Worker 
1222*f6dc9357SAndroid Build Coastguard Worker       if (nodesDataSize / _h.InodeSize != numNodes)
1223*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
1224*f6dc9357SAndroid Build Coastguard Worker 
1225*f6dc9357SAndroid Build Coastguard Worker       // that code to reduce false detecting cases
1226*f6dc9357SAndroid Build Coastguard Worker       if (nodesDataSize > fileSize)
1227*f6dc9357SAndroid Build Coastguard Worker       {
1228*f6dc9357SAndroid Build Coastguard Worker         if (numNodes > (1 << 24))
1229*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
1230*f6dc9357SAndroid Build Coastguard Worker       }
1231*f6dc9357SAndroid Build Coastguard Worker 
1232*f6dc9357SAndroid Build Coastguard Worker       const UInt32 numReserveInodes = _h.NumInodes - _h.NumFreeInodes + 1;
1233*f6dc9357SAndroid Build Coastguard Worker       // numReserveInodes = _h.NumInodes + 1;
1234*f6dc9357SAndroid Build Coastguard Worker       if (numReserveInodes != 0)
1235*f6dc9357SAndroid Build Coastguard Worker       {
1236*f6dc9357SAndroid Build Coastguard Worker         _nodes.Reserve(numReserveInodes);
1237*f6dc9357SAndroid Build Coastguard Worker         _refs.Reserve(numReserveInodes);
1238*f6dc9357SAndroid Build Coastguard Worker       }
1239*f6dc9357SAndroid Build Coastguard Worker 
1240*f6dc9357SAndroid Build Coastguard Worker       CByteBuffer nodesData;
1241*f6dc9357SAndroid Build Coastguard Worker       nodesData.Alloc(nodesDataSize);
1242*f6dc9357SAndroid Build Coastguard Worker 
1243*f6dc9357SAndroid Build Coastguard Worker       CByteBuffer nodesMap;
1244*f6dc9357SAndroid Build Coastguard Worker       const size_t blockSize = (size_t)1 << _h.BlockBits;
1245*f6dc9357SAndroid Build Coastguard Worker       nodesMap.Alloc(blockSize);
1246*f6dc9357SAndroid Build Coastguard Worker 
1247*f6dc9357SAndroid Build Coastguard Worker       unsigned globalNodeIndex = 0;
1248*f6dc9357SAndroid Build Coastguard Worker       // unsigned numEmpty = 0;
1249*f6dc9357SAndroid Build Coastguard Worker       unsigned numEmpty_in_Maps = 0;
1250*f6dc9357SAndroid Build Coastguard Worker 
1251*f6dc9357SAndroid Build Coastguard Worker       FOR_VECTOR (gi, groups)
1252*f6dc9357SAndroid Build Coastguard Worker       {
1253*f6dc9357SAndroid Build Coastguard Worker         if (globalNodeIndex >= _h.NumInodes)
1254*f6dc9357SAndroid Build Coastguard Worker           break;
1255*f6dc9357SAndroid Build Coastguard Worker 
1256*f6dc9357SAndroid Build Coastguard Worker         const CGroupDescriptor &gd = groups[gi];
1257*f6dc9357SAndroid Build Coastguard Worker 
1258*f6dc9357SAndroid Build Coastguard Worker         PRF(printf("\n\ng%6d block = %6x\n", gi, (unsigned)gd.InodeTable));
1259*f6dc9357SAndroid Build Coastguard Worker 
1260*f6dc9357SAndroid Build Coastguard Worker         RINOK(SeekAndRead(inStream, gd.InodeBitmap, nodesMap, blockSize))
1261*f6dc9357SAndroid Build Coastguard Worker         RINOK(SeekAndRead(inStream, gd.InodeTable, nodesData, nodesDataSize))
1262*f6dc9357SAndroid Build Coastguard Worker 
1263*f6dc9357SAndroid Build Coastguard Worker         unsigned numEmpty_in_Map = 0;
1264*f6dc9357SAndroid Build Coastguard Worker 
1265*f6dc9357SAndroid Build Coastguard Worker         for (size_t n = 0; n < numNodes && globalNodeIndex < _h.NumInodes; n++, globalNodeIndex++)
1266*f6dc9357SAndroid Build Coastguard Worker         {
1267*f6dc9357SAndroid Build Coastguard Worker           if ((nodesMap[n >> 3] & ((unsigned)1 << (n & 7))) == 0)
1268*f6dc9357SAndroid Build Coastguard Worker           {
1269*f6dc9357SAndroid Build Coastguard Worker             numEmpty_in_Map++;
1270*f6dc9357SAndroid Build Coastguard Worker             continue;
1271*f6dc9357SAndroid Build Coastguard Worker           }
1272*f6dc9357SAndroid Build Coastguard Worker 
1273*f6dc9357SAndroid Build Coastguard Worker           const Byte *p = nodesData + (size_t)n * _h.InodeSize;
1274*f6dc9357SAndroid Build Coastguard Worker           if (IsEmptyData(p, _h.InodeSize))
1275*f6dc9357SAndroid Build Coastguard Worker           {
1276*f6dc9357SAndroid Build Coastguard Worker             if (globalNodeIndex + 1 >= _h.FirstInode)
1277*f6dc9357SAndroid Build Coastguard Worker             {
1278*f6dc9357SAndroid Build Coastguard Worker               _headersError = true;
1279*f6dc9357SAndroid Build Coastguard Worker               // return S_FALSE;
1280*f6dc9357SAndroid Build Coastguard Worker             }
1281*f6dc9357SAndroid Build Coastguard Worker             continue;
1282*f6dc9357SAndroid Build Coastguard Worker           }
1283*f6dc9357SAndroid Build Coastguard Worker 
1284*f6dc9357SAndroid Build Coastguard Worker           CNode node;
1285*f6dc9357SAndroid Build Coastguard Worker 
1286*f6dc9357SAndroid Build Coastguard Worker           PRF(printf("\nnode = %5d ", (unsigned)n));
1287*f6dc9357SAndroid Build Coastguard Worker 
1288*f6dc9357SAndroid Build Coastguard Worker           if (!node.Parse(p, _h))
1289*f6dc9357SAndroid Build Coastguard Worker             return S_FALSE;
1290*f6dc9357SAndroid Build Coastguard Worker 
1291*f6dc9357SAndroid Build Coastguard Worker           // PRF(printf("\n %6d", (unsigned)n));
1292*f6dc9357SAndroid Build Coastguard Worker           /*
1293*f6dc9357SAndroid Build Coastguard Worker             SetUi32(p + 0x7C, 0)
1294*f6dc9357SAndroid Build Coastguard Worker             SetUi32(p + 0x82, 0)
1295*f6dc9357SAndroid Build Coastguard Worker 
1296*f6dc9357SAndroid Build Coastguard Worker             UInt32 crc = Crc32C_Calc(_h.Uuid, sizeof(_h.Uuid));
1297*f6dc9357SAndroid Build Coastguard Worker             Byte i_le[4];
1298*f6dc9357SAndroid Build Coastguard Worker             SetUi32(i_le, n);
1299*f6dc9357SAndroid Build Coastguard Worker             crc = Crc32C_Update(crc, i_le, 4);
1300*f6dc9357SAndroid Build Coastguard Worker             crc = Crc32C_Update(crc, p, _h.InodeSize);
1301*f6dc9357SAndroid Build Coastguard Worker             if (crc != node.Checksum) return S_FALSE;
1302*f6dc9357SAndroid Build Coastguard Worker           */
1303*f6dc9357SAndroid Build Coastguard Worker 
1304*f6dc9357SAndroid Build Coastguard Worker           while (_refs.Size() < globalNodeIndex + 1)
1305*f6dc9357SAndroid Build Coastguard Worker           {
1306*f6dc9357SAndroid Build Coastguard Worker             // numEmpty++;
1307*f6dc9357SAndroid Build Coastguard Worker             _refs.Add(-1);
1308*f6dc9357SAndroid Build Coastguard Worker           }
1309*f6dc9357SAndroid Build Coastguard Worker 
1310*f6dc9357SAndroid Build Coastguard Worker           _refs.Add((int)_nodes.Add(node));
1311*f6dc9357SAndroid Build Coastguard Worker         }
1312*f6dc9357SAndroid Build Coastguard Worker 
1313*f6dc9357SAndroid Build Coastguard Worker 
1314*f6dc9357SAndroid Build Coastguard Worker         numEmpty_in_Maps += numEmpty_in_Map;
1315*f6dc9357SAndroid Build Coastguard Worker 
1316*f6dc9357SAndroid Build Coastguard Worker         if (numEmpty_in_Map != gd.NumFreeInodes)
1317*f6dc9357SAndroid Build Coastguard Worker         {
1318*f6dc9357SAndroid Build Coastguard Worker           _headersWarning = true;
1319*f6dc9357SAndroid Build Coastguard Worker           // return S_FALSE;
1320*f6dc9357SAndroid Build Coastguard Worker         }
1321*f6dc9357SAndroid Build Coastguard Worker       }
1322*f6dc9357SAndroid Build Coastguard Worker 
1323*f6dc9357SAndroid Build Coastguard Worker       if (numEmpty_in_Maps != _h.NumFreeInodes)
1324*f6dc9357SAndroid Build Coastguard Worker       {
1325*f6dc9357SAndroid Build Coastguard Worker         // some ext2 examples has incorrect value in _h.NumFreeInodes.
1326*f6dc9357SAndroid Build Coastguard Worker         // so we disable check;
1327*f6dc9357SAndroid Build Coastguard Worker         _headersWarning = true;
1328*f6dc9357SAndroid Build Coastguard Worker       }
1329*f6dc9357SAndroid Build Coastguard Worker 
1330*f6dc9357SAndroid Build Coastguard Worker       if (_refs.Size() <= k_INODE_ROOT)
1331*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
1332*f6dc9357SAndroid Build Coastguard Worker 
1333*f6dc9357SAndroid Build Coastguard Worker       // printf("\n numReserveInodes = %6d, _refs.Size() = %d, numEmpty = %7d\n", numReserveInodes, _refs.Size(), (unsigned)numEmpty);
1334*f6dc9357SAndroid Build Coastguard Worker     }
1335*f6dc9357SAndroid Build Coastguard Worker   }
1336*f6dc9357SAndroid Build Coastguard Worker 
1337*f6dc9357SAndroid Build Coastguard Worker   _stream = inStream; // we need stream for dir nodes
1338*f6dc9357SAndroid Build Coastguard Worker 
1339*f6dc9357SAndroid Build Coastguard Worker   {
1340*f6dc9357SAndroid Build Coastguard Worker     // ---------- Read Dirs ----------
1341*f6dc9357SAndroid Build Coastguard Worker 
1342*f6dc9357SAndroid Build Coastguard Worker     CByteBuffer dataBuf;
1343*f6dc9357SAndroid Build Coastguard Worker 
1344*f6dc9357SAndroid Build Coastguard Worker     FOR_VECTOR (i, _refs)
1345*f6dc9357SAndroid Build Coastguard Worker     {
1346*f6dc9357SAndroid Build Coastguard Worker       const int nodeIndex = _refs[i];
1347*f6dc9357SAndroid Build Coastguard Worker       {
1348*f6dc9357SAndroid Build Coastguard Worker         if (nodeIndex < 0)
1349*f6dc9357SAndroid Build Coastguard Worker           continue;
1350*f6dc9357SAndroid Build Coastguard Worker         const CNode &node = _nodes[nodeIndex];
1351*f6dc9357SAndroid Build Coastguard Worker         if (!node.IsDir())
1352*f6dc9357SAndroid Build Coastguard Worker           continue;
1353*f6dc9357SAndroid Build Coastguard Worker       }
1354*f6dc9357SAndroid Build Coastguard Worker       RINOK(ExtractNode((unsigned)nodeIndex, dataBuf))
1355*f6dc9357SAndroid Build Coastguard Worker       if (dataBuf.Size() == 0)
1356*f6dc9357SAndroid Build Coastguard Worker       {
1357*f6dc9357SAndroid Build Coastguard Worker         // _headersError = true;
1358*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
1359*f6dc9357SAndroid Build Coastguard Worker       }
1360*f6dc9357SAndroid Build Coastguard Worker       else
1361*f6dc9357SAndroid Build Coastguard Worker       {
1362*f6dc9357SAndroid Build Coastguard Worker         RINOK(ParseDir(dataBuf, dataBuf.Size(), i))
1363*f6dc9357SAndroid Build Coastguard Worker       }
1364*f6dc9357SAndroid Build Coastguard Worker       RINOK(CheckProgress())
1365*f6dc9357SAndroid Build Coastguard Worker     }
1366*f6dc9357SAndroid Build Coastguard Worker 
1367*f6dc9357SAndroid Build Coastguard Worker     const int ref = _refs[k_INODE_ROOT];
1368*f6dc9357SAndroid Build Coastguard Worker     if (ref < 0 || _nodes[ref].ParentNode != k_INODE_ROOT)
1369*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1370*f6dc9357SAndroid Build Coastguard Worker   }
1371*f6dc9357SAndroid Build Coastguard Worker 
1372*f6dc9357SAndroid Build Coastguard Worker   {
1373*f6dc9357SAndroid Build Coastguard Worker     // ---------- Check NumLinks and unreferenced dir nodes ----------
1374*f6dc9357SAndroid Build Coastguard Worker 
1375*f6dc9357SAndroid Build Coastguard Worker     FOR_VECTOR (i, _refs)
1376*f6dc9357SAndroid Build Coastguard Worker     {
1377*f6dc9357SAndroid Build Coastguard Worker       int nodeIndex = _refs[i];
1378*f6dc9357SAndroid Build Coastguard Worker       if (nodeIndex < 0)
1379*f6dc9357SAndroid Build Coastguard Worker         continue;
1380*f6dc9357SAndroid Build Coastguard Worker       const CNode &node = _nodes[nodeIndex];
1381*f6dc9357SAndroid Build Coastguard Worker 
1382*f6dc9357SAndroid Build Coastguard Worker       if (node.NumLinks != node.NumLinksCalced)
1383*f6dc9357SAndroid Build Coastguard Worker       {
1384*f6dc9357SAndroid Build Coastguard Worker         if (node.NumLinks != 1 || node.NumLinksCalced != 0
1385*f6dc9357SAndroid Build Coastguard Worker             // ) && i >= _h.FirstInode
1386*f6dc9357SAndroid Build Coastguard Worker             )
1387*f6dc9357SAndroid Build Coastguard Worker         {
1388*f6dc9357SAndroid Build Coastguard Worker           _linksError = true;
1389*f6dc9357SAndroid Build Coastguard Worker           // return S_FALSE;
1390*f6dc9357SAndroid Build Coastguard Worker         }
1391*f6dc9357SAndroid Build Coastguard Worker       }
1392*f6dc9357SAndroid Build Coastguard Worker 
1393*f6dc9357SAndroid Build Coastguard Worker       if (!node.IsDir())
1394*f6dc9357SAndroid Build Coastguard Worker         continue;
1395*f6dc9357SAndroid Build Coastguard Worker 
1396*f6dc9357SAndroid Build Coastguard Worker       if (node.ParentNode < 0)
1397*f6dc9357SAndroid Build Coastguard Worker       {
1398*f6dc9357SAndroid Build Coastguard Worker         if (i >= _h.FirstInode)
1399*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
1400*f6dc9357SAndroid Build Coastguard Worker         continue;
1401*f6dc9357SAndroid Build Coastguard Worker       }
1402*f6dc9357SAndroid Build Coastguard Worker     }
1403*f6dc9357SAndroid Build Coastguard Worker   }
1404*f6dc9357SAndroid Build Coastguard Worker 
1405*f6dc9357SAndroid Build Coastguard Worker   {
1406*f6dc9357SAndroid Build Coastguard Worker     // ---------- Check that there is no loops in parents list ----------
1407*f6dc9357SAndroid Build Coastguard Worker 
1408*f6dc9357SAndroid Build Coastguard Worker     unsigned numNodes = _refs.Size();
1409*f6dc9357SAndroid Build Coastguard Worker     CIntArr UsedByNode(numNodes);
1410*f6dc9357SAndroid Build Coastguard Worker     {
1411*f6dc9357SAndroid Build Coastguard Worker       {
1412*f6dc9357SAndroid Build Coastguard Worker         for (unsigned i = 0; i < numNodes; i++)
1413*f6dc9357SAndroid Build Coastguard Worker           UsedByNode[i] = -1;
1414*f6dc9357SAndroid Build Coastguard Worker       }
1415*f6dc9357SAndroid Build Coastguard Worker     }
1416*f6dc9357SAndroid Build Coastguard Worker 
1417*f6dc9357SAndroid Build Coastguard Worker     FOR_VECTOR (i, _refs)
1418*f6dc9357SAndroid Build Coastguard Worker     {
1419*f6dc9357SAndroid Build Coastguard Worker       {
1420*f6dc9357SAndroid Build Coastguard Worker         int nodeIndex = _refs[i];
1421*f6dc9357SAndroid Build Coastguard Worker         if (nodeIndex < 0)
1422*f6dc9357SAndroid Build Coastguard Worker           continue;
1423*f6dc9357SAndroid Build Coastguard Worker         const CNode &node = _nodes[nodeIndex];
1424*f6dc9357SAndroid Build Coastguard Worker         if (node.ParentNode < 0 // not dir
1425*f6dc9357SAndroid Build Coastguard Worker             || i == k_INODE_ROOT)
1426*f6dc9357SAndroid Build Coastguard Worker           continue;
1427*f6dc9357SAndroid Build Coastguard Worker       }
1428*f6dc9357SAndroid Build Coastguard Worker 
1429*f6dc9357SAndroid Build Coastguard Worker       unsigned c = i;
1430*f6dc9357SAndroid Build Coastguard Worker 
1431*f6dc9357SAndroid Build Coastguard Worker       for (;;)
1432*f6dc9357SAndroid Build Coastguard Worker       {
1433*f6dc9357SAndroid Build Coastguard Worker         const int nodeIndex = _refs[c];
1434*f6dc9357SAndroid Build Coastguard Worker         if (nodeIndex < 0)
1435*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
1436*f6dc9357SAndroid Build Coastguard Worker         CNode &node = _nodes[nodeIndex];
1437*f6dc9357SAndroid Build Coastguard Worker 
1438*f6dc9357SAndroid Build Coastguard Worker         if (UsedByNode[c] != -1)
1439*f6dc9357SAndroid Build Coastguard Worker         {
1440*f6dc9357SAndroid Build Coastguard Worker           if ((unsigned)UsedByNode[c] == i)
1441*f6dc9357SAndroid Build Coastguard Worker             return S_FALSE;
1442*f6dc9357SAndroid Build Coastguard Worker           break;
1443*f6dc9357SAndroid Build Coastguard Worker         }
1444*f6dc9357SAndroid Build Coastguard Worker 
1445*f6dc9357SAndroid Build Coastguard Worker         UsedByNode[c] = (int)i;
1446*f6dc9357SAndroid Build Coastguard Worker         if (node.ParentNode < 0 || node.ParentNode == k_INODE_ROOT)
1447*f6dc9357SAndroid Build Coastguard Worker           break;
1448*f6dc9357SAndroid Build Coastguard Worker         if ((unsigned)node.ParentNode == i)
1449*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
1450*f6dc9357SAndroid Build Coastguard Worker         c = (unsigned)node.ParentNode;
1451*f6dc9357SAndroid Build Coastguard Worker       }
1452*f6dc9357SAndroid Build Coastguard Worker     }
1453*f6dc9357SAndroid Build Coastguard Worker   }
1454*f6dc9357SAndroid Build Coastguard Worker 
1455*f6dc9357SAndroid Build Coastguard Worker   {
1456*f6dc9357SAndroid Build Coastguard Worker     // ---------- Fill SymLinks data ----------
1457*f6dc9357SAndroid Build Coastguard Worker 
1458*f6dc9357SAndroid Build Coastguard Worker     AString s;
1459*f6dc9357SAndroid Build Coastguard Worker     CByteBuffer data;
1460*f6dc9357SAndroid Build Coastguard Worker 
1461*f6dc9357SAndroid Build Coastguard Worker     unsigned i;
1462*f6dc9357SAndroid Build Coastguard Worker     for (i = 0; i < _refs.Size(); i++)
1463*f6dc9357SAndroid Build Coastguard Worker     {
1464*f6dc9357SAndroid Build Coastguard Worker       const int nodeIndex = _refs[i];
1465*f6dc9357SAndroid Build Coastguard Worker       if (nodeIndex < 0)
1466*f6dc9357SAndroid Build Coastguard Worker         continue;
1467*f6dc9357SAndroid Build Coastguard Worker       CNode &node = _nodes[nodeIndex];
1468*f6dc9357SAndroid Build Coastguard Worker       if (!node.IsLink())
1469*f6dc9357SAndroid Build Coastguard Worker         continue;
1470*f6dc9357SAndroid Build Coastguard Worker       if (node.FileSize > ((UInt32)1 << 14))
1471*f6dc9357SAndroid Build Coastguard Worker         continue;
1472*f6dc9357SAndroid Build Coastguard Worker       if (ExtractNode((unsigned)nodeIndex, data) == S_OK && data.Size() != 0)
1473*f6dc9357SAndroid Build Coastguard Worker       {
1474*f6dc9357SAndroid Build Coastguard Worker         s.SetFrom_CalcLen((const char *)(const Byte *)data, (unsigned)data.Size());
1475*f6dc9357SAndroid Build Coastguard Worker         if (s.Len() == data.Size())
1476*f6dc9357SAndroid Build Coastguard Worker           node.SymLinkIndex = (int)_symLinks.Add(s);
1477*f6dc9357SAndroid Build Coastguard Worker         RINOK(CheckProgress())
1478*f6dc9357SAndroid Build Coastguard Worker       }
1479*f6dc9357SAndroid Build Coastguard Worker     }
1480*f6dc9357SAndroid Build Coastguard Worker 
1481*f6dc9357SAndroid Build Coastguard Worker     for (i = 0; i < _dirs.Size(); i++)
1482*f6dc9357SAndroid Build Coastguard Worker     {
1483*f6dc9357SAndroid Build Coastguard Worker       _dirs[i].Sort(CompareItemsNames, (void *)&_items);
1484*f6dc9357SAndroid Build Coastguard Worker     }
1485*f6dc9357SAndroid Build Coastguard Worker 
1486*f6dc9357SAndroid Build Coastguard Worker     unsigned prev = 0;
1487*f6dc9357SAndroid Build Coastguard Worker     unsigned complex = 0;
1488*f6dc9357SAndroid Build Coastguard Worker 
1489*f6dc9357SAndroid Build Coastguard Worker     for (i = 0; i < _items.Size(); i++)
1490*f6dc9357SAndroid Build Coastguard Worker     {
1491*f6dc9357SAndroid Build Coastguard Worker       CItem &item = _items[i];
1492*f6dc9357SAndroid Build Coastguard Worker       const int sym = _nodes[_refs[item.Node]].SymLinkIndex;
1493*f6dc9357SAndroid Build Coastguard Worker       if (sym >= 0 && item.ParentNode >= 0)
1494*f6dc9357SAndroid Build Coastguard Worker       {
1495*f6dc9357SAndroid Build Coastguard Worker         item.SymLinkItemIndex = FindTargetItem_for_SymLink((unsigned)item.ParentNode, _symLinks[sym]);
1496*f6dc9357SAndroid Build Coastguard Worker         if (_openCallback)
1497*f6dc9357SAndroid Build Coastguard Worker         {
1498*f6dc9357SAndroid Build Coastguard Worker           complex++;
1499*f6dc9357SAndroid Build Coastguard Worker           if (complex - prev >= (1 << 10))
1500*f6dc9357SAndroid Build Coastguard Worker           {
1501*f6dc9357SAndroid Build Coastguard Worker             prev = complex;
1502*f6dc9357SAndroid Build Coastguard Worker             RINOK(CheckProgress2())
1503*f6dc9357SAndroid Build Coastguard Worker           }
1504*f6dc9357SAndroid Build Coastguard Worker         }
1505*f6dc9357SAndroid Build Coastguard Worker       }
1506*f6dc9357SAndroid Build Coastguard Worker     }
1507*f6dc9357SAndroid Build Coastguard Worker   }
1508*f6dc9357SAndroid Build Coastguard Worker 
1509*f6dc9357SAndroid Build Coastguard Worker   {
1510*f6dc9357SAndroid Build Coastguard Worker     // ---------- Add items and aux folders for unreferenced files ----------
1511*f6dc9357SAndroid Build Coastguard Worker 
1512*f6dc9357SAndroid Build Coastguard Worker     bool useSys = false;
1513*f6dc9357SAndroid Build Coastguard Worker     bool useUnknown = false;
1514*f6dc9357SAndroid Build Coastguard Worker 
1515*f6dc9357SAndroid Build Coastguard Worker     FOR_VECTOR (i, _refs)
1516*f6dc9357SAndroid Build Coastguard Worker     {
1517*f6dc9357SAndroid Build Coastguard Worker       const int nodeIndex = _refs[i];
1518*f6dc9357SAndroid Build Coastguard Worker       if (nodeIndex < 0)
1519*f6dc9357SAndroid Build Coastguard Worker         continue;
1520*f6dc9357SAndroid Build Coastguard Worker       const CNode &node = _nodes[nodeIndex];
1521*f6dc9357SAndroid Build Coastguard Worker 
1522*f6dc9357SAndroid Build Coastguard Worker       if (node.NumLinksCalced == 0 /* || i > 100 && i < 150 */) // for debug
1523*f6dc9357SAndroid Build Coastguard Worker       {
1524*f6dc9357SAndroid Build Coastguard Worker         CItem item;
1525*f6dc9357SAndroid Build Coastguard Worker         item.Node = i;
1526*f6dc9357SAndroid Build Coastguard Worker 
1527*f6dc9357SAndroid Build Coastguard Worker         // we don't know how to work with k_INODE_RESIZE node (strange FileSize and Block values).
1528*f6dc9357SAndroid Build Coastguard Worker         // so we ignore it;
1529*f6dc9357SAndroid Build Coastguard Worker 
1530*f6dc9357SAndroid Build Coastguard Worker         if (i == k_INODE_RESIZE)
1531*f6dc9357SAndroid Build Coastguard Worker           continue;
1532*f6dc9357SAndroid Build Coastguard Worker 
1533*f6dc9357SAndroid Build Coastguard Worker         if (node.FileSize == 0)
1534*f6dc9357SAndroid Build Coastguard Worker           continue;
1535*f6dc9357SAndroid Build Coastguard Worker 
1536*f6dc9357SAndroid Build Coastguard Worker         if (i < _h.FirstInode)
1537*f6dc9357SAndroid Build Coastguard Worker         {
1538*f6dc9357SAndroid Build Coastguard Worker           if (item.Node < Z7_ARRAY_SIZE(k_SysInode_Names))
1539*f6dc9357SAndroid Build Coastguard Worker             item.Name = k_SysInode_Names[item.Node];
1540*f6dc9357SAndroid Build Coastguard Worker           useSys = true;
1541*f6dc9357SAndroid Build Coastguard Worker         }
1542*f6dc9357SAndroid Build Coastguard Worker         else
1543*f6dc9357SAndroid Build Coastguard Worker           useUnknown = true;
1544*f6dc9357SAndroid Build Coastguard Worker 
1545*f6dc9357SAndroid Build Coastguard Worker         if (item.Name.IsEmpty())
1546*f6dc9357SAndroid Build Coastguard Worker           item.Name.Add_UInt32(item.Node);
1547*f6dc9357SAndroid Build Coastguard Worker 
1548*f6dc9357SAndroid Build Coastguard Worker         _items.Add(item);
1549*f6dc9357SAndroid Build Coastguard Worker       }
1550*f6dc9357SAndroid Build Coastguard Worker     }
1551*f6dc9357SAndroid Build Coastguard Worker 
1552*f6dc9357SAndroid Build Coastguard Worker     if (useSys)
1553*f6dc9357SAndroid Build Coastguard Worker       _auxSysIndex = (int)_auxItems.Add((AString)"[SYS]");
1554*f6dc9357SAndroid Build Coastguard Worker     if (useUnknown)
1555*f6dc9357SAndroid Build Coastguard Worker       _auxUnknownIndex = (int)_auxItems.Add((AString)"[UNKNOWN]");
1556*f6dc9357SAndroid Build Coastguard Worker   }
1557*f6dc9357SAndroid Build Coastguard Worker 
1558*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1559*f6dc9357SAndroid Build Coastguard Worker }
1560*f6dc9357SAndroid Build Coastguard Worker 
1561*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::Open (IInStream * stream,const UInt64 *,IArchiveOpenCallback * callback))1562*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback))
1563*f6dc9357SAndroid Build Coastguard Worker {
1564*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
1565*f6dc9357SAndroid Build Coastguard Worker   {
1566*f6dc9357SAndroid Build Coastguard Worker     Close();
1567*f6dc9357SAndroid Build Coastguard Worker     HRESULT res;
1568*f6dc9357SAndroid Build Coastguard Worker     try
1569*f6dc9357SAndroid Build Coastguard Worker     {
1570*f6dc9357SAndroid Build Coastguard Worker       _openCallback = callback;
1571*f6dc9357SAndroid Build Coastguard Worker       res = Open2(stream);
1572*f6dc9357SAndroid Build Coastguard Worker     }
1573*f6dc9357SAndroid Build Coastguard Worker     catch(...)
1574*f6dc9357SAndroid Build Coastguard Worker     {
1575*f6dc9357SAndroid Build Coastguard Worker       ClearRefs();
1576*f6dc9357SAndroid Build Coastguard Worker       throw;
1577*f6dc9357SAndroid Build Coastguard Worker     }
1578*f6dc9357SAndroid Build Coastguard Worker 
1579*f6dc9357SAndroid Build Coastguard Worker     if (res != S_OK)
1580*f6dc9357SAndroid Build Coastguard Worker     {
1581*f6dc9357SAndroid Build Coastguard Worker       ClearRefs();
1582*f6dc9357SAndroid Build Coastguard Worker       return res;
1583*f6dc9357SAndroid Build Coastguard Worker     }
1584*f6dc9357SAndroid Build Coastguard Worker     _stream = stream;
1585*f6dc9357SAndroid Build Coastguard Worker   }
1586*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1587*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
1588*f6dc9357SAndroid Build Coastguard Worker }
1589*f6dc9357SAndroid Build Coastguard Worker 
1590*f6dc9357SAndroid Build Coastguard Worker 
ClearRefs()1591*f6dc9357SAndroid Build Coastguard Worker void CHandler::ClearRefs()
1592*f6dc9357SAndroid Build Coastguard Worker {
1593*f6dc9357SAndroid Build Coastguard Worker   _stream.Release();
1594*f6dc9357SAndroid Build Coastguard Worker   _items.Clear();
1595*f6dc9357SAndroid Build Coastguard Worker   _nodes.Clear();
1596*f6dc9357SAndroid Build Coastguard Worker   _refs.Clear();
1597*f6dc9357SAndroid Build Coastguard Worker   _auxItems.Clear();
1598*f6dc9357SAndroid Build Coastguard Worker   _symLinks.Clear();
1599*f6dc9357SAndroid Build Coastguard Worker   _dirs.Clear();
1600*f6dc9357SAndroid Build Coastguard Worker   _auxSysIndex = -1;
1601*f6dc9357SAndroid Build Coastguard Worker   _auxUnknownIndex = -1;
1602*f6dc9357SAndroid Build Coastguard Worker }
1603*f6dc9357SAndroid Build Coastguard Worker 
1604*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::Close ())1605*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Close())
1606*f6dc9357SAndroid Build Coastguard Worker {
1607*f6dc9357SAndroid Build Coastguard Worker   _totalRead = 0;
1608*f6dc9357SAndroid Build Coastguard Worker   _totalReadPrev = 0;
1609*f6dc9357SAndroid Build Coastguard Worker   _phySize = 0;
1610*f6dc9357SAndroid Build Coastguard Worker   _isArc = false;
1611*f6dc9357SAndroid Build Coastguard Worker   _headersError = false;
1612*f6dc9357SAndroid Build Coastguard Worker   _headersWarning = false;
1613*f6dc9357SAndroid Build Coastguard Worker   _linksError = false;
1614*f6dc9357SAndroid Build Coastguard Worker   _isUTF = true;
1615*f6dc9357SAndroid Build Coastguard Worker 
1616*f6dc9357SAndroid Build Coastguard Worker   ClearRefs();
1617*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1618*f6dc9357SAndroid Build Coastguard Worker }
1619*f6dc9357SAndroid Build Coastguard Worker 
1620*f6dc9357SAndroid Build Coastguard Worker 
ChangeSeparatorsInName(char * s,unsigned num)1621*f6dc9357SAndroid Build Coastguard Worker static void ChangeSeparatorsInName(char *s, unsigned num)
1622*f6dc9357SAndroid Build Coastguard Worker {
1623*f6dc9357SAndroid Build Coastguard Worker   for (unsigned i = 0; i < num; i++)
1624*f6dc9357SAndroid Build Coastguard Worker   {
1625*f6dc9357SAndroid Build Coastguard Worker     char c = s[i];
1626*f6dc9357SAndroid Build Coastguard Worker     if (c == CHAR_PATH_SEPARATOR || c == '/')
1627*f6dc9357SAndroid Build Coastguard Worker       s[i] = '_';
1628*f6dc9357SAndroid Build Coastguard Worker   }
1629*f6dc9357SAndroid Build Coastguard Worker }
1630*f6dc9357SAndroid Build Coastguard Worker 
1631*f6dc9357SAndroid Build Coastguard Worker 
GetPath(unsigned index,AString & s) const1632*f6dc9357SAndroid Build Coastguard Worker void CHandler::GetPath(unsigned index, AString &s) const
1633*f6dc9357SAndroid Build Coastguard Worker {
1634*f6dc9357SAndroid Build Coastguard Worker   s.Empty();
1635*f6dc9357SAndroid Build Coastguard Worker 
1636*f6dc9357SAndroid Build Coastguard Worker   if (index >= _items.Size())
1637*f6dc9357SAndroid Build Coastguard Worker   {
1638*f6dc9357SAndroid Build Coastguard Worker     s = _auxItems[index - _items.Size()];
1639*f6dc9357SAndroid Build Coastguard Worker     return;
1640*f6dc9357SAndroid Build Coastguard Worker   }
1641*f6dc9357SAndroid Build Coastguard Worker 
1642*f6dc9357SAndroid Build Coastguard Worker   for (;;)
1643*f6dc9357SAndroid Build Coastguard Worker   {
1644*f6dc9357SAndroid Build Coastguard Worker     const CItem &item = _items[index];
1645*f6dc9357SAndroid Build Coastguard Worker     if (!s.IsEmpty())
1646*f6dc9357SAndroid Build Coastguard Worker       s.InsertAtFront(CHAR_PATH_SEPARATOR);
1647*f6dc9357SAndroid Build Coastguard Worker     s.Insert(0, item.Name);
1648*f6dc9357SAndroid Build Coastguard Worker     // 18.06
1649*f6dc9357SAndroid Build Coastguard Worker     ChangeSeparatorsInName(s.GetBuf(), item.Name.Len());
1650*f6dc9357SAndroid Build Coastguard Worker 
1651*f6dc9357SAndroid Build Coastguard Worker     if (item.ParentNode == k_INODE_ROOT)
1652*f6dc9357SAndroid Build Coastguard Worker       return;
1653*f6dc9357SAndroid Build Coastguard Worker 
1654*f6dc9357SAndroid Build Coastguard Worker     if (item.ParentNode < 0)
1655*f6dc9357SAndroid Build Coastguard Worker     {
1656*f6dc9357SAndroid Build Coastguard Worker       int aux = GetParentAux(item);
1657*f6dc9357SAndroid Build Coastguard Worker       if (aux < 0)
1658*f6dc9357SAndroid Build Coastguard Worker         break;
1659*f6dc9357SAndroid Build Coastguard Worker       s.InsertAtFront(CHAR_PATH_SEPARATOR);
1660*f6dc9357SAndroid Build Coastguard Worker       s.Insert(0, _auxItems[aux]);
1661*f6dc9357SAndroid Build Coastguard Worker       return;
1662*f6dc9357SAndroid Build Coastguard Worker     }
1663*f6dc9357SAndroid Build Coastguard Worker 
1664*f6dc9357SAndroid Build Coastguard Worker     const CNode &node = _nodes[_refs[item.ParentNode]];
1665*f6dc9357SAndroid Build Coastguard Worker     if (node.ItemIndex < 0)
1666*f6dc9357SAndroid Build Coastguard Worker       return;
1667*f6dc9357SAndroid Build Coastguard Worker     index = (unsigned)node.ItemIndex;
1668*f6dc9357SAndroid Build Coastguard Worker 
1669*f6dc9357SAndroid Build Coastguard Worker     if (s.Len() > ((UInt32)1 << 16))
1670*f6dc9357SAndroid Build Coastguard Worker     {
1671*f6dc9357SAndroid Build Coastguard Worker       s.Insert(0, "[LONG]" STRING_PATH_SEPARATOR);
1672*f6dc9357SAndroid Build Coastguard Worker       return;
1673*f6dc9357SAndroid Build Coastguard Worker     }
1674*f6dc9357SAndroid Build Coastguard Worker   }
1675*f6dc9357SAndroid Build Coastguard Worker }
1676*f6dc9357SAndroid Build Coastguard Worker 
1677*f6dc9357SAndroid Build Coastguard Worker 
GetPackSize(unsigned index,UInt64 & totalPack) const1678*f6dc9357SAndroid Build Coastguard Worker bool CHandler::GetPackSize(unsigned index, UInt64 &totalPack) const
1679*f6dc9357SAndroid Build Coastguard Worker {
1680*f6dc9357SAndroid Build Coastguard Worker   if (index >= _items.Size())
1681*f6dc9357SAndroid Build Coastguard Worker   {
1682*f6dc9357SAndroid Build Coastguard Worker     totalPack = 0;
1683*f6dc9357SAndroid Build Coastguard Worker     return false;
1684*f6dc9357SAndroid Build Coastguard Worker   }
1685*f6dc9357SAndroid Build Coastguard Worker 
1686*f6dc9357SAndroid Build Coastguard Worker   const CItem &item = _items[index];
1687*f6dc9357SAndroid Build Coastguard Worker   const CNode &node = _nodes[_refs[item.Node]];
1688*f6dc9357SAndroid Build Coastguard Worker 
1689*f6dc9357SAndroid Build Coastguard Worker   // if (!node.IsFlags_EXTENTS())
1690*f6dc9357SAndroid Build Coastguard Worker   {
1691*f6dc9357SAndroid Build Coastguard Worker     totalPack = (UInt64)node.NumBlocks << (node.IsFlags_HUGE() ? _h.BlockBits : 9);
1692*f6dc9357SAndroid Build Coastguard Worker     return true;
1693*f6dc9357SAndroid Build Coastguard Worker   }
1694*f6dc9357SAndroid Build Coastguard Worker 
1695*f6dc9357SAndroid Build Coastguard Worker   /*
1696*f6dc9357SAndroid Build Coastguard Worker   CExtentTreeHeader eth;
1697*f6dc9357SAndroid Build Coastguard Worker   if (!eth.Parse(node.Block))
1698*f6dc9357SAndroid Build Coastguard Worker     return false;
1699*f6dc9357SAndroid Build Coastguard Worker   if (eth.NumEntries > 3)
1700*f6dc9357SAndroid Build Coastguard Worker     return false;
1701*f6dc9357SAndroid Build Coastguard Worker   if (!eth.Depth == 0)
1702*f6dc9357SAndroid Build Coastguard Worker     return false;
1703*f6dc9357SAndroid Build Coastguard Worker 
1704*f6dc9357SAndroid Build Coastguard Worker   UInt64 numBlocks = 0;
1705*f6dc9357SAndroid Build Coastguard Worker   {
1706*f6dc9357SAndroid Build Coastguard Worker     for (unsigned i = 0; i < eth.NumEntries; i++)
1707*f6dc9357SAndroid Build Coastguard Worker     {
1708*f6dc9357SAndroid Build Coastguard Worker       CExtent e;
1709*f6dc9357SAndroid Build Coastguard Worker       e.Parse(node.Block + 12 + i * 12);
1710*f6dc9357SAndroid Build Coastguard Worker       // const CExtent &e = node.leafs[i];
1711*f6dc9357SAndroid Build Coastguard Worker       if (e.IsInited)
1712*f6dc9357SAndroid Build Coastguard Worker         numBlocks += e.Len;
1713*f6dc9357SAndroid Build Coastguard Worker     }
1714*f6dc9357SAndroid Build Coastguard Worker   }
1715*f6dc9357SAndroid Build Coastguard Worker 
1716*f6dc9357SAndroid Build Coastguard Worker   totalPack = numBlocks << _h.BlockBits;
1717*f6dc9357SAndroid Build Coastguard Worker   return true;
1718*f6dc9357SAndroid Build Coastguard Worker   */
1719*f6dc9357SAndroid Build Coastguard Worker }
1720*f6dc9357SAndroid Build Coastguard Worker 
1721*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::GetNumberOfItems (UInt32 * numItems))1722*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
1723*f6dc9357SAndroid Build Coastguard Worker {
1724*f6dc9357SAndroid Build Coastguard Worker   *numItems = _items.Size() + _auxItems.Size();
1725*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1726*f6dc9357SAndroid Build Coastguard Worker }
1727*f6dc9357SAndroid Build Coastguard Worker 
1728*f6dc9357SAndroid Build Coastguard Worker enum
1729*f6dc9357SAndroid Build Coastguard Worker {
1730*f6dc9357SAndroid Build Coastguard Worker   kpidMountTime = kpidUserDefined,
1731*f6dc9357SAndroid Build Coastguard Worker   kpidLastCheckTime,
1732*f6dc9357SAndroid Build Coastguard Worker   kpidRevision,
1733*f6dc9357SAndroid Build Coastguard Worker   kpidINodeSize,
1734*f6dc9357SAndroid Build Coastguard Worker   kpidLastMount,
1735*f6dc9357SAndroid Build Coastguard Worker   kpidFeatureIncompat,
1736*f6dc9357SAndroid Build Coastguard Worker   kpidFeatureRoCompat,
1737*f6dc9357SAndroid Build Coastguard Worker   kpidWrittenKB
1738*f6dc9357SAndroid Build Coastguard Worker 
1739*f6dc9357SAndroid Build Coastguard Worker   // kpidGroupSize,
1740*f6dc9357SAndroid Build Coastguard Worker 
1741*f6dc9357SAndroid Build Coastguard Worker   // kpidChangeTime = kpidUserDefined + 256,
1742*f6dc9357SAndroid Build Coastguard Worker   // kpidDTime
1743*f6dc9357SAndroid Build Coastguard Worker };
1744*f6dc9357SAndroid Build Coastguard Worker 
1745*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kProps[] =
1746*f6dc9357SAndroid Build Coastguard Worker {
1747*f6dc9357SAndroid Build Coastguard Worker   kpidPath,
1748*f6dc9357SAndroid Build Coastguard Worker   kpidIsDir,
1749*f6dc9357SAndroid Build Coastguard Worker   kpidSize,
1750*f6dc9357SAndroid Build Coastguard Worker   kpidPackSize,
1751*f6dc9357SAndroid Build Coastguard Worker   kpidPosixAttrib,
1752*f6dc9357SAndroid Build Coastguard Worker   kpidMTime,
1753*f6dc9357SAndroid Build Coastguard Worker   kpidCTime,
1754*f6dc9357SAndroid Build Coastguard Worker   kpidATime,
1755*f6dc9357SAndroid Build Coastguard Worker   // kpidChangeTime,
1756*f6dc9357SAndroid Build Coastguard Worker   // kpidDTime,
1757*f6dc9357SAndroid Build Coastguard Worker   kpidINode,
1758*f6dc9357SAndroid Build Coastguard Worker   kpidLinks,
1759*f6dc9357SAndroid Build Coastguard Worker   kpidSymLink,
1760*f6dc9357SAndroid Build Coastguard Worker   kpidCharacts,
1761*f6dc9357SAndroid Build Coastguard Worker   kpidUserId,
1762*f6dc9357SAndroid Build Coastguard Worker   kpidGroupId
1763*f6dc9357SAndroid Build Coastguard Worker };
1764*f6dc9357SAndroid Build Coastguard Worker 
1765*f6dc9357SAndroid Build Coastguard Worker 
1766*f6dc9357SAndroid Build Coastguard Worker static const CStatProp kArcProps[] =
1767*f6dc9357SAndroid Build Coastguard Worker {
1768*f6dc9357SAndroid Build Coastguard Worker   { NULL, kpidHeadersSize, VT_BSTR },
1769*f6dc9357SAndroid Build Coastguard Worker   // { NULL, kpidFileSystem, VT_BSTR },
1770*f6dc9357SAndroid Build Coastguard Worker   // kpidMethod,
1771*f6dc9357SAndroid Build Coastguard Worker   { NULL, kpidClusterSize, VT_UI4 },
1772*f6dc9357SAndroid Build Coastguard Worker   // { "Group Size", kpidGroupSize, VT_UI8 },
1773*f6dc9357SAndroid Build Coastguard Worker   { NULL, kpidFreeSpace, VT_UI8 },
1774*f6dc9357SAndroid Build Coastguard Worker 
1775*f6dc9357SAndroid Build Coastguard Worker   { NULL, kpidMTime, VT_FILETIME },
1776*f6dc9357SAndroid Build Coastguard Worker   { NULL, kpidCTime, VT_FILETIME },
1777*f6dc9357SAndroid Build Coastguard Worker   { "Mount Time", kpidMountTime, VT_FILETIME },
1778*f6dc9357SAndroid Build Coastguard Worker   { "Last Check Time", kpidLastCheckTime, VT_FILETIME },
1779*f6dc9357SAndroid Build Coastguard Worker 
1780*f6dc9357SAndroid Build Coastguard Worker   { NULL, kpidHostOS, VT_BSTR},
1781*f6dc9357SAndroid Build Coastguard Worker   { "Revision", kpidRevision, VT_UI4},
1782*f6dc9357SAndroid Build Coastguard Worker   { "inode Size", kpidINodeSize, VT_UI4},
1783*f6dc9357SAndroid Build Coastguard Worker   { NULL, kpidCodePage, VT_BSTR},
1784*f6dc9357SAndroid Build Coastguard Worker   { NULL, kpidVolumeName, VT_BSTR},
1785*f6dc9357SAndroid Build Coastguard Worker   { "Last Mounted", kpidLastMount, VT_BSTR},
1786*f6dc9357SAndroid Build Coastguard Worker   { NULL, kpidId, VT_BSTR},
1787*f6dc9357SAndroid Build Coastguard Worker   { NULL, kpidCharacts, VT_BSTR },
1788*f6dc9357SAndroid Build Coastguard Worker   { "Incompatible Features", kpidFeatureIncompat, VT_BSTR },
1789*f6dc9357SAndroid Build Coastguard Worker   { "Readonly-compatible Features", kpidFeatureRoCompat, VT_BSTR },
1790*f6dc9357SAndroid Build Coastguard Worker   { "Written KiB", kpidWrittenKB, VT_UI8 }
1791*f6dc9357SAndroid Build Coastguard Worker };
1792*f6dc9357SAndroid Build Coastguard Worker 
1793*f6dc9357SAndroid Build Coastguard Worker IMP_IInArchive_Props
1794*f6dc9357SAndroid Build Coastguard Worker IMP_IInArchive_ArcProps_WITH_NAME
1795*f6dc9357SAndroid Build Coastguard Worker 
StringToProp(bool isUTF,const char * s,unsigned size,NCOM::CPropVariant & prop)1796*f6dc9357SAndroid Build Coastguard Worker static void StringToProp(bool isUTF, const char *s, unsigned size, NCOM::CPropVariant &prop)
1797*f6dc9357SAndroid Build Coastguard Worker {
1798*f6dc9357SAndroid Build Coastguard Worker   UString u;
1799*f6dc9357SAndroid Build Coastguard Worker   AString a;
1800*f6dc9357SAndroid Build Coastguard Worker   a.SetFrom_CalcLen(s, size);
1801*f6dc9357SAndroid Build Coastguard Worker   if (!isUTF || !ConvertUTF8ToUnicode(a, u))
1802*f6dc9357SAndroid Build Coastguard Worker     MultiByteToUnicodeString2(u, a);
1803*f6dc9357SAndroid Build Coastguard Worker   prop = u;
1804*f6dc9357SAndroid Build Coastguard Worker }
1805*f6dc9357SAndroid Build Coastguard Worker 
UnixTimeToProp(UInt32 val,NCOM::CPropVariant & prop)1806*f6dc9357SAndroid Build Coastguard Worker static void UnixTimeToProp(UInt32 val, NCOM::CPropVariant &prop)
1807*f6dc9357SAndroid Build Coastguard Worker {
1808*f6dc9357SAndroid Build Coastguard Worker   if (val != 0)
1809*f6dc9357SAndroid Build Coastguard Worker     PropVariant_SetFrom_UnixTime(prop, val);
1810*f6dc9357SAndroid Build Coastguard Worker }
1811*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::GetArchiveProperty (PROPID propID,PROPVARIANT * value))1812*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
1813*f6dc9357SAndroid Build Coastguard Worker {
1814*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
1815*f6dc9357SAndroid Build Coastguard Worker 
1816*f6dc9357SAndroid Build Coastguard Worker   NCOM::CPropVariant prop;
1817*f6dc9357SAndroid Build Coastguard Worker 
1818*f6dc9357SAndroid Build Coastguard Worker   switch (propID)
1819*f6dc9357SAndroid Build Coastguard Worker   {
1820*f6dc9357SAndroid Build Coastguard Worker     /*
1821*f6dc9357SAndroid Build Coastguard Worker     case kpidFileSystem:
1822*f6dc9357SAndroid Build Coastguard Worker     {
1823*f6dc9357SAndroid Build Coastguard Worker       AString res = "Ext4";
1824*f6dc9357SAndroid Build Coastguard Worker       prop = res;
1825*f6dc9357SAndroid Build Coastguard Worker       break;
1826*f6dc9357SAndroid Build Coastguard Worker     }
1827*f6dc9357SAndroid Build Coastguard Worker     */
1828*f6dc9357SAndroid Build Coastguard Worker 
1829*f6dc9357SAndroid Build Coastguard Worker     case kpidIsTree: prop = true; break;
1830*f6dc9357SAndroid Build Coastguard Worker     case kpidIsAux: prop = true; break;
1831*f6dc9357SAndroid Build Coastguard Worker     case kpidINode: prop = true; break;
1832*f6dc9357SAndroid Build Coastguard Worker 
1833*f6dc9357SAndroid Build Coastguard Worker     case kpidClusterSize: prop = (UInt32)1 << _h.BlockBits; break;
1834*f6dc9357SAndroid Build Coastguard Worker     // case kpidGroupSize: prop = (UInt64)_h.BlocksPerGroup << _h.BlockBits; break;
1835*f6dc9357SAndroid Build Coastguard Worker 
1836*f6dc9357SAndroid Build Coastguard Worker     case kpidFreeSpace: prop = (UInt64)_h.NumFreeBlocks << _h.BlockBits; break;
1837*f6dc9357SAndroid Build Coastguard Worker 
1838*f6dc9357SAndroid Build Coastguard Worker     case kpidCTime: UnixTimeToProp(_h.CTime, prop); break;
1839*f6dc9357SAndroid Build Coastguard Worker     case kpidMTime: UnixTimeToProp(_h.WriteTime, prop); break;
1840*f6dc9357SAndroid Build Coastguard Worker     case kpidMountTime: UnixTimeToProp(_h.MountTime, prop); break;
1841*f6dc9357SAndroid Build Coastguard Worker     case kpidLastCheckTime: UnixTimeToProp(_h.LastCheckTime, prop); break;
1842*f6dc9357SAndroid Build Coastguard Worker 
1843*f6dc9357SAndroid Build Coastguard Worker     case kpidHostOS:
1844*f6dc9357SAndroid Build Coastguard Worker     {
1845*f6dc9357SAndroid Build Coastguard Worker       TYPE_TO_PROP(kHostOS, _h.CreatorOs, prop);
1846*f6dc9357SAndroid Build Coastguard Worker       break;
1847*f6dc9357SAndroid Build Coastguard Worker     }
1848*f6dc9357SAndroid Build Coastguard Worker 
1849*f6dc9357SAndroid Build Coastguard Worker     case kpidRevision: prop = _h.RevLevel; break;
1850*f6dc9357SAndroid Build Coastguard Worker 
1851*f6dc9357SAndroid Build Coastguard Worker     case kpidINodeSize: prop = (UInt32)_h.InodeSize; break;
1852*f6dc9357SAndroid Build Coastguard Worker 
1853*f6dc9357SAndroid Build Coastguard Worker     case kpidId:
1854*f6dc9357SAndroid Build Coastguard Worker     {
1855*f6dc9357SAndroid Build Coastguard Worker       if (!IsEmptyData(_h.Uuid, sizeof(_h.Uuid)))
1856*f6dc9357SAndroid Build Coastguard Worker       {
1857*f6dc9357SAndroid Build Coastguard Worker         char s[sizeof(_h.Uuid) * 2 + 2];
1858*f6dc9357SAndroid Build Coastguard Worker         ConvertDataToHex_Lower(s, _h.Uuid, sizeof(_h.Uuid));
1859*f6dc9357SAndroid Build Coastguard Worker         prop = s;
1860*f6dc9357SAndroid Build Coastguard Worker       }
1861*f6dc9357SAndroid Build Coastguard Worker       break;
1862*f6dc9357SAndroid Build Coastguard Worker     }
1863*f6dc9357SAndroid Build Coastguard Worker 
1864*f6dc9357SAndroid Build Coastguard Worker     case kpidCodePage: if (_isUTF) prop = "UTF-8"; break;
1865*f6dc9357SAndroid Build Coastguard Worker 
1866*f6dc9357SAndroid Build Coastguard Worker     case kpidShortComment:
1867*f6dc9357SAndroid Build Coastguard Worker     case kpidVolumeName:
1868*f6dc9357SAndroid Build Coastguard Worker         StringToProp(_isUTF, _h.VolName, sizeof(_h.VolName), prop); break;
1869*f6dc9357SAndroid Build Coastguard Worker 
1870*f6dc9357SAndroid Build Coastguard Worker     case kpidLastMount: StringToProp(_isUTF, _h.LastMount, sizeof(_h.LastMount), prop); break;
1871*f6dc9357SAndroid Build Coastguard Worker 
1872*f6dc9357SAndroid Build Coastguard Worker     case kpidCharacts: FLAGS_TO_PROP(g_FeatureCompat_Flags, _h.FeatureCompat, prop); break;
1873*f6dc9357SAndroid Build Coastguard Worker     case kpidFeatureIncompat: FLAGS_TO_PROP(g_FeatureIncompat_Flags, _h.FeatureIncompat, prop); break;
1874*f6dc9357SAndroid Build Coastguard Worker     case kpidFeatureRoCompat: FLAGS_TO_PROP(g_FeatureRoCompat_Flags, _h.FeatureRoCompat, prop); break;
1875*f6dc9357SAndroid Build Coastguard Worker     case kpidWrittenKB: if (_h.WrittenKB != 0) prop = _h.WrittenKB; break;
1876*f6dc9357SAndroid Build Coastguard Worker 
1877*f6dc9357SAndroid Build Coastguard Worker     case kpidPhySize: prop = _phySize; break;
1878*f6dc9357SAndroid Build Coastguard Worker 
1879*f6dc9357SAndroid Build Coastguard Worker     case kpidErrorFlags:
1880*f6dc9357SAndroid Build Coastguard Worker     {
1881*f6dc9357SAndroid Build Coastguard Worker       UInt32 v = 0;
1882*f6dc9357SAndroid Build Coastguard Worker       if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;
1883*f6dc9357SAndroid Build Coastguard Worker       if (_linksError) v |= kpv_ErrorFlags_HeadersError;
1884*f6dc9357SAndroid Build Coastguard Worker       if (_headersError) v |= kpv_ErrorFlags_HeadersError;
1885*f6dc9357SAndroid Build Coastguard Worker       if (!_stream && v == 0 && _isArc)
1886*f6dc9357SAndroid Build Coastguard Worker         v = kpv_ErrorFlags_HeadersError;
1887*f6dc9357SAndroid Build Coastguard Worker       if (v != 0)
1888*f6dc9357SAndroid Build Coastguard Worker         prop = v;
1889*f6dc9357SAndroid Build Coastguard Worker       break;
1890*f6dc9357SAndroid Build Coastguard Worker     }
1891*f6dc9357SAndroid Build Coastguard Worker 
1892*f6dc9357SAndroid Build Coastguard Worker     case kpidWarningFlags:
1893*f6dc9357SAndroid Build Coastguard Worker     {
1894*f6dc9357SAndroid Build Coastguard Worker       UInt32 v = 0;
1895*f6dc9357SAndroid Build Coastguard Worker       if (_headersWarning) v |= kpv_ErrorFlags_HeadersError;
1896*f6dc9357SAndroid Build Coastguard Worker       if (v != 0)
1897*f6dc9357SAndroid Build Coastguard Worker         prop = v;
1898*f6dc9357SAndroid Build Coastguard Worker       break;
1899*f6dc9357SAndroid Build Coastguard Worker     }
1900*f6dc9357SAndroid Build Coastguard Worker   }
1901*f6dc9357SAndroid Build Coastguard Worker 
1902*f6dc9357SAndroid Build Coastguard Worker   prop.Detach(value);
1903*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1904*f6dc9357SAndroid Build Coastguard Worker 
1905*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
1906*f6dc9357SAndroid Build Coastguard Worker }
1907*f6dc9357SAndroid Build Coastguard Worker 
1908*f6dc9357SAndroid Build Coastguard Worker 
1909*f6dc9357SAndroid Build Coastguard Worker /*
1910*f6dc9357SAndroid Build Coastguard Worker static const Byte kRawProps[] =
1911*f6dc9357SAndroid Build Coastguard Worker {
1912*f6dc9357SAndroid Build Coastguard Worker   // kpidSha1,
1913*f6dc9357SAndroid Build Coastguard Worker };
1914*f6dc9357SAndroid Build Coastguard Worker */
1915*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::GetNumRawProps (UInt32 * numProps))1916*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetNumRawProps(UInt32 *numProps))
1917*f6dc9357SAndroid Build Coastguard Worker {
1918*f6dc9357SAndroid Build Coastguard Worker   // *numProps = Z7_ARRAY_SIZE(kRawProps);
1919*f6dc9357SAndroid Build Coastguard Worker   *numProps = 0;
1920*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1921*f6dc9357SAndroid Build Coastguard Worker }
1922*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::GetRawPropInfo (UInt32,BSTR * name,PROPID * propID))1923*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID))
1924*f6dc9357SAndroid Build Coastguard Worker {
1925*f6dc9357SAndroid Build Coastguard Worker   // *propID = kRawProps[index];
1926*f6dc9357SAndroid Build Coastguard Worker   *propID = 0;
1927*f6dc9357SAndroid Build Coastguard Worker   *name = NULL;
1928*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1929*f6dc9357SAndroid Build Coastguard Worker }
1930*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::GetParent (UInt32 index,UInt32 * parent,UInt32 * parentType))1931*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetParent(UInt32 index, UInt32 *parent, UInt32 *parentType))
1932*f6dc9357SAndroid Build Coastguard Worker {
1933*f6dc9357SAndroid Build Coastguard Worker   *parentType = NParentType::kDir;
1934*f6dc9357SAndroid Build Coastguard Worker   *parent = (UInt32)(Int32)-1;
1935*f6dc9357SAndroid Build Coastguard Worker 
1936*f6dc9357SAndroid Build Coastguard Worker   if (index >= _items.Size())
1937*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
1938*f6dc9357SAndroid Build Coastguard Worker 
1939*f6dc9357SAndroid Build Coastguard Worker   const CItem &item = _items[index];
1940*f6dc9357SAndroid Build Coastguard Worker 
1941*f6dc9357SAndroid Build Coastguard Worker   if (item.ParentNode < 0)
1942*f6dc9357SAndroid Build Coastguard Worker   {
1943*f6dc9357SAndroid Build Coastguard Worker     const int aux = GetParentAux(item);
1944*f6dc9357SAndroid Build Coastguard Worker     if (aux >= 0)
1945*f6dc9357SAndroid Build Coastguard Worker       *parent = _items.Size() + (unsigned)aux;
1946*f6dc9357SAndroid Build Coastguard Worker   }
1947*f6dc9357SAndroid Build Coastguard Worker   else
1948*f6dc9357SAndroid Build Coastguard Worker   {
1949*f6dc9357SAndroid Build Coastguard Worker     const int itemIndex = _nodes[_refs[item.ParentNode]].ItemIndex;
1950*f6dc9357SAndroid Build Coastguard Worker     if (itemIndex >= 0)
1951*f6dc9357SAndroid Build Coastguard Worker       *parent = (unsigned)itemIndex;
1952*f6dc9357SAndroid Build Coastguard Worker   }
1953*f6dc9357SAndroid Build Coastguard Worker 
1954*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1955*f6dc9357SAndroid Build Coastguard Worker }
1956*f6dc9357SAndroid Build Coastguard Worker 
1957*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::GetRawProp (UInt32 index,PROPID propID,const void ** data,UInt32 * dataSize,UInt32 * propType))1958*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType))
1959*f6dc9357SAndroid Build Coastguard Worker {
1960*f6dc9357SAndroid Build Coastguard Worker   *data = NULL;
1961*f6dc9357SAndroid Build Coastguard Worker   *dataSize = 0;
1962*f6dc9357SAndroid Build Coastguard Worker   *propType = 0;
1963*f6dc9357SAndroid Build Coastguard Worker 
1964*f6dc9357SAndroid Build Coastguard Worker   if (propID == kpidName && _isUTF)
1965*f6dc9357SAndroid Build Coastguard Worker   {
1966*f6dc9357SAndroid Build Coastguard Worker     if (index < _items.Size())
1967*f6dc9357SAndroid Build Coastguard Worker     {
1968*f6dc9357SAndroid Build Coastguard Worker       const AString &s = _items[index].Name;
1969*f6dc9357SAndroid Build Coastguard Worker       if (!s.IsEmpty())
1970*f6dc9357SAndroid Build Coastguard Worker       {
1971*f6dc9357SAndroid Build Coastguard Worker         *data = (void *)(const char *)s;
1972*f6dc9357SAndroid Build Coastguard Worker         *dataSize = (UInt32)s.Len() + 1;
1973*f6dc9357SAndroid Build Coastguard Worker         *propType = NPropDataType::kUtf8z;
1974*f6dc9357SAndroid Build Coastguard Worker       }
1975*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
1976*f6dc9357SAndroid Build Coastguard Worker     }
1977*f6dc9357SAndroid Build Coastguard Worker     else
1978*f6dc9357SAndroid Build Coastguard Worker     {
1979*f6dc9357SAndroid Build Coastguard Worker       const AString &s = _auxItems[index - _items.Size()];
1980*f6dc9357SAndroid Build Coastguard Worker       {
1981*f6dc9357SAndroid Build Coastguard Worker         *data = (void *)(const char *)s;
1982*f6dc9357SAndroid Build Coastguard Worker         *dataSize = (UInt32)s.Len() + 1;
1983*f6dc9357SAndroid Build Coastguard Worker         *propType = NPropDataType::kUtf8z;
1984*f6dc9357SAndroid Build Coastguard Worker       }
1985*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
1986*f6dc9357SAndroid Build Coastguard Worker     }
1987*f6dc9357SAndroid Build Coastguard Worker   }
1988*f6dc9357SAndroid Build Coastguard Worker 
1989*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1990*f6dc9357SAndroid Build Coastguard Worker }
1991*f6dc9357SAndroid Build Coastguard Worker 
1992*f6dc9357SAndroid Build Coastguard Worker 
ExtTimeToProp(const CExtTime & t,NCOM::CPropVariant & prop)1993*f6dc9357SAndroid Build Coastguard Worker static void ExtTimeToProp(const CExtTime &t, NCOM::CPropVariant &prop)
1994*f6dc9357SAndroid Build Coastguard Worker {
1995*f6dc9357SAndroid Build Coastguard Worker   if (t.Val == 0 && t.Extra == 0)
1996*f6dc9357SAndroid Build Coastguard Worker     return;
1997*f6dc9357SAndroid Build Coastguard Worker 
1998*f6dc9357SAndroid Build Coastguard Worker   FILETIME ft;
1999*f6dc9357SAndroid Build Coastguard Worker   unsigned low100ns = 0;
2000*f6dc9357SAndroid Build Coastguard Worker   // if (t.Extra != 0)
2001*f6dc9357SAndroid Build Coastguard Worker   {
2002*f6dc9357SAndroid Build Coastguard Worker     // 1901-2446 :
2003*f6dc9357SAndroid Build Coastguard Worker     Int64 v = (Int64)(Int32)t.Val;
2004*f6dc9357SAndroid Build Coastguard Worker     v += (UInt64)(t.Extra & 3) << 32;  // 2 low bits are offset for main timestamp
2005*f6dc9357SAndroid Build Coastguard Worker     UInt64 ft64 = NTime::UnixTime64_To_FileTime64(v);
2006*f6dc9357SAndroid Build Coastguard Worker     const UInt32 ns = (t.Extra >> 2);
2007*f6dc9357SAndroid Build Coastguard Worker     if (ns < 1000000000)
2008*f6dc9357SAndroid Build Coastguard Worker     {
2009*f6dc9357SAndroid Build Coastguard Worker       ft64 += ns / 100;
2010*f6dc9357SAndroid Build Coastguard Worker       low100ns = (unsigned)(ns % 100);
2011*f6dc9357SAndroid Build Coastguard Worker     }
2012*f6dc9357SAndroid Build Coastguard Worker     ft.dwLowDateTime = (DWORD)ft64;
2013*f6dc9357SAndroid Build Coastguard Worker     ft.dwHighDateTime = (DWORD)(ft64 >> 32);
2014*f6dc9357SAndroid Build Coastguard Worker   }
2015*f6dc9357SAndroid Build Coastguard Worker   /*
2016*f6dc9357SAndroid Build Coastguard Worker   else
2017*f6dc9357SAndroid Build Coastguard Worker   {
2018*f6dc9357SAndroid Build Coastguard Worker     // 1901-2038 : that code is good for ext4 and compatibility with Extra
2019*f6dc9357SAndroid Build Coastguard Worker     NTime::UnixTime64ToFileTime((Int32)t.Val, ft); // for
2020*f6dc9357SAndroid Build Coastguard Worker 
2021*f6dc9357SAndroid Build Coastguard Worker     // 1970-2106 : that code is good if timestamp is used as unsigned 32-bit
2022*f6dc9357SAndroid Build Coastguard Worker     // are there such systems?
2023*f6dc9357SAndroid Build Coastguard Worker     // NTime::UnixTimeToFileTime(t.Val, ft); // for
2024*f6dc9357SAndroid Build Coastguard Worker   }
2025*f6dc9357SAndroid Build Coastguard Worker   */
2026*f6dc9357SAndroid Build Coastguard Worker   prop.SetAsTimeFrom_FT_Prec_Ns100(ft, k_PropVar_TimePrec_1ns, low100ns);
2027*f6dc9357SAndroid Build Coastguard Worker }
2028*f6dc9357SAndroid Build Coastguard Worker 
2029*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CHandler::GetProperty (UInt32 index,PROPID propID,PROPVARIANT * value))2030*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
2031*f6dc9357SAndroid Build Coastguard Worker {
2032*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
2033*f6dc9357SAndroid Build Coastguard Worker   NCOM::CPropVariant prop;
2034*f6dc9357SAndroid Build Coastguard Worker 
2035*f6dc9357SAndroid Build Coastguard Worker   if (index >= _items.Size())
2036*f6dc9357SAndroid Build Coastguard Worker   {
2037*f6dc9357SAndroid Build Coastguard Worker     switch (propID)
2038*f6dc9357SAndroid Build Coastguard Worker     {
2039*f6dc9357SAndroid Build Coastguard Worker       case kpidPath:
2040*f6dc9357SAndroid Build Coastguard Worker       case kpidName:
2041*f6dc9357SAndroid Build Coastguard Worker       {
2042*f6dc9357SAndroid Build Coastguard Worker         prop = _auxItems[index - _items.Size()];
2043*f6dc9357SAndroid Build Coastguard Worker         break;
2044*f6dc9357SAndroid Build Coastguard Worker       }
2045*f6dc9357SAndroid Build Coastguard Worker       case kpidIsDir: prop = true; break;
2046*f6dc9357SAndroid Build Coastguard Worker       case kpidIsAux: prop = true; break;
2047*f6dc9357SAndroid Build Coastguard Worker     }
2048*f6dc9357SAndroid Build Coastguard Worker   }
2049*f6dc9357SAndroid Build Coastguard Worker   else
2050*f6dc9357SAndroid Build Coastguard Worker   {
2051*f6dc9357SAndroid Build Coastguard Worker 
2052*f6dc9357SAndroid Build Coastguard Worker   const CItem &item = _items[index];
2053*f6dc9357SAndroid Build Coastguard Worker   const CNode &node = _nodes[_refs[item.Node]];
2054*f6dc9357SAndroid Build Coastguard Worker   bool isDir = node.IsDir();
2055*f6dc9357SAndroid Build Coastguard Worker 
2056*f6dc9357SAndroid Build Coastguard Worker   switch (propID)
2057*f6dc9357SAndroid Build Coastguard Worker   {
2058*f6dc9357SAndroid Build Coastguard Worker     case kpidPath:
2059*f6dc9357SAndroid Build Coastguard Worker     {
2060*f6dc9357SAndroid Build Coastguard Worker       UString u;
2061*f6dc9357SAndroid Build Coastguard Worker       {
2062*f6dc9357SAndroid Build Coastguard Worker         AString s;
2063*f6dc9357SAndroid Build Coastguard Worker         GetPath(index, s);
2064*f6dc9357SAndroid Build Coastguard Worker         if (!_isUTF || !ConvertUTF8ToUnicode(s, u))
2065*f6dc9357SAndroid Build Coastguard Worker           MultiByteToUnicodeString2(u, s);
2066*f6dc9357SAndroid Build Coastguard Worker       }
2067*f6dc9357SAndroid Build Coastguard Worker       prop = u;
2068*f6dc9357SAndroid Build Coastguard Worker       break;
2069*f6dc9357SAndroid Build Coastguard Worker     }
2070*f6dc9357SAndroid Build Coastguard Worker 
2071*f6dc9357SAndroid Build Coastguard Worker     case kpidName:
2072*f6dc9357SAndroid Build Coastguard Worker     {
2073*f6dc9357SAndroid Build Coastguard Worker       {
2074*f6dc9357SAndroid Build Coastguard Worker         UString u;
2075*f6dc9357SAndroid Build Coastguard Worker         {
2076*f6dc9357SAndroid Build Coastguard Worker           if (!_isUTF || !ConvertUTF8ToUnicode(item.Name, u))
2077*f6dc9357SAndroid Build Coastguard Worker             MultiByteToUnicodeString2(u, item.Name);
2078*f6dc9357SAndroid Build Coastguard Worker         }
2079*f6dc9357SAndroid Build Coastguard Worker         prop = u;
2080*f6dc9357SAndroid Build Coastguard Worker       }
2081*f6dc9357SAndroid Build Coastguard Worker       break;
2082*f6dc9357SAndroid Build Coastguard Worker     }
2083*f6dc9357SAndroid Build Coastguard Worker 
2084*f6dc9357SAndroid Build Coastguard Worker     case kpidIsDir:
2085*f6dc9357SAndroid Build Coastguard Worker     {
2086*f6dc9357SAndroid Build Coastguard Worker       bool isDir2 = isDir;
2087*f6dc9357SAndroid Build Coastguard Worker       if (item.SymLinkItemIndex >= 0)
2088*f6dc9357SAndroid Build Coastguard Worker         isDir2 = _nodes[_refs[_items[item.SymLinkItemIndex].Node]].IsDir();
2089*f6dc9357SAndroid Build Coastguard Worker       prop = isDir2;
2090*f6dc9357SAndroid Build Coastguard Worker       break;
2091*f6dc9357SAndroid Build Coastguard Worker     }
2092*f6dc9357SAndroid Build Coastguard Worker 
2093*f6dc9357SAndroid Build Coastguard Worker     case kpidSize: if (!isDir) prop = node.FileSize; break;
2094*f6dc9357SAndroid Build Coastguard Worker 
2095*f6dc9357SAndroid Build Coastguard Worker     case kpidPackSize:
2096*f6dc9357SAndroid Build Coastguard Worker       if (!isDir)
2097*f6dc9357SAndroid Build Coastguard Worker       {
2098*f6dc9357SAndroid Build Coastguard Worker         UInt64 size;
2099*f6dc9357SAndroid Build Coastguard Worker         if (GetPackSize(index, size))
2100*f6dc9357SAndroid Build Coastguard Worker           prop = size;
2101*f6dc9357SAndroid Build Coastguard Worker       }
2102*f6dc9357SAndroid Build Coastguard Worker       break;
2103*f6dc9357SAndroid Build Coastguard Worker 
2104*f6dc9357SAndroid Build Coastguard Worker     case kpidPosixAttrib:
2105*f6dc9357SAndroid Build Coastguard Worker     {
2106*f6dc9357SAndroid Build Coastguard Worker       /*
2107*f6dc9357SAndroid Build Coastguard Worker       if (node.Type != 0 && node.Type < Z7_ARRAY_SIZE(k_TypeToMode))
2108*f6dc9357SAndroid Build Coastguard Worker         prop = (UInt32)(node.Mode & 0xFFF) | k_TypeToMode[node.Type];
2109*f6dc9357SAndroid Build Coastguard Worker       */
2110*f6dc9357SAndroid Build Coastguard Worker       prop = (UInt32)(node.Mode);
2111*f6dc9357SAndroid Build Coastguard Worker       break;
2112*f6dc9357SAndroid Build Coastguard Worker     }
2113*f6dc9357SAndroid Build Coastguard Worker 
2114*f6dc9357SAndroid Build Coastguard Worker     case kpidMTime: ExtTimeToProp(node.MTime, prop); break;
2115*f6dc9357SAndroid Build Coastguard Worker     case kpidCTime: ExtTimeToProp(node.CTime, prop); break;
2116*f6dc9357SAndroid Build Coastguard Worker     case kpidATime: ExtTimeToProp(node.ATime, prop); break;
2117*f6dc9357SAndroid Build Coastguard Worker     // case kpidDTime: ExtTimeToProp(node.DTime, prop); break;
2118*f6dc9357SAndroid Build Coastguard Worker     case kpidChangeTime: ExtTimeToProp(node.ChangeTime, prop); break;
2119*f6dc9357SAndroid Build Coastguard Worker     case kpidUserId: prop = (UInt32)node.Uid; break;
2120*f6dc9357SAndroid Build Coastguard Worker     case kpidGroupId: prop = (UInt32)node.Gid; break;
2121*f6dc9357SAndroid Build Coastguard Worker     case kpidLinks: prop = node.NumLinks; break;
2122*f6dc9357SAndroid Build Coastguard Worker     case kpidINode: prop = (UInt32)item.Node; break;
2123*f6dc9357SAndroid Build Coastguard Worker     case kpidStreamId: if (!isDir) prop = (UInt32)item.Node; break;
2124*f6dc9357SAndroid Build Coastguard Worker     case kpidCharacts: FLAGS_TO_PROP(g_NodeFlags, (UInt32)node.Flags, prop); break;
2125*f6dc9357SAndroid Build Coastguard Worker 
2126*f6dc9357SAndroid Build Coastguard Worker     case kpidSymLink:
2127*f6dc9357SAndroid Build Coastguard Worker     {
2128*f6dc9357SAndroid Build Coastguard Worker       if (node.SymLinkIndex >= 0)
2129*f6dc9357SAndroid Build Coastguard Worker       {
2130*f6dc9357SAndroid Build Coastguard Worker         UString u;
2131*f6dc9357SAndroid Build Coastguard Worker         {
2132*f6dc9357SAndroid Build Coastguard Worker           const AString &s = _symLinks[node.SymLinkIndex];
2133*f6dc9357SAndroid Build Coastguard Worker           if (!_isUTF || !ConvertUTF8ToUnicode(s, u))
2134*f6dc9357SAndroid Build Coastguard Worker             MultiByteToUnicodeString2(u, s);
2135*f6dc9357SAndroid Build Coastguard Worker         }
2136*f6dc9357SAndroid Build Coastguard Worker         prop = u;
2137*f6dc9357SAndroid Build Coastguard Worker       }
2138*f6dc9357SAndroid Build Coastguard Worker       break;
2139*f6dc9357SAndroid Build Coastguard Worker     }
2140*f6dc9357SAndroid Build Coastguard Worker   }
2141*f6dc9357SAndroid Build Coastguard Worker 
2142*f6dc9357SAndroid Build Coastguard Worker   }
2143*f6dc9357SAndroid Build Coastguard Worker 
2144*f6dc9357SAndroid Build Coastguard Worker   prop.Detach(value);
2145*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
2146*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
2147*f6dc9357SAndroid Build Coastguard Worker }
2148*f6dc9357SAndroid Build Coastguard Worker 
2149*f6dc9357SAndroid Build Coastguard Worker 
2150*f6dc9357SAndroid Build Coastguard Worker Z7_CLASS_IMP_IInStream(CClusterInStream2
2151*f6dc9357SAndroid Build Coastguard Worker )
2152*f6dc9357SAndroid Build Coastguard Worker   UInt64 _virtPos;
2153*f6dc9357SAndroid Build Coastguard Worker   UInt64 _physPos;
2154*f6dc9357SAndroid Build Coastguard Worker   UInt32 _curRem;
2155*f6dc9357SAndroid Build Coastguard Worker public:
2156*f6dc9357SAndroid Build Coastguard Worker   unsigned BlockBits;
2157*f6dc9357SAndroid Build Coastguard Worker   UInt64 Size;
2158*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<IInStream> Stream;
2159*f6dc9357SAndroid Build Coastguard Worker   CRecordVector<UInt32> Vector;
2160*f6dc9357SAndroid Build Coastguard Worker 
2161*f6dc9357SAndroid Build Coastguard Worker   HRESULT SeekToPhys() { return InStream_SeekSet(Stream, _physPos); }
2162*f6dc9357SAndroid Build Coastguard Worker 
2163*f6dc9357SAndroid Build Coastguard Worker   HRESULT InitAndSeek()
2164*f6dc9357SAndroid Build Coastguard Worker   {
2165*f6dc9357SAndroid Build Coastguard Worker     _curRem = 0;
2166*f6dc9357SAndroid Build Coastguard Worker     _virtPos = 0;
2167*f6dc9357SAndroid Build Coastguard Worker     _physPos = 0;
2168*f6dc9357SAndroid Build Coastguard Worker     if (Vector.Size() > 0)
2169*f6dc9357SAndroid Build Coastguard Worker     {
2170*f6dc9357SAndroid Build Coastguard Worker       _physPos = (Vector[0] << BlockBits);
2171*f6dc9357SAndroid Build Coastguard Worker       return SeekToPhys();
2172*f6dc9357SAndroid Build Coastguard Worker     }
2173*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
2174*f6dc9357SAndroid Build Coastguard Worker   }
2175*f6dc9357SAndroid Build Coastguard Worker };
2176*f6dc9357SAndroid Build Coastguard Worker 
2177*f6dc9357SAndroid Build Coastguard Worker 
2178*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CClusterInStream2::Read(void *data, UInt32 size, UInt32 *processedSize))
2179*f6dc9357SAndroid Build Coastguard Worker {
2180*f6dc9357SAndroid Build Coastguard Worker   if (processedSize)
2181*f6dc9357SAndroid Build Coastguard Worker     *processedSize = 0;
2182*f6dc9357SAndroid Build Coastguard Worker   if (_virtPos >= Size)
2183*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
2184*f6dc9357SAndroid Build Coastguard Worker   {
2185*f6dc9357SAndroid Build Coastguard Worker     UInt64 rem = Size - _virtPos;
2186*f6dc9357SAndroid Build Coastguard Worker     if (size > rem)
2187*f6dc9357SAndroid Build Coastguard Worker       size = (UInt32)rem;
2188*f6dc9357SAndroid Build Coastguard Worker   }
2189*f6dc9357SAndroid Build Coastguard Worker   if (size == 0)
2190*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
2191*f6dc9357SAndroid Build Coastguard Worker 
2192*f6dc9357SAndroid Build Coastguard Worker   if (_curRem == 0)
2193*f6dc9357SAndroid Build Coastguard Worker   {
2194*f6dc9357SAndroid Build Coastguard Worker     const UInt32 blockSize = (UInt32)1 << BlockBits;
2195*f6dc9357SAndroid Build Coastguard Worker     const UInt32 virtBlock = (UInt32)(_virtPos >> BlockBits);
2196*f6dc9357SAndroid Build Coastguard Worker     const UInt32 offsetInBlock = (UInt32)_virtPos & (blockSize - 1);
2197*f6dc9357SAndroid Build Coastguard Worker     const UInt32 phyBlock = Vector[virtBlock];
2198*f6dc9357SAndroid Build Coastguard Worker 
2199*f6dc9357SAndroid Build Coastguard Worker     if (phyBlock == 0)
2200*f6dc9357SAndroid Build Coastguard Worker     {
2201*f6dc9357SAndroid Build Coastguard Worker       UInt32 cur = blockSize - offsetInBlock;
2202*f6dc9357SAndroid Build Coastguard Worker       if (cur > size)
2203*f6dc9357SAndroid Build Coastguard Worker         cur = size;
2204*f6dc9357SAndroid Build Coastguard Worker       memset(data, 0, cur);
2205*f6dc9357SAndroid Build Coastguard Worker       _virtPos += cur;
2206*f6dc9357SAndroid Build Coastguard Worker       if (processedSize)
2207*f6dc9357SAndroid Build Coastguard Worker         *processedSize = cur;
2208*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
2209*f6dc9357SAndroid Build Coastguard Worker     }
2210*f6dc9357SAndroid Build Coastguard Worker 
2211*f6dc9357SAndroid Build Coastguard Worker     UInt64 newPos = ((UInt64)phyBlock << BlockBits) + offsetInBlock;
2212*f6dc9357SAndroid Build Coastguard Worker     if (newPos != _physPos)
2213*f6dc9357SAndroid Build Coastguard Worker     {
2214*f6dc9357SAndroid Build Coastguard Worker       _physPos = newPos;
2215*f6dc9357SAndroid Build Coastguard Worker       RINOK(SeekToPhys())
2216*f6dc9357SAndroid Build Coastguard Worker     }
2217*f6dc9357SAndroid Build Coastguard Worker 
2218*f6dc9357SAndroid Build Coastguard Worker     _curRem = blockSize - offsetInBlock;
2219*f6dc9357SAndroid Build Coastguard Worker 
2220*f6dc9357SAndroid Build Coastguard Worker     for (unsigned i = 1; i < 64 && (virtBlock + i) < (UInt32)Vector.Size() && phyBlock + i == Vector[virtBlock + i]; i++)
2221*f6dc9357SAndroid Build Coastguard Worker       _curRem += (UInt32)1 << BlockBits;
2222*f6dc9357SAndroid Build Coastguard Worker   }
2223*f6dc9357SAndroid Build Coastguard Worker 
2224*f6dc9357SAndroid Build Coastguard Worker   if (size > _curRem)
2225*f6dc9357SAndroid Build Coastguard Worker     size = _curRem;
2226*f6dc9357SAndroid Build Coastguard Worker   HRESULT res = Stream->Read(data, size, &size);
2227*f6dc9357SAndroid Build Coastguard Worker   if (processedSize)
2228*f6dc9357SAndroid Build Coastguard Worker     *processedSize = size;
2229*f6dc9357SAndroid Build Coastguard Worker   _physPos += size;
2230*f6dc9357SAndroid Build Coastguard Worker   _virtPos += size;
2231*f6dc9357SAndroid Build Coastguard Worker   _curRem -= size;
2232*f6dc9357SAndroid Build Coastguard Worker   return res;
2233*f6dc9357SAndroid Build Coastguard Worker }
2234*f6dc9357SAndroid Build Coastguard Worker 
2235*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CClusterInStream2::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
2236*f6dc9357SAndroid Build Coastguard Worker {
2237*f6dc9357SAndroid Build Coastguard Worker   switch (seekOrigin)
2238*f6dc9357SAndroid Build Coastguard Worker   {
2239*f6dc9357SAndroid Build Coastguard Worker     case STREAM_SEEK_SET: break;
2240*f6dc9357SAndroid Build Coastguard Worker     case STREAM_SEEK_CUR: offset += _virtPos; break;
2241*f6dc9357SAndroid Build Coastguard Worker     case STREAM_SEEK_END: offset += Size; break;
2242*f6dc9357SAndroid Build Coastguard Worker     default: return STG_E_INVALIDFUNCTION;
2243*f6dc9357SAndroid Build Coastguard Worker   }
2244*f6dc9357SAndroid Build Coastguard Worker   if (offset < 0)
2245*f6dc9357SAndroid Build Coastguard Worker     return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
2246*f6dc9357SAndroid Build Coastguard Worker   if (_virtPos != (UInt64)offset)
2247*f6dc9357SAndroid Build Coastguard Worker     _curRem = 0;
2248*f6dc9357SAndroid Build Coastguard Worker   _virtPos = (UInt64)offset;
2249*f6dc9357SAndroid Build Coastguard Worker   if (newPosition)
2250*f6dc9357SAndroid Build Coastguard Worker     *newPosition = (UInt64)offset;
2251*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
2252*f6dc9357SAndroid Build Coastguard Worker }
2253*f6dc9357SAndroid Build Coastguard Worker 
2254*f6dc9357SAndroid Build Coastguard Worker 
2255*f6dc9357SAndroid Build Coastguard Worker Z7_CLASS_IMP_IInStream(
2256*f6dc9357SAndroid Build Coastguard Worker   CExtInStream
2257*f6dc9357SAndroid Build Coastguard Worker )
2258*f6dc9357SAndroid Build Coastguard Worker   UInt64 _virtPos;
2259*f6dc9357SAndroid Build Coastguard Worker   UInt64 _phyPos;
2260*f6dc9357SAndroid Build Coastguard Worker public:
2261*f6dc9357SAndroid Build Coastguard Worker   unsigned BlockBits;
2262*f6dc9357SAndroid Build Coastguard Worker   UInt64 Size;
2263*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<IInStream> Stream;
2264*f6dc9357SAndroid Build Coastguard Worker   CRecordVector<CExtent> Extents;
2265*f6dc9357SAndroid Build Coastguard Worker 
2266*f6dc9357SAndroid Build Coastguard Worker   HRESULT StartSeek()
2267*f6dc9357SAndroid Build Coastguard Worker   {
2268*f6dc9357SAndroid Build Coastguard Worker     _virtPos = 0;
2269*f6dc9357SAndroid Build Coastguard Worker     _phyPos = 0;
2270*f6dc9357SAndroid Build Coastguard Worker     return InStream_SeekSet(Stream, _phyPos);
2271*f6dc9357SAndroid Build Coastguard Worker   }
2272*f6dc9357SAndroid Build Coastguard Worker };
2273*f6dc9357SAndroid Build Coastguard Worker 
2274*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CExtInStream::Read(void *data, UInt32 size, UInt32 *processedSize))
2275*f6dc9357SAndroid Build Coastguard Worker {
2276*f6dc9357SAndroid Build Coastguard Worker   if (processedSize)
2277*f6dc9357SAndroid Build Coastguard Worker     *processedSize = 0;
2278*f6dc9357SAndroid Build Coastguard Worker   if (_virtPos >= Size)
2279*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
2280*f6dc9357SAndroid Build Coastguard Worker   {
2281*f6dc9357SAndroid Build Coastguard Worker     UInt64 rem = Size - _virtPos;
2282*f6dc9357SAndroid Build Coastguard Worker     if (size > rem)
2283*f6dc9357SAndroid Build Coastguard Worker       size = (UInt32)rem;
2284*f6dc9357SAndroid Build Coastguard Worker   }
2285*f6dc9357SAndroid Build Coastguard Worker   if (size == 0)
2286*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
2287*f6dc9357SAndroid Build Coastguard Worker 
2288*f6dc9357SAndroid Build Coastguard Worker   UInt32 blockIndex = (UInt32)(_virtPos >> BlockBits);
2289*f6dc9357SAndroid Build Coastguard Worker 
2290*f6dc9357SAndroid Build Coastguard Worker   unsigned left = 0, right = Extents.Size();
2291*f6dc9357SAndroid Build Coastguard Worker   for (;;)
2292*f6dc9357SAndroid Build Coastguard Worker   {
2293*f6dc9357SAndroid Build Coastguard Worker     unsigned mid = (left + right) / 2;
2294*f6dc9357SAndroid Build Coastguard Worker     if (mid == left)
2295*f6dc9357SAndroid Build Coastguard Worker       break;
2296*f6dc9357SAndroid Build Coastguard Worker     if (blockIndex < Extents[mid].VirtBlock)
2297*f6dc9357SAndroid Build Coastguard Worker       right = mid;
2298*f6dc9357SAndroid Build Coastguard Worker     else
2299*f6dc9357SAndroid Build Coastguard Worker       left = mid;
2300*f6dc9357SAndroid Build Coastguard Worker   }
2301*f6dc9357SAndroid Build Coastguard Worker 
2302*f6dc9357SAndroid Build Coastguard Worker   {
2303*f6dc9357SAndroid Build Coastguard Worker     const CExtent &extent = Extents[left];
2304*f6dc9357SAndroid Build Coastguard Worker     if (blockIndex < extent.VirtBlock)
2305*f6dc9357SAndroid Build Coastguard Worker       return E_FAIL;
2306*f6dc9357SAndroid Build Coastguard Worker     UInt32 bo = blockIndex - extent.VirtBlock;
2307*f6dc9357SAndroid Build Coastguard Worker     if (bo >= extent.Len)
2308*f6dc9357SAndroid Build Coastguard Worker       return E_FAIL;
2309*f6dc9357SAndroid Build Coastguard Worker 
2310*f6dc9357SAndroid Build Coastguard Worker     UInt32 offset = ((UInt32)_virtPos & (((UInt32)1 << BlockBits) - 1));
2311*f6dc9357SAndroid Build Coastguard Worker     UInt32 remBlocks = extent.Len - bo;
2312*f6dc9357SAndroid Build Coastguard Worker     UInt64 remBytes = ((UInt64)remBlocks << BlockBits);
2313*f6dc9357SAndroid Build Coastguard Worker     remBytes -= offset;
2314*f6dc9357SAndroid Build Coastguard Worker 
2315*f6dc9357SAndroid Build Coastguard Worker     if (size > remBytes)
2316*f6dc9357SAndroid Build Coastguard Worker       size = (UInt32)remBytes;
2317*f6dc9357SAndroid Build Coastguard Worker 
2318*f6dc9357SAndroid Build Coastguard Worker     if (!extent.IsInited)
2319*f6dc9357SAndroid Build Coastguard Worker     {
2320*f6dc9357SAndroid Build Coastguard Worker       memset(data, 0, size);
2321*f6dc9357SAndroid Build Coastguard Worker       _virtPos += size;
2322*f6dc9357SAndroid Build Coastguard Worker       if (processedSize)
2323*f6dc9357SAndroid Build Coastguard Worker         *processedSize = size;
2324*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
2325*f6dc9357SAndroid Build Coastguard Worker     }
2326*f6dc9357SAndroid Build Coastguard Worker 
2327*f6dc9357SAndroid Build Coastguard Worker     const UInt64 phyBlock = extent.PhyStart + bo;
2328*f6dc9357SAndroid Build Coastguard Worker     const UInt64 phy = (phyBlock << BlockBits) + offset;
2329*f6dc9357SAndroid Build Coastguard Worker 
2330*f6dc9357SAndroid Build Coastguard Worker     if (phy != _phyPos)
2331*f6dc9357SAndroid Build Coastguard Worker     {
2332*f6dc9357SAndroid Build Coastguard Worker       RINOK(InStream_SeekSet(Stream, phy))
2333*f6dc9357SAndroid Build Coastguard Worker       _phyPos = phy;
2334*f6dc9357SAndroid Build Coastguard Worker     }
2335*f6dc9357SAndroid Build Coastguard Worker 
2336*f6dc9357SAndroid Build Coastguard Worker     UInt32 realProcessSize = 0;
2337*f6dc9357SAndroid Build Coastguard Worker 
2338*f6dc9357SAndroid Build Coastguard Worker     const HRESULT res = Stream->Read(data, size, &realProcessSize);
2339*f6dc9357SAndroid Build Coastguard Worker 
2340*f6dc9357SAndroid Build Coastguard Worker     _phyPos += realProcessSize;
2341*f6dc9357SAndroid Build Coastguard Worker     _virtPos += realProcessSize;
2342*f6dc9357SAndroid Build Coastguard Worker     if (processedSize)
2343*f6dc9357SAndroid Build Coastguard Worker       *processedSize = realProcessSize;
2344*f6dc9357SAndroid Build Coastguard Worker     return res;
2345*f6dc9357SAndroid Build Coastguard Worker   }
2346*f6dc9357SAndroid Build Coastguard Worker }
2347*f6dc9357SAndroid Build Coastguard Worker 
2348*f6dc9357SAndroid Build Coastguard Worker 
2349*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CExtInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
2350*f6dc9357SAndroid Build Coastguard Worker {
2351*f6dc9357SAndroid Build Coastguard Worker   switch (seekOrigin)
2352*f6dc9357SAndroid Build Coastguard Worker   {
2353*f6dc9357SAndroid Build Coastguard Worker     case STREAM_SEEK_SET: break;
2354*f6dc9357SAndroid Build Coastguard Worker     case STREAM_SEEK_CUR: offset += _virtPos; break;
2355*f6dc9357SAndroid Build Coastguard Worker     case STREAM_SEEK_END: offset += Size; break;
2356*f6dc9357SAndroid Build Coastguard Worker     default: return STG_E_INVALIDFUNCTION;
2357*f6dc9357SAndroid Build Coastguard Worker   }
2358*f6dc9357SAndroid Build Coastguard Worker   if (offset < 0)
2359*f6dc9357SAndroid Build Coastguard Worker     return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
2360*f6dc9357SAndroid Build Coastguard Worker   _virtPos = (UInt64)offset;
2361*f6dc9357SAndroid Build Coastguard Worker   if (newPosition)
2362*f6dc9357SAndroid Build Coastguard Worker     *newPosition = (UInt64)offset;
2363*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
2364*f6dc9357SAndroid Build Coastguard Worker }
2365*f6dc9357SAndroid Build Coastguard Worker 
2366*f6dc9357SAndroid Build Coastguard Worker 
2367*f6dc9357SAndroid Build Coastguard Worker 
2368*f6dc9357SAndroid Build Coastguard Worker HRESULT CHandler::FillFileBlocks2(UInt32 block, unsigned level, unsigned numBlocks, CRecordVector<UInt32> &blocks)
2369*f6dc9357SAndroid Build Coastguard Worker {
2370*f6dc9357SAndroid Build Coastguard Worker   const size_t blockSize = (size_t)1 << _h.BlockBits;
2371*f6dc9357SAndroid Build Coastguard Worker   CByteBuffer &tempBuf = _tempBufs[level];
2372*f6dc9357SAndroid Build Coastguard Worker   tempBuf.Alloc(blockSize);
2373*f6dc9357SAndroid Build Coastguard Worker 
2374*f6dc9357SAndroid Build Coastguard Worker   PRF2(printf("\n level = %d, block = %7d", level, (unsigned)block));
2375*f6dc9357SAndroid Build Coastguard Worker 
2376*f6dc9357SAndroid Build Coastguard Worker   RINOK(SeekAndRead(_stream, block, tempBuf, blockSize))
2377*f6dc9357SAndroid Build Coastguard Worker 
2378*f6dc9357SAndroid Build Coastguard Worker   const Byte *p = tempBuf;
2379*f6dc9357SAndroid Build Coastguard Worker   size_t num = (size_t)1 << (_h.BlockBits - 2);
2380*f6dc9357SAndroid Build Coastguard Worker 
2381*f6dc9357SAndroid Build Coastguard Worker   for (size_t i = 0; i < num; i++)
2382*f6dc9357SAndroid Build Coastguard Worker   {
2383*f6dc9357SAndroid Build Coastguard Worker     if (blocks.Size() == numBlocks)
2384*f6dc9357SAndroid Build Coastguard Worker       break;
2385*f6dc9357SAndroid Build Coastguard Worker     UInt32 val = GetUi32(p + 4 * i);
2386*f6dc9357SAndroid Build Coastguard Worker     if (val >= _h.NumBlocks)
2387*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
2388*f6dc9357SAndroid Build Coastguard Worker 
2389*f6dc9357SAndroid Build Coastguard Worker     if (level != 0)
2390*f6dc9357SAndroid Build Coastguard Worker     {
2391*f6dc9357SAndroid Build Coastguard Worker       if (val == 0)
2392*f6dc9357SAndroid Build Coastguard Worker       {
2393*f6dc9357SAndroid Build Coastguard Worker         /*
2394*f6dc9357SAndroid Build Coastguard Worker         size_t num = (size_t)1 << ((_h.BlockBits - 2) * (level));
2395*f6dc9357SAndroid Build Coastguard Worker         PRF2(printf("\n num empty = %3d", (unsigned)num));
2396*f6dc9357SAndroid Build Coastguard Worker         for (size_t k = 0; k < num; k++)
2397*f6dc9357SAndroid Build Coastguard Worker         {
2398*f6dc9357SAndroid Build Coastguard Worker           blocks.Add(0);
2399*f6dc9357SAndroid Build Coastguard Worker           if (blocks.Size() == numBlocks)
2400*f6dc9357SAndroid Build Coastguard Worker             return S_OK;
2401*f6dc9357SAndroid Build Coastguard Worker         }
2402*f6dc9357SAndroid Build Coastguard Worker         continue;
2403*f6dc9357SAndroid Build Coastguard Worker         */
2404*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
2405*f6dc9357SAndroid Build Coastguard Worker       }
2406*f6dc9357SAndroid Build Coastguard Worker 
2407*f6dc9357SAndroid Build Coastguard Worker       RINOK(FillFileBlocks2(val, level - 1, numBlocks, blocks))
2408*f6dc9357SAndroid Build Coastguard Worker       continue;
2409*f6dc9357SAndroid Build Coastguard Worker     }
2410*f6dc9357SAndroid Build Coastguard Worker 
2411*f6dc9357SAndroid Build Coastguard Worker     PRF2(printf("\n i = %3d,  blocks.Size() = %6d, block = %5d ", i, blocks.Size(), (unsigned)val));
2412*f6dc9357SAndroid Build Coastguard Worker 
2413*f6dc9357SAndroid Build Coastguard Worker     PRF(printf("\n i = %3d,  start = %5d ", (unsigned)i, (unsigned)val));
2414*f6dc9357SAndroid Build Coastguard Worker 
2415*f6dc9357SAndroid Build Coastguard Worker     blocks.Add(val);
2416*f6dc9357SAndroid Build Coastguard Worker   }
2417*f6dc9357SAndroid Build Coastguard Worker 
2418*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
2419*f6dc9357SAndroid Build Coastguard Worker }
2420*f6dc9357SAndroid Build Coastguard Worker 
2421*f6dc9357SAndroid Build Coastguard Worker 
2422*f6dc9357SAndroid Build Coastguard Worker static const unsigned kNumDirectNodeBlocks = 12;
2423*f6dc9357SAndroid Build Coastguard Worker 
2424*f6dc9357SAndroid Build Coastguard Worker HRESULT CHandler::FillFileBlocks(const Byte *p, unsigned numBlocks, CRecordVector<UInt32> &blocks)
2425*f6dc9357SAndroid Build Coastguard Worker {
2426*f6dc9357SAndroid Build Coastguard Worker   // ext2 supports zero blocks (blockIndex == 0).
2427*f6dc9357SAndroid Build Coastguard Worker 
2428*f6dc9357SAndroid Build Coastguard Worker   blocks.ClearAndReserve(numBlocks);
2429*f6dc9357SAndroid Build Coastguard Worker 
2430*f6dc9357SAndroid Build Coastguard Worker   for (unsigned i = 0; i < kNumDirectNodeBlocks; i++)
2431*f6dc9357SAndroid Build Coastguard Worker   {
2432*f6dc9357SAndroid Build Coastguard Worker     if (i == numBlocks)
2433*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
2434*f6dc9357SAndroid Build Coastguard Worker     UInt32 val = GetUi32(p + 4 * i);
2435*f6dc9357SAndroid Build Coastguard Worker     if (val >= _h.NumBlocks)
2436*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
2437*f6dc9357SAndroid Build Coastguard Worker     blocks.Add(val);
2438*f6dc9357SAndroid Build Coastguard Worker   }
2439*f6dc9357SAndroid Build Coastguard Worker 
2440*f6dc9357SAndroid Build Coastguard Worker   for (unsigned level = 0; level < 3; level++)
2441*f6dc9357SAndroid Build Coastguard Worker   {
2442*f6dc9357SAndroid Build Coastguard Worker     if (blocks.Size() == numBlocks)
2443*f6dc9357SAndroid Build Coastguard Worker       break;
2444*f6dc9357SAndroid Build Coastguard Worker     UInt32 val = GetUi32(p + 4 * (kNumDirectNodeBlocks + level));
2445*f6dc9357SAndroid Build Coastguard Worker     if (val >= _h.NumBlocks)
2446*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
2447*f6dc9357SAndroid Build Coastguard Worker 
2448*f6dc9357SAndroid Build Coastguard Worker     if (val == 0)
2449*f6dc9357SAndroid Build Coastguard Worker     {
2450*f6dc9357SAndroid Build Coastguard Worker       /*
2451*f6dc9357SAndroid Build Coastguard Worker       size_t num = (size_t)1 << ((_h.BlockBits - 2) * (level + 1));
2452*f6dc9357SAndroid Build Coastguard Worker       for (size_t k = 0; k < num; k++)
2453*f6dc9357SAndroid Build Coastguard Worker       {
2454*f6dc9357SAndroid Build Coastguard Worker         blocks.Add(0);
2455*f6dc9357SAndroid Build Coastguard Worker         if (blocks.Size() == numBlocks)
2456*f6dc9357SAndroid Build Coastguard Worker           return S_OK;
2457*f6dc9357SAndroid Build Coastguard Worker       }
2458*f6dc9357SAndroid Build Coastguard Worker       continue;
2459*f6dc9357SAndroid Build Coastguard Worker       */
2460*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
2461*f6dc9357SAndroid Build Coastguard Worker     }
2462*f6dc9357SAndroid Build Coastguard Worker 
2463*f6dc9357SAndroid Build Coastguard Worker     RINOK(FillFileBlocks2(val, level, numBlocks, blocks))
2464*f6dc9357SAndroid Build Coastguard Worker   }
2465*f6dc9357SAndroid Build Coastguard Worker 
2466*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
2467*f6dc9357SAndroid Build Coastguard Worker }
2468*f6dc9357SAndroid Build Coastguard Worker 
2469*f6dc9357SAndroid Build Coastguard Worker 
2470*f6dc9357SAndroid Build Coastguard Worker static void AddSkipExtents(CRecordVector<CExtent> &extents, UInt32 virtBlock, UInt32 numBlocks)
2471*f6dc9357SAndroid Build Coastguard Worker {
2472*f6dc9357SAndroid Build Coastguard Worker   while (numBlocks != 0)
2473*f6dc9357SAndroid Build Coastguard Worker   {
2474*f6dc9357SAndroid Build Coastguard Worker     UInt32 len = numBlocks;
2475*f6dc9357SAndroid Build Coastguard Worker     const UInt32 kLenMax = (UInt32)1 << 15;
2476*f6dc9357SAndroid Build Coastguard Worker     if (len > kLenMax)
2477*f6dc9357SAndroid Build Coastguard Worker       len = kLenMax;
2478*f6dc9357SAndroid Build Coastguard Worker     CExtent e;
2479*f6dc9357SAndroid Build Coastguard Worker     e.VirtBlock = virtBlock;
2480*f6dc9357SAndroid Build Coastguard Worker     e.Len = (UInt16)len;
2481*f6dc9357SAndroid Build Coastguard Worker     e.IsInited = false;
2482*f6dc9357SAndroid Build Coastguard Worker     e.PhyStart = 0;
2483*f6dc9357SAndroid Build Coastguard Worker     extents.Add(e);
2484*f6dc9357SAndroid Build Coastguard Worker     virtBlock += len;
2485*f6dc9357SAndroid Build Coastguard Worker     numBlocks -= len;
2486*f6dc9357SAndroid Build Coastguard Worker   }
2487*f6dc9357SAndroid Build Coastguard Worker }
2488*f6dc9357SAndroid Build Coastguard Worker 
2489*f6dc9357SAndroid Build Coastguard Worker static bool UpdateExtents(CRecordVector<CExtent> &extents, UInt32 block)
2490*f6dc9357SAndroid Build Coastguard Worker {
2491*f6dc9357SAndroid Build Coastguard Worker   if (extents.IsEmpty())
2492*f6dc9357SAndroid Build Coastguard Worker   {
2493*f6dc9357SAndroid Build Coastguard Worker     if (block == 0)
2494*f6dc9357SAndroid Build Coastguard Worker       return true;
2495*f6dc9357SAndroid Build Coastguard Worker     AddSkipExtents(extents, 0, block);
2496*f6dc9357SAndroid Build Coastguard Worker     return true;
2497*f6dc9357SAndroid Build Coastguard Worker   }
2498*f6dc9357SAndroid Build Coastguard Worker 
2499*f6dc9357SAndroid Build Coastguard Worker   const CExtent &prev = extents.Back();
2500*f6dc9357SAndroid Build Coastguard Worker   if (block < prev.VirtBlock)
2501*f6dc9357SAndroid Build Coastguard Worker     return false;
2502*f6dc9357SAndroid Build Coastguard Worker   UInt32 prevEnd = prev.GetVirtEnd();
2503*f6dc9357SAndroid Build Coastguard Worker   if (block == prevEnd)
2504*f6dc9357SAndroid Build Coastguard Worker     return true;
2505*f6dc9357SAndroid Build Coastguard Worker   AddSkipExtents(extents, prevEnd, block - prevEnd);
2506*f6dc9357SAndroid Build Coastguard Worker   return true;
2507*f6dc9357SAndroid Build Coastguard Worker }
2508*f6dc9357SAndroid Build Coastguard Worker 
2509*f6dc9357SAndroid Build Coastguard Worker 
2510*f6dc9357SAndroid Build Coastguard Worker HRESULT CHandler::FillExtents(const Byte *p, size_t size, CRecordVector<CExtent> &extents, int parentDepth)
2511*f6dc9357SAndroid Build Coastguard Worker {
2512*f6dc9357SAndroid Build Coastguard Worker   CExtentTreeHeader eth;
2513*f6dc9357SAndroid Build Coastguard Worker   if (!eth.Parse(p))
2514*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
2515*f6dc9357SAndroid Build Coastguard Worker 
2516*f6dc9357SAndroid Build Coastguard Worker   if (parentDepth >= 0 && eth.Depth != parentDepth - 1) // (eth.Depth >= parentDepth)
2517*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
2518*f6dc9357SAndroid Build Coastguard Worker 
2519*f6dc9357SAndroid Build Coastguard Worker   if (12 + 12 * (size_t)eth.NumEntries > size)
2520*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
2521*f6dc9357SAndroid Build Coastguard Worker 
2522*f6dc9357SAndroid Build Coastguard Worker   if (eth.Depth >= kNumTreeLevelsMax)
2523*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
2524*f6dc9357SAndroid Build Coastguard Worker 
2525*f6dc9357SAndroid Build Coastguard Worker   if (eth.Depth == 0)
2526*f6dc9357SAndroid Build Coastguard Worker   {
2527*f6dc9357SAndroid Build Coastguard Worker     for (unsigned i = 0; i < eth.NumEntries; i++)
2528*f6dc9357SAndroid Build Coastguard Worker     {
2529*f6dc9357SAndroid Build Coastguard Worker       CExtent e;
2530*f6dc9357SAndroid Build Coastguard Worker       e.Parse(p + 12 + i * 12);
2531*f6dc9357SAndroid Build Coastguard Worker       if (e.PhyStart == 0
2532*f6dc9357SAndroid Build Coastguard Worker           || e.PhyStart > _h.NumBlocks
2533*f6dc9357SAndroid Build Coastguard Worker           || e.PhyStart + e.Len > _h.NumBlocks
2534*f6dc9357SAndroid Build Coastguard Worker           || !e.IsLenOK())
2535*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
2536*f6dc9357SAndroid Build Coastguard Worker       if (!UpdateExtents(extents, e.VirtBlock))
2537*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
2538*f6dc9357SAndroid Build Coastguard Worker       extents.Add(e);
2539*f6dc9357SAndroid Build Coastguard Worker     }
2540*f6dc9357SAndroid Build Coastguard Worker 
2541*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
2542*f6dc9357SAndroid Build Coastguard Worker   }
2543*f6dc9357SAndroid Build Coastguard Worker 
2544*f6dc9357SAndroid Build Coastguard Worker   const size_t blockSize = (size_t)1 << _h.BlockBits;
2545*f6dc9357SAndroid Build Coastguard Worker   CByteBuffer &tempBuf = _tempBufs[eth.Depth];
2546*f6dc9357SAndroid Build Coastguard Worker   tempBuf.Alloc(blockSize);
2547*f6dc9357SAndroid Build Coastguard Worker 
2548*f6dc9357SAndroid Build Coastguard Worker   for (unsigned i = 0; i < eth.NumEntries; i++)
2549*f6dc9357SAndroid Build Coastguard Worker   {
2550*f6dc9357SAndroid Build Coastguard Worker     CExtentIndexNode e;
2551*f6dc9357SAndroid Build Coastguard Worker     e.Parse(p + 12 + i * 12);
2552*f6dc9357SAndroid Build Coastguard Worker 
2553*f6dc9357SAndroid Build Coastguard Worker     if (e.PhyLeaf == 0 || e.PhyLeaf >= _h.NumBlocks)
2554*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
2555*f6dc9357SAndroid Build Coastguard Worker 
2556*f6dc9357SAndroid Build Coastguard Worker     if (!UpdateExtents(extents, e.VirtBlock))
2557*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
2558*f6dc9357SAndroid Build Coastguard Worker 
2559*f6dc9357SAndroid Build Coastguard Worker     RINOK(SeekAndRead(_stream, e.PhyLeaf, tempBuf, blockSize))
2560*f6dc9357SAndroid Build Coastguard Worker     RINOK(FillExtents(tempBuf, blockSize, extents, eth.Depth))
2561*f6dc9357SAndroid Build Coastguard Worker   }
2562*f6dc9357SAndroid Build Coastguard Worker 
2563*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
2564*f6dc9357SAndroid Build Coastguard Worker }
2565*f6dc9357SAndroid Build Coastguard Worker 
2566*f6dc9357SAndroid Build Coastguard Worker 
2567*f6dc9357SAndroid Build Coastguard Worker HRESULT CHandler::GetStream_Node(unsigned nodeIndex, ISequentialInStream **stream)
2568*f6dc9357SAndroid Build Coastguard Worker {
2569*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
2570*f6dc9357SAndroid Build Coastguard Worker 
2571*f6dc9357SAndroid Build Coastguard Worker   *stream = NULL;
2572*f6dc9357SAndroid Build Coastguard Worker 
2573*f6dc9357SAndroid Build Coastguard Worker   const CNode &node = _nodes[nodeIndex];
2574*f6dc9357SAndroid Build Coastguard Worker 
2575*f6dc9357SAndroid Build Coastguard Worker   if (!node.IsFlags_EXTENTS())
2576*f6dc9357SAndroid Build Coastguard Worker   {
2577*f6dc9357SAndroid Build Coastguard Worker     // maybe sparse file can have (node.NumBlocks == 0) ?
2578*f6dc9357SAndroid Build Coastguard Worker 
2579*f6dc9357SAndroid Build Coastguard Worker     /* The following code doesn't work correctly for some CentOS images,
2580*f6dc9357SAndroid Build Coastguard Worker        where there are nodes with inline data and (node.NumBlocks != 0).
2581*f6dc9357SAndroid Build Coastguard Worker        If you know better way to detect inline data, please notify 7-Zip developers. */
2582*f6dc9357SAndroid Build Coastguard Worker 
2583*f6dc9357SAndroid Build Coastguard Worker     if (node.NumBlocks == 0 && node.FileSize < kNodeBlockFieldSize)
2584*f6dc9357SAndroid Build Coastguard Worker     {
2585*f6dc9357SAndroid Build Coastguard Worker       Create_BufInStream_WithNewBuffer(node.Block, (size_t)node.FileSize, stream);
2586*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
2587*f6dc9357SAndroid Build Coastguard Worker     }
2588*f6dc9357SAndroid Build Coastguard Worker   }
2589*f6dc9357SAndroid Build Coastguard Worker 
2590*f6dc9357SAndroid Build Coastguard Worker   if (node.FileSize >= ((UInt64)1 << 63))
2591*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
2592*f6dc9357SAndroid Build Coastguard Worker 
2593*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<IInStream> streamTemp;
2594*f6dc9357SAndroid Build Coastguard Worker 
2595*f6dc9357SAndroid Build Coastguard Worker   const UInt64 numBlocks64 = (node.FileSize + (UInt64)(((UInt32)1 << _h.BlockBits) - 1)) >> _h.BlockBits;
2596*f6dc9357SAndroid Build Coastguard Worker 
2597*f6dc9357SAndroid Build Coastguard Worker   if (node.IsFlags_EXTENTS())
2598*f6dc9357SAndroid Build Coastguard Worker   {
2599*f6dc9357SAndroid Build Coastguard Worker     if ((UInt32)numBlocks64 != numBlocks64)
2600*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
2601*f6dc9357SAndroid Build Coastguard Worker 
2602*f6dc9357SAndroid Build Coastguard Worker     CExtInStream *streamSpec = new CExtInStream;
2603*f6dc9357SAndroid Build Coastguard Worker     streamTemp = streamSpec;
2604*f6dc9357SAndroid Build Coastguard Worker 
2605*f6dc9357SAndroid Build Coastguard Worker     streamSpec->BlockBits = _h.BlockBits;
2606*f6dc9357SAndroid Build Coastguard Worker     streamSpec->Size = node.FileSize;
2607*f6dc9357SAndroid Build Coastguard Worker     streamSpec->Stream = _stream;
2608*f6dc9357SAndroid Build Coastguard Worker 
2609*f6dc9357SAndroid Build Coastguard Worker     RINOK(FillExtents(node.Block, kNodeBlockFieldSize, streamSpec->Extents, -1))
2610*f6dc9357SAndroid Build Coastguard Worker 
2611*f6dc9357SAndroid Build Coastguard Worker     UInt32 end = 0;
2612*f6dc9357SAndroid Build Coastguard Worker     if (!streamSpec->Extents.IsEmpty())
2613*f6dc9357SAndroid Build Coastguard Worker       end = streamSpec->Extents.Back().GetVirtEnd();
2614*f6dc9357SAndroid Build Coastguard Worker     if (end < numBlocks64)
2615*f6dc9357SAndroid Build Coastguard Worker     {
2616*f6dc9357SAndroid Build Coastguard Worker       AddSkipExtents(streamSpec->Extents, end, (UInt32)(numBlocks64 - end));
2617*f6dc9357SAndroid Build Coastguard Worker       // return S_FALSE;
2618*f6dc9357SAndroid Build Coastguard Worker     }
2619*f6dc9357SAndroid Build Coastguard Worker 
2620*f6dc9357SAndroid Build Coastguard Worker     RINOK(streamSpec->StartSeek())
2621*f6dc9357SAndroid Build Coastguard Worker   }
2622*f6dc9357SAndroid Build Coastguard Worker   else
2623*f6dc9357SAndroid Build Coastguard Worker   {
2624*f6dc9357SAndroid Build Coastguard Worker     {
2625*f6dc9357SAndroid Build Coastguard Worker       UInt64 numBlocks2 = numBlocks64;
2626*f6dc9357SAndroid Build Coastguard Worker 
2627*f6dc9357SAndroid Build Coastguard Worker       if (numBlocks64 > kNumDirectNodeBlocks)
2628*f6dc9357SAndroid Build Coastguard Worker       {
2629*f6dc9357SAndroid Build Coastguard Worker         UInt64 rem = numBlocks64 - kNumDirectNodeBlocks;
2630*f6dc9357SAndroid Build Coastguard Worker         const unsigned refBits = (_h.BlockBits - 2);
2631*f6dc9357SAndroid Build Coastguard Worker         const size_t numRefsInBlocks = (size_t)1 << refBits;
2632*f6dc9357SAndroid Build Coastguard Worker         numBlocks2++;
2633*f6dc9357SAndroid Build Coastguard Worker         if (rem > numRefsInBlocks)
2634*f6dc9357SAndroid Build Coastguard Worker         {
2635*f6dc9357SAndroid Build Coastguard Worker           numBlocks2++;
2636*f6dc9357SAndroid Build Coastguard Worker           const UInt64 numL2 = (rem - 1) >> refBits;
2637*f6dc9357SAndroid Build Coastguard Worker           numBlocks2 += numL2;
2638*f6dc9357SAndroid Build Coastguard Worker           if (numL2 > numRefsInBlocks)
2639*f6dc9357SAndroid Build Coastguard Worker           {
2640*f6dc9357SAndroid Build Coastguard Worker             numBlocks2++;
2641*f6dc9357SAndroid Build Coastguard Worker             numBlocks2 += (numL2 - 1) >> refBits;
2642*f6dc9357SAndroid Build Coastguard Worker           }
2643*f6dc9357SAndroid Build Coastguard Worker         }
2644*f6dc9357SAndroid Build Coastguard Worker       }
2645*f6dc9357SAndroid Build Coastguard Worker 
2646*f6dc9357SAndroid Build Coastguard Worker       const unsigned specBits = (node.IsFlags_HUGE() ? 0 : _h.BlockBits - 9);
2647*f6dc9357SAndroid Build Coastguard Worker       const UInt32 specMask = ((UInt32)1 << specBits) - 1;
2648*f6dc9357SAndroid Build Coastguard Worker       if ((node.NumBlocks & specMask) != 0)
2649*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
2650*f6dc9357SAndroid Build Coastguard Worker       const UInt64 numBlocks64_from_header = node.NumBlocks >> specBits;
2651*f6dc9357SAndroid Build Coastguard Worker       if (numBlocks64_from_header < numBlocks2)
2652*f6dc9357SAndroid Build Coastguard Worker       {
2653*f6dc9357SAndroid Build Coastguard Worker         // why (numBlocks64_from_header > numBlocks2) in some cases?
2654*f6dc9357SAndroid Build Coastguard Worker         // return S_FALSE;
2655*f6dc9357SAndroid Build Coastguard Worker       }
2656*f6dc9357SAndroid Build Coastguard Worker     }
2657*f6dc9357SAndroid Build Coastguard Worker 
2658*f6dc9357SAndroid Build Coastguard Worker     unsigned numBlocks = (unsigned)numBlocks64;
2659*f6dc9357SAndroid Build Coastguard Worker     if (numBlocks != numBlocks64)
2660*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
2661*f6dc9357SAndroid Build Coastguard Worker 
2662*f6dc9357SAndroid Build Coastguard Worker     CClusterInStream2 *streamSpec = new CClusterInStream2;
2663*f6dc9357SAndroid Build Coastguard Worker     streamTemp = streamSpec;
2664*f6dc9357SAndroid Build Coastguard Worker 
2665*f6dc9357SAndroid Build Coastguard Worker     streamSpec->BlockBits = _h.BlockBits;
2666*f6dc9357SAndroid Build Coastguard Worker     streamSpec->Size = node.FileSize;
2667*f6dc9357SAndroid Build Coastguard Worker     streamSpec->Stream = _stream;
2668*f6dc9357SAndroid Build Coastguard Worker 
2669*f6dc9357SAndroid Build Coastguard Worker     RINOK(FillFileBlocks(node.Block, numBlocks, streamSpec->Vector))
2670*f6dc9357SAndroid Build Coastguard Worker     streamSpec->InitAndSeek();
2671*f6dc9357SAndroid Build Coastguard Worker   }
2672*f6dc9357SAndroid Build Coastguard Worker 
2673*f6dc9357SAndroid Build Coastguard Worker   *stream = streamTemp.Detach();
2674*f6dc9357SAndroid Build Coastguard Worker 
2675*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
2676*f6dc9357SAndroid Build Coastguard Worker 
2677*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
2678*f6dc9357SAndroid Build Coastguard Worker }
2679*f6dc9357SAndroid Build Coastguard Worker 
2680*f6dc9357SAndroid Build Coastguard Worker 
2681*f6dc9357SAndroid Build Coastguard Worker HRESULT CHandler::ExtractNode(unsigned nodeIndex, CByteBuffer &data)
2682*f6dc9357SAndroid Build Coastguard Worker {
2683*f6dc9357SAndroid Build Coastguard Worker   data.Free();
2684*f6dc9357SAndroid Build Coastguard Worker   const CNode &node = _nodes[nodeIndex];
2685*f6dc9357SAndroid Build Coastguard Worker   size_t size = (size_t)node.FileSize;
2686*f6dc9357SAndroid Build Coastguard Worker   if (size != node.FileSize)
2687*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
2688*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<ISequentialInStream> inSeqStream;
2689*f6dc9357SAndroid Build Coastguard Worker   RINOK(GetStream_Node(nodeIndex, &inSeqStream))
2690*f6dc9357SAndroid Build Coastguard Worker   if (!inSeqStream)
2691*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
2692*f6dc9357SAndroid Build Coastguard Worker   data.Alloc(size);
2693*f6dc9357SAndroid Build Coastguard Worker   _totalRead += size;
2694*f6dc9357SAndroid Build Coastguard Worker   return ReadStream_FALSE(inSeqStream, data, size);
2695*f6dc9357SAndroid Build Coastguard Worker }
2696*f6dc9357SAndroid Build Coastguard Worker 
2697*f6dc9357SAndroid Build Coastguard Worker 
2698*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
2699*f6dc9357SAndroid Build Coastguard Worker     Int32 testMode, IArchiveExtractCallback *extractCallback))
2700*f6dc9357SAndroid Build Coastguard Worker {
2701*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
2702*f6dc9357SAndroid Build Coastguard Worker   const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
2703*f6dc9357SAndroid Build Coastguard Worker   if (allFilesMode)
2704*f6dc9357SAndroid Build Coastguard Worker     numItems = _items.Size() + _auxItems.Size();
2705*f6dc9357SAndroid Build Coastguard Worker   if (numItems == 0)
2706*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
2707*f6dc9357SAndroid Build Coastguard Worker 
2708*f6dc9357SAndroid Build Coastguard Worker   UInt64 totalSize = 0;
2709*f6dc9357SAndroid Build Coastguard Worker   UInt32 i;
2710*f6dc9357SAndroid Build Coastguard Worker 
2711*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < numItems; i++)
2712*f6dc9357SAndroid Build Coastguard Worker   {
2713*f6dc9357SAndroid Build Coastguard Worker     const UInt32 index = allFilesMode ? i : indices[i];
2714*f6dc9357SAndroid Build Coastguard Worker     if (index >= _items.Size())
2715*f6dc9357SAndroid Build Coastguard Worker       continue;
2716*f6dc9357SAndroid Build Coastguard Worker     const CItem &item = _items[index];
2717*f6dc9357SAndroid Build Coastguard Worker     const CNode &node = _nodes[_refs[item.Node]];
2718*f6dc9357SAndroid Build Coastguard Worker     if (!node.IsDir())
2719*f6dc9357SAndroid Build Coastguard Worker       totalSize += node.FileSize;
2720*f6dc9357SAndroid Build Coastguard Worker   }
2721*f6dc9357SAndroid Build Coastguard Worker 
2722*f6dc9357SAndroid Build Coastguard Worker   RINOK(extractCallback->SetTotal(totalSize))
2723*f6dc9357SAndroid Build Coastguard Worker 
2724*f6dc9357SAndroid Build Coastguard Worker   UInt64 totalPackSize;
2725*f6dc9357SAndroid Build Coastguard Worker   totalSize = totalPackSize = 0;
2726*f6dc9357SAndroid Build Coastguard Worker 
2727*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ICompressProgressInfo, CLocalProgress> lps;
2728*f6dc9357SAndroid Build Coastguard Worker   lps->Init(extractCallback, false);
2729*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ICompressCoder, NCompress::CCopyCoder> copyCoder;
2730*f6dc9357SAndroid Build Coastguard Worker 
2731*f6dc9357SAndroid Build Coastguard Worker   for (i = 0;; i++)
2732*f6dc9357SAndroid Build Coastguard Worker   {
2733*f6dc9357SAndroid Build Coastguard Worker     lps->InSize = totalPackSize;
2734*f6dc9357SAndroid Build Coastguard Worker     lps->OutSize = totalSize;
2735*f6dc9357SAndroid Build Coastguard Worker     RINOK(lps->SetCur())
2736*f6dc9357SAndroid Build Coastguard Worker     if (i >= numItems)
2737*f6dc9357SAndroid Build Coastguard Worker       break;
2738*f6dc9357SAndroid Build Coastguard Worker 
2739*f6dc9357SAndroid Build Coastguard Worker     int opRes;
2740*f6dc9357SAndroid Build Coastguard Worker    {
2741*f6dc9357SAndroid Build Coastguard Worker     CMyComPtr<ISequentialOutStream> outStream;
2742*f6dc9357SAndroid Build Coastguard Worker     const Int32 askMode = testMode ?
2743*f6dc9357SAndroid Build Coastguard Worker         NExtract::NAskMode::kTest :
2744*f6dc9357SAndroid Build Coastguard Worker         NExtract::NAskMode::kExtract;
2745*f6dc9357SAndroid Build Coastguard Worker 
2746*f6dc9357SAndroid Build Coastguard Worker     const UInt32 index = allFilesMode ? i : indices[i];
2747*f6dc9357SAndroid Build Coastguard Worker 
2748*f6dc9357SAndroid Build Coastguard Worker     RINOK(extractCallback->GetStream(index, &outStream, askMode))
2749*f6dc9357SAndroid Build Coastguard Worker 
2750*f6dc9357SAndroid Build Coastguard Worker     if (index >= _items.Size())
2751*f6dc9357SAndroid Build Coastguard Worker     {
2752*f6dc9357SAndroid Build Coastguard Worker       RINOK(extractCallback->PrepareOperation(askMode))
2753*f6dc9357SAndroid Build Coastguard Worker       RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
2754*f6dc9357SAndroid Build Coastguard Worker       continue;
2755*f6dc9357SAndroid Build Coastguard Worker     }
2756*f6dc9357SAndroid Build Coastguard Worker 
2757*f6dc9357SAndroid Build Coastguard Worker     const CItem &item = _items[index];
2758*f6dc9357SAndroid Build Coastguard Worker     const CNode &node = _nodes[_refs[item.Node]];
2759*f6dc9357SAndroid Build Coastguard Worker 
2760*f6dc9357SAndroid Build Coastguard Worker     if (node.IsDir())
2761*f6dc9357SAndroid Build Coastguard Worker     {
2762*f6dc9357SAndroid Build Coastguard Worker       RINOK(extractCallback->PrepareOperation(askMode))
2763*f6dc9357SAndroid Build Coastguard Worker       RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
2764*f6dc9357SAndroid Build Coastguard Worker       continue;
2765*f6dc9357SAndroid Build Coastguard Worker     }
2766*f6dc9357SAndroid Build Coastguard Worker 
2767*f6dc9357SAndroid Build Coastguard Worker     UInt64 unpackSize = node.FileSize;
2768*f6dc9357SAndroid Build Coastguard Worker     totalSize += unpackSize;
2769*f6dc9357SAndroid Build Coastguard Worker     UInt64 packSize;
2770*f6dc9357SAndroid Build Coastguard Worker     if (GetPackSize(index, packSize))
2771*f6dc9357SAndroid Build Coastguard Worker       totalPackSize += packSize;
2772*f6dc9357SAndroid Build Coastguard Worker 
2773*f6dc9357SAndroid Build Coastguard Worker     if (!testMode && !outStream)
2774*f6dc9357SAndroid Build Coastguard Worker       continue;
2775*f6dc9357SAndroid Build Coastguard Worker     RINOK(extractCallback->PrepareOperation(askMode))
2776*f6dc9357SAndroid Build Coastguard Worker 
2777*f6dc9357SAndroid Build Coastguard Worker     opRes = NExtract::NOperationResult::kDataError;
2778*f6dc9357SAndroid Build Coastguard Worker     {
2779*f6dc9357SAndroid Build Coastguard Worker       CMyComPtr<ISequentialInStream> inSeqStream;
2780*f6dc9357SAndroid Build Coastguard Worker       HRESULT hres = GetStream(index, &inSeqStream);
2781*f6dc9357SAndroid Build Coastguard Worker       if (hres == S_FALSE || !inSeqStream)
2782*f6dc9357SAndroid Build Coastguard Worker       {
2783*f6dc9357SAndroid Build Coastguard Worker         if (hres == E_OUTOFMEMORY)
2784*f6dc9357SAndroid Build Coastguard Worker           return hres;
2785*f6dc9357SAndroid Build Coastguard Worker         opRes = NExtract::NOperationResult::kUnsupportedMethod;
2786*f6dc9357SAndroid Build Coastguard Worker       }
2787*f6dc9357SAndroid Build Coastguard Worker       else
2788*f6dc9357SAndroid Build Coastguard Worker       {
2789*f6dc9357SAndroid Build Coastguard Worker         RINOK(hres)
2790*f6dc9357SAndroid Build Coastguard Worker         {
2791*f6dc9357SAndroid Build Coastguard Worker           hres = copyCoder.Interface()->Code(inSeqStream, outStream, NULL, NULL, lps);
2792*f6dc9357SAndroid Build Coastguard Worker           if (hres == S_OK)
2793*f6dc9357SAndroid Build Coastguard Worker           {
2794*f6dc9357SAndroid Build Coastguard Worker             if (copyCoder->TotalSize == unpackSize)
2795*f6dc9357SAndroid Build Coastguard Worker               opRes = NExtract::NOperationResult::kOK;
2796*f6dc9357SAndroid Build Coastguard Worker           }
2797*f6dc9357SAndroid Build Coastguard Worker           else if (hres == E_NOTIMPL)
2798*f6dc9357SAndroid Build Coastguard Worker           {
2799*f6dc9357SAndroid Build Coastguard Worker             opRes = NExtract::NOperationResult::kUnsupportedMethod;
2800*f6dc9357SAndroid Build Coastguard Worker           }
2801*f6dc9357SAndroid Build Coastguard Worker           else if (hres != S_FALSE)
2802*f6dc9357SAndroid Build Coastguard Worker           {
2803*f6dc9357SAndroid Build Coastguard Worker             RINOK(hres)
2804*f6dc9357SAndroid Build Coastguard Worker           }
2805*f6dc9357SAndroid Build Coastguard Worker         }
2806*f6dc9357SAndroid Build Coastguard Worker       }
2807*f6dc9357SAndroid Build Coastguard Worker     }
2808*f6dc9357SAndroid Build Coastguard Worker    }
2809*f6dc9357SAndroid Build Coastguard Worker     RINOK(extractCallback->SetOperationResult(opRes))
2810*f6dc9357SAndroid Build Coastguard Worker   }
2811*f6dc9357SAndroid Build Coastguard Worker 
2812*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
2813*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
2814*f6dc9357SAndroid Build Coastguard Worker }
2815*f6dc9357SAndroid Build Coastguard Worker 
2816*f6dc9357SAndroid Build Coastguard Worker 
2817*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
2818*f6dc9357SAndroid Build Coastguard Worker {
2819*f6dc9357SAndroid Build Coastguard Worker   *stream = NULL;
2820*f6dc9357SAndroid Build Coastguard Worker   if (index >= _items.Size())
2821*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
2822*f6dc9357SAndroid Build Coastguard Worker   return GetStream_Node((unsigned)_refs[_items[index].Node], stream);
2823*f6dc9357SAndroid Build Coastguard Worker }
2824*f6dc9357SAndroid Build Coastguard Worker 
2825*f6dc9357SAndroid Build Coastguard Worker 
2826*f6dc9357SAndroid Build Coastguard Worker API_FUNC_IsArc IsArc_Ext_PhySize(const Byte *p, size_t size, UInt64 *phySize);
2827*f6dc9357SAndroid Build Coastguard Worker API_FUNC_IsArc IsArc_Ext_PhySize(const Byte *p, size_t size, UInt64 *phySize)
2828*f6dc9357SAndroid Build Coastguard Worker {
2829*f6dc9357SAndroid Build Coastguard Worker   if (phySize)
2830*f6dc9357SAndroid Build Coastguard Worker     *phySize = 0;
2831*f6dc9357SAndroid Build Coastguard Worker   if (size < kHeaderSize)
2832*f6dc9357SAndroid Build Coastguard Worker     return k_IsArc_Res_NEED_MORE;
2833*f6dc9357SAndroid Build Coastguard Worker   CHeader h;
2834*f6dc9357SAndroid Build Coastguard Worker   if (!h.Parse(p + kHeaderDataOffset))
2835*f6dc9357SAndroid Build Coastguard Worker     return k_IsArc_Res_NO;
2836*f6dc9357SAndroid Build Coastguard Worker   if (phySize)
2837*f6dc9357SAndroid Build Coastguard Worker     *phySize = h.GetPhySize();
2838*f6dc9357SAndroid Build Coastguard Worker   return k_IsArc_Res_YES;
2839*f6dc9357SAndroid Build Coastguard Worker }
2840*f6dc9357SAndroid Build Coastguard Worker 
2841*f6dc9357SAndroid Build Coastguard Worker 
2842*f6dc9357SAndroid Build Coastguard Worker API_FUNC_IsArc IsArc_Ext(const Byte *p, size_t size);
2843*f6dc9357SAndroid Build Coastguard Worker API_FUNC_IsArc IsArc_Ext(const Byte *p, size_t size)
2844*f6dc9357SAndroid Build Coastguard Worker {
2845*f6dc9357SAndroid Build Coastguard Worker   return IsArc_Ext_PhySize(p, size, NULL);
2846*f6dc9357SAndroid Build Coastguard Worker }
2847*f6dc9357SAndroid Build Coastguard Worker 
2848*f6dc9357SAndroid Build Coastguard Worker 
2849*f6dc9357SAndroid Build Coastguard Worker static const Byte k_Signature[] = { 0x53, 0xEF };
2850*f6dc9357SAndroid Build Coastguard Worker 
2851*f6dc9357SAndroid Build Coastguard Worker REGISTER_ARC_I(
2852*f6dc9357SAndroid Build Coastguard Worker   "Ext", "ext ext2 ext3 ext4 img", NULL, 0xC7,
2853*f6dc9357SAndroid Build Coastguard Worker   k_Signature,
2854*f6dc9357SAndroid Build Coastguard Worker   0x438,
2855*f6dc9357SAndroid Build Coastguard Worker   0,
2856*f6dc9357SAndroid Build Coastguard Worker   IsArc_Ext)
2857*f6dc9357SAndroid Build Coastguard Worker 
2858*f6dc9357SAndroid Build Coastguard Worker }}
2859