mirror of
https://github.com/LongSoft/UEFITool.git
synced 2024-11-25 09:28: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
|
344
ffsengine.cpp
344
ffsengine.cpp
@ -46,14 +46,14 @@ TreeModel* FfsEngine::model() const
|
|||||||
return treeModel;
|
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
|
QByteArray FfsEngine::header(const QModelIndex& index) const
|
||||||
@ -148,9 +148,11 @@ UINT8 FfsEngine::parseInputFile(const QByteArray & buffer)
|
|||||||
{
|
{
|
||||||
UINT32 capsuleHeaderSize = 0;
|
UINT32 capsuleHeaderSize = 0;
|
||||||
FLASH_DESCRIPTOR_HEADER* descriptorHeader = NULL;
|
FLASH_DESCRIPTOR_HEADER* descriptorHeader = NULL;
|
||||||
|
QModelIndex index;
|
||||||
QByteArray flashImage;
|
QByteArray flashImage;
|
||||||
QByteArray bios;
|
QByteArray bios;
|
||||||
QModelIndex index;
|
QByteArray header;
|
||||||
|
QByteArray body;
|
||||||
QString name;
|
QString name;
|
||||||
QString info;
|
QString info;
|
||||||
|
|
||||||
@ -166,8 +168,8 @@ UINT8 FfsEngine::parseInputFile(const QByteArray & buffer)
|
|||||||
// Get info
|
// Get info
|
||||||
EFI_CAPSULE_HEADER* capsuleHeader = (EFI_CAPSULE_HEADER*) buffer.constData();
|
EFI_CAPSULE_HEADER* capsuleHeader = (EFI_CAPSULE_HEADER*) buffer.constData();
|
||||||
capsuleHeaderSize = capsuleHeader->HeaderSize;
|
capsuleHeaderSize = capsuleHeader->HeaderSize;
|
||||||
QByteArray header = buffer.left(capsuleHeaderSize);
|
header = buffer.left(capsuleHeaderSize);
|
||||||
QByteArray body = buffer.right(buffer.size() - capsuleHeaderSize);
|
body = buffer.right(buffer.size() - capsuleHeaderSize);
|
||||||
name = tr("UEFI capsule");
|
name = tr("UEFI capsule");
|
||||||
info = tr("Header size: %1\nFlags: %2\nImage size: %3")
|
info = tr("Header size: %1\nFlags: %2\nImage size: %3")
|
||||||
.arg(capsuleHeader->HeaderSize, 8, 16, QChar('0'))
|
.arg(capsuleHeader->HeaderSize, 8, 16, QChar('0'))
|
||||||
@ -182,8 +184,8 @@ UINT8 FfsEngine::parseInputFile(const QByteArray & buffer)
|
|||||||
// Get info
|
// Get info
|
||||||
APTIO_CAPSULE_HEADER* aptioCapsuleHeader = (APTIO_CAPSULE_HEADER*) buffer.constData();
|
APTIO_CAPSULE_HEADER* aptioCapsuleHeader = (APTIO_CAPSULE_HEADER*) buffer.constData();
|
||||||
capsuleHeaderSize = aptioCapsuleHeader->RomImageOffset;
|
capsuleHeaderSize = aptioCapsuleHeader->RomImageOffset;
|
||||||
QByteArray header = buffer.left(capsuleHeaderSize);
|
header = buffer.left(capsuleHeaderSize);
|
||||||
QByteArray body = buffer.right(buffer.size() - capsuleHeaderSize);
|
body = buffer.right(buffer.size() - capsuleHeaderSize);
|
||||||
name = tr("AMI Aptio capsule");
|
name = tr("AMI Aptio capsule");
|
||||||
info = tr("Header size: %1\nFlags: %2\nImage size: %3")
|
info = tr("Header size: %1\nFlags: %2\nImage size: %3")
|
||||||
.arg(aptioCapsuleHeader->RomImageOffset, 4, 16, QChar('0'))
|
.arg(aptioCapsuleHeader->RomImageOffset, 4, 16, QChar('0'))
|
||||||
@ -193,6 +195,14 @@ UINT8 FfsEngine::parseInputFile(const QByteArray & buffer)
|
|||||||
// Add tree item
|
// Add tree item
|
||||||
index = treeModel->addItem(TreeItem::Capsule, TreeItem::AptioCapsule, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body);
|
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
|
// Skip capsule header to have flash chip image
|
||||||
flashImage = buffer.right(buffer.size() - capsuleHeaderSize);
|
flashImage = buffer.right(buffer.size() - capsuleHeaderSize);
|
||||||
@ -230,7 +240,7 @@ UINT8 FfsEngine::parseInputFile(const QByteArray & buffer)
|
|||||||
.arg(descriptorMap->NumberOfIccTableEntries);
|
.arg(descriptorMap->NumberOfIccTableEntries);
|
||||||
//!TODO: more info about descriptor
|
//!TODO: more info about descriptor
|
||||||
// Add tree item
|
// 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
|
// Parse regions
|
||||||
QModelIndex regionIndex;
|
QModelIndex regionIndex;
|
||||||
@ -284,26 +294,26 @@ UINT8 FfsEngine::parseRegion(const QByteArray & flashImage, UINT8 regionSubtype,
|
|||||||
// Check region base to be in buffer
|
// Check region base to be in buffer
|
||||||
if (regionOffset >= flashImageSize)
|
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)
|
if (twoChips)
|
||||||
msg(tr("Two flash chips installed, so it could be in another flash chip\n"
|
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
|
else
|
||||||
msg(tr("One flash chip installed, so it is an error caused by damaged or incomplete dump"));
|
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));
|
msg(tr("Absence of %1 region assumed").arg(regionName), parent);
|
||||||
return ERR_INVALID_REGION;
|
return ERR_INVALID_REGION;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check region to be fully present in buffer
|
// Check region to be fully present in buffer
|
||||||
else if (regionOffset + regionSize > flashImageSize)
|
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)
|
if (twoChips)
|
||||||
msg(tr("Two flash chips installed, so it could be in another flash chip\n"
|
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
|
else
|
||||||
msg(tr("One flash chip installed, so it is an error caused by damaged or incomplete dump"));
|
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));
|
msg(tr("Absence of %1 region assumed\n").arg(regionName), parent);
|
||||||
return ERR_INVALID_REGION;
|
return ERR_INVALID_REGION;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -337,7 +347,7 @@ UINT8 FfsEngine::parseRegion(const QByteArray & flashImage, UINT8 regionSubtype,
|
|||||||
meVersionOffset = body.indexOf(ME_VERSION_SIGNATURE);
|
meVersionOffset = body.indexOf(ME_VERSION_SIGNATURE);
|
||||||
if (meVersionOffset < 0){
|
if (meVersionOffset < 0){
|
||||||
info += tr("\nVersion: unknown");
|
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 {
|
else {
|
||||||
meVersion = (ME_VERSION*) (body.constData() + meVersionOffset);
|
meVersion = (ME_VERSION*) (body.constData() + meVersionOffset);
|
||||||
@ -356,7 +366,7 @@ UINT8 FfsEngine::parseRegion(const QByteArray & flashImage, UINT8 regionSubtype,
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
name = tr("Unknown region");
|
name = tr("Unknown region");
|
||||||
msg(tr("insertInTree: Unknown region"));
|
msg(tr("parseRegion: Unknown region"), parent);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -415,7 +425,7 @@ UINT8 FfsEngine::parseBios(const QByteArray & bios, const QModelIndex & parent)
|
|||||||
|
|
||||||
//Check that volume is fully present in input
|
//Check that volume is fully present in input
|
||||||
if (volumeOffset + volumeSize > (UINT32) bios.size()) {
|
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;
|
return ERR_INVALID_VOLUME;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -448,7 +458,7 @@ UINT8 FfsEngine::parseBios(const QByteArray & bios, const QModelIndex & parent)
|
|||||||
|| alignment32 || alignment64 || alignment128 || alignment256
|
|| alignment32 || alignment64 || alignment128 || alignment256
|
||||||
|| alignment512 || alignment1k || alignment2k || alignment4k
|
|| alignment512 || alignment1k || alignment2k || alignment4k
|
||||||
|| alignment8k || alignment16k || alignment32k || alignment64k))
|
|| 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
|
// Assume that smaller alignment value consumes greater
|
||||||
//!TODO: refactor this code
|
//!TODO: refactor this code
|
||||||
@ -488,7 +498,7 @@ UINT8 FfsEngine::parseBios(const QByteArray & bios, const QModelIndex & parent)
|
|||||||
|
|
||||||
// Check alignment
|
// Check alignment
|
||||||
if (volumeOffset % alignment) {
|
if (volumeOffset % alignment) {
|
||||||
msg(tr("parseBios: Unaligned revision 1 volume"));
|
msg(tr("parseBios: Unaligned revision 1 volume"), parent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (volumeHeader->Revision == 2) {
|
else if (volumeHeader->Revision == 2) {
|
||||||
@ -497,16 +507,16 @@ UINT8 FfsEngine::parseBios(const QByteArray & bios, const QModelIndex & parent)
|
|||||||
|
|
||||||
// Check alignment
|
// Check alignment
|
||||||
if (volumeOffset % alignment) {
|
if (volumeOffset % alignment) {
|
||||||
msg(tr("parseBios: Unaligned revision 2 volume"));
|
msg(tr("parseBios: Unaligned revision 2 volume"), parent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
msg(tr("parseBios: Unknown volume revision (%1)").arg(volumeHeader->Revision));
|
msg(tr("parseBios: Unknown volume revision (%1)").arg(volumeHeader->Revision), parent);
|
||||||
|
|
||||||
// Parse volume
|
// Parse volume
|
||||||
UINT8 result = parseVolume(bios.mid(volumeOffset, volumeSize), parent);
|
UINT8 result = parseVolume(bios.mid(volumeOffset, volumeSize), parent);
|
||||||
if (result)
|
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
|
// Go to next volume
|
||||||
prevVolumeOffset = volumeOffset;
|
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)
|
if (QByteArray((const char*) &volumeHeader->Signature, sizeof(volumeHeader->Signature)) != EFI_FV_SIGNATURE)
|
||||||
return ERR_INVALID_VOLUME;
|
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;
|
return ERR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -575,7 +595,7 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, const QModelIndex & par
|
|||||||
}
|
}
|
||||||
// Other GUID
|
// Other GUID
|
||||||
else {
|
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;
|
parseCurrentVolume = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -585,7 +605,7 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, const QModelIndex & par
|
|||||||
|
|
||||||
// Check header checksum by recalculating it
|
// Check header checksum by recalculating it
|
||||||
if (!calculateChecksum16((UINT8*) volumeHeader, volumeHeader->HeaderLength)) {
|
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
|
// 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;
|
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
|
// Get info
|
||||||
QString name = guidToQString(volumeHeader->FileSystemGuid);
|
QString name = guidToQString(volumeHeader->FileSystemGuid);
|
||||||
QString info = tr("Size: %1\nRevision: %2\nAttributes: %3\nHeader size: %4")
|
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->Revision)
|
||||||
.arg(volumeHeader->Attributes, 8, 16, QChar('0'))
|
.arg(volumeHeader->Attributes, 8, 16, QChar('0'))
|
||||||
.arg(volumeHeader->HeaderLength, 4, 16, QChar('0'));
|
.arg(volumeHeader->HeaderLength, 4, 16, QChar('0'));
|
||||||
|
|
||||||
// Add tree item
|
// Add tree item
|
||||||
QByteArray header = volume.left(headerSize);
|
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);
|
QModelIndex index = treeModel->addItem(TreeItem::Volume, 0, COMPRESSION_ALGORITHM_NONE, name, "", info, header, body, parent, mode);
|
||||||
|
|
||||||
// Do not parse volumes with unknown FS
|
// 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
|
// Search for and parse all files
|
||||||
UINT32 fileOffset = headerSize;
|
UINT32 fileOffset = headerSize;
|
||||||
UINT32 fileSize;
|
UINT32 fileSize;
|
||||||
UINT8 result;
|
|
||||||
QQueue<QByteArray> files;
|
QQueue<QByteArray> files;
|
||||||
|
|
||||||
while (true) {
|
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)
|
// Check file size to be at least sizeof(EFI_FFS_FILE_HEADER)
|
||||||
if (fileSize < 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;
|
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];
|
UINT8 alignmentPower = ffsAlignmentTable[(fileHeader->Attributes & FFS_ATTRIB_DATA_ALIGNMENT) >> 3];
|
||||||
UINT32 alignment = pow(2, alignmentPower);
|
UINT32 alignment = pow(2, alignmentPower);
|
||||||
if ((fileOffset + sizeof(EFI_FFS_FILE_HEADER)) % alignment) {
|
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
|
// Check file GUID
|
||||||
if (fileHeader->Type != EFI_FV_FILETYPE_PAD && files.indexOf(header.left(sizeof(EFI_GUID))) != -1)
|
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
|
// Add file GUID to queue
|
||||||
files.enqueue(header.left(sizeof(EFI_GUID)));
|
files.enqueue(header.left(sizeof(EFI_GUID)));
|
||||||
@ -656,7 +691,7 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, const QModelIndex & par
|
|||||||
// Parse file
|
// Parse file
|
||||||
result = parseFile(file, volumeHeader->Revision, empty, index);
|
result = parseFile(file, volumeHeader->Revision, empty, index);
|
||||||
if (result)
|
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
|
// Move to next file
|
||||||
fileOffset += fileSize;
|
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")
|
msg(tr("parseVolume: %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')));
|
.arg(calculated, 2, 16, QChar('0')), parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check data checksum
|
// 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")
|
msg(tr("parseVolume: %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')));
|
.arg(calculated, 2, 16, QChar('0')), parent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Data checksum must be one of predefined values
|
// 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) {
|
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")
|
msg(tr("parseVolume: %1, stored data checksum %2 differs from standard value")
|
||||||
.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')), 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")
|
msg(tr("parseVolume: %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')));
|
.arg(fileHeader->IntegrityCheck.TailReference, 4, 16, QChar('0')), parent);
|
||||||
|
|
||||||
// Remove tail from file body
|
// Remove tail from file body
|
||||||
body = body.left(body.size() - sizeof(UINT16));
|
body = body.left(body.size() - sizeof(UINT16));
|
||||||
@ -782,7 +817,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')));
|
msg(tr("parseVolume: Unknown file type (%1)").arg(fileHeader->Type, 2, 16, QChar('0')), parent);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check for empty file
|
// Check for empty file
|
||||||
@ -815,7 +850,7 @@ 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));
|
msg(tr("parseVolume: Parse file as BIOS failed (%1)").arg(result), index);
|
||||||
return ERR_SUCCESS;
|
return ERR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -874,8 +909,8 @@ UINT8 FfsEngine::parseSection(const QByteArray & section, const UINT8 revision,
|
|||||||
QByteArray header;
|
QByteArray header;
|
||||||
QByteArray body;
|
QByteArray body;
|
||||||
UINT32 headerSize;
|
UINT32 headerSize;
|
||||||
QModelIndex index;
|
|
||||||
UINT8 result;
|
UINT8 result;
|
||||||
|
QModelIndex index;
|
||||||
|
|
||||||
switch (sectionHeader->Type) {
|
switch (sectionHeader->Type) {
|
||||||
// Encapsulated sections
|
// Encapsulated sections
|
||||||
@ -891,7 +926,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));
|
msg(tr("parseFile: Section decompression failed (%1)").arg(result), parent);
|
||||||
parseCurrentSection = false;
|
parseCurrentSection = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -933,7 +968,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));
|
msg(tr("parseFile: GUID defined section can not be decompressed (%1)").arg(result), parent);
|
||||||
parseCurrentSection = false;
|
parseCurrentSection = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1035,7 +1070,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));
|
msg(tr("parseFile: Firmware volume image can not be parsed (%1)").arg(result), index);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1054,12 +1089,11 @@ 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));
|
msg(tr("parseFile: Raw section can not be parsed as BIOS (%1)").arg(result), index);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
msg(tr("parseFile: Section with unknown type (%1)").arg(sectionHeader->Type, 2, 16, QChar('0')));
|
|
||||||
header = section.left(sizeof(EFI_COMMON_SECTION_HEADER));
|
header = section.left(sizeof(EFI_COMMON_SECTION_HEADER));
|
||||||
body = section.mid(sizeof(EFI_COMMON_SECTION_HEADER), sectionSize - sizeof(EFI_COMMON_SECTION_HEADER));
|
body = section.mid(sizeof(EFI_COMMON_SECTION_HEADER), sectionSize - sizeof(EFI_COMMON_SECTION_HEADER));
|
||||||
// Get info
|
// Get info
|
||||||
@ -1069,7 +1103,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, parent, mode);
|
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;
|
return ERR_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -1091,7 +1125,7 @@ UINT8 FfsEngine::insert(const QModelIndex & index, const QByteArray & object, co
|
|||||||
// Parent type must be volume
|
// Parent type must be volume
|
||||||
TreeItem * parentItem = static_cast<TreeItem*>(parent.internalPointer());
|
TreeItem * parentItem = static_cast<TreeItem*>(parent.internalPointer());
|
||||||
if (parentItem->type() != TreeItem::Volume) {
|
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;
|
return ERR_INVALID_VOLUME;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1122,7 +1156,7 @@ UINT8 FfsEngine::insert(const QModelIndex & index, const QByteArray & object, co
|
|||||||
parentItem->subtype() == EFI_SECTION_DISPOSABLE))) {
|
parentItem->subtype() == EFI_SECTION_DISPOSABLE))) {
|
||||||
QModelIndex volumeIndex = findParentOfType(TreeItem::Volume, parent);
|
QModelIndex volumeIndex = findParentOfType(TreeItem::Volume, parent);
|
||||||
if (!volumeIndex.isValid()) {
|
if (!volumeIndex.isValid()) {
|
||||||
msg(tr("insert: Parent volume not found"));
|
msg(tr("insert: Parent volume not found"), parent);
|
||||||
return ERR_INVALID_VOLUME;
|
return ERR_INVALID_VOLUME;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1139,7 +1173,7 @@ UINT8 FfsEngine::insert(const QModelIndex & index, const QByteArray & object, co
|
|||||||
treeModel->setItemAction(TreeItem::Reconstruct, 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"));
|
msg(tr("insert: section can't be inserted into something that is not file or encapsulation section"), parent);
|
||||||
return ERR_INVALID_FILE;
|
return ERR_INVALID_FILE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1164,8 +1198,6 @@ UINT8 FfsEngine::remove(const QModelIndex & index)
|
|||||||
return ERR_SUCCESS;
|
return ERR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Compression routines
|
// Compression routines
|
||||||
UINT8 FfsEngine::decompress(const QByteArray & compressedData, const UINT8 compressionType, QByteArray & decompressedData, UINT8 * algorithm)
|
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];
|
scratch = new UINT8[scratchSize];
|
||||||
|
|
||||||
// Decompress section data
|
// Decompress section data
|
||||||
|
// Try EFI1.1 decompression first
|
||||||
if (ERR_SUCCESS != EfiDecompress(data, dataSize, decompressed, decompressedSize, scratch, scratchSize)) {
|
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 (ERR_SUCCESS != TianoDecompress(data, dataSize, decompressed, decompressedSize, scratch, scratchSize)) {
|
||||||
if (algorithm)
|
if (algorithm)
|
||||||
*algorithm = COMPRESSION_ALGORITHM_UNKNOWN;
|
*algorithm = COMPRESSION_ALGORITHM_UNKNOWN;
|
||||||
@ -1212,9 +1246,34 @@ UINT8 FfsEngine::decompress(const QByteArray & compressedData, const UINT8 compr
|
|||||||
else if (algorithm)
|
else if (algorithm)
|
||||||
*algorithm = COMPRESSION_ALGORITHM_TIANO;
|
*algorithm = COMPRESSION_ALGORITHM_TIANO;
|
||||||
}
|
}
|
||||||
else if (algorithm)
|
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;
|
*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);
|
decompressedData = QByteArray((const char*) decompressed, decompressedSize);
|
||||||
|
|
||||||
// Free allocated memory
|
// Free allocated memory
|
||||||
@ -1352,8 +1411,6 @@ UINT8 FfsEngine::compress(const QByteArray & data, const UINT8 algorithm, QByteA
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Construction routines
|
// Construction routines
|
||||||
UINT8 FfsEngine::reconstructImage(QByteArray & reconstructed)
|
UINT8 FfsEngine::reconstructImage(QByteArray & reconstructed)
|
||||||
{
|
{
|
||||||
@ -1380,7 +1437,7 @@ UINT8 FfsEngine::constructPadFile(const UINT32 size, const UINT8 revision, const
|
|||||||
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;
|
header->State = 0xF8; //TODO: Check state of pad file in section with empty = 0x00
|
||||||
// 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;
|
||||||
@ -1451,6 +1508,7 @@ UINT8 FfsEngine::reconstruct(TreeItem* item, QQueue<QByteArray> & queue, const U
|
|||||||
if (item->subtype() == TreeItem::AptioCapsule)
|
if (item->subtype() == TreeItem::AptioCapsule)
|
||||||
msg(tr("reconstruct: Aptio extended header checksum and signature are now invalid"));
|
msg(tr("reconstruct: Aptio extended header checksum and signature are now invalid"));
|
||||||
case TreeItem::Root:
|
case TreeItem::Root:
|
||||||
|
case TreeItem::Image:
|
||||||
case TreeItem::Descriptor:
|
case TreeItem::Descriptor:
|
||||||
case TreeItem::Region:
|
case TreeItem::Region:
|
||||||
case TreeItem::Padding:
|
case TreeItem::Padding:
|
||||||
@ -1491,7 +1549,7 @@ UINT8 FfsEngine::reconstruct(TreeItem* item, QQueue<QByteArray> & queue, const U
|
|||||||
return result;
|
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)
|
foreach(const QByteArray & child, childrenQueue)
|
||||||
{
|
{
|
||||||
EFI_FFS_FILE_HEADER* fileHeader = (EFI_FFS_FILE_HEADER*) child.constData();
|
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);
|
childrenQueue.removeAll(child);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get volume size
|
||||||
|
UINT32 volumeSize;
|
||||||
|
result = getVolumeSize(header, 0, volumeSize);
|
||||||
|
if (result)
|
||||||
|
return result;
|
||||||
|
|
||||||
// Construct new volume body
|
// Construct new volume body
|
||||||
UINT32 offset = 0;
|
UINT32 offset = 0;
|
||||||
while (!childrenQueue.isEmpty())
|
while (!childrenQueue.isEmpty())
|
||||||
@ -1539,14 +1603,14 @@ UINT8 FfsEngine::reconstruct(TreeItem* item, QQueue<QByteArray> & queue, const U
|
|||||||
offset += size;
|
offset += size;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this is a last file in volume
|
// If this is the last file in volume
|
||||||
if (childrenQueue.isEmpty())
|
if (childrenQueue.isEmpty())
|
||||||
{
|
{
|
||||||
// Last file of the volume can be Volume Top File
|
// Last file of the volume can be Volume Top File
|
||||||
if (file.left(sizeof(EFI_GUID)) == EFI_FFS_VOLUME_TOP_FILE_GUID) {
|
if (file.left(sizeof(EFI_GUID)) == EFI_FFS_VOLUME_TOP_FILE_GUID) {
|
||||||
// Determine correct VTF offset
|
// Determine correct VTF offset
|
||||||
UINT32 vtfOffset = volumeHeader->FvLength - header.size() - file.size();
|
UINT32 vtfOffset = volumeSize - header.size() - file.size();
|
||||||
if (offset % 8) {
|
if (vtfOffset % 8) {
|
||||||
msg(tr("reconstruct: %1: Wrong size of Volume Top File")
|
msg(tr("reconstruct: %1: Wrong size of Volume Top File")
|
||||||
.arg(guidToQString(volumeHeader->FileSystemGuid)));
|
.arg(guidToQString(volumeHeader->FileSystemGuid)));
|
||||||
return ERR_INVALID_FILE;
|
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
|
// Append constructed pad file to volume body
|
||||||
reconstructed.append(pad);
|
reconstructed.append(pad);
|
||||||
offset = vtfOffset;
|
offset = vtfOffset;
|
||||||
// Ensure that no more files will be in this volume
|
|
||||||
childrenQueue.clear();
|
|
||||||
}
|
}
|
||||||
// No more space left in volume
|
// No more space left in volume
|
||||||
else if (vtfOffset < offset) {
|
else if (vtfOffset < offset) {
|
||||||
//!TODO: attempt volume grow
|
// Check if volume can be grown
|
||||||
msg(tr("reconstruct: %1: can't insert VTF, need additional %2 bytes")
|
UINT8 parentType = item->parent()->type();
|
||||||
.arg(guidToQString(volumeHeader->FileSystemGuid))
|
if(parentType != TreeItem::File && parentType != TreeItem::Section) {
|
||||||
.arg(offset - vtfOffset, 8, 16, QChar('0')));
|
msg(tr("%1: can't grow root volume").arg(guidToQString(volumeHeader->FileSystemGuid)));
|
||||||
return ERR_INVALID_VOLUME;
|
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;
|
||||||
}
|
}
|
||||||
// Fill all following bytes with empty char
|
// 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Append last file and fill the rest with empty char
|
||||||
else {
|
else {
|
||||||
INT32 size = volumeHeader->FvLength - header.size() - offset - file.size();
|
reconstructed.append(file);
|
||||||
// Append fill
|
UINT32 volumeBodySize = volumeSize - header.size();
|
||||||
if (size > 0)
|
if (volumeBodySize > (UINT32) reconstructed.size()) {
|
||||||
file.append(QByteArray(size, empty));
|
// 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,70 +1692,12 @@ UINT8 FfsEngine::reconstruct(TreeItem* item, QQueue<QByteArray> & queue, const U
|
|||||||
offset += file.size();
|
offset += file.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check new body size
|
// Check new volume size
|
||||||
if (header.size() + reconstructed.size() > volumeHeader->FvLength)
|
if ((UINT32)(header.size() + reconstructed.size()) > volumeSize)
|
||||||
{
|
{
|
||||||
//!TODO: attemt volume grow
|
msg(tr("reconstruct: Volume grow failed"));
|
||||||
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)));
|
|
||||||
return ERR_INVALID_VOLUME;
|
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
|
// Use current volume body
|
||||||
else
|
else
|
||||||
@ -1835,7 +1879,37 @@ UINT8 FfsEngine::reconstruct(TreeItem* item, QQueue<QByteArray> & queue, const U
|
|||||||
return ERR_NOT_IMPLEMENTED;
|
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
|
// Will be refactored later
|
||||||
QByteArray FfsEngine::decompressFile(const QModelIndex& index) const
|
QByteArray FfsEngine::decompressFile(const QModelIndex& index) const
|
||||||
|
14
ffsengine.h
14
ffsengine.h
@ -21,6 +21,7 @@ WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|||||||
#include "basetypes.h"
|
#include "basetypes.h"
|
||||||
#include "treeitem.h"
|
#include "treeitem.h"
|
||||||
#include "treemodel.h"
|
#include "treemodel.h"
|
||||||
|
#include "debuglistitem.h"
|
||||||
|
|
||||||
class TreeModel;
|
class TreeModel;
|
||||||
|
|
||||||
@ -32,10 +33,12 @@ public:
|
|||||||
// Default constructor and destructor
|
// Default constructor and destructor
|
||||||
FfsEngine(QObject *parent = 0);
|
FfsEngine(QObject *parent = 0);
|
||||||
~FfsEngine(void);
|
~FfsEngine(void);
|
||||||
|
|
||||||
// Returns model for Qt view classes
|
// Returns model for Qt view classes
|
||||||
TreeModel* model() const;
|
TreeModel* model() const;
|
||||||
// Returns current message
|
|
||||||
QString message() const;
|
// Returns debug items queue
|
||||||
|
QQueue<DebugListItem*> debugMessage();
|
||||||
|
|
||||||
// Firmware image parsing
|
// Firmware image parsing
|
||||||
UINT8 parseInputFile(const QByteArray & buffer);
|
UINT8 parseInputFile(const QByteArray & buffer);
|
||||||
@ -59,6 +62,7 @@ public:
|
|||||||
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 char empty, QByteArray & pad);
|
||||||
UINT8 reconstruct(TreeItem* item, QQueue<QByteArray> & queue, const UINT8 revision = 2, char empty = '\xFF');
|
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
|
// Operations on tree items
|
||||||
UINT8 insert(const QModelIndex & index, const QByteArray & object, const UINT8 type, const UINT8 mode);
|
UINT8 insert(const QModelIndex & index, const QByteArray & object, const UINT8 type, const UINT8 mode);
|
||||||
@ -80,11 +84,11 @@ public:
|
|||||||
QByteArray decompressFile(const QModelIndex & index) const;
|
QByteArray decompressFile(const QModelIndex & index) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString text;
|
|
||||||
TreeItem *rootItem;
|
TreeItem *rootItem;
|
||||||
TreeModel *treeModel;
|
TreeModel *treeModel;
|
||||||
// Adds string to message
|
// Debug window helper
|
||||||
void msg(const QString & message);
|
QQueue<DebugListItem*> debugItems;
|
||||||
|
void msg(const QString & message, const QModelIndex index = QModelIndex());
|
||||||
// Internal operations used in insertInTree
|
// Internal operations used in insertInTree
|
||||||
bool setTreeItemName(const QString & data, const QModelIndex & index);
|
bool setTreeItemName(const QString & data, const QModelIndex & index);
|
||||||
bool setTreeItemText(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) {
|
switch (type) {
|
||||||
case TreeItem::Root:
|
case TreeItem::Root:
|
||||||
return QObject::tr("Root");
|
return QObject::tr("Root");
|
||||||
|
case TreeItem::Image:
|
||||||
|
return QObject::tr("Image");
|
||||||
case TreeItem::Capsule:
|
case TreeItem::Capsule:
|
||||||
return QObject::tr("Capsule");
|
return QObject::tr("Capsule");
|
||||||
case TreeItem::Descriptor:
|
case TreeItem::Descriptor:
|
||||||
return QObject::tr("Flash descriptor");
|
return QObject::tr("Descriptor");
|
||||||
case TreeItem::Region:
|
case TreeItem::Region:
|
||||||
return QObject::tr("Region");
|
return QObject::tr("Region");
|
||||||
case TreeItem::Volume:
|
case TreeItem::Volume:
|
||||||
@ -44,6 +46,7 @@ QString itemSubtypeToQString(const UINT8 type, const UINT8 subtype)
|
|||||||
{
|
{
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case TreeItem::Root:
|
case TreeItem::Root:
|
||||||
|
case TreeItem::Image:
|
||||||
case TreeItem::Descriptor:
|
case TreeItem::Descriptor:
|
||||||
case TreeItem::Padding:
|
case TreeItem::Padding:
|
||||||
case TreeItem::Volume:
|
case TreeItem::Volume:
|
||||||
|
@ -38,6 +38,7 @@ public:
|
|||||||
// Item types
|
// Item types
|
||||||
enum ItemTypes {
|
enum ItemTypes {
|
||||||
Root,
|
Root,
|
||||||
|
Image,
|
||||||
Capsule,
|
Capsule,
|
||||||
Descriptor,
|
Descriptor,
|
||||||
Region,
|
Region,
|
||||||
|
@ -93,6 +93,9 @@ QModelIndex TreeModel::parent(const QModelIndex &index) const
|
|||||||
return QModelIndex();
|
return QModelIndex();
|
||||||
|
|
||||||
TreeItem *childItem = static_cast<TreeItem*>(index.internalPointer());
|
TreeItem *childItem = static_cast<TreeItem*>(index.internalPointer());
|
||||||
|
if (childItem == rootItem)
|
||||||
|
return QModelIndex();
|
||||||
|
|
||||||
TreeItem *parentItem = childItem->parent();
|
TreeItem *parentItem = childItem->parent();
|
||||||
|
|
||||||
if (parentItem == rootItem)
|
if (parentItem == rootItem)
|
||||||
|
40
uefitool.cpp
40
uefitool.cpp
@ -48,8 +48,8 @@ UEFITool::~UEFITool()
|
|||||||
|
|
||||||
void UEFITool::init()
|
void UEFITool::init()
|
||||||
{
|
{
|
||||||
// Clear UI components
|
// Clear components
|
||||||
ui->debugEdit->clear();
|
ui->debugListWidget->clear();
|
||||||
ui->infoEdit->clear();
|
ui->infoEdit->clear();
|
||||||
|
|
||||||
// Disable all actions except openImageFile
|
// 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, SIGNAL(expanded(const QModelIndex &)), this, SLOT(resizeTreeViewColums(void)));
|
||||||
connect(ui->structureTreeView->selectionModel(), SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)),
|
connect(ui->structureTreeView->selectionModel(), SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)),
|
||||||
this, SLOT(populateUi(const QModelIndex &)));
|
this, SLOT(populateUi(const QModelIndex &)));
|
||||||
|
connect(ui->debugListWidget, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(scrollTreeView(QListWidgetItem*)));
|
||||||
|
|
||||||
resizeTreeViewColums();
|
resizeTreeViewColums();
|
||||||
}
|
}
|
||||||
@ -88,7 +89,10 @@ void UEFITool::populateUi(const QModelIndex ¤t)
|
|||||||
|| ffsEngine->isOfType(TreeItem::Section, current));
|
|| ffsEngine->isOfType(TreeItem::Section, current));
|
||||||
ui->actionInsertInto->setEnabled(ffsEngine->isOfType(TreeItem::Volume, current)
|
ui->actionInsertInto->setEnabled(ffsEngine->isOfType(TreeItem::Volume, current)
|
||||||
|| ffsEngine->isOfType(TreeItem::File, 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)
|
ui->actionInsertBefore->setEnabled(ffsEngine->isOfType(TreeItem::File, current)
|
||||||
|| ffsEngine->isOfType(TreeItem::Section, current));
|
|| ffsEngine->isOfType(TreeItem::Section, current));
|
||||||
ui->actionInsertAfter->setEnabled(ffsEngine->isOfType(TreeItem::File, current)
|
ui->actionInsertAfter->setEnabled(ffsEngine->isOfType(TreeItem::File, current)
|
||||||
@ -100,7 +104,7 @@ void UEFITool::remove()
|
|||||||
{
|
{
|
||||||
UINT8 result = ffsEngine->remove(currentIndex);
|
UINT8 result = ffsEngine->remove(currentIndex);
|
||||||
if (result) {
|
if (result) {
|
||||||
ui->debugEdit->setPlainText(ffsEngine->message());
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
ui->actionSaveImageFile->setEnabled(true);
|
ui->actionSaveImageFile->setEnabled(true);
|
||||||
@ -115,7 +119,7 @@ void UEFITool::insert(const UINT8 mode)
|
|||||||
|
|
||||||
UINT8 type;
|
UINT8 type;
|
||||||
UINT8 objectType;
|
UINT8 objectType;
|
||||||
if (mode == INSERT_MODE_BEFORE || mode == INSERT_MODE_BEFORE)
|
if (mode == INSERT_MODE_BEFORE || mode == INSERT_MODE_AFTER)
|
||||||
type = item->parent()->type();
|
type = item->parent()->type();
|
||||||
else
|
else
|
||||||
type = item->type();
|
type = item->type();
|
||||||
@ -199,7 +203,7 @@ void UEFITool::saveImageFile()
|
|||||||
if (result)
|
if (result)
|
||||||
{
|
{
|
||||||
ui->statusBar->showMessage(tr("Reconstruction failed (%1)").arg(result));
|
ui->statusBar->showMessage(tr("Reconstruction failed (%1)").arg(result));
|
||||||
ui->debugEdit->setPlainText(ffsEngine->message());
|
showDebugMessage();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,7 +211,7 @@ void UEFITool::saveImageFile()
|
|||||||
outputFile.write(reconstructed);
|
outputFile.write(reconstructed);
|
||||||
outputFile.close();
|
outputFile.close();
|
||||||
ui->statusBar->showMessage(tr("Reconstructed image written"));
|
ui->statusBar->showMessage(tr("Reconstructed image written"));
|
||||||
ui->debugEdit->setPlainText(ffsEngine->message());
|
showDebugMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UEFITool::resizeTreeViewColums()
|
void UEFITool::resizeTreeViewColums()
|
||||||
@ -251,8 +255,7 @@ void UEFITool::openImageFile(QString path)
|
|||||||
else
|
else
|
||||||
ui->statusBar->showMessage(tr("Opened: %1").arg(fileInfo.fileName()));
|
ui->statusBar->showMessage(tr("Opened: %1").arg(fileInfo.fileName()));
|
||||||
|
|
||||||
ui->debugEdit->appendPlainText(ffsEngine->message());
|
showDebugMessage();
|
||||||
|
|
||||||
resizeTreeViewColums();
|
resizeTreeViewColums();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -319,3 +322,22 @@ void UEFITool::dropEvent(QDropEvent* event)
|
|||||||
openImageFile(path);
|
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 <QUrl>
|
||||||
|
|
||||||
#include "basetypes.h"
|
#include "basetypes.h"
|
||||||
|
#include "ffs.h"
|
||||||
#include "ffsengine.h"
|
#include "ffsengine.h"
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
@ -58,6 +59,7 @@ private slots:
|
|||||||
void insertAfter();
|
void insertAfter();
|
||||||
void replace();
|
void replace();
|
||||||
void remove();
|
void remove();
|
||||||
|
void scrollTreeView(QListWidgetItem* item);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::UEFITool * ui;
|
Ui::UEFITool * ui;
|
||||||
@ -66,6 +68,7 @@ private:
|
|||||||
|
|
||||||
void dragEnterEvent(QDragEnterEvent* event);
|
void dragEnterEvent(QDragEnterEvent* event);
|
||||||
void dropEvent(QDropEvent* event);
|
void dropEvent(QDropEvent* event);
|
||||||
|
void showDebugMessage();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -11,6 +11,7 @@ SOURCES += main.cpp \
|
|||||||
ffsengine.cpp \
|
ffsengine.cpp \
|
||||||
treeitem.cpp \
|
treeitem.cpp \
|
||||||
treemodel.cpp \
|
treemodel.cpp \
|
||||||
|
debuglistitem.cpp \
|
||||||
LZMA/LzmaCompress.c \
|
LZMA/LzmaCompress.c \
|
||||||
LZMA/LzmaDecompress.c \
|
LZMA/LzmaDecompress.c \
|
||||||
LZMA/SDK/C/LzFind.c \
|
LZMA/SDK/C/LzFind.c \
|
||||||
@ -28,6 +29,7 @@ HEADERS += uefitool.h \
|
|||||||
ffsengine.h \
|
ffsengine.h \
|
||||||
treeitem.h \
|
treeitem.h \
|
||||||
treemodel.h \
|
treemodel.h \
|
||||||
|
debuglistitem.h \
|
||||||
LZMA/LzmaCompress.h \
|
LZMA/LzmaCompress.h \
|
||||||
LZMA/LzmaDecompress.h \
|
LZMA/LzmaDecompress.h \
|
||||||
Tiano/EfiTianoDecompress.h \
|
Tiano/EfiTianoDecompress.h \
|
||||||
|
48
uefitool.ui
48
uefitool.ui
@ -6,8 +6,8 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>900</width>
|
<width>1100</width>
|
||||||
<height>600</height>
|
<height>700</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
@ -20,7 +20,7 @@
|
|||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>UEFITool 0.5.0</string>
|
<string>UEFITool 0.6.0</string>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QWidget" name="centralWidget">
|
<widget class="QWidget" name="centralWidget">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
@ -142,6 +142,12 @@
|
|||||||
<verstretch>0</verstretch>
|
<verstretch>0</verstretch>
|
||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>16777215</width>
|
||||||
|
<height>120</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>Debug</string>
|
<string>Debug</string>
|
||||||
</property>
|
</property>
|
||||||
@ -153,41 +159,7 @@
|
|||||||
<number>5</number>
|
<number>5</number>
|
||||||
</property>
|
</property>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPlainTextEdit" name="debugEdit">
|
<widget class="QListWidget" name="debugListWidget"/>
|
||||||
<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>
|
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
|
Loading…
Reference in New Issue
Block a user