mirror of
https://github.com/LongSoft/UEFITool.git
synced 2025-05-09 13:52:01 -04:00
1) Added special subspecifier "h" for specifier "X" (hex values print), added corresponding menu option and application setting to UEFITool.
2) Fixed QHexView misalignment in Windows and macOS. 3) Added some more analysis to raw files and sections: raw files can (or can not) contain sections, raw sections can contain NVAR storage or PE/TE. 4) Improved CPU base address detection and propagation. 5) Improved FIT recognition. 7) ME region not displayed if it is in unknown format, fixed this because we still want to operate with it. 8) Small changes to Flash Descriptor parsing to get more cases for valid "Intel image". To get rid of cases when "Intel image" is already in tree but with parse error because of which "UEFI image" appears. 9) Added parsing of individual UEFI-files (these can be trimmed from UEFI-volume), displaying it as "UEFI volume part". 10) Added possibility to view/save contents of elements "Free volume space", "Free space" and such, because these can be non-empty. 11) Added info about blocks number and block size (with preliminary and stupid validity check) to volume info. 12) Added storage in settings of the following paths: open image file, save image file, open GUIDs file. 13) Added last opened files list. 14) Added permanent opened file name string to the end of the status bar. 15) Added opened file changes tracking: if the file was modified in other program while it is opened in UEFITool, there are 3 ways to act: a) ignore changes (but mark file path displayed in the status bar with italic font); b) ask user to reopen or ignore (if ignore, mark as in a); c) auto reopen changed file in UEFITool. If changes were in some way ignored, file path displayed in the right of the status bar will be marked with italic font and then become clickable: on click request to reopen appears again. 16) Switched to offset/size instead of byte array storing in each tree item. 17) For clarity - added icons to key tree items (compressed and with contents, contents now must be in root item only). 18) For usability - added expanding tree on open image (to depth level 1) and by menu command (expand all).
This commit is contained in:
parent
7cea8ee512
commit
936b09dbf4
27 changed files with 3699 additions and 859 deletions
|
@ -92,7 +92,7 @@ USTATUS UEFIFind::findFileRecursive(const UModelIndex index, const UString & hex
|
|||
|
||||
// For patterns that cross header|body boundary, skip patterns entirely located in body, since
|
||||
// children search above has already found them.
|
||||
if (hasChildren && mode == SEARCH_MODE_ALL && offset >= model->header(index).size()) {
|
||||
if (hasChildren && mode == SEARCH_MODE_ALL && offset >= model->headerSize(index)) {
|
||||
offset = -1;
|
||||
}
|
||||
|
||||
|
|
|
@ -788,6 +788,7 @@ void QHexView::drawDocument(QTextCursor& c) const {
|
|||
else if(m_options.linebackground.isValid() && !(line % 2))
|
||||
bf.setBackground(m_options.linebackground);
|
||||
|
||||
bf.setLineHeight(this->lineHeight(), QTextBlockFormat::FixedHeight);
|
||||
c.setBlockFormat(bf);
|
||||
c.insertBlock({});
|
||||
if(m_hexdocument->isEmpty())
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
*/
|
||||
|
||||
#include "ffsfinder.h"
|
||||
#include "../common/utility.h"
|
||||
|
||||
#if QT_VERSION_MAJOR >= 6
|
||||
#include <QRegularExpression>
|
||||
|
@ -36,7 +37,8 @@ USTATUS FfsFinder::findHexPattern(const UModelIndex & index, const UByteArray &
|
|||
return U_INVALID_PARAMETER;
|
||||
|
||||
// Check for "all substrings" pattern
|
||||
if (hexPattern.count('.') == hexPattern.length())
|
||||
auto c = checkSingle(hexPattern);
|
||||
if (c == '.')
|
||||
return U_SUCCESS;
|
||||
|
||||
USTATUS ret = U_ITEM_NOT_FOUND;
|
||||
|
@ -78,7 +80,7 @@ USTATUS FfsFinder::findHexPattern(const UModelIndex & index, const UByteArray &
|
|||
if (offset % 2 == 0) {
|
||||
// For patterns that cross header|body boundary, skip patterns entirely located in body, since
|
||||
// children search above has already found them.
|
||||
if (!(hasChildren && mode == SEARCH_MODE_ALL && offset/2 >= model->header(index).size())) {
|
||||
if (!(hasChildren && mode == SEARCH_MODE_ALL && offset/2 >= model->headerSize(index))) {
|
||||
UModelIndex parentFileIndex = model->findParentOfType(index, Types::File);
|
||||
UString name = model->name(index);
|
||||
if (model->parent(index) == parentFileIndex) {
|
||||
|
@ -165,7 +167,8 @@ USTATUS FfsFinder::findGuidPattern(const UModelIndex & index, const UByteArray &
|
|||
hexPattern.append(list.at(3)).append(list.at(4));
|
||||
|
||||
// Check for "all substrings" pattern
|
||||
if (hexPattern.count('.') == hexPattern.length())
|
||||
auto c = checkSingle(hexPattern);
|
||||
if (c == '.')
|
||||
return U_SUCCESS;
|
||||
|
||||
#if QT_VERSION_MAJOR >= 6
|
||||
|
|
|
@ -23,12 +23,22 @@ UEFITool::UEFITool(QWidget *parent) :
|
|||
QMainWindow(parent),
|
||||
ui(new Ui::UEFITool),
|
||||
version(tr(PROGRAM_VERSION)),
|
||||
markingEnabled(true)
|
||||
changedFileFlag(false),
|
||||
markingEnabled(true),
|
||||
cStyleHexEnabled(true)
|
||||
{
|
||||
clipboard = QApplication::clipboard();
|
||||
|
||||
// Create UI
|
||||
ui->setupUi(this);
|
||||
openedFileLabel.setToolButtonStyle(Qt::ToolButtonTextOnly);
|
||||
openedFileLabel.setStyleSheet("QToolButton { border: none; background-color: transparent; }");
|
||||
openedFileLabel.setFocusPolicy(Qt::NoFocus);
|
||||
ui->statusBar->addPermanentWidget(&openedFileLabel);
|
||||
QFont font = ui->statusBar->font();
|
||||
font.setBold(true);
|
||||
openedFileLabel.setFont(font);
|
||||
connect(&openedFileLabel, SIGNAL(clicked()), this, SLOT(fileChangedResume()));
|
||||
searchDialog = new SearchDialog(this);
|
||||
hexViewDialog = new HexViewDialog(this);
|
||||
goToAddressDialog = new GoToAddressDialog(this);
|
||||
|
@ -73,7 +83,10 @@ markingEnabled(true)
|
|||
connect(ui->actionExportDiscoveredGuids, SIGNAL(triggered()), this, SLOT(exportDiscoveredGuids()));
|
||||
connect(ui->actionGenerateReport, SIGNAL(triggered()), this, SLOT(generateReport()));
|
||||
connect(ui->actionToggleBootGuardMarking, SIGNAL(toggled(bool)), this, SLOT(toggleBootGuardMarking(bool)));
|
||||
connect(ui->actionToggleCStyleHexValues, SIGNAL(toggled(bool)), this, SLOT(toggleCStyleHexValues(bool)));
|
||||
connect(ui->actionExpandAll, SIGNAL(triggered()), this, SLOT(expandTree()));
|
||||
connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()), this, SLOT(writeSettings()));
|
||||
connect(&watcher, SIGNAL(fileChanged(QString)), this, SLOT(fileChanged(QString)));
|
||||
|
||||
// Enable Drag-and-Drop actions
|
||||
setAcceptDrops(true);
|
||||
|
@ -92,6 +105,24 @@ markingEnabled(true)
|
|||
|
||||
// Read stored settings
|
||||
readSettings();
|
||||
|
||||
// Update recent files list in menu
|
||||
updateRecentFilesMenu();
|
||||
|
||||
// Create a QActionGroup
|
||||
QActionGroup* actionGroup = new QActionGroup(this);
|
||||
actionGroup->setExclusive(true); // Ensure only one action is checked at a time
|
||||
// Add actions from the menu to the QActionGroup
|
||||
ui->actionTrackAndIgnore->setData(TRACK_IGNORE);
|
||||
ui->actionTrackAndIgnore->setChecked(ui->actionTrackAndIgnore->data() == fileTrackingState);
|
||||
actionGroup->addAction(ui->actionTrackAndIgnore);
|
||||
ui->actionTrackAndAsk->setData(TRACK_ASK);
|
||||
ui->actionTrackAndAsk->setChecked(ui->actionTrackAndAsk->data() == fileTrackingState);
|
||||
actionGroup->addAction(ui->actionTrackAndAsk);
|
||||
ui->actionTrackAndReopen->setData(TRACK_REOPEN);
|
||||
ui->actionTrackAndReopen->setChecked(ui->actionTrackAndReopen->data() == fileTrackingState);
|
||||
actionGroup->addAction(ui->actionTrackAndReopen);
|
||||
connect(actionGroup, SIGNAL(triggered(QAction*)), this, SLOT(onTrackingAction(QAction*)));
|
||||
}
|
||||
|
||||
UEFITool::~UEFITool()
|
||||
|
@ -125,6 +156,9 @@ void UEFITool::init()
|
|||
// Set window title
|
||||
setWindowTitle(tr("UEFITool %1").arg(version));
|
||||
|
||||
// Some font hint
|
||||
setFont(ui->infoEdit->font());
|
||||
|
||||
// Disable menus
|
||||
ui->actionSearch->setEnabled(false);
|
||||
ui->actionGoToBase->setEnabled(false);
|
||||
|
@ -139,6 +173,7 @@ void UEFITool::init()
|
|||
ui->menuStoreActions->setEnabled(false);
|
||||
ui->menuEntryActions->setEnabled(false);
|
||||
ui->menuMessageActions->setEnabled(false);
|
||||
ui->actionExpandAll->setEnabled(false);
|
||||
|
||||
// Create new model ...
|
||||
delete model;
|
||||
|
@ -152,11 +187,17 @@ void UEFITool::init()
|
|||
model->setMarkingEnabled(markingEnabled);
|
||||
ui->actionToggleBootGuardMarking->setChecked(markingEnabled);
|
||||
|
||||
// Set proper C-Style hex values view state
|
||||
model->setCStyleHexEnabled(cStyleHexEnabled);
|
||||
ui->actionToggleCStyleHexValues->setChecked(cStyleHexEnabled);
|
||||
|
||||
// Connect signals to slots
|
||||
connect(ui->structureTreeView->selectionModel(), SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)),
|
||||
this, SLOT(populateUi(const QModelIndex &)));
|
||||
connect(ui->structureTreeView->selectionModel(), SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)),
|
||||
this, SLOT(populateUi(const QItemSelection &)));
|
||||
connect(ui->structureTreeView, SIGNAL(expanded(const QModelIndex &)), this, SLOT(setExpandAll()));
|
||||
connect(ui->structureTreeView, SIGNAL(collapsed(const QModelIndex&)), this, SLOT(setExpandAll()));
|
||||
connect(ui->parserMessagesListWidget, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(scrollTreeView(QListWidgetItem*)));
|
||||
connect(ui->parserMessagesListWidget, SIGNAL(itemEntered(QListWidgetItem*)), this, SLOT(enableMessagesCopyActions(QListWidgetItem*)));
|
||||
connect(ui->finderMessagesListWidget, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(scrollTreeView(QListWidgetItem*)));
|
||||
|
@ -211,6 +252,38 @@ void UEFITool::updateUiForNewColorScheme(Qt::ColorScheme scheme)
|
|||
}
|
||||
#endif
|
||||
|
||||
void UEFITool::updateRecentFilesMenu(const QString& fileName)
|
||||
{
|
||||
// Update list
|
||||
if (!fileName.isEmpty()) {
|
||||
recentFiles.removeAll(fileName);
|
||||
recentFiles.prepend(fileName);
|
||||
while (recentFiles.size() > 21) {
|
||||
recentFiles.removeLast();
|
||||
}
|
||||
}
|
||||
|
||||
// Delete old actions
|
||||
for (QAction* action : recentFileActions) {
|
||||
ui->menuFile->removeAction(action);
|
||||
delete action;
|
||||
}
|
||||
recentFileActions.clear();
|
||||
|
||||
if (!recentFiles.isEmpty()) {
|
||||
// Insert new actions before "Quit"
|
||||
for (const QString& path : recentFiles) {
|
||||
QAction* action = new QAction(QDir::toNativeSeparators(path), this);
|
||||
connect(action, SIGNAL(triggered()), this, SLOT(openRecentImageFile()));
|
||||
action->setData(path);
|
||||
ui->menuFile->insertAction(ui->actionQuit, action);
|
||||
recentFileActions.append(action);
|
||||
}
|
||||
// Finally, insert a separator after the list and before "Quit"
|
||||
recentFileActions.append(ui->menuFile->insertSeparator(ui->actionQuit));
|
||||
}
|
||||
}
|
||||
|
||||
void UEFITool::populateUi(const QItemSelection &selected)
|
||||
{
|
||||
if (selected.isEmpty()) {
|
||||
|
@ -235,7 +308,10 @@ void UEFITool::populateUi(const QModelIndex ¤t)
|
|||
|
||||
// Enable menus
|
||||
ui->menuCapsuleActions->setEnabled(type == Types::Capsule);
|
||||
ui->menuImageActions->setEnabled(type == Types::Image);
|
||||
ui->menuImageActions->setEnabled(type == Types::Image
|
||||
|| (type == Types::Volume && model->hasEmptyHeader(current))
|
||||
|| type == Types::FreeSpace
|
||||
);
|
||||
ui->menuRegionActions->setEnabled(type == Types::Region);
|
||||
ui->menuPaddingActions->setEnabled(type == Types::Padding);
|
||||
ui->menuVolumeActions->setEnabled(type == Types::Volume);
|
||||
|
@ -300,6 +376,8 @@ void UEFITool::populateUi(const QModelIndex ¤t)
|
|||
//ui->actionReplaceBody->setEnabled(type == Types::Volume || type == Types::File || type == Types::Section);
|
||||
|
||||
ui->menuMessageActions->setEnabled(false);
|
||||
|
||||
setExpandAll();
|
||||
}
|
||||
|
||||
void UEFITool::search()
|
||||
|
@ -310,7 +388,7 @@ void UEFITool::search()
|
|||
int index = searchDialog->ui->tabWidget->currentIndex();
|
||||
if (index == 0) { // Hex pattern
|
||||
searchDialog->ui->hexEdit->setFocus();
|
||||
QByteArray pattern = searchDialog->ui->hexEdit->text().toLatin1().replace(" ", "");
|
||||
UByteArray pattern = searchDialog->ui->hexEdit->text().toLatin1().replace(" ", "");
|
||||
if (pattern.isEmpty())
|
||||
return;
|
||||
UINT8 mode;
|
||||
|
@ -326,7 +404,7 @@ void UEFITool::search()
|
|||
else if (index == 1) { // GUID
|
||||
searchDialog->ui->guidEdit->setFocus();
|
||||
searchDialog->ui->guidEdit->setCursorPosition(0);
|
||||
QByteArray pattern = searchDialog->ui->guidEdit->text().toLatin1();
|
||||
UByteArray pattern = searchDialog->ui->guidEdit->text().toLatin1();
|
||||
if (pattern.isEmpty())
|
||||
return;
|
||||
UINT8 mode;
|
||||
|
@ -508,7 +586,7 @@ void UEFITool::extract(const UINT8 mode)
|
|||
if (!index.isValid())
|
||||
return;
|
||||
|
||||
QByteArray extracted;
|
||||
UByteArray extracted;
|
||||
QString name;
|
||||
USTATUS result = ffsOps->extract(index, name, extracted, mode);
|
||||
if (result) {
|
||||
|
@ -516,7 +594,7 @@ void UEFITool::extract(const UINT8 mode)
|
|||
return;
|
||||
}
|
||||
|
||||
name = QDir::toNativeSeparators(currentDir + QDir::separator() + name);
|
||||
name = QDir::toNativeSeparators(extractDir + QDir::separator() + name);
|
||||
|
||||
//ui->statusBar->showMessage(name);
|
||||
|
||||
|
@ -566,6 +644,8 @@ void UEFITool::extract(const UINT8 mode)
|
|||
outputFile.resize(0);
|
||||
outputFile.write(extracted);
|
||||
outputFile.close();
|
||||
|
||||
extractDir = QFileInfo(path).absolutePath();
|
||||
}
|
||||
|
||||
void UEFITool::rebuild()
|
||||
|
@ -617,20 +697,185 @@ void UEFITool::saveImageFile()
|
|||
|
||||
}
|
||||
|
||||
void UEFITool::askReopenImageFile()
|
||||
{
|
||||
QMessageBox msgBox(QMessageBox::Question, tr("Confirmation"),
|
||||
tr("Image file was changed by external program, do you want to reopen it?"),
|
||||
QMessageBox::Yes | QMessageBox::No);
|
||||
QCheckBox checkBox(tr("Do not ask again"));
|
||||
checkBox.setChecked(TRACK_IGNORE == fileTrackingState);
|
||||
msgBox.setDefaultButton(QMessageBox::Yes);
|
||||
msgBox.setCheckBox(&checkBox);
|
||||
|
||||
int ret = msgBox.exec();
|
||||
|
||||
if (checkBox.isChecked()) {
|
||||
if (ret == QMessageBox::Yes) {
|
||||
ui->actionTrackAndReopen->setChecked(true);
|
||||
fileTrackingState = TRACK_REOPEN;
|
||||
}
|
||||
else if (ret == QMessageBox::No) {
|
||||
ui->actionTrackAndIgnore->setChecked(true);
|
||||
fileTrackingState = TRACK_IGNORE;
|
||||
}
|
||||
}
|
||||
if (ret == QMessageBox::Yes)
|
||||
reopenImageFile();
|
||||
}
|
||||
|
||||
void UEFITool::onTrackingAction(QAction* action)
|
||||
{
|
||||
if (action) {
|
||||
int newTrackingState = action->data().toInt();
|
||||
if (newTrackingState != fileTrackingState) {
|
||||
fileTrackingState = newTrackingState;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UEFITool::saveTreeState(const QModelIndex& index, QHash<QString, bool>& states)
|
||||
{
|
||||
if (!index.isValid())
|
||||
return;
|
||||
|
||||
// Save the expanded state using the item's data as the key
|
||||
QString key = model->data(index, Qt::DisplayRole).toString();
|
||||
states[key] = ui->structureTreeView->isExpanded(index);
|
||||
|
||||
// Recursively save child states
|
||||
for (int row = 0; row < model->rowCount(index); row++) {
|
||||
saveTreeState(model->index(row, 0, index), states);
|
||||
}
|
||||
}
|
||||
|
||||
void UEFITool::restoreTreeState(const QModelIndex& index, const QHash<QString, bool>& states)
|
||||
{
|
||||
if (!index.isValid())
|
||||
return;
|
||||
|
||||
// Restore the expanded state using the item's data as the key
|
||||
QString key = model->data(index, Qt::DisplayRole).toString();
|
||||
if (states.contains(key)) {
|
||||
ui->structureTreeView->setExpanded(index, states[key]);
|
||||
}
|
||||
|
||||
// Recursively restore child states
|
||||
for (int row = 0; row < model->rowCount(index); row++) {
|
||||
restoreTreeState(model->index(row, 0, index), states);
|
||||
}
|
||||
}
|
||||
|
||||
bool UEFITool::isAllExpanded()
|
||||
{
|
||||
QAbstractItemModel* model = ui->structureTreeView->model();
|
||||
if (!model)
|
||||
return false;
|
||||
|
||||
QStack<QModelIndex> stack;
|
||||
stack.push(QModelIndex());
|
||||
|
||||
while (!stack.isEmpty()) {
|
||||
QModelIndex current = stack.pop();
|
||||
|
||||
if (current.isValid() && ui->structureTreeView->isExpanded(current) == false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int rowCount = model->rowCount(current);
|
||||
for (int i = 0; i < rowCount; ++i) {
|
||||
QModelIndex child = model->index(i, 0, current);
|
||||
if (child.isValid()) {
|
||||
stack.push(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void UEFITool::setExpandAll()
|
||||
{
|
||||
ui->actionExpandAll->setEnabled(!isAllExpanded());
|
||||
}
|
||||
|
||||
void UEFITool::expandTree()
|
||||
{
|
||||
ui->structureTreeView->expandAll();
|
||||
}
|
||||
|
||||
void UEFITool::fileChangedResume()
|
||||
{
|
||||
if (changedFileFlag) {
|
||||
askReopenImageFile();
|
||||
}
|
||||
}
|
||||
|
||||
void UEFITool::fileChanged(const QString& path)
|
||||
{
|
||||
setChangedFileFlag(true);
|
||||
|
||||
switch (fileTrackingState) {
|
||||
case TRACK_REOPEN :
|
||||
reopenImageFile();
|
||||
case TRACK_IGNORE :
|
||||
return;
|
||||
}
|
||||
|
||||
askReopenImageFile();
|
||||
}
|
||||
|
||||
void UEFITool::setChangedFileFlag(const bool flag)
|
||||
{
|
||||
QFont font(openedFileLabel.font());
|
||||
font.setItalic(flag);
|
||||
openedFileLabel.setFont(font);
|
||||
changedFileFlag = flag;
|
||||
}
|
||||
|
||||
void UEFITool::openImageFile()
|
||||
{
|
||||
QString path = QFileDialog::getOpenFileName(this, tr("Open BIOS image file"), currentDir, tr("BIOS image files (*.rom *.bin *.cap *scap *.bio *.fd *.wph *.dec);;All files (*)"));
|
||||
QString path = QFileDialog::getOpenFileName(this, tr("Open BIOS image file"), openImageDir, tr("BIOS image files (*.rom *.bin *.cap *scap *.bio *.fd *.wph *.dec);;All files (*)"));
|
||||
openImageFile(path);
|
||||
}
|
||||
|
||||
void UEFITool::openImageFileInNewWindow()
|
||||
{
|
||||
QString path = QFileDialog::getOpenFileName(this, tr("Open BIOS image file in new window"), currentDir, tr("BIOS image files (*.rom *.bin *.cap *scap *.bio *.fd *.wph *.dec);;All files (*)"));
|
||||
QString path = QFileDialog::getOpenFileName(this, tr("Open BIOS image file in new window"), openImageDir, tr("BIOS image files (*.rom *.bin *.cap *scap *.bio *.fd *.wph *.dec);;All files (*)"));
|
||||
if (path.trimmed().isEmpty())
|
||||
return;
|
||||
QProcess::startDetached(currentProgramPath, QStringList(path));
|
||||
}
|
||||
|
||||
void UEFITool::openRecentImageFile()
|
||||
{
|
||||
QAction* action = qobject_cast<QAction*>(sender());
|
||||
if (action) {
|
||||
QString fileName = action->data().toString();
|
||||
if (!fileName.isEmpty()) {
|
||||
openImageFile(fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UEFITool::reopenImageFile()
|
||||
{
|
||||
if (!currentPath.isEmpty() && ui->structureTreeView->model()->hasChildren(UModelIndex())) {
|
||||
QHash<QString, bool> states;
|
||||
saveTreeState(model->index(0, 0), states);
|
||||
QList <UModelIndex> selected = ui->structureTreeView->selectionModel()->selectedIndexes();
|
||||
UINT64 base = selected.isEmpty() ? UEFI_UPPER_INVALID_ADDRESS : model->base(selected.first());
|
||||
|
||||
openImageFile(currentPath);
|
||||
|
||||
restoreTreeState(model->index(0, 0), states);
|
||||
if (base < UEFI_UPPER_INVALID_ADDRESS) {
|
||||
UModelIndex index = model->findByBase(base);
|
||||
ui->structureTreeView->selectionModel()->select(index, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
|
||||
ui->structureTreeView->scrollTo(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UEFITool::openImageFile(QString path)
|
||||
{
|
||||
if (path.trimmed().isEmpty())
|
||||
|
@ -645,18 +890,23 @@ void UEFITool::openImageFile(QString path)
|
|||
|
||||
QFile inputFile;
|
||||
inputFile.setFileName(path);
|
||||
|
||||
QElapsedTimer timer;
|
||||
timer.start();
|
||||
if (!inputFile.open(QFile::ReadOnly)) {
|
||||
QMessageBox::critical(this, tr("Image parsing failed"), tr("Can't open input file for reading"), QMessageBox::Ok);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
watcher.removePaths(watcher.files());
|
||||
setChangedFileFlag(false);
|
||||
watcher.addPath(path);
|
||||
|
||||
QByteArray buffer = inputFile.readAll();
|
||||
inputFile.close();
|
||||
|
||||
|
||||
init();
|
||||
setWindowTitle(tr("UEFITool %1 - %2").arg(version).arg(fileInfo.fileName()));
|
||||
|
||||
|
||||
// Parse the image
|
||||
USTATUS result = ffsParser->parse(buffer);
|
||||
showParserMessages();
|
||||
|
@ -665,7 +915,10 @@ void UEFITool::openImageFile(QString path)
|
|||
return;
|
||||
}
|
||||
else {
|
||||
ui->statusBar->showMessage(tr("Opened: %1").arg(fileInfo.fileName()));
|
||||
ui->statusBar->showMessage(QString("Image file %1 ").arg(fileInfo.fileName())
|
||||
+ (path == currentPath ? tr("reopened") : tr("opened"))
|
||||
+ QString(" in %1 sec").arg(timer.elapsed() / 1000.0));
|
||||
openedFileLabel.setText(QDir::toNativeSeparators(fileInfo.absoluteFilePath()));
|
||||
}
|
||||
ffsParser->outputInfo();
|
||||
|
||||
|
@ -688,7 +941,7 @@ void UEFITool::openImageFile(QString path)
|
|||
|
||||
// Enable goToBase and goToAddress
|
||||
ui->actionGoToBase->setEnabled(true);
|
||||
if (ffsParser->getAddressDiff() <= 0xFFFFFFFFUL)
|
||||
if (ffsParser->getAddressDiff() < UEFI_UPPER_INVALID_ADDRESS)
|
||||
ui->actionGoToAddress->setEnabled(true);
|
||||
|
||||
// Enable generateReport
|
||||
|
@ -699,9 +952,15 @@ void UEFITool::openImageFile(QString path)
|
|||
|
||||
// Set current directory
|
||||
currentDir = fileInfo.absolutePath();
|
||||
|
||||
openImageDir = currentDir;
|
||||
|
||||
// Set current path
|
||||
currentPath = path;
|
||||
|
||||
// Update menu
|
||||
updateRecentFilesMenu(currentPath);
|
||||
|
||||
ui->structureTreeView->expandToDepth(1);
|
||||
}
|
||||
|
||||
void UEFITool::enableMessagesCopyActions(QListWidgetItem* item)
|
||||
|
@ -771,6 +1030,12 @@ void UEFITool::toggleBootGuardMarking(bool enabled)
|
|||
markingEnabled = enabled;
|
||||
}
|
||||
|
||||
void UEFITool::toggleCStyleHexValues(bool enabled)
|
||||
{
|
||||
model->setCStyleHexEnabled(enabled);
|
||||
cStyleHexEnabled = enabled;
|
||||
}
|
||||
|
||||
// Emit double click signal of QListWidget on enter/return key pressed
|
||||
bool UEFITool::eventFilter(QObject* obj, QEvent* event)
|
||||
{
|
||||
|
@ -898,14 +1163,21 @@ void UEFITool::contextMenuEvent(QContextMenuEvent* event)
|
|||
return;
|
||||
}
|
||||
|
||||
QMenu* menu = nullptr;
|
||||
|
||||
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;
|
||||
case Types::Capsule: menu = ui->menuCapsuleActions; break;
|
||||
case Types::Image: menu = ui->menuImageActions; break;
|
||||
case Types::Region: menu = ui->menuRegionActions; break;
|
||||
case Types::Padding: menu = ui->menuPaddingActions; break;
|
||||
case Types::Volume:
|
||||
if (model->hasEmptyHeader(index))
|
||||
menu = ui->menuImageActions;
|
||||
else
|
||||
menu = ui->menuVolumeActions;
|
||||
break;
|
||||
case Types::File: menu = ui->menuFileActions; break;
|
||||
case Types::Section: menu = ui->menuSectionActions; break;
|
||||
case Types::VssStore:
|
||||
case Types::Vss2Store:
|
||||
case Types::FdcStore:
|
||||
|
@ -918,9 +1190,16 @@ void UEFITool::contextMenuEvent(QContextMenuEvent* event)
|
|||
case Types::CmdbStore:
|
||||
case Types::FptStore:
|
||||
case Types::CpdStore:
|
||||
case Types::BpdtStore: ui->menuStoreActions->exec(event->globalPos()); break;
|
||||
case Types::FreeSpace: break; // No menu needed for FreeSpace item
|
||||
default: ui->menuEntryActions->exec(event->globalPos()); break;
|
||||
case Types::BpdtStore: menu = ui->menuStoreActions; break;
|
||||
case Types::FreeSpace: menu = ui->menuImageActions; break;
|
||||
default: menu = ui->menuEntryActions; break;
|
||||
}
|
||||
|
||||
if (menu != nullptr) {
|
||||
QList<QAction*> actions = menu->actions();
|
||||
QAction s = QAction(nullptr);
|
||||
s.setSeparator(true);
|
||||
QMenu::exec(actions << &s << ui->actionExpandAll, event->globalPos());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -942,11 +1221,20 @@ void UEFITool::readSettings()
|
|||
ui->structureTreeView->setColumnWidth(3, settings.value("tree/columnWidth3", ui->structureTreeView->columnWidth(3)).toInt());
|
||||
markingEnabled = settings.value("tree/markingEnabled", true).toBool();
|
||||
ui->actionToggleBootGuardMarking->setChecked(markingEnabled);
|
||||
|
||||
cStyleHexEnabled = settings.value("tree/cStyleHexEnabled", true).toBool();
|
||||
ui->actionToggleCStyleHexValues->setChecked(cStyleHexEnabled);
|
||||
openImageDir = settings.value("paths/openImageDir", ".").toString();
|
||||
openGuidDatabaseDir = settings.value("paths/openGuidDatabaseDir", ".").toString();
|
||||
extractDir = settings.value("paths/extractDir", ".").toString();
|
||||
recentFiles = settings.value("paths/recentFiles").toStringList();
|
||||
fileTrackingState = settings.value("options/fileTracking", TRACK_IGNORE).toInt();
|
||||
if (fileTrackingState < TRACK_MIN || fileTrackingState > TRACK_MAX)
|
||||
fileTrackingState = TRACK_IGNORE;
|
||||
|
||||
// Set monospace font
|
||||
QString fontName;
|
||||
int fontSize;
|
||||
#if defined Q_OS_MACOS
|
||||
#if defined Q_OS_OSX
|
||||
fontName = settings.value("mainWindow/fontName", QString("Menlo")).toString();
|
||||
fontSize = settings.value("mainWindow/fontSize", 10).toInt();
|
||||
#elif defined Q_OS_WIN
|
||||
|
@ -975,8 +1263,14 @@ void UEFITool::writeSettings()
|
|||
settings.setValue("tree/columnWidth2", ui->structureTreeView->columnWidth(2));
|
||||
settings.setValue("tree/columnWidth3", ui->structureTreeView->columnWidth(3));
|
||||
settings.setValue("tree/markingEnabled", markingEnabled);
|
||||
settings.setValue("tree/cStyleHexEnabled", cStyleHexEnabled);
|
||||
settings.setValue("mainWindow/fontName", currentFont.family());
|
||||
settings.setValue("mainWindow/fontSize", currentFont.pointSize());
|
||||
settings.setValue("paths/openImageDir", openImageDir);
|
||||
settings.setValue("paths/openGuidDatabaseDir", openGuidDatabaseDir);
|
||||
settings.setValue("paths/extractDir", extractDir);
|
||||
settings.setValue("paths/recentFiles", recentFiles);
|
||||
settings.setValue("options/fileTracking", fileTrackingState);
|
||||
}
|
||||
|
||||
void UEFITool::showFitTable()
|
||||
|
@ -1041,11 +1335,12 @@ void UEFITool::currentTabChanged(int index)
|
|||
|
||||
void UEFITool::loadGuidDatabase()
|
||||
{
|
||||
QString path = QFileDialog::getOpenFileName(this, tr("Select GUID database file to load"), currentDir, tr("Comma-separated values files (*.csv);;All files (*)"));
|
||||
QString path = QFileDialog::getOpenFileName(this, tr("Select GUID database file to load"), openGuidDatabaseDir, tr("Comma-separated values files (*.csv);;All files (*)"));
|
||||
if (!path.isEmpty()) {
|
||||
initGuidDatabase(path);
|
||||
if (!currentPath.isEmpty() && QMessageBox::Yes == QMessageBox::information(this, tr("New GUID database loaded"), tr("Apply new GUID database on the opened file?\nUnsaved changes and tree position will be lost."), QMessageBox::Yes, QMessageBox::No))
|
||||
openImageFile(currentPath);
|
||||
openGuidDatabaseDir = QFileInfo(path).absolutePath();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#define UEFITOOL_H
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QActionGroup>
|
||||
#include <QByteArray>
|
||||
#include <QClipboard>
|
||||
#include <QDragEnterEvent>
|
||||
|
@ -22,6 +23,7 @@
|
|||
#include <QFile>
|
||||
#include <QFileDialog>
|
||||
#include <QFileInfo>
|
||||
#include <QFileSystemWatcher>
|
||||
#include <QFont>
|
||||
#include <QListWidget>
|
||||
#include <QMenu>
|
||||
|
@ -32,10 +34,12 @@
|
|||
#include <QProcess>
|
||||
#include <QSettings>
|
||||
#include <QSplitter>
|
||||
#include <QStack>
|
||||
#include <QStyleFactory>
|
||||
#include <QString>
|
||||
#include <QTableWidget>
|
||||
#include <QTreeView>
|
||||
#include <QToolButton>
|
||||
#include <QUrl>
|
||||
|
||||
#include "../common/basetypes.h"
|
||||
|
@ -75,13 +79,19 @@ private slots:
|
|||
void scrollTreeView(QListWidgetItem* item); // For messages
|
||||
void scrollTreeView(QTableWidgetItem* item); // For FIT table entries
|
||||
|
||||
void onTrackingAction(QAction* action);
|
||||
void fileChangedResume();
|
||||
void fileChanged(const QString& path);
|
||||
void setChangedFileFlag(const bool flag);
|
||||
void openImageFile();
|
||||
void openImageFileInNewWindow();
|
||||
void openRecentImageFile();
|
||||
void saveImageFile();
|
||||
|
||||
void search();
|
||||
void goToBase();
|
||||
void goToAddress();
|
||||
void expandTree();
|
||||
|
||||
void hexView();
|
||||
void bodyHexView();
|
||||
|
@ -112,6 +122,8 @@ private slots:
|
|||
void clearMessages();
|
||||
|
||||
void toggleBootGuardMarking(bool enabled);
|
||||
void toggleCStyleHexValues(bool enabled);
|
||||
void setExpandAll();
|
||||
|
||||
void about();
|
||||
void aboutQt();
|
||||
|
@ -144,23 +156,39 @@ private:
|
|||
GoToBaseDialog* goToBaseDialog;
|
||||
GoToAddressDialog* goToAddressDialog;
|
||||
QClipboard* clipboard;
|
||||
QList<QAction*> recentFileActions;
|
||||
QFileSystemWatcher watcher;
|
||||
QToolButton openedFileLabel;
|
||||
QStringList recentFiles;
|
||||
QString currentDir;
|
||||
QString currentPath;
|
||||
QString currentProgramPath;
|
||||
QString openImageDir;
|
||||
QString openGuidDatabaseDir;
|
||||
QString extractDir;
|
||||
QFont currentFont;
|
||||
const QString version;
|
||||
int fileTrackingState;
|
||||
bool changedFileFlag;
|
||||
bool markingEnabled;
|
||||
bool cStyleHexEnabled;
|
||||
|
||||
bool eventFilter(QObject* obj, QEvent* event);
|
||||
void dragEnterEvent(QDragEnterEvent* event);
|
||||
void dropEvent(QDropEvent* event);
|
||||
void contextMenuEvent(QContextMenuEvent* event);
|
||||
void updateRecentFilesMenu(const QString& fileName = QString());
|
||||
void readSettings();
|
||||
void askReopenImageFile();
|
||||
void reopenImageFile();
|
||||
void showParserMessages();
|
||||
void showFinderMessages();
|
||||
void showFitTable();
|
||||
void showSecurityInfo();
|
||||
void showBuilderMessages();
|
||||
bool isAllExpanded();
|
||||
void saveTreeState(const QModelIndex& index, QHash<QString, bool>& states);
|
||||
void restoreTreeState(const QModelIndex& index, const QHash<QString, bool>& states);
|
||||
|
||||
enum {
|
||||
TAB_PARSER,
|
||||
|
@ -169,6 +197,14 @@ private:
|
|||
TAB_SEARCH,
|
||||
TAB_BUILDER
|
||||
};
|
||||
|
||||
enum {
|
||||
TRACK_MIN = 0,
|
||||
TRACK_IGNORE = TRACK_MIN,
|
||||
TRACK_ASK,
|
||||
TRACK_REOPEN,
|
||||
TRACK_MAX = TRACK_REOPEN
|
||||
};
|
||||
};
|
||||
|
||||
#endif // UEFITOOL_H
|
||||
|
|
|
@ -48,11 +48,11 @@
|
|||
<item>
|
||||
<widget class="QSplitter" name="messagesSplitter">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<widget class="QSplitter" name="infoSplitter">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<widget class="QGroupBox" name="structureGroupBox">
|
||||
<property name="title">
|
||||
|
@ -196,7 +196,7 @@
|
|||
<item>
|
||||
<widget class="QSplitter" name="splitter">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<widget class="QTableWidget" name="fitTableWidget"/>
|
||||
</widget>
|
||||
|
@ -311,17 +311,27 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>851</width>
|
||||
<height>31</height>
|
||||
<height>33</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuFile">
|
||||
<property name="title">
|
||||
<string>&File</string>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuOpenedImageFileTracking">
|
||||
<property name="title">
|
||||
<string>Opened image file tracking</string>
|
||||
</property>
|
||||
<addaction name="actionTrackAndIgnore"/>
|
||||
<addaction name="actionTrackAndAsk"/>
|
||||
<addaction name="actionTrackAndReopen"/>
|
||||
</widget>
|
||||
<addaction name="actionOpenImageFile"/>
|
||||
<addaction name="actionOpenImageFileInNewWindow"/>
|
||||
<addaction name="actionSaveImageFile"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="menuOpenedImageFileTracking"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionGenerateReport"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionLoadGuidDatabase"/>
|
||||
|
@ -329,6 +339,7 @@
|
|||
<addaction name="actionUnloadGuidDatabase"/>
|
||||
<addaction name="actionExportDiscoveredGuids"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionQuit"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuHelp">
|
||||
|
@ -548,6 +559,9 @@
|
|||
<string>&View</string>
|
||||
</property>
|
||||
<addaction name="actionToggleBootGuardMarking"/>
|
||||
<addaction name="actionToggleCStyleHexValues"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionExpandAll"/>
|
||||
</widget>
|
||||
<addaction name="menuFile"/>
|
||||
<addaction name="menuAction"/>
|
||||
|
@ -699,7 +713,7 @@
|
|||
<string>F1</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::AboutRole</enum>
|
||||
<enum>QAction::MenuRole::AboutRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionAboutQt">
|
||||
|
@ -710,7 +724,7 @@
|
|||
<string>Shift+F1</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::AboutQtRole</enum>
|
||||
<enum>QAction::MenuRole::AboutQtRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionQuit">
|
||||
|
@ -721,7 +735,7 @@
|
|||
<string>Alt+X</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::QuitRole</enum>
|
||||
<enum>QAction::MenuRole::QuitRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSearch">
|
||||
|
@ -936,6 +950,52 @@
|
|||
<string>Ctrl+Alt+E</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionToggleCStyleHexValues">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>C-style hex values</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>C-style hex values</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+Shift+C</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionTrackAndIgnore">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Ignore changes</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionTrackAndAsk">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Ask if changed</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionTrackAndReopen">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Auto reopen if changed</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionExpandAll">
|
||||
<property name="text">
|
||||
<string>Expand all</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Expand all tree items</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<resources/>
|
||||
|
|
|
@ -78,6 +78,8 @@ typedef size_t USTATUS;
|
|||
#define U_INVALID_SYMBOL 55
|
||||
#define U_ZLIB_DECOMPRESSION_FAILED 56
|
||||
#define U_INVALID_STORE 57
|
||||
#define U_INVALID_PE_HEADER 58
|
||||
#define U_INVALID_TE_HEADER 59
|
||||
|
||||
#define U_INVALID_MANIFEST 251
|
||||
#define U_UNKNOWN_MANIFEST_HEADER_VERSION 252
|
||||
|
@ -221,6 +223,10 @@ typedef struct EFI_TIME_ {
|
|||
#define TCG_HASH_ALGORITHM_ID_NULL 0x0010
|
||||
#define TCG_HASH_ALGORITHM_ID_SM3 0x0012
|
||||
|
||||
// Some whole image-related notional defines
|
||||
#define UEFI_UPPER_INVALID_ADDRESS 0x100000000ULL
|
||||
#define UEFI_LOWER_INVALID_ADDRESS (UEFI_UPPER_INVALID_ADDRESS >> 1)
|
||||
|
||||
// A workaround for compilers not supporting c++11 and c11
|
||||
// for using PRIX64.
|
||||
#define __STDC_FORMAT_MACROS
|
||||
|
|
|
@ -39,7 +39,7 @@ USTATUS FfsBuilder::erase(const UModelIndex & index, UByteArray & erased)
|
|||
}
|
||||
}
|
||||
|
||||
erased = UByteArray(model->header(index).size() + model->body(index).size() + model->tail(index).size(), emptyByte);
|
||||
erased = UByteArray(model->headerSize(index) + model->bodySize(index) + model->tailSize(index), emptyByte);
|
||||
|
||||
return U_SUCCESS;
|
||||
}
|
||||
|
@ -124,7 +124,7 @@ USTATUS FfsBuilder::buildCapsule(const UModelIndex & index, UByteArray & capsule
|
|||
|
||||
// Check size of reconstructed capsule body, it must remain the same
|
||||
UINT32 newSize = (UINT32)capsule.size();
|
||||
UINT32 oldSize = (UINT32)model->body(index).size();
|
||||
UINT32 oldSize = (UINT32)model->bodySize(index);
|
||||
if (newSize > oldSize) {
|
||||
msg(usprintf("buildCapsule: new capsule size %Xh (%u) is bigger than the original %Xh (%u)", newSize, newSize, oldSize, oldSize), index);
|
||||
return U_INVALID_CAPSULE;
|
||||
|
@ -223,7 +223,7 @@ USTATUS FfsBuilder::buildIntelImage(const UModelIndex & index, UByteArray & inte
|
|||
|
||||
// Check size of new image, it must be same as old one
|
||||
UINT32 newSize = (UINT32)intelImage.size();
|
||||
UINT32 oldSize = (UINT32)model->body(index).size();
|
||||
UINT32 oldSize = (UINT32)model->bodySize(index);
|
||||
if (newSize > oldSize) {
|
||||
msg(usprintf("buildIntelImage: new image size %Xh (%u) is bigger than the original %Xh (%u)", newSize, newSize, oldSize, oldSize), index);
|
||||
return U_INVALID_IMAGE;
|
||||
|
@ -294,7 +294,7 @@ USTATUS FfsBuilder::buildRawArea(const UModelIndex & index, UByteArray & rawArea
|
|||
|
||||
// Check size of new raw area, it must be same as original one
|
||||
UINT32 newSize = (UINT32)rawArea.size();
|
||||
UINT32 oldSize = (UINT32)model->body(index).size();
|
||||
UINT32 oldSize = (UINT32)model->bodySize(index);
|
||||
if (newSize > oldSize) {
|
||||
msg(usprintf("buildRawArea: new area size %Xh (%u) is bigger than the original %Xh (%u)", newSize, newSize, oldSize, oldSize), index);
|
||||
return U_INVALID_RAW_AREA;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -14,6 +14,7 @@ WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|||
#define FFSPARSER_H
|
||||
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "basetypes.h"
|
||||
#include "ustring.h"
|
||||
|
@ -115,6 +116,8 @@ private:
|
|||
UModelIndex lastVtf;
|
||||
UINT32 imageBase;
|
||||
UINT64 addressDiff;
|
||||
REGION_INFO biosRegionInfo;
|
||||
std::unordered_map<UINT64, int> baseAddressesMap;
|
||||
|
||||
UString securityInfo;
|
||||
|
||||
|
@ -126,6 +129,7 @@ private:
|
|||
USTATUS performFirstPass(const UByteArray & imageFile, UModelIndex & index);
|
||||
|
||||
USTATUS parseCapsule(const UByteArray & capsule, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
|
||||
USTATUS parseImage(const UByteArray& buffer, const UINT32 localOffset, const UModelIndex& parent, UModelIndex& index);
|
||||
USTATUS parseIntelImage(const UByteArray & intelImage, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
|
||||
USTATUS parseGenericImage(const UByteArray & intelImage, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
|
||||
|
||||
|
@ -136,9 +140,9 @@ private:
|
|||
|
||||
USTATUS parseRawArea(const UModelIndex & index);
|
||||
USTATUS parseVolumeHeader(const UByteArray & volume, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
|
||||
USTATUS parseVolumeBody(const UModelIndex & index);
|
||||
USTATUS parseVolumeBody(const UModelIndex & index, const bool probe = false);
|
||||
USTATUS parseMicrocodeVolumeBody(const UModelIndex & index);
|
||||
USTATUS parseFileHeader(const UByteArray & file, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
|
||||
USTATUS parseFileHeader(const UByteArray & file, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index, const bool probe = false);
|
||||
USTATUS parseFileBody(const UModelIndex & index);
|
||||
USTATUS parseSectionHeader(const UByteArray & section, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index, const bool insertIntoTree);
|
||||
USTATUS parseSectionBody(const UModelIndex & index);
|
||||
|
@ -167,8 +171,8 @@ private:
|
|||
USTATUS parseDepexSectionBody(const UModelIndex & index);
|
||||
USTATUS parseUiSectionBody(const UModelIndex & index);
|
||||
USTATUS parseRawSectionBody(const UModelIndex & index);
|
||||
USTATUS parsePeImageSectionBody(const UModelIndex & index);
|
||||
USTATUS parseTeImageSectionBody(const UModelIndex & index);
|
||||
USTATUS parsePeImageSectionBody(const UModelIndex & index, const bool probe = false);
|
||||
USTATUS parseTeImageSectionBody(const UModelIndex & index, const bool probe = false);
|
||||
|
||||
USTATUS parseAprioriRawSection(const UByteArray & body, UString & parsed);
|
||||
USTATUS findNextRawAreaItem(const UModelIndex & index, const UINT32 localOffset, UINT8 & nextItemType, UINT32 & nextItemOffset, UINT32 & nextItemSize, UINT32 & nextItemAlternativeSize);
|
||||
|
|
|
@ -200,7 +200,7 @@ USTATUS FitParser::parseFit(const UModelIndex & index)
|
|||
return U_SUCCESS;
|
||||
}
|
||||
|
||||
void FitParser::findFitRecursive(const UModelIndex & index, UModelIndex & found, UINT32 & fitOffset)
|
||||
void FitParser::findFitRecursive(const UModelIndex& index, UModelIndex & found, UINT32 & fitOffset)
|
||||
{
|
||||
// Sanity check
|
||||
if (!index.isValid()) {
|
||||
|
@ -217,28 +217,30 @@ void FitParser::findFitRecursive(const UModelIndex & index, UModelIndex & found,
|
|||
}
|
||||
}
|
||||
|
||||
// Check for all FIT signatures in item body
|
||||
UByteArray lastVtfBody = model->body(ffsParser->lastVtf);
|
||||
// Check for all FIT signatures in item body - we want to log 'em all
|
||||
UByteArray lastVtfBody = model->header(ffsParser->lastVtf) + model->body(ffsParser->lastVtf) + model->tail(ffsParser->lastVtf);
|
||||
UINT64 fitSignatureValue = INTEL_FIT_SIGNATURE;
|
||||
UByteArray fitSignature((const char*)&fitSignatureValue, sizeof(fitSignatureValue));
|
||||
UINT32 storedFitAddress = *(const UINT32*)(lastVtfBody.constData() + lastVtfBody.size() - INTEL_FIT_POINTER_OFFSET);
|
||||
UINT32 storedFitAddress = *(const UINT32*)(lastVtfBody.constData() + UEFI_UPPER_INVALID_ADDRESS - INTEL_FIT_POINTER_OFFSET
|
||||
- model->base(ffsParser->lastVtf) - ffsParser->addressDiff);
|
||||
for (INT32 offset = (INT32)model->body(index).indexOf(fitSignature);
|
||||
offset >= 0;
|
||||
offset = (INT32)model->body(index).indexOf(fitSignature, offset + 1)) {
|
||||
// FIT candidate found, calculate its physical address
|
||||
UINT32 fitAddress = (UINT32)(model->base(index) + (UINT32)ffsParser->addressDiff + model->header(index).size() + (UINT32)offset);
|
||||
UINT32 fitAddress = (UINT32)(model->base(index) + (UINT32)ffsParser->addressDiff + model->headerSize(index) + (UINT32)offset);
|
||||
|
||||
// Check FIT address to be stored in the last VTF
|
||||
if (fitAddress == storedFitAddress) {
|
||||
// Valid FIT table must have at least two entries
|
||||
if ((UINT32)model->body(index).size() < offset + 2*sizeof(INTEL_FIT_ENTRY)) {
|
||||
if ((UINT32)model->bodySize(index) < offset + 2*sizeof(INTEL_FIT_ENTRY)) {
|
||||
msg(usprintf("%s: FIT table candidate found, too small to contain real FIT", __FUNCTION__), index);
|
||||
}
|
||||
else {
|
||||
// Real FIT found
|
||||
found = index;
|
||||
fitOffset = offset;
|
||||
msg(usprintf("%s: real FIT table found at physical address %08Xh", __FUNCTION__, fitAddress), found);
|
||||
msg(usprintf("%s: real FIT table found at physical address %08Xh (offset %Xh)", __FUNCTION__,
|
||||
fitAddress, fitOffset), found);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -709,8 +711,8 @@ USTATUS FitParser::parseFitEntryBootGuardBootPolicy(const UByteArray & bootPolic
|
|||
else {
|
||||
// Add postIbbHash protected range
|
||||
UByteArray postIbbHash(ibbs_body->post_ibb_hash()->hash().data(), ibbs_body->post_ibb_hash()->len_hash());
|
||||
if (postIbbHash.count('\x00') != postIbbHash.size()
|
||||
&& postIbbHash.count('\xFF') != postIbbHash.size()) {
|
||||
auto c = checkSingle(postIbbHash);
|
||||
if (c != 0 && c != 0xFF) {
|
||||
PROTECTED_RANGE range = {};
|
||||
range.Type = PROTECTED_RANGE_INTEL_BOOT_GUARD_POST_IBB;
|
||||
range.AlgorithmId = ibbs_body->post_ibb_hash()->hash_algorithm_id();
|
||||
|
@ -990,8 +992,8 @@ USTATUS FitParser::parseFitEntryBootGuardBootPolicy(const UByteArray & bootPolic
|
|||
else {
|
||||
// Add postIbbHash protected range
|
||||
UByteArray postIbbHash(ibbs_body->post_ibb_digest()->hash().data(), ibbs_body->post_ibb_digest()->len_hash());
|
||||
if (postIbbHash.count('\x00') != postIbbHash.size()
|
||||
&& postIbbHash.count('\xFF') != postIbbHash.size()) {
|
||||
auto c = checkSingle(postIbbHash);
|
||||
if (c != 0 && c != 0xFF) {
|
||||
PROTECTED_RANGE range = {};
|
||||
range.Type = PROTECTED_RANGE_INTEL_BOOT_GUARD_POST_IBB;
|
||||
range.AlgorithmId = ibbs_body->post_ibb_digest()->hash_algorithm_id();
|
||||
|
@ -1021,8 +1023,8 @@ USTATUS FitParser::parseFitEntryBootGuardBootPolicy(const UByteArray & bootPolic
|
|||
|
||||
// Add ObbHash protected range
|
||||
UByteArray obbHash(ibbs_body->obb_digest()->hash().data(), ibbs_body->obb_digest()->len_hash());
|
||||
if (obbHash.count('\x00') != obbHash.size()
|
||||
&& obbHash.count('\xFF') != obbHash.size()) {
|
||||
auto c = checkSingle(obbHash);
|
||||
if (c != 0 && c != 0xFF) {
|
||||
PROTECTED_RANGE range = {};
|
||||
range.Type = PROTECTED_RANGE_INTEL_BOOT_GUARD_OBB;
|
||||
range.AlgorithmId = ibbs_body->obb_digest()->hash_algorithm_id();
|
||||
|
|
|
@ -21,7 +21,7 @@ WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|||
|
||||
// This structure is described in Section 9.11.1 of the Intel Software Developer manual Volume 3A Part 1
|
||||
typedef struct INTEL_MICROCODE_HEADER_ {
|
||||
UINT32 HeaderVersion; // 0x00000001
|
||||
UINT32 HeaderType; // 0x00000001 for Microcode (we do not need to support IFS yet)
|
||||
UINT32 UpdateRevision;
|
||||
UINT16 DateYear; // BCD
|
||||
UINT8 DateDay; // BCD
|
||||
|
@ -31,8 +31,7 @@ typedef struct INTEL_MICROCODE_HEADER_ {
|
|||
// Checksum is correct when the summation of all the DWORDs (including the extended Processor Signature Table)
|
||||
// that comprise the microcode update result in 00000000H.
|
||||
UINT32 LoaderRevision; // 0x00000001
|
||||
UINT8 ProcessorFlags;
|
||||
UINT8 ProcessorFlagsReserved[3]; // Zeroes
|
||||
UINT32 PlatformIds; // Platform Ids
|
||||
UINT32 DataSize; // Specifies the size of the encrypted data in bytes, and must be a multiple of DWORDs.
|
||||
// If this value is 00000000H, then the microcode update encrypted data is 2000 bytes (or 500 DWORDs).
|
||||
// Sane values are less than 0x1000000
|
||||
|
@ -40,7 +39,9 @@ typedef struct INTEL_MICROCODE_HEADER_ {
|
|||
// It is the summation of the header size, the encrypted data size and the size of the optional extended signature table.
|
||||
// This value is always a multiple of 1024 according to the spec, but Intel already breached it several times.
|
||||
// Sane values are less than 0x1000000
|
||||
UINT8 Reserved[12]; // Zeroes
|
||||
UINT32 MetadataSize; // Reserved in Microcode headers
|
||||
UINT32 UpdateRevisionMin; // Minimum required version for OS Kernel Late Loading
|
||||
UINT32 Reserved; // Zeroes
|
||||
} INTEL_MICROCODE_HEADER;
|
||||
|
||||
#define INTEL_MICROCODE_REAL_DATA_SIZE_ON_ZERO 2000
|
||||
|
@ -57,8 +58,8 @@ typedef struct INTEL_MICROCODE_EXTENDED_HEADER_ {
|
|||
|
||||
typedef struct INTEL_MICROCODE_EXTENDED_HEADER_ENTRY_ {
|
||||
UINT32 ProcessorSignature;
|
||||
UINT32 ProcessorFlags;
|
||||
UINT32 Checksum; // To calculate the Checksum, substitute the Primary Processor Signature entry and the Processor Flags entry with the corresponding Extended Patch entry.
|
||||
UINT32 PlatformIds;
|
||||
UINT32 Checksum; // To calculate the Checksum, substitute the Primary Processor Signature entry and the Platform Ids entry with the corresponding Extended Patch entry.
|
||||
// Delete the Extended Processor Signature Table entries.
|
||||
// Checksum is correct when the summation of all DWORDs that comprise the created Extended Processor Patch results in 00000000H.
|
||||
} INTEL_MICROCODE_EXTENDED_HEADER_ENTRY;
|
||||
|
|
|
@ -126,8 +126,7 @@ USTATUS MeParser::parseFptRegion(const UByteArray & region, const UModelIndex &
|
|||
}
|
||||
|
||||
// Get info
|
||||
UByteArray header = region.left(romBypassVectorSize + sizeof(FPT_HEADER));
|
||||
UByteArray body = region.mid(header.size(), ptBodySize);
|
||||
UINT32 headerSize = romBypassVectorSize + sizeof(FPT_HEADER);
|
||||
|
||||
UString name = UString("FPT partition table");
|
||||
UString info;
|
||||
|
@ -139,7 +138,7 @@ USTATUS MeParser::parseFptRegion(const UByteArray & region, const UModelIndex &
|
|||
info = usprintf("Full size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nROM bypass vector: %s\nNumber of entries: %u\nHeader version: %02Xh\nEntry version: %02Xh\n"
|
||||
"Header length: %02Xh\nFlags: %Xh\nTicks to add: %04Xh\nTokens to add: %04Xh\nSPS Flags: %Xh\nFITC version: %u.%u.%u.%u\nCRC32 Checksum: %08Xh",
|
||||
ptSize, ptSize,
|
||||
(UINT32)header.size(), (UINT32)header.size(),
|
||||
headerSize, headerSize,
|
||||
ptBodySize, ptBodySize,
|
||||
(romBypassVectorSize ? "present" : "absent"),
|
||||
ptHeader21->NumEntries,
|
||||
|
@ -159,7 +158,7 @@ USTATUS MeParser::parseFptRegion(const UByteArray & region, const UModelIndex &
|
|||
info = usprintf("Full size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nROM bypass vector: %s\nNumber of entries: %u\nHeader version: %02Xh\nEntry version: %02Xh\n"
|
||||
"Header length: %02Xh\nFlash cycle life: %04Xh\nFlash cycle limit: %04Xh\nUMA size: %Xh\nFlags: %Xh\nFITC version: %u.%u.%u.%u\nChecksum: %02Xh",
|
||||
ptSize, ptSize,
|
||||
(UINT32)header.size(), (UINT32)header.size(),
|
||||
headerSize, headerSize,
|
||||
ptBodySize, ptBodySize,
|
||||
(romBypassVectorSize ? "present" : "absent"),
|
||||
ptHeader->NumEntries,
|
||||
|
@ -176,11 +175,15 @@ USTATUS MeParser::parseFptRegion(const UByteArray & region, const UModelIndex &
|
|||
}
|
||||
|
||||
// Add tree item
|
||||
index = model->addItem(0, Types::FptStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, parent);
|
||||
index = model->addItem(
|
||||
0, Types::FptStore, 0,
|
||||
name, UString(), info,
|
||||
headerSize, ptBodySize, 0,
|
||||
Fixed, parent);
|
||||
|
||||
// Add partition table entries
|
||||
std::vector<FPT_PARTITION_INFO> partitions;
|
||||
UINT32 offset = (UINT32)header.size();
|
||||
UINT32 offset = headerSize;
|
||||
UINT32 numEntries = ptHeader->NumEntries;
|
||||
const FPT_HEADER_ENTRY* firstPtEntry = (const FPT_HEADER_ENTRY*)(region.constData() + offset);
|
||||
for (UINT32 i = 0; i < numEntries; i++) {
|
||||
|
@ -197,7 +200,11 @@ USTATUS MeParser::parseFptRegion(const UByteArray & region, const UModelIndex &
|
|||
|
||||
// Add tree item
|
||||
const UINT8 type = (ptEntry->Offset != 0 && ptEntry->Offset != 0xFFFFFFFF && ptEntry->Size != 0 && ptEntry->EntryValid != 0xFF) ? Subtypes::ValidFptEntry : Subtypes::InvalidFptEntry;
|
||||
UModelIndex entryIndex = model->addItem(offset, Types::FptEntry, type, name, UString(), info, UByteArray(), UByteArray((const char*)ptEntry, sizeof(FPT_HEADER_ENTRY)), UByteArray(), Fixed, index);
|
||||
UModelIndex entryIndex = model->addItem(
|
||||
offset, Types::FptEntry, type,
|
||||
name, UString(), info,
|
||||
0, sizeof(FPT_HEADER_ENTRY), 0,
|
||||
Fixed, index);
|
||||
|
||||
// Adjust offset
|
||||
offset += sizeof(FPT_HEADER_ENTRY);
|
||||
|
@ -311,7 +318,11 @@ make_partition_table_consistent:
|
|||
|
||||
// Add tree item
|
||||
UINT8 type = Subtypes::CodeFptPartition + partitions[i].ptEntry.Type;
|
||||
partitionIndex = model->addItem(partitions[i].ptEntry.Offset, Types::FptPartition, type, name, UString(), info, UByteArray(), partition, UByteArray(), Fixed, parent);
|
||||
partitionIndex = model->addItem(
|
||||
partitions[i].ptEntry.Offset, Types::FptPartition, type,
|
||||
name, UString(), info,
|
||||
0, partition.size(), 0,
|
||||
Fixed, parent);
|
||||
if (type == Subtypes::CodeFptPartition && partition.size() >= (int) sizeof(UINT32) && readUnaligned((const UINT32*)partition.constData()) == CPD_SIGNATURE) {
|
||||
// Parse code partition contents
|
||||
UModelIndex cpdIndex;
|
||||
|
@ -324,7 +335,11 @@ make_partition_table_consistent:
|
|||
info = usprintf("Full size: %Xh (%u)", (UINT32)partition.size(), (UINT32)partition.size());
|
||||
|
||||
// Add tree item
|
||||
model->addItem(partitions[i].ptEntry.Offset, Types::Padding, getPaddingType(partition), name, UString(), info, UByteArray(), partition, UByteArray(), Fixed, parent);
|
||||
model->addItem(
|
||||
partitions[i].ptEntry.Offset, Types::Padding, getPaddingType(partition),
|
||||
name, UString(), info,
|
||||
0, partition.size(), 0,
|
||||
Fixed, parent);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -343,7 +358,7 @@ USTATUS MeParser::parseIfwi16Region(const UByteArray & region, const UModelIndex
|
|||
|
||||
// Add header
|
||||
UINT32 ptSize = sizeof(IFWI_16_LAYOUT_HEADER);
|
||||
UByteArray header = region.left(ptSize);
|
||||
UINT32 headerSize = ptSize > region.size() ? region.size() : ptSize;
|
||||
|
||||
UString name = UString("IFWI 1.6 header");
|
||||
UString info = usprintf("Full size: %Xh (%u)\n"
|
||||
|
@ -354,7 +369,7 @@ USTATUS MeParser::parseIfwi16Region(const UByteArray & region, const UModelIndex
|
|||
"Boot4 partition offset: %Xh\nBoot4 partition size: %Xh\n"
|
||||
"Boot5 partition offset: %Xh\nBoot5 partition size: %Xh\n"
|
||||
"Checksum: %" PRIX64 "h",
|
||||
(UINT32)header.size(), (UINT32)header.size(),
|
||||
headerSize, headerSize,
|
||||
ifwiHeader->DataPartition.Offset, ifwiHeader->DataPartition.Size,
|
||||
ifwiHeader->BootPartition[0].Offset, ifwiHeader->BootPartition[0].Size,
|
||||
ifwiHeader->BootPartition[1].Offset, ifwiHeader->BootPartition[1].Size,
|
||||
|
@ -363,7 +378,11 @@ USTATUS MeParser::parseIfwi16Region(const UByteArray & region, const UModelIndex
|
|||
ifwiHeader->BootPartition[4].Offset, ifwiHeader->BootPartition[4].Size,
|
||||
ifwiHeader->Checksum);
|
||||
// Add tree item
|
||||
index = model->addItem(0, Types::IfwiHeader, 0, name, UString(), info, UByteArray(), header, UByteArray(), Fixed, parent);
|
||||
index = model->addItem(
|
||||
0, Types::IfwiHeader, 0,
|
||||
name, UString(), info,
|
||||
0, headerSize, 0,
|
||||
Fixed, parent);
|
||||
|
||||
std::vector<IFWI_PARTITION_INFO> partitions;
|
||||
// Add data partition
|
||||
|
@ -474,7 +493,11 @@ make_partition_table_consistent:
|
|||
info = usprintf("Full size: %Xh (%u)\n", (UINT32)partition.size(), (UINT32)partition.size());
|
||||
|
||||
// Add tree item
|
||||
partitionIndex = model->addItem(partitions[i].ptEntry.Offset, partitions[i].type, partitions[i].subtype, name, UString(), info, UByteArray(), partition, UByteArray(), Fixed, parent);
|
||||
partitionIndex = model->addItem(
|
||||
partitions[i].ptEntry.Offset, partitions[i].type, partitions[i].subtype,
|
||||
name, UString(), info,
|
||||
0, partition.size(), 0,
|
||||
Fixed, parent);
|
||||
|
||||
// Parse partition further
|
||||
if (partitions[i].subtype == Subtypes::DataIfwiPartition) {
|
||||
|
@ -493,7 +516,11 @@ make_partition_table_consistent:
|
|||
info = usprintf("Full size: %Xh (%u)", (UINT32)partition.size(), (UINT32)partition.size());
|
||||
|
||||
// Add tree item
|
||||
model->addItem(partitions[i].ptEntry.Offset, Types::Padding, getPaddingType(partition), name, UString(), info, UByteArray(), partition, UByteArray(), Fixed, parent);
|
||||
model->addItem(
|
||||
partitions[i].ptEntry.Offset, Types::Padding, getPaddingType(partition),
|
||||
name, UString(), info,
|
||||
0, partition.size(), 0,
|
||||
Fixed, parent);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -513,7 +540,7 @@ USTATUS MeParser::parseIfwi17Region(const UByteArray & region, const UModelIndex
|
|||
|
||||
// Add header
|
||||
UINT32 ptSize = sizeof(IFWI_17_LAYOUT_HEADER);
|
||||
UByteArray header = region.left(ptSize);
|
||||
UINT32 headerSize = ptSize > region.size() ? region.size() : ptSize;
|
||||
|
||||
UString name = UString("IFWI 1.7 header");
|
||||
UString info = usprintf("Full size: %Xh (%u)\n"
|
||||
|
@ -527,7 +554,7 @@ USTATUS MeParser::parseIfwi17Region(const UByteArray & region, const UModelIndex
|
|||
"Boot4 partition offset: %Xh\nBoot4 partition size: %Xh\n"
|
||||
"Boot5 partition offset: %Xh\nBoot5 partition size: %Xh\n"
|
||||
"Temp page offset: %Xh\nTemp page size: %Xh\n",
|
||||
(UINT32)header.size(), (UINT32)header.size(),
|
||||
headerSize, headerSize,
|
||||
ifwiHeader->Flags,
|
||||
ifwiHeader->Reserved,
|
||||
ifwiHeader->Checksum,
|
||||
|
@ -539,7 +566,11 @@ USTATUS MeParser::parseIfwi17Region(const UByteArray & region, const UModelIndex
|
|||
ifwiHeader->BootPartition[4].Offset, ifwiHeader->BootPartition[4].Size,
|
||||
ifwiHeader->TempPage.Offset, ifwiHeader->TempPage.Size);
|
||||
// Add tree item
|
||||
index = model->addItem(0, Types::IfwiHeader, 0, name, UString(), info, UByteArray(), header, UByteArray(), Fixed, parent);
|
||||
index = model->addItem(
|
||||
0, Types::IfwiHeader, 0,
|
||||
name, UString(), info,
|
||||
0, headerSize, 0,
|
||||
Fixed, parent);
|
||||
|
||||
std::vector<IFWI_PARTITION_INFO> partitions;
|
||||
// Add data partition
|
||||
|
@ -662,7 +693,11 @@ make_partition_table_consistent:
|
|||
info = usprintf("Full size: %Xh (%u)\n", (UINT32)partition.size(), (UINT32)partition.size());
|
||||
|
||||
// Add tree item
|
||||
partitionIndex = model->addItem(partitions[i].ptEntry.Offset, partitions[i].type, partitions[i].subtype, name, UString(), info, UByteArray(), partition, UByteArray(), Fixed, parent);
|
||||
partitionIndex = model->addItem(
|
||||
partitions[i].ptEntry.Offset, partitions[i].type, partitions[i].subtype,
|
||||
name, UString(), info,
|
||||
0, partition.size(), 0,
|
||||
Fixed, parent);
|
||||
|
||||
// Parse partition further
|
||||
if (partitions[i].subtype == Subtypes::DataIfwiPartition) {
|
||||
|
@ -688,7 +723,11 @@ make_partition_table_consistent:
|
|||
info = usprintf("Full size: %Xh (%u)", (UINT32)partition.size(), (UINT32)partition.size());
|
||||
|
||||
// Add tree item
|
||||
model->addItem(partitions[i].ptEntry.Offset, Types::Padding, getPaddingType(partition), name, UString(), info, UByteArray(), partition, UByteArray(), Fixed, parent);
|
||||
model->addItem(
|
||||
partitions[i].ptEntry.Offset, Types::Padding, getPaddingType(partition),
|
||||
name, UString(), info,
|
||||
0, partition.size(), 0,
|
||||
Fixed, parent);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -37,8 +37,8 @@ public:
|
|||
void clearMessages() { messagesVector.clear(); }
|
||||
|
||||
// NVRAM parsing
|
||||
USTATUS parseNvramVolumeBody(const UModelIndex & index, const UINT32 fdcStoreSizeOverride = 0);
|
||||
USTATUS parseNvarStore(const UModelIndex & index);
|
||||
USTATUS parseNvramVolumeBody(const UModelIndex& index, const UINT32 fdcStoreSizeOverride = 0);
|
||||
USTATUS parseNvarStore(const UModelIndex & index, const bool probe = false);
|
||||
|
||||
private:
|
||||
TreeModel *model;
|
||||
|
@ -63,7 +63,7 @@ public:
|
|||
|
||||
// NVRAM parsing
|
||||
USTATUS parseNvramVolumeBody(const UModelIndex &) { return U_SUCCESS; }
|
||||
USTATUS parseNvarStore(const UModelIndex &) { return U_SUCCESS; }
|
||||
USTATUS parseNvarStore(const UModelIndex &, const bool probe = false) { return U_SUCCESS; }
|
||||
};
|
||||
#endif // U_ENABLE_NVRAM_PARSING_SUPPORT
|
||||
#endif // NVRAMPARSER_H
|
||||
|
|
1509
common/printf/printf.c
Normal file
1509
common/printf/printf.c
Normal file
File diff suppressed because it is too large
Load diff
240
common/printf/printf.h
Normal file
240
common/printf/printf.h
Normal file
|
@ -0,0 +1,240 @@
|
|||
/**
|
||||
* @author (c) Eyal Rozenberg <eyalroz1@gmx.com>
|
||||
* 2021-2023, Haifa, Palestine/Israel
|
||||
* @author (c) Marco Paland (info@paland.com)
|
||||
* 2014-2019, PALANDesign Hannover, Germany
|
||||
*
|
||||
* @note Others have made smaller contributions to this file: see the
|
||||
* contributors page at https://github.com/eyalroz/printf/graphs/contributors
|
||||
* or ask one of the authors.
|
||||
*
|
||||
* @brief Small stand-alone implementation of the printf family of functions
|
||||
* (`(v)printf`, `(v)s(n)printf` etc., geared towards use on embedded systems
|
||||
* with a very limited resources.
|
||||
*
|
||||
* @note the implementations are thread-safe; re-entrant; use no functions from
|
||||
* the standard library; and do not dynamically allocate any memory.
|
||||
*
|
||||
* @license The MIT License (MIT)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef PRINTF_H_
|
||||
#define PRINTF_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
# include <cstdarg>
|
||||
# include <cstddef>
|
||||
extern "C" {
|
||||
#else
|
||||
# include <stdarg.h>
|
||||
# include <stddef.h>
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
# if ((__GNUC__ == 4 && __GNUC_MINOR__>= 4) || __GNUC__ > 4)
|
||||
# define ATTR_PRINTF(one_based_format_index, first_arg) \
|
||||
__attribute__((format(gnu_printf, (one_based_format_index), (first_arg))))
|
||||
# else
|
||||
# define ATTR_PRINTF(one_based_format_index, first_arg) \
|
||||
__attribute__((format(printf, (one_based_format_index), (first_arg))))
|
||||
# endif
|
||||
# define ATTR_VPRINTF(one_based_format_index) \
|
||||
ATTR_PRINTF((one_based_format_index), 0)
|
||||
#else
|
||||
# define ATTR_PRINTF(one_based_format_index, first_arg)
|
||||
# define ATTR_VPRINTF(one_based_format_index)
|
||||
#endif
|
||||
|
||||
#ifndef PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_SOFT
|
||||
#define PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_SOFT 0
|
||||
#endif
|
||||
|
||||
#ifndef PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_HARD
|
||||
#define PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_HARD 0
|
||||
#endif
|
||||
|
||||
#if PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_HARD
|
||||
# define printf_ printf
|
||||
# define sprintf_ sprintf
|
||||
# define vsprintf_ vsprintf
|
||||
# define snprintf_ snprintf
|
||||
# define vsnprintf_ vsnprintf
|
||||
# define vprintf_ vprintf
|
||||
#endif
|
||||
|
||||
// If you want to include this implementation file directly rather than
|
||||
// link against it, this will let you control the functions' visibility,
|
||||
// e.g. make them static so as not to clash with other objects also
|
||||
// using them.
|
||||
#ifndef PRINTF_VISIBILITY
|
||||
#define PRINTF_VISIBILITY
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Prints/send a single character to some opaque output entity
|
||||
*
|
||||
* @note This function is not implemented by the library, only declared; you
|
||||
* must provide an implementation if you wish to use the @ref printf / @ref
|
||||
* vprintf function (and possibly for linking against the library, if your
|
||||
* toolchain does not support discarding unused functions)
|
||||
*
|
||||
* @note The output could be as simple as a wrapper for the `write()` system
|
||||
* call on a Unix-like * system, or even libc's @ref putchar , for replicating
|
||||
* actual functionality of libc's @ref printf * function; but on an embedded
|
||||
* system it may involve interaction with a special output device, like a UART,
|
||||
* etc.
|
||||
*
|
||||
* @note in libc's @ref putchar, the parameter type is an int; this was intended
|
||||
* to support the representation of either a proper character or EOF in a
|
||||
* variable - but this is really not meaningful to pass into @ref putchar and is
|
||||
* discouraged today. See further discussion in:
|
||||
* @link https://stackoverflow.com/q/17452847/1593077
|
||||
*
|
||||
* @param c the single character to print
|
||||
*/
|
||||
PRINTF_VISIBILITY
|
||||
void putchar_(char c);
|
||||
|
||||
|
||||
/**
|
||||
* An implementation of the C standard's printf/vprintf
|
||||
*
|
||||
* @note you must implement a @ref putchar_ function for using this function -
|
||||
* it invokes @ref putchar_ * rather than directly performing any I/O (which
|
||||
* insulates it from any dependence on the operating system * and external
|
||||
* libraries).
|
||||
*
|
||||
* @param format A string specifying the format of the output, with %-marked
|
||||
* specifiers of how to interpret additional arguments.
|
||||
* @param arg Additional arguments to the function, one for each %-specifier in
|
||||
* @p format
|
||||
* @return The number of characters written into @p s, not counting the
|
||||
* terminating null character
|
||||
*/
|
||||
///@{
|
||||
PRINTF_VISIBILITY
|
||||
int printf_(const char* format, ...) ATTR_PRINTF(1, 2);
|
||||
PRINTF_VISIBILITY
|
||||
int vprintf_(const char* format, va_list arg) ATTR_VPRINTF(1);
|
||||
///@}
|
||||
|
||||
|
||||
/**
|
||||
* An implementation of the C standard's sprintf/vsprintf
|
||||
*
|
||||
* @note For security considerations (the potential for exceeding the buffer
|
||||
* bounds), please consider using the size-constrained variant, @ref snprintf /
|
||||
* @ref vsnprintf, instead.
|
||||
*
|
||||
* @param s An array in which to store the formatted string. It must be large
|
||||
* enough to fit the formatted output!
|
||||
* @param format A string specifying the format of the output, with %-marked
|
||||
* specifiers of how to interpret additional arguments
|
||||
* @param arg Additional arguments to the function, one for each specifier in
|
||||
* @p format
|
||||
* @return The number of characters written into @p s, not counting the
|
||||
* terminating null character
|
||||
*/
|
||||
///@{
|
||||
PRINTF_VISIBILITY
|
||||
int sprintf_(char* s, const char* format, ...) ATTR_PRINTF(2, 3);
|
||||
PRINTF_VISIBILITY
|
||||
int vsprintf_(char* s, const char* format, va_list arg) ATTR_VPRINTF(2);
|
||||
///@}
|
||||
|
||||
|
||||
/**
|
||||
* An implementation of the C standard's snprintf/vsnprintf
|
||||
*
|
||||
* @param s An array in which to store the formatted string. It must be large
|
||||
* enough to fit either the entire formatted output, or at least @p n
|
||||
* characters. Alternatively, it can be NULL, in which case nothing will
|
||||
* be printed, and only the number of characters which _could_ have been
|
||||
* printed is tallied and returned.
|
||||
* @param n The maximum number of characters to write to the array, including
|
||||
* a terminating null character
|
||||
* @param format A string specifying the format of the output, with %-marked
|
||||
* specifiers of how to interpret additional arguments.
|
||||
* @param arg Additional arguments to the function, one for each specifier in
|
||||
* @p format
|
||||
* @return The number of characters that COULD have been written into @p s, not
|
||||
* counting the terminating null character. A value equal or larger than
|
||||
* @p n indicates truncation. Only when the returned value is non-negative
|
||||
* and less than @p n, the null-terminated string has been fully and
|
||||
* successfully printed.
|
||||
*/
|
||||
///@{
|
||||
PRINTF_VISIBILITY
|
||||
int snprintf_(char* s, size_t count, const char* format, ...) ATTR_PRINTF(3, 4);
|
||||
PRINTF_VISIBILITY
|
||||
int vsnprintf_(char* s, size_t count, const char* format, va_list arg) ATTR_VPRINTF(3);
|
||||
PRINTF_VISIBILITY
|
||||
int vosnprintf_(char* s, size_t count, const char* format, va_list arg) ATTR_VPRINTF(3);
|
||||
///@}
|
||||
|
||||
/**
|
||||
* printf/vprintf with user-specified output function
|
||||
*
|
||||
* An alternative to @ref printf_, in which the output function is specified
|
||||
* dynamically (rather than @ref putchar_ being used)
|
||||
*
|
||||
* @param out An output function which takes one character and a type-erased
|
||||
* additional parameters
|
||||
* @param extra_arg The type-erased argument to pass to the output function @p
|
||||
* out with each call
|
||||
* @param format A string specifying the format of the output, with %-marked
|
||||
* specifiers of how to interpret additional arguments.
|
||||
* @param arg Additional arguments to the function, one for each specifier in
|
||||
* @p format
|
||||
* @return The number of characters for which the output f unction was invoked,
|
||||
* not counting the terminating null character
|
||||
*
|
||||
*/
|
||||
PRINTF_VISIBILITY
|
||||
int fctprintf(void (*out)(char c, void* extra_arg), void* extra_arg, const char* format, ...) ATTR_PRINTF(3, 4);
|
||||
PRINTF_VISIBILITY
|
||||
int vfctprintf(void (*out)(char c, void* extra_arg), void* extra_arg, const char* format, va_list arg) ATTR_VPRINTF(3);
|
||||
PRINTF_VISIBILITY
|
||||
int vofctprintf(void (*out)(char c, void* extra_arg), void* extra_arg, const char* format, va_list arg) ATTR_VPRINTF(3);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#if PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_HARD
|
||||
# undef printf_
|
||||
# undef sprintf_
|
||||
# undef vsprintf_
|
||||
# undef snprintf_
|
||||
# undef vsnprintf_
|
||||
# undef vprintf_
|
||||
#else
|
||||
#if PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_SOFT
|
||||
# define printf printf_
|
||||
# define sprintf sprintf_
|
||||
# define vsprintf vsprintf_
|
||||
# define snprintf snprintf_
|
||||
# define vsnprintf vsnprintf_
|
||||
# define vprintf vprintf_
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // PRINTF_H_
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
TreeItem::TreeItem(const UINT32 offset, const UINT8 type, const UINT8 subtype,
|
||||
const UString & name, const UString & text, const UString & info,
|
||||
const UByteArray & header, const UByteArray & body, const UByteArray & tail,
|
||||
const UINT32 headerSize, const UINT32 bodySize, const UINT32 tailSize,
|
||||
const bool fixed, const bool compressed,
|
||||
TreeItem *parent) :
|
||||
itemOffset(offset),
|
||||
|
@ -27,9 +27,9 @@ itemMarking(0),
|
|||
itemName(name),
|
||||
itemText(text),
|
||||
itemInfo(info),
|
||||
itemHeader(header),
|
||||
itemBody(body),
|
||||
itemTail(tail),
|
||||
itemHeaderSize(headerSize),
|
||||
itemBodySize(bodySize),
|
||||
itemTailSize(tailSize),
|
||||
itemFixed(fixed),
|
||||
itemCompressed(compressed),
|
||||
parentItem(parent)
|
||||
|
@ -37,16 +37,39 @@ parentItem(parent)
|
|||
}
|
||||
|
||||
TreeItem::~TreeItem() {
|
||||
std::list<TreeItem*>::iterator begin = childItems.begin();
|
||||
auto begin = childItems.begin();
|
||||
while (begin != childItems.end()) {
|
||||
delete *begin;
|
||||
++begin;
|
||||
}
|
||||
}
|
||||
|
||||
const char * TreeItem::content(UINT32 dataOffset) const
|
||||
{
|
||||
if (!itemContent.isEmpty()) {
|
||||
return itemContent.constData() + dataOffset;
|
||||
}
|
||||
auto o = itemOffset;
|
||||
auto p = parentItem;
|
||||
while (p && ((!p->itemCompressed && p->itemContent.isEmpty()) || (p->itemCompressed && p->itemUncompressedData.isEmpty()))) {
|
||||
o += p->itemOffset;
|
||||
p = p->parentItem;
|
||||
}
|
||||
if (!p)
|
||||
return nullptr;
|
||||
return !p->itemCompressed ? p->content(o + dataOffset) : p->itemUncompressedData.constData() + o + dataOffset - p->itemHeaderSize;
|
||||
}
|
||||
|
||||
bool TreeItem::compressedInherited() const {
|
||||
auto p = this;
|
||||
while (p && p->itemType != Types::Root && !p->itemCompressed)
|
||||
p = p->parentItem;
|
||||
return p ? p->itemCompressed : false;
|
||||
}
|
||||
|
||||
UINT8 TreeItem::insertChildBefore(TreeItem *item, TreeItem *newItem)
|
||||
{
|
||||
std::list<TreeItem*>::iterator found = std::find(childItems.begin(), childItems.end(), item);
|
||||
auto found = std::find(childItems.begin(), childItems.end(), item);
|
||||
if (found == childItems.end())
|
||||
return U_ITEM_NOT_FOUND;
|
||||
childItems.insert(found, newItem);
|
||||
|
@ -55,7 +78,7 @@ UINT8 TreeItem::insertChildBefore(TreeItem *item, TreeItem *newItem)
|
|||
|
||||
UINT8 TreeItem::insertChildAfter(TreeItem *item, TreeItem *newItem)
|
||||
{
|
||||
std::list<TreeItem*>::iterator found = std::find(childItems.begin(), childItems.end(), item);
|
||||
auto found = std::find(childItems.begin(), childItems.end(), item);
|
||||
if (found == childItems.end())
|
||||
return U_ITEM_NOT_FOUND;
|
||||
childItems.insert(++found, newItem);
|
||||
|
@ -84,7 +107,7 @@ UString TreeItem::data(int column) const
|
|||
int TreeItem::row() const
|
||||
{
|
||||
if (parentItem) {
|
||||
std::list<TreeItem*>::const_iterator iter = parentItem->childItems.begin();
|
||||
auto iter = parentItem->childItems.begin();
|
||||
for (int i = 0; i < (int)parentItem->childItems.size(); ++i, ++iter) {
|
||||
if (const_cast<TreeItem*>(this) == *iter)
|
||||
return i;
|
||||
|
@ -95,7 +118,7 @@ int TreeItem::row() const
|
|||
|
||||
TreeItem* TreeItem::child(int row)
|
||||
{
|
||||
std::list<TreeItem*>::iterator child = childItems.begin();
|
||||
auto child = childItems.begin();
|
||||
std::advance(child, row);
|
||||
return *child;
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|||
#ifndef TREEITEM_H
|
||||
#define TREEITEM_H
|
||||
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <iterator>
|
||||
|
||||
#include "basetypes.h"
|
||||
|
@ -25,20 +25,20 @@ class TreeItem
|
|||
{
|
||||
public:
|
||||
TreeItem(const UINT32 offset, const UINT8 type, const UINT8 subtype, const UString &name, const UString &text, const UString &info,
|
||||
const UByteArray & header, const UByteArray & body, const UByteArray & tail,
|
||||
const UINT32 headerSize, const UINT32 bodySize, const UINT32 tailSize,
|
||||
const bool fixed, const bool compressed,
|
||||
TreeItem *parent = 0);
|
||||
~TreeItem(); // Non-trivial implementation in CPP file
|
||||
|
||||
// Operations with items
|
||||
void appendChild(TreeItem *item) { childItems.push_back(item); }
|
||||
void prependChild(TreeItem *item) { childItems.push_front(item); };
|
||||
void prependChild(TreeItem *item) { childItems.insert(childItems.begin(), item); };
|
||||
UINT8 insertChildBefore(TreeItem *item, TreeItem *newItem); // Non-trivial implementation in CPP file
|
||||
UINT8 insertChildAfter(TreeItem *item, TreeItem *newItem); // Non-trivial implementation in CPP file
|
||||
|
||||
// Model support operations
|
||||
TreeItem *child(int row); // Non-trivial implementation in CPP file
|
||||
int childCount() const {return (int)childItems.size(); }
|
||||
int childCount() const { return (int)childItems.size(); }
|
||||
int columnCount() const { return 5; }
|
||||
UString data(int column) const; // Non-trivial implementation in CPP file
|
||||
int row() const; // Non-trivial implementation in CPP file
|
||||
|
@ -60,14 +60,17 @@ public:
|
|||
UString text() const { return itemText; }
|
||||
void setText(const UString &text) { itemText = text; }
|
||||
|
||||
UByteArray header() const { return itemHeader; }
|
||||
bool hasEmptyHeader() const { return itemHeader.isEmpty(); }
|
||||
UByteArray header() const { return UByteArray(content(0), itemHeaderSize); }
|
||||
UINT32 headerSize() const { return itemHeaderSize; }
|
||||
bool hasEmptyHeader() const { return itemHeaderSize == 0; }
|
||||
|
||||
UByteArray body() const { return itemBody; };
|
||||
bool hasEmptyBody() const { return itemBody.isEmpty(); }
|
||||
UByteArray body() const { return UByteArray(content(itemHeaderSize), itemBodySize); }
|
||||
UINT32 bodySize() const { return itemBodySize; }
|
||||
bool hasEmptyBody() const { return itemBodySize == 0; }
|
||||
|
||||
UByteArray tail() const { return itemTail; };
|
||||
bool hasEmptyTail() const { return itemTail.isEmpty(); }
|
||||
UByteArray tail() const { return UByteArray(content(itemHeaderSize + itemBodySize), itemTailSize); }
|
||||
UINT32 tailSize() const { return itemTailSize; }
|
||||
bool hasEmptyTail() const { return itemTailSize == 0; }
|
||||
|
||||
UString info() const { return itemInfo; }
|
||||
void addInfo(const UString &info, const bool append) { if (append) itemInfo += info; else itemInfo = info + itemInfo; }
|
||||
|
@ -79,6 +82,10 @@ public:
|
|||
bool fixed() const { return itemFixed; }
|
||||
void setFixed(const bool fixed) { itemFixed = fixed; }
|
||||
|
||||
bool hasContent() const { return !itemContent.isEmpty(); }
|
||||
void setContent(const UByteArray& c) { itemContent = c; }
|
||||
|
||||
bool compressedInherited() const;
|
||||
bool compressed() const { return itemCompressed; }
|
||||
void setCompressed(const bool compressed) { itemCompressed = compressed; }
|
||||
|
||||
|
@ -94,8 +101,13 @@ public:
|
|||
void setMarking(const UINT8 marking) { itemMarking = marking; }
|
||||
|
||||
private:
|
||||
std::list<TreeItem*> childItems;
|
||||
const char* content(UINT32 dataOffset) const;
|
||||
|
||||
std::vector<TreeItem*> childItems;
|
||||
UINT32 itemOffset;
|
||||
UINT32 itemHeaderSize;
|
||||
UINT32 itemBodySize;
|
||||
UINT32 itemTailSize;
|
||||
UINT8 itemAction;
|
||||
UINT8 itemType;
|
||||
UINT8 itemSubtype;
|
||||
|
@ -103,9 +115,7 @@ private:
|
|||
UString itemName;
|
||||
UString itemText;
|
||||
UString itemInfo;
|
||||
UByteArray itemHeader;
|
||||
UByteArray itemBody;
|
||||
UByteArray itemTail;
|
||||
UByteArray itemContent;
|
||||
bool itemFixed;
|
||||
bool itemCompressed;
|
||||
UByteArray itemParsingData;
|
||||
|
|
|
@ -11,6 +11,12 @@
|
|||
|
||||
*/
|
||||
|
||||
#if defined (QT_GUI_LIB)
|
||||
#include <QtWidgets/QApplication>
|
||||
#include <QIcon>
|
||||
#include <QtWidgets/QStyle>
|
||||
#endif
|
||||
|
||||
#include "treemodel.h"
|
||||
|
||||
#include "stack"
|
||||
|
@ -36,6 +42,16 @@ QVariant TreeModel::data(const UModelIndex &index, int role) const
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (role == Qt::DecorationRole) {
|
||||
if ((item->hasContent() || (item->parent()->hasContent() && item->parent()->type() == Types::Root)) && index.column() == 0) {
|
||||
if (item->compressed())
|
||||
return QApplication::style()->standardIcon(QStyle::SP_MessageBoxWarning);
|
||||
else
|
||||
return QApplication::style()->standardIcon(QStyle::SP_FileDialogContentsView);
|
||||
}
|
||||
else if (item->compressed() && index.column() == 0)
|
||||
return QApplication::style()->standardIcon(QStyle::SP_FileDialogStart);
|
||||
}
|
||||
#endif
|
||||
else if (role == Qt::UserRole) {
|
||||
return item->info().toLocal8Bit();
|
||||
|
@ -214,6 +230,14 @@ UByteArray TreeModel::header(const UModelIndex &index) const
|
|||
return item->header();
|
||||
}
|
||||
|
||||
UINT32 TreeModel::headerSize(const UModelIndex& index) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return 0;
|
||||
TreeItem* item = static_cast<TreeItem*>(index.internalPointer());
|
||||
return item->headerSize();
|
||||
}
|
||||
|
||||
bool TreeModel::hasEmptyHeader(const UModelIndex &index) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
|
@ -230,6 +254,14 @@ UByteArray TreeModel::body(const UModelIndex &index) const
|
|||
return item->body();
|
||||
}
|
||||
|
||||
UINT32 TreeModel::bodySize(const UModelIndex& index) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return 0;
|
||||
TreeItem* item = static_cast<TreeItem*>(index.internalPointer());
|
||||
return item->bodySize();
|
||||
}
|
||||
|
||||
bool TreeModel::hasEmptyBody(const UModelIndex &index) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
|
@ -246,6 +278,14 @@ UByteArray TreeModel::tail(const UModelIndex &index) const
|
|||
return item->tail();
|
||||
}
|
||||
|
||||
UINT32 TreeModel::tailSize(const UModelIndex& index) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return 0;
|
||||
TreeItem* item = static_cast<TreeItem*>(index.internalPointer());
|
||||
return item->tailSize();
|
||||
}
|
||||
|
||||
bool TreeModel::hasEmptyTail(const UModelIndex &index) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
|
@ -299,7 +339,7 @@ bool TreeModel::compressed(const UModelIndex &index) const
|
|||
if (!index.isValid())
|
||||
return false;
|
||||
TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
|
||||
return item->compressed();
|
||||
return item->compressedInherited();
|
||||
}
|
||||
|
||||
void TreeModel::setFixed(const UModelIndex &index, const bool fixed)
|
||||
|
@ -315,7 +355,7 @@ void TreeModel::setFixed(const UModelIndex &index, const bool fixed)
|
|||
|
||||
if (fixed) {
|
||||
// Special handling for uncompressed to compressed boundary
|
||||
if (item->compressed() && item->parent()->compressed() == FALSE) {
|
||||
if (item->compressedInherited() && item->parent()->compressedInherited() == FALSE) {
|
||||
item->setFixed(item->parent()->fixed());
|
||||
return;
|
||||
}
|
||||
|
@ -352,6 +392,14 @@ void TreeModel::TreeModel::setMarkingDarkMode(const bool enabled)
|
|||
emit dataChanged(UModelIndex(), UModelIndex());
|
||||
}
|
||||
|
||||
void TreeModel::TreeModel::setCStyleHexEnabled(const bool enabled)
|
||||
{
|
||||
cStyleHexEnabledFlag = enabled;
|
||||
setCStyleHexView(enabled);
|
||||
|
||||
emit dataChanged(UModelIndex(), UModelIndex());
|
||||
}
|
||||
|
||||
void TreeModel::setMarking(const UModelIndex &index, const UINT8 marking)
|
||||
{
|
||||
if (!index.isValid())
|
||||
|
@ -501,7 +549,7 @@ void TreeModel::setUncompressedData(const UModelIndex &index, const UByteArray &
|
|||
|
||||
UModelIndex TreeModel::addItem(const UINT32 offset, const UINT8 type, const UINT8 subtype,
|
||||
const UString & name, const UString & text, const UString & info,
|
||||
const UByteArray & header, const UByteArray & body, const UByteArray & tail,
|
||||
const UINT32 headerSize, const UINT32 bodySize, const UINT32 tailSize,
|
||||
const ItemFixedState fixed,
|
||||
const UModelIndex & parent, const UINT8 mode)
|
||||
{
|
||||
|
@ -524,8 +572,8 @@ UModelIndex TreeModel::addItem(const UINT32 offset, const UINT8 type, const UINT
|
|||
}
|
||||
}
|
||||
|
||||
TreeItem *newItem = new TreeItem(offset, type, subtype, name, text, info, header, body, tail, Movable, this->compressed(parent), parentItem);
|
||||
|
||||
TreeItem* newItem = new TreeItem(offset, type, subtype, name, text, info, headerSize, bodySize, tailSize, Movable, false, parentItem);
|
||||
|
||||
if (mode == CREATE_MODE_APPEND) {
|
||||
emit layoutAboutToBeChanged();
|
||||
parentItem->appendChild(newItem);
|
||||
|
@ -551,6 +599,7 @@ UModelIndex TreeModel::addItem(const UINT32 offset, const UINT8 type, const UINT
|
|||
|
||||
UModelIndex created = createIndex(newItem->row(), parentColumn, newItem);
|
||||
setFixed(created, (bool)fixed); // Non-trivial logic requires additional call
|
||||
|
||||
return created;
|
||||
}
|
||||
|
||||
|
@ -601,7 +650,7 @@ goDeeper:
|
|||
UModelIndex currentIndex = parentIndex.model()->index(i, 0, parentIndex);
|
||||
|
||||
UINT32 currentBase = this->base(currentIndex);
|
||||
UINT32 fullSize = (UINT32)(header(currentIndex).size() + body(currentIndex).size() + tail(currentIndex).size());
|
||||
UINT32 fullSize = (UINT32)(headerSize(currentIndex) + bodySize(currentIndex) + tailSize(currentIndex));
|
||||
if ((compressed(currentIndex) == false || (compressed(currentIndex) == true && compressed(currentIndex.parent()) == false)) // Base is meaningful only for true uncompressed items
|
||||
&& currentBase <= base && base < currentBase + fullSize) { // Base must be in range [currentBase, currentBase + fullSize)
|
||||
// Found a better candidate
|
||||
|
|
|
@ -97,14 +97,15 @@ private:
|
|||
TreeItem *rootItem;
|
||||
bool markingEnabledFlag;
|
||||
bool markingDarkModeFlag;
|
||||
bool cStyleHexEnabledFlag;
|
||||
|
||||
public:
|
||||
QVariant data(const UModelIndex &index, int role) const;
|
||||
Qt::ItemFlags flags(const UModelIndex &index) const;
|
||||
QVariant headerData(int section, Qt::Orientation orientation,
|
||||
int role = Qt::DisplayRole) const;
|
||||
TreeModel(QObject *parent = 0) : QAbstractItemModel(parent), markingEnabledFlag(true), markingDarkModeFlag(false) {
|
||||
rootItem = new TreeItem(0, Types::Root, 0, UString(), UString(), UString(), UByteArray(), UByteArray(), UByteArray(), true, false);
|
||||
TreeModel(QObject *parent = 0) : QAbstractItemModel(parent), markingEnabledFlag(true), markingDarkModeFlag(false), cStyleHexEnabledFlag (true) {
|
||||
rootItem = new TreeItem(0, Types::Root, 0, UString(), UString(), UString(), 0, 0, 0, true, false);
|
||||
}
|
||||
|
||||
#else
|
||||
|
@ -116,6 +117,7 @@ private:
|
|||
TreeItem *rootItem;
|
||||
bool markingEnabledFlag;
|
||||
bool markingDarkModeFlag;
|
||||
bool cStyleHexEnabledFlag;
|
||||
|
||||
void dataChanged(const UModelIndex &, const UModelIndex &) {}
|
||||
void layoutAboutToBeChanged() {}
|
||||
|
@ -126,7 +128,7 @@ public:
|
|||
UString headerData(int section, int orientation, int role = 0) const;
|
||||
|
||||
TreeModel() : markingEnabledFlag(false), markingDarkModeFlag(false) {
|
||||
rootItem = new TreeItem(0, Types::Root, 0, UString(), UString(), UString(), UByteArray(), UByteArray(), UByteArray(), true, false);
|
||||
rootItem = new TreeItem(0, Types::Root, 0, UString(), UString(), UString(), 0, 0, 0, true, false);
|
||||
}
|
||||
|
||||
bool hasIndex(int row, int column, const UModelIndex &parent = UModelIndex()) const {
|
||||
|
@ -142,12 +144,17 @@ public:
|
|||
delete rootItem;
|
||||
}
|
||||
|
||||
void setImage(const UByteArray& image) { rootItem->setContent(image); }
|
||||
|
||||
bool markingEnabled() { return markingEnabledFlag; }
|
||||
void setMarkingEnabled(const bool enabled);
|
||||
|
||||
bool markingDarkMode() { return markingDarkModeFlag; }
|
||||
void setMarkingDarkMode(const bool enabled);
|
||||
|
||||
bool cStyleHexEnabled() { return cStyleHexEnabledFlag; }
|
||||
void setCStyleHexEnabled(const bool enabled);
|
||||
|
||||
UModelIndex index(int row, int column, const UModelIndex &parent = UModelIndex()) const;
|
||||
UModelIndex parent(const UModelIndex &index) const;
|
||||
int rowCount(const UModelIndex &parent = UModelIndex()) const;
|
||||
|
@ -190,12 +197,15 @@ public:
|
|||
void setMarking(const UModelIndex &index, const UINT8 marking);
|
||||
|
||||
UByteArray header(const UModelIndex &index) const;
|
||||
UINT32 headerSize(const UModelIndex& index) const;
|
||||
bool hasEmptyHeader(const UModelIndex &index) const;
|
||||
|
||||
UByteArray body(const UModelIndex &index) const;
|
||||
UINT32 bodySize(const UModelIndex& index) const;
|
||||
bool hasEmptyBody(const UModelIndex &index) const;
|
||||
|
||||
UByteArray tail(const UModelIndex &index) const;
|
||||
UINT32 tailSize(const UModelIndex& index) const;
|
||||
bool hasEmptyTail(const UModelIndex &index) const;
|
||||
|
||||
UByteArray parsingData(const UModelIndex &index) const;
|
||||
|
@ -204,7 +214,7 @@ public:
|
|||
|
||||
UModelIndex addItem(const UINT32 offset, const UINT8 type, const UINT8 subtype,
|
||||
const UString & name, const UString & text, const UString & info,
|
||||
const UByteArray & header, const UByteArray & body, const UByteArray & tail,
|
||||
const UINT32 headerSize, const UINT32 bodySize, const UINT32 tailSize,
|
||||
const ItemFixedState fixed,
|
||||
const UModelIndex & parent = UModelIndex(), const UINT8 mode = CREATE_MODE_APPEND);
|
||||
|
||||
|
|
|
@ -116,6 +116,7 @@ namespace Subtypes {
|
|||
Reserved1Region,
|
||||
Reserved2Region,
|
||||
PttRegion,
|
||||
InvalidRegion,
|
||||
};
|
||||
|
||||
enum PaddingSubtypes {
|
||||
|
|
|
@ -46,7 +46,6 @@ public:
|
|||
uint32_t toUInt(bool* ok = NULL, const uint8_t base = 10) { return (uint32_t)strtoul(d.c_str(), NULL, base); }
|
||||
|
||||
int32_t size() const { return (int32_t)d.size(); }
|
||||
int32_t count(char ch) const { return (int32_t)std::count(d.begin(), d.end(), ch); }
|
||||
char at(uint32_t i) const { return d.at(i); }
|
||||
char operator[](uint32_t i) const { return d[i]; }
|
||||
char& operator[](uint32_t i) { return d[i]; }
|
||||
|
|
|
@ -14,19 +14,42 @@
|
|||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <stdarg.h>
|
||||
#include "printf/printf.c"
|
||||
|
||||
static bool cStyleHexEnabled = false;
|
||||
|
||||
void putchar_(char c) {}
|
||||
|
||||
void setCStyleHexView(const bool enable)
|
||||
{
|
||||
cStyleHexEnabled = enable;
|
||||
}
|
||||
|
||||
#if defined(QT_CORE_LIB)
|
||||
|
||||
typedef struct {
|
||||
char flag_cstyle_Xh;
|
||||
UString* string;
|
||||
} qstring_opt_t;
|
||||
|
||||
void qstring_out(char c, void* extra_arg)
|
||||
{
|
||||
((qstring_opt_t*)extra_arg)->string->append(c);
|
||||
}
|
||||
|
||||
UString usprintf(const char* fmt, ...)
|
||||
{
|
||||
UString msg;
|
||||
qstring_opt_t opt = { cStyleHexEnabled ? '\1' : '\0', &msg };
|
||||
|
||||
va_list vl;
|
||||
va_start(vl, fmt);
|
||||
|
||||
msg = msg.vasprintf(fmt, vl);
|
||||
|
||||
|
||||
int n = vofctprintf(qstring_out, &opt, fmt, vl);
|
||||
|
||||
va_end(vl);
|
||||
return msg;
|
||||
};
|
||||
}
|
||||
|
||||
UString urepeated(char c, int len)
|
||||
{
|
||||
|
@ -84,7 +107,8 @@ UString usprintf(const char* fmt, ...)
|
|||
}
|
||||
|
||||
va_start(arglist, fmt);
|
||||
exvsnprintf(r, (char *)b->data, n + 1, fmt, arglist);
|
||||
*(char*)b->data = cStyleHexEnabled ? '\1' : '\0';
|
||||
r = vosnprintf_((char*)b->data, n + 1, fmt, arglist);
|
||||
va_end(arglist);
|
||||
|
||||
b->data[n] = '\0';
|
||||
|
|
|
@ -31,6 +31,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|||
#define ATTRIBUTE_FORMAT_(t,f,a)
|
||||
#endif
|
||||
|
||||
void setCStyleHexView(const bool enable);
|
||||
UString usprintf(const char* fmt, ...) ATTRIBUTE_FORMAT_(printf, 1, 2);
|
||||
UString urepeated(char c, int len);
|
||||
UString uFromUcs2(const char* str, size_t max_len = 0);
|
||||
|
|
|
@ -429,16 +429,6 @@ UINT32 calculateChecksum32(const UINT32* buffer, UINT32 bufferSize)
|
|||
return (UINT32)(0x100000000ULL - counter);
|
||||
}
|
||||
|
||||
// Get padding type for a given padding
|
||||
UINT8 getPaddingType(const UByteArray & padding)
|
||||
{
|
||||
if (padding.count('\x00') == padding.size())
|
||||
return Subtypes::ZeroPadding;
|
||||
if (padding.count('\xFF') == padding.size())
|
||||
return Subtypes::OnePadding;
|
||||
return Subtypes::DataPadding;
|
||||
}
|
||||
|
||||
static inline int char2hex(char c)
|
||||
{
|
||||
if (c >= '0' && c <= '9')
|
||||
|
|
|
@ -59,8 +59,33 @@ UINT16 calculateChecksum16(const UINT16* buffer, UINT32 bufferSize);
|
|||
// 32bit checksum calculation routine
|
||||
UINT32 calculateChecksum32(const UINT32* buffer, UINT32 bufferSize);
|
||||
|
||||
// Return padding type from it's contents
|
||||
UINT8 getPaddingType(const UByteArray & padding);
|
||||
// Check if an array is filled in by a single repeated char
|
||||
inline signed long checkSingle(const UByteArray& a, signed long defaultRc = -1)
|
||||
{
|
||||
size_t s = a.size();
|
||||
if (!s)
|
||||
return defaultRc;
|
||||
if (s == 1 || memcmp(a.constData(), a.constData() + 1, s - 1) == 0)
|
||||
return (unsigned char)a.at(0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Get padding type for a given padding
|
||||
inline UINT8 getPaddingType(const UByteArray& a)
|
||||
{
|
||||
size_t s = a.size();
|
||||
if (s) {
|
||||
if (s == 1 || memcmp(a.constData(), a.constData() + 1, s - 1) == 0) {
|
||||
switch (a.at(0)) {
|
||||
case 0:
|
||||
return Subtypes::ZeroPadding;
|
||||
case 0xFF:
|
||||
return Subtypes::OnePadding;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Subtypes::DataPadding;
|
||||
}
|
||||
|
||||
// Make pattern from a hexstring with an assumption of . being any char
|
||||
bool makePattern(const CHAR8 *textPattern, std::vector<UINT8> &pattern, std::vector<UINT8> &patternMask);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue