xref: /aosp_15_r20/external/lzma/CPP/7zip/Archive/VhdxHandler.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1*f6dc9357SAndroid Build Coastguard Worker // VhdxHandler.cpp
2*f6dc9357SAndroid Build Coastguard Worker 
3*f6dc9357SAndroid Build Coastguard Worker #include "StdAfx.h"
4*f6dc9357SAndroid Build Coastguard Worker 
5*f6dc9357SAndroid Build Coastguard Worker // #include <stdio.h>
6*f6dc9357SAndroid Build Coastguard Worker 
7*f6dc9357SAndroid Build Coastguard Worker #include "../../../C/CpuArch.h"
8*f6dc9357SAndroid Build Coastguard Worker 
9*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/ComTry.h"
10*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/IntToString.h"
11*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/StringToInt.h"
12*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/MyBuffer.h"
13*f6dc9357SAndroid Build Coastguard Worker 
14*f6dc9357SAndroid Build Coastguard Worker #include "../../Windows/PropVariant.h"
15*f6dc9357SAndroid Build Coastguard Worker 
16*f6dc9357SAndroid Build Coastguard Worker #include "../Common/RegisterArc.h"
17*f6dc9357SAndroid Build Coastguard Worker #include "../Common/StreamUtils.h"
18*f6dc9357SAndroid Build Coastguard Worker 
19*f6dc9357SAndroid Build Coastguard Worker #include "HandlerCont.h"
20*f6dc9357SAndroid Build Coastguard Worker 
21*f6dc9357SAndroid Build Coastguard Worker #define Get16(p) GetUi16(p)
22*f6dc9357SAndroid Build Coastguard Worker #define Get32(p) GetUi32(p)
23*f6dc9357SAndroid Build Coastguard Worker #define Get64(p) GetUi64(p)
24*f6dc9357SAndroid Build Coastguard Worker 
25*f6dc9357SAndroid Build Coastguard Worker #define G32(_offs_, dest) dest = Get32(p + (_offs_))
26*f6dc9357SAndroid Build Coastguard Worker #define G64(_offs_, dest) dest = Get64(p + (_offs_))
27*f6dc9357SAndroid Build Coastguard Worker 
28*f6dc9357SAndroid Build Coastguard Worker using namespace NWindows;
29*f6dc9357SAndroid Build Coastguard Worker 
30*f6dc9357SAndroid Build Coastguard Worker 
31*f6dc9357SAndroid Build Coastguard Worker EXTERN_C_BEGIN
32*f6dc9357SAndroid Build Coastguard Worker 
33*f6dc9357SAndroid Build Coastguard Worker // CRC-32C (Castagnoli) : reversed for poly 0x1EDC6F41
34*f6dc9357SAndroid Build Coastguard Worker #define k_Crc32c_Poly 0x82f63b78
35*f6dc9357SAndroid Build Coastguard Worker 
36*f6dc9357SAndroid Build Coastguard Worker MY_ALIGN(64)
37*f6dc9357SAndroid Build Coastguard Worker static UInt32 g_Crc32c_Table[256];
38*f6dc9357SAndroid Build Coastguard Worker 
Crc32c_GenerateTable()39*f6dc9357SAndroid Build Coastguard Worker static void Z7_FASTCALL Crc32c_GenerateTable()
40*f6dc9357SAndroid Build Coastguard Worker {
41*f6dc9357SAndroid Build Coastguard Worker   UInt32 i;
42*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < 256; i++)
43*f6dc9357SAndroid Build Coastguard Worker   {
44*f6dc9357SAndroid Build Coastguard Worker     UInt32 r = i;
45*f6dc9357SAndroid Build Coastguard Worker     unsigned j;
46*f6dc9357SAndroid Build Coastguard Worker     for (j = 0; j < 8; j++)
47*f6dc9357SAndroid Build Coastguard Worker       r = (r >> 1) ^ (k_Crc32c_Poly & ((UInt32)0 - (r & 1)));
48*f6dc9357SAndroid Build Coastguard Worker     g_Crc32c_Table[i] = r;
49*f6dc9357SAndroid Build Coastguard Worker   }
50*f6dc9357SAndroid Build Coastguard Worker }
51*f6dc9357SAndroid Build Coastguard Worker 
52*f6dc9357SAndroid Build Coastguard Worker 
53*f6dc9357SAndroid Build Coastguard Worker #define CRC32C_INIT_VAL 0xFFFFFFFF
54*f6dc9357SAndroid Build Coastguard Worker 
55*f6dc9357SAndroid Build Coastguard Worker #define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
56*f6dc9357SAndroid Build Coastguard Worker 
57*f6dc9357SAndroid Build Coastguard Worker // UInt32 Z7_FASTCALL CrcUpdateT1(UInt32 v, const void *data, size_t size, const UInt32 *table);
CrcUpdateT1_vhdx(UInt32 v,const void * data,size_t size,const UInt32 * table)58*f6dc9357SAndroid Build Coastguard Worker static UInt32 Z7_FASTCALL CrcUpdateT1_vhdx(UInt32 v, const void *data, size_t size, const UInt32 *table)
59*f6dc9357SAndroid Build Coastguard Worker {
60*f6dc9357SAndroid Build Coastguard Worker   const Byte *p = (const Byte *)data;
61*f6dc9357SAndroid Build Coastguard Worker   const Byte *pEnd = p + size;
62*f6dc9357SAndroid Build Coastguard Worker   for (; p != pEnd; p++)
63*f6dc9357SAndroid Build Coastguard Worker     v = CRC_UPDATE_BYTE_2(v, *p);
64*f6dc9357SAndroid Build Coastguard Worker   return v;
65*f6dc9357SAndroid Build Coastguard Worker }
66*f6dc9357SAndroid Build Coastguard Worker 
Crc32c_Calc(const void * data,size_t size)67*f6dc9357SAndroid Build Coastguard Worker static UInt32 Z7_FASTCALL Crc32c_Calc(const void *data, size_t size)
68*f6dc9357SAndroid Build Coastguard Worker {
69*f6dc9357SAndroid Build Coastguard Worker   return CrcUpdateT1_vhdx(CRC32C_INIT_VAL, data, size, g_Crc32c_Table) ^ CRC32C_INIT_VAL;
70*f6dc9357SAndroid Build Coastguard Worker }
71*f6dc9357SAndroid Build Coastguard Worker 
72*f6dc9357SAndroid Build Coastguard Worker EXTERN_C_END
73*f6dc9357SAndroid Build Coastguard Worker 
74*f6dc9357SAndroid Build Coastguard Worker 
75*f6dc9357SAndroid Build Coastguard Worker namespace NArchive {
76*f6dc9357SAndroid Build Coastguard Worker namespace NVhdx {
77*f6dc9357SAndroid Build Coastguard Worker 
C_CRC32c_TableInitNArchive::NVhdx::C_CRC32c_TableInit78*f6dc9357SAndroid Build Coastguard Worker static struct C_CRC32c_TableInit { C_CRC32c_TableInit() { Crc32c_GenerateTable(); } } g_CRC32c_TableInit;
79*f6dc9357SAndroid Build Coastguard Worker 
80*f6dc9357SAndroid Build Coastguard Worker static const unsigned kSignatureSize = 8;
81*f6dc9357SAndroid Build Coastguard Worker static const Byte kSignature[kSignatureSize] =
82*f6dc9357SAndroid Build Coastguard Worker   { 'v', 'h', 'd', 'x', 'f', 'i', 'l', 'e' };
83*f6dc9357SAndroid Build Coastguard Worker 
84*f6dc9357SAndroid Build Coastguard Worker static const unsigned kBitmapSize_Log = 20;
85*f6dc9357SAndroid Build Coastguard Worker static const size_t kBitmapSize = (size_t)1 << kBitmapSize_Log;
86*f6dc9357SAndroid Build Coastguard Worker 
87*f6dc9357SAndroid Build Coastguard Worker 
IsZeroArr(const Byte * p,size_t size)88*f6dc9357SAndroid Build Coastguard Worker static bool IsZeroArr(const Byte *p, size_t size)
89*f6dc9357SAndroid Build Coastguard Worker {
90*f6dc9357SAndroid Build Coastguard Worker   for (size_t i = 0; i < size; i++)
91*f6dc9357SAndroid Build Coastguard Worker     if (p[i] != 0)
92*f6dc9357SAndroid Build Coastguard Worker       return false;
93*f6dc9357SAndroid Build Coastguard Worker   return true;
94*f6dc9357SAndroid Build Coastguard Worker }
95*f6dc9357SAndroid Build Coastguard Worker 
96*f6dc9357SAndroid Build Coastguard Worker 
97*f6dc9357SAndroid Build Coastguard Worker 
98*f6dc9357SAndroid Build Coastguard Worker Z7_FORCE_INLINE
DecodeFrom2HexChars(const wchar_t * s)99*f6dc9357SAndroid Build Coastguard Worker static int DecodeFrom2HexChars(const wchar_t *s)
100*f6dc9357SAndroid Build Coastguard Worker {
101*f6dc9357SAndroid Build Coastguard Worker   unsigned v0 = (unsigned)s[0];  Z7_PARSE_HEX_DIGIT(v0, return -1;)
102*f6dc9357SAndroid Build Coastguard Worker   unsigned v1 = (unsigned)s[1];  Z7_PARSE_HEX_DIGIT(v1, return -1;)
103*f6dc9357SAndroid Build Coastguard Worker   return (int)((v0 << 4) | v1);
104*f6dc9357SAndroid Build Coastguard Worker }
105*f6dc9357SAndroid Build Coastguard Worker 
106*f6dc9357SAndroid Build Coastguard Worker 
107*f6dc9357SAndroid Build Coastguard Worker struct CGuid
108*f6dc9357SAndroid Build Coastguard Worker {
109*f6dc9357SAndroid Build Coastguard Worker   Byte Data[16];
110*f6dc9357SAndroid Build Coastguard Worker 
IsZeroNArchive::NVhdx::CGuid111*f6dc9357SAndroid Build Coastguard Worker   bool IsZero() const { return IsZeroArr(Data, 16); }
IsEqualToNArchive::NVhdx::CGuid112*f6dc9357SAndroid Build Coastguard Worker   bool IsEqualTo(const Byte *a) const { return memcmp(Data, a, 16) == 0; }
IsEqualToNArchive::NVhdx::CGuid113*f6dc9357SAndroid Build Coastguard Worker   bool IsEqualTo(const CGuid &g) const { return IsEqualTo(g.Data); }
114*f6dc9357SAndroid Build Coastguard Worker   void AddHexToString(UString &s) const;
115*f6dc9357SAndroid Build Coastguard Worker 
SetFromNArchive::NVhdx::CGuid116*f6dc9357SAndroid Build Coastguard Worker   void SetFrom(const Byte *p) { memcpy(Data, p, 16); }
117*f6dc9357SAndroid Build Coastguard Worker 
ParseFromFormatedHexStringNArchive::NVhdx::CGuid118*f6dc9357SAndroid Build Coastguard Worker   bool ParseFromFormatedHexString(const UString &s)
119*f6dc9357SAndroid Build Coastguard Worker   {
120*f6dc9357SAndroid Build Coastguard Worker     const unsigned kLen = 16 * 2 + 4 + 2;
121*f6dc9357SAndroid Build Coastguard Worker     if (s.Len() != kLen || s[0] != '{' || s[kLen - 1] != '}')
122*f6dc9357SAndroid Build Coastguard Worker       return false;
123*f6dc9357SAndroid Build Coastguard Worker     unsigned pos = 0;
124*f6dc9357SAndroid Build Coastguard Worker     for (unsigned i = 1; i < kLen - 1;)
125*f6dc9357SAndroid Build Coastguard Worker     {
126*f6dc9357SAndroid Build Coastguard Worker       if (i == 9 || i == 14 || i == 19 || i == 24)
127*f6dc9357SAndroid Build Coastguard Worker       {
128*f6dc9357SAndroid Build Coastguard Worker         if (s[i] != '-')
129*f6dc9357SAndroid Build Coastguard Worker           return false;
130*f6dc9357SAndroid Build Coastguard Worker         i++;
131*f6dc9357SAndroid Build Coastguard Worker         continue;
132*f6dc9357SAndroid Build Coastguard Worker       }
133*f6dc9357SAndroid Build Coastguard Worker       const int v = DecodeFrom2HexChars(s.Ptr(i));
134*f6dc9357SAndroid Build Coastguard Worker       if (v < 0)
135*f6dc9357SAndroid Build Coastguard Worker         return false;
136*f6dc9357SAndroid Build Coastguard Worker       unsigned pos2 = pos;
137*f6dc9357SAndroid Build Coastguard Worker       if (pos < 8)
138*f6dc9357SAndroid Build Coastguard Worker         pos2 ^= (pos < 4 ? 3 : 1);
139*f6dc9357SAndroid Build Coastguard Worker       Data[pos2] = (Byte)v;
140*f6dc9357SAndroid Build Coastguard Worker       pos++;
141*f6dc9357SAndroid Build Coastguard Worker       i += 2;
142*f6dc9357SAndroid Build Coastguard Worker     }
143*f6dc9357SAndroid Build Coastguard Worker     return true; // pos == 16;
144*f6dc9357SAndroid Build Coastguard Worker   }
145*f6dc9357SAndroid Build Coastguard Worker };
146*f6dc9357SAndroid Build Coastguard Worker 
AddHexToString(UString & s) const147*f6dc9357SAndroid Build Coastguard Worker void CGuid::AddHexToString(UString &s) const
148*f6dc9357SAndroid Build Coastguard Worker {
149*f6dc9357SAndroid Build Coastguard Worker   char temp[sizeof(Data) * 2 + 2];
150*f6dc9357SAndroid Build Coastguard Worker   ConvertDataToHex_Lower(temp, Data, sizeof(Data));
151*f6dc9357SAndroid Build Coastguard Worker   s += temp;
152*f6dc9357SAndroid Build Coastguard Worker }
153*f6dc9357SAndroid Build Coastguard Worker 
154*f6dc9357SAndroid Build Coastguard Worker 
155*f6dc9357SAndroid Build Coastguard Worker #define IS_NON_ALIGNED(v) (((v) & 0xFFFFF) != 0)
156*f6dc9357SAndroid Build Coastguard Worker 
157*f6dc9357SAndroid Build Coastguard Worker static const unsigned kHeader_GUID_Index_FileWriteGuid = 0;
158*f6dc9357SAndroid Build Coastguard Worker static const unsigned kHeader_GUID_Index_DataWriteGuid = 1;
159*f6dc9357SAndroid Build Coastguard Worker static const unsigned kHeader_GUID_Index_LogGuid = 2;
160*f6dc9357SAndroid Build Coastguard Worker 
161*f6dc9357SAndroid Build Coastguard Worker struct CHeader
162*f6dc9357SAndroid Build Coastguard Worker {
163*f6dc9357SAndroid Build Coastguard Worker   UInt64 SequenceNumber;
164*f6dc9357SAndroid Build Coastguard Worker   // UInt16 LogVersion;
165*f6dc9357SAndroid Build Coastguard Worker   // UInt16 Version;
166*f6dc9357SAndroid Build Coastguard Worker   UInt32 LogLength;
167*f6dc9357SAndroid Build Coastguard Worker   UInt64 LogOffset;
168*f6dc9357SAndroid Build Coastguard Worker   CGuid Guids[3];
169*f6dc9357SAndroid Build Coastguard Worker 
IsEqualToNArchive::NVhdx::CHeader170*f6dc9357SAndroid Build Coastguard Worker   bool IsEqualTo(const CHeader &h) const
171*f6dc9357SAndroid Build Coastguard Worker   {
172*f6dc9357SAndroid Build Coastguard Worker     if (SequenceNumber != h.SequenceNumber)
173*f6dc9357SAndroid Build Coastguard Worker       return false;
174*f6dc9357SAndroid Build Coastguard Worker     if (LogLength != h.LogLength)
175*f6dc9357SAndroid Build Coastguard Worker       return false;
176*f6dc9357SAndroid Build Coastguard Worker     if (LogOffset != h.LogOffset)
177*f6dc9357SAndroid Build Coastguard Worker       return false;
178*f6dc9357SAndroid Build Coastguard Worker     for (unsigned i = 0; i < 3; i++)
179*f6dc9357SAndroid Build Coastguard Worker       if (!Guids[i].IsEqualTo(h.Guids[i]))
180*f6dc9357SAndroid Build Coastguard Worker         return false;
181*f6dc9357SAndroid Build Coastguard Worker     return true;
182*f6dc9357SAndroid Build Coastguard Worker   }
183*f6dc9357SAndroid Build Coastguard Worker 
184*f6dc9357SAndroid Build Coastguard Worker   bool Parse(Byte *p);
185*f6dc9357SAndroid Build Coastguard Worker };
186*f6dc9357SAndroid Build Coastguard Worker 
187*f6dc9357SAndroid Build Coastguard Worker static const unsigned kHeader2Size = 1 << 12;
188*f6dc9357SAndroid Build Coastguard Worker 
Parse(Byte * p)189*f6dc9357SAndroid Build Coastguard Worker bool CHeader::Parse(Byte *p)
190*f6dc9357SAndroid Build Coastguard Worker {
191*f6dc9357SAndroid Build Coastguard Worker   if (Get32(p) != 0x64616568) // "head"
192*f6dc9357SAndroid Build Coastguard Worker     return false;
193*f6dc9357SAndroid Build Coastguard Worker   const UInt32 crc = Get32(p + 4);
194*f6dc9357SAndroid Build Coastguard Worker   SetUi32(p + 4, 0)
195*f6dc9357SAndroid Build Coastguard Worker   if (Crc32c_Calc(p, kHeader2Size) != crc)
196*f6dc9357SAndroid Build Coastguard Worker     return false;
197*f6dc9357SAndroid Build Coastguard Worker   G64(8, SequenceNumber);
198*f6dc9357SAndroid Build Coastguard Worker   for (unsigned i = 0; i < 3; i++)
199*f6dc9357SAndroid Build Coastguard Worker     Guids[i].SetFrom(p + 0x10 + 0x10 * i);
200*f6dc9357SAndroid Build Coastguard Worker   // LogVersion = Get16(p + 0x40);
201*f6dc9357SAndroid Build Coastguard Worker   /* LogVersion MUST be set to zero, for known log format
202*f6dc9357SAndroid Build Coastguard Worker      but we don't parse log so we ignore it */
203*f6dc9357SAndroid Build Coastguard Worker   G32(0x44, LogLength);
204*f6dc9357SAndroid Build Coastguard Worker   G64(0x48, LogOffset);
205*f6dc9357SAndroid Build Coastguard Worker   if (Get16(p + 0x42) != 1) // Header format Version
206*f6dc9357SAndroid Build Coastguard Worker     return false;
207*f6dc9357SAndroid Build Coastguard Worker   if (IS_NON_ALIGNED(LogLength))
208*f6dc9357SAndroid Build Coastguard Worker     return false;
209*f6dc9357SAndroid Build Coastguard Worker   if (IS_NON_ALIGNED(LogOffset))
210*f6dc9357SAndroid Build Coastguard Worker     return false;
211*f6dc9357SAndroid Build Coastguard Worker   return true;
212*f6dc9357SAndroid Build Coastguard Worker   // return IsZeroArr(p + 0x50, kHeader2Size - 0x50);
213*f6dc9357SAndroid Build Coastguard Worker }
214*f6dc9357SAndroid Build Coastguard Worker 
215*f6dc9357SAndroid Build Coastguard Worker 
216*f6dc9357SAndroid Build Coastguard Worker 
217*f6dc9357SAndroid Build Coastguard Worker static const Byte kBat[16] =
218*f6dc9357SAndroid Build Coastguard Worker   { 0x66,0x77,0xC2,0x2D,0x23,0xF6,0x00,0x42,0x9D,0x64,0x11,0x5E,0x9B,0xFD,0x4A,0x08 };
219*f6dc9357SAndroid Build Coastguard Worker static const Byte kMetadataRegion[16] =
220*f6dc9357SAndroid Build Coastguard Worker   { 0x06,0xA2,0x7C,0x8B,0x90,0x47,0x9A,0x4B,0xB8,0xFE,0x57,0x5F,0x05,0x0F,0x88,0x6E };
221*f6dc9357SAndroid Build Coastguard Worker 
222*f6dc9357SAndroid Build Coastguard Worker struct CRegionEntry
223*f6dc9357SAndroid Build Coastguard Worker {
224*f6dc9357SAndroid Build Coastguard Worker   // CGuid Guid;
225*f6dc9357SAndroid Build Coastguard Worker   UInt64 Offset;
226*f6dc9357SAndroid Build Coastguard Worker   UInt32 Len;
227*f6dc9357SAndroid Build Coastguard Worker   UInt32 Required;
228*f6dc9357SAndroid Build Coastguard Worker 
GetEndPosNArchive::NVhdx::CRegionEntry229*f6dc9357SAndroid Build Coastguard Worker   UInt64 GetEndPos() const { return Offset + Len; }
230*f6dc9357SAndroid Build Coastguard Worker   bool Parse(const Byte *p);
231*f6dc9357SAndroid Build Coastguard Worker };
232*f6dc9357SAndroid Build Coastguard Worker 
Parse(const Byte * p)233*f6dc9357SAndroid Build Coastguard Worker bool CRegionEntry::Parse(const Byte *p)
234*f6dc9357SAndroid Build Coastguard Worker {
235*f6dc9357SAndroid Build Coastguard Worker   // Guid.SetFrom(p);
236*f6dc9357SAndroid Build Coastguard Worker   G64(0x10, Offset);
237*f6dc9357SAndroid Build Coastguard Worker   G32(0x18, Len);
238*f6dc9357SAndroid Build Coastguard Worker   G32(0x1c, Required);
239*f6dc9357SAndroid Build Coastguard Worker   if (IS_NON_ALIGNED(Offset))
240*f6dc9357SAndroid Build Coastguard Worker     return false;
241*f6dc9357SAndroid Build Coastguard Worker   if (IS_NON_ALIGNED(Len))
242*f6dc9357SAndroid Build Coastguard Worker     return false;
243*f6dc9357SAndroid Build Coastguard Worker   if (Offset + Len < Offset)
244*f6dc9357SAndroid Build Coastguard Worker     return false;
245*f6dc9357SAndroid Build Coastguard Worker   return true;
246*f6dc9357SAndroid Build Coastguard Worker }
247*f6dc9357SAndroid Build Coastguard Worker 
248*f6dc9357SAndroid Build Coastguard Worker 
249*f6dc9357SAndroid Build Coastguard Worker struct CRegion
250*f6dc9357SAndroid Build Coastguard Worker {
251*f6dc9357SAndroid Build Coastguard Worker   bool Bat_Defined;
252*f6dc9357SAndroid Build Coastguard Worker   bool Meta_Defined;
253*f6dc9357SAndroid Build Coastguard Worker   UInt64 EndPos;
254*f6dc9357SAndroid Build Coastguard Worker   UInt64 DataSize;
255*f6dc9357SAndroid Build Coastguard Worker 
256*f6dc9357SAndroid Build Coastguard Worker   CRegionEntry BatEntry;
257*f6dc9357SAndroid Build Coastguard Worker   CRegionEntry MetaEntry;
258*f6dc9357SAndroid Build Coastguard Worker 
259*f6dc9357SAndroid Build Coastguard Worker   bool Parse(Byte *p);
260*f6dc9357SAndroid Build Coastguard Worker };
261*f6dc9357SAndroid Build Coastguard Worker 
262*f6dc9357SAndroid Build Coastguard Worker 
263*f6dc9357SAndroid Build Coastguard Worker static const size_t kRegionSize = 1 << 16;
264*f6dc9357SAndroid Build Coastguard Worker static const unsigned kNumRegionEntriesMax = (1 << 11) - 1;
265*f6dc9357SAndroid Build Coastguard Worker 
Parse(Byte * p)266*f6dc9357SAndroid Build Coastguard Worker bool CRegion::Parse(Byte *p)
267*f6dc9357SAndroid Build Coastguard Worker {
268*f6dc9357SAndroid Build Coastguard Worker   Bat_Defined = false;
269*f6dc9357SAndroid Build Coastguard Worker   Meta_Defined = false;
270*f6dc9357SAndroid Build Coastguard Worker   EndPos = 0;
271*f6dc9357SAndroid Build Coastguard Worker   DataSize = 0;
272*f6dc9357SAndroid Build Coastguard Worker 
273*f6dc9357SAndroid Build Coastguard Worker   if (Get32(p) != 0x69676572) // "regi"
274*f6dc9357SAndroid Build Coastguard Worker     return false;
275*f6dc9357SAndroid Build Coastguard Worker   const UInt32 crc = Get32(p + 4);
276*f6dc9357SAndroid Build Coastguard Worker   SetUi32(p + 4, 0)
277*f6dc9357SAndroid Build Coastguard Worker   const UInt32 crc_calced = Crc32c_Calc(p, kRegionSize);
278*f6dc9357SAndroid Build Coastguard Worker   if (crc_calced != crc)
279*f6dc9357SAndroid Build Coastguard Worker     return false;
280*f6dc9357SAndroid Build Coastguard Worker 
281*f6dc9357SAndroid Build Coastguard Worker   const UInt32 EntryCount = Get32(p + 8);
282*f6dc9357SAndroid Build Coastguard Worker   if (Get32(p + 12) != 0) // reserved field must be set to 0.
283*f6dc9357SAndroid Build Coastguard Worker     return false;
284*f6dc9357SAndroid Build Coastguard Worker   if (EntryCount > kNumRegionEntriesMax)
285*f6dc9357SAndroid Build Coastguard Worker     return false;
286*f6dc9357SAndroid Build Coastguard Worker   for (UInt32 i = 0; i < EntryCount; i++)
287*f6dc9357SAndroid Build Coastguard Worker   {
288*f6dc9357SAndroid Build Coastguard Worker     CRegionEntry e;
289*f6dc9357SAndroid Build Coastguard Worker     const Byte *p2 = p + 0x10 + 0x20 * (size_t)i;
290*f6dc9357SAndroid Build Coastguard Worker     if (!e.Parse(p2))
291*f6dc9357SAndroid Build Coastguard Worker       return false;
292*f6dc9357SAndroid Build Coastguard Worker     DataSize += e.Len;
293*f6dc9357SAndroid Build Coastguard Worker     const UInt64 endPos = e.GetEndPos();
294*f6dc9357SAndroid Build Coastguard Worker     if (EndPos < endPos)
295*f6dc9357SAndroid Build Coastguard Worker       EndPos = endPos;
296*f6dc9357SAndroid Build Coastguard Worker     CGuid Guid;
297*f6dc9357SAndroid Build Coastguard Worker     Guid.SetFrom(p2);
298*f6dc9357SAndroid Build Coastguard Worker     if (Guid.IsEqualTo(kBat))
299*f6dc9357SAndroid Build Coastguard Worker     {
300*f6dc9357SAndroid Build Coastguard Worker       if (Bat_Defined)
301*f6dc9357SAndroid Build Coastguard Worker         return false;
302*f6dc9357SAndroid Build Coastguard Worker       BatEntry = e;
303*f6dc9357SAndroid Build Coastguard Worker       Bat_Defined = true;
304*f6dc9357SAndroid Build Coastguard Worker     }
305*f6dc9357SAndroid Build Coastguard Worker     else if (Guid.IsEqualTo(kMetadataRegion))
306*f6dc9357SAndroid Build Coastguard Worker     {
307*f6dc9357SAndroid Build Coastguard Worker       if (Meta_Defined)
308*f6dc9357SAndroid Build Coastguard Worker         return false;
309*f6dc9357SAndroid Build Coastguard Worker       MetaEntry = e;
310*f6dc9357SAndroid Build Coastguard Worker       Meta_Defined = true;
311*f6dc9357SAndroid Build Coastguard Worker     }
312*f6dc9357SAndroid Build Coastguard Worker     else
313*f6dc9357SAndroid Build Coastguard Worker     {
314*f6dc9357SAndroid Build Coastguard Worker       if (e.Required != 0)
315*f6dc9357SAndroid Build Coastguard Worker         return false;
316*f6dc9357SAndroid Build Coastguard Worker       // it's allowed to ignore unknown non-required region entries
317*f6dc9357SAndroid Build Coastguard Worker     }
318*f6dc9357SAndroid Build Coastguard Worker   }
319*f6dc9357SAndroid Build Coastguard Worker   /*
320*f6dc9357SAndroid Build Coastguard Worker   const size_t k = 0x10 + 0x20 * EntryCount;
321*f6dc9357SAndroid Build Coastguard Worker   return IsZeroArr(p + k, kRegionSize - k);
322*f6dc9357SAndroid Build Coastguard Worker   */
323*f6dc9357SAndroid Build Coastguard Worker   return true;
324*f6dc9357SAndroid Build Coastguard Worker }
325*f6dc9357SAndroid Build Coastguard Worker 
326*f6dc9357SAndroid Build Coastguard Worker 
327*f6dc9357SAndroid Build Coastguard Worker 
328*f6dc9357SAndroid Build Coastguard Worker 
329*f6dc9357SAndroid Build Coastguard Worker struct CMetaEntry
330*f6dc9357SAndroid Build Coastguard Worker {
331*f6dc9357SAndroid Build Coastguard Worker   CGuid Guid;
332*f6dc9357SAndroid Build Coastguard Worker   UInt32 Offset;
333*f6dc9357SAndroid Build Coastguard Worker   UInt32 Len;
334*f6dc9357SAndroid Build Coastguard Worker   UInt32 Flags0;
335*f6dc9357SAndroid Build Coastguard Worker   // UInt32 Flags1;
336*f6dc9357SAndroid Build Coastguard Worker 
IsUserNArchive::NVhdx::CMetaEntry337*f6dc9357SAndroid Build Coastguard Worker   bool IsUser()        const { return (Flags0 & 1) != 0; }
IsVirtualDiskNArchive::NVhdx::CMetaEntry338*f6dc9357SAndroid Build Coastguard Worker   bool IsVirtualDisk() const { return (Flags0 & 2) != 0; }
IsRequiredNArchive::NVhdx::CMetaEntry339*f6dc9357SAndroid Build Coastguard Worker   bool IsRequired()    const { return (Flags0 & 4) != 0; }
340*f6dc9357SAndroid Build Coastguard Worker 
CheckLimitNArchive::NVhdx::CMetaEntry341*f6dc9357SAndroid Build Coastguard Worker   bool CheckLimit(size_t regionSize) const
342*f6dc9357SAndroid Build Coastguard Worker   {
343*f6dc9357SAndroid Build Coastguard Worker     return Offset <= regionSize && Len <= regionSize - Offset;
344*f6dc9357SAndroid Build Coastguard Worker   }
345*f6dc9357SAndroid Build Coastguard Worker 
346*f6dc9357SAndroid Build Coastguard Worker   bool Parse(const Byte *p);
347*f6dc9357SAndroid Build Coastguard Worker };
348*f6dc9357SAndroid Build Coastguard Worker 
349*f6dc9357SAndroid Build Coastguard Worker 
Parse(const Byte * p)350*f6dc9357SAndroid Build Coastguard Worker bool CMetaEntry::Parse(const Byte *p)
351*f6dc9357SAndroid Build Coastguard Worker {
352*f6dc9357SAndroid Build Coastguard Worker   Guid.SetFrom(p);
353*f6dc9357SAndroid Build Coastguard Worker 
354*f6dc9357SAndroid Build Coastguard Worker   G32(0x10, Offset);
355*f6dc9357SAndroid Build Coastguard Worker   G32(0x14, Len);
356*f6dc9357SAndroid Build Coastguard Worker   G32(0x18, Flags0);
357*f6dc9357SAndroid Build Coastguard Worker   UInt32 Flags1;
358*f6dc9357SAndroid Build Coastguard Worker   G32(0x1C, Flags1);
359*f6dc9357SAndroid Build Coastguard Worker 
360*f6dc9357SAndroid Build Coastguard Worker   if (Offset != 0 && Offset < (1 << 16))
361*f6dc9357SAndroid Build Coastguard Worker     return false;
362*f6dc9357SAndroid Build Coastguard Worker   if (Len > (1 << 20))
363*f6dc9357SAndroid Build Coastguard Worker     return false;
364*f6dc9357SAndroid Build Coastguard Worker   if (Len == 0 && Offset != 0)
365*f6dc9357SAndroid Build Coastguard Worker     return false;
366*f6dc9357SAndroid Build Coastguard Worker   if ((Flags0 >> 3) != 0) // Reserved
367*f6dc9357SAndroid Build Coastguard Worker     return false;
368*f6dc9357SAndroid Build Coastguard Worker   if ((Flags1 & 3) != 0) // Reserved2
369*f6dc9357SAndroid Build Coastguard Worker     return false;
370*f6dc9357SAndroid Build Coastguard Worker   return true;
371*f6dc9357SAndroid Build Coastguard Worker }
372*f6dc9357SAndroid Build Coastguard Worker 
373*f6dc9357SAndroid Build Coastguard Worker 
374*f6dc9357SAndroid Build Coastguard Worker struct CParentPair
375*f6dc9357SAndroid Build Coastguard Worker {
376*f6dc9357SAndroid Build Coastguard Worker   UString Key;
377*f6dc9357SAndroid Build Coastguard Worker   UString Value;
378*f6dc9357SAndroid Build Coastguard Worker };
379*f6dc9357SAndroid Build Coastguard Worker 
380*f6dc9357SAndroid Build Coastguard Worker 
381*f6dc9357SAndroid Build Coastguard Worker struct CMetaHeader
382*f6dc9357SAndroid Build Coastguard Worker {
383*f6dc9357SAndroid Build Coastguard Worker   // UInt16 EntryCount;
384*f6dc9357SAndroid Build Coastguard Worker   bool Guid_Defined;
385*f6dc9357SAndroid Build Coastguard Worker   bool VirtualDiskSize_Defined;
386*f6dc9357SAndroid Build Coastguard Worker   bool Locator_Defined;
387*f6dc9357SAndroid Build Coastguard Worker 
388*f6dc9357SAndroid Build Coastguard Worker   unsigned BlockSize_Log;
389*f6dc9357SAndroid Build Coastguard Worker   unsigned LogicalSectorSize_Log;
390*f6dc9357SAndroid Build Coastguard Worker   unsigned PhysicalSectorSize_Log;
391*f6dc9357SAndroid Build Coastguard Worker 
392*f6dc9357SAndroid Build Coastguard Worker   UInt32 Flags;
393*f6dc9357SAndroid Build Coastguard Worker   UInt64 VirtualDiskSize;
394*f6dc9357SAndroid Build Coastguard Worker   CGuid Guid;
395*f6dc9357SAndroid Build Coastguard Worker   // CGuid LocatorType;
396*f6dc9357SAndroid Build Coastguard Worker 
397*f6dc9357SAndroid Build Coastguard Worker   CObjectVector<CParentPair> ParentPairs;
398*f6dc9357SAndroid Build Coastguard Worker 
FindParentKeyNArchive::NVhdx::CMetaHeader399*f6dc9357SAndroid Build Coastguard Worker   int FindParentKey(const char *name) const
400*f6dc9357SAndroid Build Coastguard Worker   {
401*f6dc9357SAndroid Build Coastguard Worker     FOR_VECTOR (i, ParentPairs)
402*f6dc9357SAndroid Build Coastguard Worker     {
403*f6dc9357SAndroid Build Coastguard Worker       const CParentPair &pair = ParentPairs[i];
404*f6dc9357SAndroid Build Coastguard Worker       if (pair.Key.IsEqualTo(name))
405*f6dc9357SAndroid Build Coastguard Worker         return (int)i;
406*f6dc9357SAndroid Build Coastguard Worker     }
407*f6dc9357SAndroid Build Coastguard Worker     return -1;
408*f6dc9357SAndroid Build Coastguard Worker   }
409*f6dc9357SAndroid Build Coastguard Worker 
Is_LeaveBlockAllocatedNArchive::NVhdx::CMetaHeader410*f6dc9357SAndroid Build Coastguard Worker   bool Is_LeaveBlockAllocated() const { return (Flags & 1) != 0; }
Is_HasParentNArchive::NVhdx::CMetaHeader411*f6dc9357SAndroid Build Coastguard Worker   bool Is_HasParent() const { return (Flags & 2) != 0; }
412*f6dc9357SAndroid Build Coastguard Worker 
ClearNArchive::NVhdx::CMetaHeader413*f6dc9357SAndroid Build Coastguard Worker   void Clear()
414*f6dc9357SAndroid Build Coastguard Worker   {
415*f6dc9357SAndroid Build Coastguard Worker     Guid_Defined = false;
416*f6dc9357SAndroid Build Coastguard Worker     VirtualDiskSize_Defined = false;
417*f6dc9357SAndroid Build Coastguard Worker     Locator_Defined = false;
418*f6dc9357SAndroid Build Coastguard Worker     BlockSize_Log = 0;
419*f6dc9357SAndroid Build Coastguard Worker     LogicalSectorSize_Log = 0;
420*f6dc9357SAndroid Build Coastguard Worker     PhysicalSectorSize_Log = 0;
421*f6dc9357SAndroid Build Coastguard Worker     Flags = 0;
422*f6dc9357SAndroid Build Coastguard Worker     VirtualDiskSize = 0;
423*f6dc9357SAndroid Build Coastguard Worker     ParentPairs.Clear();
424*f6dc9357SAndroid Build Coastguard Worker   }
425*f6dc9357SAndroid Build Coastguard Worker 
426*f6dc9357SAndroid Build Coastguard Worker   bool Parse(const Byte *p, size_t size);
427*f6dc9357SAndroid Build Coastguard Worker };
428*f6dc9357SAndroid Build Coastguard Worker 
429*f6dc9357SAndroid Build Coastguard Worker 
GetLogSize(UInt32 size)430*f6dc9357SAndroid Build Coastguard Worker static unsigned GetLogSize(UInt32 size)
431*f6dc9357SAndroid Build Coastguard Worker {
432*f6dc9357SAndroid Build Coastguard Worker   unsigned k;
433*f6dc9357SAndroid Build Coastguard Worker   for (k = 0; k < 32; k++)
434*f6dc9357SAndroid Build Coastguard Worker     if (((UInt32)1 << k) == size)
435*f6dc9357SAndroid Build Coastguard Worker       return k;
436*f6dc9357SAndroid Build Coastguard Worker   return k;
437*f6dc9357SAndroid Build Coastguard Worker }
438*f6dc9357SAndroid Build Coastguard Worker 
439*f6dc9357SAndroid Build Coastguard Worker 
440*f6dc9357SAndroid Build Coastguard Worker static const unsigned kMetadataSize = 8;
441*f6dc9357SAndroid Build Coastguard Worker static const Byte kMetadata[kMetadataSize] =
442*f6dc9357SAndroid Build Coastguard Worker   { 'm','e','t','a','d','a','t','a' };
443*f6dc9357SAndroid Build Coastguard Worker 
444*f6dc9357SAndroid Build Coastguard Worker static const unsigned k_Num_MetaEntries_Max = (1 << 11) - 1;
445*f6dc9357SAndroid Build Coastguard Worker 
446*f6dc9357SAndroid Build Coastguard Worker static const Byte kFileParameters[16] =
447*f6dc9357SAndroid Build Coastguard Worker   { 0x37,0x67,0xa1,0xca,0x36,0xfa,0x43,0x4d,0xb3,0xb6,0x33,0xf0,0xaa,0x44,0xe7,0x6b };
448*f6dc9357SAndroid Build Coastguard Worker static const Byte kVirtualDiskSize[16] =
449*f6dc9357SAndroid Build Coastguard Worker   { 0x24,0x42,0xa5,0x2f,0x1b,0xcd,0x76,0x48,0xb2,0x11,0x5d,0xbe,0xd8,0x3b,0xf4,0xb8 };
450*f6dc9357SAndroid Build Coastguard Worker static const Byte kVirtualDiskID[16] =
451*f6dc9357SAndroid Build Coastguard Worker   { 0xab,0x12,0xca,0xbe,0xe6,0xb2,0x23,0x45,0x93,0xef,0xc3,0x09,0xe0,0x00,0xc7,0x46 };
452*f6dc9357SAndroid Build Coastguard Worker static const Byte kLogicalSectorSize[16] =
453*f6dc9357SAndroid Build Coastguard Worker   { 0x1d,0xbf,0x41,0x81,0x6f,0xa9,0x09,0x47,0xba,0x47,0xf2,0x33,0xa8,0xfa,0xab,0x5f };
454*f6dc9357SAndroid Build Coastguard Worker static const Byte kPhysicalSectorSize[16] =
455*f6dc9357SAndroid Build Coastguard Worker   { 0xc7,0x48,0xa3,0xcd,0x5d,0x44,0x71,0x44,0x9c,0xc9,0xe9,0x88,0x52,0x51,0xc5,0x56 };
456*f6dc9357SAndroid Build Coastguard Worker static const Byte kParentLocator[16] =
457*f6dc9357SAndroid Build Coastguard Worker   { 0x2d,0x5f,0xd3,0xa8,0x0b,0xb3,0x4d,0x45,0xab,0xf7,0xd3,0xd8,0x48,0x34,0xab,0x0c };
458*f6dc9357SAndroid Build Coastguard Worker 
GetString16(UString & s,const Byte * p,size_t size)459*f6dc9357SAndroid Build Coastguard Worker static bool GetString16(UString &s, const Byte *p, size_t size)
460*f6dc9357SAndroid Build Coastguard Worker {
461*f6dc9357SAndroid Build Coastguard Worker   s.Empty();
462*f6dc9357SAndroid Build Coastguard Worker   if (size & 1)
463*f6dc9357SAndroid Build Coastguard Worker     return false;
464*f6dc9357SAndroid Build Coastguard Worker   for (size_t i = 0; i < size; i += 2)
465*f6dc9357SAndroid Build Coastguard Worker   {
466*f6dc9357SAndroid Build Coastguard Worker     const wchar_t c = Get16(p + i);
467*f6dc9357SAndroid Build Coastguard Worker     if (c == 0)
468*f6dc9357SAndroid Build Coastguard Worker       return false;
469*f6dc9357SAndroid Build Coastguard Worker     s += c;
470*f6dc9357SAndroid Build Coastguard Worker   }
471*f6dc9357SAndroid Build Coastguard Worker   return true;
472*f6dc9357SAndroid Build Coastguard Worker }
473*f6dc9357SAndroid Build Coastguard Worker 
474*f6dc9357SAndroid Build Coastguard Worker 
Parse(const Byte * p,size_t size)475*f6dc9357SAndroid Build Coastguard Worker bool CMetaHeader::Parse(const Byte *p, size_t size)
476*f6dc9357SAndroid Build Coastguard Worker {
477*f6dc9357SAndroid Build Coastguard Worker   if (memcmp(p, kMetadata, kMetadataSize) != 0)
478*f6dc9357SAndroid Build Coastguard Worker     return false;
479*f6dc9357SAndroid Build Coastguard Worker   if (Get16(p + 8) != 0) // Reserved
480*f6dc9357SAndroid Build Coastguard Worker     return false;
481*f6dc9357SAndroid Build Coastguard Worker   const UInt32 EntryCount = Get16(p + 10);
482*f6dc9357SAndroid Build Coastguard Worker   if (EntryCount > k_Num_MetaEntries_Max)
483*f6dc9357SAndroid Build Coastguard Worker     return false;
484*f6dc9357SAndroid Build Coastguard Worker   if (!IsZeroArr(p + 12, 20)) // Reserved
485*f6dc9357SAndroid Build Coastguard Worker     return false;
486*f6dc9357SAndroid Build Coastguard Worker 
487*f6dc9357SAndroid Build Coastguard Worker   for (unsigned i = 0; i < EntryCount; i++)
488*f6dc9357SAndroid Build Coastguard Worker   {
489*f6dc9357SAndroid Build Coastguard Worker     CMetaEntry e;
490*f6dc9357SAndroid Build Coastguard Worker     if (!e.Parse(p + 32 + 32 * (size_t)i))
491*f6dc9357SAndroid Build Coastguard Worker       return false;
492*f6dc9357SAndroid Build Coastguard Worker     if (!e.CheckLimit(size))
493*f6dc9357SAndroid Build Coastguard Worker       return false;
494*f6dc9357SAndroid Build Coastguard Worker     const Byte *p2 = p + e.Offset;
495*f6dc9357SAndroid Build Coastguard Worker 
496*f6dc9357SAndroid Build Coastguard Worker     if (e.Guid.IsEqualTo(kFileParameters))
497*f6dc9357SAndroid Build Coastguard Worker     {
498*f6dc9357SAndroid Build Coastguard Worker       if (BlockSize_Log != 0)
499*f6dc9357SAndroid Build Coastguard Worker         return false;
500*f6dc9357SAndroid Build Coastguard Worker       if (e.Len != 8)
501*f6dc9357SAndroid Build Coastguard Worker         return false;
502*f6dc9357SAndroid Build Coastguard Worker       const UInt32 v = Get32(p2);
503*f6dc9357SAndroid Build Coastguard Worker       Flags = Get32(p2 + 4);
504*f6dc9357SAndroid Build Coastguard Worker       BlockSize_Log = GetLogSize(v);
505*f6dc9357SAndroid Build Coastguard Worker       if (BlockSize_Log < 20 || BlockSize_Log > 28) // specification from 1 MB to 256 MB
506*f6dc9357SAndroid Build Coastguard Worker         return false;
507*f6dc9357SAndroid Build Coastguard Worker       if ((Flags >> 2) != 0) // reserved
508*f6dc9357SAndroid Build Coastguard Worker         return false;
509*f6dc9357SAndroid Build Coastguard Worker     }
510*f6dc9357SAndroid Build Coastguard Worker     else if (e.Guid.IsEqualTo(kVirtualDiskSize))
511*f6dc9357SAndroid Build Coastguard Worker     {
512*f6dc9357SAndroid Build Coastguard Worker       if (VirtualDiskSize_Defined)
513*f6dc9357SAndroid Build Coastguard Worker         return false;
514*f6dc9357SAndroid Build Coastguard Worker       if (e.Len != 8)
515*f6dc9357SAndroid Build Coastguard Worker         return false;
516*f6dc9357SAndroid Build Coastguard Worker       VirtualDiskSize = Get64(p2);
517*f6dc9357SAndroid Build Coastguard Worker       VirtualDiskSize_Defined = true;
518*f6dc9357SAndroid Build Coastguard Worker     }
519*f6dc9357SAndroid Build Coastguard Worker     else if (e.Guid.IsEqualTo(kVirtualDiskID))
520*f6dc9357SAndroid Build Coastguard Worker     {
521*f6dc9357SAndroid Build Coastguard Worker       if (e.Len != 16)
522*f6dc9357SAndroid Build Coastguard Worker         return false;
523*f6dc9357SAndroid Build Coastguard Worker       Guid.SetFrom(p2);
524*f6dc9357SAndroid Build Coastguard Worker       Guid_Defined = true;
525*f6dc9357SAndroid Build Coastguard Worker     }
526*f6dc9357SAndroid Build Coastguard Worker     else if (e.Guid.IsEqualTo(kLogicalSectorSize))
527*f6dc9357SAndroid Build Coastguard Worker     {
528*f6dc9357SAndroid Build Coastguard Worker       if (LogicalSectorSize_Log != 0)
529*f6dc9357SAndroid Build Coastguard Worker         return false;
530*f6dc9357SAndroid Build Coastguard Worker       if (e.Len != 4)
531*f6dc9357SAndroid Build Coastguard Worker         return false;
532*f6dc9357SAndroid Build Coastguard Worker       const UInt32 v = Get32(p2);
533*f6dc9357SAndroid Build Coastguard Worker       LogicalSectorSize_Log = GetLogSize(v);
534*f6dc9357SAndroid Build Coastguard Worker       if (LogicalSectorSize_Log != 9 && LogicalSectorSize_Log != 12)
535*f6dc9357SAndroid Build Coastguard Worker         return false;
536*f6dc9357SAndroid Build Coastguard Worker     }
537*f6dc9357SAndroid Build Coastguard Worker     else if (e.Guid.IsEqualTo(kPhysicalSectorSize))
538*f6dc9357SAndroid Build Coastguard Worker     {
539*f6dc9357SAndroid Build Coastguard Worker       if (PhysicalSectorSize_Log != 0)
540*f6dc9357SAndroid Build Coastguard Worker         return false;
541*f6dc9357SAndroid Build Coastguard Worker       if (e.Len != 4)
542*f6dc9357SAndroid Build Coastguard Worker         return false;
543*f6dc9357SAndroid Build Coastguard Worker       const UInt32 v = Get32(p2);
544*f6dc9357SAndroid Build Coastguard Worker       PhysicalSectorSize_Log = GetLogSize(v);
545*f6dc9357SAndroid Build Coastguard Worker       if (PhysicalSectorSize_Log != 9 && PhysicalSectorSize_Log != 12)
546*f6dc9357SAndroid Build Coastguard Worker         return false;
547*f6dc9357SAndroid Build Coastguard Worker     }
548*f6dc9357SAndroid Build Coastguard Worker     else if (e.Guid.IsEqualTo(kParentLocator))
549*f6dc9357SAndroid Build Coastguard Worker     {
550*f6dc9357SAndroid Build Coastguard Worker       if (Locator_Defined)
551*f6dc9357SAndroid Build Coastguard Worker         return false;
552*f6dc9357SAndroid Build Coastguard Worker       if (e.Len < 20)
553*f6dc9357SAndroid Build Coastguard Worker         return false;
554*f6dc9357SAndroid Build Coastguard Worker       // LocatorType.SetFrom(p2);
555*f6dc9357SAndroid Build Coastguard Worker       /* Specifies the type of the parent virtual disk.
556*f6dc9357SAndroid Build Coastguard Worker          is different for each type: VHDX, VHD or iSCSI.
557*f6dc9357SAndroid Build Coastguard Worker          only "B04AEFB7-D19E-4A81-B789-25B8E9445913" (for VHDX) is supported now
558*f6dc9357SAndroid Build Coastguard Worker       */
559*f6dc9357SAndroid Build Coastguard Worker       Locator_Defined = true;
560*f6dc9357SAndroid Build Coastguard Worker       if (Get16(p2 + 16) != 0) // reserved
561*f6dc9357SAndroid Build Coastguard Worker         return false;
562*f6dc9357SAndroid Build Coastguard Worker       const UInt32 KeyValueCount = Get16(p2 + 18);
563*f6dc9357SAndroid Build Coastguard Worker       if (20 + (UInt32)KeyValueCount * 12 > e.Len)
564*f6dc9357SAndroid Build Coastguard Worker         return false;
565*f6dc9357SAndroid Build Coastguard Worker       for (unsigned k = 0; k < KeyValueCount; k++)
566*f6dc9357SAndroid Build Coastguard Worker       {
567*f6dc9357SAndroid Build Coastguard Worker         const Byte *p3 = p2 + 20 + (size_t)k * 12;
568*f6dc9357SAndroid Build Coastguard Worker         const UInt32 KeyOffset   = Get32(p3);
569*f6dc9357SAndroid Build Coastguard Worker         const UInt32 ValueOffset = Get32(p3 + 4);
570*f6dc9357SAndroid Build Coastguard Worker         const UInt32 KeyLength   = Get16(p3 + 8);
571*f6dc9357SAndroid Build Coastguard Worker         const UInt32 ValueLength = Get16(p3 + 10);
572*f6dc9357SAndroid Build Coastguard Worker         if (KeyOffset > e.Len || KeyLength > e.Len - KeyOffset)
573*f6dc9357SAndroid Build Coastguard Worker           return false;
574*f6dc9357SAndroid Build Coastguard Worker         if (ValueOffset > e.Len || ValueLength > e.Len - ValueOffset)
575*f6dc9357SAndroid Build Coastguard Worker           return false;
576*f6dc9357SAndroid Build Coastguard Worker         CParentPair pair;
577*f6dc9357SAndroid Build Coastguard Worker         if (!GetString16(pair.Key, p2 + KeyOffset, KeyLength))
578*f6dc9357SAndroid Build Coastguard Worker           return false;
579*f6dc9357SAndroid Build Coastguard Worker         if (!GetString16(pair.Value, p2 + ValueOffset, ValueLength))
580*f6dc9357SAndroid Build Coastguard Worker           return false;
581*f6dc9357SAndroid Build Coastguard Worker         ParentPairs.Add(pair);
582*f6dc9357SAndroid Build Coastguard Worker       }
583*f6dc9357SAndroid Build Coastguard Worker     }
584*f6dc9357SAndroid Build Coastguard Worker     else
585*f6dc9357SAndroid Build Coastguard Worker     {
586*f6dc9357SAndroid Build Coastguard Worker       if (e.IsRequired())
587*f6dc9357SAndroid Build Coastguard Worker         return false;
588*f6dc9357SAndroid Build Coastguard Worker       // return false; // unknown metadata;
589*f6dc9357SAndroid Build Coastguard Worker     }
590*f6dc9357SAndroid Build Coastguard Worker   }
591*f6dc9357SAndroid Build Coastguard Worker 
592*f6dc9357SAndroid Build Coastguard Worker   // some properties are required for correct processing
593*f6dc9357SAndroid Build Coastguard Worker 
594*f6dc9357SAndroid Build Coastguard Worker   if (BlockSize_Log == 0)
595*f6dc9357SAndroid Build Coastguard Worker     return false;
596*f6dc9357SAndroid Build Coastguard Worker   if (LogicalSectorSize_Log == 0)
597*f6dc9357SAndroid Build Coastguard Worker     return false;
598*f6dc9357SAndroid Build Coastguard Worker   if (!VirtualDiskSize_Defined)
599*f6dc9357SAndroid Build Coastguard Worker     return false;
600*f6dc9357SAndroid Build Coastguard Worker   if (((UInt32)VirtualDiskSize & ((UInt32)1 << LogicalSectorSize_Log)) != 0)
601*f6dc9357SAndroid Build Coastguard Worker     return false;
602*f6dc9357SAndroid Build Coastguard Worker 
603*f6dc9357SAndroid Build Coastguard Worker   // vhdx specification sets limit for 64 TB.
604*f6dc9357SAndroid Build Coastguard Worker   // do we need to check over same limit ?
605*f6dc9357SAndroid Build Coastguard Worker   const UInt64 kVirtualDiskSize_Max = (UInt64)1 << 46;
606*f6dc9357SAndroid Build Coastguard Worker   if (VirtualDiskSize > kVirtualDiskSize_Max)
607*f6dc9357SAndroid Build Coastguard Worker     return false;
608*f6dc9357SAndroid Build Coastguard Worker 
609*f6dc9357SAndroid Build Coastguard Worker   return true;
610*f6dc9357SAndroid Build Coastguard Worker }
611*f6dc9357SAndroid Build Coastguard Worker 
612*f6dc9357SAndroid Build Coastguard Worker 
613*f6dc9357SAndroid Build Coastguard Worker 
614*f6dc9357SAndroid Build Coastguard Worker struct CBat
615*f6dc9357SAndroid Build Coastguard Worker {
616*f6dc9357SAndroid Build Coastguard Worker   CByteBuffer Data;
617*f6dc9357SAndroid Build Coastguard Worker 
ClearNArchive::NVhdx::CBat618*f6dc9357SAndroid Build Coastguard Worker   void Clear() { Data.Free(); }
GetItemNArchive::NVhdx::CBat619*f6dc9357SAndroid Build Coastguard Worker   UInt64 GetItem(size_t n) const
620*f6dc9357SAndroid Build Coastguard Worker   {
621*f6dc9357SAndroid Build Coastguard Worker     return Get64(Data + n * 8);
622*f6dc9357SAndroid Build Coastguard Worker   }
623*f6dc9357SAndroid Build Coastguard Worker };
624*f6dc9357SAndroid Build Coastguard Worker 
625*f6dc9357SAndroid Build Coastguard Worker 
626*f6dc9357SAndroid Build Coastguard Worker 
627*f6dc9357SAndroid Build Coastguard Worker Z7_class_CHandler_final: public CHandlerImg
628*f6dc9357SAndroid Build Coastguard Worker {
629*f6dc9357SAndroid Build Coastguard Worker   UInt64 _phySize;
630*f6dc9357SAndroid Build Coastguard Worker 
631*f6dc9357SAndroid Build Coastguard Worker   CBat Bat;
632*f6dc9357SAndroid Build Coastguard Worker   CObjectVector<CByteBuffer> BitMaps;
633*f6dc9357SAndroid Build Coastguard Worker 
634*f6dc9357SAndroid Build Coastguard Worker   unsigned ChunkRatio_Log;
635*f6dc9357SAndroid Build Coastguard Worker   size_t ChunkRatio;
636*f6dc9357SAndroid Build Coastguard Worker   size_t TotalBatEntries;
637*f6dc9357SAndroid Build Coastguard Worker 
638*f6dc9357SAndroid Build Coastguard Worker   CMetaHeader Meta;
639*f6dc9357SAndroid Build Coastguard Worker   CHeader Header;
640*f6dc9357SAndroid Build Coastguard Worker 
641*f6dc9357SAndroid Build Coastguard Worker   UInt32 NumUsedBlocks;
642*f6dc9357SAndroid Build Coastguard Worker   UInt32 NumUsedBitMaps;
643*f6dc9357SAndroid Build Coastguard Worker   UInt64 HeadersSize;
644*f6dc9357SAndroid Build Coastguard Worker 
645*f6dc9357SAndroid Build Coastguard Worker   UInt32 NumLevels;
646*f6dc9357SAndroid Build Coastguard Worker   UInt64 PackSize_Total;
647*f6dc9357SAndroid Build Coastguard Worker 
648*f6dc9357SAndroid Build Coastguard Worker   /*
649*f6dc9357SAndroid Build Coastguard Worker   UInt64 NumUsed_1MB_Blocks; // data and bitmaps
650*f6dc9357SAndroid Build Coastguard Worker   bool NumUsed_1MB_Blocks_Defined;
651*f6dc9357SAndroid Build Coastguard Worker   */
652*f6dc9357SAndroid Build Coastguard Worker 
653*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<IInStream> ParentStream;
654*f6dc9357SAndroid Build Coastguard Worker   CHandler *Parent;
655*f6dc9357SAndroid Build Coastguard Worker   UString _errorMessage;
656*f6dc9357SAndroid Build Coastguard Worker   UString _creator;
657*f6dc9357SAndroid Build Coastguard Worker 
658*f6dc9357SAndroid Build Coastguard Worker   bool _nonEmptyLog;
659*f6dc9357SAndroid Build Coastguard Worker   bool _isDataContiguous;
660*f6dc9357SAndroid Build Coastguard Worker   // bool _batOverlap;
661*f6dc9357SAndroid Build Coastguard Worker 
662*f6dc9357SAndroid Build Coastguard Worker   CGuid _parentGuid;
663*f6dc9357SAndroid Build Coastguard Worker   bool _parentGuid_IsDefined;
664*f6dc9357SAndroid Build Coastguard Worker   UStringVector ParentNames;
665*f6dc9357SAndroid Build Coastguard Worker   UString ParentName_Used;
666*f6dc9357SAndroid Build Coastguard Worker 
667*f6dc9357SAndroid Build Coastguard Worker   const CHandler *_child;
668*f6dc9357SAndroid Build Coastguard Worker   unsigned _level;
669*f6dc9357SAndroid Build Coastguard Worker   bool _isCyclic;
670*f6dc9357SAndroid Build Coastguard Worker   bool _isCyclic_or_CyclicParent;
671*f6dc9357SAndroid Build Coastguard Worker 
672*f6dc9357SAndroid Build Coastguard Worker   void AddErrorMessage(const char *message);
673*f6dc9357SAndroid Build Coastguard Worker   void AddErrorMessage(const char *message, const wchar_t *name);
674*f6dc9357SAndroid Build Coastguard Worker 
675*f6dc9357SAndroid Build Coastguard Worker   void UpdatePhySize(UInt64 value)
676*f6dc9357SAndroid Build Coastguard Worker   {
677*f6dc9357SAndroid Build Coastguard Worker     if (_phySize < value)
678*f6dc9357SAndroid Build Coastguard Worker       _phySize = value;
679*f6dc9357SAndroid Build Coastguard Worker   }
680*f6dc9357SAndroid Build Coastguard Worker 
681*f6dc9357SAndroid Build Coastguard Worker   HRESULT Seek2(UInt64 offset);
682*f6dc9357SAndroid Build Coastguard Worker   HRESULT Read_FALSE(Byte *data, size_t size)
683*f6dc9357SAndroid Build Coastguard Worker   {
684*f6dc9357SAndroid Build Coastguard Worker     return ReadStream_FALSE(Stream, data, size);
685*f6dc9357SAndroid Build Coastguard Worker   }
686*f6dc9357SAndroid Build Coastguard Worker   HRESULT ReadToBuf_FALSE(CByteBuffer &buf, size_t size)
687*f6dc9357SAndroid Build Coastguard Worker   {
688*f6dc9357SAndroid Build Coastguard Worker     buf.Alloc(size);
689*f6dc9357SAndroid Build Coastguard Worker     return ReadStream_FALSE(Stream, buf, size);
690*f6dc9357SAndroid Build Coastguard Worker   }
691*f6dc9357SAndroid Build Coastguard Worker 
692*f6dc9357SAndroid Build Coastguard Worker   void InitSeekPositions();
693*f6dc9357SAndroid Build Coastguard Worker   HRESULT ReadPhy(UInt64 offset, void *data, UInt32 size, UInt32 &processed);
694*f6dc9357SAndroid Build Coastguard Worker 
695*f6dc9357SAndroid Build Coastguard Worker   bool IsDiff() const
696*f6dc9357SAndroid Build Coastguard Worker   {
697*f6dc9357SAndroid Build Coastguard Worker     // here we suppose that only HasParent() flag is mandatory for Diff archive type
698*f6dc9357SAndroid Build Coastguard Worker     return Meta.Is_HasParent();
699*f6dc9357SAndroid Build Coastguard Worker     // return _parentGuid_IsDefined;
700*f6dc9357SAndroid Build Coastguard Worker   }
701*f6dc9357SAndroid Build Coastguard Worker 
702*f6dc9357SAndroid Build Coastguard Worker   void AddTypeString(AString &s) const
703*f6dc9357SAndroid Build Coastguard Worker   {
704*f6dc9357SAndroid Build Coastguard Worker     if (IsDiff())
705*f6dc9357SAndroid Build Coastguard Worker       s += "Differencing";
706*f6dc9357SAndroid Build Coastguard Worker     else
707*f6dc9357SAndroid Build Coastguard Worker     {
708*f6dc9357SAndroid Build Coastguard Worker       if (Meta.Is_LeaveBlockAllocated())
709*f6dc9357SAndroid Build Coastguard Worker         s +=  _isDataContiguous ? "fixed" : "fixed-non-cont";
710*f6dc9357SAndroid Build Coastguard Worker       else
711*f6dc9357SAndroid Build Coastguard Worker         s += "dynamic";
712*f6dc9357SAndroid Build Coastguard Worker     }
713*f6dc9357SAndroid Build Coastguard Worker   }
714*f6dc9357SAndroid Build Coastguard Worker 
715*f6dc9357SAndroid Build Coastguard Worker   void AddComment(UString &s) const;
716*f6dc9357SAndroid Build Coastguard Worker 
717*f6dc9357SAndroid Build Coastguard Worker   UInt64 GetPackSize() const
718*f6dc9357SAndroid Build Coastguard Worker   {
719*f6dc9357SAndroid Build Coastguard Worker     return (UInt64)NumUsedBlocks << Meta.BlockSize_Log;
720*f6dc9357SAndroid Build Coastguard Worker   }
721*f6dc9357SAndroid Build Coastguard Worker 
722*f6dc9357SAndroid Build Coastguard Worker   UString GetParentSequence() const
723*f6dc9357SAndroid Build Coastguard Worker   {
724*f6dc9357SAndroid Build Coastguard Worker     const CHandler *p = this;
725*f6dc9357SAndroid Build Coastguard Worker     UString res;
726*f6dc9357SAndroid Build Coastguard Worker     while (p && p->IsDiff())
727*f6dc9357SAndroid Build Coastguard Worker     {
728*f6dc9357SAndroid Build Coastguard Worker       if (!res.IsEmpty())
729*f6dc9357SAndroid Build Coastguard Worker         res += " -> ";
730*f6dc9357SAndroid Build Coastguard Worker       res += ParentName_Used;
731*f6dc9357SAndroid Build Coastguard Worker       p = p->Parent;
732*f6dc9357SAndroid Build Coastguard Worker     }
733*f6dc9357SAndroid Build Coastguard Worker     return res;
734*f6dc9357SAndroid Build Coastguard Worker   }
735*f6dc9357SAndroid Build Coastguard Worker 
736*f6dc9357SAndroid Build Coastguard Worker   bool AreParentsOK() const
737*f6dc9357SAndroid Build Coastguard Worker   {
738*f6dc9357SAndroid Build Coastguard Worker     if (_isCyclic_or_CyclicParent)
739*f6dc9357SAndroid Build Coastguard Worker       return false;
740*f6dc9357SAndroid Build Coastguard Worker     const CHandler *p = this;
741*f6dc9357SAndroid Build Coastguard Worker     while (p->IsDiff())
742*f6dc9357SAndroid Build Coastguard Worker     {
743*f6dc9357SAndroid Build Coastguard Worker       p = p->Parent;
744*f6dc9357SAndroid Build Coastguard Worker       if (!p)
745*f6dc9357SAndroid Build Coastguard Worker         return false;
746*f6dc9357SAndroid Build Coastguard Worker     }
747*f6dc9357SAndroid Build Coastguard Worker     return true;
748*f6dc9357SAndroid Build Coastguard Worker   }
749*f6dc9357SAndroid Build Coastguard Worker 
750*f6dc9357SAndroid Build Coastguard Worker   // bool ParseLog(CByteBuffer &log);
751*f6dc9357SAndroid Build Coastguard Worker   bool ParseBat();
752*f6dc9357SAndroid Build Coastguard Worker   bool CheckBat();
753*f6dc9357SAndroid Build Coastguard Worker 
754*f6dc9357SAndroid Build Coastguard Worker   HRESULT Open3();
755*f6dc9357SAndroid Build Coastguard Worker   HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openArchiveCallback) Z7_override;
756*f6dc9357SAndroid Build Coastguard Worker   HRESULT OpenParent(IArchiveOpenCallback *openArchiveCallback, bool &_parentFileWasOpen);
757*f6dc9357SAndroid Build Coastguard Worker   virtual void CloseAtError() Z7_override;
758*f6dc9357SAndroid Build Coastguard Worker 
759*f6dc9357SAndroid Build Coastguard Worker public:
760*f6dc9357SAndroid Build Coastguard Worker   Z7_IFACE_COM7_IMP(IInArchive_Img)
761*f6dc9357SAndroid Build Coastguard Worker 
762*f6dc9357SAndroid Build Coastguard Worker   Z7_IFACE_COM7_IMP(IInArchiveGetStream)
763*f6dc9357SAndroid Build Coastguard Worker   Z7_IFACE_COM7_IMP(ISequentialInStream)
764*f6dc9357SAndroid Build Coastguard Worker 
765*f6dc9357SAndroid Build Coastguard Worker   CHandler():
766*f6dc9357SAndroid Build Coastguard Worker     _child(NULL),
767*f6dc9357SAndroid Build Coastguard Worker     _level(0),
768*f6dc9357SAndroid Build Coastguard Worker     _isCyclic(false),
769*f6dc9357SAndroid Build Coastguard Worker     _isCyclic_or_CyclicParent(false)
770*f6dc9357SAndroid Build Coastguard Worker     {}
771*f6dc9357SAndroid Build Coastguard Worker };
772*f6dc9357SAndroid Build Coastguard Worker 
773*f6dc9357SAndroid Build Coastguard Worker 
774*f6dc9357SAndroid Build Coastguard Worker HRESULT CHandler::Seek2(UInt64 offset)
775*f6dc9357SAndroid Build Coastguard Worker {
776*f6dc9357SAndroid Build Coastguard Worker   return InStream_SeekSet(Stream, offset);
777*f6dc9357SAndroid Build Coastguard Worker }
778*f6dc9357SAndroid Build Coastguard Worker 
779*f6dc9357SAndroid Build Coastguard Worker 
780*f6dc9357SAndroid Build Coastguard Worker void CHandler::InitSeekPositions()
781*f6dc9357SAndroid Build Coastguard Worker {
782*f6dc9357SAndroid Build Coastguard Worker   /* (_virtPos) and (_posInArc) is used only in Read() (that calls ReadPhy()).
783*f6dc9357SAndroid Build Coastguard Worker      So we must reset these variables before first call of Read() */
784*f6dc9357SAndroid Build Coastguard Worker   Reset_VirtPos();
785*f6dc9357SAndroid Build Coastguard Worker   Reset_PosInArc();
786*f6dc9357SAndroid Build Coastguard Worker   if (ParentStream)
787*f6dc9357SAndroid Build Coastguard Worker     Parent->InitSeekPositions();
788*f6dc9357SAndroid Build Coastguard Worker }
789*f6dc9357SAndroid Build Coastguard Worker 
790*f6dc9357SAndroid Build Coastguard Worker 
791*f6dc9357SAndroid Build Coastguard Worker HRESULT CHandler::ReadPhy(UInt64 offset, void *data, UInt32 size, UInt32 &processed)
792*f6dc9357SAndroid Build Coastguard Worker {
793*f6dc9357SAndroid Build Coastguard Worker   processed = 0;
794*f6dc9357SAndroid Build Coastguard Worker   if (offset > _phySize
795*f6dc9357SAndroid Build Coastguard Worker       || offset + size > _phySize)
796*f6dc9357SAndroid Build Coastguard Worker   {
797*f6dc9357SAndroid Build Coastguard Worker     // we don't expect these cases, if (_phySize) was set correctly.
798*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
799*f6dc9357SAndroid Build Coastguard Worker   }
800*f6dc9357SAndroid Build Coastguard Worker   if (offset != _posInArc)
801*f6dc9357SAndroid Build Coastguard Worker   {
802*f6dc9357SAndroid Build Coastguard Worker     const HRESULT res = Seek2(offset);
803*f6dc9357SAndroid Build Coastguard Worker     if (res != S_OK)
804*f6dc9357SAndroid Build Coastguard Worker     {
805*f6dc9357SAndroid Build Coastguard Worker       Reset_PosInArc(); // we don't trust seek_pos in case of error
806*f6dc9357SAndroid Build Coastguard Worker       return res;
807*f6dc9357SAndroid Build Coastguard Worker     }
808*f6dc9357SAndroid Build Coastguard Worker     _posInArc = offset;
809*f6dc9357SAndroid Build Coastguard Worker   }
810*f6dc9357SAndroid Build Coastguard Worker   {
811*f6dc9357SAndroid Build Coastguard Worker     size_t size2 = size;
812*f6dc9357SAndroid Build Coastguard Worker     const HRESULT res = ReadStream(Stream, data, &size2);
813*f6dc9357SAndroid Build Coastguard Worker     processed = (UInt32)size2;
814*f6dc9357SAndroid Build Coastguard Worker     _posInArc += size2;
815*f6dc9357SAndroid Build Coastguard Worker     if (res != S_OK)
816*f6dc9357SAndroid Build Coastguard Worker       Reset_PosInArc(); // we don't trust seek_pos in case of reading error
817*f6dc9357SAndroid Build Coastguard Worker     return res;
818*f6dc9357SAndroid Build Coastguard Worker   }
819*f6dc9357SAndroid Build Coastguard Worker }
820*f6dc9357SAndroid Build Coastguard Worker 
821*f6dc9357SAndroid Build Coastguard Worker 
822*f6dc9357SAndroid Build Coastguard Worker #define PAYLOAD_BLOCK_NOT_PRESENT   0
823*f6dc9357SAndroid Build Coastguard Worker #define PAYLOAD_BLOCK_UNDEFINED     1
824*f6dc9357SAndroid Build Coastguard Worker #define PAYLOAD_BLOCK_ZERO          2
825*f6dc9357SAndroid Build Coastguard Worker #define PAYLOAD_BLOCK_UNMAPPED      3
826*f6dc9357SAndroid Build Coastguard Worker #define PAYLOAD_BLOCK_FULLY_PRESENT 6
827*f6dc9357SAndroid Build Coastguard Worker #define PAYLOAD_BLOCK_PARTIALLY_PRESENT 7
828*f6dc9357SAndroid Build Coastguard Worker 
829*f6dc9357SAndroid Build Coastguard Worker #define SB_BLOCK_NOT_PRESENT 0
830*f6dc9357SAndroid Build Coastguard Worker #define SB_BLOCK_PRESENT     6
831*f6dc9357SAndroid Build Coastguard Worker 
832*f6dc9357SAndroid Build Coastguard Worker #define BAT_GET_OFFSET(v) ((v) & ~(UInt64)0xFFFFF)
833*f6dc9357SAndroid Build Coastguard Worker #define BAT_GET_STATE(v)  ((UInt32)(v) & 7)
834*f6dc9357SAndroid Build Coastguard Worker 
835*f6dc9357SAndroid Build Coastguard Worker /* The log contains only   updates to metadata, bat and region tables
836*f6dc9357SAndroid Build Coastguard Worker    The log doesn't contain updates to start header, and 2 headers (first 192 KB of file).
837*f6dc9357SAndroid Build Coastguard Worker    The log is array of 4 KB blocks and each block has 4-byte signature.
838*f6dc9357SAndroid Build Coastguard Worker    So it's possible to scan whole log to find the latest entry sequence (and header for replay).
839*f6dc9357SAndroid Build Coastguard Worker */
840*f6dc9357SAndroid Build Coastguard Worker 
841*f6dc9357SAndroid Build Coastguard Worker /*
842*f6dc9357SAndroid Build Coastguard Worker struct CLogEntry
843*f6dc9357SAndroid Build Coastguard Worker {
844*f6dc9357SAndroid Build Coastguard Worker   UInt32 EntryLength;
845*f6dc9357SAndroid Build Coastguard Worker   UInt32 Tail;
846*f6dc9357SAndroid Build Coastguard Worker   UInt64 SequenceNumber;
847*f6dc9357SAndroid Build Coastguard Worker   CGuid LogGuid;
848*f6dc9357SAndroid Build Coastguard Worker   UInt32 DescriptorCount;
849*f6dc9357SAndroid Build Coastguard Worker   UInt64 FlushedFileOffset;
850*f6dc9357SAndroid Build Coastguard Worker   UInt64 LastFileOffset;
851*f6dc9357SAndroid Build Coastguard Worker 
852*f6dc9357SAndroid Build Coastguard Worker   bool Parse(const Byte *p);
853*f6dc9357SAndroid Build Coastguard Worker };
854*f6dc9357SAndroid Build Coastguard Worker 
855*f6dc9357SAndroid Build Coastguard Worker bool CLogEntry::Parse(const Byte *p)
856*f6dc9357SAndroid Build Coastguard Worker {
857*f6dc9357SAndroid Build Coastguard Worker   G32 (8, EntryLength);
858*f6dc9357SAndroid Build Coastguard Worker   G32 (12,Tail);
859*f6dc9357SAndroid Build Coastguard Worker   G64 (16, SequenceNumber);
860*f6dc9357SAndroid Build Coastguard Worker   G32 (24, DescriptorCount); // it's 32-bit, but specification says 64-bit
861*f6dc9357SAndroid Build Coastguard Worker   if (Get32(p + 28) != 0) // reserved
862*f6dc9357SAndroid Build Coastguard Worker     return false;
863*f6dc9357SAndroid Build Coastguard Worker   LogGuid.SetFrom(p + 32);
864*f6dc9357SAndroid Build Coastguard Worker   G64 (48, FlushedFileOffset);
865*f6dc9357SAndroid Build Coastguard Worker   G64 (56, LastFileOffset);
866*f6dc9357SAndroid Build Coastguard Worker 
867*f6dc9357SAndroid Build Coastguard Worker   if (SequenceNumber == 0)
868*f6dc9357SAndroid Build Coastguard Worker     return false;
869*f6dc9357SAndroid Build Coastguard Worker   if ((Tail & 0xfff) != 0)
870*f6dc9357SAndroid Build Coastguard Worker     return false;
871*f6dc9357SAndroid Build Coastguard Worker   if (IS_NON_ALIGNED(FlushedFileOffset))
872*f6dc9357SAndroid Build Coastguard Worker     return false;
873*f6dc9357SAndroid Build Coastguard Worker   if (IS_NON_ALIGNED(LastFileOffset))
874*f6dc9357SAndroid Build Coastguard Worker     return false;
875*f6dc9357SAndroid Build Coastguard Worker   return true;
876*f6dc9357SAndroid Build Coastguard Worker }
877*f6dc9357SAndroid Build Coastguard Worker 
878*f6dc9357SAndroid Build Coastguard Worker 
879*f6dc9357SAndroid Build Coastguard Worker bool CHandler::ParseLog(CByteBuffer &log)
880*f6dc9357SAndroid Build Coastguard Worker {
881*f6dc9357SAndroid Build Coastguard Worker   CLogEntry lastEntry;
882*f6dc9357SAndroid Build Coastguard Worker   lastEntry.SequenceNumber = 0;
883*f6dc9357SAndroid Build Coastguard Worker   bool lastEntry_found = false;
884*f6dc9357SAndroid Build Coastguard Worker   size_t lastEntry_Offset = 0;
885*f6dc9357SAndroid Build Coastguard Worker   for (size_t i = 0; i < log.Size(); i += 1 << 12)
886*f6dc9357SAndroid Build Coastguard Worker   {
887*f6dc9357SAndroid Build Coastguard Worker     Byte *p = (Byte *)(log + i);
888*f6dc9357SAndroid Build Coastguard Worker 
889*f6dc9357SAndroid Build Coastguard Worker     if (Get32(p) != 0x65676F6C) // "loge"
890*f6dc9357SAndroid Build Coastguard Worker       continue;
891*f6dc9357SAndroid Build Coastguard Worker     const UInt32 crc = Get32(p + 4);
892*f6dc9357SAndroid Build Coastguard Worker 
893*f6dc9357SAndroid Build Coastguard Worker     CLogEntry e;
894*f6dc9357SAndroid Build Coastguard Worker     if (!e.Parse(p))
895*f6dc9357SAndroid Build Coastguard Worker     {
896*f6dc9357SAndroid Build Coastguard Worker       return false;
897*f6dc9357SAndroid Build Coastguard Worker       continue;
898*f6dc9357SAndroid Build Coastguard Worker     }
899*f6dc9357SAndroid Build Coastguard Worker     const UInt32 entryLength = Get32(p + 8);
900*f6dc9357SAndroid Build Coastguard Worker     if (e.EntryLength > log.Size() || (e.EntryLength & 0xFFF) != 0 || e.EntryLength == 0)
901*f6dc9357SAndroid Build Coastguard Worker     {
902*f6dc9357SAndroid Build Coastguard Worker       return false;
903*f6dc9357SAndroid Build Coastguard Worker       continue;
904*f6dc9357SAndroid Build Coastguard Worker     }
905*f6dc9357SAndroid Build Coastguard Worker     SetUi32(p + 4, 0);
906*f6dc9357SAndroid Build Coastguard Worker     const UInt32 crc_calced = Crc32c_Calc(p, entryLength);
907*f6dc9357SAndroid Build Coastguard Worker     SetUi32(p + 4, crc); // we must restore crc if we want same data in log
908*f6dc9357SAndroid Build Coastguard Worker     if (crc_calced != crc)
909*f6dc9357SAndroid Build Coastguard Worker       continue;
910*f6dc9357SAndroid Build Coastguard Worker     if (!lastEntry_found || lastEntry.SequenceNumber < e.SequenceNumber)
911*f6dc9357SAndroid Build Coastguard Worker     {
912*f6dc9357SAndroid Build Coastguard Worker       lastEntry = e;
913*f6dc9357SAndroid Build Coastguard Worker       lastEntry_found = true;
914*f6dc9357SAndroid Build Coastguard Worker       lastEntry_Offset = i;
915*f6dc9357SAndroid Build Coastguard Worker     }
916*f6dc9357SAndroid Build Coastguard Worker   }
917*f6dc9357SAndroid Build Coastguard Worker 
918*f6dc9357SAndroid Build Coastguard Worker   return true;
919*f6dc9357SAndroid Build Coastguard Worker }
920*f6dc9357SAndroid Build Coastguard Worker */
921*f6dc9357SAndroid Build Coastguard Worker 
922*f6dc9357SAndroid Build Coastguard Worker 
923*f6dc9357SAndroid Build Coastguard Worker bool CHandler::ParseBat()
924*f6dc9357SAndroid Build Coastguard Worker {
925*f6dc9357SAndroid Build Coastguard Worker   ChunkRatio_Log = kBitmapSize_Log + 3 + Meta.LogicalSectorSize_Log - Meta.BlockSize_Log;
926*f6dc9357SAndroid Build Coastguard Worker   ChunkRatio = (size_t)1 << (ChunkRatio_Log);
927*f6dc9357SAndroid Build Coastguard Worker 
928*f6dc9357SAndroid Build Coastguard Worker   UInt64 totalBatEntries64;
929*f6dc9357SAndroid Build Coastguard Worker   const bool isDiff = IsDiff();
930*f6dc9357SAndroid Build Coastguard Worker   const UInt32 blockSize = (UInt32)1 << Meta.BlockSize_Log;
931*f6dc9357SAndroid Build Coastguard Worker   {
932*f6dc9357SAndroid Build Coastguard Worker     const UInt64 up = Meta.VirtualDiskSize + blockSize - 1;
933*f6dc9357SAndroid Build Coastguard Worker     if (up < Meta.VirtualDiskSize)
934*f6dc9357SAndroid Build Coastguard Worker       return false;
935*f6dc9357SAndroid Build Coastguard Worker     const UInt64 numDataBlocks = up >> Meta.BlockSize_Log;
936*f6dc9357SAndroid Build Coastguard Worker 
937*f6dc9357SAndroid Build Coastguard Worker     if (isDiff)
938*f6dc9357SAndroid Build Coastguard Worker     {
939*f6dc9357SAndroid Build Coastguard Worker       // differencing table must be finished with bitmap entry
940*f6dc9357SAndroid Build Coastguard Worker       const UInt64 numBitmaps = (numDataBlocks + ChunkRatio - 1) >> ChunkRatio_Log;
941*f6dc9357SAndroid Build Coastguard Worker       totalBatEntries64 = numBitmaps * (ChunkRatio + 1);
942*f6dc9357SAndroid Build Coastguard Worker     }
943*f6dc9357SAndroid Build Coastguard Worker     else
944*f6dc9357SAndroid Build Coastguard Worker     {
945*f6dc9357SAndroid Build Coastguard Worker       // we don't need last Bitmap entry
946*f6dc9357SAndroid Build Coastguard Worker       totalBatEntries64 = numDataBlocks + ((numDataBlocks - 1) >> ChunkRatio_Log);
947*f6dc9357SAndroid Build Coastguard Worker     }
948*f6dc9357SAndroid Build Coastguard Worker   }
949*f6dc9357SAndroid Build Coastguard Worker 
950*f6dc9357SAndroid Build Coastguard Worker   if (totalBatEntries64 > Bat.Data.Size() / 8)
951*f6dc9357SAndroid Build Coastguard Worker     return false;
952*f6dc9357SAndroid Build Coastguard Worker 
953*f6dc9357SAndroid Build Coastguard Worker   const size_t totalBatEntries = (size_t)totalBatEntries64;
954*f6dc9357SAndroid Build Coastguard Worker   TotalBatEntries = totalBatEntries;
955*f6dc9357SAndroid Build Coastguard Worker 
956*f6dc9357SAndroid Build Coastguard Worker   bool isCont = (!isDiff && Meta.Is_LeaveBlockAllocated());
957*f6dc9357SAndroid Build Coastguard Worker   UInt64 prevBlockOffset = 0;
958*f6dc9357SAndroid Build Coastguard Worker   UInt64 maxBlockOffset = 0;
959*f6dc9357SAndroid Build Coastguard Worker 
960*f6dc9357SAndroid Build Coastguard Worker   size_t remEntries = ChunkRatio + 1;
961*f6dc9357SAndroid Build Coastguard Worker 
962*f6dc9357SAndroid Build Coastguard Worker   size_t i;
963*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < totalBatEntries; i++)
964*f6dc9357SAndroid Build Coastguard Worker   {
965*f6dc9357SAndroid Build Coastguard Worker     const UInt64 v = Bat.GetItem(i);
966*f6dc9357SAndroid Build Coastguard Worker     if ((v & 0xFFFF8) != 0)
967*f6dc9357SAndroid Build Coastguard Worker       return false;
968*f6dc9357SAndroid Build Coastguard Worker     const UInt64 offset = BAT_GET_OFFSET(v);
969*f6dc9357SAndroid Build Coastguard Worker     const unsigned state = BAT_GET_STATE(v);
970*f6dc9357SAndroid Build Coastguard Worker 
971*f6dc9357SAndroid Build Coastguard Worker     /*
972*f6dc9357SAndroid Build Coastguard Worker     UInt64 index64 = v >> 20;
973*f6dc9357SAndroid Build Coastguard Worker     printf("\n%7d", i);
974*f6dc9357SAndroid Build Coastguard Worker     printf("%10d, ", (unsigned)index64);
975*f6dc9357SAndroid Build Coastguard Worker     printf("%4x, ", (unsigned)state);
976*f6dc9357SAndroid Build Coastguard Worker     */
977*f6dc9357SAndroid Build Coastguard Worker 
978*f6dc9357SAndroid Build Coastguard Worker     remEntries--;
979*f6dc9357SAndroid Build Coastguard Worker     if (remEntries == 0)
980*f6dc9357SAndroid Build Coastguard Worker     {
981*f6dc9357SAndroid Build Coastguard Worker       // printf(" ========");
982*f6dc9357SAndroid Build Coastguard Worker       // printf("\n");
983*f6dc9357SAndroid Build Coastguard Worker       remEntries = ChunkRatio + 1;
984*f6dc9357SAndroid Build Coastguard Worker       if (state == SB_BLOCK_PRESENT)
985*f6dc9357SAndroid Build Coastguard Worker       {
986*f6dc9357SAndroid Build Coastguard Worker         isCont = false;
987*f6dc9357SAndroid Build Coastguard Worker         if (!isDiff)
988*f6dc9357SAndroid Build Coastguard Worker           return false;
989*f6dc9357SAndroid Build Coastguard Worker         if (offset == 0)
990*f6dc9357SAndroid Build Coastguard Worker           return false;
991*f6dc9357SAndroid Build Coastguard Worker         const UInt64 lim = offset + kBitmapSize;
992*f6dc9357SAndroid Build Coastguard Worker         if (lim < offset)
993*f6dc9357SAndroid Build Coastguard Worker           return false;
994*f6dc9357SAndroid Build Coastguard Worker         if (_phySize < lim)
995*f6dc9357SAndroid Build Coastguard Worker           _phySize = lim;
996*f6dc9357SAndroid Build Coastguard Worker         NumUsedBitMaps++;
997*f6dc9357SAndroid Build Coastguard Worker       }
998*f6dc9357SAndroid Build Coastguard Worker       else if (state != SB_BLOCK_NOT_PRESENT)
999*f6dc9357SAndroid Build Coastguard Worker         return false;
1000*f6dc9357SAndroid Build Coastguard Worker     }
1001*f6dc9357SAndroid Build Coastguard Worker     else
1002*f6dc9357SAndroid Build Coastguard Worker     {
1003*f6dc9357SAndroid Build Coastguard Worker       if (state == PAYLOAD_BLOCK_FULLY_PRESENT
1004*f6dc9357SAndroid Build Coastguard Worker           || state == PAYLOAD_BLOCK_PARTIALLY_PRESENT)
1005*f6dc9357SAndroid Build Coastguard Worker       {
1006*f6dc9357SAndroid Build Coastguard Worker         if (offset == 0)
1007*f6dc9357SAndroid Build Coastguard Worker           return false;
1008*f6dc9357SAndroid Build Coastguard Worker         if (maxBlockOffset < offset)
1009*f6dc9357SAndroid Build Coastguard Worker           maxBlockOffset = offset;
1010*f6dc9357SAndroid Build Coastguard Worker 
1011*f6dc9357SAndroid Build Coastguard Worker         if (state == PAYLOAD_BLOCK_PARTIALLY_PRESENT)
1012*f6dc9357SAndroid Build Coastguard Worker         {
1013*f6dc9357SAndroid Build Coastguard Worker           isCont = false;
1014*f6dc9357SAndroid Build Coastguard Worker           if (!isDiff)
1015*f6dc9357SAndroid Build Coastguard Worker             return false;
1016*f6dc9357SAndroid Build Coastguard Worker         }
1017*f6dc9357SAndroid Build Coastguard Worker         else if (isCont)
1018*f6dc9357SAndroid Build Coastguard Worker         {
1019*f6dc9357SAndroid Build Coastguard Worker           if (prevBlockOffset != 0 && prevBlockOffset + blockSize != offset)
1020*f6dc9357SAndroid Build Coastguard Worker             isCont = false;
1021*f6dc9357SAndroid Build Coastguard Worker           else
1022*f6dc9357SAndroid Build Coastguard Worker             prevBlockOffset = offset;
1023*f6dc9357SAndroid Build Coastguard Worker         }
1024*f6dc9357SAndroid Build Coastguard Worker 
1025*f6dc9357SAndroid Build Coastguard Worker         NumUsedBlocks++;
1026*f6dc9357SAndroid Build Coastguard Worker       }
1027*f6dc9357SAndroid Build Coastguard Worker       else if (state == PAYLOAD_BLOCK_UNMAPPED)
1028*f6dc9357SAndroid Build Coastguard Worker       {
1029*f6dc9357SAndroid Build Coastguard Worker         isCont = false;
1030*f6dc9357SAndroid Build Coastguard Worker         // non-empty (offset) is allowed
1031*f6dc9357SAndroid Build Coastguard Worker       }
1032*f6dc9357SAndroid Build Coastguard Worker       else if (state == PAYLOAD_BLOCK_NOT_PRESENT
1033*f6dc9357SAndroid Build Coastguard Worker           || state == PAYLOAD_BLOCK_UNDEFINED
1034*f6dc9357SAndroid Build Coastguard Worker           || state == PAYLOAD_BLOCK_ZERO)
1035*f6dc9357SAndroid Build Coastguard Worker       {
1036*f6dc9357SAndroid Build Coastguard Worker         isCont = false;
1037*f6dc9357SAndroid Build Coastguard Worker         /* (offset) is reserved and (offset == 0) is expected here,
1038*f6dc9357SAndroid Build Coastguard Worker            but we ignore (offset) here */
1039*f6dc9357SAndroid Build Coastguard Worker         // if (offset != 0) return false;
1040*f6dc9357SAndroid Build Coastguard Worker       }
1041*f6dc9357SAndroid Build Coastguard Worker       else
1042*f6dc9357SAndroid Build Coastguard Worker         return false;
1043*f6dc9357SAndroid Build Coastguard Worker     }
1044*f6dc9357SAndroid Build Coastguard Worker   }
1045*f6dc9357SAndroid Build Coastguard Worker 
1046*f6dc9357SAndroid Build Coastguard Worker   _isDataContiguous = isCont;
1047*f6dc9357SAndroid Build Coastguard Worker 
1048*f6dc9357SAndroid Build Coastguard Worker   if (maxBlockOffset != 0)
1049*f6dc9357SAndroid Build Coastguard Worker   {
1050*f6dc9357SAndroid Build Coastguard Worker     const UInt64 lim = maxBlockOffset + blockSize;
1051*f6dc9357SAndroid Build Coastguard Worker     if (lim < maxBlockOffset)
1052*f6dc9357SAndroid Build Coastguard Worker       return false;
1053*f6dc9357SAndroid Build Coastguard Worker     if (_phySize < lim)
1054*f6dc9357SAndroid Build Coastguard Worker       _phySize = lim;
1055*f6dc9357SAndroid Build Coastguard Worker     const UInt64 kPhyLimit = (UInt64)1 << 62;
1056*f6dc9357SAndroid Build Coastguard Worker     if (maxBlockOffset >= kPhyLimit)
1057*f6dc9357SAndroid Build Coastguard Worker       return false;
1058*f6dc9357SAndroid Build Coastguard Worker   }
1059*f6dc9357SAndroid Build Coastguard Worker   return true;
1060*f6dc9357SAndroid Build Coastguard Worker }
1061*f6dc9357SAndroid Build Coastguard Worker 
1062*f6dc9357SAndroid Build Coastguard Worker 
1063*f6dc9357SAndroid Build Coastguard Worker bool CHandler::CheckBat()
1064*f6dc9357SAndroid Build Coastguard Worker {
1065*f6dc9357SAndroid Build Coastguard Worker   const UInt64 upSize = _phySize + kBitmapSize * 8 - 1;
1066*f6dc9357SAndroid Build Coastguard Worker   if (upSize < _phySize)
1067*f6dc9357SAndroid Build Coastguard Worker     return false;
1068*f6dc9357SAndroid Build Coastguard Worker   const UInt64 useMapSize64 = upSize >> (kBitmapSize_Log + 3);
1069*f6dc9357SAndroid Build Coastguard Worker   const size_t useMapSize = (size_t)useMapSize64;
1070*f6dc9357SAndroid Build Coastguard Worker 
1071*f6dc9357SAndroid Build Coastguard Worker   const UInt32 blockSizeMB = (UInt32)1 << (Meta.BlockSize_Log - kBitmapSize_Log);
1072*f6dc9357SAndroid Build Coastguard Worker 
1073*f6dc9357SAndroid Build Coastguard Worker   // we don't check useMap, if it's too big.
1074*f6dc9357SAndroid Build Coastguard Worker   if (useMapSize != useMapSize64)
1075*f6dc9357SAndroid Build Coastguard Worker     return true;
1076*f6dc9357SAndroid Build Coastguard Worker   if (useMapSize == 0 || useMapSize > ((size_t)1 << 28))
1077*f6dc9357SAndroid Build Coastguard Worker     return true;
1078*f6dc9357SAndroid Build Coastguard Worker 
1079*f6dc9357SAndroid Build Coastguard Worker   CByteArr useMap;
1080*f6dc9357SAndroid Build Coastguard Worker   useMap.Alloc(useMapSize);
1081*f6dc9357SAndroid Build Coastguard Worker   memset(useMap, 0, useMapSize);
1082*f6dc9357SAndroid Build Coastguard Worker   // useMap[0] = (Byte)(1 << 0); // first 1 MB is used by headers
1083*f6dc9357SAndroid Build Coastguard Worker   // we can also update useMap for log, and region data.
1084*f6dc9357SAndroid Build Coastguard Worker 
1085*f6dc9357SAndroid Build Coastguard Worker   const size_t totalBatEntries = TotalBatEntries;
1086*f6dc9357SAndroid Build Coastguard Worker   size_t remEntries = ChunkRatio + 1;
1087*f6dc9357SAndroid Build Coastguard Worker 
1088*f6dc9357SAndroid Build Coastguard Worker   size_t i;
1089*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < totalBatEntries; i++)
1090*f6dc9357SAndroid Build Coastguard Worker   {
1091*f6dc9357SAndroid Build Coastguard Worker     const UInt64 v = Bat.GetItem(i);
1092*f6dc9357SAndroid Build Coastguard Worker     const UInt64 offset = BAT_GET_OFFSET(v);
1093*f6dc9357SAndroid Build Coastguard Worker     const unsigned state = BAT_GET_STATE(v);
1094*f6dc9357SAndroid Build Coastguard Worker     const UInt64 index = offset >> kBitmapSize_Log;
1095*f6dc9357SAndroid Build Coastguard Worker     UInt32 numBlocks = 1;
1096*f6dc9357SAndroid Build Coastguard Worker     remEntries--;
1097*f6dc9357SAndroid Build Coastguard Worker     if (remEntries == 0)
1098*f6dc9357SAndroid Build Coastguard Worker     {
1099*f6dc9357SAndroid Build Coastguard Worker       remEntries = ChunkRatio + 1;
1100*f6dc9357SAndroid Build Coastguard Worker       if (state != SB_BLOCK_PRESENT)
1101*f6dc9357SAndroid Build Coastguard Worker         continue;
1102*f6dc9357SAndroid Build Coastguard Worker     }
1103*f6dc9357SAndroid Build Coastguard Worker     else
1104*f6dc9357SAndroid Build Coastguard Worker     {
1105*f6dc9357SAndroid Build Coastguard Worker       if (state != PAYLOAD_BLOCK_FULLY_PRESENT &&
1106*f6dc9357SAndroid Build Coastguard Worker           state != PAYLOAD_BLOCK_PARTIALLY_PRESENT)
1107*f6dc9357SAndroid Build Coastguard Worker         continue;
1108*f6dc9357SAndroid Build Coastguard Worker       numBlocks = blockSizeMB;
1109*f6dc9357SAndroid Build Coastguard Worker     }
1110*f6dc9357SAndroid Build Coastguard Worker 
1111*f6dc9357SAndroid Build Coastguard Worker     for (unsigned k = 0; k < numBlocks; k++)
1112*f6dc9357SAndroid Build Coastguard Worker     {
1113*f6dc9357SAndroid Build Coastguard Worker       const UInt64 index2 = index + k;
1114*f6dc9357SAndroid Build Coastguard Worker       const unsigned flag = (unsigned)1 << ((unsigned)index2 & 7);
1115*f6dc9357SAndroid Build Coastguard Worker       const size_t byteIndex = (size_t)(index2 >> 3);
1116*f6dc9357SAndroid Build Coastguard Worker       if (byteIndex >= useMapSize)
1117*f6dc9357SAndroid Build Coastguard Worker         return false;
1118*f6dc9357SAndroid Build Coastguard Worker       const unsigned m = useMap[byteIndex];
1119*f6dc9357SAndroid Build Coastguard Worker       if (m & flag)
1120*f6dc9357SAndroid Build Coastguard Worker         return false;
1121*f6dc9357SAndroid Build Coastguard Worker       useMap[byteIndex] = (Byte)(m | flag);
1122*f6dc9357SAndroid Build Coastguard Worker     }
1123*f6dc9357SAndroid Build Coastguard Worker   }
1124*f6dc9357SAndroid Build Coastguard Worker 
1125*f6dc9357SAndroid Build Coastguard Worker   /*
1126*f6dc9357SAndroid Build Coastguard Worker   UInt64 num = 0;
1127*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < useMapSize; i++)
1128*f6dc9357SAndroid Build Coastguard Worker   {
1129*f6dc9357SAndroid Build Coastguard Worker     Byte b = useMap[i];
1130*f6dc9357SAndroid Build Coastguard Worker     unsigned t = 0;
1131*f6dc9357SAndroid Build Coastguard Worker     t += (b & 1);  b >>= 1;
1132*f6dc9357SAndroid Build Coastguard Worker     t += (b & 1);  b >>= 1;
1133*f6dc9357SAndroid Build Coastguard Worker     t += (b & 1);  b >>= 1;
1134*f6dc9357SAndroid Build Coastguard Worker     t += (b & 1);  b >>= 1;
1135*f6dc9357SAndroid Build Coastguard Worker     t += (b & 1);  b >>= 1;
1136*f6dc9357SAndroid Build Coastguard Worker     t += (b & 1);  b >>= 1;
1137*f6dc9357SAndroid Build Coastguard Worker     t += (b & 1);  b >>= 1;
1138*f6dc9357SAndroid Build Coastguard Worker     t += (b & 1);
1139*f6dc9357SAndroid Build Coastguard Worker     num += t;
1140*f6dc9357SAndroid Build Coastguard Worker   }
1141*f6dc9357SAndroid Build Coastguard Worker   NumUsed_1MB_Blocks = num;
1142*f6dc9357SAndroid Build Coastguard Worker   NumUsed_1MB_Blocks_Defined = true;
1143*f6dc9357SAndroid Build Coastguard Worker   */
1144*f6dc9357SAndroid Build Coastguard Worker 
1145*f6dc9357SAndroid Build Coastguard Worker   return true;
1146*f6dc9357SAndroid Build Coastguard Worker }
1147*f6dc9357SAndroid Build Coastguard Worker 
1148*f6dc9357SAndroid Build Coastguard Worker 
1149*f6dc9357SAndroid Build Coastguard Worker 
1150*f6dc9357SAndroid Build Coastguard Worker HRESULT CHandler::Open3()
1151*f6dc9357SAndroid Build Coastguard Worker {
1152*f6dc9357SAndroid Build Coastguard Worker   {
1153*f6dc9357SAndroid Build Coastguard Worker     const unsigned kHeaderSize = 512; // + 8
1154*f6dc9357SAndroid Build Coastguard Worker     Byte header[kHeaderSize];
1155*f6dc9357SAndroid Build Coastguard Worker 
1156*f6dc9357SAndroid Build Coastguard Worker     RINOK(Read_FALSE(header, kHeaderSize))
1157*f6dc9357SAndroid Build Coastguard Worker 
1158*f6dc9357SAndroid Build Coastguard Worker     if (memcmp(header, kSignature, kSignatureSize) != 0)
1159*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1160*f6dc9357SAndroid Build Coastguard Worker 
1161*f6dc9357SAndroid Build Coastguard Worker     const Byte *p = &header[0];
1162*f6dc9357SAndroid Build Coastguard Worker     for (unsigned i = kSignatureSize; i < kHeaderSize; i += 2)
1163*f6dc9357SAndroid Build Coastguard Worker     {
1164*f6dc9357SAndroid Build Coastguard Worker       const wchar_t c = Get16(p + i);
1165*f6dc9357SAndroid Build Coastguard Worker       if (c < 0x20 || c > 0x7F)
1166*f6dc9357SAndroid Build Coastguard Worker         break;
1167*f6dc9357SAndroid Build Coastguard Worker       _creator += c;
1168*f6dc9357SAndroid Build Coastguard Worker     }
1169*f6dc9357SAndroid Build Coastguard Worker   }
1170*f6dc9357SAndroid Build Coastguard Worker 
1171*f6dc9357SAndroid Build Coastguard Worker   HeadersSize = (UInt32)1 << 20;
1172*f6dc9357SAndroid Build Coastguard Worker   CHeader headers[2];
1173*f6dc9357SAndroid Build Coastguard Worker   {
1174*f6dc9357SAndroid Build Coastguard Worker     Byte header[kHeader2Size];
1175*f6dc9357SAndroid Build Coastguard Worker     for (unsigned i = 0; i < 2; i++)
1176*f6dc9357SAndroid Build Coastguard Worker     {
1177*f6dc9357SAndroid Build Coastguard Worker       RINOK(Seek2((1 << 16) * (1 + i)))
1178*f6dc9357SAndroid Build Coastguard Worker       RINOK(Read_FALSE(header, kHeader2Size))
1179*f6dc9357SAndroid Build Coastguard Worker       bool headerIsOK = headers[i].Parse(header);
1180*f6dc9357SAndroid Build Coastguard Worker       if (!headerIsOK)
1181*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
1182*f6dc9357SAndroid Build Coastguard Worker     }
1183*f6dc9357SAndroid Build Coastguard Worker   }
1184*f6dc9357SAndroid Build Coastguard Worker   unsigned mainIndex;
1185*f6dc9357SAndroid Build Coastguard Worker        if (headers[0].SequenceNumber > headers[1].SequenceNumber) mainIndex = 0;
1186*f6dc9357SAndroid Build Coastguard Worker   else if (headers[0].SequenceNumber < headers[1].SequenceNumber) mainIndex = 1;
1187*f6dc9357SAndroid Build Coastguard Worker   else
1188*f6dc9357SAndroid Build Coastguard Worker   {
1189*f6dc9357SAndroid Build Coastguard Worker     /* Disk2vhd v2.02 can create image with 2 full copies of headers.
1190*f6dc9357SAndroid Build Coastguard Worker        It's violation of VHDX specification:
1191*f6dc9357SAndroid Build Coastguard Worker           "A header is current if it is the only valid header
1192*f6dc9357SAndroid Build Coastguard Worker            or if it is valid and its SequenceNumber field is
1193*f6dc9357SAndroid Build Coastguard Worker            greater than the other header's SequenceNumber".
1194*f6dc9357SAndroid Build Coastguard Worker        but we support such Disk2vhd archives. */
1195*f6dc9357SAndroid Build Coastguard Worker     if (!headers[0].IsEqualTo(headers[1]))
1196*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1197*f6dc9357SAndroid Build Coastguard Worker     mainIndex = 0;
1198*f6dc9357SAndroid Build Coastguard Worker   }
1199*f6dc9357SAndroid Build Coastguard Worker 
1200*f6dc9357SAndroid Build Coastguard Worker   const CHeader &h = headers[mainIndex];
1201*f6dc9357SAndroid Build Coastguard Worker   Header = h;
1202*f6dc9357SAndroid Build Coastguard Worker   if (h.LogLength != 0)
1203*f6dc9357SAndroid Build Coastguard Worker   {
1204*f6dc9357SAndroid Build Coastguard Worker     HeadersSize += h.LogLength;
1205*f6dc9357SAndroid Build Coastguard Worker     UpdatePhySize(h.LogOffset + h.LogLength);
1206*f6dc9357SAndroid Build Coastguard Worker     if (!h.Guids[kHeader_GUID_Index_LogGuid].IsZero())
1207*f6dc9357SAndroid Build Coastguard Worker     {
1208*f6dc9357SAndroid Build Coastguard Worker       _nonEmptyLog = true;
1209*f6dc9357SAndroid Build Coastguard Worker       AddErrorMessage("non-empty LOG was not replayed");
1210*f6dc9357SAndroid Build Coastguard Worker       /*
1211*f6dc9357SAndroid Build Coastguard Worker       if (h.LogVersion != 0)
1212*f6dc9357SAndroid Build Coastguard Worker         AddErrorMessage("unknown LogVresion");
1213*f6dc9357SAndroid Build Coastguard Worker       else
1214*f6dc9357SAndroid Build Coastguard Worker       {
1215*f6dc9357SAndroid Build Coastguard Worker         CByteBuffer log;
1216*f6dc9357SAndroid Build Coastguard Worker         RINOK(Seek2(h.LogOffset));
1217*f6dc9357SAndroid Build Coastguard Worker         RINOK(ReadToBuf_FALSE(log, h.LogLength));
1218*f6dc9357SAndroid Build Coastguard Worker         if (!ParseLog(log))
1219*f6dc9357SAndroid Build Coastguard Worker         {
1220*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
1221*f6dc9357SAndroid Build Coastguard Worker         }
1222*f6dc9357SAndroid Build Coastguard Worker       }
1223*f6dc9357SAndroid Build Coastguard Worker       */
1224*f6dc9357SAndroid Build Coastguard Worker     }
1225*f6dc9357SAndroid Build Coastguard Worker   }
1226*f6dc9357SAndroid Build Coastguard Worker   CRegion regions[2];
1227*f6dc9357SAndroid Build Coastguard Worker   int correctRegionIndex = -1;
1228*f6dc9357SAndroid Build Coastguard Worker 
1229*f6dc9357SAndroid Build Coastguard Worker   {
1230*f6dc9357SAndroid Build Coastguard Worker     CByteBuffer temp;
1231*f6dc9357SAndroid Build Coastguard Worker     temp.Alloc(kRegionSize * 2);
1232*f6dc9357SAndroid Build Coastguard Worker     RINOK(Seek2((1 << 16) * 3))
1233*f6dc9357SAndroid Build Coastguard Worker     RINOK(Read_FALSE(temp, kRegionSize * 2))
1234*f6dc9357SAndroid Build Coastguard Worker     unsigned numTables = 1;
1235*f6dc9357SAndroid Build Coastguard Worker     if (memcmp(temp, temp + kRegionSize, kRegionSize) != 0)
1236*f6dc9357SAndroid Build Coastguard Worker     {
1237*f6dc9357SAndroid Build Coastguard Worker       AddErrorMessage("Region tables mismatch");
1238*f6dc9357SAndroid Build Coastguard Worker       numTables = 2;
1239*f6dc9357SAndroid Build Coastguard Worker     }
1240*f6dc9357SAndroid Build Coastguard Worker 
1241*f6dc9357SAndroid Build Coastguard Worker     for (unsigned i = 0; i < numTables; i++)
1242*f6dc9357SAndroid Build Coastguard Worker     {
1243*f6dc9357SAndroid Build Coastguard Worker       // RINOK(Seek2((1 << 16) * (3 + i)));
1244*f6dc9357SAndroid Build Coastguard Worker       // RINOK(Read_FALSE(temp, kRegionSize));
1245*f6dc9357SAndroid Build Coastguard Worker       if (regions[i].Parse(temp))
1246*f6dc9357SAndroid Build Coastguard Worker       {
1247*f6dc9357SAndroid Build Coastguard Worker         if (correctRegionIndex < 0)
1248*f6dc9357SAndroid Build Coastguard Worker           correctRegionIndex = (int)i;
1249*f6dc9357SAndroid Build Coastguard Worker       }
1250*f6dc9357SAndroid Build Coastguard Worker       else
1251*f6dc9357SAndroid Build Coastguard Worker       {
1252*f6dc9357SAndroid Build Coastguard Worker         AddErrorMessage("Incorrect region table");
1253*f6dc9357SAndroid Build Coastguard Worker       }
1254*f6dc9357SAndroid Build Coastguard Worker     }
1255*f6dc9357SAndroid Build Coastguard Worker     if (correctRegionIndex < 0)
1256*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1257*f6dc9357SAndroid Build Coastguard Worker     /*
1258*f6dc9357SAndroid Build Coastguard Worker     if (!regions[0].IsEqualTo(regions[1]))
1259*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1260*f6dc9357SAndroid Build Coastguard Worker     */
1261*f6dc9357SAndroid Build Coastguard Worker   }
1262*f6dc9357SAndroid Build Coastguard Worker 
1263*f6dc9357SAndroid Build Coastguard Worker   // UpdatePhySize((1 << 16) * 5);
1264*f6dc9357SAndroid Build Coastguard Worker   UpdatePhySize(1 << 20);
1265*f6dc9357SAndroid Build Coastguard Worker 
1266*f6dc9357SAndroid Build Coastguard Worker   {
1267*f6dc9357SAndroid Build Coastguard Worker     const CRegion &region = regions[correctRegionIndex];
1268*f6dc9357SAndroid Build Coastguard Worker     HeadersSize += region.DataSize;
1269*f6dc9357SAndroid Build Coastguard Worker     UpdatePhySize(region.EndPos);
1270*f6dc9357SAndroid Build Coastguard Worker     {
1271*f6dc9357SAndroid Build Coastguard Worker       if (!region.Meta_Defined)
1272*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
1273*f6dc9357SAndroid Build Coastguard Worker       const CRegionEntry &e = region.MetaEntry;
1274*f6dc9357SAndroid Build Coastguard Worker       if (e.Len == 0)
1275*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
1276*f6dc9357SAndroid Build Coastguard Worker       {
1277*f6dc9357SAndroid Build Coastguard Worker         // static const kMetaTableSize = 1 << 16;
1278*f6dc9357SAndroid Build Coastguard Worker         CByteBuffer temp;
1279*f6dc9357SAndroid Build Coastguard Worker         {
1280*f6dc9357SAndroid Build Coastguard Worker           RINOK(Seek2(e.Offset))
1281*f6dc9357SAndroid Build Coastguard Worker           RINOK(ReadToBuf_FALSE(temp, e.Len))
1282*f6dc9357SAndroid Build Coastguard Worker         }
1283*f6dc9357SAndroid Build Coastguard Worker         if (!Meta.Parse(temp, temp.Size()))
1284*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
1285*f6dc9357SAndroid Build Coastguard Worker       }
1286*f6dc9357SAndroid Build Coastguard Worker       // UpdatePhySize(e.GetEndPos());
1287*f6dc9357SAndroid Build Coastguard Worker     }
1288*f6dc9357SAndroid Build Coastguard Worker     {
1289*f6dc9357SAndroid Build Coastguard Worker       if (!region.Bat_Defined)
1290*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
1291*f6dc9357SAndroid Build Coastguard Worker       const CRegionEntry &e = region.BatEntry;
1292*f6dc9357SAndroid Build Coastguard Worker       if (e.Len == 0)
1293*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
1294*f6dc9357SAndroid Build Coastguard Worker       // UpdatePhySize(e.GetEndPos());
1295*f6dc9357SAndroid Build Coastguard Worker       {
1296*f6dc9357SAndroid Build Coastguard Worker         RINOK(Seek2(e.Offset))
1297*f6dc9357SAndroid Build Coastguard Worker         RINOK(ReadToBuf_FALSE(Bat.Data, e.Len))
1298*f6dc9357SAndroid Build Coastguard Worker       }
1299*f6dc9357SAndroid Build Coastguard Worker       if (!ParseBat())
1300*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
1301*f6dc9357SAndroid Build Coastguard Worker       if (!CheckBat())
1302*f6dc9357SAndroid Build Coastguard Worker       {
1303*f6dc9357SAndroid Build Coastguard Worker         AddErrorMessage("BAT overlap");
1304*f6dc9357SAndroid Build Coastguard Worker         // _batOverlap = true;
1305*f6dc9357SAndroid Build Coastguard Worker         // return S_FALSE;
1306*f6dc9357SAndroid Build Coastguard Worker       }
1307*f6dc9357SAndroid Build Coastguard Worker     }
1308*f6dc9357SAndroid Build Coastguard Worker   }
1309*f6dc9357SAndroid Build Coastguard Worker 
1310*f6dc9357SAndroid Build Coastguard Worker   {
1311*f6dc9357SAndroid Build Coastguard Worker     // do we need to check "parent_linkage2" also?
1312*f6dc9357SAndroid Build Coastguard Worker     FOR_VECTOR (i, Meta.ParentPairs)
1313*f6dc9357SAndroid Build Coastguard Worker     {
1314*f6dc9357SAndroid Build Coastguard Worker       const CParentPair &pair = Meta.ParentPairs[i];
1315*f6dc9357SAndroid Build Coastguard Worker       if (pair.Key.IsEqualTo("parent_linkage"))
1316*f6dc9357SAndroid Build Coastguard Worker       {
1317*f6dc9357SAndroid Build Coastguard Worker         _parentGuid_IsDefined = _parentGuid.ParseFromFormatedHexString(pair.Value);
1318*f6dc9357SAndroid Build Coastguard Worker         break;
1319*f6dc9357SAndroid Build Coastguard Worker       }
1320*f6dc9357SAndroid Build Coastguard Worker     }
1321*f6dc9357SAndroid Build Coastguard Worker   }
1322*f6dc9357SAndroid Build Coastguard Worker 
1323*f6dc9357SAndroid Build Coastguard Worker   {
1324*f6dc9357SAndroid Build Coastguard Worker     // absolute paths for parent stream can be rejected later in client callback
1325*f6dc9357SAndroid Build Coastguard Worker     // the order of check by specification:
1326*f6dc9357SAndroid Build Coastguard Worker     const char * const g_ParentKeys[] =
1327*f6dc9357SAndroid Build Coastguard Worker     {
1328*f6dc9357SAndroid Build Coastguard Worker         "relative_path"       // "..\..\path2\sub3\parent.vhdx"
1329*f6dc9357SAndroid Build Coastguard Worker       , "volume_path"         // "\\?\Volume{26A21BDA-A627-11D7-9931-806E6F6E6963}\path2\sub3\parent.vhdx")
1330*f6dc9357SAndroid Build Coastguard Worker       , "absolute_win32_path" // "d:\path2\sub3\parent.vhdx"
1331*f6dc9357SAndroid Build Coastguard Worker     };
1332*f6dc9357SAndroid Build Coastguard Worker     for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_ParentKeys); i++)
1333*f6dc9357SAndroid Build Coastguard Worker     {
1334*f6dc9357SAndroid Build Coastguard Worker       const int index = Meta.FindParentKey(g_ParentKeys[i]);
1335*f6dc9357SAndroid Build Coastguard Worker       if (index < 0)
1336*f6dc9357SAndroid Build Coastguard Worker         continue;
1337*f6dc9357SAndroid Build Coastguard Worker       ParentNames.Add(Meta.ParentPairs[index].Value);
1338*f6dc9357SAndroid Build Coastguard Worker     }
1339*f6dc9357SAndroid Build Coastguard Worker   }
1340*f6dc9357SAndroid Build Coastguard Worker 
1341*f6dc9357SAndroid Build Coastguard Worker   if (Meta.Is_HasParent())
1342*f6dc9357SAndroid Build Coastguard Worker   {
1343*f6dc9357SAndroid Build Coastguard Worker     if (!Meta.Locator_Defined)
1344*f6dc9357SAndroid Build Coastguard Worker       AddErrorMessage("Parent locator is not defined");
1345*f6dc9357SAndroid Build Coastguard Worker     else
1346*f6dc9357SAndroid Build Coastguard Worker     {
1347*f6dc9357SAndroid Build Coastguard Worker       if (!_parentGuid_IsDefined)
1348*f6dc9357SAndroid Build Coastguard Worker         AddErrorMessage("Parent GUID is not defined");
1349*f6dc9357SAndroid Build Coastguard Worker       if (ParentNames.IsEmpty())
1350*f6dc9357SAndroid Build Coastguard Worker         AddErrorMessage("Parent VHDX file name is not defined");
1351*f6dc9357SAndroid Build Coastguard Worker     }
1352*f6dc9357SAndroid Build Coastguard Worker   }
1353*f6dc9357SAndroid Build Coastguard Worker   else
1354*f6dc9357SAndroid Build Coastguard Worker   {
1355*f6dc9357SAndroid Build Coastguard Worker     if (Meta.Locator_Defined)
1356*f6dc9357SAndroid Build Coastguard Worker       AddErrorMessage("Unexpected parent locator");
1357*f6dc9357SAndroid Build Coastguard Worker   }
1358*f6dc9357SAndroid Build Coastguard Worker 
1359*f6dc9357SAndroid Build Coastguard Worker   // here we suppose that and locator can be used only with HasParent flag
1360*f6dc9357SAndroid Build Coastguard Worker 
1361*f6dc9357SAndroid Build Coastguard Worker   // return S_FALSE;
1362*f6dc9357SAndroid Build Coastguard Worker 
1363*f6dc9357SAndroid Build Coastguard Worker   _size = Meta.VirtualDiskSize; // CHandlerImg
1364*f6dc9357SAndroid Build Coastguard Worker 
1365*f6dc9357SAndroid Build Coastguard Worker   // _posInArc = 0;
1366*f6dc9357SAndroid Build Coastguard Worker   // Reset_PosInArc();
1367*f6dc9357SAndroid Build Coastguard Worker   // RINOK(InStream_SeekToBegin(Stream))
1368*f6dc9357SAndroid Build Coastguard Worker 
1369*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1370*f6dc9357SAndroid Build Coastguard Worker }
1371*f6dc9357SAndroid Build Coastguard Worker 
1372*f6dc9357SAndroid Build Coastguard Worker 
1373*f6dc9357SAndroid Build Coastguard Worker /*
1374*f6dc9357SAndroid Build Coastguard Worker static UInt32 g_NumCalls = 0;
1375*f6dc9357SAndroid Build Coastguard Worker static UInt32 g_NumCalls2 = 0;
1376*f6dc9357SAndroid Build Coastguard Worker static struct CCounter { ~CCounter()
1377*f6dc9357SAndroid Build Coastguard Worker {
1378*f6dc9357SAndroid Build Coastguard Worker   printf("\nNumCalls = %10u\n", g_NumCalls);
1379*f6dc9357SAndroid Build Coastguard Worker   printf("NumCalls2 = %10u\n", g_NumCalls2);
1380*f6dc9357SAndroid Build Coastguard Worker } } g_Counter;
1381*f6dc9357SAndroid Build Coastguard Worker */
1382*f6dc9357SAndroid Build Coastguard Worker 
1383*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Read(void *data, UInt32 size, UInt32 *processedSize))
1384*f6dc9357SAndroid Build Coastguard Worker {
1385*f6dc9357SAndroid Build Coastguard Worker   // g_NumCalls++;
1386*f6dc9357SAndroid Build Coastguard Worker   if (processedSize)
1387*f6dc9357SAndroid Build Coastguard Worker     *processedSize = 0;
1388*f6dc9357SAndroid Build Coastguard Worker   if (_virtPos >= Meta.VirtualDiskSize)
1389*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
1390*f6dc9357SAndroid Build Coastguard Worker   {
1391*f6dc9357SAndroid Build Coastguard Worker     const UInt64 rem = Meta.VirtualDiskSize - _virtPos;
1392*f6dc9357SAndroid Build Coastguard Worker     if (size > rem)
1393*f6dc9357SAndroid Build Coastguard Worker       size = (UInt32)rem;
1394*f6dc9357SAndroid Build Coastguard Worker   }
1395*f6dc9357SAndroid Build Coastguard Worker   if (size == 0)
1396*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
1397*f6dc9357SAndroid Build Coastguard Worker   const size_t blockIndex = (size_t)(_virtPos >> Meta.BlockSize_Log);
1398*f6dc9357SAndroid Build Coastguard Worker   const size_t chunkIndex = blockIndex >> ChunkRatio_Log;
1399*f6dc9357SAndroid Build Coastguard Worker   const size_t chunkRatio = (size_t)1 << ChunkRatio_Log;
1400*f6dc9357SAndroid Build Coastguard Worker   const size_t blockIndex2 = chunkIndex * (chunkRatio + 1) + (blockIndex & (chunkRatio - 1));
1401*f6dc9357SAndroid Build Coastguard Worker   const UInt64 blockSectVal = Bat.GetItem(blockIndex2);
1402*f6dc9357SAndroid Build Coastguard Worker   const UInt64 blockOffset = BAT_GET_OFFSET(blockSectVal);
1403*f6dc9357SAndroid Build Coastguard Worker   const UInt32 blockState = BAT_GET_STATE(blockSectVal);
1404*f6dc9357SAndroid Build Coastguard Worker 
1405*f6dc9357SAndroid Build Coastguard Worker   const UInt32 blockSize = (UInt32)1 << Meta.BlockSize_Log;
1406*f6dc9357SAndroid Build Coastguard Worker   const UInt32 offsetInBlock = (UInt32)_virtPos & (blockSize - 1);
1407*f6dc9357SAndroid Build Coastguard Worker   size = MyMin(blockSize - offsetInBlock, size);
1408*f6dc9357SAndroid Build Coastguard Worker 
1409*f6dc9357SAndroid Build Coastguard Worker   bool needParent = false;
1410*f6dc9357SAndroid Build Coastguard Worker   bool needRead = false;
1411*f6dc9357SAndroid Build Coastguard Worker 
1412*f6dc9357SAndroid Build Coastguard Worker   if (blockState == PAYLOAD_BLOCK_FULLY_PRESENT)
1413*f6dc9357SAndroid Build Coastguard Worker     needRead = true;
1414*f6dc9357SAndroid Build Coastguard Worker   else if (blockState == PAYLOAD_BLOCK_NOT_PRESENT)
1415*f6dc9357SAndroid Build Coastguard Worker   {
1416*f6dc9357SAndroid Build Coastguard Worker     /* for a differencing VHDX: parent virtual disk SHOULD be
1417*f6dc9357SAndroid Build Coastguard Worker          inspected to determine the associated contents (SPECIFICATION).
1418*f6dc9357SAndroid Build Coastguard Worker          we suppose that we should not check BitMap.
1419*f6dc9357SAndroid Build Coastguard Worker        for fixed or dynamic VHDX files: the block contents are undefined and
1420*f6dc9357SAndroid Build Coastguard Worker          can contain arbitrary data (SPECIFICATION). NTFS::pagefile.sys can use such state. */
1421*f6dc9357SAndroid Build Coastguard Worker     if (IsDiff())
1422*f6dc9357SAndroid Build Coastguard Worker       needParent = true;
1423*f6dc9357SAndroid Build Coastguard Worker   }
1424*f6dc9357SAndroid Build Coastguard Worker   else if (blockState == PAYLOAD_BLOCK_PARTIALLY_PRESENT)
1425*f6dc9357SAndroid Build Coastguard Worker   {
1426*f6dc9357SAndroid Build Coastguard Worker     // only allowed for differencing VHDX files.
1427*f6dc9357SAndroid Build Coastguard Worker     // associated sector bitmap block MUST be valid
1428*f6dc9357SAndroid Build Coastguard Worker     if (chunkIndex >= BitMaps.Size())
1429*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1430*f6dc9357SAndroid Build Coastguard Worker     // else
1431*f6dc9357SAndroid Build Coastguard Worker     {
1432*f6dc9357SAndroid Build Coastguard Worker       const CByteBuffer &bitmap = BitMaps[(unsigned)chunkIndex];
1433*f6dc9357SAndroid Build Coastguard Worker       const Byte *p = (const Byte *)bitmap;
1434*f6dc9357SAndroid Build Coastguard Worker       if (!p)
1435*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
1436*f6dc9357SAndroid Build Coastguard Worker       // else
1437*f6dc9357SAndroid Build Coastguard Worker       {
1438*f6dc9357SAndroid Build Coastguard Worker         // g_NumCalls2++;
1439*f6dc9357SAndroid Build Coastguard Worker         const UInt64 sectorIndex = _virtPos >> Meta.LogicalSectorSize_Log;
1440*f6dc9357SAndroid Build Coastguard Worker 
1441*f6dc9357SAndroid Build Coastguard Worker         #define BIT_MAP_UNIT_LOG  3 // it's for small block (4 KB)
1442*f6dc9357SAndroid Build Coastguard Worker         // #define BIT_MAP_UNIT_LOG  5 // speed optimization for large blocks (16 KB)
1443*f6dc9357SAndroid Build Coastguard Worker 
1444*f6dc9357SAndroid Build Coastguard Worker         const size_t offs = (size_t)(sectorIndex >> 3) &
1445*f6dc9357SAndroid Build Coastguard Worker             (
1446*f6dc9357SAndroid Build Coastguard Worker               (kBitmapSize - 1)
1447*f6dc9357SAndroid Build Coastguard Worker               & ~(((UInt32)1 << (BIT_MAP_UNIT_LOG - 3)) - 1)
1448*f6dc9357SAndroid Build Coastguard Worker             );
1449*f6dc9357SAndroid Build Coastguard Worker 
1450*f6dc9357SAndroid Build Coastguard Worker         unsigned sector2 = (unsigned)sectorIndex & ((1 << BIT_MAP_UNIT_LOG) - 1);
1451*f6dc9357SAndroid Build Coastguard Worker       #if BIT_MAP_UNIT_LOG == 5
1452*f6dc9357SAndroid Build Coastguard Worker         UInt32 v = GetUi32(p + offs) >> sector2;
1453*f6dc9357SAndroid Build Coastguard Worker       #else
1454*f6dc9357SAndroid Build Coastguard Worker         unsigned v = (unsigned)p[offs] >> sector2;
1455*f6dc9357SAndroid Build Coastguard Worker       #endif
1456*f6dc9357SAndroid Build Coastguard Worker         // UInt32 v = GetUi32(p + offs) >> sector2;
1457*f6dc9357SAndroid Build Coastguard Worker         const UInt32 sectorSize = (UInt32)1 << Meta.LogicalSectorSize_Log;
1458*f6dc9357SAndroid Build Coastguard Worker         const UInt32 offsetInSector = (UInt32)_virtPos & (sectorSize - 1);
1459*f6dc9357SAndroid Build Coastguard Worker         const unsigned bit = (unsigned)(v & 1);
1460*f6dc9357SAndroid Build Coastguard Worker         if (bit)
1461*f6dc9357SAndroid Build Coastguard Worker           needRead = true;
1462*f6dc9357SAndroid Build Coastguard Worker         else
1463*f6dc9357SAndroid Build Coastguard Worker           needParent = true; // zero - from the parent VHDX file
1464*f6dc9357SAndroid Build Coastguard Worker         UInt32 rem = sectorSize - offsetInSector;
1465*f6dc9357SAndroid Build Coastguard Worker         for (sector2++; sector2 < (1 << BIT_MAP_UNIT_LOG); sector2++)
1466*f6dc9357SAndroid Build Coastguard Worker         {
1467*f6dc9357SAndroid Build Coastguard Worker           v >>= 1;
1468*f6dc9357SAndroid Build Coastguard Worker           if (bit != (v & 1))
1469*f6dc9357SAndroid Build Coastguard Worker             break;
1470*f6dc9357SAndroid Build Coastguard Worker           rem += sectorSize;
1471*f6dc9357SAndroid Build Coastguard Worker         }
1472*f6dc9357SAndroid Build Coastguard Worker         if (size > rem)
1473*f6dc9357SAndroid Build Coastguard Worker           size = rem;
1474*f6dc9357SAndroid Build Coastguard Worker       }
1475*f6dc9357SAndroid Build Coastguard Worker     }
1476*f6dc9357SAndroid Build Coastguard Worker   }
1477*f6dc9357SAndroid Build Coastguard Worker 
1478*f6dc9357SAndroid Build Coastguard Worker   bool needZero = true;
1479*f6dc9357SAndroid Build Coastguard Worker 
1480*f6dc9357SAndroid Build Coastguard Worker   HRESULT res = S_OK;
1481*f6dc9357SAndroid Build Coastguard Worker 
1482*f6dc9357SAndroid Build Coastguard Worker   if (needParent)
1483*f6dc9357SAndroid Build Coastguard Worker   {
1484*f6dc9357SAndroid Build Coastguard Worker     if (!ParentStream)
1485*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1486*f6dc9357SAndroid Build Coastguard Worker     // if (ParentStream)
1487*f6dc9357SAndroid Build Coastguard Worker     {
1488*f6dc9357SAndroid Build Coastguard Worker       RINOK(InStream_SeekSet(ParentStream, _virtPos))
1489*f6dc9357SAndroid Build Coastguard Worker       size_t processed = size;
1490*f6dc9357SAndroid Build Coastguard Worker       res = ReadStream(ParentStream, (Byte *)data, &processed);
1491*f6dc9357SAndroid Build Coastguard Worker       size = (UInt32)processed;
1492*f6dc9357SAndroid Build Coastguard Worker       needZero = false;
1493*f6dc9357SAndroid Build Coastguard Worker     }
1494*f6dc9357SAndroid Build Coastguard Worker   }
1495*f6dc9357SAndroid Build Coastguard Worker   else if (needRead)
1496*f6dc9357SAndroid Build Coastguard Worker   {
1497*f6dc9357SAndroid Build Coastguard Worker     UInt32 processed = 0;
1498*f6dc9357SAndroid Build Coastguard Worker     res = ReadPhy(blockOffset + offsetInBlock, data, size, processed);
1499*f6dc9357SAndroid Build Coastguard Worker     size = processed;
1500*f6dc9357SAndroid Build Coastguard Worker     needZero = false;
1501*f6dc9357SAndroid Build Coastguard Worker   }
1502*f6dc9357SAndroid Build Coastguard Worker 
1503*f6dc9357SAndroid Build Coastguard Worker   if (needZero)
1504*f6dc9357SAndroid Build Coastguard Worker     memset(data, 0, size);
1505*f6dc9357SAndroid Build Coastguard Worker 
1506*f6dc9357SAndroid Build Coastguard Worker   if (processedSize)
1507*f6dc9357SAndroid Build Coastguard Worker     *processedSize = size;
1508*f6dc9357SAndroid Build Coastguard Worker 
1509*f6dc9357SAndroid Build Coastguard Worker   _virtPos += size;
1510*f6dc9357SAndroid Build Coastguard Worker   return res;
1511*f6dc9357SAndroid Build Coastguard Worker }
1512*f6dc9357SAndroid Build Coastguard Worker 
1513*f6dc9357SAndroid Build Coastguard Worker 
1514*f6dc9357SAndroid Build Coastguard Worker enum
1515*f6dc9357SAndroid Build Coastguard Worker {
1516*f6dc9357SAndroid Build Coastguard Worker   kpidParent = kpidUserDefined
1517*f6dc9357SAndroid Build Coastguard Worker };
1518*f6dc9357SAndroid Build Coastguard Worker 
1519*f6dc9357SAndroid Build Coastguard Worker static const CStatProp kArcProps[] =
1520*f6dc9357SAndroid Build Coastguard Worker {
1521*f6dc9357SAndroid Build Coastguard Worker   { NULL, kpidClusterSize, VT_UI4},
1522*f6dc9357SAndroid Build Coastguard Worker   { NULL, kpidSectorSize, VT_UI4},
1523*f6dc9357SAndroid Build Coastguard Worker   { NULL, kpidMethod, VT_BSTR},
1524*f6dc9357SAndroid Build Coastguard Worker   { NULL, kpidNumVolumes, VT_UI4},
1525*f6dc9357SAndroid Build Coastguard Worker   { NULL, kpidTotalPhySize, VT_UI8},
1526*f6dc9357SAndroid Build Coastguard Worker   { "Parent", kpidParent, VT_BSTR},
1527*f6dc9357SAndroid Build Coastguard Worker   { NULL, kpidCreatorApp, VT_BSTR},
1528*f6dc9357SAndroid Build Coastguard Worker   { NULL, kpidComment, VT_BSTR},
1529*f6dc9357SAndroid Build Coastguard Worker   { NULL, kpidId, VT_BSTR}
1530*f6dc9357SAndroid Build Coastguard Worker  };
1531*f6dc9357SAndroid Build Coastguard Worker 
1532*f6dc9357SAndroid Build Coastguard Worker static const Byte kProps[] =
1533*f6dc9357SAndroid Build Coastguard Worker {
1534*f6dc9357SAndroid Build Coastguard Worker   kpidSize,
1535*f6dc9357SAndroid Build Coastguard Worker   kpidPackSize
1536*f6dc9357SAndroid Build Coastguard Worker };
1537*f6dc9357SAndroid Build Coastguard Worker 
1538*f6dc9357SAndroid Build Coastguard Worker IMP_IInArchive_Props
1539*f6dc9357SAndroid Build Coastguard Worker IMP_IInArchive_ArcProps_WITH_NAME
1540*f6dc9357SAndroid Build Coastguard Worker 
1541*f6dc9357SAndroid Build Coastguard Worker 
1542*f6dc9357SAndroid Build Coastguard Worker void CHandler::AddErrorMessage(const char *message)
1543*f6dc9357SAndroid Build Coastguard Worker {
1544*f6dc9357SAndroid Build Coastguard Worker   if (!_errorMessage.IsEmpty())
1545*f6dc9357SAndroid Build Coastguard Worker     _errorMessage.Add_LF();
1546*f6dc9357SAndroid Build Coastguard Worker   _errorMessage += message;
1547*f6dc9357SAndroid Build Coastguard Worker }
1548*f6dc9357SAndroid Build Coastguard Worker 
1549*f6dc9357SAndroid Build Coastguard Worker void CHandler::AddErrorMessage(const char *message, const wchar_t *name)
1550*f6dc9357SAndroid Build Coastguard Worker {
1551*f6dc9357SAndroid Build Coastguard Worker   AddErrorMessage(message);
1552*f6dc9357SAndroid Build Coastguard Worker   _errorMessage += name;
1553*f6dc9357SAndroid Build Coastguard Worker }
1554*f6dc9357SAndroid Build Coastguard Worker 
1555*f6dc9357SAndroid Build Coastguard Worker 
1556*f6dc9357SAndroid Build Coastguard Worker static void AddComment_Name(UString &s, const char *name)
1557*f6dc9357SAndroid Build Coastguard Worker {
1558*f6dc9357SAndroid Build Coastguard Worker   s += name;
1559*f6dc9357SAndroid Build Coastguard Worker   s += ": ";
1560*f6dc9357SAndroid Build Coastguard Worker }
1561*f6dc9357SAndroid Build Coastguard Worker 
1562*f6dc9357SAndroid Build Coastguard Worker static void AddComment_Bool(UString &s, const char *name, bool val)
1563*f6dc9357SAndroid Build Coastguard Worker {
1564*f6dc9357SAndroid Build Coastguard Worker   AddComment_Name(s, name);
1565*f6dc9357SAndroid Build Coastguard Worker   s.Add_Char(val ? '+' : '-');
1566*f6dc9357SAndroid Build Coastguard Worker   s.Add_LF();
1567*f6dc9357SAndroid Build Coastguard Worker }
1568*f6dc9357SAndroid Build Coastguard Worker 
1569*f6dc9357SAndroid Build Coastguard Worker static void AddComment_UInt64(UString &s, const char *name, UInt64 v, bool showMB = false)
1570*f6dc9357SAndroid Build Coastguard Worker {
1571*f6dc9357SAndroid Build Coastguard Worker   AddComment_Name(s, name);
1572*f6dc9357SAndroid Build Coastguard Worker   s.Add_UInt64(v);
1573*f6dc9357SAndroid Build Coastguard Worker   if (showMB)
1574*f6dc9357SAndroid Build Coastguard Worker   {
1575*f6dc9357SAndroid Build Coastguard Worker     s += " (";
1576*f6dc9357SAndroid Build Coastguard Worker     s.Add_UInt64(v >> 20);
1577*f6dc9357SAndroid Build Coastguard Worker     s += " MiB)";
1578*f6dc9357SAndroid Build Coastguard Worker   }
1579*f6dc9357SAndroid Build Coastguard Worker   s.Add_LF();
1580*f6dc9357SAndroid Build Coastguard Worker }
1581*f6dc9357SAndroid Build Coastguard Worker 
1582*f6dc9357SAndroid Build Coastguard Worker static void AddComment_BlockSize(UString &s, const char *name, unsigned logSize)
1583*f6dc9357SAndroid Build Coastguard Worker {
1584*f6dc9357SAndroid Build Coastguard Worker   if (logSize != 0)
1585*f6dc9357SAndroid Build Coastguard Worker     AddComment_UInt64(s, name, ((UInt64)1 << logSize));
1586*f6dc9357SAndroid Build Coastguard Worker }
1587*f6dc9357SAndroid Build Coastguard Worker 
1588*f6dc9357SAndroid Build Coastguard Worker 
1589*f6dc9357SAndroid Build Coastguard Worker void CHandler::AddComment(UString &s) const
1590*f6dc9357SAndroid Build Coastguard Worker {
1591*f6dc9357SAndroid Build Coastguard Worker   AddComment_UInt64(s, "VirtualDiskSize", Meta.VirtualDiskSize);
1592*f6dc9357SAndroid Build Coastguard Worker   AddComment_UInt64(s, "PhysicalSize", _phySize);
1593*f6dc9357SAndroid Build Coastguard Worker 
1594*f6dc9357SAndroid Build Coastguard Worker   if (!_errorMessage.IsEmpty())
1595*f6dc9357SAndroid Build Coastguard Worker   {
1596*f6dc9357SAndroid Build Coastguard Worker     AddComment_Name(s, "Error");
1597*f6dc9357SAndroid Build Coastguard Worker     s += _errorMessage;
1598*f6dc9357SAndroid Build Coastguard Worker     s.Add_LF();
1599*f6dc9357SAndroid Build Coastguard Worker   }
1600*f6dc9357SAndroid Build Coastguard Worker 
1601*f6dc9357SAndroid Build Coastguard Worker   if (Meta.Guid_Defined)
1602*f6dc9357SAndroid Build Coastguard Worker   {
1603*f6dc9357SAndroid Build Coastguard Worker     AddComment_Name(s, "Id");
1604*f6dc9357SAndroid Build Coastguard Worker     Meta.Guid.AddHexToString(s);
1605*f6dc9357SAndroid Build Coastguard Worker     s.Add_LF();
1606*f6dc9357SAndroid Build Coastguard Worker   }
1607*f6dc9357SAndroid Build Coastguard Worker 
1608*f6dc9357SAndroid Build Coastguard Worker   AddComment_UInt64(s, "SequenceNumber", Header.SequenceNumber);
1609*f6dc9357SAndroid Build Coastguard Worker   AddComment_UInt64(s, "LogLength", Header.LogLength, true);
1610*f6dc9357SAndroid Build Coastguard Worker 
1611*f6dc9357SAndroid Build Coastguard Worker   for (unsigned i = 0; i < 3; i++)
1612*f6dc9357SAndroid Build Coastguard Worker   {
1613*f6dc9357SAndroid Build Coastguard Worker     const CGuid &g = Header.Guids[i];
1614*f6dc9357SAndroid Build Coastguard Worker     if (g.IsZero())
1615*f6dc9357SAndroid Build Coastguard Worker       continue;
1616*f6dc9357SAndroid Build Coastguard Worker     if (i == 0)
1617*f6dc9357SAndroid Build Coastguard Worker       s += "FileWrite";
1618*f6dc9357SAndroid Build Coastguard Worker     else if (i == 1)
1619*f6dc9357SAndroid Build Coastguard Worker       s += "DataWrite";
1620*f6dc9357SAndroid Build Coastguard Worker     else
1621*f6dc9357SAndroid Build Coastguard Worker       s += "Log";
1622*f6dc9357SAndroid Build Coastguard Worker     AddComment_Name(s, "Guid");
1623*f6dc9357SAndroid Build Coastguard Worker     g.AddHexToString(s);
1624*f6dc9357SAndroid Build Coastguard Worker     s.Add_LF();
1625*f6dc9357SAndroid Build Coastguard Worker   }
1626*f6dc9357SAndroid Build Coastguard Worker 
1627*f6dc9357SAndroid Build Coastguard Worker   AddComment_Bool(s, "HasParent", Meta.Is_HasParent());
1628*f6dc9357SAndroid Build Coastguard Worker   AddComment_Bool(s, "Fixed", Meta.Is_LeaveBlockAllocated());
1629*f6dc9357SAndroid Build Coastguard Worker   if (Meta.Is_LeaveBlockAllocated())
1630*f6dc9357SAndroid Build Coastguard Worker     AddComment_Bool(s, "DataContiguous", _isDataContiguous);
1631*f6dc9357SAndroid Build Coastguard Worker 
1632*f6dc9357SAndroid Build Coastguard Worker   AddComment_BlockSize(s, "BlockSize", Meta.BlockSize_Log);
1633*f6dc9357SAndroid Build Coastguard Worker   AddComment_BlockSize(s, "LogicalSectorSize", Meta.LogicalSectorSize_Log);
1634*f6dc9357SAndroid Build Coastguard Worker   AddComment_BlockSize(s, "PhysicalSectorSize", Meta.PhysicalSectorSize_Log);
1635*f6dc9357SAndroid Build Coastguard Worker 
1636*f6dc9357SAndroid Build Coastguard Worker   {
1637*f6dc9357SAndroid Build Coastguard Worker     const UInt64 packSize = GetPackSize();
1638*f6dc9357SAndroid Build Coastguard Worker     AddComment_UInt64(s, "PackSize", packSize, true);
1639*f6dc9357SAndroid Build Coastguard Worker     const UInt64 headersSize = HeadersSize + ((UInt64)NumUsedBitMaps << kBitmapSize_Log);
1640*f6dc9357SAndroid Build Coastguard Worker     AddComment_UInt64(s, "HeadersSize", headersSize, true);
1641*f6dc9357SAndroid Build Coastguard Worker     AddComment_UInt64(s, "FreeSpace", _phySize - packSize - headersSize, true);
1642*f6dc9357SAndroid Build Coastguard Worker     /*
1643*f6dc9357SAndroid Build Coastguard Worker     if (NumUsed_1MB_Blocks_Defined)
1644*f6dc9357SAndroid Build Coastguard Worker       AddComment_UInt64(s, "used2", (NumUsed_1MB_Blocks << 20));
1645*f6dc9357SAndroid Build Coastguard Worker     */
1646*f6dc9357SAndroid Build Coastguard Worker   }
1647*f6dc9357SAndroid Build Coastguard Worker 
1648*f6dc9357SAndroid Build Coastguard Worker   if (Meta.ParentPairs.Size() != 0)
1649*f6dc9357SAndroid Build Coastguard Worker   {
1650*f6dc9357SAndroid Build Coastguard Worker     s += "Parent:";
1651*f6dc9357SAndroid Build Coastguard Worker     s.Add_LF();
1652*f6dc9357SAndroid Build Coastguard Worker     FOR_VECTOR(i, Meta.ParentPairs)
1653*f6dc9357SAndroid Build Coastguard Worker     {
1654*f6dc9357SAndroid Build Coastguard Worker       const CParentPair &pair = Meta.ParentPairs[i];
1655*f6dc9357SAndroid Build Coastguard Worker       s += "  ";
1656*f6dc9357SAndroid Build Coastguard Worker       s += pair.Key;
1657*f6dc9357SAndroid Build Coastguard Worker       s += ": ";
1658*f6dc9357SAndroid Build Coastguard Worker       s += pair.Value;
1659*f6dc9357SAndroid Build Coastguard Worker       s.Add_LF();
1660*f6dc9357SAndroid Build Coastguard Worker     }
1661*f6dc9357SAndroid Build Coastguard Worker     s.Add_LF();
1662*f6dc9357SAndroid Build Coastguard Worker   }
1663*f6dc9357SAndroid Build Coastguard Worker }
1664*f6dc9357SAndroid Build Coastguard Worker 
1665*f6dc9357SAndroid Build Coastguard Worker 
1666*f6dc9357SAndroid Build Coastguard Worker 
1667*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
1668*f6dc9357SAndroid Build Coastguard Worker {
1669*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
1670*f6dc9357SAndroid Build Coastguard Worker   NCOM::CPropVariant prop;
1671*f6dc9357SAndroid Build Coastguard Worker   switch (propID)
1672*f6dc9357SAndroid Build Coastguard Worker   {
1673*f6dc9357SAndroid Build Coastguard Worker     case kpidMainSubfile: prop = (UInt32)0; break;
1674*f6dc9357SAndroid Build Coastguard Worker     case kpidClusterSize: prop = (UInt32)1 << Meta.BlockSize_Log; break;
1675*f6dc9357SAndroid Build Coastguard Worker     case kpidSectorSize: prop = (UInt32)1 << Meta.LogicalSectorSize_Log; break;
1676*f6dc9357SAndroid Build Coastguard Worker     case kpidShortComment:
1677*f6dc9357SAndroid Build Coastguard Worker     case kpidMethod:
1678*f6dc9357SAndroid Build Coastguard Worker     {
1679*f6dc9357SAndroid Build Coastguard Worker       AString s;
1680*f6dc9357SAndroid Build Coastguard Worker       AddTypeString(s);
1681*f6dc9357SAndroid Build Coastguard Worker       if (IsDiff())
1682*f6dc9357SAndroid Build Coastguard Worker       {
1683*f6dc9357SAndroid Build Coastguard Worker         s += " -> ";
1684*f6dc9357SAndroid Build Coastguard Worker         const CHandler *p = this;
1685*f6dc9357SAndroid Build Coastguard Worker         while (p && p->IsDiff())
1686*f6dc9357SAndroid Build Coastguard Worker           p = p->Parent;
1687*f6dc9357SAndroid Build Coastguard Worker         if (!p)
1688*f6dc9357SAndroid Build Coastguard Worker           s += '?';
1689*f6dc9357SAndroid Build Coastguard Worker         else
1690*f6dc9357SAndroid Build Coastguard Worker           p->AddTypeString(s);
1691*f6dc9357SAndroid Build Coastguard Worker       }
1692*f6dc9357SAndroid Build Coastguard Worker       prop = s;
1693*f6dc9357SAndroid Build Coastguard Worker       break;
1694*f6dc9357SAndroid Build Coastguard Worker     }
1695*f6dc9357SAndroid Build Coastguard Worker     case kpidComment:
1696*f6dc9357SAndroid Build Coastguard Worker     {
1697*f6dc9357SAndroid Build Coastguard Worker       UString s;
1698*f6dc9357SAndroid Build Coastguard Worker       {
1699*f6dc9357SAndroid Build Coastguard Worker         if (NumLevels > 1)
1700*f6dc9357SAndroid Build Coastguard Worker         {
1701*f6dc9357SAndroid Build Coastguard Worker           AddComment_UInt64(s, "NumVolumeLevels", NumLevels);
1702*f6dc9357SAndroid Build Coastguard Worker           AddComment_UInt64(s, "PackSizeTotal", PackSize_Total, true);
1703*f6dc9357SAndroid Build Coastguard Worker           s += "----";
1704*f6dc9357SAndroid Build Coastguard Worker           s.Add_LF();
1705*f6dc9357SAndroid Build Coastguard Worker         }
1706*f6dc9357SAndroid Build Coastguard Worker 
1707*f6dc9357SAndroid Build Coastguard Worker         const CHandler *p = this;
1708*f6dc9357SAndroid Build Coastguard Worker         for (;;)
1709*f6dc9357SAndroid Build Coastguard Worker         {
1710*f6dc9357SAndroid Build Coastguard Worker           if (p->_level != 0 || p->Parent)
1711*f6dc9357SAndroid Build Coastguard Worker             AddComment_UInt64(s, "VolumeLevel", p->_level + 1);
1712*f6dc9357SAndroid Build Coastguard Worker           p->AddComment(s);
1713*f6dc9357SAndroid Build Coastguard Worker           if (!p->Parent)
1714*f6dc9357SAndroid Build Coastguard Worker             break;
1715*f6dc9357SAndroid Build Coastguard Worker           s += "----";
1716*f6dc9357SAndroid Build Coastguard Worker           s.Add_LF();
1717*f6dc9357SAndroid Build Coastguard Worker           {
1718*f6dc9357SAndroid Build Coastguard Worker             s.Add_LF();
1719*f6dc9357SAndroid Build Coastguard Worker             if (!p->ParentName_Used.IsEmpty())
1720*f6dc9357SAndroid Build Coastguard Worker             {
1721*f6dc9357SAndroid Build Coastguard Worker               AddComment_Name(s, "Name");
1722*f6dc9357SAndroid Build Coastguard Worker               s += p->ParentName_Used;
1723*f6dc9357SAndroid Build Coastguard Worker               s.Add_LF();
1724*f6dc9357SAndroid Build Coastguard Worker             }
1725*f6dc9357SAndroid Build Coastguard Worker           }
1726*f6dc9357SAndroid Build Coastguard Worker           p = p->Parent;
1727*f6dc9357SAndroid Build Coastguard Worker         }
1728*f6dc9357SAndroid Build Coastguard Worker       }
1729*f6dc9357SAndroid Build Coastguard Worker       prop = s;
1730*f6dc9357SAndroid Build Coastguard Worker       break;
1731*f6dc9357SAndroid Build Coastguard Worker     }
1732*f6dc9357SAndroid Build Coastguard Worker     case kpidCreatorApp:
1733*f6dc9357SAndroid Build Coastguard Worker     {
1734*f6dc9357SAndroid Build Coastguard Worker       if (!_creator.IsEmpty())
1735*f6dc9357SAndroid Build Coastguard Worker         prop = _creator;
1736*f6dc9357SAndroid Build Coastguard Worker       break;
1737*f6dc9357SAndroid Build Coastguard Worker     }
1738*f6dc9357SAndroid Build Coastguard Worker     case kpidId:
1739*f6dc9357SAndroid Build Coastguard Worker     {
1740*f6dc9357SAndroid Build Coastguard Worker       if (Meta.Guid_Defined)
1741*f6dc9357SAndroid Build Coastguard Worker       {
1742*f6dc9357SAndroid Build Coastguard Worker         UString s;
1743*f6dc9357SAndroid Build Coastguard Worker         Meta.Guid.AddHexToString(s);
1744*f6dc9357SAndroid Build Coastguard Worker         prop = s;
1745*f6dc9357SAndroid Build Coastguard Worker       }
1746*f6dc9357SAndroid Build Coastguard Worker       break;
1747*f6dc9357SAndroid Build Coastguard Worker     }
1748*f6dc9357SAndroid Build Coastguard Worker     case kpidName:
1749*f6dc9357SAndroid Build Coastguard Worker     {
1750*f6dc9357SAndroid Build Coastguard Worker       if (Meta.Guid_Defined)
1751*f6dc9357SAndroid Build Coastguard Worker       {
1752*f6dc9357SAndroid Build Coastguard Worker         UString s;
1753*f6dc9357SAndroid Build Coastguard Worker         Meta.Guid.AddHexToString(s);
1754*f6dc9357SAndroid Build Coastguard Worker         s += ".vhdx";
1755*f6dc9357SAndroid Build Coastguard Worker         prop = s;
1756*f6dc9357SAndroid Build Coastguard Worker       }
1757*f6dc9357SAndroid Build Coastguard Worker       break;
1758*f6dc9357SAndroid Build Coastguard Worker     }
1759*f6dc9357SAndroid Build Coastguard Worker     case kpidParent: if (IsDiff()) prop = GetParentSequence(); break;
1760*f6dc9357SAndroid Build Coastguard Worker     case kpidPhySize: prop = _phySize; break;
1761*f6dc9357SAndroid Build Coastguard Worker     case kpidTotalPhySize:
1762*f6dc9357SAndroid Build Coastguard Worker     {
1763*f6dc9357SAndroid Build Coastguard Worker       const CHandler *p = this;
1764*f6dc9357SAndroid Build Coastguard Worker       UInt64 sum = 0;
1765*f6dc9357SAndroid Build Coastguard Worker       do
1766*f6dc9357SAndroid Build Coastguard Worker       {
1767*f6dc9357SAndroid Build Coastguard Worker         sum += p->_phySize;
1768*f6dc9357SAndroid Build Coastguard Worker         p = p->Parent;
1769*f6dc9357SAndroid Build Coastguard Worker       }
1770*f6dc9357SAndroid Build Coastguard Worker       while (p);
1771*f6dc9357SAndroid Build Coastguard Worker       prop = sum;
1772*f6dc9357SAndroid Build Coastguard Worker       break;
1773*f6dc9357SAndroid Build Coastguard Worker     }
1774*f6dc9357SAndroid Build Coastguard Worker     case kpidNumVolumes: if (NumLevels != 1) prop = (UInt32)NumLevels; break;
1775*f6dc9357SAndroid Build Coastguard Worker     case kpidError:
1776*f6dc9357SAndroid Build Coastguard Worker     {
1777*f6dc9357SAndroid Build Coastguard Worker       UString s;
1778*f6dc9357SAndroid Build Coastguard Worker       const CHandler *p = this;
1779*f6dc9357SAndroid Build Coastguard Worker       do
1780*f6dc9357SAndroid Build Coastguard Worker       {
1781*f6dc9357SAndroid Build Coastguard Worker         if (!p->_errorMessage.IsEmpty())
1782*f6dc9357SAndroid Build Coastguard Worker         {
1783*f6dc9357SAndroid Build Coastguard Worker           if (!s.IsEmpty())
1784*f6dc9357SAndroid Build Coastguard Worker             s.Add_LF();
1785*f6dc9357SAndroid Build Coastguard Worker           s += p->_errorMessage;
1786*f6dc9357SAndroid Build Coastguard Worker         }
1787*f6dc9357SAndroid Build Coastguard Worker         p = p->Parent;
1788*f6dc9357SAndroid Build Coastguard Worker       }
1789*f6dc9357SAndroid Build Coastguard Worker       while (p);
1790*f6dc9357SAndroid Build Coastguard Worker       if (!s.IsEmpty())
1791*f6dc9357SAndroid Build Coastguard Worker         prop = s;
1792*f6dc9357SAndroid Build Coastguard Worker       break;
1793*f6dc9357SAndroid Build Coastguard Worker     }
1794*f6dc9357SAndroid Build Coastguard Worker   }
1795*f6dc9357SAndroid Build Coastguard Worker   prop.Detach(value);
1796*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1797*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
1798*f6dc9357SAndroid Build Coastguard Worker }
1799*f6dc9357SAndroid Build Coastguard Worker 
1800*f6dc9357SAndroid Build Coastguard Worker 
1801*f6dc9357SAndroid Build Coastguard Worker HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openArchiveCallback)
1802*f6dc9357SAndroid Build Coastguard Worker {
1803*f6dc9357SAndroid Build Coastguard Worker   Stream = stream;
1804*f6dc9357SAndroid Build Coastguard Worker   if (_level >= (1 << 20))
1805*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
1806*f6dc9357SAndroid Build Coastguard Worker 
1807*f6dc9357SAndroid Build Coastguard Worker   RINOK(Open3())
1808*f6dc9357SAndroid Build Coastguard Worker 
1809*f6dc9357SAndroid Build Coastguard Worker   NumLevels = 1;
1810*f6dc9357SAndroid Build Coastguard Worker   PackSize_Total = GetPackSize();
1811*f6dc9357SAndroid Build Coastguard Worker 
1812*f6dc9357SAndroid Build Coastguard Worker   if (_child)
1813*f6dc9357SAndroid Build Coastguard Worker   {
1814*f6dc9357SAndroid Build Coastguard Worker     if (!_child->_parentGuid.IsEqualTo(Header.Guids[kHeader_GUID_Index_DataWriteGuid]))
1815*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1816*f6dc9357SAndroid Build Coastguard Worker     const CHandler *child = _child;
1817*f6dc9357SAndroid Build Coastguard Worker     do
1818*f6dc9357SAndroid Build Coastguard Worker     {
1819*f6dc9357SAndroid Build Coastguard Worker       /* We suppose that only FileWriteGuid is unique.
1820*f6dc9357SAndroid Build Coastguard Worker          Another IDs must be identical in in difference and parent archives. */
1821*f6dc9357SAndroid Build Coastguard Worker       if (Header.Guids[kHeader_GUID_Index_FileWriteGuid].IsEqualTo(
1822*f6dc9357SAndroid Build Coastguard Worker               child->Header.Guids[kHeader_GUID_Index_FileWriteGuid])
1823*f6dc9357SAndroid Build Coastguard Worker           && _phySize == child->_phySize)
1824*f6dc9357SAndroid Build Coastguard Worker       {
1825*f6dc9357SAndroid Build Coastguard Worker         _isCyclic = true;
1826*f6dc9357SAndroid Build Coastguard Worker         _isCyclic_or_CyclicParent = true;
1827*f6dc9357SAndroid Build Coastguard Worker         AddErrorMessage("Cyclic parent archive was blocked");
1828*f6dc9357SAndroid Build Coastguard Worker         return S_OK;
1829*f6dc9357SAndroid Build Coastguard Worker       }
1830*f6dc9357SAndroid Build Coastguard Worker       child = child->_child;
1831*f6dc9357SAndroid Build Coastguard Worker     }
1832*f6dc9357SAndroid Build Coastguard Worker     while (child);
1833*f6dc9357SAndroid Build Coastguard Worker   }
1834*f6dc9357SAndroid Build Coastguard Worker 
1835*f6dc9357SAndroid Build Coastguard Worker   if (!Meta.Is_HasParent())
1836*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
1837*f6dc9357SAndroid Build Coastguard Worker 
1838*f6dc9357SAndroid Build Coastguard Worker   if (!Meta.Locator_Defined
1839*f6dc9357SAndroid Build Coastguard Worker       || !_parentGuid_IsDefined
1840*f6dc9357SAndroid Build Coastguard Worker       || ParentNames.IsEmpty())
1841*f6dc9357SAndroid Build Coastguard Worker   {
1842*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
1843*f6dc9357SAndroid Build Coastguard Worker   }
1844*f6dc9357SAndroid Build Coastguard Worker 
1845*f6dc9357SAndroid Build Coastguard Worker   ParentName_Used = ParentNames.Front();
1846*f6dc9357SAndroid Build Coastguard Worker 
1847*f6dc9357SAndroid Build Coastguard Worker   HRESULT res;
1848*f6dc9357SAndroid Build Coastguard Worker   const unsigned kNumLevelsMax = (1 << 8);  // Maybe we need to increase that limit
1849*f6dc9357SAndroid Build Coastguard Worker   if (_level >= kNumLevelsMax - 1)
1850*f6dc9357SAndroid Build Coastguard Worker   {
1851*f6dc9357SAndroid Build Coastguard Worker     AddErrorMessage("Too many parent levels");
1852*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
1853*f6dc9357SAndroid Build Coastguard Worker   }
1854*f6dc9357SAndroid Build Coastguard Worker 
1855*f6dc9357SAndroid Build Coastguard Worker   bool _parentFileWasOpen = false;
1856*f6dc9357SAndroid Build Coastguard Worker 
1857*f6dc9357SAndroid Build Coastguard Worker   if (!openArchiveCallback)
1858*f6dc9357SAndroid Build Coastguard Worker     res = S_FALSE;
1859*f6dc9357SAndroid Build Coastguard Worker   else
1860*f6dc9357SAndroid Build Coastguard Worker     res = OpenParent(openArchiveCallback, _parentFileWasOpen);
1861*f6dc9357SAndroid Build Coastguard Worker 
1862*f6dc9357SAndroid Build Coastguard Worker   if (res != S_OK)
1863*f6dc9357SAndroid Build Coastguard Worker   {
1864*f6dc9357SAndroid Build Coastguard Worker     if (res != S_FALSE)
1865*f6dc9357SAndroid Build Coastguard Worker       return res;
1866*f6dc9357SAndroid Build Coastguard Worker 
1867*f6dc9357SAndroid Build Coastguard Worker     if (_parentFileWasOpen)
1868*f6dc9357SAndroid Build Coastguard Worker       AddErrorMessage("Can't parse parent VHDX file : ", ParentName_Used);
1869*f6dc9357SAndroid Build Coastguard Worker     else
1870*f6dc9357SAndroid Build Coastguard Worker       AddErrorMessage("Missing parent VHDX file : ", ParentName_Used);
1871*f6dc9357SAndroid Build Coastguard Worker   }
1872*f6dc9357SAndroid Build Coastguard Worker 
1873*f6dc9357SAndroid Build Coastguard Worker 
1874*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1875*f6dc9357SAndroid Build Coastguard Worker }
1876*f6dc9357SAndroid Build Coastguard Worker 
1877*f6dc9357SAndroid Build Coastguard Worker 
1878*f6dc9357SAndroid Build Coastguard Worker HRESULT CHandler::OpenParent(IArchiveOpenCallback *openArchiveCallback, bool &_parentFileWasOpen)
1879*f6dc9357SAndroid Build Coastguard Worker {
1880*f6dc9357SAndroid Build Coastguard Worker   _parentFileWasOpen = false;
1881*f6dc9357SAndroid Build Coastguard Worker   Z7_DECL_CMyComPtr_QI_FROM(
1882*f6dc9357SAndroid Build Coastguard Worker       IArchiveOpenVolumeCallback,
1883*f6dc9357SAndroid Build Coastguard Worker       openVolumeCallback, openArchiveCallback)
1884*f6dc9357SAndroid Build Coastguard Worker   if (!openVolumeCallback)
1885*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
1886*f6dc9357SAndroid Build Coastguard Worker   {
1887*f6dc9357SAndroid Build Coastguard Worker     CMyComPtr<IInStream> nextStream;
1888*f6dc9357SAndroid Build Coastguard Worker     HRESULT res = S_FALSE;
1889*f6dc9357SAndroid Build Coastguard Worker     UString name;
1890*f6dc9357SAndroid Build Coastguard Worker 
1891*f6dc9357SAndroid Build Coastguard Worker     FOR_VECTOR (i, ParentNames)
1892*f6dc9357SAndroid Build Coastguard Worker     {
1893*f6dc9357SAndroid Build Coastguard Worker       name = ParentNames[i];
1894*f6dc9357SAndroid Build Coastguard Worker 
1895*f6dc9357SAndroid Build Coastguard Worker       // we remove prefix ".\\', but client already can support any variant
1896*f6dc9357SAndroid Build Coastguard Worker       if (name[0] == L'.' && name[1] == L'\\')
1897*f6dc9357SAndroid Build Coastguard Worker         name.DeleteFrontal(2);
1898*f6dc9357SAndroid Build Coastguard Worker 
1899*f6dc9357SAndroid Build Coastguard Worker       res = openVolumeCallback->GetStream(name, &nextStream);
1900*f6dc9357SAndroid Build Coastguard Worker 
1901*f6dc9357SAndroid Build Coastguard Worker       if (res == S_OK && nextStream)
1902*f6dc9357SAndroid Build Coastguard Worker         break;
1903*f6dc9357SAndroid Build Coastguard Worker 
1904*f6dc9357SAndroid Build Coastguard Worker       if (res != S_OK && res != S_FALSE)
1905*f6dc9357SAndroid Build Coastguard Worker         return res;
1906*f6dc9357SAndroid Build Coastguard Worker     }
1907*f6dc9357SAndroid Build Coastguard Worker 
1908*f6dc9357SAndroid Build Coastguard Worker     if (res == S_FALSE || !nextStream)
1909*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1910*f6dc9357SAndroid Build Coastguard Worker 
1911*f6dc9357SAndroid Build Coastguard Worker     ParentName_Used = name;
1912*f6dc9357SAndroid Build Coastguard Worker     _parentFileWasOpen = true;
1913*f6dc9357SAndroid Build Coastguard Worker 
1914*f6dc9357SAndroid Build Coastguard Worker     Parent = new CHandler;
1915*f6dc9357SAndroid Build Coastguard Worker     ParentStream = Parent;
1916*f6dc9357SAndroid Build Coastguard Worker 
1917*f6dc9357SAndroid Build Coastguard Worker     try
1918*f6dc9357SAndroid Build Coastguard Worker     {
1919*f6dc9357SAndroid Build Coastguard Worker       Parent->_level = _level + 1;
1920*f6dc9357SAndroid Build Coastguard Worker       Parent->_child = this;
1921*f6dc9357SAndroid Build Coastguard Worker       /* we could call CHandlerImg::Open() here.
1922*f6dc9357SAndroid Build Coastguard Worker          but we don't need (_imgExt) in (Parent). So we call Open2() here */
1923*f6dc9357SAndroid Build Coastguard Worker       Parent->Close();
1924*f6dc9357SAndroid Build Coastguard Worker       res = Parent->Open2(nextStream, openArchiveCallback);
1925*f6dc9357SAndroid Build Coastguard Worker     }
1926*f6dc9357SAndroid Build Coastguard Worker     catch(...)
1927*f6dc9357SAndroid Build Coastguard Worker     {
1928*f6dc9357SAndroid Build Coastguard Worker       Parent = NULL;
1929*f6dc9357SAndroid Build Coastguard Worker       ParentStream.Release();
1930*f6dc9357SAndroid Build Coastguard Worker       res = S_FALSE;
1931*f6dc9357SAndroid Build Coastguard Worker       throw;
1932*f6dc9357SAndroid Build Coastguard Worker     }
1933*f6dc9357SAndroid Build Coastguard Worker 
1934*f6dc9357SAndroid Build Coastguard Worker     if (res != S_OK)
1935*f6dc9357SAndroid Build Coastguard Worker     {
1936*f6dc9357SAndroid Build Coastguard Worker       Parent = NULL;
1937*f6dc9357SAndroid Build Coastguard Worker       ParentStream.Release();
1938*f6dc9357SAndroid Build Coastguard Worker       if (res == E_ABORT)
1939*f6dc9357SAndroid Build Coastguard Worker         return res;
1940*f6dc9357SAndroid Build Coastguard Worker       if (res != S_FALSE)
1941*f6dc9357SAndroid Build Coastguard Worker       {
1942*f6dc9357SAndroid Build Coastguard Worker         // we must show that error code
1943*f6dc9357SAndroid Build Coastguard Worker       }
1944*f6dc9357SAndroid Build Coastguard Worker     }
1945*f6dc9357SAndroid Build Coastguard Worker 
1946*f6dc9357SAndroid Build Coastguard Worker     if (res == S_OK)
1947*f6dc9357SAndroid Build Coastguard Worker     {
1948*f6dc9357SAndroid Build Coastguard Worker       if (Parent->_isCyclic_or_CyclicParent)
1949*f6dc9357SAndroid Build Coastguard Worker         _isCyclic_or_CyclicParent = true;
1950*f6dc9357SAndroid Build Coastguard Worker 
1951*f6dc9357SAndroid Build Coastguard Worker       NumLevels = Parent->NumLevels + 1;
1952*f6dc9357SAndroid Build Coastguard Worker       PackSize_Total += Parent->GetPackSize();
1953*f6dc9357SAndroid Build Coastguard Worker 
1954*f6dc9357SAndroid Build Coastguard Worker       // we read BitMaps only if Parent was open
1955*f6dc9357SAndroid Build Coastguard Worker 
1956*f6dc9357SAndroid Build Coastguard Worker       UInt64 numBytes = (UInt64)NumUsedBitMaps << kBitmapSize_Log;
1957*f6dc9357SAndroid Build Coastguard Worker       if (openArchiveCallback && numBytes != 0)
1958*f6dc9357SAndroid Build Coastguard Worker       {
1959*f6dc9357SAndroid Build Coastguard Worker         RINOK(openArchiveCallback->SetTotal(NULL, &numBytes))
1960*f6dc9357SAndroid Build Coastguard Worker       }
1961*f6dc9357SAndroid Build Coastguard Worker       numBytes = 0;
1962*f6dc9357SAndroid Build Coastguard Worker       for (size_t i = ChunkRatio; i < TotalBatEntries; i += ChunkRatio + 1)
1963*f6dc9357SAndroid Build Coastguard Worker       {
1964*f6dc9357SAndroid Build Coastguard Worker         const UInt64 v = Bat.GetItem(i);
1965*f6dc9357SAndroid Build Coastguard Worker         const UInt64 offset = BAT_GET_OFFSET(v);
1966*f6dc9357SAndroid Build Coastguard Worker         const unsigned state = BAT_GET_STATE(v);
1967*f6dc9357SAndroid Build Coastguard Worker 
1968*f6dc9357SAndroid Build Coastguard Worker         CByteBuffer &buf = BitMaps.AddNew();
1969*f6dc9357SAndroid Build Coastguard Worker         if (state == SB_BLOCK_PRESENT)
1970*f6dc9357SAndroid Build Coastguard Worker         {
1971*f6dc9357SAndroid Build Coastguard Worker           if (openArchiveCallback)
1972*f6dc9357SAndroid Build Coastguard Worker           {
1973*f6dc9357SAndroid Build Coastguard Worker             RINOK(openArchiveCallback->SetCompleted(NULL, &numBytes))
1974*f6dc9357SAndroid Build Coastguard Worker           }
1975*f6dc9357SAndroid Build Coastguard Worker           numBytes += kBitmapSize;
1976*f6dc9357SAndroid Build Coastguard Worker           buf.Alloc(kBitmapSize);
1977*f6dc9357SAndroid Build Coastguard Worker           RINOK(Seek2(offset))
1978*f6dc9357SAndroid Build Coastguard Worker           RINOK(Read_FALSE(buf, kBitmapSize))
1979*f6dc9357SAndroid Build Coastguard Worker           /*
1980*f6dc9357SAndroid Build Coastguard Worker           for (unsigned i = 0; i < (1 << 20); i+=4)
1981*f6dc9357SAndroid Build Coastguard Worker           {
1982*f6dc9357SAndroid Build Coastguard Worker             UInt32 v = GetUi32(buf + i);
1983*f6dc9357SAndroid Build Coastguard Worker             if (v != 0 && v != (UInt32)(Int32)-1)
1984*f6dc9357SAndroid Build Coastguard Worker               printf("\n%7d %8x", i, v);
1985*f6dc9357SAndroid Build Coastguard Worker           }
1986*f6dc9357SAndroid Build Coastguard Worker           */
1987*f6dc9357SAndroid Build Coastguard Worker         }
1988*f6dc9357SAndroid Build Coastguard Worker       }
1989*f6dc9357SAndroid Build Coastguard Worker     }
1990*f6dc9357SAndroid Build Coastguard Worker   }
1991*f6dc9357SAndroid Build Coastguard Worker 
1992*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1993*f6dc9357SAndroid Build Coastguard Worker }
1994*f6dc9357SAndroid Build Coastguard Worker 
1995*f6dc9357SAndroid Build Coastguard Worker 
1996*f6dc9357SAndroid Build Coastguard Worker void CHandler::CloseAtError()
1997*f6dc9357SAndroid Build Coastguard Worker {
1998*f6dc9357SAndroid Build Coastguard Worker   // CHandlerImg
1999*f6dc9357SAndroid Build Coastguard Worker   Clear_HandlerImg_Vars();
2000*f6dc9357SAndroid Build Coastguard Worker   Stream.Release();
2001*f6dc9357SAndroid Build Coastguard Worker 
2002*f6dc9357SAndroid Build Coastguard Worker   _phySize = 0;
2003*f6dc9357SAndroid Build Coastguard Worker   Bat.Clear();
2004*f6dc9357SAndroid Build Coastguard Worker   BitMaps.Clear();
2005*f6dc9357SAndroid Build Coastguard Worker   NumUsedBlocks = 0;
2006*f6dc9357SAndroid Build Coastguard Worker   NumUsedBitMaps = 0;
2007*f6dc9357SAndroid Build Coastguard Worker   HeadersSize = 0;
2008*f6dc9357SAndroid Build Coastguard Worker   /*
2009*f6dc9357SAndroid Build Coastguard Worker   NumUsed_1MB_Blocks = 0;
2010*f6dc9357SAndroid Build Coastguard Worker   NumUsed_1MB_Blocks_Defined = false;
2011*f6dc9357SAndroid Build Coastguard Worker   */
2012*f6dc9357SAndroid Build Coastguard Worker 
2013*f6dc9357SAndroid Build Coastguard Worker   Parent = NULL;
2014*f6dc9357SAndroid Build Coastguard Worker   ParentStream.Release();
2015*f6dc9357SAndroid Build Coastguard Worker   _errorMessage.Empty();
2016*f6dc9357SAndroid Build Coastguard Worker   _creator.Empty();
2017*f6dc9357SAndroid Build Coastguard Worker   _nonEmptyLog = false;
2018*f6dc9357SAndroid Build Coastguard Worker   _parentGuid_IsDefined = false;
2019*f6dc9357SAndroid Build Coastguard Worker   _isDataContiguous = false;
2020*f6dc9357SAndroid Build Coastguard Worker   // _batOverlap = false;
2021*f6dc9357SAndroid Build Coastguard Worker 
2022*f6dc9357SAndroid Build Coastguard Worker   ParentNames.Clear();
2023*f6dc9357SAndroid Build Coastguard Worker   ParentName_Used.Empty();
2024*f6dc9357SAndroid Build Coastguard Worker 
2025*f6dc9357SAndroid Build Coastguard Worker   Meta.Clear();
2026*f6dc9357SAndroid Build Coastguard Worker 
2027*f6dc9357SAndroid Build Coastguard Worker   ChunkRatio_Log = 0;
2028*f6dc9357SAndroid Build Coastguard Worker   ChunkRatio = 0;
2029*f6dc9357SAndroid Build Coastguard Worker   TotalBatEntries = 0;
2030*f6dc9357SAndroid Build Coastguard Worker   NumLevels = 0;
2031*f6dc9357SAndroid Build Coastguard Worker   PackSize_Total = 0;
2032*f6dc9357SAndroid Build Coastguard Worker 
2033*f6dc9357SAndroid Build Coastguard Worker   _isCyclic = false;
2034*f6dc9357SAndroid Build Coastguard Worker   _isCyclic_or_CyclicParent = false;
2035*f6dc9357SAndroid Build Coastguard Worker }
2036*f6dc9357SAndroid Build Coastguard Worker 
2037*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Close())
2038*f6dc9357SAndroid Build Coastguard Worker {
2039*f6dc9357SAndroid Build Coastguard Worker   CloseAtError();
2040*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
2041*f6dc9357SAndroid Build Coastguard Worker }
2042*f6dc9357SAndroid Build Coastguard Worker 
2043*f6dc9357SAndroid Build Coastguard Worker 
2044*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value))
2045*f6dc9357SAndroid Build Coastguard Worker {
2046*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
2047*f6dc9357SAndroid Build Coastguard Worker   NCOM::CPropVariant prop;
2048*f6dc9357SAndroid Build Coastguard Worker 
2049*f6dc9357SAndroid Build Coastguard Worker   switch (propID)
2050*f6dc9357SAndroid Build Coastguard Worker   {
2051*f6dc9357SAndroid Build Coastguard Worker     case kpidSize: prop = Meta.VirtualDiskSize; break;
2052*f6dc9357SAndroid Build Coastguard Worker     case kpidPackSize: prop = PackSize_Total; break;
2053*f6dc9357SAndroid Build Coastguard Worker     case kpidExtension: prop = (_imgExt ? _imgExt : "img"); break;
2054*f6dc9357SAndroid Build Coastguard Worker   }
2055*f6dc9357SAndroid Build Coastguard Worker 
2056*f6dc9357SAndroid Build Coastguard Worker   prop.Detach(value);
2057*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
2058*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
2059*f6dc9357SAndroid Build Coastguard Worker }
2060*f6dc9357SAndroid Build Coastguard Worker 
2061*f6dc9357SAndroid Build Coastguard Worker 
2062*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream))
2063*f6dc9357SAndroid Build Coastguard Worker {
2064*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
2065*f6dc9357SAndroid Build Coastguard Worker   *stream = NULL;
2066*f6dc9357SAndroid Build Coastguard Worker   // if some prarent is not OK, we don't create stream
2067*f6dc9357SAndroid Build Coastguard Worker   if (!AreParentsOK())
2068*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
2069*f6dc9357SAndroid Build Coastguard Worker   InitSeekPositions();
2070*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<ISequentialInStream> streamTemp = this;
2071*f6dc9357SAndroid Build Coastguard Worker   *stream = streamTemp.Detach();
2072*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
2073*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
2074*f6dc9357SAndroid Build Coastguard Worker }
2075*f6dc9357SAndroid Build Coastguard Worker 
2076*f6dc9357SAndroid Build Coastguard Worker REGISTER_ARC_I(
2077*f6dc9357SAndroid Build Coastguard Worker   "VHDX", "vhdx avhdx", NULL, 0xc4,
2078*f6dc9357SAndroid Build Coastguard Worker   kSignature,
2079*f6dc9357SAndroid Build Coastguard Worker   0,
2080*f6dc9357SAndroid Build Coastguard Worker   0,
2081*f6dc9357SAndroid Build Coastguard Worker   NULL)
2082*f6dc9357SAndroid Build Coastguard Worker 
2083*f6dc9357SAndroid Build Coastguard Worker }}
2084