Browse Source

Merge branch 'types2' of https://github.com/CendioOssman/tigervnc

pull/1641/head
Pierre Ossman 10 months ago
parent
commit
9ca100d463
59 changed files with 273 additions and 120 deletions
  1. 1
    1
      common/rdr/FdInStream.cxx
  2. 1
    1
      common/rdr/FdInStream.h
  3. 2
    2
      common/rdr/FdOutStream.cxx
  4. 1
    1
      common/rdr/FdOutStream.h
  5. 1
    1
      common/rdr/InStream.h
  6. 2
    2
      common/rdr/MemInStream.h
  7. 1
    1
      common/rdr/MemOutStream.h
  8. 1
    1
      common/rdr/OutStream.h
  9. 1
    1
      common/rdr/TLSInStream.cxx
  10. 1
    1
      common/rdr/TLSOutStream.cxx
  11. 12
    8
      common/rfb/CConnection.cxx
  12. 1
    1
      common/rfb/CConnection.h
  13. 1
    1
      common/rfb/CMsgHandler.cxx
  14. 1
    1
      common/rfb/CMsgHandler.h
  15. 23
    8
      common/rfb/CMsgReader.cxx
  16. 6
    6
      common/rfb/CMsgWriter.cxx
  17. 1
    1
      common/rfb/CMsgWriter.h
  18. 2
    2
      common/rfb/CSecurityDH.cxx
  19. 2
    2
      common/rfb/CSecurityPlain.cxx
  20. 2
    2
      common/rfb/CSecurityRSAAES.cxx
  21. 2
    2
      common/rfb/CopyRectDecoder.cxx
  22. 2
    2
      common/rfb/CopyRectDecoder.h
  23. 3
    3
      common/rfb/Decoder.cxx
  24. 6
    4
      common/rfb/Decoder.h
  25. 1
    1
      common/rfb/H264Decoder.cxx
  26. 1
    1
      common/rfb/H264Decoder.h
  27. 2
    2
      common/rfb/HextileDecoder.cxx
  28. 1
    1
      common/rfb/HextileDecoder.h
  29. 4
    2
      common/rfb/HextileEncoder.cxx
  30. 1
    1
      common/rfb/JpegCompressor.cxx
  31. 1
    1
      common/rfb/JpegCompressor.h
  32. 1
    1
      common/rfb/RREDecoder.cxx
  33. 1
    1
      common/rfb/RREDecoder.h
  34. 1
    1
      common/rfb/RawDecoder.cxx
  35. 1
    1
      common/rfb/RawDecoder.h
  36. 17
    11
      common/rfb/SConnection.cxx
  37. 1
    1
      common/rfb/SConnection.h
  38. 1
    1
      common/rfb/SMsgHandler.h
  39. 6
    3
      common/rfb/SMsgReader.cxx
  40. 13
    10
      common/rfb/SMsgWriter.cxx
  41. 3
    3
      common/rfb/SMsgWriter.h
  42. 2
    2
      common/rfb/SSecurityPlain.cxx
  43. 2
    2
      common/rfb/SSecurityRSAAES.cxx
  44. 3
    3
      common/rfb/TightDecoder.cxx
  45. 3
    3
      common/rfb/TightDecoder.h
  46. 4
    4
      common/rfb/VNCSConnectionST.cxx
  47. 2
    2
      common/rfb/VNCSConnectionST.h
  48. 2
    2
      common/rfb/VNCServerST.cxx
  49. 2
    2
      common/rfb/ZRLEDecoder.cxx
  50. 1
    1
      common/rfb/ZRLEDecoder.h
  51. 40
    0
      common/rfb/util.cxx
  52. 3
    0
      common/rfb/util.h
  53. 54
    0
      tests/unit/unicode.cxx
  54. 9
    0
      unix/xserver/hw/vnc/RFBGlue.cc
  55. 2
    0
      unix/xserver/hw/vnc/RFBGlue.h
  56. 5
    0
      unix/xserver/hw/vnc/vncSelection.c
  57. 1
    1
      vncviewer/CConn.cxx
  58. 1
    1
      vncviewer/CConn.h
  59. 5
    0
      vncviewer/Viewport.cxx

+ 1
- 1
common/rdr/FdInStream.cxx View File

// returning EINTR. // returning EINTR.
// //


size_t FdInStream::readFd(void* buf, size_t len)
size_t FdInStream::readFd(uint8_t* buf, size_t len)
{ {
int n; int n;
do { do {

+ 1
- 1
common/rdr/FdInStream.h View File

private: private:
virtual bool fillBuffer(); virtual bool fillBuffer();


size_t readFd(void* buf, size_t len);
size_t readFd(uint8_t* buf, size_t len);


int fd; int fd;
bool closeWhenDone; bool closeWhenDone;

+ 2
- 2
common/rdr/FdOutStream.cxx View File



bool FdOutStream::flushBuffer() bool FdOutStream::flushBuffer()
{ {
size_t n = writeFd((const void*) sentUpTo, ptr - sentUpTo);
size_t n = writeFd(sentUpTo, ptr - sentUpTo);
if (n == 0) if (n == 0)
return false; return false;


// returning EINTR. // returning EINTR.
// //


size_t FdOutStream::writeFd(const void* data, size_t length)
size_t FdOutStream::writeFd(const uint8_t* data, size_t length)
{ {
int n; int n;



+ 1
- 1
common/rdr/FdOutStream.h View File



private: private:
virtual bool flushBuffer(); virtual bool flushBuffer();
size_t writeFd(const void* data, size_t length);
size_t writeFd(const uint8_t* data, size_t length);
int fd; int fd;
struct timeval lastWrite; struct timeval lastWrite;
}; };

+ 1
- 1
common/rdr/InStream.h View File



// readBytes() reads an exact number of bytes. // readBytes() reads an exact number of bytes.


void readBytes(void* data, size_t length) {
void readBytes(uint8_t* data, size_t length) {
check(length); check(length);
memcpy(data, ptr, length); memcpy(data, ptr, length);
ptr += length; ptr += length;

+ 2
- 2
common/rdr/MemInStream.h View File



public: public:


MemInStream(const void* data, size_t len, bool deleteWhenDone_=false)
: start((const uint8_t*)data), deleteWhenDone(deleteWhenDone_)
MemInStream(const uint8_t* data, size_t len, bool deleteWhenDone_=false)
: start(data), deleteWhenDone(deleteWhenDone_)
{ {
ptr = start; ptr = start;
end = start + len; end = start + len;

+ 1
- 1
common/rdr/MemOutStream.h View File



// data() returns a pointer to the buffer. // data() returns a pointer to the buffer.


const void* data() { return (const void*)start; }
const uint8_t* data() { return start; }


protected: protected:



+ 1
- 1
common/rdr/OutStream.h View File



// writeBytes() writes an exact number of bytes. // writeBytes() writes an exact number of bytes.


void writeBytes(const void* data, size_t length) {
void writeBytes(const uint8_t* data, size_t length) {
while (length > 0) { while (length > 0) {
check(1); check(1);
size_t n = length; size_t n = length;

+ 1
- 1
common/rdr/TLSInStream.cxx View File

if (in->avail() < size) if (in->avail() < size)
size = in->avail(); size = in->avail();
in->readBytes(data, size);
in->readBytes((uint8_t*)data, size);
} catch (EndOfStream&) { } catch (EndOfStream&) {
return 0; return 0;
} catch (SystemException &e) { } catch (SystemException &e) {

+ 1
- 1
common/rdr/TLSOutStream.cxx View File

self->saved_exception = NULL; self->saved_exception = NULL;


try { try {
out->writeBytes(data, size);
out->writeBytes((const uint8_t*)data, size);
out->flush(); out->flush();
} catch (SystemException &e) { } catch (SystemException &e) {
vlog.error("Failure sending TLS data: %s", e.str()); vlog.error("Failure sending TLS data: %s", e.str());

+ 12
- 8
common/rfb/CConnection.cxx View File

if (!is->hasData(12)) if (!is->hasData(12))
return false; return false;


is->readBytes(verStr, 12);
is->readBytes((uint8_t*)verStr, 12);
verStr[12] = '\0'; verStr[12] = '\0';


if (sscanf(verStr, "RFB %03d.%03d\n", if (sscanf(verStr, "RFB %03d.%03d\n",


sprintf(verStr, "RFB %03d.%03d\n", sprintf(verStr, "RFB %03d.%03d\n",
server.majorVersion, server.minorVersion); server.majorVersion, server.minorVersion);
os->writeBytes(verStr, 12);
os->writeBytes((const uint8_t*)verStr, 12);
os->flush(); os->flush();


state_ = RFBSTATE_SECURITY_TYPES; state_ = RFBSTATE_SECURITY_TYPES;
is->clearRestorePoint(); is->clearRestorePoint();


std::vector<char> reason(len + 1); std::vector<char> reason(len + 1);
is->readBytes(reason.data(), len);
is->readBytes((uint8_t*)reason.data(), len);
reason[len] = '\0'; reason[len] = '\0';


state_ = RFBSTATE_INVALID; state_ = RFBSTATE_INVALID;
{ {
hasLocalClipboard = false; hasLocalClipboard = false;


serverClipboard = latin1ToUTF8(str);
serverClipboard = str;
hasRemoteClipboard = true; hasRemoteClipboard = true;


handleClipboardAnnounce(true); handleClipboardAnnounce(true);
return; return;
} }


// FIXME: This conversion magic should be in CMsgReader
if (!isValidUTF8((const char*)data[0], lengths[0])) {
vlog.error("Invalid UTF-8 sequence in clipboard - ignoring");
return;
}
serverClipboard = convertLF((const char*)data[0], lengths[0]); serverClipboard = convertLF((const char*)data[0], lengths[0]);
hasRemoteClipboard = true; hasRemoteClipboard = true;


void CConnection::sendClipboardData(const char* data) void CConnection::sendClipboardData(const char* data)
{ {
if (server.clipboardFlags() & rfb::clipboardProvide) { if (server.clipboardFlags() & rfb::clipboardProvide) {
// FIXME: This conversion magic should be in CMsgWriter
std::string filtered(convertCRLF(data)); std::string filtered(convertCRLF(data));
size_t sizes[1] = { filtered.size() + 1 }; size_t sizes[1] = { filtered.size() + 1 };
const uint8_t* data[1] = { (const uint8_t*)filtered.c_str() }; const uint8_t* data[1] = { (const uint8_t*)filtered.c_str() };


writer()->writeClipboardProvide(rfb::clipboardUTF8, sizes, data); writer()->writeClipboardProvide(rfb::clipboardUTF8, sizes, data);
} else { } else {
std::string latin1(utf8ToLatin1(data));

writer()->writeClientCutText(latin1.c_str());
writer()->writeClientCutText(data);
} }
} }


formatChange = true; formatChange = true;
} }


void CConnection::fence(uint32_t flags, unsigned len, const char data[])
void CConnection::fence(uint32_t flags, unsigned len, const uint8_t data[])
{ {
CMsgHandler::fence(flags, len, data); CMsgHandler::fence(flags, len, data);



+ 1
- 1
common/rfb/CConnection.h View File

// responds to requests, stating no support for synchronisation. // responds to requests, stating no support for synchronisation.
// When overriding, call CMsgHandler::fence() directly in order to // When overriding, call CMsgHandler::fence() directly in order to
// state correct support for fence flags. // state correct support for fence flags.
virtual void fence(uint32_t flags, unsigned len, const char data[]);
virtual void fence(uint32_t flags, unsigned len, const uint8_t data[]);


private: private:
bool processVersionMsg(); bool processVersionMsg();

+ 1
- 1
common/rfb/CMsgHandler.cxx View File

} }


void CMsgHandler::fence(uint32_t /*flags*/, unsigned /*len*/, void CMsgHandler::fence(uint32_t /*flags*/, unsigned /*len*/,
const char /*data*/ [])
const uint8_t /*data*/ [])
{ {
server.supportsFence = true; server.supportsFence = true;
} }

+ 1
- 1
common/rfb/CMsgHandler.h View File

virtual void setCursorPos(const Point& pos) = 0; virtual void setCursorPos(const Point& pos) = 0;
virtual void setPixelFormat(const PixelFormat& pf); virtual void setPixelFormat(const PixelFormat& pf);
virtual void setName(const char* name); virtual void setName(const char* name);
virtual void fence(uint32_t flags, unsigned len, const char data[]);
virtual void fence(uint32_t flags, unsigned len, const uint8_t data[]);
virtual void endOfContinuousUpdates(); virtual void endOfContinuousUpdates();
virtual void supportsQEMUKeyEvent(); virtual void supportsQEMUKeyEvent();
virtual void serverInit(int width, int height, virtual void serverInit(int width, int height,

+ 23
- 8
common/rfb/CMsgReader.cxx View File

return false; return false;
is->clearRestorePoint(); is->clearRestorePoint();
std::vector<char> name(len + 1); std::vector<char> name(len + 1);
is->readBytes(name.data(), len);
is->readBytes((uint8_t*)name.data(), len);
name[len] = '\0'; name[len] = '\0';
handler->serverInit(width, height, pf, name.data());

if (isValidUTF8(name.data()))
handler->serverInit(width, height, pf, name.data());
else
handler->serverInit(width, height, pf,
latin1ToUTF8(name.data()).c_str());


return true; return true;
} }
vlog.error("cut text too long (%d bytes) - ignoring",len); vlog.error("cut text too long (%d bytes) - ignoring",len);
return true; return true;
} }

std::vector<char> ca(len); std::vector<char> ca(len);
is->readBytes(ca.data(), len);
std::string filtered(convertLF(ca.data(), len));
is->readBytes((uint8_t*)ca.data(), len);

std::string utf8(latin1ToUTF8(ca.data(), ca.size()));
std::string filtered(convertLF(utf8.data(), utf8.size()));

handler->serverCutText(filtered.c_str()); handler->serverCutText(filtered.c_str());


return true; return true;
{ {
uint32_t flags; uint32_t flags;
uint8_t len; uint8_t len;
char data[64];
uint8_t data[64];


if (!is->hasData(3 + 4 + 1)) if (!is->hasData(3 + 4 + 1))
return false; return false;
is->clearRestorePoint(); is->clearRestorePoint();


std::vector<char> name(len + 1); std::vector<char> name(len + 1);
is->readBytes(name.data(), len);
is->readBytes((uint8_t*)name.data(), len);
name[len] = '\0'; name[len] = '\0';


if (x || y || w || h) { if (x || y || w || h) {
vlog.error("Ignoring DesktopName rect with non-zero position/size"); vlog.error("Ignoring DesktopName rect with non-zero position/size");
} else {
handler->setName(name.data());
return true;
} }


if (!isValidUTF8(name.data())) {
vlog.error("Ignoring DesktopName rect with invalid UTF-8 sequence");
return true;
}

handler->setName(name.data());

return true; return true;
} }



+ 6
- 6
common/rfb/CMsgWriter.cxx View File

#include <rfb/Rect.h> #include <rfb/Rect.h>
#include <rfb/ServerParams.h> #include <rfb/ServerParams.h>
#include <rfb/CMsgWriter.h> #include <rfb/CMsgWriter.h>
#include <rfb/util.h>


using namespace rfb; using namespace rfb;


endMsg(); endMsg();
} }


void CMsgWriter::writeFence(uint32_t flags, unsigned len, const char data[])
void CMsgWriter::writeFence(uint32_t flags, unsigned len, const uint8_t data[])
{ {
if (!server->supportsFence) if (!server->supportsFence)
throw Exception("Server does not support fences"); throw Exception("Server does not support fences");


void CMsgWriter::writeClientCutText(const char* str) void CMsgWriter::writeClientCutText(const char* str)
{ {
size_t len;

if (strchr(str, '\r') != NULL) if (strchr(str, '\r') != NULL)
throw Exception("Invalid carriage return in clipboard data"); throw Exception("Invalid carriage return in clipboard data");


len = strlen(str);
std::string latin1(utf8ToLatin1(str));

startMsg(msgTypeClientCutText); startMsg(msgTypeClientCutText);
os->pad(3); os->pad(3);
os->writeU32(len);
os->writeBytes(str, len);
os->writeU32(latin1.size());
os->writeBytes((const uint8_t*)latin1.data(), latin1.size());
endMsg(); endMsg();
} }



+ 1
- 1
common/rfb/CMsgWriter.h View File

void writeFramebufferUpdateRequest(const Rect& r,bool incremental); void writeFramebufferUpdateRequest(const Rect& r,bool incremental);
void writeEnableContinuousUpdates(bool enable, int x, int y, int w, int h); void writeEnableContinuousUpdates(bool enable, int x, int y, int w, int h);


void writeFence(uint32_t flags, unsigned len, const char data[]);
void writeFence(uint32_t flags, unsigned len, const uint8_t data[]);


void writeKeyEvent(uint32_t keysym, uint32_t keycode, bool down); void writeKeyEvent(uint32_t keysym, uint32_t keycode, bool down);
void writePointerEvent(const Point& pos, int buttonMask); void writePointerEvent(const Point& pos, int buttonMask);

+ 2
- 2
common/rfb/CSecurityDH.cxx View File

struct aes128_ctx aesCtx; struct aes128_ctx aesCtx;
aes128_set_encrypt_key(&aesCtx, key); aes128_set_encrypt_key(&aesCtx, key);


char buf[128];
uint8_t buf[128];
if (!rs.hasData(128)) if (!rs.hasData(128))
throw ConnFailedException("failed to generate random padding"); throw ConnFailedException("failed to generate random padding");
rs.readBytes(buf, 128); rs.readBytes(buf, 128);
if (password.size() >= 64) if (password.size() >= 64)
throw AuthFailureException("password is too long"); throw AuthFailureException("password is too long");
memcpy(buf + 64, password.c_str(), password.size() + 1); memcpy(buf + 64, password.c_str(), password.size() + 1);
aes128_encrypt(&aesCtx, 128, (uint8_t *)buf, (uint8_t *)buf);
aes128_encrypt(&aesCtx, 128, buf, buf);


rdr::OutStream* os = cc->getOutStream(); rdr::OutStream* os = cc->getOutStream();
os->writeBytes(buf, 128); os->writeBytes(buf, 128);

+ 2
- 2
common/rfb/CSecurityPlain.cxx View File

// Return the response to the server // Return the response to the server
os->writeU32(username.size()); os->writeU32(username.size());
os->writeU32(password.size()); os->writeU32(password.size());
os->writeBytes(username.data(), username.size());
os->writeBytes(password.data(), password.size());
os->writeBytes((const uint8_t*)username.data(), username.size());
os->writeBytes((const uint8_t*)password.data(), password.size());
os->flush(); os->flush();
return true; return true;
} }

+ 2
- 2
common/rfb/CSecurityRSAAES.cxx View File

if (username.size() > 255) if (username.size() > 255)
throw AuthFailureException("username is too long"); throw AuthFailureException("username is too long");
raos->writeU8(username.size()); raos->writeU8(username.size());
raos->writeBytes(username.data(), username.size());
raos->writeBytes((const uint8_t*)username.data(), username.size());
} else { } else {
raos->writeU8(0); raos->writeU8(0);
} }
if (password.size() > 255) if (password.size() > 255)
throw AuthFailureException("password is too long"); throw AuthFailureException("password is too long");
raos->writeU8(password.size()); raos->writeU8(password.size());
raos->writeBytes(password.data(), password.size());
raos->writeBytes((const uint8_t*)password.data(), password.size());
raos->flush(); raos->flush();
} }

+ 2
- 2
common/rfb/CopyRectDecoder.cxx View File





void CopyRectDecoder::getAffectedRegion(const Rect& rect, void CopyRectDecoder::getAffectedRegion(const Rect& rect,
const void* buffer,
const uint8_t* buffer,
size_t buflen, size_t buflen,
const ServerParams& server, const ServerParams& server,
Region* region) Region* region)
srcY-rect.tl.y)))); srcY-rect.tl.y))));
} }


void CopyRectDecoder::decodeRect(const Rect& r, const void* buffer,
void CopyRectDecoder::decodeRect(const Rect& r, const uint8_t* buffer,
size_t buflen, size_t buflen,
const ServerParams& /*server*/, const ServerParams& /*server*/,
ModifiablePixelBuffer* pb) ModifiablePixelBuffer* pb)

+ 2
- 2
common/rfb/CopyRectDecoder.h View File

virtual ~CopyRectDecoder(); virtual ~CopyRectDecoder();
virtual bool readRect(const Rect& r, rdr::InStream* is, virtual bool readRect(const Rect& r, rdr::InStream* is,
const ServerParams& server, rdr::OutStream* os); const ServerParams& server, rdr::OutStream* os);
virtual void getAffectedRegion(const Rect& rect, const void* buffer,
virtual void getAffectedRegion(const Rect& rect, const uint8_t* buffer,
size_t buflen, const ServerParams& server, size_t buflen, const ServerParams& server,
Region* region); Region* region);
virtual void decodeRect(const Rect& r, const void* buffer,
virtual void decodeRect(const Rect& r, const uint8_t* buffer,
size_t buflen, const ServerParams& server, size_t buflen, const ServerParams& server,
ModifiablePixelBuffer* pb); ModifiablePixelBuffer* pb);
}; };

+ 3
- 3
common/rfb/Decoder.cxx View File

} }


void Decoder::getAffectedRegion(const Rect& rect, void Decoder::getAffectedRegion(const Rect& rect,
const void* /*buffer*/,
const uint8_t* /*buffer*/,
size_t /*buflen*/, size_t /*buflen*/,
const ServerParams& /*server*/, const ServerParams& /*server*/,
Region* region) Region* region)
} }


bool Decoder::doRectsConflict(const Rect& /*rectA*/, bool Decoder::doRectsConflict(const Rect& /*rectA*/,
const void* /*bufferA*/,
const uint8_t* /*bufferA*/,
size_t /*buflenA*/, size_t /*buflenA*/,
const Rect& /*rectB*/, const Rect& /*rectB*/,
const void* /*bufferB*/,
const uint8_t* /*bufferB*/,
size_t /*buflenB*/, size_t /*buflenB*/,
const ServerParams& /*server*/) const ServerParams& /*server*/)
{ {

+ 6
- 4
common/rfb/Decoder.h View File

#ifndef __RFB_DECODER_H__ #ifndef __RFB_DECODER_H__
#define __RFB_DECODER_H__ #define __RFB_DECODER_H__


#include <stdint.h>

namespace rdr { namespace rdr {
class InStream; class InStream;
class OutStream; class OutStream;
// getAffectedRegion() returns the parts of the frame buffer will // getAffectedRegion() returns the parts of the frame buffer will
// be either read from or written do when decoding this rect. The // be either read from or written do when decoding this rect. The
// default implementation simply returns the given rectangle. // default implementation simply returns the given rectangle.
virtual void getAffectedRegion(const Rect& rect, const void* buffer,
virtual void getAffectedRegion(const Rect& rect, const uint8_t* buffer,
size_t buflen, const ServerParams& server, size_t buflen, const ServerParams& server,
Region* region); Region* region);


// in the order they were received. This will only be called if the // in the order they were received. This will only be called if the
// DecoderPartiallyOrdered flag has been set. // DecoderPartiallyOrdered flag has been set.
virtual bool doRectsConflict(const Rect& rectA, virtual bool doRectsConflict(const Rect& rectA,
const void* bufferA,
const uint8_t* bufferA,
size_t buflenA, size_t buflenA,
const Rect& rectB, const Rect& rectB,
const void* bufferB,
const uint8_t* bufferB,
size_t buflenB, size_t buflenB,
const ServerParams& server); const ServerParams& server);


// given buffer, onto the ModifiablePixelBuffer. The PixelFormat of // given buffer, onto the ModifiablePixelBuffer. The PixelFormat of
// the PixelBuffer might not match the ConnParams and it is up to // the PixelBuffer might not match the ConnParams and it is up to
// the decoder to do any necessary conversion. // the decoder to do any necessary conversion.
virtual void decodeRect(const Rect& r, const void* buffer,
virtual void decodeRect(const Rect& r, const uint8_t* buffer,
size_t buflen, const ServerParams& server, size_t buflen, const ServerParams& server,
ModifiablePixelBuffer* pb)=0; ModifiablePixelBuffer* pb)=0;



+ 1
- 1
common/rfb/H264Decoder.cxx View File

return true; return true;
} }


void H264Decoder::decodeRect(const Rect& r, const void* buffer,
void H264Decoder::decodeRect(const Rect& r, const uint8_t* buffer,
size_t buflen, size_t buflen,
const ServerParams& /*server*/, const ServerParams& /*server*/,
ModifiablePixelBuffer* pb) ModifiablePixelBuffer* pb)

+ 1
- 1
common/rfb/H264Decoder.h View File

virtual ~H264Decoder(); virtual ~H264Decoder();
virtual bool readRect(const Rect& r, rdr::InStream* is, virtual bool readRect(const Rect& r, rdr::InStream* is,
const ServerParams& server, rdr::OutStream* os); const ServerParams& server, rdr::OutStream* os);
virtual void decodeRect(const Rect& r, const void* buffer,
virtual void decodeRect(const Rect& r, const uint8_t* buffer,
size_t buflen, const ServerParams& server, size_t buflen, const ServerParams& server,
ModifiablePixelBuffer* pb); ModifiablePixelBuffer* pb);



+ 2
- 2
common/rfb/HextileDecoder.cxx View File

return true; return true;
} }


void HextileDecoder::decodeRect(const Rect& r, const void* buffer,
void HextileDecoder::decodeRect(const Rect& r, const uint8_t* buffer,
size_t buflen, const ServerParams& server, size_t buflen, const ServerParams& server,
ModifiablePixelBuffer* pb) ModifiablePixelBuffer* pb)
{ {
int tileType = is->readU8(); int tileType = is->readU8();


if (tileType & hextileRaw) { if (tileType & hextileRaw) {
is->readBytes(buf, t.area() * sizeof(T));
is->readBytes((uint8_t*)buf, t.area() * sizeof(T));
pb->imageRect(pf, t, buf); pb->imageRect(pf, t, buf);
continue; continue;
} }

+ 1
- 1
common/rfb/HextileDecoder.h View File

virtual ~HextileDecoder(); virtual ~HextileDecoder();
virtual bool readRect(const Rect& r, rdr::InStream* is, virtual bool readRect(const Rect& r, rdr::InStream* is,
const ServerParams& server, rdr::OutStream* os); const ServerParams& server, rdr::OutStream* os);
virtual void decodeRect(const Rect& r, const void* buffer,
virtual void decodeRect(const Rect& r, const uint8_t* buffer,
size_t buflen, const ServerParams& server, size_t buflen, const ServerParams& server,
ModifiablePixelBuffer* pb); ModifiablePixelBuffer* pb);
private: private:

+ 4
- 2
common/rfb/HextileEncoder.cxx View File

if (encodedLen < 0) { if (encodedLen < 0) {
pb->getImage(buf, t); pb->getImage(buf, t);
os->writeU8(hextileRaw); os->writeU8(hextileRaw);
os->writeBytes(buf, t.width() * t.height() * sizeof(T));
os->writeBytes((const uint8_t*)buf,
t.width() * t.height() * sizeof(T));
oldBgValid = oldFgValid = false; oldBgValid = oldFgValid = false;
continue; continue;
} }
if ( (tileType & hextileRaw) != 0 || if ( (tileType & hextileRaw) != 0 ||
encodedLen >= t.width() * t.height() * sizeof(T)) { encodedLen >= t.width() * t.height() * sizeof(T)) {
os->writeU8(hextileRaw); os->writeU8(hextileRaw);
os->writeBytes(buf, t.width() * t.height() * sizeof(T));
os->writeBytes((const uint8_t*)buf,
t.width() * t.height() * sizeof(T));
oldBgValid = oldFgValid = false; oldBgValid = oldFgValid = false;
continue; continue;
} }

+ 1
- 1
common/rfb/JpegCompressor.cxx View File

delete[] rowPointer; delete[] rowPointer;
} }


void JpegCompressor::writeBytes(const void* /*data*/, int /*length*/)
void JpegCompressor::writeBytes(const uint8_t* /*data*/, int /*length*/)
{ {
throw rdr::Exception("writeBytes() is not valid with a JpegCompressor instance. Use compress() instead."); throw rdr::Exception("writeBytes() is not valid with a JpegCompressor instance. Use compress() instead.");
} }

+ 1
- 1
common/rfb/JpegCompressor.h View File



void compress(const uint8_t *, int, const Rect&, const PixelFormat&, int, int); void compress(const uint8_t *, int, const Rect&, const PixelFormat&, int, int);


void writeBytes(const void*, int);
void writeBytes(const uint8_t*, int);


private: private:



+ 1
- 1
common/rfb/RREDecoder.cxx View File

return true; return true;
} }


void RREDecoder::decodeRect(const Rect& r, const void* buffer,
void RREDecoder::decodeRect(const Rect& r, const uint8_t* buffer,
size_t buflen, const ServerParams& server, size_t buflen, const ServerParams& server,
ModifiablePixelBuffer* pb) ModifiablePixelBuffer* pb)
{ {

+ 1
- 1
common/rfb/RREDecoder.h View File

virtual ~RREDecoder(); virtual ~RREDecoder();
virtual bool readRect(const Rect& r, rdr::InStream* is, virtual bool readRect(const Rect& r, rdr::InStream* is,
const ServerParams& server, rdr::OutStream* os); const ServerParams& server, rdr::OutStream* os);
virtual void decodeRect(const Rect& r, const void* buffer,
virtual void decodeRect(const Rect& r, const uint8_t* buffer,
size_t buflen, const ServerParams& server, size_t buflen, const ServerParams& server,
ModifiablePixelBuffer* pb); ModifiablePixelBuffer* pb);
private: private:

+ 1
- 1
common/rfb/RawDecoder.cxx View File

return true; return true;
} }


void RawDecoder::decodeRect(const Rect& r, const void* buffer,
void RawDecoder::decodeRect(const Rect& r, const uint8_t* buffer,
size_t buflen, const ServerParams& server, size_t buflen, const ServerParams& server,
ModifiablePixelBuffer* pb) ModifiablePixelBuffer* pb)
{ {

+ 1
- 1
common/rfb/RawDecoder.h View File

virtual ~RawDecoder(); virtual ~RawDecoder();
virtual bool readRect(const Rect& r, rdr::InStream* is, virtual bool readRect(const Rect& r, rdr::InStream* is,
const ServerParams& server, rdr::OutStream* os); const ServerParams& server, rdr::OutStream* os);
virtual void decodeRect(const Rect& r, const void* buffer,
virtual void decodeRect(const Rect& r, const uint8_t* buffer,
size_t buflen, const ServerParams& server, size_t buflen, const ServerParams& server,
ModifiablePixelBuffer* pb); ModifiablePixelBuffer* pb);
}; };

+ 17
- 11
common/rfb/SConnection.cxx View File

char str[13]; char str[13];


sprintf(str, "RFB %03d.%03d\n", defaultMajorVersion, defaultMinorVersion); sprintf(str, "RFB %03d.%03d\n", defaultMajorVersion, defaultMinorVersion);
os->writeBytes(str, 12);
os->writeBytes((const uint8_t*)str, 12);
os->flush(); os->flush();


state_ = RFBSTATE_PROTOCOL_VERSION; state_ = RFBSTATE_PROTOCOL_VERSION;
if (!is->hasData(12)) if (!is->hasData(12))
return false; return false;


is->readBytes(verStr, 12);
is->readBytes((uint8_t*)verStr, 12);
verStr[12] = '\0'; verStr[12] = '\0';


if (sscanf(verStr, "RFB %03d.%03d\n", if (sscanf(verStr, "RFB %03d.%03d\n",
os->writeU32(secResultFailed); os->writeU32(secResultFailed);
if (!client.beforeVersion(3,8)) { // 3.8 onwards have failure message if (!client.beforeVersion(3,8)) { // 3.8 onwards have failure message
os->writeU32(authFailureMsg.size()); os->writeU32(authFailureMsg.size());
os->writeBytes(authFailureMsg.data(), authFailureMsg.size());
os->writeBytes((const uint8_t*)authFailureMsg.data(),
authFailureMsg.size());
} }
os->flush(); os->flush();
} catch (rdr::Exception& e) { } catch (rdr::Exception& e) {
if (client.majorVersion == 3 && client.minorVersion == 3) { if (client.majorVersion == 3 && client.minorVersion == 3) {
os->writeU32(0); os->writeU32(0);
os->writeU32(strlen(str)); os->writeU32(strlen(str));
os->writeBytes(str, strlen(str));
os->writeBytes((const uint8_t*)str, strlen(str));
os->flush(); os->flush();
} else { } else {
os->writeU8(0); os->writeU8(0);
os->writeU32(strlen(str)); os->writeU32(strlen(str));
os->writeBytes(str, strlen(str));
os->writeBytes((const uint8_t*)str, strlen(str));
os->flush(); os->flush();
} }
} }
{ {
hasLocalClipboard = false; hasLocalClipboard = false;


clientClipboard = latin1ToUTF8(str);
clientClipboard = str;
hasRemoteClipboard = true; hasRemoteClipboard = true;


handleClipboardAnnounce(true); handleClipboardAnnounce(true);
return; return;
} }


// FIXME: This conversion magic should be in SMsgReader
if (!isValidUTF8((const char*)data[0], lengths[0])) {
vlog.error("Invalid UTF-8 sequence in clipboard - ignoring");
return;
}
clientClipboard = convertLF((const char*)data[0], lengths[0]); clientClipboard = convertLF((const char*)data[0], lengths[0]);
hasRemoteClipboard = true; hasRemoteClipboard = true;


if (!reason) if (!reason)
reason = "Authentication failure"; reason = "Authentication failure";
os->writeU32(strlen(reason)); os->writeU32(strlen(reason));
os->writeBytes(reason, strlen(reason));
os->writeBytes((const uint8_t*)reason, strlen(reason));
} }
} }
os->flush(); os->flush();
} }
} }


void SConnection::fence(uint32_t flags, unsigned len, const char data[])
void SConnection::fence(uint32_t flags, unsigned len,
const uint8_t data[])
{ {
if (!(flags & fenceFlagRequest)) if (!(flags & fenceFlagRequest))
return; return;
{ {
if (client.supportsEncoding(pseudoEncodingExtendedClipboard) && if (client.supportsEncoding(pseudoEncodingExtendedClipboard) &&
(client.clipboardFlags() & rfb::clipboardProvide)) { (client.clipboardFlags() & rfb::clipboardProvide)) {
// FIXME: This conversion magic should be in SMsgWriter
std::string filtered(convertCRLF(data)); std::string filtered(convertCRLF(data));
size_t sizes[1] = { filtered.size() + 1 }; size_t sizes[1] = { filtered.size() + 1 };
const uint8_t* data[1] = { (const uint8_t*)filtered.c_str() }; const uint8_t* data[1] = { (const uint8_t*)filtered.c_str() };


writer()->writeClipboardProvide(rfb::clipboardUTF8, sizes, data); writer()->writeClipboardProvide(rfb::clipboardUTF8, sizes, data);
} else { } else {
std::string latin1(utf8ToLatin1(data));

writer()->writeServerCutText(latin1.c_str());
writer()->writeServerCutText(data);
} }
} }



+ 1
- 1
common/rfb/SConnection.h View File

// it responds directly to requests (stating it doesn't support any // it responds directly to requests (stating it doesn't support any
// synchronisation) and drops responses. Override to implement more proper // synchronisation) and drops responses. Override to implement more proper
// support. // support.
virtual void fence(uint32_t flags, unsigned len, const char data[]);
virtual void fence(uint32_t flags, unsigned len, const uint8_t data[]);


// enableContinuousUpdates() is called when the client wants to enable // enableContinuousUpdates() is called when the client wants to enable
// or disable continuous updates, or change the active area. // or disable continuous updates, or change the active area.

+ 1
- 1
common/rfb/SMsgHandler.h View File

virtual void framebufferUpdateRequest(const Rect& r, bool incremental) = 0; virtual void framebufferUpdateRequest(const Rect& r, bool incremental) = 0;
virtual void setDesktopSize(int fb_width, int fb_height, virtual void setDesktopSize(int fb_width, int fb_height,
const ScreenSet& layout) = 0; const ScreenSet& layout) = 0;
virtual void fence(uint32_t flags, unsigned len, const char data[]) = 0;
virtual void fence(uint32_t flags, unsigned len, const uint8_t data[]) = 0;
virtual void enableContinuousUpdates(bool enable, virtual void enableContinuousUpdates(bool enable,
int x, int y, int w, int h) = 0; int x, int y, int w, int h) = 0;



+ 6
- 3
common/rfb/SMsgReader.cxx View File

{ {
uint32_t flags; uint32_t flags;
uint8_t len; uint8_t len;
char data[64];
uint8_t data[64];


if (!is->hasData(3 + 4 + 1)) if (!is->hasData(3 + 4 + 1))
return false; return false;
} }


std::vector<char> ca(len); std::vector<char> ca(len);
is->readBytes(ca.data(), len);
std::string filtered(convertLF(ca.data(), len));
is->readBytes((uint8_t*)ca.data(), len);

std::string utf8(latin1ToUTF8(ca.data(), ca.size()));
std::string filtered(convertLF(utf8.data(), utf8.size()));

handler->clientCutText(filtered.c_str()); handler->clientCutText(filtered.c_str());


return true; return true;

+ 13
- 10
common/rfb/SMsgWriter.cxx View File

#include <rfb/SMsgWriter.h> #include <rfb/SMsgWriter.h>
#include <rfb/LogWriter.h> #include <rfb/LogWriter.h>
#include <rfb/ledStates.h> #include <rfb/ledStates.h>
#include <rfb/util.h>


using namespace rfb; using namespace rfb;


os->writeU16(height); os->writeU16(height);
pf.write(os); pf.write(os);
os->writeU32(strlen(name)); os->writeU32(strlen(name));
os->writeBytes(name, strlen(name));
os->writeBytes((const uint8_t*)name, strlen(name));
endMsg(); endMsg();
} }




void SMsgWriter::writeServerCutText(const char* str) void SMsgWriter::writeServerCutText(const char* str)
{ {
size_t len;

if (strchr(str, '\r') != NULL) if (strchr(str, '\r') != NULL)
throw Exception("Invalid carriage return in clipboard data"); throw Exception("Invalid carriage return in clipboard data");


len = strlen(str);
std::string latin1(utf8ToLatin1(str));

startMsg(msgTypeServerCutText); startMsg(msgTypeServerCutText);
os->pad(3); os->pad(3);
os->writeU32(len);
os->writeBytes(str, len);
os->writeU32(latin1.size());
os->writeBytes((const uint8_t*)latin1.data(), latin1.size());
endMsg(); endMsg();
} }


endMsg(); endMsg();
} }


void SMsgWriter::writeFence(uint32_t flags, unsigned len, const char data[])
void SMsgWriter::writeFence(uint32_t flags, unsigned len,
const uint8_t data[])
{ {
if (!client->supportsEncoding(pseudoEncodingFence)) if (!client->supportsEncoding(pseudoEncodingFence))
throw Exception("Client does not support fences"); throw Exception("Client does not support fences");
os->writeU16(0); os->writeU16(0);
os->writeU32(pseudoEncodingDesktopName); os->writeU32(pseudoEncodingDesktopName);
os->writeU32(strlen(name)); os->writeU32(strlen(name));
os->writeBytes(name, strlen(name));
os->writeBytes((const uint8_t*)name, strlen(name));
} }


void SMsgWriter::writeSetCursorRect(int width, int height, void SMsgWriter::writeSetCursorRect(int width, int height,
int hotspotX, int hotspotY, int hotspotX, int hotspotY,
const void* data, const void* mask)
const uint8_t* data,
const uint8_t* mask)
{ {
if (!client->supportsEncoding(pseudoEncodingCursor)) if (!client->supportsEncoding(pseudoEncodingCursor))
throw Exception("Client does not support local cursors"); throw Exception("Client does not support local cursors");


void SMsgWriter::writeSetXCursorRect(int width, int height, void SMsgWriter::writeSetXCursorRect(int width, int height,
int hotspotX, int hotspotY, int hotspotX, int hotspotY,
const void* data, const void* mask)
const uint8_t* data,
const uint8_t* mask)
{ {
if (!client->supportsEncoding(pseudoEncodingXCursor)) if (!client->supportsEncoding(pseudoEncodingXCursor))
throw Exception("Client does not support local cursors"); throw Exception("Client does not support local cursors");

+ 3
- 3
common/rfb/SMsgWriter.h View File

const uint8_t* const* data); const uint8_t* const* data);


// writeFence() sends a new fence request or response to the client. // writeFence() sends a new fence request or response to the client.
void writeFence(uint32_t flags, unsigned len, const char data[]);
void writeFence(uint32_t flags, unsigned len, const uint8_t data[]);


// writeEndOfContinuousUpdates() indicates that we have left continuous // writeEndOfContinuousUpdates() indicates that we have left continuous
// updates mode. // updates mode.
void writeSetDesktopNameRect(const char *name); void writeSetDesktopNameRect(const char *name);
void writeSetCursorRect(int width, int height, void writeSetCursorRect(int width, int height,
int hotspotX, int hotspotY, int hotspotX, int hotspotY,
const void* data, const void* mask);
const uint8_t* data, const uint8_t* mask);
void writeSetXCursorRect(int width, int height, void writeSetXCursorRect(int width, int height,
int hotspotX, int hotspotY, int hotspotX, int hotspotY,
const void* data, const void* mask);
const uint8_t* data, const uint8_t* mask);
void writeSetCursorWithAlphaRect(int width, int height, void writeSetCursorWithAlphaRect(int width, int height,
int hotspotX, int hotspotY, int hotspotX, int hotspotY,
const uint8_t* data); const uint8_t* data);

+ 2
- 2
common/rfb/SSecurityPlain.cxx View File

if (!is->hasData(ulen + plen)) if (!is->hasData(ulen + plen))
return false; return false;
state = 2; state = 2;
is->readBytes(username, ulen);
is->readBytes(password, plen);
is->readBytes((uint8_t*)username, ulen);
is->readBytes((uint8_t*)password, plen);
password[plen] = 0; password[plen] = 0;
username[ulen] = 0; username[ulen] = 0;
plen = 0; plen = 0;

+ 2
- 2
common/rfb/SSecurityRSAAES.cxx View File

uint8_t lenUsername = rais->readU8(); uint8_t lenUsername = rais->readU8();
if (!rais->hasDataOrRestore(lenUsername + 1)) if (!rais->hasDataOrRestore(lenUsername + 1))
return false; return false;
rais->readBytes(username, lenUsername);
rais->readBytes((uint8_t*)username, lenUsername);
username[lenUsername] = 0; username[lenUsername] = 0;
uint8_t lenPassword = rais->readU8(); uint8_t lenPassword = rais->readU8();
if (!rais->hasDataOrRestore(lenPassword)) if (!rais->hasDataOrRestore(lenPassword))
return false; return false;
rais->readBytes(password, lenPassword);
rais->readBytes((uint8_t*)password, lenPassword);
password[lenPassword] = 0; password[lenPassword] = 0;
rais->clearRestorePoint(); rais->clearRestorePoint();
return true; return true;

+ 3
- 3
common/rfb/TightDecoder.cxx View File

} }


bool TightDecoder::doRectsConflict(const Rect& /*rectA*/, bool TightDecoder::doRectsConflict(const Rect& /*rectA*/,
const void* bufferA,
const uint8_t* bufferA,
size_t buflenA, size_t buflenA,
const Rect& /*rectB*/, const Rect& /*rectB*/,
const void* bufferB,
const uint8_t* bufferB,
size_t buflenB, size_t buflenB,
const ServerParams& /*server*/) const ServerParams& /*server*/)
{ {
return false; return false;
} }


void TightDecoder::decodeRect(const Rect& r, const void* buffer,
void TightDecoder::decodeRect(const Rect& r, const uint8_t* buffer,
size_t buflen, const ServerParams& server, size_t buflen, const ServerParams& server,
ModifiablePixelBuffer* pb) ModifiablePixelBuffer* pb)
{ {

+ 3
- 3
common/rfb/TightDecoder.h View File

virtual bool readRect(const Rect& r, rdr::InStream* is, virtual bool readRect(const Rect& r, rdr::InStream* is,
const ServerParams& server, rdr::OutStream* os); const ServerParams& server, rdr::OutStream* os);
virtual bool doRectsConflict(const Rect& rectA, virtual bool doRectsConflict(const Rect& rectA,
const void* bufferA,
const uint8_t* bufferA,
size_t buflenA, size_t buflenA,
const Rect& rectB, const Rect& rectB,
const void* bufferB,
const uint8_t* bufferB,
size_t buflenB, size_t buflenB,
const ServerParams& server); const ServerParams& server);
virtual void decodeRect(const Rect& r, const void* buffer,
virtual void decodeRect(const Rect& r, const uint8_t* buffer,
size_t buflen, const ServerParams& server, size_t buflen, const ServerParams& server,
ModifiablePixelBuffer* pb); ModifiablePixelBuffer* pb);



+ 4
- 4
common/rfb/VNCSConnectionST.cxx View File

writer()->writeDesktopSize(reasonClient, result); writer()->writeDesktopSize(reasonClient, result);
} }


void VNCSConnectionST::fence(uint32_t flags, unsigned len, const char data[])
void VNCSConnectionST::fence(uint32_t flags, unsigned len, const uint8_t data[])
{ {
uint8_t type; uint8_t type;


delete [] fenceData; delete [] fenceData;
fenceData = NULL; fenceData = NULL;
if (len > 0) { if (len > 0) {
fenceData = new char[len];
fenceData = new uint8_t[len];
memcpy(fenceData, data, len); memcpy(fenceData, data, len);
} }




void VNCSConnectionST::supportsFence() void VNCSConnectionST::supportsFence()
{ {
char type = 0;
uint8_t type = 0;
writer()->writeFence(fenceFlagRequest, sizeof(type), &type); writer()->writeFence(fenceFlagRequest, sizeof(type), &type);
} }




void VNCSConnectionST::writeRTTPing() void VNCSConnectionST::writeRTTPing()
{ {
char type;
uint8_t type;


if (!client.supportsFence()) if (!client.supportsFence())
return; return;

+ 2
- 2
common/rfb/VNCSConnectionST.h View File

virtual void framebufferUpdateRequest(const Rect& r, bool incremental); virtual void framebufferUpdateRequest(const Rect& r, bool incremental);
virtual void setDesktopSize(int fb_width, int fb_height, virtual void setDesktopSize(int fb_width, int fb_height,
const ScreenSet& layout); const ScreenSet& layout);
virtual void fence(uint32_t flags, unsigned len, const char data[]);
virtual void fence(uint32_t flags, unsigned len, const uint8_t data[]);
virtual void enableContinuousUpdates(bool enable, virtual void enableContinuousUpdates(bool enable,
int x, int y, int w, int h); int x, int y, int w, int h);
virtual void handleClipboardRequest(); virtual void handleClipboardRequest();
bool pendingSyncFence, syncFence; bool pendingSyncFence, syncFence;
uint32_t fenceFlags; uint32_t fenceFlags;
unsigned fenceDataLen; unsigned fenceDataLen;
char *fenceData;
uint8_t *fenceData;


Congestion congestion; Congestion congestion;
Timer congestionTimer; Timer congestionTimer;

+ 2
- 2
common/rfb/VNCServerST.cxx View File

rdr::OutStream& os = sock->outStream(); rdr::OutStream& os = sock->outStream();


// Shortest possible way to tell a client it is not welcome // Shortest possible way to tell a client it is not welcome
os.writeBytes("RFB 003.003\n", 12);
os.writeBytes((const uint8_t*)"RFB 003.003\n", 12);
os.writeU32(0); os.writeU32(0);
const char* reason = "Too many security failures"; const char* reason = "Too many security failures";
os.writeU32(strlen(reason)); os.writeU32(strlen(reason));
os.writeBytes(reason, strlen(reason));
os.writeBytes((const uint8_t*)reason, strlen(reason));
os.flush(); os.flush();
} catch (rdr::Exception&) { } catch (rdr::Exception&) {
} }

+ 2
- 2
common/rfb/ZRLEDecoder.cxx View File

return true; return true;
} }


void ZRLEDecoder::decodeRect(const Rect& r, const void* buffer,
void ZRLEDecoder::decodeRect(const Rect& r, const uint8_t* buffer,
size_t buflen, const ServerParams& server, size_t buflen, const ServerParams& server,
ModifiablePixelBuffer* pb) ModifiablePixelBuffer* pb)
{ {
*ptr = readOpaque24B(zis); *ptr = readOpaque24B(zis);
} }
} else { } else {
zis->readBytes(buf, t.area() * sizeof(T));
zis->readBytes((uint8_t*)buf, t.area() * sizeof(T));
} }


} else { } else {

+ 1
- 1
common/rfb/ZRLEDecoder.h View File

virtual ~ZRLEDecoder(); virtual ~ZRLEDecoder();
virtual bool readRect(const Rect& r, rdr::InStream* is, virtual bool readRect(const Rect& r, rdr::InStream* is,
const ServerParams& server, rdr::OutStream* os); const ServerParams& server, rdr::OutStream* os);
virtual void decodeRect(const Rect& r, const void* buffer,
virtual void decodeRect(const Rect& r, const uint8_t* buffer,
size_t buflen, const ServerParams& server, size_t buflen, const ServerParams& server,
ModifiablePixelBuffer* pb); ModifiablePixelBuffer* pb);



+ 40
- 0
common/rfb/util.cxx View File

*dst++ = 0x80 | (src & 0x3f); *dst++ = 0x80 | (src & 0x3f);
*dst++ = '\0'; *dst++ = '\0';
return 2; return 2;
} else if ((src >= 0xd800) && (src < 0xe000)) {
return ucs4ToUTF8(0xfffd, dst);
} else if (src < 0x10000) { } else if (src < 0x10000) {
*dst++ = 0xe0 | (src >> 12); *dst++ = 0xe0 | (src >> 12);
*dst++ = 0x80 | ((src >> 6) & 0x3f); *dst++ = 0x80 | ((src >> 6) & 0x3f);
max--; max--;
} }


// UTF-16 surrogate code point?
if ((*dst >= 0xd800) && (*dst < 0xe000))
*dst = 0xfffd;

return consumed; return consumed;
} }


return out; return out;
} }


bool isValidUTF8(const char* str, size_t bytes)
{
while ((bytes > 0) && (*str != '\0')) {
size_t len;
unsigned ucs;

len = utf8ToUCS4(str, bytes, &ucs);
str += len;
bytes -= len;

if (ucs == 0xfffd)
return false;
}

return true;
}

bool isValidUTF16(const wchar_t* wstr, size_t units)
{
while ((units > 0) && (*wstr != '\0')) {
size_t len;
unsigned ucs;

len = utf16ToUCS4(wstr, units, &ucs);
wstr += len;
units -= len;

if (ucs == 0xfffd)
return false;
}

return true;
}

unsigned msBetween(const struct timeval *first, unsigned msBetween(const struct timeval *first,
const struct timeval *second) const struct timeval *second)
{ {

+ 3
- 0
common/rfb/util.h View File

std::string utf16ToUTF8(const wchar_t* src, size_t units = (size_t)-1); std::string utf16ToUTF8(const wchar_t* src, size_t units = (size_t)-1);
std::wstring utf8ToUTF16(const char* src, size_t bytes = (size_t)-1); std::wstring utf8ToUTF16(const char* src, size_t bytes = (size_t)-1);


bool isValidUTF8(const char* str, size_t bytes = (size_t)-1);
bool isValidUTF16(const wchar_t* wstr, size_t units = (size_t)-1);

// HELPER functions for timeout handling // HELPER functions for timeout handling


// soonestTimeout() is a function to help work out the soonest of several // soonestTimeout() is a function to help work out the soonest of several

+ 54
- 0
tests/unit/unicode.cxx View File

{ 0x1f638, "\xf0\x9f\x98\xb8" }, { 0x1f638, "\xf0\x9f\x98\xb8" },
{ 0x2d006, "\xf0\xad\x80\x86" }, { 0x2d006, "\xf0\xad\x80\x86" },
{ 0xfffd, "\xe5\xe4" }, { 0xfffd, "\xe5\xe4" },
{ 0xfffd, "\xed\xa2\x80" },
{ 0xfffd, "\xed\xbb\xbf" },
{ 0xd880, "\xef\xbf\xbd" },
{ 0xdeff, "\xef\xbf\xbd" },
{ 0x110200, "\xef\xbf\xbd" }, { 0x110200, "\xef\xbf\xbd" },
}; };


{ "\xed\xa1\xbf", L"\xfffd" }, { "\xed\xa1\xbf", L"\xfffd" },
}; };


const char *validutf8[] = {
"abc",
"\xc3\xa5\xc3\xa4\xc3\xb6",
"\xf0\xad\x80\x86",
};

const char *invalidutf8[] = {
"\xe5\xe4\xf6",
"\xf8\xa1\xa1\xa1\xa1",
"\xed\xa2\x80",
};

const wchar_t *validutf16[] = {
L"abc",
L"\xe5\xe4\xf6",
L"\xd83d\xde38\xd83d\xde41\xd83d\xde42",
};

const wchar_t *invalidutf16[] = {
L"\xdc40\xdc12",
};

#define ARRAY_SIZE(a) (sizeof(a)/sizeof(*a)) #define ARRAY_SIZE(a) (sizeof(a)/sizeof(*a))


int main(int /*argc*/, char** /*argv*/) int main(int /*argc*/, char** /*argv*/)
} }
} }


for (i = 0;i < ARRAY_SIZE(validutf8);i++) {
if (!rfb::isValidUTF8(validutf8[i])) {
printf("FAILED: isValidUTF8() #%d\n", (int)i+1);
failures++;
}
}

for (i = 0;i < ARRAY_SIZE(invalidutf8);i++) {
if (rfb::isValidUTF8(invalidutf8[i])) {
printf("FAILED: ! isValidUTF8() #%d\n", (int)i+1);
failures++;
}
}

for (i = 0;i < ARRAY_SIZE(validutf16);i++) {
if (!rfb::isValidUTF16(validutf16[i])) {
printf("FAILED: isValidUTF16() #%d\n", (int)i+1);
failures++;
}
}

for (i = 0;i < ARRAY_SIZE(invalidutf16);i++) {
if (rfb::isValidUTF16(invalidutf16[i])) {
printf("FAILED: ! isValidUTF16() #%d\n", (int)i+1);
failures++;
}
}

if (failures == 0) { if (failures == 0) {
printf("OK\n"); printf("OK\n");
} else { } else {

+ 9
- 0
unix/xserver/hw/vnc/RFBGlue.cc View File

return NULL; return NULL;
} }
} }

int vncIsValidUTF8(const char* str, size_t bytes)
{
try {
return isValidUTF8(str, bytes);
} catch (...) {
return 0;
}
}

+ 2
- 0
unix/xserver/hw/vnc/RFBGlue.h View File

char* vncLatin1ToUTF8(const char* src, size_t bytes); char* vncLatin1ToUTF8(const char* src, size_t bytes);
char* vncUTF8ToLatin1(const char* src, size_t bytes); char* vncUTF8ToLatin1(const char* src, size_t bytes);


int vncIsValidUTF8(const char* str, size_t bytes);

#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

+ 5
- 0
unix/xserver/hw/vnc/vncSelection.c View File

if (prop->type != xaUTF8_STRING) if (prop->type != xaUTF8_STRING)
return; return;


if (!vncIsValidUTF8(prop->data, prop->size)) {
LOG_ERROR("Invalid UTF-8 sequence in clipboard");
return;
}

filtered = vncConvertLF(prop->data, prop->size); filtered = vncConvertLF(prop->data, prop->size);
if (filtered == NULL) if (filtered == NULL)
return; return;

+ 1
- 1
vncviewer/CConn.cxx View File

desktop->setCursorPos(pos); desktop->setCursorPos(pos);
} }


void CConn::fence(uint32_t flags, unsigned len, const char data[])
void CConn::fence(uint32_t flags, unsigned len, const uint8_t data[])
{ {
CMsgHandler::fence(flags, len, data); CMsgHandler::fence(flags, len, data);



+ 1
- 1
vncviewer/CConn.h View File

const uint8_t* data); const uint8_t* data);
void setCursorPos(const rfb::Point& pos); void setCursorPos(const rfb::Point& pos);


void fence(uint32_t flags, unsigned len, const char data[]);
void fence(uint32_t flags, unsigned len, const uint8_t data[]);


void setLEDState(unsigned int state); void setLEDState(unsigned int state);



+ 5
- 0
vncviewer/Viewport.cxx View File



switch (event) { switch (event) {
case FL_PASTE: case FL_PASTE:
if (!isValidUTF8(Fl::event_text(), Fl::event_length())) {
vlog.error("Invalid UTF-8 sequence in system clipboard");
return 1;
}

filtered = convertLF(Fl::event_text(), Fl::event_length()); filtered = convertLF(Fl::event_text(), Fl::event_length());


vlog.debug("Sending clipboard data (%d bytes)", (int)filtered.size()); vlog.debug("Sending clipboard data (%d bytes)", (int)filtered.size());

Loading…
Cancel
Save