Tutorial: Add a Checksum/Hashsum Algorithm to Okteta

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

Since KDE 4.3 (resp. Okteta 0.3) Okteta features a tool to calculate a checksum/hashsum from the bytes in the current selection. It comes with some built-in checksum algorithms (Modular sum (8/16/32/64 bit), Adler-32, CRC-32), but for hashsums relies on the QCA lib (Qt Cryptographic Architecture) (can be SHA-0/1/224/256/384/512, MD2/4/5, RIPEMD-160, Whirlpool, depending on the installed QCA plugins).

Ideally you would write a new hashsum algorithm as a plugin for the QCA library, so it is available to more programs than just Okteta. But if you want to add another checksum to Okteta, here is your tutorial:

Setup of the Development Environment

See for the instructions in the first tutorial about Binary Filters.

Adding a Checksum Algorithm

In this tutorial you write a checksum algorithm which will calculate the parity of all bytes using only a given bit position. It will look like this:
Bit-Parity checksum

To do so you follow the instructions found in okteta/kasten/controllers/view/libbytearraychecksum/README.developers:

Step 1: Creating source files

Commands to get this done:

cd ../../kdeutils/okteta/kasten/controllers/view/libbytearraychecksum/algorithm/
cp template/template_bytearraychecksumalgorithm.h bitparitybytearraychecksumalgorithm.h
cp template/template_bytearraychecksumalgorithm.cpp bitparitybytearraychecksumalgorithm.cpp

Step 2: Adapting the code from the template

“bitparitybytearraychecksumalgorithm.h” should end up like this:


// lib
#include "nobytearraychecksumparameterset.h"

class BitParityByteArrayChecksumAlgorithm : public AbstractByteArrayChecksumAlgorithm

    virtual ~BitParityByteArrayChecksumAlgorithm();

  public: // AbstractByteArrayChecksumAlgorithm API
    virtual bool calculateChecksum( QString* result, const Okteta::AbstractByteArrayModel* model, const Okteta::AddressRange& range ) const;
    virtual AbstractByteArrayChecksumParameterSet* parameterSet();

    NoByteArrayChecksumParameterSet mParameterSet;


And the file”bitparitybytearraychecksumalgorithm.cpp” should end like this:

#include "bitparitybytearraychecksumalgorithm.h"

// Okteta core
// KDE

static const int DefaultBitNumber = 1; // using the LSB as default

  : AbstractByteArrayChecksumAlgorithm(
     i18nc("name of the checksum algorithm", "Bit Parity") )

AbstractByteArrayChecksumParameterSet* BitParityByteArrayChecksumAlgorithm::parameterSet() { return &mParameterSet; }

bool BitParityByteArrayChecksumAlgorithm::calculateChecksum( QString* result,
                                                           const Okteta::AbstractByteArrayModel* model, const Okteta::AddressRange& range ) const
    bool success = true;

    const int bitNumber = DefaultBitNumber;
    const int mask = ( 1 << bitNumber-1 );

    int sum = 0;

    Okteta::Address nextBlockEnd = range.start() + CalculatedByteCountSignalLimit;
    for( Okteta::Address i = range.start(); ibyte(i) & mask );

        if( i >= nextBlockEnd )
            nextBlockEnd += CalculatedByteCountSignalLimit;
            emit calculatedBytes( range.localIndex(i)+1 );

    *result = QString::fromLatin1("%1").arg( sum );

    return success;

BitParityByteArrayChecksumAlgorithm::~BitParityByteArrayChecksumAlgorithm() {}

Step 3: Adding the filter to the library

The file “okteta/kasten/controllers/view/libbytearraychecksum/bytearraychecksumalgorithmfactory.cpp” should now as both have an include for the file “algorithm/bitparitybytearraychecksumalgorithm.h”

#include "algorithm/bitparitybytearraychecksumalgorithm.h"

as well create an algorithm BitParityByteArrayChecksumAlgorithm:

        << new ModSum8ByteArrayChecksumAlgorithm()
        << new ModSum16ByteArrayChecksumAlgorithm()
        << new ModSum32ByteArrayChecksumAlgorithm()
        << new ModSum64ByteArrayChecksumAlgorithm()
        << new Adler32ByteArrayChecksumAlgorithm()
        << new Crc32ByteArrayChecksumAlgorithm()
        // new:
        << new BitParityByteArrayChecksumAlgorithm();

In the file “okteta/kasten/controllers/CMakeLists.txt” the list “LIBCHECKSUM_SRCS” should now also include the file “bitparitybytearraychecksumalgorithm.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” in the first tutorial, linked above).

Load some file, select a range, open the Checksum tool and select “Bit Parity” as algorithm. It should look like this:
Bit-Parity checksum before being applied

Now press the “Calculate” button. It should look like this:
Bit-Parity checksum after being applied

Now let’s turn to…

Making the used Bit an editable Parameter

Step 1: Creating source files

Commands to get this done:

cd ../kdeutils/okteta/kasten/controllers/view/libbytearraychecksum/algorithm/
cp template/template_bytearraychecksumparameterset.h bitparitybytearraychecksumparameterset.h
cp template/template_bytearraychecksumparameterset.cpp bitparitybytearraychecksumparameterset.cpp
cp template/template_bytearraychecksumparametersetedit.h bitparitybytearraychecksumparametersetedit.h
cp template/template_bytearraychecksumparametersetedit.cpp bitparitybytearraychecksumparametersetedit.cpp

Step 2: Adapting the code from the template

“bitparitybytearraychecksumparameterset.h” should end up like this:


// lib
#include "abstractbytearraychecksumparameterset.h"

class BitParityByteArrayChecksumParameterSet : public AbstractByteArrayChecksumParameterSet

    virtual ~BitParityByteArrayChecksumParameterSet();

  public: // AbstractByteArrayChecksumParameterSet API
    virtual const char* id() const;

  public: // getters
    int bitNumber() const;

  public: // setters
    void setBitNumber( int bitNumber );

  protected: // parameters
    int mBitNumber;


“bitparitybytearraychecksumparameterset.cpp” should end up like this:

#include "bitparitybytearraychecksumparameterset.h"

static const int DefaultBitNumber = 1;

  : mBitNumber( DefaultBitNumber )

const char* BitParityByteArrayChecksumParameterSet::id() const { return "BitParity"; }

int BitParityByteArrayChecksumParameterSet::bitNumber() const { return mBitNumber; }

void BitParityByteArrayChecksumParameterSet::setBitNumber( int bitNumber ) { mBitNumber = bitNumber; }

BitParityByteArrayChecksumParameterSet::~BitParityByteArrayChecksumParameterSet() {}

“bitparitybytearraychecksumparametersetedit.h” should end up like this:


// lib
#include "abstractbytearraychecksumparametersetedit.h"

class KIntNumInput;

class BitParityByteArrayChecksumParameterSetEdit : public AbstractByteArrayChecksumParameterSetEdit

    static const char* const Id;

    BitParityByteArrayChecksumParameterSetEdit( QWidget* parent = 0 );

    virtual ~BitParityByteArrayChecksumParameterSetEdit();

  public: // AbstractByteArrayFilterParameterSetEdit API
    virtual void setParameterSet( const AbstractByteArrayChecksumParameterSet* parameterSet );
    virtual void getParameterSet( AbstractByteArrayChecksumParameterSet* parameterSet ) const;
    virtual bool isValid() const;

  protected Q_SLOTS:
    void onBitNumberChanged( int value );

    KIntNumInput* mBitNumberEdit;

    bool mIsValid :1;


“bitparitybytearraychecksumparametersetedit.cpp” should end up like this:

#include "bitparitybytearraychecksumparametersetedit.h"

// parameterset
#include "bitparitybytearraychecksumparameterset.h"
// KDE
// Qt

const char* const BitParityByteArrayChecksumParameterSetEdit::Id = "BitParity";

BitParityByteArrayChecksumParameterSetEdit::BitParityByteArrayChecksumParameterSetEdit( QWidget* parent )
  : AbstractByteArrayChecksumParameterSetEdit( parent )
    QFormLayout* baseLayout = new QFormLayout( this );
    // margin is provided by the container for this widget
    baseLayout->setMargin( 0 );

    mBitNumberEdit = new KIntNumInput( this );
    // For demonstration purpose we start at 0, not 1, to show handling of an invalid state
    // Otherwise the range should start at 1 and there is no need to connect to the valueChanged signal
    mBitNumberEdit->setRange( 0, 8 );
    // start with the invalid number
    mBitNumberEdit->setValue( 0 );
    connect( mBitNumberEdit, SIGNAL(valueChanged( int )), SLOT(onBitNumberChanged( int )) );

    const QString levelLabelText =
         i18nc( "@label:spinbox number of the bit to use",
                "Number of bit:" );
    const QString levelToolTip =
        i18nc( "@info:tooltip",
               "The number of the bit to use for the parity calculation. 1 means the LSB, 8 the MSB." );
    mBitNumberEdit->setToolTip( levelToolTip );
    const QString levelWhatsThis =
        i18nc( "@info:whatsthis",
               "Select the bit which should be used for the parity calculation. And more explanation." );
    mBitNumberEdit->setWhatsThis( levelWhatsThis );

    baseLayout->addRow( levelLabelText, mBitNumberEdit );

    // note start state
    mIsValid = isValid();

bool BitParityByteArrayChecksumParameterSetEdit::isValid() const { return mBitNumberEdit->value() != 0; }

void BitParityByteArrayChecksumParameterSetEdit::setParameterSet( const AbstractByteArrayChecksumParameterSet* parameterSet )
    const BitParityByteArrayChecksumParameterSet* template_ParameterSet =
        static_cast( parameterSet );

    mBitNumberEdit->setValue( template_ParameterSet->bitNumber() );

void BitParityByteArrayChecksumParameterSetEdit::getParameterSet( AbstractByteArrayChecksumParameterSet* parameterSet ) const
    BitParityByteArrayChecksumParameterSet* template_ParameterSet =
        static_cast( parameterSet );

    template_ParameterSet->setBitNumber( mBitNumberEdit->value() );

void BitParityByteArrayChecksumParameterSetEdit::onBitNumberChanged( int value )
    const bool isValid = ( value != 0 );

    if( mIsValid == isValid )

    mIsValid = isValid;
    emit validityChanged( isValid );

BitParityByteArrayChecksumParameterSetEdit::~BitParityByteArrayChecksumParameterSetEdit() {}

Also make the “BitParityByteArrayChecksumAlgorithm” use the “BitParityByteArrayChecksumParameterSet”, by adapting the include notion and the used parameter set class in the file “bitparitybytearraychecksumalgorithm.h” to now be:

#include "bitparitybytearraychecksumparameterset.h"
    BitParityByteArrayChecksumParameterSet mParameterSet;

In the file “bitparitybytearraychecksumalgorithm.cpp” change the variable “bitNumber” to be not the hardcoded 1, but to take its value from the parameter set:

    const int bitNumber = mParameterSet.bitNumber();

Step 3: Adding the parameterset to the library

The file “okteta/kasten/controllers/view/libbytearraychecksum/bytearraychecksumparameterseteditfactory.cpp” should now both have an include for the file “algorithm/bitparitybytearraychecksumparametersetedit.h”

#include "algorithm/bitparitybytearraychecksumparametersetedit.h"

as well as create a widget “BitParityByteArrayChecksumParameterSetEdit” for the “BitParityByteArrayChecksumParameterSetEdit::Id”:

    if( qstrcmp(id,ModSumByteArrayChecksumParameterSetEdit::Id) == 0 )
        result = new ModSumByteArrayChecksumParameterSetEdit();
// new:
    else if( qstrcmp(id,BitParityByteArrayChecksumParameterSetEdit::Id) == 0 )
        result = new BitParityByteArrayChecksumParameterSetEdit();

In the file “okteta/kasten/controllers/CMakeLists.txt” the list “LIBCHECKSUM_SRCS” should now also include the files “bitparitybytearraychecksumparameterset.cpp” and “bitparitybytearraychecksumparametersetedit.cpp”:

# new:

Step 4: Compile, install and run

Commands to get this done:

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

Running Okteta now should get you this:
Bit-parity checksum with parameter after being applied

It did? Great πŸ™‚

Now, please go and write your own special checksum algorithms! Then share your work and send them to me for inclusion in the next Okteta release πŸ™‚

Next tutorial possibly will be: Add an Encoder (used for export of bytes to other formats, for clipboard and file).


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.