diff --git a/CMakeLists.txt b/CMakeLists.txt index 195a674..8405235 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,6 +22,7 @@ include_directories(include) # QRedis source files. set(QREDIS_SRC src/client.cpp + src/lexer.cpp src/request.cpp) # QRedis header files requiring MOC. @@ -29,6 +30,7 @@ qt5_wrap_cpp(QREDIS_MOC include/qredis/client.h include/qredis/request.h src/client_p.h + src/lexer.h src/request_p.h) # Create the client library. diff --git a/src/lexer.cpp b/src/lexer.cpp new file mode 100644 index 0000000..85a0232 --- /dev/null +++ b/src/lexer.cpp @@ -0,0 +1,89 @@ +#include "lexer.h" + +Lexer::Lexer(QIODevice * device, QObject * parent) + : QObject(parent), device(device), state(DoingNothing), crlf(0) +{ + connect(device, SIGNAL(readyRead()), SLOT(readData())); +} + +Lexer::~Lexer() +{ +} + +void Lexer::readData() +{ + buffer.append(device->readAll()); + + while(true) + { + if(state == DoingNothing && !readCharacter()) + break; + + switch(state) + { + case ReadingLength: + case ReadingUnsafeString: if(!readUnsafeString()) return; break; + case ReadingSafeString: if(!readSafeString()) return; break; + } + } +} + + +bool Lexer::readCharacter() +{ + if(!buffer.size()) + return false; + + char c = buffer.at(0); + buffer.remove(0, 1); + + switch(c) + { + case '+': + case '-': + case '*': + case ':': state = ReadingUnsafeString; break; + case '$': state = ReadingLength; break; + default: + emit warning(tr("Unexpected character '%1' encountered").arg(static_cast(c), 0, 16)); + return true; + } + + emit character(c); + return true; +} + +bool Lexer::readUnsafeString() +{ + crlf = buffer.indexOf("\r\n", crlf); + if(crlf == -1) + { + crlf = buffer.size(); + return false; + } + + QString s = buffer.mid(0, crlf); + buffer.remove(0, crlf + 2); + + if(state == ReadingLength) + { + length = s.toInt(); + state = ReadingSafeString; + } + else + emit unsafeString(s); + + return true; +} + +bool Lexer::readSafeString() +{ + if(buffer.size() < length + 2) + return false; + + QByteArray d = buffer.mid(0, length); + buffer.remove(0, length + 2); + + emit safeString(d); + return true; +} diff --git a/src/lexer.h b/src/lexer.h new file mode 100644 index 0000000..c4d3a0d --- /dev/null +++ b/src/lexer.h @@ -0,0 +1,49 @@ +#ifndef LEXER_H +#define LEXER_H + +#include +#include + +class Lexer : public QObject +{ + Q_OBJECT + + public: + + Lexer(QIODevice *, QObject * = 0); + virtual ~Lexer(); + + Q_SIGNALS: + + void character(char); + void unsafeString(const QString &); + void safeString(const QByteArray &); + + void warning(const QString &); + + private Q_SLOTS: + + void readData(); + + private: + + bool readCharacter(); + bool readLength(); + bool readUnsafeString(); + bool readSafeString(); + + QIODevice * device; + QByteArray buffer; + + enum { + DoingNothing, + ReadingLength, + ReadingUnsafeString, + ReadingSafeString + } state; + + int crlf; + int length; +}; + +#endif // LEXER_H