Big structure update

- files split into common and app-specific ones
- messages from parser and finder separated
- ffsEngine split into multiple classes to reduce complexity
- still no image rebuild
This commit is contained in:
Nikolaj Schlej 2015-04-02 10:04:37 +02:00
parent 1f0a80d035
commit 2e788a8a1a
64 changed files with 477 additions and 2469 deletions

View File

@ -1,44 +0,0 @@
UEFITool
========
.. image:: https://raw.githubusercontent.com/LongSoft/UEFITool/master/uefitool.ico
.. image:: https://scan.coverity.com/projects/1812/badge.svg?flat=1
:target: https://scan.coverity.com/projects/1812/
|
| UEFITool is a cross-platform C++/Qt program for parsing, extracting and modifying UEFI firmware images.
| It supports parsing of full BIOS images starting with the flash descriptor or any binary files containing UEFI volumes.
| Original development was started `here <http://forums.mydigitallife.info/threads/48979-UEFITool-UEFI-firmware-image-viewer-and-editor>`_ at MDL forums as a cross-platform analog to `PhoenixTool <http://forums.mydigitallife.info/threads/13194-Tool-to-Insert-Replace-SLIC-in-Phoenix-Insyde-Dell-EFI-BIOSes>`_'s structure mode with some additional features, but the program's engine was proven to be usefull for another projects like `UEFIPatch <http://www.insanelymac.com/forum/topic/285444-uefipatch-uefi-patching-utility/>`_, `UBU <http://www.win-raid.com/t154f16-Tool-quot-UEFI-BIOS-Updater-quot-UBU.html>`_ and `OZMTool <http://www.insanelymac.com/forum/topic/299711-ozmtool-an-ozmosis-toolbox/>`_.
Installation
------------
| You can either use `pre-built binaries for Windows and OSX <https://github.com/LongSoft/UEFITool/releases/latest>`_ or build a binary yourself.
| To build a binary you need a C++ compiler and an instance of Qt4/Qt5 library for it.
| Install both of them, get the sources, generate makefiles using qmake (*qmake UEFITool.pro*) and use your make command on that generated files (i.e. *nmake release*, *make release* and so on).
Usage
-----
| The program can be started directly without any arguments or supplied with a single argument - a path to the UEFI image file to open after start.
|
| The program window is divided into three panels: **Structure**, **Information** and **Messages**.
| Structure of the image is represented as a tree of elements with different names, types and subtypes. If you select an element, **Information** panel will show the available information about the selected element based on it's type and contents.
| **Messages** panel show all messages from the engine, including structure warnings and search results. Most of messages can be double-clicked to select the element that causes the message.
|
| You can open a menu on each tree element to see what operations are possible for the selected element. This can include various types of **Extract**, **Insert** and **Replace** operations, as well as **Remove** and **Rebuild**.
| **Extract** has two variants: **Extract as is** and **Extract body**. The difference is that **Extract as is** extracts the element with it's header (GUID, size, attributes and other structure-related information are located there), and **Extract body** extracts the element data only.
| **Replace** has the same two variants as **Extract** with the same meaning.
| **Insert** has the three different variants: **Insert before**, **Insert after** and **Insert into**, which is only available for UEFI volumes and encapsulation sections.
| **Remove** marks an element for removal on image reconstuction.
| **Rebuild** marks an element for rebuilding on image reconstruction. Normally, all elements that aren't marked for rebuild won't be changed at all and if you need to correct some structure error (i.e. invalid data checksum) you must mark an element for rebuild manually. If you change an element all it's parents up to the tree root will be marked for rebuild automatically. If UEFI volume is marked for rebuild all uncompressed PEI files in it will also be marked for rebuild because they must be rebased in the reconstructed image to maintain the executable-in-place constraint.
|
| There is also a search function available from the *File* menu, you can search all tree elements for a specified hexadecimal pattern (spaces are not counted, dot symbol (.) is used as placeholder for a single hex digit), a specified GUID (rules are the same as for hex except for spaces) and a specified text (either Unicode or ASCII, case sensitive or not). Search results will be added into **Messages** panel, if anything is found.
|
| After you've finished the modifications, you need to initiate image reconstruction using *Save image file* command from the *File* menu. If anything goes wrong on the reconstruction, an error will pop up, otherwise the program will prompt if you need to open the reconstructed file. Don't rush it, because reconstruction process can also generate some usefull messages, which will be lost if you open the reconstructed file immediatelly.
Known issues
------------
* Some images has non-standard calculation of base address of TE images, so the program can rebase them incorrectly after modifications. Will be solved ASAP.
* Some images may not work after modification because of no FIT table support implemented yet. It's on my high priority features list, so I hope it will be corrected soon.
* The program is meant to work with BIOS images, not some vendor-specific BIOS update files, that is why some of that update file either can\t be opened at all or return errors on reconstruction. If someone wants to write an unpacker for such crappy files - I will be glad to use it.
* AMI-specific features like NCBs, ROM_AREA structure and other things like that can't be implemented by me because of the NDA I have.

91
UEFIExtract/ffsdumper.cpp Normal file
View File

@ -0,0 +1,91 @@
/* ffsdumper.cpp
Copyright (c) 2015, 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 "ffsdumper.h"
FfsDumper::FfsDumper(TreeModel* treeModel, QObject *parent)
: model(treeModel), QObject(parent), dumped(false)
{
}
FfsDumper::~FfsDumper()
{
}
STATUS FfsDumper::dump(const QModelIndex & root, const QString & path)
{
dumped = false;
UINT8 result = recursiveDump(root, path);
if (result)
return result;
else if (!dumped)
return ERR_ITEM_NOT_FOUND;
return ERR_SUCCESS;
}
STATUS FfsDumper::recursiveDump(const QModelIndex & index, const QString & path)
{
if (!index.isValid())
return ERR_INVALID_PARAMETER;
QDir dir;
if (dir.cd(path))
return ERR_DIR_ALREADY_EXIST;
if (!dir.mkpath(path))
return ERR_DIR_CREATE;
QFile file;
if (!model->header(index).isEmpty()) {
file.setFileName(tr("%1/header.bin").arg(path));
if (!file.open(QFile::WriteOnly))
return ERR_FILE_OPEN;
file.write(model->header(index));
file.close();
}
if (!model->body(index).isEmpty()) {
file.setFileName(tr("%1/body.bin").arg(path));
if (!file.open(QFile::WriteOnly))
return ERR_FILE_OPEN;
file.write(model->body(index));
file.close();
}
QString info = tr("Type: %1\nSubtype: %2\n%3%4")
.arg(itemTypeToQString(model->type(index)))
.arg(itemSubtypeToQString(model->type(index), model->subtype(index)))
.arg(model->text(index).isEmpty() ? "" : tr("Text: %1\n").arg(model->text(index)))
.arg(model->info(index));
file.setFileName(tr("%1/info.txt").arg(path));
if (!file.open(QFile::Text | QFile::WriteOnly))
return ERR_FILE_OPEN;
file.write(info.toLatin1());
file.close();
dumped = true;
UINT8 result;
for (int i = 0; i < model->rowCount(index); i++) {
QModelIndex childIndex = index.child(i, 0);
QString childPath = QString("%1/%2 %3").arg(path).arg(i).arg(model->text(childIndex).isEmpty() ? model->name(childIndex) : model->text(childIndex));
result = recursiveDump(childIndex, childPath);
if (result)
return result;
}
return ERR_SUCCESS;
}

43
UEFIExtract/ffsdumper.h Normal file
View File

@ -0,0 +1,43 @@
/* ffsdumper.h
Copyright (c) 2015, 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 __FFSDUMPER_H__
#define __FFSDUMPER_H__
#include <QObject>
#include <QDir>
#include <QByteArray>
#include <QString>
#include <QModelIndex>
#include <QFileInfo>
#include "..\common\basetypes.h"
#include "..\common\treemodel.h"
class FfsDumper : public QObject
{
Q_OBJECT
public:
explicit FfsDumper(TreeModel * treeModel, QObject *parent = 0);
~FfsDumper();
STATUS dump(const QModelIndex & root, const QString & path);
private:
STATUS recursiveDump(const QModelIndex & root, const QString & path);
TreeModel* model;
bool dumped;
};
#endif

View File

@ -0,0 +1,37 @@
QT += core
QT -= gui
TARGET = UEFIExtract
TEMPLATE = app
CONFIG += console
CONFIG -= app_bundle
SOURCES += uefiextract_main.cpp \
ffsdumper.cpp \
../common/types.cpp \
../common/descriptor.cpp \
../common/ffs.cpp \
../common/ffsparser.cpp \
../common/peimage.cpp \
../common/treeitem.cpp \
../common/treemodel.cpp \
../common/utility.cpp \
../common/LZMA/LzmaDecompress.c \
../common/LZMA/SDK/C/LzmaDec.c \
../common/Tiano/EfiTianoDecompress.c \
HEADERS += ffsdumper.h \
../common/basetypes.h \
../common/descriptor.h \
../common/gbe.h \
../common/me.h \
../common/ffs.h \
../common/ffsparser.h \
../common/peimage.h \
../common/types.h \
../common/treeitem.h \
../common/treemodel.h \
../common/utility.h \
../common/LZMA/LzmaDecompress.h \
../common/Tiano/EfiTianoDecompress.h

View File

@ -0,0 +1,65 @@
/* uefiextract_main.cpp
Copyright (c) 2015, 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 <QCoreApplication>
#include <QVector>
#include <QPair>
#include <QString>
#include <QFileInfo>
#include <iostream>
#include "..\common\ffsparser.h"
#include "ffsdumper.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
a.setOrganizationName("CodeRush");
a.setOrganizationDomain("coderush.me");
a.setApplicationName("UEFIExtract");
if (a.arguments().length() > 1) {
QString path = a.arguments().at(1);
QFileInfo fileInfo(path);
if (!fileInfo.exists())
return ERR_FILE_OPEN;
QFile inputFile;
inputFile.setFileName(path);
if (!inputFile.open(QFile::ReadOnly))
return ERR_FILE_OPEN;
QByteArray buffer = inputFile.readAll();
inputFile.close();
TreeModel model;
FfsParser ffsParser(&model);
STATUS result = ffsParser.parseImageFile(buffer, model.index(0, 0));
if (result)
return result;
QVector<QPair<QString, QModelIndex> > messages = ffsParser.getMessages();
QPair<QString, QModelIndex> msg;
foreach(msg, messages) {
std::cout << msg.first.toLatin1().constData() << std::endl;
}
FfsDumper ffsDumper(&model);
return ffsDumper.dump(model.index(0, 0), fileInfo.fileName().append(".dump"));
}
else {
std::cout << "UEFIExtract 0.10.0" << std::endl << std::endl
<< "Usage: uefiextract imagefile" << std::endl;
return 1;
}
}

View File

@ -20,8 +20,8 @@ Header file for compression routine.
*/ */
#ifndef _EFITIANOCOMPRESS_H_ #ifndef __EFITIANOCOMPRESS_H__
#define _EFITIANOCOMPRESS_H_ #define __EFITIANOCOMPRESS_H__
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>

View File

@ -21,8 +21,8 @@ Providing both EFI and Tiano decompress algorithms.
--*/ --*/
#ifndef _EFITIANODECOMPRESS_H_ #ifndef __EFITIANODECOMPRESS_H__
#define _EFITIANODECOMPRESS_H_ #define __EFITIANODECOMPRESS_H__
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>

View File

@ -60,7 +60,7 @@ typedef UINT8 STATUS;
#define ERR_VOLUMES_NOT_FOUND 14 #define ERR_VOLUMES_NOT_FOUND 14
#define ERR_INVALID_VOLUME 15 #define ERR_INVALID_VOLUME 15
#define ERR_VOLUME_REVISION_NOT_SUPPORTED 16 #define ERR_VOLUME_REVISION_NOT_SUPPORTED 16
#define ERR_VOLUME_GROW_FAILED 17 #define ERR_COMPLEX_BLOCK_MAP 17
#define ERR_UNKNOWN_FFS 18 #define ERR_UNKNOWN_FFS 18
#define ERR_INVALID_FILE 19 #define ERR_INVALID_FILE 19
#define ERR_INVALID_SECTION 20 #define ERR_INVALID_SECTION 20
@ -70,22 +70,13 @@ typedef UINT8 STATUS;
#define ERR_STANDARD_DECOMPRESSION_FAILED 24 #define ERR_STANDARD_DECOMPRESSION_FAILED 24
#define ERR_CUSTOMIZED_DECOMPRESSION_FAILED 25 #define ERR_CUSTOMIZED_DECOMPRESSION_FAILED 25
#define ERR_UNKNOWN_COMPRESSION_TYPE 26 #define ERR_UNKNOWN_COMPRESSION_TYPE 26
#define ERR_UNKNOWN_EXTRACT_MODE 27 #define ERR_DEPEX_PARSE_FAILED 27
#define ERR_UNKNOWN_INSERT_MODE 28 #define ERR_UNKNOWN_EXTRACT_MODE 28
#define ERR_UNKNOWN_IMAGE_TYPE 29 #define ERR_UNKNOWN_IMAGE_TYPE 29
#define ERR_UNKNOWN_PE_OPTIONAL_HEADER_TYPE 30 #define ERR_UNKNOWN_PE_OPTIONAL_HEADER_TYPE 30
#define ERR_UNKNOWN_RELOCATION_TYPE 31 #define ERR_UNKNOWN_RELOCATION_TYPE 31
#define ERR_GENERIC_CALL_NOT_SUPPORTED 32 #define ERR_DIR_ALREADY_EXIST 32
#define ERR_VOLUME_BASE_NOT_FOUND 33 #define ERR_DIR_CREATE 33
#define ERR_PEI_CORE_ENTRY_POINT_NOT_FOUND 34
#define ERR_COMPLEX_BLOCK_MAP 35
#define ERR_DIR_ALREADY_EXIST 36
#define ERR_DIR_CREATE 37
#define ERR_UNKNOWN_PATCH_TYPE 38
#define ERR_PATCH_OFFSET_OUT_OF_BOUNDS 39
#define ERR_INVALID_SYMBOL 40
#define ERR_NOTHING_TO_PATCH 41
#define ERR_DEPEX_PARSE_FAILED 42
#define ERR_NOT_IMPLEMENTED 0xFF #define ERR_NOT_IMPLEMENTED 0xFF
// UDK porting definitions // UDK porting definitions

View File

13
common/ffsbuilder.cpp Normal file
View File

@ -0,0 +1,13 @@
/* fssbuilder.cpp
Copyright (c) 2015, 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.
*/

17
common/ffsbuilder.h Normal file
View File

@ -0,0 +1,17 @@
/* fssbuilder.h
Copyright (c) 2015, 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 __FFSBUILDER_H__
#define __FFSBUILDER_H__
#endif

View File

@ -20,78 +20,28 @@ WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include "gbe.h" #include "gbe.h"
#include "me.h" #include "me.h"
FfsParser::FfsParser(TreeModel* treeModel, QObject *parent)
#ifdef _CONSOLE : model(treeModel), QObject(parent)
#include <iostream>
#endif
FfsParser::FfsParser(QObject *parent)
: QObject(parent)
{ {
model = new TreeModel();
//oldPeiCoreEntryPoint = 0;
//newPeiCoreEntryPoint = 0;
//dumped = false;
} }
FfsParser::~FfsParser(void) FfsParser::~FfsParser()
{ {
delete model;
}
TreeModel* FfsParser::treeModel() const
{
return model;
} }
void FfsParser::msg(const QString & message, const QModelIndex & index) void FfsParser::msg(const QString & message, const QModelIndex & index)
{ {
#ifndef _DISABLE_ENGINE_MESSAGES messagesVector.push_back(QPair<QString, QModelIndex>(message, index));
#ifndef _CONSOLE
messageItems.enqueue(MessageListItem(message, NULL, 0, index));
#else
(void) index;
std::cout << message.toLatin1().constData() << std::endl;
#endif
#else
(void)message;
(void)index;
#endif
} }
#ifndef _CONSOLE QVector<QPair<QString, QModelIndex> > FfsParser::getMessages() const
QQueue<MessageListItem> FfsParser::messages() const
{ {
return messageItems; return messagesVector;
} }
void FfsParser::clearMessages() void FfsParser::clearMessages()
{ {
messageItems.clear(); messagesVector.clear();
}
#endif
// Utility functions
PARSING_DATA FfsParser::getParsingData(const QModelIndex & index)
{
if (index.isValid()) {
return *(PARSING_DATA*)model->parsingData(index).data();
}
PARSING_DATA data;
data.fixed = FALSE; // Item is not fixed by default
data.isOnFlash = TRUE; // Data is on flash by default
data.offset = 0;
data.address = 0;
data.ffsVersion = 0; // Unknown by default
// Type-specific parts remain unitialized
return data;
}
QByteArray FfsParser::convertParsingData(const PARSING_DATA & pdata)
{
return QByteArray((const char*)&pdata, sizeof(PARSING_DATA));
} }
BOOLEAN FfsParser::hasIntersection(const UINT32 begin1, const UINT32 end1, const UINT32 begin2, const UINT32 end2) BOOLEAN FfsParser::hasIntersection(const UINT32 begin1, const UINT32 end1, const UINT32 begin2, const UINT32 end2)
@ -107,178 +57,8 @@ BOOLEAN FfsParser::hasIntersection(const UINT32 begin1, const UINT32 end1, const
return FALSE; return FALSE;
} }
// Search routines
STATUS FfsParser::findHexPattern(const QModelIndex & index, const QByteArray & hexPattern, const UINT8 mode)
{
if (!index.isValid())
return ERR_SUCCESS;
if (hexPattern.isEmpty())
return ERR_INVALID_PARAMETER;
// Check for "all substrings" pattern
if (hexPattern.count('.') == hexPattern.length())
return ERR_SUCCESS;
bool hasChildren = (model->rowCount(index) > 0);
for (int i = 0; i < model->rowCount(index); i++) {
findHexPattern(index.child(i, index.column()), hexPattern, mode);
}
QByteArray data;
if (hasChildren) {
if (mode != SEARCH_MODE_BODY)
data = model->header(index);
}
else {
if (mode == SEARCH_MODE_HEADER)
data.append(model->header(index));
else if (mode == SEARCH_MODE_BODY)
data.append(model->body(index));
else
data.append(model->header(index)).append(model->body(index));
}
QString hexBody = QString(data.toHex());
QRegExp regexp = QRegExp(QString(hexPattern), Qt::CaseInsensitive);
INT32 offset = regexp.indexIn(hexBody);
while (offset >= 0) {
if (offset % 2 == 0) {
msg(tr("Hex pattern \"%1\" found as \"%2\" in %3 at %4-offset %5h")
.arg(QString(hexPattern))
.arg(hexBody.mid(offset, hexPattern.length()).toUpper())
.arg(model->name(index))
.arg(mode == SEARCH_MODE_BODY ? tr("body") : tr("header"))
.hexarg(offset / 2),
index);
}
offset = regexp.indexIn(hexBody, offset + 1);
}
return ERR_SUCCESS;
}
STATUS FfsParser::findGuidPattern(const QModelIndex & index, const QByteArray & guidPattern, const UINT8 mode)
{
if (guidPattern.isEmpty())
return ERR_INVALID_PARAMETER;
if (!index.isValid())
return ERR_SUCCESS;
bool hasChildren = (model->rowCount(index) > 0);
for (int i = 0; i < model->rowCount(index); i++) {
findGuidPattern(index.child(i, index.column()), guidPattern, mode);
}
QByteArray data;
if (hasChildren) {
if (mode != SEARCH_MODE_BODY)
data = model->header(index);
}
else {
if (mode == SEARCH_MODE_HEADER)
data.append(model->header(index));
else if (mode == SEARCH_MODE_BODY)
data.append(model->body(index));
else
data.append(model->header(index)).append(model->body(index));
}
QString hexBody = QString(data.toHex());
QList<QByteArray> list = guidPattern.split('-');
if (list.count() != 5)
return ERR_INVALID_PARAMETER;
QByteArray hexPattern;
// Reverse first GUID block
hexPattern.append(list.at(0).mid(6, 2));
hexPattern.append(list.at(0).mid(4, 2));
hexPattern.append(list.at(0).mid(2, 2));
hexPattern.append(list.at(0).mid(0, 2));
// Reverse second GUID block
hexPattern.append(list.at(1).mid(2, 2));
hexPattern.append(list.at(1).mid(0, 2));
// Reverse third GUID block
hexPattern.append(list.at(2).mid(2, 2));
hexPattern.append(list.at(2).mid(0, 2));
// Append fourth and fifth GUID blocks as is
hexPattern.append(list.at(3)).append(list.at(4));
// Check for "all substrings" pattern
if (hexPattern.count('.') == hexPattern.length())
return ERR_SUCCESS;
QRegExp regexp = QRegExp(QString(hexPattern), Qt::CaseInsensitive);
INT32 offset = regexp.indexIn(hexBody);
while (offset >= 0) {
if (offset % 2 == 0) {
msg(tr("GUID pattern \"%1\" found as \"%2\" in %3 at %4-offset %5h")
.arg(QString(guidPattern))
.arg(hexBody.mid(offset, hexPattern.length()).toUpper())
.arg(model->name(index))
.arg(mode == SEARCH_MODE_BODY ? tr("body") : tr("header"))
.hexarg(offset / 2),
index);
}
offset = regexp.indexIn(hexBody, offset + 1);
}
return ERR_SUCCESS;
}
STATUS FfsParser::findTextPattern(const QModelIndex & index, const QString & pattern, const bool unicode, const Qt::CaseSensitivity caseSensitive)
{
if (pattern.isEmpty())
return ERR_INVALID_PARAMETER;
if (!index.isValid())
return ERR_SUCCESS;
bool hasChildren = (model->rowCount(index) > 0);
for (int i = 0; i < model->rowCount(index); i++) {
findTextPattern(index.child(i, index.column()), pattern, unicode, caseSensitive);
}
if (hasChildren)
return ERR_SUCCESS;
QString data;
if (unicode)
data = QString::fromUtf16((const ushort*)model->body(index).data(), model->body(index).length() / 2);
else
data = QString::fromLatin1((const char*)model->body(index).data(), model->body(index).length());
int offset = -1;
while ((offset = data.indexOf(pattern, offset + 1, caseSensitive)) >= 0) {
msg(tr("%1 text \"%2\" found in %3 at offset %4h")
.arg(unicode ? "Unicode" : "ASCII")
.arg(pattern)
.arg(model->name(index))
.hexarg(unicode ? offset * 2 : offset),
index);
}
return ERR_SUCCESS;
}
STATUS FfsParser::parseAprioriRawSection(const QByteArray & body, QString & parsed)
{
parsed.clear();
UINT32 count = body.size() / sizeof(EFI_GUID);
if (count > 0) {
for (UINT32 i = 0; i < count; i++) {
const EFI_GUID* guid = (const EFI_GUID*)body.constData() + i;
parsed += tr("\n%1").arg(guidToQString(*guid));
}
}
return ERR_SUCCESS;
}
// Firmware image parsing functions // Firmware image parsing functions
STATUS FfsParser::parseImageFile(const QByteArray & buffer) STATUS FfsParser::parseImageFile(const QByteArray & buffer, const QModelIndex & root)
{ {
// Check buffer size to be more then or equal to size of EFI_CAPSULE_HEADER // Check buffer size to be more then or equal to size of EFI_CAPSULE_HEADER
if ((UINT32)buffer.size() <= sizeof(EFI_CAPSULE_HEADER)) { if ((UINT32)buffer.size() <= sizeof(EFI_CAPSULE_HEADER)) {
@ -304,15 +84,14 @@ STATUS FfsParser::parseImageFile(const QByteArray & buffer)
.hexarg2(capsuleHeader->Flags, 8); .hexarg2(capsuleHeader->Flags, 8);
// Construct parsing data // Construct parsing data
PARSING_DATA pdata = getParsingData(); PARSING_DATA pdata = getParsingData(QModelIndex());
pdata.fixed = TRUE; pdata.fixed = TRUE;
// Add tree item // Add tree item
index = model->addItem(Types::Capsule, Subtypes::UefiCapsule, name, QString(), info, header, body, convertParsingData(pdata)); index = model->addItem(Types::Capsule, Subtypes::UefiCapsule, name, QString(), info, header, body, convertParsingData(pdata), root);
} }
// Check buffer for being extended Aptio signed capsule header // Check buffer for being extended Aptio signed capsule header
else if (buffer.startsWith(APTIO_SIGNED_CAPSULE_GUID) || buffer.startsWith(APTIO_UNSIGNED_CAPSULE_GUID)) { else if (buffer.startsWith(APTIO_SIGNED_CAPSULE_GUID) || buffer.startsWith(APTIO_UNSIGNED_CAPSULE_GUID)) {
bool signedCapsule = buffer.startsWith(APTIO_SIGNED_CAPSULE_GUID); bool signedCapsule = buffer.startsWith(APTIO_SIGNED_CAPSULE_GUID);
// Get info // Get info
const APTIO_CAPSULE_HEADER* capsuleHeader = (const APTIO_CAPSULE_HEADER*)buffer.constData(); const APTIO_CAPSULE_HEADER* capsuleHeader = (const APTIO_CAPSULE_HEADER*)buffer.constData();
@ -328,17 +107,21 @@ STATUS FfsParser::parseImageFile(const QByteArray & buffer)
.hexarg2(capsuleHeader->CapsuleHeader.Flags, 8); .hexarg2(capsuleHeader->CapsuleHeader.Flags, 8);
// Construct parsing data // Construct parsing data
PARSING_DATA pdata = getParsingData(); PARSING_DATA pdata = getParsingData(QModelIndex());
pdata.fixed = TRUE; pdata.fixed = TRUE;
// Add tree item // Add tree item
index = model->addItem(Types::Capsule, signedCapsule ? Subtypes::AptioSignedCapsule : Subtypes::AptioUnsignedCapsule, name, QString(), info, header, body, convertParsingData(pdata)); index = model->addItem(Types::Capsule, signedCapsule ? Subtypes::AptioSignedCapsule : Subtypes::AptioUnsignedCapsule, name, QString(), info, header, body, convertParsingData(pdata), root);
// Show message about possible Aptio signature break // Show message about possible Aptio signature break
if (signedCapsule) { if (signedCapsule) {
msg(tr("parseImageFile: Aptio capsule signature may become invalid after image modifications"), index); msg(tr("parseImageFile: Aptio capsule signature may become invalid after image modifications"), index);
} }
} }
// Other cases
else {
index = root;
}
// Skip capsule header to have flash chip image // Skip capsule header to have flash chip image
QByteArray flashImage = buffer.mid(capsuleHeaderSize); QByteArray flashImage = buffer.mid(capsuleHeaderSize);
@ -368,6 +151,8 @@ STATUS FfsParser::parseImageFile(const QByteArray & buffer)
// Add tree item // Add tree item
QModelIndex biosIndex = model->addItem(Types::Image, Subtypes::UefiImage, name, QString(), info, QByteArray(), flashImage, convertParsingData(pdata), index); QModelIndex biosIndex = model->addItem(Types::Image, Subtypes::UefiImage, name, QString(), info, QByteArray(), flashImage, convertParsingData(pdata), index);
// Parse the image
return parseRawArea(flashImage, biosIndex); return parseRawArea(flashImage, biosIndex);
} }
@ -660,7 +445,7 @@ STATUS FfsParser::parseMeRegion(const QByteArray & me, const UINT32 parentOffset
PARSING_DATA pdata = getParsingData(parent); PARSING_DATA pdata = getParsingData(parent);
// Get info // Get info
QString name = tr("ME/TXE region"); QString name = tr("ME region");
QString info = tr("Full size: %1h (%2)"). QString info = tr("Full size: %1h (%2)").
hexarg(me.size()).arg(me.size()); hexarg(me.size()).arg(me.size());
@ -706,10 +491,10 @@ STATUS FfsParser::parseMeRegion(const QByteArray & me, const UINT32 parentOffset
// Show messages // Show messages
if (emptyRegion) { if (emptyRegion) {
msg(tr("parseMeRegion: ME/TXE region is empty"), index); msg(tr("parseMeRegion: ME region is empty"), index);
} }
else if (!versionFound) { else if (!versionFound) {
msg(tr("parseMeRegion: ME/TXE region version is unknown, it can be damaged"), index); msg(tr("parseMeRegion: ME version is unknown, it can be damaged"), index);
} }
return ERR_SUCCESS; return ERR_SUCCESS;
@ -779,7 +564,7 @@ UINT8 FfsParser::getPaddingType(const QByteArray & padding)
return Subtypes::DataPadding; return Subtypes::DataPadding;
} }
STATUS FfsParser::parseRawArea(const QByteArray & bios, const QModelIndex & index) STATUS FfsParser::parseRawArea(const QByteArray & data, const QModelIndex & index)
{ {
// Sanity check // Sanity check
if (!index.isValid()) if (!index.isValid())
@ -794,7 +579,7 @@ STATUS FfsParser::parseRawArea(const QByteArray & bios, const QModelIndex & inde
STATUS result; STATUS result;
UINT32 prevVolumeOffset; UINT32 prevVolumeOffset;
result = findNextVolume(bios, 0, prevVolumeOffset); result = findNextVolume(data, 0, prevVolumeOffset);
if (result) if (result)
return result; return result;
@ -803,7 +588,7 @@ STATUS FfsParser::parseRawArea(const QByteArray & bios, const QModelIndex & inde
QString info; QString info;
if (prevVolumeOffset > 0) { if (prevVolumeOffset > 0) {
// Get info // Get info
QByteArray padding = bios.left(prevVolumeOffset); QByteArray padding = data.left(prevVolumeOffset);
name = tr("Padding"); name = tr("Padding");
info = tr("Full size: %1h (%2)") info = tr("Full size: %1h (%2)")
.hexarg(padding.size()).arg(padding.size()); .hexarg(padding.size()).arg(padding.size());
@ -826,7 +611,7 @@ STATUS FfsParser::parseRawArea(const QByteArray & bios, const QModelIndex & inde
if (volumeOffset > prevVolumeOffset + prevVolumeSize) { if (volumeOffset > prevVolumeOffset + prevVolumeSize) {
UINT32 paddingOffset = prevVolumeOffset + prevVolumeSize; UINT32 paddingOffset = prevVolumeOffset + prevVolumeSize;
UINT32 paddingSize = volumeOffset - paddingOffset; UINT32 paddingSize = volumeOffset - paddingOffset;
QByteArray padding = bios.mid(paddingOffset, paddingSize); QByteArray padding = data.mid(paddingOffset, paddingSize);
// Get info // Get info
name = tr("Padding"); name = tr("Padding");
@ -845,15 +630,15 @@ STATUS FfsParser::parseRawArea(const QByteArray & bios, const QModelIndex & inde
// Get volume size // Get volume size
UINT32 volumeSize = 0; UINT32 volumeSize = 0;
UINT32 bmVolumeSize = 0; UINT32 bmVolumeSize = 0;
result = getVolumeSize(bios, volumeOffset, volumeSize, bmVolumeSize); result = getVolumeSize(data, volumeOffset, volumeSize, bmVolumeSize);
if (result) if (result)
return result; return result;
// Check that volume is fully present in input // Check that volume is fully present in input
QByteArray volume = bios.mid(volumeOffset, volumeSize); QByteArray volume = data.mid(volumeOffset, volumeSize);
if (volumeSize > (UINT32)volume.size()) { if (volumeSize > (UINT32)volume.size()) {
// Mark the rest as padding and finish the parsing // Mark the rest as padding and finish the parsing
QByteArray padding = bios.right(volume.size()); QByteArray padding = data.right(volume.size());
// Get info // Get info
name = tr("Padding"); name = tr("Padding");
@ -892,13 +677,13 @@ STATUS FfsParser::parseRawArea(const QByteArray & bios, const QModelIndex & inde
// Go to next volume // Go to next volume
prevVolumeOffset = volumeOffset; prevVolumeOffset = volumeOffset;
prevVolumeSize = volumeSize; prevVolumeSize = volumeSize;
result = findNextVolume(bios, volumeOffset + prevVolumeSize, volumeOffset); result = findNextVolume(data, volumeOffset + prevVolumeSize, volumeOffset);
} }
// Padding at the end of BIOS space // Padding at the end of BIOS space
volumeOffset = prevVolumeOffset + prevVolumeSize; volumeOffset = prevVolumeOffset + prevVolumeSize;
if ((UINT32)bios.size() > volumeOffset) { if ((UINT32)data.size() > volumeOffset) {
QByteArray padding = bios.mid(volumeOffset); QByteArray padding = data.mid(volumeOffset);
// Get info // Get info
name = tr("Padding"); name = tr("Padding");
@ -1268,7 +1053,7 @@ STATUS FfsParser::parseVolumeBody(const QModelIndex & index)
QModelIndex fileIndex; QModelIndex fileIndex;
STATUS result = parseFileHeader(file, volumeHeaderSize + fileOffset, index, fileIndex); STATUS result = parseFileHeader(file, volumeHeaderSize + fileOffset, index, fileIndex);
if (result) if (result)
msg(tr("parseVolumeBody: file header parsing failed with error %1").arg(errorCodeToQString(result)), index); msg(tr("parseVolumeBody: file header parsing failed with error \"%1\"").arg(errorCodeToQString(result)), index);
// Move to next file // Move to next file
fileOffset += fileSize; fileOffset += fileSize;
@ -1608,7 +1393,7 @@ STATUS FfsParser::parseSections(QByteArray sections, const QModelIndex & index)
QModelIndex sectionIndex; QModelIndex sectionIndex;
STATUS result = parseSectionHeader(sections.mid(sectionOffset, sectionSize), headerSize + sectionOffset, index, sectionIndex); STATUS result = parseSectionHeader(sections.mid(sectionOffset, sectionSize), headerSize + sectionOffset, index, sectionIndex);
if (result) if (result)
msg(tr("parseSections: section header parsing failed with error %1").arg(errorCodeToQString(result)), index); msg(tr("parseSections: section header parsing failed with error \"%1\"").arg(errorCodeToQString(result)), index);
// Move to next section // Move to next section
sectionOffset += sectionSize; sectionOffset += sectionSize;
@ -2271,6 +2056,21 @@ STATUS FfsParser::parseUiSectionBody(const QModelIndex & index)
return ERR_SUCCESS; return ERR_SUCCESS;
} }
STATUS FfsParser::parseAprioriRawSection(const QByteArray & body, QString & parsed)
{
parsed.clear();
UINT32 count = body.size() / sizeof(EFI_GUID);
if (count > 0) {
for (UINT32 i = 0; i < count; i++) {
const EFI_GUID* guid = (const EFI_GUID*)body.constData() + i;
parsed += tr("\n%1").arg(guidToQString(*guid));
}
}
return ERR_SUCCESS;
}
STATUS FfsParser::parseRawSectionBody(const QModelIndex & index) STATUS FfsParser::parseRawSectionBody(const QModelIndex & index)
{ {
// Sanity check // Sanity check
@ -2485,65 +2285,3 @@ STATUS FfsEngine::parseFirmwareVolumeImageSectionHeader(const QByteArray & secti
} }
*/ */
STATUS FfsParser::extract(const QModelIndex & index, QString & name, QByteArray & extracted, const UINT8 mode)
{
// Sanity check
if (!index.isValid())
return ERR_INVALID_PARAMETER;
// Get data from parsing data
PARSING_DATA pdata = getParsingData(index);
// Construct a name for extracted data
QString itemName = model->name(index);
QString itemText = model->text(index);
switch (model->type(index)) {
case Types::Volume: {
if (pdata.volume.hasExtendedHeader)
name = guidToQString(pdata.volume.extendedHeaderGuid);
else
name = itemName;
} break;
case Types::File: {
name = itemText.isEmpty() ? itemName : itemText.replace(' ', '_');
} break;
case Types::Section: {
// Get parent file name
QModelIndex fileIndex = model->findParentOfType(index, Types::File);
QString fileText = model->text(fileIndex);
name = fileText.isEmpty() ? model->name(fileIndex) : fileText.replace(' ', '_');
// Append section subtype name
name += QChar('_') + itemName.replace(' ', '_');
} break;
case Types::Capsule:
case Types::Image:
case Types::Region:
case Types::Padding:
default:
name = itemName.replace(' ', '_').replace('/', '_');
}
// Get extracted data
if (mode == EXTRACT_MODE_AS_IS) {
// Extract as is, with header body and tail
extracted.clear();
extracted.append(model->header(index));
extracted.append(model->body(index));
// Handle file tail
if (model->type(index) == Types::File) {
if (pdata.file.hasTail)
extracted.append(pdata.file.tail);
}
}
else if (mode == EXTRACT_MODE_BODY) {
name += tr("_body");
// Extract without header and tail
extracted.clear();
extracted.append(model->body(index));
}
else
return ERR_UNKNOWN_EXTRACT_MODE;
return ERR_SUCCESS;
}

View File

@ -19,112 +19,33 @@ WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include <QObject> #include <QObject>
#include <QModelIndex> #include <QModelIndex>
#include <QByteArray> #include <QByteArray>
#include <QQueue>
#include <QVector> #include <QVector>
#include "basetypes.h" #include "basetypes.h"
#include "treemodel.h" #include "treemodel.h"
#include "utility.h" #include "utility.h"
#include "peimage.h" #include "peimage.h"
#include "parsingdata.h"
#ifndef _CONSOLE
#include "messagelistitem.h"
#endif
class TreeModel; class TreeModel;
//The whole parsing data is an information needed for each level of image reconstruction
//routines without the need of backward traversal
//typedef struct _CAPSULE_PARSING_DATA {
//} CAPSULE_PARSING_DATA;
//typedef struct _IMAGE_PARSING_DATA {
//} IMAGE_PARSING_DATA;
//typedef struct _PADDING_PARSING_DATA {
//} PADDING_PARSING_DATA;
typedef struct _VOLUME_PARSING_DATA {
EFI_GUID extendedHeaderGuid;
UINT32 alignment;
UINT8 revision;
BOOLEAN hasExtendedHeader;
BOOLEAN hasZeroVectorCRC32;
BOOLEAN isWeakAligned;
} VOLUME_PARSING_DATA;
//typedef struct _FREE_SPACE_PARSING_DATA {
//} FREE_SPACE_PARSING_DATA;
typedef struct _FILE_PARSING_DATA {
UINT16 tail;
BOOLEAN hasTail;
} FILE_PARSING_DATA;
typedef struct _COMPRESSED_SECTION_PARSING_DATA {
UINT32 uncompressedSize;
UINT8 compressionType;
UINT8 algorithm;
} COMPRESSED_SECTION_PARSING_DATA;
typedef struct _GUIDED_SECTION_PARSING_DATA {
EFI_GUID guid;
UINT32 attributes;
} GUIDED_SECTION_PARSING_DATA;
typedef struct _FREEFORM_GUIDED_SECTION_PARSING_DATA {
EFI_GUID guid;
} FREEFORM_GUIDED_SECTION_PARSING_DATA;
typedef struct _SECTION_PARSING_DATA {
union {
COMPRESSED_SECTION_PARSING_DATA compressed;
GUIDED_SECTION_PARSING_DATA guidDefined;
FREEFORM_GUIDED_SECTION_PARSING_DATA freeformSubtypeGuid;
};
} SECTION_PARSING_DATA;
typedef struct _PARSING_DATA {
BOOLEAN fixed;
BOOLEAN isOnFlash;
UINT8 emptyByte;
UINT8 ffsVersion;
UINT32 offset;
UINT64 address;
union {
//CAPSULE_PARSING_DATA capsule;
//IMAGE_PARSING_DATA image;
//PADDING_PARSING_DATA padding;
VOLUME_PARSING_DATA volume;
//FREE_SPACE_PARSING_DATA freeSpace;
FILE_PARSING_DATA file;
SECTION_PARSING_DATA section;
};
} PARSING_DATA;
class FfsParser : public QObject class FfsParser : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
// Default constructor and destructor // Default constructor and destructor
FfsParser(QObject *parent = 0); FfsParser(TreeModel* treeModel, QObject *parent = 0);
~FfsParser(void); ~FfsParser();
// Returns model for Qt view classes // Returns messages
TreeModel* treeModel() const; QVector<QPair<QString, QModelIndex> > getMessages() const;
// Clears messages
#ifndef _CONSOLE
// Returns message items queue
QQueue<MessageListItem> messages() const;
// Clears message items queue
void clearMessages(); void clearMessages();
#endif
// Firmware image parsing // Firmware image parsing
STATUS parseImageFile(const QByteArray & imageFile); STATUS parseImageFile(const QByteArray & imageFile, const QModelIndex & index);
STATUS parseRawArea(const QByteArray & bios, const QModelIndex & index); STATUS parseRawArea(const QByteArray & data, const QModelIndex & index);
STATUS parseVolumeHeader(const QByteArray & volume, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index); STATUS parseVolumeHeader(const QByteArray & volume, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index);
STATUS parseVolumeBody(const QModelIndex & index); STATUS parseVolumeBody(const QModelIndex & index);
STATUS parseFileHeader(const QByteArray & file, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index); STATUS parseFileHeader(const QByteArray & file, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index);
@ -132,17 +53,15 @@ public:
STATUS parseSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index); STATUS parseSectionHeader(const QByteArray & section, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index);
STATUS parseSectionBody(const QModelIndex & index); STATUS parseSectionBody(const QModelIndex & index);
// Search routines TODO: move to another class /*// Search routines TODO: move to another class
STATUS findHexPattern(const QModelIndex & index, const QByteArray & hexPattern, const UINT8 mode); // Extract routine TODO: move to another class
STATUS findGuidPattern(const QModelIndex & index, const QByteArray & guidPattern, const UINT8 mode); STATUS extract(const QModelIndex & index, QString & name, QByteArray & extracted, const UINT8 mode);*/
STATUS findTextPattern(const QModelIndex & index, const QString & pattern, const bool unicode, const Qt::CaseSensitivity caseSensitive);
STATUS extract(const QModelIndex & index, QString & name, QByteArray & extracted, const UINT8 mode);
private: private:
TreeModel *model; TreeModel *model;
QVector<QPair<QString, QModelIndex> > messagesVector;
STATUS parseIntelImage(const QByteArray & intelImage, const QModelIndex & parent, QModelIndex & index); STATUS parseIntelImage(const QByteArray & intelImage, const QModelIndex & parent, QModelIndex & root = QModelIndex());
STATUS parseGbeRegion(const QByteArray & gbe, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index); STATUS parseGbeRegion(const QByteArray & gbe, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index);
STATUS parseMeRegion(const QByteArray & me, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index); STATUS parseMeRegion(const QByteArray & me, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index);
STATUS parseBiosRegion(const QByteArray & bios, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index); STATUS parseBiosRegion(const QByteArray & bios, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index);
@ -174,12 +93,7 @@ private:
// Internal operations // Internal operations
BOOLEAN hasIntersection(const UINT32 begin1, const UINT32 end1, const UINT32 begin2, const UINT32 end2); BOOLEAN hasIntersection(const UINT32 begin1, const UINT32 end1, const UINT32 begin2, const UINT32 end2);
PARSING_DATA getParsingData(const QModelIndex & index = QModelIndex());
QByteArray convertParsingData(const PARSING_DATA & pdata);
#ifndef _CONSOLE
QQueue<MessageListItem> messageItems;
#endif
// Message helper // Message helper
void msg(const QString & message, const QModelIndex &index = QModelIndex()); void msg(const QString & message, const QModelIndex &index = QModelIndex());

View File

View File

90
common/parsingdata.h Normal file
View File

@ -0,0 +1,90 @@
/* ffsparser.h
Copyright (c) 2015, 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,
WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Parsing data is an information needed for each level of image reconstruction
routines without the need of backward traversal
*/
#ifndef __PARSINGDATA_H__
#define __PARSINGDATA_H__
#include "basetypes.h"
//typedef struct _CAPSULE_PARSING_DATA {
//} CAPSULE_PARSING_DATA;
//typedef struct _IMAGE_PARSING_DATA {
//} IMAGE_PARSING_DATA;
//typedef struct _PADDING_PARSING_DATA {
//} PADDING_PARSING_DATA;
typedef struct _VOLUME_PARSING_DATA {
EFI_GUID extendedHeaderGuid;
UINT32 alignment;
UINT8 revision;
BOOLEAN hasExtendedHeader;
BOOLEAN hasZeroVectorCRC32;
BOOLEAN isWeakAligned;
} VOLUME_PARSING_DATA;
//typedef struct _FREE_SPACE_PARSING_DATA {
//} FREE_SPACE_PARSING_DATA;
typedef struct _FILE_PARSING_DATA {
UINT16 tail;
BOOLEAN hasTail;
} FILE_PARSING_DATA;
typedef struct _COMPRESSED_SECTION_PARSING_DATA {
UINT32 uncompressedSize;
UINT8 compressionType;
UINT8 algorithm;
} COMPRESSED_SECTION_PARSING_DATA;
typedef struct _GUIDED_SECTION_PARSING_DATA {
EFI_GUID guid;
UINT32 attributes;
} GUIDED_SECTION_PARSING_DATA;
typedef struct _FREEFORM_GUIDED_SECTION_PARSING_DATA {
EFI_GUID guid;
} FREEFORM_GUIDED_SECTION_PARSING_DATA;
typedef struct _SECTION_PARSING_DATA {
union {
COMPRESSED_SECTION_PARSING_DATA compressed;
GUIDED_SECTION_PARSING_DATA guidDefined;
FREEFORM_GUIDED_SECTION_PARSING_DATA freeformSubtypeGuid;
};
} SECTION_PARSING_DATA;
typedef struct _PARSING_DATA {
BOOLEAN fixed;
BOOLEAN isOnFlash;
UINT8 emptyByte;
UINT8 ffsVersion;
UINT32 offset;
UINT64 address;
union {
//CAPSULE_PARSING_DATA capsule;
//IMAGE_PARSING_DATA image;
//PADDING_PARSING_DATA padding;
VOLUME_PARSING_DATA volume;
//FREE_SPACE_PARSING_DATA freeSpace;
FILE_PARSING_DATA file;
SECTION_PARSING_DATA section;
};
} PARSING_DATA;
#endif

View File

@ -24,7 +24,7 @@ QString regionTypeToQString(const UINT8 type)
case Subtypes::GbeRegion: case Subtypes::GbeRegion:
return QObject::tr("GbE"); return QObject::tr("GbE");
case Subtypes::MeRegion: case Subtypes::MeRegion:
return QObject::tr("ME/TXE"); return QObject::tr("ME");
case Subtypes::BiosRegion: case Subtypes::BiosRegion:
return QObject::tr("BIOS"); return QObject::tr("BIOS");
case Subtypes::PdrRegion: case Subtypes::PdrRegion:

View File

@ -11,6 +11,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*/ */
#include <QObject> #include <QObject>
#include "treemodel.h"
#include "utility.h" #include "utility.h"
#include "ffs.h" #include "ffs.h"
#include "Tiano/EfiTianoCompress.h" #include "Tiano/EfiTianoCompress.h"
@ -18,6 +19,31 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include "LZMA/LzmaCompress.h" #include "LZMA/LzmaCompress.h"
#include "LZMA/LzmaDecompress.h" #include "LZMA/LzmaDecompress.h"
// Returns either new parsing data instance or obtains it from index
PARSING_DATA getParsingData(const QModelIndex & index)
{
if (index.isValid()) {
TreeModel* model = (TreeModel*)index.model();
return *(PARSING_DATA*)model->parsingData(index).data();
}
PARSING_DATA data;
data.fixed = FALSE; // Item is not fixed by default
data.isOnFlash = TRUE; // Data is on flash by default
data.offset = 0;
data.address = 0;
data.ffsVersion = 0; // Unknown by default
// Type-specific parts remain unitialized
return data;
}
// Converts parsing data to byte array
QByteArray convertParsingData(const PARSING_DATA & pdata)
{
return QByteArray((const char*)&pdata, sizeof(PARSING_DATA));
}
// Returns text representation of error code // Returns text representation of error code
QString errorCodeToQString(UINT8 errorCode) QString errorCodeToQString(UINT8 errorCode)
{ {
@ -40,7 +66,7 @@ QString errorCodeToQString(UINT8 errorCode)
case ERR_VOLUMES_NOT_FOUND: return QObject::tr("UEFI volumes not found"); case ERR_VOLUMES_NOT_FOUND: return QObject::tr("UEFI volumes not found");
case ERR_INVALID_VOLUME: return QObject::tr("Invalid UEFI volume"); case ERR_INVALID_VOLUME: return QObject::tr("Invalid UEFI volume");
case ERR_VOLUME_REVISION_NOT_SUPPORTED: return QObject::tr("Volume revision not supported"); case ERR_VOLUME_REVISION_NOT_SUPPORTED: return QObject::tr("Volume revision not supported");
case ERR_VOLUME_GROW_FAILED: return QObject::tr("Volume grow failed"); //case ERR_VOLUME_GROW_FAILED: return QObject::tr("Volume grow failed");
case ERR_UNKNOWN_FFS: return QObject::tr("Unknown file system"); case ERR_UNKNOWN_FFS: return QObject::tr("Unknown file system");
case ERR_INVALID_FILE: return QObject::tr("Invalid file"); case ERR_INVALID_FILE: return QObject::tr("Invalid file");
case ERR_INVALID_SECTION: return QObject::tr("Invalid section"); case ERR_INVALID_SECTION: return QObject::tr("Invalid section");
@ -51,20 +77,20 @@ QString errorCodeToQString(UINT8 errorCode)
case ERR_CUSTOMIZED_DECOMPRESSION_FAILED: return QObject::tr("Customized compression failed"); case ERR_CUSTOMIZED_DECOMPRESSION_FAILED: return QObject::tr("Customized compression failed");
case ERR_UNKNOWN_COMPRESSION_TYPE: return QObject::tr("Unknown compression type"); case ERR_UNKNOWN_COMPRESSION_TYPE: return QObject::tr("Unknown compression type");
case ERR_UNKNOWN_EXTRACT_MODE: return QObject::tr("Unknown extract mode"); case ERR_UNKNOWN_EXTRACT_MODE: return QObject::tr("Unknown extract mode");
case ERR_UNKNOWN_INSERT_MODE: return QObject::tr("Unknown insert mode"); //case ERR_UNKNOWN_INSERT_MODE: return QObject::tr("Unknown insert mode");
case ERR_UNKNOWN_IMAGE_TYPE: return QObject::tr("Unknown executable image type"); case ERR_UNKNOWN_IMAGE_TYPE: return QObject::tr("Unknown executable image type");
case ERR_UNKNOWN_PE_OPTIONAL_HEADER_TYPE: return QObject::tr("Unknown PE optional header type"); case ERR_UNKNOWN_PE_OPTIONAL_HEADER_TYPE: return QObject::tr("Unknown PE optional header type");
case ERR_UNKNOWN_RELOCATION_TYPE: return QObject::tr("Unknown relocation type"); case ERR_UNKNOWN_RELOCATION_TYPE: return QObject::tr("Unknown relocation type");
case ERR_GENERIC_CALL_NOT_SUPPORTED: return QObject::tr("Generic call not supported"); //case ERR_GENERIC_CALL_NOT_SUPPORTED: return QObject::tr("Generic call not supported");
case ERR_VOLUME_BASE_NOT_FOUND: return QObject::tr("Volume base address not found"); //case ERR_VOLUME_BASE_NOT_FOUND: return QObject::tr("Volume base address not found");
case ERR_PEI_CORE_ENTRY_POINT_NOT_FOUND: return QObject::tr("PEI core entry point not found"); //case ERR_PEI_CORE_ENTRY_POINT_NOT_FOUND: return QObject::tr("PEI core entry point not found");
case ERR_COMPLEX_BLOCK_MAP: return QObject::tr("Block map structure too complex for correct analysis"); case ERR_COMPLEX_BLOCK_MAP: return QObject::tr("Block map structure too complex for correct analysis");
case ERR_DIR_ALREADY_EXIST: return QObject::tr("Directory already exists"); case ERR_DIR_ALREADY_EXIST: return QObject::tr("Directory already exists");
case ERR_DIR_CREATE: return QObject::tr("Directory can't be created"); case ERR_DIR_CREATE: return QObject::tr("Directory can't be created");
case ERR_UNKNOWN_PATCH_TYPE: return QObject::tr("Unknown patch type"); //case ERR_UNKNOWN_PATCH_TYPE: return QObject::tr("Unknown patch type");
case ERR_PATCH_OFFSET_OUT_OF_BOUNDS: return QObject::tr("Patch offset out of bounds"); //case ERR_PATCH_OFFSET_OUT_OF_BOUNDS: return QObject::tr("Patch offset out of bounds");
case ERR_INVALID_SYMBOL: return QObject::tr("Invalid symbol"); //case ERR_INVALID_SYMBOL: return QObject::tr("Invalid symbol");
case ERR_NOTHING_TO_PATCH: return QObject::tr("Nothing to patch"); //case ERR_NOTHING_TO_PATCH: return QObject::tr("Nothing to patch");
case ERR_DEPEX_PARSE_FAILED: return QObject::tr("Dependency expression parsing failed"); case ERR_DEPEX_PARSE_FAILED: return QObject::tr("Dependency expression parsing failed");
default: return QObject::tr("Unknown error %1").arg(errorCode); default: return QObject::tr("Unknown error %1").arg(errorCode);
} }
@ -198,7 +224,6 @@ STATUS decompress(const QByteArray & compressedData, UINT8 & algorithm, QByteArr
// Decompress section data // Decompress section data
if (ERR_SUCCESS != LzmaDecompress(data, dataSize, decompressed)) { if (ERR_SUCCESS != LzmaDecompress(data, dataSize, decompressed)) {
//TODO: implement it again, if needed
// Intel modified LZMA workaround // Intel modified LZMA workaround
// Decompress section data once again // Decompress section data once again
data += sizeof(UINT32); data += sizeof(UINT32);

View File

@ -10,8 +10,20 @@ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*/ */
#ifndef __UTILITY_H__
#define __UTILITY_H__
#include <QString> #include <QString>
#include <QModelIndex>
#include "basetypes.h" #include "basetypes.h"
#include "parsingdata.h"
// Returns either new parsing data instance or obtains it from index
PARSING_DATA getParsingData(const QModelIndex & index);
// Converts parsing data to byte array
QByteArray convertParsingData(const PARSING_DATA & pdata);
// Converts error code to QString // Converts error code to QString
extern QString errorCodeToQString(UINT8 errorCode); extern QString errorCodeToQString(UINT8 errorCode);
@ -24,3 +36,5 @@ extern STATUS decompress(const QByteArray & compressed, UINT8 & algorithm, QByte
// CRC32 // CRC32
extern UINT32 crc32(UINT32 initial, const UINT8* buffer, UINT32 length); extern UINT32 crc32(UINT32 initial, const UINT8* buffer, UINT32 length);
#endif

View File

@ -1,61 +0,0 @@
/* guidlineedit.cpp
Copyright (c) 2014, 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 "guidlineedit.h"
GuidLineEdit::GuidLineEdit(QWidget * parent)
:QLineEdit(parent)
{
}
GuidLineEdit::GuidLineEdit(const QString & contents, QWidget * parent)
:QLineEdit(contents, parent)
{
}
GuidLineEdit::~GuidLineEdit()
{
}
void GuidLineEdit::keyPressEvent(QKeyEvent * event)
{
if (event == QKeySequence::Delete || event->key() == Qt::Key_Backspace)
{
int pos = cursorPosition();
if (event->key() == Qt::Key_Backspace && pos > 0) {
cursorBackward(false);
pos = cursorPosition();
}
QString txt = text();
QString selected = selectedText();
if (!selected.isEmpty()) {
pos = QLineEdit::selectionStart();
for (int i = pos; i < pos + selected.count(); i++)
if (txt[i] != QChar('-'))
txt[i] = QChar('.');
}
else
txt[pos] = QChar('.');
setCursorPosition(0);
insert(txt);
setCursorPosition(pos);
return;
}
// Call original event handler
QLineEdit::keyPressEvent(event);
}

View File

@ -1,36 +0,0 @@
/* guidlineedit.h
Copyright (c) 2014, 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 __GUIDLINEEDIT_H__
#define __GUIDLINEEDIT_H__
#include <QLineEdit>
#include <QKeyEvent>
#include <QKeySequence>
#include <QString>
#include "basetypes.h"
class GuidLineEdit : public QLineEdit
{
public:
GuidLineEdit(QWidget * parent = 0);
GuidLineEdit(const QString & contents, QWidget * parent = 0);
~GuidLineEdit();
protected:
void keyPressEvent(QKeyEvent * event);
};
#endif

View File

@ -1,46 +0,0 @@
/* messagelistitem.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 "messagelistitem.h"
MessageListItem::MessageListItem(QListWidget * parent, int type, const QModelIndex & index)
: QListWidgetItem(parent, type)
{
itemIndex = index;
}
MessageListItem::MessageListItem(const QString & text, QListWidget * parent, int type, const QModelIndex & index)
: QListWidgetItem(text, parent, type)
{
itemIndex = index;
}
MessageListItem::MessageListItem(const QIcon & icon, const QString & text, QListWidget * parent, int type, const QModelIndex & index)
: QListWidgetItem(icon, text, parent, type)
{
itemIndex = index;
}
MessageListItem::~MessageListItem()
{
}
QModelIndex MessageListItem::index() const
{
return itemIndex;
}
void MessageListItem::setIndex(QModelIndex & index)
{
itemIndex = index;
}

View File

@ -1,37 +0,0 @@
/* messagelistitem.h
Copyright (c) 2014, 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 __MESSAGELISTITEM_H__
#define __MESSAGELISTITEM_H__
#include <QModelIndex>
#include <QListWidgetItem>
#include "basetypes.h"
class MessageListItem : public QListWidgetItem
{
public:
MessageListItem(QListWidget * parent = 0, int type = Type, const QModelIndex & index = QModelIndex());
MessageListItem(const QString & text, QListWidget * parent = 0, int type = Type, const QModelIndex & index = QModelIndex());
MessageListItem(const QIcon & icon, const QString & text, QListWidget * parent = 0, int type = Type, const QModelIndex & index = QModelIndex());
~MessageListItem();
QModelIndex index() const;
void setIndex(QModelIndex & index);
private:
QModelIndex itemIndex;
};
#endif

View File

@ -1,49 +0,0 @@
/* searchdialog.cpp
Copyright (c) 2014, 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 "searchdialog.h"
SearchDialog::SearchDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::SearchDialog),
hexValidator(QRegExp("([0-9a-fA-F\\. ])*")),
guidValidator(QRegExp("[0-9a-fA-F\\.]{8}-[0-9a-fA-F\\.]{4}-[0-9a-fA-F\\.]{4}-[0-9a-fA-F\\.]{4}-[0-9a-fA-F\\.]{12}"))
{
// Create UI
ui->setupUi(this);
ui->hexEdit->setValidator(&hexValidator);
ui->guidEdit->setValidator(&guidValidator);
// Connect
connect(ui->tabWidget, SIGNAL(currentChanged(int)), this, SLOT(setEditFocus(int)));
// Set initial focus
setEditFocus(ui->tabWidget->currentIndex());
}
SearchDialog::~SearchDialog()
{
delete ui;
}
void SearchDialog::setEditFocus(int index)
{
if (index == 0) // Hex pattern
ui->hexEdit->setFocus();
else if (index == 1) { // GUID
ui->guidEdit->setFocus();
ui->guidEdit->setCursorPosition(0);
}
else if (index == 2) // Text
ui->textEdit->setFocus();
}

View File

@ -1,38 +0,0 @@
/* searchdialog.h
Copyright (c) 2014, 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 SEARCHDIALOG_H
#define SEARCHDIALOG_H
#include <QDialog>
#include <QRegExpValidator>
#include "ui_searchdialog.h"
class SearchDialog : public QDialog
{
Q_OBJECT
public:
SearchDialog(QWidget *parent = 0);
~SearchDialog();
Ui::SearchDialog* ui;
private slots:
void setEditFocus(int index);
private:
QRegExpValidator hexValidator;
QRegExpValidator guidValidator;
};
#endif

View File

@ -1,249 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SearchDialog</class>
<widget class="QDialog" name="SearchDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>237</height>
</rect>
</property>
<property name="windowTitle">
<string>Search</string>
</property>
<property name="modal">
<bool>false</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="hexTab">
<attribute name="title">
<string>Hex pattern</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="hexLabel">
<property name="text">
<string>Hex pattern:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="hexEdit">
<property name="inputMask">
<string/>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QGroupBox" name="hexGroupBox">
<property name="title">
<string>Search scope</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QRadioButton" name="hexScopeFullRadioButton">
<property name="text">
<string>Header and body</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="hexScopeHeaderRadioButton">
<property name="text">
<string>Header only</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="hexScopeBodyRadioButton">
<property name="text">
<string>Body only</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="guidTab">
<attribute name="title">
<string>GUID</string>
</attribute>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="guidLabel">
<property name="text">
<string>GUID:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="GuidLineEdit" name="guidEdit">
<property name="inputMask">
<string>xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx</string>
</property>
<property name="text">
<string>........-....-....-....-............</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QGroupBox" name="guidGroupBox">
<property name="title">
<string>Search scope</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<widget class="QRadioButton" name="guidScopeFullRadioButton">
<property name="text">
<string>Header and body</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="guidScopeHeaderRadioButton">
<property name="text">
<string>Header only</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="guidScopeBodyRadioButton">
<property name="text">
<string>Body only</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="textTab">
<attribute name="title">
<string>Text</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QLabel" name="textLabel">
<property name="text">
<string>Text:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="textEdit"/>
</item>
<item row="1" column="0" colspan="2">
<widget class="QGroupBox" name="textGroupBox">
<property name="title">
<string>Text search options</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QCheckBox" name="textUnicodeCheckBox">
<property name="text">
<string>Unicode</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="textCaseSensitiveCheckBox">
<property name="text">
<string>Case sensitive</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>GuidLineEdit</class>
<extends>QLineEdit</extends>
<header>guidlineedit.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>tabWidget</tabstop>
<tabstop>hexEdit</tabstop>
<tabstop>hexScopeFullRadioButton</tabstop>
<tabstop>hexScopeHeaderRadioButton</tabstop>
<tabstop>hexScopeBodyRadioButton</tabstop>
<tabstop>buttonBox</tabstop>
<tabstop>textEdit</tabstop>
<tabstop>textUnicodeCheckBox</tabstop>
<tabstop>textCaseSensitiveCheckBox</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>SearchDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>182</x>
<y>185</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>194</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>SearchDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>182</x>
<y>185</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>194</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -1,744 +0,0 @@
/* uefitool.cpp
Copyright (c) 2015, 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 "uefitool.h"
#include "ui_uefitool.h"
UEFITool::UEFITool(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::UEFITool),
version(tr("0.30.0_alpha_parser_only"))
{
clipboard = QApplication::clipboard();
// Create UI
ui->setupUi(this);
searchDialog = new SearchDialog(this);
ffsParser = NULL;
// Set window title
this->setWindowTitle(tr("UEFITool %1").arg(version));
// Connect signals to slots
connect(ui->actionOpenImageFile, SIGNAL(triggered()), this, SLOT(openImageFile()));
connect(ui->actionSaveImageFile, SIGNAL(triggered()), this, SLOT(saveImageFile()));
connect(ui->actionSearch, SIGNAL(triggered()), this, SLOT(search()));
connect(ui->actionExtract, SIGNAL(triggered()), this, SLOT(extractAsIs()));
connect(ui->actionExtractBody, SIGNAL(triggered()), this, SLOT(extractBody()));
connect(ui->actionInsertInto, SIGNAL(triggered()), this, SLOT(insertInto()));
connect(ui->actionInsertBefore, SIGNAL(triggered()), this, SLOT(insertBefore()));
connect(ui->actionInsertAfter, SIGNAL(triggered()), this, SLOT(insertAfter()));
connect(ui->actionReplace, SIGNAL(triggered()), this, SLOT(replaceAsIs()));
connect(ui->actionReplaceBody, SIGNAL(triggered()), this, SLOT(replaceBody()));
connect(ui->actionRemove, SIGNAL(triggered()), this, SLOT(remove()));
connect(ui->actionRebuild, SIGNAL(triggered()), this, SLOT(rebuild()));
connect(ui->actionMessagesCopy, SIGNAL(triggered()), this, SLOT(copyMessage()));
connect(ui->actionMessagesCopyAll, SIGNAL(triggered()), this, SLOT(copyAllMessages()));
connect(ui->actionMessagesClear, SIGNAL(triggered()), this, SLOT(clearMessages()));
connect(ui->actionAbout, SIGNAL(triggered()), this, SLOT(about()));
connect(ui->actionAboutQt, SIGNAL(triggered()), this, SLOT(aboutQt()));
connect(ui->actionQuit, SIGNAL(triggered()), this, SLOT(exit()));
connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()), this, SLOT(writeSettings()));
// Enable Drag-and-Drop actions
this->setAcceptDrops(true);
// Set current directory
currentDir = ".";
// Set monospace font for some controls
QFont font("Courier New", 10);
#if defined Q_OS_OSX
font = QFont("Menlo", 10);
#elif defined Q_OS_WIN
font = QFont("Consolas", 9);
#endif
ui->infoEdit->setFont(font);
ui->messageListWidget->setFont(font);
ui->structureTreeView->setFont(font);
searchDialog->ui->guidEdit->setFont(font);
searchDialog->ui->hexEdit->setFont(font);
// Initialize non-persistent data
init();
// Read stored settings
readSettings();
}
UEFITool::~UEFITool()
{
delete ui;
delete ffsParser;
delete searchDialog;
}
void UEFITool::init()
{
// Clear components
ui->messageListWidget->clear();
ui->infoEdit->clear();
// Set window title
this->setWindowTitle(tr("UEFITool %1").arg(version));
// Disable menus
ui->menuCapsuleActions->setDisabled(true);
ui->menuImageActions->setDisabled(true);
ui->menuRegionActions->setDisabled(true);
ui->menuPaddingActions->setDisabled(true);
ui->menuVolumeActions->setDisabled(true);
ui->menuFileActions->setDisabled(true);
ui->menuSectionActions->setDisabled(true);
ui->actionMessagesCopy->setDisabled(true);
ui->actionMessagesCopyAll->setDisabled(true);
// Make new ffsEngine
if (ffsParser)
delete ffsParser;
ffsParser = new FfsParser(this);
ui->structureTreeView->setModel(ffsParser->treeModel());
// Connect
connect(ui->structureTreeView->selectionModel(), SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)),
this, SLOT(populateUi(const QModelIndex &)));
connect(ui->messageListWidget, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(scrollTreeView(QListWidgetItem*)));
connect(ui->messageListWidget, SIGNAL(itemEntered(QListWidgetItem*)), this, SLOT(enableMessagesCopyActions(QListWidgetItem*)));
}
void UEFITool::populateUi(const QModelIndex &current)
{
if (!current.isValid())
return;
TreeModel* model = ffsParser->treeModel();
UINT8 type = model->type(current);
//UINT8 subtype = model->subtype(current);
// Set info text
ui->infoEdit->setPlainText(model->info(current));
// Enable menus
ui->menuCapsuleActions->setEnabled(type == Types::Capsule);
ui->menuImageActions->setEnabled(type == Types::Image);
ui->menuRegionActions->setEnabled(type == Types::Region);
ui->menuPaddingActions->setEnabled(type == Types::Padding);
ui->menuVolumeActions->setEnabled(type == Types::Volume);
ui->menuFileActions->setEnabled(type == Types::File);
ui->menuSectionActions->setEnabled(type == Types::Section);
// Enable actions
ui->actionExtract->setDisabled(model->hasEmptyHeader(current) && model->hasEmptyBody(current));
//ui->actionRebuild->setEnabled(type == Types::Volume || type == Types::File || type == Types::Section);
ui->actionExtractBody->setDisabled(model->hasEmptyBody(current));
//ui->actionRemove->setEnabled(type == Types::Volume || type == Types::File || type == Types::Section);
//ui->actionInsertInto->setEnabled((type == Types::Volume && subtype != Subtypes::UnknownVolume) ||
// (type == Types::File && subtype != EFI_FV_FILETYPE_ALL && subtype != EFI_FV_FILETYPE_RAW && subtype != EFI_FV_FILETYPE_PAD) ||
// (type == Types::Section && (subtype == EFI_SECTION_COMPRESSION || subtype == EFI_SECTION_GUID_DEFINED || subtype == EFI_SECTION_DISPOSABLE)));
//ui->actionInsertBefore->setEnabled(type == Types::File || type == Types::Section);
//ui->actionInsertAfter->setEnabled(type == Types::File || type == Types::Section);
//ui->actionReplace->setEnabled((type == Types::Region && subtype != Subtypes::DescriptorRegion) || type == Types::Volume || type == Types::File || type == Types::Section);
//ui->actionReplaceBody->setEnabled(type == Types::Volume || type == Types::File || type == Types::Section);
ui->actionMessagesCopy->setEnabled(false);
}
void UEFITool::search()
{
if (searchDialog->exec() != QDialog::Accepted)
return;
QModelIndex rootIndex = ffsParser->treeModel()->index(0, 0);
int index = searchDialog->ui->tabWidget->currentIndex();
if (index == 0) { // Hex pattern
searchDialog->ui->hexEdit->setFocus();
QByteArray pattern = searchDialog->ui->hexEdit->text().toLatin1().replace(" ", "");
if (pattern.isEmpty())
return;
UINT8 mode;
if (searchDialog->ui->hexScopeHeaderRadioButton->isChecked())
mode = SEARCH_MODE_HEADER;
else if (searchDialog->ui->hexScopeBodyRadioButton->isChecked())
mode = SEARCH_MODE_BODY;
else
mode = SEARCH_MODE_ALL;
ffsParser->findHexPattern(rootIndex, pattern, mode);
showMessages();
}
else if (index == 1) { // GUID
searchDialog->ui->guidEdit->setFocus();
searchDialog->ui->guidEdit->setCursorPosition(0);
QByteArray pattern = searchDialog->ui->guidEdit->text().toLatin1();
if (pattern.isEmpty())
return;
UINT8 mode;
if (searchDialog->ui->guidScopeHeaderRadioButton->isChecked())
mode = SEARCH_MODE_HEADER;
else if (searchDialog->ui->guidScopeBodyRadioButton->isChecked())
mode = SEARCH_MODE_BODY;
else
mode = SEARCH_MODE_ALL;
ffsParser->findGuidPattern(rootIndex, pattern, mode);
showMessages();
}
else if (index == 2) { // Text string
searchDialog->ui->textEdit->setFocus();
QString pattern = searchDialog->ui->textEdit->text();
if (pattern.isEmpty())
return;
ffsParser->findTextPattern(rootIndex, pattern, searchDialog->ui->textUnicodeCheckBox->isChecked(),
(Qt::CaseSensitivity) searchDialog->ui->textCaseSensitiveCheckBox->isChecked());
showMessages();
}
}
void UEFITool::rebuild()
{
QModelIndex index = ui->structureTreeView->selectionModel()->currentIndex();
if (!index.isValid())
return;
/*UINT8 result = ffsEngine->rebuild(index);
if (result == ERR_SUCCESS)
ui->actionSaveImageFile->setEnabled(true);*/
}
void UEFITool::remove()
{
QModelIndex index = ui->structureTreeView->selectionModel()->currentIndex();
if (!index.isValid())
return;
/*UINT8 result = ffsEngine->remove(index);
if (result == ERR_SUCCESS)
ui->actionSaveImageFile->setEnabled(true);*/
}
void UEFITool::insert(const UINT8 mode)
{
QModelIndex index = ui->structureTreeView->selectionModel()->currentIndex();
if (!index.isValid())
return;
TreeModel* model = ffsParser->treeModel();
UINT8 type;
if (mode == CREATE_MODE_BEFORE || mode == CREATE_MODE_AFTER)
type = model->type(index.parent());
else
type = model->type(index);
QString path;
switch (type) {
case Types::Volume:
path = QFileDialog::getOpenFileName(this, tr("Select FFS file to insert"), currentDir, "FFS files (*.ffs *.bin);;All files (*)");
break;
case Types::File:
case Types::Section:
path = QFileDialog::getOpenFileName(this, tr("Select section file to insert"), currentDir, "Section files (*.sct *.bin);;All files (*)");
break;
default:
return;
}
if (path.trimmed().isEmpty())
return;
QFileInfo fileInfo = QFileInfo(path);
if (!fileInfo.exists()) {
ui->statusBar->showMessage(tr("Please select existing file"));
return;
}
QFile inputFile;
inputFile.setFileName(path);
if (!inputFile.open(QFile::ReadOnly)) {
QMessageBox::critical(this, tr("Insertion failed"), tr("Can't open output file for reading"), QMessageBox::Ok);
return;
}
QByteArray buffer = inputFile.readAll();
inputFile.close();
/*UINT8 result = ffsEngine->insert(index, buffer, mode);
if (result) {
QMessageBox::critical(this, tr("Insertion failed"), errorMessage(result), QMessageBox::Ok);
return;
}
ui->actionSaveImageFile->setEnabled(true);*/
}
void UEFITool::insertInto()
{
insert(CREATE_MODE_PREPEND);
}
void UEFITool::insertBefore()
{
insert(CREATE_MODE_BEFORE);
}
void UEFITool::insertAfter()
{
insert(CREATE_MODE_AFTER);
}
void UEFITool::replaceAsIs()
{
replace(REPLACE_MODE_AS_IS);
}
void UEFITool::replaceBody()
{
replace(REPLACE_MODE_BODY);
}
void UEFITool::replace(const UINT8 mode)
{
QModelIndex index = ui->structureTreeView->selectionModel()->currentIndex();
if (!index.isValid())
return;
TreeModel* model = ffsParser->treeModel();
QString path;
if (model->type(index) == Types::Region) {
if (mode == REPLACE_MODE_AS_IS) {
path = QFileDialog::getOpenFileName(this, tr("Select region file to replace selected object"), currentDir, "Region files (*.rgn *.bin);;All files (*)");
}
else
return;
}
else if (model->type(index) == Types::Volume) {
if (mode == REPLACE_MODE_AS_IS) {
path = QFileDialog::getOpenFileName(this, tr("Select volume file to replace selected object"), currentDir, "Volume files (*.vol *.bin);;All files (*)");
}
else if (mode == REPLACE_MODE_BODY) {
path = QFileDialog::getOpenFileName(this, tr("Select volume body file to replace body"), currentDir, "Volume body files (*.vbd *.bin);;All files (*)");
}
else
return;
}
else if (model->type(index) == Types::File) {
if (mode == REPLACE_MODE_AS_IS) {
path = QFileDialog::getOpenFileName(this, tr("Select FFS file to replace selected object"), currentDir, "FFS files (*.ffs *.bin);;All files (*)");
}
else if (mode == REPLACE_MODE_BODY) {
if (model->subtype(index) == EFI_FV_FILETYPE_ALL || model->subtype(index) == EFI_FV_FILETYPE_RAW)
path = QFileDialog::getOpenFileName(this, tr("Select raw file to replace body"), currentDir, "Raw files (*.raw *.bin);;All files (*)");
else if (model->subtype(index) == EFI_FV_FILETYPE_PAD) // Pad file body can't be replaced
//!TODO: handle non-empty pad files
return;
else
path = QFileDialog::getOpenFileName(this, tr("Select FFS file body to replace body"), currentDir, "FFS file body files (*.fbd *.bin);;All files (*)");
}
else
return;
}
else if (model->type(index) == Types::Section) {
if (mode == REPLACE_MODE_AS_IS) {
path = QFileDialog::getOpenFileName(this, tr("Select section file to replace selected object"), currentDir, "Section files (*.sct *.bin);;All files (*)");
}
else if (mode == REPLACE_MODE_BODY) {
if (model->subtype(index) == EFI_SECTION_COMPRESSION || model->subtype(index) == EFI_SECTION_GUID_DEFINED || model->subtype(index) == EFI_SECTION_DISPOSABLE)
path = QFileDialog::getOpenFileName(this, tr("Select FFS file body file to replace body"), currentDir, "FFS file body files (*.fbd *.bin);;All files (*)");
else if (model->subtype(index) == EFI_SECTION_FIRMWARE_VOLUME_IMAGE)
path = QFileDialog::getOpenFileName(this, tr("Select volume file to replace body"), currentDir, "Volume files (*.vol *.bin);;All files (*)");
else if (model->subtype(index) == EFI_SECTION_RAW)
path = QFileDialog::getOpenFileName(this, tr("Select raw file to replace body"), currentDir, "Raw files (*.raw *.bin);;All files (*)");
else
path = QFileDialog::getOpenFileName(this, tr("Select file to replace body"), currentDir, "Binary files (*.bin);;All files (*)");
}
else
return;
}
else
return;
if (path.trimmed().isEmpty())
return;
QFileInfo fileInfo = QFileInfo(path);
if (!fileInfo.exists()) {
ui->statusBar->showMessage(tr("Please select existing file"));
return;
}
QFile inputFile;
inputFile.setFileName(path);
if (!inputFile.open(QFile::ReadOnly)) {
QMessageBox::critical(this, tr("Replacing failed"), tr("Can't open input file for reading"), QMessageBox::Ok);
return;
}
QByteArray buffer = inputFile.readAll();
inputFile.close();
/*UINT8 result = ffsEngine->replace(index, buffer, mode);
if (result) {
QMessageBox::critical(this, tr("Replacing failed"), errorMessage(result), QMessageBox::Ok);
return;
}
ui->actionSaveImageFile->setEnabled(true);*/
}
void UEFITool::extractAsIs()
{
extract(EXTRACT_MODE_AS_IS);
}
void UEFITool::extractBody()
{
extract(EXTRACT_MODE_BODY);
}
void UEFITool::extract(const UINT8 mode)
{
QModelIndex index = ui->structureTreeView->selectionModel()->currentIndex();
if (!index.isValid())
return;
TreeModel* model = ffsParser->treeModel();
QByteArray extracted;
QString name;
UINT8 result = ffsParser->extract(index, name, extracted, mode);
if (result) {
QMessageBox::critical(this, tr("Extraction failed"), errorCodeToQString(result), QMessageBox::Ok);
return;
}
name = currentDir + QDir::separator() + name;
UINT8 type = model->type(index);
QString path;
if (mode == EXTRACT_MODE_AS_IS) {
switch (type) {
case Types::Capsule:
path = QFileDialog::getSaveFileName(this, tr("Save capsule to file"), name + ".cap", "Capsule files (*.cap *.bin);;All files (*)");
break;
case Types::Image:
path = QFileDialog::getSaveFileName(this, tr("Save image to file"), name + ".rom", "Image files (*.rom *.bin);;All files (*)");
break;
case Types::Region:
path = QFileDialog::getSaveFileName(this, tr("Save region to file"), name + ".rgn", "Region files (*.rgn *.bin);;All files (*)");
break;
case Types::Padding:
path = QFileDialog::getSaveFileName(this, tr("Save padding to file"), name + ".pad", "Padding files (*.pad *.bin);;All files (*)");
break;
case Types::Volume:
path = QFileDialog::getSaveFileName(this, tr("Save volume to file"), name + ".vol", "Volume files (*.vol *.bin);;All files (*)");
break;
case Types::File:
path = QFileDialog::getSaveFileName(this, tr("Save FFS file to file"), name + ".ffs", "FFS files (*.ffs *.bin);;All files (*)");
break;
case Types::Section:
path = QFileDialog::getSaveFileName(this, tr("Save section file to file"), name + ".sct", "Section files (*.sct *.bin);;All files (*)");
break;
default:
path = QFileDialog::getSaveFileName(this, tr("Save object to file"), name + ".bin", "Binary files (*.bin);;All files (*)");
}
}
else if (mode == EXTRACT_MODE_BODY) {
switch (type) {
case Types::Capsule:
path = QFileDialog::getSaveFileName(this, tr("Save capsule body to image file"), name + ".rom", "Image files (*.rom *.bin);;All files (*)");
break;
case Types::Volume:
path = QFileDialog::getSaveFileName(this, tr("Save volume body to file"), name + ".vbd", "Volume body files (*.vbd *.bin);;All files (*)");
break;
case Types::File: {
if (model->subtype(index) == EFI_FV_FILETYPE_ALL || model->subtype(index) == EFI_FV_FILETYPE_RAW)
path = QFileDialog::getSaveFileName(this, tr("Save FFS file body to raw file"), name + ".raw", "Raw files (*.raw *.bin);;All files (*)");
else
path = QFileDialog::getSaveFileName(this, tr("Save FFS file body to file"), name + ".fbd", "FFS file body files (*.fbd *.bin);;All files (*)");
}
break;
case Types::Section: {
if (model->subtype(index) == EFI_SECTION_COMPRESSION || model->subtype(index) == EFI_SECTION_GUID_DEFINED || model->subtype(index) == EFI_SECTION_DISPOSABLE)
path = QFileDialog::getSaveFileName(this, tr("Save encapsulation section body to FFS body file"), name + ".fbd", "FFS file body files (*.fbd *.bin);;All files (*)");
else if (model->subtype(index) == EFI_SECTION_FIRMWARE_VOLUME_IMAGE)
path = QFileDialog::getSaveFileName(this, tr("Save section body to volume file"), name + ".vol", "Volume files (*.vol *.bin);;All files (*)");
else if (model->subtype(index) == EFI_SECTION_RAW)
path = QFileDialog::getSaveFileName(this, tr("Save section body to raw file"), name + ".raw", "Raw files (*.raw *.bin);;All files (*)");
else
path = QFileDialog::getSaveFileName(this, tr("Save section body to file"), name + ".bin", "Binary files (*.bin);;All files (*)");
}
break;
default:
path = QFileDialog::getSaveFileName(this, tr("Save object to file"), name + ".bin", "Binary files (*.bin);;All files (*)");
}
}
else
path = QFileDialog::getSaveFileName(this, tr("Save object to file"), name + ".bin", "Binary files (*.bin);;All files (*)");
if (path.trimmed().isEmpty())
return;
QFile outputFile;
outputFile.setFileName(path);
if (!outputFile.open(QFile::WriteOnly)) {
QMessageBox::critical(this, tr("Extraction failed"), tr("Can't open output file for rewriting"), QMessageBox::Ok);
return;
}
outputFile.resize(0);
outputFile.write(extracted);
outputFile.close();
}
void UEFITool::about()
{
QMessageBox::about(this, tr("About UEFITool"), tr(
"Copyright (c) 2015, Nikolaj Schlej aka <b>CodeRush</b>.<br>"
"Program icon made by <a href=https://www.behance.net/alzhidkov>Alexander Zhidkov</a>.<br><br>"
"The program is dedicated to <b>RevoGirl</b>. Rest in peace, young genius.<br><br>"
"The program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License.<br>"
"The full text of the license may be found at <a href=http://opensource.org/licenses/bsd-license.php>OpenSource.org</a>.<br><br>"
"<b>THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN \"AS IS\" BASIS, "
"WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, "
"EITHER EXPRESS OR IMPLIED.</b>"));
}
void UEFITool::aboutQt()
{
QMessageBox::aboutQt(this, tr("About Qt"));
}
void UEFITool::exit()
{
QCoreApplication::exit(0);
}
void UEFITool::saveImageFile()
{
/*QString path = QFileDialog::getSaveFileName(this, tr("Save BIOS image file"), currentDir, "BIOS image files (*.rom *.bin *.cap *.bio *.fd *.wph *.efi *.dec);;All files (*)");
if (path.isEmpty())
return;
QByteArray reconstructed;
UINT8 result = ffsEngine->reconstructImageFile(reconstructed);
showMessages();
if (result) {
QMessageBox::critical(this, tr("Image reconstruction failed"), errorMessage(result), QMessageBox::Ok);
return;
}
QFile outputFile;
outputFile.setFileName(path);
if (!outputFile.open(QFile::WriteOnly)) {
QMessageBox::critical(this, tr("Image reconstruction failed"), tr("Can't open output file for rewriting"), QMessageBox::Ok);
return;
}
outputFile.resize(0);
outputFile.write(reconstructed);
outputFile.close();
if (QMessageBox::information(this, tr("Image reconstruction successful"), tr("Open reconstructed file?"), QMessageBox::Yes, QMessageBox::No)
== QMessageBox::Yes)
openImageFile(path);*/
}
void UEFITool::openImageFile()
{
QString path = QFileDialog::getOpenFileName(this, tr("Open BIOS image file"), currentDir, "BIOS image files (*.rom *.bin *.cap *.bio *.fd *.wph *.efi *.dec);;All files (*)");
openImageFile(path);
}
void UEFITool::openImageFile(QString path)
{
if (path.trimmed().isEmpty())
return;
QFileInfo fileInfo = QFileInfo(path);
if (!fileInfo.exists()) {
ui->statusBar->showMessage(tr("Please select existing file"));
return;
}
QFile inputFile;
inputFile.setFileName(path);
if (!inputFile.open(QFile::ReadOnly)) {
QMessageBox::critical(this, tr("Image parsing failed"), tr("Can't open input file for reading"), QMessageBox::Ok);
return;
}
QByteArray buffer = inputFile.readAll();
inputFile.close();
init();
this->setWindowTitle(tr("UEFITool %1 - %2").arg(version).arg(fileInfo.fileName()));
UINT8 result = ffsParser->parseImageFile(buffer);
showMessages();
if (result)
QMessageBox::critical(this, tr("Image parsing failed"), errorCodeToQString(result), QMessageBox::Ok);
else
ui->statusBar->showMessage(tr("Opened: %1").arg(fileInfo.fileName()));
// Enable search
ui->actionSearch->setEnabled(true);
// Set current directory
currentDir = fileInfo.absolutePath();
}
void UEFITool::copyMessage()
{
clipboard->clear();
clipboard->setText(ui->messageListWidget->currentItem()->text());
}
void UEFITool::copyAllMessages()
{
QString text;
clipboard->clear();
for(INT32 i = 0; i < ui->messageListWidget->count(); i++)
text.append(ui->messageListWidget->item(i)->text()).append("\n");
clipboard->clear();
clipboard->setText(text);
}
void UEFITool::enableMessagesCopyActions(QListWidgetItem* item)
{
ui->actionMessagesCopy->setEnabled(item != NULL);
ui->actionMessagesCopyAll->setEnabled(item != NULL);
}
void UEFITool::clearMessages()
{
ffsParser->clearMessages();
messageItems.clear();
ui->messageListWidget->clear();
ui->actionMessagesCopy->setEnabled(false);
ui->actionMessagesCopyAll->setEnabled(false);
}
void UEFITool::dragEnterEvent(QDragEnterEvent* event)
{
if (event->mimeData()->hasFormat("text/uri-list"))
event->acceptProposedAction();
}
void UEFITool::dropEvent(QDropEvent* event)
{
QString path = event->mimeData()->urls().at(0).toLocalFile();
openImageFile(path);
}
void UEFITool::showMessages()
{
ui->messageListWidget->clear();
if (!ffsParser)
return;
messageItems = ffsParser->messages();
for (int i = 0; i < messageItems.count(); i++) {
ui->messageListWidget->addItem(new MessageListItem(messageItems.at(i)));
}
ui->messageListWidget->scrollToBottom();
}
void UEFITool::scrollTreeView(QListWidgetItem* item)
{
MessageListItem* messageItem = static_cast<MessageListItem*>(item);
QModelIndex index = messageItem->index();
if (index.isValid()) {
ui->structureTreeView->scrollTo(index, QAbstractItemView::PositionAtCenter);
ui->structureTreeView->selectionModel()->clearSelection();
ui->structureTreeView->selectionModel()->select(index, QItemSelectionModel::Select);
}
}
void UEFITool::contextMenuEvent(QContextMenuEvent* event)
{
if (ui->messageListWidget->underMouse()) {
ui->menuMessages->exec(event->globalPos());
return;
}
if (!ui->structureTreeView->underMouse())
return;
QPoint pt = event->pos();
QModelIndex index = ui->structureTreeView->indexAt(ui->structureTreeView->viewport()->mapFrom(this, pt));
if (!index.isValid())
return;
TreeModel* model = ffsParser->treeModel();
switch (model->type(index))
{
case Types::Capsule:
ui->menuCapsuleActions->exec(event->globalPos());
break;
case Types::Image:
ui->menuImageActions->exec(event->globalPos());
break;
case Types::Region:
ui->menuRegionActions->exec(event->globalPos());
break;
case Types::Padding:
ui->menuPaddingActions->exec(event->globalPos());
break;
case Types::Volume:
ui->menuVolumeActions->exec(event->globalPos());
break;
case Types::File:
ui->menuFileActions->exec(event->globalPos());
break;
case Types::Section:
ui->menuSectionActions->exec(event->globalPos());
break;
}
}
void UEFITool::readSettings()
{
QSettings settings(this);
resize(settings.value("mainWindow/size", QSize(800, 600)).toSize());
move(settings.value("mainWindow/position", QPoint(0, 0)).toPoint());
QList<int> horList, vertList;
horList.append(settings.value("mainWindow/treeWidth", 600).toInt());
horList.append(settings.value("mainWindow/infoWidth", 180).toInt());
vertList.append(settings.value("mainWindow/treeHeight", 400).toInt());
vertList.append(settings.value("mainWindow/messageHeight", 180).toInt());
ui->infoSplitter->setSizes(horList);
ui->messagesSplitter->setSizes(vertList);
ui->structureTreeView->setColumnWidth(0, settings.value("tree/columnWidth0", ui->structureTreeView->columnWidth(0)).toInt());
ui->structureTreeView->setColumnWidth(1, settings.value("tree/columnWidth1", ui->structureTreeView->columnWidth(1)).toInt());
ui->structureTreeView->setColumnWidth(2, settings.value("tree/columnWidth2", ui->structureTreeView->columnWidth(2)).toInt());
ui->structureTreeView->setColumnWidth(3, settings.value("tree/columnWidth3", ui->structureTreeView->columnWidth(3)).toInt());
}
void UEFITool::writeSettings()
{
QSettings settings(this);
settings.setValue("mainWindow/size", size());
settings.setValue("mainWindow/position", pos());
settings.setValue("mainWindow/treeWidth", ui->structureGroupBox->width());
settings.setValue("mainWindow/infoWidth", ui->infoGroupBox->width());
settings.setValue("mainWindow/treeHeight", ui->structureGroupBox->height());
settings.setValue("mainWindow/messageHeight", ui->messageGroupBox->height());
settings.setValue("tree/columnWidth0", ui->structureTreeView->columnWidth(0));
settings.setValue("tree/columnWidth1", ui->structureTreeView->columnWidth(1));
settings.setValue("tree/columnWidth2", ui->structureTreeView->columnWidth(2));
settings.setValue("tree/columnWidth3", ui->structureTreeView->columnWidth(3));
}

View File

@ -1,110 +0,0 @@
/* uefitool.h
Copyright (c) 2014, 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 __UEFITOOL_H__
#define __UEFITOOL_H__
#include <QMainWindow>
#include <QByteArray>
#include <QClipboard>
#include <QDragEnterEvent>
#include <QDropEvent>
#include <QFile>
#include <QFileDialog>
#include <QFileInfo>
#include <QListWidget>
#include <QMenu>
#include <QMessageBox>
#include <QMimeData>
#include <QPlainTextEdit>
#include <QSettings>
#include <QSplitter>
#include <QString>
#include <QTreeView>
#include <QUrl>
#include "basetypes.h"
#include "utility.h"
#include "ffs.h"
#include "ffsparser.h"
#include "searchdialog.h"
namespace Ui {
class UEFITool;
}
class UEFITool : public QMainWindow
{
Q_OBJECT
public:
explicit UEFITool(QWidget *parent = 0);
~UEFITool();
void openImageFile(QString path);
private slots:
void init();
void populateUi(const QModelIndex &current);
void scrollTreeView(QListWidgetItem* item);
void openImageFile();
void saveImageFile();
void search();
void extract(const UINT8 mode);
void extractAsIs();
void extractBody();
void insert(const UINT8 mode);
void insertInto();
void insertBefore();
void insertAfter();
void replace(const UINT8 mode);
void replaceAsIs();
void replaceBody();
void rebuild();
void remove();
void copyMessage();
void copyAllMessages();
void enableMessagesCopyActions(QListWidgetItem* item);
void clearMessages();
void about();
void aboutQt();
void exit();
void writeSettings();
private:
Ui::UEFITool* ui;
FfsParser* ffsParser;
SearchDialog* searchDialog;
QClipboard* clipboard;
QString currentDir;
QQueue<MessageListItem> messageItems;
const QString version;
void showMessages();
void dragEnterEvent(QDragEnterEvent* event);
void dropEvent(QDropEvent* event);
void contextMenuEvent(QContextMenuEvent* event);
void readSettings();
};
#endif

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

View File

@ -1,55 +0,0 @@
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = UEFITool
TEMPLATE = app
SOURCES += uefitool_main.cpp \
uefitool.cpp \
searchdialog.cpp \
types.cpp \
descriptor.cpp \
ffs.cpp \
peimage.cpp \
utility.cpp \
ffsparser.cpp \
treeitem.cpp \
treemodel.cpp \
messagelistitem.cpp \
guidlineedit.cpp \
LZMA/LzmaCompress.c \
LZMA/LzmaDecompress.c \
LZMA/SDK/C/LzFind.c \
LZMA/SDK/C/LzmaDec.c \
LZMA/SDK/C/LzmaEnc.c \
Tiano/EfiTianoDecompress.c \
Tiano/EfiTianoCompress.c \
Tiano/EfiTianoCompressLegacy.c
HEADERS += uefitool.h \
searchdialog.h \
basetypes.h \
descriptor.h \
gbe.h \
me.h \
ffs.h \
peimage.h \
types.h \
utility.h \
ffsparser.h \
treeitem.h \
treemodel.h \
messagelistitem.h \
guidlineedit.h \
LZMA/LzmaCompress.h \
LZMA/LzmaDecompress.h \
Tiano/EfiTianoDecompress.h \
Tiano/EfiTianoCompress.h
FORMS += uefitool.ui \
searchdialog.ui
RC_FILE = uefitool.rc
ICON = uefitool.icns

View File

@ -1 +0,0 @@
IDI_ICON1 ICON DISCARDABLE "uefitool.ico"

View File

@ -1,529 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>UEFITool</class>
<widget class="QMainWindow" name="UEFITool">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="acceptDrops">
<bool>true</bool>
</property>
<property name="windowTitle">
<string>UEFITool</string>
</property>
<widget class="QWidget" name="centralWidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_7">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QSplitter" name="messagesSplitter">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<widget class="QSplitter" name="infoSplitter">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<widget class="QGroupBox" name="structureGroupBox">
<property name="title">
<string>Structure</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>5</number>
</property>
<property name="topMargin">
<number>5</number>
</property>
<property name="rightMargin">
<number>5</number>
</property>
<property name="bottomMargin">
<number>5</number>
</property>
<item>
<widget class="QTreeView" name="structureTreeView">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="indentation">
<number>10</number>
</property>
<property name="headerHidden">
<bool>false</bool>
</property>
<attribute name="headerCascadingSectionResizes">
<bool>true</bool>
</attribute>
<attribute name="headerDefaultSectionSize">
<number>200</number>
</attribute>
<attribute name="headerStretchLastSection">
<bool>true</bool>
</attribute>
</widget>
</item>
</layout>
</widget>
<widget class="QGroupBox" name="infoGroupBox">
<property name="title">
<string>Information</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>5</number>
</property>
<property name="topMargin">
<number>5</number>
</property>
<property name="rightMargin">
<number>5</number>
</property>
<property name="bottomMargin">
<number>5</number>
</property>
<item>
<widget class="QPlainTextEdit" name="infoEdit">
<property name="acceptDrops">
<bool>false</bool>
</property>
<property name="undoRedoEnabled">
<bool>false</bool>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
<property name="centerOnScroll">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<widget class="QGroupBox" name="messageGroupBox">
<property name="title">
<string>Messages</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>5</number>
</property>
<property name="topMargin">
<number>5</number>
</property>
<property name="rightMargin">
<number>5</number>
</property>
<property name="bottomMargin">
<number>5</number>
</property>
<item>
<widget class="QListWidget" name="messageListWidget">
<property name="mouseTracking">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QStatusBar" name="statusBar"/>
<widget class="QMenuBar" name="menuBar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>21</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
<property name="title">
<string>&amp;File</string>
</property>
<addaction name="actionOpenImageFile"/>
<addaction name="actionSaveImageFile"/>
<addaction name="separator"/>
<addaction name="actionSearch"/>
<addaction name="separator"/>
<addaction name="actionQuit"/>
</widget>
<widget class="QMenu" name="menuHelp">
<property name="title">
<string>H&amp;elp</string>
</property>
<addaction name="actionAbout"/>
<addaction name="actionAboutQt"/>
</widget>
<widget class="QMenu" name="menuAction">
<property name="title">
<string>&amp;Action</string>
</property>
<widget class="QMenu" name="menuCapsuleActions">
<property name="title">
<string>&amp;Capsule</string>
</property>
<addaction name="actionExtract"/>
<addaction name="actionExtractBody"/>
</widget>
<widget class="QMenu" name="menuImageActions">
<property name="title">
<string>&amp;Image</string>
</property>
<addaction name="actionExtract"/>
</widget>
<widget class="QMenu" name="menuRegionActions">
<property name="title">
<string>&amp;Region</string>
</property>
<addaction name="actionExtract"/>
<addaction name="separator"/>
<addaction name="actionReplace"/>
</widget>
<widget class="QMenu" name="menuPaddingActions">
<property name="title">
<string>&amp;Padding</string>
</property>
<addaction name="actionExtract"/>
</widget>
<widget class="QMenu" name="menuVolumeActions">
<property name="title">
<string>&amp;Volume</string>
</property>
<addaction name="actionExtract"/>
<addaction name="actionExtractBody"/>
<addaction name="separator"/>
<addaction name="actionRebuild"/>
<addaction name="separator"/>
<addaction name="actionInsertInto"/>
<addaction name="separator"/>
<addaction name="actionReplace"/>
<addaction name="actionReplaceBody"/>
</widget>
<widget class="QMenu" name="menuFileActions">
<property name="title">
<string>&amp;File</string>
</property>
<addaction name="actionExtract"/>
<addaction name="actionExtractBody"/>
<addaction name="separator"/>
<addaction name="actionRebuild"/>
<addaction name="separator"/>
<addaction name="actionInsertInto"/>
<addaction name="actionInsertBefore"/>
<addaction name="actionInsertAfter"/>
<addaction name="separator"/>
<addaction name="actionReplace"/>
<addaction name="actionReplaceBody"/>
<addaction name="separator"/>
<addaction name="actionRemove"/>
</widget>
<widget class="QMenu" name="menuSectionActions">
<property name="title">
<string>&amp;Section</string>
</property>
<addaction name="actionExtract"/>
<addaction name="actionExtractBody"/>
<addaction name="separator"/>
<addaction name="actionRebuild"/>
<addaction name="separator"/>
<addaction name="actionInsertInto"/>
<addaction name="actionInsertBefore"/>
<addaction name="actionInsertAfter"/>
<addaction name="separator"/>
<addaction name="actionReplace"/>
<addaction name="actionReplaceBody"/>
<addaction name="separator"/>
<addaction name="actionRemove"/>
<addaction name="separator"/>
</widget>
<widget class="QMenu" name="menuMessages">
<property name="title">
<string>&amp;Messages</string>
</property>
<addaction name="actionMessagesCopy"/>
<addaction name="actionMessagesCopyAll"/>
<addaction name="separator"/>
<addaction name="actionMessagesClear"/>
</widget>
<addaction name="menuCapsuleActions"/>
<addaction name="menuImageActions"/>
<addaction name="menuRegionActions"/>
<addaction name="menuPaddingActions"/>
<addaction name="menuVolumeActions"/>
<addaction name="menuFileActions"/>
<addaction name="menuSectionActions"/>
<addaction name="separator"/>
<addaction name="menuMessages"/>
</widget>
<addaction name="menuFile"/>
<addaction name="menuAction"/>
<addaction name="menuHelp"/>
</widget>
<action name="actionInsertAfter">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Insert &amp;after...</string>
</property>
<property name="toolTip">
<string>Insert an object from file after selected object</string>
</property>
<property name="shortcut">
<string>Ctrl+Shift+I</string>
</property>
</action>
<action name="actionInsertBefore">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Insert b&amp;efore...</string>
</property>
<property name="toolTip">
<string>Insert object from file before selected object</string>
</property>
<property name="shortcut">
<string>Ctrl+Alt+I</string>
</property>
</action>
<action name="actionReplace">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Rep&amp;lace as is...</string>
</property>
<property name="toolTip">
<string>Replace selected object as is with an object from file</string>
</property>
<property name="shortcut">
<string>Ctrl+R</string>
</property>
</action>
<action name="actionExtract">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>E&amp;xtract as is...</string>
</property>
<property name="toolTip">
<string>Extract selected object as is to file</string>
</property>
<property name="shortcut">
<string>Ctrl+E</string>
</property>
</action>
<action name="actionExtractBody">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Extract &amp;body...</string>
</property>
<property name="toolTip">
<string>Extract body of selected object to file</string>
</property>
<property name="shortcut">
<string>Ctrl+Shift+E</string>
</property>
</action>
<action name="actionRemove">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Re&amp;move</string>
</property>
<property name="toolTip">
<string>Remove selected object</string>
</property>
<property name="shortcut">
<string>Ctrl+Del</string>
</property>
</action>
<action name="actionOpenImageFile">
<property name="text">
<string>&amp;Open image file...</string>
</property>
<property name="toolTip">
<string>Open image file</string>
</property>
<property name="shortcut">
<string>Ctrl+O</string>
</property>
</action>
<action name="actionInsertInto">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Insert &amp;into...</string>
</property>
<property name="toolTip">
<string>Insert object from file into selected object</string>
</property>
<property name="shortcut">
<string>Ctrl+I</string>
</property>
</action>
<action name="actionSaveImageFile">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>&amp;Save image file...</string>
</property>
<property name="toolTip">
<string>Save modified image file</string>
</property>
<property name="shortcut">
<string>Ctrl+S</string>
</property>
</action>
<action name="actionRebuild">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>&amp;Rebuild</string>
</property>
<property name="toolTip">
<string>Rebuild selected object</string>
</property>
<property name="shortcut">
<string>Ctrl+Space</string>
</property>
</action>
<action name="actionAbout">
<property name="text">
<string>&amp;About UEFITool</string>
</property>
<property name="shortcut">
<string>F1</string>
</property>
<property name="menuRole">
<enum>QAction::AboutRole</enum>
</property>
</action>
<action name="actionAboutQt">
<property name="text">
<string>About &amp;Qt</string>
</property>
<property name="menuRole">
<enum>QAction::AboutQtRole</enum>
</property>
</action>
<action name="actionQuit">
<property name="text">
<string>&amp;Quit</string>
</property>
<property name="menuRole">
<enum>QAction::QuitRole</enum>
</property>
</action>
<action name="actionSearch">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Sear&amp;ch...</string>
</property>
<property name="shortcut">
<string>Ctrl+F</string>
</property>
</action>
<action name="actionMessagesClear">
<property name="text">
<string>Cl&amp;ear</string>
</property>
<property name="toolTip">
<string>Clear messages</string>
</property>
<property name="shortcut">
<string>Ctrl+Backspace</string>
</property>
</action>
<action name="actionReplaceBody">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Replace b&amp;ody...</string>
</property>
<property name="toolTip">
<string>Replace body of selected object with a data from file</string>
</property>
<property name="shortcut">
<string>Ctrl+Shift+R</string>
</property>
</action>
<action name="actionMessagesCopy">
<property name="text">
<string>&amp;Copy</string>
</property>
<property name="shortcut">
<string>Ctrl+Shift+C</string>
</property>
</action>
<action name="actionMessagesCopyAll">
<property name="text">
<string>C&amp;opy all</string>
</property>
<property name="shortcut">
<string>Ctrl+Alt+C</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>

View File

@ -1,31 +0,0 @@
/* uefitool_main.cpp
Copyright (c) 2014, 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 <QApplication>
#include <QString>
#include "uefitool.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
a.setOrganizationName("CodeRush");
a.setOrganizationDomain("coderush.me");
a.setApplicationName("UEFITool");
UEFITool w;
if (a.arguments().length() > 1)
w.openImageFile(a.arguments().at(1));
w.show();
return a.exec();
}