xref: /aosp_15_r20/external/lzma/CPP/7zip/Archive/UefiHandler.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1*f6dc9357SAndroid Build Coastguard Worker // UefiHandler.cpp
2*f6dc9357SAndroid Build Coastguard Worker 
3*f6dc9357SAndroid Build Coastguard Worker #include "StdAfx.h"
4*f6dc9357SAndroid Build Coastguard Worker 
5*f6dc9357SAndroid Build Coastguard Worker // #define SHOW_DEBUG_INFO
6*f6dc9357SAndroid Build Coastguard Worker 
7*f6dc9357SAndroid Build Coastguard Worker #ifdef SHOW_DEBUG_INFO
8*f6dc9357SAndroid Build Coastguard Worker #include <stdio.h>
9*f6dc9357SAndroid Build Coastguard Worker #endif
10*f6dc9357SAndroid Build Coastguard Worker 
11*f6dc9357SAndroid Build Coastguard Worker #include "../../../C/7zCrc.h"
12*f6dc9357SAndroid Build Coastguard Worker #include "../../../C/Alloc.h"
13*f6dc9357SAndroid Build Coastguard Worker #include "../../../C/LzmaDec.h"
14*f6dc9357SAndroid Build Coastguard Worker #include "../../../C/CpuArch.h"
15*f6dc9357SAndroid Build Coastguard Worker 
16*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/AutoPtr.h"
17*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/ComTry.h"
18*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/IntToString.h"
19*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/MyBuffer.h"
20*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/StringConvert.h"
21*f6dc9357SAndroid Build Coastguard Worker 
22*f6dc9357SAndroid Build Coastguard Worker #include "../../Windows/PropVariantUtils.h"
23*f6dc9357SAndroid Build Coastguard Worker 
24*f6dc9357SAndroid Build Coastguard Worker #include "../Common/ProgressUtils.h"
25*f6dc9357SAndroid Build Coastguard Worker #include "../Common/RegisterArc.h"
26*f6dc9357SAndroid Build Coastguard Worker #include "../Common/StreamObjects.h"
27*f6dc9357SAndroid Build Coastguard Worker #include "../Common/StreamUtils.h"
28*f6dc9357SAndroid Build Coastguard Worker 
29*f6dc9357SAndroid Build Coastguard Worker #include "../Compress/CopyCoder.h"
30*f6dc9357SAndroid Build Coastguard Worker #include "../Compress/LzhDecoder.h"
31*f6dc9357SAndroid Build Coastguard Worker 
32*f6dc9357SAndroid Build Coastguard Worker #ifdef SHOW_DEBUG_INFO
33*f6dc9357SAndroid Build Coastguard Worker #define PRF(x) x
34*f6dc9357SAndroid Build Coastguard Worker #else
35*f6dc9357SAndroid Build Coastguard Worker #define PRF(x)
36*f6dc9357SAndroid Build Coastguard Worker #endif
37*f6dc9357SAndroid Build Coastguard Worker 
38*f6dc9357SAndroid Build Coastguard Worker #define Get16(p) GetUi16(p)
39*f6dc9357SAndroid Build Coastguard Worker #define Get32(p) GetUi32(p)
40*f6dc9357SAndroid Build Coastguard Worker #define Get64(p) GetUi64(p)
41*f6dc9357SAndroid Build Coastguard Worker #define Get24(p) (Get32(p) & 0xFFFFFF)
42*f6dc9357SAndroid Build Coastguard Worker 
43*f6dc9357SAndroid Build Coastguard Worker namespace NArchive {
44*f6dc9357SAndroid Build Coastguard Worker namespace NUefi {
45*f6dc9357SAndroid Build Coastguard Worker 
46*f6dc9357SAndroid Build Coastguard Worker static const size_t kBufTotalSizeMax = 1 << 29;
47*f6dc9357SAndroid Build Coastguard Worker static const unsigned kNumFilesMax = 1 << 18;
48*f6dc9357SAndroid Build Coastguard Worker static const unsigned kLevelMax = 64;
49*f6dc9357SAndroid Build Coastguard Worker 
50*f6dc9357SAndroid Build Coastguard Worker static const Byte k_IntelMeSignature[] =
51*f6dc9357SAndroid Build Coastguard Worker {
52*f6dc9357SAndroid Build Coastguard Worker   0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
53*f6dc9357SAndroid Build Coastguard Worker   0x5A, 0xA5, 0xF0, 0x0F
54*f6dc9357SAndroid Build Coastguard Worker };
55*f6dc9357SAndroid Build Coastguard Worker 
IsIntelMe(const Byte * p)56*f6dc9357SAndroid Build Coastguard Worker static bool IsIntelMe(const Byte *p)
57*f6dc9357SAndroid Build Coastguard Worker {
58*f6dc9357SAndroid Build Coastguard Worker   return memcmp(p, k_IntelMeSignature, sizeof(k_IntelMeSignature)) == 0;
59*f6dc9357SAndroid Build Coastguard Worker }
60*f6dc9357SAndroid Build Coastguard Worker 
61*f6dc9357SAndroid Build Coastguard Worker static const unsigned kFvHeaderSize = 0x38;
62*f6dc9357SAndroid Build Coastguard Worker 
63*f6dc9357SAndroid Build Coastguard Worker static const unsigned kGuidSize = 16;
64*f6dc9357SAndroid Build Coastguard Worker 
65*f6dc9357SAndroid Build Coastguard Worker #define CAPSULE_SIGNATURE   0xBD,0x86,0x66,0x3B,0x76,0x0D,0x30,0x40,0xB7,0x0E,0xB5,0x51,0x9E,0x2F,0xC5,0xA0
66*f6dc9357SAndroid Build Coastguard Worker #define CAPSULE2_SIGNATURE  0x8B,0xA6,0x3C,0x4A,0x23,0x77,0xFB,0x48,0x80,0x3D,0x57,0x8C,0xC1,0xFE,0xC4,0x4D
67*f6dc9357SAndroid Build Coastguard Worker #define CAPSULE_UEFI_SIGNATURE  0xB9,0x82,0x91,0x53,0xB5,0xAB,0x91,0x43,0xB6,0x9A,0xE3,0xA9,0x43,0xF7,0x2F,0xCC
68*f6dc9357SAndroid Build Coastguard Worker /*
69*f6dc9357SAndroid Build Coastguard Worker   6dcbd5ed-e82d-4c44-bda1-7194199ad92a : Firmware Management `
70*f6dc9357SAndroid Build Coastguard Worker */
71*f6dc9357SAndroid Build Coastguard Worker 
72*f6dc9357SAndroid Build Coastguard Worker static const Byte k_Guids_Capsules[][kGuidSize] =
73*f6dc9357SAndroid Build Coastguard Worker {
74*f6dc9357SAndroid Build Coastguard Worker   { CAPSULE_SIGNATURE },
75*f6dc9357SAndroid Build Coastguard Worker   { CAPSULE2_SIGNATURE },
76*f6dc9357SAndroid Build Coastguard Worker   { CAPSULE_UEFI_SIGNATURE }
77*f6dc9357SAndroid Build Coastguard Worker };
78*f6dc9357SAndroid Build Coastguard Worker 
79*f6dc9357SAndroid Build Coastguard Worker 
80*f6dc9357SAndroid Build Coastguard Worker static const unsigned kFfsGuidOffset = 16;
81*f6dc9357SAndroid Build Coastguard Worker 
82*f6dc9357SAndroid Build Coastguard Worker #define FFS1_SIGNATURE  0xD9,0x54,0x93,0x7A,0x68,0x04,0x4A,0x44,0x81,0xCE,0x0B,0xF6,0x17,0xD8,0x90,0xDF
83*f6dc9357SAndroid Build Coastguard Worker #define FFS2_SIGNATURE  0x78,0xE5,0x8C,0x8C,0x3D,0x8A,0x1C,0x4F,0x99,0x35,0x89,0x61,0x85,0xC3,0x2D,0xD3
84*f6dc9357SAndroid Build Coastguard Worker #define MACFS_SIGNATURE 0xAD,0xEE,0xAD,0x04,0xFF,0x61,0x31,0x4D,0xB6,0xBA,0x64,0xF8,0xBF,0x90,0x1F,0x5A
85*f6dc9357SAndroid Build Coastguard Worker // APPLE_BOOT
86*f6dc9357SAndroid Build Coastguard Worker /*
87*f6dc9357SAndroid Build Coastguard Worker   "FFS3":        "5473c07a-3dcb-4dca-bd6f-1e9689e7349a",
88*f6dc9357SAndroid Build Coastguard Worker   "NVRAM_EVSA":  "fff12b8d-7696-4c8b-a985-2747075b4f50",
89*f6dc9357SAndroid Build Coastguard Worker   "NVRAM_NVAR":  "cef5b9a3-476d-497f-9fdc-e98143e0422c",
90*f6dc9357SAndroid Build Coastguard Worker   "NVRAM_EVSA2": "00504624-8a59-4eeb-bd0f-6b36e96128e0",
91*f6dc9357SAndroid Build Coastguard Worker static const Byte k_NVRAM_NVAR_Guid[kGuidSize] =
92*f6dc9357SAndroid Build Coastguard Worker   { 0xA3,0xB9,0xF5,0xCE,0x6D,0x47,0x7F,0x49,0x9F,0xDC,0xE9,0x81,0x43,0xE0,0x42,0x2C };
93*f6dc9357SAndroid Build Coastguard Worker */
94*f6dc9357SAndroid Build Coastguard Worker 
95*f6dc9357SAndroid Build Coastguard Worker static const Byte k_Guids_FS[][kGuidSize] =
96*f6dc9357SAndroid Build Coastguard Worker {
97*f6dc9357SAndroid Build Coastguard Worker   { FFS1_SIGNATURE },
98*f6dc9357SAndroid Build Coastguard Worker   { FFS2_SIGNATURE },
99*f6dc9357SAndroid Build Coastguard Worker   { MACFS_SIGNATURE }
100*f6dc9357SAndroid Build Coastguard Worker };
101*f6dc9357SAndroid Build Coastguard Worker 
102*f6dc9357SAndroid Build Coastguard Worker 
103*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kFvSignature = 0x4856465F; // "_FVH"
104*f6dc9357SAndroid Build Coastguard Worker 
105*f6dc9357SAndroid Build Coastguard Worker static const Byte kGuids[][kGuidSize] =
106*f6dc9357SAndroid Build Coastguard Worker {
107*f6dc9357SAndroid Build Coastguard Worker   { 0xB0,0xCD,0x1B,0xFC,0x31,0x7D,0xAA,0x49,0x93,0x6A,0xA4,0x60,0x0D,0x9D,0xD0,0x83 },
108*f6dc9357SAndroid Build Coastguard Worker   { 0x2E,0x06,0xA0,0x1B,0x79,0xC7,0x82,0x45,0x85,0x66,0x33,0x6A,0xE8,0xF7,0x8F,0x09 },
109*f6dc9357SAndroid Build Coastguard Worker   { 0x25,0x4E,0x37,0x7E,0x01,0x8E,0xEE,0x4F,0x87,0xf2,0x39,0x0C,0x23,0xC6,0x06,0xCD },
110*f6dc9357SAndroid Build Coastguard Worker   { 0x97,0xE5,0x1B,0x16,0xC5,0xE9,0xDB,0x49,0xAE,0x50,0xC4,0x62,0xAB,0x54,0xEE,0xDA },
111*f6dc9357SAndroid Build Coastguard Worker   { 0xDB,0x7F,0xAD,0x77,0x2A,0xDF,0x02,0x43,0x88,0x98,0xC7,0x2E,0x4C,0xDB,0xD0,0xF4 },
112*f6dc9357SAndroid Build Coastguard Worker   { 0xAB,0x71,0xCF,0xF5,0x4B,0xB0,0x7E,0x4B,0x98,0x8A,0xD8,0xA0,0xD4,0x98,0xE6,0x92 },
113*f6dc9357SAndroid Build Coastguard Worker   { 0x91,0x45,0x53,0x7A,0xCE,0x37,0x81,0x48,0xB3,0xC9,0x71,0x38,0x14,0xF4,0x5D,0x6B },
114*f6dc9357SAndroid Build Coastguard Worker   { 0x84,0xE6,0x7A,0x36,0x5D,0x33,0x71,0x46,0xA1,0x6D,0x89,0x9D,0xBF,0xEA,0x6B,0x88 },
115*f6dc9357SAndroid Build Coastguard Worker   { 0x98,0x07,0x40,0x24,0x07,0x38,0x42,0x4A,0xB4,0x13,0xA1,0xEC,0xEE,0x20,0x5D,0xD8 },
116*f6dc9357SAndroid Build Coastguard Worker   { 0xEE,0xA2,0x3F,0x28,0x2C,0x53,0x4D,0x48,0x93,0x83,0x9F,0x93,0xB3,0x6F,0x0B,0x7E },
117*f6dc9357SAndroid Build Coastguard Worker   { 0x9B,0xD5,0xB8,0x98,0xBA,0xE8,0xEE,0x48,0x98,0xDD,0xC2,0x95,0x39,0x2F,0x1E,0xDB },
118*f6dc9357SAndroid Build Coastguard Worker   { 0x09,0x6D,0xE3,0xC3,0x94,0x82,0x97,0x4B,0xA8,0x57,0xD5,0x28,0x8F,0xE3,0x3E,0x28 },
119*f6dc9357SAndroid Build Coastguard Worker   { 0x18,0x88,0x53,0x4A,0xE0,0x5A,0xB2,0x4E,0xB2,0xEB,0x48,0x8B,0x23,0x65,0x70,0x22 }
120*f6dc9357SAndroid Build Coastguard Worker };
121*f6dc9357SAndroid Build Coastguard Worker 
122*f6dc9357SAndroid Build Coastguard Worker static const Byte k_Guid_LZMA_COMPRESSED[kGuidSize] =
123*f6dc9357SAndroid Build Coastguard Worker   { 0x98,0x58,0x4E,0xEE,0x14,0x39,0x59,0x42,0x9D,0x6E,0xDC,0x7B,0xD7,0x94,0x03,0xCF };
124*f6dc9357SAndroid Build Coastguard Worker 
125*f6dc9357SAndroid Build Coastguard Worker static const char * const kGuidNames[] =
126*f6dc9357SAndroid Build Coastguard Worker {
127*f6dc9357SAndroid Build Coastguard Worker     "CRC"
128*f6dc9357SAndroid Build Coastguard Worker   , "VolumeTopFile"
129*f6dc9357SAndroid Build Coastguard Worker   , "ACPI"
130*f6dc9357SAndroid Build Coastguard Worker   , "ACPI2"
131*f6dc9357SAndroid Build Coastguard Worker   , "Main"
132*f6dc9357SAndroid Build Coastguard Worker   , "Intel32"
133*f6dc9357SAndroid Build Coastguard Worker   , "Intel64"
134*f6dc9357SAndroid Build Coastguard Worker   , "Intel32c"
135*f6dc9357SAndroid Build Coastguard Worker   , "Intel64c"
136*f6dc9357SAndroid Build Coastguard Worker   , "MacVolume"
137*f6dc9357SAndroid Build Coastguard Worker   , "MacUpdate.txt"
138*f6dc9357SAndroid Build Coastguard Worker   , "MacName"
139*f6dc9357SAndroid Build Coastguard Worker   , "Insyde"
140*f6dc9357SAndroid Build Coastguard Worker };
141*f6dc9357SAndroid Build Coastguard Worker 
142*f6dc9357SAndroid Build Coastguard Worker enum
143*f6dc9357SAndroid Build Coastguard Worker {
144*f6dc9357SAndroid Build Coastguard Worker   kGuidIndex_CRC = 0
145*f6dc9357SAndroid Build Coastguard Worker };
146*f6dc9357SAndroid Build Coastguard Worker 
147*f6dc9357SAndroid Build Coastguard Worker struct CSigExtPair
148*f6dc9357SAndroid Build Coastguard Worker {
149*f6dc9357SAndroid Build Coastguard Worker   const char *ext;
150*f6dc9357SAndroid Build Coastguard Worker   unsigned sigSize;
151*f6dc9357SAndroid Build Coastguard Worker   Byte sig[16];
152*f6dc9357SAndroid Build Coastguard Worker };
153*f6dc9357SAndroid Build Coastguard Worker 
154*f6dc9357SAndroid Build Coastguard Worker static const CSigExtPair g_Sigs[] =
155*f6dc9357SAndroid Build Coastguard Worker {
156*f6dc9357SAndroid Build Coastguard Worker   { "bmp",  2, { 'B','M' } },
157*f6dc9357SAndroid Build Coastguard Worker   { "riff", 4, { 'R','I','F','F' } },
158*f6dc9357SAndroid Build Coastguard Worker   { "pe",   2, { 'M','Z'} },
159*f6dc9357SAndroid Build Coastguard Worker   { "gif",  6, { 'G','I','F','8','9', 'a' } },
160*f6dc9357SAndroid Build Coastguard Worker   { "png",  8, { 0x89,0x50,0x4E,0x47,0x0D,0x0A,0x1A,0x0A } },
161*f6dc9357SAndroid Build Coastguard Worker   { "jpg", 10, { 0xFF,0xD8,0xFF,0xE0,0x00,0x10,0x4A,0x46,0x49,0x46 } },
162*f6dc9357SAndroid Build Coastguard Worker   { "rom",  2, { 0x55,0xAA } }
163*f6dc9357SAndroid Build Coastguard Worker };
164*f6dc9357SAndroid Build Coastguard Worker 
165*f6dc9357SAndroid Build Coastguard Worker enum
166*f6dc9357SAndroid Build Coastguard Worker {
167*f6dc9357SAndroid Build Coastguard Worker   kSig_BMP,
168*f6dc9357SAndroid Build Coastguard Worker   kSig_RIFF,
169*f6dc9357SAndroid Build Coastguard Worker   kSig_PE
170*f6dc9357SAndroid Build Coastguard Worker };
171*f6dc9357SAndroid Build Coastguard Worker 
FindExt(const Byte * p,size_t size)172*f6dc9357SAndroid Build Coastguard Worker static const char *FindExt(const Byte *p, size_t size)
173*f6dc9357SAndroid Build Coastguard Worker {
174*f6dc9357SAndroid Build Coastguard Worker   unsigned i;
175*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < Z7_ARRAY_SIZE(g_Sigs); i++)
176*f6dc9357SAndroid Build Coastguard Worker   {
177*f6dc9357SAndroid Build Coastguard Worker     const CSigExtPair &pair = g_Sigs[i];
178*f6dc9357SAndroid Build Coastguard Worker     if (size >= pair.sigSize)
179*f6dc9357SAndroid Build Coastguard Worker       if (memcmp(p, pair.sig, pair.sigSize) == 0)
180*f6dc9357SAndroid Build Coastguard Worker         break;
181*f6dc9357SAndroid Build Coastguard Worker   }
182*f6dc9357SAndroid Build Coastguard Worker   if (i == Z7_ARRAY_SIZE(g_Sigs))
183*f6dc9357SAndroid Build Coastguard Worker     return NULL;
184*f6dc9357SAndroid Build Coastguard Worker   switch (i)
185*f6dc9357SAndroid Build Coastguard Worker   {
186*f6dc9357SAndroid Build Coastguard Worker     case kSig_BMP:
187*f6dc9357SAndroid Build Coastguard Worker       if (GetUi32(p + 2) > size || GetUi32(p + 0xA) > size)
188*f6dc9357SAndroid Build Coastguard Worker         return NULL;
189*f6dc9357SAndroid Build Coastguard Worker       break;
190*f6dc9357SAndroid Build Coastguard Worker     case kSig_RIFF:
191*f6dc9357SAndroid Build Coastguard Worker       if (GetUi32(p + 8) == 0x45564157 || GetUi32(p + 0xC) == 0x20746D66 )
192*f6dc9357SAndroid Build Coastguard Worker         return "wav";
193*f6dc9357SAndroid Build Coastguard Worker       break;
194*f6dc9357SAndroid Build Coastguard Worker     case kSig_PE:
195*f6dc9357SAndroid Build Coastguard Worker     {
196*f6dc9357SAndroid Build Coastguard Worker       if (size < 512)
197*f6dc9357SAndroid Build Coastguard Worker         return NULL;
198*f6dc9357SAndroid Build Coastguard Worker       UInt32 peOffset = GetUi32(p + 0x3C);
199*f6dc9357SAndroid Build Coastguard Worker       if (peOffset >= 0x1000 || peOffset + 512 > size || (peOffset & 7) != 0)
200*f6dc9357SAndroid Build Coastguard Worker         return NULL;
201*f6dc9357SAndroid Build Coastguard Worker       if (GetUi32(p + peOffset) != 0x00004550)
202*f6dc9357SAndroid Build Coastguard Worker         return NULL;
203*f6dc9357SAndroid Build Coastguard Worker       break;
204*f6dc9357SAndroid Build Coastguard Worker     }
205*f6dc9357SAndroid Build Coastguard Worker   }
206*f6dc9357SAndroid Build Coastguard Worker   return g_Sigs[i].ext;
207*f6dc9357SAndroid Build Coastguard Worker }
208*f6dc9357SAndroid Build Coastguard Worker 
AreGuidsEq(const Byte * p1,const Byte * p2)209*f6dc9357SAndroid Build Coastguard Worker static bool AreGuidsEq(const Byte *p1, const Byte *p2)
210*f6dc9357SAndroid Build Coastguard Worker {
211*f6dc9357SAndroid Build Coastguard Worker   return memcmp(p1, p2, kGuidSize) == 0;
212*f6dc9357SAndroid Build Coastguard Worker }
213*f6dc9357SAndroid Build Coastguard Worker 
FindGuid(const Byte * p)214*f6dc9357SAndroid Build Coastguard Worker static int FindGuid(const Byte *p)
215*f6dc9357SAndroid Build Coastguard Worker {
216*f6dc9357SAndroid Build Coastguard Worker   for (unsigned i = 0; i < Z7_ARRAY_SIZE(kGuids); i++)
217*f6dc9357SAndroid Build Coastguard Worker     if (AreGuidsEq(p, kGuids[i]))
218*f6dc9357SAndroid Build Coastguard Worker       return (int)i;
219*f6dc9357SAndroid Build Coastguard Worker   return -1;
220*f6dc9357SAndroid Build Coastguard Worker }
221*f6dc9357SAndroid Build Coastguard Worker 
IsFfs(const Byte * p)222*f6dc9357SAndroid Build Coastguard Worker static bool IsFfs(const Byte *p)
223*f6dc9357SAndroid Build Coastguard Worker {
224*f6dc9357SAndroid Build Coastguard Worker   if (Get32(p + 0x28) != kFvSignature)
225*f6dc9357SAndroid Build Coastguard Worker     return false;
226*f6dc9357SAndroid Build Coastguard Worker   for (unsigned i = 0; i < Z7_ARRAY_SIZE(k_Guids_FS); i++)
227*f6dc9357SAndroid Build Coastguard Worker     if (AreGuidsEq(p + kFfsGuidOffset, k_Guids_FS[i]))
228*f6dc9357SAndroid Build Coastguard Worker       return true;
229*f6dc9357SAndroid Build Coastguard Worker   return false;
230*f6dc9357SAndroid Build Coastguard Worker }
231*f6dc9357SAndroid Build Coastguard Worker 
232*f6dc9357SAndroid Build Coastguard Worker #define FVB_ERASE_POLARITY  (1 << 11)
233*f6dc9357SAndroid Build Coastguard Worker 
234*f6dc9357SAndroid Build Coastguard Worker /*
235*f6dc9357SAndroid Build Coastguard Worker static const CUInt32PCharPair g_FV_Attribs[] =
236*f6dc9357SAndroid Build Coastguard Worker {
237*f6dc9357SAndroid Build Coastguard Worker   {  0, "ReadDisabledCap" },
238*f6dc9357SAndroid Build Coastguard Worker   {  1, "ReadEnabledCap" },
239*f6dc9357SAndroid Build Coastguard Worker   {  2, "ReadEnabled" },
240*f6dc9357SAndroid Build Coastguard Worker   {  3, "WriteDisabledCap" },
241*f6dc9357SAndroid Build Coastguard Worker   {  4, "WriteEnabledCap" },
242*f6dc9357SAndroid Build Coastguard Worker   {  5, "WriteEnabled" },
243*f6dc9357SAndroid Build Coastguard Worker   {  6, "LockCap" },
244*f6dc9357SAndroid Build Coastguard Worker   {  7, "Locked" },
245*f6dc9357SAndroid Build Coastguard Worker 
246*f6dc9357SAndroid Build Coastguard Worker   {  9, "StickyWrite" },
247*f6dc9357SAndroid Build Coastguard Worker   { 10, "MemoryMapped" },
248*f6dc9357SAndroid Build Coastguard Worker   { 11, "ErasePolarity" },
249*f6dc9357SAndroid Build Coastguard Worker 
250*f6dc9357SAndroid Build Coastguard Worker   { 12, "ReadLockCap" },
251*f6dc9357SAndroid Build Coastguard Worker   { 13, "WriteLockCap" },
252*f6dc9357SAndroid Build Coastguard Worker   { 14, "WriteLockCap" }
253*f6dc9357SAndroid Build Coastguard Worker };
254*f6dc9357SAndroid Build Coastguard Worker */
255*f6dc9357SAndroid Build Coastguard Worker 
256*f6dc9357SAndroid Build Coastguard Worker enum
257*f6dc9357SAndroid Build Coastguard Worker {
258*f6dc9357SAndroid Build Coastguard Worker   FV_FILETYPE_ALL,
259*f6dc9357SAndroid Build Coastguard Worker   FV_FILETYPE_RAW,
260*f6dc9357SAndroid Build Coastguard Worker   FV_FILETYPE_FREEFORM,
261*f6dc9357SAndroid Build Coastguard Worker   FV_FILETYPE_SECURITY_CORE,
262*f6dc9357SAndroid Build Coastguard Worker   FV_FILETYPE_PEI_CORE,
263*f6dc9357SAndroid Build Coastguard Worker   FV_FILETYPE_DXE_CORE,
264*f6dc9357SAndroid Build Coastguard Worker   FV_FILETYPE_PEIM,
265*f6dc9357SAndroid Build Coastguard Worker   FV_FILETYPE_DRIVER,
266*f6dc9357SAndroid Build Coastguard Worker   FV_FILETYPE_COMBINED_PEIM_DRIVER,
267*f6dc9357SAndroid Build Coastguard Worker   FV_FILETYPE_APPLICATION,
268*f6dc9357SAndroid Build Coastguard Worker   // The value 0x0A is reserved and should not be used
269*f6dc9357SAndroid Build Coastguard Worker   FV_FILETYPE_FIRMWARE_VOLUME_IMAGE = 0x0B,
270*f6dc9357SAndroid Build Coastguard Worker   // types 0xF0 - 0xFF are FFS file types
271*f6dc9357SAndroid Build Coastguard Worker   FV_FILETYPE_FFS_PAD = 0xF0
272*f6dc9357SAndroid Build Coastguard Worker };
273*f6dc9357SAndroid Build Coastguard Worker 
274*f6dc9357SAndroid Build Coastguard Worker static const char * const g_FileTypes[] =
275*f6dc9357SAndroid Build Coastguard Worker {
276*f6dc9357SAndroid Build Coastguard Worker     "ALL"
277*f6dc9357SAndroid Build Coastguard Worker   , "RAW"
278*f6dc9357SAndroid Build Coastguard Worker   , "FREEFORM"
279*f6dc9357SAndroid Build Coastguard Worker   , "SECURITY_CORE"
280*f6dc9357SAndroid Build Coastguard Worker   , "PEI_CORE"
281*f6dc9357SAndroid Build Coastguard Worker   , "DXE_CORE"
282*f6dc9357SAndroid Build Coastguard Worker   , "PEIM"
283*f6dc9357SAndroid Build Coastguard Worker   , "DRIVER"
284*f6dc9357SAndroid Build Coastguard Worker   , "COMBINED_PEIM_DRIVER"
285*f6dc9357SAndroid Build Coastguard Worker   , "APPLICATION"
286*f6dc9357SAndroid Build Coastguard Worker   , "0xA"
287*f6dc9357SAndroid Build Coastguard Worker   , "VOLUME"
288*f6dc9357SAndroid Build Coastguard Worker };
289*f6dc9357SAndroid Build Coastguard Worker 
290*f6dc9357SAndroid Build Coastguard Worker // typedef Byte FFS_FILE_ATTRIBUTES;
291*f6dc9357SAndroid Build Coastguard Worker // FFS File Attributes
292*f6dc9357SAndroid Build Coastguard Worker #define FFS_ATTRIB_TAIL_PRESENT 0x01
293*f6dc9357SAndroid Build Coastguard Worker // #define FFS_ATTRIB_RECOVERY 0x02
294*f6dc9357SAndroid Build Coastguard Worker // #define FFS_ATTRIB_HEADER_EXTENSION 0x04
295*f6dc9357SAndroid Build Coastguard Worker // #define FFS_ATTRIB_DATA_ALIGNMENT 0x38
296*f6dc9357SAndroid Build Coastguard Worker #define FFS_ATTRIB_CHECKSUM 0x40
297*f6dc9357SAndroid Build Coastguard Worker 
298*f6dc9357SAndroid Build Coastguard Worker static const CUInt32PCharPair g_FFS_FILE_ATTRIBUTES[] =
299*f6dc9357SAndroid Build Coastguard Worker {
300*f6dc9357SAndroid Build Coastguard Worker   { 0, "" /* "TAIL" */ },
301*f6dc9357SAndroid Build Coastguard Worker   { 1, "RECOVERY" },
302*f6dc9357SAndroid Build Coastguard Worker   // { 2, "HEADER_EXTENSION" }, // reserved for future
303*f6dc9357SAndroid Build Coastguard Worker   { 6, "" /* "CHECKSUM" */ }
304*f6dc9357SAndroid Build Coastguard Worker };
305*f6dc9357SAndroid Build Coastguard Worker 
306*f6dc9357SAndroid Build Coastguard Worker // static const Byte g_Allignment[8] = { 3, 4, 7, 9, 10, 12, 15, 16 };
307*f6dc9357SAndroid Build Coastguard Worker 
308*f6dc9357SAndroid Build Coastguard Worker // typedef Byte FFS_FILE_STATE;
309*f6dc9357SAndroid Build Coastguard Worker 
310*f6dc9357SAndroid Build Coastguard Worker // Look also FVB_ERASE_POLARITY.
311*f6dc9357SAndroid Build Coastguard Worker // Lower-order State bits are superceded by higher-order State bits.
312*f6dc9357SAndroid Build Coastguard Worker 
313*f6dc9357SAndroid Build Coastguard Worker // #define FILE_HEADER_CONSTRUCTION  0x01
314*f6dc9357SAndroid Build Coastguard Worker // #define FILE_HEADER_VALID         0x02
315*f6dc9357SAndroid Build Coastguard Worker #define FILE_DATA_VALID           0x04
316*f6dc9357SAndroid Build Coastguard Worker // #define FILE_MARKED_FOR_UPDATE    0x08
317*f6dc9357SAndroid Build Coastguard Worker // #define FILE_DELETED              0x10
318*f6dc9357SAndroid Build Coastguard Worker // #define FILE_HEADER_INVALID       0x20
319*f6dc9357SAndroid Build Coastguard Worker 
320*f6dc9357SAndroid Build Coastguard Worker // SECTION_TYPE
321*f6dc9357SAndroid Build Coastguard Worker 
322*f6dc9357SAndroid Build Coastguard Worker // #define SECTION_ALL 0x00
323*f6dc9357SAndroid Build Coastguard Worker 
324*f6dc9357SAndroid Build Coastguard Worker #define SECTION_COMPRESSION  0x01
325*f6dc9357SAndroid Build Coastguard Worker #define SECTION_GUID_DEFINED 0x02
326*f6dc9357SAndroid Build Coastguard Worker 
327*f6dc9357SAndroid Build Coastguard Worker // Leaf section Type values
328*f6dc9357SAndroid Build Coastguard Worker // #define SECTION_PE32      0x10
329*f6dc9357SAndroid Build Coastguard Worker // #define SECTION_PIC       0x11
330*f6dc9357SAndroid Build Coastguard Worker // #define SECTION_TE        0x12
331*f6dc9357SAndroid Build Coastguard Worker #define SECTION_DXE_DEPEX 0x13
332*f6dc9357SAndroid Build Coastguard Worker #define SECTION_VERSION   0x14
333*f6dc9357SAndroid Build Coastguard Worker #define SECTION_USER_INTERFACE 0x15
334*f6dc9357SAndroid Build Coastguard Worker // #define SECTION_COMPATIBILITY16 0x16
335*f6dc9357SAndroid Build Coastguard Worker #define SECTION_FIRMWARE_VOLUME_IMAGE 0x17
336*f6dc9357SAndroid Build Coastguard Worker #define SECTION_FREEFORM_SUBTYPE_GUID 0x18
337*f6dc9357SAndroid Build Coastguard Worker #define SECTION_RAW       0x19
338*f6dc9357SAndroid Build Coastguard Worker #define SECTION_PEI_DEPEX 0x1B
339*f6dc9357SAndroid Build Coastguard Worker 
340*f6dc9357SAndroid Build Coastguard Worker 
341*f6dc9357SAndroid Build Coastguard Worker // #define GUIDED_SECTION_PROCESSING_REQUIRED 0x01
342*f6dc9357SAndroid Build Coastguard Worker // #define GUIDED_SECTION_AUTH_STATUS_VALID 0x02
343*f6dc9357SAndroid Build Coastguard Worker 
344*f6dc9357SAndroid Build Coastguard Worker static const CUInt32PCharPair g_GUIDED_SECTION_ATTRIBUTES[] =
345*f6dc9357SAndroid Build Coastguard Worker {
346*f6dc9357SAndroid Build Coastguard Worker   { 0, "PROCESSING_REQUIRED" },
347*f6dc9357SAndroid Build Coastguard Worker   { 1, "AUTH" }
348*f6dc9357SAndroid Build Coastguard Worker };
349*f6dc9357SAndroid Build Coastguard Worker 
350*f6dc9357SAndroid Build Coastguard Worker static const CUInt32PCharPair g_SECTION_TYPE[] =
351*f6dc9357SAndroid Build Coastguard Worker {
352*f6dc9357SAndroid Build Coastguard Worker   { 0x01, "COMPRESSION" },
353*f6dc9357SAndroid Build Coastguard Worker   { 0x02, "GUID" },
354*f6dc9357SAndroid Build Coastguard Worker   { 0x10, "efi" },
355*f6dc9357SAndroid Build Coastguard Worker   { 0x11, "PIC" },
356*f6dc9357SAndroid Build Coastguard Worker   { 0x12, "te" },
357*f6dc9357SAndroid Build Coastguard Worker   { 0x13, "DXE_DEPEX" },
358*f6dc9357SAndroid Build Coastguard Worker   { 0x14, "VERSION" },
359*f6dc9357SAndroid Build Coastguard Worker   { 0x15, "USER_INTERFACE" },
360*f6dc9357SAndroid Build Coastguard Worker   { 0x16, "COMPATIBILITY16" },
361*f6dc9357SAndroid Build Coastguard Worker   { 0x17, "VOLUME" },
362*f6dc9357SAndroid Build Coastguard Worker   { 0x18, "FREEFORM_SUBTYPE_GUID" },
363*f6dc9357SAndroid Build Coastguard Worker   { 0x19, "raw" },
364*f6dc9357SAndroid Build Coastguard Worker   { 0x1B, "PEI_DEPEX" }
365*f6dc9357SAndroid Build Coastguard Worker };
366*f6dc9357SAndroid Build Coastguard Worker 
367*f6dc9357SAndroid Build Coastguard Worker #define COMPRESSION_TYPE_NONE 0
368*f6dc9357SAndroid Build Coastguard Worker #define COMPRESSION_TYPE_LZH  1
369*f6dc9357SAndroid Build Coastguard Worker #define COMPRESSION_TYPE_LZMA 2
370*f6dc9357SAndroid Build Coastguard Worker 
371*f6dc9357SAndroid Build Coastguard Worker static const char * const g_Methods[] =
372*f6dc9357SAndroid Build Coastguard Worker {
373*f6dc9357SAndroid Build Coastguard Worker     "COPY"
374*f6dc9357SAndroid Build Coastguard Worker   , "LZH"
375*f6dc9357SAndroid Build Coastguard Worker   , "LZMA"
376*f6dc9357SAndroid Build Coastguard Worker };
377*f6dc9357SAndroid Build Coastguard Worker 
378*f6dc9357SAndroid Build Coastguard Worker 
AddGuid(AString & dest,const Byte * p,bool full)379*f6dc9357SAndroid Build Coastguard Worker static void AddGuid(AString &dest, const Byte *p, bool full)
380*f6dc9357SAndroid Build Coastguard Worker {
381*f6dc9357SAndroid Build Coastguard Worker   char s[64];
382*f6dc9357SAndroid Build Coastguard Worker   ::RawLeGuidToString(p, s);
383*f6dc9357SAndroid Build Coastguard Worker   // MyStringUpper_Ascii(s);
384*f6dc9357SAndroid Build Coastguard Worker   if (!full)
385*f6dc9357SAndroid Build Coastguard Worker     s[8] = 0;
386*f6dc9357SAndroid Build Coastguard Worker   dest += s;
387*f6dc9357SAndroid Build Coastguard Worker }
388*f6dc9357SAndroid Build Coastguard Worker 
389*f6dc9357SAndroid Build Coastguard Worker static const char * const kExpressionCommands[] =
390*f6dc9357SAndroid Build Coastguard Worker {
391*f6dc9357SAndroid Build Coastguard Worker   "BEFORE", "AFTER", "PUSH", "AND", "OR", "NOT", "TRUE", "FALSE", "END", "SOR"
392*f6dc9357SAndroid Build Coastguard Worker };
393*f6dc9357SAndroid Build Coastguard Worker 
ParseDepedencyExpression(const Byte * p,UInt32 size,AString & res)394*f6dc9357SAndroid Build Coastguard Worker static bool ParseDepedencyExpression(const Byte *p, UInt32 size, AString &res)
395*f6dc9357SAndroid Build Coastguard Worker {
396*f6dc9357SAndroid Build Coastguard Worker   res.Empty();
397*f6dc9357SAndroid Build Coastguard Worker   for (UInt32 i = 0; i < size;)
398*f6dc9357SAndroid Build Coastguard Worker   {
399*f6dc9357SAndroid Build Coastguard Worker     unsigned command = p[i++];
400*f6dc9357SAndroid Build Coastguard Worker     if (command > Z7_ARRAY_SIZE(kExpressionCommands))
401*f6dc9357SAndroid Build Coastguard Worker       return false;
402*f6dc9357SAndroid Build Coastguard Worker     res += kExpressionCommands[command];
403*f6dc9357SAndroid Build Coastguard Worker     if (command < 3)
404*f6dc9357SAndroid Build Coastguard Worker     {
405*f6dc9357SAndroid Build Coastguard Worker       if (i + kGuidSize > size)
406*f6dc9357SAndroid Build Coastguard Worker         return false;
407*f6dc9357SAndroid Build Coastguard Worker       res.Add_Space();
408*f6dc9357SAndroid Build Coastguard Worker       AddGuid(res, p + i, false);
409*f6dc9357SAndroid Build Coastguard Worker       i += kGuidSize;
410*f6dc9357SAndroid Build Coastguard Worker     }
411*f6dc9357SAndroid Build Coastguard Worker     res += "; ";
412*f6dc9357SAndroid Build Coastguard Worker   }
413*f6dc9357SAndroid Build Coastguard Worker   return true;
414*f6dc9357SAndroid Build Coastguard Worker }
415*f6dc9357SAndroid Build Coastguard Worker 
ParseUtf16zString(const Byte * p,UInt32 size,UString & res)416*f6dc9357SAndroid Build Coastguard Worker static bool ParseUtf16zString(const Byte *p, UInt32 size, UString &res)
417*f6dc9357SAndroid Build Coastguard Worker {
418*f6dc9357SAndroid Build Coastguard Worker   if ((size & 1) != 0)
419*f6dc9357SAndroid Build Coastguard Worker     return false;
420*f6dc9357SAndroid Build Coastguard Worker   res.Empty();
421*f6dc9357SAndroid Build Coastguard Worker   UInt32 i;
422*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < size; i += 2)
423*f6dc9357SAndroid Build Coastguard Worker   {
424*f6dc9357SAndroid Build Coastguard Worker     wchar_t c = Get16(p + i);
425*f6dc9357SAndroid Build Coastguard Worker     if (c == 0)
426*f6dc9357SAndroid Build Coastguard Worker       break;
427*f6dc9357SAndroid Build Coastguard Worker     res += c;
428*f6dc9357SAndroid Build Coastguard Worker   }
429*f6dc9357SAndroid Build Coastguard Worker   return (i == size - 2);
430*f6dc9357SAndroid Build Coastguard Worker }
431*f6dc9357SAndroid Build Coastguard Worker 
ParseUtf16zString2(const Byte * p,UInt32 size,AString & res)432*f6dc9357SAndroid Build Coastguard Worker static bool ParseUtf16zString2(const Byte *p, UInt32 size, AString &res)
433*f6dc9357SAndroid Build Coastguard Worker {
434*f6dc9357SAndroid Build Coastguard Worker   UString s;
435*f6dc9357SAndroid Build Coastguard Worker   if (!ParseUtf16zString(p, size, s))
436*f6dc9357SAndroid Build Coastguard Worker     return false;
437*f6dc9357SAndroid Build Coastguard Worker   res = UnicodeStringToMultiByte(s);
438*f6dc9357SAndroid Build Coastguard Worker   return true;
439*f6dc9357SAndroid Build Coastguard Worker }
440*f6dc9357SAndroid Build Coastguard Worker 
441*f6dc9357SAndroid Build Coastguard Worker #define FLAGS_TO_STRING(pairs, value) FlagsToString(pairs, Z7_ARRAY_SIZE(pairs), value)
442*f6dc9357SAndroid Build Coastguard Worker #define TYPE_TO_STRING(table, value) TypeToString(table, Z7_ARRAY_SIZE(table), value)
443*f6dc9357SAndroid Build Coastguard Worker #define TYPE_PAIR_TO_STRING(table, value) TypePairToString(table, Z7_ARRAY_SIZE(table), value)
444*f6dc9357SAndroid Build Coastguard Worker 
445*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kFileHeaderSize = 24;
446*f6dc9357SAndroid Build Coastguard Worker 
AddSpaceAndString(AString & res,const AString & newString)447*f6dc9357SAndroid Build Coastguard Worker static void AddSpaceAndString(AString &res, const AString &newString)
448*f6dc9357SAndroid Build Coastguard Worker {
449*f6dc9357SAndroid Build Coastguard Worker   if (!newString.IsEmpty())
450*f6dc9357SAndroid Build Coastguard Worker   {
451*f6dc9357SAndroid Build Coastguard Worker     res.Add_Space_if_NotEmpty();
452*f6dc9357SAndroid Build Coastguard Worker     res += newString;
453*f6dc9357SAndroid Build Coastguard Worker   }
454*f6dc9357SAndroid Build Coastguard Worker }
455*f6dc9357SAndroid Build Coastguard Worker 
456*f6dc9357SAndroid Build Coastguard Worker class CFfsFileHeader
457*f6dc9357SAndroid Build Coastguard Worker {
458*f6dc9357SAndroid Build Coastguard Worker PRF(public:)
459*f6dc9357SAndroid Build Coastguard Worker   Byte CheckHeader;
460*f6dc9357SAndroid Build Coastguard Worker   Byte CheckFile;
461*f6dc9357SAndroid Build Coastguard Worker   Byte Attrib;
462*f6dc9357SAndroid Build Coastguard Worker   Byte State;
463*f6dc9357SAndroid Build Coastguard Worker 
GetTailReference() const464*f6dc9357SAndroid Build Coastguard Worker   UInt16 GetTailReference() const { return (UInt16)(CheckHeader | ((UInt16)CheckFile << 8)); }
GetTailSize() const465*f6dc9357SAndroid Build Coastguard Worker   UInt32 GetTailSize() const { return IsThereTail() ? 2 : 0; }
IsThereFileChecksum() const466*f6dc9357SAndroid Build Coastguard Worker   bool IsThereFileChecksum() const { return (Attrib & FFS_ATTRIB_CHECKSUM) != 0; }
IsThereTail() const467*f6dc9357SAndroid Build Coastguard Worker   bool IsThereTail() const { return (Attrib & FFS_ATTRIB_TAIL_PRESENT) != 0; }
468*f6dc9357SAndroid Build Coastguard Worker public:
469*f6dc9357SAndroid Build Coastguard Worker   Byte GuidName[kGuidSize];
470*f6dc9357SAndroid Build Coastguard Worker   Byte Type;
471*f6dc9357SAndroid Build Coastguard Worker   UInt32 Size;
472*f6dc9357SAndroid Build Coastguard Worker 
Parse(const Byte * p)473*f6dc9357SAndroid Build Coastguard Worker   bool Parse(const Byte *p)
474*f6dc9357SAndroid Build Coastguard Worker   {
475*f6dc9357SAndroid Build Coastguard Worker     unsigned i;
476*f6dc9357SAndroid Build Coastguard Worker     for (i = 0; i < kFileHeaderSize; i++)
477*f6dc9357SAndroid Build Coastguard Worker       if (p[i] != 0xFF)
478*f6dc9357SAndroid Build Coastguard Worker         break;
479*f6dc9357SAndroid Build Coastguard Worker     if (i == kFileHeaderSize)
480*f6dc9357SAndroid Build Coastguard Worker       return false;
481*f6dc9357SAndroid Build Coastguard Worker     memcpy(GuidName, p, kGuidSize);
482*f6dc9357SAndroid Build Coastguard Worker     CheckHeader = p[0x10];
483*f6dc9357SAndroid Build Coastguard Worker     CheckFile = p[0x11];
484*f6dc9357SAndroid Build Coastguard Worker     Type = p[0x12];
485*f6dc9357SAndroid Build Coastguard Worker     Attrib = p[0x13];
486*f6dc9357SAndroid Build Coastguard Worker     Size = Get24(p + 0x14);
487*f6dc9357SAndroid Build Coastguard Worker     State = p[0x17];
488*f6dc9357SAndroid Build Coastguard Worker     return true;
489*f6dc9357SAndroid Build Coastguard Worker   }
490*f6dc9357SAndroid Build Coastguard Worker 
GetDataSize() const491*f6dc9357SAndroid Build Coastguard Worker   UInt32 GetDataSize() const { return Size - kFileHeaderSize - GetTailSize(); }
GetDataSize2(UInt32 rem) const492*f6dc9357SAndroid Build Coastguard Worker   UInt32 GetDataSize2(UInt32 rem) const { return rem - kFileHeaderSize - GetTailSize(); }
493*f6dc9357SAndroid Build Coastguard Worker 
Check(const Byte * p,UInt32 size)494*f6dc9357SAndroid Build Coastguard Worker   bool Check(const Byte *p, UInt32 size)
495*f6dc9357SAndroid Build Coastguard Worker   {
496*f6dc9357SAndroid Build Coastguard Worker     if (Size > size)
497*f6dc9357SAndroid Build Coastguard Worker       return false;
498*f6dc9357SAndroid Build Coastguard Worker     UInt32 tailSize = GetTailSize();
499*f6dc9357SAndroid Build Coastguard Worker     if (Size < kFileHeaderSize + tailSize)
500*f6dc9357SAndroid Build Coastguard Worker       return false;
501*f6dc9357SAndroid Build Coastguard Worker 
502*f6dc9357SAndroid Build Coastguard Worker     {
503*f6dc9357SAndroid Build Coastguard Worker       unsigned checkSum = 0;
504*f6dc9357SAndroid Build Coastguard Worker       for (UInt32 i = 0; i < kFileHeaderSize; i++)
505*f6dc9357SAndroid Build Coastguard Worker         checkSum += p[i];
506*f6dc9357SAndroid Build Coastguard Worker       checkSum -= p[0x17];
507*f6dc9357SAndroid Build Coastguard Worker       checkSum -= p[0x11];
508*f6dc9357SAndroid Build Coastguard Worker       if ((Byte)checkSum != 0)
509*f6dc9357SAndroid Build Coastguard Worker         return false;
510*f6dc9357SAndroid Build Coastguard Worker     }
511*f6dc9357SAndroid Build Coastguard Worker 
512*f6dc9357SAndroid Build Coastguard Worker     if (IsThereFileChecksum())
513*f6dc9357SAndroid Build Coastguard Worker     {
514*f6dc9357SAndroid Build Coastguard Worker       unsigned checkSum = 0;
515*f6dc9357SAndroid Build Coastguard Worker       UInt32 checkSize = Size - tailSize;
516*f6dc9357SAndroid Build Coastguard Worker       for (UInt32 i = 0; i < checkSize; i++)
517*f6dc9357SAndroid Build Coastguard Worker         checkSum += p[i];
518*f6dc9357SAndroid Build Coastguard Worker       checkSum -= p[0x17];
519*f6dc9357SAndroid Build Coastguard Worker       if ((Byte)checkSum != 0)
520*f6dc9357SAndroid Build Coastguard Worker         return false;
521*f6dc9357SAndroid Build Coastguard Worker     }
522*f6dc9357SAndroid Build Coastguard Worker 
523*f6dc9357SAndroid Build Coastguard Worker     if (IsThereTail())
524*f6dc9357SAndroid Build Coastguard Worker       if (GetTailReference() != (UInt16)~Get16(p + Size - 2))
525*f6dc9357SAndroid Build Coastguard Worker         return false;
526*f6dc9357SAndroid Build Coastguard Worker 
527*f6dc9357SAndroid Build Coastguard Worker     int polarity = 0;
528*f6dc9357SAndroid Build Coastguard Worker     int i;
529*f6dc9357SAndroid Build Coastguard Worker     for (i = 5; i >= 0; i--)
530*f6dc9357SAndroid Build Coastguard Worker       if (((State >> i) & 1) == polarity)
531*f6dc9357SAndroid Build Coastguard Worker       {
532*f6dc9357SAndroid Build Coastguard Worker         // AddSpaceAndString(s, g_FFS_FILE_STATE_Flags[i]);
533*f6dc9357SAndroid Build Coastguard Worker         if ((1 << i) != FILE_DATA_VALID)
534*f6dc9357SAndroid Build Coastguard Worker           return false;
535*f6dc9357SAndroid Build Coastguard Worker         break;
536*f6dc9357SAndroid Build Coastguard Worker       }
537*f6dc9357SAndroid Build Coastguard Worker     if (i < 0)
538*f6dc9357SAndroid Build Coastguard Worker       return false;
539*f6dc9357SAndroid Build Coastguard Worker 
540*f6dc9357SAndroid Build Coastguard Worker     return true;
541*f6dc9357SAndroid Build Coastguard Worker   }
542*f6dc9357SAndroid Build Coastguard Worker 
GetCharacts() const543*f6dc9357SAndroid Build Coastguard Worker   AString GetCharacts() const
544*f6dc9357SAndroid Build Coastguard Worker   {
545*f6dc9357SAndroid Build Coastguard Worker     AString s;
546*f6dc9357SAndroid Build Coastguard Worker     if (Type == FV_FILETYPE_FFS_PAD)
547*f6dc9357SAndroid Build Coastguard Worker       s += "PAD";
548*f6dc9357SAndroid Build Coastguard Worker     else
549*f6dc9357SAndroid Build Coastguard Worker       s += TYPE_TO_STRING(g_FileTypes, Type);
550*f6dc9357SAndroid Build Coastguard Worker     AddSpaceAndString(s, FLAGS_TO_STRING(g_FFS_FILE_ATTRIBUTES, Attrib & 0xC7));
551*f6dc9357SAndroid Build Coastguard Worker     /*
552*f6dc9357SAndroid Build Coastguard Worker     int align = (Attrib >> 3) & 7;
553*f6dc9357SAndroid Build Coastguard Worker     if (align != 0)
554*f6dc9357SAndroid Build Coastguard Worker     {
555*f6dc9357SAndroid Build Coastguard Worker       s += " Align:";
556*f6dc9357SAndroid Build Coastguard Worker       s.Add_UInt32((UInt32)1 << g_Allignment[align]);
557*f6dc9357SAndroid Build Coastguard Worker     }
558*f6dc9357SAndroid Build Coastguard Worker     */
559*f6dc9357SAndroid Build Coastguard Worker     return s;
560*f6dc9357SAndroid Build Coastguard Worker   }
561*f6dc9357SAndroid Build Coastguard Worker };
562*f6dc9357SAndroid Build Coastguard Worker 
563*f6dc9357SAndroid Build Coastguard Worker #define G32(_offs_, dest) dest = Get32(p + (_offs_))
564*f6dc9357SAndroid Build Coastguard Worker #define G16(_offs_, dest) dest = Get16(p + (_offs_))
565*f6dc9357SAndroid Build Coastguard Worker 
566*f6dc9357SAndroid Build Coastguard Worker struct CCapsuleHeader
567*f6dc9357SAndroid Build Coastguard Worker {
568*f6dc9357SAndroid Build Coastguard Worker   UInt32 HeaderSize;
569*f6dc9357SAndroid Build Coastguard Worker   UInt32 Flags;
570*f6dc9357SAndroid Build Coastguard Worker   UInt32 CapsuleImageSize;
571*f6dc9357SAndroid Build Coastguard Worker   UInt32 SequenceNumber;
572*f6dc9357SAndroid Build Coastguard Worker   // Guid InstanceId;
573*f6dc9357SAndroid Build Coastguard Worker   UInt32 OffsetToSplitInformation;
574*f6dc9357SAndroid Build Coastguard Worker   UInt32 OffsetToCapsuleBody;
575*f6dc9357SAndroid Build Coastguard Worker   UInt32 OffsetToOemDefinedHeader;
576*f6dc9357SAndroid Build Coastguard Worker   UInt32 OffsetToAuthorInformation;
577*f6dc9357SAndroid Build Coastguard Worker   UInt32 OffsetToRevisionInformation;
578*f6dc9357SAndroid Build Coastguard Worker   UInt32 OffsetToShortDescription;
579*f6dc9357SAndroid Build Coastguard Worker   UInt32 OffsetToLongDescription;
580*f6dc9357SAndroid Build Coastguard Worker   UInt32 OffsetToApplicableDevices;
581*f6dc9357SAndroid Build Coastguard Worker 
ClearNArchive::NUefi::CCapsuleHeader582*f6dc9357SAndroid Build Coastguard Worker   void Clear() { memset(this, 0, sizeof(*this)); }
583*f6dc9357SAndroid Build Coastguard Worker 
ParseNArchive::NUefi::CCapsuleHeader584*f6dc9357SAndroid Build Coastguard Worker   bool Parse(const Byte *p)
585*f6dc9357SAndroid Build Coastguard Worker   {
586*f6dc9357SAndroid Build Coastguard Worker     Clear();
587*f6dc9357SAndroid Build Coastguard Worker     G32(0x10, HeaderSize);
588*f6dc9357SAndroid Build Coastguard Worker     G32(0x14, Flags);
589*f6dc9357SAndroid Build Coastguard Worker     G32(0x18, CapsuleImageSize);
590*f6dc9357SAndroid Build Coastguard Worker     if (HeaderSize < 0x1C)
591*f6dc9357SAndroid Build Coastguard Worker       return false;
592*f6dc9357SAndroid Build Coastguard Worker     if (AreGuidsEq(p, k_Guids_Capsules[0]))
593*f6dc9357SAndroid Build Coastguard Worker     {
594*f6dc9357SAndroid Build Coastguard Worker       const unsigned kHeaderSize = 80;
595*f6dc9357SAndroid Build Coastguard Worker       if (HeaderSize != kHeaderSize)
596*f6dc9357SAndroid Build Coastguard Worker         return false;
597*f6dc9357SAndroid Build Coastguard Worker       G32(0x1C, SequenceNumber);
598*f6dc9357SAndroid Build Coastguard Worker       G32(0x30, OffsetToSplitInformation);
599*f6dc9357SAndroid Build Coastguard Worker       G32(0x34, OffsetToCapsuleBody);
600*f6dc9357SAndroid Build Coastguard Worker       G32(0x38, OffsetToOemDefinedHeader);
601*f6dc9357SAndroid Build Coastguard Worker       G32(0x3C, OffsetToAuthorInformation);
602*f6dc9357SAndroid Build Coastguard Worker       G32(0x40, OffsetToRevisionInformation);
603*f6dc9357SAndroid Build Coastguard Worker       G32(0x44, OffsetToShortDescription);
604*f6dc9357SAndroid Build Coastguard Worker       G32(0x48, OffsetToLongDescription);
605*f6dc9357SAndroid Build Coastguard Worker       G32(0x4C, OffsetToApplicableDevices);
606*f6dc9357SAndroid Build Coastguard Worker       return true;
607*f6dc9357SAndroid Build Coastguard Worker     }
608*f6dc9357SAndroid Build Coastguard Worker     else if (AreGuidsEq(p, k_Guids_Capsules[1]))
609*f6dc9357SAndroid Build Coastguard Worker     {
610*f6dc9357SAndroid Build Coastguard Worker       // capsule v2
611*f6dc9357SAndroid Build Coastguard Worker       G16(0x1C, OffsetToCapsuleBody);
612*f6dc9357SAndroid Build Coastguard Worker       G16(0x1E, OffsetToOemDefinedHeader);
613*f6dc9357SAndroid Build Coastguard Worker       return true;
614*f6dc9357SAndroid Build Coastguard Worker     }
615*f6dc9357SAndroid Build Coastguard Worker     else if (AreGuidsEq(p, k_Guids_Capsules[2]))
616*f6dc9357SAndroid Build Coastguard Worker     {
617*f6dc9357SAndroid Build Coastguard Worker       OffsetToCapsuleBody = HeaderSize;
618*f6dc9357SAndroid Build Coastguard Worker       return true;
619*f6dc9357SAndroid Build Coastguard Worker     }
620*f6dc9357SAndroid Build Coastguard Worker     else
621*f6dc9357SAndroid Build Coastguard Worker     {
622*f6dc9357SAndroid Build Coastguard Worker       // here we must check for another capsule types
623*f6dc9357SAndroid Build Coastguard Worker       return false;
624*f6dc9357SAndroid Build Coastguard Worker     }
625*f6dc9357SAndroid Build Coastguard Worker   }
626*f6dc9357SAndroid Build Coastguard Worker };
627*f6dc9357SAndroid Build Coastguard Worker 
628*f6dc9357SAndroid Build Coastguard Worker 
629*f6dc9357SAndroid Build Coastguard Worker struct CItem
630*f6dc9357SAndroid Build Coastguard Worker {
631*f6dc9357SAndroid Build Coastguard Worker   AString Name;
632*f6dc9357SAndroid Build Coastguard Worker   AString Characts;
633*f6dc9357SAndroid Build Coastguard Worker   int Parent;
634*f6dc9357SAndroid Build Coastguard Worker   int Method;
635*f6dc9357SAndroid Build Coastguard Worker   int NameIndex;
636*f6dc9357SAndroid Build Coastguard Worker   unsigned NumChilds;
637*f6dc9357SAndroid Build Coastguard Worker   bool IsDir;
638*f6dc9357SAndroid Build Coastguard Worker   bool Skip;
639*f6dc9357SAndroid Build Coastguard Worker   bool ThereAreSubDirs;
640*f6dc9357SAndroid Build Coastguard Worker   bool ThereIsUniqueName;
641*f6dc9357SAndroid Build Coastguard Worker   bool KeepName;
642*f6dc9357SAndroid Build Coastguard Worker 
643*f6dc9357SAndroid Build Coastguard Worker   unsigned BufIndex;
644*f6dc9357SAndroid Build Coastguard Worker   UInt32 Offset;
645*f6dc9357SAndroid Build Coastguard Worker   UInt32 Size;
646*f6dc9357SAndroid Build Coastguard Worker 
CItemNArchive::NUefi::CItem647*f6dc9357SAndroid Build Coastguard Worker   CItem(): Parent(-1), Method(-1), NameIndex(-1), NumChilds(0),
648*f6dc9357SAndroid Build Coastguard Worker       IsDir(false), Skip(false), ThereAreSubDirs(false), ThereIsUniqueName(false), KeepName(true) {}
649*f6dc9357SAndroid Build Coastguard Worker   void SetGuid(const Byte *guidName, bool full = false);
650*f6dc9357SAndroid Build Coastguard Worker   AString GetName(int numChildsInParent) const;
651*f6dc9357SAndroid Build Coastguard Worker };
652*f6dc9357SAndroid Build Coastguard Worker 
SetGuid(const Byte * guidName,bool full)653*f6dc9357SAndroid Build Coastguard Worker void CItem::SetGuid(const Byte *guidName, bool full)
654*f6dc9357SAndroid Build Coastguard Worker {
655*f6dc9357SAndroid Build Coastguard Worker   ThereIsUniqueName = true;
656*f6dc9357SAndroid Build Coastguard Worker   int index = FindGuid(guidName);
657*f6dc9357SAndroid Build Coastguard Worker   if (index >= 0)
658*f6dc9357SAndroid Build Coastguard Worker     Name = kGuidNames[(unsigned)index];
659*f6dc9357SAndroid Build Coastguard Worker   else
660*f6dc9357SAndroid Build Coastguard Worker   {
661*f6dc9357SAndroid Build Coastguard Worker     Name.Empty();
662*f6dc9357SAndroid Build Coastguard Worker     AddGuid(Name, guidName, full);
663*f6dc9357SAndroid Build Coastguard Worker   }
664*f6dc9357SAndroid Build Coastguard Worker }
665*f6dc9357SAndroid Build Coastguard Worker 
GetName(int numChildsInParent) const666*f6dc9357SAndroid Build Coastguard Worker AString CItem::GetName(int numChildsInParent) const
667*f6dc9357SAndroid Build Coastguard Worker {
668*f6dc9357SAndroid Build Coastguard Worker   if (numChildsInParent <= 1 || NameIndex < 0)
669*f6dc9357SAndroid Build Coastguard Worker     return Name;
670*f6dc9357SAndroid Build Coastguard Worker   char sz[32];
671*f6dc9357SAndroid Build Coastguard Worker   char sz2[32];
672*f6dc9357SAndroid Build Coastguard Worker   ConvertUInt32ToString((unsigned)NameIndex, sz);
673*f6dc9357SAndroid Build Coastguard Worker   ConvertUInt32ToString((unsigned)numChildsInParent - 1, sz2);
674*f6dc9357SAndroid Build Coastguard Worker   const int numZeros = (int)strlen(sz2) - (int)strlen(sz);
675*f6dc9357SAndroid Build Coastguard Worker   AString res;
676*f6dc9357SAndroid Build Coastguard Worker   for (int i = 0; i < numZeros; i++)
677*f6dc9357SAndroid Build Coastguard Worker     res += '0';
678*f6dc9357SAndroid Build Coastguard Worker   res += sz;
679*f6dc9357SAndroid Build Coastguard Worker   res.Add_Dot();
680*f6dc9357SAndroid Build Coastguard Worker   res += Name;
681*f6dc9357SAndroid Build Coastguard Worker   return res;
682*f6dc9357SAndroid Build Coastguard Worker }
683*f6dc9357SAndroid Build Coastguard Worker 
684*f6dc9357SAndroid Build Coastguard Worker struct CItem2
685*f6dc9357SAndroid Build Coastguard Worker {
686*f6dc9357SAndroid Build Coastguard Worker   AString Name;
687*f6dc9357SAndroid Build Coastguard Worker   AString Characts;
688*f6dc9357SAndroid Build Coastguard Worker   unsigned MainIndex;
689*f6dc9357SAndroid Build Coastguard Worker   int Parent;
690*f6dc9357SAndroid Build Coastguard Worker 
CItem2NArchive::NUefi::CItem2691*f6dc9357SAndroid Build Coastguard Worker   CItem2(): Parent(-1) {}
692*f6dc9357SAndroid Build Coastguard Worker };
693*f6dc9357SAndroid Build Coastguard Worker 
694*f6dc9357SAndroid Build Coastguard Worker 
695*f6dc9357SAndroid Build Coastguard Worker Z7_CLASS_IMP_CHandler_IInArchive_1(
696*f6dc9357SAndroid Build Coastguard Worker     IInArchiveGetStream
697*f6dc9357SAndroid Build Coastguard Worker )
698*f6dc9357SAndroid Build Coastguard Worker   CObjectVector<CItem> _items;
699*f6dc9357SAndroid Build Coastguard Worker   CObjectVector<CItem2> _items2;
700*f6dc9357SAndroid Build Coastguard Worker   CObjectVector<CByteBuffer> _bufs;
701*f6dc9357SAndroid Build Coastguard Worker   UString _comment;
702*f6dc9357SAndroid Build Coastguard Worker   UInt32 _methodsMask;
703*f6dc9357SAndroid Build Coastguard Worker   bool _capsuleMode;
704*f6dc9357SAndroid Build Coastguard Worker   bool _headersError;
705*f6dc9357SAndroid Build Coastguard Worker 
706*f6dc9357SAndroid Build Coastguard Worker   size_t _totalBufsSize;
707*f6dc9357SAndroid Build Coastguard Worker   CCapsuleHeader _h;
708*f6dc9357SAndroid Build Coastguard Worker   UInt64 _phySize;
709*f6dc9357SAndroid Build Coastguard Worker 
710*f6dc9357SAndroid Build Coastguard Worker   void AddCommentString(const char *name, UInt32 pos);
711*f6dc9357SAndroid Build Coastguard Worker   unsigned AddItem(const CItem &item);
712*f6dc9357SAndroid Build Coastguard Worker   unsigned AddFileItemWithIndex(CItem &item);
713*f6dc9357SAndroid Build Coastguard Worker   unsigned AddDirItem(CItem &item);
714*f6dc9357SAndroid Build Coastguard Worker   unsigned AddBuf(size_t size);
715*f6dc9357SAndroid Build Coastguard Worker 
716*f6dc9357SAndroid Build Coastguard Worker   HRESULT DecodeLzma(const Byte *data, size_t inputSize);
717*f6dc9357SAndroid Build Coastguard Worker 
718*f6dc9357SAndroid Build Coastguard Worker   HRESULT ParseSections(unsigned bufIndex, UInt32 pos,
719*f6dc9357SAndroid Build Coastguard Worker       UInt32 size,
720*f6dc9357SAndroid Build Coastguard Worker       int parent, int method, unsigned level,
721*f6dc9357SAndroid Build Coastguard Worker       bool &error);
722*f6dc9357SAndroid Build Coastguard Worker 
723*f6dc9357SAndroid Build Coastguard Worker   HRESULT ParseIntelMe(unsigned bufIndex, UInt32 posBase,
724*f6dc9357SAndroid Build Coastguard Worker       UInt32 exactSize, UInt32 limitSize,
725*f6dc9357SAndroid Build Coastguard Worker       int parent, int method, unsigned level);
726*f6dc9357SAndroid Build Coastguard Worker 
727*f6dc9357SAndroid Build Coastguard Worker   HRESULT ParseVolume(unsigned bufIndex, UInt32 posBase,
728*f6dc9357SAndroid Build Coastguard Worker       UInt32 exactSize, UInt32 limitSize,
729*f6dc9357SAndroid Build Coastguard Worker       int parent, int method, unsigned level);
730*f6dc9357SAndroid Build Coastguard Worker 
731*f6dc9357SAndroid Build Coastguard Worker   HRESULT OpenCapsule(IInStream *stream);
732*f6dc9357SAndroid Build Coastguard Worker   HRESULT OpenFv(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *callback);
733*f6dc9357SAndroid Build Coastguard Worker   HRESULT Open2(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *callback);
734*f6dc9357SAndroid Build Coastguard Worker public:
735*f6dc9357SAndroid Build Coastguard Worker   CHandler(bool capsuleMode): _capsuleMode(capsuleMode) {}
736*f6dc9357SAndroid Build Coastguard Worker };
737*f6dc9357SAndroid Build Coastguard Worker 
738*f6dc9357SAndroid Build Coastguard Worker 
739*f6dc9357SAndroid Build Coastguard Worker static const Byte kProps[] =
740*f6dc9357SAndroid Build Coastguard Worker {
741*f6dc9357SAndroid Build Coastguard Worker   kpidPath,
742*f6dc9357SAndroid Build Coastguard Worker   kpidIsDir,
743*f6dc9357SAndroid Build Coastguard Worker   kpidSize,
744*f6dc9357SAndroid Build Coastguard Worker   // kpidOffset,
745*f6dc9357SAndroid Build Coastguard Worker   kpidMethod,
746*f6dc9357SAndroid Build Coastguard Worker   kpidCharacts
747*f6dc9357SAndroid Build Coastguard Worker };
748*f6dc9357SAndroid Build Coastguard Worker 
749*f6dc9357SAndroid Build Coastguard Worker static const Byte kArcProps[] =
750*f6dc9357SAndroid Build Coastguard Worker {
751*f6dc9357SAndroid Build Coastguard Worker   kpidComment,
752*f6dc9357SAndroid Build Coastguard Worker   kpidMethod,
753*f6dc9357SAndroid Build Coastguard Worker   kpidCharacts
754*f6dc9357SAndroid Build Coastguard Worker };
755*f6dc9357SAndroid Build Coastguard Worker 
756*f6dc9357SAndroid Build Coastguard Worker IMP_IInArchive_Props
757*f6dc9357SAndroid Build Coastguard Worker IMP_IInArchive_ArcProps
758*f6dc9357SAndroid Build Coastguard Worker 
759*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
760*f6dc9357SAndroid Build Coastguard Worker {
761*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
762*f6dc9357SAndroid Build Coastguard Worker   NWindows::NCOM::CPropVariant prop;
763*f6dc9357SAndroid Build Coastguard Worker   const CItem2 &item2 = _items2[index];
764*f6dc9357SAndroid Build Coastguard Worker   const CItem &item = _items[item2.MainIndex];
765*f6dc9357SAndroid Build Coastguard Worker   switch (propID)
766*f6dc9357SAndroid Build Coastguard Worker   {
767*f6dc9357SAndroid Build Coastguard Worker     case kpidPath:
768*f6dc9357SAndroid Build Coastguard Worker     {
769*f6dc9357SAndroid Build Coastguard Worker       AString path (item2.Name);
770*f6dc9357SAndroid Build Coastguard Worker       int cur = item2.Parent;
771*f6dc9357SAndroid Build Coastguard Worker       while (cur >= 0)
772*f6dc9357SAndroid Build Coastguard Worker       {
773*f6dc9357SAndroid Build Coastguard Worker         const CItem2 &item3 = _items2[cur];
774*f6dc9357SAndroid Build Coastguard Worker         path.InsertAtFront(CHAR_PATH_SEPARATOR);
775*f6dc9357SAndroid Build Coastguard Worker         path.Insert(0, item3.Name);
776*f6dc9357SAndroid Build Coastguard Worker         cur = item3.Parent;
777*f6dc9357SAndroid Build Coastguard Worker       }
778*f6dc9357SAndroid Build Coastguard Worker       prop = path;
779*f6dc9357SAndroid Build Coastguard Worker       break;
780*f6dc9357SAndroid Build Coastguard Worker     }
781*f6dc9357SAndroid Build Coastguard Worker     case kpidIsDir: prop = item.IsDir; break;
782*f6dc9357SAndroid Build Coastguard Worker     case kpidMethod: if (item.Method >= 0) prop = g_Methods[(unsigned)item.Method]; break;
783*f6dc9357SAndroid Build Coastguard Worker     case kpidCharacts: if (!item2.Characts.IsEmpty()) prop = item2.Characts; break;
784*f6dc9357SAndroid Build Coastguard Worker     case kpidSize: if (!item.IsDir) prop = (UInt64)item.Size; break;
785*f6dc9357SAndroid Build Coastguard Worker     // case kpidOffset: if (!item.IsDir) prop = item.Offset; break;
786*f6dc9357SAndroid Build Coastguard Worker   }
787*f6dc9357SAndroid Build Coastguard Worker   prop.Detach(value);
788*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
789*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
790*f6dc9357SAndroid Build Coastguard Worker }
791*f6dc9357SAndroid Build Coastguard Worker 
792*f6dc9357SAndroid Build Coastguard Worker void CHandler::AddCommentString(const char *name, UInt32 pos)
793*f6dc9357SAndroid Build Coastguard Worker {
794*f6dc9357SAndroid Build Coastguard Worker   UString s;
795*f6dc9357SAndroid Build Coastguard Worker   if (pos < _h.HeaderSize)
796*f6dc9357SAndroid Build Coastguard Worker     return;
797*f6dc9357SAndroid Build Coastguard Worker   if (pos >= _h.OffsetToCapsuleBody)
798*f6dc9357SAndroid Build Coastguard Worker     return;
799*f6dc9357SAndroid Build Coastguard Worker   UInt32 limit = (_h.OffsetToCapsuleBody - pos) & ~(UInt32)1;
800*f6dc9357SAndroid Build Coastguard Worker   const Byte *buf = _bufs[0] + pos;
801*f6dc9357SAndroid Build Coastguard Worker   for (UInt32 i = 0;;)
802*f6dc9357SAndroid Build Coastguard Worker   {
803*f6dc9357SAndroid Build Coastguard Worker     if (s.Len() > (1 << 16) || i >= limit)
804*f6dc9357SAndroid Build Coastguard Worker       return;
805*f6dc9357SAndroid Build Coastguard Worker     wchar_t c = Get16(buf + i);
806*f6dc9357SAndroid Build Coastguard Worker     i += 2;
807*f6dc9357SAndroid Build Coastguard Worker     if (c == 0)
808*f6dc9357SAndroid Build Coastguard Worker     {
809*f6dc9357SAndroid Build Coastguard Worker       if (i >= limit)
810*f6dc9357SAndroid Build Coastguard Worker         return;
811*f6dc9357SAndroid Build Coastguard Worker       c = Get16(buf + i);
812*f6dc9357SAndroid Build Coastguard Worker       i += 2;
813*f6dc9357SAndroid Build Coastguard Worker       if (c == 0)
814*f6dc9357SAndroid Build Coastguard Worker         break;
815*f6dc9357SAndroid Build Coastguard Worker       s.Add_LF();
816*f6dc9357SAndroid Build Coastguard Worker     }
817*f6dc9357SAndroid Build Coastguard Worker     s += c;
818*f6dc9357SAndroid Build Coastguard Worker   }
819*f6dc9357SAndroid Build Coastguard Worker   if (s.IsEmpty())
820*f6dc9357SAndroid Build Coastguard Worker     return;
821*f6dc9357SAndroid Build Coastguard Worker   _comment.Add_LF();
822*f6dc9357SAndroid Build Coastguard Worker   _comment += name;
823*f6dc9357SAndroid Build Coastguard Worker   _comment += ": ";
824*f6dc9357SAndroid Build Coastguard Worker   _comment += s;
825*f6dc9357SAndroid Build Coastguard Worker }
826*f6dc9357SAndroid Build Coastguard Worker 
827*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
828*f6dc9357SAndroid Build Coastguard Worker {
829*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
830*f6dc9357SAndroid Build Coastguard Worker   NWindows::NCOM::CPropVariant prop;
831*f6dc9357SAndroid Build Coastguard Worker   switch (propID)
832*f6dc9357SAndroid Build Coastguard Worker   {
833*f6dc9357SAndroid Build Coastguard Worker     case kpidMethod:
834*f6dc9357SAndroid Build Coastguard Worker     {
835*f6dc9357SAndroid Build Coastguard Worker       AString s;
836*f6dc9357SAndroid Build Coastguard Worker       for (unsigned i = 0; i < 32; i++)
837*f6dc9357SAndroid Build Coastguard Worker         if ((_methodsMask & ((UInt32)1 << i)) != 0)
838*f6dc9357SAndroid Build Coastguard Worker           AddSpaceAndString(s, (AString)g_Methods[i]);
839*f6dc9357SAndroid Build Coastguard Worker       if (!s.IsEmpty())
840*f6dc9357SAndroid Build Coastguard Worker         prop = s;
841*f6dc9357SAndroid Build Coastguard Worker       break;
842*f6dc9357SAndroid Build Coastguard Worker     }
843*f6dc9357SAndroid Build Coastguard Worker     case kpidComment: if (!_comment.IsEmpty()) prop = _comment; break;
844*f6dc9357SAndroid Build Coastguard Worker     case kpidPhySize: prop = (UInt64)_phySize; break;
845*f6dc9357SAndroid Build Coastguard Worker 
846*f6dc9357SAndroid Build Coastguard Worker     case kpidErrorFlags:
847*f6dc9357SAndroid Build Coastguard Worker     {
848*f6dc9357SAndroid Build Coastguard Worker       UInt32 v = 0;
849*f6dc9357SAndroid Build Coastguard Worker       if (_headersError) v |= kpv_ErrorFlags_HeadersError;
850*f6dc9357SAndroid Build Coastguard Worker       if (v != 0)
851*f6dc9357SAndroid Build Coastguard Worker         prop = v;
852*f6dc9357SAndroid Build Coastguard Worker       break;
853*f6dc9357SAndroid Build Coastguard Worker     }
854*f6dc9357SAndroid Build Coastguard Worker   }
855*f6dc9357SAndroid Build Coastguard Worker   prop.Detach(value);
856*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
857*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
858*f6dc9357SAndroid Build Coastguard Worker }
859*f6dc9357SAndroid Build Coastguard Worker 
860*f6dc9357SAndroid Build Coastguard Worker #ifdef SHOW_DEBUG_INFO
861*f6dc9357SAndroid Build Coastguard Worker static void PrintLevel(unsigned level)
862*f6dc9357SAndroid Build Coastguard Worker {
863*f6dc9357SAndroid Build Coastguard Worker   PRF(printf("\n"));
864*f6dc9357SAndroid Build Coastguard Worker   for (unsigned i = 0; i < level; i++)
865*f6dc9357SAndroid Build Coastguard Worker     PRF(printf("  "));
866*f6dc9357SAndroid Build Coastguard Worker }
867*f6dc9357SAndroid Build Coastguard Worker static void MyPrint(UInt32 posBase, UInt32 size, unsigned level, const char *name)
868*f6dc9357SAndroid Build Coastguard Worker {
869*f6dc9357SAndroid Build Coastguard Worker   PrintLevel(level);
870*f6dc9357SAndroid Build Coastguard Worker   PRF(printf("%s, pos = %6x, size = %6x", name, posBase, size));
871*f6dc9357SAndroid Build Coastguard Worker }
872*f6dc9357SAndroid Build Coastguard Worker #else
873*f6dc9357SAndroid Build Coastguard Worker #define PrintLevel(level)
874*f6dc9357SAndroid Build Coastguard Worker #define MyPrint(posBase, size, level, name)
875*f6dc9357SAndroid Build Coastguard Worker #endif
876*f6dc9357SAndroid Build Coastguard Worker 
877*f6dc9357SAndroid Build Coastguard Worker 
878*f6dc9357SAndroid Build Coastguard Worker 
879*f6dc9357SAndroid Build Coastguard Worker unsigned CHandler::AddItem(const CItem &item)
880*f6dc9357SAndroid Build Coastguard Worker {
881*f6dc9357SAndroid Build Coastguard Worker   if (_items.Size() >= kNumFilesMax)
882*f6dc9357SAndroid Build Coastguard Worker     throw 2;
883*f6dc9357SAndroid Build Coastguard Worker   return _items.Add(item);
884*f6dc9357SAndroid Build Coastguard Worker }
885*f6dc9357SAndroid Build Coastguard Worker 
886*f6dc9357SAndroid Build Coastguard Worker unsigned CHandler::AddFileItemWithIndex(CItem &item)
887*f6dc9357SAndroid Build Coastguard Worker {
888*f6dc9357SAndroid Build Coastguard Worker   unsigned nameIndex = _items.Size();
889*f6dc9357SAndroid Build Coastguard Worker   if (item.Parent >= 0)
890*f6dc9357SAndroid Build Coastguard Worker     nameIndex = _items[item.Parent].NumChilds++;
891*f6dc9357SAndroid Build Coastguard Worker   item.NameIndex = (int)nameIndex;
892*f6dc9357SAndroid Build Coastguard Worker   return AddItem(item);
893*f6dc9357SAndroid Build Coastguard Worker }
894*f6dc9357SAndroid Build Coastguard Worker 
895*f6dc9357SAndroid Build Coastguard Worker unsigned CHandler::AddDirItem(CItem &item)
896*f6dc9357SAndroid Build Coastguard Worker {
897*f6dc9357SAndroid Build Coastguard Worker   if (item.Parent >= 0)
898*f6dc9357SAndroid Build Coastguard Worker     _items[item.Parent].ThereAreSubDirs = true;
899*f6dc9357SAndroid Build Coastguard Worker   item.IsDir = true;
900*f6dc9357SAndroid Build Coastguard Worker   item.Size = 0;
901*f6dc9357SAndroid Build Coastguard Worker   return AddItem(item);
902*f6dc9357SAndroid Build Coastguard Worker }
903*f6dc9357SAndroid Build Coastguard Worker 
904*f6dc9357SAndroid Build Coastguard Worker unsigned CHandler::AddBuf(size_t size)
905*f6dc9357SAndroid Build Coastguard Worker {
906*f6dc9357SAndroid Build Coastguard Worker   if (size > kBufTotalSizeMax - _totalBufsSize)
907*f6dc9357SAndroid Build Coastguard Worker     throw 1;
908*f6dc9357SAndroid Build Coastguard Worker   _totalBufsSize += size;
909*f6dc9357SAndroid Build Coastguard Worker   unsigned index = _bufs.Size();
910*f6dc9357SAndroid Build Coastguard Worker   _bufs.AddNew().Alloc(size);
911*f6dc9357SAndroid Build Coastguard Worker   return index;
912*f6dc9357SAndroid Build Coastguard Worker }
913*f6dc9357SAndroid Build Coastguard Worker 
914*f6dc9357SAndroid Build Coastguard Worker 
915*f6dc9357SAndroid Build Coastguard Worker HRESULT CHandler::DecodeLzma(const Byte *data, size_t inputSize)
916*f6dc9357SAndroid Build Coastguard Worker {
917*f6dc9357SAndroid Build Coastguard Worker   if (inputSize < 5 + 8)
918*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
919*f6dc9357SAndroid Build Coastguard Worker   const UInt64 unpackSize = Get64(data + 5);
920*f6dc9357SAndroid Build Coastguard Worker   if (unpackSize > ((UInt32)1 << 30))
921*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
922*f6dc9357SAndroid Build Coastguard Worker   SizeT destLen = (SizeT)unpackSize;
923*f6dc9357SAndroid Build Coastguard Worker   const unsigned newBufIndex = AddBuf((size_t)unpackSize);
924*f6dc9357SAndroid Build Coastguard Worker   CByteBuffer &buf = _bufs[newBufIndex];
925*f6dc9357SAndroid Build Coastguard Worker   ELzmaStatus status;
926*f6dc9357SAndroid Build Coastguard Worker   SizeT srcLen = inputSize - (5 + 8);
927*f6dc9357SAndroid Build Coastguard Worker   const SizeT srcLen2 = srcLen;
928*f6dc9357SAndroid Build Coastguard Worker   SRes res = LzmaDecode(buf, &destLen, data + 13, &srcLen,
929*f6dc9357SAndroid Build Coastguard Worker       data, 5, LZMA_FINISH_END, &status, &g_Alloc);
930*f6dc9357SAndroid Build Coastguard Worker   if (res != 0)
931*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
932*f6dc9357SAndroid Build Coastguard Worker   if (srcLen != srcLen2 || destLen != unpackSize || (
933*f6dc9357SAndroid Build Coastguard Worker       status != LZMA_STATUS_FINISHED_WITH_MARK &&
934*f6dc9357SAndroid Build Coastguard Worker       status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK))
935*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
936*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
937*f6dc9357SAndroid Build Coastguard Worker }
938*f6dc9357SAndroid Build Coastguard Worker 
939*f6dc9357SAndroid Build Coastguard Worker 
940*f6dc9357SAndroid Build Coastguard Worker HRESULT CHandler::ParseSections(unsigned bufIndex, UInt32 posBase, UInt32 size, int parent, int method, unsigned level, bool &error)
941*f6dc9357SAndroid Build Coastguard Worker {
942*f6dc9357SAndroid Build Coastguard Worker   error = false;
943*f6dc9357SAndroid Build Coastguard Worker 
944*f6dc9357SAndroid Build Coastguard Worker   if (level > kLevelMax)
945*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
946*f6dc9357SAndroid Build Coastguard Worker   MyPrint(posBase, size, level, "Sections");
947*f6dc9357SAndroid Build Coastguard Worker   level++;
948*f6dc9357SAndroid Build Coastguard Worker   const Byte *bufData = _bufs[bufIndex];
949*f6dc9357SAndroid Build Coastguard Worker   UInt32 pos = 0;
950*f6dc9357SAndroid Build Coastguard Worker   for (;;)
951*f6dc9357SAndroid Build Coastguard Worker   {
952*f6dc9357SAndroid Build Coastguard Worker     if (size == pos)
953*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
954*f6dc9357SAndroid Build Coastguard Worker     PrintLevel(level);
955*f6dc9357SAndroid Build Coastguard Worker     PRF(printf("%s, abs = %6x, relat = %6x", "Sect", posBase + pos, pos));
956*f6dc9357SAndroid Build Coastguard Worker     pos = (pos + 3) & ~(UInt32)3;
957*f6dc9357SAndroid Build Coastguard Worker     if (pos > size)
958*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
959*f6dc9357SAndroid Build Coastguard Worker     UInt32 rem = size - pos;
960*f6dc9357SAndroid Build Coastguard Worker     if (rem == 0)
961*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
962*f6dc9357SAndroid Build Coastguard Worker     if (rem < 4)
963*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
964*f6dc9357SAndroid Build Coastguard Worker 
965*f6dc9357SAndroid Build Coastguard Worker     const Byte *p = bufData + posBase + pos;
966*f6dc9357SAndroid Build Coastguard Worker 
967*f6dc9357SAndroid Build Coastguard Worker     const UInt32 sectSize = Get24(p);
968*f6dc9357SAndroid Build Coastguard Worker     const Byte type = p[3];
969*f6dc9357SAndroid Build Coastguard Worker 
970*f6dc9357SAndroid Build Coastguard Worker     // PrintLevel(level);
971*f6dc9357SAndroid Build Coastguard Worker     PRF(printf(" type = %2x, sectSize = %6x", type, sectSize));
972*f6dc9357SAndroid Build Coastguard Worker 
973*f6dc9357SAndroid Build Coastguard Worker     if (sectSize > rem || sectSize < 4)
974*f6dc9357SAndroid Build Coastguard Worker     {
975*f6dc9357SAndroid Build Coastguard Worker       _headersError = true;
976*f6dc9357SAndroid Build Coastguard Worker       error = true;
977*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
978*f6dc9357SAndroid Build Coastguard Worker       // return S_FALSE;
979*f6dc9357SAndroid Build Coastguard Worker     }
980*f6dc9357SAndroid Build Coastguard Worker 
981*f6dc9357SAndroid Build Coastguard Worker     CItem item;
982*f6dc9357SAndroid Build Coastguard Worker     item.Method = method;
983*f6dc9357SAndroid Build Coastguard Worker     item.BufIndex = bufIndex;
984*f6dc9357SAndroid Build Coastguard Worker     item.Parent = parent;
985*f6dc9357SAndroid Build Coastguard Worker     item.Offset = posBase + pos + 4;
986*f6dc9357SAndroid Build Coastguard Worker     UInt32 sectDataSize = sectSize - 4;
987*f6dc9357SAndroid Build Coastguard Worker     item.Size = sectDataSize;
988*f6dc9357SAndroid Build Coastguard Worker     item.Name = TYPE_PAIR_TO_STRING(g_SECTION_TYPE, type);
989*f6dc9357SAndroid Build Coastguard Worker 
990*f6dc9357SAndroid Build Coastguard Worker     if (type == SECTION_COMPRESSION)
991*f6dc9357SAndroid Build Coastguard Worker     {
992*f6dc9357SAndroid Build Coastguard Worker       if (sectSize < 4 + 5)
993*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
994*f6dc9357SAndroid Build Coastguard Worker       const UInt32 uncompressedSize = Get32(p + 4);
995*f6dc9357SAndroid Build Coastguard Worker       const Byte compressionType = p[8];
996*f6dc9357SAndroid Build Coastguard Worker 
997*f6dc9357SAndroid Build Coastguard Worker       UInt32 newSectSize = sectSize - 9;
998*f6dc9357SAndroid Build Coastguard Worker       UInt32 newOffset = posBase + pos + 9;
999*f6dc9357SAndroid Build Coastguard Worker       const Byte *pStart = p + 9;
1000*f6dc9357SAndroid Build Coastguard Worker 
1001*f6dc9357SAndroid Build Coastguard Worker       item.KeepName = false;
1002*f6dc9357SAndroid Build Coastguard Worker       if (compressionType > 2)
1003*f6dc9357SAndroid Build Coastguard Worker       {
1004*f6dc9357SAndroid Build Coastguard Worker         // AddFileItemWithIndex(item);
1005*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
1006*f6dc9357SAndroid Build Coastguard Worker       }
1007*f6dc9357SAndroid Build Coastguard Worker       else
1008*f6dc9357SAndroid Build Coastguard Worker       {
1009*f6dc9357SAndroid Build Coastguard Worker         item.Name = g_Methods[compressionType];
1010*f6dc9357SAndroid Build Coastguard Worker         // int parent = AddDirItem(item);
1011*f6dc9357SAndroid Build Coastguard Worker         if (compressionType == COMPRESSION_TYPE_NONE)
1012*f6dc9357SAndroid Build Coastguard Worker         {
1013*f6dc9357SAndroid Build Coastguard Worker           bool error2;
1014*f6dc9357SAndroid Build Coastguard Worker           RINOK(ParseSections(bufIndex, newOffset, newSectSize, parent, method, level, error2))
1015*f6dc9357SAndroid Build Coastguard Worker         }
1016*f6dc9357SAndroid Build Coastguard Worker         else if (compressionType == COMPRESSION_TYPE_LZH)
1017*f6dc9357SAndroid Build Coastguard Worker         {
1018*f6dc9357SAndroid Build Coastguard Worker           const unsigned newBufIndex = AddBuf(uncompressedSize);
1019*f6dc9357SAndroid Build Coastguard Worker           CByteBuffer &buf = _bufs[newBufIndex];
1020*f6dc9357SAndroid Build Coastguard Worker           CMyUniquePtr<NCompress::NLzh::NDecoder::CCoder> lzhDecoder;
1021*f6dc9357SAndroid Build Coastguard Worker           lzhDecoder.Create_if_Empty();
1022*f6dc9357SAndroid Build Coastguard Worker           {
1023*f6dc9357SAndroid Build Coastguard Worker             const Byte *src = pStart;
1024*f6dc9357SAndroid Build Coastguard Worker             if (newSectSize < 8)
1025*f6dc9357SAndroid Build Coastguard Worker               return S_FALSE;
1026*f6dc9357SAndroid Build Coastguard Worker             UInt32 packSize = Get32(src);
1027*f6dc9357SAndroid Build Coastguard Worker             const UInt32 unpackSize = Get32(src + 4);
1028*f6dc9357SAndroid Build Coastguard Worker 
1029*f6dc9357SAndroid Build Coastguard Worker             PRF(printf(" LZH packSize = %6x, unpackSize = %6x", packSize, unpackSize));
1030*f6dc9357SAndroid Build Coastguard Worker 
1031*f6dc9357SAndroid Build Coastguard Worker             if (uncompressedSize != unpackSize || newSectSize - 8 != packSize)
1032*f6dc9357SAndroid Build Coastguard Worker               return S_FALSE;
1033*f6dc9357SAndroid Build Coastguard Worker             if (packSize < 1)
1034*f6dc9357SAndroid Build Coastguard Worker               return S_FALSE;
1035*f6dc9357SAndroid Build Coastguard Worker             packSize--;
1036*f6dc9357SAndroid Build Coastguard Worker             src += 8;
1037*f6dc9357SAndroid Build Coastguard Worker             if (src[packSize] != 0)
1038*f6dc9357SAndroid Build Coastguard Worker               return S_FALSE;
1039*f6dc9357SAndroid Build Coastguard Worker 
1040*f6dc9357SAndroid Build Coastguard Worker             CMyComPtr2_Create<IInStream, CBufInStream> inStream;
1041*f6dc9357SAndroid Build Coastguard Worker             CMyComPtr2_Create<ISequentialOutStream, CBufPtrSeqOutStream> outStream;
1042*f6dc9357SAndroid Build Coastguard Worker             // const UInt64 uncompressedSize64 = uncompressedSize;
1043*f6dc9357SAndroid Build Coastguard Worker             // lzhDecoder->FinishMode = true;
1044*f6dc9357SAndroid Build Coastguard Worker             /*
1045*f6dc9357SAndroid Build Coastguard Worker               EFI 1.1 probably used LZH with small dictionary and (pbit = 4). It was named "Efi compression".
1046*f6dc9357SAndroid Build Coastguard Worker               New version of compression code (named Tiano) uses LZH with (1 << 19) dictionary.
1047*f6dc9357SAndroid Build Coastguard Worker               But maybe LZH decoder in UEFI decoder supports larger than (1 << 19) dictionary.
1048*f6dc9357SAndroid Build Coastguard Worker               We check both LZH versions: Tiano and then Efi.
1049*f6dc9357SAndroid Build Coastguard Worker             */
1050*f6dc9357SAndroid Build Coastguard Worker             HRESULT res = S_FALSE;
1051*f6dc9357SAndroid Build Coastguard Worker             for (unsigned m = 0 ; m < 2; m++)
1052*f6dc9357SAndroid Build Coastguard Worker             {
1053*f6dc9357SAndroid Build Coastguard Worker               inStream->Init(src, packSize);
1054*f6dc9357SAndroid Build Coastguard Worker               outStream->Init(buf, uncompressedSize);
1055*f6dc9357SAndroid Build Coastguard Worker               lzhDecoder->SetDictSize(m == 0 ? ((UInt32)1 << 19) : ((UInt32)1 << 14));
1056*f6dc9357SAndroid Build Coastguard Worker               res = lzhDecoder->Code(inStream, outStream, uncompressedSize, NULL);
1057*f6dc9357SAndroid Build Coastguard Worker               if (res == S_OK)
1058*f6dc9357SAndroid Build Coastguard Worker                 break;
1059*f6dc9357SAndroid Build Coastguard Worker             }
1060*f6dc9357SAndroid Build Coastguard Worker             RINOK(res)
1061*f6dc9357SAndroid Build Coastguard Worker           }
1062*f6dc9357SAndroid Build Coastguard Worker           bool error2;
1063*f6dc9357SAndroid Build Coastguard Worker           RINOK(ParseSections(newBufIndex, 0, uncompressedSize, parent, compressionType, level, error2))
1064*f6dc9357SAndroid Build Coastguard Worker         }
1065*f6dc9357SAndroid Build Coastguard Worker         else
1066*f6dc9357SAndroid Build Coastguard Worker         {
1067*f6dc9357SAndroid Build Coastguard Worker           if (newSectSize < 4 + 5 + 8)
1068*f6dc9357SAndroid Build Coastguard Worker             return S_FALSE;
1069*f6dc9357SAndroid Build Coastguard Worker           unsigned addSize = 4;
1070*f6dc9357SAndroid Build Coastguard Worker           if (pStart[0] == 0x5d && pStart[1] == 0 && pStart[2] == 0 && pStart[3] == 0x80 && pStart[4] == 0)
1071*f6dc9357SAndroid Build Coastguard Worker           {
1072*f6dc9357SAndroid Build Coastguard Worker             addSize = 0;
1073*f6dc9357SAndroid Build Coastguard Worker             // some archives have such header
1074*f6dc9357SAndroid Build Coastguard Worker           }
1075*f6dc9357SAndroid Build Coastguard Worker           else
1076*f6dc9357SAndroid Build Coastguard Worker           {
1077*f6dc9357SAndroid Build Coastguard Worker             // normal BIOS contains uncompressed size here
1078*f6dc9357SAndroid Build Coastguard Worker             // UInt32 uncompressedSize2 = Get24(pStart);
1079*f6dc9357SAndroid Build Coastguard Worker             // Byte firstSectType = p[9 + 3];
1080*f6dc9357SAndroid Build Coastguard Worker             // firstSectType can be 0 in some archives
1081*f6dc9357SAndroid Build Coastguard Worker           }
1082*f6dc9357SAndroid Build Coastguard Worker           pStart += addSize;
1083*f6dc9357SAndroid Build Coastguard Worker 
1084*f6dc9357SAndroid Build Coastguard Worker           RINOK(DecodeLzma(pStart, newSectSize - addSize))
1085*f6dc9357SAndroid Build Coastguard Worker           const size_t lzmaUncompressedSize = _bufs.Back().Size();
1086*f6dc9357SAndroid Build Coastguard Worker           // if (lzmaUncompressedSize != uncompressedSize)
1087*f6dc9357SAndroid Build Coastguard Worker           if (lzmaUncompressedSize < uncompressedSize)
1088*f6dc9357SAndroid Build Coastguard Worker             return S_FALSE;
1089*f6dc9357SAndroid Build Coastguard Worker           bool error2;
1090*f6dc9357SAndroid Build Coastguard Worker           RINOK(ParseSections(_bufs.Size() - 1, 0, (UInt32)lzmaUncompressedSize, parent, compressionType, level, error2))
1091*f6dc9357SAndroid Build Coastguard Worker         }
1092*f6dc9357SAndroid Build Coastguard Worker         _methodsMask |= (1 << compressionType);
1093*f6dc9357SAndroid Build Coastguard Worker       }
1094*f6dc9357SAndroid Build Coastguard Worker     }
1095*f6dc9357SAndroid Build Coastguard Worker     else if (type == SECTION_GUID_DEFINED)
1096*f6dc9357SAndroid Build Coastguard Worker     {
1097*f6dc9357SAndroid Build Coastguard Worker       const unsigned kHeaderSize = 4 + kGuidSize + 4;
1098*f6dc9357SAndroid Build Coastguard Worker       if (sectSize < kHeaderSize)
1099*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
1100*f6dc9357SAndroid Build Coastguard Worker       item.SetGuid(p + 4);
1101*f6dc9357SAndroid Build Coastguard Worker       const UInt32 dataOffset = Get16(p + 4 + kGuidSize);
1102*f6dc9357SAndroid Build Coastguard Worker       const UInt32 attrib = Get16(p + 4 + kGuidSize + 2);
1103*f6dc9357SAndroid Build Coastguard Worker       if (dataOffset > sectSize || dataOffset < kHeaderSize)
1104*f6dc9357SAndroid Build Coastguard Worker         return S_FALSE;
1105*f6dc9357SAndroid Build Coastguard Worker       UInt32 newSectSize = sectSize - dataOffset;
1106*f6dc9357SAndroid Build Coastguard Worker       item.Size = newSectSize;
1107*f6dc9357SAndroid Build Coastguard Worker       UInt32 newOffset = posBase + pos + dataOffset;
1108*f6dc9357SAndroid Build Coastguard Worker       item.Offset = newOffset;
1109*f6dc9357SAndroid Build Coastguard Worker       const UInt32 propsSize = dataOffset - kHeaderSize;
1110*f6dc9357SAndroid Build Coastguard Worker       AddSpaceAndString(item.Characts, FLAGS_TO_STRING(g_GUIDED_SECTION_ATTRIBUTES, attrib));
1111*f6dc9357SAndroid Build Coastguard Worker 
1112*f6dc9357SAndroid Build Coastguard Worker       bool needDir = true;
1113*f6dc9357SAndroid Build Coastguard Worker       unsigned newBufIndex = bufIndex;
1114*f6dc9357SAndroid Build Coastguard Worker       int newMethod = method;
1115*f6dc9357SAndroid Build Coastguard Worker 
1116*f6dc9357SAndroid Build Coastguard Worker       if (AreGuidsEq(p + 0x4, k_Guid_LZMA_COMPRESSED))
1117*f6dc9357SAndroid Build Coastguard Worker       {
1118*f6dc9357SAndroid Build Coastguard Worker         // item.Name = "guid.lzma";
1119*f6dc9357SAndroid Build Coastguard Worker         // AddItem(item);
1120*f6dc9357SAndroid Build Coastguard Worker         const Byte *pStart = bufData + newOffset;
1121*f6dc9357SAndroid Build Coastguard Worker         // do we need correct pStart here for lzma steram offset?
1122*f6dc9357SAndroid Build Coastguard Worker         RINOK(DecodeLzma(pStart, newSectSize))
1123*f6dc9357SAndroid Build Coastguard Worker         _methodsMask |= (1 << COMPRESSION_TYPE_LZMA);
1124*f6dc9357SAndroid Build Coastguard Worker         newBufIndex = _bufs.Size() - 1;
1125*f6dc9357SAndroid Build Coastguard Worker         newOffset = 0;
1126*f6dc9357SAndroid Build Coastguard Worker         newSectSize = (UInt32)_bufs.Back().Size();
1127*f6dc9357SAndroid Build Coastguard Worker         newMethod = COMPRESSION_TYPE_LZMA;
1128*f6dc9357SAndroid Build Coastguard Worker       }
1129*f6dc9357SAndroid Build Coastguard Worker       else if (AreGuidsEq(p + 0x4, kGuids[kGuidIndex_CRC]) && propsSize == 4)
1130*f6dc9357SAndroid Build Coastguard Worker       {
1131*f6dc9357SAndroid Build Coastguard Worker         needDir = false;
1132*f6dc9357SAndroid Build Coastguard Worker         item.KeepName = false;
1133*f6dc9357SAndroid Build Coastguard Worker         if (CrcCalc(bufData + newOffset, newSectSize) != Get32(p + kHeaderSize))
1134*f6dc9357SAndroid Build Coastguard Worker           return S_FALSE;
1135*f6dc9357SAndroid Build Coastguard Worker       }
1136*f6dc9357SAndroid Build Coastguard Worker       else
1137*f6dc9357SAndroid Build Coastguard Worker       {
1138*f6dc9357SAndroid Build Coastguard Worker         if (propsSize != 0)
1139*f6dc9357SAndroid Build Coastguard Worker         {
1140*f6dc9357SAndroid Build Coastguard Worker           CItem item2 = item;
1141*f6dc9357SAndroid Build Coastguard Worker           item2.Name += ".prop";
1142*f6dc9357SAndroid Build Coastguard Worker           item2.Size = propsSize;
1143*f6dc9357SAndroid Build Coastguard Worker           item2.Offset = posBase + pos + kHeaderSize;
1144*f6dc9357SAndroid Build Coastguard Worker           AddItem(item2);
1145*f6dc9357SAndroid Build Coastguard Worker         }
1146*f6dc9357SAndroid Build Coastguard Worker       }
1147*f6dc9357SAndroid Build Coastguard Worker 
1148*f6dc9357SAndroid Build Coastguard Worker       int newParent = parent;
1149*f6dc9357SAndroid Build Coastguard Worker       if (needDir)
1150*f6dc9357SAndroid Build Coastguard Worker         newParent = (int)AddDirItem(item);
1151*f6dc9357SAndroid Build Coastguard Worker       bool error2;
1152*f6dc9357SAndroid Build Coastguard Worker       RINOK(ParseSections(newBufIndex, newOffset, newSectSize, newParent, newMethod, level, error2))
1153*f6dc9357SAndroid Build Coastguard Worker     }
1154*f6dc9357SAndroid Build Coastguard Worker     else if (type == SECTION_FIRMWARE_VOLUME_IMAGE)
1155*f6dc9357SAndroid Build Coastguard Worker     {
1156*f6dc9357SAndroid Build Coastguard Worker       item.KeepName = false;
1157*f6dc9357SAndroid Build Coastguard Worker       const int newParent = (int)AddDirItem(item);
1158*f6dc9357SAndroid Build Coastguard Worker       RINOK(ParseVolume(bufIndex, posBase + pos + 4,
1159*f6dc9357SAndroid Build Coastguard Worker           sectSize - 4,
1160*f6dc9357SAndroid Build Coastguard Worker           sectSize - 4,
1161*f6dc9357SAndroid Build Coastguard Worker           newParent, method, level))
1162*f6dc9357SAndroid Build Coastguard Worker     }
1163*f6dc9357SAndroid Build Coastguard Worker     else
1164*f6dc9357SAndroid Build Coastguard Worker     {
1165*f6dc9357SAndroid Build Coastguard Worker       bool needAdd = true;
1166*f6dc9357SAndroid Build Coastguard Worker       switch (type)
1167*f6dc9357SAndroid Build Coastguard Worker       {
1168*f6dc9357SAndroid Build Coastguard Worker         case SECTION_RAW:
1169*f6dc9357SAndroid Build Coastguard Worker         {
1170*f6dc9357SAndroid Build Coastguard Worker           const UInt32 kInsydeOffset = 12;
1171*f6dc9357SAndroid Build Coastguard Worker           if (sectDataSize >= kFvHeaderSize + kInsydeOffset)
1172*f6dc9357SAndroid Build Coastguard Worker           {
1173*f6dc9357SAndroid Build Coastguard Worker             if (IsFfs(p + 4 + kInsydeOffset) &&
1174*f6dc9357SAndroid Build Coastguard Worker                 sectDataSize - kInsydeOffset == Get64(p + 4 + kInsydeOffset + 0x20))
1175*f6dc9357SAndroid Build Coastguard Worker             {
1176*f6dc9357SAndroid Build Coastguard Worker               needAdd = false;
1177*f6dc9357SAndroid Build Coastguard Worker               item.Name = "vol";
1178*f6dc9357SAndroid Build Coastguard Worker               const unsigned newParent = AddDirItem(item);
1179*f6dc9357SAndroid Build Coastguard Worker               RINOK(ParseVolume(bufIndex, posBase + pos + 4 + kInsydeOffset,
1180*f6dc9357SAndroid Build Coastguard Worker                   sectDataSize - kInsydeOffset,
1181*f6dc9357SAndroid Build Coastguard Worker                   sectDataSize - kInsydeOffset,
1182*f6dc9357SAndroid Build Coastguard Worker                   (int)newParent, method, level))
1183*f6dc9357SAndroid Build Coastguard Worker             }
1184*f6dc9357SAndroid Build Coastguard Worker 
1185*f6dc9357SAndroid Build Coastguard Worker             if (needAdd)
1186*f6dc9357SAndroid Build Coastguard Worker             {
1187*f6dc9357SAndroid Build Coastguard Worker               const char *ext = FindExt(p + 4, sectDataSize);
1188*f6dc9357SAndroid Build Coastguard Worker               if (ext)
1189*f6dc9357SAndroid Build Coastguard Worker                 item.Name = ext;
1190*f6dc9357SAndroid Build Coastguard Worker             }
1191*f6dc9357SAndroid Build Coastguard Worker           }
1192*f6dc9357SAndroid Build Coastguard Worker           break;
1193*f6dc9357SAndroid Build Coastguard Worker         }
1194*f6dc9357SAndroid Build Coastguard Worker         case SECTION_DXE_DEPEX:
1195*f6dc9357SAndroid Build Coastguard Worker         case SECTION_PEI_DEPEX:
1196*f6dc9357SAndroid Build Coastguard Worker         {
1197*f6dc9357SAndroid Build Coastguard Worker           AString s;
1198*f6dc9357SAndroid Build Coastguard Worker           if (ParseDepedencyExpression(p + 4, sectDataSize, s))
1199*f6dc9357SAndroid Build Coastguard Worker           {
1200*f6dc9357SAndroid Build Coastguard Worker             if (s.Len() < (1 << 9))
1201*f6dc9357SAndroid Build Coastguard Worker             {
1202*f6dc9357SAndroid Build Coastguard Worker               s.InsertAtFront('[');
1203*f6dc9357SAndroid Build Coastguard Worker               s += ']';
1204*f6dc9357SAndroid Build Coastguard Worker               AddSpaceAndString(_items[item.Parent].Characts, s);
1205*f6dc9357SAndroid Build Coastguard Worker               needAdd = false;
1206*f6dc9357SAndroid Build Coastguard Worker             }
1207*f6dc9357SAndroid Build Coastguard Worker             else
1208*f6dc9357SAndroid Build Coastguard Worker             {
1209*f6dc9357SAndroid Build Coastguard Worker               item.BufIndex = AddBuf(s.Len());
1210*f6dc9357SAndroid Build Coastguard Worker               CByteBuffer &buf0 = _bufs[item.BufIndex];
1211*f6dc9357SAndroid Build Coastguard Worker               if (s.Len() != 0)
1212*f6dc9357SAndroid Build Coastguard Worker                 memcpy(buf0, s, s.Len());
1213*f6dc9357SAndroid Build Coastguard Worker               item.Offset = 0;
1214*f6dc9357SAndroid Build Coastguard Worker               item.Size = s.Len();
1215*f6dc9357SAndroid Build Coastguard Worker             }
1216*f6dc9357SAndroid Build Coastguard Worker           }
1217*f6dc9357SAndroid Build Coastguard Worker           break;
1218*f6dc9357SAndroid Build Coastguard Worker         }
1219*f6dc9357SAndroid Build Coastguard Worker         case SECTION_VERSION:
1220*f6dc9357SAndroid Build Coastguard Worker         {
1221*f6dc9357SAndroid Build Coastguard Worker           if (sectDataSize > 2)
1222*f6dc9357SAndroid Build Coastguard Worker           {
1223*f6dc9357SAndroid Build Coastguard Worker             AString s;
1224*f6dc9357SAndroid Build Coastguard Worker             if (ParseUtf16zString2(p + 6, sectDataSize - 2, s))
1225*f6dc9357SAndroid Build Coastguard Worker             {
1226*f6dc9357SAndroid Build Coastguard Worker               AString s2 ("ver:");
1227*f6dc9357SAndroid Build Coastguard Worker               s2.Add_UInt32(Get16(p + 4));
1228*f6dc9357SAndroid Build Coastguard Worker               s2.Add_Space();
1229*f6dc9357SAndroid Build Coastguard Worker               s2 += s;
1230*f6dc9357SAndroid Build Coastguard Worker               AddSpaceAndString(_items[item.Parent].Characts, s2);
1231*f6dc9357SAndroid Build Coastguard Worker               needAdd = false;
1232*f6dc9357SAndroid Build Coastguard Worker             }
1233*f6dc9357SAndroid Build Coastguard Worker           }
1234*f6dc9357SAndroid Build Coastguard Worker           break;
1235*f6dc9357SAndroid Build Coastguard Worker         }
1236*f6dc9357SAndroid Build Coastguard Worker         case SECTION_USER_INTERFACE:
1237*f6dc9357SAndroid Build Coastguard Worker         {
1238*f6dc9357SAndroid Build Coastguard Worker           AString s;
1239*f6dc9357SAndroid Build Coastguard Worker           if (ParseUtf16zString2(p + 4, sectDataSize, s))
1240*f6dc9357SAndroid Build Coastguard Worker           {
1241*f6dc9357SAndroid Build Coastguard Worker             _items[parent].Name = s;
1242*f6dc9357SAndroid Build Coastguard Worker             needAdd = false;
1243*f6dc9357SAndroid Build Coastguard Worker           }
1244*f6dc9357SAndroid Build Coastguard Worker           break;
1245*f6dc9357SAndroid Build Coastguard Worker         }
1246*f6dc9357SAndroid Build Coastguard Worker         case SECTION_FREEFORM_SUBTYPE_GUID:
1247*f6dc9357SAndroid Build Coastguard Worker         {
1248*f6dc9357SAndroid Build Coastguard Worker           if (sectDataSize >= kGuidSize)
1249*f6dc9357SAndroid Build Coastguard Worker           {
1250*f6dc9357SAndroid Build Coastguard Worker             item.SetGuid(p + 4);
1251*f6dc9357SAndroid Build Coastguard Worker             item.Size = sectDataSize - kGuidSize;
1252*f6dc9357SAndroid Build Coastguard Worker             item.Offset = posBase + pos + 4 + kGuidSize;
1253*f6dc9357SAndroid Build Coastguard Worker           }
1254*f6dc9357SAndroid Build Coastguard Worker           break;
1255*f6dc9357SAndroid Build Coastguard Worker         }
1256*f6dc9357SAndroid Build Coastguard Worker       }
1257*f6dc9357SAndroid Build Coastguard Worker 
1258*f6dc9357SAndroid Build Coastguard Worker       if (needAdd)
1259*f6dc9357SAndroid Build Coastguard Worker         AddFileItemWithIndex(item);
1260*f6dc9357SAndroid Build Coastguard Worker     }
1261*f6dc9357SAndroid Build Coastguard Worker 
1262*f6dc9357SAndroid Build Coastguard Worker     pos += sectSize;
1263*f6dc9357SAndroid Build Coastguard Worker   }
1264*f6dc9357SAndroid Build Coastguard Worker }
1265*f6dc9357SAndroid Build Coastguard Worker 
1266*f6dc9357SAndroid Build Coastguard Worker static UInt32 Count_FF_Bytes(const Byte *p, UInt32 size)
1267*f6dc9357SAndroid Build Coastguard Worker {
1268*f6dc9357SAndroid Build Coastguard Worker   UInt32 i;
1269*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < size && p[i] == 0xFF; i++);
1270*f6dc9357SAndroid Build Coastguard Worker   return i;
1271*f6dc9357SAndroid Build Coastguard Worker }
1272*f6dc9357SAndroid Build Coastguard Worker 
1273*f6dc9357SAndroid Build Coastguard Worker static bool Is_FF_Stream(const Byte *p, UInt32 size)
1274*f6dc9357SAndroid Build Coastguard Worker {
1275*f6dc9357SAndroid Build Coastguard Worker   return (Count_FF_Bytes(p, size) == size);
1276*f6dc9357SAndroid Build Coastguard Worker }
1277*f6dc9357SAndroid Build Coastguard Worker 
1278*f6dc9357SAndroid Build Coastguard Worker struct CVolFfsHeader
1279*f6dc9357SAndroid Build Coastguard Worker {
1280*f6dc9357SAndroid Build Coastguard Worker   UInt32 HeaderLen;
1281*f6dc9357SAndroid Build Coastguard Worker   UInt64 VolSize;
1282*f6dc9357SAndroid Build Coastguard Worker 
1283*f6dc9357SAndroid Build Coastguard Worker   bool Parse(const Byte *p);
1284*f6dc9357SAndroid Build Coastguard Worker };
1285*f6dc9357SAndroid Build Coastguard Worker 
1286*f6dc9357SAndroid Build Coastguard Worker bool CVolFfsHeader::Parse(const Byte *p)
1287*f6dc9357SAndroid Build Coastguard Worker {
1288*f6dc9357SAndroid Build Coastguard Worker   if (Get32(p + 0x28) != kFvSignature)
1289*f6dc9357SAndroid Build Coastguard Worker     return false;
1290*f6dc9357SAndroid Build Coastguard Worker 
1291*f6dc9357SAndroid Build Coastguard Worker   UInt32 attribs = Get32(p + 0x2C);
1292*f6dc9357SAndroid Build Coastguard Worker   if ((attribs & FVB_ERASE_POLARITY) == 0)
1293*f6dc9357SAndroid Build Coastguard Worker     return false;
1294*f6dc9357SAndroid Build Coastguard Worker   VolSize = Get64(p + 0x20);
1295*f6dc9357SAndroid Build Coastguard Worker   HeaderLen = Get16(p + 0x30);
1296*f6dc9357SAndroid Build Coastguard Worker   if (HeaderLen < kFvHeaderSize || (HeaderLen & 0x7) != 0 || VolSize < HeaderLen)
1297*f6dc9357SAndroid Build Coastguard Worker     return false;
1298*f6dc9357SAndroid Build Coastguard Worker   return true;
1299*f6dc9357SAndroid Build Coastguard Worker }
1300*f6dc9357SAndroid Build Coastguard Worker 
1301*f6dc9357SAndroid Build Coastguard Worker 
1302*f6dc9357SAndroid Build Coastguard Worker HRESULT CHandler::ParseVolume(
1303*f6dc9357SAndroid Build Coastguard Worker     unsigned bufIndex, UInt32 posBase,
1304*f6dc9357SAndroid Build Coastguard Worker     UInt32 exactSize, UInt32 limitSize,
1305*f6dc9357SAndroid Build Coastguard Worker     int parent, int method, unsigned level)
1306*f6dc9357SAndroid Build Coastguard Worker {
1307*f6dc9357SAndroid Build Coastguard Worker   if (level > kLevelMax)
1308*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
1309*f6dc9357SAndroid Build Coastguard Worker   MyPrint(posBase, exactSize, level, "Volume");
1310*f6dc9357SAndroid Build Coastguard Worker   level++;
1311*f6dc9357SAndroid Build Coastguard Worker   if (exactSize < kFvHeaderSize)
1312*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
1313*f6dc9357SAndroid Build Coastguard Worker   const Byte *p = _bufs[bufIndex] + posBase;
1314*f6dc9357SAndroid Build Coastguard Worker   // first 16 bytes must be zeros, but they are not zeros sometimes.
1315*f6dc9357SAndroid Build Coastguard Worker   if (!IsFfs(p))
1316*f6dc9357SAndroid Build Coastguard Worker   {
1317*f6dc9357SAndroid Build Coastguard Worker     CItem item;
1318*f6dc9357SAndroid Build Coastguard Worker     item.Method = method;
1319*f6dc9357SAndroid Build Coastguard Worker     item.BufIndex = bufIndex;
1320*f6dc9357SAndroid Build Coastguard Worker     item.Parent = parent;
1321*f6dc9357SAndroid Build Coastguard Worker     item.Offset = posBase;
1322*f6dc9357SAndroid Build Coastguard Worker     item.Size = exactSize;
1323*f6dc9357SAndroid Build Coastguard Worker     if (!Is_FF_Stream(p + kFfsGuidOffset, 16))
1324*f6dc9357SAndroid Build Coastguard Worker       item.SetGuid(p + kFfsGuidOffset);
1325*f6dc9357SAndroid Build Coastguard Worker     // if (item.Name.IsEmpty())
1326*f6dc9357SAndroid Build Coastguard Worker     item.Name += "[VOL]";
1327*f6dc9357SAndroid Build Coastguard Worker     AddItem(item);
1328*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
1329*f6dc9357SAndroid Build Coastguard Worker   }
1330*f6dc9357SAndroid Build Coastguard Worker 
1331*f6dc9357SAndroid Build Coastguard Worker   CVolFfsHeader ffsHeader;
1332*f6dc9357SAndroid Build Coastguard Worker   if (!ffsHeader.Parse(p))
1333*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
1334*f6dc9357SAndroid Build Coastguard Worker   // if (parent >= 0) AddSpaceAndString(_items[parent].Characts, FLAGS_TO_STRING(g_FV_Attribs, attribs));
1335*f6dc9357SAndroid Build Coastguard Worker 
1336*f6dc9357SAndroid Build Coastguard Worker   // VolSize > exactSize (fh.Size) for some UEFI archives (is it correct UEFI?)
1337*f6dc9357SAndroid Build Coastguard Worker   // so we check VolSize for limitSize instead.
1338*f6dc9357SAndroid Build Coastguard Worker 
1339*f6dc9357SAndroid Build Coastguard Worker   if (ffsHeader.HeaderLen > limitSize || ffsHeader.VolSize > limitSize)
1340*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
1341*f6dc9357SAndroid Build Coastguard Worker 
1342*f6dc9357SAndroid Build Coastguard Worker   {
1343*f6dc9357SAndroid Build Coastguard Worker     UInt32 checkCalc = 0;
1344*f6dc9357SAndroid Build Coastguard Worker     for (UInt32 i = 0; i < ffsHeader.HeaderLen; i += 2)
1345*f6dc9357SAndroid Build Coastguard Worker       checkCalc += Get16(p + i);
1346*f6dc9357SAndroid Build Coastguard Worker     if ((checkCalc & 0xFFFF) != 0)
1347*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1348*f6dc9357SAndroid Build Coastguard Worker   }
1349*f6dc9357SAndroid Build Coastguard Worker 
1350*f6dc9357SAndroid Build Coastguard Worker   // 3 reserved bytes are not zeros sometimes.
1351*f6dc9357SAndroid Build Coastguard Worker   // UInt16 ExtHeaderOffset; // in new SPECIFICATION?
1352*f6dc9357SAndroid Build Coastguard Worker   // Byte revision = p[0x37];
1353*f6dc9357SAndroid Build Coastguard Worker 
1354*f6dc9357SAndroid Build Coastguard Worker   UInt32 pos = kFvHeaderSize;
1355*f6dc9357SAndroid Build Coastguard Worker   for (;;)
1356*f6dc9357SAndroid Build Coastguard Worker   {
1357*f6dc9357SAndroid Build Coastguard Worker     if (pos >= ffsHeader.HeaderLen)
1358*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1359*f6dc9357SAndroid Build Coastguard Worker     UInt32 numBlocks = Get32(p + pos);
1360*f6dc9357SAndroid Build Coastguard Worker     UInt32 length = Get32(p + pos + 4);
1361*f6dc9357SAndroid Build Coastguard Worker     pos += 8;
1362*f6dc9357SAndroid Build Coastguard Worker     if (numBlocks == 0 && length == 0)
1363*f6dc9357SAndroid Build Coastguard Worker       break;
1364*f6dc9357SAndroid Build Coastguard Worker   }
1365*f6dc9357SAndroid Build Coastguard Worker   if (pos != ffsHeader.HeaderLen)
1366*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
1367*f6dc9357SAndroid Build Coastguard Worker 
1368*f6dc9357SAndroid Build Coastguard Worker   CRecordVector<UInt32> guidsVector;
1369*f6dc9357SAndroid Build Coastguard Worker 
1370*f6dc9357SAndroid Build Coastguard Worker   for (;;)
1371*f6dc9357SAndroid Build Coastguard Worker   {
1372*f6dc9357SAndroid Build Coastguard Worker     UInt32 rem = (UInt32)ffsHeader.VolSize - pos;
1373*f6dc9357SAndroid Build Coastguard Worker     if (rem < kFileHeaderSize)
1374*f6dc9357SAndroid Build Coastguard Worker       break;
1375*f6dc9357SAndroid Build Coastguard Worker     pos = (pos + 7) & ~7u;
1376*f6dc9357SAndroid Build Coastguard Worker     rem = (UInt32)ffsHeader.VolSize - pos;
1377*f6dc9357SAndroid Build Coastguard Worker     if (rem < kFileHeaderSize)
1378*f6dc9357SAndroid Build Coastguard Worker       break;
1379*f6dc9357SAndroid Build Coastguard Worker 
1380*f6dc9357SAndroid Build Coastguard Worker     CItem item;
1381*f6dc9357SAndroid Build Coastguard Worker     item.Method = method;
1382*f6dc9357SAndroid Build Coastguard Worker     item.BufIndex = bufIndex;
1383*f6dc9357SAndroid Build Coastguard Worker     item.Parent = parent;
1384*f6dc9357SAndroid Build Coastguard Worker 
1385*f6dc9357SAndroid Build Coastguard Worker     const Byte *pFile = p + pos;
1386*f6dc9357SAndroid Build Coastguard Worker     CFfsFileHeader fh;
1387*f6dc9357SAndroid Build Coastguard Worker     if (!fh.Parse(pFile))
1388*f6dc9357SAndroid Build Coastguard Worker     {
1389*f6dc9357SAndroid Build Coastguard Worker       UInt32 num_FF_bytes = Count_FF_Bytes(pFile, rem);
1390*f6dc9357SAndroid Build Coastguard Worker       if (num_FF_bytes != rem)
1391*f6dc9357SAndroid Build Coastguard Worker       {
1392*f6dc9357SAndroid Build Coastguard Worker         item.Name = "[junk]";
1393*f6dc9357SAndroid Build Coastguard Worker         item.Offset = posBase + pos + num_FF_bytes;
1394*f6dc9357SAndroid Build Coastguard Worker         item.Size = rem - num_FF_bytes;
1395*f6dc9357SAndroid Build Coastguard Worker         AddItem(item);
1396*f6dc9357SAndroid Build Coastguard Worker       }
1397*f6dc9357SAndroid Build Coastguard Worker       PrintLevel(level); PRF(printf("== FF FF reminder"));
1398*f6dc9357SAndroid Build Coastguard Worker 
1399*f6dc9357SAndroid Build Coastguard Worker       break;
1400*f6dc9357SAndroid Build Coastguard Worker     }
1401*f6dc9357SAndroid Build Coastguard Worker 
1402*f6dc9357SAndroid Build Coastguard Worker     PrintLevel(level); PRF(printf("%s, type = %3d,  pos = %7x, size = %7x", "FILE", fh.Type, posBase + pos, fh.Size));
1403*f6dc9357SAndroid Build Coastguard Worker 
1404*f6dc9357SAndroid Build Coastguard Worker     if (!fh.Check(pFile, rem))
1405*f6dc9357SAndroid Build Coastguard Worker       return S_FALSE;
1406*f6dc9357SAndroid Build Coastguard Worker 
1407*f6dc9357SAndroid Build Coastguard Worker     UInt32 offset = posBase + pos + kFileHeaderSize;
1408*f6dc9357SAndroid Build Coastguard Worker     UInt32 sectSize = fh.GetDataSize();
1409*f6dc9357SAndroid Build Coastguard Worker     item.Offset = offset;
1410*f6dc9357SAndroid Build Coastguard Worker     item.Size = sectSize;
1411*f6dc9357SAndroid Build Coastguard Worker 
1412*f6dc9357SAndroid Build Coastguard Worker     pos += fh.Size;
1413*f6dc9357SAndroid Build Coastguard Worker 
1414*f6dc9357SAndroid Build Coastguard Worker     if (fh.Type == FV_FILETYPE_FFS_PAD)
1415*f6dc9357SAndroid Build Coastguard Worker       if (Is_FF_Stream(pFile + kFileHeaderSize, sectSize))
1416*f6dc9357SAndroid Build Coastguard Worker         continue;
1417*f6dc9357SAndroid Build Coastguard Worker 
1418*f6dc9357SAndroid Build Coastguard Worker     UInt32 guid32 = Get32(fh.GuidName);
1419*f6dc9357SAndroid Build Coastguard Worker     bool full = true;
1420*f6dc9357SAndroid Build Coastguard Worker     if (guidsVector.FindInSorted(guid32) < 0)
1421*f6dc9357SAndroid Build Coastguard Worker     {
1422*f6dc9357SAndroid Build Coastguard Worker       guidsVector.AddToUniqueSorted(guid32);
1423*f6dc9357SAndroid Build Coastguard Worker       full = false;
1424*f6dc9357SAndroid Build Coastguard Worker     }
1425*f6dc9357SAndroid Build Coastguard Worker     item.SetGuid(fh.GuidName, full);
1426*f6dc9357SAndroid Build Coastguard Worker 
1427*f6dc9357SAndroid Build Coastguard Worker     item.Characts = fh.GetCharacts();
1428*f6dc9357SAndroid Build Coastguard Worker     // PrintLevel(level);
1429*f6dc9357SAndroid Build Coastguard Worker     PRF(printf(" : %s", item.Characts));
1430*f6dc9357SAndroid Build Coastguard Worker 
1431*f6dc9357SAndroid Build Coastguard Worker     {
1432*f6dc9357SAndroid Build Coastguard Worker       PRF(printf(" attrib = %2d State = %3d ", (unsigned)fh.Attrib, (unsigned)fh.State));
1433*f6dc9357SAndroid Build Coastguard Worker       PRF(char s[64]);
1434*f6dc9357SAndroid Build Coastguard Worker       PRF(RawLeGuidToString(fh.GuidName, s));
1435*f6dc9357SAndroid Build Coastguard Worker       PRF(printf(" : %s ", s));
1436*f6dc9357SAndroid Build Coastguard Worker     }
1437*f6dc9357SAndroid Build Coastguard Worker 
1438*f6dc9357SAndroid Build Coastguard Worker     if (fh.Type == FV_FILETYPE_FFS_PAD ||
1439*f6dc9357SAndroid Build Coastguard Worker         fh.Type == FV_FILETYPE_RAW)
1440*f6dc9357SAndroid Build Coastguard Worker     {
1441*f6dc9357SAndroid Build Coastguard Worker       bool isVolume = false;
1442*f6dc9357SAndroid Build Coastguard Worker       if (fh.Type == FV_FILETYPE_RAW)
1443*f6dc9357SAndroid Build Coastguard Worker       {
1444*f6dc9357SAndroid Build Coastguard Worker         if (sectSize >= kFvHeaderSize)
1445*f6dc9357SAndroid Build Coastguard Worker           if (IsFfs(pFile + kFileHeaderSize))
1446*f6dc9357SAndroid Build Coastguard Worker             isVolume = true;
1447*f6dc9357SAndroid Build Coastguard Worker       }
1448*f6dc9357SAndroid Build Coastguard Worker       if (isVolume)
1449*f6dc9357SAndroid Build Coastguard Worker       {
1450*f6dc9357SAndroid Build Coastguard Worker         const unsigned newParent = AddDirItem(item);
1451*f6dc9357SAndroid Build Coastguard Worker         const UInt32 limSize = fh.GetDataSize2(rem);
1452*f6dc9357SAndroid Build Coastguard Worker         // volume.VolSize > fh.Size for some UEFI archives (is it correct UEFI?)
1453*f6dc9357SAndroid Build Coastguard Worker         // so we will check VolSize for limitSize instead.
1454*f6dc9357SAndroid Build Coastguard Worker         RINOK(ParseVolume(bufIndex, offset, sectSize, limSize, (int)newParent, method, level))
1455*f6dc9357SAndroid Build Coastguard Worker       }
1456*f6dc9357SAndroid Build Coastguard Worker       else
1457*f6dc9357SAndroid Build Coastguard Worker         AddItem(item);
1458*f6dc9357SAndroid Build Coastguard Worker     }
1459*f6dc9357SAndroid Build Coastguard Worker     else
1460*f6dc9357SAndroid Build Coastguard Worker     {
1461*f6dc9357SAndroid Build Coastguard Worker       /*
1462*f6dc9357SAndroid Build Coastguard Worker       if (fh.Type == FV_FILETYPE_FREEFORM)
1463*f6dc9357SAndroid Build Coastguard Worker       {
1464*f6dc9357SAndroid Build Coastguard Worker         // in intel bio example: one FV_FILETYPE_FREEFORM file is wav file (not sections)
1465*f6dc9357SAndroid Build Coastguard Worker         // AddItem(item);
1466*f6dc9357SAndroid Build Coastguard Worker       }
1467*f6dc9357SAndroid Build Coastguard Worker       else
1468*f6dc9357SAndroid Build Coastguard Worker       */
1469*f6dc9357SAndroid Build Coastguard Worker       {
1470*f6dc9357SAndroid Build Coastguard Worker         const unsigned newParent = AddDirItem(item);
1471*f6dc9357SAndroid Build Coastguard Worker         bool error2;
1472*f6dc9357SAndroid Build Coastguard Worker         RINOK(ParseSections(bufIndex, offset, sectSize, (int)newParent, method, level + 1, error2))
1473*f6dc9357SAndroid Build Coastguard Worker         if (error2)
1474*f6dc9357SAndroid Build Coastguard Worker         {
1475*f6dc9357SAndroid Build Coastguard Worker           // in intel bio example: one FV_FILETYPE_FREEFORM file is wav file (not sections)
1476*f6dc9357SAndroid Build Coastguard Worker           item.IsDir = false;
1477*f6dc9357SAndroid Build Coastguard Worker           item.Size = sectSize;
1478*f6dc9357SAndroid Build Coastguard Worker           item.Name.Insert(0, "[ERROR]");
1479*f6dc9357SAndroid Build Coastguard Worker           AddItem(item);
1480*f6dc9357SAndroid Build Coastguard Worker         }
1481*f6dc9357SAndroid Build Coastguard Worker       }
1482*f6dc9357SAndroid Build Coastguard Worker     }
1483*f6dc9357SAndroid Build Coastguard Worker   }
1484*f6dc9357SAndroid Build Coastguard Worker 
1485*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1486*f6dc9357SAndroid Build Coastguard Worker }
1487*f6dc9357SAndroid Build Coastguard Worker 
1488*f6dc9357SAndroid Build Coastguard Worker 
1489*f6dc9357SAndroid Build Coastguard Worker static const char * const kRegionName[] =
1490*f6dc9357SAndroid Build Coastguard Worker {
1491*f6dc9357SAndroid Build Coastguard Worker     "Descriptor"
1492*f6dc9357SAndroid Build Coastguard Worker   , "BIOS"
1493*f6dc9357SAndroid Build Coastguard Worker   , "ME"
1494*f6dc9357SAndroid Build Coastguard Worker   , "GbE"
1495*f6dc9357SAndroid Build Coastguard Worker   , "PDR"
1496*f6dc9357SAndroid Build Coastguard Worker   , "Region5"
1497*f6dc9357SAndroid Build Coastguard Worker   , "Region6"
1498*f6dc9357SAndroid Build Coastguard Worker   , "Region7"
1499*f6dc9357SAndroid Build Coastguard Worker };
1500*f6dc9357SAndroid Build Coastguard Worker 
1501*f6dc9357SAndroid Build Coastguard Worker 
1502*f6dc9357SAndroid Build Coastguard Worker HRESULT CHandler::ParseIntelMe(
1503*f6dc9357SAndroid Build Coastguard Worker     unsigned bufIndex, UInt32 posBase,
1504*f6dc9357SAndroid Build Coastguard Worker     UInt32 exactSize, UInt32 limitSize,
1505*f6dc9357SAndroid Build Coastguard Worker     int parent, int method, unsigned /* level */)
1506*f6dc9357SAndroid Build Coastguard Worker {
1507*f6dc9357SAndroid Build Coastguard Worker   UNUSED_VAR(limitSize)
1508*f6dc9357SAndroid Build Coastguard Worker   // level++;
1509*f6dc9357SAndroid Build Coastguard Worker 
1510*f6dc9357SAndroid Build Coastguard Worker   const Byte *p = _bufs[bufIndex] + posBase;
1511*f6dc9357SAndroid Build Coastguard Worker   if (exactSize < 16 + 16)
1512*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
1513*f6dc9357SAndroid Build Coastguard Worker   if (!IsIntelMe(p))
1514*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
1515*f6dc9357SAndroid Build Coastguard Worker 
1516*f6dc9357SAndroid Build Coastguard Worker   UInt32 v0 = GetUi32(p + 20);
1517*f6dc9357SAndroid Build Coastguard Worker   // UInt32 numRegions = (v0 >> 24) & 0x7;
1518*f6dc9357SAndroid Build Coastguard Worker   UInt32 regAddr = (v0 >> 12) & 0xFF0;
1519*f6dc9357SAndroid Build Coastguard Worker   // UInt32 numComps  = (v0 >> 8) & 0x3;
1520*f6dc9357SAndroid Build Coastguard Worker   // UInt32 fcba = (v0 <<  4) & 0xFF0;
1521*f6dc9357SAndroid Build Coastguard Worker 
1522*f6dc9357SAndroid Build Coastguard Worker   // (numRegions == 0) in header in some new images.
1523*f6dc9357SAndroid Build Coastguard Worker   // So we don't use the value from header
1524*f6dc9357SAndroid Build Coastguard Worker   UInt32 numRegions = 7;
1525*f6dc9357SAndroid Build Coastguard Worker 
1526*f6dc9357SAndroid Build Coastguard Worker   for (unsigned i = 0; i <= numRegions; i++)
1527*f6dc9357SAndroid Build Coastguard Worker   {
1528*f6dc9357SAndroid Build Coastguard Worker     UInt32 offset = regAddr + i * 4;
1529*f6dc9357SAndroid Build Coastguard Worker     if (offset + 4 > exactSize)
1530*f6dc9357SAndroid Build Coastguard Worker       break;
1531*f6dc9357SAndroid Build Coastguard Worker     UInt32 val = GetUi32(p + offset);
1532*f6dc9357SAndroid Build Coastguard Worker 
1533*f6dc9357SAndroid Build Coastguard Worker     // only 12 bits probably are OK.
1534*f6dc9357SAndroid Build Coastguard Worker     // How does it work for files larger than 16 MB?
1535*f6dc9357SAndroid Build Coastguard Worker     const UInt32 kMask = 0xFFF;
1536*f6dc9357SAndroid Build Coastguard Worker     // const UInt32 kMask = 0xFFFF; // 16-bit is more logical
1537*f6dc9357SAndroid Build Coastguard Worker     const UInt32 lim  = (val >> 16) & kMask;
1538*f6dc9357SAndroid Build Coastguard Worker     const UInt32 base = (val & kMask);
1539*f6dc9357SAndroid Build Coastguard Worker 
1540*f6dc9357SAndroid Build Coastguard Worker     /*
1541*f6dc9357SAndroid Build Coastguard Worker       strange combinations:
1542*f6dc9357SAndroid Build Coastguard Worker         PDR:   base = 0x1FFF lim = 0;
1543*f6dc9357SAndroid Build Coastguard Worker         empty: base = 0xFFFF lim = 0xFFFF;
1544*f6dc9357SAndroid Build Coastguard Worker 
1545*f6dc9357SAndroid Build Coastguard Worker         PDR:   base = 0x7FFF lim = 0;
1546*f6dc9357SAndroid Build Coastguard Worker         empty: base = 0x7FFF lim = 0;
1547*f6dc9357SAndroid Build Coastguard Worker     */
1548*f6dc9357SAndroid Build Coastguard Worker     if (base == kMask && lim == 0)
1549*f6dc9357SAndroid Build Coastguard Worker       continue; // unused
1550*f6dc9357SAndroid Build Coastguard Worker 
1551*f6dc9357SAndroid Build Coastguard Worker     if (lim < base)
1552*f6dc9357SAndroid Build Coastguard Worker       continue; // unused
1553*f6dc9357SAndroid Build Coastguard Worker 
1554*f6dc9357SAndroid Build Coastguard Worker     CItem item;
1555*f6dc9357SAndroid Build Coastguard Worker     item.Name = kRegionName[i];
1556*f6dc9357SAndroid Build Coastguard Worker     item.Method = method;
1557*f6dc9357SAndroid Build Coastguard Worker     item.BufIndex = bufIndex;
1558*f6dc9357SAndroid Build Coastguard Worker     item.Parent = parent;
1559*f6dc9357SAndroid Build Coastguard Worker     item.Offset = posBase + (base << 12);
1560*f6dc9357SAndroid Build Coastguard Worker     if (item.Offset > exactSize)
1561*f6dc9357SAndroid Build Coastguard Worker       continue;
1562*f6dc9357SAndroid Build Coastguard Worker     item.Size = (lim + 1 - base) << 12;
1563*f6dc9357SAndroid Build Coastguard Worker     // item.SetGuid(p + kFfsGuidOffset);
1564*f6dc9357SAndroid Build Coastguard Worker     // item.Name += " [VOLUME]";
1565*f6dc9357SAndroid Build Coastguard Worker     AddItem(item);
1566*f6dc9357SAndroid Build Coastguard Worker   }
1567*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1568*f6dc9357SAndroid Build Coastguard Worker }
1569*f6dc9357SAndroid Build Coastguard Worker 
1570*f6dc9357SAndroid Build Coastguard Worker 
1571*f6dc9357SAndroid Build Coastguard Worker HRESULT CHandler::OpenCapsule(IInStream *stream)
1572*f6dc9357SAndroid Build Coastguard Worker {
1573*f6dc9357SAndroid Build Coastguard Worker   const unsigned kHeaderSize = 80;
1574*f6dc9357SAndroid Build Coastguard Worker   Byte buf[kHeaderSize];
1575*f6dc9357SAndroid Build Coastguard Worker   RINOK(ReadStream_FALSE(stream, buf, kHeaderSize))
1576*f6dc9357SAndroid Build Coastguard Worker   if (!_h.Parse(buf))
1577*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
1578*f6dc9357SAndroid Build Coastguard Worker   if (_h.CapsuleImageSize < kHeaderSize
1579*f6dc9357SAndroid Build Coastguard Worker        || _h.CapsuleImageSize < _h.HeaderSize
1580*f6dc9357SAndroid Build Coastguard Worker        || _h.OffsetToCapsuleBody < _h.HeaderSize
1581*f6dc9357SAndroid Build Coastguard Worker        || _h.OffsetToCapsuleBody > _h.CapsuleImageSize
1582*f6dc9357SAndroid Build Coastguard Worker        || _h.CapsuleImageSize > (1u << 30) // to reduce false detection
1583*f6dc9357SAndroid Build Coastguard Worker        || _h.HeaderSize > (1u << 28) // to reduce false detection
1584*f6dc9357SAndroid Build Coastguard Worker       )
1585*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
1586*f6dc9357SAndroid Build Coastguard Worker   _phySize = _h.CapsuleImageSize;
1587*f6dc9357SAndroid Build Coastguard Worker 
1588*f6dc9357SAndroid Build Coastguard Worker   if (_h.SequenceNumber != 0 ||
1589*f6dc9357SAndroid Build Coastguard Worker       _h.OffsetToSplitInformation != 0 )
1590*f6dc9357SAndroid Build Coastguard Worker     return E_NOTIMPL;
1591*f6dc9357SAndroid Build Coastguard Worker 
1592*f6dc9357SAndroid Build Coastguard Worker   const unsigned bufIndex = AddBuf(_h.CapsuleImageSize);
1593*f6dc9357SAndroid Build Coastguard Worker   CByteBuffer &buf0 = _bufs[bufIndex];
1594*f6dc9357SAndroid Build Coastguard Worker   memcpy(buf0, buf, kHeaderSize);
1595*f6dc9357SAndroid Build Coastguard Worker   ReadStream_FALSE(stream, buf0 + kHeaderSize, _h.CapsuleImageSize - kHeaderSize);
1596*f6dc9357SAndroid Build Coastguard Worker 
1597*f6dc9357SAndroid Build Coastguard Worker   AddCommentString("Author", _h.OffsetToAuthorInformation);
1598*f6dc9357SAndroid Build Coastguard Worker   AddCommentString("Revision", _h.OffsetToRevisionInformation);
1599*f6dc9357SAndroid Build Coastguard Worker   AddCommentString("Short Description", _h.OffsetToShortDescription);
1600*f6dc9357SAndroid Build Coastguard Worker   AddCommentString("Long Description", _h.OffsetToLongDescription);
1601*f6dc9357SAndroid Build Coastguard Worker 
1602*f6dc9357SAndroid Build Coastguard Worker 
1603*f6dc9357SAndroid Build Coastguard Worker   const UInt32 size = _h.CapsuleImageSize - _h.OffsetToCapsuleBody;
1604*f6dc9357SAndroid Build Coastguard Worker 
1605*f6dc9357SAndroid Build Coastguard Worker   if (size >= 32 && IsIntelMe(buf0 + _h.OffsetToCapsuleBody))
1606*f6dc9357SAndroid Build Coastguard Worker     return ParseIntelMe(bufIndex, _h.OffsetToCapsuleBody, size, size, -1, -1, 0);
1607*f6dc9357SAndroid Build Coastguard Worker 
1608*f6dc9357SAndroid Build Coastguard Worker   return ParseVolume(bufIndex, _h.OffsetToCapsuleBody, size, size, -1, -1, 0);
1609*f6dc9357SAndroid Build Coastguard Worker }
1610*f6dc9357SAndroid Build Coastguard Worker 
1611*f6dc9357SAndroid Build Coastguard Worker 
1612*f6dc9357SAndroid Build Coastguard Worker HRESULT CHandler::OpenFv(IInStream *stream, const UInt64 * /* maxCheckStartPosition */, IArchiveOpenCallback * /* callback */)
1613*f6dc9357SAndroid Build Coastguard Worker {
1614*f6dc9357SAndroid Build Coastguard Worker   Byte buf[kFvHeaderSize];
1615*f6dc9357SAndroid Build Coastguard Worker   RINOK(ReadStream_FALSE(stream, buf, kFvHeaderSize))
1616*f6dc9357SAndroid Build Coastguard Worker   if (!IsFfs(buf))
1617*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
1618*f6dc9357SAndroid Build Coastguard Worker   CVolFfsHeader ffsHeader;
1619*f6dc9357SAndroid Build Coastguard Worker   if (!ffsHeader.Parse(buf))
1620*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
1621*f6dc9357SAndroid Build Coastguard Worker   if (ffsHeader.VolSize > ((UInt32)1 << 30))
1622*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
1623*f6dc9357SAndroid Build Coastguard Worker   _phySize = ffsHeader.VolSize;
1624*f6dc9357SAndroid Build Coastguard Worker   RINOK(InStream_SeekToBegin(stream))
1625*f6dc9357SAndroid Build Coastguard Worker   UInt32 fvSize32 = (UInt32)ffsHeader.VolSize;
1626*f6dc9357SAndroid Build Coastguard Worker   unsigned bufIndex = AddBuf(fvSize32);
1627*f6dc9357SAndroid Build Coastguard Worker   RINOK(ReadStream_FALSE(stream, _bufs[bufIndex], fvSize32))
1628*f6dc9357SAndroid Build Coastguard Worker   return ParseVolume(bufIndex, 0, fvSize32, fvSize32, -1, -1, 0);
1629*f6dc9357SAndroid Build Coastguard Worker }
1630*f6dc9357SAndroid Build Coastguard Worker 
1631*f6dc9357SAndroid Build Coastguard Worker 
1632*f6dc9357SAndroid Build Coastguard Worker HRESULT CHandler::Open2(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *callback)
1633*f6dc9357SAndroid Build Coastguard Worker {
1634*f6dc9357SAndroid Build Coastguard Worker   if (_capsuleMode)
1635*f6dc9357SAndroid Build Coastguard Worker   {
1636*f6dc9357SAndroid Build Coastguard Worker     RINOK(OpenCapsule(stream))
1637*f6dc9357SAndroid Build Coastguard Worker   }
1638*f6dc9357SAndroid Build Coastguard Worker   else
1639*f6dc9357SAndroid Build Coastguard Worker   {
1640*f6dc9357SAndroid Build Coastguard Worker     RINOK(OpenFv(stream, maxCheckStartPosition, callback))
1641*f6dc9357SAndroid Build Coastguard Worker   }
1642*f6dc9357SAndroid Build Coastguard Worker 
1643*f6dc9357SAndroid Build Coastguard Worker   const unsigned num = _items.Size();
1644*f6dc9357SAndroid Build Coastguard Worker   CIntArr numChilds(num);
1645*f6dc9357SAndroid Build Coastguard Worker 
1646*f6dc9357SAndroid Build Coastguard Worker   unsigned i;
1647*f6dc9357SAndroid Build Coastguard Worker 
1648*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < num; i++)
1649*f6dc9357SAndroid Build Coastguard Worker     numChilds[i] = 0;
1650*f6dc9357SAndroid Build Coastguard Worker 
1651*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < num; i++)
1652*f6dc9357SAndroid Build Coastguard Worker   {
1653*f6dc9357SAndroid Build Coastguard Worker     const int parent = _items[i].Parent;
1654*f6dc9357SAndroid Build Coastguard Worker     if (parent >= 0)
1655*f6dc9357SAndroid Build Coastguard Worker       numChilds[(unsigned)parent]++;
1656*f6dc9357SAndroid Build Coastguard Worker   }
1657*f6dc9357SAndroid Build Coastguard Worker 
1658*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < num; i++)
1659*f6dc9357SAndroid Build Coastguard Worker   {
1660*f6dc9357SAndroid Build Coastguard Worker     const CItem &item = _items[i];
1661*f6dc9357SAndroid Build Coastguard Worker     const int parent = item.Parent;
1662*f6dc9357SAndroid Build Coastguard Worker     if (parent >= 0)
1663*f6dc9357SAndroid Build Coastguard Worker     {
1664*f6dc9357SAndroid Build Coastguard Worker       CItem &parentItem = _items[(unsigned)parent];
1665*f6dc9357SAndroid Build Coastguard Worker       if (numChilds[(unsigned)parent] == 1)
1666*f6dc9357SAndroid Build Coastguard Worker         if (!item.ThereIsUniqueName || !parentItem.ThereIsUniqueName || !parentItem.ThereAreSubDirs)
1667*f6dc9357SAndroid Build Coastguard Worker           parentItem.Skip = true;
1668*f6dc9357SAndroid Build Coastguard Worker     }
1669*f6dc9357SAndroid Build Coastguard Worker   }
1670*f6dc9357SAndroid Build Coastguard Worker 
1671*f6dc9357SAndroid Build Coastguard Worker   CUIntVector mainToReduced;
1672*f6dc9357SAndroid Build Coastguard Worker 
1673*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < _items.Size(); i++)
1674*f6dc9357SAndroid Build Coastguard Worker   {
1675*f6dc9357SAndroid Build Coastguard Worker     mainToReduced.Add(_items2.Size());
1676*f6dc9357SAndroid Build Coastguard Worker     const CItem &item = _items[i];
1677*f6dc9357SAndroid Build Coastguard Worker     if (item.Skip)
1678*f6dc9357SAndroid Build Coastguard Worker       continue;
1679*f6dc9357SAndroid Build Coastguard Worker     AString name;
1680*f6dc9357SAndroid Build Coastguard Worker     int numItems = -1;
1681*f6dc9357SAndroid Build Coastguard Worker     int parent = item.Parent;
1682*f6dc9357SAndroid Build Coastguard Worker     if (parent >= 0)
1683*f6dc9357SAndroid Build Coastguard Worker       numItems = numChilds[(unsigned)parent];
1684*f6dc9357SAndroid Build Coastguard Worker     AString name2 (item.GetName(numItems));
1685*f6dc9357SAndroid Build Coastguard Worker     AString characts2 (item.Characts);
1686*f6dc9357SAndroid Build Coastguard Worker     if (item.KeepName)
1687*f6dc9357SAndroid Build Coastguard Worker       name = name2;
1688*f6dc9357SAndroid Build Coastguard Worker 
1689*f6dc9357SAndroid Build Coastguard Worker     while (parent >= 0)
1690*f6dc9357SAndroid Build Coastguard Worker     {
1691*f6dc9357SAndroid Build Coastguard Worker       const CItem &item3 = _items[(unsigned)parent];
1692*f6dc9357SAndroid Build Coastguard Worker       if (!item3.Skip)
1693*f6dc9357SAndroid Build Coastguard Worker         break;
1694*f6dc9357SAndroid Build Coastguard Worker       if (item3.KeepName)
1695*f6dc9357SAndroid Build Coastguard Worker       {
1696*f6dc9357SAndroid Build Coastguard Worker         AString name3 (item3.GetName(-1));
1697*f6dc9357SAndroid Build Coastguard Worker         if (name.IsEmpty())
1698*f6dc9357SAndroid Build Coastguard Worker           name = name3;
1699*f6dc9357SAndroid Build Coastguard Worker         else
1700*f6dc9357SAndroid Build Coastguard Worker           name = name3 + '.' + name;
1701*f6dc9357SAndroid Build Coastguard Worker       }
1702*f6dc9357SAndroid Build Coastguard Worker       AddSpaceAndString(characts2, item3.Characts);
1703*f6dc9357SAndroid Build Coastguard Worker       parent = item3.Parent;
1704*f6dc9357SAndroid Build Coastguard Worker     }
1705*f6dc9357SAndroid Build Coastguard Worker 
1706*f6dc9357SAndroid Build Coastguard Worker     if (name.IsEmpty())
1707*f6dc9357SAndroid Build Coastguard Worker       name = name2;
1708*f6dc9357SAndroid Build Coastguard Worker 
1709*f6dc9357SAndroid Build Coastguard Worker     CItem2 item2;
1710*f6dc9357SAndroid Build Coastguard Worker     item2.MainIndex = i;
1711*f6dc9357SAndroid Build Coastguard Worker     item2.Name = name;
1712*f6dc9357SAndroid Build Coastguard Worker     item2.Characts = characts2;
1713*f6dc9357SAndroid Build Coastguard Worker     if (parent >= 0)
1714*f6dc9357SAndroid Build Coastguard Worker       item2.Parent = (int)mainToReduced[(unsigned)parent];
1715*f6dc9357SAndroid Build Coastguard Worker     _items2.Add(item2);
1716*f6dc9357SAndroid Build Coastguard Worker     /*
1717*f6dc9357SAndroid Build Coastguard Worker     CItem2 item2;
1718*f6dc9357SAndroid Build Coastguard Worker     item2.MainIndex = i;
1719*f6dc9357SAndroid Build Coastguard Worker     item2.Name = item.Name;
1720*f6dc9357SAndroid Build Coastguard Worker     item2.Parent = item.Parent;
1721*f6dc9357SAndroid Build Coastguard Worker     _items2.Add(item2);
1722*f6dc9357SAndroid Build Coastguard Worker     */
1723*f6dc9357SAndroid Build Coastguard Worker   }
1724*f6dc9357SAndroid Build Coastguard Worker 
1725*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1726*f6dc9357SAndroid Build Coastguard Worker }
1727*f6dc9357SAndroid Build Coastguard Worker 
1728*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Open(IInStream *inStream,
1729*f6dc9357SAndroid Build Coastguard Worker     const UInt64 *maxCheckStartPosition,
1730*f6dc9357SAndroid Build Coastguard Worker     IArchiveOpenCallback *callback))
1731*f6dc9357SAndroid Build Coastguard Worker {
1732*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
1733*f6dc9357SAndroid Build Coastguard Worker   Close();
1734*f6dc9357SAndroid Build Coastguard Worker   {
1735*f6dc9357SAndroid Build Coastguard Worker     HRESULT res = Open2(inStream, maxCheckStartPosition, callback);
1736*f6dc9357SAndroid Build Coastguard Worker     if (res == E_NOTIMPL)
1737*f6dc9357SAndroid Build Coastguard Worker       res = S_FALSE;
1738*f6dc9357SAndroid Build Coastguard Worker     return res;
1739*f6dc9357SAndroid Build Coastguard Worker   }
1740*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
1741*f6dc9357SAndroid Build Coastguard Worker }
1742*f6dc9357SAndroid Build Coastguard Worker 
1743*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Close())
1744*f6dc9357SAndroid Build Coastguard Worker {
1745*f6dc9357SAndroid Build Coastguard Worker   _phySize = 0;
1746*f6dc9357SAndroid Build Coastguard Worker   _totalBufsSize = 0;
1747*f6dc9357SAndroid Build Coastguard Worker   _methodsMask = 0;
1748*f6dc9357SAndroid Build Coastguard Worker   _items.Clear();
1749*f6dc9357SAndroid Build Coastguard Worker   _items2.Clear();
1750*f6dc9357SAndroid Build Coastguard Worker   _bufs.Clear();
1751*f6dc9357SAndroid Build Coastguard Worker   _comment.Empty();
1752*f6dc9357SAndroid Build Coastguard Worker   _headersError = false;
1753*f6dc9357SAndroid Build Coastguard Worker   _h.Clear();
1754*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1755*f6dc9357SAndroid Build Coastguard Worker }
1756*f6dc9357SAndroid Build Coastguard Worker 
1757*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
1758*f6dc9357SAndroid Build Coastguard Worker {
1759*f6dc9357SAndroid Build Coastguard Worker   *numItems = _items2.Size();
1760*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1761*f6dc9357SAndroid Build Coastguard Worker }
1762*f6dc9357SAndroid Build Coastguard Worker 
1763*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
1764*f6dc9357SAndroid Build Coastguard Worker     Int32 testMode, IArchiveExtractCallback *extractCallback))
1765*f6dc9357SAndroid Build Coastguard Worker {
1766*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
1767*f6dc9357SAndroid Build Coastguard Worker   const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
1768*f6dc9357SAndroid Build Coastguard Worker   if (allFilesMode)
1769*f6dc9357SAndroid Build Coastguard Worker     numItems = _items2.Size();
1770*f6dc9357SAndroid Build Coastguard Worker   if (numItems == 0)
1771*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
1772*f6dc9357SAndroid Build Coastguard Worker   UInt64 totalSize = 0;
1773*f6dc9357SAndroid Build Coastguard Worker   UInt32 i;
1774*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < numItems; i++)
1775*f6dc9357SAndroid Build Coastguard Worker     totalSize += _items[_items2[allFilesMode ? i : indices[i]].MainIndex].Size;
1776*f6dc9357SAndroid Build Coastguard Worker   RINOK(extractCallback->SetTotal(totalSize))
1777*f6dc9357SAndroid Build Coastguard Worker   totalSize = 0;
1778*f6dc9357SAndroid Build Coastguard Worker 
1779*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ICompressProgressInfo, CLocalProgress> lps;
1780*f6dc9357SAndroid Build Coastguard Worker   lps->Init(extractCallback, false);
1781*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ICompressCoder, NCompress::CCopyCoder> copyCoder;
1782*f6dc9357SAndroid Build Coastguard Worker 
1783*f6dc9357SAndroid Build Coastguard Worker   for (i = 0;; i++)
1784*f6dc9357SAndroid Build Coastguard Worker   {
1785*f6dc9357SAndroid Build Coastguard Worker     lps->InSize = lps->OutSize = totalSize;
1786*f6dc9357SAndroid Build Coastguard Worker     RINOK(lps->SetCur())
1787*f6dc9357SAndroid Build Coastguard Worker     if (i >= numItems)
1788*f6dc9357SAndroid Build Coastguard Worker       break;
1789*f6dc9357SAndroid Build Coastguard Worker     Int32 opRes;
1790*f6dc9357SAndroid Build Coastguard Worker     {
1791*f6dc9357SAndroid Build Coastguard Worker       CMyComPtr<ISequentialOutStream> realOutStream;
1792*f6dc9357SAndroid Build Coastguard Worker       const Int32 askMode = testMode ?
1793*f6dc9357SAndroid Build Coastguard Worker           NExtract::NAskMode::kTest :
1794*f6dc9357SAndroid Build Coastguard Worker           NExtract::NAskMode::kExtract;
1795*f6dc9357SAndroid Build Coastguard Worker       const UInt32 index = allFilesMode ? i : indices[i];
1796*f6dc9357SAndroid Build Coastguard Worker       const CItem &item = _items[_items2[index].MainIndex];
1797*f6dc9357SAndroid Build Coastguard Worker       RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
1798*f6dc9357SAndroid Build Coastguard Worker       totalSize += item.Size;
1799*f6dc9357SAndroid Build Coastguard Worker       if (!testMode && !realOutStream)
1800*f6dc9357SAndroid Build Coastguard Worker         continue;
1801*f6dc9357SAndroid Build Coastguard Worker       RINOK(extractCallback->PrepareOperation(askMode))
1802*f6dc9357SAndroid Build Coastguard Worker       if (testMode || item.IsDir)
1803*f6dc9357SAndroid Build Coastguard Worker         opRes = NExtract::NOperationResult::kOK;
1804*f6dc9357SAndroid Build Coastguard Worker       else
1805*f6dc9357SAndroid Build Coastguard Worker       {
1806*f6dc9357SAndroid Build Coastguard Worker         opRes = NExtract::NOperationResult::kDataError;
1807*f6dc9357SAndroid Build Coastguard Worker         CMyComPtr<ISequentialInStream> inStream;
1808*f6dc9357SAndroid Build Coastguard Worker         GetStream(index, &inStream);
1809*f6dc9357SAndroid Build Coastguard Worker         if (inStream)
1810*f6dc9357SAndroid Build Coastguard Worker         {
1811*f6dc9357SAndroid Build Coastguard Worker           RINOK(copyCoder.Interface()->Code(inStream, realOutStream, NULL, NULL, lps))
1812*f6dc9357SAndroid Build Coastguard Worker           if (copyCoder->TotalSize == item.Size)
1813*f6dc9357SAndroid Build Coastguard Worker             opRes = NExtract::NOperationResult::kOK;
1814*f6dc9357SAndroid Build Coastguard Worker         }
1815*f6dc9357SAndroid Build Coastguard Worker       }
1816*f6dc9357SAndroid Build Coastguard Worker     }
1817*f6dc9357SAndroid Build Coastguard Worker     RINOK(extractCallback->SetOperationResult(opRes))
1818*f6dc9357SAndroid Build Coastguard Worker   }
1819*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1820*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
1821*f6dc9357SAndroid Build Coastguard Worker }
1822*f6dc9357SAndroid Build Coastguard Worker 
1823*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
1824*f6dc9357SAndroid Build Coastguard Worker {
1825*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
1826*f6dc9357SAndroid Build Coastguard Worker   const CItem &item = _items[_items2[index].MainIndex];
1827*f6dc9357SAndroid Build Coastguard Worker   if (item.IsDir)
1828*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
1829*f6dc9357SAndroid Build Coastguard Worker   CBufInStream *streamSpec = new CBufInStream;
1830*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<IInStream> streamTemp = streamSpec;
1831*f6dc9357SAndroid Build Coastguard Worker   const CByteBuffer &buf = _bufs[item.BufIndex];
1832*f6dc9357SAndroid Build Coastguard Worker   if (item.Offset > buf.Size())
1833*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
1834*f6dc9357SAndroid Build Coastguard Worker   size_t size = buf.Size() - item.Offset;
1835*f6dc9357SAndroid Build Coastguard Worker   if (size > item.Size)
1836*f6dc9357SAndroid Build Coastguard Worker     size = item.Size;
1837*f6dc9357SAndroid Build Coastguard Worker   streamSpec->Init(buf + item.Offset, size, (IInArchive *)this);
1838*f6dc9357SAndroid Build Coastguard Worker   *stream = streamTemp.Detach();
1839*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
1840*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
1841*f6dc9357SAndroid Build Coastguard Worker }
1842*f6dc9357SAndroid Build Coastguard Worker 
1843*f6dc9357SAndroid Build Coastguard Worker 
1844*f6dc9357SAndroid Build Coastguard Worker namespace UEFIc {
1845*f6dc9357SAndroid Build Coastguard Worker 
1846*f6dc9357SAndroid Build Coastguard Worker static const Byte k_Capsule_Signatures[] =
1847*f6dc9357SAndroid Build Coastguard Worker {
1848*f6dc9357SAndroid Build Coastguard Worker    16, CAPSULE_SIGNATURE,
1849*f6dc9357SAndroid Build Coastguard Worker    16, CAPSULE2_SIGNATURE,
1850*f6dc9357SAndroid Build Coastguard Worker    16, CAPSULE_UEFI_SIGNATURE
1851*f6dc9357SAndroid Build Coastguard Worker };
1852*f6dc9357SAndroid Build Coastguard Worker 
1853*f6dc9357SAndroid Build Coastguard Worker REGISTER_ARC_I_CLS(
1854*f6dc9357SAndroid Build Coastguard Worker   CHandler(true),
1855*f6dc9357SAndroid Build Coastguard Worker   "UEFIc", "scap", NULL, 0xD0,
1856*f6dc9357SAndroid Build Coastguard Worker   k_Capsule_Signatures,
1857*f6dc9357SAndroid Build Coastguard Worker   0,
1858*f6dc9357SAndroid Build Coastguard Worker   NArcInfoFlags::kMultiSignature |
1859*f6dc9357SAndroid Build Coastguard Worker   NArcInfoFlags::kFindSignature,
1860*f6dc9357SAndroid Build Coastguard Worker   NULL)
1861*f6dc9357SAndroid Build Coastguard Worker 
1862*f6dc9357SAndroid Build Coastguard Worker }
1863*f6dc9357SAndroid Build Coastguard Worker 
1864*f6dc9357SAndroid Build Coastguard Worker namespace UEFIf {
1865*f6dc9357SAndroid Build Coastguard Worker 
1866*f6dc9357SAndroid Build Coastguard Worker static const Byte k_FFS_Signatures[] =
1867*f6dc9357SAndroid Build Coastguard Worker {
1868*f6dc9357SAndroid Build Coastguard Worker    16, FFS1_SIGNATURE,
1869*f6dc9357SAndroid Build Coastguard Worker    16, FFS2_SIGNATURE
1870*f6dc9357SAndroid Build Coastguard Worker };
1871*f6dc9357SAndroid Build Coastguard Worker 
1872*f6dc9357SAndroid Build Coastguard Worker 
1873*f6dc9357SAndroid Build Coastguard Worker REGISTER_ARC_I_CLS(
1874*f6dc9357SAndroid Build Coastguard Worker   CHandler(false),
1875*f6dc9357SAndroid Build Coastguard Worker   "UEFIf", "uefif", NULL, 0xD1,
1876*f6dc9357SAndroid Build Coastguard Worker   k_FFS_Signatures,
1877*f6dc9357SAndroid Build Coastguard Worker   kFfsGuidOffset,
1878*f6dc9357SAndroid Build Coastguard Worker   NArcInfoFlags::kMultiSignature |
1879*f6dc9357SAndroid Build Coastguard Worker   NArcInfoFlags::kFindSignature,
1880*f6dc9357SAndroid Build Coastguard Worker   NULL)
1881*f6dc9357SAndroid Build Coastguard Worker 
1882*f6dc9357SAndroid Build Coastguard Worker }
1883*f6dc9357SAndroid Build Coastguard Worker 
1884*f6dc9357SAndroid Build Coastguard Worker }}
1885