394 lines
9.2 KiB
C++
Executable File
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
|