From 7531eabde88bdd7f080607a1c9da0597659d5a51 Mon Sep 17 00:00:00 2001 From: APTX Date: Fri, 21 Aug 2009 13:12:51 +0200 Subject: [PATCH] - New (broken) hashing infrastructure --- circularbuffer.h | 72 +++++++++++++++++++++++++++++++ hash.cpp | 85 +++++++++++++++++++++++++++++++++++++ hash.h | 49 +++++++++++++++++++++ hashconsumer.cpp | 63 +++++++++++++++++++++++++++ hashconsumer.h | 50 ++++++++++++++++++++++ hashproducer.cpp | 59 +++++++++++++++++++++++++ hashproducer.h | 48 +++++++++++++++++++++ include/AniDBUdpClient/Hash | 1 + 8 files changed, 427 insertions(+) create mode 100644 circularbuffer.h create mode 100644 hash.cpp create mode 100644 hash.h create mode 100644 hashconsumer.cpp create mode 100644 hashconsumer.h create mode 100644 hashproducer.cpp create mode 100644 hashproducer.h create mode 100644 include/AniDBUdpClient/Hash diff --git a/circularbuffer.h b/circularbuffer.h new file mode 100644 index 0000000..dd9a9da --- /dev/null +++ b/circularbuffer.h @@ -0,0 +1,72 @@ +#ifndef CIRCULARBUFFER_H +#define CIRCULARBUFFER_H + +#include + +namespace AniDBUdpClient { +namespace HashPrivate { + +template class CircularBuffer +{ +public: + CircularBuffer() + { + // Set N to SIZE + free.release(SIZE); + r = w = 0; + m_end = false; + } + + void put(T data, bool last = false) + { + if (m_end) return; + + free.acquire(); + buffer[w] = data; + m_end = last; + used.release(); + w++; + w %= SIZE; + } + + T get() + { + used.acquire(); + T data = buffer[r]; + free.release(); + r++; + r %= SIZE; + return data; + } + + bool end() const + { + return m_end && r == w; + } + + bool reset() + { + if (!end()) + return false; + + m_end = false; + r = w = 0; + return true; + } + +private: + T buffer[SIZE]; + QSemaphore free; + QSemaphore used; + + int r; + int w; + bool m_end; +}; + +typedef CircularBuffer Buffer; + +} // namespace HashPrivate +} // namesapce AniDBUdpClient + +#endif // CIRCULARBUFFER_H diff --git a/hash.cpp b/hash.cpp new file mode 100644 index 0000000..bd5dc0b --- /dev/null +++ b/hash.cpp @@ -0,0 +1,85 @@ +#include "hash.h" + +#include + +namespace AniDBUdpClient { + +Hash::Hash(QObject *parent) : QObject(parent) +{ + producer = 0; + consumer = 0; + buffer = 0; + hashing = false; + setUp(); +} + +Hash::~Hash() +{ + tearDown(); +} + +void Hash::hashFile(const QFileInfo &file) +{ +qDebug() << "Hash::hashFile"; + fileQueue.enqueue(file); + + if (hashing) + return; + + emit startHashing(fileQueue.first().absoluteFilePath()); +} + +void Hash::endHashing(const QByteArray &hash) +{ +qDebug() << "Hash::endHashing"; + QFileInfo f = fileQueue.dequeue(); + + if (!fileQueue.isEmpty()) + { + emit startHashing(fileQueue.first().absoluteFilePath()); + } + else + { + hashing = false; + } + emit fileHashed(f, hash); +qDebug() << "FILE" << f.fileName() << "HASH" << hash; +} + + +void Hash::setUp() +{ + if (producer || consumer || buffer) + return; + + buffer = new HashPrivate::Buffer; + producer = new HashPrivate::HashProducer(buffer, this); + consumer = new HashPrivate::HashConsumer(buffer, this); + connect(this, SIGNAL(startHashing(QString)), consumer, SLOT(hashFile(QString)), Qt::QueuedConnection); + connect(this, SIGNAL(startHashing(QString)), producer, SLOT(readFile(QString)), Qt::QueuedConnection); + connect(consumer, SIGNAL(finishedHashing(QByteArray)), this, SLOT(endHashing(QByteArray)), Qt::QueuedConnection); + + producer->start(); + consumer->start(); +} + +void Hash::tearDown() +{ + if (!producer || !consumer || !buffer) + return; + + producer->stop(); + consumer->stop(); + producer->wait(); + consumer->wait(); + + delete producer; + delete consumer; + delete buffer; + + producer = 0; + consumer = 0; + buffer = 0; +} + +} // namesapce AniDBUdpClient diff --git a/hash.h b/hash.h new file mode 100644 index 0000000..38eaf32 --- /dev/null +++ b/hash.h @@ -0,0 +1,49 @@ +#ifndef HASH_H +#define HASH_H + +#include "anidbudpclient_global.h" +#include +#include +#include +#include + +#include "hashproducer.h" +#include "hashconsumer.h" + +namespace AniDBUdpClient { + +class ANIDBUDPCLIENTSHARED_EXPORT Hash : public QObject +{ + + Q_OBJECT + +public: + Hash(QObject *parent = 0); + ~Hash(); + + void hashFile(const QFileInfo &file); + +signals: + void startHashing(const QString &file); + void fileHashed(const QFileInfo &file, const QByteArray &hash); + +private slots: + void endHashing(const QByteArray &hash); + +private: + void setUp(); + void tearDown(); + + HashPrivate::Buffer *buffer; + HashPrivate::HashProducer *producer; + HashPrivate::HashConsumer *consumer; + + QQueue fileQueue; + QMap hashedFiles; + + bool hashing; +}; + +} // namesapce AniDBUdpClient + +#endif // HASH_H diff --git a/hashconsumer.cpp b/hashconsumer.cpp new file mode 100644 index 0000000..f5dc40f --- /dev/null +++ b/hashconsumer.cpp @@ -0,0 +1,63 @@ +#include "hashconsumer.h" + +#include + +namespace AniDBUdpClient { +namespace HashPrivate { + +HashConsumer::HashConsumer(Buffer *buffer, QObject *parent) : QThread(parent) +{ + this->buffer = buffer; + hash = new QCryptographicHash(QCryptographicHash::Md4); + connect(this, SIGNAL(startHashing()), this, SLOT(doHash())); +} + +HashConsumer::~HashConsumer() +{ + delete hash; +} + +void HashConsumer::hashFile(const QString &file) +{ +qDebug() << "hashFile()"; + fileSize = QFileInfo(file).size(); + + emit startHashing(); +} + +void HashConsumer::stop() +{ + m_stop = true; + quit(); +} + +void HashConsumer::run() +{ + exec(); +} + +void HashConsumer::doHash() +{ + while (!buffer->end()) + { +qDebug() << "doHash()->while(" << buffer->end() << ")"; + hashSome(); + } + buffer->reset(); + hash->reset(); +} + +void HashConsumer::hashSome() +{ + QByteArray data = buffer->get(); + + hash->addData(QCryptographicHash::hash(data, QCryptographicHash::Md4)); + + if (buffer->end()) + emit finishedHashing(hash->result()); + +qDebug() << "hashSome()"; +} + +} // namespace HashPrivate +} // namesapce AniDBUdpClient diff --git a/hashconsumer.h b/hashconsumer.h new file mode 100644 index 0000000..69c6c0f --- /dev/null +++ b/hashconsumer.h @@ -0,0 +1,50 @@ +#ifndef HASHCONSUMER_H +#define HASHCONSUMER_H + +#include "anidbudpclient_global.h" +#include +#include +#include +#include + +#include "circularbuffer.h" + +namespace AniDBUdpClient { +namespace HashPrivate { + +class HashConsumer : public QThread +{ + Q_OBJECT +public: + HashConsumer(Buffer *buffer, QObject *parent = 0); + ~HashConsumer(); + +public slots: + void hashFile(const QString &file); + + void stop(); + +protected: + void run(); + +signals: + void startHashing(); + void finishedHashing(QByteArray hash); + +private slots: + void doHash(); + +private: + void hashSome(); + + Buffer *buffer; + QCryptographicHash *hash; + qint64 fileSize; + + bool m_stop; +}; + +} // namespace HashPrivate +} // namesapce AniDBUdpClient + +#endif // HASHCONSUMER_H diff --git a/hashproducer.cpp b/hashproducer.cpp new file mode 100644 index 0000000..d4c4358 --- /dev/null +++ b/hashproducer.cpp @@ -0,0 +1,59 @@ +#include "hashproducer.h" + +#include + +namespace AniDBUdpClient { +namespace HashPrivate { + +HashProducer::HashProducer(Buffer *buffer, QObject *parent) : QThread(parent) +{ + this->buffer = buffer; + connect(this, SIGNAL(startReading()), this, SLOT(doRead())); +} + +void HashProducer::readFile(const QString &file) +{ +qDebug() << "readFile"; + this->file.setFileName(file); + + fileSize = file.size(); + + if (!this->file.open(QIODevice::ReadOnly)) + { +qDebug() << "Failed toopen file" << this->file.fileName(); + return; + } + + emit startReading(); +} + +void HashProducer::stop() +{ + m_stop = true; + quit(); +} + +void HashProducer::run() +{ + exec(); +} + +void HashProducer::doRead() +{ + while (!this->file.atEnd()) + { +qDebug() << "doRead->while(" << (!this->file.atEnd()) << ")"; + readSome(); + } + this->file.close(); +} + +void HashProducer::readSome() +{ + QByteArray data = file.read(ED2K_PART_SIZE); +qDebug() << "readSome"; + buffer->put(data, file.atEnd()); +} + +} // namespace HashPrivate +} // namesapce AniDBUdpClient diff --git a/hashproducer.h b/hashproducer.h new file mode 100644 index 0000000..0bde203 --- /dev/null +++ b/hashproducer.h @@ -0,0 +1,48 @@ +#ifndef HASHPRODUCER_H +#define HASHPRODUCER_H + +#include "anidbudpclient_global.h" +#include +#include +#include + +#include "circularbuffer.h" + +namespace AniDBUdpClient { +namespace HashPrivate { + +class HashProducer : public QThread +{ + Q_OBJECT + +public: + HashProducer(Buffer *buffer, QObject *parent = 0); + +public slots: + void readFile(const QString &file); + + void stop(); +protected: + void run(); + +signals: + void startReading(); + void finishedReading(); + +private slots: + void doRead(); + +private: + void readSome(); + + Buffer *buffer; + QFile file; + qint64 fileSize; + + bool m_stop; +}; + +} // namespace HashPrivate +} // namesapce AniDBUdpClient + +#endif // HASHPRODUCER_H diff --git a/include/AniDBUdpClient/Hash b/include/AniDBUdpClient/Hash new file mode 100644 index 0000000..4ae187b --- /dev/null +++ b/include/AniDBUdpClient/Hash @@ -0,0 +1 @@ +#include "../../hash.h" -- 2.52.0