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:

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:
#ifndef BITPARITYBYTEARRAYCHECKSUMALGORITHM_H
#define BITPARITYBYTEARRAYCHECKSUMALGORITHM_H
// lib
#include "nobytearraychecksumparameterset.h"
#include
class BitParityByteArrayChecksumAlgorithm : public AbstractByteArrayChecksumAlgorithm
{
public:
BitParityByteArrayChecksumAlgorithm();
virtual ~BitParityByteArrayChecksumAlgorithm();
public: // AbstractByteArrayChecksumAlgorithm API
virtual bool calculateChecksum( QString* result, const Okteta::AbstractByteArrayModel* model, const Okteta::AddressRange& range ) const;
virtual AbstractByteArrayChecksumParameterSet* parameterSet();
protected:
NoByteArrayChecksumParameterSet mParameterSet;
};
#endif
And the file”bitparitybytearraychecksumalgorithm.cpp” should end like this:
#include "bitparitybytearraychecksumalgorithm.h"
// Okteta core
#include
// KDE
#include
static const int DefaultBitNumber = 1; // using the LSB as default
BitParityByteArrayChecksumAlgorithm::BitParityByteArrayChecksumAlgorithm()
: 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:
result
<< 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”:
view/libbytearraychecksum/algorithm/modsum16bytearraychecksumalgorithm.cpp view/libbytearraychecksum/algorithm/modsum32bytearraychecksumalgorithm.cpp view/libbytearraychecksum/algorithm/modsum64bytearraychecksumalgorithm.cpp # new: view/libbytearraychecksum/algorithm/bitparitybytearraychecksumalgorithm.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” 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:

Now press the “Calculate” button. It should look like this:

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:
#ifndef BITPARITYBYTEARRAYCHECKSUMPARAMETERSET_H
#define BITPARITYBYTEARRAYCHECKSUMPARAMETERSET_H
// lib
#include "abstractbytearraychecksumparameterset.h"
class BitParityByteArrayChecksumParameterSet : public AbstractByteArrayChecksumParameterSet
{
public:
BitParityByteArrayChecksumParameterSet();
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;
};
#endif
“bitparitybytearraychecksumparameterset.cpp” should end up like this:
#include "bitparitybytearraychecksumparameterset.h"
static const int DefaultBitNumber = 1;
BitParityByteArrayChecksumParameterSet::BitParityByteArrayChecksumParameterSet()
: 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:
#ifndef BITPARITYBYTEARRAYCHECKSUMPARAMETERSETEDIT_H
#define BITPARITYBYTEARRAYCHECKSUMPARAMETERSETEDIT_H
// lib
#include "abstractbytearraychecksumparametersetedit.h"
class KIntNumInput;
class BitParityByteArrayChecksumParameterSetEdit : public AbstractByteArrayChecksumParameterSetEdit
{
Q_OBJECT
public:
static const char* const Id;
public:
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 );
protected:
KIntNumInput* mBitNumberEdit;
bool mIsValid :1;
};
#endif
“bitparitybytearraychecksumparametersetedit.cpp” should end up like this:
#include "bitparitybytearraychecksumparametersetedit.h"
// parameterset
#include "bitparitybytearraychecksumparameterset.h"
// KDE
#include
#include
// Qt
#include
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 )
return;
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”:
[...] view/libbytearraychecksum/algorithm/modsumbytearraychecksumparameterset.cpp view/libbytearraychecksum/algorithm/modsumbytearraychecksumparametersetedit.cpp # new: view/libbytearraychecksum/algorithm/bitparitybytearraychecksumparameterset.cpp view/libbytearraychecksum/algorithm/bitparitybytearraychecksumparametersetedit.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? 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).
