2013-10-08 15:07:03 +08:00
|
|
|
/* uefitool.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 "uefitool.h"
|
|
|
|
#include "ui_uefitool.h"
|
|
|
|
|
|
|
|
UEFITool::UEFITool(QWidget *parent) :
|
|
|
|
QMainWindow(parent),
|
|
|
|
ui(new Ui::UEFITool)
|
|
|
|
{
|
|
|
|
ui->setupUi(this);
|
2013-10-15 23:19:15 +08:00
|
|
|
ffsEngine = NULL;
|
2013-10-08 15:07:03 +08:00
|
|
|
|
2013-10-15 23:19:15 +08:00
|
|
|
//Connect
|
|
|
|
connect(ui->actionOpenImageFile, SIGNAL(triggered()), this, SLOT(openImageFile()));
|
2013-11-07 21:46:28 +08:00
|
|
|
connect(ui->actionExtract, SIGNAL(triggered()), this, SLOT(extract()));
|
|
|
|
connect(ui->actionExtractBody, SIGNAL(triggered()), this, SLOT(extractBody()));
|
|
|
|
connect(ui->actionExtractUncompressed, SIGNAL(triggered()), this, SLOT(extractUncompressed()));
|
|
|
|
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(replace()));
|
|
|
|
connect(ui->actionRemove, SIGNAL(triggered()), this, SLOT(remove()));
|
|
|
|
connect(ui->actionSaveImageFile, SIGNAL(triggered()), this, SLOT(saveImageFile()));
|
2013-11-14 18:40:39 +08:00
|
|
|
|
2013-10-08 15:07:03 +08:00
|
|
|
// Enable Drag-and-Drop actions
|
|
|
|
this->setAcceptDrops(true);
|
|
|
|
|
2013-11-14 18:40:39 +08:00
|
|
|
// Initialize non-persistent data
|
2013-10-08 15:07:03 +08:00
|
|
|
init();
|
|
|
|
}
|
|
|
|
|
|
|
|
UEFITool::~UEFITool()
|
|
|
|
{
|
|
|
|
delete ui;
|
2013-10-15 23:19:15 +08:00
|
|
|
delete ffsEngine;
|
2013-10-08 15:07:03 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void UEFITool::init()
|
|
|
|
{
|
2013-11-15 18:48:14 +08:00
|
|
|
// Clear components
|
|
|
|
ui->debugListWidget->clear();
|
2013-10-08 15:07:03 +08:00
|
|
|
ui->infoEdit->clear();
|
2013-10-15 23:19:15 +08:00
|
|
|
|
|
|
|
// Disable all actions except openImageFile
|
|
|
|
ui->actionExtract->setDisabled(true);
|
|
|
|
ui->actionExtractBody->setDisabled(true);
|
|
|
|
ui->actionExtractUncompressed->setDisabled(true);
|
|
|
|
ui->actionReplace->setDisabled(true);
|
2013-11-07 21:46:28 +08:00
|
|
|
ui->actionRemove->setDisabled(true);
|
|
|
|
ui->actionInsertInto->setDisabled(true);
|
2013-10-15 23:19:15 +08:00
|
|
|
ui->actionInsertBefore->setDisabled(true);
|
|
|
|
ui->actionInsertAfter->setDisabled(true);
|
2013-11-07 21:46:28 +08:00
|
|
|
ui->actionSaveImageFile->setDisabled(true);
|
2013-10-15 23:19:15 +08:00
|
|
|
|
|
|
|
// Make new ffsEngine
|
|
|
|
ffsEngine = new FfsEngine(this);
|
|
|
|
ui->structureTreeView->setModel(ffsEngine->model());
|
|
|
|
|
|
|
|
// Connect
|
|
|
|
connect(ui->structureTreeView, SIGNAL(collapsed(const QModelIndex &)), this, SLOT(resizeTreeViewColums(void)));
|
|
|
|
connect(ui->structureTreeView, SIGNAL(expanded(const QModelIndex &)), this, SLOT(resizeTreeViewColums(void)));
|
2013-10-08 15:07:03 +08:00
|
|
|
connect(ui->structureTreeView->selectionModel(), SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)),
|
|
|
|
this, SLOT(populateUi(const QModelIndex &)));
|
2013-11-15 18:48:14 +08:00
|
|
|
connect(ui->debugListWidget, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(scrollTreeView(QListWidgetItem*)));
|
2013-11-14 18:40:39 +08:00
|
|
|
|
|
|
|
resizeTreeViewColums();
|
2013-10-08 15:07:03 +08:00
|
|
|
}
|
|
|
|
|
2013-11-14 18:40:39 +08:00
|
|
|
void UEFITool::populateUi(const QModelIndex ¤t)
|
2013-10-08 15:07:03 +08:00
|
|
|
{
|
|
|
|
currentIndex = current;
|
|
|
|
ui->infoEdit->setPlainText(current.data(Qt::UserRole).toString());
|
2013-10-15 23:19:15 +08:00
|
|
|
ui->actionExtract->setDisabled(ffsEngine->hasEmptyBody(current) && ffsEngine->hasEmptyHeader(current));
|
|
|
|
ui->actionExtractBody->setDisabled(ffsEngine->hasEmptyHeader(current));
|
|
|
|
ui->actionExtractUncompressed->setEnabled(ffsEngine->isCompressedFile(current));
|
2013-11-07 21:46:28 +08:00
|
|
|
ui->actionRemove->setEnabled(ffsEngine->isOfType(TreeItem::Volume, current)
|
|
|
|
|| ffsEngine->isOfType(TreeItem::File, current)
|
|
|
|
|| ffsEngine->isOfType(TreeItem::Section, current));
|
2013-11-14 18:40:39 +08:00
|
|
|
ui->actionInsertInto->setEnabled(ffsEngine->isOfType(TreeItem::Volume, current)
|
|
|
|
|| ffsEngine->isOfType(TreeItem::File, current)
|
2013-11-15 18:48:14 +08:00
|
|
|
|| (ffsEngine->isOfType(TreeItem::Section, current)
|
|
|
|
&& (ffsEngine->isOfSubtype(EFI_SECTION_COMPRESSION, current)
|
|
|
|
|| ffsEngine->isOfSubtype(EFI_SECTION_GUID_DEFINED, current)
|
|
|
|
|| ffsEngine->isOfSubtype(EFI_SECTION_DISPOSABLE, current))));
|
2013-11-14 18:40:39 +08:00
|
|
|
ui->actionInsertBefore->setEnabled(ffsEngine->isOfType(TreeItem::File, current)
|
|
|
|
|| ffsEngine->isOfType(TreeItem::Section, current));
|
|
|
|
ui->actionInsertAfter->setEnabled(ffsEngine->isOfType(TreeItem::File, current)
|
|
|
|
|| ffsEngine->isOfType(TreeItem::Section, current));
|
|
|
|
//ui->actionReplace->setEnabled(ffsEngine->isOfType(TreeItem::File, current));
|
2013-11-07 21:46:28 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void UEFITool::remove()
|
|
|
|
{
|
|
|
|
UINT8 result = ffsEngine->remove(currentIndex);
|
|
|
|
if (result) {
|
2013-11-15 18:48:14 +08:00
|
|
|
|
2013-11-07 21:46:28 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
ui->actionSaveImageFile->setEnabled(true);
|
2013-11-14 18:40:39 +08:00
|
|
|
|
|
|
|
resizeTreeViewColums();
|
2013-11-07 21:46:28 +08:00
|
|
|
}
|
|
|
|
|
2013-11-14 18:40:39 +08:00
|
|
|
void UEFITool::insert(const UINT8 mode)
|
2013-11-07 21:46:28 +08:00
|
|
|
{
|
2013-11-14 18:40:39 +08:00
|
|
|
QString path;
|
|
|
|
TreeItem* item = static_cast<TreeItem*>(currentIndex.internalPointer());
|
|
|
|
|
|
|
|
UINT8 type;
|
|
|
|
UINT8 objectType;
|
2013-11-15 18:48:14 +08:00
|
|
|
if (mode == INSERT_MODE_BEFORE || mode == INSERT_MODE_AFTER)
|
2013-11-14 18:40:39 +08:00
|
|
|
type = item->parent()->type();
|
|
|
|
else
|
|
|
|
type = item->type();
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case TreeItem::Volume:
|
|
|
|
path = QFileDialog::getOpenFileName(this, tr("Select FFS file to insert"),".","FFS file (*.ffs *.bin);;All files (*.*)");
|
|
|
|
objectType = TreeItem::File;
|
|
|
|
break;
|
|
|
|
case TreeItem::File:
|
|
|
|
case TreeItem::Section:
|
|
|
|
path = QFileDialog::getOpenFileName(this, tr("Select section file to insert"),".","Section file (*.sec *.bin);;All files (*.*)");
|
|
|
|
objectType = TreeItem::Section;
|
|
|
|
break;
|
|
|
|
default:
|
2013-11-07 21:46:28 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
QFileInfo fileInfo = QFileInfo(path);
|
|
|
|
if (!fileInfo.exists())
|
|
|
|
{
|
2013-11-14 18:40:39 +08:00
|
|
|
ui->statusBar->showMessage(tr("Please select existing file"));
|
2013-11-07 21:46:28 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
QFile inputFile;
|
|
|
|
inputFile.setFileName(path);
|
|
|
|
|
|
|
|
if (!inputFile.open(QFile::ReadOnly))
|
|
|
|
{
|
|
|
|
ui->statusBar->showMessage(tr("Can't open file for reading"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
QByteArray buffer = inputFile.readAll();
|
|
|
|
inputFile.close();
|
|
|
|
|
2013-11-14 18:40:39 +08:00
|
|
|
UINT8 result = ffsEngine->insert(currentIndex, buffer, objectType, mode);
|
2013-11-07 21:46:28 +08:00
|
|
|
if (result)
|
2013-11-14 18:40:39 +08:00
|
|
|
ui->statusBar->showMessage(tr("File can't be inserted (%1)").arg(result));
|
2013-11-07 21:46:28 +08:00
|
|
|
else
|
|
|
|
ui->actionSaveImageFile->setEnabled(true);
|
2013-11-14 18:40:39 +08:00
|
|
|
|
2013-11-07 21:46:28 +08:00
|
|
|
resizeTreeViewColums();
|
2013-10-08 15:07:03 +08:00
|
|
|
}
|
|
|
|
|
2013-11-14 18:40:39 +08:00
|
|
|
void UEFITool::insertInto()
|
2013-11-07 21:46:28 +08:00
|
|
|
{
|
2013-11-14 18:40:39 +08:00
|
|
|
insert(INSERT_MODE_PREPEND);
|
|
|
|
}
|
2013-11-07 21:46:28 +08:00
|
|
|
|
2013-11-14 18:40:39 +08:00
|
|
|
void UEFITool::insertBefore()
|
|
|
|
{
|
|
|
|
insert(INSERT_MODE_BEFORE);
|
|
|
|
}
|
2013-11-07 21:46:28 +08:00
|
|
|
|
2013-11-14 18:40:39 +08:00
|
|
|
void UEFITool::insertAfter()
|
|
|
|
{
|
|
|
|
insert(INSERT_MODE_AFTER);
|
2013-11-07 21:46:28 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void UEFITool::replace()
|
|
|
|
{
|
2013-11-14 18:40:39 +08:00
|
|
|
|
2013-11-07 21:46:28 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void UEFITool::saveImageFile()
|
|
|
|
{
|
2013-11-14 18:40:39 +08:00
|
|
|
QString path = QFileDialog::getSaveFileName(this, tr("Save BIOS image file"),".","BIOS image file (*.rom *.bin *.cap *.fd *.wph *.efi);;All files (*.*)");
|
2013-11-07 21:46:28 +08:00
|
|
|
|
|
|
|
QFile outputFile;
|
|
|
|
outputFile.setFileName(path);
|
|
|
|
if (!outputFile.open(QFile::WriteOnly))
|
|
|
|
{
|
|
|
|
ui->statusBar->showMessage(tr("Can't open file for writing"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
QByteArray reconstructed;
|
|
|
|
UINT8 result = ffsEngine->reconstructImage(reconstructed);
|
|
|
|
if (result)
|
|
|
|
{
|
|
|
|
ui->statusBar->showMessage(tr("Reconstruction failed (%1)").arg(result));
|
2013-11-15 18:48:14 +08:00
|
|
|
showDebugMessage();
|
2013-11-07 21:46:28 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-11-14 18:40:39 +08:00
|
|
|
outputFile.resize(0);
|
2013-11-07 21:46:28 +08:00
|
|
|
outputFile.write(reconstructed);
|
|
|
|
outputFile.close();
|
|
|
|
ui->statusBar->showMessage(tr("Reconstructed image written"));
|
2013-11-15 18:48:14 +08:00
|
|
|
showDebugMessage();
|
2013-11-07 21:46:28 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void UEFITool::resizeTreeViewColums()
|
2013-10-08 15:07:03 +08:00
|
|
|
{
|
2013-10-15 23:19:15 +08:00
|
|
|
int count = ffsEngine->model()->columnCount();
|
2013-10-08 15:07:03 +08:00
|
|
|
for(int i = 0; i < count; i++)
|
|
|
|
ui->structureTreeView->resizeColumnToContents(i);
|
|
|
|
}
|
|
|
|
|
|
|
|
void UEFITool::openImageFile()
|
|
|
|
{
|
|
|
|
QString path = QFileDialog::getOpenFileName(this, tr("Open BIOS image file"),".","BIOS image file (*.rom *.bin *.cap *.bio *.fd *.wph *.efi);;All files (*.*)");
|
|
|
|
openImageFile(path);
|
|
|
|
}
|
|
|
|
|
|
|
|
void UEFITool::openImageFile(QString path)
|
|
|
|
{
|
|
|
|
QFileInfo fileInfo = QFileInfo(path);
|
|
|
|
if (!fileInfo.exists())
|
|
|
|
{
|
2013-11-14 18:40:39 +08:00
|
|
|
ui->statusBar->showMessage(tr("Please select existing file"));
|
2013-10-08 15:07:03 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
QFile inputFile;
|
|
|
|
inputFile.setFileName(path);
|
|
|
|
|
|
|
|
if (!inputFile.open(QFile::ReadOnly))
|
|
|
|
{
|
2013-11-07 21:46:28 +08:00
|
|
|
ui->statusBar->showMessage(tr("Can't open file for reading"));
|
2013-10-08 15:07:03 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
QByteArray buffer = inputFile.readAll();
|
|
|
|
inputFile.close();
|
|
|
|
|
|
|
|
init();
|
2013-10-15 23:19:15 +08:00
|
|
|
UINT8 result = ffsEngine->parseInputFile(buffer);
|
2013-10-08 15:07:03 +08:00
|
|
|
if (result)
|
2013-11-14 18:40:39 +08:00
|
|
|
ui->statusBar->showMessage(tr("Opened file can't be parsed (%1)").arg(result));
|
2013-10-08 15:07:03 +08:00
|
|
|
else
|
|
|
|
ui->statusBar->showMessage(tr("Opened: %1").arg(fileInfo.fileName()));
|
2013-10-15 23:19:15 +08:00
|
|
|
|
2013-11-15 18:48:14 +08:00
|
|
|
showDebugMessage();
|
2013-10-08 15:07:03 +08:00
|
|
|
resizeTreeViewColums();
|
|
|
|
}
|
|
|
|
|
2013-11-07 21:46:28 +08:00
|
|
|
void UEFITool::extract()
|
2013-10-08 15:07:03 +08:00
|
|
|
{
|
2013-10-15 23:19:15 +08:00
|
|
|
QString path = QFileDialog::getSaveFileName(this, tr("Save selected item to binary file"),".","Binary files (*.bin);;All files (*.*)");
|
2013-10-08 15:07:03 +08:00
|
|
|
|
|
|
|
QFile outputFile;
|
|
|
|
outputFile.setFileName(path);
|
|
|
|
if (!outputFile.open(QFile::WriteOnly))
|
|
|
|
{
|
2013-11-14 18:40:39 +08:00
|
|
|
ui->statusBar->showMessage(tr("Can't open file for rewriting"));
|
2013-10-08 15:07:03 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-11-14 18:40:39 +08:00
|
|
|
outputFile.resize(0);
|
2013-10-15 23:19:15 +08:00
|
|
|
outputFile.write(ffsEngine->header(currentIndex) + ffsEngine->body(currentIndex));
|
2013-10-08 15:07:03 +08:00
|
|
|
outputFile.close();
|
|
|
|
}
|
|
|
|
|
2013-11-07 21:46:28 +08:00
|
|
|
void UEFITool::extractBody()
|
2013-10-08 15:07:03 +08:00
|
|
|
{
|
2013-11-14 18:40:39 +08:00
|
|
|
QString path = QFileDialog::getSaveFileName(this, tr("Save selected item without header to file"),".","Binary files (*.bin);;All files (*.*)");
|
2013-10-08 15:07:03 +08:00
|
|
|
|
|
|
|
QFile outputFile;
|
|
|
|
outputFile.setFileName(path);
|
|
|
|
if (!outputFile.open(QFile::WriteOnly))
|
|
|
|
{
|
2013-11-14 18:40:39 +08:00
|
|
|
ui->statusBar->showMessage(tr("Can't open file for rewriting"));
|
2013-10-08 15:07:03 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-11-14 18:40:39 +08:00
|
|
|
outputFile.resize(0);
|
2013-10-15 23:19:15 +08:00
|
|
|
outputFile.write(ffsEngine->body(currentIndex));
|
|
|
|
outputFile.close();
|
|
|
|
}
|
|
|
|
|
2013-11-07 21:46:28 +08:00
|
|
|
void UEFITool::extractUncompressed()
|
2013-10-15 23:19:15 +08:00
|
|
|
{
|
2013-11-14 18:40:39 +08:00
|
|
|
QString path = QFileDialog::getSaveFileName(this, tr("Save selected FFS file as uncompressed to file"),".","FFS files (*.ffs);;All files (*.*)");
|
2013-10-15 23:19:15 +08:00
|
|
|
|
|
|
|
QFile outputFile;
|
|
|
|
outputFile.setFileName(path);
|
|
|
|
if (!outputFile.open(QFile::WriteOnly))
|
|
|
|
{
|
2013-11-14 18:40:39 +08:00
|
|
|
ui->statusBar->showMessage(tr("Can't open file for rewriting"));
|
2013-10-15 23:19:15 +08:00
|
|
|
return;
|
|
|
|
}
|
2013-11-14 18:40:39 +08:00
|
|
|
|
|
|
|
outputFile.resize(0);
|
2013-11-07 21:46:28 +08:00
|
|
|
outputFile.write(ffsEngine->decompressFile(currentIndex));
|
2013-10-08 15:07:03 +08:00
|
|
|
outputFile.close();
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2013-11-15 18:48:14 +08:00
|
|
|
void UEFITool::showDebugMessage()
|
|
|
|
{
|
|
|
|
ui->debugListWidget->clear();
|
|
|
|
QQueue<DebugListItem*> debugItems = ffsEngine->debugMessage();
|
|
|
|
for (int i = 0; i < debugItems.count(); i++) {
|
|
|
|
ui->debugListWidget->addItem((QListWidgetItem*) debugItems.at(i));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void UEFITool::scrollTreeView(QListWidgetItem* item)
|
|
|
|
{
|
|
|
|
DebugListItem* debugItem = (DebugListItem*) item;
|
|
|
|
QModelIndex index = debugItem->index();
|
|
|
|
if (index.isValid()) {
|
|
|
|
ui->structureTreeView->scrollTo(index);
|
|
|
|
ui->structureTreeView->selectionModel()->select(currentIndex, QItemSelectionModel::Clear);
|
|
|
|
ui->structureTreeView->selectionModel()->select(index, QItemSelectionModel::Select);
|
|
|
|
}
|
|
|
|
}
|