Welcome to the first in hopefully a row of little tutorials showing how you can yourself add the features you need to Okteta, the KDE 4 hex editor.
Although, after writing this one, which took way too much time, I will see how I can make this more economic for me.
For now, you simply have to make use of this tutorial, so my time was well spent! 🙂
Setup of the development environment
Unless you already have a development environment, including the sources of kdeutils, e.g. after following the instructions from TechBase, the following little setup should work for you, too:
You need to have installed a proper compiler, cmake, a subversion client and the development packages of qt4 and kdelibs4. You might not need the kdelibs from trunk, version 4.3, perhaps even 4.2 should do it, I do not remember to have used any newer kdelibs API in Okteta so far. (Please report if you experience problems.)
Now get the sources of Okteta:
svn co svn://anonsvn.kde.org/home/kde/trunk/KDE/kdeutils -N
svn up kdeutils/okteta
Build the program in a separate directory (replace “yourinstallpath” with a proper path as useful for personal development, e.g. the output of kde4-config --prefix
):
mkdir build
cd build
cmake -DCMAKE_INSTALL_PREFIX=yourinstallpath ../kdeutils
cd okteta
make
The build will take a while as all those files you just saw when doing the checkout want to get compiled…
Do a make install
to see if the installation works, too.
Then testrun Okteta with yourinstallpath/okteta
.
(Or just okteta
if you are sure your shell does not outsmart you and instead starts okteta from a path it has cached from a previous start when this version of Okteta was not yet installed)
Hoping that all went smooth we can now turn to…
Adding a Binary Filter
In this tutorial you write a filter which will turn all bytes either to 0x00 or 0xFF, depending on whether their old value is below or above a given level. It will look like this:
To do so you follow the instructions found in okteta/kasten/controllers/view/libbytearrayfilter/README.developers:
Step 1: Creating source files
Commands to get this done:
cd ../../kdeutils/okteta/kasten/controllers/view/libbytearrayfilter/filter/
cp template/template_bytearrayfilter.h levelbytearrayfilter.h
cp template/template_bytearrayfilter.cpp levelbytearrayfilter.cpp
Step 2: Adapting the code from the template
“levelbytearrayfilter.h” should end up like this:
#ifndef LEVELBYTEARRAYFILTER_H #define LEVELBYTEARRAYFILTER_H // lib #include "nobytearrayfilterparameterset.h" #include [abstractbytearrayfilter.h] class LevelByteArrayFilter : public AbstractByteArrayFilter { public: LevelByteArrayFilter(); virtual ~LevelByteArrayFilter(); public: // AbstractByteArrayFilter API virtual bool filter( Okteta::Byte* result, Okteta::AbstractByteArrayModel* model, const Okteta::AddressRange& range ) const; virtual AbstractByteArrayFilterParameterSet* parameterSet(); protected: NoByteArrayFilterParameterSet mParameterSet; }; #endif
And the file “levelbytearrayfilter.cpp” should end like this:
#include "levelbytearrayfilter.h" // Okteta core #include [abstractbytearraymodel.h] // KDE #include [KLocale] LevelByteArrayFilter::LevelByteArrayFilter() : AbstractByteArrayFilter( i18nc("name of the filter; sets the byte to 0 or 255, depending on a level", "LEVEL data") ) {} AbstractByteArrayFilterParameterSet* LevelByteArrayFilter::parameterSet() { return &mParameterSet; } bool LevelByteArrayFilter::filter( Okteta::Byte* result, Okteta::AbstractByteArrayModel* model, const Okteta::AddressRange& range ) const { const unsigned int level = 127; int r = 0; Okteta::Address m = range.start(); int nextBlockEnd = FilteredByteCountSignalLimit; while( m byte( m++ ); const Okteta::Byte resultByte = ( byte > level ) ? 255 : 0; result[r++] = resultByte; if( r >= nextBlockEnd ) { nextBlockEnd += FilteredByteCountSignalLimit; emit filteredBytes( r ); } } return true; } LevelByteArrayFilter::~LevelByteArrayFilter() {}
Step 3: Adding the filter to the library
The file “okteta/kasten/controllers/view/libbytearrayfilter/bytearrayfilterfactory.cpp” should now as both have an include for the file “filter/levelbytearrayfilter.h”
#include "filter/levelbytearrayfilter.h"
as well create a filter “LevelByteArrayFilter”
result << new AndByteArrayFilter() << new OrByteArrayFilter() << new XOrByteArrayFilter() << new InvertByteArrayFilter() << new ReverseByteArrayFilter() << new RotateByteArrayFilter() << new ShiftByteArrayFilter() // new: << new LevelByteArrayFilter();
In the file “okteta/kasten/controllers/CMakeLists.txt” the list “LIBFILTER_SRCS” should now also include the file “levelbytearrayfilter.cpp”:
view/libbytearrayfilter/filter/reversebytearrayfilter.cpp view/libbytearrayfilter/filter/rotatebytearrayfilter.cpp view/libbytearrayfilter/filter/shiftbytearrayfilter.cpp # new: view/libbytearrayfilter/filter/levelbytearrayfilter.cpp
Step 4: Compile, install and run
Commands to get this done:
cd ../../../../../../../build/
make
make install
If the build and install went well, start Okteta with yourinstallpath/okteta
(cmp. remarks at end of section “Setup of the development environment” above).
Load some file, select a range, open the Binary Filter tool and select “LEVEL data” as filter. It should look like this:
Now press the “Filter” button. It should look like this:
Now let’s turn to…
Making the Level an editable Parameter
Step 1: Creating source files
Commands to get this done:
cd ../kdeutils/okteta/kasten/controllers/view/libbytearrayfilter/filter/
cp template/template_bytearrayfilterparameterset.h levelbytearrayfilterparameterset.h
cp template/template_bytearrayfilterparameterset.cpp levelbytearrayfilterparameterset.cpp
cp template/template_bytearrayfilterparametersetedit.h levelbytearrayfilterparametersetedit.h
cp template/template_bytearrayfilterparametersetedit.cpp levelbytearrayfilterparametersetedit.cpp
Step 2: Adapting the code from the template
“levelbytearrayfilterparameterset.h” should end up like this:
#ifndef LEVELBYTEARRAYFILTERWITHPARAMETERSET_H #define LEVELBYTEARRAYFILTERWITHPARAMETERSET_H // lib #include [abstractbytearrayfilterparameterset.h] class LevelByteArrayFilterParameterSet : public AbstractByteArrayFilterParameterSet { public: LevelByteArrayFilterParameterSet(); virtual ~LevelByteArrayFilterParameterSet(); public: // AbstractByteArrayFilterParameterSet API virtual const char* id() const; public: // getters unsigned char level() const; public: // setters void setLevel( unsigned int level ); protected: // parameters unsigned char mLevel; }; #endif
“levelbytearrayfilterparameterset.cpp” should end up like this:
#include "levelbytearrayfilterparameterset.h" static const unsigned int DefaultLevel = 127; LevelByteArrayFilterParameterSet::LevelByteArrayFilterParameterSet() : mLevel( DefaultLevel ) {} const char* LevelByteArrayFilterParameterSet::id() const { return "Level"; } unsigned char LevelByteArrayFilterParameterSet::level() const { return mLevel; } void LevelByteArrayFilterParameterSet::setLevel( unsigned int level ) { mLevel = level; } LevelByteArrayFilterParameterSet::~LevelByteArrayFilterParameterSet() {}
“levelbytearrayfilterparametersetedit.h” should end up like this:
#ifndef LEVELBYTEARRAYFILTERPARAMETERSETEDIT_H #define LEVELBYTEARRAYFILTERPARAMETERSETEDIT_H // lib #include [abstractbytearrayfilterparametersetedit.h] class KIntNumInput; class LevelByteArrayFilterParameterSetEdit : public AbstractByteArrayFilterParameterSetEdit { Q_OBJECT public: static const char* const Id; public: LevelByteArrayFilterParameterSetEdit( QWidget* parent = 0 ); virtual ~LevelByteArrayFilterParameterSetEdit(); public: // AbstractByteArrayFilterParameterSetEdit API virtual void setValues( const AbstractByteArrayFilterParameterSet* parameterSet ); virtual void getParameterSet( AbstractByteArrayFilterParameterSet* parameterSet ) const; virtual bool isValid() const; protected Q_SLOTS: void onLevelChanged( int value ); protected: KIntNumInput* mLevelEdit; bool mIsValid :1; }; #endif
“levelbytearrayfilterparametersetedit.cpp” should end up like this:
#include "levelbytearrayfilterparametersetedit.h" // parameterset #include "levelbytearrayfilterparameterset.h" // KDE #include [KLocale] #include [KIntNumInput] // Qt #include [QtGui/QFormLayout] const char* const LevelByteArrayFilterParameterSetEdit::Id = "Level"; LevelByteArrayFilterParameterSetEdit::LevelByteArrayFilterParameterSetEdit( QWidget* parent ) : AbstractByteArrayFilterParameterSetEdit( parent ) { QFormLayout* baseLayout = new QFormLayout( this ); // margin is provided by the container for this widget baseLayout->setMargin( 0 ); mLevelEdit = new KIntNumInput( this ); // For demonstration purpose we start at -1, not 0, to show handling of an invalid state // Otherwise the range should start at 0 and there is no need to connect to the valueChanged signal mLevelEdit->setRange( -1, 256 ); // start with the invalid number mLevelEdit->setValue( -1 ); connect( mLevelEdit, SIGNAL(valueChanged( int )), SLOT(onLevelChanged( int )) ); const QString levelLabelText = i18nc( "@label:spinbox decimal value up to which bytes are set to 0", "Level:" ); baseLayout->addRow( levelLabelText, mLevelEdit ); // note start state mIsValid = isValid(); } bool LevelByteArrayFilterParameterSetEdit::isValid() const { return mLevelEdit->value() != -1; } void LevelByteArrayFilterParameterSetEdit::setValues( const AbstractByteArrayFilterParameterSet* parameterSet ) { const LevelByteArrayFilterParameterSet* template_ParameterSet = static_cast( parameterSet ); mLevelEdit->setValue( template_ParameterSet->level() ); } void LevelByteArrayFilterParameterSetEdit::getParameterSet( AbstractByteArrayFilterParameterSet* parameterSet ) const { LevelByteArrayFilterParameterSet* template_ParameterSet = static_cast( parameterSet ); template_ParameterSet->setLevel( mLevelEdit->value() ); } void LevelByteArrayFilterParameterSetEdit::onLevelChanged( int value ) { const bool isValid = ( value != -1 ); if( mIsValid == isValid ) return; mIsValid = isValid; emit validityChanged( isValid ); } LevelByteArrayFilterParameterSetEdit::~LevelByteArrayFilterParameterSetEdit() {}
Also make the “LevelByteArrayFilter” use the “LevelByteArrayFilterParameterSet”, by adapting the include notion and the used parameter set class in the file “levelbytearrayfilter.h” to now be:
#include "levelbytearrayfilterparameterset.h"
LevelByteArrayFilterParameterSet mParameterSet;
In the file “levelbytearrayfilter.cpp” change the variable “level” to be not the hardcoded 127, but to take its value from the parameter set:
const unsigned int level = mParameterSet.level();
Step 3: Adding the parameterset to the library
The file “okteta/kasten/controllers/view/libbytearrayfilter/bytearrayfilterparameterseteditfactory.cpp” should now as both have an include for the file “filter/levelbytearrayfilterparametersetedit.h”
#include "filter/levelbytearrayfilterparametersetedit.h"
as well create a widget “LevelByteArrayFilterParameterSetEdit” for the “LevelByteArrayFilterParameterSetEdit::Id”:
[...] else if( qstrcmp(id,RotateByteArrayFilterParameterSetEdit::Id) == 0 ) result = new RotateByteArrayFilterParameterSetEdit(); // new: else if( qstrcmp(id,LevelByteArrayFilterParameterSetEdit::Id) == 0 ) result = new LevelByteArrayFilterParameterSetEdit(); [...]
In the file “okteta/kasten/controllers/CMakeLists.txt” the list “LIBFILTER_SRCS” should now also include the files “levelbytearrayfilterparameterset.cpp” and “levelbytearrayfilterparametersetedit.cpp”:
[...] view/libbytearrayfilter/filter/rotatebytearrayfilterparameterset.cpp # new: view/libbytearrayfilter/filter/levelbytearrayfilterparameterset.cpp [...] view/libbytearrayfilter/filter/rotatebytearrayfilterparametersetedit.cpp # new: view/libbytearrayfilter/filter/levelbytearrayfilterparametersetedit.cpp [...]
Step 4: Compile, install and run
Commands to get this done:
cd ../../../../../../../build/
make
make install
Running Okteta now should get you this:
It did? Hurra 🙂
Now, please go and write your own special filters! Then share your work and send them to me for inclusion in the next Okteta release 🙂
Next tutorial will be: Add a Checksum/Hashsum algorithm
[…] tutorial will appear on sunday (September 27th) and teach you how to write a binary filter (Update: online now). So stay tuned if you are in need of a hex editor like Okteta and interested to give the […]
[…] Tutorial: Add a Checksum/Hashsum Algorithm to Okteta Filed under: KDE, Okteta, Tutorial — by frinring @ 7:29 pm Here comes the second in a row of little tutorials showing how you can yourself add the features you need to Okteta, the KDE 4 hex editor (the first one was about Adding a Binary Filter). […]