aboutsummaryrefslogtreecommitdiffstats
path: root/common/rfb
diff options
context:
space:
mode:
authorConstantin Kaplinsky <const@tightvnc.com>2006-05-25 05:01:55 +0000
committerConstantin Kaplinsky <const@tightvnc.com>2006-05-25 05:01:55 +0000
commita2adc8d4cfdf7336ce9192414c5e775224742a97 (patch)
tree0fc9f229bd40a2de342d91338798033da8ebd7bc /common/rfb
parent4fc2026b9595e9425f50616d18781995aebe495b (diff)
downloadtigervnc-a2adc8d4cfdf7336ce9192414c5e775224742a97.tar.gz
tigervnc-a2adc8d4cfdf7336ce9192414c5e775224742a97.zip
Migrating to new directory structure adopted from the RealVNC's source tree. More changes will follow.
git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@589 3789f03b-4d11-0410-bbf8-ca57d06f2519
Diffstat (limited to 'common/rfb')
-rw-r--r--common/rfb/Blacklist.cxx86
-rw-r--r--common/rfb/Blacklist.h91
-rw-r--r--common/rfb/CConnection.cxx276
-rw-r--r--common/rfb/CConnection.h183
-rw-r--r--common/rfb/CFTMsgReader.cxx162
-rw-r--r--common/rfb/CFTMsgReader.h56
-rw-r--r--common/rfb/CFTMsgWriter.cxx182
-rw-r--r--common/rfb/CFTMsgWriter.h67
-rw-r--r--common/rfb/CMsgHandler.cxx103
-rw-r--r--common/rfb/CMsgHandler.h71
-rw-r--r--common/rfb/CMsgReader.cxx158
-rw-r--r--common/rfb/CMsgReader.h73
-rw-r--r--common/rfb/CMsgReaderV3.cxx107
-rw-r--r--common/rfb/CMsgReaderV3.h35
-rw-r--r--common/rfb/CMsgWriter.cxx132
-rw-r--r--common/rfb/CMsgWriter.h65
-rw-r--r--common/rfb/CMsgWriterV3.cxx49
-rw-r--r--common/rfb/CMsgWriterV3.h35
-rw-r--r--common/rfb/CSecurity.h52
-rw-r--r--common/rfb/CSecurityNone.h36
-rw-r--r--common/rfb/CSecurityVncAuth.cxx74
-rw-r--r--common/rfb/CSecurityVncAuth.h39
-rw-r--r--common/rfb/ColourCube.h96
-rw-r--r--common/rfb/ColourMap.h34
-rw-r--r--common/rfb/ComparingUpdateTracker.cxx137
-rw-r--r--common/rfb/ComparingUpdateTracker.h43
-rw-r--r--common/rfb/Configuration.cxx466
-rw-r--r--common/rfb/Configuration.h265
-rw-r--r--common/rfb/ConnParams.cxx125
-rw-r--r--common/rfb/ConnParams.h93
-rw-r--r--common/rfb/Cursor.cxx179
-rw-r--r--common/rfb/Cursor.h56
-rw-r--r--common/rfb/Decoder.cxx70
-rw-r--r--common/rfb/Decoder.h52
-rw-r--r--common/rfb/DirManager.h42
-rw-r--r--common/rfb/Encoder.cxx77
-rw-r--r--common/rfb/Encoder.h61
-rw-r--r--common/rfb/Exception.h37
-rw-r--r--common/rfb/FileInfo.cxx244
-rw-r--r--common/rfb/FileInfo.h74
-rw-r--r--common/rfb/FileManager.cxx81
-rw-r--r--common/rfb/FileManager.h50
-rw-r--r--common/rfb/FileReader.cxx51
-rw-r--r--common/rfb/FileReader.h41
-rw-r--r--common/rfb/FileWriter.cxx52
-rw-r--r--common/rfb/FileWriter.h41
-rw-r--r--common/rfb/HTTPServer.cxx411
-rw-r--r--common/rfb/HTTPServer.h110
-rw-r--r--common/rfb/HextileDecoder.cxx59
-rw-r--r--common/rfb/HextileDecoder.h35
-rw-r--r--common/rfb/HextileEncoder.cxx90
-rw-r--r--common/rfb/HextileEncoder.h35
-rw-r--r--common/rfb/Hostname.h55
-rw-r--r--common/rfb/ImageGetter.h30
-rw-r--r--common/rfb/InputHandler.h40
-rw-r--r--common/rfb/KeyRemapper.cxx84
-rw-r--r--common/rfb/KeyRemapper.h39
-rw-r--r--common/rfb/ListConnInfo.h122
-rw-r--r--common/rfb/LogWriter.cxx137
-rw-r--r--common/rfb/LogWriter.h106
-rw-r--r--common/rfb/Logger.cxx118
-rw-r--r--common/rfb/Logger.h70
-rw-r--r--common/rfb/Logger_file.cxx127
-rw-r--r--common/rfb/Logger_file.h51
-rw-r--r--common/rfb/Logger_stdio.cxx32
-rw-r--r--common/rfb/Logger_stdio.h39
-rw-r--r--common/rfb/Makefile.in80
-rw-r--r--common/rfb/Password.cxx77
-rw-r--r--common/rfb/Password.h46
-rw-r--r--common/rfb/Pixel.h26
-rw-r--r--common/rfb/PixelBuffer.cxx309
-rw-r--r--common/rfb/PixelBuffer.h172
-rw-r--r--common/rfb/PixelFormat.cxx239
-rw-r--r--common/rfb/PixelFormat.h58
-rw-r--r--common/rfb/RREDecoder.cxx58
-rw-r--r--common/rfb/RREDecoder.h35
-rw-r--r--common/rfb/RREEncoder.cxx75
-rw-r--r--common/rfb/RREEncoder.h37
-rw-r--r--common/rfb/RawDecoder.cxx55
-rw-r--r--common/rfb/RawDecoder.h35
-rw-r--r--common/rfb/RawEncoder.cxx59
-rw-r--r--common/rfb/RawEncoder.h35
-rw-r--r--common/rfb/Rect.h116
-rw-r--r--common/rfb/Region.cxx248
-rw-r--r--common/rfb/Region.h84
-rw-r--r--common/rfb/SConnection.cxx322
-rw-r--r--common/rfb/SConnection.h193
-rw-r--r--common/rfb/SDesktop.h121
-rw-r--r--common/rfb/SFTMsgReader.cxx201
-rw-r--r--common/rfb/SFTMsgReader.h71
-rw-r--r--common/rfb/SFTMsgWriter.cxx152
-rw-r--r--common/rfb/SFTMsgWriter.h56
-rw-r--r--common/rfb/SFileTransfer.cxx335
-rw-r--r--common/rfb/SFileTransfer.h83
-rw-r--r--common/rfb/SFileTransferManager.cxx55
-rw-r--r--common/rfb/SFileTransferManager.h51
-rw-r--r--common/rfb/SMsgHandler.cxx52
-rw-r--r--common/rfb/SMsgHandler.h64
-rw-r--r--common/rfb/SMsgReader.cxx97
-rw-r--r--common/rfb/SMsgReader.h56
-rw-r--r--common/rfb/SMsgReaderV3.cxx68
-rw-r--r--common/rfb/SMsgReaderV3.h32
-rw-r--r--common/rfb/SMsgWriter.cxx202
-rw-r--r--common/rfb/SMsgWriter.h163
-rw-r--r--common/rfb/SMsgWriterV3.cxx197
-rw-r--r--common/rfb/SMsgWriterV3.h57
-rw-r--r--common/rfb/SSecurity.h84
-rw-r--r--common/rfb/SSecurityFactoryStandard.cxx128
-rw-r--r--common/rfb/SSecurityFactoryStandard.h68
-rw-r--r--common/rfb/SSecurityNone.h36
-rw-r--r--common/rfb/SSecurityVncAuth.cxx87
-rw-r--r--common/rfb/SSecurityVncAuth.h55
-rw-r--r--common/rfb/ScaledPixelBuffer.cxx132
-rw-r--r--common/rfb/ScaledPixelBuffer.h85
-rw-r--r--common/rfb/ServerCore.cxx94
-rw-r--r--common/rfb/ServerCore.h56
-rw-r--r--common/rfb/Threading.h31
-rw-r--r--common/rfb/TightDecoder.cxx159
-rw-r--r--common/rfb/TightDecoder.h49
-rw-r--r--common/rfb/TightEncoder.cxx193
-rw-r--r--common/rfb/TightEncoder.h78
-rw-r--r--common/rfb/TightPalette.cxx110
-rw-r--r--common/rfb/TightPalette.h127
-rw-r--r--common/rfb/Timer.cxx179
-rw-r--r--common/rfb/Timer.h102
-rw-r--r--common/rfb/TransImageGetter.cxx278
-rw-r--r--common/rfb/TransImageGetter.h104
-rw-r--r--common/rfb/TransferQueue.cxx311
-rw-r--r--common/rfb/TransferQueue.h87
-rw-r--r--common/rfb/TrueColourMap.h42
-rw-r--r--common/rfb/UpdateTracker.cxx156
-rw-r--r--common/rfb/UpdateTracker.h103
-rw-r--r--common/rfb/UserPasswdGetter.h30
-rw-r--r--common/rfb/VNCSConnectionST.cxx714
-rw-r--r--common/rfb/VNCSConnectionST.h176
-rw-r--r--common/rfb/VNCServer.h86
-rw-r--r--common/rfb/VNCServerST.cxx531
-rw-r--r--common/rfb/VNCServerST.h245
-rw-r--r--common/rfb/ZRLEDecoder.cxx91
-rw-r--r--common/rfb/ZRLEDecoder.h37
-rw-r--r--common/rfb/ZRLEEncoder.cxx122
-rw-r--r--common/rfb/ZRLEEncoder.h54
-rw-r--r--common/rfb/d3des.c434
-rw-r--r--common/rfb/d3des.h51
-rw-r--r--common/rfb/encodings.cxx49
-rw-r--r--common/rfb/encodings.h47
-rw-r--r--common/rfb/fttypes.h92
-rw-r--r--common/rfb/hextileConstants.h27
-rw-r--r--common/rfb/hextileDecode.h126
-rw-r--r--common/rfb/hextileEncode.h229
-rw-r--r--common/rfb/hextileEncodeBetter.h352
-rw-r--r--common/rfb/keysymdef.h1595
-rw-r--r--common/rfb/msgTypes.h57
-rw-r--r--common/rfb/rfb.dsp767
-rw-r--r--common/rfb/rreDecode.h64
-rw-r--r--common/rfb/rreEncode.h164
-rw-r--r--common/rfb/secTypes.cxx73
-rw-r--r--common/rfb/secTypes.h54
-rw-r--r--common/rfb/tightDecode.h412
-rw-r--r--common/rfb/tightEncode.h720
-rw-r--r--common/rfb/transInitTempl.h254
-rw-r--r--common/rfb/transTempl.h151
-rw-r--r--common/rfb/util.cxx184
-rw-r--r--common/rfb/util.h111
-rw-r--r--common/rfb/zrleDecode.h251
-rw-r--r--common/rfb/zrleEncode.h328
166 files changed, 22473 insertions, 0 deletions
diff --git a/common/rfb/Blacklist.cxx b/common/rfb/Blacklist.cxx
new file mode 100644
index 00000000..4590befe
--- /dev/null
+++ b/common/rfb/Blacklist.cxx
@@ -0,0 +1,86 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#include <rfb/Blacklist.h>
+#include <rfb/Configuration.h>
+
+using namespace rfb;
+
+IntParameter Blacklist::threshold("BlacklistThreshold",
+ "The number of unauthenticated connection attempts allowed from any "
+ "individual host before that host is black-listed",
+ 5);
+IntParameter Blacklist::initialTimeout("BlacklistTimeout",
+ "The initial timeout applied when a host is first black-listed. "
+ "The host cannot re-attempt a connection until the timeout expires.",
+ 10);
+
+
+Blacklist::Blacklist() {
+}
+
+Blacklist::~Blacklist() {
+ // Free the map keys
+ BlacklistMap::iterator i;
+ for (i=blm.begin(); i!=blm.end(); i++) {
+ strFree((char*)(*i).first);
+ }
+}
+
+bool Blacklist::isBlackmarked(const char* name) {
+ BlacklistMap::iterator i = blm.find(name);
+ if (i == blm.end()) {
+ // Entry is not already black-marked.
+ // Create the entry unmarked, unblocked,
+ // with suitable defaults set.
+ BlacklistInfo bi;
+ bi.marks = 1;
+ bi.blockUntil = 0;
+ bi.blockTimeout = initialTimeout;
+ blm[strDup(name)] = bi;
+ i = blm.find(name);
+ }
+
+ // Entry exists - has it reached the threshold yet?
+ if ((*i).second.marks >= threshold) {
+ // Yes - entry is blocked - has the timeout expired?
+ time_t now = time(0);
+ if (now >= (*i).second.blockUntil) {
+ // Timeout has expired. Reset timeout and allow
+ // a re-try.
+ (*i).second.blockUntil = now + (*i).second.blockTimeout;
+ (*i).second.blockTimeout = (*i).second.blockTimeout * 2;
+ return false;
+ }
+ // Blocked and timeout still in effect - reject!
+ return true;
+ }
+
+ // We haven't reached the threshold yet.
+ // Increment the black-mark counter but allow
+ // the entry to pass.
+ (*i).second.marks++;
+ return false;
+}
+
+void Blacklist::clearBlackmark(const char* name) {
+ BlacklistMap::iterator i = blm.find(name);
+ if (i != blm.end()) {
+ strFree((char*)(*i).first);
+ blm.erase(i);
+ }
+}
diff --git a/common/rfb/Blacklist.h b/common/rfb/Blacklist.h
new file mode 100644
index 00000000..0eb38460
--- /dev/null
+++ b/common/rfb/Blacklist.h
@@ -0,0 +1,91 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+//
+// Blacklist.h - Handling of black-listed entities.
+// Just keeps a table mapping strings to timing information, including
+// how many times the entry has been black-listed and when to next
+// put it on probation (e.g. allow a connection in from the host, and
+// re-blacklist it if that fails).
+//
+
+#ifndef __RFB_BLACKLIST_H__
+#define __RFB_BLACKLIST_H__
+
+#include <string.h>
+#include <time.h>
+#include <map>
+
+#include <rfb/Configuration.h>
+#include <rfb/util.h>
+
+namespace rfb {
+
+ //
+ // -=- Blacklist handler
+ //
+ // Parameters include a threshold after which to blacklist the named
+ // host, and a timeout after which to re-consider them.
+ //
+ // Threshold means that isBlackmarked can be called that number of times
+ // before it will return true.
+ //
+ // Timeout means that after that many seconds, the next call to isBlackmarked
+ // will return false. At the same time, the timeout is doubled, so that the
+ // next calls will fail, until the timeout expires again or clearBlackmark is
+ // called.
+ //
+ // When clearBlackMark is called, the corresponding entry is completely
+ // removed, causing the next isBlackmarked call to return false.
+
+ // KNOWN BUG: Client can keep making rejected requests, thus increasing
+ // their timeout. If client does this for 30 years, timeout may wrap round
+ // to a very small value again.
+
+ // THIS CLASS IS NOT THREAD-SAFE!
+
+ class Blacklist {
+ public:
+ Blacklist();
+ ~Blacklist();
+
+ bool isBlackmarked(const char* name);
+ void clearBlackmark(const char* name);
+
+ static IntParameter threshold;
+ static IntParameter initialTimeout;
+
+ protected:
+ struct ltStr {
+ bool operator()(const char* s1, const char* s2) const {
+ return strcmp(s1, s2) < 0;
+ };
+ };
+ struct BlacklistInfo {
+ int marks;
+ time_t blockUntil;
+ unsigned int blockTimeout;
+ };
+ typedef std::map<const char*,BlacklistInfo,ltStr> BlacklistMap;
+ BlacklistMap blm;
+ };
+
+}
+
+#endif
+
diff --git a/common/rfb/CConnection.cxx b/common/rfb/CConnection.cxx
new file mode 100644
index 00000000..36778f02
--- /dev/null
+++ b/common/rfb/CConnection.cxx
@@ -0,0 +1,276 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <rfb/Exception.h>
+#include <rfb/CMsgReaderV3.h>
+#include <rfb/CMsgWriterV3.h>
+#include <rfb/CSecurity.h>
+#include <rfb/secTypes.h>
+#include <rfb/CConnection.h>
+#include <rfb/util.h>
+
+#include <rfb/LogWriter.h>
+
+using namespace rfb;
+
+static LogWriter vlog("CConnection");
+
+CConnection::CConnection()
+ : is(0), os(0), reader_(0), writer_(0),
+ shared(false), security(0), nSecTypes(0), clientSecTypeOrder(false),
+ state_(RFBSTATE_UNINITIALISED), useProtocol3_3(false)
+{
+}
+
+CConnection::~CConnection()
+{
+ if (security) security->destroy();
+ deleteReaderAndWriter();
+}
+
+void CConnection::deleteReaderAndWriter()
+{
+ delete reader_;
+ reader_ = 0;
+ delete writer_;
+ writer_ = 0;
+}
+
+void CConnection::setStreams(rdr::InStream* is_, rdr::OutStream* os_)
+{
+ is = is_;
+ os = os_;
+}
+
+void CConnection::addSecType(rdr::U8 secType)
+{
+ if (nSecTypes == maxSecTypes)
+ throw Exception("too many security types");
+ secTypes[nSecTypes++] = secType;
+}
+
+void CConnection::setClientSecTypeOrder(bool clientOrder) {
+ clientSecTypeOrder = clientOrder;
+}
+
+void CConnection::initialiseProtocol()
+{
+ state_ = RFBSTATE_PROTOCOL_VERSION;
+}
+
+void CConnection::processMsg()
+{
+ switch (state_) {
+
+ case RFBSTATE_PROTOCOL_VERSION: processVersionMsg(); break;
+ case RFBSTATE_SECURITY_TYPES: processSecurityTypesMsg(); break;
+ case RFBSTATE_SECURITY: processSecurityMsg(); break;
+ case RFBSTATE_SECURITY_RESULT: processSecurityResultMsg(); break;
+ case RFBSTATE_INITIALISATION: processInitMsg(); break;
+ case RFBSTATE_NORMAL: reader_->readMsg(); break;
+ case RFBSTATE_UNINITIALISED:
+ throw Exception("CConnection::processMsg: not initialised yet?");
+ default:
+ throw Exception("CConnection::processMsg: invalid state");
+ }
+}
+
+void CConnection::processVersionMsg()
+{
+ vlog.debug("reading protocol version");
+ bool done;
+ if (!cp.readVersion(is, &done)) {
+ state_ = RFBSTATE_INVALID;
+ throw Exception("reading version failed: not an RFB server?");
+ }
+ if (!done) return;
+
+ vlog.info("Server supports RFB protocol version %d.%d",
+ cp.majorVersion, cp.minorVersion);
+
+ // The only official RFB protocol versions are currently 3.3, 3.7 and 3.8
+ if (cp.beforeVersion(3,3)) {
+ char msg[256];
+ sprintf(msg,"Server gave unsupported RFB protocol version %d.%d",
+ cp.majorVersion, cp.minorVersion);
+ vlog.error(msg);
+ state_ = RFBSTATE_INVALID;
+ throw Exception(msg);
+ } else if (useProtocol3_3 || cp.beforeVersion(3,7)) {
+ cp.setVersion(3,3);
+ } else if (cp.afterVersion(3,8)) {
+ cp.setVersion(3,8);
+ }
+
+ cp.writeVersion(os);
+ state_ = RFBSTATE_SECURITY_TYPES;
+
+ vlog.info("Using RFB protocol version %d.%d",
+ cp.majorVersion, cp.minorVersion);
+}
+
+
+void CConnection::processSecurityTypesMsg()
+{
+ vlog.debug("processing security types message");
+
+ int secType = secTypeInvalid;
+
+ if (cp.isVersion(3,3)) {
+
+ // legacy 3.3 server may only offer "vnc authentication" or "none"
+
+ secType = is->readU32();
+ if (secType == secTypeInvalid) {
+ throwConnFailedException();
+
+ } else if (secType == secTypeNone || secType == secTypeVncAuth) {
+ int j;
+ for (j = 0; j < nSecTypes; j++)
+ if (secTypes[j] == secType) break;
+ if (j == nSecTypes)
+ secType = secTypeInvalid;
+ } else {
+ vlog.error("Unknown 3.3 security type %d", secType);
+ throw Exception("Unknown 3.3 security type");
+ }
+
+ } else {
+
+ // >=3.7 server will offer us a list
+
+ int nServerSecTypes = is->readU8();
+ if (nServerSecTypes == 0)
+ throwConnFailedException();
+
+ int secTypePos = nSecTypes;
+ for (int i = 0; i < nServerSecTypes; i++) {
+ rdr::U8 serverSecType = is->readU8();
+ vlog.debug("Server offers security type %s(%d)",
+ secTypeName(serverSecType),serverSecType);
+
+ // If we haven't already chosen a secType, try this one
+ // If we are using the client's preference for types,
+ // we keep trying types, to find the one that matches and
+ // which appears first in the client's list of supported types.
+ if (secType == secTypeInvalid || clientSecTypeOrder) {
+ for (int j = 0; j < nSecTypes; j++) {
+ if (secTypes[j] == serverSecType && j < secTypePos) {
+ secType = secTypes[j];
+ secTypePos = j;
+ break;
+ }
+ }
+ // NB: Continue reading the remaining server secTypes, but ignore them
+ }
+ }
+
+ // Inform the server of our decision
+ if (secType != secTypeInvalid) {
+ os->writeU8(secType);
+ os->flush();
+ vlog.debug("Choosing security type %s(%d)",secTypeName(secType),secType);
+ }
+ }
+
+ if (secType == secTypeInvalid) {
+ state_ = RFBSTATE_INVALID;
+ vlog.error("No matching security types");
+ throw Exception("No matching security types");
+ }
+
+ state_ = RFBSTATE_SECURITY;
+ security = getCSecurity(secType);
+ processSecurityMsg();
+}
+
+void CConnection::processSecurityMsg()
+{
+ vlog.debug("processing security message");
+ if (security->processMsg(this)) {
+ state_ = RFBSTATE_SECURITY_RESULT;
+ processSecurityResultMsg();
+ }
+}
+
+void CConnection::processSecurityResultMsg()
+{
+ vlog.debug("processing security result message");
+ int result;
+ if (cp.beforeVersion(3,8) && security->getType() == secTypeNone) {
+ result = secResultOK;
+ } else {
+ if (!is->checkNoWait(1)) return;
+ result = is->readU32();
+ }
+ switch (result) {
+ case secResultOK:
+ securityCompleted();
+ return;
+ case secResultFailed:
+ vlog.debug("auth failed");
+ break;
+ case secResultTooMany:
+ vlog.debug("auth failed - too many tries");
+ break;
+ default:
+ throw Exception("Unknown security result from server");
+ }
+ CharArray reason;
+ if (cp.beforeVersion(3,8))
+ reason.buf = strDup("Authentication failure");
+ else
+ reason.buf = is->readString();
+ state_ = RFBSTATE_INVALID;
+ throw AuthFailureException(reason.buf);
+}
+
+void CConnection::processInitMsg()
+{
+ vlog.debug("reading server initialisation");
+ reader_->readServerInit();
+}
+
+void CConnection::throwConnFailedException()
+{
+ state_ = RFBSTATE_INVALID;
+ CharArray reason;
+ reason.buf = is->readString();
+ throw ConnFailedException(reason.buf);
+}
+
+void CConnection::securityCompleted()
+{
+ state_ = RFBSTATE_INITIALISATION;
+ reader_ = new CMsgReaderV3(this, is);
+ writer_ = new CMsgWriterV3(&cp, os);
+ vlog.debug("Authentication success!");
+ authSuccess();
+ writer_->writeClientInit(shared);
+}
+
+void CConnection::authSuccess()
+{
+}
+
+void CConnection::serverInit()
+{
+ state_ = RFBSTATE_NORMAL;
+ vlog.debug("initialisation done");
+}
diff --git a/common/rfb/CConnection.h b/common/rfb/CConnection.h
new file mode 100644
index 00000000..79110eb9
--- /dev/null
+++ b/common/rfb/CConnection.h
@@ -0,0 +1,183 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+//
+// CConnection - class on the client side representing a connection to a
+// server. A derived class should override methods appropriately.
+//
+
+#ifndef __RFB_CCONNECTION_H__
+#define __RFB_CCONNECTION_H__
+
+#include <rdr/InStream.h>
+#include <rdr/OutStream.h>
+#include <rfb/CMsgHandler.h>
+#include <rfb/util.h>
+
+namespace rfb {
+
+ class CMsgReader;
+ class CMsgWriter;
+ class CSecurity;
+ class IdentityVerifier;
+
+ class CConnection : public CMsgHandler {
+ public:
+
+ CConnection();
+ virtual ~CConnection();
+
+ // Methods to initialise the connection
+
+ // setServerName() is used to provide a unique(ish) name for the server to
+ // which we are connected. This might be the result of getPeerEndpoint on
+ // a TcpSocket, for example, or a host specified by DNS name & port.
+ // The serverName is used when verifying the Identity of a host (see RA2).
+ void setServerName(const char* name_) { serverName.replaceBuf(strDup(name_)); }
+
+ // setStreams() sets the streams to be used for the connection. These must
+ // be set before initialiseProtocol() and processMsg() are called. The
+ // CSecurity object may call setStreams() again to provide alternative
+ // streams over which the RFB protocol is sent (i.e. encrypting/decrypting
+ // streams). Ownership of the streams remains with the caller
+ // (i.e. SConnection will not delete them).
+ void setStreams(rdr::InStream* is, rdr::OutStream* os);
+
+ // addSecType() should be called once for each security type which the
+ // client supports. The order in which they're added is such that the
+ // first one is most preferred.
+ void addSecType(rdr::U8 secType);
+
+ // setClientSecTypeOrder() determines whether the client should obey
+ // the server's security type preference, by picking the first server security
+ // type that the client supports, or whether it should pick the first type
+ // that the server supports, from the client-supported list of types.
+ void setClientSecTypeOrder(bool clientOrder);
+
+ // setShared sets the value of the shared flag which will be sent to the
+ // server upon initialisation.
+ void setShared(bool s) { shared = s; }
+
+ // setProtocol3_3 configures whether or not the CConnection should
+ // only ever support protocol version 3.3
+ void setProtocol3_3(bool s) {useProtocol3_3 = s;}
+
+ // initialiseProtocol() should be called once the streams and security
+ // types are set. Subsequently, processMsg() should be called whenever
+ // there is data to read on the InStream.
+ void initialiseProtocol();
+
+ // processMsg() should be called whenever there is either:
+ // - data available on the underlying network stream
+ // In this case, processMsg may return without processing an RFB message,
+ // if the available data does not result in an RFB message being ready
+ // to handle. e.g. if data is encrypted.
+ // NB: This makes it safe to call processMsg() in response to select()
+ // - data available on the CConnection's current InStream
+ // In this case, processMsg should always process the available RFB
+ // message before returning.
+ // NB: In either case, you must have called initialiseProtocol() first.
+ void processMsg();
+
+
+ // Methods to be overridden in a derived class
+
+ // getCSecurity() gets the CSecurity object for the given type. The type
+ // is guaranteed to be one of the secTypes passed in to addSecType(). The
+ // CSecurity object's destroy() method will be called by the CConnection
+ // from its destructor.
+ virtual CSecurity* getCSecurity(int secType)=0;
+
+ // getCurrentCSecurity() gets the CSecurity instance used for this connection.
+ const CSecurity* getCurrentCSecurity() const {return security;}
+
+ // getIdVerifier() returns the identity verifier associated with the connection.
+ // Ownership of the IdentityVerifier is retained by the CConnection instance.
+ virtual IdentityVerifier* getIdentityVerifier() {return 0;}
+
+ // authSuccess() is called when authentication has succeeded.
+ virtual void authSuccess();
+
+ // serverInit() is called when the ServerInit message is received. The
+ // derived class must call on to CConnection::serverInit().
+ virtual void serverInit();
+
+
+ // Other methods
+
+ // deleteReaderAndWriter() deletes the reader and writer associated with
+ // this connection. This may be useful if you want to delete the streams
+ // before deleting the SConnection to make sure that no attempt by the
+ // SConnection is made to read or write.
+ // XXX Do we really need this at all???
+ void deleteReaderAndWriter();
+
+ CMsgReader* reader() { return reader_; }
+ CMsgWriter* writer() { return writer_; }
+
+ rdr::InStream* getInStream() { return is; }
+ rdr::OutStream* getOutStream() { return os; }
+
+ // Access method used by SSecurity implementations that can verify servers'
+ // Identities, to determine the unique(ish) name of the server.
+ const char* getServerName() const { return serverName.buf; }
+
+ enum stateEnum {
+ RFBSTATE_UNINITIALISED,
+ RFBSTATE_PROTOCOL_VERSION,
+ RFBSTATE_SECURITY_TYPES,
+ RFBSTATE_SECURITY,
+ RFBSTATE_SECURITY_RESULT,
+ RFBSTATE_INITIALISATION,
+ RFBSTATE_NORMAL,
+ RFBSTATE_INVALID
+ };
+
+ stateEnum state() { return state_; }
+
+ protected:
+ void setState(stateEnum s) { state_ = s; }
+
+ private:
+ void processVersionMsg();
+ void processSecurityTypesMsg();
+ void processSecurityMsg();
+ void processSecurityResultMsg();
+ void processInitMsg();
+ void throwAuthFailureException();
+ void throwConnFailedException();
+ void securityCompleted();
+
+ rdr::InStream* is;
+ rdr::OutStream* os;
+ CMsgReader* reader_;
+ CMsgWriter* writer_;
+ bool deleteStreamsWhenDone;
+ bool shared;
+ CSecurity* security;
+ enum { maxSecTypes = 8 };
+ int nSecTypes;
+ rdr::U8 secTypes[maxSecTypes];
+ bool clientSecTypeOrder;
+ stateEnum state_;
+
+ CharArray serverName;
+
+ bool useProtocol3_3;
+ };
+}
+#endif
diff --git a/common/rfb/CFTMsgReader.cxx b/common/rfb/CFTMsgReader.cxx
new file mode 100644
index 00000000..5a17fc25
--- /dev/null
+++ b/common/rfb/CFTMsgReader.cxx
@@ -0,0 +1,162 @@
+/* Copyright (C) 2005 TightVNC Team. All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- CFTMsgReader.cxx
+
+#include <rfb/CFTMsgReader.h>
+
+using namespace rfb;
+
+CFTMsgReader::CFTMsgReader(rdr::InStream *pIS)
+{
+ m_pInStream = pIS;
+}
+
+CFTMsgReader::~CFTMsgReader()
+{
+
+}
+
+int
+CFTMsgReader::readFileListData(FileInfo *pFileInfo)
+{
+ unsigned char flags = m_pInStream->readU8();
+ int numFiles = m_pInStream->readU16();
+ int dataSize = m_pInStream->readU16();
+ int compressedSize = m_pInStream->readU16();
+
+ if (flags & 0x80) {
+ return -1;
+ } else {
+ if (numFiles > 0) {
+ char *pFilenames = new char[compressedSize];
+ SIZEDATAINFO *pSDI = new SIZEDATAINFO[numFiles];
+ for (int i = 0; i < numFiles; i++) {
+ pSDI[i].size = m_pInStream->readU32();
+ pSDI[i].data = m_pInStream->readU32();
+ }
+ m_pInStream->readBytes((void *)pFilenames, compressedSize);
+ createFileInfo(numFiles, pFileInfo, pSDI, pFilenames);
+ delete [] pSDI;
+ delete [] pFilenames;
+ }
+ }
+ return numFiles;
+}
+
+void *
+CFTMsgReader::readFileDownloadData(unsigned int *pSize, unsigned int *pModTime)
+{
+ unsigned char compressLevel = m_pInStream->readU8();
+ int realSize = m_pInStream->readU16();
+ int compressedSize = m_pInStream->readU16();
+
+ if ((realSize == 0) && (compressedSize == 0)) {
+ *pSize = 0;
+ *pModTime = m_pInStream->readU32();
+ return NULL;
+ } else {
+ char *pFile = new char [compressedSize];
+ if (pFile == NULL) {
+ m_pInStream->skip(compressedSize);
+ *pModTime = 0;
+ return NULL;
+ } else {
+ m_pInStream->readBytes(pFile, compressedSize);
+ *pSize = compressedSize;
+ return pFile;
+ }
+ }
+}
+
+char *
+CFTMsgReader::readFileUploadCancel(unsigned int *pReasonSize)
+{
+ m_pInStream->skip(1);
+ return readReasonMsg(pReasonSize);
+}
+
+char *
+CFTMsgReader::readFileDownloadFailed(unsigned int *pReasonSize)
+{
+ m_pInStream->skip(1);
+ return readReasonMsg(pReasonSize);
+}
+
+int
+CFTMsgReader::readFileDirSizeData(unsigned short *pDirSizeLow16,
+ unsigned int *pDirSizeHigh32)
+{
+ m_pInStream->skip(1);
+ *pDirSizeLow16 = m_pInStream->readU16();
+ *pDirSizeHigh32 = m_pInStream->readU32();
+ return 1;
+}
+
+char *
+CFTMsgReader::readFileLastRqstFailed(int *pTypeOfRequest, unsigned int *pReasonSize)
+{
+ *pTypeOfRequest = m_pInStream->readU8();
+ return readReasonMsg(pReasonSize);
+}
+
+bool
+CFTMsgReader::createFileInfo(unsigned int numFiles, FileInfo *fi,
+ SIZEDATAINFO *pSDInfo, char *pFilenames)
+{
+ int pos = 0;
+ int size = 0;
+ for (unsigned int i = 0; i < numFiles; i++) {
+ size = pSDInfo[i].size;
+ if (size == FT_NET_ATTR_DIR) {
+ fi->add((pFilenames + pos), size, pSDInfo[i].data, FT_ATTR_DIR);
+ } else {
+ fi->add((pFilenames + pos), size, pSDInfo[i].data, FT_ATTR_FILE);
+ }
+ pos += strlen(pFilenames + pos) + 1;
+ }
+ return true;
+}
+
+char *
+CFTMsgReader::readReasonMsg(unsigned int *pReasonSize)
+{
+ int reasonLen = m_pInStream->readU16();
+ int _reasonLen = reasonLen + 1;
+ char *pReason;
+ if (reasonLen == 0) {
+ *pReasonSize = 0;
+ return NULL;
+ } else {
+ pReason = new char [_reasonLen];
+ if (pReason == NULL) {
+ m_pInStream->skip(reasonLen);
+ *pReasonSize = 0;
+ return NULL;
+ }
+ m_pInStream->readBytes(pReason, reasonLen);
+ memset(((char *)pReason+reasonLen), '\0', 1);
+ return pReason;
+ }
+}
+
diff --git a/common/rfb/CFTMsgReader.h b/common/rfb/CFTMsgReader.h
new file mode 100644
index 00000000..aece3e78
--- /dev/null
+++ b/common/rfb/CFTMsgReader.h
@@ -0,0 +1,56 @@
+/* Copyright (C) 2005 TightVNC Team. All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- CFTMsgReader.h
+
+#ifndef __RFB_CFTMSGREADER_H__
+#define __RFB_CFTMSGREADER_H__
+
+#include <rdr/InStream.h>
+#include <rfb/FileInfo.h>
+
+namespace rfb {
+ class CFTMsgReader
+ {
+ public:
+ CFTMsgReader(rdr::InStream *pIS);
+ ~CFTMsgReader();
+
+ int readFileListData(FileInfo *pFileInfo);
+ int readFileDirSizeData(unsigned short *pDirSizeLow16, unsigned int *pDirSizeHigh32);
+
+ char *readFileUploadCancel(unsigned int *pReasonSize);
+ char *readFileDownloadFailed(unsigned int *pReasonSize);
+ char *readFileLastRqstFailed(int *pTypeOfRequest, unsigned int *pReasonSize);
+ void *readFileDownloadData(unsigned int *pSize, unsigned int *pModTime);
+
+ private:
+ rdr::InStream *m_pInStream;
+
+ bool createFileInfo(unsigned int numFiles, FileInfo *fi,
+ SIZEDATAINFO *pSDInfo, char *pFilenames);
+ char *readReasonMsg(unsigned int *pReasonSize);
+ };
+}
+
+#endif // __RFB_CFTMSGREADER_H__
diff --git a/common/rfb/CFTMsgWriter.cxx b/common/rfb/CFTMsgWriter.cxx
new file mode 100644
index 00000000..5e6854ed
--- /dev/null
+++ b/common/rfb/CFTMsgWriter.cxx
@@ -0,0 +1,182 @@
+/* Copyright (C) 2005 TightVNC Team. All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- CFTMsgWriter.cxx
+
+#include <rfb/CFTMsgWriter.h>
+
+using namespace rfb;
+
+CFTMsgWriter::CFTMsgWriter(rdr::OutStream *pOS)
+{
+ m_pOutStream = pOS;
+}
+
+CFTMsgWriter::~CFTMsgWriter()
+{
+}
+
+bool
+CFTMsgWriter::writeFileListRqst(unsigned short dirnameLen, char *pDirName,
+ bool bDirOnly)
+{
+ if (dirnameLen >= FT_FILENAME_SIZE) return false;
+
+ unsigned char flags = 0;
+ if (bDirOnly) flags = 0x10;
+
+ m_pOutStream->writeU8(msgTypeFileListRequest);
+ m_pOutStream->writeU8(flags);
+ m_pOutStream->writeU16(dirnameLen);
+ m_pOutStream->writeBytes((void *)pDirName, dirnameLen);
+ m_pOutStream->flush();
+
+ return true;
+}
+
+
+bool
+CFTMsgWriter::writeFileDownloadCancel(unsigned short reasonLen, char *pReason)
+{
+ m_pOutStream->writeU8(msgTypeFileDownloadCancel);
+ return writeU8U16StringMsg(reasonLen, pReason);
+}
+
+bool
+CFTMsgWriter::writeFileDownloadRqst(unsigned short filenameLen, char *pFilename,
+ unsigned int position)
+{
+ if (filenameLen >= FT_FILENAME_SIZE) return false;
+
+ m_pOutStream->writeU8(msgTypeFileDownloadRequest);
+ m_pOutStream->writeU8(0);
+ m_pOutStream->writeU16(filenameLen);
+ m_pOutStream->writeU32(position);
+ m_pOutStream->writeBytes(pFilename, filenameLen);
+ m_pOutStream->flush();
+
+ return true;
+}
+
+bool
+CFTMsgWriter::writeFileUploadData(unsigned short dataSize, char *pData)
+{
+ m_pOutStream->writeU8(msgTypeFileUploadData);
+ m_pOutStream->writeU8(0);
+ m_pOutStream->writeU16(dataSize);
+ m_pOutStream->writeU16(dataSize);
+ m_pOutStream->writeBytes(pData, dataSize);
+ m_pOutStream->flush();
+
+ return true;
+}
+
+bool
+CFTMsgWriter::writeFileUploadData(unsigned int modTime)
+{
+ m_pOutStream->writeU8(msgTypeFileUploadData);
+ m_pOutStream->writeU8(0);
+ m_pOutStream->writeU16(0);
+ m_pOutStream->writeU16(0);
+ m_pOutStream->writeU32(modTime);
+ m_pOutStream->flush();
+
+ return true;
+}
+
+bool
+CFTMsgWriter::writeFileUploadFailed(unsigned short reasonLen, char *pReason)
+{
+ m_pOutStream->writeU8(msgTypeFileUploadFailed);
+ return writeU8U16StringMsg(reasonLen, pReason);
+}
+
+bool
+CFTMsgWriter::writeFileUploadRqst(unsigned short filenameLen, char *pFilename,
+ unsigned int position)
+{
+ if (filenameLen >= FT_FILENAME_SIZE) return false;
+
+ m_pOutStream->writeU8(msgTypeFileUploadRequest);
+ m_pOutStream->writeU8(0);
+ m_pOutStream->writeU16(filenameLen);
+ m_pOutStream->writeU32(position);
+ m_pOutStream->writeBytes((void *)pFilename, filenameLen);
+ m_pOutStream->flush();
+
+ return true;
+}
+
+bool
+CFTMsgWriter::writeFileCreateDirRqst(unsigned short dirNameLen, char *pDirName)
+{
+ if (dirNameLen >= FT_FILENAME_SIZE) return false;
+
+ m_pOutStream->writeU8(msgTypeFileCreateDirRequest);
+ return writeU8U16StringMsg(dirNameLen, pDirName);
+}
+
+bool
+CFTMsgWriter::writeFileDirSizeRqst(unsigned short dirNameLen, char *pDirName)
+{
+ if (dirNameLen >= FT_FILENAME_SIZE) return false;
+
+ m_pOutStream->writeU8(msgTypeFileDirSizeRequest);
+ return writeU8U16StringMsg(dirNameLen, pDirName);
+}
+
+bool
+CFTMsgWriter::writeFileRenameRqst(unsigned short oldNameLen, unsigned short newNameLen,
+ char *pOldName, char *pNewName)
+{
+ if ((oldNameLen >= FT_FILENAME_SIZE) || (newNameLen >= FT_FILENAME_SIZE)) return false;
+
+ m_pOutStream->writeU8(msgTypeFileRenameRequest);
+ m_pOutStream->writeU8(0);
+ m_pOutStream->writeU16(oldNameLen);
+ m_pOutStream->writeU16(newNameLen);
+ m_pOutStream->writeBytes(pOldName, oldNameLen);
+ m_pOutStream->writeBytes(pNewName, newNameLen);
+ m_pOutStream->flush();
+
+ return true;
+}
+
+bool
+CFTMsgWriter::writeFileDeleteRqst(unsigned short nameLen, char *pName)
+{
+ if (nameLen >= FT_FILENAME_SIZE) return false;
+
+ m_pOutStream->writeU8(msgTypeFileDeleteRequest);
+ return writeU8U16StringMsg(nameLen, pName);
+}
+
+bool
+CFTMsgWriter::writeU8U16StringMsg(unsigned short strLength, char *pString)
+{
+ m_pOutStream->writeU8(0);
+ m_pOutStream->writeU16(strLength);
+ m_pOutStream->writeBytes(pString, strLength);
+ m_pOutStream->flush();
+ return true;
+}
diff --git a/common/rfb/CFTMsgWriter.h b/common/rfb/CFTMsgWriter.h
new file mode 100644
index 00000000..e4cdc0bd
--- /dev/null
+++ b/common/rfb/CFTMsgWriter.h
@@ -0,0 +1,67 @@
+/* Copyright (C) 2005 TightVNC Team. All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- CFTMsgWriter.h
+
+#ifndef __RFB_CFTMSGWRITER_H__
+#define __RFB_CFTMSGWRITER_H__
+
+#include <rdr/types.h>
+#include <rdr/OutStream.h>
+#include <rfb/msgTypes.h>
+#include <rfb/fttypes.h>
+
+namespace rfb {
+ class CFTMsgWriter
+ {
+ public:
+ CFTMsgWriter(rdr::OutStream *pOS);
+ ~CFTMsgWriter();
+
+ bool writeFileListRqst(unsigned short dirnameLen, char *pDirName, bool bDirOnly);
+
+ bool writeFileDownloadCancel(unsigned short reasonLen, char *pReason);
+ bool writeFileDownloadRqst(unsigned short filenameLen, char *pFilename,
+ unsigned int position);
+
+ bool writeFileUploadData(unsigned short dataSize, char *pData);
+ bool writeFileUploadData(unsigned int modTime);
+ bool writeFileUploadFailed(unsigned short reasonLen, char *pReason);
+ bool writeFileUploadRqst(unsigned short filenameLen, char *pFilename,
+ unsigned int position);
+
+ bool writeFileCreateDirRqst(unsigned short dirNameLen, char *pDirName);
+ bool writeFileDirSizeRqst(unsigned short dirNameLen, char *pDirName);
+
+ bool writeFileRenameRqst(unsigned short oldNameLen, unsigned short newNameLen,
+ char *pOldName, char *pNewName);
+ bool writeFileDeleteRqst(unsigned short nameLen, char *pName);
+
+ private:
+ rdr::OutStream *m_pOutStream;
+
+ bool writeU8U16StringMsg(unsigned short strLength, char *pString);
+ };
+}
+
+#endif // __RFB_CFTMSGWRITER_H__
diff --git a/common/rfb/CMsgHandler.cxx b/common/rfb/CMsgHandler.cxx
new file mode 100644
index 00000000..bbc11763
--- /dev/null
+++ b/common/rfb/CMsgHandler.cxx
@@ -0,0 +1,103 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#include <rfb/Exception.h>
+#include <rfb/CMsgHandler.h>
+
+using namespace rfb;
+
+CMsgHandler::CMsgHandler()
+{
+}
+
+CMsgHandler::~CMsgHandler()
+{
+}
+
+void CMsgHandler::setDesktopSize(int width, int height)
+{
+ cp.width = width;
+ cp.height = height;
+}
+
+void CMsgHandler::setCursor(int w, int h, const Point& hotspot, void* data, void* mask)
+{
+}
+
+void CMsgHandler::setPixelFormat(const PixelFormat& pf)
+{
+ cp.setPF(pf);
+}
+
+void CMsgHandler::setName(const char* name)
+{
+ cp.setName(name);
+}
+
+void CMsgHandler::serverInit()
+{
+ throw Exception("CMsgHandler::serverInit called");
+}
+
+void CMsgHandler::framebufferUpdateStart()
+{
+}
+
+void CMsgHandler::framebufferUpdateEnd()
+{
+}
+
+void CMsgHandler::beginRect(const Rect& r, unsigned int encoding)
+{
+}
+
+void CMsgHandler::endRect(const Rect& r, unsigned int encoding)
+{
+}
+
+
+void CMsgHandler::setColourMapEntries(int firstColour, int nColours,
+ rdr::U16* rgbs)
+{
+ throw Exception("CMsgHandler::setColourMapEntries called");
+}
+
+void CMsgHandler::bell()
+{
+}
+
+void CMsgHandler::serverCutText(const char* str, int len)
+{
+}
+
+void CMsgHandler::fillRect(const Rect& r, Pixel pix)
+{
+}
+
+void CMsgHandler::imageRect(const Rect& r, void* pixels)
+{
+}
+
+void CMsgHandler::copyRect(const Rect& r, int srcX, int srcY)
+{
+}
+
+bool CMsgHandler::processFTMsg(int type)
+{
+ return false;
+}
+
diff --git a/common/rfb/CMsgHandler.h b/common/rfb/CMsgHandler.h
new file mode 100644
index 00000000..6c86df01
--- /dev/null
+++ b/common/rfb/CMsgHandler.h
@@ -0,0 +1,71 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+//
+// CMsgHandler - class to handle incoming messages on the client side.
+//
+
+#ifndef __RFB_CMSGHANDLER_H__
+#define __RFB_CMSGHANDLER_H__
+
+#include <rdr/types.h>
+#include <rfb/Pixel.h>
+#include <rfb/ConnParams.h>
+#include <rfb/Rect.h>
+
+namespace rdr { class InStream; }
+
+namespace rfb {
+
+ class CMsgHandler {
+ public:
+ CMsgHandler();
+ virtual ~CMsgHandler();
+
+ // The following methods are called as corresponding messages are read. A
+ // derived class should override these methods as desired. Note that for
+ // the setDesktopSize(), setPixelFormat() and setName() methods, a derived
+ // class should call on to CMsgHandler's methods to set the members of cp
+ // appropriately.
+
+ virtual void setDesktopSize(int w, int h);
+ virtual void setCursor(int width, int height, const Point& hotspot,
+ void* data, void* mask);
+ virtual void setPixelFormat(const PixelFormat& pf);
+ virtual void setName(const char* name);
+ virtual void serverInit();
+
+ virtual void framebufferUpdateStart();
+ virtual void framebufferUpdateEnd();
+ virtual void beginRect(const Rect& r, unsigned int encoding);
+ virtual void endRect(const Rect& r, unsigned int encoding);
+
+ virtual void setColourMapEntries(int firstColour, int nColours,
+ rdr::U16* rgbs);
+ virtual void bell();
+ virtual void serverCutText(const char* str, int len);
+
+ virtual void fillRect(const Rect& r, Pixel pix);
+ virtual void imageRect(const Rect& r, void* pixels);
+ virtual void copyRect(const Rect& r, int srcX, int srcY);
+
+ virtual bool processFTMsg(int type);
+
+ ConnParams cp;
+ };
+}
+#endif
diff --git a/common/rfb/CMsgReader.cxx b/common/rfb/CMsgReader.cxx
new file mode 100644
index 00000000..38547c0f
--- /dev/null
+++ b/common/rfb/CMsgReader.cxx
@@ -0,0 +1,158 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#include <stdio.h>
+#include <rdr/InStream.h>
+#include <rfb/Exception.h>
+#include <rfb/util.h>
+#include <rfb/CMsgHandler.h>
+#include <rfb/CMsgReader.h>
+
+using namespace rfb;
+
+CMsgReader::CMsgReader(CMsgHandler* handler_, rdr::InStream* is_)
+ : imageBufIdealSize(0), handler(handler_), is(is_),
+ imageBuf(0), imageBufSize(0)
+{
+ for (unsigned int i = 0; i <= encodingMax; i++) {
+ decoders[i] = 0;
+ }
+}
+
+CMsgReader::~CMsgReader()
+{
+ for (unsigned int i = 0; i <= encodingMax; i++) {
+ delete decoders[i];
+ }
+ delete [] imageBuf;
+}
+
+void CMsgReader::readSetColourMapEntries()
+{
+ is->skip(1);
+ int firstColour = is->readU16();
+ int nColours = is->readU16();
+ rdr::U16Array rgbs(nColours * 3);
+ for (int i = 0; i < nColours * 3; i++)
+ rgbs.buf[i] = is->readU16();
+ handler->setColourMapEntries(firstColour, nColours, rgbs.buf);
+}
+
+void CMsgReader::readBell()
+{
+ handler->bell();
+}
+
+void CMsgReader::readServerCutText()
+{
+ is->skip(3);
+ int len = is->readU32();
+ if (len > 256*1024) {
+ is->skip(len);
+ fprintf(stderr,"cut text too long (%d bytes) - ignoring\n",len);
+ return;
+ }
+ CharArray ca(len+1);
+ ca.buf[len] = 0;
+ is->readBytes(ca.buf, len);
+ handler->serverCutText(ca.buf, len);
+}
+
+void CMsgReader::readFramebufferUpdateStart()
+{
+ handler->framebufferUpdateStart();
+}
+
+void CMsgReader::readFramebufferUpdateEnd()
+{
+ handler->framebufferUpdateEnd();
+}
+
+void CMsgReader::readRect(const Rect& r, unsigned int encoding)
+{
+ if ((r.br.x > handler->cp.width) || (r.br.y > handler->cp.height)) {
+ fprintf(stderr, "Rect too big: %dx%d at %d,%d exceeds %dx%d\n",
+ r.width(), r.height(), r.tl.x, r.tl.y,
+ handler->cp.width, handler->cp.height);
+ throw Exception("Rect too big");
+ }
+
+ if (r.is_empty())
+ fprintf(stderr, "Warning: zero size rect\n");
+
+ handler->beginRect(r, encoding);
+
+ if (encoding == encodingCopyRect) {
+ readCopyRect(r);
+ } else {
+ if (!decoders[encoding]) {
+ decoders[encoding] = Decoder::createDecoder(encoding, this);
+ if (!decoders[encoding]) {
+ fprintf(stderr, "Unknown rect encoding %d\n", encoding);
+ throw Exception("Unknown rect encoding");
+ }
+ }
+ decoders[encoding]->readRect(r, handler);
+ }
+
+ handler->endRect(r, encoding);
+}
+
+void CMsgReader::readCopyRect(const Rect& r)
+{
+ int srcX = is->readU16();
+ int srcY = is->readU16();
+ handler->copyRect(r, srcX, srcY);
+}
+
+void CMsgReader::readSetCursor(int width, int height, const Point& hotspot)
+{
+ int data_len = width * height * (handler->cp.pf().bpp/8);
+ int mask_len = ((width+7)/8) * height;
+ rdr::U8Array data(data_len);
+ rdr::U8Array mask(mask_len);
+
+ is->readBytes(data.buf, data_len);
+ is->readBytes(mask.buf, mask_len);
+
+ handler->setCursor(width, height, hotspot, data.buf, mask.buf);
+}
+
+rdr::U8* CMsgReader::getImageBuf(int required, int requested, int* nPixels)
+{
+ int requiredBytes = required * (handler->cp.pf().bpp / 8);
+ int requestedBytes = requested * (handler->cp.pf().bpp / 8);
+ int size = requestedBytes;
+ if (size > imageBufIdealSize) size = imageBufIdealSize;
+
+ if (size < requiredBytes)
+ size = requiredBytes;
+
+ if (imageBufSize < size) {
+ imageBufSize = size;
+ delete [] imageBuf;
+ imageBuf = new rdr::U8[imageBufSize];
+ }
+ if (nPixels)
+ *nPixels = imageBufSize / (handler->cp.pf().bpp / 8);
+ return imageBuf;
+}
+
+int CMsgReader::bpp()
+{
+ return handler->cp.pf().bpp;
+}
diff --git a/common/rfb/CMsgReader.h b/common/rfb/CMsgReader.h
new file mode 100644
index 00000000..7a611fc8
--- /dev/null
+++ b/common/rfb/CMsgReader.h
@@ -0,0 +1,73 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+//
+// CMsgReader - class for reading RFB messages on the server side
+// (i.e. messages from client to server).
+//
+
+#ifndef __RFB_CMSGREADER_H__
+#define __RFB_CMSGREADER_H__
+
+#include <rdr/types.h>
+#include <rfb/encodings.h>
+#include <rfb/Decoder.h>
+
+namespace rdr { class InStream; }
+
+namespace rfb {
+ class CMsgHandler;
+ struct Rect;
+
+ class CMsgReader {
+ public:
+ virtual ~CMsgReader();
+
+ virtual void readServerInit()=0;
+
+ // readMsg() reads a message, calling the handler as appropriate.
+ virtual void readMsg()=0;
+
+ rdr::InStream* getInStream() { return is; }
+ rdr::U8* getImageBuf(int required, int requested=0, int* nPixels=0);
+ int bpp();
+
+ int imageBufIdealSize;
+
+ protected:
+ virtual void readSetColourMapEntries();
+ virtual void readBell();
+ virtual void readServerCutText();
+
+ virtual void readFramebufferUpdateStart();
+ virtual void readFramebufferUpdateEnd();
+ virtual void readRect(const Rect& r, unsigned int encoding);
+
+ virtual void readCopyRect(const Rect& r);
+
+ virtual void readSetCursor(int width, int height, const Point& hotspot);
+
+ CMsgReader(CMsgHandler* handler, rdr::InStream* is);
+
+ CMsgHandler* handler;
+ rdr::InStream* is;
+ Decoder* decoders[encodingMax+1];
+ rdr::U8* imageBuf;
+ int imageBufSize;
+ };
+}
+#endif
diff --git a/common/rfb/CMsgReaderV3.cxx b/common/rfb/CMsgReaderV3.cxx
new file mode 100644
index 00000000..d0cfc89f
--- /dev/null
+++ b/common/rfb/CMsgReaderV3.cxx
@@ -0,0 +1,107 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#include <rfb/PixelFormat.h>
+#include <rfb/msgTypes.h>
+#include <rfb/Exception.h>
+#include <rdr/InStream.h>
+#include <rfb/CMsgReaderV3.h>
+#include <rfb/CMsgHandler.h>
+#include <rfb/util.h>
+
+using namespace rfb;
+
+CMsgReaderV3::CMsgReaderV3(CMsgHandler* handler, rdr::InStream* is)
+ : CMsgReader(handler, is), nUpdateRectsLeft(0)
+{
+}
+
+CMsgReaderV3::~CMsgReaderV3()
+{
+}
+
+void CMsgReaderV3::readServerInit()
+{
+ int width = is->readU16();
+ int height = is->readU16();
+ handler->setDesktopSize(width, height);
+ PixelFormat pf;
+ pf.read(is);
+ handler->setPixelFormat(pf);
+ CharArray name(is->readString());
+ handler->setName(name.buf);
+ handler->serverInit();
+}
+
+void CMsgReaderV3::readMsg()
+{
+ if (nUpdateRectsLeft == 0) {
+
+ int type = is->readU8();
+ switch (type) {
+ case msgTypeFramebufferUpdate: readFramebufferUpdate(); break;
+ case msgTypeSetColourMapEntries: readSetColourMapEntries(); break;
+ case msgTypeBell: readBell(); break;
+ case msgTypeServerCutText: readServerCutText(); break;
+
+ case msgTypeFileListData:
+ case msgTypeFileDownloadData:
+ case msgTypeFileUploadCancel:
+ case msgTypeFileDownloadFailed:
+ case msgTypeFileDirSizeData:
+ case msgTypeFileLastRequestFailed:
+ handler->processFTMsg(type); break;
+
+ default:
+ fprintf(stderr, "unknown message type %d\n", type);
+ throw Exception("unknown message type");
+ }
+
+ } else {
+
+ int x = is->readU16();
+ int y = is->readU16();
+ int w = is->readU16();
+ int h = is->readU16();
+ unsigned int encoding = is->readU32();
+
+ switch (encoding) {
+ case pseudoEncodingDesktopSize:
+ handler->setDesktopSize(w, h);
+ break;
+ case pseudoEncodingCursor:
+ readSetCursor(w, h, Point(x,y));
+ break;
+ case pseudoEncodingLastRect:
+ nUpdateRectsLeft = 1; // this rectangle is the last one
+ break;
+ default:
+ readRect(Rect(x, y, x+w, y+h), encoding);
+ break;
+ };
+
+ nUpdateRectsLeft--;
+ if (nUpdateRectsLeft == 0) handler->framebufferUpdateEnd();
+ }
+}
+
+void CMsgReaderV3::readFramebufferUpdate()
+{
+ is->skip(1);
+ nUpdateRectsLeft = is->readU16();
+ handler->framebufferUpdateStart();
+}
diff --git a/common/rfb/CMsgReaderV3.h b/common/rfb/CMsgReaderV3.h
new file mode 100644
index 00000000..689bb650
--- /dev/null
+++ b/common/rfb/CMsgReaderV3.h
@@ -0,0 +1,35 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#ifndef __RFB_CMSGREADERV3_H__
+#define __RFB_CMSGREADERV3_H__
+
+#include <rfb/CMsgReader.h>
+
+namespace rfb {
+ class CMsgReaderV3 : public CMsgReader {
+ public:
+ CMsgReaderV3(CMsgHandler* handler, rdr::InStream* is);
+ virtual ~CMsgReaderV3();
+ virtual void readServerInit();
+ virtual void readMsg();
+ private:
+ void readFramebufferUpdate();
+ int nUpdateRectsLeft;
+ };
+}
+#endif
diff --git a/common/rfb/CMsgWriter.cxx b/common/rfb/CMsgWriter.cxx
new file mode 100644
index 00000000..cdfb4e5f
--- /dev/null
+++ b/common/rfb/CMsgWriter.cxx
@@ -0,0 +1,132 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#include <stdio.h>
+#include <rdr/OutStream.h>
+#include <rfb/msgTypes.h>
+#include <rfb/PixelFormat.h>
+#include <rfb/Rect.h>
+#include <rfb/ConnParams.h>
+#include <rfb/Decoder.h>
+#include <rfb/CMsgWriter.h>
+
+using namespace rfb;
+
+CMsgWriter::CMsgWriter(ConnParams* cp_, rdr::OutStream* os_)
+ : cp(cp_), os(os_)
+{
+}
+
+CMsgWriter::~CMsgWriter()
+{
+}
+
+void CMsgWriter::writeSetPixelFormat(const PixelFormat& pf)
+{
+ startMsg(msgTypeSetPixelFormat);
+ os->pad(3);
+ pf.write(os);
+ endMsg();
+}
+
+void CMsgWriter::writeSetEncodings(int nEncodings, rdr::U32* encodings)
+{
+ startMsg(msgTypeSetEncodings);
+ os->skip(1);
+ os->writeU16(nEncodings);
+ for (int i = 0; i < nEncodings; i++)
+ os->writeU32(encodings[i]);
+ endMsg();
+}
+
+// Ask for encodings based on which decoders are supported. Assumes higher
+// encoding numbers are more desirable.
+
+void CMsgWriter::writeSetEncodings(int preferredEncoding, bool useCopyRect)
+{
+ int nEncodings = 0;
+ rdr::U32 encodings[encodingMax+3];
+ if (cp->supportsLocalCursor)
+ encodings[nEncodings++] = pseudoEncodingCursor;
+ if (cp->supportsDesktopResize)
+ encodings[nEncodings++] = pseudoEncodingDesktopSize;
+ if (Decoder::supported(preferredEncoding)) {
+ encodings[nEncodings++] = preferredEncoding;
+ }
+ if (useCopyRect) {
+ encodings[nEncodings++] = encodingCopyRect;
+ }
+ for (int i = encodingMax; i >= 0; i--) {
+ if (i != preferredEncoding && Decoder::supported(i)) {
+ encodings[nEncodings++] = i;
+ }
+ }
+ encodings[nEncodings++] = pseudoEncodingLastRect;
+ if (cp->customCompressLevel && cp->compressLevel >= 0 && cp->compressLevel <= 9)
+ encodings[nEncodings++] = pseudoEncodingCompressLevel0 + cp->compressLevel;
+ if (!cp->noJpeg && cp->qualityLevel >= 1 && cp->qualityLevel <= 9)
+ encodings[nEncodings++] = pseudoEncodingQualityLevel0 + cp->qualityLevel;
+
+ writeSetEncodings(nEncodings, encodings);
+}
+
+void CMsgWriter::writeFramebufferUpdateRequest(const Rect& r, bool incremental)
+{
+ startMsg(msgTypeFramebufferUpdateRequest);
+ os->writeU8(incremental);
+ os->writeU16(r.tl.x);
+ os->writeU16(r.tl.y);
+ os->writeU16(r.width());
+ os->writeU16(r.height());
+ endMsg();
+}
+
+
+void CMsgWriter::keyEvent(rdr::U32 key, bool down)
+{
+ startMsg(msgTypeKeyEvent);
+ os->writeU8(down);
+ os->pad(2);
+ os->writeU32(key);
+ endMsg();
+}
+
+
+void CMsgWriter::pointerEvent(const Point& pos, int buttonMask)
+{
+ Point p(pos);
+ if (p.x < 0) p.x = 0;
+ if (p.y < 0) p.y = 0;
+ if (p.x >= cp->width) p.x = cp->width - 1;
+ if (p.y >= cp->height) p.y = cp->height - 1;
+
+ startMsg(msgTypePointerEvent);
+ os->writeU8(buttonMask);
+ os->writeU16(p.x);
+ os->writeU16(p.y);
+ endMsg();
+}
+
+
+void CMsgWriter::clientCutText(const char* str, int len)
+{
+ startMsg(msgTypeClientCutText);
+ os->pad(3);
+ os->writeU32(len);
+ os->writeBytes(str, len);
+ endMsg();
+}
diff --git a/common/rfb/CMsgWriter.h b/common/rfb/CMsgWriter.h
new file mode 100644
index 00000000..19be8df9
--- /dev/null
+++ b/common/rfb/CMsgWriter.h
@@ -0,0 +1,65 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+//
+// CMsgWriter - class for writing RFB messages on the server side.
+//
+
+#ifndef __RFB_CMSGWRITER_H__
+#define __RFB_CMSGWRITER_H__
+
+#include <rfb/InputHandler.h>
+
+namespace rdr { class OutStream; }
+
+namespace rfb {
+
+ class PixelFormat;
+ class ConnParams;
+ struct Rect;
+
+ class CMsgWriter : public InputHandler {
+ public:
+ virtual ~CMsgWriter();
+
+ // CMsgWriter abstract interface methods
+ virtual void writeClientInit(bool shared)=0;
+ virtual void startMsg(int type)=0;
+ virtual void endMsg()=0;
+
+ // CMsgWriter implemented methods
+ virtual void writeSetPixelFormat(const PixelFormat& pf);
+ virtual void writeSetEncodings(int nEncodings, rdr::U32* encodings);
+ virtual void writeSetEncodings(int preferredEncoding, bool useCopyRect);
+ virtual void writeFramebufferUpdateRequest(const Rect& r,bool incremental);
+
+ // InputHandler implementation
+ virtual void keyEvent(rdr::U32 key, bool down);
+ virtual void pointerEvent(const Point& pos, int buttonMask);
+ virtual void clientCutText(const char* str, int len);
+
+ ConnParams* getConnParams() { return cp; }
+ rdr::OutStream* getOutStream() { return os; }
+
+ protected:
+ CMsgWriter(ConnParams* cp, rdr::OutStream* os);
+
+ ConnParams* cp;
+ rdr::OutStream* os;
+ };
+}
+#endif
diff --git a/common/rfb/CMsgWriterV3.cxx b/common/rfb/CMsgWriterV3.cxx
new file mode 100644
index 00000000..a9807952
--- /dev/null
+++ b/common/rfb/CMsgWriterV3.cxx
@@ -0,0 +1,49 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#include <rdr/OutStream.h>
+#include <rfb/msgTypes.h>
+#include <rfb/Exception.h>
+#include <rfb/ConnParams.h>
+#include <rfb/CMsgWriterV3.h>
+
+using namespace rfb;
+
+CMsgWriterV3::CMsgWriterV3(ConnParams* cp, rdr::OutStream* os)
+ : CMsgWriter(cp, os)
+{
+}
+
+CMsgWriterV3::~CMsgWriterV3()
+{
+}
+
+void CMsgWriterV3::writeClientInit(bool shared)
+{
+ os->writeU8(shared);
+ endMsg();
+}
+
+void CMsgWriterV3::startMsg(int type)
+{
+ os->writeU8(type);
+}
+
+void CMsgWriterV3::endMsg()
+{
+ os->flush();
+}
diff --git a/common/rfb/CMsgWriterV3.h b/common/rfb/CMsgWriterV3.h
new file mode 100644
index 00000000..0b2f9afe
--- /dev/null
+++ b/common/rfb/CMsgWriterV3.h
@@ -0,0 +1,35 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#ifndef __RFB_CMSGWRITERV3_H__
+#define __RFB_CMSGWRITERV3_H__
+
+#include <rfb/CMsgWriter.h>
+
+namespace rfb {
+ class CMsgWriterV3 : public CMsgWriter {
+ public:
+ CMsgWriterV3(ConnParams* cp, rdr::OutStream* os);
+ virtual ~CMsgWriterV3();
+
+ virtual void writeClientInit(bool shared);
+ virtual void startMsg(int type);
+ virtual void endMsg();
+
+ };
+}
+#endif
diff --git a/common/rfb/CSecurity.h b/common/rfb/CSecurity.h
new file mode 100644
index 00000000..90a01d70
--- /dev/null
+++ b/common/rfb/CSecurity.h
@@ -0,0 +1,52 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+//
+// CSecurity - class on the client side for handling security handshaking. A
+// derived class for a particular security type overrides the processMsg()
+// method.
+
+// processMsg() is called first when the security type has been decided on, and
+// will keep being called whenever there is data to read from the server. It
+// should return false when it needs more data, or true when the security
+// handshaking is over and we are now waiting for the SecurityResult message
+// from the server. In the event of failure a suitable exception should be
+// thrown.
+//
+// Note that the first time processMsg() is called, there is no guarantee that
+// there is any data to read from the CConnection's InStream, but subsequent
+// calls guarantee there is at least one byte which can be read without
+// blocking.
+//
+// description is a string describing the level of encryption applied to the
+// session, or null if no encryption will be used.
+
+#ifndef __RFB_CSECURITY_H__
+#define __RFB_CSECURITY_H__
+
+namespace rfb {
+ class CConnection;
+ class CSecurity {
+ public:
+ virtual ~CSecurity() {}
+ virtual bool processMsg(CConnection* cc)=0;
+ virtual void destroy() { delete this; }
+ virtual int getType() const = 0;
+ virtual const char* description() const = 0;
+ };
+}
+#endif
diff --git a/common/rfb/CSecurityNone.h b/common/rfb/CSecurityNone.h
new file mode 100644
index 00000000..54c10168
--- /dev/null
+++ b/common/rfb/CSecurityNone.h
@@ -0,0 +1,36 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+//
+// CSecurityNone.h
+//
+
+#ifndef __CSECURITYNONE_H__
+#define __CSECURITYNONE_H__
+
+#include <rfb/CSecurity.h>
+
+namespace rfb {
+
+ class CSecurityNone : public CSecurity {
+ public:
+ virtual bool processMsg(CConnection* cc) { return true; }
+ virtual int getType() const {return secTypeNone;}
+ virtual const char* description() const {return "No Encryption";}
+ };
+}
+#endif
diff --git a/common/rfb/CSecurityVncAuth.cxx b/common/rfb/CSecurityVncAuth.cxx
new file mode 100644
index 00000000..ba5a30b7
--- /dev/null
+++ b/common/rfb/CSecurityVncAuth.cxx
@@ -0,0 +1,74 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+//
+// CSecurityVncAuth
+//
+// XXX not thread-safe, because d3des isn't - do we need to worry about this?
+//
+
+#include <string.h>
+#include <stdio.h>
+#include <rfb/CConnection.h>
+#include <rfb/UserPasswdGetter.h>
+#include <rfb/Password.h>
+#include <rfb/CSecurityVncAuth.h>
+#include <rfb/util.h>
+extern "C" {
+#include <rfb/d3des.h>
+}
+
+
+using namespace rfb;
+
+static const int vncAuthChallengeSize = 16;
+
+
+CSecurityVncAuth::CSecurityVncAuth(UserPasswdGetter* upg_)
+ : upg(upg_)
+{
+}
+
+CSecurityVncAuth::~CSecurityVncAuth()
+{
+}
+
+bool CSecurityVncAuth::processMsg(CConnection* cc)
+{
+ rdr::InStream* is = cc->getInStream();
+ rdr::OutStream* os = cc->getOutStream();
+
+ // Read the challenge & obtain the user's password
+ rdr::U8 challenge[vncAuthChallengeSize];
+ is->readBytes(challenge, vncAuthChallengeSize);
+ PlainPasswd passwd;
+ upg->getUserPasswd(0, &passwd.buf);
+
+ // Calculate the correct response
+ rdr::U8 key[8];
+ int pwdLen = strlen(passwd.buf);
+ for (int i=0; i<8; i++)
+ key[i] = i<pwdLen ? passwd.buf[i] : 0;
+ deskey(key, EN0);
+ for (int j = 0; j < vncAuthChallengeSize; j += 8)
+ des(challenge+j, challenge+j);
+
+ // Return the response to the server
+ os->writeBytes(challenge, vncAuthChallengeSize);
+ os->flush();
+ return true;
+}
diff --git a/common/rfb/CSecurityVncAuth.h b/common/rfb/CSecurityVncAuth.h
new file mode 100644
index 00000000..8d38d878
--- /dev/null
+++ b/common/rfb/CSecurityVncAuth.h
@@ -0,0 +1,39 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#ifndef __RFB_CSECURITYVNCAUTH_H__
+#define __RFB_CSECURITYVNCAUTH_H__
+
+#include <rfb/CSecurity.h>
+#include <rfb/secTypes.h>
+
+namespace rfb {
+
+ class UserPasswdGetter;
+
+ class CSecurityVncAuth : public CSecurity {
+ public:
+ CSecurityVncAuth(UserPasswdGetter* pg);
+ virtual ~CSecurityVncAuth();
+ virtual bool processMsg(CConnection* cc);
+ virtual int getType() const {return secTypeVncAuth;};
+ virtual const char* description() const {return "No Encryption";}
+ private:
+ UserPasswdGetter* upg;
+ };
+}
+#endif
diff --git a/common/rfb/ColourCube.h b/common/rfb/ColourCube.h
new file mode 100644
index 00000000..b83cbba8
--- /dev/null
+++ b/common/rfb/ColourCube.h
@@ -0,0 +1,96 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+//
+// ColourCube - structure to represent a colour cube. The colour cube consists
+// of its dimensions (nRed x nGreen x nBlue) and a table mapping an (r,g,b)
+// triple to a pixel value.
+//
+// A colour cube is used in two cases. The first is internally in a viewer
+// when it cannot use a trueColour format, nor can it have exclusive access to
+// a writable colour map. This is most notably the case for an X viewer
+// wishing to use a PseudoColor X server's default colormap.
+//
+// The second use is on the server side when a client has asked for a colour
+// map and the server is trueColour. Instead of setting an uneven trueColour
+// format like bgr233, it can set the client's colour map up with a 6x6x6
+// colour cube. For this use the colour cube table has a null mapping, which
+// makes it easy to perform the reverse lookup operation from pixel value to
+// r,g,b values.
+
+#ifndef __RFB_COLOURCUBE_H__
+#define __RFB_COLOURCUBE_H__
+
+#include <rfb/Pixel.h>
+#include <rfb/ColourMap.h>
+
+namespace rfb {
+
+ class ColourCube : public ColourMap {
+ public:
+ ColourCube(int nr, int ng, int nb, Pixel* table_=0)
+ : nRed(nr), nGreen(ng), nBlue(nb), table(table_), deleteTable(false)
+ {
+ if (!table) {
+ table = new Pixel[size()];
+ deleteTable = true;
+ // set a null mapping by default
+ for (int i = 0; i < size(); i++)
+ table[i] = i;
+ }
+ }
+
+ ColourCube() : deleteTable(false) {}
+
+ virtual ~ColourCube() {
+ if (deleteTable) delete [] table;
+ }
+
+ void set(int r, int g, int b, Pixel p) {
+ table[(r * nGreen + g) * nBlue + b] = p;
+ }
+
+ Pixel lookup(int r, int g, int b) const {
+ return table[(r * nGreen + g) * nBlue + b];
+ }
+
+ int size() const { return nRed*nGreen*nBlue; }
+ int redMult() const { return nGreen*nBlue; }
+ int greenMult() const { return nBlue; }
+ int blueMult() const { return 1; }
+
+ // ColourMap lookup() method. Note that this only works when the table has
+ // the default null mapping.
+ virtual void lookup(int i, int* r, int* g, int* b) {
+ if (i >= size()) return;
+ *b = i % nBlue;
+ i /= nBlue;
+ *g = i % nGreen;
+ *r = i / nGreen;
+ *r = (*r * 65535 + (nRed-1) / 2) / (nRed-1);
+ *g = (*g * 65535 + (nGreen-1) / 2) / (nGreen-1);
+ *b = (*b * 65535 + (nBlue-1) / 2) / (nBlue-1);
+ }
+
+ int nRed;
+ int nGreen;
+ int nBlue;
+ Pixel* table;
+ bool deleteTable;
+ };
+}
+#endif
diff --git a/common/rfb/ColourMap.h b/common/rfb/ColourMap.h
new file mode 100644
index 00000000..da6cb126
--- /dev/null
+++ b/common/rfb/ColourMap.h
@@ -0,0 +1,34 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#ifndef __RFB_COLOURMAP_H__
+#define __RFB_COLOURMAP_H__
+namespace rfb {
+ struct Colour {
+ Colour() : r(0), g(0), b(0) {}
+ Colour(int r_, int g_, int b_) : r(r_), g(g_), b(b_) {}
+ int r, g, b;
+ bool operator==(const Colour& c) const {return c.r == r && c.g == g && c.b == b;}
+ bool operator!=(const Colour& c) const {return !(c == *this);}
+ };
+
+ class ColourMap {
+ public:
+ virtual void lookup(int index, int* r, int* g, int* b)=0;
+ };
+}
+#endif
diff --git a/common/rfb/ComparingUpdateTracker.cxx b/common/rfb/ComparingUpdateTracker.cxx
new file mode 100644
index 00000000..ce3d68ae
--- /dev/null
+++ b/common/rfb/ComparingUpdateTracker.cxx
@@ -0,0 +1,137 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#include <stdio.h>
+#include <vector>
+#include <rdr/types.h>
+#include <rfb/Exception.h>
+#include <rfb/ComparingUpdateTracker.h>
+
+using namespace rfb;
+
+ComparingUpdateTracker::ComparingUpdateTracker(PixelBuffer* buffer)
+ : fb(buffer), oldFb(fb->getPF(), 0, 0), firstCompare(true)
+{
+ changed.assign_union(fb->getRect());
+}
+
+ComparingUpdateTracker::~ComparingUpdateTracker()
+{
+}
+
+
+#define BLOCK_SIZE 16
+
+void ComparingUpdateTracker::compare()
+{
+ std::vector<Rect> rects;
+ std::vector<Rect>::iterator i;
+
+ if (firstCompare) {
+ // NB: We leave the change region untouched on this iteration,
+ // since in effect the entire framebuffer has changed.
+ oldFb.setSize(fb->width(), fb->height());
+ for (int y=0; y<fb->height(); y+=BLOCK_SIZE) {
+ Rect pos(0, y, fb->width(), __rfbmin(fb->height(), y+BLOCK_SIZE));
+ int srcStride;
+ const rdr::U8* srcData = fb->getPixelsR(pos, &srcStride);
+ oldFb.imageRect(pos, srcData, srcStride);
+ }
+ firstCompare = false;
+ } else {
+ copied.get_rects(&rects, copy_delta.x<=0, copy_delta.y<=0);
+ for (i = rects.begin(); i != rects.end(); i++)
+ oldFb.copyRect(*i, copy_delta);
+
+ Region to_check = changed.union_(copied);
+ to_check.get_rects(&rects);
+
+ Region newChanged;
+ for (i = rects.begin(); i != rects.end(); i++)
+ compareRect(*i, &newChanged);
+
+ copied.assign_subtract(newChanged);
+ changed = newChanged;
+ }
+}
+
+void ComparingUpdateTracker::compareRect(const Rect& r, Region* newChanged)
+{
+ if (!r.enclosed_by(fb->getRect())) {
+ fprintf(stderr,"ComparingUpdateTracker: rect outside fb (%d,%d-%d,%d)\n", r.tl.x, r.tl.y, r.br.x, r.br.y);
+ return;
+ }
+
+ int bytesPerPixel = fb->getPF().bpp/8;
+ int oldStride;
+ rdr::U8* oldData = oldFb.getPixelsRW(r, &oldStride);
+ int oldStrideBytes = oldStride * bytesPerPixel;
+
+ std::vector<Rect> changedBlocks;
+
+ for (int blockTop = r.tl.y; blockTop < r.br.y; blockTop += BLOCK_SIZE)
+ {
+ // Get a strip of the source buffer
+ Rect pos(r.tl.x, blockTop, r.br.x, __rfbmin(r.br.y, blockTop+BLOCK_SIZE));
+ int fbStride;
+ const rdr::U8* newBlockPtr = fb->getPixelsR(pos, &fbStride);
+ int newStrideBytes = fbStride * bytesPerPixel;
+
+ rdr::U8* oldBlockPtr = oldData;
+ int blockBottom = __rfbmin(blockTop+BLOCK_SIZE, r.br.y);
+
+ for (int blockLeft = r.tl.x; blockLeft < r.br.x; blockLeft += BLOCK_SIZE)
+ {
+ const rdr::U8* newPtr = newBlockPtr;
+ rdr::U8* oldPtr = oldBlockPtr;
+
+ int blockRight = __rfbmin(blockLeft+BLOCK_SIZE, r.br.x);
+ int blockWidthInBytes = (blockRight-blockLeft) * bytesPerPixel;
+
+ for (int y = blockTop; y < blockBottom; y++)
+ {
+ if (memcmp(oldPtr, newPtr, blockWidthInBytes) != 0)
+ {
+ // A block has changed - copy the remainder to the oldFb
+ changedBlocks.push_back(Rect(blockLeft, blockTop,
+ blockRight, blockBottom));
+ for (int y2 = y; y2 < blockBottom; y2++)
+ {
+ memcpy(oldPtr, newPtr, blockWidthInBytes);
+ newPtr += newStrideBytes;
+ oldPtr += oldStrideBytes;
+ }
+ break;
+ }
+
+ newPtr += newStrideBytes;
+ oldPtr += oldStrideBytes;
+ }
+
+ oldBlockPtr += blockWidthInBytes;
+ newBlockPtr += blockWidthInBytes;
+ }
+
+ oldData += oldStrideBytes * BLOCK_SIZE;
+ }
+
+ if (!changedBlocks.empty()) {
+ Region temp;
+ temp.setOrderedRects(changedBlocks);
+ newChanged->assign_union(temp);
+ }
+}
diff --git a/common/rfb/ComparingUpdateTracker.h b/common/rfb/ComparingUpdateTracker.h
new file mode 100644
index 00000000..5d2e5edf
--- /dev/null
+++ b/common/rfb/ComparingUpdateTracker.h
@@ -0,0 +1,43 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#ifndef __RFB_COMPARINGUPDATETRACKER_H__
+#define __RFB_COMPARINGUPDATETRACKER_H__
+
+#include <rfb/UpdateTracker.h>
+
+namespace rfb {
+
+ class ComparingUpdateTracker : public SimpleUpdateTracker {
+ public:
+ ComparingUpdateTracker(PixelBuffer* buffer);
+ ~ComparingUpdateTracker();
+
+ // compare() does the comparison and reduces its changed and copied regions
+ // as appropriate.
+
+ virtual void compare();
+ private:
+ void compareRect(const Rect& r, Region* newchanged);
+ PixelBuffer* fb;
+ ManagedPixelBuffer oldFb;
+ bool firstCompare;
+ };
+
+}
+#endif
diff --git a/common/rfb/Configuration.cxx b/common/rfb/Configuration.cxx
new file mode 100644
index 00000000..9ebc20a8
--- /dev/null
+++ b/common/rfb/Configuration.cxx
@@ -0,0 +1,466 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ * Copyright (C) 2004-2005 Cendio AB. All rights reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- Configuration.cxx
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <assert.h>
+#ifdef WIN32
+#define strcasecmp _stricmp
+#define strncasecmp _strnicmp
+#endif
+
+#include <rfb/util.h>
+#include <rfb/Configuration.h>
+#include <rfb/LogWriter.h>
+#include <rfb/Exception.h>
+#include <rfb/Threading.h>
+
+#ifdef __RFB_THREADING_IMPL
+// On platforms that support Threading, we use Locks to make getData safe
+#define LOCK_CONFIG Lock l(*configLock())
+rfb::Mutex* configLock_ = 0;
+static rfb::Mutex* configLock() {
+ if (!configLock_)
+ configLock_ = new rfb::Mutex;
+ return configLock_;
+}
+#else
+#define LOCK_CONFIG
+#endif
+
+#include <rdr/HexOutStream.h>
+#include <rdr/HexInStream.h>
+
+using namespace rfb;
+
+static LogWriter vlog("Config");
+
+
+// -=- The Global Configuration object
+Configuration* Configuration::global_ = 0;
+Configuration* Configuration::global() {
+ if (!global_)
+ global_ = new Configuration("Global");
+ return global_;
+}
+
+
+// -=- Configuration implementation
+
+Configuration::Configuration(const char* name_, Configuration* attachToGroup)
+: name(strDup(name_)), head(0), _next(0) {
+ if (attachToGroup) {
+ _next = attachToGroup->_next;
+ attachToGroup->_next = this;
+ }
+}
+
+Configuration& Configuration::operator=(const Configuration& src) {
+ VoidParameter* current = head;
+ while (current) {
+ VoidParameter* srcParam = ((Configuration&)src).get(current->getName());
+ if (srcParam) {
+ current->immutable = false;
+ CharArray value(srcParam->getValueStr());
+ vlog.debug("operator=(%s, %s)", current->getName(), value.buf);
+ current->setParam(value.buf);
+ }
+ current = current->_next;
+ }
+ if (_next)
+ *_next=src;
+ return *this;
+}
+
+bool Configuration::set(const char* n, const char* v, bool immutable) {
+ return set(n, strlen(n), v, immutable);
+}
+
+bool Configuration::set(const char* name, int len,
+ const char* val, bool immutable)
+{
+ VoidParameter* current = head;
+ while (current) {
+ if ((int)strlen(current->getName()) == len &&
+ strncasecmp(current->getName(), name, len) == 0)
+ {
+ bool b = current->setParam(val);
+ current->setHasBeenSet();
+ if (b && immutable)
+ current->setImmutable();
+ return b;
+ }
+ current = current->_next;
+ }
+ return _next ? _next->set(name, len, val, immutable) : false;
+}
+
+bool Configuration::set(const char* config, bool immutable) {
+ bool hyphen = false;
+ if (config[0] == '-') {
+ hyphen = true;
+ config++;
+ if (config[0] == '-') config++; // allow gnu-style --<option>
+ }
+ const char* equal = strchr(config, '=');
+ if (equal) {
+ return set(config, equal-config, equal+1, immutable);
+ } else if (hyphen) {
+ VoidParameter* current = head;
+ while (current) {
+ if (strcasecmp(current->getName(), config) == 0) {
+ bool b = current->setParam();
+ current->setHasBeenSet();
+ if (b && immutable)
+ current->setImmutable();
+ return b;
+ }
+ current = current->_next;
+ }
+ }
+ return _next ? _next->set(config, immutable) : false;
+}
+
+VoidParameter* Configuration::get(const char* param)
+{
+ VoidParameter* current = head;
+ while (current) {
+ if (strcasecmp(current->getName(), param) == 0)
+ return current;
+ current = current->_next;
+ }
+ return _next ? _next->get(param) : 0;
+}
+
+void Configuration::list(int width, int nameWidth) {
+ VoidParameter* current = head;
+
+ fprintf(stderr, "%s Parameters:\n", name.buf);
+ while (current) {
+ char* def_str = current->getDefaultStr();
+ const char* desc = current->getDescription();
+ fprintf(stderr," %-*s -", nameWidth, current->getName());
+ int column = strlen(current->getName());
+ if (column < nameWidth) column = nameWidth;
+ column += 4;
+ while (true) {
+ const char* s = strchr(desc, ' ');
+ int wordLen;
+ if (s) wordLen = s-desc;
+ else wordLen = strlen(desc);
+
+ if (column + wordLen + 1 > width) {
+ fprintf(stderr,"\n%*s",nameWidth+4,"");
+ column = nameWidth+4;
+ }
+ fprintf(stderr," %.*s",wordLen,desc);
+ column += wordLen + 1;
+ desc += wordLen + 1;
+ if (!s) break;
+ }
+
+ if (def_str) {
+ if (column + (int)strlen(def_str) + 11 > width)
+ fprintf(stderr,"\n%*s",nameWidth+4,"");
+ fprintf(stderr," (default=%s)\n",def_str);
+ strFree(def_str);
+ } else {
+ fprintf(stderr,"\n");
+ }
+ current = current->_next;
+ }
+
+ if (_next)
+ _next->list(width, nameWidth);
+}
+
+
+// -=- VoidParameter
+
+VoidParameter::VoidParameter(const char* name_, const char* desc_, Configuration* conf)
+ : immutable(false), _hasBeenSet(false), name(name_), description(desc_) {
+ if (!conf)
+ conf = Configuration::global();
+ _next = conf->head;
+ conf->head = this;
+}
+
+VoidParameter::~VoidParameter() {
+}
+
+const char*
+VoidParameter::getName() const {
+ return name;
+}
+
+const char*
+VoidParameter::getDescription() const {
+ return description;
+}
+
+bool VoidParameter::setParam() {
+ return false;
+}
+
+bool VoidParameter::isBool() const {
+ return false;
+}
+
+void
+VoidParameter::setImmutable() {
+ vlog.debug("set immutable %s", getName());
+ immutable = true;
+}
+
+void
+VoidParameter::setHasBeenSet() {
+ _hasBeenSet = true;
+}
+
+bool
+VoidParameter::hasBeenSet() {
+ return _hasBeenSet;
+}
+
+// -=- AliasParameter
+
+AliasParameter::AliasParameter(const char* name_, const char* desc_,
+ VoidParameter* param_, Configuration* conf)
+ : VoidParameter(name_, desc_, conf), param(param_) {
+}
+
+bool
+AliasParameter::setParam(const char* v) {
+ return param->setParam(v);
+}
+
+bool AliasParameter::setParam() {
+ return param->setParam();
+}
+
+char*
+AliasParameter::getDefaultStr() const {
+ return 0;
+}
+
+char* AliasParameter::getValueStr() const {
+ return param->getValueStr();
+}
+
+bool AliasParameter::isBool() const {
+ return param->isBool();
+}
+
+void
+AliasParameter::setImmutable() {
+ vlog.debug("set immutable %s (Alias)", getName());
+ param->setImmutable();
+}
+
+
+// -=- BoolParameter
+
+BoolParameter::BoolParameter(const char* name_, const char* desc_, bool v, Configuration* conf)
+: VoidParameter(name_, desc_, conf), value(v), def_value(v) {
+}
+
+bool
+BoolParameter::setParam(const char* v) {
+ if (immutable) return true;
+
+ if (*v == 0 || strcasecmp(v, "1") == 0 || strcasecmp(v, "on") == 0
+ || strcasecmp(v, "true") == 0 || strcasecmp(v, "yes") == 0)
+ value = 1;
+ else if (strcasecmp(v, "0") == 0 || strcasecmp(v, "off") == 0
+ || strcasecmp(v, "false") == 0 || strcasecmp(v, "no") == 0)
+ value = 0;
+ else {
+ vlog.error("Bool parameter %s: invalid value '%s'", getName(), v);
+ return false;
+ }
+
+ vlog.debug("set %s(Bool) to %s(%d)", getName(), v, value);
+ return true;
+}
+
+bool BoolParameter::setParam() {
+ setParam(true);
+ return true;
+}
+
+void BoolParameter::setParam(bool b) {
+ if (immutable) return;
+ value = b;
+ vlog.debug("set %s(Bool) to %d", getName(), value);
+}
+
+char*
+BoolParameter::getDefaultStr() const {
+ return strDup(def_value ? "1" : "0");
+}
+
+char* BoolParameter::getValueStr() const {
+ return strDup(value ? "1" : "0");
+}
+
+bool BoolParameter::isBool() const {
+ return true;
+}
+
+BoolParameter::operator bool() const {
+ return value;
+}
+
+// -=- IntParameter
+
+IntParameter::IntParameter(const char* name_, const char* desc_, int v,
+ int minValue_, int maxValue_, Configuration* conf)
+ : VoidParameter(name_, desc_, conf), value(v), def_value(v),
+ minValue(minValue_), maxValue(maxValue_)
+{
+}
+
+bool
+IntParameter::setParam(const char* v) {
+ if (immutable) return true;
+ vlog.debug("set %s(Int) to %s", getName(), v);
+ int i = atoi(v);
+ if (i < minValue || i > maxValue)
+ return false;
+ value = i;
+ return true;
+}
+
+bool
+IntParameter::setParam(int v) {
+ if (immutable) return true;
+ vlog.debug("set %s(Int) to %d", getName(), v);
+ if (v < minValue || v > maxValue)
+ return false;
+ value = v;
+ return true;
+}
+
+char*
+IntParameter::getDefaultStr() const {
+ char* result = new char[16];
+ sprintf(result, "%d", def_value);
+ return result;
+}
+
+char* IntParameter::getValueStr() const {
+ char* result = new char[16];
+ sprintf(result, "%d", value);
+ return result;
+}
+
+IntParameter::operator int() const {
+ return value;
+}
+
+// -=- StringParameter
+
+StringParameter::StringParameter(const char* name_, const char* desc_,
+ const char* v, Configuration* conf)
+ : VoidParameter(name_, desc_, conf), value(strDup(v)), def_value(v)
+{
+ if (!v) {
+ fprintf(stderr,"Default value <null> for %s not allowed\n",name_);
+ throw rfb::Exception("Default value <null> not allowed");
+ }
+}
+
+StringParameter::~StringParameter() {
+ strFree(value);
+}
+
+bool StringParameter::setParam(const char* v) {
+ LOCK_CONFIG;
+ if (immutable) return true;
+ if (!v)
+ throw rfb::Exception("setParam(<null>) not allowed");
+ vlog.debug("set %s(String) to %s", getName(), v);
+ CharArray oldValue(value);
+ value = strDup(v);
+ return value != 0;
+}
+
+char* StringParameter::getDefaultStr() const {
+ return strDup(def_value);
+}
+
+char* StringParameter::getValueStr() const {
+ LOCK_CONFIG;
+ return strDup(value);
+}
+
+// -=- BinaryParameter
+
+BinaryParameter::BinaryParameter(const char* name_, const char* desc_, const void* v, int l, Configuration* conf)
+: VoidParameter(name_, desc_, conf), value(0), length(0), def_value((char*)v), def_length(l) {
+ if (l) {
+ value = new char[l];
+ length = l;
+ memcpy(value, v, l);
+ }
+}
+BinaryParameter::~BinaryParameter() {
+ if (value)
+ delete [] value;
+}
+
+bool BinaryParameter::setParam(const char* v) {
+ LOCK_CONFIG;
+ if (immutable) return true;
+ vlog.debug("set %s(Binary) to %s", getName(), v);
+ return rdr::HexInStream::hexStrToBin(v, &value, &length);
+}
+
+void BinaryParameter::setParam(const void* v, int len) {
+ LOCK_CONFIG;
+ if (immutable) return;
+ vlog.debug("set %s(Binary)", getName());
+ delete [] value; value = 0;
+ if (len) {
+ value = new char[len];
+ length = len;
+ memcpy(value, v, len);
+ }
+}
+
+char* BinaryParameter::getDefaultStr() const {
+ return rdr::HexOutStream::binToHexStr(def_value, def_length);
+}
+
+char* BinaryParameter::getValueStr() const {
+ LOCK_CONFIG;
+ return rdr::HexOutStream::binToHexStr(value, length);
+}
+
+void BinaryParameter::getData(void** data_, int* length_) const {
+ LOCK_CONFIG;
+ if (length_) *length_ = length;
+ if (data_) {
+ *data_ = new char[length];
+ memcpy(*data_, value, length);
+ }
+}
diff --git a/common/rfb/Configuration.h b/common/rfb/Configuration.h
new file mode 100644
index 00000000..e3b85b83
--- /dev/null
+++ b/common/rfb/Configuration.h
@@ -0,0 +1,265 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- Configuration.h
+//
+// This header defines a set of classes used to represent configuration
+// parameters of different types. Instances of the different parameter
+// types are associated with instances of the Configuration class, and
+// are each given a unique name. The Configuration class provides a
+// generic API through which parameters may be located by name and their
+// value set, thus removing the need to write platform-specific code.
+// Simply defining a new parameter and associating it with a Configuration
+// will allow it to be configured by the user.
+//
+// If no Configuration is specified when creating a Parameter, then the
+// global Configuration will be assumed.
+//
+// Configurations can be "chained" into groups. Each group has a root
+// Configuration, a pointer to which should be passed to the constructors
+// of the other group members. set() and get() operations called on the
+// root will iterate through all of the group's members.
+//
+// NB: On platforms that support Threading, locking is performed to protect
+// complex parameter types from concurrent access (e.g. strings).
+// NB: NO LOCKING is performed when linking Configurations to groups
+// or when adding Parameters to Configurations.
+
+#ifndef __RFB_CONFIGURATION_H__
+#define __RFB_CONFIGURATION_H__
+
+#include <rfb/util.h>
+
+namespace rfb {
+ class VoidParameter;
+ struct ParameterIterator;
+
+ // -=- Configuration
+ // Class used to access parameters.
+
+ class Configuration {
+ public:
+ // - Create a new Configuration object
+ Configuration(const char* name, Configuration* attachToGroup=0);
+
+ // - Return the buffer containing the Configuration's name
+ const char* getName() const { return name.buf; }
+
+ // - Assignment operator. For every Parameter in this Configuration's
+ // group, get()s the corresponding source parameter and copies its
+ // content.
+ Configuration& operator=(const Configuration& src);
+
+ // - Set named parameter to value
+ bool set(const char* param, const char* value, bool immutable=false);
+
+ // - Set parameter to value (separated by "=")
+ bool set(const char* config, bool immutable=false);
+
+ // - Set named parameter to value, with name truncated at len
+ bool set(const char* name, int len,
+ const char* val, bool immutable);
+
+ // - Get named parameter
+ VoidParameter* get(const char* param);
+
+ // - List the parameters of this Configuration group
+ void list(int width=79, int nameWidth=10);
+
+ // - readFromFile
+ // Read configuration parameters from the specified file.
+ void readFromFile(const char* filename);
+
+ // - writeConfigToFile
+ // Write a new configuration parameters file, then mv it
+ // over the old file.
+ void writeToFile(const char* filename);
+
+
+ // - Get the Global Configuration object
+ // NB: This call does NOT lock the Configuration system.
+ // ALWAYS ensure that if you have ANY global Parameters,
+ // then they are defined as global objects, to ensure that
+ // global() is called when only the main thread is running.
+ static Configuration* global();
+
+ // - Container for process-wide Global parameters
+ static bool setParam(const char* param, const char* value, bool immutable=false) {
+ return global()->set(param, value, immutable);
+ }
+ static bool setParam(const char* config, bool immutable=false) {
+ return global()->set(config, immutable);
+ }
+ static bool setParam(const char* name, int len,
+ const char* val, bool immutable) {
+ return global()->set(name, len, val, immutable);
+ }
+ static VoidParameter* getParam(const char* param) { return global()->get(param); }
+ static void listParams(int width=79, int nameWidth=10) { global()->list(width, nameWidth); }
+
+ protected:
+ friend class VoidParameter;
+ friend struct ParameterIterator;
+
+ // Name for this Configuration
+ CharArray name;
+
+ // - Pointer to first Parameter in this group
+ VoidParameter* head;
+
+ // Pointer to next Configuration in this group
+ Configuration* _next;
+
+ // The process-wide, Global Configuration object
+ static Configuration* global_;
+ };
+
+ // -=- VoidParameter
+ // Configuration parameter base-class.
+
+ class VoidParameter {
+ public:
+ VoidParameter(const char* name_, const char* desc_, Configuration* conf=0);
+ virtual ~VoidParameter();
+ const char* getName() const;
+ const char* getDescription() const;
+
+ virtual bool setParam(const char* value) = 0;
+ virtual bool setParam();
+ virtual char* getDefaultStr() const = 0;
+ virtual char* getValueStr() const = 0;
+ virtual bool isBool() const;
+
+ virtual void setImmutable();
+ virtual void setHasBeenSet();
+ bool hasBeenSet();
+
+ protected:
+ friend class Configuration;
+ friend struct ParameterIterator;
+
+ VoidParameter* _next;
+ bool immutable;
+ bool _hasBeenSet;
+ const char* name;
+ const char* description;
+ };
+
+ class AliasParameter : public VoidParameter {
+ public:
+ AliasParameter(const char* name_, const char* desc_,VoidParameter* param_, Configuration* conf=0);
+ virtual bool setParam(const char* value);
+ virtual bool setParam();
+ virtual char* getDefaultStr() const;
+ virtual char* getValueStr() const;
+ virtual bool isBool() const;
+ virtual void setImmutable();
+ private:
+ VoidParameter* param;
+ };
+
+ class BoolParameter : public VoidParameter {
+ public:
+ BoolParameter(const char* name_, const char* desc_, bool v, Configuration* conf=0);
+ virtual bool setParam(const char* value);
+ virtual bool setParam();
+ virtual void setParam(bool b);
+ virtual char* getDefaultStr() const;
+ virtual char* getValueStr() const;
+ virtual bool isBool() const;
+ operator bool() const;
+ protected:
+ bool value;
+ bool def_value;
+ };
+
+ class IntParameter : public VoidParameter {
+ public:
+ IntParameter(const char* name_, const char* desc_, int v,
+ int minValue=INT_MIN, int maxValue=INT_MAX, Configuration* conf=0);
+ virtual bool setParam(const char* value);
+ virtual bool setParam(int v);
+ virtual char* getDefaultStr() const;
+ virtual char* getValueStr() const;
+ operator int() const;
+ protected:
+ int value;
+ int def_value;
+ int minValue, maxValue;
+ };
+
+ class StringParameter : public VoidParameter {
+ public:
+ // StringParameter contains a null-terminated string, which CANNOT
+ // be Null, and so neither can the default value!
+ StringParameter(const char* name_, const char* desc_, const char* v, Configuration* conf=0);
+ virtual ~StringParameter();
+ virtual bool setParam(const char* value);
+ virtual char* getDefaultStr() const;
+ virtual char* getValueStr() const;
+
+ // getData() returns a copy of the data - it must be delete[]d by the
+ // caller.
+ char* getData() const { return getValueStr(); }
+ protected:
+ char* value;
+ const char* def_value;
+ };
+
+ class BinaryParameter : public VoidParameter {
+ public:
+ BinaryParameter(const char* name_, const char* desc_, const void* v, int l, Configuration* conf=0);
+ virtual ~BinaryParameter();
+ virtual bool setParam(const char* value);
+ virtual void setParam(const void* v, int l);
+ virtual char* getDefaultStr() const;
+ virtual char* getValueStr() const;
+
+ // getData() will return length zero if there is no data
+ // NB: data may be set to zero, OR set to a zero-length buffer
+ void getData(void** data, int* length) const;
+
+ protected:
+ char* value;
+ int length;
+ char* def_value;
+ int def_length;
+ };
+
+ // -=- ParameterIterator
+ // Iterates over all the Parameters in a Configuration group. The
+ // current Parameter is accessed via param, the current Configuration
+ // via config. The next() method moves on to the next Parameter.
+
+ struct ParameterIterator {
+ ParameterIterator(Configuration* c) : config(c), param(c ? c->head : 0) {}
+ void next() {
+ param = param->_next;
+ while (!param) {
+ config = config->_next;
+ if (!config) break;
+ param = config->head;
+ }
+ }
+ Configuration* config;
+ VoidParameter* param;
+ };
+
+};
+
+#endif // __RFB_CONFIGURATION_H__
diff --git a/common/rfb/ConnParams.cxx b/common/rfb/ConnParams.cxx
new file mode 100644
index 00000000..d4ae5894
--- /dev/null
+++ b/common/rfb/ConnParams.cxx
@@ -0,0 +1,125 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#include <rdr/InStream.h>
+#include <rdr/OutStream.h>
+#include <rfb/Exception.h>
+#include <rfb/encodings.h>
+#include <rfb/Encoder.h>
+#include <rfb/ConnParams.h>
+#include <rfb/util.h>
+
+using namespace rfb;
+
+ConnParams::ConnParams()
+ : majorVersion(0), minorVersion(0), width(0), height(0), useCopyRect(false),
+ supportsLocalCursor(false), supportsLocalXCursor(false), supportsDesktopResize(true),
+ supportsLastRect(false), customCompressLevel(false), compressLevel(6),
+ noJpeg(false), qualityLevel(-1),
+ name_(0), nEncodings_(0), encodings_(0),
+ currentEncoding_(encodingRaw), verStrPos(0)
+{
+ setName("");
+}
+
+ConnParams::~ConnParams()
+{
+ delete [] name_;
+ delete [] encodings_;
+}
+
+bool ConnParams::readVersion(rdr::InStream* is, bool* done)
+{
+ if (verStrPos >= 12) return false;
+ while (is->checkNoWait(1) && verStrPos < 12) {
+ verStr[verStrPos++] = is->readU8();
+ }
+
+ if (verStrPos < 12) {
+ *done = false;
+ return true;
+ }
+ *done = true;
+ verStr[12] = 0;
+ return (sscanf(verStr, "RFB %03d.%03d\n", &majorVersion,&minorVersion) == 2);
+}
+
+void ConnParams::writeVersion(rdr::OutStream* os)
+{
+ char str[13];
+ sprintf(str, "RFB %03d.%03d\n", majorVersion, minorVersion);
+ os->writeBytes(str, 12);
+ os->flush();
+}
+
+void ConnParams::setPF(const PixelFormat& pf)
+{
+ pf_ = pf;
+
+ if (pf.bpp != 8 && pf.bpp != 16 && pf.bpp != 32)
+ throw Exception("setPF: not 8, 16 or 32 bpp?");
+}
+
+void ConnParams::setName(const char* name)
+{
+ delete [] name_;
+ name_ = strDup(name);
+}
+
+void ConnParams::setEncodings(int nEncodings, const rdr::U32* encodings)
+{
+ if (nEncodings > nEncodings_) {
+ delete [] encodings_;
+ encodings_ = new rdr::U32[nEncodings];
+ }
+ nEncodings_ = nEncodings;
+ useCopyRect = false;
+ supportsLocalCursor = false;
+ supportsDesktopResize = false;
+ supportsLocalXCursor = false;
+ supportsLastRect = false;
+ customCompressLevel = false;
+ compressLevel = -1;
+ noJpeg = true;
+ qualityLevel = -1;
+ currentEncoding_ = encodingRaw;
+
+ for (int i = nEncodings-1; i >= 0; i--) {
+ encodings_[i] = encodings[i];
+
+ if (encodings[i] == encodingCopyRect)
+ useCopyRect = true;
+ else if (encodings[i] == pseudoEncodingCursor)
+ supportsLocalCursor = true;
+ else if (encodings[i] == pseudoEncodingXCursor)
+ supportsLocalXCursor = true;
+ else if (encodings[i] == pseudoEncodingDesktopSize)
+ supportsDesktopResize = true;
+ else if (encodings[i] == pseudoEncodingLastRect)
+ supportsLastRect = true;
+ else if (encodings[i] >= pseudoEncodingCompressLevel0 &&
+ encodings[i] <= pseudoEncodingCompressLevel9) {
+ customCompressLevel = true;
+ compressLevel = encodings[i] - pseudoEncodingCompressLevel0;
+ } else if (encodings[i] >= pseudoEncodingQualityLevel0 &&
+ encodings[i] <= pseudoEncodingQualityLevel9) {
+ noJpeg = false;
+ qualityLevel = encodings[i] - pseudoEncodingQualityLevel0;
+ } else if (encodings[i] <= encodingMax && Encoder::supported(encodings[i]))
+ currentEncoding_ = encodings[i];
+ }
+}
diff --git a/common/rfb/ConnParams.h b/common/rfb/ConnParams.h
new file mode 100644
index 00000000..47e6a5fb
--- /dev/null
+++ b/common/rfb/ConnParams.h
@@ -0,0 +1,93 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+//
+// ConnParams - structure containing the connection parameters.
+//
+
+#ifndef __RFB_CONNPARAMS_H__
+#define __RFB_CONNPARAMS_H__
+
+#include <rdr/types.h>
+#include <rfb/PixelFormat.h>
+
+namespace rdr { class InStream; }
+
+namespace rfb {
+
+ class ConnParams {
+ public:
+ ConnParams();
+ ~ConnParams();
+
+ bool readVersion(rdr::InStream* is, bool* done);
+ void writeVersion(rdr::OutStream* os);
+
+ int majorVersion;
+ int minorVersion;
+
+ void setVersion(int major, int minor) {
+ majorVersion = major; minorVersion = minor;
+ }
+ bool isVersion(int major, int minor) {
+ return majorVersion == major && minorVersion == minor;
+ }
+ bool beforeVersion(int major, int minor) {
+ return (majorVersion < major ||
+ (majorVersion == major && minorVersion < minor));
+ }
+ bool afterVersion(int major, int minor) {
+ return !beforeVersion(major,minor+1);
+ }
+
+ int width;
+ int height;
+
+ const PixelFormat& pf() { return pf_; }
+ void setPF(const PixelFormat& pf);
+
+ const char* name() { return name_; }
+ void setName(const char* name);
+
+ rdr::U32 currentEncoding() { return currentEncoding_; }
+ int nEncodings() { return nEncodings_; }
+ const rdr::U32* encodings() { return encodings_; }
+ void setEncodings(int nEncodings, const rdr::U32* encodings);
+ bool useCopyRect;
+
+ bool supportsLocalCursor;
+ bool supportsLocalXCursor;
+ bool supportsDesktopResize;
+ bool supportsLastRect;
+
+ bool customCompressLevel;
+ int compressLevel;
+ bool noJpeg;
+ int qualityLevel;
+
+ private:
+
+ PixelFormat pf_;
+ char* name_;
+ int nEncodings_;
+ rdr::U32* encodings_;
+ int currentEncoding_;
+ char verStr[13];
+ int verStrPos;
+ };
+}
+#endif
diff --git a/common/rfb/Cursor.cxx b/common/rfb/Cursor.cxx
new file mode 100644
index 00000000..c8dc341b
--- /dev/null
+++ b/common/rfb/Cursor.cxx
@@ -0,0 +1,179 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#include <string.h>
+#include <rfb/Cursor.h>
+#include <rfb/LogWriter.h>
+
+using namespace rfb;
+
+static LogWriter vlog("Cursor");
+
+void Cursor::setSize(int w, int h) {
+ int oldMaskLen = maskLen();
+ ManagedPixelBuffer::setSize(w, h);
+ if (maskLen() > oldMaskLen) {
+ delete [] mask.buf;
+ mask.buf = new rdr::U8[maskLen()];
+ }
+}
+
+void Cursor::drawOutline(const Pixel& c)
+{
+ Cursor outlined;
+
+ // Create a mirror of the existing cursor
+ outlined.setPF(getPF());
+ outlined.setSize(width(), height());
+ outlined.hotspot = hotspot;
+
+ // Clear the mirror's background to the outline colour
+ outlined.fillRect(getRect(), c);
+
+ // Blit the existing cursor, using its mask
+ outlined.maskRect(getRect(), data, mask.buf);
+
+ // Now just adjust the mask to add the outline. The outline pixels
+ // will already be the right colour. :)
+ int maskBytesPerRow = (width() + 7) / 8;
+ for (int y = 0; y < height(); y++) {
+ for (int byte=0; byte<maskBytesPerRow; byte++) {
+ rdr::U8 m8 = mask.buf[y*maskBytesPerRow + byte];
+
+ // Handle above & below outline
+ if (y > 0) m8 |= mask.buf[(y-1)*maskBytesPerRow + byte];
+ if (y < height()-1) m8 |= mask.buf[(y+1)*maskBytesPerRow + byte];
+
+ // Left outline
+ m8 |= mask.buf[y*maskBytesPerRow + byte] << 1;
+ if (byte < maskBytesPerRow-1)
+ m8 |= (mask.buf[y*maskBytesPerRow + byte + 1] >> 7) & 1;
+
+ // Right outline
+ m8 |= mask.buf[y*maskBytesPerRow + byte] >> 1;
+ if (byte > 0)
+ m8 |= (mask.buf[y*maskBytesPerRow + byte - 1] << 7) & 128;
+
+ outlined.mask.buf[y*maskBytesPerRow + byte] = m8;
+ }
+ }
+
+ // Replace the existing cursor & mask with the new one
+ delete [] data;
+ delete [] mask.buf;
+ data = outlined.data; outlined.data = 0;
+ mask.buf = outlined.mask.buf; outlined.mask.buf = 0;
+}
+
+rdr::U8* Cursor::getBitmap(Pixel* pix0, Pixel* pix1)
+{
+ bool gotPix0 = false;
+ bool gotPix1 = false;
+ *pix0 = *pix1 = 0;
+ rdr::U8Array source(maskLen());
+ memset(source.buf, 0, maskLen());
+
+ int maskBytesPerRow = (width() + 7) / 8;
+ for (int y = 0; y < height(); y++) {
+ for (int x = 0; x < width(); x++) {
+ int byte = y * maskBytesPerRow + x / 8;
+ int bit = 7 - x % 8;
+ if (mask.buf[byte] & (1 << bit)) {
+ Pixel pix=0;
+ switch (getPF().bpp) {
+ case 8: pix = ((rdr::U8*) data)[y * width() + x]; break;
+ case 16: pix = ((rdr::U16*)data)[y * width() + x]; break;
+ case 32: pix = ((rdr::U32*)data)[y * width() + x]; break;
+ }
+ if (!gotPix0 || pix == *pix0) {
+ gotPix0 = true;
+ *pix0 = pix;
+ } else if (!gotPix1 || pix == *pix1) {
+ gotPix1 = true;
+ *pix1 = pix;
+ source.buf[byte] |= (1 << bit);
+ } else {
+ // not a bitmap
+ return 0;
+ }
+ }
+ }
+ }
+ return source.takeBuf();
+}
+
+// crop() determines the "busy" rectangle for the cursor - the minimum bounding
+// rectangle containing actual pixels. This isn't the most efficient algorithm
+// but it's short. For sanity, we make sure that the busy rectangle always
+// includes the hotspot (the hotspot is unsigned on the wire so otherwise it
+// would cause problems if it was above or left of the actual pixels)
+
+void Cursor::crop()
+{
+ Rect busy = getRect().intersect(Rect(hotspot.x, hotspot.y,
+ hotspot.x+1, hotspot.y+1));
+ int maskBytesPerRow = (width() + 7) / 8;
+ int x, y;
+ for (y = 0; y < height(); y++) {
+ for (x = 0; x < width(); x++) {
+ int byte = y * maskBytesPerRow + x / 8;
+ int bit = 7 - x % 8;
+ if (mask.buf[byte] & (1 << bit)) {
+ if (x < busy.tl.x) busy.tl.x = x;
+ if (x+1 > busy.br.x) busy.br.x = x+1;
+ if (y < busy.tl.y) busy.tl.y = y;
+ if (y+1 > busy.br.y) busy.br.y = y+1;
+ }
+ }
+ }
+
+ if (width() == busy.width() && height() == busy.height()) return;
+
+ vlog.debug("cropping %dx%d to %dx%d", width(), height(),
+ busy.width(), busy.height());
+
+ // Copy the pixel data
+ int newDataLen = busy.area() * (getPF().bpp/8);
+ rdr::U8* newData = new rdr::U8[newDataLen];
+ getImage(newData, busy);
+
+ // Copy the mask
+ int newMaskBytesPerRow = (busy.width()+7)/8;
+ int newMaskLen = newMaskBytesPerRow * busy.height();
+ rdr::U8* newMask = new rdr::U8[newMaskLen];
+ memset(newMask, 0, newMaskLen);
+ for (y = 0; y < busy.height(); y++) {
+ int newByte, newBit;
+ for (x = 0; x < busy.width(); x++) {
+ int oldByte = (y+busy.tl.y) * maskBytesPerRow + (x+busy.tl.x) / 8;
+ int oldBit = 7 - (x+busy.tl.x) % 8;
+ newByte = y * newMaskBytesPerRow + x / 8;
+ newBit = 7 - x % 8;
+ if (mask.buf[oldByte] & (1 << oldBit))
+ newMask[newByte] |= (1 << newBit);
+ }
+ }
+
+ // Set the size and data to the new, cropped cursor.
+ setSize(busy.width(), busy.height());
+ hotspot = hotspot.subtract(busy.tl);
+ delete [] data;
+ delete [] mask.buf;
+ datasize = newDataLen;
+ data = newData;
+ mask.buf = newMask;
+}
diff --git a/common/rfb/Cursor.h b/common/rfb/Cursor.h
new file mode 100644
index 00000000..7d94d705
--- /dev/null
+++ b/common/rfb/Cursor.h
@@ -0,0 +1,56 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+//
+// Cursor - structure containing information describing
+// the current cursor shape
+//
+
+#ifndef __RFB_CURSOR_H__
+#define __RFB_CURSOR_H__
+
+#include <rfb/PixelBuffer.h>
+
+namespace rfb {
+
+ class Cursor : public ManagedPixelBuffer {
+ public:
+ Cursor() {}
+ rdr::U8Array mask;
+ Point hotspot;
+
+ int maskLen() { return (width() + 7) / 8 * height(); }
+
+ // setSize() resizes the cursor. The contents of the data and mask are
+ // undefined after this call.
+ virtual void setSize(int w, int h);
+
+ // drawOutline() adds an outline to the cursor in the given colour.
+ void drawOutline(const Pixel& c);
+
+ // getBitmap() tests whether the cursor is monochrome, and if so returns a
+ // bitmap together with background and foreground colours. The size and
+ // layout of the bitmap are the same as the mask.
+ rdr::U8* getBitmap(Pixel* pix0, Pixel* pix1);
+
+ // crop() crops the cursor down to the smallest possible size, based on the
+ // mask.
+ void crop();
+ };
+
+}
+#endif
diff --git a/common/rfb/Decoder.cxx b/common/rfb/Decoder.cxx
new file mode 100644
index 00000000..b6e4fd5b
--- /dev/null
+++ b/common/rfb/Decoder.cxx
@@ -0,0 +1,70 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#include <stdio.h>
+#include <rfb/Exception.h>
+#include <rfb/Decoder.h>
+#include <rfb/RawDecoder.h>
+#include <rfb/RREDecoder.h>
+#include <rfb/HextileDecoder.h>
+#include <rfb/ZRLEDecoder.h>
+#include <rfb/TightDecoder.h>
+
+using namespace rfb;
+
+Decoder::~Decoder()
+{
+}
+
+DecoderCreateFnType Decoder::createFns[encodingMax+1] = { 0 };
+
+bool Decoder::supported(unsigned int encoding)
+{
+ return encoding <= encodingMax && createFns[encoding];
+}
+
+Decoder* Decoder::createDecoder(unsigned int encoding, CMsgReader* reader)
+{
+ if (encoding <= encodingMax && createFns[encoding])
+ return (*createFns[encoding])(reader);
+ return 0;
+}
+
+void Decoder::registerDecoder(unsigned int encoding,
+ DecoderCreateFnType createFn)
+{
+ if (encoding > encodingMax)
+ throw Exception("Decoder::registerDecoder: encoding out of range");
+
+ if (createFns[encoding])
+ fprintf(stderr,"Replacing existing decoder for encoding %s (%d)\n",
+ encodingName(encoding), encoding);
+ createFns[encoding] = createFn;
+}
+
+int DecoderInit::count = 0;
+
+DecoderInit::DecoderInit()
+{
+ if (count++ != 0) return;
+
+ Decoder::registerDecoder(encodingRaw, RawDecoder::create);
+ Decoder::registerDecoder(encodingRRE, RREDecoder::create);
+ Decoder::registerDecoder(encodingHextile, HextileDecoder::create);
+ Decoder::registerDecoder(encodingZRLE, ZRLEDecoder::create);
+ Decoder::registerDecoder(encodingTight, TightDecoder::create);
+}
diff --git a/common/rfb/Decoder.h b/common/rfb/Decoder.h
new file mode 100644
index 00000000..3fdba537
--- /dev/null
+++ b/common/rfb/Decoder.h
@@ -0,0 +1,52 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#ifndef __RFB_DECODER_H__
+#define __RFB_DECODER_H__
+
+#include <rfb/Rect.h>
+#include <rfb/encodings.h>
+
+namespace rfb {
+ class CMsgReader;
+ class CMsgHandler;
+ class Decoder;
+ typedef Decoder* (*DecoderCreateFnType)(CMsgReader*);
+
+ class Decoder {
+ public:
+ virtual ~Decoder();
+ virtual void readRect(const Rect& r, CMsgHandler* handler)=0;
+
+ static bool supported(unsigned int encoding);
+ static Decoder* createDecoder(unsigned int encoding, CMsgReader* reader);
+ static void registerDecoder(unsigned int encoding,
+ DecoderCreateFnType createFn);
+ private:
+ static DecoderCreateFnType createFns[encodingMax+1];
+ };
+
+ class DecoderInit {
+ static int count;
+ public:
+ DecoderInit();
+ };
+
+ static DecoderInit decoderInitObj;
+}
+
+#endif
diff --git a/common/rfb/DirManager.h b/common/rfb/DirManager.h
new file mode 100644
index 00000000..c820f648
--- /dev/null
+++ b/common/rfb/DirManager.h
@@ -0,0 +1,42 @@
+/* Copyright (C) 2005 TightVNC Team. All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- DirManager.cxx
+
+#ifndef __RFB_DIRMANAGER_H__
+#define __RFB_DIRMANAGER_H__
+
+#include <rfb/FileInfo.h>
+
+namespace rfb {
+ class DirManager {
+ public:
+ virtual bool createDir(char *pFullPath) = 0;
+ virtual bool renameIt(char *pOldName, char *pNewName) = 0;
+ virtual bool deleteIt(char *pFullPath) = 0;
+
+ virtual bool getDirInfo(char *pPath, FileInfo *pFileInfo, unsigned int dirOnly) = 0;
+ };
+}
+
+#endif // __RFB_DIRMANAGER_H__ \ No newline at end of file
diff --git a/common/rfb/Encoder.cxx b/common/rfb/Encoder.cxx
new file mode 100644
index 00000000..53cb1709
--- /dev/null
+++ b/common/rfb/Encoder.cxx
@@ -0,0 +1,77 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#include <stdio.h>
+#include <rfb/Exception.h>
+#include <rfb/Encoder.h>
+#include <rfb/RawEncoder.h>
+#include <rfb/RREEncoder.h>
+#include <rfb/HextileEncoder.h>
+#include <rfb/ZRLEEncoder.h>
+#include <rfb/TightEncoder.h>
+
+using namespace rfb;
+
+Encoder::~Encoder()
+{
+}
+
+EncoderCreateFnType Encoder::createFns[encodingMax+1] = { 0 };
+
+bool Encoder::supported(unsigned int encoding)
+{
+ return encoding <= encodingMax && createFns[encoding];
+}
+
+Encoder* Encoder::createEncoder(unsigned int encoding, SMsgWriter* writer)
+{
+ if (encoding <= encodingMax && createFns[encoding])
+ return (*createFns[encoding])(writer);
+ return 0;
+}
+
+void Encoder::registerEncoder(unsigned int encoding,
+ EncoderCreateFnType createFn)
+{
+ if (encoding > encodingMax)
+ throw Exception("Encoder::registerEncoder: encoding out of range");
+
+ if (createFns[encoding])
+ fprintf(stderr,"Replacing existing encoder for encoding %s (%d)\n",
+ encodingName(encoding), encoding);
+ createFns[encoding] = createFn;
+}
+
+void Encoder::unregisterEncoder(unsigned int encoding)
+{
+ if (encoding > encodingMax)
+ throw Exception("Encoder::unregisterEncoder: encoding out of range");
+ createFns[encoding] = 0;
+}
+
+int EncoderInit::count = 0;
+
+EncoderInit::EncoderInit()
+{
+ if (count++ != 0) return;
+
+ Encoder::registerEncoder(encodingRaw, RawEncoder::create);
+ Encoder::registerEncoder(encodingRRE, RREEncoder::create);
+ Encoder::registerEncoder(encodingHextile, HextileEncoder::create);
+ Encoder::registerEncoder(encodingZRLE, ZRLEEncoder::create);
+ Encoder::registerEncoder(encodingTight, TightEncoder::create);
+}
diff --git a/common/rfb/Encoder.h b/common/rfb/Encoder.h
new file mode 100644
index 00000000..df50dd6d
--- /dev/null
+++ b/common/rfb/Encoder.h
@@ -0,0 +1,61 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#ifndef __RFB_ENCODER_H__
+#define __RFB_ENCODER_H__
+
+#include <rfb/Rect.h>
+#include <rfb/encodings.h>
+
+namespace rfb {
+ class SMsgWriter;
+ class Encoder;
+ class ImageGetter;
+ typedef Encoder* (*EncoderCreateFnType)(SMsgWriter*);
+
+ class Encoder {
+ public:
+ virtual ~Encoder();
+
+ virtual void setCompressLevel(int level) {};
+ virtual void setQualityLevel(int level) {};
+ virtual int getNumRects(const Rect &r) { return 1; }
+
+ // writeRect() tries to write the given rectangle. If it is unable to
+ // write the whole rectangle it returns false and sets actual to the actual
+ // rectangle which was updated.
+ virtual bool writeRect(const Rect& r, ImageGetter* ig, Rect* actual)=0;
+
+ static bool supported(unsigned int encoding);
+ static Encoder* createEncoder(unsigned int encoding, SMsgWriter* writer);
+ static void registerEncoder(unsigned int encoding,
+ EncoderCreateFnType createFn);
+ static void unregisterEncoder(unsigned int encoding);
+ private:
+ static EncoderCreateFnType createFns[encodingMax+1];
+ };
+
+ class EncoderInit {
+ static int count;
+ public:
+ EncoderInit();
+ };
+
+ static EncoderInit encoderInitObj;
+}
+
+#endif
diff --git a/common/rfb/Exception.h b/common/rfb/Exception.h
new file mode 100644
index 00000000..7c2cbcaa
--- /dev/null
+++ b/common/rfb/Exception.h
@@ -0,0 +1,37 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#ifndef __RFB_EXCEPTION_H__
+#define __RFB_EXCEPTION_H__
+
+#include <rdr/Exception.h>
+
+namespace rfb {
+ typedef rdr::Exception Exception;
+ struct AuthFailureException : public Exception {
+ AuthFailureException(const char* s="Authentication failure")
+ : Exception(s) {}
+ };
+ struct AuthCancelledException : public rfb::Exception {
+ AuthCancelledException(const char* s="Authentication cancelled")
+ : Exception(s) {}
+ };
+ struct ConnFailedException : public Exception {
+ ConnFailedException(const char* s="Connection failed") : Exception(s) {}
+ };
+}
+#endif
diff --git a/common/rfb/FileInfo.cxx b/common/rfb/FileInfo.cxx
new file mode 100644
index 00000000..e97e0adb
--- /dev/null
+++ b/common/rfb/FileInfo.cxx
@@ -0,0 +1,244 @@
+/* Copyright (C) 2005 TightVNC Team. All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+#include <rfb/FileInfo.h>
+#include <rfb/util.h>
+
+#ifdef _WIN32
+#define strcasecmp _stricmp
+#endif
+
+using namespace rfb;
+
+// FIXME: Under Unix, file names are case-sensitive.
+
+int
+CompareFileInfo(const void *F, const void *S)
+{
+ FILEINFO *pF = (FILEINFO *) F;
+ FILEINFO *pS = (FILEINFO *) S;
+ if (pF->info.flags == pS->info.flags) {
+ return strcasecmp(pF->name, pS->name);
+ } else {
+ if (pF->info.flags == FT_ATTR_DIR) return -1;
+ if (pS->info.flags == FT_ATTR_DIR)
+ return 1;
+ else
+ return strcasecmp(pF->name, pS->name);
+ }
+
+ return 0;
+}
+
+FileInfo::FileInfo()
+{
+ m_numEntries = 0;
+ m_pEntries = NULL;
+}
+
+FileInfo::~FileInfo()
+{
+ free();
+}
+
+void
+FileInfo::add(FileInfo *pFI)
+{
+ m_numEntries = pFI->getNumEntries();
+ FILEINFO *pTemporary = new FILEINFO[m_numEntries];
+ memcpy(pTemporary, pFI->getNameAt(0), m_numEntries * sizeof(FILEINFO));
+
+ m_pEntries = pTemporary;
+ pTemporary = NULL;
+}
+
+void
+FileInfo::add(FILEINFO *pFIStruct)
+{
+ add(pFIStruct->name, pFIStruct->info.size, pFIStruct->info.data, pFIStruct->info.flags);
+}
+
+void
+FileInfo::add(char *pName, unsigned int size, unsigned int data, unsigned int flags)
+{
+ FILEINFO *pTemporary = new FILEINFO[m_numEntries + 1];
+ if (m_numEntries != 0)
+ memcpy(pTemporary, m_pEntries, m_numEntries * sizeof(FILEINFO));
+ strcpy(pTemporary[m_numEntries].name, pName);
+ pTemporary[m_numEntries].info.size = size;
+ pTemporary[m_numEntries].info.data = data;
+ pTemporary[m_numEntries].info.flags = flags;
+ if (m_pEntries != NULL) {
+ delete [] m_pEntries;
+ m_pEntries = NULL;
+ }
+ m_pEntries = pTemporary;
+ pTemporary = NULL;
+ m_numEntries++;
+}
+
+char *
+FileInfo::getNameAt(unsigned int number)
+{
+ if ((number >= 0) && (number < m_numEntries)) {
+ return m_pEntries[number].name;
+ }
+ return NULL;
+}
+
+bool
+FileInfo::setNameAt(unsigned int number, char *pName)
+{
+ if ((number >= 0) && (number < m_numEntries)) {
+ strcpy(m_pEntries[number].name, pName);
+ return true;
+ }
+ return false;
+}
+
+unsigned int
+FileInfo::getSizeAt(unsigned int number)
+{
+ if ((number >= 0) && (number < m_numEntries)) {
+ return m_pEntries[number].info.size;
+ }
+ return 0;
+}
+
+unsigned int
+FileInfo::getDataAt(unsigned int number)
+{
+ if ((number >= 0) && (number < m_numEntries)) {
+ return m_pEntries[number].info.data;
+ }
+ return 0;
+}
+
+unsigned int
+FileInfo::getFlagsAt(unsigned int number)
+{
+ if ((number >= 0) && (number < m_numEntries)) {
+ return m_pEntries[number].info.flags;
+ }
+ return 0;
+}
+
+FILEINFO *
+FileInfo::getFullDataAt(unsigned int number)
+{
+ if ((number >= 0) && (number < m_numEntries)) {
+ return &m_pEntries[number];
+ }
+ return NULL;
+}
+
+bool
+FileInfo::setSizeAt(unsigned int number, unsigned int value)
+{
+ if ((number >= 0) && (number < m_numEntries)) {
+ m_pEntries[number].info.size = value;
+ return true;
+ }
+ return false;
+}
+
+bool
+FileInfo::setDataAt(unsigned int number, unsigned int value)
+{
+ if ((number >= 0) && (number < m_numEntries)) {
+ m_pEntries[number].info.data = value;
+ return true;
+ }
+ return false;
+}
+
+bool
+FileInfo::setFlagsAt(unsigned int number, unsigned int value)
+{
+ if ((number >= 0) && (number < m_numEntries)) {
+ m_pEntries[number].info.flags = value;
+ return true;
+ }
+ return false;
+}
+
+bool
+FileInfo::deleteAt(unsigned int number)
+{
+ if ((number >= m_numEntries) || (number < 0)) return false;
+
+ FILEINFO *pTemporary = new FILEINFO[m_numEntries - 1];
+
+ if (number == 0) {
+ memcpy(pTemporary, &m_pEntries[1], (m_numEntries - 1) * sizeof(FILEINFO));
+ } else {
+ memcpy(pTemporary, m_pEntries, number * sizeof(FILEINFO));
+ if (number != (m_numEntries - 1))
+ memcpy(&pTemporary[number], &m_pEntries[number + 1], (m_numEntries - number - 1) * sizeof(FILEINFO));
+ }
+
+ if (m_pEntries != NULL) {
+ delete [] m_pEntries;
+ m_pEntries = NULL;
+ }
+ m_pEntries = pTemporary;
+ pTemporary = NULL;
+ m_numEntries--;
+ return true;
+}
+
+unsigned int
+FileInfo::getNumEntries()
+{
+ return m_numEntries;
+}
+
+void
+FileInfo::sort()
+{
+ qsort(m_pEntries, m_numEntries, sizeof(FILEINFO), CompareFileInfo);
+}
+
+void
+FileInfo::free()
+{
+ if (m_pEntries != NULL) {
+ delete [] m_pEntries;
+ m_pEntries = NULL;
+ }
+ m_numEntries = 0;
+}
+
+unsigned int
+FileInfo::getFilenamesSize()
+{
+ if (getNumEntries() == 0) return 0;
+
+ unsigned int filenamesSize = 0;
+
+ for (unsigned int i = 0; i < getNumEntries(); i++) {
+ filenamesSize += strlen(getNameAt(i));
+ }
+
+ return filenamesSize;
+}
diff --git a/common/rfb/FileInfo.h b/common/rfb/FileInfo.h
new file mode 100644
index 00000000..270eeee9
--- /dev/null
+++ b/common/rfb/FileInfo.h
@@ -0,0 +1,74 @@
+/* Copyright (C) 2005 TightVNC Team. All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- FileInfo.
+
+#ifndef __RFB_FILEINFO_H__
+#define __RFB_FILEINFO_H__
+
+#include <stdlib.h>
+
+#include <rfb/fttypes.h>
+
+namespace rfb {
+ class FileInfo
+ {
+ public:
+ void add(FileInfo *pFI);
+ void add(FILEINFO *pFIStruct);
+ void add(char *pName, unsigned int size, unsigned int data, unsigned int flags);
+
+ char *getNameAt(unsigned int number);
+
+ bool setNameAt(unsigned int number, char *pName);
+
+ unsigned int getSizeAt(unsigned int number);
+ unsigned int getDataAt(unsigned int number);
+ unsigned int getFlagsAt(unsigned int number);
+
+ FILEINFO *getFullDataAt(unsigned int number);
+
+ bool setSizeAt(unsigned int number, unsigned int value);
+ bool setDataAt(unsigned int number, unsigned int value);
+ bool setFlagsAt(unsigned int number, unsigned int value);
+
+ bool deleteAt(unsigned int number);
+
+ unsigned int getNumEntries();
+
+ unsigned int getFilenamesSize();
+
+ void sort();
+ void free();
+
+ FileInfo();
+ ~FileInfo();
+
+ private:
+ FILEINFO *m_pEntries;
+ unsigned int m_numEntries;
+
+ };
+}
+
+#endif // __RFB_FILEINFO_H__
diff --git a/common/rfb/FileManager.cxx b/common/rfb/FileManager.cxx
new file mode 100644
index 00000000..74cbd452
--- /dev/null
+++ b/common/rfb/FileManager.cxx
@@ -0,0 +1,81 @@
+/* Copyright (C) 2005 TightVNC Team. All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- FileManager.cxx
+
+#include <rfb/FileManager.h>
+
+using namespace rfb;
+
+FileManager::FileManager()
+{
+ m_pFile = NULL;
+}
+
+FileManager::~FileManager()
+{
+ close();
+}
+
+bool
+FileManager::create(char *pFilename)
+{
+ if (m_pFile != NULL) return false;
+
+ strcpy(m_szFilename, pFilename);
+
+ m_pFile = fopen(m_szFilename, m_szMode);
+
+ if (m_pFile == NULL) {
+ return false;
+ } else {
+ return true;
+ }
+}
+
+bool
+FileManager::close()
+{
+ if (m_pFile == NULL) return false;
+
+ int result = fclose(m_pFile);
+
+ if (result != 0) {
+ return false;
+ } else {
+ m_pFile = NULL;
+ return true;
+ }
+}
+
+bool
+FileManager::isCreated()
+{
+ if (m_pFile != NULL) return true; else return false;
+}
+
+char *
+FileManager::getFilename()
+{
+ return m_szFilename;
+}
diff --git a/common/rfb/FileManager.h b/common/rfb/FileManager.h
new file mode 100644
index 00000000..4fd736f8
--- /dev/null
+++ b/common/rfb/FileManager.h
@@ -0,0 +1,50 @@
+/* Copyright (C) 2005 TightVNC Team. All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- FileManager.
+
+#ifndef __RFB_FILEMANAGER_H__
+#define __RFB_FILEMANAGER_H__
+
+#include <rfb/fttypes.h>
+
+namespace rfb {
+ class FileManager {
+ public:
+ FileManager();
+ ~FileManager();
+
+ bool create(char *pFilename);
+ bool close();
+
+ bool isCreated();
+
+ char *getFilename();
+
+ protected:
+ FILE *m_pFile;
+ char m_szMode[4];
+ char m_szFilename[FT_FILENAME_SIZE];
+ };
+}
+#endif // __RFB_FILEMANAGER_H__
diff --git a/common/rfb/FileReader.cxx b/common/rfb/FileReader.cxx
new file mode 100644
index 00000000..a8cd2724
--- /dev/null
+++ b/common/rfb/FileReader.cxx
@@ -0,0 +1,51 @@
+/* Copyright (C) 2005 TightVNC Team. All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- FileReader.cxx
+
+#include <rfb/FileReader.h>
+
+using namespace rfb;
+
+FileReader::FileReader()
+{
+ strcpy(m_szMode, "rb");
+}
+
+bool
+FileReader::read(void *pBuf, unsigned int count, unsigned int *pBytesRead)
+{
+ if (!isCreated()) return false;
+
+ *pBytesRead = fread(pBuf, 1, count, m_pFile);
+
+ if (ferror(m_pFile)) return false;
+
+ return true;
+}
+
+unsigned int
+FileReader::getTime()
+{
+ return 0;
+}
diff --git a/common/rfb/FileReader.h b/common/rfb/FileReader.h
new file mode 100644
index 00000000..0c985d82
--- /dev/null
+++ b/common/rfb/FileReader.h
@@ -0,0 +1,41 @@
+/* Copyright (C) 2005 TightVNC Team. All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- FileReader.h
+
+#ifndef __RFB_FILEREADER_H__
+#define __RFB_FILEREADER_H__
+
+#include <rfb/FileManager.h>
+
+namespace rfb {
+ class FileReader : public FileManager {
+ public:
+ FileReader();
+
+ bool read(void *pBuf, unsigned int count, unsigned int *pBytesRead);
+
+ unsigned int getTime();
+ };
+}
+#endif // __RFB_FILEREADER_H__
diff --git a/common/rfb/FileWriter.cxx b/common/rfb/FileWriter.cxx
new file mode 100644
index 00000000..2bed5765
--- /dev/null
+++ b/common/rfb/FileWriter.cxx
@@ -0,0 +1,52 @@
+/* Copyright (C) 2005 TightVNC Team. All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- FileWriter.cxx
+
+#include <rfb/FileWriter.h>
+
+using namespace rfb;
+
+FileWriter::FileWriter()
+{
+ strcpy(m_szMode, "wb");
+}
+
+bool
+FileWriter::write(const void *pBuf, unsigned int count, unsigned int *pBytesWritten)
+{
+ if (!isCreated()) return false;
+
+ unsigned int bytesWritten = fwrite(pBuf, 1, count, m_pFile);
+
+ if (ferror(m_pFile)) return false;
+
+ *pBytesWritten = bytesWritten;
+ return true;
+}
+
+bool
+FileWriter::setTime(unsigned int modTime)
+{
+ return false;
+}
diff --git a/common/rfb/FileWriter.h b/common/rfb/FileWriter.h
new file mode 100644
index 00000000..73094a7e
--- /dev/null
+++ b/common/rfb/FileWriter.h
@@ -0,0 +1,41 @@
+/* Copyright (C) 2005 TightVNC Team. All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- FileWriter.h
+
+#ifndef __RFB_FILEWRITER_H__
+#define __RFB_FILEWRITER_H__
+
+#include <rfb/FileManager.h>
+
+namespace rfb {
+ class FileWriter : public FileManager {
+ public:
+ FileWriter();
+
+ bool write(const void *pBuf, unsigned int count, unsigned int *pBytesWritten);
+ bool setTime(unsigned int modTime);
+ };
+}
+
+#endif // __RFB_FILEWRITER_H__
diff --git a/common/rfb/HTTPServer.cxx b/common/rfb/HTTPServer.cxx
new file mode 100644
index 00000000..e40d4802
--- /dev/null
+++ b/common/rfb/HTTPServer.cxx
@@ -0,0 +1,411 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#include <rfb/HTTPServer.h>
+#include <rfb/LogWriter.h>
+#include <rfb/util.h>
+#include <rdr/MemOutStream.h>
+
+#ifdef WIN32
+#define strcasecmp _stricmp
+#endif
+
+
+using namespace rfb;
+using namespace rdr;
+
+static LogWriter vlog("HTTPServer");
+
+const int clientWaitTimeMillis = 20000;
+const int idleTimeoutSecs = 5 * 60;
+
+
+//
+// -=- LineReader
+// Helper class which is repeatedly called until a line has been read
+// (lines end in \n or \r\n).
+// Returns true when line complete, and resets internal state so that
+// next read() call will start reading a new line.
+// Only one buffer is kept - process line before reading next line!
+//
+
+class LineReader : public CharArray {
+public:
+ LineReader(InStream& is_, int l)
+ : CharArray(l), is(is_), pos(0), len(l), bufferOverrun(false) {}
+
+ // Returns true if line complete, false otherwise
+ bool read() {
+ while (is.checkNoWait(1)) {
+ char c = is.readU8();
+
+ if (c == '\n') {
+ if (pos && (buf[pos-1] == '\r'))
+ pos--;
+ bufferOverrun = false;
+ buf[pos++] = 0;
+ pos = 0;
+ return true;
+ }
+
+ if (pos == (len-1)) {
+ bufferOverrun = true;
+ buf[pos] = 0;
+ return true;
+ }
+
+ buf[pos++] = c;
+ }
+
+ return false;
+ }
+ bool didBufferOverrun() const {return bufferOverrun;}
+protected:
+ InStream& is;
+ int pos, len;
+ bool bufferOverrun;
+};
+
+
+//
+// -=- HTTPServer::Session
+// Manages the internal state for an HTTP session.
+// processHTTP returns true when request has completed,
+// indicating that socket & session data can be deleted.
+//
+
+class rfb::HTTPServer::Session {
+public:
+ Session(network::Socket& s, rfb::HTTPServer& srv)
+ : contentType(0), contentLength(-1), lastModified(-1),
+ line(s.inStream(), 256), sock(s),
+ server(srv), state(ReadRequestLine), lastActive(time(0)) {
+ }
+ ~Session() {
+ }
+
+ void writeResponse(int result, const char* text);
+ bool writeResponse(int code);
+
+ bool processHTTP();
+
+ network::Socket* getSock() const {return &sock;}
+
+ int checkIdleTimeout();
+protected:
+ CharArray uri;
+ const char* contentType;
+ int contentLength;
+ time_t lastModified;
+ LineReader line;
+ network::Socket& sock;
+ rfb::HTTPServer& server;
+ enum {ReadRequestLine, ReadHeaders, WriteResponse} state;
+ enum {GetRequest, HeadRequest} request;
+ time_t lastActive;
+};
+
+
+// - Internal helper routines
+
+void
+copyStream(InStream& is, OutStream& os) {
+ try {
+ while (1) {
+ os.writeU8(is.readU8());
+ }
+ } catch (rdr::EndOfStream) {
+ }
+}
+
+void writeLine(OutStream& os, const char* text) {
+ os.writeBytes(text, strlen(text));
+ os.writeBytes("\r\n", 2);
+}
+
+
+// - Write an HTTP-compliant response to the client
+
+
+void
+HTTPServer::Session::writeResponse(int result, const char* text) {
+ char buffer[1024];
+ if (strlen(text) > 512)
+ throw new rdr::Exception("Internal error - HTTP response text too big");
+ sprintf(buffer, "%s %d %s", "HTTP/1.1", result, text);
+ OutStream& os=sock.outStream();
+ writeLine(os, buffer);
+ writeLine(os, "Server: TightVNC/4.0");
+ time_t now = time(0);
+ struct tm* tm = gmtime(&now);
+ strftime(buffer, 1024, "Date: %a, %d %b %Y %H:%M:%S GMT", tm);
+ writeLine(os, buffer);
+ if (lastModified == (time_t)-1 || lastModified == 0)
+ lastModified = now;
+ tm = gmtime(&lastModified);
+ strftime(buffer, 1024, "Last-Modified: %a, %d %b %Y %H:%M:%S GMT", tm);
+ writeLine(os, buffer);
+ if (contentLength != -1) {
+ sprintf(buffer,"Content-Length: %d",contentLength);
+ writeLine(os, buffer);
+ }
+ writeLine(os, "Connection: close");
+ os.writeBytes("Content-Type: ", 14);
+ if (result == 200) {
+ if (!contentType)
+ contentType = guessContentType(uri.buf, "text/html");
+ os.writeBytes(contentType, strlen(contentType));
+ } else {
+ os.writeBytes("text/html", 9);
+ }
+ os.writeBytes("\r\n", 2);
+ writeLine(os, "");
+ if (result != 200) {
+ writeLine(os, "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">");
+ writeLine(os, "<HTML><HEAD>");
+ sprintf(buffer, "<TITLE>%d %s</TITLE>", result, text);
+ writeLine(os, buffer);
+ writeLine(os, "</HEAD><BODY><H1>");
+ writeLine(os, text);
+ writeLine(os, "</H1></BODY></HTML>");
+ sock.outStream().flush();
+ }
+}
+
+bool
+HTTPServer::Session::writeResponse(int code) {
+ switch (code) {
+ case 200: writeResponse(code, "OK"); break;
+ case 400: writeResponse(code, "Bad Request"); break;
+ case 404: writeResponse(code, "Not Found"); break;
+ case 501: writeResponse(code, "Not Implemented"); break;
+ default: writeResponse(500, "Unknown Error"); break;
+ };
+
+ // This return code is passed straight out of processHTTP().
+ // true indicates that the request has been completely processed.
+ return true;
+}
+
+// - Main HTTP request processing routine
+
+bool
+HTTPServer::Session::processHTTP() {
+ lastActive = time(0);
+
+ while (sock.inStream().checkNoWait(1)) {
+
+ switch (state) {
+
+ // Reading the Request-Line
+ case ReadRequestLine:
+
+ // Either read a line, or run out of incoming data
+ if (!line.read())
+ return false;
+
+ // We have read a line! Skip it if it's blank
+ if (strlen(line.buf) == 0)
+ continue;
+
+ // The line contains a request to process.
+ {
+ char method[16], path[128], version[16];
+ int matched = sscanf(line.buf, "%15s%127s%15s",
+ method, path, version);
+ if (matched != 3)
+ return writeResponse(400);
+
+ // Store the required "method"
+ if (strcmp(method, "GET") == 0)
+ request = GetRequest;
+ else if (strcmp(method, "HEAD") == 0)
+ request = HeadRequest;
+ else
+ return writeResponse(501);
+
+ // Store the URI to the "document"
+ uri.buf = strDup(path);
+ }
+
+ // Move on to reading the request headers
+ state = ReadHeaders;
+ break;
+
+ // Reading the request headers
+ case ReadHeaders:
+
+ // Try to read a line
+ if (!line.read())
+ return false;
+
+ // Skip headers until we hit a blank line
+ if (strlen(line.buf) != 0)
+ continue;
+
+ // Headers ended - write the response!
+ {
+ CharArray address(sock.getPeerAddress());
+ vlog.info("getting %s for %s", uri.buf, address.buf);
+ contentLength = -1;
+ lastModified = -1;
+ InStream* data = server.getFile(uri.buf, &contentType, &contentLength,
+ &lastModified);
+ if (!data)
+ return writeResponse(404);
+
+ try {
+ writeResponse(200);
+ if (request == GetRequest)
+ copyStream(*data, sock.outStream());
+ sock.outStream().flush();
+ } catch (rdr::Exception& e) {
+ vlog.error("error writing HTTP document:%s", e.str());
+ }
+ delete data;
+ }
+
+ // The operation is complete!
+ return true;
+
+ default:
+ throw rdr::Exception("invalid HTTPSession state!");
+ };
+
+ }
+
+ // Indicate that we're still processing the HTTP request.
+ return false;
+}
+
+int HTTPServer::Session::checkIdleTimeout() {
+ time_t now = time(0);
+ int timeout = (lastActive + idleTimeoutSecs) - now;
+ if (timeout > 0)
+ return secsToMillis(timeout);
+ sock.shutdown();
+ return 0;
+}
+
+// -=- Constructor / destructor
+
+HTTPServer::HTTPServer() {
+}
+
+HTTPServer::~HTTPServer() {
+ std::list<Session*>::iterator i;
+ for (i=sessions.begin(); i!=sessions.end(); i++)
+ delete *i;
+}
+
+
+// -=- SocketServer interface implementation
+
+void
+HTTPServer::addSocket(network::Socket* sock, bool) {
+ Session* s = new Session(*sock, *this);
+ if (!s) {
+ sock->shutdown();
+ } else {
+ sock->inStream().setTimeout(clientWaitTimeMillis);
+ sock->outStream().setTimeout(clientWaitTimeMillis);
+ sessions.push_front(s);
+ }
+}
+
+void
+HTTPServer::removeSocket(network::Socket* sock) {
+ std::list<Session*>::iterator i;
+ for (i=sessions.begin(); i!=sessions.end(); i++) {
+ if ((*i)->getSock() == sock) {
+ delete *i;
+ sessions.erase(i);
+ return;
+ }
+ }
+}
+
+void
+HTTPServer::processSocketEvent(network::Socket* sock) {
+ std::list<Session*>::iterator i;
+ for (i=sessions.begin(); i!=sessions.end(); i++) {
+ if ((*i)->getSock() == sock) {
+ try {
+ if ((*i)->processHTTP()) {
+ vlog.info("completed HTTP request");
+ sock->shutdown();
+ }
+ } catch (rdr::Exception& e) {
+ vlog.error("untrapped: %s", e.str());
+ sock->shutdown();
+ }
+ return;
+ }
+ }
+ throw rdr::Exception("invalid Socket in HTTPServer");
+}
+
+void HTTPServer::getSockets(std::list<network::Socket*>* sockets)
+{
+ sockets->clear();
+ std::list<Session*>::iterator ci;
+ for (ci = sessions.begin(); ci != sessions.end(); ci++) {
+ sockets->push_back((*ci)->getSock());
+ }
+}
+
+int HTTPServer::checkTimeouts() {
+ std::list<Session*>::iterator ci;
+ int timeout = 0;
+ for (ci = sessions.begin(); ci != sessions.end(); ci++) {
+ soonestTimeout(&timeout, (*ci)->checkIdleTimeout());
+ }
+ return timeout;
+}
+
+
+// -=- Default getFile implementation
+
+InStream*
+HTTPServer::getFile(const char* name, const char** contentType,
+ int* contentLength, time_t* lastModified)
+{
+ return 0;
+}
+
+const char*
+HTTPServer::guessContentType(const char* name, const char* defType) {
+ CharArray file, ext;
+ if (!strSplit(name, '.', &file.buf, &ext.buf))
+ return defType;
+ if (strcasecmp(ext.buf, "html") == 0 ||
+ strcasecmp(ext.buf, "htm") == 0) {
+ return "text/html";
+ } else if (strcasecmp(ext.buf, "txt") == 0) {
+ return "text/plain";
+ } else if (strcasecmp(ext.buf, "gif") == 0) {
+ return "image/gif";
+ } else if (strcasecmp(ext.buf, "jpg") == 0) {
+ return "image/jpeg";
+ } else if (strcasecmp(ext.buf, "jar") == 0) {
+ return "application/java-archive";
+ } else if (strcasecmp(ext.buf, "exe") == 0) {
+ return "application/octet-stream";
+ }
+ return defType;
+}
diff --git a/common/rfb/HTTPServer.h b/common/rfb/HTTPServer.h
new file mode 100644
index 00000000..6412946a
--- /dev/null
+++ b/common/rfb/HTTPServer.h
@@ -0,0 +1,110 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- HTTPServer.h
+
+// Single-threaded HTTP server implementation.
+// All I/O is handled by the processSocketEvent routine,
+// which is called by the main-loop of the VNC server whenever
+// there is an event on an HTTP socket.
+
+#ifndef __RFB_HTTP_SERVER_H__
+#define __RFB_HTTP_SERVER_H__
+
+#include <list>
+
+#include <rdr/MemInStream.h>
+#include <rfb/UpdateTracker.h>
+#include <rfb/Configuration.h>
+#include <network/Socket.h>
+#include <time.h>
+
+namespace rfb {
+
+ class HTTPServer : public network::SocketServer {
+ public:
+ // -=- Constructors
+
+ // - HTTPServer(files)
+ // Create an HTTP server which will use the getFile method
+ // to satisfy HTTP GET requests.
+ HTTPServer();
+
+ virtual ~HTTPServer();
+
+ // SocketServer interface
+
+ // addSocket()
+ // This causes the server to perform HTTP protocol on the
+ // supplied socket.
+ virtual void addSocket(network::Socket* sock, bool outgoing=false);
+
+ // removeSocket()
+ // Could clean up socket-specific resources here.
+ virtual void removeSocket(network::Socket* sock);
+
+ // processSocketEvent()
+ // The platform-specific side of the server implementation calls
+ // this method whenever data arrives on one of the active
+ // network sockets.
+ virtual void processSocketEvent(network::Socket* sock);
+
+ // Check for socket timeouts
+ virtual int checkTimeouts();
+
+
+ // getSockets() gets a list of sockets. This can be used to generate an
+ // fd_set for calling select().
+
+ virtual void getSockets(std::list<network::Socket*>* sockets);
+
+
+ // -=- File interface
+
+ // - getFile is passed the path portion of a URL and returns an
+ // InStream containing the data to return. If the requested
+ // file is available then the contentType should be set to the
+ // type of the file, or left untouched if the file type is to
+ // be determined automatically by HTTPServer.
+ // If the file is not available then null is returned.
+ // Overridden getFile functions should call the default version
+ // if they do not recognise a path name.
+ // NB: The caller assumes ownership of the returned InStream.
+ // NB: The contentType is statically allocated by the getFile impl.
+ // NB: contentType is *guaranteed* to be valid when getFile is called.
+
+ virtual rdr::InStream* getFile(const char* name, const char** contentType,
+ int* contentLength, time_t* lastModified);
+
+ // - guessContentType is passed the name of a file and returns the
+ // name of an HTTP content type, based on the file's extension. If
+ // the extension isn't recognised then defType is returned. This can
+ // be used from getFile to easily default to the supplied contentType,
+ // or by passing zero in to determine whether a type is recognised or
+ // not.
+
+ static const char* guessContentType(const char* name, const char* defType);
+
+ protected:
+ class Session;
+ std::list<Session*> sessions;
+ };
+}
+
+#endif
+
diff --git a/common/rfb/HextileDecoder.cxx b/common/rfb/HextileDecoder.cxx
new file mode 100644
index 00000000..e817c732
--- /dev/null
+++ b/common/rfb/HextileDecoder.cxx
@@ -0,0 +1,59 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#include <rfb/CMsgReader.h>
+#include <rfb/CMsgHandler.h>
+#include <rfb/HextileDecoder.h>
+
+using namespace rfb;
+
+#define EXTRA_ARGS CMsgHandler* handler
+#define FILL_RECT(r, p) handler->fillRect(r, p)
+#define IMAGE_RECT(r, p) handler->imageRect(r, p)
+#define BPP 8
+#include <rfb/hextileDecode.h>
+#undef BPP
+#define BPP 16
+#include <rfb/hextileDecode.h>
+#undef BPP
+#define BPP 32
+#include <rfb/hextileDecode.h>
+#undef BPP
+
+Decoder* HextileDecoder::create(CMsgReader* reader)
+{
+ return new HextileDecoder(reader);
+}
+
+HextileDecoder::HextileDecoder(CMsgReader* reader_) : reader(reader_)
+{
+}
+
+HextileDecoder::~HextileDecoder()
+{
+}
+
+void HextileDecoder::readRect(const Rect& r, CMsgHandler* handler)
+{
+ rdr::InStream* is = reader->getInStream();
+ rdr::U8* buf = reader->getImageBuf(16 * 16 * 4);
+ switch (reader->bpp()) {
+ case 8: hextileDecode8 (r, is, (rdr::U8*) buf, handler); break;
+ case 16: hextileDecode16(r, is, (rdr::U16*)buf, handler); break;
+ case 32: hextileDecode32(r, is, (rdr::U32*)buf, handler); break;
+ }
+}
diff --git a/common/rfb/HextileDecoder.h b/common/rfb/HextileDecoder.h
new file mode 100644
index 00000000..e7dd3d58
--- /dev/null
+++ b/common/rfb/HextileDecoder.h
@@ -0,0 +1,35 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#ifndef __RFB_HEXTILEDECODER_H__
+#define __RFB_HEXTILEDECODER_H__
+
+#include <rfb/Decoder.h>
+
+namespace rfb {
+
+ class HextileDecoder : public Decoder {
+ public:
+ static Decoder* create(CMsgReader* reader);
+ virtual void readRect(const Rect& r, CMsgHandler* handler);
+ virtual ~HextileDecoder();
+ private:
+ HextileDecoder(CMsgReader* reader);
+ CMsgReader* reader;
+ };
+}
+#endif
diff --git a/common/rfb/HextileEncoder.cxx b/common/rfb/HextileEncoder.cxx
new file mode 100644
index 00000000..ba71d56d
--- /dev/null
+++ b/common/rfb/HextileEncoder.cxx
@@ -0,0 +1,90 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ * Copyright (C) 2005 Constantin Kaplinsky. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#include <rfb/ImageGetter.h>
+#include <rfb/encodings.h>
+#include <rfb/SMsgWriter.h>
+#include <rfb/HextileEncoder.h>
+#include <rfb/Configuration.h>
+
+using namespace rfb;
+
+BoolParameter improvedHextile("ImprovedHextile",
+ "Use improved compression algorithm for Hextile "
+ "encoding which achieves better compression "
+ "ratios by the cost of using more CPU time",
+ true);
+
+#define EXTRA_ARGS ImageGetter* ig
+#define GET_IMAGE_INTO_BUF(r,buf) ig->getImage(buf, r);
+#define BPP 8
+#include <rfb/hextileEncode.h>
+#include <rfb/hextileEncodeBetter.h>
+#undef BPP
+#define BPP 16
+#include <rfb/hextileEncode.h>
+#include <rfb/hextileEncodeBetter.h>
+#undef BPP
+#define BPP 32
+#include <rfb/hextileEncode.h>
+#include <rfb/hextileEncodeBetter.h>
+#undef BPP
+
+Encoder* HextileEncoder::create(SMsgWriter* writer)
+{
+ return new HextileEncoder(writer);
+}
+
+HextileEncoder::HextileEncoder(SMsgWriter* writer_) : writer(writer_)
+{
+}
+
+HextileEncoder::~HextileEncoder()
+{
+}
+
+bool HextileEncoder::writeRect(const Rect& r, ImageGetter* ig, Rect* actual)
+{
+ writer->startRect(r, encodingHextile);
+ rdr::OutStream* os = writer->getOutStream();
+ switch (writer->bpp()) {
+ case 8:
+ if (improvedHextile) {
+ hextileEncodeBetter8(r, os, ig);
+ } else {
+ hextileEncode8(r, os, ig);
+ }
+ break;
+ case 16:
+ if (improvedHextile) {
+ hextileEncodeBetter16(r, os, ig);
+ } else {
+ hextileEncode16(r, os, ig);
+ }
+ break;
+ case 32:
+ if (improvedHextile) {
+ hextileEncodeBetter32(r, os, ig);
+ } else {
+ hextileEncode32(r, os, ig);
+ }
+ break;
+ }
+ writer->endRect();
+ return true;
+}
diff --git a/common/rfb/HextileEncoder.h b/common/rfb/HextileEncoder.h
new file mode 100644
index 00000000..c78107a4
--- /dev/null
+++ b/common/rfb/HextileEncoder.h
@@ -0,0 +1,35 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#ifndef __RFB_HEXTILEENCODER_H__
+#define __RFB_HEXTILEENCODER_H__
+
+#include <rfb/Encoder.h>
+
+namespace rfb {
+
+ class HextileEncoder : public Encoder {
+ public:
+ static Encoder* create(SMsgWriter* writer);
+ virtual bool writeRect(const Rect& r, ImageGetter* ig, Rect* actual);
+ virtual ~HextileEncoder();
+ private:
+ HextileEncoder(SMsgWriter* writer);
+ SMsgWriter* writer;
+ };
+}
+#endif
diff --git a/common/rfb/Hostname.h b/common/rfb/Hostname.h
new file mode 100644
index 00000000..ebdf816f
--- /dev/null
+++ b/common/rfb/Hostname.h
@@ -0,0 +1,55 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#ifndef __RFB_HOSTNAME_H__
+#define __RFB_HOSTNAME_H__
+
+#include <stdlib.h>
+#include <rdr/Exception.h>
+#include <rfb/util.h>
+
+namespace rfb {
+
+ static void getHostAndPort(const char* hi, char** host, int* port, int basePort=5900) {
+ CharArray portBuf;
+ CharArray hostBuf;
+ if (hi[0] == '[') {
+ if (!strSplit(&hi[1], ']', &hostBuf.buf, &portBuf.buf))
+ throw rdr::Exception("unmatched [ in host");
+ } else {
+ portBuf.buf = strDup(hi);
+ }
+ if (strSplit(portBuf.buf, ':', hostBuf.buf ? 0 : &hostBuf.buf, &portBuf.buf)) {
+ if (portBuf.buf[0] == ':') {
+ *port = atoi(&portBuf.buf[1]);
+ } else {
+ *port = atoi(portBuf.buf);
+ if (*port < 100) *port += basePort;
+ }
+ } else {
+ *port = basePort;
+ }
+ if (strlen(hostBuf.buf) == 0)
+ *host = strDup("localhost");
+ else
+ *host = hostBuf.takeBuf();
+ }
+
+};
+
+#endif // __RFB_HOSTNAME_H__
diff --git a/common/rfb/ImageGetter.h b/common/rfb/ImageGetter.h
new file mode 100644
index 00000000..290249f6
--- /dev/null
+++ b/common/rfb/ImageGetter.h
@@ -0,0 +1,30 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#ifndef __RFB_IMAGEGETTER_H__
+#define __RFB_IMAGEGETTER_H__
+
+#include <rfb/Rect.h>
+
+namespace rfb {
+ class ImageGetter {
+ public:
+ virtual void getImage(void* imageBuf,
+ const Rect& r, int stride=0) = 0;
+ };
+}
+#endif
diff --git a/common/rfb/InputHandler.h b/common/rfb/InputHandler.h
new file mode 100644
index 00000000..b5e5e879
--- /dev/null
+++ b/common/rfb/InputHandler.h
@@ -0,0 +1,40 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+//
+// InputHandler - abstract interface for accepting keyboard &
+// pointer input and clipboard data.
+//
+
+#ifndef __RFB_INPUTHANDLER_H__
+#define __RFB_INPUTHANDLER_H__
+
+#include <rdr/types.h>
+#include <rfb/Rect.h>
+
+namespace rfb {
+
+ class InputHandler {
+ public:
+ virtual ~InputHandler() {}
+ virtual void keyEvent(rdr::U32 key, bool down) {}
+ virtual void pointerEvent(const Point& pos, int buttonMask) {}
+ virtual void clientCutText(const char* str, int len) {}
+ };
+
+}
+#endif
diff --git a/common/rfb/KeyRemapper.cxx b/common/rfb/KeyRemapper.cxx
new file mode 100644
index 00000000..05f07632
--- /dev/null
+++ b/common/rfb/KeyRemapper.cxx
@@ -0,0 +1,84 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#include <stdio.h>
+#include <rfb/KeyRemapper.h>
+#include <rfb/Configuration.h>
+#include <rfb/LogWriter.h>
+
+using namespace rfb;
+
+static LogWriter vlog("KeyRemapper");
+
+KeyRemapper KeyRemapper::defInstance;
+
+#ifdef __RFB_THREADING_IMPL
+static Mutex mappingLock;
+#endif
+
+void KeyRemapper::setMapping(const char* m) {
+#ifdef __RFB_THREADING_IMPL
+ Lock l(mappingLock);
+#endif
+ mapping.clear();
+ while (m[0]) {
+ int from, to;
+ char bidi;
+ const char* nextComma = strchr(m, ',');
+ if (!nextComma)
+ nextComma = m + strlen(m);
+ if (sscanf(m, "0x%x%c>0x%x", &from,
+ &bidi, &to) == 3) {
+ if (bidi != '-' && bidi != '<')
+ vlog.error("warning: unknown operation %c>, assuming ->", bidi);
+ mapping[from] = to;
+ if (bidi == '<')
+ mapping[to] = from;
+ } else {
+ vlog.error("warning: bad mapping %.*s", nextComma-m, m);
+ }
+ m = nextComma;
+ if (nextComma[0])
+ m++;
+ }
+}
+
+rdr::U32 KeyRemapper::remapKey(rdr::U32 key) const {
+#ifdef __RFB_THREADING_IMPL
+ Lock l(mappingLock);
+#endif
+ std::map<rdr::U32,rdr::U32>::const_iterator i = mapping.find(key);
+ if (i != mapping.end())
+ return i->second;
+ return key;
+}
+
+
+class KeyMapParameter : public StringParameter {
+public:
+ KeyMapParameter()
+ : StringParameter("RemapKeys", "Comma-separated list of incoming keysyms to remap. Mappings are expressed as two hex values, prefixed by 0x, and separated by ->", "") {
+ setParam(value);
+ }
+ bool setParam(const char* v) {
+ KeyRemapper::defInstance.setMapping(v);
+ return StringParameter::setParam(v);
+ }
+} defaultParam;
+
+
diff --git a/common/rfb/KeyRemapper.h b/common/rfb/KeyRemapper.h
new file mode 100644
index 00000000..a4b7aa01
--- /dev/null
+++ b/common/rfb/KeyRemapper.h
@@ -0,0 +1,39 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#ifndef __RFB_KEYREMAPPER_H__
+#define __RFB_KEYREMAPPER_H__
+
+#include <map>
+#include <rdr/types.h>
+
+namespace rfb {
+
+ class KeyRemapper {
+ public:
+ KeyRemapper(const char* m="") { setMapping(m); }
+ void setMapping(const char* m);
+ rdr::U32 remapKey(rdr::U32 key) const;
+ static KeyRemapper defInstance;
+ private:
+ std::map<rdr::U32,rdr::U32> mapping;
+ };
+
+};
+
+#endif // __RFB_KEYREMAPPER_H__
diff --git a/common/rfb/ListConnInfo.h b/common/rfb/ListConnInfo.h
new file mode 100644
index 00000000..cabcbc79
--- /dev/null
+++ b/common/rfb/ListConnInfo.h
@@ -0,0 +1,122 @@
+/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+
+#ifndef __RFB_LISTCONNINFO_INCLUDED__
+#define __RFB_LISTCONNINFO_INCLUDED__
+
+namespace rfb {
+
+ struct ListConnInfo {
+ ListConnInfo() : disableClients(false) {}
+
+ void Clear() {
+ conn.clear();
+ IP_address.clear();
+ time_conn.clear();
+ status.clear();
+ }
+
+ bool Empty() { return conn.empty();}
+
+ void iBegin() {
+ ci = conn.begin();
+ Ii = IP_address.begin();
+ ti = time_conn.begin();
+ si = status.begin();
+ }
+
+ bool iEnd() { return ci == conn.end();}
+
+ void iNext() {
+ ci++;
+ Ii++;
+ ti++;
+ si++;
+ }
+
+ void addInfo(void* Conn, char* IP, char* Time, int Status) {
+ conn.push_back(Conn);
+ IP_address.push_back(strDup(IP));
+ time_conn.push_back(strDup(Time));
+ status.push_back(Status);
+ }
+
+ void iGetCharInfo(char* buf[3]) {
+ buf[0] = *Ii;
+ buf[1] = *ti;
+ switch (*si) {
+ case 0:
+ buf[2] = strDup("Full control");
+ break;
+ case 1:
+ buf[2] = strDup("View only");
+ break;
+ case 2:
+ buf[2] = strDup("Stop updating");
+ break;
+ default:
+ buf[2] = strDup("Unknown");
+ }
+ }
+
+ void* iGetConn() { return *ci;}
+
+ int iGetStatus() { return *si;}
+
+ void iSetStatus( int status) { *si = status;}
+
+ void Copy(ListConnInfo* InputList) {
+ Clear();
+ if (InputList->Empty()) return;
+ for (InputList->iBegin(); !InputList->iEnd(); InputList->iNext()) {
+ iAdd(InputList);
+ }
+ setDisable(InputList->getDisable());
+ }
+
+ void iAdd (ListConnInfo* InputList) {
+ char* buf[3];
+ InputList->iGetCharInfo(buf);
+ addInfo(InputList->iGetConn(), buf[0], buf[1], InputList->iGetStatus());
+ }
+
+ void setDisable(bool disable) {disableClients = disable;}
+
+ bool getDisable() {return disableClients;}
+
+ void setAllStatus(int stat) {
+ std::list<int>::iterator st;
+ for (st = status.begin(); st != status.end(); st++)
+ *st = stat;
+ }
+
+ private:
+ std::list<void*> conn;
+ std::list<char*> IP_address;
+ std::list<char*> time_conn;
+ std::list<int> status;
+ std::list<void*>::iterator ci;
+ std::list<char*>::iterator Ii;
+ std::list<char*>::iterator ti;
+ std::list<int>::iterator si;
+ bool disableClients;
+ };
+};
+#endif
+
diff --git a/common/rfb/LogWriter.cxx b/common/rfb/LogWriter.cxx
new file mode 100644
index 00000000..c6461d14
--- /dev/null
+++ b/common/rfb/LogWriter.cxx
@@ -0,0 +1,137 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- LogWriter.cxx - client-side logging interface
+
+#include <string.h>
+#ifdef WIN32
+#define strcasecmp _stricmp
+#endif
+
+#include <rfb/LogWriter.h>
+#include <rfb/Configuration.h>
+#include <rfb/util.h>
+#include <stdlib.h>
+
+rfb::LogParameter rfb::logParams;
+
+using namespace rfb;
+
+
+LogWriter::LogWriter(const char* name) : m_name(name), m_level(0), m_log(0), m_next(log_writers) {
+ log_writers = this;
+}
+
+LogWriter::~LogWriter() {
+ // *** Should remove this logger here!
+}
+
+void LogWriter::setLog(Logger *logger) {
+ m_log = logger;
+}
+
+void LogWriter::setLevel(int level) {
+ m_level = level;
+}
+
+void
+LogWriter::listLogWriters(int width) {
+ // *** make this respect width...
+ LogWriter* current = log_writers;
+ fprintf(stderr, " ");
+ while (current) {
+ fprintf(stderr, "%s", current->m_name);
+ current = current->m_next;
+ if (current) fprintf(stderr, ", ");
+ }
+ fprintf(stderr, "\n");
+}
+
+LogWriter* LogWriter::log_writers;
+
+LogWriter*
+LogWriter::getLogWriter(const char* name) {
+ LogWriter* current = log_writers;
+ while (current) {
+ if (strcasecmp(name, current->m_name) == 0) return current;
+ current = current->m_next;
+ }
+ return 0;
+}
+
+bool LogWriter::setLogParams(const char* params) {
+ CharArray logwriterName, loggerName, logLevel;
+ if (!strSplit(params, ':', &logwriterName.buf, &loggerName.buf) ||
+ !strSplit(loggerName.buf, ':', &loggerName.buf, &logLevel.buf)) {
+ fprintf(stderr,"failed to parse log params:%s\n",params);
+ return false;
+ }
+ int level = atoi(logLevel.buf);
+ Logger* logger = 0;
+ if (strcmp("", loggerName.buf) != 0) {
+ logger = Logger::getLogger(loggerName.buf);
+ if (!logger) fprintf(stderr,"no logger found! %s\n",loggerName.buf);
+ }
+ if (strcmp("*", logwriterName.buf) == 0) {
+ LogWriter* current = log_writers;
+ while (current) {
+ current->setLog(logger);
+ current->setLevel(level);
+ current = current->m_next;
+ }
+ return true;
+ } else {
+ LogWriter* logwriter = getLogWriter(logwriterName.buf);
+ if (!logwriter) {
+ fprintf(stderr,"no logwriter found! %s\n",logwriterName.buf);
+ } else {
+ logwriter->setLog(logger);
+ logwriter->setLevel(level);
+ return true;
+ }
+ }
+ return false;
+}
+
+
+LogParameter::LogParameter()
+ : StringParameter("Log",
+ "Specifies which log output should be directed to "
+ "which target logger, and the level of output to log. "
+ "Format is <log>:<target>:<level>[, ...].",
+ "") {
+}
+
+bool LogParameter::setParam(const char* v) {
+ if (immutable) return true;
+ LogWriter::setLogParams("*::0");
+ StringParameter::setParam(v);
+ CharArray logParam;
+ CharArray params(getData());
+ while (params.buf) {
+ strSplit(params.buf, ',', &logParam.buf, &params.buf);
+ if (strlen(logParam.buf) && !LogWriter::setLogParams(logParam.buf))
+ return false;
+ }
+ return true;
+}
+
+void LogParameter::setDefault(const char* d) {
+ def_value = d;
+ setParam(def_value);
+}
diff --git a/common/rfb/LogWriter.h b/common/rfb/LogWriter.h
new file mode 100644
index 00000000..124c58ec
--- /dev/null
+++ b/common/rfb/LogWriter.h
@@ -0,0 +1,106 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- LogWriter.h - The Log writer class.
+
+#ifndef __RFB_LOG_WRITER_H__
+#define __RFB_LOG_WRITER_H__
+
+#include <stdarg.h>
+#include <rfb/Logger.h>
+#include <rfb/Configuration.h>
+
+// Each log writer instance has a unique textual name,
+// and is attached to a particular Log instance and
+// is assigned a particular log level.
+
+#define DEF_LOGFUNCTION(name, level) \
+ inline void name(const char* fmt, ...) { \
+ if (m_log && (level <= m_level)) { \
+ va_list ap; va_start(ap, fmt); \
+ m_log->write(level, m_name, fmt, ap);\
+ va_end(ap); \
+ } \
+ }
+
+namespace rfb {
+
+ class LogWriter;
+
+ class LogWriter {
+ public:
+ LogWriter(const char* name);
+ ~LogWriter();
+
+ const char *getName() {return m_name;}
+
+ void setLog(Logger *logger);
+ void setLevel(int level);
+
+ inline void write(int level, const char* format, ...) {
+ if (m_log && (level <= m_level)) {
+ va_list ap;
+ va_start(ap, format);
+ m_log->write(level, m_name, format, ap);
+ va_end(ap);
+ }
+ }
+
+ DEF_LOGFUNCTION(error, 0)
+ DEF_LOGFUNCTION(status, 10)
+ DEF_LOGFUNCTION(info, 30)
+ DEF_LOGFUNCTION(debug, 100)
+
+ // -=- DIAGNOSTIC & HELPER ROUTINES
+
+ static void listLogWriters(int width=79);
+
+ // -=- CLASS FIELDS & FUNCTIONS
+
+ static LogWriter* log_writers;
+
+ static LogWriter* getLogWriter(const char* name);
+
+ static bool setLogParams(const char* params);
+
+ private:
+ const char* m_name;
+ int m_level;
+ Logger* m_log;
+ LogWriter* m_next;
+ };
+
+ class LogParameter : public StringParameter {
+ public:
+ LogParameter();
+ virtual bool setParam(const char* v);
+
+ // Call this to set a suitable default value.
+ // Can't use the normal default mechanism for
+ // this because there is no guarantee on C++
+ // constructor ordering - some LogWriters may
+ // not exist when LogParameter gets constructed.
+ // NB: The default value must exist for the
+ // lifetime of the process!
+ void setDefault(const char* v);
+ };
+ extern LogParameter logParams;
+
+};
+
+#endif // __RFB_LOG_WRITER_H__
diff --git a/common/rfb/Logger.cxx b/common/rfb/Logger.cxx
new file mode 100644
index 00000000..52d33085
--- /dev/null
+++ b/common/rfb/Logger.cxx
@@ -0,0 +1,118 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- Logger.cxx - support for the Logger and LogWriter classes
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#ifdef WIN32
+#define strcasecmp _stricmp
+#define vsnprintf _vsnprintf
+#define HAVE_VSNPRINTF
+#endif
+
+#include <rfb/Logger.h>
+#include <rfb/LogWriter.h>
+#include <rfb/util.h>
+#include <rfb/Threading.h>
+
+using namespace rfb;
+
+#ifndef HAVE_VSNPRINTF
+#ifdef __RFB_THREADING_IMPL
+static Mutex fpLock;
+#endif
+static FILE* fp = 0;
+int vsnprintf(char *str, size_t n, const char *format, va_list ap)
+{
+ str[0] = 0;
+ if (!fp) {
+ // Safely create a FILE* for /dev/null if there isn't already one
+#ifdef __RFB_THREADING_IMPL
+ Lock l(fpLock);
+#endif
+ if (!fp)
+ fp = fopen("/dev/null","w");
+ if (!fp) return 0;
+ }
+ int len = vfprintf(fp, format, ap);
+ if (len <= 0) return 0;
+
+ CharArray s(len+1);
+ vsprintf(s.buf, format, ap);
+
+ int written = __rfbmin(len, (int)n-1);
+ memcpy(str, s.buf, written);
+ str[written] = 0;
+ return len;
+}
+#endif
+
+
+Logger* Logger::loggers = 0;
+
+Logger::Logger(const char* name) : registered(false), m_name(name), m_next(0) {
+}
+
+Logger::~Logger() {
+ // *** Should remove this logger here!
+}
+
+void Logger::write(int level, const char *logname, const char* format,
+ va_list ap)
+{
+ // - Format the supplied data, and pass it to the
+ // actual log_message function
+ // The log level is included as a hint for loggers capable of representing
+ // different log levels in some way.
+ char buf1[4096];
+ vsnprintf(buf1, sizeof(buf1)-1, format, ap);
+ buf1[sizeof(buf1)-1] = 0;
+ write(level, logname, buf1);
+}
+
+void
+Logger::registerLogger() {
+ if (!registered) {
+ registered = true;
+ m_next = loggers;
+ loggers=this;
+ }
+}
+
+Logger*
+Logger::getLogger(const char* name) {
+ Logger* current = loggers;
+ while (current) {
+ if (strcasecmp(name, current->m_name) == 0) return current;
+ current = current->m_next;
+ }
+ return 0;
+}
+
+void
+Logger::listLoggers() {
+ Logger* current = loggers;
+ while (current) {
+ printf(" %s\n", current->m_name);
+ current = current->m_next;
+ }
+}
+
+
diff --git a/common/rfb/Logger.h b/common/rfb/Logger.h
new file mode 100644
index 00000000..e53764b7
--- /dev/null
+++ b/common/rfb/Logger.h
@@ -0,0 +1,70 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- Logger.h - The Logger class.
+
+#ifndef __RFB_LOGGER_H__
+#define __RFB_LOGGER_H__
+
+#include <stdarg.h>
+#include <stdio.h>
+
+// Each log writer instance has a unique textual name,
+// and is attached to a particular Logger instance and
+// is assigned a particular log level.
+
+namespace rfb {
+
+ class Logger {
+ public:
+
+ // -=- Create / Destroy a logger
+
+ Logger(const char* name);
+ virtual ~Logger();
+
+ // -=- Get the name of a logger
+
+ const char *getName() {return m_name;}
+
+ // -=- Write data to a log
+
+ virtual void write(int level, const char *logname, const char *text) = 0;
+ void write(int level, const char *logname, const char* format, va_list ap);
+
+ // -=- Register a logger
+
+ void registerLogger();
+
+ // -=- CLASS FIELDS & FUNCTIONS
+
+ static Logger* loggers;
+
+ static Logger* getLogger(const char* name);
+
+ static void listLoggers();
+
+ private:
+ bool registered;
+ const char *m_name;
+ Logger *m_next;
+ };
+
+};
+
+#endif // __RFB_LOGGER_H__
diff --git a/common/rfb/Logger_file.cxx b/common/rfb/Logger_file.cxx
new file mode 100644
index 00000000..8a109e4a
--- /dev/null
+++ b/common/rfb/Logger_file.cxx
@@ -0,0 +1,127 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- Logger_file.cxx - Logger instance for a file
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <rfb/util.h>
+#include <rfb/Logger_file.h>
+#include <rfb/Threading.h>
+
+using namespace rfb;
+
+
+// If threading is available then protect the write() operation
+// from concurrent accesses
+#ifdef __RFB_THREADING_IMPL
+static Mutex logLock;
+#endif
+
+
+Logger_File::Logger_File(const char* loggerName)
+ : Logger(loggerName), indent(13), width(79), m_filename(0), m_file(0),
+ m_lastLogTime(0)
+{
+}
+
+Logger_File::~Logger_File()
+{
+ closeFile();
+}
+
+void Logger_File::write(int level, const char *logname, const char *message)
+{
+#ifdef __RFB_THREADING_IMPL
+ Lock l(logLock);
+#endif
+ if (!m_file) {
+ if (!m_filename) return;
+ CharArray bakFilename(strlen(m_filename) + 1 + 4);
+ sprintf(bakFilename.buf, "%s.bak", m_filename);
+ remove(bakFilename.buf);
+ rename(m_filename, bakFilename.buf);
+ m_file = fopen(m_filename, "w+");
+ if (!m_file) return;
+ }
+
+#ifndef _WIN32_WCE
+ time_t current = time(0);
+ if (current != m_lastLogTime) {
+ m_lastLogTime = current;
+ fprintf(m_file, "\n%s", ctime(&m_lastLogTime));
+ }
+#endif
+
+ fprintf(m_file," %s:", logname);
+ int column = strlen(logname) + 2;
+ if (column < indent) {
+ fprintf(m_file,"%*s",indent-column,"");
+ column = indent;
+ }
+ while (true) {
+ const char* s = strchr(message, ' ');
+ int wordLen;
+ if (s) wordLen = s-message;
+ else wordLen = strlen(message);
+
+ if (column + wordLen + 1 > width) {
+ fprintf(m_file,"\n%*s",indent,"");
+ column = indent;
+ }
+ fprintf(m_file," %.*s",wordLen,message);
+ column += wordLen + 1;
+ message += wordLen + 1;
+ if (!s) break;
+ }
+ fprintf(m_file,"\n");
+ fflush(m_file);
+}
+
+void Logger_File::setFilename(const char* filename)
+{
+ closeFile();
+ m_filename = strDup(filename);
+}
+
+void Logger_File::setFile(FILE* file)
+{
+ closeFile();
+ m_file = file;
+}
+
+void Logger_File::closeFile()
+{
+ if (m_filename) {
+ if (m_file) {
+ fclose(m_file);
+ m_file = 0;
+ }
+ strFree(m_filename);
+ m_filename = 0;
+ }
+}
+
+static Logger_File logger("file");
+
+bool rfb::initFileLogger(const char* filename) {
+ logger.setFilename(filename);
+ logger.registerLogger();
+ return true;
+}
diff --git a/common/rfb/Logger_file.h b/common/rfb/Logger_file.h
new file mode 100644
index 00000000..5e0c917b
--- /dev/null
+++ b/common/rfb/Logger_file.h
@@ -0,0 +1,51 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- Logger_file - log to a file
+
+#ifndef __RFB_LOGGER_FILE_H__
+#define __RFB_LOGGER_FILE_H__
+
+#include <time.h>
+#include <rfb/Logger.h>
+
+namespace rfb {
+
+ class Logger_File : public Logger {
+ public:
+ Logger_File(const char* loggerName);
+ ~Logger_File();
+
+ virtual void write(int level, const char *logname, const char *message);
+ void setFilename(const char* filename);
+ void setFile(FILE* file);
+
+ int indent;
+ int width;
+
+ protected:
+ void closeFile();
+ char* m_filename;
+ FILE* m_file;
+ time_t m_lastLogTime;
+ };
+
+ bool initFileLogger(const char* filename);
+};
+
+#endif
diff --git a/common/rfb/Logger_stdio.cxx b/common/rfb/Logger_stdio.cxx
new file mode 100644
index 00000000..581dcd5b
--- /dev/null
+++ b/common/rfb/Logger_stdio.cxx
@@ -0,0 +1,32 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- Logger_stdio.cxx - Logger instances for stderr and stdout
+
+#include <rfb/Logger_stdio.h>
+
+using namespace rfb;
+
+static Logger_StdIO logStdErr("stderr", stderr);
+static Logger_StdIO logStdOut("stdout", stdout);
+
+bool rfb::initStdIOLoggers() {
+ logStdErr.registerLogger();
+ logStdOut.registerLogger();
+ return true;
+}
diff --git a/common/rfb/Logger_stdio.h b/common/rfb/Logger_stdio.h
new file mode 100644
index 00000000..a1d17a0f
--- /dev/null
+++ b/common/rfb/Logger_stdio.h
@@ -0,0 +1,39 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- Logger_stdio - standard output logger instances
+
+#ifndef __RFB_LOGGER_STDIO_H__
+#define __RFB_LOGGER_STDIO_H__
+
+#include <rfb/Logger_file.h>
+
+namespace rfb {
+
+ class Logger_StdIO : public Logger_File {
+ public:
+ Logger_StdIO(const char *name, FILE* file) : Logger_File(name) {
+ setFile(file);
+ }
+ };
+
+ bool initStdIOLoggers();
+
+};
+
+#endif
diff --git a/common/rfb/Makefile.in b/common/rfb/Makefile.in
new file mode 100644
index 00000000..835e1882
--- /dev/null
+++ b/common/rfb/Makefile.in
@@ -0,0 +1,80 @@
+
+CXXSRCS = \
+ Blacklist.cxx \
+ CConnection.cxx \
+ CMsgHandler.cxx \
+ CMsgReader.cxx \
+ CMsgReaderV3.cxx \
+ CMsgWriter.cxx \
+ CMsgWriterV3.cxx \
+ CSecurityVncAuth.cxx \
+ ComparingUpdateTracker.cxx \
+ Configuration.cxx \
+ ConnParams.cxx \
+ Cursor.cxx \
+ Decoder.cxx \
+ Encoder.cxx \
+ FileInfo.cxx \
+ FileManager.cxx \
+ FileReader.cxx \
+ FileWriter.cxx \
+ HTTPServer.cxx \
+ HextileDecoder.cxx \
+ HextileEncoder.cxx \
+ KeyRemapper.cxx \
+ LogWriter.cxx \
+ Logger.cxx \
+ Logger_file.cxx \
+ Logger_stdio.cxx \
+ Password.cxx \
+ PixelBuffer.cxx \
+ PixelFormat.cxx \
+ RREEncoder.cxx \
+ RREDecoder.cxx \
+ RawDecoder.cxx \
+ RawEncoder.cxx \
+ Region.cxx \
+ SConnection.cxx \
+ SFTMsgReader.cxx \
+ SFTMsgWriter.cxx \
+ SFileTransfer.cxx \
+ SFileTransferManager.cxx \
+ SMsgHandler.cxx \
+ SMsgReader.cxx \
+ SMsgReaderV3.cxx \
+ SMsgWriter.cxx \
+ SMsgWriterV3.cxx \
+ ServerCore.cxx \
+ SSecurityFactoryStandard.cxx \
+ SSecurityVncAuth.cxx \
+ Timer.cxx \
+ TightDecoder.cxx \
+ TightEncoder.cxx \
+ TightPalette.cxx \
+ TransImageGetter.cxx \
+ TransferQueue.cxx \
+ UpdateTracker.cxx \
+ VNCSConnectionST.cxx \
+ VNCServerST.cxx \
+ ZRLEEncoder.cxx \
+ ZRLEDecoder.cxx \
+ encodings.cxx \
+ secTypes.cxx \
+ util.cxx
+
+SRCS = d3des.c $(CXXSRCS)
+
+OBJS = d3des.o $(CXXSRCS:.cxx=.o)
+
+DIR_CPPFLAGS = -I$(top_srcdir) @ZLIB_INCLUDE@ @JPEG_INCLUDE@ @VSNPRINTF_DEFINE@
+
+library = librfb.a
+
+all:: $(library)
+
+$(library): $(OBJS)
+ rm -f $(library)
+ $(AR) $(library) $(OBJS)
+ $(RANLIB) $(library)
+
+# followed by boilerplate.mk
diff --git a/common/rfb/Password.cxx b/common/rfb/Password.cxx
new file mode 100644
index 00000000..9127862d
--- /dev/null
+++ b/common/rfb/Password.cxx
@@ -0,0 +1,77 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+//
+// XXX not thread-safe, because d3des isn't - do we need to worry about this?
+//
+
+#include <string.h>
+extern "C" {
+#include <rfb/d3des.h>
+}
+#include <rdr/types.h>
+#include <rdr/Exception.h>
+#include <rfb/Password.h>
+
+using namespace rfb;
+
+static unsigned char d3desObfuscationKey[] = {23,82,107,6,35,78,88,7};
+
+
+PlainPasswd::PlainPasswd() {}
+
+PlainPasswd::PlainPasswd(char* pwd) : CharArray(pwd) {
+}
+
+PlainPasswd::PlainPasswd(const ObfuscatedPasswd& obfPwd) : CharArray(9) {
+ if (obfPwd.length < 8)
+ throw rdr::Exception("bad obfuscated password length");
+ deskey(d3desObfuscationKey, DE1);
+ des((rdr::U8*)obfPwd.buf, (rdr::U8*)buf);
+ buf[8] = 0;
+}
+
+PlainPasswd::~PlainPasswd() {
+ replaceBuf(0);
+}
+
+void PlainPasswd::replaceBuf(char* b) {
+ if (buf)
+ memset(buf, 0, strlen(buf));
+ CharArray::replaceBuf(b);
+}
+
+
+ObfuscatedPasswd::ObfuscatedPasswd() : length(0) {
+}
+
+ObfuscatedPasswd::ObfuscatedPasswd(int len) : CharArray(len), length(len) {
+}
+
+ObfuscatedPasswd::ObfuscatedPasswd(const PlainPasswd& plainPwd) : CharArray(8), length(8) {
+ int l = strlen(plainPwd.buf), i;
+ for (i=0; i<8; i++)
+ buf[i] = i<l ? plainPwd.buf[i] : 0;
+ deskey(d3desObfuscationKey, EN0);
+ des((rdr::U8*)buf, (rdr::U8*)buf);
+}
+
+ObfuscatedPasswd::~ObfuscatedPasswd() {
+ if (buf)
+ memset(buf, 0, length);
+}
diff --git a/common/rfb/Password.h b/common/rfb/Password.h
new file mode 100644
index 00000000..ab26903a
--- /dev/null
+++ b/common/rfb/Password.h
@@ -0,0 +1,46 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#ifndef __RFB_PASSWORD_H__
+#define __RFB_PASSWORD_H__
+
+#include <rfb/util.h>
+
+namespace rfb {
+
+ class ObfuscatedPasswd;
+
+ class PlainPasswd : public CharArray {
+ public:
+ PlainPasswd();
+ PlainPasswd(char* pwd);
+ PlainPasswd(const ObfuscatedPasswd& obfPwd);
+ ~PlainPasswd();
+ void replaceBuf(char* b);
+ };
+
+ class ObfuscatedPasswd : public CharArray {
+ public:
+ ObfuscatedPasswd();
+ ObfuscatedPasswd(int l);
+ ObfuscatedPasswd(const PlainPasswd& plainPwd);
+ ~ObfuscatedPasswd();
+ int length;
+ };
+
+}
+#endif
diff --git a/common/rfb/Pixel.h b/common/rfb/Pixel.h
new file mode 100644
index 00000000..4e9d1644
--- /dev/null
+++ b/common/rfb/Pixel.h
@@ -0,0 +1,26 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#ifndef __RFB_PIXEL_H__
+#define __RFB_PIXEL_H__
+
+#include <rdr/types.h>
+
+namespace rfb {
+ typedef rdr::U32 Pixel; // must be big enough to hold any pixel value
+}
+#endif
diff --git a/common/rfb/PixelBuffer.cxx b/common/rfb/PixelBuffer.cxx
new file mode 100644
index 00000000..d093426f
--- /dev/null
+++ b/common/rfb/PixelBuffer.cxx
@@ -0,0 +1,309 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- PixelBuffer.cxx
+//
+// The PixelBuffer class encapsulates the PixelFormat and dimensions
+// of a block of pixel data.
+
+#include <rfb/Exception.h>
+#include <rfb/LogWriter.h>
+#include <rfb/PixelBuffer.h>
+
+using namespace rfb;
+using namespace rdr;
+
+static LogWriter vlog("PixelBuffer");
+
+
+// -=- Generic pixel buffer class
+
+PixelBuffer::PixelBuffer(const PixelFormat& pf, int w, int h, ColourMap* cm)
+ : format(pf), width_(w), height_(h), colourmap(cm) {}
+PixelBuffer::PixelBuffer() : width_(0), height_(0), colourmap(0) {}
+
+PixelBuffer::~PixelBuffer() {}
+
+
+void PixelBuffer::setPF(const PixelFormat &pf) {format = pf;}
+const PixelFormat& PixelBuffer::getPF() const {return format;}
+ColourMap* PixelBuffer::getColourMap() const {return colourmap;}
+
+
+void
+PixelBuffer::getImage(void* imageBuf, const Rect& r, int outStride) {
+ int inStride;
+ const U8* data = getPixelsR(r, &inStride);
+ // We assume that the specified rectangle is pre-clipped to the buffer
+ int bytesPerPixel = format.bpp/8;
+ int inBytesPerRow = inStride * bytesPerPixel;
+ if (!outStride) outStride = r.width();
+ int outBytesPerRow = outStride * bytesPerPixel;
+ int bytesPerMemCpy = r.width() * bytesPerPixel;
+ U8* imageBufPos = (U8*)imageBuf;
+ const U8* end = data + (inBytesPerRow * r.height());
+ while (data < end) {
+ memcpy(imageBufPos, data, bytesPerMemCpy);
+ imageBufPos += outBytesPerRow;
+ data += inBytesPerRow;
+ }
+}
+
+/* ***
+Pixel PixelBuffer::getPixel(const Point& p) {
+ int stride;
+ Rect r = Rect(p.x, p.y, p.x+1, p.y+1);
+ switch(format.bpp) {
+ case 8: return *((rdr::U8*)getDataAt(r, &stride));
+ case 16: return *((rdr::U16*)getDataAt(r, &stride));
+ case 32: return *((rdr::U32*)getDataAt(r, &stride));
+ default: return 0;
+ };
+}
+*/
+
+
+FullFramePixelBuffer::FullFramePixelBuffer(const PixelFormat& pf, int w, int h,
+ rdr::U8* data_, ColourMap* cm)
+ : PixelBuffer(pf, w, h, cm), data(data_)
+{
+}
+
+FullFramePixelBuffer::FullFramePixelBuffer() : data(0) {}
+
+FullFramePixelBuffer::~FullFramePixelBuffer() {}
+
+
+int FullFramePixelBuffer::getStride() const { return width(); }
+
+rdr::U8* FullFramePixelBuffer::getPixelsRW(const Rect& r, int* stride)
+{
+ *stride = getStride();
+ return &data[(r.tl.x + (r.tl.y * *stride)) * format.bpp/8];
+}
+
+
+void FullFramePixelBuffer::fillRect(const Rect& r, Pixel pix) {
+ int stride;
+ U8* data = getPixelsRW(r, &stride);
+ int bytesPerPixel = getPF().bpp/8;
+ int bytesPerRow = bytesPerPixel * stride;
+ int bytesPerFill = bytesPerPixel * r.width();
+
+ U8* end = data + (bytesPerRow * r.height());
+ while (data < end) {
+ switch (bytesPerPixel) {
+ case 1:
+ memset(data, pix, bytesPerFill);
+ break;
+ case 2:
+ {
+ U16* optr = (U16*)data;
+ U16* eol = optr + r.width();
+ while (optr < eol)
+ *optr++ = pix;
+ }
+ break;
+ case 4:
+ {
+ U32* optr = (U32*)data;
+ U32* eol = optr + r.width();
+ while (optr < eol)
+ *optr++ = pix;
+ }
+ break;
+ }
+ data += bytesPerRow;
+ }
+}
+
+void FullFramePixelBuffer::imageRect(const Rect& r, const void* pixels, int srcStride) {
+ int bytesPerPixel = getPF().bpp/8;
+ int destStride;
+ U8* dest = getPixelsRW(r, &destStride);
+ int bytesPerDestRow = bytesPerPixel * destStride;
+ if (!srcStride) srcStride = r.width();
+ int bytesPerSrcRow = bytesPerPixel * srcStride;
+ int bytesPerFill = bytesPerPixel * r.width();
+ const U8* src = (const U8*)pixels;
+ U8* end = dest + (bytesPerDestRow * r.height());
+ while (dest < end) {
+ memcpy(dest, src, bytesPerFill);
+ dest += bytesPerDestRow;
+ src += bytesPerSrcRow;
+ }
+}
+
+void FullFramePixelBuffer::maskRect(const Rect& r, const void* pixels, const void* mask_) {
+ Rect cr = getRect().intersect(r);
+ if (cr.is_empty()) return;
+ int stride;
+ U8* data = getPixelsRW(cr, &stride);
+ U8* mask = (U8*) mask_;
+ int w = cr.width();
+ int h = cr.height();
+ int bpp = getPF().bpp;
+ int pixelStride = r.width();
+ int maskStride = (r.width() + 7) / 8;
+
+ Point offset = Point(cr.tl.x-r.tl.x, cr.tl.y-r.tl.y);
+ mask += offset.y * maskStride;
+ for (int y = 0; y < h; y++) {
+ int cy = offset.y + y;
+ for (int x = 0; x < w; x++) {
+ int cx = offset.x + x;
+ U8* byte = mask + (cx / 8);
+ int bit = 7 - cx % 8;
+ if ((*byte) & (1 << bit)) {
+ switch (bpp) {
+ case 8:
+ ((U8*)data)[y * stride + x] = ((U8*)pixels)[cy * pixelStride + cx];
+ break;
+ case 16:
+ ((U16*)data)[y * stride + x] = ((U16*)pixels)[cy * pixelStride + cx];
+ break;
+ case 32:
+ ((U32*)data)[y * stride + x] = ((U32*)pixels)[cy * pixelStride + cx];
+ break;
+ }
+ }
+ }
+ mask += maskStride;
+ }
+}
+
+void FullFramePixelBuffer::maskRect(const Rect& r, Pixel pixel, const void* mask_) {
+ Rect cr = getRect().intersect(r);
+ if (cr.is_empty()) return;
+ int stride;
+ U8* data = getPixelsRW(cr, &stride);
+ U8* mask = (U8*) mask_;
+ int w = cr.width();
+ int h = cr.height();
+ int bpp = getPF().bpp;
+ int maskStride = (r.width() + 7) / 8;
+
+ Point offset = Point(cr.tl.x-r.tl.x, cr.tl.y-r.tl.y);
+ mask += offset.y * maskStride;
+ for (int y = 0; y < h; y++) {
+ for (int x = 0; x < w; x++) {
+ int cx = offset.x + x;
+ U8* byte = mask + (cx / 8);
+ int bit = 7 - cx % 8;
+ if ((*byte) & (1 << bit)) {
+ switch (bpp) {
+ case 8:
+ ((U8*)data)[y * stride + x] = pixel;
+ break;
+ case 16:
+ ((U16*)data)[y * stride + x] = pixel;
+ break;
+ case 32:
+ ((U32*)data)[y * stride + x] = pixel;
+ break;
+ }
+ }
+ }
+ mask += maskStride;
+ }
+}
+
+void FullFramePixelBuffer::copyRect(const Rect &rect, const Point &move_by_delta) {
+ int stride;
+ U8* data = getPixelsRW(getRect(), &stride);
+ // We assume that the specified rectangle is pre-clipped to the buffer
+ unsigned int bytesPerPixel, bytesPerRow, bytesPerMemCpy;
+ Rect srect = rect.translate(move_by_delta.negate());
+ bytesPerPixel = getPF().bpp/8;
+ bytesPerRow = stride * bytesPerPixel;
+ bytesPerMemCpy = rect.width() * bytesPerPixel;
+ if (move_by_delta.y <= 0) {
+ U8* dest = data + rect.tl.x*bytesPerPixel + rect.tl.y*bytesPerRow;
+ U8* src = data + srect.tl.x*bytesPerPixel + srect.tl.y*bytesPerRow;
+ for (int i=rect.tl.y; i<rect.br.y; i++) {
+ memmove(dest, src, bytesPerMemCpy);
+ dest += bytesPerRow;
+ src += bytesPerRow;
+ }
+ } else {
+ U8* dest = data + rect.tl.x*bytesPerPixel + (rect.br.y-1)*bytesPerRow;
+ U8* src = data + srect.tl.x*bytesPerPixel + (srect.br.y-1)*bytesPerRow;
+ for (int i=rect.tl.y; i<rect.br.y; i++) {
+ memmove(dest, src, bytesPerMemCpy);
+ dest -= bytesPerRow;
+ src -= bytesPerRow;
+ }
+ }
+}
+
+
+// -=- Managed pixel buffer class
+// Automatically allocates enough space for the specified format & area
+
+ManagedPixelBuffer::ManagedPixelBuffer()
+ : datasize(0), own_colourmap(false)
+{
+ checkDataSize();
+};
+
+ManagedPixelBuffer::ManagedPixelBuffer(const PixelFormat& pf, int w, int h)
+ : FullFramePixelBuffer(pf, w, h, 0, 0), datasize(0), own_colourmap(false)
+{
+ checkDataSize();
+};
+
+ManagedPixelBuffer::~ManagedPixelBuffer() {
+ if (data) delete [] data;
+ if (colourmap && own_colourmap) delete colourmap;
+};
+
+
+void
+ManagedPixelBuffer::setPF(const PixelFormat &pf) {
+ format = pf; checkDataSize();
+};
+void
+ManagedPixelBuffer::setSize(int w, int h) {
+ width_ = w; height_ = h; checkDataSize();
+};
+
+
+void
+ManagedPixelBuffer::setColourMap(ColourMap* cm, bool own_cm) {
+ if (colourmap && own_colourmap) delete colourmap;
+ colourmap = cm;
+ own_colourmap = own_cm;
+}
+
+inline void
+ManagedPixelBuffer::checkDataSize() {
+ unsigned long new_datasize = width_ * height_ * (format.bpp/8);
+ if (datasize < new_datasize) {
+ vlog.debug("reallocating managed buffer (%dx%d)", width_, height_);
+ if (data) {
+ delete [] data;
+ datasize = 0; data = 0;
+ }
+ if (new_datasize) {
+ data = new U8[new_datasize];
+ if (!data)
+ throw Exception("rfb::ManagedPixelBuffer unable to allocate buffer");
+ datasize = new_datasize;
+ }
+ }
+};
diff --git a/common/rfb/PixelBuffer.h b/common/rfb/PixelBuffer.h
new file mode 100644
index 00000000..4a13923c
--- /dev/null
+++ b/common/rfb/PixelBuffer.h
@@ -0,0 +1,172 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- PixelBuffer.h
+//
+// The PixelBuffer class encapsulates the PixelFormat and dimensions
+// of a block of pixel data.
+
+#ifndef __RFB_PIXEL_BUFFER_H__
+#define __RFB_PIXEL_BUFFER_H__
+
+#include <rfb/ImageGetter.h>
+#include <rfb/PixelFormat.h>
+#include <rfb/ColourMap.h>
+#include <rfb/Rect.h>
+#include <rfb/Pixel.h>
+
+namespace rfb {
+
+ class Region;
+
+ class PixelBuffer : public ImageGetter {
+ public:
+ PixelBuffer(const PixelFormat& pf, int width, int height, ColourMap* cm);
+ virtual ~PixelBuffer();
+
+ ///////////////////////////////////////////////
+ // Format / Layout
+ //
+
+ // Set/get pixel format & colourmap
+ virtual void setPF(const PixelFormat &pf);
+ virtual const PixelFormat &getPF() const;
+ virtual ColourMap* getColourMap() const;
+
+ // Get width, height and number of pixels
+ int width() const { return width_; }
+ int height() const { return height_; }
+ int area() const { return width_ * height_; }
+
+ // Get rectangle encompassing this buffer
+ // Top-left of rectangle is either at (0,0), or the specified point.
+ Rect getRect() const { return Rect(0, 0, width_, height_); }
+ Rect getRect(const Point& pos) const {
+ return Rect(pos, pos.translate(Point(width_, height_)));
+ }
+
+ ///////////////////////////////////////////////
+ // Access to pixel data
+ //
+
+ // Get a pointer into the buffer
+ // The pointer is to the top-left pixel of the specified Rect.
+ // The buffer stride (in pixels) is returned.
+ virtual const rdr::U8* getPixelsR(const Rect& r, int* stride) = 0;
+
+ // Get pixel data for a given part of the buffer
+ // Data is copied into the supplied buffer, with the specified
+ // stride.
+ virtual void getImage(void* imageBuf, const Rect& r, int stride=0);
+
+ // Get the data at (x,y) as a Pixel.
+ // VERY INEFFICIENT!!!
+ // *** Pixel getPixel(const Point& p);
+
+ ///////////////////////////////////////////////
+ // Framebuffer update methods
+ //
+
+ // Ensure that the specified rectangle of buffer is up to date.
+ // Overridden by derived classes implementing framebuffer access
+ // to copy the required display data into place.
+ virtual void grabRegion(const Region& region) {}
+
+ protected:
+ PixelBuffer();
+ PixelFormat format;
+ int width_, height_;
+ ColourMap* colourmap;
+ };
+
+ // FullFramePixelBuffer
+
+ class FullFramePixelBuffer : public PixelBuffer {
+ public:
+ FullFramePixelBuffer(const PixelFormat& pf, int width, int height,
+ rdr::U8* data_, ColourMap* cm);
+ virtual ~FullFramePixelBuffer();
+
+ // - Get the number of pixels per row in the actual pixel buffer data area
+ // This may in some cases NOT be the same as width().
+ virtual int getStride() const;
+
+ // Get a pointer to specified pixel data
+ virtual rdr::U8* getPixelsRW(const Rect& r, int* stride);
+ virtual const rdr::U8* getPixelsR(const Rect& r, int* stride) {
+ return getPixelsRW(r, stride);
+ }
+
+ ///////////////////////////////////////////////
+ // Basic rendering operations
+ // These operations DO NOT clip to the pixelbuffer area, or trap overruns.
+
+ // Fill a rectangle
+ virtual void fillRect(const Rect &dest, Pixel pix);
+
+ // Copy pixel data to the buffer
+ virtual void imageRect(const Rect &dest, const void* pixels, int stride=0);
+
+ // Copy pixel data from one PixelBuffer location to another
+ virtual void copyRect(const Rect &dest, const Point &move_by_delta);
+
+ // Copy pixel data to the buffer through a mask
+ // pixels is a pointer to the pixel to be copied to r.tl.
+ // maskPos specifies the pixel offset in the mask to start from.
+ // mask_ is a pointer to the mask bits at (0,0).
+ // pStride and mStride are the strides of the pixel and mask buffers.
+ virtual void maskRect(const Rect& r, const void* pixels, const void* mask_);
+
+ // pixel is the Pixel value to be used where mask_ is set
+ virtual void maskRect(const Rect& r, Pixel pixel, const void* mask_);
+
+ // *** Should this be visible?
+ rdr::U8* data;
+
+ protected:
+ FullFramePixelBuffer();
+ };
+
+ // -=- Managed pixel buffer class
+ // Automatically allocates enough space for the specified format & area
+
+ class ManagedPixelBuffer : public FullFramePixelBuffer {
+ public:
+ ManagedPixelBuffer();
+ ManagedPixelBuffer(const PixelFormat& pf, int width, int height);
+ virtual ~ManagedPixelBuffer();
+
+ // Manage the pixel buffer layout
+ virtual void setPF(const PixelFormat &pf);
+ virtual void setSize(int w, int h);
+
+ // Assign a colour map to the buffer
+ virtual void setColourMap(ColourMap* cm, bool own_cm);
+
+ // Return the total number of bytes of pixel data in the buffer
+ int dataLen() const { return width_ * height_ * (format.bpp/8); }
+
+ protected:
+ unsigned long datasize;
+ bool own_colourmap;
+ void checkDataSize();
+ };
+
+};
+
+#endif // __RFB_PIXEL_BUFFER_H__
diff --git a/common/rfb/PixelFormat.cxx b/common/rfb/PixelFormat.cxx
new file mode 100644
index 00000000..74b68372
--- /dev/null
+++ b/common/rfb/PixelFormat.cxx
@@ -0,0 +1,239 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <rdr/InStream.h>
+#include <rdr/OutStream.h>
+#include <rfb/PixelFormat.h>
+#include <rfb/util.h>
+
+#ifdef _WIN32
+#define strcasecmp _stricmp
+#endif
+
+using namespace rfb;
+
+PixelFormat::PixelFormat(int b, int d, bool e, bool t,
+ int rm, int gm, int bm, int rs, int gs, int bs)
+ : bpp(b), depth(d), bigEndian(e), trueColour(t),
+ redMax(rm), greenMax(gm), blueMax(bm),
+ redShift(rs), greenShift(gs), blueShift(bs)
+{
+}
+
+PixelFormat::PixelFormat()
+ : bpp(8), depth(8), bigEndian(false), trueColour(true),
+ redMax(7), greenMax(7), blueMax(3),
+ redShift(0), greenShift(3), blueShift(6)
+{
+}
+
+bool PixelFormat::equal(const PixelFormat& other) const
+{
+ return (bpp == other.bpp &&
+ depth == other.depth &&
+ (bigEndian == other.bigEndian || bpp == 8) &&
+ trueColour == other.trueColour &&
+ (!trueColour || (redMax == other.redMax &&
+ greenMax == other.greenMax &&
+ blueMax == other.blueMax &&
+ redShift == other.redShift &&
+ greenShift == other.greenShift &&
+ blueShift == other.blueShift)));
+}
+
+void PixelFormat::read(rdr::InStream* is)
+{
+ bpp = is->readU8();
+ depth = is->readU8();
+ bigEndian = is->readU8();
+ trueColour = is->readU8();
+ redMax = is->readU16();
+ greenMax = is->readU16();
+ blueMax = is->readU16();
+ redShift = is->readU8();
+ greenShift = is->readU8();
+ blueShift = is->readU8();
+ is->skip(3);
+}
+
+void PixelFormat::write(rdr::OutStream* os) const
+{
+ os->writeU8(bpp);
+ os->writeU8(depth);
+ os->writeU8(bigEndian);
+ os->writeU8(trueColour);
+ os->writeU16(redMax);
+ os->writeU16(greenMax);
+ os->writeU16(blueMax);
+ os->writeU8(redShift);
+ os->writeU8(greenShift);
+ os->writeU8(blueShift);
+ os->pad(3);
+}
+
+Pixel PixelFormat::pixelFromRGB(rdr::U16 red, rdr::U16 green, rdr::U16 blue,
+ ColourMap* cm) const
+{
+ if (trueColour) {
+ rdr::U32 r = ((rdr::U32)red * redMax + 32767) / 65535;
+ rdr::U32 g = ((rdr::U32)green * greenMax + 32767) / 65535;
+ rdr::U32 b = ((rdr::U32)blue * blueMax + 32767) / 65535;
+
+ return (r << redShift) | (g << greenShift) | (b << blueShift);
+ } else if (cm) {
+ // Try to find the closest pixel by Cartesian distance
+ int colours = 1 << depth;
+ int diff = 256 * 256 * 4;
+ int col = 0;
+ for (int i=0; i<colours; i++) {
+ int r, g, b;
+ cm->lookup(i, &r, &g, &b);
+ int rd = (r-red) >> 8;
+ int gd = (g-green) >> 8;
+ int bd = (b-blue) >> 8;
+ int d = rd*rd + gd*gd + bd*bd;
+ if (d < diff) {
+ col = i;
+ diff = d;
+ }
+ }
+ return col;
+ }
+ // XXX just return 0 for colour map?
+ return 0;
+}
+
+
+void PixelFormat::rgbFromPixel(Pixel p, ColourMap* cm, Colour* rgb) const
+{
+ if (trueColour) {
+ rgb->r = (((p >> redShift ) & redMax ) * 65535 + redMax /2) / redMax;
+ rgb->g = (((p >> greenShift) & greenMax) * 65535 + greenMax/2) / greenMax;
+ rgb->b = (((p >> blueShift ) & blueMax ) * 65535 + blueMax /2) / blueMax;
+ } else {
+ cm->lookup(p, &rgb->r, &rgb->g, &rgb->b);
+ }
+}
+
+
+void PixelFormat::print(char* str, int len) const
+{
+ // Unfortunately snprintf is not widely available so we build the string up
+ // using strncat - not pretty, but should be safe against buffer overruns.
+
+ char num[20];
+ if (len < 1) return;
+ str[0] = 0;
+ strncat(str, "depth ", len-1-strlen(str));
+ sprintf(num,"%d",depth);
+ strncat(str, num, len-1-strlen(str));
+ strncat(str, " (", len-1-strlen(str));
+ sprintf(num,"%d",bpp);
+ strncat(str, num, len-1-strlen(str));
+ strncat(str, "bpp)", len-1-strlen(str));
+ if (bpp != 8) {
+ if (bigEndian)
+ strncat(str, " big-endian", len-1-strlen(str));
+ else
+ strncat(str, " little-endian", len-1-strlen(str));
+ }
+
+ if (!trueColour) {
+ strncat(str, " color-map", len-1-strlen(str));
+ return;
+ }
+
+ if (blueShift == 0 && greenShift > blueShift && redShift > greenShift &&
+ blueMax == (1 << greenShift) - 1 &&
+ greenMax == (1 << (redShift-greenShift)) - 1 &&
+ redMax == (1 << (depth-redShift)) - 1)
+ {
+ strncat(str, " rgb", len-1-strlen(str));
+ sprintf(num,"%d",depth-redShift);
+ strncat(str, num, len-1-strlen(str));
+ sprintf(num,"%d",redShift-greenShift);
+ strncat(str, num, len-1-strlen(str));
+ sprintf(num,"%d",greenShift);
+ strncat(str, num, len-1-strlen(str));
+ return;
+ }
+
+ if (redShift == 0 && greenShift > redShift && blueShift > greenShift &&
+ redMax == (1 << greenShift) - 1 &&
+ greenMax == (1 << (blueShift-greenShift)) - 1 &&
+ blueMax == (1 << (depth-blueShift)) - 1)
+ {
+ strncat(str, " bgr", len-1-strlen(str));
+ sprintf(num,"%d",depth-blueShift);
+ strncat(str, num, len-1-strlen(str));
+ sprintf(num,"%d",blueShift-greenShift);
+ strncat(str, num, len-1-strlen(str));
+ sprintf(num,"%d",greenShift);
+ strncat(str, num, len-1-strlen(str));
+ return;
+ }
+
+ strncat(str, " rgb max ", len-1-strlen(str));
+ sprintf(num,"%d,",redMax);
+ strncat(str, num, len-1-strlen(str));
+ sprintf(num,"%d,",greenMax);
+ strncat(str, num, len-1-strlen(str));
+ sprintf(num,"%d",blueMax);
+ strncat(str, num, len-1-strlen(str));
+ strncat(str, " shift ", len-1-strlen(str));
+ sprintf(num,"%d,",redShift);
+ strncat(str, num, len-1-strlen(str));
+ sprintf(num,"%d,",greenShift);
+ strncat(str, num, len-1-strlen(str));
+ sprintf(num,"%d",blueShift);
+ strncat(str, num, len-1-strlen(str));
+}
+
+
+bool PixelFormat::parse(const char* str)
+{
+ char rgbbgr[4];
+ int bits1, bits2, bits3;
+ if (sscanf(str, "%3s%1d%1d%1d", rgbbgr, &bits1, &bits2, &bits3) < 4)
+ return false;
+
+ depth = bits1 + bits2 + bits3;
+ bpp = depth <= 8 ? 8 : ((depth <= 16) ? 16 : 32);
+ trueColour = true;
+ rdr::U32 endianTest = 1;
+ bigEndian = (*(rdr::U8*)&endianTest == 0);
+
+ greenShift = bits3;
+ greenMax = (1 << bits2) - 1;
+
+ if (strcasecmp(rgbbgr, "bgr") == 0) {
+ redShift = 0;
+ redMax = (1 << bits3) - 1;
+ blueShift = bits3 + bits2;
+ blueMax = (1 << bits1) - 1;
+ } else if (strcasecmp(rgbbgr, "rgb") == 0) {
+ blueShift = 0;
+ blueMax = (1 << bits3) - 1;
+ redShift = bits3 + bits2;
+ redMax = (1 << bits1) - 1;
+ } else {
+ return false;
+ }
+ return true;
+}
diff --git a/common/rfb/PixelFormat.h b/common/rfb/PixelFormat.h
new file mode 100644
index 00000000..111c38cb
--- /dev/null
+++ b/common/rfb/PixelFormat.h
@@ -0,0 +1,58 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+//
+// PixelFormat - structure to represent a pixel format. Also has useful
+// methods for reading & writing to streams, etc.
+//
+
+#ifndef __RFB_PIXELFORMAT_H__
+#define __RFB_PIXELFORMAT_H__
+
+#include <rfb/Pixel.h>
+#include <rfb/ColourMap.h>
+
+namespace rdr { class InStream; class OutStream; }
+
+namespace rfb {
+
+ class PixelFormat {
+ public:
+ PixelFormat(int b, int d, bool e, bool t,
+ int rm=0, int gm=0, int bm=0, int rs=0, int gs=0, int bs=0);
+ PixelFormat();
+ bool equal(const PixelFormat& other) const;
+ void read(rdr::InStream* is);
+ void write(rdr::OutStream* os) const;
+ Pixel pixelFromRGB(rdr::U16 red, rdr::U16 green, rdr::U16 blue, ColourMap* cm=0) const;
+ void rgbFromPixel(Pixel pix, ColourMap* cm, Colour* rgb) const;
+ void print(char* str, int len) const;
+ bool parse(const char* str);
+
+ int bpp;
+ int depth;
+ bool bigEndian;
+ bool trueColour;
+ int redMax;
+ int greenMax;
+ int blueMax;
+ int redShift;
+ int greenShift;
+ int blueShift;
+ };
+}
+#endif
diff --git a/common/rfb/RREDecoder.cxx b/common/rfb/RREDecoder.cxx
new file mode 100644
index 00000000..da56ee7c
--- /dev/null
+++ b/common/rfb/RREDecoder.cxx
@@ -0,0 +1,58 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#include <rfb/CMsgReader.h>
+#include <rfb/CMsgHandler.h>
+#include <rfb/RREDecoder.h>
+
+using namespace rfb;
+
+#define EXTRA_ARGS CMsgHandler* handler
+#define FILL_RECT(r, p) handler->fillRect(r, p)
+#define IMAGE_RECT(r, p) handler->imageRect(r, p)
+#define BPP 8
+#include <rfb/rreDecode.h>
+#undef BPP
+#define BPP 16
+#include <rfb/rreDecode.h>
+#undef BPP
+#define BPP 32
+#include <rfb/rreDecode.h>
+#undef BPP
+
+Decoder* RREDecoder::create(CMsgReader* reader)
+{
+ return new RREDecoder(reader);
+}
+
+RREDecoder::RREDecoder(CMsgReader* reader_) : reader(reader_)
+{
+}
+
+RREDecoder::~RREDecoder()
+{
+}
+
+void RREDecoder::readRect(const Rect& r, CMsgHandler* handler)
+{
+ rdr::InStream* is = reader->getInStream();
+ switch (reader->bpp()) {
+ case 8: rreDecode8 (r, is, handler); break;
+ case 16: rreDecode16(r, is, handler); break;
+ case 32: rreDecode32(r, is, handler); break;
+ }
+}
diff --git a/common/rfb/RREDecoder.h b/common/rfb/RREDecoder.h
new file mode 100644
index 00000000..2309f754
--- /dev/null
+++ b/common/rfb/RREDecoder.h
@@ -0,0 +1,35 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#ifndef __RFB_RREDECODER_H__
+#define __RFB_RREDECODER_H__
+
+#include <rfb/Decoder.h>
+
+namespace rfb {
+
+ class RREDecoder : public Decoder {
+ public:
+ static Decoder* create(CMsgReader* reader);
+ virtual void readRect(const Rect& r, CMsgHandler* handler);
+ virtual ~RREDecoder();
+ private:
+ RREDecoder(CMsgReader* reader);
+ CMsgReader* reader;
+ };
+}
+#endif
diff --git a/common/rfb/RREEncoder.cxx b/common/rfb/RREEncoder.cxx
new file mode 100644
index 00000000..b000e9d3
--- /dev/null
+++ b/common/rfb/RREEncoder.cxx
@@ -0,0 +1,75 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#include <rdr/OutStream.h>
+#include <rfb/ImageGetter.h>
+#include <rfb/encodings.h>
+#include <rfb/SMsgWriter.h>
+#include <rfb/RREEncoder.h>
+
+using namespace rfb;
+
+#define BPP 8
+#include <rfb/rreEncode.h>
+#undef BPP
+#define BPP 16
+#include <rfb/rreEncode.h>
+#undef BPP
+#define BPP 32
+#include <rfb/rreEncode.h>
+#undef BPP
+
+Encoder* RREEncoder::create(SMsgWriter* writer)
+{
+ return new RREEncoder(writer);
+}
+
+RREEncoder::RREEncoder(SMsgWriter* writer_) : writer(writer_)
+{
+}
+
+RREEncoder::~RREEncoder()
+{
+}
+
+bool RREEncoder::writeRect(const Rect& r, ImageGetter* ig, Rect* actual)
+{
+ int w = r.width();
+ int h = r.height();
+ rdr::U8* imageBuf = writer->getImageBuf(w*h);
+ ig->getImage(imageBuf, r);
+
+ mos.clear();
+
+ int nSubrects = -1;
+ switch (writer->bpp()) {
+ case 8: nSubrects = rreEncode8(imageBuf, w, h, &mos); break;
+ case 16: nSubrects = rreEncode16(imageBuf, w, h, &mos); break;
+ case 32: nSubrects = rreEncode32(imageBuf, w, h, &mos); break;
+ }
+
+ if (nSubrects < 0) {
+ return writer->writeRect(r, encodingRaw, ig, actual);
+ }
+
+ writer->startRect(r, encodingRRE);
+ rdr::OutStream* os = writer->getOutStream();
+ os->writeU32(nSubrects);
+ os->writeBytes(mos.data(), mos.length());
+ writer->endRect();
+ return true;
+}
diff --git a/common/rfb/RREEncoder.h b/common/rfb/RREEncoder.h
new file mode 100644
index 00000000..1281410d
--- /dev/null
+++ b/common/rfb/RREEncoder.h
@@ -0,0 +1,37 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#ifndef __RFB_RREENCODER_H__
+#define __RFB_RREENCODER_H__
+
+#include <rdr/MemOutStream.h>
+#include <rfb/Encoder.h>
+
+namespace rfb {
+
+ class RREEncoder : public Encoder {
+ public:
+ static Encoder* create(SMsgWriter* writer);
+ virtual bool writeRect(const Rect& r, ImageGetter* ig, Rect* actual);
+ virtual ~RREEncoder();
+ private:
+ RREEncoder(SMsgWriter* writer);
+ SMsgWriter* writer;
+ rdr::MemOutStream mos;
+ };
+}
+#endif
diff --git a/common/rfb/RawDecoder.cxx b/common/rfb/RawDecoder.cxx
new file mode 100644
index 00000000..57cb37bc
--- /dev/null
+++ b/common/rfb/RawDecoder.cxx
@@ -0,0 +1,55 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#include <rdr/InStream.h>
+#include <rfb/CMsgReader.h>
+#include <rfb/CMsgHandler.h>
+#include <rfb/RawDecoder.h>
+
+using namespace rfb;
+
+Decoder* RawDecoder::create(CMsgReader* reader)
+{
+ return new RawDecoder(reader);
+}
+
+RawDecoder::RawDecoder(CMsgReader* reader_) : reader(reader_)
+{
+}
+
+RawDecoder::~RawDecoder()
+{
+}
+
+void RawDecoder::readRect(const Rect& r, CMsgHandler* handler)
+{
+ int x = r.tl.x;
+ int y = r.tl.y;
+ int w = r.width();
+ int h = r.height();
+ int nPixels;
+ rdr::U8* imageBuf = reader->getImageBuf(w, w*h, &nPixels);
+ int bytesPerRow = w * (reader->bpp() / 8);
+ while (h > 0) {
+ int nRows = nPixels / w;
+ if (nRows > h) nRows = h;
+ reader->getInStream()->readBytes(imageBuf, nRows * bytesPerRow);
+ handler->imageRect(Rect(x, y, x+w, y+nRows), imageBuf);
+ h -= nRows;
+ y += nRows;
+ }
+}
diff --git a/common/rfb/RawDecoder.h b/common/rfb/RawDecoder.h
new file mode 100644
index 00000000..9fdbb220
--- /dev/null
+++ b/common/rfb/RawDecoder.h
@@ -0,0 +1,35 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#ifndef __RFB_RAWDECODER_H__
+#define __RFB_RAWDECODER_H__
+
+#include <rfb/Decoder.h>
+
+namespace rfb {
+
+ class RawDecoder : public Decoder {
+ public:
+ static Decoder* create(CMsgReader* reader);
+ virtual void readRect(const Rect& r, CMsgHandler* handler);
+ virtual ~RawDecoder();
+ private:
+ RawDecoder(CMsgReader* reader);
+ CMsgReader* reader;
+ };
+}
+#endif
diff --git a/common/rfb/RawEncoder.cxx b/common/rfb/RawEncoder.cxx
new file mode 100644
index 00000000..a2545b61
--- /dev/null
+++ b/common/rfb/RawEncoder.cxx
@@ -0,0 +1,59 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#include <rdr/OutStream.h>
+#include <rfb/ImageGetter.h>
+#include <rfb/encodings.h>
+#include <rfb/SMsgWriter.h>
+#include <rfb/RawEncoder.h>
+
+using namespace rfb;
+
+Encoder* RawEncoder::create(SMsgWriter* writer)
+{
+ return new RawEncoder(writer);
+}
+
+RawEncoder::RawEncoder(SMsgWriter* writer_) : writer(writer_)
+{
+}
+
+RawEncoder::~RawEncoder()
+{
+}
+
+bool RawEncoder::writeRect(const Rect& r, ImageGetter* ig, Rect* actual)
+{
+ int x = r.tl.x;
+ int y = r.tl.y;
+ int w = r.width();
+ int h = r.height();
+ int nPixels;
+ rdr::U8* imageBuf = writer->getImageBuf(w, w*h, &nPixels);
+ int bytesPerRow = w * (writer->bpp() / 8);
+ writer->startRect(r, encodingRaw);
+ while (h > 0) {
+ int nRows = nPixels / w;
+ if (nRows > h) nRows = h;
+ ig->getImage(imageBuf, Rect(x, y, x+w, y+nRows));
+ writer->getOutStream()->writeBytes(imageBuf, nRows * bytesPerRow);
+ h -= nRows;
+ y += nRows;
+ }
+ writer->endRect();
+ return true;
+}
diff --git a/common/rfb/RawEncoder.h b/common/rfb/RawEncoder.h
new file mode 100644
index 00000000..1b9ad929
--- /dev/null
+++ b/common/rfb/RawEncoder.h
@@ -0,0 +1,35 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#ifndef __RFB_RAWENCODER_H__
+#define __RFB_RAWENCODER_H__
+
+#include <rfb/Encoder.h>
+
+namespace rfb {
+
+ class RawEncoder : public Encoder {
+ public:
+ static Encoder* create(SMsgWriter* writer);
+ virtual bool writeRect(const Rect& r, ImageGetter* ig, Rect* actual);
+ virtual ~RawEncoder();
+ private:
+ RawEncoder(SMsgWriter* writer);
+ SMsgWriter* writer;
+ };
+}
+#endif
diff --git a/common/rfb/Rect.h b/common/rfb/Rect.h
new file mode 100644
index 00000000..52e92b57
--- /dev/null
+++ b/common/rfb/Rect.h
@@ -0,0 +1,116 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// rfb::Rect and rfb::Point structures
+
+#ifndef __RFB_RECT_INCLUDED__
+#define __RFB_RECT_INCLUDED__
+
+// Some platforms (e.g. Windows) include max() and min() macros in their
+// standard headers, but they are also standard C++ template functions, so some
+// C++ headers will undefine them. So we steer clear of the names min and max
+// and define __rfbmin and __rfbmax instead.
+
+#ifndef __rfbmax
+#define __rfbmax(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+#ifndef __rfbmin
+#define __rfbmin(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+namespace rfb {
+
+ // rfb::Point
+ //
+ // Represents a point in 2D space, by X and Y coordinates.
+ // Can also be used to represent a delta, or offset, between
+ // two Points.
+ // Functions are provided to allow Points to be compared for
+ // equality and translated by a supplied offset.
+ // Functions are also provided to negate offset Points.
+
+ struct Point {
+ Point() : x(0), y(0) {}
+ Point(int x_, int y_) : x(x_), y(y_) {}
+ inline Point negate() const {return Point(-x, -y);}
+ inline bool equals(const Point &p) const {return x==p.x && y==p.y;}
+ inline Point translate(const Point &p) const {return Point(x+p.x, y+p.y);}
+ inline Point subtract(const Point &p) const {return Point(x-p.x, y-p.y);}
+ int x, y;
+ };
+
+ // rfb::Rect
+ //
+ // Represents a rectangular region defined by its top-left (tl)
+ // and bottom-right (br) Points.
+ // Rects may be compared for equality, checked to determine whether
+ // or not they are empty, cleared (made empty), or intersected with
+ // one another. The bounding rectangle of two existing Rects
+ // may be calculated, as may the area of a Rect.
+ // Rects may also be translated, in the same way as Points, by
+ // an offset specified in a Point structure.
+
+ struct Rect {
+ Rect() {}
+ Rect(Point tl_, Point br_) : tl(tl_), br(br_) {}
+ Rect(int x1, int y1, int x2, int y2) : tl(x1, y1), br(x2, y2) {}
+ inline void setXYWH(int x, int y, int w, int h) {
+ tl.x = x; tl.y = y; br.x = x+w; br.y = y+h;
+ }
+ inline Rect intersect(const Rect &r) const {
+ Rect result;
+ result.tl.x = __rfbmax(tl.x, r.tl.x);
+ result.tl.y = __rfbmax(tl.y, r.tl.y);
+ result.br.x = __rfbmax(__rfbmin(br.x, r.br.x), result.tl.x);
+ result.br.y = __rfbmax(__rfbmin(br.y, r.br.y), result.tl.y);
+ return result;
+ }
+ inline Rect union_boundary(const Rect &r) const {
+ if (r.is_empty()) return *this;
+ if (is_empty()) return r;
+ Rect result;
+ result.tl.x = __rfbmin(tl.x, r.tl.x);
+ result.tl.y = __rfbmin(tl.y, r.tl.y);
+ result.br.x = __rfbmax(br.x, r.br.x);
+ result.br.y = __rfbmax(br.y, r.br.y);
+ return result;
+ }
+ inline Rect translate(const Point &p) const {
+ return Rect(tl.translate(p), br.translate(p));
+ }
+ inline bool equals(const Rect &r) const {return r.tl.equals(tl) && r.br.equals(br);}
+ inline bool is_empty() const {return (tl.x >= br.x) || (tl.y >= br.y);}
+ inline void clear() {tl = Point(); br = Point();}
+ inline bool enclosed_by(const Rect &r) const {
+ return (tl.x>=r.tl.x) && (tl.y>=r.tl.y) && (br.x<=r.br.x) && (br.y<=r.br.y);
+ }
+ inline bool overlaps(const Rect &r) const {
+ return tl.x < r.br.x && tl.y < r.br.y && br.x > r.tl.x && br.y > r.tl.y;
+ }
+ inline unsigned int area() const {return is_empty() ? 0 : (br.x-tl.x)*(br.y-tl.y);}
+ inline Point dimensions() const {return Point(width(), height());}
+ inline int width() const {return br.x-tl.x;}
+ inline int height() const {return br.y-tl.y;}
+ inline bool contains(const Point &p) const {
+ return (tl.x<=p.x) && (tl.y<=p.y) && (br.x>p.x) && (br.y>p.y);
+ }
+ Point tl;
+ Point br;
+ };
+}
+#endif // __RFB_RECT_INCLUDED__
diff --git a/common/rfb/Region.cxx b/common/rfb/Region.cxx
new file mode 100644
index 00000000..7965a6c4
--- /dev/null
+++ b/common/rfb/Region.cxx
@@ -0,0 +1,248 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// Cross-platform Region class based on the X11 region implementation. Note
+// that for efficiency this code manipulates the Xlib region structure
+// directly. Apart from the layout of the structure, there is one other key
+// assumption made: a Region returned from XCreateRegion must always have its
+// rects member allocated so that there is space for at least one rectangle.
+//
+
+#include <rfb/Region.h>
+#include <Xregion/Xregion.h>
+#include <Xregion/region.h>
+#include <assert.h>
+#include <stdio.h>
+
+// A _RectRegion must never be passed as a return parameter to the Xlib region
+// operations. This is because for efficiency its "rects" member has not been
+// allocated with Xmalloc. It is however safe to pass it as an input
+// parameter.
+
+class _RectRegion {
+public:
+ _RectRegion(const rfb::Rect& r) {
+ region.rects = &region.extents;
+ region.numRects = 1;
+ region.extents.x1 = r.tl.x;
+ region.extents.y1 = r.tl.y;
+ region.extents.x2 = r.br.x;
+ region.extents.y2 = r.br.y;
+ region.size = 1;
+ if (r.is_empty())
+ region.numRects = 0;
+ }
+ REGION region;
+};
+
+
+rfb::Region::Region() {
+ xrgn = XCreateRegion();
+ assert(xrgn);
+}
+
+rfb::Region::Region(const Rect& r) {
+ xrgn = XCreateRegion();
+ assert(xrgn);
+ reset(r);
+}
+
+rfb::Region::Region(const rfb::Region& r) {
+ xrgn = XCreateRegion();
+ assert(xrgn);
+ XUnionRegion(xrgn, r.xrgn, xrgn);
+}
+
+rfb::Region::~Region() {
+ XDestroyRegion(xrgn);
+}
+
+rfb::Region& rfb::Region::operator=(const rfb::Region& r) {
+ clear();
+ XUnionRegion(xrgn, r.xrgn, xrgn);
+ return *this;
+}
+
+void rfb::Region::clear() {
+ xrgn->numRects = 0;
+ xrgn->extents.x1 = 0;
+ xrgn->extents.y1 = 0;
+ xrgn->extents.x2 = 0;
+ xrgn->extents.y2 = 0;
+}
+
+void rfb::Region::reset(const Rect& r) {
+ if (r.is_empty()) {
+ clear();
+ } else {
+ xrgn->numRects = 1;
+ xrgn->rects[0].x1 = xrgn->extents.x1 = r.tl.x;
+ xrgn->rects[0].y1 = xrgn->extents.y1 = r.tl.y;
+ xrgn->rects[0].x2 = xrgn->extents.x2 = r.br.x;
+ xrgn->rects[0].y2 = xrgn->extents.y2 = r.br.y;
+ }
+}
+
+void rfb::Region::translate(const Point& delta) {
+ XOffsetRegion(xrgn, delta.x, delta.y);
+}
+
+void rfb::Region::setOrderedRects(const std::vector<Rect>& rects) {
+ clear();
+ std::vector<Rect>::const_iterator i;
+ for (i=rects.begin(); i != rects.end(); i++) {
+ _RectRegion rr(*i);
+ XUnionRegion(xrgn, &rr.region, xrgn);
+ }
+}
+
+void rfb::Region::setExtentsAndOrderedRects(const ShortRect* extents,
+ int nRects, const ShortRect* rects)
+{
+ if (xrgn->size < nRects)
+ {
+ BOX* prevRects = xrgn->rects;
+ xrgn->rects = (BOX*)Xrealloc((char*)xrgn->rects, nRects * sizeof(BOX));
+ if (!xrgn->rects) {
+ fprintf(stderr,"Xrealloc failed\n");
+ Xfree(prevRects);
+ return;
+ }
+ xrgn->size = nRects;
+ }
+
+ xrgn->numRects = nRects;
+ xrgn->extents.x1 = extents->x1;
+ xrgn->extents.y1 = extents->y1;
+ xrgn->extents.x2 = extents->x2;
+ xrgn->extents.y2 = extents->y2;
+ for (int i = 0; i < nRects; i++) {
+ xrgn->rects[i].x1 = rects[i].x1;
+ xrgn->rects[i].y1 = rects[i].y1;
+ xrgn->rects[i].x2 = rects[i].x2;
+ xrgn->rects[i].y2 = rects[i].y2;
+ }
+}
+
+void rfb::Region::copyFrom(const rfb::Region& r) {
+ XUnionRegion(r.xrgn, r.xrgn, xrgn);
+}
+
+void rfb::Region::assign_intersect(const rfb::Region& r) {
+ XIntersectRegion(xrgn, r.xrgn, xrgn);
+}
+
+void rfb::Region::assign_union(const rfb::Region& r) {
+ XUnionRegion(xrgn, r.xrgn, xrgn);
+}
+
+void rfb::Region::assign_subtract(const rfb::Region& r) {
+ XSubtractRegion(xrgn, r.xrgn, xrgn);
+}
+
+rfb::Region rfb::Region::intersect(const rfb::Region& r) const {
+ rfb::Region ret;
+ XIntersectRegion(xrgn, r.xrgn, ret.xrgn);
+ return ret;
+}
+
+rfb::Region rfb::Region::union_(const rfb::Region& r) const {
+ rfb::Region ret;
+ XUnionRegion(xrgn, r.xrgn, ret.xrgn);
+ return ret;
+}
+
+rfb::Region rfb::Region::subtract(const rfb::Region& r) const {
+ rfb::Region ret;
+ XSubtractRegion(xrgn, r.xrgn, ret.xrgn);
+ return ret;
+}
+
+bool rfb::Region::equals(const rfb::Region& r) const {
+ return XEqualRegion(xrgn, r.xrgn);
+}
+
+int rfb::Region::numRects() const {
+ return xrgn->numRects;
+}
+
+bool rfb::Region::get_rects(std::vector<Rect>* rects,
+ bool left2right, bool topdown, int maxArea) const
+{
+ int nRects = xrgn->numRects;
+ int xInc = left2right ? 1 : -1;
+ int yInc = topdown ? 1 : -1;
+ int i = topdown ? 0 : nRects-1;
+ rects->clear();
+ rects->reserve(nRects);
+
+ while (nRects > 0) {
+ int firstInNextBand = i;
+ int nRectsInBand = 0;
+
+ while (nRects > 0 && xrgn->rects[firstInNextBand].y1 == xrgn->rects[i].y1)
+ {
+ firstInNextBand += yInc;
+ nRects--;
+ nRectsInBand++;
+ }
+
+ if (xInc != yInc)
+ i = firstInNextBand - yInc;
+
+ while (nRectsInBand > 0) {
+ int y = xrgn->rects[i].y1;
+ int h = maxArea / (xrgn->rects[i].x2 - xrgn->rects[i].x1);
+ if (!h) h = xrgn->rects[i].y2 - y;
+ do {
+ if (h > xrgn->rects[i].y2 - y)
+ h = xrgn->rects[i].y2 - y;
+ Rect r(xrgn->rects[i].x1, y, xrgn->rects[i].x2, y+h);
+ rects->push_back(r);
+ y += h;
+ } while (y < xrgn->rects[i].y2);
+ i += xInc;
+ nRectsInBand--;
+ }
+
+ i = firstInNextBand;
+ }
+
+ return !rects->empty();
+}
+
+rfb::Rect rfb::Region::get_bounding_rect() const {
+ return Rect(xrgn->extents.x1, xrgn->extents.y1,
+ xrgn->extents.x2, xrgn->extents.y2);
+}
+
+
+void rfb::Region::debug_print(const char* prefix) const
+{
+ fprintf(stderr,"%s num rects %3ld extents %3d,%3d %3dx%3d\n",
+ prefix, xrgn->numRects, xrgn->extents.x1, xrgn->extents.y1,
+ xrgn->extents.x2-xrgn->extents.x1,
+ xrgn->extents.y2-xrgn->extents.y1);
+
+ for (int i = 0; i < xrgn->numRects; i++) {
+ fprintf(stderr," rect %3d,%3d %3dx%3d\n",
+ xrgn->rects[i].x1, xrgn->rects[i].y1,
+ xrgn->rects[i].x2-xrgn->rects[i].x1,
+ xrgn->rects[i].y2-xrgn->rects[i].y1);
+ }
+}
diff --git a/common/rfb/Region.h b/common/rfb/Region.h
new file mode 100644
index 00000000..93375569
--- /dev/null
+++ b/common/rfb/Region.h
@@ -0,0 +1,84 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// Cross-platform Region class based on the X11 region implementation
+
+#ifndef __RFB_REGION_INCLUDED__
+#define __RFB_REGION_INCLUDED__
+
+#include <rfb/Rect.h>
+#include <vector>
+
+struct _XRegion;
+
+namespace rfb {
+
+ struct ShortRect {
+ short x1, y1, x2, y2;
+ };
+
+ class Region {
+ public:
+ // Create an empty region
+ Region();
+ // Create a rectangular region
+ Region(const Rect& r);
+
+ Region(const Region& r);
+ Region &operator=(const Region& src);
+
+ ~Region();
+
+ // the following methods alter the region in place:
+
+ void clear();
+ void reset(const Rect& r);
+ void translate(const rfb::Point& delta);
+ void setOrderedRects(const std::vector<Rect>& rects);
+ void setExtentsAndOrderedRects(const ShortRect* extents, int nRects,
+ const ShortRect* rects);
+ void copyFrom(const Region& r);
+
+ void assign_intersect(const Region& r);
+ void assign_union(const Region& r);
+ void assign_subtract(const Region& r);
+
+ // the following three operations return a new region:
+
+ Region intersect(const Region& r) const;
+ Region union_(const Region& r) const;
+ Region subtract(const Region& r) const;
+
+ bool equals(const Region& b) const;
+ int numRects() const;
+ bool is_empty() const { return numRects() == 0; }
+
+ bool get_rects(std::vector<Rect>* rects, bool left2right=true,
+ bool topdown=true, int maxArea=0) const;
+ Rect get_bounding_rect() const;
+
+ void debug_print(const char *prefix) const;
+
+ protected:
+
+ struct _XRegion* xrgn;
+ };
+
+};
+
+#endif // __RFB_REGION_INCLUDED__
diff --git a/common/rfb/SConnection.cxx b/common/rfb/SConnection.cxx
new file mode 100644
index 00000000..1422b546
--- /dev/null
+++ b/common/rfb/SConnection.cxx
@@ -0,0 +1,322 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <rfb/Exception.h>
+#include <rfb/secTypes.h>
+#include <rfb/SMsgReaderV3.h>
+#include <rfb/SMsgWriterV3.h>
+#include <rfb/SConnection.h>
+#include <rfb/ServerCore.h>
+
+#include <rfb/LogWriter.h>
+
+using namespace rfb;
+
+static LogWriter vlog("SConnection");
+
+// AccessRights values
+const SConnection::AccessRights SConnection::AccessView = 0x0001;
+const SConnection::AccessRights SConnection::AccessKeyEvents = 0x0002;
+const SConnection::AccessRights SConnection::AccessPtrEvents = 0x0004;
+const SConnection::AccessRights SConnection::AccessCutText = 0x0008;
+const SConnection::AccessRights SConnection::AccessDefault = 0x03ff;
+const SConnection::AccessRights SConnection::AccessNoQuery = 0x0400;
+const SConnection::AccessRights SConnection::AccessFull = 0xffff;
+
+
+SConnection::SConnection(SSecurityFactory* secFact, bool reverseConnection_)
+ : readyForSetColourMapEntries(false),
+ is(0), os(0), reader_(0), writer_(0),
+ security(0), securityFactory(secFact), state_(RFBSTATE_UNINITIALISED),
+ reverseConnection(reverseConnection_)
+{
+ defaultMajorVersion = 3;
+ defaultMinorVersion = 8;
+ if (rfb::Server::protocol3_3)
+ defaultMinorVersion = 3;
+
+ cp.setVersion(defaultMajorVersion, defaultMinorVersion);
+}
+
+SConnection::~SConnection()
+{
+ if (security) security->destroy();
+ deleteReaderAndWriter();
+}
+
+void SConnection::deleteReaderAndWriter()
+{
+ delete reader_;
+ reader_ = 0;
+ delete writer_;
+ writer_ = 0;
+}
+
+void SConnection::setStreams(rdr::InStream* is_, rdr::OutStream* os_)
+{
+ is = is_;
+ os = os_;
+}
+
+void SConnection::initialiseProtocol()
+{
+ cp.writeVersion(os);
+ state_ = RFBSTATE_PROTOCOL_VERSION;
+}
+
+void SConnection::processMsg()
+{
+ switch (state_) {
+ case RFBSTATE_PROTOCOL_VERSION: processVersionMsg(); break;
+ case RFBSTATE_SECURITY_TYPE: processSecurityTypeMsg(); break;
+ case RFBSTATE_SECURITY: processSecurityMsg(); break;
+ case RFBSTATE_INITIALISATION: processInitMsg(); break;
+ case RFBSTATE_NORMAL: reader_->readMsg(); break;
+ case RFBSTATE_QUERYING:
+ throw Exception("SConnection::processMsg: bogus data from client while "
+ "querying");
+ case RFBSTATE_UNINITIALISED:
+ throw Exception("SConnection::processMsg: not initialised yet?");
+ default:
+ throw Exception("SConnection::processMsg: invalid state");
+ }
+}
+
+void SConnection::processVersionMsg()
+{
+ vlog.debug("reading protocol version");
+ bool done;
+ if (!cp.readVersion(is, &done)) {
+ state_ = RFBSTATE_INVALID;
+ throw Exception("reading version failed: not an RFB client?");
+ }
+ if (!done) return;
+
+ vlog.info("Client needs protocol version %d.%d",
+ cp.majorVersion, cp.minorVersion);
+
+ if (cp.majorVersion != 3) {
+ // unknown protocol version
+ char msg[256];
+ sprintf(msg,"Error: client needs protocol version %d.%d, server has %d.%d",
+ cp.majorVersion, cp.minorVersion,
+ defaultMajorVersion, defaultMinorVersion);
+ throwConnFailedException(msg);
+ }
+
+ if (cp.minorVersion != 3 && cp.minorVersion != 7 && cp.minorVersion != 8) {
+ vlog.error("Client uses unofficial protocol version %d.%d",
+ cp.majorVersion,cp.minorVersion);
+ if (cp.minorVersion >= 8)
+ cp.minorVersion = 8;
+ else if (cp.minorVersion == 7)
+ cp.minorVersion = 7;
+ else
+ cp.minorVersion = 3;
+ vlog.error("Assuming compatibility with version %d.%d",
+ cp.majorVersion,cp.minorVersion);
+ }
+
+ versionReceived();
+
+ std::list<rdr::U8> secTypes;
+ std::list<rdr::U8>::iterator i;
+ securityFactory->getSecTypes(&secTypes, reverseConnection);
+
+ if (cp.isVersion(3,3)) {
+
+ // cope with legacy 3.3 client only if "no authentication" or "vnc
+ // authentication" is supported.
+ for (i=secTypes.begin(); i!=secTypes.end(); i++) {
+ if (*i == secTypeNone || *i == secTypeVncAuth) break;
+ }
+ if (i == secTypes.end()) {
+ char msg[256];
+ sprintf(msg,"No supported security type for %d.%d client",
+ cp.majorVersion, cp.minorVersion);
+ throwConnFailedException(msg);
+ }
+
+ os->writeU32(*i);
+ if (*i == secTypeNone) os->flush();
+ state_ = RFBSTATE_SECURITY;
+ security = securityFactory->getSSecurity(*i, reverseConnection);
+ processSecurityMsg();
+ return;
+ }
+
+ // list supported security types for >=3.7 clients
+
+ if (secTypes.empty())
+ throwConnFailedException("No supported security types");
+
+ os->writeU8(secTypes.size());
+ for (i=secTypes.begin(); i!=secTypes.end(); i++)
+ os->writeU8(*i);
+ os->flush();
+ state_ = RFBSTATE_SECURITY_TYPE;
+}
+
+
+void SConnection::processSecurityTypeMsg()
+{
+ vlog.debug("processing security type message");
+ int secType = is->readU8();
+
+ // Verify that the requested security type should be offered
+ std::list<rdr::U8> secTypes;
+ std::list<rdr::U8>::iterator i;
+ securityFactory->getSecTypes(&secTypes, reverseConnection);
+ for (i=secTypes.begin(); i!=secTypes.end(); i++)
+ if (*i == secType) break;
+ if (i == secTypes.end())
+ throw Exception("Requested security type not available");
+
+ vlog.info("Client requests security type %s(%d)",
+ secTypeName(secType),secType);
+
+ try {
+ state_ = RFBSTATE_SECURITY;
+ security = securityFactory->getSSecurity(secType, reverseConnection);
+ } catch (rdr::Exception& e) {
+ throwConnFailedException(e.str());
+ }
+
+ processSecurityMsg();
+}
+
+void SConnection::processSecurityMsg()
+{
+ vlog.debug("processing security message");
+ try {
+ bool done = security->processMsg(this);
+ if (done) {
+ state_ = RFBSTATE_QUERYING;
+ queryConnection(security->getUserName());
+ }
+ } catch (AuthFailureException& e) {
+ vlog.error("AuthFailureException: %s", e.str());
+ os->writeU32(secResultFailed);
+ if (!cp.beforeVersion(3,8)) // 3.8 onwards have failure message
+ os->writeString(e.str());
+ os->flush();
+ throw;
+ }
+}
+
+void SConnection::processInitMsg()
+{
+ vlog.debug("reading client initialisation");
+ reader_->readClientInit();
+}
+
+void SConnection::throwConnFailedException(const char* msg)
+{
+ vlog.info(msg);
+ if (state_ == RFBSTATE_PROTOCOL_VERSION) {
+ if (cp.majorVersion == 3 && cp.minorVersion == 3) {
+ os->writeU32(0);
+ os->writeString(msg);
+ os->flush();
+ } else {
+ os->writeU8(0);
+ os->writeString(msg);
+ os->flush();
+ }
+ }
+ state_ = RFBSTATE_INVALID;
+ throw ConnFailedException(msg);
+}
+
+void SConnection::writeConnFailedFromScratch(const char* msg,
+ rdr::OutStream* os)
+{
+ os->writeBytes("RFB 003.003\n", 12);
+ os->writeU32(0);
+ os->writeString(msg);
+ os->flush();
+}
+
+void SConnection::versionReceived()
+{
+}
+
+void SConnection::authSuccess()
+{
+}
+
+void SConnection::queryConnection(const char* userName)
+{
+ approveConnection(true);
+}
+
+void SConnection::approveConnection(bool accept, const char* reason)
+{
+ if (state_ != RFBSTATE_QUERYING)
+ throw Exception("SConnection::approveConnection: invalid state");
+
+ if (!reason) reason = "Authentication failure";
+
+ if (!cp.beforeVersion(3,8) || security->getType() != secTypeNone) {
+ if (accept) {
+ os->writeU32(secResultOK);
+ } else {
+ os->writeU32(secResultFailed);
+ if (!cp.beforeVersion(3,8)) // 3.8 onwards have failure message
+ os->writeString(reason);
+ }
+ os->flush();
+ }
+
+ if (accept) {
+ state_ = RFBSTATE_INITIALISATION;
+ reader_ = new SMsgReaderV3(this, is);
+ writer_ = new SMsgWriterV3(&cp, os);
+ authSuccess();
+ } else {
+ state_ = RFBSTATE_INVALID;
+ throw AuthFailureException(reason);
+ }
+}
+
+void SConnection::setInitialColourMap()
+{
+}
+
+void SConnection::clientInit(bool shared)
+{
+ writer_->writeServerInit();
+ state_ = RFBSTATE_NORMAL;
+}
+
+void SConnection::setPixelFormat(const PixelFormat& pf)
+{
+ SMsgHandler::setPixelFormat(pf);
+ readyForSetColourMapEntries = true;
+}
+
+void SConnection::framebufferUpdateRequest(const Rect& r, bool incremental)
+{
+ if (!readyForSetColourMapEntries) {
+ readyForSetColourMapEntries = true;
+ if (!cp.pf().trueColour) {
+ setInitialColourMap();
+ }
+ }
+}
diff --git a/common/rfb/SConnection.h b/common/rfb/SConnection.h
new file mode 100644
index 00000000..6b943f5e
--- /dev/null
+++ b/common/rfb/SConnection.h
@@ -0,0 +1,193 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+//
+// SConnection - class on the server side representing a connection to a
+// client. A derived class should override methods appropriately.
+//
+
+#ifndef __RFB_SCONNECTION_H__
+#define __RFB_SCONNECTION_H__
+
+#include <rdr/InStream.h>
+#include <rdr/OutStream.h>
+#include <rfb/SMsgHandler.h>
+#include <rfb/SSecurity.h>
+
+namespace rfb {
+
+ class SMsgReader;
+ class SMsgWriter;
+ class SSecurity;
+
+ class SConnection : public SMsgHandler {
+ public:
+
+ SConnection(SSecurityFactory* sf, bool reverseConnection_);
+ virtual ~SConnection();
+
+ // Methods to initialise the connection
+
+ // setStreams() sets the streams to be used for the connection. These must
+ // be set before initialiseProtocol() and processMsg() are called. The
+ // SSecurity object may call setStreams() again to provide alternative
+ // streams over which the RFB protocol is sent (i.e. encrypting/decrypting
+ // streams). Ownership of the streams remains with the caller
+ // (i.e. SConnection will not delete them).
+ void setStreams(rdr::InStream* is, rdr::OutStream* os);
+
+ // initialiseProtocol() should be called once the streams and security
+ // types are set. Subsequently, processMsg() should be called whenever
+ // there is data to read on the InStream.
+ void initialiseProtocol();
+
+ // processMsg() should be called whenever there is data to read on the
+ // InStream. You must have called initialiseProtocol() first.
+ void processMsg();
+
+ // approveConnection() is called to either accept or reject the connection.
+ // If accept is false, the reason string gives the reason for the
+ // rejection. It can either be called directly from queryConnection() or
+ // later, after queryConnection() has returned. It can only be called when
+ // in state RFBSTATE_QUERYING. On rejection, an AuthFailureException is
+ // thrown, so this must be handled appropriately by the caller.
+ void approveConnection(bool accept, const char* reason=0);
+
+
+ // Methods to be overridden in a derived class
+
+ // versionReceived() indicates that the version number has just been read
+ // from the client. The version will already have been "cooked"
+ // to deal with unknown/bogus viewer protocol numbers.
+ virtual void versionReceived();
+
+ // authSuccess() is called when authentication has succeeded.
+ virtual void authSuccess();
+
+ // queryConnection() is called when authentication has succeeded, but
+ // before informing the client. It can be overridden to query a local user
+ // to accept the incoming connection, for example. The userName argument
+ // is the name of the user making the connection, or null (note that the
+ // storage for userName is owned by the caller). The connection must be
+ // accepted or rejected by calling approveConnection(), either directly
+ // from queryConnection() or some time later.
+ virtual void queryConnection(const char* userName);
+
+ // clientInit() is called when the ClientInit message is received. The
+ // derived class must call on to SConnection::clientInit().
+ virtual void clientInit(bool shared);
+
+ // setPixelFormat() is called when a SetPixelFormat message is received.
+ // The derived class must call on to SConnection::setPixelFormat().
+ virtual void setPixelFormat(const PixelFormat& pf);
+
+ // framebufferUpdateRequest() is called when a FramebufferUpdateRequest
+ // message is received. The derived class must call on to
+ // SConnection::framebufferUpdateRequest().
+ virtual void framebufferUpdateRequest(const Rect& r, bool incremental);
+
+ // setInitialColourMap() is called when the client needs an initial
+ // SetColourMapEntries message. In fact this only happens when the client
+ // accepts the server's default pixel format and it uses a colour map.
+ virtual void setInitialColourMap();
+
+ // setAccessRights() allows a security package to limit the access rights
+ // of a VNCSConnectionST to the server. How the access rights are treated
+ // is up to the derived class.
+
+ typedef rdr::U16 AccessRights;
+ static const AccessRights AccessView; // View display contents
+ static const AccessRights AccessKeyEvents; // Send key events
+ static const AccessRights AccessPtrEvents; // Send pointer events
+ static const AccessRights AccessCutText; // Send/receive clipboard events
+ static const AccessRights AccessDefault; // The default rights, INCLUDING FUTURE ONES
+ static const AccessRights AccessNoQuery; // Connect without local user accepting
+ static const AccessRights AccessFull; // All of the available AND FUTURE rights
+ virtual void setAccessRights(AccessRights ar) = 0;
+
+ // Other methods
+
+ // authenticated() returns true if the client has authenticated
+ // successfully.
+ bool authenticated() { return (state_ == RFBSTATE_INITIALISATION ||
+ state_ == RFBSTATE_NORMAL); }
+
+ // deleteReaderAndWriter() deletes the reader and writer associated with
+ // this connection. This may be useful if you want to delete the streams
+ // before deleting the SConnection to make sure that no attempt by the
+ // SConnection is made to read or write.
+ // XXX Do we really need this at all???
+ void deleteReaderAndWriter();
+
+ // throwConnFailedException() prints a message to the log, sends a conn
+ // failed message to the client (if possible) and throws a
+ // ConnFailedException.
+ void throwConnFailedException(const char* msg);
+
+ // writeConnFailedFromScratch() sends a conn failed message to an OutStream
+ // without the need to negotiate the protocol version first. It actually
+ // does this by assuming that the client will understand version 3.3 of the
+ // protocol.
+ static void writeConnFailedFromScratch(const char* msg,
+ rdr::OutStream* os);
+
+ SMsgReader* reader() { return reader_; }
+ SMsgWriter* writer() { return writer_; }
+
+ rdr::InStream* getInStream() { return is; }
+ rdr::OutStream* getOutStream() { return os; }
+
+ enum stateEnum {
+ RFBSTATE_UNINITIALISED,
+ RFBSTATE_PROTOCOL_VERSION,
+ RFBSTATE_SECURITY_TYPE,
+ RFBSTATE_SECURITY,
+ RFBSTATE_QUERYING,
+ RFBSTATE_INITIALISATION,
+ RFBSTATE_NORMAL,
+ RFBSTATE_CLOSING,
+ RFBSTATE_INVALID
+ };
+
+ stateEnum state() { return state_; }
+
+ // ssecurity() returns a pointer to this connection's SSecurity object, if
+ // any
+ const SSecurity* ssecurity() const { return security; }
+
+ protected:
+ void setState(stateEnum s) { state_ = s; }
+
+ bool readyForSetColourMapEntries;
+
+ void processVersionMsg();
+ void processSecurityTypeMsg();
+ void processSecurityMsg();
+ void processInitMsg();
+
+ int defaultMajorVersion, defaultMinorVersion;
+ rdr::InStream* is;
+ rdr::OutStream* os;
+ SMsgReader* reader_;
+ SMsgWriter* writer_;
+ SSecurity* security;
+ SSecurityFactory* securityFactory;
+ stateEnum state_;
+ bool reverseConnection;
+ };
+}
+#endif
diff --git a/common/rfb/SDesktop.h b/common/rfb/SDesktop.h
new file mode 100644
index 00000000..7b054e37
--- /dev/null
+++ b/common/rfb/SDesktop.h
@@ -0,0 +1,121 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+/////////////////////////////////////////////////////////////////////////////
+
+// SDesktop is an interface implemented by back-ends, on which callbacks are
+// made by the VNCServer as appropriate for pointer and keyboard events, etc.
+// SDesktop objects are always created before the VNCServer - the SDesktop
+// will be passed a pointer to the VNCServer in the start() call. If a more
+// implementation-specific pointer to the VNCServer is required then this
+// can be provided to the SDesktop via an implementation-specific method.
+//
+// An SDesktop usually has an associated PixelBuffer which it tells the
+// VNCServer via the VNCServer's setPixelBuffer() method. It can do this at
+// any time, but the PixelBuffer MUST be valid by the time the call to start()
+// returns. The PixelBuffer may be set to null again if desired when stop() is
+// called. Note that start() and stop() are guaranteed to be called
+// alternately; there should never be two calls to start() without an
+// intervening stop() and vice-versa.
+//
+
+#ifndef __RFB_SDESKTOP_H__
+#define __RFB_SDESKTOP_H__
+
+#include <rfb/PixelBuffer.h>
+#include <rfb/VNCServer.h>
+#include <rfb/InputHandler.h>
+#include <rfb/Exception.h>
+
+namespace rfb {
+
+ class VNCServer;
+
+ class SDesktop : public InputHandler {
+ public:
+ // start() is called by the server when the first client authenticates
+ // successfully, and can be used to begin any expensive tasks which are not
+ // needed when there are no clients. A valid PixelBuffer must have been
+ // set via the VNCServer's setPixelBuffer() method by the time this call
+ // returns.
+
+ virtual void start(VNCServer* vs) {}
+
+ // stop() is called by the server when there are no longer any
+ // authenticated clients, and therefore the desktop can cease any
+ // expensive tasks. No further calls to the VNCServer passed to start()
+ // can be made once stop has returned.
+
+ virtual void stop() {}
+
+ // framebufferUpdateRequest() is called to let the desktop know that at
+ // least one client has become ready for an update. Desktops can check
+ // whether there are clients ready at any time by calling the VNCServer's
+ // clientsReadyForUpdate() method.
+
+ virtual void framebufferUpdateRequest() {}
+
+ // getFbSize() returns the current dimensions of the framebuffer.
+ // This can be called even while the SDesktop is not start()ed.
+
+ virtual Point getFbSize() = 0;
+
+ // InputHandler interface
+ // pointerEvent(), keyEvent() and clientCutText() are called in response to
+ // the relevant RFB protocol messages from clients.
+ // See InputHandler for method signatures.
+ protected:
+ virtual ~SDesktop() {}
+ };
+
+ // -=- SStaticDesktop
+ // Trivial implementation of the SDesktop interface, which provides
+ // dummy input handlers and event processing routine, and exports
+ // a plain black desktop of the specified format.
+ class SStaticDesktop : public SDesktop {
+ public:
+ SStaticDesktop(const Point& size) : server(0), buffer(0) {
+ PixelFormat pf;
+ buffer = new ManagedPixelBuffer(pf, size.x, size.y);
+ if (buffer) memset(buffer->data, 0, (pf.bpp/8) * (size.x*size.y));
+ }
+ SStaticDesktop(const Point& size, const PixelFormat& pf) : buffer(0) {
+ buffer = new ManagedPixelBuffer(pf, size.x, size.y);
+ if (buffer) memset(buffer->data, 0, (pf.bpp/8) * (size.x*size.y));
+ }
+ virtual ~SStaticDesktop() {
+ if (buffer) delete buffer;
+ }
+
+ virtual void start(VNCServer* vs) {
+ server = vs;
+ server->setPixelBuffer(buffer);
+ }
+ virtual void stop() {
+ server->setPixelBuffer(0);
+ server = 0;
+ }
+
+ protected:
+ VNCServer* server;
+ ManagedPixelBuffer* buffer;
+ };
+
+};
+
+#endif // __RFB_SDESKTOP_H__
diff --git a/common/rfb/SFTMsgReader.cxx b/common/rfb/SFTMsgReader.cxx
new file mode 100644
index 00000000..22787bf0
--- /dev/null
+++ b/common/rfb/SFTMsgReader.cxx
@@ -0,0 +1,201 @@
+/* Copyright (C) 2005 TightVNC Team. All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- SFTMsgReader.cxx
+
+#include <rfb/SFTMsgReader.h>
+
+using namespace rfb;
+
+SFTMsgReader::SFTMsgReader(rdr::InStream *pIS)
+{
+ m_pIS = pIS;
+}
+
+SFTMsgReader::~SFTMsgReader()
+{
+}
+
+bool
+SFTMsgReader::readFileListRqst(unsigned int *pDirNameSize, char *pDirName,
+ unsigned int *pFlags)
+{
+ *pFlags = m_pIS->readU8();
+ unsigned int dirNameSize = m_pIS->readU16();
+
+ if (dirNameSize >= FT_FILENAME_SIZE) {
+ m_pIS->skip(dirNameSize);
+ return false;
+ } else {
+ m_pIS->readBytes(pDirName, dirNameSize);
+ *pDirNameSize = dirNameSize;
+ pDirName[dirNameSize] = '\0';
+ return true;
+ }
+}
+
+bool
+SFTMsgReader::readFileDownloadRqst(unsigned int *pFilenameSize, char *pFilename,
+ unsigned int *pPosition)
+{
+ unsigned char compressedLevel = 0;
+ return readU8U16U32StringMsg(&compressedLevel, pFilenameSize, pPosition, pFilename);
+}
+
+bool
+SFTMsgReader::readFileUploadRqst(unsigned int *pFilenameSize, char *pFilename,
+ unsigned int *pPosition)
+{
+ unsigned char compressedLevel = 0;
+ return readU8U16U32StringMsg(&compressedLevel, pFilenameSize, pPosition, pFilename);
+}
+
+char *
+SFTMsgReader::readFileUploadData(unsigned int *pDataSize, unsigned int *pModTime)
+{
+ unsigned char compressedLevel = m_pIS->readU8();
+ unsigned int realSize = m_pIS->readU16();
+ unsigned int compressedSize = m_pIS->readU16();
+
+ if ((realSize == 0) && (compressedSize == 0)) {
+ *pDataSize = 0;
+ *pModTime = m_pIS->readU32();
+ return NULL;
+ } else {
+ char *pData = new char [compressedSize];
+ m_pIS->readBytes(pData, compressedSize);
+ *pDataSize = compressedSize;
+ *pModTime = 0;
+ return pData;
+ }
+}
+
+bool
+SFTMsgReader::readFileCreateDirRqst(unsigned int *pDirNameSize, char *pDirName)
+{
+ return readU8U16StringMsg(pDirNameSize, pDirName);
+}
+
+bool
+SFTMsgReader::readFileDirSizeRqst(unsigned int *pDirNameSize, char *pDirName)
+{
+ return readU8U16StringMsg(pDirNameSize, pDirName);
+}
+
+bool
+SFTMsgReader::readFileDeleteRqst(unsigned int *pNameSize, char *pName)
+{
+ return readU8U16StringMsg(pNameSize, pName);
+}
+
+bool
+SFTMsgReader::readFileRenameRqst(unsigned int *pOldNameSize,
+ unsigned int *pNewNameSize,
+ char *pOldName, char *pNewName)
+{
+ m_pIS->skip(1);
+
+ unsigned int oldNameSize = m_pIS->readU16();
+ unsigned int newNameSize = m_pIS->readU16();
+
+ if ((oldNameSize >= *pOldNameSize) || (newNameSize >= *pNewNameSize)) {
+ m_pIS->skip(oldNameSize);
+ m_pIS->skip(newNameSize);
+ return false;
+ }
+
+ if (oldNameSize != 0) {
+ m_pIS->readBytes(pOldName, oldNameSize);
+ pOldName[oldNameSize] = '\0';
+ *pOldNameSize = oldNameSize;
+ } else {
+ *pOldNameSize = 0;
+ pOldName[0] = '\0';
+ }
+
+ if (newNameSize != 0) {
+ m_pIS->readBytes(pNewName, newNameSize);
+ pNewName[newNameSize] = '\0';
+ } else {
+ *pNewNameSize = 0;
+ pNewName[0] = '\0';
+ }
+
+ return true;
+}
+
+bool
+SFTMsgReader::readFileDownloadCancel(unsigned int *pReasonSize, char *pReason)
+{
+ return readU8U16StringMsg(pReasonSize, pReason);
+}
+
+bool
+SFTMsgReader::readFileUploadFailed(unsigned int *pReasonSize, char *pReason)
+{
+ return readU8U16StringMsg(pReasonSize, pReason);
+}
+
+bool
+SFTMsgReader::readU8U16StringMsg(unsigned int *pReasonSize, char *pReason)
+{
+ m_pIS->skip(1);
+ unsigned int reasonSize = m_pIS->readU16();
+
+ if (reasonSize >= FT_FILENAME_SIZE) {
+ m_pIS->skip(reasonSize);
+ return false;
+ } else {
+ if (reasonSize == 0) {
+ pReason[0] = '\0';
+ } else {
+ m_pIS->readBytes(pReason, reasonSize);
+ pReason[reasonSize] = '\0';
+ }
+ *pReasonSize = reasonSize;
+ return true;
+ }
+}
+
+bool
+SFTMsgReader::readU8U16U32StringMsg(unsigned char *pU8, unsigned int *pU16,
+ unsigned int *pU32, char *pString)
+{
+ *pU8 = m_pIS->readU8();
+ unsigned int strSize = m_pIS->readU16();
+ *pU32 = m_pIS->readU32();
+
+ if (strSize >= FT_FILENAME_SIZE) {
+ m_pIS->skip(strSize);
+ return false;
+ } else {
+ *pU16 = strSize;
+ if (strSize == 0) {
+ pString[0] = '\0';
+ } else {
+ m_pIS->readBytes(pString, strSize);
+ pString[strSize] = '\0';
+ }
+ return true;
+ }
+}
diff --git a/common/rfb/SFTMsgReader.h b/common/rfb/SFTMsgReader.h
new file mode 100644
index 00000000..32ac8697
--- /dev/null
+++ b/common/rfb/SFTMsgReader.h
@@ -0,0 +1,71 @@
+/* Copyright (C) 2005 TightVNC Team. All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- SFTMsgReader.h
+
+#ifndef __RFB_SFTMSGREADER_H__
+#define __RFB_SFTMSGREADER_H__
+
+#include <rdr/InStream.h>
+#include <rfb/fttypes.h>
+
+namespace rfb {
+ class SFTMsgReader
+ {
+ public:
+ SFTMsgReader(rdr::InStream *pIS);
+ ~SFTMsgReader();
+
+ bool readFileListRqst(unsigned int *pDirNameSize, char *pDirName,
+ unsigned int *pFlags);
+
+
+ bool readFileDownloadRqst(unsigned int *pFilenameSize, char *pFilename,
+ unsigned int *pPosition);
+
+ bool readFileUploadRqst(unsigned int *pFilenameSize, char *pFilename,
+ unsigned int *pPosition);
+
+ char *readFileUploadData(unsigned int *pDataSize, unsigned int *pModTime);
+
+
+ bool readFileCreateDirRqst(unsigned int *pDirNameSize, char *pDirName);
+ bool readFileDirSizeRqst(unsigned int *pDirNameSize, char *pDirName);
+ bool readFileDeleteRqst(unsigned int *pNameSize, char *pName);
+
+ bool readFileRenameRqst(unsigned int *pOldNameSize, unsigned int *pNewNameSize,
+ char *pOldName, char *pNewName);
+
+ bool readFileDownloadCancel(unsigned int *pReasonSize, char *pReason);
+ bool readFileUploadFailed(unsigned int *pReasonSize, char *pReason);
+
+ private:
+ rdr::InStream *m_pIS;
+
+ bool readU8U16StringMsg(unsigned int *pReasonSize, char *pReason);
+ bool readU8U16U32StringMsg(unsigned char *pU8, unsigned int *pU16,
+ unsigned int *pU32, char *pString);
+ };
+}
+
+#endif // __RFB_SFTMSGREADER_H__
diff --git a/common/rfb/SFTMsgWriter.cxx b/common/rfb/SFTMsgWriter.cxx
new file mode 100644
index 00000000..fa6a82f9
--- /dev/null
+++ b/common/rfb/SFTMsgWriter.cxx
@@ -0,0 +1,152 @@
+/* Copyright (C) 2005 TightVNC Team. All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- SFTMsgWriter.cxx
+
+#include <rfb/SFTMsgWriter.h>
+
+using namespace rfb;
+
+SFTMsgWriter::SFTMsgWriter(rdr::OutStream *pOS)
+{
+ m_pOS = pOS;
+}
+
+SFTMsgWriter::~SFTMsgWriter()
+{
+}
+
+bool
+SFTMsgWriter::writeFileListData(unsigned char flags, rfb::FileInfo *pFileInfo)
+{
+ unsigned int numFiles = pFileInfo->getNumEntries();
+
+ m_pOS->writeU8(msgTypeFileListData);
+ m_pOS->writeU8(flags);
+ m_pOS->writeU16(numFiles);
+
+ if (numFiles == 0) {
+ m_pOS->writeU16(0);
+ m_pOS->writeU16(0);
+ } else {
+ unsigned int filenamesSize = pFileInfo->getFilenamesSize() + numFiles;
+
+ m_pOS->writeU16(filenamesSize);
+ m_pOS->writeU16(filenamesSize);
+
+ char *pFilenames = new char [filenamesSize];
+ unsigned int pos = 0;
+
+ for (unsigned int i = 0; i < numFiles; i++) {
+ char *pName = pFileInfo->getNameAt(i);
+ unsigned int len = strlen(pName);
+
+ memcpy((void *)&pFilenames[pos], pName, len + 1);
+ pos += (len + 1);
+
+ if (pFileInfo->getFlagsAt(i) & FT_ATTR_DIR) {
+ m_pOS->writeU32(FT_NET_ATTR_DIR);
+ } else {
+ m_pOS->writeU32(pFileInfo->getSizeAt(i));
+ }
+ m_pOS->writeU32(pFileInfo->getDataAt(i));
+ }
+
+ m_pOS->writeBytes(pFilenames, filenamesSize);
+
+ delete [] pFilenames;
+ }
+
+ m_pOS->flush();
+
+ return true;
+}
+
+bool
+SFTMsgWriter::writeFileDownloadData(unsigned int dataSize, void *pData)
+{
+ m_pOS->writeU8(msgTypeFileDownloadData);
+ m_pOS->writeU8(0);
+ m_pOS->writeU16(dataSize);
+ m_pOS->writeU16(dataSize);
+ m_pOS->writeBytes(pData, dataSize);
+ m_pOS->flush();
+ return true;
+}
+
+bool
+SFTMsgWriter::writeFileDownloadData(unsigned int modTime)
+{
+ m_pOS->writeU8(msgTypeFileDownloadData);
+ m_pOS->writeU8(0);
+ m_pOS->writeU16(0);
+ m_pOS->writeU16(0);
+ m_pOS->writeU32(modTime);
+ m_pOS->flush();
+ return true;
+}
+
+bool
+SFTMsgWriter::writeFileUploadCancel(unsigned int reasonLen, char *pReason)
+{
+ m_pOS->writeU8(msgTypeFileUploadCancel);
+ return writeU8U16StringMsg(0, reasonLen, pReason);
+}
+
+bool
+SFTMsgWriter::writeFileDownloadFailed(unsigned int reasonLen, char *pReason)
+{
+ m_pOS->writeU8(msgTypeFileDownloadFailed);
+ return writeU8U16StringMsg(0, reasonLen, pReason);
+}
+
+bool
+SFTMsgWriter::writeFileDirSizeData(unsigned int dirSizeLow,
+ unsigned short dirSizeHigh)
+{
+ m_pOS->writeU8(msgTypeFileDirSizeData);
+ m_pOS->writeU8(0);
+ m_pOS->writeU16(dirSizeHigh);
+ m_pOS->writeU32(dirSizeLow);
+ m_pOS->flush();
+ return true;
+}
+
+bool
+SFTMsgWriter::writeFileLastRqstFailed(unsigned char lastRequest,
+ unsigned short reasonLen,
+ char *pReason)
+{
+ m_pOS->writeU8(msgTypeFileLastRequestFailed);
+ return writeU8U16StringMsg(lastRequest, reasonLen, pReason);
+}
+
+bool
+SFTMsgWriter::writeU8U16StringMsg(unsigned char p1, unsigned short p2, char *pP3)
+{
+ m_pOS->writeU8(p1);
+ m_pOS->writeU16(p2);
+ m_pOS->writeBytes(pP3, p2);
+ m_pOS->flush();
+ return true;
+}
diff --git a/common/rfb/SFTMsgWriter.h b/common/rfb/SFTMsgWriter.h
new file mode 100644
index 00000000..f6bea9f3
--- /dev/null
+++ b/common/rfb/SFTMsgWriter.h
@@ -0,0 +1,56 @@
+/* Copyright (C) 2005 TightVNC Team. All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- SFTMsgWriter.h
+
+#ifndef __RFB_SFTMSGWRITER_H__
+#define __RFB_SFTMSGWRITER_H__
+
+#include <rdr/OutStream.h>
+#include <rfb/FileInfo.h>
+#include <rfb/msgTypes.h>
+
+namespace rfb {
+ class SFTMsgWriter
+ {
+ public:
+ SFTMsgWriter(rdr::OutStream *pOS);
+ ~SFTMsgWriter();
+
+ bool writeFileListData(unsigned char flags, rfb::FileInfo *pFileInfo);
+ bool writeFileDownloadData(unsigned int dataSize, void *pData);
+ bool writeFileDownloadData(unsigned int modTime);
+ bool writeFileUploadCancel(unsigned int reasonLen, char *pReason);
+ bool writeFileDownloadFailed(unsigned int reasonLen, char *pReason);
+ bool writeFileDirSizeData(unsigned int dirSizeLow, unsigned short dirSizeHigh);
+ bool writeFileLastRqstFailed(unsigned char lastRequest, unsigned short reasonLen,
+ char *pReason);
+
+ private:
+ rdr::OutStream *m_pOS;
+
+ bool writeU8U16StringMsg(unsigned char p1, unsigned short p2, char *pP3);
+ };
+}
+
+#endif // __RFB_SFTMSGWRITER_H__
diff --git a/common/rfb/SFileTransfer.cxx b/common/rfb/SFileTransfer.cxx
new file mode 100644
index 00000000..957e50b2
--- /dev/null
+++ b/common/rfb/SFileTransfer.cxx
@@ -0,0 +1,335 @@
+/* Copyright (C) 2006 TightVNC Team. All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- SFileTransfer.cxx
+
+#include <rfb/msgTypes.h>
+#include <rfb/SFileTransfer.h>
+
+using namespace rfb;
+
+SFileTransfer::SFileTransfer(network::Socket *sock) :
+ m_bUploadStarted(false), m_bDownloadStarted(false),
+ m_reader(&sock->inStream()), m_writer(&sock->outStream()), m_pSocket(sock)
+{
+}
+
+SFileTransfer::~SFileTransfer()
+{
+}
+
+bool
+SFileTransfer::processMessages(int type)
+{
+ switch(type)
+ {
+ case msgTypeFileListRequest:
+ return processFileListRequest();
+ case msgTypeFileDownloadRequest:
+ return processFileDownloadRequest();
+ case msgTypeFileUploadRequest:
+ return processFileUploadRequest();
+ case msgTypeFileUploadData:
+ return processFileUploadData();
+ case msgTypeFileDownloadCancel:
+ return processFileDownloadCancel();
+ case msgTypeFileUploadFailed:
+ return processFileUploadFailed();
+ case msgTypeFileCreateDirRequest:
+ return processFileCreateDirRequest();
+ case msgTypeFileDirSizeRequest:
+ return processFileDirSizeRequest();
+ case msgTypeFileRenameRequest:
+ return processFileRenameRequest();
+ case msgTypeFileDeleteRequest:
+ return processFileDeleteRequest();
+ default:
+ return false;
+ }
+}
+
+bool
+SFileTransfer::processFileListRequest()
+{
+ char szDirName[FT_FILENAME_SIZE] = {0};
+ unsigned int dirNameSize = FT_FILENAME_SIZE;
+ unsigned int flags = 0;
+
+ if (!m_reader.readFileListRqst(&dirNameSize, szDirName, &flags)) return false;
+
+ if (!convertPathFromNet(szDirName)) return false;
+
+ bool bDirOnly = false;
+ if (flags & 0x10) bDirOnly = true;
+
+ FileInfo fi;
+ if (!makeFileList(szDirName, &fi, bDirOnly)) {
+ flags = (flags | 0x80);
+ }
+ return m_writer.writeFileListData((unsigned char)flags, &fi);
+}
+
+bool
+SFileTransfer::processFileDownloadRequest()
+{
+ char szName[FT_FILENAME_SIZE] = {0};
+ unsigned int nameSize = FT_FILENAME_SIZE;
+ unsigned int position = 0;
+
+ if (!m_reader.readFileDownloadRqst(&nameSize, szName, &position)) return false;
+
+ if (!convertPathFromNet(szName)) return false;
+
+ if (m_bDownloadStarted) {
+ char reason[] = "The download is already started";
+ m_writer.writeFileLastRqstFailed(msgTypeFileDownloadRequest, strlen(reason), reason);
+ return false;
+ }
+
+ if (!m_fileReader.create(szName)) return false;
+
+ m_bDownloadStarted = true;
+
+ sendFileDownloadPortion();
+
+ return true;
+}
+
+bool
+SFileTransfer::sendFileDownloadPortion()
+{
+ char buffer[FT_MAX_SENDING_SIZE];
+ unsigned int bytesRead = 0;
+
+ if (m_fileReader.read((void *)buffer, FT_MAX_SENDING_SIZE, &bytesRead)) {
+ if (bytesRead == 0) {
+ m_writer.writeFileDownloadData(m_fileReader.getTime());
+ m_fileReader.close();
+ m_bDownloadStarted = false;
+ return true;
+ } else {
+ m_writer.writeFileDownloadData(bytesRead, buffer);
+ return initDownloadCallback();
+ }
+ } else {
+ char reason[] = "Error while reading from file";
+ m_writer.writeFileDownloadFailed(strlen(reason), reason);
+ m_fileReader.close();
+ m_bDownloadStarted = false;
+ return true;
+ }
+}
+
+bool
+SFileTransfer::processFileUploadRequest()
+{
+ char szName[FT_FILENAME_SIZE] = {0};
+ unsigned int nameSize = FT_FILENAME_SIZE;
+ unsigned int position = 0;
+
+ if (!m_reader.readFileUploadRqst(&nameSize, szName, &position)) return false;
+
+ if (!convertPathFromNet(szName)) return false;
+
+ if (m_bUploadStarted) {
+ char reason[] = "The upload is already started";
+ m_writer.writeFileLastRqstFailed(msgTypeFileUploadRequest, strlen(reason), reason);
+ return false;
+ }
+
+ if (!m_fileWriter.create(szName)) {
+ char reason[] = "Can't create local file";
+ m_writer.writeFileLastRqstFailed(msgTypeFileUploadRequest, strlen(reason), reason);
+ return true;
+ }
+
+ m_bUploadStarted = true;
+
+ return true;
+}
+
+bool
+SFileTransfer::processFileUploadData()
+{
+ unsigned int dataSize = 0;
+ unsigned int modTime = 0;
+
+ char *pUploadData = m_reader.readFileUploadData(&dataSize, &modTime);
+
+ if (!m_bUploadStarted) {
+ char reason[] = "Upload is impossible";
+ m_writer.writeFileUploadCancel(strlen(reason), reason);
+ } else {
+ if (pUploadData == NULL) {
+ if (modTime == 0) {
+ char reason[] = "Upload failed";
+ m_writer.writeFileUploadCancel(strlen(reason), reason);
+ } else {
+ m_fileWriter.setTime(modTime);
+ }
+ m_fileWriter.close();
+ m_bUploadStarted = false;
+ } else {
+ unsigned int dataWritten = 0;
+ m_fileWriter.write(pUploadData, dataSize, &dataWritten);
+ if (dataWritten != dataSize) {
+ char reason[] = "Upload failed";
+ m_writer.writeFileUploadCancel(strlen(reason), reason);
+ m_fileWriter.close();
+ m_bUploadStarted = false;
+ }
+ }
+ }
+ delete [] pUploadData;
+ return true;
+}
+
+bool
+SFileTransfer::processFileDownloadCancel()
+{
+ char szReason[FT_FILENAME_SIZE] = {0};
+ unsigned int reasonSize = FT_FILENAME_SIZE;
+
+ if (!m_reader.readFileDownloadCancel(&reasonSize, szReason)) return false;
+
+ m_fileReader.close();
+ m_bDownloadStarted = false;
+ return true;
+}
+
+bool
+SFileTransfer::processFileUploadFailed()
+{
+ char szReason[FT_FILENAME_SIZE] = {0};
+ unsigned int reasonSize = FT_FILENAME_SIZE;
+
+ if (!m_reader.readFileUploadFailed(&reasonSize, szReason)) return false;
+
+ deleteIt(m_fileWriter.getFilename());
+ m_fileWriter.close();
+ m_bUploadStarted = false;
+ return true;
+}
+
+bool
+SFileTransfer::processFileCreateDirRequest()
+{
+ char szName[FT_FILENAME_SIZE] = {0};
+ unsigned int nameSize = FT_FILENAME_SIZE;
+
+ if (!m_reader.readFileCreateDirRqst(&nameSize, szName)) return false;
+
+ if (!convertPathFromNet(szName)) return false;
+
+ return createDir(szName);
+}
+
+bool
+SFileTransfer::processFileDirSizeRequest()
+{
+ char szName[FT_FILENAME_SIZE] = {0};
+ unsigned int nameSize = FT_FILENAME_SIZE;
+
+ if (!m_reader.readFileDirSizeRqst(&nameSize, szName)) return false;
+
+ if (!convertPathFromNet(szName)) return false;
+
+ unsigned short highSize16 = 0;
+ unsigned int lowSize32 = 0;
+
+ if (!getDirSize(szName, &highSize16, &lowSize32)) return false;
+
+ return m_writer.writeFileDirSizeData(lowSize32, highSize16);
+}
+
+bool
+SFileTransfer::processFileRenameRequest()
+{
+ char szOldName[FT_FILENAME_SIZE] = {0};
+ char szNewName[FT_FILENAME_SIZE] = {0};
+
+ unsigned int oldNameSize = FT_FILENAME_SIZE;
+ unsigned int newNameSize = FT_FILENAME_SIZE;
+
+ if (!m_reader.readFileRenameRqst(&oldNameSize, &newNameSize, szOldName, szNewName)) return false;
+
+ if ((!convertPathFromNet(szOldName)) || (!convertPathFromNet(szNewName))) return false;
+
+ return renameIt(szOldName, szNewName);
+}
+
+bool
+SFileTransfer::processFileDeleteRequest()
+{
+ char szName[FT_FILENAME_SIZE] = {0};
+ unsigned int nameSize = FT_FILENAME_SIZE;
+
+ if (!m_reader.readFileDeleteRqst(&nameSize, szName)) return false;
+
+ if (!convertPathFromNet(szName)) return false;
+
+ return deleteIt(szName);
+}
+
+bool
+SFileTransfer::convertPathFromNet(char *pszPath)
+{
+ return true;
+}
+
+bool
+SFileTransfer::makeFileList(char *pszPath, FileInfo *pFI, bool bDirOnly)
+{
+ return false;
+}
+
+bool
+SFileTransfer::deleteIt(char *pszPath)
+{
+ return false;
+}
+
+bool
+SFileTransfer::renameIt(char *pszOldPath, char *pszNewPath)
+{
+ return false;
+}
+
+bool
+SFileTransfer::createDir(char *pszPath)
+{
+ return false;
+}
+
+bool
+SFileTransfer::getDirSize(char *pszName, unsigned short *pHighSize16,
+ unsigned int *pLowSize32)
+{
+ return false;
+}
+
+bool
+SFileTransfer::initDownloadCallback()
+{
+ return false;
+}
diff --git a/common/rfb/SFileTransfer.h b/common/rfb/SFileTransfer.h
new file mode 100644
index 00000000..51a49282
--- /dev/null
+++ b/common/rfb/SFileTransfer.h
@@ -0,0 +1,83 @@
+/* Copyright (C) 2006 TightVNC Team. All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- SFileTransfer.h
+
+#ifndef __RFB_SFILETRANSFER_H__
+#define __RFB_SFILETRANSFER_H__
+
+#include <network/Socket.h>
+#include <rfb/SFTMsgReader.h>
+#include <rfb/SFTMsgWriter.h>
+#include <rfb/FileWriter.h>
+#include <rfb/FileReader.h>
+#include <rfb/FileInfo.h>
+#include <rfb/fttypes.h>
+
+namespace rfb {
+ class SFileTransfer
+ {
+ public:
+ SFileTransfer(network::Socket *sock);
+ virtual ~SFileTransfer();
+
+ bool processMessages(int type);
+ bool sendFileDownloadPortion();
+
+ protected:
+ bool processFileListRequest();
+ bool processFileDownloadRequest();
+ bool processFileUploadRequest();
+ bool processFileUploadData();
+ bool processFileDownloadCancel();
+ bool processFileUploadFailed();
+ bool processFileCreateDirRequest();
+ bool processFileDirSizeRequest();
+ bool processFileRenameRequest();
+ bool processFileDeleteRequest();
+
+ virtual bool initDownloadCallback();
+ virtual bool makeFileList(char *pszPath, FileInfo *pFI, bool bDirOnly);
+ virtual bool convertPathFromNet(char *pszPath);
+
+ virtual bool deleteIt(char *pszPath);
+ virtual bool renameIt(char *pszOldPath, char *pszNewPath);
+ virtual bool createDir(char *pszPath);
+
+ virtual bool getDirSize(char *pszName, unsigned short *pHighSize16, unsigned int *pLowSize32);
+
+ bool m_bUploadStarted;
+ bool m_bDownloadStarted;
+
+ private:
+ SFTMsgReader m_reader;
+ SFTMsgWriter m_writer;
+
+ FileWriter m_fileWriter;
+ FileReader m_fileReader;
+
+ network::Socket *m_pSocket;
+ };
+}
+
+#endif // __RFB_SFILETRANSFER_H__
diff --git a/common/rfb/SFileTransferManager.cxx b/common/rfb/SFileTransferManager.cxx
new file mode 100644
index 00000000..999a079b
--- /dev/null
+++ b/common/rfb/SFileTransferManager.cxx
@@ -0,0 +1,55 @@
+/* Copyright (C) 2006 TightVNC Team. All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- SFileTransferManager.cxx
+
+#include <rfb/SFileTransferManager.h>
+
+using namespace rfb;
+
+SFileTransferManager::SFileTransferManager()
+{
+
+}
+
+SFileTransferManager::~SFileTransferManager()
+{
+ destroy();
+}
+
+void
+SFileTransferManager::destroyObject(SFileTransfer *pFT)
+{
+ if (pFT == NULL) return;
+
+ m_lstFTObjects.remove(pFT);
+
+ delete pFT;
+}
+
+void
+SFileTransferManager::destroy()
+{
+ while(!m_lstFTObjects.empty())
+ delete m_lstFTObjects.front();
+}
diff --git a/common/rfb/SFileTransferManager.h b/common/rfb/SFileTransferManager.h
new file mode 100644
index 00000000..fe816444
--- /dev/null
+++ b/common/rfb/SFileTransferManager.h
@@ -0,0 +1,51 @@
+/* Copyright (C) 2006 TightVNC Team. All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- SFileTransferManager.h
+
+#ifndef __RFB_SFILETRANSFERMANAGER_H__
+#define __RFB_SFILETRANSFERMANAGER_H__
+
+#include <list>
+
+#include <rfb/SFileTransfer.h>
+#include <network/Socket.h>
+
+namespace rfb {
+ class SFileTransferManager
+ {
+ public:
+ SFileTransferManager();
+ virtual ~SFileTransferManager();
+
+ virtual SFileTransfer *createObject(network::Socket *sock) = 0;
+ void destroyObject(SFileTransfer *pFT);
+
+ protected:
+ std::list<SFileTransfer*> m_lstFTObjects;
+
+ void destroy();
+ };
+}
+
+#endif // __RFB_SFILETRANSFERMANAGER_H__
diff --git a/common/rfb/SMsgHandler.cxx b/common/rfb/SMsgHandler.cxx
new file mode 100644
index 00000000..ccc97ad0
--- /dev/null
+++ b/common/rfb/SMsgHandler.cxx
@@ -0,0 +1,52 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#include <rfb/Exception.h>
+#include <rfb/SMsgHandler.h>
+
+using namespace rfb;
+
+SMsgHandler::SMsgHandler()
+{
+}
+
+SMsgHandler::~SMsgHandler()
+{
+}
+
+void SMsgHandler::clientInit(bool shared)
+{
+}
+
+void SMsgHandler::setPixelFormat(const PixelFormat& pf)
+{
+ cp.setPF(pf);
+}
+
+void SMsgHandler::setEncodings(int nEncodings, rdr::U32* encodings)
+{
+ cp.setEncodings(nEncodings, encodings);
+ supportsLocalCursor();
+}
+
+void SMsgHandler::framebufferUpdateRequest(const Rect& r, bool incremental)
+{
+}
+
+void SMsgHandler::supportsLocalCursor()
+{
+}
diff --git a/common/rfb/SMsgHandler.h b/common/rfb/SMsgHandler.h
new file mode 100644
index 00000000..cf3377d5
--- /dev/null
+++ b/common/rfb/SMsgHandler.h
@@ -0,0 +1,64 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+//
+// SMsgHandler - class to handle incoming messages on the server side.
+//
+
+#ifndef __RFB_SMSGHANDLER_H__
+#define __RFB_SMSGHANDLER_H__
+
+#include <rdr/types.h>
+#include <rfb/PixelFormat.h>
+#include <rfb/ConnParams.h>
+#include <rfb/InputHandler.h>
+
+namespace rdr { class InStream; }
+
+namespace rfb {
+
+ class SMsgHandler : public InputHandler {
+ public:
+ SMsgHandler();
+ virtual ~SMsgHandler();
+
+ // The following methods are called as corresponding messages are read. A
+ // derived class should override these methods as desired. Note that for
+ // the setPixelFormat() and setEncodings() methods, a derived class must
+ // call on to SMsgHandler's methods.
+
+ virtual void clientInit(bool shared);
+
+ virtual void setPixelFormat(const PixelFormat& pf);
+ virtual void setEncodings(int nEncodings, rdr::U32* encodings);
+ virtual void framebufferUpdateRequest(const Rect& r, bool incremental);
+
+ // InputHandler interface
+ // The InputHandler methods will be called for the corresponding messages.
+
+ // supportsLocalCursor() is called whenever the status of
+ // cp.supportsLocalCursor has changed. At the moment this happens on a
+ // setEncodings message, but in the future this may be due to a message
+ // specially for this purpose.
+ virtual void supportsLocalCursor();
+
+ virtual bool processFTMsg(int type) = 0;
+
+ ConnParams cp;
+ };
+}
+#endif
diff --git a/common/rfb/SMsgReader.cxx b/common/rfb/SMsgReader.cxx
new file mode 100644
index 00000000..f89e0f4f
--- /dev/null
+++ b/common/rfb/SMsgReader.cxx
@@ -0,0 +1,97 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#include <stdio.h>
+#include <rdr/InStream.h>
+#include <rfb/Exception.h>
+#include <rfb/util.h>
+#include <rfb/SMsgHandler.h>
+#include <rfb/SMsgReader.h>
+#include <rfb/Configuration.h>
+
+using namespace rfb;
+
+static IntParameter maxCutText("MaxCutText", "Maximum permitted length of an incoming clipboard update", 256*1024);
+
+SMsgReader::SMsgReader(SMsgHandler* handler_, rdr::InStream* is_)
+ : handler(handler_), is(is_)
+{
+}
+
+SMsgReader::~SMsgReader()
+{
+}
+
+void SMsgReader::readSetPixelFormat()
+{
+ is->skip(3);
+ PixelFormat pf;
+ pf.read(is);
+ handler->setPixelFormat(pf);
+}
+
+void SMsgReader::readSetEncodings()
+{
+ is->skip(1);
+ int nEncodings = is->readU16();
+ rdr::U32Array encodings(nEncodings);
+ for (int i = 0; i < nEncodings; i++)
+ encodings.buf[i] = is->readU32();
+ handler->setEncodings(nEncodings, encodings.buf);
+}
+
+void SMsgReader::readFramebufferUpdateRequest()
+{
+ bool inc = is->readU8();
+ int x = is->readU16();
+ int y = is->readU16();
+ int w = is->readU16();
+ int h = is->readU16();
+ handler->framebufferUpdateRequest(Rect(x, y, x+w, y+h), inc);
+}
+
+void SMsgReader::readKeyEvent()
+{
+ bool down = is->readU8();
+ is->skip(2);
+ rdr::U32 key = is->readU32();
+ handler->keyEvent(key, down);
+}
+
+void SMsgReader::readPointerEvent()
+{
+ int mask = is->readU8();
+ int x = is->readU16();
+ int y = is->readU16();
+ handler->pointerEvent(Point(x, y), mask);
+}
+
+
+void SMsgReader::readClientCutText()
+{
+ is->skip(3);
+ int len = is->readU32();
+ if (len > maxCutText) {
+ is->skip(len);
+ fprintf(stderr,"cut text too long (%d bytes) - ignoring\n",len);
+ return;
+ }
+ CharArray ca(len+1);
+ ca.buf[len] = 0;
+ is->readBytes(ca.buf, len);
+ handler->clientCutText(ca.buf, len);
+}
diff --git a/common/rfb/SMsgReader.h b/common/rfb/SMsgReader.h
new file mode 100644
index 00000000..e6e40448
--- /dev/null
+++ b/common/rfb/SMsgReader.h
@@ -0,0 +1,56 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+//
+// SMsgReader - class for reading RFB messages on the server side
+// (i.e. messages from client to server).
+//
+
+#ifndef __RFB_SMSGREADER_H__
+#define __RFB_SMSGREADER_H__
+
+namespace rdr { class InStream; }
+
+namespace rfb {
+ class SMsgHandler;
+
+ class SMsgReader {
+ public:
+ virtual ~SMsgReader();
+
+ virtual void readClientInit()=0;
+
+ // readMsg() reads a message, calling the handler as appropriate.
+ virtual void readMsg()=0;
+
+ rdr::InStream* getInStream() { return is; }
+
+ protected:
+ virtual void readSetPixelFormat();
+ virtual void readSetEncodings();
+ virtual void readFramebufferUpdateRequest();
+ virtual void readKeyEvent();
+ virtual void readPointerEvent();
+ virtual void readClientCutText();
+
+ SMsgReader(SMsgHandler* handler, rdr::InStream* is);
+
+ SMsgHandler* handler;
+ rdr::InStream* is;
+ };
+}
+#endif
diff --git a/common/rfb/SMsgReaderV3.cxx b/common/rfb/SMsgReaderV3.cxx
new file mode 100644
index 00000000..be01b5db
--- /dev/null
+++ b/common/rfb/SMsgReaderV3.cxx
@@ -0,0 +1,68 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#include <rfb/PixelFormat.h>
+#include <rfb/msgTypes.h>
+#include <rfb/Exception.h>
+#include <rdr/InStream.h>
+#include <rfb/SMsgReaderV3.h>
+#include <rfb/SMsgHandler.h>
+
+using namespace rfb;
+
+SMsgReaderV3::SMsgReaderV3(SMsgHandler* handler, rdr::InStream* is)
+ : SMsgReader(handler, is)
+{
+}
+
+SMsgReaderV3::~SMsgReaderV3()
+{
+}
+
+void SMsgReaderV3::readClientInit()
+{
+ bool shared = is->readU8();
+ handler->clientInit(shared);
+}
+
+void SMsgReaderV3::readMsg()
+{
+ int msgType = is->readU8();
+ switch (msgType) {
+ case msgTypeSetPixelFormat: readSetPixelFormat(); break;
+ case msgTypeSetEncodings: readSetEncodings(); break;
+ case msgTypeFramebufferUpdateRequest: readFramebufferUpdateRequest(); break;
+ case msgTypeKeyEvent: readKeyEvent(); break;
+ case msgTypePointerEvent: readPointerEvent(); break;
+ case msgTypeClientCutText: readClientCutText(); break;
+
+ case msgTypeFileListRequest:
+ case msgTypeFileDownloadRequest:
+ case msgTypeFileUploadRequest:
+ case msgTypeFileUploadData:
+ case msgTypeFileDownloadCancel:
+ case msgTypeFileUploadFailed:
+ case msgTypeFileCreateDirRequest:
+ case msgTypeFileDirSizeRequest:
+ case msgTypeFileRenameRequest:
+ case msgTypeFileDeleteRequest: handler->processFTMsg(msgType); break;
+
+ default:
+ fprintf(stderr, "unknown message type %d\n", msgType);
+ throw Exception("unknown message type");
+ }
+}
diff --git a/common/rfb/SMsgReaderV3.h b/common/rfb/SMsgReaderV3.h
new file mode 100644
index 00000000..c6b7bf42
--- /dev/null
+++ b/common/rfb/SMsgReaderV3.h
@@ -0,0 +1,32 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#ifndef __RFB_SMSGREADERV3_H__
+#define __RFB_SMSGREADERV3_H__
+
+#include <rfb/SMsgReader.h>
+
+namespace rfb {
+ class SMsgReaderV3 : public SMsgReader {
+ public:
+ SMsgReaderV3(SMsgHandler* handler, rdr::InStream* is);
+ virtual ~SMsgReaderV3();
+ virtual void readClientInit();
+ virtual void readMsg();
+ };
+}
+#endif
diff --git a/common/rfb/SMsgWriter.cxx b/common/rfb/SMsgWriter.cxx
new file mode 100644
index 00000000..085dfc16
--- /dev/null
+++ b/common/rfb/SMsgWriter.cxx
@@ -0,0 +1,202 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#include <stdio.h>
+#include <assert.h>
+#include <rdr/OutStream.h>
+#include <rfb/msgTypes.h>
+#include <rfb/ColourMap.h>
+#include <rfb/ConnParams.h>
+#include <rfb/UpdateTracker.h>
+#include <rfb/SMsgWriter.h>
+#include <rfb/LogWriter.h>
+
+using namespace rfb;
+
+static LogWriter vlog("SMsgWriter");
+
+SMsgWriter::SMsgWriter(ConnParams* cp_, rdr::OutStream* os_)
+ : imageBufIdealSize(0), cp(cp_), os(os_), lenBeforeRect(0),
+ currentEncoding(0), updatesSent(0), rawBytesEquivalent(0),
+ imageBuf(0), imageBufSize(0)
+{
+ for (unsigned int i = 0; i <= encodingMax; i++) {
+ encoders[i] = 0;
+ bytesSent[i] = 0;
+ rectsSent[i] = 0;
+ }
+}
+
+SMsgWriter::~SMsgWriter()
+{
+ vlog.info("framebuffer updates %d",updatesSent);
+ int bytes = 0;
+ for (unsigned int i = 0; i <= encodingMax; i++) {
+ delete encoders[i];
+ if (i != encodingCopyRect)
+ bytes += bytesSent[i];
+ if (rectsSent[i])
+ vlog.info(" %s rects %d, bytes %d",
+ encodingName(i), rectsSent[i], bytesSent[i]);
+ }
+ vlog.info(" raw bytes equivalent %d, compression ratio %f",
+ rawBytesEquivalent, (double)rawBytesEquivalent / bytes);
+ delete [] imageBuf;
+}
+
+void SMsgWriter::writeSetColourMapEntries(int firstColour, int nColours,
+ ColourMap* cm)
+{
+ startMsg(msgTypeSetColourMapEntries);
+ os->pad(1);
+ os->writeU16(firstColour);
+ os->writeU16(nColours);
+ for (int i = firstColour; i < firstColour+nColours; i++) {
+ int r, g, b;
+ cm->lookup(i, &r, &g, &b);
+ os->writeU16(r);
+ os->writeU16(g);
+ os->writeU16(b);
+ }
+ endMsg();
+}
+
+void SMsgWriter::writeBell()
+{
+ startMsg(msgTypeBell);
+ endMsg();
+}
+
+void SMsgWriter::writeServerCutText(const char* str, int len)
+{
+ startMsg(msgTypeServerCutText);
+ os->pad(3);
+ os->writeU32(len);
+ os->writeBytes(str, len);
+ endMsg();
+}
+
+void SMsgWriter::setupCurrentEncoder()
+{
+ unsigned int encoding = cp->currentEncoding();
+
+ // FIXME: Code duplication, see writeRect().
+ if (!encoders[encoding]) {
+ encoders[encoding] = Encoder::createEncoder(encoding, this);
+ assert(encoders[encoding]);
+ }
+
+ encoders[encoding]->setCompressLevel(cp->compressLevel);
+ encoders[encoding]->setQualityLevel(cp->qualityLevel);
+}
+
+int SMsgWriter::getNumRects(const Rect &r)
+{
+ unsigned int encoding = cp->currentEncoding();
+
+ if (!encoders[encoding])
+ setupCurrentEncoder();
+
+ return encoders[encoding]->getNumRects(r);
+}
+
+// FIXME: This functions does not compute the number of rectangles correctly
+// if the Tight encoder is used (but currently that does not matter
+// because this function is never used).
+void SMsgWriter::writeFramebufferUpdate(const UpdateInfo& ui, ImageGetter* ig,
+ Region* updatedRegion)
+{
+ writeFramebufferUpdateStart(ui.numRects());
+ writeRects(ui, ig, updatedRegion);
+ writeFramebufferUpdateEnd();
+}
+
+void SMsgWriter::writeRects(const UpdateInfo& ui, ImageGetter* ig,
+ Region* updatedRegion)
+{
+ std::vector<Rect> rects;
+ std::vector<Rect>::const_iterator i;
+ updatedRegion->copyFrom(ui.changed);
+ updatedRegion->assign_union(ui.copied);
+
+ ui.copied.get_rects(&rects, ui.copy_delta.x <= 0, ui.copy_delta.y <= 0);
+ for (i = rects.begin(); i != rects.end(); i++)
+ writeCopyRect(*i, i->tl.x - ui.copy_delta.x, i->tl.y - ui.copy_delta.y);
+
+ ui.changed.get_rects(&rects);
+ for (i = rects.begin(); i != rects.end(); i++) {
+ Rect actual;
+ if (!writeRect(*i, ig, &actual)) {
+ updatedRegion->assign_subtract(*i);
+ updatedRegion->assign_union(actual);
+ }
+ }
+}
+
+
+bool SMsgWriter::needFakeUpdate()
+{
+ return false;
+}
+
+bool SMsgWriter::writeRect(const Rect& r, ImageGetter* ig, Rect* actual)
+{
+ return writeRect(r, cp->currentEncoding(), ig, actual);
+}
+
+bool SMsgWriter::writeRect(const Rect& r, unsigned int encoding,
+ ImageGetter* ig, Rect* actual)
+{
+ if (!encoders[encoding]) {
+ encoders[encoding] = Encoder::createEncoder(encoding, this);
+ assert(encoders[encoding]);
+ }
+ return encoders[encoding]->writeRect(r, ig, actual);
+}
+
+void SMsgWriter::writeCopyRect(const Rect& r, int srcX, int srcY)
+{
+ startRect(r,encodingCopyRect);
+ os->writeU16(srcX);
+ os->writeU16(srcY);
+ endRect();
+}
+
+rdr::U8* SMsgWriter::getImageBuf(int required, int requested, int* nPixels)
+{
+ int requiredBytes = required * (cp->pf().bpp / 8);
+ int requestedBytes = requested * (cp->pf().bpp / 8);
+ int size = requestedBytes;
+ if (size > imageBufIdealSize) size = imageBufIdealSize;
+
+ if (size < requiredBytes)
+ size = requiredBytes;
+
+ if (imageBufSize < size) {
+ imageBufSize = size;
+ delete [] imageBuf;
+ imageBuf = new rdr::U8[imageBufSize];
+ }
+ if (nPixels)
+ *nPixels = imageBufSize / (cp->pf().bpp / 8);
+ return imageBuf;
+}
+
+int SMsgWriter::bpp()
+{
+ return cp->pf().bpp;
+}
diff --git a/common/rfb/SMsgWriter.h b/common/rfb/SMsgWriter.h
new file mode 100644
index 00000000..ed8ad0ef
--- /dev/null
+++ b/common/rfb/SMsgWriter.h
@@ -0,0 +1,163 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+//
+// SMsgWriter - class for writing RFB messages on the server side.
+//
+
+#ifndef __RFB_SMSGWRITER_H__
+#define __RFB_SMSGWRITER_H__
+
+#include <rdr/types.h>
+#include <rfb/encodings.h>
+#include <rfb/Encoder.h>
+
+namespace rdr { class OutStream; }
+
+namespace rfb {
+
+ class PixelFormat;
+ class ConnParams;
+ class ImageGetter;
+ class ColourMap;
+ class Region;
+ class UpdateInfo;
+
+ class WriteSetCursorCallback {
+ public:
+ virtual void writeSetCursorCallback() = 0;
+ };
+
+ class SMsgWriter {
+ public:
+ virtual ~SMsgWriter();
+
+ // writeServerInit() must only be called at the appropriate time in the
+ // protocol initialisation.
+ virtual void writeServerInit()=0;
+
+ // Methods to write normal protocol messages
+
+ // writeSetColourMapEntries() writes a setColourMapEntries message, using
+ // the given ColourMap object to lookup the RGB values of the given range
+ // of colours.
+ virtual void writeSetColourMapEntries(int firstColour, int nColours,
+ ColourMap* cm);
+
+ // writeBell() and writeServerCutText() do the obvious thing.
+ virtual void writeBell();
+ virtual void writeServerCutText(const char* str, int len);
+
+ // setupCurrentEncoder() should be called before each framebuffer update,
+ // prior to calling getNumRects() or writeFramebufferUpdateStart().
+ void setupCurrentEncoder();
+
+ // getNumRects() computes the number of sub-rectangles that will compose a
+ // given rectangle, for current encoder.
+ int getNumRects(const Rect &r);
+
+ // writeSetDesktopSize() on a V3 writer won't actually write immediately,
+ // but will write the relevant pseudo-rectangle as part of the next update.
+ virtual bool writeSetDesktopSize()=0;
+
+ // Like setDesktopSize, we can't just write out a setCursor message
+ // immediately on a V3 writer. Instead of calling writeSetCursor()
+ // directly, you must call cursorChange(), and then invoke writeSetCursor()
+ // in response to the writeSetCursorCallback() callback. For a V3 writer
+ // this will happen when the next update is sent.
+ virtual void cursorChange(WriteSetCursorCallback* cb)=0;
+ virtual void writeSetCursor(int width, int height, const Point& hotspot,
+ void* data, void* mask)=0;
+ virtual void writeSetXCursor(int width, int height, int hotspotX,
+ int hotspotY, void* data, void* mask)=0;
+
+ // needFakeUpdate() returns true when an immediate update is needed in
+ // order to flush out setDesktopSize or setCursor pseudo-rectangles to the
+ // client.
+ virtual bool needFakeUpdate();
+
+ // writeFramebufferUpdate() writes a framebuffer update using the given
+ // UpdateInfo and ImageGetter. On a V3 writer this may have
+ // pseudo-rectangles for setDesktopSize and setCursor added to it, and so
+ // may invoke writeSetCursorCallback().
+ virtual void writeFramebufferUpdate(const UpdateInfo& ui, ImageGetter* ig,
+ Region* updatedRegion);
+
+ // writeRects() accepts an UpdateInfo (changed & copied regions) and an
+ // ImageGetter to fetch pixels from. It then calls writeCopyRect() and
+ // writeRect() as appropriate. writeFramebufferUpdateStart() must be used
+ // before the first writeRects() call and writeFrameBufferUpdateEnd() after
+ // the last one. It returns the actual region sent to the client, which
+ // may be smaller than the update passed in.
+ virtual void writeRects(const UpdateInfo& update, ImageGetter* ig,
+ Region* updatedRegion);
+
+ // To construct a framebuffer update you can call
+ // writeFramebufferUpdateStart(), followed by a number of writeCopyRect()s
+ // and writeRect()s, finishing with writeFramebufferUpdateEnd(). If you
+ // know the exact number of rectangles ahead of time you can specify it to
+ // writeFramebufferUpdateStart() which can be more efficient.
+ virtual void writeFramebufferUpdateStart(int nRects)=0;
+ virtual void writeFramebufferUpdateStart()=0;
+ virtual void writeFramebufferUpdateEnd()=0;
+
+ // writeRect() tries to write the given rectangle. If it is unable to
+ // write the whole rectangle it returns false and sets actual to the actual
+ // rectangle which was updated.
+ virtual bool writeRect(const Rect& r, ImageGetter* ig, Rect* actual);
+ virtual bool writeRect(const Rect& r, unsigned int encoding,
+ ImageGetter* ig, Rect* actual);
+
+ virtual void writeCopyRect(const Rect& r, int srcX, int srcY);
+
+ virtual void startRect(const Rect& r, unsigned int enc)=0;
+ virtual void endRect()=0;
+
+ ConnParams* getConnParams() { return cp; }
+ rdr::OutStream* getOutStream() { return os; }
+ rdr::U8* getImageBuf(int required, int requested=0, int* nPixels=0);
+ int bpp();
+
+ int getUpdatesSent() { return updatesSent; }
+ int getRectsSent(int encoding) { return rectsSent[encoding]; }
+ int getBytesSent(int encoding) { return bytesSent[encoding]; }
+ int getRawBytesEquivalent() { return rawBytesEquivalent; }
+
+ int imageBufIdealSize;
+
+ protected:
+ SMsgWriter(ConnParams* cp, rdr::OutStream* os);
+
+ virtual void startMsg(int type)=0;
+ virtual void endMsg()=0;
+
+ ConnParams* cp;
+ rdr::OutStream* os;
+
+ Encoder* encoders[encodingMax+1];
+ int lenBeforeRect;
+ unsigned int currentEncoding;
+ int updatesSent;
+ int bytesSent[encodingMax+1];
+ int rectsSent[encodingMax+1];
+ int rawBytesEquivalent;
+
+ rdr::U8* imageBuf;
+ int imageBufSize;
+ };
+}
+#endif
diff --git a/common/rfb/SMsgWriterV3.cxx b/common/rfb/SMsgWriterV3.cxx
new file mode 100644
index 00000000..a85f85ea
--- /dev/null
+++ b/common/rfb/SMsgWriterV3.cxx
@@ -0,0 +1,197 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#include <rdr/OutStream.h>
+#include <rdr/MemOutStream.h>
+#include <rfb/msgTypes.h>
+#include <rfb/Exception.h>
+#include <rfb/ConnParams.h>
+#include <rfb/SMsgWriterV3.h>
+
+using namespace rfb;
+
+SMsgWriterV3::SMsgWriterV3(ConnParams* cp, rdr::OutStream* os)
+ : SMsgWriter(cp, os), updateOS(0), realOS(os), nRectsInUpdate(0),
+ nRectsInHeader(0), wsccb(0),
+ needSetDesktopSize(false)
+{
+}
+
+SMsgWriterV3::~SMsgWriterV3()
+{
+ delete updateOS;
+}
+
+void SMsgWriterV3::writeServerInit()
+{
+ os->writeU16(cp->width);
+ os->writeU16(cp->height);
+ cp->pf().write(os);
+ os->writeString(cp->name());
+ endMsg();
+}
+
+void SMsgWriterV3::startMsg(int type)
+{
+ if (os != realOS)
+ throw Exception("startMsg called while writing an update?");
+
+ os->writeU8(type);
+}
+
+void SMsgWriterV3::endMsg()
+{
+ os->flush();
+}
+
+bool SMsgWriterV3::writeSetDesktopSize() {
+ if (!cp->supportsDesktopResize) return false;
+ needSetDesktopSize = true;
+ return true;
+}
+
+void SMsgWriterV3::cursorChange(WriteSetCursorCallback* cb)
+{
+ wsccb = cb;
+}
+
+void SMsgWriterV3::writeSetCursor(int width, int height, const Point& hotspot,
+ void* data, void* mask)
+{
+ if (!wsccb) return;
+ if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
+ throw Exception("SMsgWriterV3::writeSetCursor: nRects out of sync");
+ os->writeS16(hotspot.x);
+ os->writeS16(hotspot.y);
+ os->writeU16(width);
+ os->writeU16(height);
+ os->writeU32(pseudoEncodingCursor);
+ os->writeBytes(data, width * height * (cp->pf().bpp/8));
+ os->writeBytes(mask, (width+7)/8 * height);
+}
+
+void SMsgWriterV3::writeSetXCursor(int width, int height, int hotspotX,
+ int hotspotY, void* data, void* mask)
+{
+ if (!wsccb) return;
+ if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
+ throw Exception("SMsgWriterV3::writeSetXCursor: nRects out of sync");
+ os->writeS16(hotspotX);
+ os->writeS16(hotspotY);
+ os->writeU16(width);
+ os->writeU16(height);
+ os->writeU32(pseudoEncodingXCursor);
+ // FIXME: We only support black and white cursors, currently. We
+ // could pass the correct color by using the pix0/pix1 values
+ // returned from getBitmap, in writeSetCursorCallback. However, we
+ // would then need to undo the conversion from rgb to Pixel that is
+ // done by FakeAllocColor.
+ if (width * height) {
+ os->writeU8(0);
+ os->writeU8(0);
+ os->writeU8(0);
+ os->writeU8(255);
+ os->writeU8(255);
+ os->writeU8(255);
+ os->writeBytes(data, (width+7)/8 * height);
+ os->writeBytes(mask, (width+7)/8 * height);
+ }
+}
+
+void SMsgWriterV3::writeFramebufferUpdateStart(int nRects)
+{
+ startMsg(msgTypeFramebufferUpdate);
+ os->pad(1);
+ if (wsccb) nRects++;
+ if (needSetDesktopSize) nRects++;
+ os->writeU16(nRects);
+ nRectsInUpdate = 0;
+ nRectsInHeader = nRects;
+ if (wsccb) {
+ wsccb->writeSetCursorCallback();
+ wsccb = 0;
+ }
+}
+
+void SMsgWriterV3::writeFramebufferUpdateStart()
+{
+ nRectsInUpdate = nRectsInHeader = 0;
+ if (!updateOS)
+ updateOS = new rdr::MemOutStream;
+ os = updateOS;
+}
+
+void SMsgWriterV3::writeFramebufferUpdateEnd()
+{
+ if (needSetDesktopSize) {
+ if (!cp->supportsDesktopResize)
+ throw Exception("Client does not support desktop resize");
+ if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
+ throw Exception("SMsgWriterV3 setDesktopSize: nRects out of sync");
+ os->writeS16(0);
+ os->writeS16(0);
+ os->writeU16(cp->width);
+ os->writeU16(cp->height);
+ os->writeU32(pseudoEncodingDesktopSize);
+ needSetDesktopSize = false;
+ }
+
+ if (nRectsInUpdate != nRectsInHeader && nRectsInHeader)
+ throw Exception("SMsgWriterV3::writeFramebufferUpdateEnd: "
+ "nRects out of sync");
+ if (os == updateOS) {
+ os = realOS;
+ startMsg(msgTypeFramebufferUpdate);
+ os->pad(1);
+ os->writeU16(nRectsInUpdate);
+ os->writeBytes(updateOS->data(), updateOS->length());
+ updateOS->clear();
+ }
+
+ updatesSent++;
+ endMsg();
+}
+
+bool SMsgWriterV3::needFakeUpdate()
+{
+ return wsccb || needSetDesktopSize;
+}
+
+void SMsgWriterV3::startRect(const Rect& r, unsigned int encoding)
+{
+ if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
+ throw Exception("SMsgWriterV3::startRect: nRects out of sync");
+
+ currentEncoding = encoding;
+ lenBeforeRect = os->length();
+ if (encoding != encodingCopyRect)
+ rawBytesEquivalent += 12 + r.width() * r.height() * (bpp()/8);
+
+ os->writeS16(r.tl.x);
+ os->writeS16(r.tl.y);
+ os->writeU16(r.width());
+ os->writeU16(r.height());
+ os->writeU32(encoding);
+}
+
+void SMsgWriterV3::endRect()
+{
+ if (currentEncoding <= encodingMax) {
+ bytesSent[currentEncoding] += os->length() - lenBeforeRect;
+ rectsSent[currentEncoding]++;
+ }
+}
diff --git a/common/rfb/SMsgWriterV3.h b/common/rfb/SMsgWriterV3.h
new file mode 100644
index 00000000..501fa489
--- /dev/null
+++ b/common/rfb/SMsgWriterV3.h
@@ -0,0 +1,57 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#ifndef __RFB_SMSGWRITERV3_H__
+#define __RFB_SMSGWRITERV3_H__
+
+#include <rfb/SMsgWriter.h>
+
+namespace rdr { class MemOutStream; }
+
+namespace rfb {
+ class SMsgWriterV3 : public SMsgWriter {
+ public:
+ SMsgWriterV3(ConnParams* cp, rdr::OutStream* os);
+ virtual ~SMsgWriterV3();
+
+ virtual void writeServerInit();
+ virtual void startMsg(int type);
+ virtual void endMsg();
+ virtual bool writeSetDesktopSize();
+ virtual void cursorChange(WriteSetCursorCallback* cb);
+ virtual void writeSetCursor(int width, int height, const Point& hotspot,
+ void* data, void* mask);
+ virtual void writeSetXCursor(int width, int height, int hotspotX,
+ int hotspotY, void* data, void* mask);
+ virtual void writeFramebufferUpdateStart(int nRects);
+ virtual void writeFramebufferUpdateStart();
+ virtual void writeFramebufferUpdateEnd();
+ virtual bool needFakeUpdate();
+ virtual void startRect(const Rect& r, unsigned int encoding);
+ virtual void endRect();
+
+ private:
+ rdr::MemOutStream* updateOS;
+ rdr::OutStream* realOS;
+ int nRectsInUpdate;
+ int nRectsInHeader;
+ WriteSetCursorCallback* wsccb;
+ bool needSetDesktopSize;
+ bool needLastRect;
+ };
+}
+#endif
diff --git a/common/rfb/SSecurity.h b/common/rfb/SSecurity.h
new file mode 100644
index 00000000..108985b3
--- /dev/null
+++ b/common/rfb/SSecurity.h
@@ -0,0 +1,84 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+//
+// SSecurity - class on the server side for handling security handshaking. A
+// derived class for a particular security type overrides the processMsg()
+// method.
+
+// processMsg() is called first when the security type has been decided on, and
+// will keep being called whenever there is data to read from the client. It
+// should return false when it needs more data, or true when the connection has
+// been successfully authenticated. In the event of authentication failure an
+// AuthFailureException should be thrown - this will result in a "failed"
+// security result being sent to the client with the str() from the exception
+// being sent as the reason. Any other type of failure should be indicated by
+// some other kind of exception which will cause the connection to be aborted.
+//
+// processMsg() must never block (or at least must never block until the client
+// has been authenticated) - this is to prevent denial of service attacks.
+// Note that the first time processMsg() is called, there is no guarantee that
+// there is any data to read from the SConnection's InStream, but subsequent
+// calls guarantee there is at least one byte which can be read without
+// blocking.
+//
+// getType() should return the secType value corresponding to the SSecurity
+// implementation.
+//
+
+#ifndef __RFB_SSECURITY_H__
+#define __RFB_SSECURITY_H__
+
+#include <rdr/types.h>
+#include <rfb/util.h>
+#include <list>
+
+namespace rfb {
+
+ class SConnection;
+
+ class SSecurity {
+ public:
+ virtual ~SSecurity() {}
+ virtual bool processMsg(SConnection* sc)=0;
+ virtual void destroy() { delete this; }
+ virtual int getType() const = 0;
+
+ // getUserName() gets the name of the user attempting authentication. The
+ // storage is owned by the SSecurity object, so a copy must be taken if
+ // necessary. Null may be returned to indicate that there is no user name
+ // for this security type.
+ virtual const char* getUserName() const = 0;
+ };
+
+ // SSecurityFactory creates new SSecurity instances for
+ // particular security types.
+ // The instances must be destroyed by calling destroy()
+ // on them when done.
+ // getSecTypes returns a list of the security types that are both configured
+ // and actually supported. Which configuration is considered depends on the
+ // reverseConnection parameter.
+ class SSecurityFactory {
+ public:
+ virtual ~SSecurityFactory() {}
+ virtual SSecurity* getSSecurity(rdr::U8 secType, bool noAuth=false)=0;
+ virtual void getSecTypes(std::list<rdr::U8>* secTypes,
+ bool reverseConnection) = 0;
+ };
+
+}
+#endif
diff --git a/common/rfb/SSecurityFactoryStandard.cxx b/common/rfb/SSecurityFactoryStandard.cxx
new file mode 100644
index 00000000..a0726986
--- /dev/null
+++ b/common/rfb/SSecurityFactoryStandard.cxx
@@ -0,0 +1,128 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+//
+// SSecurityFactoryStandard
+//
+
+#include <rfb/secTypes.h>
+#include <rfb/SSecurityNone.h>
+#include <rfb/Configuration.h>
+#include <rfb/LogWriter.h>
+#include <rfb/Exception.h>
+#include <rfb/SSecurityFactoryStandard.h>
+#include <rfb/Password.h>
+
+using namespace rfb;
+
+static LogWriter vlog("SSecurityFactoryStandard");
+
+StringParameter SSecurityFactoryStandard::sec_types
+("SecurityTypes",
+ "Specify which security scheme to use for incoming connections (None, VncAuth)",
+ "VncAuth");
+
+StringParameter SSecurityFactoryStandard::rev_sec_types
+("ReverseSecurityTypes",
+ "Specify encryption scheme to use for reverse connections (None)",
+ "None");
+
+
+StringParameter SSecurityFactoryStandard::vncAuthPasswdFile
+("PasswordFile", "Password file for VNC authentication", "");
+VncAuthPasswdParameter SSecurityFactoryStandard::vncAuthPasswd
+("Password", "Obfuscated binary encoding of the password which clients must supply to "
+ "access the server", &SSecurityFactoryStandard::vncAuthPasswdFile);
+
+
+SSecurity* SSecurityFactoryStandard::getSSecurity(rdr::U8 secType, bool reverseConnection) {
+ switch (secType) {
+ case secTypeNone: return new SSecurityNone();
+ case secTypeVncAuth:
+ return new SSecurityVncAuth(&vncAuthPasswd);
+ default:
+ throw Exception("Security type not supported");
+ }
+}
+
+void SSecurityFactoryStandard::getSecTypes(std::list<rdr::U8>* secTypes, bool reverseConnection) {
+ CharArray secTypesStr;
+ if (reverseConnection)
+ secTypesStr.buf = rev_sec_types.getData();
+ else
+ secTypesStr.buf = sec_types.getData();
+ std::list<int> configured = parseSecTypes(secTypesStr.buf);
+ std::list<int>::iterator i;
+ for (i=configured.begin(); i!=configured.end(); i++) {
+ if (isSecTypeSupported(*i))
+ secTypes->push_back(*i);
+ }
+}
+
+bool SSecurityFactoryStandard::isSecTypeSupported(rdr::U8 secType) {
+ switch (secType) {
+ case secTypeNone:
+ case secTypeVncAuth:
+ return true;
+ default:
+ return false;
+ }
+}
+
+
+VncAuthPasswdParameter::VncAuthPasswdParameter(const char* name,
+ const char* desc,
+ StringParameter* passwdFile_)
+: BinaryParameter(name, desc, 0, 0), passwdFile(passwdFile_) {
+}
+
+char* VncAuthPasswdParameter::getVncAuthPasswd() {
+ ObfuscatedPasswd obfuscated;
+ getData((void**)&obfuscated.buf, &obfuscated.length);
+
+ if (obfuscated.length == 0) {
+ if (passwdFile) {
+ CharArray fname(passwdFile->getData());
+ if (!fname.buf[0]) {
+ vlog.info("neither %s nor %s params set", getName(), passwdFile->getName());
+ return 0;
+ }
+
+ FILE* fp = fopen(fname.buf, "r");
+ if (!fp) {
+ vlog.error("opening password file '%s' failed",fname.buf);
+ return 0;
+ }
+
+ vlog.debug("reading password file");
+ obfuscated.buf = new char[128];
+ obfuscated.length = fread(obfuscated.buf, 1, 128, fp);
+ fclose(fp);
+ } else {
+ vlog.info("%s parameter not set", getName());
+ }
+ }
+
+ try {
+ PlainPasswd password(obfuscated);
+ return password.takeBuf();
+ } catch (...) {
+ return 0;
+ }
+}
+
+
diff --git a/common/rfb/SSecurityFactoryStandard.h b/common/rfb/SSecurityFactoryStandard.h
new file mode 100644
index 00000000..165881ec
--- /dev/null
+++ b/common/rfb/SSecurityFactoryStandard.h
@@ -0,0 +1,68 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+//
+// SSecurityFactoryStandard - implementation of the SSecurityFactory
+// interface.
+//
+// Server implementations must define an instance of a
+// VncAuthPasswdParameter-based class somewhere. Any class based on
+// VncAuthPasswdParameter will automatically register itself as the
+// password parameter to be used by the Standard factory.
+//
+// Two implementations are provided here:
+//
+// VncAuthPasswdConfigParameter - reads the password from the Binary
+// parameter "Password".
+// VncAuthPasswdFileParameter - reads the password from the file named
+// in the String parameter "PasswordFile".
+//
+// This factory supports only the "None" and "VncAuth" security types.
+//
+
+#ifndef __RFB_SSECURITYFACTORY_STANDARD_H__
+#define __RFB_SSECURITYFACTORY_STANDARD_H__
+
+#include <rfb/SSecurityVncAuth.h>
+#include <rfb/Configuration.h>
+#include <rfb/util.h>
+
+namespace rfb {
+
+ class VncAuthPasswdParameter : public VncAuthPasswdGetter, BinaryParameter {
+ public:
+ VncAuthPasswdParameter(const char* name, const char* desc, StringParameter* passwdFile_);
+ virtual char* getVncAuthPasswd();
+ protected:
+ StringParameter* passwdFile;
+ };
+
+ class SSecurityFactoryStandard : public SSecurityFactory {
+ public:
+ virtual SSecurity* getSSecurity(rdr::U8 secType, bool reverse);
+ virtual void getSecTypes(std::list<rdr::U8>* secTypes, bool reverse);
+ static StringParameter sec_types;
+ static StringParameter rev_sec_types;
+ static StringParameter vncAuthPasswdFile;
+ static VncAuthPasswdParameter vncAuthPasswd;
+ protected:
+ virtual bool isSecTypeSupported(rdr::U8 secType);
+ };
+
+}
+#endif
diff --git a/common/rfb/SSecurityNone.h b/common/rfb/SSecurityNone.h
new file mode 100644
index 00000000..5c19f290
--- /dev/null
+++ b/common/rfb/SSecurityNone.h
@@ -0,0 +1,36 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+//
+// SSecurityNone.h
+//
+
+#ifndef __SSECURITYNONE_H__
+#define __SSECURITYNONE_H__
+
+#include <rfb/SSecurity.h>
+
+namespace rfb {
+
+ class SSecurityNone : public SSecurity {
+ public:
+ virtual bool processMsg(SConnection* sc) { return true; }
+ virtual int getType() const {return secTypeNone;}
+ virtual const char* getUserName() const {return 0;}
+ };
+}
+#endif
diff --git a/common/rfb/SSecurityVncAuth.cxx b/common/rfb/SSecurityVncAuth.cxx
new file mode 100644
index 00000000..29a3b964
--- /dev/null
+++ b/common/rfb/SSecurityVncAuth.cxx
@@ -0,0 +1,87 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+//
+// SSecurityVncAuth
+//
+// XXX not thread-safe, because d3des isn't - do we need to worry about this?
+//
+
+#include <rfb/SSecurityVncAuth.h>
+#include <rdr/RandomStream.h>
+#include <rfb/SConnection.h>
+#include <rfb/Password.h>
+#include <rfb/Configuration.h>
+#include <rfb/LogWriter.h>
+#include <rfb/util.h>
+#include <rfb/Exception.h>
+#include <string.h>
+#include <stdio.h>
+extern "C" {
+#include <rfb/d3des.h>
+}
+
+
+using namespace rfb;
+
+static LogWriter vlog("SVncAuth");
+
+
+SSecurityVncAuth::SSecurityVncAuth(VncAuthPasswdGetter* pg_)
+ : sentChallenge(false), responsePos(0), pg(pg_)
+{
+}
+
+bool SSecurityVncAuth::processMsg(SConnection* sc)
+{
+ rdr::InStream* is = sc->getInStream();
+ rdr::OutStream* os = sc->getOutStream();
+
+ if (!sentChallenge) {
+ rdr::RandomStream rs;
+ rs.readBytes(challenge, vncAuthChallengeSize);
+ os->writeBytes(challenge, vncAuthChallengeSize);
+ os->flush();
+ sentChallenge = true;
+ return false;
+ }
+
+ while (responsePos < vncAuthChallengeSize && is->checkNoWait(1))
+ response[responsePos++] = is->readU8();
+
+ if (responsePos < vncAuthChallengeSize) return false;
+
+ PlainPasswd passwd(pg->getVncAuthPasswd());
+
+ if (!passwd.buf)
+ throw AuthFailureException("No password configured for VNC Auth");
+
+ // Calculate the expected response
+ rdr::U8 key[8];
+ int pwdLen = strlen(passwd.buf);
+ for (int i=0; i<8; i++)
+ key[i] = i<pwdLen ? passwd.buf[i] : 0;
+ deskey(key, EN0);
+ for (int j = 0; j < vncAuthChallengeSize; j += 8)
+ des(challenge+j, challenge+j);
+
+ // Check the actual response
+ if (memcmp(challenge, response, vncAuthChallengeSize) != 0)
+ throw AuthFailureException();
+
+ return true;
+}
diff --git a/common/rfb/SSecurityVncAuth.h b/common/rfb/SSecurityVncAuth.h
new file mode 100644
index 00000000..1d0a82de
--- /dev/null
+++ b/common/rfb/SSecurityVncAuth.h
@@ -0,0 +1,55 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+// SSecurityVncAuth - legacy VNC authentication protocol.
+// The getPasswd call can be overridden if you wish to store
+// the VncAuth password in an implementation-specific place.
+// Otherwise, the password is read from a BinaryParameter
+// called Password.
+
+#ifndef __RFB_SSECURITYVNCAUTH_H__
+#define __RFB_SSECURITYVNCAUTH_H__
+
+#include <rfb/SSecurity.h>
+#include <rfb/secTypes.h>
+#include <rdr/types.h>
+
+namespace rfb {
+
+ class VncAuthPasswdGetter {
+ public:
+ // getPasswd() returns a string or null if unsuccessful. The
+ // SSecurityVncAuth object delete[]s the string when done.
+ virtual char* getVncAuthPasswd()=0;
+ };
+
+ class SSecurityVncAuth : public SSecurity {
+ public:
+ SSecurityVncAuth(VncAuthPasswdGetter* pg);
+ virtual bool processMsg(SConnection* sc);
+ virtual int getType() const {return secTypeVncAuth;}
+ virtual const char* getUserName() const {return 0;}
+ private:
+ enum {vncAuthChallengeSize = 16};
+ rdr::U8 challenge[vncAuthChallengeSize];
+ rdr::U8 response[vncAuthChallengeSize];
+ bool sentChallenge;
+ int responsePos;
+ VncAuthPasswdGetter* pg;
+ };
+}
+#endif
diff --git a/common/rfb/ScaledPixelBuffer.cxx b/common/rfb/ScaledPixelBuffer.cxx
new file mode 100644
index 00000000..bf4612de
--- /dev/null
+++ b/common/rfb/ScaledPixelBuffer.cxx
@@ -0,0 +1,132 @@
+/* Copyright (C) 2005 TightVNC Team. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- ScaledPixelBuffer.cxx
+
+#include <rfb/ScaledPixelBuffer.h>
+
+#include <math.h>
+#include <memory.h>
+
+using namespace rdr;
+using namespace rfb;
+
+ScaledPixelBuffer::ScaledPixelBuffer(U8 **src_data_, int src_width_,
+ int src_height_, int scale)
+ : bpp(32), scaled_data(0), scale_ratio(1), scale(100) {
+
+ setSourceBuffer(src_data_, src_width_, src_height_);
+}
+
+ScaledPixelBuffer::ScaledPixelBuffer()
+ : src_data(0), src_width(0), src_height(0), scale_ratio(1), scale(100),
+ bpp(32), scaled_data(0) {
+}
+
+ScaledPixelBuffer::~ScaledPixelBuffer() {
+}
+
+void ScaledPixelBuffer::setSourceBuffer(U8 **src_data_, int w, int h) {
+ src_data = src_data_;
+ src_width = w;
+ src_height = h;
+ calculateScaledBufferSize();
+ recreateScaledBuffer();
+}
+
+void ScaledPixelBuffer::setScale(int scale_) {
+ if (scale != scale_) {
+ scale = scale_;
+ scale_ratio = double(scale) / 100;
+ calculateScaledBufferSize();
+ recreateScaledBuffer();
+ }
+}
+
+void ScaledPixelBuffer::scaleRect(const Rect& r) {
+ static U8 *src_ptr, *ptr;
+ static U8 r0, r1, r2, r3;
+ static U8 g0, g1, g2, g3;
+ static U8 b0, b1, b2, b3;
+ static double c1_sub_dx, c1_sub_dy;
+ static double dx, dy;
+ static int i, j;
+ static Rect changed_rect;
+
+ // Calculate the changed pixel rect in the scaled image
+ changed_rect = calculateScaleBoundary(r);
+
+ // Scale the source rect to the destination image buffer using
+ // bilinear interplation
+ for (int y = changed_rect.tl.y; y < changed_rect.br.y; y++) {
+ j = (int)(dy = y / scale_ratio);
+ dy -= j;
+ c1_sub_dy = 1 - dy;
+
+ for (int x = changed_rect.tl.x; x < changed_rect.br.x; x++) {
+ ptr = &scaled_data[(x + y*scaled_width) * 4];
+
+ i = (int)(dx = x / scale_ratio);
+ dx -= i;
+ c1_sub_dx = 1 - dx;
+
+ src_ptr = &(*src_data)[(i + (j*src_width))*4];
+ b0 = *src_ptr; g0 = *(src_ptr+1); r0 = *(src_ptr+2);
+ if (i+1 < src_width) {
+ b1 = *(src_ptr+4); g1 = *(src_ptr+5); r1 = *(src_ptr+6);
+ } else {
+ b1 = b0; r1 = r0; g1 = g0;
+ }
+ if (j+1 < src_height) {
+ src_ptr += src_width * 4;
+ b3 = *src_ptr; g3 = *(src_ptr+1); r3 = *(src_ptr+2);
+ } else {
+ b3 = b0; r3 = r0; g3 = g0;
+ }
+ if ((i+1 < src_width) && (j+1 < src_height)) {
+ b2 = *(src_ptr+4); g2 = *(src_ptr+5); r2 = *(src_ptr+6);
+ } else if (i+1 >= src_width) {
+ b2 = b3; r2 = r3; g2 = g3;
+ } else {
+ b2 = b1; r2 = r1; g2 = g1;
+ }
+ *ptr++ = (U8)((b0*c1_sub_dx+b1*dx)*c1_sub_dy + (b3*c1_sub_dx+b2*dx)*dy);
+ *ptr++ = (U8)((g0*c1_sub_dx+g1*dx)*c1_sub_dy + (g3*c1_sub_dx+g2*dx)*dy);
+ *ptr = (U8)((r0*c1_sub_dx+r1*dx)*c1_sub_dy + (r3*c1_sub_dx+r2*dx)*dy);
+ }
+ }
+}
+
+Rect ScaledPixelBuffer::calculateScaleBoundary(const Rect& r) {
+ static int x_start, y_start, x_end, y_end;
+ x_start = r.tl.x == 0 ? 0 : ceil((r.tl.x-1) * scale_ratio);
+ y_start = r.tl.y == 0 ? 0 : ceil((r.tl.y-1) * scale_ratio);
+ x_end = ceil(r.br.x * scale_ratio - 1);
+ x_end = x_end < scaled_width ? x_end + 1 : scaled_width;
+ y_end = ceil(r.br.y * scale_ratio - 1);
+ y_end = y_end < scaled_height ? y_end + 1 : scaled_height;
+ return Rect(x_start, y_start, x_end, y_end);
+}
+
+void ScaledPixelBuffer::calculateScaledBufferSize() {
+ scaled_width = (int)ceil(src_width * scale_ratio);
+ scaled_height = (int)ceil(src_height * scale_ratio);
+}
+
+void ScaledPixelBuffer::recreateScaledBuffer() {
+}
diff --git a/common/rfb/ScaledPixelBuffer.h b/common/rfb/ScaledPixelBuffer.h
new file mode 100644
index 00000000..3b6aa7ef
--- /dev/null
+++ b/common/rfb/ScaledPixelBuffer.h
@@ -0,0 +1,85 @@
+/* Copyright (C) 2005 TightVNC Team. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- ScaledPixelBuffer.h
+//
+// The ScaledPixelBuffer class allows to scale the image data
+// from the source buffer to destination buffer using bilinear
+// interpolation.
+
+#include <rdr/types.h>
+#include <rfb/Rect.h>
+
+using namespace rdr;
+
+namespace rfb {
+
+ class ScaledPixelBuffer {
+ public:
+ ScaledPixelBuffer(U8 **data, int width, int height, int scale);
+ ScaledPixelBuffer();
+ virtual ~ScaledPixelBuffer();
+
+ // Get width, height, number of pixels and scale
+ int width() const { return scaled_width; }
+ int height() const { return scaled_height; }
+ int area() const { return scaled_width * scaled_height; }
+ int getScale() const { return scale; }
+
+ // Get rectangle encompassing this buffer
+ // Top-left of rectangle is either at (0,0), or the specified point.
+ Rect getRect() const { return Rect(0, 0, scaled_width, scaled_height); }
+ Rect getRect(const Point& pos) const {
+ return Rect(pos, pos.translate(Point(scaled_width, scaled_height)));
+ }
+
+ // Set the new source buffer and its parameters
+ void setSourceBuffer(U8 **src_data, int w, int h);
+
+ // Set the new scale, in percent
+ virtual void setScale(int scale);
+
+ // Scale rect from the source image buffer to the destination buffer
+ // using bilinear interpolation
+ virtual void scaleRect(const Rect& r);
+
+ // Calculate the scaled image rectangle which depend on the source
+ // image rectangle.
+ inline Rect calculateScaleBoundary(const Rect& r);
+
+ protected:
+
+ // Calculate the scaled buffer size depending on the source buffer
+ // parameters (width, height, pixel format)
+ void calculateScaledBufferSize();
+
+ // Recreate the scaled pixel buffer
+ virtual void recreateScaledBuffer();
+
+ int src_width;
+ int src_height;
+ int scaled_width;
+ int scaled_height;
+ int bpp;
+ int scale;
+ double scale_ratio;
+ U8 **src_data;
+ U8 *scaled_data;
+ };
+
+};
diff --git a/common/rfb/ServerCore.cxx b/common/rfb/ServerCore.cxx
new file mode 100644
index 00000000..750daae2
--- /dev/null
+++ b/common/rfb/ServerCore.cxx
@@ -0,0 +1,94 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- ServerCore.cxx
+
+// This header will define the Server interface, from which ServerMT and
+// ServerST will be derived.
+
+#include <string.h>
+#include <rfb/util.h>
+#include <rfb/ServerCore.h>
+
+rfb::IntParameter rfb::Server::idleTimeout
+("IdleTimeout",
+ "The number of seconds after which an idle VNC connection will be dropped "
+ "(zero means no timeout)",
+ 0, 0);
+rfb::IntParameter rfb::Server::maxDisconnectionTime
+("MaxDisconnectionTime",
+ "Terminate when no client has been connected for s seconds",
+ 0, 0);
+rfb::IntParameter rfb::Server::maxConnectionTime
+("MaxConnectionTime",
+ "Terminate when a client has been connected for s seconds",
+ 0, 0);
+rfb::IntParameter rfb::Server::maxIdleTime
+("MaxIdleTime",
+ "Terminate after s seconds of user inactivity",
+ 0, 0);
+rfb::IntParameter rfb::Server::clientWaitTimeMillis
+("ClientWaitTimeMillis",
+ "The number of milliseconds to wait for a client which is no longer "
+ "responding",
+ 20000, 0);
+rfb::BoolParameter rfb::Server::compareFB
+("CompareFB",
+ "Perform pixel comparison on framebuffer to reduce unnecessary updates",
+ true);
+rfb::BoolParameter rfb::Server::protocol3_3
+("Protocol3.3",
+ "Always use protocol version 3.3 for backwards compatibility with "
+ "badly-behaved clients",
+ false);
+rfb::BoolParameter rfb::Server::alwaysShared
+("AlwaysShared",
+ "Always treat incoming connections as shared, regardless of the client-"
+ "specified setting",
+ false);
+rfb::BoolParameter rfb::Server::neverShared
+("NeverShared",
+ "Never treat incoming connections as shared, regardless of the client-"
+ "specified setting",
+ false);
+rfb::BoolParameter rfb::Server::disconnectClients
+("DisconnectClients",
+ "Disconnect existing clients if an incoming connection is non-shared. "
+ "If combined with NeverShared then new connections will be refused "
+ "while there is a client active",
+ true);
+rfb::BoolParameter rfb::Server::acceptKeyEvents
+("AcceptKeyEvents",
+ "Accept key press and release events from clients.",
+ true);
+rfb::BoolParameter rfb::Server::acceptPointerEvents
+("AcceptPointerEvents",
+ "Accept pointer press and release events from clients.",
+ true);
+rfb::BoolParameter rfb::Server::acceptCutText
+("AcceptCutText",
+ "Accept clipboard updates from clients.",
+ true);
+rfb::BoolParameter rfb::Server::sendCutText
+("SendCutText",
+ "Send clipboard changes to clients.",
+ true);
+rfb::BoolParameter rfb::Server::queryConnect
+("QueryConnect",
+ "Prompt the local user to accept or reject incoming connections.",
+ false);
diff --git a/common/rfb/ServerCore.h b/common/rfb/ServerCore.h
new file mode 100644
index 00000000..68d7b74b
--- /dev/null
+++ b/common/rfb/ServerCore.h
@@ -0,0 +1,56 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- ServerCore.h
+
+// This header will define the Server interface, from which ServerMT and
+// ServerST will be derived.
+
+#ifndef __RFB_SERVER_CORE_H__
+#define __RFB_SERVER_CORE_H__
+
+#include <rfb/Configuration.h>
+#include <rfb/util.h>
+
+namespace rfb {
+
+ class Server {
+ public:
+
+ static IntParameter idleTimeout;
+ static IntParameter maxDisconnectionTime;
+ static IntParameter maxConnectionTime;
+ static IntParameter maxIdleTime;
+ static IntParameter clientWaitTimeMillis;
+ static BoolParameter compareFB;
+ static BoolParameter protocol3_3;
+ static BoolParameter alwaysShared;
+ static BoolParameter neverShared;
+ static BoolParameter disconnectClients;
+ static BoolParameter acceptKeyEvents;
+ static BoolParameter acceptPointerEvents;
+ static BoolParameter acceptCutText;
+ static BoolParameter sendCutText;
+ static BoolParameter queryConnect;
+
+ };
+
+};
+
+#endif // __RFB_SERVER_CORE_H__
+
diff --git a/common/rfb/Threading.h b/common/rfb/Threading.h
new file mode 100644
index 00000000..66b3aa0f
--- /dev/null
+++ b/common/rfb/Threading.h
@@ -0,0 +1,31 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- Threading.h
+// General purpose threading interface.
+// If the current platform supports threading then __RFB_THREADING_IMPL
+// will be defined after this header has been included.
+
+#ifndef __RFB_THREADING_H__
+#define __RFB_THREADING_H__
+
+#ifdef WIN32
+#include <rfb_win32/Threading.h>
+#endif
+
+#endif // __RFB_THREADING_H__
diff --git a/common/rfb/TightDecoder.cxx b/common/rfb/TightDecoder.cxx
new file mode 100644
index 00000000..9f8c505e
--- /dev/null
+++ b/common/rfb/TightDecoder.cxx
@@ -0,0 +1,159 @@
+/* Copyright (C) 2000-2003 Constantin Kaplinsky. All Rights Reserved.
+ * Copyright (C) 2004-2005 Cendio AB. All rights reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#include <rfb/CMsgReader.h>
+#include <rfb/CMsgHandler.h>
+#include <rfb/TightDecoder.h>
+#include <stdio.h> /* jpeglib.h needs FILE */
+extern "C" {
+#include <jpeglib.h>
+}
+
+using namespace rfb;
+
+#define RGB_TO_PIXEL(r,g,b) \
+ (((PIXEL_T)(r) & myFormat.redMax) << myFormat.redShift | \
+ ((PIXEL_T)(g) & myFormat.greenMax) << myFormat.greenShift | \
+ ((PIXEL_T)(b) & myFormat.blueMax) << myFormat.blueShift)
+
+#define RGB24_TO_PIXEL(r,g,b) \
+ ((((PIXEL_T)(r) & 0xFF) * myFormat.redMax + 127) / 255 \
+ << myFormat.redShift | \
+ (((PIXEL_T)(g) & 0xFF) * myFormat.greenMax + 127) / 255 \
+ << myFormat.greenShift | \
+ (((PIXEL_T)(b) & 0xFF) * myFormat.blueMax + 127) / 255 \
+ << myFormat.blueShift)
+
+#define RGB24_TO_PIXEL32(r,g,b) \
+ (((rdr::U32)(r) & 0xFF) << myFormat.redShift | \
+ ((rdr::U32)(g) & 0xFF) << myFormat.greenShift | \
+ ((rdr::U32)(b) & 0xFF) << myFormat.blueShift)
+
+#define TIGHT_MAX_WIDTH 2048
+
+static void JpegSetSrcManager(j_decompress_ptr cinfo, char *compressedData,
+ int compressedLen);
+static bool jpegError;
+
+#define EXTRA_ARGS CMsgHandler* handler
+#define FILL_RECT(r, p) handler->fillRect(r, p)
+#define IMAGE_RECT(r, p) handler->imageRect(r, p)
+#define BPP 8
+#include <rfb/tightDecode.h>
+#undef BPP
+#define BPP 16
+#include <rfb/tightDecode.h>
+#undef BPP
+#define BPP 32
+#include <rfb/tightDecode.h>
+#undef BPP
+
+Decoder* TightDecoder::create(CMsgReader* reader)
+{
+ return new TightDecoder(reader);
+}
+
+TightDecoder::TightDecoder(CMsgReader* reader_) : reader(reader_)
+{
+}
+
+TightDecoder::~TightDecoder()
+{
+}
+
+void TightDecoder::readRect(const Rect& r, CMsgHandler* handler)
+{
+ rdr::InStream* is = reader->getInStream();
+ /* Uncompressed RGB24 JPEG data, before translated, can be up to 3
+ times larger, if VNC bpp is 8. */
+ rdr::U8* buf = reader->getImageBuf(r.area()*3);
+ switch (reader->bpp()) {
+ case 8:
+ tightDecode8 (r, is, zis, (rdr::U8*) buf, handler); break;
+ case 16:
+ tightDecode16(r, is, zis, (rdr::U16*)buf, handler); break;
+ case 32:
+ tightDecode32(r, is, zis, (rdr::U32*)buf, handler); break;
+ }
+}
+
+
+//
+// A "Source manager" for the JPEG library.
+//
+
+static struct jpeg_source_mgr jpegSrcManager;
+static JOCTET *jpegBufferPtr;
+static size_t jpegBufferLen;
+
+static void JpegInitSource(j_decompress_ptr cinfo);
+static boolean JpegFillInputBuffer(j_decompress_ptr cinfo);
+static void JpegSkipInputData(j_decompress_ptr cinfo, long num_bytes);
+static void JpegTermSource(j_decompress_ptr cinfo);
+
+static void
+JpegInitSource(j_decompress_ptr cinfo)
+{
+ jpegError = false;
+}
+
+static boolean
+JpegFillInputBuffer(j_decompress_ptr cinfo)
+{
+ jpegError = true;
+ jpegSrcManager.bytes_in_buffer = jpegBufferLen;
+ jpegSrcManager.next_input_byte = (JOCTET *)jpegBufferPtr;
+
+ return TRUE;
+}
+
+static void
+JpegSkipInputData(j_decompress_ptr cinfo, long num_bytes)
+{
+ if (num_bytes < 0 || (size_t)num_bytes > jpegSrcManager.bytes_in_buffer) {
+ jpegError = true;
+ jpegSrcManager.bytes_in_buffer = jpegBufferLen;
+ jpegSrcManager.next_input_byte = (JOCTET *)jpegBufferPtr;
+ } else {
+ jpegSrcManager.next_input_byte += (size_t) num_bytes;
+ jpegSrcManager.bytes_in_buffer -= (size_t) num_bytes;
+ }
+}
+
+static void
+JpegTermSource(j_decompress_ptr cinfo)
+{
+ /* No work necessary here. */
+}
+
+static void
+JpegSetSrcManager(j_decompress_ptr cinfo, char *compressedData, int compressedLen)
+{
+ jpegBufferPtr = (JOCTET *)compressedData;
+ jpegBufferLen = (size_t)compressedLen;
+
+ jpegSrcManager.init_source = JpegInitSource;
+ jpegSrcManager.fill_input_buffer = JpegFillInputBuffer;
+ jpegSrcManager.skip_input_data = JpegSkipInputData;
+ jpegSrcManager.resync_to_restart = jpeg_resync_to_restart;
+ jpegSrcManager.term_source = JpegTermSource;
+ jpegSrcManager.next_input_byte = jpegBufferPtr;
+ jpegSrcManager.bytes_in_buffer = jpegBufferLen;
+
+ cinfo->src = &jpegSrcManager;
+}
diff --git a/common/rfb/TightDecoder.h b/common/rfb/TightDecoder.h
new file mode 100644
index 00000000..1047b374
--- /dev/null
+++ b/common/rfb/TightDecoder.h
@@ -0,0 +1,49 @@
+/* Copyright (C) 2000-2003 Constantin Kaplinsky. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#ifndef __RFB_TIGHTDECODER_H__
+#define __RFB_TIGHTDECODER_H__
+
+#include <rdr/ZlibInStream.h>
+#include <rfb/Decoder.h>
+
+namespace rfb {
+
+ class TightDecoder : public Decoder {
+ public:
+ static Decoder* create(CMsgReader* reader);
+ virtual void readRect(const Rect& r, CMsgHandler* handler);
+ virtual ~TightDecoder();
+ private:
+ TightDecoder(CMsgReader* reader);
+ CMsgReader* reader;
+ rdr::ZlibInStream zis[4];
+ };
+
+ // Compression control
+ const unsigned int rfbTightExplicitFilter = 0x04;
+ const unsigned int rfbTightFill = 0x08;
+ const unsigned int rfbTightJpeg = 0x09;
+ const unsigned int rfbTightMaxSubencoding = 0x09;
+
+ // Filters to improve compression efficiency
+ const unsigned int rfbTightFilterCopy = 0x00;
+ const unsigned int rfbTightFilterPalette = 0x01;
+ const unsigned int rfbTightFilterGradient = 0x02;
+}
+
+#endif
diff --git a/common/rfb/TightEncoder.cxx b/common/rfb/TightEncoder.cxx
new file mode 100644
index 00000000..e89a5609
--- /dev/null
+++ b/common/rfb/TightEncoder.cxx
@@ -0,0 +1,193 @@
+/* Copyright (C) 2000-2003 Constantin Kaplinsky. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#include <rdr/OutStream.h>
+#include <rfb/ImageGetter.h>
+#include <rfb/encodings.h>
+#include <rfb/ConnParams.h>
+#include <rfb/SMsgWriter.h>
+#include <rfb/TightEncoder.h>
+
+using namespace rfb;
+
+// Minimum amount of data to be compressed. This value should not be
+// changed, doing so will break compatibility with existing clients.
+#define TIGHT_MIN_TO_COMPRESS 12
+
+// Adjustable parameters.
+// FIXME: Get rid of #defines
+#define TIGHT_JPEG_MIN_RECT_SIZE 1024
+#define TIGHT_DETECT_MIN_WIDTH 8
+#define TIGHT_DETECT_MIN_HEIGHT 8
+
+//
+// Compression level stuff. The following array contains various
+// encoder parameters for each of 10 compression levels (0..9).
+// Last three parameters correspond to JPEG quality levels (0..9).
+//
+// NOTE: s_conf[9].maxRectSize should be >= s_conf[i].maxRectSize,
+// where i in [0..8]. RequiredBuffSize() method depends on this.
+// FIXME: Is this comment obsolete?
+//
+
+const TIGHT_CONF TightEncoder::conf[10] = {
+ { 512, 32, 6, 0, 0, 0, 4, 5 },
+ { 2048, 64, 6, 1, 1, 1, 8, 10 },
+ { 4096, 128, 8, 3, 3, 2, 24, 15 },
+ { 8192, 256, 12, 5, 5, 2, 32, 25 },
+ { 16384, 512, 12, 6, 7, 3, 32, 37 },
+ { 32768, 512, 12, 7, 8, 4, 32, 50 },
+ { 65536, 1024, 16, 7, 8, 5, 32, 60 },
+ { 65536, 1024, 16, 8, 9, 6, 64, 70 },
+ { 65536, 2048, 24, 9, 9, 7, 64, 75 },
+ { 65536, 2048, 32, 9, 9, 9, 96, 80 }
+};
+const int TightEncoder::defaultCompressLevel = 6;
+
+// FIXME: Not good to mirror TightEncoder's members here.
+static const TIGHT_CONF* s_pconf;
+static const TIGHT_CONF* s_pjconf;
+
+//
+// Including BPP-dependent implementation of the encoder.
+//
+
+#define EXTRA_ARGS ImageGetter* ig
+#define GET_IMAGE_INTO_BUF(r,buf) ig->getImage(buf, r);
+#define BPP 8
+#include <rfb/tightEncode.h>
+#undef BPP
+#define BPP 16
+#include <rfb/tightEncode.h>
+#undef BPP
+#define BPP 32
+#include <rfb/tightEncode.h>
+#undef BPP
+
+Encoder* TightEncoder::create(SMsgWriter* writer)
+{
+ return new TightEncoder(writer);
+}
+
+TightEncoder::TightEncoder(SMsgWriter* writer_) : writer(writer_)
+{
+ setCompressLevel(defaultCompressLevel);
+ setQualityLevel(-1);
+}
+
+TightEncoder::~TightEncoder()
+{
+}
+
+void TightEncoder::setCompressLevel(int level)
+{
+ if (level >= 0 && level <= 9) {
+ pconf = &conf[level];
+ } else {
+ pconf = &conf[defaultCompressLevel];
+ }
+}
+
+void TightEncoder::setQualityLevel(int level)
+{
+ if (level >= 0 && level <= 9) {
+ pjconf = &conf[level];
+ } else {
+ pjconf = NULL;
+ }
+}
+
+int TightEncoder::getNumRects(const Rect &r)
+{
+ const unsigned int w = r.width();
+ const unsigned int h = r.height();
+
+ // Will this rectangle split into subrects?
+ bool rectTooBig = w > pconf->maxRectWidth || w * h > pconf->maxRectSize;
+ if (!rectTooBig)
+ return 1;
+
+ // Compute max sub-rectangle size.
+ const unsigned int subrectMaxWidth =
+ (w > pconf->maxRectWidth) ? pconf->maxRectWidth : w;
+ const unsigned int subrectMaxHeight =
+ pconf->maxRectSize / subrectMaxWidth;
+
+ // Return the number of subrects.
+ return (((w - 1) / pconf->maxRectWidth + 1) *
+ ((h - 1) / subrectMaxHeight + 1));
+}
+
+bool TightEncoder::writeRect(const Rect& r, ImageGetter* ig, Rect* actual)
+{
+ // Shortcuts to rectangle coordinates and dimensions.
+ const int x = r.tl.x;
+ const int y = r.tl.y;
+ const unsigned int w = r.width();
+ const unsigned int h = r.height();
+
+ // Copy members of current TightEncoder instance to static variables.
+ s_pconf = pconf;
+ s_pjconf = pjconf;
+
+ // Encode small rects as is.
+ bool rectTooBig = w > pconf->maxRectWidth || w * h > pconf->maxRectSize;
+ if (!rectTooBig) {
+ writeSubrect(r, ig);
+ return true;
+ }
+
+ // Compute max sub-rectangle size.
+ const unsigned int subrectMaxWidth =
+ (w > pconf->maxRectWidth) ? pconf->maxRectWidth : w;
+ const unsigned int subrectMaxHeight =
+ pconf->maxRectSize / subrectMaxWidth;
+
+ // Split big rects into separately encoded subrects.
+ Rect sr;
+ unsigned int dx, dy, sw, sh;
+ for (dy = 0; dy < h; dy += subrectMaxHeight) {
+ for (dx = 0; dx < w; dx += pconf->maxRectWidth) {
+ sw = (dx + pconf->maxRectWidth < w) ? pconf->maxRectWidth : w - dx;
+ sh = (dy + subrectMaxHeight < h) ? subrectMaxHeight : h - dy;
+ sr.setXYWH(x + dx, y + dy, sw, sh);
+ writeSubrect(sr, ig);
+ }
+ }
+ return true;
+}
+
+void TightEncoder::writeSubrect(const Rect& r, ImageGetter* ig)
+{
+ rdr::U8* imageBuf = writer->getImageBuf(r.area());
+ ConnParams* cp = writer->getConnParams();
+ mos.clear();
+
+ switch (writer->bpp()) {
+ case 8:
+ tightEncode8(r, &mos, zos, imageBuf, cp, ig); break;
+ case 16:
+ tightEncode16(r, &mos, zos, imageBuf, cp, ig); break;
+ case 32:
+ tightEncode32(r, &mos, zos, imageBuf, cp, ig); break;
+ }
+
+ writer->startRect(r, encodingTight);
+ rdr::OutStream* os = writer->getOutStream();
+ os->writeBytes(mos.data(), mos.length());
+ writer->endRect();
+}
diff --git a/common/rfb/TightEncoder.h b/common/rfb/TightEncoder.h
new file mode 100644
index 00000000..9c11eaff
--- /dev/null
+++ b/common/rfb/TightEncoder.h
@@ -0,0 +1,78 @@
+/* Copyright (C) 2000-2003 Constantin Kaplinsky. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#ifndef __RFB_TIGHTENCODER_H__
+#define __RFB_TIGHTENCODER_H__
+
+#include <rdr/MemOutStream.h>
+#include <rdr/ZlibOutStream.h>
+#include <rfb/Encoder.h>
+
+// FIXME: Check if specifying extern "C" is really necessary.
+#include <stdio.h>
+extern "C" {
+#include "jpeg/jpeglib.h"
+}
+
+namespace rfb {
+
+ struct TIGHT_CONF {
+ unsigned int maxRectSize, maxRectWidth;
+ unsigned int monoMinRectSize;
+ int idxZlibLevel, monoZlibLevel, rawZlibLevel;
+ int idxMaxColorsDivisor;
+ int jpegQuality;
+ };
+
+ //
+ // Compression level stuff. The following array contains various
+ // encoder parameters for each of 10 compression levels (0..9).
+ // Last three parameters correspond to JPEG quality levels (0..9).
+ //
+ // NOTE: s_conf[9].maxRectSize should be >= s_conf[i].maxRectSize,
+ // where i in [0..8]. RequiredBuffSize() method depends on this.
+ // FIXME: Is this comment obsolete?
+ //
+
+
+ class TightEncoder : public Encoder {
+ public:
+ static Encoder* create(SMsgWriter* writer);
+ virtual void setCompressLevel(int level);
+ virtual void setQualityLevel(int level);
+ virtual int getNumRects(const Rect &r);
+ virtual bool writeRect(const Rect& r, ImageGetter* ig, Rect* actual);
+ virtual ~TightEncoder();
+
+ private:
+ TightEncoder(SMsgWriter* writer);
+ void writeSubrect(const Rect& r, ImageGetter* ig);
+
+ SMsgWriter* writer;
+ rdr::MemOutStream mos;
+ rdr::ZlibOutStream zos[4];
+
+ static const int defaultCompressLevel;
+ static const TIGHT_CONF conf[];
+
+ const TIGHT_CONF* pconf;
+ const TIGHT_CONF* pjconf;
+ };
+
+}
+
+#endif
diff --git a/common/rfb/TightPalette.cxx b/common/rfb/TightPalette.cxx
new file mode 100644
index 00000000..c4ed04e4
--- /dev/null
+++ b/common/rfb/TightPalette.cxx
@@ -0,0 +1,110 @@
+/* Copyright (C) 2000-2005 Constantin Kaplinsky. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+//
+// TightPalette class implementation.
+//
+
+#include <rfb/TightPalette.h>
+
+using namespace rfb;
+
+TightPalette::TightPalette(int maxColors)
+{
+ setMaxColors(maxColors);
+ reset();
+}
+
+void TightPalette::reset()
+{
+ m_numColors = 0;
+ memset(m_hash, 0, 256 * sizeof(TightColorList *));
+}
+
+void TightPalette::setMaxColors(int maxColors)
+{
+ m_maxColors = maxColors;
+ if (m_maxColors < 0) {
+ m_maxColors = 0;
+ } else if (m_maxColors > 254) {
+ m_maxColors = 254;
+ }
+}
+
+int TightPalette::insert(rdr::U32 rgb, int numPixels)
+{
+ TightColorList *pnode;
+ TightColorList *prev_pnode = NULL;
+ int hash_key, idx, new_idx, count;
+
+ hash_key = hashFunc(rgb);
+
+ pnode = m_hash[hash_key];
+
+ while (pnode != NULL) {
+ if (pnode->rgb == rgb) {
+ // Such palette entry already exists.
+ new_idx = idx = pnode->idx;
+ count = m_entry[idx].numPixels + numPixels;
+ if (new_idx && m_entry[new_idx-1].numPixels < count) {
+ do {
+ m_entry[new_idx] = m_entry[new_idx-1];
+ m_entry[new_idx].listNode->idx = new_idx;
+ new_idx--;
+ }
+ while (new_idx && m_entry[new_idx-1].numPixels < count);
+
+ m_entry[new_idx].listNode = pnode;
+ pnode->idx = new_idx;
+ }
+ m_entry[new_idx].numPixels = count;
+ return m_numColors;
+ }
+ prev_pnode = pnode;
+ pnode = pnode->next;
+ }
+
+ // Check if the palette is full.
+ if (m_numColors == 256 || m_numColors == m_maxColors) {
+ m_numColors = 0;
+ return 0;
+ }
+
+ // Move palette entries with lesser pixel counts.
+ for ( idx = m_numColors;
+ idx > 0 && m_entry[idx-1].numPixels < numPixels;
+ idx-- ) {
+ m_entry[idx] = m_entry[idx-1];
+ m_entry[idx].listNode->idx = idx;
+ }
+
+ // Add new palette entry into the freed slot.
+ pnode = &m_list[m_numColors];
+ if (prev_pnode != NULL) {
+ prev_pnode->next = pnode;
+ } else {
+ m_hash[hash_key] = pnode;
+ }
+ pnode->next = NULL;
+ pnode->idx = idx;
+ pnode->rgb = rgb;
+ m_entry[idx].listNode = pnode;
+ m_entry[idx].numPixels = numPixels;
+
+ return ++m_numColors;
+}
diff --git a/common/rfb/TightPalette.h b/common/rfb/TightPalette.h
new file mode 100644
index 00000000..2f6448ea
--- /dev/null
+++ b/common/rfb/TightPalette.h
@@ -0,0 +1,127 @@
+/* Copyright (C) 2000-2005 Constantin Kaplinsky. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+//
+// TightPalette class is a container for ordered color values. Colors
+// are keys in a hash where values are frequency counts. Also, there
+// is a list where colors are always sorted by these counts (more
+// frequent first).
+//
+
+#ifndef __RFB_TIGHTPALETTE_H__
+#define __RFB_TIGHTPALETTE_H__
+
+#include <string.h>
+#include <rdr/types.h>
+
+namespace rfb {
+
+ struct TightColorList {
+ TightColorList *next;
+ int idx;
+ rdr::U32 rgb;
+ };
+
+ struct TightPaletteEntry {
+ TightColorList *listNode;
+ int numPixels;
+ };
+
+ class TightPalette {
+
+ protected:
+
+ // FIXME: Bigger hash table? Better hash function?
+ inline static int hashFunc(rdr::U32 rgb) {
+ return (rgb ^ (rgb >> 13)) & 0xFF;
+ }
+
+ public:
+
+ TightPalette(int maxColors = 254);
+
+ //
+ // Re-initialize the object. This does not change maximum number
+ // of colors.
+ //
+ void reset();
+
+ //
+ // Set limit on the number of colors in the palette. Note that
+ // this value cannot exceed 254.
+ //
+ void setMaxColors(int maxColors);
+
+ //
+ // Insert new color into the palette, or increment its counter if
+ // the color is already there. Returns new number of colors, or
+ // zero if the palette is full. If the palette becomes full, it
+ // reports zero colors and cannot be used any more without calling
+ // reset().
+ //
+ int insert(rdr::U32 rgb, int numPixels);
+
+ //
+ // Return number of colors in the palette.
+ //
+ inline int getNumColors() const {
+ return m_numColors;
+ }
+
+ //
+ // Return the color specified by its index in the palette.
+ //
+ inline rdr::U32 getEntry(int i) const {
+ return (i < m_numColors) ? m_entry[i].listNode->rgb : (rdr::U32)-1;
+ }
+
+ //
+ // Return the pixel counter of the color specified by its index.
+ //
+ inline int getCount(int i) const {
+ return (i < m_numColors) ? m_entry[i].numPixels : 0;
+ }
+
+ //
+ // Return the index of a specified color.
+ //
+ inline rdr::U8 getIndex(rdr::U32 rgb) const {
+ TightColorList *pnode = m_hash[hashFunc(rgb)];
+ while (pnode != NULL) {
+ if (pnode->rgb == rgb) {
+ return (rdr::U8)pnode->idx;
+ }
+ pnode = pnode->next;
+ }
+ return 0xFF; // no such color
+ }
+
+ protected:
+
+ int m_maxColors;
+ int m_numColors;
+
+ TightPaletteEntry m_entry[256];
+ TightColorList *m_hash[256];
+ TightColorList m_list[256];
+
+ };
+
+} // namespace rfb
+
+#endif // __RFB_TIGHTPALETTE_H__
diff --git a/common/rfb/Timer.cxx b/common/rfb/Timer.cxx
new file mode 100644
index 00000000..66fd2b12
--- /dev/null
+++ b/common/rfb/Timer.cxx
@@ -0,0 +1,179 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- Timer.cxx
+
+#include <stdio.h>
+#ifdef WIN32
+#include <windows.h>
+#ifndef _WIN32_WCE
+#include <sys/timeb.h>
+#endif
+#endif
+#include <rfb/Timer.h>
+#include <rfb/util.h>
+#include <rfb/LogWriter.h>
+
+// XXX Lynx/OS 2.3: proto for gettimeofday()
+#ifdef Lynx
+#include <sys/proto.h>
+#endif
+
+using namespace rfb;
+
+#ifndef __NO_DEFINE_VLOG__
+static LogWriter vlog("Timer");
+#endif
+
+
+// Win32 does not provide gettimeofday, so we emulate it to simplify the
+// Timer code.
+
+#ifdef _WIN32
+static void gettimeofday(struct timeval* tv, void*)
+{
+ LARGE_INTEGER counts, countsPerSec;
+ static double usecPerCount = 0.0;
+
+ if (QueryPerformanceCounter(&counts)) {
+ if (usecPerCount == 0.0) {
+ QueryPerformanceFrequency(&countsPerSec);
+ usecPerCount = 1000000.0 / countsPerSec.QuadPart;
+ }
+
+ LONGLONG usecs = (LONGLONG)(counts.QuadPart * usecPerCount);
+ tv->tv_usec = (long)(usecs % 1000000);
+ tv->tv_sec = (long)(usecs / 1000000);
+
+ } else {
+#ifndef _WIN32_WCE
+ struct timeb tb;
+ ftime(&tb);
+ tv->tv_sec = tb.time;
+ tv->tv_usec = tb.millitm * 1000;
+#else
+ throw SystemException("QueryPerformanceCounter", GetLastError());
+#endif
+ }
+}
+#endif
+
+
+// Millisecond timeout processing helper functions
+
+inline static timeval addMillis(timeval inTime, int millis) {
+ int secs = millis / 1000;
+ millis = millis % 1000;
+ inTime.tv_sec += secs;
+ inTime.tv_usec += millis * 1000;
+ if (inTime.tv_usec >= 1000000) {
+ inTime.tv_sec++;
+ inTime.tv_usec -= 1000000;
+ }
+ return inTime;
+}
+
+inline static int diffTimeMillis(timeval later, timeval earlier) {
+ return ((later.tv_sec - earlier.tv_sec) * 1000) + ((later.tv_usec - earlier.tv_usec) / 1000);
+}
+
+std::list<Timer*> Timer::pending;
+
+int Timer::checkTimeouts() {
+ if (pending.empty())
+ return 0;
+ timeval now;
+ gettimeofday(&now, 0);
+ while (pending.front()->isBefore(now)) {
+ Timer* timer = pending.front();
+ pending.pop_front();
+ vlog.debug("handleTimeout(%p)", timer);
+ if (timer->cb->handleTimeout(timer)) {
+ timer->dueTime = addMillis(timer->dueTime, timer->timeoutMs);
+ if (timer->isBefore(now)) {
+ // Time has jumped forwards!
+ vlog.info("time has moved forwards!");
+ timer->dueTime = addMillis(now, timer->timeoutMs);
+ }
+ insertTimer(timer);
+ } else if (pending.empty()) {
+ return 0;
+ }
+ }
+ return getNextTimeout();
+}
+
+int Timer::getNextTimeout() {
+ timeval now;
+ gettimeofday(&now, 0);
+ int toWait = __rfbmax(1, diffTimeMillis(pending.front()->dueTime, now));
+ if (toWait > pending.front()->timeoutMs) {
+ if (toWait - pending.front()->timeoutMs < 1000) {
+ vlog.info("gettimeofday is broken...");
+ return toWait;
+ }
+ // Time has jumped backwards!
+ vlog.info("time has moved backwards!");
+ pending.front()->dueTime = now;
+ toWait = 1;
+ }
+ return toWait;
+}
+
+void Timer::insertTimer(Timer* t) {
+ std::list<Timer*>::iterator i;
+ for (i=pending.begin(); i!=pending.end(); i++) {
+ if (t->isBefore((*i)->dueTime)) {
+ pending.insert(i, t);
+ return;
+ }
+ }
+ pending.push_back(t);
+}
+
+void Timer::start(int timeoutMs_) {
+ timeval now;
+ gettimeofday(&now, 0);
+ stop();
+ timeoutMs = timeoutMs_;
+ dueTime = addMillis(now, timeoutMs);
+ insertTimer(this);
+}
+
+void Timer::stop() {
+ pending.remove(this);
+}
+
+bool Timer::isStarted() {
+ std::list<Timer*>::iterator i;
+ for (i=pending.begin(); i!=pending.end(); i++) {
+ if (*i == this)
+ return true;
+ }
+ return false;
+}
+
+int Timer::getTimeoutMs() {
+ return timeoutMs;
+}
+
+bool Timer::isBefore(timeval other) {
+ return (dueTime.tv_sec < other.tv_sec) ||
+ ((dueTime.tv_sec == other.tv_sec) &&
+ (dueTime.tv_usec < other.tv_usec));
+}
diff --git a/common/rfb/Timer.h b/common/rfb/Timer.h
new file mode 100644
index 00000000..e295b826
--- /dev/null
+++ b/common/rfb/Timer.h
@@ -0,0 +1,102 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#ifndef __RFB_TIMER_H__
+#define __RFB_TIMER_H__
+
+#include <list>
+#ifdef WIN32
+#include <winsock2.h>
+#else
+#include <sys/time.h>
+#endif
+
+namespace rfb {
+
+ /* Timer
+
+ Cross-platform timeout handling. The caller creates instances of Timer and passes a
+ Callback implementation to each. The Callback will then be called with a pointer to
+ the Timer instance that timed-out when the timeout occurs.
+
+ The static methods of Timer are used by the main loop of the application both to
+ dispatch elapsed Timer callbacks and to determine how long to wait in select() for
+ the next timeout to occur.
+
+ */
+
+ struct Timer {
+
+ struct Callback {
+ // handleTimeout
+ // Passed a pointer to the Timer that has timed out. If the handler returns true
+ // then the Timer is reset and left running, causing another timeout after the
+ // appropriate interval.
+ // If the handler returns false then the Timer is cancelled.
+ virtual bool handleTimeout(Timer* t) = 0;
+ };
+
+ // checkTimeouts()
+ // Dispatches any elapsed Timers, and returns the number of milliseconds until the
+ // next Timer will timeout.
+ static int checkTimeouts();
+
+ // getNextTimeout()
+ // Returns the number of milliseconds until the next timeout, without dispatching
+ // any elapsed Timers.
+ static int getNextTimeout();
+
+ // Create a Timer with the specified callback handler
+ Timer(Callback* cb_) {cb = cb_;}
+ ~Timer() {stop();}
+
+ // startTimer
+ // Starts the timer, causing a timeout after the specified number of milliseconds.
+ // If the timer is already active then it will be implicitly cancelled and re-started.
+ void start(int timeoutMs_);
+
+ // stopTimer
+ // Cancels the timer.
+ void stop();
+
+ // isStarted
+ // Determines whether the timer is started.
+ bool isStarted();
+
+ // getTimeoutMs
+ // Determines the previously used timeout value, if any.
+ // Usually used with isStarted() to get the _current_ timeout.
+ int getTimeoutMs();
+
+ // isBefore
+ // Determine whether the Timer will timeout before the specified time.
+ bool isBefore(timeval other);
+
+ protected:
+ timeval dueTime;
+ int timeoutMs;
+ Callback* cb;
+
+ static void insertTimer(Timer* t);
+ // The list of currently active Timers, ordered by time left until timeout.
+ static std::list<Timer*> pending;
+ };
+
+};
+
+#endif
diff --git a/common/rfb/TransImageGetter.cxx b/common/rfb/TransImageGetter.cxx
new file mode 100644
index 00000000..82c291b6
--- /dev/null
+++ b/common/rfb/TransImageGetter.cxx
@@ -0,0 +1,278 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <rfb/PixelFormat.h>
+#include <rfb/Exception.h>
+#include <rfb/ConnParams.h>
+#include <rfb/SMsgWriter.h>
+#include <rfb/ColourMap.h>
+#include <rfb/TrueColourMap.h>
+#include <rfb/PixelBuffer.h>
+#include <rfb/ColourCube.h>
+#include <rfb/TransImageGetter.h>
+
+using namespace rfb;
+
+const PixelFormat bgr233PF(8, 8, false, true, 7, 7, 3, 0, 3, 6);
+
+static void noTransFn(void* table_,
+ const PixelFormat& inPF, void* inPtr, int inStride,
+ const PixelFormat& outPF, void* outPtr, int outStride,
+ int width, int height)
+{
+ rdr::U8* ip = (rdr::U8*)inPtr;
+ rdr::U8* op = (rdr::U8*)outPtr;
+ int inStrideBytes = inStride * (inPF.bpp/8);
+ int outStrideBytes = outStride * (outPF.bpp/8);
+ int widthBytes = width * (outPF.bpp/8);
+
+ while (height > 0) {
+ memcpy(op, ip, widthBytes);
+ ip += inStrideBytes;
+ op += outStrideBytes;
+ height--;
+ }
+}
+
+#define BPPOUT 8
+#include "transInitTempl.h"
+#define BPPIN 8
+#include "transTempl.h"
+#undef BPPIN
+#define BPPIN 16
+#include "transTempl.h"
+#undef BPPIN
+#define BPPIN 32
+#include "transTempl.h"
+#undef BPPIN
+#undef BPPOUT
+
+#define BPPOUT 16
+#include "transInitTempl.h"
+#define BPPIN 8
+#include "transTempl.h"
+#undef BPPIN
+#define BPPIN 16
+#include "transTempl.h"
+#undef BPPIN
+#define BPPIN 32
+#include "transTempl.h"
+#undef BPPIN
+#undef BPPOUT
+
+#define BPPOUT 32
+#include "transInitTempl.h"
+#define BPPIN 8
+#include "transTempl.h"
+#undef BPPIN
+#define BPPIN 16
+#include "transTempl.h"
+#undef BPPIN
+#define BPPIN 32
+#include "transTempl.h"
+#undef BPPIN
+#undef BPPOUT
+
+
+// Translation functions. Note that transSimple* is only used for 8/16bpp and
+// transRGB* is used for 16/32bpp
+
+static transFnType transSimpleFns[][3] = {
+ { transSimple8to8, transSimple8to16, transSimple8to32 },
+ { transSimple16to8, transSimple16to16, transSimple16to32 },
+};
+static transFnType transRGBFns[][3] = {
+ { transRGB16to8, transRGB16to16, transRGB16to32 },
+ { transRGB32to8, transRGB32to16, transRGB32to32 }
+};
+static transFnType transRGBCubeFns[][3] = {
+ { transRGBCube16to8, transRGBCube16to16, transRGBCube16to32 },
+ { transRGBCube32to8, transRGBCube32to16, transRGBCube32to32 }
+};
+
+// Table initialisation functions.
+
+typedef void (*initCMtoTCFnType)(rdr::U8** tablep, const PixelFormat& inPF,
+ ColourMap* cm, const PixelFormat& outPF);
+typedef void (*initTCtoTCFnType)(rdr::U8** tablep, const PixelFormat& inPF,
+ const PixelFormat& outPF);
+typedef void (*initCMtoCubeFnType)(rdr::U8** tablep, const PixelFormat& inPF,
+ ColourMap* cm, ColourCube* cube);
+typedef void (*initTCtoCubeFnType)(rdr::U8** tablep, const PixelFormat& inPF,
+ ColourCube* cube);
+
+
+static initCMtoTCFnType initSimpleCMtoTCFns[] = {
+ initSimpleCMtoTC8, initSimpleCMtoTC16, initSimpleCMtoTC32
+};
+
+static initTCtoTCFnType initSimpleTCtoTCFns[] = {
+ initSimpleTCtoTC8, initSimpleTCtoTC16, initSimpleTCtoTC32
+};
+
+static initCMtoCubeFnType initSimpleCMtoCubeFns[] = {
+ initSimpleCMtoCube8, initSimpleCMtoCube16, initSimpleCMtoCube32
+};
+
+static initTCtoCubeFnType initSimpleTCtoCubeFns[] = {
+ initSimpleTCtoCube8, initSimpleTCtoCube16, initSimpleTCtoCube32
+};
+
+static initTCtoTCFnType initRGBTCtoTCFns[] = {
+ initRGBTCtoTC8, initRGBTCtoTC16, initRGBTCtoTC32
+};
+
+static initTCtoCubeFnType initRGBTCtoCubeFns[] = {
+ initRGBTCtoCube8, initRGBTCtoCube16, initRGBTCtoCube32
+};
+
+
+TransImageGetter::TransImageGetter(bool econ)
+ : economic(econ), pb(0), table(0), transFn(0), cube(0)
+{
+}
+
+TransImageGetter::~TransImageGetter()
+{
+ delete [] table;
+}
+
+void TransImageGetter::init(PixelBuffer* pb_, const PixelFormat& out,
+ SMsgWriter* writer, ColourCube* cube_)
+{
+ pb = pb_;
+ outPF = out;
+ transFn = 0;
+ cube = cube_;
+ const PixelFormat& inPF = pb->getPF();
+
+ if ((inPF.bpp != 8) && (inPF.bpp != 16) && (inPF.bpp != 32))
+ throw Exception("TransImageGetter: bpp in not 8, 16 or 32");
+
+ if ((outPF.bpp != 8) && (outPF.bpp != 16) && (outPF.bpp != 32))
+ throw Exception("TransImageGetter: bpp out not 8, 16 or 32");
+
+ if (!outPF.trueColour) {
+ if (outPF.bpp != 8)
+ throw Exception("TransImageGetter: outPF has color map but not 8bpp");
+
+ if (!inPF.trueColour) {
+ if (inPF.bpp != 8)
+ throw Exception("TransImageGetter: inPF has colorMap but not 8bpp");
+
+ // CM to CM/Cube
+
+ if (cube) {
+ transFn = transSimpleFns[inPF.bpp/16][outPF.bpp/16];
+ (*initSimpleCMtoCubeFns[outPF.bpp/16]) (&table, inPF,
+ pb->getColourMap(), cube);
+ } else {
+ transFn = noTransFn;
+ setColourMapEntries(0, 256, writer);
+ }
+ return;
+ }
+
+ // TC to CM/Cube
+
+ ColourCube defaultCube(6,6,6);
+ if (!cube) cube = &defaultCube;
+
+ if ((inPF.bpp > 16) || (economic && (inPF.bpp == 16))) {
+ transFn = transRGBCubeFns[inPF.bpp/32][outPF.bpp/16];
+ (*initRGBTCtoCubeFns[outPF.bpp/16]) (&table, inPF, cube);
+ } else {
+ transFn = transSimpleFns[inPF.bpp/16][outPF.bpp/16];
+ (*initSimpleTCtoCubeFns[outPF.bpp/16]) (&table, inPF, cube);
+ }
+
+ if (cube != &defaultCube)
+ return;
+
+ if (writer) writer->writeSetColourMapEntries(0, 216, cube);
+ cube = 0;
+ return;
+ }
+
+ if (inPF.equal(outPF)) {
+ transFn = noTransFn;
+ return;
+ }
+
+ if (!inPF.trueColour) {
+
+ // CM to TC
+
+ if (inPF.bpp != 8)
+ throw Exception("TransImageGetter: inPF has colorMap but not 8bpp");
+ transFn = transSimpleFns[inPF.bpp/16][outPF.bpp/16];
+ (*initSimpleCMtoTCFns[outPF.bpp/16]) (&table, inPF, pb->getColourMap(),
+ outPF);
+ return;
+ }
+
+ // TC to TC
+
+ if ((inPF.bpp > 16) || (economic && (inPF.bpp == 16))) {
+ transFn = transRGBFns[inPF.bpp/32][outPF.bpp/16];
+ (*initRGBTCtoTCFns[outPF.bpp/16]) (&table, inPF, outPF);
+ } else {
+ transFn = transSimpleFns[inPF.bpp/16][outPF.bpp/16];
+ (*initSimpleTCtoTCFns[outPF.bpp/16]) (&table, inPF, outPF);
+ }
+}
+
+void TransImageGetter::setColourMapEntries(int firstCol, int nCols,
+ SMsgWriter* writer)
+{
+ if (nCols == 0)
+ nCols = (1 << pb->getPF().depth) - firstCol;
+ if (pb->getPF().trueColour) return; // shouldn't be called in this case
+
+ if (outPF.trueColour) {
+ (*initSimpleCMtoTCFns[outPF.bpp/16]) (&table, pb->getPF(),
+ pb->getColourMap(), outPF);
+ } else if (cube) {
+ (*initSimpleCMtoCubeFns[outPF.bpp/16]) (&table, pb->getPF(),
+ pb->getColourMap(), cube);
+ } else if (writer && pb->getColourMap()) {
+ writer->writeSetColourMapEntries(firstCol, nCols, pb->getColourMap());
+ }
+}
+
+void TransImageGetter::getImage(void* outPtr, const Rect& r, int outStride)
+{
+ if (!transFn)
+ throw Exception("TransImageGetter: not initialised yet");
+
+ int inStride;
+ const rdr::U8* inPtr = pb->getPixelsR(r.translate(offset.negate()), &inStride);
+
+ if (!outStride) outStride = r.width();
+
+ (*transFn)(table, pb->getPF(), (void*)inPtr, inStride,
+ outPF, outPtr, outStride, r.width(), r.height());
+}
+
+void TransImageGetter::translatePixels(void* inPtr, void* outPtr,
+ int nPixels) const
+{
+ (*transFn)(table, pb->getPF(), inPtr, nPixels,
+ outPF, outPtr, nPixels, nPixels, 1);
+}
diff --git a/common/rfb/TransImageGetter.h b/common/rfb/TransImageGetter.h
new file mode 100644
index 00000000..5328e6d0
--- /dev/null
+++ b/common/rfb/TransImageGetter.h
@@ -0,0 +1,104 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+//
+// TransImageGetter - class to perform translation between pixel formats,
+// implementing the ImageGetter interface.
+//
+
+#ifndef __RFB_TRANSIMAGEGETTER_H__
+#define __RFB_TRANSIMAGEGETTER_H__
+
+#include <rfb/Rect.h>
+#include <rfb/PixelFormat.h>
+#include <rfb/ImageGetter.h>
+
+namespace rfb {
+ typedef void (*transFnType)(void* table_,
+ const PixelFormat& inPF, void* inPtr,
+ int inStride,
+ const PixelFormat& outPF, void* outPtr,
+ int outStride, int width, int height);
+
+ class SMsgWriter;
+ class ColourMap;
+ class PixelBuffer;
+ class ColourCube;
+
+ class TransImageGetter : public ImageGetter {
+ public:
+
+ TransImageGetter(bool econ=false);
+ virtual ~TransImageGetter();
+
+ // init() is called to initialise the translation tables. The PixelBuffer
+ // argument gives the source data and format details, outPF gives the
+ // client's pixel format. If the client has a colour map, then the writer
+ // argument is used to send a SetColourMapEntries message to the client.
+
+ void init(PixelBuffer* pb, const PixelFormat& outPF, SMsgWriter* writer=0,
+ ColourCube* cube=0);
+
+ // setColourMapEntries() is called when the PixelBuffer has a colour map
+ // which has changed. firstColour and nColours specify which part of the
+ // colour map has changed. If nColours is 0, this means the rest of the
+ // colour map. The PixelBuffer previously passed to init() must have a
+ // valid ColourMap object. If the client also has a colour map, then the
+ // writer argument is used to send a SetColourMapEntries message to the
+ // client. If the client is true colour then instead we update the
+ // internal translation table - in this case the caller should also make
+ // sure that the client receives an update of the relevant parts of the
+ // framebuffer (the simplest thing to do is just update the whole
+ // framebuffer, though it is possible to be smarter than this).
+
+ void setColourMapEntries(int firstColour, int nColours,
+ SMsgWriter* writer=0);
+
+ // getImage() gets the given rectangle of data from the PixelBuffer,
+ // translates it into the client's pixel format and puts it in the buffer
+ // pointed to by the outPtr argument. The optional outStride argument can
+ // be used where padding is required between the output scanlines (the
+ // padding will be outStride-r.width() pixels).
+ void getImage(void* outPtr, const Rect& r, int outStride=0);
+
+ // translatePixels() translates the given number of pixels from inPtr,
+ // putting it into the buffer pointed to by outPtr. The pixels at inPtr
+ // should be in the same format as the PixelBuffer, and the translated
+ // pixels will be in the format previously given by the outPF argument to
+ // init(). Note that this call does not use the PixelBuffer's pixel data.
+ void translatePixels(void* inPtr, void* outPtr, int nPixels) const;
+
+ // setPixelBuffer() changes the pixel buffer to be used. The new pixel
+ // buffer MUST have the same pixel format as the old one - if not you
+ // should call init() instead.
+ void setPixelBuffer(PixelBuffer* pb_) { pb = pb_; }
+
+ // setOffset() sets an offset which is subtracted from the coordinates of
+ // the rectangle given to getImage().
+ void setOffset(const Point& offset_) { offset = offset_; }
+
+ private:
+ bool economic;
+ PixelBuffer* pb;
+ PixelFormat outPF;
+ rdr::U8* table;
+ transFnType transFn;
+ ColourCube* cube;
+ Point offset;
+ };
+}
+#endif
diff --git a/common/rfb/TransferQueue.cxx b/common/rfb/TransferQueue.cxx
new file mode 100644
index 00000000..01807524
--- /dev/null
+++ b/common/rfb/TransferQueue.cxx
@@ -0,0 +1,311 @@
+/* Copyright (C) 2005 TightVNC Team. All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- TransferQueue.
+
+#include <rfb/TransferQueue.h>
+
+using namespace rfb;
+
+TransferQueue::TransferQueue()
+{
+ m_numEntries = 0;
+ m_pEntries = NULL;
+}
+
+TransferQueue::~TransferQueue()
+{
+ free();
+}
+
+void
+TransferQueue::add(TransferQueue *pTQ)
+{
+ for (unsigned int i = 0; i < pTQ->getNumEntries(); i++) {
+ add(pTQ->getLocPathAt(i), pTQ->getRemPathAt(i), pTQ->getLocNameAt(i),
+ pTQ->getRemNameAt(i), pTQ->getSizeAt(i), pTQ->getDataAt(i), pTQ->getFlagsAt(i));
+ }
+}
+
+void
+TransferQueue::add(char *pLocPath, char *pRemPath, FileInfo *pFI, unsigned int flags)
+{
+ char locPath[FT_FILENAME_SIZE];
+ char remPath[FT_FILENAME_SIZE];
+ strcpy(locPath, pLocPath);
+ strcpy(remPath, pRemPath);
+
+ for (unsigned int i = 0; i < pFI->getNumEntries(); i++) {
+ add(locPath, remPath, pFI->getNameAt(i), pFI->getNameAt(i),
+ pFI->getSizeAt(i), pFI->getDataAt(i), (pFI->getFlagsAt(i) | flags));
+ }
+}
+
+void
+TransferQueue::add(char *pLocPath, char *pRemPath, char *pLocName, char *pRemName,
+ unsigned int size, unsigned int data, unsigned int flags)
+{
+ FILEINFOEX *pTemporary = new FILEINFOEX[m_numEntries + 1];
+ if (m_numEntries != 0)
+ memcpy(pTemporary, m_pEntries, m_numEntries * sizeof(FILEINFOEX));
+
+ strcpy(pTemporary[m_numEntries].locPath, pLocPath);
+ strcpy(pTemporary[m_numEntries].locName, pLocName);
+ strcpy(pTemporary[m_numEntries].remPath, pRemPath);
+ strcpy(pTemporary[m_numEntries].remName, pRemName);
+
+ pTemporary[m_numEntries].info.size = size;
+ pTemporary[m_numEntries].info.data = data;
+ pTemporary[m_numEntries].info.flags = flags;
+
+ if (m_pEntries != NULL) {
+ delete [] m_pEntries;
+ m_pEntries = NULL;
+ }
+
+ m_pEntries = pTemporary;
+ pTemporary = NULL;
+ m_numEntries++;
+}
+
+char *
+TransferQueue::getLocPathAt(unsigned int number)
+{
+ if ((number >= 0) && (number < m_numEntries)) {
+ return m_pEntries[number].locPath;
+ }
+ return NULL;
+}
+
+char *
+TransferQueue::getLocNameAt(unsigned int number)
+{
+ if ((number >= 0) && (number < m_numEntries)) {
+ return m_pEntries[number].locName;
+ }
+ return NULL;
+}
+
+char *
+TransferQueue::getRemPathAt(unsigned int number)
+{
+ if ((number >= 0) && (number < m_numEntries)) {
+ return m_pEntries[number].remPath;
+ }
+ return NULL;
+}
+
+char *
+TransferQueue::getRemNameAt(unsigned int number)
+{
+ if ((number >= 0) && (number < m_numEntries)) {
+ return m_pEntries[number].remName;
+ }
+ return NULL;
+}
+
+char *
+TransferQueue::getFullLocPathAt(unsigned int number)
+{
+ if ((number >= 0) && (number < m_numEntries)) {
+ sprintf(m_szFullLocPath, "%s\\%s", getLocPathAt(number), getLocNameAt(number));
+ return m_szFullLocPath;
+ }
+ return NULL;
+}
+
+char *
+TransferQueue::getFullRemPathAt(unsigned int number)
+{
+ if ((number >= 0) && (number < m_numEntries)) {
+ sprintf(m_szFullRemPath, "%s\\%s", getRemPathAt(number), getRemNameAt(number));
+ return m_szFullRemPath;
+ }
+ return NULL;
+}
+
+SIZEDATAFLAGSINFO *
+TransferQueue::getSizeDataFlagsAt(unsigned int number)
+{
+ if ((number >= 0) && (number < m_numEntries)) {
+ return &m_pEntries[number].info;
+ }
+ return NULL;
+}
+
+bool
+TransferQueue::setLocPathAt(unsigned int number, char *pName)
+{
+ if ((number >= 0) && (number < m_numEntries)) {
+ strcpy(m_pEntries[number].locPath, pName);
+ return true;
+ }
+ return false;
+}
+
+bool
+TransferQueue::setLocNameAt(unsigned int number, char *pName)
+{
+ if ((number >= 0) && (number < m_numEntries)) {
+ strcpy(m_pEntries[number].locName, pName);
+ return true;
+ }
+ return false;
+}
+
+bool
+TransferQueue::setRemPathAt(unsigned int number, char *pName)
+{
+ if ((number >= 0) && (number < m_numEntries)) {
+ strcpy(m_pEntries[number].remPath, pName);
+ return true;
+ }
+ return false;
+}
+
+bool
+TransferQueue::setRemNameAt(unsigned int number, char *pName)
+{
+ if ((number >= 0) && (number < m_numEntries)) {
+ strcpy(m_pEntries[number].remName, pName);
+ return true;
+ }
+ return false;
+}
+
+unsigned int
+TransferQueue::getSizeAt(unsigned int number)
+{
+ if ((number >= 0) && (number < m_numEntries)) {
+ return m_pEntries[number].info.size;
+ }
+ return 0;
+}
+
+unsigned int
+TransferQueue::getDataAt(unsigned int number)
+{
+ if ((number >= 0) && (number < m_numEntries)) {
+ return m_pEntries[number].info.data;
+ }
+ return 0;
+}
+
+unsigned int
+TransferQueue::getFlagsAt(unsigned int number)
+{
+ if ((number >= 0) && (number < m_numEntries)) {
+ return m_pEntries[number].info.flags;
+ }
+ return 0;
+}
+
+bool
+TransferQueue::setSizeAt(unsigned int number, unsigned int value)
+{
+ if ((number >= 0) && (number < m_numEntries)) {
+ m_pEntries[number].info.size = value;
+ return true;
+ }
+ return false;
+}
+
+bool
+TransferQueue::setDataAt(unsigned int number, unsigned int value)
+{
+ if ((number >= 0) && (number < m_numEntries)) {
+ m_pEntries[number].info.data = value;
+ return true;
+ }
+ return false;
+}
+
+bool
+TransferQueue::setFlagsAt(unsigned int number, unsigned int value)
+{
+ if ((number >= 0) && (number < m_numEntries)) {
+ m_pEntries[number].info.flags = m_pEntries[number].info.flags | value;
+ return true;
+ }
+ return false;
+}
+
+bool
+TransferQueue::clearFlagAt(unsigned int number, unsigned int value)
+{
+ if ((number >= 0) && (number < m_numEntries)) {
+ m_pEntries[number].info.flags = (m_pEntries[number].info.flags & (value ^ 0xFFFFFFFF));
+ return true;
+ }
+ return false;
+}
+
+bool
+TransferQueue::setFlagToAll(unsigned int flag)
+{
+ for (unsigned int i = 0; i < m_numEntries; i++) {
+ setFlagsAt(i, flag);
+ }
+ return true;
+}
+
+bool
+TransferQueue::deleteAt(unsigned int number)
+{
+ if ((number >= m_numEntries) || (number < 0)) return false;
+
+ FILEINFOEX *pTemporary = new FILEINFOEX[m_numEntries - 1];
+
+ if (number == 0) {
+ memcpy(pTemporary, &m_pEntries[1], (m_numEntries - 1) * sizeof(FILEINFOEX));
+ } else {
+ memcpy(pTemporary, m_pEntries, number * sizeof(FILEINFOEX));
+ if (number != (m_numEntries - 1))
+ memcpy(&pTemporary[number], &m_pEntries[number + 1], (m_numEntries - number - 1) * sizeof(FILEINFOEX));
+ }
+
+ if (m_pEntries != NULL) {
+ delete [] m_pEntries;
+ m_pEntries = NULL;
+ }
+ m_pEntries = pTemporary;
+ pTemporary = NULL;
+ m_numEntries--;
+ return true;
+}
+
+unsigned int
+TransferQueue::getNumEntries()
+{
+ return m_numEntries;
+}
+
+void
+TransferQueue::free()
+{
+ if (m_pEntries != NULL) {
+ delete [] m_pEntries;
+ m_pEntries = NULL;
+ }
+ m_numEntries = 0;
+}
diff --git a/common/rfb/TransferQueue.h b/common/rfb/TransferQueue.h
new file mode 100644
index 00000000..ba748e0e
--- /dev/null
+++ b/common/rfb/TransferQueue.h
@@ -0,0 +1,87 @@
+/* Copyright (C) 2005 TightVNC Team. All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- TransferQueue.
+
+#ifndef __RFB_TRANSFERQUEUE_H__
+#define __RFB_TRANSFERQUEUE_H__
+
+#include <stdlib.h>
+
+#include <rfb/FileInfo.h>
+#include <rfb/fttypes.h>
+
+namespace rfb {
+ class TransferQueue
+ {
+ public:
+ TransferQueue();
+ ~TransferQueue();
+
+ void add(TransferQueue *pTQ);
+ void add(char *pLocPath, char*pRemPath, FileInfo *pFI, unsigned int flags);
+ void add(char *pLocPath, char *pRemPath, char *pLocName, char *pRemName,
+ unsigned int size, unsigned int data, unsigned int flags);
+
+ char *getLocPathAt(unsigned int number);
+ char *getLocNameAt(unsigned int number);
+ char *getRemPathAt(unsigned int number);
+ char *getRemNameAt(unsigned int number);
+
+ char *getFullLocPathAt(unsigned int number);
+ char *getFullRemPathAt(unsigned int number);
+
+ bool setLocPathAt(unsigned int number, char *pName);
+ bool setLocNameAt(unsigned int number, char *pName);
+ bool setRemPathAt(unsigned int number, char *pName);
+ bool setRemNameAt(unsigned int number, char *pName);
+
+ unsigned int getSizeAt(unsigned int number);
+ unsigned int getDataAt(unsigned int number);
+ unsigned int getFlagsAt(unsigned int number);
+
+ SIZEDATAFLAGSINFO * getSizeDataFlagsAt(unsigned int number);
+
+
+ bool setSizeAt(unsigned int number, unsigned int value);
+ bool setDataAt(unsigned int number, unsigned int value);
+ bool setFlagsAt(unsigned int number, unsigned int value);
+ bool clearFlagAt(unsigned int number, unsigned int value);
+ bool setFlagToAll(unsigned int flag);
+
+ bool deleteAt(unsigned int number);
+
+ unsigned int getNumEntries();
+
+ void free();
+
+ private:
+ FILEINFOEX *m_pEntries;
+ unsigned int m_numEntries;
+
+ char m_szFullLocPath[FT_FILENAME_SIZE];
+ char m_szFullRemPath[FT_FILENAME_SIZE];
+ };
+}
+
+#endif // __RFB_TRANSFERQUEUE_H__
diff --git a/common/rfb/TrueColourMap.h b/common/rfb/TrueColourMap.h
new file mode 100644
index 00000000..1e87fa4c
--- /dev/null
+++ b/common/rfb/TrueColourMap.h
@@ -0,0 +1,42 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#ifndef __RFB_TRUECOLOURMAP_H__
+#define __RFB_TRUECOLOURMAP_H__
+
+#include <rfb/ColourMap.h>
+
+namespace rfb {
+
+ class TrueColourMap : public ColourMap {
+ public:
+ TrueColourMap(const PixelFormat& pf_) : pf(pf_) {}
+
+ virtual void lookup(int i, int* r, int* g, int* b)
+ {
+ *r = (((i >> pf.redShift ) & pf.redMax)
+ * 65535 + pf.redMax/2) / pf.redMax;
+ *g = (((i >> pf.greenShift) & pf.greenMax)
+ * 65535 + pf.greenMax/2) / pf.greenMax;
+ *b = (((i >> pf.blueShift) & pf.blueMax)
+ * 65535 + pf.blueMax/2) / pf.blueMax;
+ }
+ private:
+ PixelFormat pf;
+ };
+}
+#endif
diff --git a/common/rfb/UpdateTracker.cxx b/common/rfb/UpdateTracker.cxx
new file mode 100644
index 00000000..14ac49d7
--- /dev/null
+++ b/common/rfb/UpdateTracker.cxx
@@ -0,0 +1,156 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- rfbUpdateTracker.cpp
+//
+// Tracks updated regions and a region-copy event, too
+//
+
+#include <assert.h>
+
+#include <rfb/UpdateTracker.h>
+#include <rfb/LogWriter.h>
+
+using namespace rfb;
+
+static LogWriter vlog("UpdateTracker");
+
+
+// -=- ClippingUpdateTracker
+
+void ClippingUpdateTracker::add_changed(const Region &region) {
+ ut->add_changed(region.intersect(clipRect));
+}
+
+void ClippingUpdateTracker::add_copied(const Region &dest, const Point &delta) {
+ // Clip the destination to the display area
+ Region clipdest = dest.intersect(clipRect);
+ if (clipdest.is_empty()) return;
+
+ // Clip the source to the screen
+ Region tmp = clipdest;
+ tmp.translate(delta.negate());
+ tmp.assign_intersect(clipRect);
+ if (!tmp.is_empty()) {
+ // Translate the source back to a destination region
+ tmp.translate(delta);
+
+ // Pass the copy region to the child tracker
+ ut->add_copied(tmp, delta);
+ }
+
+ // And add any bits that we had to remove to the changed region
+ tmp = clipdest.subtract(tmp);
+ if (!tmp.is_empty())
+ ut->add_changed(tmp);
+}
+
+// SimpleUpdateTracker
+
+SimpleUpdateTracker::SimpleUpdateTracker(bool use_copyrect) {
+ copy_enabled = use_copyrect;
+}
+
+SimpleUpdateTracker::~SimpleUpdateTracker() {
+}
+
+void SimpleUpdateTracker::enable_copyrect(bool enable) {
+ if (!enable && copy_enabled) {
+ add_changed(copied);
+ copied.clear();
+ }
+ copy_enabled=enable;
+}
+
+void SimpleUpdateTracker::add_changed(const Region &region) {
+ changed.assign_union(region);
+}
+
+void SimpleUpdateTracker::add_copied(const Region &dest, const Point &delta) {
+ // Do we support copyrect?
+ if (!copy_enabled) {
+ add_changed(dest);
+ return;
+ }
+
+ // Is there anything to do?
+ if (dest.is_empty()) return;
+
+ // Calculate whether any of this copy can be treated as a continuation
+ // of an earlier one
+ Region src = dest;
+ src.translate(delta.negate());
+ Region overlap = src.intersect(copied);
+
+ if (overlap.is_empty()) {
+ // There is no overlap
+
+ Rect newbr = dest.get_bounding_rect();
+ Rect oldbr = copied.get_bounding_rect();
+ if (oldbr.area() > newbr.area()) {
+ // Old copyrect is (probably) bigger - use it
+ changed.assign_union(dest);
+ } else {
+ // New copyrect is probably bigger
+ // Use the new one
+ // But be careful not to copy stuff that still needs
+ // to be updated.
+ Region invalid_src = src.intersect(changed);
+ invalid_src.translate(delta);
+ changed.assign_union(invalid_src);
+ changed.assign_union(copied);
+ copied = dest;
+ copy_delta = delta;
+ }
+ return;
+ }
+
+ Region invalid_src = overlap.intersect(changed);
+ invalid_src.translate(delta);
+ changed.assign_union(invalid_src);
+
+ overlap.translate(delta);
+
+ Region nonoverlapped_copied = dest.union_(copied).subtract(overlap);
+ changed.assign_union(nonoverlapped_copied);
+
+ copied = overlap;
+ copy_delta = copy_delta.translate(delta);
+
+ return;
+}
+
+void SimpleUpdateTracker::subtract(const Region& region) {
+ copied.assign_subtract(region);
+ changed.assign_subtract(region);
+}
+
+void SimpleUpdateTracker::getUpdateInfo(UpdateInfo* info, const Region& clip)
+{
+ copied.assign_subtract(changed);
+ info->changed = changed.intersect(clip);
+ info->copied = copied.intersect(clip);
+ info->copy_delta = copy_delta;
+}
+
+void SimpleUpdateTracker::copyTo(UpdateTracker* to) const {
+ if (!copied.is_empty())
+ to->add_copied(copied, copy_delta);
+ if (!changed.is_empty())
+ to->add_changed(changed);
+}
diff --git a/common/rfb/UpdateTracker.h b/common/rfb/UpdateTracker.h
new file mode 100644
index 00000000..5b51317a
--- /dev/null
+++ b/common/rfb/UpdateTracker.h
@@ -0,0 +1,103 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#ifndef __RFB_UPDATETRACKER_INCLUDED__
+#define __RFB_UPDATETRACKER_INCLUDED__
+
+#include <rfb/Rect.h>
+#include <rfb/Region.h>
+#include <rfb/PixelBuffer.h>
+
+namespace rfb {
+
+ class UpdateInfo {
+ public:
+ Region changed;
+ Region copied;
+ Point copy_delta;
+ bool is_empty() const {
+ return copied.is_empty() && changed.is_empty();
+ }
+ int numRects() const {
+ return copied.numRects() + changed.numRects();
+ }
+ };
+
+ class UpdateTracker {
+ public:
+ UpdateTracker() {};
+ virtual ~UpdateTracker() {};
+
+ virtual void add_changed(const Region &region) = 0;
+ virtual void add_copied(const Region &dest, const Point &delta) = 0;
+ };
+
+ class ClippingUpdateTracker : public UpdateTracker {
+ public:
+ ClippingUpdateTracker() : ut(0) {}
+ ClippingUpdateTracker(UpdateTracker* ut_, const Rect& r=Rect()) : ut(ut_), clipRect(r) {}
+
+ void setUpdateTracker(UpdateTracker* ut_) {ut = ut_;}
+ void setClipRect(const Rect& cr) {clipRect = cr;}
+
+ virtual void add_changed(const Region &region);
+ virtual void add_copied(const Region &dest, const Point &delta);
+ protected:
+ UpdateTracker* ut;
+ Region clipRect;
+ };
+
+ class SimpleUpdateTracker : public UpdateTracker {
+ public:
+ SimpleUpdateTracker(bool use_copyrect=true);
+ virtual ~SimpleUpdateTracker();
+
+ virtual void enable_copyrect(bool enable);
+
+ virtual void add_changed(const Region &region);
+ virtual void add_copied(const Region &dest, const Point &delta);
+ virtual void subtract(const Region& region);
+
+ // Fill the supplied UpdateInfo structure with update information
+ virtual void getUpdateInfo(UpdateInfo* info, const Region& cliprgn);
+
+ // Copy the contained updates to another tracker
+ virtual void copyTo(UpdateTracker* to) const;
+
+
+ // Get the changed/copied regions
+ const Region& get_changed() const {return changed;}
+ const Region& get_copied() const {return copied;}
+ const Point& get_delta() const {return copy_delta;}
+
+ // Move the entire update region by an offset
+ void translate(const Point& p) {changed.translate(p); copied.translate(p);}
+
+ virtual bool is_empty() const {return changed.is_empty() && copied.is_empty();}
+
+ virtual void clear() {changed.clear(); copied.clear();};
+ protected:
+ Region changed;
+ Region copied;
+ Point copy_delta;
+ bool copy_enabled;
+ };
+
+}
+
+#endif // __RFB_UPDATETRACKER_INCLUDED__
diff --git a/common/rfb/UserPasswdGetter.h b/common/rfb/UserPasswdGetter.h
new file mode 100644
index 00000000..18b0bae3
--- /dev/null
+++ b/common/rfb/UserPasswdGetter.h
@@ -0,0 +1,30 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#ifndef __RFB_USERPASSWDGETTER_H__
+#define __RFB_USERPASSWDGETTER_H__
+namespace rfb {
+ class UserPasswdGetter {
+ public:
+ // getUserPasswd gets the username and password. This might involve a
+ // dialog, getpass(), etc. The user buffer pointer can be null, in which
+ // case no user name will be retrieved. The caller MUST delete [] the
+ // result(s).
+ virtual void getUserPasswd(char** user, char** password)=0;
+ };
+}
+#endif
diff --git a/common/rfb/VNCSConnectionST.cxx b/common/rfb/VNCSConnectionST.cxx
new file mode 100644
index 00000000..fe60e431
--- /dev/null
+++ b/common/rfb/VNCSConnectionST.cxx
@@ -0,0 +1,714 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#include <rfb/VNCSConnectionST.h>
+#include <rfb/LogWriter.h>
+#include <rfb/secTypes.h>
+#include <rfb/ServerCore.h>
+#include <rfb/ComparingUpdateTracker.h>
+#include <rfb/KeyRemapper.h>
+#define XK_MISCELLANY
+#define XK_XKB_KEYS
+#include <rfb/keysymdef.h>
+
+using namespace rfb;
+
+static LogWriter vlog("VNCSConnST");
+
+VNCSConnectionST::VNCSConnectionST(VNCServerST* server_, network::Socket *s,
+ bool reverse)
+ : SConnection(server_->securityFactory, reverse), sock(s), server(server_),
+ updates(false), image_getter(server->useEconomicTranslate),
+ drawRenderedCursor(false), removeRenderedCursor(false),
+ pointerEventTime(0), accessRights(AccessDefault),
+ startTime(time(0)), m_pFileTransfer(0)
+{
+ setStreams(&sock->inStream(), &sock->outStream());
+ peerEndpoint.buf = sock->getPeerEndpoint();
+ VNCServerST::connectionsLog.write(1,"accepted: %s", peerEndpoint.buf);
+
+ // Configure the socket
+ setSocketTimeouts();
+ lastEventTime = time(0);
+
+ // Add this client to the VNCServerST
+ if (server->m_pFTManager != NULL) {
+ SFileTransfer *pFT = server->m_pFTManager->createObject(sock);
+ if (pFT != NULL) {
+ m_pFileTransfer = pFT;
+ }
+ }
+
+ server->clients.push_front(this);
+}
+
+
+VNCSConnectionST::~VNCSConnectionST()
+{
+ // If we reach here then VNCServerST is deleting us!
+ VNCServerST::connectionsLog.write(1,"closed: %s (%s)",
+ peerEndpoint.buf,
+ (closeReason.buf) ? closeReason.buf : "");
+
+ // Release any keys the client still had pressed
+ std::set<rdr::U32>::iterator i;
+ for (i=pressedKeys.begin(); i!=pressedKeys.end(); i++)
+ server->desktop->keyEvent(*i, false);
+ if (server->pointerClient == this)
+ server->pointerClient = 0;
+
+ if (m_pFileTransfer)
+ server->m_pFTManager->destroyObject(m_pFileTransfer);
+
+ // Remove this client from the server
+ server->clients.remove(this);
+
+}
+
+
+// Methods called from VNCServerST
+
+bool VNCSConnectionST::init()
+{
+ try {
+ initialiseProtocol();
+ } catch (rdr::Exception& e) {
+ close(e.str());
+ return false;
+ }
+ return true;
+}
+
+void VNCSConnectionST::close(const char* reason)
+{
+ // Log the reason for the close
+ if (!closeReason.buf)
+ closeReason.buf = strDup(reason);
+ else
+ vlog.debug("second close: %s (%s)", peerEndpoint.buf, reason);
+
+ if (authenticated()) {
+ server->lastDisconnectTime = time(0);
+ }
+
+ // Just shutdown the socket and mark our state as closing. Eventually the
+ // calling code will call VNCServerST's removeSocket() method causing us to
+ // be deleted.
+ sock->shutdown();
+ setState(RFBSTATE_CLOSING);
+}
+
+
+void VNCSConnectionST::processMessages()
+{
+ if (state() == RFBSTATE_CLOSING) return;
+ try {
+ // - Now set appropriate socket timeouts and process data
+ setSocketTimeouts();
+ bool clientsReadyBefore = server->clientsReadyForUpdate();
+
+ while (getInStream()->checkNoWait(1)) {
+ processMsg();
+ }
+
+ if (!clientsReadyBefore && !requested.is_empty())
+ server->desktop->framebufferUpdateRequest();
+ } catch (rdr::EndOfStream&) {
+ close("Clean disconnection");
+ } catch (rdr::Exception &e) {
+ close(e.str());
+ }
+}
+
+void VNCSConnectionST::writeFramebufferUpdateOrClose()
+{
+ try {
+ writeFramebufferUpdate();
+ } catch(rdr::Exception &e) {
+ close(e.str());
+ }
+}
+
+void VNCSConnectionST::pixelBufferChange()
+{
+ try {
+ if (!authenticated()) return;
+ if (cp.width && cp.height && (server->pb->width() != cp.width ||
+ server->pb->height() != cp.height))
+ {
+ // We need to clip the next update to the new size, but also add any
+ // extra bits if it's bigger. If we wanted to do this exactly, something
+ // like the code below would do it, but at the moment we just update the
+ // entire new size. However, we do need to clip the renderedCursorRect
+ // because that might be added to updates in writeFramebufferUpdate().
+
+ //updates.intersect(server->pb->getRect());
+ //
+ //if (server->pb->width() > cp.width)
+ // updates.add_changed(Rect(cp.width, 0, server->pb->width(),
+ // server->pb->height()));
+ //if (server->pb->height() > cp.height)
+ // updates.add_changed(Rect(0, cp.height, cp.width,
+ // server->pb->height()));
+
+ renderedCursorRect = renderedCursorRect.intersect(server->pb->getRect());
+
+ cp.width = server->pb->width();
+ cp.height = server->pb->height();
+ if (state() == RFBSTATE_NORMAL) {
+ if (!writer()->writeSetDesktopSize()) {
+ close("Client does not support desktop resize");
+ return;
+ }
+ }
+ }
+ // Just update the whole screen at the moment because we're too lazy to
+ // work out what's actually changed.
+ updates.clear();
+ updates.add_changed(server->pb->getRect());
+ vlog.debug("pixel buffer changed - re-initialising image getter");
+ image_getter.init(server->pb, cp.pf(), writer());
+ if (writer()->needFakeUpdate())
+ writeFramebufferUpdate();
+ } catch(rdr::Exception &e) {
+ close(e.str());
+ }
+}
+
+void VNCSConnectionST::setColourMapEntriesOrClose(int firstColour,int nColours)
+{
+ try {
+ setColourMapEntries(firstColour, nColours);
+ } catch(rdr::Exception& e) {
+ close(e.str());
+ }
+}
+
+void VNCSConnectionST::bell()
+{
+ try {
+ if (state() == RFBSTATE_NORMAL) writer()->writeBell();
+ } catch(rdr::Exception& e) {
+ close(e.str());
+ }
+}
+
+void VNCSConnectionST::serverCutText(const char *str, int len)
+{
+ try {
+ if (!(accessRights & AccessCutText)) return;
+ if (!rfb::Server::sendCutText) return;
+ if (state() == RFBSTATE_NORMAL)
+ writer()->writeServerCutText(str, len);
+ } catch(rdr::Exception& e) {
+ close(e.str());
+ }
+}
+
+void VNCSConnectionST::setCursorOrClose()
+{
+ try {
+ setCursor();
+ } catch(rdr::Exception& e) {
+ close(e.str());
+ }
+}
+
+
+int VNCSConnectionST::checkIdleTimeout()
+{
+ int idleTimeout = rfb::Server::idleTimeout;
+ if (idleTimeout == 0) return 0;
+ if (state() != RFBSTATE_NORMAL && idleTimeout < 15)
+ idleTimeout = 15; // minimum of 15 seconds while authenticating
+ time_t now = time(0);
+ if (now < lastEventTime) {
+ // Someone must have set the time backwards. Set lastEventTime so that the
+ // idleTimeout will count from now.
+ vlog.info("Time has gone backwards - resetting idle timeout");
+ lastEventTime = now;
+ }
+ int timeLeft = lastEventTime + idleTimeout - now;
+ if (timeLeft < -60) {
+ // Our callback is over a minute late - someone must have set the time
+ // forwards. Set lastEventTime so that the idleTimeout will count from
+ // now.
+ vlog.info("Time has gone forwards - resetting idle timeout");
+ lastEventTime = now;
+ return secsToMillis(idleTimeout);
+ }
+ if (timeLeft <= 0) {
+ close("Idle timeout");
+ return 0;
+ }
+ return secsToMillis(timeLeft);
+}
+
+// renderedCursorChange() is called whenever the server-side rendered cursor
+// changes shape or position. It ensures that the next update will clean up
+// the old rendered cursor and if necessary draw the new rendered cursor.
+
+void VNCSConnectionST::renderedCursorChange()
+{
+ if (state() != RFBSTATE_NORMAL) return;
+ removeRenderedCursor = true;
+ if (needRenderedCursor())
+ drawRenderedCursor = true;
+}
+
+// needRenderedCursor() returns true if this client needs the server-side
+// rendered cursor. This may be because it does not support local cursor or
+// because the current cursor position has not been set by this client.
+// Unfortunately we can't know for sure when the current cursor position has
+// been set by this client. We guess that this is the case when the current
+// cursor position is the same as the last pointer event from this client, or
+// if it is a very short time since this client's last pointer event (up to a
+// second). [ Ideally we should do finer-grained timing here and make the time
+// configurable, but I don't think it's that important. ]
+
+bool VNCSConnectionST::needRenderedCursor()
+{
+ return (state() == RFBSTATE_NORMAL
+ && (!cp.supportsLocalCursor && !cp.supportsLocalXCursor
+ || (!server->cursorPos.equals(pointerEventPos) &&
+ (time(0) - pointerEventTime) > 0)));
+}
+
+
+void VNCSConnectionST::approveConnectionOrClose(bool accept,
+ const char* reason)
+{
+ try {
+ approveConnection(accept, reason);
+ } catch (rdr::Exception& e) {
+ close(e.str());
+ }
+}
+
+
+
+// -=- Callbacks from SConnection
+
+void VNCSConnectionST::authSuccess()
+{
+ lastEventTime = time(0);
+
+ server->startDesktop();
+
+ // - Set the connection parameters appropriately
+ cp.width = server->pb->width();
+ cp.height = server->pb->height();
+ cp.setName(server->getName());
+
+ // - Set the default pixel format
+ cp.setPF(server->pb->getPF());
+ char buffer[256];
+ cp.pf().print(buffer, 256);
+ vlog.info("Server default pixel format %s", buffer);
+ image_getter.init(server->pb, cp.pf(), 0);
+
+ // - Mark the entire display as "dirty"
+ updates.add_changed(server->pb->getRect());
+ startTime = time(0);
+}
+
+void VNCSConnectionST::queryConnection(const char* userName)
+{
+ // - Authentication succeeded - clear from blacklist
+ CharArray name; name.buf = sock->getPeerAddress();
+ server->blHosts->clearBlackmark(name.buf);
+
+ // - Special case to provide a more useful error message
+ if (rfb::Server::neverShared && !rfb::Server::disconnectClients &&
+ server->authClientCount() > 0) {
+ approveConnection(false, "The server is already in use");
+ return;
+ }
+
+ // - Does the client have the right to bypass the query?
+ if (reverseConnection ||
+ !(rfb::Server::queryConnect || sock->requiresQuery()) ||
+ (accessRights & AccessNoQuery))
+ {
+ approveConnection(true);
+ return;
+ }
+
+ // - Get the server to display an Accept/Reject dialog, if required
+ // If a dialog is displayed, the result will be PENDING, and the
+ // server will call approveConnection at a later time
+ CharArray reason;
+ VNCServerST::queryResult qr = server->queryConnection(sock, userName,
+ &reason.buf);
+ if (qr == VNCServerST::PENDING)
+ return;
+
+ // - If server returns ACCEPT/REJECT then pass result to SConnection
+ approveConnection(qr == VNCServerST::ACCEPT, reason.buf);
+}
+
+void VNCSConnectionST::clientInit(bool shared)
+{
+ lastEventTime = time(0);
+ if (rfb::Server::alwaysShared || reverseConnection) shared = true;
+ if (rfb::Server::neverShared) shared = false;
+ if (!shared) {
+ if (rfb::Server::disconnectClients) {
+ // - Close all the other connected clients
+ vlog.debug("non-shared connection - closing clients");
+ server->closeClients("Non-shared connection requested", getSock());
+ } else {
+ // - Refuse this connection if there are existing clients, in addition to
+ // this one
+ if (server->authClientCount() > 1) {
+ close("Server is already in use");
+ return;
+ }
+ }
+ }
+ SConnection::clientInit(shared);
+}
+
+void VNCSConnectionST::setPixelFormat(const PixelFormat& pf)
+{
+ SConnection::setPixelFormat(pf);
+ char buffer[256];
+ pf.print(buffer, 256);
+ vlog.info("Client pixel format %s", buffer);
+ image_getter.init(server->pb, pf, writer());
+ setCursor();
+}
+
+void VNCSConnectionST::pointerEvent(const Point& pos, int buttonMask)
+{
+ pointerEventTime = lastEventTime = time(0);
+ server->lastUserInputTime = lastEventTime;
+ if (!(accessRights & AccessPtrEvents)) return;
+ if (!rfb::Server::acceptPointerEvents) return;
+ if (!server->pointerClient || server->pointerClient == this) {
+ pointerEventPos = pos;
+ if (buttonMask)
+ server->pointerClient = this;
+ else
+ server->pointerClient = 0;
+ server->desktop->pointerEvent(pointerEventPos, buttonMask);
+ }
+}
+
+
+class VNCSConnectionSTShiftPresser {
+public:
+ VNCSConnectionSTShiftPresser(SDesktop* desktop_)
+ : desktop(desktop_), pressed(false) {}
+ ~VNCSConnectionSTShiftPresser() {
+ if (pressed) { desktop->keyEvent(XK_Shift_L, false); }
+ }
+ void press() {
+ desktop->keyEvent(XK_Shift_L, true);
+ pressed = true;
+ }
+ SDesktop* desktop;
+ bool pressed;
+};
+
+// keyEvent() - record in the pressedKeys which keys were pressed. Allow
+// multiple down events (for autorepeat), but only allow a single up event.
+void VNCSConnectionST::keyEvent(rdr::U32 key, bool down) {
+ lastEventTime = time(0);
+ server->lastUserInputTime = lastEventTime;
+ if (!(accessRights & AccessKeyEvents)) return;
+ if (!rfb::Server::acceptKeyEvents) return;
+
+ // Remap the key if required
+ if (server->keyRemapper)
+ key = server->keyRemapper->remapKey(key);
+
+ // Turn ISO_Left_Tab into shifted Tab.
+ VNCSConnectionSTShiftPresser shiftPresser(server->desktop);
+ if (key == XK_ISO_Left_Tab) {
+ if (pressedKeys.find(XK_Shift_L) == pressedKeys.end() &&
+ pressedKeys.find(XK_Shift_R) == pressedKeys.end())
+ shiftPresser.press();
+ key = XK_Tab;
+ }
+
+ if (down) {
+ pressedKeys.insert(key);
+ } else {
+ if (!pressedKeys.erase(key)) return;
+ }
+ server->desktop->keyEvent(key, down);
+}
+
+void VNCSConnectionST::clientCutText(const char* str, int len)
+{
+ if (!(accessRights & AccessCutText)) return;
+ if (!rfb::Server::acceptCutText) return;
+ server->desktop->clientCutText(str, len);
+}
+
+void VNCSConnectionST::framebufferUpdateRequest(const Rect& r,bool incremental)
+{
+ if (!(accessRights & AccessView)) return;
+
+ SConnection::framebufferUpdateRequest(r, incremental);
+
+ Region reqRgn(r);
+ requested.assign_union(reqRgn);
+
+ if (!incremental) {
+ // Non-incremental update - treat as if area requested has changed
+ updates.add_changed(reqRgn);
+ server->comparer->add_changed(reqRgn);
+ }
+
+ writeFramebufferUpdate();
+}
+
+void VNCSConnectionST::setInitialColourMap()
+{
+ setColourMapEntries(0, 0);
+}
+
+// supportsLocalCursor() is called whenever the status of
+// cp.supportsLocalCursor has changed. If the client does now support local
+// cursor, we make sure that the old server-side rendered cursor is cleaned up
+// and the cursor is sent to the client.
+
+void VNCSConnectionST::supportsLocalCursor()
+{
+ if (cp.supportsLocalCursor || cp.supportsLocalXCursor) {
+ removeRenderedCursor = true;
+ drawRenderedCursor = false;
+ setCursor();
+ }
+}
+
+void VNCSConnectionST::writeSetCursorCallback()
+{
+ if (cp.supportsLocalXCursor) {
+ Pixel pix0, pix1;
+ rdr::U8Array bitmap(server->cursor.getBitmap(&pix0, &pix1));
+ if (bitmap.buf) {
+ // The client supports XCursor and the cursor only has two
+ // colors. Use the XCursor encoding.
+ writer()->writeSetXCursor(server->cursor.width(),
+ server->cursor.height(),
+ server->cursor.hotspot.x,
+ server->cursor.hotspot.y,
+ bitmap.buf, server->cursor.mask.buf);
+ return;
+ } else {
+ // More than two colors
+ if (!cp.supportsLocalCursor) {
+ // FIXME: We could reduce to two colors.
+ vlog.info("Unable to send multicolor cursor: RichCursor not supported by client");
+ return;
+ }
+ }
+ }
+
+ // Use RichCursor
+ rdr::U8* transData = writer()->getImageBuf(server->cursor.area());
+ image_getter.translatePixels(server->cursor.data, transData,
+ server->cursor.area());
+ writer()->writeSetCursor(server->cursor.width(),
+ server->cursor.height(),
+ server->cursor.hotspot,
+ transData, server->cursor.mask.buf);
+}
+
+
+void VNCSConnectionST::writeFramebufferUpdate()
+{
+ if (state() != RFBSTATE_NORMAL || requested.is_empty()) return;
+
+ server->checkUpdate();
+
+ // If the previous position of the rendered cursor overlaps the source of the
+ // copy, then when the copy happens the corresponding rectangle in the
+ // destination will be wrong, so add it to the changed region.
+
+ if (!updates.get_copied().is_empty() && !renderedCursorRect.is_empty()) {
+ Rect bogusCopiedCursor = (renderedCursorRect.translate(updates.get_delta())
+ .intersect(server->pb->getRect()));
+ if (!updates.get_copied().intersect(bogusCopiedCursor).is_empty()) {
+ updates.add_changed(bogusCopiedCursor);
+ }
+ }
+
+ // If we need to remove the old rendered cursor, just add the rectangle to
+ // the changed region.
+
+ if (removeRenderedCursor) {
+ updates.add_changed(renderedCursorRect);
+ renderedCursorRect.clear();
+ removeRenderedCursor = false;
+ }
+
+ // Return if there is nothing to send the client.
+
+ if (updates.is_empty() && !writer()->needFakeUpdate() && !drawRenderedCursor)
+ return;
+
+ // If the client needs a server-side rendered cursor, work out the cursor
+ // rectangle. If it's empty then don't bother drawing it, but if it overlaps
+ // with the update region, we need to draw the rendered cursor regardless of
+ // whether it has changed.
+
+ if (needRenderedCursor()) {
+ renderedCursorRect
+ = (server->renderedCursor.getRect(server->renderedCursorTL)
+ .intersect(requested.get_bounding_rect()));
+
+ if (renderedCursorRect.is_empty()) {
+ drawRenderedCursor = false;
+ } else if (!updates.get_changed().union_(updates.get_copied())
+ .intersect(renderedCursorRect).is_empty()) {
+ drawRenderedCursor = true;
+ }
+
+ // We could remove the new cursor rect from updates here. It's not clear
+ // whether this is worth it. If we do remove it, then we won't draw over
+ // the same bit of screen twice, but we have the overhead of a more complex
+ // region.
+
+ //if (drawRenderedCursor)
+ // updates.subtract(renderedCursorRect);
+ }
+
+ UpdateInfo update;
+ updates.enable_copyrect(cp.useCopyRect);
+ updates.getUpdateInfo(&update, requested);
+ if (!update.is_empty() || writer()->needFakeUpdate() || drawRenderedCursor) {
+ // Compute the number of rectangles. Tight encoder makes the things more
+ // complicated as compared to the original RealVNC.
+ writer()->setupCurrentEncoder();
+ int nRects = update.copied.numRects() + (drawRenderedCursor ? 1 : 0);
+ std::vector<Rect> rects;
+ std::vector<Rect>::const_iterator i;
+ update.changed.get_rects(&rects);
+ for (i = rects.begin(); i != rects.end(); i++) {
+ if (i->width() && i->height())
+ nRects += writer()->getNumRects(*i);
+ }
+
+ writer()->writeFramebufferUpdateStart(nRects);
+ Region updatedRegion;
+ writer()->writeRects(update, &image_getter, &updatedRegion);
+ updates.subtract(updatedRegion);
+ if (drawRenderedCursor)
+ writeRenderedCursorRect();
+ writer()->writeFramebufferUpdateEnd();
+ requested.clear();
+ }
+}
+
+
+// writeRenderedCursorRect() writes a single rectangle drawing the rendered
+// cursor on the client.
+
+void VNCSConnectionST::writeRenderedCursorRect()
+{
+ image_getter.setPixelBuffer(&server->renderedCursor);
+ image_getter.setOffset(server->renderedCursorTL);
+
+ Rect actual;
+ writer()->writeRect(renderedCursorRect, &image_getter, &actual);
+
+ image_getter.setPixelBuffer(server->pb);
+ image_getter.setOffset(Point(0,0));
+
+ drawRenderedCursor = false;
+}
+
+void VNCSConnectionST::setColourMapEntries(int firstColour, int nColours)
+{
+ if (!readyForSetColourMapEntries) return;
+ if (server->pb->getPF().trueColour) return;
+
+ image_getter.setColourMapEntries(firstColour, nColours, writer());
+
+ if (cp.pf().trueColour) {
+ updates.add_changed(server->pb->getRect());
+ }
+}
+
+
+// setCursor() is called whenever the cursor has changed shape or pixel format.
+// If the client supports local cursor then it will arrange for the cursor to
+// be sent to the client.
+
+void VNCSConnectionST::setCursor()
+{
+ if (state() != RFBSTATE_NORMAL || !cp.supportsLocalCursor) return;
+ writer()->cursorChange(this);
+ if (writer()->needFakeUpdate())
+ writeFramebufferUpdate();
+}
+
+void VNCSConnectionST::setSocketTimeouts()
+{
+ int timeoutms = rfb::Server::clientWaitTimeMillis;
+ soonestTimeout(&timeoutms, secsToMillis(rfb::Server::idleTimeout));
+ if (timeoutms == 0)
+ timeoutms = -1;
+ sock->inStream().setTimeout(timeoutms);
+ sock->outStream().setTimeout(timeoutms);
+}
+
+char* VNCSConnectionST::getStartTime()
+{
+ char* result = ctime(&startTime);
+ result[24] = '\0';
+ return result;
+}
+
+void VNCSConnectionST::setStatus(int status)
+{
+ switch (status) {
+ case 0:
+ accessRights = accessRights | AccessPtrEvents | AccessKeyEvents | AccessView;
+ break;
+ case 1:
+ accessRights = accessRights & !(AccessPtrEvents | AccessKeyEvents) | AccessView;
+ break;
+ case 2:
+ accessRights = accessRights & !(AccessPtrEvents | AccessKeyEvents | AccessView);
+ break;
+ }
+ framebufferUpdateRequest(server->pb->getRect(), false);
+}
+int VNCSConnectionST::getStatus()
+{
+ if ((accessRights & (AccessPtrEvents | AccessKeyEvents | AccessView)) == 0x0007)
+ return 0;
+ if ((accessRights & (AccessPtrEvents | AccessKeyEvents | AccessView)) == 0x0001)
+ return 1;
+ if ((accessRights & (AccessPtrEvents | AccessKeyEvents | AccessView)) == 0x0000)
+ return 2;
+ return 4;
+}
+
+bool VNCSConnectionST::processFTMsg(int type)
+{
+ if (m_pFileTransfer != NULL)
+ return m_pFileTransfer->processMessages(type);
+ else
+ return false;
+}
diff --git a/common/rfb/VNCSConnectionST.h b/common/rfb/VNCSConnectionST.h
new file mode 100644
index 00000000..a04296d3
--- /dev/null
+++ b/common/rfb/VNCSConnectionST.h
@@ -0,0 +1,176 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+//
+// VNCSConnectionST is our derived class of SConnection for VNCServerST - there
+// is one for each connected client. We think of VNCSConnectionST as part of
+// the VNCServerST implementation, so its methods are allowed full access to
+// members of VNCServerST.
+//
+
+#ifndef __RFB_VNCSCONNECTIONST_H__
+#define __RFB_VNCSCONNECTIONST_H__
+
+#include <set>
+#include <rfb/SConnection.h>
+#include <rfb/SMsgWriter.h>
+#include <rfb/TransImageGetter.h>
+#include <rfb/VNCServerST.h>
+#include <rfb/SFileTransfer.h>
+
+namespace rfb {
+ class VNCSConnectionST : public SConnection,
+ public WriteSetCursorCallback {
+ public:
+ VNCSConnectionST(VNCServerST* server_, network::Socket* s, bool reverse);
+ virtual ~VNCSConnectionST();
+
+ // Methods called from VNCServerST. None of these methods ever knowingly
+ // throw an exception.
+
+ // Unless otherwise stated, the SConnectionST may not be valid after any of
+ // these methods are called, since they catch exceptions and may have
+ // called close() which deletes the object.
+
+ // init() must be called to initialise the protocol. If it fails it
+ // returns false, and close() will have been called.
+ bool init();
+
+ // close() shuts down the socket to the client and deletes the
+ // SConnectionST object.
+ void close(const char* reason);
+
+ // processMessages() processes incoming messages from the client, invoking
+ // various callbacks as a result. It continues to process messages until
+ // reading might block. shutdown() will be called on the connection's
+ // Socket if an error occurs, via the close() call.
+ void processMessages();
+
+ void writeFramebufferUpdateOrClose();
+ void pixelBufferChange();
+ void setColourMapEntriesOrClose(int firstColour, int nColours);
+ void bell();
+ void serverCutText(const char *str, int len);
+ void setCursorOrClose();
+
+ // checkIdleTimeout() returns the number of milliseconds left until the
+ // idle timeout expires. If it has expired, the connection is closed and
+ // zero is returned. Zero is also returned if there is no idle timeout.
+ int checkIdleTimeout();
+
+ // The following methods never throw exceptions nor do they ever delete the
+ // SConnectionST object.
+
+ // renderedCursorChange() is called whenever the server-side rendered
+ // cursor changes shape or position. It ensures that the next update will
+ // clean up the old rendered cursor and if necessary draw the new rendered
+ // cursor.
+ void renderedCursorChange();
+
+ // needRenderedCursor() returns true if this client needs the server-side
+ // rendered cursor. This may be because it does not support local cursor
+ // or because the current cursor position has not been set by this client.
+ bool needRenderedCursor();
+
+ network::Socket* getSock() { return sock; }
+ bool readyForUpdate() { return !requested.is_empty(); }
+ void add_changed(const Region& region) { updates.add_changed(region); }
+ void add_copied(const Region& dest, const Point& delta) {
+ updates.add_copied(dest, delta);
+ }
+
+ const char* getPeerEndpoint() const {return peerEndpoint.buf;}
+
+ // approveConnectionOrClose() is called some time after
+ // VNCServerST::queryConnection() has returned with PENDING to accept or
+ // reject the connection. The accept argument should be true for
+ // acceptance, or false for rejection, in which case a string reason may
+ // also be given.
+
+ void approveConnectionOrClose(bool accept, const char* reason);
+
+ char* getStartTime();
+
+ void setStatus(int status);
+ int getStatus();
+
+ bool processFTMsg(int type);
+
+ private:
+ // SConnection callbacks
+
+ // These methods are invoked as callbacks from processMsg(). Note that
+ // none of these methods should call any of the above methods which may
+ // delete the SConnectionST object.
+
+ virtual void authSuccess();
+ virtual void queryConnection(const char* userName);
+ virtual void clientInit(bool shared);
+ virtual void setPixelFormat(const PixelFormat& pf);
+ virtual void pointerEvent(const Point& pos, int buttonMask);
+ virtual void keyEvent(rdr::U32 key, bool down);
+ virtual void clientCutText(const char* str, int len);
+ virtual void framebufferUpdateRequest(const Rect& r, bool incremental);
+ virtual void setInitialColourMap();
+ virtual void supportsLocalCursor();
+
+ // setAccessRights() allows a security package to limit the access rights
+ // of a VNCSConnectioST to the server. These access rights are applied
+ // such that the actual rights granted are the minimum of the server's
+ // default access settings and the connection's access settings.
+ virtual void setAccessRights(AccessRights ar) {accessRights=ar;}
+
+ // WriteSetCursorCallback
+ virtual void writeSetCursorCallback();
+
+ // Internal methods
+
+ // writeFramebufferUpdate() attempts to write a framebuffer update to the
+ // client.
+
+ void writeFramebufferUpdate();
+
+ void writeRenderedCursorRect();
+ void setColourMapEntries(int firstColour, int nColours);
+ void setCursor();
+ void setSocketTimeouts();
+
+ network::Socket* sock;
+ CharArray peerEndpoint;
+ VNCServerST* server;
+ SimpleUpdateTracker updates;
+ TransImageGetter image_getter;
+ Region requested;
+ bool drawRenderedCursor, removeRenderedCursor;
+ Rect renderedCursorRect;
+
+ std::set<rdr::U32> pressedKeys;
+
+ time_t lastEventTime;
+ time_t pointerEventTime;
+ Point pointerEventPos;
+
+ AccessRights accessRights;
+
+ CharArray closeReason;
+ time_t startTime;
+
+ SFileTransfer *m_pFileTransfer;
+ };
+}
+#endif
diff --git a/common/rfb/VNCServer.h b/common/rfb/VNCServer.h
new file mode 100644
index 00000000..df0fb0e5
--- /dev/null
+++ b/common/rfb/VNCServer.h
@@ -0,0 +1,86 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+//
+// VNCServer - abstract interface implemented by the RFB library. The back-end
+// code calls the relevant methods as appropriate.
+
+#ifndef __RFB_VNCSERVER_H__
+#define __RFB_VNCSERVER_H__
+
+#include <rfb/UpdateTracker.h>
+#include <rfb/SSecurity.h>
+
+namespace rfb {
+
+ class VNCServer : public UpdateTracker {
+ public:
+
+ // setPixelBuffer() tells the server to use the given pixel buffer. If
+ // this differs in size from the previous pixel buffer, this may result in
+ // protocol messages being sent, or clients being disconnected.
+ virtual void setPixelBuffer(PixelBuffer* pb) = 0;
+
+ // setColourMapEntries() tells the server that some entries in the colour
+ // map have changed. The server will retrieve them via the PixelBuffer's
+ // ColourMap object. This may result in protocol messages being sent.
+ // If nColours is 0, this means the rest of the colour map.
+ virtual void setColourMapEntries(int firstColour=0, int nColours=0) = 0;
+
+ // serverCutText() tells the server that the cut text has changed. This
+ // will normally be sent to all clients.
+ virtual void serverCutText(const char* str, int len) = 0;
+
+ // bell() tells the server that it should make all clients make a bell sound.
+ virtual void bell() = 0;
+
+ // clientsReadyForUpdate() returns true if there is at least one client
+ // waiting for an update, false if no clients are ready.
+ virtual bool clientsReadyForUpdate() = 0;
+
+ // - Close all currently-connected clients, by calling
+ // their close() method with the supplied reason.
+ virtual void closeClients(const char* reason) = 0;
+
+ // tryUpdate() causes the server to attempt to send updates to any waiting
+ // clients.
+ virtual void tryUpdate() = 0;
+
+ // setCursor() tells the server that the cursor has changed. The
+ // cursorData argument contains width*height pixel values in the pixel
+ // buffer's format. The mask argument is a bitmask with a 1-bit meaning
+ // the corresponding pixel in cursorData is valid. The mask consists of
+ // left-to-right, top-to-bottom scanlines, where each scanline is padded to
+ // a whole number of bytes [(width+7)/8]. Within each byte the most
+ // significant bit represents the leftmost pixel, and the bytes are simply
+ // in left-to-right order. The server takes its own copy of the data in
+ // cursorData and mask.
+ virtual void setCursor(int width, int height, const Point& hotspot,
+ void* cursorData, void* mask) = 0;
+
+ // setCursorPos() tells the server the current position of the cursor.
+ virtual void setCursorPos(const Point& p) = 0;
+
+ // setSSecurityFactory() tells the server which factory to use when
+ // attempting to authenticate connections.
+ virtual void setSSecurityFactory(SSecurityFactory* f) = 0;
+
+ // setName() tells the server what desktop title to supply to clients
+ virtual void setName(const char* name) = 0;
+ };
+}
+#endif
diff --git a/common/rfb/VNCServerST.cxx b/common/rfb/VNCServerST.cxx
new file mode 100644
index 00000000..cc18faa3
--- /dev/null
+++ b/common/rfb/VNCServerST.cxx
@@ -0,0 +1,531 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- Single-Threaded VNC Server implementation
+
+
+// Note about how sockets get closed:
+//
+// Closing sockets to clients is non-trivial because the code which calls
+// VNCServerST must explicitly know about all the sockets (so that it can block
+// on them appropriately). However, VNCServerST may want to close clients for
+// a number of reasons, and from a variety of entry points. The simplest is
+// when processSocketEvent() is called for a client, and the remote end has
+// closed its socket. A more complex reason is when processSocketEvent() is
+// called for a client which has just sent a ClientInit with the shared flag
+// set to false - in this case we want to close all other clients. Yet another
+// reason for disconnecting clients is when the desktop size has changed as a
+// result of a call to setPixelBuffer().
+//
+// The responsibility for creating and deleting sockets is entirely with the
+// calling code. When VNCServerST wants to close a connection to a client it
+// calls the VNCSConnectionST's close() method which calls shutdown() on the
+// socket. Eventually the calling code will notice that the socket has been
+// shut down and call removeSocket() so that we can delete the
+// VNCSConnectionST. Note that the socket must not be deleted by the calling
+// code until after removeSocket() has been called.
+//
+// One minor complication is that we don't allocate a VNCSConnectionST object
+// for a blacklisted host (since we want to minimise the resources used for
+// dealing with such a connection). In order to properly implement the
+// getSockets function, we must maintain a separate closingSockets list,
+// otherwise blacklisted connections might be "forgotten".
+
+
+#include <rfb/ServerCore.h>
+#include <rfb/VNCServerST.h>
+#include <rfb/VNCSConnectionST.h>
+#include <rfb/ComparingUpdateTracker.h>
+#include <rfb/SSecurityFactoryStandard.h>
+#include <rfb/KeyRemapper.h>
+#include <rfb/util.h>
+
+#include <rdr/types.h>
+
+using namespace rfb;
+
+static LogWriter slog("VNCServerST");
+LogWriter VNCServerST::connectionsLog("Connections");
+static SSecurityFactoryStandard defaultSecurityFactory;
+
+//
+// -=- VNCServerST Implementation
+//
+
+// -=- Constructors/Destructor
+
+VNCServerST::VNCServerST(const char* name_, SDesktop* desktop_,
+ SSecurityFactory* sf)
+ : blHosts(&blacklist), desktop(desktop_), desktopStarted(false), pb(0),
+ m_pFTManager(0), name(strDup(name_)), pointerClient(0), comparer(0),
+ renderedCursorInvalid(false),
+ securityFactory(sf ? sf : &defaultSecurityFactory),
+ queryConnectionHandler(0), keyRemapper(&KeyRemapper::defInstance),
+ useEconomicTranslate(false),
+ lastConnectionTime(0), disableclients(false)
+{
+ lastUserInputTime = lastDisconnectTime = time(0);
+ slog.debug("creating single-threaded server %s", name.buf);
+}
+
+VNCServerST::~VNCServerST()
+{
+ slog.debug("shutting down server %s", name.buf);
+
+ // Close any active clients, with appropriate logging & cleanup
+ closeClients("Server shutdown");
+
+ // Delete all the clients, and their sockets, and any closing sockets
+ // NB: Deleting a client implicitly removes it from the clients list
+ while (!clients.empty()) {
+ delete clients.front();
+ }
+
+ // Stop the desktop object if active, *only* after deleting all clients!
+ if (desktopStarted) {
+ desktopStarted = false;
+ desktop->stop();
+ }
+
+ delete comparer;
+}
+
+
+// SocketServer methods
+
+void VNCServerST::addSocket(network::Socket* sock, bool outgoing)
+{
+ // - Check the connection isn't black-marked
+ // *** do this in getSecurity instead?
+ CharArray address(sock->getPeerAddress());
+ if (blHosts->isBlackmarked(address.buf)) {
+ connectionsLog.error("blacklisted: %s", address.buf);
+ try {
+ SConnection::writeConnFailedFromScratch("Too many security failures",
+ &sock->outStream());
+ } catch (rdr::Exception&) {
+ }
+ sock->shutdown();
+ closingSockets.push_back(sock);
+ return;
+ }
+
+ if (clients.empty()) {
+ lastConnectionTime = time(0);
+ }
+
+ VNCSConnectionST* client = new VNCSConnectionST(this, sock, outgoing);
+ client->init();
+}
+
+void VNCServerST::removeSocket(network::Socket* sock) {
+ // - If the socket has resources allocated to it, delete them
+ std::list<VNCSConnectionST*>::iterator ci;
+ for (ci = clients.begin(); ci != clients.end(); ci++) {
+ if ((*ci)->getSock() == sock) {
+ // - Delete the per-Socket resources
+ delete *ci;
+
+ // - Check that the desktop object is still required
+ if (authClientCount() == 0 && desktopStarted) {
+ slog.debug("no authenticated clients - stopping desktop");
+ desktopStarted = false;
+ desktop->stop();
+ }
+ return;
+ }
+ }
+
+ // - If the Socket has no resources, it may have been a closingSocket
+ closingSockets.remove(sock);
+}
+
+void VNCServerST::processSocketEvent(network::Socket* sock)
+{
+ // - Find the appropriate VNCSConnectionST and process the event
+ std::list<VNCSConnectionST*>::iterator ci;
+ for (ci = clients.begin(); ci != clients.end(); ci++) {
+ if ((*ci)->getSock() == sock) {
+ (*ci)->processMessages();
+ return;
+ }
+ }
+ throw rdr::Exception("invalid Socket in VNCServerST");
+}
+
+int VNCServerST::checkTimeouts()
+{
+ int timeout = 0;
+ std::list<VNCSConnectionST*>::iterator ci, ci_next;
+ for (ci=clients.begin();ci!=clients.end();ci=ci_next) {
+ ci_next = ci; ci_next++;
+ soonestTimeout(&timeout, (*ci)->checkIdleTimeout());
+ }
+
+ int timeLeft;
+ time_t now;
+
+ // Optimization: Only call time() if using any maxTime.
+ if (rfb::Server::maxDisconnectionTime || rfb::Server::maxConnectionTime || rfb::Server::maxIdleTime) {
+ now = time(0);
+ }
+
+ // Check MaxDisconnectionTime
+ if (rfb::Server::maxDisconnectionTime && clients.empty()) {
+ if (now < lastDisconnectTime) {
+ // Someone must have set the time backwards.
+ slog.info("Time has gone backwards - resetting lastDisconnectTime");
+ lastDisconnectTime = now;
+ }
+ timeLeft = lastDisconnectTime + rfb::Server::maxDisconnectionTime - now;
+ if (timeLeft < -60) {
+ // Someone must have set the time forwards.
+ slog.info("Time has gone forwards - resetting lastDisconnectTime");
+ lastDisconnectTime = now;
+ timeLeft = rfb::Server::maxDisconnectionTime;
+ }
+ if (timeLeft <= 0) {
+ slog.info("MaxDisconnectionTime reached, exiting");
+ exit(0);
+ }
+ soonestTimeout(&timeout, timeLeft * 1000);
+ }
+
+ // Check MaxConnectionTime
+ if (rfb::Server::maxConnectionTime && lastConnectionTime && !clients.empty()) {
+ if (now < lastConnectionTime) {
+ // Someone must have set the time backwards.
+ slog.info("Time has gone backwards - resetting lastConnectionTime");
+ lastConnectionTime = now;
+ }
+ timeLeft = lastConnectionTime + rfb::Server::maxConnectionTime - now;
+ if (timeLeft < -60) {
+ // Someone must have set the time forwards.
+ slog.info("Time has gone forwards - resetting lastConnectionTime");
+ lastConnectionTime = now;
+ timeLeft = rfb::Server::maxConnectionTime;
+ }
+ if (timeLeft <= 0) {
+ slog.info("MaxConnectionTime reached, exiting");
+ exit(0);
+ }
+ soonestTimeout(&timeout, timeLeft * 1000);
+ }
+
+
+ // Check MaxIdleTime
+ if (rfb::Server::maxIdleTime) {
+ if (now < lastUserInputTime) {
+ // Someone must have set the time backwards.
+ slog.info("Time has gone backwards - resetting lastUserInputTime");
+ lastUserInputTime = now;
+ }
+ timeLeft = lastUserInputTime + rfb::Server::maxIdleTime - now;
+ if (timeLeft < -60) {
+ // Someone must have set the time forwards.
+ slog.info("Time has gone forwards - resetting lastUserInputTime");
+ lastUserInputTime = now;
+ timeLeft = rfb::Server::maxIdleTime;
+ }
+ if (timeLeft <= 0) {
+ slog.info("MaxIdleTime reached, exiting");
+ exit(0);
+ }
+ soonestTimeout(&timeout, timeLeft * 1000);
+ }
+
+ return timeout;
+}
+
+
+// VNCServer methods
+
+void VNCServerST::setPixelBuffer(PixelBuffer* pb_)
+{
+ pb = pb_;
+ delete comparer;
+ comparer = 0;
+
+ if (pb) {
+ comparer = new ComparingUpdateTracker(pb);
+ cursor.setPF(pb->getPF());
+ renderedCursor.setPF(pb->getPF());
+
+ std::list<VNCSConnectionST*>::iterator ci, ci_next;
+ for (ci=clients.begin();ci!=clients.end();ci=ci_next) {
+ ci_next = ci; ci_next++;
+ (*ci)->pixelBufferChange();
+ }
+ } else {
+ if (desktopStarted)
+ throw Exception("setPixelBuffer: null PixelBuffer when desktopStarted?");
+ }
+}
+
+void VNCServerST::setColourMapEntries(int firstColour, int nColours)
+{
+ std::list<VNCSConnectionST*>::iterator ci, ci_next;
+ for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
+ ci_next = ci; ci_next++;
+ (*ci)->setColourMapEntriesOrClose(firstColour, nColours);
+ }
+}
+
+void VNCServerST::bell()
+{
+ std::list<VNCSConnectionST*>::iterator ci, ci_next;
+ for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
+ ci_next = ci; ci_next++;
+ (*ci)->bell();
+ }
+}
+
+void VNCServerST::serverCutText(const char* str, int len)
+{
+ std::list<VNCSConnectionST*>::iterator ci, ci_next;
+ for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
+ ci_next = ci; ci_next++;
+ (*ci)->serverCutText(str, len);
+ }
+}
+
+void VNCServerST::add_changed(const Region& region)
+{
+ comparer->add_changed(region);
+}
+
+void VNCServerST::add_copied(const Region& dest, const Point& delta)
+{
+ comparer->add_copied(dest, delta);
+}
+
+bool VNCServerST::clientsReadyForUpdate()
+{
+ std::list<VNCSConnectionST*>::iterator ci;
+ for (ci = clients.begin(); ci != clients.end(); ci++) {
+ if ((*ci)->readyForUpdate())
+ return true;
+ }
+ return false;
+}
+
+void VNCServerST::tryUpdate()
+{
+ std::list<VNCSConnectionST*>::iterator ci, ci_next;
+ for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
+ ci_next = ci; ci_next++;
+ (*ci)->writeFramebufferUpdateOrClose();
+ }
+}
+
+void VNCServerST::setCursor(int width, int height, const Point& newHotspot,
+ void* data, void* mask)
+{
+ cursor.hotspot = newHotspot;
+ cursor.setSize(width, height);
+ memcpy(cursor.data, data, cursor.dataLen());
+ memcpy(cursor.mask.buf, mask, cursor.maskLen());
+
+ cursor.crop();
+
+ renderedCursorInvalid = true;
+
+ std::list<VNCSConnectionST*>::iterator ci, ci_next;
+ for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
+ ci_next = ci; ci_next++;
+ (*ci)->renderedCursorChange();
+ (*ci)->setCursorOrClose();
+ }
+}
+
+void VNCServerST::setCursorPos(const Point& pos)
+{
+ if (!cursorPos.equals(pos)) {
+ cursorPos = pos;
+ renderedCursorInvalid = true;
+ std::list<VNCSConnectionST*>::iterator ci;
+ for (ci = clients.begin(); ci != clients.end(); ci++)
+ (*ci)->renderedCursorChange();
+ }
+}
+
+// Other public methods
+
+void VNCServerST::approveConnection(network::Socket* sock, bool accept,
+ const char* reason)
+{
+ std::list<VNCSConnectionST*>::iterator ci;
+ for (ci = clients.begin(); ci != clients.end(); ci++) {
+ if ((*ci)->getSock() == sock) {
+ (*ci)->approveConnectionOrClose(accept, reason);
+ return;
+ }
+ }
+}
+
+void VNCServerST::closeClients(const char* reason, network::Socket* except)
+{
+ std::list<VNCSConnectionST*>::iterator i, next_i;
+ for (i=clients.begin(); i!=clients.end(); i=next_i) {
+ next_i = i; next_i++;
+ if ((*i)->getSock() != except)
+ (*i)->close(reason);
+ }
+}
+
+void VNCServerST::getSockets(std::list<network::Socket*>* sockets)
+{
+ sockets->clear();
+ std::list<VNCSConnectionST*>::iterator ci;
+ for (ci = clients.begin(); ci != clients.end(); ci++) {
+ sockets->push_back((*ci)->getSock());
+ }
+ std::list<network::Socket*>::iterator si;
+ for (si = closingSockets.begin(); si != closingSockets.end(); si++) {
+ sockets->push_back(*si);
+ }
+}
+
+SConnection* VNCServerST::getSConnection(network::Socket* sock) {
+ std::list<VNCSConnectionST*>::iterator ci;
+ for (ci = clients.begin(); ci != clients.end(); ci++) {
+ if ((*ci)->getSock() == sock)
+ return *ci;
+ }
+ return 0;
+}
+
+
+// -=- Internal methods
+
+void VNCServerST::startDesktop()
+{
+ if (!desktopStarted) {
+ slog.debug("starting desktop");
+ desktop->start(this);
+ desktopStarted = true;
+ if (!pb)
+ throw Exception("SDesktop::start() did not set a valid PixelBuffer");
+ }
+}
+
+int VNCServerST::authClientCount() {
+ int count = 0;
+ std::list<VNCSConnectionST*>::iterator ci;
+ for (ci = clients.begin(); ci != clients.end(); ci++) {
+ if ((*ci)->authenticated())
+ count++;
+ }
+ return count;
+}
+
+inline bool VNCServerST::needRenderedCursor()
+{
+ std::list<VNCSConnectionST*>::iterator ci;
+ for (ci = clients.begin(); ci != clients.end(); ci++)
+ if ((*ci)->needRenderedCursor()) return true;
+ return false;
+}
+
+// checkUpdate() is called just before sending an update. It checks to see
+// what updates are pending and propagates them to the update tracker for each
+// client. It uses the ComparingUpdateTracker's compare() method to filter out
+// areas of the screen which haven't actually changed. It also checks the
+// state of the (server-side) rendered cursor, if necessary rendering it again
+// with the correct background.
+
+void VNCServerST::checkUpdate()
+{
+ bool renderCursor = needRenderedCursor();
+
+ if (comparer->is_empty() && !(renderCursor && renderedCursorInvalid))
+ return;
+
+ Region toCheck = comparer->get_changed().union_(comparer->get_copied());
+
+ if (renderCursor) {
+ Rect clippedCursorRect
+ = cursor.getRect(cursorTL()).intersect(pb->getRect());
+
+ if (!renderedCursorInvalid && (toCheck.intersect(clippedCursorRect)
+ .is_empty())) {
+ renderCursor = false;
+ } else {
+ renderedCursorTL = clippedCursorRect.tl;
+ renderedCursor.setSize(clippedCursorRect.width(),
+ clippedCursorRect.height());
+ toCheck.assign_union(clippedCursorRect);
+ }
+ }
+
+ pb->grabRegion(toCheck);
+
+ if (rfb::Server::compareFB)
+ comparer->compare();
+
+ if (renderCursor) {
+ pb->getImage(renderedCursor.data,
+ renderedCursor.getRect(renderedCursorTL));
+ renderedCursor.maskRect(cursor.getRect(cursorTL()
+ .subtract(renderedCursorTL)),
+ cursor.data, cursor.mask.buf);
+ renderedCursorInvalid = false;
+ }
+
+ std::list<VNCSConnectionST*>::iterator ci, ci_next;
+ for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
+ ci_next = ci; ci_next++;
+ (*ci)->add_copied(comparer->get_copied(), comparer->get_delta());
+ (*ci)->add_changed(comparer->get_changed());
+ }
+
+ comparer->clear();
+}
+
+void VNCServerST::getConnInfo(ListConnInfo * listConn)
+{
+ listConn->Clear();
+ listConn->setDisable(getDisable());
+ if (clients.empty())
+ return;
+ std::list<VNCSConnectionST*>::iterator i;
+ for (i = clients.begin(); i != clients.end(); i++)
+ listConn->addInfo((void*)(*i), (*i)->getSock()->getPeerAddress(),
+ (*i)->getStartTime(), (*i)->getStatus());
+}
+
+void VNCServerST::setConnStatus(ListConnInfo* listConn)
+{
+ setDisable(listConn->getDisable());
+ if (listConn->Empty() || clients.empty()) return;
+ for (listConn->iBegin(); !listConn->iEnd(); listConn->iNext()) {
+ VNCSConnectionST* conn = (VNCSConnectionST*)listConn->iGetConn();
+ std::list<VNCSConnectionST*>::iterator i;
+ for (i = clients.begin(); i != clients.end(); i++) {
+ if ((*i) == conn) {
+ int status = listConn->iGetStatus();
+ if (status == 3) {
+ (*i)->close(0);
+ } else {
+ (*i)->setStatus(status);
+ }
+ break;
+ }
+ }
+ }
+}
diff --git a/common/rfb/VNCServerST.h b/common/rfb/VNCServerST.h
new file mode 100644
index 00000000..bc15b7f4
--- /dev/null
+++ b/common/rfb/VNCServerST.h
@@ -0,0 +1,245 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- VNCServerST.h
+
+// Single-threaded VNCServer implementation
+
+#ifndef __RFB_VNCSERVERST_H__
+#define __RFB_VNCSERVERST_H__
+
+#include <list>
+
+#include <rfb/SDesktop.h>
+#include <rfb/VNCServer.h>
+#include <rfb/Configuration.h>
+#include <rfb/LogWriter.h>
+#include <rfb/Blacklist.h>
+#include <rfb/Cursor.h>
+#include <network/Socket.h>
+#include <rfb/ListConnInfo.h>
+#include <rfb/SFileTransferManager.h>
+
+namespace rfb {
+
+ class VNCSConnectionST;
+ class ComparingUpdateTracker;
+ class PixelBuffer;
+ class KeyRemapper;
+
+ class VNCServerST : public VNCServer, public network::SocketServer {
+ public:
+ // -=- Constructors
+
+ // Create a server exporting the supplied desktop.
+ VNCServerST(const char* name_, SDesktop* desktop_,
+ SSecurityFactory* securityFactory_=0);
+ virtual ~VNCServerST();
+
+
+ // Methods overridden from SocketServer
+
+ // addSocket
+ // Causes the server to allocate an RFB-protocol management
+ // structure for the socket & initialise it.
+ virtual void addSocket(network::Socket* sock, bool outgoing=false);
+
+ // removeSocket
+ // Clean up any resources associated with the Socket
+ virtual void removeSocket(network::Socket* sock);
+
+ // processSocketEvent
+ // Read more RFB data from the Socket. If an error occurs during
+ // processing then shutdown() is called on the Socket, causing
+ // removeSocket() to be called by the caller at a later time.
+ virtual void processSocketEvent(network::Socket* sock);
+
+ // checkTimeouts
+ // Returns the number of milliseconds left until the next idle timeout
+ // expires. If any have already expired, the corresponding connections
+ // are closed. Zero is returned if there is no idle timeout.
+ virtual int checkTimeouts();
+
+
+ // Methods overridden from VNCServer
+
+ virtual void setPixelBuffer(PixelBuffer* pb);
+ virtual void setColourMapEntries(int firstColour=0, int nColours=0);
+ virtual void serverCutText(const char* str, int len);
+ virtual void add_changed(const Region &region);
+ virtual void add_copied(const Region &dest, const Point &delta);
+ virtual bool clientsReadyForUpdate();
+ virtual void tryUpdate();
+ virtual void setCursor(int width, int height, const Point& hotspot,
+ void* cursorData, void* mask);
+ virtual void setCursorPos(const Point& p);
+ virtual void setSSecurityFactory(SSecurityFactory* f) {securityFactory=f;}
+
+ virtual void bell();
+
+ // - Close all currently-connected clients, by calling
+ // their close() method with the supplied reason.
+ virtual void closeClients(const char* reason) {closeClients(reason, 0);}
+
+ // VNCServerST-only methods
+
+ // closeClients() closes all RFB sessions, except the specified one (if
+ // any), and logs the specified reason for closure.
+ void closeClients(const char* reason, network::Socket* sock);
+
+ // getSockets() gets a list of sockets. This can be used to generate an
+ // fd_set for calling select().
+
+ void getSockets(std::list<network::Socket*>* sockets);
+
+ // getSConnection() gets the SConnection for a particular Socket. If
+ // the Socket is not recognised then null is returned.
+
+ SConnection* getSConnection(network::Socket* sock);
+
+ // getDesktopSize() returns the size of the SDesktop exported by this
+ // server.
+ Point getDesktopSize() const {return desktop->getFbSize();}
+
+ // getName() returns the name of this VNC Server. NB: The value returned
+ // is the server's internal buffer which may change after any other methods
+ // are called - take a copy if necessary.
+ const char* getName() const {return name.buf;}
+
+ // setName() specifies the desktop name that the server should provide to
+ // clients
+ void setName(const char* name_) {name.replaceBuf(strDup(name_));}
+
+ // A QueryConnectionHandler, if supplied, is passed details of incoming
+ // connections to approve, reject, or query the user about.
+ //
+ // queryConnection() is called when a connection has been
+ // successfully authenticated. The sock and userName arguments identify
+ // the socket and the name of the authenticated user, if any. It should
+ // return ACCEPT if the connection should be accepted, REJECT if it should
+ // be rejected, or PENDING if a decision cannot yet be reached. If REJECT
+ // is returned, *reason can be set to a string describing the reason - this
+ // will be delete[]ed when it is finished with. If PENDING is returned,
+ // approveConnection() must be called some time later to accept or reject
+ // the connection.
+ enum queryResult { ACCEPT, REJECT, PENDING };
+ struct QueryConnectionHandler {
+ virtual ~QueryConnectionHandler() {}
+ virtual queryResult queryConnection(network::Socket* sock,
+ const char* userName,
+ char** reason) = 0;
+ };
+ void setQueryConnectionHandler(QueryConnectionHandler* qch) {
+ queryConnectionHandler = qch;
+ }
+
+ // queryConnection is called as described above, and either passes the
+ // request on to the registered handler, or accepts the connection if
+ // no handler has been specified.
+ virtual queryResult queryConnection(network::Socket* sock,
+ const char* userName,
+ char** reason) {
+ return queryConnectionHandler
+ ? queryConnectionHandler->queryConnection(sock, userName, reason)
+ : ACCEPT;
+ }
+
+ // approveConnection() is called by the active QueryConnectionHandler,
+ // some time after queryConnection() has returned with PENDING, to accept
+ // or reject the connection. The accept argument should be true for
+ // acceptance, or false for rejection, in which case a string reason may
+ // also be given.
+ void approveConnection(network::Socket* sock, bool accept,
+ const char* reason);
+
+ // setBlacklist() is called to replace the VNCServerST's internal
+ // Blacklist instance with another instance. This allows a single
+ // Blacklist to be shared by multiple VNCServerST instances.
+ void setBlacklist(Blacklist* bl) {blHosts = bl ? bl : &blacklist;}
+
+ // setEconomicTranslate() determines (for new connections) whether pixels
+ // should be translated for <=16bpp clients using a large lookup table
+ // (fast) or separate, smaller R, G and B tables (slower). If set to true,
+ // small tables are used, to save memory.
+ void setEconomicTranslate(bool et) { useEconomicTranslate = et; }
+
+ // setKeyRemapper() replaces the VNCServerST's default key remapper.
+ // NB: A null pointer is valid here.
+ void setKeyRemapper(KeyRemapper* kr) { keyRemapper = kr; }
+
+ void getConnInfo(ListConnInfo * listConn);
+ void setConnStatus(ListConnInfo* listConn);
+
+ bool getDisable() { return disableclients;};
+ void setDisable(bool disable) { disableclients = disable;};
+
+ void setFTManager(rfb::SFileTransferManager *pFTManager) { m_pFTManager = pFTManager; };
+
+ protected:
+
+ friend class VNCSConnectionST;
+
+ void startDesktop();
+
+ static LogWriter connectionsLog;
+ Blacklist blacklist;
+ Blacklist* blHosts;
+
+ SDesktop* desktop;
+ bool desktopStarted;
+ PixelBuffer* pb;
+
+ SFileTransferManager *m_pFTManager;
+
+ CharArray name;
+
+ std::list<VNCSConnectionST*> clients;
+ VNCSConnectionST* pointerClient;
+ std::list<network::Socket*> closingSockets;
+
+ ComparingUpdateTracker* comparer;
+
+ Point cursorPos;
+ Cursor cursor;
+ Point cursorTL() { return cursorPos.subtract(cursor.hotspot); }
+ Point renderedCursorTL;
+ ManagedPixelBuffer renderedCursor;
+ bool renderedCursorInvalid;
+
+ // - Check how many of the clients are authenticated.
+ int authClientCount();
+
+ bool needRenderedCursor();
+ void checkUpdate();
+
+ SSecurityFactory* securityFactory;
+ QueryConnectionHandler* queryConnectionHandler;
+ KeyRemapper* keyRemapper;
+ bool useEconomicTranslate;
+
+ time_t lastUserInputTime;
+ time_t lastDisconnectTime;
+ time_t lastConnectionTime;
+
+ bool disableclients;
+ };
+
+};
+
+#endif
+
diff --git a/common/rfb/ZRLEDecoder.cxx b/common/rfb/ZRLEDecoder.cxx
new file mode 100644
index 00000000..b7c69129
--- /dev/null
+++ b/common/rfb/ZRLEDecoder.cxx
@@ -0,0 +1,91 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#include <rfb/CMsgReader.h>
+#include <rfb/CMsgHandler.h>
+#include <rfb/ZRLEDecoder.h>
+
+using namespace rfb;
+
+#define EXTRA_ARGS CMsgHandler* handler
+#define FILL_RECT(r, p) handler->fillRect(r, p)
+#define IMAGE_RECT(r, p) handler->imageRect(r, p)
+#define BPP 8
+#include <rfb/zrleDecode.h>
+#undef BPP
+#define BPP 16
+#include <rfb/zrleDecode.h>
+#undef BPP
+#define BPP 32
+#include <rfb/zrleDecode.h>
+#define CPIXEL 24A
+#include <rfb/zrleDecode.h>
+#undef CPIXEL
+#define CPIXEL 24B
+#include <rfb/zrleDecode.h>
+#undef CPIXEL
+#undef BPP
+
+Decoder* ZRLEDecoder::create(CMsgReader* reader)
+{
+ return new ZRLEDecoder(reader);
+}
+
+ZRLEDecoder::ZRLEDecoder(CMsgReader* reader_) : reader(reader_)
+{
+}
+
+ZRLEDecoder::~ZRLEDecoder()
+{
+}
+
+void ZRLEDecoder::readRect(const Rect& r, CMsgHandler* handler)
+{
+ rdr::InStream* is = reader->getInStream();
+ rdr::U8* buf = reader->getImageBuf(64 * 64 * 4);
+ switch (reader->bpp()) {
+ case 8: zrleDecode8 (r, is, &zis, (rdr::U8*) buf, handler); break;
+ case 16: zrleDecode16(r, is, &zis, (rdr::U16*)buf, handler); break;
+ case 32:
+ {
+ const rfb::PixelFormat& pf = handler->cp.pf();
+ bool fitsInLS3Bytes = ((pf.redMax << pf.redShift) < (1<<24) &&
+ (pf.greenMax << pf.greenShift) < (1<<24) &&
+ (pf.blueMax << pf.blueShift) < (1<<24));
+
+ bool fitsInMS3Bytes = (pf.redShift > 7 &&
+ pf.greenShift > 7 &&
+ pf.blueShift > 7);
+
+ if ((fitsInLS3Bytes && !pf.bigEndian) ||
+ (fitsInMS3Bytes && pf.bigEndian))
+ {
+ zrleDecode24A(r, is, &zis, (rdr::U32*)buf, handler);
+ }
+ else if ((fitsInLS3Bytes && pf.bigEndian) ||
+ (fitsInMS3Bytes && !pf.bigEndian))
+ {
+ zrleDecode24B(r, is, &zis, (rdr::U32*)buf, handler);
+ }
+ else
+ {
+ zrleDecode32(r, is, &zis, (rdr::U32*)buf, handler);
+ }
+ break;
+ }
+ }
+}
diff --git a/common/rfb/ZRLEDecoder.h b/common/rfb/ZRLEDecoder.h
new file mode 100644
index 00000000..fe96c737
--- /dev/null
+++ b/common/rfb/ZRLEDecoder.h
@@ -0,0 +1,37 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#ifndef __RFB_ZRLEDECODER_H__
+#define __RFB_ZRLEDECODER_H__
+
+#include <rdr/ZlibInStream.h>
+#include <rfb/Decoder.h>
+
+namespace rfb {
+
+ class ZRLEDecoder : public Decoder {
+ public:
+ static Decoder* create(CMsgReader* reader);
+ virtual void readRect(const Rect& r, CMsgHandler* handler);
+ virtual ~ZRLEDecoder();
+ private:
+ ZRLEDecoder(CMsgReader* reader);
+ CMsgReader* reader;
+ rdr::ZlibInStream zis;
+ };
+}
+#endif
diff --git a/common/rfb/ZRLEEncoder.cxx b/common/rfb/ZRLEEncoder.cxx
new file mode 100644
index 00000000..d84c4cfb
--- /dev/null
+++ b/common/rfb/ZRLEEncoder.cxx
@@ -0,0 +1,122 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#include <rdr/OutStream.h>
+#include <rfb/Exception.h>
+#include <rfb/ImageGetter.h>
+#include <rfb/encodings.h>
+#include <rfb/ConnParams.h>
+#include <rfb/SMsgWriter.h>
+#include <rfb/ZRLEEncoder.h>
+#include <rfb/Configuration.h>
+
+using namespace rfb;
+
+rdr::MemOutStream* ZRLEEncoder::sharedMos = 0;
+int ZRLEEncoder::maxLen = 4097 * 1024; // enough for width 16384 32-bit pixels
+
+IntParameter zlibLevel("ZlibLevel","Zlib compression level",-1);
+
+#define EXTRA_ARGS ImageGetter* ig
+#define GET_IMAGE_INTO_BUF(r,buf) ig->getImage(buf, r);
+#define BPP 8
+#include <rfb/zrleEncode.h>
+#undef BPP
+#define BPP 16
+#include <rfb/zrleEncode.h>
+#undef BPP
+#define BPP 32
+#include <rfb/zrleEncode.h>
+#define CPIXEL 24A
+#include <rfb/zrleEncode.h>
+#undef CPIXEL
+#define CPIXEL 24B
+#include <rfb/zrleEncode.h>
+#undef CPIXEL
+#undef BPP
+
+Encoder* ZRLEEncoder::create(SMsgWriter* writer)
+{
+ return new ZRLEEncoder(writer);
+}
+
+ZRLEEncoder::ZRLEEncoder(SMsgWriter* writer_)
+ : writer(writer_), zos(0,0,zlibLevel)
+{
+ if (sharedMos)
+ mos = sharedMos;
+ else
+ mos = new rdr::MemOutStream(129*1024);
+}
+
+ZRLEEncoder::~ZRLEEncoder()
+{
+ if (!sharedMos)
+ delete mos;
+}
+
+bool ZRLEEncoder::writeRect(const Rect& r, ImageGetter* ig, Rect* actual)
+{
+ rdr::U8* imageBuf = writer->getImageBuf(64 * 64 * 4 + 4);
+ mos->clear();
+ bool wroteAll = true;
+ *actual = r;
+
+ switch (writer->bpp()) {
+ case 8:
+ wroteAll = zrleEncode8(r, mos, &zos, imageBuf, maxLen, actual, ig);
+ break;
+ case 16:
+ wroteAll = zrleEncode16(r, mos, &zos, imageBuf, maxLen, actual, ig);
+ break;
+ case 32:
+ {
+ const PixelFormat& pf = writer->getConnParams()->pf();
+
+ bool fitsInLS3Bytes = ((pf.redMax << pf.redShift) < (1<<24) &&
+ (pf.greenMax << pf.greenShift) < (1<<24) &&
+ (pf.blueMax << pf.blueShift) < (1<<24));
+
+ bool fitsInMS3Bytes = (pf.redShift > 7 &&
+ pf.greenShift > 7 &&
+ pf.blueShift > 7);
+
+ if ((fitsInLS3Bytes && !pf.bigEndian) ||
+ (fitsInMS3Bytes && pf.bigEndian))
+ {
+ wroteAll = zrleEncode24A(r, mos, &zos, imageBuf, maxLen, actual, ig);
+ }
+ else if ((fitsInLS3Bytes && pf.bigEndian) ||
+ (fitsInMS3Bytes && !pf.bigEndian))
+ {
+ wroteAll = zrleEncode24B(r, mos, &zos, imageBuf, maxLen, actual, ig);
+ }
+ else
+ {
+ wroteAll = zrleEncode32(r, mos, &zos, imageBuf, maxLen, actual, ig);
+ }
+ break;
+ }
+ }
+
+ writer->startRect(*actual, encodingZRLE);
+ rdr::OutStream* os = writer->getOutStream();
+ os->writeU32(mos->length());
+ os->writeBytes(mos->data(), mos->length());
+ writer->endRect();
+ return wroteAll;
+}
diff --git a/common/rfb/ZRLEEncoder.h b/common/rfb/ZRLEEncoder.h
new file mode 100644
index 00000000..7768917d
--- /dev/null
+++ b/common/rfb/ZRLEEncoder.h
@@ -0,0 +1,54 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#ifndef __RFB_ZRLEENCODER_H__
+#define __RFB_ZRLEENCODER_H__
+
+#include <rdr/MemOutStream.h>
+#include <rdr/ZlibOutStream.h>
+#include <rfb/Encoder.h>
+
+namespace rfb {
+
+ class ZRLEEncoder : public Encoder {
+ public:
+ static Encoder* create(SMsgWriter* writer);
+ virtual bool writeRect(const Rect& r, ImageGetter* ig, Rect* actual);
+ virtual ~ZRLEEncoder();
+
+ // setMaxLen() sets the maximum size in bytes of any ZRLE rectangle. This
+ // can be used to stop the MemOutStream from growing too large. The value
+ // must be large enough to allow for at least one row of ZRLE tiles. So
+ // for example for a screen width of 2048 32-bit pixels this is 2K*4*64 =
+ // 512Kbytes plus a bit of overhead (the overhead is about 1/16 of the
+ // width, in this example about 128 bytes).
+ static void setMaxLen(int m) { maxLen = m; }
+
+ // setSharedMos() sets a MemOutStream to be shared amongst all
+ // ZRLEEncoders. Should be called before any ZRLEEncoders are created.
+ static void setSharedMos(rdr::MemOutStream* mos_) { sharedMos = mos_; }
+
+ private:
+ ZRLEEncoder(SMsgWriter* writer);
+ SMsgWriter* writer;
+ rdr::ZlibOutStream zos;
+ rdr::MemOutStream* mos;
+ static rdr::MemOutStream* sharedMos;
+ static int maxLen;
+ };
+}
+#endif
diff --git a/common/rfb/d3des.c b/common/rfb/d3des.c
new file mode 100644
index 00000000..eaca5816
--- /dev/null
+++ b/common/rfb/d3des.c
@@ -0,0 +1,434 @@
+/*
+ * This is D3DES (V5.09) by Richard Outerbridge with the double and
+ * triple-length support removed for use in VNC. Also the bytebit[] array
+ * has been reversed so that the most significant bit in each byte of the
+ * key is ignored, not the least significant.
+ *
+ * These changes are:
+ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* D3DES (V5.09) -
+ *
+ * A portable, public domain, version of the Data Encryption Standard.
+ *
+ * Written with Symantec's THINK (Lightspeed) C by Richard Outerbridge.
+ * Thanks to: Dan Hoey for his excellent Initial and Inverse permutation
+ * code; Jim Gillogly & Phil Karn for the DES key schedule code; Dennis
+ * Ferguson, Eric Young and Dana How for comparing notes; and Ray Lau,
+ * for humouring me on.
+ *
+ * Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge.
+ * (GEnie : OUTER; CIS : [71755,204]) Graven Imagery, 1992.
+ */
+
+#include "d3des.h"
+
+static void scrunch(unsigned char *, unsigned long *);
+static void unscrun(unsigned long *, unsigned char *);
+static void desfunc(unsigned long *, unsigned long *);
+static void cookey(unsigned long *);
+
+static unsigned long KnL[32] = { 0L };
+
+static unsigned short bytebit[8] = {
+ 01, 02, 04, 010, 020, 040, 0100, 0200 };
+
+static unsigned long bigbyte[24] = {
+ 0x800000L, 0x400000L, 0x200000L, 0x100000L,
+ 0x80000L, 0x40000L, 0x20000L, 0x10000L,
+ 0x8000L, 0x4000L, 0x2000L, 0x1000L,
+ 0x800L, 0x400L, 0x200L, 0x100L,
+ 0x80L, 0x40L, 0x20L, 0x10L,
+ 0x8L, 0x4L, 0x2L, 0x1L };
+
+/* Use the key schedule specified in the Standard (ANSI X3.92-1981). */
+
+static unsigned char pc1[56] = {
+ 56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17,
+ 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35,
+ 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21,
+ 13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3 };
+
+static unsigned char totrot[16] = {
+ 1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28 };
+
+static unsigned char pc2[48] = {
+ 13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9,
+ 22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1,
+ 40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47,
+ 43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31 };
+
+void deskey(key, edf) /* Thanks to James Gillogly & Phil Karn! */
+unsigned char *key;
+int edf;
+{
+ register int i, j, l, m, n;
+ unsigned char pc1m[56], pcr[56];
+ unsigned long kn[32];
+
+ for ( j = 0; j < 56; j++ ) {
+ l = pc1[j];
+ m = l & 07;
+ pc1m[j] = (key[l >> 3] & bytebit[m]) ? 1 : 0;
+ }
+ for( i = 0; i < 16; i++ ) {
+ if( edf == DE1 ) m = (15 - i) << 1;
+ else m = i << 1;
+ n = m + 1;
+ kn[m] = kn[n] = 0L;
+ for( j = 0; j < 28; j++ ) {
+ l = j + totrot[i];
+ if( l < 28 ) pcr[j] = pc1m[l];
+ else pcr[j] = pc1m[l - 28];
+ }
+ for( j = 28; j < 56; j++ ) {
+ l = j + totrot[i];
+ if( l < 56 ) pcr[j] = pc1m[l];
+ else pcr[j] = pc1m[l - 28];
+ }
+ for( j = 0; j < 24; j++ ) {
+ if( pcr[pc2[j]] ) kn[m] |= bigbyte[j];
+ if( pcr[pc2[j+24]] ) kn[n] |= bigbyte[j];
+ }
+ }
+ cookey(kn);
+ return;
+ }
+
+static void cookey(raw1)
+register unsigned long *raw1;
+{
+ register unsigned long *cook, *raw0;
+ unsigned long dough[32];
+ register int i;
+
+ cook = dough;
+ for( i = 0; i < 16; i++, raw1++ ) {
+ raw0 = raw1++;
+ *cook = (*raw0 & 0x00fc0000L) << 6;
+ *cook |= (*raw0 & 0x00000fc0L) << 10;
+ *cook |= (*raw1 & 0x00fc0000L) >> 10;
+ *cook++ |= (*raw1 & 0x00000fc0L) >> 6;
+ *cook = (*raw0 & 0x0003f000L) << 12;
+ *cook |= (*raw0 & 0x0000003fL) << 16;
+ *cook |= (*raw1 & 0x0003f000L) >> 4;
+ *cook++ |= (*raw1 & 0x0000003fL);
+ }
+ usekey(dough);
+ return;
+ }
+
+void cpkey(into)
+register unsigned long *into;
+{
+ register unsigned long *from, *endp;
+
+ from = KnL, endp = &KnL[32];
+ while( from < endp ) *into++ = *from++;
+ return;
+ }
+
+void usekey(from)
+register unsigned long *from;
+{
+ register unsigned long *to, *endp;
+
+ to = KnL, endp = &KnL[32];
+ while( to < endp ) *to++ = *from++;
+ return;
+ }
+
+void des(inblock, outblock)
+unsigned char *inblock, *outblock;
+{
+ unsigned long work[2];
+
+ scrunch(inblock, work);
+ desfunc(work, KnL);
+ unscrun(work, outblock);
+ return;
+ }
+
+static void scrunch(outof, into)
+register unsigned char *outof;
+register unsigned long *into;
+{
+ *into = (*outof++ & 0xffL) << 24;
+ *into |= (*outof++ & 0xffL) << 16;
+ *into |= (*outof++ & 0xffL) << 8;
+ *into++ |= (*outof++ & 0xffL);
+ *into = (*outof++ & 0xffL) << 24;
+ *into |= (*outof++ & 0xffL) << 16;
+ *into |= (*outof++ & 0xffL) << 8;
+ *into |= (*outof & 0xffL);
+ return;
+ }
+
+static void unscrun(outof, into)
+register unsigned long *outof;
+register unsigned char *into;
+{
+ *into++ = (unsigned char)((*outof >> 24) & 0xffL);
+ *into++ = (unsigned char)((*outof >> 16) & 0xffL);
+ *into++ = (unsigned char)((*outof >> 8) & 0xffL);
+ *into++ = (unsigned char)(*outof++ & 0xffL);
+ *into++ = (unsigned char)((*outof >> 24) & 0xffL);
+ *into++ = (unsigned char)((*outof >> 16) & 0xffL);
+ *into++ = (unsigned char)((*outof >> 8) & 0xffL);
+ *into = (unsigned char)(*outof & 0xffL);
+ return;
+ }
+
+static unsigned long SP1[64] = {
+ 0x01010400L, 0x00000000L, 0x00010000L, 0x01010404L,
+ 0x01010004L, 0x00010404L, 0x00000004L, 0x00010000L,
+ 0x00000400L, 0x01010400L, 0x01010404L, 0x00000400L,
+ 0x01000404L, 0x01010004L, 0x01000000L, 0x00000004L,
+ 0x00000404L, 0x01000400L, 0x01000400L, 0x00010400L,
+ 0x00010400L, 0x01010000L, 0x01010000L, 0x01000404L,
+ 0x00010004L, 0x01000004L, 0x01000004L, 0x00010004L,
+ 0x00000000L, 0x00000404L, 0x00010404L, 0x01000000L,
+ 0x00010000L, 0x01010404L, 0x00000004L, 0x01010000L,
+ 0x01010400L, 0x01000000L, 0x01000000L, 0x00000400L,
+ 0x01010004L, 0x00010000L, 0x00010400L, 0x01000004L,
+ 0x00000400L, 0x00000004L, 0x01000404L, 0x00010404L,
+ 0x01010404L, 0x00010004L, 0x01010000L, 0x01000404L,
+ 0x01000004L, 0x00000404L, 0x00010404L, 0x01010400L,
+ 0x00000404L, 0x01000400L, 0x01000400L, 0x00000000L,
+ 0x00010004L, 0x00010400L, 0x00000000L, 0x01010004L };
+
+static unsigned long SP2[64] = {
+ 0x80108020L, 0x80008000L, 0x00008000L, 0x00108020L,
+ 0x00100000L, 0x00000020L, 0x80100020L, 0x80008020L,
+ 0x80000020L, 0x80108020L, 0x80108000L, 0x80000000L,
+ 0x80008000L, 0x00100000L, 0x00000020L, 0x80100020L,
+ 0x00108000L, 0x00100020L, 0x80008020L, 0x00000000L,
+ 0x80000000L, 0x00008000L, 0x00108020L, 0x80100000L,
+ 0x00100020L, 0x80000020L, 0x00000000L, 0x00108000L,
+ 0x00008020L, 0x80108000L, 0x80100000L, 0x00008020L,
+ 0x00000000L, 0x00108020L, 0x80100020L, 0x00100000L,
+ 0x80008020L, 0x80100000L, 0x80108000L, 0x00008000L,
+ 0x80100000L, 0x80008000L, 0x00000020L, 0x80108020L,
+ 0x00108020L, 0x00000020L, 0x00008000L, 0x80000000L,
+ 0x00008020L, 0x80108000L, 0x00100000L, 0x80000020L,
+ 0x00100020L, 0x80008020L, 0x80000020L, 0x00100020L,
+ 0x00108000L, 0x00000000L, 0x80008000L, 0x00008020L,
+ 0x80000000L, 0x80100020L, 0x80108020L, 0x00108000L };
+
+static unsigned long SP3[64] = {
+ 0x00000208L, 0x08020200L, 0x00000000L, 0x08020008L,
+ 0x08000200L, 0x00000000L, 0x00020208L, 0x08000200L,
+ 0x00020008L, 0x08000008L, 0x08000008L, 0x00020000L,
+ 0x08020208L, 0x00020008L, 0x08020000L, 0x00000208L,
+ 0x08000000L, 0x00000008L, 0x08020200L, 0x00000200L,
+ 0x00020200L, 0x08020000L, 0x08020008L, 0x00020208L,
+ 0x08000208L, 0x00020200L, 0x00020000L, 0x08000208L,
+ 0x00000008L, 0x08020208L, 0x00000200L, 0x08000000L,
+ 0x08020200L, 0x08000000L, 0x00020008L, 0x00000208L,
+ 0x00020000L, 0x08020200L, 0x08000200L, 0x00000000L,
+ 0x00000200L, 0x00020008L, 0x08020208L, 0x08000200L,
+ 0x08000008L, 0x00000200L, 0x00000000L, 0x08020008L,
+ 0x08000208L, 0x00020000L, 0x08000000L, 0x08020208L,
+ 0x00000008L, 0x00020208L, 0x00020200L, 0x08000008L,
+ 0x08020000L, 0x08000208L, 0x00000208L, 0x08020000L,
+ 0x00020208L, 0x00000008L, 0x08020008L, 0x00020200L };
+
+static unsigned long SP4[64] = {
+ 0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L,
+ 0x00802080L, 0x00800081L, 0x00800001L, 0x00002001L,
+ 0x00000000L, 0x00802000L, 0x00802000L, 0x00802081L,
+ 0x00000081L, 0x00000000L, 0x00800080L, 0x00800001L,
+ 0x00000001L, 0x00002000L, 0x00800000L, 0x00802001L,
+ 0x00000080L, 0x00800000L, 0x00002001L, 0x00002080L,
+ 0x00800081L, 0x00000001L, 0x00002080L, 0x00800080L,
+ 0x00002000L, 0x00802080L, 0x00802081L, 0x00000081L,
+ 0x00800080L, 0x00800001L, 0x00802000L, 0x00802081L,
+ 0x00000081L, 0x00000000L, 0x00000000L, 0x00802000L,
+ 0x00002080L, 0x00800080L, 0x00800081L, 0x00000001L,
+ 0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L,
+ 0x00802081L, 0x00000081L, 0x00000001L, 0x00002000L,
+ 0x00800001L, 0x00002001L, 0x00802080L, 0x00800081L,
+ 0x00002001L, 0x00002080L, 0x00800000L, 0x00802001L,
+ 0x00000080L, 0x00800000L, 0x00002000L, 0x00802080L };
+
+static unsigned long SP5[64] = {
+ 0x00000100L, 0x02080100L, 0x02080000L, 0x42000100L,
+ 0x00080000L, 0x00000100L, 0x40000000L, 0x02080000L,
+ 0x40080100L, 0x00080000L, 0x02000100L, 0x40080100L,
+ 0x42000100L, 0x42080000L, 0x00080100L, 0x40000000L,
+ 0x02000000L, 0x40080000L, 0x40080000L, 0x00000000L,
+ 0x40000100L, 0x42080100L, 0x42080100L, 0x02000100L,
+ 0x42080000L, 0x40000100L, 0x00000000L, 0x42000000L,
+ 0x02080100L, 0x02000000L, 0x42000000L, 0x00080100L,
+ 0x00080000L, 0x42000100L, 0x00000100L, 0x02000000L,
+ 0x40000000L, 0x02080000L, 0x42000100L, 0x40080100L,
+ 0x02000100L, 0x40000000L, 0x42080000L, 0x02080100L,
+ 0x40080100L, 0x00000100L, 0x02000000L, 0x42080000L,
+ 0x42080100L, 0x00080100L, 0x42000000L, 0x42080100L,
+ 0x02080000L, 0x00000000L, 0x40080000L, 0x42000000L,
+ 0x00080100L, 0x02000100L, 0x40000100L, 0x00080000L,
+ 0x00000000L, 0x40080000L, 0x02080100L, 0x40000100L };
+
+static unsigned long SP6[64] = {
+ 0x20000010L, 0x20400000L, 0x00004000L, 0x20404010L,
+ 0x20400000L, 0x00000010L, 0x20404010L, 0x00400000L,
+ 0x20004000L, 0x00404010L, 0x00400000L, 0x20000010L,
+ 0x00400010L, 0x20004000L, 0x20000000L, 0x00004010L,
+ 0x00000000L, 0x00400010L, 0x20004010L, 0x00004000L,
+ 0x00404000L, 0x20004010L, 0x00000010L, 0x20400010L,
+ 0x20400010L, 0x00000000L, 0x00404010L, 0x20404000L,
+ 0x00004010L, 0x00404000L, 0x20404000L, 0x20000000L,
+ 0x20004000L, 0x00000010L, 0x20400010L, 0x00404000L,
+ 0x20404010L, 0x00400000L, 0x00004010L, 0x20000010L,
+ 0x00400000L, 0x20004000L, 0x20000000L, 0x00004010L,
+ 0x20000010L, 0x20404010L, 0x00404000L, 0x20400000L,
+ 0x00404010L, 0x20404000L, 0x00000000L, 0x20400010L,
+ 0x00000010L, 0x00004000L, 0x20400000L, 0x00404010L,
+ 0x00004000L, 0x00400010L, 0x20004010L, 0x00000000L,
+ 0x20404000L, 0x20000000L, 0x00400010L, 0x20004010L };
+
+static unsigned long SP7[64] = {
+ 0x00200000L, 0x04200002L, 0x04000802L, 0x00000000L,
+ 0x00000800L, 0x04000802L, 0x00200802L, 0x04200800L,
+ 0x04200802L, 0x00200000L, 0x00000000L, 0x04000002L,
+ 0x00000002L, 0x04000000L, 0x04200002L, 0x00000802L,
+ 0x04000800L, 0x00200802L, 0x00200002L, 0x04000800L,
+ 0x04000002L, 0x04200000L, 0x04200800L, 0x00200002L,
+ 0x04200000L, 0x00000800L, 0x00000802L, 0x04200802L,
+ 0x00200800L, 0x00000002L, 0x04000000L, 0x00200800L,
+ 0x04000000L, 0x00200800L, 0x00200000L, 0x04000802L,
+ 0x04000802L, 0x04200002L, 0x04200002L, 0x00000002L,
+ 0x00200002L, 0x04000000L, 0x04000800L, 0x00200000L,
+ 0x04200800L, 0x00000802L, 0x00200802L, 0x04200800L,
+ 0x00000802L, 0x04000002L, 0x04200802L, 0x04200000L,
+ 0x00200800L, 0x00000000L, 0x00000002L, 0x04200802L,
+ 0x00000000L, 0x00200802L, 0x04200000L, 0x00000800L,
+ 0x04000002L, 0x04000800L, 0x00000800L, 0x00200002L };
+
+static unsigned long SP8[64] = {
+ 0x10001040L, 0x00001000L, 0x00040000L, 0x10041040L,
+ 0x10000000L, 0x10001040L, 0x00000040L, 0x10000000L,
+ 0x00040040L, 0x10040000L, 0x10041040L, 0x00041000L,
+ 0x10041000L, 0x00041040L, 0x00001000L, 0x00000040L,
+ 0x10040000L, 0x10000040L, 0x10001000L, 0x00001040L,
+ 0x00041000L, 0x00040040L, 0x10040040L, 0x10041000L,
+ 0x00001040L, 0x00000000L, 0x00000000L, 0x10040040L,
+ 0x10000040L, 0x10001000L, 0x00041040L, 0x00040000L,
+ 0x00041040L, 0x00040000L, 0x10041000L, 0x00001000L,
+ 0x00000040L, 0x10040040L, 0x00001000L, 0x00041040L,
+ 0x10001000L, 0x00000040L, 0x10000040L, 0x10040000L,
+ 0x10040040L, 0x10000000L, 0x00040000L, 0x10001040L,
+ 0x00000000L, 0x10041040L, 0x00040040L, 0x10000040L,
+ 0x10040000L, 0x10001000L, 0x10001040L, 0x00000000L,
+ 0x10041040L, 0x00041000L, 0x00041000L, 0x00001040L,
+ 0x00001040L, 0x00040040L, 0x10000000L, 0x10041000L };
+
+static void desfunc(block, keys)
+register unsigned long *block, *keys;
+{
+ register unsigned long fval, work, right, leftt;
+ register int round;
+
+ leftt = block[0];
+ right = block[1];
+ work = ((leftt >> 4) ^ right) & 0x0f0f0f0fL;
+ right ^= work;
+ leftt ^= (work << 4);
+ work = ((leftt >> 16) ^ right) & 0x0000ffffL;
+ right ^= work;
+ leftt ^= (work << 16);
+ work = ((right >> 2) ^ leftt) & 0x33333333L;
+ leftt ^= work;
+ right ^= (work << 2);
+ work = ((right >> 8) ^ leftt) & 0x00ff00ffL;
+ leftt ^= work;
+ right ^= (work << 8);
+ right = ((right << 1) | ((right >> 31) & 1L)) & 0xffffffffL;
+ work = (leftt ^ right) & 0xaaaaaaaaL;
+ leftt ^= work;
+ right ^= work;
+ leftt = ((leftt << 1) | ((leftt >> 31) & 1L)) & 0xffffffffL;
+
+ for( round = 0; round < 8; round++ ) {
+ work = (right << 28) | (right >> 4);
+ work ^= *keys++;
+ fval = SP7[ work & 0x3fL];
+ fval |= SP5[(work >> 8) & 0x3fL];
+ fval |= SP3[(work >> 16) & 0x3fL];
+ fval |= SP1[(work >> 24) & 0x3fL];
+ work = right ^ *keys++;
+ fval |= SP8[ work & 0x3fL];
+ fval |= SP6[(work >> 8) & 0x3fL];
+ fval |= SP4[(work >> 16) & 0x3fL];
+ fval |= SP2[(work >> 24) & 0x3fL];
+ leftt ^= fval;
+ work = (leftt << 28) | (leftt >> 4);
+ work ^= *keys++;
+ fval = SP7[ work & 0x3fL];
+ fval |= SP5[(work >> 8) & 0x3fL];
+ fval |= SP3[(work >> 16) & 0x3fL];
+ fval |= SP1[(work >> 24) & 0x3fL];
+ work = leftt ^ *keys++;
+ fval |= SP8[ work & 0x3fL];
+ fval |= SP6[(work >> 8) & 0x3fL];
+ fval |= SP4[(work >> 16) & 0x3fL];
+ fval |= SP2[(work >> 24) & 0x3fL];
+ right ^= fval;
+ }
+
+ right = (right << 31) | (right >> 1);
+ work = (leftt ^ right) & 0xaaaaaaaaL;
+ leftt ^= work;
+ right ^= work;
+ leftt = (leftt << 31) | (leftt >> 1);
+ work = ((leftt >> 8) ^ right) & 0x00ff00ffL;
+ right ^= work;
+ leftt ^= (work << 8);
+ work = ((leftt >> 2) ^ right) & 0x33333333L;
+ right ^= work;
+ leftt ^= (work << 2);
+ work = ((right >> 16) ^ leftt) & 0x0000ffffL;
+ leftt ^= work;
+ right ^= (work << 16);
+ work = ((right >> 4) ^ leftt) & 0x0f0f0f0fL;
+ leftt ^= work;
+ right ^= (work << 4);
+ *block++ = right;
+ *block = leftt;
+ return;
+ }
+
+/* Validation sets:
+ *
+ * Single-length key, single-length plaintext -
+ * Key : 0123 4567 89ab cdef
+ * Plain : 0123 4567 89ab cde7
+ * Cipher : c957 4425 6a5e d31d
+ *
+ * Double-length key, single-length plaintext -
+ * Key : 0123 4567 89ab cdef fedc ba98 7654 3210
+ * Plain : 0123 4567 89ab cde7
+ * Cipher : 7f1d 0a77 826b 8aff
+ *
+ * Double-length key, double-length plaintext -
+ * Key : 0123 4567 89ab cdef fedc ba98 7654 3210
+ * Plain : 0123 4567 89ab cdef 0123 4567 89ab cdff
+ * Cipher : 27a0 8440 406a df60 278f 47cf 42d6 15d7
+ *
+ * Triple-length key, single-length plaintext -
+ * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567
+ * Plain : 0123 4567 89ab cde7
+ * Cipher : de0b 7c06 ae5e 0ed5
+ *
+ * Triple-length key, double-length plaintext -
+ * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567
+ * Plain : 0123 4567 89ab cdef 0123 4567 89ab cdff
+ * Cipher : ad0d 1b30 ac17 cf07 0ed1 1c63 81e4 4de5
+ *
+ * d3des V5.0a rwo 9208.07 18:44 Graven Imagery
+ **********************************************************************/
diff --git a/common/rfb/d3des.h b/common/rfb/d3des.h
new file mode 100644
index 00000000..ea3da44c
--- /dev/null
+++ b/common/rfb/d3des.h
@@ -0,0 +1,51 @@
+/*
+ * This is D3DES (V5.09) by Richard Outerbridge with the double and
+ * triple-length support removed for use in VNC.
+ *
+ * These changes are:
+ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* d3des.h -
+ *
+ * Headers and defines for d3des.c
+ * Graven Imagery, 1992.
+ *
+ * Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge
+ * (GEnie : OUTER; CIS : [71755,204])
+ */
+
+#define EN0 0 /* MODE == encrypt */
+#define DE1 1 /* MODE == decrypt */
+
+extern void deskey(unsigned char *, int);
+/* hexkey[8] MODE
+ * Sets the internal key register according to the hexadecimal
+ * key contained in the 8 bytes of hexkey, according to the DES,
+ * for encryption or decryption according to MODE.
+ */
+
+extern void usekey(unsigned long *);
+/* cookedkey[32]
+ * Loads the internal key register with the data in cookedkey.
+ */
+
+extern void cpkey(unsigned long *);
+/* cookedkey[32]
+ * Copies the contents of the internal key register into the storage
+ * located at &cookedkey[0].
+ */
+
+extern void des(unsigned char *, unsigned char *);
+/* from[8] to[8]
+ * Encrypts/Decrypts (according to the key currently loaded in the
+ * internal key register) one block of eight bytes at address 'from'
+ * into the block at address 'to'. They can be the same.
+ */
+
+/* d3des.h V5.09 rwo 9208.04 15:06 Graven Imagery
+ ********************************************************************/
diff --git a/common/rfb/encodings.cxx b/common/rfb/encodings.cxx
new file mode 100644
index 00000000..6aa81c4f
--- /dev/null
+++ b/common/rfb/encodings.cxx
@@ -0,0 +1,49 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#include <string.h>
+#ifdef _WIN32
+#define strcasecmp _stricmp
+#endif
+#include <rfb/encodings.h>
+#include <rfb/util.h>
+
+int rfb::encodingNum(const char* name)
+{
+ if (strcasecmp(name, "raw") == 0) return encodingRaw;
+ if (strcasecmp(name, "copyRect") == 0) return encodingCopyRect;
+ if (strcasecmp(name, "RRE") == 0) return encodingRRE;
+ if (strcasecmp(name, "CoRRE") == 0) return encodingCoRRE;
+ if (strcasecmp(name, "hextile") == 0) return encodingHextile;
+ if (strcasecmp(name, "ZRLE") == 0) return encodingZRLE;
+ if (strcasecmp(name, "Tight") == 0) return encodingTight;
+ return -1;
+}
+
+const char* rfb::encodingName(unsigned int num)
+{
+ switch (num) {
+ case encodingRaw: return "raw";
+ case encodingCopyRect: return "copyRect";
+ case encodingRRE: return "RRE";
+ case encodingCoRRE: return "CoRRE";
+ case encodingHextile: return "hextile";
+ case encodingZRLE: return "ZRLE";
+ case encodingTight: return "Tight";
+ default: return "[unknown encoding]";
+ }
+}
diff --git a/common/rfb/encodings.h b/common/rfb/encodings.h
new file mode 100644
index 00000000..51f6f1ec
--- /dev/null
+++ b/common/rfb/encodings.h
@@ -0,0 +1,47 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#ifndef __RFB_ENCODINGS_H__
+#define __RFB_ENCODINGS_H__
+
+namespace rfb {
+
+ const unsigned int encodingRaw = 0;
+ const unsigned int encodingCopyRect = 1;
+ const unsigned int encodingRRE = 2;
+ const unsigned int encodingCoRRE = 4;
+ const unsigned int encodingHextile = 5;
+ const unsigned int encodingTight = 7;
+ const unsigned int encodingZRLE = 16;
+
+ const unsigned int encodingMax = 255;
+
+ const unsigned int pseudoEncodingXCursor = 0xffffff10;
+ const unsigned int pseudoEncodingCursor = 0xffffff11;
+ const unsigned int pseudoEncodingDesktopSize = 0xffffff21;
+
+ // TightVNC-specific
+ const unsigned int pseudoEncodingLastRect = 0xFFFFFF20;
+ const unsigned int pseudoEncodingQualityLevel0 = 0xFFFFFFE0;
+ const unsigned int pseudoEncodingQualityLevel9 = 0xFFFFFFE9;
+ const unsigned int pseudoEncodingCompressLevel0 = 0xFFFFFF00;
+ const unsigned int pseudoEncodingCompressLevel9 = 0xFFFFFF09;
+
+ int encodingNum(const char* name);
+ const char* encodingName(unsigned int num);
+}
+#endif
diff --git a/common/rfb/fttypes.h b/common/rfb/fttypes.h
new file mode 100644
index 00000000..4404508c
--- /dev/null
+++ b/common/rfb/fttypes.h
@@ -0,0 +1,92 @@
+/* Copyright (C) 2005 TightVNC Team. All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- fttypes.h
+
+#ifndef __RFB_FTTYPES_H__
+#define __RFB_FTTYPES_H__
+
+#include "stdio.h"
+#include "stdlib.h"
+#include "string.h"
+
+#define FT_FILENAME_SIZE 256
+
+#define FT_MAX_STATUS_STRINGS 255
+#define FT_MAX_LENGTH_STATUS_STRINGS 130
+
+#define FT_MAX_SENDING_SIZE 8192
+
+#define FT_NET_ATTR_DIR ((unsigned int)-1)
+
+#define FT_ATTR_UNKNOWN 0x00000000
+#define FT_ATTR_FILE 0x00000001
+#define FT_ATTR_DIR 0x00000002
+
+#define FT_ATTR_RESIZE_NEEDED 0x00040000
+#define FT_ATTR_FOLDER_EXISTS 0x00080000
+#define FT_ATTR_COPY_OVERWRITE 0x00100000
+#define FT_ATTR_FLR_UPLOAD_CHECK 0x00200000
+#define FT_ATTR_FLR_UPLOAD_ADD 0x00400000
+#define FT_ATTR_COPY_UPLOAD 0x00800000
+#define FT_ATTR_FLR_DOWNLOAD_CHECK 0x01000000
+#define FT_ATTR_FLR_DOWNLOAD_ADD 0x02000000
+#define FT_ATTR_COPY_DOWNLOAD 0x04000000
+#define FT_ATTR_DELETE_LOCAL 0x08000000
+#define FT_ATTR_DELETE_REMOTE 0x10000000
+#define FT_ATTR_RENAME_LOCAL 0x20000000
+#define FT_ATTR_RENAME_REMOTE 0x40000000
+
+#define FT_FLR_DEST_MAIN 101
+#define FT_FLR_DEST_BROWSE 102
+#define FT_FLR_DEST_DOWNLOAD 103
+#define FT_FLR_DEST_UPLOAD 104
+#define FT_FLR_DEST_DELETE 105
+#define FT_FLR_DEST_RENAME 106
+
+typedef struct tagSIZEDATAINFO
+{
+ unsigned int size;
+ unsigned int data;
+} SIZEDATAINFO;
+
+typedef struct tagSIZEDATAFLAGSINFO
+{
+ unsigned int size;
+ unsigned int data;
+ unsigned int flags;
+} SIZEDATAFLAGSINFO;
+
+typedef struct tagFILEINFO
+{
+ char name[FT_FILENAME_SIZE];
+ SIZEDATAFLAGSINFO info;
+} FILEINFO;
+
+typedef struct tagFILEINFOEX
+{
+ char locPath[FT_FILENAME_SIZE];
+ char locName[FT_FILENAME_SIZE];
+ char remPath[FT_FILENAME_SIZE];
+ char remName[FT_FILENAME_SIZE];
+ SIZEDATAFLAGSINFO info;
+} FILEINFOEX;
+
+#endif // __RFB_FTTYPES_H__
diff --git a/common/rfb/hextileConstants.h b/common/rfb/hextileConstants.h
new file mode 100644
index 00000000..b8713cb6
--- /dev/null
+++ b/common/rfb/hextileConstants.h
@@ -0,0 +1,27 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#ifndef __RFB_HEXTILECONSTANTS_H__
+#define __RFB_HEXTILECONSTANTS_H__
+namespace rfb {
+ const int hextileRaw = (1 << 0);
+ const int hextileBgSpecified = (1 << 1);
+ const int hextileFgSpecified = (1 << 2);
+ const int hextileAnySubrects = (1 << 3);
+ const int hextileSubrectsColoured = (1 << 4);
+}
+#endif
diff --git a/common/rfb/hextileDecode.h b/common/rfb/hextileDecode.h
new file mode 100644
index 00000000..77befc7d
--- /dev/null
+++ b/common/rfb/hextileDecode.h
@@ -0,0 +1,126 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+//
+// Hextile decoding function.
+//
+// This file is #included after having set the following macros:
+// BPP - 8, 16 or 32
+// EXTRA_ARGS - optional extra arguments
+// FILL_RECT - fill a rectangle with a single colour
+// IMAGE_RECT - draw a rectangle of pixel data from a buffer
+
+#include <rdr/InStream.h>
+#include <rfb/hextileConstants.h>
+
+namespace rfb {
+
+// CONCAT2E concatenates its arguments, expanding them if they are macros
+
+#ifndef CONCAT2E
+#define CONCAT2(a,b) a##b
+#define CONCAT2E(a,b) CONCAT2(a,b)
+#endif
+
+#define PIXEL_T rdr::CONCAT2E(U,BPP)
+#define READ_PIXEL CONCAT2E(readOpaque,BPP)
+#define HEXTILE_DECODE CONCAT2E(hextileDecode,BPP)
+
+void HEXTILE_DECODE (const Rect& r, rdr::InStream* is, PIXEL_T* buf
+#ifdef EXTRA_ARGS
+ , EXTRA_ARGS
+#endif
+ )
+{
+ Rect t;
+ PIXEL_T bg = 0;
+ PIXEL_T fg = 0;
+
+ for (t.tl.y = r.tl.y; t.tl.y < r.br.y; t.tl.y += 16) {
+
+ t.br.y = __rfbmin(r.br.y, t.tl.y + 16);
+
+ for (t.tl.x = r.tl.x; t.tl.x < r.br.x; t.tl.x += 16) {
+
+ t.br.x = __rfbmin(r.br.x, t.tl.x + 16);
+
+ int tileType = is->readU8();
+
+ if (tileType & hextileRaw) {
+ is->readBytes(buf, t.area() * (BPP/8));
+ IMAGE_RECT(t, buf);
+ continue;
+ }
+
+ if (tileType & hextileBgSpecified)
+ bg = is->READ_PIXEL();
+
+#ifdef FAVOUR_FILL_RECT
+ FILL_RECT(t, bg);
+#else
+ int len = t.area();
+ PIXEL_T* ptr = (PIXEL_T*)buf;
+ while (len-- > 0) *ptr++ = bg;
+#endif
+
+ if (tileType & hextileFgSpecified)
+ fg = is->READ_PIXEL();
+
+ if (tileType & hextileAnySubrects) {
+ int nSubrects = is->readU8();
+
+ for (int i = 0; i < nSubrects; i++) {
+
+ if (tileType & hextileSubrectsColoured)
+ fg = is->READ_PIXEL();
+
+ int xy = is->readU8();
+ int wh = is->readU8();
+
+#ifdef FAVOUR_FILL_RECT
+ Rect s;
+ s.tl.x = t.tl.x + ((xy >> 4) & 15);
+ s.tl.y = t.tl.y + (xy & 15);
+ s.br.x = s.tl.x + ((wh >> 4) & 15) + 1;
+ s.br.y = s.tl.y + (wh & 15) + 1;
+ FILL_RECT(s, fg);
+#else
+ int x = ((xy >> 4) & 15);
+ int y = (xy & 15);
+ int w = ((wh >> 4) & 15) + 1;
+ int h = (wh & 15) + 1;
+ PIXEL_T* ptr = (PIXEL_T*)buf + y * t.width() + x;
+ int rowAdd = t.width() - w;
+ while (h-- > 0) {
+ int len = w;
+ while (len-- > 0) *ptr++ = fg;
+ ptr += rowAdd;
+ }
+#endif
+ }
+ }
+#ifndef FAVOUR_FILL_RECT
+ IMAGE_RECT(t, buf);
+#endif
+ }
+ }
+}
+
+#undef PIXEL_T
+#undef READ_PIXEL
+#undef HEXTILE_DECODE
+}
diff --git a/common/rfb/hextileEncode.h b/common/rfb/hextileEncode.h
new file mode 100644
index 00000000..9f8bd558
--- /dev/null
+++ b/common/rfb/hextileEncode.h
@@ -0,0 +1,229 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ * Copyright (C) 2005 Constantin Kaplinsky. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+//
+// Hextile encoding function.
+//
+// This file is #included after having set the following macros:
+// BPP - 8, 16 or 32
+// EXTRA_ARGS - optional extra arguments
+// GET_IMAGE_INTO_BUF - gets a rectangle of pixel data into a buffer
+
+#include <rdr/OutStream.h>
+#include <rfb/hextileConstants.h>
+
+namespace rfb {
+
+// CONCAT2E concatenates its arguments, expanding them if they are macros
+
+#ifndef CONCAT2E
+#define CONCAT2(a,b) a##b
+#define CONCAT2E(a,b) CONCAT2(a,b)
+#endif
+
+#define PIXEL_T rdr::CONCAT2E(U,BPP)
+#define WRITE_PIXEL CONCAT2E(writeOpaque,BPP)
+#define HEXTILE_ENCODE CONCAT2E(hextileEncode,BPP)
+#define HEXTILE_ENCODE_TILE CONCAT2E(hextileEncodeTile,BPP)
+#define TEST_TILE_TYPE CONCAT2E(hextileTestTileType,BPP)
+
+int TEST_TILE_TYPE (PIXEL_T* data, int w, int h, PIXEL_T* bg, PIXEL_T* fg);
+int HEXTILE_ENCODE_TILE (PIXEL_T* data, int w, int h, int tileType,
+ rdr::U8* encoded, PIXEL_T bg);
+
+void HEXTILE_ENCODE(const Rect& r, rdr::OutStream* os
+#ifdef EXTRA_ARGS
+ , EXTRA_ARGS
+#endif
+ )
+{
+ Rect t;
+ PIXEL_T buf[256];
+ PIXEL_T oldBg = 0, oldFg = 0;
+ bool oldBgValid = false;
+ bool oldFgValid = false;
+ rdr::U8 encoded[256*(BPP/8)];
+
+ for (t.tl.y = r.tl.y; t.tl.y < r.br.y; t.tl.y += 16) {
+
+ t.br.y = __rfbmin(r.br.y, t.tl.y + 16);
+
+ for (t.tl.x = r.tl.x; t.tl.x < r.br.x; t.tl.x += 16) {
+
+ t.br.x = __rfbmin(r.br.x, t.tl.x + 16);
+
+ GET_IMAGE_INTO_BUF(t,buf);
+
+ PIXEL_T bg, fg;
+ int tileType = TEST_TILE_TYPE(buf, t.width(), t.height(), &bg, &fg);
+
+ if (!oldBgValid || oldBg != bg) {
+ tileType |= hextileBgSpecified;
+ oldBg = bg;
+ oldBgValid = true;
+ }
+
+ int encodedLen = 0;
+
+ if (tileType & hextileAnySubrects) {
+
+ if (tileType & hextileSubrectsColoured) {
+ oldFgValid = false;
+ } else {
+ if (!oldFgValid || oldFg != fg) {
+ tileType |= hextileFgSpecified;
+ oldFg = fg;
+ oldFgValid = true;
+ }
+ }
+
+ encodedLen = HEXTILE_ENCODE_TILE(buf, t.width(), t.height(), tileType,
+ encoded, bg);
+
+ if (encodedLen < 0) {
+ GET_IMAGE_INTO_BUF(t,buf);
+ os->writeU8(hextileRaw);
+ os->writeBytes(buf, t.width() * t.height() * (BPP/8));
+ oldBgValid = oldFgValid = false;
+ continue;
+ }
+ }
+
+ os->writeU8(tileType);
+ if (tileType & hextileBgSpecified) os->WRITE_PIXEL(bg);
+ if (tileType & hextileFgSpecified) os->WRITE_PIXEL(fg);
+ if (tileType & hextileAnySubrects) os->writeBytes(encoded, encodedLen);
+ }
+ }
+}
+
+
+int HEXTILE_ENCODE_TILE (PIXEL_T* data, int w, int h, int tileType,
+ rdr::U8* encoded, PIXEL_T bg)
+{
+ rdr::U8* nSubrectsPtr = encoded;
+ *nSubrectsPtr = 0;
+ encoded++;
+
+ for (int y = 0; y < h; y++)
+ {
+ int x = 0;
+ while (x < w) {
+ if (*data == bg) {
+ x++;
+ data++;
+ continue;
+ }
+
+ // Find horizontal subrect first
+ PIXEL_T* ptr = data+1;
+ PIXEL_T* eol = data+w-x;
+ while (ptr < eol && *ptr == *data) ptr++;
+ int sw = ptr - data;
+
+ ptr = data + w;
+ int sh = 1;
+ while (sh < h-y) {
+ eol = ptr + sw;
+ while (ptr < eol)
+ if (*ptr++ != *data) goto endOfSubrect;
+ ptr += w - sw;
+ sh++;
+ }
+ endOfSubrect:
+
+ (*nSubrectsPtr)++;
+
+ if (tileType & hextileSubrectsColoured) {
+ if (encoded - nSubrectsPtr + (BPP/8) > w*h*(BPP/8)) return -1;
+#if (BPP == 8)
+ *encoded++ = *data;
+#elif (BPP == 16)
+ *encoded++ = ((rdr::U8*)data)[0];
+ *encoded++ = ((rdr::U8*)data)[1];
+#elif (BPP == 32)
+ *encoded++ = ((rdr::U8*)data)[0];
+ *encoded++ = ((rdr::U8*)data)[1];
+ *encoded++ = ((rdr::U8*)data)[2];
+ *encoded++ = ((rdr::U8*)data)[3];
+#endif
+ }
+
+ if (encoded - nSubrectsPtr + 2 > w*h*(BPP/8)) return -1;
+ *encoded++ = (x << 4) | y;
+ *encoded++ = ((sw-1) << 4) | (sh-1);
+
+ ptr = data+w;
+ PIXEL_T* eor = data+w*sh;
+ while (ptr < eor) {
+ eol = ptr + sw;
+ while (ptr < eol) *ptr++ = bg;
+ ptr += w - sw;
+ }
+ x += sw;
+ data += sw;
+ }
+ }
+ return encoded - nSubrectsPtr;
+}
+
+
+int TEST_TILE_TYPE (PIXEL_T* data, int w, int h, PIXEL_T* bg, PIXEL_T* fg)
+{
+ PIXEL_T pix1 = *data;
+ PIXEL_T* end = data + w * h;
+
+ PIXEL_T* ptr = data + 1;
+ while (ptr < end && *ptr == pix1)
+ ptr++;
+
+ if (ptr == end) {
+ *bg = pix1;
+ return 0; // solid-color tile
+ }
+
+ int count1 = ptr - data;
+ int count2 = 1;
+ PIXEL_T pix2 = *ptr++;
+ int tileType = hextileAnySubrects;
+
+ for (; ptr < end; ptr++) {
+ if (*ptr == pix1) {
+ count1++;
+ } else if (*ptr == pix2) {
+ count2++;
+ } else {
+ tileType |= hextileSubrectsColoured;
+ break;
+ }
+ }
+
+ if (count1 >= count2) {
+ *bg = pix1; *fg = pix2;
+ } else {
+ *bg = pix2; *fg = pix1;
+ }
+ return tileType;
+}
+
+#undef PIXEL_T
+#undef WRITE_PIXEL
+#undef HEXTILE_ENCODE
+#undef HEXTILE_ENCODE_TILE
+#undef TEST_TILE_TYPE
+}
diff --git a/common/rfb/hextileEncodeBetter.h b/common/rfb/hextileEncodeBetter.h
new file mode 100644
index 00000000..2b6b160a
--- /dev/null
+++ b/common/rfb/hextileEncodeBetter.h
@@ -0,0 +1,352 @@
+/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
+ * Copyright (C) 2005 Constantin Kaplinsky. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+//
+// Hextile encoding function.
+//
+// This file is #included after having set the following macros:
+// BPP - 8, 16 or 32
+// EXTRA_ARGS - optional extra arguments
+// GET_IMAGE_INTO_BUF - gets a rectangle of pixel data into a buffer
+
+#include <rdr/OutStream.h>
+#include <rfb/hextileConstants.h>
+#include <rfb/TightPalette.h>
+
+#include <assert.h>
+
+namespace rfb {
+
+// CONCAT2E concatenates its arguments, expanding them if they are macros
+
+#ifndef CONCAT2E
+#define CONCAT2(a,b) a##b
+#define CONCAT2E(a,b) CONCAT2(a,b)
+#endif
+
+#define PIXEL_T rdr::CONCAT2E(U,BPP)
+#define WRITE_PIXEL CONCAT2E(writeOpaque,BPP)
+#define HEXTILE_TILE CONCAT2E(HextileTile,BPP)
+#define HEXTILE_ENCODE CONCAT2E(hextileEncodeBetter,BPP)
+
+//
+// This class analyzes a separate tile and encodes its subrectangles.
+//
+
+class HEXTILE_TILE {
+
+ public:
+
+ HEXTILE_TILE ();
+
+ //
+ // Initialize existing object instance with new tile data.
+ //
+ void newTile(const PIXEL_T *src, int w, int h);
+
+ //
+ // Flags can include: hextileRaw, hextileAnySubrects and
+ // hextileSubrectsColoured. Note that if hextileRaw is set, other
+ // flags make no sense. Also, hextileSubrectsColoured is meaningful
+ // only when hextileAnySubrects is set as well.
+ //
+ int getFlags() const { return m_flags; }
+
+ //
+ // Returns the size of encoded subrects data, including subrect count.
+ // The size is zero if flags do not include hextileAnySubrects.
+ //
+ int getSize() const { return m_size; }
+
+ //
+ // Return optimal background.
+ //
+ int getBackground() const { return m_background; }
+
+ //
+ // Return foreground if flags include hextileSubrectsColoured.
+ //
+ int getForeground() const { return m_foreground; }
+
+ //
+ // Encode subrects. This function may be called only if
+ // hextileAnySubrects bit is set in flags. The buffer size should be
+ // big enough to store at least the number of bytes returned by the
+ // getSize() method.
+ //
+ void encode(rdr::U8* dst) const;
+
+ protected:
+
+ //
+ // Analyze the tile pixels, fill in all the data fields.
+ //
+ void analyze();
+
+ const PIXEL_T *m_tile;
+ int m_width;
+ int m_height;
+
+ int m_size;
+ int m_flags;
+ PIXEL_T m_background;
+ PIXEL_T m_foreground;
+
+ int m_numSubrects;
+ rdr::U8 m_coords[256 * 2];
+ PIXEL_T m_colors[256];
+
+ private:
+
+ bool m_processed[16][16];
+ TightPalette m_pal;
+};
+
+HEXTILE_TILE::HEXTILE_TILE()
+ : m_tile(NULL), m_width(0), m_height(0),
+ m_size(0), m_flags(0), m_background(0), m_foreground(0),
+ m_numSubrects(0), m_pal(48 + 2 * BPP)
+{
+}
+
+void HEXTILE_TILE::newTile(const PIXEL_T *src, int w, int h)
+{
+ m_tile = src;
+ m_width = w;
+ m_height = h;
+
+ analyze();
+}
+
+void HEXTILE_TILE::analyze()
+{
+ assert(m_tile && m_width && m_height);
+
+ const PIXEL_T *ptr = m_tile;
+ const PIXEL_T *end = &m_tile[m_width * m_height];
+ PIXEL_T color = *ptr++;
+ while (ptr != end && *ptr == color)
+ ptr++;
+
+ // Handle solid tile
+ if (ptr == end) {
+ m_background = m_tile[0];
+ m_flags = 0;
+ m_size = 0;
+ return;
+ }
+
+ // Compute number of complete rows of the same color, at the top
+ int y = (ptr - m_tile) / m_width;
+
+ PIXEL_T *colorsPtr = m_colors;
+ rdr::U8 *coordsPtr = m_coords;
+ m_pal.reset();
+ m_numSubrects = 0;
+
+ // Have we found the first subrect already?
+ if (y > 0) {
+ *colorsPtr++ = color;
+ *coordsPtr++ = 0;
+ *coordsPtr++ = (rdr::U8)(((m_width - 1) << 4) | ((y - 1) & 0x0F));
+ m_pal.insert(color, 1);
+ m_numSubrects++;
+ }
+
+ memset(m_processed, 0, 16 * 16 * sizeof(bool));
+
+ int x, sx, sy, sw, sh, max_x;
+
+ for (; y < m_height; y++) {
+ for (x = 0; x < m_width; x++) {
+ // Skip pixels that were processed earlier
+ if (m_processed[y][x]) {
+ continue;
+ }
+ // Determine dimensions of the horizontal subrect
+ color = m_tile[y * m_width + x];
+ for (sx = x + 1; sx < m_width; sx++) {
+ if (m_tile[y * m_width + sx] != color)
+ break;
+ }
+ sw = sx - x;
+ max_x = sx;
+ for (sy = y + 1; sy < m_height; sy++) {
+ for (sx = x; sx < max_x; sx++) {
+ if (m_tile[sy * m_width + sx] != color)
+ goto done;
+ }
+ }
+ done:
+ sh = sy - y;
+
+ // Save properties of this subrect
+ *colorsPtr++ = color;
+ *coordsPtr++ = (rdr::U8)((x << 4) | (y & 0x0F));
+ *coordsPtr++ = (rdr::U8)(((sw - 1) << 4) | ((sh - 1) & 0x0F));
+
+ if (m_pal.insert(color, 1) == 0) {
+ // Handle palette overflow
+ m_flags = hextileRaw;
+ m_size = 0;
+ return;
+ }
+
+ m_numSubrects++;
+
+ // Mark pixels of this subrect as processed, below this row
+ for (sy = y + 1; sy < y + sh; sy++) {
+ for (sx = x; sx < x + sw; sx++)
+ m_processed[sy][sx] = true;
+ }
+
+ // Skip processed pixels of this row
+ x += (sw - 1);
+ }
+ }
+
+ // Save number of colors in this tile (should be no less than 2)
+ int numColors = m_pal.getNumColors();
+ assert(numColors >= 2);
+
+ m_background = (PIXEL_T)m_pal.getEntry(0);
+ m_flags = hextileAnySubrects;
+ int numSubrects = m_numSubrects - m_pal.getCount(0);
+
+ if (numColors == 2) {
+ // Monochrome tile
+ m_foreground = (PIXEL_T)m_pal.getEntry(1);
+ m_size = 1 + 2 * numSubrects;
+ } else {
+ // Colored tile
+ m_flags |= hextileSubrectsColoured;
+ m_size = 1 + (2 + (BPP/8)) * numSubrects;
+ }
+}
+
+void HEXTILE_TILE::encode(rdr::U8 *dst) const
+{
+ assert(m_numSubrects && (m_flags & hextileAnySubrects));
+
+ // Zero subrects counter
+ rdr::U8 *numSubrectsPtr = dst;
+ *dst++ = 0;
+
+ for (int i = 0; i < m_numSubrects; i++) {
+ if (m_colors[i] == m_background)
+ continue;
+
+ if (m_flags & hextileSubrectsColoured) {
+#if (BPP == 8)
+ *dst++ = m_colors[i];
+#elif (BPP == 16)
+ *dst++ = ((rdr::U8*)&m_colors[i])[0];
+ *dst++ = ((rdr::U8*)&m_colors[i])[1];
+#elif (BPP == 32)
+ *dst++ = ((rdr::U8*)&m_colors[i])[0];
+ *dst++ = ((rdr::U8*)&m_colors[i])[1];
+ *dst++ = ((rdr::U8*)&m_colors[i])[2];
+ *dst++ = ((rdr::U8*)&m_colors[i])[3];
+#endif
+ }
+ *dst++ = m_coords[i * 2];
+ *dst++ = m_coords[i * 2 + 1];
+
+ (*numSubrectsPtr)++;
+ }
+
+ assert(dst - numSubrectsPtr == m_size);
+}
+
+//
+// Main encoding function.
+//
+
+void HEXTILE_ENCODE(const Rect& r, rdr::OutStream* os
+#ifdef EXTRA_ARGS
+ , EXTRA_ARGS
+#endif
+ )
+{
+ Rect t;
+ PIXEL_T buf[256];
+ PIXEL_T oldBg = 0, oldFg = 0;
+ bool oldBgValid = false;
+ bool oldFgValid = false;
+ rdr::U8 encoded[256*(BPP/8)];
+
+ HEXTILE_TILE tile;
+
+ for (t.tl.y = r.tl.y; t.tl.y < r.br.y; t.tl.y += 16) {
+
+ t.br.y = __rfbmin(r.br.y, t.tl.y + 16);
+
+ for (t.tl.x = r.tl.x; t.tl.x < r.br.x; t.tl.x += 16) {
+
+ t.br.x = __rfbmin(r.br.x, t.tl.x + 16);
+
+ GET_IMAGE_INTO_BUF(t,buf);
+
+ tile.newTile(buf, t.width(), t.height());
+ int tileType = tile.getFlags();
+ int encodedLen = tile.getSize();
+
+ if ( (tileType & hextileRaw) != 0 ||
+ encodedLen >= t.width() * t.height() * (BPP/8)) {
+ os->writeU8(hextileRaw);
+ os->writeBytes(buf, t.width() * t.height() * (BPP/8));
+ oldBgValid = oldFgValid = false;
+ continue;
+ }
+
+ PIXEL_T bg = tile.getBackground();
+ PIXEL_T fg = 0;
+
+ if (!oldBgValid || oldBg != bg) {
+ tileType |= hextileBgSpecified;
+ oldBg = bg;
+ oldBgValid = true;
+ }
+
+ if (tileType & hextileAnySubrects) {
+ if (tileType & hextileSubrectsColoured) {
+ oldFgValid = false;
+ } else {
+ fg = tile.getForeground();
+ if (!oldFgValid || oldFg != fg) {
+ tileType |= hextileFgSpecified;
+ oldFg = fg;
+ oldFgValid = true;
+ }
+ }
+ tile.encode(encoded);
+ }
+
+ os->writeU8(tileType);
+ if (tileType & hextileBgSpecified) os->WRITE_PIXEL(bg);
+ if (tileType & hextileFgSpecified) os->WRITE_PIXEL(fg);
+ if (tileType & hextileAnySubrects) os->writeBytes(encoded, encodedLen);
+ }
+ }
+}
+
+#undef PIXEL_T
+#undef WRITE_PIXEL
+#undef HEXTILE_TILE
+#undef HEXTILE_ENCODE
+}
diff --git a/common/rfb/keysymdef.h b/common/rfb/keysymdef.h
new file mode 100644
index 00000000..979ebdd5
--- /dev/null
+++ b/common/rfb/keysymdef.h
@@ -0,0 +1,1595 @@
+/* $TOG: keysymdef.h /main/28 1998/05/22 16:18:01 kaleb $ */
+
+/***********************************************************
+Copyright 1987, 1994, 1998 The Open Group
+
+All Rights Reserved.
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from The Open Group.
+
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+#define XK_VoidSymbol 0xFFFFFF /* void symbol */
+
+#ifdef XK_MISCELLANY
+/*
+ * TTY Functions, cleverly chosen to map to ascii, for convenience of
+ * programming, but could have been arbitrary (at the cost of lookup
+ * tables in client code.
+ */
+
+#define XK_BackSpace 0xFF08 /* back space, back char */
+#define XK_Tab 0xFF09
+#define XK_Linefeed 0xFF0A /* Linefeed, LF */
+#define XK_Clear 0xFF0B
+#define XK_Return 0xFF0D /* Return, enter */
+#define XK_Pause 0xFF13 /* Pause, hold */
+#define XK_Scroll_Lock 0xFF14
+#define XK_Sys_Req 0xFF15
+#define XK_Escape 0xFF1B
+#define XK_Delete 0xFFFF /* Delete, rubout */
+
+
+
+/* International & multi-key character composition */
+
+#define XK_Multi_key 0xFF20 /* Multi-key character compose */
+#define XK_Codeinput 0xFF37
+#define XK_SingleCandidate 0xFF3C
+#define XK_MultipleCandidate 0xFF3D
+#define XK_PreviousCandidate 0xFF3E
+
+/* Japanese keyboard support */
+
+#define XK_Kanji 0xFF21 /* Kanji, Kanji convert */
+#define XK_Muhenkan 0xFF22 /* Cancel Conversion */
+#define XK_Henkan_Mode 0xFF23 /* Start/Stop Conversion */
+#define XK_Henkan 0xFF23 /* Alias for Henkan_Mode */
+#define XK_Romaji 0xFF24 /* to Romaji */
+#define XK_Hiragana 0xFF25 /* to Hiragana */
+#define XK_Katakana 0xFF26 /* to Katakana */
+#define XK_Hiragana_Katakana 0xFF27 /* Hiragana/Katakana toggle */
+#define XK_Zenkaku 0xFF28 /* to Zenkaku */
+#define XK_Hankaku 0xFF29 /* to Hankaku */
+#define XK_Zenkaku_Hankaku 0xFF2A /* Zenkaku/Hankaku toggle */
+#define XK_Touroku 0xFF2B /* Add to Dictionary */
+#define XK_Massyo 0xFF2C /* Delete from Dictionary */
+#define XK_Kana_Lock 0xFF2D /* Kana Lock */
+#define XK_Kana_Shift 0xFF2E /* Kana Shift */
+#define XK_Eisu_Shift 0xFF2F /* Alphanumeric Shift */
+#define XK_Eisu_toggle 0xFF30 /* Alphanumeric toggle */
+#define XK_Kanji_Bangou 0xFF37 /* Codeinput */
+#define XK_Zen_Koho 0xFF3D /* Multiple/All Candidate(s) */
+#define XK_Mae_Koho 0xFF3E /* Previous Candidate */
+
+/* 0xFF31 thru 0xFF3F are under XK_KOREAN */
+
+/* Cursor control & motion */
+
+#define XK_Home 0xFF50
+#define XK_Left 0xFF51 /* Move left, left arrow */
+#define XK_Up 0xFF52 /* Move up, up arrow */
+#define XK_Right 0xFF53 /* Move right, right arrow */
+#define XK_Down 0xFF54 /* Move down, down arrow */
+#define XK_Prior 0xFF55 /* Prior, previous */
+#define XK_Page_Up 0xFF55
+#define XK_Next 0xFF56 /* Next */
+#define XK_Page_Down 0xFF56
+#define XK_End 0xFF57 /* EOL */
+#define XK_Begin 0xFF58 /* BOL */
+
+
+/* Misc Functions */
+
+#define XK_Select 0xFF60 /* Select, mark */
+#define XK_Print 0xFF61
+#define XK_Execute 0xFF62 /* Execute, run, do */
+#define XK_Insert 0xFF63 /* Insert, insert here */
+#define XK_Undo 0xFF65 /* Undo, oops */
+#define XK_Redo 0xFF66 /* redo, again */
+#define XK_Menu 0xFF67
+#define XK_Find 0xFF68 /* Find, search */
+#define XK_Cancel 0xFF69 /* Cancel, stop, abort, exit */
+#define XK_Help 0xFF6A /* Help */
+#define XK_Break 0xFF6B
+#define XK_Mode_switch 0xFF7E /* Character set switch */
+#define XK_script_switch 0xFF7E /* Alias for mode_switch */
+#define XK_Num_Lock 0xFF7F
+
+/* Keypad Functions, keypad numbers cleverly chosen to map to ascii */
+
+#define XK_KP_Space 0xFF80 /* space */
+#define XK_KP_Tab 0xFF89
+#define XK_KP_Enter 0xFF8D /* enter */
+#define XK_KP_F1 0xFF91 /* PF1, KP_A, ... */
+#define XK_KP_F2 0xFF92
+#define XK_KP_F3 0xFF93
+#define XK_KP_F4 0xFF94
+#define XK_KP_Home 0xFF95
+#define XK_KP_Left 0xFF96
+#define XK_KP_Up 0xFF97
+#define XK_KP_Right 0xFF98
+#define XK_KP_Down 0xFF99
+#define XK_KP_Prior 0xFF9A
+#define XK_KP_Page_Up 0xFF9A
+#define XK_KP_Next 0xFF9B
+#define XK_KP_Page_Down 0xFF9B
+#define XK_KP_End 0xFF9C
+#define XK_KP_Begin 0xFF9D
+#define XK_KP_Insert 0xFF9E
+#define XK_KP_Delete 0xFF9F
+#define XK_KP_Equal 0xFFBD /* equals */
+#define XK_KP_Multiply 0xFFAA
+#define XK_KP_Add 0xFFAB
+#define XK_KP_Separator 0xFFAC /* separator, often comma */
+#define XK_KP_Subtract 0xFFAD
+#define XK_KP_Decimal 0xFFAE
+#define XK_KP_Divide 0xFFAF
+
+#define XK_KP_0 0xFFB0
+#define XK_KP_1 0xFFB1
+#define XK_KP_2 0xFFB2
+#define XK_KP_3 0xFFB3
+#define XK_KP_4 0xFFB4
+#define XK_KP_5 0xFFB5
+#define XK_KP_6 0xFFB6
+#define XK_KP_7 0xFFB7
+#define XK_KP_8 0xFFB8
+#define XK_KP_9 0xFFB9
+
+
+
+/*
+ * Auxilliary Functions; note the duplicate definitions for left and right
+ * function keys; Sun keyboards and a few other manufactures have such
+ * function key groups on the left and/or right sides of the keyboard.
+ * We've not found a keyboard with more than 35 function keys total.
+ */
+
+#define XK_F1 0xFFBE
+#define XK_F2 0xFFBF
+#define XK_F3 0xFFC0
+#define XK_F4 0xFFC1
+#define XK_F5 0xFFC2
+#define XK_F6 0xFFC3
+#define XK_F7 0xFFC4
+#define XK_F8 0xFFC5
+#define XK_F9 0xFFC6
+#define XK_F10 0xFFC7
+#define XK_F11 0xFFC8
+#define XK_L1 0xFFC8
+#define XK_F12 0xFFC9
+#define XK_L2 0xFFC9
+#define XK_F13 0xFFCA
+#define XK_L3 0xFFCA
+#define XK_F14 0xFFCB
+#define XK_L4 0xFFCB
+#define XK_F15 0xFFCC
+#define XK_L5 0xFFCC
+#define XK_F16 0xFFCD
+#define XK_L6 0xFFCD
+#define XK_F17 0xFFCE
+#define XK_L7 0xFFCE
+#define XK_F18 0xFFCF
+#define XK_L8 0xFFCF
+#define XK_F19 0xFFD0
+#define XK_L9 0xFFD0
+#define XK_F20 0xFFD1
+#define XK_L10 0xFFD1
+#define XK_F21 0xFFD2
+#define XK_R1 0xFFD2
+#define XK_F22 0xFFD3
+#define XK_R2 0xFFD3
+#define XK_F23 0xFFD4
+#define XK_R3 0xFFD4
+#define XK_F24 0xFFD5
+#define XK_R4 0xFFD5
+#define XK_F25 0xFFD6
+#define XK_R5 0xFFD6
+#define XK_F26 0xFFD7
+#define XK_R6 0xFFD7
+#define XK_F27 0xFFD8
+#define XK_R7 0xFFD8
+#define XK_F28 0xFFD9
+#define XK_R8 0xFFD9
+#define XK_F29 0xFFDA
+#define XK_R9 0xFFDA
+#define XK_F30 0xFFDB
+#define XK_R10 0xFFDB
+#define XK_F31 0xFFDC
+#define XK_R11 0xFFDC
+#define XK_F32 0xFFDD
+#define XK_R12 0xFFDD
+#define XK_F33 0xFFDE
+#define XK_R13 0xFFDE
+#define XK_F34 0xFFDF
+#define XK_R14 0xFFDF
+#define XK_F35 0xFFE0
+#define XK_R15 0xFFE0
+
+/* Modifiers */
+
+#define XK_Shift_L 0xFFE1 /* Left shift */
+#define XK_Shift_R 0xFFE2 /* Right shift */
+#define XK_Control_L 0xFFE3 /* Left control */
+#define XK_Control_R 0xFFE4 /* Right control */
+#define XK_Caps_Lock 0xFFE5 /* Caps lock */
+#define XK_Shift_Lock 0xFFE6 /* Shift lock */
+
+#define XK_Meta_L 0xFFE7 /* Left meta */
+#define XK_Meta_R 0xFFE8 /* Right meta */
+#define XK_Alt_L 0xFFE9 /* Left alt */
+#define XK_Alt_R 0xFFEA /* Right alt */
+#define XK_Super_L 0xFFEB /* Left super */
+#define XK_Super_R 0xFFEC /* Right super */
+#define XK_Hyper_L 0xFFED /* Left hyper */
+#define XK_Hyper_R 0xFFEE /* Right hyper */
+#endif /* XK_MISCELLANY */
+
+/*
+ * ISO 9995 Function and Modifier Keys
+ * Byte 3 = 0xFE
+ */
+
+#ifdef XK_XKB_KEYS
+#define XK_ISO_Lock 0xFE01
+#define XK_ISO_Level2_Latch 0xFE02
+#define XK_ISO_Level3_Shift 0xFE03
+#define XK_ISO_Level3_Latch 0xFE04
+#define XK_ISO_Level3_Lock 0xFE05
+#define XK_ISO_Group_Shift 0xFF7E /* Alias for mode_switch */
+#define XK_ISO_Group_Latch 0xFE06
+#define XK_ISO_Group_Lock 0xFE07
+#define XK_ISO_Next_Group 0xFE08
+#define XK_ISO_Next_Group_Lock 0xFE09
+#define XK_ISO_Prev_Group 0xFE0A
+#define XK_ISO_Prev_Group_Lock 0xFE0B
+#define XK_ISO_First_Group 0xFE0C
+#define XK_ISO_First_Group_Lock 0xFE0D
+#define XK_ISO_Last_Group 0xFE0E
+#define XK_ISO_Last_Group_Lock 0xFE0F
+
+#define XK_ISO_Left_Tab 0xFE20
+#define XK_ISO_Move_Line_Up 0xFE21
+#define XK_ISO_Move_Line_Down 0xFE22
+#define XK_ISO_Partial_Line_Up 0xFE23
+#define XK_ISO_Partial_Line_Down 0xFE24
+#define XK_ISO_Partial_Space_Left 0xFE25
+#define XK_ISO_Partial_Space_Right 0xFE26
+#define XK_ISO_Set_Margin_Left 0xFE27
+#define XK_ISO_Set_Margin_Right 0xFE28
+#define XK_ISO_Release_Margin_Left 0xFE29
+#define XK_ISO_Release_Margin_Right 0xFE2A
+#define XK_ISO_Release_Both_Margins 0xFE2B
+#define XK_ISO_Fast_Cursor_Left 0xFE2C
+#define XK_ISO_Fast_Cursor_Right 0xFE2D
+#define XK_ISO_Fast_Cursor_Up 0xFE2E
+#define XK_ISO_Fast_Cursor_Down 0xFE2F
+#define XK_ISO_Continuous_Underline 0xFE30
+#define XK_ISO_Discontinuous_Underline 0xFE31
+#define XK_ISO_Emphasize 0xFE32
+#define XK_ISO_Center_Object 0xFE33
+#define XK_ISO_Enter 0xFE34
+
+#define XK_dead_grave 0xFE50
+#define XK_dead_acute 0xFE51
+#define XK_dead_circumflex 0xFE52
+#define XK_dead_tilde 0xFE53
+#define XK_dead_macron 0xFE54
+#define XK_dead_breve 0xFE55
+#define XK_dead_abovedot 0xFE56
+#define XK_dead_diaeresis 0xFE57
+#define XK_dead_abovering 0xFE58
+#define XK_dead_doubleacute 0xFE59
+#define XK_dead_caron 0xFE5A
+#define XK_dead_cedilla 0xFE5B
+#define XK_dead_ogonek 0xFE5C
+#define XK_dead_iota 0xFE5D
+#define XK_dead_voiced_sound 0xFE5E
+#define XK_dead_semivoiced_sound 0xFE5F
+#define XK_dead_belowdot 0xFE60
+
+#define XK_First_Virtual_Screen 0xFED0
+#define XK_Prev_Virtual_Screen 0xFED1
+#define XK_Next_Virtual_Screen 0xFED2
+#define XK_Last_Virtual_Screen 0xFED4
+#define XK_Terminate_Server 0xFED5
+
+#define XK_AccessX_Enable 0xFE70
+#define XK_AccessX_Feedback_Enable 0xFE71
+#define XK_RepeatKeys_Enable 0xFE72
+#define XK_SlowKeys_Enable 0xFE73
+#define XK_BounceKeys_Enable 0xFE74
+#define XK_StickyKeys_Enable 0xFE75
+#define XK_MouseKeys_Enable 0xFE76
+#define XK_MouseKeys_Accel_Enable 0xFE77
+#define XK_Overlay1_Enable 0xFE78
+#define XK_Overlay2_Enable 0xFE79
+#define XK_AudibleBell_Enable 0xFE7A
+
+#define XK_Pointer_Left 0xFEE0
+#define XK_Pointer_Right 0xFEE1
+#define XK_Pointer_Up 0xFEE2
+#define XK_Pointer_Down 0xFEE3
+#define XK_Pointer_UpLeft 0xFEE4
+#define XK_Pointer_UpRight 0xFEE5
+#define XK_Pointer_DownLeft 0xFEE6
+#define XK_Pointer_DownRight 0xFEE7
+#define XK_Pointer_Button_Dflt 0xFEE8
+#define XK_Pointer_Button1 0xFEE9
+#define XK_Pointer_Button2 0xFEEA
+#define XK_Pointer_Button3 0xFEEB
+#define XK_Pointer_Button4 0xFEEC
+#define XK_Pointer_Button5 0xFEED
+#define XK_Pointer_DblClick_Dflt 0xFEEE
+#define XK_Pointer_DblClick1 0xFEEF
+#define XK_Pointer_DblClick2 0xFEF0
+#define XK_Pointer_DblClick3 0xFEF1
+#define XK_Pointer_DblClick4 0xFEF2
+#define XK_Pointer_DblClick5 0xFEF3
+#define XK_Pointer_Drag_Dflt 0xFEF4
+#define XK_Pointer_Drag1 0xFEF5
+#define XK_Pointer_Drag2 0xFEF6
+#define XK_Pointer_Drag3 0xFEF7
+#define XK_Pointer_Drag4 0xFEF8
+#define XK_Pointer_Drag5 0xFEFD
+
+#define XK_Pointer_EnableKeys 0xFEF9
+#define XK_Pointer_Accelerate 0xFEFA
+#define XK_Pointer_DfltBtnNext 0xFEFB
+#define XK_Pointer_DfltBtnPrev 0xFEFC
+
+#endif
+
+/*
+ * 3270 Terminal Keys
+ * Byte 3 = 0xFD
+ */
+
+#ifdef XK_3270
+#define XK_3270_Duplicate 0xFD01
+#define XK_3270_FieldMark 0xFD02
+#define XK_3270_Right2 0xFD03
+#define XK_3270_Left2 0xFD04
+#define XK_3270_BackTab 0xFD05
+#define XK_3270_EraseEOF 0xFD06
+#define XK_3270_EraseInput 0xFD07
+#define XK_3270_Reset 0xFD08
+#define XK_3270_Quit 0xFD09
+#define XK_3270_PA1 0xFD0A
+#define XK_3270_PA2 0xFD0B
+#define XK_3270_PA3 0xFD0C
+#define XK_3270_Test 0xFD0D
+#define XK_3270_Attn 0xFD0E
+#define XK_3270_CursorBlink 0xFD0F
+#define XK_3270_AltCursor 0xFD10
+#define XK_3270_KeyClick 0xFD11
+#define XK_3270_Jump 0xFD12
+#define XK_3270_Ident 0xFD13
+#define XK_3270_Rule 0xFD14
+#define XK_3270_Copy 0xFD15
+#define XK_3270_Play 0xFD16
+#define XK_3270_Setup 0xFD17
+#define XK_3270_Record 0xFD18
+#define XK_3270_ChangeScreen 0xFD19
+#define XK_3270_DeleteWord 0xFD1A
+#define XK_3270_ExSelect 0xFD1B
+#define XK_3270_CursorSelect 0xFD1C
+#define XK_3270_PrintScreen 0xFD1D
+#define XK_3270_Enter 0xFD1E
+#endif
+
+/*
+ * Latin 1
+ * Byte 3 = 0
+ */
+#ifdef XK_LATIN1
+#define XK_space 0x020
+#define XK_exclam 0x021
+#define XK_quotedbl 0x022
+#define XK_numbersign 0x023
+#define XK_dollar 0x024
+#define XK_percent 0x025
+#define XK_ampersand 0x026
+#define XK_apostrophe 0x027
+#define XK_quoteright 0x027 /* deprecated */
+#define XK_parenleft 0x028
+#define XK_parenright 0x029
+#define XK_asterisk 0x02a
+#define XK_plus 0x02b
+#define XK_comma 0x02c
+#define XK_minus 0x02d
+#define XK_period 0x02e
+#define XK_slash 0x02f
+#define XK_0 0x030
+#define XK_1 0x031
+#define XK_2 0x032
+#define XK_3 0x033
+#define XK_4 0x034
+#define XK_5 0x035
+#define XK_6 0x036
+#define XK_7 0x037
+#define XK_8 0x038
+#define XK_9 0x039
+#define XK_colon 0x03a
+#define XK_semicolon 0x03b
+#define XK_less 0x03c
+#define XK_equal 0x03d
+#define XK_greater 0x03e
+#define XK_question 0x03f
+#define XK_at 0x040
+#define XK_A 0x041
+#define XK_B 0x042
+#define XK_C 0x043
+#define XK_D 0x044
+#define XK_E 0x045
+#define XK_F 0x046
+#define XK_G 0x047
+#define XK_H 0x048
+#define XK_I 0x049
+#define XK_J 0x04a
+#define XK_K 0x04b
+#define XK_L 0x04c
+#define XK_M 0x04d
+#define XK_N 0x04e
+#define XK_O 0x04f
+#define XK_P 0x050
+#define XK_Q 0x051
+#define XK_R 0x052
+#define XK_S 0x053
+#define XK_T 0x054
+#define XK_U 0x055
+#define XK_V 0x056
+#define XK_W 0x057
+#define XK_X 0x058
+#define XK_Y 0x059
+#define XK_Z 0x05a
+#define XK_bracketleft 0x05b
+#define XK_backslash 0x05c
+#define XK_bracketright 0x05d
+#define XK_asciicircum 0x05e
+#define XK_underscore 0x05f
+#define XK_grave 0x060
+#define XK_quoteleft 0x060 /* deprecated */
+#define XK_a 0x061
+#define XK_b 0x062
+#define XK_c 0x063
+#define XK_d 0x064
+#define XK_e 0x065
+#define XK_f 0x066
+#define XK_g 0x067
+#define XK_h 0x068
+#define XK_i 0x069
+#define XK_j 0x06a
+#define XK_k 0x06b
+#define XK_l 0x06c
+#define XK_m 0x06d
+#define XK_n 0x06e
+#define XK_o 0x06f
+#define XK_p 0x070
+#define XK_q 0x071
+#define XK_r 0x072
+#define XK_s 0x073
+#define XK_t 0x074
+#define XK_u 0x075
+#define XK_v 0x076
+#define XK_w 0x077
+#define XK_x 0x078
+#define XK_y 0x079
+#define XK_z 0x07a
+#define XK_braceleft 0x07b
+#define XK_bar 0x07c
+#define XK_braceright 0x07d
+#define XK_asciitilde 0x07e
+
+#define XK_nobreakspace 0x0a0
+#define XK_exclamdown 0x0a1
+#define XK_cent 0x0a2
+#define XK_sterling 0x0a3
+#define XK_currency 0x0a4
+#define XK_yen 0x0a5
+#define XK_brokenbar 0x0a6
+#define XK_section 0x0a7
+#define XK_diaeresis 0x0a8
+#define XK_copyright 0x0a9
+#define XK_ordfeminine 0x0aa
+#define XK_guillemotleft 0x0ab /* left angle quotation mark */
+#define XK_notsign 0x0ac
+#define XK_hyphen 0x0ad
+#define XK_registered 0x0ae
+#define XK_macron 0x0af
+#define XK_degree 0x0b0
+#define XK_plusminus 0x0b1
+#define XK_twosuperior 0x0b2
+#define XK_threesuperior 0x0b3
+#define XK_acute 0x0b4
+#define XK_mu 0x0b5
+#define XK_paragraph 0x0b6
+#define XK_periodcentered 0x0b7
+#define XK_cedilla 0x0b8
+#define XK_onesuperior 0x0b9
+#define XK_masculine 0x0ba
+#define XK_guillemotright 0x0bb /* right angle quotation mark */
+#define XK_onequarter 0x0bc
+#define XK_onehalf 0x0bd
+#define XK_threequarters 0x0be
+#define XK_questiondown 0x0bf
+#define XK_Agrave 0x0c0
+#define XK_Aacute 0x0c1
+#define XK_Acircumflex 0x0c2
+#define XK_Atilde 0x0c3
+#define XK_Adiaeresis 0x0c4
+#define XK_Aring 0x0c5
+#define XK_AE 0x0c6
+#define XK_Ccedilla 0x0c7
+#define XK_Egrave 0x0c8
+#define XK_Eacute 0x0c9
+#define XK_Ecircumflex 0x0ca
+#define XK_Ediaeresis 0x0cb
+#define XK_Igrave 0x0cc
+#define XK_Iacute 0x0cd
+#define XK_Icircumflex 0x0ce
+#define XK_Idiaeresis 0x0cf
+#define XK_ETH 0x0d0
+#define XK_Eth 0x0d0 /* deprecated */
+#define XK_Ntilde 0x0d1
+#define XK_Ograve 0x0d2
+#define XK_Oacute 0x0d3
+#define XK_Ocircumflex 0x0d4
+#define XK_Otilde 0x0d5
+#define XK_Odiaeresis 0x0d6
+#define XK_multiply 0x0d7
+#define XK_Ooblique 0x0d8
+#define XK_Ugrave 0x0d9
+#define XK_Uacute 0x0da
+#define XK_Ucircumflex 0x0db
+#define XK_Udiaeresis 0x0dc
+#define XK_Yacute 0x0dd
+#define XK_THORN 0x0de
+#define XK_Thorn 0x0de /* deprecated */
+#define XK_ssharp 0x0df
+#define XK_agrave 0x0e0
+#define XK_aacute 0x0e1
+#define XK_acircumflex 0x0e2
+#define XK_atilde 0x0e3
+#define XK_adiaeresis 0x0e4
+#define XK_aring 0x0e5
+#define XK_ae 0x0e6
+#define XK_ccedilla 0x0e7
+#define XK_egrave 0x0e8
+#define XK_eacute 0x0e9
+#define XK_ecircumflex 0x0ea
+#define XK_ediaeresis 0x0eb
+#define XK_igrave 0x0ec
+#define XK_iacute 0x0ed
+#define XK_icircumflex 0x0ee
+#define XK_idiaeresis 0x0ef
+#define XK_eth 0x0f0
+#define XK_ntilde 0x0f1
+#define XK_ograve 0x0f2
+#define XK_oacute 0x0f3
+#define XK_ocircumflex 0x0f4
+#define XK_otilde 0x0f5
+#define XK_odiaeresis 0x0f6
+#define XK_division 0x0f7
+#define XK_oslash 0x0f8
+#define XK_ugrave 0x0f9
+#define XK_uacute 0x0fa
+#define XK_ucircumflex 0x0fb
+#define XK_udiaeresis 0x0fc
+#define XK_yacute 0x0fd
+#define XK_thorn 0x0fe
+#define XK_ydiaeresis 0x0ff
+#endif /* XK_LATIN1 */
+
+/*
+ * Latin 2
+ * Byte 3 = 1
+ */
+
+#ifdef XK_LATIN2
+#define XK_Aogonek 0x1a1
+#define XK_breve 0x1a2
+#define XK_Lstroke 0x1a3
+#define XK_Lcaron 0x1a5
+#define XK_Sacute 0x1a6
+#define XK_Scaron 0x1a9
+#define XK_Scedilla 0x1aa
+#define XK_Tcaron 0x1ab
+#define XK_Zacute 0x1ac
+#define XK_Zcaron 0x1ae
+#define XK_Zabovedot 0x1af
+#define XK_aogonek 0x1b1
+#define XK_ogonek 0x1b2
+#define XK_lstroke 0x1b3
+#define XK_lcaron 0x1b5
+#define XK_sacute 0x1b6
+#define XK_caron 0x1b7
+#define XK_scaron 0x1b9
+#define XK_scedilla 0x1ba
+#define XK_tcaron 0x1bb
+#define XK_zacute 0x1bc
+#define XK_doubleacute 0x1bd
+#define XK_zcaron 0x1be
+#define XK_zabovedot 0x1bf
+#define XK_Racute 0x1c0
+#define XK_Abreve 0x1c3
+#define XK_Lacute 0x1c5
+#define XK_Cacute 0x1c6
+#define XK_Ccaron 0x1c8
+#define XK_Eogonek 0x1ca
+#define XK_Ecaron 0x1cc
+#define XK_Dcaron 0x1cf
+#define XK_Dstroke 0x1d0
+#define XK_Nacute 0x1d1
+#define XK_Ncaron 0x1d2
+#define XK_Odoubleacute 0x1d5
+#define XK_Rcaron 0x1d8
+#define XK_Uring 0x1d9
+#define XK_Udoubleacute 0x1db
+#define XK_Tcedilla 0x1de
+#define XK_racute 0x1e0
+#define XK_abreve 0x1e3
+#define XK_lacute 0x1e5
+#define XK_cacute 0x1e6
+#define XK_ccaron 0x1e8
+#define XK_eogonek 0x1ea
+#define XK_ecaron 0x1ec
+#define XK_dcaron 0x1ef
+#define XK_dstroke 0x1f0
+#define XK_nacute 0x1f1
+#define XK_ncaron 0x1f2
+#define XK_odoubleacute 0x1f5
+#define XK_udoubleacute 0x1fb
+#define XK_rcaron 0x1f8
+#define XK_uring 0x1f9
+#define XK_tcedilla 0x1fe
+#define XK_abovedot 0x1ff
+#endif /* XK_LATIN2 */
+
+/*
+ * Latin 3
+ * Byte 3 = 2
+ */
+
+#ifdef XK_LATIN3
+#define XK_Hstroke 0x2a1
+#define XK_Hcircumflex 0x2a6
+#define XK_Iabovedot 0x2a9
+#define XK_Gbreve 0x2ab
+#define XK_Jcircumflex 0x2ac
+#define XK_hstroke 0x2b1
+#define XK_hcircumflex 0x2b6
+#define XK_idotless 0x2b9
+#define XK_gbreve 0x2bb
+#define XK_jcircumflex 0x2bc
+#define XK_Cabovedot 0x2c5
+#define XK_Ccircumflex 0x2c6
+#define XK_Gabovedot 0x2d5
+#define XK_Gcircumflex 0x2d8
+#define XK_Ubreve 0x2dd
+#define XK_Scircumflex 0x2de
+#define XK_cabovedot 0x2e5
+#define XK_ccircumflex 0x2e6
+#define XK_gabovedot 0x2f5
+#define XK_gcircumflex 0x2f8
+#define XK_ubreve 0x2fd
+#define XK_scircumflex 0x2fe
+#endif /* XK_LATIN3 */
+
+
+/*
+ * Latin 4
+ * Byte 3 = 3
+ */
+
+#ifdef XK_LATIN4
+#define XK_kra 0x3a2
+#define XK_kappa 0x3a2 /* deprecated */
+#define XK_Rcedilla 0x3a3
+#define XK_Itilde 0x3a5
+#define XK_Lcedilla 0x3a6
+#define XK_Emacron 0x3aa
+#define XK_Gcedilla 0x3ab
+#define XK_Tslash 0x3ac
+#define XK_rcedilla 0x3b3
+#define XK_itilde 0x3b5
+#define XK_lcedilla 0x3b6
+#define XK_emacron 0x3ba
+#define XK_gcedilla 0x3bb
+#define XK_tslash 0x3bc
+#define XK_ENG 0x3bd
+#define XK_eng 0x3bf
+#define XK_Amacron 0x3c0
+#define XK_Iogonek 0x3c7
+#define XK_Eabovedot 0x3cc
+#define XK_Imacron 0x3cf
+#define XK_Ncedilla 0x3d1
+#define XK_Omacron 0x3d2
+#define XK_Kcedilla 0x3d3
+#define XK_Uogonek 0x3d9
+#define XK_Utilde 0x3dd
+#define XK_Umacron 0x3de
+#define XK_amacron 0x3e0
+#define XK_iogonek 0x3e7
+#define XK_eabovedot 0x3ec
+#define XK_imacron 0x3ef
+#define XK_ncedilla 0x3f1
+#define XK_omacron 0x3f2
+#define XK_kcedilla 0x3f3
+#define XK_uogonek 0x3f9
+#define XK_utilde 0x3fd
+#define XK_umacron 0x3fe
+#endif /* XK_LATIN4 */
+
+/*
+ * Latin-9 (a.k.a. Latin-0)
+ * Byte 3 = 19
+ */
+
+#ifdef XK_LATIN9
+#define XK_OE 0x13bc
+#define XK_oe 0x13bd
+#define XK_Ydiaeresis 0x13be
+#endif /* XK_LATIN9 */
+
+/*
+ * Katakana
+ * Byte 3 = 4
+ */
+
+#ifdef XK_KATAKANA
+#define XK_overline 0x47e
+#define XK_kana_fullstop 0x4a1
+#define XK_kana_openingbracket 0x4a2
+#define XK_kana_closingbracket 0x4a3
+#define XK_kana_comma 0x4a4
+#define XK_kana_conjunctive 0x4a5
+#define XK_kana_middledot 0x4a5 /* deprecated */
+#define XK_kana_WO 0x4a6
+#define XK_kana_a 0x4a7
+#define XK_kana_i 0x4a8
+#define XK_kana_u 0x4a9
+#define XK_kana_e 0x4aa
+#define XK_kana_o 0x4ab
+#define XK_kana_ya 0x4ac
+#define XK_kana_yu 0x4ad
+#define XK_kana_yo 0x4ae
+#define XK_kana_tsu 0x4af
+#define XK_kana_tu 0x4af /* deprecated */
+#define XK_prolongedsound 0x4b0
+#define XK_kana_A 0x4b1
+#define XK_kana_I 0x4b2
+#define XK_kana_U 0x4b3
+#define XK_kana_E 0x4b4
+#define XK_kana_O 0x4b5
+#define XK_kana_KA 0x4b6
+#define XK_kana_KI 0x4b7
+#define XK_kana_KU 0x4b8
+#define XK_kana_KE 0x4b9
+#define XK_kana_KO 0x4ba
+#define XK_kana_SA 0x4bb
+#define XK_kana_SHI 0x4bc
+#define XK_kana_SU 0x4bd
+#define XK_kana_SE 0x4be
+#define XK_kana_SO 0x4bf
+#define XK_kana_TA 0x4c0
+#define XK_kana_CHI 0x4c1
+#define XK_kana_TI 0x4c1 /* deprecated */
+#define XK_kana_TSU 0x4c2
+#define XK_kana_TU 0x4c2 /* deprecated */
+#define XK_kana_TE 0x4c3
+#define XK_kana_TO 0x4c4
+#define XK_kana_NA 0x4c5
+#define XK_kana_NI 0x4c6
+#define XK_kana_NU 0x4c7
+#define XK_kana_NE 0x4c8
+#define XK_kana_NO 0x4c9
+#define XK_kana_HA 0x4ca
+#define XK_kana_HI 0x4cb
+#define XK_kana_FU 0x4cc
+#define XK_kana_HU 0x4cc /* deprecated */
+#define XK_kana_HE 0x4cd
+#define XK_kana_HO 0x4ce
+#define XK_kana_MA 0x4cf
+#define XK_kana_MI 0x4d0
+#define XK_kana_MU 0x4d1
+#define XK_kana_ME 0x4d2
+#define XK_kana_MO 0x4d3
+#define XK_kana_YA 0x4d4
+#define XK_kana_YU 0x4d5
+#define XK_kana_YO 0x4d6
+#define XK_kana_RA 0x4d7
+#define XK_kana_RI 0x4d8
+#define XK_kana_RU 0x4d9
+#define XK_kana_RE 0x4da
+#define XK_kana_RO 0x4db
+#define XK_kana_WA 0x4dc
+#define XK_kana_N 0x4dd
+#define XK_voicedsound 0x4de
+#define XK_semivoicedsound 0x4df
+#define XK_kana_switch 0xFF7E /* Alias for mode_switch */
+#endif /* XK_KATAKANA */
+
+/*
+ * Arabic
+ * Byte 3 = 5
+ */
+
+#ifdef XK_ARABIC
+#define XK_Arabic_comma 0x5ac
+#define XK_Arabic_semicolon 0x5bb
+#define XK_Arabic_question_mark 0x5bf
+#define XK_Arabic_hamza 0x5c1
+#define XK_Arabic_maddaonalef 0x5c2
+#define XK_Arabic_hamzaonalef 0x5c3
+#define XK_Arabic_hamzaonwaw 0x5c4
+#define XK_Arabic_hamzaunderalef 0x5c5
+#define XK_Arabic_hamzaonyeh 0x5c6
+#define XK_Arabic_alef 0x5c7
+#define XK_Arabic_beh 0x5c8
+#define XK_Arabic_tehmarbuta 0x5c9
+#define XK_Arabic_teh 0x5ca
+#define XK_Arabic_theh 0x5cb
+#define XK_Arabic_jeem 0x5cc
+#define XK_Arabic_hah 0x5cd
+#define XK_Arabic_khah 0x5ce
+#define XK_Arabic_dal 0x5cf
+#define XK_Arabic_thal 0x5d0
+#define XK_Arabic_ra 0x5d1
+#define XK_Arabic_zain 0x5d2
+#define XK_Arabic_seen 0x5d3
+#define XK_Arabic_sheen 0x5d4
+#define XK_Arabic_sad 0x5d5
+#define XK_Arabic_dad 0x5d6
+#define XK_Arabic_tah 0x5d7
+#define XK_Arabic_zah 0x5d8
+#define XK_Arabic_ain 0x5d9
+#define XK_Arabic_ghain 0x5da
+#define XK_Arabic_tatweel 0x5e0
+#define XK_Arabic_feh 0x5e1
+#define XK_Arabic_qaf 0x5e2
+#define XK_Arabic_kaf 0x5e3
+#define XK_Arabic_lam 0x5e4
+#define XK_Arabic_meem 0x5e5
+#define XK_Arabic_noon 0x5e6
+#define XK_Arabic_ha 0x5e7
+#define XK_Arabic_heh 0x5e7 /* deprecated */
+#define XK_Arabic_waw 0x5e8
+#define XK_Arabic_alefmaksura 0x5e9
+#define XK_Arabic_yeh 0x5ea
+#define XK_Arabic_fathatan 0x5eb
+#define XK_Arabic_dammatan 0x5ec
+#define XK_Arabic_kasratan 0x5ed
+#define XK_Arabic_fatha 0x5ee
+#define XK_Arabic_damma 0x5ef
+#define XK_Arabic_kasra 0x5f0
+#define XK_Arabic_shadda 0x5f1
+#define XK_Arabic_sukun 0x5f2
+#define XK_Arabic_switch 0xFF7E /* Alias for mode_switch */
+#endif /* XK_ARABIC */
+
+/*
+ * Cyrillic
+ * Byte 3 = 6
+ */
+#ifdef XK_CYRILLIC
+#define XK_Serbian_dje 0x6a1
+#define XK_Macedonia_gje 0x6a2
+#define XK_Cyrillic_io 0x6a3
+#define XK_Ukrainian_ie 0x6a4
+#define XK_Ukranian_je 0x6a4 /* deprecated */
+#define XK_Macedonia_dse 0x6a5
+#define XK_Ukrainian_i 0x6a6
+#define XK_Ukranian_i 0x6a6 /* deprecated */
+#define XK_Ukrainian_yi 0x6a7
+#define XK_Ukranian_yi 0x6a7 /* deprecated */
+#define XK_Cyrillic_je 0x6a8
+#define XK_Serbian_je 0x6a8 /* deprecated */
+#define XK_Cyrillic_lje 0x6a9
+#define XK_Serbian_lje 0x6a9 /* deprecated */
+#define XK_Cyrillic_nje 0x6aa
+#define XK_Serbian_nje 0x6aa /* deprecated */
+#define XK_Serbian_tshe 0x6ab
+#define XK_Macedonia_kje 0x6ac
+#define XK_Byelorussian_shortu 0x6ae
+#define XK_Cyrillic_dzhe 0x6af
+#define XK_Serbian_dze 0x6af /* deprecated */
+#define XK_numerosign 0x6b0
+#define XK_Serbian_DJE 0x6b1
+#define XK_Macedonia_GJE 0x6b2
+#define XK_Cyrillic_IO 0x6b3
+#define XK_Ukrainian_IE 0x6b4
+#define XK_Ukranian_JE 0x6b4 /* deprecated */
+#define XK_Macedonia_DSE 0x6b5
+#define XK_Ukrainian_I 0x6b6
+#define XK_Ukranian_I 0x6b6 /* deprecated */
+#define XK_Ukrainian_YI 0x6b7
+#define XK_Ukranian_YI 0x6b7 /* deprecated */
+#define XK_Cyrillic_JE 0x6b8
+#define XK_Serbian_JE 0x6b8 /* deprecated */
+#define XK_Cyrillic_LJE 0x6b9
+#define XK_Serbian_LJE 0x6b9 /* deprecated */
+#define XK_Cyrillic_NJE 0x6ba
+#define XK_Serbian_NJE 0x6ba /* deprecated */
+#define XK_Serbian_TSHE 0x6bb
+#define XK_Macedonia_KJE 0x6bc
+#define XK_Byelorussian_SHORTU 0x6be
+#define XK_Cyrillic_DZHE 0x6bf
+#define XK_Serbian_DZE 0x6bf /* deprecated */
+#define XK_Cyrillic_yu 0x6c0
+#define XK_Cyrillic_a 0x6c1
+#define XK_Cyrillic_be 0x6c2
+#define XK_Cyrillic_tse 0x6c3
+#define XK_Cyrillic_de 0x6c4
+#define XK_Cyrillic_ie 0x6c5
+#define XK_Cyrillic_ef 0x6c6
+#define XK_Cyrillic_ghe 0x6c7
+#define XK_Cyrillic_ha 0x6c8
+#define XK_Cyrillic_i 0x6c9
+#define XK_Cyrillic_shorti 0x6ca
+#define XK_Cyrillic_ka 0x6cb
+#define XK_Cyrillic_el 0x6cc
+#define XK_Cyrillic_em 0x6cd
+#define XK_Cyrillic_en 0x6ce
+#define XK_Cyrillic_o 0x6cf
+#define XK_Cyrillic_pe 0x6d0
+#define XK_Cyrillic_ya 0x6d1
+#define XK_Cyrillic_er 0x6d2
+#define XK_Cyrillic_es 0x6d3
+#define XK_Cyrillic_te 0x6d4
+#define XK_Cyrillic_u 0x6d5
+#define XK_Cyrillic_zhe 0x6d6
+#define XK_Cyrillic_ve 0x6d7
+#define XK_Cyrillic_softsign 0x6d8
+#define XK_Cyrillic_yeru 0x6d9
+#define XK_Cyrillic_ze 0x6da
+#define XK_Cyrillic_sha 0x6db
+#define XK_Cyrillic_e 0x6dc
+#define XK_Cyrillic_shcha 0x6dd
+#define XK_Cyrillic_che 0x6de
+#define XK_Cyrillic_hardsign 0x6df
+#define XK_Cyrillic_YU 0x6e0
+#define XK_Cyrillic_A 0x6e1
+#define XK_Cyrillic_BE 0x6e2
+#define XK_Cyrillic_TSE 0x6e3
+#define XK_Cyrillic_DE 0x6e4
+#define XK_Cyrillic_IE 0x6e5
+#define XK_Cyrillic_EF 0x6e6
+#define XK_Cyrillic_GHE 0x6e7
+#define XK_Cyrillic_HA 0x6e8
+#define XK_Cyrillic_I 0x6e9
+#define XK_Cyrillic_SHORTI 0x6ea
+#define XK_Cyrillic_KA 0x6eb
+#define XK_Cyrillic_EL 0x6ec
+#define XK_Cyrillic_EM 0x6ed
+#define XK_Cyrillic_EN 0x6ee
+#define XK_Cyrillic_O 0x6ef
+#define XK_Cyrillic_PE 0x6f0
+#define XK_Cyrillic_YA 0x6f1
+#define XK_Cyrillic_ER 0x6f2
+#define XK_Cyrillic_ES 0x6f3
+#define XK_Cyrillic_TE 0x6f4
+#define XK_Cyrillic_U 0x6f5
+#define XK_Cyrillic_ZHE 0x6f6
+#define XK_Cyrillic_VE 0x6f7
+#define XK_Cyrillic_SOFTSIGN 0x6f8
+#define XK_Cyrillic_YERU 0x6f9
+#define XK_Cyrillic_ZE 0x6fa
+#define XK_Cyrillic_SHA 0x6fb
+#define XK_Cyrillic_E 0x6fc
+#define XK_Cyrillic_SHCHA 0x6fd
+#define XK_Cyrillic_CHE 0x6fe
+#define XK_Cyrillic_HARDSIGN 0x6ff
+#endif /* XK_CYRILLIC */
+
+/*
+ * Greek
+ * Byte 3 = 7
+ */
+
+#ifdef XK_GREEK
+#define XK_Greek_ALPHAaccent 0x7a1
+#define XK_Greek_EPSILONaccent 0x7a2
+#define XK_Greek_ETAaccent 0x7a3
+#define XK_Greek_IOTAaccent 0x7a4
+#define XK_Greek_IOTAdiaeresis 0x7a5
+#define XK_Greek_OMICRONaccent 0x7a7
+#define XK_Greek_UPSILONaccent 0x7a8
+#define XK_Greek_UPSILONdieresis 0x7a9
+#define XK_Greek_OMEGAaccent 0x7ab
+#define XK_Greek_accentdieresis 0x7ae
+#define XK_Greek_horizbar 0x7af
+#define XK_Greek_alphaaccent 0x7b1
+#define XK_Greek_epsilonaccent 0x7b2
+#define XK_Greek_etaaccent 0x7b3
+#define XK_Greek_iotaaccent 0x7b4
+#define XK_Greek_iotadieresis 0x7b5
+#define XK_Greek_iotaaccentdieresis 0x7b6
+#define XK_Greek_omicronaccent 0x7b7
+#define XK_Greek_upsilonaccent 0x7b8
+#define XK_Greek_upsilondieresis 0x7b9
+#define XK_Greek_upsilonaccentdieresis 0x7ba
+#define XK_Greek_omegaaccent 0x7bb
+#define XK_Greek_ALPHA 0x7c1
+#define XK_Greek_BETA 0x7c2
+#define XK_Greek_GAMMA 0x7c3
+#define XK_Greek_DELTA 0x7c4
+#define XK_Greek_EPSILON 0x7c5
+#define XK_Greek_ZETA 0x7c6
+#define XK_Greek_ETA 0x7c7
+#define XK_Greek_THETA 0x7c8
+#define XK_Greek_IOTA 0x7c9
+#define XK_Greek_KAPPA 0x7ca
+#define XK_Greek_LAMDA 0x7cb
+#define XK_Greek_LAMBDA 0x7cb
+#define XK_Greek_MU 0x7cc
+#define XK_Greek_NU 0x7cd
+#define XK_Greek_XI 0x7ce
+#define XK_Greek_OMICRON 0x7cf
+#define XK_Greek_PI 0x7d0
+#define XK_Greek_RHO 0x7d1
+#define XK_Greek_SIGMA 0x7d2
+#define XK_Greek_TAU 0x7d4
+#define XK_Greek_UPSILON 0x7d5
+#define XK_Greek_PHI 0x7d6
+#define XK_Greek_CHI 0x7d7
+#define XK_Greek_PSI 0x7d8
+#define XK_Greek_OMEGA 0x7d9
+#define XK_Greek_alpha 0x7e1
+#define XK_Greek_beta 0x7e2
+#define XK_Greek_gamma 0x7e3
+#define XK_Greek_delta 0x7e4
+#define XK_Greek_epsilon 0x7e5
+#define XK_Greek_zeta 0x7e6
+#define XK_Greek_eta 0x7e7
+#define XK_Greek_theta 0x7e8
+#define XK_Greek_iota 0x7e9
+#define XK_Greek_kappa 0x7ea
+#define XK_Greek_lamda 0x7eb
+#define XK_Greek_lambda 0x7eb
+#define XK_Greek_mu 0x7ec
+#define XK_Greek_nu 0x7ed
+#define XK_Greek_xi 0x7ee
+#define XK_Greek_omicron 0x7ef
+#define XK_Greek_pi 0x7f0
+#define XK_Greek_rho 0x7f1
+#define XK_Greek_sigma 0x7f2
+#define XK_Greek_finalsmallsigma 0x7f3
+#define XK_Greek_tau 0x7f4
+#define XK_Greek_upsilon 0x7f5
+#define XK_Greek_phi 0x7f6
+#define XK_Greek_chi 0x7f7
+#define XK_Greek_psi 0x7f8
+#define XK_Greek_omega 0x7f9
+#define XK_Greek_switch 0xFF7E /* Alias for mode_switch */
+#endif /* XK_GREEK */
+
+/*
+ * Technical
+ * Byte 3 = 8
+ */
+
+#ifdef XK_TECHNICAL
+#define XK_leftradical 0x8a1
+#define XK_topleftradical 0x8a2
+#define XK_horizconnector 0x8a3
+#define XK_topintegral 0x8a4
+#define XK_botintegral 0x8a5
+#define XK_vertconnector 0x8a6
+#define XK_topleftsqbracket 0x8a7
+#define XK_botleftsqbracket 0x8a8
+#define XK_toprightsqbracket 0x8a9
+#define XK_botrightsqbracket 0x8aa
+#define XK_topleftparens 0x8ab
+#define XK_botleftparens 0x8ac
+#define XK_toprightparens 0x8ad
+#define XK_botrightparens 0x8ae
+#define XK_leftmiddlecurlybrace 0x8af
+#define XK_rightmiddlecurlybrace 0x8b0
+#define XK_topleftsummation 0x8b1
+#define XK_botleftsummation 0x8b2
+#define XK_topvertsummationconnector 0x8b3
+#define XK_botvertsummationconnector 0x8b4
+#define XK_toprightsummation 0x8b5
+#define XK_botrightsummation 0x8b6
+#define XK_rightmiddlesummation 0x8b7
+#define XK_lessthanequal 0x8bc
+#define XK_notequal 0x8bd
+#define XK_greaterthanequal 0x8be
+#define XK_integral 0x8bf
+#define XK_therefore 0x8c0
+#define XK_variation 0x8c1
+#define XK_infinity 0x8c2
+#define XK_nabla 0x8c5
+#define XK_approximate 0x8c8
+#define XK_similarequal 0x8c9
+#define XK_ifonlyif 0x8cd
+#define XK_implies 0x8ce
+#define XK_identical 0x8cf
+#define XK_radical 0x8d6
+#define XK_includedin 0x8da
+#define XK_includes 0x8db
+#define XK_intersection 0x8dc
+#define XK_union 0x8dd
+#define XK_logicaland 0x8de
+#define XK_logicalor 0x8df
+#define XK_partialderivative 0x8ef
+#define XK_function 0x8f6
+#define XK_leftarrow 0x8fb
+#define XK_uparrow 0x8fc
+#define XK_rightarrow 0x8fd
+#define XK_downarrow 0x8fe
+#endif /* XK_TECHNICAL */
+
+/*
+ * Special
+ * Byte 3 = 9
+ */
+
+#ifdef XK_SPECIAL
+#define XK_blank 0x9df
+#define XK_soliddiamond 0x9e0
+#define XK_checkerboard 0x9e1
+#define XK_ht 0x9e2
+#define XK_ff 0x9e3
+#define XK_cr 0x9e4
+#define XK_lf 0x9e5
+#define XK_nl 0x9e8
+#define XK_vt 0x9e9
+#define XK_lowrightcorner 0x9ea
+#define XK_uprightcorner 0x9eb
+#define XK_upleftcorner 0x9ec
+#define XK_lowleftcorner 0x9ed
+#define XK_crossinglines 0x9ee
+#define XK_horizlinescan1 0x9ef
+#define XK_horizlinescan3 0x9f0
+#define XK_horizlinescan5 0x9f1
+#define XK_horizlinescan7 0x9f2
+#define XK_horizlinescan9 0x9f3
+#define XK_leftt 0x9f4
+#define XK_rightt 0x9f5
+#define XK_bott 0x9f6
+#define XK_topt 0x9f7
+#define XK_vertbar 0x9f8
+#endif /* XK_SPECIAL */
+
+/*
+ * Publishing
+ * Byte 3 = a
+ */
+
+#ifdef XK_PUBLISHING
+#define XK_emspace 0xaa1
+#define XK_enspace 0xaa2
+#define XK_em3space 0xaa3
+#define XK_em4space 0xaa4
+#define XK_digitspace 0xaa5
+#define XK_punctspace 0xaa6
+#define XK_thinspace 0xaa7
+#define XK_hairspace 0xaa8
+#define XK_emdash 0xaa9
+#define XK_endash 0xaaa
+#define XK_signifblank 0xaac
+#define XK_ellipsis 0xaae
+#define XK_doubbaselinedot 0xaaf
+#define XK_onethird 0xab0
+#define XK_twothirds 0xab1
+#define XK_onefifth 0xab2
+#define XK_twofifths 0xab3
+#define XK_threefifths 0xab4
+#define XK_fourfifths 0xab5
+#define XK_onesixth 0xab6
+#define XK_fivesixths 0xab7
+#define XK_careof 0xab8
+#define XK_figdash 0xabb
+#define XK_leftanglebracket 0xabc
+#define XK_decimalpoint 0xabd
+#define XK_rightanglebracket 0xabe
+#define XK_marker 0xabf
+#define XK_oneeighth 0xac3
+#define XK_threeeighths 0xac4
+#define XK_fiveeighths 0xac5
+#define XK_seveneighths 0xac6
+#define XK_trademark 0xac9
+#define XK_signaturemark 0xaca
+#define XK_trademarkincircle 0xacb
+#define XK_leftopentriangle 0xacc
+#define XK_rightopentriangle 0xacd
+#define XK_emopencircle 0xace
+#define XK_emopenrectangle 0xacf
+#define XK_leftsinglequotemark 0xad0
+#define XK_rightsinglequotemark 0xad1
+#define XK_leftdoublequotemark 0xad2
+#define XK_rightdoublequotemark 0xad3
+#define XK_prescription 0xad4
+#define XK_minutes 0xad6
+#define XK_seconds 0xad7
+#define XK_latincross 0xad9
+#define XK_hexagram 0xada
+#define XK_filledrectbullet 0xadb
+#define XK_filledlefttribullet 0xadc
+#define XK_filledrighttribullet 0xadd
+#define XK_emfilledcircle 0xade
+#define XK_emfilledrect 0xadf
+#define XK_enopencircbullet 0xae0
+#define XK_enopensquarebullet 0xae1
+#define XK_openrectbullet 0xae2
+#define XK_opentribulletup 0xae3
+#define XK_opentribulletdown 0xae4
+#define XK_openstar 0xae5
+#define XK_enfilledcircbullet 0xae6
+#define XK_enfilledsqbullet 0xae7
+#define XK_filledtribulletup 0xae8
+#define XK_filledtribulletdown 0xae9
+#define XK_leftpointer 0xaea
+#define XK_rightpointer 0xaeb
+#define XK_club 0xaec
+#define XK_diamond 0xaed
+#define XK_heart 0xaee
+#define XK_maltesecross 0xaf0
+#define XK_dagger 0xaf1
+#define XK_doubledagger 0xaf2
+#define XK_checkmark 0xaf3
+#define XK_ballotcross 0xaf4
+#define XK_musicalsharp 0xaf5
+#define XK_musicalflat 0xaf6
+#define XK_malesymbol 0xaf7
+#define XK_femalesymbol 0xaf8
+#define XK_telephone 0xaf9
+#define XK_telephonerecorder 0xafa
+#define XK_phonographcopyright 0xafb
+#define XK_caret 0xafc
+#define XK_singlelowquotemark 0xafd
+#define XK_doublelowquotemark 0xafe
+#define XK_cursor 0xaff
+#endif /* XK_PUBLISHING */
+
+/*
+ * APL
+ * Byte 3 = b
+ */
+
+#ifdef XK_APL
+#define XK_leftcaret 0xba3
+#define XK_rightcaret 0xba6
+#define XK_downcaret 0xba8
+#define XK_upcaret 0xba9
+#define XK_overbar 0xbc0
+#define XK_downtack 0xbc2
+#define XK_upshoe 0xbc3
+#define XK_downstile 0xbc4
+#define XK_underbar 0xbc6
+#define XK_jot 0xbca
+#define XK_quad 0xbcc
+#define XK_uptack 0xbce
+#define XK_circle 0xbcf
+#define XK_upstile 0xbd3
+#define XK_downshoe 0xbd6
+#define XK_rightshoe 0xbd8
+#define XK_leftshoe 0xbda
+#define XK_lefttack 0xbdc
+#define XK_righttack 0xbfc
+#endif /* XK_APL */
+
+/*
+ * Hebrew
+ * Byte 3 = c
+ */
+
+#ifdef XK_HEBREW
+#define XK_hebrew_doublelowline 0xcdf
+#define XK_hebrew_aleph 0xce0
+#define XK_hebrew_bet 0xce1
+#define XK_hebrew_beth 0xce1 /* deprecated */
+#define XK_hebrew_gimel 0xce2
+#define XK_hebrew_gimmel 0xce2 /* deprecated */
+#define XK_hebrew_dalet 0xce3
+#define XK_hebrew_daleth 0xce3 /* deprecated */
+#define XK_hebrew_he 0xce4
+#define XK_hebrew_waw 0xce5
+#define XK_hebrew_zain 0xce6
+#define XK_hebrew_zayin 0xce6 /* deprecated */
+#define XK_hebrew_chet 0xce7
+#define XK_hebrew_het 0xce7 /* deprecated */
+#define XK_hebrew_tet 0xce8
+#define XK_hebrew_teth 0xce8 /* deprecated */
+#define XK_hebrew_yod 0xce9
+#define XK_hebrew_finalkaph 0xcea
+#define XK_hebrew_kaph 0xceb
+#define XK_hebrew_lamed 0xcec
+#define XK_hebrew_finalmem 0xced
+#define XK_hebrew_mem 0xcee
+#define XK_hebrew_finalnun 0xcef
+#define XK_hebrew_nun 0xcf0
+#define XK_hebrew_samech 0xcf1
+#define XK_hebrew_samekh 0xcf1 /* deprecated */
+#define XK_hebrew_ayin 0xcf2
+#define XK_hebrew_finalpe 0xcf3
+#define XK_hebrew_pe 0xcf4
+#define XK_hebrew_finalzade 0xcf5
+#define XK_hebrew_finalzadi 0xcf5 /* deprecated */
+#define XK_hebrew_zade 0xcf6
+#define XK_hebrew_zadi 0xcf6 /* deprecated */
+#define XK_hebrew_qoph 0xcf7
+#define XK_hebrew_kuf 0xcf7 /* deprecated */
+#define XK_hebrew_resh 0xcf8
+#define XK_hebrew_shin 0xcf9
+#define XK_hebrew_taw 0xcfa
+#define XK_hebrew_taf 0xcfa /* deprecated */
+#define XK_Hebrew_switch 0xFF7E /* Alias for mode_switch */
+#endif /* XK_HEBREW */
+
+/*
+ * Thai
+ * Byte 3 = d
+ */
+
+#ifdef XK_THAI
+#define XK_Thai_kokai 0xda1
+#define XK_Thai_khokhai 0xda2
+#define XK_Thai_khokhuat 0xda3
+#define XK_Thai_khokhwai 0xda4
+#define XK_Thai_khokhon 0xda5
+#define XK_Thai_khorakhang 0xda6
+#define XK_Thai_ngongu 0xda7
+#define XK_Thai_chochan 0xda8
+#define XK_Thai_choching 0xda9
+#define XK_Thai_chochang 0xdaa
+#define XK_Thai_soso 0xdab
+#define XK_Thai_chochoe 0xdac
+#define XK_Thai_yoying 0xdad
+#define XK_Thai_dochada 0xdae
+#define XK_Thai_topatak 0xdaf
+#define XK_Thai_thothan 0xdb0
+#define XK_Thai_thonangmontho 0xdb1
+#define XK_Thai_thophuthao 0xdb2
+#define XK_Thai_nonen 0xdb3
+#define XK_Thai_dodek 0xdb4
+#define XK_Thai_totao 0xdb5
+#define XK_Thai_thothung 0xdb6
+#define XK_Thai_thothahan 0xdb7
+#define XK_Thai_thothong 0xdb8
+#define XK_Thai_nonu 0xdb9
+#define XK_Thai_bobaimai 0xdba
+#define XK_Thai_popla 0xdbb
+#define XK_Thai_phophung 0xdbc
+#define XK_Thai_fofa 0xdbd
+#define XK_Thai_phophan 0xdbe
+#define XK_Thai_fofan 0xdbf
+#define XK_Thai_phosamphao 0xdc0
+#define XK_Thai_moma 0xdc1
+#define XK_Thai_yoyak 0xdc2
+#define XK_Thai_rorua 0xdc3
+#define XK_Thai_ru 0xdc4
+#define XK_Thai_loling 0xdc5
+#define XK_Thai_lu 0xdc6
+#define XK_Thai_wowaen 0xdc7
+#define XK_Thai_sosala 0xdc8
+#define XK_Thai_sorusi 0xdc9
+#define XK_Thai_sosua 0xdca
+#define XK_Thai_hohip 0xdcb
+#define XK_Thai_lochula 0xdcc
+#define XK_Thai_oang 0xdcd
+#define XK_Thai_honokhuk 0xdce
+#define XK_Thai_paiyannoi 0xdcf
+#define XK_Thai_saraa 0xdd0
+#define XK_Thai_maihanakat 0xdd1
+#define XK_Thai_saraaa 0xdd2
+#define XK_Thai_saraam 0xdd3
+#define XK_Thai_sarai 0xdd4
+#define XK_Thai_saraii 0xdd5
+#define XK_Thai_saraue 0xdd6
+#define XK_Thai_sarauee 0xdd7
+#define XK_Thai_sarau 0xdd8
+#define XK_Thai_sarauu 0xdd9
+#define XK_Thai_phinthu 0xdda
+#define XK_Thai_maihanakat_maitho 0xdde
+#define XK_Thai_baht 0xddf
+#define XK_Thai_sarae 0xde0
+#define XK_Thai_saraae 0xde1
+#define XK_Thai_sarao 0xde2
+#define XK_Thai_saraaimaimuan 0xde3
+#define XK_Thai_saraaimaimalai 0xde4
+#define XK_Thai_lakkhangyao 0xde5
+#define XK_Thai_maiyamok 0xde6
+#define XK_Thai_maitaikhu 0xde7
+#define XK_Thai_maiek 0xde8
+#define XK_Thai_maitho 0xde9
+#define XK_Thai_maitri 0xdea
+#define XK_Thai_maichattawa 0xdeb
+#define XK_Thai_thanthakhat 0xdec
+#define XK_Thai_nikhahit 0xded
+#define XK_Thai_leksun 0xdf0
+#define XK_Thai_leknung 0xdf1
+#define XK_Thai_leksong 0xdf2
+#define XK_Thai_leksam 0xdf3
+#define XK_Thai_leksi 0xdf4
+#define XK_Thai_lekha 0xdf5
+#define XK_Thai_lekhok 0xdf6
+#define XK_Thai_lekchet 0xdf7
+#define XK_Thai_lekpaet 0xdf8
+#define XK_Thai_lekkao 0xdf9
+#endif /* XK_THAI */
+
+/*
+ * Korean
+ * Byte 3 = e
+ */
+
+#ifdef XK_KOREAN
+
+#define XK_Hangul 0xff31 /* Hangul start/stop(toggle) */
+#define XK_Hangul_Start 0xff32 /* Hangul start */
+#define XK_Hangul_End 0xff33 /* Hangul end, English start */
+#define XK_Hangul_Hanja 0xff34 /* Start Hangul->Hanja Conversion */
+#define XK_Hangul_Jamo 0xff35 /* Hangul Jamo mode */
+#define XK_Hangul_Romaja 0xff36 /* Hangul Romaja mode */
+#define XK_Hangul_Codeinput 0xff37 /* Hangul code input mode */
+#define XK_Hangul_Jeonja 0xff38 /* Jeonja mode */
+#define XK_Hangul_Banja 0xff39 /* Banja mode */
+#define XK_Hangul_PreHanja 0xff3a /* Pre Hanja conversion */
+#define XK_Hangul_PostHanja 0xff3b /* Post Hanja conversion */
+#define XK_Hangul_SingleCandidate 0xff3c /* Single candidate */
+#define XK_Hangul_MultipleCandidate 0xff3d /* Multiple candidate */
+#define XK_Hangul_PreviousCandidate 0xff3e /* Previous candidate */
+#define XK_Hangul_Special 0xff3f /* Special symbols */
+#define XK_Hangul_switch 0xFF7E /* Alias for mode_switch */
+
+/* Hangul Consonant Characters */
+#define XK_Hangul_Kiyeog 0xea1
+#define XK_Hangul_SsangKiyeog 0xea2
+#define XK_Hangul_KiyeogSios 0xea3
+#define XK_Hangul_Nieun 0xea4
+#define XK_Hangul_NieunJieuj 0xea5
+#define XK_Hangul_NieunHieuh 0xea6
+#define XK_Hangul_Dikeud 0xea7
+#define XK_Hangul_SsangDikeud 0xea8
+#define XK_Hangul_Rieul 0xea9
+#define XK_Hangul_RieulKiyeog 0xeaa
+#define XK_Hangul_RieulMieum 0xeab
+#define XK_Hangul_RieulPieub 0xeac
+#define XK_Hangul_RieulSios 0xead
+#define XK_Hangul_RieulTieut 0xeae
+#define XK_Hangul_RieulPhieuf 0xeaf
+#define XK_Hangul_RieulHieuh 0xeb0
+#define XK_Hangul_Mieum 0xeb1
+#define XK_Hangul_Pieub 0xeb2
+#define XK_Hangul_SsangPieub 0xeb3
+#define XK_Hangul_PieubSios 0xeb4
+#define XK_Hangul_Sios 0xeb5
+#define XK_Hangul_SsangSios 0xeb6
+#define XK_Hangul_Ieung 0xeb7
+#define XK_Hangul_Jieuj 0xeb8
+#define XK_Hangul_SsangJieuj 0xeb9
+#define XK_Hangul_Cieuc 0xeba
+#define XK_Hangul_Khieuq 0xebb
+#define XK_Hangul_Tieut 0xebc
+#define XK_Hangul_Phieuf 0xebd
+#define XK_Hangul_Hieuh 0xebe
+
+/* Hangul Vowel Characters */
+#define XK_Hangul_A 0xebf
+#define XK_Hangul_AE 0xec0
+#define XK_Hangul_YA 0xec1
+#define XK_Hangul_YAE 0xec2
+#define XK_Hangul_EO 0xec3
+#define XK_Hangul_E 0xec4
+#define XK_Hangul_YEO 0xec5
+#define XK_Hangul_YE 0xec6
+#define XK_Hangul_O 0xec7
+#define XK_Hangul_WA 0xec8
+#define XK_Hangul_WAE 0xec9
+#define XK_Hangul_OE 0xeca
+#define XK_Hangul_YO 0xecb
+#define XK_Hangul_U 0xecc
+#define XK_Hangul_WEO 0xecd
+#define XK_Hangul_WE 0xece
+#define XK_Hangul_WI 0xecf
+#define XK_Hangul_YU 0xed0
+#define XK_Hangul_EU 0xed1
+#define XK_Hangul_YI 0xed2
+#define XK_Hangul_I 0xed3
+
+/* Hangul syllable-final (JongSeong) Characters */
+#define XK_Hangul_J_Kiyeog 0xed4
+#define XK_Hangul_J_SsangKiyeog 0xed5
+#define XK_Hangul_J_KiyeogSios 0xed6
+#define XK_Hangul_J_Nieun 0xed7
+#define XK_Hangul_J_NieunJieuj 0xed8
+#define XK_Hangul_J_NieunHieuh 0xed9
+#define XK_Hangul_J_Dikeud 0xeda
+#define XK_Hangul_J_Rieul 0xedb
+#define XK_Hangul_J_RieulKiyeog 0xedc
+#define XK_Hangul_J_RieulMieum 0xedd
+#define XK_Hangul_J_RieulPieub 0xede
+#define XK_Hangul_J_RieulSios 0xedf
+#define XK_Hangul_J_RieulTieut 0xee0
+#define XK_Hangul_J_RieulPhieuf 0xee1
+#define XK_Hangul_J_RieulHieuh 0xee2
+#define XK_Hangul_J_Mieum 0xee3
+#define XK_Hangul_J_Pieub 0xee4
+#define XK_Hangul_J_PieubSios 0xee5
+#define XK_Hangul_J_Sios 0xee6
+#define XK_Hangul_J_SsangSios 0xee7
+#define XK_Hangul_J_Ieung 0xee8
+#define XK_Hangul_J_Jieuj 0xee9
+#define XK_Hangul_J_Cieuc 0xeea
+#define XK_Hangul_J_Khieuq 0xeeb
+#define XK_Hangul_J_Tieut 0xeec
+#define XK_Hangul_J_Phieuf 0xeed
+#define XK_Hangul_J_Hieuh 0xeee
+
+/* Ancient Hangul Consonant Characters */
+#define XK_Hangul_RieulYeorinHieuh 0xeef
+#define XK_Hangul_SunkyeongeumMieum 0xef0
+#define XK_Hangul_SunkyeongeumPieub 0xef1
+#define XK_Hangul_PanSios 0xef2
+#define XK_Hangul_KkogjiDalrinIeung 0xef3
+#define XK_Hangul_SunkyeongeumPhieuf 0xef4
+#define XK_Hangul_YeorinHieuh 0xef5
+
+/* Ancient Hangul Vowel Characters */
+#define XK_Hangul_AraeA 0xef6
+#define XK_Hangul_AraeAE 0xef7
+
+/* Ancient Hangul syllable-final (JongSeong) Characters */
+#define XK_Hangul_J_PanSios 0xef8
+#define XK_Hangul_J_KkogjiDalrinIeung 0xef9
+#define XK_Hangul_J_YeorinHieuh 0xefa
+
+/* Korean currency symbol */
+#define XK_Korean_Won 0xeff
+
+#endif /* XK_KOREAN */
+
+#ifdef XK_CURRENCY
+#define XK_EcuSign 0x20a0
+#define XK_ColonSign 0x20a1
+#define XK_CruzeiroSign 0x20a2
+#define XK_FFrancSign 0x20a3
+#define XK_LiraSign 0x20a4
+#define XK_MillSign 0x20a5
+#define XK_NairaSign 0x20a6
+#define XK_PesetaSign 0x20a7
+#define XK_RupeeSign 0x20a8
+#define XK_WonSign 0x20a9
+#define XK_NewSheqelSign 0x20aa
+#define XK_DongSign 0x20ab
+#define XK_EuroSign 0x20ac
+#endif
diff --git a/common/rfb/msgTypes.h b/common/rfb/msgTypes.h
new file mode 100644
index 00000000..f6f8d5cf
--- /dev/null
+++ b/common/rfb/msgTypes.h
@@ -0,0 +1,57 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#ifndef __RFB_MSGTYPES_H__
+#define __RFB_MSGTYPES_H__
+
+namespace rfb {
+ // server to client
+
+ const int msgTypeFramebufferUpdate = 0;
+ const int msgTypeSetColourMapEntries = 1;
+ const int msgTypeBell = 2;
+ const int msgTypeServerCutText = 3;
+
+ const int msgTypeFileListData = 130;
+ const int msgTypeFileDownloadData = 131;
+ const int msgTypeFileUploadCancel = 132;
+ const int msgTypeFileDownloadFailed = 133;
+ const int msgTypeFileDirSizeData = 134;
+ const int msgTypeFileLastRequestFailed = 135;
+
+ // client to server
+
+ const int msgTypeSetPixelFormat = 0;
+ const int msgTypeFixColourMapEntries = 1;
+ const int msgTypeSetEncodings = 2;
+ const int msgTypeFramebufferUpdateRequest = 3;
+ const int msgTypeKeyEvent = 4;
+ const int msgTypePointerEvent = 5;
+ const int msgTypeClientCutText = 6;
+
+ const int msgTypeFileListRequest = 130;
+ const int msgTypeFileDownloadRequest = 131;
+ const int msgTypeFileUploadRequest = 132;
+ const int msgTypeFileUploadData = 133;
+ const int msgTypeFileDownloadCancel = 134;
+ const int msgTypeFileUploadFailed = 135;
+ const int msgTypeFileCreateDirRequest = 136;
+ const int msgTypeFileDirSizeRequest = 137;
+ const int msgTypeFileRenameRequest = 138;
+ const int msgTypeFileDeleteRequest = 139;
+}
+#endif
diff --git a/common/rfb/rfb.dsp b/common/rfb/rfb.dsp
new file mode 100644
index 00000000..aef5e43c
--- /dev/null
+++ b/common/rfb/rfb.dsp
@@ -0,0 +1,767 @@
+# Microsoft Developer Studio Project File - Name="rfb" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=rfb - Win32 Debug Unicode
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "rfb.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "rfb.mak" CFG="rfb - Win32 Debug Unicode"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "rfb - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "rfb - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE "rfb - Win32 Debug Unicode" (based on "Win32 (x86) Static Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "rfb - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "..\Release"
+# PROP Intermediate_Dir "..\Release\rfb"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O1 /I ".." /I "../../win" /FI"rdr/msvcwarning.h" /D "NDEBUG" /D "_LIB" /D "WIN32" /D "_MBCS" /YX /FD /c
+# ADD BASE RSC /l 0x809 /d "NDEBUG"
+# ADD RSC /l 0x809 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ELSEIF "$(CFG)" == "rfb - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\Debug"
+# PROP Intermediate_Dir "..\Debug\rfb"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
+# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I ".." /I "../../win" /FI"rdr/msvcwarning.h" /D "_DEBUG" /D "_LIB" /D "WIN32" /D "_MBCS" /YX /FD /GZ /c
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ELSEIF "$(CFG)" == "rfb - Win32 Debug Unicode"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "rfb___Win32_Debug_Unicode"
+# PROP BASE Intermediate_Dir "rfb___Win32_Debug_Unicode"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\Debug_Unicode"
+# PROP Intermediate_Dir "..\Debug_Unicode\rfb"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I ".." /FI"msvcwarning.h" /D "_DEBUG" /D "_LIB" /D "WIN32" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I ".." /I "../../win" /FI"rdr/msvcwarning.h" /D "_LIB" /D "_DEBUG" /D "WIN32" /D "_UNICODE" /D "UNICODE" /YX /FD /GZ /c
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ENDIF
+
+# Begin Target
+
+# Name "rfb - Win32 Release"
+# Name "rfb - Win32 Debug"
+# Name "rfb - Win32 Debug Unicode"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\Blacklist.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\CConnection.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\CFTMsgReader.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\CFTMsgWriter.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\CMsgHandler.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\CMsgReader.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\CMsgReaderV3.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\CMsgWriter.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\CMsgWriterV3.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\ComparingUpdateTracker.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\Configuration.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\ConnParams.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\CSecurityVncAuth.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\Cursor.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\d3des.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\Decoder.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\Encoder.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\encodings.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\FileInfo.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\FileManager.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\FileReader.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\FileWriter.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\HextileDecoder.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\HextileEncoder.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\HTTPServer.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\KeyRemapper.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\Logger.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\Logger_file.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\Logger_stdio.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\LogWriter.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\Password.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\PixelBuffer.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\PixelFormat.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\RawDecoder.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\RawEncoder.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\Region.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\RREDecoder.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\RREEncoder.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\ScaledPixelBuffer.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\SConnection.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\secTypes.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\ServerCore.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\SFileTransfer.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\SFileTransferManager.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\SFTMsgReader.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\SFTMsgWriter.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\SMsgHandler.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\SMsgReader.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\SMsgReaderV3.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\SMsgWriter.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\SMsgWriterV3.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\SSecurityFactoryStandard.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\SSecurityVncAuth.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\TightDecoder.cxx
+# ADD CPP /I "../jpeg"
+# End Source File
+# Begin Source File
+
+SOURCE=.\TightEncoder.cxx
+# ADD CPP /I "../jpeg"
+# End Source File
+# Begin Source File
+
+SOURCE=.\TightPalette.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\TransferQueue.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\TransImageGetter.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\UpdateTracker.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\util.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\VNCSConnectionST.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\VNCServerST.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\ZRLEDecoder.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\ZRLEEncoder.cxx
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\Blacklist.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\CConnection.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\CFTMsgReader.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\CFTMsgWriter.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\CMsgHandler.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\CMsgReader.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\CMsgReaderV3.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\CMsgWriter.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\CMsgWriterV3.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ColourCube.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ColourMap.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ComparingUpdateTracker.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Configuration.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ConnParams.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\CSecurity.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\CSecurityNone.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\CSecurityVncAuth.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Cursor.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\d3des.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Decoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\DirManager.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Encoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\encodings.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Exception.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\FileInfo.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\FileManager.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\FileReader.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\FileWriter.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\hextileConstants.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\hextileDecode.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\HextileDecoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\hextileEncode.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\hextileEncodeBetter.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\HextileEncoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Hostname.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\HTTPServer.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ImageGetter.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\InputHandler.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\KeyRemapper.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\keysymdef.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ListConnInfo.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Logger.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Logger_file.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Logger_stdio.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\LogWriter.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\msgTypes.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\msvcwarning.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Password.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Pixel.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\PixelBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\PixelFormat.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\RawDecoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\RawEncoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Rect.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Region.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\rreDecode.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\RREDecoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\rreEncode.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\RREEncoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ScaledPixelBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\SConnection.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\SDesktop.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\secTypes.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ServerCore.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\SFileTransfer.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\SFileTransferManager.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\SFTMsgReader.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\SFTMsgWriter.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\SMsgHandler.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\SMsgReader.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\SMsgReaderV3.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\SMsgWriter.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\SMsgWriterV3.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\SSecurity.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\SSecurityFactoryStandard.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\SSecurityNone.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\SSecurityVncAuth.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Threading.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tightDecode.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\TightDecoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tightEncode.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\TightEncoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\TightPalette.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\TransferQueue.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\TransImageGetter.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\transInitTempl.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\transTempl.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\TrueColourMap.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\UpdateTracker.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\UserPasswdGetter.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\util.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\VNCSConnectionST.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\VNCServer.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\VNCServerST.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\zrleDecode.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ZRLEDecoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\zrleEncode.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ZRLEEncoder.h
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/common/rfb/rreDecode.h b/common/rfb/rreDecode.h
new file mode 100644
index 00000000..1f5bdf8b
--- /dev/null
+++ b/common/rfb/rreDecode.h
@@ -0,0 +1,64 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+//
+// RRE decoding function.
+//
+// This file is #included after having set the following macros:
+// BPP - 8, 16 or 32
+// EXTRA_ARGS - optional extra arguments
+// FILL_RECT - fill a rectangle with a single colour
+
+#include <rdr/InStream.h>
+
+namespace rfb {
+
+// CONCAT2E concatenates its arguments, expanding them if they are macros
+
+#ifndef CONCAT2E
+#define CONCAT2(a,b) a##b
+#define CONCAT2E(a,b) CONCAT2(a,b)
+#endif
+
+#define PIXEL_T rdr::CONCAT2E(U,BPP)
+#define READ_PIXEL CONCAT2E(readOpaque,BPP)
+#define RRE_DECODE CONCAT2E(rreDecode,BPP)
+
+void RRE_DECODE (const Rect& r, rdr::InStream* is
+#ifdef EXTRA_ARGS
+ , EXTRA_ARGS
+#endif
+ )
+{
+ int nSubrects = is->readU32();
+ PIXEL_T bg = is->READ_PIXEL();
+ FILL_RECT(r, bg);
+
+ for (int i = 0; i < nSubrects; i++) {
+ PIXEL_T pix = is->READ_PIXEL();
+ int x = is->readU16();
+ int y = is->readU16();
+ int w = is->readU16();
+ int h = is->readU16();
+ FILL_RECT(Rect(r.tl.x+x, r.tl.y+y, r.tl.x+x+w, r.tl.y+y+h), pix);
+ }
+}
+
+#undef PIXEL_T
+#undef READ_PIXEL
+#undef RRE_DECODE
+}
diff --git a/common/rfb/rreEncode.h b/common/rfb/rreEncode.h
new file mode 100644
index 00000000..3f834877
--- /dev/null
+++ b/common/rfb/rreEncode.h
@@ -0,0 +1,164 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+//
+// RRE encoding function.
+//
+// This file is #included after having set the following macros:
+// BPP - 8, 16 or 32
+//
+// The data argument to RRE_ENCODE contains the pixel data, and it writes the
+// encoded version to the given OutStream. If the encoded version exceeds w*h
+// it aborts and returns -1, otherwise it returns the number of subrectangles.
+//
+
+#include <rdr/OutStream.h>
+
+namespace rfb {
+
+// CONCAT2E concatenates its arguments, expanding them if they are macros
+
+#ifndef CONCAT2E
+#define CONCAT2(a,b) a##b
+#define CONCAT2E(a,b) CONCAT2(a,b)
+#endif
+
+#define PIXEL_T rdr::CONCAT2E(U,BPP)
+#define WRITE_PIXEL CONCAT2E(writeOpaque,BPP)
+#define RRE_ENCODE CONCAT2E(rreEncode,BPP)
+
+int RRE_ENCODE (PIXEL_T* data, int w, int h, rdr::OutStream* os, PIXEL_T bg);
+
+int RRE_ENCODE (void* data, int w, int h, rdr::OutStream* os)
+{
+ // Find the background colour - count occurrences of up to 4 different pixel
+ // values, and choose the one which occurs most often.
+
+ const int nCols = 4;
+ PIXEL_T pix[nCols];
+ int count[nCols] = { 0, };
+ PIXEL_T* ptr = (PIXEL_T*)data;
+ PIXEL_T* end = ptr + w*h;
+
+ while (ptr < end) {
+ int i;
+ for (i = 0; i < nCols; i++) {
+ if (count[i] == 0)
+ pix[i] = *ptr;
+
+ if (pix[i] == *ptr) {
+ count[i]++;
+ break;
+ }
+ }
+
+ if (i == nCols) break;
+ ptr++;
+ }
+
+ int bg = 0;
+ for (int i = 1; i < nCols; i++)
+ if (count[i] > count[bg]) bg = i;
+
+ // Now call the function to do the encoding.
+
+ return RRE_ENCODE ((PIXEL_T*)data, w, h, os, pix[bg]);
+}
+
+int RRE_ENCODE (PIXEL_T* data, int w, int h, rdr::OutStream* os, PIXEL_T bg)
+{
+ int oldLen = os->length();
+ os->WRITE_PIXEL(bg);
+
+ int nSubrects = 0;
+
+ for (int y = 0; y < h; y++)
+ {
+ int x = 0;
+ while (x < w) {
+ if (*data == bg) {
+ x++;
+ data++;
+ continue;
+ }
+
+ // Find horizontal subrect first
+ PIXEL_T* ptr = data+1;
+ PIXEL_T* eol = data+w-x;
+ while (ptr < eol && *ptr == *data) ptr++;
+ int sw = ptr - data;
+
+ ptr = data + w;
+ int sh = 1;
+ while (sh < h-y) {
+ eol = ptr + sw;
+ while (ptr < eol)
+ if (*ptr++ != *data) goto endOfHorizSubrect;
+ ptr += w - sw;
+ sh++;
+ }
+ endOfHorizSubrect:
+
+ // Find vertical subrect
+ int vh;
+ for (vh = sh; vh < h-y; vh++)
+ if (data[vh*w] != *data) break;
+
+ if (vh != sh) {
+ ptr = data+1;
+ int vw;
+ for (vw = 1; vw < sw; vw++) {
+ for (int i = 0; i < vh; i++)
+ if (ptr[i*w] != *data) goto endOfVertSubrect;
+ ptr++;
+ }
+ endOfVertSubrect:
+
+ // If vertical subrect bigger than horizontal then use that.
+ if (sw*sh < vw*vh) {
+ sw = vw;
+ sh = vh;
+ }
+ }
+
+ nSubrects++;
+ os->WRITE_PIXEL(*data);
+ os->writeU16(x);
+ os->writeU16(y);
+ os->writeU16(sw);
+ os->writeU16(sh);
+ if (os->length() > oldLen + w*h) return -1;
+
+ ptr = data+w;
+ PIXEL_T* eor = data+w*sh;
+ while (ptr < eor) {
+ eol = ptr + sw;
+ while (ptr < eol) *ptr++ = bg;
+ ptr += w - sw;
+ }
+ x += sw;
+ data += sw;
+ }
+ }
+
+ return nSubrects;
+}
+
+#undef PIXEL_T
+#undef WRITE_PIXEL
+#undef RRE_ENCODE
+}
diff --git a/common/rfb/secTypes.cxx b/common/rfb/secTypes.cxx
new file mode 100644
index 00000000..830d8444
--- /dev/null
+++ b/common/rfb/secTypes.cxx
@@ -0,0 +1,73 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#include <string.h>
+#ifdef _WIN32
+#define strcasecmp _stricmp
+#endif
+#include <rfb/secTypes.h>
+#include <rfb/util.h>
+
+int rfb::secTypeNum(const char* name)
+{
+ if (strcasecmp(name, "None") == 0) return secTypeNone;
+ if (strcasecmp(name, "VncAuth") == 0) return secTypeVncAuth;
+ if (strcasecmp(name, "Tight") == 0) return secTypeTight;
+ if (strcasecmp(name, "RA2") == 0) return secTypeRA2;
+ if (strcasecmp(name, "RA2ne") == 0) return secTypeRA2ne;
+ if (strcasecmp(name, "SSPI") == 0) return secTypeSSPI;
+ if (strcasecmp(name, "SSPIne") == 0) return secTypeSSPIne;
+ return secTypeInvalid;
+}
+
+const char* rfb::secTypeName(int num)
+{
+ switch (num) {
+ case secTypeNone: return "None";
+ case secTypeVncAuth: return "VncAuth";
+ case secTypeTight: return "Tight";
+ case secTypeRA2: return "RA2";
+ case secTypeRA2ne: return "RA2ne";
+ case secTypeSSPI: return "SSPI";
+ case secTypeSSPIne: return "SSPIne";
+ default: return "[unknown secType]";
+ }
+}
+
+bool rfb::secTypeEncrypts(int num)
+{
+ switch (num) {
+ case secTypeRA2:
+ case secTypeSSPI:
+ return true;
+ default:
+ return false;
+ }
+}
+
+std::list<int> rfb::parseSecTypes(const char* types_)
+{
+ std::list<int> result;
+ CharArray types(strDup(types_)), type;
+ while (types.buf) {
+ strSplit(types.buf, ',', &type.buf, &types.buf);
+ int typeNum = secTypeNum(type.buf);
+ if (typeNum != secTypeInvalid)
+ result.push_back(typeNum);
+ }
+ return result;
+}
diff --git a/common/rfb/secTypes.h b/common/rfb/secTypes.h
new file mode 100644
index 00000000..3cf783bd
--- /dev/null
+++ b/common/rfb/secTypes.h
@@ -0,0 +1,54 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+//
+// secTypes.h - constants for the various security types.
+//
+
+#ifndef __RFB_SECTYPES_H__
+#define __RFB_SECTYPES_H__
+
+#include <list>
+
+namespace rfb {
+ const int secTypeInvalid = 0;
+ const int secTypeNone = 1;
+ const int secTypeVncAuth = 2;
+
+ const int secTypeRA2 = 5;
+ const int secTypeRA2ne = 6;
+
+ const int secTypeSSPI = 7;
+ const int secTypeSSPIne = 8;
+
+ const int secTypeTight = 16;
+ const int secTypeUltra = 17;
+ const int secTypeTLS = 18;
+
+ // result types
+
+ const int secResultOK = 0;
+ const int secResultFailed = 1;
+ const int secResultTooMany = 2; // deprecated
+
+ const char* secTypeName(int num);
+ int secTypeNum(const char* name);
+ bool secTypeEncrypts(int num);
+ std::list<int> parseSecTypes(const char* types);
+}
+
+#endif
diff --git a/common/rfb/tightDecode.h b/common/rfb/tightDecode.h
new file mode 100644
index 00000000..dd0c4d97
--- /dev/null
+++ b/common/rfb/tightDecode.h
@@ -0,0 +1,412 @@
+/* Copyright (C) 2000-2003 Constantin Kaplinsky. All Rights Reserved.
+ * Copyright (C) 2004-2005 Cendio AB. All rights reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+//
+// Tight decoding functions.
+//
+// This file is #included after having set the following macros:
+// BPP - 8, 16 or 32
+// EXTRA_ARGS - optional extra arguments
+// FILL_RECT - fill a rectangle with a single color
+// IMAGE_RECT - draw a rectangle of pixel data from a buffer
+
+#include <rdr/InStream.h>
+#include <rdr/ZlibInStream.h>
+#include <rfb/Exception.h>
+#include <assert.h>
+
+namespace rfb {
+
+// CONCAT2E concatenates its arguments, expanding them if they are macros
+
+#ifndef CONCAT2E
+#define CONCAT2(a,b) a##b
+#define CONCAT2E(a,b) CONCAT2(a,b)
+#endif
+
+#define PIXEL_T rdr::CONCAT2E(U,BPP)
+#define READ_PIXEL CONCAT2E(readOpaque,BPP)
+#define TIGHT_DECODE CONCAT2E(tightDecode,BPP)
+
+#define TIGHT_MIN_TO_COMPRESS 12
+static bool DecompressJpegRect(const Rect& r, rdr::InStream* is,
+ PIXEL_T* buf, CMsgHandler* handler);
+static void FilterGradient(const Rect& r, rdr::InStream* is, int dataSize,
+ PIXEL_T* buf, CMsgHandler* handler);
+#if BPP == 32
+static void FilterGradient24(const Rect& r, rdr::InStream* is, int dataSize,
+ PIXEL_T* buf, CMsgHandler* handler);
+#endif
+
+// Main function implementing Tight decoder
+
+void TIGHT_DECODE (const Rect& r, rdr::InStream* is,
+ rdr::ZlibInStream zis[], PIXEL_T* buf
+#ifdef EXTRA_ARGS
+ , EXTRA_ARGS
+#endif
+ )
+{
+ rdr::U8 *bytebuf = (rdr::U8*) buf;
+ bool cutZeros = false;
+ const rfb::PixelFormat& myFormat = handler->cp.pf();
+#if BPP == 32
+ if (myFormat.depth == 24 && myFormat.redMax == 0xFF &&
+ myFormat.greenMax == 0xFF && myFormat.blueMax == 0xFF) {
+ cutZeros = true;
+ }
+#endif
+
+ rdr::U8 comp_ctl = is->readU8();
+
+ // Flush zlib streams if we are told by the server to do so.
+ for (int i = 0; i < 4; i++) {
+ if (comp_ctl & 1) {
+ zis[i].reset();
+ }
+ comp_ctl >>= 1;
+ }
+
+ // "Fill" compression type.
+ if (comp_ctl == rfbTightFill) {
+ PIXEL_T pix;
+ if (cutZeros) {
+ is->readBytes(bytebuf, 3);
+ pix = RGB24_TO_PIXEL32(bytebuf[0], bytebuf[1], bytebuf[2]);
+ } else {
+ pix = is->READ_PIXEL();
+ }
+ FILL_RECT(r, pix);
+ return;
+ }
+
+ // "JPEG" compression type.
+ if (comp_ctl == rfbTightJpeg) {
+ DecompressJpegRect(r, is, buf, handler);
+ return;
+ }
+
+ // Quit on unsupported compression type.
+ if (comp_ctl > rfbTightMaxSubencoding) {
+ throw Exception("TightDecoder: bad subencoding value received");
+ return;
+ }
+
+ // "Basic" compression type.
+ int palSize = 0;
+ static PIXEL_T palette[256];
+ bool useGradient = false;
+
+ if ((comp_ctl & rfbTightExplicitFilter) != 0) {
+ rdr::U8 filterId = is->readU8();
+
+ switch (filterId) {
+ case rfbTightFilterPalette:
+ palSize = is->readU8() + 1;
+ if (cutZeros) {
+ rdr::U8 *tightPalette = (rdr::U8*) palette;
+ is->readBytes(tightPalette, palSize*3);
+ for (int i = palSize - 1; i >= 0; i--) {
+ palette[i] = RGB24_TO_PIXEL32(tightPalette[i*3],
+ tightPalette[i*3+1],
+ tightPalette[i*3+2]);
+ }
+ } else {
+ for (int i = 0; i < palSize; i++)
+ palette[i] = is->READ_PIXEL();
+ }
+ break;
+ case rfbTightFilterGradient:
+ useGradient = true;
+ break;
+ case rfbTightFilterCopy:
+ break;
+ default:
+ throw Exception("TightDecoder: unknown filter code received");
+ return;
+ }
+ }
+
+ int bppp = BPP;
+ if (palSize != 0) {
+ bppp = (palSize <= 2) ? 1 : 8;
+ } else if (cutZeros) {
+ bppp = 24;
+ }
+
+ // Determine if the data should be decompressed or just copied.
+ int rowSize = (r.width() * bppp + 7) / 8;
+ int dataSize = r.height() * rowSize;
+ int streamId = -1;
+ rdr::InStream *input;
+ if (dataSize < TIGHT_MIN_TO_COMPRESS) {
+ input = is;
+ } else {
+ int length = is->readCompactLength();
+ streamId = comp_ctl & 0x03;
+ zis[streamId].setUnderlying(is, length);
+ input = &zis[streamId];
+ }
+
+ if (palSize == 0) {
+ // Truecolor data
+ if (useGradient) {
+#if BPP == 32
+ if (cutZeros) {
+ FilterGradient24(r, input, dataSize, buf, handler);
+ } else
+#endif
+ {
+ FilterGradient(r, input, dataSize, buf, handler);
+ }
+ } else {
+ input->readBytes(buf, dataSize);
+ if (cutZeros) {
+ for (int p = r.height() * r.width() - 1; p >= 0; p--) {
+ buf[p] = RGB24_TO_PIXEL32(bytebuf[p*3],
+ bytebuf[p*3+1],
+ bytebuf[p*3+2]);
+ }
+ }
+ }
+ } else {
+ int x, y, b, w;
+ PIXEL_T *ptr = buf;
+ rdr::U8 bits;
+ if (palSize <= 2) {
+ // 2-color palette
+ w = (r.width() + 7) / 8;
+ for (y = 0; y < r.height(); y++) {
+ for (x = 0; x < r.width() / 8; x++) {
+ bits = input->readU8();
+ for (b = 7; b >= 0; b--) {
+ *ptr++ = palette[bits >> b & 1];
+ }
+ }
+ if (r.width() % 8 != 0) {
+ bits = input->readU8();
+ for (b = 7; b >= 8 - r.width() % 8; b--) {
+ *ptr++ = palette[bits >> b & 1];
+ }
+ }
+ }
+ } else {
+ // 256-color palette
+ for (y = 0; y < r.height(); y++) {
+ for (x = 0; x < r.width(); x++) {
+ *ptr++ = palette[input->readU8()];
+ }
+ }
+ }
+ }
+
+ IMAGE_RECT(r, buf);
+
+ if (streamId != -1) {
+ zis[streamId].reset();
+ }
+}
+
+static bool
+DecompressJpegRect(const Rect& r, rdr::InStream* is,
+ PIXEL_T* buf, CMsgHandler* handler)
+{
+ struct jpeg_decompress_struct cinfo;
+ struct jpeg_error_mgr jerr;
+ PIXEL_T *pixelPtr = buf;
+ static rdr::U8 scanline_buffer[TIGHT_MAX_WIDTH*3];
+ JSAMPROW scanline = scanline_buffer;
+
+ // Read length
+ int compressedLen = is->readCompactLength();
+ if (compressedLen <= 0) {
+ throw Exception("Incorrect data received from the server.\n");
+ }
+
+ // Allocate netbuf and read in data
+ rdr::U8* netbuf = new rdr::U8[compressedLen];
+ if (!netbuf) {
+ throw Exception("rfb::tightDecode unable to allocate buffer");
+ }
+ is->readBytes(netbuf, compressedLen);
+
+ // Set up JPEG decompression
+ cinfo.err = jpeg_std_error(&jerr);
+ jpeg_create_decompress(&cinfo);
+ JpegSetSrcManager(&cinfo, (char*)netbuf, compressedLen);
+ jpeg_read_header(&cinfo, TRUE);
+ cinfo.out_color_space = JCS_RGB;
+
+ jpeg_start_decompress(&cinfo);
+ if (cinfo.output_width != (unsigned)r.width() || cinfo.output_height != (unsigned)r.height() ||
+ cinfo.output_components != 3) {
+ jpeg_destroy_decompress(&cinfo);
+ throw Exception("Tight Encoding: Wrong JPEG data received.\n");
+ }
+
+ // Decompress
+ const rfb::PixelFormat& myFormat = handler->cp.pf();
+ while (cinfo.output_scanline < cinfo.output_height) {
+ jpeg_read_scanlines(&cinfo, &scanline, 1);
+ if (jpegError) {
+ break;
+ }
+
+ for (int dx = 0; dx < r.width(); dx++) {
+ *pixelPtr++ =
+ RGB24_TO_PIXEL(scanline[dx*3], scanline[dx*3+1], scanline[dx*3+2]);
+ }
+ }
+
+ IMAGE_RECT(r, buf);
+
+ if (!jpegError) {
+ jpeg_finish_decompress(&cinfo);
+ }
+
+ jpeg_destroy_decompress(&cinfo);
+
+ delete [] netbuf;
+
+ return !jpegError;
+}
+
+#if BPP == 32
+
+static void
+FilterGradient24(const Rect& r, rdr::InStream* is, int dataSize,
+ PIXEL_T* buf, CMsgHandler* handler)
+{
+ int x, y, c;
+ static rdr::U8 prevRow[TIGHT_MAX_WIDTH*3];
+ static rdr::U8 thisRow[TIGHT_MAX_WIDTH*3];
+ rdr::U8 pix[3];
+ int est[3];
+
+ memset(prevRow, 0, sizeof(prevRow));
+
+ // Allocate netbuf and read in data
+ rdr::U8 *netbuf = new rdr::U8[dataSize];
+ if (!netbuf) {
+ throw Exception("rfb::tightDecode unable to allocate buffer");
+ }
+ is->readBytes(netbuf, dataSize);
+
+ // Set up shortcut variables
+ const rfb::PixelFormat& myFormat = handler->cp.pf();
+ int rectHeight = r.height();
+ int rectWidth = r.width();
+
+ for (y = 0; y < rectHeight; y++) {
+ /* First pixel in a row */
+ for (c = 0; c < 3; c++) {
+ pix[c] = netbuf[y*rectWidth*3+c] + prevRow[c];
+ thisRow[c] = pix[c];
+ }
+ buf[y*rectWidth] = RGB24_TO_PIXEL32(pix[0], pix[1], pix[2]);
+
+ /* Remaining pixels of a row */
+ for (x = 1; x < rectWidth; x++) {
+ for (c = 0; c < 3; c++) {
+ est[c] = prevRow[x*3+c] + pix[c] - prevRow[(x-1)*3+c];
+ if (est[c] > 0xff) {
+ est[c] = 0xff;
+ } else if (est[c] < 0) {
+ est[c] = 0;
+ }
+ pix[c] = netbuf[(y*rectWidth+x)*3+c] + est[c];
+ thisRow[x*3+c] = pix[c];
+ }
+ buf[y*rectWidth+x] = RGB24_TO_PIXEL32(pix[0], pix[1], pix[2]);
+ }
+
+ memcpy(prevRow, thisRow, sizeof(prevRow));
+ }
+
+ delete [] netbuf;
+}
+
+#endif
+
+static void
+FilterGradient(const Rect& r, rdr::InStream* is, int dataSize,
+ PIXEL_T* buf, CMsgHandler* handler)
+{
+ int x, y, c;
+ static rdr::U8 prevRow[TIGHT_MAX_WIDTH*sizeof(PIXEL_T)];
+ static rdr::U8 thisRow[TIGHT_MAX_WIDTH*sizeof(PIXEL_T)];
+ int pix[3];
+ int max[3];
+ int shift[3];
+ int est[3];
+
+ memset(prevRow, 0, sizeof(prevRow));
+
+ // Allocate netbuf and read in data
+ PIXEL_T *netbuf = (PIXEL_T*)new rdr::U8[dataSize];
+ if (!netbuf) {
+ throw Exception("rfb::tightDecode unable to allocate buffer");
+ }
+ is->readBytes(netbuf, dataSize);
+
+ // Set up shortcut variables
+ const rfb::PixelFormat& myFormat = handler->cp.pf();
+ max[0] = myFormat.redMax;
+ max[1] = myFormat.greenMax;
+ max[2] = myFormat.blueMax;
+ shift[0] = myFormat.redShift;
+ shift[1] = myFormat.greenShift;
+ shift[2] = myFormat.blueShift;
+ int rectHeight = r.height();
+ int rectWidth = r.width();
+
+ for (y = 0; y < rectHeight; y++) {
+ /* First pixel in a row */
+ for (c = 0; c < 3; c++) {
+ pix[c] = (netbuf[y*rectWidth] >> shift[c]) + prevRow[c] & max[c];
+ thisRow[c] = pix[c];
+ }
+ buf[y*rectWidth] = RGB_TO_PIXEL(pix[0], pix[1], pix[2]);
+
+ /* Remaining pixels of a row */
+ for (x = 1; x < rectWidth; x++) {
+ for (c = 0; c < 3; c++) {
+ est[c] = prevRow[x*3+c] + pix[c] - prevRow[(x-1)*3+c];
+ if (est[c] > max[c]) {
+ est[c] = max[c];
+ } else if (est[c] < 0) {
+ est[c] = 0;
+ }
+ pix[c] = (netbuf[y*rectWidth+x] >> shift[c]) + est[c] & max[c];
+ thisRow[x*3+c] = pix[c];
+ }
+ buf[y*rectWidth+x] = RGB_TO_PIXEL(pix[0], pix[1], pix[2]);
+ }
+
+ memcpy(prevRow, thisRow, sizeof(prevRow));
+ }
+
+ delete [] netbuf;
+}
+
+#undef TIGHT_MIN_TO_COMPRESS
+#undef TIGHT_DECODE
+#undef READ_PIXEL
+#undef PIXEL_T
+}
diff --git a/common/rfb/tightEncode.h b/common/rfb/tightEncode.h
new file mode 100644
index 00000000..71f076e6
--- /dev/null
+++ b/common/rfb/tightEncode.h
@@ -0,0 +1,720 @@
+/* Copyright (C) 2000-2003 Constantin Kaplinsky. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+//
+// tightEncode.h - Tight encoding function.
+//
+// This file is #included after having set the following macros:
+// BPP - 8, 16 or 32
+// EXTRA_ARGS - optional extra arguments
+// GET_IMAGE_INTO_BUF - gets a rectangle of pixel data into a buffer
+//
+
+#include <rdr/OutStream.h>
+#include <rdr/ZlibOutStream.h>
+#include <assert.h>
+
+namespace rfb {
+
+// CONCAT2E concatenates its arguments, expanding them if they are macros
+
+#ifndef CONCAT2E
+#define CONCAT2(a,b) a##b
+#define CONCAT2E(a,b) CONCAT2(a,b)
+#endif
+
+#define PIXEL_T rdr::CONCAT2E(U,BPP)
+#define WRITE_PIXEL CONCAT2E(writeOpaque,BPP)
+#define TIGHT_ENCODE CONCAT2E(tightEncode,BPP)
+#define SWAP_PIXEL CONCAT2E(SWAP,BPP)
+#define HASH_FUNCTION CONCAT2E(HASH_FUNC,BPP)
+#define PACK_PIXELS CONCAT2E(packPixels,BPP)
+#define DETECT_SMOOTH_IMAGE CONCAT2E(detectSmoothImage,BPP)
+#define ENCODE_SOLID_RECT CONCAT2E(encodeSolidRect,BPP)
+#define ENCODE_FULLCOLOR_RECT CONCAT2E(encodeFullColorRect,BPP)
+#define ENCODE_MONO_RECT CONCAT2E(encodeMonoRect,BPP)
+#define ENCODE_INDEXED_RECT CONCAT2E(encodeIndexedRect,BPP)
+#define PREPARE_JPEG_ROW CONCAT2E(prepareJpegRow,BPP)
+#define ENCODE_JPEG_RECT CONCAT2E(encodeJpegRect,BPP)
+#define FILL_PALETTE CONCAT2E(fillPalette,BPP)
+
+#ifndef TIGHT_ONCE
+#define TIGHT_ONCE
+
+//
+// C-style structures to store palette entries and compression paramentes.
+// Such code probably should be converted into C++ classes.
+//
+
+struct TIGHT_COLOR_LIST {
+ TIGHT_COLOR_LIST *next;
+ int idx;
+ rdr::U32 rgb;
+};
+
+struct TIGHT_PALETTE_ENTRY {
+ TIGHT_COLOR_LIST *listNode;
+ int numPixels;
+};
+
+struct TIGHT_PALETTE {
+ TIGHT_PALETTE_ENTRY entry[256];
+ TIGHT_COLOR_LIST *hash[256];
+ TIGHT_COLOR_LIST list[256];
+};
+
+// FIXME: Is it really a good idea to use static variables for this?
+static int s_endianMismatch; // local/remote formats differ in byte order
+static bool s_pack24; // use 24-bit packing for 32-bit pixels
+static int s_rs, s_gs, s_bs; // shifts for 24-bit pixel conversion
+
+// FIXME: Make a separate class for palette operations.
+static int s_palMaxColors, s_palNumColors;
+static rdr::U32 s_monoBackground, s_monoForeground;
+static TIGHT_PALETTE s_palette;
+
+//
+// Swapping bytes in pixels.
+// FIXME: Use a sort of ImageGetter that does not convert pixel format?
+//
+
+#ifndef SWAP16
+#define SWAP16(n) ((((n) & 0xff) << 8) | (((n) >> 8) & 0xff))
+#endif
+#ifndef SWAP32
+#define SWAP32(n) (((n) >> 24) | (((n) & 0x00ff0000) >> 8) | \
+ (((n) & 0x0000ff00) << 8) | ((n) << 24))
+#endif
+
+//
+// Functions to operate on palette structures.
+//
+
+#define HASH_FUNC16(rgb) ((int)(((rgb >> 8) + rgb) & 0xFF))
+#define HASH_FUNC32(rgb) ((int)(((rgb >> 16) + (rgb >> 8)) & 0xFF))
+
+static void paletteReset(void)
+{
+ s_palNumColors = 0;
+ memset(s_palette.hash, 0, 256 * sizeof(TIGHT_COLOR_LIST *));
+}
+
+static int paletteInsert(rdr::U32 rgb, int numPixels, int bpp)
+{
+ TIGHT_COLOR_LIST *pnode;
+ TIGHT_COLOR_LIST *prev_pnode = NULL;
+ int hash_key, idx, new_idx, count;
+
+ hash_key = (bpp == 16) ? HASH_FUNC16(rgb) : HASH_FUNC32(rgb);
+
+ pnode = s_palette.hash[hash_key];
+
+ while (pnode != NULL) {
+ if (pnode->rgb == rgb) {
+ // Such palette entry already exists.
+ new_idx = idx = pnode->idx;
+ count = s_palette.entry[idx].numPixels + numPixels;
+ if (new_idx && s_palette.entry[new_idx-1].numPixels < count) {
+ do {
+ s_palette.entry[new_idx] = s_palette.entry[new_idx-1];
+ s_palette.entry[new_idx].listNode->idx = new_idx;
+ new_idx--;
+ }
+ while (new_idx &&
+ s_palette.entry[new_idx-1].numPixels < count);
+ s_palette.entry[new_idx].listNode = pnode;
+ pnode->idx = new_idx;
+ }
+ s_palette.entry[new_idx].numPixels = count;
+ return s_palNumColors;
+ }
+ prev_pnode = pnode;
+ pnode = pnode->next;
+ }
+
+ // Check if palette is full.
+ if ( s_palNumColors == 256 || s_palNumColors == s_palMaxColors ) {
+ s_palNumColors = 0;
+ return 0;
+ }
+
+ // Move palette entries with lesser pixel counts.
+ for ( idx = s_palNumColors;
+ idx > 0 && s_palette.entry[idx-1].numPixels < numPixels;
+ idx-- ) {
+ s_palette.entry[idx] = s_palette.entry[idx-1];
+ s_palette.entry[idx].listNode->idx = idx;
+ }
+
+ // Add new palette entry into the freed slot.
+ pnode = &s_palette.list[s_palNumColors];
+ if (prev_pnode != NULL) {
+ prev_pnode->next = pnode;
+ } else {
+ s_palette.hash[hash_key] = pnode;
+ }
+ pnode->next = NULL;
+ pnode->idx = idx;
+ pnode->rgb = rgb;
+ s_palette.entry[idx].listNode = pnode;
+ s_palette.entry[idx].numPixels = numPixels;
+
+ return (++s_palNumColors);
+}
+
+//
+// Compress the data (but do not perform actual compression if the data
+// size is less than TIGHT_MIN_TO_COMPRESS bytes.
+//
+
+static void compressData(rdr::OutStream *os, rdr::ZlibOutStream *zos,
+ const void *buf, unsigned int length, int zlibLevel)
+{
+ if (length < TIGHT_MIN_TO_COMPRESS) {
+ os->writeBytes(buf, length);
+ } else {
+ // FIXME: Using a temporary MemOutStream may be not efficient.
+ // Maybe use the same static object used in the JPEG coder?
+ rdr::MemOutStream mem_os;
+ zos->setUnderlying(&mem_os);
+ zos->setCompressionLevel(zlibLevel);
+ zos->writeBytes(buf, length);
+ zos->flush();
+ os->writeCompactLength(mem_os.length());
+ os->writeBytes(mem_os.data(), mem_os.length());
+ }
+}
+
+//
+// Destination manager implementation for the JPEG library.
+// FIXME: Implement JPEG compression in new rdr::JpegOutStream class.
+//
+
+// FIXME: Keeping a MemOutStream instance may consume too much space.
+rdr::MemOutStream s_jpeg_os;
+
+static struct jpeg_destination_mgr s_jpegDstManager;
+static JOCTET *s_jpegDstBuffer;
+static size_t s_jpegDstBufferLen;
+
+static void
+JpegInitDestination(j_compress_ptr cinfo)
+{
+ s_jpeg_os.clear();
+ s_jpegDstManager.next_output_byte = s_jpegDstBuffer;
+ s_jpegDstManager.free_in_buffer = s_jpegDstBufferLen;
+}
+
+static boolean
+JpegEmptyOutputBuffer(j_compress_ptr cinfo)
+{
+ s_jpeg_os.writeBytes(s_jpegDstBuffer, s_jpegDstBufferLen);
+ s_jpegDstManager.next_output_byte = s_jpegDstBuffer;
+ s_jpegDstManager.free_in_buffer = s_jpegDstBufferLen;
+
+ return TRUE;
+}
+
+static void
+JpegTermDestination(j_compress_ptr cinfo)
+{
+ int dataLen = s_jpegDstBufferLen - s_jpegDstManager.free_in_buffer;
+ s_jpeg_os.writeBytes(s_jpegDstBuffer, dataLen);
+}
+
+static void
+JpegSetDstManager(j_compress_ptr cinfo, JOCTET *buf, size_t buflen)
+{
+ s_jpegDstBuffer = buf;
+ s_jpegDstBufferLen = buflen;
+ s_jpegDstManager.init_destination = JpegInitDestination;
+ s_jpegDstManager.empty_output_buffer = JpegEmptyOutputBuffer;
+ s_jpegDstManager.term_destination = JpegTermDestination;
+ cinfo->dest = &s_jpegDstManager;
+}
+
+#endif // #ifndef TIGHT_ONCE
+
+static void ENCODE_SOLID_RECT (rdr::OutStream *os,
+ PIXEL_T *buf);
+static void ENCODE_FULLCOLOR_RECT (rdr::OutStream *os, rdr::ZlibOutStream zos[4],
+ PIXEL_T *buf, const Rect& r);
+static void ENCODE_MONO_RECT (rdr::OutStream *os, rdr::ZlibOutStream zos[4],
+ PIXEL_T *buf, const Rect& r);
+#if (BPP != 8)
+static void ENCODE_INDEXED_RECT (rdr::OutStream *os, rdr::ZlibOutStream zos[4],
+ PIXEL_T *buf, const Rect& r);
+static void ENCODE_JPEG_RECT (rdr::OutStream *os,
+ PIXEL_T *buf, const PixelFormat& pf, const Rect& r);
+#endif
+
+static void FILL_PALETTE (PIXEL_T *data, int count);
+
+//
+// Convert 32-bit color samples into 24-bit colors, in place.
+// Performs packing only when redMax, greenMax and blueMax are all 255.
+// Color components are assumed to be byte-aligned.
+//
+
+static inline unsigned int PACK_PIXELS (PIXEL_T *buf, unsigned int count)
+{
+#if (BPP != 32)
+ return count * sizeof(PIXEL_T);
+#else
+ if (!s_pack24)
+ return count * sizeof(PIXEL_T);
+
+ rdr::U32 pix;
+ rdr::U8 *dst = (rdr::U8 *)buf;
+ for (unsigned int i = 0; i < count; i++) {
+ pix = *buf++;
+ *dst++ = (rdr::U8)(pix >> s_rs);
+ *dst++ = (rdr::U8)(pix >> s_gs);
+ *dst++ = (rdr::U8)(pix >> s_bs);
+ }
+ return count * 3;
+#endif
+}
+
+//
+// Function to guess if a given rectangle is suitable for JPEG compression.
+// Returns true is it looks like a good data for JPEG, false otherwise.
+//
+// FIXME: Scan the image and determine is it really good for JPEG.
+//
+
+#if (BPP != 8)
+static bool DETECT_SMOOTH_IMAGE (PIXEL_T *buf, const Rect& r)
+{
+ if (r.width() < TIGHT_DETECT_MIN_WIDTH ||
+ r.height() < TIGHT_DETECT_MIN_HEIGHT ||
+ r.area() < TIGHT_JPEG_MIN_RECT_SIZE ||
+ s_pjconf == NULL)
+ return 0;
+
+ return 1;
+}
+#endif
+
+// FIXME: Split rectangles into smaller ones!
+// FIXME: Compare encoder code with 1.3 before the final version.
+
+//
+// Main function of the Tight encoder
+//
+
+void TIGHT_ENCODE (const Rect& r, rdr::OutStream *os,
+ rdr::ZlibOutStream zos[4], void* buf, ConnParams* cp
+#ifdef EXTRA_ARGS
+ , EXTRA_ARGS
+#endif
+ )
+{
+ const PixelFormat& pf = cp->pf();
+ GET_IMAGE_INTO_BUF(r, buf);
+ PIXEL_T* pixels = (PIXEL_T*)buf;
+
+#if (BPP != 8)
+ union {
+ rdr::U32 value32;
+ rdr::U8 test;
+ } littleEndian;
+ littleEndian.value32 = 1;
+ s_endianMismatch = (littleEndian.test != !pf.bigEndian);
+#endif
+
+#if (BPP == 32)
+ // Check if it's necessary to pack 24-bit pixels, and
+ // compute appropriate shift values if necessary.
+ s_pack24 = (pf.depth == 24 && pf.redMax == 0xFF &&
+ pf.greenMax == 0xFF && pf.blueMax == 0xFF);
+ if (s_pack24) {
+ if (!s_endianMismatch) {
+ s_rs = pf.redShift;
+ s_gs = pf.greenShift;
+ s_bs = pf.blueShift;
+ } else {
+ s_rs = 24 - pf.redShift;
+ s_gs = 24 - pf.greenShift;
+ s_bs = 24 - pf.blueShift;
+ }
+ }
+#endif
+
+ s_palMaxColors = r.area() / s_pconf->idxMaxColorsDivisor;
+ if (s_palMaxColors < 2 && r.area() >= s_pconf->monoMinRectSize) {
+ s_palMaxColors = 2;
+ }
+ // FIXME: Temporary limitation for switching to JPEG earlier.
+ if (s_palMaxColors > 96 && s_pjconf != NULL) {
+ s_palMaxColors = 96;
+ }
+
+ FILL_PALETTE(pixels, r.area());
+
+ switch (s_palNumColors) {
+ case 0:
+ // Truecolor image
+#if (BPP != 8)
+ if (s_pjconf != NULL && DETECT_SMOOTH_IMAGE(pixels, r)) {
+ ENCODE_JPEG_RECT(os, pixels, pf, r);
+ break;
+ }
+#endif
+ ENCODE_FULLCOLOR_RECT(os, zos, pixels, r);
+ break;
+ case 1:
+ // Solid rectangle
+ ENCODE_SOLID_RECT(os, pixels);
+ break;
+ case 2:
+ // Two-color rectangle
+ ENCODE_MONO_RECT(os, zos, pixels, r);
+ break;
+#if (BPP != 8)
+ default:
+ // Up to 256 different colors
+ ENCODE_INDEXED_RECT(os, zos, pixels, r);
+#endif
+ }
+}
+
+//
+// Subencoding implementations.
+//
+
+static void ENCODE_SOLID_RECT (rdr::OutStream *os, PIXEL_T *buf)
+{
+ os->writeU8(0x08 << 4);
+
+ int length = PACK_PIXELS(buf, 1);
+ os->writeBytes(buf, length);
+}
+
+static void ENCODE_FULLCOLOR_RECT (rdr::OutStream *os, rdr::ZlibOutStream zos[4],
+ PIXEL_T *buf, const Rect& r)
+{
+ const int streamId = 0;
+ os->writeU8(streamId << 4);
+
+ int length = PACK_PIXELS(buf, r.area());
+ compressData(os, &zos[streamId], buf, length, s_pconf->rawZlibLevel);
+}
+
+static void ENCODE_MONO_RECT (rdr::OutStream *os, rdr::ZlibOutStream zos[4],
+ PIXEL_T *buf, const Rect& r)
+{
+ const int streamId = 1;
+ os->writeU8((streamId | 0x04) << 4);
+ os->writeU8(0x01);
+
+ // Write the palette
+ PIXEL_T pal[2] = { (PIXEL_T)s_monoBackground, (PIXEL_T)s_monoForeground };
+ os->writeU8(1);
+ os->writeBytes(pal, PACK_PIXELS(pal, 2));
+
+ // Encode the data in-place
+ PIXEL_T *src = buf;
+ rdr::U8 *dst = (rdr::U8 *)buf;
+ int w = r.width();
+ int h = r.height();
+ PIXEL_T bg;
+ unsigned int value, mask;
+ int aligned_width;
+ int x, y, bg_bits;
+
+ bg = (PIXEL_T) s_monoBackground;
+ aligned_width = w - w % 8;
+
+ for (y = 0; y < h; y++) {
+ for (x = 0; x < aligned_width; x += 8) {
+ for (bg_bits = 0; bg_bits < 8; bg_bits++) {
+ if (*src++ != bg)
+ break;
+ }
+ if (bg_bits == 8) {
+ *dst++ = 0;
+ continue;
+ }
+ mask = 0x80 >> bg_bits;
+ value = mask;
+ for (bg_bits++; bg_bits < 8; bg_bits++) {
+ mask >>= 1;
+ if (*src++ != bg) {
+ value |= mask;
+ }
+ }
+ *dst++ = (rdr::U8)value;
+ }
+
+ mask = 0x80;
+ value = 0;
+ if (x >= w)
+ continue;
+
+ for (; x < w; x++) {
+ if (*src++ != bg) {
+ value |= mask;
+ }
+ mask >>= 1;
+ }
+ *dst++ = (rdr::U8)value;
+ }
+
+ // Write the data
+ int length = (w + 7) / 8;
+ length *= h;
+ compressData(os, &zos[streamId], buf, length, s_pconf->monoZlibLevel);
+}
+
+#if (BPP != 8)
+static void ENCODE_INDEXED_RECT (rdr::OutStream *os, rdr::ZlibOutStream zos[4],
+ PIXEL_T *buf, const Rect& r)
+{
+ const int streamId = 2;
+ os->writeU8((streamId | 0x04) << 4);
+ os->writeU8(0x01);
+
+ // Write the palette
+ {
+ PIXEL_T pal[256];
+ for (int i = 0; i < s_palNumColors; i++)
+ pal[i] = (PIXEL_T)s_palette.entry[i].listNode->rgb;
+ os->writeU8((rdr::U8)(s_palNumColors - 1));
+ os->writeBytes(pal, PACK_PIXELS(pal, s_palNumColors));
+ }
+
+ // Encode data in-place
+ PIXEL_T *src = buf;
+ rdr::U8 *dst = (rdr::U8 *)buf;
+ int count = r.area();
+ PIXEL_T rgb;
+ TIGHT_COLOR_LIST *pnode;
+ int rep = 0;
+
+ while (count--) {
+ rgb = *src++;
+ while (count && *src == rgb) {
+ rep++, src++, count--;
+ }
+ pnode = s_palette.hash[HASH_FUNCTION(rgb)];
+ while (pnode != NULL) {
+ if ((PIXEL_T)pnode->rgb == rgb) {
+ *dst++ = (rdr::U8)pnode->idx;
+ while (rep) {
+ *dst++ = (rdr::U8)pnode->idx;
+ rep--;
+ }
+ break;
+ }
+ pnode = pnode->next;
+ }
+ }
+
+ // Write the data
+ compressData(os, &zos[streamId], buf, r.area(), s_pconf->idxZlibLevel);
+}
+#endif // #if (BPP != 8)
+
+//
+// JPEG compression.
+//
+
+#if (BPP != 8)
+static void PREPARE_JPEG_ROW (PIXEL_T *src, const PixelFormat& pf,
+ rdr::U8 *dst, int count)
+{
+ // FIXME: Add a version of this function optimized for 24-bit colors?
+ PIXEL_T pix;
+ while (count--) {
+ pix = *src++;
+ if (s_endianMismatch)
+ pix = SWAP_PIXEL(pix);
+ *dst++ = (rdr::U8)((pix >> pf.redShift & pf.redMax) * 255 / pf.redMax);
+ *dst++ = (rdr::U8)((pix >> pf.greenShift & pf.greenMax) * 255 / pf.greenMax);
+ *dst++ = (rdr::U8)((pix >> pf.blueShift & pf.blueMax) * 255 / pf.blueMax);
+ }
+}
+#endif // #if (BPP != 8)
+
+#if (BPP != 8)
+static void ENCODE_JPEG_RECT (rdr::OutStream *os, PIXEL_T *buf,
+ const PixelFormat& pf, const Rect& r)
+{
+ int w = r.width();
+ int h = r.height();
+
+ struct jpeg_compress_struct cinfo;
+ struct jpeg_error_mgr jerr;
+
+ // FIXME: Make srcBuf[] and/or dstBuf[] static?
+ rdr::U8 *srcBuf = new rdr::U8[w * 3];
+ JSAMPROW rowPointer[1];
+ rowPointer[0] = (JSAMPROW)srcBuf;
+
+ cinfo.err = jpeg_std_error(&jerr);
+ jpeg_create_compress(&cinfo);
+
+ cinfo.image_width = w;
+ cinfo.image_height = h;
+ cinfo.input_components = 3;
+ cinfo.in_color_space = JCS_RGB;
+
+ jpeg_set_defaults(&cinfo);
+ jpeg_set_quality(&cinfo, s_pjconf->jpegQuality, TRUE);
+
+ rdr::U8 *dstBuf = new rdr::U8[2048];
+ JpegSetDstManager(&cinfo, dstBuf, 2048);
+
+ jpeg_start_compress(&cinfo, TRUE);
+ for (int dy = 0; dy < h; dy++) {
+ PREPARE_JPEG_ROW(&buf[dy * w], pf, srcBuf, w);
+ jpeg_write_scanlines(&cinfo, rowPointer, 1);
+ }
+ jpeg_finish_compress(&cinfo);
+ jpeg_destroy_compress(&cinfo);
+
+ delete[] srcBuf;
+ delete[] dstBuf;
+
+ os->writeU8(0x09 << 4);
+ os->writeCompactLength(s_jpeg_os.length());
+ os->writeBytes(s_jpeg_os.data(), s_jpeg_os.length());
+}
+#endif // #if (BPP != 8)
+
+//
+// Determine the number of colors in the rectangle, and fill in the palette.
+//
+
+#if (BPP == 8)
+static void FILL_PALETTE (PIXEL_T *data, int count)
+{
+ PIXEL_T c0, c1;
+ int i, n0, n1;
+
+ s_palNumColors = 0;
+
+ c0 = data[0];
+ for (i = 1; i < count && data[i] == c0; i++);
+ if (i == count) {
+ s_palNumColors = 1;
+ return; // Solid rectangle
+ }
+
+ if (s_palMaxColors < 2)
+ return;
+
+ n0 = i;
+ c1 = data[i];
+ n1 = 0;
+ for (i++; i < count; i++) {
+ if (data[i] == c0) {
+ n0++;
+ } else if (data[i] == c1) {
+ n1++;
+ } else
+ break;
+ }
+ if (i == count) {
+ if (n0 > n1) {
+ s_monoBackground = (rdr::U32)c0;
+ s_monoForeground = (rdr::U32)c1;
+ } else {
+ s_monoBackground = (rdr::U32)c1;
+ s_monoForeground = (rdr::U32)c0;
+ }
+ s_palNumColors = 2; // Two colors
+ }
+}
+#else // (BPP != 8)
+static void FILL_PALETTE (PIXEL_T *data, int count)
+{
+ PIXEL_T c0, c1, ci = 0;
+ int i, n0, n1, ni;
+
+ c0 = data[0];
+ for (i = 1; i < count && data[i] == c0; i++);
+ if (i >= count) {
+ s_palNumColors = 1; // Solid rectangle
+ return;
+ }
+
+ if (s_palMaxColors < 2) {
+ s_palNumColors = 0; // Full-color format preferred
+ return;
+ }
+
+ n0 = i;
+ c1 = data[i];
+ n1 = 0;
+ for (i++; i < count; i++) {
+ ci = data[i];
+ if (ci == c0) {
+ n0++;
+ } else if (ci == c1) {
+ n1++;
+ } else
+ break;
+ }
+ if (i >= count) {
+ if (n0 > n1) {
+ s_monoBackground = (rdr::U32)c0;
+ s_monoForeground = (rdr::U32)c1;
+ } else {
+ s_monoBackground = (rdr::U32)c1;
+ s_monoForeground = (rdr::U32)c0;
+ }
+ s_palNumColors = 2; // Two colors
+ return;
+ }
+
+ paletteReset();
+ paletteInsert (c0, (rdr::U32)n0, BPP);
+ paletteInsert (c1, (rdr::U32)n1, BPP);
+
+ ni = 1;
+ for (i++; i < count; i++) {
+ if (data[i] == ci) {
+ ni++;
+ } else {
+ if (!paletteInsert (ci, (rdr::U32)ni, BPP))
+ return;
+ ci = data[i];
+ ni = 1;
+ }
+ }
+ paletteInsert (ci, (rdr::U32)ni, BPP);
+}
+#endif // #if (BPP == 8)
+
+#undef PIXEL_T
+#undef WRITE_PIXEL
+#undef TIGHT_ENCODE
+#undef SWAP_PIXEL
+#undef HASH_FUNCTION
+#undef PACK_PIXELS
+#undef DETECT_SMOOTH_IMAGE
+#undef ENCODE_SOLID_RECT
+#undef ENCODE_FULLCOLOR_RECT
+#undef ENCODE_MONO_RECT
+#undef ENCODE_INDEXED_RECT
+#undef PREPARE_JPEG_ROW
+#undef ENCODE_JPEG_RECT
+#undef FILL_PALETTE
+}
diff --git a/common/rfb/transInitTempl.h b/common/rfb/transInitTempl.h
new file mode 100644
index 00000000..464cfdfc
--- /dev/null
+++ b/common/rfb/transInitTempl.h
@@ -0,0 +1,254 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+//
+// transInitTempl.h - templates for functions to initialise lookup tables for
+// the translation functions.
+//
+// This file is #included after having set the following macros:
+// BPPOUT - 8, 16 or 32
+
+#if !defined(BPPOUT)
+#error "transInitTempl.h: BPPOUT not defined"
+#endif
+
+namespace rfb {
+
+// CONCAT2E concatenates its arguments, expanding them if they are macros
+
+#ifndef CONCAT2E
+#define CONCAT2(a,b) a##b
+#define CONCAT2E(a,b) CONCAT2(a,b)
+#endif
+
+#ifndef SWAP16
+#define SWAP16(n) ((((n) & 0xff) << 8) | (((n) >> 8) & 0xff))
+#endif
+
+#ifndef SWAP32
+#define SWAP32(n) (((n) >> 24) | (((n) & 0x00ff0000) >> 8) | \
+ (((n) & 0x0000ff00) << 8) | ((n) << 24))
+#endif
+
+#define OUTPIXEL rdr::CONCAT2E(U,BPPOUT)
+#define SWAPOUT CONCAT2E(SWAP,BPPOUT)
+#define initSimpleCMtoTCOUT CONCAT2E(initSimpleCMtoTC,BPPOUT)
+#define initSimpleTCtoTCOUT CONCAT2E(initSimpleTCtoTC,BPPOUT)
+#define initSimpleCMtoCubeOUT CONCAT2E(initSimpleCMtoCube,BPPOUT)
+#define initSimpleTCtoCubeOUT CONCAT2E(initSimpleTCtoCube,BPPOUT)
+#define initRGBTCtoTCOUT CONCAT2E(initRGBTCtoTC,BPPOUT)
+#define initRGBTCtoCubeOUT CONCAT2E(initRGBTCtoCube,BPPOUT)
+#define initOneRGBTableOUT CONCAT2E(initOneRGBTable,BPPOUT)
+#define initOneRGBCubeTableOUT CONCAT2E(initOneRGBCubeTable,BPPOUT)
+
+#ifndef TRANS_INIT_TEMPL_ENDIAN_TEST
+#define TRANS_INIT_TEMPL_ENDIAN_TEST
+ static rdr::U32 endianTest = 1;
+ static bool nativeBigEndian = *(rdr::U8*)(&endianTest) != 1;
+#endif
+
+void initSimpleCMtoTCOUT (rdr::U8** tablep, const PixelFormat& inPF,
+ ColourMap* cm, const PixelFormat& outPF)
+{
+ if (inPF.bpp != 8 && inPF.bigEndian != nativeBigEndian)
+ throw Exception("Internal error: inPF is not native endian");
+
+ int size = 1 << inPF.bpp;
+
+ delete [] *tablep;
+ *tablep = new rdr::U8[size * sizeof(OUTPIXEL)];
+ OUTPIXEL* table = (OUTPIXEL*)*tablep;
+
+ for (int i = 0; i < size; i++) {
+ int r,g,b;
+ cm->lookup(i,&r,&g,&b);
+
+ table[i] = ((((r * outPF.redMax + 32767) / 65535) << outPF.redShift) |
+ (((g * outPF.greenMax + 32767) / 65535) << outPF.greenShift) |
+ (((b * outPF.blueMax + 32767) / 65535) << outPF.blueShift));
+#if (BPPOUT != 8)
+ if (outPF.bigEndian != nativeBigEndian)
+ table[i] = SWAPOUT (table[i]);
+#endif
+ }
+}
+
+void initSimpleTCtoTCOUT (rdr::U8** tablep, const PixelFormat& inPF,
+ const PixelFormat& outPF)
+{
+ if (inPF.bpp != 8 && inPF.bigEndian != nativeBigEndian)
+ throw Exception("Internal error: inPF is not native endian");
+
+ int size = 1 << inPF.bpp;
+
+ delete [] *tablep;
+ *tablep = new rdr::U8[size * sizeof(OUTPIXEL)];
+ OUTPIXEL* table = (OUTPIXEL*)*tablep;
+
+ for (int i = 0; i < size; i++) {
+ int r = (i >> inPF.redShift) & inPF.redMax;
+ int g = (i >> inPF.greenShift) & inPF.greenMax;
+ int b = (i >> inPF.blueShift) & inPF.blueMax;
+
+ r = (r * outPF.redMax + inPF.redMax/2) / inPF.redMax;
+ g = (g * outPF.greenMax + inPF.greenMax/2) / inPF.greenMax;
+ b = (b * outPF.blueMax + inPF.blueMax/2) / inPF.blueMax;
+
+ table[i] = ((r << outPF.redShift) |
+ (g << outPF.greenShift) |
+ (b << outPF.blueShift));
+#if (BPPOUT != 8)
+ if (outPF.bigEndian != nativeBigEndian)
+ table[i] = SWAPOUT (table[i]);
+#endif
+ }
+}
+
+void initSimpleCMtoCubeOUT (rdr::U8** tablep, const PixelFormat& inPF,
+ ColourMap* cm, ColourCube* cube)
+{
+ if (inPF.bpp != 8 && inPF.bigEndian != nativeBigEndian)
+ throw Exception("Internal error: inPF is not native endian");
+
+ int size = 1 << inPF.bpp;
+
+ delete [] *tablep;
+ *tablep = new rdr::U8[size * sizeof(OUTPIXEL)];
+ OUTPIXEL* table = (OUTPIXEL*)*tablep;
+
+ for (int i = 0; i < size; i++) {
+ int r,g,b;
+ cm->lookup(i,&r,&g,&b);
+ r = (r * (cube->nRed-1) + 32767) / 65535;
+ g = (g * (cube->nGreen-1) + 32767) / 65535;
+ b = (b * (cube->nBlue-1) + 32767) / 65535;
+ table[i] = cube->lookup(r, g, b);
+ }
+}
+
+void initSimpleTCtoCubeOUT (rdr::U8** tablep, const PixelFormat& inPF,
+ ColourCube* cube)
+{
+ if (inPF.bpp != 8 && inPF.bigEndian != nativeBigEndian)
+ throw Exception("Internal error: inPF is not native endian");
+
+ int size = 1 << inPF.bpp;
+
+ delete [] *tablep;
+ *tablep = new rdr::U8[size * sizeof(OUTPIXEL)];
+ OUTPIXEL* table = (OUTPIXEL*)*tablep;
+
+ for (int i = 0; i < size; i++) {
+ int r = (i >> inPF.redShift) & inPF.redMax;
+ int g = (i >> inPF.greenShift) & inPF.greenMax;
+ int b = (i >> inPF.blueShift) & inPF.blueMax;
+
+ r = (r * (cube->nRed-1) + inPF.redMax/2) / inPF.redMax;
+ g = (g * (cube->nGreen-1) + inPF.greenMax/2) / inPF.greenMax;
+ b = (b * (cube->nBlue-1) + inPF.blueMax/2) / inPF.blueMax;
+
+ table[i] = cube->lookup(r, g, b);
+ }
+}
+
+void initOneRGBTableOUT (OUTPIXEL* table, int inMax, int outMax,
+ int outShift, bool swap)
+{
+ int size = inMax + 1;
+
+ for (int i = 0; i < size; i++) {
+ table[i] = ((i * outMax + inMax / 2) / inMax) << outShift;
+#if (BPPOUT != 8)
+ if (swap)
+ table[i] = SWAPOUT (table[i]);
+#endif
+ }
+}
+
+void initRGBTCtoTCOUT (rdr::U8** tablep, const PixelFormat& inPF,
+ const PixelFormat& outPF)
+{
+ if (inPF.bpp != 8 && inPF.bigEndian != nativeBigEndian)
+ throw Exception("Internal error: inPF is not native endian");
+
+ int size = inPF.redMax + inPF.greenMax + inPF.blueMax + 3;
+
+ delete [] *tablep;
+ *tablep = new rdr::U8[size * sizeof(OUTPIXEL)];
+
+ OUTPIXEL* redTable = (OUTPIXEL*)*tablep;
+ OUTPIXEL* greenTable = redTable + inPF.redMax + 1;
+ OUTPIXEL* blueTable = greenTable + inPF.greenMax + 1;
+
+ bool swap = (outPF.bigEndian != nativeBigEndian);
+
+ initOneRGBTableOUT (redTable, inPF.redMax, outPF.redMax,
+ outPF.redShift, swap);
+ initOneRGBTableOUT (greenTable, inPF.greenMax, outPF.greenMax,
+ outPF.greenShift, swap);
+ initOneRGBTableOUT (blueTable, inPF.blueMax, outPF.blueMax,
+ outPF.blueShift, swap);
+}
+
+
+void initOneRGBCubeTableOUT (OUTPIXEL* table, int inMax, int outMax,
+ int outMult)
+{
+ int size = inMax + 1;
+
+ for (int i = 0; i < size; i++) {
+ table[i] = ((i * outMax + inMax / 2) / inMax) * outMult;
+ }
+}
+
+void initRGBTCtoCubeOUT (rdr::U8** tablep, const PixelFormat& inPF,
+ ColourCube* cube)
+{
+ if (inPF.bpp != 8 && inPF.bigEndian != nativeBigEndian)
+ throw Exception("Internal error: inPF is not native endian");
+
+ int size = inPF.redMax + inPF.greenMax + inPF.blueMax + 3 + cube->size();
+
+ delete [] *tablep;
+ *tablep = new rdr::U8[size * sizeof(OUTPIXEL)];
+
+ OUTPIXEL* redTable = (OUTPIXEL*)*tablep;
+ OUTPIXEL* greenTable = redTable + inPF.redMax + 1;
+ OUTPIXEL* blueTable = greenTable + inPF.greenMax + 1;
+ OUTPIXEL* cubeTable = blueTable + inPF.blueMax + 1;
+
+ initOneRGBCubeTableOUT (redTable, inPF.redMax, cube->nRed-1,
+ cube->redMult());
+ initOneRGBCubeTableOUT (greenTable, inPF.greenMax, cube->nGreen-1,
+ cube->greenMult());
+ initOneRGBCubeTableOUT (blueTable, inPF.blueMax, cube->nBlue-1,
+ cube->blueMult());
+ for (int i = 0; i < cube->size(); i++) {
+ cubeTable[i] = cube->table[i];
+ }
+}
+
+#undef OUTPIXEL
+#undef initSimpleCMtoTCOUT
+#undef initSimpleTCtoTCOUT
+#undef initSimpleCMtoCubeOUT
+#undef initSimpleTCtoCubeOUT
+#undef initRGBTCtoTCOUT
+#undef initRGBTCtoCubeOUT
+#undef initOneRGBTableOUT
+#undef initOneRGBCubeTableOUT
+}
diff --git a/common/rfb/transTempl.h b/common/rfb/transTempl.h
new file mode 100644
index 00000000..09dc7f95
--- /dev/null
+++ b/common/rfb/transTempl.h
@@ -0,0 +1,151 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+//
+// transTempl.h - templates for translation functions.
+//
+// This file is #included after having set the following macros:
+// BPPIN - 8, 16 or 32
+// BPPOUT - 8, 16 or 32
+
+#if !defined(BPPIN) || !defined(BPPOUT)
+#error "transTempl.h: BPPIN or BPPOUT not defined"
+#endif
+
+// CONCAT2E concatenates its arguments, expanding them if they are macros
+
+#ifndef CONCAT2E
+#define CONCAT2(a,b) a##b
+#define CONCAT2E(a,b) CONCAT2(a,b)
+#endif
+
+#ifndef CONCAT4E
+#define CONCAT4(a,b,c,d) a##b##c##d
+#define CONCAT4E(a,b,c,d) CONCAT4(a,b,c,d)
+#endif
+
+#define INPIXEL rdr::CONCAT2E(U,BPPIN)
+#define OUTPIXEL rdr::CONCAT2E(U,BPPOUT)
+#define transSimpleINtoOUT CONCAT4E(transSimple,BPPIN,to,BPPOUT)
+#define transRGBINtoOUT CONCAT4E(transRGB,BPPIN,to,BPPOUT)
+#define transRGBCubeINtoOUT CONCAT4E(transRGBCube,BPPIN,to,BPPOUT)
+
+#if (BPPIN <= 16)
+
+// transSimpleINtoOUT uses a single table. This can be used for any incoming
+// and outgoing pixel formats, as long as the incoming pixel format is not too
+// large (for 16bpp, the table needs 64K entries).
+
+void transSimpleINtoOUT (void* table_,
+ const PixelFormat& inPF, void* inPtr, int inStride,
+ const PixelFormat& outPF, void* outPtr, int outStride,
+ int width, int height)
+{
+ OUTPIXEL* table = (OUTPIXEL*)table_;
+ INPIXEL* ip = (INPIXEL*)inPtr;
+ OUTPIXEL* op = (OUTPIXEL*)outPtr;
+ int inExtra = inStride - width;
+ int outExtra = outStride - width;
+
+ while (height > 0) {
+ OUTPIXEL* opEndOfRow = op + width;
+ while (op < opEndOfRow)
+ *op++ = table[*ip++];
+ ip += inExtra;
+ op += outExtra;
+ height--;
+ }
+}
+
+#endif
+
+#if (BPPIN >= 16)
+
+// transRGBINtoOUT uses three tables, one each for red, green and blue
+// components and adds the values to produce the result. This can be used
+// where a single table would be too large (e.g. 32bpp). It only works for a
+// trueColour incoming pixel format. Usually the outgoing pixel format is
+// trueColour, but we add rather than ORing the three values so that it is also
+// possible to generate an index into a colour cube. I believe that in most
+// cases adding is just as fast as ORing - if not then we should split this
+// into two different functions for efficiency.
+
+void transRGBINtoOUT (void* table,
+ const PixelFormat& inPF, void* inPtr, int inStride,
+ const PixelFormat& outPF, void* outPtr, int outStride,
+ int width, int height)
+{
+ OUTPIXEL* redTable = (OUTPIXEL*)table;
+ OUTPIXEL* greenTable = redTable + inPF.redMax + 1;
+ OUTPIXEL* blueTable = greenTable + inPF.greenMax + 1;
+ INPIXEL* ip = (INPIXEL*)inPtr;
+ OUTPIXEL* op = (OUTPIXEL*)outPtr;
+ int inExtra = inStride - width;
+ int outExtra = outStride - width;
+
+ while (height > 0) {
+ OUTPIXEL* opEndOfRow = op + width;
+ while (op < opEndOfRow) {
+ *op++ = (redTable [(*ip >> inPF.redShift) & inPF.redMax] +
+ greenTable[(*ip >> inPF.greenShift) & inPF.greenMax] +
+ blueTable [(*ip >> inPF.blueShift) & inPF.blueMax]);
+ ip++;
+ }
+ ip += inExtra;
+ op += outExtra;
+ height--;
+ }
+}
+
+// transRGBCubeINtoOUT is similar to transRGBINtoOUT but also looks up the
+// colour cube index in a fourth table to yield a pixel value.
+
+void transRGBCubeINtoOUT (void* table,
+ const PixelFormat& inPF, void* inPtr, int inStride,
+ const PixelFormat& outPF, void* outPtr,
+ int outStride, int width, int height)
+{
+ OUTPIXEL* redTable = (OUTPIXEL*)table;
+ OUTPIXEL* greenTable = redTable + inPF.redMax + 1;
+ OUTPIXEL* blueTable = greenTable + inPF.greenMax + 1;
+ OUTPIXEL* cubeTable = blueTable + inPF.blueMax + 1;
+ INPIXEL* ip = (INPIXEL*)inPtr;
+ OUTPIXEL* op = (OUTPIXEL*)outPtr;
+ int inExtra = inStride - width;
+ int outExtra = outStride - width;
+
+ while (height > 0) {
+ OUTPIXEL* opEndOfRow = op + width;
+ while (op < opEndOfRow) {
+ *op++ = cubeTable[(redTable [(*ip >> inPF.redShift) & inPF.redMax] +
+ greenTable[(*ip >> inPF.greenShift) & inPF.greenMax] +
+ blueTable [(*ip >> inPF.blueShift) & inPF.blueMax])];
+ ip++;
+ }
+ ip += inExtra;
+ op += outExtra;
+ height--;
+ }
+}
+
+#endif
+
+#undef INPIXEL
+#undef OUTPIXEL
+#undef transSimpleINtoOUT
+#undef transRGBINtoOUT
+#undef transRGBCubeINtoOUT
diff --git a/common/rfb/util.cxx b/common/rfb/util.cxx
new file mode 100644
index 00000000..57454324
--- /dev/null
+++ b/common/rfb/util.cxx
@@ -0,0 +1,184 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+/*
+ * The following applies to stcasecmp and strncasecmp implementations:
+ *
+ * Copyright (c) 1987 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of California at Berkeley. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific written prior permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+
+#include <rfb/util.h>
+
+// Provide strcasecmp() and/or strncasecmp() if absent on this system.
+
+#ifndef WIN32
+#if !defined(HAVE_STRCASECMP) || !defined(HAVE_STRNCASECMP)
+
+extern "C" {
+
+/*
+ * This array is designed for mapping upper and lower case letter
+ * together for a case independent comparison. The mappings are
+ * based upon ascii character sequences.
+ */
+static unsigned char s_charmap[] = {
+ '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
+ '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
+ '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
+ '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
+ '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
+ '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
+ '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
+ '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
+ '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+ '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
+ '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+ '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
+ '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
+ '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
+ '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
+ '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
+ '\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
+ '\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
+ '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
+ '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
+ '\300', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+ '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+ '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+ '\370', '\371', '\372', '\333', '\334', '\335', '\336', '\337',
+ '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+ '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+ '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+ '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377',
+};
+
+#ifndef HAVE_STRCASECMP
+int
+strcasecmp(const char *s1, const char *s2)
+{
+ unsigned char u1, u2;
+
+ for (;;) {
+ u1 = (unsigned char) *s1++;
+ u2 = (unsigned char) *s2++;
+ if (s_charmap[u1] != s_charmap[u2]) {
+ return s_charmap[u1] - s_charmap[u2];
+ }
+ if (u1 == '\0') {
+ return 0;
+ }
+ }
+}
+#endif // !defined(HAVE_STRCASECMP)
+
+#ifndef HAVE_STRNCASECMP
+int
+strncasecmp(const char *s1, const char *s2, size_t n)
+{
+ unsigned char u1, u2;
+
+ for (; n != 0; --n) {
+ u1 = (unsigned char) *s1++;
+ u2 = (unsigned char) *s2++;
+ if (s_charmap[u1] != s_charmap[u2]) {
+ return s_charmap[u1] - s_charmap[u2];
+ }
+ if (u1 == '\0') {
+ return 0;
+ }
+ }
+ return 0;
+}
+#endif // !defined(HAVE_STRNCASECMP)
+
+} // extern "C"
+
+#endif // !defined(HAVE_STRCASECMP) || !defined(HAVE_STRNCASECMP)
+#endif // defined(WIN32)
+
+namespace rfb {
+
+ char* strDup(const char* s) {
+ if (!s) return 0;
+ int l = strlen(s);
+ char* r = new char[l+1];
+ memcpy(r, s, l+1);
+ return r;
+ };
+
+ void strFree(char* s) {
+ delete [] s;
+ }
+
+
+ bool strSplit(const char* src, const char limiter, char** out1, char** out2, bool fromEnd) {
+ CharArray out1old, out2old;
+ if (out1) out1old.buf = *out1;
+ if (out2) out2old.buf = *out2;
+ int len = strlen(src);
+ int i=0, increment=1, limit=len;
+ if (fromEnd) {
+ i=len-1; increment = -1; limit = -1;
+ }
+ while (i!=limit) {
+ if (src[i] == limiter) {
+ if (out1) {
+ *out1 = new char[i+1];
+ if (i) memcpy(*out1, src, i);
+ (*out1)[i] = 0;
+ }
+ if (out2) {
+ *out2 = new char[len-i];
+ if (len-i-1) memcpy(*out2, &src[i+1], len-i-1);
+ (*out2)[len-i-1] = 0;
+ }
+ return true;
+ }
+ i+=increment;
+ }
+ if (out1) *out1 = strDup(src);
+ if (out2) *out2 = 0;
+ return false;
+ }
+
+ bool strContains(const char* src, char c) {
+ int l=strlen(src);
+ for (int i=0; i<l; i++)
+ if (src[i] == c) return true;
+ return false;
+ }
+
+ void strCopy(char* dest, const char* src, int destlen) {
+ if (src)
+ strncpy(dest, src, destlen-1);
+ dest[src ? destlen-1 : 0] = 0;
+ }
+
+};
diff --git a/common/rfb/util.h b/common/rfb/util.h
new file mode 100644
index 00000000..fa205f08
--- /dev/null
+++ b/common/rfb/util.h
@@ -0,0 +1,111 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+//
+// util.h - miscellaneous useful bits
+//
+
+#ifndef __RFB_UTIL_H__
+#define __RFB_UTIL_H__
+
+#include <limits.h>
+#include <string.h>
+
+namespace rfb {
+
+ // -=- Class to handle cleanup of arrays of characters
+ class CharArray {
+ public:
+ CharArray() : buf(0) {}
+ CharArray(char* str) : buf(str) {} // note: assumes ownership
+ CharArray(int len) {
+ buf = new char[len];
+ }
+ ~CharArray() {
+ delete [] buf;
+ }
+ // Get the buffer pointer & clear it (i.e. caller takes ownership)
+ char* takeBuf() {char* tmp = buf; buf = 0; return tmp;}
+ void replaceBuf(char* b) {delete [] buf; buf = b;}
+ char* buf;
+ private:
+ CharArray(const CharArray&);
+ CharArray& operator=(const CharArray&);
+ };
+
+ char* strDup(const char* s);
+ void strFree(char* s);
+
+ // Returns true if split successful. Returns false otherwise.
+ // ALWAYS *copies* first part of string to out1 buffer.
+ // If limiter not found, leaves out2 alone (null) and just copies to out1.
+ // If out1 or out2 non-zero, calls strFree and zeroes them.
+ // If fromEnd is true, splits at end of string rather than beginning.
+ // Either out1 or out2 may be null, in which case the split will not return
+ // that part of the string. Obviously, setting both to 0 is not useful...
+ bool strSplit(const char* src, const char limiter, char** out1, char** out2, bool fromEnd=false);
+
+ // Returns true if src contains c
+ bool strContains(const char* src, char c);
+
+ // Copies src to dest, up to specified length-1, and guarantees termination
+ void strCopy(char* dest, const char* src, int destlen);
+
+
+ // HELPER functions for timeout handling
+
+ // soonestTimeout() is a function to help work out the soonest of several
+ // timeouts.
+ inline void soonestTimeout(int* timeout, int newTimeout) {
+ if (newTimeout && (!*timeout || newTimeout < *timeout))
+ *timeout = newTimeout;
+ }
+
+ // secsToMillis() turns seconds into milliseconds, capping the value so it
+ // can't wrap round and become -ve
+ inline int secsToMillis(int secs) {
+ return (secs < 0 || secs > (INT_MAX/1000) ? INT_MAX : secs * 1000);
+ }
+}
+
+// Some platforms (e.g. Windows) include max() and min() macros in their
+// standard headers, but they are also standard C++ template functions, so some
+// C++ headers will undefine them. So we steer clear of the names min and max
+// and define __rfbmin and __rfbmax instead.
+
+#ifndef __rfbmax
+#define __rfbmax(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+#ifndef __rfbmin
+#define __rfbmin(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+// Declare strcasecmp() and/or strncasecmp() if absent on this system.
+
+#if !defined(WIN32) && !defined(HAVE_STRCASECMP)
+extern "C" {
+ int strcasecmp(const char *s1, const char *s2);
+}
+#endif
+#if !defined(WIN32) && !defined(HAVE_STRNCASECMP)
+extern "C" {
+ int strncasecmp(const char *s1, const char *s2, size_t n);
+}
+#endif
+
+#endif
diff --git a/common/rfb/zrleDecode.h b/common/rfb/zrleDecode.h
new file mode 100644
index 00000000..15d27900
--- /dev/null
+++ b/common/rfb/zrleDecode.h
@@ -0,0 +1,251 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+//
+// ZRLE decoding function.
+//
+// This file is #included after having set the following macros:
+// BPP - 8, 16 or 32
+// EXTRA_ARGS - optional extra arguments
+// FILL_RECT - fill a rectangle with a single colour
+// IMAGE_RECT - draw a rectangle of pixel data from a buffer
+
+#include <rdr/InStream.h>
+#include <rdr/ZlibInStream.h>
+#include <assert.h>
+
+namespace rfb {
+
+// CONCAT2E concatenates its arguments, expanding them if they are macros
+
+#ifndef CONCAT2E
+#define CONCAT2(a,b) a##b
+#define CONCAT2E(a,b) CONCAT2(a,b)
+#endif
+
+#ifdef CPIXEL
+#define PIXEL_T rdr::CONCAT2E(U,BPP)
+#define READ_PIXEL CONCAT2E(readOpaque,CPIXEL)
+#define ZRLE_DECODE CONCAT2E(zrleDecode,CPIXEL)
+#else
+#define PIXEL_T rdr::CONCAT2E(U,BPP)
+#define READ_PIXEL CONCAT2E(readOpaque,BPP)
+#define ZRLE_DECODE CONCAT2E(zrleDecode,BPP)
+#endif
+
+void ZRLE_DECODE (const Rect& r, rdr::InStream* is,
+ rdr::ZlibInStream* zis, PIXEL_T* buf
+#ifdef EXTRA_ARGS
+ , EXTRA_ARGS
+#endif
+ )
+{
+ int length = is->readU32();
+ zis->setUnderlying(is, length);
+ Rect t;
+
+ for (t.tl.y = r.tl.y; t.tl.y < r.br.y; t.tl.y += 64) {
+
+ t.br.y = __rfbmin(r.br.y, t.tl.y + 64);
+
+ for (t.tl.x = r.tl.x; t.tl.x < r.br.x; t.tl.x += 64) {
+
+ t.br.x = __rfbmin(r.br.x, t.tl.x + 64);
+
+ int mode = zis->readU8();
+ bool rle = mode & 128;
+ int palSize = mode & 127;
+ PIXEL_T palette[128];
+
+ for (int i = 0; i < palSize; i++) {
+ palette[i] = zis->READ_PIXEL();
+ }
+
+ if (palSize == 1) {
+ PIXEL_T pix = palette[0];
+ FILL_RECT(t,pix);
+ continue;
+ }
+
+ if (!rle) {
+ if (palSize == 0) {
+
+ // raw
+
+#ifdef CPIXEL
+ for (PIXEL_T* ptr = buf; ptr < buf+t.area(); ptr++) {
+ *ptr = zis->READ_PIXEL();
+ }
+#else
+ zis->readBytes(buf, t.area() * (BPP / 8));
+#endif
+
+ } else {
+
+ // packed pixels
+ int bppp = ((palSize > 16) ? 8 :
+ ((palSize > 4) ? 4 : ((palSize > 2) ? 2 : 1)));
+
+ PIXEL_T* ptr = buf;
+
+ for (int i = 0; i < t.height(); i++) {
+ PIXEL_T* eol = ptr + t.width();
+ rdr::U8 byte = 0;
+ rdr::U8 nbits = 0;
+
+ while (ptr < eol) {
+ if (nbits == 0) {
+ byte = zis->readU8();
+ nbits = 8;
+ }
+ nbits -= bppp;
+ rdr::U8 index = (byte >> nbits) & ((1 << bppp) - 1) & 127;
+ *ptr++ = palette[index];
+ }
+ }
+ }
+
+#ifdef FAVOUR_FILL_RECT
+ //fprintf(stderr,"copying data to screen %dx%d at %d,%d\n",
+ //t.width(),t.height(),t.tl.x,t.tl.y);
+ IMAGE_RECT(t,buf);
+#endif
+
+ } else {
+
+ if (palSize == 0) {
+
+ // plain RLE
+
+ PIXEL_T* ptr = buf;
+ PIXEL_T* end = ptr + t.area();
+ while (ptr < end) {
+ PIXEL_T pix = zis->READ_PIXEL();
+ int len = 1;
+ int b;
+ do {
+ b = zis->readU8();
+ len += b;
+ } while (b == 255);
+
+ assert(len <= end - ptr);
+
+#ifdef FAVOUR_FILL_RECT
+ int i = ptr - buf;
+ ptr += len;
+
+ int runX = i % t.width();
+ int runY = i / t.width();
+
+ if (runX + len > t.width()) {
+ if (runX != 0) {
+ FILL_RECT(Rect(t.tl.x+runX, t.tl.y+runY, t.width()-runX, 1),
+ pix);
+ len -= t.width()-runX;
+ runX = 0;
+ runY++;
+ }
+
+ if (len > t.width()) {
+ FILL_RECT(Rect(t.tl.x, t.tl.y+runY, t.width(), len/t.width()),
+ pix);
+ runY += len / t.width();
+ len = len % t.width();
+ }
+ }
+
+ if (len != 0) {
+ FILL_RECT(Rect(t.tl.x+runX, t.tl.y+runY, len, 1), pix);
+ }
+#else
+ while (len-- > 0) *ptr++ = pix;
+#endif
+
+ }
+ } else {
+
+ // palette RLE
+
+ PIXEL_T* ptr = buf;
+ PIXEL_T* end = ptr + t.area();
+ while (ptr < end) {
+ int index = zis->readU8();
+ int len = 1;
+ if (index & 128) {
+ int b;
+ do {
+ b = zis->readU8();
+ len += b;
+ } while (b == 255);
+
+ assert(len <= end - ptr);
+ }
+
+ index &= 127;
+
+ PIXEL_T pix = palette[index];
+
+#ifdef FAVOUR_FILL_RECT
+ int i = ptr - buf;
+ ptr += len;
+
+ int runX = i % t.width();
+ int runY = i / t.width();
+
+ if (runX + len > t.width()) {
+ if (runX != 0) {
+ FILL_RECT(Rect(t.tl.x+runX, t.tl.y+runY, t.width()-runX, 1),
+ pix);
+ len -= t.width()-runX;
+ runX = 0;
+ runY++;
+ }
+
+ if (len > t.width()) {
+ FILL_RECT(Rect(t.tl.x, t.tl.y+runY, t.width(), len/t.width()),
+ pix);
+ runY += len / t.width();
+ len = len % t.width();
+ }
+ }
+
+ if (len != 0) {
+ FILL_RECT(Rect(t.tl.x+runX, t.tl.y+runY, len, 1), pix);
+ }
+#else
+ while (len-- > 0) *ptr++ = pix;
+#endif
+ }
+ }
+ }
+
+#ifndef FAVOUR_FILL_RECT
+ //fprintf(stderr,"copying data to screen %dx%d at %d,%d\n",
+ //t.width(),t.height(),t.tl.x,t.tl.y);
+ IMAGE_RECT(t,buf);
+#endif
+ }
+ }
+
+ zis->reset();
+}
+
+#undef ZRLE_DECODE
+#undef READ_PIXEL
+#undef PIXEL_T
+}
diff --git a/common/rfb/zrleEncode.h b/common/rfb/zrleEncode.h
new file mode 100644
index 00000000..9b7263b3
--- /dev/null
+++ b/common/rfb/zrleEncode.h
@@ -0,0 +1,328 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+//
+// zrleEncode.h - zrle encoding function.
+//
+// This file is #included after having set the following macros:
+// BPP - 8, 16 or 32
+// EXTRA_ARGS - optional extra arguments
+// GET_IMAGE_INTO_BUF - gets a rectangle of pixel data into a buffer
+//
+// Note that the buf argument to ZRLE_ENCODE needs to be at least one pixel
+// bigger than the largest tile of pixel data, since the ZRLE encoding
+// algorithm writes to the position one past the end of the pixel data.
+//
+
+#include <rdr/OutStream.h>
+#include <rdr/ZlibOutStream.h>
+#include <assert.h>
+
+namespace rfb {
+
+// CONCAT2E concatenates its arguments, expanding them if they are macros
+
+#ifndef CONCAT2E
+#define CONCAT2(a,b) a##b
+#define CONCAT2E(a,b) CONCAT2(a,b)
+#endif
+
+#ifdef CPIXEL
+#define PIXEL_T rdr::CONCAT2E(U,BPP)
+#define WRITE_PIXEL CONCAT2E(writeOpaque,CPIXEL)
+#define ZRLE_ENCODE CONCAT2E(zrleEncode,CPIXEL)
+#define ZRLE_ENCODE_TILE CONCAT2E(zrleEncodeTile,CPIXEL)
+#define BPPOUT 24
+#else
+#define PIXEL_T rdr::CONCAT2E(U,BPP)
+#define WRITE_PIXEL CONCAT2E(writeOpaque,BPP)
+#define ZRLE_ENCODE CONCAT2E(zrleEncode,BPP)
+#define ZRLE_ENCODE_TILE CONCAT2E(zrleEncodeTile,BPP)
+#define BPPOUT BPP
+#endif
+
+#ifndef ZRLE_ONCE
+#define ZRLE_ONCE
+static const int bitsPerPackedPixel[] = {
+ 0, 1, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4
+};
+
+// The PaletteHelper class helps us build up the palette from pixel data by
+// storing a reverse index using a simple hash-table
+
+class PaletteHelper {
+public:
+ enum { MAX_SIZE = 127 };
+
+ PaletteHelper()
+ {
+ memset(index, 255, sizeof(index));
+ size = 0;
+ }
+
+ inline int hash(rdr::U32 pix)
+ {
+ return (pix ^ (pix >> 17)) & 4095;
+ }
+
+ inline void insert(rdr::U32 pix)
+ {
+ if (size < MAX_SIZE) {
+ int i = hash(pix);
+ while (index[i] != 255 && key[i] != pix)
+ i++;
+ if (index[i] != 255) return;
+
+ index[i] = size;
+ key[i] = pix;
+ palette[size] = pix;
+ }
+ size++;
+ }
+
+ inline int lookup(rdr::U32 pix)
+ {
+ assert(size <= MAX_SIZE);
+ int i = hash(pix);
+ while (index[i] != 255 && key[i] != pix)
+ i++;
+ if (index[i] != 255) return index[i];
+ return -1;
+ }
+
+ rdr::U32 palette[MAX_SIZE];
+ rdr::U8 index[4096+MAX_SIZE];
+ rdr::U32 key[4096+MAX_SIZE];
+ int size;
+};
+#endif
+
+void ZRLE_ENCODE_TILE (PIXEL_T* data, int w, int h, rdr::OutStream* os);
+
+bool ZRLE_ENCODE (const Rect& r, rdr::OutStream* os,
+ rdr::ZlibOutStream* zos, void* buf, int maxLen, Rect* actual
+#ifdef EXTRA_ARGS
+ , EXTRA_ARGS
+#endif
+ )
+{
+ zos->setUnderlying(os);
+ // RLE overhead is at worst 1 byte per 64x64 (4Kpixel) block
+ int worstCaseLine = r.width() * 64 * (BPPOUT/8) + 1 + r.width() / 64;
+ // Zlib overhead is at worst 6 bytes plus 5 bytes per 32Kbyte block.
+ worstCaseLine += 11 + 5 * (worstCaseLine >> 15);
+ Rect t;
+
+ for (t.tl.y = r.tl.y; t.tl.y < r.br.y; t.tl.y += 64) {
+
+ t.br.y = __rfbmin(r.br.y, t.tl.y + 64);
+
+ if (os->length() + worstCaseLine > maxLen) {
+ if (t.tl.y == r.tl.y)
+ throw Exception("ZRLE: not enough space for first line?");
+ actual->tl = r.tl;
+ actual->br.x = r.br.x;
+ actual->br.y = t.tl.y;
+ return false;
+ }
+
+ for (t.tl.x = r.tl.x; t.tl.x < r.br.x; t.tl.x += 64) {
+
+ t.br.x = __rfbmin(r.br.x, t.tl.x + 64);
+
+ GET_IMAGE_INTO_BUF(t,buf);
+
+ ZRLE_ENCODE_TILE((PIXEL_T*)buf, t.width(), t.height(), zos);
+ }
+
+ zos->flush();
+ }
+ return true;
+}
+
+
+void ZRLE_ENCODE_TILE (PIXEL_T* data, int w, int h, rdr::OutStream* os)
+{
+ // First find the palette and the number of runs
+
+ PaletteHelper ph;
+
+ int runs = 0;
+ int singlePixels = 0;
+
+ PIXEL_T* ptr = data;
+ PIXEL_T* end = ptr + h * w;
+ *end = ~*(end-1); // one past the end is different so the while loop ends
+
+ while (ptr < end) {
+ PIXEL_T pix = *ptr;
+ if (*++ptr != pix) {
+ singlePixels++;
+ } else {
+ while (*++ptr == pix) ;
+ runs++;
+ }
+ ph.insert(pix);
+ }
+
+ //fprintf(stderr,"runs %d, single pixels %d, paletteSize %d\n",
+ // runs, singlePixels, ph.size);
+
+ // Solid tile is a special case
+
+ if (ph.size == 1) {
+ os->writeU8(1);
+ os->WRITE_PIXEL(ph.palette[0]);
+ return;
+ }
+
+ // Try to work out whether to use RLE and/or a palette. We do this by
+ // estimating the number of bytes which will be generated and picking the
+ // method which results in the fewest bytes. Of course this may not result
+ // in the fewest bytes after compression...
+
+ bool useRle = false;
+ bool usePalette = false;
+
+ int estimatedBytes = w * h * (BPPOUT/8); // start assuming raw
+
+ int plainRleBytes = ((BPPOUT/8)+1) * (runs + singlePixels);
+
+ if (plainRleBytes < estimatedBytes) {
+ useRle = true;
+ estimatedBytes = plainRleBytes;
+ }
+
+ if (ph.size < 128) {
+ int paletteRleBytes = (BPPOUT/8) * ph.size + 2 * runs + singlePixels;
+
+ if (paletteRleBytes < estimatedBytes) {
+ useRle = true;
+ usePalette = true;
+ estimatedBytes = paletteRleBytes;
+ }
+
+ if (ph.size < 17) {
+ int packedBytes = ((BPPOUT/8) * ph.size +
+ w * h * bitsPerPackedPixel[ph.size-1] / 8);
+
+ if (packedBytes < estimatedBytes) {
+ useRle = false;
+ usePalette = true;
+ estimatedBytes = packedBytes;
+ }
+ }
+ }
+
+ if (!usePalette) ph.size = 0;
+
+ os->writeU8((useRle ? 128 : 0) | ph.size);
+
+ for (int i = 0; i < ph.size; i++) {
+ os->WRITE_PIXEL(ph.palette[i]);
+ }
+
+ if (useRle) {
+
+ PIXEL_T* ptr = data;
+ PIXEL_T* end = ptr + w * h;
+ PIXEL_T* runStart;
+ PIXEL_T pix;
+ while (ptr < end) {
+ runStart = ptr;
+ pix = *ptr++;
+ while (*ptr == pix && ptr < end)
+ ptr++;
+ int len = ptr - runStart;
+ if (len <= 2 && usePalette) {
+ int index = ph.lookup(pix);
+ if (len == 2)
+ os->writeU8(index);
+ os->writeU8(index);
+ continue;
+ }
+ if (usePalette) {
+ int index = ph.lookup(pix);
+ os->writeU8(index | 128);
+ } else {
+ os->WRITE_PIXEL(pix);
+ }
+ len -= 1;
+ while (len >= 255) {
+ os->writeU8(255);
+ len -= 255;
+ }
+ os->writeU8(len);
+ }
+
+ } else {
+
+ // no RLE
+
+ if (usePalette) {
+
+ // packed pixels
+
+ assert (ph.size < 17);
+
+ int bppp = bitsPerPackedPixel[ph.size-1];
+
+ PIXEL_T* ptr = data;
+
+ for (int i = 0; i < h; i++) {
+ rdr::U8 nbits = 0;
+ rdr::U8 byte = 0;
+
+ PIXEL_T* eol = ptr + w;
+
+ while (ptr < eol) {
+ PIXEL_T pix = *ptr++;
+ rdr::U8 index = ph.lookup(pix);
+ byte = (byte << bppp) | index;
+ nbits += bppp;
+ if (nbits >= 8) {
+ os->writeU8(byte);
+ nbits = 0;
+ }
+ }
+ if (nbits > 0) {
+ byte <<= 8 - nbits;
+ os->writeU8(byte);
+ }
+ }
+ } else {
+
+ // raw
+
+#ifdef CPIXEL
+ for (PIXEL_T* ptr = data; ptr < data+w*h; ptr++) {
+ os->WRITE_PIXEL(*ptr);
+ }
+#else
+ os->writeBytes(data, w*h*(BPP/8));
+#endif
+ }
+ }
+}
+
+#undef PIXEL_T
+#undef WRITE_PIXEL
+#undef ZRLE_ENCODE
+#undef ZRLE_ENCODE_TILE
+#undef BPPOUT
+}