aboutsummaryrefslogtreecommitdiffstats
path: root/common/rdr
diff options
context:
space:
mode:
Diffstat (limited to 'common/rdr')
-rw-r--r--common/rdr/Exception.cxx73
-rw-r--r--common/rdr/Exception.h58
-rw-r--r--common/rdr/FdInStream.cxx304
-rw-r--r--common/rdr/FdInStream.h77
-rw-r--r--common/rdr/FdOutStream.cxx159
-rw-r--r--common/rdr/FdOutStream.h55
-rw-r--r--common/rdr/FixedMemOutStream.h52
-rw-r--r--common/rdr/HexInStream.cxx117
-rw-r--r--common/rdr/HexInStream.h50
-rw-r--r--common/rdr/HexOutStream.cxx110
-rw-r--r--common/rdr/HexOutStream.h51
-rw-r--r--common/rdr/InStream.cxx35
-rw-r--r--common/rdr/InStream.h170
-rw-r--r--common/rdr/Makefile.in19
-rw-r--r--common/rdr/MemInStream.h63
-rw-r--r--common/rdr/MemOutStream.h83
-rw-r--r--common/rdr/OutStream.h171
-rw-r--r--common/rdr/RandomStream.cxx130
-rw-r--r--common/rdr/RandomStream.h63
-rw-r--r--common/rdr/SubstitutingInStream.h102
-rw-r--r--common/rdr/ZlibInStream.cxx125
-rw-r--r--common/rdr/ZlibInStream.h59
-rw-r--r--common/rdr/ZlibOutStream.cxx161
-rw-r--r--common/rdr/ZlibOutStream.h61
-rw-r--r--common/rdr/msvcwarning.h26
-rw-r--r--common/rdr/rdr.dsp222
-rw-r--r--common/rdr/types.h66
27 files changed, 2662 insertions, 0 deletions
diff --git a/common/rdr/Exception.cxx b/common/rdr/Exception.cxx
new file mode 100644
index 00000000..7d387119
--- /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 00000000..1b92f777
--- /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 00000000..2b119735
--- /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 00000000..5d9598c8
--- /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 00000000..07ac04c2
--- /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 00000000..a3e29127
--- /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 00000000..e4ec52cb
--- /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 00000000..80f8a796
--- /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 00000000..6bfb8433
--- /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 00000000..9b0b6c4d
--- /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 00000000..10247e68
--- /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 00000000..a413b6c1
--- /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 00000000..6d22ac6a
--- /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 00000000..09fa5544
--- /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 00000000..77ca3f3a
--- /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 00000000..ee3e9500
--- /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 00000000..aed2eea1
--- /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 00000000..7056c2cc
--- /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 00000000..c33360d7
--- /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 00000000..325b01c5
--- /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 00000000..6f3a7d02
--- /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 00000000..c26b6d63
--- /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 00000000..df1dbeec
--- /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 00000000..8027d27a
--- /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 00000000..bea8d3f4
--- /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 00000000..6717adfd
--- /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 00000000..6421b137
--- /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