-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
aekhv
committed
Dec 20, 2024
1 parent
5c92509
commit ca980ad
Showing
23 changed files
with
1,727 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,34 @@ | ||
# ace-database-viewer | ||
ACE Lab PC-3000 database viewer and extractor | ||
# Ace Database Viewer | ||
This tiny app allows to view and unpack ACE Lab PC-3000 database files (*.pcr & *.fdb). | ||
|
||
![](/img/screenshot.png) | ||
*** | ||
|
||
# Download | ||
See latest release [here](https://github.com/aekhv/ace-database-viewer/releases). | ||
*** | ||
|
||
# Discuss and bug report | ||
[https://forum.hddguru.com/viewtopic.php?f=7&t=44656](https://forum.hddguru.com/viewtopic.php?f=7&t=44656) | ||
*** | ||
|
||
# How to build | ||
I wish I could say all you need is Qt and Firebird library... But it's not true, he-he... Unfortunately ACE Lab (R) uses too old Firebird 2.x engine for their database and this engine is 32-bit only. This means Firebird library must be 32-bit too. And this also means your Qt application also must be 32-bit. And this also means you have to use old 32-bit MinGW available in Qt5 only. Yes, you can forget about Qt6. I recommend Qt 5.15.2 + MinGW 8.1 32-bit. | ||
|
||
## Requirements | ||
1. Last available Qt5 + MinGW 32-bit. Don't forget about Qt sources, you'll need them too. | ||
2. Firebird 2.x sources, for example from [there](https://www.firebirdsql.org/en/firebird-2-5-4/#Win32). All you need is `Firebird-2.5.4.26856_0_Win32.exe`, just install it with default options. | ||
3. QHexEdit2 widget from [there](https://github.com/simsys/qhexedit2). | ||
|
||
## Adding Firebird support to Qt | ||
To add Firebird (IBASE) support to Qt use `make-qt-ibase.cmd` command file. Do not forget to run this file from MinGW 32-bit environment. | ||
|
||
## QHexEdit2 widget compilation | ||
To compile QHexEdit2 widget type following commands from MinGW 32-bit environment: | ||
``` | ||
qmake qhexedit.pro | ||
mingw32-make | ||
``` | ||
|
||
## Known troubleshooting | ||
If you see error message - "driver not loaded" - try to copy `fbclient.dll` from the Firebird binaries to the folder of your application. |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
@echo off | ||
rem *** Run this script from MinGW 32-bit environment! *** | ||
|
||
set fb_bin=c:\Program Files (x86)\Firebird\Firebird_2_5\bin | ||
set fb_include=c:\Program Files (x86)\Firebird\Firebird_2_5\include | ||
set fb_lib=c:\Program Files (x86)\Firebird\Firebird_2_5\lib\fbclient_ms.lib | ||
set sql=c:\Qt\5.15.2\Src\qtbase\src\plugins\sqldrivers | ||
|
||
for %%A in ("%fb_include%") do set fb_include=%%~sA | ||
for %%A in ("%fb_lib%") do set fb_lib=%%~sA | ||
set PATH=%PATH%;%fb_bin% | ||
cd /d %sql% | ||
|
||
qmake -- IBASE_INCDIR="%fb_include%" IBASE_LIBS="%fb_lib%" | ||
mingw32-make sub-ibase | ||
mingw32-make install |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,175 @@ | ||
/**************************************************************************** | ||
** | ||
** This file is part of the Ace Database Viewer project. | ||
** Copyright (C) 2024 Alexander E. <[email protected]> | ||
** License: GNU GPL v2, see file LICENSE. | ||
** | ||
****************************************************************************/ | ||
|
||
#include "DataViewDialog.h" | ||
#include "ui_DataViewDialog.h" | ||
#include <QFileIconProvider> | ||
#include <QMenuBar> | ||
#include <QClipboard> | ||
#include <QFileDialog> | ||
#include <QMessageBox> | ||
|
||
DataViewDialog::DataViewDialog(const QString &fname, | ||
bool plainText, | ||
const QByteArray &rawData, | ||
const QByteArray &rawProfile, | ||
QWidget *parent) | ||
: QDialog(parent), | ||
ui(new Ui::DataViewDialog), | ||
m_fname(fname), | ||
m_rawData(rawData) | ||
{ | ||
ui->setupUi(this); | ||
|
||
// Remove "?" button from window title | ||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); | ||
|
||
// Window title | ||
setWindowTitle("File Viewer: " + m_fname); | ||
|
||
// Window icon | ||
QFileInfo fileInfo(m_fname); | ||
QFileIconProvider iconProvider; | ||
setWindowIcon(iconProvider.icon(fileInfo)); | ||
|
||
// Buttons | ||
connect(ui->exportButton, &QPushButton::clicked, this, &DataViewDialog::exportToFile); | ||
connect(ui->closeButton, &QPushButton::clicked, this, &QDialog::accept); | ||
|
||
// Monospace font definition | ||
QFont mainFont = QApplication::font(); | ||
QFont monoFont = QFont("Courier", mainFont.pointSize()); | ||
|
||
// HEX viewer widget | ||
m_hexEdit = new QHexEdit; | ||
m_hexEdit->setReadOnly(true); | ||
m_hexEdit->setFont(monoFont); | ||
|
||
// Hex viewer layout | ||
QVBoxLayout *vHexLayout = new QVBoxLayout; | ||
ui->hexPage->setLayout(vHexLayout); | ||
vHexLayout->setMargin(0); | ||
vHexLayout->addWidget(m_hexEdit); | ||
|
||
// Text viewer | ||
m_textEdit = new QPlainTextEdit; | ||
m_textEdit->setReadOnly(true); | ||
m_textEdit->setFont(monoFont); | ||
m_textEdit->setWordWrapMode(QTextOption::NoWrap); | ||
|
||
// Text viewer layout | ||
QVBoxLayout *vTextLayout = new QVBoxLayout; | ||
ui->textPage->setLayout(vTextLayout); | ||
vTextLayout->setMargin(0); | ||
vTextLayout->addWidget(m_textEdit); | ||
|
||
// Data type selection | ||
if (plainText) { | ||
QTextStream ts(m_rawData); // This trick also detects encoding | ||
m_textEdit->appendPlainText(ts.readAll()); | ||
m_textEdit->moveCursor(QTextCursor::Start); | ||
ui->stackedWidget->setCurrentWidget(ui->textPage); | ||
} else { | ||
m_hexEdit->setData(m_rawData); | ||
ui->stackedWidget->setCurrentWidget(ui->hexPage); | ||
} | ||
|
||
// Profile model | ||
m_profileModel = new ProfileModel(rawProfile, this); | ||
ui->profileView->setModel(m_profileModel); | ||
ui->profileView->setWordWrap(false); | ||
ui->profileView->horizontalHeader()->setStretchLastSection(true); | ||
ui->profileView->verticalHeader()->setDefaultSectionSize( | ||
ui->profileView->verticalHeader()->fontMetrics().height()); | ||
ui->profileView->verticalHeader()->setSectionResizeMode(QHeaderView::Fixed); | ||
|
||
// Resize first column for better view | ||
const int w = ui->profileView->horizontalHeader()->width(); | ||
ui->profileView->horizontalHeader()->resizeSection(0, w * 40 / 100); | ||
|
||
// Context menu | ||
QAction *m_copyAction = new QAction("Copy as text"); | ||
connect(m_copyAction, &QAction::triggered, this, &DataViewDialog::copyAsText); | ||
QAction *m_copyAllAction = new QAction("Copy all as text"); | ||
connect(m_copyAllAction, &QAction::triggered, this, &DataViewDialog::copyAllAsText); | ||
m_contextMenu = new QMenu(this); | ||
m_contextMenu->addAction(m_copyAction); | ||
m_contextMenu->addAction(m_copyAllAction); | ||
ui->profileView->setContextMenuPolicy(Qt::CustomContextMenu); | ||
connect(ui->profileView, &QTableView::customContextMenuRequested, this, &DataViewDialog::contextMenuRequested); | ||
|
||
// Default tab | ||
ui->tabWidget->setCurrentWidget(ui->dataTab); | ||
} | ||
|
||
DataViewDialog::~DataViewDialog() | ||
{ | ||
delete ui; | ||
} | ||
|
||
void DataViewDialog::contextMenuRequested(QPoint pos) | ||
{ | ||
QModelIndex index = ui->profileView->indexAt(pos); | ||
|
||
if (!index.isValid()) | ||
return; | ||
|
||
m_contextMenu->popup(ui->profileView->viewport()->mapToGlobal(pos)); | ||
} | ||
|
||
void DataViewDialog::copyAsText() | ||
{ | ||
QModelIndex index = ui->profileView->selectionModel()->currentIndex(); | ||
|
||
if (!index.isValid()) | ||
return; | ||
|
||
QClipboard *clipboard = QGuiApplication::clipboard(); | ||
clipboard->setText(index.data().toString()); | ||
} | ||
|
||
void DataViewDialog::copyAllAsText() | ||
{ | ||
QModelIndex index = ui->profileView->selectionModel()->currentIndex(); | ||
|
||
if (!index.isValid()) | ||
return; | ||
|
||
QStringList list; | ||
for (int row = 0; row < m_profileModel->rowCount(QModelIndex()); row++) { | ||
QModelIndex param = m_profileModel->index(row, 0); | ||
QModelIndex value = m_profileModel->index(row, 1); | ||
QString line = QString("%1: %2") | ||
.arg(param.data().toString()) | ||
.arg(value.data().toString()); | ||
list.append(line); | ||
} | ||
|
||
QClipboard *clipboard = QGuiApplication::clipboard(); | ||
clipboard->setText(list.join(QChar::LineFeed)); | ||
} | ||
|
||
void DataViewDialog::exportToFile() | ||
{ | ||
const QStringList docs = QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation); | ||
const QString path = QFileDialog::getSaveFileName(this, | ||
"Export", | ||
docs.first() + QDir::separator() + m_fname); | ||
if (path.isEmpty()) | ||
return; | ||
|
||
QFile f(path); | ||
|
||
if(!f.open(QIODevice::WriteOnly)) { | ||
QMessageBox::critical(this, "Error", "File creation error!"); | ||
return; | ||
} | ||
|
||
f.write(m_rawData); | ||
f.close(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
/**************************************************************************** | ||
** | ||
** This file is part of the Ace Database Viewer project. | ||
** Copyright (C) 2024 Alexander E. <[email protected]> | ||
** License: GNU GPL v2, see file LICENSE. | ||
** | ||
****************************************************************************/ | ||
|
||
#ifndef DATAVIEWDIALOG_H | ||
#define DATAVIEWDIALOG_H | ||
|
||
#include <QDialog> | ||
#include "qhexedit.h" | ||
#include "ProfileModel/ProfileModel.h" | ||
#include <QPlainTextEdit> | ||
#include <QMenu> | ||
|
||
namespace Ui { | ||
class DataViewDialog; | ||
} | ||
|
||
class DataViewDialog : public QDialog | ||
{ | ||
Q_OBJECT | ||
|
||
public: | ||
explicit DataViewDialog(const QString &fname, | ||
bool plainText, | ||
const QByteArray &rawData, | ||
const QByteArray &rawProfile, | ||
QWidget *parent = nullptr); | ||
~DataViewDialog(); | ||
|
||
private: | ||
Ui::DataViewDialog *ui; | ||
QHexEdit *m_hexEdit; | ||
QPlainTextEdit *m_textEdit; | ||
ProfileModel *m_profileModel; | ||
QMenu *m_contextMenu; | ||
|
||
QString m_fname; | ||
QByteArray m_rawData; | ||
|
||
private slots: | ||
void contextMenuRequested(QPoint pos); | ||
void copyAsText(); | ||
void copyAllAsText(); | ||
void exportToFile(); | ||
}; | ||
|
||
#endif // DATAVIEWDIALOG_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<ui version="4.0"> | ||
<class>DataViewDialog</class> | ||
<widget class="QDialog" name="DataViewDialog"> | ||
<property name="geometry"> | ||
<rect> | ||
<x>0</x> | ||
<y>0</y> | ||
<width>650</width> | ||
<height>450</height> | ||
</rect> | ||
</property> | ||
<property name="windowTitle"> | ||
<string>Dialog</string> | ||
</property> | ||
<layout class="QVBoxLayout" name="verticalLayout"> | ||
<item> | ||
<widget class="QTabWidget" name="tabWidget"> | ||
<property name="currentIndex"> | ||
<number>1</number> | ||
</property> | ||
<widget class="QWidget" name="dataTab"> | ||
<attribute name="title"> | ||
<string>Data</string> | ||
</attribute> | ||
<layout class="QVBoxLayout" name="verticalLayout_2"> | ||
<item> | ||
<widget class="QStackedWidget" name="stackedWidget"> | ||
<widget class="QWidget" name="hexPage"/> | ||
<widget class="QWidget" name="textPage"/> | ||
</widget> | ||
</item> | ||
</layout> | ||
</widget> | ||
<widget class="QWidget" name="profileTab"> | ||
<attribute name="title"> | ||
<string>Profile</string> | ||
</attribute> | ||
<layout class="QVBoxLayout" name="verticalLayout_3"> | ||
<item> | ||
<widget class="QTableView" name="profileView"/> | ||
</item> | ||
</layout> | ||
</widget> | ||
</widget> | ||
</item> | ||
<item> | ||
<layout class="QHBoxLayout" name="horizontalLayout"> | ||
<item> | ||
<widget class="QPushButton" name="exportButton"> | ||
<property name="text"> | ||
<string>Export</string> | ||
</property> | ||
</widget> | ||
</item> | ||
<item> | ||
<spacer name="horizontalSpacer"> | ||
<property name="orientation"> | ||
<enum>Qt::Horizontal</enum> | ||
</property> | ||
<property name="sizeHint" stdset="0"> | ||
<size> | ||
<width>40</width> | ||
<height>20</height> | ||
</size> | ||
</property> | ||
</spacer> | ||
</item> | ||
<item> | ||
<widget class="QPushButton" name="closeButton"> | ||
<property name="text"> | ||
<string>Close</string> | ||
</property> | ||
</widget> | ||
</item> | ||
</layout> | ||
</item> | ||
</layout> | ||
</widget> | ||
<resources/> | ||
<connections/> | ||
</ui> |
Oops, something went wrong.