/** * @RDE_HEADER@ * $Id$ * $HeadURL$ * $Author$ */ #pragma once #include #include #include namespace ProjectionWorkstation { namespace RfbProtocol { struct RfbPixelFormat { quint8 bitsPerPixel = 0; quint8 depth = 0; quint8 bigEndianFlag = 0; quint8 trueColourFlag = 0; quint8 redShift = 0; quint8 greenShift = 0; quint8 blueShift = 0; quint16 redMax = 0; quint16 greenMax = 0; quint16 blueMax = 0; }; struct RfbRectangle { QByteArray pixelData; quint16 xpos = 0; quint16 ypos = 0; quint16 width = 0; quint16 height = 0; qint32 encoding = 0; }; static constexpr int RAW_ENCODING = 0; static constexpr int HEXTILE_ENCODING = 5; static constexpr int LAST_RECT_PSEUDO_ENCODING = -224; namespace STC { enum Type { // Official Values v RFB_FRAMEBUFFER_UPDATE = 0, RFB_SET_COLORMAP = 1, RFB_RING_BELL = 2, RFB_SERVER_CUTTEXT = 3, // User Defined Values v RFB_VERSION = 256, RFB_SUP_SECURITY_TYPES = 257, RFB_VNC_AUTHENTICATION = 258, RFB_SECURITY_RESULT = 259, RFB_SERVER_INIT = 260 }; class ServerToClient { public: virtual ~ServerToClient() = default; friend QDataStream &operator>>(QDataStream &ds, ServerToClient &stc) { stc.fillDataFromStream(ds); return ds; } protected: explicit ServerToClient(Type type) : m_type(type) {} virtual void fillDataFromStream(QDataStream &ds) = 0; Type m_type; }; // ServerToClient // -------------------------------------------------- class RfbVersion final : public ServerToClient { quint8 m_minor = 0; quint8 m_major = 0; public: constexpr static Type TYPE = RFB_VERSION; RfbVersion() : ServerToClient(TYPE) {} quint8 majorVersion() const { return m_major; } quint8 minorVersion() const { return m_minor; } void fillDataFromStream(QDataStream &ds) override final { QVarLengthArray data(12); ds.readRawData(data.data(), 12); if (ds.status() == QDataStream::Ok) { m_major = data[6] - '0'; m_minor = data[10] - '0'; } } }; // RfbVersion // -------------------------------------------------- class RfbSupportedSecurityTypes final : public ServerToClient { QVector m_secTypes; public: constexpr static Type TYPE = RFB_SUP_SECURITY_TYPES; RfbSupportedSecurityTypes() : ServerToClient(TYPE) {} const QVector &types() const { return m_secTypes; } void fillDataFromStream(QDataStream &ds) override final { quint8 amountOfSupportedTypes; ds >> amountOfSupportedTypes; for (int count = 0; count < amountOfSupportedTypes; ++count) { quint8 type; ds >> type; m_secTypes.append(type); } } }; // RfbSupportedSecurityTypes // -------------------------------------------------- class RfbVncAuthentication final : public ServerToClient { quint64 m_challengeBlockA = 0; quint64 m_challengeBlockB = 0; public: constexpr static Type TYPE = RFB_VNC_AUTHENTICATION; RfbVncAuthentication() : ServerToClient(TYPE) {} quint64 challengeBlockA() const { return m_challengeBlockA; } quint64 challengeBlockB() const { return m_challengeBlockB; } void fillDataFromStream(QDataStream &ds) override final { ds >> m_challengeBlockA; ds >> m_challengeBlockB; } }; // RfbVncAuthentication // -------------------------------------------------- class RfbSecurityResult : public ServerToClient { QByteArray m_reason; quint32 m_resultCode = 0; public: constexpr static Type TYPE = RFB_SECURITY_RESULT; RfbSecurityResult() : ServerToClient(TYPE) {} quint32 resultCode() const { return m_resultCode; } const QByteArray &reason() const { return m_reason; } void fillDataFromStream(QDataStream &ds) override final { ds >> m_resultCode; if (ds.status() == QDataStream::Ok) { if (m_resultCode == 0) return; else { quint32 reasonLength; ds >> reasonLength; QByteArray reason(reasonLength, Qt::Uninitialized); ds.readRawData(reason.data(), reasonLength); m_reason = reason; } } } }; // RfbSecurityResult // -------------------------------------------------- class RfbServerInit final : public ServerToClient { QByteArray m_name; RfbPixelFormat m_pixelFormat; quint16 m_frameBufferWidth = 0; quint16 m_frameBufferHeight = 0; public: constexpr static Type TYPE = RFB_SERVER_INIT; RfbServerInit() : ServerToClient(TYPE) {} quint16 frameBufferWidth() const { return m_frameBufferWidth; } quint16 frameBufferHeight() const { return m_frameBufferHeight; } const RfbPixelFormat &pixelFormat() const { return m_pixelFormat; } const QByteArray &name() const { return m_name; } void fillDataFromStream(QDataStream &ds) override final { ds >> m_frameBufferWidth >> m_frameBufferHeight; ds >> m_pixelFormat.bitsPerPixel >> m_pixelFormat.depth >> m_pixelFormat.bigEndianFlag >> m_pixelFormat.trueColourFlag >> m_pixelFormat.redMax >> m_pixelFormat.greenMax >> m_pixelFormat.blueMax >> m_pixelFormat.redShift >> m_pixelFormat.greenShift >> m_pixelFormat.blueShift; ds.skipRawData(3); // padding quint32 nameLength; ds >> nameLength; QByteArray nameData(nameLength, Qt::Uninitialized); ds.readRawData(nameData.data(), nameLength); m_name = nameData; } }; // RfbServerInit // -------------------------------------------------- class RfbFramebufferUpdate final : public ServerToClient { QVector m_rectangles; public: RfbFramebufferUpdate() : ServerToClient(RFB_FRAMEBUFFER_UPDATE) {} const QVector &rectangles() const { return m_rectangles; } void fillDataFromStream(QDataStream &ds) override final; }; // RfbFramebufferUpdate // -------------------------------------------------- class RfbSetColormap final : public ServerToClient { public: RfbSetColormap() : ServerToClient(RFB_SET_COLORMAP) {} void fillDataFromStream(QDataStream &ds) override final { if (ds.status() == QDataStream::Ok) { quint8 padding; ds >> padding; quint16 firstColor, numberOfColors; ds >> firstColor >> numberOfColors; if (ds.status() != QDataStream::Ok) return; qint32 payloadLen = numberOfColors + 3 * sizeof(quint16); // rgb, 16 bit // we don't care ds.skipRawData(payloadLen); } else ds.setStatus(QDataStream::ReadPastEnd); } }; // RfbSetColormap // -------------------------------------------------- class RfbRingBell final : public ServerToClient { public: RfbRingBell() : ServerToClient(RFB_RING_BELL) {} void fillDataFromStream(QDataStream &) override final { // nothing to do here } }; // RfbRingBell // -------------------------------------------------- class RfbServerCutText final : public ServerToClient { QByteArray m_text; public: RfbServerCutText() : ServerToClient(RFB_SERVER_CUTTEXT) {} const QByteArray &text() const { return m_text; } void fillDataFromStream(QDataStream &ds) override final { if (ds.status() == QDataStream::Ok) { ds.skipRawData(3); //padding quint32 length; ds >> length; QByteArray data(length, Qt::Uninitialized); ds.readRawData(data.data(), length); m_text = data; } else ds.setStatus(QDataStream::ReadPastEnd); } }; // RfbServerCutText // -------------------------------------------------- } // STC namespace CTS { inline QByteArray RfbVersion(quint8 majorVersion, quint8 minorVersion) { QByteArray data; QString version = QStringLiteral("RFB 00%1.00%2\n"); data.append(version.arg(majorVersion).arg(minorVersion).toLatin1()); return data; } inline QByteArray RfbSecurityType(quint8 type) { QByteArray data; data.append(type); return data; } inline QByteArray RfbVncAuthentication(quint64 blockA, quint64 blockB) { QByteArray data; QDataStream stream(&data, QIODevice::WriteOnly); stream << blockA << blockB; return data; } inline QByteArray RfbClientInit(bool sharedConnection) { quint8 share = sharedConnection ? 1 : 0; QByteArray data; data.append(share); return data; } inline QByteArray RfbFrameBufferUpdateRequest(bool isIncremental, quint16 xPos, quint16 yPos, quint16 width, quint16 height) { quint8 type = 3; quint8 incremental = isIncremental ? 1 : 0; QByteArray data; QDataStream stream(&data, QIODevice::WriteOnly); stream << type << incremental << xPos << yPos << width << height; return data; } inline QByteArray RfbPointerEvent(quint8 buttonMask, quint16 xpos, quint16 ypos) { quint8 type = 5; QByteArray data; QDataStream stream(&data, QIODevice::WriteOnly); stream << type << buttonMask << xpos << ypos; return data; } inline QByteArray RfbKeyEvent(quint32 key, bool isPressed) { quint8 type = 4; quint8 pressed = isPressed ? 1 : 0; QByteArray data; QDataStream stream(&data, QIODevice::WriteOnly); stream << type << pressed << quint16(0) << key; return data; } inline QByteArray RfbSetEncodings(const QVector &encodings) { quint8 type = 2; QByteArray data; QDataStream stream(&data, QIODevice::WriteOnly); stream << type << quint8(0) << quint16(encodings.length()); for (qint32 encoding : encodings) stream << encoding; return data; } } // CTS } // RfbProtocol } // ProjectionWorkstation