Files
qt5-legatus-legacy/Lts/Plugins/ProjectionWorkstation/Common/pws_rfb_protocol.h
T
2026-08-13 18:33:10 +02:00

394 lines
9.2 KiB
C++
Executable File

/**
* @RDE_HEADER@
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <QtGlobal>
#include <QVector>
#include <QDataStream>
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<char, 12> 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<quint8> m_secTypes;
public:
constexpr static Type TYPE = RFB_SUP_SECURITY_TYPES;
RfbSupportedSecurityTypes() : ServerToClient(TYPE) {}
const QVector<quint8> &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<RfbRectangle> m_rectangles;
public:
RfbFramebufferUpdate() : ServerToClient(RFB_FRAMEBUFFER_UPDATE) {}
const QVector<RfbRectangle> &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<qint32> &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