UT 0.20.8

- data after the latest region of Intel image is in tree now
- added Intel, Lenovo and Toshiba-specific capsule GUIDs to the list of
known GUIDs
- fixed bogus "File with invalid size" message while working on almost
full volumes
- pressing Cancel on "Open in new window" dialog now works as expected

Big thanks to Lordkag for spotting most of the issues (#31).
This commit is contained in:
Nikolaj Schlej 2015-08-30 10:52:19 +02:00
parent 63e5a4dd1c
commit 9c4ddbec62
6 changed files with 159 additions and 61 deletions

View File

@ -85,6 +85,7 @@ typedef unsigned int UINTN;
#define ERR_INVALID_SYMBOL 40
#define ERR_NOTHING_TO_PATCH 41
#define ERR_DEPEX_PARSE_FAILED 42
#define ERR_TRUNCATED_IMAGE 43
#define ERR_NOT_IMPLEMENTED 0xFF
// UDK porting definitions

32
ffs.h
View File

@ -32,7 +32,7 @@ extern QString sectionTypeToQString(const UINT8 type);
//*****************************************************************************
// EFI Capsule
//*****************************************************************************
// Capsule header
// Standard EFI Capsule header
typedef struct _EFI_CAPSULE_HEADER {
EFI_GUID CapsuleGuid;
UINT32 HeaderSize;
@ -49,16 +49,36 @@ typedef struct _EFI_CAPSULE_HEADER {
const QByteArray EFI_CAPSULE_GUID
("\xBD\x86\x66\x3B\x76\x0D\x30\x40\xB7\x0E\xB5\x51\x9E\x2F\xC5\xA0", 16);
// Intel capsule GUID
const QByteArray INTEL_CAPSULE_GUID
("\xB9\x82\x91\x53\xB5\xAB\x91\x43\xB6\x9A\xE3\xA9\x43\xF7\x2F\xCC", 16);
// Lenovo capsule GUID
const QByteArray LENOVO_CAPSULE_GUID
("\x8B\xA6\x3C\x4A\x23\x77\xFB\x48\x80\x3D\x57\x8C\xC1\xFE\xC4\x4D", 16);
// Toshiba EFI Capsule header
typedef struct _TOSHIBA_CAPSULE_HEADER {
EFI_GUID CapsuleGuid;
UINT32 HeaderSize;
UINT32 FullSize;
UINT32 Flags;
} TOSHIBA_CAPSULE_HEADER;
// Toshiba capsule GUID
const QByteArray TOSHIBA_CAPSULE_GUID
("\x62\x70\xE0\x3B\x51\x1D\xD2\x45\x83\x2B\xF0\x93\x25\x7E\xD4\x61", 16);
// AMI Aptio extended capsule header
typedef struct _APTIO_CAPSULE_HEADER {
EFI_CAPSULE_HEADER CapsuleHeader;
UINT16 RomImageOffset; // offset in bytes from the beginning of the capsule header to the start of
UINT16 RomImageOffset; // offset in bytes from the beginning of the capsule header to the start of
// the capsule volume
//!TODO: Enable certificate and ROM layout reading
//UINT16 RomLayoutOffset; // offset to the table of the module descriptors in the capsule's volume
//UINT16 RomLayoutOffset; // offset to the table of the module descriptors in the capsule's volume
// that are included in the signature calculation
//FW_CERTIFICATE FWCert;
//ROM_AREA RomAreaMap[1];
//ROM_AREA RomAreaMap[1];
} APTIO_CAPSULE_HEADER;
// AMI Aptio signed extended capsule GUID
@ -252,8 +272,8 @@ extern UINT16 calculateChecksum16(const UINT16* buffer, UINT32 bufferSize);
// Integrity check
typedef union {
struct {
UINT8 Header;
UINT8 File;
UINT8 Header;
UINT8 File;
} Checksum;
UINT16 TailReference; // Revision 1
UINT16 Checksum16; // Revision 2

View File

@ -75,6 +75,7 @@ QString errorMessage(UINT8 errorCode)
case ERR_INVALID_SYMBOL: return QObject::tr("Invalid symbol");
case ERR_NOTHING_TO_PATCH: return QObject::tr("Nothing to patch");
case ERR_DEPEX_PARSE_FAILED: return QObject::tr("Dependency expression parsing failed");
case ERR_TRUNCATED_IMAGE: return QObject::tr("Image is truncated");
default: return QObject::tr("Unknown error %1").arg(errorCode);
}
}
@ -146,14 +147,16 @@ UINT8 FfsEngine::parseImageFile(const QByteArray & buffer)
// Check buffer size to be more then or equal to size of EFI_CAPSULE_HEADER
if ((UINT32)buffer.size() <= sizeof(EFI_CAPSULE_HEADER)) {
msg(tr("parseImageFile: image file is smaller then minimum size of %1h (%2) bytes").hexarg(sizeof(EFI_CAPSULE_HEADER)).arg(sizeof(EFI_CAPSULE_HEADER)));
msg(tr("parseImageFile: image file is smaller then minimum size of %1h (%2) bytes").hexarg(sizeof(EFI_CAPSULE_HEADER)).arg(sizeof(EFI_CAPSULE_HEADER)));
return ERR_INVALID_PARAMETER;
}
// Check buffer for being normal EFI capsule header
UINT32 capsuleHeaderSize = 0;
QModelIndex index;
if (buffer.startsWith(EFI_CAPSULE_GUID)) {
if (buffer.startsWith(EFI_CAPSULE_GUID)
|| buffer.startsWith(INTEL_CAPSULE_GUID)
|| buffer.startsWith(LENOVO_CAPSULE_GUID)) {
// Get info
const EFI_CAPSULE_HEADER* capsuleHeader = (const EFI_CAPSULE_HEADER*)buffer.constData();
capsuleHeaderSize = capsuleHeader->HeaderSize;
@ -170,7 +173,24 @@ UINT8 FfsEngine::parseImageFile(const QByteArray & buffer)
// Add tree item
index = model->addItem(Types::Capsule, Subtypes::UefiCapsule, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body);
}
// Check buffer for being Toshiba capsule header
else if (buffer.startsWith(TOSHIBA_CAPSULE_GUID)) {
// Get info
const TOSHIBA_CAPSULE_HEADER* capsuleHeader = (const TOSHIBA_CAPSULE_HEADER*)buffer.constData();
capsuleHeaderSize = capsuleHeader->HeaderSize;
QByteArray header = buffer.left(capsuleHeaderSize);
QByteArray body = buffer.right(buffer.size() - capsuleHeaderSize);
QString name = tr("UEFI capsule");
QString info = tr("Capsule GUID: %1\nFull size: %2h (%3)\nHeader size: %4h (%5)\nImage size: %6h (%7)\nFlags: %8h")
.arg(guidToQString(capsuleHeader->CapsuleGuid))
.hexarg(buffer.size()).arg(buffer.size())
.hexarg(capsuleHeader->HeaderSize).arg(capsuleHeader->HeaderSize)
.hexarg(capsuleHeader->FullSize - capsuleHeader->HeaderSize).arg(capsuleHeader->FullSize - capsuleHeader->HeaderSize)
.hexarg2(capsuleHeader->Flags, 8);
// Add tree item
index = model->addItem(Types::Capsule, Subtypes::ToshibaCapsule, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body);
}
// Check buffer for being extended Aptio signed capsule header
else if (buffer.startsWith(APTIO_SIGNED_CAPSULE_GUID) || buffer.startsWith(APTIO_UNSIGNED_CAPSULE_GUID)) {
// Get info
@ -192,7 +212,7 @@ UINT8 FfsEngine::parseImageFile(const QByteArray & buffer)
// Add tree item
index = model->addItem(Types::Capsule, signedCapsule ? Subtypes::AptioSignedCapsule : Subtypes::AptioUnsignedCapsule, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body);
// Show message about possible Aptio signature break
if (signedCapsule) {
msg(tr("parseImageFile: Aptio capsule signature may become invalid after image modifications"), index);
@ -458,6 +478,34 @@ UINT8 FfsEngine::parseIntelImage(const QByteArray & intelImage, QModelIndex & in
return result;
}
// Add the data after the last region as padding
UINT32 IntelDataEnd = 0;
UINT32 LastRegionOffset = offsets.last();
if (LastRegionOffset == gbeBegin)
IntelDataEnd = gbeEnd;
else if (LastRegionOffset == meBegin)
IntelDataEnd = meEnd;
else if (LastRegionOffset == biosBegin)
IntelDataEnd = biosEnd;
else if (LastRegionOffset == pdrBegin)
IntelDataEnd = pdrEnd;
if (IntelDataEnd > (UINT32)intelImage.size()) { // Image file is truncated
msg(tr("parseIntelImage: image size %1 (%2) is smaller than the end of last region %3 (%4), may be damaged")
.hexarg(intelImage.size()).arg(intelImage.size())
.hexarg(IntelDataEnd).arg(IntelDataEnd), index);
return ERR_TRUNCATED_IMAGE;
}
else if (IntelDataEnd < (UINT32)intelImage.size()) { // Insert padding
QByteArray padding = bios.right(intelImage.size() - IntelDataEnd);
// Get info
name = tr("Padding");
info = tr("Full size: %1h (%2)")
.hexarg(padding.size()).arg(padding.size());
// Add tree item
model->addItem(Types::Padding, getPaddingType(padding), COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), padding, index);
}
return ERR_SUCCESS;
}
@ -495,7 +543,7 @@ UINT8 FfsEngine::parseMeRegion(const QByteArray & me, QModelIndex & index, const
return ERR_EMPTY_REGION;
// Get info
QString name = tr("ME/TXE region");
QString name = tr("ME region");
QString info = tr("Full size: %1h (%2)").
hexarg(me.size()).arg(me.size());
@ -536,10 +584,10 @@ UINT8 FfsEngine::parseMeRegion(const QByteArray & me, QModelIndex & index, const
// Show messages
if (emptyRegion) {
msg(tr("parseRegion: ME/TXE region is empty"), index);
msg(tr("parseRegion: ME region is empty"), index);
}
else if (!versionFound) {
msg(tr("parseRegion: ME/TXE region version is unknown, it can be damaged"), index);
msg(tr("parseRegion: ME region version is unknown, it can be damaged"), index);
}
return ERR_SUCCESS;
@ -611,7 +659,7 @@ UINT8 FfsEngine::parseBios(const QByteArray & bios, const QModelIndex & parent)
name = tr("Padding");
info = tr("Full size: %1h (%2)")
.hexarg(padding.size()).arg(padding.size());
// Add tree item
model->addItem(Types::Padding, getPaddingType(padding), COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), padding, parent);
}
@ -777,7 +825,7 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, co
// Check for volume structure to be known
bool volumeIsUnknown = true;
/*UINT8 volumeFfsVersion = 0;*/
// Check for FFS v2 volume
if (FFSv2Volumes.contains(QByteArray::fromRawData((const char*)volumeHeader->FileSystemGuid.Data, sizeof(EFI_GUID)))) {
volumeIsUnknown = false;
@ -864,7 +912,7 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, co
if (msgInvalidChecksum) {
msg(tr("parseVolume: volume header checksum is invalid"), index);
}
// Search for and parse all files
UINT32 fileOffset = headerSize;
UINT32 fileSize;
@ -874,6 +922,22 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, co
bool msgUnalignedFile = false;
bool msgDuplicateGuid = false;
// Check if it's possibly the latest file in the volume
if (volumeSize - fileOffset < sizeof(EFI_FFS_FILE_HEADER)) {
// No files are possible after this point
// All the rest is either free space or non-UEFI data
QByteArray rest = volume.right(volumeSize - fileOffset);
if (rest.count(empty) == rest.size()) { // It's a free space
model->addItem(Types::FreeSpace, 0, COMPRESSION_ALGORITHM_NONE, tr("Volume free space"), "", tr("Full size: %1h (%2)").hexarg(rest.size()).arg(rest.size()), QByteArray(), rest, index, mode);
}
else { //It's non-UEFI data
QModelIndex dataIndex = model->addItem(Types::Padding, Subtypes::DataPadding, COMPRESSION_ALGORITHM_NONE, tr("Non-UEFI data"), "", tr("Full size: %1h (%2)").hexarg(rest.size()).arg(rest.size()), QByteArray(), rest, index, mode);
msg(tr("parseVolume: non-UEFI data found in volume's free space"), dataIndex);
}
// Exit from loop
break;
}
result = getFileSize(volume, fileOffset, fileSize);
if (result)
return result;
@ -907,7 +971,7 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, co
i = ALIGN8(i) - 8;
// Add all bytes before as free space...
if (i > 0) {
if (i > 0) {
QByteArray free = freeSpace.left(i);
model->addItem(Types::FreeSpace, 0, COMPRESSION_ALGORITHM_NONE, tr("Volume free space"), "", tr("Full size: %1h (%2)").hexarg(free.size()).arg(free.size()), QByteArray(), free, index, mode);
}
@ -1079,7 +1143,7 @@ UINT8 FfsEngine::parseFile(const QByteArray & file, QModelIndex & index, const U
QString info;
if (fileHeader->Type != EFI_FV_FILETYPE_PAD)
name = guidToQString(fileHeader->Name);
else
else
name = parseAsNonEmptyPadFile ? tr("Non-empty pad-file") : tr("Pad-file");
info = tr("File GUID: %1\nType: %2h\nAttributes: %3h\nFull size: %4h (%5)\nHeader size: %6h (%7)\nBody size: %8h (%9)\nState: %10h")
@ -1103,7 +1167,7 @@ UINT8 FfsEngine::parseFile(const QByteArray & file, QModelIndex & index, const U
msg(tr("parseFile: invalid tail value"), index);
if (msgInvalidType)
msg(tr("parseFile: unknown file type %1h").arg(fileHeader->Type, 2), index);
// No parsing needed
if (!parseCurrentFile)
return ERR_SUCCESS;
@ -1126,10 +1190,10 @@ UINT8 FfsEngine::parseFile(const QByteArray & file, QModelIndex & index, const U
// ... and all bytes after as a padding
QByteArray padding = body.mid(i);
QModelIndex dataIndex = model->addItem(Types::Padding, Subtypes::DataPadding, COMPRESSION_ALGORITHM_NONE, tr("Non-UEFI data"), "", tr("Full size: %1h (%2)").hexarg(padding.size()).arg(padding.size()), QByteArray(), padding, index, mode);
// Show message
msg(tr("parseFile: non-empty pad-file contents will be destroyed after volume modifications"), dataIndex);
return ERR_SUCCESS;
}
@ -1211,7 +1275,7 @@ UINT8 FfsEngine::parseDepexSection(const QByteArray & body, QString & parsed)
const EFI_GUID * guid;
const UINT8* current = (const UINT8*)body.constData();
// Special cases of first opcode
switch (*current) {
case EFI_DEP_BEFORE:
@ -1241,7 +1305,7 @@ UINT8 FfsEngine::parseDepexSection(const QByteArray & body, QString & parsed)
break;
}
// Parse the rest of depex
// Parse the rest of depex
while (current - (const UINT8*)body.constData() < body.size()) {
switch (*current) {
case EFI_DEP_BEFORE:
@ -1287,9 +1351,9 @@ UINT8 FfsEngine::parseDepexSection(const QByteArray & body, QString & parsed)
return ERR_DEPEX_PARSE_FAILED;
}
break;
default:
return ERR_DEPEX_PARSE_FAILED;
break;
default:
return ERR_DEPEX_PARSE_FAILED;
break;
}
}
@ -1379,11 +1443,11 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
// Tiano compressed section
if (QByteArray((const char*)&guidDefinedSectionHeader->SectionDefinitionGuid, sizeof(EFI_GUID)) == EFI_GUIDED_SECTION_TIANO) {
algorithm = COMPRESSION_ALGORITHM_UNKNOWN;
result = decompress(body, EFI_STANDARD_COMPRESSION, processed, &algorithm);
if (result)
parseCurrentSection = false;
if (algorithm == COMPRESSION_ALGORITHM_TIANO) {
info += tr("\nCompression type: Tiano");
info += tr("\nDecompressed size: %1h (%2)").hexarg(processed.length()).arg(processed.length());
@ -1392,17 +1456,17 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
info += tr("\nCompression type: EFI 1.1");
info += tr("\nDecompressed size: %1h (%2)").hexarg(processed.length()).arg(processed.length());
}
else
else
info += tr("\nCompression type: unknown");
}
// LZMA compressed section
else if (QByteArray((const char*)&guidDefinedSectionHeader->SectionDefinitionGuid, sizeof(EFI_GUID)) == EFI_GUIDED_SECTION_LZMA) {
algorithm = COMPRESSION_ALGORITHM_UNKNOWN;
result = decompress(body, EFI_CUSTOMIZED_COMPRESSION, processed, &algorithm);
if (result)
parseCurrentSection = false;
if (algorithm == COMPRESSION_ALGORITHM_LZMA) {
info += tr("\nCompression type: LZMA");
info += tr("\nDecompressed size: %1h (%2)").hexarg(processed.length()).arg(processed.length());
@ -1570,7 +1634,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
if (teHeader->Signature != EFI_IMAGE_TE_SIGNATURE) {
info += tr("\nSignature: %1h, invalid").hexarg2(teHeader->Signature, 4);
msgInvalidSignature = true;
}
}
else {
info += tr("\nSignature: %1h\nMachine type: %2\nNumber of sections: %3\nSubsystem: %4h\nStrippedSize: %5h (%6)\nBaseOfCode: %7h\nRelativeEntryPoint: %8h\nImageBase: %9h\nEntryPoint: %10h")
.hexarg2(teHeader->Signature, 4)
@ -1833,7 +1897,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, QModelIndex & index, c
index = model->addItem(Types::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, parent, mode);
// Parse section body as BIOS space
if (!parsed) {
if (!parsed) {
result = parseBios(body, index);
if (result && result != ERR_VOLUMES_NOT_FOUND && result != ERR_INVALID_VOLUME) {
msg(tr("parseSection: parsing raw section as BIOS failed with error \"%1\"").arg(errorMessage(result)), index);
@ -1922,7 +1986,7 @@ UINT8 FfsEngine::create(const QModelIndex & index, const UINT8 type, const QByte
}
else if (type == Types::Volume) {
QByteArray volume;
if (header.isEmpty()) // Whole volume
if (header.isEmpty()) // Whole volume
volume.append(body);
else { // Body only
volume.append(model->header(index)).append(body);
@ -1936,7 +2000,7 @@ UINT8 FfsEngine::create(const QModelIndex & index, const UINT8 type, const QByte
result = parseVolume(volume, fileIndex, index, mode);
if (result)
return result;
// Set action
model->setAction(fileIndex, action);
}
@ -1954,7 +2018,7 @@ UINT8 FfsEngine::create(const QModelIndex & index, const UINT8 type, const QByte
QByteArray newHeader = header;
EFI_FFS_FILE_HEADER* fileHeader = (EFI_FFS_FILE_HEADER*)newHeader.data();
// Correct file size
UINT8 tailSize = fileHeader->Attributes & FFS_ATTRIB_TAIL_PRESENT ? sizeof(UINT16) : 0;
uint32ToUint24(sizeof(EFI_FFS_FILE_HEADER) + body.size() + tailSize, fileHeader->Size);
@ -2478,7 +2542,7 @@ UINT8 FfsEngine::compress(const QByteArray & data, const UINT8 algorithm, QByteA
return ERR_STANDARD_COMPRESSION_FAILED;
}
compressedData = QByteArray((const char*)compressed, compressedSize);
// Check that compressed data can be decompressed normally
QByteArray decompressed;
if (decompress(compressedData, EFI_STANDARD_COMPRESSION, decompressed, NULL) == ERR_SUCCESS
@ -2498,7 +2562,7 @@ UINT8 FfsEngine::compress(const QByteArray & data, const UINT8 algorithm, QByteA
return ERR_STANDARD_COMPRESSION_FAILED;
}
compressedData = QByteArray((const char*)compressed, compressedSize);
// New functions will be trusted here, because another check will reduce performance
delete[] compressed;
return ERR_SUCCESS;
@ -2657,12 +2721,20 @@ UINT8 FfsEngine::reconstructIntelImage(const QModelIndex& index, QByteArray& rec
char empty = '\xFF';
for (int i = 1; i < model->rowCount(index); i++) {
QByteArray region;
// Padding after the end of all Intel regions
if (model->type(index.child(i, 0)) == Types::Padding) {
region = model->body(index.child(i, 0));
reconstructed.append(region);
offset += region.size();
continue;
}
result = reconstructRegion(index.child(i, 0), region);
if (result)
return result;
UINT8 type = model->subtype(index.child(i, 0));
switch (type)
switch (model->subtype(index.child(i, 0)))
{
case Subtypes::GbeRegion:
gbe = region;
@ -2761,7 +2833,7 @@ UINT8 FfsEngine::reconstructRegion(const QModelIndex& index, QByteArray& reconst
if (reconstructed.size() > model->body(index).size()) {
msg(tr("reconstructRegion: reconstructed region size %1h (%2) is bigger then original %3h (%4)")
.hexarg(reconstructed.size()).arg(reconstructed.size())
.hexarg(model->body(index).size()).arg(reconstructed.size()),
.hexarg(model->body(index).size()).arg(reconstructed.size()),
index);
return ERR_INVALID_PARAMETER;
}
@ -2799,7 +2871,7 @@ UINT8 FfsEngine::reconstructVolume(const QModelIndex & index, QByteArray & recon
reconstructed.clear();
return ERR_SUCCESS;
}
else if (model->action(index) == Actions::Replace ||
else if (model->action(index) == Actions::Replace ||
model->action(index) == Actions::Rebuild) {
QByteArray header = model->header(index);
QByteArray body = model->body(index);
@ -2811,7 +2883,7 @@ UINT8 FfsEngine::reconstructVolume(const QModelIndex & index, QByteArray & recon
// Get volume size
UINT32 volumeSize = header.size() + body.size();
// Reconstruct volume body
UINT32 freeSpaceOffset = 0;
if (model->rowCount(index)) {
@ -2926,7 +2998,7 @@ UINT8 FfsEngine::reconstructVolume(const QModelIndex & index, QByteArray & recon
// Pad file
if (fileHeader->Type == EFI_FV_FILETYPE_PAD) {
padFileGuid = file.left(sizeof(EFI_GUID));
// Parse non-empty pad file
if (model->rowCount(index.child(i, 0))) {
//TODO: handle it
@ -2981,7 +3053,7 @@ UINT8 FfsEngine::reconstructVolume(const QModelIndex & index, QByteArray & recon
// Get non-UEFI data and it's offset
nonUefiData = model->body(index.child(i + 1, 0));
nonUefiDataOffset = body.size() - nonUefiData.size();
break;
break;
}
}
}
@ -3133,7 +3205,7 @@ UINT8 FfsEngine::reconstructVolume(const QModelIndex & index, QByteArray & recon
volumeHeader->Checksum = calculateChecksum16((const UINT16*)volumeHeader, volumeHeader->HeaderLength);
}
}
return ERR_SUCCESS;
}
@ -3435,7 +3507,7 @@ UINT8 FfsEngine::reconstructSection(const QModelIndex& index, const UINT32 base,
const EFI_IMAGE_TE_HEADER* teHeader = (const EFI_IMAGE_TE_HEADER*)model->body(index).constData();
teFixup = teHeader->StrippedSize - sizeof(EFI_IMAGE_TE_HEADER);
}*/
if (base) {
result = rebase(reconstructed, base - teFixup + header.size());
if (result) {
@ -3966,7 +4038,7 @@ UINT8 FfsEngine::getBase(const QByteArray& file, UINT32& base)
// Populate TE header
const EFI_IMAGE_TE_HEADER* teHeader = (const EFI_IMAGE_TE_HEADER*)file.constData();
//!TODO: add handling
base = teHeader->ImageBase;
base = teHeader->ImageBase;
}
return ERR_SUCCESS;
@ -4041,10 +4113,10 @@ UINT8 FfsEngine::recursiveDump(const QModelIndex & index, const QString & path,
return ERR_INVALID_PARAMETER;
QDir dir;
if (guid.isEmpty() ||
if (guid.isEmpty() ||
guidToQString(*(const EFI_GUID*)model->header(index).constData()) == guid ||
guidToQString(*(const EFI_GUID*)model->header(model->findParentOfType(index, Types::File)).constData()) == guid) {
if (dir.cd(path))
return ERR_DIR_ALREADY_EXIST;
@ -4079,7 +4151,7 @@ UINT8 FfsEngine::recursiveDump(const QModelIndex & index, const QString & path,
file.write(info.toLatin1());
file.close();
dumped = true;
}
}
UINT8 result;
for (int i = 0; i < model->rowCount(index); i++) {

View File

@ -24,7 +24,7 @@ QString regionTypeToQString(const UINT8 type)
case Subtypes::GbeRegion:
return QObject::tr("GbE");
case Subtypes::MeRegion:
return QObject::tr("ME/TXE");
return QObject::tr("ME");
case Subtypes::BiosRegion:
return QObject::tr("BIOS");
case Subtypes::PdrRegion:
@ -80,7 +80,7 @@ QString itemSubtypeToQString(const UINT8 type, const UINT8 subtype)
return QObject::tr("Non-empty");
else
return QObject::tr("Unknown subtype");
case Types::Volume:
case Types::Volume:
if (subtype == Subtypes::UnknownVolume)
return QObject::tr("Unknown");
else if (subtype == Subtypes::Ffs2Volume)
@ -89,14 +89,16 @@ QString itemSubtypeToQString(const UINT8 type, const UINT8 subtype)
return QObject::tr("FFSv3");
else
return QObject::tr("Unknown subtype");
case Types::Capsule:
case Types::Capsule:
if (subtype == Subtypes::AptioSignedCapsule)
return QObject::tr("Aptio signed");
else if (subtype == Subtypes::AptioUnsignedCapsule)
return QObject::tr("Aptio unsigned");
else if (subtype == Subtypes::UefiCapsule)
return QObject::tr("UEFI 2.0 ");
else
return QObject::tr("UEFI 2.0");
else if (subtype == Subtypes::ToshibaCapsule)
return QObject::tr("Toshiba");
else
return QObject::tr("Unknown subtype");
case Types::Region:
return regionTypeToQString(subtype);

View File

@ -54,7 +54,8 @@ namespace Subtypes {
enum CapsuleSubtypes {
AptioSignedCapsule = 80,
AptioUnsignedCapsule,
UefiCapsule
UefiCapsule,
ToshibaCapsule
};
enum VolumeSubtypes {

View File

@ -16,8 +16,8 @@
UEFITool::UEFITool(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::UEFITool),
version(tr("0.20.7"))
ui(new Ui::UEFITool),
version(tr("0.20.8"))
{
clipboard = QApplication::clipboard();
@ -85,8 +85,8 @@ UEFITool::~UEFITool()
}
void UEFITool::setProgramPath(QString path)
{
currentProgramPath = path;
{
currentProgramPath = path;
};
void UEFITool::init()
@ -455,7 +455,7 @@ void UEFITool::extract(const UINT8 mode)
case Types::Capsule:
path = QFileDialog::getSaveFileName(this, tr("Save capsule body to image file"), currentDir, "Image files (*.rom *.bin);;All files (*)");
break;
case Types::Volume:
case Types::Volume:
path = QFileDialog::getSaveFileName(this, tr("Save volume body to file"), currentDir, "Volume body files (*.vbd *.bin);;All files (*)");
break;
case Types::File: {
@ -567,6 +567,8 @@ void UEFITool::openImageFile()
void UEFITool::openImageFileInNewWindow()
{
QString path = QFileDialog::getOpenFileName(this, tr("Open BIOS image file in new window"), currentDir, "BIOS image files (*.rom *.bin *.cap *.bio *.fd *.wph *.dec);;All files (*)");
if (path.trimmed().isEmpty())
return;
QProcess::startDetached(currentProgramPath, QStringList(path));
}