Page MenuHomePhabricator

No OneTemporary

Size
113 KB
Referenced Files
None
Subscribers
None
diff --git a/trunk/compileinfo.sh b/trunk/compileinfo.sh
index 54e37f5..35997a9 100755
--- a/trunk/compileinfo.sh
+++ b/trunk/compileinfo.sh
@@ -1,45 +1,45 @@
#!/bin/bash
PWD=""
if [ $# -eq 1 ]; then
PWD="$1"
PWD="${PWD%/}/"
fi
echo '// Automatically generated file. See project file and compileinfo.sh for further informations.'
#head -n 1 debian/changelog | awk '{
# Version = $2
# gsub ("\\(", "", Version)
# gsub ("\\)", "", Version)
# print "const char *pCompileInfoVersion = \"" Version "\";"}'
echo '#define APP_NAME "fred"'
echo '#define APP_TITLE "Forensic Registry EDitor (fred)"'
-echo '#define APP_COPYRIGHT "Copyright (c) 2011 by Gillen Daniel"'
+echo '#define APP_COPYRIGHT "Copyright (c) 2011-2012 by Gillen Daniel"'
echo '#define APP_DEVELOPPER_EMAIL "gillen.dan@pinguin.lu"'
echo '#define APP_DESCRIPTION "Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor with special feautures useful during forensic analysis."'
date '+#define APP_COMPILETIME "%Y/%m/%d %H:%M:%S"'
GOT_VERSION=0
if [[ $GOT_VERSION -eq 0 && -f "$PWD"debian/changelog ]]; then
# Get version and release timestamp from debian/changelog file
CUR_LINE=0
while read LINE; do
CUR_LINE=$(($CUR_LINE+1))
if [ $CUR_LINE -eq 1 ]; then
# first line contains version
echo "$LINE" | awk '{ Version = $2
gsub ("\\(", "", Version)
gsub ("\\)", "", Version)
print "#define APP_VERSION \"" Version "\"" }'
break
fi
done <"$PWD"debian/changelog
GOT_VERSION=1
fi
if [ $GOT_VERSION -eq 0 ]; then
echo '#define APP_VERSION "0.0.0alpha0"'
fi
diff --git a/trunk/datareporterengine.cpp b/trunk/datareporterengine.cpp
index 3321ad2..1b8b938 100644
--- a/trunk/datareporterengine.cpp
+++ b/trunk/datareporterengine.cpp
@@ -1,323 +1,325 @@
/*******************************************************************************
* fred Copyright (c) 2011 by Gillen Daniel <gillen.dan@pinguin.lu> *
* *
* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
* with special feautures useful during forensic analysis. *
* *
* This program is free software: you can redistribute it and/or modify it *
* under the terms of the GNU General Public License as published by the Free *
* Software Foundation, either version 3 of the License, or (at your option) *
* any later version. *
* *
* This program is distributed in the hope that it will be useful, but WITHOUT *
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
* more details. *
* *
* You should have received a copy of the GNU General Public License along with *
* this program. If not, see <http://www.gnu.org/licenses/>. *
*******************************************************************************/
#include "datareporterengine.h"
#include <QString>
#include <QMap>
#include <QMapIterator>
#include <QStringList>
-#include <QDateTime>
+
+#include <stdio.h>
DataReporterEngine::DataReporterEngine(RegistryHive *p_hive) : QScriptEngine() {
// Init vars
this->p_registry_hive=p_hive;
this->report_content="";
// Add our types to engine
qScriptRegisterMetaType<s_RegistryKeyValue>(this,
this->RegistryKeyValueToScript,
this->RegistryKeyValueFromScript);
this->p_type_byte_array=new ByteArray(this);
this->globalObject().setProperty("ByteArray",
this->p_type_byte_array->constructor());
// Add our functions
// print
QScriptValue func_print=this->newFunction(this->Print);
this->globalObject().setProperty("print",func_print);
// println
QScriptValue func_println=this->newFunction(this->PrintLn);
this->globalObject().setProperty("println",func_println);
// GetRegistryNodes
QScriptValue func_get_nodes=this->newFunction(this->GetRegistryNodes,1);
func_get_nodes.setData(this->newQObject(this->p_registry_hive));
this->globalObject().setProperty("GetRegistryNodes",func_get_nodes);
// GetRegistryKeys
QScriptValue func_get_keys=this->newFunction(this->GetRegistryKeys,1);
func_get_keys.setData(this->newQObject(this->p_registry_hive));
this->globalObject().setProperty("GetRegistryKeys",func_get_keys);
// GetRegistryKeyValue
QScriptValue func_get_key_value=this->newFunction(this->GetRegistryKeyValue,
2);
func_get_key_value.setData(this->newQObject(this->p_registry_hive));
this->globalObject().setProperty("GetRegistryKeyValue",func_get_key_value);
// RegistryKeyValueToString
QScriptValue func_value_to_string=
this->newFunction(this->RegistryKeyValueToString,2);
this->globalObject().setProperty("RegistryKeyValueToString",
func_value_to_string);
// RegistryKeyValueToVariant
QScriptValue func_value_to_variant=
this->newFunction(this->RegistryKeyValueToVariant);
this->globalObject().setProperty("RegistryKeyValueToVariant",
func_value_to_variant);
// RegistryKeyTypeToString
QScriptValue func_type_to_string=
this->newFunction(this->RegistryKeyTypeToString,1);
this->globalObject().setProperty("RegistryKeyTypeToString",
func_type_to_string);
}
DataReporterEngine::~DataReporterEngine() {
delete this->p_type_byte_array;
}
QScriptValue DataReporterEngine::Print(QScriptContext *context,
QScriptEngine *engine)
{
int i;
QString content;
// Append all arguments to content
for(i=0;i<context->argumentCount();++i) {
//if(i>0) content.append(" ");
content.append(context->argument(i).toString());
}
//QScriptValue calleeData=context->callee().data();
//DataReporterEngine *engine=
// qobject_cast<DataReporterEngine*>(calleeData.toQObject());
qobject_cast<DataReporterEngine*>(engine)->report_content.append(content);
return engine->undefinedValue();
}
QScriptValue DataReporterEngine::PrintLn(QScriptContext *context,
QScriptEngine *engine)
{
int i;
QString content;
// Append all arguments to content
for(i=0;i<context->argumentCount();++i) {
//if(i>0) content.append(" ");
content.append(context->argument(i).toString());
}
qobject_cast<DataReporterEngine*>(engine)->
report_content.append(content).append("\n");
return engine->undefinedValue();
}
/*
* GetRegistryNodes
*/
QScriptValue DataReporterEngine::GetRegistryNodes(QScriptContext *context,
QScriptEngine *engine)
{
QScriptValue calleeData;
RegistryHive *p_hive;
QMap<QString,int> nodes;
QScriptValue ret_nodes;
int ii=0;
// This function needs one argument, parent node path
if(context->argumentCount()!=1) return engine->undefinedValue();
// Get calle data (Pointer to RegistryHive class)
calleeData=context->callee().data();
p_hive=qobject_cast<RegistryHive*>(calleeData.toQObject());
// Get nodes
nodes=p_hive->GetNodes(context->argument(0).toString());
if(p_hive->Error()) {
// Clear error state
p_hive->GetErrorMsg();
return engine->undefinedValue();
}
// Build script array
ret_nodes=engine->newArray(nodes.count());
QMapIterator<QString,int> i(nodes);
while(i.hasNext()) {
i.next();
ret_nodes.setProperty(ii++,QScriptValue(i.key()));
}
return ret_nodes;
}
/*
* GetRegistryKeys
*/
QScriptValue DataReporterEngine::GetRegistryKeys(QScriptContext *context,
QScriptEngine *engine)
{
QScriptValue calleeData;
RegistryHive *p_hive;
QMap<QString,int> keys;
QScriptValue ret_keys;
int ii=0;
// This function needs one argument, parent node path
if(context->argumentCount()!=1) return engine->undefinedValue();
// Get calle data (Pointer to RegistryHive class)
calleeData=context->callee().data();
p_hive=qobject_cast<RegistryHive*>(calleeData.toQObject());
// Get keys
keys=p_hive->GetKeys(context->argument(0).toString());
if(p_hive->Error()) {
// Clear error state
p_hive->GetErrorMsg();
return engine->undefinedValue();
}
// Build script array
ret_keys=engine->newArray(keys.count());
QMapIterator<QString,int> i(keys);
while(i.hasNext()) {
i.next();
ret_keys.setProperty(ii++,QScriptValue(i.key()));
}
return ret_keys;
}
/*
* RegistryKeyValueToScript
*/
QScriptValue DataReporterEngine::RegistryKeyValueToScript(QScriptEngine *engine,
const
s_RegistryKeyValue
&s)
{
QScriptValue obj=engine->newObject();
obj.setProperty("type",s.type);
obj.setProperty("length",s.length);
ByteArray *p_byte_array=new ByteArray(engine);
obj.setProperty("value",p_byte_array->newInstance(s.value));
return obj;
}
/*
* RegistryKeyValueFromScriptValue
*/
void DataReporterEngine::RegistryKeyValueFromScript(const QScriptValue &obj,
s_RegistryKeyValue &s)
{
s.type=obj.property("type").toInt32();
s.length=obj.property("length").toInt32();
// TODO: Don't know if this works, but it probably does ;)
s.value=qvariant_cast<QByteArray>(obj.property("value").data().toVariant());
}
QScriptValue DataReporterEngine::GetRegistryKeyValue(QScriptContext *context,
QScriptEngine *engine)
{
QScriptValue calleeData;
RegistryHive *p_hive;
QByteArray key_value;
int key_type=0;
size_t key_length=0;
s_RegistryKeyValue script_key_value;
// This function needs two arguments, key path and key name
if(context->argumentCount()!=2) return engine->undefinedValue();
// Get calle data (Pointer to RegistryHive class)
calleeData=context->callee().data();
p_hive=qobject_cast<RegistryHive*>(calleeData.toQObject());
// Get key value
key_value=p_hive->GetKeyValue(context->argument(0).toString(),
context->argument(1).toString(),
&key_type,
&key_length);
if(p_hive->Error()) {
// Get error message to clear error state
p_hive->GetErrorMsg();
+// printf("\nError: %s\n",p_hive->GetErrorMsg().toAscii().constData());
return engine->undefinedValue();
}
// Save key value to s_RegistryKeyValue struct
script_key_value.type=key_type;
script_key_value.length=key_length;
script_key_value.value=key_value;
return DataReporterEngine::RegistryKeyValueToScript(engine,script_key_value);
}
QScriptValue DataReporterEngine::RegistryKeyValueToString(
QScriptContext *context,
QScriptEngine *engine)
{
QByteArray key_value;
QString ret="";
// This function needs two arguments, key value and value type
if(context->argumentCount()!=2) return engine->undefinedValue();
// Cast ByteArray argument to QByteArray and convert
key_value=qvariant_cast<QByteArray>(context->argument(0).data().toVariant());
ret=RegistryHive::KeyValueToString(key_value,
context->argument(1).toInt32());
return engine->newVariant(ret);
}
QScriptValue DataReporterEngine::RegistryKeyValueToVariant(
QScriptContext *context,
QScriptEngine *engine)
{
int offset=0;
int length=-1;
QByteArray key_value;
QString format="";
QString ret="";
// This function needs at least two arguments, key value and variant type,
// and may have two optional arguments, offset and length
if(context->argumentCount()<2 || context->argumentCount()>4) {
return engine->undefinedValue();
}
if(context->argumentCount()==3) {
offset=context->argument(2).toInt32();
}
if(context->argumentCount()==4) {
offset=context->argument(2).toInt32();
length=context->argument(3).toInt32();
}
// Cast ByteArray argument to QByteArray
key_value=qvariant_cast<QByteArray>(context->argument(0).data().toVariant());
format=context->argument(1).toString();
ret=RegistryHive::KeyValueToString(key_value,format,offset,length);
return engine->newVariant(ret);
}
QScriptValue DataReporterEngine::RegistryKeyTypeToString(
QScriptContext *context,
QScriptEngine *engine)
{
QString ret="";
// This function needs one arguments, key type
if(context->argumentCount()!=1) return engine->undefinedValue();
ret=RegistryHive::KeyTypeToString(context->argument(0).toInt32());
return engine->newVariant(ret);
}
diff --git a/trunk/debian/changelog b/trunk/debian/changelog
index b52ebf1..6026ea9 100644
--- a/trunk/debian/changelog
+++ b/trunk/debian/changelog
@@ -1,39 +1,45 @@
+fred (0.1.0beta4) unstable; urgency=low
+
+ * Fixed some minor UI bugs
+
+ -- Daniel Gillen <gillen.dan@pinguin.lu> Mon, 21 May 2012 00:00:00 +0200
+
fred (0.1.0beta3) unstable; urgency=low
* Added search functionality
* Added various context menus to copy values to clipboard
* Now linking statically against libhivex to support older Debian / Ubuntu distros
* Some small fixes to ease portability
-- Daniel Gillen <gillen.dan@pinguin.lu> Sun, 04 Sep 2011 00:15:00 +0200
fred (0.1.0beta2) unstable; urgency=low
* Fixed some more bugs and subclassed QTreeView and QTableView
-- Daniel Gillen <gillen.dan@pinguin.lu> Tue, 23 Aug 2011 17:00:00 +0200
fred (0.1.0beta1) unstable; urgency=low
* Fixed some minor bugs and added more report templates
-- Daniel Gillen <gillen.dan@pinguin.lu> Mon, 22 Aug 2011 08:00:00 +0200
fred (0.1.0alpha3) unstable; urgency=low
* Added data report engine and 2 basic report templates
-- Daniel Gillen <gillen.dan@pinguin.lu> Wed, 17 Aug 2011 11:30:00 +0200
fred (0.1.0alpha2) unstable; urgency=low
* Integrated hexeditor into main windows.
* Added data interpreters
-- Daniel Gillen <gillen.dan@pinguin.lu> Tue, 09 Aug 2011 17:00:00 +0200
fred (0.1.0alpha1) unstable; urgency=low
* First public release
-- Daniel Gillen <gillen.dan@pinguin.lu> Sat, 06 Aug 2011 22:00:00 +0200
diff --git a/trunk/dlgsearch.cpp b/trunk/dlgsearch.cpp
index 8cfa10d..fcb1efe 100644
--- a/trunk/dlgsearch.cpp
+++ b/trunk/dlgsearch.cpp
@@ -1,127 +1,135 @@
/*******************************************************************************
* fred Copyright (c) 2011 by Gillen Daniel <gillen.dan@pinguin.lu> *
* *
* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
* with special feautures useful during forensic analysis. *
* *
* This program is free software: you can redistribute it and/or modify it *
* under the terms of the GNU General Public License as published by the Free *
* Software Foundation, either version 3 of the License, or (at your option) *
* any later version. *
* *
* This program is distributed in the hope that it will be useful, but WITHOUT *
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
* more details. *
* *
* You should have received a copy of the GNU General Public License along with *
* this program. If not, see <http://www.gnu.org/licenses/>. *
*******************************************************************************/
#include "dlgsearch.h"
#include "ui_dlgsearch.h"
#include <QMessageBox>
DlgSearch::DlgSearch(QWidget *parent) : QDialog(parent), ui(new Ui::DlgSearch)
{
ui->setupUi(this);
}
DlgSearch::~DlgSearch() {
delete ui;
}
QList<QByteArray> DlgSearch::Keywords() {
return this->keywords;
}
bool DlgSearch::SearchNodeNames() {
return this->search_nodes;
}
bool DlgSearch::SearchKeyNames() {
return this->search_keys;
}
bool DlgSearch::SearchKeyValues() {
return this->search_values;
}
void DlgSearch::changeEvent(QEvent *e) {
QDialog::changeEvent(e);
switch (e->type()) {
case QEvent::LanguageChange:
ui->retranslateUi(this);
break;
default:
break;
}
}
+void DlgSearch::keyPressEvent(QKeyEvent *p_event) {
+ if(p_event->key()==Qt::Key_Return || p_event->key()==Qt::Key_Enter) {
+ this->on_BtnSearch_clicked();
+ } else {
+ QDialog::keyPressEvent(p_event);
+ }
+}
+
void DlgSearch::on_BtnCancel_clicked() {
this->reject();
}
void DlgSearch::on_BtnSearch_clicked() {
if(this->ui->EdtValue->text()=="" ||
(!this->ui->CbAscii->isChecked() &&
!this->ui->CbUtf16->isChecked() &&
!this->ui->CbHex->isChecked()))
{
// No value type specified
QMessageBox::critical(this,
tr("Error"),
tr("Please specify a search value and type!"));
return;
}
if(!this->ui->CbNodeNames->isChecked() &&
!this->ui->CbKeyNames->isChecked() &&
!this->ui->CbKeyValues->isChecked())
{
// No target specified
QMessageBox::critical(this,
tr("Error"),
tr("Please specify a search target!"));
return;
}
// Save settings
QString keyword=this->ui->EdtValue->text();
this->keywords.clear();
if(this->ui->CbAscii->isChecked()) this->keywords.append(QByteArray(keyword.toAscii()));
if(this->ui->CbUtf16->isChecked()) {
// TODO: .size()*2 will definetly fail sometimes!!!!
this->keywords.append(QByteArray((char*)(keyword.utf16()),keyword.size()*2));
}
if(this->ui->CbHex->isChecked()) {
// TODO: Convert to hex
}
this->search_nodes=this->ui->CbNodeNames->isChecked();
this->search_keys=this->ui->CbKeyNames->isChecked();
this->search_values=this->ui->CbKeyValues->isChecked();
this->accept();
}
void DlgSearch::on_CbAscii_toggled(bool checked) {
// It is not possible to search for text and hex
if(checked && this->ui->CbHex->isChecked())
this->ui->CbHex->setChecked(false);
}
void DlgSearch::on_CbUtf16_toggled(bool checked) {
// It is not possible to search for text and hex
if(checked && this->ui->CbHex->isChecked())
this->ui->CbHex->setChecked(false);
}
void DlgSearch::on_CbHex_toggled(bool checked) {
// It is not possible to search for text and hex
if(checked) {
this->ui->CbAscii->setChecked(false);
this->ui->CbUtf16->setChecked(false);
}
}
diff --git a/trunk/dlgsearch.h b/trunk/dlgsearch.h
index e50d348..b5c4d89 100644
--- a/trunk/dlgsearch.h
+++ b/trunk/dlgsearch.h
@@ -1,62 +1,64 @@
/*******************************************************************************
* fred Copyright (c) 2011 by Gillen Daniel <gillen.dan@pinguin.lu> *
* *
* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
* with special feautures useful during forensic analysis. *
* *
* This program is free software: you can redistribute it and/or modify it *
* under the terms of the GNU General Public License as published by the Free *
* Software Foundation, either version 3 of the License, or (at your option) *
* any later version. *
* *
* This program is distributed in the hope that it will be useful, but WITHOUT *
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
* more details. *
* *
* You should have received a copy of the GNU General Public License along with *
* this program. If not, see <http://www.gnu.org/licenses/>. *
*******************************************************************************/
#ifndef DLGSEARCH_H
#define DLGSEARCH_H
#include <QDialog>
#include <QList>
#include <QByteArray>
+#include <QKeyEvent>
namespace Ui {
class DlgSearch;
}
class DlgSearch : public QDialog {
Q_OBJECT
public:
explicit DlgSearch(QWidget *parent = 0);
~DlgSearch();
QList<QByteArray> Keywords();
bool SearchNodeNames();
bool SearchKeyNames();
bool SearchKeyValues();
protected:
void changeEvent(QEvent *e);
+ void keyPressEvent(QKeyEvent *p_event);
private slots:
void on_BtnCancel_clicked();
void on_BtnSearch_clicked();
void on_CbAscii_toggled(bool checked);
void on_CbUtf16_toggled(bool checked);
void on_CbHex_toggled(bool checked);
private:
Ui::DlgSearch *ui;
QList<QByteArray> keywords;
bool search_nodes;
bool search_keys;
bool search_values;
};
#endif // DLGSEARCH_H
diff --git a/trunk/mainwindow.cpp b/trunk/mainwindow.cpp
index 6136a65..7d530d8 100644
--- a/trunk/mainwindow.cpp
+++ b/trunk/mainwindow.cpp
@@ -1,685 +1,705 @@
/*******************************************************************************
* fred Copyright (c) 2011 by Gillen Daniel <gillen.dan@pinguin.lu> *
* *
* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
* with special feautures useful during forensic analysis. *
* *
* This program is free software: you can redistribute it and/or modify it *
* under the terms of the GNU General Public License as published by the Free *
* Software Foundation, either version 3 of the License, or (at your option) *
* any later version. *
* *
* This program is distributed in the hope that it will be useful, but WITHOUT *
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
* more details. *
* *
* You should have received a copy of the GNU General Public License along with *
* this program. If not, see <http://www.gnu.org/licenses/>. *
*******************************************************************************/
#ifndef FRED_REPORT_TEMPLATE_DIR
#ifndef __MINGW32__
#define FRED_REPORT_TEMPLATE_DIR "/usr/share/fred/report_templates/"
#else
#define FRED_REPORT_TEMPLATE_DIR ".\\report_templates\\"
#endif
#endif
#include <QFileDialog>
#include <QMessageBox>
#include <QStringList>
#include <QDesktopWidget>
#include <QDir>
#include <QSplitter>
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "dlgabout.h"
#include "dlgkeydetails.h"
#include "dlgreportviewer.h"
#include "dlgsearch.h"
#include "compileinfo.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent), ui(new Ui::MainWindow)
{
ui->setupUi(this);
// Initialize private vars
this->p_hive=new RegistryHive(this);
this->is_hive_open=false;
this->p_reg_node_tree_model=NULL;
this->p_reg_key_table_model=NULL;
this->p_search_thread=NULL;
this->search_result_widgets.clear();
// Check for ~/.fred config dir
this->CheckUserConfigDir();
// Set main window size
int cur_screen=QApplication::desktop()->screenNumber(this);
int window_width=
QApplication::desktop()->availableGeometry(cur_screen).width()*0.5;
int window_height=
QApplication::desktop()->availableGeometry(cur_screen).height()*0.5;
int window_x=
(QApplication::desktop()->availableGeometry(cur_screen).width()/2)-
(window_width/2);
int window_y=
(QApplication::desktop()->availableGeometry(cur_screen).height()/2)-
(window_height/2);
this->setGeometry(window_x,
window_y,
window_width,
window_height);
// Create widgets
this->p_horizontal_splitter=new QSplitter();
this->p_horizontal_splitter->setOrientation(Qt::Horizontal);
this->p_node_tree=new RegistryNodeTree(this->p_horizontal_splitter);
this->p_node_tree->setHeaderHidden(true);
this->p_vertical_splitter=new QSplitter(this->p_horizontal_splitter);
this->p_vertical_splitter->setOrientation(Qt::Vertical);
this->p_key_table=new RegistryKeyTable(this->p_vertical_splitter);
this->p_tab_widget=new TabWidget(this->p_vertical_splitter);
this->p_horizontal_splitter2=new QSplitter();
this->p_horizontal_splitter2->setOrientation(Qt::Horizontal);
this->p_hex_edit_widget=new QWidget(this->p_horizontal_splitter2);
this->p_hex_edit_layout=new QVBoxLayout(this->p_hex_edit_widget);
this->p_hex_edit_layout->setContentsMargins(0,0,0,0);
this->p_hex_edit=new QHexEdit();
this->p_hex_edit->setReadOnly(true);
this->p_hex_edit_status_bar=new QLabel();
this->p_data_interpreter=new DataInterpreter(this->p_horizontal_splitter2);
// Make sure hex viewer font is monospaced.
QFont mono_font("Monospace");
mono_font.setStyleHint(QFont::TypeWriter);
this->p_hex_edit->setFont(mono_font);
// Add hexedit page to tab_widget
this->p_tab_widget->addTab(this->p_horizontal_splitter2,tr("Hex viewer"));
// Lay out widgets
this->p_hex_edit_layout->addWidget(this->p_hex_edit);
this->p_hex_edit_layout->addWidget(this->p_hex_edit_status_bar);
this->p_horizontal_splitter2->addWidget(this->p_hex_edit_widget);
this->p_horizontal_splitter2->addWidget(this->p_data_interpreter);
this->p_vertical_splitter->addWidget(this->p_key_table);
this->p_vertical_splitter->addWidget(this->p_tab_widget);
this->p_horizontal_splitter->addWidget(this->p_node_tree);
this->p_horizontal_splitter->addWidget(this->p_vertical_splitter);
// Set stretch factors
QSizePolicy node_tree_policy=this->p_node_tree->sizePolicy();
node_tree_policy.setHorizontalStretch(1);
node_tree_policy.setVerticalStretch(100);
this->p_node_tree->setSizePolicy(node_tree_policy);
QSizePolicy vertical_splitter_policy=this->p_vertical_splitter->sizePolicy();
vertical_splitter_policy.setHorizontalStretch(4);
vertical_splitter_policy.setVerticalStretch(100);
this->p_vertical_splitter->setSizePolicy(vertical_splitter_policy);
QSizePolicy key_table_policy=this->p_key_table->sizePolicy();
key_table_policy.setVerticalStretch(5);
key_table_policy.setHorizontalStretch(100);
this->p_key_table->setSizePolicy(key_table_policy);
QSizePolicy tab_widget_policy=this->p_tab_widget->sizePolicy();
tab_widget_policy.setVerticalStretch(2);
tab_widget_policy.setHorizontalStretch(200);
this->p_tab_widget->setSizePolicy(tab_widget_policy);
QSizePolicy hex_edit_widget_policy=this->p_hex_edit_widget->sizePolicy();
hex_edit_widget_policy.setVerticalStretch(2);
hex_edit_widget_policy.setHorizontalStretch(200);
this->p_hex_edit_widget->setSizePolicy(hex_edit_widget_policy);
QSizePolicy data_interpreter_policy=this->p_data_interpreter->sizePolicy();
data_interpreter_policy.setVerticalStretch(2);
data_interpreter_policy.setHorizontalStretch(0);
this->p_data_interpreter->setSizePolicy(data_interpreter_policy);
// Connect signals
this->connect(this->p_node_tree,
SIGNAL(clicked(QModelIndex)),
this,
SLOT(SlotNodeTreeClicked(QModelIndex)));
this->connect(this->p_node_tree,
SIGNAL(activated(QModelIndex)),
this,
SLOT(SlotNodeTreeClicked(QModelIndex)));
+ this->connect(this->p_node_tree,
+ SIGNAL(CurrentItemChanged(QModelIndex)),
+ this,
+ SLOT(SlotNodeTreeClicked(QModelIndex)));
this->connect(this->p_key_table,
SIGNAL(clicked(QModelIndex)),
this,
SLOT(SlotKeyTableClicked(QModelIndex)));
this->connect(this->p_key_table,
SIGNAL(doubleClicked(QModelIndex)),
this,
SLOT(SlotKeyTableDoubleClicked(QModelIndex)));
+ this->connect(this->p_key_table,
+ SIGNAL(CurrentItemChanged(QModelIndex)),
+ this,
+ SLOT(SlotKeyTableClicked(QModelIndex)));
this->connect(this->p_hex_edit,
SIGNAL(currentAddressChanged(int)),
this,
SLOT(SlotHexEditAddressChanged(int)));
this->connect(this->p_tab_widget,
SIGNAL(tabCloseRequested(int)),
this,
SLOT(SlotTabCloseButtonClicked(int)));
// Add central widget
this->setCentralWidget(this->p_horizontal_splitter);
this->centralWidget()->setContentsMargins(4,4,4,0);
// Set window title
this->UpdateWindowTitle();
// Set last open location to home dir
this->last_open_location=QDir::homePath();
// Load report templates and update menu
this->p_data_reporter=new DataReporter();
// Load reports from system wide include dir
this->p_data_reporter->LoadReportTemplates(FRED_REPORT_TEMPLATE_DIR);
// Load user's report templates
this->p_data_reporter->LoadReportTemplates(QDir::homePath()
.append(QDir::separator())
.append(".fred")
.append(QDir::separator())
.append("report_templates"));
this->UpdateDataReporterMenu();
// Finally, parse command line arguments
this->ParseCommandLineArgs();
}
MainWindow::~MainWindow() {
if(this->is_hive_open) {
this->p_hive->Close();
}
delete ui;
}
void MainWindow::on_action_Quit_triggered() {
qApp->exit();
}
void MainWindow::on_action_Open_hive_triggered() {
QString hive_file="";
hive_file=QFileDialog::getOpenFileName(this,
tr("Open registry hive"),
this->last_open_location,
tr("All files (*)"));
if(hive_file=="") return;
this->OpenHive(hive_file);
}
void MainWindow::on_action_Close_hive_triggered() {
if(this->is_hive_open) {
// Remove search results
while(this->p_tab_widget->count()>1) {
this->p_tab_widget->removeTab(this->p_tab_widget->count()-1);
delete this->search_result_widgets.at(this->p_tab_widget->count()-1);
this->search_result_widgets.removeLast();
}
// Delete models
if(this->p_reg_node_tree_model!=NULL) {
this->p_node_tree->setModel(NULL);
delete this->p_reg_node_tree_model;
this->p_reg_node_tree_model=NULL;
}
if(this->p_reg_key_table_model!=NULL) {
this->p_key_table->setModel(NULL);
delete this->p_reg_key_table_model;
this->p_reg_key_table_model=NULL;
}
// Remove any data from hex edit and data interpreter
this->p_hex_edit->setData(QByteArray());
this->p_hex_edit_status_bar->setText("");
this->p_data_interpreter->ClearValues();
// Close hive
this->p_hive->Close();
this->is_hive_open=false;
this->ui->action_Close_hive->setEnabled(false);
this->ui->ActionSearch->setEnabled(false);
this->ui->MenuReports->setEnabled(false);
this->UpdateWindowTitle();
}
}
void MainWindow::on_actionAbout_Qt_triggered() {
QMessageBox::aboutQt(this,tr("About Qt"));
}
void MainWindow::on_actionAbout_fred_triggered() {
DlgAbout dlg_about(this);
dlg_about.exec();
}
void MainWindow::on_ActionSearch_triggered() {
DlgSearch dlg_search(this);
if(dlg_search.exec()==QDialog::Accepted) {
// Create search thread and connect needed signals/slots
this->p_search_thread=new ThreadSearch(this);
QList<QByteArray> keywords;
keywords.append(QByteArray(QString("Windows").toAscii()));
// Add new search widget to tabwidget and to internal widget list
SearchResultWidget *p_search_widget=
new SearchResultWidget(this->p_tab_widget);
p_search_widget->setEnabled(false);
this->search_result_widgets.append(p_search_widget);
this->connect(p_search_widget,
SIGNAL(doubleClicked(QModelIndex)),
this,
SLOT(SlotSearchResultWidgetDoubleClicked(QModelIndex)));
this->p_tab_widget->addTab(p_search_widget,tr("Search results"),true);
this->p_tab_widget->setCurrentIndex(this->p_tab_widget->count()-1);
// Connect search thread to result widget
this->connect(this->p_search_thread,
SIGNAL(SignalFoundMatch(ThreadSearch::eMatchType,
QString,QString,QString)),
p_search_widget,
SLOT(SlotFoundMatch(ThreadSearch::eMatchType,
QString,QString,QString)));
this->connect(this->p_search_thread,
SIGNAL(finished()),
this,
SLOT(SlotSearchFinished()));
this->connect(this->p_search_thread,
SIGNAL(finished()),
p_search_widget,
SLOT(SlotSearchFinished()));
// Start searching
this->ui->ActionSearch->setEnabled(false);
p_search_thread->Search(this->p_hive->Filename(),
dlg_search.Keywords(),
dlg_search.SearchNodeNames(),
dlg_search.SearchKeyNames(),
dlg_search.SearchKeyValues());
}
}
void MainWindow::SlotNodeTreeClicked(QModelIndex index) {
QString node_path;
if(!index.isValid()) return;
//Built node path
node_path=this->p_reg_node_tree_model->GetNodePath(index);
// Create table model and attach it to the table view
if(this->p_reg_key_table_model!=NULL) {
this->p_key_table->setModel(NULL);
delete this->p_reg_key_table_model;
this->p_hex_edit->setData(QByteArray());
this->p_hex_edit_status_bar->setText("");
this->p_data_interpreter->ClearValues();
}
this->p_reg_key_table_model=new RegistryKeyTableModel(this->p_hive,node_path);
this->p_key_table->setModel(this->p_reg_key_table_model);
+ // Set focus back to nodetree to be able to navigate with keyboard
+ this->p_node_tree->setFocus();
}
void MainWindow::SlotKeyTableDoubleClicked(QModelIndex index) {
Q_UNUSED(index);
/*
QModelIndex key_index;
QModelIndex node_index;
QStringList nodes;
QString key_name;
QString key_type;
QByteArray key_value;
if(!index.isValid()) return;
// Get key name, type and value
key_index=this->p_reg_key_table_model->index(index.row(),0);
key_name=this->p_reg_key_table_model->data(key_index,Qt::DisplayRole)
.toString();
key_index=this->p_reg_key_table_model->index(index.row(),1);
key_type=this->p_reg_key_table_model->data(key_index,Qt::DisplayRole)
.toString();ThreadSearch
key_index=this->p_reg_key_table_model->index(index.row(),2);
key_value=this->p_reg_key_table_model->data(key_index,
RegistryKeyTableModel::
AdditionalRoles_GetRawData)
.toByteArray();
// Get current node
node_index=this->p_node_tree->currentIndex();
//Built node path
nodes.clear();
nodes.append(this->p_reg_node_tree_model->
data(node_index,Qt::DisplayRole).toString());
while(this->p_reg_node_tree_model->parent(node_index)!=QModelIndex()) {
// Prepend all parent nodes
node_index=this->p_reg_node_tree_model->parent(node_index);
nodes.prepend(this->p_reg_node_tree_model->
data(node_index,Qt::DisplayRole).toString());
}
DlgKeyDetails dlg_key_details(this);
dlg_key_details.SetValues(nodes,key_name,key_type,key_value);
dlg_key_details.exec();
*/
}
void MainWindow::SlotKeyTableClicked(QModelIndex index) {
if(!index.isValid()) return;
this->selected_key_value=
this->p_reg_key_table_model->data(this->p_reg_key_table_model->
index(index.row(),2),
RegistryKeyTableModel::
AdditionalRoles_GetRawData)
.toByteArray();
this->p_hex_edit->setData(this->selected_key_value);
+ // Set focus back to nodetree to be able to navigate with keyboard
+ this->p_key_table->setFocus();
}
void MainWindow::SlotHexEditAddressChanged(int hex_offset) {
if(!this->is_hive_open || this->selected_key_value.isEmpty()) return;
// Update hex edit status bar
this->p_hex_edit_status_bar->
setText(QString("Byte offset: 0x%1 (%2)")
.arg((uint16_t)hex_offset,4,16,QChar('0'))
.arg(hex_offset));
// Update data interpreter
this->UpdateDataInterpreter(hex_offset);
}
void MainWindow::SlotReportClicked() {
// Get report category and name from sender and it's parent
QString category=((QMenu*)((QAction*)QObject::sender())->parent())->title();
QString report=((QAction*)QObject::sender())->text();
// Generate report
QString report_content=this->p_data_reporter->GenerateReport(this->p_hive,
category,
report);
// Show result in report viewer
if(report_content!=QString()) {
DlgReportViewer *p_dlg_report_view=new DlgReportViewer(report_content,this);
p_dlg_report_view->exec();
delete p_dlg_report_view;
} else {
// TODO: Something went wrong!
}
}
void MainWindow::SlotSearchFinished() {
delete this->p_search_thread;
this->p_search_thread=NULL;
this->ui->ActionSearch->setEnabled(true);
// Enable result widget
this->search_result_widgets.last()->setEnabled(true);
}
void MainWindow::SlotSearchResultWidgetDoubleClicked(QModelIndex index) {
SearchResultWidget *p_sender;
QString path;
QString match_type;
QString value;
QString key="";
int i;
if(!index.isValid()) return;
// Get pointer to sender
p_sender=(SearchResultWidget*)QObject::sender();
// Get path and matchtype
path=p_sender->item(index.row(),0)->text();
match_type=p_sender->item(index.row(),1)->text();
value=p_sender->item(index.row(),2)->text();
if(match_type==tr("Node name")) {
// Node name is not part of path. Add it
if(path=="\\") path.append(value);
else path.append("\\").append(value);
} else if(match_type==tr("Key name")) {
// Key name is stored in value
key=value;
} else if(match_type==tr("Key value")) {
// Key name is part of path. Save and remove it
QStringList nodes=path.split("\\",QString::SkipEmptyParts);
key=nodes.at(nodes.count()-1);
// Remove \<key name> from path
path.chop(key.length()+1);
}
// Expand treeview to correct node
QList<QModelIndex> indexes=
this->p_reg_node_tree_model->GetIndexListOf(path);
for(i=0;i<indexes.count();i++) {
this->p_node_tree->expand(indexes.at(i));
}
if(indexes.count()>0) {
// Scroll to last expanded node, select it and update widgets
this->p_node_tree->scrollTo(indexes.at(indexes.count()-1),
QAbstractItemView::PositionAtCenter);
this->p_node_tree->selectionModel()->clear();
this->p_node_tree->selectionModel()->
select(indexes.at(indexes.count()-1),
QItemSelectionModel::Select);
+ // TODO: This does not work!!
this->SlotNodeTreeClicked(indexes.at(indexes.count()-1));
}
// Select correct key if search matched on keay name / value
if(key!="") {
int row=this->p_reg_key_table_model->GetKeyRow(key);
this->p_key_table->clearSelection();
this->p_key_table->scrollTo(this->p_reg_key_table_model->index(row,0),
QAbstractItemView::PositionAtCenter);
this->p_key_table->selectRow(row);
this->SlotKeyTableClicked(this->p_reg_key_table_model->index(row,0));
}
}
void MainWindow::SlotTabCloseButtonClicked(int index) {
// Delete tab widget and remove tab
this->p_tab_widget->removeTab(index);
delete this->search_result_widgets.at(index-1);
this->search_result_widgets.removeAt(index-1);
}
void MainWindow::CheckUserConfigDir() {
QString user_config_dir=QDir::homePath()
.append(QDir::separator())
.append(".fred");
if(!QDir(user_config_dir).exists()) {
// User config dir does not exists, try to create it
if(!QDir().mkpath(user_config_dir)) {
// TODO: Maybe warn user
return;
}
user_config_dir.append(QDir::separator()).append("report_templates");
if(!QDir().mkpath(user_config_dir)) {
// TODO: Maybe warn user
return;
}
}
}
void MainWindow::UpdateWindowTitle(QString filename) {
if(filename=="") {
this->setWindowTitle(QString("%1 v%2").arg(APP_TITLE,APP_VERSION));
} else {
this->setWindowTitle(QString("%1 v%2 - %3").arg(APP_TITLE,
APP_VERSION,
filename.toLocal8Bit()
.constData()));
}
}
void MainWindow::UpdateDataInterpreter(int hex_offset) {
- QDateTime date_time;
const char *p_data;
int remaining_data_len;
// Remove all old values from data interpreter
this->p_data_interpreter->ClearValues();
// Calculate how many bytes are remainig after current offset
remaining_data_len=this->selected_key_value.size()-hex_offset;
if(!remaining_data_len>0) {
// Nothing to show
return;
}
// Get pointer to data at current offset
p_data=this->selected_key_value.constData();
p_data+=hex_offset;
//#define rotl32(x,n) (((x) << n) | ((x) >> (32 - n)))
//#define rotr32(x,n) (((x) >> n) | ((x) << (32 - n)))
//#define rotl64(x,n) (((x) << n) | ((x) >> (64 - n)))
//#define rotr64(x,n) (((x) >> n) | ((x) << (64 - n)))
if(remaining_data_len>=1) {
this->p_data_interpreter->AddValue("int8:",
RegistryHive::KeyValueToString(
this->selected_key_value,
"int8",
hex_offset));
this->p_data_interpreter->AddValue("uint8:",
RegistryHive::KeyValueToString(
this->selected_key_value,
"uint8",
hex_offset));
}
if(remaining_data_len>=2) {
this->p_data_interpreter->AddValue("int16:",
RegistryHive::KeyValueToString(
this->selected_key_value,
"int16",
hex_offset));
this->p_data_interpreter->AddValue("uint16:",
RegistryHive::KeyValueToString(
this->selected_key_value,
"uint16",
hex_offset));
}
if(remaining_data_len>=4) {
this->p_data_interpreter->AddValue("int32:",
RegistryHive::KeyValueToString(
this->selected_key_value,
"int32",
hex_offset));
this->p_data_interpreter->AddValue("uint32:",
RegistryHive::KeyValueToString(
this->selected_key_value,
"uint32",
hex_offset));
this->p_data_interpreter->AddValue("unixtime:",
RegistryHive::KeyValueToString(
this->selected_key_value,
"unixtime",
hex_offset));
}
if(remaining_data_len>=8) {
this->p_data_interpreter->AddValue("int64:",
RegistryHive::KeyValueToString(
this->selected_key_value,
"int64",
hex_offset));
this->p_data_interpreter->AddValue("uint64:",
RegistryHive::KeyValueToString(
this->selected_key_value,
"uint64",
hex_offset));
+/*
+ TODO: Check one could implement this
+ this->p_data_interpreter->AddValue("unixtime64:",
+ RegistryHive::KeyValueToString(
+ this->selected_key_value,
+ "unixtime64",
+ hex_offset));
+*/
this->p_data_interpreter->AddValue("filetime64:",
RegistryHive::KeyValueToString(
this->selected_key_value,
"filetime",
hex_offset));
}
//#undef rotl32
//#undef rotl64
}
void MainWindow::UpdateDataReporterMenu() {
int i=0,ii=0;
QMenu *p_category_entry;
QAction *p_report_entry;
QStringList categories=this->p_data_reporter->GetAvailableReportCategories();
QStringList reports;
for(i=0;i<categories.count();i++) {
// First create category submenu
p_category_entry=this->ui->MenuReports->addMenu(categories.value(i));
// Now add category reports
reports=this->p_data_reporter->GetAvailableReports(categories.value(i));
for(ii=0;ii<reports.count();ii++) {
p_report_entry=new QAction(reports.value(ii),p_category_entry);
p_category_entry->addAction(p_report_entry);
this->connect(p_report_entry,
SIGNAL(triggered()),
this,
SLOT(SlotReportClicked()));
}
}
}
void MainWindow::OpenHive(QString hive_file) {
// Update last open location
this->last_open_location=hive_file.left(hive_file.
lastIndexOf(QDir::separator()));
// If another hive is currently open, close it
if(this->is_hive_open) this->on_action_Close_hive_triggered();
// Try to open hive
if(!this->p_hive->Open(hive_file)) {
QMessageBox::critical(this,
tr("Error opening hive file"),
tr("Unable to open file '%1'").arg(hive_file));
return;
}
// Create tree model
this->p_reg_node_tree_model=
new RegistryNodeTreeModel(this->p_hive);
this->p_node_tree->setModel(this->p_reg_node_tree_model);
this->is_hive_open=true;
this->ui->action_Close_hive->setEnabled(true);
this->ui->ActionSearch->setEnabled(true);
this->ui->MenuReports->setEnabled(true);
this->UpdateWindowTitle(hive_file);
}
void MainWindow::ParseCommandLineArgs() {
QStringList args=qApp->arguments();
// If exactly 1 argument was specified, it should be a hive to open
if(args.count()==2) {
this->OpenHive(args.at(1));
}
}
diff --git a/trunk/qhexedit/qhexedit_p.cpp b/trunk/qhexedit/qhexedit_p.cpp
index 3988385..ed8e23d 100644
--- a/trunk/qhexedit/qhexedit_p.cpp
+++ b/trunk/qhexedit/qhexedit_p.cpp
@@ -1,455 +1,589 @@
/*******************************************************************************
* qhexedit Copyright (c) 2011 by Gillen Daniel <gillen.dan@pinguin.lu> *
* *
* Simple hex editor widget for Qt. *
* *
* Derived from code by Simon Winfried under a compatible license: *
* Copyright (c) 2010 by Simon Winfried *
* *
* This program is free software: you can redistribute it and/or modify it *
* under the terms of the GNU General Public License as published by the Free *
* Software Foundation, either version 3 of the License, or (at your option) *
* any later version. *
* *
* This program is distributed in the hope that it will be useful, but WITHOUT *
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
* more details. *
* *
* You should have received a copy of the GNU General Public License along with *
* this program. If not, see <http://www.gnu.org/licenses/>. *
*******************************************************************************/
#include <QtGui>
#include "qhexedit_p.h"
const int HEXCHARS_IN_LINE = 47;
const int GAP_ADR_HEX = 10;
const int GAP_HEX_ASCII = 16;
const int BYTES_PER_LINE = 16;
-QHexEditPrivate::QHexEditPrivate(QScrollArea *parent) : QWidget(parent)
-{
- _scrollArea = parent;
- setAddressWidth(4);
- setAddressOffset(0);
- setAddressArea(true);
- setAsciiArea(true);
- setHighlighting(true);
- setOverwriteMode(true);
- setAddressAreaColor(QColor(Qt::lightGray).lighter(110));
- setHighlightingColor(QColor(Qt::yellow).lighter(160));
- this->setReadOnly(true);
-
- setFont(QFont("Mono", 10));
- connect(&_cursorTimer, SIGNAL(timeout()), this, SLOT(updateCursor()));
-
- _cursorTimer.setInterval(500);
+QHexEditPrivate::QHexEditPrivate(QScrollArea *parent) : QWidget(parent) {
+ _scrollArea = parent;
+ setAddressWidth(4);
+ setAddressOffset(0);
+ setAddressArea(true);
+ setAsciiArea(true);
+ setHighlighting(true);
+ setOverwriteMode(true);
+ setAddressAreaColor(QColor(Qt::lightGray).lighter(110));
+ setHighlightingColor(QColor(Qt::yellow).lighter(160));
+ this->setReadOnly(true);
+ this->sel_origin=QPoint(0,0);
+ this->sel_start=QPoint(0,0);
+ this->sel_end=QPoint(0,0);
+
+ setFont(QFont("Mono", 10));
+ connect(&_cursorTimer, SIGNAL(timeout()), this, SLOT(updateCursor()));
+
+ _cursorTimer.setInterval(500);
+
+ setFocusPolicy(Qt::StrongFocus);
+ _size = -1;
+
+ // Create context menu
+ this->p_menu_copy=new QMenu(tr("Copy"),this);
+ this->p_action_copy_selected_bytes=
+ new QAction(tr("Selected bytes"),this->p_menu_copy);
+ this->p_action_copy_selected_text_ascii=
+ new QAction(tr("Selected text as ASCII"),this->p_menu_copy);
+ this->p_action_copy_selected_text_utf8=
+ new QAction(tr("Selected text as UTF8"),this->p_menu_copy);
+
+ this->p_menu_copy->addAction(this->p_action_copy_selected_bytes);
+ this->p_menu_copy->addAction(this->p_action_copy_selected_text_ascii);
+ this->p_menu_copy->addAction(this->p_action_copy_selected_text_utf8);
+
+ this->connect(this->p_action_copy_selected_bytes,
+ SIGNAL(triggered()),
+ this,
+ SLOT(SlotCopySelectedBytes()));
+ this->connect(this->p_action_copy_selected_text_ascii,
+ SIGNAL(triggered()),
+ this,
+ SLOT(SlotCopySelectedBytes()));
+ this->connect(this->p_action_copy_selected_text_utf8,
+ SIGNAL(triggered()),
+ this,
+ SLOT(SlotCopySelectedBytes()));
+}
- setFocusPolicy(Qt::StrongFocus);
- _size = -1;
+QHexEditPrivate::~QHexEditPrivate() {
+ // Delete context menu
+ delete this->p_action_copy_selected_bytes;
+ delete this->p_action_copy_selected_text_ascii;
+ delete this->p_action_copy_selected_text_utf8;
+ delete this->p_menu_copy;
}
void QHexEditPrivate::setAddressOffset(int offset)
{
_addressOffset = offset;
adjust();
}
int QHexEditPrivate::addressOffset()
{
return _addressOffset;
}
void QHexEditPrivate::setData(const QByteArray &data)
{
if(!data.isNull() && !data.isEmpty()) this->_cursorTimer.start();
else this->_cursorTimer.stop();
this->_data = data;
this->_originalData = data;
this->adjust();
this->setCursorPos(0);
this->setFocus();
}
QByteArray QHexEditPrivate::data()
{
return _data;
}
void QHexEditPrivate::setAddressAreaColor(const QColor &color)
{
_addressAreaColor = color;
update();
}
QColor QHexEditPrivate::addressAreaColor()
{
return _addressAreaColor;
}
void QHexEditPrivate::setHighlightingColor(const QColor &color)
{
_highlightingColor = color;
update();
}
QColor QHexEditPrivate::highlightingColor()
{
return _highlightingColor;
}
void QHexEditPrivate::setOverwriteMode(bool overwriteMode)
{
if (overwriteMode != _overwriteMode)
{
emit overwriteModeChanged(overwriteMode);
_overwriteMode = overwriteMode;
adjust();
}
}
bool QHexEditPrivate::overwriteMode()
{
return _overwriteMode;
}
void QHexEditPrivate::setReadOnly(bool read_only) {
this->_readOnly=read_only;
}
bool QHexEditPrivate::readOnly() {
return this->_readOnly;
}
void QHexEditPrivate::insert(int i, const QByteArray & ba)
{
_data.insert(i, ba);
_originalData.insert(i, ba);
}
void QHexEditPrivate::insert(int i, char ch)
{
_data.insert(i, ch);
_originalData.insert(i, ch);
}
void QHexEditPrivate::remove(int index, int len)
{
_data.remove(index, len);
_originalData.remove(index, len);
}
void QHexEditPrivate::setAddressArea(bool addressArea)
{
_addressArea = addressArea;
adjust();
setCursorPos(_cursorPosition);
}
void QHexEditPrivate::setAddressWidth(int addressWidth)
{
if ((addressWidth >= 0) and (addressWidth<=6))
{
_addressNumbers = addressWidth;
adjust();
setCursorPos(_cursorPosition);
}
}
void QHexEditPrivate::setAsciiArea(bool asciiArea)
{
_asciiArea = asciiArea;
adjust();
}
void QHexEditPrivate::setFont(const QFont &font)
{
QWidget::setFont(font);
adjust();
}
void QHexEditPrivate::setHighlighting(bool mode)
{
_highlighting = mode;
update();
}
void QHexEditPrivate::keyPressEvent(QKeyEvent *event)
{
bool down = false;
int charX = (_cursorX - _xPosHex) / _charWidth;
int posX = (charX / 3) * 2 + (charX % 3);
int posBa = (_cursorY / _charHeight) * BYTES_PER_LINE + posX / 2;
int key = int(event->text()[0].toAscii());
if (!this->_readOnly &&
((key>='0' && key<='9') || (key>='a' && key <= 'f')))
{
// insert char
if (_overwriteMode == false)
if ((charX % 3) == 0)
{
insert(posBa, char(0));
adjust();
}
if (_data.size() > 0)
{
QByteArray hexValue = _data.mid(posBa, 1).toHex();
if ((charX % 3) == 0)
hexValue[0] = key;
else
hexValue[1] = key;
_data.replace(posBa, 1, QByteArray().fromHex(hexValue));
emit dataChanged();
setCursorPos(_cursorPosition + 1);
down = true;
}
}
// delete char
if (!this->_readOnly && event->matches(QKeySequence::Delete)) {
remove(posBa);
}
if (!this->_readOnly && event->key() == Qt::Key_Backspace) {
remove(posBa - 1);
setCursorPos(_cursorPosition - 2);
}
// handle other function keys
if(!this->_readOnly && event->key() == Qt::Key_Insert) {
setOverwriteMode(!_overwriteMode);
setCursorPos(_cursorPosition);
}
if (event->matches(QKeySequence::MoveToNextChar))
{
setCursorPos(_cursorPosition + 1);
down = true;
}
if (event->matches(QKeySequence::MoveToPreviousChar))
setCursorPos(_cursorPosition - 1);
if (event->matches(QKeySequence::MoveToStartOfLine))
setCursorPos(_cursorPosition - (_cursorPosition % (2 * BYTES_PER_LINE)));
if (event->matches(QKeySequence::MoveToEndOfLine))
setCursorPos(_cursorPosition | (2 * BYTES_PER_LINE -1));
if (event->matches(QKeySequence::MoveToPreviousLine))
setCursorPos(_cursorPosition - (2 * BYTES_PER_LINE));
if (event->matches(QKeySequence::MoveToPreviousPage))
setCursorPos(_cursorPosition - (((_scrollArea->viewport()->height() / _charHeight) - 1) * 2 * BYTES_PER_LINE));
if (event->matches(QKeySequence::MoveToStartOfDocument))
setCursorPos(0);
if (event->matches(QKeySequence::MoveToNextLine))
{
setCursorPos(_cursorPosition + (2 * BYTES_PER_LINE));
down = true;
}
if (event->matches(QKeySequence::MoveToEndOfDocument))
{
setCursorPos(_data.size() * 2);
down = true;
}
if (event->matches(QKeySequence::MoveToNextPage))
{
setCursorPos(_cursorPosition + (((_scrollArea->viewport()->height() / _charHeight) - 1) * 2 * BYTES_PER_LINE));
down = true;
}
// when we move downwards, we have to go a little further
if (down)
_scrollArea->ensureVisible(_cursorX, _cursorY, 3, 3 + _charHeight);
else
_scrollArea->ensureVisible(_cursorX, _cursorY, 3, 3);
update();
}
-void QHexEditPrivate::mousePressEvent(QMouseEvent * event)
-{
- setCursorPos(event->pos());
+void QHexEditPrivate::mousePressEvent(QMouseEvent *p_event) {
+ if(p_event->button()==Qt::LeftButton) {
+ // Init selection origin, start and end point
+ this->sel_origin=p_event->pos();
+ this->sel_end=this->sel_start=this->sel_origin;
+
+ // Set cursor to current pos
+ int curs_pos=this->Point2Char(this->sel_start);
+ if(curs_pos!=-1) setCursorPos(curs_pos);
+ } else {
+ QWidget::mousePressEvent(p_event);
+ }
}
-void QHexEditPrivate::paintEvent(QPaintEvent *event)
-{
- QPainter painter(this);
+void QHexEditPrivate::mouseMoveEvent(QMouseEvent *p_event) {
+ if(p_event->buttons()==Qt::LeftButton) {
+ // Update current selection and repaint hexedit
+ if(this->Point2Char(p_event->pos())>this->Point2Char(this->sel_origin)) {
+ this->sel_start=this->sel_origin;
+ this->sel_end=p_event->pos();
+ } else {
+ this->sel_end=this->sel_origin;
+ this->sel_start=p_event->pos();
+ }
+ this->update();
+ } else {
+ QWidget::mouseMoveEvent(p_event);
+ }
+}
- // draw some patterns if needed
- painter.fillRect(event->rect(), this->palette().color(QPalette::Base));
- if (_addressArea)
- painter.fillRect(QRect(_xPosAdr, event->rect().top(), _xPosHex - GAP_ADR_HEX + 2, height()), _addressAreaColor);
- if (_asciiArea)
+void QHexEditPrivate::paintEvent(QPaintEvent *event) {
+ QPainter painter(this);
+
+ // Draw some patterns if needed
+ painter.fillRect(event->rect(), this->palette().color(QPalette::Base));
+ if(_addressArea) {
+ painter.fillRect(QRect(_xPosAdr,
+ event->rect().top(),
+ _xPosHex-GAP_ADR_HEX+2,
+ height()),
+ _addressAreaColor);
+ }
+ if(_asciiArea) {
+ int linePos=_xPosAscii-(GAP_HEX_ASCII / 2);
+ painter.setPen(Qt::gray);
+ painter.drawLine(linePos,event->rect().top(),linePos,height());
+ }
+
+ painter.setPen(this->palette().color(QPalette::WindowText));
+
+ // Calc positions
+ int firstLineIdx=
+ ((event->rect().top()/_charHeight)-_charHeight)*BYTES_PER_LINE;
+ if(firstLineIdx<0) firstLineIdx=0;
+ int lastLineIdx=
+ ((event->rect().bottom()/_charHeight)+_charHeight)*BYTES_PER_LINE;
+ if(lastLineIdx>_data.size()) lastLineIdx=_data.size();
+ int yPosStart=((firstLineIdx)/BYTES_PER_LINE)*_charHeight+_charHeight;
+
+ // Paint address area
+ if(_addressArea) {
+ for(int lineIdx=firstLineIdx, yPos=yPosStart;
+ lineIdx<lastLineIdx;
+ lineIdx+=BYTES_PER_LINE, yPos+=_charHeight)
{
- int linePos = _xPosAscii - (GAP_HEX_ASCII / 2);
- painter.setPen(Qt::gray);
- painter.drawLine(linePos, event->rect().top(), linePos, height());
+ QString address=QString("%1").arg(lineIdx+_addressOffset,
+ _realAddressNumbers,
+ 16,
+ QChar('0'));
+ painter.drawText(_xPosAdr, yPos, address);
}
-
- painter.setPen(this->palette().color(QPalette::WindowText));
-
- // calc position
- int firstLineIdx = ((event->rect().top()/ _charHeight) - _charHeight) * BYTES_PER_LINE;
- if (firstLineIdx < 0)
- firstLineIdx = 0;
- int lastLineIdx = ((event->rect().bottom() / _charHeight) + _charHeight) * BYTES_PER_LINE;
- if (lastLineIdx > _data.size())
- lastLineIdx = _data.size();
- int yPosStart = ((firstLineIdx) / BYTES_PER_LINE) * _charHeight + _charHeight;
-
- // paint address area
- if (_addressArea)
+ }
+
+ // Prepare values for a selection
+ int selection_start=0,selection_end=0;
+ bool selection=false;
+ if(!(this->sel_start.isNull() && this->sel_end.isNull()) &&
+ this->sel_start!=this->sel_end)
+ {
+ selection_start=this->Point2Char(this->sel_start)/2;
+ selection_end=this->Point2Char(this->sel_end)/2;
+ selection=true;
+ }
+
+ // Paint hex area
+ QByteArray hexBa(_data.mid(firstLineIdx,lastLineIdx-firstLineIdx+1).toHex());
+ QBrush highLighted=QBrush(_highlightingColor);
+ painter.setBackground(highLighted);
+ painter.setBackgroundMode(Qt::TransparentMode);
+ for(int lineIdx=firstLineIdx, yPos=yPosStart;
+ lineIdx<lastLineIdx;
+ lineIdx+=BYTES_PER_LINE, yPos+=_charHeight)
+ {
+ QByteArray hex;
+ int xPos=_xPosHex;
+ for(int colIdx=0;
+ ((lineIdx+colIdx)<_data.size() && (colIdx<BYTES_PER_LINE));
+ colIdx++)
{
- for (int lineIdx = firstLineIdx, yPos = yPosStart; lineIdx < lastLineIdx; lineIdx += BYTES_PER_LINE, yPos +=_charHeight)
- {
- QString address = QString("%1")
- .arg(lineIdx + _addressOffset, _realAddressNumbers, 16, QChar('0'));
- painter.drawText(_xPosAdr, yPos, address);
+ // Highlight diff bytes
+ if(_highlighting) {
+ int posBa=lineIdx+colIdx;
+ if(posBa>=_originalData.size()) {
+ painter.setBackgroundMode(Qt::TransparentMode);
+ } else {
+ if(_data[posBa]==_originalData[posBa]) {
+ painter.setBackgroundMode(Qt::TransparentMode);
+ } else {
+ painter.setBackgroundMode(Qt::OpaqueMode);
+ }
+ }
+ }
+
+ // Highlight selection
+ if(selection) {
+ int cur_char=lineIdx+colIdx;
+ if(cur_char>=selection_start && cur_char<=selection_end) {
+ painter.setBackgroundMode(Qt::OpaqueMode);
+ } else {
+ painter.setBackgroundMode(Qt::TransparentMode);
}
+ }
+
+ // Render hex value
+ if(colIdx==0) {
+ hex=hexBa.mid((lineIdx-firstLineIdx)*2,2);
+ painter.drawText(xPos,yPos,hex);
+ xPos+=2*_charWidth;
+ } else {
+ hex=hexBa.mid((lineIdx+colIdx-firstLineIdx)*2,2).prepend(" ");
+ painter.drawText(xPos,yPos,hex);
+ xPos+=3*_charWidth;
+ }
}
+ }
- // paint hex area
- QByteArray hexBa(_data.mid(firstLineIdx, lastLineIdx - firstLineIdx + 1).toHex());
- QBrush highLighted = QBrush(_highlightingColor);
- painter.setBackground(highLighted);
- painter.setBackgroundMode(Qt::TransparentMode);
- for (int lineIdx = firstLineIdx, yPos = yPosStart; lineIdx < lastLineIdx; lineIdx += BYTES_PER_LINE, yPos +=_charHeight)
+ // Paint ascii area
+ if(_asciiArea) {
+ for(int lineIdx=firstLineIdx, yPos=yPosStart;
+ lineIdx<lastLineIdx;
+ lineIdx+=BYTES_PER_LINE, yPos+=_charHeight)
{
- QByteArray hex;
- int xPos = _xPosHex;
- for (int colIdx = 0; ((lineIdx + colIdx) < _data.size() and (colIdx < BYTES_PER_LINE)); colIdx++)
- {
- // hilight diff bytes
- if (_highlighting)
- {
- int posBa = lineIdx + colIdx;
- if (posBa >= _originalData.size())
- painter.setBackgroundMode(Qt::TransparentMode);
- else
- if (_data[posBa] == _originalData[posBa])
- painter.setBackgroundMode(Qt::TransparentMode);
- else
- painter.setBackgroundMode(Qt::OpaqueMode);
- }
-
- // render hex value
- if (colIdx == 0)
- {
- hex = hexBa.mid((lineIdx - firstLineIdx) * 2, 2);
- painter.drawText(xPos, yPos, hex);
- xPos += 2 * _charWidth;
- } else {
- hex = hexBa.mid((lineIdx + colIdx - firstLineIdx) * 2, 2).prepend(" ");
- painter.drawText(xPos, yPos, hex);
- xPos += 3 * _charWidth;
- }
+ QByteArray ascii=_data.mid(lineIdx,BYTES_PER_LINE);
+ for(int idx=0, xpos=_xPosAscii;
+ idx<ascii.size();
+ idx++, xpos+=_charWidth)
+ {
+ // Highlight selection
+ if(selection) {
+ int cur_char=lineIdx+idx;
+ if(cur_char>=selection_start && cur_char<=selection_end) {
+ painter.setBackgroundMode(Qt::OpaqueMode);
+ } else {
+ painter.setBackgroundMode(Qt::TransparentMode);
+ }
}
- }
- painter.setBackgroundMode(Qt::TransparentMode);
- // paint ascii area
- if (_asciiArea)
- {
- for (int lineIdx = firstLineIdx, yPos = yPosStart; lineIdx < lastLineIdx; lineIdx += BYTES_PER_LINE, yPos +=_charHeight)
- {
- QByteArray ascii = _data.mid(lineIdx, BYTES_PER_LINE);
- for (int idx=0; idx < ascii.size(); idx++)
- if (((char)ascii[idx] < 0x20) or ((char)ascii[idx] > 0x7e))
- ascii[idx] = '.';
- painter.drawText(_xPosAscii, yPos, ascii);
+ // Render char
+ if(((char)ascii[idx]<0x20) || ((char)ascii[idx]>0x7e)) {
+ painter.drawText(xpos, yPos, QString("."));
+ } else {
+ painter.drawText(xpos, yPos, QString(ascii.at(idx)));
}
+ }
}
-
- // paint cursor
- if (_blink && !this->_data.isNull() && !this->_data.isEmpty())
- {
- if (_overwriteMode)
- painter.fillRect(_cursorX, _cursorY + _charHeight - 2, _charWidth, 2, this->palette().color(QPalette::WindowText));
- else
- painter.fillRect(_cursorX, _cursorY, 2, _charHeight, this->palette().color(QPalette::WindowText));
+ }
+
+ // Reset painter background if it is still set from highlighting
+ painter.setBackgroundMode(Qt::TransparentMode);
+
+ // Paint cursor
+ if(_blink && !this->_data.isNull() && !this->_data.isEmpty()) {
+ if(_overwriteMode) {
+ painter.fillRect(_cursorX,
+ _cursorY+_charHeight-2,
+ _charWidth,
+ 2,
+ this->palette().color(QPalette::WindowText));
+ } else {
+ painter.fillRect(_cursorX,
+ _cursorY,
+ 2,
+ _charHeight,
+ this->palette().color(QPalette::WindowText));
}
+ }
- if (_size != _data.size())
- {
- _size = _data.size();
- emit currentSizeChanged(_size);
- }
+ if(_size!=_data.size()) {
+ _size=_data.size();
+ emit currentSizeChanged(_size);
+ }
}
void QHexEditPrivate::setCursorPos(int position)
{
- // delete cursor
- _blink = false;
- update();
-
- // cursor in range?
- if (_overwriteMode)
- {
- if (position > (_data.size() * 2 - 1))
- position = _data.size() * 2 - 1;
- } else {
- if (position > (_data.size() * 2))
- position = _data.size() * 2;
- }
+ // delete cursor
+ _blink=false;
+ update();
+
+ // cursor in range?
+ if(_overwriteMode) {
+ if(position>(_data.size()*2-1)) position=_data.size()*2-1;
+ } else {
+ if(position>(_data.size()*2)) position=_data.size()*2;
+ }
+
+ if(position < 0) position=0;
+
+ // calc position
+ _cursorPosition=position;
+ _cursorY=(position/(2*BYTES_PER_LINE))*_charHeight+4;
+ int x=(position%(2*BYTES_PER_LINE));
+ _cursorX=(((x/2)*3)+(x%2))*_charWidth+_xPosHex;
+
+ // immiadately draw cursor
+ _blink=true;
+ update();
+ emit currentAddressChanged(_cursorPosition/2);
+}
- if (position < 0)
- position = 0;
+void QHexEditPrivate::contextMenuEvent(QContextMenuEvent *p_event) {
- // calc position
- _cursorPosition = position;
- _cursorY = (position / (2 * BYTES_PER_LINE)) * _charHeight + 4;
- int x = (position % (2 * BYTES_PER_LINE));
- _cursorX = (((x / 2) * 3) + (x % 2)) * _charWidth + _xPosHex;
+ // TODO: Only show context menu when something is selected
- // immiadately draw cursor
- _blink = true;
- update();
- emit currentAddressChanged(_cursorPosition/2);
-}
-
-void QHexEditPrivate::setCursorPos(QPoint pos)
-{
- // find char under cursor
- if ((pos.x() >= _xPosHex) and (pos.x() < (_xPosHex + HEXCHARS_IN_LINE * _charWidth)))
- {
- int x = (pos.x() - _xPosHex) / _charWidth;
- if ((x % 3) == 0)
- x = (x / 3) * 2;
- else
- x = ((x / 3) * 2) + 1;
- int y = (pos.y() / _charHeight) * 2 * BYTES_PER_LINE;
- setCursorPos(x + y);
- }
+ // Create context menu and add actions
+ QMenu context_menu(this);
+ context_menu.addMenu(this->p_menu_copy);
+ context_menu.exec(p_event->globalPos());
}
void QHexEditPrivate::updateCursor()
{
if (_blink)
_blink = false;
else
_blink = true;
update(_cursorX, _cursorY, _charWidth, _charHeight);
}
+void QHexEditPrivate::SlotCopySelectedBytes() {
+ // TODO: Implement
+}
+
+void QHexEditPrivate::SlotCopySelectedTextAsAscii() {
+ // TODO: Implement
+}
+
+void QHexEditPrivate::SlotCopySelectedTextAsUtf8() {
+ // TODO: Implement
+}
+
void QHexEditPrivate::adjust()
{
_charWidth = fontMetrics().width(QLatin1Char('9'));
_charHeight = fontMetrics().height();
// is addressNumbers wide enought?
QString test = QString("%1")
.arg(_data.size() + _addressOffset, _addressNumbers, 16, QChar('0'));
_realAddressNumbers = test.size();
_xPosAdr = 0;
if (_addressArea)
_xPosHex = _realAddressNumbers *_charWidth + GAP_ADR_HEX;
else
_xPosHex = 0;
_xPosAscii = _xPosHex + HEXCHARS_IN_LINE * _charWidth + GAP_HEX_ASCII;
// tell QAbstractScollbar, how big we are
setMinimumHeight(((_data.size()/16 + 1) * _charHeight) + 3);
setMinimumWidth(_xPosAscii + (BYTES_PER_LINE * _charWidth));
update();
}
+
+int QHexEditPrivate::Point2Char(QPoint pos) {
+ // find char under cursor
+ if((pos.x()>=_xPosHex) && (pos.x()<(_xPosHex+HEXCHARS_IN_LINE*_charWidth))) {
+ int x=(pos.x()-_xPosHex)/_charWidth;
+ if((x%3)==0) x=(x/3)*2;
+ else x=((x/3)*2)+1;
+ int y=(pos.y()/_charHeight)*2*BYTES_PER_LINE;
+ return x+y;
+ }
+ return -1;
+}
diff --git a/trunk/qhexedit/qhexedit_p.h b/trunk/qhexedit/qhexedit_p.h
index 70ec39e..8fea7d9 100644
--- a/trunk/qhexedit/qhexedit_p.h
+++ b/trunk/qhexedit/qhexedit_p.h
@@ -1,109 +1,121 @@
/*******************************************************************************
* qhexedit Copyright (c) 2011 by Gillen Daniel <gillen.dan@pinguin.lu> *
* *
* Simple hex editor widget for Qt. *
* *
* Derived from code by Simon Winfried under a compatible license: *
* Copyright (c) 2010 by Simon Winfried *
* *
* This program is free software: you can redistribute it and/or modify it *
* under the terms of the GNU General Public License as published by the Free *
* Software Foundation, either version 3 of the License, or (at your option) *
* any later version. *
* *
* This program is distributed in the hope that it will be useful, but WITHOUT *
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
* more details. *
* *
* You should have received a copy of the GNU General Public License along with *
* this program. If not, see <http://www.gnu.org/licenses/>. *
*******************************************************************************/
#ifndef QHEXEDIT_P_H
#define QHEXEDIT_P_H
/** \cond docNever */
-
#include <QtGui>
+#include <QPoint>
-class QHexEditPrivate : public QWidget
-{
-Q_OBJECT
+class QHexEditPrivate : public QWidget {
+ Q_OBJECT
-public:
+ public:
QHexEditPrivate(QScrollArea *parent);
+ ~QHexEditPrivate();
void setAddressOffset(int offset);
int addressOffset();
void setData(QByteArray const &data);
QByteArray data();
void setAddressAreaColor(QColor const &color);
QColor addressAreaColor();
void setHighlightingColor(QColor const &color);
QColor highlightingColor();
void setOverwriteMode(bool overwriteMode);
bool overwriteMode();
void setReadOnly(bool read_only);
bool readOnly();
void insert(int i, const QByteArray & ba);
void insert(int i, char ch);
void remove(int index, int len=1);
void setAddressArea(bool addressArea);
void setAddressWidth(int addressWidth);
void setAsciiArea(bool asciiArea);
void setHighlighting(bool mode);
virtual void setFont(const QFont &font);
-signals:
+ signals:
void currentAddressChanged(int address);
void currentSizeChanged(int size);
void dataChanged();
void overwriteModeChanged(bool state);
-protected:
+ protected:
void keyPressEvent(QKeyEvent * event);
- void mousePressEvent(QMouseEvent * event);
+ void mousePressEvent(QMouseEvent *p_event);
+ void mouseMoveEvent(QMouseEvent *p_event);
void paintEvent(QPaintEvent *event);
- void setCursorPos(QPoint pos);
void setCursorPos(int position);
+ void contextMenuEvent(QContextMenuEvent *p_event);
-private slots:
+ private slots:
void updateCursor();
+ void SlotCopySelectedBytes();
+ void SlotCopySelectedTextAsAscii();
+ void SlotCopySelectedTextAsUtf8();
-private:
+ private:
void adjust();
+ int Point2Char(QPoint pos);
QColor _addressAreaColor;
QByteArray _data;
QByteArray _originalData;
QColor _highlightingColor;
QScrollArea *_scrollArea;
QTimer _cursorTimer;
+ QPoint sel_origin;
+ QPoint sel_start;
+ QPoint sel_end;
+ QMenu *p_menu_copy;
+ QAction *p_action_copy_selected_bytes;
+ QAction *p_action_copy_selected_text_ascii;
+ QAction *p_action_copy_selected_text_utf8;
bool _blink;
bool _addressArea;
bool _asciiArea;
bool _highlighting;
bool _overwriteMode;
bool _readOnly;
int _addressNumbers, _realAddressNumbers;
int _addressOffset;
int _charWidth, _charHeight;
int _cursorX, _cursorY, _cursorPosition;
int _xPosAdr, _xPosHex, _xPosAscii;
int _size;
};
/** \endcond docNever */
#endif
diff --git a/trunk/registryhive.cpp b/trunk/registryhive.cpp
index 06916d4..a34fad6 100644
--- a/trunk/registryhive.cpp
+++ b/trunk/registryhive.cpp
@@ -1,546 +1,566 @@
/*******************************************************************************
* fred Copyright (c) 2011 by Gillen Daniel <gillen.dan@pinguin.lu> *
* *
* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
* with special feautures useful during forensic analysis. *
* *
* This program is free software: you can redistribute it and/or modify it *
* under the terms of the GNU General Public License as published by the Free *
* Software Foundation, either version 3 of the License, or (at your option) *
* any later version. *
* *
* This program is distributed in the hope that it will be useful, but WITHOUT *
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
* more details. *
* *
* You should have received a copy of the GNU General Public License along with *
* this program. If not, see <http://www.gnu.org/licenses/>. *
*******************************************************************************/
#include "registryhive.h"
#include <QStringList>
#include <QDateTime>
#include <stdlib.h>
+#include <stdio.h>
// TODO: __WORDSIZE is not defined under mingw and I currently have no idea how
// to identify a 64bit windows
#ifndef __WORDSIZE
#define __WORDSIZE 32
#endif
#if __WORDSIZE == 64
#define EPOCH_DIFF 0x19DB1DED53E8000
#else
#define EPOCH_DIFF 0x19DB1DED53E8000LL
#endif
/*
* RegistryHive
*/
RegistryHive::RegistryHive(QObject *p_parent) : QObject(p_parent) {
this->erro_msg="";
this->is_error=false;
this->hive_file="";
this->p_hive=NULL;
this->is_hive_open=false;
}
/*
* ~RegistryHive
*/
RegistryHive::~RegistryHive() {
if(this->is_hive_open) this->Close();
}
/*
* Error
*/
bool RegistryHive::Error() {
return this->is_error;
}
/*
* GetErrorMsg
*/
QString RegistryHive::GetErrorMsg() {
QString msg=this->erro_msg;
this->erro_msg="";
this->is_error=false;
return msg;
}
/*
* Open
*/
bool RegistryHive::Open(QString file, bool read_only) {
if(this->is_hive_open) return false;
// Open hive file
this->p_hive=hivex_open(file.toAscii().constData(),
read_only ? 0 : HIVEX_OPEN_WRITE);
if(this->p_hive==NULL) return false;
// Set local vars
this->hive_file=file;
this->is_hive_open=true;
return true;
}
/*
* Close
*/
bool RegistryHive::Close(bool commit_changes) {
if(this->is_hive_open) {
if(commit_changes) {
// Commit changes before closing hive.
// TODO: Maybe it would be more secure to commit changes to a new file and
// then move it over the original one.
hivex_commit(this->p_hive,NULL,0);
}
// As hivex_close will _ALWAYS_ free the handle, we don't need the following
// values anymore
this->hive_file="";
this->is_hive_open=false;
// Close hive
if(hivex_close(this->p_hive)!=0) return false;
}
return true;
}
QString RegistryHive::Filename() {
if(this->is_hive_open) return this->hive_file;
return QString();
}
/*
* GetNodes
*/
QMap<QString,int> RegistryHive::GetNodes(QString path) {
hive_node_h parent_node;
// Get handle to last node in path
if(!this->GetNodeHandle(path,&parent_node)) return QMap<QString,int>();
// Get and return nodes
return this->GetNodesHelper(parent_node);
}
/*
* GetNodes
*/
QMap<QString,int> RegistryHive::GetNodes(int parent_node) {
if(parent_node==0) {
this->SetError(tr("Invalid parent node handle specified!"));
return QMap<QString,int>();
}
// Get and return nodes
return this->GetNodesHelper(parent_node);
}
/*
* GetKeys
*/
QMap<QString,int> RegistryHive::GetKeys(QString path) {
hive_node_h parent_node;
// Get handle to last node in path
if(!this->GetNodeHandle(path,&parent_node)) return QMap<QString,int>();
// Get and return keys
return this->GetKeysHelper(parent_node);
}
/*
* GetKeys
*/
QMap<QString,int> RegistryHive::GetKeys(int parent_node) {
if(parent_node==0) {
this->SetError(tr("Invalid parent node handle specified!"));
return QMap<QString,int>();
}
// Get and return keys
return this->GetKeysHelper(parent_node);
}
/*
* GetKeyValue
*/
QByteArray RegistryHive::GetKeyValue(QString path,
QString key,
int *p_value_type,
size_t *p_value_len)
{
hive_node_h parent_node;
hive_value_h hive_key;
// Get handle to last node in path
if(!this->GetNodeHandle(path,&parent_node)) return QByteArray();
// Get key handle
hive_key=hivex_node_get_value(this->p_hive,
parent_node,key.toAscii().constData());
if(hive_key==0) {
this->SetError(tr("Unable to get key handle!"));
*p_value_len=-1;
return QByteArray();
}
// Get and return key value
return this->GetKeyValueHelper(hive_key,p_value_type,p_value_len);
}
/*
* GetKeyValue
*/
QByteArray RegistryHive::GetKeyValue(int hive_key,
int *p_value_type,
size_t *p_value_len)
{
if(hive_key==0) {
this->SetError(tr("Invalid key handle specified!"));
*p_value_type=-1;
return QByteArray();
}
// Get and return key value
return this->GetKeyValueHelper(hive_key,p_value_type,p_value_len);
}
/*
* KeyValueToString
*/
QString RegistryHive::KeyValueToString(QByteArray value, int value_type) {
QString ret="";
int i=0;
#define ToHexStr() { \
for(i=0;i<value.size();i++) { \
ret.append(QString().sprintf("%02X ",(uint8_t)(value.constData()[i]))); \
} \
ret.chop(1); \
}
switch(value_type) {
case hive_t_REG_NONE:
// Just a key without a value, but to be certain...
ToHexStr();
break;
case hive_t_REG_SZ:
// A Windows string (encoding is unknown, but often UTF16-LE)
// TODO: What happens if encoding is not UTF16-LE ??? Thx Billy!!!
ret=value.size() ? QString().fromUtf16((ushort*)(value.constData())) : "";
break;
case hive_t_REG_EXPAND_SZ:
// A Windows string that contains %env% (environment variable expansion)
ret=value.size() ? QString().fromUtf16((ushort*)(value.constData())) : "";
break;
case hive_t_REG_BINARY:
// A blob of binary
ToHexStr();
break;
case hive_t_REG_DWORD:
// DWORD (32 bit integer), little endian
ret=QString().sprintf("0x%08X",*(uint32_t*)value.constData());
break;
case hive_t_REG_DWORD_BIG_ENDIAN:
// DWORD (32 bit integer), big endian
ret=QString().sprintf("0x%08X",*(uint32_t*)value.constData());
break;
case hive_t_REG_LINK:
// Symbolic link to another part of the registry tree
ToHexStr();
break;
case hive_t_REG_MULTI_SZ:
// Multiple Windows strings.
// See http://blogs.msdn.com/oldnewthing/archive/2009/10/08/9904646.aspx
ToHexStr();
break;
case hive_t_REG_RESOURCE_LIST:
// Resource list
ToHexStr();
break;
case hive_t_REG_FULL_RESOURCE_DESCRIPTOR:
// Resource descriptor
ToHexStr();
break;
case hive_t_REG_RESOURCE_REQUIREMENTS_LIST:
// Resouce requirements list
ToHexStr();
break;
case hive_t_REG_QWORD:
// QWORD (64 bit integer). Usually little endian.
ret=
QString("0x%1").arg((quint64)(*(uint64_t*)value.constData()),16,16,QChar('0'));
break;
default:
ToHexStr();
}
#undef ToHexStr
return ret;
}
/*
* KeyValueToString
*/
QString RegistryHive::KeyValueToString(QByteArray key_value,
QString format,
int offset,
int length)
{
int remaining_data_len;
const char *p_data;
QString ret="";
// Calculate how many bytes are remainig after specified offset
remaining_data_len=key_value.size()-offset;
if(!remaining_data_len>0) {
// Nothing to show
return QString();
}
// Get pointer to data at specified offset
p_data=key_value.constData();
p_data+=offset;
// ConvertFull name
if(format=="int8" && remaining_data_len>=1) {
ret=QString().sprintf("%d",*(int8_t*)p_data);
} else if(format=="uint8" && remaining_data_len>=1) {
ret=QString().sprintf("%u",*(uint8_t*)p_data);
} else if(format=="int16" && remaining_data_len>=2) {
ret=QString().sprintf("%d",*(int16_t*)p_data);
} else if(format=="uint16" && remaining_data_len>=2) {
ret=QString().sprintf("%u",*(uint16_t*)p_data);
} else if(format=="int32" && remaining_data_len>=4) {
ret=QString().sprintf("%d",*(int32_t*)p_data);
} else if(format=="uint32" && remaining_data_len>=4) {
ret=QString().sprintf("%u",*(uint32_t*)p_data);
} else if(format=="unixtime" && remaining_data_len>=4) {
if(*(uint32_t*)p_data==0) {
ret="n/a";
} else {
QDateTime date_time;
+ date_time.setTimeSpec(Qt::UTC);
date_time.setTime_t(*(uint32_t*)p_data);
ret=date_time.toString("yyyy/MM/dd hh:mm:ss");
}
} else if(format=="int64" && remaining_data_len>=8) {
ret=QString("%1").arg(*(int64_t*)p_data);
} else if(format=="uint64" && remaining_data_len>=8) {
ret=QString("%1").arg(*(uint64_t*)p_data);
+/*
+ // TODO: Check how one could implement this
+ } else if(format=="unixtime64" && remaining_data_len>=8) {
+ if(*(uint64_t*)p_data==0) {
+ ret="n/a";
+ } else {
+ uint64_t secs=*(uint64_t*)p_data;
+ QDateTime date_time;
+ date_time.setTimeSpec(Qt::UTC);
+ // Set 32bit part of date/time
+ date_time.setTime_t(secs&0xFFFFFFFF);
+ // Now add high 32bit part of date/time
+ date_time.addSecs(secs>>32);
+ ret=date_time.toString("yyyy/MM/dd hh:mm:ss");
+ }
+*/
} else if(format=="filetime" && remaining_data_len>=8) {
if(*(uint64_t*)p_data==0) {
ret="n/a";
} else {
// TODO: Warn if >32bit
QDateTime date_time;
+ date_time.setTimeSpec(Qt::UTC);
date_time.setTime_t((*(uint64_t*)p_data-EPOCH_DIFF)/10000000);
ret=date_time.toString("yyyy/MM/dd hh:mm:ss");
}
} else if(format=="ascii") {
// TODO: This fails bad if the string is not null terminated!! It might be
// wise checking for a null char here
ret=QString().fromAscii((char*)p_data,length);
} else if(format=="utf16" && remaining_data_len>=2) {
ret=QString().fromUtf16((ushort*)p_data,length);
} else {
// Unknown variant type or another error
return QString();
}
return ret;
}
/*
* KeyTypeToString
*/
QString RegistryHive::KeyTypeToString(int value_type) {
QString ret="";
switch(value_type) {
case hive_t_REG_NONE:
ret="REG_NONE";
break;
case hive_t_REG_SZ:
ret="REG_SZ";
break;
case hive_t_REG_EXPAND_SZ:
ret="REG_EXPAND_SZ";
break;
case hive_t_REG_BINARY:
ret="REG_BINARY";
break;
case hive_t_REG_DWORD:
ret="REG_DWORD";
break;
case hive_t_REG_DWORD_BIG_ENDIAN:
ret="REG_DWORD_BIG_ENDIAN";
break;
case hive_t_REG_LINK:
ret="REG_LINK";
break;
case hive_t_REG_MULTI_SZ:
ret="REG_MULTI_SZ";
break;
case hive_t_REG_RESOURCE_LIST:
ret="REG_RESOURCE_LIST";
break;
case hive_t_REG_FULL_RESOURCE_DESCRIPTOR:
ret="REG_FULL_RESOURCE_DESC";
break;
case hive_t_REG_RESOURCE_REQUIREMENTS_LIST:
ret="REG_RESOURCE_REQ_LIST";
break;
case hive_t_REG_QWORD:
ret="REG_QWORD";
break;
default:
ret=QString().sprintf("0x%08X",(uint32_t)value_type);
}
return ret;
}
/*
* SetError
*/
void RegistryHive::SetError(QString msg) {
this->erro_msg=msg;
this->is_error=true;
}
/*
* GetNodeHandle
*/
bool RegistryHive::GetNodeHandle(QString &path, hive_node_h *p_node) {
QStringList nodes;
int i=0;
// Get root node handle
*p_node=hivex_root(this->p_hive);
if(*p_node==0) {
this->SetError(tr("Unable to get root node!"));
return false;
}
if(path!="\\") {
// If we aren't listing the root node, we have to get a handle to the
// last node in the path. Split path into nodes
nodes=path.split('\\',QString::SkipEmptyParts);
// Iterate to the correct parent node
for(i=0;i<nodes.count();i++) {
+// printf("Spotting node '%s'\n",nodes.value(i).toAscii().constData());
*p_node=hivex_node_get_child(this->p_hive,
*p_node,
nodes.value(i).toAscii().constData());
if(*p_node==0) {
this->SetError(tr("Unable to find node '%1'!").arg(nodes.value(i)));
return false;
}
}
}
return true;
}
/*
* GetNodesHelper
*/
QMap<QString,int> RegistryHive::GetNodesHelper(hive_node_h parent_node) {
QMap<QString,int> keys;
char *p_name;
int i=0;
// Get child nodes
hive_node_h *child_nodes=hivex_node_children(this->p_hive,parent_node);
if(child_nodes==NULL) {
this->SetError(
tr("Unable to enumerate child nodes!"));
return QMap<QString,int>();
}
// Build result
keys.clear();
i=0;
while(child_nodes[i]) {
p_name=hivex_node_name(this->p_hive,child_nodes[i]);
if(p_name==NULL) {
this->SetError(tr("Unable to get node name!"));
free(child_nodes);
return QMap<QString,int>();
}
keys.insert(QString(p_name),(int)child_nodes[i]);
free(p_name);
i++;
}
free(child_nodes);
return keys;
}
/*
* GetKeysHelper
*/
QMap<QString,int> RegistryHive::GetKeysHelper(hive_node_h parent_node) {
QMap<QString,int> keys;
char *p_name;
int i=0;
// Get child keys
hive_value_h *p_keys=hivex_node_values(this->p_hive,parent_node);
if(p_keys==NULL) {
this->SetError(
tr("Unable to enumerate child keys!"));
return QMap<QString,int>();
}
// Build result list
keys.clear();
i=0;
while(p_keys[i]) {
p_name=hivex_value_key(this->p_hive,p_keys[i]);
if(p_name==NULL) {
this->SetError(tr("Unable to get key name!"));
return QMap<QString,int>();
}
keys.insert(QString(p_name),p_keys[i]);
free(p_name);
i++;
}
free(p_keys);
return keys;
}
QByteArray RegistryHive::GetKeyValueHelper(hive_value_h hive_key,
int *p_value_type,
size_t *p_value_len)
{
QByteArray key_value;
char *p_key_value;
p_key_value=hivex_value_value(this->p_hive,
hive_key,
(hive_type*)p_value_type,
p_value_len);
if(p_key_value==NULL) {
this->SetError(tr("Unable to get key value!"));
*p_value_type=-1;
return QByteArray();
}
// Feed QByteArray and free p_key_value
key_value=QByteArray(p_key_value,*p_value_len);
free(p_key_value);
return key_value;
}
diff --git a/trunk/registrykeytable.cpp b/trunk/registrykeytable.cpp
index ad65f73..9ec1832 100644
--- a/trunk/registrykeytable.cpp
+++ b/trunk/registrykeytable.cpp
@@ -1,129 +1,145 @@
/*******************************************************************************
* fred Copyright (c) 2011 by Gillen Daniel <gillen.dan@pinguin.lu> *
* *
* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
* with special feautures useful during forensic analysis. *
* *
* This program is free software: you can redistribute it and/or modify it *
* under the terms of the GNU General Public License as published by the Free *
* Software Foundation, either version 3 of the License, or (at your option) *
* any later version. *
* *
* This program is distributed in the hope that it will be useful, but WITHOUT *
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
* more details. *
* *
* You should have received a copy of the GNU General Public License along with *
* this program. If not, see <http://www.gnu.org/licenses/>. *
*******************************************************************************/
#include "registrykeytable.h"
#include <QHeaderView>
#include <QApplication>
#include <QClipboard>
RegistryKeyTable::RegistryKeyTable(QWidget *p_parent) : QTableView(p_parent) {
// Configure widget
this->setSelectionMode(QAbstractItemView::SingleSelection);
this->setSelectionBehavior(QAbstractItemView::SelectRows);
+ this->setAutoScroll(false);
this->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
this->verticalHeader()->setHidden(true);
this->setTextElideMode(Qt::ElideNone);
// Create context menu
this->p_menu_copy=new QMenu(tr("Copy"),this);
this->p_action_copy_key_name=new QAction(tr("Key name"),
this->p_menu_copy);
this->p_menu_copy->addAction(this->p_action_copy_key_name);
this->connect(this->p_action_copy_key_name,
SIGNAL(triggered()),
this,
SLOT(SlotCopyKeyName()));
this->p_action_copy_key_value=new QAction(tr("Key value"),
this->p_menu_copy);
this->p_menu_copy->addAction(this->p_action_copy_key_value);
this->connect(this->p_action_copy_key_value,
SIGNAL(triggered()),
this,
SLOT(SlotCopyKeyValue()));
}
RegistryKeyTable::~RegistryKeyTable() {
// Delete context menu
delete this->p_action_copy_key_name;
delete this->p_action_copy_key_value;
delete this->p_menu_copy;
}
void RegistryKeyTable::setModel(QAbstractItemModel *p_model) {
QTableView::setModel(p_model);
// Resize table rows / columns to fit data
this->resizeColumnsToContents();
this->resizeRowsToContents();
this->horizontalHeader()->stretchLastSection();
+ if(p_model!=NULL && p_model->rowCount()>0) {
+ // Select first table item
+ this->selectRow(0);
+ }
}
/*
void RegistryKeyTable::selectRow(QString key_name) {
int i;
this->clearSelection();
for(i=0;i<this->model()->rowCount();i++) {
if(this->model())
}
}
*/
int RegistryKeyTable::sizeHintForColumn(int column) const {
int size_hint=-1;
int i=0;
int item_width=0;
QFontMetrics fm(this->fontMetrics());
QModelIndex idx;
if(this->model()==NULL) return -1;
// Find string that needs the most amount of space
idx=this->model()->index(i,column);
while(idx.isValid()) {
item_width=fm.width(this->model()->data(idx).toString())+10;
if(item_width>size_hint) size_hint=item_width;
idx=this->model()->index(++i,column);
}
return size_hint;
}
void RegistryKeyTable::contextMenuEvent(QContextMenuEvent *p_event) {
// Only show context menu when a row is selected
if(this->selectedIndexes().count()!=3) return;
// Only show context menu when user clicked on selected row
if(!(this->indexAt(p_event->pos())==this->selectedIndexes().at(0) ||
this->indexAt(p_event->pos())==this->selectedIndexes().at(1) ||
this->indexAt(p_event->pos())==this->selectedIndexes().at(2)))
{
return;
}
// Emit a click signal
emit(this->clicked(this->indexAt(p_event->pos())));
// Create context menu and add actions
QMenu context_menu(this);
context_menu.addMenu(this->p_menu_copy);
context_menu.exec(p_event->globalPos());
}
+void RegistryKeyTable::currentChanged(const QModelIndex &current,
+ const QModelIndex &previous)
+{
+ // Call parent class's currentChanged first
+ QTableView::currentChanged(current,previous);
+
+ // Now emit our signal
+ QModelIndex current_item=QModelIndex(current);
+ emit(RegistryKeyTable::CurrentItemChanged(current_item));
+}
+
void RegistryKeyTable::SlotCopyKeyName() {
QApplication::clipboard()->
setText(this->selectedIndexes().at(0).data().toString(),
QClipboard::Clipboard);
}
void RegistryKeyTable::SlotCopyKeyValue() {
QApplication::clipboard()->
setText(this->selectedIndexes().at(2).data().toString(),
QClipboard::Clipboard);
}
diff --git a/trunk/registrykeytable.h b/trunk/registrykeytable.h
index b070d42..c954696 100644
--- a/trunk/registrykeytable.h
+++ b/trunk/registrykeytable.h
@@ -1,53 +1,58 @@
/*******************************************************************************
* fred Copyright (c) 2011 by Gillen Daniel <gillen.dan@pinguin.lu> *
* *
* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
* with special feautures useful during forensic analysis. *
* *
* This program is free software: you can redistribute it and/or modify it *
* under the terms of the GNU General Public License as published by the Free *
* Software Foundation, either version 3 of the License, or (at your option) *
* any later version. *
* *
* This program is distributed in the hope that it will be useful, but WITHOUT *
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
* more details. *
* *
* You should have received a copy of the GNU General Public License along with *
* this program. If not, see <http://www.gnu.org/licenses/>. *
*******************************************************************************/
#ifndef REGISTRYKEYTABLE_H
#define REGISTRYKEYTABLE_H
#include <QTableView>
#include <QContextMenuEvent>
#include <QMenu>
#include <QAction>
class RegistryKeyTable : public QTableView {
Q_OBJECT
public:
RegistryKeyTable(QWidget *p_parent=0);
~RegistryKeyTable();
void setModel(QAbstractItemModel *p_model);
//void selectRow(QString key_name);
+ Q_SIGNALS:
+ void CurrentItemChanged(QModelIndex current);
+
protected:
int sizeHintForColumn(int column) const;
void contextMenuEvent(QContextMenuEvent *p_event);
private:
QMenu *p_menu_copy;
QAction *p_action_copy_key_name;
QAction *p_action_copy_key_value;
+ void currentChanged(const QModelIndex &current,
+ const QModelIndex &previous);
private slots:
void SlotCopyKeyName();
void SlotCopyKeyValue();
};
#endif // REGISTRYKEYTABLE_H
diff --git a/trunk/registrynodetree.cpp b/trunk/registrynodetree.cpp
index 561c39a..f4655cb 100644
--- a/trunk/registrynodetree.cpp
+++ b/trunk/registrynodetree.cpp
@@ -1,90 +1,129 @@
/*******************************************************************************
* fred Copyright (c) 2011 by Gillen Daniel <gillen.dan@pinguin.lu> *
* *
* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
* with special feautures useful during forensic analysis. *
* *
* This program is free software: you can redistribute it and/or modify it *
* under the terms of the GNU General Public License as published by the Free *
* Software Foundation, either version 3 of the License, or (at your option) *
* any later version. *
* *
* This program is distributed in the hope that it will be useful, but WITHOUT *
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
* more details. *
* *
* You should have received a copy of the GNU General Public License along with *
* this program. If not, see <http://www.gnu.org/licenses/>. *
*******************************************************************************/
#include "registrynodetree.h"
#include "registrynodetreemodel.h"
#include <QHeaderView>
#include <QApplication>
#include <QClipboard>
RegistryNodeTree::RegistryNodeTree(QWidget *p_parent) : QTreeView(p_parent) {
// Configure widget
this->setTextElideMode(Qt::ElideNone);
// Create context menu
this->p_menu_copy=new QMenu(tr("Copy"),this);
this->p_action_copy_node_name=new QAction(tr("Copy node name"),
this->p_menu_copy);
this->p_menu_copy->addAction(this->p_action_copy_node_name);
this->connect(this->p_action_copy_node_name,
SIGNAL(triggered()),
this,
SLOT(SlotCopyNodeName()));
this->p_action_copy_node_path=new QAction(tr("Copy node path"),
this->p_menu_copy);
this->p_menu_copy->addAction(this->p_action_copy_node_path);
this->connect(this->p_action_copy_node_path,
SIGNAL(triggered()),
this,
SLOT(SlotCopyNodePath()));
}
RegistryNodeTree::~RegistryNodeTree() {
// Delete context menu
delete this->p_action_copy_node_name;
delete this->p_action_copy_node_path;
delete this->p_menu_copy;
}
void RegistryNodeTree::setModel(QAbstractItemModel *p_model) {
QTreeView::setModel(p_model);
this->header()->setResizeMode(0,QHeaderView::ResizeToContents);
this->header()->setStretchLastSection(false);
+ if(p_model!=NULL && p_model->index(0,0).isValid()) {
+ // Select first tree item
+ this->setCurrentIndex(p_model->index(0,0));
+ }
}
//int RegistryNodeTree::sizeHintForColumn(int column) const {}
void RegistryNodeTree::contextMenuEvent(QContextMenuEvent *p_event) {
// Only show context menu when a node is selected
if(this->selectedIndexes().count()!=1) return;
// Only show context menu when user clicked on selected row
if(this->indexAt(p_event->pos())!=this->selectedIndexes().at(0)) return;
// Emit a click signal
emit(this->clicked(this->indexAt(p_event->pos())));
// Create context menu and add actions
QMenu context_menu(this);
context_menu.addMenu(this->p_menu_copy);
context_menu.exec(p_event->globalPos());
}
+void RegistryNodeTree::keyPressEvent(QKeyEvent *p_event) {
+ // Only react if a node is selected and user pressed Key_Left
+ if(this->selectedIndexes().count()==1 &&
+ p_event->key()==Qt::Key_Left)
+ {
+ QModelIndex cur_index=this->selectedIndexes().at(0);
+
+ if(this->model()->hasChildren(cur_index)) {
+ // Collapse current node
+ this->collapse(cur_index);
+ }
+ if(!cur_index.parent().isValid()) {
+ // Do no try to collapse anything above root node
+ return;
+ }
+ this->collapse(cur_index.parent());
+ this->setCurrentIndex(cur_index.parent());
+ return;
+ }
+
+ // If we didn't handle the key event, let our parent handle it
+ QTreeView::keyPressEvent(p_event);
+}
+
+void RegistryNodeTree::currentChanged(const QModelIndex &current,
+ const QModelIndex &previous)
+{
+ // Call parent class's currentChanged first
+ QTreeView::currentChanged(current,previous);
+
+ // Now emit our signal
+ QModelIndex current_item=QModelIndex(current);
+ emit(RegistryNodeTree::CurrentItemChanged(current_item));
+}
+
void RegistryNodeTree::SlotCopyNodeName() {
QApplication::clipboard()->
setText(this->selectedIndexes().at(0).data().toString(),
QClipboard::Clipboard);
}
void RegistryNodeTree::SlotCopyNodePath() {
QString path=((RegistryNodeTreeModel*)(this->model()))->
GetNodePath(this->selectedIndexes().at(0));
QApplication::clipboard()->setText(path,QClipboard::Clipboard);
}
diff --git a/trunk/registrynodetree.h b/trunk/registrynodetree.h
index caa5004..02e4698 100644
--- a/trunk/registrynodetree.h
+++ b/trunk/registrynodetree.h
@@ -1,53 +1,59 @@
/*******************************************************************************
* fred Copyright (c) 2011 by Gillen Daniel <gillen.dan@pinguin.lu> *
* *
* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
* with special feautures useful during forensic analysis. *
* *
* This program is free software: you can redistribute it and/or modify it *
* under the terms of the GNU General Public License as published by the Free *
* Software Foundation, either version 3 of the License, or (at your option) *
* any later version. *
* *
* This program is distributed in the hope that it will be useful, but WITHOUT *
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
* more details. *
* *
* You should have received a copy of the GNU General Public License along with *
* this program. If not, see <http://www.gnu.org/licenses/>. *
*******************************************************************************/
#ifndef REGISTRYNODETREE_H
#define REGISTRYNODETREE_H
#include <QTreeView>
#include <QAbstractItemModel>
#include <QContextMenuEvent>
#include <QMenu>
#include <QAction>
class RegistryNodeTree : public QTreeView {
Q_OBJECT
public:
RegistryNodeTree(QWidget *p_parent=0);
~RegistryNodeTree();
void setModel(QAbstractItemModel *p_model);
+ Q_SIGNALS:
+ void CurrentItemChanged(QModelIndex current);
+
protected:
// int sizeHintForColumn(int column) const;
void contextMenuEvent(QContextMenuEvent *p_event);
+ void keyPressEvent(QKeyEvent *p_event);
private:
QMenu *p_menu_copy;
QAction *p_action_copy_node_name;
QAction *p_action_copy_node_path;
+ void currentChanged(const QModelIndex &current,
+ const QModelIndex &previous);
private slots:
void SlotCopyNodeName();
void SlotCopyNodePath();
};
#endif // REGISTRYNODETREE_H
diff --git a/trunk/report_templates/SAM_UserAccounts.qs b/trunk/report_templates/SAM_UserAccounts.qs
index 7ae130a..08c8a3a 100644
--- a/trunk/report_templates/SAM_UserAccounts.qs
+++ b/trunk/report_templates/SAM_UserAccounts.qs
@@ -1,84 +1,85 @@
// See http://windowsir.blogspot.com/2006/08/getting-user-info-from-image.html
function print_table_row(cell01,cell02) {
println(" <tr><td>",cell01,"</td><td>",cell02,"</td></tr>");
}
function print_v_info(v_key_value,info_name,str_off) {
var offset=Number(RegistryKeyValueToVariant(v_key_value,"uint16",str_off))+0x0cc;
var len=Number(RegistryKeyValueToVariant(v_key_value,"uint16",str_off+4))/2;
if(len>0) print_table_row(info_name,RegistryKeyValueToVariant(v_key_value,"utf16",offset,len));
}
println("<html>");
println(" <head><title>User Accounts</title></head>");
println(" <body style=\"font-size:12\">");
println(" <h2>User accounts</h2>");
// Iterate over all user names
var user_names=GetRegistryNodes("\\SAM\\Domains\\Account\\Users\\Names");
for(var i=0;i<user_names.length;i++) {
println(" <p style=\"font-size:12; white-space:nowrap\">");
// Print user name
println(" <u>",user_names[i],"</u><br />");
println(" <table style=\"margin-left:20px; font-size:12\">");
// Get user rid stored in "default" key
var user_rid=GetRegistryKeyValue(String().concat("\\SAM\\Domains\\Account\\Users\\Names\\",user_names[i]),"");
user_rid=RegistryKeyTypeToString(user_rid.type);
println(" <tr><td>RID:</td><td>",Number(user_rid).toString(10)," (",user_rid,")","</td></tr>");
// RegistryKeyTypeToString returns the rid prepended with "0x". We have to remove that for further processing
user_rid=String(user_rid).substr(2);
// Get user's V key and print various infos
var v_key=GetRegistryKeyValue(String().concat("\\SAM\\Domains\\Account\\Users\\",user_rid),"V");
print_v_info(v_key.value,"Full name:",0x18);
print_v_info(v_key.value,"Comment:",0x24);
print_v_info(v_key.value,"Home directory:",0x48);
print_v_info(v_key.value,"Home directory drive:",0x54);
print_v_info(v_key.value,"Logon script path:",0x60);
print_v_info(v_key.value,"Profile path:",0x6c);
// Get user's F key and print various infos
var f_key=GetRegistryKeyValue(String().concat("\\SAM\\Domains\\Account\\Users\\",user_rid),"F");
print_table_row("Last login time:",RegistryKeyValueToVariant(f_key.value,"filetime",8));
print_table_row("Last pw change:",RegistryKeyValueToVariant(f_key.value,"filetime",24));
print_table_row("Last failed login:",RegistryKeyValueToVariant(f_key.value,"filetime",40));
print_table_row("Account expires:",RegistryKeyValueToVariant(f_key.value,"filetime",32));
print_table_row("Total logins:",RegistryKeyValueToVariant(f_key.value,"uint16",66));
print_table_row("Failed logins:",RegistryKeyValueToVariant(f_key.value,"uint16",64));
var acc_flags=Number(RegistryKeyValueToVariant(f_key.value,"uint16",56));
print(" <tr><td>Account flags:</td><td>");
if(acc_flags&0x0001) print("Disabled ");
if(acc_flags&0x0002) print("HomeDirReq ");
if(acc_flags&0x0004) print("PwNotReq ");
if(acc_flags&0x0008) print("TempDupAcc ");
// I don't think this would be useful to show
//if(acc_flags&0x0010) print("NormUserAcc ");
if(acc_flags&0x0020) print("MnsAcc ");
if(acc_flags&0x0040) print("DomTrustAcc ");
if(acc_flags&0x0080) print("WksTrustAcc ");
if(acc_flags&0x0100) print("SrvTrustAcc ");
if(acc_flags&0x0200) print("NoPwExpiry ");
if(acc_flags&0x0400) print("AccAutoLock ");
+ print(" (",acc_flags,")");
println("</td></tr>");
// Get password hint if available
var hint=GetRegistryKeyValue(String().concat("\\SAM\\Domains\\Account\\Users\\",user_rid),"UserPasswordHint");
if(typeof hint !== 'undefined') {
// Append missing trailing utf16 zero byte
hint.value.appendByte(0);
hint.value.appendByte(0);
print_table_row("Password hint:",RegistryKeyValueToVariant(hint.value,"utf16"));
}
// TODO: User group membership
println(" </table>");
println(" </p>");
}
println("</html>");

File Metadata

Mime Type
text/x-diff
Expires
Sat, Nov 23, 5:02 PM (1 d, 11 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1162992
Default Alt Text
(113 KB)

Event Timeline