Page MenuHomePhabricator

No OneTemporary

Size
414 KB
Referenced Files
None
Subscribers
None
This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/trunk/README b/trunk/README
index bd4a427..266c48d 100644
--- a/trunk/README
+++ b/trunk/README
@@ -1,214 +1,214 @@
FRED README FILE REVISION 1
Table of contents
0.0 Author and license stuff
1.0 What is fred? - A short description
2.0 Installation instructions
2.1 Prerequisits
2.1.1 Linux
2.1.2 Mac OSX
2.1.3 Windows
2.2 Installing a prebuild binary package
2.3 Installing from source
2.3.1 Shared vs static libhivex
2.3.2 Linux
2.3.2.1 Prerequisites
2.3.2.2 Compiling
2.3.2.3 Packaging
2.3.3 Mac OSX
2.3.3.1 Prerequisites
2.3.3.2 Compiling
2.3.3.3 Packaging
2.3.4 Windows
2.3.5 Crosscompiling for Windows
2.3.5.1 Prerequisites
2.3.5.1.1 Compiler
2.3.5.1.2 Qt
2.3.5.2 Compiling
2.3.5.3 Packaging
0.0 Author and license stuff
- fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu>
+ fred Copyright (c) 2011-2014 by Gillen Daniel <gillen.dan@pinguin.lu>
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/>.
1.0 What is fred? - A short description
Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor.
This project was born out of the need for a reasonably good registry hive
viewer for Linux to conduct forensic analysis. Therefore it includes some
functions not found in normal "free" registry editors like a hex viewer with
data interpreter and a reporting function that can easily be extended with
custom ECMAScript report templates.
2.0 Installation instructions
2.1 Prerequisits
If you are not going to use my prebuild packages, in addition to the
prerequisits below you probably will also need Richard W.M. Jones's libhivex
available from https://github.com/libguestfs/hivex.
2.1.1 Linux
Any Linux with Qt v4.x libraries.
2.1.2 Mac OSX
OSX v10.5 or above with Qt v4.x libraries.
2.1.3 Windows
Windows XP or newer with Qt v4.x libraries.
2.2 Installing a prebuild binary package
Chances are I provide prebuild binary packages for your OS (generally
Debian/Ubuntu, Mac OSX and Windows). If so, you can simply download them
from https://www.pinguin.lu.
ForDebian/Ubuntu, add my repository and execute the following command:
$ sudo apt-get install fred fred-reports
For Mac OSX and Windows, execute the installer and follow the on-screen
instructions.
If I have no prebuild binary packages for your OS, you will have to compile
fred by yourself. In this case, read the instructions under "Installing from
source".
2.3 Installing from source
Start by getting the source code from https://www.pinguin.lu and unpacking
it to some temporary directory. Under Linux and Mac OSX, use:
$ cd /some/temp/dir/
$ tar xfvz fred-x.x.x.tar.gz
Under Windows, use 7zip or alike to decompress the tar.gz file.
2.3.1 Shared vs static libhivex
When compiling fred from source, you have two possibilities how to include
libhivex. When using Linux, chances are your distribution has a package
for it available. In this case, you may install the binary and developper
version of it and go ahead to build fred. If your distribution has no
libhivex package available (Mac OSX and Windows definitely haven't), or
you want to use the latest version of it available that might fix some
bugs, make sure you use the "--static-hivex" command line option when
running my bootstrap.sh script. This will checkout, compile and statically
link the latest libhivex compatible with fred while building.
2.3.2 Linux
2.3.2.1 Prerequisites
TODO
2.3.2.2 Compiling
Compiling under Linux for Linux should be very simple. Just execute the
following commands:
$ cd /path/to/fred/source/
$ ./autogen.sh --platform=linux
Or, if you want to use the static libhivex:
$ cd /path/to/fred/source/
$ ./autogen.sh --static-hivex --platform=linux
2.3.2.3 Packaging
TODO
2.3.3 Mac OSX
2.3.3.1 Prerequisites
In order to compile fred under Mac OSX, you need to install the
following software:
- XCode from Apple
- Git from http://code.google.com/p/git-osx-installer/
- MacPorts from http://www.macports.org
- Qt 4.8.x library from http://qt-project.org
Aditionally, after installing MacPorts, install the following packages:
$ sudo port install ocaml libxml2 pkgconfig autoconf gettext
2.3.3.2 Compiling
Compilation should be straight forward executing the following command:
$ cd /path/to/fred/source/
$ ./autogen.sh --static-hivex --platform=mac
2.3.3.3 Packaging
TODO
2.3.4 Windows
Until beta5, fred for Windows was build under Windows. But it was a pain
in the bud to do so. Therefore I switched to crosscompiling under Linux
which works very well. If you want to build fred under Windows, good luck
and please, don't contact me if you have any problems! My only answer will
be:
Crosscompile under Linux!
2.3.5 Crosscompiling for Windows
2.3.5.1 Prerequisites
The following instructions are for Debian / Ubuntu like distros. If you
are using another distro, you will need to get the compiler and Qt on
your own.
2.3.5.1.1 Compiler
You need the mingw-w64 gcc and g++ compiler. When using Debian/Ubuntu
install the following packages:
$ sudo apt-get install mingw-w64 mingw-w64-tools g++-mingw-w64 \
gcc-mingw-w64 mingw-ocaml
2.3.5.1.2 Qt
After you have a compiler, you will need to crosscompile Qt as it is
currently not available as package. Start by getting the source:
$ cd /some/temp/dir/
$ QTU="http://download.qt-project.org/official_releases/qt/4.8/4.8.4"
$ QTP="qt-everywhere-opensource-src-4.8.4"
$ wget $QTU/$QTP.tar.gz
$ tar xfvz $QTP.tar.gz
$ cd $QTP
Unfortunately, Qt won't build until you apply two small patches:
$ SRC="/path/to/fred/source/qt_patches"
$ patch -p1 <"$SRC/mingw32-qt-4.8.0-no-webkit-tests.patch"
$ patch -p1 <"$SRC/qt-4.8.4-fix-sse-suppport-build-regression.patch"
Now configure, compile and install Qt (I compiled it on my dual Xeon
machine with 24 cores (using make -j24) which took about 5 minutes. It
might take a bit longer on your machine :-p):
$ sudo ./configure -prefix /opt/qt-4.8.4-mingw -opensource \
-no-qt3support -no-multimedia -no-audio-backend \
-no-phonon -no-phonon-backend -no-javascript-jit \
-nomake examples -nomake demos -nomake docs \
-xplatform win32-g++-4.6 \
-device-option CROSS_COMPILE=i686-w64-mingw32-
$ sudo make
$ sudo make install
If you are asking you why the heck I used sudo to run configure, well,
Qt likes to copy some files to the prefix dir in that step which will
fail if you aren't root.
2.3.5.3 Compiling
If all the above worked, you are ready to crosscompile fred:
$ cd /path/to/fred/source/
$ ./autogen.sh --static-hivex --platform=win32
The build process of hivex will probably complain and might even fail
with an error but normally the lib gets build before that without errors,
so just ignore it.
2.3.5.4 Packaging
TODO
diff --git a/trunk/argparser.cpp b/trunk/argparser.cpp
index fc162e7..bb9ab7f 100644
--- a/trunk/argparser.cpp
+++ b/trunk/argparser.cpp
@@ -1,133 +1,133 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 "argparser.h"
ArgParser::ArgParser(QStringList args) {
this->argv=QStringList(args);
this->argc=this->argv.count();
this->error_msg="";
this->parsed_args.clear();
}
QString ArgParser::GetErrorMsg() {
QString msg=this->error_msg;
this->error_msg="";
return msg;
}
bool ArgParser::ParseArgs() {
int i=0;
int sep_pos=0;
QString cur_arg="";
QString cur_arg_param="";
while(i+1<this->argc) {
// Get current argument
cur_arg=this->argv.at(++i);
if(cur_arg.size()>1) {
// Check for short mode command line args
if(cur_arg[0]=='-' && cur_arg[1]!='-') {
if(cur_arg=="-?" || cur_arg=="-h") {
this->parsed_args.insert(cur_arg.mid(1),QString());
continue;
} else if(cur_arg=="-v") {
this->parsed_args.insert(cur_arg.mid(1),QString());
continue;
} else {
// Unknown argument
this->SetError(QString("Unknown command line argument '%1'!")
.arg(cur_arg));
return false;
}
}
// Check for long mode command line args
if(cur_arg[0]=='-' && cur_arg[1]=='-') {
// Extract argument parameter if there is one
sep_pos=cur_arg.indexOf('=');
if(sep_pos!=-1) {
cur_arg_param=cur_arg.mid(sep_pos+1);
// Remove parameter from arg
cur_arg=cur_arg.left(sep_pos);
} else {
cur_arg_param="";
}
if(cur_arg=="--") {
// Stop processing arguments. Anything that follows this argument is
// considered to be a hive to open
i++;
break;
} else if(cur_arg=="--dump-report") {
this->parsed_args.insert(cur_arg.mid(2),cur_arg_param);
continue;
} else if(cur_arg=="--fullscreen") {
this->parsed_args.insert(cur_arg.mid(2),cur_arg_param);
continue;
} else if(cur_arg=="--help") {
this->parsed_args.insert(cur_arg.mid(2),QString());
continue;
} else if(cur_arg=="--maximized") {
this->parsed_args.insert(cur_arg.mid(2),cur_arg_param);
continue;
} else if(cur_arg=="--version") {
this->parsed_args.insert(cur_arg.mid(2),QString());
continue;
} else {
// Unknown argument
this->SetError(QString("Unknown command line argument '%1'!")
.arg(cur_arg));
return false;
}
}
}
// Found argument not beginning with '-' or '--'
if(i+1==this->argc) {
// If this is the last argument, it should be a hive file
this->parsed_args.insert(QString("hive-file"),cur_arg);
break;
} else {
// If it isn't the last argument, there is an error
this->SetError(QString("Unknown command line argument '%1'!")
.arg(cur_arg));
return false;
}
}
return true;
}
bool ArgParser::IsSet(QString arg) {
return this->parsed_args.contains(arg);
}
QString ArgParser::GetArgVal(QString arg) {
// If arg is not in parsed_args, the following will return a
// "default-constructed value" which should be a QString() according to the
// docs.
return this->parsed_args[arg];
}
void ArgParser::SetError(QString msg) {
this->error_msg=msg;
}
diff --git a/trunk/argparser.h b/trunk/argparser.h
index 0ca9259..a984c17 100644
--- a/trunk/argparser.h
+++ b/trunk/argparser.h
@@ -1,45 +1,45 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 ARGPARSER_H
#define ARGPARSER_H
#include <QString>
#include <QStringList>
#include <QHash>
class ArgParser {
public:
ArgParser(QStringList args);
QString GetErrorMsg();
bool ParseArgs();
bool IsSet(QString arg);
QString GetArgVal(QString arg);
private:
QStringList argv;
int argc;
QString error_msg;
QHash<QString,QString> parsed_args;
void SetError(QString msg=QString());
};
#endif // ARGPARSER_H
diff --git a/trunk/compileinfo.sh b/trunk/compileinfo.sh
index ba781e9..ffe38f0 100755
--- a/trunk/compileinfo.sh
+++ b/trunk/compileinfo.sh
@@ -1,46 +1,46 @@
#!/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_NAME_LONG "Forensic Registry EDitor"'
echo '#define APP_TITLE "Forensic Registry EDitor (fred)"'
-echo '#define APP_COPYRIGHT "Copyright (c) 2011-2013 by Gillen Daniel"'
+echo '#define APP_COPYRIGHT "Copyright (c) 2011-2014 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 features 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/datainterpretertable.cpp b/trunk/datainterpretertable.cpp
index 63e6aa6..a8aabcd 100644
--- a/trunk/datainterpretertable.cpp
+++ b/trunk/datainterpretertable.cpp
@@ -1,111 +1,111 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 <QHeaderView>
#include <QFontMetrics>
#include <QMenu>
#include <QApplication>
#include <QClipboard>
#include "datainterpretertable.h"
DataInterpreterTable::DataInterpreterTable(QWidget *p_parent)
: QTableWidget(p_parent)
{
this->setColumnCount(2);
this->setTextElideMode(Qt::ElideNone);
this->horizontalHeader()->setHidden(true);
this->verticalHeader()->setHidden(true);
this->setSelectionBehavior(QAbstractItemView::SelectRows);
this->setSelectionMode(QAbstractItemView::SingleSelection);
// Create context menu actions
this->p_action_copy_value=new QAction(tr("Copy value"),this);
this->connect(this->p_action_copy_value,
SIGNAL(triggered()),
this,
SLOT(SlotCopyValue()));
}
DataInterpreterTable::~DataInterpreterTable() {
// Free table widget items
this->ClearValues();
// Delete context menu actions
delete this->p_action_copy_value;
}
void DataInterpreterTable::AddValue(QString name, QString value) {
QTableWidgetItem *p_name_item=new QTableWidgetItem(name);
p_name_item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
QTableWidgetItem *p_value_item=new QTableWidgetItem(value);
p_value_item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
this->setRowCount(this->rowCount()+1);
this->setItem(this->rowCount()-1,0,p_name_item);
this->setItem(this->rowCount()-1,1,p_value_item);
this->resizeColumnsToContents();
this->resizeRowsToContents();
}
void DataInterpreterTable::ClearValues() {
// Free all items
while(this->rowCount()>0) {
delete this->item(0,0);
delete this->item(0,1);
this->setRowCount(this->rowCount()-1);
}
}
int DataInterpreterTable::sizeHintForColumn(int column) const {
int size_hint=0;
int i=0;
int item_width=0;
QFontMetrics fm(this->fontMetrics());
// Find string that needs the most amount of space
for(i=0;i<this->rowCount();i++) {
item_width=fm.width(this->item(i,column)->text())+10;
if(item_width>size_hint) size_hint=item_width;
}
return size_hint;
}
void DataInterpreterTable::contextMenuEvent(QContextMenuEvent *p_event) {
// Only show context menu when a node is selected
if(this->selectedIndexes().count()!=2) 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)))
{
return;
}
// Create context menu and add actions
QMenu context_menu(this);
context_menu.addAction(this->p_action_copy_value);
context_menu.exec(p_event->globalPos());
}
void DataInterpreterTable::SlotCopyValue() {
QApplication::clipboard()->
setText(this->selectedIndexes().at(1).data().toString(),
QClipboard::Clipboard);
}
diff --git a/trunk/datainterpretertable.h b/trunk/datainterpretertable.h
index 6fe37a0..33f6d18 100644
--- a/trunk/datainterpretertable.h
+++ b/trunk/datainterpretertable.h
@@ -1,68 +1,68 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 DATAINTERPRETERTABLE_H
#define DATAINTERPRETERTABLE_H
#include <QWidget>
#include <QTableWidget>
#include <QContextMenuEvent>
#include <QAction>
class DataInterpreterTable : public QTableWidget {
Q_OBJECT
public:
DataInterpreterTable(QWidget *p_parent=0);
~DataInterpreterTable();
/*
* AddValue
*
* Add a value pair (name,value) to data interprter.
*/
void AddValue(QString name, QString value);
/*
* ClearValues
*
* Remove all value pairs from table
*/
void ClearValues();
protected:
/*
* sizeHintForColumn
*
* Needed reimplementation in order to allow resizeColumnsToContent
* to resize hidden columns too.
*/
int sizeHintForColumn(int column) const;
void contextMenuEvent(QContextMenuEvent *p_event);
private:
QAction *p_action_copy_value;
private slots:
void SlotCopyValue();
};
#endif // DATAINTERPRETERTABLE_H
diff --git a/trunk/datainterpreterwidget.cpp b/trunk/datainterpreterwidget.cpp
index dc6dfa0..9caa0e4 100644
--- a/trunk/datainterpreterwidget.cpp
+++ b/trunk/datainterpreterwidget.cpp
@@ -1,201 +1,201 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 "datainterpreterwidget.h"
#include "registryhive.h"
DataInterpreterWidget::DataInterpreterWidget(QWidget *p_parent) :
QWidget(p_parent)
{
// Init private vars
this->data=QByteArray();
this->endianness=DataInterpreterWidget::Endianness_LittleEndian;
// Set widget layout. Setting it's parent to "this" will also call
// this->SetLayout.
this->p_widget_layout=new QVBoxLayout(this);
// Create sub-widgets
this->p_data_interpreter_table=new DataInterpreterTable();
this->p_endianness_selector_layout=new QHBoxLayout();
this->p_endianness_selector_le=new QRadioButton(tr("Little endian"));
this->p_endianness_selector_be=new QRadioButton(tr("Big endian"));
// Add endianness selector buttons to their layout
this->p_endianness_selector_layout->addWidget(this->p_endianness_selector_le);
this->p_endianness_selector_layout->addWidget(this->p_endianness_selector_be);
// Add sub-widgets to our layout
this->p_widget_layout->addWidget(this->p_data_interpreter_table);
this->p_widget_layout->addLayout(this->p_endianness_selector_layout);
// Configure widget and sub-widgets
this->setContentsMargins(0,0,0,0);
this->p_widget_layout->setContentsMargins(0,0,0,0);
this->p_endianness_selector_layout->setContentsMargins(0,0,0,0);
this->p_endianness_selector_le->setContentsMargins(0,0,0,0);
this->p_endianness_selector_be->setContentsMargins(0,0,0,0);
// Set initial endianness selector state
this->p_endianness_selector_le->setChecked(
(this->endianness==DataInterpreterWidget::Endianness_LittleEndian));
this->p_endianness_selector_be->setChecked(
(this->endianness==DataInterpreterWidget::Endianness_BigEndian));
// Connect signals
this->connect(this->p_endianness_selector_le,
SIGNAL(clicked(bool)),
this,
SLOT(SlotEndiannessSelectorLeClicked(bool)));
this->connect(this->p_endianness_selector_be,
SIGNAL(clicked(bool)),
this,
SLOT(SlotEndiannessSelectorBeClicked(bool)));
}
DataInterpreterWidget::~DataInterpreterWidget() {
delete this->p_endianness_selector_le;
delete this->p_endianness_selector_be;
delete this->p_endianness_selector_layout;
delete this->p_data_interpreter_table;
delete this->p_widget_layout;
}
void DataInterpreterWidget::SetData(QByteArray new_data) {
// Save new data and interpret it
this->data=new_data;
this->InterpretData();
}
void DataInterpreterWidget::InterpretData() {
// Get data length
int data_length=this->data.size();
// Remove old values from data interpreter table
this->p_data_interpreter_table->ClearValues();
if(data_length>=1) {
this->p_data_interpreter_table->AddValue("int8:",
RegistryHive::KeyValueToString(
this->data,
"int8"));
this->p_data_interpreter_table->AddValue("uint8:",
RegistryHive::KeyValueToString(
this->data,
"uint8"));
}
if(data_length>=2) {
this->p_data_interpreter_table->AddValue(
"int16:",
RegistryHive::KeyValueToString(
this->data,
"int16",
0,
0,
this->endianness==DataInterpreterWidget::Endianness_LittleEndian));
this->p_data_interpreter_table->AddValue(
"uint16:",
RegistryHive::KeyValueToString(
this->data,
"uint16",
0,
0,
this->endianness==DataInterpreterWidget::Endianness_LittleEndian));
}
if(data_length>=4) {
this->p_data_interpreter_table->AddValue(
"int32:",
RegistryHive::KeyValueToString(
this->data,
"int32",
0,
0,
this->endianness==DataInterpreterWidget::Endianness_LittleEndian));
this->p_data_interpreter_table->AddValue(
"uint32:",
RegistryHive::KeyValueToString(
this->data,
"uint32",
0,
0,
this->endianness==DataInterpreterWidget::Endianness_LittleEndian));
this->p_data_interpreter_table->AddValue(
"unixtime:",
RegistryHive::KeyValueToString(
this->data,
"unixtime",
0,
0,
this->endianness==DataInterpreterWidget::Endianness_LittleEndian));
}
if(data_length>=8) {
this->p_data_interpreter_table->AddValue(
"int64:",
RegistryHive::KeyValueToString(
this->data,
"int64",
0,
0,
this->endianness==DataInterpreterWidget::Endianness_LittleEndian));
this->p_data_interpreter_table->AddValue(
"uint64:",
RegistryHive::KeyValueToString(
this->data,
"uint64",
0,
0,
this->endianness==DataInterpreterWidget::Endianness_LittleEndian));
/*
TODO: Check how one could implement this
this->p_data_interpreter_table->AddValue(
"unixtime64:",
RegistryHive::KeyValueToString(
this->data,
"unixtime64",
0,
0,
this->endianness==DataInterpreterWidget::Endianness_LittleEndian));
*/
this->p_data_interpreter_table->AddValue(
"filetime64:",
RegistryHive::KeyValueToString(
this->data,
"filetime",
0,
0,
this->endianness==DataInterpreterWidget::Endianness_LittleEndian));
}
}
void DataInterpreterWidget::SlotEndiannessSelectorLeClicked(bool checked) {
if(checked) {
// Save selected endianness and update interpreted values
this->endianness=DataInterpreterWidget::Endianness_LittleEndian;
this->InterpretData();
}
}
void DataInterpreterWidget::SlotEndiannessSelectorBeClicked(bool checked) {
if(checked) {
// Save selected endianness and update interpreted values
this->endianness=DataInterpreterWidget::Endianness_BigEndian;
this->InterpretData();
}
}
diff --git a/trunk/datainterpreterwidget.h b/trunk/datainterpreterwidget.h
index 2c61367..00b08b1 100644
--- a/trunk/datainterpreterwidget.h
+++ b/trunk/datainterpreterwidget.h
@@ -1,72 +1,72 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 DATAINTERPRETERWIDGET_H
#define DATAINTERPRETERWIDGET_H
#include <QWidget>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QRadioButton>
#include <QString>
#include <QByteArray>
#include "datainterpretertable.h"
class DataInterpreterWidget : public QWidget {
Q_OBJECT
public:
enum Endianness {
Endianness_LittleEndian=0,
Endianness_BigEndian
};
explicit DataInterpreterWidget(QWidget *p_parent=0);
~DataInterpreterWidget();
/*
* SetData
*
* Set data to be interpreted (will also interpret it).
*/
void SetData(QByteArray new_data);
private:
// Widget layout
QVBoxLayout *p_widget_layout;
// Sub-widgets
DataInterpreterTable *p_data_interpreter_table;
QHBoxLayout *p_endianness_selector_layout;
QRadioButton *p_endianness_selector_le;
QRadioButton *p_endianness_selector_be;
// Vars
QByteArray data;
int endianness;
void InterpretData();
private slots:
void SlotEndiannessSelectorLeClicked(bool checked);
void SlotEndiannessSelectorBeClicked(bool checked);
};
#endif // DATAINTERPRETERWIDGET_H
diff --git a/trunk/dlgabout.cpp b/trunk/dlgabout.cpp
index 2582bd3..191c454 100644
--- a/trunk/dlgabout.cpp
+++ b/trunk/dlgabout.cpp
@@ -1,74 +1,74 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 "dlgabout.h"
#include "ui_dlgabout.h"
#include "compileinfo.h"
DlgAbout::DlgAbout(QWidget *parent) :
QDialog(parent),
m_ui(new Ui::DlgAbout)
{
m_ui->setupUi(this);
this->setWindowTitle(tr("About %1").arg(APP_NAME));
// Update dialog with current infos
this->m_ui->LblAbout->setText(
this->m_ui->LblAbout->text().replace("%APP_NAME_LONG%",APP_NAME_LONG));
this->m_ui->LblAbout->setText(
this->m_ui->LblAbout->text().replace("%APP_NAME%",APP_NAME));
this->m_ui->LblAbout->setText(
this->m_ui->LblAbout->text().replace("%APP_COPYRIGHT%",APP_COPYRIGHT));
this->m_ui->TextEditInfo->setPlainText(
this->m_ui->TextEditInfo->toPlainText().replace("%APP_NAME%",APP_NAME));
this->m_ui->TextEditInfo->setPlainText(
this->m_ui->TextEditInfo->toPlainText().replace("%APP_VERSION%",
APP_VERSION));
this->m_ui->TextEditInfo->setPlainText(
this->m_ui->TextEditInfo->toPlainText().replace("%APP_DESCRIPTION%",
APP_DESCRIPTION));
this->m_ui->TextEditCopyright->setPlainText(
this->m_ui->TextEditCopyright->toPlainText().replace("%APP_COPYRIGHT%",
APP_COPYRIGHT));
this->m_ui->TextEditCopyright->setPlainText(
this->m_ui->TextEditCopyright->toPlainText()
.replace("%APP_DEVELOPPER_EMAIL%",
APP_DEVELOPPER_EMAIL));
}
DlgAbout::~DlgAbout() {
delete m_ui;
}
void DlgAbout::changeEvent(QEvent *e) {
QDialog::changeEvent(e);
switch (e->type()) {
case QEvent::LanguageChange:
m_ui->retranslateUi(this);
break;
default:
break;
}
}
void DlgAbout::on_btnClose_clicked() {
this->accept();
}
diff --git a/trunk/dlgabout.h b/trunk/dlgabout.h
index 8d8c881..63815fc 100644
--- a/trunk/dlgabout.h
+++ b/trunk/dlgabout.h
@@ -1,47 +1,47 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 DLGABOUT_H
#define DLGABOUT_H
#include <QDialog>
namespace Ui {
class DlgAbout;
}
class DlgAbout : public QDialog {
Q_OBJECT
public:
DlgAbout(QWidget *parent = 0);
~DlgAbout();
protected:
void changeEvent(QEvent *e);
private:
Ui::DlgAbout *m_ui;
private slots:
void on_btnClose_clicked();
};
#endif // DLGABOUT_H
diff --git a/trunk/dlgaddkey.cpp b/trunk/dlgaddkey.cpp
index 2809e46..695ef44 100644
--- a/trunk/dlgaddkey.cpp
+++ b/trunk/dlgaddkey.cpp
@@ -1,441 +1,441 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 <QString>
#include <QStringList>
#include <QMessageBox>
#include <QRegExp>
#include <QtEndian>
#include <QDebug>
#include <stdlib.h>
#include "dlgaddkey.h"
#include "ui_dlgaddkey.h"
#include "registryhive.h"
DlgAddKey::DlgAddKey(QWidget *p_parent,
QString key_name,
QString key_value_type,
QByteArray key_value) :
QDialog(p_parent),
ui(new Ui::DlgAddKey)
{
this->p_current_widget=NULL;
ui->setupUi(this);
this->ansi_encoded=false;
// Create widgets
this->CreateValueWidgets();
// Set dialog title
if(key_name.isEmpty() && key_value_type.isEmpty() && key_value.isEmpty()) {
// If no values were passed, we consider this the ddd key dialog
this->setWindowTitle(tr("Add key"));
} else {
// If a value was passed, this is considered the edit key dialog
this->setWindowTitle(tr("Edit key"));
this->ui->EdtKeyName->setEnabled(false);
this->ui->CmbKeyType->setEnabled(false);
}
// Preload key value type values
QStringList value_types=RegistryHive::GetKeyValueTypes();
this->ui->CmbKeyType->addItems(value_types);
// Load values
if(!key_name.isEmpty()) this->ui->EdtKeyName->setText(key_name);
if(!key_value_type.isEmpty())
this->ui->CmbKeyType->setCurrentIndex(value_types.indexOf(key_value_type));
if(!key_value.isEmpty()) this->SetValueWidgetData(key_value,key_value_type);
// Connect signals
this->connect(this->p_number_widget_rb_dec,
SIGNAL(clicked(bool)),
this,
SLOT(SlotNumberWidgetRbDecClicked(bool)));
this->connect(this->p_number_widget_rb_hex,
SIGNAL(clicked(bool)),
this,
SLOT(SlotNumberWidgetRbHexClicked(bool)));
}
DlgAddKey::~DlgAddKey() {
this->DestroyValueWidgets();
delete ui;
}
QString DlgAddKey::KeyName() {
return this->ui->EdtKeyName->text();
}
QString DlgAddKey::KeyType() {
return this->ui->CmbKeyType->currentText();
}
QByteArray DlgAddKey::KeyValue() {
return this->GetValueWidgetData();
}
void DlgAddKey::on_BtnCancel_clicked() {
this->reject();
}
void DlgAddKey::on_BtnOk_clicked() {
QString key_value_type=this->KeyType();
// Check entered data for correctness
if(key_value_type=="REG_MULTI_SZ") {
// REG_MULTI_SZ's can't contain empty sub-strings
QString cur_data=this->p_text_widget_text_edit->toPlainText();
QString new_data=cur_data;
// TODO: Do we need to check for \r\n on Windows??
new_data.replace(QRegExp("\n\n*"),"\n");
if(new_data.startsWith("\n")) new_data.remove(0,1);
if(new_data.endsWith("\n")) new_data.chop(1);
if(cur_data!=new_data) {
if(QMessageBox::information(this,
tr("Invalid data"),
tr("A REG_MULTI_SZ can not contain empty "
"sub-strings! If you continue, they "
"will be removed."),
QMessageBox::Yes,
QMessageBox::No)==QMessageBox::Yes)
{
this->p_text_widget_text_edit->setPlainText(new_data);
} else {
return;
}
}
} else if(key_value_type=="REG_DWORD" ||
key_value_type=="REG_DWORD_BIG_ENDIAN")
{
bool ok=false;
if(this->p_number_widget_rb_dec->isChecked()) {
this->p_number_widget_line_edit->text().toUInt(&ok);
} else {
this->p_number_widget_line_edit->text().toUInt(&ok,16);
}
if(!ok) {
QMessageBox::information(this,
tr("Invalid data"),
tr("The value you entered could not be "
"converted to a %1! Please correct it.")
.arg(key_value_type),
QMessageBox::Ok);
return;
}
} else if(key_value_type=="REG_QWORD") {
bool ok=false;
if(this->p_number_widget_rb_dec->isChecked()) {
this->p_number_widget_line_edit->text().toULongLong(&ok);
} else {
this->p_number_widget_line_edit->text().toULongLong(&ok,16);
}
if(!ok) {
QMessageBox::information(this,
tr("Invalid data"),
tr("The value you entered could not be "
"converted to a %1! Please correct it.")
.arg(key_value_type),
QMessageBox::Ok);
return;
}
}
this->accept();
}
void DlgAddKey::on_CmbKeyType_currentIndexChanged(const QString &arg1) {
// Remove current widget from grid layout
if(this->p_current_widget!=NULL) {
this->ui->gridLayout->removeWidget(this->p_current_widget);
this->p_current_widget->setVisible(false);
this->p_current_widget=NULL;
}
// Add new widget for selected value type
if(arg1=="REG_SZ" || arg1=="REG_EXPAND_SZ") {
// Line edit widget for REG_SZ and REG_EXPAND_SZ
this->ui->gridLayout->addWidget(this->p_line_widget,2,1);
this->p_current_widget=this->p_line_widget;
} else if(arg1=="REG_MULTI_SZ") {
// Text edit widget for REG_MULTI_SZ
this->ui->gridLayout->addWidget(this->p_text_widget,2,1);
this->p_current_widget=this->p_text_widget;
} else if(arg1=="REG_DWORD" ||
arg1=="REG_DWORD_BIG_ENDIAN" ||
arg1=="REG_QWORD")
{
// Number widget for REG_DWORD, REG_DWORD_BIG_ENDIAN and REG_QWORD
this->ui->gridLayout->addWidget(this->p_number_widget,2,1);
this->p_current_widget=this->p_number_widget;
} else if(arg1=="REG_BINARY" ||
arg1=="REG_LINK" ||
arg1=="REG_RESOURCE_LIST" ||
arg1=="REG_FULL_RESOURCE_DESC" ||
arg1=="REG_RESOURCE_REQ_LIST")
{
// Binary widget for all other types
this->ui->gridLayout->addWidget(this->p_binary_widget,2,1);
this->p_current_widget=this->p_binary_widget;
}
if(arg1!="REG_NONE") {
this->p_current_widget->setVisible(true);
this->ui->LblKeyValue->setVisible(true);
} else {
this->ui->LblKeyValue->setVisible(false);
}
}
void DlgAddKey::SlotNumberWidgetRbDecClicked(bool checked) {
if(checked) {
bool ok=false;
if(this->KeyType()=="REG_QWORD") {
quint64 num=this->p_number_widget_line_edit->text().toULongLong(&ok,16);
if(ok) {
// Convert number to dec
this->p_number_widget_line_edit->setText(QString("%1").arg(num));
}
} else {
quint32 num=this->p_number_widget_line_edit->text().toUInt(&ok,16);
if(ok) {
// Convert number to dec
this->p_number_widget_line_edit->setText(QString("%1").arg(num));
}
}
if(!ok) {
QMessageBox::warning(this,
tr("Errror"),
tr("Unable to convert entered value to decimal!"),
QMessageBox::Ok);
this->p_number_widget_rb_hex->setChecked(true);
}
}
}
void DlgAddKey::SlotNumberWidgetRbHexClicked(bool checked) {
if(checked) {
bool ok=false;
if(this->KeyType()=="REG_QWORD") {
quint64 num=this->p_number_widget_line_edit->text().toULongLong(&ok);
if(ok) {
// Convert number to hex
this->p_number_widget_line_edit->setText(QString("%1")
.arg(num,16,16,QChar('0')));
}
} else {
quint32 num=this->p_number_widget_line_edit->text().toUInt(&ok);
if(ok) {
// Convert number to hex
this->p_number_widget_line_edit->setText(QString("%1")
.arg(num,8,16,QChar('0')));
}
}
if(!ok) {
QMessageBox::warning(this,
tr("Errror"),
tr("Unable to convert entered value to hex!"),
QMessageBox::Ok);
this->p_number_widget_rb_dec->setChecked(true);
}
}
}
void DlgAddKey::CreateValueWidgets() {
this->p_line_widget=new QWidget();
this->p_line_widget_layout=new QHBoxLayout(this->p_line_widget);
//this->p_line_widget_layout_rb_ansi=new QRadioButton(tr("Ansi"));
//this->p_line_widget_layout_rb_unicode=new QRadioButton(tr("Unicode"));
//this->p_line_widget_layout_rb_unicode->setChecked(true);
this->p_line_widget_line_edit=new QLineEdit();
this->p_line_widget->setContentsMargins(0,0,0,0);
this->p_line_widget_layout->setContentsMargins(0,0,0,0);
this->p_line_widget_layout->addWidget(this->p_line_widget_line_edit);
//this->p_line_widget_layout->addWidget(this->p_line_widget_layout_rb_ansi);
//this->p_line_widget_layout->addWidget(this->p_line_widget_layout_rb_unicode);
this->p_text_widget=new QWidget();
this->p_text_widget_layout=new QHBoxLayout(this->p_text_widget);
this->p_text_widget_text_edit=new QPlainTextEdit();
this->p_text_widget->setContentsMargins(0,0,0,0);
this->p_text_widget_layout->setContentsMargins(0,0,0,0);
this->p_text_widget_layout->addWidget(this->p_text_widget_text_edit);
this->p_number_widget=new QWidget();
this->p_number_widget_layout=new QHBoxLayout(this->p_number_widget);
this->p_number_widget_line_edit=new QLineEdit();
this->p_number_widget_rb_dec=new QRadioButton(tr("Dec base"));
this->p_number_widget_rb_dec->setChecked(true);
this->p_number_widget_rb_hex=new QRadioButton(tr("Hex base"));
this->p_number_widget->setContentsMargins(0,0,0,0);
this->p_number_widget_layout->setContentsMargins(0,0,0,0);
this->p_number_widget_layout->addWidget(this->p_number_widget_line_edit);
this->p_number_widget_layout->addWidget(this->p_number_widget_rb_dec);
this->p_number_widget_layout->addWidget(this->p_number_widget_rb_hex);
this->p_binary_widget=new QWidget();
this->p_binary_widget_layout=new QHBoxLayout(this->p_binary_widget);
this->p_binary_widget_hex_edit=new HexEditWidget(this,false,false);
this->p_binary_widget->setContentsMargins(0,0,0,0);
this->p_binary_widget_layout->setContentsMargins(0,0,0,0);
this->p_binary_widget_layout->addWidget(this->p_binary_widget_hex_edit);
}
void DlgAddKey::DestroyValueWidgets() {
//delete this->p_line_widget_layout_rb_ansi;
//delete this->p_line_widget_layout_rb_unicode;
delete this->p_line_widget_line_edit;
delete this->p_line_widget_layout;
delete this->p_line_widget;
delete this->p_text_widget_text_edit;
delete this->p_text_widget_layout;
delete this->p_text_widget;
delete this->p_number_widget_rb_hex;
delete this->p_number_widget_rb_dec;
delete this->p_number_widget_line_edit;
delete this->p_number_widget_layout;
delete this->p_number_widget;
delete this->p_binary_widget_hex_edit;
delete this->p_binary_widget_layout;
delete this->p_binary_widget;
}
void DlgAddKey::SetValueWidgetData(QByteArray &key_value,
QString &key_value_type)
{
if(key_value_type=="REG_SZ" || key_value_type=="REG_EXPAND_SZ") {
this->p_line_widget_line_edit->setText(
RegistryHive::KeyValueToString(key_value,
RegistryHive::StringToKeyValueType(
key_value_type)));
} else if(key_value_type=="REG_MULTI_SZ") {
QStringList strings=
RegistryHive::KeyValueToStringList(key_value,&(this->ansi_encoded));
this->p_text_widget_text_edit->setPlainText(strings.join("\n"));
} else if(key_value_type=="REG_DWORD") {
this->p_number_widget_line_edit->setText(
RegistryHive::KeyValueToString(key_value,"uint32"));
} else if(key_value_type=="REG_DWORD_BIG_ENDIAN") {
this->p_number_widget_line_edit->setText(
RegistryHive::KeyValueToString(key_value,"uint32",0,0,false));
} else if(key_value_type=="REG_QWORD") {
this->p_number_widget_line_edit->setText(
RegistryHive::KeyValueToString(key_value,"uint64",0,0,false));
} else if(key_value_type=="REG_BINARY" ||
key_value_type=="REG_LINK" ||
key_value_type=="REG_RESOURCE_LIST" ||
key_value_type=="REG_FULL_RESOURCE_DESC" ||
key_value_type=="REG_RESOURCE_REQ_LIST")
{
this->p_binary_widget_hex_edit->SetData(key_value);
}
}
QByteArray DlgAddKey::GetValueWidgetData() {
QString key_value_type=this->KeyType();
if(key_value_type=="REG_SZ" || key_value_type=="REG_EXPAND_SZ") {
// TODO: Wouldn't it be wise to let the user choose the encoding?
// Get data
QString data=this->p_line_widget_line_edit->text();
// Convert data to UTF16LE buffer
quint16 *p_buf=NULL;
int buf_len=this->ToUtf16LeBuf(&p_buf,data.utf16(),data.size());
if(p_buf==NULL || buf_len==0) {
// TODO: Inform user there was an error???
return QByteArray("\x00\x00",2);
}
// Construct ByteArray, free buffer and return
QByteArray ret=QByteArray((char*)p_buf,buf_len);
free(p_buf);
return ret;
} else if(key_value_type=="REG_MULTI_SZ") {
// TODO: Let the user choose the encoding / endianness
// TODO: Do we need to check for \r\n on Windows??
return RegistryHive::StringListToKeyValue(
this->p_text_widget_text_edit->
toPlainText().split("\n",
QString::SkipEmptyParts),
true,
this->ansi_encoded);
} else if(key_value_type=="REG_DWORD" ||
key_value_type=="REG_DWORD_BIG_ENDIAN")
{
quint32 val;
if(this->p_number_widget_rb_dec->isChecked()) {
val=this->p_number_widget_line_edit->text().toUInt();
} else {
val=this->p_number_widget_line_edit->text().toUInt(0,16);
}
if(key_value_type=="REG_DWORD") val=qToLittleEndian(val);
else val=qToBigEndian(val);
return QByteArray((char*)&val,4);
} else if(key_value_type=="REG_QWORD") {
quint64 val;
if(this->p_number_widget_rb_dec->isChecked()) {
val=this->p_number_widget_line_edit->text().toULongLong();
} else {
val=this->p_number_widget_line_edit->text().toULongLong(0,16);
}
val=qToLittleEndian(val);
return QByteArray((char*)&val,8);
} else if(key_value_type=="REG_BINARY" ||
key_value_type=="REG_LINK" ||
key_value_type=="REG_RESOURCE_LIST" ||
key_value_type=="REG_FULL_RESOURCE_DESC" ||
key_value_type=="REG_RESOURCE_REQ_LIST")
{
return this->p_binary_widget_hex_edit->GetData();
}
return QByteArray();
}
int DlgAddKey::ToUtf16LeBuf(quint16 **pp_buf,
const quint16 *p_data,
int ascii_len)
{
// Calculate utf16 buffer size
// TODO: This fails if there are chars that need more than 16bit!!
int buf_len=(ascii_len*2)+2;
// Alloc buffer and set to 0x00h
*pp_buf=(quint16*)malloc(buf_len);
if(*pp_buf==NULL) return 0;
memset(*pp_buf,0,buf_len);
if(ascii_len==0) {
// Empty string, we're done (buffer contains \0\0)
return buf_len;
}
// Fill buffer with UTF16 string (ignoring \0\0 at the end)
memcpy(*pp_buf,p_data,buf_len-2);
// Make sure endianness is LE
for(int i=0;i<ascii_len;i++) {
(*pp_buf)[i]=qToLittleEndian((*pp_buf)[i]);
}
return buf_len;
}
diff --git a/trunk/dlgaddkey.h b/trunk/dlgaddkey.h
index 81cf1c5..1442309 100644
--- a/trunk/dlgaddkey.h
+++ b/trunk/dlgaddkey.h
@@ -1,87 +1,87 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 DLGADDKEY_H
#define DLGADDKEY_H
#include <QDialog>
#include <QWidget>
#include <QHBoxLayout>
#include <QLineEdit>
#include <QPlainTextEdit>
#include <QRadioButton>
#include "hexeditwidget.h"
namespace Ui {
class DlgAddKey;
}
class DlgAddKey : public QDialog {
Q_OBJECT
public:
explicit DlgAddKey(QWidget *p_parent=0,
QString key_name=QString(),
QString key_value_type=QString(),
QByteArray key_value=QByteArray());
~DlgAddKey();
QString KeyName();
QString KeyType();
QByteArray KeyValue();
private slots:
void on_BtnCancel_clicked();
void on_BtnOk_clicked();
void on_CmbKeyType_currentIndexChanged(const QString &arg1);
void SlotNumberWidgetRbDecClicked(bool checked);
void SlotNumberWidgetRbHexClicked(bool checked);
private:
Ui::DlgAddKey *ui;
QWidget *p_current_widget;
QWidget *p_line_widget;
QHBoxLayout *p_line_widget_layout;
//QRadioButton *p_line_widget_layout_rb_ansi;
//QRadioButton *p_line_widget_layout_rb_unicode;
QLineEdit *p_line_widget_line_edit;
QWidget *p_text_widget;
QHBoxLayout *p_text_widget_layout;
QPlainTextEdit *p_text_widget_text_edit;
QWidget *p_number_widget;
QHBoxLayout *p_number_widget_layout;
QLineEdit *p_number_widget_line_edit;
QRadioButton *p_number_widget_rb_dec;
QRadioButton *p_number_widget_rb_hex;
QWidget *p_binary_widget;
QHBoxLayout *p_binary_widget_layout;
HexEditWidget *p_binary_widget_hex_edit;
bool ansi_encoded;
void CreateValueWidgets();
void DestroyValueWidgets();
void SetValueWidgetData(QByteArray &key_value, QString &key_value_type);
QByteArray GetValueWidgetData();
int ToUtf16LeBuf(quint16 **pp_buf, const quint16 *p_data, int ascii_len);
void SetNumberWidgetLineEditInputMask();
};
#endif // DLGADDKEY_H
diff --git a/trunk/dlgpreferences.cpp b/trunk/dlgpreferences.cpp
index 8a8b4b7..d275425 100644
--- a/trunk/dlgpreferences.cpp
+++ b/trunk/dlgpreferences.cpp
@@ -1,235 +1,235 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 <QString>
#include <QStringList>
#include <QListIterator>
#include <QModelIndexList>
#include <QFileDialog>
#include <QMessageBox>
#include <QDebug>
#include "dlgpreferences.h"
#include "ui_dlgpreferences.h"
/*******************************************************************************
* Public
******************************************************************************/
DlgPreferences::DlgPreferences(Settings *p_sets, QWidget *p_parent) :
QDialog(p_parent), ui(new Ui::DlgPreferences)
{
ui->setupUi(this);
this->p_settings=p_sets;
// Load current values
this->LoadPreferences();
}
DlgPreferences::~DlgPreferences() {
delete ui;
}
/*******************************************************************************
* Private slots
******************************************************************************/
void DlgPreferences::on_BtnCancel_clicked() {
this->reject();
}
void DlgPreferences::on_ListReportLocations_clicked(const QModelIndex &index) {
if(!index.isValid()) {
// No valid row selected, disable some buttons
this->ui->BtnEditReportLoc->setEnabled(false);
this->ui->BtnRemoveReportLoc->setEnabled(false);
this->ui->BtnMoveReportLocUp->setEnabled(false);
this->ui->BtnMoveReportLocDown->setEnabled(false);
this->ui->BtnAddReportLoc->setFocus();
return;
}
if(this->ui->ListReportLocations->count()==1) {
// Only one item left, disable up/down buttons
this->ui->BtnEditReportLoc->setEnabled(true);
this->ui->BtnRemoveReportLoc->setEnabled(true);
this->ui->BtnMoveReportLocUp->setEnabled(false);
this->ui->BtnMoveReportLocDown->setEnabled(false);
return;
}
if(index.row()==0) {
// First row selected, disable up button
this->ui->BtnEditReportLoc->setEnabled(true);
this->ui->BtnRemoveReportLoc->setEnabled(true);
this->ui->BtnMoveReportLocUp->setEnabled(false);
this->ui->BtnMoveReportLocDown->setEnabled(true);
return;
}
if(index.row()==(this->ui->ListReportLocations->count()-1)) {
// Last row selected, disable down button
this->ui->BtnEditReportLoc->setEnabled(true);
this->ui->BtnRemoveReportLoc->setEnabled(true);
this->ui->BtnMoveReportLocUp->setEnabled(true);
this->ui->BtnMoveReportLocDown->setEnabled(false);
return;
}
// Any other valid row selected, enable up/down buttons
this->ui->BtnEditReportLoc->setEnabled(true);
this->ui->BtnRemoveReportLoc->setEnabled(true);
this->ui->BtnMoveReportLocUp->setEnabled(true);
this->ui->BtnMoveReportLocDown->setEnabled(true);
}
void DlgPreferences::on_BtnAddReportLoc_clicked() {
QString new_loc=QFileDialog::getExistingDirectory(this,
tr("Select new report "
"directory"));
if(!new_loc.isEmpty()) {
this->ui->ListReportLocations->addItem(new_loc);
}
}
void DlgPreferences::on_BtnEditReportLoc_clicked() {
QModelIndex cur_item=this->ui->ListReportLocations->currentIndex();
if(!cur_item.isValid()) return;
// Get selected item
QListWidgetItem *p_item=this->ui->ListReportLocations->item(cur_item.row());
// Let user select new directory
QString new_loc=QFileDialog::getExistingDirectory(this,
tr("Edit report directory"),
p_item->text());
if(!new_loc.isEmpty()) {
p_item->setText(new_loc);
}
}
void DlgPreferences::on_BtnRemoveReportLoc_clicked() {
QModelIndex cur_item=this->ui->ListReportLocations->currentIndex();
if(!cur_item.isValid()) return;
QListWidgetItem *p_item=
this->ui->ListReportLocations->takeItem(cur_item.row());
delete p_item;
// Update buttons
this->on_ListReportLocations_clicked(
this->ui->ListReportLocations->currentIndex());
}
void DlgPreferences::on_BtnMoveReportLocUp_clicked() {
QModelIndex cur_item=this->ui->ListReportLocations->currentIndex();
if(!cur_item.isValid() || cur_item.row()==0) return;
// Move selected item up
QListWidgetItem *p_item=
this->ui->ListReportLocations->takeItem(cur_item.row());
this->ui->ListReportLocations->insertItem(cur_item.row()-1,p_item);
// Reselect moved item and update buttons
this->ui->ListReportLocations->setCurrentItem(p_item);
this->on_ListReportLocations_clicked(
this->ui->ListReportLocations->currentIndex());
}
void DlgPreferences::on_BtnMoveReportLocDown_clicked() {
QModelIndex cur_item=this->ui->ListReportLocations->currentIndex();
if(!cur_item.isValid() ||
cur_item.row()==(this->ui->ListReportLocations->count()-1))
{
return;
}
// Move selected item up
QListWidgetItem *p_item=
this->ui->ListReportLocations->takeItem(cur_item.row());
this->ui->ListReportLocations->insertItem(cur_item.row()+1,p_item);
// Reselect moved item and update buttons
this->ui->ListReportLocations->setCurrentItem(p_item);
this->on_ListReportLocations_clicked(
this->ui->ListReportLocations->currentIndex());
}
void DlgPreferences::on_BtnReset_clicked() {
if(QMessageBox::warning(this,
tr("Reset default settings"),
tr("Are you sure to reset all settings to their defaults?"),
QMessageBox::No,
QMessageBox::Yes)==QMessageBox::Yes)
{
this->p_settings->Reset();
this->LoadPreferences();
}
}
void DlgPreferences::on_BtnOk_clicked() {
this->SavePreferences();
this->accept();
}
/*******************************************************************************
* Private
******************************************************************************/
void DlgPreferences::LoadPreferences() {
// Load general preferences
this->ui->SpinBoxRecentFiles->setValue(
this->p_settings->GetRecentFilesDepth());
this->ui->ChkBoxSavePositions->setChecked(
this->p_settings->GetWindowGeometryStatus());
this->ui->ChkBoxOpenReadOnly->setChecked(
this->p_settings->GetOpenHivesReadOnly());
// Populate report location list
this->ui->ListReportLocations->clear();
QStringList report_dirs=this->p_settings->GetReportTemplateDirs();
QListIterator<QString> it_report_dirs(report_dirs);
if(!report_dirs.isEmpty()) {
while(it_report_dirs.hasNext()) {
this->ui->ListReportLocations->addItem(it_report_dirs.next());
}
this->ui->ListReportLocations->setCurrentRow(0);
this->ui->BtnEditReportLoc->setEnabled(true);
this->ui->BtnRemoveReportLoc->setEnabled(true);
this->ui->BtnMoveReportLocDown->setEnabled(true);
}
}
void DlgPreferences::SavePreferences() {
// Save general preferences
this->p_settings->SetRecentFilesDepth(this->ui->SpinBoxRecentFiles->value());
this->p_settings->SetWindowGeometryStatus(
this->ui->ChkBoxSavePositions->isChecked());
this->p_settings->SetOpenHivesReadOnly(
this->ui->ChkBoxOpenReadOnly->isChecked());
// Save report location list
QStringList report_dirs;
for(int i=0;i<this->ui->ListReportLocations->count();i++) {
report_dirs.append(this->ui->ListReportLocations->item(i)->text());
}
this->p_settings->SetReportTemplateDirs(report_dirs);
}
diff --git a/trunk/dlgpreferences.h b/trunk/dlgpreferences.h
index af342b8..35d6cb0 100644
--- a/trunk/dlgpreferences.h
+++ b/trunk/dlgpreferences.h
@@ -1,60 +1,60 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 DLGPREFERENCES_H
#define DLGPREFERENCES_H
#include <QDialog>
#include <QModelIndex>
#include "settings.h"
namespace Ui {
class DlgPreferences;
}
class DlgPreferences : public QDialog {
Q_OBJECT
public:
explicit DlgPreferences(Settings *p_sets, QWidget *p_parent=0);
~DlgPreferences();
private slots:
void on_BtnCancel_clicked();
void on_ListReportLocations_clicked(const QModelIndex &index);
void on_BtnAddReportLoc_clicked();
void on_BtnEditReportLoc_clicked();
void on_BtnRemoveReportLoc_clicked();
void on_BtnMoveReportLocUp_clicked();
void on_BtnMoveReportLocDown_clicked();
void on_BtnReset_clicked();
void on_BtnOk_clicked();
private:
Ui::DlgPreferences *ui;
Settings *p_settings;
void LoadPreferences();
void SavePreferences();
};
#endif // DLGPREFERENCES_H
diff --git a/trunk/dlgreportchooser.cpp b/trunk/dlgreportchooser.cpp
index d433f1c..21087d5 100644
--- a/trunk/dlgreportchooser.cpp
+++ b/trunk/dlgreportchooser.cpp
@@ -1,159 +1,159 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 <QString>
#include <QStringList>
#include <QListIterator>
#include <QDebug>
#include "dlgreportchooser.h"
#include "ui_dlgreportchooser.h"
DlgReportChooser::DlgReportChooser(Reports *p_reps,
QString hive_type_string,
Settings *p_sets,
QWidget *p_parent)
: QDialog(p_parent), ui(new Ui::DlgReportChooser)
{
QStringList tree_cats;
QString cur_tree_cat;
QTreeWidgetItem *p_tree_cat_widget;
QTreeWidgetItem *p_tree_cat_rep_widget;
QList<ReportTemplate*> tree_cat_reports;
ReportTemplate* p_report;
// Init private vars
this->ui->setupUi(this);
this->p_reports=p_reps;
this->p_settings=p_sets;
this->hive_type=hive_type_string;
this->tree_category_items.clear();
this->selected_reports.clear();
// Restore dialog geometry if possible
QByteArray geometry=this->p_settings->GetWindowGeometry("DlgReportChooser");
if(!geometry.isEmpty()) this->restoreGeometry(geometry);
// Populate tree with reports
tree_cats=this->p_reports->GetAvailableReportCategories();
QListIterator<QString> tree_cat_it(tree_cats);
while(tree_cat_it.hasNext()) {
cur_tree_cat=tree_cat_it.next();
p_tree_cat_widget=new QTreeWidgetItem(this->ui->TrReports);
p_tree_cat_widget->setText(0,cur_tree_cat);
p_tree_cat_widget->setFlags(Qt::ItemIsEnabled|
Qt::ItemIsUserCheckable|
Qt::ItemIsTristate);
p_tree_cat_widget->setCheckState(0,Qt::Unchecked);
tree_cat_reports=this->p_reports->GetAvailableReports(cur_tree_cat);
QListIterator<ReportTemplate*> tree_cat_rep_it(tree_cat_reports);
while(tree_cat_rep_it.hasNext()) {
p_report=tree_cat_rep_it.next();
p_tree_cat_rep_widget=new QTreeWidgetItem(p_tree_cat_widget);
// Save pointer to ReportTemplate alongside
p_tree_cat_rep_widget->setData(0,
Qt::UserRole,
QVariant().fromValue(p_report));
p_tree_cat_rep_widget->setText(0,p_report->Name());
p_tree_cat_rep_widget->setFlags(Qt::ItemIsEnabled|
Qt::ItemIsSelectable|
Qt::ItemIsUserCheckable);
if(this->hive_type!="UNKNOWN" && this->hive_type==p_report->Hive()) {
p_tree_cat_rep_widget->setCheckState(0,Qt::Checked);
} else {
p_tree_cat_rep_widget->setCheckState(0,Qt::Unchecked);
}
}
this->tree_category_items.append(p_tree_cat_widget);
}
// Finally, expand all categories
this->ui->TrReports->expandAll();
}
DlgReportChooser::~DlgReportChooser() {
// Save dialog geometry
this->p_settings->SetWindowGeometry("DlgReportChooser",this->saveGeometry());
delete this->ui;
}
QList<ReportTemplate*> DlgReportChooser::GetSelectedReports()
{
return this->selected_reports;
}
void DlgReportChooser::changeEvent(QEvent *p_event) {
QDialog::changeEvent(p_event);
switch (p_event->type()) {
case QEvent::LanguageChange:
this->ui->retranslateUi(this);
break;
default:
break;
}
}
void DlgReportChooser::on_BtnCancel_clicked() {
this->reject();
}
void DlgReportChooser::on_TrReports_currentItemChanged(
QTreeWidgetItem *p_current, QTreeWidgetItem *p_previous)
{
Q_UNUSED(p_previous)
// If item has no parent, clear labels and return
if(p_current->parent()==NULL) {
this->ui->LblHive->clear();
this->ui->LblAuthor->clear();
this->ui->LblDesc->clear();
return;
}
// Update labels
this->ui->LblHive->setText(
p_current->data(0,Qt::UserRole).value<ReportTemplate*>()->Hive());
this->ui->LblAuthor->setText(
p_current->data(0,Qt::UserRole).value<ReportTemplate*>()->Author());
this->ui->LblDesc->setText(
p_current->data(0,Qt::UserRole).value<ReportTemplate*>()->Description());
}
void DlgReportChooser::on_BtnGenerate_clicked() {
QTreeWidgetItem *p_cat;
int i;
// Add selected reports to selected_reports
QListIterator<QTreeWidgetItem*> cat_it(this->tree_category_items);
while(cat_it.hasNext()) {
p_cat=cat_it.next();
for(i=0;i<p_cat->childCount();i++) {
if(p_cat->child(i)->checkState(0)==Qt::Checked) {
// Get saved pointer to ReportTemplate and append it to selected_reps
this->selected_reports.append(p_cat->
child(i)->data(0,Qt::UserRole).value<ReportTemplate*>());
}
}
}
this->accept();
}
diff --git a/trunk/dlgreportchooser.h b/trunk/dlgreportchooser.h
index 4c05951..d87b41f 100644
--- a/trunk/dlgreportchooser.h
+++ b/trunk/dlgreportchooser.h
@@ -1,65 +1,65 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 DLGREPORTCHOOSER_H
#define DLGREPORTCHOOSER_H
#include <QDialog>
#include <QList>
#include <QTreeWidgetItem>
#include "reports.h"
#include "settings.h"
namespace Ui {
class DlgReportChooser;
}
class DlgReportChooser : public QDialog {
Q_OBJECT
public:
explicit DlgReportChooser(Reports *p_reps,
QString hive_type_string,
Settings *p_sets,
QWidget *p_parent=0);
~DlgReportChooser();
QList<ReportTemplate*> GetSelectedReports();
protected:
void changeEvent(QEvent *p_event);
private slots:
void on_BtnCancel_clicked();
void on_TrReports_currentItemChanged(QTreeWidgetItem *p_current,
QTreeWidgetItem *p_previous);
void on_BtnGenerate_clicked();
private:
Ui::DlgReportChooser *ui;
Reports *p_reports;
Settings *p_settings;
QString hive_type;
QList<QTreeWidgetItem*> tree_category_items;
QList<ReportTemplate*> selected_reports;
};
#endif // DLGREPORTCHOOSER_H
diff --git a/trunk/dlgreportviewer.cpp b/trunk/dlgreportviewer.cpp
index 697d818..838a1e3 100644
--- a/trunk/dlgreportviewer.cpp
+++ b/trunk/dlgreportviewer.cpp
@@ -1,116 +1,116 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 <QPrinter>
#include <QPrintDialog>
#include <QFileDialog>
#include <QTextDocument>
#include <QTextDocumentWriter>
#include "dlgreportviewer.h"
#include "ui_dlgreportviewer.h"
DlgReportViewer::DlgReportViewer(QString &report_data,
Settings *p_sets,
QWidget *p_parent)
: QMainWindow(p_parent,Qt::Dialog | Qt::Popup), ui(new Ui::DlgReportViewer)
{
// Init local vars
ui->setupUi(this);
this->p_local_event_loop=NULL;
this->orig_report_data=report_data;
this->p_settings=p_sets;
// Try to restore dialog geometry
QByteArray geometry=this->p_settings->GetWindowGeometry("DlgReportViewer");
if(!geometry.isEmpty()) this->restoreGeometry(geometry);
// Set report content
this->ui->WebView->setHtml(report_data);
// Set dialog title based on report content title
QString report_title=this->ui->WebView->title();
this->setWindowTitle("Report Viewer");
}
DlgReportViewer::~DlgReportViewer() {
// Save dialog geometry
this->p_settings->SetWindowGeometry("DlgReportViewer",this->saveGeometry());
delete ui;
if(this->p_local_event_loop!=NULL) this->p_local_event_loop->exit();
}
void DlgReportViewer::changeEvent(QEvent *p_event) {
QMainWindow::changeEvent(p_event);
switch(p_event->type()) {
case QEvent::LanguageChange:
ui->retranslateUi(this);
break;
default:
break;
}
}
void DlgReportViewer::closeEvent(QCloseEvent *p_event) {
// Make sure we exit the local event loop on exit
if(this->p_local_event_loop!=NULL) {
this->p_local_event_loop->exit();
this->p_local_event_loop=NULL;
}
p_event->accept();
}
void DlgReportViewer::exec() {
// Create local event loop
this->p_local_event_loop=new QEventLoop(this);
// Show window and enter loop
this->show();
this->p_local_event_loop->exec();
}
void DlgReportViewer::on_action_Print_triggered() {
// Print report
QPrinter printer;
QPrintDialog *p_dlg_print=new QPrintDialog(&printer);
if(p_dlg_print->exec()==QDialog::Accepted) {
this->ui->WebView->print(&printer);
}
delete p_dlg_print;
}
void DlgReportViewer::on_action_Close_triggered() {
this->close();
}
void DlgReportViewer::on_action_Save_triggered() {
QString filename=QFileDialog::getSaveFileName(this,
tr("Save report as"),
"",
"ODF file (*.odf)");
if(filename!="") {
QTextDocument *p_doc=new QTextDocument(this);
p_doc->setHtml(this->orig_report_data);
QTextDocumentWriter *p_doc_writer=new QTextDocumentWriter(filename);
p_doc_writer->setFormat(QByteArray("ODF"));
p_doc_writer->write(p_doc);
delete p_doc_writer;
delete p_doc;
}
}
diff --git a/trunk/dlgreportviewer.h b/trunk/dlgreportviewer.h
index 3472cee..4c05646 100644
--- a/trunk/dlgreportviewer.h
+++ b/trunk/dlgreportviewer.h
@@ -1,62 +1,62 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 DLGREPORTVIEWER_H
#define DLGREPORTVIEWER_H
#include <QMainWindow>
#include <QEventLoop>
#include <QCloseEvent>
#include "settings.h"
namespace Ui {
class DlgReportViewer;
}
class DlgReportViewer : public QMainWindow {
Q_OBJECT
public:
explicit DlgReportViewer(QString &report_data,
Settings *p_sets,
QWidget *p_parent=0);
~DlgReportViewer();
void exec();
protected:
void changeEvent(QEvent *p_event);
void closeEvent(QCloseEvent *p_event);
private slots:
void on_action_Print_triggered();
void on_action_Close_triggered();
void on_action_Save_triggered();
private:
Ui::DlgReportViewer *ui;
QEventLoop *p_local_event_loop;
QString orig_report_data;
Settings *p_settings;
};
#endif // DLGREPORTVIEWER_H
diff --git a/trunk/dlgsearch.cpp b/trunk/dlgsearch.cpp
index 12179c7..8a34e3b 100644
--- a/trunk/dlgsearch.cpp
+++ b/trunk/dlgsearch.cpp
@@ -1,136 +1,136 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 <QMessageBox>
#include "dlgsearch.h"
#include "ui_dlgsearch.h"
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 8ebb8f6..9cb34d8 100644
--- a/trunk/dlgsearch.h
+++ b/trunk/dlgsearch.h
@@ -1,64 +1,64 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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/fred.pro b/trunk/fred.pro
index c0217bb..4780758 100644
--- a/trunk/fred.pro
+++ b/trunk/fred.pro
@@ -1,133 +1,133 @@
#*******************************************************************************
-# fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+# fred Copyright (c) 2011-2014 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/>. *
#******************************************************************************/
# Generate compileinfo.h
system(bash compileinfo.sh > compileinfo.h)
#compileinfo.target = compileinfo.h
#compileinfo.commands = $$PWD/compileinfo.sh > compileinfo.h
#QMAKE_EXTRA_TARGETS += compileinfo
#PRE_TARGETDEPS += compileinfo.h
# Check command line args
!isEmpty(HIVEX_STATIC) {
DEFINES += "HIVEX_STATIC"
}
# Configure fred
QMAKE_CXXFLAGS += -Wall
QT += core \
gui \
script \
webkit
CONFIG += console
TARGET = fred
TEMPLATE = app
SOURCES += main.cpp\
mainwindow.cpp \
registrynode.cpp \
registrynodetreemodel.cpp \
registrykey.cpp \
registrykeytablemodel.cpp \
dlgabout.cpp \
qhexedit/qhexedit_p.cpp \
qhexedit/qhexedit.cpp \
reporttemplate.cpp \
registryhive.cpp \
qtscript_types/bytearray.cpp \
qtscript_types/bytearrayprototype.cpp \
qtscript_types/bytearrayiterator.cpp \
dlgreportviewer.cpp \
registrykeytable.cpp \
registrynodetree.cpp \
dlgsearch.cpp \
threadsearch.cpp \
searchresultwidget.cpp \
tabwidget.cpp \
argparser.cpp \
datainterpretertable.cpp \
datainterpreterwidget.cpp \
hexeditwidget.cpp \
settings.cpp \
searchresulttabledelegate.cpp \
registrynodetreemodelproxy.cpp \
reports.cpp \
reportengine.cpp \
dlgreportchooser.cpp \
dlgpreferences.cpp \
dlgaddkey.cpp
HEADERS += mainwindow.h \
registrynode.h \
registrynodetreemodel.h \
registrykey.h \
registrykeytablemodel.h \
dlgabout.h \
qhexedit/qhexedit_p.h \
qhexedit/qhexedit.h \
reporttemplate.h \
registryhive.h \
qtscript_types/bytearray.h \
qtscript_types/bytearrayprototype.h \
qtscript_types/bytearrayiterator.h \
dlgreportviewer.h \
registrykeytable.h \
registrynodetree.h \
dlgsearch.h \
threadsearch.h \
searchresultwidget.h \
tabwidget.h \
argparser.h \
datainterpretertable.h \
datainterpreterwidget.h \
hexeditwidget.h \
settings.h \
searchresulttabledelegate.h \
registrynodetreemodelproxy.h \
reports.h \
reportengine.h \
dlgreportchooser.h \
dlgpreferences.h \
dlgaddkey.h
FORMS += mainwindow.ui \
dlgabout.ui \
dlgreportviewer.ui \
dlgsearch.ui \
dlgreportchooser.ui \
dlgpreferences.ui \
dlgaddkey.ui
!isEmpty(HIVEX_STATIC) {
LIBS += $$PWD/hivex/lib/.libs/libhivex.a
} else {
LIBS += -lhivex
}
win32:LIBS += -liconv
mac:LIBS += -liconv
RESOURCES += fred.qrc
RC_FILE = fred.rc
ICON = resources/fred.icns
diff --git a/trunk/fred_license_template.txt b/trunk/fred_license_template.txt
index 0acb41d..4e0e039 100644
--- a/trunk/fred_license_template.txt
+++ b/trunk/fred_license_template.txt
@@ -1,19 +1,19 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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/>. *
*******************************************************************************/
diff --git a/trunk/hexeditwidget.cpp b/trunk/hexeditwidget.cpp
index 622b835..ac6feef 100644
--- a/trunk/hexeditwidget.cpp
+++ b/trunk/hexeditwidget.cpp
@@ -1,148 +1,148 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 <QFont>
#include <QSizePolicy>
#include "hexeditwidget.h"
HexEditWidget::HexEditWidget(QWidget *p_parent,
bool with_data_interpreter,
bool is_read_only) : QWidget(p_parent)
{
// Init private vars
this->has_data_interpreter=with_data_interpreter;
this->read_only=is_read_only;
this->data=QByteArray();
// Set widget layout. Setting it's parent to "this" will also call
// this->SetLayout.
this->p_widget_layout=new QVBoxLayout(this);
// Create sub-widgets
if(this->has_data_interpreter) {
// Widget should include a data interpreter
this->p_widget_splitter=new QSplitter(this);
this->p_hex_edit_layout_widget=new QWidget(this->p_widget_splitter);
this->p_hex_edit_layout=new QVBoxLayout(this->p_hex_edit_layout_widget);
this->p_hex_edit=new QHexEdit(this->p_hex_edit_layout_widget);
this->p_hex_edit_status_bar=new QLabel(this);
this->p_data_interpreter_widget=new DataInterpreterWidget(this);
// Add hex edit and hex edit status bar to their layout
this->p_hex_edit_layout->addWidget(this->p_hex_edit);
this->p_hex_edit_layout->addWidget(this->p_hex_edit_status_bar);
// Add sub-widgets to splitter and splitter to our layout
this->p_widget_splitter->addWidget(this->p_hex_edit_layout_widget);
this->p_widget_splitter->addWidget(this->p_data_interpreter_widget);
this->p_widget_layout->addWidget(this->p_widget_splitter);
// Configure sub-widgets
this->p_widget_splitter->setOrientation(Qt::Horizontal);
this->p_hex_edit_layout_widget->setContentsMargins(0,0,0,0);
this->p_hex_edit_layout->setContentsMargins(0,0,0,0);
// Set size policies of sub-widgets
QSizePolicy hex_edit_layout_widget_policy=
this->p_hex_edit_layout_widget->sizePolicy();
hex_edit_layout_widget_policy.setVerticalStretch(2);
hex_edit_layout_widget_policy.setHorizontalStretch(200);
this->p_hex_edit_layout_widget->setSizePolicy(hex_edit_layout_widget_policy);
QSizePolicy data_interpreter_widget_policy=
this->p_data_interpreter_widget->sizePolicy();
data_interpreter_widget_policy.setVerticalStretch(2);
data_interpreter_widget_policy.setHorizontalStretch(0);
this->p_data_interpreter_widget->
setSizePolicy(data_interpreter_widget_policy);
} else {
// Widget shouldn't include a data interpreter
this->p_hex_edit=new QHexEdit(this);
this->p_hex_edit_status_bar=new QLabel(this);
this->p_widget_layout->addWidget(this->p_hex_edit);
this->p_widget_layout->addWidget(this->p_hex_edit_status_bar);
}
// Configure widget and sub-widgets
this->setContentsMargins(0,0,0,0);
this->p_widget_layout->setContentsMargins(0,0,0,0);
this->p_hex_edit->setContentsMargins(0,0,0,0);
// 5 pixel bottom margin makes hex edit and data interpreter lignup correctly
this->p_hex_edit_status_bar->setContentsMargins(0,0,0,5);
this->p_hex_edit->setReadOnly(this->read_only);
// If we're not read only, it should also be possible to add data
this->p_hex_edit->setOverwriteMode(this->read_only);
// Make sure hex edit font is monospaced.
QFont mono_font("Monospace");
mono_font.setStyleHint(QFont::TypeWriter);
this->p_hex_edit->setFont(mono_font);
// Connect signals
this->connect(this->p_hex_edit,
SIGNAL(currentAddressChanged(int)),
this,
SLOT(SlotHexEditOffsetChanged(int)));
}
HexEditWidget::~HexEditWidget() {
delete this->p_hex_edit_status_bar;
delete this->p_hex_edit;
if(this->has_data_interpreter) {
delete this->p_data_interpreter_widget;
delete this->p_hex_edit_layout;
delete this->p_hex_edit_layout_widget;
delete this->p_widget_splitter;
}
delete this->p_widget_layout;
}
void HexEditWidget::SetData(QByteArray const &new_data) {
this->data=new_data;
this->p_hex_edit->setData(this->data);
if(data.size()!=0) {
// Data set, update status bar and init data interpreter
this->SlotHexEditOffsetChanged(0);
} else {
// No data set, clear status bar and data interpreter
this->p_hex_edit_status_bar->setText("");
this->p_data_interpreter_widget->SetData(QByteArray());
}
}
QByteArray HexEditWidget::GetData() {
return this->p_hex_edit->data();
}
void HexEditWidget::SlotHexEditOffsetChanged(int offset) {
// Update hex edit status bar
this->p_hex_edit_status_bar->setText(tr("Byte offset: 0x%1 (%2)")
.arg((quint16)offset,
4,
16,
QChar('0'))
.arg(offset));
// Update data interpreter
if(this->has_data_interpreter) {
this->p_data_interpreter_widget->SetData(this->data.mid(offset,8));
}
}
diff --git a/trunk/hexeditwidget.h b/trunk/hexeditwidget.h
index 6546555..0ac6504 100644
--- a/trunk/hexeditwidget.h
+++ b/trunk/hexeditwidget.h
@@ -1,68 +1,68 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 HEXEDITWIDGET_H
#define HEXEDITWIDGET_H
#include <QWidget>
#include <QSplitter>
#include <QVBoxLayout>
#include <QLabel>
#include <QByteArray>
#include "qhexedit/qhexedit.h"
#include "datainterpreterwidget.h"
class HexEditWidget : public QWidget {
Q_OBJECT
public:
explicit HexEditWidget(QWidget *p_parent=0,
bool with_data_interpreter=true,
bool is_read_only=true);
~HexEditWidget();
void SetData(QByteArray const &data);
QByteArray GetData();
signals:
public slots:
private:
// Widget layout
QVBoxLayout *p_widget_layout;
QSplitter *p_widget_splitter;
// Sub-widgets
QWidget *p_hex_edit_layout_widget;
QVBoxLayout *p_hex_edit_layout;
QHexEdit *p_hex_edit;
QLabel *p_hex_edit_status_bar;
DataInterpreterWidget *p_data_interpreter_widget;
// Vars
bool has_data_interpreter;
bool read_only;
QByteArray data;
private slots:
void SlotHexEditOffsetChanged(int offset);
};
#endif // HEXEDITWIDGET_H
diff --git a/trunk/main.cpp b/trunk/main.cpp
index 60c4f09..5d5010f 100644
--- a/trunk/main.cpp
+++ b/trunk/main.cpp
@@ -1,158 +1,158 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 <QtGui/QApplication>
#include <QStringList>
#include <stdio.h>
#include "mainwindow.h"
#include "argparser.h"
#include "compileinfo.h"
#include "reportengine.h"
#include "registryhive.h"
// Forward declarations
void PrintUsage();
void DumpReport(QString report_template, QString hive_file);
// Main entry point
int main(int argc, char *argv[]) {
// Disable output buffering
setbuf(stdout,NULL);
// Init QApplication
QApplication a(argc, argv);
#define PRINT_HEADER { \
printf("%s v%s %s\n\n",APP_NAME,APP_VERSION,APP_COPYRIGHT); \
}
#define PRINT_HEADER_AND_USAGE { \
PRINT_HEADER; \
PrintUsage(); \
}
#define PRINT_VERSION printf("%s\n",APP_VERSION);
#define PRINT_UNKNOWN_ARG_ERROR(s) { \
PRINT_HEADER; \
printf("ERROR: Unknown command line argument '%s'!\n\n",s); \
PrintUsage(); \
}
// Parse command line args
ArgParser args(a.arguments());
if(!args.ParseArgs()) {
PRINT_HEADER;
printf("ERROR: %s\n\n",args.GetErrorMsg().toAscii().constData());
PrintUsage();
exit(1);
}
// Check command line args for correctness
if(args.IsSet("dump-report")) {
if(args.GetArgVal("dump-report")=="") {
PRINT_HEADER;
printf("ERROR: --dump-report specified without a report file!\n\n");
PrintUsage();
exit(1);
}
if(!args.IsSet("hive-file")) {
PRINT_HEADER;
printf("ERROR: --dump-report specified without a hive file!\n\n");
PrintUsage();
exit(1);
}
}
if(args.IsSet("fullscreen") && args.IsSet("maximized")) {
PRINT_HEADER;
printf("ERROR: --fullscreen and --maximized cannot be specified both!\n\n");
PrintUsage();
exit(1);
}
// React on some command line args early
if(args.IsSet("?") || args.IsSet("h") || args.IsSet("help")) {
PRINT_HEADER_AND_USAGE;
exit(0);
}
if(args.IsSet("v") || args.IsSet("version")) {
PRINT_VERSION;
exit(0);
}
if(args.IsSet("dump-report")) {
// Dump report to stdout
DumpReport(args.GetArgVal("dump-report"),args.GetArgVal("hive-file"));
exit(0);
}
#undef PRINT_UNKNOWN_ARG_ERROR
#undef PRINT_VERSION
#undef PRINT_HEADER_AND_USAGE
#undef PRINT_HEADER
// Create and show main window
MainWindow w(&args);
w.show();
return a.exec();
}
void PrintUsage() {
printf("Usage:\n");
printf(" %s [opts] [hive]\n\n",
qApp->arguments().at(0).toAscii().constData());
printf("Options:\n");
printf(" opts:\n");
printf(" --dump-report=FILE : Dump the specified report to stdout.\n");
printf(" --fullscreen : Display main window in fullscreen mode.\n");
printf(" -h, -?, --help : Display this help message.\n");
printf(" --maximized : Display main window in maximized mode.\n");
printf(" -v, --version : Display version info.\n");
printf(" hive:\n");
printf(" Open / Use the specified hive file.\n");
printf("\n");
}
void DumpReport(QString report_template, QString hive_file) {
RegistryHive *p_hive=new RegistryHive();
ReportEngine *p_report_engine=new ReportEngine(NULL);
// Open hive
if(!p_hive->Open(hive_file,true)) {
printf("ERROR: Unable to open hive file '%s'!\n",
hive_file.toAscii().constData());
exit(1);
}
// Generate report
QString result="";
p_report_engine->GenerateReport(p_hive,
report_template,
result,
true);
// Close hive and free DataReporter and RegistryHive
p_hive->Close();
delete p_report_engine;
delete p_hive;
// Print result to stdout
printf("%s",result.toAscii().constData());
}
diff --git a/trunk/mainwindow.cpp b/trunk/mainwindow.cpp
index 9e64ebd..8d9724d 100644
--- a/trunk/mainwindow.cpp
+++ b/trunk/mainwindow.cpp
@@ -1,1106 +1,1106 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 <QFileDialog>
#include <QMessageBox>
#include <QStringList>
#include <QDesktopWidget>
#include <QDir>
#include <QSplitter>
#include <QListIterator>
#include <QInputDialog>
#include <QDebug>
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "dlgabout.h"
#include "dlgreportchooser.h"
#include "dlgreportviewer.h"
#include "dlgsearch.h"
#include "dlgpreferences.h"
#include "dlgaddkey.h"
#include "compileinfo.h"
/*******************************************************************************
* Public
******************************************************************************/
/*
* Constructor
*/
MainWindow::MainWindow(ArgParser *p_arg_parser) :
QMainWindow(0), ui(new Ui::MainWindow)
{
ui->setupUi(this);
// Initialize private vars
this->p_args=p_arg_parser;
this->p_hive=new RegistryHive(this);
this->is_hive_open=false;
this->p_reg_node_tree_model=NULL;
this->p_reg_node_tree_model_proxy=NULL;
this->p_reg_key_table_model=NULL;
this->p_search_thread=NULL;
this->search_result_widgets.clear();
// Init and load settings
this->p_settings=new Settings(this);
this->is_hive_writable=!this->p_settings->GetOpenHivesReadOnly();
// Set main window size
QByteArray geometry=this->p_settings->GetWindowGeometry("MainWindow");
if(!geometry.isEmpty()) {
// Restore saved geometry
this->restoreGeometry(geometry);
} else {
// No saved geometry, calculate and set default
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_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_hex_edit_widget=new HexEditWidget();
this->p_hex_edit_widget->setEnabled(false);
// Add hexedit page to tab_widget
this->p_tab_widget->addTab(this->p_hex_edit_widget,tr("Hex viewer"));
// Add widgets to their splitters
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);
// 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_tab_widget,
SIGNAL(tabCloseRequested(int)),
this,
SLOT(SlotTabCloseButtonClicked(int)));
this->connect(this->p_node_tree,
SIGNAL(SignalAddNode(QModelIndex)),
this,
SLOT(SlotAddNode(QModelIndex)));
this->connect(this->p_node_tree,
SIGNAL(SignalDeleteNode(QModelIndex)),
this,
SLOT(SlotDeleteNode(QModelIndex)));
this->connect(this->p_key_table,
SIGNAL(SignalAddKey()),
this,
SLOT(SlotAddKey()));
this->connect(this->p_key_table,
SIGNAL(SignalEditKey(QModelIndex)),
this,
SLOT(SlotEditKey(QModelIndex)));
this->connect(this->p_key_table,
SIGNAL(SignalDeleteKey(QModelIndex)),
this,
SLOT(SlotDeleteKey(QModelIndex)));
// Add central widget
this->setCentralWidget(this->p_horizontal_splitter);
this->centralWidget()->setContentsMargins(4,4,4,0);
// Set window title
this->UpdateWindowTitle();
// Create and update recently opened menu
this->p_recently_opened_menu=new QMenu(this);
this->ui->ActionRecentlyOpened->setMenu(this->p_recently_opened_menu);
this->UpdateRecentlyOpenedMenu();
// Update EnableWriteSupport menu according to defaults
this->UpdateEnableWriteSupportMenu();
// Load report templates
this->p_reports=new Reports(this->p_settings);
// Finally, react on some command line arguments
if(this->p_args->IsSet("maximized")) {
this->setWindowState(Qt::WindowMaximized);
}
if(this->p_args->IsSet("fullscreen")) {
this->setWindowState(Qt::WindowFullScreen);
}
if(this->p_args->IsSet("hive-file")) {
// Resolve path
this->OpenHive(QDir(this->p_args->GetArgVal("hive-file")).canonicalPath());
}
}
/*
* Destructor
*/
MainWindow::~MainWindow() {
if(this->is_hive_open) {
this->p_hive->Close();
}
// Delete created objects
delete this->p_reports;
this->ClearRecentlyOpenedMenu();
delete this->p_recently_opened_menu;
delete this->p_hex_edit_widget;
delete this->p_tab_widget;
delete this->p_key_table;
delete this->p_vertical_splitter;
delete this->p_node_tree;
delete this->p_horizontal_splitter;
delete this->p_settings;
delete this->p_hive;
delete ui;
}
/*******************************************************************************
* Protected
******************************************************************************/
/*
* closeEvent
*/
void MainWindow::closeEvent(QCloseEvent *p_event) {
Q_UNUSED(p_event)
// Make sure the user can save any changes
// TODO: If saving fails, let the user cancel closing
this->SaveHiveChanges();
// Save window position and size on exit
this->p_settings->SetWindowGeometry("MainWindow",this->saveGeometry());
QMainWindow::closeEvent(p_event);
}
/*******************************************************************************
* Private slots
******************************************************************************/
/*
* on_ActionOpenHive_triggered
*/
void MainWindow::on_ActionOpenHive_triggered() {
QString hive_file="";
hive_file=QFileDialog::getOpenFileName(this,
tr("Open registry hive"),
this->p_settings->GetLastOpenLocation(),
tr("All files (*)"));
if(hive_file=="") return;
this->OpenHive(hive_file);
}
/*
* on_ActionSave_triggered
*/
void MainWindow::on_ActionSave_triggered() {
if(!(this->is_hive_open && this->is_hive_writable)) {
this->ui->ActionSave->setEnabled(false);
return;
}
this->SaveHiveChanges(true);
if(!this->p_hive->HasChangesToCommit()) {
this->ui->ActionSave->setEnabled(false);
}
}
/*
* on_ActionCloseHive_triggered
*/
void MainWindow::on_ActionCloseHive_triggered() {
// Make sure the user can save any changes
// TODO: If saving fails, let the user cancel closing
this->SaveHiveChanges();
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_proxy;
delete this->p_reg_node_tree_model;
this->p_reg_node_tree_model_proxy=NULL;
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_widget->SetData(QByteArray());
this->p_hex_edit_widget->setEnabled(false);
// Close hive
this->p_hive->Close();
this->is_hive_open=false;
this->is_hive_writable=!this->p_settings->GetOpenHivesReadOnly();
this->UpdateWindowTitle();
this->UpdateMenuStates();
this->UpdateEnableWriteSupportMenu();
}
}
/*
* on_ActionQuit_triggered
*/
void MainWindow::on_ActionQuit_triggered() {
qApp->exit();
}
/*
* on_ActionFind_triggered
*/
void MainWindow::on_ActionFind_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);
// 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->ActionFind->setEnabled(false);
p_search_thread->Search(this->p_hive->Filename(),
dlg_search.Keywords(),
dlg_search.SearchNodeNames(),
dlg_search.SearchKeyNames(),
dlg_search.SearchKeyValues());
}
}
/*
* on_ActionEnableWriteSupport_triggered
*/
void MainWindow::on_ActionEnableWriteSupport_triggered() {
// There might be unsaved changes, give the user the chance to save them
if(!this->SaveHiveChanges()) return;
// Reopen hive
// Reopen has read_only as parameter. Thus we need to pass
// !this->is_hive_writable which is the case when passing
// this->is_hive_writable as long as we do it before actually changing our
// internal state.
if(!this->p_hive->Reopen(this->is_hive_writable)) {
QMessageBox::critical(this,
tr("Error"),
tr("Unable to switch write-support: %1")
.arg(this->p_hive->GetErrorMsg()));
return;
}
// Switch internal state
this->is_hive_writable=!this->is_hive_writable;
this->UpdateEnableWriteSupportMenu();
this->p_node_tree->SetWritable(this->is_hive_writable);
this->p_key_table->SetWritable(this->is_hive_writable);
this->UpdateWindowTitle(this->p_hive->Filename());
}
/*
* on_ActionPreferences_triggered
*/
void MainWindow::on_ActionPreferences_triggered() {
DlgPreferences dlg_preferences(this->p_settings,this);
dlg_preferences.exec();
// Update vars, objects and GUI elements which might be affected by the new
// settings
this->UpdateRecentlyOpenedMenu();
this->is_hive_writable=!this->p_settings->GetOpenHivesReadOnly();
this->UpdateEnableWriteSupportMenu();
this->p_reports->LoadReportTemplates();
}
/*
* on_ActionGenerateReport_triggered
*/
void MainWindow::on_ActionGenerateReport_triggered() {
DlgReportChooser dlg_repchooser(this->p_reports,
this->p_hive->HiveTypeToString(
this->p_hive->HiveType()),
this->p_settings,
this);
if(dlg_repchooser.exec()==QDialog::Accepted) {
QList<ReportTemplate*> selected_reports;
// Get selected report
selected_reports=dlg_repchooser.GetSelectedReports();
if(selected_reports.isEmpty()) return;
// Generate report(s)
QString report_result="";
if(this->p_reports->GenerateReport(this->p_hive,
selected_reports,
report_result,
false))
{
// Report generation was successfull, show reports
DlgReportViewer *p_dlg_report_view=new DlgReportViewer(report_result,
this->p_settings,
this);
p_dlg_report_view->exec();
delete p_dlg_report_view;
} else {
// TODO: Inform user
qDebug()<<"ERROR: "<<report_result;
}
}
}
/*
* on_ActionReloadReportTemplates_triggered
*/
void MainWindow::on_ActionReloadReportTemplates_triggered() {
this->p_reports->LoadReportTemplates();
}
/*
* on_ActionAboutQt_triggered
*/
void MainWindow::on_ActionAboutQt_triggered() {
QMessageBox::aboutQt(this,tr("About Qt"));
}
/*
* on_ActionAboutFred_triggered
*/
void MainWindow::on_ActionAboutFred_triggered() {
DlgAbout dlg_about(this);
dlg_about.exec();
}
/*
* SlotNodeTreeClicked
*/
void MainWindow::SlotNodeTreeClicked(QModelIndex index) {
QString node_path;
if(!index.isValid()) return;
// Map proxy index to tree model index
index=this->p_reg_node_tree_model_proxy->mapToSource(index);
// 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) {
// If a previous model was set, delete it and clear hexedit etc...
this->p_key_table->setModel(NULL);
delete this->p_reg_key_table_model;
this->p_hex_edit_widget->SetData(QByteArray());
}
this->p_reg_key_table_model=new RegistryKeyTableModel(this->p_hive,node_path);
this->p_key_table->setModel(this->p_reg_key_table_model,
this->is_hive_writable);
// Set focus back to nodetree to be able to navigate with keyboard
this->p_node_tree->setFocus();
}
/*
* SlotKeyTableClicked
*/
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_widget->SetData(this->selected_key_value);
// Set focus back to nodetree to be able to navigate with keyboard
this->p_key_table->setFocus();
}
/*
* SlotKeyTableDoubleClicked
*/
void MainWindow::SlotKeyTableDoubleClicked(QModelIndex index) {
if(!index.isValid()) return;
if(!this->is_hive_open) return;
if(this->is_hive_writable) this->SlotEditKey(index);
}
/*
* SlotSearchFinished
*/
void MainWindow::SlotSearchFinished() {
delete this->p_search_thread;
this->p_search_thread=NULL;
this->ui->ActionFind->setEnabled(true);
// Enable result widget
this->search_result_widgets.last()->setEnabled(true);
}
/*
* SlotSearchResultWidgetDoubleClicked
*/
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++) {
indexes.replace(i,this->p_reg_node_tree_model_proxy->
mapFromSource(indexes.at(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::ClearAndSelect |
QItemSelectionModel::Rows |
QItemSelectionModel::Current);
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));
}
}
/*
* SlotTabCloseButtonClicked
*/
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);
}
/*
* SlotRecentlyOpenedFileClicked
*/
void MainWindow::SlotRecentlyOpenedFileClicked(bool checked) {
Q_UNUSED(checked)
QAction *p_sender=(QAction*)QObject::sender();
this->OpenHive(p_sender->text());
}
/*
* SlotAddNode
*/
void MainWindow::SlotAddNode(QModelIndex index) {
QString node_path;
int new_node_id;
if(!index.isValid()) return;
// Map proxy index to tree model index and get node path
index=this->p_reg_node_tree_model_proxy->mapToSource(index);
node_path=this->p_reg_node_tree_model->GetNodePath(index);
// Query user for a node name
bool ok=false;
QString node_name=QInputDialog::getText(this,
tr("Add node"),
tr("Please specify a name for the new node"),
QLineEdit::Normal,
QString(),
&ok);
if(ok) {
if((new_node_id=this->p_hive->AddNode(node_path,node_name))==0) {
QMessageBox::critical(this,
tr("Error"),
tr("Unable to create node '%1\\%2': %3!")
.arg(node_path,
node_name,
this->p_hive->GetErrorMsg()));
} else {
// Add node to model. We have to pass node_name as Ascii as utf8 names are
// not supported inside hives!
QModelIndex new_node_index=
this->p_reg_node_tree_model->AddNode(this->p_hive,
index,
new_node_id,
node_name.toAscii());
// Now that node has been added, expand parent and select new node
this->p_node_tree->expand(
this->p_reg_node_tree_model_proxy->mapFromSource(index));
new_node_index=
this->p_reg_node_tree_model_proxy->mapFromSource(new_node_index);
this->p_node_tree->scrollTo(new_node_index,
QAbstractItemView::PositionAtCenter);
this->p_node_tree->selectionModel()->clear();
this->p_node_tree->selectionModel()->
select(new_node_index,
QItemSelectionModel::ClearAndSelect |
QItemSelectionModel::Rows |
QItemSelectionModel::Current);
// Finally update key table and enable Save menu
this->SlotNodeTreeClicked(new_node_index);
this->ui->ActionSave->setEnabled(true);
}
}
}
/*
* SlotDeleteNode
*/
void MainWindow::SlotDeleteNode(QModelIndex index) {
QString node_path;
if(!index.isValid()) return;
// Map proxy index to tree model index and get node path
index=this->p_reg_node_tree_model_proxy->mapToSource(index);
node_path=this->p_reg_node_tree_model->GetNodePath(index);
if(QMessageBox::warning(this,
tr("Delete node"),
tr("Are you sure you want to remove the node '%1' and all of its child nodes?").arg(node_path),
QMessageBox::Yes,
QMessageBox::No)==QMessageBox::Yes)
{
// Remove node from hive
if(!this->p_hive->DeleteNode(node_path)) {
QMessageBox::critical(this,
tr("Error"),
tr("Unable to delete node '%1': %2!")
.arg(node_path,this->p_hive->GetErrorMsg()));
return;
}
// Remove node from tree model and select nearest node
QModelIndex next_node_index=this->p_reg_node_tree_model->RemoveNode(index);
if(next_node_index.isValid()) {
next_node_index=
this->p_reg_node_tree_model_proxy->mapFromSource(next_node_index);
this->p_node_tree->selectionModel()->clear();
this->p_node_tree->selectionModel()->
select(next_node_index,
QItemSelectionModel::ClearAndSelect |
QItemSelectionModel::Rows |
QItemSelectionModel::Current);
}
// And finally update key table and enable Save menu
this->SlotNodeTreeClicked(next_node_index);
this->ui->ActionSave->setEnabled(true);
}
}
/*
* SlotAddKey
*/
void MainWindow::SlotAddKey() {
DlgAddKey dlg_add_key(this);
if(dlg_add_key.exec()==QDialog::Accepted) {
// Get selected parent node
QModelIndex parent_node=this->p_node_tree->currentIndex();
parent_node=this->p_reg_node_tree_model_proxy->mapToSource(parent_node);
QString parent_node_path=this->p_reg_node_tree_model->GetNodePath(parent_node);
// Add key
int new_key=this->p_hive->AddKey(parent_node_path,
dlg_add_key.KeyName(),
dlg_add_key.KeyType(),
dlg_add_key.KeyValue());
if(new_key==0) {
QMessageBox::critical(this,
tr("Error"),
tr("Unable to add key: %1")
.arg(this->p_hive->GetErrorMsg()));
return;
}
// Add new key to the key table model
QModelIndex new_key_index=
this->p_reg_key_table_model->AddKey(this->p_hive,new_key);
if(new_key_index.isValid()) {
this->p_key_table->clearSelection();
this->p_key_table->scrollTo(new_key_index,
QAbstractItemView::PositionAtCenter);
this->p_key_table->selectRow(new_key_index.row());
}
// Update key table and enable save menu
this->SlotKeyTableClicked(new_key_index);
this->ui->ActionSave->setEnabled(true);
}
}
/*
* SlotEditKey
*/
void MainWindow::SlotEditKey(QModelIndex index) {
if(!index.isValid()) return;
// Get current values
QString key_name=
this->p_reg_key_table_model->data(this->p_reg_key_table_model->
index(index.row(),
RegistryKeyTableModel::
ColumnContent_KeyName),
Qt::DisplayRole).toString();
QString key_value_type=
this->p_reg_key_table_model->data(this->p_reg_key_table_model->
index(index.row(),
RegistryKeyTableModel::
ColumnContent_KeyType),
Qt::DisplayRole).toString();
QByteArray key_value=
this->p_reg_key_table_model->data(this->p_reg_key_table_model->
index(index.row(),
RegistryKeyTableModel::
ColumnContent_KeyValue),
RegistryKeyTableModel::
AdditionalRoles_GetRawData).toByteArray();
// Exec update dialog
DlgAddKey dlg_update_key(this,key_name,key_value_type,key_value);
if(dlg_update_key.exec()==QDialog::Accepted) {
// Get selected parent node
QModelIndex parent_node=this->p_node_tree->currentIndex();
parent_node=this->p_reg_node_tree_model_proxy->mapToSource(parent_node);
QString parent_node_path=this->p_reg_node_tree_model->GetNodePath(parent_node);
// Update key
int new_key=this->p_hive->UpdateKey(parent_node_path,
dlg_update_key.KeyName(),
dlg_update_key.KeyType(),
dlg_update_key.KeyValue());
if(new_key==0) {
QMessageBox::critical(this,
tr("Error"),
tr("Unable to update key: %1")
.arg(this->p_hive->GetErrorMsg()));
return;
}
// Update key in key table model
QModelIndex new_key_index=
this->p_reg_key_table_model->UpdateKey(this->p_hive,new_key);
this->p_key_table->clearSelection();
if(new_key_index.isValid()) {
this->p_key_table->scrollTo(new_key_index,
QAbstractItemView::PositionAtCenter);
this->p_key_table->selectRow(new_key_index.row());
// TODO: Update geometry in case data has been added and is now expanding
// behind the right border
// Update HexEditWidget
}
// Update key table and enable Save menu
this->SlotKeyTableClicked(new_key_index);
this->ui->ActionSave->setEnabled(true);
}
}
/*
* SlotDeleteKey
*/
void MainWindow::SlotDeleteKey(QModelIndex index) {
if(!index.isValid()) return;
// Get selected key name
QString key_name=
this->p_reg_key_table_model->data(this->p_reg_key_table_model->
index(index.row(),
RegistryKeyTableModel::
ColumnContent_KeyName),
Qt::DisplayRole).toString();
// Get selected parent node
QModelIndex parent_node=this->p_node_tree->currentIndex();
parent_node=this->p_reg_node_tree_model_proxy->mapToSource(parent_node);
QString parent_node_path=this->p_reg_node_tree_model->GetNodePath(parent_node);
if(QMessageBox::warning(this,
tr("Delete key"),
tr("Are you sure you want to remove the key '%1\\%2'?")
.arg(parent_node_path,key_name),
QMessageBox::Yes,
QMessageBox::No)==QMessageBox::Yes)
{
// Remove key from hive
if(!this->p_hive->DeleteKey(parent_node_path,key_name)) {
QMessageBox::critical(this,
tr("Error"),
tr("Unable to delete key '%1\\%2': %3")
.arg(parent_node_path,
key_name,
this->p_hive->GetErrorMsg()));
return;
}
// Remove key from table model and update selection
QModelIndex new_key_index=this->p_reg_key_table_model->RemoveKey(index);
this->p_key_table->clearSelection();
if(new_key_index.isValid()) {
this->p_key_table->scrollTo(new_key_index,
QAbstractItemView::PositionAtCenter);
this->p_key_table->selectRow(new_key_index.row());
}
// Enable Save menu
this->ui->ActionSave->setEnabled(true);
}
}
/*******************************************************************************
* Private
******************************************************************************/
/*
* OpenHive
*/
void MainWindow::OpenHive(QString hive_file) {
// Make sure hive_file has native directory separators
hive_file=QDir::toNativeSeparators(hive_file);
// Update last open location
this->p_settings->SetLastOpenLocation(
hive_file.left(hive_file.lastIndexOf(QDir::separator())));
// If another hive is currently open, close it
if(this->is_hive_open) this->on_ActionCloseHive_triggered();
// Try to open hive
if(!this->p_hive->Open(hive_file,!this->is_hive_writable)) {
QMessageBox::critical(this,
tr("Error opening hive file"),
tr("Unable to open file '%1'").arg(hive_file));
return;
}
// Create tree model & proxy
this->p_reg_node_tree_model=new RegistryNodeTreeModel(this->p_hive);
this->p_reg_node_tree_model_proxy=new RegistryNodeTreeModelProxy(this);
//this->p_reg_node_tree_model_proxy->setDynamicSortFilter(true);
this->p_reg_node_tree_model_proxy->
setSourceModel(this->p_reg_node_tree_model);
this->p_node_tree->setModel(this->p_reg_node_tree_model_proxy,
this->is_hive_writable);
this->is_hive_open=true;
// Enable data interpreter
this->p_hex_edit_widget->setEnabled(true);
// Update window title
this->UpdateWindowTitle(hive_file);
// Update menu states
this->UpdateMenuStates();
// Add file to recent list and update recently opened menu
this->p_settings->AddRecentFile(hive_file);
this->UpdateRecentlyOpenedMenu();
}
/*
* UpdateWindowTitle
*/
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()));
if(!this->is_hive_writable) {
this->setWindowTitle(this->windowTitle().append(QString(" (%1)")
.arg(tr("read-only"))));
}
}
}
/*
* UpdateMenuStates
*/
void MainWindow::UpdateMenuStates() {
if(this->is_hive_open) {
this->ui->ActionCloseHive->setEnabled(true);
this->ui->ActionFind->setEnabled(true);
this->ui->ActionEnableWriteSupport->setEnabled(true);
this->ui->ActionGenerateReport->setEnabled(true);
this->ui->ActionReloadReportTemplates->setEnabled(true);
this->UpdateEnableWriteSupportMenu();
} else {
this->ui->ActionSave->setEnabled(false);
this->ui->ActionCloseHive->setEnabled(false);
this->ui->ActionEnableWriteSupport->setEnabled(false);
this->ui->ActionFind->setEnabled(false);
this->ui->ActionEnableWriteSupport->setEnabled(false);
this->ui->ActionGenerateReport->setEnabled(false);
this->ui->ActionReloadReportTemplates->setEnabled(false);
}
}
/*
* ClearRecentlyOpenedMenu
*/
void MainWindow::ClearRecentlyOpenedMenu() {
QAction *p_action;
// Remove existing menu entries
QList<QAction*> menu_entries=this->p_recently_opened_menu->actions();
QListIterator<QAction*> it_me(menu_entries);
while(it_me.hasNext()) {
p_action=it_me.next();
this->p_recently_opened_menu->removeAction(p_action);
delete p_action;
}
}
/*
* UpdateRecentlyOpenedMenu
*/
void MainWindow::UpdateRecentlyOpenedMenu() {
QStringList recent_files=this->p_settings->GetRecentFiles();
QAction *p_action;
// Remove existing menu entries
this->ClearRecentlyOpenedMenu();
// If there are no recent files, disable submenu and return
if(recent_files.isEmpty()) {
this->ui->ActionRecentlyOpened->setEnabled(false);
return;
} else {
this->ui->ActionRecentlyOpened->setEnabled(true);
}
// Add recently opened files to menu
QListIterator<QString> it_rf(recent_files);
while(it_rf.hasNext()) {
// Create menu entry
p_action=new QAction(it_rf.next(),this->p_recently_opened_menu);
// Connect it to us
this->connect(p_action,
SIGNAL(triggered(bool)),
this,
SLOT(SlotRecentlyOpenedFileClicked(bool)));
// Add it to submenu
this->p_recently_opened_menu->addAction(p_action);
}
}
/*
* UpdateEnableWriteSupportMenu
*/
void MainWindow::UpdateEnableWriteSupportMenu() {
if(!this->is_hive_writable) {
this->ui->ActionEnableWriteSupport->setText(tr("Enable &write support"));
this->p_node_tree->SetWritable(false);
this->p_key_table->SetWritable(false);
} else {
this->ui->ActionEnableWriteSupport->setEnabled(false);
this->p_node_tree->SetWritable(true);
this->p_key_table->SetWritable(true);
}
}
/*
* SaveHiveChanges
*/
bool MainWindow::SaveHiveChanges(bool force) {
if(!this->is_hive_open) return true;
if(!this->is_hive_writable) return true;
if(!this->p_hive->HasChangesToCommit()) return true;
if(!force) {
// There are unsaved changes, ask user if we should commit them
switch(QMessageBox::information(this,
tr("Hive contains unsaved data"),
tr("Do you want to save them now?"),
QMessageBox::Yes,
QMessageBox::No,
QMessageBox::Cancel))
{
case QMessageBox::Yes: {
if(!this->p_hive->CommitChanges()) {
QMessageBox::critical(this,
tr("Saving changes"),
tr("Unable to save changes: %1")
.arg(this->p_hive->GetErrorMsg()));
return false;
}
break;
}
case QMessageBox::No: {
break;
}
default: {
return false;
}
}
} else {
if(!this->p_hive->CommitChanges()) {
QMessageBox::critical(this,
tr("Saving changes"),
tr("Unable to save changes: %1")
.arg(this->p_hive->GetErrorMsg()));
return false;
}
}
return true;
}
diff --git a/trunk/mainwindow.h b/trunk/mainwindow.h
index 75ed4c0..7c8de2d 100644
--- a/trunk/mainwindow.h
+++ b/trunk/mainwindow.h
@@ -1,127 +1,127 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QWidget>
#include <QLabel>
#include <QTabWidget>
#include <QVBoxLayout>
#include <QSplitter>
#include <QString>
#include <QByteArray>
//#include <hivex.h>
#include "argparser.h"
#include "registryhive.h"
#include "registrynodetree.h"
#include "registrynodetreemodel.h"
#include "registrynodetreemodelproxy.h"
#include "registrykeytable.h"
#include "registrykeytablemodel.h"
#include "hexeditwidget.h"
#include "reports.h"
#include "threadsearch.h"
#include "searchresultwidget.h"
#include "tabwidget.h"
#include "settings.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow {
Q_OBJECT
public:
explicit MainWindow(ArgParser *p_arg_parser);
~MainWindow();
protected:
void closeEvent(QCloseEvent *p_event);
private slots:
void on_ActionOpenHive_triggered();
void on_ActionCloseHive_triggered();
void on_ActionQuit_triggered();
void on_ActionEnableWriteSupport_triggered();
void on_ActionPreferences_triggered();
void on_ActionGenerateReport_triggered();
void on_ActionReloadReportTemplates_triggered();
void on_ActionAboutQt_triggered();
void on_ActionAboutFred_triggered();
void on_ActionFind_triggered();
void SlotNodeTreeClicked(QModelIndex index);
void SlotKeyTableClicked(QModelIndex index);
void SlotKeyTableDoubleClicked(QModelIndex index);
void SlotSearchFinished();
void SlotSearchResultWidgetDoubleClicked(QModelIndex index);
void SlotTabCloseButtonClicked(int index);
void SlotRecentlyOpenedFileClicked(bool checked);
void SlotAddNode(QModelIndex index);
void SlotDeleteNode(QModelIndex index);
void SlotAddKey();
void SlotEditKey(QModelIndex index);
void SlotDeleteKey(QModelIndex index);
void on_ActionSave_triggered();
private:
Ui::MainWindow *ui;
ArgParser *p_args;
RegistryHive *p_hive;
bool is_hive_open;
bool is_hive_writable;
QByteArray selected_key_value;
QList<SearchResultWidget*> search_result_widgets;
Settings *p_settings;
// Models
RegistryNodeTreeModel *p_reg_node_tree_model;
RegistryNodeTreeModelProxy *p_reg_node_tree_model_proxy;
RegistryKeyTableModel *p_reg_key_table_model;
// Widgets etc...
RegistryNodeTree *p_node_tree;
RegistryKeyTable *p_key_table;
TabWidget *p_tab_widget;
HexEditWidget *p_hex_edit_widget;
QSplitter *p_horizontal_splitter;
QSplitter *p_vertical_splitter;
Reports *p_reports;
QMenu *p_recently_opened_menu;
// Threads
ThreadSearch *p_search_thread;
// Functions
void OpenHive(QString hive_file);
void UpdateWindowTitle(QString filename="");
void UpdateMenuStates();
void ClearRecentlyOpenedMenu();
void UpdateRecentlyOpenedMenu();
void UpdateEnableWriteSupportMenu();
bool SaveHiveChanges(bool force=false);
};
#endif // MAINWINDOW_H
diff --git a/trunk/qhexedit/qhexedit.cpp b/trunk/qhexedit/qhexedit.cpp
index 9dfd01a..e193c0c 100644
--- a/trunk/qhexedit/qhexedit.cpp
+++ b/trunk/qhexedit/qhexedit.cpp
@@ -1,137 +1,137 @@
/*******************************************************************************
-* qhexedit Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* qhexedit Copyright (c) 2011-2014 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.h"
QHexEdit::QHexEdit(QWidget *parent) : QScrollArea(parent)
{
qHexEdit_p = new QHexEditPrivate(this);
setWidget(qHexEdit_p);
setWidgetResizable(true);
connect(qHexEdit_p, SIGNAL(currentAddressChanged(int)), this, SIGNAL(currentAddressChanged(int)));
connect(qHexEdit_p, SIGNAL(currentSizeChanged(int)), this, SIGNAL(currentSizeChanged(int)));
connect(qHexEdit_p, SIGNAL(dataChanged()), this, SIGNAL(dataChanged()));
connect(qHexEdit_p, SIGNAL(overwriteModeChanged(bool)), this, SIGNAL(overwriteModeChanged(bool)));
}
void QHexEdit::insert(int i, const QByteArray & ba)
{
qHexEdit_p->insert(i, ba);
}
void QHexEdit::insert(int i, char ch)
{
qHexEdit_p->insert(i, ch);
}
void QHexEdit::remove(int pos, int len)
{
qHexEdit_p->remove(pos, len);
}
void QHexEdit::setAddressArea(bool addressArea)
{
qHexEdit_p->setAddressArea(addressArea);
}
void QHexEdit::setAddressWidth(int addressWidth)
{
qHexEdit_p->setAddressWidth(addressWidth);
}
void QHexEdit::setAsciiArea(bool asciiArea)
{
qHexEdit_p->setAsciiArea(asciiArea);
}
void QHexEdit::setHighlighting(bool mode)
{
qHexEdit_p->setHighlighting(mode);
}
void QHexEdit::setAddressOffset(int offset)
{
qHexEdit_p->setAddressOffset(offset);
}
int QHexEdit::addressOffset()
{
return addressOffset();
}
void QHexEdit::setData(const QByteArray &data)
{
qHexEdit_p->setData(data);
}
QByteArray QHexEdit::data()
{
return qHexEdit_p->data();
}
void QHexEdit::setAddressAreaColor(const QColor &color)
{
qHexEdit_p->setAddressAreaColor(color);
}
QColor QHexEdit::addressAreaColor()
{
return qHexEdit_p->addressAreaColor();
}
void QHexEdit::setHighlightingColor(const QColor &color)
{
qHexEdit_p->setHighlightingColor(color);
}
QColor QHexEdit::highlightingColor()
{
return qHexEdit_p->highlightingColor();
}
void QHexEdit::setOverwriteMode(bool overwriteMode)
{
qHexEdit_p->setOverwriteMode(overwriteMode);
}
bool QHexEdit::overwriteMode()
{
return qHexEdit_p->overwriteMode();
}
void QHexEdit::setReadOnly(bool read_only) {
qHexEdit_p->setReadOnly(read_only);
}
bool QHexEdit::readOnly() {
return qHexEdit_p->readOnly();
}
void QHexEdit::setFont(const QFont &font)
{
qHexEdit_p->setFont(font);
}
diff --git a/trunk/qhexedit/qhexedit.h b/trunk/qhexedit/qhexedit.h
index f399ae7..57035c1 100644
--- a/trunk/qhexedit/qhexedit.h
+++ b/trunk/qhexedit/qhexedit.h
@@ -1,178 +1,178 @@
/*******************************************************************************
-* qhexedit Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* qhexedit Copyright (c) 2011-2014 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_H
#define QHEXEDIT_H
#include <QtGui>
#include "qhexedit_p.h"
/** \mainpage
QHexEdit is a binary editor widget for Qt.
\version Version 0.4.6
\image html hexedit.png
*/
/*! QHexEdit is a hex editor widget written in C++ for the Qt (Qt4) framework.
It is a simple editor for binary data, just like QPlainTextEdit is for text data.
There are sip configuration files included, so it is easy to create bindings
for PyQt and you can use this widget also in python.
QHexEdit takes the data of a QByteArray (setData()) and shows it. You can use the
mouse or the keyboard to navigate inside the widget. If you hit the keys (0..9, a..f)
you will change the data. Changed data is highlighted and can be accessed via data().
Normaly QHexEdit works in the overwrite Mode. You can set overwriteMode(false) and
insert data. In this case the size of data() increases. It is also possible to delete
bytes under the cursor, here the size of data decreases.
There are some limitations: The size of data has in general to be below 10 megabytes,
otherwise the scroll sliders ard not shown and you can't scroll any more. Copy and
paste functionality is perhaps a subject of a later release.
*/
class QHexEdit : public QScrollArea
{
Q_OBJECT
/*! Property data holds the content of QHexEdit. Call setData() to set the
content of QHexEdit, data() returns the actual content.
*/
Q_PROPERTY(QByteArray data READ data WRITE setData)
/*! Property addressOffset is added to the Numbers of the Address Area.
A offset in the address area (left side) is sometimes usefull, whe you show
only a segment of a complete memory picture. With setAddressOffset() you set
this property - with addressOffset() you get the actual value.
*/
Q_PROPERTY(int addressOffset READ addressOffset WRITE setAddressOffset)
/*! Property address area color sets (setAddressAreaColor()) the backgorund
color of address areas. You can also read the color (addressaAreaColor()).
*/
Q_PROPERTY(QColor addressAreaColor READ addressAreaColor WRITE setAddressAreaColor)
/*! Property highlighting color sets (setHighlightingColor()) the backgorund
color of highlighted text areas. You can also read the color
(highlightingColor()).
*/
Q_PROPERTY(QColor highlightingColor READ highlightingColor WRITE setHighlightingColor)
/*! Porperty overwrite mode sets (setOverwriteMode()) or gets (overwriteMode()) the mode
in which the editor works. In overwritem mode the user will overwrite existing data.
*/
Q_PROPERTY(bool overwriteMode READ overwriteMode WRITE setOverwriteMode)
/*! Porperty read only sets (setReadOnly()) or gets (readOnly()) the
current editable mode.
*/
Q_PROPERTY(bool readOnly READ readOnly WRITE setReadOnly)
public:
/*! Creates an instance of QHexEdit.
\param parent Parent widget of QHexEdit.
*/
QHexEdit(QWidget *parent = 0);
/*! Inserts a byte array.
\param i Index position, where to insert
\param ba byte array, which is to insert
*/
void insert(int i, const QByteArray & ba);
/*! Inserts a char.
\param i Index position, where to insert
\param ch Char, which is to insert
*/
void insert(int i, char ch);
/*! Removes len bytes from the content.
\param pos Index position, where to remove
\param len Amount of bytes to remove
*/
void remove(int pos, int len=1);
/*! Set the font of the widget. Please use fixed width fonts like Mono or Courier.*/
void setFont(const QFont &);
/*! \cond docNever */
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);
bool overwriteMode();
void setReadOnly(bool);
bool readOnly();
/*! \endcond docNever */
public slots:
/*! Set the minimum width of the address area.
\param addressWidth Width in characters.
*/
void setAddressWidth(int addressWidth);
/*! Switch the address area on or off.
\param addressArea true (show it), false (hide it).
*/
void setAddressArea(bool addressArea);
/*! Switch the ascii area on or off.
\param asciiArea true (show it), false (hide it).
*/
void setAsciiArea(bool asciiArea);
/*! Switch the highlighting feature on or of.
\param mode true (show it), false (hide it).
*/
void setHighlighting(bool mode);
signals:
/*! Contains the address, where the cursor is located. */
void currentAddressChanged(int address);
/*! Contains the size of the data to edit. */
void currentSizeChanged(int size);
/*! The signal is emited every time, the data is changed. */
void dataChanged();
/*! The signal is emited every time, the overwrite mode is changed. */
void overwriteModeChanged(bool state);
private:
/*! \cond docNever */
QHexEditPrivate *qHexEdit_p;
QHBoxLayout *layout;
QScrollArea *scrollArea;
/*! \endcond docNever */
};
#endif
diff --git a/trunk/qhexedit/qhexedit_p.cpp b/trunk/qhexedit/qhexedit_p.cpp
index 272ee8a..0887812 100644
--- a/trunk/qhexedit/qhexedit_p.cpp
+++ b/trunk/qhexedit/qhexedit_p.cpp
@@ -1,628 +1,628 @@
/*******************************************************************************
-* qhexedit Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* qhexedit Copyright (c) 2011-2014 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 <QClipboard>
#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);
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 bytes converted to 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(SlotCopySelectedTextAsAscii()));
/*
this->connect(this->p_action_copy_selected_text_utf8,
SIGNAL(triggered()),
this,
SLOT(SlotCopySelectedTextAsUtf8()));
*/
}
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)
{
// Delete any previous selections
this->sel_origin.setX(0);
this->sel_origin.setY(0);
this->sel_start=this->sel_origin;
this->sel_end=this->sel_origin;
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 *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::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);
}
}
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)
{
QString address=QString("%1").arg(lineIdx+_addressOffset,
_realAddressNumbers,
16,
QChar('0'));
painter.drawText(_xPosAdr, yPos, address);
}
}
// 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++)
{
// 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 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, 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);
}
}
// 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)));
}
}
}
}
// 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);
}
}
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;
}
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);
}
void QHexEditPrivate::contextMenuEvent(QContextMenuEvent *p_event) {
// Only show context menu when something is selected
if(!(this->sel_start.isNull() && this->sel_end.isNull()) &&
this->sel_start!=this->sel_end)
{
// 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() {
int selection_start=this->Point2Char(this->sel_start)/2;
int selection_count=this->Point2Char(this->sel_end)/2;
selection_count-=(selection_start-1);
QByteArray hex(this->_data.mid(selection_start,selection_count).toHex());
QApplication::clipboard()->setText(hex,QClipboard::Clipboard);
}
void QHexEditPrivate::SlotCopySelectedTextAsAscii() {
int selection_start=this->Point2Char(this->sel_start)/2;
int selection_count=this->Point2Char(this->sel_end)/2;
selection_count-=(selection_start-1);
QByteArray values(this->_data.mid(selection_start,selection_count));
QString ascii="";
int i=0;
for(i=0;i<values.size();i++) {
if(!(((char)values[i]<0x20) || ((char)values[i]>0x7e))) {
ascii.append(values.at(i));
}
}
QApplication::clipboard()->setText(ascii,QClipboard::Clipboard);
}
/*
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 37a5c5c..1f27f55 100644
--- a/trunk/qhexedit/qhexedit_p.h
+++ b/trunk/qhexedit/qhexedit_p.h
@@ -1,125 +1,125 @@
/*******************************************************************************
-* qhexedit Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* qhexedit Copyright (c) 2011-2014 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
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:
void currentAddressChanged(int address);
void currentSizeChanged(int size);
void dataChanged();
void overwriteModeChanged(bool state);
protected:
void keyPressEvent(QKeyEvent * event);
void mousePressEvent(QMouseEvent *p_event);
void mouseMoveEvent(QMouseEvent *p_event);
void paintEvent(QPaintEvent *event);
void setCursorPos(int position);
void contextMenuEvent(QContextMenuEvent *p_event);
private slots:
void updateCursor();
void SlotCopySelectedBytes();
void SlotCopySelectedTextAsAscii();
/*
void SlotCopySelectedTextAsUtf8();
*/
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/qtscript_types/bytearray.cpp b/trunk/qtscript_types/bytearray.cpp
index e65d855..2d396b6 100644
--- a/trunk/qtscript_types/bytearray.cpp
+++ b/trunk/qtscript_types/bytearray.cpp
@@ -1,181 +1,181 @@
/*******************************************************************************
-* Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* Copyright (c) 2011-2014 by Gillen Daniel <gillen.dan@pinguin.lu> *
* *
* Derived from code by Nokia Corporation and/or its subsidiary(-ies) under a *
* compatible license: *
* *
* Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). *
* All rights reserved. *
* *
* 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 <QtScript/QScriptEngine>
#include <stdlib.h>
#include "bytearray.h"
#include "bytearrayiterator.h"
#include "bytearrayprototype.h"
Q_DECLARE_METATYPE(QByteArray*)
Q_DECLARE_METATYPE(ByteArray*)
ByteArray::ByteArray(QScriptEngine *engine)
: QObject(engine), QScriptClass(engine)
{
qScriptRegisterMetaType<QByteArray>(engine,
this->toScriptValue,
this->fromScriptValue);
this->length=engine->toStringHandle(QLatin1String("length"));
this->proto=engine->newQObject(new ByteArrayPrototype(this),
QScriptEngine::QtOwnership,
QScriptEngine::SkipMethodsInEnumeration |
QScriptEngine::ExcludeSuperClassMethods |
QScriptEngine::ExcludeSuperClassProperties);
QScriptValue global=engine->globalObject();
proto.setPrototype(global.property("Object").property("prototype"));
this->ctor=engine->newFunction(this->construct,this->proto);
this->ctor.setData(qScriptValueFromValue(engine,this));
}
ByteArray::~ByteArray() {}
QScriptClass::QueryFlags ByteArray::queryProperty(const QScriptValue &object,
const QScriptString &name,
QueryFlags flags,
uint *id)
{
QByteArray *ba=qscriptvalue_cast<QByteArray*>(object.data());
if(!ba) return 0;
if(name!=this->length) {
bool is_array_index;
qint32 pos=name.toArrayIndex(&is_array_index);
if(!is_array_index) return 0;
*id=pos;
if((flags & HandlesReadAccess) && (pos>=ba->size()))
flags &= ~HandlesReadAccess;
}
return flags;
}
QScriptValue ByteArray::property(const QScriptValue &object,
const QScriptString &name,
uint id)
{
QByteArray *ba=qscriptvalue_cast<QByteArray*>(object.data());
if(!ba) return QScriptValue();
if(name==length) return ba->length();
else {
qint32 pos=id;
if((pos < 0) || (pos >= ba->size())) return QScriptValue();
return uint(ba->at(pos)) & 255;
}
return QScriptValue();
}
void ByteArray::setProperty(QScriptValue &object,
const QScriptString &name,
uint id,
const QScriptValue &value)
{
QByteArray *ba=qscriptvalue_cast<QByteArray*>(object.data());
if(!ba) return;
if(name==length) this->resize(*ba,value.toInt32());
else {
qint32 pos=id;
if(pos<0) return;
if(ba->size()<=pos) this->resize(*ba,pos + 1);
(*ba)[pos]=char(value.toInt32());
}
}
QScriptValue::PropertyFlags ByteArray::propertyFlags(const QScriptValue &object,
const QScriptString &name,
uint id)
{
Q_UNUSED(object);
Q_UNUSED(id);
if(name==length) {
return QScriptValue::Undeletable | QScriptValue::SkipInEnumeration;
}
return QScriptValue::Undeletable;
}
QScriptClassPropertyIterator *ByteArray::newIterator(const QScriptValue &object)
{
return new ByteArrayIterator(object);
}
QString ByteArray::name() const {
return QLatin1String("ByteArray");
}
QScriptValue ByteArray::prototype() const {
return proto;
}
QScriptValue ByteArray::constructor() {
return ctor;
}
QScriptValue ByteArray::newInstance(int size) {
#if QT_VERSION >= 0x040700
this->engine()->reportAdditionalMemoryCost(size);
#endif
return newInstance(QByteArray(size,0));
}
QScriptValue ByteArray::newInstance(const QByteArray &ba) {
QScriptValue data=engine()->newVariant(qVariantFromValue(ba));
return engine()->newObject(this,data);
}
QScriptValue ByteArray::construct(QScriptContext *ctx, QScriptEngine *) {
ByteArray *cls=qscriptvalue_cast<ByteArray*>(ctx->callee().data());
if(!cls) return QScriptValue();
QScriptValue arg=ctx->argument(0);
if(arg.instanceOf(ctx->callee()))
return cls->newInstance(qscriptvalue_cast<QByteArray>(arg));
int size=arg.toInt32();
return cls->newInstance(size);
}
QScriptValue ByteArray::toScriptValue(QScriptEngine *eng, const QByteArray &ba)
{
QScriptValue ctor=eng->globalObject().property("ByteArray");
ByteArray *cls=qscriptvalue_cast<ByteArray*>(ctor.data());
if(!cls) return eng->newVariant(qVariantFromValue(ba));
return cls->newInstance(ba);
}
void ByteArray::fromScriptValue(const QScriptValue &obj, QByteArray &ba) {
ba=qvariant_cast<QByteArray>(obj.data().toVariant());
}
void ByteArray::resize(QByteArray &ba, int newSize) {
int oldSize=ba.size();
ba.resize(newSize);
#if QT_VERSION >= 0x040700
if(newSize>oldSize)
this->engine()->reportAdditionalMemoryCost(newSize-oldSize);
#endif
}
diff --git a/trunk/qtscript_types/bytearray.h b/trunk/qtscript_types/bytearray.h
index 7de44f6..6b59be6 100644
--- a/trunk/qtscript_types/bytearray.h
+++ b/trunk/qtscript_types/bytearray.h
@@ -1,76 +1,76 @@
/*******************************************************************************
-* Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* Copyright (c) 2011-2014 by Gillen Daniel <gillen.dan@pinguin.lu> *
* *
* Derived from code by Nokia Corporation and/or its subsidiary(-ies) under a *
* compatible license: *
* *
* Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). *
* All rights reserved. *
* *
* 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/>. *
*******************************************************************************/
// Description: http://cs.karelia.ru/~aborod/doc/qt/script-customclass.html
#ifndef BYTEARRAY_H
#define BYTEARRAY_H
#include <QObject>
#include <QtScript/QScriptClass>
#include <QtScript/QScriptString>
class ByteArray : public QObject, public QScriptClass {
public:
ByteArray(QScriptEngine *engine);
~ByteArray();
QScriptValue constructor();
QScriptValue newInstance(int size = 0);
QScriptValue newInstance(const QByteArray &ba);
QueryFlags queryProperty(const QScriptValue &object,
const QScriptString &name,
QueryFlags flags,
uint *id);
QScriptValue property(const QScriptValue &object,
const QScriptString &name,
uint id);
void setProperty(QScriptValue &object,
const QScriptString &name,
uint id,
const QScriptValue &value);
QScriptValue::PropertyFlags propertyFlags(const QScriptValue &object,
const QScriptString &name,
uint id);
QScriptClassPropertyIterator *newIterator(const QScriptValue &object);
QString name() const;
QScriptValue prototype() const;
private:
static QScriptValue construct(QScriptContext *ctx, QScriptEngine *eng);
static QScriptValue toScriptValue(QScriptEngine *eng, const QByteArray &ba);
static void fromScriptValue(const QScriptValue &obj, QByteArray &ba);
void resize(QByteArray &ba, int newSize);
QScriptString length;
QScriptValue proto;
QScriptValue ctor;
};
#endif // BYTEARRAY_H
diff --git a/trunk/qtscript_types/bytearrayiterator.cpp b/trunk/qtscript_types/bytearrayiterator.cpp
index 747cbee..adad025 100644
--- a/trunk/qtscript_types/bytearrayiterator.cpp
+++ b/trunk/qtscript_types/bytearrayiterator.cpp
@@ -1,74 +1,74 @@
/*******************************************************************************
-* Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* Copyright (c) 2011-2014 by Gillen Daniel <gillen.dan@pinguin.lu> *
* *
* Derived from code by Nokia Corporation and/or its subsidiary(-ies) under a *
* compatible license: *
* *
* Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). *
* All rights reserved. *
* *
* 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 <QtScript/QScriptEngine>
#include "bytearrayiterator.h"
Q_DECLARE_METATYPE(QByteArray*)
ByteArrayIterator::ByteArrayIterator(const QScriptValue &object)
: QScriptClassPropertyIterator(object)
{
toFront();
}
ByteArrayIterator::~ByteArrayIterator() {}
bool ByteArrayIterator::hasNext() const {
QByteArray *ba=qscriptvalue_cast<QByteArray*>(object().data());
return m_index<ba->size();
}
void ByteArrayIterator::next() {
m_last=m_index;
++m_index;
}
bool ByteArrayIterator::hasPrevious() const {
return(m_index>0);
}
void ByteArrayIterator::previous() {
--m_index;
m_last=m_index;
}
void ByteArrayIterator::toFront() {
m_index=0;
m_last=-1;
}
void ByteArrayIterator::toBack() {
QByteArray *ba=qscriptvalue_cast<QByteArray*>(object().data());
m_index=ba->size();
m_last=-1;
}
QScriptString ByteArrayIterator::name() const {
return this->object().engine()->toStringHandle(QString::number(this->m_last));
}
uint ByteArrayIterator::id() const {
return m_last;
}
diff --git a/trunk/qtscript_types/bytearrayiterator.h b/trunk/qtscript_types/bytearrayiterator.h
index 088489b..b80e16a 100644
--- a/trunk/qtscript_types/bytearrayiterator.h
+++ b/trunk/qtscript_types/bytearrayiterator.h
@@ -1,51 +1,51 @@
/*******************************************************************************
-* Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* Copyright (c) 2011-2014 by Gillen Daniel <gillen.dan@pinguin.lu> *
* *
* Derived from code by Nokia Corporation and/or its subsidiary(-ies) under a *
* compatible license: *
* *
* Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). *
* All rights reserved. *
* *
* 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 BYTEARRAYITERATOR_H
#define BYTEARRAYITERATOR_H
#include <QtScript/QScriptClassPropertyIterator>
class ByteArrayIterator : public QScriptClassPropertyIterator {
public:
ByteArrayIterator(const QScriptValue &object);
~ByteArrayIterator();
bool hasNext() const;
void next();
bool hasPrevious() const;
void previous();
void toFront();
void toBack();
QScriptString name() const;
uint id() const;
private:
int m_index;
int m_last;
};
#endif // BYTEARRAYITERATOR_H
diff --git a/trunk/qtscript_types/bytearrayprototype.cpp b/trunk/qtscript_types/bytearrayprototype.cpp
index af6fb83..0c291a7 100644
--- a/trunk/qtscript_types/bytearrayprototype.cpp
+++ b/trunk/qtscript_types/bytearrayprototype.cpp
@@ -1,110 +1,110 @@
/*******************************************************************************
-* Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* Copyright (c) 2011-2014 by Gillen Daniel <gillen.dan@pinguin.lu> *
* *
* Derived from code by Nokia Corporation and/or its subsidiary(-ies) under a *
* compatible license: *
* *
* Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). *
* All rights reserved. *
* *
* 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 <QtScript/QScriptEngine>
#include "bytearrayprototype.h"
Q_DECLARE_METATYPE(QByteArray*)
ByteArrayPrototype::ByteArrayPrototype(QObject *p_parent) : QObject(p_parent) {}
ByteArrayPrototype::~ByteArrayPrototype() {}
QByteArray *ByteArrayPrototype::thisByteArray() const {
return qscriptvalue_cast<QByteArray*>(thisObject().data());
}
void ByteArrayPrototype::chop(int n) {
thisByteArray()->chop(n);
}
bool ByteArrayPrototype::equals(const QByteArray &other) {
return *thisByteArray()==other;
}
QByteArray ByteArrayPrototype::left(int len) const {
return thisByteArray()->left(len);
}
QByteArray ByteArrayPrototype::mid(int pos, int len) const {
return thisByteArray()->mid(pos,len);
}
QScriptValue ByteArrayPrototype::remove(int pos, int len) {
thisByteArray()->remove(pos,len);
return thisObject();
}
QScriptValue ByteArrayPrototype::append(const QByteArray &ba) {
thisByteArray()->append(ba);
return thisObject();
}
QScriptValue ByteArrayPrototype::appendByte(char byte) const {
thisByteArray()->append(byte);
return thisObject();
}
QByteArray ByteArrayPrototype::right(int len) const {
return thisByteArray()->right(len);
}
/*
QByteArray ByteArrayPrototype::simplified() const {
return thisByteArray()->simplified();
}
*/
int ByteArrayPrototype::size() const {
return thisByteArray()->size();
}
QByteArray ByteArrayPrototype::toBase64() const {
return thisByteArray()->toBase64();
}
QByteArray ByteArrayPrototype::toLower() const {
return thisByteArray()->toLower();
}
QByteArray ByteArrayPrototype::toUpper() const {
return thisByteArray()->toUpper();
}
QByteArray ByteArrayPrototype::trimmed() const {
return thisByteArray()->trimmed();
}
void ByteArrayPrototype::truncate(int pos) {
thisByteArray()->truncate(pos);
}
QString ByteArrayPrototype::toLatin1String() const {
return QString::fromLatin1(*thisByteArray());
}
QScriptValue ByteArrayPrototype::valueOf() const {
return thisObject().data();
}
diff --git a/trunk/qtscript_types/bytearrayprototype.h b/trunk/qtscript_types/bytearrayprototype.h
index b4cc9f9..7afeb6b 100644
--- a/trunk/qtscript_types/bytearrayprototype.h
+++ b/trunk/qtscript_types/bytearrayprototype.h
@@ -1,63 +1,63 @@
/*******************************************************************************
-* Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* Copyright (c) 2011-2014 by Gillen Daniel <gillen.dan@pinguin.lu> *
* *
* Derived from code by Nokia Corporation and/or its subsidiary(-ies) under a *
* compatible license: *
* *
* Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). *
* All rights reserved. *
* *
* 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 BYTEARRAYPROTOTYPE_H
#define BYTEARRAYPROTOTYPE_H
#include <QByteArray>
#include <QObject>
#include <QtScript/QScriptable>
#include <QtScript/QScriptValue>
class ByteArrayPrototype : public QObject, public QScriptable {
Q_OBJECT
public:
ByteArrayPrototype(QObject *p_parent=0);
~ByteArrayPrototype();
public slots:
void chop(int n);
bool equals(const QByteArray &other);
QByteArray left(int len) const;
QByteArray mid(int pos, int len = -1) const;
QScriptValue remove(int pos, int len);
QScriptValue append(const QByteArray &ba);
QScriptValue appendByte(char byte) const;
QByteArray right(int len) const;
//QByteArray simplified() const;
int size() const;
QByteArray toBase64() const;
QByteArray toLower() const;
QByteArray toUpper() const;
QByteArray trimmed() const;
void truncate(int pos);
QString toLatin1String() const;
QScriptValue valueOf() const;
private:
QByteArray *thisByteArray() const;
};
#endif // BYTEARRAYPROTOTYPE_H
diff --git a/trunk/registryhive.cpp b/trunk/registryhive.cpp
index de31dff..f10d888 100644
--- a/trunk/registryhive.cpp
+++ b/trunk/registryhive.cpp
@@ -1,1400 +1,1400 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 <QStringList>
#include <QDateTime>
#include <QtEndian>
#include <QDebug>
#include <stdlib.h>
#include <stdio.h>
#include "registryhive.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
// Macros to ease UTF16 endianness conversions
#undef UTF16LETOH
#define UTF16LETOH(buf,buf_len) { \
for(int buf_off=0;buf_off<((buf_len)-1);buf_off+=2) { \
*((quint16*)((buf)+buf_off))=qFromLittleEndian(*((quint16*)((buf)+buf_off))); \
} \
}
#undef UTF16BETOH
#define UTF16BETOH(buf,buf_len) { \
for(int buf_off=0;buf_off<((buf_len)-1);buf_off+=2) { \
*((quint16*)((buf)+buf_off))=qFromBigEndian(*((quint16*)((buf)+buf_off))); \
} \
}
#undef HTOUTF16LE
#define HTOUTF16LE(buf,buf_len) { \
for(int buf_off=0;buf_off<((buf_len)-1);buf_off+=2) { \
*((quint16*)((buf)+buf_off))=qToLittleEndian(*((quint16*)((buf)+buf_off))); \
} \
}
#undef HTOUTF16BE
#define HTOUTF16BE(buf,buf_len) { \
for(int buf_off=0;buf_off<((buf_len)-1);buf_off+=2) { \
*((quint16*)((buf)+buf_off))=qToBigEndian(*((quint16*)((buf)+buf_off))); \
} \
}
// Some errno numbers that hivex uses are not defined under Windows
#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
// These are the same values as defined by MSVC 10, for interoperability.
#ifndef ENOTSUP
#define ENOTSUP 129
#endif
#ifndef ELOOP
#define ELOOP 114
#endif
#endif
/*******************************************************************************
* Public
******************************************************************************/
/*
* 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;
this->is_hive_writable=false;
this->has_changes_to_commit=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;
this->is_hive_writable=!read_only;
return true;
}
/*
* Reopen
*/
bool RegistryHive::Reopen(bool read_only) {
if(!this->is_hive_open) return false;
// Close hive first
if(hivex_close(this->p_hive)!=0) {
// According to the docs, even if hivex_close fails, it frees all handles.
// So we consider this fatal and final!
this->hive_file="";
this->is_hive_open=false;
this->is_hive_writable=false;
this->has_changes_to_commit=false;
return false;
}
// Reopen same hive
this->p_hive=hivex_open(this->hive_file.toAscii().constData(),
read_only ? 0 : HIVEX_OPEN_WRITE);
if(this->p_hive==NULL) {
this->hive_file="";
this->is_hive_open=false;
this->is_hive_writable=false;
this->has_changes_to_commit=false;
return false;
}
// Update local vars
this->is_hive_writable=!read_only;
this->has_changes_to_commit=false;
return true;
}
/*
* CommitChanges
*/
bool RegistryHive::CommitChanges() {
if(!this->is_hive_open || !this->is_hive_writable) return false;
if(!this->has_changes_to_commit) return true;
// TODO: Maybe it would be more secure to commit changes to a new file and
// then move it over the original one.
if(hivex_commit(this->p_hive,NULL,0)!=0) {
return false;
}
this->has_changes_to_commit=false;
return true;
}
/*
* Close
*/
bool RegistryHive::Close() {
if(this->is_hive_open) {
// As hivex_close will _ALWAYS_ free the handle, we don't need the following
// values anymore
this->hive_file="";
this->is_hive_open=false;
this->is_hive_writable=false;
this->has_changes_to_commit=false;
// Close hive
if(hivex_close(this->p_hive)!=0) return false;
}
return true;
}
/*
* Filename
*/
QString RegistryHive::Filename() {
if(this->is_hive_open) return this->hive_file;
return QString();
}
/*
* HiveType
*/
RegistryHive::teHiveType RegistryHive::HiveType() {
// Check for SYSTEM hive
if(this->PathExists("\\Select") && this->PathExists("\\MountedDevices"))
return RegistryHive::eHiveType_SYSTEM;
// Check for SOFTWARE hive
if(this->PathExists("\\Microsoft\\Windows\\CurrentVersion") &&
this->PathExists("\\Microsoft\\Windows NT\\CurrentVersion"))
return RegistryHive::eHiveType_SOFTWARE;
// Check for SAM
if(this->PathExists("SAM\\Domains\\Account\\Users"))
return RegistryHive::eHiveType_SAM;
// Check for SECURITY
if(this->PathExists("\\Policy\\Accounts") &&
this->PathExists("\\Policy\\PolAdtEv"))
return RegistryHive::eHiveType_SECURITY;
// Check for NTUSER.DAT
if(this->PathExists("\\Software\\Microsoft\\Windows\\CurrentVersion"))
return RegistryHive::eHiveType_NTUSER;
// Unknown hive
return RegistryHive::eHiveType_UNKNOWN;
}
/*
* HiveTypeToString
*/
QString RegistryHive::HiveTypeToString(teHiveType hive_type) {
switch(hive_type) {
case RegistryHive::eHiveType_SYSTEM:
return "SYSTEM";
break;
case RegistryHive::eHiveType_SOFTWARE:
return "SOFTWARE";
break;
case RegistryHive::eHiveType_SAM:
return "SAM";
break;
case RegistryHive::eHiveType_SECURITY:
return "SECURITY";
break;
case RegistryHive::eHiveType_NTUSER:
return "NTUSER";
break;
default:
return "UNKNOWN";
}
}
/*
* HasChangesToCommit
*/
bool RegistryHive::HasChangesToCommit() {
return this->has_changes_to_commit;
}
/*
* 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);
}
/*
* GetKeyName
*/
bool RegistryHive::GetKeyName(int hive_key, QString &key_name) {
char *buf;
if(!this->is_hive_open) {
this->SetError(tr("Need to operate on an open hive!"));
return false;
}
buf=hivex_value_key(this->p_hive,(hive_value_h)hive_key);
if(buf==NULL) {
this->SetError(tr("Unable to get key name for key '%1'").arg(hive_key));
return false;
}
key_name=QString(buf);
free(buf);
return true;
}
/*
* 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);
}
/*
* GetKeyModTime
*/
qint64 RegistryHive::GetNodeModTime(QString path) {
hive_node_h node;
// Get handle to last node in path
if(!this->GetNodeHandle(path,&node)) {
this->SetError(tr("Unable to get node handle!"));
return 0;
}
// Get and return node's last modification timestamp
return this->GetNodeModTime(node);
}
/*
* GetKeyModTime
*/
qint64 RegistryHive::GetNodeModTime(int node) {
if(node==0) {
this->SetError(tr("Invalid node handle specified!"));
return 0;
}
// Get and return key's last modification timestamp
return hivex_node_timestamp(this->p_hive,node);
}
/*
* KeyValueToString
*/
QString RegistryHive::KeyValueToString(QByteArray value, int value_type) {
QString ret="";
#define ToHexStr() { \
for(int i=0;i<value.size();i++) { \
ret.append(QString("%1 ").arg((quint8)(value.constData()[i]), \
2,16,QChar('0'))); \
} \
ret.chop(1); \
}
// Convert value according to it's type
switch(value_type) {
case hive_t_REG_SZ:
case hive_t_REG_EXPAND_SZ:
// A Windows string (REG_SZ), or a Windows string containing %env%
// (environment variable expansion) elements (REG_EXPAND_SZ).
// Encoding is unknown, but often UTF16-LE (isn't this great?)
// Try to detect ANSI vs UNICODE encoding
if(value.size()==0) {
ret=QString();
} else if(value.size()>=2 && value.endsWith(QByteArray("\x00\x00",2))) {
// Seems to be a unicode string, convert to host endianness and return
// TODO: What if it is UTF16-BE?? Thx Billy!
QByteArray buf=value;
UTF16LETOH(buf.data(),buf.size());
ret=QString().fromUtf16((ushort*)(buf.constData()));
} else if(value.endsWith(QByteArray("\x00",1))) {
// Seems to be an ansi string
ret=QString().fromAscii((char*)value.constData());
} else {
// If we can't detect encoding, return string as hex
ToHexStr();
}
break;
case hive_t_REG_MULTI_SZ:
// Multiple Windows strings.
// I suppose this is always LE encoded! M$ devs really suck!
ret=RegistryHive::KeyValueToStringList(value).join("\n");
break;
case hive_t_REG_DWORD:
// DWORD (32 bit integer), little endian
ret=QString("0x%1")
.arg(qFromLittleEndian(*(quint32*)value.constData()),
8,16,QChar('0'));
break;
case hive_t_REG_DWORD_BIG_ENDIAN:
// DWORD (32 bit integer), big endian
ret=QString("0x%1")
.arg(qFromBigEndian(*(quint32*)value.constData()),
8,16,QChar('0'));
break;
case hive_t_REG_QWORD:
// QWORD (64 bit integer). Usually little endian (grrrr).
ret=QString("0x%1")
.arg(qFromLittleEndian(*(quint64*)value.constData()),
16,16,QChar('0'));
break;
case hive_t_REG_NONE:
case hive_t_REG_BINARY:
case hive_t_REG_LINK:
case hive_t_REG_RESOURCE_LIST:
case hive_t_REG_FULL_RESOURCE_DESCRIPTOR:
case hive_t_REG_RESOURCE_REQUIREMENTS_LIST:
default:
// A key without a value (REG_NONE), a blob of binary (REG_BINARY), a
// symbolic link to another part of the registry tree (REG_LINK), a
// resource list (REG_RESOURCE_LIST), a resource descriptor
// (FULL_RESOURCE_DESCRIPTOR), a resource requirements list
// (REG_RESOURCE_REQUIREMENTS_LIST) or something unknown.
// All these are converted to hex.
ToHexStr();
}
#undef ToHexStr
return ret;
}
/*
* KeyValueToString
*/
QString RegistryHive::KeyValueToString(QByteArray key_value,
QString format,
int offset,
int length,
bool little_endian)
{
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;
// Convert value
if(format=="int8" && remaining_data_len>=1) {
ret=QString("%1").arg(*(qint8*)p_data);
} else if(format=="uint8" && remaining_data_len>=1) {
ret=QString("%1").arg(*(quint8*)p_data);
} else if(format=="int16" && remaining_data_len>=2) {
qint16 val;
if(little_endian) val=qFromLittleEndian(*(qint16*)p_data);
else val=qFromBigEndian(*(qint16*)p_data);
ret=QString("%1").arg(val);
} else if(format=="uint16" && remaining_data_len>=2) {
quint16 val;
if(little_endian) val=qFromLittleEndian(*(quint16*)p_data);
else val=qFromBigEndian(*(quint16*)p_data);
ret=QString("%1").arg(val);
} else if(format=="int32" && remaining_data_len>=4) {
qint32 val;
if(little_endian) val=qFromLittleEndian(*(qint32*)p_data);
else val=qFromBigEndian(*(qint32*)p_data);
ret=QString("%1").arg(val);
} else if(format=="uint32" && remaining_data_len>=4) {
quint32 val;
if(little_endian) val=qFromLittleEndian(*(quint32*)p_data);
else val=qFromBigEndian(*(quint32*)p_data);
ret=QString("%1").arg(val);
} else if(format=="unixtime" && remaining_data_len>=4) {
quint32 val;
if(little_endian) val=qFromLittleEndian(*(quint32*)p_data);
else val=qFromBigEndian(*(quint32*)p_data);
if(val==0) {
ret="n/a";
} else {
QDateTime date_time;
date_time.setTimeSpec(Qt::UTC);
date_time.setTime_t(val);
ret=date_time.toString("yyyy/MM/dd hh:mm:ss");
}
} else if(format=="int64" && remaining_data_len>=8) {
qint64 val;
if(little_endian) val=qFromLittleEndian(*(qint64*)p_data);
else val=qFromBigEndian(*(qint64*)p_data);
ret=QString("%1").arg(val);
} else if(format=="uint64" && remaining_data_len>=8) {
quint64 val;
if(little_endian) val=qFromLittleEndian(*(quint64*)p_data);
else val=qFromBigEndian(*(quint64*)p_data);
ret=QString("%1").arg(val);
/*
// TODO: Check how one could implement this
} else if(format=="unixtime64" && remaining_data_len>=8) {
if(*(quint64*)p_data==0) {
ret="n/a";
} else {
quint64 secs=*(quint64*)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) {
quint64 val;
if(little_endian) val=qFromLittleEndian(*(quint64*)p_data);
else val=qFromBigEndian(*(quint64*)p_data);
if(val==0) {
ret="n/a";
} else {
// TODO: Warn if >32bit
QDateTime date_time;
date_time.setTimeSpec(Qt::UTC);
date_time.setTime_t(RegistryHive::FiletimeToUnixtime(val));
ret=date_time.toString("yyyy/MM/dd hh:mm:ss");
}
} else if(format=="ascii") {
if(length!=-1) {
// User specified how many bytes to convert
ret=QString().fromAscii((char*)p_data,length);
} else {
// User did not specify how many bytes to convert, make sure data is 0
// terminated
if(key_value.indexOf("\x00",offset)!=-1) {
// Data is 0 terminated
ret=QString().fromAscii((char*)p_data);
} else {
// Data is not 0 terminated, convert all remaining_data_len bytes
ret=QString().fromAscii((char*)p_data,remaining_data_len);
}
}
} else if(format=="utf16" && remaining_data_len>=2) {
QByteArray buf;
if(length!=-1) {
// User specified how many bytes to convert
buf=key_value.mid(offset,(length%2)==0 ? length : length-1);
buf.append("\x00\x00",2);
} else {
// User did not specify how many bytes to convert, make sure data is
// double 0 terminated
int null_offset=RegistryHive::FindUnicodeStringEnd(key_value.mid(offset));
if(null_offset!=-1) {
// Data is double 0 terminated
buf=key_value.mid(offset,null_offset+2);
} else {
// Data is not double 0 terminated, convert all remaining_data_len bytes
buf=key_value.mid(offset,
(remaining_data_len%2)==0 ?
remaining_data_len : remaining_data_len-1);
buf.append("\x00\x00",2);
}
}
// Convert from requested endianness to host
if(little_endian) {
UTF16LETOH(buf.data(),buf.size());
} else {
UTF16BETOH(buf.data(),buf.size());
}
ret=QString().fromUtf16((ushort*)buf.constData());
} else {
// Unknown variant type or another error
// TODO: Maybe return an error
return QString();
}
return ret;
}
/*
* KeyValueToStringList
*
* Should only be used for REG_MULTI_SZ values
*/
QStringList RegistryHive::KeyValueToStringList(QByteArray value,
bool little_endian,
bool *p_ansi_encoded)
{
// Try to find value encoding (ANSI vs UNICODE)
bool is_ansi;
if(value.size()<=2) {
// http://blogs.msdn.com/b/oldnewthing/archive/2009/10/08/9904646.aspx
// Ansi version of a REG_MULTI_SZ needs to be terminated by 2 \0 chars.
// So as long as the byte array has less or equal to 2 chars, it must be
// empty.
return QStringList();
} else if(value.size()==3) {
// Only 3 chars, this can only be an ansi string consisting of 1 char and 2
// \0 to terminate it
return QStringList()
<<QString(QChar((char)*((quint8*)(value.constData()))));
} else if(value.size()==4) {
if((quint32)*((quint32*)(value.constData()))==0) {
// http://blogs.msdn.com/b/oldnewthing/archive/2009/10/08/9904646.aspx
// Unicode version of a REG_MULTI_SZ needs to be terminated by 4 \0 chars.
// So as long as the byte array has less or equal to 4 chars, and they are
// all 0 it must be empty.
return QStringList();
} else {
// Must be the ansi version of REG_MULTI_SZ
is_ansi=true;
}
} else if((quint32)*((quint32*)(value.right(4).constData()))==0) {
// Value ends with 4 \0 chars, it must be unicode
is_ansi=false;
} else if((quint32)*((quint32*)(value.right(3).constData()))==0) {
// Value ends with 3 \0 chars. Not possible according to the specs, but
// already seen in values M$ is storing! Those were unicode.
is_ansi=false;
} else if((quint16)*((quint16*)(value.right(2).constData()))==0) {
// Value only ends with 2 \0 chars, it must be ansi
is_ansi=true;
} else {
// Value has more than 4 chars but does not end in 2 or 4 \0 chars. This
// is not according to specs!
return QStringList();
}
// Convert value to string list
QStringList result=QStringList();
QByteArray buf;
int last_pos=0,cur_pos=0;
if(!is_ansi) {
// Extract unicode strings
while(last_pos<value.size() &&
(cur_pos=RegistryHive::FindUnicodeStringEnd(value,last_pos))!=-1)
{
if(cur_pos==last_pos) break;
buf=value.mid(last_pos,(cur_pos-last_pos)+2);
if(little_endian) {
// Convert from LE to host
UTF16LETOH(buf.data(),buf.size());
} else {
// Convert from BE to host
UTF16BETOH(buf.data(),buf.size());
}
result.append(QString().fromUtf16((ushort*)buf.constData()));
last_pos=cur_pos+2;
}
} else {
// Extract ansi strings
while(last_pos<value.count() &&
(cur_pos=value.indexOf(QByteArray("\x00",1),last_pos))!=-1)
{
if(cur_pos==last_pos) break;
result.append(QString().fromLocal8Bit(value.mid(last_pos,
(cur_pos-last_pos)+1)
.constData()));
last_pos=cur_pos+1;
}
}
if(p_ansi_encoded!=NULL) *p_ansi_encoded=is_ansi;
return result;
}
/*
* StringListToKeyValue
*/
QByteArray RegistryHive::StringListToKeyValue(QStringList strings,
bool little_endian,
bool ansi_encoded)
{
// Return empty key value if there are no strings
if(strings.count()==0) {
if(ansi_encoded) return QByteArray("\x00\x00",2);
else return QByteArray("\x00\x00\x00\x00",4);
}
// Convert string list
QByteArray result=QByteArray();
QString cur_string;
QByteArray buf;
QListIterator<QString> strings_it(strings);
while(strings_it.hasNext()) {
cur_string=strings_it.next();
if(ansi_encoded) {
// Ansi encoding, simply append char string and terminating \0
result.append(cur_string.toAscii().constData(),cur_string.size());
result.append("\x00",1);
} else {
// Unicode encoding
// First, convert value to utf16
// TODO: May fail if there is a char that needs more than 16 bit
buf=QByteArray((char*)(cur_string.utf16()),cur_string.size()*2);
// Then convert to correct endianness
if(little_endian) {
HTOUTF16LE(buf.data(),buf.size());
} else {
HTOUTF16BE(buf.data(),buf.size());
}
// And finally append converted value and terminating \0\0 to result
result.append(buf);
result.append("\x00\x00",2);
}
}
// Append terminating \0 chars and return
if(ansi_encoded) result.append("\x00",1);
else result.append("\x00\x00",2);
return result;
}
/*
* GetKeyValueTypes
*/
QStringList RegistryHive::GetKeyValueTypes() {
return QStringList()<<"REG_NONE"
<<"REG_SZ"
<<"REG_EXPAND_SZ"
<<"REG_BINARY"
<<"REG_DWORD"
<<"REG_DWORD_BIG_ENDIAN"
<<"REG_LINK"
<<"REG_MULTI_SZ"
<<"REG_RESOURCE_LIST"
<<"REG_FULL_RESOURCE_DESC"
<<"REG_RESOURCE_REQ_LIST"
<<"REG_QWORD";
}
/*
* KeyTypeToString
*/
QString RegistryHive::KeyValueTypeToString(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("0x%1").arg((quint32)value_type,8,16,QChar('0'));
}
return ret;
}
/*
* StringToKeyValueType
*/
int RegistryHive::StringToKeyValueType(QString value_type) {
if(value_type=="REG_NONE") return hive_t_REG_NONE;
if(value_type=="REG_SZ") return hive_t_REG_SZ;
if(value_type=="REG_EXPAND_SZ") return hive_t_REG_EXPAND_SZ;
if(value_type=="REG_BINARY") return hive_t_REG_BINARY;
if(value_type=="REG_DWORD") return hive_t_REG_DWORD;
if(value_type=="REG_DWORD_BIG_ENDIAN") return hive_t_REG_DWORD_BIG_ENDIAN;
if(value_type=="REG_LINK") return hive_t_REG_LINK;
if(value_type=="REG_MULTI_SZ") return hive_t_REG_MULTI_SZ;
if(value_type=="REG_RESOURCE_LIST") return hive_t_REG_RESOURCE_LIST;
if(value_type=="REG_FULL_RESOURCE_DESC")
return hive_t_REG_FULL_RESOURCE_DESCRIPTOR;
if(value_type=="REG_RESOURCE_REQ_LIST")
return hive_t_REG_RESOURCE_REQUIREMENTS_LIST;
if(value_type=="REG_QWORD") return hive_t_REG_QWORD;
// I think this might be a good default :-)
return hive_t_REG_BINARY;
}
/*
* FiletimeToUnixtime
*/
quint64 RegistryHive::FiletimeToUnixtime(qint64 filetime) {
return (unsigned)((filetime-EPOCH_DIFF)/10000000);
}
/*
* AddNode
*/
int RegistryHive::AddNode(QString parent_node_path, QString node_name) {
if(!this->is_hive_writable) return 0;
// Make sure name does not contain a backslash char
if(node_name.contains('\\')) {
this->SetError(tr("Unable to add node with name '%1'. "
"Names can not include a backslash character.")
.arg(node_name));
return 0;
}
// Get node handle to the parent where the new node should be created
hive_node_h parent_node;
if(!this->GetNodeHandle(parent_node_path,&parent_node)) {
this->SetError(tr("Unable to get node handle for '%1'!")
.arg(parent_node_path));
return 0;
}
// Make sure there is no other node with same name
QMap<QString,int> child_nodes=this->GetNodes(parent_node);
if(child_nodes.contains(node_name.toAscii())) {
this->SetError(tr("The node '%1\\%2' already exists!")
.arg(parent_node_path,node_name));
return 0;
}
// Add new node
hive_node_h new_node=hivex_node_add_child(this->p_hive,
parent_node,
node_name.toAscii().constData());
if(new_node==0) {
this->SetError(tr("Unable to create new node '%1\\%2'!")
.arg(parent_node_path,node_name));
return 0;
}
this->has_changes_to_commit=true;
return new_node;
}
/*
* DeleteNode
*/
bool RegistryHive::DeleteNode(QString node_path) {
if(!this->is_hive_writable) return false;
// Get node handle to the node that should be deleted
hive_node_h node;
if(!this->GetNodeHandle(node_path,&node)) {
this->SetError(tr("Unable to get node handle for '%1'!")
.arg(node_path));
return false;
}
// Delete node
if(hivex_node_delete_child(this->p_hive,node)==-1) {
this->SetError(tr("Unable to delete node '%1'!")
.arg(node_path));
return false;
}
this->has_changes_to_commit=true;
return true;
}
/*
* AddKey
*/
int RegistryHive::AddKey(QString parent_node_path,
QString key_name,
QString key_value_type,
QByteArray key_value)
{
if(!this->is_hive_open || !this->is_hive_writable) {
this->SetError(tr("Hive has not been opened or opened read-only!"));
return false;
}
return this->SetKey(parent_node_path,
key_name,
key_value_type,
key_value,
true);
}
/*
* UpdateKey
*/
int RegistryHive::UpdateKey(QString parent_node_path,
QString key_name,
QString key_value_type,
QByteArray key_value)
{
if(!this->is_hive_open || !this->is_hive_writable) {
this->SetError(tr("Hive has not been opened or opened read-only!"));
return false;
}
return this->SetKey(parent_node_path,
key_name,
key_value_type,
key_value,
false);
}
/*
* DeleteKey
*/
bool RegistryHive::DeleteKey(QString parent_node_path, QString key_name) {
if(!this->is_hive_open || !this->is_hive_writable) {
this->SetError(tr("Hive has not been opened or opened read-only!"));
return false;
}
// libhivex offers no possibility to delete a single key :-(
// As a work around, this function temporarly stores all keys of the specified
// node, then deletes them all an re-creates all but the one that should be
// deleted.
// Get handle to parent node
hive_node_h parent_node;
if(!this->GetNodeHandle(parent_node_path,&parent_node)) {
return false;
}
// Get all 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 for parent '%1'!")
.arg(parent_node_path));
return false;
}
// Get all child key values except the one that should be deleted
int i=0;
char *p_name;
int node_keys_count=0;
hive_set_value *node_keys=NULL;
#define FREE_NODE_KEYS() { \
for(int x=0;x<node_keys_count;x++) { \
free(node_keys[x].key); \
free(node_keys[x].value); \
} \
free(node_keys); \
}
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 for a child of '%1'!")
.arg(parent_node_path));
return false;
}
if(QString(p_name)!=key_name) {
// Current key is not the one that should be deleted, save it
// Alloc mem for new hive_set_value struct in node_keys array
node_keys=(hive_set_value*)realloc(node_keys,
sizeof(hive_set_value)*
(node_keys_count+1));
if(node_keys==NULL) {
this->SetError(tr("Unable to alloc enough memory for all child keys!"));
return false;
}
// Save key name in hive_set_value struct
node_keys[node_keys_count].key=p_name;
// Get key value, key value type and key value len and save to
// hive_set_value struct
node_keys[node_keys_count].value=
hivex_value_value(this->p_hive,
p_keys[i],
&(node_keys[node_keys_count].t),
&(node_keys[node_keys_count].len));
if(node_keys[node_keys_count].value==NULL) {
this->SetError(tr("Unable to get value for key '%1'!").arg(p_name));
free(p_name);
// Free all temporary stored keys
FREE_NODE_KEYS();
return false;
}
node_keys_count++;
} else {
// Current key is to be deleted, ignore it
free(p_name);
}
i++;
}
// Save all stored keys to hive, which will discard the one that should be
// deleted
if(hivex_node_set_values(this->p_hive,
parent_node,
node_keys_count,
node_keys,
0)!=0)
{
this->SetError(tr("Unable to re-save all child keys! Please discard any "
"changes you made and start over. No doing so might end "
"in data loss!"));
// Free all temporary stored keys
FREE_NODE_KEYS();
return false;
}
// Free all temporary stored keys and return
FREE_NODE_KEYS();
#undef FREE_NODE_KEYS
this->has_changes_to_commit=true;
return true;
}
/*******************************************************************************
* Private
******************************************************************************/
/*
* HivexError2String
*/
QString RegistryHive::HivexError2String(int error) {
switch(error) {
case ENOTSUP:
return QString("Corrupt or unsupported Registry file format.");
break;
case HIVEX_NO_KEY:
return QString("Missing root key.");
break;
case EINVAL:
return QString("Passed an invalid argument to the function.");
break;
case EFAULT:
return QString("Followed a Registry pointer which goes outside the "
"registry or outside a registry block.");
break;
case ELOOP:
return QString("Registry contains cycles.");
break;
case ERANGE:
return QString("Field in the registry out of range.");
break;
case EEXIST:
return QString("Registry key already exists.");
break;
case EROFS:
return QString("Tried to write to a registry which is not opened for "
"writing.");
break;
default:
return QString("Unknown error.");
}
}
/*
* 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++) {
*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;
}
/*
* GetKeyHandle
*/
bool RegistryHive::GetKeyHandle(QString &parent_node_path,
QString &key_name,
hive_value_h *p_key)
{
// Get handle to parent node
hive_node_h parent_node;
if(!this->GetNodeHandle(parent_node_path,&parent_node)) {
return false;
}
// Get handle to key
*p_key=hivex_node_get_value(this->p_hive,
parent_node,
key_name.toAscii().constData());
if(*p_key==0) {
this->SetError(tr("Unable to get handle to key '%1\\%2'!")
.arg(parent_node_path,key_name));
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;
}
/*
* GetKeyValueHelper
*/
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;
}
/*
* PathExists
*/
bool RegistryHive::PathExists(QString path) {
bool ret;
hive_node_h node;
ret=this->GetNodeHandle(path,&node);
if(!ret || this->Error()) {
// Clear error and return false
this->GetErrorMsg();
return false;
}
return true;
}
/*
* SetKey
*/
int RegistryHive::SetKey(QString &parent_node_path,
QString &key_name,
QString &key_value_type,
QByteArray &key_value,
bool create_key)
{
// Get node handle to the node that holds the key to create/update
hive_node_h parent_node;
if(!this->GetNodeHandle(parent_node_path,&parent_node)) {
return 0;
}
// Make sure key exists if we should update it
if(!create_key) {
hive_value_h temp_key=hivex_node_get_value(this->p_hive,
parent_node,
key_name.toAscii().constData());
if(temp_key==0) {
this->SetError(tr("Inexisting key '%1\\%2' can't be updated!")
.arg(parent_node_path,key_name));
return 0;
}
}
// Create and populate hive_set_value structure
hive_set_value key_val;
key_val.key=(char*)malloc((sizeof(char)*key_name.toAscii().count())+1);
key_val.value=(char*)malloc(sizeof(char)*key_value.size());
if(key_val.key==NULL || key_val.value==NULL) {
this->SetError(tr("Unable to alloc memory for hive_set_value struct!"));
return 0;
}
strcpy(key_val.key,key_name.toAscii().constData());
key_val.t=(hive_type)this->StringToKeyValueType(key_value_type);
key_val.len=key_value.size();
memcpy(key_val.value,key_value.constData(),key_value.size());
// Create/Update key
if(hivex_node_set_value(this->p_hive,parent_node,&key_val,0)!=0) {
this->SetError(tr("Unable to update key '%1\\%2'!")
.arg(parent_node_path,key_name));
return 0;
}
// Free the hive_set_value structure
free(key_val.key);
free(key_val.value);
// To make sure everything worked, a hadle to the new key is now requeried
// from hive and then returned
hive_value_h key;
if(!this->GetKeyHandle(parent_node_path,key_name,&key)) {
return 0;
}
this->has_changes_to_commit=true;
return key;
}
/*
* FindUnicodeStringEnd
*/
int RegistryHive::FindUnicodeStringEnd(QByteArray data, int offset) {
int end_pos;
for(end_pos=offset;end_pos<(data.size()-1);end_pos+=2) {
if(*((quint16*)(data.constData()+end_pos))==0) break;
}
return end_pos<(data.size()-1) ? end_pos : -1;
}
diff --git a/trunk/registryhive.h b/trunk/registryhive.h
index 5faaa4b..f7b7898 100644
--- a/trunk/registryhive.h
+++ b/trunk/registryhive.h
@@ -1,136 +1,136 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 REGISTRYHIVE_H
#define REGISTRYHIVE_H
#include <QObject>
#include <QMap>
#ifndef HIVEX_STATIC
#include <hivex.h>
#else
#include "hivex/lib/hivex.h"
#endif
class RegistryHive : public QObject {
Q_OBJECT
public:
typedef enum eHiveType {
eHiveType_UNKNOWN=0,
eHiveType_SYSTEM,
eHiveType_SOFTWARE,
eHiveType_SAM,
eHiveType_SECURITY,
eHiveType_NTUSER
} teHiveType;
explicit RegistryHive(QObject *p_parent=0);
~RegistryHive();
bool Error();
QString GetErrorMsg();
bool Open(QString file, bool read_only=true);
bool Reopen(bool read_only=true);
bool CommitChanges();
bool Close();
QString Filename();
teHiveType HiveType();
QString HiveTypeToString(teHiveType hive_type);
bool HasChangesToCommit();
QMap<QString,int> GetNodes(QString path="\\");
QMap<QString,int> GetNodes(int parent_node=0);
QMap<QString,int> GetKeys(QString path="\\");
QMap<QString,int> GetKeys(int parent_node=0);
bool GetKeyName(int hive_key, QString &key_name);
QByteArray GetKeyValue(QString path,
QString key,
int *p_value_type,
size_t *p_value_len);
QByteArray GetKeyValue(int hive_key,
int *p_value_type,
size_t *p_value_len);
qint64 GetNodeModTime(QString path);
qint64 GetNodeModTime(int node);
static QString KeyValueToString(QByteArray value, int value_type);
static QString KeyValueToString(QByteArray value,
QString format,
int offset=0,
int length=-1,
bool little_endian=true);
static QStringList KeyValueToStringList(QByteArray value,
bool little_endian=true,
bool *p_ansi_encoded=NULL);
static QByteArray StringListToKeyValue(QStringList strings,
bool little_endian=true,
bool ansi_encoded=false);
static QStringList GetKeyValueTypes();
static QString KeyValueTypeToString(int value_type);
static int StringToKeyValueType(QString value_type);
static quint64 FiletimeToUnixtime(qint64 filetime);
int AddNode(QString parent_node_path, QString node_name);
bool DeleteNode(QString node_path);
int AddKey(QString parent_node_path,
QString key_name,
QString key_value_type,
QByteArray key_value);
int UpdateKey(QString parent_node_path,
QString key_name,
QString key_value_type,
QByteArray key_value);
bool DeleteKey(QString parent_node_path, QString key_name);
private:
QString erro_msg;
bool is_error;
QString hive_file;
hive_h *p_hive;
bool is_hive_open;
bool is_hive_writable;
bool has_changes_to_commit;
QString HivexError2String(int error);
void SetError(QString msg);
bool GetNodeHandle(QString &path, hive_node_h *p_node);
bool GetKeyHandle(QString &parent_node_path,
QString &key_name,
hive_value_h *p_key);
QMap<QString,int> GetNodesHelper(hive_node_h parent_node);
QMap<QString,int> GetKeysHelper(hive_node_h parent_node);
QByteArray GetKeyValueHelper(hive_value_h hive_key,
int *p_value_type,
size_t *p_value_len);
bool PathExists(QString path);
int SetKey(QString &parent_node_path,
QString &key_name,
QString &key_value_type,
QByteArray &key_value,
bool create_key);
static int FindUnicodeStringEnd(QByteArray data, int offset=0);
};
#endif // REGISTRYHIVE_H
diff --git a/trunk/registrykey.cpp b/trunk/registrykey.cpp
index d9ac54e..8d9904c 100644
--- a/trunk/registrykey.cpp
+++ b/trunk/registrykey.cpp
@@ -1,63 +1,63 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 "registrykey.h"
RegistryKey::RegistryKey(const QList<QVariant> &data) {
this->key_data=data;
}
RegistryKey::~RegistryKey() {
qDeleteAll(this->keys);
}
void RegistryKey::Append(RegistryKey *p_key) {
this->keys.append(p_key);
}
void RegistryKey::SetData(const QList<QVariant> &data) {
this->key_data=data;
}
void RegistryKey::Remove(quint64 row) {
RegistryKey *p_key=this->keys.takeAt(row);
delete p_key;
}
RegistryKey* RegistryKey::Key(quint64 row) {
return this->keys.value(row);
}
quint64 RegistryKey::RowCount() {
return this->keys.count();
}
QVariant RegistryKey::Data(int column) const {
if(column>=0 && column<3) {
return this->key_data.value(column);
} else {
return QVariant();
}
}
quint64 RegistryKey::Row() const {
return this->keys.indexOf(const_cast<RegistryKey*>(this));
}
diff --git a/trunk/registrykey.h b/trunk/registrykey.h
index 82f5439..a804bca 100644
--- a/trunk/registrykey.h
+++ b/trunk/registrykey.h
@@ -1,45 +1,45 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 REGISTRYKEY_H
#define REGISTRYKEY_H
#include <QList>
#include <QVariant>
class RegistryKey {
public:
RegistryKey(const QList<QVariant> &data);
~RegistryKey();
void Append(RegistryKey *p_key);
void SetData(const QList<QVariant> &data);
void Remove(quint64 row);
RegistryKey *Key(quint64 row);
quint64 RowCount();
QVariant Data(int column) const;
quint64 Row() const;
private:
QList<RegistryKey*> keys;
QList<QVariant> key_data;
};
#endif // REGISTRYKEY_H
diff --git a/trunk/registrykeytable.cpp b/trunk/registrykeytable.cpp
index 63358ea..017323b 100644
--- a/trunk/registrykeytable.cpp
+++ b/trunk/registrykeytable.cpp
@@ -1,213 +1,213 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 <QHeaderView>
#include <QApplication>
#include <QClipboard>
#include "registrykeytable.h"
/*******************************************************************************
* Public
******************************************************************************/
RegistryKeyTable::RegistryKeyTable(QWidget *p_parent) : QTableView(p_parent) {
this->is_writable=false;
// 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 item
this->p_action_add_key=new QAction(tr("Add new key"),this);
this->p_action_edit_key=new QAction(tr("Edit selected key"),this);
this->p_action_delete_key=new QAction(tr("Delete selected key"),this);
this->p_menu_copy=new QMenu(tr("Copy"),this);
this->p_action_copy_key_name=
new QAction(tr("Selected key name"),this->p_menu_copy);
this->p_menu_copy->addAction(this->p_action_copy_key_name);
this->p_action_copy_key_value=
new QAction(tr("Selected key value"),this->p_menu_copy);
this->p_menu_copy->addAction(this->p_action_copy_key_value);
// Connect context menu signals
this->connect(this->p_action_add_key,
SIGNAL(triggered()),
this,
SLOT(SlotAddKey()));
this->connect(this->p_action_edit_key,
SIGNAL(triggered()),
this,
SLOT(SlotEditKey()));
this->connect(this->p_action_delete_key,
SIGNAL(triggered()),
this,
SLOT(SlotDeleteKey()));
this->connect(this->p_action_copy_key_name,
SIGNAL(triggered()),
this,
SLOT(SlotCopyKeyName()));
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;
delete this->p_action_delete_key;
delete this->p_action_edit_key;
delete this->p_action_add_key;
}
void RegistryKeyTable::setModel(QAbstractItemModel *p_model, bool writable) {
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);
}
// Set writable status
this->SetWritable(writable);
}
void RegistryKeyTable::SetWritable(bool writable) {
this->is_writable=writable;
this->p_action_add_key->setEnabled(this->is_writable);
this->p_action_edit_key->setEnabled(this->is_writable);
this->p_action_delete_key->setEnabled(this->is_writable);
}
/*
void RegistryKeyTable::selectRow(QString key_name) {
int i;
this->clearSelection();
for(i=0;i<this->model()->rowCount();i++) {
if(this->model())
}
}
*/
/*******************************************************************************
* Protected
******************************************************************************/
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 if a hive is open (a model was set)
if(this->model()==NULL) return;
// Decide what menus should be enabled
if(this->selectedIndexes().count()==3) {
// A row is selected, enable full context menu
this->p_action_add_key->setEnabled(this->is_writable);
this->p_action_edit_key->setEnabled(this->is_writable);
this->p_action_delete_key->setEnabled(this->is_writable);
this->p_menu_copy->setEnabled(true);
} else {
// No row is selected, disable all menu items except AddKey
this->p_action_add_key->setEnabled(this->is_writable);
this->p_action_edit_key->setEnabled(false);
this->p_action_delete_key->setEnabled(false);
this->p_menu_copy->setEnabled(false);
}
// Emit clicked signal (makes sure item under cursor is selected if it wasn't)
emit(this->clicked(this->indexAt(p_event->pos())));
// Create context menu, add actions and show it
QMenu context_menu(this);
context_menu.addAction(this->p_action_add_key);
context_menu.addAction(this->p_action_edit_key);
context_menu.addAction(this->p_action_delete_key);
context_menu.addSeparator();
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));
}
/*******************************************************************************
* Private slots
******************************************************************************/
void RegistryKeyTable::SlotAddKey() {
emit(this->SignalAddKey());
}
void RegistryKeyTable::SlotEditKey() {
emit(this->SignalEditKey(this->selectedIndexes().at(0)));
}
void RegistryKeyTable::SlotDeleteKey() {
emit(this->SignalDeleteKey(this->selectedIndexes().at(0)));
}
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 1502886..acd8be0 100644
--- a/trunk/registrykeytable.h
+++ b/trunk/registrykeytable.h
@@ -1,69 +1,69 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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, bool writable=false);
void SetWritable(bool writable);
//void selectRow(QString key_name);
Q_SIGNALS:
void CurrentItemChanged(QModelIndex current);
void SignalAddKey();
void SignalEditKey(QModelIndex node);
void SignalDeleteKey(QModelIndex node);
protected:
int sizeHintForColumn(int column) const;
void contextMenuEvent(QContextMenuEvent *p_event);
void currentChanged(const QModelIndex &current,
const QModelIndex &previous);
private:
bool is_writable;
QAction *p_action_add_key;
QAction *p_action_edit_key;
QAction *p_action_delete_key;
QMenu *p_menu_copy;
QAction *p_action_copy_key_name;
QAction *p_action_copy_key_value;
private slots:
void SlotAddKey();
void SlotEditKey();
void SlotDeleteKey();
void SlotCopyKeyName();
void SlotCopyKeyValue();
};
#endif // REGISTRYKEYTABLE_H
diff --git a/trunk/registrykeytablemodel.cpp b/trunk/registrykeytablemodel.cpp
index 2e742e3..96260aa 100644
--- a/trunk/registrykeytablemodel.cpp
+++ b/trunk/registrykeytablemodel.cpp
@@ -1,286 +1,286 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 "registrykeytablemodel.h"
/*******************************************************************************
* Public
******************************************************************************/
RegistryKeyTableModel::RegistryKeyTableModel(RegistryHive *p_hive,
QString node_path,
QObject *p_parent)
: QAbstractTableModel(p_parent)
{
// Create the "root" key. It's values will be used as header values.
this->p_keys=new RegistryKey(QList<QVariant>()<<
tr("Key")<<
tr("Type")<<
tr("Value"));
// Build key list
this->SetupModelData(p_hive,node_path);
}
RegistryKeyTableModel::~RegistryKeyTableModel() {
delete this->p_keys;
}
QVariant RegistryKeyTableModel::data(const QModelIndex &index, int role) const {
bool ok;
if(!index.isValid()) return QVariant();
RegistryKey *p_key=static_cast<RegistryKey*>(index.internalPointer());
switch(role) {
case Qt::DisplayRole: {
switch(index.column()) {
case RegistryKeyTableModel::ColumnContent_KeyName: {
return p_key->Data(index.column());
break;
}
case RegistryKeyTableModel::ColumnContent_KeyType: {
int value_type=p_key->Data(index.column()).toInt(&ok);
if(!ok) return QVariant();
return RegistryHive::KeyValueTypeToString(value_type);
break;
}
case RegistryKeyTableModel::ColumnContent_KeyValue: {
// Get index to value type
QModelIndex type_index=this->index(index.row(),
RegistryKeyTableModel::
ColumnContent_KeyType);
// Get value type
int value_type=this->data(type_index,
RegistryKeyTableModel::
AdditionalRoles_GetRawData).toInt(&ok);
if(!ok) return QVariant();
// Return value converted to human readeable string
QByteArray value_array=p_key->Data(index.column()).toByteArray();
return RegistryHive::KeyValueToString(value_array,value_type);
break;
}
default:
return QVariant();
}
break;
}
case RegistryKeyTableModel::AdditionalRoles_GetRawData: {
return p_key->Data(index.column());
break;
}
default:
return QVariant();
}
return QVariant();
}
Qt::ItemFlags RegistryKeyTableModel::flags(const QModelIndex &index) const {
if(!index.isValid()) return 0;
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
}
QVariant RegistryKeyTableModel::headerData(int section,
Qt::Orientation orientation,
int role) const
{
// Only horizontal header is supported
if(orientation!=Qt::Horizontal) return QVariant();
switch(role) {
case Qt::TextAlignmentRole:
// Handle text alignment
if(section==2) return Qt::AlignLeft;
else return Qt::AlignCenter;
break;
case Qt::DisplayRole:
// Header text
return this->p_keys->Data(section);
break;
default:
return QVariant();
}
}
QModelIndex RegistryKeyTableModel::index(int row,
int column,
const QModelIndex &parent) const
{
if(!this->hasIndex(row,column,parent)) return QModelIndex();
RegistryKey *p_key=this->p_keys->Key(row);
return this->createIndex(row,column,p_key);
}
int RegistryKeyTableModel::rowCount(const QModelIndex &parent) const {
// According to Qt doc, when parent in TableModel is valid, we should return 0
if(parent.isValid()) return 0;
// Get and return row count from the keys list
return this->p_keys->RowCount();
}
int RegistryKeyTableModel::columnCount(const QModelIndex &parent) const {
// According to Qt doc, when parent in TableModel is valid, we should return 0
if(parent.isValid()) return 0;
// There are always 3 columns
return 3;
}
int RegistryKeyTableModel::GetKeyRow(QString key_name) const {
int i;
for(i=0;i<this->p_keys->RowCount();i++) {
if(this->p_keys->Key(i)->Data(0)==key_name) {
return i;
}
}
// When key isn't found, return the first row
return 0;
}
QModelIndex RegistryKeyTableModel::AddKey(RegistryHive *p_hive,
int new_key_id)
{
RegistryKey *p_key;
QString key_name;
QByteArray key_value;
int key_value_type;
size_t key_value_len;
// Tell users of this model that we are going to add a row
emit(RegistryKeyTableModel::beginInsertRows(QModelIndex(),
this->p_keys->RowCount(),
this->p_keys->RowCount()));
// Get key name
if(!p_hive->GetKeyName(new_key_id,key_name)) {
return QModelIndex();
}
// Get key value, value type and value length
key_value=p_hive->GetKeyValue(new_key_id,&key_value_type,&key_value_len);
if(p_hive->GetErrorMsg()!="") {
return QModelIndex();
}
// Create new RegistryKey object and add it to our internal list
p_key=new RegistryKey(QList<QVariant>()<<
QString(key_name.length() ? key_name : "(default)")<<
QVariant(key_value_type)<<
key_value);
this->p_keys->Append(p_key);
// Tell users of this model we have finished adding a row
emit(RegistryKeyTableModel::endInsertRows());
// Return an index to the new row
return this->index(this->p_keys->RowCount()-1,0);
}
QModelIndex RegistryKeyTableModel::UpdateKey(RegistryHive *p_hive,
int new_key_id)
{
QString key_name;
QByteArray key_value;
int key_value_type;
size_t key_value_len;
int key_row=-1;
// Get key name
if(!p_hive->GetKeyName(new_key_id,key_name)) {
return QModelIndex();
}
// Get key value, value type and value length
key_value=p_hive->GetKeyValue(new_key_id,&key_value_type,&key_value_len);
if(p_hive->GetErrorMsg()!="") {
return QModelIndex();
}
// Find row containig the key to update
for(int i=0;i<this->p_keys->RowCount();i++) {
if(this->p_keys->Key(i)->Data(0).toString().toLower()==key_name.toLower()) {
key_row=i;
}
}
if(key_row==-1) return QModelIndex();
// Update values
this->p_keys->Key(key_row)->SetData(QList<QVariant>()<<
QString(key_name.length() ?
key_name : "(default)")<<
QVariant(key_value_type)<<
key_value);
// Tell users of this model that data has changed
emit(RegistryKeyTableModel::dataChanged(this->index(key_row,0),
this->index(key_row,0)));
return this->index(key_row,0);
}
QModelIndex RegistryKeyTableModel::RemoveKey(const QModelIndex &index) {
// Tell users of this model that a row is going to be removed
emit(RegistryKeyTableModel::beginRemoveRows(QModelIndex(),
index.row(),
index.row()));
// Remove row
this->p_keys->Remove(index.row());
// Tell users of this model that a row has been removed
emit(RegistryKeyTableModel::endRemoveRows());
// Return a valid index to be selected
if(this->rowCount()==0) return QModelIndex();
else if(index.row()==0) return this->index(0,0);
else if(index.row()<this->rowCount()) return this->index(index.row(),0);
else return this->index(index.row()-1,0);
}
/*******************************************************************************
* Private
******************************************************************************/
void RegistryKeyTableModel::SetupModelData(RegistryHive *p_hive,
QString &node_path)
{
QMap<QString,int> node_keys;
RegistryKey *p_key;
QByteArray key_value;
int key_value_type;
size_t key_value_len;
// Get all keys for current node
node_keys=p_hive->GetKeys(node_path);
if(node_keys.isEmpty()) return;
// Add all keys to list
QMapIterator<QString,int> i(node_keys);
while(i.hasNext()) {
i.next();
key_value=p_hive->GetKeyValue(i.value(),
&key_value_type,
&key_value_len);
if(p_hive->GetErrorMsg()!="") continue;
p_key=new RegistryKey(QList<QVariant>()<<
QString(i.key().length() ? i.key() : tr("(default)"))<<
QVariant(key_value_type)<<
key_value);
this->p_keys->Append(p_key);
}
}
diff --git a/trunk/registrykeytablemodel.h b/trunk/registrykeytablemodel.h
index 12ed33e..b0a3662 100644
--- a/trunk/registrykeytablemodel.h
+++ b/trunk/registrykeytablemodel.h
@@ -1,70 +1,70 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 REGISTRYKEYTABLEMODEL_H
#define REGISTRYKEYTABLEMODEL_H
#include <QAbstractTableModel>
#include "registrykey.h"
#include "registryhive.h"
class RegistryKeyTableModel : public QAbstractTableModel {
Q_OBJECT
public:
enum ColumnContent {
ColumnContent_KeyName=0,
ColumnContent_KeyType,
ColumnContent_KeyValue
};
enum AdditionalRoles {
AdditionalRoles_GetRawData=Qt::UserRole
};
RegistryKeyTableModel(RegistryHive *p_hive,
QString node_path,
QObject *p_parent=0);
~RegistryKeyTableModel();
QVariant data(const QModelIndex &index, int role) const;
Qt::ItemFlags flags(const QModelIndex &index) const;
QVariant headerData(int section,
Qt::Orientation orientation,
int role=Qt::DisplayRole) const;
QModelIndex index(int row,
int column,
const QModelIndex &parent=QModelIndex()) const;
int rowCount(const QModelIndex &parent=QModelIndex()) const;
int columnCount(const QModelIndex &parent=QModelIndex()) const;
int GetKeyRow(QString key_name) const;
QModelIndex AddKey(RegistryHive *p_hive, int new_key_id);
QModelIndex UpdateKey(RegistryHive *p_hive, int new_key_id);
QModelIndex RemoveKey(const QModelIndex &index);
private:
RegistryKey *p_keys;
void SetupModelData(RegistryHive *p_hive, QString &node_path);
};
#endif // REGISTRYKEYTABLEMODEL_H
diff --git a/trunk/registrynode.cpp b/trunk/registrynode.cpp
index a3f0e1d..4fbdaeb 100644
--- a/trunk/registrynode.cpp
+++ b/trunk/registrynode.cpp
@@ -1,74 +1,74 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 "registrynode.h"
RegistryNode::RegistryNode(const QList<QVariant> &data,
RegistryNode *p_parent)
{
this->node_data=data;
this->p_parent_node=p_parent;
}
RegistryNode::~RegistryNode() {
qDeleteAll(this->child_nodes);
}
void RegistryNode::AppendChild(RegistryNode *p_child) {
this->child_nodes.append(p_child);
}
void RegistryNode::RemoveChild(quint64 row) {
if(row>=this->child_nodes.count()) return;
// Remove child from list and delete it (Will also delete all sub-nodes)
RegistryNode *p_child;
p_child=this->child_nodes.takeAt(row);
delete p_child;
}
RegistryNode* RegistryNode::Child(quint64 row) {
return this->child_nodes.value(row);
}
quint64 RegistryNode::ChildCount() const {
return this->child_nodes.count();
}
QVariant RegistryNode::Data(int column) const {
if(column>=0 && column<2) {
return this->node_data.value(column);
} else {
return QVariant();
}
}
quint64 RegistryNode::Row() const {
if(this->p_parent_node) {
return this->p_parent_node->
child_nodes.indexOf(const_cast<RegistryNode*>(this));
} else {
return 0;
}
}
RegistryNode *RegistryNode::Parent() {
return this->p_parent_node;
}
diff --git a/trunk/registrynode.h b/trunk/registrynode.h
index 927f3f7..1604517 100644
--- a/trunk/registrynode.h
+++ b/trunk/registrynode.h
@@ -1,47 +1,47 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 REGISTRYNODE_H
#define REGISTRYNODE_H
#include <QList>
#include <QVariant>
class RegistryNode {
public:
RegistryNode(const QList<QVariant> &data,
RegistryNode *p_parent=0);
~RegistryNode();
void AppendChild(RegistryNode *p_child);
void RemoveChild(quint64 row);
RegistryNode *Child(quint64 row);
quint64 ChildCount() const;
QVariant Data(int column) const;
quint64 Row() const;
RegistryNode *Parent();
private:
QList<RegistryNode*> child_nodes;
QList<QVariant> node_data;
RegistryNode *p_parent_node;
};
#endif // REGISTRYNODE_H
diff --git a/trunk/registrynodetree.cpp b/trunk/registrynodetree.cpp
index 3e6fc76..4503468 100644
--- a/trunk/registrynodetree.cpp
+++ b/trunk/registrynodetree.cpp
@@ -1,185 +1,185 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 <QHeaderView>
#include <QApplication>
#include <QClipboard>
#include <QDebug>
#include "registrynodetree.h"
#include "registrynodetreemodel.h"
/*******************************************************************************
* Public
******************************************************************************/
RegistryNodeTree::RegistryNodeTree(QWidget *p_parent) : QTreeView(p_parent) {
this->is_writable=false;
// Configure widget
this->setTextElideMode(Qt::ElideNone);
this->setSelectionMode(QAbstractItemView::SingleSelection);
this->setSelectionBehavior(QAbstractItemView::SelectRows);
this->sortByColumn(0,Qt::AscendingOrder);
this->setSortingEnabled(true);
// Create context menu items
this->p_action_add_node=new QAction(tr("Add new node"),this);
this->p_action_delete_node=new QAction(tr("Delete selected node"),this);
this->p_menu_copy=new QMenu(tr("Copy"),this);
this->p_action_copy_node_name=
new QAction(tr("Selected node name"),this->p_menu_copy);
this->p_menu_copy->addAction(this->p_action_copy_node_name);
this->p_action_copy_node_path=
new QAction(tr("Selected node path"),this->p_menu_copy);
this->p_menu_copy->addAction(this->p_action_copy_node_path);
// Connect context menu signals
this->connect(this->p_action_add_node,
SIGNAL(triggered()),
this,
SLOT(SlotAddNode()));
this->connect(this->p_action_delete_node,
SIGNAL(triggered()),
this,
SLOT(SlotDeleteNode()));
this->connect(this->p_action_copy_node_name,
SIGNAL(triggered()),
this,
SLOT(SlotCopyNodeName()));
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;
delete this->p_action_delete_node;
delete this->p_action_add_node;
}
void RegistryNodeTree::setModel(QAbstractItemModel *p_model, bool writable) {
// Assign model to view
QTreeView::setModel(p_model);
this->header()->setResizeMode(0,QHeaderView::ResizeToContents);
this->header()->setStretchLastSection(true);
if(p_model!=NULL && p_model->index(0,0).isValid()) {
// Select first tree item
this->setCurrentIndex(p_model->index(0,0));
}
// Set writable status
this->SetWritable(writable);
}
void RegistryNodeTree::SetWritable(bool writable) {
this->is_writable=writable;
this->p_action_add_node->setEnabled(this->is_writable);
this->p_action_delete_node->setEnabled(this->is_writable);
}
/*******************************************************************************
* Protected
******************************************************************************/
void RegistryNodeTree::contextMenuEvent(QContextMenuEvent *p_event) {
// Only show context menu when a node is selected
if(this->selectedIndexes().count()!=2) return;
// Only show context menu when user clicked on selected row
if(this->indexAt(p_event->pos()).row()!=this->selectedIndexes().at(0).row())
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.addAction(this->p_action_add_node);
context_menu.addAction(this->p_action_delete_node);
context_menu.addSeparator();
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()==2 &&
p_event->key()==Qt::Key_Left)
{
QModelIndex cur_index=this->selectedIndexes().at(0);
if(this->model()->hasChildren(cur_index) && this->isExpanded(cur_index)) {
// Current node is expanded. Only collapse this one
this->collapse(cur_index);
return;
}
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));
}
/*******************************************************************************
* Private slots
******************************************************************************/
void RegistryNodeTree::SlotAddNode() {
emit(RegistryNodeTree::SignalAddNode(this->selectedIndexes().at(0)));
}
void RegistryNodeTree::SlotDeleteNode() {
emit(RegistryNodeTree::SignalDeleteNode(this->selectedIndexes().at(0)));
}
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 6a7d988..884fd51 100644
--- a/trunk/registrynodetree.h
+++ b/trunk/registrynodetree.h
@@ -1,68 +1,68 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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, bool writable=false);
void SetWritable(bool writable);
Q_SIGNALS:
void CurrentItemChanged(QModelIndex current);
void SignalAddNode(QModelIndex root_node);
void SignalRenameNode(QModelIndex node);
void SignalDeleteNode(QModelIndex node);
protected:
// int sizeHintForColumn(int column) const;
void contextMenuEvent(QContextMenuEvent *p_event);
void keyPressEvent(QKeyEvent *p_event);
void currentChanged(const QModelIndex &current,
const QModelIndex &previous);
private:
bool is_writable;
QAction *p_action_add_node;
QAction *p_action_delete_node;
QMenu *p_menu_copy;
QAction *p_action_copy_node_name;
QAction *p_action_copy_node_path;
private slots:
void SlotAddNode();
void SlotDeleteNode();
void SlotCopyNodeName();
void SlotCopyNodePath();
};
#endif // REGISTRYNODETREE_H
diff --git a/trunk/registrynodetreemodel.cpp b/trunk/registrynodetreemodel.cpp
index 14483f9..7d66d94 100644
--- a/trunk/registrynodetreemodel.cpp
+++ b/trunk/registrynodetreemodel.cpp
@@ -1,325 +1,325 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 <QList>
#include <QStringList>
#include <QVariant>
#include <QDateTime>
#include "registrynodetreemodel.h"
/*******************************************************************************
* Public
******************************************************************************/
RegistryNodeTreeModel::RegistryNodeTreeModel(RegistryHive *p_hive,
QObject *p_parent)
: QAbstractItemModel(p_parent)
{
// Create root node. It's values will be used as header values.
this->p_root_node=new RegistryNode(QList<QVariant>()<<tr("Node")
<<tr("Last mod. time"));
// Load data
this->SetupModelData(p_hive,this->p_root_node);
}
RegistryNodeTreeModel::~RegistryNodeTreeModel() {
delete this->p_root_node;
}
QVariant RegistryNodeTreeModel::data(const QModelIndex &index, int role) const
{
if(!index.isValid()) return QVariant();
if(role!=Qt::DisplayRole) return QVariant();
RegistryNode *p_node=static_cast<RegistryNode*>(index.internalPointer());
switch(role) {
case Qt::DisplayRole: {
switch(index.column()) {
case RegistryNodeTreeModel::ColumnContent_NodeName: {
return p_node->Data(index.column());
break;
}
case RegistryNodeTreeModel::ColumnContent_NodeModTime: {
QDateTime date_time;
bool ok=false;
date_time.setTimeSpec(Qt::UTC);
date_time.setTime_t(RegistryHive::FiletimeToUnixtime(
p_node->Data(index.column()).toLongLong(&ok)));
if(ok) return date_time.toString("yyyy/MM/dd hh:mm:ss");
else return tr("Unknown");
break;
}
default: {
return QVariant();
}
}
break;
}
default: {
return QVariant();
}
}
// Control will never reach this, but in order to stop g++ complaining...
return QVariant();
}
Qt::ItemFlags RegistryNodeTreeModel::flags(const QModelIndex &index) const {
if(!index.isValid()) return 0;
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
}
QVariant RegistryNodeTreeModel::headerData(int section,
Qt::Orientation orientation,
int role) const
{
// Only horizontal header is supported
if(orientation!=Qt::Horizontal) return QVariant();
switch(role) {
case Qt::TextAlignmentRole:
// Handle text alignment
return Qt::AlignCenter;
break;
case Qt::DisplayRole:
// Header text
return this->p_root_node->Data(section);
break;
default:
return QVariant();
}
}
QModelIndex RegistryNodeTreeModel::index(int row,
int column,
const QModelIndex &parent) const
{
if(!this->hasIndex(row,column,parent)) return QModelIndex();
RegistryNode *p_parent_node;
if(!parent.isValid()) {
p_parent_node=this->p_root_node;
} else {
p_parent_node=static_cast<RegistryNode*>(parent.internalPointer());
}
RegistryNode *p_child_node=p_parent_node->Child(row);
if(p_child_node) {
return this->createIndex(row,column,p_child_node);
} else {
return QModelIndex();
}
}
QModelIndex RegistryNodeTreeModel::parent(const QModelIndex &index) const {
if(!index.isValid()) return QModelIndex();
RegistryNode *p_child_node=
static_cast<RegistryNode*>(index.internalPointer());
RegistryNode *p_parent_node=p_child_node->Parent();
if(p_parent_node==this->p_root_node) {
return QModelIndex();
} else {
return this->createIndex(p_parent_node->Row(),0,p_parent_node);
}
}
int RegistryNodeTreeModel::rowCount(const QModelIndex &parent) const {
if(parent.column()>0) return 0;
RegistryNode *p_parent_node;
if(!parent.isValid()) {
p_parent_node=this->p_root_node;
} else {
p_parent_node=static_cast<RegistryNode*>(parent.internalPointer());
}
return p_parent_node->ChildCount();
}
int RegistryNodeTreeModel::columnCount(const QModelIndex &parent) const {
Q_UNUSED(parent);
return 2;
}
QList<QModelIndex> RegistryNodeTreeModel::GetIndexListOf(QString path) {
RegistryNode *p_parent_node=this->p_root_node;
QList<QModelIndex> ret;
QStringList nodes=path.split("\\",QString::SkipEmptyParts);
bool found=false;
// Create a list of all index's that form the supplied path
ret.clear();
for(int i=0;i<nodes.count();i++) {
found=false;
for(quint64 ii=0;ii<p_parent_node->ChildCount();ii++) {
if(p_parent_node->Child(ii)->Data(0)==nodes.at(i)) {
ret.append(this->createIndex(ii,0,p_parent_node->Child(ii)));
p_parent_node=p_parent_node->Child(ii);
found=true;
break;
}
}
// Break when last child node was found
if(found && i==nodes.count()-1) break;
// Return an empty list when a child node wasn't found
else if(!found) return QList<QModelIndex>();
}
return ret;
}
QString RegistryNodeTreeModel::GetNodePath(QModelIndex child_index) {
QString path;
// Make the specified index point to the ColumnContent_NodeName column!
child_index=this->GetNodeNameIndex(child_index);
// Get current node name
path=this->data(child_index,Qt::DisplayRole).toString().prepend("\\");
// Build node path by prepending all parent nodes names
while(this->parent(child_index)!=QModelIndex()) {
child_index=this->parent(child_index);
path.prepend(this->data(child_index,
Qt::DisplayRole).toString().prepend("\\"));
}
return path;
}
QModelIndex RegistryNodeTreeModel::AddNode(RegistryHive *p_hive,
QModelIndex parent_index,
int new_node_id,
QString new_node_name)
{
RegistryNode *p_parent_node;
qint64 key_mod_time;
RegistryNode *p_node;
// Make the specified index point to the ColumnContent_NodeName column!
parent_index=this->GetNodeNameIndex(parent_index);
// Get pointer to parent node
p_parent_node=static_cast<RegistryNode*>(parent_index.internalPointer());
// Tell users of this view that we are going to insert a row
emit(RegistryNodeTreeModel::beginInsertRows(parent_index,
p_parent_node->ChildCount(),
p_parent_node->ChildCount()));
// Create and add new node in internal node list
key_mod_time=p_hive->GetNodeModTime(new_node_id);
p_node=new RegistryNode(QList<QVariant>()<<new_node_name<<
QVariant((qlonglong)key_mod_time),
p_parent_node);
p_parent_node->AppendChild(p_node);
// Tell users of this view we have finished inserting a row
emit(RegistryNodeTreeModel::endInsertRows());
// Return index to new node
return this->createIndex(p_parent_node->ChildCount()-1,0,p_node);
}
QModelIndex RegistryNodeTreeModel::RemoveNode(QModelIndex index) {
RegistryNode *p_node;
RegistryNode *p_parent_node;
int node_row;
QModelIndex parent_node_index;
// Make the specified index point to the ColumnContent_NodeName column!
index=this->GetNodeNameIndex(index);
// Get pointers to current node and its parent
p_node=static_cast<RegistryNode*>(index.internalPointer());
p_parent_node=p_node->Parent();
// Get current nodes row
node_row=p_node->Row();
// Create index of parent node
parent_node_index=this->createIndex(p_parent_node->Row(),0,p_parent_node);
// Tell users of this view that we are going to remove a row
emit(RegistryNodeTreeModel::beginRemoveRows(parent_node_index,
node_row,
node_row));
// Remove node
p_parent_node->RemoveChild(node_row);
// Tell users of this view we have finished removing a row
emit(RegistryNodeTreeModel::endRemoveRows());
// Find a suitable index that should be selected after the current one has
// been deleted.
if(p_parent_node->ChildCount()>0) {
// Parent node still has child nodes, return nearest child node
if(node_row<p_parent_node->ChildCount()) {
// Any child node removed except the last one, row is still valid
return this->createIndex(node_row,0,p_parent_node->Child(node_row));
} else {
// Last child node removed, row-1 should be valid
return this->createIndex(node_row-1,0,p_parent_node->Child(node_row-1));
}
}
// If no child nodes are left, return parent node except if it is our root
// node!
if(p_parent_node->Parent()!=NULL) return parent_node_index;
else return QModelIndex();
}
/*******************************************************************************
* Private
******************************************************************************/
void RegistryNodeTreeModel::SetupModelData(RegistryHive *p_hive,
RegistryNode *p_parent,
int hive_node)
{
QMap<QString,int> hive_children;
RegistryNode *p_node;
qint64 key_mod_time;
// Get all sub nodes of current hive node
if(hive_node) hive_children=p_hive->GetNodes(hive_node);
else hive_children=p_hive->GetNodes("\\");
if(hive_children.isEmpty()) return;
// Recursivly iterate over all sub nodes
QMapIterator<QString, int> i(hive_children);
while(i.hasNext()) {
i.next();
key_mod_time=p_hive->GetNodeModTime(i.value());
// TODO: Maybe we have to call GetErrorMsg in case an error occured
p_node=new RegistryNode(QList<QVariant>()<<i.key()<<
QVariant((qlonglong)key_mod_time),p_parent);
p_parent->AppendChild(p_node);
this->SetupModelData(p_hive,p_node,i.value());
}
}
QModelIndex RegistryNodeTreeModel::GetNodeNameIndex(QModelIndex index) {
return this->index(index.row(),
RegistryNodeTreeModel::ColumnContent_NodeName,
index.parent());
}
diff --git a/trunk/registrynodetreemodel.h b/trunk/registrynodetreemodel.h
index 38bf211..d689622 100644
--- a/trunk/registrynodetreemodel.h
+++ b/trunk/registrynodetreemodel.h
@@ -1,71 +1,71 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 REGISTRYNODETREEMODEL_H
#define REGISTRYNODETREEMODEL_H
#include <QAbstractItemModel>
#include <QList>
#include <QString>
#include "registrynode.h"
#include "registryhive.h"
class RegistryNodeTreeModel : public QAbstractItemModel {
Q_OBJECT
public:
enum ColumnContent {
ColumnContent_NodeName=0,
ColumnContent_NodeModTime
};
RegistryNodeTreeModel(RegistryHive *p_hive, QObject *p_parent=0);
~RegistryNodeTreeModel();
QVariant data(const QModelIndex &index, int role) const;
Qt::ItemFlags flags(const QModelIndex &index) const;
QVariant headerData(int section,
Qt::Orientation orientation,
int role=Qt::DisplayRole) const;
QModelIndex index(int row,
int column,
const QModelIndex &parent=QModelIndex()) const;
QModelIndex parent(const QModelIndex &index) const;
int rowCount(const QModelIndex &parent=QModelIndex()) const;
int columnCount(const QModelIndex &parent=QModelIndex()) const;
QList<QModelIndex> GetIndexListOf(QString path);
QString GetNodePath(QModelIndex child_index);
QModelIndex AddNode(RegistryHive *p_hive, QModelIndex parent_index,
int new_node_id,
QString new_node_name);
QModelIndex RemoveNode(QModelIndex index);
private:
RegistryNode *p_root_node;
void SetupModelData(RegistryHive *p_hive,
RegistryNode *p_parent,
int hive_node=0);
QModelIndex GetNodeNameIndex(QModelIndex index);
};
#endif // REGISTRYNODETREEMODEL_H
diff --git a/trunk/registrynodetreemodelproxy.cpp b/trunk/registrynodetreemodelproxy.cpp
index 1aab83b..92fe2ad 100644
--- a/trunk/registrynodetreemodelproxy.cpp
+++ b/trunk/registrynodetreemodelproxy.cpp
@@ -1,40 +1,40 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 "registrynodetreemodelproxy.h"
RegistryNodeTreeModelProxy::RegistryNodeTreeModelProxy(QObject *p_parent) :
QSortFilterProxyModel(p_parent)
{
}
bool RegistryNodeTreeModelProxy::lessThan(const QModelIndex &left,
const QModelIndex &right) const
{
QVariant leftData=this->sourceModel()->data(left);
QVariant rightData=this->sourceModel()->data(right);
if(leftData.type()==QVariant::String && rightData.type()==QVariant::String) {
// Sort strings case insensitive
return leftData.toString().toLower()<rightData.toString().toLower();
} else {
return QSortFilterProxyModel::lessThan(left,right);
}
}
diff --git a/trunk/registrynodetreemodelproxy.h b/trunk/registrynodetreemodelproxy.h
index f5aaf73..2c7243d 100644
--- a/trunk/registrynodetreemodelproxy.h
+++ b/trunk/registrynodetreemodelproxy.h
@@ -1,36 +1,36 @@
/*******************************************************************************
-* fred Copyright (c) 2011 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 REGISTRYNODETREEMODELPROXY_H
#define REGISTRYNODETREEMODELPROXY_H
#include <QSortFilterProxyModel>
class RegistryNodeTreeModelProxy : public QSortFilterProxyModel {
Q_OBJECT
public:
explicit RegistryNodeTreeModelProxy(QObject *p_parent=0);
protected:
bool lessThan(const QModelIndex &left, const QModelIndex &right) const;
};
#endif // REGISTRYNODETREEMODELPROXY_H
diff --git a/trunk/reportengine.cpp b/trunk/reportengine.cpp
index 9375df2..ca572a9 100644
--- a/trunk/reportengine.cpp
+++ b/trunk/reportengine.cpp
@@ -1,562 +1,562 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 <QFile>
#include <QTextStream>
#include <QDateTime>
#include <QStringList>
#include <QtDebug>
#include "reportengine.h"
/*******************************************************************************
* Public
******************************************************************************/
ReportEngine::ReportEngine(RegistryHive *p_hive) : QScriptEngine() {
// Init vars
this->p_registry_hive=p_hive;
this->report_content="";
// Add our constants
this->globalObject().setProperty("ENGINE_API_VERSION",
FRED_REPORTENGINE_API_VERSION,
QScriptValue::ReadOnly|
QScriptValue::Undeletable);
/*
this->globalObject().setProperty("HIVE_FILE",
this->p_registry_hive->Filename(),
QScriptValue::ReadOnly|
QScriptValue::Undeletable);
*/
// 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());
// TODO: Is it really necessary to explicitly export these functions
// here ??????????
// 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);
// 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);
// RegistryKeyValueToStringList
QScriptValue func_value_to_string_list=
this->newFunction(this->RegistryKeyValueToStringList);
this->globalObject().setProperty("RegistryKeyValueToStringList",
func_value_to_string_list);
// RegistryKeyTypeToString
QScriptValue func_type_to_string=
this->newFunction(this->RegistryKeyTypeToString,1);
this->globalObject().setProperty("RegistryKeyTypeToString",
func_type_to_string);
}
ReportEngine::~ReportEngine() {
delete this->p_type_byte_array;
}
/*
* GetReportTemplateInfo
*/
QMap<QString,QVariant> ReportEngine::GetReportTemplateInfo(QString file) {
// Read template file
QString report_code;
if(!this->GetReportTemplateFileContents(file,report_code)) {
QMap<QString,QVariant> error_msg;
error_msg["error"]=report_code;
return error_msg;
}
// Evaluate report template script
QScriptValue report_result=this->evaluate(report_code,file);
if (report_result.isError() || this->hasUncaughtException()) {
QMap<QString,QVariant> error_msg;
error_msg["error"]=QString("File: %1\n Line: %2\nError: %3")
.arg(file)
.arg(report_result.property("lineNumber").toInt32())
.arg(report_result.toString());
return error_msg;
}
// Try to call the fred_report_info script function and return result
QScriptValue fred_report_info_func=
this->globalObject().property("fred_report_info");
if(!fred_report_info_func.isFunction()) {
QMap<QString,QVariant> error_msg;
error_msg["error"]=
QString("Report template '%1' does not have a fred_report_info function!")
.arg(file)
.arg(report_result.property("lineNumber").toInt32())
.arg(report_result.toString());
return error_msg;
}
QScriptValue fred_report_info_res=fred_report_info_func.call();
// TODO: Maybe do more checking on return value
return fred_report_info_res.toVariant().toMap();
}
/*
* GenerateReport
*/
bool ReportEngine::GenerateReport(RegistryHive *p_hive,
QString report_file,
QString &report_result,
bool console_mode)
{
// TODO: Support or remove console_mode
Q_UNUSED(console_mode);
// Clear internal buffer
this->report_content.clear();
// Update exported functions
this->UpdateExportedFunctions(p_hive);
// Read template file
QString report_code;
if(!this->GetReportTemplateFileContents(report_file,report_code)) {
report_result=report_code;
return false;
}
// Evaluate report template script
QScriptValue script_result=this->evaluate(report_code,report_file);
if (script_result.isError() || this->hasUncaughtException()) {
script_result=QString("File: %1\n Line: %2\nError: %3")
.arg(report_file)
.arg(script_result.property("lineNumber").toInt32())
.arg(script_result.toString());
return false;
}
// Try to call the fred_report_html script function and return result
QScriptValue fred_report_html_func=
this->globalObject().property("fred_report_html");
if(!fred_report_html_func.isFunction()) {
report_result=
QString("Report template '%1' does not have a fred_report_info function!")
.arg(report_file)
.arg(script_result.property("lineNumber").toInt32())
.arg(script_result.toString());
return false;
}
QScriptValue fred_report_html_res=fred_report_html_func.call();
// TODO: Maybe do more checking on return value
report_result=this->report_content;
return true;
}
/*******************************************************************************
* Public Slots
******************************************************************************/
/*******************************************************************************
* Private
******************************************************************************/
/*
* Print
*/
QScriptValue ReportEngine::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());
}
qobject_cast<ReportEngine*>(engine)->report_content.append(content);
return engine->undefinedValue();
}
/*
* PrintLn
*/
QScriptValue ReportEngine::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<ReportEngine*>(engine)->
report_content.append(content).append("\n");
return engine->undefinedValue();
}
/*
* GetRegistryNodes
*/
QScriptValue ReportEngine::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 ReportEngine::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 ReportEngine::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 ReportEngine::RegistryKeyValueFromScript(const QScriptValue &obj,
s_RegistryKeyValue &s)
{
s.type=obj.property("type").toInt32();
s.length=obj.property("length").toInt32();
s.value=qvariant_cast<QByteArray>(obj.property("value").data().toVariant());
}
/*
* GetRegistryKeyValue
*/
QScriptValue ReportEngine::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 ReportEngine::RegistryKeyValueToScript(engine,script_key_value);
}
/*
* RegistryKeyValueToString
*/
QScriptValue ReportEngine::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);
}
/*
* RegistryKeyValueToVariant
*/
QScriptValue ReportEngine::RegistryKeyValueToVariant(QScriptContext *context,
QScriptEngine *engine)
{
int offset=0;
int length=-1;
bool little_endian=true;
QByteArray key_value;
QString format="";
QString ret="";
// This function needs at least two arguments, key value and variant type,
// and may have three optional arguments, offset, length and little_endian
if(context->argumentCount()<2 || context->argumentCount()>5) {
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();
}
if(context->argumentCount()==5) {
offset=context->argument(2).toInt32();
length=context->argument(3).toInt32();
little_endian=(context->argument(4).toInt32()==1);
}
// 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,little_endian);
return engine->newVariant(ret);
}
/*
* RegistryKeyValueToStringList
*/
QScriptValue ReportEngine::RegistryKeyValueToStringList(QScriptContext *context,
QScriptEngine *engine)
{
QByteArray value;
QStringList strings;
QScriptValue ret;
int i=0;
bool little_endian=true;
// This function needs one arguments, key value, and may have a second
// specifying endianness
if(context->argumentCount()==0 || context->argumentCount()>2)
return engine->undefinedValue();
if(context->argumentCount()==2) {
little_endian=context->argument(2).toBool();
}
// Cast ByteArray argument to QByteArray and convert
value=qvariant_cast<QByteArray>(context->argument(0).data().toVariant());
strings=RegistryHive::KeyValueToStringList(value,little_endian);
// Build script array
ret=engine->newArray(strings.count());
QListIterator<QString> str_it(strings);
while(str_it.hasNext()) {
ret.setProperty(i++,QScriptValue(str_it.next()));
}
return ret;
}
/*
* RegistryKeyTypeToString
*/
QScriptValue ReportEngine::RegistryKeyTypeToString(QScriptContext *context,
QScriptEngine *engine)
{
QString ret="";
// This function needs one argument, key type
if(context->argumentCount()!=1) return engine->undefinedValue();
ret=RegistryHive::KeyValueTypeToString(context->argument(0).toInt32());
return engine->newVariant(ret);
}
/*
* GetRegistryNodeModTime
*/
QScriptValue ReportEngine::GetRegistryNodeModTime(QScriptContext *context,
QScriptEngine *engine)
{
QScriptValue calleeData;
RegistryHive *p_hive;
qint64 mod_time=0;
// This function needs one argument, 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());
mod_time=p_hive->GetNodeModTime(context->argument(0).toString());
if(p_hive->Error()) {
// Get error message to clear error state
p_hive->GetErrorMsg();
return engine->undefinedValue();
}
QDateTime date_time;
date_time.setTimeSpec(Qt::UTC);
date_time.setTime_t(RegistryHive::FiletimeToUnixtime(mod_time));
return engine->newVariant(date_time.toString("yyyy/MM/dd hh:mm:ss"));
}
/*
* GetReportTemplateFileContents
*/
bool ReportEngine::GetReportTemplateFileContents(QString file,
QString &contents)
{
// Open report template file
QFile template_file(file);
if(!template_file.open(QIODevice::ReadOnly | QIODevice::Text)) {
contents=QString("Couldn't open report template file '%1'!").arg(file);
return false;
}
// Read template file and close it
contents.clear();
QTextStream in(&template_file);
while(!in.atEnd()) contents.append(in.readLine()).append("\n");
template_file.close();
return true;
}
/*
* UpdateExportedFunctions
*/
void ReportEngine::UpdateExportedFunctions(RegistryHive *p_hive) {
this->p_registry_hive=p_hive;
// 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);
// GetRegistryNodeModTime
QScriptValue func_get_node_modt=
this->newFunction(this->GetRegistryNodeModTime,1);
func_get_node_modt.setData(this->newQObject(this->p_registry_hive));
this->globalObject().setProperty("GetRegistryNodeModTime",func_get_node_modt);
}
diff --git a/trunk/reportengine.h b/trunk/reportengine.h
index df4f376..a7b0240 100644
--- a/trunk/reportengine.h
+++ b/trunk/reportengine.h
@@ -1,91 +1,91 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 REPORTENGINE_H
#define REPORTENGINE_H
#include <QObject>
#include <QtScript/QScriptEngine>
#include <QtScript/QScriptValue>
#include <QtScript/QScriptContext>
#include <QString>
#include <QVariant>
#include <QMap>
#include "registryhive.h"
#include "qtscript_types/bytearray.h"
#define FRED_REPORTENGINE_API_VERSION 2
class ReportEngine : public QScriptEngine {
Q_OBJECT
public:
struct s_RegistryKeyValue {
int type;
int length;
QByteArray value;
};
RegistryHive *p_registry_hive;
QString report_content;
ReportEngine(RegistryHive *p_hive);
~ReportEngine();
QMap<QString,QVariant> GetReportTemplateInfo(QString file);
bool GenerateReport(RegistryHive *p_hive,
QString report_file,
QString &report_result,
bool console_mode=true);
private:
ByteArray *p_type_byte_array;
static QScriptValue Print(QScriptContext *context, QScriptEngine *engine);
static QScriptValue PrintLn(QScriptContext *context, QScriptEngine *engine);
static QScriptValue GetRegistryNodes(QScriptContext *context,
QScriptEngine *engine);
static QScriptValue GetRegistryKeys(QScriptContext *context,
QScriptEngine *engine);
static QScriptValue RegistryKeyValueToScript(QScriptEngine *engine,
const s_RegistryKeyValue &s);
static void RegistryKeyValueFromScript(const QScriptValue &obj,
s_RegistryKeyValue &s);
static QScriptValue GetRegistryKeyValue(QScriptContext *context,
QScriptEngine *engine);
static QScriptValue RegistryKeyValueToString(QScriptContext *context,
QScriptEngine *engine);
static QScriptValue RegistryKeyValueToVariant(QScriptContext *context,
QScriptEngine *engine);
static QScriptValue RegistryKeyValueToStringList(QScriptContext *context,
QScriptEngine *engine);
static QScriptValue RegistryKeyTypeToString(QScriptContext *context,
QScriptEngine *engine);
static QScriptValue GetRegistryNodeModTime(QScriptContext *context,
QScriptEngine *engine);
bool GetReportTemplateFileContents(QString file, QString &contents);
void UpdateExportedFunctions(RegistryHive *p_hive);
};
Q_DECLARE_METATYPE(ReportEngine::s_RegistryKeyValue)
#endif // REPORTENGINE_H
diff --git a/trunk/reports.cpp b/trunk/reports.cpp
index 8920d99..ffc08eb 100644
--- a/trunk/reports.cpp
+++ b/trunk/reports.cpp
@@ -1,205 +1,205 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 <QStringList>
#include <QListIterator>
#include <QDir>
#include <QMap>
#include <QDebug>
#include "reports.h"
/*******************************************************************************
* Public
******************************************************************************/
Reports::Reports(Settings *p_sets) {
this->p_settings=p_sets;
this->p_engine=new ReportEngine(NULL);
this->report_templates.clear();
if(this->p_settings!=NULL) this->LoadReportTemplates();
}
Reports::~Reports() {
qDeleteAll(this->report_templates);
delete this->p_engine;
}
void Reports::LoadReportTemplates() {
// Delete any previously loaded reports
qDeleteAll(this->report_templates);
this->report_templates.clear();
// Return if we have no settings loaded
if(this->p_settings==NULL) return;
// Load all available reports
QStringList report_dirs=this->p_settings->GetReportTemplateDirs();
QListIterator<QString> report_dir_it(report_dirs);
while(report_dir_it.hasNext()) {
this->LoadReportTemplatesFromDir(report_dir_it.next());
}
}
QStringList Reports::GetAvailableReportCategories() {
QStringList ret;
QString cat;
int i;
ret.clear();
for(i=0;i<this->report_templates.count();i++) {
cat=this->report_templates.value(i)->Category();
if(!ret.contains(cat)) ret.append(cat);
}
ret.sort();
return ret;
}
QList<ReportTemplate*> Reports::GetAvailableReports(QString category) {
QList<ReportTemplate*> ret;
QString cat;
int i=0;
ret.clear();
for(i=0;i<this->report_templates.count();i++) {
cat=this->report_templates.value(i)->Category();
if(cat==category) ret.append(this->report_templates.value(i));
}
return ret;
}
bool Reports::GenerateReport(RegistryHive *p_hive,
QString report_file,
QString &report_result,
bool console_mode)
{
return this->p_engine->GenerateReport(p_hive,
report_file,
report_result,
console_mode);
}
bool Reports::GenerateReport(RegistryHive *p_hive,
QList<ReportTemplate*> report_list,
QString &report_result,
bool console_mode)
{
bool ret;
QString res;
QListIterator<ReportTemplate*> rep_it(report_list);
while(rep_it.hasNext()) {
res="";
ret=this->GenerateReport(p_hive,
rep_it.next()->File(),
res,
console_mode);
if(ret) report_result.append(res);
// TODO: Inform user something didn't work
}
return true;
}
/*******************************************************************************
* Private
******************************************************************************/
void Reports::LoadReportTemplatesFromDir(QString dir) {
QString report_template="";
QString report_category,report_name,report_author,report_desc,report_hive;
bool found;
int i;
ReportTemplate *p_report;
// Get all template files in report_templates directory
QDir report_dir(dir);
QStringList found_report_templates=report_dir.
entryList(QStringList()<<"*.qs");
QListIterator<QString> it(found_report_templates);
while(it.hasNext()) {
// Build path to template file
report_template=report_dir.path();
report_template.append(QDir::separator());
report_template.append(it.next());
// Get report info
QMap<QString,QVariant> report_info=this->p_engine->
GetReportTemplateInfo(report_template);
if(report_info.contains("error")) {
// TODO: Inform user
qDebug()<<"Error in report '"<<report_template<<"'\n"
<<report_info["error"].toString();
continue;
}
// Make sure report is compatible with current API
if(report_info.value("fred_api",QVariant(0)).toInt()>
FRED_REPORTENGINE_API_VERSION)
{
// TODO: Inform user
qDebug()<<"Report '"<<report_template
<<"' is not compatible with current API!";
continue;
}
// Extract info values. If a value isn't present, it will be set to ""
report_category=report_info.value("report_cat").toString();
report_name=report_info.value("report_name").toString();
report_author=report_info.value("report_author").toString();
report_desc=report_info.value("report_desc").toString();
report_hive=report_info.value("hive").toString().toUpper();
// Check if a report with the same category and name was already added
found=false;
for(i=0;i<this->report_templates.count();i++) {
if(this->report_templates.at(i)->Category()==report_category &&
this->report_templates.at(i)->Name()==report_name)
{
found=true;
break;
}
}
// Add to or update report template list
if(!found) {
// Add report to list
p_report=new ReportTemplate(report_template,
report_category,
report_name,
report_author,
report_desc,
report_hive);
this->report_templates.append(p_report);
} else {
// Update report entry
p_report=this->report_templates.at(i);
p_report->SetFile(report_template);
p_report->SetAuthor(report_author);
p_report->SetDescription(report_desc);
}
}
}
diff --git a/trunk/reports.h b/trunk/reports.h
index 6ef00da..54c7abd 100644
--- a/trunk/reports.h
+++ b/trunk/reports.h
@@ -1,57 +1,57 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 REPORTS_H
#define REPORTS_H
#include <QList>
#include <QString>
#include <QStringList>
#include "reporttemplate.h"
#include "reportengine.h"
#include "settings.h"
class Reports {
public:
Reports(Settings *p_sets=NULL);
~Reports();
void LoadReportTemplates();
QStringList GetAvailableReportCategories();
QList<ReportTemplate*> GetAvailableReports(QString category);
bool GenerateReport(RegistryHive *p_hive,
QString report_file,
QString &report_result,
bool console_mode=false);
bool GenerateReport(RegistryHive *p_hive,
QList<ReportTemplate*> report_list,
QString &report_result,
bool console_mode=false);
private:
Settings *p_settings;
QList<ReportTemplate*> report_templates;
ReportEngine *p_engine;
void LoadReportTemplatesFromDir(QString dir);
};
#endif // REPORTS_H
diff --git a/trunk/reporttemplate.cpp b/trunk/reporttemplate.cpp
index 507d831..61d572b 100644
--- a/trunk/reporttemplate.cpp
+++ b/trunk/reporttemplate.cpp
@@ -1,84 +1,84 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 "reporttemplate.h"
ReportTemplate::ReportTemplate(QString report_template_file,
QString report_category,
QString report_name,
QString report_author,
QString report_desc,
QString report_hive)
{
this->template_file=report_template_file;
this->category=report_category;
this->name=report_name;
this->author=report_author;
this->description=report_desc;
this->hive=report_hive;
}
void ReportTemplate::SetFile(QString new_file) {
this->template_file=new_file;
}
void ReportTemplate::SetCategory(QString new_category) {
this->category=new_category;
}
void ReportTemplate::SetName(QString new_name) {
this->name=new_name;
}
void ReportTemplate::SetAuthor(QString new_author) {
this->author=new_author;
}
void ReportTemplate::SetDescription(QString new_desc) {
this->description=new_desc;
}
void ReportTemplate::SetHive(QString new_hive) {
this->hive=new_hive;
}
QString ReportTemplate::ReportTemplate::File() {
return this->template_file;
}
QString ReportTemplate::ReportTemplate::Category() {
return this->category;
}
QString ReportTemplate::ReportTemplate::Name() {
return this->name;
}
QString ReportTemplate::ReportTemplate::Author() {
return this->author;
}
QString ReportTemplate::ReportTemplate::Description() {
return this->description;
}
QString ReportTemplate::ReportTemplate::Hive() {
return this->hive;
}
diff --git a/trunk/reporttemplate.h b/trunk/reporttemplate.h
index 84ff695..268aa62 100644
--- a/trunk/reporttemplate.h
+++ b/trunk/reporttemplate.h
@@ -1,61 +1,61 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 REPORTTEMPLATE_H
#define REPORTTEMPLATE_H
#include <QMetaType>
#include <QString>
class ReportTemplate {
public:
ReportTemplate(QString report_template_file,
QString report_category,
QString report_name,
QString report_author,
QString report_desc,
QString report_hive);
void SetFile(QString new_file);
void SetCategory(QString new_category);
void SetName(QString new_name);
void SetAuthor(QString new_author);
void SetDescription(QString new_desc);
void SetHive(QString new_hive);
QString File();
QString Category();
QString Name();
QString Author();
QString Description();
QString Hive();
private:
QString template_file;
QString category;
QString name;
QString author;
QString description;
QString hive;
};
Q_DECLARE_METATYPE(ReportTemplate*)
#endif // REPORTTEMPLATE_H
diff --git a/trunk/searchresulttabledelegate.cpp b/trunk/searchresulttabledelegate.cpp
index 77fd779..486cfb4 100644
--- a/trunk/searchresulttabledelegate.cpp
+++ b/trunk/searchresulttabledelegate.cpp
@@ -1,38 +1,38 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 "searchresulttabledelegate.h"
SearchResultTableDelegate::SearchResultTableDelegate(QObject *parent) :
QStyledItemDelegate(parent)
{
}
void SearchResultTableDelegate::paint(QPainter *painter,
const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
if(index.isValid() && index.column()==2) {
// TODO: Render match string different
QStyledItemDelegate::paint(painter,option,index);
} else {
QStyledItemDelegate::paint(painter,option,index);
}
}
diff --git a/trunk/searchresulttabledelegate.h b/trunk/searchresulttabledelegate.h
index d1f4f2f..792a8d9 100644
--- a/trunk/searchresulttabledelegate.h
+++ b/trunk/searchresulttabledelegate.h
@@ -1,36 +1,36 @@
/*******************************************************************************
-* fred Copyright (c) 2011 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 SEARCHRESULTTABLEDELEGATE_H
#define SEARCHRESULTTABLEDELEGATE_H
#include <QStyledItemDelegate>
class SearchResultTableDelegate : public QStyledItemDelegate {
Q_OBJECT
public:
explicit SearchResultTableDelegate(QObject *parent = 0);
void paint(QPainter *painter,
const QStyleOptionViewItem &option,
const QModelIndex &index) const;
};
#endif // SEARCHRESULTTABLEDELEGATE_H
diff --git a/trunk/searchresultwidget.cpp b/trunk/searchresultwidget.cpp
index 8fea4cb..de62d33 100644
--- a/trunk/searchresultwidget.cpp
+++ b/trunk/searchresultwidget.cpp
@@ -1,124 +1,124 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 <QHeaderView>
#include <QAbstractItemView>
#include <QStringList>
#include <QTableWidgetItem>
#include <QFontMetrics>
//#include <QTextEdit>
#include "searchresultwidget.h"
SearchResultWidget::SearchResultWidget(QWidget *p_parent)
: QTableWidget(p_parent)
{
// Create our delegate instance
this->p_delegate=new SearchResultTableDelegate();
this->setItemDelegate(this->p_delegate);
this->setColumnCount(3);
this->setRowCount(0);
this->setTextElideMode(Qt::ElideNone);
this->verticalHeader()->setHidden(true);
this->setSelectionBehavior(QAbstractItemView::SelectRows);
this->setSelectionMode(QAbstractItemView::SingleSelection);
this->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
this->setHorizontalHeaderLabels(QStringList()<<tr("Path")
<<tr("Match type")
<<tr("Match text"));
}
SearchResultWidget::~SearchResultWidget() {
delete this->p_delegate;
}
void SearchResultWidget::SlotFoundMatch(ThreadSearch::eMatchType match_type,
QString path,
QString key,
QString value)
{
QTableWidgetItem *p_item;
// QTextEdit* p_te;
QString full_path;
QString type;
QString match;
switch(match_type) {
case ThreadSearch::eMatchType_NodeName:
type=tr("Node name");
full_path=path;
match=key;
break;
case ThreadSearch::eMatchType_KeyName:
type=tr("Key name");
full_path=path;
match=key;
break;
case ThreadSearch::eMatchType_KeyValue:
type=tr("Key value");
full_path=path+"\\"+key;
//if(value.length()<6934) match=value;
//else
//match=value.left(5610);
//match=QString(value);
match=value;
break;
}
int rows=this->rowCount();
this->setRowCount(rows+1);
// TODO: Use setCellWidget to add QTextEdit and then use insertText and
// insertHtml to format match
p_item=new QTableWidgetItem(full_path=="" ? "\\" : full_path);
p_item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
this->setItem(rows,0,p_item);
p_item=new QTableWidgetItem(type);
p_item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
this->setItem(rows,1,p_item);
p_item=new QTableWidgetItem(match);
p_item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
this->setItem(rows,2,p_item);
// p_te=new QTextEdit(match);
// p_te->setReadOnly(true);
// this->setCellWidget(rows,2,p_te);
}
int SearchResultWidget::sizeHintForColumn(int column) const {
int size_hint=0;
int i=0;
int item_width=0;
QFontMetrics fm(this->fontMetrics());
// if(column<0 || column>=this->columnCount()) return -1;
// Find string that needs the most amount of space
for(i=0;i<this->rowCount();i++) {
item_width=fm.width(this->item(i,column)->text())+10;
if(item_width>size_hint) size_hint=item_width;
}
return size_hint;
}
void SearchResultWidget::SlotSearchFinished() {
this->resizeColumnsToContents();
this->resizeRowsToContents();
}
diff --git a/trunk/searchresultwidget.h b/trunk/searchresultwidget.h
index b53446b..58017bb 100644
--- a/trunk/searchresultwidget.h
+++ b/trunk/searchresultwidget.h
@@ -1,48 +1,48 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 SEARCHRESULTWIDGET_H
#define SEARCHRESULTWIDGET_H
#include <QTableWidget>
#include "threadsearch.h"
#include "searchresulttabledelegate.h"
class SearchResultWidget : public QTableWidget {
Q_OBJECT
public:
SearchResultWidget(QWidget *p_parent=0);
~SearchResultWidget();
public slots:
void SlotFoundMatch(ThreadSearch::eMatchType match_type,
QString path,
QString key,
QString value);
void SlotSearchFinished();
protected:
int sizeHintForColumn(int column) const;
SearchResultTableDelegate *p_delegate;
};
#endif // SEARCHRESULTWIDGET_H
diff --git a/trunk/settings.cpp b/trunk/settings.cpp
index cb80b6c..b7d26ec 100644
--- a/trunk/settings.cpp
+++ b/trunk/settings.cpp
@@ -1,206 +1,206 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 <QDir>
#include "settings.h"
#ifndef SYSTEM_REPORT_TEMPLATE_DIR
#ifndef __MINGW32__
#define SYSTEM_REPORT_TEMPLATE_DIR "/usr/share/fred/report_templates"
#else
#define SYSTEM_REPORT_TEMPLATE_DIR ".\\report_templates\\"
#endif
#endif
#define APP_ORGANIZATION "pinguin.lu"
#define APP_NAME "fred"
// Default settings
#define DEFAULT_REPORT_TEMPLATE_DIRS QStringList()<<SYSTEM_REPORT_TEMPLATE_DIR \
<<this->user_report_template_dir
#define DEFAULT_WINDOW_GEOMETRY_STATUS true
#define DEFAULT_RECENT_FILES_DEPTH 5
#define DEFAULT_LAST_OPEN_LOCATION QDir::homePath()
#define DEFAULT_OPEN_HIVES_READ_ONLY true
/*******************************************************************************
* Public
******************************************************************************/
Settings::Settings(QObject *p_parent) : QObject(p_parent) {
// Init vars
this->p_settings=NULL;
this->initialized=false;
this->user_settings_dir=QDir::homePath()
.append(QDir::separator()).append(".fred");
this->user_report_template_dir=QString(this->user_settings_dir)
.append(QDir::separator())
.append("report_templates");
// Make sure config dirs exist
if(!QDir(this->user_settings_dir).exists()) {
// User config dir does not exists, try to create it
if(!QDir().mkpath(this->user_settings_dir)) {
// TODO: Maybe warn user
return;
}
}
if(!QDir(this->user_report_template_dir).exists()) {
// Create config dir sub folder for report templates
if(!QDir().mkpath(this->user_report_template_dir)) {
// TODO: Maybe warn user
return;
}
}
// Create / open settings
#ifndef __MINGW32__
// On any Unix-like OS, settings should be saved in the .fred folder
this->p_settings=new QSettings(QString(this->user_settings_dir)
.append(QDir::separator())
.append("fred.conf"),
QSettings::NativeFormat,
this);
#else
// On Windows, it can be stored inside registry
this->p_settings=new QSettings(QSettings::NativeFormat,
QSettings::UserScope,
APP_ORGANIZATION,
APP_NAME,
this);
#endif
if(this->p_settings->status()!=QSettings::NoError ||
!this->p_settings->isWritable())
{
return;
}
this->initialized=true;
}
void Settings::Reset() {
if(!this->initialized) return;
// Clear all current settings
this->p_settings->clear();
}
void Settings::SetReportTemplateDirs(QStringList &dirs) {
if(!this->initialized) return;
this->p_settings->setValue("ReportTemplateDirs",dirs);
}
QStringList Settings::GetReportTemplateDirs() {
if(!this->initialized) return DEFAULT_REPORT_TEMPLATE_DIRS;
return this->p_settings->value("ReportTemplateDirs",
DEFAULT_REPORT_TEMPLATE_DIRS).toStringList();
}
void Settings::SetWindowGeometryStatus(bool save) {
if(!this->initialized) return;
this->p_settings->setValue("WindowGeometries/EnableSaving",save);
}
bool Settings::GetWindowGeometryStatus() {
if(!this->initialized) return DEFAULT_WINDOW_GEOMETRY_STATUS;
return this->p_settings->value("WindowGeometries/EnableSaving",
DEFAULT_WINDOW_GEOMETRY_STATUS).toBool();
}
void Settings::SetWindowGeometry(QString window_name, QByteArray geometry) {
if(!this->initialized || !this->GetWindowGeometryStatus()) return;
this->p_settings->setValue(QString("WindowGeometries/%1").arg(window_name),
geometry);
}
QByteArray Settings::GetWindowGeometry(QString window_name) {
if(!this->initialized || !this->GetWindowGeometryStatus()) {
return QByteArray();
}
return this->p_settings->value(QString("WindowGeometries/%1")
.arg(window_name)).toByteArray();
}
void Settings::SetRecentFilesDepth(int depth) {
if(!this->initialized) return;
this->p_settings->setValue("RecentFilesDepth",depth);
// Make sure there are currently not more recent files as allowed
QStringList recent_files=this->GetRecentFiles();
while(recent_files.count()>depth) recent_files.removeLast();
this->SetRecentFiles(recent_files);
}
int Settings::GetRecentFilesDepth() {
if(!this->initialized) return DEFAULT_RECENT_FILES_DEPTH;
return this->p_settings->value("RecentFilesDepth",
DEFAULT_RECENT_FILES_DEPTH).toInt();
}
void Settings::SetRecentFiles(QStringList &recent_files) {
if(!this->initialized) return;
this->p_settings->setValue("RecentFiles",recent_files);
}
void Settings::AddRecentFile(QString file) {
// Get recent files
QStringList recent_files=this->GetRecentFiles();
if(recent_files.contains(file)) {
// File already exists in recent list. Simply move it to top
recent_files.move(recent_files.indexOf(file),0);
} else {
// We only save RecentFilesDepth() files at max
while(recent_files.count()>=this->GetRecentFilesDepth())
recent_files.removeLast();
recent_files.prepend(file);
}
this->SetRecentFiles(recent_files);
}
QStringList Settings::GetRecentFiles() {
if(!this->initialized) return QStringList();
return this->p_settings->value("RecentFiles",QStringList()).toStringList();
}
void Settings::SetLastOpenLocation(QString dir) {
if(!this->initialized) return;
this->p_settings->setValue("LastOpenLocation",dir);
}
QString Settings::GetLastOpenLocation() {
if(!this->initialized) return DEFAULT_LAST_OPEN_LOCATION;
QString last_loc;
last_loc=this->p_settings->value("RecentFiles",
DEFAULT_LAST_OPEN_LOCATION).toString();
if(QDir(last_loc).exists()) return last_loc;
else return DEFAULT_LAST_OPEN_LOCATION;
}
void Settings::SetOpenHivesReadOnly(bool read_only) {
if(!this->initialized) return;
this->p_settings->setValue("OpenFilesReadOnly",read_only);
}
bool Settings::GetOpenHivesReadOnly() {
if(!this->initialized) return DEFAULT_OPEN_HIVES_READ_ONLY;
return this->p_settings->value("OpenFilesReadOnly",
DEFAULT_OPEN_HIVES_READ_ONLY).toBool();
}
diff --git a/trunk/settings.h b/trunk/settings.h
index 57f92c5..90a3198 100644
--- a/trunk/settings.h
+++ b/trunk/settings.h
@@ -1,65 +1,65 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 SETTINGS_H
#define SETTINGS_H
#include <QObject>
#include <QSettings>
#include <QString>
#include <QStringList>
#include <QByteArray>
class Settings : public QObject {
Q_OBJECT
public:
explicit Settings(QObject *p_parent=0);
void Reset();
void SetReportTemplateDirs(QStringList &dirs);
QStringList GetReportTemplateDirs();
void SetWindowGeometryStatus(bool save);
bool GetWindowGeometryStatus();
void SetWindowGeometry(QString window_name, QByteArray geometry);
QByteArray GetWindowGeometry(QString window_name);
void SetRecentFilesDepth(int depth);
int GetRecentFilesDepth();
void SetRecentFiles(QStringList &recent_files);
void AddRecentFile(QString file);
QStringList GetRecentFiles();
void SetLastOpenLocation(QString dir);
QString GetLastOpenLocation();
void SetOpenHivesReadOnly(bool read_only);
bool GetOpenHivesReadOnly();
private:
QSettings *p_settings;
bool initialized;
QString user_settings_dir;
QString user_report_template_dir;
};
#endif // SETTINGS_H
diff --git a/trunk/tabwidget.cpp b/trunk/tabwidget.cpp
index 467938e..d4fbf2a 100644
--- a/trunk/tabwidget.cpp
+++ b/trunk/tabwidget.cpp
@@ -1,65 +1,65 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 <QTabBar>
#include <QPushButton>
#include <QIcon>
#include <QSize>
#include <QPoint>
#include "tabwidget.h"
TabWidget::TabWidget(QWidget *p_parent) : QTabWidget(p_parent) {}
int TabWidget::addTab(QWidget *p_widget,
const QString &title,
bool close_button)
{
// Add tab
int tab_index=QTabWidget::addTab(p_widget,title);
// If desired, add a close button to the tab
if(close_button) {
// Create close button
QPushButton *p_close_button=
new QPushButton(QIcon(":/icons/close_button"),QString());
p_close_button->setFlat(true);
p_close_button->setIconSize(QSize(14,14));
p_close_button->setGeometry(p_close_button->x(),p_close_button->y(),14,14);
// Connect clicked signal
this->connect(p_close_button,
SIGNAL(clicked()),
this,
SLOT(SlotCloseButtonClicked()));
this->tabBar()->setTabButton(tab_index,QTabBar::RightSide,p_close_button);
}
return tab_index;
}
void TabWidget::SlotCloseButtonClicked() {
// Find index of tab to close. The trolls do it by iterating over all tabs
// and comparing their widget with QObject::sender().
QPushButton *p_close_button=(QPushButton*)(QObject::sender());
int index=this->tabBar()->tabAt(QPoint(p_close_button->x(),
p_close_button->y()));
// Emit tabCloseRequested
emit(this->tabCloseRequested(index));
}
diff --git a/trunk/tabwidget.h b/trunk/tabwidget.h
index 5dbf65a..24e25c6 100644
--- a/trunk/tabwidget.h
+++ b/trunk/tabwidget.h
@@ -1,41 +1,41 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 TABWIDGET_H
#define TABWIDGET_H
#include <QTabWidget>
#include <QString>
class TabWidget : public QTabWidget {
Q_OBJECT
public:
TabWidget(QWidget *p_parent);
int addTab(QWidget *p_widget,
const QString &title,
bool close_button=false);
private slots:
void SlotCloseButtonClicked();
};
#endif // TABWIDGET_H
diff --git a/trunk/threadsearch.cpp b/trunk/threadsearch.cpp
index 267c614..b0a2657 100644
--- a/trunk/threadsearch.cpp
+++ b/trunk/threadsearch.cpp
@@ -1,195 +1,195 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 <QStringList>
#include <QMetaType>
#include "threadsearch.h"
#include "registryhive.h"
ThreadSearch::ThreadSearch(QObject *p_parent) : QThread(p_parent) {
this->hive_file="";
this->h_hive=NULL;
this->keywords=QList<QByteArray>();
this->search_nodes=false;
this->search_keys=false;
this->search_values=false;
this->root_node=0;
// Register meta types to be used in signals
qRegisterMetaType<ThreadSearch::eMatchType>("ThreadSearch::eMatchType");
}
bool ThreadSearch::Search(QString registry_hive,
QList<QByteArray> search_keywords,
bool search_node_names,
bool search_key_names,
bool search_key_values,
QString search_path)
{
this->hive_file=registry_hive;
this->keywords=search_keywords;
this->search_nodes=search_node_names;
this->search_keys=search_key_names;
this->search_values=search_key_values;
this->root_path=search_path=="\\" ? "" : search_path;
// Try to open hive
this->h_hive=hivex_open(this->hive_file.toAscii().constData(),0);
if(this->h_hive==NULL) return false;
// Get root node
this->root_node=hivex_root(this->h_hive);
if(this->root_node==0) {
hivex_close(this->h_hive);
return false;
}
// If a root path was specified, iterate to it
if(this->root_path!="") {
QStringList path_nodes=search_path.split("\\",QString::SkipEmptyParts);
int i;
for(i=0;i<path_nodes.count();i++) {
this->root_node=hivex_node_get_child(this->h_hive,
this->root_node,
path_nodes.at(i).toAscii().constData());
if(this->root_node==0) {
hivex_close(this->h_hive);
return false;
}
}
}
this->start();
return true;
}
void ThreadSearch::run() {
this->Match();
hivex_close(this->h_hive);
}
void ThreadSearch::Match(QString path, hive_node_h node) {
char *p_node_name;
int i,ii;
hive_node_h *p_node_childs;
QByteArray *p_byte_array;
if(node!=0) {
p_node_name=hivex_node_name(this->h_hive,node);
if(p_node_name==NULL) return;
if(this->search_nodes) {
// Compare node name to keywords
p_byte_array=new QByteArray(p_node_name);
for(i=0;i<this->keywords.count();i++) {
if(p_byte_array->indexOf(this->keywords.at(i))!=-1) {
emit(SignalFoundMatch(ThreadSearch::eMatchType_NodeName,
path,
QString(p_node_name),
QString()));
break;
}
}
delete p_byte_array;
}
if(this->search_keys || this->search_values) {
// Get key,value pairs for current node
hive_value_h *p_keys=hivex_node_values(this->h_hive,node);
if(p_keys==NULL) {
delete p_node_name;
return;
}
if(this->search_keys) {
// Compare key names to keywords
char *p_keyname;
for(i=0;p_keys[i];i++) {
p_keyname=hivex_value_key(this->h_hive,p_keys[i]);
if(p_keyname==NULL) continue;
p_byte_array=new QByteArray(p_keyname);
for(ii=0;ii<this->keywords.count();ii++) {
if(p_byte_array->indexOf(this->keywords.at(ii))!=-1) {
emit(SignalFoundMatch(ThreadSearch::eMatchType_KeyName,
path+"\\"+p_node_name,
strlen(p_keyname)==0 ? QString("(default)") : QString(p_keyname),
QString()));
break;
}
}
delete p_byte_array;
delete p_keyname;
}
}
if(this->search_values) {
// Compare key values to keywords
char *p_value;
hive_type val_type;
size_t val_len;
for(i=0;p_keys[i];i++) {
p_value=hivex_value_value(this->h_hive,p_keys[i],&val_type,&val_len);
if(p_value==NULL) continue;
p_byte_array=new QByteArray(p_value,val_len);
for(ii=0;ii<this->keywords.count();ii++) {
if(p_byte_array->indexOf(this->keywords.at(ii))!=-1) {
char *p_keyname=hivex_value_key(this->h_hive,p_keys[i]);
if(p_keyname==NULL) continue;
emit(SignalFoundMatch(ThreadSearch::eMatchType_KeyValue,
path+"\\"+p_node_name,
strlen(p_keyname)==0 ? QString("(default)") : QString(p_keyname),
RegistryHive::KeyValueToString(*p_byte_array,val_type)));
delete p_keyname;
break;
}
}
delete p_byte_array;
delete p_value;
}
}
delete p_keys;
}
// Search in subnodes
p_node_childs=hivex_node_children(this->h_hive,node);
if(p_node_childs!=NULL) {
i=0;
while(p_node_childs[i]) {
this->Match(path+"\\"+p_node_name,p_node_childs[i]);
i++;
}
delete p_node_childs;
}
delete p_node_name;
} else {
p_node_childs=hivex_node_children(this->h_hive,this->root_node);
if(p_node_childs!=NULL) {
i=0;
while(p_node_childs[i]) {
this->Match(this->root_path,p_node_childs[i]);
i++;
}
delete p_node_childs;
}
}
}
diff --git a/trunk/threadsearch.h b/trunk/threadsearch.h
index 6e1c0ff..82f23d2 100644
--- a/trunk/threadsearch.h
+++ b/trunk/threadsearch.h
@@ -1,77 +1,77 @@
/*******************************************************************************
-* fred Copyright (c) 2011-2013 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011-2014 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 THREADSEARCH_H
#define THREADSEARCH_H
#include <QThread>
#include <QObject>
#include <QString>
#include <QList>
#include <QByteArray>
#ifndef HIVEX_STATIC
#include <hivex.h>
#else
#include "hivex/lib/hivex.h"
#endif
class ThreadSearch : public QThread {
Q_OBJECT
public:
enum eMatchType {
eMatchType_NodeName=0,
eMatchType_KeyName,
eMatchType_KeyValue
};
ThreadSearch(QObject *p_parent=0);
bool Search(QString registry_hive,
QList<QByteArray> search_keywords,
bool search_node_names,
bool search_key_names,
bool search_key_values,
QString search_path="\\");
signals:
void SignalFoundMatch(ThreadSearch::eMatchType match_type,
QString path,
QString key,
QString value);
protected:
void run();
private:
QString hive_file;
hive_h *h_hive;
QList<QByteArray> keywords;
bool search_nodes;
bool search_keys;
bool search_values;
QString root_path;
hive_node_h root_node;
void Match(QString path="", hive_node_h node=0);
};
#endif // THREADSEARCH_H

File Metadata

Mime Type
text/x-diff
Expires
Mon, Dec 23, 11:35 AM (12 h, 11 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1176805
Default Alt Text
(414 KB)

Event Timeline