mirror of
https://github.com/LongSoft/UEFITool.git
synced 2024-11-21 23:48:22 +08:00
Version 0.6.0
- Debug window upgrade - Volume grow for non-root volumes - Minor bugfix
This commit is contained in:
parent
6ff5119048
commit
3c90bc4a61
47
debuglistitem.cpp
Normal file
47
debuglistitem.cpp
Normal file
@ -0,0 +1,47 @@
|
||||
/* debuglistitem.cpp
|
||||
|
||||
Copyright (c) 2013, Nikolaj Schlej. All rights reserved.
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
*/
|
||||
|
||||
#include "debuglistitem.h"
|
||||
|
||||
DebugListItem::DebugListItem(QListWidget * parent, int type, const QModelIndex & index)
|
||||
: QListWidgetItem(parent, type)
|
||||
{
|
||||
itemIndex = index;
|
||||
}
|
||||
|
||||
DebugListItem::DebugListItem(const QString & text, QListWidget * parent, int type, const QModelIndex & index)
|
||||
: QListWidgetItem(text, parent, type)
|
||||
{
|
||||
itemIndex = index;
|
||||
}
|
||||
|
||||
DebugListItem::DebugListItem(const QIcon & icon, const QString & text, QListWidget * parent, int type, const QModelIndex & index)
|
||||
: QListWidgetItem(icon, text, parent, type)
|
||||
{
|
||||
itemIndex = index;
|
||||
}
|
||||
|
||||
DebugListItem::~DebugListItem()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QModelIndex DebugListItem::index() const
|
||||
{
|
||||
return itemIndex;
|
||||
}
|
||||
|
||||
void DebugListItem::setIndex(QModelIndex & index)
|
||||
{
|
||||
itemIndex = index;
|
||||
}
|
37
debuglistitem.h
Normal file
37
debuglistitem.h
Normal file
@ -0,0 +1,37 @@
|
||||
/* debuglistitem.h
|
||||
|
||||
Copyright (c) 2013, Nikolaj Schlej. All rights reserved.
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef __DEBUGLISTITEM_H__
|
||||
#define __DEBUGLISTITEM_H__
|
||||
|
||||
#include <QModelIndex>
|
||||
#include <QListWidgetItem>
|
||||
|
||||
#include "basetypes.h"
|
||||
|
||||
class DebugListItem : public QListWidgetItem
|
||||
{
|
||||
public:
|
||||
DebugListItem(QListWidget * parent = 0, int type = Type, const QModelIndex & index = QModelIndex());
|
||||
DebugListItem(const QString & text, QListWidget * parent = 0, int type = Type, const QModelIndex & index = QModelIndex());
|
||||
DebugListItem(const QIcon & icon, const QString & text, QListWidget * parent = 0, int type = Type, const QModelIndex & index = QModelIndex());
|
||||
~DebugListItem();
|
||||
|
||||
QModelIndex index() const;
|
||||
void setIndex(QModelIndex & index);
|
||||
|
||||
private:
|
||||
QModelIndex itemIndex;
|
||||
};
|
||||
|
||||
#endif
|
364
ffsengine.cpp
364
ffsengine.cpp
@ -46,14 +46,14 @@ TreeModel* FfsEngine::model() const
|
||||
return treeModel;
|
||||
}
|
||||
|
||||
QString FfsEngine::message() const
|
||||
void FfsEngine::msg(const QString & message, const QModelIndex index)
|
||||
{
|
||||
return text;
|
||||
debugItems.enqueue(new DebugListItem(message, NULL, 0, index));
|
||||
}
|
||||
|
||||
void FfsEngine::msg(const QString & message)
|
||||
QQueue<DebugListItem*> FfsEngine::debugMessage()
|
||||
{
|
||||
text.append(message).append("\n");
|
||||
return debugItems;
|
||||
}
|
||||
|
||||
QByteArray FfsEngine::header(const QModelIndex& index) const
|
||||
@ -146,13 +146,15 @@ bool FfsEngine::isOfSubtype(UINT8 subtype, const QModelIndex & index) const
|
||||
// Firmware image parsing
|
||||
UINT8 FfsEngine::parseInputFile(const QByteArray & buffer)
|
||||
{
|
||||
UINT32 capsuleHeaderSize = 0;
|
||||
UINT32 capsuleHeaderSize = 0;
|
||||
FLASH_DESCRIPTOR_HEADER* descriptorHeader = NULL;
|
||||
QByteArray flashImage;
|
||||
QByteArray bios;
|
||||
QModelIndex index;
|
||||
QString name;
|
||||
QString info;
|
||||
QModelIndex index;
|
||||
QByteArray flashImage;
|
||||
QByteArray bios;
|
||||
QByteArray header;
|
||||
QByteArray body;
|
||||
QString name;
|
||||
QString info;
|
||||
|
||||
// Check buffer size to be more or equal then sizeof(EFI_CAPSULE_HEADER)
|
||||
if (buffer.size() <= sizeof(EFI_CAPSULE_HEADER))
|
||||
@ -166,8 +168,8 @@ UINT8 FfsEngine::parseInputFile(const QByteArray & buffer)
|
||||
// Get info
|
||||
EFI_CAPSULE_HEADER* capsuleHeader = (EFI_CAPSULE_HEADER*) buffer.constData();
|
||||
capsuleHeaderSize = capsuleHeader->HeaderSize;
|
||||
QByteArray header = buffer.left(capsuleHeaderSize);
|
||||
QByteArray body = buffer.right(buffer.size() - capsuleHeaderSize);
|
||||
header = buffer.left(capsuleHeaderSize);
|
||||
body = buffer.right(buffer.size() - capsuleHeaderSize);
|
||||
name = tr("UEFI capsule");
|
||||
info = tr("Header size: %1\nFlags: %2\nImage size: %3")
|
||||
.arg(capsuleHeader->HeaderSize, 8, 16, QChar('0'))
|
||||
@ -182,8 +184,8 @@ UINT8 FfsEngine::parseInputFile(const QByteArray & buffer)
|
||||
// Get info
|
||||
APTIO_CAPSULE_HEADER* aptioCapsuleHeader = (APTIO_CAPSULE_HEADER*) buffer.constData();
|
||||
capsuleHeaderSize = aptioCapsuleHeader->RomImageOffset;
|
||||
QByteArray header = buffer.left(capsuleHeaderSize);
|
||||
QByteArray body = buffer.right(buffer.size() - capsuleHeaderSize);
|
||||
header = buffer.left(capsuleHeaderSize);
|
||||
body = buffer.right(buffer.size() - capsuleHeaderSize);
|
||||
name = tr("AMI Aptio capsule");
|
||||
info = tr("Header size: %1\nFlags: %2\nImage size: %3")
|
||||
.arg(aptioCapsuleHeader->RomImageOffset, 4, 16, QChar('0'))
|
||||
@ -193,7 +195,15 @@ UINT8 FfsEngine::parseInputFile(const QByteArray & buffer)
|
||||
// Add tree item
|
||||
index = treeModel->addItem(TreeItem::Capsule, TreeItem::AptioCapsule, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body);
|
||||
}
|
||||
|
||||
else {
|
||||
// Add tree item
|
||||
name = tr("UEFI image");
|
||||
info = tr("Size: %1")
|
||||
.arg(buffer.size(), 8, 16, QChar('0'));
|
||||
// Add tree item
|
||||
index = treeModel->addItem(TreeItem::Image, 0, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), buffer);
|
||||
}
|
||||
|
||||
// Skip capsule header to have flash chip image
|
||||
flashImage = buffer.right(buffer.size() - capsuleHeaderSize);
|
||||
|
||||
@ -230,7 +240,7 @@ UINT8 FfsEngine::parseInputFile(const QByteArray & buffer)
|
||||
.arg(descriptorMap->NumberOfIccTableEntries);
|
||||
//!TODO: more info about descriptor
|
||||
// Add tree item
|
||||
index = treeModel->addItem(TreeItem::Descriptor, 0, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body);
|
||||
index = treeModel->addItem(TreeItem::Descriptor, 0, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, index);
|
||||
|
||||
// Parse regions
|
||||
QModelIndex regionIndex;
|
||||
@ -284,26 +294,26 @@ UINT8 FfsEngine::parseRegion(const QByteArray & flashImage, UINT8 regionSubtype,
|
||||
// Check region base to be in buffer
|
||||
if (regionOffset >= flashImageSize)
|
||||
{
|
||||
msg(tr("parseRegion: %1 region stored in descriptor not found").arg(regionName));
|
||||
msg(tr("parseRegion: %1 region stored in descriptor not found").arg(regionName), parent);
|
||||
if (twoChips)
|
||||
msg(tr("Two flash chips installed, so it could be in another flash chip\n"
|
||||
"Make a dump from another flash chip and open it to view information about %1 region").arg(regionName));
|
||||
"Make a dump from another flash chip and open it to view information about %1 region").arg(regionName), parent);
|
||||
else
|
||||
msg(tr("One flash chip installed, so it is an error caused by damaged or incomplete dump"));
|
||||
msg(tr("Absence of %1 region assumed").arg(regionName));
|
||||
msg(tr("One flash chip installed, so it is an error caused by damaged or incomplete dump"), parent);
|
||||
msg(tr("Absence of %1 region assumed").arg(regionName), parent);
|
||||
return ERR_INVALID_REGION;
|
||||
}
|
||||
|
||||
// Check region to be fully present in buffer
|
||||
else if (regionOffset + regionSize > flashImageSize)
|
||||
{
|
||||
msg(tr("parseRegion: %1 region stored in descriptor overlaps the end of opened file").arg(regionName));
|
||||
msg(tr("parseRegion: %1 region stored in descriptor overlaps the end of opened file").arg(regionName), parent);
|
||||
if (twoChips)
|
||||
msg(tr("Two flash chips installed, so it could be in another flash chip\n"
|
||||
"Make a dump from another flash chip and open it to view information about %1 region").arg(regionName));
|
||||
"Make a dump from another flash chip and open it to view information about %1 region").arg(regionName), parent);
|
||||
else
|
||||
msg(tr("One flash chip installed, so it is an error caused by damaged or incomplete dump"));
|
||||
msg(tr("Absence of %1 region assumed\n").arg(regionName));
|
||||
msg(tr("One flash chip installed, so it is an error caused by damaged or incomplete dump"), parent);
|
||||
msg(tr("Absence of %1 region assumed\n").arg(regionName), parent);
|
||||
return ERR_INVALID_REGION;
|
||||
}
|
||||
|
||||
@ -337,7 +347,7 @@ UINT8 FfsEngine::parseRegion(const QByteArray & flashImage, UINT8 regionSubtype,
|
||||
meVersionOffset = body.indexOf(ME_VERSION_SIGNATURE);
|
||||
if (meVersionOffset < 0){
|
||||
info += tr("\nVersion: unknown");
|
||||
msg(tr("parseRegion: ME region version is unknown, it can be damaged"));
|
||||
msg(tr("parseRegion: ME region version is unknown, it can be damaged"), parent);
|
||||
}
|
||||
else {
|
||||
meVersion = (ME_VERSION*) (body.constData() + meVersionOffset);
|
||||
@ -356,7 +366,7 @@ UINT8 FfsEngine::parseRegion(const QByteArray & flashImage, UINT8 regionSubtype,
|
||||
break;
|
||||
default:
|
||||
name = tr("Unknown region");
|
||||
msg(tr("insertInTree: Unknown region"));
|
||||
msg(tr("parseRegion: Unknown region"), parent);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -412,10 +422,10 @@ UINT8 FfsEngine::parseBios(const QByteArray & bios, const QModelIndex & parent)
|
||||
result = getVolumeSize(bios, volumeOffset, volumeSize);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
|
||||
//Check that volume is fully present in input
|
||||
if (volumeOffset + volumeSize > (UINT32) bios.size()) {
|
||||
msg(tr("parseBios: Volume overlaps the end of input buffer"));
|
||||
msg(tr("parseBios: Volume overlaps the end of input buffer"), parent);
|
||||
return ERR_INVALID_VOLUME;
|
||||
}
|
||||
|
||||
@ -448,7 +458,7 @@ UINT8 FfsEngine::parseBios(const QByteArray & bios, const QModelIndex & parent)
|
||||
|| alignment32 || alignment64 || alignment128 || alignment256
|
||||
|| alignment512 || alignment1k || alignment2k || alignment4k
|
||||
|| alignment8k || alignment16k || alignment32k || alignment64k))
|
||||
msg("parseBios: Incompatible revision 1 volume alignment setup");
|
||||
msg("parseBios: Incompatible revision 1 volume alignment setup", parent);
|
||||
|
||||
// Assume that smaller alignment value consumes greater
|
||||
//!TODO: refactor this code
|
||||
@ -488,7 +498,7 @@ UINT8 FfsEngine::parseBios(const QByteArray & bios, const QModelIndex & parent)
|
||||
|
||||
// Check alignment
|
||||
if (volumeOffset % alignment) {
|
||||
msg(tr("parseBios: Unaligned revision 1 volume"));
|
||||
msg(tr("parseBios: Unaligned revision 1 volume"), parent);
|
||||
}
|
||||
}
|
||||
else if (volumeHeader->Revision == 2) {
|
||||
@ -497,16 +507,16 @@ UINT8 FfsEngine::parseBios(const QByteArray & bios, const QModelIndex & parent)
|
||||
|
||||
// Check alignment
|
||||
if (volumeOffset % alignment) {
|
||||
msg(tr("parseBios: Unaligned revision 2 volume"));
|
||||
msg(tr("parseBios: Unaligned revision 2 volume"), parent);
|
||||
}
|
||||
}
|
||||
else
|
||||
msg(tr("parseBios: Unknown volume revision (%1)").arg(volumeHeader->Revision));
|
||||
msg(tr("parseBios: Unknown volume revision (%1)").arg(volumeHeader->Revision), parent);
|
||||
|
||||
// Parse volume
|
||||
UINT8 result = parseVolume(bios.mid(volumeOffset, volumeSize), parent);
|
||||
if (result)
|
||||
msg(tr("parseBios: Volume parsing failed (%1)").arg(result));
|
||||
msg(tr("parseBios: Volume parsing failed (%1)").arg(result), parent);
|
||||
|
||||
// Go to next volume
|
||||
prevVolumeOffset = volumeOffset;
|
||||
@ -553,7 +563,17 @@ UINT8 FfsEngine::getVolumeSize(const QByteArray & bios, UINT32 volumeOffset, UIN
|
||||
if (QByteArray((const char*) &volumeHeader->Signature, sizeof(volumeHeader->Signature)) != EFI_FV_SIGNATURE)
|
||||
return ERR_INVALID_VOLUME;
|
||||
|
||||
volumeSize = volumeHeader->FvLength;
|
||||
// Use BlockMap to determine volume size
|
||||
EFI_FV_BLOCK_MAP_ENTRY* entry = (EFI_FV_BLOCK_MAP_ENTRY*) (bios.constData() + volumeOffset + sizeof(EFI_FIRMWARE_VOLUME_HEADER));
|
||||
volumeSize = 0;
|
||||
while(entry->NumBlocks != 0 && entry->Length != 0) {
|
||||
if ((void*) entry > bios.constData() + bios.size()) {
|
||||
return ERR_INVALID_VOLUME;
|
||||
}
|
||||
volumeSize += entry->NumBlocks * entry->Length;
|
||||
entry += 1;
|
||||
}
|
||||
|
||||
return ERR_SUCCESS;
|
||||
}
|
||||
|
||||
@ -575,7 +595,7 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, const QModelIndex & par
|
||||
}
|
||||
// Other GUID
|
||||
else {
|
||||
msg(tr("parseBios: Unknown file system (%1)").arg(guidToQString(volumeHeader->FileSystemGuid)));
|
||||
msg(tr("parseBios: Unknown file system (%1)").arg(guidToQString(volumeHeader->FileSystemGuid)), parent);
|
||||
parseCurrentVolume = false;
|
||||
}
|
||||
|
||||
@ -585,7 +605,7 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, const QModelIndex & par
|
||||
|
||||
// Check header checksum by recalculating it
|
||||
if (!calculateChecksum16((UINT8*) volumeHeader, volumeHeader->HeaderLength)) {
|
||||
msg(tr("parseBios: Volume header checksum is invalid"));
|
||||
msg(tr("parseBios: Volume header checksum is invalid"), parent);
|
||||
}
|
||||
|
||||
// Check for presence of extended header, only if header revision is greater then 1
|
||||
@ -597,17 +617,33 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, const QModelIndex & par
|
||||
headerSize = volumeHeader->HeaderLength;
|
||||
}
|
||||
|
||||
// Get volume size
|
||||
UINT8 result;
|
||||
UINT32 volumeSize;
|
||||
|
||||
result = getVolumeSize(volume, 0, volumeSize);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
// Check reported size
|
||||
if (volumeSize != volumeHeader->FvLength) {
|
||||
msg(tr("%1: volume size stored in header %2 differs from calculated size %3")
|
||||
.arg(guidToQString(volumeHeader->FileSystemGuid))
|
||||
.arg(volumeHeader->FvLength, 8, 16, QChar('0'))
|
||||
.arg(volumeSize, 8, 16, QChar('0')), parent);
|
||||
}
|
||||
|
||||
// Get info
|
||||
QString name = guidToQString(volumeHeader->FileSystemGuid);
|
||||
QString info = tr("Size: %1\nRevision: %2\nAttributes: %3\nHeader size: %4")
|
||||
.arg(volumeHeader->FvLength, 8, 16, QChar('0'))
|
||||
.arg(volumeSize, 8, 16, QChar('0'))
|
||||
.arg(volumeHeader->Revision)
|
||||
.arg(volumeHeader->Attributes, 8, 16, QChar('0'))
|
||||
.arg(volumeHeader->HeaderLength, 4, 16, QChar('0'));
|
||||
|
||||
// Add tree item
|
||||
QByteArray header = volume.left(headerSize);
|
||||
QByteArray body = volume.mid(headerSize, volumeHeader->FvLength - headerSize);
|
||||
QByteArray body = volume.mid(headerSize, volumeSize - headerSize);
|
||||
QModelIndex index = treeModel->addItem(TreeItem::Volume, 0, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, parent, mode);
|
||||
|
||||
// Do not parse volumes with unknown FS
|
||||
@ -617,7 +653,6 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, const QModelIndex & par
|
||||
// Search for and parse all files
|
||||
UINT32 fileOffset = headerSize;
|
||||
UINT32 fileSize;
|
||||
UINT8 result;
|
||||
QQueue<QByteArray> files;
|
||||
|
||||
while (true) {
|
||||
@ -627,7 +662,7 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, const QModelIndex & par
|
||||
|
||||
// Check file size to be at least sizeof(EFI_FFS_FILE_HEADER)
|
||||
if (fileSize < sizeof(EFI_FFS_FILE_HEADER)) {
|
||||
msg(tr("parseVolume: File with invalid size"));
|
||||
msg(tr("parseVolume: File with invalid size"), index);
|
||||
return ERR_INVALID_FILE;
|
||||
}
|
||||
|
||||
@ -643,12 +678,12 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, const QModelIndex & par
|
||||
UINT8 alignmentPower = ffsAlignmentTable[(fileHeader->Attributes & FFS_ATTRIB_DATA_ALIGNMENT) >> 3];
|
||||
UINT32 alignment = pow(2, alignmentPower);
|
||||
if ((fileOffset + sizeof(EFI_FFS_FILE_HEADER)) % alignment) {
|
||||
msg(tr("parseVolume: %1, unaligned file").arg(guidToQString(fileHeader->Name)));
|
||||
msg(tr("parseVolume: %1, unaligned file").arg(guidToQString(fileHeader->Name)), index);
|
||||
}
|
||||
|
||||
// Check file GUID
|
||||
if (fileHeader->Type != EFI_FV_FILETYPE_PAD && files.indexOf(header.left(sizeof(EFI_GUID))) != -1)
|
||||
msg(tr("%1: file with duplicate GUID").arg(guidToQString(fileHeader->Name)));
|
||||
msg(tr("%1: file with duplicate GUID").arg(guidToQString(fileHeader->Name)), index);
|
||||
|
||||
// Add file GUID to queue
|
||||
files.enqueue(header.left(sizeof(EFI_GUID)));
|
||||
@ -656,7 +691,7 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, const QModelIndex & par
|
||||
// Parse file
|
||||
result = parseFile(file, volumeHeader->Revision, empty, index);
|
||||
if (result)
|
||||
msg(tr("parseVolume: Parse FFS file failed (%1)").arg(result));
|
||||
msg(tr("parseVolume: Parse FFS file failed (%1)").arg(result), index);
|
||||
|
||||
// Move to next file
|
||||
fileOffset += fileSize;
|
||||
@ -693,7 +728,7 @@ UINT8 FfsEngine::parseFile(const QByteArray & file, UINT8 revision, const char e
|
||||
msg(tr("parseVolume: %1, stored header checksum %2 differs from calculated %3")
|
||||
.arg(guidToQString(fileHeader->Name))
|
||||
.arg(fileHeader->IntegrityCheck.Checksum.Header, 2, 16, QChar('0'))
|
||||
.arg(calculated, 2, 16, QChar('0')));
|
||||
.arg(calculated, 2, 16, QChar('0')), parent);
|
||||
}
|
||||
|
||||
// Check data checksum
|
||||
@ -708,7 +743,7 @@ UINT8 FfsEngine::parseFile(const QByteArray & file, UINT8 revision, const char e
|
||||
msg(tr("parseVolume: %1, stored data checksum %2 differs from calculated %3")
|
||||
.arg(guidToQString(fileHeader->Name))
|
||||
.arg(fileHeader->IntegrityCheck.Checksum.File, 2, 16, QChar('0'))
|
||||
.arg(calculated, 2, 16, QChar('0')));
|
||||
.arg(calculated, 2, 16, QChar('0')), parent);
|
||||
}
|
||||
}
|
||||
// Data checksum must be one of predefined values
|
||||
@ -716,7 +751,7 @@ UINT8 FfsEngine::parseFile(const QByteArray & file, UINT8 revision, const char e
|
||||
if (fileHeader->IntegrityCheck.Checksum.File != FFS_FIXED_CHECKSUM && fileHeader->IntegrityCheck.Checksum.File != FFS_FIXED_CHECKSUM2) {
|
||||
msg(tr("parseVolume: %1, stored data checksum %2 differs from standard value")
|
||||
.arg(guidToQString(fileHeader->Name))
|
||||
.arg(fileHeader->IntegrityCheck.Checksum.File, 2, 16, QChar('0')));
|
||||
.arg(fileHeader->IntegrityCheck.Checksum.File, 2, 16, QChar('0')), parent);
|
||||
}
|
||||
}
|
||||
|
||||
@ -732,7 +767,7 @@ UINT8 FfsEngine::parseFile(const QByteArray & file, UINT8 revision, const char e
|
||||
msg(tr("parseVolume: %1, file tail value %2 is not a bitwise not of %3 stored in file header")
|
||||
.arg(guidToQString(fileHeader->Name))
|
||||
.arg(*tail, 4, 16, QChar('0'))
|
||||
.arg(fileHeader->IntegrityCheck.TailReference, 4, 16, QChar('0')));
|
||||
.arg(fileHeader->IntegrityCheck.TailReference, 4, 16, QChar('0')), parent);
|
||||
|
||||
// Remove tail from file body
|
||||
body = body.left(body.size() - sizeof(UINT16));
|
||||
@ -782,7 +817,7 @@ UINT8 FfsEngine::parseFile(const QByteArray & file, UINT8 revision, const char e
|
||||
break;
|
||||
default:
|
||||
parseCurrentFile = false;
|
||||
msg(tr("parseVolume: Unknown file type (%1)").arg(fileHeader->Type, 2, 16, QChar('0')));
|
||||
msg(tr("parseVolume: Unknown file type (%1)").arg(fileHeader->Type, 2, 16, QChar('0')), parent);
|
||||
};
|
||||
|
||||
// Check for empty file
|
||||
@ -815,7 +850,7 @@ UINT8 FfsEngine::parseFile(const QByteArray & file, UINT8 revision, const char e
|
||||
if (parseAsBios) {
|
||||
result = parseBios(body, index);
|
||||
if (result && result != ERR_VOLUMES_NOT_FOUND)
|
||||
msg(tr("parseVolume: Parse file as BIOS failed (%1)").arg(result));
|
||||
msg(tr("parseVolume: Parse file as BIOS failed (%1)").arg(result), index);
|
||||
return ERR_SUCCESS;
|
||||
}
|
||||
|
||||
@ -874,8 +909,8 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, const UINT8 revision,
|
||||
QByteArray header;
|
||||
QByteArray body;
|
||||
UINT32 headerSize;
|
||||
QModelIndex index;
|
||||
UINT8 result;
|
||||
QModelIndex index;
|
||||
|
||||
switch (sectionHeader->Type) {
|
||||
// Encapsulated sections
|
||||
@ -891,7 +926,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, const UINT8 revision,
|
||||
// Decompress section
|
||||
result = decompress(body, compressedSectionHeader->CompressionType, decompressed, &algorithm);
|
||||
if (result) {
|
||||
msg(tr("parseFile: Section decompression failed (%1)").arg(result));
|
||||
msg(tr("parseFile: Section decompression failed (%1)").arg(result), parent);
|
||||
parseCurrentSection = false;
|
||||
}
|
||||
|
||||
@ -933,7 +968,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, const UINT8 revision,
|
||||
if (result) {
|
||||
result = decompress(body, EFI_CUSTOMIZED_COMPRESSION, decompressed, &algorithm);
|
||||
if (result) {
|
||||
msg(tr("parseFile: GUID defined section can not be decompressed (%1)").arg(result));
|
||||
msg(tr("parseFile: GUID defined section can not be decompressed (%1)").arg(result), parent);
|
||||
parseCurrentSection = false;
|
||||
}
|
||||
}
|
||||
@ -1035,7 +1070,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, const UINT8 revision,
|
||||
// Parse section body as BIOS space
|
||||
result = parseBios(body, index);
|
||||
if (result && result != ERR_VOLUMES_NOT_FOUND) {
|
||||
msg(tr("parseFile: Firmware volume image can not be parsed (%1)").arg(result));
|
||||
msg(tr("parseFile: Firmware volume image can not be parsed (%1)").arg(result), index);
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
@ -1054,12 +1089,11 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, const UINT8 revision,
|
||||
// Parse section body as BIOS space
|
||||
result = parseBios(body, index);
|
||||
if (result && result != ERR_VOLUMES_NOT_FOUND) {
|
||||
msg(tr("parseFile: Raw section can not be parsed as BIOS (%1)").arg(result));
|
||||
msg(tr("parseFile: Raw section can not be parsed as BIOS (%1)").arg(result), index);
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
msg(tr("parseFile: Section with unknown type (%1)").arg(sectionHeader->Type, 2, 16, QChar('0')));
|
||||
header = section.left(sizeof(EFI_COMMON_SECTION_HEADER));
|
||||
body = section.mid(sizeof(EFI_COMMON_SECTION_HEADER), sectionSize - sizeof(EFI_COMMON_SECTION_HEADER));
|
||||
// Get info
|
||||
@ -1069,7 +1103,7 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, const UINT8 revision,
|
||||
|
||||
// Add tree item
|
||||
index = treeModel->addItem(TreeItem::Section, sectionHeader->Type, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, parent, mode);
|
||||
return ERR_UNKNOWN_SECTION;
|
||||
msg(tr("parseFile: Section with unknown type (%1)").arg(sectionHeader->Type, 2, 16, QChar('0')), index);
|
||||
}
|
||||
return ERR_SUCCESS;
|
||||
}
|
||||
@ -1091,7 +1125,7 @@ UINT8 FfsEngine::insert(const QModelIndex & index, const QByteArray & object, co
|
||||
// Parent type must be volume
|
||||
TreeItem * parentItem = static_cast<TreeItem*>(parent.internalPointer());
|
||||
if (parentItem->type() != TreeItem::Volume) {
|
||||
msg(tr("insert: file can't be inserted into something that is not volume"));
|
||||
msg(tr("insert: file can't be inserted into something that is not volume"), parent);
|
||||
return ERR_INVALID_VOLUME;
|
||||
}
|
||||
|
||||
@ -1122,7 +1156,7 @@ UINT8 FfsEngine::insert(const QModelIndex & index, const QByteArray & object, co
|
||||
parentItem->subtype() == EFI_SECTION_DISPOSABLE))) {
|
||||
QModelIndex volumeIndex = findParentOfType(TreeItem::Volume, parent);
|
||||
if (!volumeIndex.isValid()) {
|
||||
msg(tr("insert: Parent volume not found"));
|
||||
msg(tr("insert: Parent volume not found"), parent);
|
||||
return ERR_INVALID_VOLUME;
|
||||
}
|
||||
|
||||
@ -1139,7 +1173,7 @@ UINT8 FfsEngine::insert(const QModelIndex & index, const QByteArray & object, co
|
||||
treeModel->setItemAction(TreeItem::Reconstruct, parent);
|
||||
}
|
||||
else {
|
||||
msg(tr("insert: section can't be inserted into something that is not file or encapsulation section"));
|
||||
msg(tr("insert: section can't be inserted into something that is not file or encapsulation section"), parent);
|
||||
return ERR_INVALID_FILE;
|
||||
}
|
||||
}
|
||||
@ -1164,8 +1198,6 @@ UINT8 FfsEngine::remove(const QModelIndex & index)
|
||||
return ERR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Compression routines
|
||||
UINT8 FfsEngine::decompress(const QByteArray & compressedData, const UINT8 compressionType, QByteArray & decompressedData, UINT8 * algorithm)
|
||||
{
|
||||
@ -1203,7 +1235,9 @@ UINT8 FfsEngine::decompress(const QByteArray & compressedData, const UINT8 compr
|
||||
scratch = new UINT8[scratchSize];
|
||||
|
||||
// Decompress section data
|
||||
// Try EFI1.1 decompression first
|
||||
if (ERR_SUCCESS != EfiDecompress(data, dataSize, decompressed, decompressedSize, scratch, scratchSize)) {
|
||||
// Not EFI 1.1, try Tiano
|
||||
if (ERR_SUCCESS != TianoDecompress(data, dataSize, decompressed, decompressedSize, scratch, scratchSize)) {
|
||||
if (algorithm)
|
||||
*algorithm = COMPRESSION_ALGORITHM_UNKNOWN;
|
||||
@ -1212,9 +1246,34 @@ UINT8 FfsEngine::decompress(const QByteArray & compressedData, const UINT8 compr
|
||||
else if (algorithm)
|
||||
*algorithm = COMPRESSION_ALGORITHM_TIANO;
|
||||
}
|
||||
else if (algorithm)
|
||||
*algorithm = COMPRESSION_ALGORITHM_EFI11;
|
||||
|
||||
else {
|
||||
// Possible EFI 1.1
|
||||
// Try decompressing it as Tiano
|
||||
UINT8* tianoDecompressed = new UINT8[decompressedSize];
|
||||
UINT8* tianoScratch = new UINT8[scratchSize];
|
||||
if (ERR_SUCCESS != TianoDecompress(data, dataSize, tianoDecompressed, decompressedSize, tianoScratch, scratchSize)) {
|
||||
// Not Tiano, definitely EFI 1.1
|
||||
if (algorithm)
|
||||
*algorithm = COMPRESSION_ALGORITHM_EFI11;
|
||||
}
|
||||
else {
|
||||
// Both algorithms work
|
||||
if(memcmp(decompressed, tianoDecompressed, decompressedSize)) {
|
||||
// If decompressed data are different - it's Tiano for sure
|
||||
delete decompressed;
|
||||
delete scratch;
|
||||
decompressed = tianoDecompressed;
|
||||
scratch = tianoScratch;
|
||||
if (algorithm)
|
||||
*algorithm = COMPRESSION_ALGORITHM_TIANO;
|
||||
}
|
||||
else {
|
||||
// Data are same - it's EFI 1.1
|
||||
if (algorithm)
|
||||
*algorithm = COMPRESSION_ALGORITHM_EFI11;
|
||||
}
|
||||
}
|
||||
}
|
||||
decompressedData = QByteArray((const char*) decompressed, decompressedSize);
|
||||
|
||||
// Free allocated memory
|
||||
@ -1352,8 +1411,6 @@ UINT8 FfsEngine::compress(const QByteArray & data, const UINT8 algorithm, QByteA
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Construction routines
|
||||
UINT8 FfsEngine::reconstructImage(QByteArray & reconstructed)
|
||||
{
|
||||
@ -1380,7 +1437,7 @@ UINT8 FfsEngine::constructPadFile(const UINT32 size, const UINT8 revision, const
|
||||
uint32ToUint24(size, header->Size);
|
||||
header->Attributes = 0x00;
|
||||
header->Type = EFI_FV_FILETYPE_PAD;
|
||||
header->State = 0xF8;
|
||||
header->State = 0xF8; //TODO: Check state of pad file in section with empty = 0x00
|
||||
// Calculate header checksum
|
||||
header->IntegrityCheck.Checksum.Header = 0;
|
||||
header->IntegrityCheck.Checksum.File = 0;
|
||||
@ -1433,7 +1490,7 @@ UINT8 FfsEngine::reconstruct(TreeItem* item, QQueue<QByteArray> & queue, const U
|
||||
// File can be removed
|
||||
if (item->type() == TreeItem::File)
|
||||
// Add nothing to queue
|
||||
return ERR_SUCCESS;
|
||||
return ERR_SUCCESS;
|
||||
// Section can be removed
|
||||
else if (item->type() == TreeItem::Section)
|
||||
// Add nothing to queue
|
||||
@ -1451,6 +1508,7 @@ UINT8 FfsEngine::reconstruct(TreeItem* item, QQueue<QByteArray> & queue, const U
|
||||
if (item->subtype() == TreeItem::AptioCapsule)
|
||||
msg(tr("reconstruct: Aptio extended header checksum and signature are now invalid"));
|
||||
case TreeItem::Root:
|
||||
case TreeItem::Image:
|
||||
case TreeItem::Descriptor:
|
||||
case TreeItem::Region:
|
||||
case TreeItem::Padding:
|
||||
@ -1491,7 +1549,7 @@ UINT8 FfsEngine::reconstruct(TreeItem* item, QQueue<QByteArray> & queue, const U
|
||||
return result;
|
||||
}
|
||||
|
||||
// Remove all pad files, which will be recreated later
|
||||
// Remove all pad files, they will be recreated later
|
||||
foreach(const QByteArray & child, childrenQueue)
|
||||
{
|
||||
EFI_FFS_FILE_HEADER* fileHeader = (EFI_FFS_FILE_HEADER*) child.constData();
|
||||
@ -1499,6 +1557,12 @@ UINT8 FfsEngine::reconstruct(TreeItem* item, QQueue<QByteArray> & queue, const U
|
||||
childrenQueue.removeAll(child);
|
||||
}
|
||||
|
||||
// Get volume size
|
||||
UINT32 volumeSize;
|
||||
result = getVolumeSize(header, 0, volumeSize);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
// Construct new volume body
|
||||
UINT32 offset = 0;
|
||||
while (!childrenQueue.isEmpty())
|
||||
@ -1539,14 +1603,14 @@ UINT8 FfsEngine::reconstruct(TreeItem* item, QQueue<QByteArray> & queue, const U
|
||||
offset += size;
|
||||
}
|
||||
|
||||
// If this is a last file in volume
|
||||
// If this is the last file in volume
|
||||
if (childrenQueue.isEmpty())
|
||||
{
|
||||
// Last file of the volume can be Volume Top File
|
||||
if (file.left(sizeof(EFI_GUID)) == EFI_FFS_VOLUME_TOP_FILE_GUID) {
|
||||
// Determine correct VTF offset
|
||||
UINT32 vtfOffset = volumeHeader->FvLength - header.size() - file.size();
|
||||
if (offset % 8) {
|
||||
UINT32 vtfOffset = volumeSize - header.size() - file.size();
|
||||
if (vtfOffset % 8) {
|
||||
msg(tr("reconstruct: %1: Wrong size of Volume Top File")
|
||||
.arg(guidToQString(volumeHeader->FileSystemGuid)));
|
||||
return ERR_INVALID_FILE;
|
||||
@ -1563,24 +1627,62 @@ UINT8 FfsEngine::reconstruct(TreeItem* item, QQueue<QByteArray> & queue, const U
|
||||
// Append constructed pad file to volume body
|
||||
reconstructed.append(pad);
|
||||
offset = vtfOffset;
|
||||
// Ensure that no more files will be in this volume
|
||||
childrenQueue.clear();
|
||||
}
|
||||
// No more space left in volume
|
||||
else if (vtfOffset < offset) {
|
||||
//!TODO: attempt volume grow
|
||||
msg(tr("reconstruct: %1: can't insert VTF, need additional %2 bytes")
|
||||
.arg(guidToQString(volumeHeader->FileSystemGuid))
|
||||
.arg(offset - vtfOffset, 8, 16, QChar('0')));
|
||||
return ERR_INVALID_VOLUME;
|
||||
// Check if volume can be grown
|
||||
UINT8 parentType = item->parent()->type();
|
||||
if(parentType != TreeItem::File && parentType != TreeItem::Section) {
|
||||
msg(tr("%1: can't grow root volume").arg(guidToQString(volumeHeader->FileSystemGuid)));
|
||||
return ERR_INVALID_VOLUME;
|
||||
}
|
||||
// Grow volume to fit VTF
|
||||
UINT32 newSize = volumeSize + (offset - vtfOffset) + sizeof(EFI_FFS_FILE_HEADER);
|
||||
result = growVolume(header, volumeSize, newSize);
|
||||
if (result)
|
||||
return result;
|
||||
// Determine new VTF offset
|
||||
vtfOffset = newSize - header.size() - file.size();
|
||||
if (vtfOffset % 8) {
|
||||
msg(tr("reconstruct: %1: Wrong size of Volume Top File")
|
||||
.arg(guidToQString(volumeHeader->FileSystemGuid)));
|
||||
return ERR_INVALID_FILE;
|
||||
}
|
||||
// Construct pad file
|
||||
QByteArray pad;
|
||||
result = constructPadFile(vtfOffset - offset, revision, empty, pad);
|
||||
if (result)
|
||||
return result;
|
||||
// Append constructed pad file to volume body
|
||||
reconstructed.append(pad);
|
||||
reconstructed.append(file);
|
||||
volumeSize = newSize;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Fill all following bytes with empty char
|
||||
// Append last file and fill the rest with empty char
|
||||
else {
|
||||
INT32 size = volumeHeader->FvLength - header.size() - offset - file.size();
|
||||
// Append fill
|
||||
if (size > 0)
|
||||
file.append(QByteArray(size, empty));
|
||||
reconstructed.append(file);
|
||||
UINT32 volumeBodySize = volumeSize - header.size();
|
||||
if (volumeBodySize > (UINT32) reconstructed.size()) {
|
||||
// Fill volume end with empty char
|
||||
reconstructed.append(QByteArray(volumeBodySize - reconstructed.size(), empty));
|
||||
}
|
||||
else {
|
||||
// Check if volume can be grown
|
||||
UINT8 parentType = item->parent()->type();
|
||||
if(parentType != TreeItem::File && parentType != TreeItem::Section) {
|
||||
msg(tr("%1: can't grow root volume").arg(guidToQString(volumeHeader->FileSystemGuid)));
|
||||
return ERR_INVALID_VOLUME;
|
||||
}
|
||||
// Grow volume to fit new body
|
||||
UINT32 newSize = header.size() + reconstructed.size();
|
||||
result = growVolume(header, volumeSize, newSize);
|
||||
// Fill volume end with empty char
|
||||
reconstructed.append(QByteArray(newSize - header.size() - reconstructed.size(), empty));
|
||||
volumeSize = newSize;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1590,69 +1692,11 @@ UINT8 FfsEngine::reconstruct(TreeItem* item, QQueue<QByteArray> & queue, const U
|
||||
offset += file.size();
|
||||
}
|
||||
|
||||
// Check new body size
|
||||
if (header.size() + reconstructed.size() > volumeHeader->FvLength)
|
||||
// Check new volume size
|
||||
if ((UINT32)(header.size() + reconstructed.size()) > volumeSize)
|
||||
{
|
||||
//!TODO: attemt volume grow
|
||||
msg(tr("reconstruct: Volume grow operation is not yet implemented"));
|
||||
return ERR_NOT_IMPLEMENTED;
|
||||
/*// Volumes can be children of RootItem, CapsuleItem, RegionItem, FileItem and SectionItem
|
||||
|
||||
UINT32 sizeToGrow = 0;
|
||||
UINT8 parentType = item->parent()->type();
|
||||
//!TODO: refactor this code to make it work
|
||||
// First 3 kind of volumes can be grown only if they have padding after them
|
||||
if (parentType == RootItem || parentType == CapsuleItem || parentType == RegionItem) {
|
||||
// Find next item
|
||||
for (int i = 0; i < item->parent()->childCount(); i++)
|
||||
if (item == item->parent()->child(i) && item->parent()->child(i+1) != NULL) {
|
||||
TreeItem* pad = item->parent()->child(i+1);
|
||||
// Check if that item is padding
|
||||
if (pad->type() == PaddingItem) {
|
||||
// All it's space can be used for volume growing
|
||||
sizeToGrow = pad->body().size();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Second 2 kind can just be grown up to UIN32_MAX in size
|
||||
if (parentType == TreeItem::File || parentType == TreeItem::Section) {
|
||||
sizeToGrow = UINT32_MAX - header.size() - reconstructed.size();
|
||||
}
|
||||
|
||||
// Volume is a child of some other item, this is a bug
|
||||
else {
|
||||
msg(tr("reconstructTreeItem: %1: volume is a child of incompatible item")
|
||||
.arg(guidToQString(volumeHeader->FileSystemGuid)));
|
||||
msg(tr("reconstruct: Volume grow failed"));
|
||||
return ERR_INVALID_VOLUME;
|
||||
}
|
||||
|
||||
if (sizeToGrow == 0 || (header.size() + reconstructed.size() - volumeHeader->FvLength) > sizeToGrow) {
|
||||
msg(tr("reconstruct: %1: volume can not be grown")
|
||||
.arg(guidToQString(volumeHeader->FileSystemGuid)));
|
||||
return ERR_VOLUME_GROW_FAILED;
|
||||
}
|
||||
|
||||
// Adjust new size to be representable by current FvBlockMap
|
||||
// We assume that all current volumes have only one meaningful FvBlockMap entry
|
||||
EFI_FV_BLOCK_MAP_ENTRY* blockMap = (EFI_FV_BLOCK_MAP_ENTRY*) (header.data() + sizeof(EFI_FIRMWARE_VOLUME_HEADER));
|
||||
|
||||
// Calculate new size
|
||||
UINT32 size = header.size() + reconstructed.size();
|
||||
sizeToGrow = blockMap->Length - size % blockMap->Length;
|
||||
|
||||
// Recalculate number of blocks
|
||||
blockMap->NumBlocks += sizeToGrow / blockMap->Length + 1;
|
||||
|
||||
// Set new volume size
|
||||
//!NOTE: this is dangerous and must be checked before adding volume to items tree
|
||||
volumeHeader->FvLength = 0;
|
||||
while (blockMap->NumBlocks != 0 || blockMap->Length != 0)
|
||||
volumeHeader->FvLength += blockMap->NumBlocks * blockMap->Length;
|
||||
|
||||
// Recalculate volume header checksum
|
||||
volumeHeader->Checksum = 0;
|
||||
volumeHeader->Checksum = calculateChecksum16((UINT8*) volumeHeader, volumeHeader->HeaderLength);*/
|
||||
}
|
||||
}
|
||||
// Use current volume body
|
||||
@ -1835,7 +1879,37 @@ UINT8 FfsEngine::reconstruct(TreeItem* item, QQueue<QByteArray> & queue, const U
|
||||
return ERR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
UINT8 FfsEngine::growVolume(QByteArray & header, const UINT32 size, UINT32 & newSize)
|
||||
{
|
||||
// Adjust new size to be representable by current FvBlockMap
|
||||
EFI_FIRMWARE_VOLUME_HEADER* volumeHeader = (EFI_FIRMWARE_VOLUME_HEADER*) header.data();
|
||||
EFI_FV_BLOCK_MAP_ENTRY* blockMap = (EFI_FV_BLOCK_MAP_ENTRY*) (header.data() + sizeof(EFI_FIRMWARE_VOLUME_HEADER));
|
||||
UINT32 blockMapSize = header.size() - sizeof(EFI_FIRMWARE_VOLUME_HEADER);
|
||||
UINT32 blockMapCount = blockMapSize / sizeof(EFI_FV_BLOCK_MAP_ENTRY);
|
||||
|
||||
// Check blockMap validity
|
||||
if (blockMap[blockMapCount-1].NumBlocks != 0 || blockMap[blockMapCount-1].Length != 0)
|
||||
return ERR_INVALID_VOLUME;
|
||||
|
||||
// Calculate new size
|
||||
if (newSize <= size)
|
||||
return ERR_INVALID_PARAMETER;
|
||||
newSize += blockMap->Length - newSize % blockMap->Length;
|
||||
|
||||
// Recalculate number of blocks
|
||||
blockMap->NumBlocks = newSize / blockMap->Length;
|
||||
|
||||
// Set new volume size
|
||||
volumeHeader->FvLength = 0;
|
||||
for(UINT8 i = 0; i < blockMapCount; i++) {
|
||||
volumeHeader->FvLength += blockMap[i].NumBlocks * blockMap[i].Length;
|
||||
}
|
||||
|
||||
// Recalculate volume header checksum
|
||||
volumeHeader->Checksum = 0;
|
||||
volumeHeader->Checksum = calculateChecksum16((UINT8*) volumeHeader, volumeHeader->HeaderLength);
|
||||
return ERR_SUCCESS;
|
||||
}
|
||||
|
||||
// Will be refactored later
|
||||
QByteArray FfsEngine::decompressFile(const QModelIndex& index) const
|
||||
|
16
ffsengine.h
16
ffsengine.h
@ -21,6 +21,7 @@ WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
#include "basetypes.h"
|
||||
#include "treeitem.h"
|
||||
#include "treemodel.h"
|
||||
#include "debuglistitem.h"
|
||||
|
||||
class TreeModel;
|
||||
|
||||
@ -32,10 +33,12 @@ public:
|
||||
// Default constructor and destructor
|
||||
FfsEngine(QObject *parent = 0);
|
||||
~FfsEngine(void);
|
||||
|
||||
// Returns model for Qt view classes
|
||||
TreeModel* model() const;
|
||||
// Returns current message
|
||||
QString message() const;
|
||||
|
||||
// Returns debug items queue
|
||||
QQueue<DebugListItem*> debugMessage();
|
||||
|
||||
// Firmware image parsing
|
||||
UINT8 parseInputFile(const QByteArray & buffer);
|
||||
@ -59,7 +62,8 @@ public:
|
||||
UINT8 reconstructImage(QByteArray & reconstructed);
|
||||
UINT8 constructPadFile(const UINT32 size, const UINT8 revision, const char empty, QByteArray & pad);
|
||||
UINT8 reconstruct(TreeItem* item, QQueue<QByteArray> & queue, const UINT8 revision = 2, char empty = '\xFF');
|
||||
|
||||
UINT8 growVolume(QByteArray & header, const UINT32 size, UINT32 & newSize);
|
||||
|
||||
// Operations on tree items
|
||||
UINT8 insert(const QModelIndex & index, const QByteArray & object, const UINT8 type, const UINT8 mode);
|
||||
UINT8 remove(const QModelIndex & index);
|
||||
@ -80,11 +84,11 @@ public:
|
||||
QByteArray decompressFile(const QModelIndex & index) const;
|
||||
|
||||
private:
|
||||
QString text;
|
||||
TreeItem *rootItem;
|
||||
TreeModel *treeModel;
|
||||
// Adds string to message
|
||||
void msg(const QString & message);
|
||||
// Debug window helper
|
||||
QQueue<DebugListItem*> debugItems;
|
||||
void msg(const QString & message, const QModelIndex index = QModelIndex());
|
||||
// Internal operations used in insertInTree
|
||||
bool setTreeItemName(const QString & data, const QModelIndex & index);
|
||||
bool setTreeItemText(const QString & data, const QModelIndex & index);
|
||||
|
@ -21,10 +21,12 @@ QString itemTypeToQString(const UINT8 type)
|
||||
switch (type) {
|
||||
case TreeItem::Root:
|
||||
return QObject::tr("Root");
|
||||
case TreeItem::Image:
|
||||
return QObject::tr("Image");
|
||||
case TreeItem::Capsule:
|
||||
return QObject::tr("Capsule");
|
||||
case TreeItem::Descriptor:
|
||||
return QObject::tr("Flash descriptor");
|
||||
return QObject::tr("Descriptor");
|
||||
case TreeItem::Region:
|
||||
return QObject::tr("Region");
|
||||
case TreeItem::Volume:
|
||||
@ -44,6 +46,7 @@ QString itemSubtypeToQString(const UINT8 type, const UINT8 subtype)
|
||||
{
|
||||
switch (type) {
|
||||
case TreeItem::Root:
|
||||
case TreeItem::Image:
|
||||
case TreeItem::Descriptor:
|
||||
case TreeItem::Padding:
|
||||
case TreeItem::Volume:
|
||||
|
@ -38,6 +38,7 @@ public:
|
||||
// Item types
|
||||
enum ItemTypes {
|
||||
Root,
|
||||
Image,
|
||||
Capsule,
|
||||
Descriptor,
|
||||
Region,
|
||||
|
@ -93,6 +93,9 @@ QModelIndex TreeModel::parent(const QModelIndex &index) const
|
||||
return QModelIndex();
|
||||
|
||||
TreeItem *childItem = static_cast<TreeItem*>(index.internalPointer());
|
||||
if (childItem == rootItem)
|
||||
return QModelIndex();
|
||||
|
||||
TreeItem *parentItem = childItem->parent();
|
||||
|
||||
if (parentItem == rootItem)
|
||||
|
@ -49,7 +49,7 @@ public:
|
||||
const QString & name = QString(), const QString & text = QString(), const QString & info = QString(),
|
||||
const QByteArray & header = QByteArray(), const QByteArray & body = QByteArray(), const QModelIndex & index = QModelIndex(),
|
||||
const UINT8 mode = INSERT_MODE_APPEND);
|
||||
|
||||
|
||||
private:
|
||||
TreeItem *rootItem;
|
||||
};
|
||||
|
40
uefitool.cpp
40
uefitool.cpp
@ -48,8 +48,8 @@ UEFITool::~UEFITool()
|
||||
|
||||
void UEFITool::init()
|
||||
{
|
||||
// Clear UI components
|
||||
ui->debugEdit->clear();
|
||||
// Clear components
|
||||
ui->debugListWidget->clear();
|
||||
ui->infoEdit->clear();
|
||||
|
||||
// Disable all actions except openImageFile
|
||||
@ -72,6 +72,7 @@ void UEFITool::init()
|
||||
connect(ui->structureTreeView, SIGNAL(expanded(const QModelIndex &)), this, SLOT(resizeTreeViewColums(void)));
|
||||
connect(ui->structureTreeView->selectionModel(), SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)),
|
||||
this, SLOT(populateUi(const QModelIndex &)));
|
||||
connect(ui->debugListWidget, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(scrollTreeView(QListWidgetItem*)));
|
||||
|
||||
resizeTreeViewColums();
|
||||
}
|
||||
@ -88,7 +89,10 @@ void UEFITool::populateUi(const QModelIndex ¤t)
|
||||
|| ffsEngine->isOfType(TreeItem::Section, current));
|
||||
ui->actionInsertInto->setEnabled(ffsEngine->isOfType(TreeItem::Volume, current)
|
||||
|| ffsEngine->isOfType(TreeItem::File, current)
|
||||
|| ffsEngine->isOfType(TreeItem::Section, current));
|
||||
|| (ffsEngine->isOfType(TreeItem::Section, current)
|
||||
&& (ffsEngine->isOfSubtype(EFI_SECTION_COMPRESSION, current)
|
||||
|| ffsEngine->isOfSubtype(EFI_SECTION_GUID_DEFINED, current)
|
||||
|| ffsEngine->isOfSubtype(EFI_SECTION_DISPOSABLE, current))));
|
||||
ui->actionInsertBefore->setEnabled(ffsEngine->isOfType(TreeItem::File, current)
|
||||
|| ffsEngine->isOfType(TreeItem::Section, current));
|
||||
ui->actionInsertAfter->setEnabled(ffsEngine->isOfType(TreeItem::File, current)
|
||||
@ -100,7 +104,7 @@ void UEFITool::remove()
|
||||
{
|
||||
UINT8 result = ffsEngine->remove(currentIndex);
|
||||
if (result) {
|
||||
ui->debugEdit->setPlainText(ffsEngine->message());
|
||||
|
||||
}
|
||||
else
|
||||
ui->actionSaveImageFile->setEnabled(true);
|
||||
@ -115,7 +119,7 @@ void UEFITool::insert(const UINT8 mode)
|
||||
|
||||
UINT8 type;
|
||||
UINT8 objectType;
|
||||
if (mode == INSERT_MODE_BEFORE || mode == INSERT_MODE_BEFORE)
|
||||
if (mode == INSERT_MODE_BEFORE || mode == INSERT_MODE_AFTER)
|
||||
type = item->parent()->type();
|
||||
else
|
||||
type = item->type();
|
||||
@ -199,7 +203,7 @@ void UEFITool::saveImageFile()
|
||||
if (result)
|
||||
{
|
||||
ui->statusBar->showMessage(tr("Reconstruction failed (%1)").arg(result));
|
||||
ui->debugEdit->setPlainText(ffsEngine->message());
|
||||
showDebugMessage();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -207,7 +211,7 @@ void UEFITool::saveImageFile()
|
||||
outputFile.write(reconstructed);
|
||||
outputFile.close();
|
||||
ui->statusBar->showMessage(tr("Reconstructed image written"));
|
||||
ui->debugEdit->setPlainText(ffsEngine->message());
|
||||
showDebugMessage();
|
||||
}
|
||||
|
||||
void UEFITool::resizeTreeViewColums()
|
||||
@ -251,8 +255,7 @@ void UEFITool::openImageFile(QString path)
|
||||
else
|
||||
ui->statusBar->showMessage(tr("Opened: %1").arg(fileInfo.fileName()));
|
||||
|
||||
ui->debugEdit->appendPlainText(ffsEngine->message());
|
||||
|
||||
showDebugMessage();
|
||||
resizeTreeViewColums();
|
||||
}
|
||||
|
||||
@ -319,3 +322,22 @@ void UEFITool::dropEvent(QDropEvent* event)
|
||||
openImageFile(path);
|
||||
}
|
||||
|
||||
void UEFITool::showDebugMessage()
|
||||
{
|
||||
ui->debugListWidget->clear();
|
||||
QQueue<DebugListItem*> debugItems = ffsEngine->debugMessage();
|
||||
for (int i = 0; i < debugItems.count(); i++) {
|
||||
ui->debugListWidget->addItem((QListWidgetItem*) debugItems.at(i));
|
||||
}
|
||||
}
|
||||
|
||||
void UEFITool::scrollTreeView(QListWidgetItem* item)
|
||||
{
|
||||
DebugListItem* debugItem = (DebugListItem*) item;
|
||||
QModelIndex index = debugItem->index();
|
||||
if (index.isValid()) {
|
||||
ui->structureTreeView->scrollTo(index);
|
||||
ui->structureTreeView->selectionModel()->select(currentIndex, QItemSelectionModel::Clear);
|
||||
ui->structureTreeView->selectionModel()->select(index, QItemSelectionModel::Select);
|
||||
}
|
||||
}
|
@ -27,6 +27,7 @@
|
||||
#include <QUrl>
|
||||
|
||||
#include "basetypes.h"
|
||||
#include "ffs.h"
|
||||
#include "ffsengine.h"
|
||||
|
||||
namespace Ui {
|
||||
@ -58,6 +59,7 @@ private slots:
|
||||
void insertAfter();
|
||||
void replace();
|
||||
void remove();
|
||||
void scrollTreeView(QListWidgetItem* item);
|
||||
|
||||
private:
|
||||
Ui::UEFITool * ui;
|
||||
@ -66,6 +68,7 @@ private:
|
||||
|
||||
void dragEnterEvent(QDragEnterEvent* event);
|
||||
void dropEvent(QDropEvent* event);
|
||||
void showDebugMessage();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -11,6 +11,7 @@ SOURCES += main.cpp \
|
||||
ffsengine.cpp \
|
||||
treeitem.cpp \
|
||||
treemodel.cpp \
|
||||
debuglistitem.cpp \
|
||||
LZMA/LzmaCompress.c \
|
||||
LZMA/LzmaDecompress.c \
|
||||
LZMA/SDK/C/LzFind.c \
|
||||
@ -28,6 +29,7 @@ HEADERS += uefitool.h \
|
||||
ffsengine.h \
|
||||
treeitem.h \
|
||||
treemodel.h \
|
||||
debuglistitem.h \
|
||||
LZMA/LzmaCompress.h \
|
||||
LZMA/LzmaDecompress.h \
|
||||
Tiano/EfiTianoDecompress.h \
|
||||
|
48
uefitool.ui
48
uefitool.ui
@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>900</width>
|
||||
<height>600</height>
|
||||
<width>1100</width>
|
||||
<height>700</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
@ -20,7 +20,7 @@
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>UEFITool 0.5.0</string>
|
||||
<string>UEFITool 0.6.0</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralWidget">
|
||||
<property name="sizePolicy">
|
||||
@ -142,6 +142,12 @@
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>120</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Debug</string>
|
||||
</property>
|
||||
@ -153,41 +159,7 @@
|
||||
<number>5</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QPlainTextEdit" name="debugEdit">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>80</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="baseSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>50</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Consolas</family>
|
||||
<pointsize>10</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="undoRedoEnabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="centerOnScroll">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QListWidget" name="debugListWidget"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
|
Loading…
Reference in New Issue
Block a user