Version 0.9.0

- fixed all interaction with file state
- added application meny
- added actions for changing compression method for selected compressed
section
This commit is contained in:
Nikolaj Schlej 2013-11-18 16:23:59 +01:00
parent a858cc23f5
commit bfd8edcdf9
11 changed files with 640 additions and 243 deletions

View File

@ -106,6 +106,11 @@ typedef uint16_t CHAR16;
#define INSERT_MODE_BEFORE 2 #define INSERT_MODE_BEFORE 2
#define INSERT_MODE_AFTER 3 #define INSERT_MODE_AFTER 3
// Erase polarity types
#define ERASE_POLARITY_FALSE 0
#define ERASE_POLARITY_TRUE 1
#define ERASE_POLARITY_UNKNOWN 0xFF
// EFI GUID // EFI GUID
typedef struct{ typedef struct{
UINT8 Data[16]; UINT8 Data[16];

1
ffs.h
View File

@ -296,6 +296,7 @@ extern const UINT8 ffsAlignmentTable[];
#define EFI_FILE_MARKED_FOR_UPDATE 0x08 #define EFI_FILE_MARKED_FOR_UPDATE 0x08
#define EFI_FILE_DELETED 0x10 #define EFI_FILE_DELETED 0x10
#define EFI_FILE_HEADER_INVALID 0x20 #define EFI_FILE_HEADER_INVALID 0x20
#define EFI_FILE_ERASE_POLARITY 0x80
// Volume top file // Volume top file
const QByteArray EFI_FFS_VOLUME_TOP_FILE_GUID const QByteArray EFI_FFS_VOLUME_TOP_FILE_GUID

View File

@ -274,7 +274,6 @@ UINT8 FfsEngine::parseIntelImage(const QByteArray & flashImage, const QModelInde
QString name; QString name;
QString info; QString info;
//!TODO: reorganize info
// Intel image // Intel image
name = tr("Intel image"); name = tr("Intel image");
info = tr("Size: %1\nFlash chips: %2\nRegions: %3\nMasters: %4\nPCH straps: %5\nPROC straps: %6\nICC table entries: %7") info = tr("Size: %1\nFlash chips: %2\nRegions: %3\nMasters: %4\nPCH straps: %5\nPROC straps: %6\nICC table entries: %7")
@ -441,7 +440,7 @@ UINT8 FfsEngine::parseBios(const QByteArray & bios, const QModelIndex & parent)
UINT32 prevVolumeOffset; UINT32 prevVolumeOffset;
UINT8 result; UINT8 result;
result = findNextVolume(bios, 0, prevVolumeOffset); result = findNextVolume(bios, 0, prevVolumeOffset);
if (result == ERR_VOLUMES_NOT_FOUND) { if (result) {
return result; return result;
} }
@ -771,10 +770,23 @@ UINT8 FfsEngine::getFileSize(const QByteArray & volume, const UINT32 fileOffset,
return ERR_SUCCESS; return ERR_SUCCESS;
} }
UINT8 FfsEngine::parseFile(const QByteArray & file, UINT8 revision, const char empty, const QModelIndex & parent, const UINT8 mode) UINT8 FfsEngine::parseFile(const QByteArray & file, UINT8 revision, const UINT8 erasePolarity, const QModelIndex & parent, const UINT8 mode)
{ {
// Populate file header
EFI_FFS_FILE_HEADER* fileHeader = (EFI_FFS_FILE_HEADER*) file.constData(); EFI_FFS_FILE_HEADER* fileHeader = (EFI_FFS_FILE_HEADER*) file.constData();
// Check file state
// Determine file erase polarity
bool fileErasePolarity = fileHeader->State | EFI_FILE_ERASE_POLARITY;
// Check file erase polarity to be the same as parent erase polarity
if (erasePolarity != ERASE_POLARITY_UNKNOWN && (bool) erasePolarity != fileErasePolarity) {
msg(tr("parseFile: %1, erase polarity differs from parent erase polarity"), parent);
}
// Construct empty byte for this file
char empty = fileErasePolarity ? '\xFF' : '\x00';
// Check header checksum // Check header checksum
QByteArray header = file.left(sizeof(EFI_FFS_FILE_HEADER)); QByteArray header = file.left(sizeof(EFI_FFS_FILE_HEADER));
QByteArray tempHeader = header; QByteArray tempHeader = header;
@ -784,7 +796,7 @@ UINT8 FfsEngine::parseFile(const QByteArray & file, UINT8 revision, const char e
UINT8 calculated = calculateChecksum8((UINT8*) tempFileHeader, sizeof(EFI_FFS_FILE_HEADER) - 1); UINT8 calculated = calculateChecksum8((UINT8*) tempFileHeader, sizeof(EFI_FFS_FILE_HEADER) - 1);
if (fileHeader->IntegrityCheck.Checksum.Header != calculated) if (fileHeader->IntegrityCheck.Checksum.Header != calculated)
{ {
msg(tr("parseVolume: %1, stored header checksum %2 differs from calculated %3") msg(tr("parseFile: %1, stored header checksum %2 differs from calculated %3")
.arg(guidToQString(fileHeader->Name)) .arg(guidToQString(fileHeader->Name))
.arg(fileHeader->IntegrityCheck.Checksum.Header, 2, 16, QChar('0')) .arg(fileHeader->IntegrityCheck.Checksum.Header, 2, 16, QChar('0'))
.arg(calculated, 2, 16, QChar('0')), parent); .arg(calculated, 2, 16, QChar('0')), parent);
@ -799,7 +811,7 @@ UINT8 FfsEngine::parseFile(const QByteArray & file, UINT8 revision, const char e
bufferSize -= sizeof(UINT16); bufferSize -= sizeof(UINT16);
calculated = calculateChecksum8((UINT8*)(file.constData() + sizeof(EFI_FFS_FILE_HEADER)), bufferSize); calculated = calculateChecksum8((UINT8*)(file.constData() + sizeof(EFI_FFS_FILE_HEADER)), bufferSize);
if (fileHeader->IntegrityCheck.Checksum.File != calculated) { if (fileHeader->IntegrityCheck.Checksum.File != calculated) {
msg(tr("parseVolume: %1, stored data checksum %2 differs from calculated %3") msg(tr("parseFile: %1, stored data checksum %2 differs from calculated %3")
.arg(guidToQString(fileHeader->Name)) .arg(guidToQString(fileHeader->Name))
.arg(fileHeader->IntegrityCheck.Checksum.File, 2, 16, QChar('0')) .arg(fileHeader->IntegrityCheck.Checksum.File, 2, 16, QChar('0'))
.arg(calculated, 2, 16, QChar('0')), parent); .arg(calculated, 2, 16, QChar('0')), parent);
@ -823,7 +835,7 @@ UINT8 FfsEngine::parseFile(const QByteArray & file, UINT8 revision, const char e
//Check file tail; //Check file tail;
tail = body.right(sizeof(UINT16)); tail = body.right(sizeof(UINT16));
if (!fileHeader->IntegrityCheck.TailReference == *(UINT16*)tail.constData()) if (!fileHeader->IntegrityCheck.TailReference == *(UINT16*)tail.constData())
msg(tr("parseVolume: %1, file tail value %2 is not a bitwise not of %3 stored in file header") msg(tr("parseFile: %1, file tail value %2 is not a bitwise not of %3 stored in file header")
.arg(guidToQString(fileHeader->Name)) .arg(guidToQString(fileHeader->Name))
.arg(*tail, 4, 16, QChar('0')) .arg(*tail, 4, 16, QChar('0'))
.arg(fileHeader->IntegrityCheck.TailReference, 4, 16, QChar('0')), parent); .arg(fileHeader->IntegrityCheck.TailReference, 4, 16, QChar('0')), parent);
@ -875,7 +887,7 @@ UINT8 FfsEngine::parseFile(const QByteArray & file, UINT8 revision, const char e
break; break;
default: default:
parseCurrentFile = false; parseCurrentFile = false;
msg(tr("parseVolume: Unknown file type (%1)").arg(fileHeader->Type, 2, 16, QChar('0')), parent); msg(tr("parseFile: Unknown file type (%1)").arg(fileHeader->Type, 2, 16, QChar('0')), parent);
}; };
// Check for empty file // Check for empty file
@ -908,12 +920,12 @@ UINT8 FfsEngine::parseFile(const QByteArray & file, UINT8 revision, const char e
if (parseAsBios) { if (parseAsBios) {
result = parseBios(body, index); result = parseBios(body, index);
if (result && result != ERR_VOLUMES_NOT_FOUND) if (result && result != ERR_VOLUMES_NOT_FOUND)
msg(tr("parseVolume: Parse file as BIOS failed (%1)").arg(result), index); msg(tr("parseFile: Parse file as BIOS failed (%1)").arg(result), index);
return ERR_SUCCESS; return ERR_SUCCESS;
} }
// Parse sections // Parse sections
result = parseSections(body, revision, empty, index); result = parseSections(body, index);
if (result) if (result)
return result; return result;
@ -927,7 +939,7 @@ UINT8 FfsEngine::getSectionSize(const QByteArray & file, const UINT32 sectionOff
return ERR_SUCCESS; return ERR_SUCCESS;
} }
UINT8 FfsEngine::parseSections(const QByteArray & body, const UINT8 revision, const char empty, const QModelIndex & parent) UINT8 FfsEngine::parseSections(const QByteArray & body, const QModelIndex & parent)
{ {
// Search for and parse all sections // Search for and parse all sections
UINT32 sectionOffset = 0; UINT32 sectionOffset = 0;
@ -941,7 +953,7 @@ UINT8 FfsEngine::parseSections(const QByteArray & body, const UINT8 revision, co
return result; return result;
// Parse section // Parse section
result = parseSection(body.mid(sectionOffset, sectionSize), revision, empty, parent); result = parseSection(body.mid(sectionOffset, sectionSize), parent);
if (result) if (result)
return result; return result;
@ -957,8 +969,7 @@ UINT8 FfsEngine::parseSections(const QByteArray & body, const UINT8 revision, co
return ERR_SUCCESS; return ERR_SUCCESS;
} }
UINT8 FfsEngine::parseSection(const QByteArray & section, const UINT8 revision, UINT8 FfsEngine::parseSection(const QByteArray & section, const QModelIndex & parent, const UINT8 mode)
const char empty, const QModelIndex & parent, const UINT8 mode)
{ {
EFI_COMMON_SECTION_HEADER* sectionHeader = (EFI_COMMON_SECTION_HEADER*) (section.constData()); EFI_COMMON_SECTION_HEADER* sectionHeader = (EFI_COMMON_SECTION_HEADER*) (section.constData());
UINT32 sectionSize = uint24ToUint32(sectionHeader->Size); UINT32 sectionSize = uint24ToUint32(sectionHeader->Size);
@ -970,6 +981,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, const UINT8 revision,
UINT8 result; UINT8 result;
QModelIndex index; QModelIndex index;
switch (sectionHeader->Type) { switch (sectionHeader->Type) {
// Encapsulated sections // Encapsulated sections
case EFI_SECTION_COMPRESSION: case EFI_SECTION_COMPRESSION:
@ -984,7 +996,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, const UINT8 revision,
// Decompress section // Decompress section
result = decompress(body, compressedSectionHeader->CompressionType, decompressed, &algorithm); result = decompress(body, compressedSectionHeader->CompressionType, decompressed, &algorithm);
if (result) { if (result) {
msg(tr("parseFile: Section decompression failed (%1)").arg(result), parent); msg(tr("parseSection: Section decompression failed (%1)").arg(result), parent);
parseCurrentSection = false; parseCurrentSection = false;
} }
@ -1000,7 +1012,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, const UINT8 revision,
// Parse decompressed data // Parse decompressed data
if (parseCurrentSection) { if (parseCurrentSection) {
result = parseSections(decompressed, revision, empty, index); result = parseSections(decompressed, index);
if (result) if (result)
return result; return result;
} }
@ -1026,7 +1038,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, const UINT8 revision,
if (result) { if (result) {
result = decompress(body, EFI_CUSTOMIZED_COMPRESSION, decompressed, &algorithm); result = decompress(body, EFI_CUSTOMIZED_COMPRESSION, decompressed, &algorithm);
if (result) { if (result) {
msg(tr("parseFile: GUID defined section can not be decompressed (%1)").arg(result), parent); msg(tr("parseSection: GUID defined section can not be decompressed (%1)").arg(result), parent);
parseCurrentSection = false; parseCurrentSection = false;
} }
} }
@ -1047,7 +1059,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, const UINT8 revision,
// Parse decompressed data // Parse decompressed data
if (parseCurrentSection) { if (parseCurrentSection) {
result = parseSections(decompressed, revision, empty, index); result = parseSections(decompressed, index);
if (result) if (result)
return result; return result;
} }
@ -1059,7 +1071,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, const UINT8 revision,
body = section.mid(sizeof(EFI_DISPOSABLE_SECTION), sectionSize - sizeof(EFI_DISPOSABLE_SECTION)); body = section.mid(sizeof(EFI_DISPOSABLE_SECTION), sectionSize - sizeof(EFI_DISPOSABLE_SECTION));
// Get info // Get info
info = tr("Type: %1\nSize: %2") info = tr("parseSection: %1\nSize: %2")
.arg(sectionHeader->Type, 2, 16, QChar('0')) .arg(sectionHeader->Type, 2, 16, QChar('0'))
.arg(body.size(), 8, 16, QChar('0')); .arg(body.size(), 8, 16, QChar('0'));
@ -1067,7 +1079,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, const UINT8 revision,
index = treeModel->addItem(TreeItem::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode); index = treeModel->addItem(TreeItem::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode);
// Parse section body // Parse section body
result = parseSections(body, revision, empty, index); result = parseSections(body, index);
if (result) if (result)
return result; return result;
} }
@ -1128,7 +1140,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, const UINT8 revision,
// Parse section body as BIOS space // Parse section body as BIOS space
result = parseBios(body, index); result = parseBios(body, index);
if (result && result != ERR_VOLUMES_NOT_FOUND) { if (result && result != ERR_VOLUMES_NOT_FOUND) {
msg(tr("parseFile: Firmware volume image can not be parsed (%1)").arg(result), index); msg(tr("parseSection: Firmware volume image can not be parsed as BIOS (%1)").arg(result), index);
return result; return result;
} }
break; break;
@ -1147,7 +1159,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, const UINT8 revision,
// Parse section body as BIOS space // Parse section body as BIOS space
result = parseBios(body, index); result = parseBios(body, index);
if (result && result != ERR_VOLUMES_NOT_FOUND) { if (result && result != ERR_VOLUMES_NOT_FOUND) {
msg(tr("parseFile: Raw section can not be parsed as BIOS (%1)").arg(result), index); msg(tr("parseSection: Raw section can not be parsed as BIOS (%1)").arg(result), index);
return result; return result;
} }
break; break;
@ -1161,7 +1173,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, const UINT8 revision,
// Add tree item // Add tree item
index = treeModel->addItem(TreeItem::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode); index = treeModel->addItem(TreeItem::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, QByteArray(), parent, mode);
msg(tr("parseFile: Section with unknown type (%1)").arg(sectionHeader->Type, 2, 16, QChar('0')), index); msg(tr("parseSection: Section with unknown type (%1)").arg(sectionHeader->Type, 2, 16, QChar('0')), index);
} }
return ERR_SUCCESS; return ERR_SUCCESS;
} }
@ -1219,14 +1231,11 @@ UINT8 FfsEngine::insert(const QModelIndex & index, const QByteArray & object, co
EFI_FIRMWARE_VOLUME_HEADER* header = (EFI_FIRMWARE_VOLUME_HEADER*) parentItem->header().constData(); EFI_FIRMWARE_VOLUME_HEADER* header = (EFI_FIRMWARE_VOLUME_HEADER*) parentItem->header().constData();
// Parse file // Parse file
UINT8 result = parseFile(object, header->Revision, header->Attributes & EFI_FVB_ERASE_POLARITY ? '\xFF' : '\x00', index, mode); UINT8 result = parseFile(object, header->Revision, ERASE_POLARITY_UNKNOWN, index, mode);
if (result) if (result)
return result; return result;
// Set rebuild action for parent
// Set reconstruct action for all it's parents treeModel->setItemAction(TreeItem::Rebuild, parent);
for (;parent.isValid(); parent = parent.parent())
treeModel->setItemAction(TreeItem::Reconstruct, parent);
} }
else if (type == TreeItem::Section) { else if (type == TreeItem::Section) {
QModelIndex parent; QModelIndex parent;
@ -1241,23 +1250,12 @@ UINT8 FfsEngine::insert(const QModelIndex & index, const QByteArray & object, co
(parentItem->subtype() == EFI_SECTION_COMPRESSION || (parentItem->subtype() == EFI_SECTION_COMPRESSION ||
parentItem->subtype() == EFI_SECTION_GUID_DEFINED || parentItem->subtype() == EFI_SECTION_GUID_DEFINED ||
parentItem->subtype() == EFI_SECTION_DISPOSABLE))) { parentItem->subtype() == EFI_SECTION_DISPOSABLE))) {
QModelIndex volumeIndex = findParentOfType(TreeItem::Volume, parent);
if (!volumeIndex.isValid()) {
msg(tr("insert: Parent volume not found"), parent);
return ERR_INVALID_VOLUME;
}
TreeItem * volumeItem = static_cast<TreeItem*>(volumeIndex.internalPointer());
EFI_FIRMWARE_VOLUME_HEADER* header = (EFI_FIRMWARE_VOLUME_HEADER*) volumeItem->header().constData();
// Parse section // Parse section
UINT8 result = parseSection(object, header->Revision, header->Attributes & EFI_FVB_ERASE_POLARITY ? '\xFF' : '\x00', index, mode); UINT8 result = parseSection(object, index, mode);
if (result) if (result)
return result; return result;
// Set rebuild action for parent
// Set reconstruct action for all parents treeModel->setItemAction(TreeItem::Rebuild, parent);
for (;parent.isValid(); parent = parent.parent())
treeModel->setItemAction(TreeItem::Reconstruct, parent);
} }
else { else {
msg(tr("insert: section can't be inserted into something that is not file or encapsulation section"), parent); msg(tr("insert: section can't be inserted into something that is not file or encapsulation section"), parent);
@ -1278,9 +1276,27 @@ UINT8 FfsEngine::remove(const QModelIndex & index)
// Set action for the item // Set action for the item
treeModel->setItemAction(TreeItem::Remove, index); treeModel->setItemAction(TreeItem::Remove, index);
// Set reconstruct action for all it's parents return ERR_SUCCESS;
for (QModelIndex parent = index.parent(); parent.isValid(); parent = parent.parent()) }
treeModel->setItemAction(TreeItem::Reconstruct, parent);
UINT8 FfsEngine::rebuild(const QModelIndex & index)
{
if (!index.isValid())
return ERR_INVALID_PARAMETER;
// Set action for the item
treeModel->setItemAction(TreeItem::Rebuild, index);
return ERR_SUCCESS;
}
UINT8 FfsEngine::changeCompression(const QModelIndex & index, const UINT8 algorithm)
{
if (!index.isValid())
return ERR_INVALID_PARAMETER;
// Set action for the item
treeModel->setItemCompression(algorithm, index);
return ERR_SUCCESS; return ERR_SUCCESS;
} }
@ -1512,21 +1528,26 @@ UINT8 FfsEngine::reconstructImage(QByteArray & reconstructed)
return ERR_SUCCESS; return ERR_SUCCESS;
} }
UINT8 FfsEngine::constructPadFile(const UINT32 size, const UINT8 revision, const char empty, QByteArray & pad) UINT8 FfsEngine::constructPadFile(const UINT32 size, const UINT8 revision, const UINT8 erasePolarity, QByteArray & pad)
{ {
if (size < sizeof(EFI_FFS_FILE_HEADER)) if (size < sizeof(EFI_FFS_FILE_HEADER) || erasePolarity == ERASE_POLARITY_UNKNOWN)
return ERR_INVALID_PARAMETER; return ERR_INVALID_PARAMETER;
pad = QByteArray(size, empty); pad = QByteArray(size, erasePolarity == ERASE_POLARITY_TRUE ? '\xFF' : '\x00');
EFI_FFS_FILE_HEADER* header = (EFI_FFS_FILE_HEADER*) pad.data(); EFI_FFS_FILE_HEADER* header = (EFI_FFS_FILE_HEADER*) pad.data();
uint32ToUint24(size, header->Size); uint32ToUint24(size, header->Size);
header->Attributes = 0x00; header->Attributes = 0x00;
header->Type = EFI_FV_FILETYPE_PAD; header->Type = EFI_FV_FILETYPE_PAD;
header->State = 0xF8; //TODO: Check state of pad file in section with empty = 0x00 header->State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID;
// Invert state bits if erase polarity is true
if (erasePolarity == ERASE_POLARITY_TRUE)
header->State = ~header->State;
// Calculate header checksum // Calculate header checksum
header->IntegrityCheck.Checksum.Header = 0; header->IntegrityCheck.Checksum.Header = 0;
header->IntegrityCheck.Checksum.File = 0; header->IntegrityCheck.Checksum.File = 0;
header->IntegrityCheck.Checksum.Header = calculateChecksum8((UINT8*) header, sizeof(EFI_FFS_FILE_HEADER) - 1); header->IntegrityCheck.Checksum.Header = calculateChecksum8((UINT8*) header, sizeof(EFI_FFS_FILE_HEADER) - 1);
// Set data checksum // Set data checksum
if (revision == 1) if (revision == 1)
header->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM; header->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;
@ -1536,14 +1557,17 @@ UINT8 FfsEngine::constructPadFile(const UINT32 size, const UINT8 revision, const
return ERR_SUCCESS; return ERR_SUCCESS;
} }
UINT8 FfsEngine::reconstruct(const QModelIndex & index, QQueue<QByteArray> & queue, const UINT8 revision, char empty) UINT8 FfsEngine::reconstruct(const QModelIndex & index, QQueue<QByteArray> & queue, const UINT8 revision, const UINT8 erasePolarity)
{ {
if (!index.isValid()) if (!index.isValid())
return ERR_SUCCESS; return ERR_SUCCESS;
TreeItem* item = static_cast<TreeItem*>(index.internalPointer());
if (item == rootItem)
return ERR_SUCCESS;
QByteArray reconstructed; QByteArray reconstructed;
UINT8 result; UINT8 result;
TreeItem* item = static_cast<TreeItem*>(index.internalPointer());
// No action is needed, just return header + body // No action is needed, just return header + body
if (item->action() == TreeItem::NoAction) { if (item->action() == TreeItem::NoAction) {
@ -1553,13 +1577,10 @@ UINT8 FfsEngine::reconstruct(const QModelIndex & index, QQueue<QByteArray> & que
} }
// Remove item // Remove item
else if (item->action() == TreeItem::Remove) { else if (item->action() == TreeItem::Remove) {
// Root item can't be removed
if (item == rootItem)
return ERR_INVALID_PARAMETER;
// Volume can be removed by replacing all it's contents with empty bytes // Volume can be removed by replacing all it's contents with empty bytes
if (item->type() == TreeItem::Volume) { if (item->type() == TreeItem::Volume) {
EFI_FIRMWARE_VOLUME_HEADER* volumeHeader = (EFI_FIRMWARE_VOLUME_HEADER*) item->header().constData(); EFI_FIRMWARE_VOLUME_HEADER* volumeHeader = (EFI_FIRMWARE_VOLUME_HEADER*) item->header().constData();
empty = volumeHeader->Attributes & EFI_FVB_ERASE_POLARITY ? '\xFF' : '\x00'; char empty = volumeHeader->Attributes & EFI_FVB_ERASE_POLARITY ? '\xFF' : '\x00';
reconstructed.fill(empty, item->header().size() + item->body().size() + item->tail().size()); reconstructed.fill(empty, item->header().size() + item->body().size() + item->tail().size());
queue.enqueue(reconstructed); queue.enqueue(reconstructed);
return ERR_SUCCESS; return ERR_SUCCESS;
@ -1577,7 +1598,7 @@ UINT8 FfsEngine::reconstruct(const QModelIndex & index, QQueue<QByteArray> & que
return ERR_NOT_IMPLEMENTED; return ERR_NOT_IMPLEMENTED;
} }
// Reconstruct item and it's children recursive // Reconstruct item and it's children recursive
else if (item->action() == TreeItem::Reconstruct) { else if (item->action() == TreeItem::Rebuild) {
QQueue<QByteArray> childrenQueue; QQueue<QByteArray> childrenQueue;
switch (item->type()) { switch (item->type()) {
@ -1608,6 +1629,7 @@ UINT8 FfsEngine::reconstruct(const QModelIndex & index, QQueue<QByteArray> & que
UINT32 offset = descriptor.size(); UINT32 offset = descriptor.size();
// Reconstruct other regions // Reconstruct other regions
char empty = '\xFF'; //!TODO: determine empty char using one of reserved descriptor fields
for (int i = 1; i < item->childCount(); i++) { for (int i = 1; i < item->childCount(); i++) {
result = reconstruct(index.child(i, index.column()), childrenQueue); result = reconstruct(index.child(i, index.column()), childrenQueue);
if (result) if (result)
@ -1650,6 +1672,7 @@ UINT8 FfsEngine::reconstruct(const QModelIndex & index, QQueue<QByteArray> & que
if ((UINT32)item->body().size() > offset) if ((UINT32)item->body().size() > offset)
reconstructed.append(QByteArray((UINT32)item->body().size() - offset, empty)); reconstructed.append(QByteArray((UINT32)item->body().size() - offset, empty));
// Check size of reconstructed image, it must be same
if (reconstructed.size() > item->body().size()) { if (reconstructed.size() > item->body().size()) {
msg(tr("reconstruct: reconstructed body %1 is bigger then original %2") msg(tr("reconstruct: reconstructed body %1 is bigger then original %2")
.arg(reconstructed.size(), 8, 16, QChar('0')) .arg(reconstructed.size(), 8, 16, QChar('0'))
@ -1690,7 +1713,7 @@ UINT8 FfsEngine::reconstruct(const QModelIndex & index, QQueue<QByteArray> & que
else else
reconstructed = item->body(); reconstructed = item->body();
// Check size of reconstructed image, it must be the same // Check size of reconstructed image, it must be same
if (item->type() != TreeItem::Root) { if (item->type() != TreeItem::Root) {
if (reconstructed.size() > item->body().size()) { if (reconstructed.size() > item->body().size()) {
msg(tr("reconstructed: reconstructed body %1 is bigger then original %2") msg(tr("reconstructed: reconstructed body %1 is bigger then original %2")
@ -1715,14 +1738,21 @@ UINT8 FfsEngine::reconstruct(const QModelIndex & index, QQueue<QByteArray> & que
{ {
//!TODO: add check for weak aligned volumes //!TODO: add check for weak aligned volumes
QByteArray header = item->header(); QByteArray header = item->header();
EFI_FIRMWARE_VOLUME_HEADER* volumeHeader = (EFI_FIRMWARE_VOLUME_HEADER*) header.constData(); EFI_FIRMWARE_VOLUME_HEADER* volumeHeader = (EFI_FIRMWARE_VOLUME_HEADER*) header.data();
empty = volumeHeader->Attributes & EFI_FVB_ERASE_POLARITY ? '\xFF' : '\x00';
// Recalculate volume header checksum
volumeHeader->Checksum = 0;
volumeHeader->Checksum = calculateChecksum16((UINT8*) volumeHeader, volumeHeader->HeaderLength);
// Reconstruct volume body // Reconstruct volume body
if (item->childCount()) { if (item->childCount()) {
UINT8 polarity = volumeHeader->Attributes & EFI_FVB_ERASE_POLARITY ? ERASE_POLARITY_TRUE : ERASE_POLARITY_FALSE;
char empty = volumeHeader->Attributes & EFI_FVB_ERASE_POLARITY ? '\xFF' : '\x00';
// Reconstruct files in volume // Reconstruct files in volume
for (int i = 0; i < item->childCount(); i++) { for (int i = 0; i < item->childCount(); i++) {
// Reconstruct files // Reconstruct files
result = reconstruct(index.child(i, index.column()), childrenQueue, volumeHeader->Revision, empty); result = reconstruct(index.child(i, index.column()), childrenQueue, volumeHeader->Revision, polarity);
if (result) if (result)
return result; return result;
} }
@ -1773,7 +1803,7 @@ UINT8 FfsEngine::reconstruct(const QModelIndex & index, QQueue<QByteArray> & que
} }
// Construct pad file // Construct pad file
QByteArray pad; QByteArray pad;
result = constructPadFile(size, revision, empty, pad); result = constructPadFile(size, revision, polarity, pad);
if (result) if (result)
return result; return result;
// Append constructed pad file to volume body // Append constructed pad file to volume body
@ -1799,7 +1829,7 @@ UINT8 FfsEngine::reconstruct(const QModelIndex & index, QQueue<QByteArray> & que
UINT32 size = vtfOffset - offset; UINT32 size = vtfOffset - offset;
// Construct pad file // Construct pad file
QByteArray pad; QByteArray pad;
result = constructPadFile(size, revision, empty, pad); result = constructPadFile(size, revision, polarity, pad);
if (result) if (result)
return result; return result;
// Append constructed pad file to volume body // Append constructed pad file to volume body
@ -1828,7 +1858,7 @@ UINT8 FfsEngine::reconstruct(const QModelIndex & index, QQueue<QByteArray> & que
} }
// Construct pad file // Construct pad file
QByteArray pad; QByteArray pad;
result = constructPadFile(vtfOffset - offset, revision, empty, pad); result = constructPadFile(vtfOffset - offset, revision, polarity, pad);
if (result) if (result)
return result; return result;
// Append constructed pad file to volume body // Append constructed pad file to volume body
@ -1891,6 +1921,59 @@ UINT8 FfsEngine::reconstruct(const QModelIndex & index, QQueue<QByteArray> & que
QByteArray header = item->header(); QByteArray header = item->header();
EFI_FFS_FILE_HEADER* fileHeader = (EFI_FFS_FILE_HEADER*) header.data(); EFI_FFS_FILE_HEADER* fileHeader = (EFI_FFS_FILE_HEADER*) header.data();
// Check erase polarity
if (erasePolarity == ERASE_POLARITY_UNKNOWN) {
msg(tr("reconstruct: %1, unknown erase polarity").arg(guidToQString(fileHeader->Name)), index);
return ERR_INVALID_PARAMETER;
}
// Construct empty char for this file
char empty = erasePolarity == ERASE_POLARITY_TRUE ? '\xFF' : '\x00';
// Check file state
// Invert it first if erase polarity is true
UINT8 state = fileHeader->State;
if (erasePolarity == ERASE_POLARITY_TRUE)
state = ~state;
// Order of this checks must be preserved
// Check file to have valid state, or delete it otherwise
if (state & EFI_FILE_HEADER_INVALID) {
// File marked to have invalid header and must be deleted
// Do not add anything to queue
msg(tr("reconstruct: %1, file is HEADER_INVALID state, and will be removed from reconstructed image")
.arg(guidToQString(fileHeader->Name)), index);
return ERR_SUCCESS;
}
else if (state & EFI_FILE_DELETED) {
// File marked to have been deleted form and must be deleted
// Do not add anything to queue
msg(tr("reconstruct: %1, file is in DELETED state, and will be removed from reconstructed image")
.arg(guidToQString(fileHeader->Name)), index);
return ERR_SUCCESS;
}
else if (state & EFI_FILE_MARKED_FOR_UPDATE) {
// File is marked for update, the mark must be removed
msg(tr("reconstruct: %1, file MARKED_FOR_UPDATE state cleared")
.arg(guidToQString(fileHeader->Name)), index);
state &= ~EFI_FILE_MARKED_FOR_UPDATE;
}
else if (state & EFI_FILE_DATA_VALID) {
// File is in good condition, reconstruct it
}
else if (state & EFI_FILE_HEADER_VALID) {
// Header is valid, but data is not, so file must be deleted
msg(tr("reconstruct: %1, file is in HEADER_VALID (but not in DATA_VALID) state, and will be removed from reconstructed image")
.arg(guidToQString(fileHeader->Name)), index);
return ERR_SUCCESS;
}
else if (state & EFI_FILE_HEADER_CONSTRUCTION) {
// Header construction not finished, so file must be deleted
msg(tr("reconstruct: %1, file is in HEADER_CONSTRUCTION (but not in DATA_VALID) state, and will be removed from reconstructed image")
.arg(guidToQString(fileHeader->Name)), index);
return ERR_SUCCESS;
}
// Reconstruct file body // Reconstruct file body
if (item->childCount()) { if (item->childCount()) {
for (int i = 0; i < item->childCount(); i++) { for (int i = 0; i < item->childCount(); i++) {
@ -1931,6 +2014,11 @@ UINT8 FfsEngine::reconstruct(const QModelIndex & index, QQueue<QByteArray> & que
fileHeader->IntegrityCheck.Checksum.File = 0; fileHeader->IntegrityCheck.Checksum.File = 0;
fileHeader->IntegrityCheck.Checksum.Header = calculateChecksum8((UINT8*) fileHeader, sizeof(EFI_FFS_FILE_HEADER) - 1); fileHeader->IntegrityCheck.Checksum.Header = calculateChecksum8((UINT8*) fileHeader, sizeof(EFI_FFS_FILE_HEADER) - 1);
}
// Use current file body
else
reconstructed = item->body();
// Recalculate data checksum, if needed // Recalculate data checksum, if needed
if (fileHeader->Attributes & FFS_ATTRIB_CHECKSUM) { if (fileHeader->Attributes & FFS_ATTRIB_CHECKSUM) {
fileHeader->IntegrityCheck.Checksum.File = calculateChecksum8((UINT8*) reconstructed.constData(), reconstructed.size()); fileHeader->IntegrityCheck.Checksum.File = calculateChecksum8((UINT8*) reconstructed.constData(), reconstructed.size());
@ -1941,12 +2029,13 @@ UINT8 FfsEngine::reconstruct(const QModelIndex & index, QQueue<QByteArray> & que
fileHeader->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM2; fileHeader->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM2;
// Append tail, if needed // Append tail, if needed
if (tailSize) if (!item->hasEmptyTail())
reconstructed.append(!fileHeader->IntegrityCheck.TailReference); reconstructed.append(!fileHeader->IntegrityCheck.TailReference);
}
// Use current file body and tail // Set file state
else state = EFI_FILE_DATA_VALID | EFI_FILE_HEADER_VALID | EFI_FILE_HEADER_CONSTRUCTION;
reconstructed = item->body().append(item->tail()); if (erasePolarity == ERASE_POLARITY_TRUE)
state = ~state;
// Enqueue reconstructed item // Enqueue reconstructed item
queue.enqueue(header.append(reconstructed)); queue.enqueue(header.append(reconstructed));
@ -1963,7 +2052,7 @@ UINT8 FfsEngine::reconstruct(const QModelIndex & index, QQueue<QByteArray> & que
// Reconstruct section body // Reconstruct section body
for (int i = 0; i < item->childCount(); i++) { for (int i = 0; i < item->childCount(); i++) {
// Reconstruct subsections // Reconstruct subsections
result = reconstruct(index.child(i, index.column()), childrenQueue, revision, empty); result = reconstruct(index.child(i, index.column()), childrenQueue);
if (result) if (result)
return result; return result;
} }
@ -1977,7 +2066,7 @@ UINT8 FfsEngine::reconstruct(const QModelIndex & index, QQueue<QByteArray> & que
if (alignment) { if (alignment) {
alignment = 4 - alignment; alignment = 4 - alignment;
offset += alignment; offset += alignment;
reconstructed.append(QByteArray(alignment, empty)); reconstructed.append(QByteArray(alignment, '\x00'));
} }
// Get section from queue // Get section from queue
@ -1985,6 +2074,7 @@ UINT8 FfsEngine::reconstruct(const QModelIndex & index, QQueue<QByteArray> & que
// Append current subsection to new section body // Append current subsection to new section body
reconstructed.append(section); reconstructed.append(section);
// Change current file offset // Change current file offset
offset += section.size(); offset += section.size();
} }
@ -2049,6 +2139,65 @@ UINT8 FfsEngine::reconstruct(const QModelIndex & index, QQueue<QByteArray> & que
return ERR_SUCCESS; return ERR_SUCCESS;
} }
/*// Compress object with new compression algorithm
else if (item->action() == TreeItem::EfiCompress || item->action() == TreeItem::TianoCompress || item->action() == TreeItem::LzmaCompress) {
// Select algorithm
UINT8 algorithm;
if (item->action() == TreeItem::EfiCompress)
algorithm = COMPRESSION_ALGORITHM_EFI11;
else if (item->action() == TreeItem::TianoCompress)
algorithm = COMPRESSION_ALGORITHM_TIANO;
else if (item->action() == TreeItem::LzmaCompress)
algorithm = COMPRESSION_ALGORITHM_LZMA;
else
return ERR_UNKNOWN_COMPRESSION_ALGORITHM;
// Possible only for compressed sections with EFI1.1, Tiano or LZMA algorithm
if (item->type() == TreeItem::Section && item->subtype() == EFI_SECTION_COMPRESSION &&
(item->compression() == COMPRESSION_ALGORITHM_EFI11 || item->compression() == COMPRESSION_ALGORITHM_TIANO || item->compression() == COMPRESSION_ALGORITHM_LZMA)) {
QByteArray header = item->header();
EFI_COMPRESSION_SECTION* sectionHeader = (EFI_COMPRESSION_SECTION*) header.data();
if (!item->childCount())
return ERR_INVALID_SECTION;
QQueue<QByteArray> childrenQueue;
for (int i = 0; i < item->childCount(); i++) {
// Reconstruct subsections
result = reconstruct(index.child(i, index.column()), childrenQueue);
if (result)
return result;
}
// Construct new section body
UINT32 offset = 0;
while (!childrenQueue.isEmpty())
{
// Align to 4 byte boundary
UINT8 alignment = offset % 4;
if (alignment) {
alignment = 4 - alignment;
offset += alignment;
reconstructed.append(QByteArray(alignment, '\x00'));
}
// Get section from queue
QByteArray section = childrenQueue.dequeue();
// Append current subsection to new section body
reconstructed.append(section);
// Change current file offset
offset += section.size();
}
// Compress new section body using determined compression algorithm
}
else
return ERR_NOT_IMPLEMENTED;
}*/
return ERR_NOT_IMPLEMENTED; return ERR_NOT_IMPLEMENTED;
} }
@ -2093,82 +2242,82 @@ UINT8 FfsEngine::growVolume(QByteArray & header, const UINT32 size, UINT32 & new
// Will be refactored later // Will be refactored later
/*QByteArray FfsEngine::decompressFile(const QModelIndex& index) const /*QByteArray FfsEngine::decompressFile(const QModelIndex& index) const
{ {
if (!index.isValid()) if (!index.isValid())
return QByteArray(); return QByteArray();
// Check index item to be FFS file // Check index item to be FFS file
TreeItem *item = static_cast<TreeItem*>(index.internalPointer()); TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
if(item->type() != TreeItem::File) if(item->type() != TreeItem::File)
return QByteArray(); return QByteArray();
QByteArray file; QByteArray file;
UINT32 offset = 0; UINT32 offset = 0;
// Construct new item body // Construct new item body
for (int i = 0; i < item->childCount(); i++) { for (int i = 0; i < item->childCount(); i++) {
// If section is not compressed, add it to new body as is // If section is not compressed, add it to new body as is
TreeItem* sectionItem = item->child(i); TreeItem* sectionItem = item->child(i);
if (sectionItem->subtype() != EFI_SECTION_COMPRESSION) { if (sectionItem->subtype() != EFI_SECTION_COMPRESSION) {
QByteArray section = sectionItem->header().append(sectionItem->body()); QByteArray section = sectionItem->header().append(sectionItem->body());
UINT32 align = ALIGN4(offset) - offset; UINT32 align = ALIGN4(offset) - offset;
file.append(QByteArray(align, '\x00')).append(section); file.append(QByteArray(align, '\x00')).append(section);
offset += align + section.size(); offset += align + section.size();
} }
else { else {
// Construct new section body by adding all child sections to this new section // Construct new section body by adding all child sections to this new section
QByteArray section; QByteArray section;
UINT32 subOffset = 0; UINT32 subOffset = 0;
for (int j = 0; j < sectionItem->childCount(); j++) for (int j = 0; j < sectionItem->childCount(); j++)
{ {
TreeItem* subSectionItem = sectionItem->child(j); TreeItem* subSectionItem = sectionItem->child(j);
QByteArray subSection = subSectionItem->header().append(subSectionItem->body()); QByteArray subSection = subSectionItem->header().append(subSectionItem->body());
UINT32 align = ALIGN4(subOffset) - subOffset; UINT32 align = ALIGN4(subOffset) - subOffset;
section.append(QByteArray(align, '\x00')).append(subSection); section.append(QByteArray(align, '\x00')).append(subSection);
subOffset += align + subSection.size(); subOffset += align + subSection.size();
} }
// Add newly constructed section to file body // Add newly constructed section to file body
EFI_COMPRESSION_SECTION sectionHeader; EFI_COMPRESSION_SECTION sectionHeader;
sectionHeader.Type = EFI_SECTION_COMPRESSION; sectionHeader.Type = EFI_SECTION_COMPRESSION;
sectionHeader.CompressionType = EFI_NOT_COMPRESSED; sectionHeader.CompressionType = EFI_NOT_COMPRESSED;
sectionHeader.UncompressedLength = section.size(); sectionHeader.UncompressedLength = section.size();
uint32ToUint24(section.size() + sizeof(EFI_COMPRESSION_SECTION), sectionHeader.Size); uint32ToUint24(section.size() + sizeof(EFI_COMPRESSION_SECTION), sectionHeader.Size);
UINT32 align = ALIGN4(offset) - offset; UINT32 align = ALIGN4(offset) - offset;
file.append(QByteArray(align, '\x00')) file.append(QByteArray(align, '\x00'))
.append(QByteArray((const char*) &sectionHeader, sizeof(EFI_COMPRESSION_SECTION))) .append(QByteArray((const char*) &sectionHeader, sizeof(EFI_COMPRESSION_SECTION)))
.append(section); .append(section);
offset += align + section.size(); offset += align + section.size();
} }
} }
QByteArray header = item->header(); QByteArray header = item->header();
EFI_FFS_FILE_HEADER* fileHeader = (EFI_FFS_FILE_HEADER*) header.data(); EFI_FFS_FILE_HEADER* fileHeader = (EFI_FFS_FILE_HEADER*) header.data();
// Correct file data checksum, if needed // Correct file data checksum, if needed
if (fileHeader->Attributes & FFS_ATTRIB_CHECKSUM) { if (fileHeader->Attributes & FFS_ATTRIB_CHECKSUM) {
UINT32 bufferSize = file.size() - sizeof(EFI_FFS_FILE_HEADER); UINT32 bufferSize = file.size() - sizeof(EFI_FFS_FILE_HEADER);
fileHeader->IntegrityCheck.Checksum.File = calculateChecksum8((UINT8*)(file.data() + sizeof(EFI_FFS_FILE_HEADER)), bufferSize); fileHeader->IntegrityCheck.Checksum.File = calculateChecksum8((UINT8*)(file.data() + sizeof(EFI_FFS_FILE_HEADER)), bufferSize);
} }
// Add file tail, if needed // Add file tail, if needed
if(fileHeader->Attributes & FFS_ATTRIB_TAIL_PRESENT) if(fileHeader->Attributes & FFS_ATTRIB_TAIL_PRESENT)
file.append(!fileHeader->IntegrityCheck.TailReference); file.append(!fileHeader->IntegrityCheck.TailReference);
return header.append(file); return header.append(file);
}*/ }*/
/*bool FfsEngine::isCompressedFile(const QModelIndex& index) const /*bool FfsEngine::isCompressedFile(const QModelIndex& index) const
{ {
if (!index.isValid()) if (!index.isValid())
return false; return false;
TreeItem *item = static_cast<TreeItem*>(index.internalPointer()); TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
if(item->type() != TreeItem::File) if(item->type() != TreeItem::File)
return false; return false;
for (int i = 0; i < item->childCount(); i++) { for (int i = 0; i < item->childCount(); i++) {
if (item->child(i)->subtype() == EFI_SECTION_COMPRESSION) if (item->child(i)->subtype() == EFI_SECTION_COMPRESSION)
return true; return true;
} }
return false; return false;
}*/ }*/

View File

@ -52,10 +52,10 @@ public:
UINT8 getVolumeSize(const QByteArray & bios, const UINT32 volumeOffset, UINT32 & volumeSize); UINT8 getVolumeSize(const QByteArray & bios, const UINT32 volumeOffset, UINT32 & volumeSize);
UINT8 parseVolume(const QByteArray & volume, const QModelIndex & parent = QModelIndex(), const UINT8 mode = INSERT_MODE_APPEND); UINT8 parseVolume(const QByteArray & volume, const QModelIndex & parent = QModelIndex(), const UINT8 mode = INSERT_MODE_APPEND);
UINT8 getFileSize(const QByteArray & volume, const UINT32 fileOffset, UINT32 & fileSize); UINT8 getFileSize(const QByteArray & volume, const UINT32 fileOffset, UINT32 & fileSize);
UINT8 parseFile(const QByteArray & file, const UINT8 revision, const char empty = '\xFF', const QModelIndex & parent = QModelIndex(), const UINT8 mode = INSERT_MODE_APPEND); UINT8 parseFile(const QByteArray & file, const UINT8 revision, const UINT8 erasePolarity = ERASE_POLARITY_UNKNOWN, const QModelIndex & parent = QModelIndex(), const UINT8 mode = INSERT_MODE_APPEND);
UINT8 getSectionSize(const QByteArray & file, const UINT32 sectionOffset, UINT32 & sectionSize); UINT8 getSectionSize(const QByteArray & file, const UINT32 sectionOffset, UINT32 & sectionSize);
UINT8 parseSections(const QByteArray & body, const UINT8 revision, const char empty = '\xFF', const QModelIndex & parent = QModelIndex()); UINT8 parseSections(const QByteArray & body, const QModelIndex & parent = QModelIndex());
UINT8 parseSection(const QByteArray & section, const UINT8 revision, const char empty = '\xFF', const QModelIndex & parent = QModelIndex(), const UINT8 mode = INSERT_MODE_APPEND); UINT8 parseSection(const QByteArray & section, const QModelIndex & parent = QModelIndex(), const UINT8 mode = INSERT_MODE_APPEND);
// Compression routines // Compression routines
UINT8 decompress(const QByteArray & compressed, const UINT8 compressionType, QByteArray & decompressedData, UINT8 * algorithm = NULL); UINT8 decompress(const QByteArray & compressed, const UINT8 compressionType, QByteArray & decompressedData, UINT8 * algorithm = NULL);
@ -63,14 +63,16 @@ public:
// Construction routines // Construction routines
UINT8 reconstructImage(QByteArray & reconstructed); UINT8 reconstructImage(QByteArray & reconstructed);
UINT8 constructPadFile(const UINT32 size, const UINT8 revision, const char empty, QByteArray & pad); UINT8 constructPadFile(const UINT32 size, const UINT8 revision, const UINT8 erasePolarity, QByteArray & pad);
UINT8 reconstruct(const QModelIndex & index, QQueue<QByteArray> & queue, const UINT8 revision = 2, char empty = '\xFF'); UINT8 reconstruct(const QModelIndex & index, QQueue<QByteArray> & queue, const UINT8 revision = 2, const UINT8 erasePolarity = ERASE_POLARITY_UNKNOWN);
UINT8 growVolume(QByteArray & header, const UINT32 size, UINT32 & newSize); UINT8 growVolume(QByteArray & header, const UINT32 size, UINT32 & newSize);
// Operations on tree items // Operations on tree items
UINT8 extract(const QModelIndex & index, QByteArray & extracted, const UINT8 mode); UINT8 extract(const QModelIndex & index, QByteArray & extracted, const UINT8 mode);
UINT8 insert(const QModelIndex & index, const QByteArray & object, const UINT8 objectType, const UINT8 mode); UINT8 insert(const QModelIndex & index, const QByteArray & object, const UINT8 objectType, const UINT8 mode);
UINT8 remove(const QModelIndex & index); UINT8 remove(const QModelIndex & index);
UINT8 rebuild(const QModelIndex & index);
UINT8 changeCompression(const QModelIndex & index, const UINT8 algorithm);
private: private:
TreeItem *rootItem; TreeItem *rootItem;

View File

@ -174,7 +174,7 @@ QVariant TreeItem::data(int column) const
case 1: //Action case 1: //Action
if (itemAction == TreeItem::Remove) if (itemAction == TreeItem::Remove)
return "X"; return "X";
if (itemAction == TreeItem::Reconstruct) if (itemAction == TreeItem::Rebuild)
return "R"; return "R";
return QVariant(); return QVariant();
case 2: //Type case 2: //Type
@ -261,7 +261,6 @@ QByteArray TreeItem::tail() const
return itemTail; return itemTail;
} }
bool TreeItem::hasEmptyHeader() const bool TreeItem::hasEmptyHeader() const
{ {
return itemHeader.isEmpty(); return itemHeader.isEmpty();
@ -281,7 +280,20 @@ UINT8 TreeItem::action() const
{ {
return itemAction; return itemAction;
} }
void TreeItem::setAction(const UINT8 action) void TreeItem::setAction(const UINT8 action)
{ {
itemAction = action; itemAction = action;
// Set rebuild action for parent
if (parentItem)
parentItem->setAction(TreeItem::Rebuild);
}
void TreeItem::setCompression(const UINT8 algorithm)
{
itemCompression = algorithm;
// Set rebuild action
setAction(TreeItem::Rebuild);
} }

View File

@ -32,7 +32,7 @@ public:
enum ActionTypes { enum ActionTypes {
NoAction = 50, NoAction = 50,
Remove, Remove,
Reconstruct Rebuild
}; };
// Item types // Item types
@ -100,11 +100,13 @@ public:
QByteArray tail() const; QByteArray tail() const;
bool hasEmptyTail() const; bool hasEmptyTail() const;
QString info() const; QString info() const;
UINT8 action() const;
UINT8 compression() const; UINT8 compression() const;
// Actions can also be changed // Action can be changed
UINT8 action() const;
void setAction(const UINT8 action); void setAction(const UINT8 action);
// Compression can be changed
void setCompression(const UINT8 algorithm);
// Text values can be changed after item construction // Text values can be changed after item construction
void setTypeName(const QString &text); void setTypeName(const QString &text);
@ -123,6 +125,7 @@ private:
UINT8 itemType; UINT8 itemType;
UINT8 itemSubtype; UINT8 itemSubtype;
UINT8 itemCompression; UINT8 itemCompression;
UINT8 itemNewCompression;
QByteArray itemHeader; QByteArray itemHeader;
QByteArray itemBody; QByteArray itemBody;
QByteArray itemTail; QByteArray itemTail;

View File

@ -148,7 +148,18 @@ UINT8 TreeModel::setItemAction(const UINT8 action, const QModelIndex &index)
TreeItem *item = static_cast<TreeItem*>(index.internalPointer()); TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
item->setAction(action); item->setAction(action);
emit dataChanged(index, index); emit dataChanged(this->index(0,0), index);
return ERR_SUCCESS;
}
UINT8 TreeModel::setItemCompression(const UINT8 algorithm, const QModelIndex &index)
{
if(!index.isValid())
return ERR_INVALID_PARAMETER;
TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
item->setCompression(algorithm);
emit dataChanged(this->index(0,0), index);
return ERR_SUCCESS; return ERR_SUCCESS;
} }

View File

@ -44,6 +44,7 @@ public:
UINT8 setItemName(const QString &data, const QModelIndex &index); UINT8 setItemName(const QString &data, const QModelIndex &index);
UINT8 setItemText(const QString &data, const QModelIndex &index); UINT8 setItemText(const QString &data, const QModelIndex &index);
UINT8 setItemAction(const UINT8 action, const QModelIndex &index); UINT8 setItemAction(const UINT8 action, const QModelIndex &index);
UINT8 setItemCompression(const UINT8 algorithm, const QModelIndex &index);
QModelIndex addItem(const UINT8 type, const UINT8 subtype = 0, const UINT8 compression = COMPRESSION_ALGORITHM_NONE, QModelIndex addItem(const UINT8 type, const UINT8 subtype = 0, const UINT8 compression = COMPRESSION_ALGORITHM_NONE,
const QString & name = QString(), const QString & text = QString(), const QString & info = QString(), const QString & name = QString(), const QString & text = QString(), const QString & info = QString(),

View File

@ -31,8 +31,14 @@ UEFITool::UEFITool(QWidget *parent) :
connect(ui->actionInsertAfter, SIGNAL(triggered()), this, SLOT(insertAfter())); connect(ui->actionInsertAfter, SIGNAL(triggered()), this, SLOT(insertAfter()));
connect(ui->actionReplace, SIGNAL(triggered()), this, SLOT(replace())); connect(ui->actionReplace, SIGNAL(triggered()), this, SLOT(replace()));
connect(ui->actionRemove, SIGNAL(triggered()), this, SLOT(remove())); connect(ui->actionRemove, SIGNAL(triggered()), this, SLOT(remove()));
connect(ui->actionRebuild, SIGNAL(triggered()), this, SLOT(rebuild()));
connect(ui->actionSaveImageFile, SIGNAL(triggered()), this, SLOT(saveImageFile())); connect(ui->actionSaveImageFile, SIGNAL(triggered()), this, SLOT(saveImageFile()));
connect(ui->actionChangeToEfi11, SIGNAL(triggered()), this, SLOT(changeToEfi11()));
connect(ui->actionChangeToTiano, SIGNAL(triggered()), this, SLOT(changeToTiano()));
connect(ui->actionChangeToLzma, SIGNAL(triggered()), this, SLOT(changeToLzma()));
connect(ui->actionAbout, SIGNAL(triggered()), this, SLOT(about()));
connect(ui->actionAboutQt, SIGNAL(triggered()), this, SLOT(aboutQt()));
connect(ui->actionQuit, SIGNAL(triggered()), this, SLOT(exit()));
// Enable Drag-and-Drop actions // Enable Drag-and-Drop actions
this->setAcceptDrops(true); this->setAcceptDrops(true);
@ -58,6 +64,7 @@ void UEFITool::init()
ui->actionExtractUncompressed->setDisabled(true); ui->actionExtractUncompressed->setDisabled(true);
ui->actionReplace->setDisabled(true); ui->actionReplace->setDisabled(true);
ui->actionRemove->setDisabled(true); ui->actionRemove->setDisabled(true);
ui->actionRebuild->setDisabled(true);
ui->actionInsertInto->setDisabled(true); ui->actionInsertInto->setDisabled(true);
ui->actionInsertBefore->setDisabled(true); ui->actionInsertBefore->setDisabled(true);
ui->actionInsertAfter->setDisabled(true); ui->actionInsertAfter->setDisabled(true);
@ -87,9 +94,11 @@ void UEFITool::populateUi(const QModelIndex &current)
TreeItem* item = static_cast<TreeItem*>(current.internalPointer()); TreeItem* item = static_cast<TreeItem*>(current.internalPointer());
UINT8 type = item->type(); UINT8 type = item->type();
UINT8 subtype = item->subtype(); UINT8 subtype = item->subtype();
UINT8 algorithm = item->compression();
ui->infoEdit->setPlainText(item->info()); ui->infoEdit->setPlainText(item->info());
ui->actionExtract->setDisabled(item->hasEmptyHeader() && item->hasEmptyBody() && item->hasEmptyTail()); ui->actionExtract->setDisabled(item->hasEmptyHeader() && item->hasEmptyBody() && item->hasEmptyTail());
ui->actionRebuild->setDisabled(item->hasEmptyHeader() && item->hasEmptyBody() && item->hasEmptyTail());
ui->actionExtractBody->setDisabled(item->hasEmptyHeader()); ui->actionExtractBody->setDisabled(item->hasEmptyHeader());
//ui->actionExtractUncompressed->setEnabled(ffsEngine->isCompressedFile(current)); //ui->actionExtractUncompressed->setEnabled(ffsEngine->isCompressedFile(current));
ui->actionRemove->setEnabled(type == TreeItem::Volume || type == TreeItem::File || type == TreeItem::Section); ui->actionRemove->setEnabled(type == TreeItem::Volume || type == TreeItem::File || type == TreeItem::Section);
@ -98,6 +107,26 @@ void UEFITool::populateUi(const QModelIndex &current)
ui->actionInsertBefore->setEnabled(type == TreeItem::File || type == TreeItem::Section); ui->actionInsertBefore->setEnabled(type == TreeItem::File || type == TreeItem::Section);
ui->actionInsertAfter->setEnabled(type == TreeItem::File || type == TreeItem::Section); ui->actionInsertAfter->setEnabled(type == TreeItem::File || type == TreeItem::Section);
//ui->actionReplace->setEnabled(ffsEngine->isOfType(TreeItem::File, current)); //ui->actionReplace->setEnabled(ffsEngine->isOfType(TreeItem::File, current));
ui->actionChangeToEfi11->setEnabled(type == TreeItem::Section && subtype == EFI_SECTION_COMPRESSION &&
(algorithm == COMPRESSION_ALGORITHM_NONE || algorithm == COMPRESSION_ALGORITHM_TIANO || algorithm == COMPRESSION_ALGORITHM_LZMA));
ui->actionChangeToTiano->setEnabled(type == TreeItem::Section && subtype == EFI_SECTION_COMPRESSION &&
(algorithm == COMPRESSION_ALGORITHM_NONE || algorithm == COMPRESSION_ALGORITHM_EFI11 || algorithm == COMPRESSION_ALGORITHM_LZMA));
ui->actionChangeToLzma->setEnabled(type == TreeItem::Section && subtype == EFI_SECTION_COMPRESSION &&
(algorithm == COMPRESSION_ALGORITHM_NONE || algorithm == COMPRESSION_ALGORITHM_EFI11 || algorithm == COMPRESSION_ALGORITHM_TIANO));
ui->menuChangeCompressionTo->setEnabled(ui->actionChangeToEfi11->isEnabled() ||
ui->actionChangeToTiano->isEnabled() || ui->actionChangeToLzma->isEnabled());
}
void UEFITool::rebuild()
{
QModelIndex index = ui->structureTreeView->selectionModel()->currentIndex();
if (!index.isValid())
return;
UINT8 result = ffsEngine->rebuild(index);
if (result == ERR_SUCCESS)
ui->actionSaveImageFile->setEnabled(true);
} }
void UEFITool::remove() void UEFITool::remove()
@ -188,6 +217,58 @@ void UEFITool::replace()
} }
void UEFITool::changeToEfi11()
{
QModelIndex index = ui->structureTreeView->selectionModel()->currentIndex();
if (!index.isValid())
return;
UINT8 result = ffsEngine->changeCompression(index, COMPRESSION_ALGORITHM_EFI11);
if (result == ERR_SUCCESS)
ui->actionSaveImageFile->setEnabled(true);
}
void UEFITool::changeToTiano()
{
QModelIndex index = ui->structureTreeView->selectionModel()->currentIndex();
if (!index.isValid())
return;
UINT8 result = ffsEngine->changeCompression(index, COMPRESSION_ALGORITHM_TIANO);
if (result == ERR_SUCCESS)
ui->actionSaveImageFile->setEnabled(true);
}
void UEFITool::changeToLzma()
{
QModelIndex index = ui->structureTreeView->selectionModel()->currentIndex();
if (!index.isValid())
return;
UINT8 result = ffsEngine->changeCompression(index, COMPRESSION_ALGORITHM_LZMA);
if (result == ERR_SUCCESS)
ui->actionSaveImageFile->setEnabled(true);
}
void UEFITool::about()
{
QMessageBox::about(this, tr("About UEFITool"), tr(
"Copyright (c) 2013, Nikolaj Schlej aka CodeRush.\n\n"
"The program is dedicated to RevoGirl. Rest in peace, young genius.\n\n"
"The program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License.\n"
"The full text of the license may be found at\nhttp://opensource.org/licenses/bsd-license.php\n\n"
"THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN \"AS IS\" BASIS,\n"
"WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND,\n"
"EITHER EXPRESS OR IMPLIED."
));
}
void UEFITool::aboutQt()
{
QMessageBox::aboutQt(this, tr("About Qt"));
}
void UEFITool::saveImageFile() void UEFITool::saveImageFile()
{ {
QString path = QFileDialog::getSaveFileName(this, tr("Save BIOS image file"),".","BIOS image file (*.rom *.bin *.cap *.fd *.wph *.efi);;All files (*.*)"); QString path = QFileDialog::getSaveFileName(this, tr("Save BIOS image file"),".","BIOS image file (*.rom *.bin *.cap *.fd *.wph *.efi);;All files (*.*)");

View File

@ -60,6 +60,12 @@ private slots:
void insertAfter(); void insertAfter();
void replace(); void replace();
void remove(); void remove();
void rebuild();
void changeToEfi11();
void changeToTiano();
void changeToLzma();
void about();
void aboutQt();
void scrollTreeView(QListWidgetItem* item); void scrollTreeView(QListWidgetItem* item);
private: private:

View File

@ -20,7 +20,7 @@
<bool>true</bool> <bool>true</bool>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>UEFITool 0.8.1</string> <string>UEFITool 0.9.0</string>
</property> </property>
<widget class="QWidget" name="centralWidget"> <widget class="QWidget" name="centralWidget">
<property name="sizePolicy"> <property name="sizePolicy">
@ -183,6 +183,10 @@
<addaction name="actionOpenImageFile"/> <addaction name="actionOpenImageFile"/>
<addaction name="actionSaveImageFile"/> <addaction name="actionSaveImageFile"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="actionRebuild"/>
<addaction name="separator"/>
<addaction name="actionRemove"/>
<addaction name="separator"/>
<addaction name="actionExtract"/> <addaction name="actionExtract"/>
<addaction name="actionExtractBody"/> <addaction name="actionExtractBody"/>
<addaction name="actionExtractUncompressed"/> <addaction name="actionExtractUncompressed"/>
@ -192,22 +196,79 @@
<addaction name="actionInsertAfter"/> <addaction name="actionInsertAfter"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="actionReplace"/> <addaction name="actionReplace"/>
</widget>
<widget class="QMenuBar" name="menuBar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1100</width>
<height>21</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
<property name="title">
<string>&amp;File</string>
</property>
<addaction name="actionOpenImageFile"/>
<addaction name="actionSaveImageFile"/>
<addaction name="separator"/>
<addaction name="actionQuit"/>
</widget>
<widget class="QMenu" name="menuAction">
<property name="title">
<string>A&amp;ction</string>
</property>
<widget class="QMenu" name="menuChangeCompressionTo">
<property name="enabled">
<bool>false</bool>
</property>
<property name="title">
<string>Change &amp;compression to</string>
</property>
<addaction name="actionChangeToTiano"/>
<addaction name="actionChangeToEfi11"/>
<addaction name="actionChangeToLzma"/>
</widget>
<addaction name="actionRebuild"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="actionRemove"/> <addaction name="actionRemove"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="actionExtract"/>
<addaction name="actionExtractBody"/>
<addaction name="actionExtractUncompressed"/>
<addaction name="separator"/>
<addaction name="actionInsertInto"/>
<addaction name="actionInsertAfter"/>
<addaction name="actionInsertBefore"/>
<addaction name="separator"/>
<addaction name="actionReplace"/>
<addaction name="separator"/>
<addaction name="menuChangeCompressionTo"/>
</widget>
<widget class="QMenu" name="menuHelp">
<property name="title">
<string>H&amp;elp</string>
</property>
<addaction name="actionAbout"/>
<addaction name="actionAboutQt"/>
</widget>
<addaction name="menuFile"/>
<addaction name="menuAction"/>
<addaction name="menuHelp"/>
</widget> </widget>
<action name="actionInsertAfter"> <action name="actionInsertAfter">
<property name="enabled"> <property name="enabled">
<bool>false</bool> <bool>false</bool>
</property> </property>
<property name="text"> <property name="text">
<string>Insert object after...</string> <string>Insert &amp;after...</string>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>Insert an object from file after selected object</string> <string>Insert an object from file after selected object</string>
</property> </property>
<property name="shortcut"> <property name="shortcut">
<string>Ctrl+I</string> <string>Ctrl+Shift+I</string>
</property> </property>
</action> </action>
<action name="actionInsertBefore"> <action name="actionInsertBefore">
@ -215,13 +276,13 @@
<bool>false</bool> <bool>false</bool>
</property> </property>
<property name="text"> <property name="text">
<string>Insert object before...</string> <string>Insert &amp;before...</string>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>Insert object from file before selected object</string> <string>Insert object from file before selected object</string>
</property> </property>
<property name="shortcut"> <property name="shortcut">
<string>Ctrl+Shift+I</string> <string>Ctrl+Alt+I</string>
</property> </property>
</action> </action>
<action name="actionReplace"> <action name="actionReplace">
@ -229,7 +290,7 @@
<bool>false</bool> <bool>false</bool>
</property> </property>
<property name="text"> <property name="text">
<string>Replace</string> <string>Rep&amp;lace</string>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>Replace selected object with an object from file</string> <string>Replace selected object with an object from file</string>
@ -243,7 +304,7 @@
<bool>false</bool> <bool>false</bool>
</property> </property>
<property name="text"> <property name="text">
<string>Extract as is...</string> <string>E&amp;xtract as is...</string>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>Extract selected object as is to file</string> <string>Extract selected object as is to file</string>
@ -257,7 +318,7 @@
<bool>false</bool> <bool>false</bool>
</property> </property>
<property name="text"> <property name="text">
<string>Extract without header...</string> <string>Extract &amp;without header...</string>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>Extract selected object without header to file</string> <string>Extract selected object without header to file</string>
@ -271,7 +332,7 @@
<bool>false</bool> <bool>false</bool>
</property> </property>
<property name="text"> <property name="text">
<string>Extract uncompressed...</string> <string>Extract &amp;uncompressed...</string>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>Extract selected FFS file uncompressing it </string> <string>Extract selected FFS file uncompressing it </string>
@ -285,7 +346,7 @@
<bool>false</bool> <bool>false</bool>
</property> </property>
<property name="text"> <property name="text">
<string>Remove</string> <string>Re&amp;move</string>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>Remove selected object</string> <string>Remove selected object</string>
@ -296,7 +357,7 @@
</action> </action>
<action name="actionOpenImageFile"> <action name="actionOpenImageFile">
<property name="text"> <property name="text">
<string>Open image file...</string> <string>&amp;Open image file...</string>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>Open image file</string> <string>Open image file</string>
@ -310,13 +371,13 @@
<bool>false</bool> <bool>false</bool>
</property> </property>
<property name="text"> <property name="text">
<string>Insert object into...</string> <string>Insert &amp;into...</string>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>Insert object from file into selected object</string> <string>Insert object from file into selected object</string>
</property> </property>
<property name="shortcut"> <property name="shortcut">
<string>Ctrl+Ins</string> <string>Ctrl+I</string>
</property> </property>
</action> </action>
<action name="actionSaveImageFile"> <action name="actionSaveImageFile">
@ -324,7 +385,7 @@
<bool>false</bool> <bool>false</bool>
</property> </property>
<property name="text"> <property name="text">
<string>Save image file...</string> <string>&amp;Save image file...</string>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>Save modified image file</string> <string>Save modified image file</string>
@ -333,6 +394,71 @@
<string>Ctrl+S</string> <string>Ctrl+S</string>
</property> </property>
</action> </action>
<action name="actionRebuild">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>&amp;Rebuild</string>
</property>
<property name="toolTip">
<string>Rebuild selected object</string>
</property>
<property name="shortcut">
<string>Ctrl+Space</string>
</property>
</action>
<action name="actionChangeToTiano">
<property name="text">
<string>&amp;Tiano</string>
</property>
<property name="shortcut">
<string>Ctrl+T</string>
</property>
</action>
<action name="actionChangeToEfi11">
<property name="text">
<string>&amp;EFI 1.1</string>
</property>
<property name="shortcut">
<string>Ctrl+Shift+T</string>
</property>
</action>
<action name="actionChangeToLzma">
<property name="text">
<string>&amp;LZMA</string>
</property>
<property name="shortcut">
<string>Ctrl+L</string>
</property>
</action>
<action name="actionAbout">
<property name="text">
<string>&amp;About UEFITool</string>
</property>
<property name="shortcut">
<string>F1</string>
</property>
<property name="menuRole">
<enum>QAction::AboutRole</enum>
</property>
</action>
<action name="actionAboutQt">
<property name="text">
<string>About &amp;Qt</string>
</property>
<property name="menuRole">
<enum>QAction::AboutQtRole</enum>
</property>
</action>
<action name="actionQuit">
<property name="text">
<string>&amp;Quit</string>
</property>
<property name="menuRole">
<enum>QAction::QuitRole</enum>
</property>
</action>
</widget> </widget>
<layoutdefault spacing="6" margin="11"/> <layoutdefault spacing="6" margin="11"/>
<resources/> <resources/>