p7zip/CPP/7zip/Archive/UefiHandler.cpp
2017-10-11 12:35:36 +02:00

1619 lines
41 KiB
C++

// UefiHandler.cpp
#include "StdAfx.h"
// #define SHOW_DEBUG_INFO
#ifdef SHOW_DEBUG_INFO
#include <stdio.h>
#endif
#include "../../../C/7zCrc.h"
#include "../../../C/Alloc.h"
#include "../../../C/CpuArch.h"
#include "../../../C/LzmaDec.h"
#include "../../Common/ComTry.h"
#include "../../Common/IntToString.h"
#include "../../Common/MyBuffer.h"
#include "../../Common/StringConvert.h"
#include "../../Windows/PropVariantUtils.h"
#include "../Common/ProgressUtils.h"
#include "../Common/RegisterArc.h"
#include "../Common/StreamObjects.h"
#include "../Common/StreamUtils.h"
#include "../Compress/CopyCoder.h"
#include "../Compress/LzhDecoder.h"
#ifdef SHOW_DEBUG_INFO
#define PRF(x) x
#else
#define PRF(x)
#endif
#define Get16(p) GetUi16(p)
#define Get32(p) GetUi32(p)
#define Get64(p) GetUi64(p)
#define Get24(p) (Get32(p) & 0xFFFFFF)
namespace NArchive {
namespace NUefi {
static const size_t kBufTotalSizeMax = (1 << 29);
static const unsigned kNumFilesMax = (1 << 18);
static const unsigned kLevelMax = 64;
static const unsigned kFvHeaderSize = 0x38;
static const unsigned kGuidSize = 16;
#define CAPSULE_SIGNATURE \
{ 0xBD,0x86,0x66,0x3B,0x76,0x0D,0x30,0x40,0xB7,0x0E,0xB5,0x51,0x9E,0x2F,0xC5,0xA0 }
static const Byte kCapsuleSig[kGuidSize] = CAPSULE_SIGNATURE;
static const unsigned kFfsGuidOffset = 16;
#define FFS_SIGNATURE \
{ 0xD9,0x54,0x93,0x7A,0x68,0x04,0x4A,0x44,0x81,0xCE,0x0B,0xF6,0x17,0xD8,0x90,0xDF }
static const Byte k_FFS_Guid[kGuidSize] = FFS_SIGNATURE;
static const Byte k_MacFS_Guid[kGuidSize] =
{ 0xAD,0xEE,0xAD,0x04,0xFF,0x61,0x31,0x4D,0xB6,0xBA,0x64,0xF8,0xBF,0x90,0x1F,0x5A };
static const UInt32 kFvSignature = 0x4856465F; // "_FVH"
static const Byte kGuids[][kGuidSize] =
{
{ 0xB0,0xCD,0x1B,0xFC,0x31,0x7D,0xAA,0x49,0x93,0x6A,0xA4,0x60,0x0D,0x9D,0xD0,0x83 },
{ 0x2E,0x06,0xA0,0x1B,0x79,0xC7,0x82,0x45,0x85,0x66,0x33,0x6A,0xE8,0xF7,0x8F,0x09 },
{ 0x25,0x4E,0x37,0x7E,0x01,0x8E,0xEE,0x4F,0x87,0xf2,0x39,0x0C,0x23,0xC6,0x06,0xCD },
{ 0x97,0xE5,0x1B,0x16,0xC5,0xE9,0xDB,0x49,0xAE,0x50,0xC4,0x62,0xAB,0x54,0xEE,0xDA },
{ 0xDB,0x7F,0xAD,0x77,0x2A,0xDF,0x02,0x43,0x88,0x98,0xC7,0x2E,0x4C,0xDB,0xD0,0xF4 },
{ 0xAB,0x71,0xCF,0xF5,0x4B,0xB0,0x7E,0x4B,0x98,0x8A,0xD8,0xA0,0xD4,0x98,0xE6,0x92 },
{ 0x91,0x45,0x53,0x7A,0xCE,0x37,0x81,0x48,0xB3,0xC9,0x71,0x38,0x14,0xF4,0x5D,0x6B },
{ 0x84,0xE6,0x7A,0x36,0x5D,0x33,0x71,0x46,0xA1,0x6D,0x89,0x9D,0xBF,0xEA,0x6B,0x88 },
{ 0x98,0x07,0x40,0x24,0x07,0x38,0x42,0x4A,0xB4,0x13,0xA1,0xEC,0xEE,0x20,0x5D,0xD8 },
{ 0xEE,0xA2,0x3F,0x28,0x2C,0x53,0x4D,0x48,0x93,0x83,0x9F,0x93,0xB3,0x6F,0x0B,0x7E },
{ 0x9B,0xD5,0xB8,0x98,0xBA,0xE8,0xEE,0x48,0x98,0xDD,0xC2,0x95,0x39,0x2F,0x1E,0xDB },
{ 0x09,0x6D,0xE3,0xC3,0x94,0x82,0x97,0x4B,0xA8,0x57,0xD5,0x28,0x8F,0xE3,0x3E,0x28 },
{ 0x18,0x88,0x53,0x4A,0xE0,0x5A,0xB2,0x4E,0xB2,0xEB,0x48,0x8B,0x23,0x65,0x70,0x22 }
};
static const char * const kGuidNames[] =
{
"CRC"
, "VolumeTopFile"
, "ACPI"
, "ACPI2"
, "Main"
, "Intel32"
, "Intel64"
, "Intel32c"
, "Intel64c"
, "MacVolume"
, "MacUpdate.txt"
, "MacName"
, "Insyde"
};
enum
{
kGuidIndex_CRC = 0
};
struct CSigExtPair
{
const char *ext;
unsigned sigSize;
Byte sig[16];
};
static const CSigExtPair g_Sigs[] =
{
{ "bmp", 2, { 'B','M' } },
{ "riff", 4, { 'R','I','F','F' } },
{ "pe", 2, { 'M','Z'} },
{ "gif", 6, { 'G','I','F','8','9', 'a' } },
{ "png", 8, { 0x89,0x50,0x4E,0x47,0x0D,0x0A,0x1A,0x0A } },
{ "jpg", 10, { 0xFF,0xD8,0xFF,0xE0,0x00,0x10,0x4A,0x46,0x49,0x46 } },
{ "rom", 2, { 0x55,0xAA } }
};
enum
{
kSig_BMP,
kSig_RIFF,
kSig_PE
};
static const char *FindExt(const Byte *p, size_t size)
{
unsigned i;
for (i = 0; i < ARRAY_SIZE(g_Sigs); i++)
{
const CSigExtPair &pair = g_Sigs[i];
if (size >= pair.sigSize)
if (memcmp(p, pair.sig, pair.sigSize) == 0)
break;
}
if (i == ARRAY_SIZE(g_Sigs))
return NULL;
switch (i)
{
case kSig_BMP:
if (GetUi32(p + 2) > size || GetUi32(p + 0xA) > size)
return NULL;
break;
case kSig_RIFF:
if (GetUi32(p + 8) == 0x45564157 || GetUi32(p + 0xC) == 0x20746D66 )
return "wav";
break;
case kSig_PE:
{
if (size < 512)
return NULL;
UInt32 peOffset = GetUi32(p + 0x3C);
if (peOffset >= 0x1000 || peOffset + 512 > size || (peOffset & 7) != 0)
return NULL;
if (GetUi32(p + peOffset) != 0x00004550)
return NULL;
break;
}
}
return g_Sigs[i].ext;
}
static bool AreGuidsEq(const Byte *p1, const Byte *p2)
{
return memcmp(p1, p2, kGuidSize) == 0;
}
static int FindGuid(const Byte *p)
{
for (unsigned i = 0; i < ARRAY_SIZE(kGuids); i++)
if (AreGuidsEq(p, kGuids[i]))
return i;
return -1;
}
static bool IsFfs(const Byte *p)
{
return (Get32(p + 0x28) == kFvSignature && AreGuidsEq(p + kFfsGuidOffset, k_FFS_Guid));
}
#define FVB_ERASE_POLARITY (1 << 11)
/*
static const CUInt32PCharPair g_FV_Attribs[] =
{
{ 0, "ReadDisabledCap" },
{ 1, "ReadEnabledCap" },
{ 2, "ReadEnabled" },
{ 3, "WriteDisabledCap" },
{ 4, "WriteEnabledCap" },
{ 5, "WriteEnabled" },
{ 6, "LockCap" },
{ 7, "Locked" },
{ 9, "StickyWrite" },
{ 10, "MemoryMapped" },
{ 11, "ErasePolarity" },
{ 12, "ReadLockCap" },
{ 13, "WriteLockCap" },
{ 14, "WriteLockCap" }
};
*/
enum
{
FV_FILETYPE_ALL,
FV_FILETYPE_RAW,
FV_FILETYPE_FREEFORM,
FV_FILETYPE_SECURITY_CORE,
FV_FILETYPE_PEI_CORE,
FV_FILETYPE_DXE_CORE,
FV_FILETYPE_PEIM,
FV_FILETYPE_DRIVER,
FV_FILETYPE_COMBINED_PEIM_DRIVER,
FV_FILETYPE_APPLICATION,
// The value 0x0A is reserved and should not be used
FV_FILETYPE_FIRMWARE_VOLUME_IMAGE = 0x0B,
// types 0xF0 - 0xFF are FFS file types
FV_FILETYPE_FFS_PAD = 0xF0
};
static const char *g_FileTypes[] =
{
"ALL"
, "RAW"
, "FREEFORM"
, "SECURITY_CORE"
, "PEI_CORE"
, "DXE_CORE"
, "PEIM"
, "DRIVER"
, "COMBINED_PEIM_DRIVER"
, "APPLICATION"
, "0xA"
, "VOLUME"
};
// typedef Byte FFS_FILE_ATTRIBUTES;
// FFS File Attributes
#define FFS_ATTRIB_TAIL_PRESENT 0x01
// #define FFS_ATTRIB_RECOVERY 0x02
// #define FFS_ATTRIB_HEADER_EXTENSION 0x04
// #define FFS_ATTRIB_DATA_ALIGNMENT 0x38
#define FFS_ATTRIB_CHECKSUM 0x40
static const CUInt32PCharPair g_FFS_FILE_ATTRIBUTES[] =
{
{ 0, "" /* "TAIL" */ },
{ 1, "RECOVERY" },
// { 2, "HEADER_EXTENSION" }, // reserved for future
{ 6, "" /* "CHECKSUM" */ }
};
// static const Byte g_Allignment[8] = { 3, 4, 7, 9, 10, 12, 15, 16 };
// typedef Byte FFS_FILE_STATE;
// Look also FVB_ERASE_POLARITY.
// Lower-order State bits are superceded by higher-order State bits.
// #define FILE_HEADER_CONSTRUCTION 0x01
// #define FILE_HEADER_VALID 0x02
#define FILE_DATA_VALID 0x04
// #define FILE_MARKED_FOR_UPDATE 0x08
// #define FILE_DELETED 0x10
// #define FILE_HEADER_INVALID 0x20
// SECTION_TYPE
#define SECTION_ALL 0x00
#define SECTION_COMPRESSION 0x01
#define SECTION_GUID_DEFINED 0x02
// Leaf section Type values
#define SECTION_PE32 0x10
#define SECTION_PIC 0x11
#define SECTION_TE 0x12
#define SECTION_DXE_DEPEX 0x13
#define SECTION_VERSION 0x14
#define SECTION_USER_INTERFACE 0x15
#define SECTION_COMPATIBILITY16 0x16
#define SECTION_FIRMWARE_VOLUME_IMAGE 0x17
#define SECTION_FREEFORM_SUBTYPE_GUID 0x18
#define SECTION_RAW 0x19
#define SECTION_PEI_DEPEX 0x1B
// #define GUIDED_SECTION_PROCESSING_REQUIRED 0x01
// #define GUIDED_SECTION_AUTH_STATUS_VALID 0x02
static const CUInt32PCharPair g_GUIDED_SECTION_ATTRIBUTES[] =
{
{ 0, "PROCESSING_REQUIRED" },
{ 1, "AUTH" }
};
static const CUInt32PCharPair g_SECTION_TYPE[] =
{
{ 0x01, "COMPRESSION" },
{ 0x02, "GUID" },
{ 0x10, "efi" },
{ 0x11, "PIC" },
{ 0x12, "te" },
{ 0x13, "DXE_DEPEX" },
{ 0x14, "VERSION" },
{ 0x15, "USER_INTERFACE" },
{ 0x16, "COMPATIBILITY16" },
{ 0x17, "VOLUME" },
{ 0x18, "FREEFORM_SUBTYPE_GUID" },
{ 0x19, "raw" },
{ 0x1B, "PEI_DEPEX" }
};
#define COMPRESSION_TYPE_NONE 0
#define COMPRESSION_TYPE_LZH 1
#define COMPRESSION_TYPE_LZMA 2
static const char * const g_Methods[] =
{
"COPY"
, "LZH"
, "LZMA"
};
static AString UInt32ToString(UInt32 val)
{
char sz[16];
ConvertUInt32ToString(val, sz);
return sz;
}
static void ConvertByteToHex(unsigned value, char *s)
{
for (int i = 0; i < 2; i++)
{
unsigned t = value & 0xF;
value >>= 4;
s[1 - i] = (char)((t < 10) ? ('0' + t) : ('A' + (t - 10)));
}
}
static AString GuidToString(const Byte *p, bool full)
{
char s[16 * 2 + 8];
int i;
for (i = 0; i < 4; i++)
ConvertByteToHex(p[3 - i], s + i * 2);
s[8] = 0;
if (full)
{
s[8] = '-';
for (i = 4; i < kGuidSize; i++)
ConvertByteToHex(p[i], s + 1 + i * 2);
s[32 + 1] = 0;
}
return s;
}
static const char * const kExpressionCommands[] =
{
"BEFORE", "AFTER", "PUSH", "AND", "OR", "NOT", "TRUE", "FALSE", "END", "SOR"
};
static bool ParseDepedencyExpression(const Byte *p, UInt32 size, AString &res)
{
res.Empty();
for (UInt32 i = 0; i < size;)
{
unsigned command = p[i++];
if (command > ARRAY_SIZE(kExpressionCommands))
return false;
res += kExpressionCommands[command];
if (command < 3)
{
if (i + kGuidSize > size)
return false;
res.Add_Space();
res += GuidToString(p + i, false);
i += kGuidSize;
}
res += "; ";
}
return true;
}
static bool ParseUtf16zString(const Byte *p, UInt32 size, UString &res)
{
if ((size & 1) != 0)
return false;
res.Empty();
UInt32 i;
for (i = 0; i < size; i += 2)
{
wchar_t c = Get16(p + i);
if (c == 0)
break;
res += c;
}
return (i == size - 2);
}
static bool ParseUtf16zString2(const Byte *p, UInt32 size, AString &res)
{
UString s;
if (!ParseUtf16zString(p, size, s))
return false;
res = UnicodeStringToMultiByte(s);
return true;
}
#define FLAGS_TO_STRING(pairs, value) FlagsToString(pairs, ARRAY_SIZE(pairs), value)
#define TYPE_TO_STRING(table, value) TypeToString(table, ARRAY_SIZE(table), value)
#define TYPE_PAIR_TO_STRING(table, value) TypePairToString(table, ARRAY_SIZE(table), value)
static const UInt32 kFileHeaderSize = 24;
static void AddSpaceAndString(AString &res, const AString &newString)
{
if (!newString.IsEmpty())
{
res.Add_Space_if_NotEmpty();
res += newString;
}
}
class CFfsFileHeader
{
Byte CheckHeader;
Byte CheckFile;
Byte Attrib;
Byte State;
UInt16 GetTailReference() const { return (UInt16)(CheckHeader | ((UInt16)CheckFile << 8)); }
UInt32 GetTailSize() const { return IsThereTail() ? 2 : 0; }
bool IsThereFileChecksum() const { return (Attrib & FFS_ATTRIB_CHECKSUM) != 0; }
bool IsThereTail() const { return (Attrib & FFS_ATTRIB_TAIL_PRESENT) != 0; }
public:
Byte GuidName[kGuidSize];
Byte Type;
UInt32 Size;
bool Parse(const Byte *p)
{
int i;
for (i = 0; i < kFileHeaderSize; i++)
if (p[i] != 0xFF)
break;
if (i == kFileHeaderSize)
return false;
memcpy(GuidName, p, kGuidSize);
CheckHeader = p[0x10];
CheckFile = p[0x11];
Type = p[0x12];
Attrib = p[0x13];
Size = Get24(p + 0x14);
State = p[0x17];
return true;
}
UInt32 GetDataSize() const { return Size - kFileHeaderSize - GetTailSize(); }
UInt32 GetDataSize2(UInt32 rem) const { return rem - kFileHeaderSize - GetTailSize(); }
bool Check(const Byte *p, UInt32 size)
{
if (Size > size)
return false;
UInt32 tailSize = GetTailSize();
if (Size < kFileHeaderSize + tailSize)
return false;
{
unsigned checkSum = 0;
for (UInt32 i = 0; i < kFileHeaderSize; i++)
checkSum += p[i];
checkSum -= p[0x17];
checkSum -= p[0x11];
if ((Byte)checkSum != 0)
return false;
}
if (IsThereFileChecksum())
{
unsigned checkSum = 0;
UInt32 checkSize = Size - tailSize;
for (UInt32 i = 0; i < checkSize; i++)
checkSum += p[i];
checkSum -= p[0x17];
if ((Byte)checkSum != 0)
return false;
}
if (IsThereTail())
if (GetTailReference() != (UInt16)~Get16(p + Size - 2))
return false;
int polarity = 0;
int i;
for (i = 5; i >= 0; i--)
if (((State >> i) & 1) == polarity)
{
// AddSpaceAndString(s, g_FFS_FILE_STATE_Flags[i]);
if ((1 << i) != FILE_DATA_VALID)
return false;
break;
}
if (i < 0)
return false;
return true;
}
AString GetCharacts() const
{
AString s;
if (Type == FV_FILETYPE_FFS_PAD)
s += "PAD";
else
s += TYPE_TO_STRING(g_FileTypes, Type);
AddSpaceAndString(s, FLAGS_TO_STRING(g_FFS_FILE_ATTRIBUTES, Attrib & 0xC7));
/*
int align = (Attrib >> 3) & 7;
if (align != 0)
{
s += " Align:";
s += UInt32ToString((UInt32)1 << g_Allignment[align]);
}
*/
return s;
}
};
#define G32(_offs_, dest) dest = Get32(p + (_offs_));
struct CCapsuleHeader
{
UInt32 HeaderSize;
UInt32 Flags;
UInt32 CapsuleImageSize;
UInt32 SequenceNumber;
// Guid InstanceId;
UInt32 OffsetToSplitInformation;
UInt32 OffsetToCapsuleBody;
UInt32 OffsetToOemDefinedHeader;
UInt32 OffsetToAuthorInformation;
UInt32 OffsetToRevisionInformation;
UInt32 OffsetToShortDescription;
UInt32 OffsetToLongDescription;
UInt32 OffsetToApplicableDevices;
void Clear() { memset(this, 0, sizeof(*this)); }
void Parse(const Byte *p)
{
G32(0x10, HeaderSize);
G32(0x14, Flags);
G32(0x18, CapsuleImageSize);
G32(0x1C, SequenceNumber);
G32(0x30, OffsetToSplitInformation);
G32(0x34, OffsetToCapsuleBody);
G32(0x38, OffsetToOemDefinedHeader);
G32(0x3C, OffsetToAuthorInformation);
G32(0x40, OffsetToRevisionInformation);
G32(0x44, OffsetToShortDescription);
G32(0x48, OffsetToLongDescription);
G32(0x4C, OffsetToApplicableDevices);
}
};
struct CItem
{
AString Name;
AString Characts;
int Parent;
int Method;
int NameIndex;
int NumChilds;
bool IsDir;
bool Skip;
bool ThereAreSubDirs;
bool ThereIsUniqueName;
bool KeepName;
int BufIndex;
UInt32 Offset;
UInt32 Size;
CItem(): Parent(-1), Method(-1), NameIndex(-1), NumChilds(0),
IsDir(false), Skip(false), ThereAreSubDirs(false), ThereIsUniqueName(false), KeepName(true) {}
void SetGuid(const Byte *guidName, bool full = false);
AString GetName(int numChildsInParent) const;
};
void CItem::SetGuid(const Byte *guidName, bool full)
{
ThereIsUniqueName = true;
int index = FindGuid(guidName);
if (index >= 0)
Name = kGuidNames[(unsigned)index];
else
Name = GuidToString(guidName, full);
}
AString CItem::GetName(int numChildsInParent) const
{
if (numChildsInParent <= 1 || NameIndex < 0)
return Name;
char sz[32];
char sz2[32];
ConvertUInt32ToString(NameIndex, sz);
ConvertUInt32ToString(numChildsInParent - 1, sz2);
unsigned numZeros = (unsigned)strlen(sz2) - (unsigned)strlen(sz);
AString res;
for (unsigned i = 0; i < numZeros; i++)
res += '0';
return res + (AString)sz + '.' + Name;
}
struct CItem2
{
AString Name;
AString Characts;
int MainIndex;
int Parent;
CItem2(): Parent(-1) {}
};
class CHandler:
public IInArchive,
public IInArchiveGetStream,
public CMyUnknownImp
{
CObjectVector<CItem> _items;
CObjectVector<CItem2> _items2;
CObjectVector<CByteBuffer> _bufs;
UString _comment;
UInt32 _methodsMask;
bool _capsuleMode;
size_t _totalBufsSize;
CCapsuleHeader _h;
UInt64 _phySize;
void AddCommentString(const wchar_t *name, UInt32 pos);
int AddItem(const CItem &item);
int AddFileItemWithIndex(CItem &item);
int AddDirItem(CItem &item);
unsigned AddBuf(size_t size);
HRESULT ParseSections(int bufIndex, UInt32 pos, UInt32 size, int parent, int method, unsigned level);
HRESULT ParseVolume(int bufIndex, UInt32 posBase,
UInt32 exactSize, UInt32 limitSize,
int parent, int method, int level);
HRESULT OpenCapsule(IInStream *stream);
HRESULT OpenFv(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *callback);
HRESULT Open2(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *callback);
public:
CHandler(bool capsuleMode): _capsuleMode(capsuleMode) {}
MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
INTERFACE_IInArchive(;)
STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
};
static const Byte kProps[] =
{
kpidPath,
kpidIsDir,
kpidSize,
kpidMethod,
kpidCharacts
};
static const Byte kArcProps[] =
{
kpidComment,
kpidMethod,
kpidCharacts
};
IMP_IInArchive_Props
IMP_IInArchive_ArcProps
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
NWindows::NCOM::CPropVariant prop;
const CItem2 &item2 = _items2[index];
const CItem &item = _items[item2.MainIndex];
switch (propID)
{
case kpidPath:
{
AString path = item2.Name;
int cur = item2.Parent;
while (cur >= 0)
{
const CItem2 &item3 = _items2[cur];
path.InsertAtFront(CHAR_PATH_SEPARATOR);
path.Insert(0, item3.Name);
cur = item3.Parent;
}
prop = path;
break;
}
case kpidIsDir: prop = item.IsDir; break;
case kpidMethod: if (item.Method >= 0) prop = g_Methods[(unsigned)item.Method]; break;
case kpidCharacts: if (!item2.Characts.IsEmpty()) prop = item2.Characts; break;
case kpidSize: if (!item.IsDir) prop = (UInt64)item.Size; break;
}
prop.Detach(value);
return S_OK;
COM_TRY_END
}
void CHandler::AddCommentString(const wchar_t *name, UInt32 pos)
{
UString s;
const Byte *buf = _bufs[0];
if (pos < _h.HeaderSize)
return;
for (UInt32 i = pos;; i += 2)
{
if (s.Len() > (1 << 16) || i >= _h.OffsetToCapsuleBody)
return;
wchar_t c = Get16(buf + i);
if (c == 0)
{
i += 2;
if (i >= _h.OffsetToCapsuleBody)
return;
c = Get16(buf + i);
if (c == 0)
break;
s.Add_LF();
}
s += c;
}
if (s.IsEmpty())
return;
_comment.Add_LF();
_comment += name;
_comment.AddAscii(": ");
_comment += s;
}
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
NWindows::NCOM::CPropVariant prop;
switch (propID)
{
case kpidMethod:
{
AString s;
for (unsigned i = 0; i < 32; i++)
if ((_methodsMask & ((UInt32)1 << i)) != 0)
AddSpaceAndString(s, g_Methods[i]);
if (!s.IsEmpty())
prop = s;
break;
}
case kpidComment: if (!_comment.IsEmpty()) prop = _comment; break;
case kpidPhySize: prop = (UInt64)_phySize; break;
}
prop.Detach(value);
return S_OK;
COM_TRY_END
}
#ifdef SHOW_DEBUG_INFO
static void PrintLevel(int level)
{
PRF(printf("\n"));
for (int i = 0; i < level; i++)
PRF(printf(" "));
}
static void MyPrint(UInt32 posBase, UInt32 size, int level, const char *name)
{
PrintLevel(level);
PRF(printf("%s, pos = %6x, size = %6d", name, posBase, size));
}
#else
#define PrintLevel(level)
#define MyPrint(posBase, size, level, name)
#endif
int CHandler::AddItem(const CItem &item)
{
if (_items.Size() >= kNumFilesMax)
throw 2;
return _items.Add(item);
}
int CHandler::AddFileItemWithIndex(CItem &item)
{
int nameIndex = _items.Size();
if (item.Parent >= 0)
nameIndex = _items[item.Parent].NumChilds++;
item.NameIndex = nameIndex;
return AddItem(item);
}
int CHandler::AddDirItem(CItem &item)
{
if (item.Parent >= 0)
_items[item.Parent].ThereAreSubDirs = true;
item.IsDir = true;
item.Size = 0;
return AddItem(item);
}
unsigned CHandler::AddBuf(size_t size)
{
if (size > kBufTotalSizeMax - _totalBufsSize)
throw 1;
_totalBufsSize += size;
unsigned index = _bufs.Size();
_bufs.AddNew().Alloc(size);
return index;
}
HRESULT CHandler::ParseSections(int bufIndex, UInt32 posBase, UInt32 size, int parent, int method, unsigned level)
{
if (level > kLevelMax)
return S_FALSE;
MyPrint(posBase, size, level, "Sections");
level++;
const Byte *bufData = _bufs[bufIndex];
UInt32 pos = 0;
for (;;)
{
if (size == pos)
return S_OK;
PrintLevel(level);
PRF(printf("%s, pos = %6x", "Sect", pos));
pos = (pos + 3) & ~(UInt32)3;
if (pos > size)
return S_FALSE;
UInt32 rem = size - pos;
if (rem == 0)
return S_OK;
if (rem < 4)
return S_FALSE;
const Byte *p = bufData + posBase + pos;
UInt32 sectSize = Get24(p);
if (sectSize > rem || sectSize < 4)
return S_FALSE;
Byte type = p[3];
PrintLevel(level);
PRF(printf("%s, type = %2x, pos = %6x, size = %6d", "Sect", type, pos, sectSize));
CItem item;
item.Method = method;
item.BufIndex = bufIndex;
item.Parent = parent;
item.Offset = posBase + pos + 4;
UInt32 sectDataSize = sectSize - 4;
item.Size = sectDataSize;
item.Name = TYPE_PAIR_TO_STRING(g_SECTION_TYPE, type);
if (type == SECTION_COMPRESSION)
{
if (sectSize < 4 + 5)
return S_FALSE;
UInt32 uncompressedSize = Get32(p + 4);
Byte compressionType = p[8];
UInt32 newSectSize = sectSize - 9;
UInt32 newOffset = posBase + pos + 9;
const Byte *pStart = p + 9;
item.KeepName = false;
if (compressionType > 2)
{
// AddFileItemWithIndex(item);
return S_FALSE;
}
else
{
item.Name = g_Methods[compressionType];
// int parent = AddDirItem(item);
if (compressionType == COMPRESSION_TYPE_NONE)
{
RINOK(ParseSections(bufIndex, newOffset, newSectSize, parent, method, level));
}
else if (compressionType == COMPRESSION_TYPE_LZH)
{
unsigned newBufIndex = AddBuf(uncompressedSize);
CByteBuffer &buf = _bufs[newBufIndex];
NCompress::NLzh::NDecoder::CCoder *lzhDecoderSpec = 0;
CMyComPtr<ICompressCoder> lzhDecoder;
lzhDecoderSpec = new NCompress::NLzh::NDecoder::CCoder;
lzhDecoder = lzhDecoderSpec;
{
const Byte *src = pStart;
if (newSectSize < 8)
return S_FALSE;
UInt32 packSize = Get32(src);
UInt32 unpackSize = Get32(src + 4);
if (uncompressedSize != unpackSize || newSectSize - 8 != packSize)
return S_FALSE;
if (packSize < 1)
return S_FALSE;
packSize--;
src += 8;
if (src[packSize] != 0)
return S_FALSE;
CBufInStream *inStreamSpec = new CBufInStream;
CMyComPtr<IInStream> inStream = inStreamSpec;
inStreamSpec->Init(src, packSize);
CBufPtrSeqOutStream *outStreamSpec = new CBufPtrSeqOutStream;
CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;
outStreamSpec->Init(buf, uncompressedSize);
UInt64 uncompressedSize64 = uncompressedSize;
lzhDecoderSpec->FinishMode = true;
/*
EFI 1.1 probably used small dictionary and (pbit = 4) in LZH. We don't support such archives.
New version of compression code (named Tiano) uses LZH with (1 << 19) dictionary.
But maybe LZH decoder in UEFI decoder supports larger than (1 << 19) dictionary.
*/
lzhDecoderSpec->SetDictSize(1 << 19);
HRESULT res = lzhDecoder->Code(inStream, outStream, NULL, &uncompressedSize64, NULL);
if (res != S_OK)
return res;
if (lzhDecoderSpec->GetInputProcessedSize() != packSize)
return S_FALSE;
}
RINOK(ParseSections(newBufIndex, 0, uncompressedSize, parent, compressionType, level));
}
else
{
if (newSectSize < 4 + 5 + 8)
return S_FALSE;
unsigned addSize = 4;
if (pStart[0] == 0x5d && pStart[1] == 0 && pStart[2] == 0 && pStart[3] == 0x80 && pStart[4] == 0)
{
addSize = 0;
// some archives have such header
}
else
{
// normal BIOS contains uncompressed size here
// UInt32 uncompressedSize2 = Get24(pStart);
// Byte firstSectType = p[9 + 3];
// firstSectType can be 0 in some archives
}
pStart += addSize;
UInt64 lzmaUncompressedSize = Get64(pStart + 5);
if (lzmaUncompressedSize > (1 << 30))
return S_FALSE;
if (lzmaUncompressedSize < uncompressedSize)
return S_FALSE;
SizeT destLen = (SizeT)lzmaUncompressedSize;
unsigned newBufIndex = AddBuf((size_t)lzmaUncompressedSize);
CByteBuffer &buf = _bufs[newBufIndex];
ELzmaStatus status;
SizeT srcLen = newSectSize - (addSize + 5 + 8);
SizeT srcLen2 = srcLen;
SRes res = LzmaDecode(buf, &destLen, pStart + 13, &srcLen,
pStart, 5, LZMA_FINISH_END, &status, &g_Alloc);
if (res != 0)
return S_FALSE;
if (srcLen != srcLen2 || destLen != lzmaUncompressedSize || (
status != LZMA_STATUS_FINISHED_WITH_MARK &&
status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK))
return S_FALSE;
RINOK(ParseSections(newBufIndex, 0, (UInt32)lzmaUncompressedSize, parent, compressionType, level));
}
_methodsMask |= (1 << compressionType);
}
}
else if (type == SECTION_GUID_DEFINED)
{
const unsigned kHeaderSize = 4 + kGuidSize + 4;
if (sectSize < kHeaderSize)
return S_FALSE;
item.SetGuid(p + 4);
UInt32 dataOffset = Get16(p + 4 + kGuidSize);
UInt32 attrib = Get16(p + 4 + kGuidSize + 2);
if (dataOffset > sectSize || dataOffset < kHeaderSize)
return S_FALSE;
UInt32 newSectSize = sectSize - dataOffset;
item.Size = newSectSize;
UInt32 newOffset = posBase + pos + dataOffset;
item.Offset = newOffset;
UInt32 propsSize = dataOffset - kHeaderSize;
bool needDir = true;
AddSpaceAndString(item.Characts, FLAGS_TO_STRING(g_GUIDED_SECTION_ATTRIBUTES, attrib));
if (AreGuidsEq(p + 0x4, kGuids[kGuidIndex_CRC]) && propsSize == 4)
{
needDir = false;
item.KeepName = false;
if (CrcCalc(bufData + newOffset, newSectSize) != Get32(p + kHeaderSize))
return S_FALSE;
}
else
{
if (propsSize != 0)
{
CItem item2 = item;
item2.Name += ".prop";
item2.Size = propsSize;
item2.Offset = posBase + pos + kHeaderSize;
AddItem(item2);
}
}
int newParent = parent;
if (needDir)
newParent = AddDirItem(item);
RINOK(ParseSections(bufIndex, newOffset, newSectSize, newParent, method, level));
}
else if (type == SECTION_FIRMWARE_VOLUME_IMAGE)
{
item.KeepName = false;
int newParent = AddDirItem(item);
RINOK(ParseVolume(bufIndex, posBase + pos + 4,
sectSize - 4,
sectSize - 4,
newParent, method, level));
}
else
{
bool needAdd = true;
switch (type)
{
case SECTION_RAW:
{
const UInt32 kInsydeOffset = 12;
if (sectDataSize >= kFvHeaderSize + kInsydeOffset)
{
if (IsFfs(p + 4 + kInsydeOffset) &&
sectDataSize - kInsydeOffset == Get64(p + 4 + kInsydeOffset + 0x20))
{
needAdd = false;
item.Name = "vol";
int newParent = AddDirItem(item);
RINOK(ParseVolume(bufIndex, posBase + pos + 4 + kInsydeOffset,
sectDataSize - kInsydeOffset,
sectDataSize - kInsydeOffset,
newParent, method, level));
}
if (needAdd)
{
const char *ext = FindExt(p + 4, sectDataSize);
if (ext)
item.Name = ext;
}
}
break;
}
case SECTION_DXE_DEPEX:
case SECTION_PEI_DEPEX:
{
AString s;
if (ParseDepedencyExpression(p + 4, sectDataSize, s))
{
if (s.Len() < (1 << 9))
{
s.InsertAtFront('[');
s += ']';
AddSpaceAndString(_items[item.Parent].Characts, s);
needAdd = false;
}
else
{
item.BufIndex = AddBuf(s.Len());
CByteBuffer &buf0 = _bufs[item.BufIndex];
if (s.Len() != 0)
memcpy(buf0, s, s.Len());
item.Offset = 0;
item.Size = s.Len();
}
}
break;
}
case SECTION_VERSION:
{
if (sectDataSize > 2)
{
AString s;
if (ParseUtf16zString2(p + 6, sectDataSize - 2, s))
{
AString s2 = "ver:";
s2 += UInt32ToString(Get16(p + 4));
s2.Add_Space();
s2 += s;
AddSpaceAndString(_items[item.Parent].Characts, s2);
needAdd = false;
}
}
break;
}
case SECTION_USER_INTERFACE:
{
AString s;
if (ParseUtf16zString2(p + 4, sectDataSize, s))
{
_items[parent].Name = s;
needAdd = false;
}
break;
}
case SECTION_FREEFORM_SUBTYPE_GUID:
{
if (sectDataSize >= kGuidSize)
{
item.SetGuid(p + 4);
item.Size = sectDataSize - kGuidSize;
item.Offset = posBase + pos + 4 + kGuidSize;
}
break;
}
}
if (needAdd)
AddFileItemWithIndex(item);
}
pos += sectSize;
}
}
static UInt32 Count_FF_Bytes(const Byte *p, UInt32 size)
{
UInt32 i;
for (i = 0; i < size && p[i] == 0xFF; i++);
return i;
}
static bool Is_FF_Stream(const Byte *p, UInt32 size)
{
return (Count_FF_Bytes(p, size) == size);
}
struct CVolFfsHeader
{
UInt32 HeaderLen;
UInt64 VolSize;
bool Parse(const Byte *p);
};
bool CVolFfsHeader::Parse(const Byte *p)
{
if (Get32(p + 0x28) != kFvSignature)
return false;
UInt32 attribs = Get32(p + 0x2C);
if ((attribs & FVB_ERASE_POLARITY) == 0)
return false;
VolSize = Get64(p + 0x20);
HeaderLen = Get16(p + 0x30);
if (HeaderLen < kFvHeaderSize || (HeaderLen & 0x7) != 0 || VolSize < HeaderLen)
return false;
return true;
};
HRESULT CHandler::ParseVolume(
int bufIndex, UInt32 posBase,
UInt32 exactSize, UInt32 limitSize,
int parent, int method, int level)
{
if (level > kLevelMax)
return S_FALSE;
MyPrint(posBase, size, level, "Volume");
level++;
if (exactSize < kFvHeaderSize)
return S_FALSE;
const Byte *p = _bufs[bufIndex] + posBase;
// first 16 bytes must be zeros, but they are not zeros sometimes.
if (!AreGuidsEq(p + kFfsGuidOffset, k_FFS_Guid) &&
!AreGuidsEq(p + kFfsGuidOffset, k_MacFS_Guid))
{
CItem item;
item.Method = method;
item.BufIndex = bufIndex;
item.Parent = parent;
item.Offset = posBase;
item.Size = exactSize;
item.SetGuid(p + kFfsGuidOffset);
item.Name += " [VOLUME]";
AddItem(item);
return S_OK;
}
CVolFfsHeader ffsHeader;
if (!ffsHeader.Parse(p))
return S_FALSE;
// if (parent >= 0) AddSpaceAndString(_items[parent].Characts, FLAGS_TO_STRING(g_FV_Attribs, attribs));
// VolSize > exactSize (fh.Size) for some UEFI archives (is it correct UEFI?)
// so we check VolSize for limitSize instead.
if (ffsHeader.HeaderLen > limitSize || ffsHeader.VolSize > limitSize)
return S_FALSE;
{
UInt32 checkCalc = 0;
for (UInt32 i = 0; i < ffsHeader.HeaderLen; i += 2)
checkCalc += Get16(p + i);
if ((checkCalc & 0xFFFF) != 0)
return S_FALSE;
}
// 3 reserved bytes are not zeros sometimes.
// UInt16 ExtHeaderOffset; // in new SPECIFICATION?
// Byte revision = p[0x37];
UInt32 pos = kFvHeaderSize;
for (;;)
{
if (pos >= ffsHeader.HeaderLen)
return S_FALSE;
UInt32 numBlocks = Get32(p + pos);
UInt32 length = Get32(p + pos + 4);
pos += 8;
if (numBlocks == 0 && length == 0)
break;
}
if (pos != ffsHeader.HeaderLen)
return S_FALSE;
CRecordVector<UInt32> guidsVector;
for (;;)
{
UInt32 rem = (UInt32)ffsHeader.VolSize - pos;
if (rem < kFileHeaderSize)
break;
pos = (pos + 7) & ~7;
rem = (UInt32)ffsHeader.VolSize - pos;
if (rem < kFileHeaderSize)
break;
CItem item;
item.Method = method;
item.BufIndex = bufIndex;
item.Parent = parent;
const Byte *pFile = p + pos;
CFfsFileHeader fh;
if (!fh.Parse(pFile))
{
UInt32 num_FF_bytes = Count_FF_Bytes(pFile, rem);
if (num_FF_bytes != rem)
{
item.Name = "[junk]";
item.Offset = posBase + pos + num_FF_bytes;
item.Size = rem - num_FF_bytes;
AddItem(item);
}
break;
}
PrintLevel(level); PRF(printf("%s, pos = %6x, size = %6d", "FILE", posBase + pos, fh.Size));
if (!fh.Check(pFile, rem))
return S_FALSE;
UInt32 offset = posBase + pos + kFileHeaderSize;
UInt32 sectSize = fh.GetDataSize();
item.Offset = offset;
item.Size = sectSize;
pos += fh.Size;
if (fh.Type == FV_FILETYPE_FFS_PAD)
if (Is_FF_Stream(pFile + kFileHeaderSize, sectSize))
continue;
UInt32 guid32 = Get32(fh.GuidName);
bool full = true;
if (guidsVector.FindInSorted(guid32) < 0)
{
guidsVector.AddToUniqueSorted(guid32);
full = false;
}
item.SetGuid(fh.GuidName, full);
item.Characts = fh.GetCharacts();
PrintLevel(level);
PRF(printf("%s", item.Characts));
if (fh.Type == FV_FILETYPE_FFS_PAD ||
fh.Type == FV_FILETYPE_RAW)
{
bool isVolume = false;
if (fh.Type == FV_FILETYPE_RAW)
{
if (sectSize >= kFvHeaderSize)
if (IsFfs(pFile + kFileHeaderSize))
isVolume = true;
}
if (isVolume)
{
int newParent = AddDirItem(item);
UInt32 limSize = fh.GetDataSize2(rem);
// volume.VolSize > fh.Size for some UEFI archives (is it correct UEFI?)
// so we will check VolSize for limitSize instead.
RINOK(ParseVolume(bufIndex, offset, sectSize, limSize, newParent, method, level));
}
else
AddItem(item);
}
else
{
int newParent = AddDirItem(item);
RINOK(ParseSections(bufIndex, offset, sectSize, newParent, method, level));
}
}
return S_OK;
}
HRESULT CHandler::OpenCapsule(IInStream *stream)
{
const unsigned kHeaderSize = 80;
Byte buf[kHeaderSize];
RINOK(ReadStream_FALSE(stream, buf, kHeaderSize));
_h.Parse(buf);
if (_h.HeaderSize != kHeaderSize ||
_h.CapsuleImageSize < kHeaderSize ||
_h.OffsetToCapsuleBody < kHeaderSize ||
_h.OffsetToCapsuleBody > _h.CapsuleImageSize)
return S_FALSE;
_phySize = _h.CapsuleImageSize;
if (_h.SequenceNumber != 0 ||
_h.OffsetToSplitInformation != 0 )
return E_NOTIMPL;
unsigned bufIndex = AddBuf(_h.CapsuleImageSize);
CByteBuffer &buf0 = _bufs[bufIndex];
memcpy(buf0, buf, kHeaderSize);
ReadStream_FALSE(stream, buf0 + kHeaderSize, _h.CapsuleImageSize - kHeaderSize);
AddCommentString(L"Author", _h.OffsetToAuthorInformation);
AddCommentString(L"Revision", _h.OffsetToRevisionInformation);
AddCommentString(L"Short Description", _h.OffsetToShortDescription);
AddCommentString(L"Long Description", _h.OffsetToLongDescription);
return ParseVolume(bufIndex, _h.OffsetToCapsuleBody,
_h.CapsuleImageSize - _h.OffsetToCapsuleBody,
_h.CapsuleImageSize - _h.OffsetToCapsuleBody,
-1, -1, 0);
}
HRESULT CHandler::OpenFv(IInStream *stream, const UInt64 * /* maxCheckStartPosition */, IArchiveOpenCallback * /* callback */)
{
Byte buf[kFvHeaderSize];
RINOK(ReadStream_FALSE(stream, buf, kFvHeaderSize));
if (!IsFfs(buf))
return S_FALSE;
CVolFfsHeader ffsHeader;
if (!ffsHeader.Parse(buf))
return S_FALSE;
if (ffsHeader.VolSize > ((UInt32)1 << 30))
return S_FALSE;
_phySize = ffsHeader.VolSize;
RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
UInt32 fvSize32 = (UInt32)ffsHeader.VolSize;
unsigned bufIndex = AddBuf(fvSize32);
RINOK(ReadStream_FALSE(stream, _bufs[bufIndex], fvSize32));
return ParseVolume(bufIndex, 0, fvSize32, fvSize32, -1, -1, 0);
}
HRESULT CHandler::Open2(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *callback)
{
if (_capsuleMode)
{
RINOK(OpenCapsule(stream));
}
else
{
RINOK(OpenFv(stream, maxCheckStartPosition, callback));
}
unsigned num = _items.Size();
CIntArr numChilds(num);
unsigned i;
for (i = 0; i < num; i++)
numChilds[i] = 0;
for (i = 0; i < num; i++)
{
int parent = _items[i].Parent;
if (parent >= 0)
numChilds[(unsigned)parent]++;
}
for (i = 0; i < num; i++)
{
const CItem &item = _items[i];
int parent = item.Parent;
if (parent >= 0)
{
CItem &parentItem = _items[(unsigned)parent];
if (numChilds[(unsigned)parent] == 1)
if (!item.ThereIsUniqueName || !parentItem.ThereIsUniqueName || !parentItem.ThereAreSubDirs)
parentItem.Skip = true;
}
}
CUIntVector mainToReduced;
for (i = 0; i < _items.Size(); i++)
{
mainToReduced.Add(_items2.Size());
const CItem &item = _items[i];
if (item.Skip)
continue;
AString name;
int numItems = -1;
int parent = item.Parent;
if (parent >= 0)
numItems = numChilds[(unsigned)parent];
AString name2 = item.GetName(numItems);
AString characts2 = item.Characts;
if (item.KeepName)
name = name2;
while (parent >= 0)
{
const CItem &item3 = _items[(unsigned)parent];
if (!item3.Skip)
break;
if (item3.KeepName)
{
AString name3 = item3.GetName(-1);
if (name.IsEmpty())
name = name3;
else
name = name3 + '.' + name;
}
AddSpaceAndString(characts2, item3.Characts);
parent = item3.Parent;
}
if (name.IsEmpty())
name = name2;
CItem2 item2;
item2.MainIndex = i;
item2.Name = name;
item2.Characts = characts2;
if (parent >= 0)
item2.Parent = mainToReduced[(unsigned)parent];
_items2.Add(item2);
/*
CItem2 item2;
item2.MainIndex = i;
item2.Name = item.Name;
item2.Parent = item.Parent;
_items2.Add(item2);
*/
}
return S_OK;
}
STDMETHODIMP CHandler::Open(IInStream *inStream,
const UInt64 *maxCheckStartPosition,
IArchiveOpenCallback *callback)
{
COM_TRY_BEGIN
Close();
{
HRESULT res = Open2(inStream, maxCheckStartPosition, callback);
if (res == E_NOTIMPL)
res = S_FALSE;
return res;
}
COM_TRY_END
}
STDMETHODIMP CHandler::Close()
{
_phySize = 0;
_totalBufsSize = 0;
_methodsMask = 0;
_items.Clear();
_items2.Clear();
_bufs.Clear();
_comment.Empty();
_h.Clear();
return S_OK;
}
STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
{
*numItems = _items2.Size();
return S_OK;
}
STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Int32 testMode, IArchiveExtractCallback *extractCallback)
{
COM_TRY_BEGIN
bool allFilesMode = (numItems == (UInt32)(Int32)-1);
if (allFilesMode)
numItems = _items2.Size();
if (numItems == 0)
return S_OK;
UInt64 totalSize = 0;
UInt32 i;
for (i = 0; i < numItems; i++)
totalSize += _items[_items2[allFilesMode ? i : indices[i]].MainIndex].Size;
extractCallback->SetTotal(totalSize);
UInt64 currentTotalSize = 0;
NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
CLocalProgress *lps = new CLocalProgress;
CMyComPtr<ICompressProgressInfo> progress = lps;
lps->Init(extractCallback, false);
for (i = 0; i < numItems; i++)
{
lps->InSize = lps->OutSize = currentTotalSize;
RINOK(lps->SetCur());
CMyComPtr<ISequentialOutStream> realOutStream;
Int32 askMode = testMode ?
NExtract::NAskMode::kTest :
NExtract::NAskMode::kExtract;
UInt32 index = allFilesMode ? i : indices[i];
const CItem &item = _items[_items2[index].MainIndex];
RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
currentTotalSize += item.Size;
if (!testMode && !realOutStream)
continue;
RINOK(extractCallback->PrepareOperation(askMode));
if (testMode || item.IsDir)
{
RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
continue;
}
int res = NExtract::NOperationResult::kDataError;
CMyComPtr<ISequentialInStream> inStream;
GetStream(index, &inStream);
if (inStream)
{
RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress));
if (copyCoderSpec->TotalSize == item.Size)
res = NExtract::NOperationResult::kOK;
}
realOutStream.Release();
RINOK(extractCallback->SetOperationResult(res));
}
return S_OK;
COM_TRY_END
}
STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
{
COM_TRY_BEGIN
const CItem &item = _items[_items2[index].MainIndex];
if (item.IsDir)
return S_FALSE;
CBufInStream *streamSpec = new CBufInStream;
CMyComPtr<IInStream> streamTemp = streamSpec;
const CByteBuffer &buf = _bufs[item.BufIndex];
/*
if (item.Offset + item.Size > buf.GetCapacity())
return S_FALSE;
*/
streamSpec->Init(buf + item.Offset, item.Size, (IInArchive *)this);
*stream = streamTemp.Detach();
return S_OK;
COM_TRY_END
}
namespace UEFIc {
REGISTER_ARC_I_CLS(
CHandler(true),
"UEFIc", "scap", 0, 0xD0,
kCapsuleSig,
0,
NArcInfoFlags::kFindSignature,
NULL)
}
namespace UEFIf {
REGISTER_ARC_I_CLS(
CHandler(false),
"UEFIf", "uefif", 0, 0xD1,
k_FFS_Guid,
kFfsGuidOffset,
NArcInfoFlags::kFindSignature,
NULL)
}
}}