Question

I have developed my own hybrid stream cipher and for the GUI i am using Qt. Initially i wrote it on a single thread but it being a stream cipher was making GUI dysfunctional when operating on large files. So i shifted the encryption/decryption to a separate Qthread. Also to show the progress i included a standard QProgressbar onto the GUI. But when I run the File I/O the encryption/decryption works perfectly but the progress bar doesn't update properly. After the whole operation completes, the progress bar suddenly goes from 0% to 100% showing that it didn't get the chance to update during the operation. For the code, I emitted the completed percentage from the FileCrypto to the main GUI thread onto the QProgressbar's setValue(int) slot. Since it didn't work I also tried to sent a int poitner over to the FileCrypto thread whilst updating the pointer with the percentage and using a QTimer on the GUI thread to check the value of the int value locally and update the progress bar but still I got the exact same result.

Here is my code:

The FileCrypto class:

#include <QThread>
#include <QFile>
#include <PolyVernam.h>  //my algo header

class FileCrypto : public QThread
{
    Q_OBJECT

public:
    FileCrypto(QString, QString, int);
    bool stopIt;

protected:
    void run();

signals:
    void completed(int);
    void msg(QString);
    void pathMsg1(QString);
    void pathMsg2(QString);
    void keyMsg(QString);

private:
    QFile src, dest;
    QString tag;
    int mode;
    qint64 length;
    PolyVernam pv;
};

The Code:

#include <FileCrypto.h>

FileCrypto::FileCrypto(QString input, QString keyFile, int mode)
{
    stopIt = false;
    this->mode = mode;
    src.setFileName(input);

    if(mode == 1)
    {
        emit msg("Current Encryption/Decryption status: Encrypting file... :D:D");
        tag = "-encrypted";
        pv.setMode("encrypt", "");
    }
    else
    {
        emit msg("Current Encryption/Decryption status: Decrypting file... :D:D");
        tag = "-decrypted";
        pv.setMode("decrypt", keyFile);
    }

    dest.setFileName(QFileInfo(src).absolutePath() + "/" + QFileInfo(src).baseName()
                     + tag + "." + QFileInfo(src).completeSuffix());

    length = src.bytesAvailable();
}

void FileCrypto::run()
{
    qint64 done = 0;
    quint8 r, outChar;
    char ch;

    QDataStream in(&src);
    in.setVersion(QDataStream::Qt_4_7);
    src.open(QIODevice::ReadOnly);

    QDataStream out(&dest);
    out.setVersion(QDataStream::Qt_4_7);
    dest.open(QIODevice::WriteOnly);

    while(!in.atEnd() && !stopIt)
    {
        done++;

        in >> r;
        ch = char(r);

        if(mode == 1)
            outChar = pv.encrypt(QString(ch)).at(0).toAscii();
        else
            outChar = pv.decrypt(QString(ch)).at(0).toAscii();

        out << outChar;

        emit completed(int((done / length) * 100));
    }

    src.close();
    dest.close();

    if(stopIt)
        this->exit(0);

    if(mode == 1)
    {
        emit pathMsg1(QFileInfo(src).absoluteFilePath());
        emit pathMsg2(QFileInfo(dest).absoluteFilePath());
    }
    else
    {
        emit pathMsg1(QFileInfo(dest).absoluteFilePath());
        emit pathMsg2(QFileInfo(src).absoluteFilePath());
    }

    emit keyMsg(pv.keyFilePath);
    emit msg("Current Encryption/Decryption status: Idle... :'(");
}

This is how I am making the thread and connecting it on the main GUI thread:

FileCrypto *fc = new FileCrypto(ui->lineEdit_4->text(), "", 1);

connect(fc, SIGNAL(completed(int)), ui->progressBar, SLOT(setValue(int)));
connect(fc, SIGNAL(msg(QString)), ui->statusBar, SLOT(showMessage(QString)));
connect(fc, SIGNAL(pathMsg1(QString)), ui->lineEdit_4, SLOT(setText(QString)));
connect(fc, SIGNAL(pathMsg2(QString)), ui->lineEdit_5, SLOT(setText(QString)));
connect(fc, SIGNAL(keyMsg(QString)), ui->lineEdit_2, SLOT(setText(QString)));
connect(fc, SIGNAL(keyMsg(QString)), this, SLOT(done()));

If I don't update the progress bar i.e. don't emit the percentage, the process happens much faster. I also tried printing the percentage. It slows it down like hell but the values are fine. Also can you suggest a way to change it to buffered IO....

Any sort of help is much appreciated here.......

Was it helpful?

Solution

The problem does not lie in the fact that you are calling from a different thread. It is located in:

emit completed(int((done / length) * 100));

Since done and length are int types, and done <= length, done/length == 0. So change it to:

emit completed(100 * done / length);

(it can lead to arithmetic overflow).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top