Tutorial: Add a Binary Filter to Okteta

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

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:
Level Filter

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:


// lib
#include "nobytearrayfilterparameterset.h"
#include [abstractbytearrayfilter.h]

class LevelByteArrayFilter : public AbstractByteArrayFilter

    virtual ~LevelByteArrayFilter();

  public: // AbstractByteArrayFilter API
    virtual bool filter( Okteta::Byte* result, Okteta::AbstractByteArrayModel* model, const Okteta::AddressRange& range ) const;
    virtual AbstractByteArrayFilterParameterSet* parameterSet();

    NoByteArrayFilterParameterSet mParameterSet;


And the file “levelbytearrayfilter.cpp” should end like this:

#include "levelbytearrayfilter.h"

// Okteta core
#include [abstractbytearraymodel.h]
// KDE
#include [KLocale]

  : 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”

        << 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”:

# new:

Step 4: Compile, install and run

Commands to get this done:

cd ../../../../../../../build/
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:
Level Filter before being applied

Now press the “Filter” button. It should look like this:
Level Filter after being applied

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:


// lib
#include [abstractbytearrayfilterparameterset.h]

class LevelByteArrayFilterParameterSet : public AbstractByteArrayFilterParameterSet

    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;


“levelbytearrayfilterparameterset.cpp” should end up like this:

#include "levelbytearrayfilterparameterset.h"

static const unsigned int DefaultLevel = 127;

  : 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:


// lib
#include [abstractbytearrayfilterparametersetedit.h]

class KIntNumInput;

class LevelByteArrayFilterParameterSetEdit : public AbstractByteArrayFilterParameterSetEdit

    static const char* const Id;

    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 );

    KIntNumInput* mLevelEdit;

    bool mIsValid :1;


“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 )

    mIsValid = isValid;
    emit validityChanged( isValid );


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”:

# new:
# new:

Step 4: Compile, install and run

Commands to get this done:

cd ../../../../../../../build/
make install

Running Okteta now should get you this:
Level Filter with Parameter after being applied

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


2 thoughts on “Tutorial: Add a Binary Filter to Okteta

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.