summaryrefslogtreecommitdiffstats
path: root/libvncserver
diff options
context:
space:
mode:
authordscho <dscho>2004-05-25 09:05:09 +0000
committerdscho <dscho>2004-05-25 09:05:09 +0000
commit876868553da8f69ed1a368688b6d01a8a7bc1a39 (patch)
tree0bf872ebeadb746eec0f4695230c8777680ece9f /libvncserver
parent0130bdb9d6c61e0446ab514816041f1b9283410a (diff)
downloadlibtdevnc-876868553da8f69ed1a368688b6d01a8a7bc1a39.tar.gz
libtdevnc-876868553da8f69ed1a368688b6d01a8a7bc1a39.zip
move the library into libvncserver/, x11vnc into x11vnc/
Diffstat (limited to 'libvncserver')
-rw-r--r--libvncserver/Makefile.am42
-rwxr-xr-xlibvncserver/auth.c104
-rw-r--r--libvncserver/cargs.c169
-rw-r--r--libvncserver/config.h240
-rwxr-xr-xlibvncserver/corre.c352
-rw-r--r--libvncserver/cursor.c527
-rwxr-xr-xlibvncserver/cutpaste.c38
-rwxr-xr-xlibvncserver/d3des.c442
-rwxr-xr-xlibvncserver/d3des.h56
-rwxr-xr-xlibvncserver/draw.c61
-rwxr-xr-xlibvncserver/font.c192
-rwxr-xr-xlibvncserver/hextile.c346
-rwxr-xr-xlibvncserver/httpd.c579
-rw-r--r--libvncserver/main.c851
-rw-r--r--libvncserver/rfbconfig.h243
-rwxr-xr-xlibvncserver/rfbregion.c862
-rw-r--r--libvncserver/rfbserver.c1808
-rwxr-xr-xlibvncserver/rre.c321
-rwxr-xr-xlibvncserver/selbox.c301
-rwxr-xr-xlibvncserver/sockets.c619
-rwxr-xr-xlibvncserver/stats.c119
-rwxr-xr-xlibvncserver/tableinit24.c157
-rwxr-xr-xlibvncserver/tableinitcmtemplate.c84
-rwxr-xr-xlibvncserver/tableinittctemplate.c142
-rwxr-xr-xlibvncserver/tabletrans24template.c281
-rwxr-xr-xlibvncserver/tabletranstemplate.c117
-rw-r--r--libvncserver/tight.c1820
-rwxr-xr-xlibvncserver/translate.c484
-rw-r--r--libvncserver/vncauth.c185
-rw-r--r--libvncserver/zlib.c302
-rw-r--r--libvncserver/zrle.c183
-rw-r--r--libvncserver/zrleencodetemplate.c272
-rw-r--r--libvncserver/zrleoutstream.c276
-rw-r--r--libvncserver/zrleoutstream.h62
-rw-r--r--libvncserver/zrlepalettehelper.c62
-rw-r--r--libvncserver/zrlepalettehelper.h46
-rwxr-xr-xlibvncserver/zrletypes.h30
37 files changed, 12775 insertions, 0 deletions
diff --git a/libvncserver/Makefile.am b/libvncserver/Makefile.am
new file mode 100644
index 0000000..0a14983
--- /dev/null
+++ b/libvncserver/Makefile.am
@@ -0,0 +1,42 @@
+CFLAGS=-g -Wall
+
+includedir=$(prefix)/include/rfb
+#include_HEADERS=rfb.h rfbconfig.h rfbint.h rfbproto.h keysym.h rfbregion.h
+
+include_HEADERS=../rfb/rfb.h ../rfb/rfbconfig.h ../rfb/rfbint.h \
+ ../rfb/rfbproto.h ../rfb/keysym.h ../rfb/rfbregion.h ../rfb/rfbclient.h
+
+noinst_HEADERS=d3des.h ../rfb/default8x16.h zrleoutstream.h \
+ zrlepalettehelper.h zrletypes.h
+
+EXTRA_DIST=tableinit24.c tableinittctemplate.c tabletranstemplate.c \
+ tableinitcmtemplate.c tabletrans24template.c \
+ zrleencodetemplate.c
+
+if HAVE_LIBZ
+ZLIBSRCS = zlib.c zrle.c zrleoutstream.c zrlepalettehelper.c
+if HAVE_LIBJPEG
+JPEGSRCS = tight.c
+endif
+endif
+
+LIB_SRCS = main.c rfbserver.c rfbregion.c auth.c sockets.c \
+ stats.c corre.c hextile.c rre.c translate.c cutpaste.c \
+ httpd.c cursor.c font.c \
+ draw.c selbox.c d3des.c vncauth.c cargs.c \
+ $(ZLIBSRCS) $(JPEGSRCS)
+
+libvncserver_a_SOURCES=$(LIB_SRCS)
+
+lib_LIBRARIES=libvncserver.a
+
+if HAVE_RPM
+$(PACKAGE)-$(VERSION).tar.gz: dist
+
+# Rule to build RPM distribution package
+rpm: $(PACKAGE)-$(VERSION).tar.gz libvncserver.spec
+ cp $(PACKAGE)-$(VERSION).tar.gz @RPMSOURCEDIR@
+ rpm -ba libvncserver.spec
+endif
+
+
diff --git a/libvncserver/auth.c b/libvncserver/auth.c
new file mode 100755
index 0000000..ec253dd
--- /dev/null
+++ b/libvncserver/auth.c
@@ -0,0 +1,104 @@
+/*
+ * auth.c - deal with authentication.
+ *
+ * This file implements the VNC authentication protocol when setting up an RFB
+ * connection.
+ */
+
+/*
+ * OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
+ * Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge.
+ * 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/rfb.h>
+
+/*
+ * rfbAuthNewClient is called when we reach the point of authenticating
+ * a new client. If authentication isn't being used then we simply send
+ * rfbNoAuth. Otherwise we send rfbVncAuth plus the challenge.
+ */
+
+void
+rfbAuthNewClient(cl)
+ rfbClientPtr cl;
+{
+ char buf[4 + CHALLENGESIZE];
+ int len;
+
+ cl->state = RFB_AUTHENTICATION;
+
+ if (cl->screen->rfbAuthPasswdData && !cl->reverseConnection) {
+ *(uint32_t *)buf = Swap32IfLE(rfbVncAuth);
+ vncRandomBytes(cl->authChallenge);
+ memcpy(&buf[4], (char *)cl->authChallenge, CHALLENGESIZE);
+ len = 4 + CHALLENGESIZE;
+ } else {
+ *(uint32_t *)buf = Swap32IfLE(rfbNoAuth);
+ len = 4;
+ cl->state = RFB_INITIALISATION;
+ }
+
+ if (WriteExact(cl, buf, len) < 0) {
+ rfbLogPerror("rfbAuthNewClient: write");
+ rfbCloseClient(cl);
+ return;
+ }
+}
+
+
+/*
+ * rfbAuthProcessClientMessage is called when the client sends its
+ * authentication response.
+ */
+
+void
+rfbAuthProcessClientMessage(cl)
+ rfbClientPtr cl;
+{
+ int n;
+ uint8_t response[CHALLENGESIZE];
+ uint32_t authResult;
+
+ if ((n = ReadExact(cl, (char *)response, CHALLENGESIZE)) <= 0) {
+ if (n != 0)
+ rfbLogPerror("rfbAuthProcessClientMessage: read");
+ rfbCloseClient(cl);
+ return;
+ }
+
+ if(!cl->screen->passwordCheck(cl,(const char*)response,CHALLENGESIZE)) {
+ rfbErr("rfbAuthProcessClientMessage: password check failed\n");
+ authResult = Swap32IfLE(rfbVncAuthFailed);
+ if (WriteExact(cl, (char *)&authResult, 4) < 0) {
+ rfbLogPerror("rfbAuthProcessClientMessage: write");
+ }
+ rfbCloseClient(cl);
+ return;
+ }
+
+ authResult = Swap32IfLE(rfbVncAuthOK);
+
+ if (WriteExact(cl, (char *)&authResult, 4) < 0) {
+ rfbLogPerror("rfbAuthProcessClientMessage: write");
+ rfbCloseClient(cl);
+ return;
+ }
+
+ cl->state = RFB_INITIALISATION;
+}
diff --git a/libvncserver/cargs.c b/libvncserver/cargs.c
new file mode 100644
index 0000000..c26050e
--- /dev/null
+++ b/libvncserver/cargs.c
@@ -0,0 +1,169 @@
+/*
+ * This parses the command line arguments. It was seperated from main.c by
+ * Justin Dearing <jdeari01@longisland.poly.edu>.
+ */
+
+/*
+ * LibVNCServer (C) 2001 Johannes E. Schindelin <Johannes.Schindelin@gmx.de>
+ * Original OSXvnc (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
+ * Original Xvnc (C) 1999 AT&T Laboratories Cambridge.
+ * All Rights Reserved.
+ *
+ * see GPL (latest version) for full details
+ */
+
+#include <rfb/rfb.h>
+
+void
+rfbUsage(void)
+{
+ fprintf(stderr, "-rfbport port TCP port for RFB protocol\n");
+ fprintf(stderr, "-rfbwait time max time in ms to wait for RFB client\n");
+ fprintf(stderr, "-rfbauth passwd-file use authentication on RFB protocol\n"
+ " (use 'storepasswd' to create a password file)\n");
+ fprintf(stderr, "-passwd plain-password use authentication \n"
+ " (use plain-password as password, USE AT YOUR RISK)\n");
+ fprintf(stderr, "-deferupdate time time in ms to defer updates "
+ "(default 40)\n");
+ fprintf(stderr, "-desktop name VNC desktop name (default \"LibVNCServer\")\n");
+ fprintf(stderr, "-alwaysshared always treat new clients as shared\n");
+ fprintf(stderr, "-nevershared never treat new clients as shared\n");
+ fprintf(stderr, "-dontdisconnect don't disconnect existing clients when a "
+ "new non-shared\n"
+ " connection comes in (refuse new connection "
+ "instead)\n");
+ fprintf(stderr, "-httpdir dir-path enable http server using dir-path home\n");
+ fprintf(stderr, "-httpport portnum use portnum for http connection\n");
+ fprintf(stderr, "-enablehttpproxy enable http proxy support\n");
+ fprintf(stderr, "-progressive height enable progressive updating for slow links\n");
+}
+
+/* purges COUNT arguments from ARGV at POSITION and decrements ARGC.
+ POSITION points to the first non purged argument afterwards. */
+void rfbPurgeArguments(int* argc,int* position,int count,char *argv[])
+{
+ int amount=(*argc)-(*position)-count;
+ if(amount)
+ memmove(argv+(*position),argv+(*position)+count,sizeof(char*)*amount);
+ (*argc)-=count;
+}
+
+rfbBool
+rfbProcessArguments(rfbScreenInfoPtr rfbScreen,int* argc, char *argv[])
+{
+ int i,i1;
+
+ if(!argc) return TRUE;
+
+ for (i = i1 = 1; i < *argc;) {
+ if (strcmp(argv[i], "-help") == 0) {
+ rfbUsage();
+ return FALSE;
+ } else if (strcmp(argv[i], "-rfbport") == 0) { /* -rfbport port */
+ if (i + 1 >= *argc) {
+ rfbUsage();
+ return FALSE;
+ }
+ rfbScreen->rfbPort = atoi(argv[++i]);
+ } else if (strcmp(argv[i], "-rfbwait") == 0) { /* -rfbwait ms */
+ if (i + 1 >= *argc) {
+ rfbUsage();
+ return FALSE;
+ }
+ rfbScreen->rfbMaxClientWait = atoi(argv[++i]);
+ } else if (strcmp(argv[i], "-rfbauth") == 0) { /* -rfbauth passwd-file */
+ if (i + 1 >= *argc) {
+ rfbUsage();
+ return FALSE;
+ }
+ rfbScreen->rfbAuthPasswdData = argv[++i];
+ } else if (strcmp(argv[i], "-passwd") == 0) { /* -passwd password */
+ char **passwds = malloc(sizeof(char**)*2);
+ if (i + 1 >= *argc) {
+ rfbUsage();
+ return FALSE;
+ }
+ passwds[0] = argv[++i];
+ passwds[1] = 0;
+ rfbScreen->rfbAuthPasswdData = (void*)passwds;
+ rfbScreen->passwordCheck = rfbCheckPasswordByList;
+ } else if (strcmp(argv[i], "-deferupdate") == 0) { /* -deferupdate milliseconds */
+ if (i + 1 >= *argc) {
+ rfbUsage();
+ return FALSE;
+ }
+ rfbScreen->rfbDeferUpdateTime = atoi(argv[++i]);
+ } else if (strcmp(argv[i], "-desktop") == 0) { /* -desktop desktop-name */
+ if (i + 1 >= *argc) {
+ rfbUsage();
+ return FALSE;
+ }
+ rfbScreen->desktopName = argv[++i];
+ } else if (strcmp(argv[i], "-alwaysshared") == 0) {
+ rfbScreen->rfbAlwaysShared = TRUE;
+ } else if (strcmp(argv[i], "-nevershared") == 0) {
+ rfbScreen->rfbNeverShared = TRUE;
+ } else if (strcmp(argv[i], "-dontdisconnect") == 0) {
+ rfbScreen->rfbDontDisconnect = TRUE;
+ } else if (strcmp(argv[i], "-httpdir") == 0) { /* -httpdir directory-path */
+ if (i + 1 >= *argc) {
+ rfbUsage();
+ return FALSE;
+ }
+ rfbScreen->httpDir = argv[++i];
+ } else if (strcmp(argv[i], "-httpport") == 0) { /* -httpport portnum */
+ if (i + 1 >= *argc) {
+ rfbUsage();
+ return FALSE;
+ }
+ rfbScreen->httpPort = atoi(argv[++i]);
+ } else if (strcmp(argv[i], "-enablehttpproxy") == 0) {
+ rfbScreen->httpEnableProxyConnect = TRUE;
+ } else if (strcmp(argv[i], "-progressive") == 0) { /* -httpport portnum */
+ if (i + 1 >= *argc) {
+ rfbUsage();
+ return FALSE;
+ }
+ rfbScreen->progressiveSliceHeight = atoi(argv[++i]);
+ } else {
+ i++;
+ i1=i;
+ continue;
+ }
+ /* we just remove the processed arguments from the list */
+ rfbPurgeArguments(argc,&i1,i-i1+1,argv);
+ i=i1;
+ }
+ return TRUE;
+}
+
+void rfbSizeUsage()
+{
+ fprintf(stderr, "-width sets the width of the framebuffer\n");
+ fprintf(stderr, "-height sets the height of the framebuffer\n");
+}
+
+rfbBool
+rfbProcessSizeArguments(int* width,int* height,int* bpp,int* argc, char *argv[])
+{
+ int i,i1;
+
+ if(!argc) return TRUE;
+ for (i = i1 = 1; i < *argc-1;) {
+ if (strcmp(argv[i], "-bpp") == 0) {
+ *bpp = atoi(argv[++i]);
+ } else if (strcmp(argv[i], "-width") == 0) {
+ *width = atoi(argv[++i]);
+ } else if (strcmp(argv[i], "-height") == 0) {
+ *height = atoi(argv[++i]);
+ } else {
+ i++;
+ i1=i;
+ continue;
+ }
+ rfbPurgeArguments(argc,&i1,i-i1,argv);
+ i=i1;
+ }
+ return TRUE;
+}
+
diff --git a/libvncserver/config.h b/libvncserver/config.h
new file mode 100644
index 0000000..4daa20c
--- /dev/null
+++ b/libvncserver/config.h
@@ -0,0 +1,240 @@
+/* config.h. Generated by configure. */
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* Enable 24 bit per pixel in native framebuffer */
+#define ALLOW24BPP 1
+
+/* Enable BackChannel communication */
+#define BACKCHANNEL 1
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#define HAVE_ARPA_INET_H 1
+
+/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */
+/* #undef HAVE_DOPRNT */
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have the `fork' function. */
+#define HAVE_FORK 1
+
+/* Define to 1 if you have the `ftime' function. */
+#define HAVE_FTIME 1
+
+/* Define to 1 if you have the `gethostbyname' function. */
+#define HAVE_GETHOSTBYNAME 1
+
+/* Define to 1 if you have the `gethostname' function. */
+#define HAVE_GETHOSTNAME 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have the `inet_ntoa' function. */
+#define HAVE_INET_NTOA 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `cygipc' library (-lcygipc). */
+/* #undef HAVE_LIBCYGIPC */
+
+/* Define to 1 if you have the `jpeg' library (-ljpeg). */
+#define HAVE_LIBJPEG 1
+
+/* Define to 1 if you have the `nsl' library (-lnsl). */
+#define HAVE_LIBNSL 1
+
+/* Define to 1 if you have the `pthread' library (-lpthread). */
+#define HAVE_LIBPTHREAD 1
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+/* #undef HAVE_LIBSOCKET */
+
+/* Define to 1 if you have the `z' library (-lz). */
+#define HAVE_LIBZ 1
+
+/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
+ to 0 otherwise. */
+#define HAVE_MALLOC 1
+
+/* Define to 1 if you have the `memmove' function. */
+#define HAVE_MEMMOVE 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `memset' function. */
+#define HAVE_MEMSET 1
+
+/* Define to 1 if you have the `mkfifo' function. */
+#define HAVE_MKFIFO 1
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#define HAVE_NETDB_H 1
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#define HAVE_NETINET_IN_H 1
+
+/* Define to 1 if you have the `select' function. */
+#define HAVE_SELECT 1
+
+/* Define to 1 if you have the `setsid' function. */
+#define HAVE_SETSID 1
+
+/* Define to 1 if you have the `socket' function. */
+#define HAVE_SOCKET 1
+
+/* Define to 1 if `stat' has the bug that it succeeds when given the
+ zero-length file name argument. */
+/* #undef HAVE_STAT_EMPTY_STRING_BUG */
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the `strchr' function. */
+#define HAVE_STRCHR 1
+
+/* Define to 1 if you have the `strcspn' function. */
+#define HAVE_STRCSPN 1
+
+/* Define to 1 if you have the `strdup' function. */
+#define HAVE_STRDUP 1
+
+/* Define to 1 if you have the `strerror' function. */
+#define HAVE_STRERROR 1
+
+/* Define to 1 if you have the `strftime' function. */
+#define HAVE_STRFTIME 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strstr' function. */
+#define HAVE_STRSTR 1
+
+/* Define to 1 if you have the <syslog.h> header file. */
+#define HAVE_SYSLOG_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/timeb.h> header file. */
+#define HAVE_SYS_TIMEB_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
+#define HAVE_SYS_WAIT_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `vfork' function. */
+#define HAVE_VFORK 1
+
+/* Define to 1 if you have the <vfork.h> header file. */
+/* #undef HAVE_VFORK_H */
+
+/* Define to 1 if you have the `vprintf' function. */
+#define HAVE_VPRINTF 1
+
+/* Define to 1 if `fork' works. */
+#define HAVE_WORKING_FORK 1
+
+/* Define to 1 if `vfork' works. */
+#define HAVE_WORKING_VFORK 1
+
+/* XKEYBOARD extension build environment present */
+#define HAVE_XKEYBOARD 1
+
+/* Define to 1 if `lstat' dereferences a symlink specified with a trailing
+ slash. */
+#define LSTAT_FOLLOWS_SLASHED_SYMLINK 1
+
+/* Name of package */
+#define PACKAGE "LibVNCServer"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "http://sourceforge.net/projects/libvncserver"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "LibVNCServer"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "LibVNCServer 0.7pre"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "libvncserver"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "0.7pre"
+
+/* The number of bytes in type char */
+/* #undef SIZEOF_CHAR */
+
+/* The number of bytes in type int */
+/* #undef SIZEOF_INT */
+
+/* The number of bytes in type long */
+/* #undef SIZEOF_LONG */
+
+/* The number of bytes in type short */
+/* #undef SIZEOF_SHORT */
+
+/* The number of bytes in type void* */
+/* #undef SIZEOF_VOIDP */
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Version number of package */
+#define VERSION "0.7pre"
+
+/* Define to 1 if your processor stores words with the most significant byte
+ first (like Motorola and SPARC, unlike Intel and VAX). */
+/* #undef WORDS_BIGENDIAN */
+
+/* Define to 1 if the X Window System is missing or not being used. */
+/* #undef X_DISPLAY_MISSING */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+ calls it, or to nothing if 'inline' is not supported under any name. */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+/* Define to rpl_malloc if the replacement function should be used. */
+/* #undef malloc */
+
+/* Define to `int' if <sys/types.h> does not define. */
+/* #undef pid_t */
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+/* The type for socklen */
+/* #undef socklen_t */
+
+/* Define as `fork' if `vfork' does not work. */
+/* #undef vfork */
diff --git a/libvncserver/corre.c b/libvncserver/corre.c
new file mode 100755
index 0000000..3f123b0
--- /dev/null
+++ b/libvncserver/corre.c
@@ -0,0 +1,352 @@
+/*
+ * corre.c
+ *
+ * Routines to implement Compact Rise-and-Run-length Encoding (CoRRE). This
+ * code is based on krw's original javatel rfbserver.
+ */
+
+/*
+ * Copyright (C) 2002 RealVNC Ltd.
+ * OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
+ * Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge.
+ * 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/rfb.h>
+
+/*
+ * rreBeforeBuf contains pixel data in the client's format.
+ * rreAfterBuf contains the RRE encoded version. If the RRE encoded version is
+ * larger than the raw data or if it exceeds rreAfterBufSize then
+ * raw encoding is used instead.
+ */
+
+static int rreBeforeBufSize = 0;
+static char *rreBeforeBuf = NULL;
+
+static int rreAfterBufSize = 0;
+static char *rreAfterBuf = NULL;
+static int rreAfterBufLen;
+
+static int subrectEncode8(uint8_t *data, int w, int h);
+static int subrectEncode16(uint16_t *data, int w, int h);
+static int subrectEncode32(uint32_t *data, int w, int h);
+static uint32_t getBgColour(char *data, int size, int bpp);
+static rfbBool rfbSendSmallRectEncodingCoRRE(rfbClientPtr cl, int x, int y,
+ int w, int h);
+
+
+/*
+ * rfbSendRectEncodingCoRRE - send an arbitrary size rectangle using CoRRE
+ * encoding.
+ */
+
+rfbBool
+rfbSendRectEncodingCoRRE(cl, x, y, w, h)
+ rfbClientPtr cl;
+ int x, y, w, h;
+{
+ if (h > cl->correMaxHeight) {
+ return (rfbSendRectEncodingCoRRE(cl, x, y, w, cl->correMaxHeight) &&
+ rfbSendRectEncodingCoRRE(cl, x, y + cl->correMaxHeight, w,
+ h - cl->correMaxHeight));
+ }
+
+ if (w > cl->correMaxWidth) {
+ return (rfbSendRectEncodingCoRRE(cl, x, y, cl->correMaxWidth, h) &&
+ rfbSendRectEncodingCoRRE(cl, x + cl->correMaxWidth, y,
+ w - cl->correMaxWidth, h));
+ }
+
+ rfbSendSmallRectEncodingCoRRE(cl, x, y, w, h);
+ return TRUE;
+}
+
+
+
+/*
+ * rfbSendSmallRectEncodingCoRRE - send a small (guaranteed < 256x256)
+ * rectangle using CoRRE encoding.
+ */
+
+static rfbBool
+rfbSendSmallRectEncodingCoRRE(cl, x, y, w, h)
+ rfbClientPtr cl;
+ int x, y, w, h;
+{
+ rfbFramebufferUpdateRectHeader rect;
+ rfbRREHeader hdr;
+ int nSubrects;
+ int i;
+ char *fbptr = (cl->screen->frameBuffer + (cl->screen->paddedWidthInBytes * y)
+ + (x * (cl->screen->bitsPerPixel / 8)));
+
+ int maxRawSize = (cl->screen->width * cl->screen->height
+ * (cl->format.bitsPerPixel / 8));
+
+ if (rreBeforeBufSize < maxRawSize) {
+ rreBeforeBufSize = maxRawSize;
+ if (rreBeforeBuf == NULL)
+ rreBeforeBuf = (char *)malloc(rreBeforeBufSize);
+ else
+ rreBeforeBuf = (char *)realloc(rreBeforeBuf, rreBeforeBufSize);
+ }
+
+ if (rreAfterBufSize < maxRawSize) {
+ rreAfterBufSize = maxRawSize;
+ if (rreAfterBuf == NULL)
+ rreAfterBuf = (char *)malloc(rreAfterBufSize);
+ else
+ rreAfterBuf = (char *)realloc(rreAfterBuf, rreAfterBufSize);
+ }
+
+ (*cl->translateFn)(cl->translateLookupTable,&(cl->screen->rfbServerFormat),
+ &cl->format, fbptr, rreBeforeBuf,
+ cl->screen->paddedWidthInBytes, w, h);
+
+ switch (cl->format.bitsPerPixel) {
+ case 8:
+ nSubrects = subrectEncode8((uint8_t *)rreBeforeBuf, w, h);
+ break;
+ case 16:
+ nSubrects = subrectEncode16((uint16_t *)rreBeforeBuf, w, h);
+ break;
+ case 32:
+ nSubrects = subrectEncode32((uint32_t *)rreBeforeBuf, w, h);
+ break;
+ default:
+ rfbLog("getBgColour: bpp %d?\n",cl->format.bitsPerPixel);
+ return FALSE;
+ }
+
+ if (nSubrects < 0) {
+
+ /* RRE encoding was too large, use raw */
+
+ return rfbSendRectEncodingRaw(cl, x, y, w, h);
+ }
+
+ cl->rfbRectanglesSent[rfbEncodingCoRRE]++;
+ cl->rfbBytesSent[rfbEncodingCoRRE] += (sz_rfbFramebufferUpdateRectHeader
+ + sz_rfbRREHeader + rreAfterBufLen);
+
+ if (cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbRREHeader
+ > UPDATE_BUF_SIZE)
+ {
+ if (!rfbSendUpdateBuf(cl))
+ return FALSE;
+ }
+
+ rect.r.x = Swap16IfLE(x);
+ rect.r.y = Swap16IfLE(y);
+ rect.r.w = Swap16IfLE(w);
+ rect.r.h = Swap16IfLE(h);
+ rect.encoding = Swap32IfLE(rfbEncodingCoRRE);
+
+ memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
+ sz_rfbFramebufferUpdateRectHeader);
+ cl->ublen += sz_rfbFramebufferUpdateRectHeader;
+
+ hdr.nSubrects = Swap32IfLE(nSubrects);
+
+ memcpy(&cl->updateBuf[cl->ublen], (char *)&hdr, sz_rfbRREHeader);
+ cl->ublen += sz_rfbRREHeader;
+
+ for (i = 0; i < rreAfterBufLen;) {
+
+ int bytesToCopy = UPDATE_BUF_SIZE - cl->ublen;
+
+ if (i + bytesToCopy > rreAfterBufLen) {
+ bytesToCopy = rreAfterBufLen - i;
+ }
+
+ memcpy(&cl->updateBuf[cl->ublen], &rreAfterBuf[i], bytesToCopy);
+
+ cl->ublen += bytesToCopy;
+ i += bytesToCopy;
+
+ if (cl->ublen == UPDATE_BUF_SIZE) {
+ if (!rfbSendUpdateBuf(cl))
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+
+/*
+ * subrectEncode() encodes the given multicoloured rectangle as a background
+ * colour overwritten by single-coloured rectangles. It returns the number
+ * of subrectangles in the encoded buffer, or -1 if subrect encoding won't
+ * fit in the buffer. It puts the encoded rectangles in rreAfterBuf. The
+ * single-colour rectangle partition is not optimal, but does find the biggest
+ * horizontal or vertical rectangle top-left anchored to each consecutive
+ * coordinate position.
+ *
+ * The coding scheme is simply [<bgcolour><subrect><subrect>...] where each
+ * <subrect> is [<colour><x><y><w><h>].
+ */
+
+#define DEFINE_SUBRECT_ENCODE(bpp) \
+static int \
+subrectEncode##bpp(data,w,h) \
+ uint##bpp##_t *data; \
+ int w; \
+ int h; \
+{ \
+ uint##bpp##_t cl; \
+ rfbCoRRERectangle subrect; \
+ int x,y; \
+ int i,j; \
+ int hx=0,hy,vx=0,vy; \
+ int hyflag; \
+ uint##bpp##_t *seg; \
+ uint##bpp##_t *line; \
+ int hw,hh,vw,vh; \
+ int thex,they,thew,theh; \
+ int numsubs = 0; \
+ int newLen; \
+ uint##bpp##_t bg = (uint##bpp##_t)getBgColour((char*)data,w*h,bpp); \
+ \
+ *((uint##bpp##_t*)rreAfterBuf) = bg; \
+ \
+ rreAfterBufLen = (bpp/8); \
+ \
+ for (y=0; y<h; y++) { \
+ line = data+(y*w); \
+ for (x=0; x<w; x++) { \
+ if (line[x] != bg) { \
+ cl = line[x]; \
+ hy = y-1; \
+ hyflag = 1; \
+ for (j=y; j<h; j++) { \
+ seg = data+(j*w); \
+ if (seg[x] != cl) {break;} \
+ i = x; \
+ while ((seg[i] == cl) && (i < w)) i += 1; \
+ i -= 1; \
+ if (j == y) vx = hx = i; \
+ if (i < vx) vx = i; \
+ if ((hyflag > 0) && (i >= hx)) {hy += 1;} else {hyflag = 0;} \
+ } \
+ vy = j-1; \
+ \
+ /* We now have two possible subrects: (x,y,hx,hy) and (x,y,vx,vy) \
+ * We'll choose the bigger of the two. \
+ */ \
+ hw = hx-x+1; \
+ hh = hy-y+1; \
+ vw = vx-x+1; \
+ vh = vy-y+1; \
+ \
+ thex = x; \
+ they = y; \
+ \
+ if ((hw*hh) > (vw*vh)) { \
+ thew = hw; \
+ theh = hh; \
+ } else { \
+ thew = vw; \
+ theh = vh; \
+ } \
+ \
+ subrect.x = thex; \
+ subrect.y = they; \
+ subrect.w = thew; \
+ subrect.h = theh; \
+ \
+ newLen = rreAfterBufLen + (bpp/8) + sz_rfbCoRRERectangle; \
+ if ((newLen > (w * h * (bpp/8))) || (newLen > rreAfterBufSize)) \
+ return -1; \
+ \
+ numsubs += 1; \
+ *((uint##bpp##_t*)(rreAfterBuf + rreAfterBufLen)) = cl; \
+ rreAfterBufLen += (bpp/8); \
+ memcpy(&rreAfterBuf[rreAfterBufLen],&subrect,sz_rfbCoRRERectangle); \
+ rreAfterBufLen += sz_rfbCoRRERectangle; \
+ \
+ /* \
+ * Now mark the subrect as done. \
+ */ \
+ for (j=they; j < (they+theh); j++) { \
+ for (i=thex; i < (thex+thew); i++) { \
+ data[j*w+i] = bg; \
+ } \
+ } \
+ } \
+ } \
+ } \
+ \
+ return numsubs; \
+}
+
+DEFINE_SUBRECT_ENCODE(8)
+DEFINE_SUBRECT_ENCODE(16)
+DEFINE_SUBRECT_ENCODE(32)
+
+
+/*
+ * getBgColour() gets the most prevalent colour in a byte array.
+ */
+static uint32_t
+getBgColour(data,size,bpp)
+ char *data;
+ int size;
+ int bpp;
+{
+
+#define NUMCLRS 256
+
+ static int counts[NUMCLRS];
+ int i,j,k;
+
+ int maxcount = 0;
+ uint8_t maxclr = 0;
+
+ if (bpp != 8) {
+ if (bpp == 16) {
+ return ((uint16_t *)data)[0];
+ } else if (bpp == 32) {
+ return ((uint32_t *)data)[0];
+ } else {
+ rfbLog("getBgColour: bpp %d?\n",bpp);
+ return 0;
+ }
+ }
+
+ for (i=0; i<NUMCLRS; i++) {
+ counts[i] = 0;
+ }
+
+ for (j=0; j<size; j++) {
+ k = (int)(((uint8_t *)data)[j]);
+ if (k >= NUMCLRS) {
+ rfbLog("getBgColour: unusual colour = %d\n", k);
+ return 0;
+ }
+ counts[k] += 1;
+ if (counts[k] > maxcount) {
+ maxcount = counts[k];
+ maxclr = ((uint8_t *)data)[j];
+ }
+ }
+
+ return maxclr;
+}
diff --git a/libvncserver/cursor.c b/libvncserver/cursor.c
new file mode 100644
index 0000000..4f290da
--- /dev/null
+++ b/libvncserver/cursor.c
@@ -0,0 +1,527 @@
+/*
+ * cursor.c - support for cursor shape updates.
+ */
+
+/*
+ * Copyright (C) 2000, 2001 Const Kaplinsky. All Rights Reserved.
+ * Copyright (C) 1999 AT&T Laboratories Cambridge. 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/rfb.h>
+
+/*
+ * Send cursor shape either in X-style format or in client pixel format.
+ */
+
+rfbBool
+rfbSendCursorShape(cl)
+ rfbClientPtr cl;
+{
+ rfbCursorPtr pCursor;
+ rfbFramebufferUpdateRectHeader rect;
+ rfbXCursorColors colors;
+ int saved_ublen;
+ int bitmapRowBytes, maskBytes, dataBytes;
+ int i, j;
+ uint8_t *bitmapData;
+ uint8_t bitmapByte;
+
+ pCursor = cl->screen->getCursorPtr(cl);
+ /*if(!pCursor) return TRUE;*/
+
+ if (cl->useRichCursorEncoding) {
+ if(pCursor && !pCursor->richSource)
+ MakeRichCursorFromXCursor(cl->screen,pCursor);
+ rect.encoding = Swap32IfLE(rfbEncodingRichCursor);
+ } else {
+ if(pCursor && !pCursor->source)
+ MakeXCursorFromRichCursor(cl->screen,pCursor);
+ rect.encoding = Swap32IfLE(rfbEncodingXCursor);
+ }
+
+ /* If there is no cursor, send update with empty cursor data. */
+
+ if ( pCursor && pCursor->width == 1 &&
+ pCursor->height == 1 &&
+ pCursor->mask[0] == 0 ) {
+ pCursor = NULL;
+ }
+
+ if (pCursor == NULL) {
+ if (cl->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE ) {
+ if (!rfbSendUpdateBuf(cl))
+ return FALSE;
+ }
+ rect.r.x = rect.r.y = 0;
+ rect.r.w = rect.r.h = 0;
+ memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
+ sz_rfbFramebufferUpdateRectHeader);
+ cl->ublen += sz_rfbFramebufferUpdateRectHeader;
+
+ cl->rfbCursorShapeBytesSent += sz_rfbFramebufferUpdateRectHeader;
+ cl->rfbCursorShapeUpdatesSent++;
+
+ if (!rfbSendUpdateBuf(cl))
+ return FALSE;
+
+ return TRUE;
+ }
+
+ /* Calculate data sizes. */
+
+ bitmapRowBytes = (pCursor->width + 7) / 8;
+ maskBytes = bitmapRowBytes * pCursor->height;
+ dataBytes = (cl->useRichCursorEncoding) ?
+ (pCursor->width * pCursor->height *
+ (cl->format.bitsPerPixel / 8)) : maskBytes;
+
+ /* Send buffer contents if needed. */
+
+ if ( cl->ublen + sz_rfbFramebufferUpdateRectHeader +
+ sz_rfbXCursorColors + maskBytes + dataBytes > UPDATE_BUF_SIZE ) {
+ if (!rfbSendUpdateBuf(cl))
+ return FALSE;
+ }
+
+ if ( cl->ublen + sz_rfbFramebufferUpdateRectHeader +
+ sz_rfbXCursorColors + maskBytes + dataBytes > UPDATE_BUF_SIZE ) {
+ return FALSE; /* FIXME. */
+ }
+
+ saved_ublen = cl->ublen;
+
+ /* Prepare rectangle header. */
+
+ rect.r.x = Swap16IfLE(pCursor->xhot);
+ rect.r.y = Swap16IfLE(pCursor->yhot);
+ rect.r.w = Swap16IfLE(pCursor->width);
+ rect.r.h = Swap16IfLE(pCursor->height);
+
+ memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,sz_rfbFramebufferUpdateRectHeader);
+ cl->ublen += sz_rfbFramebufferUpdateRectHeader;
+
+ /* Prepare actual cursor data (depends on encoding used). */
+
+ if (!cl->useRichCursorEncoding) {
+ /* XCursor encoding. */
+ colors.foreRed = (char)(pCursor->foreRed >> 8);
+ colors.foreGreen = (char)(pCursor->foreGreen >> 8);
+ colors.foreBlue = (char)(pCursor->foreBlue >> 8);
+ colors.backRed = (char)(pCursor->backRed >> 8);
+ colors.backGreen = (char)(pCursor->backGreen >> 8);
+ colors.backBlue = (char)(pCursor->backBlue >> 8);
+
+ memcpy(&cl->updateBuf[cl->ublen], (char *)&colors, sz_rfbXCursorColors);
+ cl->ublen += sz_rfbXCursorColors;
+
+ bitmapData = (uint8_t *)pCursor->source;
+
+ for (i = 0; i < pCursor->height; i++) {
+ for (j = 0; j < bitmapRowBytes; j++) {
+ bitmapByte = bitmapData[i * bitmapRowBytes + j];
+ cl->updateBuf[cl->ublen++] = (char)bitmapByte;
+ }
+ }
+ } else {
+ /* RichCursor encoding. */
+ int bpp1=cl->screen->rfbServerFormat.bitsPerPixel/8,
+ bpp2=cl->format.bitsPerPixel/8;
+ (*cl->translateFn)(cl->translateLookupTable,
+ &(cl->screen->rfbServerFormat),
+ &cl->format, (char*)pCursor->richSource,
+ &cl->updateBuf[cl->ublen],
+ pCursor->width*bpp1, pCursor->width, pCursor->height);
+
+ cl->ublen += pCursor->width*bpp2*pCursor->height;
+ }
+
+ /* Prepare transparency mask. */
+
+ bitmapData = (uint8_t *)pCursor->mask;
+
+ for (i = 0; i < pCursor->height; i++) {
+ for (j = 0; j < bitmapRowBytes; j++) {
+ bitmapByte = bitmapData[i * bitmapRowBytes + j];
+ cl->updateBuf[cl->ublen++] = (char)bitmapByte;
+ }
+ }
+
+ /* Send everything we have prepared in the cl->updateBuf[]. */
+
+ cl->rfbCursorShapeBytesSent += (cl->ublen - saved_ublen);
+ cl->rfbCursorShapeUpdatesSent++;
+
+ if (!rfbSendUpdateBuf(cl))
+ return FALSE;
+
+ return TRUE;
+}
+
+/*
+ * Send cursor position (PointerPos pseudo-encoding).
+ */
+
+rfbBool
+rfbSendCursorPos(rfbClientPtr cl)
+{
+ rfbFramebufferUpdateRectHeader rect;
+
+ if (cl->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) {
+ if (!rfbSendUpdateBuf(cl))
+ return FALSE;
+ }
+
+ rect.encoding = Swap32IfLE(rfbEncodingPointerPos);
+ rect.r.x = Swap16IfLE(cl->screen->cursorX);
+ rect.r.y = Swap16IfLE(cl->screen->cursorY);
+ rect.r.w = 0;
+ rect.r.h = 0;
+
+ memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
+ sz_rfbFramebufferUpdateRectHeader);
+ cl->ublen += sz_rfbFramebufferUpdateRectHeader;
+
+ cl->rfbCursorPosBytesSent += sz_rfbFramebufferUpdateRectHeader;
+ cl->rfbCursorPosUpdatesSent++;
+
+ if (!rfbSendUpdateBuf(cl))
+ return FALSE;
+
+ return TRUE;
+}
+
+/* conversion routine for predefined cursors in LSB order */
+unsigned char rfbReverseByte[0x100] = {
+ /* copied from Xvnc/lib/font/util/utilbitmap.c */
+ 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+ 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+ 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+ 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+ 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+ 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+ 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+ 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+ 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+ 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+ 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+ 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+ 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+ 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+ 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+ 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+ 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+ 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+ 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+ 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+ 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+ 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+ 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+ 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+ 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+ 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+ 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+ 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+ 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+ 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+ 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+ 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
+};
+
+void rfbConvertLSBCursorBitmapOrMask(int width,int height,unsigned char* bitmap)
+{
+ int i,t=(width+7)/8*height;
+ for(i=0;i<t;i++)
+ bitmap[i]=rfbReverseByte[(int)bitmap[i]];
+}
+
+/* Cursor creation. You "paint" a cursor and let these routines do the work */
+
+rfbCursorPtr rfbMakeXCursor(int width,int height,char* cursorString,char* maskString)
+{
+ int i,j,w=(width+7)/8;
+ rfbCursorPtr cursor = (rfbCursorPtr)calloc(1,sizeof(rfbCursor));
+ char* cp;
+ unsigned char bit;
+
+ cursor->cleanup=TRUE;
+ cursor->width=width;
+ cursor->height=height;
+ /*cursor->backRed=cursor->backGreen=cursor->backBlue=0xffff;*/
+ cursor->foreRed=cursor->foreGreen=cursor->foreBlue=0xffff;
+
+ cursor->source = (unsigned char*)calloc(w,height);
+ cursor->cleanupSource = TRUE;
+ for(j=0,cp=cursorString;j<height;j++)
+ for(i=0,bit=0x80;i<width;i++,bit=(bit&1)?0x80:bit>>1,cp++)
+ if(*cp!=' ') cursor->source[j*w+i/8]|=bit;
+
+ if(maskString) {
+ cursor->mask = (unsigned char*)calloc(w,height);
+ for(j=0,cp=maskString;j<height;j++)
+ for(i=0,bit=0x80;i<width;i++,bit=(bit&1)?0x80:bit>>1,cp++)
+ if(*cp!=' ') cursor->mask[j*w+i/8]|=bit;
+ } else
+ cursor->mask = (unsigned char*)rfbMakeMaskForXCursor(width,height,(char*)cursor->source);
+ cursor->cleanupMask = TRUE;
+
+ return(cursor);
+}
+
+char* rfbMakeMaskForXCursor(int width,int height,char* source)
+{
+ int i,j,w=(width+7)/8;
+ char* mask=(char*)calloc(w,height);
+ unsigned char c;
+
+ for(j=0;j<height;j++)
+ for(i=w-1;i>=0;i--) {
+ c=source[j*w+i];
+ if(j>0) c|=source[(j-1)*w+i];
+ if(j<height-1) c|=source[(j+1)*w+i];
+
+ if(i>0 && (c&0x80))
+ mask[j*w+i-1]|=0x01;
+ if(i<w-1 && (c&0x01))
+ mask[j*w+i+1]|=0x80;
+
+ mask[j*w+i]|=(c<<1)|c|(c>>1);
+ }
+
+ return(mask);
+}
+
+void rfbFreeCursor(rfbCursorPtr cursor)
+{
+ if(cursor) {
+ if(cursor->cleanupRichSource && cursor->richSource)
+ free(cursor->richSource);
+ if(cursor->cleanupSource && cursor->source)
+ free(cursor->source);
+ if(cursor->cleanupMask && cursor->mask)
+ free(cursor->mask);
+ if(cursor->cleanup)
+ free(cursor);
+ else {
+ cursor->cleanup=cursor->cleanupSource=cursor->cleanupMask
+ =cursor->cleanupRichSource=FALSE;
+ cursor->source=cursor->mask=cursor->richSource=0;
+ }
+ }
+
+}
+
+/* background and foregroud colour have to be set beforehand */
+void MakeXCursorFromRichCursor(rfbScreenInfoPtr rfbScreen,rfbCursorPtr cursor)
+{
+ rfbPixelFormat* format=&rfbScreen->rfbServerFormat;
+ int i,j,w=(cursor->width+7)/8,bpp=format->bitsPerPixel/8,
+ width=cursor->width*bpp;
+ uint32_t background;
+ char *back=(char*)&background;
+ unsigned char bit;
+
+ if(cursor->source && cursor->cleanupSource)
+ free(cursor->source);
+ cursor->source=(unsigned char*)calloc(w,cursor->height);
+ cursor->cleanupSource=TRUE;
+
+ if(format->bigEndian)
+ back+=4-bpp;
+
+ background=cursor->backRed<<format->redShift|
+ cursor->backGreen<<format->greenShift|cursor->backBlue<<format->blueShift;
+
+ for(j=0;j<cursor->height;j++)
+ for(i=0,bit=0x80;i<cursor->width;i++,bit=(bit&1)?0x80:bit>>1)
+ if(memcmp(cursor->richSource+j*width+i*bpp,back,bpp))
+ cursor->source[j*w+i/8]|=bit;
+}
+
+void MakeRichCursorFromXCursor(rfbScreenInfoPtr rfbScreen,rfbCursorPtr cursor)
+{
+ rfbPixelFormat* format=&rfbScreen->rfbServerFormat;
+ int i,j,w=(cursor->width+7)/8,bpp=format->bitsPerPixel/8;
+ uint32_t background,foreground;
+ char *back=(char*)&background,*fore=(char*)&foreground;
+ unsigned char *cp;
+ unsigned char bit;
+
+ if(cursor->richSource && cursor->cleanupRichSource)
+ free(cursor->richSource);
+ cp=cursor->richSource=(unsigned char*)calloc(cursor->width*bpp,cursor->height);
+ cursor->cleanupRichSource=TRUE;
+
+ if(format->bigEndian) {
+ back+=4-bpp;
+ fore+=4-bpp;
+ }
+
+ background=cursor->backRed<<format->redShift|
+ cursor->backGreen<<format->greenShift|cursor->backBlue<<format->blueShift;
+ foreground=cursor->foreRed<<format->redShift|
+ cursor->foreGreen<<format->greenShift|cursor->foreBlue<<format->blueShift;
+
+ for(j=0;j<cursor->height;j++)
+ for(i=0,bit=0x80;i<cursor->height;i++,bit=(bit&1)?0x80:bit>>1,cp+=bpp)
+ if(cursor->source[j*w+i/8]&bit) memcpy(cp,fore,bpp);
+ else memcpy(cp,back,bpp);
+}
+
+/* functions to draw/hide cursor directly in the frame buffer */
+
+void rfbUndrawCursor(rfbScreenInfoPtr s)
+{
+ rfbCursorPtr c=s->cursor;
+ int j,x1,x2,y1,y2,bpp=s->rfbServerFormat.bitsPerPixel/8,
+ rowstride=s->paddedWidthInBytes;
+ LOCK(s->cursorMutex);
+ if(!s->cursorIsDrawn) {
+ UNLOCK(s->cursorMutex);
+ return;
+ }
+
+ /* restore what is under the cursor */
+ x1=s->cursorX-c->xhot;
+ x2=x1+c->width;
+ if(x1<0) x1=0;
+ if(x2>=s->width) x2=s->width-1;
+ x2-=x1; if(x2<=0) {
+ UNLOCK(s->cursorMutex);
+ return;
+ }
+ y1=s->cursorY-c->yhot;
+ y2=y1+c->height;
+ if(y1<0) y1=0;
+ if(y2>=s->height) y2=s->height-1;
+ y2-=y1; if(y2<=0) {
+ UNLOCK(s->cursorMutex);
+ return;
+ }
+
+ /* get saved data */
+ for(j=0;j<y2;j++)
+ memcpy(s->frameBuffer+(y1+j)*rowstride+x1*bpp,
+ s->underCursorBuffer+j*x2*bpp,
+ x2*bpp);
+
+ /* rfbMarkRectAsModified(s,x1,y1,x1+x2,y1+y2); */
+ s->cursorIsDrawn = FALSE;
+ UNLOCK(s->cursorMutex);
+}
+
+void rfbDrawCursor(rfbScreenInfoPtr s)
+{
+ rfbCursorPtr c=s->cursor;
+ int i,j,x1,x2,y1,y2,i1,j1,bpp=s->rfbServerFormat.bitsPerPixel/8,
+ rowstride=s->paddedWidthInBytes,
+ bufSize,w;
+ rfbBool wasChanged=FALSE;
+
+ if(!c) return;
+ LOCK(s->cursorMutex);
+ if(s->cursorIsDrawn) {
+ /* is already drawn */
+ UNLOCK(s->cursorMutex);
+ return;
+ }
+ bufSize=c->width*c->height*bpp;
+ w=(c->width+7)/8;
+ if(s->underCursorBufferLen<bufSize) {
+ if(s->underCursorBuffer!=NULL)
+ free(s->underCursorBuffer);
+ s->underCursorBuffer=malloc(bufSize);
+ s->underCursorBufferLen=bufSize;
+ }
+ /* save what is under the cursor */
+ i1=j1=0; /* offset in cursor */
+ x1=s->cursorX-c->xhot;
+ x2=x1+c->width;
+ if(x1<0) { i1=-x1; x1=0; }
+ if(x2>=s->width) x2=s->width-1;
+ x2-=x1; if(x2<=0) {
+ UNLOCK(s->cursorMutex);
+ return; /* nothing to do */
+ }
+ y1=s->cursorY-c->yhot;
+ y2=y1+c->height;
+ if(y1<0) { j1=-y1; y1=0; }
+ if(y2>=s->height) y2=s->height-1;
+ y2-=y1; if(y2<=0) {
+ UNLOCK(s->cursorMutex);
+ return; /* nothing to do */
+ }
+
+ /* save data */
+ for(j=0;j<y2;j++) {
+ char* dest=s->underCursorBuffer+j*x2*bpp;
+ const char* src=s->frameBuffer+(y1+j)*rowstride+x1*bpp;
+ unsigned int count=x2*bpp;
+ if(wasChanged || memcmp(dest,src,count)) {
+ wasChanged=TRUE;
+ memcpy(dest,src,count);
+ }
+ }
+
+ if(!c->richSource)
+ MakeRichCursorFromXCursor(s,c);
+
+ /* now the cursor has to be drawn */
+ for(j=0;j<y2;j++)
+ for(i=0;i<x2;i++)
+ if((c->mask[(j+j1)*w+(i+i1)/8]<<((i+i1)&7))&0x80)
+ memcpy(s->frameBuffer+(j+y1)*rowstride+(i+x1)*bpp,
+ c->richSource+(j+j1)*c->width*bpp+(i+i1)*bpp,bpp);
+
+ if(wasChanged)
+ rfbMarkRectAsModified(s,x1,y1,x1+x2,y1+y2);
+ s->cursorIsDrawn = TRUE;
+ UNLOCK(s->cursorMutex);
+}
+
+/* for debugging */
+
+void rfbPrintXCursor(rfbCursorPtr cursor)
+{
+ int i,i1,j,w=(cursor->width+7)/8;
+ unsigned char bit;
+ for(j=0;j<cursor->height;j++) {
+ for(i=0,i1=0,bit=0x80;i1<cursor->width;i1++,i+=(bit&1)?1:0,bit=(bit&1)?0x80:bit>>1)
+ if(cursor->source[j*w+i]&bit) putchar('#'); else putchar(' ');
+ putchar(':');
+ for(i=0,i1=0,bit=0x80;i1<cursor->width;i1++,i+=(bit&1)?1:0,bit=(bit&1)?0x80:bit>>1)
+ if(cursor->mask[j*w+i]&bit) putchar('#'); else putchar(' ');
+ putchar('\n');
+ }
+}
+
+void rfbSetCursor(rfbScreenInfoPtr rfbScreen,rfbCursorPtr c,rfbBool freeOld)
+{
+ LOCK(rfbScreen->cursorMutex);
+ while(rfbScreen->cursorIsDrawn) {
+ UNLOCK(rfbScreen->cursorMutex);
+ rfbUndrawCursor(rfbScreen);
+ LOCK(rfbScreen->cursorMutex);
+ }
+
+ if(rfbScreen->cursor && (freeOld || rfbScreen->cursor->cleanup))
+ rfbFreeCursor(rfbScreen->cursor);
+
+ rfbScreen->cursor = c;
+
+ UNLOCK(rfbScreen->cursorMutex);
+}
diff --git a/libvncserver/cutpaste.c b/libvncserver/cutpaste.c
new file mode 100755
index 0000000..6a9dcb9
--- /dev/null
+++ b/libvncserver/cutpaste.c
@@ -0,0 +1,38 @@
+/*
+ * cutpaste.c - routines to deal with cut & paste buffers / selection.
+ */
+
+/*
+ * OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
+ * Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge.
+ * 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/rfb.h>
+
+
+/*
+ * rfbSetXCutText sets the cut buffer to be the given string. We also clear
+ * the primary selection. Ideally we'd like to set it to the same thing, but I
+ * can't work out how to do that without some kind of helper X client.
+ */
+
+void rfbGotXCutText(rfbScreenInfoPtr rfbScreen, char *str, int len)
+{
+ rfbSendServerCutText(rfbScreen, str, len);
+}
diff --git a/libvncserver/d3des.c b/libvncserver/d3des.c
new file mode 100755
index 0000000..4994afb
--- /dev/null
+++ b/libvncserver/d3des.c
@@ -0,0 +1,442 @@
+/*
+ * 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 long KnR[32] = { 0L };
+static unsigned long Kn3[32] = { 0L };
+static unsigned char Df_Key[24] = {
+ 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,
+ 0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10,
+ 0x89,0xab,0xcd,0xef,0x01,0x23,0x45,0x67 };
+*/
+
+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/libvncserver/d3des.h b/libvncserver/d3des.h
new file mode 100755
index 0000000..b2f9724
--- /dev/null
+++ b/libvncserver/d3des.h
@@ -0,0 +1,56 @@
+#ifndef D3DES_H
+#define D3DES_H
+
+/*
+ * 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
+ ********************************************************************/
+
+#endif
diff --git a/libvncserver/draw.c b/libvncserver/draw.c
new file mode 100755
index 0000000..7e1ed49
--- /dev/null
+++ b/libvncserver/draw.c
@@ -0,0 +1,61 @@
+#include <rfb/rfb.h>
+
+void rfbFillRect(rfbScreenInfoPtr s,int x1,int y1,int x2,int y2,rfbPixel col)
+{
+ int rowstride = s->paddedWidthInBytes, bpp = s->bitsPerPixel>>3;
+ int i,j;
+ char* colour=(char*)&col;
+
+ if(!rfbEndianTest)
+ colour += 4-bpp;
+ for(j=y1;j<y2;j++)
+ for(i=x1;i<x2;i++)
+ memcpy(s->frameBuffer+j*rowstride+i*bpp,colour,bpp);
+ rfbMarkRectAsModified(s,x1,y1,x2,y2);
+}
+
+#define SETPIXEL(x,y) \
+ memcpy(s->frameBuffer+(y)*rowstride+(x)*bpp,colour,bpp)
+
+void rfbDrawPixel(rfbScreenInfoPtr s,int x,int y,rfbPixel col)
+{
+ int rowstride = s->paddedWidthInBytes, bpp = s->bitsPerPixel>>3;
+ char* colour=(char*)&col;
+
+ if(!rfbEndianTest)
+ colour += 4-bpp;
+ SETPIXEL(x,y);
+ rfbMarkRectAsModified(s,x,y,x+1,y+1);
+}
+
+void rfbDrawLine(rfbScreenInfoPtr s,int x1,int y1,int x2,int y2,rfbPixel col)
+{
+ int rowstride = s->paddedWidthInBytes, bpp = s->bitsPerPixel>>3;
+ int i;
+ char* colour=(char*)&col;
+
+ if(!rfbEndianTest)
+ colour += 4-bpp;
+
+#define SWAPPOINTS { i=x1; x1=x2; x2=i; i=y1; y1=y2; y2=i; }
+ if(abs(x1-x2)<abs(y1-y2)) {
+ if(y1>y2)
+ SWAPPOINTS
+ for(i=y1;i<=y2;i++)
+ SETPIXEL(x1+(i-y1)*(x2-x1)/(y2-y1),i);
+ /* TODO: Maybe make this more intelligently? */
+ if(x2<x1) { i=x1; x1=x2; x2=i; }
+ rfbMarkRectAsModified(s,x1,y1,x2+1,y2+1);
+ } else {
+ if(x1>x2)
+ SWAPPOINTS
+ else if(x1==x2) {
+ rfbDrawPixel(s,x1,y1,col);
+ return;
+ }
+ for(i=x1;i<=x2;i++)
+ SETPIXEL(i,y1+(i-x1)*(y2-y1)/(x2-x1));
+ if(y2<y1) { i=y1; y1=y2; y2=i; }
+ rfbMarkRectAsModified(s,x1,y1,x2+1,y2+1);
+ }
+}
diff --git a/libvncserver/font.c b/libvncserver/font.c
new file mode 100755
index 0000000..423d415
--- /dev/null
+++ b/libvncserver/font.c
@@ -0,0 +1,192 @@
+#include <rfb/rfb.h>
+
+int rfbDrawChar(rfbScreenInfoPtr rfbScreen,rfbFontDataPtr font,
+ int x,int y,unsigned char c,rfbPixel col)
+{
+ int i,j,width,height;
+ unsigned char* data=font->data+font->metaData[c*5];
+ unsigned char d=*data;
+ int rowstride=rfbScreen->paddedWidthInBytes;
+ int bpp=rfbScreen->rfbServerFormat.bitsPerPixel/8;
+ char *colour=(char*)&col;
+
+ if(!rfbEndianTest)
+ colour += 4-bpp;
+
+ width=font->metaData[c*5+1];
+ height=font->metaData[c*5+2];
+ x+=font->metaData[c*5+3];
+ y+=-font->metaData[c*5+4]-height+1;
+
+ for(j=0;j<height;j++) {
+ for(i=0;i<width;i++) {
+ if((i&7)==0) {
+ d=*data;
+ data++;
+ }
+ if(d&0x80)
+ memcpy(rfbScreen->frameBuffer+(y+j)*rowstride+(x+i)*bpp,colour,bpp);
+ d<<=1;
+ }
+ /* if((i&7)!=0) data++; */
+ }
+ return(width);
+}
+
+void rfbDrawString(rfbScreenInfoPtr rfbScreen,rfbFontDataPtr font,
+ int x,int y,const char* string,rfbPixel colour)
+{
+ while(*string) {
+ x+=rfbDrawChar(rfbScreen,font,x,y,*string,colour);
+ string++;
+ }
+}
+
+/* TODO: these two functions need to be more efficient */
+int rfbDrawCharWithClip(rfbScreenInfoPtr rfbScreen,rfbFontDataPtr font,
+ int x,int y,unsigned char c,
+ int x1,int y1,int x2,int y2,
+ rfbPixel col,rfbPixel bcol)
+{
+ int i,j,width,height;
+ unsigned char* data=font->data+font->metaData[c*5];
+ unsigned char d;
+ int rowstride=rfbScreen->paddedWidthInBytes;
+ int bpp=rfbScreen->rfbServerFormat.bitsPerPixel/8,extra_bytes=0;
+ char* colour=(char*)&col;
+ char* bcolour=(char*)&bcol;
+
+ if(!rfbEndianTest) {
+ colour+=4-bpp;
+ bcolour+=4-bpp;
+ }
+
+ width=font->metaData[c*5+1];
+ height=font->metaData[c*5+2];
+ x+=font->metaData[c*5+3];
+ y+=-font->metaData[c*5+4]-height+1;
+
+ /* after clipping, x2 will be count of bytes between rows,
+ * x1 start of i, y1 start of j, width and height will be adjusted. */
+ if(y1>y) { y1-=y; data+=(width+7)/8; height-=y1; y+=y1; } else y1=0;
+ if(x1>x) { x1-=x; data+=x1; width-=x1; x+=x1; extra_bytes+=x1/8; } else x1=0;
+ if(y2<y+height) height-=y+height-y2;
+ if(x2<x+width) { extra_bytes+=(x1+width)/8-(x+width-x2+7)/8; width-=x+width-x2; }
+
+ d=*data;
+ for(j=y1;j<height;j++) {
+ if((x1&7)!=0)
+ d=data[-1]; /* TODO: check if in this case extra_bytes is correct! */
+ for(i=x1;i<width;i++) {
+ if((i&7)==0) {
+ d=*data;
+ data++;
+ }
+ /* if(x+i>=x1 && x+i<x2 && y+j>=y1 && y+j<y2) */ {
+ if(d&0x80) {
+ memcpy(rfbScreen->frameBuffer+(y+j)*rowstride+(x+i)*bpp,
+ colour,bpp);
+ } else if(bcol!=col) {
+ memcpy(rfbScreen->frameBuffer+(y+j)*rowstride+(x+i)*bpp,
+ bcolour,bpp);
+ }
+ }
+ d<<=1;
+ }
+ /* if((i&7)==0) data++; */
+ data += extra_bytes;
+ }
+ return(width);
+}
+
+void rfbDrawStringWithClip(rfbScreenInfoPtr rfbScreen,rfbFontDataPtr font,
+ int x,int y,const char* string,
+ int x1,int y1,int x2,int y2,
+ rfbPixel colour,rfbPixel backColour)
+{
+ while(*string) {
+ x+=rfbDrawCharWithClip(rfbScreen,font,x,y,*string,x1,y1,x2,y2,
+ colour,backColour);
+ string++;
+ }
+}
+
+int rfbWidthOfString(rfbFontDataPtr font,const char* string)
+{
+ int i=0;
+ while(*string) {
+ i+=font->metaData[*string*5+1];
+ string++;
+ }
+ return(i);
+}
+
+int rfbWidthOfChar(rfbFontDataPtr font,unsigned char c)
+{
+ return(font->metaData[c*5+1]+font->metaData[c*5+3]);
+}
+
+void rfbFontBBox(rfbFontDataPtr font,unsigned char c,int* x1,int* y1,int* x2,int* y2)
+{
+ *x1+=font->metaData[c*5+3];
+ *y1+=-font->metaData[c*5+4]-font->metaData[c*5+2]+1;
+ *x2=*x1+font->metaData[c*5+1];
+ *y2=*y1+font->metaData[c*5+2];
+}
+
+#ifndef INT_MAX
+#define INT_MAX 0x7fffffff
+#endif
+
+void rfbWholeFontBBox(rfbFontDataPtr font,
+ int *x1, int *y1, int *x2, int *y2)
+{
+ int i;
+ int* m=font->metaData;
+
+ (*x1)=(*y1)=INT_MAX; (*x2)=(*y2)=-INT_MAX+1;
+ for(i=0;i<256;i++) {
+ if(m[i*5+1]-m[i*5+3]>(*x2))
+ (*x2)=m[i*5+1]-m[i*5+3];
+ if(-m[i*5+2]+m[i*5+4]<(*y1))
+ (*y1)=-m[i*5+2]+m[i*5+4];
+ if(m[i*5+3]<(*x1))
+ (*x1)=m[i*5+3];
+ if(-m[i*5+4]>(*y2))
+ (*y2)=-m[i*5+4];
+ }
+}
+
+rfbFontDataPtr rfbLoadConsoleFont(char *filename)
+{
+ FILE *f=fopen(filename,"rb");
+ rfbFontDataPtr p;
+ int i;
+
+ if(!f) return(0);
+
+ p=(rfbFontDataPtr)malloc(sizeof(rfbFontData));
+ p->data=(unsigned char*)malloc(4096);
+ if(1!=fread(p->data,4096,1,f)) {
+ free(p->data);
+ free(p);
+ return(0);
+ }
+ fclose(f);
+ p->metaData=(int*)malloc(256*5*sizeof(int));
+ for(i=0;i<256;i++) {
+ p->metaData[i*5+0]=i*16; /* offset */
+ p->metaData[i*5+1]=8; /* width */
+ p->metaData[i*5+2]=16; /* height */
+ p->metaData[i*5+3]=0; /* xhot */
+ p->metaData[i*5+4]=0; /* yhot */
+ }
+ return(p);
+}
+
+void rfbFreeFont(rfbFontDataPtr f)
+{
+ free(f->data);
+ free(f->metaData);
+ free(f);
+}
diff --git a/libvncserver/hextile.c b/libvncserver/hextile.c
new file mode 100755
index 0000000..e13021b
--- /dev/null
+++ b/libvncserver/hextile.c
@@ -0,0 +1,346 @@
+/*
+ * hextile.c
+ *
+ * Routines to implement Hextile Encoding
+ */
+
+/*
+ * OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
+ * Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge.
+ * 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/rfb.h>
+
+static rfbBool sendHextiles8(rfbClientPtr cl, int x, int y, int w, int h);
+static rfbBool sendHextiles16(rfbClientPtr cl, int x, int y, int w, int h);
+static rfbBool sendHextiles32(rfbClientPtr cl, int x, int y, int w, int h);
+
+
+/*
+ * rfbSendRectEncodingHextile - send a rectangle using hextile encoding.
+ */
+
+rfbBool
+rfbSendRectEncodingHextile(cl, x, y, w, h)
+ rfbClientPtr cl;
+ int x, y, w, h;
+{
+ rfbFramebufferUpdateRectHeader rect;
+
+ if (cl->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) {
+ if (!rfbSendUpdateBuf(cl))
+ return FALSE;
+ }
+
+ rect.r.x = Swap16IfLE(x);
+ rect.r.y = Swap16IfLE(y);
+ rect.r.w = Swap16IfLE(w);
+ rect.r.h = Swap16IfLE(h);
+ rect.encoding = Swap32IfLE(rfbEncodingHextile);
+
+ memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
+ sz_rfbFramebufferUpdateRectHeader);
+ cl->ublen += sz_rfbFramebufferUpdateRectHeader;
+
+ cl->rfbRectanglesSent[rfbEncodingHextile]++;
+ cl->rfbBytesSent[rfbEncodingHextile] += sz_rfbFramebufferUpdateRectHeader;
+
+ switch (cl->format.bitsPerPixel) {
+ case 8:
+ return sendHextiles8(cl, x, y, w, h);
+ case 16:
+ return sendHextiles16(cl, x, y, w, h);
+ case 32:
+ return sendHextiles32(cl, x, y, w, h);
+ }
+
+ rfbLog("rfbSendRectEncodingHextile: bpp %d?\n", cl->format.bitsPerPixel);
+ return FALSE;
+}
+
+
+#define PUT_PIXEL8(pix) (cl->updateBuf[cl->ublen++] = (pix))
+
+#define PUT_PIXEL16(pix) (cl->updateBuf[cl->ublen++] = ((char*)&(pix))[0], \
+ cl->updateBuf[cl->ublen++] = ((char*)&(pix))[1])
+
+#define PUT_PIXEL32(pix) (cl->updateBuf[cl->ublen++] = ((char*)&(pix))[0], \
+ cl->updateBuf[cl->ublen++] = ((char*)&(pix))[1], \
+ cl->updateBuf[cl->ublen++] = ((char*)&(pix))[2], \
+ cl->updateBuf[cl->ublen++] = ((char*)&(pix))[3])
+
+
+#define DEFINE_SEND_HEXTILES(bpp) \
+ \
+ \
+static rfbBool subrectEncode##bpp(rfbClientPtr cli, uint##bpp##_t *data, int w, int h, \
+ uint##bpp##_t bg, uint##bpp##_t fg, rfbBool mono); \
+static void testColours##bpp(uint##bpp##_t *data, int size, rfbBool *mono, \
+ rfbBool *solid, uint##bpp##_t *bg, uint##bpp##_t *fg); \
+ \
+ \
+/* \
+ * rfbSendHextiles \
+ */ \
+ \
+static rfbBool \
+sendHextiles##bpp(cl, rx, ry, rw, rh) \
+ rfbClientPtr cl; \
+ int rx, ry, rw, rh; \
+{ \
+ int x, y, w, h; \
+ int startUblen; \
+ char *fbptr; \
+ uint##bpp##_t bg = 0, fg = 0, newBg, newFg; \
+ rfbBool mono, solid; \
+ rfbBool validBg = FALSE; \
+ rfbBool validFg = FALSE; \
+ uint##bpp##_t clientPixelData[16*16*(bpp/8)]; \
+ \
+ for (y = ry; y < ry+rh; y += 16) { \
+ for (x = rx; x < rx+rw; x += 16) { \
+ w = h = 16; \
+ if (rx+rw - x < 16) \
+ w = rx+rw - x; \
+ if (ry+rh - y < 16) \
+ h = ry+rh - y; \
+ \
+ if ((cl->ublen + 1 + (2 + 16 * 16) * (bpp/8)) > \
+ UPDATE_BUF_SIZE) { \
+ if (!rfbSendUpdateBuf(cl)) \
+ return FALSE; \
+ } \
+ \
+ fbptr = (cl->screen->frameBuffer + (cl->screen->paddedWidthInBytes * y) \
+ + (x * (cl->screen->bitsPerPixel / 8))); \
+ \
+ (*cl->translateFn)(cl->translateLookupTable, &(cl->screen->rfbServerFormat), \
+ &cl->format, fbptr, (char *)clientPixelData, \
+ cl->screen->paddedWidthInBytes, w, h); \
+ \
+ startUblen = cl->ublen; \
+ cl->updateBuf[startUblen] = 0; \
+ cl->ublen++; \
+ \
+ testColours##bpp(clientPixelData, w * h, \
+ &mono, &solid, &newBg, &newFg); \
+ \
+ if (!validBg || (newBg != bg)) { \
+ validBg = TRUE; \
+ bg = newBg; \
+ cl->updateBuf[startUblen] |= rfbHextileBackgroundSpecified; \
+ PUT_PIXEL##bpp(bg); \
+ } \
+ \
+ if (solid) { \
+ cl->rfbBytesSent[rfbEncodingHextile] += cl->ublen - startUblen; \
+ continue; \
+ } \
+ \
+ cl->updateBuf[startUblen] |= rfbHextileAnySubrects; \
+ \
+ if (mono) { \
+ if (!validFg || (newFg != fg)) { \
+ validFg = TRUE; \
+ fg = newFg; \
+ cl->updateBuf[startUblen] |= rfbHextileForegroundSpecified; \
+ PUT_PIXEL##bpp(fg); \
+ } \
+ } else { \
+ validFg = FALSE; \
+ cl->updateBuf[startUblen] |= rfbHextileSubrectsColoured; \
+ } \
+ \
+ if (!subrectEncode##bpp(cl, clientPixelData, w, h, bg, fg, mono)) { \
+ /* encoding was too large, use raw */ \
+ validBg = FALSE; \
+ validFg = FALSE; \
+ cl->ublen = startUblen; \
+ cl->updateBuf[cl->ublen++] = rfbHextileRaw; \
+ (*cl->translateFn)(cl->translateLookupTable, \
+ &(cl->screen->rfbServerFormat), &cl->format, fbptr, \
+ (char *)clientPixelData, \
+ cl->screen->paddedWidthInBytes, w, h); \
+ \
+ memcpy(&cl->updateBuf[cl->ublen], (char *)clientPixelData, \
+ w * h * (bpp/8)); \
+ \
+ cl->ublen += w * h * (bpp/8); \
+ } \
+ \
+ cl->rfbBytesSent[rfbEncodingHextile] += cl->ublen - startUblen; \
+ } \
+ } \
+ \
+ return TRUE; \
+} \
+ \
+ \
+static rfbBool \
+subrectEncode##bpp(rfbClientPtr cl, uint##bpp##_t *data, int w, int h, \
+ uint##bpp##_t bg, uint##bpp##_t fg, rfbBool mono) \
+{ \
+ uint##bpp##_t cl2; \
+ int x,y; \
+ int i,j; \
+ int hx=0,hy,vx=0,vy; \
+ int hyflag; \
+ uint##bpp##_t *seg; \
+ uint##bpp##_t *line; \
+ int hw,hh,vw,vh; \
+ int thex,they,thew,theh; \
+ int numsubs = 0; \
+ int newLen; \
+ int nSubrectsUblen; \
+ \
+ nSubrectsUblen = cl->ublen; \
+ cl->ublen++; \
+ \
+ for (y=0; y<h; y++) { \
+ line = data+(y*w); \
+ for (x=0; x<w; x++) { \
+ if (line[x] != bg) { \
+ cl2 = line[x]; \
+ hy = y-1; \
+ hyflag = 1; \
+ for (j=y; j<h; j++) { \
+ seg = data+(j*w); \
+ if (seg[x] != cl2) {break;} \
+ i = x; \
+ while ((seg[i] == cl2) && (i < w)) i += 1; \
+ i -= 1; \
+ if (j == y) vx = hx = i; \
+ if (i < vx) vx = i; \
+ if ((hyflag > 0) && (i >= hx)) { \
+ hy += 1; \
+ } else { \
+ hyflag = 0; \
+ } \
+ } \
+ vy = j-1; \
+ \
+ /* We now have two possible subrects: (x,y,hx,hy) and \
+ * (x,y,vx,vy). We'll choose the bigger of the two. \
+ */ \
+ hw = hx-x+1; \
+ hh = hy-y+1; \
+ vw = vx-x+1; \
+ vh = vy-y+1; \
+ \
+ thex = x; \
+ they = y; \
+ \
+ if ((hw*hh) > (vw*vh)) { \
+ thew = hw; \
+ theh = hh; \
+ } else { \
+ thew = vw; \
+ theh = vh; \
+ } \
+ \
+ if (mono) { \
+ newLen = cl->ublen - nSubrectsUblen + 2; \
+ } else { \
+ newLen = cl->ublen - nSubrectsUblen + bpp/8 + 2; \
+ } \
+ \
+ if (newLen > (w * h * (bpp/8))) \
+ return FALSE; \
+ \
+ numsubs += 1; \
+ \
+ if (!mono) PUT_PIXEL##bpp(cl2); \
+ \
+ cl->updateBuf[cl->ublen++] = rfbHextilePackXY(thex,they); \
+ cl->updateBuf[cl->ublen++] = rfbHextilePackWH(thew,theh); \
+ \
+ /* \
+ * Now mark the subrect as done. \
+ */ \
+ for (j=they; j < (they+theh); j++) { \
+ for (i=thex; i < (thex+thew); i++) { \
+ data[j*w+i] = bg; \
+ } \
+ } \
+ } \
+ } \
+ } \
+ \
+ cl->updateBuf[nSubrectsUblen] = numsubs; \
+ \
+ return TRUE; \
+} \
+ \
+ \
+/* \
+ * testColours() tests if there are one (solid), two (mono) or more \
+ * colours in a tile and gets a reasonable guess at the best background \
+ * pixel, and the foreground pixel for mono. \
+ */ \
+ \
+static void \
+testColours##bpp(data,size,mono,solid,bg,fg) \
+ uint##bpp##_t *data; \
+ int size; \
+ rfbBool *mono; \
+ rfbBool *solid; \
+ uint##bpp##_t *bg; \
+ uint##bpp##_t *fg; \
+{ \
+ uint##bpp##_t colour1 = 0, colour2 = 0; \
+ int n1 = 0, n2 = 0; \
+ *mono = TRUE; \
+ *solid = TRUE; \
+ \
+ for (; size > 0; size--, data++) { \
+ \
+ if (n1 == 0) \
+ colour1 = *data; \
+ \
+ if (*data == colour1) { \
+ n1++; \
+ continue; \
+ } \
+ \
+ if (n2 == 0) { \
+ *solid = FALSE; \
+ colour2 = *data; \
+ } \
+ \
+ if (*data == colour2) { \
+ n2++; \
+ continue; \
+ } \
+ \
+ *mono = FALSE; \
+ break; \
+ } \
+ \
+ if (n1 > n2) { \
+ *bg = colour1; \
+ *fg = colour2; \
+ } else { \
+ *bg = colour2; \
+ *fg = colour1; \
+ } \
+}
+
+DEFINE_SEND_HEXTILES(8)
+DEFINE_SEND_HEXTILES(16)
+DEFINE_SEND_HEXTILES(32)
diff --git a/libvncserver/httpd.c b/libvncserver/httpd.c
new file mode 100755
index 0000000..85c8e44
--- /dev/null
+++ b/libvncserver/httpd.c
@@ -0,0 +1,579 @@
+/*
+ * httpd.c - a simple HTTP server
+ */
+
+/*
+ * Copyright (C) 2002 RealVNC Ltd.
+ * Copyright (C) 1999 AT&T Laboratories Cambridge. 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/rfb.h>
+
+#include <ctype.h>
+#ifdef LIBVNCSERVER_HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef LIBVNCSERVER_HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef LIBVNCSERVER_HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#include <errno.h>
+
+#ifdef WIN32
+#include <winsock.h>
+#define close closesocket
+#else
+#ifdef LIBVNCSERVER_HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef LIBVNCSERVER_HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef LIBVNCSERVER_HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#endif
+#include <pwd.h>
+#endif
+
+#ifdef USE_LIBWRAP
+#include <tcpd.h>
+#endif
+
+#define NOT_FOUND_STR "HTTP/1.0 404 Not found\r\n\r\n" \
+ "<HEAD><TITLE>File Not Found</TITLE></HEAD>\n" \
+ "<BODY><H1>File Not Found</H1></BODY>\n"
+
+#define INVALID_REQUEST_STR "HTTP/1.0 400 Invalid Request\r\n\r\n" \
+ "<HEAD><TITLE>Invalid Request</TITLE></HEAD>\n" \
+ "<BODY><H1>Invalid request</H1></BODY>\n"
+
+#define OK_STR "HTTP/1.0 200 OK\nContent-Type: text/html\r\n\r\n"
+
+static void httpProcessInput();
+static rfbBool compareAndSkip(char **ptr, const char *str);
+static rfbBool parseParams(const char *request, char *result, int max_bytes);
+static rfbBool validateString(char *str);
+
+#define BUF_SIZE 32768
+
+static char buf[BUF_SIZE];
+static size_t buf_filled=0;
+
+/*
+ * httpInitSockets sets up the TCP socket to listen for HTTP connections.
+ */
+
+void
+httpInitSockets(rfbScreenInfoPtr rfbScreen)
+{
+ if (rfbScreen->httpInitDone)
+ return;
+
+ rfbScreen->httpInitDone = TRUE;
+
+ if (!rfbScreen->httpDir)
+ return;
+
+ if (rfbScreen->httpPort == 0) {
+ rfbScreen->httpPort = rfbScreen->rfbPort-100;
+ }
+
+ rfbLog("Listening for HTTP connections on TCP port %d\n", rfbScreen->httpPort);
+
+ rfbLog(" URL http://%s:%d\n",rfbScreen->rfbThisHost,rfbScreen->httpPort);
+
+ if ((rfbScreen->httpListenSock = ListenOnTCPPort(rfbScreen->httpPort)) < 0) {
+ rfbLogPerror("ListenOnTCPPort");
+ return;
+ }
+
+ /*AddEnabledDevice(httpListenSock);*/
+}
+
+
+/*
+ * httpCheckFds is called from ProcessInputEvents to check for input on the
+ * HTTP socket(s). If there is input to process, httpProcessInput is called.
+ */
+
+void
+httpCheckFds(rfbScreenInfoPtr rfbScreen)
+{
+ int nfds;
+ fd_set fds;
+ struct timeval tv;
+ struct sockaddr_in addr;
+ size_t addrlen = sizeof(addr);
+
+ if (!rfbScreen->httpDir)
+ return;
+
+ FD_ZERO(&fds);
+ FD_SET(rfbScreen->httpListenSock, &fds);
+ if (rfbScreen->httpSock >= 0) {
+ FD_SET(rfbScreen->httpSock, &fds);
+ }
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ nfds = select(max(rfbScreen->httpSock,rfbScreen->httpListenSock) + 1, &fds, NULL, NULL, &tv);
+ if (nfds == 0) {
+ return;
+ }
+ if (nfds < 0) {
+#ifdef WIN32
+ errno = WSAGetLastError();
+#endif
+ if (errno != EINTR)
+ rfbLogPerror("httpCheckFds: select");
+ return;
+ }
+
+ if ((rfbScreen->httpSock >= 0) && FD_ISSET(rfbScreen->httpSock, &fds)) {
+ httpProcessInput(rfbScreen);
+ }
+
+ if (FD_ISSET(rfbScreen->httpListenSock, &fds)) {
+ int flags;
+ if (rfbScreen->httpSock >= 0) close(rfbScreen->httpSock);
+
+ if ((rfbScreen->httpSock = accept(rfbScreen->httpListenSock,
+ (struct sockaddr *)&addr, &addrlen)) < 0) {
+ rfbLogPerror("httpCheckFds: accept");
+ return;
+ }
+#ifdef USE_LIBWRAP
+ if(!hosts_ctl("vnc",STRING_UNKNOWN,inet_ntoa(addr.sin_addr),
+ STRING_UNKNOWN)) {
+ rfbLog("Rejected HTTP connection from client %s\n",
+ inet_ntoa(addr.sin_addr));
+#else
+ flags = fcntl(rfbScreen->httpSock, F_GETFL);
+
+ if (flags < 0 || fcntl(rfbScreen->httpSock, F_SETFL, flags | O_NONBLOCK) == -1) {
+ rfbLogPerror("httpCheckFds: fcntl");
+#endif
+ close(rfbScreen->httpSock);
+ rfbScreen->httpSock = -1;
+ return;
+ }
+ flags=fcntl(rfbScreen->httpSock,F_GETFL);
+ if(flags==-1 ||
+ fcntl(rfbScreen->httpSock,F_SETFL,flags|O_NONBLOCK)==-1) {
+ rfbLogPerror("httpCheckFds: fcntl");
+ close(rfbScreen->httpSock);
+ rfbScreen->httpSock=-1;
+ return;
+ }
+
+ /*AddEnabledDevice(httpSock);*/
+ }
+}
+
+
+static void
+httpCloseSock(rfbScreenInfoPtr rfbScreen)
+{
+ close(rfbScreen->httpSock);
+ rfbScreen->httpSock = -1;
+ buf_filled = 0;
+}
+
+static rfbClientRec cl;
+
+/*
+ * httpProcessInput is called when input is received on the HTTP socket.
+ */
+
+static void
+httpProcessInput(rfbScreenInfoPtr rfbScreen)
+{
+ struct sockaddr_in addr;
+ size_t addrlen = sizeof(addr);
+ char fullFname[512];
+ char params[1024];
+ char *ptr;
+ char *fname;
+ unsigned int maxFnameLen;
+ FILE* fd;
+ rfbBool performSubstitutions = FALSE;
+ char str[256+32];
+#ifndef WIN32
+ char* user=getenv("USER");
+#endif
+
+ cl.sock=rfbScreen->httpSock;
+
+ if (strlen(rfbScreen->httpDir) > 255) {
+ rfbErr("-httpd directory too long\n");
+ httpCloseSock(rfbScreen);
+ return;
+ }
+ strcpy(fullFname, rfbScreen->httpDir);
+ fname = &fullFname[strlen(fullFname)];
+ maxFnameLen = 511 - strlen(fullFname);
+
+ buf_filled=0;
+
+ /* Read data from the HTTP client until we get a complete request. */
+ while (1) {
+ ssize_t got;
+
+ if (buf_filled > sizeof (buf)) {
+ rfbErr("httpProcessInput: HTTP request is too long\n");
+ httpCloseSock(rfbScreen);
+ return;
+ }
+
+ got = read (rfbScreen->httpSock, buf + buf_filled,
+ sizeof (buf) - buf_filled - 1);
+
+ if (got <= 0) {
+ if (got == 0) {
+ rfbErr("httpd: premature connection close\n");
+ } else {
+ if (errno == EAGAIN) {
+ return;
+ }
+ rfbLogPerror("httpProcessInput: read");
+ }
+ httpCloseSock(rfbScreen);
+ return;
+ }
+
+ buf_filled += got;
+ buf[buf_filled] = '\0';
+
+ /* Is it complete yet (is there a blank line)? */
+ if (strstr (buf, "\r\r") || strstr (buf, "\n\n") ||
+ strstr (buf, "\r\n\r\n") || strstr (buf, "\n\r\n\r"))
+ break;
+ }
+
+
+ /* Process the request. */
+ if(rfbScreen->httpEnableProxyConnect) {
+ const static char* PROXY_OK_STR = "HTTP/1.0 200 OK\r\nContent-Type: octet-stream\r\nPragma: no-cache\r\n\r\n";
+ if(!strncmp(buf, "CONNECT ", 8)) {
+ if(atoi(strchr(buf, ':')+1)!=rfbScreen->rfbPort) {
+ rfbErr("httpd: CONNECT format invalid.\n");
+ WriteExact(&cl,INVALID_REQUEST_STR, strlen(INVALID_REQUEST_STR));
+ httpCloseSock(rfbScreen);
+ return;
+ }
+ /* proxy connection */
+ rfbLog("httpd: client asked for CONNECT\n");
+ WriteExact(&cl,PROXY_OK_STR,strlen(PROXY_OK_STR));
+ rfbNewClientConnection(rfbScreen,rfbScreen->httpSock);
+ rfbScreen->httpSock = -1;
+ return;
+ }
+ if (!strncmp(buf, "GET ",4) && !strncmp(strchr(buf,'/'),"/proxied.connection HTTP/1.", 27)) {
+ /* proxy connection */
+ rfbLog("httpd: client asked for /proxied.connection\n");
+ WriteExact(&cl,PROXY_OK_STR,strlen(PROXY_OK_STR));
+ rfbNewClientConnection(rfbScreen,rfbScreen->httpSock);
+ rfbScreen->httpSock = -1;
+ return;
+ }
+ }
+
+ if (strncmp(buf, "GET ", 4)) {
+ rfbErr("httpd: no GET line\n");
+ httpCloseSock(rfbScreen);
+ return;
+ } else {
+ /* Only use the first line. */
+ buf[strcspn(buf, "\n\r")] = '\0';
+ }
+
+ if (strlen(buf) > maxFnameLen) {
+ rfbErr("httpd: GET line too long\n");
+ httpCloseSock(rfbScreen);
+ return;
+ }
+
+ if (sscanf(buf, "GET %s HTTP/1.0", fname) != 1) {
+ rfbErr("httpd: couldn't parse GET line\n");
+ httpCloseSock(rfbScreen);
+ return;
+ }
+
+ if (fname[0] != '/') {
+ rfbErr("httpd: filename didn't begin with '/'\n");
+ WriteExact(&cl, NOT_FOUND_STR, strlen(NOT_FOUND_STR));
+ httpCloseSock(rfbScreen);
+ return;
+ }
+
+ if (strchr(fname+1, '/') != NULL) {
+ rfbErr("httpd: asking for file in other directory\n");
+ WriteExact(&cl, NOT_FOUND_STR, strlen(NOT_FOUND_STR));
+ httpCloseSock(rfbScreen);
+ return;
+ }
+
+ getpeername(rfbScreen->httpSock, (struct sockaddr *)&addr, &addrlen);
+ rfbLog("httpd: get '%s' for %s\n", fname+1,
+ inet_ntoa(addr.sin_addr));
+
+ /* Extract parameters from the URL string if necessary */
+
+ params[0] = '\0';
+ ptr = strchr(fname, '?');
+ if (ptr != NULL) {
+ *ptr = '\0';
+ if (!parseParams(&ptr[1], params, 1024)) {
+ params[0] = '\0';
+ rfbErr("httpd: bad parameters in the URL\n");
+ }
+ }
+
+
+ /* If we were asked for '/', actually read the file index.vnc */
+
+ if (strcmp(fname, "/") == 0) {
+ strcpy(fname, "/index.vnc");
+ rfbLog("httpd: defaulting to '%s'\n", fname+1);
+ }
+
+ /* Substitutions are performed on files ending .vnc */
+
+ if (strlen(fname) >= 4 && strcmp(&fname[strlen(fname)-4], ".vnc") == 0) {
+ performSubstitutions = TRUE;
+ }
+
+ /* Open the file */
+
+ if ((fd = fopen(fullFname, "r")) == 0) {
+ rfbLogPerror("httpProcessInput: open");
+ WriteExact(&cl, NOT_FOUND_STR, strlen(NOT_FOUND_STR));
+ httpCloseSock(rfbScreen);
+ return;
+ }
+
+ WriteExact(&cl, OK_STR, strlen(OK_STR));
+
+ while (1) {
+ int n = fread(buf, 1, BUF_SIZE-1, fd);
+ if (n < 0) {
+ rfbLogPerror("httpProcessInput: read");
+ fclose(fd);
+ httpCloseSock(rfbScreen);
+ return;
+ }
+
+ if (n == 0)
+ break;
+
+ if (performSubstitutions) {
+
+ /* Substitute $WIDTH, $HEIGHT, etc with the appropriate values.
+ This won't quite work properly if the .vnc file is longer than
+ BUF_SIZE, but it's reasonable to assume that .vnc files will
+ always be short. */
+
+ char *ptr = buf;
+ char *dollar;
+ buf[n] = 0; /* make sure it's null-terminated */
+
+ while ((dollar = strchr(ptr, '$'))!=NULL) {
+ WriteExact(&cl, ptr, (dollar - ptr));
+
+ ptr = dollar;
+
+ if (compareAndSkip(&ptr, "$WIDTH")) {
+
+ sprintf(str, "%d", rfbScreen->width);
+ WriteExact(&cl, str, strlen(str));
+
+ } else if (compareAndSkip(&ptr, "$HEIGHT")) {
+
+ sprintf(str, "%d", rfbScreen->height);
+ WriteExact(&cl, str, strlen(str));
+
+ } else if (compareAndSkip(&ptr, "$APPLETWIDTH")) {
+
+ sprintf(str, "%d", rfbScreen->width);
+ WriteExact(&cl, str, strlen(str));
+
+ } else if (compareAndSkip(&ptr, "$APPLETHEIGHT")) {
+
+ sprintf(str, "%d", rfbScreen->height + 32);
+ WriteExact(&cl, str, strlen(str));
+
+ } else if (compareAndSkip(&ptr, "$PORT")) {
+
+ sprintf(str, "%d", rfbScreen->rfbPort);
+ WriteExact(&cl, str, strlen(str));
+
+ } else if (compareAndSkip(&ptr, "$DESKTOP")) {
+
+ WriteExact(&cl, rfbScreen->desktopName, strlen(rfbScreen->desktopName));
+
+ } else if (compareAndSkip(&ptr, "$DISPLAY")) {
+
+ sprintf(str, "%s:%d", rfbScreen->rfbThisHost, rfbScreen->rfbPort-5900);
+ WriteExact(&cl, str, strlen(str));
+
+ } else if (compareAndSkip(&ptr, "$USER")) {
+#ifndef WIN32
+ if (user) {
+ WriteExact(&cl, user,
+ strlen(user));
+ } else
+#endif
+ WriteExact(&cl, "?", 1);
+ } else if (compareAndSkip(&ptr, "$PARAMS")) {
+ if (params[0] != '\0')
+ WriteExact(&cl, params, strlen(params));
+ } else {
+ if (!compareAndSkip(&ptr, "$$"))
+ ptr++;
+
+ if (WriteExact(&cl, "$", 1) < 0) {
+ fclose(fd);
+ httpCloseSock(rfbScreen);
+ return;
+ }
+ }
+ }
+ if (WriteExact(&cl, ptr, (&buf[n] - ptr)) < 0)
+ break;
+
+ } else {
+
+ /* For files not ending .vnc, just write out the buffer */
+
+ if (WriteExact(&cl, buf, n) < 0)
+ break;
+ }
+ }
+
+ fclose(fd);
+ httpCloseSock(rfbScreen);
+}
+
+
+static rfbBool
+compareAndSkip(char **ptr, const char *str)
+{
+ if (strncmp(*ptr, str, strlen(str)) == 0) {
+ *ptr += strlen(str);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/*
+ * Parse the request tail after the '?' character, and format a sequence
+ * of <param> tags for inclusion into an HTML page with embedded applet.
+ */
+
+static rfbBool
+parseParams(const char *request, char *result, int max_bytes)
+{
+ char param_request[128];
+ char param_formatted[196];
+ const char *tail;
+ char *delim_ptr;
+ char *value_str;
+ int cur_bytes, len;
+
+ result[0] = '\0';
+ cur_bytes = 0;
+
+ tail = request;
+ for (;;) {
+ /* Copy individual "name=value" string into a buffer */
+ delim_ptr = strchr((char *)tail, '&');
+ if (delim_ptr == NULL) {
+ if (strlen(tail) >= sizeof(param_request)) {
+ return FALSE;
+ }
+ strcpy(param_request, tail);
+ } else {
+ len = delim_ptr - tail;
+ if (len >= sizeof(param_request)) {
+ return FALSE;
+ }
+ memcpy(param_request, tail, len);
+ param_request[len] = '\0';
+ }
+
+ /* Split the request into parameter name and value */
+ value_str = strchr(&param_request[1], '=');
+ if (value_str == NULL) {
+ return FALSE;
+ }
+ *value_str++ = '\0';
+ if (strlen(value_str) == 0) {
+ return FALSE;
+ }
+
+ /* Validate both parameter name and value */
+ if (!validateString(param_request) || !validateString(value_str)) {
+ return FALSE;
+ }
+
+ /* Prepare HTML-formatted representation of the name=value pair */
+ len = sprintf(param_formatted,
+ "<PARAM NAME=\"%s\" VALUE=\"%s\">\n",
+ param_request, value_str);
+ if (cur_bytes + len + 1 > max_bytes) {
+ return FALSE;
+ }
+ strcat(result, param_formatted);
+ cur_bytes += len;
+
+ /* Go to the next parameter */
+ if (delim_ptr == NULL) {
+ break;
+ }
+ tail = delim_ptr + 1;
+ }
+ return TRUE;
+}
+
+/*
+ * Check if the string consists only of alphanumeric characters, '+'
+ * signs, underscores, and dots. Replace all '+' signs with spaces.
+ */
+
+static rfbBool
+validateString(char *str)
+{
+ char *ptr;
+
+ for (ptr = str; *ptr != '\0'; ptr++) {
+ if (!isalnum(*ptr) && *ptr != '_' && *ptr != '.') {
+ if (*ptr == '+') {
+ *ptr = ' ';
+ } else {
+ return FALSE;
+ }
+ }
+ }
+ return TRUE;
+}
+
diff --git a/libvncserver/main.c b/libvncserver/main.c
new file mode 100644
index 0000000..488f09d
--- /dev/null
+++ b/libvncserver/main.c
@@ -0,0 +1,851 @@
+/*
+ * This file is called main.c, because it contains most of the new functions
+ * for use with LibVNCServer.
+ *
+ * LibVNCServer (C) 2001 Johannes E. Schindelin <Johannes.Schindelin@gmx.de>
+ * Original OSXvnc (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
+ * Original Xvnc (C) 1999 AT&T Laboratories Cambridge.
+ * All Rights Reserved.
+ *
+ * see GPL (latest version) for full details
+ */
+
+#include <rfb/rfb.h>
+#include <rfb/rfbregion.h>
+
+#include <stdarg.h>
+#include <errno.h>
+
+#ifndef false
+#define false 0
+#define true -1
+#endif
+
+#ifdef LIBVNCSERVER_HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifndef WIN32
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <unistd.h>
+#endif
+
+#include <signal.h>
+#include <time.h>
+
+#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
+MUTEX(logMutex);
+#endif
+
+int rfbEnableLogging=1;
+
+#ifdef LIBVNCSERVER_WORDS_BIGENDIAN
+char rfbEndianTest = 0;
+#else
+char rfbEndianTest = -1;
+#endif
+
+/* from rfbserver.c */
+void rfbIncrClientRef(rfbClientPtr cl);
+void rfbDecrClientRef(rfbClientPtr cl);
+
+void rfbLogEnable(int enabled) {
+ rfbEnableLogging=enabled;
+}
+
+/*
+ * rfbLog prints a time-stamped message to the log file (stderr).
+ */
+
+void
+rfbDefaultLog(const char *format, ...)
+{
+ va_list args;
+ char buf[256];
+ time_t log_clock;
+
+ if(!rfbEnableLogging)
+ return;
+
+ LOCK(logMutex);
+ va_start(args, format);
+
+ time(&log_clock);
+ strftime(buf, 255, "%d/%m/%Y %X ", localtime(&log_clock));
+ fprintf(stderr,buf);
+
+ vfprintf(stderr, format, args);
+ fflush(stderr);
+
+ va_end(args);
+ UNLOCK(logMutex);
+}
+
+rfbLogProc rfbLog=rfbDefaultLog;
+rfbLogProc rfbErr=rfbDefaultLog;
+
+void rfbLogPerror(const char *str)
+{
+ rfbErr("%s: %s\n", str, strerror(errno));
+}
+
+void rfbScheduleCopyRegion(rfbScreenInfoPtr rfbScreen,sraRegionPtr copyRegion,int dx,int dy)
+{
+ rfbClientIteratorPtr iterator;
+ rfbClientPtr cl;
+
+ rfbUndrawCursor(rfbScreen);
+
+ iterator=rfbGetClientIterator(rfbScreen);
+ while((cl=rfbClientIteratorNext(iterator))) {
+ LOCK(cl->updateMutex);
+ if(cl->useCopyRect) {
+ sraRegionPtr modifiedRegionBackup;
+ if(!sraRgnEmpty(cl->copyRegion)) {
+ if(cl->copyDX!=dx || cl->copyDY!=dy) {
+ /* if a copyRegion was not yet executed, treat it as a
+ * modifiedRegion. The idea: in this case it could be
+ * source of the new copyRect or modified anyway. */
+ sraRgnOr(cl->modifiedRegion,cl->copyRegion);
+ sraRgnMakeEmpty(cl->copyRegion);
+ } else {
+ /* we have to set the intersection of the source of the copy
+ * and the old copy to modified. */
+ modifiedRegionBackup=sraRgnCreateRgn(copyRegion);
+ sraRgnOffset(modifiedRegionBackup,-dx,-dy);
+ sraRgnAnd(modifiedRegionBackup,cl->copyRegion);
+ sraRgnOr(cl->modifiedRegion,modifiedRegionBackup);
+ sraRgnDestroy(modifiedRegionBackup);
+ }
+ }
+
+ sraRgnOr(cl->copyRegion,copyRegion);
+ cl->copyDX = dx;
+ cl->copyDY = dy;
+
+ /* if there were modified regions, which are now copied,
+ * mark them as modified, because the source of these can be overlapped
+ * either by new modified or now copied regions. */
+ modifiedRegionBackup=sraRgnCreateRgn(cl->modifiedRegion);
+ sraRgnOffset(modifiedRegionBackup,dx,dy);
+ sraRgnAnd(modifiedRegionBackup,cl->copyRegion);
+ sraRgnOr(cl->modifiedRegion,modifiedRegionBackup);
+ sraRgnDestroy(modifiedRegionBackup);
+
+#if 0
+ /* TODO: is this needed? Or does it mess up deferring? */
+ /* while(!sraRgnEmpty(cl->copyRegion)) */ {
+#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
+ if(!cl->screen->backgroundLoop)
+#endif
+ {
+ sraRegionPtr updateRegion = sraRgnCreateRgn(cl->modifiedRegion);
+ sraRgnOr(updateRegion,cl->copyRegion);
+ UNLOCK(cl->updateMutex);
+ rfbSendFramebufferUpdate(cl,updateRegion);
+ sraRgnDestroy(updateRegion);
+ continue;
+ }
+ }
+#endif
+ } else {
+ sraRgnOr(cl->modifiedRegion,copyRegion);
+ }
+ TSIGNAL(cl->updateCond);
+ UNLOCK(cl->updateMutex);
+ }
+
+ rfbReleaseClientIterator(iterator);
+}
+
+void rfbDoCopyRegion(rfbScreenInfoPtr rfbScreen,sraRegionPtr copyRegion,int dx,int dy)
+{
+ sraRectangleIterator* i;
+ sraRect rect;
+ int j,widthInBytes,bpp=rfbScreen->rfbServerFormat.bitsPerPixel/8,
+ rowstride=rfbScreen->paddedWidthInBytes;
+ char *in,*out;
+
+ rfbUndrawCursor(rfbScreen);
+
+ /* copy it, really */
+ i = sraRgnGetReverseIterator(copyRegion,dx<0,dy<0);
+ while(sraRgnIteratorNext(i,&rect)) {
+ widthInBytes = (rect.x2-rect.x1)*bpp;
+ out = rfbScreen->frameBuffer+rect.x1*bpp+rect.y1*rowstride;
+ in = rfbScreen->frameBuffer+(rect.x1-dx)*bpp+(rect.y1-dy)*rowstride;
+ if(dy<0)
+ for(j=rect.y1;j<rect.y2;j++,out+=rowstride,in+=rowstride)
+ memmove(out,in,widthInBytes);
+ else {
+ out += rowstride*(rect.y2-rect.y1-1);
+ in += rowstride*(rect.y2-rect.y1-1);
+ for(j=rect.y2-1;j>=rect.y1;j--,out-=rowstride,in-=rowstride)
+ memmove(out,in,widthInBytes);
+ }
+ }
+
+ rfbScheduleCopyRegion(rfbScreen,copyRegion,dx,dy);
+}
+
+void rfbDoCopyRect(rfbScreenInfoPtr rfbScreen,int x1,int y1,int x2,int y2,int dx,int dy)
+{
+ sraRegionPtr region = sraRgnCreateRect(x1,y1,x2,y2);
+ rfbDoCopyRegion(rfbScreen,region,dx,dy);
+}
+
+void rfbScheduleCopyRect(rfbScreenInfoPtr rfbScreen,int x1,int y1,int x2,int y2,int dx,int dy)
+{
+ sraRegionPtr region = sraRgnCreateRect(x1,y1,x2,y2);
+ rfbScheduleCopyRegion(rfbScreen,region,dx,dy);
+}
+
+void rfbMarkRegionAsModified(rfbScreenInfoPtr rfbScreen,sraRegionPtr modRegion)
+{
+ rfbClientIteratorPtr iterator;
+ rfbClientPtr cl;
+
+ iterator=rfbGetClientIterator(rfbScreen);
+ while((cl=rfbClientIteratorNext(iterator))) {
+ LOCK(cl->updateMutex);
+ sraRgnOr(cl->modifiedRegion,modRegion);
+ TSIGNAL(cl->updateCond);
+ UNLOCK(cl->updateMutex);
+ }
+
+ rfbReleaseClientIterator(iterator);
+}
+
+void rfbMarkRectAsModified(rfbScreenInfoPtr rfbScreen,int x1,int y1,int x2,int y2)
+{
+ sraRegionPtr region;
+ int i;
+
+ if(x1>x2) { i=x1; x1=x2; x2=i; }
+ if(x1<0) x1=0;
+ if(x2>=rfbScreen->width) x2=rfbScreen->width-1;
+ if(x1==x2) return;
+
+ if(y1>y2) { i=y1; y1=y2; y2=i; }
+ if(y1<0) y1=0;
+ if(y2>=rfbScreen->height) y2=rfbScreen->height-1;
+ if(y1==y2) return;
+
+ region = sraRgnCreateRect(x1,y1,x2,y2);
+ rfbMarkRegionAsModified(rfbScreen,region);
+ sraRgnDestroy(region);
+}
+
+#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
+static void *
+clientOutput(void *data)
+{
+ rfbClientPtr cl = (rfbClientPtr)data;
+ rfbBool haveUpdate;
+ sraRegion* updateRegion;
+
+ while (1) {
+ haveUpdate = false;
+ while (!haveUpdate) {
+ if (cl->sock == -1) {
+ /* Client has disconnected. */
+ return NULL;
+ }
+ LOCK(cl->updateMutex);
+ haveUpdate = FB_UPDATE_PENDING(cl);
+ if(!haveUpdate) {
+ updateRegion = sraRgnCreateRgn(cl->modifiedRegion);
+ haveUpdate = sraRgnAnd(updateRegion,cl->requestedRegion);
+ sraRgnDestroy(updateRegion);
+ }
+ UNLOCK(cl->updateMutex);
+
+ if (!haveUpdate) {
+ WAIT(cl->updateCond, cl->updateMutex);
+ UNLOCK(cl->updateMutex); /* we really needn't lock now. */
+ }
+ }
+
+ /* OK, now, to save bandwidth, wait a little while for more
+ updates to come along. */
+ usleep(cl->screen->rfbDeferUpdateTime * 1000);
+
+ /* Now, get the region we're going to update, and remove
+ it from cl->modifiedRegion _before_ we send the update.
+ That way, if anything that overlaps the region we're sending
+ is updated, we'll be sure to do another update later. */
+ LOCK(cl->updateMutex);
+ updateRegion = sraRgnCreateRgn(cl->modifiedRegion);
+ UNLOCK(cl->updateMutex);
+
+ /* Now actually send the update. */
+ rfbIncrClientRef(cl);
+ rfbSendFramebufferUpdate(cl, updateRegion);
+ rfbDecrClientRef(cl);
+
+ sraRgnDestroy(updateRegion);
+ }
+
+ return NULL;
+}
+
+static void *
+clientInput(void *data)
+{
+ rfbClientPtr cl = (rfbClientPtr)data;
+ pthread_t output_thread;
+ pthread_create(&output_thread, NULL, clientOutput, (void *)cl);
+
+ while (1) {
+ rfbProcessClientMessage(cl);
+ if (cl->sock == -1) {
+ /* Client has disconnected. */
+ break;
+ }
+ }
+
+ /* Get rid of the output thread. */
+ LOCK(cl->updateMutex);
+ TSIGNAL(cl->updateCond);
+ UNLOCK(cl->updateMutex);
+ IF_PTHREADS(pthread_join(output_thread, NULL));
+
+ rfbClientConnectionGone(cl);
+
+ return NULL;
+}
+
+static void*
+listenerRun(void *data)
+{
+ rfbScreenInfoPtr rfbScreen=(rfbScreenInfoPtr)data;
+ int client_fd;
+ struct sockaddr_in peer;
+ rfbClientPtr cl;
+ size_t len;
+
+ len = sizeof(peer);
+
+ /* TODO: this thread wont die by restarting the server */
+ while ((client_fd = accept(rfbScreen->rfbListenSock,
+ (struct sockaddr*)&peer, &len)) >= 0) {
+ cl = rfbNewClient(rfbScreen,client_fd);
+ len = sizeof(peer);
+
+ if (cl && !cl->onHold )
+ rfbStartOnHoldClient(cl);
+ }
+ return(NULL);
+}
+
+void
+rfbStartOnHoldClient(rfbClientPtr cl)
+{
+ pthread_create(&cl->client_thread, NULL, clientInput, (void *)cl);
+}
+
+#else
+
+void
+rfbStartOnHoldClient(rfbClientPtr cl)
+{
+ cl->onHold = FALSE;
+}
+
+#endif
+
+void
+rfbRefuseOnHoldClient(rfbClientPtr cl)
+{
+ rfbCloseClient(cl);
+ rfbClientConnectionGone(cl);
+}
+
+static void
+defaultKbdAddEvent(rfbBool down, rfbKeySym keySym, rfbClientPtr cl)
+{
+}
+
+void
+defaultPtrAddEvent(int buttonMask, int x, int y, rfbClientPtr cl)
+{
+ rfbClientIteratorPtr iterator;
+ rfbClientPtr other_client;
+
+ if (x != cl->screen->cursorX || y != cl->screen->cursorY) {
+ if (cl->screen->cursorIsDrawn)
+ rfbUndrawCursor(cl->screen);
+ LOCK(cl->screen->cursorMutex);
+ if (!cl->screen->cursorIsDrawn) {
+ cl->screen->cursorX = x;
+ cl->screen->cursorY = y;
+ }
+ UNLOCK(cl->screen->cursorMutex);
+
+ /* The cursor was moved by this client, so don't send CursorPos. */
+ if (cl->enableCursorPosUpdates)
+ cl->cursorWasMoved = FALSE;
+
+ /* But inform all remaining clients about this cursor movement. */
+ iterator = rfbGetClientIterator(cl->screen);
+ while ((other_client = rfbClientIteratorNext(iterator)) != NULL) {
+ if (other_client != cl && other_client->enableCursorPosUpdates) {
+ other_client->cursorWasMoved = TRUE;
+ }
+ }
+ rfbReleaseClientIterator(iterator);
+ }
+}
+
+void defaultSetXCutText(char* text, int len, rfbClientPtr cl)
+{
+}
+
+/* TODO: add a nice VNC or RFB cursor */
+
+#if defined(WIN32) || defined(sparc) || !defined(NO_STRICT_ANSI)
+static rfbCursor myCursor =
+{
+ FALSE, FALSE, FALSE, FALSE,
+ (unsigned char*)"\000\102\044\030\044\102\000",
+ (unsigned char*)"\347\347\176\074\176\347\347",
+ 8, 7, 3, 3,
+ 0, 0, 0,
+ 0xffff, 0xffff, 0xffff,
+ 0
+};
+#else
+static rfbCursor myCursor =
+{
+ cleanup: FALSE,
+ cleanupSource: FALSE,
+ cleanupMask: FALSE,
+ cleanupRichSource: FALSE,
+ source: "\000\102\044\030\044\102\000",
+ mask: "\347\347\176\074\176\347\347",
+ width: 8, height: 7, xhot: 3, yhot: 3,
+ foreRed: 0, foreGreen: 0, foreBlue: 0,
+ backRed: 0xffff, backGreen: 0xffff, backBlue: 0xffff,
+ richSource: 0
+};
+#endif
+
+rfbCursorPtr defaultGetCursorPtr(rfbClientPtr cl)
+{
+ return(cl->screen->cursor);
+}
+
+/* response is cl->authChallenge vncEncrypted with passwd */
+rfbBool defaultPasswordCheck(rfbClientPtr cl,const char* response,int len)
+{
+ int i;
+ char *passwd=vncDecryptPasswdFromFile(cl->screen->rfbAuthPasswdData);
+
+ if(!passwd) {
+ rfbErr("Couldn't read password file: %s\n",cl->screen->rfbAuthPasswdData);
+ return(FALSE);
+ }
+
+ vncEncryptBytes(cl->authChallenge, passwd);
+
+ /* Lose the password from memory */
+ for (i = strlen(passwd); i >= 0; i--) {
+ passwd[i] = '\0';
+ }
+
+ free(passwd);
+
+ if (memcmp(cl->authChallenge, response, len) != 0) {
+ rfbErr("rfbAuthProcessClientMessage: authentication failed from %s\n",
+ cl->host);
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+/* for this method, rfbAuthPasswdData is really a pointer to an array
+ of char*'s, where the last pointer is 0. */
+rfbBool rfbCheckPasswordByList(rfbClientPtr cl,const char* response,int len)
+{
+ char **passwds;
+ int i=0;
+
+ for(passwds=(char**)cl->screen->rfbAuthPasswdData;*passwds;passwds++,i++) {
+ vncEncryptBytes(cl->authChallenge, *passwds);
+
+ if (memcmp(cl->authChallenge, response, len) == 0) {
+ if(i>=cl->screen->rfbAuthPasswdFirstViewOnly)
+ cl->viewOnly=TRUE;
+ return(TRUE);
+ }
+ }
+
+ rfbErr("rfbAuthProcessClientMessage: authentication failed from %s\n",
+ cl->host);
+ return(FALSE);
+}
+
+void doNothingWithClient(rfbClientPtr cl)
+{
+}
+
+enum rfbNewClientAction defaultNewClientHook(rfbClientPtr cl)
+{
+ return RFB_CLIENT_ACCEPT;
+}
+
+/*
+ * Update server's pixel format in rfbScreenInfo structure. This
+ * function is called from rfbGetScreen() and rfbNewFramebuffer().
+ */
+
+static void rfbInitServerFormat(rfbScreenInfoPtr rfbScreen, int bitsPerSample)
+{
+ rfbPixelFormat* format=&rfbScreen->rfbServerFormat;
+
+ format->bitsPerPixel = rfbScreen->bitsPerPixel;
+ format->depth = rfbScreen->depth;
+ format->bigEndian = rfbEndianTest?FALSE:TRUE;
+ format->trueColour = TRUE;
+ rfbScreen->colourMap.count = 0;
+ rfbScreen->colourMap.is16 = 0;
+ rfbScreen->colourMap.data.bytes = NULL;
+
+ if (format->bitsPerPixel == 8) {
+ format->redMax = 7;
+ format->greenMax = 7;
+ format->blueMax = 3;
+ format->redShift = 0;
+ format->greenShift = 3;
+ format->blueShift = 6;
+ } else {
+ format->redMax = (1 << bitsPerSample) - 1;
+ format->greenMax = (1 << bitsPerSample) - 1;
+ format->blueMax = (1 << bitsPerSample) - 1;
+ if(rfbEndianTest) {
+ format->redShift = 0;
+ format->greenShift = bitsPerSample;
+ format->blueShift = bitsPerSample * 2;
+ } else {
+ if(format->bitsPerPixel==8*3) {
+ format->redShift = bitsPerSample*2;
+ format->greenShift = bitsPerSample*1;
+ format->blueShift = 0;
+ } else {
+ format->redShift = bitsPerSample*3;
+ format->greenShift = bitsPerSample*2;
+ format->blueShift = bitsPerSample;
+ }
+ }
+ }
+}
+
+rfbScreenInfoPtr rfbGetScreen(int* argc,char** argv,
+ int width,int height,int bitsPerSample,int samplesPerPixel,
+ int bytesPerPixel)
+{
+ rfbScreenInfoPtr rfbScreen=malloc(sizeof(rfbScreenInfo));
+
+ INIT_MUTEX(logMutex);
+
+ if(width&3)
+ rfbErr("WARNING: Width (%d) is not a multiple of 4. VncViewer has problems with that.\n",width);
+
+ rfbScreen->autoPort=FALSE;
+ rfbScreen->rfbClientHead=0;
+ rfbScreen->rfbPort=5900;
+ rfbScreen->socketInitDone=FALSE;
+
+ rfbScreen->inetdInitDone = FALSE;
+ rfbScreen->inetdSock=-1;
+
+ rfbScreen->udpSock=-1;
+ rfbScreen->udpSockConnected=FALSE;
+ rfbScreen->udpPort=0;
+ rfbScreen->udpClient=0;
+
+ rfbScreen->maxFd=0;
+ rfbScreen->rfbListenSock=-1;
+
+ rfbScreen->httpInitDone=FALSE;
+ rfbScreen->httpEnableProxyConnect=FALSE;
+ rfbScreen->httpPort=0;
+ rfbScreen->httpDir=NULL;
+ rfbScreen->httpListenSock=-1;
+ rfbScreen->httpSock=-1;
+
+ rfbScreen->desktopName = "LibVNCServer";
+ rfbScreen->rfbAlwaysShared = FALSE;
+ rfbScreen->rfbNeverShared = FALSE;
+ rfbScreen->rfbDontDisconnect = FALSE;
+ rfbScreen->rfbAuthPasswdData = 0;
+ rfbScreen->rfbAuthPasswdFirstViewOnly = 1;
+
+ rfbScreen->width = width;
+ rfbScreen->height = height;
+ rfbScreen->bitsPerPixel = rfbScreen->depth = 8*bytesPerPixel;
+
+ rfbScreen->passwordCheck = defaultPasswordCheck;
+
+ rfbScreen->ignoreSIGPIPE = TRUE;
+
+ /* disable progressive updating per default */
+ rfbScreen->progressiveSliceHeight = 0;
+
+ if(!rfbProcessArguments(rfbScreen,argc,argv)) {
+ free(rfbScreen);
+ return 0;
+ }
+
+#ifdef WIN32
+ {
+ DWORD dummy=255;
+ GetComputerName(rfbScreen->rfbThisHost,&dummy);
+ }
+#else
+ gethostname(rfbScreen->rfbThisHost, 255);
+#endif
+
+ rfbScreen->paddedWidthInBytes = width*bytesPerPixel;
+
+ /* format */
+
+ rfbInitServerFormat(rfbScreen, bitsPerSample);
+
+ /* cursor */
+
+ rfbScreen->cursorIsDrawn = FALSE;
+ rfbScreen->dontSendFramebufferUpdate = FALSE;
+ rfbScreen->cursorX=rfbScreen->cursorY=rfbScreen->underCursorBufferLen=0;
+ rfbScreen->underCursorBuffer=NULL;
+ rfbScreen->dontConvertRichCursorToXCursor = FALSE;
+ rfbScreen->cursor = &myCursor;
+ INIT_MUTEX(rfbScreen->cursorMutex);
+
+ IF_PTHREADS(rfbScreen->backgroundLoop = FALSE);
+
+ rfbScreen->rfbDeferUpdateTime=5;
+ rfbScreen->maxRectsPerUpdate=50;
+
+ /* proc's and hook's */
+
+ rfbScreen->kbdAddEvent = defaultKbdAddEvent;
+ rfbScreen->kbdReleaseAllKeys = doNothingWithClient;
+ rfbScreen->ptrAddEvent = defaultPtrAddEvent;
+ rfbScreen->setXCutText = defaultSetXCutText;
+ rfbScreen->getCursorPtr = defaultGetCursorPtr;
+ rfbScreen->setTranslateFunction = rfbSetTranslateFunction;
+ rfbScreen->newClientHook = defaultNewClientHook;
+ rfbScreen->displayHook = 0;
+
+ /* initialize client list and iterator mutex */
+ rfbClientListInit(rfbScreen);
+
+ return(rfbScreen);
+}
+
+/*
+ * Switch to another framebuffer (maybe of different size and color
+ * format). Clients supporting NewFBSize pseudo-encoding will change
+ * their local framebuffer dimensions if necessary.
+ * NOTE: Rich cursor data should be converted to new pixel format by
+ * the caller.
+ */
+
+void rfbNewFramebuffer(rfbScreenInfoPtr rfbScreen, char *framebuffer,
+ int width, int height,
+ int bitsPerSample, int samplesPerPixel,
+ int bytesPerPixel)
+{
+ rfbPixelFormat old_format;
+ rfbBool format_changed = FALSE;
+ rfbClientIteratorPtr iterator;
+ rfbClientPtr cl;
+
+ /* Remove the pointer */
+
+ rfbUndrawCursor(rfbScreen);
+
+ /* Update information in the rfbScreenInfo structure */
+
+ old_format = rfbScreen->rfbServerFormat;
+
+ if (width & 3)
+ rfbErr("WARNING: New width (%d) is not a multiple of 4.\n", width);
+
+ rfbScreen->width = width;
+ rfbScreen->height = height;
+ rfbScreen->bitsPerPixel = rfbScreen->depth = 8*bytesPerPixel;
+ rfbScreen->paddedWidthInBytes = width*bytesPerPixel;
+
+ rfbInitServerFormat(rfbScreen, bitsPerSample);
+
+ if (memcmp(&rfbScreen->rfbServerFormat, &old_format,
+ sizeof(rfbPixelFormat)) != 0) {
+ format_changed = TRUE;
+ }
+
+ rfbScreen->frameBuffer = framebuffer;
+
+ /* Adjust pointer position if necessary */
+
+ if (rfbScreen->cursorX >= width)
+ rfbScreen->cursorX = width - 1;
+ if (rfbScreen->cursorY >= height)
+ rfbScreen->cursorY = height - 1;
+
+ /* For each client: */
+ iterator = rfbGetClientIterator(rfbScreen);
+ while ((cl = rfbClientIteratorNext(iterator)) != NULL) {
+
+ /* Re-install color translation tables if necessary */
+
+ if (format_changed)
+ rfbScreen->setTranslateFunction(cl);
+
+ /* Mark the screen contents as changed, and schedule sending
+ NewFBSize message if supported by this client. */
+
+ LOCK(cl->updateMutex);
+ sraRgnDestroy(cl->modifiedRegion);
+ cl->modifiedRegion = sraRgnCreateRect(0, 0, width, height);
+ sraRgnMakeEmpty(cl->copyRegion);
+ cl->copyDX = 0;
+ cl->copyDY = 0;
+
+ if (cl->useNewFBSize)
+ cl->newFBSizePending = TRUE;
+
+ TSIGNAL(cl->updateCond);
+ UNLOCK(cl->updateMutex);
+ }
+ rfbReleaseClientIterator(iterator);
+}
+
+#ifdef LIBVNCSERVER_HAVE_LIBJPEG
+extern void TightCleanup();
+#endif
+
+void rfbScreenCleanup(rfbScreenInfoPtr rfbScreen)
+{
+ rfbClientIteratorPtr i=rfbGetClientIterator(rfbScreen);
+ rfbClientPtr cl,cl1=rfbClientIteratorNext(i);
+ while(cl1) {
+ cl=rfbClientIteratorNext(i);
+ rfbClientConnectionGone(cl1);
+ cl1=cl;
+ }
+ rfbReleaseClientIterator(i);
+
+ /* TODO: hang up on all clients and free all reserved memory */
+#define FREE_IF(x) if(rfbScreen->x) free(rfbScreen->x)
+ FREE_IF(colourMap.data.bytes);
+ FREE_IF(underCursorBuffer);
+ TINI_MUTEX(rfbScreen->cursorMutex);
+ if(rfbScreen->cursor)
+ rfbFreeCursor(rfbScreen->cursor);
+ free(rfbScreen);
+#ifdef LIBVNCSERVER_HAVE_LIBJPEG
+ TightCleanup();
+#endif
+}
+
+void rfbInitServer(rfbScreenInfoPtr rfbScreen)
+{
+#ifdef WIN32
+ WSADATA trash;
+ int i=WSAStartup(MAKEWORD(2,2),&trash);
+#endif
+ rfbInitSockets(rfbScreen);
+ httpInitSockets(rfbScreen);
+ if(rfbScreen->ignoreSIGPIPE)
+ signal(SIGPIPE,SIG_IGN);
+}
+
+#ifndef LIBVNCSERVER_HAVE_GETTIMEOFDAY
+#include <fcntl.h>
+#include <conio.h>
+#include <sys/timeb.h>
+
+void gettimeofday(struct timeval* tv,char* dummy)
+{
+ SYSTEMTIME t;
+ GetSystemTime(&t);
+ tv->tv_sec=t.wHour*3600+t.wMinute*60+t.wSecond;
+ tv->tv_usec=t.wMilliseconds*1000;
+}
+#endif
+
+/* defined in rfbserver.c, but kind of "private" */
+rfbClientPtr rfbClientIteratorHead(rfbClientIteratorPtr i);
+
+void
+rfbProcessEvents(rfbScreenInfoPtr rfbScreen,long usec)
+{
+ rfbClientIteratorPtr i;
+ rfbClientPtr cl,clPrev;
+ struct timeval tv;
+
+ if(usec<0)
+ usec=rfbScreen->rfbDeferUpdateTime*1000;
+
+ rfbCheckFds(rfbScreen,usec);
+ httpCheckFds(rfbScreen);
+#ifdef CORBA
+ corbaCheckFds(rfbScreen);
+#endif
+
+ i = rfbGetClientIterator(rfbScreen);
+ cl=rfbClientIteratorHead(i);
+ while(cl) {
+ if (cl->sock >= 0 && !cl->onHold && FB_UPDATE_PENDING(cl) &&
+ !sraRgnEmpty(cl->requestedRegion)) {
+ if(rfbScreen->rfbDeferUpdateTime == 0) {
+ rfbSendFramebufferUpdate(cl,cl->modifiedRegion);
+ } else if(cl->startDeferring.tv_usec == 0) {
+ gettimeofday(&cl->startDeferring,NULL);
+ if(cl->startDeferring.tv_usec == 0)
+ cl->startDeferring.tv_usec++;
+ } else {
+ gettimeofday(&tv,NULL);
+ if(tv.tv_sec < cl->startDeferring.tv_sec /* at midnight */
+ || ((tv.tv_sec-cl->startDeferring.tv_sec)*1000
+ +(tv.tv_usec-cl->startDeferring.tv_usec)/1000)
+ > rfbScreen->rfbDeferUpdateTime) {
+ cl->startDeferring.tv_usec = 0;
+ rfbSendFramebufferUpdate(cl,cl->modifiedRegion);
+ }
+ }
+ }
+ clPrev=cl;
+ cl=rfbClientIteratorNext(i);
+ if(clPrev->sock==-1)
+ rfbClientConnectionGone(clPrev);
+ }
+ rfbReleaseClientIterator(i);
+}
+
+void rfbRunEventLoop(rfbScreenInfoPtr rfbScreen, long usec, rfbBool runInBackground)
+{
+ if(runInBackground) {
+#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
+ pthread_t listener_thread;
+
+ rfbScreen->backgroundLoop = TRUE;
+
+ pthread_create(&listener_thread, NULL, listenerRun, rfbScreen);
+ return;
+#else
+ rfbErr("Can't run in background, because I don't have PThreads!\n");
+ return;
+#endif
+ }
+
+ if(usec<0)
+ usec=rfbScreen->rfbDeferUpdateTime*1000;
+
+ while(1)
+ rfbProcessEvents(rfbScreen,usec);
+}
diff --git a/libvncserver/rfbconfig.h b/libvncserver/rfbconfig.h
new file mode 100644
index 0000000..888fc9b
--- /dev/null
+++ b/libvncserver/rfbconfig.h
@@ -0,0 +1,243 @@
+/* rfbconfig.h. Generated by configure. */
+/* rfbconfig.h.in. Generated from configure.ac by autoheader. */
+
+/* Enable 24 bit per pixel in native framebuffer */
+#define ALLOW24BPP 1
+
+/* Enable BackChannel communication */
+#define BACKCHANNEL 1
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#define HAVE_ARPA_INET_H 1
+
+/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */
+/* #undef HAVE_DOPRNT */
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have the `fork' function. */
+#define HAVE_FORK 1
+
+/* Define to 1 if you have the `ftime' function. */
+#define HAVE_FTIME 1
+
+/* Define to 1 if you have the `gethostbyname' function. */
+#define HAVE_GETHOSTBYNAME 1
+
+/* Define to 1 if you have the `gethostname' function. */
+#define HAVE_GETHOSTNAME 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have the `inet_ntoa' function. */
+#define HAVE_INET_NTOA 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `cygipc' library (-lcygipc). */
+/* #undef HAVE_LIBCYGIPC */
+
+/* Define to 1 if you have the `jpeg' library (-ljpeg). */
+#define HAVE_LIBJPEG 1
+
+/* Define to 1 if you have the `nsl' library (-lnsl). */
+#define HAVE_LIBNSL 1
+
+/* Define to 1 if you have the `pthread' library (-lpthread). */
+#define HAVE_LIBPTHREAD 1
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+/* #undef HAVE_LIBSOCKET */
+
+/* XINERAMA extension build environment present */
+#define HAVE_LIBXINERAMA 1
+
+/* Define to 1 if you have the `z' library (-lz). */
+#define HAVE_LIBZ 1
+
+/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
+ to 0 otherwise. */
+#define HAVE_MALLOC 1
+
+/* Define to 1 if you have the `memmove' function. */
+#define HAVE_MEMMOVE 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `memset' function. */
+#define HAVE_MEMSET 1
+
+/* Define to 1 if you have the `mkfifo' function. */
+#define HAVE_MKFIFO 1
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#define HAVE_NETDB_H 1
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#define HAVE_NETINET_IN_H 1
+
+/* Define to 1 if you have the `select' function. */
+#define HAVE_SELECT 1
+
+/* Define to 1 if you have the `setsid' function. */
+#define HAVE_SETSID 1
+
+/* Define to 1 if you have the `socket' function. */
+#define HAVE_SOCKET 1
+
+/* Define to 1 if `stat' has the bug that it succeeds when given the
+ zero-length file name argument. */
+/* #undef HAVE_STAT_EMPTY_STRING_BUG */
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the `strchr' function. */
+#define HAVE_STRCHR 1
+
+/* Define to 1 if you have the `strcspn' function. */
+#define HAVE_STRCSPN 1
+
+/* Define to 1 if you have the `strdup' function. */
+#define HAVE_STRDUP 1
+
+/* Define to 1 if you have the `strerror' function. */
+#define HAVE_STRERROR 1
+
+/* Define to 1 if you have the `strftime' function. */
+#define HAVE_STRFTIME 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strstr' function. */
+#define HAVE_STRSTR 1
+
+/* Define to 1 if you have the <syslog.h> header file. */
+#define HAVE_SYSLOG_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/timeb.h> header file. */
+#define HAVE_SYS_TIMEB_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
+#define HAVE_SYS_WAIT_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `vfork' function. */
+#define HAVE_VFORK 1
+
+/* Define to 1 if you have the <vfork.h> header file. */
+/* #undef HAVE_VFORK_H */
+
+/* Define to 1 if you have the `vprintf' function. */
+#define HAVE_VPRINTF 1
+
+/* Define to 1 if `fork' works. */
+#define HAVE_WORKING_FORK 1
+
+/* Define to 1 if `vfork' works. */
+#define HAVE_WORKING_VFORK 1
+
+/* XKEYBOARD extension build environment present */
+#define HAVE_XKEYBOARD 1
+
+/* Define to 1 if `lstat' dereferences a symlink specified with a trailing
+ slash. */
+#define LSTAT_FOLLOWS_SLASHED_SYMLINK 1
+
+/* Name of package */
+#define PACKAGE "LibVNCServer"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "http://sourceforge.net/projects/libvncserver"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "LibVNCServer"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "LibVNCServer 0.7pre"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "libvncserver"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "0.7pre"
+
+/* The number of bytes in type char */
+/* #undef SIZEOF_CHAR */
+
+/* The number of bytes in type int */
+/* #undef SIZEOF_INT */
+
+/* The number of bytes in type long */
+/* #undef SIZEOF_LONG */
+
+/* The number of bytes in type short */
+/* #undef SIZEOF_SHORT */
+
+/* The number of bytes in type void* */
+/* #undef SIZEOF_VOIDP */
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Version number of package */
+#define VERSION "0.7pre"
+
+/* Define to 1 if your processor stores words with the most significant byte
+ first (like Motorola and SPARC, unlike Intel and VAX). */
+/* #undef WORDS_BIGENDIAN */
+
+/* Define to 1 if the X Window System is missing or not being used. */
+/* #undef X_DISPLAY_MISSING */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+ calls it, or to nothing if 'inline' is not supported under any name. */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+/* Define to rpl_malloc if the replacement function should be used. */
+/* #undef malloc */
+
+/* Define to `int' if <sys/types.h> does not define. */
+/* #undef pid_t */
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+/* The type for socklen */
+/* #undef socklen_t */
+
+/* Define as `fork' if `vfork' does not work. */
+/* #undef vfork */
diff --git a/libvncserver/rfbregion.c b/libvncserver/rfbregion.c
new file mode 100755
index 0000000..a102bc2
--- /dev/null
+++ b/libvncserver/rfbregion.c
@@ -0,0 +1,862 @@
+/* -=- sraRegion.c
+ * Copyright (c) 2001 James "Wez" Weatherall, Johannes E. Schindelin
+ *
+ * A general purpose region clipping library
+ * Only deals with rectangular regions, though.
+ */
+
+#include <rfb/rfb.h>
+#include <rfb/rfbregion.h>
+
+/* -=- Internal Span structure */
+
+struct sraRegion;
+
+typedef struct sraSpan {
+ struct sraSpan *_next;
+ struct sraSpan *_prev;
+ int start;
+ int end;
+ struct sraRegion *subspan;
+} sraSpan;
+
+typedef struct sraRegion {
+ sraSpan front;
+ sraSpan back;
+} sraSpanList;
+
+/* -=- Span routines */
+
+sraSpanList *sraSpanListDup(const sraSpanList *src);
+void sraSpanListDestroy(sraSpanList *list);
+
+sraSpan *
+sraSpanCreate(int start, int end, const sraSpanList *subspan) {
+ sraSpan *item = (sraSpan*)malloc(sizeof(sraSpan));
+ item->_next = item->_prev = NULL;
+ item->start = start;
+ item->end = end;
+ item->subspan = sraSpanListDup(subspan);
+ return item;
+}
+
+sraSpan *
+sraSpanDup(const sraSpan *src) {
+ sraSpan *span;
+ if (!src) return NULL;
+ span = sraSpanCreate(src->start, src->end, src->subspan);
+ return span;
+}
+
+void
+sraSpanInsertAfter(sraSpan *newspan, sraSpan *after) {
+ newspan->_next = after->_next;
+ newspan->_prev = after;
+ after->_next->_prev = newspan;
+ after->_next = newspan;
+}
+
+void
+sraSpanInsertBefore(sraSpan *newspan, sraSpan *before) {
+ newspan->_next = before;
+ newspan->_prev = before->_prev;
+ before->_prev->_next = newspan;
+ before->_prev = newspan;
+}
+
+void
+sraSpanRemove(sraSpan *span) {
+ span->_prev->_next = span->_next;
+ span->_next->_prev = span->_prev;
+}
+
+void
+sraSpanDestroy(sraSpan *span) {
+ if (span->subspan) sraSpanListDestroy(span->subspan);
+ free(span);
+}
+
+void
+sraSpanCheck(const sraSpan *span, const char *text) {
+ /* Check the span is valid! */
+ if (span->start == span->end) {
+ printf(text);
+ printf(":%d-%d\n", span->start, span->end);
+ }
+}
+
+/* -=- SpanList routines */
+
+void sraSpanPrint(const sraSpan *s);
+
+void
+sraSpanListPrint(const sraSpanList *l) {
+ sraSpan *curr;
+ if (!l) {
+ printf("NULL");
+ return;
+ }
+ curr = l->front._next;
+ printf("[");
+ while (curr != &(l->back)) {
+ sraSpanPrint(curr);
+ curr = curr->_next;
+ }
+ printf("]");
+}
+
+void
+sraSpanPrint(const sraSpan *s) {
+ printf("(%d-%d)", (s->start), (s->end));
+ if (s->subspan)
+ sraSpanListPrint(s->subspan);
+}
+
+sraSpanList *
+sraSpanListCreate() {
+ sraSpanList *item = (sraSpanList*)malloc(sizeof(sraSpanList));
+ item->front._next = &(item->back);
+ item->front._prev = NULL;
+ item->back._prev = &(item->front);
+ item->back._next = NULL;
+ return item;
+}
+
+sraSpanList *
+sraSpanListDup(const sraSpanList *src) {
+ sraSpanList *newlist;
+ sraSpan *newspan, *curr;
+
+ if (!src) return NULL;
+ newlist = sraSpanListCreate();
+ curr = src->front._next;
+ while (curr != &(src->back)) {
+ newspan = sraSpanDup(curr);
+ sraSpanInsertBefore(newspan, &(newlist->back));
+ curr = curr->_next;
+ }
+
+ return newlist;
+}
+
+void
+sraSpanListDestroy(sraSpanList *list) {
+ sraSpan *curr, *next;
+ while (list->front._next != &(list->back)) {
+ curr = list->front._next;
+ next = curr->_next;
+ sraSpanRemove(curr);
+ sraSpanDestroy(curr);
+ curr = next;
+ }
+ free(list);
+}
+
+void
+sraSpanListMakeEmpty(sraSpanList *list) {
+ sraSpan *curr, *next;
+ while (list->front._next != &(list->back)) {
+ curr = list->front._next;
+ next = curr->_next;
+ sraSpanRemove(curr);
+ sraSpanDestroy(curr);
+ curr = next;
+ }
+ list->front._next = &(list->back);
+ list->front._prev = NULL;
+ list->back._prev = &(list->front);
+ list->back._next = NULL;
+}
+
+rfbBool
+sraSpanListEqual(const sraSpanList *s1, const sraSpanList *s2) {
+ sraSpan *sp1, *sp2;
+
+ if (!s1) {
+ if (!s2) {
+ return 1;
+ } else {
+ printf("sraSpanListEqual:incompatible spans (only one NULL!)\n");
+ return FALSE;
+ }
+ }
+
+ sp1 = s1->front._next;
+ sp2 = s2->front._next;
+ while ((sp1 != &(s1->back)) &&
+ (sp2 != &(s2->back))) {
+ if ((sp1->start != sp2->start) ||
+ (sp1->end != sp2->end) ||
+ (!sraSpanListEqual(sp1->subspan, sp2->subspan))) {
+ return 0;
+ }
+ sp1 = sp1->_next;
+ sp2 = sp2->_next;
+ }
+
+ if ((sp1 == &(s1->back)) && (sp2 == &(s2->back))) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+rfbBool
+sraSpanListEmpty(const sraSpanList *list) {
+ return (list->front._next == &(list->back));
+}
+
+unsigned long
+sraSpanListCount(const sraSpanList *list) {
+ sraSpan *curr = list->front._next;
+ unsigned long count = 0;
+ while (curr != &(list->back)) {
+ if (curr->subspan) {
+ count += sraSpanListCount(curr->subspan);
+ } else {
+ count += 1;
+ }
+ curr = curr->_next;
+ }
+ return count;
+}
+
+void
+sraSpanMergePrevious(sraSpan *dest) {
+ sraSpan *prev = dest->_prev;
+
+ while ((prev->_prev) &&
+ (prev->end == dest->start) &&
+ (sraSpanListEqual(prev->subspan, dest->subspan))) {
+ /*
+ printf("merge_prev:");
+ sraSpanPrint(prev);
+ printf(" & ");
+ sraSpanPrint(dest);
+ printf("\n");
+ */
+ dest->start = prev->start;
+ sraSpanRemove(prev);
+ sraSpanDestroy(prev);
+ prev = dest->_prev;
+ }
+}
+
+void
+sraSpanMergeNext(sraSpan *dest) {
+ sraSpan *next = dest->_next;
+ while ((next->_next) &&
+ (next->start == dest->end) &&
+ (sraSpanListEqual(next->subspan, dest->subspan))) {
+/*
+ printf("merge_next:");
+ sraSpanPrint(dest);
+ printf(" & ");
+ sraSpanPrint(next);
+ printf("\n");
+ */
+ dest->end = next->end;
+ sraSpanRemove(next);
+ sraSpanDestroy(next);
+ next = dest->_next;
+ }
+}
+
+void
+sraSpanListOr(sraSpanList *dest, const sraSpanList *src) {
+ sraSpan *d_curr, *s_curr;
+ int s_start, s_end;
+
+ if (!dest) {
+ if (!src) {
+ return;
+ } else {
+ printf("sraSpanListOr:incompatible spans (only one NULL!)\n");
+ return;
+ }
+ }
+
+ d_curr = dest->front._next;
+ s_curr = src->front._next;
+ s_start = s_curr->start;
+ s_end = s_curr->end;
+ while (s_curr != &(src->back)) {
+
+ /* - If we are at end of destination list OR
+ If the new span comes before the next destination one */
+ if ((d_curr == &(dest->back)) ||
+ (d_curr->start >= s_end)) {
+ /* - Add the span */
+ sraSpanInsertBefore(sraSpanCreate(s_start, s_end,
+ s_curr->subspan),
+ d_curr);
+ if (d_curr != &(dest->back))
+ sraSpanMergePrevious(d_curr);
+ s_curr = s_curr->_next;
+ s_start = s_curr->start;
+ s_end = s_curr->end;
+ } else {
+
+ /* - If the new span overlaps the existing one */
+ if ((s_start < d_curr->end) &&
+ (s_end > d_curr->start)) {
+
+ /* - Insert new span before the existing destination one? */
+ if (s_start < d_curr->start) {
+ sraSpanInsertBefore(sraSpanCreate(s_start,
+ d_curr->start,
+ s_curr->subspan),
+ d_curr);
+ sraSpanMergePrevious(d_curr);
+ }
+
+ /* Split the existing span if necessary */
+ if (s_end < d_curr->end) {
+ sraSpanInsertAfter(sraSpanCreate(s_end,
+ d_curr->end,
+ d_curr->subspan),
+ d_curr);
+ d_curr->end = s_end;
+ }
+ if (s_start > d_curr->start) {
+ sraSpanInsertBefore(sraSpanCreate(d_curr->start,
+ s_start,
+ d_curr->subspan),
+ d_curr);
+ d_curr->start = s_start;
+ }
+
+ /* Recursively OR subspans */
+ sraSpanListOr(d_curr->subspan, s_curr->subspan);
+
+ /* Merge this span with previous or next? */
+ if (d_curr->_prev != &(dest->front))
+ sraSpanMergePrevious(d_curr);
+ if (d_curr->_next != &(dest->back))
+ sraSpanMergeNext(d_curr);
+
+ /* Move onto the next pair to compare */
+ if (s_end > d_curr->end) {
+ s_start = d_curr->end;
+ d_curr = d_curr->_next;
+ } else {
+ s_curr = s_curr->_next;
+ s_start = s_curr->start;
+ s_end = s_curr->end;
+ }
+ } else {
+ /* - No overlap. Move to the next destination span */
+ d_curr = d_curr->_next;
+ }
+ }
+ }
+}
+
+rfbBool
+sraSpanListAnd(sraSpanList *dest, const sraSpanList *src) {
+ sraSpan *d_curr, *s_curr, *d_next;
+
+ if (!dest) {
+ if (!src) {
+ return 1;
+ } else {
+ printf("sraSpanListAnd:incompatible spans (only one NULL!)\n");
+ return FALSE;
+ }
+ }
+
+ d_curr = dest->front._next;
+ s_curr = src->front._next;
+ while ((s_curr != &(src->back)) && (d_curr != &(dest->back))) {
+
+ /* - If we haven't reached a destination span yet then move on */
+ if (d_curr->start >= s_curr->end) {
+ s_curr = s_curr->_next;
+ continue;
+ }
+
+ /* - If we are beyond the current destination span then remove it */
+ if (d_curr->end <= s_curr->start) {
+ sraSpan *next = d_curr->_next;
+ sraSpanRemove(d_curr);
+ sraSpanDestroy(d_curr);
+ d_curr = next;
+ continue;
+ }
+
+ /* - If we partially overlap a span then split it up or remove bits */
+ if (s_curr->start > d_curr->start) {
+ /* - The top bit of the span does not match */
+ d_curr->start = s_curr->start;
+ }
+ if (s_curr->end < d_curr->end) {
+ /* - The end of the span does not match */
+ sraSpanInsertAfter(sraSpanCreate(s_curr->end,
+ d_curr->end,
+ d_curr->subspan),
+ d_curr);
+ d_curr->end = s_curr->end;
+ }
+
+ /* - Now recursively process the affected span */
+ if (!sraSpanListAnd(d_curr->subspan, s_curr->subspan)) {
+ /* - The destination subspan is now empty, so we should remove it */
+ sraSpan *next = d_curr->_next;
+ sraSpanRemove(d_curr);
+ sraSpanDestroy(d_curr);
+ d_curr = next;
+ } else {
+ /* Merge this span with previous or next? */
+ if (d_curr->_prev != &(dest->front))
+ sraSpanMergePrevious(d_curr);
+
+ /* - Move on to the next span */
+ d_next = d_curr;
+ if (s_curr->end >= d_curr->end) {
+ d_next = d_curr->_next;
+ }
+ if (s_curr->end <= d_curr->end) {
+ s_curr = s_curr->_next;
+ }
+ d_curr = d_next;
+ }
+ }
+
+ while (d_curr != &(dest->back)) {
+ sraSpan *next = d_curr->_next;
+ sraSpanRemove(d_curr);
+ sraSpanDestroy(d_curr);
+ d_curr=next;
+ }
+
+ return !sraSpanListEmpty(dest);
+}
+
+rfbBool
+sraSpanListSubtract(sraSpanList *dest, const sraSpanList *src) {
+ sraSpan *d_curr, *s_curr;
+
+ if (!dest) {
+ if (!src) {
+ return 1;
+ } else {
+ printf("sraSpanListSubtract:incompatible spans (only one NULL!)\n");
+ return FALSE;
+ }
+ }
+
+ d_curr = dest->front._next;
+ s_curr = src->front._next;
+ while ((s_curr != &(src->back)) && (d_curr != &(dest->back))) {
+
+ /* - If we haven't reached a destination span yet then move on */
+ if (d_curr->start >= s_curr->end) {
+ s_curr = s_curr->_next;
+ continue;
+ }
+
+ /* - If we are beyond the current destination span then skip it */
+ if (d_curr->end <= s_curr->start) {
+ d_curr = d_curr->_next;
+ continue;
+ }
+
+ /* - If we partially overlap the current span then split it up */
+ if (s_curr->start > d_curr->start) {
+ sraSpanInsertBefore(sraSpanCreate(d_curr->start,
+ s_curr->start,
+ d_curr->subspan),
+ d_curr);
+ d_curr->start = s_curr->start;
+ }
+ if (s_curr->end < d_curr->end) {
+ sraSpanInsertAfter(sraSpanCreate(s_curr->end,
+ d_curr->end,
+ d_curr->subspan),
+ d_curr);
+ d_curr->end = s_curr->end;
+ }
+
+ /* - Now recursively process the affected span */
+ if ((!d_curr->subspan) || !sraSpanListSubtract(d_curr->subspan, s_curr->subspan)) {
+ /* - The destination subspan is now empty, so we should remove it */
+ sraSpan *next = d_curr->_next;
+ sraSpanRemove(d_curr);
+ sraSpanDestroy(d_curr);
+ d_curr = next;
+ } else {
+ /* Merge this span with previous or next? */
+ if (d_curr->_prev != &(dest->front))
+ sraSpanMergePrevious(d_curr);
+ if (d_curr->_next != &(dest->back))
+ sraSpanMergeNext(d_curr);
+
+ /* - Move on to the next span */
+ if (s_curr->end > d_curr->end) {
+ d_curr = d_curr->_next;
+ } else {
+ s_curr = s_curr->_next;
+ }
+ }
+ }
+
+ return !sraSpanListEmpty(dest);
+}
+
+/* -=- Region routines */
+
+sraRegion *
+sraRgnCreate() {
+ return (sraRegion*)sraSpanListCreate();
+}
+
+sraRegion *
+sraRgnCreateRect(int x1, int y1, int x2, int y2) {
+ sraSpanList *vlist, *hlist;
+ sraSpan *vspan, *hspan;
+
+ /* - Build the horizontal portion of the span */
+ hlist = sraSpanListCreate();
+ hspan = sraSpanCreate(x1, x2, NULL);
+ sraSpanInsertAfter(hspan, &(hlist->front));
+
+ /* - Build the vertical portion of the span */
+ vlist = sraSpanListCreate();
+ vspan = sraSpanCreate(y1, y2, hlist);
+ sraSpanInsertAfter(vspan, &(vlist->front));
+
+ sraSpanListDestroy(hlist);
+
+ return (sraRegion*)vlist;
+}
+
+sraRegion *
+sraRgnCreateRgn(const sraRegion *src) {
+ return (sraRegion*)sraSpanListDup((sraSpanList*)src);
+}
+
+void
+sraRgnDestroy(sraRegion *rgn) {
+ sraSpanListDestroy((sraSpanList*)rgn);
+}
+
+void
+sraRgnMakeEmpty(sraRegion *rgn) {
+ sraSpanListMakeEmpty((sraSpanList*)rgn);
+}
+
+/* -=- Boolean Region ops */
+
+rfbBool
+sraRgnAnd(sraRegion *dst, const sraRegion *src) {
+ return sraSpanListAnd((sraSpanList*)dst, (sraSpanList*)src);
+}
+
+void
+sraRgnOr(sraRegion *dst, const sraRegion *src) {
+ sraSpanListOr((sraSpanList*)dst, (sraSpanList*)src);
+}
+
+rfbBool
+sraRgnSubtract(sraRegion *dst, const sraRegion *src) {
+ return sraSpanListSubtract((sraSpanList*)dst, (sraSpanList*)src);
+}
+
+void
+sraRgnOffset(sraRegion *dst, int dx, int dy) {
+ sraSpan *vcurr, *hcurr;
+
+ vcurr = ((sraSpanList*)dst)->front._next;
+ while (vcurr != &(((sraSpanList*)dst)->back)) {
+ vcurr->start += dy;
+ vcurr->end += dy;
+
+ hcurr = vcurr->subspan->front._next;
+ while (hcurr != &(vcurr->subspan->back)) {
+ hcurr->start += dx;
+ hcurr->end += dx;
+ hcurr = hcurr->_next;
+ }
+
+ vcurr = vcurr->_next;
+ }
+}
+
+sraRegion *sraRgnBBox(const sraRegion *src) {
+ int xmin=((unsigned int)(int)-1)>>1,ymin=xmin,xmax=1-xmin,ymax=xmax;
+ sraSpan *vcurr, *hcurr;
+
+ if(!src)
+ return sraRgnCreate();
+
+ vcurr = ((sraSpanList*)src)->front._next;
+ while (vcurr != &(((sraSpanList*)src)->back)) {
+ if(vcurr->start<ymin)
+ ymin=vcurr->start;
+ if(vcurr->end>ymax)
+ ymax=vcurr->end;
+
+ hcurr = vcurr->subspan->front._next;
+ while (hcurr != &(vcurr->subspan->back)) {
+ if(hcurr->start<xmin)
+ xmin=hcurr->start;
+ if(hcurr->end>xmax)
+ xmax=hcurr->end;
+ hcurr = hcurr->_next;
+ }
+
+ vcurr = vcurr->_next;
+ }
+
+ if(xmax<xmin || ymax<ymin)
+ return sraRgnCreate();
+
+ return sraRgnCreateRect(xmin,ymin,xmax,ymax);
+}
+
+rfbBool
+sraRgnPopRect(sraRegion *rgn, sraRect *rect, unsigned long flags) {
+ sraSpan *vcurr, *hcurr;
+ sraSpan *vend, *hend;
+ rfbBool right2left = flags & 2;
+ rfbBool bottom2top = flags & 1;
+
+ /* - Pick correct order */
+ if (bottom2top) {
+ vcurr = ((sraSpanList*)rgn)->back._prev;
+ vend = &(((sraSpanList*)rgn)->front);
+ } else {
+ vcurr = ((sraSpanList*)rgn)->front._next;
+ vend = &(((sraSpanList*)rgn)->back);
+ }
+
+ if (vcurr != vend) {
+ rect->y1 = vcurr->start;
+ rect->y2 = vcurr->end;
+
+ /* - Pick correct order */
+ if (right2left) {
+ hcurr = vcurr->subspan->back._prev;
+ hend = &(vcurr->subspan->front);
+ } else {
+ hcurr = vcurr->subspan->front._next;
+ hend = &(vcurr->subspan->back);
+ }
+
+ if (hcurr != hend) {
+ rect->x1 = hcurr->start;
+ rect->x2 = hcurr->end;
+
+ sraSpanRemove(hcurr);
+ sraSpanDestroy(hcurr);
+
+ if (sraSpanListEmpty(vcurr->subspan)) {
+ sraSpanRemove(vcurr);
+ sraSpanDestroy(vcurr);
+ }
+
+#if 0
+ printf("poprect:(%dx%d)-(%dx%d)\n",
+ rect->x1, rect->y1, rect->x2, rect->y2);
+#endif
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+unsigned long
+sraRgnCountRects(const sraRegion *rgn) {
+ unsigned long count = sraSpanListCount((sraSpanList*)rgn);
+ return count;
+}
+
+rfbBool
+sraRgnEmpty(const sraRegion *rgn) {
+ return sraSpanListEmpty((sraSpanList*)rgn);
+}
+
+/* iterator stuff */
+sraRectangleIterator *sraRgnGetIterator(sraRegion *s)
+{
+ /* these values have to be multiples of 4 */
+#define DEFSIZE 4
+#define DEFSTEP 8
+ sraRectangleIterator *i =
+ (sraRectangleIterator*)malloc(sizeof(sraRectangleIterator));
+ if(!i)
+ return(0);
+
+ /* we have to recurse eventually. So, the first sPtr is the pointer to
+ the sraSpan in the first level. the second sPtr is the pointer to
+ the sraRegion.back. The third and fourth sPtr are for the second
+ recursion level and so on. */
+ i->sPtrs = (sraSpan**)malloc(sizeof(sraSpan*)*DEFSIZE);
+ if(!i->sPtrs) {
+ free(i);
+ return(0);
+ }
+ i->ptrSize = DEFSIZE;
+ i->sPtrs[0] = &(s->front);
+ i->sPtrs[1] = &(s->back);
+ i->ptrPos = 0;
+ i->reverseX = 0;
+ i->reverseY = 0;
+ return(i);
+}
+
+sraRectangleIterator *sraRgnGetReverseIterator(sraRegion *s,rfbBool reverseX,rfbBool reverseY)
+{
+ sraRectangleIterator *i = sraRgnGetIterator(s);
+ if(reverseY) {
+ i->sPtrs[1] = &(s->front);
+ i->sPtrs[0] = &(s->back);
+ }
+ i->reverseX = reverseX;
+ i->reverseY = reverseY;
+ return(i);
+}
+
+rfbBool sraReverse(sraRectangleIterator *i)
+{
+ return( ((i->ptrPos&2) && i->reverseX) ||
+ (!(i->ptrPos&2) && i->reverseY));
+}
+
+sraSpan* sraNextSpan(sraRectangleIterator *i)
+{
+ if(sraReverse(i))
+ return(i->sPtrs[i->ptrPos]->_prev);
+ else
+ return(i->sPtrs[i->ptrPos]->_next);
+}
+
+rfbBool sraRgnIteratorNext(sraRectangleIterator* i,sraRect* r)
+{
+ /* is the subspan finished? */
+ while(sraNextSpan(i) == i->sPtrs[i->ptrPos+1]) {
+ i->ptrPos -= 2;
+ if(i->ptrPos < 0) /* the end */
+ return(0);
+ }
+
+ i->sPtrs[i->ptrPos] = sraNextSpan(i);
+
+ /* is this a new subspan? */
+ while(i->sPtrs[i->ptrPos]->subspan) {
+ if(i->ptrPos+2 > i->ptrSize) { /* array is too small */
+ i->ptrSize += DEFSTEP;
+ i->sPtrs = (sraSpan**)realloc(i->sPtrs, sizeof(sraSpan*)*i->ptrSize);
+ }
+ i->ptrPos =+ 2;
+ if(sraReverse(i)) {
+ i->sPtrs[i->ptrPos] = i->sPtrs[i->ptrPos-2]->subspan->back._prev;
+ i->sPtrs[i->ptrPos+1] = &(i->sPtrs[i->ptrPos-2]->subspan->front);
+ } else {
+ i->sPtrs[i->ptrPos] = i->sPtrs[i->ptrPos-2]->subspan->front._next;
+ i->sPtrs[i->ptrPos+1] = &(i->sPtrs[i->ptrPos-2]->subspan->back);
+ }
+ }
+
+ if((i->ptrPos%4)!=2) {
+ rfbErr("sraRgnIteratorNext: offset is wrong (%d%%4!=2)\n",i->ptrPos);
+ return FALSE;
+ }
+
+ r->y1 = i->sPtrs[i->ptrPos-2]->start;
+ r->y2 = i->sPtrs[i->ptrPos-2]->end;
+ r->x1 = i->sPtrs[i->ptrPos]->start;
+ r->x2 = i->sPtrs[i->ptrPos]->end;
+
+ return(-1);
+}
+
+void sraRgnReleaseIterator(sraRectangleIterator* i)
+{
+ free(i->sPtrs);
+ free(i);
+}
+
+void
+sraRgnPrint(const sraRegion *rgn) {
+ sraSpanListPrint((sraSpanList*)rgn);
+}
+
+rfbBool
+sraClipRect(int *x, int *y, int *w, int *h,
+ int cx, int cy, int cw, int ch) {
+ if (*x < cx) {
+ *w -= (cx-*x);
+ *x = cx;
+ }
+ if (*y < cy) {
+ *h -= (cy-*y);
+ *y = cy;
+ }
+ if (*x+*w > cx+cw) {
+ *w = (cx+cw)-*x;
+ }
+ if (*y+*h > cy+ch) {
+ *h = (cy+ch)-*y;
+ }
+ return (*w>0) && (*h>0);
+}
+
+/* test */
+
+#ifdef SRA_TEST
+/* pipe the output to sort|uniq -u and you'll get the errors. */
+int main(int argc, char** argv)
+{
+ sraRegionPtr region, region1, region2;
+ sraRectangleIterator* i;
+ sraRect rect;
+ rfbBool b;
+
+ region = sraRgnCreateRect(10, 10, 600, 300);
+ region1 = sraRgnCreateRect(40, 50, 350, 200);
+ region2 = sraRgnCreateRect(0, 0, 20, 40);
+
+ sraRgnPrint(region);
+ printf("\n[(10-300)[(10-600)]]\n\n");
+
+ b = sraRgnSubtract(region, region1);
+ printf("%s ",b?"true":"false");
+ sraRgnPrint(region);
+ printf("\ntrue [(10-50)[(10-600)](50-200)[(10-40)(350-600)](200-300)[(10-600)]]\n\n");
+
+ sraRgnOr(region, region2);
+ printf("%ld\n6\n\n", sraRgnCountRects(region));
+
+ i = sraRgnGetIterator(region);
+ while(sraRgnIteratorNext(i, &rect))
+ printf("%dx%d+%d+%d ",
+ rect.x2-rect.x1,rect.y2-rect.y1,
+ rect.x1,rect.y1);
+ sraRgnReleaseIterator(i);
+ printf("\n20x10+0+0 600x30+0+10 590x10+10+40 30x150+10+50 250x150+350+50 590x100+10+200 \n\n");
+
+ i = sraRgnGetReverseIterator(region,1,0);
+ while(sraRgnIteratorNext(i, &rect))
+ printf("%dx%d+%d+%d ",
+ rect.x2-rect.x1,rect.y2-rect.y1,
+ rect.x1,rect.y1);
+ sraRgnReleaseIterator(i);
+ printf("\n20x10+0+0 600x30+0+10 590x10+10+40 250x150+350+50 30x150+10+50 590x100+10+200 \n\n");
+
+ i = sraRgnGetReverseIterator(region,1,1);
+ while(sraRgnIteratorNext(i, &rect))
+ printf("%dx%d+%d+%d ",
+ rect.x2-rect.x1,rect.y2-rect.y1,
+ rect.x1,rect.y1);
+ sraRgnReleaseIterator(i);
+ printf("\n590x100+10+200 250x150+350+50 30x150+10+50 590x10+10+40 600x30+0+10 20x10+0+0 \n\n");
+
+ sraRgnDestroy(region);
+ sraRgnDestroy(region1);
+ sraRgnDestroy(region2);
+
+ return(0);
+}
+#endif
diff --git a/libvncserver/rfbserver.c b/libvncserver/rfbserver.c
new file mode 100644
index 0000000..e22283e
--- /dev/null
+++ b/libvncserver/rfbserver.c
@@ -0,0 +1,1808 @@
+/*
+ * rfbserver.c - deal with server-side of the RFB protocol.
+ */
+
+/*
+ * Copyright (C) 2002 RealVNC Ltd.
+ * OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
+ * Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge.
+ * 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/rfb.h>
+#include <rfb/rfbregion.h>
+
+#ifdef LIBVNCSERVER_HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#ifdef WIN32
+#define write(sock,buf,len) send(sock,buf,len,0)
+#else
+#ifdef LIBVNCSERVER_HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <pwd.h>
+#ifdef LIBVNCSERVER_HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef LIBVNCSERVER_HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#endif
+#endif
+
+#ifdef CORBA
+#include <vncserverctrl.h>
+#endif
+
+#ifdef DEBUGPROTO
+#undef DEBUGPROTO
+#define DEBUGPROTO(x) x
+#else
+#define DEBUGPROTO(x)
+#endif
+
+rfbClientPtr pointerClient = NULL; /* Mutex for pointer events */
+
+static void rfbProcessClientProtocolVersion(rfbClientPtr cl);
+static void rfbProcessClientNormalMessage(rfbClientPtr cl);
+static void rfbProcessClientInitMessage(rfbClientPtr cl);
+
+#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
+void rfbIncrClientRef(rfbClientPtr cl)
+{
+ LOCK(cl->refCountMutex);
+ cl->refCount++;
+ UNLOCK(cl->refCountMutex);
+}
+
+void rfbDecrClientRef(rfbClientPtr cl)
+{
+ LOCK(cl->refCountMutex);
+ cl->refCount--;
+ if(cl->refCount<=0) /* just to be sure also < 0 */
+ TSIGNAL(cl->deleteCond);
+ UNLOCK(cl->refCountMutex);
+}
+#else
+void rfbIncrClientRef(rfbClientPtr cl) {}
+void rfbDecrClientRef(rfbClientPtr cl) {}
+#endif
+
+#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
+MUTEX(rfbClientListMutex);
+#endif
+
+struct rfbClientIterator {
+ rfbClientPtr next;
+ rfbScreenInfoPtr screen;
+};
+
+void
+rfbClientListInit(rfbScreenInfoPtr rfbScreen)
+{
+ if(sizeof(rfbBool)!=1) {
+ /* a sanity check */
+ fprintf(stderr,"rfbBool's size is not 1 (%d)!\n",sizeof(rfbBool));
+ /* we cannot continue, because rfbBool is supposed to be char everywhere */
+ exit(1);
+ }
+ rfbScreen->rfbClientHead = NULL;
+ INIT_MUTEX(rfbClientListMutex);
+}
+
+rfbClientIteratorPtr
+rfbGetClientIterator(rfbScreenInfoPtr rfbScreen)
+{
+ rfbClientIteratorPtr i =
+ (rfbClientIteratorPtr)malloc(sizeof(struct rfbClientIterator));
+ i->next = 0;
+ i->screen = rfbScreen;
+ return i;
+}
+
+rfbClientPtr
+rfbClientIteratorHead(rfbClientIteratorPtr i)
+{
+#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
+ if(i->next != 0) {
+ rfbDecrClientRef(i->next);
+ rfbIncrClientRef(i->screen->rfbClientHead);
+ }
+#endif
+ LOCK(rfbClientListMutex);
+ i->next = i->screen->rfbClientHead;
+ UNLOCK(rfbClientListMutex);
+ return i->next;
+}
+
+rfbClientPtr
+rfbClientIteratorNext(rfbClientIteratorPtr i)
+{
+ if(i->next == 0) {
+ LOCK(rfbClientListMutex);
+ i->next = i->screen->rfbClientHead;
+ UNLOCK(rfbClientListMutex);
+ } else {
+ IF_PTHREADS(rfbClientPtr cl = i->next);
+ i->next = i->next->next;
+ IF_PTHREADS(rfbDecrClientRef(cl));
+ }
+
+#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
+ while(i->next && i->next->sock<0)
+ i->next = i->next->next;
+ if(i->next)
+ rfbIncrClientRef(i->next);
+#endif
+
+ return i->next;
+}
+
+void
+rfbReleaseClientIterator(rfbClientIteratorPtr iterator)
+{
+ IF_PTHREADS(if(iterator->next) rfbDecrClientRef(iterator->next));
+ free(iterator);
+}
+
+
+/*
+ * rfbNewClientConnection is called from sockets.c when a new connection
+ * comes in.
+ */
+
+void
+rfbNewClientConnection(rfbScreen,sock)
+ rfbScreenInfoPtr rfbScreen;
+ int sock;
+{
+ rfbClientPtr cl;
+
+ cl = rfbNewClient(rfbScreen,sock);
+#ifdef CORBA
+ if(cl!=NULL)
+ newConnection(cl, (KEYBOARD_DEVICE|POINTER_DEVICE),1,1,1);
+#endif
+}
+
+
+/*
+ * rfbReverseConnection is called by the CORBA stuff to make an outward
+ * connection to a "listening" RFB client.
+ */
+
+rfbClientPtr
+rfbReverseConnection(rfbScreen,host, port)
+ rfbScreenInfoPtr rfbScreen;
+ char *host;
+ int port;
+{
+ int sock;
+ rfbClientPtr cl;
+
+ if ((sock = rfbConnect(rfbScreen, host, port)) < 0)
+ return (rfbClientPtr)NULL;
+
+ cl = rfbNewClient(rfbScreen, sock);
+
+ if (cl) {
+ cl->reverseConnection = TRUE;
+ }
+
+ return cl;
+}
+
+
+/*
+ * rfbNewClient is called when a new connection has been made by whatever
+ * means.
+ */
+
+rfbClientPtr
+rfbNewTCPOrUDPClient(rfbScreen,sock,isUDP)
+ rfbScreenInfoPtr rfbScreen;
+ int sock;
+ rfbBool isUDP;
+{
+ rfbProtocolVersionMsg pv;
+ rfbClientIteratorPtr iterator;
+ rfbClientPtr cl,cl_;
+ struct sockaddr_in addr;
+ size_t addrlen = sizeof(struct sockaddr_in);
+
+ cl = (rfbClientPtr)calloc(sizeof(rfbClientRec),1);
+
+ cl->screen = rfbScreen;
+ cl->sock = sock;
+ cl->viewOnly = FALSE;
+
+ rfbResetStats(cl);
+
+ if(isUDP) {
+ rfbLog(" accepted UDP client\n");
+ } else {
+ int one=1;
+
+ getpeername(sock, (struct sockaddr *)&addr, &addrlen);
+ cl->host = strdup(inet_ntoa(addr.sin_addr));
+
+ rfbLog(" other clients:\n");
+ iterator = rfbGetClientIterator(rfbScreen);
+ while ((cl_ = rfbClientIteratorNext(iterator)) != NULL) {
+ rfbLog(" %s\n",cl_->host);
+ }
+ rfbReleaseClientIterator(iterator);
+
+#ifndef WIN32
+ if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) {
+ rfbLogPerror("fcntl failed");
+ close(sock);
+ return NULL;
+ }
+#endif
+
+ if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
+ (char *)&one, sizeof(one)) < 0) {
+ rfbLogPerror("setsockopt failed");
+ close(sock);
+ return NULL;
+ }
+
+ FD_SET(sock,&(rfbScreen->allFds));
+ rfbScreen->maxFd = max(sock,rfbScreen->maxFd);
+
+ INIT_MUTEX(cl->outputMutex);
+ INIT_MUTEX(cl->refCountMutex);
+ INIT_COND(cl->deleteCond);
+
+ cl->state = RFB_PROTOCOL_VERSION;
+
+ cl->reverseConnection = FALSE;
+ cl->readyForSetColourMapEntries = FALSE;
+ cl->useCopyRect = FALSE;
+ cl->preferredEncoding = rfbEncodingRaw;
+ cl->correMaxWidth = 48;
+ cl->correMaxHeight = 48;
+#ifdef LIBVNCSERVER_HAVE_LIBZ
+ cl->zrleData = 0;
+#endif
+
+ cl->copyRegion = sraRgnCreate();
+ cl->copyDX = 0;
+ cl->copyDY = 0;
+
+ cl->modifiedRegion =
+ sraRgnCreateRect(0,0,rfbScreen->width,rfbScreen->height);
+
+ INIT_MUTEX(cl->updateMutex);
+ INIT_COND(cl->updateCond);
+
+ cl->requestedRegion = sraRgnCreate();
+
+ cl->format = cl->screen->rfbServerFormat;
+ cl->translateFn = rfbTranslateNone;
+ cl->translateLookupTable = NULL;
+
+ LOCK(rfbClientListMutex);
+
+ IF_PTHREADS(cl->refCount = 0);
+ cl->next = rfbScreen->rfbClientHead;
+ cl->prev = NULL;
+ if (rfbScreen->rfbClientHead)
+ rfbScreen->rfbClientHead->prev = cl;
+
+ rfbScreen->rfbClientHead = cl;
+ UNLOCK(rfbClientListMutex);
+
+#ifdef LIBVNCSERVER_HAVE_LIBJPEG
+ cl->tightCompressLevel = TIGHT_DEFAULT_COMPRESSION;
+ cl->tightQualityLevel = -1;
+ {
+ int i;
+ for (i = 0; i < 4; i++)
+ cl->zsActive[i] = FALSE;
+ }
+#endif
+
+ cl->enableCursorShapeUpdates = FALSE;
+ cl->enableCursorPosUpdates = FALSE;
+ cl->useRichCursorEncoding = FALSE;
+ cl->enableLastRectEncoding = FALSE;
+ cl->useNewFBSize = FALSE;
+
+#ifdef LIBVNCSERVER_HAVE_LIBZ
+ cl->compStreamInited = FALSE;
+ cl->compStream.total_in = 0;
+ cl->compStream.total_out = 0;
+ cl->compStream.zalloc = Z_NULL;
+ cl->compStream.zfree = Z_NULL;
+ cl->compStream.opaque = Z_NULL;
+
+ cl->zlibCompressLevel = 5;
+#endif
+
+ cl->progressiveSliceY = 0;
+
+ sprintf(pv,rfbProtocolVersionFormat,rfbProtocolMajorVersion,
+ rfbProtocolMinorVersion);
+
+ if (WriteExact(cl, pv, sz_rfbProtocolVersionMsg) < 0) {
+ rfbLogPerror("rfbNewClient: write");
+ rfbCloseClient(cl);
+ /* TODO: memory leak here (cl is never freed)
+ * can rfbClientConnectionGone called at this time?
+ * tim@tjansen.de
+ */
+ return NULL;
+ }
+ }
+
+ cl->clientData = NULL;
+ cl->clientGoneHook = doNothingWithClient;
+ switch (cl->screen->newClientHook(cl)) {
+ case RFB_CLIENT_ON_HOLD:
+ cl->onHold = TRUE;
+ break;
+ case RFB_CLIENT_ACCEPT:
+ cl->onHold = FALSE;
+ break;
+ case RFB_CLIENT_REFUSE:
+ rfbCloseClient(cl);
+ rfbClientConnectionGone(cl);
+ cl = NULL;
+ break;
+ }
+ return cl;
+}
+
+rfbClientPtr
+rfbNewClient(rfbScreen,sock)
+ rfbScreenInfoPtr rfbScreen;
+ int sock;
+{
+ return(rfbNewTCPOrUDPClient(rfbScreen,sock,FALSE));
+}
+
+rfbClientPtr
+rfbNewUDPClient(rfbScreen)
+ rfbScreenInfoPtr rfbScreen;
+{
+ return((rfbScreen->udpClient=
+ rfbNewTCPOrUDPClient(rfbScreen,rfbScreen->udpSock,TRUE)));
+}
+
+/*
+ * rfbClientConnectionGone is called from sockets.c just after a connection
+ * has gone away.
+ */
+
+void
+rfbClientConnectionGone(cl)
+ rfbClientPtr cl;
+{
+ int i;
+
+ LOCK(rfbClientListMutex);
+
+ if (cl->prev)
+ cl->prev->next = cl->next;
+ else
+ cl->screen->rfbClientHead = cl->next;
+ if (cl->next)
+ cl->next->prev = cl->prev;
+
+#ifdef LIBVNCSERVER_HAVE_LIBZ
+ FreeZrleData(cl);
+#endif
+
+#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
+ if(cl->screen->backgroundLoop != FALSE)
+ do {
+ LOCK(cl->refCountMutex);
+ i=cl->refCount;
+ UNLOCK(cl->refCountMutex);
+ if(i>0)
+ WAIT(cl->deleteCond,cl->refCountMutex);
+ } while(i>0);
+#endif
+
+ if(cl->sock>=0)
+ FD_CLR(cl->sock,&(cl->screen->allFds));
+
+ cl->clientGoneHook(cl);
+
+ rfbLog("Client %s gone\n",cl->host);
+ free(cl->host);
+
+#ifdef LIBVNCSERVER_HAVE_LIBZ
+ /* Release the compression state structures if any. */
+ if ( cl->compStreamInited ) {
+ deflateEnd( &(cl->compStream) );
+ }
+
+#ifdef LIBVNCSERVER_HAVE_LIBJPEG
+ for (i = 0; i < 4; i++) {
+ if (cl->zsActive[i])
+ deflateEnd(&cl->zsStruct[i]);
+ }
+#endif
+#endif
+
+ if (pointerClient == cl)
+ pointerClient = NULL;
+
+ sraRgnDestroy(cl->modifiedRegion);
+ sraRgnDestroy(cl->requestedRegion);
+ sraRgnDestroy(cl->copyRegion);
+
+ UNLOCK(rfbClientListMutex);
+
+ if (cl->translateLookupTable) free(cl->translateLookupTable);
+
+ TINI_COND(cl->updateCond);
+ TINI_MUTEX(cl->updateMutex);
+
+ LOCK(cl->outputMutex);
+ TINI_MUTEX(cl->outputMutex);
+
+#ifdef CORBA
+ destroyConnection(cl);
+#endif
+
+ rfbPrintStats(cl);
+
+ free(cl);
+}
+
+
+/*
+ * rfbProcessClientMessage is called when there is data to read from a client.
+ */
+
+void
+rfbProcessClientMessage(cl)
+ rfbClientPtr cl;
+{
+ switch (cl->state) {
+ case RFB_PROTOCOL_VERSION:
+ rfbProcessClientProtocolVersion(cl);
+ return;
+ case RFB_AUTHENTICATION:
+ rfbAuthProcessClientMessage(cl);
+ return;
+ case RFB_INITIALISATION:
+ rfbProcessClientInitMessage(cl);
+ return;
+ default:
+ rfbProcessClientNormalMessage(cl);
+ return;
+ }
+}
+
+
+/*
+ * rfbProcessClientProtocolVersion is called when the client sends its
+ * protocol version.
+ */
+
+static void
+rfbProcessClientProtocolVersion(cl)
+ rfbClientPtr cl;
+{
+ rfbProtocolVersionMsg pv;
+ int n, major_, minor_;
+ char failureReason[256];
+
+ if ((n = ReadExact(cl, pv, sz_rfbProtocolVersionMsg)) <= 0) {
+ if (n == 0)
+ rfbLog("rfbProcessClientProtocolVersion: client gone\n");
+ else
+ rfbLogPerror("rfbProcessClientProtocolVersion: read");
+ rfbCloseClient(cl);
+ return;
+ }
+
+ pv[sz_rfbProtocolVersionMsg] = 0;
+ if (sscanf(pv,rfbProtocolVersionFormat,&major_,&minor_) != 2) {
+ char name[1024];
+ if(sscanf(pv,"RFB %03d.%03d %1024s\n",&major_,&minor_,name) != 3) {
+ rfbErr("rfbProcessClientProtocolVersion: not a valid RFB client\n");
+ rfbCloseClient(cl);
+ return;
+ }
+ free(cl->host);
+ cl->host=strdup(name);
+ }
+ rfbLog("Protocol version %d.%d\n", major_, minor_);
+
+ if (major_ != rfbProtocolMajorVersion) {
+ /* Major version mismatch - send a ConnFailed message */
+
+ rfbErr("Major version mismatch\n");
+ sprintf(failureReason,
+ "RFB protocol version mismatch - server %d.%d, client %d.%d",
+ rfbProtocolMajorVersion,rfbProtocolMinorVersion,major_,minor_);
+ rfbClientConnFailed(cl, failureReason);
+ return;
+ }
+
+ if (minor_ != rfbProtocolMinorVersion) {
+ /* Minor version mismatch - warn but try to continue */
+ rfbLog("Ignoring minor version mismatch\n");
+ }
+
+ rfbAuthNewClient(cl);
+}
+
+
+/*
+ * rfbClientConnFailed is called when a client connection has failed either
+ * because it talks the wrong protocol or it has failed authentication.
+ */
+
+void
+rfbClientConnFailed(cl, reason)
+ rfbClientPtr cl;
+ char *reason;
+{
+ char *buf;
+ int len = strlen(reason);
+
+ buf = (char *)malloc(8 + len);
+ ((uint32_t *)buf)[0] = Swap32IfLE(rfbConnFailed);
+ ((uint32_t *)buf)[1] = Swap32IfLE(len);
+ memcpy(buf + 8, reason, len);
+
+ if (WriteExact(cl, buf, 8 + len) < 0)
+ rfbLogPerror("rfbClientConnFailed: write");
+ free(buf);
+ rfbCloseClient(cl);
+}
+
+
+/*
+ * rfbProcessClientInitMessage is called when the client sends its
+ * initialisation message.
+ */
+
+static void
+rfbProcessClientInitMessage(cl)
+ rfbClientPtr cl;
+{
+ rfbClientInitMsg ci;
+ char buf[256];
+ rfbServerInitMsg *si = (rfbServerInitMsg *)buf;
+ int len, n;
+ rfbClientIteratorPtr iterator;
+ rfbClientPtr otherCl;
+
+ if ((n = ReadExact(cl, (char *)&ci,sz_rfbClientInitMsg)) <= 0) {
+ if (n == 0)
+ rfbLog("rfbProcessClientInitMessage: client gone\n");
+ else
+ rfbLogPerror("rfbProcessClientInitMessage: read");
+ rfbCloseClient(cl);
+ return;
+ }
+
+ si->framebufferWidth = Swap16IfLE(cl->screen->width);
+ si->framebufferHeight = Swap16IfLE(cl->screen->height);
+ si->format = cl->screen->rfbServerFormat;
+ si->format.redMax = Swap16IfLE(si->format.redMax);
+ si->format.greenMax = Swap16IfLE(si->format.greenMax);
+ si->format.blueMax = Swap16IfLE(si->format.blueMax);
+
+ if (strlen(cl->screen->desktopName) > 128) /* sanity check on desktop name len */
+ ((char*)cl->screen->desktopName)[128] = 0;
+
+ strcpy(buf + sz_rfbServerInitMsg, cl->screen->desktopName);
+ len = strlen(buf + sz_rfbServerInitMsg);
+ si->nameLength = Swap32IfLE(len);
+
+ if (WriteExact(cl, buf, sz_rfbServerInitMsg + len) < 0) {
+ rfbLogPerror("rfbProcessClientInitMessage: write");
+ rfbCloseClient(cl);
+ return;
+ }
+
+ cl->state = RFB_NORMAL;
+
+ if (!cl->reverseConnection &&
+ (cl->screen->rfbNeverShared || (!cl->screen->rfbAlwaysShared && !ci.shared))) {
+
+ if (cl->screen->rfbDontDisconnect) {
+ iterator = rfbGetClientIterator(cl->screen);
+ while ((otherCl = rfbClientIteratorNext(iterator)) != NULL) {
+ if ((otherCl != cl) && (otherCl->state == RFB_NORMAL)) {
+ rfbLog("-dontdisconnect: Not shared & existing client\n");
+ rfbLog(" refusing new client %s\n", cl->host);
+ rfbCloseClient(cl);
+ rfbReleaseClientIterator(iterator);
+ return;
+ }
+ }
+ rfbReleaseClientIterator(iterator);
+ } else {
+ iterator = rfbGetClientIterator(cl->screen);
+ while ((otherCl = rfbClientIteratorNext(iterator)) != NULL) {
+ if ((otherCl != cl) && (otherCl->state == RFB_NORMAL)) {
+ rfbLog("Not shared - closing connection to client %s\n",
+ otherCl->host);
+ rfbCloseClient(otherCl);
+ }
+ }
+ rfbReleaseClientIterator(iterator);
+ }
+ }
+}
+
+static rfbBool rectSwapIfLEAndClip(uint16_t* x,uint16_t* y,uint16_t* w,uint16_t* h,
+ rfbScreenInfoPtr screen)
+{
+ *x=Swap16IfLE(*x);
+ *y=Swap16IfLE(*y);
+ *w=Swap16IfLE(*w);
+ *h=Swap16IfLE(*h);
+ if(*w>screen->width-*x)
+ *w=screen->width-*x;
+ /* possible underflow */
+ if(*w>screen->width-*x)
+ return FALSE;
+ if(*h>screen->height-*y)
+ *h=screen->height-*y;
+ if(*h>screen->height-*y)
+ return FALSE;
+
+ return TRUE;
+}
+
+/*
+ * rfbProcessClientNormalMessage is called when the client has sent a normal
+ * protocol message.
+ */
+
+static void
+rfbProcessClientNormalMessage(cl)
+ rfbClientPtr cl;
+{
+ int n=0;
+ rfbClientToServerMsg msg;
+ char *str;
+
+ if ((n = ReadExact(cl, (char *)&msg, 1)) <= 0) {
+ if (n != 0)
+ rfbLogPerror("rfbProcessClientNormalMessage: read");
+ rfbCloseClient(cl);
+ return;
+ }
+
+ switch (msg.type) {
+
+ case rfbSetPixelFormat:
+
+ if ((n = ReadExact(cl, ((char *)&msg) + 1,
+ sz_rfbSetPixelFormatMsg - 1)) <= 0) {
+ if (n != 0)
+ rfbLogPerror("rfbProcessClientNormalMessage: read");
+ rfbCloseClient(cl);
+ return;
+ }
+
+ cl->format.bitsPerPixel = msg.spf.format.bitsPerPixel;
+ cl->format.depth = msg.spf.format.depth;
+ cl->format.bigEndian = (msg.spf.format.bigEndian ? TRUE : FALSE);
+ cl->format.trueColour = (msg.spf.format.trueColour ? TRUE : FALSE);
+ cl->format.redMax = Swap16IfLE(msg.spf.format.redMax);
+ cl->format.greenMax = Swap16IfLE(msg.spf.format.greenMax);
+ cl->format.blueMax = Swap16IfLE(msg.spf.format.blueMax);
+ cl->format.redShift = msg.spf.format.redShift;
+ cl->format.greenShift = msg.spf.format.greenShift;
+ cl->format.blueShift = msg.spf.format.blueShift;
+
+ cl->readyForSetColourMapEntries = TRUE;
+ cl->screen->setTranslateFunction(cl);
+
+ return;
+
+
+ case rfbFixColourMapEntries:
+ if ((n = ReadExact(cl, ((char *)&msg) + 1,
+ sz_rfbFixColourMapEntriesMsg - 1)) <= 0) {
+ if (n != 0)
+ rfbLogPerror("rfbProcessClientNormalMessage: read");
+ rfbCloseClient(cl);
+ return;
+ }
+ rfbLog("rfbProcessClientNormalMessage: %s",
+ "FixColourMapEntries unsupported\n");
+ rfbCloseClient(cl);
+ return;
+
+
+ case rfbSetEncodings:
+ {
+ int i;
+ uint32_t enc;
+
+ if ((n = ReadExact(cl, ((char *)&msg) + 1,
+ sz_rfbSetEncodingsMsg - 1)) <= 0) {
+ if (n != 0)
+ rfbLogPerror("rfbProcessClientNormalMessage: read");
+ rfbCloseClient(cl);
+ return;
+ }
+
+ msg.se.nEncodings = Swap16IfLE(msg.se.nEncodings);
+
+ cl->preferredEncoding = -1;
+ cl->useCopyRect = FALSE;
+ cl->enableCursorShapeUpdates = FALSE;
+ cl->enableCursorPosUpdates = FALSE;
+ cl->enableLastRectEncoding = FALSE;
+ cl->useNewFBSize = FALSE;
+
+ for (i = 0; i < msg.se.nEncodings; i++) {
+ if ((n = ReadExact(cl, (char *)&enc, 4)) <= 0) {
+ if (n != 0)
+ rfbLogPerror("rfbProcessClientNormalMessage: read");
+ rfbCloseClient(cl);
+ return;
+ }
+ enc = Swap32IfLE(enc);
+
+ switch (enc) {
+
+ case rfbEncodingCopyRect:
+ cl->useCopyRect = TRUE;
+ break;
+ case rfbEncodingRaw:
+ if (cl->preferredEncoding == -1) {
+ cl->preferredEncoding = enc;
+ rfbLog("Using raw encoding for client %s\n",
+ cl->host);
+ }
+ break;
+ case rfbEncodingRRE:
+ if (cl->preferredEncoding == -1) {
+ cl->preferredEncoding = enc;
+ rfbLog("Using rre encoding for client %s\n",
+ cl->host);
+ }
+ break;
+ case rfbEncodingCoRRE:
+ if (cl->preferredEncoding == -1) {
+ cl->preferredEncoding = enc;
+ rfbLog("Using CoRRE encoding for client %s\n",
+ cl->host);
+ }
+ break;
+ case rfbEncodingHextile:
+ if (cl->preferredEncoding == -1) {
+ cl->preferredEncoding = enc;
+ rfbLog("Using hextile encoding for client %s\n",
+ cl->host);
+ }
+ break;
+#ifdef LIBVNCSERVER_HAVE_LIBZ
+ case rfbEncodingZlib:
+ if (cl->preferredEncoding == -1) {
+ cl->preferredEncoding = enc;
+ rfbLog("Using zlib encoding for client %s\n",
+ cl->host);
+ }
+ break;
+#ifdef LIBVNCSERVER_HAVE_LIBJPEG
+ case rfbEncodingTight:
+ if (cl->preferredEncoding == -1) {
+ cl->preferredEncoding = enc;
+ rfbLog("Using tight encoding for client %s\n",
+ cl->host);
+ }
+ break;
+#endif
+#endif
+ case rfbEncodingXCursor:
+ if(!cl->screen->dontConvertRichCursorToXCursor) {
+ rfbLog("Enabling X-style cursor updates for client %s\n",
+ cl->host);
+ cl->enableCursorShapeUpdates = TRUE;
+ cl->cursorWasChanged = TRUE;
+ }
+ break;
+ case rfbEncodingRichCursor:
+ rfbLog("Enabling full-color cursor updates for client %s\n",
+ cl->host);
+ cl->enableCursorShapeUpdates = TRUE;
+ cl->useRichCursorEncoding = TRUE;
+ cl->cursorWasChanged = TRUE;
+ break;
+ case rfbEncodingPointerPos:
+ if (!cl->enableCursorPosUpdates) {
+ rfbLog("Enabling cursor position updates for client %s\n",
+ cl->host);
+ cl->enableCursorPosUpdates = TRUE;
+ cl->cursorWasMoved = TRUE;
+ }
+ break;
+ case rfbEncodingLastRect:
+ if (!cl->enableLastRectEncoding) {
+ rfbLog("Enabling LastRect protocol extension for client "
+ "%s\n", cl->host);
+ cl->enableLastRectEncoding = TRUE;
+ }
+ break;
+ case rfbEncodingNewFBSize:
+ if (!cl->useNewFBSize) {
+ rfbLog("Enabling NewFBSize protocol extension for client "
+ "%s\n", cl->host);
+ cl->useNewFBSize = TRUE;
+ }
+ break;
+#ifdef LIBVNCSERVER_BACKCHANNEL
+ case rfbEncodingBackChannel:
+ if (!cl->enableBackChannel) {
+ rfbLog("Enabling BackChannel protocol extension for "
+ "client %s\n", cl->host);
+ cl->enableBackChannel = TRUE;
+ }
+ break;
+#endif
+#ifdef LIBVNCSERVER_HAVE_LIBZ
+ case rfbEncodingZRLE:
+ if (cl->preferredEncoding == -1) {
+ cl->preferredEncoding = enc;
+ rfbLog("Using ZRLE encoding for client %s\n",
+ cl->host);
+ }
+ break;
+#endif
+ default:
+#ifdef LIBVNCSERVER_HAVE_LIBZ
+ if ( enc >= (uint32_t)rfbEncodingCompressLevel0 &&
+ enc <= (uint32_t)rfbEncodingCompressLevel9 ) {
+ cl->zlibCompressLevel = enc & 0x0F;
+#ifdef LIBVNCSERVER_HAVE_LIBJPEG
+ cl->tightCompressLevel = enc & 0x0F;
+ rfbLog("Using compression level %d for client %s\n",
+ cl->tightCompressLevel, cl->host);
+ } else if ( enc >= (uint32_t)rfbEncodingQualityLevel0 &&
+ enc <= (uint32_t)rfbEncodingQualityLevel9 ) {
+ cl->tightQualityLevel = enc & 0x0F;
+ rfbLog("Using image quality level %d for client %s\n",
+ cl->tightQualityLevel, cl->host);
+#endif
+ } else
+#endif
+ rfbLog("rfbProcessClientNormalMessage: ignoring unknown "
+ "encoding type %d\n", (int)enc);
+ }
+ }
+
+ if (cl->preferredEncoding == -1) {
+ cl->preferredEncoding = rfbEncodingRaw;
+ }
+
+ if (cl->enableCursorPosUpdates && !cl->enableCursorShapeUpdates) {
+ rfbLog("Disabling cursor position updates for client %s\n",
+ cl->host);
+ cl->enableCursorPosUpdates = FALSE;
+ }
+
+ return;
+ }
+
+
+ case rfbFramebufferUpdateRequest:
+ {
+ sraRegionPtr tmpRegion;
+
+ if ((n = ReadExact(cl, ((char *)&msg) + 1,
+ sz_rfbFramebufferUpdateRequestMsg-1)) <= 0) {
+ if (n != 0)
+ rfbLogPerror("rfbProcessClientNormalMessage: read");
+ rfbCloseClient(cl);
+ return;
+ }
+
+ if(!rectSwapIfLEAndClip(&msg.fur.x,&msg.fur.y,&msg.fur.w,&msg.fur.h,
+ cl->screen))
+ return;
+
+ tmpRegion =
+ sraRgnCreateRect(msg.fur.x,
+ msg.fur.y,
+ msg.fur.x+msg.fur.w,
+ msg.fur.y+msg.fur.h);
+
+ LOCK(cl->updateMutex);
+ sraRgnOr(cl->requestedRegion,tmpRegion);
+
+ if (!cl->readyForSetColourMapEntries) {
+ /* client hasn't sent a SetPixelFormat so is using server's */
+ cl->readyForSetColourMapEntries = TRUE;
+ if (!cl->format.trueColour) {
+ if (!rfbSetClientColourMap(cl, 0, 0)) {
+ sraRgnDestroy(tmpRegion);
+ UNLOCK(cl->updateMutex);
+ return;
+ }
+ }
+ }
+
+ if (!msg.fur.incremental) {
+ sraRgnOr(cl->modifiedRegion,tmpRegion);
+ sraRgnSubtract(cl->copyRegion,tmpRegion);
+ }
+ TSIGNAL(cl->updateCond);
+ UNLOCK(cl->updateMutex);
+
+ sraRgnDestroy(tmpRegion);
+
+ return;
+ }
+
+ case rfbKeyEvent:
+
+ cl->rfbKeyEventsRcvd++;
+
+ if ((n = ReadExact(cl, ((char *)&msg) + 1,
+ sz_rfbKeyEventMsg - 1)) <= 0) {
+ if (n != 0)
+ rfbLogPerror("rfbProcessClientNormalMessage: read");
+ rfbCloseClient(cl);
+ return;
+ }
+
+ if(!cl->viewOnly) {
+ cl->screen->kbdAddEvent(msg.ke.down, (rfbKeySym)Swap32IfLE(msg.ke.key), cl);
+ }
+
+ return;
+
+
+ case rfbPointerEvent:
+
+ cl->rfbPointerEventsRcvd++;
+
+ if ((n = ReadExact(cl, ((char *)&msg) + 1,
+ sz_rfbPointerEventMsg - 1)) <= 0) {
+ if (n != 0)
+ rfbLogPerror("rfbProcessClientNormalMessage: read");
+ rfbCloseClient(cl);
+ return;
+ }
+
+ if (pointerClient && (pointerClient != cl))
+ return;
+
+ if (msg.pe.buttonMask == 0)
+ pointerClient = NULL;
+ else
+ pointerClient = cl;
+
+ if(!cl->viewOnly) {
+ cl->screen->ptrAddEvent(msg.pe.buttonMask,
+ Swap16IfLE(msg.pe.x), Swap16IfLE(msg.pe.y), cl);
+ }
+
+ return;
+
+
+ case rfbClientCutText:
+
+ if ((n = ReadExact(cl, ((char *)&msg) + 1,
+ sz_rfbClientCutTextMsg - 1)) <= 0) {
+ if (n != 0)
+ rfbLogPerror("rfbProcessClientNormalMessage: read");
+ rfbCloseClient(cl);
+ return;
+ }
+
+ if(!cl->viewOnly) {
+ msg.cct.length = Swap32IfLE(msg.cct.length);
+
+ str = (char *)malloc(msg.cct.length);
+
+ if ((n = ReadExact(cl, str, msg.cct.length)) <= 0) {
+ if (n != 0)
+ rfbLogPerror("rfbProcessClientNormalMessage: read");
+ free(str);
+ rfbCloseClient(cl);
+ return;
+ }
+
+ cl->screen->setXCutText(str, msg.cct.length, cl);
+ free(str);
+ }
+
+ return;
+
+
+ default:
+
+ rfbLog("rfbProcessClientNormalMessage: unknown message type %d\n",
+ msg.type);
+ rfbLog(" ... closing connection\n");
+ rfbCloseClient(cl);
+ return;
+ }
+}
+
+
+
+/*
+ * rfbSendFramebufferUpdate - send the currently pending framebuffer update to
+ * the RFB client.
+ * givenUpdateRegion is not changed.
+ */
+
+rfbBool
+rfbSendFramebufferUpdate(cl, givenUpdateRegion)
+ rfbClientPtr cl;
+ sraRegionPtr givenUpdateRegion;
+{
+ sraRectangleIterator* i;
+ sraRect rect;
+ int nUpdateRegionRects;
+ rfbFramebufferUpdateMsg *fu = (rfbFramebufferUpdateMsg *)cl->updateBuf;
+ sraRegionPtr updateRegion,updateCopyRegion,tmpRegion;
+ int dx, dy;
+ rfbBool sendCursorShape = FALSE;
+ rfbBool sendCursorPos = FALSE;
+
+ if(cl->screen->displayHook)
+ cl->screen->displayHook(cl);
+
+ /*
+ * If framebuffer size was changed and the client supports NewFBSize
+ * encoding, just send NewFBSize marker and return.
+ */
+
+ if (cl->useNewFBSize && cl->newFBSizePending) {
+ LOCK(cl->updateMutex);
+ cl->newFBSizePending = FALSE;
+ UNLOCK(cl->updateMutex);
+ cl->rfbFramebufferUpdateMessagesSent++;
+ fu->type = rfbFramebufferUpdate;
+ fu->nRects = Swap16IfLE(1);
+ cl->ublen = sz_rfbFramebufferUpdateMsg;
+ if (!rfbSendNewFBSize(cl, cl->screen->width, cl->screen->height)) {
+ return FALSE;
+ }
+ return rfbSendUpdateBuf(cl);
+ }
+
+ /*
+ * If this client understands cursor shape updates, cursor should be
+ * removed from the framebuffer. Otherwise, make sure it's put up.
+ */
+
+ if (cl->enableCursorShapeUpdates) {
+ if (cl->screen->cursorIsDrawn) {
+ rfbUndrawCursor(cl->screen);
+ }
+ if (!cl->screen->cursorIsDrawn && cl->cursorWasChanged &&
+ cl->readyForSetColourMapEntries)
+ sendCursorShape = TRUE;
+ } else {
+ if (!cl->screen->cursorIsDrawn) {
+ rfbDrawCursor(cl->screen);
+ }
+ }
+
+ /*
+ * Do we plan to send cursor position update?
+ */
+
+ if (cl->enableCursorPosUpdates && cl->cursorWasMoved)
+ sendCursorPos = TRUE;
+
+ LOCK(cl->updateMutex);
+
+ /*
+ * The modifiedRegion may overlap the destination copyRegion. We remove
+ * any overlapping bits from the copyRegion (since they'd only be
+ * overwritten anyway).
+ */
+
+ sraRgnSubtract(cl->copyRegion,cl->modifiedRegion);
+
+ /*
+ * The client is interested in the region requestedRegion. The region
+ * which should be updated now is the intersection of requestedRegion
+ * and the union of modifiedRegion and copyRegion. If it's empty then
+ * no update is needed.
+ */
+
+ updateRegion = sraRgnCreateRgn(givenUpdateRegion);
+ if(cl->screen->progressiveSliceHeight>0) {
+ int height=cl->screen->progressiveSliceHeight,
+ y=cl->progressiveSliceY;
+ sraRegionPtr bbox=sraRgnBBox(updateRegion);
+ sraRect rect;
+ if(sraRgnPopRect(bbox,&rect,0)) {
+ sraRegionPtr slice;
+ if(y<rect.y1 || y>=rect.y2)
+ y=rect.y1;
+ slice=sraRgnCreateRect(0,y,cl->screen->width,y+height);
+ sraRgnAnd(updateRegion,slice);
+ sraRgnDestroy(slice);
+ }
+ sraRgnDestroy(bbox);
+ y+=height;
+ if(y>=cl->screen->height)
+ y=0;
+ cl->progressiveSliceY=y;
+ }
+
+ sraRgnOr(updateRegion,cl->copyRegion);
+ if(!sraRgnAnd(updateRegion,cl->requestedRegion) &&
+ !sendCursorShape && !sendCursorPos) {
+ sraRgnDestroy(updateRegion);
+ UNLOCK(cl->updateMutex);
+ return TRUE;
+ }
+
+ /*
+ * We assume that the client doesn't have any pixel data outside the
+ * requestedRegion. In other words, both the source and destination of a
+ * copy must lie within requestedRegion. So the region we can send as a
+ * copy is the intersection of the copyRegion with both the requestedRegion
+ * and the requestedRegion translated by the amount of the copy. We set
+ * updateCopyRegion to this.
+ */
+
+ updateCopyRegion = sraRgnCreateRgn(cl->copyRegion);
+ sraRgnAnd(updateCopyRegion,cl->requestedRegion);
+ tmpRegion = sraRgnCreateRgn(cl->requestedRegion);
+ sraRgnOffset(tmpRegion,cl->copyDX,cl->copyDY);
+ sraRgnAnd(updateCopyRegion,tmpRegion);
+ sraRgnDestroy(tmpRegion);
+ dx = cl->copyDX;
+ dy = cl->copyDY;
+
+ /*
+ * Next we remove updateCopyRegion from updateRegion so that updateRegion
+ * is the part of this update which is sent as ordinary pixel data (i.e not
+ * a copy).
+ */
+
+ sraRgnSubtract(updateRegion,updateCopyRegion);
+
+ /*
+ * Finally we leave modifiedRegion to be the remainder (if any) of parts of
+ * the screen which are modified but outside the requestedRegion. We also
+ * empty both the requestedRegion and the copyRegion - note that we never
+ * carry over a copyRegion for a future update.
+ */
+
+
+ sraRgnOr(cl->modifiedRegion,cl->copyRegion);
+ sraRgnSubtract(cl->modifiedRegion,updateRegion);
+ sraRgnSubtract(cl->modifiedRegion,updateCopyRegion);
+
+ sraRgnMakeEmpty(cl->requestedRegion);
+ sraRgnMakeEmpty(cl->copyRegion);
+ cl->copyDX = 0;
+ cl->copyDY = 0;
+
+ UNLOCK(cl->updateMutex);
+
+ /*
+ * Now send the update.
+ */
+
+ cl->rfbFramebufferUpdateMessagesSent++;
+
+ if (cl->preferredEncoding == rfbEncodingCoRRE) {
+ nUpdateRegionRects = 0;
+
+ for(i = sraRgnGetIterator(updateRegion); sraRgnIteratorNext(i,&rect);){
+ int x = rect.x1;
+ int y = rect.y1;
+ int w = rect.x2 - x;
+ int h = rect.y2 - y;
+ nUpdateRegionRects += (((w-1) / cl->correMaxWidth + 1)
+ * ((h-1) / cl->correMaxHeight + 1));
+ }
+ sraRgnReleaseIterator(i);
+#ifdef LIBVNCSERVER_HAVE_LIBZ
+ } else if (cl->preferredEncoding == rfbEncodingZlib) {
+ nUpdateRegionRects = 0;
+
+ for(i = sraRgnGetIterator(updateRegion); sraRgnIteratorNext(i,&rect);){
+ int x = rect.x1;
+ int y = rect.y1;
+ int w = rect.x2 - x;
+ int h = rect.y2 - y;
+ nUpdateRegionRects += (((h-1) / (ZLIB_MAX_SIZE( w ) / w)) + 1);
+ }
+ sraRgnReleaseIterator(i);
+#ifdef LIBVNCSERVER_HAVE_LIBJPEG
+ } else if (cl->preferredEncoding == rfbEncodingTight) {
+ nUpdateRegionRects = 0;
+
+ for(i = sraRgnGetIterator(updateRegion); sraRgnIteratorNext(i,&rect);){
+ int x = rect.x1;
+ int y = rect.y1;
+ int w = rect.x2 - x;
+ int h = rect.y2 - y;
+ int n = rfbNumCodedRectsTight(cl, x, y, w, h);
+ if (n == 0) {
+ nUpdateRegionRects = 0xFFFF;
+ break;
+ }
+ nUpdateRegionRects += n;
+ }
+ sraRgnReleaseIterator(i);
+#endif
+#endif
+ } else {
+ nUpdateRegionRects = sraRgnCountRects(updateRegion);
+ }
+
+ fu->type = rfbFramebufferUpdate;
+ if (nUpdateRegionRects != 0xFFFF) {
+ if(cl->screen->maxRectsPerUpdate>0
+#ifdef LIBVNCSERVER_HAVE_LIBJPEG
+ /* Tight encoding counts the rectangles differently */
+ && cl->preferredEncoding != rfbEncodingTight
+#endif
+ && nUpdateRegionRects>cl->screen->maxRectsPerUpdate) {
+ sraRegion* newUpdateRegion = sraRgnBBox(updateRegion);
+ sraRgnDestroy(updateRegion);
+ updateRegion = newUpdateRegion;
+ nUpdateRegionRects = sraRgnCountRects(updateRegion);
+ }
+ fu->nRects = Swap16IfLE((uint16_t)(sraRgnCountRects(updateCopyRegion) +
+ nUpdateRegionRects +
+ !!sendCursorShape + !!sendCursorPos));
+ } else {
+ fu->nRects = 0xFFFF;
+ }
+ cl->ublen = sz_rfbFramebufferUpdateMsg;
+
+ if (sendCursorShape) {
+ cl->cursorWasChanged = FALSE;
+ if (!rfbSendCursorShape(cl)) {
+ sraRgnDestroy(updateRegion);
+ return FALSE;
+ }
+ }
+
+ if (sendCursorPos) {
+ cl->cursorWasMoved = FALSE;
+ if (!rfbSendCursorPos(cl)) {
+ sraRgnDestroy(updateRegion);
+ return FALSE;
+ }
+ }
+
+ if (!sraRgnEmpty(updateCopyRegion)) {
+ if (!rfbSendCopyRegion(cl,updateCopyRegion,dx,dy)) {
+ sraRgnDestroy(updateRegion);
+ sraRgnDestroy(updateCopyRegion);
+ return FALSE;
+ }
+ }
+
+ sraRgnDestroy(updateCopyRegion);
+
+ for(i = sraRgnGetIterator(updateRegion); sraRgnIteratorNext(i,&rect);){
+ int x = rect.x1;
+ int y = rect.y1;
+ int w = rect.x2 - x;
+ int h = rect.y2 - y;
+
+ cl->rfbRawBytesEquivalent += (sz_rfbFramebufferUpdateRectHeader
+ + w * (cl->format.bitsPerPixel / 8) * h);
+
+ switch (cl->preferredEncoding) {
+ case rfbEncodingRaw:
+ if (!rfbSendRectEncodingRaw(cl, x, y, w, h)) {
+ sraRgnDestroy(updateRegion);
+ sraRgnReleaseIterator(i);
+ return FALSE;
+ }
+ break;
+ case rfbEncodingRRE:
+ if (!rfbSendRectEncodingRRE(cl, x, y, w, h)) {
+ sraRgnDestroy(updateRegion);
+ sraRgnReleaseIterator(i);
+ return FALSE;
+ }
+ break;
+ case rfbEncodingCoRRE:
+ if (!rfbSendRectEncodingCoRRE(cl, x, y, w, h)) {
+ sraRgnDestroy(updateRegion);
+ sraRgnReleaseIterator(i);
+ return FALSE;
+ }
+ break;
+ case rfbEncodingHextile:
+ if (!rfbSendRectEncodingHextile(cl, x, y, w, h)) {
+ sraRgnDestroy(updateRegion);
+ sraRgnReleaseIterator(i);
+ return FALSE;
+ }
+ break;
+#ifdef LIBVNCSERVER_HAVE_LIBZ
+ case rfbEncodingZlib:
+ if (!rfbSendRectEncodingZlib(cl, x, y, w, h)) {
+ sraRgnDestroy(updateRegion);
+ sraRgnReleaseIterator(i);
+ return FALSE;
+ }
+ break;
+#ifdef LIBVNCSERVER_HAVE_LIBJPEG
+ case rfbEncodingTight:
+ if (!rfbSendRectEncodingTight(cl, x, y, w, h)) {
+ sraRgnDestroy(updateRegion);
+ sraRgnReleaseIterator(i);
+ return FALSE;
+ }
+ break;
+#endif
+#endif
+#ifdef LIBVNCSERVER_HAVE_LIBZ
+ case rfbEncodingZRLE:
+ if (!rfbSendRectEncodingZRLE(cl, x, y, w, h)) {
+ sraRgnDestroy(updateRegion);
+ sraRgnReleaseIterator(i);
+ return FALSE;
+ }
+ break;
+#endif
+ }
+ }
+ sraRgnReleaseIterator(i);
+
+ if ( nUpdateRegionRects == 0xFFFF &&
+ !rfbSendLastRectMarker(cl) ) {
+ sraRgnDestroy(updateRegion);
+ return FALSE;
+ }
+
+ if (!rfbSendUpdateBuf(cl)) {
+ sraRgnDestroy(updateRegion);
+ return FALSE;
+ }
+
+ sraRgnDestroy(updateRegion);
+ return TRUE;
+}
+
+
+/*
+ * Send the copy region as a string of CopyRect encoded rectangles.
+ * The only slightly tricky thing is that we should send the messages in
+ * the correct order so that an earlier CopyRect will not corrupt the source
+ * of a later one.
+ */
+
+rfbBool
+rfbSendCopyRegion(cl, reg, dx, dy)
+ rfbClientPtr cl;
+ sraRegionPtr reg;
+ int dx, dy;
+{
+ int x, y, w, h;
+ rfbFramebufferUpdateRectHeader rect;
+ rfbCopyRect cr;
+ sraRectangleIterator* i;
+ sraRect rect1;
+
+ /* printf("copyrect: "); sraRgnPrint(reg); putchar('\n');fflush(stdout); */
+ i = sraRgnGetReverseIterator(reg,dx>0,dy>0);
+
+ while(sraRgnIteratorNext(i,&rect1)) {
+ x = rect1.x1;
+ y = rect1.y1;
+ w = rect1.x2 - x;
+ h = rect1.y2 - y;
+
+ rect.r.x = Swap16IfLE(x);
+ rect.r.y = Swap16IfLE(y);
+ rect.r.w = Swap16IfLE(w);
+ rect.r.h = Swap16IfLE(h);
+ rect.encoding = Swap32IfLE(rfbEncodingCopyRect);
+
+ memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
+ sz_rfbFramebufferUpdateRectHeader);
+ cl->ublen += sz_rfbFramebufferUpdateRectHeader;
+
+ cr.srcX = Swap16IfLE(x - dx);
+ cr.srcY = Swap16IfLE(y - dy);
+
+ memcpy(&cl->updateBuf[cl->ublen], (char *)&cr, sz_rfbCopyRect);
+ cl->ublen += sz_rfbCopyRect;
+
+ cl->rfbRectanglesSent[rfbEncodingCopyRect]++;
+ cl->rfbBytesSent[rfbEncodingCopyRect]
+ += sz_rfbFramebufferUpdateRectHeader + sz_rfbCopyRect;
+
+ }
+
+ return TRUE;
+}
+
+/*
+ * Send a given rectangle in raw encoding (rfbEncodingRaw).
+ */
+
+rfbBool
+rfbSendRectEncodingRaw(cl, x, y, w, h)
+ rfbClientPtr cl;
+ int x, y, w, h;
+{
+ rfbFramebufferUpdateRectHeader rect;
+ int nlines;
+ int bytesPerLine = w * (cl->format.bitsPerPixel / 8);
+ char *fbptr = (cl->screen->frameBuffer + (cl->screen->paddedWidthInBytes * y)
+ + (x * (cl->screen->bitsPerPixel / 8)));
+
+ /* Flush the buffer to guarantee correct alignment for translateFn(). */
+ if (cl->ublen > 0) {
+ if (!rfbSendUpdateBuf(cl))
+ return FALSE;
+ }
+
+ rect.r.x = Swap16IfLE(x);
+ rect.r.y = Swap16IfLE(y);
+ rect.r.w = Swap16IfLE(w);
+ rect.r.h = Swap16IfLE(h);
+ rect.encoding = Swap32IfLE(rfbEncodingRaw);
+
+ memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,sz_rfbFramebufferUpdateRectHeader);
+ cl->ublen += sz_rfbFramebufferUpdateRectHeader;
+
+ cl->rfbRectanglesSent[rfbEncodingRaw]++;
+ cl->rfbBytesSent[rfbEncodingRaw]
+ += sz_rfbFramebufferUpdateRectHeader + bytesPerLine * h;
+
+ nlines = (UPDATE_BUF_SIZE - cl->ublen) / bytesPerLine;
+
+ while (TRUE) {
+ if (nlines > h)
+ nlines = h;
+
+ (*cl->translateFn)(cl->translateLookupTable,
+ &(cl->screen->rfbServerFormat),
+ &cl->format, fbptr, &cl->updateBuf[cl->ublen],
+ cl->screen->paddedWidthInBytes, w, nlines);
+
+ cl->ublen += nlines * bytesPerLine;
+ h -= nlines;
+
+ if (h == 0) /* rect fitted in buffer, do next one */
+ return TRUE;
+
+ /* buffer full - flush partial rect and do another nlines */
+
+ if (!rfbSendUpdateBuf(cl))
+ return FALSE;
+
+ fbptr += (cl->screen->paddedWidthInBytes * nlines);
+
+ nlines = (UPDATE_BUF_SIZE - cl->ublen) / bytesPerLine;
+ if (nlines == 0) {
+ rfbErr("rfbSendRectEncodingRaw: send buffer too small for %d "
+ "bytes per line\n", bytesPerLine);
+ rfbCloseClient(cl);
+ return FALSE;
+ }
+ }
+}
+
+
+
+/*
+ * Send an empty rectangle with encoding field set to value of
+ * rfbEncodingLastRect to notify client that this is the last
+ * rectangle in framebuffer update ("LastRect" extension of RFB
+ * protocol).
+ */
+
+rfbBool
+rfbSendLastRectMarker(cl)
+ rfbClientPtr cl;
+{
+ rfbFramebufferUpdateRectHeader rect;
+
+ if (cl->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) {
+ if (!rfbSendUpdateBuf(cl))
+ return FALSE;
+ }
+
+ rect.encoding = Swap32IfLE(rfbEncodingLastRect);
+ rect.r.x = 0;
+ rect.r.y = 0;
+ rect.r.w = 0;
+ rect.r.h = 0;
+
+ memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,sz_rfbFramebufferUpdateRectHeader);
+ cl->ublen += sz_rfbFramebufferUpdateRectHeader;
+
+ cl->rfbLastRectMarkersSent++;
+ cl->rfbLastRectBytesSent += sz_rfbFramebufferUpdateRectHeader;
+
+ return TRUE;
+}
+
+
+/*
+ * Send NewFBSize pseudo-rectangle. This tells the client to change
+ * its framebuffer size.
+ */
+
+rfbBool
+rfbSendNewFBSize(cl, w, h)
+ rfbClientPtr cl;
+ int w, h;
+{
+ rfbFramebufferUpdateRectHeader rect;
+
+ if (cl->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) {
+ if (!rfbSendUpdateBuf(cl))
+ return FALSE;
+ }
+
+ rect.encoding = Swap32IfLE(rfbEncodingNewFBSize);
+ rect.r.x = 0;
+ rect.r.y = 0;
+ rect.r.w = Swap16IfLE(w);
+ rect.r.h = Swap16IfLE(h);
+
+ memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
+ sz_rfbFramebufferUpdateRectHeader);
+ cl->ublen += sz_rfbFramebufferUpdateRectHeader;
+
+ cl->rfbLastRectMarkersSent++;
+ cl->rfbLastRectBytesSent += sz_rfbFramebufferUpdateRectHeader;
+
+ return TRUE;
+}
+
+
+/*
+ * Send the contents of cl->updateBuf. Returns 1 if successful, -1 if
+ * not (errno should be set).
+ */
+
+rfbBool
+rfbSendUpdateBuf(cl)
+ rfbClientPtr cl;
+{
+ if(cl->sock<0)
+ return FALSE;
+
+ if (WriteExact(cl, cl->updateBuf, cl->ublen) < 0) {
+ rfbLogPerror("rfbSendUpdateBuf: write");
+ rfbCloseClient(cl);
+ return FALSE;
+ }
+
+ cl->ublen = 0;
+ return TRUE;
+}
+
+/*
+ * rfbSendSetColourMapEntries sends a SetColourMapEntries message to the
+ * client, using values from the currently installed colormap.
+ */
+
+rfbBool
+rfbSendSetColourMapEntries(cl, firstColour, nColours)
+ rfbClientPtr cl;
+ int firstColour;
+ int nColours;
+{
+ char buf[sz_rfbSetColourMapEntriesMsg + 256 * 3 * 2];
+ rfbSetColourMapEntriesMsg *scme = (rfbSetColourMapEntriesMsg *)buf;
+ uint16_t *rgb = (uint16_t *)(&buf[sz_rfbSetColourMapEntriesMsg]);
+ rfbColourMap* cm = &cl->screen->colourMap;
+
+ int i, len;
+
+ scme->type = rfbSetColourMapEntries;
+
+ scme->firstColour = Swap16IfLE(firstColour);
+ scme->nColours = Swap16IfLE(nColours);
+
+ len = sz_rfbSetColourMapEntriesMsg;
+
+ for (i = 0; i < nColours; i++) {
+ if(i<(int)cm->count) {
+ if(cm->is16) {
+ rgb[i*3] = Swap16IfLE(cm->data.shorts[i*3]);
+ rgb[i*3+1] = Swap16IfLE(cm->data.shorts[i*3+1]);
+ rgb[i*3+2] = Swap16IfLE(cm->data.shorts[i*3+2]);
+ } else {
+ rgb[i*3] = Swap16IfLE(cm->data.bytes[i*3]);
+ rgb[i*3+1] = Swap16IfLE(cm->data.bytes[i*3+1]);
+ rgb[i*3+2] = Swap16IfLE(cm->data.bytes[i*3+2]);
+ }
+ }
+ }
+
+ len += nColours * 3 * 2;
+
+ if (WriteExact(cl, buf, len) < 0) {
+ rfbLogPerror("rfbSendSetColourMapEntries: write");
+ rfbCloseClient(cl);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*
+ * rfbSendBell sends a Bell message to all the clients.
+ */
+
+void
+rfbSendBell(rfbScreenInfoPtr rfbScreen)
+{
+ rfbClientIteratorPtr i;
+ rfbClientPtr cl;
+ rfbBellMsg b;
+
+ i = rfbGetClientIterator(rfbScreen);
+ while((cl=rfbClientIteratorNext(i))) {
+ b.type = rfbBell;
+ if (WriteExact(cl, (char *)&b, sz_rfbBellMsg) < 0) {
+ rfbLogPerror("rfbSendBell: write");
+ rfbCloseClient(cl);
+ }
+ }
+ rfbReleaseClientIterator(i);
+}
+
+
+/*
+ * rfbSendServerCutText sends a ServerCutText message to all the clients.
+ */
+
+void
+rfbSendServerCutText(rfbScreenInfoPtr rfbScreen,char *str, int len)
+{
+ rfbClientPtr cl;
+ rfbServerCutTextMsg sct;
+ rfbClientIteratorPtr iterator;
+
+ iterator = rfbGetClientIterator(rfbScreen);
+ while ((cl = rfbClientIteratorNext(iterator)) != NULL) {
+ sct.type = rfbServerCutText;
+ sct.length = Swap32IfLE(len);
+ if (WriteExact(cl, (char *)&sct,
+ sz_rfbServerCutTextMsg) < 0) {
+ rfbLogPerror("rfbSendServerCutText: write");
+ rfbCloseClient(cl);
+ continue;
+ }
+ if (WriteExact(cl, str, len) < 0) {
+ rfbLogPerror("rfbSendServerCutText: write");
+ rfbCloseClient(cl);
+ }
+ }
+ rfbReleaseClientIterator(iterator);
+}
+
+/*****************************************************************************
+ *
+ * UDP can be used for keyboard and pointer events when the underlying
+ * network is highly reliable. This is really here to support ORL's
+ * videotile, whose TCP implementation doesn't like sending lots of small
+ * packets (such as 100s of pen readings per second!).
+ */
+
+unsigned char ptrAcceleration = 50;
+
+void
+rfbNewUDPConnection(rfbScreen,sock)
+ rfbScreenInfoPtr rfbScreen;
+ int sock;
+{
+ if (write(sock, &ptrAcceleration, 1) < 0) {
+ rfbLogPerror("rfbNewUDPConnection: write");
+ }
+}
+
+/*
+ * Because UDP is a message based service, we can't read the first byte and
+ * then the rest of the packet separately like we do with TCP. We will always
+ * get a whole packet delivered in one go, so we ask read() for the maximum
+ * number of bytes we can possibly get.
+ */
+
+void
+rfbProcessUDPInput(rfbScreenInfoPtr rfbScreen)
+{
+ int n;
+ rfbClientPtr cl=rfbScreen->udpClient;
+ rfbClientToServerMsg msg;
+
+ if((!cl) || cl->onHold)
+ return;
+
+ if ((n = read(rfbScreen->udpSock, (char *)&msg, sizeof(msg))) <= 0) {
+ if (n < 0) {
+ rfbLogPerror("rfbProcessUDPInput: read");
+ }
+ rfbDisconnectUDPSock(rfbScreen);
+ return;
+ }
+
+ switch (msg.type) {
+
+ case rfbKeyEvent:
+ if (n != sz_rfbKeyEventMsg) {
+ rfbErr("rfbProcessUDPInput: key event incorrect length\n");
+ rfbDisconnectUDPSock(rfbScreen);
+ return;
+ }
+ cl->screen->kbdAddEvent(msg.ke.down, (rfbKeySym)Swap32IfLE(msg.ke.key), cl);
+ break;
+
+ case rfbPointerEvent:
+ if (n != sz_rfbPointerEventMsg) {
+ rfbErr("rfbProcessUDPInput: ptr event incorrect length\n");
+ rfbDisconnectUDPSock(rfbScreen);
+ return;
+ }
+ cl->screen->ptrAddEvent(msg.pe.buttonMask,
+ Swap16IfLE(msg.pe.x), Swap16IfLE(msg.pe.y), cl);
+ break;
+
+ default:
+ rfbErr("rfbProcessUDPInput: unknown message type %d\n",
+ msg.type);
+ rfbDisconnectUDPSock(rfbScreen);
+ }
+}
+
+#ifdef LIBVNCSERVER_BACKCHANNEL
+void rfbSendBackChannel(rfbScreenInfoPtr rfbScreen,char* str,int len)
+{
+ rfbClientPtr cl;
+ rfbBackChannelMsg sct;
+ rfbClientIteratorPtr iterator;
+
+ iterator = rfbGetClientIterator(rfbScreen);
+ while ((cl = rfbClientIteratorNext(iterator)) != NULL) {
+ if (cl->enableBackChannel) {
+ sct.type = rfbBackChannel;
+ sct.length = Swap32IfLE(len);
+ if (WriteExact(cl, (char *)&sct,
+ sz_rfbBackChannelMsg) < 0) {
+ rfbLogPerror("rfbSendBackChannel: write");
+ rfbCloseClient(cl);
+ continue;
+ }
+ if (WriteExact(cl, str, len) < 0) {
+ rfbLogPerror("rfbSendBackChannel: write");
+ rfbCloseClient(cl);
+ }
+ }
+ }
+ rfbReleaseClientIterator(iterator);
+}
+#endif
diff --git a/libvncserver/rre.c b/libvncserver/rre.c
new file mode 100755
index 0000000..3e00c05
--- /dev/null
+++ b/libvncserver/rre.c
@@ -0,0 +1,321 @@
+/*
+ * rre.c
+ *
+ * Routines to implement Rise-and-Run-length Encoding (RRE). This
+ * code is based on krw's original javatel rfbserver.
+ */
+
+/*
+ * OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
+ * Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge.
+ * 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/rfb.h>
+
+/*
+ * rreBeforeBuf contains pixel data in the client's format.
+ * rreAfterBuf contains the RRE encoded version. If the RRE encoded version is
+ * larger than the raw data or if it exceeds rreAfterBufSize then
+ * raw encoding is used instead.
+ */
+
+static int rreBeforeBufSize = 0;
+static char *rreBeforeBuf = NULL;
+
+static int rreAfterBufSize = 0;
+static char *rreAfterBuf = NULL;
+static int rreAfterBufLen;
+
+static int subrectEncode8(uint8_t *data, int w, int h);
+static int subrectEncode16(uint16_t *data, int w, int h);
+static int subrectEncode32(uint32_t *data, int w, int h);
+static uint32_t getBgColour(char *data, int size, int bpp);
+
+
+/*
+ * rfbSendRectEncodingRRE - send a given rectangle using RRE encoding.
+ */
+
+rfbBool
+rfbSendRectEncodingRRE(cl, x, y, w, h)
+ rfbClientPtr cl;
+ int x, y, w, h;
+{
+ rfbFramebufferUpdateRectHeader rect;
+ rfbRREHeader hdr;
+ int nSubrects;
+ int i;
+ char *fbptr = (cl->screen->frameBuffer + (cl->screen->paddedWidthInBytes * y)
+ + (x * (cl->screen->bitsPerPixel / 8)));
+
+ int maxRawSize = (cl->screen->width * cl->screen->height
+ * (cl->format.bitsPerPixel / 8));
+
+ if (rreBeforeBufSize < maxRawSize) {
+ rreBeforeBufSize = maxRawSize;
+ if (rreBeforeBuf == NULL)
+ rreBeforeBuf = (char *)malloc(rreBeforeBufSize);
+ else
+ rreBeforeBuf = (char *)realloc(rreBeforeBuf, rreBeforeBufSize);
+ }
+
+ if (rreAfterBufSize < maxRawSize) {
+ rreAfterBufSize = maxRawSize;
+ if (rreAfterBuf == NULL)
+ rreAfterBuf = (char *)malloc(rreAfterBufSize);
+ else
+ rreAfterBuf = (char *)realloc(rreAfterBuf, rreAfterBufSize);
+ }
+
+ (*cl->translateFn)(cl->translateLookupTable,
+ &(cl->screen->rfbServerFormat),
+ &cl->format, fbptr, rreBeforeBuf,
+ cl->screen->paddedWidthInBytes, w, h);
+
+ switch (cl->format.bitsPerPixel) {
+ case 8:
+ nSubrects = subrectEncode8((uint8_t *)rreBeforeBuf, w, h);
+ break;
+ case 16:
+ nSubrects = subrectEncode16((uint16_t *)rreBeforeBuf, w, h);
+ break;
+ case 32:
+ nSubrects = subrectEncode32((uint32_t *)rreBeforeBuf, w, h);
+ break;
+ default:
+ rfbLog("getBgColour: bpp %d?\n",cl->format.bitsPerPixel);
+ return FALSE;
+ }
+
+ if (nSubrects < 0) {
+
+ /* RRE encoding was too large, use raw */
+
+ return rfbSendRectEncodingRaw(cl, x, y, w, h);
+ }
+
+ cl->rfbRectanglesSent[rfbEncodingRRE]++;
+ cl->rfbBytesSent[rfbEncodingRRE] += (sz_rfbFramebufferUpdateRectHeader
+ + sz_rfbRREHeader + rreAfterBufLen);
+
+ if (cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbRREHeader
+ > UPDATE_BUF_SIZE)
+ {
+ if (!rfbSendUpdateBuf(cl))
+ return FALSE;
+ }
+
+ rect.r.x = Swap16IfLE(x);
+ rect.r.y = Swap16IfLE(y);
+ rect.r.w = Swap16IfLE(w);
+ rect.r.h = Swap16IfLE(h);
+ rect.encoding = Swap32IfLE(rfbEncodingRRE);
+
+ memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
+ sz_rfbFramebufferUpdateRectHeader);
+ cl->ublen += sz_rfbFramebufferUpdateRectHeader;
+
+ hdr.nSubrects = Swap32IfLE(nSubrects);
+
+ memcpy(&cl->updateBuf[cl->ublen], (char *)&hdr, sz_rfbRREHeader);
+ cl->ublen += sz_rfbRREHeader;
+
+ for (i = 0; i < rreAfterBufLen;) {
+
+ int bytesToCopy = UPDATE_BUF_SIZE - cl->ublen;
+
+ if (i + bytesToCopy > rreAfterBufLen) {
+ bytesToCopy = rreAfterBufLen - i;
+ }
+
+ memcpy(&cl->updateBuf[cl->ublen], &rreAfterBuf[i], bytesToCopy);
+
+ cl->ublen += bytesToCopy;
+ i += bytesToCopy;
+
+ if (cl->ublen == UPDATE_BUF_SIZE) {
+ if (!rfbSendUpdateBuf(cl))
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+
+/*
+ * subrectEncode() encodes the given multicoloured rectangle as a background
+ * colour overwritten by single-coloured rectangles. It returns the number
+ * of subrectangles in the encoded buffer, or -1 if subrect encoding won't
+ * fit in the buffer. It puts the encoded rectangles in rreAfterBuf. The
+ * single-colour rectangle partition is not optimal, but does find the biggest
+ * horizontal or vertical rectangle top-left anchored to each consecutive
+ * coordinate position.
+ *
+ * The coding scheme is simply [<bgcolour><subrect><subrect>...] where each
+ * <subrect> is [<colour><x><y><w><h>].
+ */
+
+#define DEFINE_SUBRECT_ENCODE(bpp) \
+static int \
+subrectEncode##bpp(data,w,h) \
+ uint##bpp##_t *data; \
+ int w; \
+ int h; \
+{ \
+ uint##bpp##_t cl; \
+ rfbRectangle subrect; \
+ int x,y; \
+ int i,j; \
+ int hx=0,hy,vx=0,vy; \
+ int hyflag; \
+ uint##bpp##_t *seg; \
+ uint##bpp##_t *line; \
+ int hw,hh,vw,vh; \
+ int thex,they,thew,theh; \
+ int numsubs = 0; \
+ int newLen; \
+ uint##bpp##_t bg = (uint##bpp##_t)getBgColour((char*)data,w*h,bpp); \
+ \
+ *((uint##bpp##_t*)rreAfterBuf) = bg; \
+ \
+ rreAfterBufLen = (bpp/8); \
+ \
+ for (y=0; y<h; y++) { \
+ line = data+(y*w); \
+ for (x=0; x<w; x++) { \
+ if (line[x] != bg) { \
+ cl = line[x]; \
+ hy = y-1; \
+ hyflag = 1; \
+ for (j=y; j<h; j++) { \
+ seg = data+(j*w); \
+ if (seg[x] != cl) {break;} \
+ i = x; \
+ while ((seg[i] == cl) && (i < w)) i += 1; \
+ i -= 1; \
+ if (j == y) vx = hx = i; \
+ if (i < vx) vx = i; \
+ if ((hyflag > 0) && (i >= hx)) {hy += 1;} else {hyflag = 0;} \
+ } \
+ vy = j-1; \
+ \
+ /* We now have two possible subrects: (x,y,hx,hy) and (x,y,vx,vy) \
+ * We'll choose the bigger of the two. \
+ */ \
+ hw = hx-x+1; \
+ hh = hy-y+1; \
+ vw = vx-x+1; \
+ vh = vy-y+1; \
+ \
+ thex = x; \
+ they = y; \
+ \
+ if ((hw*hh) > (vw*vh)) { \
+ thew = hw; \
+ theh = hh; \
+ } else { \
+ thew = vw; \
+ theh = vh; \
+ } \
+ \
+ subrect.x = Swap16IfLE(thex); \
+ subrect.y = Swap16IfLE(they); \
+ subrect.w = Swap16IfLE(thew); \
+ subrect.h = Swap16IfLE(theh); \
+ \
+ newLen = rreAfterBufLen + (bpp/8) + sz_rfbRectangle; \
+ if ((newLen > (w * h * (bpp/8))) || (newLen > rreAfterBufSize)) \
+ return -1; \
+ \
+ numsubs += 1; \
+ *((uint##bpp##_t*)(rreAfterBuf + rreAfterBufLen)) = cl; \
+ rreAfterBufLen += (bpp/8); \
+ memcpy(&rreAfterBuf[rreAfterBufLen],&subrect,sz_rfbRectangle); \
+ rreAfterBufLen += sz_rfbRectangle; \
+ \
+ /* \
+ * Now mark the subrect as done. \
+ */ \
+ for (j=they; j < (they+theh); j++) { \
+ for (i=thex; i < (thex+thew); i++) { \
+ data[j*w+i] = bg; \
+ } \
+ } \
+ } \
+ } \
+ } \
+ \
+ return numsubs; \
+}
+
+DEFINE_SUBRECT_ENCODE(8)
+DEFINE_SUBRECT_ENCODE(16)
+DEFINE_SUBRECT_ENCODE(32)
+
+
+/*
+ * getBgColour() gets the most prevalent colour in a byte array.
+ */
+static uint32_t
+getBgColour(data,size,bpp)
+ char *data;
+ int size;
+ int bpp;
+{
+
+#define NUMCLRS 256
+
+ static int counts[NUMCLRS];
+ int i,j,k;
+
+ int maxcount = 0;
+ uint8_t maxclr = 0;
+
+ if (bpp != 8) {
+ if (bpp == 16) {
+ return ((uint16_t *)data)[0];
+ } else if (bpp == 32) {
+ return ((uint32_t *)data)[0];
+ } else {
+ rfbLog("getBgColour: bpp %d?\n",bpp);
+ return 0;
+ }
+ }
+
+ for (i=0; i<NUMCLRS; i++) {
+ counts[i] = 0;
+ }
+
+ for (j=0; j<size; j++) {
+ k = (int)(((uint8_t *)data)[j]);
+ if (k >= NUMCLRS) {
+ rfbErr("getBgColour: unusual colour = %d\n", k);
+ return 0;
+ }
+ counts[k] += 1;
+ if (counts[k] > maxcount) {
+ maxcount = counts[k];
+ maxclr = ((uint8_t *)data)[j];
+ }
+ }
+
+ return maxclr;
+}
diff --git a/libvncserver/selbox.c b/libvncserver/selbox.c
new file mode 100755
index 0000000..8d76e23
--- /dev/null
+++ b/libvncserver/selbox.c
@@ -0,0 +1,301 @@
+#include <ctype.h>
+#include <rfb/rfb.h>
+#include <rfb/keysym.h>
+
+typedef struct {
+ rfbScreenInfoPtr screen;
+ rfbFontDataPtr font;
+ char** list;
+ int listSize;
+ int selected;
+ int displayStart;
+ int x1,y1,x2,y2,textH,pageH;
+ int xhot,yhot;
+ int buttonWidth,okBX,cancelBX,okX,cancelX,okY;
+ rfbBool okInverted,cancelInverted;
+ int lastButtons;
+ rfbPixel colour,backColour;
+ SelectionChangedHookPtr selChangedHook;
+ enum { SELECTING, OK, CANCEL } state;
+} rfbSelectData;
+
+static const char* okStr="OK";
+static const char* cancelStr="Cancel";
+
+static void selPaintButtons(rfbSelectData* m,rfbBool invertOk,rfbBool invertCancel)
+{
+ rfbScreenInfoPtr s = m->screen;
+ rfbPixel bcolour = m->backColour;
+ rfbPixel colour = m->colour;
+
+ rfbFillRect(s,m->x1,m->okY-m->textH,m->x2,m->okY,bcolour);
+
+ if(invertOk) {
+ rfbFillRect(s,m->okBX,m->okY-m->textH,m->okBX+m->buttonWidth,m->okY,colour);
+ rfbDrawStringWithClip(s,m->font,m->okX+m->xhot,m->okY-1+m->yhot,okStr,
+ m->x1,m->okY-m->textH,m->x2,m->okY,
+ bcolour,colour);
+ } else
+ rfbDrawString(s,m->font,m->okX+m->xhot,m->okY-1+m->yhot,okStr,colour);
+
+ if(invertCancel) {
+ rfbFillRect(s,m->cancelBX,m->okY-m->textH,
+ m->cancelBX+m->buttonWidth,m->okY,colour);
+ rfbDrawStringWithClip(s,m->font,m->cancelX+m->xhot,m->okY-1+m->yhot,
+ cancelStr,m->x1,m->okY-m->textH,m->x2,m->okY,
+ bcolour,colour);
+ } else
+ rfbDrawString(s,m->font,m->cancelX+m->xhot,m->okY-1+m->yhot,cancelStr,colour);
+
+ m->okInverted = invertOk;
+ m->cancelInverted = invertCancel;
+}
+
+/* line is relative to displayStart */
+static void selPaintLine(rfbSelectData* m,int line,rfbBool invert)
+{
+ int y1 = m->y1+line*m->textH, y2 = y1+m->textH;
+ if(y2>m->y2)
+ y2=m->y2;
+ rfbFillRect(m->screen,m->x1,y1,m->x2,y2,invert?m->colour:m->backColour);
+ if(m->displayStart+line<m->listSize)
+ rfbDrawStringWithClip(m->screen,m->font,m->x1+m->xhot,y2-1+m->yhot,
+ m->list[m->displayStart+line],
+ m->x1,y1,m->x2,y2,
+ invert?m->backColour:m->colour,
+ invert?m->backColour:m->colour);
+}
+
+static void selSelect(rfbSelectData* m,int _index)
+{
+ int delta;
+
+ if(_index==m->selected || _index<0 || _index>=m->listSize)
+ return;
+
+ if(m->selected>=0)
+ selPaintLine(m,m->selected-m->displayStart,FALSE);
+
+ if(_index<m->displayStart || _index>=m->displayStart+m->pageH) {
+ /* targetLine is the screen line in which the selected line will
+ be displayed.
+ targetLine = m->pageH/2 doesn't look so nice */
+ int targetLine = m->selected-m->displayStart;
+ int lineStart,lineEnd;
+
+ /* scroll */
+ if(_index<targetLine)
+ targetLine = _index;
+ else if(_index+m->pageH-targetLine>=m->listSize)
+ targetLine = _index+m->pageH-m->listSize;
+ delta = _index-(m->displayStart+targetLine);
+
+ if(delta>-m->pageH && delta<m->pageH) {
+ if(delta>0) {
+ lineStart = m->pageH-delta;
+ lineEnd = m->pageH;
+ rfbDoCopyRect(m->screen,m->x1,m->y1,m->x2,m->y1+lineStart*m->textH,
+ 0,-delta*m->textH);
+ } else {
+ lineStart = 0;
+ lineEnd = -delta;
+ rfbDoCopyRect(m->screen,
+ m->x1,m->y1+lineEnd*m->textH,m->x2,m->y2,
+ 0,-delta*m->textH);
+ }
+ } else {
+ lineStart = 0;
+ lineEnd = m->pageH;
+ }
+ m->displayStart += delta;
+ for(delta=lineStart;delta<lineEnd;delta++)
+ if(delta!=_index)
+ selPaintLine(m,delta,FALSE);
+ }
+
+ m->selected = _index;
+ selPaintLine(m,m->selected-m->displayStart,TRUE);
+
+ if(m->selChangedHook)
+ m->selChangedHook(_index);
+
+ /* todo: scrollbars */
+}
+
+static void selKbdAddEvent(rfbBool down,rfbKeySym keySym,rfbClientPtr cl)
+{
+ if(down) {
+ if(keySym>' ' && keySym<0xff) {
+ int i;
+ rfbSelectData* m = (rfbSelectData*)cl->screen->screenData;
+ char c = tolower(keySym);
+
+ for(i=m->selected+1;m->list[i] && tolower(m->list[i][0])!=c;i++);
+ if(!m->list[i])
+ for(i=0;i<m->selected && tolower(m->list[i][0])!=c;i++);
+ selSelect(m,i);
+ } else if(keySym==XK_Escape) {
+ rfbSelectData* m = (rfbSelectData*)cl->screen->screenData;
+ m->state = CANCEL;
+ } else if(keySym==XK_Return) {
+ rfbSelectData* m = (rfbSelectData*)cl->screen->screenData;
+ m->state = OK;
+ } else {
+ rfbSelectData* m = (rfbSelectData*)cl->screen->screenData;
+ int curSel=m->selected;
+ if(keySym==XK_Up) {
+ if(curSel>0)
+ selSelect(m,curSel-1);
+ } else if(keySym==XK_Down) {
+ if(curSel+1<m->listSize)
+ selSelect(m,curSel+1);
+ } else {
+ if(keySym==XK_Page_Down) {
+ if(curSel+m->pageH<m->listSize)
+ selSelect(m,curSel+m->pageH);
+ else
+ selSelect(m,m->listSize-1);
+ } else if(keySym==XK_Page_Up) {
+ if(curSel-m->pageH>=0)
+ selSelect(m,curSel-m->pageH);
+ else
+ selSelect(m,0);
+ }
+ }
+ }
+ }
+}
+
+static void selPtrAddEvent(int buttonMask,int x,int y,rfbClientPtr cl)
+{
+ rfbSelectData* m = (rfbSelectData*)cl->screen->screenData;
+ if(y<m->okY && y>=m->okY-m->textH) {
+ if(x>=m->okBX && x<m->okBX+m->buttonWidth) {
+ if(!m->okInverted)
+ selPaintButtons(m,TRUE,FALSE);
+ if(buttonMask)
+ m->state = OK;
+ } else if(x>=m->cancelBX && x<m->cancelBX+m->buttonWidth) {
+ if(!m->cancelInverted)
+ selPaintButtons(m,FALSE,TRUE);
+ if(buttonMask)
+ m->state = CANCEL;
+ } else if(m->okInverted || m->cancelInverted)
+ selPaintButtons(m,FALSE,FALSE);
+ } else {
+ if(m->okInverted || m->cancelInverted)
+ selPaintButtons(m,FALSE,FALSE);
+ if(!m->lastButtons && buttonMask) {
+ if(x>=m->x1 && x<m->x2 && y>=m->y1 && y<m->y2)
+ selSelect(m,m->displayStart+(y-m->y1)/m->textH);
+ }
+ }
+ m->lastButtons = buttonMask;
+
+ /* todo: scrollbars */
+}
+
+static rfbCursorPtr selGetCursorPtr(rfbClientPtr cl)
+{
+ return(0);
+}
+
+int rfbSelectBox(rfbScreenInfoPtr rfbScreen,rfbFontDataPtr font,
+ char** list,
+ int x1,int y1,int x2,int y2,
+ rfbPixel colour,rfbPixel backColour,
+ int border,SelectionChangedHookPtr selChangedHook)
+{
+ int bpp = rfbScreen->bitsPerPixel/8;
+ char* frameBufferBackup;
+ void* screenDataBackup = rfbScreen->screenData;
+ KbdAddEventProcPtr kbdAddEventBackup = rfbScreen->kbdAddEvent;
+ PtrAddEventProcPtr ptrAddEventBackup = rfbScreen->ptrAddEvent;
+ GetCursorProcPtr getCursorPtrBackup = rfbScreen->getCursorPtr;
+ DisplayHookPtr displayHookBackup = rfbScreen->displayHook;
+ rfbSelectData selData;
+ int i,j,k;
+ int fx1,fy1,fx2,fy2; /* for font bbox */
+
+ if(list==0 || *list==0)
+ return(-1);
+
+ rfbWholeFontBBox(font, &fx1, &fy1, &fx2, &fy2);
+ selData.textH = fy2-fy1;
+ /* I need at least one line for the choice and one for the buttons */
+ if(y2-y1<selData.textH*2+3*border)
+ return(-1);
+ selData.xhot = -fx1;
+ selData.yhot = -fy2;
+ selData.x1 = x1+border;
+ selData.y1 = y1+border;
+ selData.y2 = y2-selData.textH-3*border;
+ selData.x2 = x2-2*border;
+ selData.pageH = (selData.y2-selData.y1)/selData.textH;
+
+ i = rfbWidthOfString(font,okStr);
+ j = rfbWidthOfString(font,cancelStr);
+ selData.buttonWidth= k = 4*border+(i<j)?j:i;
+ selData.okBX = x1+(x2-x1-2*k)/3;
+ if(selData.okBX<x1+border) /* too narrow! */
+ return(-1);
+ selData.cancelBX = x1+k+(x2-x1-2*k)*2/3;
+ selData.okX = selData.okBX+(k-i)/2;
+ selData.cancelX = selData.cancelBX+(k-j)/2;
+ selData.okY = y2-border;
+
+ rfbUndrawCursor(rfbScreen);
+ frameBufferBackup = (char*)malloc(bpp*(x2-x1)*(y2-y1));
+
+ selData.state = SELECTING;
+ selData.screen = rfbScreen;
+ selData.font = font;
+ selData.list = list;
+ selData.colour = colour;
+ selData.backColour = backColour;
+ for(i=0;list[i];i++);
+ selData.selected = i;
+ selData.listSize = i;
+ selData.displayStart = i;
+ selData.lastButtons = 0;
+ selData.selChangedHook = selChangedHook;
+
+ rfbScreen->screenData = &selData;
+ rfbScreen->kbdAddEvent = selKbdAddEvent;
+ rfbScreen->ptrAddEvent = selPtrAddEvent;
+ rfbScreen->getCursorPtr = selGetCursorPtr;
+ rfbScreen->displayHook = 0;
+
+ /* backup screen */
+ for(j=0;j<y2-y1;j++)
+ memcpy(frameBufferBackup+j*(x2-x1)*bpp,
+ rfbScreen->frameBuffer+j*rfbScreen->paddedWidthInBytes+x1*bpp,
+ (x2-x1)*bpp);
+
+ /* paint list and buttons */
+ rfbFillRect(rfbScreen,x1,y1,x2,y2,colour);
+ selPaintButtons(&selData,FALSE,FALSE);
+ selSelect(&selData,0);
+
+ /* modal loop */
+ while(selData.state == SELECTING)
+ rfbProcessEvents(rfbScreen,20000);
+
+ /* copy back screen data */
+ for(j=0;j<y2-y1;j++)
+ memcpy(rfbScreen->frameBuffer+j*rfbScreen->paddedWidthInBytes+x1*bpp,
+ frameBufferBackup+j*(x2-x1)*bpp,
+ (x2-x1)*bpp);
+ free(frameBufferBackup);
+ rfbMarkRectAsModified(rfbScreen,x1,y1,x2,y2);
+ rfbScreen->screenData = screenDataBackup;
+ rfbScreen->kbdAddEvent = kbdAddEventBackup;
+ rfbScreen->ptrAddEvent = ptrAddEventBackup;
+ rfbScreen->getCursorPtr = getCursorPtrBackup;
+ rfbScreen->displayHook = displayHookBackup;
+
+ if(selData.state==CANCEL)
+ selData.selected=-1;
+ return(selData.selected);
+}
+
diff --git a/libvncserver/sockets.c b/libvncserver/sockets.c
new file mode 100755
index 0000000..cea1898
--- /dev/null
+++ b/libvncserver/sockets.c
@@ -0,0 +1,619 @@
+/*
+ * sockets.c - deal with TCP & UDP sockets.
+ *
+ * This code should be independent of any changes in the RFB protocol. It just
+ * deals with the X server scheduling stuff, calling rfbNewClientConnection and
+ * rfbProcessClientMessage to actually deal with the protocol. If a socket
+ * needs to be closed for any reason then rfbCloseClient should be called, and
+ * this in turn will call rfbClientConnectionGone. To make an active
+ * connection out, call rfbConnect - note that this does _not_ call
+ * rfbNewClientConnection.
+ *
+ * This file is divided into two types of function. Those beginning with
+ * "rfb" are specific to sockets using the RFB protocol. Those without the
+ * "rfb" prefix are more general socket routines (which are used by the http
+ * code).
+ *
+ * Thanks to Karl Hakimian for pointing out that some platforms return EAGAIN
+ * not EWOULDBLOCK.
+ */
+
+/*
+ * OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
+ * Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge.
+ * 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/rfb.h>
+
+#ifdef LIBVNCSERVER_HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef WIN32
+#pragma warning (disable: 4018 4761)
+#define close closesocket
+#define read(sock,buf,len) recv(sock,buf,len,0)
+#define EWOULDBLOCK WSAEWOULDBLOCK
+#define ETIMEDOUT WSAETIMEDOUT
+#define write(sock,buf,len) send(sock,buf,len,0)
+#else
+#ifdef LIBVNCSERVER_HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef LIBVNCSERVER_HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef LIBVNCSERVER_HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#endif
+#ifdef LIBVNCSERVER_HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#endif
+
+#if defined(__linux__) && defined(NEED_TIMEVAL)
+struct timeval
+{
+ long int tv_sec,tv_usec;
+}
+;
+#endif
+
+#ifdef LIBVNCSERVER_HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#include <errno.h>
+
+#ifdef USE_LIBWRAP
+#include <syslog.h>
+#include <tcpd.h>
+int allow_severity=LOG_INFO;
+int deny_severity=LOG_WARNING;
+#endif
+
+/*#ifndef WIN32
+int max(int i,int j) { return(i<j?j:i); }
+#endif
+*/
+
+int rfbMaxClientWait = 20000; /* time (ms) after which we decide client has
+ gone away - needed to stop us hanging */
+
+/*
+ * rfbInitSockets sets up the TCP and UDP sockets to listen for RFB
+ * connections. It does nothing if called again.
+ */
+
+void
+rfbInitSockets(rfbScreenInfoPtr rfbScreen)
+{
+ if (rfbScreen->socketInitDone)
+ return;
+
+ rfbScreen->socketInitDone = TRUE;
+
+ if (rfbScreen->inetdSock != -1) {
+ const int one = 1;
+
+#ifndef WIN32
+ if (fcntl(rfbScreen->inetdSock, F_SETFL, O_NONBLOCK) < 0) {
+ rfbLogPerror("fcntl");
+ return;
+ }
+#endif
+
+ if (setsockopt(rfbScreen->inetdSock, IPPROTO_TCP, TCP_NODELAY,
+ (char *)&one, sizeof(one)) < 0) {
+ rfbLogPerror("setsockopt");
+ return;
+ }
+
+ FD_ZERO(&(rfbScreen->allFds));
+ FD_SET(rfbScreen->inetdSock, &(rfbScreen->allFds));
+ rfbScreen->maxFd = rfbScreen->inetdSock;
+ return;
+ }
+
+ if(rfbScreen->autoPort) {
+ int i;
+ rfbLog("Autoprobing TCP port \n");
+
+ for (i = 5900; i < 6000; i++) {
+ if ((rfbScreen->rfbListenSock = ListenOnTCPPort(i)) >= 0) {
+ rfbScreen->rfbPort = i;
+ break;
+ }
+ }
+
+ if (i >= 6000) {
+ rfbLogPerror("Failure autoprobing");
+ return;
+ }
+
+ rfbLog("Autoprobing selected port %d\n", rfbScreen->rfbPort);
+ FD_ZERO(&(rfbScreen->allFds));
+ FD_SET(rfbScreen->rfbListenSock, &(rfbScreen->allFds));
+ rfbScreen->maxFd = rfbScreen->rfbListenSock;
+ }
+ else if(rfbScreen->rfbPort>0) {
+ rfbLog("Listening for VNC connections on TCP port %d\n", rfbScreen->rfbPort);
+
+ if ((rfbScreen->rfbListenSock = ListenOnTCPPort(rfbScreen->rfbPort)) < 0) {
+ rfbLogPerror("ListenOnTCPPort");
+ return;
+ }
+
+ FD_ZERO(&(rfbScreen->allFds));
+ FD_SET(rfbScreen->rfbListenSock, &(rfbScreen->allFds));
+ rfbScreen->maxFd = rfbScreen->rfbListenSock;
+ }
+
+ if (rfbScreen->udpPort != 0) {
+ rfbLog("rfbInitSockets: listening for input on UDP port %d\n",rfbScreen->udpPort);
+
+ if ((rfbScreen->udpSock = ListenOnUDPPort(rfbScreen->udpPort)) < 0) {
+ rfbLogPerror("ListenOnUDPPort");
+ return;
+ }
+ FD_SET(rfbScreen->udpSock, &(rfbScreen->allFds));
+ rfbScreen->maxFd = max((int)rfbScreen->udpSock,rfbScreen->maxFd);
+ }
+}
+
+
+/*
+ * rfbCheckFds is called from ProcessInputEvents to check for input on the RFB
+ * socket(s). If there is input to process, the appropriate function in the
+ * RFB server code will be called (rfbNewClientConnection,
+ * rfbProcessClientMessage, etc).
+ */
+
+void
+rfbCheckFds(rfbScreenInfoPtr rfbScreen,long usec)
+{
+ int nfds;
+ fd_set fds;
+ struct timeval tv;
+ struct sockaddr_in addr;
+ size_t addrlen = sizeof(addr);
+ char buf[6];
+ const int one = 1;
+ int sock;
+ rfbClientIteratorPtr i;
+ rfbClientPtr cl;
+
+ if (!rfbScreen->inetdInitDone && rfbScreen->inetdSock != -1) {
+ rfbNewClientConnection(rfbScreen,rfbScreen->inetdSock);
+ rfbScreen->inetdInitDone = TRUE;
+ }
+
+ memcpy((char *)&fds, (char *)&(rfbScreen->allFds), sizeof(fd_set));
+ tv.tv_sec = 0;
+ tv.tv_usec = usec;
+ nfds = select(rfbScreen->maxFd + 1, &fds, NULL, NULL /* &fds */, &tv);
+ if (nfds == 0) {
+ return;
+ }
+ if (nfds < 0) {
+#ifdef WIN32
+ errno = WSAGetLastError();
+#endif
+ if (errno != EINTR)
+ rfbLogPerror("rfbCheckFds: select");
+ return;
+ }
+
+ if (rfbScreen->rfbListenSock != -1 && FD_ISSET(rfbScreen->rfbListenSock, &fds)) {
+
+ if ((sock = accept(rfbScreen->rfbListenSock,
+ (struct sockaddr *)&addr, &addrlen)) < 0) {
+ rfbLogPerror("rfbCheckFds: accept");
+ return;
+ }
+
+#ifndef WIN32
+ if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) {
+ rfbLogPerror("rfbCheckFds: fcntl");
+ close(sock);
+ return;
+ }
+#endif
+
+ if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
+ (char *)&one, sizeof(one)) < 0) {
+ rfbLogPerror("rfbCheckFds: setsockopt");
+ close(sock);
+ return;
+ }
+
+#ifdef USE_LIBWRAP
+ if(!hosts_ctl("vnc",STRING_UNKNOWN,inet_ntoa(addr.sin_addr),
+ STRING_UNKNOWN)) {
+ rfbLog("Rejected connection from client %s\n",
+ inet_ntoa(addr.sin_addr));
+ close(sock);
+ return;
+ }
+#endif
+
+ rfbLog("Got connection from client %s\n", inet_ntoa(addr.sin_addr));
+
+ rfbNewClient(rfbScreen,sock);
+
+ FD_CLR(rfbScreen->rfbListenSock, &fds);
+ if (--nfds == 0)
+ return;
+ }
+
+ if ((rfbScreen->udpSock != -1) && FD_ISSET(rfbScreen->udpSock, &fds)) {
+ if(!rfbScreen->udpClient)
+ rfbNewUDPClient(rfbScreen);
+ if (recvfrom(rfbScreen->udpSock, buf, 1, MSG_PEEK,
+ (struct sockaddr *)&addr, &addrlen) < 0) {
+ rfbLogPerror("rfbCheckFds: UDP: recvfrom");
+ rfbDisconnectUDPSock(rfbScreen);
+ rfbScreen->udpSockConnected = FALSE;
+ } else {
+ if (!rfbScreen->udpSockConnected ||
+ (memcmp(&addr, &rfbScreen->udpRemoteAddr, addrlen) != 0))
+ {
+ /* new remote end */
+ rfbLog("rfbCheckFds: UDP: got connection\n");
+
+ memcpy(&rfbScreen->udpRemoteAddr, &addr, addrlen);
+ rfbScreen->udpSockConnected = TRUE;
+
+ if (connect(rfbScreen->udpSock,
+ (struct sockaddr *)&addr, addrlen) < 0) {
+ rfbLogPerror("rfbCheckFds: UDP: connect");
+ rfbDisconnectUDPSock(rfbScreen);
+ return;
+ }
+
+ rfbNewUDPConnection(rfbScreen,rfbScreen->udpSock);
+ }
+
+ rfbProcessUDPInput(rfbScreen);
+ }
+
+ FD_CLR(rfbScreen->udpSock, &fds);
+ if (--nfds == 0)
+ return;
+ }
+
+ i = rfbGetClientIterator(rfbScreen);
+ while((cl = rfbClientIteratorNext(i))) {
+ if (cl->onHold)
+ continue;
+ if (FD_ISSET(cl->sock, &fds) && FD_ISSET(cl->sock, &(rfbScreen->allFds)))
+ rfbProcessClientMessage(cl);
+ }
+ rfbReleaseClientIterator(i);
+}
+
+
+void
+rfbDisconnectUDPSock(rfbScreenInfoPtr rfbScreen)
+{
+ rfbScreen->udpSockConnected = FALSE;
+}
+
+
+
+void
+rfbCloseClient(cl)
+ rfbClientPtr cl;
+{
+ LOCK(cl->updateMutex);
+#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
+ if (cl->sock != -1)
+#endif
+ {
+ FD_CLR(cl->sock,&(cl->screen->allFds));
+ if(cl->sock==cl->screen->maxFd)
+ while(cl->screen->maxFd>0
+ && !FD_ISSET(cl->screen->maxFd,&(cl->screen->allFds)))
+ cl->screen->maxFd--;
+ shutdown(cl->sock,SHUT_RDWR);
+ close(cl->sock);
+ cl->sock = -1;
+ }
+ TSIGNAL(cl->updateCond);
+ UNLOCK(cl->updateMutex);
+}
+
+
+/*
+ * rfbConnect is called to make a connection out to a given TCP address.
+ */
+
+int
+rfbConnect(rfbScreen, host, port)
+ rfbScreenInfoPtr rfbScreen;
+ char *host;
+ int port;
+{
+ int sock;
+ int one = 1;
+
+ rfbLog("Making connection to client on host %s port %d\n",
+ host,port);
+
+ if ((sock = ConnectToTcpAddr(host, port)) < 0) {
+ rfbLogPerror("connection failed");
+ return -1;
+ }
+
+#ifndef WIN32
+ if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) {
+ rfbLogPerror("fcntl failed");
+ close(sock);
+ return -1;
+ }
+#endif
+
+ if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
+ (char *)&one, sizeof(one)) < 0) {
+ rfbLogPerror("setsockopt failed");
+ close(sock);
+ return -1;
+ }
+
+ /* AddEnabledDevice(sock); */
+ FD_SET(sock, &rfbScreen->allFds);
+ rfbScreen->maxFd = max(sock,rfbScreen->maxFd);
+
+ return sock;
+}
+
+/*
+ * ReadExact reads an exact number of bytes from a client. Returns 1 if
+ * those bytes have been read, 0 if the other end has closed, or -1 if an error
+ * occurred (errno is set to ETIMEDOUT if it timed out).
+ */
+
+int
+ReadExactTimeout(rfbClientPtr cl, char* buf, int len, int timeout)
+{
+ int sock = cl->sock;
+ int n;
+ fd_set fds;
+ struct timeval tv;
+
+ while (len > 0) {
+ n = read(sock, buf, len);
+
+ if (n > 0) {
+
+ buf += n;
+ len -= n;
+
+ } else if (n == 0) {
+
+ return 0;
+
+ } else {
+#ifdef WIN32
+ errno = WSAGetLastError();
+#endif
+ if (errno == EINTR)
+ continue;
+
+ if (errno != EWOULDBLOCK && errno != EAGAIN) {
+ return n;
+ }
+
+ FD_ZERO(&fds);
+ FD_SET(sock, &fds);
+ tv.tv_sec = timeout / 1000;
+ tv.tv_usec = (timeout % 1000) * 1000;
+ n = select(sock+1, &fds, NULL, &fds, &tv);
+ if (n < 0) {
+ rfbLogPerror("ReadExact: select");
+ return n;
+ }
+ if (n == 0) {
+ errno = ETIMEDOUT;
+ return -1;
+ }
+ }
+ }
+ return 1;
+}
+
+int ReadExact(rfbClientPtr cl,char* buf,int len)
+{
+ return(ReadExactTimeout(cl,buf,len,rfbMaxClientWait));
+}
+
+/*
+ * WriteExact writes an exact number of bytes to a client. Returns 1 if
+ * those bytes have been written, or -1 if an error occurred (errno is set to
+ * ETIMEDOUT if it timed out).
+ */
+
+int
+WriteExact(cl, buf, len)
+ rfbClientPtr cl;
+ const char *buf;
+ int len;
+{
+ int sock = cl->sock;
+ int n;
+ fd_set fds;
+ struct timeval tv;
+ int totalTimeWaited = 0;
+
+ LOCK(cl->outputMutex);
+ while (len > 0) {
+ n = write(sock, buf, len);
+
+ if (n > 0) {
+
+ buf += n;
+ len -= n;
+
+ } else if (n == 0) {
+
+ rfbErr("WriteExact: write returned 0?\n");
+ return 0;
+
+ } else {
+#ifdef WIN32
+ errno = WSAGetLastError();
+#endif
+ if (errno == EINTR)
+ continue;
+
+ if (errno != EWOULDBLOCK && errno != EAGAIN) {
+ UNLOCK(cl->outputMutex);
+ return n;
+ }
+
+ /* Retry every 5 seconds until we exceed rfbMaxClientWait. We
+ need to do this because select doesn't necessarily return
+ immediately when the other end has gone away */
+
+ FD_ZERO(&fds);
+ FD_SET(sock, &fds);
+ tv.tv_sec = 5;
+ tv.tv_usec = 0;
+ n = select(sock+1, NULL, &fds, NULL /* &fds */, &tv);
+ if (n < 0) {
+ if(errno==EINTR)
+ continue;
+ rfbLogPerror("WriteExact: select");
+ UNLOCK(cl->outputMutex);
+ return n;
+ }
+ if (n == 0) {
+ totalTimeWaited += 5000;
+ if (totalTimeWaited >= rfbMaxClientWait) {
+ errno = ETIMEDOUT;
+ UNLOCK(cl->outputMutex);
+ return -1;
+ }
+ } else {
+ totalTimeWaited = 0;
+ }
+ }
+ }
+ UNLOCK(cl->outputMutex);
+ return 1;
+}
+
+int
+ListenOnTCPPort(port)
+ int port;
+{
+ struct sockaddr_in addr;
+ int sock;
+ int one = 1;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+ /* addr.sin_addr.s_addr = interface.s_addr; */
+ addr.sin_addr.s_addr = INADDR_ANY;
+
+ if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ return -1;
+ }
+ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
+ (char *)&one, sizeof(one)) < 0) {
+ close(sock);
+ return -1;
+ }
+ if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+ close(sock);
+ return -1;
+ }
+ if (listen(sock, 5) < 0) {
+ close(sock);
+ return -1;
+ }
+
+ return sock;
+}
+
+int
+ConnectToTcpAddr(host, port)
+ char *host;
+ int port;
+{
+ struct hostent *hp;
+ int sock;
+ struct sockaddr_in addr;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+
+ if ((addr.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE)
+ {
+ if (!(hp = gethostbyname(host))) {
+ errno = EINVAL;
+ return -1;
+ }
+ addr.sin_addr.s_addr = *(unsigned long *)hp->h_addr;
+ }
+
+ if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ return -1;
+ }
+
+ if (connect(sock, (struct sockaddr *)&addr, (sizeof(addr))) < 0) {
+ close(sock);
+ return -1;
+ }
+
+ return sock;
+}
+
+int
+ListenOnUDPPort(port)
+ int port;
+{
+ struct sockaddr_in addr;
+ int sock;
+ int one = 1;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+ /* addr.sin_addr.s_addr = interface.s_addr; */
+ addr.sin_addr.s_addr = INADDR_ANY;
+
+ if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ return -1;
+ }
+ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
+ (char *)&one, sizeof(one)) < 0) {
+ return -1;
+ }
+ if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+ return -1;
+ }
+
+ return sock;
+}
diff --git a/libvncserver/stats.c b/libvncserver/stats.c
new file mode 100755
index 0000000..931c5d2
--- /dev/null
+++ b/libvncserver/stats.c
@@ -0,0 +1,119 @@
+/*
+ * stats.c
+ */
+
+/*
+ * Copyright (C) 2002 RealVNC Ltd.
+ * OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
+ * Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge.
+ * 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/rfb.h>
+
+static const char* encNames[] = {
+ "raw", "copyRect", "RRE", "[encoding 3]", "CoRRE", "hextile",
+ "zlib", "tight", "[encoding 8]", "[encoding 9]", "[encoding 10]",
+ "[encoding 11]", "[encoding 12]", "[encoding 13]", "[encoding 14]",
+#ifdef LIBVNCSERVER_BACKCHANNEL
+ "BackChannel",
+#else
+ "[encoding 15]",
+#endif
+ "ZRLE", "[encoding 17]", "[encoding 18]", "[encoding 19]", "[encoding 20]"
+};
+
+
+void
+rfbResetStats(rfbClientPtr cl)
+{
+ int i;
+ for (i = 0; i < MAX_ENCODINGS; i++) {
+ cl->rfbBytesSent[i] = 0;
+ cl->rfbRectanglesSent[i] = 0;
+ }
+ cl->rfbLastRectMarkersSent = 0;
+ cl->rfbLastRectBytesSent = 0;
+ cl->rfbCursorShapeBytesSent = 0;
+ cl->rfbCursorShapeUpdatesSent = 0;
+ cl->rfbCursorPosBytesSent = 0;
+ cl->rfbCursorPosUpdatesSent = 0;
+ cl->rfbFramebufferUpdateMessagesSent = 0;
+ cl->rfbRawBytesEquivalent = 0;
+ cl->rfbKeyEventsRcvd = 0;
+ cl->rfbPointerEventsRcvd = 0;
+}
+
+void
+rfbPrintStats(rfbClientPtr cl)
+{
+ int i;
+ int totalRectanglesSent = 0;
+ int totalBytesSent = 0;
+
+ rfbLog("Statistics:\n");
+
+ if ((cl->rfbKeyEventsRcvd != 0) || (cl->rfbPointerEventsRcvd != 0))
+ rfbLog(" key events received %d, pointer events %d\n",
+ cl->rfbKeyEventsRcvd, cl->rfbPointerEventsRcvd);
+
+ for (i = 0; i < MAX_ENCODINGS; i++) {
+ totalRectanglesSent += cl->rfbRectanglesSent[i];
+ totalBytesSent += cl->rfbBytesSent[i];
+ }
+
+ totalRectanglesSent += (cl->rfbCursorShapeUpdatesSent +
+ cl->rfbCursorPosUpdatesSent +
+ cl->rfbLastRectMarkersSent);
+ totalBytesSent += (cl->rfbCursorShapeBytesSent +
+ cl->rfbCursorPosBytesSent +
+ cl->rfbLastRectBytesSent);
+
+ rfbLog(" framebuffer updates %d, rectangles %d, bytes %d\n",
+ cl->rfbFramebufferUpdateMessagesSent, totalRectanglesSent,
+ totalBytesSent);
+
+ if (cl->rfbLastRectMarkersSent != 0)
+ rfbLog(" LastRect and NewFBSize markers %d, bytes %d\n",
+ cl->rfbLastRectMarkersSent, cl->rfbLastRectBytesSent);
+
+ if (cl->rfbCursorShapeUpdatesSent != 0)
+ rfbLog(" cursor shape updates %d, bytes %d\n",
+ cl->rfbCursorShapeUpdatesSent, cl->rfbCursorShapeBytesSent);
+
+ if (cl->rfbCursorPosUpdatesSent != 0)
+ rfbLog(" cursor position updates %d, bytes %d\n",
+ cl->rfbCursorPosUpdatesSent, cl->rfbCursorPosBytesSent);
+
+ for (i = 0; i < MAX_ENCODINGS; i++) {
+ if (cl->rfbRectanglesSent[i] != 0)
+ rfbLog(" %s rectangles %d, bytes %d\n",
+ encNames[i], cl->rfbRectanglesSent[i], cl->rfbBytesSent[i]);
+ }
+
+ if ((totalBytesSent - cl->rfbBytesSent[rfbEncodingCopyRect]) != 0) {
+ rfbLog(" raw bytes equivalent %d, compression ratio %f\n",
+ cl->rfbRawBytesEquivalent,
+ (double)cl->rfbRawBytesEquivalent
+ / (double)(totalBytesSent
+ - cl->rfbBytesSent[rfbEncodingCopyRect]-
+ cl->rfbCursorShapeBytesSent -
+ cl->rfbCursorPosBytesSent -
+ cl->rfbLastRectBytesSent));
+ }
+}
diff --git a/libvncserver/tableinit24.c b/libvncserver/tableinit24.c
new file mode 100755
index 0000000..39e9920
--- /dev/null
+++ b/libvncserver/tableinit24.c
@@ -0,0 +1,157 @@
+/*
+ 24 bit
+ */
+
+/*
+ * OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
+ * Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge.
+ * 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.
+ */
+
+static void
+rfbInitOneRGBTable24 (uint8_t *table, int inMax, int outMax, int outShift,int swap);
+
+
+static void
+rfbInitColourMapSingleTable24(char **table, rfbPixelFormat *in,
+ rfbPixelFormat *out,rfbColourMap* colourMap)
+{
+ uint32_t i, r, g, b, outValue;
+ uint8_t *t;
+ uint8_t c;
+ unsigned int nEntries = 1 << in->bitsPerPixel;
+ int shift = colourMap->is16?16:8;
+
+ if (*table) free(*table);
+ *table = (char *)malloc(nEntries * 3 + 1);
+ t = (uint8_t *)*table;
+
+ for (i = 0; i < nEntries; i++) {
+ r = g = b = 0;
+ if(i < colourMap->count) {
+ if(colourMap->is16) {
+ r = colourMap->data.shorts[3*i+0];
+ g = colourMap->data.shorts[3*i+1];
+ b = colourMap->data.shorts[3*i+2];
+ } else {
+ r = colourMap->data.bytes[3*i+0];
+ g = colourMap->data.bytes[3*i+1];
+ b = colourMap->data.bytes[3*i+2];
+ }
+ }
+ outValue = ((((r * (1 + out->redMax)) >> shift) << out->redShift) |
+ (((g * (1 + out->greenMax)) >> shift) << out->greenShift) |
+ (((b * (1 + out->blueMax)) >> shift) << out->blueShift));
+ *(uint32_t*)&t[3*i] = outValue;
+ if(!rfbEndianTest)
+ memmove(t+3*i,t+3*i+1,3);
+ if (out->bigEndian != in->bigEndian) {
+ c = t[3*i]; t[3*i] = t[3*i+2]; t[3*i+2] = c;
+ }
+ }
+}
+
+/*
+ * rfbInitTrueColourSingleTable sets up a single lookup table for truecolour
+ * translation.
+ */
+
+static void
+rfbInitTrueColourSingleTable24 (char **table, rfbPixelFormat *in,
+ rfbPixelFormat *out)
+{
+ int i,outValue;
+ int inRed, inGreen, inBlue, outRed, outGreen, outBlue;
+ uint8_t *t;
+ uint8_t c;
+ int nEntries = 1 << in->bitsPerPixel;
+
+ if (*table) free(*table);
+ *table = (char *)malloc(nEntries * 3 + 1);
+ t = (uint8_t *)*table;
+
+ for (i = 0; i < nEntries; i++) {
+ inRed = (i >> in->redShift) & in->redMax;
+ inGreen = (i >> in->greenShift) & in->greenMax;
+ inBlue = (i >> in->blueShift) & in->blueMax;
+
+ outRed = (inRed * out->redMax + in->redMax / 2) / in->redMax;
+ outGreen = (inGreen * out->greenMax + in->greenMax / 2) / in->greenMax;
+ outBlue = (inBlue * out->blueMax + in->blueMax / 2) / in->blueMax;
+
+ outValue = ((outRed << out->redShift) |
+ (outGreen << out->greenShift) |
+ (outBlue << out->blueShift));
+ *(uint32_t*)&t[3*i] = outValue;
+ if(!rfbEndianTest)
+ memmove(t+3*i,t+3*i+1,3);
+ if (out->bigEndian != in->bigEndian) {
+ c = t[3*i]; t[3*i] = t[3*i+2]; t[3*i+2] = c;
+ }
+ }
+}
+
+
+/*
+ * rfbInitTrueColourRGBTables sets up three separate lookup tables for the
+ * red, green and blue values.
+ */
+
+static void
+rfbInitTrueColourRGBTables24 (char **table, rfbPixelFormat *in,
+ rfbPixelFormat *out)
+{
+ uint8_t *redTable;
+ uint8_t *greenTable;
+ uint8_t *blueTable;
+
+ if (*table) free(*table);
+ *table = (char *)malloc((in->redMax + in->greenMax + in->blueMax + 3)
+ * 3 + 1);
+ redTable = (uint8_t *)*table;
+ greenTable = redTable + 3*(in->redMax + 1);
+ blueTable = greenTable + 3*(in->greenMax + 1);
+
+ rfbInitOneRGBTable24 (redTable, in->redMax, out->redMax,
+ out->redShift, (out->bigEndian != in->bigEndian));
+ rfbInitOneRGBTable24 (greenTable, in->greenMax, out->greenMax,
+ out->greenShift, (out->bigEndian != in->bigEndian));
+ rfbInitOneRGBTable24 (blueTable, in->blueMax, out->blueMax,
+ out->blueShift, (out->bigEndian != in->bigEndian));
+}
+
+static void
+rfbInitOneRGBTable24 (uint8_t *table, int inMax, int outMax, int outShift,
+ int swap)
+{
+ int i;
+ int nEntries = inMax + 1;
+ uint32_t outValue;
+ uint8_t c;
+
+ for (i = 0; i < nEntries; i++) {
+ outValue = ((i * outMax + inMax / 2) / inMax) << outShift;
+ *(uint32_t *)&table[3*i] = outValue;
+ if(!rfbEndianTest)
+ memmove(table+3*i,table+3*i+1,3);
+ if (swap) {
+ c = table[3*i]; table[3*i] = table[3*i+2];
+ table[3*i+2] = c;
+ }
+ }
+}
diff --git a/libvncserver/tableinitcmtemplate.c b/libvncserver/tableinitcmtemplate.c
new file mode 100755
index 0000000..df01b23
--- /dev/null
+++ b/libvncserver/tableinitcmtemplate.c
@@ -0,0 +1,84 @@
+/*
+ * tableinitcmtemplate.c - template for initialising lookup tables for
+ * translation from a colour map to true colour.
+ *
+ * This file shouldn't be compiled. It is included multiple times by
+ * translate.c, each time with a different definition of the macro OUT.
+ * For each value of OUT, this file defines a function which allocates an
+ * appropriately sized lookup table and initialises it.
+ *
+ * I know this code isn't nice to read because of all the macros, but
+ * efficiency is important here.
+ */
+
+/*
+ * OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
+ * Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge.
+ * 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.
+ */
+
+#if !defined(OUT)
+#error "This file shouldn't be compiled."
+#error "It is included as part of translate.c"
+#endif
+
+#define OUT_T CONCAT3E(uint,OUT,_t)
+#define SwapOUT(x) CONCAT2E(Swap,OUT(x))
+#define rfbInitColourMapSingleTableOUT \
+ CONCAT2E(rfbInitColourMapSingleTable,OUT)
+
+static void
+rfbInitColourMapSingleTableOUT(char **table, rfbPixelFormat *in,
+ rfbPixelFormat *out,rfbColourMap* colourMap)
+{
+ uint32_t i, r, g, b;
+ OUT_T *t;
+ uint32_t nEntries = 1 << in->bitsPerPixel;
+ int shift = colourMap->is16?16:8;
+
+ if (*table) free(*table);
+ *table = (char *)malloc(nEntries * sizeof(OUT_T));
+ t = (OUT_T *)*table;
+
+ for (i = 0; i < nEntries; i++) {
+ r = g = b = 0;
+ if(i < colourMap->count) {
+ if(colourMap->is16) {
+ r = colourMap->data.shorts[3*i+0];
+ g = colourMap->data.shorts[3*i+1];
+ b = colourMap->data.shorts[3*i+2];
+ } else {
+ r = colourMap->data.bytes[3*i+0];
+ g = colourMap->data.bytes[3*i+1];
+ b = colourMap->data.bytes[3*i+2];
+ }
+ }
+ t[i] = ((((r * (1 + out->redMax)) >> shift) << out->redShift) |
+ (((g * (1 + out->greenMax)) >> shift) << out->greenShift) |
+ (((b * (1 + out->blueMax)) >> shift) << out->blueShift));
+#if (OUT != 8)
+ if (out->bigEndian != in->bigEndian) {
+ t[i] = SwapOUT(t[i]);
+ }
+#endif
+ }
+}
+
+#undef OUT_T
+#undef SwapOUT
+#undef rfbInitColourMapSingleTableOUT
diff --git a/libvncserver/tableinittctemplate.c b/libvncserver/tableinittctemplate.c
new file mode 100755
index 0000000..8d4f742
--- /dev/null
+++ b/libvncserver/tableinittctemplate.c
@@ -0,0 +1,142 @@
+/*
+ * tableinittctemplate.c - template for initialising lookup tables for
+ * truecolour to truecolour translation.
+ *
+ * This file shouldn't be compiled. It is included multiple times by
+ * translate.c, each time with a different definition of the macro OUT.
+ * For each value of OUT, this file defines two functions for initialising
+ * lookup tables. One is for truecolour translation using a single lookup
+ * table, the other is for truecolour translation using three separate
+ * lookup tables for the red, green and blue values.
+ *
+ * I know this code isn't nice to read because of all the macros, but
+ * efficiency is important here.
+ */
+
+/*
+ * OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
+ * Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge.
+ * 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.
+ */
+
+#if !defined(OUT)
+#error "This file shouldn't be compiled."
+#error "It is included as part of translate.c"
+#endif
+
+#define OUT_T CONCAT3E(uint,OUT,_t)
+#define SwapOUT(x) CONCAT2E(Swap,OUT(x))
+#define rfbInitTrueColourSingleTableOUT \
+ CONCAT2E(rfbInitTrueColourSingleTable,OUT)
+#define rfbInitTrueColourRGBTablesOUT CONCAT2E(rfbInitTrueColourRGBTables,OUT)
+#define rfbInitOneRGBTableOUT CONCAT2E(rfbInitOneRGBTable,OUT)
+
+static void
+rfbInitOneRGBTableOUT (OUT_T *table, int inMax, int outMax, int outShift,
+ int swap);
+
+
+/*
+ * rfbInitTrueColourSingleTable sets up a single lookup table for truecolour
+ * translation.
+ */
+
+static void
+rfbInitTrueColourSingleTableOUT (char **table, rfbPixelFormat *in,
+ rfbPixelFormat *out)
+{
+ int i;
+ int inRed, inGreen, inBlue, outRed, outGreen, outBlue;
+ OUT_T *t;
+ int nEntries = 1 << in->bitsPerPixel;
+
+ if (*table) free(*table);
+ *table = (char *)malloc(nEntries * sizeof(OUT_T));
+ t = (OUT_T *)*table;
+
+ for (i = 0; i < nEntries; i++) {
+ inRed = (i >> in->redShift) & in->redMax;
+ inGreen = (i >> in->greenShift) & in->greenMax;
+ inBlue = (i >> in->blueShift) & in->blueMax;
+
+ outRed = (inRed * out->redMax + in->redMax / 2) / in->redMax;
+ outGreen = (inGreen * out->greenMax + in->greenMax / 2) / in->greenMax;
+ outBlue = (inBlue * out->blueMax + in->blueMax / 2) / in->blueMax;
+
+ t[i] = ((outRed << out->redShift) |
+ (outGreen << out->greenShift) |
+ (outBlue << out->blueShift));
+#if (OUT != 8)
+ if (out->bigEndian != in->bigEndian) {
+ t[i] = SwapOUT(t[i]);
+ }
+#endif
+ }
+}
+
+
+/*
+ * rfbInitTrueColourRGBTables sets up three separate lookup tables for the
+ * red, green and blue values.
+ */
+
+static void
+rfbInitTrueColourRGBTablesOUT (char **table, rfbPixelFormat *in,
+ rfbPixelFormat *out)
+{
+ OUT_T *redTable;
+ OUT_T *greenTable;
+ OUT_T *blueTable;
+
+ if (*table) free(*table);
+ *table = (char *)malloc((in->redMax + in->greenMax + in->blueMax + 3)
+ * sizeof(OUT_T));
+ redTable = (OUT_T *)*table;
+ greenTable = redTable + in->redMax + 1;
+ blueTable = greenTable + in->greenMax + 1;
+
+ rfbInitOneRGBTableOUT (redTable, in->redMax, out->redMax,
+ out->redShift, (out->bigEndian != in->bigEndian));
+ rfbInitOneRGBTableOUT (greenTable, in->greenMax, out->greenMax,
+ out->greenShift, (out->bigEndian != in->bigEndian));
+ rfbInitOneRGBTableOUT (blueTable, in->blueMax, out->blueMax,
+ out->blueShift, (out->bigEndian != in->bigEndian));
+}
+
+static void
+rfbInitOneRGBTableOUT (OUT_T *table, int inMax, int outMax, int outShift,
+ int swap)
+{
+ int i;
+ int nEntries = inMax + 1;
+
+ for (i = 0; i < nEntries; i++) {
+ table[i] = ((i * outMax + inMax / 2) / inMax) << outShift;
+#if (OUT != 8)
+ if (swap) {
+ table[i] = SwapOUT(table[i]);
+ }
+#endif
+ }
+}
+
+#undef OUT_T
+#undef SwapOUT
+#undef rfbInitTrueColourSingleTableOUT
+#undef rfbInitTrueColourRGBTablesOUT
+#undef rfbInitOneRGBTableOUT
diff --git a/libvncserver/tabletrans24template.c b/libvncserver/tabletrans24template.c
new file mode 100755
index 0000000..4b3a0a0
--- /dev/null
+++ b/libvncserver/tabletrans24template.c
@@ -0,0 +1,281 @@
+/*
+ * tabletranstemplate.c - template for translation using lookup tables.
+ *
+ * This file shouldn't be compiled. It is included multiple times by
+ * translate.c, each time with different definitions of the macros IN and OUT.
+ *
+ * For each pair of values IN and OUT, this file defines two functions for
+ * translating a given rectangle of pixel data. One uses a single lookup
+ * table, and the other uses three separate lookup tables for the red, green
+ * and blue values.
+ *
+ * I know this code isn't nice to read because of all the macros, but
+ * efficiency is important here.
+ */
+
+/*
+ * OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
+ * Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge.
+ * 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.
+ */
+
+#if !defined(BPP)
+#error "This file shouldn't be compiled."
+#error "It is included as part of translate.c"
+#endif
+
+#if BPP == 24
+
+/*
+ * rfbTranslateWithSingleTableINtoOUT translates a rectangle of pixel data
+ * using a single lookup table.
+ */
+
+static void
+rfbTranslateWithSingleTable24to24 (char *table, rfbPixelFormat *in,
+ rfbPixelFormat *out,
+ char *iptr, char *optr,
+ int bytesBetweenInputLines,
+ int width, int height)
+{
+ uint8_t *ip = (uint8_t *)iptr;
+ uint8_t *op = (uint8_t *)optr;
+ int ipextra = bytesBetweenInputLines - width * 3;
+ uint8_t *opLineEnd;
+ uint8_t *t = (uint8_t *)table;
+ int shift = rfbEndianTest?0:8;
+ uint8_t c;
+
+ while (height > 0) {
+ opLineEnd = op + width*3;
+
+ while (op < opLineEnd) {
+ *(uint32_t*)op = t[((*(uint32_t *)ip)>>shift)&0x00ffffff];
+ if(!rfbEndianTest)
+ memmove(op,op+1,3);
+ if (out->bigEndian != in->bigEndian) {
+ c = op[0]; op[0] = op[2]; op[2] = c;
+ }
+ op += 3;
+ ip += 3;
+ }
+
+ ip += ipextra;
+ height--;
+ }
+}
+
+/*
+ * rfbTranslateWithRGBTablesINtoOUT translates a rectangle of pixel data
+ * using three separate lookup tables for the red, green and blue values.
+ */
+
+static void
+rfbTranslateWithRGBTables24to24 (char *table, rfbPixelFormat *in,
+ rfbPixelFormat *out,
+ char *iptr, char *optr,
+ int bytesBetweenInputLines,
+ int width, int height)
+{
+ uint8_t *ip = (uint8_t *)iptr;
+ uint8_t *op = (uint8_t *)optr;
+ int ipextra = bytesBetweenInputLines - width*3;
+ uint8_t *opLineEnd;
+ uint8_t *redTable = (uint8_t *)table;
+ uint8_t *greenTable = redTable + 3*(in->redMax + 1);
+ uint8_t *blueTable = greenTable + 3*(in->greenMax + 1);
+ uint32_t outValue,inValue;
+ int shift = rfbEndianTest?0:8;
+
+ while (height > 0) {
+ opLineEnd = op+3*width;
+
+ while (op < opLineEnd) {
+ inValue = ((*(uint32_t *)ip)>>shift)&0x00ffffff;
+ outValue = (redTable[(inValue >> in->redShift) & in->redMax] |
+ greenTable[(inValue >> in->greenShift) & in->greenMax] |
+ blueTable[(inValue >> in->blueShift) & in->blueMax]);
+ memcpy(op,&outValue,3);
+ op += 3;
+ ip+=3;
+ }
+ ip += ipextra;
+ height--;
+ }
+}
+
+#else
+
+#define IN_T CONCAT3E(uint,BPP,_t)
+#define OUT_T CONCAT3E(uint,BPP,_t)
+#define rfbTranslateWithSingleTable24toOUT \
+ CONCAT4E(rfbTranslateWithSingleTable,24,to,BPP)
+#define rfbTranslateWithSingleTableINto24 \
+ CONCAT4E(rfbTranslateWithSingleTable,BPP,to,24)
+#define rfbTranslateWithRGBTables24toOUT \
+ CONCAT4E(rfbTranslateWithRGBTables,24,to,BPP)
+#define rfbTranslateWithRGBTablesINto24 \
+ CONCAT4E(rfbTranslateWithRGBTables,BPP,to,24)
+
+/*
+ * rfbTranslateWithSingleTableINtoOUT translates a rectangle of pixel data
+ * using a single lookup table.
+ */
+
+static void
+rfbTranslateWithSingleTable24toOUT (char *table, rfbPixelFormat *in,
+ rfbPixelFormat *out,
+ char *iptr, char *optr,
+ int bytesBetweenInputLines,
+ int width, int height)
+{
+ uint8_t *ip = (uint8_t *)iptr;
+ OUT_T *op = (OUT_T *)optr;
+ int ipextra = bytesBetweenInputLines - width*3;
+ OUT_T *opLineEnd;
+ OUT_T *t = (OUT_T *)table;
+ int shift = rfbEndianTest?0:8;
+
+ while (height > 0) {
+ opLineEnd = op + width;
+
+ while (op < opLineEnd) {
+ *(op++) = t[((*(uint32_t *)ip)>>shift)&0x00ffffff];
+ ip+=3;
+ }
+
+ ip += ipextra;
+ height--;
+ }
+}
+
+
+/*
+ * rfbTranslateWithRGBTablesINtoOUT translates a rectangle of pixel data
+ * using three separate lookup tables for the red, green and blue values.
+ */
+
+static void
+rfbTranslateWithRGBTables24toOUT (char *table, rfbPixelFormat *in,
+ rfbPixelFormat *out,
+ char *iptr, char *optr,
+ int bytesBetweenInputLines,
+ int width, int height)
+{
+ uint8_t *ip = (uint8_t *)iptr;
+ OUT_T *op = (OUT_T *)optr;
+ int ipextra = bytesBetweenInputLines - width*3;
+ OUT_T *opLineEnd;
+ OUT_T *redTable = (OUT_T *)table;
+ OUT_T *greenTable = redTable + in->redMax + 1;
+ OUT_T *blueTable = greenTable + in->greenMax + 1;
+ uint32_t inValue;
+ int shift = rfbEndianTest?0:8;
+
+ while (height > 0) {
+ opLineEnd = &op[width];
+
+ while (op < opLineEnd) {
+ inValue = ((*(uint32_t *)ip)>>shift)&0x00ffffff;
+ *(op++) = (redTable[(inValue >> in->redShift) & in->redMax] |
+ greenTable[(inValue >> in->greenShift) & in->greenMax] |
+ blueTable[(inValue >> in->blueShift) & in->blueMax]);
+ ip+=3;
+ }
+ ip += ipextra;
+ height--;
+ }
+}
+
+/*
+ * rfbTranslateWithSingleTableINto24 translates a rectangle of pixel data
+ * using a single lookup table.
+ */
+
+static void
+rfbTranslateWithSingleTableINto24 (char *table, rfbPixelFormat *in,
+ rfbPixelFormat *out,
+ char *iptr, char *optr,
+ int bytesBetweenInputLines,
+ int width, int height)
+{
+ IN_T *ip = (IN_T *)iptr;
+ uint8_t *op = (uint8_t *)optr;
+ int ipextra = bytesBetweenInputLines / sizeof(IN_T) - width;
+ uint8_t *opLineEnd;
+ uint8_t *t = (uint8_t *)table;
+
+ while (height > 0) {
+ opLineEnd = op + width * 3;
+
+ while (op < opLineEnd) {
+ memcpy(op,&t[3*(*(ip++))],3);
+ op += 3;
+ }
+
+ ip += ipextra;
+ height--;
+ }
+}
+
+
+/*
+ * rfbTranslateWithRGBTablesINto24 translates a rectangle of pixel data
+ * using three separate lookup tables for the red, green and blue values.
+ */
+
+static void
+rfbTranslateWithRGBTablesINto24 (char *table, rfbPixelFormat *in,
+ rfbPixelFormat *out,
+ char *iptr, char *optr,
+ int bytesBetweenInputLines,
+ int width, int height)
+{
+ IN_T *ip = (IN_T *)iptr;
+ uint8_t *op = (uint8_t *)optr;
+ int ipextra = bytesBetweenInputLines / sizeof(IN_T) - width;
+ uint8_t *opLineEnd;
+ uint8_t *redTable = (uint8_t *)table;
+ uint8_t *greenTable = redTable + 3*(in->redMax + 1);
+ uint8_t *blueTable = greenTable + 3*(in->greenMax + 1);
+ uint32_t outValue;
+
+ while (height > 0) {
+ opLineEnd = op+3*width;
+
+ while (op < opLineEnd) {
+ outValue = (redTable[(*ip >> in->redShift) & in->redMax] |
+ greenTable[(*ip >> in->greenShift) & in->greenMax] |
+ blueTable[(*ip >> in->blueShift) & in->blueMax]);
+ memcpy(op,&outValue,3);
+ op += 3;
+ ip++;
+ }
+ ip += ipextra;
+ height--;
+ }
+}
+
+#undef IN_T
+#undef OUT_T
+#undef rfbTranslateWithSingleTable24toOUT
+#undef rfbTranslateWithRGBTables24toOUT
+#undef rfbTranslateWithSingleTableINto24
+#undef rfbTranslateWithRGBTablesINto24
+
+#endif
diff --git a/libvncserver/tabletranstemplate.c b/libvncserver/tabletranstemplate.c
new file mode 100755
index 0000000..e83c623
--- /dev/null
+++ b/libvncserver/tabletranstemplate.c
@@ -0,0 +1,117 @@
+/*
+ * tabletranstemplate.c - template for translation using lookup tables.
+ *
+ * This file shouldn't be compiled. It is included multiple times by
+ * translate.c, each time with different definitions of the macros IN and OUT.
+ *
+ * For each pair of values IN and OUT, this file defines two functions for
+ * translating a given rectangle of pixel data. One uses a single lookup
+ * table, and the other uses three separate lookup tables for the red, green
+ * and blue values.
+ *
+ * I know this code isn't nice to read because of all the macros, but
+ * efficiency is important here.
+ */
+
+/*
+ * OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
+ * Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge.
+ * 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.
+ */
+
+#if !defined(IN) || !defined(OUT)
+#error "This file shouldn't be compiled."
+#error "It is included as part of translate.c"
+#endif
+
+#define IN_T CONCAT3E(uint,IN,_t)
+#define OUT_T CONCAT3E(uint,OUT,_t)
+#define rfbTranslateWithSingleTableINtoOUT \
+ CONCAT4E(rfbTranslateWithSingleTable,IN,to,OUT)
+#define rfbTranslateWithRGBTablesINtoOUT \
+ CONCAT4E(rfbTranslateWithRGBTables,IN,to,OUT)
+
+/*
+ * rfbTranslateWithSingleTableINtoOUT translates a rectangle of pixel data
+ * using a single lookup table.
+ */
+
+static void
+rfbTranslateWithSingleTableINtoOUT (char *table, rfbPixelFormat *in,
+ rfbPixelFormat *out,
+ char *iptr, char *optr,
+ int bytesBetweenInputLines,
+ int width, int height)
+{
+ IN_T *ip = (IN_T *)iptr;
+ OUT_T *op = (OUT_T *)optr;
+ int ipextra = bytesBetweenInputLines / sizeof(IN_T) - width;
+ OUT_T *opLineEnd;
+ OUT_T *t = (OUT_T *)table;
+
+ while (height > 0) {
+ opLineEnd = op + width;
+
+ while (op < opLineEnd) {
+ *(op++) = t[*(ip++)];
+ }
+
+ ip += ipextra;
+ height--;
+ }
+}
+
+
+/*
+ * rfbTranslateWithRGBTablesINtoOUT translates a rectangle of pixel data
+ * using three separate lookup tables for the red, green and blue values.
+ */
+
+static void
+rfbTranslateWithRGBTablesINtoOUT (char *table, rfbPixelFormat *in,
+ rfbPixelFormat *out,
+ char *iptr, char *optr,
+ int bytesBetweenInputLines,
+ int width, int height)
+{
+ IN_T *ip = (IN_T *)iptr;
+ OUT_T *op = (OUT_T *)optr;
+ int ipextra = bytesBetweenInputLines / sizeof(IN_T) - width;
+ OUT_T *opLineEnd;
+ OUT_T *redTable = (OUT_T *)table;
+ OUT_T *greenTable = redTable + in->redMax + 1;
+ OUT_T *blueTable = greenTable + in->greenMax + 1;
+
+ while (height > 0) {
+ opLineEnd = &op[width];
+
+ while (op < opLineEnd) {
+ *(op++) = (redTable[(*ip >> in->redShift) & in->redMax] |
+ greenTable[(*ip >> in->greenShift) & in->greenMax] |
+ blueTable[(*ip >> in->blueShift) & in->blueMax]);
+ ip++;
+ }
+ ip += ipextra;
+ height--;
+ }
+}
+
+#undef IN_T
+#undef OUT_T
+#undef rfbTranslateWithSingleTableINtoOUT
+#undef rfbTranslateWithRGBTablesINtoOUT
diff --git a/libvncserver/tight.c b/libvncserver/tight.c
new file mode 100644
index 0000000..b97adb9
--- /dev/null
+++ b/libvncserver/tight.c
@@ -0,0 +1,1820 @@
+/*
+ * tight.c
+ *
+ * Routines to implement Tight Encoding
+ */
+
+/*
+ * Copyright (C) 2000, 2001 Const Kaplinsky. All Rights Reserved.
+ * Copyright (C) 1999 AT&T Laboratories Cambridge. 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/rfb.h>
+
+#ifdef WIN32
+#define XMD_H
+#undef FAR
+#define NEEDFAR_POINTERS
+#endif
+
+#include <jpeglib.h>
+
+/* Note: The following constant should not be changed. */
+#define TIGHT_MIN_TO_COMPRESS 12
+
+/* The parameters below may be adjusted. */
+#define MIN_SPLIT_RECT_SIZE 4096
+#define MIN_SOLID_SUBRECT_SIZE 2048
+#define MAX_SPLIT_TILE_SIZE 16
+
+/* May be set to TRUE with "-lazytight" Xvnc option. */
+rfbBool rfbTightDisableGradient = FALSE;
+
+/* This variable is set on every rfbSendRectEncodingTight() call. */
+static rfbBool usePixelFormat24;
+
+
+/* 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). */
+
+typedef struct TIGHT_CONF_s {
+ int maxRectSize, maxRectWidth;
+ int monoMinRectSize, gradientMinRectSize;
+ int idxZlibLevel, monoZlibLevel, rawZlibLevel, gradientZlibLevel;
+ int gradientThreshold, gradientThreshold24;
+ int idxMaxColorsDivisor;
+ int jpegQuality, jpegThreshold, jpegThreshold24;
+} TIGHT_CONF;
+
+static TIGHT_CONF tightConf[10] = {
+ { 512, 32, 6, 65536, 0, 0, 0, 0, 0, 0, 4, 5, 10000, 23000 },
+ { 2048, 128, 6, 65536, 1, 1, 1, 0, 0, 0, 8, 10, 8000, 18000 },
+ { 6144, 256, 8, 65536, 3, 3, 2, 0, 0, 0, 24, 15, 6500, 15000 },
+ { 10240, 1024, 12, 65536, 5, 5, 3, 0, 0, 0, 32, 25, 5000, 12000 },
+ { 16384, 2048, 12, 65536, 6, 6, 4, 0, 0, 0, 32, 37, 4000, 10000 },
+ { 32768, 2048, 12, 4096, 7, 7, 5, 4, 150, 380, 32, 50, 3000, 8000 },
+ { 65536, 2048, 16, 4096, 7, 7, 6, 4, 170, 420, 48, 60, 2000, 5000 },
+ { 65536, 2048, 16, 4096, 8, 8, 7, 5, 180, 450, 64, 70, 1000, 2500 },
+ { 65536, 2048, 32, 8192, 9, 9, 8, 6, 190, 475, 64, 75, 500, 1200 },
+ { 65536, 2048, 32, 8192, 9, 9, 9, 6, 200, 500, 96, 80, 200, 500 }
+};
+
+static int compressLevel;
+static int qualityLevel;
+
+/* Stuff dealing with palettes. */
+
+typedef struct COLOR_LIST_s {
+ struct COLOR_LIST_s *next;
+ int idx;
+ uint32_t rgb;
+} COLOR_LIST;
+
+typedef struct PALETTE_ENTRY_s {
+ COLOR_LIST *listNode;
+ int numPixels;
+} PALETTE_ENTRY;
+
+typedef struct PALETTE_s {
+ PALETTE_ENTRY entry[256];
+ COLOR_LIST *hash[256];
+ COLOR_LIST list[256];
+} PALETTE;
+
+static int paletteNumColors, paletteMaxColors;
+static uint32_t monoBackground, monoForeground;
+static PALETTE palette;
+
+/* Pointers to dynamically-allocated buffers. */
+
+static int tightBeforeBufSize = 0;
+static char *tightBeforeBuf = NULL;
+
+static int tightAfterBufSize = 0;
+static char *tightAfterBuf = NULL;
+
+static int *prevRowBuf = NULL;
+
+void TightCleanup()
+{
+ if(tightBeforeBufSize) {
+ free(tightBeforeBuf);
+ tightBeforeBufSize=0;
+ }
+ if(tightAfterBufSize) {
+ free(tightAfterBuf);
+ tightAfterBufSize=0;
+ }
+}
+
+/* Prototypes for static functions. */
+
+static void FindBestSolidArea (rfbClientPtr cl, int x, int y, int w, int h,
+ uint32_t colorValue, int *w_ptr, int *h_ptr);
+static void ExtendSolidArea (rfbClientPtr cl, int x, int y, int w, int h,
+ uint32_t colorValue,
+ int *x_ptr, int *y_ptr, int *w_ptr, int *h_ptr);
+static rfbBool CheckSolidTile (rfbClientPtr cl, int x, int y, int w, int h,
+ uint32_t *colorPtr, rfbBool needSameColor);
+static rfbBool CheckSolidTile8 (rfbClientPtr cl, int x, int y, int w, int h,
+ uint32_t *colorPtr, rfbBool needSameColor);
+static rfbBool CheckSolidTile16 (rfbClientPtr cl, int x, int y, int w, int h,
+ uint32_t *colorPtr, rfbBool needSameColor);
+static rfbBool CheckSolidTile32 (rfbClientPtr cl, int x, int y, int w, int h,
+ uint32_t *colorPtr, rfbBool needSameColor);
+
+static rfbBool SendRectSimple (rfbClientPtr cl, int x, int y, int w, int h);
+static rfbBool SendSubrect (rfbClientPtr cl, int x, int y, int w, int h);
+static rfbBool SendTightHeader (rfbClientPtr cl, int x, int y, int w, int h);
+
+static rfbBool SendSolidRect (rfbClientPtr cl);
+static rfbBool SendMonoRect (rfbClientPtr cl, int w, int h);
+static rfbBool SendIndexedRect (rfbClientPtr cl, int w, int h);
+static rfbBool SendFullColorRect (rfbClientPtr cl, int w, int h);
+static rfbBool SendGradientRect (rfbClientPtr cl, int w, int h);
+
+static rfbBool CompressData(rfbClientPtr cl, int streamId, int dataLen,
+ int zlibLevel, int zlibStrategy);
+static rfbBool SendCompressedData(rfbClientPtr cl, int compressedLen);
+
+static void FillPalette8(int count);
+static void FillPalette16(int count);
+static void FillPalette32(int count);
+
+static void PaletteReset(void);
+static int PaletteInsert(uint32_t rgb, int numPixels, int bpp);
+
+static void Pack24(rfbClientPtr cl, char *buf, rfbPixelFormat *fmt, int count);
+
+static void EncodeIndexedRect16(uint8_t *buf, int count);
+static void EncodeIndexedRect32(uint8_t *buf, int count);
+
+static void EncodeMonoRect8(uint8_t *buf, int w, int h);
+static void EncodeMonoRect16(uint8_t *buf, int w, int h);
+static void EncodeMonoRect32(uint8_t *buf, int w, int h);
+
+static void FilterGradient24(rfbClientPtr cl, char *buf, rfbPixelFormat *fmt, int w, int h);
+static void FilterGradient16(rfbClientPtr cl, uint16_t *buf, rfbPixelFormat *fmt, int w, int h);
+static void FilterGradient32(rfbClientPtr cl, uint32_t *buf, rfbPixelFormat *fmt, int w, int h);
+
+static int DetectSmoothImage(rfbClientPtr cl, rfbPixelFormat *fmt, int w, int h);
+static unsigned long DetectSmoothImage24(rfbClientPtr cl, rfbPixelFormat *fmt, int w, int h);
+static unsigned long DetectSmoothImage16(rfbClientPtr cl, rfbPixelFormat *fmt, int w, int h);
+static unsigned long DetectSmoothImage32(rfbClientPtr cl, rfbPixelFormat *fmt, int w, int h);
+
+static rfbBool SendJpegRect(rfbClientPtr cl, int x, int y, int w, int h,
+ int quality);
+static void PrepareRowForJpeg(rfbClientPtr cl, uint8_t *dst, int x, int y, int count);
+static void PrepareRowForJpeg24(rfbClientPtr cl, uint8_t *dst, int x, int y, int count);
+static void PrepareRowForJpeg16(rfbClientPtr cl, uint8_t *dst, int x, int y, int count);
+static void PrepareRowForJpeg32(rfbClientPtr cl, uint8_t *dst, int x, int y, int count);
+
+static void JpegInitDestination(j_compress_ptr cinfo);
+static boolean JpegEmptyOutputBuffer(j_compress_ptr cinfo);
+static void JpegTermDestination(j_compress_ptr cinfo);
+static void JpegSetDstManager(j_compress_ptr cinfo);
+
+
+/*
+ * Tight encoding implementation.
+ */
+
+int
+rfbNumCodedRectsTight(cl, x, y, w, h)
+ rfbClientPtr cl;
+ int x, y, w, h;
+{
+ int maxRectSize, maxRectWidth;
+ int subrectMaxWidth, subrectMaxHeight;
+
+ /* No matter how many rectangles we will send if LastRect markers
+ are used to terminate rectangle stream. */
+ if (cl->enableLastRectEncoding && w * h >= MIN_SPLIT_RECT_SIZE)
+ return 0;
+
+ maxRectSize = tightConf[cl->tightCompressLevel].maxRectSize;
+ maxRectWidth = tightConf[cl->tightCompressLevel].maxRectWidth;
+
+ if (w > maxRectWidth || w * h > maxRectSize) {
+ subrectMaxWidth = (w > maxRectWidth) ? maxRectWidth : w;
+ subrectMaxHeight = maxRectSize / subrectMaxWidth;
+ return (((w - 1) / maxRectWidth + 1) *
+ ((h - 1) / subrectMaxHeight + 1));
+ } else {
+ return 1;
+ }
+}
+
+rfbBool
+rfbSendRectEncodingTight(cl, x, y, w, h)
+ rfbClientPtr cl;
+ int x, y, w, h;
+{
+ int nMaxRows;
+ uint32_t colorValue;
+ int dx, dy, dw, dh;
+ int x_best, y_best, w_best, h_best;
+ char *fbptr;
+
+ rfbSendUpdateBuf(cl);
+
+ compressLevel = cl->tightCompressLevel;
+ qualityLevel = cl->tightQualityLevel;
+
+ if ( cl->format.depth == 24 && cl->format.redMax == 0xFF &&
+ cl->format.greenMax == 0xFF && cl->format.blueMax == 0xFF ) {
+ usePixelFormat24 = TRUE;
+ } else {
+ usePixelFormat24 = FALSE;
+ }
+
+ if (!cl->enableLastRectEncoding || w * h < MIN_SPLIT_RECT_SIZE)
+ return SendRectSimple(cl, x, y, w, h);
+
+ /* Make sure we can write at least one pixel into tightBeforeBuf. */
+
+ if (tightBeforeBufSize < 4) {
+ tightBeforeBufSize = 4;
+ if (tightBeforeBuf == NULL)
+ tightBeforeBuf = (char *)malloc(tightBeforeBufSize);
+ else
+ tightBeforeBuf = (char *)realloc(tightBeforeBuf,
+ tightBeforeBufSize);
+ }
+
+ /* Calculate maximum number of rows in one non-solid rectangle. */
+
+ {
+ int maxRectSize, maxRectWidth, nMaxWidth;
+
+ maxRectSize = tightConf[compressLevel].maxRectSize;
+ maxRectWidth = tightConf[compressLevel].maxRectWidth;
+ nMaxWidth = (w > maxRectWidth) ? maxRectWidth : w;
+ nMaxRows = maxRectSize / nMaxWidth;
+ }
+
+ /* Try to find large solid-color areas and send them separately. */
+
+ for (dy = y; dy < y + h; dy += MAX_SPLIT_TILE_SIZE) {
+
+ /* If a rectangle becomes too large, send its upper part now. */
+
+ if (dy - y >= nMaxRows) {
+ if (!SendRectSimple(cl, x, y, w, nMaxRows))
+ return 0;
+ y += nMaxRows;
+ h -= nMaxRows;
+ }
+
+ dh = (dy + MAX_SPLIT_TILE_SIZE <= y + h) ?
+ MAX_SPLIT_TILE_SIZE : (y + h - dy);
+
+ for (dx = x; dx < x + w; dx += MAX_SPLIT_TILE_SIZE) {
+
+ dw = (dx + MAX_SPLIT_TILE_SIZE <= x + w) ?
+ MAX_SPLIT_TILE_SIZE : (x + w - dx);
+
+ if (CheckSolidTile(cl, dx, dy, dw, dh, &colorValue, FALSE)) {
+
+ /* Get dimensions of solid-color area. */
+
+ FindBestSolidArea(cl, dx, dy, w - (dx - x), h - (dy - y),
+ colorValue, &w_best, &h_best);
+
+ /* Make sure a solid rectangle is large enough
+ (or the whole rectangle is of the same color). */
+
+ if ( w_best * h_best != w * h &&
+ w_best * h_best < MIN_SOLID_SUBRECT_SIZE )
+ continue;
+
+ /* Try to extend solid rectangle to maximum size. */
+
+ x_best = dx; y_best = dy;
+ ExtendSolidArea(cl, x, y, w, h, colorValue,
+ &x_best, &y_best, &w_best, &h_best);
+
+ /* Send rectangles at top and left to solid-color area. */
+
+ if ( y_best != y &&
+ !SendRectSimple(cl, x, y, w, y_best-y) )
+ return FALSE;
+ if ( x_best != x &&
+ !rfbSendRectEncodingTight(cl, x, y_best,
+ x_best-x, h_best) )
+ return FALSE;
+
+ /* Send solid-color rectangle. */
+
+ if (!SendTightHeader(cl, x_best, y_best, w_best, h_best))
+ return FALSE;
+
+ fbptr = (cl->screen->frameBuffer +
+ (cl->screen->paddedWidthInBytes * y_best) +
+ (x_best * (cl->screen->bitsPerPixel / 8)));
+
+ (*cl->translateFn)(cl->translateLookupTable, &cl->screen->rfbServerFormat,
+ &cl->format, fbptr, tightBeforeBuf,
+ cl->screen->paddedWidthInBytes, 1, 1);
+
+ if (!SendSolidRect(cl))
+ return FALSE;
+
+ /* Send remaining rectangles (at right and bottom). */
+
+ if ( x_best + w_best != x + w &&
+ !rfbSendRectEncodingTight(cl, x_best+w_best, y_best,
+ w-(x_best-x)-w_best, h_best) )
+ return FALSE;
+ if ( y_best + h_best != y + h &&
+ !rfbSendRectEncodingTight(cl, x, y_best+h_best,
+ w, h-(y_best-y)-h_best) )
+ return FALSE;
+
+ /* Return after all recursive calls are done. */
+
+ return TRUE;
+ }
+
+ }
+
+ }
+
+ /* No suitable solid-color rectangles found. */
+
+ return SendRectSimple(cl, x, y, w, h);
+}
+
+static void
+FindBestSolidArea(cl, x, y, w, h, colorValue, w_ptr, h_ptr)
+ rfbClientPtr cl;
+ int x, y, w, h;
+ uint32_t colorValue;
+ int *w_ptr, *h_ptr;
+{
+ int dx, dy, dw, dh;
+ int w_prev;
+ int w_best = 0, h_best = 0;
+
+ w_prev = w;
+
+ for (dy = y; dy < y + h; dy += MAX_SPLIT_TILE_SIZE) {
+
+ dh = (dy + MAX_SPLIT_TILE_SIZE <= y + h) ?
+ MAX_SPLIT_TILE_SIZE : (y + h - dy);
+ dw = (w_prev > MAX_SPLIT_TILE_SIZE) ?
+ MAX_SPLIT_TILE_SIZE : w_prev;
+
+ if (!CheckSolidTile(cl, x, dy, dw, dh, &colorValue, TRUE))
+ break;
+
+ for (dx = x + dw; dx < x + w_prev;) {
+ dw = (dx + MAX_SPLIT_TILE_SIZE <= x + w_prev) ?
+ MAX_SPLIT_TILE_SIZE : (x + w_prev - dx);
+ if (!CheckSolidTile(cl, dx, dy, dw, dh, &colorValue, TRUE))
+ break;
+ dx += dw;
+ }
+
+ w_prev = dx - x;
+ if (w_prev * (dy + dh - y) > w_best * h_best) {
+ w_best = w_prev;
+ h_best = dy + dh - y;
+ }
+ }
+
+ *w_ptr = w_best;
+ *h_ptr = h_best;
+}
+
+static void
+ExtendSolidArea(cl, x, y, w, h, colorValue, x_ptr, y_ptr, w_ptr, h_ptr)
+ rfbClientPtr cl;
+ int x, y, w, h;
+ uint32_t colorValue;
+ int *x_ptr, *y_ptr, *w_ptr, *h_ptr;
+{
+ int cx, cy;
+
+ /* Try to extend the area upwards. */
+ for ( cy = *y_ptr - 1;
+ cy >= y && CheckSolidTile(cl, *x_ptr, cy, *w_ptr, 1, &colorValue, TRUE);
+ cy-- );
+ *h_ptr += *y_ptr - (cy + 1);
+ *y_ptr = cy + 1;
+
+ /* ... downwards. */
+ for ( cy = *y_ptr + *h_ptr;
+ cy < y + h &&
+ CheckSolidTile(cl, *x_ptr, cy, *w_ptr, 1, &colorValue, TRUE);
+ cy++ );
+ *h_ptr += cy - (*y_ptr + *h_ptr);
+
+ /* ... to the left. */
+ for ( cx = *x_ptr - 1;
+ cx >= x && CheckSolidTile(cl, cx, *y_ptr, 1, *h_ptr, &colorValue, TRUE);
+ cx-- );
+ *w_ptr += *x_ptr - (cx + 1);
+ *x_ptr = cx + 1;
+
+ /* ... to the right. */
+ for ( cx = *x_ptr + *w_ptr;
+ cx < x + w &&
+ CheckSolidTile(cl, cx, *y_ptr, 1, *h_ptr, &colorValue, TRUE);
+ cx++ );
+ *w_ptr += cx - (*x_ptr + *w_ptr);
+}
+
+/*
+ * Check if a rectangle is all of the same color. If needSameColor is
+ * set to non-zero, then also check that its color equals to the
+ * *colorPtr value. The result is 1 if the test is successfull, and in
+ * that case new color will be stored in *colorPtr.
+ */
+
+static rfbBool CheckSolidTile(rfbClientPtr cl, int x, int y, int w, int h, uint32_t* colorPtr, rfbBool needSameColor)
+{
+ switch(cl->screen->rfbServerFormat.bitsPerPixel) {
+ case 32:
+ return CheckSolidTile32(cl, x, y, w, h, colorPtr, needSameColor);
+ case 16:
+ return CheckSolidTile16(cl, x, y, w, h, colorPtr, needSameColor);
+ default:
+ return CheckSolidTile8(cl, x, y, w, h, colorPtr, needSameColor);
+ }
+}
+
+#define DEFINE_CHECK_SOLID_FUNCTION(bpp) \
+ \
+static rfbBool \
+CheckSolidTile##bpp(rfbClientPtr cl, int x, int y, int w, int h, uint32_t* colorPtr, rfbBool needSameColor) \
+{ \
+ uint##bpp##_t *fbptr; \
+ uint##bpp##_t colorValue; \
+ int dx, dy; \
+ \
+ fbptr = (uint##bpp##_t *) \
+ &cl->screen->frameBuffer[y * cl->screen->paddedWidthInBytes + x * (bpp/8)]; \
+ \
+ colorValue = *fbptr; \
+ if (needSameColor && (uint32_t)colorValue != *colorPtr) \
+ return FALSE; \
+ \
+ for (dy = 0; dy < h; dy++) { \
+ for (dx = 0; dx < w; dx++) { \
+ if (colorValue != fbptr[dx]) \
+ return FALSE; \
+ } \
+ fbptr = (uint##bpp##_t *)((uint8_t *)fbptr + cl->screen->paddedWidthInBytes); \
+ } \
+ \
+ *colorPtr = (uint32_t)colorValue; \
+ return TRUE; \
+}
+
+DEFINE_CHECK_SOLID_FUNCTION(8)
+DEFINE_CHECK_SOLID_FUNCTION(16)
+DEFINE_CHECK_SOLID_FUNCTION(32)
+
+static rfbBool
+SendRectSimple(cl, x, y, w, h)
+ rfbClientPtr cl;
+ int x, y, w, h;
+{
+ int maxBeforeSize, maxAfterSize;
+ int maxRectSize, maxRectWidth;
+ int subrectMaxWidth, subrectMaxHeight;
+ int dx, dy;
+ int rw, rh;
+
+ maxRectSize = tightConf[compressLevel].maxRectSize;
+ maxRectWidth = tightConf[compressLevel].maxRectWidth;
+
+ maxBeforeSize = maxRectSize * (cl->format.bitsPerPixel / 8);
+ maxAfterSize = maxBeforeSize + (maxBeforeSize + 99) / 100 + 12;
+
+ if (tightBeforeBufSize < maxBeforeSize) {
+ tightBeforeBufSize = maxBeforeSize;
+ if (tightBeforeBuf == NULL)
+ tightBeforeBuf = (char *)malloc(tightBeforeBufSize);
+ else
+ tightBeforeBuf = (char *)realloc(tightBeforeBuf,
+ tightBeforeBufSize);
+ }
+
+ if (tightAfterBufSize < maxAfterSize) {
+ tightAfterBufSize = maxAfterSize;
+ if (tightAfterBuf == NULL)
+ tightAfterBuf = (char *)malloc(tightAfterBufSize);
+ else
+ tightAfterBuf = (char *)realloc(tightAfterBuf,
+ tightAfterBufSize);
+ }
+
+ if (w > maxRectWidth || w * h > maxRectSize) {
+ subrectMaxWidth = (w > maxRectWidth) ? maxRectWidth : w;
+ subrectMaxHeight = maxRectSize / subrectMaxWidth;
+
+ for (dy = 0; dy < h; dy += subrectMaxHeight) {
+ for (dx = 0; dx < w; dx += maxRectWidth) {
+ rw = (dx + maxRectWidth < w) ? maxRectWidth : w - dx;
+ rh = (dy + subrectMaxHeight < h) ? subrectMaxHeight : h - dy;
+ if (!SendSubrect(cl, x+dx, y+dy, rw, rh))
+ return FALSE;
+ }
+ }
+ } else {
+ if (!SendSubrect(cl, x, y, w, h))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static rfbBool
+SendSubrect(cl, x, y, w, h)
+ rfbClientPtr cl;
+ int x, y, w, h;
+{
+ char *fbptr;
+ rfbBool success = FALSE;
+
+ /* Send pending data if there is more than 128 bytes. */
+ if (cl->ublen > 128) {
+ if (!rfbSendUpdateBuf(cl))
+ return FALSE;
+ }
+
+ if (!SendTightHeader(cl, x, y, w, h))
+ return FALSE;
+
+ fbptr = (cl->screen->frameBuffer + (cl->screen->paddedWidthInBytes * y)
+ + (x * (cl->screen->bitsPerPixel / 8)));
+
+ (*cl->translateFn)(cl->translateLookupTable, &cl->screen->rfbServerFormat,
+ &cl->format, fbptr, tightBeforeBuf,
+ cl->screen->paddedWidthInBytes, w, h);
+
+ paletteMaxColors = w * h / tightConf[compressLevel].idxMaxColorsDivisor;
+ if ( paletteMaxColors < 2 &&
+ w * h >= tightConf[compressLevel].monoMinRectSize ) {
+ paletteMaxColors = 2;
+ }
+ switch (cl->format.bitsPerPixel) {
+ case 8:
+ FillPalette8(w * h);
+ break;
+ case 16:
+ FillPalette16(w * h);
+ break;
+ default:
+ FillPalette32(w * h);
+ }
+
+ switch (paletteNumColors) {
+ case 0:
+ /* Truecolor image */
+ if (DetectSmoothImage(cl, &cl->format, w, h)) {
+ if (qualityLevel != -1) {
+ success = SendJpegRect(cl, x, y, w, h,
+ tightConf[qualityLevel].jpegQuality);
+ } else {
+ success = SendGradientRect(cl, w, h);
+ }
+ } else {
+ success = SendFullColorRect(cl, w, h);
+ }
+ break;
+ case 1:
+ /* Solid rectangle */
+ success = SendSolidRect(cl);
+ break;
+ case 2:
+ /* Two-color rectangle */
+ success = SendMonoRect(cl, w, h);
+ break;
+ default:
+ /* Up to 256 different colors */
+ if ( paletteNumColors > 96 &&
+ qualityLevel != -1 && qualityLevel <= 3 &&
+ DetectSmoothImage(cl, &cl->format, w, h) ) {
+ success = SendJpegRect(cl, x, y, w, h,
+ tightConf[qualityLevel].jpegQuality);
+ } else {
+ success = SendIndexedRect(cl, w, h);
+ }
+ }
+ return success;
+}
+
+static rfbBool
+SendTightHeader(cl, x, y, w, h)
+ rfbClientPtr cl;
+ int x, y, w, h;
+{
+ rfbFramebufferUpdateRectHeader rect;
+
+ if (cl->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) {
+ if (!rfbSendUpdateBuf(cl))
+ return FALSE;
+ }
+
+ rect.r.x = Swap16IfLE(x);
+ rect.r.y = Swap16IfLE(y);
+ rect.r.w = Swap16IfLE(w);
+ rect.r.h = Swap16IfLE(h);
+ rect.encoding = Swap32IfLE(rfbEncodingTight);
+
+ memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
+ sz_rfbFramebufferUpdateRectHeader);
+ cl->ublen += sz_rfbFramebufferUpdateRectHeader;
+
+ cl->rfbRectanglesSent[rfbEncodingTight]++;
+ cl->rfbBytesSent[rfbEncodingTight] += sz_rfbFramebufferUpdateRectHeader;
+
+ return TRUE;
+}
+
+/*
+ * Subencoding implementations.
+ */
+
+static rfbBool
+SendSolidRect(cl)
+ rfbClientPtr cl;
+{
+ int len;
+
+ if (usePixelFormat24) {
+ Pack24(cl, tightBeforeBuf, &cl->format, 1);
+ len = 3;
+ } else
+ len = cl->format.bitsPerPixel / 8;
+
+ if (cl->ublen + 1 + len > UPDATE_BUF_SIZE) {
+ if (!rfbSendUpdateBuf(cl))
+ return FALSE;
+ }
+
+ cl->updateBuf[cl->ublen++] = (char)(rfbTightFill << 4);
+ memcpy (&cl->updateBuf[cl->ublen], tightBeforeBuf, len);
+ cl->ublen += len;
+
+ cl->rfbBytesSent[rfbEncodingTight] += len + 1;
+
+ return TRUE;
+}
+
+static rfbBool
+SendMonoRect(cl, w, h)
+ rfbClientPtr cl;
+ int w, h;
+{
+ int streamId = 1;
+ int paletteLen, dataLen;
+
+ if ( cl->ublen + TIGHT_MIN_TO_COMPRESS + 6 +
+ 2 * cl->format.bitsPerPixel / 8 > UPDATE_BUF_SIZE ) {
+ if (!rfbSendUpdateBuf(cl))
+ return FALSE;
+ }
+
+ /* Prepare tight encoding header. */
+ dataLen = (w + 7) / 8;
+ dataLen *= h;
+
+ cl->updateBuf[cl->ublen++] = (streamId | rfbTightExplicitFilter) << 4;
+ cl->updateBuf[cl->ublen++] = rfbTightFilterPalette;
+ cl->updateBuf[cl->ublen++] = 1;
+
+ /* Prepare palette, convert image. */
+ switch (cl->format.bitsPerPixel) {
+
+ case 32:
+ EncodeMonoRect32((uint8_t *)tightBeforeBuf, w, h);
+
+ ((uint32_t *)tightAfterBuf)[0] = monoBackground;
+ ((uint32_t *)tightAfterBuf)[1] = monoForeground;
+ if (usePixelFormat24) {
+ Pack24(cl, tightAfterBuf, &cl->format, 2);
+ paletteLen = 6;
+ } else
+ paletteLen = 8;
+
+ memcpy(&cl->updateBuf[cl->ublen], tightAfterBuf, paletteLen);
+ cl->ublen += paletteLen;
+ cl->rfbBytesSent[rfbEncodingTight] += 3 + paletteLen;
+ break;
+
+ case 16:
+ EncodeMonoRect16((uint8_t *)tightBeforeBuf, w, h);
+
+ ((uint16_t *)tightAfterBuf)[0] = (uint16_t)monoBackground;
+ ((uint16_t *)tightAfterBuf)[1] = (uint16_t)monoForeground;
+
+ memcpy(&cl->updateBuf[cl->ublen], tightAfterBuf, 4);
+ cl->ublen += 4;
+ cl->rfbBytesSent[rfbEncodingTight] += 7;
+ break;
+
+ default:
+ EncodeMonoRect8((uint8_t *)tightBeforeBuf, w, h);
+
+ cl->updateBuf[cl->ublen++] = (char)monoBackground;
+ cl->updateBuf[cl->ublen++] = (char)monoForeground;
+ cl->rfbBytesSent[rfbEncodingTight] += 5;
+ }
+
+ return CompressData(cl, streamId, dataLen,
+ tightConf[compressLevel].monoZlibLevel,
+ Z_DEFAULT_STRATEGY);
+}
+
+static rfbBool
+SendIndexedRect(cl, w, h)
+ rfbClientPtr cl;
+ int w, h;
+{
+ int streamId = 2;
+ int i, entryLen;
+
+ if ( cl->ublen + TIGHT_MIN_TO_COMPRESS + 6 +
+ paletteNumColors * cl->format.bitsPerPixel / 8 >
+ UPDATE_BUF_SIZE ) {
+ if (!rfbSendUpdateBuf(cl))
+ return FALSE;
+ }
+
+ /* Prepare tight encoding header. */
+ cl->updateBuf[cl->ublen++] = (streamId | rfbTightExplicitFilter) << 4;
+ cl->updateBuf[cl->ublen++] = rfbTightFilterPalette;
+ cl->updateBuf[cl->ublen++] = (char)(paletteNumColors - 1);
+
+ /* Prepare palette, convert image. */
+ switch (cl->format.bitsPerPixel) {
+
+ case 32:
+ EncodeIndexedRect32((uint8_t *)tightBeforeBuf, w * h);
+
+ for (i = 0; i < paletteNumColors; i++) {
+ ((uint32_t *)tightAfterBuf)[i] =
+ palette.entry[i].listNode->rgb;
+ }
+ if (usePixelFormat24) {
+ Pack24(cl, tightAfterBuf, &cl->format, paletteNumColors);
+ entryLen = 3;
+ } else
+ entryLen = 4;
+
+ memcpy(&cl->updateBuf[cl->ublen], tightAfterBuf, paletteNumColors * entryLen);
+ cl->ublen += paletteNumColors * entryLen;
+ cl->rfbBytesSent[rfbEncodingTight] += 3 + paletteNumColors * entryLen;
+ break;
+
+ case 16:
+ EncodeIndexedRect16((uint8_t *)tightBeforeBuf, w * h);
+
+ for (i = 0; i < paletteNumColors; i++) {
+ ((uint16_t *)tightAfterBuf)[i] =
+ (uint16_t)palette.entry[i].listNode->rgb;
+ }
+
+ memcpy(&cl->updateBuf[cl->ublen], tightAfterBuf, paletteNumColors * 2);
+ cl->ublen += paletteNumColors * 2;
+ cl->rfbBytesSent[rfbEncodingTight] += 3 + paletteNumColors * 2;
+ break;
+
+ default:
+ return FALSE; /* Should never happen. */
+ }
+
+ return CompressData(cl, streamId, w * h,
+ tightConf[compressLevel].idxZlibLevel,
+ Z_DEFAULT_STRATEGY);
+}
+
+static rfbBool
+SendFullColorRect(cl, w, h)
+ rfbClientPtr cl;
+ int w, h;
+{
+ int streamId = 0;
+ int len;
+
+ if (cl->ublen + TIGHT_MIN_TO_COMPRESS + 1 > UPDATE_BUF_SIZE) {
+ if (!rfbSendUpdateBuf(cl))
+ return FALSE;
+ }
+
+ cl->updateBuf[cl->ublen++] = 0x00; /* stream id = 0, no flushing, no filter */
+ cl->rfbBytesSent[rfbEncodingTight]++;
+
+ if (usePixelFormat24) {
+ Pack24(cl, tightBeforeBuf, &cl->format, w * h);
+ len = 3;
+ } else
+ len = cl->format.bitsPerPixel / 8;
+
+ return CompressData(cl, streamId, w * h * len,
+ tightConf[compressLevel].rawZlibLevel,
+ Z_DEFAULT_STRATEGY);
+}
+
+static rfbBool
+SendGradientRect(cl, w, h)
+ rfbClientPtr cl;
+ int w, h;
+{
+ int streamId = 3;
+ int len;
+
+ if (cl->format.bitsPerPixel == 8)
+ return SendFullColorRect(cl, w, h);
+
+ if (cl->ublen + TIGHT_MIN_TO_COMPRESS + 2 > UPDATE_BUF_SIZE) {
+ if (!rfbSendUpdateBuf(cl))
+ return FALSE;
+ }
+
+ if (prevRowBuf == NULL)
+ prevRowBuf = (int *)malloc(2048 * 3 * sizeof(int));
+
+ cl->updateBuf[cl->ublen++] = (streamId | rfbTightExplicitFilter) << 4;
+ cl->updateBuf[cl->ublen++] = rfbTightFilterGradient;
+ cl->rfbBytesSent[rfbEncodingTight] += 2;
+
+ if (usePixelFormat24) {
+ FilterGradient24(cl, tightBeforeBuf, &cl->format, w, h);
+ len = 3;
+ } else if (cl->format.bitsPerPixel == 32) {
+ FilterGradient32(cl, (uint32_t *)tightBeforeBuf, &cl->format, w, h);
+ len = 4;
+ } else {
+ FilterGradient16(cl, (uint16_t *)tightBeforeBuf, &cl->format, w, h);
+ len = 2;
+ }
+
+ return CompressData(cl, streamId, w * h * len,
+ tightConf[compressLevel].gradientZlibLevel,
+ Z_FILTERED);
+}
+
+static rfbBool
+CompressData(cl, streamId, dataLen, zlibLevel, zlibStrategy)
+ rfbClientPtr cl;
+ int streamId, dataLen, zlibLevel, zlibStrategy;
+{
+ z_streamp pz;
+ int err;
+
+ if (dataLen < TIGHT_MIN_TO_COMPRESS) {
+ memcpy(&cl->updateBuf[cl->ublen], tightBeforeBuf, dataLen);
+ cl->ublen += dataLen;
+ cl->rfbBytesSent[rfbEncodingTight] += dataLen;
+ return TRUE;
+ }
+
+ pz = &cl->zsStruct[streamId];
+
+ /* Initialize compression stream if needed. */
+ if (!cl->zsActive[streamId]) {
+ pz->zalloc = Z_NULL;
+ pz->zfree = Z_NULL;
+ pz->opaque = Z_NULL;
+
+ err = deflateInit2 (pz, zlibLevel, Z_DEFLATED, MAX_WBITS,
+ MAX_MEM_LEVEL, zlibStrategy);
+ if (err != Z_OK)
+ return FALSE;
+
+ cl->zsActive[streamId] = TRUE;
+ cl->zsLevel[streamId] = zlibLevel;
+ }
+
+ /* Prepare buffer pointers. */
+ pz->next_in = (Bytef *)tightBeforeBuf;
+ pz->avail_in = dataLen;
+ pz->next_out = (Bytef *)tightAfterBuf;
+ pz->avail_out = tightAfterBufSize;
+
+ /* Change compression parameters if needed. */
+ if (zlibLevel != cl->zsLevel[streamId]) {
+ if (deflateParams (pz, zlibLevel, zlibStrategy) != Z_OK) {
+ return FALSE;
+ }
+ cl->zsLevel[streamId] = zlibLevel;
+ }
+
+ /* Actual compression. */
+ if ( deflate (pz, Z_SYNC_FLUSH) != Z_OK ||
+ pz->avail_in != 0 || pz->avail_out == 0 ) {
+ return FALSE;
+ }
+
+ return SendCompressedData(cl, tightAfterBufSize - pz->avail_out);
+}
+
+static rfbBool SendCompressedData(cl, compressedLen)
+ rfbClientPtr cl;
+ int compressedLen;
+{
+ int i, portionLen;
+
+ cl->updateBuf[cl->ublen++] = compressedLen & 0x7F;
+ cl->rfbBytesSent[rfbEncodingTight]++;
+ if (compressedLen > 0x7F) {
+ cl->updateBuf[cl->ublen-1] |= 0x80;
+ cl->updateBuf[cl->ublen++] = compressedLen >> 7 & 0x7F;
+ cl->rfbBytesSent[rfbEncodingTight]++;
+ if (compressedLen > 0x3FFF) {
+ cl->updateBuf[cl->ublen-1] |= 0x80;
+ cl->updateBuf[cl->ublen++] = compressedLen >> 14 & 0xFF;
+ cl->rfbBytesSent[rfbEncodingTight]++;
+ }
+ }
+
+ portionLen = UPDATE_BUF_SIZE;
+ for (i = 0; i < compressedLen; i += portionLen) {
+ if (i + portionLen > compressedLen) {
+ portionLen = compressedLen - i;
+ }
+ if (cl->ublen + portionLen > UPDATE_BUF_SIZE) {
+ if (!rfbSendUpdateBuf(cl))
+ return FALSE;
+ }
+ memcpy(&cl->updateBuf[cl->ublen], &tightAfterBuf[i], portionLen);
+ cl->ublen += portionLen;
+ }
+ cl->rfbBytesSent[rfbEncodingTight] += compressedLen;
+
+ return TRUE;
+}
+
+/*
+ * Code to determine how many different colors used in rectangle.
+ */
+
+static void
+FillPalette8(count)
+ int count;
+{
+ uint8_t *data = (uint8_t *)tightBeforeBuf;
+ uint8_t c0, c1;
+ int i, n0, n1;
+
+ paletteNumColors = 0;
+
+ c0 = data[0];
+ for (i = 1; i < count && data[i] == c0; i++);
+ if (i == count) {
+ paletteNumColors = 1;
+ return; /* Solid rectangle */
+ }
+
+ if (paletteMaxColors < 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) {
+ monoBackground = (uint32_t)c0;
+ monoForeground = (uint32_t)c1;
+ } else {
+ monoBackground = (uint32_t)c1;
+ monoForeground = (uint32_t)c0;
+ }
+ paletteNumColors = 2; /* Two colors */
+ }
+}
+
+#define DEFINE_FILL_PALETTE_FUNCTION(bpp) \
+ \
+static void \
+FillPalette##bpp(count) \
+ int count; \
+{ \
+ uint##bpp##_t *data = (uint##bpp##_t *)tightBeforeBuf; \
+ uint##bpp##_t c0, c1, ci; \
+ int i, n0, n1, ni; \
+ \
+ c0 = data[0]; \
+ for (i = 1; i < count && data[i] == c0; i++); \
+ if (i >= count) { \
+ paletteNumColors = 1; /* Solid rectangle */ \
+ return; \
+ } \
+ \
+ if (paletteMaxColors < 2) { \
+ paletteNumColors = 0; /* Full-color encoding 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) { \
+ monoBackground = (uint32_t)c0; \
+ monoForeground = (uint32_t)c1; \
+ } else { \
+ monoBackground = (uint32_t)c1; \
+ monoForeground = (uint32_t)c0; \
+ } \
+ paletteNumColors = 2; /* Two colors */ \
+ return; \
+ } \
+ \
+ PaletteReset(); \
+ PaletteInsert (c0, (uint32_t)n0, bpp); \
+ PaletteInsert (c1, (uint32_t)n1, bpp); \
+ \
+ ni = 1; \
+ for (i++; i < count; i++) { \
+ if (data[i] == ci) { \
+ ni++; \
+ } else { \
+ if (!PaletteInsert (ci, (uint32_t)ni, bpp)) \
+ return; \
+ ci = data[i]; \
+ ni = 1; \
+ } \
+ } \
+ PaletteInsert (ci, (uint32_t)ni, bpp); \
+}
+
+DEFINE_FILL_PALETTE_FUNCTION(16)
+DEFINE_FILL_PALETTE_FUNCTION(32)
+
+
+/*
+ * Functions to operate with 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)
+{
+ paletteNumColors = 0;
+ memset(palette.hash, 0, 256 * sizeof(COLOR_LIST *));
+}
+
+static int
+PaletteInsert(rgb, numPixels, bpp)
+ uint32_t rgb;
+ int numPixels;
+ int bpp;
+{
+ COLOR_LIST *pnode;
+ COLOR_LIST *prev_pnode = NULL;
+ int hash_key, idx, new_idx, count;
+
+ hash_key = (bpp == 16) ? HASH_FUNC16(rgb) : HASH_FUNC32(rgb);
+
+ pnode = palette.hash[hash_key];
+
+ while (pnode != NULL) {
+ if (pnode->rgb == rgb) {
+ /* Such palette entry already exists. */
+ new_idx = idx = pnode->idx;
+ count = palette.entry[idx].numPixels + numPixels;
+ if (new_idx && palette.entry[new_idx-1].numPixels < count) {
+ do {
+ palette.entry[new_idx] = palette.entry[new_idx-1];
+ palette.entry[new_idx].listNode->idx = new_idx;
+ new_idx--;
+ }
+ while (new_idx && palette.entry[new_idx-1].numPixels < count);
+ palette.entry[new_idx].listNode = pnode;
+ pnode->idx = new_idx;
+ }
+ palette.entry[new_idx].numPixels = count;
+ return paletteNumColors;
+ }
+ prev_pnode = pnode;
+ pnode = pnode->next;
+ }
+
+ /* Check if palette is full. */
+ if (paletteNumColors == 256 || paletteNumColors == paletteMaxColors) {
+ paletteNumColors = 0;
+ return 0;
+ }
+
+ /* Move palette entries with lesser pixel counts. */
+ for ( idx = paletteNumColors;
+ idx > 0 && palette.entry[idx-1].numPixels < numPixels;
+ idx-- ) {
+ palette.entry[idx] = palette.entry[idx-1];
+ palette.entry[idx].listNode->idx = idx;
+ }
+
+ /* Add new palette entry into the freed slot. */
+ pnode = &palette.list[paletteNumColors];
+ if (prev_pnode != NULL) {
+ prev_pnode->next = pnode;
+ } else {
+ palette.hash[hash_key] = pnode;
+ }
+ pnode->next = NULL;
+ pnode->idx = idx;
+ pnode->rgb = rgb;
+ palette.entry[idx].listNode = pnode;
+ palette.entry[idx].numPixels = numPixels;
+
+ return (++paletteNumColors);
+}
+
+
+/*
+ * Converting 32-bit color samples into 24-bit colors.
+ * Should be called only when redMax, greenMax and blueMax are 255.
+ * Color components assumed to be byte-aligned.
+ */
+
+static void Pack24(cl, buf, fmt, count)
+ rfbClientPtr cl;
+ char *buf;
+ rfbPixelFormat *fmt;
+ int count;
+{
+ uint32_t *buf32;
+ uint32_t pix;
+ int r_shift, g_shift, b_shift;
+
+ buf32 = (uint32_t *)buf;
+
+ if (!cl->screen->rfbServerFormat.bigEndian == !fmt->bigEndian) {
+ r_shift = fmt->redShift;
+ g_shift = fmt->greenShift;
+ b_shift = fmt->blueShift;
+ } else {
+ r_shift = 24 - fmt->redShift;
+ g_shift = 24 - fmt->greenShift;
+ b_shift = 24 - fmt->blueShift;
+ }
+
+ while (count--) {
+ pix = *buf32++;
+ *buf++ = (char)(pix >> r_shift);
+ *buf++ = (char)(pix >> g_shift);
+ *buf++ = (char)(pix >> b_shift);
+ }
+}
+
+
+/*
+ * Converting truecolor samples into palette indices.
+ */
+
+#define DEFINE_IDX_ENCODE_FUNCTION(bpp) \
+ \
+static void \
+EncodeIndexedRect##bpp(buf, count) \
+ uint8_t *buf; \
+ int count; \
+{ \
+ COLOR_LIST *pnode; \
+ uint##bpp##_t *src; \
+ uint##bpp##_t rgb; \
+ int rep = 0; \
+ \
+ src = (uint##bpp##_t *) buf; \
+ \
+ while (count--) { \
+ rgb = *src++; \
+ while (count && *src == rgb) { \
+ rep++, src++, count--; \
+ } \
+ pnode = palette.hash[HASH_FUNC##bpp(rgb)]; \
+ while (pnode != NULL) { \
+ if ((uint##bpp##_t)pnode->rgb == rgb) { \
+ *buf++ = (uint8_t)pnode->idx; \
+ while (rep) { \
+ *buf++ = (uint8_t)pnode->idx; \
+ rep--; \
+ } \
+ break; \
+ } \
+ pnode = pnode->next; \
+ } \
+ } \
+}
+
+DEFINE_IDX_ENCODE_FUNCTION(16)
+DEFINE_IDX_ENCODE_FUNCTION(32)
+
+#define DEFINE_MONO_ENCODE_FUNCTION(bpp) \
+ \
+static void \
+EncodeMonoRect##bpp(buf, w, h) \
+ uint8_t *buf; \
+ int w, h; \
+{ \
+ uint##bpp##_t *ptr; \
+ uint##bpp##_t bg; \
+ unsigned int value, mask; \
+ int aligned_width; \
+ int x, y, bg_bits; \
+ \
+ ptr = (uint##bpp##_t *) buf; \
+ bg = (uint##bpp##_t) 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 (*ptr++ != bg) \
+ break; \
+ } \
+ if (bg_bits == 8) { \
+ *buf++ = 0; \
+ continue; \
+ } \
+ mask = 0x80 >> bg_bits; \
+ value = mask; \
+ for (bg_bits++; bg_bits < 8; bg_bits++) { \
+ mask >>= 1; \
+ if (*ptr++ != bg) { \
+ value |= mask; \
+ } \
+ } \
+ *buf++ = (uint8_t)value; \
+ } \
+ \
+ mask = 0x80; \
+ value = 0; \
+ if (x >= w) \
+ continue; \
+ \
+ for (; x < w; x++) { \
+ if (*ptr++ != bg) { \
+ value |= mask; \
+ } \
+ mask >>= 1; \
+ } \
+ *buf++ = (uint8_t)value; \
+ } \
+}
+
+DEFINE_MONO_ENCODE_FUNCTION(8)
+DEFINE_MONO_ENCODE_FUNCTION(16)
+DEFINE_MONO_ENCODE_FUNCTION(32)
+
+
+/*
+ * ``Gradient'' filter for 24-bit color samples.
+ * Should be called only when redMax, greenMax and blueMax are 255.
+ * Color components assumed to be byte-aligned.
+ */
+
+static void
+FilterGradient24(cl, buf, fmt, w, h)
+ rfbClientPtr cl;
+ char *buf;
+ rfbPixelFormat *fmt;
+ int w, h;
+{
+ uint32_t *buf32;
+ uint32_t pix32;
+ int *prevRowPtr;
+ int shiftBits[3];
+ int pixHere[3], pixUpper[3], pixLeft[3], pixUpperLeft[3];
+ int prediction;
+ int x, y, c;
+
+ buf32 = (uint32_t *)buf;
+ memset (prevRowBuf, 0, w * 3 * sizeof(int));
+
+ if (!cl->screen->rfbServerFormat.bigEndian == !fmt->bigEndian) {
+ shiftBits[0] = fmt->redShift;
+ shiftBits[1] = fmt->greenShift;
+ shiftBits[2] = fmt->blueShift;
+ } else {
+ shiftBits[0] = 24 - fmt->redShift;
+ shiftBits[1] = 24 - fmt->greenShift;
+ shiftBits[2] = 24 - fmt->blueShift;
+ }
+
+ for (y = 0; y < h; y++) {
+ for (c = 0; c < 3; c++) {
+ pixUpper[c] = 0;
+ pixHere[c] = 0;
+ }
+ prevRowPtr = prevRowBuf;
+ for (x = 0; x < w; x++) {
+ pix32 = *buf32++;
+ for (c = 0; c < 3; c++) {
+ pixUpperLeft[c] = pixUpper[c];
+ pixLeft[c] = pixHere[c];
+ pixUpper[c] = *prevRowPtr;
+ pixHere[c] = (int)(pix32 >> shiftBits[c] & 0xFF);
+ *prevRowPtr++ = pixHere[c];
+
+ prediction = pixLeft[c] + pixUpper[c] - pixUpperLeft[c];
+ if (prediction < 0) {
+ prediction = 0;
+ } else if (prediction > 0xFF) {
+ prediction = 0xFF;
+ }
+ *buf++ = (char)(pixHere[c] - prediction);
+ }
+ }
+ }
+}
+
+
+/*
+ * ``Gradient'' filter for other color depths.
+ */
+
+#define DEFINE_GRADIENT_FILTER_FUNCTION(bpp) \
+ \
+static void \
+FilterGradient##bpp(cl, buf, fmt, w, h) \
+ rfbClientPtr cl; \
+ uint##bpp##_t *buf; \
+ rfbPixelFormat *fmt; \
+ int w, h; \
+{ \
+ uint##bpp##_t pix, diff; \
+ rfbBool endianMismatch; \
+ int *prevRowPtr; \
+ int maxColor[3], shiftBits[3]; \
+ int pixHere[3], pixUpper[3], pixLeft[3], pixUpperLeft[3]; \
+ int prediction; \
+ int x, y, c; \
+ \
+ memset (prevRowBuf, 0, w * 3 * sizeof(int)); \
+ \
+ endianMismatch = (!cl->screen->rfbServerFormat.bigEndian != !fmt->bigEndian); \
+ \
+ maxColor[0] = fmt->redMax; \
+ maxColor[1] = fmt->greenMax; \
+ maxColor[2] = fmt->blueMax; \
+ shiftBits[0] = fmt->redShift; \
+ shiftBits[1] = fmt->greenShift; \
+ shiftBits[2] = fmt->blueShift; \
+ \
+ for (y = 0; y < h; y++) { \
+ for (c = 0; c < 3; c++) { \
+ pixUpper[c] = 0; \
+ pixHere[c] = 0; \
+ } \
+ prevRowPtr = prevRowBuf; \
+ for (x = 0; x < w; x++) { \
+ pix = *buf; \
+ if (endianMismatch) { \
+ pix = Swap##bpp(pix); \
+ } \
+ diff = 0; \
+ for (c = 0; c < 3; c++) { \
+ pixUpperLeft[c] = pixUpper[c]; \
+ pixLeft[c] = pixHere[c]; \
+ pixUpper[c] = *prevRowPtr; \
+ pixHere[c] = (int)(pix >> shiftBits[c] & maxColor[c]); \
+ *prevRowPtr++ = pixHere[c]; \
+ \
+ prediction = pixLeft[c] + pixUpper[c] - pixUpperLeft[c]; \
+ if (prediction < 0) { \
+ prediction = 0; \
+ } else if (prediction > maxColor[c]) { \
+ prediction = maxColor[c]; \
+ } \
+ diff |= ((pixHere[c] - prediction) & maxColor[c]) \
+ << shiftBits[c]; \
+ } \
+ if (endianMismatch) { \
+ diff = Swap##bpp(diff); \
+ } \
+ *buf++ = diff; \
+ } \
+ } \
+}
+
+DEFINE_GRADIENT_FILTER_FUNCTION(16)
+DEFINE_GRADIENT_FILTER_FUNCTION(32)
+
+
+/*
+ * Code to guess if given rectangle is suitable for smooth image
+ * compression (by applying "gradient" filter or JPEG coder).
+ */
+
+#define JPEG_MIN_RECT_SIZE 4096
+
+#define DETECT_SUBROW_WIDTH 7
+#define DETECT_MIN_WIDTH 8
+#define DETECT_MIN_HEIGHT 8
+
+static int
+DetectSmoothImage (cl, fmt, w, h)
+ rfbClientPtr cl;
+ rfbPixelFormat *fmt;
+ int w, h;
+{
+ long avgError;
+
+ if ( cl->screen->rfbServerFormat.bitsPerPixel == 8 || fmt->bitsPerPixel == 8 ||
+ w < DETECT_MIN_WIDTH || h < DETECT_MIN_HEIGHT ) {
+ return 0;
+ }
+
+ if (qualityLevel != -1) {
+ if (w * h < JPEG_MIN_RECT_SIZE) {
+ return 0;
+ }
+ } else {
+ if ( rfbTightDisableGradient ||
+ w * h < tightConf[compressLevel].gradientMinRectSize ) {
+ return 0;
+ }
+ }
+
+ if (fmt->bitsPerPixel == 32) {
+ if (usePixelFormat24) {
+ avgError = DetectSmoothImage24(cl, fmt, w, h);
+ if (qualityLevel != -1) {
+ return (avgError < tightConf[qualityLevel].jpegThreshold24);
+ }
+ return (avgError < tightConf[compressLevel].gradientThreshold24);
+ } else {
+ avgError = DetectSmoothImage32(cl, fmt, w, h);
+ }
+ } else {
+ avgError = DetectSmoothImage16(cl, fmt, w, h);
+ }
+ if (qualityLevel != -1) {
+ return (avgError < tightConf[qualityLevel].jpegThreshold);
+ }
+ return (avgError < tightConf[compressLevel].gradientThreshold);
+}
+
+static unsigned long
+DetectSmoothImage24 (cl, fmt, w, h)
+ rfbClientPtr cl;
+ rfbPixelFormat *fmt;
+ int w, h;
+{
+ int off;
+ int x, y, d, dx, c;
+ int diffStat[256];
+ int pixelCount = 0;
+ int pix, left[3];
+ unsigned long avgError;
+
+ /* If client is big-endian, color samples begin from the second
+ byte (offset 1) of a 32-bit pixel value. */
+ off = (fmt->bigEndian != 0);
+
+ memset(diffStat, 0, 256*sizeof(int));
+
+ y = 0, x = 0;
+ while (y < h && x < w) {
+ for (d = 0; d < h - y && d < w - x - DETECT_SUBROW_WIDTH; d++) {
+ for (c = 0; c < 3; c++) {
+ left[c] = (int)tightBeforeBuf[((y+d)*w+x+d)*4+off+c] & 0xFF;
+ }
+ for (dx = 1; dx <= DETECT_SUBROW_WIDTH; dx++) {
+ for (c = 0; c < 3; c++) {
+ pix = (int)tightBeforeBuf[((y+d)*w+x+d+dx)*4+off+c] & 0xFF;
+ diffStat[abs(pix - left[c])]++;
+ left[c] = pix;
+ }
+ pixelCount++;
+ }
+ }
+ if (w > h) {
+ x += h;
+ y = 0;
+ } else {
+ x = 0;
+ y += w;
+ }
+ }
+
+ if (diffStat[0] * 33 / pixelCount >= 95)
+ return 0;
+
+ avgError = 0;
+ for (c = 1; c < 8; c++) {
+ avgError += (unsigned long)diffStat[c] * (unsigned long)(c * c);
+ if (diffStat[c] == 0 || diffStat[c] > diffStat[c-1] * 2)
+ return 0;
+ }
+ for (; c < 256; c++) {
+ avgError += (unsigned long)diffStat[c] * (unsigned long)(c * c);
+ }
+ avgError /= (pixelCount * 3 - diffStat[0]);
+
+ return avgError;
+}
+
+#define DEFINE_DETECT_FUNCTION(bpp) \
+ \
+static unsigned long \
+DetectSmoothImage##bpp (cl, fmt, w, h) \
+ rfbClientPtr cl; \
+ rfbPixelFormat *fmt; \
+ int w, h; \
+{ \
+ rfbBool endianMismatch; \
+ uint##bpp##_t pix; \
+ int maxColor[3], shiftBits[3]; \
+ int x, y, d, dx, c; \
+ int diffStat[256]; \
+ int pixelCount = 0; \
+ int sample, sum, left[3]; \
+ unsigned long avgError; \
+ \
+ endianMismatch = (!cl->screen->rfbServerFormat.bigEndian != !fmt->bigEndian); \
+ \
+ maxColor[0] = fmt->redMax; \
+ maxColor[1] = fmt->greenMax; \
+ maxColor[2] = fmt->blueMax; \
+ shiftBits[0] = fmt->redShift; \
+ shiftBits[1] = fmt->greenShift; \
+ shiftBits[2] = fmt->blueShift; \
+ \
+ memset(diffStat, 0, 256*sizeof(int)); \
+ \
+ y = 0, x = 0; \
+ while (y < h && x < w) { \
+ for (d = 0; d < h - y && d < w - x - DETECT_SUBROW_WIDTH; d++) { \
+ pix = ((uint##bpp##_t *)tightBeforeBuf)[(y+d)*w+x+d]; \
+ if (endianMismatch) { \
+ pix = Swap##bpp(pix); \
+ } \
+ for (c = 0; c < 3; c++) { \
+ left[c] = (int)(pix >> shiftBits[c] & maxColor[c]); \
+ } \
+ for (dx = 1; dx <= DETECT_SUBROW_WIDTH; dx++) { \
+ pix = ((uint##bpp##_t *)tightBeforeBuf)[(y+d)*w+x+d+dx]; \
+ if (endianMismatch) { \
+ pix = Swap##bpp(pix); \
+ } \
+ sum = 0; \
+ for (c = 0; c < 3; c++) { \
+ sample = (int)(pix >> shiftBits[c] & maxColor[c]); \
+ sum += abs(sample - left[c]); \
+ left[c] = sample; \
+ } \
+ if (sum > 255) \
+ sum = 255; \
+ diffStat[sum]++; \
+ pixelCount++; \
+ } \
+ } \
+ if (w > h) { \
+ x += h; \
+ y = 0; \
+ } else { \
+ x = 0; \
+ y += w; \
+ } \
+ } \
+ \
+ if ((diffStat[0] + diffStat[1]) * 100 / pixelCount >= 90) \
+ return 0; \
+ \
+ avgError = 0; \
+ for (c = 1; c < 8; c++) { \
+ avgError += (unsigned long)diffStat[c] * (unsigned long)(c * c); \
+ if (diffStat[c] == 0 || diffStat[c] > diffStat[c-1] * 2) \
+ return 0; \
+ } \
+ for (; c < 256; c++) { \
+ avgError += (unsigned long)diffStat[c] * (unsigned long)(c * c); \
+ } \
+ avgError /= (pixelCount - diffStat[0]); \
+ \
+ return avgError; \
+}
+
+DEFINE_DETECT_FUNCTION(16)
+DEFINE_DETECT_FUNCTION(32)
+
+
+/*
+ * JPEG compression stuff.
+ */
+
+static struct jpeg_destination_mgr jpegDstManager;
+static rfbBool jpegError;
+static int jpegDstDataLen;
+
+static rfbBool
+SendJpegRect(cl, x, y, w, h, quality)
+ rfbClientPtr cl;
+ int x, y, w, h;
+ int quality;
+{
+ struct jpeg_compress_struct cinfo;
+ struct jpeg_error_mgr jerr;
+ uint8_t *srcBuf;
+ JSAMPROW rowPointer[1];
+ int dy;
+
+ if (cl->screen->rfbServerFormat.bitsPerPixel == 8)
+ return SendFullColorRect(cl, w, h);
+
+ srcBuf = (uint8_t *)malloc(w * 3);
+ if (srcBuf == NULL) {
+ return SendFullColorRect(cl, w, h);
+ }
+ rowPointer[0] = 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, quality, TRUE);
+
+ JpegSetDstManager (&cinfo);
+
+ jpeg_start_compress(&cinfo, TRUE);
+
+ for (dy = 0; dy < h; dy++) {
+ PrepareRowForJpeg(cl, srcBuf, x, y + dy, w);
+ jpeg_write_scanlines(&cinfo, rowPointer, 1);
+ if (jpegError)
+ break;
+ }
+
+ if (!jpegError)
+ jpeg_finish_compress(&cinfo);
+
+ jpeg_destroy_compress(&cinfo);
+ free(srcBuf);
+
+ if (jpegError)
+ return SendFullColorRect(cl, w, h);
+
+ if (cl->ublen + TIGHT_MIN_TO_COMPRESS + 1 > UPDATE_BUF_SIZE) {
+ if (!rfbSendUpdateBuf(cl))
+ return FALSE;
+ }
+
+ cl->updateBuf[cl->ublen++] = (char)(rfbTightJpeg << 4);
+ cl->rfbBytesSent[rfbEncodingTight]++;
+
+ return SendCompressedData(cl, jpegDstDataLen);
+}
+
+static void
+PrepareRowForJpeg(cl, dst, x, y, count)
+ rfbClientPtr cl;
+ uint8_t *dst;
+ int x, y, count;
+{
+ if (cl->screen->rfbServerFormat.bitsPerPixel == 32) {
+ if ( cl->screen->rfbServerFormat.redMax == 0xFF &&
+ cl->screen->rfbServerFormat.greenMax == 0xFF &&
+ cl->screen->rfbServerFormat.blueMax == 0xFF ) {
+ PrepareRowForJpeg24(cl, dst, x, y, count);
+ } else {
+ PrepareRowForJpeg32(cl, dst, x, y, count);
+ }
+ } else {
+ /* 16 bpp assumed. */
+ PrepareRowForJpeg16(cl, dst, x, y, count);
+ }
+}
+
+static void
+PrepareRowForJpeg24(cl, dst, x, y, count)
+ rfbClientPtr cl;
+ uint8_t *dst;
+ int x, y, count;
+{
+ uint32_t *fbptr;
+ uint32_t pix;
+
+ fbptr = (uint32_t *)
+ &cl->screen->frameBuffer[y * cl->screen->paddedWidthInBytes + x * 4];
+
+ while (count--) {
+ pix = *fbptr++;
+ *dst++ = (uint8_t)(pix >> cl->screen->rfbServerFormat.redShift);
+ *dst++ = (uint8_t)(pix >> cl->screen->rfbServerFormat.greenShift);
+ *dst++ = (uint8_t)(pix >> cl->screen->rfbServerFormat.blueShift);
+ }
+}
+
+#define DEFINE_JPEG_GET_ROW_FUNCTION(bpp) \
+ \
+static void \
+PrepareRowForJpeg##bpp(cl, dst, x, y, count) \
+ rfbClientPtr cl; \
+ uint8_t *dst; \
+ int x, y, count; \
+{ \
+ uint##bpp##_t *fbptr; \
+ uint##bpp##_t pix; \
+ int inRed, inGreen, inBlue; \
+ \
+ fbptr = (uint##bpp##_t *) \
+ &cl->screen->frameBuffer[y * cl->screen->paddedWidthInBytes + \
+ x * (bpp / 8)]; \
+ \
+ while (count--) { \
+ pix = *fbptr++; \
+ \
+ inRed = (int) \
+ (pix >> cl->screen->rfbServerFormat.redShift & cl->screen->rfbServerFormat.redMax); \
+ inGreen = (int) \
+ (pix >> cl->screen->rfbServerFormat.greenShift & cl->screen->rfbServerFormat.greenMax); \
+ inBlue = (int) \
+ (pix >> cl->screen->rfbServerFormat.blueShift & cl->screen->rfbServerFormat.blueMax); \
+ \
+ *dst++ = (uint8_t)((inRed * 255 + cl->screen->rfbServerFormat.redMax / 2) / \
+ cl->screen->rfbServerFormat.redMax); \
+ *dst++ = (uint8_t)((inGreen * 255 + cl->screen->rfbServerFormat.greenMax / 2) / \
+ cl->screen->rfbServerFormat.greenMax); \
+ *dst++ = (uint8_t)((inBlue * 255 + cl->screen->rfbServerFormat.blueMax / 2) / \
+ cl->screen->rfbServerFormat.blueMax); \
+ } \
+}
+
+DEFINE_JPEG_GET_ROW_FUNCTION(16)
+DEFINE_JPEG_GET_ROW_FUNCTION(32)
+
+/*
+ * Destination manager implementation for JPEG library.
+ */
+
+static void
+JpegInitDestination(j_compress_ptr cinfo)
+{
+ jpegError = FALSE;
+ jpegDstManager.next_output_byte = (JOCTET *)tightAfterBuf;
+ jpegDstManager.free_in_buffer = (size_t)tightAfterBufSize;
+}
+
+static boolean
+JpegEmptyOutputBuffer(j_compress_ptr cinfo)
+{
+ jpegError = TRUE;
+ jpegDstManager.next_output_byte = (JOCTET *)tightAfterBuf;
+ jpegDstManager.free_in_buffer = (size_t)tightAfterBufSize;
+
+ return TRUE;
+}
+
+static void
+JpegTermDestination(j_compress_ptr cinfo)
+{
+ jpegDstDataLen = tightAfterBufSize - jpegDstManager.free_in_buffer;
+}
+
+static void
+JpegSetDstManager(j_compress_ptr cinfo)
+{
+ jpegDstManager.init_destination = JpegInitDestination;
+ jpegDstManager.empty_output_buffer = JpegEmptyOutputBuffer;
+ jpegDstManager.term_destination = JpegTermDestination;
+ cinfo->dest = &jpegDstManager;
+}
+
diff --git a/libvncserver/translate.c b/libvncserver/translate.c
new file mode 100755
index 0000000..d5f0896
--- /dev/null
+++ b/libvncserver/translate.c
@@ -0,0 +1,484 @@
+/*
+ * translate.c - translate between different pixel formats
+ */
+
+/*
+ * OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
+ * Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge.
+ * 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/rfb.h>
+#include <rfb/rfbregion.h>
+
+static void PrintPixelFormat(rfbPixelFormat *pf);
+static rfbBool rfbSetClientColourMapBGR233(rfbClientPtr cl);
+
+rfbBool rfbEconomicTranslate = FALSE;
+
+/*
+ * Some standard pixel formats.
+ */
+
+static const rfbPixelFormat BGR233Format = {
+ 8, 8, 0, 1, 7, 7, 3, 0, 3, 6, 0, 0
+};
+
+
+/*
+ * Macro to compare pixel formats.
+ */
+
+#define PF_EQ(x,y) \
+ ((x.bitsPerPixel == y.bitsPerPixel) && \
+ (x.depth == y.depth) && \
+ ((x.bigEndian == y.bigEndian) || (x.bitsPerPixel == 8)) && \
+ (x.trueColour == y.trueColour) && \
+ (!x.trueColour || ((x.redMax == y.redMax) && \
+ (x.greenMax == y.greenMax) && \
+ (x.blueMax == y.blueMax) && \
+ (x.redShift == y.redShift) && \
+ (x.greenShift == y.greenShift) && \
+ (x.blueShift == y.blueShift))))
+
+#define CONCAT2(a,b) a##b
+#define CONCAT2E(a,b) CONCAT2(a,b)
+#define CONCAT3(a,b,c) a##b##c
+#define CONCAT3E(a,b,c) CONCAT3(a,b,c)
+#define CONCAT4(a,b,c,d) a##b##c##d
+#define CONCAT4E(a,b,c,d) CONCAT4(a,b,c,d)
+
+#undef OUT
+#undef IN
+
+#define OUT 8
+#include "tableinitcmtemplate.c"
+#include "tableinittctemplate.c"
+#define IN 8
+#include "tabletranstemplate.c"
+#undef IN
+#define IN 16
+#include "tabletranstemplate.c"
+#undef IN
+#define IN 32
+#include "tabletranstemplate.c"
+#undef IN
+#undef OUT
+
+#define OUT 16
+#include "tableinitcmtemplate.c"
+#include "tableinittctemplate.c"
+#define IN 8
+#include "tabletranstemplate.c"
+#undef IN
+#define IN 16
+#include "tabletranstemplate.c"
+#undef IN
+#define IN 32
+#include "tabletranstemplate.c"
+#undef IN
+#undef OUT
+
+#define OUT 32
+#include "tableinitcmtemplate.c"
+#include "tableinittctemplate.c"
+#define IN 8
+#include "tabletranstemplate.c"
+#undef IN
+#define IN 16
+#include "tabletranstemplate.c"
+#undef IN
+#define IN 32
+#include "tabletranstemplate.c"
+#undef IN
+#undef OUT
+
+#ifdef LIBVNCSERVER_ALLOW24BPP
+#define COUNT_OFFSETS 4
+#define BPP2OFFSET(bpp) ((bpp)/8-1)
+#include "tableinit24.c"
+#define BPP 8
+#include "tabletrans24template.c"
+#undef BPP
+#define BPP 16
+#include "tabletrans24template.c"
+#undef BPP
+#define BPP 24
+#include "tabletrans24template.c"
+#undef BPP
+#define BPP 32
+#include "tabletrans24template.c"
+#undef BPP
+#else
+#define COUNT_OFFSETS 3
+#define BPP2OFFSET(bpp) ((int)(bpp)/16)
+#endif
+
+typedef void (*rfbInitCMTableFnType)(char **table, rfbPixelFormat *in,
+ rfbPixelFormat *out,rfbColourMap* cm);
+typedef void (*rfbInitTableFnType)(char **table, rfbPixelFormat *in,
+ rfbPixelFormat *out);
+
+rfbInitCMTableFnType rfbInitColourMapSingleTableFns[COUNT_OFFSETS] = {
+ rfbInitColourMapSingleTable8,
+ rfbInitColourMapSingleTable16,
+#ifdef LIBVNCSERVER_ALLOW24BPP
+ rfbInitColourMapSingleTable24,
+#endif
+ rfbInitColourMapSingleTable32
+};
+
+rfbInitTableFnType rfbInitTrueColourSingleTableFns[COUNT_OFFSETS] = {
+ rfbInitTrueColourSingleTable8,
+ rfbInitTrueColourSingleTable16,
+#ifdef LIBVNCSERVER_ALLOW24BPP
+ rfbInitTrueColourSingleTable24,
+#endif
+ rfbInitTrueColourSingleTable32
+};
+
+rfbInitTableFnType rfbInitTrueColourRGBTablesFns[COUNT_OFFSETS] = {
+ rfbInitTrueColourRGBTables8,
+ rfbInitTrueColourRGBTables16,
+#ifdef LIBVNCSERVER_ALLOW24BPP
+ rfbInitTrueColourRGBTables24,
+#endif
+ rfbInitTrueColourRGBTables32
+};
+
+rfbTranslateFnType rfbTranslateWithSingleTableFns[COUNT_OFFSETS][COUNT_OFFSETS] = {
+ { rfbTranslateWithSingleTable8to8,
+ rfbTranslateWithSingleTable8to16,
+#ifdef LIBVNCSERVER_ALLOW24BPP
+ rfbTranslateWithSingleTable8to24,
+#endif
+ rfbTranslateWithSingleTable8to32 },
+ { rfbTranslateWithSingleTable16to8,
+ rfbTranslateWithSingleTable16to16,
+#ifdef LIBVNCSERVER_ALLOW24BPP
+ rfbTranslateWithSingleTable16to24,
+#endif
+ rfbTranslateWithSingleTable16to32 },
+#ifdef LIBVNCSERVER_ALLOW24BPP
+ { rfbTranslateWithSingleTable24to8,
+ rfbTranslateWithSingleTable24to16,
+ rfbTranslateWithSingleTable24to24,
+ rfbTranslateWithSingleTable24to32 },
+#endif
+ { rfbTranslateWithSingleTable32to8,
+ rfbTranslateWithSingleTable32to16,
+#ifdef LIBVNCSERVER_ALLOW24BPP
+ rfbTranslateWithSingleTable32to24,
+#endif
+ rfbTranslateWithSingleTable32to32 }
+};
+
+rfbTranslateFnType rfbTranslateWithRGBTablesFns[COUNT_OFFSETS][COUNT_OFFSETS] = {
+ { rfbTranslateWithRGBTables8to8,
+ rfbTranslateWithRGBTables8to16,
+#ifdef LIBVNCSERVER_ALLOW24BPP
+ rfbTranslateWithRGBTables8to24,
+#endif
+ rfbTranslateWithRGBTables8to32 },
+ { rfbTranslateWithRGBTables16to8,
+ rfbTranslateWithRGBTables16to16,
+#ifdef LIBVNCSERVER_ALLOW24BPP
+ rfbTranslateWithRGBTables16to24,
+#endif
+ rfbTranslateWithRGBTables16to32 },
+#ifdef LIBVNCSERVER_ALLOW24BPP
+ { rfbTranslateWithRGBTables24to8,
+ rfbTranslateWithRGBTables24to16,
+ rfbTranslateWithRGBTables24to24,
+ rfbTranslateWithRGBTables24to32 },
+#endif
+ { rfbTranslateWithRGBTables32to8,
+ rfbTranslateWithRGBTables32to16,
+#ifdef LIBVNCSERVER_ALLOW24BPP
+ rfbTranslateWithRGBTables32to24,
+#endif
+ rfbTranslateWithRGBTables32to32 }
+};
+
+
+
+/*
+ * rfbTranslateNone is used when no translation is required.
+ */
+
+void
+rfbTranslateNone(char *table, rfbPixelFormat *in, rfbPixelFormat *out,
+ char *iptr, char *optr, int bytesBetweenInputLines,
+ int width, int height)
+{
+ int bytesPerOutputLine = width * (out->bitsPerPixel / 8);
+
+ while (height > 0) {
+ memcpy(optr, iptr, bytesPerOutputLine);
+ iptr += bytesBetweenInputLines;
+ optr += bytesPerOutputLine;
+ height--;
+ }
+}
+
+
+/*
+ * rfbSetTranslateFunction sets the translation function.
+ */
+
+rfbBool
+rfbSetTranslateFunction(cl)
+ rfbClientPtr cl;
+{
+ rfbLog("Pixel format for client %s:\n",cl->host);
+ PrintPixelFormat(&cl->format);
+
+ /*
+ * Check that bits per pixel values are valid
+ */
+
+ if ((cl->screen->rfbServerFormat.bitsPerPixel != 8) &&
+ (cl->screen->rfbServerFormat.bitsPerPixel != 16) &&
+#ifdef LIBVNCSERVER_ALLOW24BPP
+ (cl->screen->rfbServerFormat.bitsPerPixel != 24) &&
+#endif
+ (cl->screen->rfbServerFormat.bitsPerPixel != 32))
+ {
+ rfbErr("%s: server bits per pixel not 8, 16 or 32 (is %d)\n",
+ "rfbSetTranslateFunction",
+ cl->screen->rfbServerFormat.bitsPerPixel);
+ rfbCloseClient(cl);
+ return FALSE;
+ }
+
+ if ((cl->format.bitsPerPixel != 8) &&
+ (cl->format.bitsPerPixel != 16) &&
+#ifdef LIBVNCSERVER_ALLOW24BPP
+ (cl->format.bitsPerPixel != 24) &&
+#endif
+ (cl->format.bitsPerPixel != 32))
+ {
+ rfbErr("%s: client bits per pixel not 8, 16 or 32\n",
+ "rfbSetTranslateFunction");
+ rfbCloseClient(cl);
+ return FALSE;
+ }
+
+ if (!cl->format.trueColour && (cl->format.bitsPerPixel != 8)) {
+ rfbErr("rfbSetTranslateFunction: client has colour map "
+ "but %d-bit - can only cope with 8-bit colour maps\n",
+ cl->format.bitsPerPixel);
+ rfbCloseClient(cl);
+ return FALSE;
+ }
+
+ /*
+ * bpp is valid, now work out how to translate
+ */
+
+ if (!cl->format.trueColour) {
+ /*
+ * truecolour -> colour map
+ *
+ * Set client's colour map to BGR233, then effectively it's
+ * truecolour as well
+ */
+
+ if (!rfbSetClientColourMapBGR233(cl))
+ return FALSE;
+
+ cl->format = BGR233Format;
+ }
+
+ /* truecolour -> truecolour */
+
+ if (PF_EQ(cl->format,cl->screen->rfbServerFormat)) {
+
+ /* client & server the same */
+
+ rfbLog("no translation needed\n");
+ cl->translateFn = rfbTranslateNone;
+ return TRUE;
+ }
+
+ if ((cl->screen->rfbServerFormat.bitsPerPixel < 16) ||
+ ((!cl->screen->rfbServerFormat.trueColour || !rfbEconomicTranslate) &&
+ (cl->screen->rfbServerFormat.bitsPerPixel == 16))) {
+
+ /* we can use a single lookup table for <= 16 bpp */
+
+ cl->translateFn = rfbTranslateWithSingleTableFns
+ [BPP2OFFSET(cl->screen->rfbServerFormat.bitsPerPixel)]
+ [BPP2OFFSET(cl->format.bitsPerPixel)];
+
+ if(cl->screen->rfbServerFormat.trueColour)
+ (*rfbInitTrueColourSingleTableFns
+ [BPP2OFFSET(cl->format.bitsPerPixel)]) (&cl->translateLookupTable,
+ &(cl->screen->rfbServerFormat), &cl->format);
+ else
+ (*rfbInitColourMapSingleTableFns
+ [BPP2OFFSET(cl->format.bitsPerPixel)]) (&cl->translateLookupTable,
+ &(cl->screen->rfbServerFormat), &cl->format,&cl->screen->colourMap);
+
+ } else {
+
+ /* otherwise we use three separate tables for red, green and blue */
+
+ cl->translateFn = rfbTranslateWithRGBTablesFns
+ [BPP2OFFSET(cl->screen->rfbServerFormat.bitsPerPixel)]
+ [BPP2OFFSET(cl->format.bitsPerPixel)];
+
+ (*rfbInitTrueColourRGBTablesFns
+ [BPP2OFFSET(cl->format.bitsPerPixel)]) (&cl->translateLookupTable,
+ &(cl->screen->rfbServerFormat), &cl->format);
+ }
+
+ return TRUE;
+}
+
+
+
+/*
+ * rfbSetClientColourMapBGR233 sets the client's colour map so that it's
+ * just like an 8-bit BGR233 true colour client.
+ */
+
+static rfbBool
+rfbSetClientColourMapBGR233(cl)
+ rfbClientPtr cl;
+{
+ char buf[sz_rfbSetColourMapEntriesMsg + 256 * 3 * 2];
+ rfbSetColourMapEntriesMsg *scme = (rfbSetColourMapEntriesMsg *)buf;
+ uint16_t *rgb = (uint16_t *)(&buf[sz_rfbSetColourMapEntriesMsg]);
+ int i, len;
+ int r, g, b;
+
+ if (cl->format.bitsPerPixel != 8 ) {
+ rfbErr("%s: client not 8 bits per pixel\n",
+ "rfbSetClientColourMapBGR233");
+ rfbCloseClient(cl);
+ return FALSE;
+ }
+
+ scme->type = rfbSetColourMapEntries;
+
+ scme->firstColour = Swap16IfLE(0);
+ scme->nColours = Swap16IfLE(256);
+
+ len = sz_rfbSetColourMapEntriesMsg;
+
+ i = 0;
+
+ for (b = 0; b < 4; b++) {
+ for (g = 0; g < 8; g++) {
+ for (r = 0; r < 8; r++) {
+ rgb[i++] = Swap16IfLE(r * 65535 / 7);
+ rgb[i++] = Swap16IfLE(g * 65535 / 7);
+ rgb[i++] = Swap16IfLE(b * 65535 / 3);
+ }
+ }
+ }
+
+ len += 256 * 3 * 2;
+
+ if (WriteExact(cl, buf, len) < 0) {
+ rfbLogPerror("rfbSetClientColourMapBGR233: write");
+ rfbCloseClient(cl);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/* this function is not called very often, so it needn't be
+ efficient. */
+
+/*
+ * rfbSetClientColourMap is called to set the client's colour map. If the
+ * client is a true colour client, we simply update our own translation table
+ * and mark the whole screen as having been modified.
+ */
+
+rfbBool
+rfbSetClientColourMap(cl, firstColour, nColours)
+ rfbClientPtr cl;
+ int firstColour;
+ int nColours;
+{
+ if (cl->screen->rfbServerFormat.trueColour || !cl->readyForSetColourMapEntries) {
+ return TRUE;
+ }
+
+ if (nColours == 0) {
+ nColours = cl->screen->colourMap.count;
+ }
+
+ if (cl->format.trueColour) {
+ (*rfbInitColourMapSingleTableFns
+ [BPP2OFFSET(cl->format.bitsPerPixel)]) (&cl->translateLookupTable,
+ &cl->screen->rfbServerFormat, &cl->format,&cl->screen->colourMap);
+
+ sraRgnDestroy(cl->modifiedRegion);
+ cl->modifiedRegion =
+ sraRgnCreateRect(0,0,cl->screen->width,cl->screen->height);
+
+ return TRUE;
+ }
+
+ return rfbSendSetColourMapEntries(cl, firstColour, nColours);
+}
+
+
+/*
+ * rfbSetClientColourMaps sets the colour map for each RFB client.
+ */
+
+void
+rfbSetClientColourMaps(rfbScreen, firstColour, nColours)
+ rfbScreenInfoPtr rfbScreen;
+ int firstColour;
+ int nColours;
+{
+ rfbClientIteratorPtr i;
+ rfbClientPtr cl;
+
+ i = rfbGetClientIterator(rfbScreen);
+ while((cl = rfbClientIteratorNext(i)))
+ rfbSetClientColourMap(cl, firstColour, nColours);
+ rfbReleaseClientIterator(i);
+}
+
+static void
+PrintPixelFormat(pf)
+ rfbPixelFormat *pf;
+{
+ if (pf->bitsPerPixel == 1) {
+ rfbLog(" 1 bpp, %s sig bit in each byte is leftmost on the screen.\n",
+ (pf->bigEndian ? "most" : "least"));
+ } else {
+ rfbLog(" %d bpp, depth %d%s\n",pf->bitsPerPixel,pf->depth,
+ ((pf->bitsPerPixel == 8) ? ""
+ : (pf->bigEndian ? ", big endian" : ", little endian")));
+ if (pf->trueColour) {
+ rfbLog(" true colour: max r %d g %d b %d, shift r %d g %d b %d\n",
+ pf->redMax, pf->greenMax, pf->blueMax,
+ pf->redShift, pf->greenShift, pf->blueShift);
+ } else {
+ rfbLog(" uses a colour map (not true colour).\n");
+ }
+ }
+}
diff --git a/libvncserver/vncauth.c b/libvncserver/vncauth.c
new file mode 100644
index 0000000..2146e67
--- /dev/null
+++ b/libvncserver/vncauth.c
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 1999 AT&T Laboratories Cambridge. 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 program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+/*
+ * vncauth.c - Functions for VNC password management and authentication.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <rfb/rfbproto.h>
+#include "d3des.h"
+
+#include <string.h>
+#include <math.h>
+
+#ifdef LIBVNCSERVER_HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef LIBVNCSERVER_HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+#include <time.h>
+
+#ifdef WIN32
+#define srandom srand
+#define random rand
+#else
+#include <sys/time.h>
+#endif
+
+
+/*
+ * We use a fixed key to store passwords, since we assume that our local
+ * file system is secure but nonetheless don't want to store passwords
+ * as plaintext.
+ */
+
+static unsigned char fixedkey[8] = {23,82,107,6,35,78,88,7};
+
+
+/*
+ * Encrypt a password and store it in a file. Returns 0 if successful,
+ * 1 if the file could not be written.
+ */
+
+int
+vncEncryptAndStorePasswd(char *passwd, char *fname)
+{
+ FILE *fp;
+ unsigned int i;
+ unsigned char encryptedPasswd[8];
+
+ if ((fp = fopen(fname,"w")) == NULL) return 1;
+
+ /* windows security sux */
+#ifndef WIN32
+ fchmod(fileno(fp), S_IRUSR|S_IWUSR);
+#endif
+
+ /* pad password with nulls */
+
+ for (i = 0; i < 8; i++) {
+ if (i < strlen(passwd)) {
+ encryptedPasswd[i] = passwd[i];
+ } else {
+ encryptedPasswd[i] = 0;
+ }
+ }
+
+ /* Do encryption in-place - this way we overwrite our copy of the plaintext
+ password */
+
+ deskey(fixedkey, EN0);
+ des(encryptedPasswd, encryptedPasswd);
+
+ for (i = 0; i < 8; i++) {
+ putc(encryptedPasswd[i], fp);
+ }
+
+ fclose(fp);
+ return 0;
+}
+
+
+/*
+ * Decrypt a password from a file. Returns a pointer to a newly allocated
+ * string containing the password or a null pointer if the password could
+ * not be retrieved for some reason.
+ */
+
+char *
+vncDecryptPasswdFromFile(char *fname)
+{
+ FILE *fp;
+ int i, ch;
+ unsigned char *passwd = (unsigned char *)malloc(9);
+
+ if ((fp = fopen(fname,"r")) == NULL) return NULL;
+
+ for (i = 0; i < 8; i++) {
+ ch = getc(fp);
+ if (ch == EOF) {
+ fclose(fp);
+ return NULL;
+ }
+ passwd[i] = ch;
+ }
+
+ fclose(fp);
+
+ deskey(fixedkey, DE1);
+ des(passwd, passwd);
+
+ passwd[8] = 0;
+
+ return (char *)passwd;
+}
+
+
+/*
+ * Generate CHALLENGESIZE random bytes for use in challenge-response
+ * authentication.
+ */
+
+void
+vncRandomBytes(unsigned char *bytes)
+{
+ int i;
+ static rfbBool s_srandom_called = FALSE;
+
+ if (!s_srandom_called) {
+ srandom((unsigned int)time(0) ^ (unsigned int)getpid());
+ s_srandom_called = TRUE;
+ }
+
+ for (i = 0; i < CHALLENGESIZE; i++) {
+ bytes[i] = (unsigned char)(random() & 255);
+ }
+}
+
+
+/*
+ * Encrypt CHALLENGESIZE bytes in memory using a password.
+ */
+
+void
+vncEncryptBytes(unsigned char *bytes, char *passwd)
+{
+ unsigned char key[8];
+ unsigned int i;
+
+ /* key is simply password padded with nulls */
+
+ for (i = 0; i < 8; i++) {
+ if (i < strlen(passwd)) {
+ key[i] = passwd[i];
+ } else {
+ key[i] = 0;
+ }
+ }
+
+ deskey(key, EN0);
+
+ for (i = 0; i < CHALLENGESIZE; i += 8) {
+ des(bytes+i, bytes+i);
+ }
+}
diff --git a/libvncserver/zlib.c b/libvncserver/zlib.c
new file mode 100644
index 0000000..9905810
--- /dev/null
+++ b/libvncserver/zlib.c
@@ -0,0 +1,302 @@
+/*
+ * zlib.c
+ *
+ * Routines to implement zlib based encoding (deflate).
+ */
+
+/*
+ * Copyright (C) 2000 Tridia Corporation. All Rights Reserved.
+ * Copyright (C) 1999 AT&T Laboratories Cambridge. 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.
+ *
+ * For the latest source code, please check:
+ *
+ * http://www.developVNC.org/
+ *
+ * or send email to feedback@developvnc.org.
+ */
+
+#include <rfb/rfb.h>
+
+/*
+ * zlibBeforeBuf contains pixel data in the client's format.
+ * zlibAfterBuf contains the zlib (deflated) encoding version.
+ * If the zlib compressed/encoded version is
+ * larger than the raw data or if it exceeds zlibAfterBufSize then
+ * raw encoding is used instead.
+ */
+
+static int zlibBeforeBufSize = 0;
+static char *zlibBeforeBuf = NULL;
+
+static int zlibAfterBufSize = 0;
+static char *zlibAfterBuf = NULL;
+static int zlibAfterBufLen;
+
+/*
+ * rfbSendOneRectEncodingZlib - send a given rectangle using one Zlib
+ * rectangle encoding.
+ */
+
+rfbBool
+rfbSendOneRectEncodingZlib(cl, x, y, w, h)
+ rfbClientPtr cl;
+ int x, y, w, h;
+{
+ rfbFramebufferUpdateRectHeader rect;
+ rfbZlibHeader hdr;
+ int deflateResult;
+ int previousOut;
+ int i;
+ char *fbptr = (cl->screen->frameBuffer + (cl->screen->paddedWidthInBytes * y)
+ + (x * (cl->screen->bitsPerPixel / 8)));
+
+ int maxRawSize;
+ int maxCompSize;
+
+ maxRawSize = (cl->screen->width * cl->screen->height
+ * (cl->format.bitsPerPixel / 8));
+
+ if (zlibBeforeBufSize < maxRawSize) {
+ zlibBeforeBufSize = maxRawSize;
+ if (zlibBeforeBuf == NULL)
+ zlibBeforeBuf = (char *)malloc(zlibBeforeBufSize);
+ else
+ zlibBeforeBuf = (char *)realloc(zlibBeforeBuf, zlibBeforeBufSize);
+ }
+
+ /* zlib compression is not useful for very small data sets.
+ * So, we just send these raw without any compression.
+ */
+ if (( w * h * (cl->screen->bitsPerPixel / 8)) <
+ VNC_ENCODE_ZLIB_MIN_COMP_SIZE ) {
+
+ int result;
+
+ /* The translation function (used also by the in raw encoding)
+ * requires 4/2/1 byte alignment in the output buffer (which is
+ * updateBuf for the raw encoding) based on the bitsPerPixel of
+ * the viewer/client. This prevents SIGBUS errors on some
+ * architectures like SPARC, PARISC...
+ */
+ if (( cl->format.bitsPerPixel > 8 ) &&
+ ( cl->ublen % ( cl->format.bitsPerPixel / 8 )) != 0 ) {
+ if (!rfbSendUpdateBuf(cl))
+ return FALSE;
+ }
+
+ result = rfbSendRectEncodingRaw(cl, x, y, w, h);
+
+ return result;
+
+ }
+
+ /*
+ * zlib requires output buffer to be slightly larger than the input
+ * buffer, in the worst case.
+ */
+ maxCompSize = maxRawSize + (( maxRawSize + 99 ) / 100 ) + 12;
+
+ if (zlibAfterBufSize < maxCompSize) {
+ zlibAfterBufSize = maxCompSize;
+ if (zlibAfterBuf == NULL)
+ zlibAfterBuf = (char *)malloc(zlibAfterBufSize);
+ else
+ zlibAfterBuf = (char *)realloc(zlibAfterBuf, zlibAfterBufSize);
+ }
+
+ /*
+ * Convert pixel data to client format.
+ */
+ (*cl->translateFn)(cl->translateLookupTable, &cl->screen->rfbServerFormat,
+ &cl->format, fbptr, zlibBeforeBuf,
+ cl->screen->paddedWidthInBytes, w, h);
+
+ cl->compStream.next_in = ( Bytef * )zlibBeforeBuf;
+ cl->compStream.avail_in = w * h * (cl->format.bitsPerPixel / 8);
+ cl->compStream.next_out = ( Bytef * )zlibAfterBuf;
+ cl->compStream.avail_out = maxCompSize;
+ cl->compStream.data_type = Z_BINARY;
+
+ /* Initialize the deflation state. */
+ if ( cl->compStreamInited == FALSE ) {
+
+ cl->compStream.total_in = 0;
+ cl->compStream.total_out = 0;
+ cl->compStream.zalloc = Z_NULL;
+ cl->compStream.zfree = Z_NULL;
+ cl->compStream.opaque = Z_NULL;
+
+ deflateInit2( &(cl->compStream),
+ cl->zlibCompressLevel,
+ Z_DEFLATED,
+ MAX_WBITS,
+ MAX_MEM_LEVEL,
+ Z_DEFAULT_STRATEGY );
+ /* deflateInit( &(cl->compStream), Z_BEST_COMPRESSION ); */
+ /* deflateInit( &(cl->compStream), Z_BEST_SPEED ); */
+ cl->compStreamInited = TRUE;
+
+ }
+
+ previousOut = cl->compStream.total_out;
+
+ /* Perform the compression here. */
+ deflateResult = deflate( &(cl->compStream), Z_SYNC_FLUSH );
+
+ /* Find the total size of the resulting compressed data. */
+ zlibAfterBufLen = cl->compStream.total_out - previousOut;
+
+ if ( deflateResult != Z_OK ) {
+ rfbErr("zlib deflation error: %s\n", cl->compStream.msg);
+ return FALSE;
+ }
+
+ /* Note that it is not possible to switch zlib parameters based on
+ * the results of the compression pass. The reason is
+ * that we rely on the compressor and decompressor states being
+ * in sync. Compressing and then discarding the results would
+ * cause lose of synchronization.
+ */
+
+ /* Update statics */
+ cl->rfbRectanglesSent[rfbEncodingZlib]++;
+ cl->rfbBytesSent[rfbEncodingZlib] += (sz_rfbFramebufferUpdateRectHeader
+ + sz_rfbZlibHeader + zlibAfterBufLen);
+
+ if (cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbZlibHeader
+ > UPDATE_BUF_SIZE)
+ {
+ if (!rfbSendUpdateBuf(cl))
+ return FALSE;
+ }
+
+ rect.r.x = Swap16IfLE(x);
+ rect.r.y = Swap16IfLE(y);
+ rect.r.w = Swap16IfLE(w);
+ rect.r.h = Swap16IfLE(h);
+ rect.encoding = Swap32IfLE(rfbEncodingZlib);
+
+ memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
+ sz_rfbFramebufferUpdateRectHeader);
+ cl->ublen += sz_rfbFramebufferUpdateRectHeader;
+
+ hdr.nBytes = Swap32IfLE(zlibAfterBufLen);
+
+ memcpy(&cl->updateBuf[cl->ublen], (char *)&hdr, sz_rfbZlibHeader);
+ cl->ublen += sz_rfbZlibHeader;
+
+ for (i = 0; i < zlibAfterBufLen;) {
+
+ int bytesToCopy = UPDATE_BUF_SIZE - cl->ublen;
+
+ if (i + bytesToCopy > zlibAfterBufLen) {
+ bytesToCopy = zlibAfterBufLen - i;
+ }
+
+ memcpy(&cl->updateBuf[cl->ublen], &zlibAfterBuf[i], bytesToCopy);
+
+ cl->ublen += bytesToCopy;
+ i += bytesToCopy;
+
+ if (cl->ublen == UPDATE_BUF_SIZE) {
+ if (!rfbSendUpdateBuf(cl))
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+
+}
+
+
+/*
+ * rfbSendRectEncodingZlib - send a given rectangle using one or more
+ * Zlib encoding rectangles.
+ */
+
+rfbBool
+rfbSendRectEncodingZlib(cl, x, y, w, h)
+ rfbClientPtr cl;
+ int x, y, w, h;
+{
+ int maxLines;
+ int linesRemaining;
+ rfbRectangle partialRect;
+
+ partialRect.x = x;
+ partialRect.y = y;
+ partialRect.w = w;
+ partialRect.h = h;
+
+ /* Determine maximum pixel/scan lines allowed per rectangle. */
+ maxLines = ( ZLIB_MAX_SIZE(w) / w );
+
+ /* Initialize number of scan lines left to do. */
+ linesRemaining = h;
+
+ /* Loop until all work is done. */
+ while ( linesRemaining > 0 ) {
+
+ int linesToComp;
+
+ if ( maxLines < linesRemaining )
+ linesToComp = maxLines;
+ else
+ linesToComp = linesRemaining;
+
+ partialRect.h = linesToComp;
+
+ /* Encode (compress) and send the next rectangle. */
+ if ( ! rfbSendOneRectEncodingZlib( cl,
+ partialRect.x,
+ partialRect.y,
+ partialRect.w,
+ partialRect.h )) {
+
+ return FALSE;
+ }
+
+ /* Technically, flushing the buffer here is not extrememly
+ * efficient. However, this improves the overall throughput
+ * of the system over very slow networks. By flushing
+ * the buffer with every maximum size zlib rectangle, we
+ * improve the pipelining usage of the server CPU, network,
+ * and viewer CPU components. Insuring that these components
+ * are working in parallel actually improves the performance
+ * seen by the user.
+ * Since, zlib is most useful for slow networks, this flush
+ * is appropriate for the desired behavior of the zlib encoding.
+ */
+ if (( cl->ublen > 0 ) &&
+ ( linesToComp == maxLines )) {
+ if (!rfbSendUpdateBuf(cl)) {
+
+ return FALSE;
+ }
+ }
+
+ /* Update remaining and incremental rectangle location. */
+ linesRemaining -= linesToComp;
+ partialRect.y += linesToComp;
+
+ }
+
+ return TRUE;
+
+}
+
diff --git a/libvncserver/zrle.c b/libvncserver/zrle.c
new file mode 100644
index 0000000..6ab933e
--- /dev/null
+++ b/libvncserver/zrle.c
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2002 RealVNC Ltd. All Rights Reserved.
+ * Copyright (C) 2003 Sun Microsystems, Inc.
+ *
+ * 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.c
+ *
+ * Routines to implement Zlib Run-length Encoding (ZRLE).
+ */
+
+#include "rfb/rfb.h"
+#include "zrleoutstream.h"
+
+
+#define GET_IMAGE_INTO_BUF(tx,ty,tw,th,buf) \
+{ char *fbptr = (cl->screen->frameBuffer \
+ + (cl->screen->paddedWidthInBytes * ty) \
+ + (tx * (cl->screen->bitsPerPixel / 8))); \
+ \
+ (*cl->translateFn)(cl->translateLookupTable, &cl->screen->rfbServerFormat,\
+ &cl->format, fbptr, (char*)buf, \
+ cl->screen->paddedWidthInBytes, tw, th); }
+
+#define EXTRA_ARGS , rfbClientPtr cl
+
+#define BPP 8
+#include <zrleencodetemplate.c>
+#undef BPP
+#define BPP 16
+#include <zrleencodetemplate.c>
+#undef BPP
+#define BPP 32
+#include <zrleencodetemplate.c>
+#define CPIXEL 24A
+#include <zrleencodetemplate.c>
+#undef CPIXEL
+#define CPIXEL 24B
+#include <zrleencodetemplate.c>
+#undef CPIXEL
+#undef BPP
+
+
+/*
+ * zrleBeforeBuf contains pixel data in the client's format. It must 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.
+ */
+
+static char zrleBeforeBuf[rfbZRLETileWidth * rfbZRLETileHeight * 4 + 4];
+
+
+
+/*
+ * rfbSendRectEncodingZRLE - send a given rectangle using ZRLE encoding.
+ */
+
+
+rfbBool rfbSendRectEncodingZRLE(rfbClientPtr cl, int x, int y, int w, int h)
+{
+ zrleOutStream* zos;
+ rfbFramebufferUpdateRectHeader rect;
+ rfbZRLEHeader hdr;
+ int i;
+
+ if (!cl->zrleData)
+ cl->zrleData = zrleOutStreamNew();
+ zos = cl->zrleData;
+ zos->in.ptr = zos->in.start;
+ zos->out.ptr = zos->out.start;
+
+ switch (cl->format.bitsPerPixel) {
+
+ case 8:
+ zrleEncode8( x, y, w, h, zos, zrleBeforeBuf, cl);
+ break;
+
+ case 16:
+ zrleEncode16(x, y, w, h, zos, zrleBeforeBuf, cl);
+ break;
+
+ case 32: {
+ rfbBool fitsInLS3Bytes
+ = ((cl->format.redMax << cl->format.redShift) < (1<<24) &&
+ (cl->format.greenMax << cl->format.greenShift) < (1<<24) &&
+ (cl->format.blueMax << cl->format.blueShift) < (1<<24));
+
+ rfbBool fitsInMS3Bytes = (cl->format.redShift > 7 &&
+ cl->format.greenShift > 7 &&
+ cl->format.blueShift > 7);
+
+ if ((fitsInLS3Bytes && !cl->format.bigEndian) ||
+ (fitsInMS3Bytes && cl->format.bigEndian))
+ {
+ zrleEncode24A(x, y, w, h, zos, zrleBeforeBuf, cl);
+ }
+ else if ((fitsInLS3Bytes && cl->format.bigEndian) ||
+ (fitsInMS3Bytes && !cl->format.bigEndian))
+ {
+ zrleEncode24B(x, y, w, h, zos, zrleBeforeBuf, cl);
+ }
+ else
+ {
+ zrleEncode32(x, y, w, h, zos, zrleBeforeBuf, cl);
+ }
+ }
+ break;
+ }
+
+ cl->rfbRectanglesSent[rfbEncodingZRLE]++;
+ cl->rfbBytesSent[rfbEncodingZRLE] += (sz_rfbFramebufferUpdateRectHeader
+ + sz_rfbZRLEHeader + ZRLE_BUFFER_LENGTH(&zos->out));
+
+ if (cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbZRLEHeader
+ > UPDATE_BUF_SIZE)
+ {
+ if (!rfbSendUpdateBuf(cl))
+ return FALSE;
+ }
+
+ rect.r.x = Swap16IfLE(x);
+ rect.r.y = Swap16IfLE(y);
+ rect.r.w = Swap16IfLE(w);
+ rect.r.h = Swap16IfLE(h);
+ rect.encoding = Swap32IfLE(rfbEncodingZRLE);
+
+ memcpy(cl->updateBuf+cl->ublen, (char *)&rect,
+ sz_rfbFramebufferUpdateRectHeader);
+ cl->ublen += sz_rfbFramebufferUpdateRectHeader;
+
+ hdr.length = Swap32IfLE(ZRLE_BUFFER_LENGTH(&zos->out));
+
+ memcpy(cl->updateBuf+cl->ublen, (char *)&hdr, sz_rfbZRLEHeader);
+ cl->ublen += sz_rfbZRLEHeader;
+
+ /* copy into updateBuf and send from there. Maybe should send directly? */
+
+ for (i = 0; i < ZRLE_BUFFER_LENGTH(&zos->out);) {
+
+ int bytesToCopy = UPDATE_BUF_SIZE - cl->ublen;
+
+ if (i + bytesToCopy > ZRLE_BUFFER_LENGTH(&zos->out)) {
+ bytesToCopy = ZRLE_BUFFER_LENGTH(&zos->out) - i;
+ }
+
+ memcpy(cl->updateBuf+cl->ublen, (uint8_t*)zos->out.start + i, bytesToCopy);
+
+ cl->ublen += bytesToCopy;
+ i += bytesToCopy;
+
+ if (cl->ublen == UPDATE_BUF_SIZE) {
+ if (!rfbSendUpdateBuf(cl))
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+void FreeZrleData(rfbClientPtr cl)
+{
+ if (cl->zrleData)
+ zrleOutStreamFree(cl->zrleData);
+ cl->zrleData = NULL;
+}
+
diff --git a/libvncserver/zrleencodetemplate.c b/libvncserver/zrleencodetemplate.c
new file mode 100644
index 0000000..a1772ae
--- /dev/null
+++ b/libvncserver/zrleencodetemplate.c
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2002 RealVNC Ltd. All Rights Reserved.
+ * Copyright (C) 2003 Sun Microsystems, Inc.
+ *
+ * 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.
+ */
+
+/*
+ * Before including this file, you must define a number of CPP macros.
+ *
+ * BPP should be 8, 16 or 32 depending on the bits per pixel.
+ * GET_IMAGE_INTO_BUF should be some code which gets a rectangle of pixel data
+ * into the given buffer. EXTRA_ARGS can be defined to pass any other
+ * arguments needed by GET_IMAGE_INTO_BUF.
+ *
+ * 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 "zrleoutstream.h"
+#include "zrlepalettehelper.h"
+#include <assert.h>
+
+/* __RFB_CONCAT2 concatenates its two arguments. __RFB_CONCAT2E does the same
+ but also expands its arguments if they are macros */
+
+#ifndef __RFB_CONCAT2E
+#define __RFB_CONCAT2(a,b) a##b
+#define __RFB_CONCAT2E(a,b) __RFB_CONCAT2(a,b)
+#endif
+
+#ifdef CPIXEL
+#define PIXEL_T __RFB_CONCAT2E(zrle_U,BPP)
+#define zrleOutStreamWRITE_PIXEL __RFB_CONCAT2E(zrleOutStreamWriteOpaque,CPIXEL)
+#define ZRLE_ENCODE __RFB_CONCAT2E(zrleEncode,CPIXEL)
+#define ZRLE_ENCODE_TILE __RFB_CONCAT2E(zrleEncodeTile,CPIXEL)
+#define BPPOUT 24
+#else
+#define PIXEL_T __RFB_CONCAT2E(zrle_U,BPP)
+#define zrleOutStreamWRITE_PIXEL __RFB_CONCAT2E(zrleOutStreamWriteOpaque,BPP)
+#define ZRLE_ENCODE __RFB_CONCAT2E(zrleEncode,BPP)
+#define ZRLE_ENCODE_TILE __RFB_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
+};
+
+static zrlePaletteHelper paletteHelper;
+
+#endif /* ZRLE_ONCE */
+
+void ZRLE_ENCODE_TILE (PIXEL_T* data, int w, int h, zrleOutStream* os);
+
+void ZRLE_ENCODE (int x, int y, int w, int h,
+ zrleOutStream* os, void* buf
+ EXTRA_ARGS
+ )
+{
+ int ty;
+ for (ty = y; ty < y+h; ty += rfbZRLETileHeight) {
+ int tx, th = rfbZRLETileHeight;
+ if (th > y+h-ty) th = y+h-ty;
+ for (tx = x; tx < x+w; tx += rfbZRLETileWidth) {
+ int tw = rfbZRLETileWidth;
+ if (tw > x+w-tx) tw = x+w-tx;
+
+ GET_IMAGE_INTO_BUF(tx,ty,tw,th,buf);
+
+ ZRLE_ENCODE_TILE((PIXEL_T*)buf, tw, th, os);
+ }
+ }
+ zrleOutStreamFlush(os);
+}
+
+
+void ZRLE_ENCODE_TILE (PIXEL_T* data, int w, int h, zrleOutStream* os)
+{
+ /* First find the palette and the number of runs */
+
+ zrlePaletteHelper *ph;
+
+ int runs = 0;
+ int singlePixels = 0;
+
+ rfbBool useRle;
+ rfbBool usePalette;
+
+ int estimatedBytes;
+ int plainRleBytes;
+ int i;
+
+ PIXEL_T* ptr = data;
+ PIXEL_T* end = ptr + h * w;
+ *end = ~*(end-1); /* one past the end is different so the while loop ends */
+
+ ph = &paletteHelper;
+ zrlePaletteHelperInit(ph);
+
+ while (ptr < end) {
+ PIXEL_T pix = *ptr;
+ if (*++ptr != pix) {
+ singlePixels++;
+ } else {
+ while (*++ptr == pix) ;
+ runs++;
+ }
+ zrlePaletteHelperInsert(ph, pix);
+ }
+
+ /* Solid tile is a special case */
+
+ if (ph->size == 1) {
+ zrleOutStreamWriteU8(os, 1);
+ zrleOutStreamWRITE_PIXEL(os, 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...
+
+ useRle = FALSE;
+ usePalette = FALSE;
+
+ estimatedBytes = w * h * (BPPOUT/8); // start assuming raw
+
+ 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;
+
+ zrleOutStreamWriteU8(os, (useRle ? 128 : 0) | ph->size);
+
+ for (i = 0; i < ph->size; i++) {
+ zrleOutStreamWRITE_PIXEL(os, ph->palette[i]);
+ }
+
+ if (useRle) {
+
+ PIXEL_T* ptr = data;
+ PIXEL_T* end = ptr + w * h;
+ PIXEL_T* runStart;
+ PIXEL_T pix;
+ while (ptr < end) {
+ int len;
+ runStart = ptr;
+ pix = *ptr++;
+ while (*ptr == pix && ptr < end)
+ ptr++;
+ len = ptr - runStart;
+ if (len <= 2 && usePalette) {
+ int index = zrlePaletteHelperLookup(ph, pix);
+ if (len == 2)
+ zrleOutStreamWriteU8(os, index);
+ zrleOutStreamWriteU8(os, index);
+ continue;
+ }
+ if (usePalette) {
+ int index = zrlePaletteHelperLookup(ph, pix);
+ zrleOutStreamWriteU8(os, index | 128);
+ } else {
+ zrleOutStreamWRITE_PIXEL(os, pix);
+ }
+ len -= 1;
+ while (len >= 255) {
+ zrleOutStreamWriteU8(os, 255);
+ len -= 255;
+ }
+ zrleOutStreamWriteU8(os, len);
+ }
+
+ } else {
+
+ // no RLE
+
+ if (usePalette) {
+ int bppp;
+ PIXEL_T* ptr = data;
+
+ // packed pixels
+
+ assert (ph->size < 17);
+
+ bppp = bitsPerPackedPixel[ph->size-1];
+
+ for (i = 0; i < h; i++) {
+ zrle_U8 nbits = 0;
+ zrle_U8 byte = 0;
+
+ PIXEL_T* eol = ptr + w;
+
+ while (ptr < eol) {
+ PIXEL_T pix = *ptr++;
+ zrle_U8 index = zrlePaletteHelperLookup(ph, pix);
+ byte = (byte << bppp) | index;
+ nbits += bppp;
+ if (nbits >= 8) {
+ zrleOutStreamWriteU8(os, byte);
+ nbits = 0;
+ }
+ }
+ if (nbits > 0) {
+ byte <<= 8 - nbits;
+ zrleOutStreamWriteU8(os, byte);
+ }
+ }
+ } else {
+
+ // raw
+
+#ifdef CPIXEL
+ PIXEL_T *ptr;
+ for (ptr = data; ptr < data+w*h; ptr++) {
+ zrleOutStreamWRITE_PIXEL(os, *ptr);
+ }
+#else
+ zrleOutStreamWriteBytes(os, (zrle_U8 *)data, w*h*(BPP/8));
+#endif
+ }
+ }
+}
+
+#undef PIXEL_T
+#undef zrleOutStreamWRITE_PIXEL
+#undef ZRLE_ENCODE
+#undef ZRLE_ENCODE_TILE
+#undef BPPOUT
diff --git a/libvncserver/zrleoutstream.c b/libvncserver/zrleoutstream.c
new file mode 100644
index 0000000..d22d649
--- /dev/null
+++ b/libvncserver/zrleoutstream.c
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2002 RealVNC Ltd. All Rights Reserved.
+ * Copyright (C) 2003 Sun Microsystems, Inc.
+ *
+ * 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 "zrleoutstream.h"
+#include <stdlib.h>
+
+#define ZRLE_IN_BUFFER_SIZE 16384
+#define ZRLE_OUT_BUFFER_SIZE 1024
+#undef ZRLE_DEBUG
+
+static rfbBool zrleBufferAlloc(zrleBuffer *buffer, int size)
+{
+ buffer->ptr = buffer->start = malloc(size);
+ if (buffer->start == NULL) {
+ buffer->end = NULL;
+ return FALSE;
+ }
+
+ buffer->end = buffer->start + size;
+
+ return TRUE;
+}
+
+static void zrleBufferFree(zrleBuffer *buffer)
+{
+ if (buffer->start)
+ free(buffer->start);
+ buffer->start = buffer->ptr = buffer->end = NULL;
+}
+
+static rfbBool zrleBufferGrow(zrleBuffer *buffer, int size)
+{
+ int offset;
+
+ size += buffer->end - buffer->start;
+ offset = ZRLE_BUFFER_LENGTH (buffer);
+
+ buffer->start = realloc(buffer->start, size);
+ if (!buffer->start) {
+ return FALSE;
+ }
+
+ buffer->end = buffer->start + size;
+ buffer->ptr = buffer->start + offset;
+
+ return TRUE;
+}
+
+zrleOutStream *zrleOutStreamNew(void)
+{
+ zrleOutStream *os;
+
+ os = malloc(sizeof(zrleOutStream));
+ if (os == NULL)
+ return NULL;
+
+ if (!zrleBufferAlloc(&os->in, ZRLE_IN_BUFFER_SIZE)) {
+ free(os);
+ return NULL;
+ }
+
+ if (!zrleBufferAlloc(&os->out, ZRLE_OUT_BUFFER_SIZE)) {
+ zrleBufferFree(&os->in);
+ free(os);
+ return NULL;
+ }
+
+ os->zs.zalloc = Z_NULL;
+ os->zs.zfree = Z_NULL;
+ os->zs.opaque = Z_NULL;
+ if (deflateInit(&os->zs, Z_DEFAULT_COMPRESSION) != Z_OK) {
+ zrleBufferFree(&os->in);
+ free(os);
+ return NULL;
+ }
+
+ return os;
+}
+
+void zrleOutStreamFree (zrleOutStream *os)
+{
+ deflateEnd(&os->zs);
+ zrleBufferFree(&os->in);
+ zrleBufferFree(&os->out);
+ free(os);
+}
+
+rfbBool zrleOutStreamFlush(zrleOutStream *os)
+{
+ os->zs.next_in = os->in.start;
+ os->zs.avail_in = ZRLE_BUFFER_LENGTH (&os->in);
+
+#ifdef ZRLE_DEBUG
+ rfbLog("zrleOutStreamFlush: avail_in %d\n", os->zs.avail_in);
+#endif
+
+ while (os->zs.avail_in != 0) {
+ do {
+ int ret;
+
+ if (os->out.ptr >= os->out.end &&
+ !zrleBufferGrow(&os->out, os->out.end - os->out.start)) {
+ rfbLog("zrleOutStreamFlush: failed to grow output buffer\n");
+ return FALSE;
+ }
+
+ os->zs.next_out = os->out.ptr;
+ os->zs.avail_out = os->out.end - os->out.ptr;
+
+#ifdef ZRLE_DEBUG
+ rfbLog("zrleOutStreamFlush: calling deflate, avail_in %d, avail_out %d\n",
+ os->zs.avail_in, os->zs.avail_out);
+#endif
+
+ if ((ret = deflate(&os->zs, Z_SYNC_FLUSH)) != Z_OK) {
+ rfbLog("zrleOutStreamFlush: deflate failed with error code %d\n", ret);
+ return FALSE;
+ }
+
+#ifdef ZRLE_DEBUG
+ rfbLog("zrleOutStreamFlush: after deflate: %d bytes\n",
+ os->zs.next_out - os->out.ptr);
+#endif
+
+ os->out.ptr = os->zs.next_out;
+ } while (os->zs.avail_out == 0);
+ }
+
+ os->in.ptr = os->in.start;
+
+ return TRUE;
+}
+
+static int zrleOutStreamOverrun(zrleOutStream *os,
+ int size)
+{
+#ifdef ZRLE_DEBUG
+ rfbLog("zrleOutStreamOverrun\n");
+#endif
+
+ while (os->in.end - os->in.ptr < size && os->in.ptr > os->in.start) {
+ os->zs.next_in = os->in.start;
+ os->zs.avail_in = ZRLE_BUFFER_LENGTH (&os->in);
+
+ do {
+ int ret;
+
+ if (os->out.ptr >= os->out.end &&
+ !zrleBufferGrow(&os->out, os->out.end - os->out.start)) {
+ rfbLog("zrleOutStreamOverrun: failed to grow output buffer\n");
+ return FALSE;
+ }
+
+ os->zs.next_out = os->out.ptr;
+ os->zs.avail_out = os->out.end - os->out.ptr;
+
+#ifdef ZRLE_DEBUG
+ rfbLog("zrleOutStreamOverrun: calling deflate, avail_in %d, avail_out %d\n",
+ os->zs.avail_in, os->zs.avail_out);
+#endif
+
+ if ((ret = deflate(&os->zs, 0)) != Z_OK) {
+ rfbLog("zrleOutStreamOverrun: deflate failed with error code %d\n", ret);
+ return 0;
+ }
+
+#ifdef ZRLE_DEBUG
+ rfbLog("zrleOutStreamOverrun: after deflate: %d bytes\n",
+ os->zs.next_out - os->out.ptr);
+#endif
+
+ os->out.ptr = os->zs.next_out;
+ } while (os->zs.avail_out == 0);
+
+ /* output buffer not full */
+
+ if (os->zs.avail_in == 0) {
+ os->in.ptr = os->in.start;
+ } else {
+ /* but didn't consume all the data? try shifting what's left to the
+ * start of the buffer.
+ */
+ rfbLog("zrleOutStreamOverrun: out buf not full, but in data not consumed\n");
+ memmove(os->in.start, os->zs.next_in, os->in.ptr - os->zs.next_in);
+ os->in.ptr -= os->zs.next_in - os->in.start;
+ }
+ }
+
+ if (size > os->in.end - os->in.ptr)
+ size = os->in.end - os->in.ptr;
+
+ return size;
+}
+
+static inline int zrleOutStreamCheck(zrleOutStream *os,
+ int size)
+{
+ if (os->in.ptr + size > os->in.end) {
+ return zrleOutStreamOverrun(os, size);
+ }
+ return size;
+}
+
+void zrleOutStreamWriteBytes(zrleOutStream *os,
+ const zrle_U8 *data,
+ int length)
+{
+ const zrle_U8* dataEnd = data + length;
+ while (data < dataEnd) {
+ int n = zrleOutStreamCheck(os, dataEnd - data);
+ memcpy(os->in.ptr, data, n);
+ os->in.ptr += n;
+ data += n;
+ }
+}
+
+void zrleOutStreamWriteU8(zrleOutStream *os, zrle_U8 u)
+{
+ zrleOutStreamCheck(os, 1);
+ *os->in.ptr++ = u;
+}
+
+void zrleOutStreamWriteOpaque8(zrleOutStream *os, zrle_U8 u)
+{
+ zrleOutStreamCheck(os, 1);
+ *os->in.ptr++ = u;
+}
+
+void zrleOutStreamWriteOpaque16 (zrleOutStream *os, zrle_U16 u)
+{
+ zrleOutStreamCheck(os, 2);
+ *os->in.ptr++ = ((zrle_U8*)&u)[0];
+ *os->in.ptr++ = ((zrle_U8*)&u)[1];
+}
+
+void zrleOutStreamWriteOpaque32 (zrleOutStream *os, zrle_U32 u)
+{
+ zrleOutStreamCheck(os, 4);
+ *os->in.ptr++ = ((zrle_U8*)&u)[0];
+ *os->in.ptr++ = ((zrle_U8*)&u)[1];
+ *os->in.ptr++ = ((zrle_U8*)&u)[2];
+ *os->in.ptr++ = ((zrle_U8*)&u)[3];
+}
+
+void zrleOutStreamWriteOpaque24A(zrleOutStream *os, zrle_U32 u)
+{
+ zrleOutStreamCheck(os, 3);
+ *os->in.ptr++ = ((zrle_U8*)&u)[0];
+ *os->in.ptr++ = ((zrle_U8*)&u)[1];
+ *os->in.ptr++ = ((zrle_U8*)&u)[2];
+}
+
+void zrleOutStreamWriteOpaque24B(zrleOutStream *os, zrle_U32 u)
+{
+ zrleOutStreamCheck(os, 3);
+ *os->in.ptr++ = ((zrle_U8*)&u)[1];
+ *os->in.ptr++ = ((zrle_U8*)&u)[2];
+ *os->in.ptr++ = ((zrle_U8*)&u)[3];
+}
diff --git a/libvncserver/zrleoutstream.h b/libvncserver/zrleoutstream.h
new file mode 100644
index 0000000..9e4fe51
--- /dev/null
+++ b/libvncserver/zrleoutstream.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2002 RealVNC Ltd. All Rights Reserved.
+ * Copyright (C) 2003 Sun Microsystems, Inc.
+ *
+ * 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 __ZRLE_OUT_STREAM_H__
+#define __ZRLE_OUT_STREAM_H__
+
+#include <zlib.h>
+#include "zrletypes.h"
+#include "rfb/rfb.h"
+
+typedef struct {
+ zrle_U8 *start;
+ zrle_U8 *ptr;
+ zrle_U8 *end;
+} zrleBuffer;
+
+typedef struct {
+ zrleBuffer in;
+ zrleBuffer out;
+
+ z_stream zs;
+} zrleOutStream;
+
+#define ZRLE_BUFFER_LENGTH(b) ((b)->ptr - (b)->start)
+
+zrleOutStream *zrleOutStreamNew (void);
+void zrleOutStreamFree (zrleOutStream *os);
+rfbBool zrleOutStreamFlush (zrleOutStream *os);
+void zrleOutStreamWriteBytes (zrleOutStream *os,
+ const zrle_U8 *data,
+ int length);
+void zrleOutStreamWriteU8 (zrleOutStream *os,
+ zrle_U8 u);
+void zrleOutStreamWriteOpaque8 (zrleOutStream *os,
+ zrle_U8 u);
+void zrleOutStreamWriteOpaque16 (zrleOutStream *os,
+ zrle_U16 u);
+void zrleOutStreamWriteOpaque32 (zrleOutStream *os,
+ zrle_U32 u);
+void zrleOutStreamWriteOpaque24A(zrleOutStream *os,
+ zrle_U32 u);
+void zrleOutStreamWriteOpaque24B(zrleOutStream *os,
+ zrle_U32 u);
+
+#endif /* __ZRLE_OUT_STREAM_H__ */
diff --git a/libvncserver/zrlepalettehelper.c b/libvncserver/zrlepalettehelper.c
new file mode 100644
index 0000000..d758a26
--- /dev/null
+++ b/libvncserver/zrlepalettehelper.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2002 RealVNC Ltd. All Rights Reserved.
+ * Copyright (C) 2003 Sun Microsystems, Inc.
+ *
+ * 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 "zrlepalettehelper.h"
+#include <assert.h>
+#include <string.h>
+
+#define ZRLE_HASH(pix) (((pix) ^ ((pix) >> 17)) & 4095)
+
+void zrlePaletteHelperInit(zrlePaletteHelper *helper)
+{
+ memset(helper->palette, 0, sizeof(helper->palette));
+ memset(helper->index, 255, sizeof(helper->index));
+ memset(helper->key, 0, sizeof(helper->key));
+ helper->size = 0;
+}
+
+void zrlePaletteHelperInsert(zrlePaletteHelper *helper, zrle_U32 pix)
+{
+ if (helper->size < ZRLE_PALETTE_MAX_SIZE) {
+ int i = ZRLE_HASH(pix);
+
+ while (helper->index[i] != 255 && helper->key[i] != pix)
+ i++;
+ if (helper->index[i] != 255) return;
+
+ helper->index[i] = helper->size;
+ helper->key[i] = pix;
+ helper->palette[helper->size] = pix;
+ }
+ helper->size++;
+}
+
+int zrlePaletteHelperLookup(zrlePaletteHelper *helper, zrle_U32 pix)
+{
+ int i = ZRLE_HASH(pix);
+
+ assert(helper->size <= ZRLE_PALETTE_MAX_SIZE);
+
+ while (helper->index[i] != 255 && helper->key[i] != pix)
+ i++;
+ if (helper->index[i] != 255) return helper->index[i];
+
+ return -1;
+}
diff --git a/libvncserver/zrlepalettehelper.h b/libvncserver/zrlepalettehelper.h
new file mode 100644
index 0000000..e1213d1
--- /dev/null
+++ b/libvncserver/zrlepalettehelper.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2002 RealVNC Ltd. All Rights Reserved.
+ * Copyright (C) 2003 Sun Microsystems, Inc.
+ *
+ * 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 PaletteHelper class helps us build up the palette from pixel data by
+ * storing a reverse index using a simple hash-table
+ */
+
+#ifndef __ZRLE_PALETTE_HELPER_H__
+#define __ZRLE_PALETTE_HELPER_H__
+
+#include "zrletypes.h"
+
+#define ZRLE_PALETTE_MAX_SIZE 127
+
+typedef struct {
+ zrle_U32 palette[ZRLE_PALETTE_MAX_SIZE];
+ zrle_U8 index[ZRLE_PALETTE_MAX_SIZE + 4096];
+ zrle_U32 key[ZRLE_PALETTE_MAX_SIZE + 4096];
+ int size;
+} zrlePaletteHelper;
+
+void zrlePaletteHelperInit (zrlePaletteHelper *helper);
+void zrlePaletteHelperInsert(zrlePaletteHelper *helper,
+ zrle_U32 pix);
+int zrlePaletteHelperLookup(zrlePaletteHelper *helper,
+ zrle_U32 pix);
+
+#endif /* __ZRLE_PALETTE_HELPER_H__ */
diff --git a/libvncserver/zrletypes.h b/libvncserver/zrletypes.h
new file mode 100755
index 0000000..0df42c9
--- /dev/null
+++ b/libvncserver/zrletypes.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2002 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 __ZRLE_TYPES_H__
+#define __ZRLE_TYPES_H__
+
+typedef unsigned char zrle_U8;
+typedef unsigned short zrle_U16;
+typedef unsigned int zrle_U32;
+typedef signed char zrle_S8;
+typedef signed short zrle_S16;
+typedef signed int zrle_S32;
+
+#endif /* __ZRLE_TYPES_H__ */