Migrating to new directory structure adopted from the RealVNC's source tree. More changes will follow.

git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@589 3789f03b-4d11-0410-bbf8-ca57d06f2519
diff --git a/common/rdr/Exception.cxx b/common/rdr/Exception.cxx
new file mode 100644
index 0000000..7d38711
--- /dev/null
+++ b/common/rdr/Exception.cxx
@@ -0,0 +1,73 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+#include <rdr/Exception.h>
+#ifdef _WIN32
+#include <tchar.h>
+#include <winsock2.h>
+#include <windows.h>
+#endif
+
+using namespace rdr;
+
+SystemException::SystemException(const char* s, int err_)
+  : Exception(s), err(err_)
+{
+  strncat(str_, ": ", len-1-strlen(str_));
+#ifdef _WIN32
+  // Windows error messages are crap, so use unix ones for common errors.
+  const char* msg = 0;
+  switch (err) {
+  case WSAECONNREFUSED: msg = "Connection refused";       break;
+  case WSAETIMEDOUT:    msg = "Connection timed out";     break;
+  case WSAECONNRESET:   msg = "Connection reset by peer"; break;
+  case WSAECONNABORTED: msg = "Connection aborted";       break;
+  }
+  if (msg) {
+    strncat(str_, msg, len-1-strlen(str_));
+  } else {
+#ifdef UNICODE
+    WCHAR* tmsg = new WCHAR[len-strlen(str_)];
+    FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+                  0, err, 0, tmsg, len-1-strlen(str_), 0);
+    WideCharToMultiByte(CP_ACP, 0, tmsg, wcslen(tmsg)+1,
+		              str_+strlen(str_), len-strlen(str_), 0, 0);
+    delete [] tmsg;
+#else
+    char* currStr = str_+strlen(str_);
+    FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+                  0, err, 0, currStr, len-1-strlen(str_), 0);
+#endif
+    int l = strlen(str_);
+    if ((l >= 2) && (str_[l-2] == '\r') && (str_[l-1] == '\n'))
+      str_[l-2] = 0;
+  }
+
+#else
+  strncat(str_, strerror(err), len-1-strlen(str_));
+#endif
+  strncat(str_, " (", len-1-strlen(str_));
+  char buf[20];
+#ifdef WIN32
+  if (err < 0)
+    sprintf(buf, "%x", err);
+  else
+#endif
+    sprintf(buf,"%d",err);
+  strncat(str_, buf, len-1-strlen(str_));
+  strncat(str_, ")", len-1-strlen(str_));
+}
diff --git a/common/rdr/Exception.h b/common/rdr/Exception.h
new file mode 100644
index 0000000..1b92f77
--- /dev/null
+++ b/common/rdr/Exception.h
@@ -0,0 +1,58 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+#ifndef __RDR_EXCEPTION_H__
+#define __RDR_EXCEPTION_H__
+
+#include <stdio.h>
+#include <string.h>
+
+namespace rdr {
+
+  struct Exception {
+    enum { len = 256 };
+    char str_[len];
+    Exception(const char* s=0) {
+      str_[0] = 0;
+      if (s)
+        strncat(str_, s, len-1);
+      else
+        strcat(str_, "Exception");
+    }
+    virtual const char* str() const { return str_; }
+  };
+
+  struct SystemException : public Exception {
+    int err;
+    SystemException(const char* s, int err_);
+  }; 
+
+  struct TimedOut : public Exception {
+    TimedOut(const char* s="Timed out") : Exception(s) {}
+  };
+ 
+  struct EndOfStream : public Exception {
+    EndOfStream(const char* s="End of stream") : Exception(s) {}
+  };
+
+  struct FrameException : public Exception {
+    FrameException(const char* s="Frame exception") : Exception(s) {}
+  };
+}
+
+#endif
diff --git a/common/rdr/FdInStream.cxx b/common/rdr/FdInStream.cxx
new file mode 100644
index 0000000..2b11973
--- /dev/null
+++ b/common/rdr/FdInStream.cxx
@@ -0,0 +1,304 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#ifdef _WIN32
+#include <winsock2.h>
+#ifndef _WIN32_WCE
+#include <sys/timeb.h>
+#endif
+#define read(s,b,l) recv(s,(char*)b,l,0)
+#define close closesocket
+#undef errno
+#define errno WSAGetLastError()
+#undef EINTR
+#define EINTR WSAEINTR
+#else
+#include <sys/types.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/time.h>
+#endif
+
+#ifndef vncmin
+#define vncmin(a,b)            (((a) < (b)) ? (a) : (b))
+#endif
+#ifndef vncmax
+#define vncmax(a,b)            (((a) > (b)) ? (a) : (b))
+#endif
+
+// XXX should use autoconf HAVE_SYS_SELECT_H
+#ifdef _AIX
+#include <sys/select.h>
+#endif
+
+// XXX Lynx/OS 2.3: protos for gettimeofday(), select(), bzero()
+#ifdef Lynx
+#include <sys/proto.h>
+#endif
+
+#include <rdr/FdInStream.h>
+#include <rdr/Exception.h>
+
+using namespace rdr;
+
+enum { DEFAULT_BUF_SIZE = 8192,
+       MIN_BULK_SIZE = 1024 };
+
+FdInStream::FdInStream(int fd_, int timeoutms_, int bufSize_,
+                       bool closeWhenDone_)
+  : fd(fd_), closeWhenDone(closeWhenDone_),
+    timeoutms(timeoutms_), blockCallback(0),
+    timing(false), timeWaitedIn100us(5), timedKbits(0),
+    bufSize(bufSize_ ? bufSize_ : DEFAULT_BUF_SIZE), offset(0)
+{
+  ptr = end = start = new U8[bufSize];
+}
+
+FdInStream::FdInStream(int fd_, FdInStreamBlockCallback* blockCallback_,
+                       int bufSize_)
+  : fd(fd_), timeoutms(0), blockCallback(blockCallback_),
+    timing(false), timeWaitedIn100us(5), timedKbits(0),
+    bufSize(bufSize_ ? bufSize_ : DEFAULT_BUF_SIZE), offset(0)
+{
+  ptr = end = start = new U8[bufSize];
+}
+
+FdInStream::~FdInStream()
+{
+  delete [] start;
+  if (closeWhenDone) close(fd);
+}
+
+
+void FdInStream::setTimeout(int timeoutms_) {
+  timeoutms = timeoutms_;
+}
+
+void FdInStream::setBlockCallback(FdInStreamBlockCallback* blockCallback_)
+{
+  blockCallback = blockCallback_;
+  timeoutms = 0;
+}
+
+int FdInStream::pos()
+{
+  return offset + ptr - start;
+}
+
+void FdInStream::readBytes(void* data, int length)
+{
+  if (length < MIN_BULK_SIZE) {
+    InStream::readBytes(data, length);
+    return;
+  }
+
+  U8* dataPtr = (U8*)data;
+
+  int n = end - ptr;
+  if (n > length) n = length;
+
+  memcpy(dataPtr, ptr, n);
+  dataPtr += n;
+  length -= n;
+  ptr += n;
+
+  while (length > 0) {
+    n = readWithTimeoutOrCallback(dataPtr, length);
+    dataPtr += n;
+    length -= n;
+    offset += n;
+  }
+}
+
+
+int FdInStream::overrun(int itemSize, int nItems, bool wait)
+{
+  if (itemSize > bufSize)
+    throw Exception("FdInStream overrun: max itemSize exceeded");
+
+  if (end - ptr != 0)
+    memmove(start, ptr, end - ptr);
+
+  offset += ptr - start;
+  end -= ptr - start;
+  ptr = start;
+
+  int bytes_to_read;
+  while (end < start + itemSize) {
+    bytes_to_read = start + bufSize - end;
+    if (!timing) {
+      // When not timing, we must be careful not to read too much
+      // extra data into the buffer. Otherwise, the line speed
+      // estimation might stay at zero for a long time: All reads
+      // during timing=1 can be satisfied without calling
+      // readWithTimeoutOrCallback. However, reading only 1 or 2 bytes
+      // bytes is ineffecient.
+      bytes_to_read = vncmin(bytes_to_read, vncmax(itemSize*nItems, 8));
+    }
+    int n = readWithTimeoutOrCallback((U8*)end, bytes_to_read, wait);
+    if (n == 0) return 0;
+    end += n;
+  }
+
+  if (itemSize * nItems > end - ptr)
+    nItems = (end - ptr) / itemSize;
+
+  return nItems;
+}
+
+#ifdef _WIN32
+static void gettimeofday(struct timeval* tv, void*)
+{
+  LARGE_INTEGER counts, countsPerSec;
+  static double usecPerCount = 0.0;
+
+  if (QueryPerformanceCounter(&counts)) {
+    if (usecPerCount == 0.0) {
+      QueryPerformanceFrequency(&countsPerSec);
+      usecPerCount = 1000000.0 / countsPerSec.QuadPart;
+    }
+
+    LONGLONG usecs = (LONGLONG)(counts.QuadPart * usecPerCount);
+    tv->tv_usec = (long)(usecs % 1000000);
+    tv->tv_sec = (long)(usecs / 1000000);
+
+  } else {
+#ifndef _WIN32_WCE
+    struct timeb tb;
+    ftime(&tb);
+    tv->tv_sec = tb.time;
+    tv->tv_usec = tb.millitm * 1000;
+#else
+    throw SystemException("QueryPerformanceCounter", GetLastError());
+#endif
+  }
+}
+#endif
+
+//
+// readWithTimeoutOrCallback() reads up to the given length in bytes from the
+// file descriptor into a buffer.  If the wait argument is false, then zero is
+// returned if no bytes can be read without blocking.  Otherwise if a
+// blockCallback is set, it will be called (repeatedly) instead of blocking.
+// If alternatively there is a timeout set and that timeout expires, it throws
+// a TimedOut exception.  Otherwise it returns the number of bytes read.  It
+// never attempts to read() unless select() indicates that the fd is readable -
+// this means it can be used on an fd which has been set non-blocking.  It also
+// has to cope with the annoying possibility of both select() and read()
+// returning EINTR.
+//
+
+int FdInStream::readWithTimeoutOrCallback(void* buf, int len, bool wait)
+{
+  struct timeval before, after;
+  if (timing)
+    gettimeofday(&before, 0);
+
+  int n;
+  while (true) {
+    do {
+      fd_set fds;
+      struct timeval tv;
+      struct timeval* tvp = &tv;
+
+      if (!wait) {
+        tv.tv_sec = tv.tv_usec = 0;
+      } else if (timeoutms != -1) {
+        tv.tv_sec = timeoutms / 1000;
+        tv.tv_usec = (timeoutms % 1000) * 1000;
+      } else {
+        tvp = 0;
+      }
+
+      FD_ZERO(&fds);
+      FD_SET(fd, &fds);
+      n = select(fd+1, &fds, 0, 0, tvp);
+    } while (n < 0 && errno == EINTR);
+
+    if (n > 0) break;
+    if (n < 0) throw SystemException("select",errno);
+    if (!wait) return 0;
+    if (!blockCallback) throw TimedOut();
+
+    blockCallback->blockCallback();
+  }
+
+  do {
+    n = ::read(fd, buf, len);
+  } while (n < 0 && errno == EINTR);
+
+  if (n < 0) throw SystemException("read",errno);
+  if (n == 0) throw EndOfStream();
+
+  if (timing) {
+    gettimeofday(&after, 0);
+//      fprintf(stderr,"%d.%06d\n",(after.tv_sec - before.tv_sec),
+//              (after.tv_usec - before.tv_usec));
+    int newTimeWaited = ((after.tv_sec - before.tv_sec) * 10000 +
+                         (after.tv_usec - before.tv_usec) / 100);
+    int newKbits = n * 8 / 1000;
+
+//      if (newTimeWaited == 0) {
+//        fprintf(stderr,"new kbps infinite t %d k %d\n",
+//                newTimeWaited, newKbits);
+//      } else {
+//        fprintf(stderr,"new kbps %d t %d k %d\n",
+//                newKbits * 10000 / newTimeWaited, newTimeWaited, newKbits);
+//      }
+
+    // limit rate to between 10kbit/s and 40Mbit/s
+
+    if (newTimeWaited > newKbits*1000) newTimeWaited = newKbits*1000;
+    if (newTimeWaited < newKbits/4)    newTimeWaited = newKbits/4;
+
+    timeWaitedIn100us += newTimeWaited;
+    timedKbits += newKbits;
+  }
+
+  return n;
+}
+
+void FdInStream::startTiming()
+{
+  timing = true;
+
+  // Carry over up to 1s worth of previous rate for smoothing.
+
+  if (timeWaitedIn100us > 10000) {
+    timedKbits = timedKbits * 10000 / timeWaitedIn100us;
+    timeWaitedIn100us = 10000;
+  }
+}
+
+void FdInStream::stopTiming()
+{
+  timing = false; 
+  if (timeWaitedIn100us < timedKbits/2)
+    timeWaitedIn100us = timedKbits/2; // upper limit 20Mbit/s
+}
+
+unsigned int FdInStream::kbitsPerSecond()
+{
+  // The following calculation will overflow 32-bit arithmetic if we have
+  // received more than about 50Mbytes (400Mbits) since we started timing, so
+  // it should be OK for a single RFB update.
+
+  return timedKbits * 10000 / timeWaitedIn100us;
+}
diff --git a/common/rdr/FdInStream.h b/common/rdr/FdInStream.h
new file mode 100644
index 0000000..5d9598c
--- /dev/null
+++ b/common/rdr/FdInStream.h
@@ -0,0 +1,77 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+//
+// FdInStream streams from a file descriptor.
+//
+
+#ifndef __RDR_FDINSTREAM_H__
+#define __RDR_FDINSTREAM_H__
+
+#include <rdr/InStream.h>
+
+namespace rdr {
+
+  class FdInStreamBlockCallback {
+  public:
+    virtual void blockCallback() = 0;
+  };
+
+  class FdInStream : public InStream {
+
+  public:
+
+    FdInStream(int fd, int timeoutms=-1, int bufSize=0,
+               bool closeWhenDone_=false);
+    FdInStream(int fd, FdInStreamBlockCallback* blockCallback, int bufSize=0);
+    virtual ~FdInStream();
+
+    void setTimeout(int timeoutms);
+    void setBlockCallback(FdInStreamBlockCallback* blockCallback);
+    int getFd() { return fd; }
+    int pos();
+    void readBytes(void* data, int length);
+
+    void startTiming();
+    void stopTiming();
+    unsigned int kbitsPerSecond();
+    unsigned int timeWaited() { return timeWaitedIn100us; }
+
+  protected:
+    int overrun(int itemSize, int nItems, bool wait);
+
+  private:
+    int readWithTimeoutOrCallback(void* buf, int len, bool wait=true);
+
+    int fd;
+    bool closeWhenDone;
+    int timeoutms;
+    FdInStreamBlockCallback* blockCallback;
+
+    bool timing;
+    unsigned int timeWaitedIn100us;
+    unsigned int timedKbits;
+
+    int bufSize;
+    int offset;
+    U8* start;
+  };
+
+} // end of namespace rdr
+
+#endif
diff --git a/common/rdr/FdOutStream.cxx b/common/rdr/FdOutStream.cxx
new file mode 100644
index 0000000..07ac04c
--- /dev/null
+++ b/common/rdr/FdOutStream.cxx
@@ -0,0 +1,159 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#ifdef _WIN32
+#include <winsock2.h>
+#define write(s,b,l) send(s,(const char*)b,l,0)
+#define EWOULDBLOCK WSAEWOULDBLOCK
+#undef errno
+#define errno WSAGetLastError()
+#undef EINTR
+#define EINTR WSAEINTR
+#else
+#include <sys/types.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/time.h>
+#endif
+
+// XXX Lynx/OS 2.3: protos for select(), bzero()
+#ifdef Lynx
+#include <sys/proto.h>
+#endif
+
+#include <rdr/FdOutStream.h>
+#include <rdr/Exception.h>
+
+
+using namespace rdr;
+
+enum { DEFAULT_BUF_SIZE = 16384 };
+
+FdOutStream::FdOutStream(int fd_, int timeoutms_, int bufSize_)
+  : fd(fd_), timeoutms(timeoutms_),
+    bufSize(bufSize_ ? bufSize_ : DEFAULT_BUF_SIZE), offset(0)
+{
+  ptr = start = new U8[bufSize];
+  end = start + bufSize;
+}
+
+FdOutStream::~FdOutStream()
+{
+  try {
+    flush();
+  } catch (Exception&) {
+  }
+  delete [] start;
+}
+
+void FdOutStream::setTimeout(int timeoutms_) {
+  timeoutms = timeoutms_;
+}
+
+int FdOutStream::length()
+{
+  return offset + ptr - start;
+}
+
+void FdOutStream::flush()
+{
+  U8* sentUpTo = start;
+  while (sentUpTo < ptr) {
+    int n = writeWithTimeout((const void*) sentUpTo, ptr - sentUpTo);
+    sentUpTo += n;
+    offset += n;
+  }
+
+  ptr = start;
+}
+
+
+int FdOutStream::overrun(int itemSize, int nItems)
+{
+  if (itemSize > bufSize)
+    throw Exception("FdOutStream overrun: max itemSize exceeded");
+
+  flush();
+
+  if (itemSize * nItems > end - ptr)
+    nItems = (end - ptr) / itemSize;
+
+  return nItems;
+}
+
+//
+// writeWithTimeout() writes up to the given length in bytes from the given
+// buffer to the file descriptor.  If there is a timeout set and that timeout
+// expires, it throws a TimedOut exception.  Otherwise it returns the number of
+// bytes written.  It never attempts to write() unless select() indicates that
+// the fd is writable - this means it can be used on an fd which has been set
+// non-blocking.  It also has to cope with the annoying possibility of both
+// select() and write() returning EINTR.
+//
+
+int FdOutStream::writeWithTimeout(const void* data, int length)
+{
+  int n;
+
+  do {
+
+    do {
+      fd_set fds;
+      struct timeval tv;
+      struct timeval* tvp = &tv;
+
+      if (timeoutms != -1) {
+        tv.tv_sec = timeoutms / 1000;
+        tv.tv_usec = (timeoutms % 1000) * 1000;
+      } else {
+        tvp = 0;
+      }
+
+      FD_ZERO(&fds);
+      FD_SET(fd, &fds);
+#ifdef _WIN32_WCE
+      // NB: This fixes a broken Winsock2 select() behaviour.  select()
+      // never returns for non-blocking sockets, unless they're already
+      // ready to be written to...
+      u_long zero = 0; ioctlsocket(fd, FIONBIO, &zero);
+#endif
+      n = select(fd+1, 0, &fds, 0, tvp);
+#ifdef _WIN32_WCE
+      u_long one = 0; ioctlsocket(fd, FIONBIO, &one);
+#endif
+    } while (n < 0 && errno == EINTR);
+
+    if (n < 0) throw SystemException("select",errno);
+
+    if (n == 0) throw TimedOut();
+
+    do {
+      n = ::write(fd, data, length);
+    } while (n < 0 && (errno == EINTR));
+      
+    // NB: This outer loop simply fixes a broken Winsock2 EWOULDBLOCK
+    // condition, found only under Win98 (first edition), with slow
+    // network connections.  Should in fact never ever happen...
+  } while (n < 0 && (errno == EWOULDBLOCK));
+
+  if (n < 0) throw SystemException("write",errno);
+
+  return n;
+}
diff --git a/common/rdr/FdOutStream.h b/common/rdr/FdOutStream.h
new file mode 100644
index 0000000..a3e2912
--- /dev/null
+++ b/common/rdr/FdOutStream.h
@@ -0,0 +1,55 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+//
+// FdOutStream streams to a file descriptor.
+//
+
+#ifndef __RDR_FDOUTSTREAM_H__
+#define __RDR_FDOUTSTREAM_H__
+
+#include <rdr/OutStream.h>
+
+namespace rdr {
+
+  class FdOutStream : public OutStream {
+
+  public:
+
+    FdOutStream(int fd, int timeoutms=-1, int bufSize=0);
+    virtual ~FdOutStream();
+
+    void setTimeout(int timeoutms);
+    int getFd() { return fd; }
+
+    void flush();
+    int length();
+
+  private:
+    int overrun(int itemSize, int nItems);
+    int writeWithTimeout(const void* data, int length);
+    int fd;
+    int timeoutms;
+    int bufSize;
+    int offset;
+    U8* start;
+  };
+
+}
+
+#endif
diff --git a/common/rdr/FixedMemOutStream.h b/common/rdr/FixedMemOutStream.h
new file mode 100644
index 0000000..e4ec52c
--- /dev/null
+++ b/common/rdr/FixedMemOutStream.h
@@ -0,0 +1,52 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+//
+// A FixedMemOutStream writes to a buffer of a fixed length.
+//
+
+#ifndef __RDR_FIXEDMEMOUTSTREAM_H__
+#define __RDR_FIXEDMEMOUTSTREAM_H__
+
+#include <rdr/OutStream.h>
+#include <rdr/Exception.h>
+
+namespace rdr {
+
+  class FixedMemOutStream : public OutStream {
+
+  public:
+
+    FixedMemOutStream(void* buf, int len) {
+      ptr = start = (U8*)buf;
+      end = start + len;
+    }
+
+    int length() { return ptr - start; }
+    void reposition(int pos) { ptr = start + pos; }
+    const void* data() { return (const void*)start; }
+
+  private:
+
+    int overrun(int itemSize, int nItems) { throw EndOfStream(); }
+    U8* start;
+  };
+
+}
+
+#endif
diff --git a/common/rdr/HexInStream.cxx b/common/rdr/HexInStream.cxx
new file mode 100644
index 0000000..80f8a79
--- /dev/null
+++ b/common/rdr/HexInStream.cxx
@@ -0,0 +1,117 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+#include <rdr/HexInStream.h>
+#include <rdr/Exception.h>
+
+#include <stdlib.h>
+#include <ctype.h>
+
+using namespace rdr;
+
+const int DEFAULT_BUF_LEN = 16384;
+
+static inline int min(int a, int b) {return a<b ? a : b;}
+
+HexInStream::HexInStream(InStream& is, int bufSize_)
+: bufSize(bufSize_ ? bufSize_ : DEFAULT_BUF_LEN), offset(0), in_stream(is)
+{
+  ptr = end = start = new U8[bufSize];
+}
+
+HexInStream::~HexInStream() {
+  delete [] start;
+}
+
+
+bool HexInStream::readHexAndShift(char c, int* v) {
+  c=tolower(c);
+  if ((c >= '0') && (c <= '9'))
+    *v = (*v << 4) + (c - '0');
+  else if ((c >= 'a') && (c <= 'f'))
+    *v = (*v << 4) + (c - 'a' + 10);
+  else
+    return false;
+  return true;
+}
+
+bool HexInStream::hexStrToBin(const char* s, char** data, int* length) {
+  int l=strlen(s);
+  if ((l % 2) == 0) {
+    delete [] *data;
+    *data = 0; *length = 0;
+    if (l == 0)
+      return true;
+    *data = new char[l/2];
+    *length = l/2;
+    for(int i=0;i<l;i+=2) {
+      int byte = 0;
+      if (!readHexAndShift(s[i], &byte) ||
+        !readHexAndShift(s[i+1], &byte))
+        goto decodeError;
+      (*data)[i/2] = byte;
+    }
+    return true;
+  }
+decodeError:
+  delete [] *data;
+  *data = 0;
+  *length = 0;
+  return false;
+}
+
+
+int HexInStream::pos() {
+  return offset + ptr - start;
+}
+
+int HexInStream::overrun(int itemSize, int nItems, bool wait) {
+  if (itemSize > bufSize)
+    throw Exception("HexInStream overrun: max itemSize exceeded");
+
+  if (end - ptr != 0)
+    memmove(start, ptr, end - ptr);
+
+  end -= ptr - start;
+  offset += ptr - start;
+  ptr = start;
+
+  while (end < ptr + itemSize) {
+    int n = in_stream.check(2, 1, wait);
+    if (n == 0) return 0;
+    const U8* iptr = in_stream.getptr();
+    const U8* eptr = in_stream.getend();
+    int length = min((eptr - iptr)/2, start + bufSize - end);
+
+    U8* optr = (U8*) end;
+    for (int i=0; i<length; i++) {
+      int v = 0;
+      readHexAndShift(iptr[i*2], &v);
+      readHexAndShift(iptr[i*2+1], &v);
+      optr[i] = v;
+    }
+
+    in_stream.setptr(iptr + length*2);
+    end += length;
+  }
+
+  if (itemSize * nItems > end - ptr)
+    nItems = (end - ptr) / itemSize;
+
+  return nItems;
+}
diff --git a/common/rdr/HexInStream.h b/common/rdr/HexInStream.h
new file mode 100644
index 0000000..6bfb843
--- /dev/null
+++ b/common/rdr/HexInStream.h
@@ -0,0 +1,50 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+#ifndef __RDR_HEX_INSTREAM_H__
+#define __RDR_HEX_INSTREAM_H__
+
+#include <rdr/InStream.h>
+
+namespace rdr {
+
+  class HexInStream : public InStream {
+  public:
+
+    HexInStream(InStream& is, int bufSize=0);
+    virtual ~HexInStream();
+
+    int pos();
+
+    static bool readHexAndShift(char c, int* v);
+    static bool hexStrToBin(const char* s, char** data, int* length);
+
+  protected:
+    int overrun(int itemSize, int nItems, bool wait);
+
+  private:
+    int bufSize;
+    U8* start;
+    int offset;
+
+    InStream& in_stream;
+  };
+
+} // end of namespace rdr
+
+#endif
diff --git a/common/rdr/HexOutStream.cxx b/common/rdr/HexOutStream.cxx
new file mode 100644
index 0000000..9b0b6c4
--- /dev/null
+++ b/common/rdr/HexOutStream.cxx
@@ -0,0 +1,110 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+#include <rdr/HexOutStream.h>
+#include <rdr/Exception.h>
+
+using namespace rdr;
+
+const int DEFAULT_BUF_LEN = 16384;
+
+static inline int min(int a, int b) {return a<b ? a : b;}
+
+HexOutStream::HexOutStream(OutStream& os, int buflen)
+: out_stream(os), offset(0), bufSize(buflen ? buflen : DEFAULT_BUF_LEN)
+{
+  if (bufSize % 2)
+    bufSize--;
+  ptr = start = new U8[bufSize];
+  end = start + bufSize;
+}
+
+HexOutStream::~HexOutStream() {
+  delete [] start;
+}
+
+
+char HexOutStream::intToHex(int i) {
+  if ((i>=0) && (i<=9))
+    return '0'+i;
+  else if ((i>=10) && (i<=15))
+    return 'a'+(i-10);
+  else
+    throw rdr::Exception("intToHex failed");
+}
+
+char* HexOutStream::binToHexStr(const char* data, int length) {
+  char* buffer = new char[length*2+1];
+  for (int i=0; i<length; i++) {
+    buffer[i*2] = intToHex((data[i] >> 4) & 15);
+    buffer[i*2+1] = intToHex((data[i] & 15));
+    if (!buffer[i*2] || !buffer[i*2+1]) {
+      delete [] buffer;
+      return 0;
+    }
+  }
+  buffer[length*2] = 0;
+  return buffer;
+}
+
+
+void
+HexOutStream::writeBuffer() {
+  U8* pos = start;
+  while (pos != ptr) {
+    out_stream.check(2);
+    U8* optr = out_stream.getptr();
+    U8* oend = out_stream.getend();
+    int length = min(ptr-pos, (oend-optr)/2);
+
+    for (int i=0; i<length; i++) {
+      optr[i*2] = intToHex((pos[i] >> 4) & 0xf);
+      optr[i*2+1] = intToHex(pos[i] & 0xf);
+    }
+
+    out_stream.setptr(optr + length*2);
+    pos += length;
+  }
+  offset += ptr - start;
+  ptr = start;
+}
+
+int HexOutStream::length()
+{
+  return offset + ptr - start;
+}
+
+void
+HexOutStream::flush() {
+  writeBuffer();
+  out_stream.flush();
+}
+
+int
+HexOutStream::overrun(int itemSize, int nItems) {
+  if (itemSize > bufSize)
+    throw Exception("HexOutStream overrun: max itemSize exceeded");
+
+  writeBuffer();
+
+  if (itemSize * nItems > end - ptr)
+    nItems = (end - ptr) / itemSize;
+
+  return nItems;
+}
+
diff --git a/common/rdr/HexOutStream.h b/common/rdr/HexOutStream.h
new file mode 100644
index 0000000..10247e6
--- /dev/null
+++ b/common/rdr/HexOutStream.h
@@ -0,0 +1,51 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+#ifndef __RDR_HEX_OUTSTREAM_H__
+#define __RDR_HEX_OUTSTREAM_H__
+
+#include <rdr/OutStream.h>
+
+namespace rdr {
+
+  class HexOutStream : public OutStream {
+  public:
+
+    HexOutStream(OutStream& os, int buflen=0);
+    virtual ~HexOutStream();
+
+    void flush();
+    int length();
+
+    static char intToHex(int i);
+    static char* binToHexStr(const char* data, int length);
+
+  private:
+    void writeBuffer();
+    int overrun(int itemSize, int nItems);
+
+    OutStream& out_stream;
+
+    U8* start;
+    int offset;
+    int bufSize;
+  };
+
+}
+
+#endif
diff --git a/common/rdr/InStream.cxx b/common/rdr/InStream.cxx
new file mode 100644
index 0000000..a413b6c
--- /dev/null
+++ b/common/rdr/InStream.cxx
@@ -0,0 +1,35 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+#include <rdr/InStream.h>
+#include <rdr/Exception.h>
+
+using namespace rdr;
+
+U32 InStream::maxStringLength = 65535;
+
+char* InStream::readString()
+{
+  U32 len = readU32();
+  if (len > maxStringLength)
+    throw Exception("InStream max string length exceeded");
+  char* str = new char[len+1];
+  readBytes(str, len);
+  str[len] = 0;
+  return str;
+}
diff --git a/common/rdr/InStream.h b/common/rdr/InStream.h
new file mode 100644
index 0000000..6d22ac6
--- /dev/null
+++ b/common/rdr/InStream.h
@@ -0,0 +1,170 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+//
+// rdr::InStream marshalls data from a buffer stored in RDR (RFB Data
+// Representation).
+//
+
+#ifndef __RDR_INSTREAM_H__
+#define __RDR_INSTREAM_H__
+
+#include <rdr/types.h>
+#include <string.h> // for memcpy
+
+namespace rdr {
+
+  class InStream {
+
+  public:
+
+    virtual ~InStream() {}
+
+    // check() ensures there is buffer data for at least one item of size
+    // itemSize bytes.  Returns the number of items in the buffer (up to a
+    // maximum of nItems).  If wait is false, then instead of blocking to wait
+    // for the bytes, zero is returned if the bytes are not immediately
+    // available.
+
+    inline int check(int itemSize, int nItems=1, bool wait=true)
+    {
+      if (ptr + itemSize * nItems > end) {
+        if (ptr + itemSize > end)
+          return overrun(itemSize, nItems, wait);
+
+        nItems = (end - ptr) / itemSize;
+      }
+      return nItems;
+    }
+
+    // checkNoWait() tries to make sure that the given number of bytes can
+    // be read without blocking.  It returns true if this is the case, false
+    // otherwise.  The length must be "small" (less than the buffer size).
+
+    inline bool checkNoWait(int length) { return check(length, 1, false)!=0; }
+
+    // readU/SN() methods read unsigned and signed N-bit integers.
+
+    inline U8  readU8()  { check(1); return *ptr++; }
+    inline U16 readU16() { check(2); int b0 = *ptr++; int b1 = *ptr++;
+                           return b0 << 8 | b1; }
+    inline U32 readU32() { check(4); int b0 = *ptr++; int b1 = *ptr++;
+                                     int b2 = *ptr++; int b3 = *ptr++;
+                           return b0 << 24 | b1 << 16 | b2 << 8 | b3; }
+
+    inline S8  readS8()  { return (S8) readU8();  }
+    inline S16 readS16() { return (S16)readU16(); }
+    inline S32 readS32() { return (S32)readU32(); }
+
+    // readCompactLength() reads 1..3 bytes representing length of the data
+    // following.  This method is used by the Tight decoder.
+
+    inline unsigned int readCompactLength() {
+      U8 b = readU8();
+      int result = (int)b & 0x7F;
+      if (b & 0x80) {
+        b = readU8();
+        result |= ((int)b & 0x7F) << 7;
+        if (b & 0x80) {
+          b = readU8();
+          result |= ((int)b & 0xFF) << 14;
+        }
+      }
+      return result;
+    }
+
+    // readString() reads a string - a U32 length followed by the data.
+    // Returns a null-terminated string - the caller should delete[] it
+    // afterwards.
+
+    char* readString();
+
+    // maxStringLength protects against allocating a huge buffer.  Set it
+    // higher if you need longer strings.
+
+    static U32 maxStringLength;
+
+    inline void skip(int bytes) {
+      while (bytes > 0) {
+        int n = check(1, bytes);
+        ptr += n;
+        bytes -= n;
+      }
+    }
+
+    // readBytes() reads an exact number of bytes.
+
+    virtual void readBytes(void* data, int length) {
+      U8* dataPtr = (U8*)data;
+      U8* dataEnd = dataPtr + length;
+      while (dataPtr < dataEnd) {
+        int n = check(1, dataEnd - dataPtr);
+        memcpy(dataPtr, ptr, n);
+        ptr += n;
+        dataPtr += n;
+      }
+    }
+
+    // readOpaqueN() reads a quantity without byte-swapping.
+
+    inline U8  readOpaque8()  { return readU8(); }
+    inline U16 readOpaque16() { check(2); U16 r; ((U8*)&r)[0] = *ptr++;
+                                ((U8*)&r)[1] = *ptr++; return r; }
+    inline U32 readOpaque32() { check(4); U32 r; ((U8*)&r)[0] = *ptr++;
+                                ((U8*)&r)[1] = *ptr++; ((U8*)&r)[2] = *ptr++;
+                                ((U8*)&r)[3] = *ptr++; return r; }
+    inline U32 readOpaque24A() { check(3); U32 r=0; ((U8*)&r)[0] = *ptr++;
+                                 ((U8*)&r)[1] = *ptr++; ((U8*)&r)[2] = *ptr++;
+                                 return r; }
+    inline U32 readOpaque24B() { check(3); U32 r=0; ((U8*)&r)[1] = *ptr++;
+                                 ((U8*)&r)[2] = *ptr++; ((U8*)&r)[3] = *ptr++;
+                                 return r; }
+
+    // pos() returns the position in the stream.
+
+    virtual int pos() = 0;
+
+    // getptr(), getend() and setptr() are "dirty" methods which allow you to
+    // manipulate the buffer directly.  This is useful for a stream which is a
+    // wrapper around an underlying stream.
+
+    inline const U8* getptr() const { return ptr; }
+    inline const U8* getend() const { return end; }
+    inline void setptr(const U8* p) { ptr = p; }
+
+  private:
+
+    // overrun() is implemented by a derived class to cope with buffer overrun.
+    // It ensures there are at least itemSize bytes of buffer data.  Returns
+    // the number of items in the buffer (up to a maximum of nItems).  itemSize
+    // is supposed to be "small" (a few bytes).  If wait is false, then
+    // instead of blocking to wait for the bytes, zero is returned if the bytes
+    // are not immediately available.
+
+    virtual int overrun(int itemSize, int nItems, bool wait=true) = 0;
+
+  protected:
+
+    InStream() {}
+    const U8* ptr;
+    const U8* end;
+  };
+
+}
+
+#endif
diff --git a/common/rdr/Makefile.in b/common/rdr/Makefile.in
new file mode 100644
index 0000000..09fa554
--- /dev/null
+++ b/common/rdr/Makefile.in
@@ -0,0 +1,19 @@
+
+SRCS = Exception.cxx FdInStream.cxx FdOutStream.cxx InStream.cxx \
+       RandomStream.cxx ZlibInStream.cxx ZlibOutStream.cxx \
+       HexInStream.cxx HexOutStream.cxx
+
+OBJS = $(SRCS:.cxx=.o)
+
+DIR_CPPFLAGS = -I$(top_srcdir) @ZLIB_INCLUDE@
+
+library = librdr.a
+
+all:: $(library)
+
+$(library): $(OBJS)
+	rm -f $(library)
+	$(AR) $(library) $(OBJS)
+	$(RANLIB) $(library)
+
+# followed by boilerplate.mk
diff --git a/common/rdr/MemInStream.h b/common/rdr/MemInStream.h
new file mode 100644
index 0000000..77ca3f3
--- /dev/null
+++ b/common/rdr/MemInStream.h
@@ -0,0 +1,63 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+//
+// rdr::MemInStream is an InStream which streams from a given memory buffer.
+// If the deleteWhenDone parameter is true then the buffer will be delete[]d in
+// the destructor.  Note that it is delete[]d as a U8* - strictly speaking this
+// means it ought to be new[]ed as a U8* as well, but on most platforms this
+// doesn't matter.
+//
+
+#ifndef __RDR_MEMINSTREAM_H__
+#define __RDR_MEMINSTREAM_H__
+
+#include <rdr/InStream.h>
+#include <rdr/Exception.h>
+
+namespace rdr {
+
+  class MemInStream : public InStream {
+
+  public:
+
+    MemInStream(const void* data, int len, bool deleteWhenDone_=false)
+      : start((const U8*)data), deleteWhenDone(deleteWhenDone_)
+    {
+      ptr = start;
+      end = start + len;
+    }
+
+    virtual ~MemInStream() {
+      if (deleteWhenDone)
+        delete [] (U8*)start;
+    }
+
+    int pos() { return ptr - start; }
+    void reposition(int pos) { ptr = start + pos; }
+
+  private:
+
+    int overrun(int itemSize, int nItems, bool wait) { throw EndOfStream(); }
+    const U8* start;
+    bool deleteWhenDone;
+  };
+
+}
+
+#endif
diff --git a/common/rdr/MemOutStream.h b/common/rdr/MemOutStream.h
new file mode 100644
index 0000000..ee3e950
--- /dev/null
+++ b/common/rdr/MemOutStream.h
@@ -0,0 +1,83 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+//
+// A MemOutStream grows as needed when data is written to it.
+//
+
+#ifndef __RDR_MEMOUTSTREAM_H__
+#define __RDR_MEMOUTSTREAM_H__
+
+#include <rdr/OutStream.h>
+
+namespace rdr {
+
+  class MemOutStream : public OutStream {
+
+  public:
+
+    MemOutStream(int len=1024) {
+      start = ptr = new U8[len];
+      end = start + len;
+    }
+
+    virtual ~MemOutStream() {
+      delete [] start;
+    }
+
+    void writeBytes(const void* data, int length) {
+      check(length);
+      memcpy(ptr, data, length);
+      ptr += length;
+    }
+
+    int length() { return ptr - start; }
+    void clear() { ptr = start; };
+    void clearAndZero() { memset(start, 0, ptr-start); clear(); }
+    void reposition(int pos) { ptr = start + pos; }
+
+    // data() returns a pointer to the buffer.
+
+    const void* data() { return (const void*)start; }
+
+  private:
+
+    // overrun() either doubles the buffer or adds enough space for nItems of
+    // size itemSize bytes.
+
+    int overrun(int itemSize, int nItems) {
+      int len = ptr - start + itemSize * nItems;
+      if (len < (end - start) * 2)
+        len = (end - start) * 2;
+
+      U8* newStart = new U8[len];
+      memcpy(newStart, start, ptr - start);
+      ptr = newStart + (ptr - start);
+      delete [] start;
+      start = newStart;
+      end = newStart + len;
+
+      return nItems;
+    }
+
+    U8* start;
+  };
+
+}
+
+#endif
diff --git a/common/rdr/OutStream.h b/common/rdr/OutStream.h
new file mode 100644
index 0000000..aed2eea
--- /dev/null
+++ b/common/rdr/OutStream.h
@@ -0,0 +1,171 @@
+/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
+ *    
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+//
+// rdr::OutStream marshalls data into a buffer stored in RDR (RFB Data
+// Representation).
+//
+
+#ifndef __RDR_OUTSTREAM_H__
+#define __RDR_OUTSTREAM_H__
+
+#include <rdr/types.h>
+#include <string.h> // for memcpy
+
+namespace rdr {
+
+  class OutStream {
+
+  protected:
+
+    OutStream() {}
+
+  public:
+
+    virtual ~OutStream() {}
+
+    // check() ensures there is buffer space for at least one item of size
+    // itemSize bytes.  Returns the number of items which fit (up to a maximum
+    // of nItems).
+
+    inline int check(int itemSize, int nItems=1)
+    {
+      if (ptr + itemSize * nItems > end) {
+        if (ptr + itemSize > end)
+          return overrun(itemSize, nItems);
+
+        nItems = (end - ptr) / itemSize;
+      }
+      return nItems;
+    }
+
+    // writeU/SN() methods write unsigned and signed N-bit integers.
+
+    inline void writeU8( U8  u) { check(1); *ptr++ = u; }
+    inline void writeU16(U16 u) { check(2); *ptr++ = u >> 8; *ptr++ = (U8)u; }
+    inline void writeU32(U32 u) { check(4); *ptr++ = u >> 24; *ptr++ = u >> 16;
+                                            *ptr++ = u >> 8; *ptr++ = u; }
+
+    inline void writeS8( S8  s) { writeU8((U8)s); }
+    inline void writeS16(S16 s) { writeU16((U16)s); }
+    inline void writeS32(S32 s) { writeU32((U32)s); }
+
+    // writeCompactLength() writes 1..3 bytes representing length of the data
+    // following.  This method is used by the Tight encoder.
+
+    inline void writeCompactLength(unsigned int len) {
+      U8 b = len & 0x7F;
+      if (len <= 0x7F) {
+        writeU8(b);
+      } else {
+        writeU8(b | 0x80);
+        b = len >> 7 & 0x7F;
+        if (len <= 0x3FFF) {
+          writeU8(b);
+        } else {
+          writeU8(b | 0x80);
+          writeU8(len >> 14 & 0xFF);
+        }
+      }
+    }
+
+    // writeString() writes a string - a U32 length followed by the data.  The
+    // given string should be null-terminated (but the terminating null is not
+    // written to the stream).
+
+    inline void writeString(const char* str) {
+      U32 len = strlen(str);
+      writeU32(len);
+      writeBytes(str, len);
+    }
+
+    inline void pad(int bytes) {
+      while (bytes-- > 0) writeU8(0);
+    }
+
+    inline void skip(int bytes) {
+      while (bytes > 0) {
+        int n = check(1, bytes);
+        ptr += n;
+        bytes -= n;
+      }
+    }
+
+    // writeBytes() writes an exact number of bytes.
+
+    virtual void writeBytes(const void* data, int length) {
+      const U8* dataPtr = (const U8*)data;
+      const U8* dataEnd = dataPtr + length;
+      while (dataPtr < dataEnd) {
+        int n = check(1, dataEnd - dataPtr);
+        memcpy(ptr, dataPtr, n);
+        ptr += n;
+        dataPtr += n;
+      }
+    }
+
+    // writeOpaqueN() writes a quantity without byte-swapping.
+
+    inline void writeOpaque8( U8  u) { writeU8(u); }
+    inline void writeOpaque16(U16 u) { check(2); *ptr++ = ((U8*)&u)[0];
+                                       *ptr++ = ((U8*)&u)[1]; }
+    inline void writeOpaque32(U32 u) { check(4); *ptr++ = ((U8*)&u)[0];
+                                       *ptr++ = ((U8*)&u)[1];
+                                       *ptr++ = ((U8*)&u)[2];
+                                       *ptr++ = ((U8*)&u)[3]; }
+    inline void writeOpaque24A(U32 u) { check(3); *ptr++ = ((U8*)&u)[0];
+                                        *ptr++ = ((U8*)&u)[1];
+                                        *ptr++ = ((U8*)&u)[2]; }
+    inline void writeOpaque24B(U32 u) { check(3); *ptr++ = ((U8*)&u)[1];
+                                        *ptr++ = ((U8*)&u)[2];
+                                        *ptr++ = ((U8*)&u)[3]; }
+
+    // length() returns the length of the stream.
+
+    virtual int length() = 0;
+
+    // flush() requests that the stream be flushed.
+
+    virtual void flush() {}
+
+    // getptr(), getend() and setptr() are "dirty" methods which allow you to
+    // manipulate the buffer directly.  This is useful for a stream which is a
+    // wrapper around an underlying stream.
+
+    inline U8* getptr() { return ptr; }
+    inline U8* getend() { return end; }
+    inline void setptr(U8* p) { ptr = p; }
+
+  private:
+
+    // overrun() is implemented by a derived class to cope with buffer overrun.
+    // It ensures there are at least itemSize bytes of buffer space.  Returns
+    // the number of items which fit (up to a maximum of nItems).  itemSize is
+    // supposed to be "small" (a few bytes).
+
+    virtual int overrun(int itemSize, int nItems) = 0;
+
+  protected:
+
+    U8* ptr;
+    U8* end;
+  };
+
+}
+
+#endif
diff --git a/common/rdr/RandomStream.cxx b/common/rdr/RandomStream.cxx
new file mode 100644
index 0000000..7056c2c
--- /dev/null
+++ b/common/rdr/RandomStream.cxx
@@ -0,0 +1,130 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+#include <rdr/RandomStream.h>
+#include <rdr/Exception.h>
+#include <time.h>
+#include <stdlib.h>
+#ifndef WIN32
+#include <unistd.h>
+#include <errno.h>
+#else
+#define getpid() GetCurrentProcessId()
+#ifndef RFB_HAVE_WINCRYPT
+#pragma message("  NOTE: Not building WinCrypt-based RandomStream")
+#endif
+#endif
+
+using namespace rdr;
+
+const int DEFAULT_BUF_LEN = 256;
+
+unsigned int RandomStream::seed;
+
+RandomStream::RandomStream()
+  : offset(0)
+{
+  ptr = end = start = new U8[DEFAULT_BUF_LEN];
+
+#ifdef RFB_HAVE_WINCRYPT
+  provider = 0;
+  if (!CryptAcquireContext(&provider, 0, 0, PROV_RSA_FULL, 0)) {
+    if (GetLastError() == NTE_BAD_KEYSET) {
+      if (!CryptAcquireContext(&provider, 0, 0, PROV_RSA_FULL, CRYPT_NEWKEYSET)) {
+        fprintf(stderr, "RandomStream: unable to create keyset\n");
+        provider = 0;
+      }
+    } else {
+      fprintf(stderr, "RandomStream: unable to acquire context\n");
+      provider = 0;
+    }
+  }
+  if (!provider) {
+#else
+#ifndef WIN32
+  fp = fopen("/dev/urandom", "r");
+  if (!fp)
+    fp = fopen("/dev/random", "r");
+  if (!fp) {
+#else
+  {
+#endif
+#endif
+    fprintf(stderr,"RandomStream: warning: no OS supplied random source - using rand()\n");
+    seed += (unsigned int) time(0) + getpid() + getpid() * 987654 + rand();
+    srand(seed);
+  }
+}
+
+RandomStream::~RandomStream() {
+  delete [] start;
+
+#ifdef RFB_HAVE_WINCRYPT
+  if (provider)
+    CryptReleaseContext(provider, 0);
+#endif
+#ifndef WIN32
+  if (fp) fclose(fp);
+#endif
+}
+
+int RandomStream::pos() {
+  return offset + ptr - start;
+}
+
+int RandomStream::overrun(int itemSize, int nItems, bool wait) {
+  if (itemSize > DEFAULT_BUF_LEN)
+    throw Exception("RandomStream overrun: max itemSize exceeded");
+
+  if (end - ptr != 0)
+    memmove(start, ptr, end - ptr);
+
+  end -= ptr - start;
+  offset += ptr - start;
+  ptr = start;
+
+  int length = start + DEFAULT_BUF_LEN - end;
+
+#ifdef RFB_HAVE_WINCRYPT
+  if (provider) {
+    if (!CryptGenRandom(provider, length, (U8*)end))
+      throw rdr::SystemException("unable to CryptGenRandom", GetLastError());
+    end += length;
+  } else {
+#else
+#ifndef WIN32
+  if (fp) {
+    int n = fread((U8*)end, length, 1, fp);
+    if (n != 1)
+      throw rdr::SystemException("reading /dev/urandom or /dev/random failed",
+                                 errno);
+    end += length;
+  } else {
+#else
+  {
+#endif
+#endif
+    for (int i=0; i<length; i++)
+      *(U8*)end++ = (int) (256.0*rand()/(RAND_MAX+1.0));
+  }
+
+  if (itemSize * nItems > end - ptr)
+    nItems = (end - ptr) / itemSize;
+
+  return nItems;
+}
diff --git a/common/rdr/RandomStream.h b/common/rdr/RandomStream.h
new file mode 100644
index 0000000..c33360d
--- /dev/null
+++ b/common/rdr/RandomStream.h
@@ -0,0 +1,63 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+#ifndef __RDR_RANDOMSTREAM_H__
+#define __RDR_RANDOMSTREAM_H__
+
+#include <stdio.h>
+#include <rdr/InStream.h>
+
+#ifdef WIN32
+#include <windows.h>
+#include <wincrypt.h>
+#ifdef WINCRYPT32API
+#define RFB_HAVE_WINCRYPT
+#endif
+#endif
+
+namespace rdr {
+
+  class RandomStream : public InStream {
+
+  public:
+
+    RandomStream();
+    virtual ~RandomStream();
+
+    int pos();
+
+  protected:
+    int overrun(int itemSize, int nItems, bool wait);
+
+  private:
+    U8* start;
+    int offset;
+
+    static unsigned int seed;
+#ifdef RFB_HAVE_WINCRYPT
+    HCRYPTPROV provider;
+#endif
+#ifndef WIN32
+    FILE* fp;
+#endif
+
+  };
+
+} // end of namespace rdr
+
+#endif
diff --git a/common/rdr/SubstitutingInStream.h b/common/rdr/SubstitutingInStream.h
new file mode 100644
index 0000000..325b01c
--- /dev/null
+++ b/common/rdr/SubstitutingInStream.h
@@ -0,0 +1,102 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+#ifndef __RDR_SUBSTITUTINGINSTREAM_H__
+#define __RDR_SUBSTITUTINGINSTREAM_H__
+
+#include <rdr/InStream.h>
+#include <rdr/Exception.h>
+
+namespace rdr {
+
+  class Substitutor {
+  public:
+    virtual char* substitute(const char* varName) = 0;
+  };
+
+  class SubstitutingInStream : public InStream {
+  public:
+    SubstitutingInStream(InStream* underlying_, Substitutor* s,
+                         int maxVarNameLen_)
+      : underlying(underlying_), dollar(0), substitutor(s), subst(0),
+        maxVarNameLen(maxVarNameLen_)
+    {
+      ptr = end = underlying->getptr();
+      varName = new char[maxVarNameLen+1];
+    }
+    ~SubstitutingInStream() {
+      delete underlying;
+      delete [] varName;
+      delete [] subst;
+    }
+
+    int pos() { return underlying->pos(); }
+
+    virtual int overrun(int itemSize, int nItems, bool wait=true) {
+      if (itemSize != 1)
+        throw new rdr::Exception("SubstitutingInStream: itemSize must be 1");
+
+      if (subst) {
+        delete [] subst;
+        subst = 0;
+      } else {
+        underlying->setptr(ptr);
+      }
+
+      underlying->check(1);
+      ptr = underlying->getptr();
+      end = underlying->getend();
+      dollar = (const U8*)memchr(ptr, '$', end-ptr);
+      if (dollar) {
+        if (dollar == ptr) {
+          try {
+            int i = 0;
+            while (i < maxVarNameLen) {
+              varName[i++] = underlying->readS8();
+              varName[i] = 0;
+              subst = substitutor->substitute(varName);
+              if (subst) {
+                ptr = (U8*)subst;
+                end = (U8*)subst + strlen(subst);
+                break;
+              }
+            }
+          } catch (EndOfStream&) {
+          }
+
+          if (!subst)
+            dollar = (const U8*)memchr(ptr+1, '$', end-ptr-1);
+        }
+        if (!subst && dollar) end = dollar;
+      }
+
+      if (itemSize * nItems > end - ptr)
+        nItems = (end - ptr) / itemSize;
+
+      return nItems;
+    }
+
+    InStream* underlying;
+    const U8* dollar;
+    Substitutor* substitutor;
+    char* varName;
+    char* subst;
+    int maxVarNameLen;
+  };
+}
+#endif
diff --git a/common/rdr/ZlibInStream.cxx b/common/rdr/ZlibInStream.cxx
new file mode 100644
index 0000000..6f3a7d0
--- /dev/null
+++ b/common/rdr/ZlibInStream.cxx
@@ -0,0 +1,125 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+#include <rdr/ZlibInStream.h>
+#include <rdr/Exception.h>
+#include <zlib.h>
+
+using namespace rdr;
+
+enum { DEFAULT_BUF_SIZE = 16384 };
+
+ZlibInStream::ZlibInStream(int bufSize_)
+  : underlying(0), bufSize(bufSize_ ? bufSize_ : DEFAULT_BUF_SIZE), offset(0),
+    bytesIn(0)
+{
+  zs = new z_stream;
+  zs->zalloc    = Z_NULL;
+  zs->zfree     = Z_NULL;
+  zs->opaque    = Z_NULL;
+  zs->next_in   = Z_NULL;
+  zs->avail_in  = 0;
+  if (inflateInit(zs) != Z_OK) {
+    delete zs;
+    throw Exception("ZlibInStream: inflateInit failed");
+  }
+  ptr = end = start = new U8[bufSize];
+}
+
+ZlibInStream::~ZlibInStream()
+{
+  delete [] start;
+  inflateEnd(zs);
+  delete zs;
+}
+
+void ZlibInStream::setUnderlying(InStream* is, int bytesIn_)
+{
+  underlying = is;
+  bytesIn = bytesIn_;
+  ptr = end = start;
+}
+
+int ZlibInStream::pos()
+{
+  return offset + ptr - start;
+}
+
+void ZlibInStream::reset()
+{
+  ptr = end = start;
+  if (!underlying) return;
+
+  while (bytesIn > 0) {
+    decompress(true);
+    end = start; // throw away any data
+  }
+  underlying = 0;
+}
+
+int ZlibInStream::overrun(int itemSize, int nItems, bool wait)
+{
+  if (itemSize > bufSize)
+    throw Exception("ZlibInStream overrun: max itemSize exceeded");
+  if (!underlying)
+    throw Exception("ZlibInStream overrun: no underlying stream");
+
+  if (end - ptr != 0)
+    memmove(start, ptr, end - ptr);
+
+  offset += ptr - start;
+  end -= ptr - start;
+  ptr = start;
+
+  while (end - ptr < itemSize) {
+    if (!decompress(wait))
+      return 0;
+  }
+
+  if (itemSize * nItems > end - ptr)
+    nItems = (end - ptr) / itemSize;
+
+  return nItems;
+}
+
+// decompress() calls the decompressor once.  Note that this won't necessarily
+// generate any output data - it may just consume some input data.  Returns
+// false if wait is false and we would block on the underlying stream.
+
+bool ZlibInStream::decompress(bool wait)
+{
+  zs->next_out = (U8*)end;
+  zs->avail_out = start + bufSize - end;
+
+  int n = underlying->check(1, 1, wait);
+  if (n == 0) return false;
+  zs->next_in = (U8*)underlying->getptr();
+  zs->avail_in = underlying->getend() - underlying->getptr();
+  if ((int)zs->avail_in > bytesIn)
+    zs->avail_in = bytesIn;
+
+  int rc = inflate(zs, Z_SYNC_FLUSH);
+  if (rc != Z_OK) {
+    throw Exception("ZlibInStream: inflate failed");
+  }
+
+  bytesIn -= zs->next_in - underlying->getptr();
+  end = zs->next_out;
+  underlying->setptr(zs->next_in);
+  return true;
+}
diff --git a/common/rdr/ZlibInStream.h b/common/rdr/ZlibInStream.h
new file mode 100644
index 0000000..c26b6d6
--- /dev/null
+++ b/common/rdr/ZlibInStream.h
@@ -0,0 +1,59 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+//
+// ZlibInStream streams from a compressed data stream ("underlying"),
+// decompressing with zlib on the fly.
+//
+
+#ifndef __RDR_ZLIBINSTREAM_H__
+#define __RDR_ZLIBINSTREAM_H__
+
+#include <rdr/InStream.h>
+
+struct z_stream_s;
+
+namespace rdr {
+
+  class ZlibInStream : public InStream {
+
+  public:
+
+    ZlibInStream(int bufSize=0);
+    virtual ~ZlibInStream();
+
+    void setUnderlying(InStream* is, int bytesIn);
+    void reset();
+    int pos();
+
+  private:
+
+    int overrun(int itemSize, int nItems, bool wait);
+    bool decompress(bool wait);
+
+    InStream* underlying;
+    int bufSize;
+    int offset;
+    z_stream_s* zs;
+    int bytesIn;
+    U8* start;
+  };
+
+} // end of namespace rdr
+
+#endif
diff --git a/common/rdr/ZlibOutStream.cxx b/common/rdr/ZlibOutStream.cxx
new file mode 100644
index 0000000..df1dbee
--- /dev/null
+++ b/common/rdr/ZlibOutStream.cxx
@@ -0,0 +1,161 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+#include <rdr/ZlibOutStream.h>
+#include <rdr/Exception.h>
+#include <zlib.h>
+
+using namespace rdr;
+
+enum { DEFAULT_BUF_SIZE = 16384 };
+
+ZlibOutStream::ZlibOutStream(OutStream* os, int bufSize_, int compressLevel)
+  : underlying(os), compressionLevel(compressLevel), newLevel(compressLevel),
+    bufSize(bufSize_ ? bufSize_ : DEFAULT_BUF_SIZE), offset(0)
+{
+  zs = new z_stream;
+  zs->zalloc    = Z_NULL;
+  zs->zfree     = Z_NULL;
+  zs->opaque    = Z_NULL;
+  if (deflateInit(zs, compressLevel) != Z_OK) {
+    delete zs;
+    throw Exception("ZlibOutStream: deflateInit failed");
+  }
+  ptr = start = new U8[bufSize];
+  end = start + bufSize;
+}
+
+ZlibOutStream::~ZlibOutStream()
+{
+  try {
+    flush();
+  } catch (Exception&) {
+  }
+  delete [] start;
+  deflateEnd(zs);
+  delete zs;
+}
+
+void ZlibOutStream::setUnderlying(OutStream* os)
+{
+  underlying = os;
+}
+
+void ZlibOutStream::setCompressionLevel(int level)
+{
+  if (level < -1 || level > 9)
+    level = -1;                 // Z_DEFAULT_COMPRESSION
+
+  newLevel = level;
+}
+
+int ZlibOutStream::length()
+{
+  return offset + ptr - start;
+}
+
+void ZlibOutStream::flush()
+{
+  zs->next_in = start;
+  zs->avail_in = ptr - start;
+
+//    fprintf(stderr,"zos flush: avail_in %d\n",zs->avail_in);
+
+  while (zs->avail_in != 0) {
+
+    do {
+      underlying->check(1);
+      zs->next_out = underlying->getptr();
+      zs->avail_out = underlying->getend() - underlying->getptr();
+
+//        fprintf(stderr,"zos flush: calling deflate, avail_in %d, avail_out %d\n",
+//                zs->avail_in,zs->avail_out);
+      checkCompressionLevel();
+      int rc = deflate(zs, Z_SYNC_FLUSH);
+      if (rc != Z_OK) throw Exception("ZlibOutStream: deflate failed");
+
+//        fprintf(stderr,"zos flush: after deflate: %d bytes\n",
+//                zs->next_out-underlying->getptr());
+
+      underlying->setptr(zs->next_out);
+    } while (zs->avail_out == 0);
+  }
+
+  offset += ptr - start;
+  ptr = start;
+}
+
+int ZlibOutStream::overrun(int itemSize, int nItems)
+{
+//    fprintf(stderr,"ZlibOutStream overrun\n");
+
+  if (itemSize > bufSize)
+    throw Exception("ZlibOutStream overrun: max itemSize exceeded");
+
+  while (end - ptr < itemSize) {
+    zs->next_in = start;
+    zs->avail_in = ptr - start;
+
+    do {
+      underlying->check(1);
+      zs->next_out = underlying->getptr();
+      zs->avail_out = underlying->getend() - underlying->getptr();
+
+//        fprintf(stderr,"zos overrun: calling deflate, avail_in %d, avail_out %d\n",
+//                zs->avail_in,zs->avail_out);
+
+      checkCompressionLevel();
+      int rc = deflate(zs, 0);
+      if (rc != Z_OK) throw Exception("ZlibOutStream: deflate failed");
+
+//        fprintf(stderr,"zos overrun: after deflate: %d bytes\n",
+//                zs->next_out-underlying->getptr());
+
+      underlying->setptr(zs->next_out);
+    } while (zs->avail_out == 0);
+
+    // output buffer not full
+
+    if (zs->avail_in == 0) {
+      offset += ptr - start;
+      ptr = start;
+    } else {
+      // but didn't consume all the data?  try shifting what's left to the
+      // start of the buffer.
+      fprintf(stderr,"z out buf not full, but in data not consumed\n");
+      memmove(start, zs->next_in, ptr - zs->next_in);
+      offset += zs->next_in - start;
+      ptr -= zs->next_in - start;
+    }
+  }
+
+  if (itemSize * nItems > end - ptr)
+    nItems = (end - ptr) / itemSize;
+
+  return nItems;
+}
+
+void ZlibOutStream::checkCompressionLevel()
+{
+  if (newLevel != compressionLevel) {
+    if (deflateParams (zs, newLevel, Z_DEFAULT_STRATEGY) != Z_OK) {
+      throw Exception("ZlibOutStream: deflateParams failed");
+    }
+    compressionLevel = newLevel;
+  }
+}
diff --git a/common/rdr/ZlibOutStream.h b/common/rdr/ZlibOutStream.h
new file mode 100644
index 0000000..8027d27
--- /dev/null
+++ b/common/rdr/ZlibOutStream.h
@@ -0,0 +1,61 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+//
+// ZlibOutStream streams to a compressed data stream (underlying), compressing
+// with zlib on the fly.
+//
+
+#ifndef __RDR_ZLIBOUTSTREAM_H__
+#define __RDR_ZLIBOUTSTREAM_H__
+
+#include <rdr/OutStream.h>
+
+struct z_stream_s;
+
+namespace rdr {
+
+  class ZlibOutStream : public OutStream {
+
+  public:
+
+    ZlibOutStream(OutStream* os=0, int bufSize=0, int compressionLevel=-1);
+    virtual ~ZlibOutStream();
+
+    void setUnderlying(OutStream* os);
+    void setCompressionLevel(int level=-1);
+    void flush();
+    int length();
+
+  private:
+
+    int overrun(int itemSize, int nItems);
+    void checkCompressionLevel();
+
+    OutStream* underlying;
+    int compressionLevel;
+    int newLevel;
+    int bufSize;
+    int offset;
+    z_stream_s* zs;
+    U8* start;
+  };
+
+} // end of namespace rdr
+
+#endif
diff --git a/common/rdr/msvcwarning.h b/common/rdr/msvcwarning.h
new file mode 100644
index 0000000..bea8d3f
--- /dev/null
+++ b/common/rdr/msvcwarning.h
@@ -0,0 +1,26 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+// Trim out extraneous cruft from windows.h includes
+#define WIN32_LEAN_AND_MEAN
+
+// Force all Windows NT-specific APIs to be visible
+#define _WIN32_WINNT 0xffff
+
+#pragma warning( disable : 4800 ) // forcing bool 'true' or 'false'
+#pragma warning( disable : 4786 ) // truncating debug information to 255 chars
\ No newline at end of file
diff --git a/common/rdr/rdr.dsp b/common/rdr/rdr.dsp
new file mode 100644
index 0000000..6717adf
--- /dev/null
+++ b/common/rdr/rdr.dsp
@@ -0,0 +1,222 @@
+# Microsoft Developer Studio Project File - Name="rdr" - Package Owner=<4>

+# Microsoft Developer Studio Generated Build File, Format Version 6.00

+# ** DO NOT EDIT **

+

+# TARGTYPE "Win32 (x86) Static Library" 0x0104

+

+CFG=rdr - Win32 Debug Unicode

+!MESSAGE This is not a valid makefile. To build this project using NMAKE,

+!MESSAGE use the Export Makefile command and run

+!MESSAGE 

+!MESSAGE NMAKE /f "rdr.mak".

+!MESSAGE 

+!MESSAGE You can specify a configuration when running NMAKE

+!MESSAGE by defining the macro CFG on the command line. For example:

+!MESSAGE 

+!MESSAGE NMAKE /f "rdr.mak" CFG="rdr - Win32 Debug Unicode"

+!MESSAGE 

+!MESSAGE Possible choices for configuration are:

+!MESSAGE 

+!MESSAGE "rdr - Win32 Release" (based on "Win32 (x86) Static Library")

+!MESSAGE "rdr - Win32 Debug" (based on "Win32 (x86) Static Library")

+!MESSAGE "rdr - Win32 Debug Unicode" (based on "Win32 (x86) Static Library")

+!MESSAGE 

+

+# Begin Project

+# PROP AllowPerConfigDependencies 0

+# PROP Scc_ProjName ""

+# PROP Scc_LocalPath ""

+CPP=cl.exe

+RSC=rc.exe

+

+!IF  "$(CFG)" == "rdr - Win32 Release"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 0

+# PROP BASE Output_Dir "Release"

+# PROP BASE Intermediate_Dir "Release"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 0

+# PROP Output_Dir "..\Release"

+# PROP Intermediate_Dir "..\Release\rdr"

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c

+# ADD CPP /nologo /MT /W3 /GX /O1 /I ".." /FI"rdr/msvcwarning.h" /D "NDEBUG" /D "_LIB" /D "WIN32" /D "_MBCS" /YX /FD /c

+# ADD BASE RSC /l 0x809 /d "NDEBUG"

+# ADD RSC /l 0x809 /d "NDEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LIB32=link.exe -lib

+# ADD BASE LIB32 /nologo

+# ADD LIB32 /nologo

+

+!ELSEIF  "$(CFG)" == "rdr - Win32 Debug"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 1

+# PROP BASE Output_Dir "Debug"

+# PROP BASE Intermediate_Dir "Debug"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 1

+# PROP Output_Dir "..\Debug"

+# PROP Intermediate_Dir "..\Debug\rdr"

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c

+# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I ".." /FI"rdr/msvcwarning.h" /D "_DEBUG" /D "_LIB" /D "WIN32" /D "_MBCS" /YX /FD /GZ /c

+# ADD BASE RSC /l 0x809 /d "_DEBUG"

+# ADD RSC /l 0x809 /d "_DEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LIB32=link.exe -lib

+# ADD BASE LIB32 /nologo

+# ADD LIB32 /nologo

+

+!ELSEIF  "$(CFG)" == "rdr - Win32 Debug Unicode"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 1

+# PROP BASE Output_Dir "rdr___Win32_Debug_Unicode"

+# PROP BASE Intermediate_Dir "rdr___Win32_Debug_Unicode"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 1

+# PROP Output_Dir "..\Debug_Unicode"

+# PROP Intermediate_Dir "..\Debug_Unicode\rdr"

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I ".." /FI"msvcwarning.h" /D "_DEBUG" /D "_LIB" /D "WIN32" /D "_MBCS" /YX /FD /GZ /c

+# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I ".." /FI"rdr/msvcwarning.h" /D "_LIB" /D "_DEBUG" /D "WIN32" /D "_UNICODE" /D "UNICODE" /YX /FD /GZ /c

+# ADD BASE RSC /l 0x809 /d "_DEBUG"

+# ADD RSC /l 0x809 /d "_DEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LIB32=link.exe -lib

+# ADD BASE LIB32 /nologo

+# ADD LIB32 /nologo

+

+!ENDIF 

+

+# Begin Target

+

+# Name "rdr - Win32 Release"

+# Name "rdr - Win32 Debug"

+# Name "rdr - Win32 Debug Unicode"

+# Begin Group "Header Files"

+

+# PROP Default_Filter "h;hpp;hxx;hm;inl"

+# Begin Source File

+

+SOURCE=.\Exception.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\FdInStream.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\FdOutStream.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\FixedMemOutStream.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\HexInStream.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\HexOutStream.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\InStream.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\MemInStream.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\MemOutStream.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\msvcwarning.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\OutStream.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\RandomStream.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\SubstitutingInStream.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\types.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\ZlibInStream.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\ZlibOutStream.h

+# End Source File

+# End Group

+# Begin Group "Source Files"

+

+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"

+# Begin Source File

+

+SOURCE=.\Exception.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\FdInStream.cxx

+# ADD CPP /I "../zlib"

+# End Source File

+# Begin Source File

+

+SOURCE=.\FdOutStream.cxx

+# ADD CPP /I "../zlib"

+# End Source File

+# Begin Source File

+

+SOURCE=.\HexInStream.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\HexOutStream.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\InStream.cxx

+# ADD CPP /I "../zlib"

+# End Source File

+# Begin Source File

+

+SOURCE=.\RandomStream.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\ZlibInStream.cxx

+# ADD CPP /I "../zlib"

+# End Source File

+# Begin Source File

+

+SOURCE=.\ZlibOutStream.cxx

+# ADD CPP /I "../zlib"

+# End Source File

+# End Group

+# End Target

+# End Project

diff --git a/common/rdr/types.h b/common/rdr/types.h
new file mode 100644
index 0000000..6421b13
--- /dev/null
+++ b/common/rdr/types.h
@@ -0,0 +1,66 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+#ifndef __RDR_TYPES_H__
+#define __RDR_TYPES_H__
+
+namespace rdr {
+
+  typedef unsigned char U8;
+  typedef unsigned short U16;
+  typedef unsigned int U32;
+  typedef signed char S8;
+  typedef signed short S16;
+  typedef signed int S32;
+
+  class U8Array {
+  public:
+    U8Array() : buf(0) {}
+    U8Array(U8* a) : buf(a) {} // note: assumes ownership
+    U8Array(int len) : buf(new U8[len]) {}
+    ~U8Array() { delete [] buf; }
+
+    // Get the buffer pointer & clear it (i.e. caller takes ownership)
+    U8* takeBuf() { U8* tmp = buf; buf = 0; return tmp; }
+
+    U8* buf;
+  };
+
+  class U16Array {
+  public:
+    U16Array() : buf(0) {}
+    U16Array(U16* a) : buf(a) {} // note: assumes ownership
+    U16Array(int len) : buf(new U16[len]) {}
+    ~U16Array() { delete [] buf; }
+    U16* takeBuf() { U16* tmp = buf; buf = 0; return tmp; }
+    U16* buf;
+  };
+
+  class U32Array {
+  public:
+    U32Array() : buf(0) {}
+    U32Array(U32* a) : buf(a) {} // note: assumes ownership
+    U32Array(int len) : buf(new U32[len]) {}
+    ~U32Array() { delete [] buf; }
+    U32* takeBuf() { U32* tmp = buf; buf = 0; return tmp; }
+    U32* buf;
+  };
+
+} // end of namespace rdr
+
+#endif