diff options
author | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
---|---|---|
committer | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
commit | bcb704366cb5e333a626c18c308c7e0448a8e69f (patch) | |
tree | f0d6ab7d78ecdd9207cf46536376b44b91a1ca71 /krdc/vnc/rfbproto.c | |
download | tdenetwork-bcb704366cb5e333a626c18c308c7e0448a8e69f.tar.gz tdenetwork-bcb704366cb5e333a626c18c308c7e0448a8e69f.zip |
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdenetwork@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'krdc/vnc/rfbproto.c')
-rw-r--r-- | krdc/vnc/rfbproto.c | 1335 |
1 files changed, 1335 insertions, 0 deletions
diff --git a/krdc/vnc/rfbproto.c b/krdc/vnc/rfbproto.c new file mode 100644 index 00000000..e9ed5764 --- /dev/null +++ b/krdc/vnc/rfbproto.c @@ -0,0 +1,1335 @@ +/* + * Copyright (C) 2002, Tim Jansen. All Rights Reserved. + * Copyright (C) 2000-2002 Constantin Kaplinsky. All Rights Reserved. + * Copyright (C) 2000 Tridia Corporation. All Rights Reserved. + * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +/* + * rfbproto.c - functions to deal with client side of RFB protocol. + * tim@tjansen.de: - added softcursor encoding + * - changed various things for krdc + */ + +#include <unistd.h> +#include <errno.h> +#include <pwd.h> +#include "vncviewer.h" +#include "vncauth.h" +#include <zlib.h> +#include <jpeglib.h> + +static Bool HandleHextile8(int rx, int ry, int rw, int rh); +static Bool HandleHextile16(int rx, int ry, int rw, int rh); +static Bool HandleHextile32(int rx, int ry, int rw, int rh); +static Bool HandleZlib8(int rx, int ry, int rw, int rh); +static Bool HandleZlib16(int rx, int ry, int rw, int rh); +static Bool HandleZlib32(int rx, int ry, int rw, int rh); +static Bool HandleTight8(int rx, int ry, int rw, int rh); +static Bool HandleTight16(int rx, int ry, int rw, int rh); +static Bool HandleTight32(int rx, int ry, int rw, int rh); + +static long ReadCompactLen (void); + +static void JpegInitSource(j_decompress_ptr cinfo); +static boolean JpegFillInputBuffer(j_decompress_ptr cinfo); +static void JpegSkipInputData(j_decompress_ptr cinfo, long num_bytes); +static void JpegTermSource(j_decompress_ptr cinfo); +static void JpegSetSrcManager(j_decompress_ptr cinfo, CARD8 *compressedData, + int compressedLen); + + +#define RGB24_TO_PIXEL(bpp,r,g,b) \ + ((((CARD##bpp)(r) & 0xFF) * myFormat.redMax + 127) / 255 \ + << myFormat.redShift | \ + (((CARD##bpp)(g) & 0xFF) * myFormat.greenMax + 127) / 255 \ + << myFormat.greenShift | \ + (((CARD##bpp)(b) & 0xFF) * myFormat.blueMax + 127) / 255 \ + << myFormat.blueShift) + +int rfbsock; +char *desktopName; +rfbPixelFormat myFormat; +rfbServerInitMsg si; + +int endianTest = 1; + +/* + * Softcursor variables + */ + +int cursorX, cursorY; +int imageIndex = -1; + +PointerImage pointerImages[rfbSoftCursorMaxImages]; + + +/* Hextile assumes it is big enough to hold 16 * 16 * 32 bits. + Tight encoding assumes BUFFER_SIZE is at least 16384 bytes. */ + +#define BUFFER_SIZE (16384) +static char buffer[BUFFER_SIZE]; + + +/* The zlib encoding requires expansion/decompression/deflation of the + compressed data in the "buffer" above into another, result buffer. + However, the size of the result buffer can be determined precisely + based on the bitsPerPixel, height and width of the rectangle. We + allocate this buffer one time to be the full size of the buffer. */ + +static int raw_buffer_size = -1; +static char *raw_buffer = NULL; + +static z_stream decompStream; +static Bool decompStreamInited = False; + + +/* + * Variables for the ``tight'' encoding implementation. + */ + +/* Separate buffer for compressed data. */ +#define ZLIB_BUFFER_SIZE 512 +static char zlib_buffer[ZLIB_BUFFER_SIZE]; + +/* Four independent compression streams for zlib library. */ +static z_stream zlibStream[4]; +static Bool zlibStreamActive[4] = { + False, False, False, False +}; + +/* Filter stuff. Should be initialized by filter initialization code. */ +static Bool cutZeros; +static int rectWidth, rectColors; +static char tightPalette[256*4]; +static CARD8 tightPrevRow[2048*3*sizeof(CARD16)]; + +/* JPEG decoder state. */ +static Bool jpegError; + +/* Maximum length for the cut buffer (16 MB)*/ +#define MAX_CUTBUFFER (1024*1024*16) + +/* Maximum length for the strings (64 kB)*/ +#define MAX_STRING (1024*64) + +/* Maximum length for the strings (32 MB)*/ +#define MAX_JPEG_SIZE (1024*1024*32) + + +/* + * ConnectToRFBServer. + */ + +int +ConnectToRFBServer(const char *hostname, int port) +{ + unsigned int host; + + if (!StringToIPAddr(hostname, &host)) { + fprintf(stderr,"Couldn't convert '%s' to host address\n", hostname); + return -(int)INIT_NAME_RESOLUTION_FAILURE; + } + + rfbsock = ConnectToTcpAddr(host, port); + if (rfbsock < 0) { + fprintf(stderr,"Unable to connect to VNC server\n"); + } + + return rfbsock; +} + + +/* + * InitialiseRFBConnection. + */ + +enum InitStatus +InitialiseRFBConnection() +{ + rfbProtocolVersionMsg pv; + int major,minor; + CARD32 authScheme, reasonLen, authResult; + char *reason; + CARD8 challenge[CHALLENGESIZE]; + char passwd[9]; + int i; + rfbClientInitMsg ci; + + /* if the connection is immediately closed, don't report anything, so + that pmw's monitor can make test connections */ + + if (!ReadFromRFBServer(pv, sz_rfbProtocolVersionMsg)) return INIT_SERVER_BLOCKED; + + errorMessageOnReadFailure = True; + + pv[sz_rfbProtocolVersionMsg] = 0; + + if (sscanf(pv,rfbProtocolVersionFormat,&major,&minor) != 2) { + fprintf(stderr,"Not a valid VNC server\n"); + return INIT_PROTOCOL_FAILURE; + } + + fprintf(stderr,"VNC server supports protocol version %d.%d (viewer %d.%d)\n", + major, minor, rfbProtocolMajorVersion, rfbProtocolMinorVersion); + + major = rfbProtocolMajorVersion; + minor = rfbProtocolMinorVersion; + + sprintf(pv,rfbProtocolVersionFormat,major,minor); + + if (!WriteExact(rfbsock, pv, sz_rfbProtocolVersionMsg)) return INIT_CONNECTION_FAILED; + + if (!ReadFromRFBServer((char *)&authScheme, 4)) return INIT_CONNECTION_FAILED; + + authScheme = Swap32IfLE(authScheme); + + switch (authScheme) { + + case rfbConnFailed: + if (!ReadFromRFBServer((char *)&reasonLen, 4)) return INIT_CONNECTION_FAILED; + reasonLen = Swap32IfLE(reasonLen); + + if (reasonLen > MAX_STRING) { + fprintf(stderr, "Connection failure reason too long.\n"); + return INIT_CONNECTION_FAILED; + } + + reason = malloc(reasonLen); + if (!reason) + return INIT_CONNECTION_FAILED; + + if (!ReadFromRFBServer(reason, reasonLen)) return INIT_CONNECTION_FAILED; + + fprintf(stderr,"VNC connection failed: %.*s\n",(int)reasonLen, reason); + free(reason); + return INIT_CONNECTION_FAILED; + + case rfbNoAuth: + fprintf(stderr,"No authentication needed\n"); + break; + + case rfbVncAuth: + if (!ReadFromRFBServer((char *)challenge, CHALLENGESIZE)) return INIT_CONNECTION_FAILED; + + if (!getPassword(passwd, 8)) + return INIT_ABORTED; + + passwd[8] = '\0'; + + vncEncryptBytes(challenge, passwd); + + /* Lose the password from memory */ + for (i = strlen(passwd); i >= 0; i--) { + passwd[i] = '\0'; + } + + if (!WriteExact(rfbsock, (char *)challenge, CHALLENGESIZE)) return INIT_CONNECTION_FAILED; + + if (!ReadFromRFBServer((char *)&authResult, 4)) return INIT_CONNECTION_FAILED; + + authResult = Swap32IfLE(authResult); + + switch (authResult) { + case rfbVncAuthOK: + fprintf(stderr,"VNC authentication succeeded\n"); + break; + case rfbVncAuthFailed: + fprintf(stderr,"VNC authentication failed\n"); + return INIT_AUTHENTICATION_FAILED; + case rfbVncAuthTooMany: + fprintf(stderr,"VNC authentication failed - too many tries\n"); + return INIT_AUTHENTICATION_FAILED; + default: + fprintf(stderr,"Unknown VNC authentication result: %d\n", + (int)authResult); + return INIT_CONNECTION_FAILED; + } + break; + + default: + fprintf(stderr,"Unknown authentication scheme from VNC server: %d\n", + (int)authScheme); + return INIT_CONNECTION_FAILED; + } + + ci.shared = (appData.shareDesktop ? 1 : 0); + + if (!WriteExact(rfbsock, (char *)&ci, sz_rfbClientInitMsg)) return INIT_CONNECTION_FAILED; + + if (!ReadFromRFBServer((char *)&si, sz_rfbServerInitMsg)) return INIT_CONNECTION_FAILED; + + si.framebufferWidth = Swap16IfLE(si.framebufferWidth); + si.framebufferHeight = Swap16IfLE(si.framebufferHeight); + si.format.redMax = Swap16IfLE(si.format.redMax); + si.format.greenMax = Swap16IfLE(si.format.greenMax); + si.format.blueMax = Swap16IfLE(si.format.blueMax); + si.nameLength = Swap32IfLE(si.nameLength); + + if ((si.framebufferWidth*si.framebufferHeight) > (4096*4096)) + return INIT_CONNECTION_FAILED; + + if (si.nameLength > MAX_STRING) { + fprintf(stderr, "Display name too long.\n"); + return INIT_CONNECTION_FAILED; + } + + desktopName = malloc(si.nameLength + 1); + if (!desktopName) { + fprintf(stderr, "Error allocating memory for desktop name, %lu bytes\n", + (unsigned long)si.nameLength); + return INIT_CONNECTION_FAILED; + } + + if (!ReadFromRFBServer(desktopName, si.nameLength)) return INIT_CONNECTION_FAILED; + + desktopName[si.nameLength] = 0; + + fprintf(stderr,"Desktop name \"%s\"\n",desktopName); + + fprintf(stderr,"Connected to VNC server, using protocol version %d.%d\n", + rfbProtocolMajorVersion, rfbProtocolMinorVersion); + + fprintf(stderr,"VNC server default format:\n"); + PrintPixelFormat(&si.format); + + return INIT_OK; +} + + +/* + * SetFormatAndEncodings. + */ + +Bool +SetFormatAndEncodings() +{ + rfbSetPixelFormatMsg spf; + char buf[sz_rfbSetEncodingsMsg + MAX_ENCODINGS * 4]; + rfbSetEncodingsMsg *se = (rfbSetEncodingsMsg *)buf; + CARD32 *encs = (CARD32 *)(&buf[sz_rfbSetEncodingsMsg]); + int len = 0; + Bool requestCompressLevel = False; + Bool requestQualityLevel = False; + Bool requestLastRectEncoding = False; + + spf.type = rfbSetPixelFormat; + spf.pad1 = 0; + spf.pad2 = 0; + spf.format = myFormat; + spf.format.redMax = Swap16IfLE(spf.format.redMax); + spf.format.greenMax = Swap16IfLE(spf.format.greenMax); + spf.format.blueMax = Swap16IfLE(spf.format.blueMax); + + if (!WriteExact(rfbsock, (char *)&spf, sz_rfbSetPixelFormatMsg)) + return False; + + se->type = rfbSetEncodings; + se->pad = 0; + se->nEncodings = 0; + + if (appData.encodingsString) { + const char *encStr = appData.encodingsString; + int encStrLen; + do { + char *nextEncStr = strchr(encStr, ' '); + if (nextEncStr) { + encStrLen = nextEncStr - encStr; + nextEncStr++; + } else { + encStrLen = strlen(encStr); + } + + if (strncasecmp(encStr,"raw",encStrLen) == 0) { + encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRaw); + } else if (strncasecmp(encStr,"copyrect",encStrLen) == 0) { + encs[se->nEncodings++] = Swap32IfLE(rfbEncodingCopyRect); + } else if (strncasecmp(encStr,"softcursor",encStrLen) == 0) { + encs[se->nEncodings++] = Swap32IfLE(rfbEncodingSoftCursor); + /* if server supports SoftCursor, it will ignore X/RichCursor + * and PointerPos */ + encs[se->nEncodings++] = Swap32IfLE(rfbEncodingXCursor); + encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRichCursor); + encs[se->nEncodings++] = Swap32IfLE(rfbEncodingPointerPos); + } else if (strncasecmp(encStr,"background",encStrLen) == 0) { + encs[se->nEncodings++] = Swap32IfLE(rfbEncodingBackground); + } else if (strncasecmp(encStr,"tight",encStrLen) == 0) { + encs[se->nEncodings++] = Swap32IfLE(rfbEncodingTight); + requestLastRectEncoding = True; + if (appData.compressLevel >= 0 && appData.compressLevel <= 9) + requestCompressLevel = True; + if (appData.qualityLevel >= 0 && appData.qualityLevel <= 9) + requestQualityLevel = True; + } else if (strncasecmp(encStr,"hextile",encStrLen) == 0) { + encs[se->nEncodings++] = Swap32IfLE(rfbEncodingHextile); + } else if (strncasecmp(encStr,"zlib",encStrLen) == 0) { + encs[se->nEncodings++] = Swap32IfLE(rfbEncodingZlib); + if (appData.compressLevel >= 0 && appData.compressLevel <= 9) + requestCompressLevel = True; + } else { + fprintf(stderr,"Unknown encoding '%.*s'\n",encStrLen,encStr); + } + + encStr = nextEncStr; + } while (encStr && se->nEncodings < MAX_ENCODINGS); + + if (se->nEncodings < MAX_ENCODINGS && requestCompressLevel) { + encs[se->nEncodings++] = Swap32IfLE(appData.compressLevel + + rfbEncodingCompressLevel0); + } + + if (se->nEncodings < MAX_ENCODINGS && requestQualityLevel) { + encs[se->nEncodings++] = Swap32IfLE(appData.qualityLevel + + rfbEncodingQualityLevel0); + } + + if (se->nEncodings < MAX_ENCODINGS && requestLastRectEncoding) { + encs[se->nEncodings++] = Swap32IfLE(rfbEncodingLastRect); + } + } + else { + encs[se->nEncodings++] = Swap32IfLE(rfbEncodingCopyRect); + encs[se->nEncodings++] = Swap32IfLE(rfbEncodingTight); + encs[se->nEncodings++] = Swap32IfLE(rfbEncodingHextile); + encs[se->nEncodings++] = Swap32IfLE(rfbEncodingZlib); + encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRaw); + + if (appData.compressLevel >= 0 && appData.compressLevel <= 9) { + encs[se->nEncodings++] = Swap32IfLE(appData.compressLevel + + rfbEncodingCompressLevel0); + } + + if (appData.qualityLevel >= 0 && appData.qualityLevel <= 9) { + encs[se->nEncodings++] = Swap32IfLE(appData.qualityLevel + + rfbEncodingQualityLevel0); + } + + if (si.format.depth >= 8) + encs[se->nEncodings++] = Swap32IfLE(rfbEncodingSoftCursor); + encs[se->nEncodings++] = Swap32IfLE(rfbEncodingLastRect); + } + + len = sz_rfbSetEncodingsMsg + se->nEncodings * 4; + + se->nEncodings = Swap16IfLE(se->nEncodings); + + if (!WriteExact(rfbsock, buf, len)) return False; + + return True; +} + + +/* + * SendIncrementalFramebufferUpdateRequest. + * Note: this should only be called by the WriterThread + */ + +Bool +SendIncrementalFramebufferUpdateRequest() +{ + return SendFramebufferUpdateRequest(0, 0, si.framebufferWidth, + si.framebufferHeight, True); +} + + +/* + * SendFramebufferUpdateRequest. + * Note: this should only be called by the WriterThread + */ + +Bool +SendFramebufferUpdateRequest(int x, int y, int w, int h, Bool incremental) +{ + rfbFramebufferUpdateRequestMsg fur; + + fur.type = rfbFramebufferUpdateRequest; + fur.incremental = incremental ? 1 : 0; + fur.x = Swap16IfLE(x); + fur.y = Swap16IfLE(y); + fur.w = Swap16IfLE(w); + fur.h = Swap16IfLE(h); + + if (!WriteExact(rfbsock, (char *)&fur, sz_rfbFramebufferUpdateRequestMsg)) + return False; + + return True; +} + + +/* + * SendPointerEvent. + * Note: this should only be called by the WriterThread + */ + +Bool +SendPointerEvent(int x, int y, int buttonMask) +{ + rfbPointerEventMsg pe; + + pe.type = rfbPointerEvent; + pe.buttonMask = buttonMask; + if (x < 0) x = 0; + if (y < 0) y = 0; + pe.x = Swap16IfLE(x); + pe.y = Swap16IfLE(y); + return WriteExact(rfbsock, (char *)&pe, sz_rfbPointerEventMsg); +} + + +/* + * SendKeyEvent. + * Note: this should only be called by the WriterThread + */ + +Bool +SendKeyEvent(CARD32 key, Bool down) +{ + rfbKeyEventMsg ke; + + ke.type = rfbKeyEvent; + ke.down = down ? 1 : 0; + ke.key = Swap32IfLE(key); + return WriteExact(rfbsock, (char *)&ke, sz_rfbKeyEventMsg); +} + + +/* + * SendClientCutText. + * Note: this should only be called by the WriterThread + */ + +Bool +SendClientCutText(const char *str, int len) +{ + rfbClientCutTextMsg cct; + + cct.type = rfbClientCutText; + cct.length = Swap32IfLE((unsigned int)len); + return (WriteExact(rfbsock, (char *)&cct, sz_rfbClientCutTextMsg) && + WriteExact(rfbsock, str, len)); +} + + +static Bool +HandleSoftCursorSetImage(rfbSoftCursorSetImage *msg, rfbRectangle *rect) +{ + int iindex = msg->imageIndex - rfbSoftCursorSetIconOffset; + PointerImage *pi = &pointerImages[iindex]; + if (iindex >= rfbSoftCursorMaxImages) { + fprintf(stderr, "Received invalid soft cursor image index %d for SetImage\n", iindex); + return False; + } + EnableClientCursor(0); + + if (pi->set && pi->image) + free(pi->image); + + pi->w = rect->w; + pi->h = rect->h; + pi->hotX = rect->x; + pi->hotY = rect->y; + pi->len = Swap16IfLE(msg->imageLength); + pi->image = malloc(pi->len); + if (!pi->image) { + fprintf(stderr, "out of memory (size=%d)\n", pi->len); + return False; + } + + if (!ReadFromRFBServer(pi->image, pi->len)) + return False; + pi->set = 1; + return True; +} + +/* framebuffer must be locked when calling this!!! */ +static Bool +PointerMove(unsigned int x, unsigned int y, unsigned int mask, + int ox, int oy, int ow, int oh) +{ + int nx, ny, nw, nh; + + if (x >= si.framebufferWidth) + x = si.framebufferWidth - 1; + if (y >= si.framebufferHeight) + y = si.framebufferHeight - 1; + + cursorX = x; + cursorY = y; + drawCursor(); + UnlockFramebuffer(); + + getBoundingRectCursor(cursorX, cursorY, imageIndex, + &nx, &ny, &nw, &nh); + + if (rectsIntersect(ox, oy, ow, oh, nx, ny, nw, nh)) { + rectsJoin(&ox, &oy, &ow, &oh, nx, ny, nw, nh); + SyncScreenRegion(ox, oy, ow, oh); + } + else { + SyncScreenRegion(ox, oy, ow, oh); + SyncScreenRegion(nx, ny, nw, nh); + } + + postMouseEvent(cursorX, cursorY, mask); + + return True; +} + +static Bool +HandleSoftCursorMove(rfbSoftCursorMove *msg, rfbRectangle *rect) +{ + int ii, ox, oy, ow, oh; + + /* get old cursor rect to know what to update */ + getBoundingRectCursor(cursorX, cursorY, imageIndex, + &ox, &oy, &ow, &oh); + + ii = msg->imageIndex; + if (ii >= rfbSoftCursorMaxImages) { + fprintf(stderr, "Received invalid soft cursor image index %d for Move\n", ii); + return False; + } + + if (!pointerImages[ii].set) + return True; + + LockFramebuffer(); + undrawCursor(); + imageIndex = ii; + + return PointerMove(rect->w, rect->h, msg->buttonMask, ox, oy, ow, oh); +} + +static Bool +HandleCursorPos(unsigned int x, unsigned int y) +{ + int ox, oy, ow, oh; + + /* get old cursor rect to know what to update */ + getBoundingRectCursor(cursorX, cursorY, imageIndex, + &ox, &oy, &ow, &oh); + if (!pointerImages[0].set) + return True; + + LockFramebuffer(); + undrawCursor(); + imageIndex = 0; + return PointerMove(x, y, 0, ox, oy, ow, oh); +} + +/* call only from X11 thread. Only updates framebuffer, does not sync! */ +void DrawCursorX11Thread(int x, int y) { + int ox, oy, ow, oh, nx, ny, nw, nh; + if (!pointerImages[0].set) + return True; + imageIndex = 0; + + if (x >= si.framebufferWidth) + x = si.framebufferWidth - 1; + if (y >= si.framebufferHeight) + y = si.framebufferHeight - 1; + + LockFramebuffer(); + getBoundingRectCursor(cursorX, cursorY, imageIndex, + &ox, &oy, &ow, &oh); + undrawCursor(); + cursorX = x; + cursorY = y; + drawCursor(); + UnlockFramebuffer(); + + getBoundingRectCursor(cursorX, cursorY, imageIndex, + &nx, &ny, &nw, &nh); + if (rectsIntersect(ox, oy, ow, oh, nx, ny, nw, nh)) { + rectsJoin(&ox, &oy, &ow, &oh, nx, ny, nw, nh); + SyncScreenRegionX11Thread(ox, oy, ow, oh); + } + else { + SyncScreenRegionX11Thread(ox, oy, ow, oh); + SyncScreenRegionX11Thread(nx, ny, nw, nh); + } +} + +/** + * Create a softcursor in the "compressed alpha" format. + * Returns the softcursor, caller owns the object + */ +static void *MakeSoftCursor(int bpp, int cursorWidth, int cursorHeight, + CARD8 *cursorData, CARD8 *cursorMask, short *imageLen) +{ + int w = (cursorWidth+7)/8; + unsigned char *cp, *sp, *dstData; + int state; /* 0 = transparent, 1 otherwise */ + CARD8 *counter; + unsigned char bit; + int i,j; + + sp = (unsigned char*)cursorData; + dstData = cp = (unsigned char*)calloc(cursorWidth*(bpp+2),cursorHeight); + if (!dstData) + return 0; + + state = 0; + counter = cp++; + *counter = 0; + + for(j=0;j<cursorHeight;j++) + for(i=0,bit=0x80;i<cursorWidth;i++,bit=(bit&1)?0x80:bit>>1) + if(cursorMask[j*w+i/8]&bit) { + if (state) { + memcpy(cp,sp,bpp); + cp += bpp; + sp += bpp; + (*counter)++; + if (*counter == 255) { + state = 0; + counter = cp++; + *counter = 0; + } + } + else { + state = 1; + counter = cp++; + *counter = 1; + memcpy(cp,sp,bpp); + cp += bpp; + sp += bpp; + } + } + else { + if (!state) { + (*counter)++; + if (*counter == 255) { + state = 1; + counter = cp++; + *counter = 0; + } + } + else { + state = 0; + counter = cp++; + *counter = 1; + } + sp += bpp; + } + + *imageLen = cp - dstData; + return (void*) dstData; +} + + +/********************************************************************* + * HandleCursorShape(). Support for XCursor and RichCursor shape + * updates. We emulate cursor operating on the frame buffer (that is + * why we call it "software cursor"). + ********************************************************************/ + +static Bool HandleCursorShape(int xhot, int yhot, int width, int height, CARD32 enc) +{ + int bytesPerPixel; + size_t bytesPerRow, bytesMaskData; + rfbXCursorColors rgb; + CARD32 colors[2]; + CARD8 *ptr, *rcSource, *rcMask; + void *softCursor; + int x, y, b; + int ox, oy, ow, oh; + PointerImage *pi; + short imageLen; + + bytesPerPixel = myFormat.bitsPerPixel / 8; + bytesPerRow = (width + 7) / 8; + bytesMaskData = bytesPerRow * height; + + if (width * height == 0) + return True; + + /* Allocate memory for pixel data and temporary mask data. */ + + rcSource = malloc(width * height * bytesPerPixel); + if (rcSource == NULL) + return False; + + rcMask = malloc(bytesMaskData); + if (rcMask == NULL) { + free(rcSource); + return False; + } + + /* Read and decode cursor pixel data, depending on the encoding type. */ + + if (enc == rfbEncodingXCursor) { + /* Read and convert background and foreground colors. */ + if (!ReadFromRFBServer((char *)&rgb, sz_rfbXCursorColors)) { + free(rcSource); + free(rcMask); + return False; + } + colors[0] = RGB24_TO_PIXEL(32, rgb.backRed, rgb.backGreen, rgb.backBlue); + colors[1] = RGB24_TO_PIXEL(32, rgb.foreRed, rgb.foreGreen, rgb.foreBlue); + + /* Read 1bpp pixel data into a temporary buffer. */ + if (!ReadFromRFBServer((char*)rcMask, bytesMaskData)) { + free(rcSource); + free(rcMask); + return False; + } + + /* Convert 1bpp data to byte-wide color indices. */ + ptr = rcSource; + for (y = 0; y < height; y++) { + for (x = 0; x < width / 8; x++) { + for (b = 7; b >= 0; b--) { + *ptr = rcMask[y * bytesPerRow + x] >> b & 1; + ptr += bytesPerPixel; + } + } + for (b = 7; b > 7 - width % 8; b--) { + *ptr = rcMask[y * bytesPerRow + x] >> b & 1; + ptr += bytesPerPixel; + } + } + + /* Convert indices into the actual pixel values. */ + switch (bytesPerPixel) { + case 1: + for (x = 0; x < width * height; x++) + rcSource[x] = (CARD8)colors[rcSource[x]]; + break; + case 2: + for (x = 0; x < width * height; x++) + ((CARD16 *)rcSource)[x] = (CARD16)colors[rcSource[x * 2]]; + break; + case 4: + for (x = 0; x < width * height; x++) + ((CARD32 *)rcSource)[x] = colors[rcSource[x * 4]]; + break; + } + + + } else { + if (!ReadFromRFBServer((char *)rcSource, width * height * bytesPerPixel)) { + free(rcSource); + free(rcMask); + return False; + } + } + + /* Read mask data. */ + + if (!ReadFromRFBServer((char*)rcMask, bytesMaskData)) { + free(rcSource); + free(rcMask); + return False; + } + + + /* Set the soft cursor. */ + softCursor = MakeSoftCursor(bytesPerPixel, width, height, rcSource, rcMask, &imageLen); + if (!softCursor) { + free(rcMask); + free(rcSource); + return False; + } + + /* get old cursor rect to know what to update */ + EnableClientCursor(1); + LockFramebuffer(); + getBoundingRectCursor(cursorX, cursorY, imageIndex, + &ox, &oy, &ow, &oh); + undrawCursor(); + + pi = &pointerImages[0]; + if (pi->set && pi->image) + free(pi->image); + pi->w = width; + pi->h = height; + pi->hotX = xhot; + pi->hotY = yhot; + pi->len = imageLen; + pi->image = softCursor; + pi->set = 1; + + imageIndex = 0; + + free(rcMask); + free(rcSource); + + return PointerMove(cursorX, cursorY, 0, ox, oy, ow, oh); +} + + + +/* + * HandleRFBServerMessage. + */ + +Bool +HandleRFBServerMessage() +{ + rfbServerToClientMsg msg; + if (!ReadFromRFBServer((char *)&msg, 1)) + return False; + + switch (msg.type) { + + case rfbSetColourMapEntries: + { + int i; + CARD16 rgb[3]; + XColor xc; + + if (!ReadFromRFBServer(((char *)&msg) + 1, + sz_rfbSetColourMapEntriesMsg - 1)) + return False; + + msg.scme.firstColour = Swap16IfLE(msg.scme.firstColour); + msg.scme.nColours = Swap16IfLE(msg.scme.nColours); + + for (i = 0; i < msg.scme.nColours; i++) { + if (!ReadFromRFBServer((char *)rgb, 6)) + return False; + xc.pixel = msg.scme.firstColour + i; + xc.red = Swap16IfLE(rgb[0]); + xc.green = Swap16IfLE(rgb[1]); + xc.blue = Swap16IfLE(rgb[2]); + xc.flags = DoRed|DoGreen|DoBlue; + /* Disable colormaps + lockQt(); + XStoreColor(dpy, cmap, &xc); + unlockQt(); + */ + } + + break; + } + + case rfbFramebufferUpdate: + { + rfbFramebufferUpdateRectHeader rect; + int linesToRead; + int bytesPerLine; + int i; + + announceIncrementalUpdateRequest(); + + if (!ReadFromRFBServer(((char *)&msg.fu) + 1, + sz_rfbFramebufferUpdateMsg - 1)) + return False; + + msg.fu.nRects = Swap16IfLE(msg.fu.nRects); + + for (i = 0; i < msg.fu.nRects; i++) { + if (!ReadFromRFBServer((char *)&rect, sz_rfbFramebufferUpdateRectHeader)) + return False; + + rect.encoding = Swap32IfLE(rect.encoding); + if (rect.encoding == rfbEncodingLastRect) + break; + + rect.r.x = Swap16IfLE(rect.r.x); + rect.r.y = Swap16IfLE(rect.r.y); + rect.r.w = Swap16IfLE(rect.r.w); + rect.r.h = Swap16IfLE(rect.r.h); + + if (rect.encoding == rfbEncodingPointerPos) { + if (!HandleCursorPos(rect.r.x, rect.r.y)) { + return False; + } + continue; + } + + if (rect.encoding == rfbEncodingXCursor || + rect.encoding == rfbEncodingRichCursor) { + if (!HandleCursorShape(rect.r.x, rect.r.y, rect.r.w, rect.r.h, + rect.encoding)) { + return False; + } + continue; + } + + if ((rect.r.x + rect.r.w > si.framebufferWidth) || + (rect.r.y + rect.r.h > si.framebufferHeight)) + { + fprintf(stderr,"Rect too large: %dx%d at (%d, %d)\n", + rect.r.w, rect.r.h, rect.r.x, rect.r.y); + return False; + } + + if ((rect.r.h * rect.r.w == 0) && + (rect.encoding != rfbEncodingSoftCursor)) { + fprintf(stderr,"Zero size rect - ignoring\n"); + continue; + } + + switch (rect.encoding) { + + case rfbEncodingRaw: + + bytesPerLine = rect.r.w * myFormat.bitsPerPixel / 8; + linesToRead = BUFFER_SIZE / bytesPerLine; + + while (rect.r.h > 0) { + if (linesToRead > rect.r.h) + linesToRead = rect.r.h; + + if (!ReadFromRFBServer(buffer,bytesPerLine * linesToRead)) + return False; + + CopyDataToScreen(buffer, rect.r.x, rect.r.y, rect.r.w, + linesToRead); + + rect.r.h -= linesToRead; + rect.r.y += linesToRead; + + } + break; + + case rfbEncodingCopyRect: + { + rfbCopyRect cr; + + if (!ReadFromRFBServer((char *)&cr, sz_rfbCopyRect)) + return False; + + cr.srcX = Swap16IfLE(cr.srcX); + cr.srcY = Swap16IfLE(cr.srcY); + + CopyArea(cr.srcX, cr.srcY, rect.r.w, rect.r.h, rect.r.x, rect.r.y); + + break; + } + + case rfbEncodingHextile: + { + switch (myFormat.bitsPerPixel) { + case 8: + if (!HandleHextile8(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) + return False; + break; + case 16: + if (!HandleHextile16(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) + return False; + break; + case 32: + if (!HandleHextile32(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) + return False; + break; + } + break; + } + + case rfbEncodingZlib: + { + switch (myFormat.bitsPerPixel) { + case 8: + if (!HandleZlib8(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) + return False; + break; + case 16: + if (!HandleZlib16(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) + return False; + break; + case 32: + if (!HandleZlib32(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) + return False; + break; + } + break; + } + + case rfbEncodingTight: + { + switch (myFormat.bitsPerPixel) { + case 8: + if (!HandleTight8(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) + return False; + break; + case 16: + if (!HandleTight16(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) + return False; + break; + case 32: + if (!HandleTight32(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) + return False; + break; + } + break; + } + + case rfbEncodingSoftCursor: + { + rfbSoftCursorMsg scmsg; + if (!ReadFromRFBServer((char *)&scmsg, 1)) + return False; + if (scmsg.type < rfbSoftCursorMaxImages) { + if (!ReadFromRFBServer(((char *)&scmsg)+1, + sizeof(rfbSoftCursorMove)- 1)) + return False; + if (!HandleSoftCursorMove(&scmsg.move, &rect.r)) + return False; + } + else if((scmsg.type >= rfbSoftCursorSetIconOffset) && + (scmsg.type < rfbSoftCursorSetIconOffset+rfbSoftCursorMaxImages)) { + if (!ReadFromRFBServer(((char *)&scmsg)+1, + sizeof(rfbSoftCursorSetImage)- 1)) + return False; + if (!HandleSoftCursorSetImage(&scmsg.setImage, &rect.r)) + return False; + } + else { + fprintf(stderr,"Unknown soft cursor image index %d\n", + (int)scmsg.type); + return False; + } + break; + } + + default: + fprintf(stderr,"Unknown rect encoding %d\n", + (int)rect.encoding); + return False; + } + + } + + queueIncrementalUpdateRequest(); + + break; + } + + case rfbBell: + { + beep(); + break; + } + + case rfbServerCutText: + { + char *serverCutText; + if (!ReadFromRFBServer(((char *)&msg) + 1, + sz_rfbServerCutTextMsg - 1)) + return False; + + msg.sct.length = Swap32IfLE(msg.sct.length); + + if (msg.sct.length > MAX_CUTBUFFER) { + fprintf(stderr, "Cutbuffer too long.\n"); + return False; + } + + serverCutText = malloc(msg.sct.length+1); + + if (!serverCutText) { + fprintf(stderr, "Out-of-memory, cutbuffer too long.\n"); + return False; + } + + if (!ReadFromRFBServer(serverCutText, msg.sct.length)) + return False; + + serverCutText[msg.sct.length] = 0; + newServerCut(serverCutText, msg.sct.length); /* takes ownership of serverCutText */ + + break; + } + + default: + fprintf(stderr,"Unknown message type %d from VNC server\n",msg.type); + return False; + } + + return True; +} + + +#define GET_PIXEL8(pix, ptr) ((pix) = *(ptr)++) + +#define GET_PIXEL16(pix, ptr) (((CARD8*)&(pix))[0] = *(ptr)++, \ + ((CARD8*)&(pix))[1] = *(ptr)++) + +#define GET_PIXEL32(pix, ptr) (((CARD8*)&(pix))[0] = *(ptr)++, \ + ((CARD8*)&(pix))[1] = *(ptr)++, \ + ((CARD8*)&(pix))[2] = *(ptr)++, \ + ((CARD8*)&(pix))[3] = *(ptr)++) + +/* CONCAT2 concatenates its two arguments. CONCAT2E does the same but also + expands its arguments if they are macros */ + +#define CONCAT2(a,b) a##b +#define CONCAT2E(a,b) CONCAT2(a,b) + +#define BPP 8 +#include "hextile.c" +#include "zlib.c" +#include "tight.c" +#undef BPP +#define BPP 16 +#include "hextile.c" +#include "zlib.c" +#include "tight.c" +#undef BPP +#define BPP 32 +#include "hextile.c" +#include "zlib.c" +#include "tight.c" +#undef BPP + + +/* + * PrintPixelFormat. + */ + +void +PrintPixelFormat(format) + rfbPixelFormat *format; +{ + if (format->bitsPerPixel == 1) { + fprintf(stderr," Single bit per pixel.\n"); + fprintf(stderr, + " %s significant bit in each byte is leftmost on the screen.\n", + (format->bigEndian ? "Most" : "Least")); + } else { + fprintf(stderr," %d bits per pixel.\n",format->bitsPerPixel); + if (format->bitsPerPixel != 8) { + fprintf(stderr," %s significant byte first in each pixel.\n", + (format->bigEndian ? "Most" : "Least")); + } + if (format->trueColour) { + fprintf(stderr," True colour: max red %d green %d blue %d", + format->redMax, format->greenMax, format->blueMax); + fprintf(stderr,", shift red %d green %d blue %d\n", + format->redShift, format->greenShift, format->blueShift); + } else { + fprintf(stderr," Colour map (not true colour).\n"); + } + } +} + +static long +ReadCompactLen (void) +{ + long len; + CARD8 b; + + if (!ReadFromRFBServer((char *)&b, 1)) + return -1; + len = (int)b & 0x7F; + if (b & 0x80) { + if (!ReadFromRFBServer((char *)&b, 1)) + return -1; + len |= ((int)b & 0x7F) << 7; + if (b & 0x80) { + if (!ReadFromRFBServer((char *)&b, 1)) + return -1; + len |= ((int)b & 0xFF) << 14; + } + } + return len; +} + +void freeRFBProtoResources() { + int i; + + if (desktopName) + free(desktopName); + if (raw_buffer) + free(raw_buffer); + for (i = 0; i < rfbSoftCursorMaxImages; i++) + if (pointerImages[i].set && pointerImages[i].image) + free(pointerImages[i].image); + + raw_buffer_size = -1; + raw_buffer = NULL; + decompStreamInited = False; + zlibStreamActive[0] = False; + zlibStreamActive[1] = False; + zlibStreamActive[2] = False; + zlibStreamActive[3] = False; + for (i = 0; i < rfbSoftCursorMaxImages; i++) + pointerImages[i].set = 0; + imageIndex = -1; +} + +void freeResources() { + freeSocketsResources(); + freeDesktopResources(); + freeRFBProtoResources(); +} + +/* + * JPEG source manager functions for JPEG decompression in Tight decoder. + */ + +static struct jpeg_source_mgr jpegSrcManager; +static JOCTET *jpegBufferPtr; +static size_t jpegBufferLen; + +static void +JpegInitSource(j_decompress_ptr cinfo) +{ + jpegError = False; +} + +static boolean +JpegFillInputBuffer(j_decompress_ptr cinfo) +{ + jpegError = True; + jpegSrcManager.bytes_in_buffer = jpegBufferLen; + jpegSrcManager.next_input_byte = (JOCTET *)jpegBufferPtr; + + return TRUE; +} + +static void +JpegSkipInputData(j_decompress_ptr cinfo, long num_bytes) +{ + if (num_bytes < 0 || num_bytes > jpegSrcManager.bytes_in_buffer) { + jpegError = True; + jpegSrcManager.bytes_in_buffer = jpegBufferLen; + jpegSrcManager.next_input_byte = (JOCTET *)jpegBufferPtr; + } else { + jpegSrcManager.next_input_byte += (size_t) num_bytes; + jpegSrcManager.bytes_in_buffer -= (size_t) num_bytes; + } +} + +static void +JpegTermSource(j_decompress_ptr cinfo) +{ + /* No work necessary here. */ +} + +static void +JpegSetSrcManager(j_decompress_ptr cinfo, CARD8 *compressedData, + int compressedLen) +{ + jpegBufferPtr = (JOCTET *)compressedData; + jpegBufferLen = (size_t)compressedLen; + + jpegSrcManager.init_source = JpegInitSource; + jpegSrcManager.fill_input_buffer = JpegFillInputBuffer; + jpegSrcManager.skip_input_data = JpegSkipInputData; + jpegSrcManager.resync_to_restart = jpeg_resync_to_restart; + jpegSrcManager.term_source = JpegTermSource; + jpegSrcManager.next_input_byte = jpegBufferPtr; + jpegSrcManager.bytes_in_buffer = jpegBufferLen; + + cinfo->src = &jpegSrcManager; +} + |